NOTE: the below assumes you’re running the VMs in NAT mode.
nowadays most distros are very good at acquiring dynamic IP addys from DHCP
servers during the install process, and libvirt
comes with a lightweight
DHCP server (as part of dnsmasq
) which works just fine for the job at hand.
however, sometimes it’s handy to ensure your VMs have static IPs while playing around, e.g. on a lappy. there are a couple ways of achieving this, depending on whether you can easily change the network config of VMs themselves and are inclined to do so.
NOTE: in the below, keep in mind that changes done to
libvirt
XML network definitions withvirsh net-edit
do NOT take effect until the network is destroyed and restarted. therefore, these changes are best done ahead of time, before there are a bunch of VMs live on the affected network. to apply your changes on the fly, choose thevirsh net-update
instructions, which are a bit more tricky.
assigning proper static IPs
in this case you simply manually configure the relevant network interfaces
inside the VMs for static addys (including IP, netmask, etc). which would be
the end of it, if not for the fact that at least some versions of libvirt
tend to assign the entire range of IP addys of the virtual bridge they create
to the DHCP server by default. so, you’ll need to first reserve a block of
addys in libvirt
network config for static assignment, unless you want to
spend time debugging IP collisions. actual VM-side config is distro-specific
and is out of scope here, what follows is the libvirt
side of things.
first, figure out which libvirt
network you want to configure (often
default
):
# virsh net-list --all
Name State Autostart Persistent
----------------------------------------------------------
default active yes yes
where:
--all ensures that you're viewing both the live networks and those only
defined, but not actively started by libvirt
check out the relevant net config to see if it doesn’t already have a reserved range using:
# virsh net-dumpxml <net-name>
where:
<net-name> is the network name from the 'virsh net-list' output
e.g.:
# virsh net-dumpxml default
<network connections='1'>
<name>default</name>
<uuid>1234abcd-a6f8-4f46-a8a5-123456abcdef</uuid>
<forward mode='nat'>
<nat>
<port start='1024' end='65535'/>
</nat>
</forward>
<bridge name='virbr0' stp='on' delay='0'/>
<mac address='52:54:00:11:22:33'/>
<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>
<range start=... end=.../>
tag inside the <dhcp>
stanza spills the beans,
in this case, the entire range of the bridge is handed over to dnsmasq
for
dynamic IP addys.
offline static IP range reservation
the easiest and hassle-free way to go about it is to just tear down the network using:
# virsh net-destroy <net-name>
then edit the config XML using:
# virsh net-edit <net-name>
which will essentially just pop up a copy of the corresponding XML file in an editor for you to edit (or, if you’re adventurous, just hack at it in-situ, which might be:
/etc/libvirt/qemu/networks/default.xml
or whatever). find the <range start=
tag of interest, edit the start
and/or end IPs, save, and finally restart the network:
# virsh net-start <net-name>
needless to say, the VMs already live on that network (or, rather, their connections!) will not like their net being yanked down from under them like that…
online IP ranges modification to reserve static IPs
an alternative and less intrusive way uses virsh net-update
which can
operate on live nets.
unfortunately, since virsh net-update
can’t modify ip-dhcp-range
stanzas,
you’ll need to delete the relevant one and add a new one instead. make
sure to exactly specify an existing stanza to delete, e.g. by copy-pasting
from the ‘virsh net-dumpxml’ output, otherwise virsh
will refuse to
cooperate. fortunately, libvirt
appears to allow multiple overlapping addy
ranges to co-exist (and, more importantly, apparently so does dnsmasq
as
that’s where these configs are immediately propagated, and you can verify
afterwards under:
/var/lib/libvirt/dnsmasq/default.conf
that you ended up with a desired IP addy range). so you can add the new, narrower range first, then delete the original range, without leaving the DHCP server empty-handed at runtime, using:
# virsh net-update <net-name> add ip-dhcp-range "<new-range>" --live --config
# virsh net-update <net-name> delete ip-dhcp-range "<old-range>" --live --config
where:
<net-name> - libvirt network name, e.g. 'default'
<old-range> - verbatim "<range start='...' end='...'/>" tag from the
current 'virsh net-dumpxml' output, the one you want to narrow
down
<new-range> - new range tag, presumably narrower than <old-range>
e.g.:
# virsh net-update default add ip-dhcp-range \
"<range start='192.168.122.100' end='192.168.122.254'/>" \
--live --config
Updated network default persistent config and live state
# virsh net-update default delete ip-dhcp-range \
"<range start='192.168.122.2' end='192.168.122.254'/>" \
--live --config
Updated network default persistent config and live state
now verify with a final virsh net-dumpxml
that the <dhcp>
stanza contains
the desired narrower range of IP addys to hand out using DHCP and you’re
free to statically assign the rest as you see fit.
assigning fixed IPs dynamically
this way will usually make sense if the VMs in question are already configured for dynamic IP addys and you don’t want to bother reconfiguring them, or if you actually want them to keep using their DHCP clients, e.g. for testing purposes, without having to check and recheck their IPs every time you bring them about.
in this case, you can just assign fixed IP addy(s) on the host DHCP server
side, while keeping the VM in DHCP mode, which will give roughly the same
end result of a VM having fixed IP(s). to do that you need to know the VM’s
MAC addy(s) (or, in more recent versions of libvirt
, since around CentOS
v5.4 - just the host name that the DHCP client will send with its request)
and which libvirt
net(s) they’re on.
as with the proper static IPs method above, the easiest way is to tear down
the libvirt
network:
# virsh net-destroy <net-name>
start editing the net config XML using:
# virsh net-edit <net-name>
(or hack on it directly as above). at this point you’ll want to find the
<dhcp>
stanza and add an entry in the spirit of:
<host mac='<vm-mac>' ip='<desired-ip>'/>
OR, for libvirt
v0.4.5 and on (CentOS v5.4+):
<host name='<vm-hostname>' ip='<desired-ip>'/>
e.g.:
<host mac='52:54:00:00:00:01' ip='192.168.122.1'/>
<host name='foobar' ip='192.168.122.2'/>
save the XML and restart the network for the changes to take effect:
# virsh net-start <net-name>
same caveat as above about restarting the net like that.
the live virsh net-update
route might be a bit easier to take with fixed
dynamic IPs, since you just need to add a new config tag, using:
# virsh net-update <net-name> add ip-dhcp-host \
"<host mac='<vm-mac>' ip='<desired-ip>' />" --live --config
where:
<net-name> - libvirt network name, e.g. 'default'
<vm-mac> - MAC addy of the VM nic in question, visible in the
VM config GUI of virt-manager or in the 'mac address' tag of
the VM XML definition file under /etc/libvirt/qemu/
<desired-ip> - desired fixed IP
the other angled braces should be kept as is (XML! <bleh/>)
e.g.:
# virsh net-update default add ip-dhcp-host \
"<host mac='52:54:00:00:00:01' ip='192.168.122.1' />" \
--live --config
presumably the same feat can be achieved using the name
selector instead
of MAC, though i’ve never tried that one…
for an overview of libvirt
’s net config see:
libvirt Networking
for a spec of libvirt
’s network XML see:
Network XML format