[libvirt] [PATCH v2 5/5] Network: Add support for DNS hosts definition to the network XML

Michal Novotny minovotn at redhat.com
Fri Apr 1 10:45:56 UTC 2011


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

Signed-off-by: Michal Novotny <minovotn at redhat.com>
---
 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>
+                    </oneOrMore>
+                  </element>
+                </zeroOrMore>
               </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,
+                              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")) {
+              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);
+                  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"));
+                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) {
+            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);
         }
+
         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;
+} 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,
         goto cleanup;
     }
 
-    if (! force && virFileExists(dctx->hostsfile->path))
-        return 0;
+    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 (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);
             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);
 }
-- 
1.7.3.2




More information about the libvir-list mailing list