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
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> are support <span class="since">Since 0.8.7</span>.
+ Similar to IPv4, one IPv6 address per network can also have
+ a <code>dhcp</code> definition. <span class="since">Since 1.0.1</span>
+
<dl>
<dt><code>tftp</code></dt>
<dd>Immediately within
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
- <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>
+ <code>dhcp</code> element supported for both
+ IPv4 <span class="since">Since 0.3.0</span>
+ and IPv6 <span class="since">Since 1.0.1</span>, but
+ only for one IP address of each type per network.
<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
+ IPv4 <code>host</code> 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>
+ An IPv6 <code>host</code> element differs slightly 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 also 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
<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>
<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>
<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>
</zeroOrMore>
<zeroOrMore>
<element name="host">
- <attribute name="ip"><ref name="ipv4Addr"/></attribute>
+ <attribute name="ip"><ref name="ipAddr"/></attribute>
<oneOrMore>
<element name="hostname"><ref name="dnsName"/></element>
</oneOrMore>
<element name="dhcp">
<zeroOrMore>
<element name="range">
- <attribute name="start"><ref name="ipv4Addr"/></attribute>
- <attribute name="end"><ref name="ipv4Addr"/></attribute>
+ <attribute name="start"><ref name="ipAddr"/></attribute>
+ <attribute name="end"><ref name="ipAddr"/></attribute>
</element>
</zeroOrMore>
<zeroOrMore>
<element name="host">
- <attribute name="mac"><ref name="uniMacAddr"/></attribute>
+ <optional>
+ <attribute name="mac"><ref name="uniMacAddr"/></attribute>
+ </optional>
<attribute name="name"><text/></attribute>
- <attribute name="ip"><ref name="ipv4Addr"/></attribute>
+ <attribute name="ip"><ref name="ipAddr"/></attribute>
</element>
</zeroOrMore>
<optional>
static int
virNetworkDHCPHostDefParseXML(const char *networkName,
+ const virNetworkIpDefPtr def,
xmlNodePtr node,
virNetworkDHCPHostDefPtr host,
bool partialOkay)
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 network '%s' IPv6 static host definition"),
+ mac, networkName);
+ goto cleanup;
+ }
if (virMacAddrParse(mac, &addr) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Cannot parse MAC address '%s' in network '%s'"),
networkName);
}
} else {
- /* normal usage - you need at least one MAC address or one host name */
- if (!(mac || name)) {
+ /* normal usage - you need at least name (IPv6) or one of MAC
+ * address or name (IPv4)
+ */
+ 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;
+ }
+ } 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;
virReportOOMError();
return -1;
}
- if (virNetworkDHCPHostDefParseXML(networkName, cur,
+ if (virNetworkDHCPHostDefParseXML(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")) {
+ } else if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) &&
+ cur->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(cur->name, BAD_CAST "bootp")) {
char *file;
char *server;
virSocketAddr inaddr;
}
}
- if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
- /* parse IPv4-related info */
- cur = node->children;
- while (cur != NULL) {
- if (cur->type == XML_ELEMENT_NODE &&
- xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
- result = virNetworkDHCPDefParseXML(networkName, cur, def);
- if (result)
- goto cleanup;
-
- } else if (cur->type == XML_ELEMENT_NODE &&
- xmlStrEqual(cur->name, BAD_CAST "tftp")) {
- char *root;
-
- if (!(root = virXMLPropString(cur, "root"))) {
- cur = cur->next;
- continue;
- }
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
+ if (virNetworkDHCPDefParseXML(networkName, cur, def) < 0)
+ goto cleanup;
+ } else if (cur->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(cur->name, BAD_CAST "tftp")) {
+ char *root;
- def->tftproot = (char *)root;
+ if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unsupported <tftp> element in an IPv6 element in network '%s'"),
+ networkName);
+ goto cleanup;
}
-
- cur = cur->next;
+ if (!(root = virXMLPropString(cur, "root"))) {
+ cur = cur->next;
+ continue;
+ }
+ def->tftproot = (char *)root;
}
+ cur = cur->next;
}
result = 0;
/* 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'> "
+ _("couldn't update dhcp host entry - no <ip> "
"element found at index %d in network '%s'"),
parentIndex, def->name);
}
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'> "
+ _("couldn't update dhcp host entry - no <ip> "
"element found in network '%s'"), def->name);
}
return ipdef;
/* parse the xml into a virNetworkDHCPHostDef */
if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
- if (virNetworkDHCPHostDefParseXML(def->name, ctxt->node, &host, false) < 0)
+ if (virNetworkDHCPHostDefParseXML(def->name, ipdef,
+ ctxt->node, &host, false) < 0) {
goto cleanup;
+ }
/* search for the entry with this (mac|name),
* and update the IP+(mac|name) */
} else if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
(command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) {
- if (virNetworkDHCPHostDefParseXML(def->name, ctxt->node, &host, true) < 0)
+ if (virNetworkDHCPHostDefParseXML(def->name, ipdef,
+ ctxt->node, &host, true) < 0) {
goto cleanup;
+ }
/* log error if an entry with same name/address/ip already exists */
for (ii = 0; ii < ipdef->nhosts; ii++) {
}
} else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
- if (virNetworkDHCPHostDefParseXML(def->name, ctxt->node, &host, false) < 0)
+ if (virNetworkDHCPHostDefParseXML(def->name, ipdef,
+ ctxt->node, &host, false) < 0) {
goto cleanup;
+ }
/* find matching entry - all specified attributes must match */
for (ii = 0; ii < ipdef->nhosts; ii++) {
+
/*
* bridge_driver.c: core driver methods for managing network
*
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;
+ bool ipv6 = false;
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
+ ipv6 = true;
for (i = 0; i < ipdef->nhosts; i++) {
virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
- if ((host->mac) && VIR_SOCKET_ADDR_VALID(&host->ip))
- if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip, host->name) < 0)
+ if (VIR_SOCKET_ADDR_VALID(&host->ip))
+ if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip, host->name, ipv6) < 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++) {
virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
static int
networkBuildDnsmasqArgv(virNetworkObjPtr network,
- virNetworkIpDefPtr ipdef,
const char *pidfile,
virCommandPtr cmd,
dnsmasqContext *dctx,
char *recordWeight = NULL;
char *recordPriority = NULL;
virNetworkDNSDefPtr dns = &network->def->dns;
- virNetworkIpDefPtr tmpipdef;
+ virNetworkIpDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
+ bool ipv6SLAAC;
/*
* NB, be careful about syntax for dnsmasq options in long format.
* Needed to ensure dnsmasq uses same algorithm for processing
* multiple namedriver entries in /etc/resolv.conf as GLibC.
*/
- virCommandAddArg(cmd, "--strict-order");
+ virCommandAddArgList(cmd, "--strict-order",
+ "--domain-needed",
+ NULL);
- if (network->def->domain)
+ if (network->def->domain) {
virCommandAddArgPair(cmd, "--domain", network->def->domain);
+ virCommandAddArg(cmd, "--expand-hosts");
+ }
/* need to specify local even if no domain specified */
virCommandAddArgFormat(cmd, "--local=/%s/",
network->def->domain ? network->def->domain : "");
- virCommandAddArg(cmd, "--domain-needed");
if (pidfile)
virCommandAddArgPair(cmd, "--pid-file", pidfile);
}
}
- if (ipdef) {
+ /* Find the first dhcp for both IPv4 and IPv6 */
+ for (ii = 0, ipv4def = NULL, ipv6def = NULL, ipv6SLAAC = 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) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("For IPv4, multiple DHCP definitions cannot "
+ "be specified."));
+ goto cleanup;
+ } else {
+ ipv4def = ipdef;
+ }
+ }
+ }
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
+ if (ipdef->nranges || ipdef->nhosts) {
+ if (!DNSMASQ_DHCPv6_SUPPORT(caps)) {
+ unsigned long version = dnsmasqCapsGetVersion(caps);
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("The version of dnsmasq on this host (%d.%d) doesn't "
+ "adequately support IPv6 dhcp range or dhcp host "
+ "specification. Version %d.%d or later is required."),
+ (int)version / 1000000, (int)(version % 1000000) / 1000,
+ DNSMASQ_DHCPv6_MAJOR_REQD, DNSMASQ_DHCPv6_MINOR_REQD);
+ goto cleanup;
+ }
+ if (ipv6def) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("For IPv6, multiple DHCP definitions cannot "
+ "be specified."));
+ goto cleanup;
+ } else {
+ ipv6def = ipdef;
+ }
+ } else {
+ ipv6SLAAC = true;
+ }
+ }
+ }
+
+ if (ipv6def && ipv6SLAAC) {
+ VIR_WARN("For IPv6, when DHCP is specified for one address, then "
+ "state-full Router Advertising will occur. The additional "
+ "IPv6 addresses specified require manually configured guest "
+ "network to work properly since both state-full (DHCP) "
+ "and state-less (SLAAC) addressing are not supported "
+ "on the same network interface.");
+ }
+
+ ipdef = ipv4def ? ipv4def : ipv6def;
+
+ while (ipdef) {
for (r = 0 ; r < ipdef->nranges ; r++) {
char *saddr = virSocketAddrFormat(&ipdef->ranges[r].start);
if (!saddr)
/*
* 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);
VIR_FREE(bridgeaddr);
}
- if (ipdef->nranges > 0) {
- char *leasefile = networkDnsmasqLeaseFileName(network->def->name);
- if (!leasefile)
- goto cleanup;
- virCommandAddArgFormat(cmd, "--dhcp-leasefile=%s", leasefile);
- VIR_FREE(leasefile);
- virCommandAddArgFormat(cmd, "--dhcp-lease-max=%d", nbleases);
- }
-
- if (ipdef->nranges || ipdef->nhosts)
- virCommandAddArg(cmd, "--dhcp-no-override");
+ if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
+ goto cleanup;
- /* add domain to any non-qualified hostnames in /etc/hosts or addn-hosts */
- if (network->def->domain)
- virCommandAddArg(cmd, "--expand-hosts");
+ /* Note: the following is IPv4 only */
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
+ if (ipdef->nranges || ipdef->nhosts)
+ virCommandAddArg(cmd, "--dhcp-no-override");
- if (networkBuildDnsmasqHostsfile(dctx, ipdef, &network->def->dns) < 0)
- goto cleanup;
+ if (ipdef->tftproot) {
+ virCommandAddArgList(cmd, "--enable-tftp",
+ "--tftp-root", ipdef->tftproot,
+ NULL);
+ }
- /* 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)
- virCommandAddArgPair(cmd, "--dhcp-hostsfile",
- dctx->hostsfile->path);
+ if (ipdef->bootfile) {
+ virCommandAddArg(cmd, "--dhcp-boot");
+ if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
+ char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
- /* Likewise, always create this file and put it on the commandline, to allow for
- * for runtime additions.
- */
- virCommandAddArgPair(cmd, "--addn-hosts",
- dctx->addnhostsfile->path);
+ if (!bootserver) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ virCommandAddArgFormat(cmd, "%s%s%s",
+ ipdef->bootfile, ",,", bootserver);
+ VIR_FREE(bootserver);
+ } else {
+ virCommandAddArg(cmd, ipdef->bootfile);
+ }
+ }
+ }
+ ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
+ }
- if (ipdef->tftproot) {
- virCommandAddArgList(cmd, "--enable-tftp",
- "--tftp-root", ipdef->tftproot,
- NULL);
+ if (nbleases > 0) {
+ char *leasefile = networkDnsmasqLeaseFileName(network->def->name);
+ if (!leasefile) {
+ virReportOOMError();
+ goto cleanup;
}
- if (ipdef->bootfile) {
- virCommandAddArg(cmd, "--dhcp-boot");
- if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
- char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
+ virCommandAddArgFormat(cmd, "--dhcp-leasefile=%s", leasefile);
+ VIR_FREE(leasefile);
+ virCommandAddArgFormat(cmd, "--dhcp-lease-max=%d", nbleases);
+ }
- if (!bootserver)
- goto cleanup;
- virCommandAddArgFormat(cmd, "%s%s%s",
- ipdef->bootfile, ",,", bootserver);
- VIR_FREE(bootserver);
- } else {
- virCommandAddArg(cmd, ipdef->bootfile);
+ /* this is done once per interface */
+ if (networkBuildDnsmasqHostsList(dctx, 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 (ipv4def || ipv6def)
+ virCommandAddArgPair(cmd, "--dhcp-hostsfile",
+ dctx->hostsfile->path);
+
+ /* Likewise, always create this file and put it on the commandline,
+ * to allow for runtime additions.
+ */
+ virCommandAddArgPair(cmd, "--addn-hosts",
+ dctx->addnhostsfile->path);
+
+ /* Are we doing RA instead of radvd? */
+ if (DNSMASQ_RA_SUPPORT(caps)) {
+ if (ipv6def)
+ virCommandAddArg(cmd, "--enable-ra");
+ else {
+ for (ii = 0;
+ (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, ii));
+ ii++) {
+ if (!(ipdef->nranges || ipdef->nhosts)) {
+ char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
+ if (!bridgeaddr)
+ goto cleanup;
+ virCommandAddArgFormat(cmd, "--dhcp-range=%s,ra-only",
+ bridgeaddr);
+ VIR_FREE(bridgeaddr);
+ }
}
}
}
ret = 0;
+
cleanup:
VIR_FREE(record);
VIR_FREE(recordPort);
dnsmasqCapsPtr caps)
{
virCommandPtr cmd = NULL;
- int ret = -1, ii;
- virNetworkIpDefPtr ipdef;
+ int ret = -1;
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,
- * we should continue and run dnsmasq, just for the DNS capabilities.
- */
- if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0))
- return 0;
-
cmd = virCommandNew(dnsmasqCapsGetBinaryPath(caps));
- if (networkBuildDnsmasqArgv(network, ipdef, pidfile, cmd, dctx, caps) < 0) {
+ if (networkBuildDnsmasqArgv(network, pidfile, cmd, dctx, caps) < 0) {
goto cleanup;
}
char *pidfile = 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 */
+ /* no IP addresses, so we don't need to run */
ret = 0;
goto cleanup;
}
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;
/* networkRefreshDhcpDaemon:
* Update dnsmasq config files, then send a SIGHUP so that it rereads
- * them.
+ * them. This only works for the dhcp-hostsfile and the
+ * addn-hosts file.
*
* Returns 0 on success, -1 on failure.
*/
virNetworkObjPtr network)
{
int ret = -1, ii;
- virNetworkIpDefPtr ipdef;
+ virNetworkIpDefPtr ipdef, ipv4def, ipv6def;
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(driver, network);
- /* Look for first IPv4 address that has dhcp defined. */
- /* We support dhcp config on 1 IPv4 interface only. */
+ VIR_INFO("Refreshing dnsmasq for network %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 one IPv4 subnetwork
+ * and on one IPv6 subnetwork.
+ */
+ ipv4def = NULL;
for (ii = 0;
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, ii));
ii++) {
- if (ipdef->nranges || ipdef->nhosts)
- break;
+ if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
+ ipv4def = ipdef;
}
/* 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;
+ ipv6def = NULL;
+ for (ii = 0;
+ (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, ii));
+ ii++) {
+ if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
+ ipv6def = ipdef;
}
- if (!(dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR)))
- goto cleanup;
+ if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
+ goto cleanup;
+
+ if (ipv6def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv6def) < 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)
return networkStartDhcpDaemon(driver, 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)
{
virBuffer configbuf = VIR_BUFFER_INITIALIZER;
int ret = -1, ii;
virNetworkIpDefPtr ipdef;
- bool v6present = false;
+ bool v6present = false, dhcp6 = false;
*configstr = NULL;
+ /* Check if DHCPv6 is needed */
+ for (ii = 0;
+ (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, ii));
+ ii++) {
+ v6present = true;
+ if (ipdef->nranges || ipdef->nhosts) {
+ 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;
int prefix;
char *netaddr;
- v6present = true;
prefix = virNetworkIpDefPrefix(ipdef);
if (prefix < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
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);
}
}
static int
-networkStartRadvd(virNetworkObjPtr network)
+networkStartRadvd(struct network_driver *driver ATTRIBUTE_UNUSED,
+ virNetworkObjPtr network)
{
char *pidfile = NULL;
char *radvdpidbase = NULL;
network->radvdPid = -1;
+ /* Is dnsmasq handling RA? */
+ if (DNSMASQ_RA_SUPPORT(driver->dnsmasqCaps)) {
+ ret = 0;
+ goto cleanup;
+ }
+
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
/* no IPv6 addresses, so we don't need to run radvd */
ret = 0;
networkRefreshRadvd(struct network_driver *driver ATTRIBUTE_UNUSED,
virNetworkObjPtr network)
{
+ char *radvdpidbase;
+
+ /* Is dnsmasq handling RA? */
+ if (DNSMASQ_RA_SUPPORT(driver->dnsmasqCaps)) {
+ if (network->radvdPid <= 0)
+ return 0;
+ /* radvd should not be running but in case it is */
+ if ((networkKillDaemon(network->radvdPid, "radvd",
+ network->def->name) >= 0) &&
+ ((radvdpidbase = networkRadvdPidfileBasename(network->def->name))
+ != NULL)) {
+ virPidFileDelete(NETWORK_PID_DIR, radvdpidbase);
+ VIR_FREE(radvdpidbase);
+ }
+ network->radvdPid = -1;
+ return 0;
+ }
+
/* if there's no running radvd, just start it */
if (network->radvdPid <= 0 || (kill(network->radvdPid, 0) < 0))
- return networkStartRadvd(network);
+ return networkStartRadvd(driver, network);
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
/* no IPv6 addresses, so we don't need to run radvd */
* since there's really no better recovery to be done than to
* just push ahead (and that may be exactly what's needed).
*/
- if ((networkKillDaemon(network->dnsmasqPid, "radvd",
+ if ((networkKillDaemon(network->radvdPid, "radvd",
network->def->name) >= 0) &&
((radvdpidbase = networkRadvdPidfileBasename(network->def->name))
!= NULL)) {
}
/* Add all once/network rules required for IPv6.
-
* If no IPv6 addresses are defined and <network ipv6='yes'> is
- * specified, then allow IPv6 commuinications between guests connected
- * to this network. If any IPv6 addresses are defined, then add all
- * rules for regular operation (including inter-guest communication).
+ * specified, then allow IPv6 commuinications between virtual systems.
+ * If any IPv6 addresses are defined, then add the rules for regular operation.
*/
static int
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:
virNetworkObjPtr network)
{
if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0) &&
- !network->def->ipv6nogw)
+ !network->def->ipv6nogw) {
return;
+ }
if (virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
+ 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);
}
goto err3;
/* start radvd if there are any ipv6 addresses */
- if (v6present && networkStartRadvd(network) < 0)
+ if (v6present && networkStartRadvd(driver, network) < 0)
goto err4;
/* DAD has happened (dnsmasq waits for it), dnsmasq is now bound to the
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)
}
}
- /* 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;
+ }
}
}
}
VIR_FREE(hostsfile);
}
+/* Note: There are many additional dhcp-host specifications
+ * supported by dnsmasq. There are only the basic ones.
+ */
static int
hostsfileAdd(dnsmasqHostsfile *hostsfile,
const char *mac,
virSocketAddr *ip,
- const char *name)
+ const char *name,
+ bool ipv6)
{
char *ipstr = NULL;
if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0)
if (!(ipstr = virSocketAddrFormat(ip)))
return -1;
- if (name) {
+ /* 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 (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s",
- mac, ipstr, name) < 0) {
+ mac, ipstr, name) < 0)
+ goto alloc_error;
+ } else if (name && !mac){
+ if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s",
+ name, ipstr) < 0)
goto alloc_error;
- }
} else {
if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s",
- mac, ipstr) < 0) {
+ mac, ipstr) < 0)
goto alloc_error;
- }
}
VIR_FREE(ipstr);
dnsmasqAddDhcpHost(dnsmasqContext *ctx,
const char *mac,
virSocketAddr *ip,
- const char *name)
+ const char *name,
+ bool ipv6)
{
- return hostsfileAdd(ctx->hostsfile, mac, ip, name);
+ return hostsfileAdd(ctx->hostsfile, mac, ip, name, ipv6);
}
/*
int dnsmasqAddDhcpHost(dnsmasqContext *ctx,
const char *mac,
virSocketAddr *ip,
- const char *name);
+ const char *name,
+ bool ipv6);
int dnsmasqAddHost(dnsmasqContext *ctx,
virSocketAddr *ip,
const char *name);
bool dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag);
const char *dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps);
unsigned long dnsmasqCapsGetVersion(dnsmasqCapsPtr caps);
+
+# define DNSMASQ_DHCPv6_MAJOR_REQD 2
+# define DNSMASQ_DHCPv6_MINOR_REQD 64
+# define DNSMASQ_RA_MAJOR_REQD 2
+# define DNSMASQ_RA_MINOR_REQD 64
+
+# define DNSMASQ_DHCPv6_SUPPORT(CAPS) \
+ (dnsmasqCapsGetVersion(CAPS) >= \
+ (DNSMASQ_DHCPv6_MAJOR_REQD * 1000000) + \
+ (DNSMASQ_DHCPv6_MINOR_REQD * 1000))
+# define DNSMASQ_RA_SUPPORT(CAPS) \
+ (dnsmasqCapsGetVersion(CAPS) >= \
+ (DNSMASQ_RA_MAJOR_REQD * 1000000) + \
+ (DNSMASQ_RA_MINOR_REQD * 1000))
#endif /* __DNSMASQ_H__ */
--- /dev/null
+@DNSMASQ@ \
+--strict-order \
+--domain-needed \
+--local=// \
+--conf-file= \
+--bind-dynamic \
+--interface virbr0 \
+--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 \
+--enable-ra\
--- /dev/null
+<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: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>
--- /dev/null
+@DNSMASQ@ \
+--strict-order \
+--domain-needed \
+--domain=mynet \
+--expand-hosts \
+--local=/mynet/ \
+--conf-file= \
+--bind-dynamic \
+--interface virbr0 \
+--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 \
+--enable-ra\
--- /dev/null
+<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: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>
--- /dev/null
+@DNSMASQ@ \
+--strict-order \
+--domain-needed \
+--local=// \
+--conf-file= \
+--bind-dynamic \
+--interface virbr1 \
+--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 \
+--enable-ra\
--- /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 name='ralph' ip='2001:db8:ac10:fd01::1:20' />
+ <host name='paul' ip='2001:db8:ac10:fd01::1:21' />
+ </dhcp>
+ </ip>
+</network>
-@DNSMASQ@ --strict-order \
---local=// --domain-needed --conf-file= \
---bind-interfaces --except-interface lo \
+@DNSMASQ@ \
+--strict-order \
+--domain-needed \
+--local=// \
+--conf-file= \
+--bind-interfaces \
+--except-interface lo \
--listen-address 192.168.152.1 \
---dhcp-option=3 --no-resolv \
+--dhcp-option=3 \
+--no-resolv \
--dhcp-range 192.168.152.2,192.168.152.254 \
---dhcp-leasefile=/var/lib/libvirt/dnsmasq/private.leases --dhcp-lease-max=253 \
--dhcp-no-override \
+--dhcp-leasefile=/var/lib/libvirt/dnsmasq/private.leases \
+--dhcp-lease-max=253 \
--dhcp-hostsfile=/var/lib/libvirt/dnsmasq/private.hostsfile \
--addn-hosts=/var/lib/libvirt/dnsmasq/private.addnhosts\
-@DNSMASQ@ --strict-order --domain=example.com \
---local=/example.com/ --domain-needed \
+@DNSMASQ@ \
+--strict-order \
+--domain-needed \
+--domain=example.com \
+--expand-hosts \
+--local=/example.com/ \
--conf-file= \
---bind-dynamic --interface virbr0 \
---expand-hosts --addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\
+--bind-dynamic \
+--interface virbr0 \
+--addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\
@DNSMASQ@ \
--strict-order \
---local=// --domain-needed --conf-file= \
---bind-interfaces --except-interface lo \
+--domain-needed \
+--local=// \
+--conf-file= \
+--bind-interfaces \
+--except-interface lo \
--listen-address 192.168.122.1 \
--listen-address 192.168.123.1 \
--listen-address fc00:db8:ac10:fe01::1 \
--listen-address 10.24.10.1 \
--srv-host=name.tcp.,,,, \
--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\
@DNSMASQ@ \
--strict-order \
---local=// --domain-needed --conf-file= \
---bind-dynamic --interface virbr0 \
+--domain-needed \
+--local=// \
+--conf-file= \
+--bind-dynamic \
+--interface virbr0 \
--srv-host=name.tcp.test-domain-name,.,1024,10,10 \
--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\
-@DNSMASQ@ --strict-order \
---local=// --domain-needed --conf-file= \
+@DNSMASQ@ \
+--strict-order \
+--domain-needed \
+--local=// \
+--conf-file= \
--bind-dynamic --interface virbr0 \
'--txt-record=example,example value' \
--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-lease-max=253 \
--dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile \
--addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\
-@DNSMASQ@ --strict-order \
---local=// --domain-needed --conf-file= \
---bind-dynamic --interface virbr0 \
+@DNSMASQ@ \
+--strict-order \
+--domain-needed \
+--local=// \
+--conf-file= \
+--bind-dynamic \
+--interface virbr0 \
--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-lease-max=253 \
--dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile \
---addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\
+--addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts \
+--dhcp-range=2001:db8:ac10:fe01::1,ra-only \
+--dhcp-range=2001:db8:ac10:fd01::1,ra-only\
-@DNSMASQ@ --strict-order --domain=example.com \
---local=/example.com/ --domain-needed --conf-file= \
---bind-interfaces --except-interface lo --listen-address 192.168.122.1 \
+@DNSMASQ@ \
+--strict-order \
+--domain-needed \
+--domain=example.com \
+--expand-hosts \
+--local=/example.com/ \
+--conf-file= \
+--bind-interfaces \
+--except-interface lo \
+--listen-address 192.168.122.1 \
--dhcp-range 192.168.122.2,192.168.122.254 \
+--dhcp-no-override \
+--enable-tftp \
+--tftp-root /var/lib/tftproot \
+--dhcp-boot pxeboot.img \
--dhcp-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases \
---dhcp-lease-max=253 --dhcp-no-override --expand-hosts \
+--dhcp-lease-max=253 \
--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\
+--addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts\
-@DNSMASQ@ --strict-order --domain=example.com \
---local=/example.com/ --domain-needed --conf-file= \
---bind-interfaces --except-interface lo \
+@DNSMASQ@ \
+--strict-order \
+--domain-needed \
+--domain=example.com \
+--expand-hosts \
+--local=/example.com/ \
+--conf-file= \
+--bind-interfaces \
+--except-interface lo \
--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 --expand-hosts \
+--dhcp-lease-max=253 \
--dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile \
---addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts \
---dhcp-boot pxeboot.img,,10.20.30.40\
+--addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts\
-@DNSMASQ@ --strict-order \
---local=// --domain-needed --conf-file= \
---bind-dynamic --interface virbr1 \
+@DNSMASQ@ \
+--strict-order \
+--domain-needed \
+--local=// \
+--conf-file= \
+--bind-dynamic \
+--interface virbr1 \
--addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts\
= dnsmasqCapsNewFromBuffer("Dnsmasq version 2.48", DNSMASQ);
dnsmasqCapsPtr full
= dnsmasqCapsNewFromBuffer("Dnsmasq version 2.63\n--bind-dynamic", DNSMASQ);
+ dnsmasqCapsPtr dhcpv6
+ = dnsmasqCapsNewFromBuffer("Dnsmasq version 2.64\n--bind-dynamic", DNSMASQ);
networkDnsmasqLeaseFileName = testDnsmasqLeaseFileName;
DO_TEST("netboot-proxy-network", restricted);
DO_TEST("nat-network-dns-srv-record-minimal", restricted);
DO_TEST("routed-network", full);
- DO_TEST("nat-network", full);
+ DO_TEST("nat-network", dhcpv6);
DO_TEST("nat-network-dns-txt-record", full);
DO_TEST("nat-network-dns-srv-record", full);
DO_TEST("nat-network-dns-hosts", full);
+ DO_TEST("dhcp6-network", dhcpv6);
+ DO_TEST("dhcp6-nat-network", dhcpv6);
+ DO_TEST("dhcp6host-routed-network", dhcpv6);
return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
}