KVM Bridge and NAT

I ran into an interesting problem to solve. I have multiple VMs using KVM that do not require inbound IPv4 but do require at least IPv6 inbound (for CloudFlare) and it would be nice to have outbound IPv4.

I already have a bridge setup for IPv4 + IPv6 named br0 but need a separate bridge just for NAT routing for special VMs that do not require public IPv4 addresses.

  1. A second NIC needs to be added. This one will use the default network.

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      <interface type='bridge'>
      <mac address='11:11:11:11:11:11'/>
      <source bridge='br0'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
      </interface>
      <interface type='network'>
      <mac address='22:22:22:22:22:22'/>
      <source network='default'/>
      <model type='virtio'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
      </interface>
  2. Stop all VMs you modified and restart libvirtd.

    • systemctl restart libvirtd.service
  3. Set the default network to auto start.

    • 1
      2
      virsh net-autostart default
      virsh net-start default
    • By default the bridge IP is 192.168.122.1. This is the subnet we’ll use in the VMs.

      • 1
        2
        3
        4
        13: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
        link/ether fe:54:00:9d:ef:df brd ff:ff:ff:ff:ff:ff
        inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
        valid_lft forever preferred_lft forever
  4. Forwarding must be allowed in iptables and sysctl. Remember that br0 is the original bridge I set up for public IPv4 + IPv6. The bridge that gets created by libvirt (virbr0) is for the internal IPv4 network.

    • 1
      2
      3
      iptables -t nat -A POSTROUTING -s 192.168.122.0/24 -o br0 -j MASQUERADE
      sysctl -w net.ipv4.ip_forward=1
      sysctl -w net.ipv6.conf.all.forwarding=1
  5. Start the VMs back up.

  6. Make sure you now have a new interface named eth1. Edit the interfaces file in the VM:

    • 1
      2
      3
      4
      5
      auto eth1
      iface eth1 inet static
      address 192.168.122.10
      netmask 255.255.255.0
      gateway 192.168.122.1
  7. Reboot the VM and you should be good to go.