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 configurationdelete
- Removes existing configurationmodify
- 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:
- Check
journalctl -u libvirtd
for parsing errors - Ensure no MAC address conflicts exist
- Verify IP addresses are within your defined range