Mastering KVM Virtual Networking: Bridges, NAT, and Bonded Interfaces

Virtual networking in KVM environments is foundational for enabling communication between guest VMs, the host, and external networks. This guide covers core concepts and practical implementations—including Linux bridges, NAT-based and bridged virtual networks, and resilient bonded interfaces—using modern libvirt tooling and kernel-native mechanisms.

Understanding Linux Bridges and libvirt Network Models

A Linux bridge functions as a software-based Layer 2 switch: it forwards Ethernet frames based on MAC addresses and aggregates multiple network interfaces (physical, virtual, or both) into a single logical segment. In KVM deployments, bridges serve as the backbone for inter-VM connectivity and external reachability.

libvirt abstracts network configuration through <network> definitions, supporting several operational modes:

  • NAT mode: Isolated private network with host-based masquerading and DHCP service.
  • Bridged mode: Direct attachment of VMs to the physical LAN via a host bridge.
  • Isolated mode: No external connectivity—only internal VM-to-VM communication.
  • Direct device assignment: PCI passthrough (e.g., SR-IOV VFs or VT-d devices) for low-latency, high-throughput use cases.

VM network adapters can be emulated (e.g., e1000, rtl8139) or paravirtualized (virtio-net). The latter delivers superior performance and is strongly recommended for production workloads.

Inspecting and Managing Default NAT Networks

The default virtual network—typically named default—is auto-created during libvirt installation. Its configuration resides at /etc/libvirt/qemu/networks/default.xml. While editing this file directly is discouraged, its contents reveal key design choices:

<network>
  <name>default</name>
  <uuid>5687d2e1-c14d-42bb-abe2-fcb4bfac2a12</uuid>
  <forward mode='nat'/>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:79:e3:41'/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
    </dhcp>
  </ip>
</network>

This defines a private subnet (192.168.122.0/24) where virbr0 acts as the gateway and DHCP server. To manage such networks programmatically, use virsh:

# List active and defined networks
virsh net-list --all

# Display runtime details
virsh net-info default

# Export full XML definition
virsh net-dumpxml default

# Edit safely (triggers validation and reload)
virsh net-edit default

Network Interface Topology and Traffic Flow

When a VM uses the default NAT network, libvirt creates three related interfaces on the host:

  • virbr0: The bridge itself—assigned 192.168.122.1.
  • virbr0-nic: A dummy interface attached solely to maintain bridge state.
  • vnetX: TAP devices representing each VM’s virtual NIC, enslaved to virbr0.

Confirm this layout using standard tools:

ip link show | grep -E '^(virbr|vnet)'
brctl show virbr0

Within the VM, the corresponding NIC (e.g., eth0) receives an IP via DHCP from the virbr0 subnet. Host-to-VM and VM-to-external traffic flows through iptables rules that perform SNAT/DNAT and enable forwarding.

Implementing Bridged Networking

Bridged mode eliminates NAT overhead by placing VMs directly on the same L2 segment as the host’s physical network. This requires creating a persistent Linux bridge and reassigning the host’s physical interface to it.

Assume the host’s primary interface is ens32. First, disable NetworkManager control and define a bridge configuration:

# /etc/sysconfig/network-scripts/ifcfg-virbr1
DEVICE=virbr1
TYPE=Bridge
BOOTPROTO=static
IPADDR=192.168.200.200
NETMASK=255.255.255.0
GATEWAY=192.168.200.2
DNS1=192.168.200.2
ONBOOT=yes
STP=on
DELAY=0

Then modify the physical interface to join the bridge:

# /etc/sysconfig/network-scripts/ifcfg-ens32
DEVICE=ens32
TYPE=Ethernet
ONBOOT=yes
BRIDGE=virbr1
NM_CONTROLLED=no

Restart the network stack:

systemctl restart network

Afterward, ens32 loses its IP address, and virbr1 assumes it—making the bridge the new network endpoint. VMs configured with <source network='virbr1'/> now appear as native peers on the LAN.

Building Resilient Bridged Networks with Bonding

To eliminate single points of failure, bind multiple physical NICs into a single logical interface before attaching it to a bridge. This example uses active-backup bonding (mode=1), where only one slave is active unless failure occurs.

Configure each physical interface as a bond slave:

# /etc/sysconfig/network-scripts/ifcfg-ens32
DEVICE=ens32
TYPE=Ethernet
ONBOOT=yes
MASTER=bond0
SLAVE=yes
NM_CONTROLLED=no
USERCTL=no
# /etc/sysconfig/network-scripts/ifcfg-ens36
DEVICE=ens36
TYPE=Ethernet
ONBOOT=yes
MASTER=bond0
SLAVE=yes
NM_CONTROLLED=no
USERCTL=no

Define the bond master with health monitoring:

# /etc/sysconfig/network-scripts/ifcfg-bond0
DEVICE=bond0
TYPE=Bond
NAME=bond0
ONBOOT=yes
BOOTPROTO=static
IPADDR=192.168.200.132
NETMASK=255.255.255.0
BONDING_OPTS="mode=active-backup miimon=100"

Load the kernel module and restart networking:

modprobe bonding
systemctl restart network

Verify status:

cat /proc/net/bonding/bond0
ip link show bond0

Finally, attach bond0 to your bridge (e.g., virbr1) and assign VMs to that network. Failover behavior can be tested by unplugging one cable—the bond will seamlessly shift traffic to the remaining interface without disrupting VM connectivity.

Tags: KVM libvirt linux-bridge NAT Bonding

Posted on Fri, 17 Jul 2026 17:24:20 +0000 by johnsonzhang