[libvirt] dnsmasq option "dhcp-authoritative" in libvirt virtual networks?

Hello, I am seeing a slightly annoying behavior of libvirt-created networks on my system. Whenever a VM fails to renew its DHCP lease in time (for example because my laptop is suspended), the IP address changes, causing various annoyances. If this happens, the log message "DHCPNAK(virbrX): ... lease not found" appears in the libvirtd logs. Looking at the dnsmasq code, it seems that this would be fixed by running dnsmasq with the "dhcp-authoritative" option, which, according to the dnsmasq man page, "should be set when dnsmasq is definitely the only DHCP server on a network" - IMO that's the case for libvirtd- managed virtual networks. So the question comes to my mind: is there a good reason why libvirtd doesn't set "dhcp-authoritative" on the dnsmasq instances it starts? Regards Martin -- Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107 SUSELinux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton HRB 21284 (AG Nürnberg)

On 09/19/2016 09:48 AM, Martin Wilck wrote:
Hello,
I am seeing a slightly annoying behavior of libvirt-created networks on my system. Whenever a VM fails to renew its DHCP lease in time (for example because my laptop is suspended), the IP address changes, causing various annoyances. If this happens, the log message "DHCPNAK(virbrX): ... lease not found" appears in the libvirtd logs.
Looking at the dnsmasq code, it seems that this would be fixed by running dnsmasq with the "dhcp-authoritative" option, which, according to the dnsmasq man page, "should be set when dnsmasq is definitely the only DHCP server on a network" - IMO that's the case for libvirtd- managed virtual networks. So the question comes to my mind: is there a good reason why libvirtd doesn't set "dhcp-authoritative" on the dnsmasq instances it starts?
I've searched the list archives and didn't see any mention of the '--dhcp-authoritative' option, so the reason may be that no one has made such an inquiry :-). If it has been discussed and I missed it, Laine most likely knows something about it. A small bit of detective work shows that OpenStack neutron adopted use of this option a while back https://review.openstack.org/#/c/152080/ In a related discussion, Simon agrees with using '--dhcp-authoritative' when dnsmasq is the only dhcp server on the network http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2015q1/009171.html I also stumbled across a complaint about using '--dhcp-authoritative' on a network with multiple dhcp servers, but I can't find that now. I'm not sure if there are use-cases for multiple dhcp servers on a single libvirt virtual network. Regards, Jim

On 09/19/2016 05:25 PM, Jim Fehlig wrote:
On 09/19/2016 09:48 AM, Martin Wilck wrote:
Hello,
I am seeing a slightly annoying behavior of libvirt-created networks on my system. Whenever a VM fails to renew its DHCP lease in time (for example because my laptop is suspended), the IP address changes, causing various annoyances. If this happens, the log message "DHCPNAK(virbrX): ... lease not found" appears in the libvirtd logs.
Looking at the dnsmasq code, it seems that this would be fixed by running dnsmasq with the "dhcp-authoritative" option, which, according to the dnsmasq man page, "should be set when dnsmasq is definitely the only DHCP server on a network" - IMO that's the case for libvirtd- managed virtual networks. So the question comes to my mind: is there a good reason why libvirtd doesn't set "dhcp-authoritative" on the dnsmasq instances it starts? I've searched the list archives and didn't see any mention of the '--dhcp-authoritative' option, so the reason may be that no one has made such an inquiry :-). If it has been discussed and I missed it, Laine most likely knows something about it.
Nope, this is the first I've heard of it.
A small bit of detective work shows that OpenStack neutron adopted use of this option a while back
...but for a completely different reason - they were encountering problems when they restarted their dnsmasq, because they didn't keep a leasefile. After reading Simon's mail, and the openstack patch and description, it isn't clear that this will actually solve your problem. Have you tried it? (to test it, you should be able to just kill dnsmasq, add the option to the dnsmasq conf file referenced in its commandline, then restart it with the same commandline. libvirt will no longer know where the dnsmasq process is (since you will have changed its pid), but otherwise it should operate okay) If that does solve your problem, we could consider a patch to add it. Do you know the first version of dnsmasq that had this option? Hopefully the answer is "very old" so we don't have to check for support.
In a related discussion, Simon agrees with using '--dhcp-authoritative' when dnsmasq is the only dhcp server on the network
http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2015q1/009171.html
I also stumbled across a complaint about using '--dhcp-authoritative' on a network with multiple dhcp servers, but I can't find that now. I'm not sure if there are use-cases for multiple dhcp servers on a single libvirt virtual network.
Yeah, I don't think that should ever happen with libvirt's networks (unless somebody comes up with a network that is bridged across several hosts, and they want each host to have a DHCP server, or something like that. *I'm certainly not going to do that though :-)

On Mon, 2016-09-19 at 17:45 -0400, Laine Stump wrote:
After reading Simon's mail, and the openstack patch and description, it isn't clear that this will actually solve your problem. Have you tried it? (to test it, you should be able to just kill dnsmasq, add the option to the dnsmasq conf file referenced in its commandline, then restart it with the same commandline.
I just tried this successfully (I had to remove the options '--leasefile-ro --dhcp-script=/usr/lib64/libvirt/libvirt_leaseshelper' from the dnsmasq command line in order to make dnsmasq start). In order to be certain, I patched and rebuilt libvirt on OpenSUSE factory using the follow-up patch set. That test was also successful - IP addresses don't change any more when a VM renews too late. Please review the patch set. As you can see I added the option only for IPv4 networks. For IPv6, it has a different effect (just setting the priority of dnsmasq's replies) which isn't necessary here AFAICS.
Do you know the first version of dnsmasq that had this option? Hopefully the answer is "very old" so we don't have to check for support.
The option pre-dates the import into dnsmasq repository git://thekelleys.org.uk/dnsmasq.git which occured with v2.48 in June 2009. According to CHANGELOG.archive, the option was added in dnsmasq v2.16 in 2004. Regards, Martin Martin Wilck (2): network: add dnsmasq option 'dhcp-authoritative' tests/networkxml2confdata: add dhcp-authoritative option src/network/bridge_driver.c | 4 +++- tests/networkxml2confdata/dhcp6-nat-network.conf | 1 + tests/networkxml2confdata/dhcp6host-routed-network.conf | 1 + tests/networkxml2confdata/isolated-network.conf | 1 + tests/networkxml2confdata/nat-network-dns-srv-record-minimal.conf | 1 + tests/networkxml2confdata/nat-network-dns-srv-record.conf | 1 + tests/networkxml2confdata/nat-network-dns-txt-record.conf | 1 + tests/networkxml2confdata/nat-network-name-with-quotes.conf | 1 + tests/networkxml2confdata/nat-network.conf | 1 + tests/networkxml2confdata/netboot-network.conf | 1 + tests/networkxml2confdata/netboot-proxy-network.conf | 1 + 11 files changed, 13 insertions(+), 1 deletion(-) -- 2.9.3

The dnsmasq man page recommends that dhcp-authoritative "should be set when dnsmasq is definitely the only DHCP server on a network". This is the case for libvirt-managed virtual networks. The effect of this is that VMs that fail to renew their DHCP lease in time (e.g. if the VM or host is suspended) will be able to re-acquire the lease even if it's expired, unless the IP address has been taken by some other host. This avoids various annoyances caused by changing VM IP addresses. --- src/network/bridge_driver.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 7b99aca..cb4fb1c 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1258,8 +1258,10 @@ networkDnsmasqConfContents(virNetworkObjPtr network, /* Note: the following is IPv4 only */ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) { - if (ipdef->nranges || ipdef->nhosts) + if (ipdef->nranges || ipdef->nhosts) { virBufferAddLit(&configbuf, "dhcp-no-override\n"); + virBufferAddLit(&configbuf, "dhcp-authoritative\n"); + } if (ipdef->tftproot) { virBufferAddLit(&configbuf, "enable-tftp\n"); -- 2.9.3

On 09/21/2016 04:49 AM, Martin Wilck wrote:
The dnsmasq man page recommends that dhcp-authoritative "should be set when dnsmasq is definitely the only DHCP server on a network". This is the case for libvirt-managed virtual networks.
The effect of this is that VMs that fail to renew their DHCP lease in time (e.g. if the VM or host is suspended) will be able to re-acquire the lease even if it's expired, unless the IP address has been taken by some other host. This avoids various annoyances caused by changing VM IP addresses.
We had earlier (finally!) agreed in principle on pushing this patch, but were in freeze at the time, and I later forgot to do it. I checked to be sure that the dnsmasq on one of the oldest Linux distros that we still support does have the dhcp-authoritative option. It does (it's dnsmasq-2.48-something) so we don't need any extra code to verify the option is there. I do have a couple comments below, so don't hit the "next" button yet! :-)
--- src/network/bridge_driver.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 7b99aca..cb4fb1c 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1258,8 +1258,10 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
/* Note: the following is IPv4 only */ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) { - if (ipdef->nranges || ipdef->nhosts) + if (ipdef->nranges || ipdef->nhosts) { virBufferAddLit(&configbuf, "dhcp-no-override\n"); + virBufferAddLit(&configbuf, "dhcp-authoritative\n"); + }
You accidentally got a tab character in the line below, so I replaced it with spaces so that make syntax-check passes.
if (ipdef->tftproot) { virBufferAddLit(&configbuf, "enable-tftp\n");
Although your cover letter included diff statistics for the networkxml2conftest test cases that needed the extra line for dhcp-authoritative, those diffs weren't included in the patch itself. Fortunately it's simple to regenerate the test case outputs (VIR_TEST_REGENERATE_OUTPUT=1 tests/networkxml2conftest), so I regenerated and verified them. ACK, and pushed. Thanks for the submission, and sorry for the delay (and the seemingly protracted debate about a single line - we've been burned in the past by unforeseen consequences of adding a seemingly innocuous dnsmasq option to our dnsmasq conf files, and I was nervous about that happening again, so I wanted to make sure we explored all possibilities.)

The previous patch changes the confdata output for dnsmasq. Adapt the expected test results to match. --- tests/networkxml2confdata/dhcp6-nat-network.conf | 1 + tests/networkxml2confdata/dhcp6host-routed-network.conf | 1 + tests/networkxml2confdata/isolated-network.conf | 1 + tests/networkxml2confdata/nat-network-dns-srv-record-minimal.conf | 1 + tests/networkxml2confdata/nat-network-dns-srv-record.conf | 1 + tests/networkxml2confdata/nat-network-dns-txt-record.conf | 1 + tests/networkxml2confdata/nat-network-name-with-quotes.conf | 1 + tests/networkxml2confdata/nat-network.conf | 1 + tests/networkxml2confdata/netboot-network.conf | 1 + tests/networkxml2confdata/netboot-proxy-network.conf | 1 + 10 files changed, 10 insertions(+) diff --git a/tests/networkxml2confdata/dhcp6-nat-network.conf b/tests/networkxml2confdata/dhcp6-nat-network.conf index 17076b8..d1058df 100644 --- a/tests/networkxml2confdata/dhcp6-nat-network.conf +++ b/tests/networkxml2confdata/dhcp6-nat-network.conf @@ -10,6 +10,7 @@ bind-dynamic interface=virbr0 dhcp-range=192.168.122.2,192.168.122.254 dhcp-no-override +dhcp-authoritative dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff,64 dhcp-lease-max=493 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile diff --git a/tests/networkxml2confdata/dhcp6host-routed-network.conf b/tests/networkxml2confdata/dhcp6host-routed-network.conf index 5728ee4..87a1498 100644 --- a/tests/networkxml2confdata/dhcp6host-routed-network.conf +++ b/tests/networkxml2confdata/dhcp6host-routed-network.conf @@ -10,6 +10,7 @@ bind-dynamic interface=virbr1 dhcp-range=192.168.122.1,static dhcp-no-override +dhcp-authoritative dhcp-range=2001:db8:ac10:fd01::1,static,64 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/local.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts diff --git a/tests/networkxml2confdata/isolated-network.conf b/tests/networkxml2confdata/isolated-network.conf index fbdf75a..ce4a59f 100644 --- a/tests/networkxml2confdata/isolated-network.conf +++ b/tests/networkxml2confdata/isolated-network.conf @@ -12,6 +12,7 @@ dhcp-option=3 no-resolv dhcp-range=192.168.152.2,192.168.152.254 dhcp-no-override +dhcp-authoritative dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/private.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/private.addnhosts diff --git a/tests/networkxml2confdata/nat-network-dns-srv-record-minimal.conf b/tests/networkxml2confdata/nat-network-dns-srv-record-minimal.conf index 08ed672..f35ea1d 100644 --- a/tests/networkxml2confdata/nat-network-dns-srv-record-minimal.conf +++ b/tests/networkxml2confdata/nat-network-dns-srv-record-minimal.conf @@ -15,6 +15,7 @@ listen-address=10.24.10.1 srv-host=_name._tcp dhcp-range=192.168.122.2,192.168.122.254 dhcp-no-override +dhcp-authoritative dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2confdata/nat-network-dns-srv-record.conf b/tests/networkxml2confdata/nat-network-dns-srv-record.conf index d7de422..af1ed70 100644 --- a/tests/networkxml2confdata/nat-network-dns-srv-record.conf +++ b/tests/networkxml2confdata/nat-network-dns-srv-record.conf @@ -17,6 +17,7 @@ srv-host=_name6._tcp.test6.com,test6.example.com,6666,0,666 srv-host=_name7._tcp.test7.com,test7.example.com,1,0,777 dhcp-range=192.168.122.2,192.168.122.254 dhcp-no-override +dhcp-authoritative dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2confdata/nat-network-dns-txt-record.conf b/tests/networkxml2confdata/nat-network-dns-txt-record.conf index 44ed6bd..7f560fb 100644 --- a/tests/networkxml2confdata/nat-network-dns-txt-record.conf +++ b/tests/networkxml2confdata/nat-network-dns-txt-record.conf @@ -11,6 +11,7 @@ interface=virbr0 txt-record=example,example value dhcp-range=192.168.122.2,192.168.122.254 dhcp-no-override +dhcp-authoritative dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2confdata/nat-network-name-with-quotes.conf b/tests/networkxml2confdata/nat-network-name-with-quotes.conf index a1c839e..36e11d1 100644 --- a/tests/networkxml2confdata/nat-network-name-with-quotes.conf +++ b/tests/networkxml2confdata/nat-network-name-with-quotes.conf @@ -15,6 +15,7 @@ listen-address=10.24.10.1 srv-host=_name._tcp dhcp-range=192.168.122.2,192.168.122.254 dhcp-no-override +dhcp-authoritative dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default"with"quotes".hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default"with"quotes".addnhosts diff --git a/tests/networkxml2confdata/nat-network.conf b/tests/networkxml2confdata/nat-network.conf index 34d5b17..a3c8b10 100644 --- a/tests/networkxml2confdata/nat-network.conf +++ b/tests/networkxml2confdata/nat-network.conf @@ -10,6 +10,7 @@ bind-dynamic interface=virbr0 dhcp-range=192.168.122.2,192.168.122.254 dhcp-no-override +dhcp-authoritative dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2confdata/netboot-network.conf b/tests/networkxml2confdata/netboot-network.conf index 4b8f0cc..b554a54 100644 --- a/tests/networkxml2confdata/netboot-network.conf +++ b/tests/networkxml2confdata/netboot-network.conf @@ -12,6 +12,7 @@ bind-interfaces listen-address=192.168.122.1 dhcp-range=192.168.122.2,192.168.122.254 dhcp-no-override +dhcp-authoritative enable-tftp tftp-root=/var/lib/tftproot dhcp-boot=pxeboot.img diff --git a/tests/networkxml2confdata/netboot-proxy-network.conf b/tests/networkxml2confdata/netboot-proxy-network.conf index 61a025c..afb4033 100644 --- a/tests/networkxml2confdata/netboot-proxy-network.conf +++ b/tests/networkxml2confdata/netboot-proxy-network.conf @@ -12,6 +12,7 @@ bind-interfaces listen-address=192.168.122.1 dhcp-range=192.168.122.2,192.168.122.254 dhcp-no-override +dhcp-authoritative dhcp-boot=pxeboot.img,,10.20.30.40 dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile -- 2.9.3
participants (4)
-
Jim Fehlig
-
Laine Stump
-
Martin Wilck
-
Martin Wilck