添加一个桥设备——br_add_bridge(二)

来源:互联网 发布:seo超级外链工具 编辑:程序博客网 时间:2024/06/06 16:37
   上一节,讲述桥模式初始化时需要做的一些事情,这一节,我们一起来看看如何添加一个网桥设备。   我们先来看一个命令:       **brctl addbr br1**   上节我们提到一个用来处理ioctl命令的函数br_ioctl_deviceless_stub通过调用brioctl_set,   将br_ioctl_deviceless_stub赋值给回调函数br_ioctl_hook,而br_ioctl_hook在sock_ioctl中使用。   这样通过在应用层调用socket的ioctl函数,就能够进行网桥的添加与删除了。   如果我们想增加新的ioctl,用于我们新开放的功能,就可以在该函数里增加新的case即可。   当我们输入上面命令时,就会触发br_ioctl_deviceless_stub函数来响应br_add_bridge函数,当命令执行完成以后,   使用brctl show命令就可以看见我们添加的br1这个网桥设备已经生成。
int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg){    switch (cmd) {    case SIOCGIFBR:    case SIOCSIFBR:        return old_deviceless(net, uarg);    case SIOCBRADDBR:    case SIOCBRDELBR:    {        char buf[IFNAMSIZ];        if (!ns_capable(net->user_ns, CAP_NET_ADMIN))            return -EPERM;        if (copy_from_user(buf, uarg, IFNAMSIZ))            return -EFAULT;        buf[IFNAMSIZ-1] = 0;        if (cmd == SIOCBRADDBR)            return br_add_bridge(net, buf);/*添加网桥设备的操作*/        return br_del_bridge(net, buf);    }    }    return -EOPNOTSUPP;}
    好!知道br_ioctl_deviceless_stub的功能后,我们来看看br_add_bridge,这个函数添加桥设备需要初始化哪些东西:
int br_add_bridge(struct net *net, const char *name){    struct net_device *dev;    int res;    /*为设备分配一块内存,并且调用br_dev_setup函数初始化*/    dev = alloc_netdev(sizeof(struct net_bridge), name, NET_NAME_UNKNOWN,               br_dev_setup);    if (!dev)        return -ENOMEM;    dev_net_set(dev, net);    /*初始化dev的netlink链接通知操作函数*/    dev->rtnl_link_ops = &br_link_ops;    /*注册一个网络设备*/    res = register_netdev(dev);    if (res)        free_netdev(dev);    return res;}
    br_dev_setup函数用来初始化桥设备所需要的基本数据,尤其是在br_netdev_ops,中指定了很多的设备函数,    包括启用,关闭网桥,修改mtu以及设备ioctl函数,添加或删除,桥下设备等等一系列函数,这些函数的具体作用我们会在后续的章节中继续讨论。
void br_dev_setup(struct net_device *dev){    struct net_bridge *br = netdev_priv(dev);    eth_hw_addr_random(dev);    ether_setup(dev);    /*指定网络设备的管理钩子,关于各个钩子函数的作用以及用法,    请参见/linux/netdev.h中的net_device_ops结构体描述,这是很重要的一部分*/    dev->netdev_ops = &br_netdev_ops;    /*可选netdev操作, 关于各个钩子函数的作用以及用法,    请参见/linux/ethtool.h中的ethtool_ops结构体描述*/    dev->destructor = br_dev_free;    dev->ethtool_ops = &br_ethtool_ops;    SET_NETDEV_DEVTYPE(dev, &br_type);    /*IFF_EBRIDGE内核用来区别网桥设备和其他类型的设备*/    dev->priv_flags = IFF_EBRIDGE | IFF_NO_QUEUE;    dev->features = COMMON_FEATURES | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL |            NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;    dev->hw_features = COMMON_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |               NETIF_F_HW_VLAN_STAG_TX;    dev->vlan_features = COMMON_FEATURES;    br->dev = dev;    spin_lock_init(&br->lock);    INIT_LIST_HEAD(&br->port_list);    spin_lock_init(&br->hash_lock);    /*制定默认优先权*/    br->bridge_id.prio[0] = 0x80;    br->bridge_id.prio[1] = 0x00;    ether_addr_copy(br->group_addr, eth_reserved_addr_base);    br->stp_enabled = BR_NO_STP;    br->group_fwd_mask = BR_GROUPFWD_DEFAULT;    br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT;    br->designated_root = br->bridge_id;    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;    /*老化时间初值默认为5分钟*/    br->ageing_time = BR_DEFAULT_AGEING_TIME;    /*初始化该网桥的netfilter*/    br_netfilter_rtable_init(br);     /*初始化网桥的各类定时器,hello定时器,垃圾回收定时器等等*/    br_stp_timer_init(br);    /*多播初始化*/    br_multicast_init(br);}
    在上面的函数中,除了br_netdev_ops需要注意以外还有一个需要注意的函数br_netfilter_rtable_init(br);    这个函数是用来初始化Bridging-Firewalling,在后续的章节中,可以看到Netfilter钩子(hook)在桥接程序用于处理入口和出口网络流量的主要位置。    另外,在编译内核时,选中:    Networking support->Networking options->Networking packet filtering(replaces ipchains) -> Bridged IP/ARP packet filtering后,    内核就支持Bridging-Firewalling.Ethernel-Bridging-Tables选项(也就是ebtables).

以上就是,桥设备初始化的相关操作。

阅读全文
0 0