[libvirt] [PATCH 2/3] v7.1 add support for DHCPv6

Gene Czarcinski gene at czarc.net
Thu Nov 22 19:21:51 UTC 2012


On 11/21/2012 04:18 PM, Gene Czarcinski wrote:
> 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.
>
> Note that the check for dnsmasq version is performed at
> network start and only then will an error condition occur.
> Thus, it is possible to define/edit a network configuration
> which will not start.  The error message indicates that
> dnsmasq version 2.64 or later is required.
>
> This patch provides the same DHCP support for IPv6 which
> has been available for IPv4.
>
> With dnsmasq >= 2.64, support for the RA service is now provided
> by dnsmasq (radvd is no longer needed/used/started).
>
> Documentation has been updated to reflect the new support.

Oops.  I did not realize that there are schemas that should be updated.  
I have most of what is needed figured out but there are a couple of 
things not working cleanly.  I should have a update patch submitted 
"real soon now".

Suggestion: add something to the developers guidance so that you check 
to make sure that the schemas are updated properly.  I wonder if the 
tests would pass testing?

Gene

> ---
>   docs/formatnetwork.html.in                         | 108 ++++++-
>   src/conf/network_conf.c                            | 100 ++++---
>   src/conf/network_conf.h                            |   1 +
>   src/network/bridge_driver.c                        | 333 +++++++++++++++------
>   src/util/dnsmasq.c                                 |   9 +-
>   tests/networkxml2argvdata/dhcp6-network.argv       |  17 ++
>   tests/networkxml2argvdata/dhcp6-network.xml        |  16 +
>   tests/networkxml2argvdata/isolated-network.argv    |  15 +-
>   tests/networkxml2argvdata/nat-network-dhcp6.argv   |  20 ++
>   tests/networkxml2argvdata/nat-network-dhcp6.xml    |  26 ++
>   .../networkxml2argvdata/nat-network-dns-hosts.argv |  15 +-
>   .../nat-network-dns-srv-record-minimal.argv        |  11 +-
>   .../nat-network-dns-srv-record.argv                |  11 +-
>   .../nat-network-dns-txt-record.argv                |  23 +-
>   tests/networkxml2argvdata/nat-network.argv         |  23 +-
>   tests/networkxml2argvdata/netboot-network.argv     |  23 +-
>   .../networkxml2argvdata/netboot-proxy-network.argv |  20 +-
>   .../routed-network-dhcphost.argv                   |  15 +
>   .../routed-network-dhcphost.xml                    |  19 ++
>   tests/networkxml2argvdata/routed-network.argv      |  11 +-
>   tests/networkxml2argvtest.c                        |   4 +
>   21 files changed, 633 insertions(+), 187 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 7b3b25c..50e00f9 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/conf/network_conf.h b/src/conf/network_conf.h
> index 3e46304..226da04 100644
> --- a/src/conf/network_conf.h
> +++ b/src/conf/network_conf.h
> @@ -218,6 +218,7 @@ struct _virNetworkObj {
>       unsigned int active : 1;
>       unsigned int autostart : 1;
>       unsigned int persistent : 1;
> +    unsigned int dnsmasqVersion;
>   
>       virNetworkDefPtr def; /* The current definition */
>       virNetworkDefPtr newDef; /* New definition to activate at shutdown */
> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
> index 9c67348..19a9170 100644
> --- a/src/network/bridge_driver.c
> +++ b/src/network/bridge_driver.c
> @@ -75,6 +75,11 @@
>   
>   #define VIR_FROM_THIS VIR_FROM_NETWORK
>   
> +#define DNSMASQ_PREFIX_TEXT "Dnsmasq version "
> +
> +#define CHECK_DNSMASQ_VERSION()                   \
> +                (network->dnsmasqVersion >= 2064)
> +
>   /* Main driver state */
>   struct network_driver {
>       virMutex lock;
> @@ -582,20 +587,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]);
> @@ -613,7 +630,6 @@ networkBuildDnsmasqHostsfile(dnsmasqContext *dctx,
>   
>   static int
>   networkBuildDnsmasqArgv(virNetworkObjPtr network,
> -                        virNetworkIpDefPtr ipdef,
>                           const char *pidfile,
>                           virCommandPtr cmd,
>                           dnsmasqContext *dctx)
> @@ -625,7 +641,8 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
>       char *recordPort = NULL;
>       char *recordWeight = NULL;
>       char *recordPriority = NULL;
> -    virNetworkIpDefPtr tmpipdef;
> +    virNetworkIpDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
> +    bool dhcp4flag, dhcp6flag;
>   
>       /*
>        * NB, be careful about syntax for dnsmasq options in long format.
> @@ -650,14 +667,19 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
>        * Needed to ensure dnsmasq uses same algorithm for processing
>        * multiple namedriver entries in /etc/resolv.conf as GLibC.
>        */
> -    virCommandAddArgList(cmd, "--strict-order", "--bind-interfaces", NULL);
> +    virCommandAddArgList(cmd, "--strict-order",
> +                              "--bind-interfaces",
> +                              "--domain-needed",
> +                              "--except-interface=lo",
> +                              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);
> @@ -665,10 +687,6 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
>       /* *no* conf file */
>       virCommandAddArg(cmd, "--conf-file=");
>   
> -    virCommandAddArgList(cmd,
> -                         "--except-interface", "lo",
> -                         NULL);
> -
>       /* If this is an isolated network, set the default route option
>        * (3) to be empty to avoid setting a default route that's
>        * guaranteed to not work, and set --no-resolv so that no dns
> @@ -751,7 +769,39 @@ networkBuildDnsmasqArgv(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 (!CHECK_DNSMASQ_VERSION()) {
> +                    virReportError(VIR_ERR_XML_ERROR, "%s",
> +                       _("dnsmasq version >= 2.64 required to specify DHCPv6 range or host"));
> +                    goto cleanup;
> +                }
> +                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)
> @@ -772,7 +822,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);
> @@ -783,61 +833,93 @@ 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 (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
> +            goto cleanup;
>   
> -        if (ipdef->nranges || ipdef->nhosts)
> -            virCommandAddArg(cmd, "--dhcp-no-override");
> +        /* 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");
>   
> -        /* add domain to any non-qualified hostnames in /etc/hosts or addn-hosts */
> -        if (network->def->domain)
> -           virCommandAddArg(cmd, "--expand-hosts");
> +            if (ipdef->tftproot) {
> +                virCommandAddArgList(cmd, "--enable-tftp",
> +                                     "--tftp-root", ipdef->tftproot,
> +                                     NULL);
> +            }
>   
> -        if (networkBuildDnsmasqHostsfile(dctx, ipdef, network->def->dns) < 0)
> -            goto cleanup;
> +            if (ipdef->bootfile) {
> +                virCommandAddArg(cmd, "--dhcp-boot");
> +                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
> +                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
>   
> -        /* 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 (!bootserver)
> +                        goto cleanup;
> +                    virCommandAddArgFormat(cmd, "%s%s%s",
> +                                       ipdef->bootfile, ",,", bootserver);
> +                    VIR_FREE(bootserver);
> +                } else {
> +                    virCommandAddArg(cmd, ipdef->bootfile);
> +                }
> +            }
> +        }
> +        if (ipdef == ipv6def)
> +            ipdef = NULL;
> +        else
> +            ipdef = ipv6def;
> +    }
>   
> -        /* 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 (nbleases > 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->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);
> +    /* this is done once per interface */
> +    if (networkBuildDnsmasqHostsList(dctx, network->def->dns) < 0)
> +       goto cleanup;
>   
> -                if (!bootserver)
> +    /* 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)
> +        virCommandAddArgPair(cmd, "--dhcp-hostsfile",
> +                             dctx->hostsfile->path);
> +
> +    /* Likewise, always create this file and put it on the commandline, to allow for
> +     * for runtime additions.
> +     */
> +    virCommandAddArgPair(cmd, "--addn-hosts",
> +                         dctx->addnhostsfile->path);
> +
> +    /* we are doing RA instead of radvd */
> +    if (CHECK_DNSMASQ_VERSION()) {
> +        if (dhcp6flag)
> +            virCommandAddArg(cmd, "--enable-ra");
> +        else {
> +            char *bridgeaddr = NULL;
> +            ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, 0);
> +            if (ipdef) {
> +                bridgeaddr = virSocketAddrFormat(&ipdef->address);
> +                if (bridgeaddr) {
> +                    virCommandAddArgFormat(cmd,
> +                        "--dhcp-range=%s,ra-only", bridgeaddr);
> +                } else {
> +                    virReportError(VIR_ERR_XML_ERROR,
> +                       _("invalid IPv6 configuration for %s ra-only"),
> +                       network->def->name);
>                       goto cleanup;
> -                virCommandAddArgFormat(cmd, "%s%s%s",
> -                                       ipdef->bootfile, ",,", bootserver);
> -                VIR_FREE(bootserver);
> -            } else {
> -                virCommandAddArg(cmd, ipdef->bootfile);
> +                }
> +                VIR_FREE(bridgeaddr);
>               }
>           }
>       }
>   
>       ret = 0;
> +
>   cleanup:
>       VIR_FREE(record);
>       VIR_FREE(recordPort);
> @@ -877,7 +959,7 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network, virCommandPtr *cmdou
>           return 0;
>   
>       cmd = virCommandNew(DNSMASQ);
> -    if (networkBuildDnsmasqArgv(network, ipdef, pidfile, cmd, dctx) < 0) {
> +    if (networkBuildDnsmasqArgv(network, pidfile, cmd, dctx) < 0) {
>           goto cleanup;
>       }
>   
> @@ -894,18 +976,45 @@ static int
>   networkStartDhcpDaemon(virNetworkObjPtr network)
>   {
>       virCommandPtr cmd = NULL;
> +    const char *cmdname = DNSMASQ;
> +    char *tmp, *version = NULL;
> +    unsigned int  major = 0, minor = 0;
>       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 (!virFileIsExecutable(cmdname)) {
> +        VIR_WARN("file %s missing or not executable", cmdname);
> +        goto cleanup;
> +    }
> +    VIR_INFO("starting dhcp daemon (%s)", cmdname);
> +    network->dnsmasqVersion = 0;
> +
> +    cmd = virCommandNew(cmdname);
> +    virCommandAddArg(cmd, "--version");
> +    virCommandSetOutputBuffer(cmd, &version);
> +    if (virCommandRun(cmd, NULL) < 0)
> +        goto cleanup;
> +    virCommandFree(cmd);
> +    cmd = NULL;
> +
> +    if ((version!=NULL) &&
> +        (STREQLEN(version, DNSMASQ_PREFIX_TEXT, strlen(DNSMASQ_PREFIX_TEXT)))) {
> +        tmp = version + strlen(DNSMASQ_PREFIX_TEXT);
> +        if (virStrToLong_ui(tmp, &tmp, 10, &major) >= 0) {
> +            if ((*tmp == '.') &&
> +                    virStrToLong_ui(tmp + 1, &tmp, 10, &minor) >= 0) {
> +                network->dnsmasqVersion = (major * 1000) + minor;
> +            }
> +        }
> +    }
> +
>       if (virFileMakePath(NETWORK_PID_DIR) < 0) {
>           virReportSystemError(errno,
>                                _("cannot create directory %s"),
> @@ -939,18 +1048,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;
> @@ -976,6 +1073,7 @@ networkStartDhcpDaemon(virNetworkObjPtr network)
>       ret = 0;
>   cleanup:
>       VIR_FREE(pidfile);
> +    VIR_FREE(version);
>       virCommandFree(cmd);
>       dnsmasqContextFree(dctx);
>       return ret;
> @@ -994,31 +1092,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)
> @@ -1170,6 +1272,12 @@ networkStartRadvd(virNetworkObjPtr network)
>       virCommandPtr cmd = NULL;
>       int ret = -1;
>   
> +    /* is dnsmasq handling RA */
> +    if (CHECK_DNSMASQ_VERSION()) {
> +        ret = 0;
> +        goto cleanup;
> +    }
> +
>       network->radvdPid = -1;
>   
>       if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
> @@ -1247,6 +1355,10 @@ cleanup:
>   static int
>   networkRefreshRadvd(virNetworkObjPtr network)
>   {
> +    /* is dnsmasq handling RA */
> +    if (CHECK_DNSMASQ_VERSION())
> +        return 0;
> +
>       /* if there's no running radvd, just start it */
>       if (network->radvdPid <= 0 || (kill(network->radvdPid, 0) < 0))
>           return networkStartRadvd(network);
> @@ -1626,9 +1738,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:
> @@ -1646,6 +1768,7 @@ networkRemoveGeneralIp6tablesRules(struct network_driver *driver,
>                                     virNetworkObjPtr network)
>   {
>       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);
>       }
> @@ -2695,8 +2818,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)
> @@ -2715,17 +2837,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..87c68ac
> --- /dev/null
> +++ b/tests/networkxml2argvdata/dhcp6-network.argv
> @@ -0,0 +1,17 @@
> + at DNSMASQ@ \
> +--strict-order \
> +--bind-interfaces \
> +--domain-needed \
> +--except-interface=lo \
> +--domain=mynet \
> +--expand-hosts \
> +--local=/mynet/ \
> +--conf-file= \
> +--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 \
> +--enable-ra\
> 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 13e77b2..97f7b11 100644
> --- a/tests/networkxml2argvdata/isolated-network.argv
> +++ b/tests/networkxml2argvdata/isolated-network.argv
> @@ -1,9 +1,16 @@
> - at DNSMASQ@ --strict-order --bind-interfaces \
> ---local=// --domain-needed --conf-file= \
> ---except-interface lo --dhcp-option=3 --no-resolv \
> + at DNSMASQ@ \
> +--strict-order \
> +--bind-interfaces \
> +--domain-needed \
> +--except-interface=lo \
> +--local=// \
> +--conf-file= \
> +--dhcp-option=3 \
> +--no-resolv \
>   --listen-address 192.168.152.1 \
>   --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\
> diff --git a/tests/networkxml2argvdata/nat-network-dhcp6.argv b/tests/networkxml2argvdata/nat-network-dhcp6.argv
> new file mode 100644
> index 0000000..a4795e5
> --- /dev/null
> +++ b/tests/networkxml2argvdata/nat-network-dhcp6.argv
> @@ -0,0 +1,20 @@
> + at DNSMASQ@ \
> +--strict-order \
> +--bind-interfaces \
> +--domain-needed \
> +--except-interface=lo \
> +--local=// \
> +--conf-file= \
> +--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 \
> +--enable-ra\
> 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-hosts.argv b/tests/networkxml2argvdata/nat-network-dns-hosts.argv
> index 03a0676..32ad19f 100644
> --- a/tests/networkxml2argvdata/nat-network-dns-hosts.argv
> +++ b/tests/networkxml2argvdata/nat-network-dns-hosts.argv
> @@ -1,4 +1,11 @@
> - at DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \
> ---local=/example.com/ --domain-needed \
> ---conf-file= --except-interface lo --listen-address 192.168.122.1 \
> ---expand-hosts --addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\
> + at DNSMASQ@ \
> +--strict-order \
> +--bind-interfaces \
> +--domain-needed \
> +--except-interface=lo \
> +--domain=example.com \
> +--expand-hosts \
> +--local=/example.com/ \
> +--conf-file= \
> +--listen-address 192.168.122.1 \
> +--addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts\
> diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv
> index 210a60c..4c21ff1 100644
> --- a/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv
> +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record-minimal.argv
> @@ -1,8 +1,10 @@
>   @DNSMASQ@ \
>   --strict-order \
>   --bind-interfaces \
> ---local=// --domain-needed --conf-file= \
> ---except-interface lo \
> +--domain-needed \
> +--except-interface=lo \
> +--local=// \
> +--conf-file= \
>   --srv-host=name.tcp.,,,, \
>   --listen-address 192.168.122.1 \
>   --listen-address 192.168.123.1 \
> @@ -10,8 +12,9 @@
>   --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\
> +--addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts \
> +--dhcp-range=2001:db8:ac10:fe01::1,ra-only\
> diff --git a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv
> index 833d3cd..246dbeb 100644
> --- a/tests/networkxml2argvdata/nat-network-dns-srv-record.argv
> +++ b/tests/networkxml2argvdata/nat-network-dns-srv-record.argv
> @@ -1,8 +1,10 @@
>   @DNSMASQ@ \
>   --strict-order \
>   --bind-interfaces \
> ---local=// --domain-needed --conf-file= \
> ---except-interface lo \
> +--domain-needed \
> +--except-interface=lo \
> +--local=// \
> +--conf-file= \
>   --srv-host=name.tcp.test-domain-name,.,1024,10,10 \
>   --listen-address 192.168.122.1 \
>   --listen-address 192.168.123.1 \
> @@ -10,8 +12,9 @@
>   --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\
> +--addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts \
> +--dhcp-range=2001:db8:ac10:fe01::1,ra-only\
> diff --git a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv
> index 3481507..8d18f3f 100644
> --- a/tests/networkxml2argvdata/nat-network-dns-txt-record.argv
> +++ b/tests/networkxml2argvdata/nat-network-dns-txt-record.argv
> @@ -1,11 +1,20 @@
> - at DNSMASQ@ --strict-order --bind-interfaces \
> ---local=// --domain-needed --conf-file= \
> ---except-interface lo '--txt-record=example,example value' \
> ---listen-address 192.168.122.1 --listen-address 192.168.123.1 \
> + at DNSMASQ@ \
> +--strict-order \
> +--bind-interfaces \
> +--domain-needed \
> +--except-interface=lo \
> +--local=// \
> +--conf-file= \
> +'--txt-record=example,example value' \
> +--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 \
> +--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-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\
> diff --git a/tests/networkxml2argvdata/nat-network.argv b/tests/networkxml2argvdata/nat-network.argv
> index 37fd2fc..32afeaa 100644
> --- a/tests/networkxml2argvdata/nat-network.argv
> +++ b/tests/networkxml2argvdata/nat-network.argv
> @@ -1,10 +1,19 @@
> - at DNSMASQ@ --strict-order --bind-interfaces \
> ---local=// --domain-needed --conf-file= \
> ---except-interface lo --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 \
> + at DNSMASQ@ \
> +--strict-order \
> +--bind-interfaces \
> +--domain-needed \
> +--except-interface=lo \
> +--local=// \
> +--conf-file= \
> +--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-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\
> diff --git a/tests/networkxml2argvdata/netboot-network.argv b/tests/networkxml2argvdata/netboot-network.argv
> index 5408eb7..41e9416 100644
> --- a/tests/networkxml2argvdata/netboot-network.argv
> +++ b/tests/networkxml2argvdata/netboot-network.argv
> @@ -1,10 +1,19 @@
> - at DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \
> ---local=/example.com/ --domain-needed --conf-file= \
> ---except-interface lo --listen-address 192.168.122.1 \
> + at DNSMASQ@ \
> +--strict-order \
> +--bind-interfaces \
> +--domain-needed \
> +--except-interface=lo \
> +--domain=example.com \
> +--expand-hosts \
> +--local=/example.com/ \
> +--conf-file= \
> +--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\
> diff --git a/tests/networkxml2argvdata/netboot-proxy-network.argv b/tests/networkxml2argvdata/netboot-proxy-network.argv
> index 21e01e3..eebe560 100644
> --- a/tests/networkxml2argvdata/netboot-proxy-network.argv
> +++ b/tests/networkxml2argvdata/netboot-proxy-network.argv
> @@ -1,9 +1,17 @@
> - at DNSMASQ@ --strict-order --bind-interfaces --domain=example.com \
> ---local=/example.com/ --domain-needed --conf-file= \
> ---except-interface lo --listen-address 192.168.122.1 \
> + at DNSMASQ@ \
> +--strict-order \
> +--bind-interfaces \
> +--domain-needed \
> +--except-interface=lo \
> +--domain=example.com \
> +--expand-hosts \
> +--local=/example.com/ \
> +--conf-file= \
> +--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\
> diff --git a/tests/networkxml2argvdata/routed-network-dhcphost.argv b/tests/networkxml2argvdata/routed-network-dhcphost.argv
> new file mode 100644
> index 0000000..9f52b98
> --- /dev/null
> +++ b/tests/networkxml2argvdata/routed-network-dhcphost.argv
> @@ -0,0 +1,15 @@
> + at DNSMASQ@ \
> +--strict-order \
> +--bind-interfaces \
> +--domain-needed \
> +--except-interface=lo \
> +--local=// \
> +--conf-file= \
> +--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 \
> +--enable-ra\
> 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/networkxml2argvdata/routed-network.argv b/tests/networkxml2argvdata/routed-network.argv
> index 9fedb2b..78ad8a2 100644
> --- a/tests/networkxml2argvdata/routed-network.argv
> +++ b/tests/networkxml2argvdata/routed-network.argv
> @@ -1,4 +1,9 @@
> - at DNSMASQ@ --strict-order --bind-interfaces \
> ---local=// --domain-needed --conf-file= \
> ---except-interface lo --listen-address 192.168.122.1 \
> + at DNSMASQ@ \
> +--strict-order \
> +--bind-interfaces \
> +--domain-needed \
> +--except-interface=lo \
> +--local=// \
> +--conf-file= \
> +--listen-address 192.168.122.1 \
>   --addn-hosts=/var/lib/libvirt/dnsmasq/local.addnhosts\
> diff --git a/tests/networkxml2argvtest.c b/tests/networkxml2argvtest.c
> index 87519e4..206e2d7 100644
> --- a/tests/networkxml2argvtest.c
> +++ b/tests/networkxml2argvtest.c
> @@ -73,6 +73,7 @@ static int testCompareXMLToArgvFiles(const char *inxml, const char *outargv) {
>           goto fail;
>   
>       obj->def = dev;
> +    obj->dnsmasqVersion = 2064;
>       dctx = dnsmasqContextNew(dev->name, "/var/lib/libvirt/dnsmasq");
>   
>       if (dctx == NULL)
> @@ -157,6 +158,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;
>   }




More information about the libvir-list mailing list