歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

linux協議棧之鏈路層上的數據傳輸(新建網橋(三))

新建網橋:

從上面的分析可以知道,在用戶空間調用ioctl(br_socket_fd, SIOCBRADDBR, brname).進入到br_ioctl_deviceless_stub,可以看到它的相關處理:

int br_ioctl_deviceless_stub(unsigned int cmd, void __user *uarg)

{

switch (cmd) {

case SIOCGIFBR:

case SIOCSIFBR:

return old_deviceless(uarg);

//新建網橋

case SIOCBRADDBR:

//刪除網橋

case SIOCBRDELBR:

{

char buf[IFNAMSIZ];

if (!capable(CAP_NET_ADMIN))

return -EPERM;

//copy_from_user:把用戶空間的數據拷入內核空間

if (copy_from_user(buf, uarg, IFNAMSIZ))

return -EFAULT;

buf[IFNAMSIZ-1] = 0;

if (cmd == SIOCBRADDBR)

return br_add_bridge(buf);

return br_del_bridge(buf);

}

}

return -EOPNOTSUPP;

}

在這裡,我們傳入的cmd為SIOCBRADDBR.轉入br_add_bridge(buf)中進行:

int br_add_bridge(const char *name)

{

struct net_device *dev;

int ret;

//為虛擬橋新建一個net_device

//在前面“網絡設備的管理”經講述此結構

dev = new_bridge_dev(name);

if (!dev)

return -ENOMEM;



rtnl_lock();

//由內核確定接口名字,例如eth0 eth1等

if (strchr(dev->name, '%')) {

ret = dev_alloc_name(dev, dev->name);

if (ret < 0)

goto err1;

}

//向內核注冊此網絡設備

ret = register_netdevice(dev);

if (ret)

goto err2;

dev_hold(dev);

rtnl_unlock();

//在sysfs中建立相關信息

ret = br_sysfs_addbr(dev);

dev_put(dev);

if (ret)

unregister_netdev(dev);

out:

return ret;

err2:

free_netdev(dev);

err1:

rtnl_unlock();

goto out;

}

網橋的注冊跟我們以前看到的物理網絡設備注冊是一樣的。我們關心的是網橋對應的net_device結構是什麼樣的,繼續跟蹤進new_bridge_dev:

static struct net_device *new_bridge_dev(const char *name)

{

struct net_bridge *br;

struct net_device *dev;

//分配net_device

dev = alloc_netdev(sizeof(struct net_bridge), name,

br_dev_setup);

if (!dev)

return NULL;

網橋的私區結構為net_bridge

br = netdev_priv(dev);

//私區結構中的dev字段指向它本身

br->dev = dev;

br->lock = SPIN_LOCK_UNLOCKED;

//隊列初始化。在port_list中保存了這個橋上的端口列表

INIT_LIST_HEAD(&br->port_list);

br->hash_lock = SPIN_LOCK_UNLOCKED;

//下面這部份代碼跟stp協議相關,我們暫不關心

br->bridge_id.prio[0] = 0x80;

br->bridge_id.prio[1] = 0x00;

memset(br->bridge_id.addr, 0, ETH_ALEN);



br->stp_enabled = 0;

br->designated_root = br->bridge_id;

br->root_path_cost = 0;

br->root_port = 0;

br->bridge_max_age = br->max_age = 20 * HZ;

br->bridge_hello_time = br->hello_time = 2 * HZ;

br->bridge_forward_delay = br->forward_delay = 15 * HZ;

br->topology_change = 0;

br->topology_change_detected = 0;

br->ageing_time = 300 * HZ;

INIT_LIST_HEAD(&br->age_list);



br_stp_timer_init(br);



return dev;

}

在br_dev_setup中還做了一些另外在函數指針初始化:

void br_dev_setup(struct net_device *dev)

{

//將橋的MAC地址設為零

memset(dev->dev_addr, 0, ETH_ALEN);

//以太網結構初始化

ether_setup(dev);

//一系列函數指針初始化

dev->do_ioctl = br_dev_ioctl;

dev->get_stats = br_dev_get_stats;

dev->hard_start_xmit = br_dev_xmit;

dev->open = br_dev_open;

dev->set_multicast_list = br_dev_set_multicast_list;

dev->change_mtu = br_change_mtu;

dev->destructor = free_netdev;

SET_MODULE_OWNER(dev);

dev->stop = br_dev_stop;

dev->accept_fastpath = br_dev_accept_fastpath;

dev->tx_queue_len = 0;

dev->set_mac_address = NULL;

dev->priv_flags = IFF_EBRIDGE;

}

這一部份,對橋設備的私區空間進行了初始化。在這裡,有必要給橋的net_device對應的私區結構:

Copyright © Linux教程網 All Rights Reserved