Virtual Network Configuration with Libvirt: Complete Guide

Introduction

Virtual networking is a fundamental component of KVM/QEMU virtualization, enabling virtual machines to communicate with each other, the host system, and external networks. Libvirt provides a comprehensive framework for configuring and managing virtual networks, offering flexibility ranging from simple NAT configurations to complex multi-tier network architectures.

This comprehensive guide explores libvirt's virtual networking capabilities in depth, covering network modes, bridge configurations, advanced routing scenarios, and performance optimization. Whether you're building a home lab, development environment, or production infrastructure, understanding libvirt networking is essential for creating secure, efficient, and scalable virtualized environments.

Libvirt virtual networks leverage Linux networking components including bridges, TAP devices, iptables, and dnsmasq to provide networking services to virtual machines. The abstraction layer libvirt provides simplifies complex networking configurations while maintaining the flexibility to implement advanced networking scenarios when needed.

By the end of this guide, you'll master libvirt network configuration, from basic NAT setups to advanced scenarios involving VLANs, multiple bridges, custom routing, and network isolation strategies used in production environments.

Understanding Libvirt Virtual Networking

Libvirt Network Architecture

┌─────────────────────────────────────────────┐
│         Virtual Machine (Guest)             │
│              eth0 (Guest NIC)               │
└──────────────────┬──────────────────────────┘
                   │
         ┌─────────▼─────────┐
         │  vnet0 (TAP Device)│
         │   52:54:00:xx:xx  │
         └─────────┬──────────┘
                   │
         ┌─────────▼─────────┐
         │  virbr0 (Bridge)  │
         │   192.168.122.1   │
         └─────────┬──────────┘
                   │
    ┌──────────────┴───────────────┐
    │                              │
┌───▼────┐                  ┌──────▼─────┐
│dnsmasq │                  │  iptables  │
│ (DHCP) │                  │    (NAT)   │
└────────┘                  └──────┬─────┘
                                   │
                           ┌───────▼────────┐
                           │ Physical NIC   │
                           │ (Host Network) │
                           └────────────────┘

Network Components

Virtual Network Interface (vnet):

  • TAP device connected to guest VM
  • Appears as regular NIC inside guest
  • Managed by libvirt automatically

Virtual Bridge (virbr):

  • Software switch connecting VMs
  • Bridges TAP devices together
  • Provides layer 2 connectivity

dnsmasq:

  • Provides DHCP services
  • DNS forwarding and caching
  • Managed by libvirt

iptables:

  • NAT and forwarding rules
  • Firewall and filtering
  • Routing between networks

Network Modes in Libvirt

1. NAT Mode (Default)

NAT (Network Address Translation) mode provides internet connectivity to VMs while keeping them isolated from the external network.

Characteristics:

  • VMs get private IP addresses (192.168.122.0/24 by default)
  • VMs can access external networks
  • External networks cannot directly access VMs
  • Host acts as router with NAT

Use cases:

  • Development environments
  • Test VMs
  • VMs that need internet but not external access

Creating NAT Network:

# Create NAT network configuration
cat > nat-network.xml << 'EOF'
<network>
  <name>nat-network</name>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='virbr1' stp='on' delay='0'/>
  <domain name='nat-network.local'/>
  <ip address='192.168.100.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.100.10' end='192.168.100.250'/>
      <host mac='52:54:00:11:22:33' name='webserver' ip='192.168.100.50'/>
    </dhcp>
  </ip>
</network>
EOF

# Define and start the network
virsh net-define nat-network.xml
virsh net-start nat-network
virsh net-autostart nat-network

# Verify network
virsh net-list
virsh net-info nat-network

View generated iptables rules:

# Check NAT rules
iptables -t nat -L -n -v | grep virbr1

# Check forwarding rules
iptables -L FORWARD -n -v | grep virbr1

# View all rules for virtual network
iptables-save | grep virbr1

2. Routed Mode

Routed mode connects VMs to the physical network through routing instead of bridging, maintaining separate subnets.

Characteristics:

  • VMs use routable IP addresses
  • No NAT translation
  • Requires static routes on physical network
  • Layer 3 connectivity

Creating Routed Network:

cat > routed-network.xml << 'EOF'
<network>
  <name>routed-network</name>
  <forward mode='route' dev='eth0'/>
  <bridge name='virbr-route' stp='on' delay='0'/>
  <ip address='10.10.10.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.10.10.10' end='10.10.10.250'/>
    </dhcp>
  </ip>
</network>
EOF

virsh net-define routed-network.xml
virsh net-start routed-network
virsh net-autostart routed-network

# Add route on external router (example)
# Route 10.10.10.0/24 via <host-IP>

Configure host routing:

# Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward

# Make permanent
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

# Add firewall rules
iptables -A FORWARD -i virbr-route -j ACCEPT
iptables -A FORWARD -o virbr-route -j ACCEPT

3. Bridge Mode

Bridge mode connects VMs directly to the physical network, making them appear as physical hosts on the same network.

Characteristics:

  • VMs get IP addresses from physical network DHCP
  • Direct layer 2 connectivity
  • VMs visible on physical network
  • Best performance

Prerequisites:

# Install bridge utilities
apt install bridge-utils  # Debian/Ubuntu
dnf install bridge-utils  # RHEL/CentOS

# Check existing bridges
brctl show
ip link show type bridge

Creating Host Bridge (Netplan - Ubuntu/Debian):

# Backup existing configuration
cp /etc/netplan/01-netcfg.yaml /etc/netplan/01-netcfg.yaml.bak

# Create bridge configuration
cat > /etc/netplan/01-netcfg.yaml << 'EOF'
network:
  version: 2
  ethernets:
    ens18:
      dhcp4: no
      dhcp6: no
  bridges:
    br0:
      interfaces: [ens18]
      dhcp4: yes
      parameters:
        stp: true
        forward-delay: 4
EOF

# Apply configuration
netplan apply

# Verify bridge
ip addr show br0
brctl show br0

Creating Host Bridge (NetworkManager - RHEL/CentOS):

# Create bridge
nmcli connection add type bridge ifname br0 con-name br0

# Add physical interface to bridge
nmcli connection add type bridge-slave ifname ens18 master br0

# Configure bridge IP (DHCP or static)
nmcli connection modify br0 ipv4.method auto

# Activate bridge
nmcli connection up br0

# Verify
nmcli connection show
bridge link show

Creating Libvirt Bridge Network:

cat > bridge-network.xml << 'EOF'
<network>
  <name>bridge-network</name>
  <forward mode='bridge'/>
  <bridge name='br0'/>
</network>
EOF

virsh net-define bridge-network.xml
virsh net-start bridge-network
virsh net-autostart bridge-network

Attach VM to Bridge:

# Attach to existing VM
virsh attach-interface ubuntu-vm bridge br0 --model virtio --config --live

# Or create VM with bridge
virt-install \
  --name ubuntu-bridge \
  --memory 2048 \
  --vcpus 2 \
  --disk path=/var/lib/libvirt/images/ubuntu-bridge.qcow2,size=20 \
  --network bridge=br0,model=virtio \
  --os-variant ubuntu22.04 \
  --cdrom /path/to/ubuntu.iso

4. Isolated Mode

Isolated mode creates a network where VMs can communicate with each other but have no connectivity to the host or external networks.

Characteristics:

  • Complete network isolation
  • VMs can only communicate with each other
  • No internet or host access
  • Useful for security testing

Creating Isolated Network:

cat > isolated-network.xml << 'EOF'
<network>
  <name>isolated</name>
  <bridge name='virbr-iso' stp='on' delay='0'/>
  <domain name='isolated.local'/>
  <ip address='10.0.0.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.0.0.10' end='10.0.0.250'/>
    </dhcp>
  </ip>
</network>
EOF

virsh net-define isolated-network.xml
virsh net-start isolated
virsh net-autostart isolated

# Verify no forwarding is configured
virsh net-dumpxml isolated | grep forward
# Should show no forward element

5. Open/Forwarding Mode

Open mode forwards all traffic without NAT or routing restrictions.

cat > open-network.xml << 'EOF'
<network>
  <name>open-network</name>
  <forward mode='open'/>
  <bridge name='virbr-open' stp='on' delay='0'/>
  <ip address='172.16.0.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='172.16.0.10' end='172.16.0.250'/>
    </dhcp>
  </ip>
</network>
EOF

virsh net-define open-network.xml
virsh net-start open-network

Advanced Network Configuration

Static IP Assignment via DHCP

# Get VM MAC address
virsh dumpxml ubuntu-vm | grep "mac address"
# Output: <mac address='52:54:00:xx:xx:xx'/>

# Update network with static DHCP entry
virsh net-update default add ip-dhcp-host \
  "<host mac='52:54:00:xx:xx:xx' name='ubuntu-vm' ip='192.168.122.100'/>" \
  --live --config

# Verify
virsh net-dhcp-leases default

# Add multiple static assignments
cat > dhcp-hosts.xml << 'EOF'
<host mac='52:54:00:11:11:11' name='web1' ip='192.168.122.11'/>
<host mac='52:54:00:22:22:22' name='web2' ip='192.168.122.12'/>
<host mac='52:54:00:33:33:33' name='db1' ip='192.168.122.20'/>
EOF

# Add each host
while IFS= read -r line; do
    virsh net-update default add ip-dhcp-host "$line" --live --config
done < dhcp-hosts.xml

Port Forwarding in NAT Networks

# Forward host port to VM
virsh net-update default add-last ip-forward \
  "<forward proto='tcp' address='0.0.0.0' port='8080' dev='virbr0'> \
   <interface dev='eth0'/> \
   <backend dev='eth0'/> \
   </forward>" \
  --live --config

# Using iptables directly for more control
# Forward host port 80 to VM port 80
iptables -t nat -A PREROUTING -p tcp --dport 8080 \
  -j DNAT --to-destination 192.168.122.100:80

# Allow forwarding
iptables -A FORWARD -d 192.168.122.100 -p tcp --dport 80 -j ACCEPT

# Make permanent (Ubuntu/Debian)
apt install iptables-persistent
iptables-save > /etc/iptables/rules.v4

Multiple IP Ranges on Single Network

cat > multi-ip-network.xml << 'EOF'
<network>
  <name>multi-ip</name>
  <forward mode='nat'/>
  <bridge name='virbr-multi' stp='on' delay='0'/>
  <ip address='192.168.100.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.100.10' end='192.168.100.100'/>
    </dhcp>
  </ip>
  <ip address='10.10.10.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.10.10.10' end='10.10.10.100'/>
    </dhcp>
  </ip>
</network>
EOF

virsh net-define multi-ip-network.xml
virsh net-start multi-ip

IPv6 Configuration

cat > ipv6-network.xml << 'EOF'
<network>
  <name>ipv6-network</name>
  <forward mode='nat'/>
  <bridge name='virbr-v6' stp='on' delay='0'/>
  <ip address='192.168.150.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.150.10' end='192.168.150.250'/>
    </dhcp>
  </ip>
  <ip family='ipv6' address='fd00:cafe:cafe::1' prefix='64'>
    <dhcp>
      <range start='fd00:cafe:cafe::10' end='fd00:cafe:cafe::ff'/>
    </dhcp>
  </ip>
</network>
EOF

virsh net-define ipv6-network.xml
virsh net-start ipv6-network

# Enable IPv6 forwarding on host
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf
sysctl -p

VLAN Configuration

# Create VLAN tagged network
cat > vlan-network.xml << 'EOF'
<network>
  <name>vlan100</name>
  <forward mode='bridge'/>
  <bridge name='br0'/>
  <vlan trunk='yes'>
    <tag id='100'/>
  </vlan>
</network>
EOF

virsh net-define vlan-network.xml
virsh net-start vlan100

# Configure VM with VLAN
virsh edit ubuntu-vm

# Add VLAN to interface:
<interface type='network'>
  <source network='vlan100'/>
  <vlan>
    <tag id='100'/>
  </vlan>
</interface>

SR-IOV Configuration

SR-IOV (Single Root I/O Virtualization) provides near-native network performance by allowing VMs to directly access physical network interfaces.

# Check if NIC supports SR-IOV
lspci | grep Ethernet
lspci -v -s <device-id> | grep SR-IOV

# Enable SR-IOV on NIC
echo 4 > /sys/class/net/ens1f0/device/sriov_numvfs

# Make persistent (add to /etc/rc.local or udev rule)
cat > /etc/udev/rules.d/sriov.rules << 'EOF'
ACTION=="add", SUBSYSTEM=="net", ENV{ID_NET_NAME}=="ens1f0", \
RUN+="/bin/bash -c 'echo 4 > /sys/class/net/ens1f0/device/sriov_numvfs'"
EOF

# List virtual functions
lspci | grep Virtual

# Create network pool for VFs
cat > sriov-network.xml << 'EOF'
<network>
  <name>sriov-network</name>
  <forward mode='hostdev' managed='yes'>
    <pf dev='ens1f0'/>
  </forward>
</network>
EOF

virsh net-define sriov-network.xml
virsh net-start sriov-network

# Attach SR-IOV interface to VM
virsh edit ubuntu-vm

<interface type='network'>
  <source network='sriov-network'/>
</interface>

Network Performance Optimization

Multi-queue virtio-net

# Enable multi-queue in VM definition
virsh edit ubuntu-vm

<interface type='network'>
  <source network='default'/>
  <model type='virtio'/>
  <driver name='vhost' queues='4'/>
</interface>

# Restart VM
virsh shutdown ubuntu-vm
virsh start ubuntu-vm

# Inside guest VM, enable multi-queue
ethtool -L eth0 combined 4

# Verify
ethtool -l eth0

vhost-net Optimization

# Ensure vhost-net module is loaded
lsmod | grep vhost
modprobe vhost_net

# Make permanent
echo "vhost_net" >> /etc/modules

# Use vhost in network configuration
virsh edit ubuntu-vm

<interface type='network'>
  <source network='default'/>
  <model type='virtio'/>
  <driver name='vhost' txmode='iothread' ioeventfd='on' event_idx='on'/>
</interface>

Network Offloading

# Configure offloading in VM XML
<interface type='network'>
  <source network='default'/>
  <model type='virtio'/>
  <driver name='vhost'>
    <host csum='on' gso='on' tso4='on' tso6='on' ecn='on' ufo='on'/>
    <guest csum='on' tso4='on' tso6='on' ecn='on' ufo='on'/>
  </driver>
</interface>

# Inside guest, verify offloading
ethtool -k eth0 | grep offload

Bandwidth Limiting

# Limit bandwidth for VM interface
virsh domiftune ubuntu-vm vnet0 \
  --inbound 100000,150000,200000 \
  --outbound 80000,120000,160000

# Parameters: average,peak,burst (in KiB/s)

# Verify
virsh domiftune ubuntu-vm vnet0

# Make permanent
virsh edit ubuntu-vm

<interface type='network'>
  <source network='default'/>
  <bandwidth>
    <inbound average='100000' peak='150000' burst='200000'/>
    <outbound average='80000' peak='120000' burst='160000'/>
  </bandwidth>
</interface>

DNS Configuration

Custom DNS Entries

# Add custom DNS entries to network
virsh net-update default add dns-host \
  "<host ip='192.168.122.100'><hostname>web.local</hostname></host>" \
  --live --config

# Add multiple hostnames to same IP
virsh net-update default add dns-host \
  "<host ip='192.168.122.100'><hostname>web.local</hostname><hostname>www.local</hostname></host>" \
  --live --config

# Add DNS forwarder
virsh net-update default add dns-forwarder \
  "<forwarder addr='8.8.8.8'/>" \
  --live --config

virsh net-update default add dns-forwarder \
  "<forwarder addr='8.8.4.4'/>" \
  --live --config

DNS Configuration in Network XML

cat > dns-network.xml << 'EOF'
<network>
  <name>dns-network</name>
  <forward mode='nat'/>
  <bridge name='virbr-dns'/>
  <domain name='example.local' localOnly='yes'/>
  <dns>
    <forwarder addr='8.8.8.8'/>
    <forwarder addr='1.1.1.1'/>
    <host ip='192.168.200.10'>
      <hostname>web1.example.local</hostname>
      <hostname>www.example.local</hostname>
    </host>
    <host ip='192.168.200.20'>
      <hostname>db1.example.local</hostname>
    </host>
    <txt name='example.local' value='v=spf1 a mx ~all'/>
    <srv service='ldap' protocol='tcp' domain='example.local'
         target='ldap.example.local' port='389' priority='10' weight='10'/>
  </dns>
  <ip address='192.168.200.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.200.10' end='192.168.200.250'/>
    </dhcp>
  </ip>
</network>
EOF

virsh net-define dns-network.xml
virsh net-start dns-network

Firewall and Security

Custom Firewall Rules

# Add custom rules to network
cat > secure-network.xml << 'EOF'
<network>
  <name>secure-network</name>
  <forward mode='nat'/>
  <bridge name='virbr-sec'/>
  <ip address='192.168.180.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.180.10' end='192.168.180.250'/>
    </dhcp>
  </ip>
</network>
EOF

virsh net-define secure-network.xml
virsh net-start secure-network

# Add custom iptables rules
iptables -I FORWARD -i virbr-sec -o virbr-sec -p tcp --dport 22 -j ACCEPT
iptables -I FORWARD -i virbr-sec -o virbr-sec -p tcp --dport 80 -j ACCEPT
iptables -I FORWARD -i virbr-sec -o virbr-sec -p tcp --dport 443 -j ACCEPT
iptables -I FORWARD -i virbr-sec -o virbr-sec -j DROP

# Save rules
iptables-save > /etc/iptables/rules.v4

Network Filtering (nwfilter)

# List available filters
virsh nwfilter-list

# View filter definition
virsh nwfilter-dumpxml clean-traffic

# Create custom filter
cat > custom-filter.xml << 'EOF'
<filter name='custom-filter' chain='root'>
  <uuid>12345678-1234-1234-1234-123456789abc</uuid>
  <!-- Allow ARP -->
  <rule action='accept' direction='inout' priority='100'>
    <mac protocolid='arp'/>
  </rule>
  <!-- Allow IPv4 -->
  <rule action='accept' direction='out' priority='100'>
    <ip/>
  </rule>
  <!-- Allow incoming HTTP/HTTPS -->
  <rule action='accept' direction='in' priority='100'>
    <tcp dstportstart='80' dstportend='80'/>
  </rule>
  <rule action='accept' direction='in' priority='100'>
    <tcp dstportstart='443' dstportend='443'/>
  </rule>
  <!-- Drop everything else -->
  <rule action='drop' direction='inout' priority='1000'>
    <all/>
  </rule>
</filter>
EOF

virsh nwfilter-define custom-filter.xml

# Apply filter to VM interface
virsh edit ubuntu-vm

<interface type='network'>
  <source network='default'/>
  <filterref filter='custom-filter'/>
</interface>

Rate Limiting and QoS

# Create QoS-enabled network
cat > qos-network.xml << 'EOF'
<network>
  <name>qos-network</name>
  <forward mode='nat'/>
  <bridge name='virbr-qos'/>
  <bandwidth>
    <inbound average='50000' peak='100000' burst='50000'/>
    <outbound average='50000' peak='100000' burst='50000'/>
  </bandwidth>
  <ip address='192.168.190.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.190.10' end='192.168.190.250'/>
    </dhcp>
  </ip>
</network>
EOF

virsh net-define qos-network.xml
virsh net-start qos-network

Multi-Host Networking

Connecting VMs Across Hosts

Using VXLAN:

# Host 1
ip link add vxlan100 type vxlan id 100 \
  local 10.0.0.1 \
  remote 10.0.0.2 \
  dev eth0 \
  dstport 4789

ip link set vxlan100 up
brctl addbr br-vxlan
brctl addif br-vxlan vxlan100
ip link set br-vxlan up

# Create libvirt network
cat > vxlan-network.xml << 'EOF'
<network>
  <name>vxlan-network</name>
  <forward mode='bridge'/>
  <bridge name='br-vxlan'/>
</network>
EOF

virsh net-define vxlan-network.xml
virsh net-start vxlan-network

# Host 2 (reverse local/remote IPs)
ip link add vxlan100 type vxlan id 100 \
  local 10.0.0.2 \
  remote 10.0.0.1 \
  dev eth0 \
  dstport 4789
# ... repeat bridge configuration

Using GRE Tunnels:

# Host 1
ip tunnel add gre1 mode gre remote 10.0.0.2 local 10.0.0.1 ttl 255
ip link set gre1 up
ip addr add 172.16.0.1/30 dev gre1

brctl addbr br-gre
brctl addif br-gre gre1
ip link set br-gre up

# Host 2
ip tunnel add gre1 mode gre remote 10.0.0.1 local 10.0.0.2 ttl 255
ip link set gre1 up
ip addr add 172.16.0.2/30 dev gre1
# ... repeat bridge configuration

Network Troubleshooting

Diagnostic Commands

# List all networks
virsh net-list --all

# Check network status
virsh net-info default

# View network XML
virsh net-dumpxml default

# Show DHCP leases
virsh net-dhcp-leases default

# Check bridge status
brctl show
bridge link show

# View bridge forwarding database
bridge fdb show br virbr0

# Check dnsmasq configuration
ps aux | grep dnsmasq
cat /var/lib/libvirt/dnsmasq/default.conf

# View dnsmasq leases
cat /var/lib/libvirt/dnsmasq/default.leases

# Check iptables rules
iptables -t nat -L -n -v
iptables -L FORWARD -n -v

# Monitor network traffic
tcpdump -i virbr0 -n

Common Issues and Solutions

Issue: Network won't start

# Check for errors
virsh net-start default
# View detailed error

# Check if bridge exists
ip link show virbr0

# Verify dnsmasq is not running elsewhere
ps aux | grep dnsmasq

# Check for port conflicts
ss -tulpn | grep :53

# Restart libvirtd
systemctl restart libvirtd
virsh net-start default

Issue: VMs can't get IP addresses

# Check DHCP range
virsh net-dumpxml default | grep range

# Verify dnsmasq is running
ps aux | grep dnsmasq

# Check firewall allows DHCP
iptables -L INPUT -n | grep 67

# Restart network
virsh net-destroy default
virsh net-start default

# Inside VM, request DHCP
dhclient -v eth0  # or
dhcpcd eth0

Issue: VMs can't access internet (NAT)

# Check IP forwarding
cat /proc/sys/net/ipv4/ip_forward
# Should be 1

# Enable if needed
echo 1 > /proc/sys/net/ipv4/ip_forward

# Check NAT rules
iptables -t nat -L POSTROUTING -n -v

# Check forwarding rules
iptables -L FORWARD -n -v

# Verify default route on VM
ip route show

Issue: Bridged network not working

# Check physical interface is in bridge
brctl show br0

# Verify physical interface has no IP
ip addr show ens18
# Should show no inet address

# Check bridge has IP
ip addr show br0
# Should have IP address

# Test connectivity
ping -c 4 <gateway-ip>

# Check bridge forwarding
cat /sys/class/net/br0/bridge/stp_state

Network Monitoring and Statistics

Real-time Monitoring

# Monitor interface statistics
watch -n 1 'virsh domifstat ubuntu-vm vnet0'

# Monitor all VMs
#!/bin/bash
while true; do
    clear
    echo "Network Statistics - $(date)"
    echo "================================"
    for vm in $(virsh list --name); do
        echo "VM: $vm"
        virsh domiflist "$vm"
        for iface in $(virsh domiflist "$vm" | awk 'NR>2 {print $1}'); do
            virsh domifstat "$vm" "$iface"
        done
        echo ""
    done
    sleep 5
done

# Use iftop for bandwidth monitoring
iftop -i virbr0

# Use nethogs for per-process monitoring
nethogs virbr0

Collecting Network Metrics

#!/bin/bash
# Network metrics collection script

LOG_FILE="/var/log/vm-network-stats.log"

collect_stats() {
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')

    for vm in $(virsh list --name); do
        for iface in $(virsh domiflist "$vm" | awk 'NR>2 {print $1}'); do
            stats=$(virsh domifstat "$vm" "$iface" | grep -E 'rx_bytes|tx_bytes')
            echo "$timestamp | $vm | $iface | $stats" >> "$LOG_FILE"
        done
    done
}

# Run every 60 seconds
while true; do
    collect_stats
    sleep 60
done

Best Practices

Network Design Principles

  1. Separate networks by function:
# Management network
virsh net-define mgmt-network.xml

# Application network
virsh net-define app-network.xml

# Database network (isolated)
virsh net-define db-network.xml

# DMZ network
virsh net-define dmz-network.xml
  1. Use static DHCP for servers:
# Assign consistent IPs to server VMs
virsh net-update default add ip-dhcp-host \
  "<host mac='52:54:00:aa:bb:cc' name='web-server' ip='192.168.122.10'/>"
  1. Implement network isolation:
# Use isolated networks for testing
# Use separate networks for production
# Implement firewall rules between networks
  1. Document network topology:
# Create network documentation
virsh net-list --all > /docs/networks.txt
for net in $(virsh net-list --name); do
    virsh net-dumpxml "$net" > "/docs/network-${net}.xml"
done

Security Hardening

# Disable unused networks
virsh net-destroy unused-network
virsh net-autostart unused-network --disable

# Implement strict firewall rules
# Use nwfilter for VM-level filtering
# Enable STP on bridges
# Use VLANs for segmentation
# Implement MAC filtering
# Enable port security

Conclusion

Libvirt's virtual networking capabilities provide a robust, flexible foundation for building complex network topologies in virtualized environments. From simple NAT configurations to advanced multi-host scenarios with VXLANs and SR-IOV, libvirt abstracts the complexity of Linux networking while maintaining full control when needed.

Key takeaways:

  • Choose the appropriate network mode (NAT, bridge, routed, isolated) based on requirements
  • Leverage static DHCP for predictable IP assignments
  • Use network filters and iptables for security
  • Optimize performance with virtio, multi-queue, and vhost-net
  • Implement proper monitoring and troubleshooting procedures
  • Design networks with segmentation and isolation in mind

Master libvirt networking to build secure, efficient, and scalable virtualized infrastructure that meets production requirements while maintaining flexibility for development and testing environments. The networking layer is critical to VM performance and security—invest time in proper configuration and monitoring to ensure optimal results.