前面已經分析了,將接口添進網橋時,用戶空間調用ioctl(br_socket_fd, SIOCBRADDIF, &ifr)
注意到在void br_dev_setup(struct net_device *dev)中已經對dev->do_ioctl進行了賦值,即:
dev->do_ioctl = br_dev_ioctl
進行ioctl進行訪問的時候,進入到br_dev_ioctl: (net/brige/br_ioctl.c)
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct net_bridge *br = netdev_priv(dev);
switch(cmd) {
case SIOCDEVPRIVATE:
return old_dev_ioctl(dev, rq, cmd);
//添加一個接口
case SIOCBRADDIF:
//刪除一個接口
case SIOCBRDELIF:
return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);
}
pr_debug("Bridge does not support ioctl 0x%x\n", cmd);
return -EOPNOTSUPP;
}
我們在用戶空間使用的標志是SIOCBRADDIF。所以流程進入add_del_if()
static int add_del_if(struct net_bridge *br, int ifindex, int isadd)
{
struct net_device *dev;
int ret;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev = dev_get_by_index(ifindex);
if (dev == NULL)
return -EINVAL;
if (isadd)
ret = br_add_if(br, dev);
else
ret = br_del_if(br, dev);
dev_put(dev);
return ret;
}
因為cmd == SIOCBRADDIF為真,所以調用br_add_if():
int br_add_if(struct net_bridge *br, struct net_device *dev) (net/brige/br_if.c))
{
struct net_bridge_port *p;
int err = 0;
//回環。或者非以及網接口
if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER)
return -EINVAL;
//構造數據包函數為網橋類型
if (dev->hard_start_xmit == br_dev_xmit)
return -ELOOP;
//此接口已經存在於網橋
if (dev->br_port != NULL)
return -EBUSY;
//為dev 創建網橋接口.dev->br_port。指向所屬網橋端口
//dev->br_port->br:指向它所屬的網橋
//為該接口創建net_bridge_port
if (IS_ERR(p = new_nbp(br, dev, br_initial_port_cost(dev))))
return PTR_ERR(p);
//更新port->MAC對應表
if ((err = br_fdb_insert(br, p, dev->dev_addr, 1)))
destroy_nbp(p);
else if ((err = br_sysfs_addif(p)))
del_nbp(p);
else {
//設置接口為混雜模式
dev_set_promiscuity(dev, 1);
//將p->list更新至br->port_list中
list_add_rcu(&p->list, &br->port_list);
spin_lock_bh(&br->lock);
br_stp_recalculate_bridge_id(br);
if ((br->dev->flags & IFF_UP)
&& (dev->flags & IFF_UP) && netif_carrier_ok(dev))
br_stp_enable_port(p);
spin_unlock_bh(&br->lock);
dev_set_mtu(br->dev, br_min_mtu(br));
}
return err;
}
為接口創建net_bridge_port的函數為new_nbp。這個函數比較簡單:
static struct net_bridge_port *new_nbp(struct net_bridge *br,
struct net_device *dev,
unsigned long cost)
{
int index;
struct net_bridge_port *p;
index = find_portno(br);
if (index < 0)
return ERR_PTR(index);
p = kmalloc(sizeof(*p), GFP_KERNEL);
if (p == NULL)
return ERR_PTR(-ENOMEM);
memset(p, 0, sizeof(*p));
p->br = br;
dev_hold(dev);
p->dev = dev;
p->path_cost = cost;
p->priority = 0x8000 >> BR_PORT_BITS;
dev->br_port = p;
p->port_no = index;
br_init_port(p);
p->state = BR_STATE_DISABLED;
kobject_init(&p->kobj);
return p;
}
之後,把要加入的接口對應的mac與接口作為本機靜態項加入到prot—mac對應表。這是在br_fdb_insert()中實現的
int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
const unsigned char *addr, int is_local)
{
int ret;
spin_lock_bh(&br->hash_lock);
ret = fdb_insert(br, source, addr, is_local);
spin_unlock_bh(&br->hash_lock);
return ret;