Tip: Find the IP address of a virtual machine

Update: see comments

Virtual machines are given a virtual network, but have to decide on their own IP address, which they would usually get from DHCP or by static assignment. This is analogous to the physical case: a physical machine is plugged into a network port, but has to choose its own IP address somehow.

The problem with this is how do you know what IP address the virtual machine has picked?

There are several methods, but by far the simplest is to look at the output of the arp command on the same network segment (usually, just running arp -an on the host will do). As long as the VM has sent anything over the network, it will have sent out its IP address in an ARP response, and the host will have picked that up and added it to the ARP table.

For example, the one virtual machine I am running now has broadcast its IP address to the host:

$ arp -an
? (192.168.0.**) at **:**:**:23:06:bb [ether] on eth0
? (192.168.0.**) at **:**:**:74:02:28 [ether] on eth0
? (192.168.122.16) at 52:54:00:18:04:63 [ether] on virbr0
? (192.168.0.**) at **:**:**:7c:8b:7e [ether] on eth0

I already described this and it works well if you have one or a few virtual machines, but if you have many, how do you know which MAC address corresponds to the one you want?

libvirt knows the MAC address which was assigned to each virtual machine’s network card. It is in the libvirt XML for the domain, and you can get it from libvirt using the command virsh dumpxml.

If we put all this together, we can write a short script which queries libvirt for the MAC address, then looks that up in the ARP table. All you need to do is to write:

# virt-addr F14x64
192.168.122.16

Note: As it stands this would only work as root, but you can make it also work for non-root by setting this environment variable:

$ export LIBVIRT_DEFAULT_URI=qemu:///system
$ virt-addr F14x64
192.168.122.16
$ ssh $(virt-addr F14x64)
rjones@192.168.122.16's password: ***
Last login: Sat Oct 16 16:56:17 2010 from 192.168.122.1
[rjones@f14x64 ~]$ 

The script follows below.

#!/usr/bin/perl -w

use strict;
use XML::XPath;
use XML::XPath::XMLParser;
use Sys::Virt;

# Open libvirt connection and get the domain.
my $conn = Sys::Virt->new (readonly => 1);
my $dom = $conn->get_domain_by_name ($ARGV[0]);

# Get the libvirt XML for the domain.
my $xml = $dom->get_xml_description ();

# Parse out the MAC addresses using an XPath expression.
my $xp = XML::XPath->new (xml => $xml);
my $nodes = $xp->find ("//devices/interface[\@type='network']/mac/\@address");
my $node;
my @mac_addrs;
foreach $node ($nodes->get_nodelist) {
    push @mac_addrs, lc ($node->getData)
}

# Look up the MAC addresses in the output of 'arp -an'.
my @arp_lines = split /\n/, `arp -an`;
foreach (@arp_lines) {
    if (/\((.*?)\) at (.*?) /) {
        my $this_addr = lc $2;
        if (list_member ($this_addr, @mac_addrs)) {
            print "$1\n";
        }
    }
}

sub list_member
{
    local $_;
    my $item = shift;
    foreach (@_) {
        return 1 if $item eq $_;
    }
    return 0;
}

30 Comments

Filed under Uncategorized

30 responses to “Tip: Find the IP address of a virtual machine

  1. Matěj Cepl

    If anybody prefers Python, my old script (now updated … arp cache is much better than parsing /var/log/messages which I did before) is on http://gitorious.org/various-small-stuff/virt-addr/blobs/master/virt-addr.py

  2. Matěj Cepl

    … and of course, even better is to use avahi and you can do then

    ssh .local

    • rich

      Interesting Matěj, I didn’t notice that our domains advertise themselves over Rendezvous (or whatever the protocol is called today), but it does work:

      $ ssh f14x64.local
      rjones@f14x64.local's password: 
      Last login: Tue Oct 26 12:06:51 2010 from 192.168.122.1
      
      • Matěj Cepl

        no, domain doesn’t advertise anything, but a virtual machine is just another computer on network, right? So, if its Avahi (or whatever Mac and Windows can use) advertise anything, than it is visible as from any networked computer. Of course, you have to make sure iptables are not in the way.

  3. Nifty script. Are you putting these scripts into a utils or similar package? They’re really useful for people. 🙂

  4. That’s a thought, but not sure how many people’s guests would actually be running services like Avahi.

    Certainly no-one who cares about security of their guests would let them run things advertising their capabilities or installed software.

    • lzap

      +1 I do not run Avahi, I have _clean_ Fedora installation (bash, vim, x window system). I’d appreciate this script to be part of the Rich’s tools 😀

  5. Alex

    If user uses bridge type network and uses xenbr0 rather than virbr0 bridge in the guest interface, it seems that we willn’t get any ip address return by arp -an.

  6. Pingback: Tip: Code for getting DHCP address from a virtual machine disk image | Richard WM Jones

  7. what if the MAC address in not in arp cache ? in which case virt-addr doesn’t give any result

  8. Kenneth

    Looks like I landed in an expert nest, well let me just take the occasion to ask this question.

    I was able to setup my virtual machines, they seem to pickup 2 ips, the first is the one from the br0, 122.X the second is from my dns server 1.X, but for some reason I cannot ping their 122.X ids and I can’t refer to them with hostname, what I’m I doing wrong.

  9. feeliwood

    can I get the dom name of a Virtual Machine if I know its IP address ?

  10. Chris Davies

    As I understand it, the arp table is only populated on demand. So if the host hasn’t already communicated with the guest there’s going to be no entry in the arp table. So how can the script work?

  11. you saved my -script- life, thanks!

  12. “arp -a” will not work if you’re using a bridge to your physical LAN so the guests can get non-NAT’d networking.

    I installed arpwatch (debian package “arpwatch”) as advised by Niklas Andersson (@niklasa9). This immediately reported ip-to-mac assignments via email. I had postfix running and it sent them to local mailbox of the non-root user. A sample mail is:

    hostname:
    ip address: 192.168.42.131
    interface: eth0
    ethernet address: 52:54:00:6c:55:52
    ethernet vendor:
    timestamp: Tuesday, January 15, 2013 23:57:51 +0000

    I can then do this in virsh on each domain to find a match:

    virsh # domiflist wheezy001
    Interface Type Source Model MAC
    ——————————————————-
    vnet1 bridge br0 virtio 52:54:00:6c:55:52

    Is there an easier way to find which dom the mac belongs to rather than use domiflist on every domain? I only half half a dozen but it’s a hassle.

  13. easier way and most relevant if using dhcp. you can grep syslog with that mac:
    virsh # domiflist win7
    Interface Type Source Model MAC
    ——————————————————-
    vnet0 bridge br0 – 52:54:00:a8:19:16

    [ROOT@delphinus log]# grep ‘new station’ /var/log/syslog | grep 52:54:00:a8:19:16
    Jan 15 23:57:51 delphinus arpwatch: new station 192.168.42.130 52:54:00:a8:19:16 eth0

  14. I HATE perl, for not other reason that I have a personal preference against it. So if you want to accomplish the same thing. Here is how you can do this with BASH (ip, virsh, awk).

    ip neighbour | grep $(sudo virsh dumpxml Domain_Name | \
    grep “mac address” | awk -F\’ ‘{print $2}’) | awk ‘{print $1}’

  15. Michal Privoznik

    Libvirt’s participating in GSoC this year we’re gonna be working on this feature [1]. So hold your fingers crossed and by the end of summer you’ll be able to ‘virsh getipaddress $dom’ or similar 🙂

    1: http://qemu-project.org/Google_Summer_of_Code_2013#Introduce_API_to_query_IP_addresses_for_given_domain

  16. Pingback: Find Guest IP address using QEMU Guest Agent « A Random Walk Down Tech Street

  17. Michal, Can’t wait til this feature comes through. In the meantime you may be able to use qemu guest agent with the “guest-network-get-interfaces” command.. I have written a short post about it here:

    http://dustymabe.com/2013/07/14/find-guest-ip-address-using-qemu-guest-agent/

    Its fairly new stuff so not everyone may be able to use it but hope someone is able to 🙂

    Dusty

  18. Jim W.

    domiflist seems reasonable, but it doesn’t work in Ubuntu 13.04 (or at least it doesn’t work on mine. Crossing my fingers doesn’t help with the summer of code command either. Thanks for trying though.

  19. Basically you need to fill the arp cache. I do that by ping the “possible” IP and then grep in the arp out:

    ++++
    [root@localhost ~]# virsh domiflist RHEL7-tests
    Interface Type Source Model MAC
    ——————————————————-
    vnet0 bridge br0 virtio 52:54:00:e4:f2:ca

    +++
    Then you have the MAC.

    Run a cript to ping possible IP in your network (192.168.1 is what you may have to change…
    +++
    i=1;
    while true
    do
    ping -c 1 -W 1 192.168.1.$i
    i=`expr $i + 1`
    if [ $i = “255” ]; then
    break;
    fi
    done
    +++

    grep for the arp cache for the MAC
    +++
    [root@localhost ~]# arp -na | grep 52:54:00:e4:f2:ca
    ? (192.168.1.111) at 52:54:00:e4:f2:ca [ether] on br0
    +++
    Done!!!

  20. Pingback: DNS for your virtual machines | Technitribe

  21. This whole script can be compressed to a bash one-liner:

    arp -an | grep `virsh dumpxml | grep ‘<mac' | grep -o '\([0-9a-f][0-9a-f]:\)\+[0-9a-f][0-9a-f]'` | grep -o '\([0-9]\{1,3\}\.\)\+[0-9]\{1,3\}'

  22. Thanks for this! BTW, instead of repeatedly checking for list membership, it’s better practice (more idiomatic, better asymptotic complexity) to use hashes:

    my %mac_addrs;
    foreach $node ($nodes->get_nodelist) {
        $mac_addrs{lc($node->getData)}++;
    }
    
    # Look up the MAC addresses in the output of 'arp -an'.
    my @arp_lines = split /\n/, `arp -an`;
    foreach (@arp_lines) {
        if (/\((.*?)\) at (.*?) /) {
            my $this_addr = lc $2;
            if ($mac_addrs{$this_addr}) {
                print "$1\n";
            }
        }
    }
    
  23. Basanta

    Add following to the end of your /etc/bash.bashrc and use virtip command.
    You will have to log out and back in.
    #alias virtip=’sudo virsh net-dhcp-leases default’

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.