Get list of DHCP clients with KVM+libvirt?
Solution 1:
This feature was requested a long time ago. Now libvirt supports it by providing two new commands: domifaddr and net-dhcp-leases
Usage: domifaddr <domain> [interface] [--full] [--source lease|agent]
Example outputs:
virsh # domifaddr f20 --source agent
Name MAC address Protocol Address
-------------------------------------------------------------------------------
lo 00:00:00:00:00:00 ipv4 127.0.0.1/8
- - ipv6 ::1/128
eth0 52:54:00:2e:45:ce ipv4 10.1.33.188/24
- - ipv6 2001:db8:0:f101::2/64
- - ipv6 fe80::5054:ff:fe2e:45ce/64
eth1 52:54:00:b1:70:19 ipv4 192.168.105.201/16
- - ipv4 192.168.201.195/16
- - ipv6 2001:db8:ca2:2:1::bd/128
eth2 52:54:00:36:2a:e5 N/A N/A
eth3 52:54:00:20:70:3d ipv4 192.168.105.240/16
- - ipv6 fe80::5054:ff:fe20:703d/64
virsh # domifaddr f20 --full
Name MAC address Protocol Address
-------------------------------------------------------------------------------
vnet0 52:54:00:2e:45:ce ipv6 2001:db8:0:f101::2/64
vnet1 52:54:00:b1:70:19 ipv4 192.168.105.201/16
vnet1 52:54:00:b1:70:19 ipv6 2001:db8:ca2:2:1::bd/128
vnet3 52:54:00:20:70:3d ipv4 192.168.105.240/16
virsh # domifaddr f20 eth0 --source agent --full
Name MAC address Protocol Address
-------------------------------------------------------------------------------
eth0 52:54:00:2e:45:ce ipv4 10.1.33.188/24
eth0 52:54:00:2e:45:ce ipv6 2001:db8:0:f101::2/128
eth0 52:54:00:2e:45:ce ipv6 fe80::5054:ff:fe2e:45ce/64
For eth0, ipv6 is managed by libvirt, but ipv4 is not.
For eth1, the second IP is created using ip aliasing.
For eth2, there is no IP configured as of yet.
For eth3, only ipv4 has been configured.
fd00::/8 are private ipv6 ranges. Hence not visible through --source lease
In a different scenario:
Example Usage: net-dhcp-leases <network> [mac]
virsh # net-dhcp-leases --network default6
Expiry Time MAC address Protocol IP address Hostname Client ID or DUID
-------------------------------------------------------------------------------------------------------------------
2014-06-16 03:40:14 52:54:00:85:90:e2 ipv4 192.168.150.231/24 fedora20-test 01:52:54:00:85:90:e2
2014-06-16 03:40:17 52:54:00:85:90:e2 ipv6 2001:db8:ca2:2:1::c0/64 fedora20-test 00:04:b1:d8:86:42:e1:6a:aa:cf:d5:86:94:23:6f:94:04:cd
2014-06-16 03:34:42 52:54:00:e8:73:eb ipv4 192.168.150.181/24 ubuntu14-vm -
2014-06-16 03:34:46 52:54:00:e8:73:eb ipv6 2001:db8:ca2:2:1::5b/64 - 00:01:00:01:1b:30:c6:aa:52:54:00:e8:73:eb
Solution 2:
libvirt uses dnsmasq to provide DHCP to the guests, so you could trawl /var/log/daemon.log or dig through the leases file in /var/lib/libvirt to get an IP to hostname mapping.
Solution 3:
So, when investigating this, I found that libvirt uses dnsmasq in order to do DHCP and DNS for guest OSes.
And dnsmasq will set the hostname in the hosts's DNS table based on whatever hostname it receives from the guest.
So in accordance with these instructions and a lot of googling, I simply needed to create and add this to /etc/dhclient.conf:
send host-name "machine1"
Now, from my host OS, I can ping machine1.
Does anyone know why I need to add the trailing "." in order for the DNS entry to resolve? How can I change this?
Solution 4:
I had the same problem so I created the following script:
#!/bin/bash
function showMAC(){
virsh dumpxml ${1}|grep "mac address"|sed "s/.*'\(.*\)'.*/\1/g"
}
function showIP(){
for mac in $($0 -m $1); do
grep $mac /var/log/daemon.log | tail -n 1 | awk '{print $7}'
done
}
if test -z "${1}"; then
echo "Usage: ${0} [-i | -m] <domain>"
echo " -i Show IP address (the default)."
echo " -m Show MAC address."
exit
fi
addr_type="-i"
if test ${1} = "-i" || test ${1} = "-m"; then
addr_type=${1}
shift
fi
domain=${1}
test $addr_type = "-i" && showIP $domain || showMAC $domain
Solution 5:
Lars Kellogg-Stedman has created a set of scripts to automate some of this process. He calls it 'virt-utils'.
He describes it in his blog post here: http://blog.oddbit.com/2013/10/04/automatic-dns-entrie/
He also has a github with some of the scripts he wrote, here:
https://github.com/larsks/virt-utils
You can basically just run this:
git clone https://github.com/larsks/virt-utils
cd virt-utils
sudo make install
virt-hosts
and you will get a listing of each virtual machine by it's "domain name" inside libvirt's virtual-machine-manager. For example, on my machine I have 3 vms running.
don@serebryanya:~/src/virt-utils$ virt-hosts
192.168.122.23 mageia4.x64-net0.default.virt mageia4.x64.default.virt
192.168.122.197 debian7amd64-net0.default.virt debian7amd64.default.virt
192.168.122.15 freebsd10_amd64-net0.default.virt freebsd10_amd64.default.virt
Note, this is not the 'hostname' the VM itself is using, but for a large number of use-cases, it will be 'good enough' and solves the problem of having to 'ifconfig' from within each VM in dhcp land.
Lars' blog posting also shows a way for this to 'auto update' your own /etc/hosts file as libvirt starts and/or stops new VMs. This enables you to do things like ssh myname@fedora20vm or ssh myname@debian6vm without having to find the 192.168.122.x addresses by hand.
I have added a few very minor enhancements, like a script to spit out some ~/.ssh/config options (very very handy for using github on VMs, via Agent Forwarding), here:
https://github.com/donbright/virt-utils (appears to be deleted?)
I'd also like to note that the method of editing dhclient.conf to 'send host-name xxxxx' only works on systems that actually use dhclient.conf in a standard manner. Mageia, for example, has an unusual setup of how it's dhclient works, so the simple instructions wont necessarily work. However, with Lars' method, it works regarldess of the guest OS'es dhcp setup, because he is not relying on the VM to send it's hostname - he is using the 'domain names' within libvirt's machine manager.