QEMU/KVM hassio os ip bridge not working

Hi. I have been looking at various guides but i cannot seem to get bridge configuration working. I have a static ip on the host side of bridge but it is ignored and for some reason DHCP on my router is still giving OS an IP address so I think QEMU/KVM is using default network xml for NAT. I know WIFI does not work as bridge - I am using a USB LAN adapter on the host as enx00e04c6806d9. My host is Ubuntu 22.04 desktop.

On host

$ip addr show
3: enx00e04c6806d9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:e0:4c:68:06:d9 brd ff:ff:ff:ff:ff:ff
    inet 10.33.66.202/24 brd 10.33.66.255 scope global noprefixroute enx00e04c6806d9
       valid_lft forever preferred_lft forever
    inet6 fe80::f140:19af:b295:f05a/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
...
5: bri0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether be:bf:37:80:a2:9e brd ff:ff:ff:ff:ff:ff
    inet 10.33.66.201/24 brd 10.33.66.255 scope global noprefixroute bri0
       valid_lft forever preferred_lft forever
    inet6 fe80::bcbf:37ff:fe80:a29e/64 scope link 
       valid_lft forever preferred_lft forever

$ brctl show
bridge name	bridge id		STP enabled	interfaces
br-b243d562082c		8000.02422484bcf5	no		vethbd77fc2
bri0		8000.bebf3780a29e	yes		
docker0		8000.0242418b17a8	no		vethc8401e9

This is my netplan bridge:

$sudo cat /etc/netplan/02-qemu-bridge.yaml
  version: 2
  renderer: NetworkManager
  ethernets:
    enp0s31f6:
      dhcp4: false
      dhcp6: false
  bridges:
    bri0:
      interfaces: [enp0s31f6]
      addresses: [10.33.66.201/24]
      routes:
        - to: default
          via: 10.33.66.1
          metric: 100
          on-link: true
      nameservers:
        addresses: [194.168.4.100, 194.168.8.100]
      parameters:
        stp: true
        forward-delay: 4
      dhcp4: no
      dhcp6: no
$ip route
default via 10.33.66.1 dev enx00e04c6806d9 proto static metric 100 
default via 10.33.66.1 dev bri0 proto static metric 20100 onlink linkdown 
10.33.66.0/24 dev enx00e04c6806d9 proto kernel scope link src 10.33.66.202 metric 100 
10.33.66.0/24 dev bri0 proto kernel scope link src 10.33.66.201 metric 425 linkdown 
169.254.0.0/16 dev enx00e04c6806d9 scope link metric 1000 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
172.19.0.0/16 dev br-b243d562082c proto kernel scope link src 172.19.0.1 

For QEMU/KVM:

$ sudo virsh 
Welcome to virsh, the virtualization interactive terminal.

Type:  'help' for help with commands
       'quit' to quit

virsh # net-list
 Name              State    Autostart   Persistent
----------------------------------------------------
 bridged-network   active   yes         yes

virsh # net-dumpxml bridged-network
<network>
  <name>bridged-network</name>
  <uuid>84c2b57c-beda-434c-abcc-b8e271ebdc7d</uuid>
  <forward mode='bridge'/>
  <bridge name='bri0'/>
</network>

My hassio VM:
<domain type='kvm'>
  <name>hass</name>
  <uuid>7fe4c758-3a6b-4e74-9c42-9bbdd466ae7f</uuid>
  <memory unit='KiB'>2146304</memory>
  <currentMemory unit='KiB'>2146304</currentMemory>
  <vcpu placement='static'>2</vcpu>
  <os firmware='efi'>
    <type arch='x86_64' machine='pc-i440fx-jammy'>hvm</type>
    <boot dev='hd'/>
  </os>
  <features>
    <acpi/>
    <apic/>
  </features>
  <cpu mode='host-model' check='partial'/>
  <clock offset='utc'>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='hpet' present='no'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <pm>
    <suspend-to-mem enabled='no'/>
    <suspend-to-disk enabled='no'/>
  </pm>
  <devices>
  <devices>
    <emulator>/usr/bin/qemu-system-x86_64</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='/var/lib/libvirt/images/hassos-vm/haos_ova-14.1.qcow2'/>
      <target dev='vda' bus='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
    </disk>
    <controller type='usb' index='0' model='ich9-ehci1'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x7'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci1'>
      <master startport='0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0' multifunction='on'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci2'>
      <master startport='2'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x1'/>
    </controller>
    <controller type='usb' index='0' model='ich9-uhci3'>
      <master startport='4'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pci-root'/>
    <interface type='network'>
      <mac address='52:54:00:6e:33:d3'/>
      <source network='bridged-network'/>
      <model type='virtio'/>
      <link state='up'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </interface>
    <serial type='pty'>
      <target type='isa-serial' port='0'>
        <model name='isa-serial'/>
      </target>
    </serial>
    <console type='pty'>
      <target type='serial' port='0'/>
    </console>
    <input type='mouse' bus='ps2'/>
    <input type='keyboard' bus='ps2'/>
    <tpm model='tpm-crb'>
      <backend type='emulator' version='2.0'/>
    </tpm>
    <audio id='1' type='none'/>
    <memballoon model='virtio'>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/>
    </memballoon>
  </devices>
</domain>

virsh # start hass
Domain ‘hass’ started

virsh # console hass
Connected to domain ‘hass’
Escape character is ^] (Ctrl + ])

Welcome to Home Assistant
homeassistant login:

# ip addr show
...
2: enp0s2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:6e:33:d3 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::b04c:fc73:41d4:18f5/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

I have emptied iptables and will repopulate when I get this working. ufw is enabled still.

sudo iptables --list
Chain INPUT (policy DROP)
target     prot opt source               destination         
ufw-before-logging-input  all  --  anywhere             anywhere            
ufw-before-input  all  --  anywhere             anywhere            
ufw-after-input  all  --  anywhere             anywhere            
ufw-after-logging-input  all  --  anywhere             anywhere            
ufw-reject-input  all  --  anywhere             anywhere            
ufw-track-input  all  --  anywhere             anywhere            

Chain FORWARD (policy DROP)
target     prot opt source               destination         
DOCKER-USER  all  --  anywhere             anywhere            
DOCKER-ISOLATION-STAGE-1  all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
DOCKER     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere            
ufw-before-logging-forward  all  --  anywhere             anywhere            
ufw-before-forward  all  --  anywhere             anywhere            
ufw-after-forward  all  --  anywhere             anywhere            
ufw-after-logging-forward  all  --  anywhere             anywhere            
ufw-reject-forward  all  --  anywhere             anywhere            
ufw-track-forward  all  --  anywhere             anywhere            

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
ufw-before-logging-output  all  --  anywhere             anywhere            
ufw-before-output  all  --  anywhere             anywhere            
ufw-after-output  all  --  anywhere             anywhere            
ufw-after-logging-output  all  --  anywhere             anywhere            
ufw-reject-output  all  --  anywhere             anywhere            
ufw-track-output  all  --  anywhere             anywhere            

Chain DOCKER (2 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             172.17.0.2           tcp dpt:5000
ACCEPT     tcp  --  anywhere             172.19.0.2           tcp dpt:51821
ACCEPT     udp  --  anywhere             172.19.0.2           udp dpt:51820

Chain DOCKER-ISOLATION-STAGE-1 (1 references)
target     prot opt source               destination         
DOCKER-ISOLATION-STAGE-2  all  --  anywhere             anywhere            
DOCKER-ISOLATION-STAGE-2  all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            

Chain DOCKER-ISOLATION-STAGE-2 (2 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere            
DROP       all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            

Chain DOCKER-USER (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
RETURN     all  --  anywhere             anywhere            

Chain ufw-after-forward (1 references)
target     prot opt source               destination         

Chain ufw-after-input (1 references)
target     prot opt source               destination         
ufw-skip-to-policy-input  udp  --  anywhere             anywhere             udp dpt:netbios-ns
ufw-skip-to-policy-input  udp  --  anywhere             anywhere             udp dpt:netbios-dgm
ufw-skip-to-policy-input  tcp  --  anywhere             anywhere             tcp dpt:netbios-ssn
ufw-skip-to-policy-input  tcp  --  anywhere             anywhere             tcp dpt:microsoft-ds
ufw-skip-to-policy-input  udp  --  anywhere             anywhere             udp dpt:bootps
ufw-skip-to-policy-input  udp  --  anywhere             anywhere             udp dpt:bootpc
ufw-skip-to-policy-input  all  --  anywhere             anywhere             ADDRTYPE match dst-type BROADCAST

Chain ufw-after-logging-forward (1 references)
target     prot opt source               destination         
LOG        all  --  anywhere             anywhere             limit: avg 3/min burst 10 LOG level warning prefix "[UFW BLOCK] "

Chain ufw-after-logging-input (1 references)
target     prot opt source               destination         
LOG        all  --  anywhere             anywhere             limit: avg 3/min burst 10 LOG level warning prefix "[UFW BLOCK] "

Chain ufw-after-logging-output (1 references)
target     prot opt source               destination         

Chain ufw-after-output (1 references)
target     prot opt source               destination         

Chain ufw-before-forward (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ACCEPT     icmp --  anywhere             anywhere             icmp destination-unreachable
ACCEPT     icmp --  anywhere             anywhere             icmp time-exceeded
ACCEPT     icmp --  anywhere             anywhere             icmp parameter-problem
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
ufw-user-forward  all  --  anywhere             anywhere            

Chain ufw-before-input (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ufw-logging-deny  all  --  anywhere             anywhere             ctstate INVALID
DROP       all  --  anywhere             anywhere             ctstate INVALID
ACCEPT     icmp --  anywhere             anywhere             icmp destination-unreachable
ACCEPT     icmp --  anywhere             anywhere             icmp time-exceeded
ACCEPT     icmp --  anywhere             anywhere             icmp parameter-problem
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
ACCEPT     udp  --  anywhere             anywhere             udp spt:bootps dpt:bootpc
ufw-not-local  all  --  anywhere             anywhere            
ACCEPT     udp  --  anywhere             mdns.mcast.net       udp dpt:mdns
ACCEPT     udp  --  anywhere             239.255.255.250      udp dpt:1900
ufw-user-input  all  --  anywhere             anywhere            

Chain ufw-before-logging-forward (1 references)
target     prot opt source               destination         

Chain ufw-before-logging-input (1 references)
target     prot opt source               destination         

Chain ufw-before-logging-output (1 references)
target     prot opt source               destination         

Chain ufw-before-output (1 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate RELATED,ESTABLISHED
ufw-user-output  all  --  anywhere             anywhere            

Chain ufw-logging-allow (0 references)
target     prot opt source               destination         
LOG        all  --  anywhere             anywhere             limit: avg 3/min burst 10 LOG level warning prefix "[UFW ALLOW] "

Chain ufw-logging-deny (2 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere             ctstate INVALID limit: avg 3/min burst 10
LOG        all  --  anywhere             anywhere             limit: avg 3/min burst 10 LOG level warning prefix "[UFW BLOCK] "

Chain ufw-not-local (1 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL
RETURN     all  --  anywhere             anywhere             ADDRTYPE match dst-type MULTICAST
RETURN     all  --  anywhere             anywhere             ADDRTYPE match dst-type BROADCAST
ufw-logging-deny  all  --  anywhere             anywhere             limit: avg 3/min burst 10
DROP       all  --  anywhere             anywhere            

Chain ufw-reject-forward (1 references)
target     prot opt source               destination         

Chain ufw-reject-input (1 references)
target     prot opt source               destination         

Chain ufw-reject-output (1 references)
target     prot opt source               destination         

Chain ufw-skip-to-policy-forward (0 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere            

Chain ufw-skip-to-policy-input (7 references)
target     prot opt source               destination         
DROP       all  --  anywhere             anywhere            

Chain ufw-skip-to-policy-output (0 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            

Chain ufw-track-forward (1 references)
target     prot opt source               destination         

Chain ufw-track-input (1 references)
target     prot opt source               destination         

Chain ufw-track-output (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere             ctstate NEW
ACCEPT     udp  --  anywhere             anywhere             ctstate NEW

Chain ufw-user-forward (1 references)
target     prot opt source               destination         

Chain ufw-user-input (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh

Chain ufw-user-limit (0 references)
target     prot opt source               destination         
LOG        all  --  anywhere             anywhere             limit: avg 3/min burst 5 LOG level warning prefix "[UFW LIMIT BLOCK] "
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable

Chain ufw-user-limit-accept (0 references)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            

Chain ufw-user-logging-forward (0 references)
target     prot opt source               destination         

Chain ufw-user-logging-input (0 references)
target     prot opt source               destination         

Chain ufw-user-logging-output (0 references)
target     prot opt source               destination         

Chain ufw-user-output (1 references)
target     prot opt source               destination 

A bit too much for me to go through right now, but at a quick glance, netplan: you’ve set the bridge to work with enp0s31f6, but enp0s31f6 is not shown in the ip addr show. Plus the bridge is DOWN so not sure anything using it will have connectivity.
Anyway, here is a good community guide for this.

@wmaker Thanks. I tried so many examples, i guess my last attempt left the tutorials network adapter in netplan.
Now I’m back to where I originally was, it looks like the bridge works which I get is at ethernet frame level but at network level I did specify a bridge ip of 10.33.66.201 and i expected the hassio os when booted to use this IP. Now it is as before using my router’s DHCP and for some reason ignoring the static bridge IP. Here are my details now:

host:

my only netplan file which generates and applies ok now looks like this:

network:
  version: 2
  renderer: networkd
  ethernets:
    enx00e04c6806d9:
      dhcp4: false
      dhcp6: false
      addresses:
      - 10.33.66.202/24
      routes:
      - to: default
        via: 10.33.66.1
      nameservers:
       addresses: [1.1.1.1,208.67.222.123]
  bridges:
    bri0:
      interfaces: [enx00e04c6806d9]
      #qemu mac
      #macaddress: 52:54:00:6E:33:D3
      #specifing the above mac which hass vm uses causes no ip
      addresses: [10.33.66.201/24]
      routes:
        - to: default
          via: 10.33.66.1
          metric: 100
          on-link: true
      nameservers:
        addresses: [1.1.1.1, 208.67.222.123]
      parameters:
        stp: true
        forward-delay: 4
      dhcp4: no
      dhcp6: no

$ip addr show bri0

3: enx00e04c6806d9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master bri0 state UP group default qlen 1000
    link/ether 00:e0:4c:68:06:d9 brd ff:ff:ff:ff:ff:ff
    inet 10.33.66.202/24 brd 10.33.66.255 scope global enx00e04c6806d9
       valid_lft forever preferred_lft forever
...
5: bri0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether be:bf:37:80:a2:9e brd ff:ff:ff:ff:ff:ff
    inet 10.33.66.201/24 brd 10.33.66.255 scope global bri0
       valid_lft forever preferred_lft forever
    inet6 fe80::bcbf:37ff:fe80:a29e/64 scope link 
       valid_lft forever preferred_lft forever
...
12: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master bri0 state UNKNOWN group default qlen 1000
    link/ether fe:54:00:6e:33:d3 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc54:ff:fe6e:33d3/64 scope link 
       valid_lft forever preferred_lft forever

$brctl show bri0

bridge name	bridge id		STP enabled	interfaces
bri0		8000.bebf3780a29e	yes		enx00e04c6806d9
							vnet0

qemu hass:

when started through virsh, logging as root:

$ip addr show enp0s2

2: enp0s2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:6e:33:d3 brd ff:ff:ff:ff:ff:ff
    inet 10.33.66.107/24 brd 10.33.66.255 scope global dynamic noprefixroute enp0s2
       valid_lft 86391sec preferred_lft 86391sec
    inet6 fe80::b04c:fc73:41d4:18f5/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

I have connectivity but it is not a static IP, router DHCP gave it that address.

In my home router setup, if i allocate a static IP for the mac address above:
52:54:00:6E:33:D3 10.33.66.200

Previously it was getting the next DHCP address 10.33.66.107, when VM started it does get 10.33.66.200.

So I can connect to HASSIO via http://10.33.66.200:8123/ on my LAN, outside of my QEMU/KVM image but why is it using my routers DHCP?

You’ve pretty much got it working.

  • You don’t really need an IP address for enx00e04c6806d9. Your host will work using bri0’s address. By giving both enx00e04c6806d9 and bri0 an IP address, then your host is working off of two interfaces connected to the same LAN which is unnecessary.
  • Your HA VM has an Ethernet port connected to the bri0 bridge via Ethernet, and that is all the VM knows about the bridge. So the HAOS sees its own enp0s2 with its own MAC Address (52:54:00:6e:33:d3) and you can set enp0s2 to use DHCP or you can configure a static IP (using HA’s UI). Hopefully this makes it clearer why your router’s DHCP is assigning 10.33.66.200 to MAC 52:54:00:6e:33:d3

@wmaker Thanks again for your time and help on this.