网桥接口的混杂模式

网桥接口的混杂模式取决于三个因素,一个是自身的混杂模式设置;第二是vlan过滤是否开启;最后是处于自动状态(auto_port)的子接口的数量。网桥的混杂模式管理函数br_manage_promisc如下:


void br_manage_promisc(struct net_bridge *br)
{
    if ((br->dev->flags & IFF_PROMISC) || !br_vlan_enabled(br))
        set_all = true;

    list_for_each_entry(p, &br->port_list, list) {
        if (set_all) {
            br_port_set_promisc(p);
        } else {
            if (br->auto_cnt == 0 ||
                (br->auto_cnt == 1 && br_auto_port(p)))
                br_port_clear_promisc(p);
            else
                br_port_set_promisc(p);
        }
    }
}


混杂模式设置



如下通过命令设置网桥br_2为混杂模式,此时,所有网桥子接口都将处于混杂模式(eth1与eth2 promiscuity mode):

ip link add br_2 type bridge
ip link set eth1 master br_2
ip link set eth2 master br_2


通过ip命令设置接口的混杂模式:
ip link set br_2 promisc on

或者ioctl系统调用设置混杂模式:

int set_bridge_promiscuity(void)
{
  sockfd = socket(AF_INET, SOCK_DGRAM, 0);

  strncpy(ifr.ifr_name, "br_2", IFNAMSIZ);
  ioctl(sockfd, SIOCGIFFLAGS, &ifr);

  ifr.ifr_flags |= IFF_PROMISC;
  ioctl(sockfd, SIOCSIFFLAGS, &ifr);
}


VLAN过滤


如果网桥的VLAN filtering过滤功能没有开启,即使网桥没有设置混杂模式,也需开启所有子接口的混杂模式。

/sys/devices/virtual/net/br_2/bridge/vlan_filtering


自动状态接口AUTO_PORT


内核中对自动状态接口的定义如下,即设置了学习(learning)或者单播泛洪(flood)标志的接口。

#define BR_AUTO_MASK        (BR_FLOOD | BR_LEARNING)
#define br_auto_port(p) ((p)->flags & BR_AUTO_MASK)

可通过bridge或者ip命令设置网桥接口的flood/learning等标志:

bridge link set dev eth1 flood on/off
bridge link set dev eth1 learning on/off
ip link set dev eth1 type bridge_slave flood on/off
ip link set dev eth1 type bridge_slave learning on/off


网桥添加网络设备时,新接口的flags赋值为BR_LEARNING与BR_FLOOD标志,即新接口为自动状态接口。


static struct net_bridge_port *new_nbp(struct net_bridge *br, struct net_device *dev)
{
	struct net_bridge_port *p;
    p->flags = BR_LEARNING | BR_FLOOD;
}


BR_LEARNING标志,在函数br_handle_frame_finish中判断,用来决定是否使用数据包的源MAC地址更新网桥的FDB转发表。


int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
    struct net_bridge_port *p = br_port_get_rcu(skb->dev);
    struct net_bridge *br;

    br = p->br;
    if (p->flags & BR_LEARNING)
        br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);
}

BR_FLOOD标志用来控制是否在接口上泛洪单播数据包,如果没有设置此标志,不能在此接口泛洪单播包。


void br_flood(struct net_bridge *br, struct sk_buff *skb, ...)
{
    struct net_bridge_port *p;

    list_for_each_entry_rcu(p, &br->port_list, list) {
        switch (pkt_type) {
        case BR_PKT_UNICAST:
            if (!(p->flags & BR_FLOOD))
                continue;
            break;
}

网桥结构体中保存了自动状态接口的数量auto_cnt,在向网桥添加接口或者删除接口的时候,调用nbp_update_port_count更新自动状态接口的数量。通过遍历网桥的接口列表,获取自动接口数量。


static void nbp_update_port_count(struct net_bridge *br)
{
    struct net_bridge_port *p;
    u32 cnt = 0;

    list_for_each_entry(p, &br->port_list, list) {
        if (br_auto_port(p))
            cnt++;
    }
    if (br->auto_cnt != cnt) {
        br->auto_cnt = cnt;
        br_manage_promisc(br);
    }
}


所谓非自动接口,即此接口不自动学习数据包的源MAC地址,或者不泛洪单播包。对于此类接口,要正常转发报文,必须静态指定其在FDB转发表中的转发表项。由上文br_manage_promisc函数中的条件判断可知,当网桥下都是非自动接口时(auto_cnt=0),关闭混杂模式,因为此时所有接口都已经配置好了转发表项,不需要混杂模式。当只有一个接口时自动接口的时候,从这个接口接收到的数据包无非是要转发到系统剩余的其它接口,而其它接口都是非自动的,这就反向决定了此自动接口的转发路径也被确定下了,此时也不需要混杂模式。


所以当自动接口大于1时,开启混杂模式。


内核版本

linux-4.15


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