KVM/libvirt: How to Configure Static Guest IPs via Host-Managed Bridge Networking


2 views

When managing virtual machines with KVM/libvirt, you might want to enforce static IP configurations from the host rather than configuring each guest individually. This becomes particularly useful when:

  • Managing large VM deployments
  • Needing consistent network configurations across environments
  • Automating VM provisioning

In bridge mode (the most common production setup), you have two approaches:

1. <interface type='bridge'>
   <mac address='52:54:00:xx:xx:xx'/>
   <source bridge='br0'/>
   <model type='virtio'/>
</interface>

2. <interface type='network'>
   <source network='default'/>
   <model type='virtio'/>
</interface>

Modify your libvirt network definition:

sudo virsh net-edit default

<network>
  <name>default</name>
  <bridge name='virbr0'/>
  <forward/>
  <ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='192.168.122.2' end='192.168.122.254'/>
      <host mac='52:54:00:xx:xx:xx' name='vm1' ip='192.168.122.100'/>
    </dhcp>
  </ip>
</network>

Restart the network and VM:

sudo virsh net-destroy default
sudo virsh net-start default
sudo virsh reboot vm1

For more control, create a dedicated network:

cat > static-net.xml <<EOF
<network>
  <name>static-vm-net</name>
  <bridge name='virbr1'/>
  <forward mode='bridge'/>
  <ip address='10.0.0.1' netmask='255.255.255.0'>
    <static>
      <mac address='52:54:00:xx:xx:xx'/>
      <ip address='10.0.0.100'/>
    </static>
  </ip>
</network>
EOF

sudo virsh net-define static-net.xml
sudo virsh net-start static-vm-net

For Windows VMs, you'll need to:

  1. Install virtio-net drivers
  2. Set the MAC address in the VM configuration to match your static assignment
  3. Use this PowerShell command in the guest if needed:
Set-NetIPInterface -InterfaceAlias "Ethernet" -Dhcp Disabled
New-NetIPAddress -InterfaceAlias "Ethernet" -IPAddress 10.0.0.100 -PrefixLength 24 -DefaultGateway 10.0.0.1
  • Check MAC address consistency between VM config and network definition
  • Verify network filters aren't blocking traffic (virsh nwfilter-list)
  • Inspect DHCP leases: cat /var/lib/libvirt/dnsmasq/default.leases

When working with KVM/libvirt in bridge mode, the virtualization host acts as a network bridge connecting virtual machines to the physical network. The traditional approach involves configuring network settings within each guest OS, but there are scenarios where host-side configuration is preferable:

  • Centralized management of VM network configurations
  • Automation through infrastructure-as-code tools
  • Pre-boot network configuration
  • Standardization across multiple VM deployments

There are two primary approaches to achieve static IP assignment from the host:

Method 1: Using DHCP Reservations

This method leverages libvirt's built-in DHCP server capabilities:


# Edit the network definition
virsh net-edit default

# Add the following inside the <network> tag
<ip address='192.168.122.1' netmask='255.255.255.0'>
    <dhcp>
        <range start='192.168.122.2' end='192.168.122.254'/>
        <host mac='52:54:00:00:00:01' name='vm1' ip='192.168.122.100'/>
    </dhcp>
</ip>

Method 2: Direct Interface Configuration

For more control, configure the interface directly in the VM's XML:


virsh edit vm1

# Add/modify the interface section
<interface type='bridge'>
    <mac address='52:54:00:00:00:01'/>
    <source bridge='br0'/>
    <protocol family='ipv4'>
        <ip address='192.168.1.100' prefix='24'/>
        <route gateway='192.168.1.1'/>
    </protocol>
</interface>

For Windows VMs, additional steps may be required to ensure proper network initialization:


# In the VM XML definition, add:
<metadata>
    <libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
        <libosinfo:os id="http://microsoft.com/win/10"/>
    </libosinfo:libosinfo>
</metadata>
<clock offset='localtime'/>
<features>
    <acpi/>
    <apic/>
    <hyperv>
        <relaxed state='on'/>
        <vapic state='on'/>
        <spinlocks state='on' retries='8191'/>
    </hyperv>
</features>

When configuration doesn't take effect:

  1. Restart the libvirt network: virsh net-destroy default && virsh net-start default
  2. Verify guest agent is installed and running
  3. Check for MAC address conflicts
  4. Ensure the bridge interface is properly configured on the host

For automated deployments, consider this bash script snippet:


#!/bin/bash
VM_NAME="vm1"
IP_ADDR="192.168.1.100"
GATEWAY="192.168.1.1"
MAC="52:54:00:00:00:01"

virsh dumpxml $VM_NAME > /tmp/$VM_NAME.xml
xmlstarlet ed -L \
    -u "/domain/devices/interface[@type='bridge']/mac/@address" -v "$MAC" \
    -s "/domain/devices/interface[@type='bridge']" -t elem -n "protocol" -v "" \
    -s "/domain/devices/interface[@type='bridge']/protocol" -t elem -n "ip" -v "" \
    -i "/domain/devices/interface[@type='bridge']/protocol/ip" -t attr -n "address" -v "$IP_ADDR" \
    -i "/domain/devices/interface[@type='bridge']/protocol/ip" -t attr -n "prefix" -v "24" \
    -s "/domain/devices/interface[@type='bridge']/protocol" -t elem -n "route" -v "" \
    -i "/domain/devices/interface[@type='bridge']/protocol/route" -t attr -n "gateway" -v "$GATEWAY" \
    /tmp/$VM_NAME.xml

virsh define /tmp/$VM_NAME.xml