Linux中國

在 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/ 目錄下找到的規則集進行匹配。規則文件包括匹配鍵和分配鍵,可用的匹配鍵包括 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

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&apos;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

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國