udev
Dynamic Kernel Device Management with udev
1 The /dev Directory
The device nodes in the /dev directory provide access to the corresponding kernel devices.The content of the /dev directory is kept on a temporary file system and all files are rendered at every system start-up.
2 Kernel uevents and udev
The required device information is exported by the sysfs file system.For every device the kernel has detected and initialized, a directory with the device name is created. It contains attribute files with device-specific properties.
Every time a device is added or removed, the kernel sends a uevent to notify the udev daemon of the change.
- The udev daemon reads and parses all rules from the /usr/lib/udev/rules.d/*.rules and /etc/udev/rules.d/*.rules files at start-up and keeps them in memory.
- If rules files are changed, added or removed, the daemon can reload their in-memory representation with the command udevadm control --reload.
- The driver core uevents(a MODALIAS string) are received from a kernel netlink socket. Every received event by the udev daemon is matched against the set of provided udev rules.
- add or change event environment keys
- request a specific name for the device node to create
- add symbolic links pointing to the node or add programs to run after the device node is created
The rules can
3 Drivers, Kernel Modules and Devices
The kernel bus drivers probe for devices.For every detected device, the kernel creates an internal device structure while the driver core sends a uevent to the udev daemon. Modalias is a little sysfs trick that exports hardware information to a file named 'modalias'.
The hardware information is told by the hardware to the kernel.
This file simply contains a formatted form of the information normal hardware exposes.
$ cat /sys/devices/pci0000:00/0000:00:1f.0/modalias pci:v00008086d0000A143sv00001043sd00008694bc06sc01i00This specifies a structure for exposing this information.
- the path name This expose the information about the hardware system related to a device:
- pci0000:00. the id for the first PCI bus
- 0000:00:1f.0 the index of the given device on the PCI bus. Specifically, this is on bus 0000:00 and has index 1f.1
$ lspci | grep "00:1f.0" 00:1f.0 ISA bridge: Intel Corporation H110 Chipset LPC/eSPI Controller (rev 31) $ lspci -n | grep "00:1f.0" 00:1f.0 0601: 8086:a143 (rev 31)
- v the vendor id, 00008086
- d the device id, 0000A143
- sv the subsystem version of vendor id, 00001043
- sd the subsystem version of device id, 00008694
- bc base class, 06
- sc sub class, 01
- i Programming interface 00
The kernel takes the device information, composes a MODALIAS string from it and sends that string along with the event.
Every device driver carries a list of known aliases for devices it can handle. The list is contained in the kernel module file itself.
When you run depmod, it reads the ID lists and creates a series of map file in the kernel's /lib/modules/$(uname -r) directory for all currently available modules.
$ find /lib/modules -name modules.alias -print /lib/modules/5.11.0-37-generic/modules.alias /lib/modules/5.11.0-38-generic/modules.alias /lib/modules/5.8.0-43-generic/modules.alias /lib/modules/5.13.0-27-generic/modules.alias /lib/modules/5.11.0-46-generic/modules.alias /lib/modules/5.13.0-28-generic/modules.alias /lib/modules/5.11.0-40-generic/modules.alias /lib/modules/5.11.0-42-generic/modules.alias /lib/modules/5.11.0-44-generic/modules.alias /lib/modules/5.13.0-30-generic/modules.alias /lib/modules/5.11.0-41-generic/modules.aliasThis file module.alias contains aliases, or secondary names for modules. It's a rather simple format of
alias <something> <actual module>For ex., snd_intel8x0m:
$ grep snd_intel8x0m /lib/modules/`uname -r`/modules.alias alias pci:v00001022d0000746Esv*sd*bc*sc*i* snd_intel8x0m alias pci:v000010DEd000000D9sv*sd*bc*sc*i* snd_intel8x0m alias pci:v000010DEd00000089sv*sd*bc*sc*i* snd_intel8x0m alias pci:v000010DEd00000069sv*sd*bc*sc*i* snd_intel8x0m alias pci:v000010DEd000001C1sv*sd*bc*sc*i* snd_intel8x0m alias pci:v00001039d00007013sv*sd*bc*sc*i* snd_intel8x0m alias pci:v00001022d00007446sv*sd*bc*sc*i* snd_intel8x0m alias pci:v00008086d00007196sv*sd*bc*sc*i* snd_intel8x0m alias pci:v00008086d000027DDsv*sd*bc*sc*i* snd_intel8x0m alias pci:v00008086d0000266Dsv*sd*bc*sc*i* snd_intel8x0m alias pci:v00008086d000024D6sv*sd*bc*sc*i* snd_intel8x0m alias pci:v00008086d000024C6sv*sd*bc*sc*i* snd_intel8x0m alias pci:v00008086d00002486sv*sd*bc*sc*i* snd_intel8x0m alias pci:v00008086d00002446sv*sd*bc*sc*i* snd_intel8x0m alias pci:v00008086d00002426sv*sd*bc*sc*i* snd_intel8x0m alias pci:v00008086d00002416sv*sd*bc*sc*i* snd_intel8x0mThe "*" indicates it will match anything.
I can add "alias boogabooga snd_intel8x0m" and then safely "modprobe boogabooga".
$ grep fs- /lib/modules/`uname -r`/modules.alias alias fs-msdos msdos alias fs-virtiofs virtiofs alias fs-binfmt_misc binfmt_misc alias fs-reiserfs reiserfs alias fs-cramfs cramfs ...Each specific module should know what hardware it supports, as it's coded specifically for that hardware.
Look at the modinfo for snd_intel8x0m:
$ modinfo snd_intel8x0m filename: /lib/modules/2.6.14-ARCH/kernel/sound/pci/snd-intel8x0m.ko author: Jaroslav Kysela <perex@suse.cz> description: Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7013; NVidia MCP/2/2S/3 modems license: GPL vermagic: 2.6.14-ARCH SMP preempt 686 gcc-4.1 depends: snd-ac97-codec,snd-pcm,snd-page-alloc,snd alias: pci:v00008086d00002416sv*sd*bc*sc*i* alias: pci:v00008086d00002426sv*sd*bc*sc*i* alias: pci:v00008086d00002446sv*sd*bc*sc*i* alias: pci:v00008086d00002486sv*sd*bc*sc*i* alias: pci:v00008086d000024C6sv*sd*bc*sc*i* alias: pci:v00008086d000024D6sv*sd*bc*sc*i* alias: pci:v00008086d0000266Dsv*sd*bc*sc*i* alias: pci:v00008086d000027DDsv*sd*bc*sc*i* alias: pci:v00008086d00007196sv*sd*bc*sc*i* alias: pci:v00001022d00007446sv*sd*bc*sc*i* alias: pci:v00001039d00007013sv*sd*bc*sc*i* alias: pci:v000010DEd000001C1sv*sd*bc*sc*i* alias: pci:v000010DEd00000069sv*sd*bc*sc*i* alias: pci:v000010DEd00000089sv*sd*bc*sc*i* alias: pci:v000010DEd000000D9sv*sd*bc*sc*i*Each module knows exactly what it supports, and therefore depmod can use that information to help load modules.
These aliases exported by each module, are gathered by depmod and merged into the modules.alias file dynamically.
udev daemon load modules based on the modalias when a new device is added (or when udev is first started on boot).
The following line is part of the default udev rules:
DRIVER!="?*", ENV{MODALIAS}=="?*", RUN{builtin}="kmod load $env{MODALIAS}"If modprobe $ALIAS is called, modprobe looks in the module directory /lib/modules/`uname -r` for all the modules and other files. It matches the device alias composed for the device with the aliases provided by the modules. If a matching entry is found, that module is loaded.
modprobe expects an up-to-date modules.dep.bin file as generated by the depmod. This file lists what other modules each module needs (if any), and modprobe uses this to add or remove these dependencies automatically.
4 Booting and Initial Device Setup
All device events happening during the boot process before the udev daemon is running are lost, therefore, the kernel provides a uevent file located in the device directory of every device in the sysfs file system.udev daemon requests all device events from the kernel after the root file system is available.
A simple loop over all uevent files in /sys triggers all events again to create the device nodes and perform device setup.
5 Monitoring the Running udev Daemon
The program udevadm monitor can be used to visualize the driver core events and the timing of the udev event processes.The events after plug off a USB WiFi dongle:
$ udevadm monitor monitor will print the received events for: UDEV - the event which udev sends out after rule processing KERNEL - the kernel uevent KERNEL[3284.562361] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/net/wlx2c4d54ccfca6/queues/rx-0 (queues) KERNEL[3284.562431] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/net/wlx2c4d54ccfca6/queues/tx-0 (queues) KERNEL[3284.562488] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/net/wlx2c4d54ccfca6 (net) UDEV [3284.566068] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/net/wlx2c4d54ccfca6/queues/rx-0 (queues) UDEV [3284.567845] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/net/wlx2c4d54ccfca6/queues/tx-0 (queues) UDEV [3284.570459] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/net/wlx2c4d54ccfca6 (net) KERNEL[3284.593957] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/ieee80211/phy0/rfkill0 (rfkill) UDEV [3284.596105] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/ieee80211/phy0/rfkill0 (rfkill) KERNEL[3284.610008] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/ieee80211/phy0 (ieee80211) KERNEL[3284.610283] unbind /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0 (usb) KERNEL[3284.610346] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0 (usb) KERNEL[3284.610832] unbind /devices/pci0000:00/0000:00:14.0/usb1/1-8 (usb) KERNEL[3284.610904] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8 (usb) UDEV [3284.612271] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0/ieee80211/phy0 (ieee80211) UDEV [3284.614170] unbind /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0 (usb) UDEV [3284.616314] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8:1.0 (usb) UDEV [3284.618993] unbind /devices/pci0000:00/0000:00:14.0/usb1/1-8 (usb) UDEV [3284.620921] remove /devices/pci0000:00/0000:00:14.0/usb1/1-8 (usb)
- The KERNEL lines show the events the kernel has sent over netlink.
- The UDEV lines show the the event udev sends out after rule processing.
UDEV [3865.660400] remove /devices/pci0000:00/0000:00:14.0/usb1/1-6/1-6.4 (usb) ACTION=remove BUSNUM=001 DEVNAME=/dev/bus/usb/001/006 DEVNUM=006 DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-6/1-6.4 DEVTYPE=usb_device MAJOR=189 MINOR=5 PRODUCT=5e3/723/9451 SEQNUM=4017 SUBSYSTEM=usb TYPE=0/0/0 USEC_INITIALIZED=3865648161udev also sends messages to syslog.
6 Influencing Kernel Device Event Handling with udev Rules
A udev rule can match any property the kernel adds to the event itself or any information that the kernel exports to sysfs.The udev rules are read from the files located in:
- the system rules directory: /lib/udev/rules.d
- the volatile runtime directory: /run/udev/rules.d
- the local administration directory: /etc/udev/rules.d
Rule files must have the extension .rules.
Every line in the rules file contains at least one key-value pair.
- keys The following key names can be used to match against device properties.
- ACTION Match the name of the event action.
- DEVPATH Match the devpath of the event device.
- KERNEL Match the name of the event device.
- NAME Match the name of a network interface. It can be used once the NAME key has been set in one of the preceding rules.
- SYMLINK Match the name of a symlink targeting the node.
- SUBSYSTEM Match the subsystem of the event device.
- DRIVER Match the driver name of the event device.
- ATTR{filename} Match sysfs attribute values of the event device.
- SYSCTL{kernel parameter}
- KERNELS Search the devpath upwards for a matching device name.
- SUBSYSTEMS Search the devpath upwards for a matching device subsystem name.
- DRIVERS Search the devpath upwards for a matching device driver name.
- ATTRS{filename} Search the devpath upwards for a device with matching sysfs attribute values.
- TAGS Search the devpath upwards for a device with matching tag.
- ENV{key} Match against a device property value.
- TAG Match against a device tag.
- TEST{octal mode mask}
- PROGRAM
- RESULT
- operators
- == Compare for equality.
- != Compare for inequality.
- = Assign a value to a key.
- += Add the value to a key that holds a list of entries.
- -= Remove the value from a key that holds a list of entries.
- := Assign a value to a key finally; disallow any later changes.
Each key has a distinct operation, depending on the used operator.
There are two kinds of keys:
- match If all match keys match against their values, the rule gets applied
- assignment The assignment keys get the specified values assigned.
# do not edit this file, it will be overwritten on update # run a command on remove events ACTION=="remove", ENV{REMOVE_CMD}!="", RUN+="$env{REMOVE_CMD}" ACTION=="remove", GOTO="default_end" # console KERNEL=="console", MODE="0600", OPTIONS="last_rule" # serial devices KERNEL=="ttyUSB*", ATTRS{product}=="[Pp]alm*Handheld*", SYMLINK+="pilot" # printer SUBSYSTEM=="usb", KERNEL=="lp*", NAME="usb/%k", SYMLINK+="usb%k", GROUP="lp" # kernel firmware loader SUBSYSTEM=="firmware", ACTION=="add", RUN+="firmware.sh" LABEL="default_end"
- The console rule This consists of three keys: one match(==) key (KERNEL) and two assign(=) keys (MODE, OPTIONS).
- The KERNEL match rule searches the device list for any items of the type console. Only exact matches are valid and trigger this rule to be executed.
- The MODE key assigns special permissions to the device node In this case, read and write permissions to the owner of this device only.
- The OPTIONS key makes this rule the last rule to be applie to any device of this type. Any later rule matching this particular device type does not have any effect.
- The serial devices rule is not available in 50-udev-default.rules anymore, but it is still worth considering. It consists of two match keys (KERNEL and ATTRS) and one assign key (SYMLINK). The KERNEL key searches for all devices of the ttyUSB type. Using the * wild card, this key matches several of these devices. The second match key, ATTRS, checks whether the product attribute file in sysfs for any ttyUSB device contains a certain string. The assign key (SYMLINK) triggers the addition of a symbolic link to this device under /dev/pilot. The operator used in this key (+=) tells udev to additionally perform this action, even if previous or later rules add other symbolic links. As this rule contains two match keys, it is only applied if both conditions are met.
- The printer rule deals with USB printers and contains two match keys which must both apply to get the entire rule applied (SUBSYSTEM and KERNEL). Three assign keys deal with the naming for this device type (NAME), the creation of symbolic device links (SYMLINK) and the group membership for this device type (GROUP). Using the * wild card in the KERNEL key makes it match several lp printer devices. Substitutions are used in both, the NAME and the SYMLINK keys to extend these strings by the internal device name. For example, the symbolic link to the first lp USB printer would read /dev/usblp0.
- The kernel firmware loader rule This rule makes udev load additional firmware by an external helper script during runtime.
- The SUBSYSTEM match key searches for the firmware subsystem.
- The ACTION key checks whether any device belonging to the firmware subsystem has been added.
- The RUN+= key triggers the execution of the firmware.sh script to locate the firmware that is to be loaded.
Hotplugging with udev
udev takes advantage of sysfs, it is entirely in user space.It automatically creates/removes device entriesin /dev/ according to inserted/removed devices.
At the very beginning of user-space startup, udev mounts the /dev/ directory as a tmpfs filesystem:
sudo mount -t tmpfs udev /dev/dev/ is populated with static devices available in /lib/udev/devices/.
The udevd daemon is started.
It listens to uevents from the driver core, which are sent whenever devices are inserted or removed.
The udevd daemon reads and parses all the rules found in /etc/udev/rules.d/ and keeps them in memory.
Whenever rules are added, removed or modified,udevd receives an inotify event and updates itsruleset in memory.
Example, inserting a USB mouse
recv(4, // socket id" add@/class/input/input9/mouse2\0 // message ACTION=add\0 // action type DEVPATH=/class/input/input9/mouse2\0 // path in /sys SUBSYSTEM=input\0 // subsystem (class) SEQNUM=1064\0 // sequence number PHYSDEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-2/2-2:1.0\0// device path in /sys PHYSDEVBUS=usb\0 // bus PHYSDEVDRIVER=usbhid\0 // driver MAJOR=13\0 // major number MINOR=34\0", // minor number2048, // message buffer size 0) // flags = 221 // actual message sizeWhen an event is received, udevd starts a process to:
- try to match the event against udev rules
- create / remove device files
- run programs (to load / remove a driver, to notify user space...)
Writing udev rules
When a udev rule matching event information is found,it can be used:- To define the name and path of a device file. udev naming rule examples:
# Naming testing the output of a program BUS=="scsi", PROGRAM="/sbin/scsi_id", RESULT=="OEM 0815", NAME="disk1" # USB printer to be called lp_color BUS=="usb", SYSFS{serial}=="W09090207101241330", NAME="lp_color" # SCSI disk with a specific vendor and model number will be called boot BUS=="scsi", SYSFS{vendor}=="IBM", SYSFS{model}=="ST336", NAME="boot%n" # sound card with PCI bus id 00:0b.0 to be called dsp BUS=="pci", ID=="00:0b.0", NAME="dsp" # USB mouse at third port of the second hub to be called mouse1 BUS=="usb", PLACE=="2.3", NAME="mouse1" # ttyUSB1 should always be called pda with two additional symlinks KERNEL=="ttyUSB1", NAME="pda", SYMLINK="palmtop handheld" # multiple USB webcams with symlinks to be called webcam0, webcam1, ... BUS=="usb", SYSFS{model}=="XV3", NAME="video%n", SYMLINK="webcam%n"lshw is a small tool to extract detailed information on the hardware configuration of the machine.
*-network description: Ethernet interface product: Intel Corporation vendor: Intel Corporation physical id: 0 bus info: pci@0000:04:00.0 logical name: eno1 version: 03 serial: 38:68:dd:61:73:4c capacity: 1Gbit/s width: 32 bits clock: 33MHz capabilities: bus_master cap_list ethernet physical 10bt 10bt-fd 100bt 100bt-fd 1000bt-fd autonegotiation configuration: autonegotiation=on broadcast=yes driver=igc driverversion=5.13.0-1009-intel firmware=1057:8754 latency=0 link=no multicast=yes port=twisted pair resources: irq:18 memory:50a00000-50afffff memory:50b00000-50b03fff
Identifying device driver modules
Kernel / module compiling:- Each driver announces which device and vendorids it supports. Information stored in module files *.ko.
- The depmod -a command processes module files and generates /lib/modules/$(uname -r)/modules.alias
The Debian Administrator's Handbook: Hot Plugging
1. Introduction
The hotplug kernel subsystem dynamically handles the addition and removal of devices, by loading the appropriate drivers and by creating the corresponding device files (with the help of udevd).The kernel has a database that associates each device ID with the required driver.
This database is used to load all the drivers when :
- booting the peripheral devices detected on the different buses
- hotplugging an additional hotplug device is connected.
2. The Naming Problem
The device name is not fixed; it depends on the order in which devices are connected.Besides, more and more drivers use dynamic values for devices' major/minor numbers, which makes it impossible to have static device numbers for the given devices.
udev was created precisely to solve this problem.
systemd.net-naming-scheme — Network device naming schemes
Ppossible names may be generated by the systemd-udevd.service builtin net_id and exported as udev properties (ID_NET_NAME_ONBOARD=, ID_NET_LABEL_ONBOARD=, ID_NET_NAME_PATH=, ID_NET_NAME_SLOT=).
The naming scheme may also be overridden using the net.naming-scheme= kernel command line switch.
After the udev properties have been generated, appropriate udev rules may be used to actually rename devices based on those properties.
All names start with a two-character prefix that signifies the interface type.
- en Ethernet
- ib InfiniBand
- sl Serial line IP (slip)
- wl Wireless local area network (WLAN)
- ww Wireless wide area network (WWAN)
- ID_NET_NAME_ONBOARD=prefixonumber This name is set based on the numeric ordering information given by the firmware for on-board devices.
- ID_NET_LABEL_ONBOARD=prefix label This property is set based on textual label given by the firmware for on-board devices.
- ID_NET_NAME_MAC=prefixxAABBCCDDEEFF This name consists of the prefix, letter x, and 12 hexadecimal digits of the MAC address.
- ID_NET_NAME_SLOT=prefix[Pdomain]sslot[ffunction][nport_name|ddev_port], ID_NET_NAME_SLOT=prefixvslot, ID_NET_NAME_SLOT=prefixxslot, ID_NET_NAME_SLOT=prefix[Pdomain]sslot[ffunction][nport_name|ddev_port]bnumber, ID_NET_NAME_SLOT=prefix[Pdomain]sslot[ffunction][nport_name|ddev_port]uport…[cconfig][iinterface], ID_NET_NAME_SLOT=prefix[Pdomain]sslot[ffunction][nport_name|ddev_port]vslot This property describes the slot position. Different schemes are used depending on the bus type.
The name consists of the prefix, letter o, and a number specified by the firmware. This is only available for PCI devices.
The name consists of the prefix concatenated with the label. This is only available for PCI devices.
It is available if the device has a fixed MAC address.
Because this name is based on an attribute of the card itself, it remains "stable" when the device is moved (even between machines), but will change when the hardware is replaced.
3. How udev Works
When udev is notified by the kernel of the appearance of a new device, it collects various information(SN, MAC, vendor ID, device ID, ...) on the given device by consulting the corresponding entries in /sys/, especially those that uniquely identify it (MAC address for a network card, serial number for some USB devices, etc.).
With all of this collected information, udev then consults all of the rules contained in /etc/udev/rules.d/ and /lib/udev/rules.d/.
In this process it decides how to name the device, what symbolic links to create (to give it alternative names), and what commands to execute.
All of these files are consulted, and the rules are all evaluated sequentially (except when a file uses “GOTO” directives).
Thus, there may be several rules that correspond to a given event.
The syntax of rules files is quite simple: each row contains selection criteria and variable assignments.
The former are used to select events for which there is a need to react, and the latter defines the action to take.
They are all simply separated with commas, and the operator implicitly differentiates between a selection criterion (with comparison operators, such as == or !=) or an assignment directive (with operators such as =, += or :=).
Selection
Comparison operators are used on the following variables:- KERNEL the name that the kernel assigns to the device
- ACTION the action corresponding to the event (“add” when a device has been added, “remove” when it has been removed);
- DEVPATH the path of the device's /sys/ entry;
- SUBSYSTEM the kernel subsystem which generated the request (there are many, but a few examples are “usb”, “ide”, “net”, “firmware”, etc.);
- ATTR{attribute} file contents of the attribute file in the /sys/$devpath/ directory of the device. This is where you find the MAC address and other bus specific identifiers;
- KERNELS, SUBSYSTEMS and ATTRS{attributes} are variations that will try to match the different options on one of the parent devices of the current device;
- PROGRAM delegates the test to the indicated program (true if it returns 0, false if not). The content of the program's standard output is stored so that it can be reused by the RESULT test;
- RESULT execute tests on the standard output stored during the last call to PROGRAM.
For instance,
- * matches any string (even an empty one);
- ? matches any character, and
- [] matches the set of characters listed between the square brackets (or the opposite thereof if the first character is an exclamation point, and contiguous ranges of characters are indicated like a-z).
Assignment
Regarding the assignment operators,- = assigns a value (and replaces the current value); in the case of a list, it is emptied and contains only the value assigned.
- := does the same as =, but prevents later changes to the same variable.
- += adds an item to a list.
- NAME the device filename to be created in /dev/. Only the first assignment counts; the others are ignored;
- SYMLINK the list of symbolic links that will point to the same device;
- OWNER, GROUP and MODE define the user and group that owns the device, as well as the associated permission;
- RUN the list of programs to execute in response to this event.
- $id, %b The name of the device matched while searching the devpath upwards for SUBSYSTEMS, KERNELS, DRIVERS, and ATTRS.
- $kernel or %k equivalent to KERNEL;
- $number or %n the order number of the device, for example, for sda3, it would be “3”;
- $devpath or %p equivalent to DEVPATH;
- $attr{attribute} or %s{attribute} equivalent to ATTRS{attribute};
- $major or %M the kernel major number of the device;
- $minor or %m the kernel minor number of the device;
- use man dev to get the full list of available substitutions
A concrete example
Rename a USB stick
Let us consider the case of a simple USB stick and try to assign it a fixed name.
- find the elements that will identify it in a unique manner Plug it in and use "lsblk" to find the device name.
- create a new rule, you can use tests on the device's variables, as well as those of one of the parent devices. For example, use 2 variables to create /etc/udev/rules.d/010_local.rules,
- simply remove and reconnect the USB key.
$ lsusb Bus 003 Device 003: ID 8564:1000 Transcend Information, Inc. JetFlashRun
$ udevadm info -a -n /dev/sdb ... looking at device '/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4/1-2.4:1.0/host3/target3:0:0/3:0:0:0/block/sdb': KERNEL=="sdb" SUBSYSTEM=="block" ... looking at parent device '/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2.4': KERNELS=="1-2.4" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{bmAttributes}=="80" ATTRS{speed}=="480" ATTRS{rx_lanes}=="1" ATTRS{bDeviceSubClass}=="00" ATTRS{version}==" 2.00" ATTRS{bDeviceClass}=="00" ATTRS{avoid_reset_quirk}=="0" ATTRS{bMaxPacketSize0}=="64" ATTRS{tx_lanes}=="1" ATTRS{idProduct}=="1000" ATTRS{bMaxPower}=="100mA" ATTRS{product}=="Mass Storage Device" ATTRS{idVendor}=="8564" ATTRS{bNumConfigurations}=="1" ATTRS{devpath}=="2.4" ATTRS{maxchild}=="0" ATTRS{devnum}=="7" ATTRS{bDeviceProtocol}=="00" ATTRS{bNumInterfaces}==" 1" ATTRS{authorized}=="1" ATTRS{bcdDevice}=="0100" ATTRS{quirks}=="0x0" ATTRS{configuration}=="" ATTRS{busnum}=="1" ATTRS{urbnum}=="1112" ATTRS{serial}=="RAVEHPWS" ATTRS{manufacturer}=="JetFlash" ATTRS{bConfigurationValue}=="1" ATTRS{removable}=="unknown" ATTRS{ltm_capable}=="no" ...
KERNEL=="sd?", SUBSYSTEM=="block", ATTRS{idVendor}=="8564", ATTRS{idProduct}=="1000", SYMLINK+="usb_jetflash/disk" KERNEL=="sd?[0-9]", SUBSYSTEM=="block", ATTRS{idVendor}=="8564", ATTRS{idProduct}=="1000", SYMLINK+="usb_jetflash/part%n"
$ tree /dev/usb_jetflash /dev/usb_jetflash |-- disk -> ../sda |-- part1 -> ../sda1 |-- part2 -> ../sda2 |-- part3 -> ../sda3 `-- part4 -> ../sda4
Debugging udev's configuration
To enable debug verbose,$ sudo udevadm control --log-priority=infoTo restart an dtrigger events:
$ sudo udevadm control --reload-rules $ sudo udevadm trigger
Fix a USB modem name
$ lsusb Bus 004 Device 002: ID 2cb7:0104 Fibocom Fibocom Modem_SN:9C08AC4C $ udevadm info -a -n /dev/cdc-wdm0 looking at device '/devices/pci0000:00/0000:00:14.0/usb4/4-4/4-4:1.4/usbmisc/cdc-wdm0': KERNEL=="cdc-wdm0" SUBSYSTEM=="usbmisc" DRIVER=="" looking at parent device '/devices/pci0000:00/0000:00:14.0/usb4/4-4/4-4:1.4': KERNELS=="4-4:1.4" SUBSYSTEMS=="usb" DRIVERS=="qmi_wwan" ATTRS{supports_autosuspend}=="1" ATTRS{bNumEndpoints}=="03" ATTRS{authorized}=="1" ATTRS{bInterfaceProtocol}=="ff" ATTRS{bInterfaceNumber}=="04" ATTRS{bInterfaceSubClass}=="ff" ATTRS{bInterfaceClass}=="ff" ATTRS{bAlternateSetting}==" 0" looking at parent device '/devices/pci0000:00/0000:00:14.0/usb4/4-4': KERNELS=="4-4" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{bNumConfigurations}=="1" ATTRS{bNumInterfaces}==" 5" ATTRS{bConfigurationValue}=="1" ATTRS{quirks}=="0x0" ATTRS{idVendor}=="2cb7" ATTRS{bDeviceSubClass}=="00" ATTRS{removable}=="fixed" ATTRS{busnum}=="4" ATTRS{bmAttributes}=="a0" ATTRS{serial}=="9c08ac4c" ATTRS{idProduct}=="0104" ATTRS{urbnum}=="750" ATTRS{bMaxPacketSize0}=="9" ATTRS{tx_lanes}=="1" ATTRS{ltm_capable}=="no" ATTRS{bDeviceProtocol}=="00" ATTRS{devnum}=="2" ATTRS{manufacturer}=="Fibocom" ATTRS{speed}=="5000" ATTRS{devpath}=="4" ATTRS{bMaxPower}=="896mA" ATTRS{rx_lanes}=="1" ATTRS{bDeviceClass}=="00" ATTRS{bcdDevice}=="0414" ATTRS{product}=="Fibocom Modem_SN:9C08AC4C" ATTRS{version}==" 3.20" ATTRS{configuration}=="DIAG_DUN_SER_NMEA_RMNET" ATTRS{avoid_reset_quirk}=="0" ATTRS{authorized}=="1" ATTRS{maxchild}=="0" looking at parent device '/devices/pci0000:00/0000:00:14.0/usb4': KERNELS=="usb4" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{configuration}=="" ATTRS{speed}=="10000" ATTRS{bMaxPacketSize0}=="9" ATTRS{bNumConfigurations}=="1" ATTRS{bConfigurationValue}=="1" ATTRS{avoid_reset_quirk}=="0" ATTRS{bcdDevice}=="0513" ATTRS{authorized_default}=="1" ATTRS{idProduct}=="0003" ATTRS{devpath}=="0" ATTRS{ltm_capable}=="yes" ATTRS{bmAttributes}=="e0" ATTRS{tx_lanes}=="1" ATTRS{quirks}=="0x0" ATTRS{devnum}=="1" ATTRS{idVendor}=="1d6b" ATTRS{bDeviceProtocol}=="03" ATTRS{bMaxPower}=="0mA" ATTRS{bDeviceClass}=="09" ATTRS{authorized}=="1" ATTRS{rx_lanes}=="1" ATTRS{serial}=="0000:00:14.0" ATTRS{interface_authorized_default}=="1" ATTRS{maxchild}=="4" ATTRS{bDeviceSubClass}=="00" ATTRS{manufacturer}=="Linux 5.13.0-1009-intel xhci-hcd" ATTRS{product}=="xHCI Host Controller" ATTRS{removable}=="unknown" ATTRS{version}==" 3.10" ATTRS{bNumInterfaces}==" 1" ATTRS{busnum}=="4" ATTRS{urbnum}=="42" looking at parent device '/devices/pci0000:00/0000:00:14.0': KERNELS=="0000:00:14.0" SUBSYSTEMS=="pci" DRIVERS=="xhci_hcd" ATTRS{class}=="0x0c0330" ATTRS{irq}=="143" ATTRS{dbc}=="disabled" ATTRS{msi_bus}=="1" ATTRS{device}=="0xa0ed" ATTRS{local_cpus}=="ff" ATTRS{broken_parity_status}=="0" ATTRS{numa_node}=="-1" ATTRS{dma_mask_bits}=="64" ATTRS{driver_override}=="(null)" ATTRS{enable}=="1" ATTRS{subsystem_device}=="0x7270" ATTRS{power_state}=="D0" ATTRS{d3cold_allowed}=="1" ATTRS{consistent_dma_mask_bits}=="64" ATTRS{ari_enabled}=="0" ATTRS{subsystem_vendor}=="0x8086" ATTRS{revision}=="0x20" ATTRS{local_cpulist}=="0-7" ATTRS{vendor}=="0x8086" looking at parent device '/devices/pci0000:00': KERNELS=="pci0000:00" SUBSYSTEMS=="" DRIVERS=="" ATTRS{waiting_for_supplier}=="0"Test if the keys can be matched:
ACTION=="add|change", SUBSYSTEM=="usbmisc", KERNEL=="cdc-wdm*", RUN+="/bin/sh -c 'echo jerry >> /tmp/udevtest.txt'"Create the symlink for all cdc-wdm:
ACTION=="add|change", SUBSYSTEM=="usbmisc", KERNEL=="cdc-wdm*", SYMLINK+="cdc-wdm0"Trigger the rules:
$ sudo udevadm control --reload-rules $ sudo udevadm triggerCheck the log:
$ sudo journalctl | grep cdc-wdm ... May 02 12:47:32 ubuntu systemd-udevd[2710]: cdc-wdm0: /etc/udev/rules.d/69-e200.rules:1 LINK 'cdc-wdm0' May 02 12:47:32 ubuntu systemd-udevd[2710]: cdc-wdm0: /etc/udev/rules.d/70-snap.modem-manager.rules:1013 RUN '/usr/lib/snapd/snap-device-helper $env{ACTION} snap_modem-manager_mbim-network $devpath $major:$minor' May 02 12:47:32 ubuntu systemd-udevd[2710]: cdc-wdm0: /etc/udev/rules.d/70-snap.modem-manager.rules:1016 RUN '/usr/lib/snapd/snap-device-helper $env{ACTION} snap_modem-manager_mbimcli $devpath $major:$minor' May 02 12:47:32 ubuntu systemd-udevd[2710]: cdc-wdm0: /etc/udev/rules.d/70-snap.modem-manager.rules:1019 RUN '/usr/lib/snapd/snap-device-helper $env{ACTION} snap_modem-manager_modemmanager $devpath $major:$minor' May 02 12:47:32 ubuntu systemd-udevd[2710]: cdc-wdm0: /etc/udev/rules.d/70-snap.modem-manager.rules:1022 RUN '/usr/lib/snapd/snap-device-helper $env{ACTION} snap_modem-manager_qmi-network $devpath $major:$minor' May 02 12:47:32 ubuntu systemd-udevd[2710]: cdc-wdm0: /etc/udev/rules.d/70-snap.modem-manager.rules:1025 RUN '/usr/lib/snapd/snap-device-helper $env{ACTION} snap_modem-manager_qmicli $devpath $major:$minor' May 02 12:47:32 ubuntu systemd-udevd[2710]: cdc-wdm0: Handling device node '/dev/cdc-wdm0', devnum=c180:0 May 02 12:47:32 ubuntu systemd-udevd[2710]: cdc-wdm0: Preserve already existing symlink '/dev/char/180:0' to '../cdc-wdm0' May 02 12:47:32 ubuntu systemd-udevd[2710]: cdc-wdm0: Conflicting device node '/dev/cdc-wdm0' found, link to '/dev/cdc-wdm0' will not be created. ...
Tips
How to add the ID of a known-compatible device to a driver (or: making “echo new_id” permanent)?
If a networking device works with the driver already in the kernel, and you know the vendor and device ID.A quick look through the driver source, confirms that my device is not in the device table.
For ex., a uncommon USB WiFi device works with the rt2800usb:
sudo modprobe rt2800usb sudo bash -c "echo 0e66 0004 > /sys/bus/usb/drivers/rt2800/new_id"You can add a udev rule, /etc/udev/rules.d/network_drivers.rules:
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0e66", ATTR{idProduct}=="0004", RUN+="/sbin/modprobe -qba rt2800usb"
How to rename Ethernet devices through udev
Situation
- ethX was replaced with a new NIC. The new NIC is showing as ethY, but it needs to have the same name as the replaced ethX.
- A virtual machine was cloned and eth0 does not show, but an eth1 does.
- Business rules dictate that interface X needs to be known by a certain name.
- A wireless NIC is showing as wlanX but needs to appear as ethX.
Resolution
Renaming Ethernet devices is done through udev.- Identify the hardware MAC address of the Ethernet device
- Open /etc/udev/rules.d/30-net_persistent_names.rules for editing. In this example, the interface eth0 will be renamed to eth5:
- Save the file. Reboot to test changes.
SUBSYSTEM=="net", ACTION=="add", SYSFS{address}=="00:1a:4b:b7:31:13", IMPORT="/lib/udev/rename_netiface %k eth5"
留言