network: add support for DHCPv6

The DHCPv6 support includes IPV6 dhcp-range and dhcp-host for one
IPv6 subnetwork on one interface.  This support will only work
if dnsmasq version >= 2.64; otherwise an error occurs if
dhcp-range or dhcp-host is specified for an IPv6 address.

Essentially, this change provides the same DHCP support for IPv6
that has been available for IPv4.

With dnsmasq >= 2.64, support for the RA service is also now provided
by dnsmasq (radvd is no longer used/started). (Although at least one
version of dnsmasq prior to 2.64 "supported" IPv6 Router
Advertisement, there were bugs (fixed in 2.64) that rendered it
unusable.)

Documentation and the network schema has been updated
to reflect the new support.
This commit is contained in:
Gene Czarcinski 2012-12-06 12:20:38 -05:00 committed by Laine Stump
parent 71e30eff46
commit 2d5cd1d724
22 changed files with 697 additions and 251 deletions

View File

@ -583,8 +583,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
@ -593,10 +595,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> 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
@ -614,30 +619,44 @@
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
@ -680,6 +699,29 @@
&lt;ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" /&gt;
&lt;/network&gt;</pre>
<p>
Below is a variation of the above example which adds an IPv6
dhcp range definition.
</p>
<pre>
&lt;network&gt;
&lt;name&gt;default6&lt;/name&gt;
&lt;bridge name="virbr0" /&gt;
&lt;forward mode="nat"/&gt;
&lt;ip address="192.168.122.1" netmask="255.255.255.0"&gt;
&lt;dhcp&gt;
&lt;range start="192.168.122.2" end="192.168.122.254" /&gt;
&lt;/dhcp&gt;
&lt;/ip&gt;
&lt;ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" &gt;
&lt;dhcp&gt;
&lt;range start="2001:db8:ca2:2:1::10" end="2001:db8:ca2:2:1::ff" /&gt;
&lt;/dhcp&gt;
&lt;/ip&gt;
&lt;/network&gt;</pre>
<h3><a name="examplesRoute">Routed network config</a></h3>
<p>
@ -704,6 +746,29 @@
&lt;ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" /&gt;
&lt;/network&gt;</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>
&lt;network&gt;
&lt;name&gt;local6&lt;/name&gt;
&lt;bridge name="virbr1" /&gt;
&lt;forward mode="route" dev="eth1"/&gt;
&lt;ip address="192.168.122.1" netmask="255.255.255.0"&gt;
&lt;dhcp&gt;
&lt;range start="192.168.122.2" end="192.168.122.254" /&gt;
&lt;/dhcp&gt;
&lt;/ip&gt;
&lt;ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" &gt;
&lt;dhcp&gt;
&lt;host name="paul" ip="2001:db8:ca2:2:3::1" /&gt;
&lt;host name="bob" ip="2001:db8:ca2:2:3::2" /&gt;
&lt;/dhcp&gt;
&lt;/ip&gt;
&lt;/network&gt;</pre>
<h3><a name="examplesPrivate">Isolated network config</a></h3>
<p>
@ -726,6 +791,24 @@
&lt;ip family="ipv6" address="2001:db8:ca2:3::1" prefix="64" /&gt;
&lt;/network&gt;</pre>
<h3><a name="examplesPrivate6">Isolated IPv6 network config</a></h3>
<p>
This variation of an isolated network defines only IPv6.
</p>
<pre>
&lt;network&gt;
&lt;name&gt;sixnet&lt;/name&gt;
&lt;bridge name="virbr6" /&gt;
&lt;ip family="ipv6" address="2001:db8:ca2:6::1" prefix="64" &gt;
&lt;dhcp&gt;
&lt;host name="peter" ip="2001:db8:ca2:6:6::1" /&gt;
&lt;host name="dariusz" ip="2001:db8:ca2:6:6::2" /&gt;
&lt;/dhcp&gt;
&lt;/ip&gt;
&lt;/network&gt;</pre>
<h3><a name="examplesBridge">Using an existing host bridge</a></h3>
<p>

View File

@ -218,7 +218,7 @@
</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>
@ -272,15 +272,17 @@
<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>

View File

@ -654,6 +654,7 @@ cleanup:
static int
virNetworkDHCPHostDefParseXML(const char *networkName,
const virNetworkIpDefPtr def,
xmlNodePtr node,
virNetworkDHCPHostDefPtr host,
bool partialOkay)
@ -665,6 +666,13 @@ virNetworkDHCPHostDefParseXML(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 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'"),
@ -707,10 +715,20 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
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;
@ -769,15 +787,16 @@ virNetworkDHCPDefParseXML(const char *networkName,
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;
@ -1189,30 +1208,29 @@ virNetworkIPDefParseXML(const char *networkName,
}
}
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;
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;
} else if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "tftp")) {
char *root;
if (!(root = virXMLPropString(cur, "root"))) {
cur = cur->next;
continue;
}
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;
@ -2494,11 +2512,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'> "
_("couldn't update dhcp host entry - no <ip> "
"element found at index %d in network '%s'"),
parentIndex, def->name);
}
@ -2511,17 +2527,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'> "
_("couldn't update dhcp host entry - no <ip> "
"element found in network '%s'"), def->name);
}
return ipdef;
@ -2551,8 +2567,10 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def,
/* 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) */
@ -2584,8 +2602,10 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def,
} 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++) {
@ -2618,8 +2638,10 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def,
}
} 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++) {

View File

@ -1,3 +1,4 @@
/*
* bridge_driver.c: core driver methods for managing network
*
@ -564,20 +565,35 @@ 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,
networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
virNetworkIpDefPtr ipdef)
{
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 (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;
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)
return -1;
}
if (dnsdef) {
for (i = 0; i < dnsdef->nhosts; i++) {
virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
@ -595,7 +611,6 @@ networkBuildDnsmasqHostsfile(dnsmasqContext *dctx,
static int
networkBuildDnsmasqArgv(virNetworkObjPtr network,
virNetworkIpDefPtr ipdef,
const char *pidfile,
virCommandPtr cmd,
dnsmasqContext *dctx,
@ -609,7 +624,8 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
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.
@ -634,14 +650,17 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
* 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);
@ -763,7 +782,60 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
}
}
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)
@ -784,7 +856,7 @@ networkBuildDnsmasqArgv(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,61 +867,91 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
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");
/* add domain to any non-qualified hostnames in /etc/hosts or addn-hosts */
if (network->def->domain)
virCommandAddArg(cmd, "--expand-hosts");
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)
virCommandAddArgPair(cmd, "--dhcp-hostsfile",
dctx->hostsfile->path);
/* 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");
/* 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 (ipdef->tftproot) {
virCommandAddArgList(cmd, "--enable-tftp",
"--tftp-root", ipdef->tftproot,
NULL);
}
if (ipdef->tftproot) {
virCommandAddArgList(cmd, "--enable-tftp",
"--tftp-root", ipdef->tftproot,
NULL);
}
if (ipdef->bootfile) {
virCommandAddArg(cmd, "--dhcp-boot");
if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
if (ipdef->bootfile) {
virCommandAddArg(cmd, "--dhcp-boot");
if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
if (!bootserver)
goto cleanup;
virCommandAddArgFormat(cmd, "%s%s%s",
if (!bootserver) {
virReportOOMError();
goto cleanup;
}
virCommandAddArgFormat(cmd, "%s%s%s",
ipdef->bootfile, ",,", bootserver);
VIR_FREE(bootserver);
} else {
virCommandAddArg(cmd, ipdef->bootfile);
VIR_FREE(bootserver);
} else {
virCommandAddArg(cmd, ipdef->bootfile);
}
}
}
ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
}
if (nbleases > 0) {
char *leasefile = networkDnsmasqLeaseFileName(network->def->name);
if (!leasefile) {
virReportOOMError();
goto cleanup;
}
virCommandAddArgFormat(cmd, "--dhcp-leasefile=%s", leasefile);
VIR_FREE(leasefile);
virCommandAddArgFormat(cmd, "--dhcp-lease-max=%d", nbleases);
}
/* 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);
@ -864,33 +966,12 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdou
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;
}
@ -911,11 +992,9 @@ networkStartDhcpDaemon(struct network_driver *driver,
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;
}
@ -956,18 +1035,6 @@ networkStartDhcpDaemon(struct network_driver *driver,
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;
@ -1000,7 +1067,8 @@ 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.
*/
@ -1009,34 +1077,51 @@ networkRefreshDhcpDaemon(struct network_driver *driver,
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 (networkBuildDnsmasqHostsfile(dctx, ipdef, &network->def->dns) < 0)
if (ipv6def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv6def) < 0))
goto cleanup;
if (networkBuildDnsmasqHostsList(dctx, &network->def->dns) < 0)
goto cleanup;
if ((ret = dnsmasqSave(dctx)) < 0)
@ -1069,27 +1154,51 @@ networkRestartDhcpDaemon(struct network_driver *driver,
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;
@ -1098,7 +1207,6 @@ networkRadvdConfContents(virNetworkObjPtr network, char **configstr)
int prefix;
char *netaddr;
v6present = true;
prefix = virNetworkIpDefPrefix(ipdef);
if (prefix < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@ -1110,12 +1218,9 @@ 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);
}
@ -1181,7 +1286,8 @@ cleanup:
}
static int
networkStartRadvd(virNetworkObjPtr network)
networkStartRadvd(struct network_driver *driver ATTRIBUTE_UNUSED,
virNetworkObjPtr network)
{
char *pidfile = NULL;
char *radvdpidbase = NULL;
@ -1191,6 +1297,12 @@ networkStartRadvd(virNetworkObjPtr network)
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;
@ -1267,9 +1379,27 @@ static int
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 */
@ -1296,7 +1426,7 @@ networkRestartRadvd(struct network_driver *driver,
* 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)) {
@ -1590,11 +1720,9 @@ networkRemoveRoutingIptablesRules(struct network_driver *driver,
}
/* 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,
@ -1654,9 +1782,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:
@ -1674,9 +1812,11 @@ networkRemoveGeneralIp6tablesRules(struct network_driver *driver,
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);
}
@ -2268,7 +2408,7 @@ networkStartNetworkVirtual(struct network_driver *driver,
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
@ -2729,8 +2869,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)
@ -2777,17 +2916,36 @@ networkValidate(struct network_driver *driver,
}
}
/* 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;
}
}
}
}

View File

@ -293,11 +293,15 @@ hostsfileFree(dnsmasqHostsfile *hostsfile)
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)
@ -306,16 +310,24 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile,
if (!(ipstr = virSocketAddrFormat(ip)))
return -1;
if (name) {
if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s",
mac, ipstr, name) < 0) {
/* 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)
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);
@ -496,9 +508,10 @@ int
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);
}
/*

View File

@ -82,7 +82,8 @@ void dnsmasqContextFree(dnsmasqContext *ctx);
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);
@ -99,4 +100,18 @@ int dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath);
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__ */

View File

@ -0,0 +1,15 @@
@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\

View File

@ -0,0 +1,24 @@
<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>

View File

@ -0,0 +1,15 @@
@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\

View File

@ -0,0 +1,14 @@
<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>

View File

@ -0,0 +1,13 @@
@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\

View File

@ -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>

View File

@ -1,10 +1,16 @@
@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\

View File

@ -1,5 +1,10 @@
@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\

View File

@ -1,7 +1,10 @@
@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 \
@ -9,8 +12,8 @@
--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\

View File

@ -1,11 +1,14 @@
@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\

View File

@ -1,9 +1,13 @@
@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\

View File

@ -1,8 +1,15 @@
@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\

View File

@ -1,10 +1,19 @@
@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-leasefile=/var/lib/libvirt/dnsmasq/netboot.leases \
--dhcp-lease-max=253 --dhcp-no-override --expand-hosts \
--dhcp-hostsfile=/var/lib/libvirt/dnsmasq/netboot.hostsfile \
--addn-hosts=/var/lib/libvirt/dnsmasq/netboot.addnhosts \
--dhcp-no-override \
--enable-tftp \
--tftp-root /var/lib/tftproot --dhcp-boot pxeboot.img\
--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\

View File

@ -1,10 +1,17 @@
@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\

View File

@ -1,4 +1,8 @@
@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\

View File

@ -152,6 +152,8 @@ mymain(void)
= 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;
@ -172,10 +174,13 @@ mymain(void)
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;
}