linux bridge - mac forward

linux bridge - mac forward

https://www.jianshu.com/nb/46196362

 

linux bridge在虚拟化场景和docker中用的比较多,之前也知道它的原理,基本上就是类似二层交换机,根据mac地址和vid转发。但是对于vlan的处理网上的文档比较少,所以这次就看一下源码,分析下不配置vlan时如何转发,vlan又如何生效。

不配置vlan时,bridge纯靠mac转发,可通过如下两个命令之一查看mac转发表

//此命令只显示单播转发表,比较符合硬件交换机的显示规范,
//匹配到mac的,从port转发出去(可通过brctl showbsp br1查看端
//口号和端口的对应关系)
root@node2:~# brctl showmacs br1
port no mac addr        is local?   ageing timer
  2 12:27:96:8c:f4:58   yes        0.00
  2 12:27:96:8c:f4:58   yes        0.00
  1 66:e6:6f:a8:d4:97   yes        0.00
  1 66:e6:6f:a8:d4:97   yes        0.00

//通过此命令可显示所有的单播和组播表项
root@node2:~# bridge fdb show br br1
33:33:00:00:00:01 dev br1 self permanent
66:e6:6f:a8:d4:97 dev vetha master br1 permanent
66:e6:6f:a8:d4:97 dev vetha vlan 1 master br1 permanent
33:33:00:00:00:01 dev vetha self permanent
01:00:5e:00:00:01 dev vetha self permanent
12:27:96:8c:f4:58 dev vethx master br1 permanent
12:27:96:8c:f4:58 dev vethx vlan 1 master br1 permanent
33:33:00:00:00:01 dev vethx self permanent
01:00:5e:00:00:01 dev vethx self permanent

这篇文档就先介绍不使能vlan的情况,主要分为下面几个部分
a. kernel端bridge module的初始化都做了哪些事
b. 添加网桥时,命令行和kernel端代码流程
c. 给网桥添加端口时,命令行和kernel端代码流程
d. 从端口收到报文后,内部是如何转发的

广播/组播/未知单播报文flood到所有端口。
查找到转发表项的已知单播报文,发送到此表项的出端口。
广播/组播/已知单播并且dst为locol的报文,或者网桥设备使能了混杂模式,这几种情况都需要通过网桥设备将报文上送本机协议栈处理。

e. 从网桥br发出去的报文如何转发

广播/组播/未知单播报文,flood到所有端口。
能查找到转发表项的单播报文,从表项的出端口发送出去。

bridge还有如下几个注意的地方


单播flood: 控制单播报文是否从此端口发送一份,有两种设置方式,
a. bridge link set dev vnet1 flood on
b. echo 1 > /sys/class/net/br1/brif/vnet1/unicast_flood

hairpin模式:控制接收到广播/组播/未知单播的端口,再次从此端口发出。已知单播正常转发。
a. bridge link set dev vnet1 hairpin on
b. echo 1 > /sys/class/net/br1/brif/vnet1/hairpin_mode

网桥设备down后,所有端口状态都会变成 disabled, 导致网桥不会正确转发。
vetha (1)
 port id                8001                    state                  disabled
 designated root        8000.3adce07c2043       path cost                  2
 designated bridge      8000.3adce07c2043       message age timer          0.00
 designated port        8001                    forward delay timer        0.00
 designated cost           0                    hold timer                 0.00
 flags

bridge netfilter框架,可使用ebtables设置和查看

linux bridge - mac forward

1. module初始化流程

#module初始化流程
module_init(br_init)
static int __init br_init(void)
    static const struct stp_proto br_stp_proto = {
        .rcv    = br_stp_rcv,
    };
    //注册stp协议处理函数,防止环路产生,此文不看stp部分
    stp_proto_register(&br_stp_proto);
    
    //初始化fdb表项用到的cache
    br_fdb_init();
        static struct kmem_cache *br_fdb_cache __read_mostly;
        br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
                     sizeof(struct net_bridge_fdb_entry),0,
                     SLAB_HWCACHE_ALIGN, NULL);
                     
        static u32 fdb_salt __read_mostly;
        get_random_bytes(&fdb_salt, sizeof(fdb_salt));
        
    static struct pernet_operations br_net_ops = {
        .exit   = br_net_exit,
    };
    //注册pernet操作,只提供了exit,所以namespace初始化时无操作
    register_pernet_subsys(&br_net_ops);
    
    static struct notifier_block br_device_notifier = {
        .notifier_call = br_device_event
    };
    //注册网络设备事件处理函数
    register_netdevice_notifier(&br_device_notifier);
    
    br_netlink_init();
        br_mdb_init();
            rtnl_register(PF_BRIDGE, RTM_GETMDB, NULL, br_mdb_dump, NULL);
            rtnl_register(PF_BRIDGE, RTM_NEWMDB, br_mdb_add, NULL, NULL);
            rtnl_register(PF_BRIDGE, RTM_DELMDB, br_mdb_del, NULL, NULL);
            
        static struct rtnl_af_ops br_af_ops = {
            .family         = AF_BRIDGE,
            .get_link_af_size   = br_get_link_af_size,
        };
        rtnl_af_register(&br_af_ops);
            list_add_tail(&ops->list, &rtnl_af_ops);
            
        struct rtnl_link_ops br_link_ops __read_mostly = {
            .kind           = "bridge",
            .priv_size      = sizeof(struct net_bridge),
            .setup          = br_dev_setup,
            .maxtype        = IFLA_BRPORT_MAX,
            .policy         = br_policy,
            .validate       = br_validate,
            .newlink        = br_dev_newlink,
            .changelink     = br_changelink,
            .dellink        = br_dev_delete,
            .get_size       = br_get_size,
            .fill_info      = br_fill_info,
            .slave_maxtype      = IFLA_BRPORT_MAX,
            .slave_policy       = br_port_policy,
            .slave_changelink   = br_port_slave_changelink,
            .get_slave_size     = br_port_get_slave_size,
            .fill_slave_info    = br_port_fill_slave_info,
        };
        rtnl_link_register(&br_link_ops);
            __rtnl_link_register(ops);
                list_add_tail(&ops->list, &link_ops);
    //注册hook函数到br_ioctl_hook,添加网桥时调用br_ioctl_hook
    brioctl_set(br_ioctl_deviceless_stub);
        static int (
上一篇:Linux环境部署


下一篇:# 2021-01-09 #「Eclipse」- 安装插件市场(Marketplace)