On 04/01/2011 06:45 AM, Michal Novotny wrote:
Make: passed Make check: passed Make syntax-check: passed Hi, this is the patch to add support for DNS hosts definition in the network XML description to generate the the hosts file. This patch uses the addnhosts* APIs implemented to the src/util/dnsmasq.c by part 2 of this patch series. Also, tests for the XML to XML definition and command-line regression tests has been added. Michal
Same comments about the commit message - remove the testing comments, salutation, signature; add in a short example of the XML.
Signed-off-by: Michal Novotny<minovotn@xxxxxxxxxx> --- docs/formatnetwork.html.in | 7 + docs/schemas/network.rng | 8 ++ src/conf/network_conf.c | 128 ++++++++++++++++++-- src/conf/network_conf.h | 9 ++ src/network/bridge_driver.c | 20 ++- .../networkxml2argvdata/nat-network-dns-hosts.argv | 1 + .../networkxml2argvdata/nat-network-dns-hosts.xml | 19 +++ tests/networkxml2argvtest.c | 1 + tests/networkxml2xmlin/nat-network-dns-hosts.xml | 27 ++++ tests/networkxml2xmlout/nat-network-dns-hosts.xml | 27 ++++ tests/networkxml2xmltest.c | 1 + 11 files changed, 234 insertions(+), 14 deletions(-) create mode 100644 tests/networkxml2argvdata/nat-network-dns-hosts.argv create mode 100644 tests/networkxml2argvdata/nat-network-dns-hosts.xml create mode 100644 tests/networkxml2xmlin/nat-network-dns-hosts.xml create mode 100644 tests/networkxml2xmlout/nat-network-dns-hosts.xml diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 5211ed2..5d18ed9 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -222,6 +222,13 @@ separated by commas. <span class="since">Since 0.9.1</span> </dd> +<dt><code>host</code></dt> +<dd>The<code>host</code> element is the definition of DNS hosts to be passed + to the DNS service. The IP address is identified by the<code>ip</code> attribute + and the names for the IP addresses are identified in the<code>hostname</code> + subelements of the<code>host</code> element. +<span class="since">Since 0.9.1</span> +</dd> </dl> <h2><a name="examples">Example configuration</a></h2> diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng index e27dace..05066a5 100644 --- a/docs/schemas/network.rng +++ b/docs/schemas/network.rng @@ -146,6 +146,14 @@ <attribute name="value"><text/></attribute> </element> </zeroOrMore> +<zeroOrMore> +<element name="host"> +<attribute name="ip"><ref name="ipv4-addr"/></attribute> +<oneOrMore> +<element name="hostname"><text/></element>
I think it would be better to simply call it "name" rather than "hostname" (since "host" is already implied by its parent being "<host>")
+</oneOrMore> +</element> +</zeroOrMore>
Also, this will move up a level along with the rest of <dns>.
</element> </optional> </element> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index b7427d0..1f88649 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -435,6 +435,53 @@ virNetworkDHCPRangeDefParseXML(const char *networkName, } static int +virNetworkDNSHostsDefParseXML(virNetworkIpDefPtr def,
(will be virNetworkDefPtr def...)
+ xmlNodePtr node, + virSocketAddr ip) +{ + xmlNodePtr cur; + int result = -1; + + if (def->dns->hosts == NULL) { + if (VIR_ALLOC(def->dns->hosts)< 0) + goto oom_error; + def->dns->nhosts = 0; + } + + cur = node->children; + while (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE&& + xmlStrEqual(cur->name, BAD_CAST "hostname")) {
Again, s/hostname/name/
+ if (cur->children != NULL) { + char *hostname; + + hostname = strdup((char *)cur->children->content); + + if (VIR_REALLOC_N(def->dns->hosts, def->dns->nhosts + 1)< 0) { + VIR_FREE(hostname); + result = -1; + goto oom_error; + } + + def->dns->hosts[def->dns->nhosts].name = strdup(hostname);
Rather than strduping hostname, then freeing it, just assign the original directly into the struct.
+ def->dns->hosts[def->dns->nhosts].ip = ip; + def->dns->nhosts++; + + VIR_FREE(hostname); + } + } + + cur = cur->next; + } + + return 0; + +oom_error: + virReportOOMError(); + return result; +} + +static int virNetworkDNSDefParseXML(virNetworkIpDefPtr def, xmlNodePtr node) { @@ -476,6 +523,27 @@ virNetworkDNSDefParseXML(virNetworkIpDefPtr def, VIR_FREE(name); VIR_FREE(value); + } else if (cur->type == XML_ELEMENT_NODE&& + xmlStrEqual(cur->name, BAD_CAST "host")) { + char *ip; + virSocketAddr inaddr; + memset(&inaddr, 0, sizeof(inaddr)); + + if (!(ip = virXMLPropString(cur, "ip"))) { + cur = cur->next; + continue; + } + if ((ip == NULL) || + (virSocketParseAddr(ip,&inaddr, AF_UNSPEC)< 0)) { + virNetworkReportError(VIR_ERR_XML_DETAIL, + _("Missing IP address in DNS host definition"));
"Missing/incorrect". Also, since def will end up being virNetworkDefPtr, you can add the name of the network, as well as the string that was given for ip. That will help in finding the source of the error.
+ VIR_FREE(ip); + goto error; + } + VIR_FREE(ip); + result = virNetworkDNSHostsDefParseXML(def, cur, inaddr); + if (result) + goto error; } cur = cur->next; @@ -485,6 +553,7 @@ virNetworkDNSDefParseXML(virNetworkIpDefPtr def, oom_error: virReportOOMError(); +error: return result; } @@ -888,17 +957,60 @@ virNetworkIpDefFormat(virBufferPtr buf, virBufferAddLit(buf, "</dhcp>\n"); } - if ((def->dns != NULL)&& (def->dns->ntxtrecords)) { - int ii; - + if (def->dns != NULL) { virBufferAddLit(buf, "<dns>\n"); - for (ii = 0 ; ii< def->dns->ntxtrecords ; ii++) { - virBufferVSprintf(buf, "<txt-record name='%s' value='%s' />\n", - def->dns->txtrecords[ii].name, - def->dns->txtrecords[ii].value); + + if (def->dns->ntxtrecords) {
This if() should have been in the patch for <txt>. That way this patch wouldn't be polluted with diffs unrelated to the new feature introduced in this patch.
+ int ii; + + for (ii = 0 ; ii< def->dns->ntxtrecords; ii++) { + virBufferVSprintf(buf, "<txt-record name='%s' value='%s' />\n", + def->dns->txtrecords[ii].name, + def->dns->txtrecords[ii].value); + } + } + if (def->dns->nhosts) { + int ii, j; + char **iplist = NULL; + int iplist_size = 0; + bool in_list; + + if (VIR_ALLOC(iplist)< 0) + goto error; + + for (ii = 0 ; ii< def->dns->nhosts; ii++) { + char *ip = virSocketFormatAddr(&def->dns->hosts[ii].ip); + in_list = false; + for (j = 0; j< iplist_size; j++) + if (STREQ(iplist[j], ip)) + in_list = true; + + if (!in_list) { + virBufferVSprintf(buf, "<host ip='%s'>\n", ip); + + for (j = 0 ; j< def->dns->nhosts; j++) { + char *thisip = virSocketFormatAddr(&def->dns->hosts[j].ip); + if (STREQ(ip, thisip)) + virBufferVSprintf(buf, "<hostname>%s</hostname>\n", + def->dns->hosts[j].name); + } + virBufferVSprintf(buf, "</host>\n"); + + if (VIR_REALLOC_N(iplist, iplist_size + 1)< 0) + goto error; + + iplist[iplist_size] = strdup(ip); + iplist_size++; + } + } + + for (j = 0; j< iplist_size; j++) + VIR_FREE(iplist[j]); + VIR_FREE(iplist);
It would make more sense if virNetworkDNSHostsDef->name was char** and had an array of names, as you did in PATCH 4/5. That would make the object a more direct representation of the XML data, and eliminate all of this complicated code dealing with "iplist" and nested loops.
} + virBufferAddLit(buf, "</dns>\n"); - } + } virBufferAddLit(buf, "</ip>\n"); diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 5f47595..305ef0f 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -64,9 +64,18 @@ struct _virNetworkDNSTxtRecordsDef { char *value; }; +struct virNetworkDNSHostsDef { + virSocketAddr ip; + char *name;
Again - make name char** as you did in PATCH 4/5.
+} virNetworkDNSHostsDef; + +typedef struct virNetworkDNSHostsDef *virNetworkDNSHostsDefPtr; + struct virNetworkDNSDef { unsigned int ntxtrecords; + unsigned int nhosts; virNetworkDNSTxtRecordsDefPtr txtrecords; + virNetworkDNSHostsDefPtr hosts; } virNetworkDNSDef; typedef struct virNetworkDNSDef *virNetworkDNSDefPtr; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 4ad3143..99a61b0 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -434,13 +434,20 @@ networkSaveDnsmasqHostsfile(virNetworkIpDefPtr ipdef,
This function is going to also need a virNetworkDefPtr arg if dns moves up a level.
goto cleanup; } - if (! force&& virFileExists(dctx->hostsfile->path)) - return 0; + if (!(! force&& virFileExists(dctx->hostsfile->path))) {
That is much easier to understand if written as: if (force || !virFileExists(dctx->hostsfile->path)
+ for (i = 0; i< ipdef->nhosts; i++) { + virNetworkDHCPHostDefPtr host =&(ipdef->hosts[i]); + if ((host->mac)&& VIR_SOCKET_HAS_ADDR(&host->ip)) + dnsmasqAddDhcpHost(dctx, host->mac,&host->ip, host->name); + } + } - for (i = 0; i< ipdef->nhosts; i++) { - virNetworkDHCPHostDefPtr host =&(ipdef->hosts[i]); - if ((host->mac)&& VIR_SOCKET_HAS_ADDR(&host->ip)) - dnsmasqAddDhcpHost(dctx, host->mac,&host->ip, host->name); + if (ipdef->dns) { + for (i = 0; i< ipdef->dns->nhosts; i++) { + virNetworkDNSHostsDefPtr host =&(ipdef->dns->hosts[i]); + if (VIR_SOCKET_HAS_ADDR(&host->ip)) + dnsmasqAddHost(dctx,&host->ip, host->name);
If you change the virNetworkDNSHostDefPtr to contain char **name instead of char *name, and dnsmasqAddHost to accept char** rather than char*, this can remain pretty much unchanged.
+ } } if (dnsmasqSave(dctx)< 0) @@ -589,6 +596,7 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network, if (dctx->hostsfile->nhosts) virCommandAddArgPair(cmd, "--dhcp-hostsfile", dctx->hostsfile->path); + VIR_DEBUG("ADDN HOSTS: %d => %p", dctx->addnhostsfile->nhosts, ipdef->dns);
Did you mean to leave this DEBUG in?
if (dctx->addnhostsfile->nhosts) virCommandAddArgPair(cmd, "--addn-hosts", dctx->addnhostsfile->path); diff --git a/tests/networkxml2argvdata/nat-network-dns-hosts.argv b/tests/networkxml2argvdata/nat-network-dns-hosts.argv new file mode 100644 index 0000000..99dc724 --- /dev/null +++ b/tests/networkxml2argvdata/nat-network-dns-hosts.argv @@ -0,0 +1 @@ +/usr/sbin/dnsmasq --strict-order --bind-interfaces --pid-file=/var/run/libvirt/network/default.pid --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/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-hosts.xml b/tests/networkxml2argvdata/nat-network-dns-hosts.xml new file mode 100644 index 0000000..35ee151 --- /dev/null +++ b/tests/networkxml2argvdata/nat-network-dns-hosts.xml @@ -0,0 +1,19 @@ +<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> +<dns> +<host ip='192.168.122.1'> +<hostname>host</hostname> +<hostname>gateway</hostname> +</host> +</dns> +</ip> +</network> diff --git a/tests/networkxml2argvtest.c b/tests/networkxml2argvtest.c index e3a8bb4..ce09206 100644 --- a/tests/networkxml2argvtest.c +++ b/tests/networkxml2argvtest.c @@ -112,6 +112,7 @@ mymain(int argc, char **argv) DO_TEST("netboot-network"); DO_TEST("netboot-proxy-network"); DO_TEST("nat-network-dns-txt-record"); + DO_TEST("nat-network-dns-hosts"); return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); } diff --git a/tests/networkxml2xmlin/nat-network-dns-hosts.xml b/tests/networkxml2xmlin/nat-network-dns-hosts.xml new file mode 100644 index 0000000..fe545cf --- /dev/null +++ b/tests/networkxml2xmlin/nat-network-dns-hosts.xml @@ -0,0 +1,27 @@ +<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> +<dns> +<host ip='192.168.122.1'> +<hostname>host</hostname> +<hostname>gateway</hostname> +</host> +</dns> +</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'> +</ip> +<ip family='ipv4' address='10.24.10.1'> +</ip> +</network> diff --git a/tests/networkxml2xmlout/nat-network-dns-hosts.xml b/tests/networkxml2xmlout/nat-network-dns-hosts.xml new file mode 100644 index 0000000..fe545cf --- /dev/null +++ b/tests/networkxml2xmlout/nat-network-dns-hosts.xml @@ -0,0 +1,27 @@ +<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> +<dns> +<host ip='192.168.122.1'> +<hostname>host</hostname> +<hostname>gateway</hostname> +</host> +</dns> +</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'> +</ip> +<ip family='ipv4' address='10.24.10.1'> +</ip> +</network> diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c index beb00ef..f5c5715 100644 --- a/tests/networkxml2xmltest.c +++ b/tests/networkxml2xmltest.c @@ -91,6 +91,7 @@ mymain(int argc, char **argv) DO_TEST("netboot-network"); DO_TEST("netboot-proxy-network"); DO_TEST("nat-network-dns-txt-record"); + DO_TEST("nat-network-dns-hosts"); return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE); }
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list