Scenario
On a Debian GNU/Linux 11 Bullseye server running kernel 5.10.0-38-amd64, I had a fairly standard KVM/QEMU network setup:
eno1 -> br0 -> VM
The server was using a static address on the 192.168.50.0/24 LAN:
- server:
192.168.50.23 - gateway/router:
192.168.50.254 - local Pi-hole DNS:
192.168.50.10
The bridge used by the virtual machines was br0. The old physical NIC was eno1, handled by the e1000e driver.
The symptom was easy to notice: the network would drop and then come back. Since eno1 was the physical port inside the bridge, every reset affected both the host and the VMs.
The kernel log
The first useful check was to look at kernel messages related to the NIC:
sudo dmesg -T | egrep -i "e1000e|tx unit hang|watchdog|reset|hang|netdev"
The relevant output looked like this:
[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
The important part is not br0. The sequence says something else:
Detected Hardware Unit Hangmeans the NIC, or the driver managing it, got stuck.NETDEV WATCHDOG: transmit queue 0 timed outmeans the transmit queue timed out.Reset adapter unexpectedlymeans the driver reset the NIC.br0: topology change detected, propagatingis a consequence: the bridge saw the physical port go down and come back up.
With bridge_stp on, the bridge propagates topology changes. That line was not the root cause. STP was reacting to the physical port reset.
So the issue was not KVM, not QEMU, and not br0. The issue was eno1, using the e1000e driver, hanging and being reset.
The same pattern appeared again over the following days:
[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
Original network configuration
The original /etc/network/interfaces file was:
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
The key line was:
bridge_ports eno1
It means that eno1 was the physical port of the br0 bridge. When eno1 reset, the bridge lost and reacquired its physical path to the LAN. The VMs did not need changes: the weak point was underneath them, in the physical link.
Why the bridge was not the problem
On a KVM/QEMU host with a bridge, the VMs use br0 as if they were connected to the same LAN as the host.
The rule of thumb is:
correct:
physical NIC without IP -> br0 with IP -> VM
wrong:
physical NIC with IP + separate bridge
The physical NIC should not have its own IP address. It should only be a bridge port. The server IP stays on br0.
In this case, the goal was to replace only the physical port:
before:
eno1 -> br0 -> VM
after:
lanusb0 -> br0 -> VM
Detecting the new Realtek USB Ethernet 2.5G adapter
After plugging in the Realtek USB Ethernet 2.5G adapter, the kernel detected it like this:
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
The initial interface name was:
enx0242ac320025
The MAC address was:
02:42:ac:32:00:25
With ip a, the adapter was up and had received a temporary DHCP address:
enx0242ac320025: <BROADCAST,MULTICAST,UP,LOWER_UP>
inet 192.168.50.84/24
That address was only useful for testing the link and cable. In the final configuration, the IP must be on br0, not on the physical NIC.
I also checked the link:
ethtool enx0242ac320025
Relevant output:
Link detected: yes
Giving the new adapter a stable name
The name enx0242ac320025 works, but it is not pleasant to read or maintain in a network config. I assigned a stable name based on the MAC address.
I created this file:
nano /etc/systemd/network/10-lanusb0.link
With this content:
[Match]
MACAddress=02:42:ac:32:00:25
[Link]
Name=lanusb0
This tells systemd/udev: when a NIC with MAC 02:42:ac:32:00:25 appears, name it lanusb0.
Before changing the network configuration, I checked that the link file was recognized:
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
Back up the configuration
Before editing /etc/network/interfaces, I made a simple backup:
cp /etc/network/interfaces /etc/network/interfaces.bak
New network configuration
The new /etc/network/interfaces configuration replaces eno1 with lanusb0 as the bridge’s physical port:
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
The important bits:
auto loandiface lo inet loopbackare the loopback interface and always stay there.auto lanusb0brings the new adapter up.iface lanusb0 inet manualmeans the physical NIC does not get its own IP.bridge_ports lanusb0puts the new NIC insidebr0.- the static IP stays on
br0. eno1is removed because it should no longer be used.
Reboot
On a remote server, I would avoid doing something risky like:
ifdown br0 && ifup br0
If something goes wrong, SSH access can disappear.
The safer path was a reboot, keeping both network cables connected for the first boot:
reboot
After verifying that everything worked through lanusb0, I physically unplugged the cable from eno1 and left the old NIC as a possible fallback.
Verifying after reboot
After the reboot, I checked the interfaces and bridge:
ip a
brctl show
bridge link
Relevant output:
3: lanusb0: <BROADCAST,MULTICAST,UP,LOWER_UP> master br0 state UP
4: br0: <BROADCAST,MULTICAST,UP,LOWER_UP>
inet 192.168.50.23/24
And the bridge:
bridge name bridge id STP enabled interfaces
br0 8000.0242ac320025 yes lanusb0
vnet0
vnet1
vnet2
This confirms three important things:
lanusb0is insidebr0.br0still has the static IP192.168.50.23.vnet0,vnet1andvnet2are still insidebr0.
The VMs continue to work without changes. Only the physical port used by the bridge changed.
DNS issue after the change
After changing cable and adapter, IP connectivity worked, but DNS did not.
Symptom:
ping google.com
Output:
ping: google.com: Name or service not known
/etc/resolv.conf contained:
# Generated by NetworkManager
The local DNS server is Pi-hole:
192.168.50.10
The router is:
192.168.50.254
Immediate fix, using only Pi-hole:
printf "nameserver 192.168.50.10\n" > /etc/resolv.conf
Or, with the router as fallback:
printf "nameserver 192.168.50.10\nnameserver 192.168.50.254\n" > /etc/resolv.conf
If everything should always go through Pi-hole, use only 192.168.50.10. If a fallback is preferred, add 192.168.50.254 too.
Inside the br0 block, you can add:
dns-nameservers 192.168.50.10
Or:
dns-nameservers 192.168.50.10 192.168.50.254
NetworkManager
I also checked 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 was active, but br0 showed as connected (externally). That means br0 is managed by /etc/network/interfaces.
lanusb0 being unmanaged is also correct: it should not be managed directly by NetworkManager, because it is only the physical bridge port.
Realtek USB 2.5G driver
The Realtek 2.5G adapter was detected as this USB device:
idVendor=0bda, idProduct=8156
On Debian 11 with kernel 5.10, it used cdc_ncm.
Module check:
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
I also checked r8152:
modinfo r8152
The r8152 module existed, but it was old:
r8152 version v1.11.11
On Debian 11 with kernel 5.10, that module did not include the alias for 0bda:8156, so I did not force it.
The physical LAN is 1 Gbit, so cdc_ncm is fine for now. If real 2.5G throughput is needed later, or if stability issues appear, I would first consider a newer kernel or a Debian upgrade instead of installing external drivers.
Checks after the migration
To watch for resets, disconnects or carrier problems:
journalctl -k -b | grep -i -E 'lanusb0|cdc_ncm|usbnet|realtek|reset|disconnect|carrier|link'
Or:
dmesg -T | grep -i -E 'lanusb0|cdc_ncm|usbnet|realtek|reset|disconnect|carrier|link'
To follow the kernel log live:
journalctl -k -f | grep -i -E 'lanusb0|cdc_ncm|usbnet|realtek|reset|disconnect|link|carrier'
And to check interface counters:
ip -s link show lanusb0
ip -s link show br0
The counters to watch are mainly:
errorsdroppedoverrunscarrier
If those counters stay clean and there are no new resets in the logs, the migration did its job.
Conclusion
The issue was caused by the integrated eno1 NIC, or by its e1000e driver.
The key errors were:
Detected Hardware Unit Hang
NETDEV WATCHDOG
Reset adapter unexpectedly
Since eno1 was the physical bridge port, each reset affected br0, and therefore both the host and the VMs.
The solution was to replace the physical bridge port with lanusb0, while leaving the IP address, bridge and VM configuration unchanged:
lanusb0 = physical port without IP
br0 = main interface with IP 192.168.50.23
In practice, the bridge was not “fixed”. The unstable port was removed from it.
Use the share button below if you liked it.
Your click is my virtual high-five.