Linux 网络:网卡 promiscuous 模式疑云

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. 问题场景

调试 Marvell 88E6320 时,发现 eth0 出人意料的进入了 promiscuous(混杂) 模式:

[ 5384.145131] device eth0 entered promiscuous mode

Marvell 88E6320eth0 对应 SoCcpsw 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)

3. 问题定位和分析

经过一番分析,最后发现,是由下列命令导致 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。从前面的信息看到,lan3eth0 公用了 MAC ,lan4 配置了一个不同于 eth0 的 MAC,然后将 lan4 的 MAC 添加到 eth0单播过滤(unicast filtering) MAC 列表,这样使得 eth0 除了可以接收 lan3 的数据外,也可以接收 lan4 的数据,同时由于 eth0 不支持 单播过滤(unicast filtering) 功能,所以只能将 eth0 配置为 promiscuous(混杂)模式来变相的达到目的。

4. 参考资料

[1] 4.5.3.1. Unicast Frame Filtering
[2] Layerscape Software Development Kit User Guide
[3] UG10081: Layerscape Linux Distribution POC User Guide

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值