<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>
<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></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>
<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></pre>
</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">
<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>
virNetworkDHCPHostDefClear(virNetworkDHCPHostDefPtr def)
{
VIR_FREE(def->mac);
+ VIR_FREE(def->id);
VIR_FREE(def->name);
}
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;
}
}
+ 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;
}
* 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;
}
host->mac = mac;
mac = NULL;
+ host->id = id;
+ id = NULL;
host->name = name;
name = NULL;
if (ip)
cleanup:
VIR_FREE(mac);
+ VIR_FREE(id);
VIR_FREE(name);
VIR_FREE(ip);
return ret;
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)) {
typedef virNetworkDHCPHostDef *virNetworkDHCPHostDefPtr;
struct _virNetworkDHCPHostDef {
char *mac;
+ char *id;
char *name;
virSocketAddr ip;
};
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;
}
const char *mac,
virSocketAddr *ip,
const char *name,
+ const char *id,
bool ipv6)
{
char *ipstr = NULL;
/* 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;
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);
}
/*
const char *mac,
virSocketAddr *ip,
const char *name,
+ const char *id,
bool ipv6);
int dnsmasqAddHost(dnsmasqContext *ctx,
virSocketAddr *ip,
<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'>
<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>
</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>
--- /dev/null
+<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>
--- /dev/null
+<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>
} 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");