在 Linux 使用 systemd-udevd 管理你的接入硬體
Linux 能夠出色地自動識別、載入、並公開接入的無數廠商的硬體設備。事實上,很多年以前,正是這個特性說服我,堅持讓我的僱主將整個基礎設施轉換到 Linux。痛點在於 Redmond 的某家公司(LCTT 譯註:指微軟)不能在我們的 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/
目錄下找到的規則集進行匹配。規則文件包括匹配鍵和分配鍵,可用的匹配鍵包括 action
、name
和 subsystem
。這意味著如果探測到一個屬於某個子系統的、帶有特定名稱的設備,就會給設備指定一個預設的配置。
接著,「分配」鍵值對被拿來應用想要的配置。例如,你可以給設備分配一個新名稱、將其關聯到文件系統中的一個符號鏈接、或者限制為只能由特定的所有者或組訪問。這是從我的工作站摘出的一條規則:
$ 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.rules
和 99-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
Linux 默認包含這條 udev 規則,我不需要自己寫。但是為什麼費力進行這樣的命名呢——尤其是看到這樣的介面命名這麼難使用後?仔細看一下包含在規則中的注釋:
對直接或間接插入在 USB 上的網路介面使用基於 MAC 的名稱,並且用一個普遍提供的(穩定的)MAC 地址(第二位是 0)。當 ifnames 通過內核命令行或
customizing/disabling 99-default.link
(或之前的80-net-setup-link.rules
)被禁用時,不要這樣做。
注意,這個規則專為基於 USB 的網路介面設計的。和 PCI 網路介面卡(NIC)不同,USB 設備很可能時不時地被移除或者替換,這意味著無法保證它們的 ID 不變。某一天 ID 可能是 wlan0
,第二天卻變成了 wlan3
。為了避免迷惑應用程序,指定絕對 ID 給設備——就像分配給我的 USB 介面的 ID。
操作 udev 的設置
下一個示例中,我將從 VirtualBox 虛擬機里抓取乙太網介面的 MAC 地址和當前介面 ID,然後用這些信息創建一個改變介面 ID 的 udev 新規則。為什麼這麼做?也許我打算從命令行操作設備,需要輸入那麼長的名稱讓人十分煩惱。下面是工作原理。
改變介面 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
目錄,創建一個名為 /etc/cloud/cloud.cfg.d
的新文件,插入 network: {config: disabled}
字元串。
儘管我只在 Ubuntu 發行版上測試了這個方法,但它應該在任何一個帶有 systemd 的 Linux(幾乎所有的 Linux 發行版都有 systemd)上都可以工作。不管你使用哪個,都可以很好地了解編寫 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 控制計算機按照你想要的方式指向一個網卡,但更重要的是,你已經有了一些工具,可以弄清楚如何管理任何不聽話的設備。
via: https://opensource.com/article/20/2/linux-systemd-udevd
作者:David Clinton 選題:lujun9972 譯者:YungeG 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive