赞
踩
限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。
调试 Marvell 88E6320
时,发现 eth0
出人意料的进入了 promiscuous(混杂)
模式:
[ 5384.145131] device eth0 entered promiscuous mode
Marvell 88E6320
和 eth0
对应 SoC
的 cpsw
MAC 芯片的连接拓扑结构如下:
系统网络设备配置如下:
# ifconfig eth0 Link encap:Ethernet HWaddr 60:B6:E1:6E:14:F8 inet6 addr: fe80::62b6:e1ff:fe6e:14f8/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:247 errors:0 dropped:0 overruns:0 frame:0 TX packets:32 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:19440 (18.9 KiB) TX bytes:2560 (2.5 KiB) Interrupt:47 lan3 Link encap:Ethernet HWaddr 60:B6:E1:6E:14:F8 inet addr:192.168.3.5 Bcast:0.0.0.0 Mask:255.255.255.0 inet6 addr: fe80::62b6:e1ff:fe6e:14f8/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:247 errors:0 dropped:0 overruns:0 frame:0 TX packets:16 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:13018 (12.7 KiB) TX bytes:1216 (1.1 KiB) lan4 Link encap:Ethernet HWaddr 62:B6:E1:6E:14:F8 inet addr:192.168.3.8 Bcast:0.0.0.0 Mask:255.255.255.0 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
经过一番分析,最后发现,是由下列命令导致 eth0
进入 promiscuous(混杂)
模式:
ip link set dev lan4 address 62:b6:e1:6e:14:f8
这里有两个问题:
1. 操作的 lan4,为什么影响到了 eth0?
2. 不过是一条设置 MAC 的指令,怎么会导致进入 promiscuous(混杂)模式?
跟踪下指令 ip link set dev lan4 address 62:b6:e1:6e:14:f8
流程:
/* ip link 程序通过 netlink 来进行 MAC 设置 */ sys_sendmsg() ... netlink_unicast() rtnetlink_rcv() netlink_rcv_skb() rtnetlink_rcv_msg() rtnl_newlink() do_setlink() dev_set_mac_address() // 触发 lan4 的 MAC 设置接口 ops->ndo_set_mac_address(dev, sa) = dsa_slave_set_mac_address() // 接上面流程 static int dsa_slave_set_mac_address(struct net_device *dev, void *a) { // 这里回答了问题 1. 操作的 lan4,为什么影响到了 eth0? // @dev : lan4 // @master: eth0 // 对 lan4 的操作反映到了 eth0 struct net_device *master = dsa_slave_to_master(dev); ... if (!ether_addr_equal(addr->sa_data, master->dev_addr)) { err = dev_uc_add(master, addr->sa_data); ... } ... } int dev_uc_add(struct net_device *dev, const unsigned char *addr) { ... // 增加一条 单播过滤(unicast filtering)地址 到 eth0 err = __hw_addr_add(&dev->uc, addr, dev->addr_len, NETDEV_HW_ADDR_T_UNICAST); if (!err) __dev_set_rx_mode(dev); ... } void __dev_set_rx_mode(struct net_device *dev) { ... if (!(dev->priv_flags & IFF_UNICAST_FLT)) { // 如果 eth0 不支持单播地址过滤 // 如果 eth0 不支持单播地址过滤,通过将 eth0 设置为 promiscuous(混杂) // 变相的来支持 eth0 单播地址过滤。 if (!netdev_uc_empty(dev) && !dev->uc_promisc) { // 场景下,触发这条执行路径 __dev_set_promiscuity(dev, 1, false); dev->uc_promisc = true; } else if (netdev_uc_empty(dev) && dev->uc_promisc) { __dev_set_promiscuity(dev, -1, false); dev->uc_promisc = false; } } // eth0 的 RX 模式 配置 if (ops->ndo_set_rx_mode) ops->ndo_set_rx_mode(dev); // cpsw_ndo_set_rx_mode() } // 设置网卡 eth0 promiscuous(混杂)模式标记 IFF_PROMISC static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify) { ... // 这里回答了问题 2. 不过是一条设置 MAC 的指令,怎么会导致进入 promiscuous(混杂)模式? dev->flags |= IFF_PROMISC; dev->promiscuity += inc; ... if (dev->flags != old_flags) { // 对应内核日志: // [ 5384.145131] device eth0 entered promiscuous mode pr_info("device %s %s promiscuous mode\n", dev->name, dev->flags & IFF_PROMISC ? "entered" : "left"); ... dev_change_rx_flags(dev, IFF_PROMISC); } if (notify) __dev_notify_flags(dev, old_flags, IFF_PROMISC); ... } // eth0 的 rx 模式配置 static void cpsw_ndo_set_rx_mode(struct net_device *ndev) { ... if (ndev->flags & IFF_PROMISC) { /* Enable promiscuous mode */ cpsw_set_promiscious(ndev, true); // 将 eth0 设为 promiscuous(混杂)模式 ... } else { ... } ... }
到此,真相浮出水面,原来,交换芯片 port3 (lan3)
和 port4 (lan4)
,要将数据转发给 eth0
。从前面的信息看到,lan3
和 eth0
公用了 MAC ,lan4
配置了一个不同于 eth0
的 MAC,然后将 lan4
的 MAC 添加到 eth0
的单播过滤(unicast filtering)
MAC 列表,这样使得 eth0
除了可以接收 lan3
的数据外,也可以接收 lan4
的数据,同时由于 eth0
不支持 单播过滤(unicast filtering)
功能,所以只能将 eth0
配置为 promiscuous(混杂)模式
来变相的达到目的。
[1] 4.5.3.1. Unicast Frame Filtering
[2] Layerscape Software Development Kit User Guide
[3] UG10081: Layerscape Linux Distribution POC User Guide
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。