新建網橋:
從上面的分析可以知道,在用戶空間調用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對應的私區結構: