diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index f7c483d39f..41a83fa9d1 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -782,6 +782,11 @@
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. Since 1.0.3
@@ -797,7 +802,9 @@
<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" />
+ <host id="0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66" ip="2001:db8:ca2:2:3::2" />
+ <host id="0:3:0:1:0:16:3e:11:22:33" name="ralph" ip="2001:db8:ca2:2:3::3" />
+ <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" />
</dhcp>
</ip>
</network>
@@ -828,6 +835,11 @@
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. Since 1.0.3
@@ -837,7 +849,9 @@
<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" />
+ <host id="0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66" ip="2001:db8:ca2:6:6::2" />
+ <host id="0:3:0:1:0:16:3e:11:22:33" name="dariusz" ip="2001:db8:ca2:6:6::3" />
+ <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" />
</dhcp>
</ip>
</network>
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index cfc820889b..ec1d940218 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -101,6 +101,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [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}
+
+
+
+
+
+
+ [0]{1,2}:[0]{0,1}[2](:[a-fA-F0-9]{1,2}){4}(:[a-fA-F0-9]{1,2}){1,124}
+
+
+
+
+
+
+ [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}
+
+
+
+
+
+
+ [0]{1,2}:[0]{0,1}[4](:[a-fA-F0-9]{1,2}){16}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index fff169b982..da7d8adcde 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -280,7 +280,10 @@
-
+
+
+
+
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 34fd05abe7..3fc01cf584 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -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, "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)) {
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index e7a4f95f2b..c509915cc1 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -66,6 +66,7 @@ typedef struct _virNetworkDHCPHostDef virNetworkDHCPHostDef;
typedef virNetworkDHCPHostDef *virNetworkDHCPHostDefPtr;
struct _virNetworkDHCPHostDef {
char *mac;
+ char *id;
char *name;
virSocketAddr ip;
};
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 0c3f778da8..0932cf8e5e 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -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;
}
diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c
index 6637a8977d..2e63d83af2 100644
--- a/src/util/virdnsmasq.c
+++ b/src/util/virdnsmasq.c
@@ -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);
}
/*
diff --git a/src/util/virdnsmasq.h b/src/util/virdnsmasq.h
index a97d3e6019..ed560da45d 100644
--- a/src/util/virdnsmasq.h
+++ b/src/util/virdnsmasq.h
@@ -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,
diff --git a/tests/networkxml2confdata/dhcp6-nat-network.xml b/tests/networkxml2confdata/dhcp6-nat-network.xml
index 72103f7139..4259173854 100644
--- a/tests/networkxml2confdata/dhcp6-nat-network.xml
+++ b/tests/networkxml2confdata/dhcp6-nat-network.xml
@@ -15,8 +15,11 @@
-
+
+
+
+
diff --git a/tests/networkxml2confdata/dhcp6-network.xml b/tests/networkxml2confdata/dhcp6-network.xml
index 311013ad52..776737e26c 100644
--- a/tests/networkxml2confdata/dhcp6-network.xml
+++ b/tests/networkxml2confdata/dhcp6-network.xml
@@ -7,8 +7,11 @@
-
+
+
+
+
diff --git a/tests/networkxml2confdata/dhcp6host-routed-network.xml b/tests/networkxml2confdata/dhcp6host-routed-network.xml
index 38d9ebf892..2693d872fc 100644
--- a/tests/networkxml2confdata/dhcp6host-routed-network.xml
+++ b/tests/networkxml2confdata/dhcp6host-routed-network.xml
@@ -12,8 +12,11 @@
-
+
+
+
+
diff --git a/tests/networkxml2xmlin/dhcp6host-routed-network.xml b/tests/networkxml2xmlin/dhcp6host-routed-network.xml
new file mode 100644
index 0000000000..2693d872fc
--- /dev/null
+++ b/tests/networkxml2xmlin/dhcp6host-routed-network.xml
@@ -0,0 +1,22 @@
+
+ local
+ 81ff0d90-c91e-6742-64da-4a736edb9a9b
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/networkxml2xmlout/dhcp6host-routed-network.xml b/tests/networkxml2xmlout/dhcp6host-routed-network.xml
new file mode 100644
index 0000000000..7305043f37
--- /dev/null
+++ b/tests/networkxml2xmlout/dhcp6host-routed-network.xml
@@ -0,0 +1,24 @@
+
+ local
+ 81ff0d90-c91e-6742-64da-4a736edb9a9b
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c
index 1cd74d1018..1063435651 100644
--- a/tests/networkxml2xmltest.c
+++ b/tests/networkxml2xmltest.c
@@ -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");