For most of my Setup, I used KVM virtual machines on Ubuntu Host Machine (Ubuntu 16.04). These Virtual machines get dynamic IP Address through KVM in-build DHCP. But today my requirement is to manage DHCP Mac-binding for IP Address to this Virtual Machine. So How To Do Mac-binding For KVM Virtual Machine in KVM DHCP.

SetUP

For this Demo I am using Ubuntu host machine and below KVM version

root@jarvis:~# lsb_release -d
Description:	Ubuntu 18.04.1 LTS
root@jarvis:~# kvm -V

root@jarvis:~# kvm --version
QEMU emulator version 2.11.1(Debian 1:2.11+dfsg-1ubuntu7.4)
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers

In this Setup, I have one CentOS7 machine name gpw

root@jarvis:~# virsh list
 Id    Name                           State
----------------------------------------------------
 1     gpw                            running

which has Dynamic allocated IP Address assigned through KVM DHCP.

root@jarvis:~# virsh net-dhcp-leases default
 Expiry Time          MAC address        Protocol  IP address                Hostname        Client ID or DUID
-------------------------------------------------------------------------------------------------------------------
 2018-08-11 10:26:48  52:54:00:45:ca:67  ipv4      192.168.123.183/24        srv1-test       -

root@jarvis:~# virsh domifaddr gpw
 Name       MAC address          Protocol     Address
-------------------------------------------------------------------------------
 vnet0      52:54:00:45:ca:67    ipv4         192.168.123.183/24

But what if I like to reserve this IP address to this machine particular MAC address like normal DHCP Mac binding. For same first we have to understand KVM network.

Brief Understanding of KVM default network

So by-default Virtual network switch operates in NAT mode using IPtables, this connection is configured in such way that any Guest machine could connect inside outside but any Machine from outside can’t connect it inside.

root@jarvis:~# iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT
-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT
-A FORWARD -d 192.168.123.0/24 -o virbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s 192.168.123.0/24 -i virbr0 -j ACCEPT
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -o virbr0 -p udp -m udp --dport 68 -j ACCEPT

This could also explain in one of image from wiki.libvirt.org mentioned below.

So now we have to check this default network settings and add one mac binding for virtual machine.

root@jarvis:~# virsh dumpxml gpw| sed -n '/interface/,/interface/p' 
<interface type='network'>
<mac address='52:54:00:45:ca:67'/>
<source network='default' bridge='virbr0'/>
<target dev='vnet0'/>
<model type='rtl8139'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>

Now we know that our Guest machine has default network that bridge through virbr0 interface on host machine. Now we could do Mac-bindings in default network settings.

Virsh net-update command

For same we should edit default network through virsh net-update command like below, i have added Mac, Hostname and IP address information.

root@jarvis:~# virsh net-update default add ip-dhcp-host --xml "<host mac='52:54:00:45:ca:67' name='srv1-test' ip='192.168.123.183'/>" --live --config
Updated network default persistent config and live state

For testing it on new interface , I have added another interface on same Guest machine like below

root@jarvis:~# virsh attach-interface gpw bridge virbr0 --target vnet1 --mac 52:54:00:45:ca:68
Interface attached successfully

This will add another interface on KVM Virtual Machine and show below logs.

[11620.304938] pci 0000:00:08.0: [10ec:8139] type 00 class 0x020000
[11620.305094] pci 0000:00:08.0: reg 0x10: [io  0x0000-0x00ff]
[11620.305179] pci 0000:00:08.0: reg 0x14: [mem 0x00000000-0x000000ff]
[11620.305573] pci 0000:00:08.0: reg 0x30: [mem 0x00000000-0x0003ffff pref]
[11620.306032] pci 0000:00:08.0: BAR 6: assigned [mem 0x40000000-0x4003ffff pref]
[11620.307105] pci 0000:00:08.0: BAR 0: assigned [io  0x1000-0x10ff]
[11620.308314] pci 0000:00:08.0: BAR 1: assigned [mem 0x40040000-0x400400ff]
[11620.309712] 8139cp 0000:00:08.0: enabling device (0000 -> 0003)
[11620.336864] 8139cp 0000:00:08.0 eth0: RTL-8139C+ at 0xffffa7fc4021e000, 52:54:00:45:ca:68, IRQ 11
[11620.351798] IPv6: ADDRCONF(NETDEV_UP): ens8: link is not ready
[11620.353353] 8139cp 0000:00:08.0 ens8: link up, 100Mbps, full-duplex, lpa 0x05E1

now i added another IP binding on KVM default network through below command

root@jarvis:~# virsh net-update default add ip-dhcp-host --xml "<host mac='52:54:00:45:ca:68' name='srv-test' ip='192.168.123.50'/>" --live --config
Updated network default persistent config and live state

This added another Mac bindings for same Guest VM on this host KVM default network.

root@jarvis:~# virsh net-dumpxml default|sed -n '/dhcp/,/dhcp/p'
<dhcp>
<range start='192.168.123.2' end='192.168.123.254'/>
<host mac='52:54:00:45:ca:67' name='srv1-test' ip='192.168.123.183'/>
<host mac='52:54:00:45:ca:68' name='srv-test' ip='192.168.123.50'/>
</dhcp>  

That also update on KVM Guest xml file as well.

root@jarvis:~# virsh dumpxml gpw| sed -n '/interface/,/interface/p' 
<interface type='network'>
<mac address='52:54:00:45:ca:67'/>
<source network='default' bridge='virbr0'/>
<target dev='vnet0'/>
<model type='rtl8139'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<interface type='bridge'>
<mac address='52:54:00:45:ca:68'/>
<source bridge='virbr0'/>
<target dev='vnet1'/>
<model type='rtl8139'/>
<alias name='net1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</interface>    

Now we could login on Guest machine and ask for DHCP request for assigning new IP on new interface.

[root@srv1-test ~]# ifconfig ens8
ens8: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether 52:54:00:45:ca:68  txqueuelen 1000  (Ethernet)
        RX packets 105  bytes 12186 (11.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 134  bytes 24946 (24.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0



[root@srv1-test ~]# dhclient -v ens8
Internet Systems Consortium DHCP Client 4.2.5
Copyright 2004-2013 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

[18188.177747] 8139cp 0000:00:08.0 ens8: link up, 100Mbps, full-duplex, lpa 0x05E1
Listening on LPF/ens8/52:54:00:45:ca:68
Sending on   LPF/ens8/52:54:00:45:ca:68
Sending on   Socket/fallback
DHCPDISCOVER on ens8 to 255.255.255.255 port 67 interval 8 (xid=0x59c31028)
DHCPREQUEST on ens8 to 255.255.255.255 port 67 (xid=0x59c31028)
DHCPOFFER from 192.168.123.1
DHCPACK from 192.168.123.1 (xid=0x59c31028)
bound to 192.168.123.50 -- renewal in 1594 seconds.