Una scheda di rete che non va, una scheda video che usa il driver sbagliato, un disco veloce che non compare: prima di tutto bisogna sapere che cosa c'è dentro la macchina. lspci risponde: elenca i dispositivi collegati al bus PCI e, con un'opzione, dice quale driver li sta gestendo. È il compagno naturale di lscpu (il processore) e di lsmod (i moduli del kernel).
Cos'è
Il bus PCI (e il suo successore PCI Express) è il collegamento interno attraverso cui il processore parla con schede di rete, schede video, controller dei dischi, dischi NVMe e molti dispositivi integrati nella scheda madre. lspci (list PCI) fa parte del pacchetto pciutils (su Debian e Ubuntu: sudo apt install pciutils, vedi l'articolo su apt). Legge i dati che il kernel (vedi uname) raccoglie in /sys/bus/pci/ e li traduce in nomi leggibili, usando un archivio di identificativi (pci.ids).
Cosa fa
Elenca ogni dispositivo PCI con il suo indirizzo (bus:dispositivo.funzione), la classe (scheda di rete, controller di archiviazione, scheda video...), il costruttore e il modello. Con le opzioni giuste mostra anche gli identificativi numerici, il driver in uso, la struttura ad albero e i dettagli tecnici. Non modifica niente.
Come si usa
$ lspci [opzioni]Gli esempi dal "sandbox" sono output reali di una macchina virtuale di prova (11 dispositivi virtuali di tipo virtio, con lspci 3.10.0); quelli con web01, il server degli articoli precedenti, sono illustrativi, perché una macchina fisica ha dispositivi diversi.
Esempio 1: l'elenco dei dispositivi
$ lspci
00:00.0 Host bridge: Intel Corporation Device 0d57
00:01.0 Unassigned class [ffff]: Red Hat, Inc. Virtio 1.0 memory balloon (rev 01)
00:02.0 Mass storage controller: Red Hat, Inc. Virtio 1.0 block device (rev 01)
00:03.0 Mass storage controller: Red Hat, Inc. Virtio 1.0 block device (rev 01)
...
00:08.0 Ethernet controller: Red Hat, Inc. Virtio 1.0 network device (rev 01)
00:09.0 Unassigned class [ffff]: Red Hat, Inc. Virtio 1.0 socket (rev 01)
00:0a.0 Unassigned class [ffff]: Red Hat, Inc. Virtio 1.0 RNG (rev 01)
$ lspci | wc -l
11Ogni riga comincia con l'indirizzo del dispositivo, nella forma bus:dispositivo.funzione (qui 00:08.0), seguito dalla classe (Ethernet controller, Mass storage controller, VGA compatible controller...), dal costruttore e dal modello. Se l'archivio dei nomi non conosce un dispositivo, mostra solo Device e il codice (Device 0d57), e se non conosce la classe scrive Unassigned class. Per cercare un tipo di dispositivo si usa grep (vedi l'articolo relativo): lspci | grep -i -E 'ethernet|network|vga|nvme'. Il numero di righe (qui 11) è il numero dei dispositivi; su un server fisico sono di solito decine, perché ci sono anche i bridge e i controller integrati nel chipset.
Esempio 2: quale driver gestisce un dispositivo
$ lspci -k -s 00:08.0
00:08.0 Ethernet controller: Red Hat, Inc. Virtio 1.0 network device (rev 01)
Subsystem: Red Hat, Inc. Virtio 1.0 network device
Kernel driver in use: virtio-pci
$ lspci -k -s 03:00.0 # esempio su web01
03:00.0 Ethernet controller: Realtek RTL8111/8168 PCI Express Gigabit
Subsystem: ASUSTeK Computer Inc. Device 859e
Kernel driver in use: r8169
Kernel modules: r8169Con -k (kernel) si vede il driver in uso: è l'opzione che si usa più spesso. Con -s (slot) si limita l'output a un solo dispositivo, dato il suo indirizzo (si può scrivere anche -s 00: per tutto un bus). Le righe da leggere: Kernel driver in use è il driver che sta gestendo il dispositivo adesso; Kernel modules sono i moduli del kernel che potrebbero gestirlo (vedi l'articolo su lsmod e modinfo). Se Kernel driver in use manca, il dispositivo non ha un driver attivo, ed è il primo indizio quando "la scheda non funziona". Nel sandbox il primo comando mostra solo virtio-pci e non c'è la riga dei moduli, perché il kernel di prova non ha moduli. In più lspci scrive sullo stream di errore Unable to load libkmod resources, per lo stesso motivo: su un sistema normale non compare. Il secondo blocco è illustrativo.
Esempio 3: codici numerici
$ lspci -nn -s 00:00.0
00:00.0 Host bridge [0600]: Intel Corporation Device [8086:0d57]
$ lspci -nn -s 00:08.0 | fold -s -w 70
00:08.0 Ethernet controller [0200]: Red Hat, Inc. Virtio 1.0 network
device [1af4:1041] (rev 01)
$ lspci -n -s 00:08.0
00:08.0 0200: 1af4:1041 (rev 01)
$ lspci -d 1af4: | wc -l
10
$ lspci -d ::0200
00:08.0 Ethernet controller: Red Hat, Inc. Virtio 1.0 network device (rev 01)
$ lspci -D | head -n 1
0000:00:00.0 Host bridge: Intel Corporation Device 0d57Con -nn accanto ai nomi compaiono i codici numerici tra parentesi quadre: la classe (0200 = scheda di rete) e la coppia costruttore:modello (1af4:1041). Sono utili quando il nome non è noto, o per cercare informazioni precise (un driver, un errore, un bollettino) senza ambiguità. Con -n si hanno solo i numeri. Con -d si filtra: -d 1af4: tutti i dispositivi di un costruttore, -d ::0200 per classe. Con -D si mostra anche il "dominio" davanti all'indirizzo (0000:), come lo scrive il kernel nei suoi percorsi. Nel secondo esempio, fold -s -w 70 spezza la riga lunga a 70 caratteri, solo per farla stare nella pagina: l'output reale è su una riga sola.
Esempio 4: i dettagli di un dispositivo
$ lspci -v -s 00:08.0
00:08.0 Ethernet controller: Red Hat, Inc. Virtio 1.0 network device (rev 01)
Subsystem: Red Hat, Inc. Virtio 1.0 network device
Flags: bus master, fast devsel, latency 0
Memory at 4000380000 (64-bit, non-prefetchable) [size=512K]
Capabilities: [98] MSI-X: Enable+ Count=3 Masked-
Kernel driver in use: virtio-pci
$ sudo lspci -vv -s 03:00.0 | grep -E 'LnkCap|LnkSta' # esempio su web01
LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1
LnkSta: Speed 2.5GT/s, Width x1
$ lspci -vv -s 00:08.0 | grep -c 'access denied' # senza privilegi
1-v (verbose) aggiunge i dettagli: flag, aree di memoria, funzioni supportate (Capabilities); -vv e -vvv ne aggiungono ancora, fino alla velocità e alla larghezza del collegamento PCI Express (LnkCap è il massimo possibile, LnkSta è quello in uso: se sono diversi, per esempio un disco veloce collegato a velocità ridotta, il dispositivo non rende quanto potrebbe). Il primo blocco è reale (ho ridotto le righe Capabilities iniziali). Il secondo è illustrativo. Il terzo l'ho provato con un utente senza privilegi: alcune informazioni, come le Capabilities, compaiono solo con sudo, e senza compare <access denied>.
Esempio 5: la struttura ad albero
$ lspci -t
-[0000:00]-+-00.0
+-01.0
+-02.0
...
+-08.0
+-09.0
\-0a.0
$ lspci -tv | head -n 4
-[0000:00]-+-00.0 Intel Corporation Device 0d57
+-01.0 Red Hat, Inc. Virtio 1.0 memory balloon
+-02.0 Red Hat, Inc. Virtio 1.0 block device
+-03.0 Red Hat, Inc. Virtio 1.0 block deviceCon -t (tree) i dispositivi sono disegnati ad albero, che mostra come sono collegati tra loro: dal bus principale (00) ai bridge e ai bus secondari. Con -tv compaiono anche i nomi. Su un server fisico l'albero è più profondo (per esempio una scheda di rete sotto un bridge PCI Express): serve a capire "dietro a cosa" sta un dispositivo, o a trovare quelli che dividono lo stesso collegamento. Nel sandbox, tutto è collegato direttamente al bus 00.
Esempio 6: una forma adatta agli script
$ lspci -vmm -s 00:08.0
Slot: 00:08.0
Class: Ethernet controller
Vendor: Red Hat, Inc.
Device: Virtio 1.0 network device
SVendor: Red Hat, Inc.
SDevice: Virtio 1.0 network device
Rev: 01
ProgIf: 00
$ lspci -mm -s 00:08.0
00:08.0 "Ethernet controller" "Red Hat, Inc." "Virtio 1.0 network device" -r01 -p00
$ cat /sys/bus/pci/devices/0000:00:08.0/vendor
0x1af4
$ readlink /sys/bus/pci/devices/0000:00:08.0/driver
../../../bus/pci/drivers/virtio-pciPer l'elaborazione automatica l'output normale non è adatto, perché cambia forma da riga a riga. Con -vmm si ha un blocco Campo: valore per ogni dispositivo (campi separati da tabulazioni, un blocco separato dall'altro da una riga vuota), con -mm una riga per dispositivo con i campi tra virgolette. Le informazioni arrivano comunque dal kernel, in /sys/bus/pci/devices/: ogni dispositivo ha una cartella con file semplici (vendor, device, class, il collegamento driver), e si leggono anche senza lspci (utile su un sistema minimale, o in un container di cui si ha il /sys). Nell'ultimo esempio readlink mostra il driver in uso. Il codice del costruttore, scritto in esadecimale (0x1af4), è lo stesso di -nn.
Esempio 7: uso negli script
#!/bin/bash
# Elenca i dispositivi PCI senza un driver in uso (esclusi i bridge)
ESCLUSI='Host bridge|PCI bridge|ISA bridge'
SENZA=$(lspci -k 2>/dev/null | awk '
/^[0-9a-f]/ { if (dev != "" && !drv) print dev; dev = $0; drv = 0; next }
/Kernel driver in use/ { drv = 1 }
END { if (dev != "" && !drv) print dev }' | grep -v -E "$ESCLUSI")
if [ -n "$SENZA" ]; then
echo "Dispositivi senza driver:" >&2
echo "$SENZA" >&2
exit 1
fi
echo "Tutti i dispositivi hanno un driver"Lo script legge l'output di lspci -k con awk (vedi l'articolo relativo): una riga che inizia con una cifra o una lettera esadecimale è l'inizio di un nuovo dispositivo, e se il precedente non aveva la riga Kernel driver in use lo stampa. I bridge, che non sempre hanno un driver, sono esclusi con grep -v. Se trova qualcosa termina con l'errore (exit 1: è comodo per cron, vedi l'articolo su crontab). L'ho provato nel sandbox, dove risponde "Tutti i dispositivi hanno un driver", e con un lspci finto che contiene una scheda video senza driver, dove l'ha segnalata e ha terminato con codice 1. Un dispositivo senza driver non è sempre un problema (può essere inutilizzato, o gestito da un programma in user space): è un'indicazione da valutare.
Opzioni utili
lspci: elenco;-k: con driver e moduli;-v,-vv,-vvv: più dettagli;-s indirizzo: un solo dispositivo.-n: solo codici numerici;-nn: nomi e codici;-d costruttore:modelloo-d ::classe: filtra;-D: indirizzo con il dominio.-t: albero dei collegamenti;-tv: albero con i nomi.-m,-mm,-vmm: output per i programmi (-mmè la forma consigliata).-x: lo spazio di configurazione in esadecimale (per chi sa leggerlo);-xxx: in modo esteso (solo amministratore).update-pciids: aggiorna l'archivio dei nomi dei dispositivi (richiede la rete).lsusb,lsblk,lsmod,dmesg,ip: i dispositivi USB, i dischi, i moduli, i messaggi del kernel, le interfacce di rete.
Attenzione a
- Mostra solo i dispositivi PCI: non elenca le periferiche USB (si usa
lsusb, del pacchetto usbutils), i dischi SATA (che sono dietro un controller: vedilsblk), né le interfacce di rete (vediip). Un disco NVMe invece compare, perché è un dispositivo PCI Express. - Un dispositivo elencato non è un dispositivo funzionante:
lspcimostra che l'hardware è presente e il kernel lo ha visto. Se funziona lo dice il driver: guardaKernel driver in usee i messaggi didmesg(sudo dmesg | grep -i firmwareè una prova utile per i driver che chiedono un file di firmware). - Nei container e nelle macchine virtuali i dati sono quelli che l'ambiente espone: in un container si vedono di solito i dispositivi della macchina ospite (o niente); in una macchina virtuale i dispositivi sono virtuali, come nel sandbox (
virtio), e i driver in uso possono essere un "generico" comevirtio-pci. - I nomi dipendono dall'archivio
pci.ids: un dispositivo recente può comparire comeDevice 0d57finché l'archivio non viene aggiornato (conupdate-pciids, che ha bisogno della rete, o con l'aggiornamento del pacchetto). I codici di-nnrestano il riferimento sicuro. - Il messaggio
Unable to load libkmod resourcescompare quandolspci -knon trova l'elenco dei moduli del kernel in uso (è il caso del sandbox, che non ha moduli). Su un sistema normale non si vede; se lo vedi, di solito manca la cartella/lib/modules/del kernel in esecuzione, ad esempio dopo un aggiornamento senza riavvio. - Alcuni dettagli richiedono
sudo:-vve simili mostrano il campoCapabilitiessolo all'amministratore (altrimenti<access denied>); per le informazioni di base non serve. - Non si modifica niente con
lspci, masetpcisì: lo stesso pacchetto contienesetpci, che scrive nei registri di un dispositivo. Un valore sbagliato può bloccare l'hardware o l'intero sistema: va usato solo se si sa esattamente cosa si sta facendo. - Gli indirizzi cambiano: l'indirizzo di un dispositivo (
03:00.0) dipende dalla posizione fisica e può cambiare dopo l'aggiunta di una scheda o un aggiornamento del BIOS. Per riconoscere un dispositivo in modo stabile, meglio i codicicostruttore:modello.
Riepilogo
| Comando | Cosa fa |
|---|---|
lspci | Elenca i dispositivi PCI |
lspci | grep -i ethernet | Cerca un tipo di dispositivo |
lspci -k | Mostra anche il driver in uso e i moduli |
lspci -k -s 00:08.0 | Driver di un solo dispositivo |
lspci -nn | Nomi e codici numerici |
lspci -d 1af4: | Filtra per costruttore (o per classe: -d ::0200) |
sudo lspci -vv -s 00:08.0 | Dettagli completi di un dispositivo |
lspci -t, lspci -tv | Albero dei collegamenti |
lspci -vmm | Output a campi, per gli script |
cat /sys/bus/pci/devices/*/vendor | Dati grezzi dal kernel |
sudo update-pciids | Aggiorna l'archivio dei nomi |