Environment:
- A router with DHCP server. This router manages a subnet of 172.16.0.1/16
- A host with Ubuntu 20.04 installed, and it has a NIC named eno0.
- A QEMU virtual machine running on host.
Purpose:
Bridge the virtual machine with host's NIC to obtain IP via DHCP protocol.
What I have tried:
-
Setup a bridge on host, and add the
eno0
interface in it:ip link add name br0 type bridge ip link set br0 up ip link set eno0 master br0
-
Assign IP to
br0
via DHCP:dhclient br0
-
Run qemu machine with tap network:
qemu-system-x86_64 \ -enable-kvm \ -nographic \ -drive format=raw,file=/path/to/img \ -netdev tap,id=nic0,br=br0,helper=/opt/qemu/libexec/qemu-bridge-helper \ -device e1000e,mac=52:54:00:12:34:50,netdev=nic0
-
After virtual machine booting, try to obtain IP via
udhcpc
command (a dhclient variant in busybox):udpchc eth0
Till now, the eth0 cannot be assigned a IP in subnet 172.16.x.x/16.
So, is there anything wrong with my configuration?
Update:
To simplify this experiment, I use a dummy interface, say dm0, instead of eno0, and setup a DHCP server on that dm0 interface.
# Create a dummy interface
ip link add dm0 type dummy
# Create bridge and add dm0 to it
ip link add br0 type bridge
ip link set dm0 master br0
# Bring interfaces up
ip link set br0 up
ip link set dm0 up
# Setup a DHCP server on dm0, managed subnet is 10.0.0.1/24.
# Assign address to dm0 interface
ip addr add dev dm0 10.0.0.1/24
# Initiate QEMU virtual machine
qemu-system-x86_64 \
-enable-kvm \
-nographic \
-drive format=raw,file=/path/to/img \
-netdev tap,id=nic0,br=br0,helper=/opt/qemu/libexec/qemu-bridge-helper \
-device e1000e,mac=52:54:00:12:34:50,netdev=nic0
# Try to obtain IP address in virtual machine
udhcpc -i eth0
Run tcpdump both on dm0 and tap0 interface by command:
tcpdump -nli dm0
tcpdump -nli tap0
I can see that the DHCP request is received by DHCP server, and the server gives responses by allocating a new IP address.
# From dm0 interface
17:44:50.237133 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 52:54:00:12:34:51, length 300
17:44:50.237239 IP 10.0.0.1.67 > 10.0.0.200.68: BOOTP/DHCP, Reply, length 300
However, on interface tap0, only DHCP request packages can be seen. The response packages are missing.
17:44:50.237122 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 52:54:00:12:34:51, length 300
It seems that the response packages are filter out by bridge, which is the reason that VM cannot obtain a valid address, and I don't how to figure out what has happend.
Best Answer
I promised to formulate my comment which solved the problem in the form of an answer and forgot. Shame on me. Let me fix that already; @DouglasSu please accept for future readers to be aware of the solution.
The problem is that Netfilter (the Linux firewall) blocked forwarding of said packet. Why it blocked a bridged packet?
There is a knob in the kernel whether it calls the IP-level firewall for bridged packets. In ancient distros it was called
net.bridge.bridge-nf-call-iptables
, which controlled overall system behaviour (e.g. for all bridges simultaneously). In such old system you may add into/etc/sysctl.d/bridge.conf
:And
iptables
rules won't get traversed for bridged packets. To check a setting, you may runsysctl | grep bridge-nf-call-iptables
.In new systems, this is controllable per-bridge with
nf_call_iptables
variable (and its friends):E.g. you may set it for each bridge individually, for example, during creation:
and check value using
ip -d link show br0
or in/sys/class/net/br0/bridge/nf_call_iptables
. There you can also change its value at runtime.And, at last, you may properly configure
iptables
to allow bridged packets. There isphysdev
match to determine which bridge port the packet was entered from.