| |

LFCE 144 ๐Ÿง KVM Networking โ€” Bridges and NAT

โฑ๏ธ Estimated read: 12 min | |

KVM virtual machines need a network path to communicate with each other, with the host, and with the outside world. The two primary mechanisms are NAT, which hides the VMs behind the host’s IP address, and bridging, which places the VMs directly on the physical LAN with their own routable IPs. The choice between them is a decision about reachability: a VM that only needs outbound internet access can use NAT, but a VM that needs to accept incoming connections from the LAN must use a bridge.

This chapter covers both modes: the default NAT network (virbr0) that libvirt creates automatically, the host bridge (br0) that connects a VM’s tap interface to the physical NIC, and the virsh commands that define, start, and inspect the networks. It also covers the macvtap alternative for direct attachment without a bridge, and the firewall considerations that often prevent a correctly configured bridge from passing traffic.

Key point: The default NAT network works out of the box but makes VMs unreachable from the LAN. A bridged network makes VMs first-class citizens on the physical network, but requires creating a host bridge and attaching the physical NIC to it. The virsh net-define command registers a libvirt network; the ip link command creates the underlying Linux bridge.


Why the two modes exist

The reachability problem. NAT is the default because it requires no configuration. libvirt creates a virtual bridge (virbr0), runs a DHCP server on it, and adds firewall rules that masquerade the VMs’ outbound traffic through the host’s IP . The VM can reach the internet, but the internet cannot reach the VM. For a development VM, this is sufficient. For a production web server, it is not.

The bridge problem. A bridge places the VM’s virtual NIC on the same layer-2 network as the host’s physical NIC. The VM gets an IP from the LAN’s DHCP server (or a static assignment), and it is reachable by that IP from any other machine on the LAN . The host’s physical interface becomes a member of the bridge, and the VM’s vnetX interface is attached to the same bridge. The host and the VM are peers on the network.

The macvtap problem. macvtap is a middle ground. It attaches the VM directly to the physical interface without creating a Linux bridge, giving the VM a private MAC-VLAN endpoint on the wire. It avoids the bridge configuration overhead, but the host cannot communicate with the VM over the macvtap interface in the default mode . Red Hat recommends a Linux bridge over macvtap unless the use case explicitly requires macvtap .


a. The default NAT network

libvirt creates the default NAT network on installation. It is defined in /etc/libvirt/qemu/networks/default.xml and is active by default on most distributions.

# Check the default network
virsh net-list --all

# Name      State    Autostart   Persistent
# default   active   yes         yes

The network’s XML definition uses virbr0 as the bridge, 192.168.122.0/24 as the subnet, and a forward element with mode='nat' .

<network>
  <name>default</name>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <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>

A VM attached to the default network receives an address in the 192.168.122.0/24 range from the dnsmasq instance that libvirt runs. Outbound traffic is masqueraded through the host’s default route. Inbound traffic is blocked unless a port-forwarding rule is added to the host’s firewall .

To attach a VM to the default NAT network:

virt-install --name test-vm --network network=default,model=virtio ...

The model=virtio selects the paravirtualized network driver, which is faster than the emulated e1000 or rtl8139 drivers.


b. The bridged network

A bridged network requires a Linux bridge on the host with the physical NIC attached. The VM’s vnetX interface is then attached to the same bridge, placing it on the physical LAN.

The bridge can be created with nmcli, ip link, or the distribution’s network configuration. The virsh iface-bridge command is a libvirt shortcut that creates the bridge and attaches the physical interface in one step .

# Create a bridge and attach eth0 to it (libvirt shortcut)
virsh iface-bridge eth0 br0

This moves the host’s IP address from eth0 to br0. The host remains reachable on the same address, but the address is now on the bridge instead of the physical interface. The physical interface becomes a member of the bridge with no IP of its own.

For a more controlled configuration, the bridge can be created with ip link:

# Create the bridge
ip link add name br0 type bridge

# Attach the physical interface
ip link set eth0 master br0

# Bring up the bridge
ip link set br0 up

Once the bridge exists, a libvirt network can be defined to reference it. The network’s XML uses forward mode='bridge' and specifies the bridge name.

<network>
  <name>host-bridge</name>
  <forward mode='bridge'/>
  <bridge name='br0'/>
</network>
# Define, start, and autostart the network
virsh net-define br0-network.xml
virsh net-start host-bridge
virsh net-autostart host-bridge

A VM can then be attached to the bridge either through the libvirt network (--network network=host-bridge) or directly by specifying the bridge name in the VM’s interface definition .

<interface type='bridge'>
  <source bridge='br0'/>
  <model type='virtio'/>
</interface>

The VM receives an IP address from the LAN’s DHCP server (or a static assignment) and is reachable by that address from any machine on the LAN. The host and the VM are peers on the same network .


c. Firewall and bridge netfilter

A correctly configured bridge can still fail to pass traffic if the host’s firewall is blocking it. The firewalld service may treat the bridge as a separate zone with different rules. The kernel’s bridge netfilter may also be enabled, which causes iptables rules to apply to bridged traffic in ways that surprise administrators .

# Check if bridge netfilter is enabled
sysctl net.bridge.bridge-nf-call-iptables

# If it is 1 and traffic is failing, try setting it to 0
sysctl -w net.bridge.bridge-nf-call-iptables=0

On systems with firewalld, the bridge interface may need to be added to a trusted zone or the appropriate zone for the LAN.

# Add the bridge to the trusted zone
firewall-cmd --permanent --zone=trusted --add-interface=br0
firewall-cmd --reload

The clean-traffic network filter is a libvirt feature that prevents MAC and IP spoofing from the guest. It is applied with a <filterref> in the interface definition and is recommended for bridged networks where the guest is on the same layer-2 segment as other machines .


Complete Example Session

# ============================================
# PART 1: THE DEFAULT NAT NETWORK
# ============================================
virsh net-list --all

# The default network is active and autostarted.
# It uses virbr0 and 192.168.122.0/24.
# ============================================
# PART 2: INSPECT THE NAT NETWORK
# ============================================
virsh net-dumpxml default

# Shows the forward mode='nat', the bridge name,
# and the DHCP range.
# ============================================
# PART 3: CREATE A VM ON THE NAT NETWORK
# ============================================
virt-install --name nat-vm \
  --vcpus 2 --ram 2048 \
  --disk size=10 \
  --network network=default,model=virtio \
  --cdrom /path/to/iso
# ============================================
# PART 4: CREATE THE HOST BRIDGE
# ============================================
virsh iface-bridge eth0 br0

# The host IP moves from eth0 to br0.
# eth0 becomes a member of the bridge.
# ============================================
# PART 5: VERIFY THE BRIDGE
# ============================================
ip link show type bridge
brctl show br0

# br0 is UP.
# eth0 is a member of br0.
# ============================================
# PART 6: DEFINE THE LIBVIRT BRIDGE NETWORK
# ============================================
cat > br0-network.xml <<'EOF'
<network>
  <name>host-bridge</name>
  <forward mode='bridge'/>
  <bridge name='br0'/>
</network>
EOF

virsh net-define br0-network.xml
virsh net-start host-bridge
virsh net-autostart host-bridge
# ============================================
# PART 7: CREATE A VM ON THE BRIDGE
# ============================================
virt-install --name bridge-vm \
  --vcpus 2 --ram 2048 \
  --disk size=10 \
  --network network=host-bridge,model=virtio \
  --cdrom /path/to/iso
# ============================================
# PART 8: VERIFY THE VM'S IP
# ============================================
virsh domifaddr bridge-vm

# The VM has an IP from the LAN's DHCP range.
# It is reachable from other machines on the LAN.
# ============================================
# PART 9: FIREWALL CHECK
# ============================================
sysctl net.bridge.bridge-nf-call-iptables
firewall-cmd --zone=trusted --add-interface=br0
# ============================================
# PART 10: THE MACVTAP ALTERNATIVE
# ============================================
# Direct attachment without a bridge.
# The host cannot reach the VM in default mode.
# Use only when bridge config is not possible.

The ten parts covered the default NAT network, inspecting it, creating a NAT VM, creating the host bridge, verifying the bridge, defining the libvirt network, creating a bridge VM, verifying the VM’s IP, firewall checks, and the macvtap alternative.


Quick Reference

NAT vs Bridge

FeatureNAT (default)Bridge
Default bridgevirbr0br0 (host-created)
VM IP range192.168.122.0/24LAN subnet
Outbound accessYes (masqueraded)Yes (direct)
Inbound accessNo (without port forward)Yes (direct)
LAN reachabilityNoYes
Host-VM communicationYesYes
ConfigurationNone (default)Host bridge + libvirt network

virsh network commands

CommandPurpose
virsh net-list --allList all networks
virsh net-dumpxml <net>Show network XML
virsh net-define <file>Register a network
virsh net-start <net>Activate a network
virsh net-autostart <net>Start on boot
virsh net-info <net>Show network details

Bridge creation

ToolCommand
libvirt shortcutvirsh iface-bridge eth0 br0
ip linkip link add name br0 type bridge
nmclinmcli con add type bridge ifname br0

VM interface XML

TypeSnippet
NAT<interface type='network'><source network='default'/></interface>
Bridge<interface type='bridge'><source bridge='br0'/></interface>
macvtap<interface type='direct'><source dev='eth0' mode='bridge'/></interface>

Best Practices

โœ… Do This:

# Use NAT for development VMs that only need outbound access
virt-install --network network=default,model=virtio              # โœ…
# Use a bridge for production VMs that need LAN reachability
virsh iface-bridge eth0 br0                                       # โœ…
# Use virtio for the network model
--network network=host-bridge,model=virtio                        # โœ…
# Check bridge netfilter if traffic fails
sysctl net.bridge.bridge-nf-call-iptables                         # โœ…

โŒ Don’t Do This:

# Use NAT for a VM that must accept inbound connections
# Port forwarding is required, which is extra configuration    # โŒ
# Assume a bridge works without checking the firewall
# firewalld may block bridged traffic                           # โŒ
# Use macvtap when host-VM communication is needed
# The host cannot reach the VM in default mode                  # โŒ

Common Pitfalls

PitfallWhy It HappensFix
VM unreachable from LANNAT network usedCreate a bridge and attach the VM
Bridge VM has no IPDHCP not available on the LAN or bridge misconfiguredCheck the bridge members and DHCP
Bridge traffic blockedfirewalld or bridge netfilterAdd the bridge to a trusted zone; check bridge-nf-call-iptables
Host loses IP after iface-bridgeThe IP moved from eth0 to br0Configure the IP on br0 instead
macvtap VM cannot reach hostmacvtap default mode blocks host-VM trafficUse a bridge instead

Real-World Examples

1. Default NAT network

virsh net-list --all

2. NAT VM creation

virt-install --network network=default,model=virtio

3. Create a bridge

virsh iface-bridge eth0 br0

4. Verify bridge members

brctl show br0

5. Define a libvirt bridge network

virsh net-define br0-network.xml

6. Bridge VM creation

virt-install --network network=host-bridge,model=virtio

7. Check VM IP

virsh domifaddr bridge-vm

8. Firewall trust

firewall-cmd --zone=trusted --add-interface=br0

9. Bridge netfilter

sysctl net.bridge.bridge-nf-call-iptables

10. macvtap interface

<interface type='direct'>
  <source dev='eth0' mode='bridge'/>
</interface>

Visual

NAT networking

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  HOST                                                        โ”‚
โ”‚    eth0 (192.168.1.10)                                       โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  virbr0 (192.168.122.1)                                     โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ”œโ”€โ”€ VM1 (192.168.122.2)                               โ”‚
โ”‚       โ””โ”€โ”€ VM2 (192.168.122.3)                               โ”‚
โ”‚                                                              โ”‚
โ”‚  Outbound: NAT through eth0                                 โ”‚
โ”‚  Inbound: blocked (no port forward)                          โ”‚
โ”‚  LAN cannot reach the VMs directly.                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Bridged networking

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  HOST                                                        โ”‚
โ”‚    br0 (192.168.1.10)                                       โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ”œโ”€โ”€ eth0 (physical, no IP)                            โ”‚
โ”‚       โ”œโ”€โ”€ vnet0 (VM1)                                       โ”‚
โ”‚       โ””โ”€โ”€ vnet1 (VM2)                                       โ”‚
โ”‚                                                              โ”‚
โ”‚  VM1 and VM2 are on the LAN.                                 โ”‚
โ”‚  They get LAN IPs and are reachable from the LAN.            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The bridge components

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  br0 (bridge)                                                โ”‚
โ”‚    โ”œโ”€โ”€ eth0 (physical NIC)                                   โ”‚
โ”‚    โ”œโ”€โ”€ vnet0 (VM1 tap)                                       โ”‚
โ”‚    โ””โ”€โ”€ vnet1 (VM2 tap)                                       โ”‚
โ”‚                                                              โ”‚
โ”‚  All members share the same layer-2 segment.                 โ”‚
โ”‚  The bridge forwards frames between them.                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The NAT port forward

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  External client                                             โ”‚
โ”‚       โ”‚                                                      โ”‚
โ”‚       โ–ผ                                                      โ”‚
โ”‚  Host IP:8080 โ”€โ”€โ–บ DNAT โ”€โ”€โ–บ VM 192.168.122.50:80            โ”‚
โ”‚                                                              โ”‚
โ”‚  Without the DNAT rule, inbound is blocked.                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Default networkNAT, virbr0, 192.168.122.0/24
Bridge networkHost bridge (br0), LAN subnet
NAT inboundBlocked without port forwarding
Bridge inboundDirect
Bridge creationvirsh iface-bridge eth0 br0
libvirt network definevirsh net-define <file>
VM interface modelvirtio (recommended)
macvtap limitationHost cannot reach VM in default mode
FirewallAdd bridge to trusted zone if needed

Key takeaways:

  • NAT is the default and requires no configuration. libvirt creates virbr0, runs DHCP, and masquerades outbound traffic. The VM can reach the internet, but the internet cannot reach the VM without port forwarding .
  • Bridging makes the VM a peer on the physical LAN. The host’s physical NIC is attached to a Linux bridge, and the VM’s tap interface is attached to the same bridge. The VM gets a LAN IP and is reachable from any machine on the network .
  • The bridge must be created on the host before libvirt can use it. virsh iface-bridge creates the bridge and moves the host’s IP to it. A libvirt network with forward mode='bridge' references the bridge by name .
  • Firewall and bridge netfilter can block bridged traffic. firewalld may treat the bridge as a separate zone, and net.bridge.bridge-nf-call-iptables may cause iptables rules to filter bridged frames. Check both if the bridge is configured but traffic fails .
  • macvtap is an alternative but has a host-VM communication limitation. It attaches the VM directly to the physical NIC without a bridge, but the host cannot reach the VM over the macvtap interface in the default mode. Use a bridge when host-VM communication is required .
  • virtio is the recommended network model. It is paravirtualized and significantly faster than the emulated e1000 or rtl8139 drivers.

Remember: KVM networking is a choice between reachability and simplicity. NAT is simple and works for development, but the VMs are hidden behind the host. A bridge is more configuration, but it makes the VMs first-class citizens on the LAN. Create the bridge with virsh iface-bridge, define a libvirt network with forward mode='bridge', and attach the VM with model=virtio. Check the firewall and bridge netfilter if the VM has an IP but cannot communicate. And remember that macvtap is not a drop-in replacement for a bridge when the host needs to talk to the VM.

Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!