I was in the middle of setting up a tiny homelab VM that bridges straight to the host. The guest could ping the gateway just fine, but ip addr show br0 was staring back at me with no inet line. The bridge was up, state UP, yet no IPv4. What’s going on?
1. Distinguish link‑state from IP‑state
ip link only tells you about the link layer. An interface can be physically up and still have no IP if the DHCP client never got a lease or a static config never ran.
ip link show br0
# state UP, no inet
If you’re on a system that uses systemd‑networkd, check the unit status:
systemctl status systemd-networkd
Since kernel 5.15, bridge‑DHCP handling got stricter. If you set DHCP=yes on a bridge but the DHCP server is unreachable, the interface will stay link‑up but without an address.
2. Look at the DHCP client
On most distros the DHCP assignment for bridges comes from dhclient or systemd-networkd. Dig into the logs:
journalctl -u systemd-networkd | grep br0
If you see No DHCPOFFER received, the server is either down or the bridge’s MAC is being blocked. Remember, a bridge inherits the MAC of its first enslaved interface; if that interface is down, the bridge’s MAC can look “unknown” to the DHCP server.
3. Make sure you actually have enslaved ports
A bridge with no enslaved interface is just a virtual NIC that won’t talk to the network. Run:
brctl show br0
You should see at least one member, e.g. eth0 or enp0s3. An empty list means the bridge is effectively a dead‑end; you can’t reach the gateway unless you’re on loopback or a purely virtual network.
4. Netfilter bridge hooks can kill you silently
If you’re forwarding packets with iptables or nftables, the kernel’s bridge hooks might be dropping traffic before the DHCP client even sees it. Check the flag:
sysctl net.bridge.bridge-nf-call-iptables
# 1 means the bridge passes packets through iptables
If it’s 0, packets get dropped early. Enable it:
sysctl -w net.bridge.bridge-nf-call-iptables=1
Persist it with a file like /etc/sysctl.d/99-bridge.conf.
5. Double‑check the gateway’s ARP table
Sometimes the gateway sees the bridge’s MAC but never assigns an IP because the MAC isn’t in its ARP table. On the gateway:
arp -n | grep <bridge-mac>
If nothing shows up, clear the stale entry:
arp -d <bridge-mac>
6. A quick security sanity check
Bridges can be a vector for MAC spoofing if you let untrusted VMs plug in. Lock the bridge’s MAC to a permanent entry:
bridge fdb add <mac> dev br0 permanent
That stops other VMs from impersonating the bridge and potentially snatching an IP from the DHCP server.
Quick checklist
| Step | Command | What to look for |
|---|---|---|
| Verify link | ip link show br0 |
state UP |
| Check DHCP logs | `journalctl -u systemd-networkd | grep br0` |
| Enslaved interfaces | brctl show br0 |
At least one enslaved |
| Netfilter bridge hooks | sysctl net.bridge.bridge-nf-call-iptables |
Should be 1 |
| ARP table | `arp -n | grep ` |
| MAC lock | bridge fdb add <mac> dev br0 permanent |
Permanent entry |
If everything looks good but the bridge still shows no IP, a quick restart of the networking service usually does the trick:
systemctl restart systemd-networkd
or just reboot the VM. In my experience, the most common culprits are a missing enslaved interface or a DHCP client that didn’t get a lease.
See also
- When Wayland Won’t Run My Games: Tweaking a Laptop for Better Battery Life
- When a backup script keeps my CPU pegged: a quick ps, nice, ionice tweak to keep the terminal responsive.
- Why my headphone jack stopped working after the latest update—and how a single udev rule brought it back
- How I Configured Caddy as a Reverse Proxy for My Home Lab and Solved the HTTPS Redirect Bug
- How I Prevented a Rootless Podman Container From Filling My Disk With Logs