Windows XP Windows 7 Windows 2003 Windows Vista Windows教程綜合 Linux 系統教程
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟件教程
 Windows教程網 >> Linux系統教程 >> Linux教程 >> linux協議棧之鏈路層上的數據傳輸(向網橋添加接口(四))

linux協議棧之鏈路層上的數據傳輸(向網橋添加接口(四))

日期:2017/2/7 14:39:46      編輯:Linux教程
 

前面已經分析了,將接口添進網橋時,用戶空間調用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;

Copyright © Windows教程網 All Rights Reserved