]> xenbits.xensource.com Git - libvirt.git/commitdiff
use client id for IPv6 DHCP host definition
authorGene Czarcinski <gene@czarc.net>
Fri, 15 Feb 2013 19:02:26 +0000 (14:02 -0500)
committerLaine Stump <laine@laine.org>
Mon, 25 Feb 2013 07:49:06 +0000 (02:49 -0500)
Originally, only a host name was used to associate a
DHCPv6 request with a specific IPv6 address.  Further testing
demonstrates that this is an unreliable method and, instead,
a client-id or DUID needs to be used.  According to DHCPv6
standards, this id can be a duid-LLT, duid-LL, or duid-UUID
even though dnsmasq will accept almost any text string.

Although validity checking of a specified string makes sure it is
hexadecimal notation with bytes separated by colons, there is no
rigorous check to make sure it meets the standard.

Documentation and schemas have been updated.

Signed-off-by: Gene Czarcinski <gene@czarc.net>
Signed-off-by: Laine Stump <laine@laine.org>
14 files changed:
docs/formatnetwork.html.in
docs/schemas/basictypes.rng
docs/schemas/network.rng
src/conf/network_conf.c
src/conf/network_conf.h
src/network/bridge_driver.c
src/util/virdnsmasq.c
src/util/virdnsmasq.h
tests/networkxml2confdata/dhcp6-nat-network.xml
tests/networkxml2confdata/dhcp6-network.xml
tests/networkxml2confdata/dhcp6host-routed-network.xml
tests/networkxml2xmlin/dhcp6host-routed-network.xml [new file with mode: 0644]
tests/networkxml2xmlout/dhcp6host-routed-network.xml [new file with mode: 0644]
tests/networkxml2xmltest.c

index f7c483d39fd04481c0d19b0e763f059baca0e364..41a83fa9d14e39e53d4df1e33532551239760661 100644 (file)
     <p>
       Below is another IPv6 varition.  Instead of a dhcp range being
       specified, this example has a couple of IPv6 host definitions.
+      Note that most of the dhcp host definitions use an "id" (client
+      id or DUID) since this has proven to be a more reliable way
+      of specifying the interface and its association with an IPv6
+      address.  The first is a DUID-LLT, the second a DUID-LL, and
+      the third a DUID-UUID.  <span class="since">Since 1.0.3</span>
     </p>
 
     <pre>
         &lt;ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" &gt;
           &lt;dhcp&gt;
             &lt;host name="paul"   ip="2001:db8:ca2:2:3::1" /&gt;
-            &lt;host name="bob"    ip="2001:db8:ca2:2:3::2" /&gt;
+            &lt;host id="0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66"    ip="2001:db8:ca2:2:3::2" /&gt;
+            &lt;host id="0:3:0:1:0:16:3e:11:22:33" name="ralph"  ip="2001:db8:ca2:2:3::3" /&gt;
+            &lt;host id="0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63" name="badbob" ip="2001:db8:ca2:2:3::4" /&gt;
           &lt;/dhcp&gt;
         &lt;/ip&gt;
       &lt;/network&gt;</pre>
 
     <p>
       This variation of an isolated network defines only IPv6.
+      Note that most of the dhcp host definitions use an "id" (client
+      id or DUID) since this has proven to be a more reliable way
+      of specifying the interface and its association with an IPv6
+      address.  The first is a DUID-LLT, the second a DUID-LL, and
+      the third a DUID-UUID.  <span class="since">Since 1.0.3</span>
     </p>
 
     <pre>
         &lt;ip family="ipv6" address="2001:db8:ca2:6::1" prefix="64" &gt;
           &lt;dhcp&gt;
             &lt;host name="peter"   ip="2001:db8:ca2:6:6::1" /&gt;
-            &lt;host name="dariusz" ip="2001:db8:ca2:6:6::2" /&gt;
+            &lt;host id="0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66" ip="2001:db8:ca2:6:6::2" /&gt;
+            &lt;host id="0:3:0:1:0:16:3e:11:22:33" name="dariusz" ip="2001:db8:ca2:6:6::3" /&gt;
+            &lt;host id="0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63" name="anita" ip="2001:db8:ca2:6:6::4" /&gt;
           &lt;/dhcp&gt;
         &lt;/ip&gt;
       &lt;/network&gt;</pre>
index cfc820889b184967f38517d693fc1a9cb3e7b004..ec1d9402189f56a821fea610ee4a685e493387c5 100644 (file)
     </data>
   </define>
 
+  <!--====================================================================-->
+  <!--The duid is a unique identifier used in DHCPv6 to identity an       -->
+  <!--interface on a device (system).  The duid is often used by servers  -->
+  <!--such as dnsmasq to assign a specific IP address (and optionally a   -->
+  <!--name to an interface.  The applicable standards are RFC3315 and     -->
+  <!--RFC6355.  These standards actualy require the duid to be fixed for  -->
+  <!--the hardward device and applicable to all network interfaces on     -->
+  <!--that device.  It is not clear that any software currently enforces  -->
+  <!--this requirement although it could be implemented manually.         -->
+  <!--====================================================================-->
+  <!--There are currently four types of duids defined:                    -->
+  <!--  type 1, duid-LLT, link-layer (MAC) plus 32 bit time when the      -->
+  <!--          duid-LLT was created in seconds from January 1, 2000      -->
+  <!--  type 2, duid-EN, 32 bit "enterprise number" followed by a         -->
+  <!--          variable length unique identifier.                        -->
+  <!--  type 3, duid-LL, link-layer (MAC)                                 -->
+  <!--  type 4, duid-UUID, a 128 bit UUID (16 bytes)                      -->
+  <!--RFC3315 states that the maximum length of a duid is 128 bytes plus  -->
+  <!--the 16 bit type field.  Often, the machine type is "1" which is the -->
+  <!--number assigned to ethernet.                                        -->
+
+  <define name="duidLLT">
+    <data type="string">
+                     <!--   0======| type======| 0======| machine type======| time================| link-layer============|     -->
+      <param name="pattern">[0]{1,2}:[0]{0,1}[1]:[0]{1,2}:[0]{0,1}[a-fA-F1-9](:[a-fA-F0-9]{1,2}){4}(:[a-fA-F0-9]{1,2}){6,8}</param>
+    </data>
+  </define>
+
+  <define name="duidEN">
+    <data type="string">
+                     <!--   0======| type======| Enterprise number===| unique id ==============|     -->
+      <param name="pattern">[0]{1,2}:[0]{0,1}[2](:[a-fA-F0-9]{1,2}){4}(:[a-fA-F0-9]{1,2}){1,124}</param>
+    </data>
+  </define>
+
+  <define name="duidLL">
+    <data type="string">
+                     <!--   0======| type======| 0======| machine type======| link-layer============|     -->
+      <param name="pattern">[0]{1,2}:[0]{0,1}[3]:[0]{1,2}:[0]{0,1}[a-fA-F1-9](:[a-fA-F0-9]{1,2}){6,8}</param>
+    </data>
+  </define>
+
+  <define name="duidUUID">
+    <data type="string">
+                     <!--   0======| type======| UUID=================|     -->
+      <param name="pattern">[0]{1,2}:[0]{0,1}[4](:[a-fA-F0-9]{1,2}){16}</param>
+    </data>
+  </define>
+
+  <define name="DUID">
+    <choice>
+      <ref name="duidLLT"/>
+      <ref name="duidEN"/>
+      <ref name="duidLL"/>
+      <ref name="duidUUID"/>
+    </choice>
+  </define>
+  <!--======================================================================-->
+
   <!-- An ipv4 "dotted quad" address -->
   <define name="ipv4Addr">
     <data type="string">
index fff169b9829d37c14185f4b567240f3c6bf273d5..da7d8adcde96ebcb4de1f36057da26973105bb26 100644 (file)
                   <element name="host">
                     <choice>
                       <group>
-                        <attribute name="mac"><ref name="uniMacAddr"/></attribute>
+                        <choice>
+                          <attribute name="mac"><ref name="uniMacAddr"/></attribute>
+                          <attribute name="id"><ref name="DUID"/></attribute>
+                        </choice>
                         <optional>
                           <attribute name="name"><text/></attribute>
                         </optional>
index 34fd05abe70db62053e04174f6b77f38404563c1..3fc01cf584b5588d287a13fbad37a8396471f35b 100644 (file)
@@ -118,6 +118,7 @@ static void
 virNetworkDHCPHostDefClear(virNetworkDHCPHostDefPtr def)
 {
     VIR_FREE(def->mac);
+    VIR_FREE(def->id);
     VIR_FREE(def->name);
 }
 
@@ -678,7 +679,7 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
                               virNetworkDHCPHostDefPtr host,
                               bool partialOkay)
 {
-    char *mac = NULL, *name = NULL, *ip = NULL;
+    char *mac = NULL, *name = NULL, *ip = NULL, *id = NULL;
     virMacAddr addr;
     virSocketAddr inaddr;
     int ret = -1;
@@ -707,10 +708,20 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
         }
     }
 
+    id = virXMLPropString(node, "id");
+    if (id) {
+        char *cp = id + strspn(id, "0123456789abcdefABCDEF:");
+        if (*cp) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("Invalid character '%c' in id '%s' of network '%s'"),
+                           *cp, id, networkName);
+        }
+    }
+
     name = virXMLPropString(node, "name");
     if (name && (!c_isalpha(name[0]))) {
         virReportError(VIR_ERR_XML_ERROR,
-                       _("Cannot use name address '%s' in network '%s'"),
+                       _("Cannot use host name '%s' in network '%s'"),
                        name, networkName);
         goto cleanup;
     }
@@ -738,10 +749,10 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
          * address or name (IPv4)
          */
         if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
-            if (!name) {
+            if (!(id || name)) {
                 virReportError(VIR_ERR_XML_ERROR,
                            _("Static host definition in IPv6 network '%s' "
-                             "must have name attribute"),
+                             "must have id or name attribute"),
                            networkName);
                 goto cleanup;
             }
@@ -763,6 +774,8 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
 
     host->mac = mac;
     mac = NULL;
+    host->id = id;
+    id = NULL;
     host->name = name;
     name = NULL;
     if (ip)
@@ -771,6 +784,7 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
 
 cleanup:
     VIR_FREE(mac);
+    VIR_FREE(id);
     VIR_FREE(name);
     VIR_FREE(ip);
     return ret;
@@ -2189,6 +2203,8 @@ virNetworkIpDefFormat(virBufferPtr buf,
             virBufferAddLit(buf, "<host ");
             if (def->hosts[ii].mac)
                 virBufferAsprintf(buf, "mac='%s' ", def->hosts[ii].mac);
+            if (def->hosts[ii].id)
+                virBufferAsprintf(buf, "id='%s' ", def->hosts[ii].id);
             if (def->hosts[ii].name)
                 virBufferAsprintf(buf, "name='%s' ", def->hosts[ii].name);
             if (VIR_SOCKET_ADDR_VALID(&def->hosts[ii].ip)) {
index e7a4f95f2b9b14678e9f74cbdf3136725532f5ac..c509915cc159ed2921860440955dbe7cae02b26b 100644 (file)
@@ -66,6 +66,7 @@ typedef struct _virNetworkDHCPHostDef virNetworkDHCPHostDef;
 typedef virNetworkDHCPHostDef *virNetworkDHCPHostDefPtr;
 struct _virNetworkDHCPHostDef {
     char *mac;
+    char *id;
     char *name;
     virSocketAddr ip;
 };
index 0c3f778da87e881758b0493b58699e8f41e8ae8d..0932cf8e5edbe258243511f88f069d665ddd0e87 100644 (file)
@@ -599,7 +599,8 @@ networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
     for (i = 0; i < ipdef->nhosts; i++) {
         virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
         if (VIR_SOCKET_ADDR_VALID(&host->ip))
-            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip, host->name, ipv6) < 0)
+            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
+                                   host->name, host->id, ipv6) < 0)
                 return -1;
     }
 
index 6637a8977debd5224a83e32dbbefa03fc5c0c8a7..2e63d83af2174ee3456ed8d3f5a0d7e55845d828 100644 (file)
@@ -303,6 +303,7 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile,
              const char *mac,
              virSocketAddr *ip,
              const char *name,
+             const char *id,
              bool ipv6)
 {
     char *ipstr = NULL;
@@ -314,11 +315,20 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile,
 
     /* the first test determines if it is a dhcpv6 host */
     if (ipv6) {
-        if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,[%s]",
-                        name, ipstr) < 0)
-            goto alloc_error;
-    }
-    else if (name && mac) {
+        if (name && id) {
+            if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
+                            "id:%s,%s,[%s]", id, name, ipstr) < 0)
+                goto alloc_error;
+        } else if (name && !id) {
+            if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
+                            "%s,[%s]", name, ipstr) < 0)
+                goto alloc_error;
+        } else if (!name && id) {
+            if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
+                            "id:%s,[%s]", id, ipstr) < 0)
+                goto alloc_error;
+        }
+    } else if (name && mac) {
         if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s",
                         mac, ipstr, name) < 0)
             goto alloc_error;
@@ -511,9 +521,10 @@ dnsmasqAddDhcpHost(dnsmasqContext *ctx,
                    const char *mac,
                    virSocketAddr *ip,
                    const char *name,
+                   const char *id,
                    bool ipv6)
 {
-    return hostsfileAdd(ctx->hostsfile, mac, ip, name, ipv6);
+    return hostsfileAdd(ctx->hostsfile, mac, ip, name, id, ipv6);
 }
 
 /*
index a97d3e60191dd1dc434c29451d467bdb83db39f3..ed560da45d56b2b5c9d04c7d8b7d8e5282b24b6e 100644 (file)
@@ -86,6 +86,7 @@ int              dnsmasqAddDhcpHost(dnsmasqContext *ctx,
                                     const char *mac,
                                     virSocketAddr *ip,
                                     const char *name,
+                                    const char *id,
                                     bool ipv6);
 int              dnsmasqAddHost(dnsmasqContext *ctx,
                                 virSocketAddr *ip,
index 72103f71391ce116e880cbedcca6d456ef7fdc40..4259173854ef94a2b1f80c49ef1397a9142bf367 100644 (file)
   <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 id='0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63' ip='2001:db8:ac10:fd01::1:20' />
       <host name='paul' ip='2001:db8:ac10:fd01::1:21' />
+      <host id='0:3:0:1:0:16:3e:11:22:33' name='peter.xyz' ip='2001:db8:ac10:fd01::1:22' />
+      <host id='0:3:0:1:0:16:3e:44:55:33' ip='2001:db8:ac10:fd01::1:23' />
+      <host id='0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66' name='badbob' ip='2001:db8:ac10:fd01::1:24' />
     </dhcp>
   </ip>
   <ip family='ipv4' address='10.24.10.1'>
index 311013ad5297ebf9d3b62b025ed3bd33b1e2317b..776737e26c26734ad5f8116a42c73d0696ae5044 100644 (file)
@@ -7,8 +7,11 @@
   <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 id='0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63' ip='2001:db8:ac10:fd01::1:20' />
       <host name='paul' ip='2001:db8:ac10:fd01::1:21' />
+      <host id='0:3:0:1:0:16:3e:11:22:33' name='peter.xyz' ip='2001:db8:ac10:fd01::1:22' />
+      <host id='0:3:0:1:0:16:3e:44:55:33' ip='2001:db8:ac10:fd01::1:23' />
+      <host id='0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66' name='badbob' ip='2001:db8:ac10:fd01::1:24' />
     </dhcp>
   </ip>
 </network>
index 38d9ebf892f5b21a1d6b1e08799308929d1726bb..2693d872fc3c4da71f9d5caa819424962dd66f3c 100644 (file)
   </ip>
   <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
     <dhcp>
-      <host name='ralph' ip='2001:db8:ac10:fd01::1:20' />
+      <host id='0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63' ip='2001:db8:ac10:fd01::1:20' />
       <host name='paul' ip='2001:db8:ac10:fd01::1:21' />
+      <host id='0:3:0:1:0:16:3e:11:22:33' name='peter.xyz' ip='2001:db8:ac10:fd01::1:22' />
+      <host id='0:3:0:1:0:16:3e:44:55:33' ip='2001:db8:ac10:fd01::1:23' />
+      <host id='0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66' name='badbob' ip='2001:db8:ac10:fd01::1:24' />
     </dhcp>
   </ip>
 </network>
diff --git a/tests/networkxml2xmlin/dhcp6host-routed-network.xml b/tests/networkxml2xmlin/dhcp6host-routed-network.xml
new file mode 100644 (file)
index 0000000..2693d87
--- /dev/null
@@ -0,0 +1,22 @@
+<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 id='0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63' ip='2001:db8:ac10:fd01::1:20' />
+      <host name='paul' ip='2001:db8:ac10:fd01::1:21' />
+      <host id='0:3:0:1:0:16:3e:11:22:33' name='peter.xyz' ip='2001:db8:ac10:fd01::1:22' />
+      <host id='0:3:0:1:0:16:3e:44:55:33' ip='2001:db8:ac10:fd01::1:23' />
+      <host id='0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66' name='badbob' ip='2001:db8:ac10:fd01::1:24' />
+    </dhcp>
+  </ip>
+</network>
diff --git a/tests/networkxml2xmlout/dhcp6host-routed-network.xml b/tests/networkxml2xmlout/dhcp6host-routed-network.xml
new file mode 100644 (file)
index 0000000..7305043
--- /dev/null
@@ -0,0 +1,24 @@
+<network>
+  <name>local</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <forward dev='eth1' mode='route'>
+    <interface dev='eth1'/>
+  </forward>
+  <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 id='0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63' ip='2001:db8:ac10:fd01::1:20' />
+      <host name='paul' ip='2001:db8:ac10:fd01::1:21' />
+      <host id='0:3:0:1:0:16:3e:11:22:33' name='peter.xyz' ip='2001:db8:ac10:fd01::1:22' />
+      <host id='0:3:0:1:0:16:3e:44:55:33' ip='2001:db8:ac10:fd01::1:23' />
+      <host id='0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66' name='badbob' ip='2001:db8:ac10:fd01::1:24' />
+    </dhcp>
+  </ip>
+</network>
index 1cd74d101817834a0d9970e8d5a96bbcfbfaa504..1063435651e693732ad045f77f7562e1f9b439d8 100644 (file)
@@ -92,6 +92,7 @@ mymain(void)
     } while (0)
 #define DO_TEST(name) DO_TEST_FULL(name, 0)
 
+    DO_TEST("dhcp6host-routed-network");
     DO_TEST("empty-allow-ipv6");
     DO_TEST("isolated-network");
     DO_TEST("routed-network");