排查Linux一处网络设备命名问题

陪她去流浪 桃子 阅读次数:19

我的小主机接入了两个网络:一个是通过网线有线接入的(流量有限,速度较快),一个是通过WiFi无线接入的(流量较多,速度较慢)。这样的网络配置我用了很久,但是某天重启了系统后,突然发现处于同一有线网络内的SSH居然连不上它了。以下排查问题过程。

背景

文件“/etc/network/interfaces”的内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
  metric 500

auto wlan0
iface wlan0 inet dhcp
  metric 300

简单解释一下:

  • eth0wlan0分别是有线和无线网络;
  • 均设置成DHCP自动获取IP地址;
  • 无线网络的优先级更高(metric更低);

有线网络网段是192.168.10.0/24,无线网络网段是192.168.0.0/24

现象

SSH走TCP连接不上后,我尝试用SSH走蓝牙连接1,查看当前的IP地址时,发现两个IP地址均在192.168.0.0/24。太神奇了不是吗?我的eth0明明是走有线连接到路由器的,路由器完全正常工作(有子网、有DHCP……)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
$ ifconfig eth0; ifconfig wlan0;
eth0      Link encap:Ethernet  HWaddr 34:4B:50:00:00:00
          inet addr:192.168.0.104  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::364b:50ff:fe00:0/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1542 errors:0 dropped:0 overruns:0 frame:0
          TX packets:374 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:419837 (409.9 KiB)  TX bytes:217831 (212.7 KiB)

wlan0     Link encap:Ethernet  HWaddr F8:AC:65:DA:62:40
          inet addr:192.168.0.102  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::faac:65ff:feda:6240/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:144725816 errors:0 dropped:0 overruns:0 frame:0
          TX packets:50473211 errors:0 dropped:1 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:171787073182 (159.9 GiB)  TX bytes:5691888559 (5.3 GiB)

让Codex排查了一番,它居然跟我说是因为我的路由器把小主机的DHCP请求转发/桥接给了路由器的上级,所以IP是来自……上级的上级。我网络中上级的上级的IP网段确实在192.168.0.0/24,这一度让我差点信以为真。我最终没有相信Codex的说法,因为:

  • 我目前的路由器网络中已有很多设备在正常工作中,完全没有出现过此类问题;
  • 我在路由器上抓包并没有抓到来自小主机的DHCP请求(包含转发/桥接的)。

排查

对比小主机的eth0和路由器的eth1(它们“物理”相连)的ifconfig后我发现,路由器的eth1显示“NO-CARRIER”。也就是说,路由器的LAN口并没有“承载网络”————没有和任何设备相连。所以,Codex前面说路由器转发/桥接了小主机的DHCP请求完全是一派胡言。

斩断这条路线后,我马上有了自己的结论:这两个IP地址都来自无线网络

等等,eth0一听就是有线网络设备(例如:RJ45端口)的名字啊,怎么可能也来自无线网络?好问题,我“隐瞒”了一个事实:此无线网络是一个USB随身WiFi设备,是插在小主机的USB上供电的。

也就是说,我这个便宜的随身WiFi设备可能支持USB供网;同时,我的小主机也安装了USB CDC 以太网络驱动

然后我再次让Codex根据我的思路重新查了一下,果然不出我所料:

因为 Linux 里的 eth* 不等于“RJ45 口”。任何看起来像以太网的设备都可能叫 ethX。

我查到小主机上实际是:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
eth0: USB CDC Ethernet
driver: cdc_ether
device: ZTE CDC Ethernet Device / USB Mobile Broadband
MAC: 34:4b:50:00:00:00
state: up

eth1: 板载 Intel 有线网卡,也就是外壳上的 RJ45
driver: e1000e
MAC: 1c:69:7a:6d:27:2e
state: down

所以答案是:你的 eth0 不是那个 RJ45 口,而是一个 USB 设备暴露出来的“虚拟以太网”接口,看起来像 ZTE 移动宽带/USB 网络设备。它先被内核注册,所以拿到了名字 eth0;真正的 RJ45 反而叫 eth1。

另外,一开始我没主动意识到这个问题还有另外一个原因:ifconfig不会显示“DOWN”状态的网卡,而ip link会显示。我第一次用的是前者,没有想到这一层问题。

我好奇Codex查了什么数据库知道那个eth0的详细描述信息的。发现它查了以下信息:

1
/sys/class/net/eth0/device -> /sys/devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0

然后查到了这是个USB CDC(Communications Device Class)设备,然后就查了驱动描述符信息,找到了设备厂商等较详细的信息。

如此一来,我前面配置在/etc/network/interfaces中的带具体名字的配置就可能已经失效了。

网络接口名字被抢占的问题

我的小主机物理自带一个RJ45网口,挂在PCIe上。按理说会被内核极早地识别并加载(然后命名),为什么会被插入的USB抢了先?难以理解。

所以,我觉得手动永久地给我的RJ45端口绑定一个固定的名字。

我用的系统是AlpineLinux,Codex告诉内核的接口热插拔管理是mdev负责的:

1
2
3
4
root@nuc:~ → cat /proc/sys/kernel/hotplug
/sbin/mdev
root@nuc:~ → ls -lh /sbin/mdev
lrwxrwxrwx    1 root     root          12 Apr 22 08:32 /sbin/mdev -> /bin/busybox

mdev会读取/etc/mdev.conf文件,其中配置了网络接口如何管理,如下:

1
2
3
4
5
# net devices
# 666 is fine: https://www.kernel.org/doc/Documentation/networking/tuntap.txt
net/tun[0-9]*	root:netdev 0666
net/tap[0-9]*	root:netdev 0666
SUBSYSTEM=net;INTERFACE=.*;.*   root:root 600 @test -r /etc/mactab && nameif -s

其中的/etc/mactab文件用于列出接口名与MAC地址的对应规则,nameif命令按此规则给新的接口命名。

当然,不再建议使用ethX这种命名规则,太容易冲突了。所以我选择了“lanX”:

1
2
$ cat /etc/mactab
lan0 1C:69:7A:6D:27:2E

重启系统或者网络后,一切就回归正常了。