Il kernel di Linux non contiene tutto il necessario dall'inizio: i driver per le schede di rete, i file system meno comuni, le funzioni del firewall o della virtualizzazione sono spesso moduli, pezzi di codice che vengono caricati solo quando servono. Per sapere quali sono attivi in questo momento si usa lsmod. È il comando da cui partire quando un dispositivo "non viene riconosciuto", o quando un programma si lamenta che manca una funzione del kernel.
Cos'è
lsmod (list modules) fa parte del pacchetto kmod, insieme a modprobe, modinfo, insmod, rmmod e depmod. Non fa altro che leggere il file /proc/modules (e le informazioni in /sys/module/), che il kernel (vedi l'articolo su uname) aggiorna a ogni caricamento o rimozione, e metterlo in una tabella ordinata. Non serve essere amministratori per leggere.
Cosa fa
Mostra, per ogni modulo caricato, il nome, la dimensione in memoria e chi lo sta usando: il numero di utilizzi e i nomi degli altri moduli che ne dipendono. Quest'ultima informazione è la più utile, perché un modulo in uso non si può rimuovere. Per i dettagli su un modulo si usa modinfo, per caricarlo o scaricarlo modprobe.
Come si usa
$ lsmodUn avviso prima di cominciare: il kernel della macchina di prova che uso per verificare i comandi è stato compilato senza supporto ai moduli, quindi lsmod non può mostrare nulla di reale. Per questo gli esempi sono stati provati così: il programma lsmod (kmod 31) è quello vero, ma i dati che legge (/proc/modules e /sys/module) li ho preparati io, in un ambiente isolato, con un piccolo gruppo di moduli reali di un kernel Ubuntu (6.8). Il formato è quindi quello vero; i valori (dimensioni, utilizzi) sono illustrativi, e quelli di un server come web01, il server degli articoli precedenti, saranno diversi. Per modinfo e modprobe -n (esempi 3 e 4) ho invece usato i file dei moduli veri di quel kernel.
Esempio 1: l'elenco dei moduli
$ lsmod
Module Size Used by
nf_tables 372736 2 nft_compat,nft_chain_nat
nft_chain_nat 12288 0
nft_compat 20480 0
bridge 421888 0
stp 12288 1 bridge
llc 16384 2 stp,bridge
dummy 12288 0Le colonne: Module è il nome; Size è la dimensione in byte occupata in memoria; Used by comincia con un numero (quante volte il modulo è usato) seguito dai nomi dei moduli che dipendono da lui. Qui stp è usato da bridge, e llc da stp e da bridge: caricando bridge il sistema carica prima, da solo, llc e stp. Un 0 senza altri nomi significa che nessuno lo usa in questo momento. Attenzione: il numero non è sempre uguale al numero dei nomi, perché può contare anche utilizzi che non sono moduli (un dispositivo aperto, un file system montato). Su un server vero l'elenco ha di solito decine o centinaia di righe.
Esempio 2: cercare e ordinare
$ lsmod | grep -w bridge
bridge 421888 0
$ lsmod | grep -q '^bridge' && echo presente
presente
$ lsmod | sort -k2 -n -r | head -n 3
bridge 421888 0
nf_tables 372736 2 nft_compat,nft_chain_nat
nft_compat 20480 0
$ lsmod | awk 'NR > 1 && $3 == 0 {print $1}'
nft_chain_nat
nft_compat
bridge
dummy
$ lsmod | tail -n +2 | wc -l
7Per cercare un modulo si usa grep; con -w (parola intera) si evita di trovare nomi che lo contengono (vedi l'articolo su grep). Il secondo comando è la forma da usare negli script: grep -q non stampa nulla, e il risultato sta nel codice d'uscita. Con sort -k2 -n -r i moduli si ordinano per dimensione, dal più grande (la prima riga, l'intestazione, finisce in fondo e non conta). Con awk si estraggono i nomi di quelli con 0 utilizzi (la terza colonna: vedi l'articolo su awk), cioè quelli che si potrebbero scaricare. Il conteggio con tail -n +2 salta l'intestazione. Il file grezzo è /proc/modules: contiene gli stessi dati in una forma meno leggibile, con gli indirizzi di memoria, e si legge anche con cat. Se il kernel non supporta i moduli, come nel sandbox, lsmod risponde could not open /proc/modules: No such file or directory (questo messaggio l'ho visto).
Esempio 3: le informazioni su un modulo
$ modinfo bridge | head -n 9
filename: /lib/modules/6.8.0-31-generic/kernel/net/bridge/bridge.ko.zst
description: Ethernet bridge driver
alias: rtnl-link-bridge
version: 2.3
license: GPL
srcversion: 161BFDA8E18BE2AA8758647
depends: llc,stp
retpoline: Y
intree: Y
$ modinfo -F description dummy
Dummy netdevice driver which discards all packets sent to it
$ modinfo -F depends bridge
llc,stp
$ modinfo -p dummy
numdummies:Number of dummy pseudo devices (int)
$ modinfo nonesiste
modinfo: ERROR: Module nonesiste not found.modinfo legge l'intestazione del file del modulo (un file con estensione .ko, qui compresso in .ko.zst, nella cartella /lib/modules/ del kernel in uso). I campi più utili: description (a cosa serve), depends (da quali altri moduli dipende), license, alias (i nomi con cui il sistema lo cerca) e parm, i parametri che si possono impostare (per dummy, numdummies, il numero di interfacce da creare). Con -F (field) si stampa solo un campo, comodo negli script; con -p solo i parametri. Se il modulo non esiste per il kernel in uso, o lo si è scritto male, risponde con l'errore. Il filename e i campi sono stati letti, nel sandbox, dai file veri di un kernel Ubuntu 6.8; il percorso lo mostro come sarebbe in un sistema normale. I moduli firmati mostrano anche campi lunghi (signature, sig_key): per questo conviene limitare l'output con head.
Esempio 4: caricare e scaricare un modulo
$ sudo modprobe -n -v bridge
insmod /lib/modules/6.8.0-31-generic/kernel/net/llc/llc.ko.zst
insmod /lib/modules/6.8.0-31-generic/kernel/net/802/stp.ko.zst
insmod /lib/modules/6.8.0-31-generic/kernel/net/bridge/bridge.ko.zst
$ modprobe --show-depends bridge
$ sudo modprobe bridge
$ sudo modprobe -r bridge
$ sudo modprobe -n -v -r bridge
rmmod bridge
$ sudo modprobe nonesiste
modprobe: FATAL: Module nonesiste not found in directory /lib/modules/6.8.0-31-genericmodprobe è il comando giusto per caricare un modulo, perché risolve da solo le dipendenze: per bridge carica prima llc e stp. Con -n (dry run) e -v (verbose) mostra cosa farebbe, senza farlo: ed è il modo più sicuro per capire un'operazione prima di eseguirla. --show-depends stampa le stesse righe insmod (l'elenco delle dipendenze, in ordine di caricamento). Con -r (remove) il modulo viene scaricato; con -n -v -r si vede cosa verrebbe rimosso. Gli esempi con -n, e il messaggio d'errore sul modulo inesistente, li ho provati sul kernel 6.8 di prova (usando le sue cartelle con l'opzione -d: i percorsi sono quelli che compaiono su un sistema normale). Il caricamento e la rimozione veri (sudo modprobe bridge, -r) non li ho potuti eseguire, perché il kernel del sandbox non li supporta. Esiste anche insmod file.ko, che carica un file senza risolvere le dipendenze, e rmmod nome, che scarica un modulo: di solito è meglio modprobe.
Esempio 5: i parametri di un modulo
$ cat /sys/module/loop/parameters/max_loop
8
$ cat /sys/module/8250/parameters/nr_uarts
1
$ ls /sys/module | wc -l
77
$ sudo modprobe dummy numdummies=2I parametri dei moduli compaiono in /sys/module/NOME/parameters/, un file per parametro, con il valore corrente (la lettura è libera). I due valori sono reali: vengono dal kernel del sandbox, dove questi moduli sono compilati dentro il kernel (built-in) e quindi non compaiono in lsmod, ma hanno comunque la loro cartella. Anche il conteggio di /sys/module (77 qui) include i moduli built-in: è un numero diverso da quello di lsmod. Per impostare un parametro al caricamento si scrive nome=valore dopo il nome del modulo (l'ultima riga: illustrativa, non eseguibile nel sandbox). Alcuni parametri si possono cambiare anche a modulo caricato, scrivendo nel file corrispondente, ma solo se il modulo lo permette.
Esempio 6: renderlo permanente
$ cat /etc/modules-load.d/prova.conf
# Moduli da caricare all'avvio, uno per riga
br_netfilter
overlay
$ cat /etc/modprobe.d/prova.conf
# Parametri dei moduli e moduli esclusi
options dummy numdummies=2
blacklist pcspkr
$ modprobe -c | grep blacklist | head -n 3
blacklist ath_pci
blacklist ohci1394
blacklist sbp2Un modulo caricato a mano scompare al riavvio. Per caricarlo a ogni avvio si elenca (uno per riga) in un file .conf dentro /etc/modules-load.d/: è la strada giusta, per esempio, per br_netfilter e overlay richiesti da Docker e Kubernetes (vedi anche l'articolo su sysctl, perché alcuni parametri di rete esistono solo dopo il caricamento di un modulo). Nella cartella /etc/modprobe.d/ si scrivono invece le regole di modprobe: options per impostare i parametri, blacklist per impedire il caricamento automatico di un modulo. I file si modificano con nano (vedi l'articolo relativo). Con modprobe -c (showconfig) si vede la configurazione completa: l'ultimo blocco, con le prime righe di blacklist, l'ho provato nel sandbox. Dopo aver cambiato i file, su Debian e Ubuntu si aggiorna l'immagine di avvio con sudo update-initramfs -u, se il modulo serve in fase di avvio. Gli esempi dei file prova.conf sono illustrativi.
Esempio 7: quale modulo gestisce un dispositivo
$ lspci -k | grep -A 3 -i ethernet
03:00.0 Ethernet controller: Realtek RTL8111/8168 PCI Express Gigabit
Subsystem: ASUSTeK Computer Inc. Device 859e
Kernel driver in use: r8169
Kernel modules: r8169
$ lsmod | grep r8169
r8169 110592 0
$ modinfo -F description r8169
Realtek RTL8169 Gigabit Ethernet driverIl blocco è illustrativo (l'ho adattato a un caso tipico: una scheda di rete su web01). lspci -k (del pacchetto pciutils) mostra, per ogni dispositivo PCI, il driver in uso (Kernel driver in use) e i moduli possibili (Kernel modules); è il passaggio tra "ho questa scheda" e "il suo driver è questo modulo". Poi si controlla con lsmod che sia caricato, e con modinfo che cosa fa. Se la riga Kernel driver in use manca, il dispositivo non ha un driver attivo: è il momento di cercare un modulo adatto, o un pacchetto con il firmware (vedi apt e dmesg: il kernel scrive lì se un driver non riesce a partire). Per i dispositivi USB c'è lsusb. Questi due comandi non li ho provati nel sandbox.
Esempio 8: uso negli script
#!/bin/bash
# Verifica che i moduli necessari siano caricati
MODULI="bridge br_netfilter overlay"
MANCANTI=0
for M in $MODULI; do
if ! lsmod | awk -v m="$M" '$1 == m {trovato = 1} END {exit !trovato}'; then
echo "Modulo non caricato: $M" >&2
MANCANTI=$((MANCANTI + 1))
fi
done
[ "$MANCANTI" -eq 0 ] && echo "Tutti i moduli sono caricati"
exit "$MANCANTI"Lo script controlla l'elenco di moduli e segnala quelli assenti; il codice d'uscita è il numero dei mancanti (0 vuol dire che va tutto bene, e cron o un altro script possono accorgersene: vedi l'articolo su crontab). Il confronto è sul nome intero nella prima colonna con awk, così bridge non viene confuso con br_netfilter o con un modulo che contiene la parola. L'ho provato, con il vero lsmod e i dati preparati di cui sopra: con i moduli bridge e stp presenti, e l'elenco bridge br_netfilter overlay, ha segnalato i due mancanti e ha terminato con codice 2; con il solo stp nell'elenco, ha risposto che tutti erano caricati, con codice 0.
Opzioni utili
lsmod: elenco dei moduli caricati; non ha opzioni utili: si combina congrep,sorteawk.modinfo modulo: dettagli;-F campo: un solo campo (description,depends,filename,license...);-p: i parametri.modprobe modulo: carica (con le dipendenze);-r: scarica;-n -v: mostra cosa farebbe;--show-depends: elenca le dipendenze;-c: mostra la configurazione.insmod file.ko,rmmod modulo: caricamento e rimozione "a basso livello", senza dipendenze.depmod -a: ricostruisce l'indice delle dipendenze (di norma lo fa l'installazione dei pacchetti del kernel)./proc/modules,/sys/module/: i dati grezzi;/etc/modules-load.d/,/etc/modprobe.d/: la configurazione.lspci -k,lsusb: i dispositivi con i loro driver;dmesg: i messaggi del kernel;uname -r: la versione del kernel.
Attenzione a
lsmodnon mostra i moduli built-in: un driver compilato dentro il kernel non compare nell'elenco, anche se funziona. Se un modulo "manca" inlsmod, controlla/lib/modules/$(uname -r)/modules.builtine la cartella/sys/module/prima di concludere che non c'è.- Un modulo in uso non si rimuove:
modprobe -rfallisce con un errore (Module ... is in use) se l'utilizzo è diverso da zero. Prima si fermano i programmi o i dispositivi che lo usano (guarda la colonnaUsed by). Evitarmmod -f, che forza la rimozione e può bloccare il sistema. - Non scaricare moduli a caso su un server in produzione: la rimozione di un driver di rete o di un disco può interrompere la connessione, anche SSH, e la macchina non si raggiunge più. Prova prima con
modprobe -n -v -r, e meglio in una sessionetmuxo con accesso alla console. - Un modulo caricato a mano non è permanente: serve un file in
/etc/modules-load.d/, come nell'esempio 6. blacklistnon è un divieto assoluto: impedisce il caricamento automatico per nome, ma il modulo si può ancora caricare a mano, o da un altro modulo che ne dipende. Per un divieto vero si usa una rigainstall nome /bin/falsenel file dimodprobe.d.- I moduli sono legati alla versione del kernel: dopo un aggiornamento e un riavvio, quelli del kernel nuovo sono in un'altra cartella di
/lib/modules/; un modulo compilato fuori dall'albero ufficiale (per esempio un driver proprietario) va ricostruito, di solito in automatico con DKMS. - Con Secure Boot i moduli non firmati sono rifiutati: un driver esterno non firmato non si carica, e l'errore può essere poco chiaro (
Key was rejected by service); i dettagli sono indmesg. - Nei container non si caricano moduli: il kernel è quello della macchina ospite, e il contenitore non può né caricarli né scaricarli (di solito); un modulo richiesto dal container va caricato sul sistema ospite.
- Non è una misura della memoria: la colonna
Sizedice quanto occupa il modulo, non il lavoro che svolge; per la memoria del sistema vedifree.
Riepilogo
| Comando | Cosa fa |
|---|---|
lsmod | Elenca i moduli caricati, con dimensioni e utilizzi |
lsmod | grep -w nome | Controlla se un modulo è caricato |
lsmod | sort -k2 -n -r | head | I moduli più grandi |
modinfo nome | Dettagli su un modulo |
modinfo -F description nome | Solo la descrizione |
modinfo -p nome | I parametri del modulo |
sudo modprobe -n -v nome | Mostra cosa caricherebbe, senza farlo |
sudo modprobe nome | Carica un modulo con le dipendenze |
sudo modprobe -r nome | Scarica un modulo |
/etc/modules-load.d/*.conf | Moduli da caricare all'avvio |
/etc/modprobe.d/*.conf | Parametri (options) ed esclusioni (blacklist) |
lspci -k | Driver e moduli dei dispositivi PCI |