一致的网络接口设备命名

Linux 内核通过将固定前缀与随着内核初始化网络设备而增加的数字连接在一起,来为网络接口分配名称。例如,eth0 代表启动时被探测的第一个设备。如果您在系统中添加另一个网卡,则内核设备名称的分配将不再是固定的。因此,重启后内核可能会以不同的方式为该设备命名。

要解决这个问题,`udev` 设备管理器支持几种不同的命名方案。默认情况下,`udev` 根据固件、拓扑和位置信息分配固定名称。它有以下优点: 	
  • 设备名称完全可预测。
  • 即使添加或删除了硬件,设备名称也会保持不变,因为不会进行重新枚举。
  • 因此,有问题的硬件可以被无缝地替换。

网络接口设备命名等级

​ 如果启用了一致的设备命名(在 Red Hat Enterprise Linux 中是默认设置),则 udev 设备管理器会根据以下方案生成设备名称:

方案 描述 示例
1 设备名称包含固件或者 BIOS 提供的索引号,用于板上的设备。如果此信息不可用或不适用,则 udev 将使用方案 2。 eno1
2 设备名称包含固件或 BIOS 提供的 PCI Express(PCIe)热插件插槽索引号。如果此信息不可用或不适用,则 udev 将使用方案 3。 ens1
3 设备名称包含硬件连接器的物理位置。如果此信息不可用或不适用,则 udev 将使用方案 5。 enp2s0
4 设备名称包含 MAC 地址。Red Hat Enterprise Linux 默认不使用这个方案,但管理员可选择性地使用它。 enx525400d5e0fb
5 传统的无法预计的内核命名方案。如果 udev 无法应用任何其他方案,则设备管理器使用这个方案。 eth0

​ 默认情况下,Red Hat Enterprise Linux 根据 /usr/lib/systemd/network/99-default.link 文件中的 NamePolicy 设置选择设备名称。NamePolicy 中值的顺序非常重要。Red Hat Enterprise Linux 使用文件中指定的和 udev 生成的第一个设备名称。

​ 如果您手动配置 udev 规则来更改内核设备名称,则这些规则优先。

可以通过udevadm test /sys/class/net/eth0这个命令查看某个网卡使用了哪些命名规则。

image-20230827144703282

image-20230827144723324

网络设备重命名是如何工作的

​ 默认情况下,在 Red Hat Enterprise Linux 中启用了一致的设备命名。udev 设备管理器会处理不同的规则来重命名设备。udev 服务按以下顺序处理这些规则:

  1. /usr/lib/udev/rules.d/60-net.rules 文件定义了 /lib/udev/rename_device 帮助工具搜索 /etc/sysconfig/network-scripts/ifcfg-* 文件中的 HWADDR 参数。如果变量中设置的值与接口的 MAC 地址匹配,则帮助工具会将接口重命名为文件的 DEVICE 参数中设置的名称。

  2. /usr/lib/udev/rules.d/71-biosdevname.rules 文件定义了 biosdevname 工具根据其命名策略重命名接口,只要它在上一步中没有重命名。

  3. /usr/lib/udev/rules.d/75-net-description.rules 文件定义了 udev 检查网络接口设备,并在 udev-internal 变量中设置在下一步中将要处理的属性。请注意,其中一些属性可能没有定义。

  4. /usr/lib/udev/rules.d/80-net-setup-link.rules 文件调用内置的 net_setup_link udev ,然后应用策略。以下是存储在 /usr/lib/systemd/network/99-default.link 文件中的默认策略:

    1
    2
    3
    [Link]
    NamePolicy=kernel database onboard slot path
    MACAddressPolicy=persistent

    有了这个策略,如果内核使用持久名称,则 udev 不会重命名接口。如果内核不使用持久名称,则 udev 会将接口重命名为 udev 的硬件数据库提供的名称。如果这个数据库不可用,Red Hat Enterprise Linux 会回复到上述机制中。

    另外,对于基于介质访问控制(MAC)地址的接口名称,将此文件中的 NamePolicy 参数设为 mac

  5. /usr/lib/udev/rules.d/80-net-setup-link.rules 文件定义了 udev 按以下顺序,根据 udev-internal 参数重命名接口:

    1. ID_NET_NAME_ONBOARD
    2. ID_NET_NAME_SLOT
    3. ID_NET_NAME_PATH

    如果没有设置参数,则 udev 将使用下一个参数。如果没有设置任何参数,接口就不会被重命名。

使用 udev 规则分配用户定义的网络接口名称

udev 设备管理器支持一组规则来自定义接口名称。

步骤

  1. 显示所有网络接口及其 MAC 地址:

    1
    2
    3
    4
    5
    6
    7
    8
    # ip link list

    enp6s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether b4:96:91:14:ae:58 brd ff:ff:ff:ff:ff:ff
    enp6s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether b4:96:91:14:ae:5a brd ff:ff:ff:ff:ff:ff
    enp4s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 00:90:fa:6a:7d:90 brd ff:ff:ff:ff:ff:ff
  2. 使用以下内容创建文件 /etc/udev/rules.d/70-custom-ifnames.rules

    1
    2
    3
    SUBSYSTEM=="net",ACTION=="add",ATTR{address}=="b4:96:91:14:ae:58",ATTR{type}=="1",NAME="provider0"
    SUBSYSTEM=="net",ACTION=="add",ATTR{address}=="b4:96:91:14:ae:5a",ATTR{type}=="1",NAME="provider1"
    SUBSYSTEM=="net",ACTION=="add",ATTR{address}=="00:90:fa:6a:7d:90",ATTR{type}=="1",NAME="dmz"

    这些规则与网络接口的 MAC 地址相匹配,并将它们重命名为 NAME 属性中指定的名称。在这些示例中,ATTR{type} 参数值 1 定义了接口类型为 Ethernet。

验证

  1. 重启系统:

    1
    # reboot
  2. 验证每个 MAC 地址的接口名称是否与您在规则文件的 NAME 参数中设置的值相匹配:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # ip link show

    provider0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether b4:96:91:14:ae:58 brd ff:ff:ff:ff:ff:ff
    altname enp6s0f0
    provider1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether b4:96:91:14:ae:5a brd ff:ff:ff:ff:ff:ff
    altname enp6s0f1
    dmz: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 00:90:fa:6a:7d:90 brd ff:ff:ff:ff:ff:ff
    altname enp4s0f0

使用 systemd 链接文件分配用户定义的网络接口名称

​ 通过将网络接口重命名为 provider0来创建一个命名方案。

流程

  1. 显示所有接口名称及其 MAC 地址:

    1
    2
    3
    4
    5
    6
    7
    8
    # ip link show

    enp6s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether b4:96:91:14:ae:58 brd ff:ff:ff:ff:ff:ff
    enp6s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether b4:96:91:14:ae:5a brd ff:ff:ff:ff:ff:ff
    enp4s0f0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 00:90:fa:6a:7d:90 brd ff:ff:ff:ff:ff:ff
  2. 创建 /etc/systemd/network/ 目录:

    1
    # mkdir /etc/systemd/network/
  3. 要将 MAC 地址为 b4:96:91:14:ae:58 的接口命名为 provider0,请创建包含以下内容的 /etc/systemd/network/70-custom-ifnames.link 文件:

    1
    2
    3
    4
    5
    [Match]
    MACAddress=b4:96:91:14:ae:58

    [Link]
    Name=provider0

    此链接文件与 MAC 地址相匹配,并将网络接口重命名为 Name 参数中设置的名称。

验证

  1. 重启系统:

    1
    # reboot
  2. 验证 MAC 地址为您在链接文件中指定的设备是否已分配给 provider0

    1
    2
    3
    4
    # ip link show

    provider0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether b4:96:91:14:ae:58 brd ff:ff:ff:ff:ff:ff

使用 systemd 链接文件向网络接口分配额外的名称

​ 备用接口命名允许内核为网络接口设置备用名称。默认情况下,它提供与常规接口命名设置 - NamePolicy 相同的命名方案 。您可以使用 AlternativeNamesPolicyAlternativeName 指令编写自定义 systemd 链接文件,来向您选择的网络接口提供备用名称。

​ 备用接口命名的最新实现可让您:

  • 创建任意长度的备用名称。
  • 同一网络接口有一个或多个备用名称。
  • 使用备用名称作为命令的句柄。

先决条件

  • 您知道介质访问控制(MAC)地址或其他网络接口标识符。详情请查看 systemd.link(5) 中的 [MATCH] SECTION OPTIONS 部分。

流程

  1. 使用以下内容创建 /etc/systemd/network/10-altnames.link 文件:

    1
    2
    3
    4
    5
    6
    [Match]
    MACAddress=52:54:00:76:e0:2a

    [Link]
    AlternativeName=production_alias_of_arbitrary_length
    AlternativeName=PRD
  2. 重启系统以使更改生效。

验证

  • 您可以使用备用名称来显示网络接口的状态:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # ip address show production_alias_of_arbitrary_length
    2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:76:e0:2a brd ff:ff:ff:ff:ff:ff
    altname production_alias_of_arbitrary_length
    altname PRD
    inet 192.0.2.1/24 brd 192.0.2.255 scope global dynamic noprefixroute enp1s0
    valid_lft 2760sec preferred_lft 2760sec
    inet6 2001:db8::/64 scope link noprefixroute
    valid_lft forever preferred_lft forever

Systemd is the rapidly evolving mother-ship of Linux initialisation systems (and rather more besides) and one that most popular distributions now use (in recent versions at least) including RHEL, Fedora, CentOS, Debian, Ubuntu, Arch, and CoreOS. This brings us some degree of ‘standardization’ in how we configure networking on these distributions. It’s not complete and it’s a work in progress, but it surely is progress.

Systemd 是 Linux 初始化系统(以及更多其他系统)快速发展的母舰,也是现在最流行的发行版(至少在最近的版本中)使用的系统,包括 RHEL、Fedora、CentOS、Debian、Ubuntu、Arch 和 CoreOS。这给我们在这些发行版上配置网络的方式带来了一定程度的“标准化”。它尚未完成,仍在进行中,但它确实是进步。

Systemd first touches the networking stack in relation to hardware, with the udev device manager, the core library of which was merged into systemd in 2012 (it used to be a separate project). You can do pretty much everything you’d want with a network interface using udev, but it’s jarring if you are used to the legacy configuration methods and it seems rather odd to be configuring IP addressing in a hardware device configuration file, thus systemd-networkd was born. I’ll cover networkd in a following piece, but suffice to say it deals with things in a more logical, better-defined way. Why cover udev at all then? Well, networkd is pretty new and it’ll be a while before it’s widespread so for now, udev is probably the best thing most have at their disposal and it’s still very useful.

Systemd 首先通过 udev 设备管理器触及与硬件相关的网络堆栈,其核心库于 2012 年合并到 systemd 中(它曾经是一个单独的项目)。你可以使用 udev 通过网络接口做几乎所有你想做的事情,但是如果你习惯了传统的配置方法,那么它会很不和谐,并且在硬件设备配置文件中配置 IP 寻址似乎很奇怪,因此 systemd-networkd出生于。我将在下一篇文章中介绍网络,但足以说明它以更逻辑、更明确的方式处理事物。那么为什么要覆盖 udev 呢?嗯,网络是相当新的东西,它还需要一段时间才能广泛使用,所以就目前而言,udev 可能是大多数人可以使用的最好的东西,而且它仍然非常有用。

In essence, you can run any command you’d like to use to configure the interface via udev, such as ethtool, ip and dhclient. Better yet, consistent network device naming is fully supported and you don’t need to rely on MAC addresses for identification (despite the numerous examples you’ll find via Google). I’m not aware of any Network Operating Systems (NOSs) using systemd at present, but I’m sure it’s in the pipeline so I’ll continue and anyway, we all need to be silo free and multi-disciplinary right?

本质上,您可以运行任何您想用来通过 udev 配置接口的命令,例如 ethtool、ip 和 dhclient。更好的是,完全支持一致的网络设备命名,并且您不需要依赖 MAC 地址进行识别(尽管您可以通过 Google 找到大量示例)。我目前不知道有任何网络操作系统 (NOS) 使用 systemd,但我确信它正在酝酿之中,所以我会继续,无论如何,我们都需要摆脱孤岛和多学科,对吗?

Remove Network Manager

You might not even know it’s in use, but Network Manager can conflict with udev in strange and unusual ways so I prefer to simply remove it. This isn’t strictly required and may not be necessary but if you hit problems, its an extra complication. Be aware that doing so will probably result in the host losing all network connectivity on reboot if udev encounters an error, but hey, we’re just doing this on a vm right? Here’s a few examples of how to do so, depending on your distribution (further suggestions welcome):

您甚至可能不知道它正在使用,但网络管理器可能会以奇怪和不寻常的方式与 udev 发生冲突,因此我更愿意简单地将其删除。这不是严格要求的,也可能不是必要的,但如果你遇到问题,那就会变得更加复杂。请注意,如果 udev 遇到错误,这样做可能会导致主机在重新启动时丢失所有网络连接,但是嘿,我们只是在虚拟机上执行此操作,对吧?以下是一些如何执行此操作的示例,具体取决于您的发行版(欢迎进一步建议):

Consistent Network Device Naming

The bane of Linux for many a year, physical network interfaces were typically named and numbered based on the order in which the kernel detected them, which could be change on each boot. Imagine a switch randomly assigning different numbers to its physical interfaces on each boot. Fine if they are all configured the same, far from it if not. This issue was resolved around 2012 with the fairly widespread implementation of the biosdevname module, based on a standard created in 2009. Things were slower back then right?

As I’ve mentioned, most examples I’ve seen when searching using Google and others seem to rely on matching the interface using its MAC address. This seems to be at odds with the whole point of consistent naming and won’t work well with vm images, Vagrant or containers. Of course, with embedded interfaces on physical servers it’s not a problem because the MAC will never change.

正如我所提到的,我在使用 Google 和其他搜索时看到的大多数示例似乎都依赖于使用 MAC 地址来匹配接口。这似乎与一致命名的整体要点相矛盾,并且不能很好地与 vm 镜像、Vagrant 或容器配合使用。当然,对于物理服务器上的嵌入式接口来说,这不是问题,因为 MAC 永远不会改变。

The match is used by udev to identify an interface to be configured, just to reiterate, it’s specified in this file:

1
/etc/udev/rules.d/70-persistent-net.rules

It’s taken me an age to find an alternative but the PCI bus identifier seems rather more reliable than a MAC address. You can find out what it is by using this command (you’ll probably have to install the pciutils package to make this command available):

我花了很长时间才找到替代方案,但 PCI 总线标识符似乎比 MAC 地址更可靠。您可以使用此命令找出它是什么(您可能必须安装 pciutils 软件包才能使此命令可用):

1
lspci

Here’s what the output looks like with a embedded interface on physical servers:

1
2
00:19.0 Ethernet controller: Intel Corporation Ethernet Connection (2) I218-LM (rev 05)
08:00.0 Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev 03)

image-20230827132307358

We can now use the data with an entry in the file like this:

1
SUBSYSTEM=="net", ACTION=="add", KERNELS=="0000:08:00.0", NAME=="ethlab2"

To set the speed and duplex (scroll right):

1
SUBSYSTEM=="net", ACTION=="add", KERNELS=="0000:08:00.0", NAME=="ethlab", RUN+="/sbin/ethtool -s '%k' speed 100 duplex full autoneg off"

‘%k’ Is a variable that represents the device name udev has given to the network interface. I know we’ve called it bingo already, but even if our ‘rename’ fails, the ethtool and ip link commands will still succeed.

‘%k’ 是一个变量,表示 udev 赋予网络接口的设备名称。我知道我们已经将其称为 ethlab,但即使我们的“重命名”失败,ethtool 和 ip link 命令仍然会成功。

Let’s make use of DHCP too (and log things verbosely with -v):

1
SUBSYSTEM=="net", ACTION=="add", KERNELS=="0000:08:00.0", NAME=="ethlab", RUN+="/sbin/ethtool -s '%k' speed 100 duplex full autoneg off", RUN+="/sbin/ip link set mtu 1400 dev '%k'", RUN+="dhclient -v '%k'"

Testing

You can force a reload of udevd and its functions with this command:

1
systemctl restart systemd-udevd

Note that if you’ve manually reconfigured an interface handled by udev, this will revert those changes if the settings in question are specified in a valid .rules file. Also note that restarting udev will not bring an interface UP if it has been manually set to DOWN and there is no command to bring it UP in a valid .rules file. A reboot however, will.

请注意,如果您手动重新配置了由 udev 处理的接口,并且在有效的 .rules 文件中指定了相关设置,则这将恢复这些更改。另请注意,如果已手动将接口设置为 DOWN 并且在有效的 .rules 文件中没有命令将其恢复为 UP,则重新启动 udev 不会将其恢复为 UP。然而,重新启动就会。

You can also ‘test’ changes using this command, but I’ve found this isn’t too helpful (perhaps I’m wrong):

1
udevadm test /sys/class/net/eth0 | less

Logging

The logging level for udev can be controlled by editing this configuration file: /etc/udev/udev.conf like so:

1
dev_log="info" #Change to err, debug etc. or a syslog number as required

You can inspect the log entries generated by udev using this command (-b restricts things to boot time entries, remove it if you want everything):

1
journalctl -b |grep udev

Debug

所有配置文件:

1
2
/usr/lib/udev/rules.d/
/etc/udev/rules.d/
1
sudo vim /etc/udev/rules.d/10-local.rules
1
2
3
#SUBSYSTEM=="net", ACTION=="add", KERNELS=="0000:08:00.0", NAME=="ethlab2"
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="fc:4d:d4:3e:cd:2d",ATTR{type}=="1", NAME="ethlab"

查看某个网络设备的信息

1
sudo udevadm test /sys/class/net/eth0

列出某个设备的所有属性

1
udevadm info -ap /devices/pci0000:00/0000:00:1c.2/0000:08:00.0/net/eth0

image-20230827165659758

1
2
sudo systemctl restart systemd-udevd && sudo systemctl status systemd-udevd
sudo udevadm control --reload-rules && sudo udevadm trigger
1
journalctl -b |grep udev

Linux Network Interface Configuration With udev

Chapter 1. Consistent network interface device naming

Change “eth0” interface name and reload udev rules without a reboot

What is wrong with my udev rule?

在Linux中如何编写基本的udev规则

Predictable Network Interface Names

使用 biosdevname 的一致网络设备命名