How to List DHCP-Assigned IP Addresses for KVM/libvirt Virtual Machines


2 views

The most straightforward method is examining the DHCP lease file maintained by libvirt's dnsmasq instance. On Ubuntu systems, this is typically located at:

sudo cat /var/lib/libvirt/dnsmasq/virbr0.status

This JSON-formatted output will show all active leases with MAC addresses and assigned IPs. For older systems, you might need to check:

sudo cat /var/lib/libvirt/dnsmasq/default.leases

To create a complete mapping from VM names to IP addresses, you'll need to combine the lease information with VM configuration data:

for vm in $(virsh list --name --all); do
    vm_mac=$(virsh dumpxml $vm | grep 'mac address' | awk -F\' '{print $2}')
    vm_ip=$(grep -B1 "$vm_mac" /var/lib/libvirt/dnsmasq/virbr0.status | grep ip-address | cut -d\" -f4)
    echo "$vm: $vm_ip"
done

For newer libvirt versions (1.2.6+), a built-in command provides this functionality:

virsh net-dhcp-leases default

Sample output:

 Expiry Time          MAC address        Protocol  IP address        Hostname        Client ID or DUID
------------------------------------------------------------------------------------------------------
 2023-07-15 14:23:45  52:54:00:12:34:56  ipv4      192.168.122.45    machine1        -

For environments where DHCP lease files aren't accessible, you can parse the ARP cache after correlating MAC addresses:

arp -n -i virbr0 | grep -v incomplete | while read ip _ _ mac _; do
    vm=$(virsh list --name --all | while read name; do 
        [[ $(virsh dumpxml $name | grep -q $mac) ]] && echo $name && break
    done)
    [ -n "$vm" ] && echo "$vm: $ip"
done

Ensure your network is properly configured for DHCP. The XML should resemble:

<network>
  <name>default</name>
  <bridge name='virbr0'/>
  <forward mode='nat'/>
  <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>

If you're not seeing expected results:

  • Verify the network is active: virsh net-list --all
  • Check dnsmasq is running: ps aux | grep dnsmasq
  • Restart the network: virsh net-destroy default && virsh net-start default

When working with KVM/libvirt virtual networks, DHCP lease information is stored in a specific location. For the default network configuration shown in your XML, leases are recorded in:

/var/lib/libvirt/dnsmasq/virbr0.status

This JSON-formatted file contains the complete mapping between MAC addresses and assigned IPs, along with lease timestamps.

The most reliable way to list active DHCP leases is through libvirt's network commands:

virsh net-dhcp-leases default

Sample output for your case would look like:

Expiry Time          MAC address        Protocol  IP address        Hostname  Client ID or DUID
-----------------------------------------------------------------------------------------
2024-03-15 12:34:56  00:16:36:52:e8:9c  ipv4      192.168.122.16    machine1  -
2024-03-15 12:35:12  00:16:36:00:61:b0  ipv4      192.168.122.238   machine2  -

For older libvirt versions without net-dhcp-leases support, parse the JSON file directly:

sudo cat /var/lib/libvirt/dnsmasq/virbr0.status | jq -r '.[] | "\(.hostname) IP address = \(.ip-address)"'

This produces your desired output format:

machine1 IP address = 192.168.122.16
machine2 IP address = 192.168.122.238

When you need to cross-reference ARP data with libvirt domain information:

for mac in $(virsh dumpxml machine1 | xmllint --xpath "string(/domain/devices/interface/mac/@address)" -); do
  grep "$mac" /proc/net/arp
done

Here's a complete Bash solution that combines all approaches:

#!/bin/bash

NETWORK="default"
OUTPUT_FORMAT="%-20s %-15s %-17s\\n"

printf "$OUTPUT_FORMAT" "VM Name" "IP Address" "MAC Address"
printf "===================================================\\n"

for domain in $(virsh list --name --all); do
  MAC=$(virsh dumpxml "$domain" | xmllint --xpath "string(/domain/devices/interface/mac/@address)" - 2>/dev/null)
  
  if [ -n "$MAC" ]; then
    IP=$(virsh net-dhcp-leases "$NETWORK" | awk -v mac="$MAC" '$2 == mac {print $5}')
    printf "$OUTPUT_FORMAT" "$domain" "${IP:-N/A}" "$MAC"
  fi
done
  • Use virsh net-dhcp-leases as the primary method (libvirt 1.2.6+)
  • For legacy systems, parse virbr0.status with JSON tools
  • Combine with virsh domifaddr for additional interface data
  • Consider setting static DHCP mappings in your network XML for critical VMs