@f4-0 I'm not hosting a dhcpd guest with libvirt so can't comment on that issue, but I tried various bridging techniques including libvirt's virtual networks and openvswitch. All worked. But in the end I found the simplest (for me to implement and understand) was to bring up the bridges on the host using Ubuntu's netplan and networkd. I only have one NIC on this machine (desktop) and it receives tagged and untagged traffic.
#/etc/netplan/01.vmbr.yaml
network:
version: 2
renderer: networkd
ethernets:
enp0s31f6: {}
vlans:
vlan100:
accept-ra: no
id: 100
link: enp0s31f6
vlan200:
accept-ra: no
id: 200
link: enp0s31f6
bridges:
br0:
interfaces: [enp0s31f6]
macaddress: 00:01:02:03:04:05
addresses: [192.168.30.11/24]
routes:
- to: default
via: 192.168.30.1
nameservers:
search: [local.lan]
addresses: [192.168.30.10]
br100:
interfaces: [vlan100]
link-local: []
br200:
interfaces: [vlan200]
link-local: []
$ networkctl list
IDX LINK TYPE OPERATIONAL SETUP
1 lo loopback carrier unmanaged
2 enp0s31f6 ether enslaved configured
3 br0 bridge routable configured
4 br100 bridge carrier configured
5 br200 bridge carrier configured
6 vlan200 vlan enslaved configured
7 vlan100 vlan enslaved configured
Then with libvirt, dispense with virtual network definitions and assign guest interfaces to the bridges:
<interface type='bridge'>
<mac address='00:00:00:00:00:00'/>
<source bridge='br200'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
</interface>
Also, check iptables configuration.