9.4. 管理设备

9.4.1. 网络设备

Udev 在默认情况下,根据固件或 BIOS 的数据,或总线、插槽,以及 MAC 地址等物理特性命名网络设备。这种命名法的主要目的是保证网络设备在每次引导时获得一致的命名,而不是基于网卡被系统发现的时间进行命名。例如,如果在一台拥有两块网卡 —— 例如,其中一块由 Intel 生产,另一块由 Realtek 生产 —— 的计算机使用旧版的 Linux,则 Intel 网卡可能被命名为 eth0,而 Realtek 网卡被命名为 eth1。然而在重新启动系统后,它们的顺序可能会颠倒。

在新的命名架构中,典型的网络设备名称类似 enp5s0 或 wlp3s0。如果您不喜欢这种命名惯例,可以采用传统或自定义命名架构。

9.4.1.1. 在内核命令行中禁用一致性命名

传统的,类似 eth0,eth1 这样的命名格式可以通过在内核命令行中加入 net.ifnames=0 而恢复。这在那些没有两块同类以太网设备的机器上最为合适。笔记本一般拥有两个以太网连接,在这种命名方式下分别是 eth0 和 wlan0;也可以为这些笔记本采用这种方法。内核命令行需要写入 GRUB 配置文件中,参阅第 10.4.4 节 “创建 GRUB 配置文件”

9.4.1.2. 创建自定义 Udev 规则

可以创建自定义 Udev 规则,定制命名架构。系统中包含一个生成初始规则的脚本,执行以下命令生成初始规则:

bash /usr/lib/udev/init-net-rules.sh

现在检查文件 /etc/udev/rules.d/70-persistent-net.rules,确认网络设备与命名的对应关系:

cat /etc/udev/rules.d/70-persistent-net.rules
[注意]

注意

某些情况下,例如 MAC 地址被手动指定给了某块网卡,或在 Qemu、Xen 等虚拟环境下,可能不会生成网络设备规则文件,因为 MAC 地址的分配没有一致性。此时不能使用这种方法。

该文件的开头是一个注释块,之后对于每个网络接口设备 (NIC) 都给出两行。第一行是注释,给出该 NIC 的硬件 ID (例如对于 PCI 设备,就是 PCI 生产商 ID 和设备 ID),以及其驱动程序的名称 (在括号中,如果能找到驱动程序的话)。它们并不被用于确定该设备的命名,仅供您在编写规则时进行参考。第二行是匹配该 NIC 的 udev 规则,和实际赋予它的设备名。

所有 udev 规则包含一些关键字,用逗号和可选的空格进行分隔。下面给出规则中包含的关键字和对它们的解释:

  • SUBSYSTEM=="net" - 告诉 udev 忽略除网卡以外的设备。

  • ACTION=="add" - 告诉 udev 忽略除了“添加”外的所有 uevent (也存在“删除”或“修改”类型的 uevent,但在这种情况下不需要重命名网络接口)。

  • DRIVERS=="?*" - 这使得 udev 忽略 VLAN 或桥接子接口 (它们没有驱动程序)。它们必须被忽略,否则其命名会与父设备冲突。

  • ATTR{address} - 该关键字的值是 NIC 的 MAC 地址。

  • ATTR{type}=="1" - 这保证在使用创建多个虚拟接口的无线驱动程序时,只匹配主要接口。跳过其他接口的原因和忽略 VLAN 与桥接子接口一样,是为了防止命名冲突。

  • NAME - 该关键字的值是 udev 将赋予该网络接口的命名。

NAME 的值是我们关注的重点。在继续阅读之前,您需要确保自己知道赋予每个网络接口的命名,在之后的配置文件中需要使用 NAME 的值。

即使使用了自定义的 udev 规则文件,udev 仍然可能根据物理特性,为网卡分配一个或多个备用命名。如果某条自定义 udev 规则试图将某个网卡重命名为另一网卡的备用命名,则这条 udev 规则会失败。如果出现这类问题,可以创建 /etc/udev/network/99-default.link 文件并在其中将备用命名规则置空,以覆盖默认配置文件 /usr/lib/udev/network/99-default.link 的设置:

sed -e '/^AlternativeNamesPolicy/s/=.*$/=/'  \
       /usr/lib/udev/network/99-default.link \
     > /etc/udev/network/99-default.link

9.4.2. CD-ROM 符号链接

您之后可能希望安装的一些程序 (如某些媒体播放器) 预期 /dev/cdrom/dev/dvd 符号链接存在,并指向 CD-ROM 或 DVD-ROM 设备。另外,在 /etc/fstab 中引用它们也非常方便。Udev 提供了一个脚本,能根据每个设备的功能,为您生成创建这两个符号链接的规则。但是,您需要确定,自己希望使用该脚本提供的两种操作模式中的哪一种。

首先,该脚本可以在 by-path 模式下运行 (这是 USB 和 FireWire 设备的默认模式),此时它创建的规则依赖于 CD 或 DVD 设备的物理路径。其次,它可以在 by-id 模式下运行,此时它创建的规则依赖于 CD 或 DVD 设备本身存储的识别字符串。物理路径由 udev 的 path_id 脚本确定,而识别字符串由 ata_idscsi_id 程序 (根据设备类型选用其中一个) 从硬件中读取。

两种方式各有优点;正确的方式依赖于设备可能发生的变化。如果您预期指向设备的物理路径 (即它连接的端口或插槽) 可能变化,例如您可能会将它移动到另一个 IDE 接口或另一个 USB 接口,您应该使用 by-id 模式。另一方面,如果您可能用具有相同功能,并接入相同接口的另一台设备替换它 (因为设备可能损坏),则应该使用 by-path 模式。

如果两种变化都可能发生,则根据您预期较常发生的变化选择模式。

[重要]

重要

外接设备 (例如 USB 接口的 CD 驱动器) 不应使用 by-path 模式,因为每次将该设备插入到新的外部接口时,其物理路径都可能变化。只要您使用了基于物理路径识别外接设备的 udev 规则,都会导致这个问题,并不仅限于 CD 或 DVD 设备。

如果您希望知道 udev 脚本会使用的路径或识别字符串值,对于正确的 CD-ROM 驱动器,在 /sys 目录中找到对应的目录 (例如 /sys/block/hdd),然后运行类似下面这样的命令:

udevadm test /sys/block/hdd

观察包含一些 *_id 程序输出的行。by-id 模式在 ID_SERIAL 存在且非空时会使用它,否则就使用 ID_MODEL 和 ID_REVISION 的组合。by-path 模式会使用 ID_PATH 的值。

如果默认模式不适合您的情况,可以像下面这样修改 /etc/udev/rules.d/83-cdrom-symlinks.rules 文件 (将 mode 替换成 by-idby-path 中的一个):

sed -e 's/"write_cd_rules"/"write_cd_rules mode"/' \
    -i /etc/udev/rules.d/83-cdrom-symlinks.rules

注意现在并不需要创建规则文件和符号链接,因为已经绑定挂载了宿主的 /dev 目录,我们假定宿主系统存在正确的符号链接。只要在第一次引导 LFS 系统后创建规则和符号链接即可。

然而,如果您有多个 CD-ROM 设备,则生成的符号链接可能指向不同于您的宿主系统的设备,因为设备发现的顺序不可预测。在您第一次引导 LFS 系统后,创建的设备分配将会是稳定的,因此这仅在您希望宿主系统和 LFS 中的符号链接指向同一设备时才会成为问题。如果您有这种需求,在引导后检查 (如果需要的话修改) 生成的 /etc/udev/rules.d/70-persistent-cd.rules 文件,保证分配的符号链接和您的需要一致。

9.4.3. 处理重复设备

正如第 9.3 节 “设备和模块管理概述”中所述,那些功能相同的设备在 /dev 中的顺序是随机的。例如,如果您有一个 USB 摄像头和一个电视棒,有时 /dev/video0 会指向摄像头,/dev/video1 指向电视棒,而有时在重启后这个顺序正好颠倒过来。对于所有除了声卡和网卡以外的设备,该问题都可以通过建立 udev 规则以创建持久化符号链接来解决。对于网卡的解决方案在第 9.5 节 “一般网络配置”中单独描述,而声卡配置可以在 BLFS 中找到。

对于您的每个可能有这类问题的设备 (即使在您当前使用的 Linux 发行版上并没有问题),找到 /sys/class/sys/block 中的对应目录。对于视频设备,目录可能是 /sys/class/video4linux/videoX。找出能够唯一确认该设备的属性 (通常是厂商和产品 ID,或者序列号):

udevadm info -a -p /sys/class/video4linux/video0

然后编写创建符号链接的规则,例如:

cat > /etc/udev/rules.d/83-duplicate_devs.rules << "EOF"

# 摄像头和电视棒的持久化符号链接
KERNEL=="video*", ATTRS{idProduct}=="1910", ATTRS{idVendor}=="0d81", SYMLINK+="webcam"
KERNEL=="video*", ATTRS{device}=="0x036f",  ATTRS{vendor}=="0x109e", SYMLINK+="tvtuner"

EOF

结果是,/dev/video0/dev/video1 仍然会随机指向电视棒和摄像头 (因此不应直接使用它们),但符号链接 /dev/tvtuner/dev/webcam 总会指向正确设备。