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

   上一节,讲述桥模式初始化时需要做的一些事情,这一节,我们一起来看看如何添加一个网桥设备。

   我们先来看一个命令:
       **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).

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

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页