How to Update Libvirt DHCP Configuration Without Restarting VMs or Daemon


5 views

When working with libvirt's network configurations, many administrators face the frustrating requirement of restarting the entire libvirt daemon (and consequently all running VMs) when making DHCP changes. This becomes particularly problematic in production environments where downtime must be minimized.

The typical network XML configuration looks like this:

<network>
  <name>mybridge</name>
  <forward mode='bridge'/>
  <bridge name='br0'/>
  <ip address='10.1.1.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.1.1.2' end='10.1.1.254'/>
      <host mac='54:52:00:21:01:ba' name='virstvm' ip='10.1.1.10'/>
      <host mac='00:16:36:2d:71:f9' name='secvm' ip='10.1.1.20'/>
    </dhcp>
  </ip>
</network>

Libvirt provides commands to modify network configurations without requiring a full daemon restart:

# First, define the updated network configuration in a file
cat > updated_network.xml <<EOF
<network>
  <name>mybridge</name>
  <forward mode='bridge'/>
  <bridge name='br0'/>
  <ip address='10.1.1.1' netmask='255.255.255.0'>
    <dhcp>
      <range start='10.1.1.2' end='10.1.1.254'/>
      <host mac='54:52:00:21:01:ba' name='virstvm' ip='10.1.1.10'/>
      <host mac='00:16:36:2d:71:f9' name='secvm' ip='10.1.1.20'/>
      <host mac='52:54:00:12:34:56' name='newvm' ip='10.1.1.30'/>
    </dhcp>
  </ip>
</network>
EOF

# Update the network definition
virsh net-update mybridge --command define --file updated_network.xml --live --config

For simpler changes, you can use the direct net-update syntax:

virsh net-update mybridge add ip-dhcp-host \
"<host mac='52:54:00:12:34:56' name='newvm' ip='10.1.1.30'/>" \
--live --config

After making changes, verify they've been applied:

# Check current network XML
virsh net-dumpxml mybridge

# Check DHCP leases
virsh net-dhcp-leases mybridge
  • The --live flag applies changes to the running configuration
  • The --config flag persists changes across reboots
  • New DHCP entries will only affect new leases - existing leases may need renewal
  • For complete DHCP reload, you can restart just dnsmasq: pkill -HUP dnsmasq

For frequent changes, consider creating a helper script:

#!/bin/bash
NETWORK="mybridge"
MAC=$1
NAME=$2
IP=$3

virsh net-update $NETWORK add ip-dhcp-host \
"<host mac='$MAC' name='$NAME' ip='$IP'/>" \
--live --config

echo "Added $NAME ($MAC) with IP $IP to $NETWORK network"

When working with libvirt's network configurations, many administrators face this frustrating scenario: You need to add a new static DHCP reservation for a VM, but applying the changes requires restarting the libvirtd service - which inevitably disrupts all running virtual machines. The standard approach of editing /etc/libvirt/qemu/networks/default.xml and restarting simply isn't production-friendly.

Libvirt provides a dynamic alternative through the virsh command-line tool. Here's the proper workflow:

# First, dump the current network config to a temporary file
virsh net-dumpxml default > default_network.xml

# Edit the file to add your new DHCP host entry
<host mac='52:54:00:4a:1d:07' name='newvm' ip='10.1.1.30'/>

# Define the updated network
virsh net-define default_network.xml

# Apply changes to the running network
virsh net-update default add ip-dhcp-host \
    "--mac 52:54:00:4a:1d:07 --ip 10.1.1.30 --name newvm" \
    --live --config

The magic happens with net-update, which supports several operations:

  • add - Appends new configuration
  • delete - Removes existing configuration
  • modify - Edits existing entries

The --live flag applies changes immediately to the running network, while --config persists them for future boots.

To confirm your updates took effect without disruption:

# Check the running configuration
virsh net-dumpxml default

# View active leases
virsh net-dhcp-leases default

For infrastructure-as-code environments, you can integrate this into your provisioning scripts. Here's an Ansible example:

- name: Add static DHCP reservation
  community.libvirt.virt_net:
    name: default
    command: update
    xml: |
      <host mac='{{ vm_mac }}' name='{{ vm_name }}' ip='{{ vm_ip }}'/>
    live: yes
    config: yes

If you encounter issues after updates:

  1. Check journalctl -u libvirtd for parsing errors
  2. Ensure no MAC address conflicts exist
  3. Verify IP addresses are within your defined range