[libvirt] [PATCH 0/6] dnsmasq conf-file, DHCPv6, dnsmasq-RA updates

OK, here it is. There are a related set of patches in that they are mostly dependent and need to be applied in the order show.. The individual patch files explain what each one is. Note that patch file 0003 for DHCPv6 adds some test files. Note that patch file 0006 add a test for the dnsmasq version for DHCPv6 support and if it is less that 2.64, it errors out. Gene Czarcinski (6): v6-6: put dnsmasq parameters into a file v6-6: add dnsmasq interface= parameter v6-7: Add support for DHCPv6 v1: get, parse, and save dnsmasq version id v1: use dnsmasq instead of radvd to handle RA service v1: for DHCPv6, add dnsmasq version check docs/formatnetwork.html.in | 108 +++- src/conf/network_conf.c | 100 ++-- src/conf/network_conf.h | 3 + src/network/bridge_driver.c | 541 ++++++++++++++------- src/network/bridge_driver.h | 7 +- src/util/dnsmasq.c | 9 +- tests/networkxml2argvdata/dhcp6-network.argv | 17 + tests/networkxml2argvdata/dhcp6-network.xml | 16 + tests/networkxml2argvdata/isolated-network.argv | 25 +- tests/networkxml2argvdata/nat-network-dhcp6.argv | 20 + tests/networkxml2argvdata/nat-network-dhcp6.xml | 26 + .../networkxml2argvdata/nat-network-dns-hosts.argv | 15 +- .../nat-network-dns-srv-record-minimal.argv | 37 +- .../nat-network-dns-srv-record.argv | 37 +- .../nat-network-dns-txt-record.argv | 31 +- tests/networkxml2argvdata/nat-network.argv | 29 +- tests/networkxml2argvdata/netboot-network.argv | 29 +- .../networkxml2argvdata/netboot-proxy-network.argv | 26 +- .../routed-network-dhcphost.argv | 15 + .../routed-network-dhcphost.xml | 19 + tests/networkxml2argvdata/routed-network.argv | 13 +- tests/networkxml2argvtest.c | 49 +- 22 files changed, 822 insertions(+), 350 deletions(-) create mode 100644 tests/networkxml2argvdata/dhcp6-network.argv create mode 100644 tests/networkxml2argvdata/dhcp6-network.xml create mode 100644 tests/networkxml2argvdata/nat-network-dhcp6.argv create mode 100644 tests/networkxml2argvdata/nat-network-dhcp6.xml create mode 100644 tests/networkxml2argvdata/routed-network-dhcphost.argv create mode 100644 tests/networkxml2argvdata/routed-network-dhcphost.xml -- 1.7.11.7

This patch changes how parameters are passed to dnsmasq. Instead of being on the command line, the parameters are put into a file (one parameter per line) and a commandline --conf-file= specifies the location of the file. The file is located in the same directory as the leases file. --- src/network/bridge_driver.c | 153 ++++++++++++++------- src/network/bridge_driver.h | 7 +- tests/networkxml2argvdata/isolated-network.argv | 24 ++-- .../networkxml2argvdata/nat-network-dns-hosts.argv | 14 +- .../nat-network-dns-srv-record-minimal.argv | 35 ++--- .../nat-network-dns-srv-record.argv | 35 ++--- .../nat-network-dns-txt-record.argv | 29 ++-- tests/networkxml2argvdata/nat-network.argv | 27 ++-- tests/networkxml2argvdata/netboot-network.argv | 28 ++-- .../networkxml2argvdata/netboot-proxy-network.argv | 25 ++-- tests/networkxml2argvdata/routed-network.argv | 12 +- tests/networkxml2argvtest.c | 43 +----- 12 files changed, 245 insertions(+), 187 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index c153d36..508de3a 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -136,6 +136,16 @@ networkDnsmasqLeaseFileNameFunc networkDnsmasqLeaseFileName = networkDnsmasqLeaseFileNameDefault; static char * +networkDnsmasqConfigFileName(const char *netname) +{ + char *conffile; + + ignore_value(virAsprintf(&conffile, DNSMASQ_STATE_DIR "/%s.conf", + netname)); + return conffile; +} + +static char * networkRadvdPidfileBasename(const char *netname) { /* this is simple but we want to be sure it's consistently done */ @@ -163,6 +173,7 @@ networkRemoveInactive(struct network_driver *driver, char *leasefile = NULL; char *radvdconfigfile = NULL; char *radvdpidbase = NULL; + char *configfile = NULL; dnsmasqContext *dctx = NULL; virNetworkDefPtr def = virNetworkObjGetPersistentDef(net); @@ -178,12 +189,16 @@ networkRemoveInactive(struct network_driver *driver, if (!(radvdconfigfile = networkRadvdConfigFileName(def->name))) goto no_memory; - if (!(radvdpidbase = networkRadvdPidfileBasename(def->name))) + if (!(radvdconfigfile = networkRadvdConfigFileName(def->name))) + goto no_memory; + + if (!(configfile = networkDnsmasqConfigFileName(def->name))) goto no_memory; /* dnsmasq */ dnsmasqDelete(dctx); unlink(leasefile); + unlink(configfile); /* radvd */ unlink(radvdconfigfile); @@ -196,6 +211,7 @@ networkRemoveInactive(struct network_driver *driver, cleanup: VIR_FREE(leasefile); + VIR_FREE(configfile); VIR_FREE(radvdconfigfile); VIR_FREE(radvdpidbase); dnsmasqContextFree(dctx); @@ -610,14 +626,15 @@ networkBuildDnsmasqHostsfile(dnsmasqContext *dctx, return 0; } - + /* build the dnsmasq conf file contents */ static int -networkBuildDnsmasqArgv(virNetworkObjPtr network, +networkDnsmasqConfContents(virNetworkObjPtr network, virNetworkIpDefPtr ipdef, const char *pidfile, - virCommandPtr cmd, + char **configstr, dnsmasqContext *dctx) { + virBuffer configbuf = VIR_BUFFER_INITIALIZER;; int r, ret = -1; int nbleases = 0; int ii; @@ -627,6 +644,8 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, char *recordPriority = NULL; virNetworkIpDefPtr tmpipdef; + *configstr = NULL; + /* * NB, be careful about syntax for dnsmasq options in long format. * @@ -646,28 +665,22 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, * very explicit on this. */ - /* - * Needed to ensure dnsmasq uses same algorithm for processing - * multiple namedriver entries in /etc/resolv.conf as GLibC. - */ - virCommandAddArgList(cmd, "--strict-order", "--bind-interfaces", NULL); - + /* create dnsmasq config file appropriate for this network */ + virBufferAsprintf(&configbuf, "# dnsmasq conf file created by libvirt\n" + "strict-order\n" + "bind-interfaces\n" + "except-interface=lo\n" + "domain-needed\n" + "local=/%s/\n", + network->def->domain ? network->def->domain : ""); if (network->def->domain) - virCommandAddArgPair(cmd, "--domain", network->def->domain); - /* need to specify local even if no domain specified */ - virCommandAddArgFormat(cmd, "--local=/%s/", - network->def->domain ? network->def->domain : ""); - virCommandAddArg(cmd, "--domain-needed"); + virBufferAsprintf(&configbuf, + "domain=%s\n" + "expand-hosts\n", + network->def->domain); if (pidfile) - virCommandAddArgPair(cmd, "--pid-file", pidfile); - - /* *no* conf file */ - virCommandAddArg(cmd, "--conf-file="); - - virCommandAddArgList(cmd, - "--except-interface", "lo", - NULL); + virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile); /* If this is an isolated network, set the default route option * (3) to be empty to avoid setting a default route that's @@ -677,16 +690,21 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, * to build a connection to the outside). */ if (network->def->forwardType == VIR_NETWORK_FORWARD_NONE) { - virCommandAddArgList(cmd, "--dhcp-option=3", - "--no-resolv", NULL); + virBufferAsprintf(&configbuf, "dhcp-option=3\n" + "no-resolv\n"); } + /* + * Needed to ensure dnsmasq uses same algorithm for processing + * multiple namedriver entries in /etc/resolv.conf as GLibC. + */ + if (network->def->dns != NULL) { virNetworkDNSDefPtr dns = network->def->dns; int i; for (i = 0; i < dns->ntxtrecords; i++) { - virCommandAddArgFormat(cmd, "--txt-record=%s,%s", + virBufferAsprintf(&configbuf, "txt-record=%s,%s\n", dns->txtrecords[i].name, dns->txtrecords[i].value); } @@ -724,7 +742,7 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, goto cleanup; } - virCommandAddArgPair(cmd, "--srv-host", record); + virBufferAsprintf(&configbuf, "srv-host=%s\n", record); VIR_FREE(record); VIR_FREE(recordPort); VIR_FREE(recordWeight); @@ -743,11 +761,12 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, */ for (ii = 0; (tmpipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii)); - ii++) { + ii++) + { char *ipaddr = virSocketAddrFormat(&tmpipdef->address); if (!ipaddr) goto cleanup; - virCommandAddArgList(cmd, "--listen-address", ipaddr, NULL); + virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr); VIR_FREE(ipaddr); } @@ -761,8 +780,8 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, VIR_FREE(saddr); goto cleanup; } - virCommandAddArg(cmd, "--dhcp-range"); - virCommandAddArgFormat(cmd, "%s,%s", saddr, eaddr); + virBufferAsprintf(&configbuf, "dhcp-range=%s,%s\n", + saddr, eaddr); VIR_FREE(saddr); VIR_FREE(eaddr); nbleases += virSocketAddrGetRange(&ipdef->ranges[r].start, @@ -778,8 +797,7 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, char *bridgeaddr = virSocketAddrFormat(&ipdef->address); if (!bridgeaddr) goto cleanup; - virCommandAddArg(cmd, "--dhcp-range"); - virCommandAddArgFormat(cmd, "%s,static", bridgeaddr); + virBufferAsprintf(&configbuf, "dhcp-range=%s,static\n", bridgeaddr); VIR_FREE(bridgeaddr); } @@ -787,17 +805,13 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, char *leasefile = networkDnsmasqLeaseFileName(network->def->name); if (!leasefile) goto cleanup; - virCommandAddArgFormat(cmd, "--dhcp-leasefile=%s", leasefile); + virBufferAsprintf(&configbuf, "dhcp-leasefile=%s\n", leasefile); VIR_FREE(leasefile); - virCommandAddArgFormat(cmd, "--dhcp-lease-max=%d", nbleases); + virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases); } if (ipdef->nranges || ipdef->nhosts) - virCommandAddArg(cmd, "--dhcp-no-override"); - - /* add domain to any non-qualified hostnames in /etc/hosts or addn-hosts */ - if (network->def->domain) - virCommandAddArg(cmd, "--expand-hosts"); + virBufferAsprintf(&configbuf, "dhcp-no-override\n"); if (networkBuildDnsmasqHostsfile(dctx, ipdef, network->def->dns) < 0) goto cleanup; @@ -807,38 +821,42 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, * file to allow for runtime additions. */ if (ipdef->nranges || ipdef->nhosts) - virCommandAddArgPair(cmd, "--dhcp-hostsfile", + virBufferAsprintf(&configbuf, "dhcp-hostsfile=%s\n", dctx->hostsfile->path); /* Likewise, always create this file and put it on the commandline, to allow for * for runtime additions. */ - virCommandAddArgPair(cmd, "--addn-hosts", + virBufferAsprintf(&configbuf, "addn-hosts=%s\n", dctx->addnhostsfile->path); if (ipdef->tftproot) { - virCommandAddArgList(cmd, "--enable-tftp", - "--tftp-root", ipdef->tftproot, - NULL); + virBufferAsprintf(&configbuf, "enable-tftp\n"); + virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot); } if (ipdef->bootfile) { - virCommandAddArg(cmd, "--dhcp-boot"); if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) { char *bootserver = virSocketAddrFormat(&ipdef->bootserver); if (!bootserver) goto cleanup; - virCommandAddArgFormat(cmd, "%s%s%s", + virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n", ipdef->bootfile, ",,", bootserver); VIR_FREE(bootserver); } else { - virCommandAddArg(cmd, ipdef->bootfile); + virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile); } } } + if (!(*configstr = virBufferContentAndReset(&configbuf))) { + virReportOOMError(); + goto cleanup; + } ret = 0; + cleanup: + virBufferFreeAndReset(&configbuf); VIR_FREE(record); VIR_FREE(recordPort); VIR_FREE(recordWeight); @@ -846,13 +864,17 @@ cleanup: return ret; } + /* build the dnsmasq command line */ int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdout, - char *pidfile, dnsmasqContext *dctx) + char *pidfile, dnsmasqContext *dctx, + int testOnly, char **testConfigStr) { virCommandPtr cmd = NULL; int ret = -1, ii; virNetworkIpDefPtr ipdef; + char *configfile = NULL; + char *configstr = NULL; network->dnsmasqPid = -1; @@ -876,15 +898,40 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdou if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) return 0; - cmd = virCommandNew(DNSMASQ); - if (networkBuildDnsmasqArgv(network, ipdef, pidfile, cmd, dctx) < 0) { + if (networkDnsmasqConfContents(network, ipdef, pidfile, &configstr, dctx) < 0) goto cleanup; + if (!configstr) + goto cleanup; + + if (testOnly) { + *testConfigStr = configstr; + return 0; } + /* construct the filename */ + if (!(configfile = networkDnsmasqConfigFileName(network->def->name))) { + virReportOOMError(); + goto cleanup; + } + + /* Write the file */ + if (virFileWriteStr(configfile, configstr, 0600) < 0) { + virReportSystemError(errno, + _("couldn't write dnsmasq config file '%s'"), + configfile); + goto cleanup; + } + VIR_INFO("dnsmasq conf file %s written", configfile); + + cmd = virCommandNew(DNSMASQ); + virCommandAddArgFormat(cmd, "--conf-file=%s", configfile); + if (cmdout) *cmdout = cmd; ret = 0; cleanup: + VIR_FREE(configstr); + VIR_FREE(configfile); if (ret < 0) virCommandFree(cmd); return ret; @@ -895,6 +942,7 @@ networkStartDhcpDaemon(virNetworkObjPtr network) { virCommandPtr cmd = NULL; char *pidfile = NULL; + char *testconfigstr = NULL; int ret = -1; dnsmasqContext *dctx = NULL; virNetworkIpDefPtr ipdef; @@ -935,7 +983,8 @@ networkStartDhcpDaemon(virNetworkObjPtr network) if (dctx == NULL) goto cleanup; - ret = networkBuildDhcpDaemonCommandLine(network, &cmd, pidfile, dctx); + ret = networkBuildDhcpDaemonCommandLine(network, &cmd, pidfile, dctx, + 0, &testconfigstr); if (ret < 0) goto cleanup; diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h index 0fae275..b6dd6c9 100644 --- a/src/network/bridge_driver.h +++ b/src/network/bridge_driver.h @@ -48,15 +48,16 @@ int networkGetNetworkAddress(const char *netname, char **netaddr) int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdout, char *pidfile, - dnsmasqContext *dctx) - ; + dnsmasqContext *dctx, + int testOnly, char **testConfigStr); # else /* Define no-op replacements that don't drag in any link dependencies. */ # define networkAllocateActualDevice(iface) 0 # define networkNotifyActualDevice(iface) 0 # define networkReleaseActualDevice(iface) 0 # define networkGetNetworkAddress(netname, netaddr) (-2) -# define networkBuildDhcpDaemonCommandLine(network, cmdout, pidfile, dctx) 0 +# define networkBuildDhcpDaemonCommandLine(network, cmdout, pidfile, \ + dctx, testOnly, testConfigStr) 0 # endif typedef char *(*networkDnsmasqLeaseFileNameFunc)(const char *netname); diff --git a/tests/networkxml2argvdata/isolated-network.argv b/tests/networkxml2argvdata/isolated-network.argv index 13e77b2..042158b 100644 --- a/tests/networkxml2argvdata/isolated-network.argv +++ b/tests/networkxml2argvdata/isolated-network.argv @@ -1,9 +1,15 @@ -@DNSMASQ@ --strict-order --bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo --dhcp-option=3 --no-resolv \ ---listen-address 192.168.152.1 \ ---dhcp-range 192.168.152.2,192.168.152.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/private.leases --dhcp-lease-max=253 \ ---dhcp-no-override \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/private.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/private.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +dhcp-option=3 +no-resolv +listen-address=192.168.152.1 +dhcp-range=192.168.152.2,192.168.152.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/private.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/private.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/private.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-hosts.argv b/tests/networkxml2argvdata/nat-network-dns-hosts.argv index 03a0676..91eb682 100644 --- a/tests/networkxml2argvdata/nat-network-dns-hosts.argv +++ b/tests/networkxml2argvdata/nat-network-dns-hosts.argv @@ -1,4 +1,10 @@ -@DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \ ---local=/example.com/ --domain-needed \ ---conf-file= --except-interface lo --listen-address 192.168.122.1 \ ---expand-hosts --addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=/example.com/ +domain=example.com +expand-hosts +listen-address=192.168.122.1 +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv index 210a60c..d92497b 100644 --- a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv @@ -1,17 +1,18 @@ -@DNSMASQ@ \ ---strict-order \ ---bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo \ ---srv-host=name.tcp.,,,, \ ---listen-address 192.168.122.1 \ ---listen-address 192.168.123.1 \ ---listen-address 2001:db8:ac10:fe01::1 \ ---listen-address 2001:db8:ac10:fd01::1 \ ---listen-address 10.24.10.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \ ---dhcp-lease-max=253 \ ---dhcp-no-override \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +srv-host=name.tcp.,,,, +listen-address=192.168.122.1 +listen-address=192.168.123.1 +listen-address=2001:db8:ac10:fe01::1 +listen-address=2001:db8:ac10:fd01::1 +listen-address=10.24.10.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv index 833d3cd..d8846c2 100644 --- a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv @@ -1,17 +1,18 @@ -@DNSMASQ@ \ ---strict-order \ ---bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo \ ---srv-host=name.tcp.test-domain-name,.,1024,10,10 \ ---listen-address 192.168.122.1 \ ---listen-address 192.168.123.1 \ ---listen-address 2001:db8:ac10:fe01::1 \ ---listen-address 2001:db8:ac10:fd01::1 \ ---listen-address 10.24.10.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \ ---dhcp-lease-max=253 \ ---dhcp-no-override \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +srv-host=name.tcp.test-domain-name,.,1024,10,10 +listen-address=192.168.122.1 +listen-address=192.168.123.1 +listen-address=2001:db8:ac10:fe01::1 +listen-address=2001:db8:ac10:fd01::1 +listen-address=10.24.10.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv index 3481507..bf00513 100644 --- a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv +++ b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv @@ -1,11 +1,18 @@ -@DNSMASQ@ --strict-order --bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo '--txt-record=example,example value' \ ---listen-address 192.168.122.1 --listen-address 192.168.123.1 \ ---listen-address 2001:db8:ac10:fe01::1 \ ---listen-address 2001:db8:ac10:fd01::1 --listen-address 10.24.10.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \ ---dhcp-lease-max=253 --dhcp-no-override \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +txt-record=example,example value +listen-address=192.168.122.1 +listen-address=192.168.123.1 +listen-address=2001:db8:ac10:fe01::1 +listen-address=2001:db8:ac10:fd01::1 +listen-address=10.24.10.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network.argv b/tests/networkxml2argvdata/nat-network.argv index 37fd2fc..d542bbc 100644 --- a/tests/networkxml2argvdata/nat-network.argv +++ b/tests/networkxml2argvdata/nat-network.argv @@ -1,10 +1,17 @@ -@DNSMASQ@ --strict-order --bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo --listen-address 192.168.122.1 \ ---listen-address 192.168.123.1 --listen-address 2001:db8:ac10:fe01::1 \ ---listen-address 2001:db8:ac10:fd01::1 --listen-address 10.24.10.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \ ---dhcp-lease-max=253 --dhcp-no-override \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +listen-address=192.168.122.1 +listen-address=192.168.123.1 +listen-address=2001:db8:ac10:fe01::1 +listen-address=2001:db8:ac10:fd01::1 +listen-address=10.24.10.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/netboot-network.argv b/tests/networkxml2argvdata/netboot-network.argv index 5408eb7..4f5fedd 100644 --- a/tests/networkxml2argvdata/netboot-network.argv +++ b/tests/networkxml2argvdata/netboot-network.argv @@ -1,10 +1,18 @@ -@DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \ ---local=/example.com/ --domain-needed --conf-file= \ ---except-interface lo --listen-address 192.168.122.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases \ ---dhcp-lease-max=253 --dhcp-no-override --expand-hosts \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts \ ---enable-tftp \ ---tftp-root /var/lib/tftproot --dhcp-boot pxeboot.img\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=/example.com/ +domain=example.com +expand-hosts +listen-address=192.168.122.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts +enable-tftp +tftp-root=/var/lib/tftproot +dhcp-boot=pxeboot.img diff --git a/tests/networkxml2argvdata/netboot-proxy-network.argv b/tests/networkxml2argvdata/netboot-proxy-network.argv index 21e01e3..8b9c03a 100644 --- a/tests/networkxml2argvdata/netboot-proxy-network.argv +++ b/tests/networkxml2argvdata/netboot-proxy-network.argv @@ -1,9 +1,16 @@ -@DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \ ---local=/example.com/ --domain-needed --conf-file= \ ---except-interface lo --listen-address 192.168.122.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases \ ---dhcp-lease-max=253 --dhcp-no-override --expand-hosts \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts \ ---dhcp-boot pxeboot.img,,10.20.30.40\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=/example.com/ +domain=example.com +expand-hosts +listen-address=192.168.122.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts +dhcp-boot=pxeboot.img,,10.20.30.40 diff --git a/tests/networkxml2argvdata/routed-network.argv b/tests/networkxml2argvdata/routed-network.argv index 9fedb2b..ad9e121 100644 --- a/tests/networkxml2argvdata/routed-network.argv +++ b/tests/networkxml2argvdata/routed-network.argv @@ -1,4 +1,8 @@ -@DNSMASQ@ --strict-order --bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo --listen-address 192.168.122.1 \ ---addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +listen-address=192.168.122.1 +addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts diff --git a/tests/networkxml2argvtest.c b/tests/networkxml2argvtest.c index 87519e4..3738734 100644 --- a/tests/networkxml2argvtest.c +++ b/tests/networkxml2argvtest.c @@ -15,37 +15,6 @@ #include "memory.h" #include "network/bridge_driver.h" -/* Replace all occurrences of @token in @buf by @replacement and adjust size of - * @buf accordingly. Returns 0 on success and -1 on out-of-memory errors. */ -static int replaceTokens(char **buf, const char *token, const char *replacement) { - size_t token_start, token_end; - size_t buf_len, rest_len; - const size_t token_len = strlen(token); - const size_t replacement_len = strlen(replacement); - const int diff = replacement_len - token_len; - - buf_len = rest_len = strlen(*buf) + 1; - token_end = 0; - for (;;) { - char *match = strstr(*buf + token_end, token); - if (match == NULL) - break; - token_start = match - *buf; - rest_len -= token_start + token_len - token_end; - token_end = token_start + token_len; - buf_len += diff; - if (diff > 0) - if (VIR_REALLOC_N(*buf, buf_len) < 0) - return -1; - if (diff != 0) - memmove(*buf + token_end + diff, *buf + token_end, rest_len); - memcpy(*buf + token_start, replacement, replacement_len); - token_end += diff; - } - /* if diff < 0, we could shrink the buffer here... */ - return 0; -} - static int testCompareXMLToArgvFiles(const char *inxml, const char *outargv) { char *inXmlData = NULL; char *outArgvData = NULL; @@ -62,10 +31,6 @@ static int testCompareXMLToArgvFiles(const char *inxml, const char *outargv) { if (virtTestLoadFile(outargv, &outArgvData) < 0) goto fail; - - if (replaceTokens(&outArgvData, "@DNSMASQ@", DNSMASQ)) - goto fail; - if (!(dev = virNetworkDefParseString(inXmlData))) goto fail; @@ -78,12 +43,9 @@ static int testCompareXMLToArgvFiles(const char *inxml, const char *outargv) { if (dctx == NULL) goto fail; - if (networkBuildDhcpDaemonCommandLine(obj, &cmd, pidfile, dctx) < 0) - goto fail; - - if (!(actual = virCommandToString(cmd))) + if (networkBuildDhcpDaemonCommandLine(obj, &cmd, pidfile, + dctx, 1, &actual) < 0) goto fail; - if (STRNEQ(outArgvData, actual)) { virtTestDifference(stderr, outArgvData, actual); goto fail; @@ -147,7 +109,6 @@ mymain(void) if (virtTestRun("Network XML-2-Argv " name, \ 1, testCompareXMLToArgvHelper, (name)) < 0) \ ret = -1 - DO_TEST("isolated-network"); DO_TEST("routed-network"); DO_TEST("nat-network"); -- 1.7.11.7

On Thu, Nov 08, 2012 at 04:13:41PM -0500, Gene Czarcinski wrote:
This patch changes how parameters are passed to dnsmasq. Instead of being on the command line, the parameters are put into a file (one parameter per line) and a commandline --conf-file= specifies the location of the file. The file is located in the same directory as the leases file.
It'd be great if the commit message would state _why_ this is useful. Cheers, -- Guido
--- src/network/bridge_driver.c | 153 ++++++++++++++------- src/network/bridge_driver.h | 7 +- tests/networkxml2argvdata/isolated-network.argv | 24 ++-- .../networkxml2argvdata/nat-network-dns-hosts.argv | 14 +- .../nat-network-dns-srv-record-minimal.argv | 35 ++--- .../nat-network-dns-srv-record.argv | 35 ++--- .../nat-network-dns-txt-record.argv | 29 ++-- tests/networkxml2argvdata/nat-network.argv | 27 ++-- tests/networkxml2argvdata/netboot-network.argv | 28 ++-- .../networkxml2argvdata/netboot-proxy-network.argv | 25 ++-- tests/networkxml2argvdata/routed-network.argv | 12 +- tests/networkxml2argvtest.c | 43 +----- 12 files changed, 245 insertions(+), 187 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index c153d36..508de3a 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -136,6 +136,16 @@ networkDnsmasqLeaseFileNameFunc networkDnsmasqLeaseFileName = networkDnsmasqLeaseFileNameDefault;
static char * +networkDnsmasqConfigFileName(const char *netname) +{ + char *conffile; + + ignore_value(virAsprintf(&conffile, DNSMASQ_STATE_DIR "/%s.conf", + netname)); + return conffile; +} + +static char * networkRadvdPidfileBasename(const char *netname) { /* this is simple but we want to be sure it's consistently done */ @@ -163,6 +173,7 @@ networkRemoveInactive(struct network_driver *driver, char *leasefile = NULL; char *radvdconfigfile = NULL; char *radvdpidbase = NULL; + char *configfile = NULL; dnsmasqContext *dctx = NULL; virNetworkDefPtr def = virNetworkObjGetPersistentDef(net);
@@ -178,12 +189,16 @@ networkRemoveInactive(struct network_driver *driver, if (!(radvdconfigfile = networkRadvdConfigFileName(def->name))) goto no_memory;
- if (!(radvdpidbase = networkRadvdPidfileBasename(def->name))) + if (!(radvdconfigfile = networkRadvdConfigFileName(def->name))) + goto no_memory; + + if (!(configfile = networkDnsmasqConfigFileName(def->name))) goto no_memory;
/* dnsmasq */ dnsmasqDelete(dctx); unlink(leasefile); + unlink(configfile);
/* radvd */ unlink(radvdconfigfile); @@ -196,6 +211,7 @@ networkRemoveInactive(struct network_driver *driver,
cleanup: VIR_FREE(leasefile); + VIR_FREE(configfile); VIR_FREE(radvdconfigfile); VIR_FREE(radvdpidbase); dnsmasqContextFree(dctx); @@ -610,14 +626,15 @@ networkBuildDnsmasqHostsfile(dnsmasqContext *dctx, return 0; }
- + /* build the dnsmasq conf file contents */ static int -networkBuildDnsmasqArgv(virNetworkObjPtr network, +networkDnsmasqConfContents(virNetworkObjPtr network, virNetworkIpDefPtr ipdef, const char *pidfile, - virCommandPtr cmd, + char **configstr, dnsmasqContext *dctx) { + virBuffer configbuf = VIR_BUFFER_INITIALIZER;; int r, ret = -1; int nbleases = 0; int ii; @@ -627,6 +644,8 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, char *recordPriority = NULL; virNetworkIpDefPtr tmpipdef;
+ *configstr = NULL; + /* * NB, be careful about syntax for dnsmasq options in long format. * @@ -646,28 +665,22 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, * very explicit on this. */
- /* - * Needed to ensure dnsmasq uses same algorithm for processing - * multiple namedriver entries in /etc/resolv.conf as GLibC. - */ - virCommandAddArgList(cmd, "--strict-order", "--bind-interfaces", NULL); - + /* create dnsmasq config file appropriate for this network */ + virBufferAsprintf(&configbuf, "# dnsmasq conf file created by libvirt\n" + "strict-order\n" + "bind-interfaces\n" + "except-interface=lo\n" + "domain-needed\n" + "local=/%s/\n", + network->def->domain ? network->def->domain : ""); if (network->def->domain) - virCommandAddArgPair(cmd, "--domain", network->def->domain); - /* need to specify local even if no domain specified */ - virCommandAddArgFormat(cmd, "--local=/%s/", - network->def->domain ? network->def->domain : ""); - virCommandAddArg(cmd, "--domain-needed"); + virBufferAsprintf(&configbuf, + "domain=%s\n" + "expand-hosts\n", + network->def->domain);
if (pidfile) - virCommandAddArgPair(cmd, "--pid-file", pidfile); - - /* *no* conf file */ - virCommandAddArg(cmd, "--conf-file="); - - virCommandAddArgList(cmd, - "--except-interface", "lo", - NULL); + virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
/* If this is an isolated network, set the default route option * (3) to be empty to avoid setting a default route that's @@ -677,16 +690,21 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, * to build a connection to the outside). */ if (network->def->forwardType == VIR_NETWORK_FORWARD_NONE) { - virCommandAddArgList(cmd, "--dhcp-option=3", - "--no-resolv", NULL); + virBufferAsprintf(&configbuf, "dhcp-option=3\n" + "no-resolv\n"); }
+ /* + * Needed to ensure dnsmasq uses same algorithm for processing + * multiple namedriver entries in /etc/resolv.conf as GLibC. + */ + if (network->def->dns != NULL) { virNetworkDNSDefPtr dns = network->def->dns; int i;
for (i = 0; i < dns->ntxtrecords; i++) { - virCommandAddArgFormat(cmd, "--txt-record=%s,%s", + virBufferAsprintf(&configbuf, "txt-record=%s,%s\n", dns->txtrecords[i].name, dns->txtrecords[i].value); } @@ -724,7 +742,7 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, goto cleanup; }
- virCommandAddArgPair(cmd, "--srv-host", record); + virBufferAsprintf(&configbuf, "srv-host=%s\n", record); VIR_FREE(record); VIR_FREE(recordPort); VIR_FREE(recordWeight); @@ -743,11 +761,12 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, */ for (ii = 0; (tmpipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii)); - ii++) { + ii++) + { char *ipaddr = virSocketAddrFormat(&tmpipdef->address); if (!ipaddr) goto cleanup; - virCommandAddArgList(cmd, "--listen-address", ipaddr, NULL); + virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr); VIR_FREE(ipaddr); }
@@ -761,8 +780,8 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, VIR_FREE(saddr); goto cleanup; } - virCommandAddArg(cmd, "--dhcp-range"); - virCommandAddArgFormat(cmd, "%s,%s", saddr, eaddr); + virBufferAsprintf(&configbuf, "dhcp-range=%s,%s\n", + saddr, eaddr); VIR_FREE(saddr); VIR_FREE(eaddr); nbleases += virSocketAddrGetRange(&ipdef->ranges[r].start, @@ -778,8 +797,7 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, char *bridgeaddr = virSocketAddrFormat(&ipdef->address); if (!bridgeaddr) goto cleanup; - virCommandAddArg(cmd, "--dhcp-range"); - virCommandAddArgFormat(cmd, "%s,static", bridgeaddr); + virBufferAsprintf(&configbuf, "dhcp-range=%s,static\n", bridgeaddr); VIR_FREE(bridgeaddr); }
@@ -787,17 +805,13 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, char *leasefile = networkDnsmasqLeaseFileName(network->def->name); if (!leasefile) goto cleanup; - virCommandAddArgFormat(cmd, "--dhcp-leasefile=%s", leasefile); + virBufferAsprintf(&configbuf, "dhcp-leasefile=%s\n", leasefile); VIR_FREE(leasefile); - virCommandAddArgFormat(cmd, "--dhcp-lease-max=%d", nbleases); + virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases); }
if (ipdef->nranges || ipdef->nhosts) - virCommandAddArg(cmd, "--dhcp-no-override"); - - /* add domain to any non-qualified hostnames in /etc/hosts or addn-hosts */ - if (network->def->domain) - virCommandAddArg(cmd, "--expand-hosts"); + virBufferAsprintf(&configbuf, "dhcp-no-override\n");
if (networkBuildDnsmasqHostsfile(dctx, ipdef, network->def->dns) < 0) goto cleanup; @@ -807,38 +821,42 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, * file to allow for runtime additions. */ if (ipdef->nranges || ipdef->nhosts) - virCommandAddArgPair(cmd, "--dhcp-hostsfile", + virBufferAsprintf(&configbuf, "dhcp-hostsfile=%s\n", dctx->hostsfile->path);
/* Likewise, always create this file and put it on the commandline, to allow for * for runtime additions. */ - virCommandAddArgPair(cmd, "--addn-hosts", + virBufferAsprintf(&configbuf, "addn-hosts=%s\n", dctx->addnhostsfile->path);
if (ipdef->tftproot) { - virCommandAddArgList(cmd, "--enable-tftp", - "--tftp-root", ipdef->tftproot, - NULL); + virBufferAsprintf(&configbuf, "enable-tftp\n"); + virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot); } if (ipdef->bootfile) { - virCommandAddArg(cmd, "--dhcp-boot"); if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) { char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
if (!bootserver) goto cleanup; - virCommandAddArgFormat(cmd, "%s%s%s", + virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n", ipdef->bootfile, ",,", bootserver); VIR_FREE(bootserver); } else { - virCommandAddArg(cmd, ipdef->bootfile); + virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile); } } } + if (!(*configstr = virBufferContentAndReset(&configbuf))) { + virReportOOMError(); + goto cleanup; + }
ret = 0; + cleanup: + virBufferFreeAndReset(&configbuf); VIR_FREE(record); VIR_FREE(recordPort); VIR_FREE(recordWeight); @@ -846,13 +864,17 @@ cleanup: return ret; }
+ /* build the dnsmasq command line */ int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdout, - char *pidfile, dnsmasqContext *dctx) + char *pidfile, dnsmasqContext *dctx, + int testOnly, char **testConfigStr) { virCommandPtr cmd = NULL; int ret = -1, ii; virNetworkIpDefPtr ipdef; + char *configfile = NULL; + char *configstr = NULL;
network->dnsmasqPid = -1;
@@ -876,15 +898,40 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdou if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) return 0;
- cmd = virCommandNew(DNSMASQ); - if (networkBuildDnsmasqArgv(network, ipdef, pidfile, cmd, dctx) < 0) { + if (networkDnsmasqConfContents(network, ipdef, pidfile, &configstr, dctx) < 0) goto cleanup; + if (!configstr) + goto cleanup; + + if (testOnly) { + *testConfigStr = configstr; + return 0; }
+ /* construct the filename */ + if (!(configfile = networkDnsmasqConfigFileName(network->def->name))) { + virReportOOMError(); + goto cleanup; + } + + /* Write the file */ + if (virFileWriteStr(configfile, configstr, 0600) < 0) { + virReportSystemError(errno, + _("couldn't write dnsmasq config file '%s'"), + configfile); + goto cleanup; + } + VIR_INFO("dnsmasq conf file %s written", configfile); + + cmd = virCommandNew(DNSMASQ); + virCommandAddArgFormat(cmd, "--conf-file=%s", configfile); + if (cmdout) *cmdout = cmd; ret = 0; cleanup: + VIR_FREE(configstr); + VIR_FREE(configfile); if (ret < 0) virCommandFree(cmd); return ret; @@ -895,6 +942,7 @@ networkStartDhcpDaemon(virNetworkObjPtr network) { virCommandPtr cmd = NULL; char *pidfile = NULL; + char *testconfigstr = NULL; int ret = -1; dnsmasqContext *dctx = NULL; virNetworkIpDefPtr ipdef; @@ -935,7 +983,8 @@ networkStartDhcpDaemon(virNetworkObjPtr network) if (dctx == NULL) goto cleanup;
- ret = networkBuildDhcpDaemonCommandLine(network, &cmd, pidfile, dctx); + ret = networkBuildDhcpDaemonCommandLine(network, &cmd, pidfile, dctx, + 0, &testconfigstr); if (ret < 0) goto cleanup;
diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h index 0fae275..b6dd6c9 100644 --- a/src/network/bridge_driver.h +++ b/src/network/bridge_driver.h @@ -48,15 +48,16 @@ int networkGetNetworkAddress(const char *netname, char **netaddr)
int networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdout, char *pidfile, - dnsmasqContext *dctx) - ; + dnsmasqContext *dctx, + int testOnly, char **testConfigStr); # else /* Define no-op replacements that don't drag in any link dependencies. */ # define networkAllocateActualDevice(iface) 0 # define networkNotifyActualDevice(iface) 0 # define networkReleaseActualDevice(iface) 0 # define networkGetNetworkAddress(netname, netaddr) (-2) -# define networkBuildDhcpDaemonCommandLine(network, cmdout, pidfile, dctx) 0 +# define networkBuildDhcpDaemonCommandLine(network, cmdout, pidfile, \ + dctx, testOnly, testConfigStr) 0 # endif
typedef char *(*networkDnsmasqLeaseFileNameFunc)(const char *netname); diff --git a/tests/networkxml2argvdata/isolated-network.argv b/tests/networkxml2argvdata/isolated-network.argv index 13e77b2..042158b 100644 --- a/tests/networkxml2argvdata/isolated-network.argv +++ b/tests/networkxml2argvdata/isolated-network.argv @@ -1,9 +1,15 @@ -@DNSMASQ@ --strict-order --bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo --dhcp-option=3 --no-resolv \ ---listen-address 192.168.152.1 \ ---dhcp-range 192.168.152.2,192.168.152.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/private.leases --dhcp-lease-max=253 \ ---dhcp-no-override \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/private.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/private.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +dhcp-option=3 +no-resolv +listen-address=192.168.152.1 +dhcp-range=192.168.152.2,192.168.152.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/private.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/private.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/private.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-hosts.argv b/tests/networkxml2argvdata/nat-network-dns-hosts.argv index 03a0676..91eb682 100644 --- a/tests/networkxml2argvdata/nat-network-dns-hosts.argv +++ b/tests/networkxml2argvdata/nat-network-dns-hosts.argv @@ -1,4 +1,10 @@ -@DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \ ---local=/example.com/ --domain-needed \ ---conf-file= --except-interface lo --listen-address 192.168.122.1 \ ---expand-hosts --addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=/example.com/ +domain=example.com +expand-hosts +listen-address=192.168.122.1 +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv index 210a60c..d92497b 100644 --- a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv @@ -1,17 +1,18 @@ -@DNSMASQ@ \ ---strict-order \ ---bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo \ ---srv-host=name.tcp.,,,, \ ---listen-address 192.168.122.1 \ ---listen-address 192.168.123.1 \ ---listen-address 2001:db8:ac10:fe01::1 \ ---listen-address 2001:db8:ac10:fd01::1 \ ---listen-address 10.24.10.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \ ---dhcp-lease-max=253 \ ---dhcp-no-override \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +srv-host=name.tcp.,,,, +listen-address=192.168.122.1 +listen-address=192.168.123.1 +listen-address=2001:db8:ac10:fe01::1 +listen-address=2001:db8:ac10:fd01::1 +listen-address=10.24.10.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv index 833d3cd..d8846c2 100644 --- a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv @@ -1,17 +1,18 @@ -@DNSMASQ@ \ ---strict-order \ ---bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo \ ---srv-host=name.tcp.test-domain-name,.,1024,10,10 \ ---listen-address 192.168.122.1 \ ---listen-address 192.168.123.1 \ ---listen-address 2001:db8:ac10:fe01::1 \ ---listen-address 2001:db8:ac10:fd01::1 \ ---listen-address 10.24.10.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \ ---dhcp-lease-max=253 \ ---dhcp-no-override \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +srv-host=name.tcp.test-domain-name,.,1024,10,10 +listen-address=192.168.122.1 +listen-address=192.168.123.1 +listen-address=2001:db8:ac10:fe01::1 +listen-address=2001:db8:ac10:fd01::1 +listen-address=10.24.10.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv index 3481507..bf00513 100644 --- a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv +++ b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv @@ -1,11 +1,18 @@ -@DNSMASQ@ --strict-order --bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo '--txt-record=example,example value' \ ---listen-address 192.168.122.1 --listen-address 192.168.123.1 \ ---listen-address 2001:db8:ac10:fe01::1 \ ---listen-address 2001:db8:ac10:fd01::1 --listen-address 10.24.10.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \ ---dhcp-lease-max=253 --dhcp-no-override \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +txt-record=example,example value +listen-address=192.168.122.1 +listen-address=192.168.123.1 +listen-address=2001:db8:ac10:fe01::1 +listen-address=2001:db8:ac10:fd01::1 +listen-address=10.24.10.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network.argv b/tests/networkxml2argvdata/nat-network.argv index 37fd2fc..d542bbc 100644 --- a/tests/networkxml2argvdata/nat-network.argv +++ b/tests/networkxml2argvdata/nat-network.argv @@ -1,10 +1,17 @@ -@DNSMASQ@ --strict-order --bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo --listen-address 192.168.122.1 \ ---listen-address 192.168.123.1 --listen-address 2001:db8:ac10:fe01::1 \ ---listen-address 2001:db8:ac10:fd01::1 --listen-address 10.24.10.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases \ ---dhcp-lease-max=253 --dhcp-no-override \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +listen-address=192.168.122.1 +listen-address=192.168.123.1 +listen-address=2001:db8:ac10:fe01::1 +listen-address=2001:db8:ac10:fd01::1 +listen-address=10.24.10.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/netboot-network.argv b/tests/networkxml2argvdata/netboot-network.argv index 5408eb7..4f5fedd 100644 --- a/tests/networkxml2argvdata/netboot-network.argv +++ b/tests/networkxml2argvdata/netboot-network.argv @@ -1,10 +1,18 @@ -@DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \ ---local=/example.com/ --domain-needed --conf-file= \ ---except-interface lo --listen-address 192.168.122.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases \ ---dhcp-lease-max=253 --dhcp-no-override --expand-hosts \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts \ ---enable-tftp \ ---tftp-root /var/lib/tftproot --dhcp-boot pxeboot.img\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=/example.com/ +domain=example.com +expand-hosts +listen-address=192.168.122.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts +enable-tftp +tftp-root=/var/lib/tftproot +dhcp-boot=pxeboot.img diff --git a/tests/networkxml2argvdata/netboot-proxy-network.argv b/tests/networkxml2argvdata/netboot-proxy-network.argv index 21e01e3..8b9c03a 100644 --- a/tests/networkxml2argvdata/netboot-proxy-network.argv +++ b/tests/networkxml2argvdata/netboot-proxy-network.argv @@ -1,9 +1,16 @@ -@DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \ ---local=/example.com/ --domain-needed --conf-file= \ ---except-interface lo --listen-address 192.168.122.1 \ ---dhcp-range 192.168.122.2,192.168.122.254 \ ---dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases \ ---dhcp-lease-max=253 --dhcp-no-override --expand-hosts \ ---dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile \ ---addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts \ ---dhcp-boot pxeboot.img,,10.20.30.40\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=/example.com/ +domain=example.com +expand-hosts +listen-address=192.168.122.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases +dhcp-lease-max=253 +dhcp-no-override +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts +dhcp-boot=pxeboot.img,,10.20.30.40 diff --git a/tests/networkxml2argvdata/routed-network.argv b/tests/networkxml2argvdata/routed-network.argv index 9fedb2b..ad9e121 100644 --- a/tests/networkxml2argvdata/routed-network.argv +++ b/tests/networkxml2argvdata/routed-network.argv @@ -1,4 +1,8 @@ -@DNSMASQ@ --strict-order --bind-interfaces \ ---local=// --domain-needed --conf-file= \ ---except-interface lo --listen-address 192.168.122.1 \ ---addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts\ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +listen-address=192.168.122.1 +addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts diff --git a/tests/networkxml2argvtest.c b/tests/networkxml2argvtest.c index 87519e4..3738734 100644 --- a/tests/networkxml2argvtest.c +++ b/tests/networkxml2argvtest.c @@ -15,37 +15,6 @@ #include "memory.h" #include "network/bridge_driver.h"
-/* Replace all occurrences of @token in @buf by @replacement and adjust size of - * @buf accordingly. Returns 0 on success and -1 on out-of-memory errors. */ -static int replaceTokens(char **buf, const char *token, const char *replacement) { - size_t token_start, token_end; - size_t buf_len, rest_len; - const size_t token_len = strlen(token); - const size_t replacement_len = strlen(replacement); - const int diff = replacement_len - token_len; - - buf_len = rest_len = strlen(*buf) + 1; - token_end = 0; - for (;;) { - char *match = strstr(*buf + token_end, token); - if (match == NULL) - break; - token_start = match - *buf; - rest_len -= token_start + token_len - token_end; - token_end = token_start + token_len; - buf_len += diff; - if (diff > 0) - if (VIR_REALLOC_N(*buf, buf_len) < 0) - return -1; - if (diff != 0) - memmove(*buf + token_end + diff, *buf + token_end, rest_len); - memcpy(*buf + token_start, replacement, replacement_len); - token_end += diff; - } - /* if diff < 0, we could shrink the buffer here... */ - return 0; -} - static int testCompareXMLToArgvFiles(const char *inxml, const char *outargv) { char *inXmlData = NULL; char *outArgvData = NULL; @@ -62,10 +31,6 @@ static int testCompareXMLToArgvFiles(const char *inxml, const char *outargv) {
if (virtTestLoadFile(outargv, &outArgvData) < 0) goto fail; - - if (replaceTokens(&outArgvData, "@DNSMASQ@", DNSMASQ)) - goto fail; - if (!(dev = virNetworkDefParseString(inXmlData))) goto fail;
@@ -78,12 +43,9 @@ static int testCompareXMLToArgvFiles(const char *inxml, const char *outargv) { if (dctx == NULL) goto fail;
- if (networkBuildDhcpDaemonCommandLine(obj, &cmd, pidfile, dctx) < 0) - goto fail; - - if (!(actual = virCommandToString(cmd))) + if (networkBuildDhcpDaemonCommandLine(obj, &cmd, pidfile, + dctx, 1, &actual) < 0) goto fail; - if (STRNEQ(outArgvData, actual)) { virtTestDifference(stderr, outArgvData, actual); goto fail; @@ -147,7 +109,6 @@ mymain(void) if (virtTestRun("Network XML-2-Argv " name, \ 1, testCompareXMLToArgvHelper, (name)) < 0) \ ret = -1 - DO_TEST("isolated-network"); DO_TEST("routed-network"); DO_TEST("nat-network"); -- 1.7.11.7
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 11/09/2012 07:36 AM, Guido Günther wrote:
On Thu, Nov 08, 2012 at 04:13:41PM -0500, Gene Czarcinski wrote:
This patch changes how parameters are passed to dnsmasq. Instead of being on the command line, the parameters are put into a file (one parameter per line) and a commandline --conf-file= specifies the location of the file. The file is located in the same directory as the leases file. It'd be great if the commit message would state_why_ this is useful. Cheers, Much as it pains me to admit it but you have a valid point. I have been working on this for some time and the usefulness of this is "obvious" to me. While one of the first objectives was to remove the command line clutter by moving the dnsmasq parameters into a conf-file, it is with some planned (by me) future additions/enhancements where it becomes more important.
1. Specify a second conf-file which will initially be allocated as a zero-length file. This file will not be deleted when the network is destroyed. The purpose here is to be able to add log-queries and/or log-dhcp parameters to turn on dnsmasq logging. This can produce a log of clutter in syslog so it should be used onlt when necessary. But, when it it needed, it can be the only way to figure out what is happening. 2. A previous patch I submitted which was accepted involved adding the local=/<domain-name>/ parameter. With this parameter, dnsmasq will not forward queries for the domain it handles. However, currently it will forward reverse lookup queries for it subnetwork. The fix is to add more local=/<ip4>.in-addr-arpa/ for IPv6 and local=/<ip6>.ip6.arpa/. And "<ip6>.ip6.arpa" expands into a forty four character string. I also find it a lot easier to look and and understand a conf-file than looking at the the command line. In addition, the rest of the string of submitted updates all assume this this one is applied. And lastly, from what I have observed, configuration files are preferred to command line parameters. I hope this scratches your itch. Gene

On Fri, Nov 09, 2012 at 08:39:46AM -0500, Gene Czarcinski wrote:
On Thu, Nov 08, 2012 at 04:13:41PM -0500, Gene Czarcinski wrote:
This patch changes how parameters are passed to dnsmasq. Instead of being on the command line, the parameters are put into a file (one parameter per line) and a commandline --conf-file= specifies the location of the file. The file is located in the same directory as the leases file. It'd be great if the commit message would state_why_ this is useful. Cheers, Much as it pains me to admit it but you have a valid point. I have been working on this for some time and the usefulness of this is "obvious" to me. While one of the first objectives was to remove
On 11/09/2012 07:36 AM, Guido Günther wrote: the command line clutter by moving the dnsmasq parameters into a conf-file, it is with some planned (by me) future additions/enhancements where it becomes more important.
1. Specify a second conf-file which will initially be allocated as a zero-length file. This file will not be deleted when the network is destroyed. The purpose here is to be able to add log-queries and/or log-dhcp parameters to turn on dnsmasq logging. This can produce a log of clutter in syslog so it should be used onlt when necessary. But, when it it needed, it can be the only way to figure out what is happening.
2. A previous patch I submitted which was accepted involved adding the local=/<domain-name>/ parameter. With this parameter, dnsmasq will not forward queries for the domain it handles. However, currently it will forward reverse lookup queries for it subnetwork. The fix is to add more local=/<ip4>.in-addr-arpa/ for IPv6 and local=/<ip6>.ip6.arpa/. And "<ip6>.ip6.arpa" expands into a forty four character string.
I also find it a lot easier to look and and understand a conf-file than looking at the the command line.
Thanks for the summary! But wouldn't it also make sense to include this in the commit message for reference (this also applies to the other commits)? Cheers, -- Guido
In addition, the rest of the string of submitted updates all assume this this one is applied.
And lastly, from what I have observed, configuration files are preferred to command line parameters.
I hope this scratches your itch.
Gene

On 11/09/2012 08:39 AM, Gene Czarcinski wrote:
On 11/09/2012 07:36 AM, Guido Günther wrote:
On Thu, Nov 08, 2012 at 04:13:41PM -0500, Gene Czarcinski wrote:
This patch changes how parameters are passed to dnsmasq. Instead of being on the command line, the parameters are put into a file (one parameter per line) and a commandline --conf-file= specifies the location of the file. The file is located in the same directory as the leases file. It'd be great if the commit message would state_why_ this is useful. Cheers, Much as it pains me to admit it but you have a valid point. I have been working on this for some time and the usefulness of this is "obvious" to me. While one of the first objectives was to remove the command line clutter by moving the dnsmasq parameters into a conf-file, it is with some planned (by me) future additions/enhancements where it becomes more important.
1. Specify a second conf-file which will initially be allocated as a zero-length file. This file will not be deleted when the network is destroyed. The purpose here is to be able to add log-queries and/or log-dhcp parameters to turn on dnsmasq logging. This can produce a log of clutter in syslog so it should be used onlt when necessary. But, when it it needed, it can be the only way to figure out what is happening.
I thought that we had determined this wouldn't work, because dnsmasq has its capabilities/privileges dropped as soon as it does the initial read of its config, and so it can't re-read its config files? Even if that isn't the case and dnsmasq *is* able to reread this config file, we can't allow that until we have a "network tainting" system in place similar to what we currently have for domains. This is needed to make it plainly clear that a configuration is operating "outside the box" and therefore all troubleshooting assumptions are invalid (this is what happens to a domain when, for example, a direct qemu-monitor command is sent to the domain, a "generic ethernet" device with a script file is attached, or an arbitrary commandline option is added to the qemu commandline). As a matter of fact, I think the more proper method of implementing this is to, as we've done in qemu, introduce a special dnsmasq namespace to the network xml, and allow specifying arbitrary command args via xml in that namespace. This way all of the config is still available in a single location, so there's never a question during debugging of whether or not extra command args were given to dnsmasq.
2. A previous patch I submitted which was accepted involved adding the local=/<domain-name>/ parameter. With this parameter, dnsmasq will not forward queries for the domain it handles. However, currently it will forward reverse lookup queries for it subnetwork. The fix is to add more local=/<ip4>.in-addr-arpa/ for IPv6 and local=/<ip6>.ip6.arpa/. And "<ip6>.ip6.arpa" expands into a forty four character string.
I also find it a lot easier to look and and understand a conf-file than looking at the the command line.
It's the above reasons that are most compelling to me.
In addition, the rest of the string of submitted updates all assume this this one is applied.
And lastly, from what I have observed, configuration files are preferred to command line parameters.
Well, we do call qemu with a big hairy long commandline... :-)

This patch adds the interface= dnsmasq parameter to the dnsmasq conf-file. The relavant tests are updated. --- src/network/bridge_driver.c | 10 ++-------- tests/networkxml2argvdata/isolated-network.argv | 1 + tests/networkxml2argvdata/nat-network-dns-hosts.argv | 1 + .../nat-network-dns-srv-record-minimal.argv | 1 + tests/networkxml2argvdata/nat-network-dns-srv-record.argv | 1 + tests/networkxml2argvdata/nat-network-dns-txt-record.argv | 1 + tests/networkxml2argvdata/nat-network.argv | 1 + tests/networkxml2argvdata/netboot-network.argv | 1 + tests/networkxml2argvdata/netboot-proxy-network.argv | 1 + tests/networkxml2argvdata/routed-network.argv | 1 + 10 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 508de3a..236d8f8 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -751,14 +751,8 @@ networkDnsmasqConfContents(virNetworkObjPtr network, } } - /* - * --interface does not actually work with dnsmasq < 2.47, - * due to DAD for ipv6 addresses on the interface. - * - * virCommandAddArgList(cmd, "--interface", ipdef->bridge, NULL); - * - * So listen on all defined IPv[46] addresses - */ + virBufferAsprintf(&configbuf, "interface=%s\n", network->def->bridge); + for (ii = 0; (tmpipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii)); ii++) diff --git a/tests/networkxml2argvdata/isolated-network.argv b/tests/networkxml2argvdata/isolated-network.argv index 042158b..abcde93 100644 --- a/tests/networkxml2argvdata/isolated-network.argv +++ b/tests/networkxml2argvdata/isolated-network.argv @@ -6,6 +6,7 @@ domain-needed local=// dhcp-option=3 no-resolv +interface=virbr2 listen-address=192.168.152.1 dhcp-range=192.168.152.2,192.168.152.254 dhcp-leasefile=/var/lib/libvirt/dnsmasq/private.leases diff --git a/tests/networkxml2argvdata/nat-network-dns-hosts.argv b/tests/networkxml2argvdata/nat-network-dns-hosts.argv index 91eb682..7dce6f9 100644 --- a/tests/networkxml2argvdata/nat-network-dns-hosts.argv +++ b/tests/networkxml2argvdata/nat-network-dns-hosts.argv @@ -6,5 +6,6 @@ domain-needed local=/example.com/ domain=example.com expand-hosts +interface=virbr0 listen-address=192.168.122.1 addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv index d92497b..d87d438 100644 --- a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv @@ -5,6 +5,7 @@ except-interface=lo domain-needed local=// srv-host=name.tcp.,,,, +interface=virbr0 listen-address=192.168.122.1 listen-address=192.168.123.1 listen-address=2001:db8:ac10:fe01::1 diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv index d8846c2..53882fe 100644 --- a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv @@ -5,6 +5,7 @@ except-interface=lo domain-needed local=// srv-host=name.tcp.test-domain-name,.,1024,10,10 +interface=virbr0 listen-address=192.168.122.1 listen-address=192.168.123.1 listen-address=2001:db8:ac10:fe01::1 diff --git a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv index bf00513..cc3ed28 100644 --- a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv +++ b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv @@ -5,6 +5,7 @@ except-interface=lo domain-needed local=// txt-record=example,example value +interface=virbr0 listen-address=192.168.122.1 listen-address=192.168.123.1 listen-address=2001:db8:ac10:fe01::1 diff --git a/tests/networkxml2argvdata/nat-network.argv b/tests/networkxml2argvdata/nat-network.argv index d542bbc..431fffb 100644 --- a/tests/networkxml2argvdata/nat-network.argv +++ b/tests/networkxml2argvdata/nat-network.argv @@ -4,6 +4,7 @@ bind-interfaces except-interface=lo domain-needed local=// +interface=virbr0 listen-address=192.168.122.1 listen-address=192.168.123.1 listen-address=2001:db8:ac10:fe01::1 diff --git a/tests/networkxml2argvdata/netboot-network.argv b/tests/networkxml2argvdata/netboot-network.argv index 4f5fedd..8405095 100644 --- a/tests/networkxml2argvdata/netboot-network.argv +++ b/tests/networkxml2argvdata/netboot-network.argv @@ -6,6 +6,7 @@ domain-needed local=/example.com/ domain=example.com expand-hosts +interface=virbr1 listen-address=192.168.122.1 dhcp-range=192.168.122.2,192.168.122.254 dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases diff --git a/tests/networkxml2argvdata/netboot-proxy-network.argv b/tests/networkxml2argvdata/netboot-proxy-network.argv index 8b9c03a..d7c8966 100644 --- a/tests/networkxml2argvdata/netboot-proxy-network.argv +++ b/tests/networkxml2argvdata/netboot-proxy-network.argv @@ -6,6 +6,7 @@ domain-needed local=/example.com/ domain=example.com expand-hosts +interface=virbr1 listen-address=192.168.122.1 dhcp-range=192.168.122.2,192.168.122.254 dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases diff --git a/tests/networkxml2argvdata/routed-network.argv b/tests/networkxml2argvdata/routed-network.argv index ad9e121..771240f 100644 --- a/tests/networkxml2argvdata/routed-network.argv +++ b/tests/networkxml2argvdata/routed-network.argv @@ -4,5 +4,6 @@ bind-interfaces except-interface=lo domain-needed local=// +interface=virbr1 listen-address=192.168.122.1 addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts -- 1.7.11.7

This support includes IPv6 dhcp-range= and dhcp-host= for one IPv6 subnetwork on one interface. The parameter tests have been updated to add some new DHCPv6 tests. Three new tests (6 files) were added. The xml format html documentation has been updated to reflect support for IPv6 DHCP. This patch include a bugfix for ipv4flag and ipv6flag initialization. --- docs/formatnetwork.html.in | 108 ++++++- src/conf/network_conf.c | 100 ++++--- src/network/bridge_driver.c | 326 +++++++++++++-------- src/util/dnsmasq.c | 9 +- tests/networkxml2argvdata/dhcp6-network.argv | 16 + tests/networkxml2argvdata/dhcp6-network.xml | 16 + tests/networkxml2argvdata/isolated-network.argv | 2 +- tests/networkxml2argvdata/nat-network-dhcp6.argv | 19 ++ tests/networkxml2argvdata/nat-network-dhcp6.xml | 26 ++ .../nat-network-dns-srv-record-minimal.argv | 2 +- .../nat-network-dns-srv-record.argv | 2 +- .../nat-network-dns-txt-record.argv | 2 +- tests/networkxml2argvdata/nat-network.argv | 2 +- tests/networkxml2argvdata/netboot-network.argv | 8 +- .../networkxml2argvdata/netboot-proxy-network.argv | 4 +- .../routed-network-dhcphost.argv | 14 + .../routed-network-dhcphost.xml | 19 ++ tests/networkxml2argvtest.c | 3 + 18 files changed, 498 insertions(+), 180 deletions(-) create mode 100644 tests/networkxml2argvdata/dhcp6-network.argv create mode 100644 tests/networkxml2argvdata/dhcp6-network.xml create mode 100644 tests/networkxml2argvdata/nat-network-dhcp6.argv create mode 100644 tests/networkxml2argvdata/nat-network-dhcp6.xml create mode 100644 tests/networkxml2argvdata/routed-network-dhcphost.argv create mode 100644 tests/networkxml2argvdata/routed-network-dhcphost.xml diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 49206dd..b91672a 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -577,8 +577,10 @@ dotted-decimal format, or an IPv6 address in standard colon-separated hexadecimal format, that will be configured on the bridge - device associated with the virtual network. To the guests this - address will be their default route. For IPv4 addresses, the <code>netmask</code> + device associated with the virtual network. To the guests this IPv4 + address will be their IPv4 default route. For IPv6, the default route is + established via Router Advertisement. + For IPv4 addresses, the <code>netmask</code> attribute defines the significant bits of the network address, again specified in dotted-decimal format. For IPv6 addresses, and as an alternate method for IPv4 addresses, you can specify @@ -587,10 +589,13 @@ could also be given as <code>prefix='24'</code>. The <code>family</code> attribute is used to specify the type of address - 'ipv4' or 'ipv6'; if no <code>family</code> is given, 'ipv4' is assumed. A network can have more than - one of each family of address defined, but only a single address can have a - <code>dhcp</code> or <code>tftp</code> element. <span class="since">Since 0.3.0; + one of each family of address defined, but only a single IPv4 address can have a + <code>dhcp</code> or <code>tftp</code> element. <span class="since">Since 0.3.0 </span> IPv6, multiple addresses on a single network, <code>family</code>, and - <code>prefix</code> since 0.8.7</span> + <code>prefix</code>. <span class="since">Since 0.8.7</span> In addition + to the one IPv4 address which has a <code>dhcp</code> definition, one IPv6 + address can have a <code>dhcp</code> definition. + <span class="since"> Since 1.0.1</span> <dl> <dt><code>tftp</code></dt> <dd>Immediately within @@ -611,27 +616,46 @@ <code>dhcp</code> element is not supported for IPv6, and is only supported on a single IP address per network for IPv4. <span class="since">Since 0.3.0</span> + The <code>dhcp</code> element is now supported for IPv6. + Again, there is a restriction that only one IPv6 address definition + is able to have a <code>dhcp</code> element. + <span class="since">Since 1.0.1</span> <dl> <dt><code>range</code></dt> <dd>The <code>start</code> and <code>end</code> attributes on the <code>range</code> element specify the boundaries of a pool of - IPv4 addresses to be provided to DHCP clients. These two addresses + addresses to be provided to DHCP clients. These two addresses must lie within the scope of the network defined on the parent - <code>ip</code> element. <span class="since">Since 0.3.0</span> + <code>ip</code> element. There may be zero or more + <code>range</code> elements specified. + <span class="since">Since 0.3.0</span> + <code>Range</code> can be specified for one IPv4 address, + one IPv6 address, or both. <span class="since">Since 1.0.1</span> </dd> <dt><code>host</code></dt> <dd>Within the <code>dhcp</code> element there may be zero or more - <code>host</code> elements; these specify hosts which will be given + <code>host</code> elements. These specify hosts which will be given names and predefined IP addresses by the built-in DHCP server. Any - such element must specify the MAC address of the host to be assigned + such IPv4 element must specify the MAC address of the host to be assigned a given name (via the <code>mac</code> attribute), the IP to be assigned to that host (via the <code>ip</code> attribute), and the name to be given that host by the DHCP server (via the <code>name</code> attribute). <span class="since">Since 0.4.5</span> + Within the IPv6 <code>dhcp</code> element zero or more + <code>host</code> elements are now supported. The definition for + an IPv6 <code>host</code> element differs from that for IPv4: + there is no <code>mac</code> attribute since a MAC address has no + defined meaning in IPv6. Instead, the <code>name</code> attribute is + used to identify the host to be assigned the IPv6 address. For DHCPv6, + the name is the plain name of the client host sent by the + client to the server. Note that this method of assigning a + specific IP address can be used instead of the <code>mac</code> + attribute for IPv4. <span class="since">Since 1.0.1</span> </dd> <dt><code>bootp</code></dt> <dd>The optional <code>bootp</code> - element specifies BOOTP options to be provided by the DHCP server. + element specifies BOOTP options to be provided by the DHCP + server for IPv4 only. Two attributes are supported: <code>file</code> is mandatory and gives the file to be used for the boot image; <code>server</code> is optional and gives the address of the TFTP server from which the boot @@ -674,6 +698,29 @@ <ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" /> </network></pre> + + <p> + Below is a variation of the above example which adds an IPv6 + dhcp range definition. + </p> + + <pre> + <network> + <name>default6</name> + <bridge name="virbr0" /> + <forward mode="nat"/> + <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> + <ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" > + <dhcp> + <range start="2001:db8:ca2:2:1::10" end="2001:db8:ca2:2:1::ff" /> + </dhcp> + </ip> + </network></pre> + <h3><a name="examplesRoute">Routed network config</a></h3> <p> @@ -698,6 +745,29 @@ <ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" /> </network></pre> + <p> + Below is another IPv6 varition. Instead of a dhcp range being + specified, this example has a couple of IPv6 host definitions. + </p> + + <pre> + <network> + <name>local6</name> + <bridge name="virbr1" /> + <forward mode="route" dev="eth1"/> + <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> + <ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" > + <dhcp> + <host name="paul" ip="2001:db8:ca2:2:3::1" /> + <host name="bob" ip="2001:db8:ca2:2:3::2" /> + </dhcp> + </ip> + </network></pre> + <h3><a name="examplesPrivate">Isolated network config</a></h3> <p> @@ -720,6 +790,24 @@ <ip family="ipv6" address="2001:db8:ca2:3::1" prefix="64" /> </network></pre> + <h3><a name="examplesPrivate6">Isolated IPv6 network config</a></h3> + + <p> + This variation of an isolated network defines only IPv6. + </p> + + <pre> + <network> + <name>sixnet</name> + <bridge name="virbr6" /> + <ip family="ipv6" address="2001:db8:ca2:6::1" prefix="64" > + <dhcp> + <host name="peter" ip="2001:db8:ca2:6:6::1" /> + <host name="dariusz" ip="2001:db8:ca2:6:6::2" /> + </dhcp> + </ip> + </network></pre> + <h3><a name="examplesBridge">Using an existing host bridge</a></h3> <p> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 228951d..a56b2e6 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -633,6 +633,7 @@ cleanup: static int virNetworkDHCPHostDefParse(const char *networkName, + virNetworkIpDefPtr def, xmlNodePtr node, virNetworkDHCPHostDefPtr host, bool partialOkay) @@ -644,6 +645,13 @@ virNetworkDHCPHostDefParse(const char *networkName, mac = virXMLPropString(node, "mac"); if (mac != NULL) { + if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) { + virReportError(VIR_ERR_XML_ERROR, + _("Invalid to specify MAC address '%s' " + "in IPv6 network '%s'"), + mac, networkName); + goto cleanup; + } if (virMacAddrParse(mac, &addr) < 0) { virReportError(VIR_ERR_XML_ERROR, _("Cannot parse MAC address '%s' in network '%s'"), @@ -686,10 +694,19 @@ virNetworkDHCPHostDefParse(const char *networkName, networkName); } } else { + if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) { + if (!name) { + virReportError(VIR_ERR_XML_ERROR, + _("Static host definition in IPv6 network '%s' " + "must have name attribute"), + networkName); + goto cleanup; + } + } /* normal usage - you need at least one MAC address or one host name */ - if (!(mac || name)) { + else if (!(mac || name)) { virReportError(VIR_ERR_XML_ERROR, - _("Static host definition in network '%s' " + _("Static host definition in IPv4 network '%s' " "must have mac or name attribute"), networkName); goto cleanup; @@ -748,36 +765,39 @@ virNetworkDHCPDefParse(const char *networkName, virReportOOMError(); return -1; } - if (virNetworkDHCPHostDefParse(networkName, cur, + if (virNetworkDHCPHostDefParse(networkName, def, cur, &def->hosts[def->nhosts], false) < 0) { return -1; } def->nhosts++; - } else if (cur->type == XML_ELEMENT_NODE && - xmlStrEqual(cur->name, BAD_CAST "bootp")) { - char *file; - char *server; - virSocketAddr inaddr; - memset(&inaddr, 0, sizeof(inaddr)); - - if (!(file = virXMLPropString(cur, "file"))) { - cur = cur->next; - continue; - } - server = virXMLPropString(cur, "server"); + } else if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) { + /* the following only applies to IPv4 */ + if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST "bootp")) { + char *file; + char *server; + virSocketAddr inaddr; + memset(&inaddr, 0, sizeof(inaddr)); + + if (!(file = virXMLPropString(cur, "file"))) { + cur = cur->next; + continue; + } + server = virXMLPropString(cur, "server"); + + if (server && + virSocketAddrParse(&inaddr, server, AF_UNSPEC) < 0) { + VIR_FREE(file); + VIR_FREE(server); + return -1; + } - if (server && - virSocketAddrParse(&inaddr, server, AF_UNSPEC) < 0) { - VIR_FREE(file); + def->bootfile = file; + def->bootserver = inaddr; VIR_FREE(server); - return -1; } - - def->bootfile = file; - def->bootserver = inaddr; - VIR_FREE(server); } cur = cur->next; @@ -1139,6 +1159,20 @@ virNetworkIPParseXML(const char *networkName, } } + if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) { + /* parse IPv6-related info */ + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST "dhcp")) { + result = virNetworkDHCPDefParse(networkName, def, cur); + if (result) + goto error; + } + cur = cur->next; + } + } + result = 0; error: @@ -2347,11 +2381,9 @@ virNetworkIpDefByIndex(virNetworkDefPtr def, int parentIndex) /* first find which ip element's dhcp host list to work on */ if (parentIndex >= 0) { ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, parentIndex); - if (!(ipdef && - VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))) { + if (!(ipdef)) { virReportError(VIR_ERR_OPERATION_INVALID, _("couldn't update dhcp host entry - " - "no <ip family='ipv4'> " "element found at index %d in network '%s'"), parentIndex, def->name); } @@ -2364,17 +2396,17 @@ virNetworkIpDefByIndex(virNetworkDefPtr def, int parentIndex) for (ii = 0; (ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, ii)); ii++) { - if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET) && - (ipdef->nranges || ipdef->nhosts)) { + if (ipdef->nranges || ipdef->nhosts) break; - } } - if (!ipdef) + if (!ipdef) { ipdef = virNetworkDefGetIpByIndex(def, AF_INET, 0); + if (!ipdef) + ipdef = virNetworkDefGetIpByIndex(def, AF_INET6, 0); + } if (!ipdef) { virReportError(VIR_ERR_OPERATION_INVALID, _("couldn't update dhcp host entry - " - "no <ip family='ipv4'> " "element found in network '%s'"), def->name); } return ipdef; @@ -2404,7 +2436,7 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def, /* parse the xml into a virNetworkDHCPHostDef */ if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) { - if (virNetworkDHCPHostDefParse(def->name, ctxt->node, &host, false) < 0) + if (virNetworkDHCPHostDefParse(def->name, ipdef, ctxt->node, &host, false) < 0) goto cleanup; /* search for the entry with this (mac|name), @@ -2437,7 +2469,7 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def, } else if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) || (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) { - if (virNetworkDHCPHostDefParse(def->name, ctxt->node, &host, true) < 0) + if (virNetworkDHCPHostDefParse(def->name, ipdef, ctxt->node, &host, true) < 0) goto cleanup; /* log error if an entry with same name/address/ip already exists */ @@ -2483,7 +2515,7 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def, } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) { - if (virNetworkDHCPHostDefParse(def->name, ctxt->node, &host, false) < 0) + if (virNetworkDHCPHostDefParse(def->name, ipdef, ctxt->node, &host, false) < 0) goto cleanup; /* find matching entry - all specified attributes must match */ diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 236d8f8..0c4c794 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -598,20 +598,32 @@ cleanup: return ret; } + /* the following does not build a file, it builds a list + * which is later saved into a file + */ + static int -networkBuildDnsmasqHostsfile(dnsmasqContext *dctx, - virNetworkIpDefPtr ipdef, - virNetworkDNSDefPtr dnsdef) +networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx, + virNetworkIpDefPtr ipdef) { - unsigned int i, j; + unsigned int i; for (i = 0; i < ipdef->nhosts; i++) { virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]); - if ((host->mac) && VIR_SOCKET_ADDR_VALID(&host->ip)) + if (VIR_SOCKET_ADDR_VALID(&host->ip)) if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip, host->name) < 0) return -1; } + return 0; +} + +static int +networkBuildDnsmasqHostsList(dnsmasqContext *dctx, + virNetworkDNSDefPtr dnsdef) +{ + unsigned int i, j; + if (dnsdef) { for (i = 0; i < dnsdef->nhosts; i++) { virNetworkDNSHostsDefPtr host = &(dnsdef->hosts[i]); @@ -629,7 +641,6 @@ networkBuildDnsmasqHostsfile(dnsmasqContext *dctx, /* build the dnsmasq conf file contents */ static int networkDnsmasqConfContents(virNetworkObjPtr network, - virNetworkIpDefPtr ipdef, const char *pidfile, char **configstr, dnsmasqContext *dctx) @@ -642,7 +653,8 @@ networkDnsmasqConfContents(virNetworkObjPtr network, char *recordPort = NULL; char *recordWeight = NULL; char *recordPriority = NULL; - virNetworkIpDefPtr tmpipdef; + virNetworkIpDefPtr tmpipdef, ipdef, ipv4def, ipv6def; + bool dhcp4flag, dhcp6flag; *configstr = NULL; @@ -674,7 +686,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network, "local=/%s/\n", network->def->domain ? network->def->domain : ""); if (network->def->domain) - virBufferAsprintf(&configbuf, + virBufferAsprintf(&configbuf, "domain=%s\n" "expand-hosts\n", network->def->domain); @@ -764,7 +776,34 @@ networkDnsmasqConfContents(virNetworkObjPtr network, VIR_FREE(ipaddr); } - if (ipdef) { + /* Find the first dhcp for both IPv4 and IPv6 */ + for (ii = 0, ipv4def = NULL, ipv6def = NULL, dhcp4flag = false, dhcp6flag = false; + (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii)); + ii++) { + if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) { + if (ipdef->nranges || ipdef->nhosts) { + if (!ipv4def) { + ipv4def = ipdef; + dhcp4flag = true; + } + } + } + if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) { + if (ipdef->nranges || ipdef->nhosts) { + if (!ipv6def) { + ipv6def = ipdef; + dhcp6flag = true; + } + } + } + } + + if (ipv4def) + ipdef = ipv4def; + else + ipdef = ipv6def; + + while (ipdef) { for (r = 0 ; r < ipdef->nranges ; r++) { char *saddr = virSocketAddrFormat(&ipdef->ranges[r].start); if (!saddr) @@ -785,7 +824,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network, /* * For static-only DHCP, i.e. with no range but at least one host element, * we have to add a special --dhcp-range option to enable the service in - * dnsmasq. + * dnsmasq. [this is for dhcp-hosts= support] */ if (!ipdef->nranges && ipdef->nhosts) { char *bridgeaddr = virSocketAddrFormat(&ipdef->address); @@ -795,53 +834,65 @@ networkDnsmasqConfContents(virNetworkObjPtr network, VIR_FREE(bridgeaddr); } - if (ipdef->nranges > 0) { - char *leasefile = networkDnsmasqLeaseFileName(network->def->name); - if (!leasefile) - goto cleanup; - virBufferAsprintf(&configbuf, "dhcp-leasefile=%s\n", leasefile); - VIR_FREE(leasefile); - virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases); - } - - if (ipdef->nranges || ipdef->nhosts) - virBufferAsprintf(&configbuf, "dhcp-no-override\n"); - - if (networkBuildDnsmasqHostsfile(dctx, ipdef, network->def->dns) < 0) + if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0) goto cleanup; - /* Even if there are currently no static hosts, if we're - * listening for DHCP, we should write a 0-length hosts - * file to allow for runtime additions. - */ - if (ipdef->nranges || ipdef->nhosts) - virBufferAsprintf(&configbuf, "dhcp-hostsfile=%s\n", - dctx->hostsfile->path); + /* Note: the following is IPv4 only */ + if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) { + if (ipdef->nranges || ipdef->nhosts) + virBufferAsprintf(&configbuf, "dhcp-no-override\n"); - /* Likewise, always create this file and put it on the commandline, to allow for - * for runtime additions. - */ - virBufferAsprintf(&configbuf, "addn-hosts=%s\n", - dctx->addnhostsfile->path); - - if (ipdef->tftproot) { - virBufferAsprintf(&configbuf, "enable-tftp\n"); - virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot); - } - if (ipdef->bootfile) { - if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) { - char *bootserver = virSocketAddrFormat(&ipdef->bootserver); + if (ipdef->tftproot) { + virBufferAsprintf(&configbuf, "enable-tftp\n"); + virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot); + } + if (ipdef->bootfile) { + if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) { + char *bootserver = virSocketAddrFormat(&ipdef->bootserver); - if (!bootserver) - goto cleanup; - virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n", - ipdef->bootfile, ",,", bootserver); - VIR_FREE(bootserver); - } else { - virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile); + if (!bootserver) + goto cleanup; + virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n", + ipdef->bootfile, ",,", bootserver); + VIR_FREE(bootserver); + } else { + virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile); + } } } + if (ipdef == ipv6def) + ipdef = NULL; + else + ipdef = ipv6def; } + + if (nbleases > 0) { + char *leasefile = networkDnsmasqLeaseFileName(network->def->name); + if (!leasefile) + goto cleanup; + virBufferAsprintf(&configbuf, "dhcp-leasefile=%s\n", leasefile); + VIR_FREE(leasefile); + virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases); + } + + /* this is done once per interface */ + if (networkBuildDnsmasqHostsList(dctx, network->def->dns) < 0) + goto cleanup; + + /* Even if there are currently no static hosts, if we're + * listening for DHCP, we should write a 0-length hosts + * file to allow for runtime additions. + */ + if (dhcp4flag || dhcp6flag) + virBufferAsprintf(&configbuf, "dhcp-hostsfile=%s\n", + dctx->hostsfile->path); + + /* Likewise, always create this file and put it on the commandline, to allow for + * for runtime additions. + */ + virBufferAsprintf(&configbuf, "addn-hosts=%s\n", + dctx->addnhostsfile->path); + if (!(*configstr = virBufferContentAndReset(&configbuf))) { virReportOOMError(); goto cleanup; @@ -865,25 +916,12 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdou int testOnly, char **testConfigStr) { virCommandPtr cmd = NULL; - int ret = -1, ii; - virNetworkIpDefPtr ipdef; + int ret = -1; char *configfile = NULL; char *configstr = NULL; network->dnsmasqPid = -1; - /* Look for first IPv4 address that has dhcp defined. */ - /* We support dhcp config on 1 IPv4 interface only. */ - for (ii = 0; - (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii)); - ii++) { - if (ipdef->nranges || ipdef->nhosts) - break; - } - /* If no IPv4 addresses had dhcp info, pick the first (if there were any). */ - if (!ipdef) - ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, 0); - /* If there are no IP addresses at all (v4 or v6), return now, since * there won't be any address for dnsmasq to listen on anyway. * If there are any addresses, even if no dhcp ranges or static entries, @@ -892,7 +930,7 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdou if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) return 0; - if (networkDnsmasqConfContents(network, ipdef, pidfile, &configstr, dctx) < 0) + if (networkDnsmasqConfContents(network, pidfile, &configstr, dctx) < 0) goto cleanup; if (!configstr) goto cleanup; @@ -915,7 +953,6 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdou configfile); goto cleanup; } - VIR_INFO("dnsmasq conf file %s written", configfile); cmd = virCommandNew(DNSMASQ); virCommandAddArgFormat(cmd, "--conf-file=%s", configfile); @@ -939,14 +976,13 @@ networkStartDhcpDaemon(virNetworkObjPtr network) char *testconfigstr = NULL; int ret = -1; dnsmasqContext *dctx = NULL; - virNetworkIpDefPtr ipdef; - int i; if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) { /* no IPv6 addresses, so we don't need to run radvd */ ret = 0; goto cleanup; } + VIR_INFO("starting dhcp daemon (dnsmasq)"); if (virFileMakePath(NETWORK_PID_DIR) < 0) { virReportSystemError(errno, @@ -982,18 +1018,6 @@ networkStartDhcpDaemon(virNetworkObjPtr network) if (ret < 0) goto cleanup; - /* populate dnsmasq hosts file */ - for (i = 0; (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i)); i++) { - if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET) && - (ipdef->nranges || ipdef->nhosts)) { - if (networkBuildDnsmasqHostsfile(dctx, ipdef, - network->def->dns) < 0) - goto cleanup; - - break; - } - } - ret = dnsmasqSave(dctx); if (ret < 0) goto cleanup; @@ -1037,31 +1061,35 @@ networkRefreshDhcpDaemon(virNetworkObjPtr network) virNetworkIpDefPtr ipdef; dnsmasqContext *dctx = NULL; + /* if no IP addresses specified, nothing to do */ + if (virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) + return 0; + /* if there's no running dnsmasq, just start it */ if (network->dnsmasqPid <= 0 || (kill(network->dnsmasqPid, 0) < 0)) return networkStartDhcpDaemon(network); - /* Look for first IPv4 address that has dhcp defined. */ - /* We support dhcp config on 1 IPv4 interface only. */ + VIR_INFO("REFRESH: DhcpDaemon: for %s", network->def->bridge); + if (!(dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR))) + goto cleanup; + + /* Look for first IPv4 address that has dhcp defined. + * We only support dhcp-host config on 1 IPv4 interface. + */ for (ii = 0; (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii)); ii++) { if (ipdef->nranges || ipdef->nhosts) break; } - /* If no IPv4 addresses had dhcp info, pick the first (if there were any). */ if (!ipdef) ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, 0); - if (!ipdef) { - /* no <ip> elements, so nothing to do */ - return 0; - } - - if (!(dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR))) - goto cleanup; + if (ipdef) + if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0) + goto cleanup; - if (networkBuildDnsmasqHostsfile(dctx, ipdef, network->def->dns) < 0) + if (networkBuildDnsmasqHostsList(dctx, network->def->dns) < 0) goto cleanup; if ((ret = dnsmasqSave(dctx)) < 0) @@ -1093,6 +1121,12 @@ networkRestartDhcpDaemon(virNetworkObjPtr network) return networkStartDhcpDaemon(network); } +static char radvd1[] = " AdvOtherConfigFlag off;\n\n"; +static char radvd2[] = " AdvAutonomous off;\n"; +static char radvd3[] = " AdvOnLink on;\n" + " AdvAutonomous on;\n" + " AdvRouterAddr off;\n"; + static int networkRadvdConfContents(virNetworkObjPtr network, char **configstr) { @@ -1100,20 +1134,42 @@ networkRadvdConfContents(virNetworkObjPtr network, char **configstr) int ret = -1, ii; virNetworkIpDefPtr ipdef; bool v6present = false; + bool dhcp6 = false; *configstr = NULL; + /* stateful/stateless is done on an interface basis; + * go through the list to see if any subnets have dhcp + */ + for (ii = 0; + (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, ii)); + ii++) { + + v6present = true; + if (ipdef->nranges > 0) { + dhcp6 = true; + break; + } + } + + /* If there are no IPv6 addresses, then we are done */ + if (!v6present) { + ret = 0; + goto cleanup; + } + /* create radvd config file appropriate for this network; * IgnoreIfMissing allows radvd to start even when the bridge is down */ virBufferAsprintf(&configbuf, "interface %s\n" "{\n" " AdvSendAdvert on;\n" - " AdvManagedFlag off;\n" - " AdvOtherConfigFlag off;\n" " IgnoreIfMissing on;\n" - "\n", - network->def->bridge); + " AdvManagedFlag %s;\n" + "%s", + network->def->bridge, + dhcp6 ? "on" : "off", + dhcp6 ? "\n" : radvd1); /* add a section for each IPv6 address in the config */ for (ii = 0; @@ -1122,7 +1178,6 @@ networkRadvdConfContents(virNetworkObjPtr network, char **configstr) int prefix; char *netaddr; - v6present = true; prefix = virNetworkIpDefPrefix(ipdef); if (prefix < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -1134,27 +1189,21 @@ networkRadvdConfContents(virNetworkObjPtr network, char **configstr) goto cleanup; virBufferAsprintf(&configbuf, " prefix %s/%d\n" - " {\n" - " AdvOnLink on;\n" - " AdvAutonomous on;\n" - " AdvRouterAddr off;\n" - " };\n", - netaddr, prefix); + " {\n%s };\n", + netaddr, prefix, + dhcp6 ? radvd2 : radvd3); VIR_FREE(netaddr); } - /* only create the string if we found at least one IPv6 address */ - if (v6present) { - virBufferAddLit(&configbuf, "};\n"); + virBufferAddLit(&configbuf, "};\n"); - if (virBufferError(&configbuf)) { - virReportOOMError(); - goto cleanup; - } - if (!(*configstr = virBufferContentAndReset(&configbuf))) { - virReportOOMError(); - goto cleanup; - } + if (virBufferError(&configbuf)) { + virReportOOMError(); + goto cleanup; + } + if (!(*configstr = virBufferContentAndReset(&configbuf))) { + virReportOOMError(); + goto cleanup; } ret = 0; @@ -1664,9 +1713,19 @@ networkAddGeneralIp6tablesRules(struct network_driver *driver, goto err5; } + if (iptablesAddUdpInput(driver->iptables, AF_INET6, + network->def->bridge, 547) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("failed to add ip6tables rule to allow DHCP6 requests from '%s'"), + network->def->bridge); + goto err6; + } + return 0; /* unwind in reverse order from the point of failure */ +err6: + iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge, 53); err5: iptablesRemoveTcpInput(driver->iptables, AF_INET6, network->def->bridge, 53); err4: @@ -1686,6 +1745,7 @@ networkRemoveGeneralIp6tablesRules(struct network_driver *driver, if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) return; + iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge, 547); iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge, 53); iptablesRemoveTcpInput(driver->iptables, AF_INET6, network->def->bridge, 53); iptablesRemoveForwardAllowCross(driver->iptables, AF_INET6, network->def->bridge); @@ -2732,8 +2792,7 @@ networkValidate(struct network_driver *driver, bool vlanUsed, vlanAllowed, badVlanUse = false; virPortGroupDefPtr defaultPortGroup = NULL; virNetworkIpDefPtr ipdef; - bool ipv4def = false; - int i; + bool ipv4def = false, ipv6def = false; /* check for duplicate networks */ if (virNetworkObjIsDuplicate(&driver->networks, def, check_active) < 0) @@ -2752,17 +2811,36 @@ networkValidate(struct network_driver *driver, virNetworkSetBridgeMacAddr(def); } - /* We only support dhcp on one IPv4 address per defined network */ - for (i = 0; (ipdef = virNetworkDefGetIpByIndex(def, AF_INET, i)); i++) { - if (ipdef->nranges || ipdef->nhosts) { - if (ipv4def) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Multiple dhcp sections found. " + /* We only support dhcp on one IPv4 address and + * on one IPv6 address per defined network + */ + for (ii = 0; + (ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, ii)); + ii++) { + if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) { + if (ipdef->nranges || ipdef->nhosts) { + if (ipv4def) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Multiple IPv4 dhcp sections found -- " "dhcp is supported only for a " "single IPv4 address on each network")); - return -1; - } else { - ipv4def = true; + return -1; + } else { + ipv4def = true; + } + } + } + if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) { + if (ipdef->nranges || ipdef->nhosts) { + if (ipv6def) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Multiple IPv6 dhcp sections found -- " + "dhcp is supported only for a " + "single IPv6 address on each network")); + return -1; + } else { + ipv6def = true; + } } } } diff --git a/src/util/dnsmasq.c b/src/util/dnsmasq.c index 9d1c07b..b0cf3ce 100644 --- a/src/util/dnsmasq.c +++ b/src/util/dnsmasq.c @@ -304,7 +304,14 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile, if (!(ipstr = virSocketAddrFormat(ip))) return -1; - if (name) { + /* the first test determins if it is a dhcpv6 host */ + if (mac==NULL) { + if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,[%s]", + name, ipstr) < 0) { + goto alloc_error; + } + } + else if (name) { if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s", mac, ipstr, name) < 0) { goto alloc_error; diff --git a/tests/networkxml2argvdata/dhcp6-network.argv b/tests/networkxml2argvdata/dhcp6-network.argv new file mode 100644 index 0000000..6697833 --- /dev/null +++ b/tests/networkxml2argvdata/dhcp6-network.argv @@ -0,0 +1,16 @@ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=/mynet/ +domain=mynet +expand-hosts +interface=virbr0 +listen-address=2001:db8:ac10:fe01::1 +listen-address=2001:db8:ac10:fd01::1 +dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=240 +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/dhcp6-network.xml b/tests/networkxml2argvdata/dhcp6-network.xml new file mode 100644 index 0000000..990b403 --- /dev/null +++ b/tests/networkxml2argvdata/dhcp6-network.xml @@ -0,0 +1,16 @@ +<network> + <name>default</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward dev='eth1' mode='nat'/> + <bridge name='virbr0' stp='on' delay='0' /> + <domain name='mynet'/> + <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'> + </ip> + <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'> + <dhcp> + <range start='2001:db8:ac10:fd01::1:10' end='2001:db8:ac10:fd01::1:ff' /> + <host name='ralph' ip='2001:db8:ac10:fd01::1:20' /> + <host name='paul' ip='2001:db8:ac10:fd01::1:21' /> + </dhcp> + </ip> +</network> diff --git a/tests/networkxml2argvdata/isolated-network.argv b/tests/networkxml2argvdata/isolated-network.argv index abcde93..3a67cb4 100644 --- a/tests/networkxml2argvdata/isolated-network.argv +++ b/tests/networkxml2argvdata/isolated-network.argv @@ -9,8 +9,8 @@ no-resolv interface=virbr2 listen-address=192.168.152.1 dhcp-range=192.168.152.2,192.168.152.254 +dhcp-no-override dhcp-leasefile=/var/lib/libvirt/dnsmasq/private.leases dhcp-lease-max=253 -dhcp-no-override dhcp-hostsfile=/var/lib/libvirt/dnsmasq/private.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/private.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dhcp6.argv b/tests/networkxml2argvdata/nat-network-dhcp6.argv new file mode 100644 index 0000000..14256ae --- /dev/null +++ b/tests/networkxml2argvdata/nat-network-dhcp6.argv @@ -0,0 +1,19 @@ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +interface=virbr0 +listen-address=192.168.122.1 +listen-address=192.168.123.1 +listen-address=2001:db8:ac10:fe01::1 +listen-address=2001:db8:ac10:fd01::1 +listen-address=10.24.10.1 +dhcp-range=192.168.122.2,192.168.122.254 +dhcp-no-override +dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=493 +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dhcp6.xml b/tests/networkxml2argvdata/nat-network-dhcp6.xml new file mode 100644 index 0000000..f993a26 --- /dev/null +++ b/tests/networkxml2argvdata/nat-network-dhcp6.xml @@ -0,0 +1,26 @@ +<network> + <name>default</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward dev='eth1' mode='nat'/> + <bridge name='virbr0' stp='on' delay='0' /> + <ip address='192.168.122.1' netmask='255.255.255.0'> + <dhcp> + <range start='192.168.122.2' end='192.168.122.254' /> + <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10' /> + <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11' /> + </dhcp> + </ip> + <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'> + </ip> + <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'> + </ip> + <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'> + <dhcp> + <range start='2001:db8:ac10:fd01::1:10' end='2001:db8:ac10:fd01::1:ff' /> + <host name='ralph' ip='2001:db8:ac10:fd01::1:20' /> + <host name='paul' ip='2001:db8:ac10:fd01::1:21' /> + </dhcp> + </ip> + <ip family='ipv4' address='10.24.10.1'> + </ip> +</network> diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv index d87d438..45a658b 100644 --- a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv @@ -12,8 +12,8 @@ listen-address=2001:db8:ac10:fe01::1 listen-address=2001:db8:ac10:fd01::1 listen-address=10.24.10.1 dhcp-range=192.168.122.2,192.168.122.254 +dhcp-no-override dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases dhcp-lease-max=253 -dhcp-no-override dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv index 53882fe..13e80b9 100644 --- a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv @@ -12,8 +12,8 @@ listen-address=2001:db8:ac10:fe01::1 listen-address=2001:db8:ac10:fd01::1 listen-address=10.24.10.1 dhcp-range=192.168.122.2,192.168.122.254 +dhcp-no-override dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases dhcp-lease-max=253 -dhcp-no-override dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv index cc3ed28..7277132 100644 --- a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv +++ b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv @@ -12,8 +12,8 @@ listen-address=2001:db8:ac10:fe01::1 listen-address=2001:db8:ac10:fd01::1 listen-address=10.24.10.1 dhcp-range=192.168.122.2,192.168.122.254 +dhcp-no-override dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases dhcp-lease-max=253 -dhcp-no-override dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/nat-network.argv b/tests/networkxml2argvdata/nat-network.argv index 431fffb..6e0161b 100644 --- a/tests/networkxml2argvdata/nat-network.argv +++ b/tests/networkxml2argvdata/nat-network.argv @@ -11,8 +11,8 @@ listen-address=2001:db8:ac10:fe01::1 listen-address=2001:db8:ac10:fd01::1 listen-address=10.24.10.1 dhcp-range=192.168.122.2,192.168.122.254 +dhcp-no-override dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases dhcp-lease-max=253 -dhcp-no-override dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts diff --git a/tests/networkxml2argvdata/netboot-network.argv b/tests/networkxml2argvdata/netboot-network.argv index 8405095..025903b 100644 --- a/tests/networkxml2argvdata/netboot-network.argv +++ b/tests/networkxml2argvdata/netboot-network.argv @@ -9,11 +9,11 @@ expand-hosts interface=virbr1 listen-address=192.168.122.1 dhcp-range=192.168.122.2,192.168.122.254 -dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases -dhcp-lease-max=253 dhcp-no-override -dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile -addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts enable-tftp tftp-root=/var/lib/tftproot dhcp-boot=pxeboot.img +dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases +dhcp-lease-max=253 +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts diff --git a/tests/networkxml2argvdata/netboot-proxy-network.argv b/tests/networkxml2argvdata/netboot-proxy-network.argv index d7c8966..8a1cb51 100644 --- a/tests/networkxml2argvdata/netboot-proxy-network.argv +++ b/tests/networkxml2argvdata/netboot-proxy-network.argv @@ -9,9 +9,9 @@ expand-hosts interface=virbr1 listen-address=192.168.122.1 dhcp-range=192.168.122.2,192.168.122.254 +dhcp-no-override +dhcp-boot=pxeboot.img,,10.20.30.40 dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases dhcp-lease-max=253 -dhcp-no-override dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts -dhcp-boot=pxeboot.img,,10.20.30.40 diff --git a/tests/networkxml2argvdata/routed-network-dhcphost.argv b/tests/networkxml2argvdata/routed-network-dhcphost.argv new file mode 100644 index 0000000..cf38381 --- /dev/null +++ b/tests/networkxml2argvdata/routed-network-dhcphost.argv @@ -0,0 +1,14 @@ +# dnsmasq conf file created by libvirt +strict-order +bind-interfaces +except-interface=lo +domain-needed +local=// +interface=virbr1 +listen-address=192.168.122.1 +listen-address=2001:db8:ac10:fd01::1 +dhcp-range=192.168.122.1,static +dhcp-no-override +dhcp-range=2001:db8:ac10:fd01::1,static +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/local.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts diff --git a/tests/networkxml2argvdata/routed-network-dhcphost.xml b/tests/networkxml2argvdata/routed-network-dhcphost.xml new file mode 100644 index 0000000..38d9ebf --- /dev/null +++ b/tests/networkxml2argvdata/routed-network-dhcphost.xml @@ -0,0 +1,19 @@ +<network> + <name>local</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> + <forward dev='eth1' mode='route'/> + <bridge name='virbr1' stp='on' delay='0' /> + <mac address='12:34:56:78:9A:BC'/> + <ip address='192.168.122.1' netmask='255.255.255.0'> + <dhcp> + <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10' /> + <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11' /> + </dhcp> + </ip> + <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'> + <dhcp> + <host name='ralph' ip='2001:db8:ac10:fd01::1:20' /> + <host name='paul' ip='2001:db8:ac10:fd01::1:21' /> + </dhcp> + </ip> +</network> diff --git a/tests/networkxml2argvtest.c b/tests/networkxml2argvtest.c index 3738734..ef32aa5 100644 --- a/tests/networkxml2argvtest.c +++ b/tests/networkxml2argvtest.c @@ -118,6 +118,9 @@ mymain(void) DO_TEST("nat-network-dns-srv-record"); DO_TEST("nat-network-dns-srv-record-minimal"); DO_TEST("nat-network-dns-hosts"); + DO_TEST("nat-network-dhcp6"); + DO_TEST("routed-network-dhcphost"); + DO_TEST("dhcp6-network"); return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.7.11.7

Use "dnsmasq --version" to obtain dnsmasq's version id and save the major/minor values. This is a separate patch since other patches will depend on it. --- src/conf/network_conf.h | 2 ++ src/network/bridge_driver.c | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 3e46304..cfc49af 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -218,6 +218,8 @@ struct _virNetworkObj { unsigned int active : 1; unsigned int autostart : 1; unsigned int persistent : 1; + unsigned int dnsmasqMajor; + unsigned int dnsmasqMinor; virNetworkDefPtr def; /* The current definition */ virNetworkDefPtr newDef; /* New definition to activate at shutdown */ diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 0c4c794..19610f2 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -968,21 +968,51 @@ cleanup: return ret; } +#define DNSMASQ_VERSION_PREFIX "Dnsmasq version " + static int networkStartDhcpDaemon(virNetworkObjPtr network) { virCommandPtr cmd = NULL; + const char *cmdname = DNSMASQ; + char *tmp, *version = NULL; + unsigned int major = 0, minor = 0; char *pidfile = NULL; char *testconfigstr = NULL; int ret = -1; dnsmasqContext *dctx = NULL; if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) { - /* no IPv6 addresses, so we don't need to run radvd */ + /* no IP addresses, so we don't need to run */ ret = 0; goto cleanup; } - VIR_INFO("starting dhcp daemon (dnsmasq)"); + + if (!virFileIsExecutable(cmdname)) { + VIR_WARN("file %s missing or not executable", cmdname); + goto cleanup; + } + VIR_INFO("starting dhcp daemon (%s)", cmdname); + + cmd = virCommandNew(cmdname); + virCommandAddArg(cmd, "--version"); + virCommandSetOutputBuffer(cmd, &version); + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; + virCommandFree(cmd); + cmd = NULL; + + if ((version!=NULL) && + (strncmp(version, DNSMASQ_VERSION_PREFIX, strlen(DNSMASQ_VERSION_PREFIX))==0)) { + tmp = version + strlen(DNSMASQ_VERSION_PREFIX); + if (virStrToLong_ui(tmp, &tmp, 10, &major) >= 0) { + if ((*tmp == '.') && + virStrToLong_ui(tmp + 1, &tmp, 10, &minor) >= 0) { + network->dnsmasqMajor = major; + network->dnsmasqMinor = minor; + } + } + } if (virFileMakePath(NETWORK_PID_DIR) < 0) { virReportSystemError(errno, @@ -1043,6 +1073,7 @@ networkStartDhcpDaemon(virNetworkObjPtr network) ret = 0; cleanup: VIR_FREE(pidfile); + VIR_FREE(version); virCommandFree(cmd); dnsmasqContextFree(dctx); return ret; -- 1.7.11.7

This patch tests the version of dnsmasq. If (major > 2) or ((major==2) and (minor >= 63)), then use dnsmasq. Otherwise, use radvd to provide the RA service. --- src/conf/network_conf.h | 1 + src/network/bridge_driver.c | 36 ++++++++++++++++++++++ tests/networkxml2argvdata/dhcp6-network.argv | 1 + tests/networkxml2argvdata/nat-network-dhcp6.argv | 1 + .../nat-network-dns-srv-record-minimal.argv | 1 + .../nat-network-dns-srv-record.argv | 1 + .../nat-network-dns-txt-record.argv | 1 + tests/networkxml2argvdata/nat-network.argv | 1 + .../routed-network-dhcphost.argv | 1 + tests/networkxml2argvtest.c | 1 + 10 files changed, 45 insertions(+) diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index cfc49af..39fffd7 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -220,6 +220,7 @@ struct _virNetworkObj { unsigned int persistent : 1; unsigned int dnsmasqMajor; unsigned int dnsmasqMinor; + unsigned int dnsmasqRA; virNetworkDefPtr def; /* The current definition */ virNetworkDefPtr newDef; /* New definition to activate at shutdown */ diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 19610f2..2230268 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -893,6 +893,26 @@ networkDnsmasqConfContents(virNetworkObjPtr network, virBufferAsprintf(&configbuf, "addn-hosts=%s\n", dctx->addnhostsfile->path); + /* we are doing RA instead of radvd */ + if (network->dnsmasqRA) { + if (dhcp6flag) + virBufferAsprintf(&configbuf, "enable-ra\n"); + else { + char *bridgeaddr = NULL; + ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, 0); + if (ipdef) { + bridgeaddr = virSocketAddrFormat(&ipdef->address); + if (bridgeaddr) { + virBufferAsprintf(&configbuf, + "dhcp-range=%s,ra-only\n", bridgeaddr); + } + } + if ((!ipdef) || (!bridgeaddr)) + VIR_WARN("IPv6 invalid configuration for %s", network->def->name); + VIR_FREE(bridgeaddr); + } + } + if (!(*configstr = virBufferContentAndReset(&configbuf))) { virReportOOMError(); goto cleanup; @@ -1014,6 +1034,12 @@ networkStartDhcpDaemon(virNetworkObjPtr network) } } + /* is radvd or dnsmasq to handle RA? */ + if ((network->dnsmasqMajor > 2) || + ((network->dnsmasqMajor == 2) && + (network->dnsmasqMinor >= 63))) + network->dnsmasqRA = 1; + if (virFileMakePath(NETWORK_PID_DIR) < 0) { virReportSystemError(errno, _("cannot create directory %s"), @@ -1293,6 +1319,12 @@ networkStartRadvd(virNetworkObjPtr network) virCommandPtr cmd = NULL; int ret = -1; + /* is dnsmasq handling RA */ + if (network->dnsmasqRA) { + ret = 0; + goto cleanup; + } + network->radvdPid = -1; if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) { @@ -1370,6 +1402,10 @@ cleanup: static int networkRefreshRadvd(virNetworkObjPtr network) { + /* is dnsmasq handling RA */ + if (network->dnsmasqRA) + return 0; + /* if there's no running radvd, just start it */ if (network->radvdPid <= 0 || (kill(network->radvdPid, 0) < 0)) return networkStartRadvd(network); diff --git a/tests/networkxml2argvdata/dhcp6-network.argv b/tests/networkxml2argvdata/dhcp6-network.argv index 6697833..66ec430 100644 --- a/tests/networkxml2argvdata/dhcp6-network.argv +++ b/tests/networkxml2argvdata/dhcp6-network.argv @@ -14,3 +14,4 @@ dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases dhcp-lease-max=240 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts +enable-ra diff --git a/tests/networkxml2argvdata/nat-network-dhcp6.argv b/tests/networkxml2argvdata/nat-network-dhcp6.argv index 14256ae..c56fff1 100644 --- a/tests/networkxml2argvdata/nat-network-dhcp6.argv +++ b/tests/networkxml2argvdata/nat-network-dhcp6.argv @@ -17,3 +17,4 @@ dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases dhcp-lease-max=493 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts +enable-ra diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv index 45a658b..26f283e 100644 --- a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv @@ -17,3 +17,4 @@ dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts +dhcp-range=2001:db8:ac10:fe01::1,ra-only diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv index 13e80b9..1840ae6 100644 --- a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv @@ -17,3 +17,4 @@ dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts +dhcp-range=2001:db8:ac10:fe01::1,ra-only diff --git a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv index 7277132..ecc79e7 100644 --- a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv +++ b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv @@ -17,3 +17,4 @@ dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts +dhcp-range=2001:db8:ac10:fe01::1,ra-only diff --git a/tests/networkxml2argvdata/nat-network.argv b/tests/networkxml2argvdata/nat-network.argv index 6e0161b..74d3c64 100644 --- a/tests/networkxml2argvdata/nat-network.argv +++ b/tests/networkxml2argvdata/nat-network.argv @@ -16,3 +16,4 @@ dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases dhcp-lease-max=253 dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts +dhcp-range=2001:db8:ac10:fe01::1,ra-only diff --git a/tests/networkxml2argvdata/routed-network-dhcphost.argv b/tests/networkxml2argvdata/routed-network-dhcphost.argv index cf38381..744b8f0 100644 --- a/tests/networkxml2argvdata/routed-network-dhcphost.argv +++ b/tests/networkxml2argvdata/routed-network-dhcphost.argv @@ -12,3 +12,4 @@ dhcp-no-override dhcp-range=2001:db8:ac10:fd01::1,static dhcp-hostsfile=/var/lib/libvirt/dnsmasq/local.hostsfile addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts +enable-ra diff --git a/tests/networkxml2argvtest.c b/tests/networkxml2argvtest.c index ef32aa5..413ba80 100644 --- a/tests/networkxml2argvtest.c +++ b/tests/networkxml2argvtest.c @@ -38,6 +38,7 @@ static int testCompareXMLToArgvFiles(const char *inxml, const char *outargv) { goto fail; obj->def = dev; + obj->dnsmasqRA = 1; dctx = dnsmasqContextNew(dev->name, "/var/lib/libvirt/dnsmasq"); if (dctx == NULL) -- 1.7.11.7

If dnsmasq version is => 2.64, then IPV6 dhcp-range and dhcp-host are proccessed/supported. Otherwise, error out with message that DHCPv6 range and host not supported by the installed dnsmasq version. --- src/network/bridge_driver.c | 15 ++++++++++++++- tests/networkxml2argvtest.c | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 2230268..a0c85b5 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -654,7 +654,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network, char *recordWeight = NULL; char *recordPriority = NULL; virNetworkIpDefPtr tmpipdef, ipdef, ipv4def, ipv6def; - bool dhcp4flag, dhcp6flag; + bool dhcp4flag, dhcp6flag, dhcp6_OK; *configstr = NULL; @@ -776,6 +776,13 @@ networkDnsmasqConfContents(virNetworkObjPtr network, VIR_FREE(ipaddr); } + /* check to is if dnsmasq version >= 2.64 so that DHCPv6 is OK */ + dhcp6_OK = false; + if (network->dnsmasqMajor > 2) + dhcp6_OK = true; + if ((network->dnsmasqMajor == 2) && (network->dnsmasqMinor > 63)) + dhcp6_OK = true; + /* Find the first dhcp for both IPv4 and IPv6 */ for (ii = 0, ipv4def = NULL, ipv6def = NULL, dhcp4flag = false, dhcp6flag = false; (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii)); @@ -790,6 +797,12 @@ networkDnsmasqConfContents(virNetworkObjPtr network, } if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) { if (ipdef->nranges || ipdef->nhosts) { + if (!dhcp6_OK) { + virReportError(VIR_ERR_XML_ERROR, + _("Invlaid to specify DHCPv6 range or host for dnsmasq version %u.%u"), + network->dnsmasqMajor, network->dnsmasqMinor); + goto cleanup; + } if (!ipv6def) { ipv6def = ipdef; dhcp6flag = true; diff --git a/tests/networkxml2argvtest.c b/tests/networkxml2argvtest.c index 413ba80..a64da65 100644 --- a/tests/networkxml2argvtest.c +++ b/tests/networkxml2argvtest.c @@ -38,6 +38,8 @@ static int testCompareXMLToArgvFiles(const char *inxml, const char *outargv) { goto fail; obj->def = dev; + obj->dnsmasqMajor = 2; + obj->dnsmasqMinor = 64; obj->dnsmasqRA = 1; dctx = dnsmasqContextNew(dev->name, "/var/lib/libvirt/dnsmasq"); -- 1.7.11.7
participants (3)
-
Gene Czarcinski
-
Guido Günther
-
Laine Stump