在 Linux 上使用 systemd-udevd 管理连接的硬件

使用 udev 操作 Linux 系统处理物理设备的方式。
107 位读者喜欢这篇文章。
gadgets

Opensource.com

Linux 在自动识别、加载和公开来自无数供应商的连接硬件设备方面做得非常出色。事实上,正是这个特性,多年前说服我坚持让我的雇主将其整个基础设施转换为 Linux。痛点是位于雷德蒙德的某公司无法加载我们 Compaq 台式机上集成网卡的驱动程序,而 Linux 却能轻松做到。

从那时起,Linux 识别设备的库以及该过程的复杂性都得到了极大的增长。而这一切的核心是 udev。Udev 的工作是监听来自 Linux 内核的事件,这些事件涉及设备状态的更改。这可能是一个新的 USB 设备被插入或拔出,或者也可能是一只无线鼠标因浸泡在洒出的咖啡中而离线。

Udev 的工作是处理所有状态更改,例如,通过分配访问设备的名称或权限。可以通过 dmesg 访问这些更改的记录。由于 dmesg 通常会输出数千条条目,因此明智的做法是过滤结果。下面的示例展示了 Linux 如何识别我的 WiFi 接口。它显示了我的无线设备使用的芯片组 (ath9k)、在过程早期分配的原始名称 (wlan0) 以及当前使用的大而丑陋的永久名称 (wlxec086b1ef0b3)

$ dmesg | grep wlan
[    5.396874] ath9k_htc 1-3:1.0 wlxec086b1ef0b3: renamed from wlan0

在本文中,我将讨论为什么有人可能想要使用像这样的名称。在此过程中,我将探讨 udev 配置文件的结构,然后展示如何更改 udev 设置,包括如何编辑系统命名设备的方式。本文基于我的新课程 Linux 系统优化 中的一个模块。

了解 udev 配置系统

在 systemd 机器上,udev 操作由 systemd-udevd 守护程序管理。您可以使用常规的 systemd 方式使用 systemctl status systemd-udevd 检查 udev 守护程序的状态。

从技术上讲,udev 的工作原理是尝试将它接收到的每个系统事件与 /lib/udev/rules.d//etc/udev/rules.d/ 目录中找到的规则集进行匹配。规则文件包括匹配键和赋值键。可用的匹配键集包括 actionnamesubsystem。这意味着,如果检测到具有指定名称且属于指定子系统的设备,则将为其分配预设配置。

然后,“赋值”键/值对用于应用所需的配置。例如,您可以为设备分配一个新名称,将其与文件系统符号链接关联,或限制对特定所有者或组的访问。以下是我工作站中此类规则的摘录

$ cat /lib/udev/rules.d/73-usb-net-by-mac.rules
# Use MAC based names for network interfaces which are directly or indirectly
# on USB and have an universally administered (stable) MAC address (second bit
# is 0). Don't do this when ifnames is disabled via kernel command line or
# customizing/disabling 99-default.link (or previously 80-net-setup-link.rules).

IMPORT{cmdline}="net.ifnames"
ENV{net.ifnames}=="0", GOTO="usb_net_by_mac_end"

ACTION=="add", SUBSYSTEM=="net", SUBSYSTEMS=="usb", NAME=="", \
    ATTR{address}=="?[014589cd]:*", \
    TEST!="/etc/udev/rules.d/80-net-setup-link.rules", \
    TEST!="/etc/systemd/network/99-default.link", \
    IMPORT{builtin}="net_id", NAME="$env{ID_NET_NAME_MAC}"

add 操作告诉 udev 在插入属于网络子系统是 USB 设备的新设备时启动。此外,如果我理解正确,该规则仅在设备的 MAC 地址包含在特定范围内的字符时应用,并且仅当 80-net-setup-link.rules99-default.link 文件存在时才应用。

假设所有这些条件都满足,接口 ID 将更改为与设备的 MAC 地址匹配。还记得之前 dmesg 条目显示我的接口名称是如何从 wlan0 更改为那个讨厌的 wlxec086b1ef0b3 名称吗?那是执行此规则的结果。我怎么知道?因为 ec:08:6b:1e:f0:b3 是设备的 MAC 地址(减去冒号)

$ ifconfig -a
wlxec086b1ef0b3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.0.103  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 fe80::7484:3120:c6a3:e3d1  prefixlen 64  scopeid 0x20<link>
        ether ec:08:6b:1e:f0:b3  txqueuelen 1000  (Ethernet)
        RX packets 682098  bytes 714517869 (714.5 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 472448  bytes 201773965 (201.7 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

此 udev 规则默认存在于 Linux 中。我不必自己编写它。但是为什么要费心呢?尤其是看到处理这样的接口名称有多么困难?再看看规则中包含的注释

# Use MAC based names for network interfaces which are directly or indirectly
# on USB and have an universally administered (stable) MAC address (second bit
# is 0). Don't do this when ifnames is disabled via kernel command line or
# customizing/disabling 99-default.link (or previously 80-net-setup-link.rules).

请注意,此规则专门为基于 USB 的网络接口设计。与 PCI 网络接口卡 (NIC) 不同,USB 设备很可能不时被移除和更换。这意味着无法保证它们的 ID 不会更改。它们可能有一天是 wlan0,第二天是 wlan3。为了避免混淆应用程序,请为设备分配绝对 ID,就像分配给我 USB 接口的 ID 一样。

操作 udev 设置

我的下一个技巧是获取 VirtualBox 虚拟机上以太网网络接口的 MAC 地址和当前 ID,然后使用该信息创建一个新的 udev 规则,该规则将更改接口 ID。为什么?嗯,也许我计划从命令行使用该设备,而不得不键入那么长的名称可能会很烦人。以下是它的工作原理。

在更改我的 ID 之前,我需要禁用 Netplan 当前的网络配置。这将迫使 Linux 注意新的配置。以下是我的 /etc/netplan/ 目录中的当前网络接口配置文件

$ less /etc/netplan/50-cloud-init.yaml
# This file is generated from information provided by
# the datasource.  Changes to it will not persist across an instance.
# To disable cloud-init's network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        enp0s3:
            addresses: []
            dhcp4: true
    version: 2

50-cloud-init.yaml 文件包含一个非常基本的接口定义。但它还在注释中包含了一些关于禁用配置的重要信息。为此,我将移动到 /etc/cloud/cloud.cfg.d 目录并创建一个名为 99-disable-network-config.cfg 的新文件,并添加 network: {config: disabled} 字符串。

虽然我没有在 Ubuntu 以外的发行版上测试过此方法,但它应该适用于任何带有 systemd 的 Linux 版本(几乎所有 Linux 版本都是如此)。无论您使用什么版本,您都将很好地了解如何编写 udev 配置文件并对其进行测试。

接下来,我需要收集一些系统信息。运行 ip 命令报告我的以太网接口名为 enp0s3,其 MAC 地址为 08:00:27:1d:28:10

$ ip a
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:1d:28:10 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.115/24 brd 192.168.0.255 scope global dynamic enp0s3

现在,我将在 /etc/udev/rules.d 目录中创建一个名为 peristent-net.rules 的新文件。我将给文件一个以较小数字 10 开头的名称

$ cat /etc/udev/rules.d/10-persistent-network.rules
ACTION=="add", SUBSYSTEM=="net",ATTR{address}=="08:00:27:1d:28:10",NAME="eth3"

数字越小,Linux 执行该文件的时间越早,我希望这个文件尽早执行。该文件包含的代码将在添加网络设备时为其命名为 eth3,只要其地址与 08:00:27:1d:28:10(即我的接口的 MAC 地址)匹配。

保存文件并重启机器后,我的新接口名称应该就可以使用了。我可能需要直接登录到我的虚拟机并使用 dhclient 手动让 Linux 请求此新命名的网络上的 IP 地址。如果不首先这样做,则可能无法打开 SSH 会话

$ sudo dhclient eth3

完成。因此,您现在能够强制 udev 让您的计算机以您想要的方式引用 NIC。但更重要的是,您已经掌握了解决任何行为异常设备的工具。

接下来阅读什么
标签
David Clinton
DAVID CLINTON 是一名系统管理员、教师和作家。他管理、撰写并创建了许多重要技术主题的培训材料,包括 Linux 系统、云计算(尤其是 AWS)和 Docker 等容器技术。

评论已关闭。

© 2025 open-source.net.cn. All rights reserved.