[转载] Linux Bridge 实现
原文:http://blog.chinaunix.net/uid-26321024-id-2938338.html
分类: LINUX
- br = netdev_priv(dev);
- struct net_bridge{
- struct list_head port_list;
- ......
- struct hlist_head hash[BR_HASH_SIZE];
- }
- struct net_bridge_port{
- struct net_bridge *br;
- struct net_device *dev;
- u16 port_no;
- ...
- }
- struct net_bridge_fdb_entry
- {
- struct hlist_node hlist;
- struct net_bridge_port *dst;
- struct rcu_head rcu;
- unsigned long ageing_timer;
- mac_addr addr;
- unsigned char is_local; //若为1,表示是本地的,若转往此端口,则直接向上走协议栈
- unsigned char is_static; //若为1,表示这个entry是静态的,不会被timer动态超时掉
- };
sock_ioctl -> br_ioctl_hook
其中br_ioctl_hook在br_init中被设置为br_ioctl_deviceless_stub
brioctl_set(br_ioctl_deviceless_stub);
2. br_ioctl_deviceless_stub -> br_add_bridge
生成一个新的net_device
dev = new_bridge_dev(net, name);
注册网络设备 register_netdevice(dev)
增加sysfs entry: br_sysfs_addbr(dev)
三、attatch 一个网络设备到bridge上 (brctl addif )
1.通过对bridge ioctl来设置
- br_dev_ioctl:
- case SIOCBRADDIF:
- case SIOCBRDELIF:
- return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);
2. add_del_if -> br_add_if
Loopback设备和非ethernet设备不能接到网桥上。
- if ((dev->flags & IFF_LOOPBACK) ||
- dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN) return -EINVAL;
不能将网桥接到网桥上:
- if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit)
- return -ELOOP;
不能将一个设备接到多个网桥上:
- if (dev->br_port != NULL) //不能将一个设备接在两个bridge上
- return -EBUSY;
分配一个端口号,创建一个net_bridge_port,将port和dev绑定在一起
- p = new_nbp(br, dev);
设置接到网桥上网络设备的混杂模式,否则网络设备就会丢dst mac不是自己的包,就不能起到网桥转发的作用。
- err = dev_set_promiscuity(dev, 1);
针对此设备,插入一个fdb项:
err = br_fdb_insert(br, p, dev->dev_addr); -> fdb_insert ->fdb_create
插入的这个fdb项是个静态的: timer触发的过期fdb删除永远不会影响到静态fdb
Local的: 命中这个fdb的skb直接走本机协议栈,不用转发。
- if (!fdb_create(head, source, addr, 1))
- return -ENOMEM;
- static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
- struct net_bridge_port *source,
- const unsigned char *addr,
- int is_local)
- {
- struct net_bridge_fdb_entry *fdb;
- fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);
- if (fdb) {
- memcpy(fdb->addr.addr, addr, ETH_ALEN);
- hlist_add_head_rcu(&fdb->hlist, head);
- fdb->dst = source;
- fdb->is_local = is_local;
- fdb->is_static = is_local;
- fdb->ageing_timer = jiffies;
- }
- return fdb;
- }
相互关系设置:
- rcu_assign_pointer(dev->br_port, p);
- dev_disable_lro(dev);
- list_add_rcu(&p->list, &br->port_list);
通过STP设置port状态:
- if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
- (br->dev->flags & IFF_UP))
- br_stp_enable_port(p);
设置bridge的mtu为所连接net_device MTU的最小值
- dev_set_mtu(br->dev, br_min_mtu(br));

浙公网安备 33010602011771号