网桥本地链路组播控制group_fwd_mask

在创建网桥时,可指定组播转发掩码值group_fwd_mask,如下0xff00。掩码中的位表示的为链路本地地址(01:80:C2:00:00:0X)的最后一个4位的值,即X的值,其范围为0到15,所以,group_fwd_mask的值为16比特。

网桥下的子接口可以设置自身的group_fwd_mask掩码值。

$ sudo ip link add name br1 type bridge group_fwd_mask 0xff00
$ 
$ cat /sys/devices/virtual/net/br1/bridge/group_fwd_mask
0xff00
$
$ ip -d link show dev br1
28: br1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 2a:36:87:af:fd:62 brd ff:ff:ff:ff:ff:ff promiscuity 0 minmtu 68 maxmtu 65535 
    bridge ... group_fwd_mask 0xff00 group_address 01:80:c2:00:00:00

在网桥设备初始化时,将group_fwd_mask和group_fwd_mask_required赋值为零,没有任何转发掩码位。

void br_dev_setup(struct net_device *dev)
{

    br->group_fwd_mask = BR_GROUPFWD_DEFAULT;
    br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT;

宏定义BR_GROUPFWD_RESTRICTED规定了不能设置的3个转发位,分别为STP报文,PAUSE帧,和LACP聚合协议报文。

#define BR_GROUPFWD_DEFAULT 0
/* Don't allow forwarding of control protocols like STP, MAC PAUSE and LACP */
enum {
    BR_GROUPFWD_STP     = BIT(0),
    BR_GROUPFWD_MACPAUSE    = BIT(1),
    BR_GROUPFWD_LACP    = BIT(2),
};
#define BR_GROUPFWD_RESTRICTED (BR_GROUPFWD_STP | BR_GROUPFWD_MACPAUSE | BR_GROUPFWD_LACP)

以下设置网桥自身的group_fwd_mask掩码值,合法值不能设置BR_GROUPFWD_RESTRICTED中定义的位,即第0、1、2位都不能为1。

static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
             struct nlattr *data[], struct netlink_ext_ack *extack)
{

    if (data[IFLA_BR_GROUP_FWD_MASK]) {
        u16 fwd_mask = nla_get_u16(data[IFLA_BR_GROUP_FWD_MASK]);

        if (fwd_mask & BR_GROUPFWD_RESTRICTED)
            return -EINVAL;
        br->group_fwd_mask = fwd_mask;
    }

以下函数设置网桥子接口的group_fwd_mask掩码值,合法的掩码值要求第一位不能置位,即不能允许转发PAUSE帧。

/* Process bridge protocol info on port */
static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
{

    if (tb[IFLA_BRPORT_GROUP_FWD_MASK]) {
        u16 fwd_mask = nla_get_u16(tb[IFLA_BRPORT_GROUP_FWD_MASK]);

        if (fwd_mask & BR_GROUPFWD_MACPAUSE)
            return -EINVAL;
        p->group_fwd_mask = fwd_mask;
    } 

设置组播地址

首先设置的地址必须是本地链路地址,另外最后一个字节的值不能等于1、2、3,即不能等于BR_GROUPFWD_RESTRICTED中定义的位对应的协议。对于合法的地址,需要重新计算组播转发掩码。

static int br_changelink(struct net_device *brdev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack)
{

    if (data[IFLA_BR_GROUP_ADDR]) {
        u8 new_addr[ETH_ALEN];

        if (nla_len(data[IFLA_BR_GROUP_ADDR]) != ETH_ALEN)
            return -EINVAL;
        memcpy(new_addr, nla_data(data[IFLA_BR_GROUP_ADDR]), ETH_ALEN);
        if (!is_link_local_ether_addr(new_addr))
            return -EINVAL;
        if (new_addr[5] == 1 ||     /* 802.3x Pause address */
            new_addr[5] == 2 ||     /* 802.3ad Slow protocols */
            new_addr[5] == 3)       /* 802.1X PAE address */
            return -EINVAL;
        spin_lock_bh(&br->lock);
        memcpy(br->group_addr, new_addr, sizeof(br->group_addr));
        spin_unlock_bh(&br->lock);
        br_opt_toggle(br, BROPT_GROUP_ADDR_SET, true);
        br_recalculate_fwd_mask(br);

以下函数修改的为网桥自身的group_fwd_mask_required掩码值,对于未使能VLAN选项,或者VLAN协议为802.1q时,掩码值为默认的0,对于802.1ad协议,掩码值为802.1ad的5个地址中,去掉和组播地址最后一字节对应的地址位,所得到的值,即不转发自身组播地址的报文。可见,仅在最后一种情况下,group_fwd_mask_required才有可能不为空。

void br_recalculate_fwd_mask(struct net_bridge *br)
{   
    if (!br_opt_get(br, BROPT_VLAN_ENABLED) ||
        br->vlan_proto == htons(ETH_P_8021Q))
        br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT;
    else /* vlan_enabled && ETH_P_8021AD */
        br->group_fwd_mask_required = BR_GROUPFWD_8021AD &
                          ~(1u << br->group_addr[5]);
} 

/* The Nearest Customer Bridge Group Address, 01-80-C2-00-00-[00,0B,0C,0D,0F] */
#define BR_GROUPFWD_8021AD  0xB801u

组播处理

在网桥接收处理函数br_handle_frame中,如果报文的目的MAC地址为:01:80:c2:00:00:0X,表示其为链路本地保留地址。

static rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
{
    struct net_bridge_port *p;

    p = br_port_get_rcu(skb->dev);

    if (unlikely(is_link_local_ether_addr(dest))) {
        u16 fwd_mask = p->br->group_fwd_mask_required;

        /*
         * See IEEE 802.1D Table 7-10 Reserved addresses
         *
         * Assignment               Value
         * Bridge Group Address     01-80-C2-00-00-00
         * (MAC Control) 802.3      01-80-C2-00-00-01
         * (Link Aggregation) 802.3 01-80-C2-00-00-02
         * 802.1X PAE address       01-80-C2-00-00-03
         *
         * 802.1AB LLDP         01-80-C2-00-00-0E
         *
         * Others reserved for future standardization
         */
        fwd_mask |= p->group_fwd_mask;
        switch (dest[5]) {

对于目的MAC最后一个字节为0的情况,即网桥组播地址,如果STP没有开启,或者fwd_mask第0位置位的情况下,转发此报文。fwd_mask等于网桥结构的group_fwd_mask_required和接收报文的接口结构的成员group_fwd_mask的相或的值。也就是说,不管是网桥还是其子接口,只要有一个设置另外第0位,就成立,转发报文。

        case 0x00:  /* Bridge Group Address */
            /* If STP is turned off, then must forward to keep loop detection */
            if (p->br->stp_enabled == BR_NO_STP || fwd_mask & (1u << dest[5]))
                goto forward;
            *pskb = skb;
            __br_handle_local_finish(skb);
            return RX_HANDLER_PASS;

        case 0x01:  /* IEEE MAC (Pause) */
            goto drop;

对于LLDP报文的情况,fwd_mask又或上了网桥结构的group_fwd_mask的值,如果最终的掩码值的第14位为1,转发此类报文。

        case 0x0E:  /* 802.1AB LLDP */
            fwd_mask |= p->br->group_fwd_mask;
            if (fwd_mask & (1u << dest[5]))
                goto forward;
            *pskb = skb;
            __br_handle_local_finish(skb);
            return RX_HANDLER_PASS;

最后,其它情况下,也是将fwd_mask或上网桥结构的group_fwd_mask的值,如果最终的掩码值中,dest[5]所表示的位为1,转发此类报文。

        default:
            /* Allow selective forwarding for most other protocols */
            fwd_mask |= p->br->group_fwd_mask;
            if (fwd_mask & (1u << dest[5]))
                goto forward;

由以上可见,网桥组播报文的转发,由网桥结构的group_fwd_mask_required,以及相关接口的group_fwd_mask值的控制;而不受网桥结构的group_fwd_mask掩码值控制。

内核版本 5.10

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页