This support includes IPv6 dhcp-range= and dhcp-host=
for one IPv6 subnetwork on one interface.
The parameter tests have been updated to add some new
DHCPv6 tests. Three new tests (6 files) were added.
The xml format html documentation has been updated to
reflect support for IPv6 DHCP.
This patch include a bugfix for ipv4flag and ipv6flag
initialization.
---
docs/formatnetwork.html.in | 108 ++++++-
src/conf/network_conf.c | 100 ++++---
src/network/bridge_driver.c | 326 +++++++++++++--------
src/util/dnsmasq.c | 9 +-
tests/networkxml2argvdata/dhcp6-network.argv | 16 +
tests/networkxml2argvdata/dhcp6-network.xml | 16 +
tests/networkxml2argvdata/isolated-network.argv | 2 +-
tests/networkxml2argvdata/nat-network-dhcp6.argv | 19 ++
tests/networkxml2argvdata/nat-network-dhcp6.xml | 26 ++
.../nat-network-dns-srv-record-minimal.argv | 2 +-
.../nat-network-dns-srv-record.argv | 2 +-
.../nat-network-dns-txt-record.argv | 2 +-
tests/networkxml2argvdata/nat-network.argv | 2 +-
tests/networkxml2argvdata/netboot-network.argv | 8 +-
.../networkxml2argvdata/netboot-proxy-network.argv | 4 +-
.../routed-network-dhcphost.argv | 14 +
.../routed-network-dhcphost.xml | 19 ++
tests/networkxml2argvtest.c | 3 +
18 files changed, 498 insertions(+), 180 deletions(-)
create mode 100644 tests/networkxml2argvdata/dhcp6-network.argv
create mode 100644 tests/networkxml2argvdata/dhcp6-network.xml
create mode 100644 tests/networkxml2argvdata/nat-network-dhcp6.argv
create mode 100644 tests/networkxml2argvdata/nat-network-dhcp6.xml
create mode 100644 tests/networkxml2argvdata/routed-network-dhcphost.argv
create mode 100644 tests/networkxml2argvdata/routed-network-dhcphost.xml
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 49206dd..b91672a 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -577,8 +577,10 @@
dotted-decimal format, or an IPv6 address in standard
colon-separated hexadecimal format, that will be configured on
the bridge
- device associated with the virtual network. To the guests this
- address will be their default route. For IPv4 addresses, the
<code>netmask</code>
+ device associated with the virtual network. To the guests this IPv4
+ address will be their IPv4 default route. For IPv6, the default route is
+ established via Router Advertisement.
+ For IPv4 addresses, the <code>netmask</code>
attribute defines the significant bits of the network address,
again specified in dotted-decimal format. For IPv6 addresses,
and as an alternate method for IPv4 addresses, you can specify
@@ -587,10 +589,13 @@
could also be given as <code>prefix='24'</code>. The
<code>family</code>
attribute is used to specify the type of address - 'ipv4' or
'ipv6'; if no
<code>family</code> is given, 'ipv4' is assumed. A network
can have more than
- one of each family of address defined, but only a single address can have a
- <code>dhcp</code> or <code>tftp</code> element. <span
class="since">Since 0.3.0;
+ one of each family of address defined, but only a single IPv4 address can have a
+ <code>dhcp</code> or <code>tftp</code> element. <span
class="since">Since 0.3.0 </span>
IPv6, multiple addresses on a single network, <code>family</code>,
and
- <code>prefix</code> since 0.8.7</span>
+ <code>prefix</code>. <span class="since">Since
0.8.7</span> In addition
+ to the one IPv4 address which has a <code>dhcp</code> definition, one
IPv6
+ address can have a <code>dhcp</code> definition.
+ <span class="since"> Since 1.0.1</span>
<dl>
<dt><code>tftp</code></dt>
<dd>Immediately within
@@ -611,27 +616,46 @@
<code>dhcp</code> element is not supported for IPv6, and
is only supported on a single IP address per network for IPv4.
<span class="since">Since 0.3.0</span>
+ The <code>dhcp</code> element is now supported for IPv6.
+ Again, there is a restriction that only one IPv6 address definition
+ is able to have a <code>dhcp</code> element.
+ <span class="since">Since 1.0.1</span>
<dl>
<dt><code>range</code></dt>
<dd>The <code>start</code> and
<code>end</code> attributes on the
<code>range</code> element specify the boundaries of a pool
of
- IPv4 addresses to be provided to DHCP clients. These two addresses
+ addresses to be provided to DHCP clients. These two addresses
must lie within the scope of the network defined on the parent
- <code>ip</code> element. <span
class="since">Since 0.3.0</span>
+ <code>ip</code> element. There may be zero or more
+ <code>range</code> elements specified.
+ <span class="since">Since 0.3.0</span>
+ <code>Range</code> can be specified for one IPv4 address,
+ one IPv6 address, or both. <span class="since">Since
1.0.1</span>
</dd>
<dt><code>host</code></dt>
<dd>Within the <code>dhcp</code> element there may be
zero or more
- <code>host</code> elements; these specify hosts which will be
given
+ <code>host</code> elements. These specify hosts which will
be given
names and predefined IP addresses by the built-in DHCP server. Any
- such element must specify the MAC address of the host to be assigned
+ such IPv4 element must specify the MAC address of the host to be
assigned
a given name (via the <code>mac</code> attribute), the IP to
be
assigned to that host (via the <code>ip</code> attribute),
and the
name to be given that host by the DHCP server (via the
<code>name</code> attribute). <span
class="since">Since 0.4.5</span>
+ Within the IPv6 <code>dhcp</code> element zero or more
+ <code>host</code> elements are now supported. The definition
for
+ an IPv6 <code>host</code> element differs from that for
IPv4:
+ there is no <code>mac</code> attribute since a MAC address
has no
+ defined meaning in IPv6. Instead, the <code>name</code>
attribute is
+ used to identify the host to be assigned the IPv6 address. For DHCPv6,
+ the name is the plain name of the client host sent by the
+ client to the server. Note that this method of assigning a
+ specific IP address can be used instead of the
<code>mac</code>
+ attribute for IPv4. <span class="since">Since
1.0.1</span>
</dd>
<dt><code>bootp</code></dt>
<dd>The optional <code>bootp</code>
- element specifies BOOTP options to be provided by the DHCP server.
+ element specifies BOOTP options to be provided by the DHCP
+ server for IPv4 only.
Two attributes are supported: <code>file</code> is mandatory
and
gives the file to be used for the boot image;
<code>server</code> is
optional and gives the address of the TFTP server from which the boot
@@ -674,6 +698,29 @@
<ip family="ipv6" address="2001:db8:ca2:2::1"
prefix="64" />
</network></pre>
+
+ <p>
+ Below is a variation of the above example which adds an IPv6
+ dhcp range definition.
+ </p>
+
+ <pre>
+ <network>
+ <name>default6</name>
+ <bridge name="virbr0" />
+ <forward mode="nat"/>
+ <ip address="192.168.122.1"
netmask="255.255.255.0">
+ <dhcp>
+ <range start="192.168.122.2" end="192.168.122.254"
/>
+ </dhcp>
+ </ip>
+ <ip family="ipv6" address="2001:db8:ca2:2::1"
prefix="64" >
+ <dhcp>
+ <range start="2001:db8:ca2:2:1::10"
end="2001:db8:ca2:2:1::ff" />
+ </dhcp>
+ </ip>
+ </network></pre>
+
<h3><a name="examplesRoute">Routed network
config</a></h3>
<p>
@@ -698,6 +745,29 @@
<ip family="ipv6" address="2001:db8:ca2:2::1"
prefix="64" />
</network></pre>
+ <p>
+ Below is another IPv6 varition. Instead of a dhcp range being
+ specified, this example has a couple of IPv6 host definitions.
+ </p>
+
+ <pre>
+ <network>
+ <name>local6</name>
+ <bridge name="virbr1" />
+ <forward mode="route" dev="eth1"/>
+ <ip address="192.168.122.1"
netmask="255.255.255.0">
+ <dhcp>
+ <range start="192.168.122.2" end="192.168.122.254"
/>
+ </dhcp>
+ </ip>
+ <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"
/>
+ </dhcp>
+ </ip>
+ </network></pre>
+
<h3><a name="examplesPrivate">Isolated network
config</a></h3>
<p>
@@ -720,6 +790,24 @@
<ip family="ipv6" address="2001:db8:ca2:3::1"
prefix="64" />
</network></pre>
+ <h3><a name="examplesPrivate6">Isolated IPv6 network
config</a></h3>
+
+ <p>
+ This variation of an isolated network defines only IPv6.
+ </p>
+
+ <pre>
+ <network>
+ <name>sixnet</name>
+ <bridge name="virbr6" />
+ <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"
/>
+ </dhcp>
+ </ip>
+ </network></pre>
+
<h3><a name="examplesBridge">Using an existing host
bridge</a></h3>
<p>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 228951d..a56b2e6 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -633,6 +633,7 @@ cleanup:
static int
virNetworkDHCPHostDefParse(const char *networkName,
+ virNetworkIpDefPtr def,
xmlNodePtr node,
virNetworkDHCPHostDefPtr host,
bool partialOkay)
@@ -644,6 +645,13 @@ virNetworkDHCPHostDefParse(const char *networkName,
mac = virXMLPropString(node, "mac");
if (mac != NULL) {
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid to specify MAC address '%s' "
+ "in IPv6 network '%s'"),
+ mac, networkName);
+ goto cleanup;
+ }
if (virMacAddrParse(mac, &addr) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Cannot parse MAC address '%s' in network
'%s'"),
@@ -686,10 +694,19 @@ virNetworkDHCPHostDefParse(const char *networkName,
networkName);
}
} else {
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
+ if (!name) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Static host definition in IPv6 network '%s'
"
+ "must have name attribute"),
+ networkName);
+ goto cleanup;
+ }
+ }
/* normal usage - you need at least one MAC address or one host name */
- if (!(mac || name)) {
+ else if (!(mac || name)) {
virReportError(VIR_ERR_XML_ERROR,
- _("Static host definition in network '%s' "
+ _("Static host definition in IPv4 network '%s'
"
"must have mac or name attribute"),
networkName);
goto cleanup;
@@ -748,36 +765,39 @@ virNetworkDHCPDefParse(const char *networkName,
virReportOOMError();
return -1;
}
- if (virNetworkDHCPHostDefParse(networkName, cur,
+ if (virNetworkDHCPHostDefParse(networkName, def, cur,
&def->hosts[def->nhosts],
false) < 0) {
return -1;
}
def->nhosts++;
- } else if (cur->type == XML_ELEMENT_NODE &&
- xmlStrEqual(cur->name, BAD_CAST "bootp")) {
- char *file;
- char *server;
- virSocketAddr inaddr;
- memset(&inaddr, 0, sizeof(inaddr));
-
- if (!(file = virXMLPropString(cur, "file"))) {
- cur = cur->next;
- continue;
- }
- server = virXMLPropString(cur, "server");
+ } else if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
+ /* the following only applies to IPv4 */
+ if (cur->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(cur->name, BAD_CAST "bootp")) {
+ char *file;
+ char *server;
+ virSocketAddr inaddr;
+ memset(&inaddr, 0, sizeof(inaddr));
+
+ if (!(file = virXMLPropString(cur, "file"))) {
+ cur = cur->next;
+ continue;
+ }
+ server = virXMLPropString(cur, "server");
+
+ if (server &&
+ virSocketAddrParse(&inaddr, server, AF_UNSPEC) < 0) {
+ VIR_FREE(file);
+ VIR_FREE(server);
+ return -1;
+ }
- if (server &&
- virSocketAddrParse(&inaddr, server, AF_UNSPEC) < 0) {
- VIR_FREE(file);
+ def->bootfile = file;
+ def->bootserver = inaddr;
VIR_FREE(server);
- return -1;
}
-
- def->bootfile = file;
- def->bootserver = inaddr;
- VIR_FREE(server);
}
cur = cur->next;
@@ -1139,6 +1159,20 @@ virNetworkIPParseXML(const char *networkName,
}
}
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
+ /* parse IPv6-related info */
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
+ result = virNetworkDHCPDefParse(networkName, def, cur);
+ if (result)
+ goto error;
+ }
+ cur = cur->next;
+ }
+ }
+
result = 0;
error:
@@ -2347,11 +2381,9 @@ virNetworkIpDefByIndex(virNetworkDefPtr def, int parentIndex)
/* first find which ip element's dhcp host list to work on */
if (parentIndex >= 0) {
ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, parentIndex);
- if (!(ipdef &&
- VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))) {
+ if (!(ipdef)) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("couldn't update dhcp host entry - "
- "no <ip family='ipv4'> "
"element found at index %d in network
'%s'"),
parentIndex, def->name);
}
@@ -2364,17 +2396,17 @@ virNetworkIpDefByIndex(virNetworkDefPtr def, int parentIndex)
for (ii = 0;
(ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, ii));
ii++) {
- if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET) &&
- (ipdef->nranges || ipdef->nhosts)) {
+ if (ipdef->nranges || ipdef->nhosts)
break;
- }
}
- if (!ipdef)
+ if (!ipdef) {
ipdef = virNetworkDefGetIpByIndex(def, AF_INET, 0);
+ if (!ipdef)
+ ipdef = virNetworkDefGetIpByIndex(def, AF_INET6, 0);
+ }
if (!ipdef) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("couldn't update dhcp host entry - "
- "no <ip family='ipv4'> "
"element found in network '%s'"),
def->name);
}
return ipdef;
@@ -2404,7 +2436,7 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def,
/* parse the xml into a virNetworkDHCPHostDef */
if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
- if (virNetworkDHCPHostDefParse(def->name, ctxt->node, &host, false)
< 0)
+ if (virNetworkDHCPHostDefParse(def->name, ipdef, ctxt->node, &host,
false) < 0)
goto cleanup;
/* search for the entry with this (mac|name),
@@ -2437,7 +2469,7 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def,
} else if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
(command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) {
- if (virNetworkDHCPHostDefParse(def->name, ctxt->node, &host, true) <
0)
+ if (virNetworkDHCPHostDefParse(def->name, ipdef, ctxt->node, &host,
true) < 0)
goto cleanup;
/* log error if an entry with same name/address/ip already exists */
@@ -2483,7 +2515,7 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def,
} else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
- if (virNetworkDHCPHostDefParse(def->name, ctxt->node, &host, false)
< 0)
+ if (virNetworkDHCPHostDefParse(def->name, ipdef, ctxt->node, &host,
false) < 0)
goto cleanup;
/* find matching entry - all specified attributes must match */
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 236d8f8..0c4c794 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -598,20 +598,32 @@ cleanup:
return ret;
}
+ /* the following does not build a file, it builds a list
+ * which is later saved into a file
+ */
+
static int
-networkBuildDnsmasqHostsfile(dnsmasqContext *dctx,
- virNetworkIpDefPtr ipdef,
- virNetworkDNSDefPtr dnsdef)
+networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
+ virNetworkIpDefPtr ipdef)
{
- unsigned int i, j;
+ unsigned int i;
for (i = 0; i < ipdef->nhosts; i++) {
virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
- if ((host->mac) && VIR_SOCKET_ADDR_VALID(&host->ip))
+ if (VIR_SOCKET_ADDR_VALID(&host->ip))
if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip, host->name)
< 0)
return -1;
}
+ return 0;
+}
+
+static int
+networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
+ virNetworkDNSDefPtr dnsdef)
+{
+ unsigned int i, j;
+
if (dnsdef) {
for (i = 0; i < dnsdef->nhosts; i++) {
virNetworkDNSHostsDefPtr host = &(dnsdef->hosts[i]);
@@ -629,7 +641,6 @@ networkBuildDnsmasqHostsfile(dnsmasqContext *dctx,
/* build the dnsmasq conf file contents */
static int
networkDnsmasqConfContents(virNetworkObjPtr network,
- virNetworkIpDefPtr ipdef,
const char *pidfile,
char **configstr,
dnsmasqContext *dctx)
@@ -642,7 +653,8 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
char *recordPort = NULL;
char *recordWeight = NULL;
char *recordPriority = NULL;
- virNetworkIpDefPtr tmpipdef;
+ virNetworkIpDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
+ bool dhcp4flag, dhcp6flag;
*configstr = NULL;
@@ -674,7 +686,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
"local=/%s/\n",
network->def->domain ? network->def->domain :
"");
if (network->def->domain)
- virBufferAsprintf(&configbuf,
+ virBufferAsprintf(&configbuf,
"domain=%s\n"
"expand-hosts\n",
network->def->domain);
@@ -764,7 +776,34 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
VIR_FREE(ipaddr);
}
- if (ipdef) {
+ /* Find the first dhcp for both IPv4 and IPv6 */
+ for (ii = 0, ipv4def = NULL, ipv6def = NULL, dhcp4flag = false, dhcp6flag = false;
+ (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
+ ii++) {
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
+ if (ipdef->nranges || ipdef->nhosts) {
+ if (!ipv4def) {
+ ipv4def = ipdef;
+ dhcp4flag = true;
+ }
+ }
+ }
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
+ if (ipdef->nranges || ipdef->nhosts) {
+ if (!ipv6def) {
+ ipv6def = ipdef;
+ dhcp6flag = true;
+ }
+ }
+ }
+ }
+
+ if (ipv4def)
+ ipdef = ipv4def;
+ else
+ ipdef = ipv6def;
+
+ while (ipdef) {
for (r = 0 ; r < ipdef->nranges ; r++) {
char *saddr = virSocketAddrFormat(&ipdef->ranges[r].start);
if (!saddr)
@@ -785,7 +824,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
/*
* For static-only DHCP, i.e. with no range but at least one host element,
* we have to add a special --dhcp-range option to enable the service in
- * dnsmasq.
+ * dnsmasq. [this is for dhcp-hosts= support]
*/
if (!ipdef->nranges && ipdef->nhosts) {
char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
@@ -795,53 +834,65 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
VIR_FREE(bridgeaddr);
}
- if (ipdef->nranges > 0) {
- char *leasefile = networkDnsmasqLeaseFileName(network->def->name);
- if (!leasefile)
- goto cleanup;
- virBufferAsprintf(&configbuf, "dhcp-leasefile=%s\n",
leasefile);
- VIR_FREE(leasefile);
- virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n",
nbleases);
- }
-
- if (ipdef->nranges || ipdef->nhosts)
- virBufferAsprintf(&configbuf, "dhcp-no-override\n");
-
- if (networkBuildDnsmasqHostsfile(dctx, ipdef, network->def->dns) < 0)
+ if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
goto cleanup;
- /* Even if there are currently no static hosts, if we're
- * listening for DHCP, we should write a 0-length hosts
- * file to allow for runtime additions.
- */
- if (ipdef->nranges || ipdef->nhosts)
- virBufferAsprintf(&configbuf, "dhcp-hostsfile=%s\n",
- dctx->hostsfile->path);
+ /* Note: the following is IPv4 only */
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
+ if (ipdef->nranges || ipdef->nhosts)
+ virBufferAsprintf(&configbuf, "dhcp-no-override\n");
- /* Likewise, always create this file and put it on the commandline, to allow for
- * for runtime additions.
- */
- virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
- dctx->addnhostsfile->path);
-
- if (ipdef->tftproot) {
- virBufferAsprintf(&configbuf, "enable-tftp\n");
- virBufferAsprintf(&configbuf, "tftp-root=%s\n",
ipdef->tftproot);
- }
- if (ipdef->bootfile) {
- if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
- char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
+ if (ipdef->tftproot) {
+ virBufferAsprintf(&configbuf, "enable-tftp\n");
+ virBufferAsprintf(&configbuf, "tftp-root=%s\n",
ipdef->tftproot);
+ }
+ if (ipdef->bootfile) {
+ if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
+ char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
- if (!bootserver)
- goto cleanup;
- virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
- ipdef->bootfile, ",,", bootserver);
- VIR_FREE(bootserver);
- } else {
- virBufferAsprintf(&configbuf, "dhcp-boot=%s\n",
ipdef->bootfile);
+ if (!bootserver)
+ goto cleanup;
+ virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
+ ipdef->bootfile, ",,",
bootserver);
+ VIR_FREE(bootserver);
+ } else {
+ virBufferAsprintf(&configbuf, "dhcp-boot=%s\n",
ipdef->bootfile);
+ }
}
}
+ if (ipdef == ipv6def)
+ ipdef = NULL;
+ else
+ ipdef = ipv6def;
}
+
+ if (nbleases > 0) {
+ char *leasefile = networkDnsmasqLeaseFileName(network->def->name);
+ if (!leasefile)
+ goto cleanup;
+ virBufferAsprintf(&configbuf, "dhcp-leasefile=%s\n", leasefile);
+ VIR_FREE(leasefile);
+ virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
+ }
+
+ /* this is done once per interface */
+ if (networkBuildDnsmasqHostsList(dctx, network->def->dns) < 0)
+ goto cleanup;
+
+ /* Even if there are currently no static hosts, if we're
+ * listening for DHCP, we should write a 0-length hosts
+ * file to allow for runtime additions.
+ */
+ if (dhcp4flag || dhcp6flag)
+ virBufferAsprintf(&configbuf, "dhcp-hostsfile=%s\n",
+ dctx->hostsfile->path);
+
+ /* Likewise, always create this file and put it on the commandline, to allow for
+ * for runtime additions.
+ */
+ virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
+ dctx->addnhostsfile->path);
+
if (!(*configstr = virBufferContentAndReset(&configbuf))) {
virReportOOMError();
goto cleanup;
@@ -865,25 +916,12 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
virCommandPtr *cmdou
int testOnly, char **testConfigStr)
{
virCommandPtr cmd = NULL;
- int ret = -1, ii;
- virNetworkIpDefPtr ipdef;
+ int ret = -1;
char *configfile = NULL;
char *configstr = NULL;
network->dnsmasqPid = -1;
- /* Look for first IPv4 address that has dhcp defined. */
- /* We support dhcp config on 1 IPv4 interface only. */
- for (ii = 0;
- (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
- ii++) {
- if (ipdef->nranges || ipdef->nhosts)
- break;
- }
- /* If no IPv4 addresses had dhcp info, pick the first (if there were any). */
- if (!ipdef)
- ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, 0);
-
/* If there are no IP addresses at all (v4 or v6), return now, since
* there won't be any address for dnsmasq to listen on anyway.
* If there are any addresses, even if no dhcp ranges or static entries,
@@ -892,7 +930,7 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
virCommandPtr *cmdou
if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0))
return 0;
- if (networkDnsmasqConfContents(network, ipdef, pidfile, &configstr, dctx) <
0)
+ if (networkDnsmasqConfContents(network, pidfile, &configstr, dctx) < 0)
goto cleanup;
if (!configstr)
goto cleanup;
@@ -915,7 +953,6 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
virCommandPtr *cmdou
configfile);
goto cleanup;
}
- VIR_INFO("dnsmasq conf file %s written", configfile);
cmd = virCommandNew(DNSMASQ);
virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
@@ -939,14 +976,13 @@ networkStartDhcpDaemon(virNetworkObjPtr network)
char *testconfigstr = NULL;
int ret = -1;
dnsmasqContext *dctx = NULL;
- virNetworkIpDefPtr ipdef;
- int i;
if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) {
/* no IPv6 addresses, so we don't need to run radvd */
ret = 0;
goto cleanup;
}
+ VIR_INFO("starting dhcp daemon (dnsmasq)");
if (virFileMakePath(NETWORK_PID_DIR) < 0) {
virReportSystemError(errno,
@@ -982,18 +1018,6 @@ networkStartDhcpDaemon(virNetworkObjPtr network)
if (ret < 0)
goto cleanup;
- /* populate dnsmasq hosts file */
- for (i = 0; (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i)); i++)
{
- if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET) &&
- (ipdef->nranges || ipdef->nhosts)) {
- if (networkBuildDnsmasqHostsfile(dctx, ipdef,
- network->def->dns) < 0)
- goto cleanup;
-
- break;
- }
- }
-
ret = dnsmasqSave(dctx);
if (ret < 0)
goto cleanup;
@@ -1037,31 +1061,35 @@ networkRefreshDhcpDaemon(virNetworkObjPtr network)
virNetworkIpDefPtr ipdef;
dnsmasqContext *dctx = NULL;
+ /* if no IP addresses specified, nothing to do */
+ if (virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0))
+ return 0;
+
/* if there's no running dnsmasq, just start it */
if (network->dnsmasqPid <= 0 || (kill(network->dnsmasqPid, 0) < 0))
return networkStartDhcpDaemon(network);
- /* Look for first IPv4 address that has dhcp defined. */
- /* We support dhcp config on 1 IPv4 interface only. */
+ VIR_INFO("REFRESH: DhcpDaemon: for %s", network->def->bridge);
+ if (!(dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR)))
+ goto cleanup;
+
+ /* Look for first IPv4 address that has dhcp defined.
+ * We only support dhcp-host config on 1 IPv4 interface.
+ */
for (ii = 0;
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
ii++) {
if (ipdef->nranges || ipdef->nhosts)
break;
}
- /* If no IPv4 addresses had dhcp info, pick the first (if there were any). */
if (!ipdef)
ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, 0);
- if (!ipdef) {
- /* no <ip> elements, so nothing to do */
- return 0;
- }
-
- if (!(dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR)))
- goto cleanup;
+ if (ipdef)
+ if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
+ goto cleanup;
- if (networkBuildDnsmasqHostsfile(dctx, ipdef, network->def->dns) < 0)
+ if (networkBuildDnsmasqHostsList(dctx, network->def->dns) < 0)
goto cleanup;
if ((ret = dnsmasqSave(dctx)) < 0)
@@ -1093,6 +1121,12 @@ networkRestartDhcpDaemon(virNetworkObjPtr network)
return networkStartDhcpDaemon(network);
}
+static char radvd1[] = " AdvOtherConfigFlag off;\n\n";
+static char radvd2[] = " AdvAutonomous off;\n";
+static char radvd3[] = " AdvOnLink on;\n"
+ " AdvAutonomous on;\n"
+ " AdvRouterAddr off;\n";
+
static int
networkRadvdConfContents(virNetworkObjPtr network, char **configstr)
{
@@ -1100,20 +1134,42 @@ networkRadvdConfContents(virNetworkObjPtr network, char
**configstr)
int ret = -1, ii;
virNetworkIpDefPtr ipdef;
bool v6present = false;
+ bool dhcp6 = false;
*configstr = NULL;
+ /* stateful/stateless is done on an interface basis;
+ * go through the list to see if any subnets have dhcp
+ */
+ for (ii = 0;
+ (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, ii));
+ ii++) {
+
+ v6present = true;
+ if (ipdef->nranges > 0) {
+ dhcp6 = true;
+ break;
+ }
+ }
+
+ /* If there are no IPv6 addresses, then we are done */
+ if (!v6present) {
+ ret = 0;
+ goto cleanup;
+ }
+
/* create radvd config file appropriate for this network;
* IgnoreIfMissing allows radvd to start even when the bridge is down
*/
virBufferAsprintf(&configbuf, "interface %s\n"
"{\n"
" AdvSendAdvert on;\n"
- " AdvManagedFlag off;\n"
- " AdvOtherConfigFlag off;\n"
" IgnoreIfMissing on;\n"
- "\n",
- network->def->bridge);
+ " AdvManagedFlag %s;\n"
+ "%s",
+ network->def->bridge,
+ dhcp6 ? "on" : "off",
+ dhcp6 ? "\n" : radvd1);
/* add a section for each IPv6 address in the config */
for (ii = 0;
@@ -1122,7 +1178,6 @@ networkRadvdConfContents(virNetworkObjPtr network, char
**configstr)
int prefix;
char *netaddr;
- v6present = true;
prefix = virNetworkIpDefPrefix(ipdef);
if (prefix < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1134,27 +1189,21 @@ networkRadvdConfContents(virNetworkObjPtr network, char
**configstr)
goto cleanup;
virBufferAsprintf(&configbuf,
" prefix %s/%d\n"
- " {\n"
- " AdvOnLink on;\n"
- " AdvAutonomous on;\n"
- " AdvRouterAddr off;\n"
- " };\n",
- netaddr, prefix);
+ " {\n%s };\n",
+ netaddr, prefix,
+ dhcp6 ? radvd2 : radvd3);
VIR_FREE(netaddr);
}
- /* only create the string if we found at least one IPv6 address */
- if (v6present) {
- virBufferAddLit(&configbuf, "};\n");
+ virBufferAddLit(&configbuf, "};\n");
- if (virBufferError(&configbuf)) {
- virReportOOMError();
- goto cleanup;
- }
- if (!(*configstr = virBufferContentAndReset(&configbuf))) {
- virReportOOMError();
- goto cleanup;
- }
+ if (virBufferError(&configbuf)) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ if (!(*configstr = virBufferContentAndReset(&configbuf))) {
+ virReportOOMError();
+ goto cleanup;
}
ret = 0;
@@ -1664,9 +1713,19 @@ networkAddGeneralIp6tablesRules(struct network_driver *driver,
goto err5;
}
+ if (iptablesAddUdpInput(driver->iptables, AF_INET6,
+ network->def->bridge, 547) < 0) {
+ virReportError(VIR_ERR_SYSTEM_ERROR,
+ _("failed to add ip6tables rule to allow DHCP6 requests from
'%s'"),
+ network->def->bridge);
+ goto err6;
+ }
+
return 0;
/* unwind in reverse order from the point of failure */
+err6:
+ iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge,
53);
err5:
iptablesRemoveTcpInput(driver->iptables, AF_INET6, network->def->bridge,
53);
err4:
@@ -1686,6 +1745,7 @@ networkRemoveGeneralIp6tablesRules(struct network_driver *driver,
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0))
return;
+ iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge,
547);
iptablesRemoveUdpInput(driver->iptables, AF_INET6, network->def->bridge,
53);
iptablesRemoveTcpInput(driver->iptables, AF_INET6, network->def->bridge,
53);
iptablesRemoveForwardAllowCross(driver->iptables, AF_INET6,
network->def->bridge);
@@ -2732,8 +2792,7 @@ networkValidate(struct network_driver *driver,
bool vlanUsed, vlanAllowed, badVlanUse = false;
virPortGroupDefPtr defaultPortGroup = NULL;
virNetworkIpDefPtr ipdef;
- bool ipv4def = false;
- int i;
+ bool ipv4def = false, ipv6def = false;
/* check for duplicate networks */
if (virNetworkObjIsDuplicate(&driver->networks, def, check_active) < 0)
@@ -2752,17 +2811,36 @@ networkValidate(struct network_driver *driver,
virNetworkSetBridgeMacAddr(def);
}
- /* We only support dhcp on one IPv4 address per defined network */
- for (i = 0; (ipdef = virNetworkDefGetIpByIndex(def, AF_INET, i)); i++) {
- if (ipdef->nranges || ipdef->nhosts) {
- if (ipv4def) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Multiple dhcp sections found. "
+ /* We only support dhcp on one IPv4 address and
+ * on one IPv6 address per defined network
+ */
+ for (ii = 0;
+ (ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, ii));
+ ii++) {
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
+ if (ipdef->nranges || ipdef->nhosts) {
+ if (ipv4def) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Multiple IPv4 dhcp sections found -- "
"dhcp is supported only for a "
"single IPv4 address on each network"));
- return -1;
- } else {
- ipv4def = true;
+ return -1;
+ } else {
+ ipv4def = true;
+ }
+ }
+ }
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
+ if (ipdef->nranges || ipdef->nhosts) {
+ if (ipv6def) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Multiple IPv6 dhcp sections found -- "
+ "dhcp is supported only for a "
+ "single IPv6 address on each network"));
+ return -1;
+ } else {
+ ipv6def = true;
+ }
}
}
}
diff --git a/src/util/dnsmasq.c b/src/util/dnsmasq.c
index 9d1c07b..b0cf3ce 100644
--- a/src/util/dnsmasq.c
+++ b/src/util/dnsmasq.c
@@ -304,7 +304,14 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile,
if (!(ipstr = virSocketAddrFormat(ip)))
return -1;
- if (name) {
+ /* the first test determins if it is a dhcpv6 host */
+ if (mac==NULL) {
+ if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
"%s,[%s]",
+ name, ipstr) < 0) {
+ goto alloc_error;
+ }
+ }
+ else if (name) {
if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
"%s,%s,%s",
mac, ipstr, name) < 0) {
goto alloc_error;
diff --git a/tests/networkxml2argvdata/dhcp6-network.argv
b/tests/networkxml2argvdata/dhcp6-network.argv
new file mode 100644
index 0000000..6697833
--- /dev/null
+++ b/tests/networkxml2argvdata/dhcp6-network.argv
@@ -0,0 +1,16 @@
+# dnsmasq conf file created by libvirt
+strict-order
+bind-interfaces
+except-interface=lo
+domain-needed
+local=/mynet/
+domain=mynet
+expand-hosts
+interface=virbr0
+listen-address=2001:db8:ac10:fe01::1
+listen-address=2001:db8:ac10:fd01::1
+dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff
+dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases
+dhcp-lease-max=240
+dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
+addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
diff --git a/tests/networkxml2argvdata/dhcp6-network.xml
b/tests/networkxml2argvdata/dhcp6-network.xml
new file mode 100644
index 0000000..990b403
--- /dev/null
+++ b/tests/networkxml2argvdata/dhcp6-network.xml
@@ -0,0 +1,16 @@
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward dev='eth1' mode='nat'/>
+ <bridge name='virbr0' stp='on' delay='0' />
+ <domain name='mynet'/>
+ <ip family='ipv6' address='2001:db8:ac10:fe01::1'
prefix='64'>
+ </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 name='paul' ip='2001:db8:ac10:fd01::1:21' />
+ </dhcp>
+ </ip>
+</network>
diff --git a/tests/networkxml2argvdata/isolated-network.argv
b/tests/networkxml2argvdata/isolated-network.argv
index abcde93..3a67cb4 100644
--- a/tests/networkxml2argvdata/isolated-network.argv
+++ b/tests/networkxml2argvdata/isolated-network.argv
@@ -9,8 +9,8 @@ no-resolv
interface=virbr2
listen-address=192.168.152.1
dhcp-range=192.168.152.2,192.168.152.254
+dhcp-no-override
dhcp-leasefile=/var/lib/libvirt/dnsmasq/private.leases
dhcp-lease-max=253
-dhcp-no-override
dhcp-hostsfile=/var/lib/libvirt/dnsmasq/private.hostsfile
addn-hosts=/var/lib/libvirt/dnsmasq/private.addnhosts
diff --git a/tests/networkxml2argvdata/nat-network-dhcp6.argv
b/tests/networkxml2argvdata/nat-network-dhcp6.argv
new file mode 100644
index 0000000..14256ae
--- /dev/null
+++ b/tests/networkxml2argvdata/nat-network-dhcp6.argv
@@ -0,0 +1,19 @@
+# dnsmasq conf file created by libvirt
+strict-order
+bind-interfaces
+except-interface=lo
+domain-needed
+local=//
+interface=virbr0
+listen-address=192.168.122.1
+listen-address=192.168.123.1
+listen-address=2001:db8:ac10:fe01::1
+listen-address=2001:db8:ac10:fd01::1
+listen-address=10.24.10.1
+dhcp-range=192.168.122.2,192.168.122.254
+dhcp-no-override
+dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff
+dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases
+dhcp-lease-max=493
+dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
+addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
diff --git a/tests/networkxml2argvdata/nat-network-dhcp6.xml
b/tests/networkxml2argvdata/nat-network-dhcp6.xml
new file mode 100644
index 0000000..f993a26
--- /dev/null
+++ b/tests/networkxml2argvdata/nat-network-dhcp6.xml
@@ -0,0 +1,26 @@
+<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>
+ </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'>
+ <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 name='paul' ip='2001:db8:ac10:fd01::1:21' />
+ </dhcp>
+ </ip>
+ <ip family='ipv4' address='10.24.10.1'>
+ </ip>
+</network>
diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv
b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv
index d87d438..45a658b 100644
--- a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv
+++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv
@@ -12,8 +12,8 @@ listen-address=2001:db8:ac10:fe01::1
listen-address=2001:db8:ac10:fd01::1
listen-address=10.24.10.1
dhcp-range=192.168.122.2,192.168.122.254
+dhcp-no-override
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-srv-record.argv
b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv
index 53882fe..13e80b9 100644
--- a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv
+++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv
@@ -12,8 +12,8 @@ listen-address=2001:db8:ac10:fe01::1
listen-address=2001:db8:ac10:fd01::1
listen-address=10.24.10.1
dhcp-range=192.168.122.2,192.168.122.254
+dhcp-no-override
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-txt-record.argv
b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv
index cc3ed28..7277132 100644
--- a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv
+++ b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv
@@ -12,8 +12,8 @@ listen-address=2001:db8:ac10:fe01::1
listen-address=2001:db8:ac10:fd01::1
listen-address=10.24.10.1
dhcp-range=192.168.122.2,192.168.122.254
+dhcp-no-override
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.argv
b/tests/networkxml2argvdata/nat-network.argv
index 431fffb..6e0161b 100644
--- a/tests/networkxml2argvdata/nat-network.argv
+++ b/tests/networkxml2argvdata/nat-network.argv
@@ -11,8 +11,8 @@ listen-address=2001:db8:ac10:fe01::1
listen-address=2001:db8:ac10:fd01::1
listen-address=10.24.10.1
dhcp-range=192.168.122.2,192.168.122.254
+dhcp-no-override
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/netboot-network.argv
b/tests/networkxml2argvdata/netboot-network.argv
index 8405095..025903b 100644
--- a/tests/networkxml2argvdata/netboot-network.argv
+++ b/tests/networkxml2argvdata/netboot-network.argv
@@ -9,11 +9,11 @@ expand-hosts
interface=virbr1
listen-address=192.168.122.1
dhcp-range=192.168.122.2,192.168.122.254
-dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases
-dhcp-lease-max=253
dhcp-no-override
-dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile
-addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts
enable-tftp
tftp-root=/var/lib/tftproot
dhcp-boot=pxeboot.img
+dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases
+dhcp-lease-max=253
+dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile
+addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts
diff --git a/tests/networkxml2argvdata/netboot-proxy-network.argv
b/tests/networkxml2argvdata/netboot-proxy-network.argv
index d7c8966..8a1cb51 100644
--- a/tests/networkxml2argvdata/netboot-proxy-network.argv
+++ b/tests/networkxml2argvdata/netboot-proxy-network.argv
@@ -9,9 +9,9 @@ expand-hosts
interface=virbr1
listen-address=192.168.122.1
dhcp-range=192.168.122.2,192.168.122.254
+dhcp-no-override
+dhcp-boot=pxeboot.img,,10.20.30.40
dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases
dhcp-lease-max=253
-dhcp-no-override
dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile
addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts
-dhcp-boot=pxeboot.img,,10.20.30.40
diff --git a/tests/networkxml2argvdata/routed-network-dhcphost.argv
b/tests/networkxml2argvdata/routed-network-dhcphost.argv
new file mode 100644
index 0000000..cf38381
--- /dev/null
+++ b/tests/networkxml2argvdata/routed-network-dhcphost.argv
@@ -0,0 +1,14 @@
+# dnsmasq conf file created by libvirt
+strict-order
+bind-interfaces
+except-interface=lo
+domain-needed
+local=//
+interface=virbr1
+listen-address=192.168.122.1
+listen-address=2001:db8:ac10:fd01::1
+dhcp-range=192.168.122.1,static
+dhcp-no-override
+dhcp-range=2001:db8:ac10:fd01::1,static
+dhcp-hostsfile=/var/lib/libvirt/dnsmasq/local.hostsfile
+addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts
diff --git a/tests/networkxml2argvdata/routed-network-dhcphost.xml
b/tests/networkxml2argvdata/routed-network-dhcphost.xml
new file mode 100644
index 0000000..38d9ebf
--- /dev/null
+++ b/tests/networkxml2argvdata/routed-network-dhcphost.xml
@@ -0,0 +1,19 @@
+<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 name='ralph' ip='2001:db8:ac10:fd01::1:20' />
+ <host name='paul' ip='2001:db8:ac10:fd01::1:21' />
+ </dhcp>
+ </ip>
+</network>
diff --git a/tests/networkxml2argvtest.c b/tests/networkxml2argvtest.c
index 3738734..ef32aa5 100644
--- a/tests/networkxml2argvtest.c
+++ b/tests/networkxml2argvtest.c
@@ -118,6 +118,9 @@ mymain(void)
DO_TEST("nat-network-dns-srv-record");
DO_TEST("nat-network-dns-srv-record-minimal");
DO_TEST("nat-network-dns-hosts");
+ DO_TEST("nat-network-dhcp6");
+ DO_TEST("routed-network-dhcphost");
+ DO_TEST("dhcp6-network");
return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
--
1.7.11.7