Debian 11, KVM e br0: sostituire una scheda di rete instabile con una USB Ethernet 2.5G

Scenario

Su un server Debian GNU/Linux 11 Bullseye con kernel 5.10.0-38-amd64 avevo una configurazione abbastanza classica per un host KVM/QEMU:

eno1 -> br0 -> VM

La macchina aveva IP statico sulla LAN 192.168.50.0/24:

  • server: 192.168.50.23
  • gateway/router: 192.168.50.254
  • DNS locale Pi-hole: 192.168.50.10

Il bridge usato dalle VM era br0. La scheda fisica integrata era eno1, gestita dal driver e1000e.

Il problema era semplice da vedere ma meno simpatico da subire: ogni tanto la rete cadeva, poi tornava su. Questo impattava sia l’host sia le VM, perche’ eno1 era la porta fisica del bridge.

Il sintomo nei log

Il primo controllo utile e’ stato guardare i messaggi del kernel legati alla scheda di rete:

sudo dmesg -T | egrep -i "e1000e|tx unit hang|watchdog|reset|hang|netdev"

L’estratto piu’ interessante era questo:

[Sun Feb 22 21:01:27 2026] e1000e 0000:00:1f.6 eno1: Detected Hardware Unit Hang:
[Sun Feb 22 21:01:29 2026] e1000e 0000:00:1f.6 eno1: Detected Hardware Unit Hang:
[Sun Feb 22 21:01:31 2026] e1000e 0000:00:1f.6 eno1: Detected Hardware Unit Hang:
[Sun Feb 22 21:01:32 2026] NETDEV WATCHDOG: eno1 (e1000e): transmit queue 0 timed out
[Sun Feb 22 21:01:32 2026] WARNING: CPU: 10 PID: 0 at net/sched/sch_generic.c:470 dev_watchdog+0x260/0x270
[Sun Feb 22 21:01:32 2026] e1000e 0000:00:1f.6 eno1: Reset adapter unexpectedly
[Sun Feb 22 21:01:32 2026] br0: topology change detected, propagating
[Sun Feb 22 21:01:36 2026] e1000e 0000:00:1f.6 eno1: NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None

Qui la parte importante non e’ br0. La sequenza dice altro:

  • Detected Hardware Unit Hang indica che la scheda, o il driver che la gestisce, si blocca.
  • NETDEV WATCHDOG: transmit queue 0 timed out indica un timeout della coda di trasmissione.
  • Reset adapter unexpectedly indica che il driver ha resettato la NIC.
  • br0: topology change detected, propagating e’ una conseguenza: il bridge vede la porta fisica cadere e tornare su.

Con bridge_stp on, il bridge propaga il cambio di topologia. Quella riga quindi non era la causa principale. STP stava reagendo a un evento sulla porta fisica.

In altre parole: il problema non era KVM, non era QEMU e non era br0. Il problema era eno1, con driver e1000e, che andava in hang e veniva resettata.

La stessa cosa si e’ ripetuta anche nei giorni successivi:

[Mon Feb 23 07:58:10 2026] e1000e 0000:00:1f.6 eno1: Detected Hardware Unit Hang:
[Mon Feb 23 07:58:14 2026] e1000e 0000:00:1f.6 eno1: Reset adapter unexpectedly
[Mon Feb 23 07:58:14 2026] br0: topology change detected, propagating
[Tue Feb 24 08:49:30 2026] e1000e 0000:00:1f.6 eno1: Detected Hardware Unit Hang:
[Tue Feb 24 08:49:33 2026] e1000e 0000:00:1f.6 eno1: Reset adapter unexpectedly
[Tue Feb 24 08:49:34 2026] br0: topology change detected, propagating
[Sat Mar 14 14:11:26 2026] e1000e 0000:00:1f.6 eno1: Reset adapter unexpectedly
[Sat Mar 14 14:11:26 2026] br0: topology change detected, propagating

La configurazione iniziale

La configurazione in /etc/network/interfaces era questa:

source /etc/network/interfaces.d/*

auto lo
iface lo inet loopback

auto eno1
iface eno1 inet manual

auto br0
iface br0 inet static
    address 192.168.50.23
    network 192.168.50.0
    netmask 255.255.255.0
    broadcast 192.168.50.255
    gateway 192.168.50.254
    bridge_ports eno1
    bridge_stp on
    bridge_fd 0
    bridge_hello 2
    bridge_maxage 12
    bridge_maxwait 0

La riga chiave era:

bridge_ports eno1

Significava che eno1 era la porta fisica del bridge br0. Quindi, quando eno1 si resettava, il bridge perdeva e riacquisiva la sua porta verso la rete fisica. Le VM non dovevano essere modificate: il punto debole era sotto di loro, nel collegamento fisico.

Perche’ il bridge non era il problema

In un host KVM/QEMU con bridge, le VM usano br0 come se fossero collegate alla stessa rete dell’host.

La regola pratica e’ questa:

corretto:
scheda fisica senza IP -> br0 con IP -> VM

sbagliato:
scheda fisica con IP + bridge separato

La scheda fisica non deve avere un IP proprio. Deve essere solo una porta del bridge. L’IP del server resta su br0.

Nel mio caso l’obiettivo era cambiare solo la porta fisica:

prima:
eno1 -> br0 -> VM

dopo:
lanusb0 -> br0 -> VM

Rilevamento della nuova USB Ethernet Realtek 2.5G

Ho collegato una scheda USB Ethernet Realtek 2.5G. Nei log e’ apparsa cosi':

usb 1-4: Product: USB 10/100/1G/2.5G LAN
usb 1-4: Manufacturer: Realtek
cdc_ncm 1-4:2.0: MAC-Address: 02:42:ac:32:00:25
cdc_ncm 1-4:2.0 enx0242ac320025: renamed from eth0

Il nome iniziale assegnato dal sistema era:

enx0242ac320025

Il MAC era:

02:42:ac:32:00:25

Con ip a la scheda risultava su e aveva preso un IP temporaneo via DHCP:

enx0242ac320025: <BROADCAST,MULTICAST,UP,LOWER_UP>
    inet 192.168.50.84/24

Questo IP serviva solo per verificare che link e cavo funzionassero. Nella configurazione finale l’IP non deve stare sulla scheda fisica, ma su br0.

Ho controllato anche il link:

ethtool enx0242ac320025

Output rilevante:

Link detected: yes

Nome stabile per la nuova scheda

Il nome enx0242ac320025 funziona, ma e’ scomodo da leggere e da usare dentro una configurazione stabile. Ho quindi assegnato un nome prevedibile alla scheda, basandomi sul suo MAC address.

Ho creato il file:

nano /etc/systemd/network/10-lanusb0.link

Con questo contenuto:

[Match]
MACAddress=02:42:ac:32:00:25

[Link]
Name=lanusb0

Questo dice a systemd/udev: quando trovi una scheda con MAC 02:42:ac:32:00:25, chiamala lanusb0.

Prima di cambiare la configurazione di rete, ho verificato che il file venisse riconosciuto:

udevadm test-builtin net_setup_link /sys/class/net/enx0242ac320025 2>/dev/null | grep -E 'Config file|ID_NET_NAME|lanusb0'

Output:

ID_NET_LINK_FILE=/etc/systemd/network/10-lanusb0.link

Backup della configurazione

Prima di toccare /etc/network/interfaces, backup semplice:

cp /etc/network/interfaces /etc/network/interfaces.bak

Nuova configurazione di rete

La nuova configurazione di /etc/network/interfaces sostituisce eno1 con lanusb0 come porta fisica del bridge:

source /etc/network/interfaces.d/*

auto lo
iface lo inet loopback

auto lanusb0
iface lanusb0 inet manual

auto br0
iface br0 inet static
    address 192.168.50.23
    network 192.168.50.0
    netmask 255.255.255.0
    broadcast 192.168.50.255
    gateway 192.168.50.254
    bridge_ports lanusb0
    bridge_stp on
    bridge_fd 0
    bridge_hello 2
    bridge_maxage 12
    bridge_maxwait 0

Riga per riga, la parte importante e’ questa:

  • auto lo e iface lo inet loopback sono la loopback e restano sempre.
  • auto lanusb0 porta su la nuova scheda.
  • iface lanusb0 inet manual dice che la scheda fisica non deve avere IP proprio.
  • bridge_ports lanusb0 mette la nuova scheda dentro br0.
  • l’IP statico resta su br0.
  • eno1 viene rimossa perche’ non deve piu’ essere usata.

Riavvio

Su un server remoto non conviene fare esperimenti aggressivi tipo:

ifdown br0 && ifup br0

Se qualcosa va storto, ci si taglia fuori via SSH.

La strada piu’ prudente e’ stata riavviare, lasciando collegati entrambi i cavi al primo boot:

reboot

Dopo aver verificato che tutto funzionasse tramite lanusb0, ho scollegato fisicamente il cavo da eno1, lasciandola come eventuale backup.

Verifica dopo il reboot

Dopo il riavvio ho controllato stato delle interfacce e bridge:

ip a
brctl show
bridge link

Output rilevante:

3: lanusb0: <BROADCAST,MULTICAST,UP,LOWER_UP> master br0 state UP
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP>
    inet 192.168.50.23/24

E il bridge:

bridge name     bridge id               STP enabled     interfaces
br0             8000.0242ac320025       yes             lanusb0
                                                        vnet0
                                                        vnet1
                                                        vnet2

Questo conferma tre cose importanti:

  • lanusb0 e’ dentro br0.
  • br0 ha ancora l’IP statico 192.168.50.23.
  • vnet0, vnet1 e vnet2 sono ancora dentro br0.

Le VM continuano quindi a funzionare senza modifiche. L’unica cosa cambiata e’ la porta fisica usata dal bridge.

Problema DNS dopo il cambio

Dopo il cambio di cavo e scheda, la rete IP funzionava, ma il DNS no.

Sintomo:

ping google.com

Output:

ping: google.com: Name or service not known

Il file /etc/resolv.conf era:

# Generated by NetworkManager

Nel mio caso il DNS locale e’ Pi-hole:

192.168.50.10

Il router e':

192.168.50.254

Fix immediato, usando solo Pi-hole:

printf "nameserver 192.168.50.10\n" > /etc/resolv.conf

Oppure, con router come fallback:

printf "nameserver 192.168.50.10\nnameserver 192.168.50.254\n" > /etc/resolv.conf

Se si vuole che tutto passi sempre da Pi-hole, ha senso usare solo 192.168.50.10. Se invece si preferisce avere un fallback, si puo’ aggiungere anche 192.168.50.254.

Nel blocco br0 si puo’ aggiungere:

dns-nameservers 192.168.50.10

Oppure:

dns-nameservers 192.168.50.10 192.168.50.254

NetworkManager

Ho controllato anche NetworkManager:

nmcli device status
systemctl is-active NetworkManager

Output:

DEVICE   TYPE      STATE                   CONNECTION
br0      bridge    connected (externally)  br0
vnet0    tun       connected (externally)  vnet0
vnet1    tun       connected (externally)  vnet1
vnet2    tun       connected (externally)  vnet2
eno1     ethernet  unavailable             --
lanusb0  ethernet  unmanaged               --
lo       loopback  unmanaged               --

NetworkManager era active, ma br0 risultava connected (externally). Questo significa che br0 e’ gestito da /etc/network/interfaces.

Anche lanusb0 come unmanaged e’ corretto: non deve essere gestita direttamente da NetworkManager, perche’ e’ solo la porta fisica del bridge.

Driver della Realtek USB 2.5G

La scheda Realtek 2.5G e’ stata vista come device USB:

idVendor=0bda, idProduct=8156

Su Debian 11 con kernel 5.10 e’ stata usata con cdc_ncm.

Controllo moduli:

lsmod | egrep 'r8152|cdc_ncm|cdc_ether'

Output:

cdc_ncm                53248  1 cdc_mbim
cdc_ether              24576  1 cdc_ncm
usbnet                 53248  3 cdc_mbim,cdc_ncm,cdc_ether

Ho verificato anche r8152:

modinfo r8152

Il modulo r8152 era presente, ma vecchio:

r8152 version v1.11.11

Su Debian 11, con kernel 5.10, quel modulo non includeva l’alias per 0bda:8156. Per questo non l’ho forzato.

La rete fisica, in questo caso, e’ a 1 Gbit. Per ora cdc_ncm va bene. Se in futuro servisse usare davvero i 2.5G, oppure se comparissero problemi di stabilita’, valuterei prima un kernel piu’ recente o un upgrade di Debian, invece di installare driver esterni.

Controlli dopo la migrazione

Per controllare eventuali reset, disconnessioni o problemi di carrier:

journalctl -k -b | grep -i -E 'lanusb0|cdc_ncm|usbnet|realtek|reset|disconnect|carrier|link'

Oppure:

dmesg -T | grep -i -E 'lanusb0|cdc_ncm|usbnet|realtek|reset|disconnect|carrier|link'

Per seguire i log live:

journalctl -k -f | grep -i -E 'lanusb0|cdc_ncm|usbnet|realtek|reset|disconnect|link|carrier'

E per guardare le statistiche delle interfacce:

ip -s link show lanusb0
ip -s link show br0

Qui conviene controllare soprattutto:

  • errors
  • dropped
  • overruns
  • carrier

Se questi contatori restano puliti e non compaiono reset nei log, la migrazione ha fatto il suo lavoro.

Conclusione

Il problema era causato dalla scheda integrata eno1 o dal suo driver e1000e.

Gli errori chiave erano:

Detected Hardware Unit Hang
NETDEV WATCHDOG
Reset adapter unexpectedly

Siccome eno1 era la porta fisica del bridge, ogni reset impattava br0 e quindi sia l’host sia le VM.

La soluzione e’ stata sostituire la porta fisica del bridge con lanusb0, lasciando invariati IP, bridge e configurazione delle VM:

lanusb0 = porta fisica senza IP
br0     = interfaccia principale con IP 192.168.50.23

In pratica, il bridge non e’ stato “riparato”. E’ stata tolta dal bridge la porta instabile.