一、基本数据结构及相互关系
net_bridge 网桥的结构信息
net_bridge_port 接在网桥上的一个port
net_bridge_fdb_entry mac->port 映射对,用于根据目的mac确定发往哪个端口
1)net_bridge紧随bridge的net_device后面
2)net_bridge中有所有挂接在该bridge上的net_bridge_port的链表
net_bridge中有所有net_bridge_fdb_entry的hash表,hash表按mac地址进行hash
- struct net_bridge{
-
struct list_head port_list;
-
......
-
struct hlist_head hash[BR_HASH_SIZE];
-
}
3) net_bridge_port 指向它关联的net_device及它attach 的net_bridge
- struct net_bridge_port{
-
struct net_bridge *br;
-
struct net_device *dev;
- u16 port_no;
-
...
-
}
4) net_bridge_fdb_entry 关联了一个mac->port的映射对
- 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动态超时掉
-
};
二. 增加一个bridge(brctl addbr)
1.
通过对一个socket的ioctl来设置
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绑定在一起
设置接到网桥上网络设备的混杂模式,否则网络设备就会丢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));
阅读(674) | 评论(0) | 转发(0) |