]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Add TXT record support for virtual DNS service
authorMichal Novotny <minovotn@redhat.com>
Fri, 24 Jun 2011 10:04:36 +0000 (12:04 +0200)
committerLaine Stump <laine@laine.org>
Fri, 24 Jun 2011 20:15:12 +0000 (16:15 -0400)
This commit introduces the <dns> element and <txt> record for the
virtual DNS network. The DNS TXT record can be defined using following
syntax in the network XML file:

  <dns>
    <txt name="example" value="example value" />
  </dns>

Also, the Relax-NG scheme has been altered to allow the texts without
spaces only for the name element and some nitpicks about memory
free'ing have been fixed by Laine so therefore I'm adding Laine to the
SOB clause ;-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
Signed-off-by: Laine Stump <laine@laine.org>
docs/formatnetwork.html.in
docs/schemas/network.rng
src/conf/network_conf.c
src/conf/network_conf.h
src/network/bridge_driver.c
tests/networkxml2xmlin/nat-network-dns-txt-record.xml [new file with mode: 0644]
tests/networkxml2xmlout/nat-network-dns-txt-record.xml [new file with mode: 0644]
tests/networkxml2xmltest.c

index 589aaff20e033c960bfcdc7b1601c63e763bc1ad..4a5cb0347b8449d2c4c6f599751d9678325b90f8 100644 (file)
     <pre>
         ...
         &lt;mac address='00:16:3E:5D:C7:9E'/&gt;
+        &lt;dns&gt;
+          &lt;txt name="example" value="example value" /&gt;
+        &lt;/dns&gt;
         &lt;ip address="192.168.122.1" netmask="255.255.255.0"&gt;
           &lt;dhcp&gt;
             &lt;range start="192.168.122.100" end="192.168.122.254" /&gt;
         supported for IPv6 addresses, can only be specified on a single IPv4 address
         per network.
         <span class="since">Since 0.7.1</span>
-      </dd><dt><code>dhcp</code></dt><dd>Also within the <code>ip</code> element there is an
+      </dd>
+
+      <dt><code>dns</code></dt><dd>
+        The dns element of a network contains configuration information for the
+        virtual network's DNS server. <span class="since">Since 0.9.3</span>
+        Currently supported elements are:
+        <dl>
+          <dt><code>txt</code></dt>
+          <dd>A <code>dns</code> element can have 0 or more <code>txt</code> elements.
+            Each txt element defines a DNS TXT record and has two attributes, both
+            required: a name that can be queried via dns, and a value that will be
+            returned when that name is queried. names cannot contain embedded spaces
+            or commas. value is a single string that can contain multiple values
+            separated by commas. <span class="since">Since 0.9.3</span>
+          </dd>
+        </dl>
+      </dd>
+      <dt><code>dhcp</code></dt>
+      <dd>Also within the <code>ip</code> element there is an
         optional <code>dhcp</code> element. The presence of this element
         enables DHCP services on the virtual network. It will further
         contain one or more <code>range</code> elements. The
index 6d01b06082bc169970c44e9b4f3cabd8d2007077..c42382e4dbbf298eb78ff99ad1bdb11ed340a317 100644 (file)
           </element>
         </optional>
 
+        <!-- Define the DNS related elements like TXT records
+             and other features in the <dns> element -->
+        <optional>
+            <element name="dns">
+              <zeroOrMore>
+                <element name="txt">
+                  <attribute name="name"><ref name="dns-name"/></attribute>
+                  <attribute name="value"><text/></attribute>
+                </element>
+              </zeroOrMore>
+            </element>
+        </optional>
+
         <!-- <ip> element -->
         <zeroOrMore>
           <!-- The IP element sets up NAT'ing and an optional DHCP server
     </data>
   </define>
 
+  <!-- a valid DNS name -->
+  <define name='dns-name'>
+    <data type='string'>
+      <param name="pattern">([a-zA-Z\-]+)</param>
+    </data>
+  </define>
+
 </grammar>
index e4765ea48c9459c74ae28cf4bd3187750d44bea0..d8f1e25c2f82c9fdd2c4810ef4f06d5c1e41b946 100644 (file)
@@ -104,6 +104,20 @@ static void virNetworkIpDefClear(virNetworkIpDefPtr def)
     VIR_FREE(def->bootfile);
 }
 
+static void virNetworkDNSDefFree(virNetworkDNSDefPtr def)
+{
+    if (def) {
+        if (def->txtrecords) {
+            while (def->ntxtrecords--) {
+                VIR_FREE(def->txtrecords[def->ntxtrecords].name);
+                VIR_FREE(def->txtrecords[def->ntxtrecords].value);
+            }
+            VIR_FREE(def->txtrecords);
+        }
+        VIR_FREE(def);
+    }
+}
+
 void virNetworkDefFree(virNetworkDefPtr def)
 {
     int ii;
@@ -121,6 +135,8 @@ void virNetworkDefFree(virNetworkDefPtr def)
     }
     VIR_FREE(def->ips);
 
+    virNetworkDNSDefFree(def->dns);
+
     VIR_FREE(def);
 }
 
@@ -434,6 +450,69 @@ virNetworkDHCPRangeDefParseXML(const char *networkName,
     return 0;
 }
 
+static int
+virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef,
+                         xmlNodePtr node)
+{
+    xmlNodePtr cur;
+    int ret = -1;
+    char *name = NULL;
+    char *value = NULL;
+    virNetworkDNSDefPtr def = NULL;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        goto error;
+    }
+
+    cur = node->children;
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE &&
+            xmlStrEqual(cur->name, BAD_CAST "txt")) {
+            if (!(name = virXMLPropString(cur, "name"))) {
+                virNetworkReportError(VIR_ERR_XML_DETAIL,
+                                      "%s", _("Missing required name attribute in dns txt record"));
+                goto error;
+            }
+            if (!(value = virXMLPropString(cur, "value"))) {
+                virNetworkReportError(VIR_ERR_XML_DETAIL,
+                                      _("Missing required value attribute in dns txt record '%s'"), name);
+                goto error;
+            }
+
+            if (strchr(name, ' ') != NULL) {
+                virNetworkReportError(VIR_ERR_XML_DETAIL,
+                                      _("spaces are not allowed in DNS TXT record names (name is '%s')"), name);
+                goto error;
+            }
+
+            if (VIR_REALLOC_N(def->txtrecords, def->ntxtrecords + 1) < 0) {
+                virReportOOMError();
+                goto error;
+            }
+
+            def->txtrecords[def->ntxtrecords].name = name;
+            def->txtrecords[def->ntxtrecords].value = value;
+            def->ntxtrecords++;
+            name = NULL;
+            value = NULL;
+        }
+
+        cur = cur->next;
+    }
+
+    ret = 0;
+error:
+    if (ret < 0) {
+        VIR_FREE(name);
+        VIR_FREE(value);
+        virNetworkDNSDefFree(def);
+    } else {
+        *dnsdef = def;
+    }
+    return ret;
+}
+
 static int
 virNetworkIPParseXML(const char *networkName,
                      virNetworkIpDefPtr def,
@@ -584,6 +663,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
     virNetworkDefPtr def;
     char *tmp;
     xmlNodePtr *ipNodes = NULL;
+    xmlNodePtr dnsNode = NULL;
     int nIps;
 
     if (VIR_ALLOC(def) < 0) {
@@ -641,6 +721,12 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
         def->mac_specified = true;
     }
 
+    dnsNode = virXPathNode("./dns", ctxt);
+    if (dnsNode != NULL) {
+        if (virNetworkDNSDefParseXML(&def->dns, dnsNode) < 0)
+            goto error;
+    }
+
     nIps = virXPathNodeSet("./ip", ctxt, &ipNodes);
     if (nIps < 0)
         goto error;
@@ -750,6 +836,29 @@ cleanup:
     return def;
 }
 
+static int
+virNetworkDNSDefFormat(virBufferPtr buf,
+                       virNetworkDNSDefPtr def)
+{
+    int result = 0;
+    int i;
+
+    if (def == NULL)
+        goto out;
+
+    virBufferAddLit(buf, "  <dns>\n");
+
+    for (i = 0 ; i < def->ntxtrecords ; i++) {
+        virBufferAsprintf(buf, "    <txt name='%s' value='%s' />\n",
+                              def->txtrecords[i].name,
+                              def->txtrecords[i].value);
+    }
+
+    virBufferAddLit(buf, "  </dns>\n");
+out:
+    return result;
+}
+
 static int
 virNetworkIpDefFormat(virBufferPtr buf,
                       const virNetworkIpDefPtr def)
@@ -881,6 +990,9 @@ char *virNetworkDefFormat(const virNetworkDefPtr def)
     if (def->domain)
         virBufferAsprintf(&buf, "  <domain name='%s'/>\n", def->domain);
 
+    if (virNetworkDNSDefFormat(&buf, def->dns) < 0)
+        goto error;
+
     for (ii = 0; ii < def->nips; ii++) {
         if (virNetworkIpDefFormat(&buf, &def->ips[ii]) < 0)
             goto error;
index 281124bff64d04f6291ddc689e6fefbf341cbf1d..d0dac021967aa77dddc6d99b3bb3cfceb7993c30 100644 (file)
@@ -57,6 +57,20 @@ struct _virNetworkDHCPHostDef {
     virSocketAddr ip;
 };
 
+typedef struct _virNetworkDNSTxtRecordsDef virNetworkDNSTxtRecordsDef;
+typedef virNetworkDNSTxtRecordsDef *virNetworkDNSTxtRecordsDefPtr;
+struct _virNetworkDNSTxtRecordsDef {
+    char *name;
+    char *value;
+};
+
+struct virNetworkDNSDef {
+    unsigned int ntxtrecords;
+    virNetworkDNSTxtRecordsDefPtr txtrecords;
+} virNetworkDNSDef;
+
+typedef struct virNetworkDNSDef *virNetworkDNSDefPtr;
+
 typedef struct _virNetworkIpDef virNetworkIpDef;
 typedef virNetworkIpDef *virNetworkIpDefPtr;
 struct _virNetworkIpDef {
@@ -101,6 +115,8 @@ struct _virNetworkDef {
 
     size_t nips;
     virNetworkIpDefPtr ips; /* ptr to array of IP addresses on this network */
+
+    virNetworkDNSDefPtr dns; /* ptr to dns related configuration */
 };
 
 typedef struct _virNetworkObj virNetworkObj;
index 4b94959333b4b548e51a45dabfbeeb6f21e999e2..dc143dbe7706b277f3b45b0a6277f90b91ff66ed 100644 (file)
@@ -510,6 +510,24 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
     if (network->def->forwardType == VIR_NETWORK_FORWARD_NONE)
         virCommandAddArg(cmd, "--dhcp-option=3");
 
+    if (network->def->dns != NULL) {
+        virNetworkDNSDefPtr dns = network->def->dns;
+        int i;
+
+        for (i = 0; i < dns->ntxtrecords; i++) {
+            char *record = NULL;
+            if (virAsprintf(&record, "%s,%s",
+                            dns->txtrecords[i].name,
+                            dns->txtrecords[i].value) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            virCommandAddArgPair(cmd, "--txt-record", record);
+            VIR_FREE(record);
+        }
+    }
+
     /*
      * --interface does not actually work with dnsmasq < 2.47,
      * due to DAD for ipv6 addresses on the interface.
diff --git a/tests/networkxml2xmlin/nat-network-dns-txt-record.xml b/tests/networkxml2xmlin/nat-network-dns-txt-record.xml
new file mode 100644 (file)
index 0000000..bd16976
--- /dev/null
@@ -0,0 +1,24 @@
+<network>
+  <name>default</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <forward dev='eth1' mode='nat'/>
+  <bridge name='virbr0' stp='on' delay='0' />
+  <dns>
+    <txt name='example' value='example value' />
+  </dns>
+  <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'>
+  </ip>
+  <ip family='ipv4' address='10.24.10.1'>
+  </ip>
+</network>
diff --git a/tests/networkxml2xmlout/nat-network-dns-txt-record.xml b/tests/networkxml2xmlout/nat-network-dns-txt-record.xml
new file mode 100644 (file)
index 0000000..bd16976
--- /dev/null
@@ -0,0 +1,24 @@
+<network>
+  <name>default</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <forward dev='eth1' mode='nat'/>
+  <bridge name='virbr0' stp='on' delay='0' />
+  <dns>
+    <txt name='example' value='example value' />
+  </dns>
+  <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'>
+  </ip>
+  <ip family='ipv4' address='10.24.10.1'>
+  </ip>
+</network>
index 468785b7f1412259abaf2d6801f9722c77d76ce5..2cc8e560fea5cff72217c6087d4ca5a4416e5a88 100644 (file)
@@ -86,6 +86,7 @@ mymain(void)
     DO_TEST("nat-network");
     DO_TEST("netboot-network");
     DO_TEST("netboot-proxy-network");
+    DO_TEST("nat-network-dns-txt-record");
 
     return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
 }