This commit adds support for IPv6 parsing and formatting to the
virtual network XML parser, including moving around data definitions
to allow for multiple <ip> elements on a single network, but only
changes the consumers of this API to accomodate for the changes in
API/structure, not to add any actual IPv6 functionality. That will
come in a later patch - this patch attempts to maintain the same final
functionality in both drivers that use the network XML parser - vbox
and "bridge" (the Linux bridge-based driver used by the qemu
hypervisor driver).
* src/libvirt_private.syms: Add new private API functions.
* src/conf/network_conf.[ch]: Change C data structure and
parsing/formatting.
* src/network/bridge_driver.c: Update to use new parser/formatter.
* src/vbox/vbox_tmpl.c: update to use new parser/formatter
* docs/schemas/network.rng: changes to the schema -
* there can now be more than one <ip> element.
* ip address is now an ip-addr (ipv4 or ipv6) rather than ipv4-addr
* new optional "prefix" attribute that can be used in place of
"netmask"
* new optional "family" attribute - "ipv4" or "ipv6"
(will default to ipv4)
* define data types for the above
* tests/networkxml2xml(in|out)/nat-network.xml: add multiple <ip> elements
(including IPv6) to a single network definition to verify they are being
correctly parsed and formatted.
---
V2 Changes:
* prefix in virNetworkIpDef struct is now unsigned int rather than int.
* caught a memory leak in an error patch of virNetworkIPParseXML().
docs/schemas/network.rng | 41 +++-
src/conf/network_conf.c | 453 +++++++++++++++++++++----------
src/conf/network_conf.h | 50 +++-
src/libvirt_private.syms | 5 +-
src/network/bridge_driver.c | 248 ++++++++++--------
src/vbox/vbox_tmpl.c | 81 ++++--
tests/networkxml2xmlin/nat-network.xml | 8 +
tests/networkxml2xmlout/nat-network.xml | 8 +
8 files changed, 590 insertions(+), 304 deletions(-)
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index ac13af2..bc34ddc 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -80,15 +80,21 @@
</optional>
<!-- <ip> element -->
- <optional>
+ <zeroOrMore>
<!-- The IP element sets up NAT'ing and an optional DHCP server
local to the host. -->
<element name="ip">
<optional>
- <attribute name="address"><ref
name="ipv4-addr"/></attribute>
+ <attribute name="address"><ref
name="ip-addr"/></attribute>
+ </optional>
+ <optional>
+ <choice>
+ <attribute name="netmask"><ref
name="ipv4-addr"/></attribute>
+ <attribute name="prefix"><ref
name="ip-prefix"/></attribute>
+ </choice>
</optional>
<optional>
- <attribute name="netmask"><ref
name="ipv4-addr"/></attribute>
+ <attribute name="family"><ref
name="addr-family"/></attribute>
</optional>
<optional>
<element name="tftp">
@@ -123,7 +129,7 @@
</element>
</optional>
</element>
- </optional>
+ </zeroOrMore>
</interleave>
</element>
</define>
@@ -135,6 +141,33 @@
</data>
</define>
+ <!-- Based on
http://blog.mes-stats.fr/2008/10/09/regex-ipv4-et-ipv6 -->
+ <define name='ipv6-addr'>
+ <data type='string'>
+ <!-- To understand this better, take apart the toplevel '|'s -->
+ <param
name="pattern">(([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2})))\.){3}(((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2}))))|(([0-9A-Fa-f]{1,4}:){0,5}:((((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2})))\.){3}(((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2}))))|(::([0-9A-Fa-f]{1,4}:){0,5}((((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2})))\.){3}(((25[0-5])|(1[0-9]{2})|(2[0-4][0-9])|([0-9]{1,2}))))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:)</param>
+ </data>
+ </define>
+
+ <define name='ip-addr'>
+ <choice>
+ <ref name='ipv4-addr'/>
+ <ref name='ipv6-addr'/>
+ </choice>
+ </define>
+
+ <define name='ip-prefix'>
+ <data type='unsignedInt'>
+ <param name="maxInclusive">128</param>
+ </data>
+ </define>
+
+ <define name='addr-family'>
+ <data type='string'>
+ <param name="pattern">(ipv4)|(ipv6)</param>
+ </data>
+ </define>
+
<!-- a 6 byte MAC address in ASCII-hex format, eg "12:34:56:78:9A:BC"
-->
<define name='mac-addr'>
<data type='string'>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index b17c708..86442ce 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -87,9 +87,26 @@ virNetworkObjPtr virNetworkFindByName(const virNetworkObjListPtr nets,
}
+static void virNetworkIpDefClear(virNetworkIpDefPtr def)
+{
+ int ii;
+
+ VIR_FREE(def->family);
+ VIR_FREE(def->ranges);
+
+ for (ii = 0 ; ii < def->nhosts && def->hosts ; ii++) {
+ VIR_FREE(def->hosts[ii].mac);
+ VIR_FREE(def->hosts[ii].name);
+ }
+
+ VIR_FREE(def->hosts);
+ VIR_FREE(def->tftproot);
+ VIR_FREE(def->bootfile);
+}
+
void virNetworkDefFree(virNetworkDefPtr def)
{
- int i;
+ int ii;
if (!def)
return;
@@ -99,16 +116,10 @@ void virNetworkDefFree(virNetworkDefPtr def)
VIR_FREE(def->forwardDev);
VIR_FREE(def->domain);
- VIR_FREE(def->ranges);
-
- for (i = 0 ; i < def->nhosts && def->hosts ; i++) {
- VIR_FREE(def->hosts[i].mac);
- VIR_FREE(def->hosts[i].name);
+ for (ii = 0 ; ii < def->nips && def->ips ; ii++) {
+ virNetworkIpDefClear(&def->ips[ii]);
}
- VIR_FREE(def->hosts);
-
- VIR_FREE(def->tftproot);
- VIR_FREE(def->bootfile);
+ VIR_FREE(def->ips);
VIR_FREE(def);
}
@@ -207,21 +218,48 @@ void virNetworkRemoveInactive(virNetworkObjListPtr nets,
}
}
+/* return ips[index], or NULL if there aren't enough ips */
+virNetworkIpDefPtr
+virNetworkDefGetIpByIndex(const virNetworkDefPtr def,
+ int family, int n)
+{
+ int ii;
+
+ if (!def->ips || n >= def->nips)
+ return NULL;
+
+ if (family == AF_UNSPEC) {
+ return &def->ips[n];
+ }
+
+ /* find the nth ip of type "family" */
+ for (ii = 0; ii < def->nips; ii++) {
+ if (VIR_SOCKET_IS_FAMILY(&def->ips[ii].address, family)
+ && (n-- <= 0)) {
+ return &def->ips[ii];
+ }
+ }
+ /* failed to find enough of the right family */
+ return NULL;
+}
+
/* return number of 1 bits in netmask for the network's ipAddress,
* or -1 on error
*/
-int virNetworkDefPrefix(const virNetworkDefPtr def)
+int virNetworkIpDefPrefix(const virNetworkIpDefPtr def)
{
- if (VIR_SOCKET_HAS_ADDR(&def->netmask)) {
+ if (def->prefix > 0) {
+ return def->prefix;
+ } else if (VIR_SOCKET_HAS_ADDR(&def->netmask)) {
return virSocketGetNumNetmaskBits(&def->netmask);
- } else if (VIR_SOCKET_IS_FAMILY(&def->ipAddress, AF_INET)) {
+ } else if (VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
/* Return the natural prefix for the network's ip address.
* On Linux we could use the IN_CLASSx() macros, but those
* aren't guaranteed on all platforms, so we just deal with
* the bits ourselves.
*/
const unsigned char *octets
- = (const unsigned char
*)(&def->ipAddress.data.inet4.sin_addr.s_addr);
+ = (const unsigned char *)(&def->address.data.inet4.sin_addr.s_addr);
if ((octets[0] & 0x80) == 0) {
/* Class A network */
return 8;
@@ -233,6 +271,8 @@ int virNetworkDefPrefix(const virNetworkDefPtr def)
return 24;
}
return -1;
+ } else if (VIR_SOCKET_IS_FAMILY(&def->address, AF_INET6)) {
+ return 64;
}
return -1;
}
@@ -241,22 +281,23 @@ int virNetworkDefPrefix(const virNetworkDefPtr def)
* definition, based on either the definition's netmask, or its
* prefix. Return -1 on error (and set the netmask family to AF_UNSPEC)
*/
-int virNetworkDefNetmask(const virNetworkDefPtr def,
- virSocketAddrPtr netmask)
+int virNetworkIpDefNetmask(const virNetworkIpDefPtr def,
+ virSocketAddrPtr netmask)
{
if (VIR_SOCKET_IS_FAMILY(&def->netmask, AF_INET)) {
*netmask = def->netmask;
return 0;
}
- return virSocketAddrPrefixToNetmask(virNetworkDefPrefix(def), netmask,
- VIR_SOCKET_FAMILY(&def->ipAddress));
+ return virSocketAddrPrefixToNetmask(virNetworkIpDefPrefix(def), netmask,
+ VIR_SOCKET_FAMILY(&def->address));
}
static int
-virNetworkDHCPRangeDefParseXML(virNetworkDefPtr def,
- xmlNodePtr node) {
+virNetworkDHCPRangeDefParseXML(virNetworkIpDefPtr def,
+ xmlNodePtr node)
+{
xmlNodePtr cur;
@@ -390,33 +431,147 @@ virNetworkDHCPRangeDefParseXML(virNetworkDefPtr def,
}
static int
-virNetworkIPParseXML(virNetworkDefPtr def,
- xmlNodePtr node) {
- xmlNodePtr cur;
+virNetworkIPParseXML(const char *networkName,
+ virNetworkIpDefPtr def,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt)
+{
+ /*
+ * virNetworkIpDef object is already allocated as part of an array.
+ * On failure clear it out, but don't free it.
+ */
- cur = node->children;
- while (cur != NULL) {
- if (cur->type == XML_ELEMENT_NODE &&
- xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
- int result = virNetworkDHCPRangeDefParseXML(def, cur);
- if (result)
- return result;
+ xmlNodePtr cur, save;
+ char *address = NULL, *netmask = NULL;
+ unsigned long prefix;
+ int result = -1;
+
+ save = ctxt->node;
+ ctxt->node = node;
+
+ /* grab raw data from XML */
+ def->family = virXPathString("string(./@family)", ctxt);
+ address = virXPathString("string(./@address)", ctxt);
+ if (virXPathULong("string(./@prefix)", ctxt, &prefix) < 0)
+ def->prefix = 0;
+ else
+ def->prefix = prefix;
+
+ netmask = virXPathString("string(./@netmask)", ctxt);
+
+ if (address) {
+ if (virSocketParseAddr(address, &def->address, AF_UNSPEC) < 0) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("Bad address '%s' in definition of
network '%s'"),
+ address, networkName);
+ goto error;
+ }
- } else if (cur->type == XML_ELEMENT_NODE &&
- xmlStrEqual(cur->name, BAD_CAST "tftp")) {
- char *root;
+ }
- if (!(root = virXMLPropString(cur, "root"))) {
- cur = cur->next;
- continue;
+ /* validate family vs. address */
+ if (def->family == NULL) {
+ if (!(VIR_SOCKET_IS_FAMILY(&def->address, AF_INET) ||
+ VIR_SOCKET_IS_FAMILY(&def->address, AF_UNSPEC))) {
+ virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("no family specified for non-IPv4 address
address '%s' in network '%s'"),
+ address, networkName);
+ goto error;
+ }
+ } else if (STREQ(def->family, "ipv4")) {
+ if (!VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
+ virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("family 'ipv4' specified for non-IPv4
address '%s' in network '%s'"),
+ address, networkName);
+ goto error;
+ }
+ } else if (STREQ(def->family, "ipv6")) {
+ if (!VIR_SOCKET_IS_FAMILY(&def->address, AF_INET6)) {
+ virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("family 'ipv6' specified for non-IPv6
address '%s' in network '%s'"),
+ address, networkName);
+ goto error;
+ }
+ } else {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("Unrecognized family '%s' in definition of
network '%s'"),
+ def->family, networkName);
+ goto error;
+ }
+
+ /* parse/validate netmask */
+ if (netmask) {
+ if (address == NULL) {
+ /* netmask is meaningless without an address */
+ virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("netmask specified without address in network
'%s'"),
+ networkName);
+ goto error;
+ }
+
+ if (!VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
+ virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("netmask not supported for address '%s'
in network '%s' (IPv4 only)"),
+ address, networkName);
+ goto error;
+ }
+
+ if (def->prefix > 0) {
+ /* can't have both netmask and prefix at the same time */
+ virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("network '%s' has prefix='%u'
but no address"),
+ networkName, def->prefix);
+ goto error;
+ }
+
+ if (virSocketParseAddr(netmask, &def->netmask, AF_UNSPEC) < 0)
+ goto error;
+
+ if (!VIR_SOCKET_IS_FAMILY(&def->netmask, AF_INET)) {
+ virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("network '%s' has invalid netmask
'%s' for address '%s' (both must be IPv4)"),
+ networkName, netmask, address);
+ goto error;
+ }
+ }
+
+ if (VIR_SOCKET_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 = virNetworkDHCPRangeDefParseXML(def, cur);
+ if (result)
+ goto error;
+
+ } 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;
}
- def->tftproot = root;
+ cur = cur->next;
}
+ }
- cur = cur->next;
+ result = 0;
+
+error:
+ if (result < 0) {
+ virNetworkIpDefClear(def);
}
- return 0;
+ VIR_FREE(address);
+ VIR_FREE(netmask);
+
+ ctxt->node = save;
+ return result;
}
static virNetworkDefPtr
@@ -424,8 +579,8 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
{
virNetworkDefPtr def;
char *tmp;
- char *ipAddress;
- char *netmask;
+ xmlNodePtr *ipNodes = NULL;
+ int nIps;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
@@ -469,44 +624,32 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
if (virXPathULong("string(./bridge[1]/@delay)", ctxt, &def->delay)
< 0)
def->delay = 0;
- ipAddress = virXPathString("string(./ip[1]/@address)", ctxt);
- if (ipAddress) {
- xmlNodePtr ip;
-
- if (virSocketParseAddr(ipAddress, &def->ipAddress, AF_UNSPEC) < 0)
- goto error;
+ nIps = virXPathNodeSet("./ip", ctxt, &ipNodes);
+ if (nIps > 0) {
+ int ii;
- /* XXX someday we want IPv6, so will need to relax this */
- if (!VIR_SOCKET_IS_FAMILY(&def->ipAddress, AF_INET)) {
- virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- "%s", _("Only IPv4 addresses are
supported"));
+ /* allocate array to hold all the addrs */
+ if (VIR_ALLOC_N(def->ips, nIps) < 0) {
+ virReportOOMError();
goto error;
}
-
- if ((ip = virXPathNode("./ip[1]", ctxt)) &&
- virNetworkIPParseXML(def, ip) < 0)
- goto error;
- }
- VIR_FREE(ipAddress);
-
- netmask = virXPathString("string(./ip[1]/@netmask)", ctxt);
- if (netmask) {
-
- if (virSocketParseAddr(netmask, &def->netmask, AF_UNSPEC) < 0)
- goto error;
-
- /* XXX someday we want IPv6, so will need to relax this */
- if (!VIR_SOCKET_IS_FAMILY(&def->netmask, AF_INET)) {
- virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- "%s", _("Only IPv4 addresses are
supported"));
- goto error;
+ /* parse each addr */
+ for (ii = 0; ii < nIps; ii++) {
+ int ret = virNetworkIPParseXML(def->name, &def->ips[ii],
+ ipNodes[ii], ctxt);
+ if (ret < 0)
+ goto error;
+ def->nips++;
}
}
- VIR_FREE(netmask);
-
/* IPv4 forwarding setup */
if (virXPathBoolean("count(./forward) > 0", ctxt)) {
+ if (def->nips == 0) {
+ virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Forwarding requested, but no IP
address provided"));
+ goto error;
+ }
tmp = virXPathString("string(./forward[1]/@mode)", ctxt);
if (tmp) {
if ((def->forwardType = virNetworkForwardTypeFromString(tmp)) < 0) {
@@ -585,11 +728,101 @@ cleanup:
return def;
}
+static int
+virNetworkIpDefFormat(virBufferPtr buf,
+ const virNetworkIpDefPtr def)
+{
+ int result = -1;
+
+ virBufferAddLit(buf, " <ip");
+
+ if (def->family) {
+ virBufferVSprintf(buf, " family='%s'", def->family);
+ }
+ if (VIR_SOCKET_HAS_ADDR(&def->address)) {
+ char *addr = virSocketFormatAddr(&def->address);
+ if (!addr)
+ goto error;
+ virBufferVSprintf(buf, " address='%s'", addr);
+ VIR_FREE(addr);
+ }
+ if (VIR_SOCKET_HAS_ADDR(&def->netmask)) {
+ char *addr = virSocketFormatAddr(&def->netmask);
+ if (!addr)
+ goto error;
+ virBufferVSprintf(buf, " netmask='%s'", addr);
+ VIR_FREE(addr);
+ }
+ if (def->prefix > 0) {
+ virBufferVSprintf(buf," prefix='%u'", def->prefix);
+ }
+ virBufferAddLit(buf, ">\n");
+
+ if (def->tftproot) {
+ virBufferEscapeString(buf, " <tftp root='%s' />\n",
+ def->tftproot);
+ }
+ if ((def->nranges || def->nhosts)) {
+ int ii;
+ virBufferAddLit(buf, " <dhcp>\n");
+ for (ii = 0 ; ii < def->nranges ; ii++) {
+ char *saddr = virSocketFormatAddr(&def->ranges[ii].start);
+ if (!saddr)
+ goto error;
+ char *eaddr = virSocketFormatAddr(&def->ranges[ii].end);
+ if (!eaddr) {
+ VIR_FREE(saddr);
+ goto error;
+ }
+ virBufferVSprintf(buf, " <range start='%s'
end='%s' />\n",
+ saddr, eaddr);
+ VIR_FREE(saddr);
+ VIR_FREE(eaddr);
+ }
+ for (ii = 0 ; ii < def->nhosts ; ii++) {
+ virBufferAddLit(buf, " <host ");
+ if (def->hosts[ii].mac)
+ virBufferVSprintf(buf, "mac='%s' ",
def->hosts[ii].mac);
+ if (def->hosts[ii].name)
+ virBufferVSprintf(buf, "name='%s' ",
def->hosts[ii].name);
+ if (VIR_SOCKET_HAS_ADDR(&def->hosts[ii].ip)) {
+ char *ipaddr = virSocketFormatAddr(&def->hosts[ii].ip);
+ if (!ipaddr)
+ goto error;
+ virBufferVSprintf(buf, "ip='%s' ", ipaddr);
+ VIR_FREE(ipaddr);
+ }
+ virBufferAddLit(buf, "/>\n");
+ }
+ if (def->bootfile) {
+ virBufferEscapeString(buf, " <bootp file='%s' ",
+ def->bootfile);
+ if (VIR_SOCKET_HAS_ADDR(&def->bootserver)) {
+ char *ipaddr = virSocketFormatAddr(&def->bootserver);
+ if (!ipaddr)
+ goto error;
+ virBufferEscapeString(buf, "server='%s' ", ipaddr);
+ VIR_FREE(ipaddr);
+ }
+ virBufferAddLit(buf, "/>\n");
+ }
+
+ virBufferAddLit(buf, " </dhcp>\n");
+ }
+
+ virBufferAddLit(buf, " </ip>\n");
+
+ result = 0;
+error:
+ return result;
+}
+
char *virNetworkDefFormat(const virNetworkDefPtr def)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
unsigned char *uuid;
char uuidstr[VIR_UUID_STRING_BUFLEN];
+ int ii;
virBufferAddLit(&buf, "<network>\n");
virBufferEscapeString(&buf, " <name>%s</name>\n",
def->name);
@@ -621,81 +854,9 @@ char *virNetworkDefFormat(const virNetworkDefPtr def)
if (def->domain)
virBufferVSprintf(&buf, " <domain name='%s'/>\n",
def->domain);
- if (VIR_SOCKET_HAS_ADDR(&def->ipAddress) ||
- VIR_SOCKET_HAS_ADDR(&def->netmask)) {
- virBufferAddLit(&buf, " <ip");
-
- if (VIR_SOCKET_HAS_ADDR(&def->ipAddress)) {
- char *addr = virSocketFormatAddr(&def->ipAddress);
- if (!addr)
- goto error;
- virBufferVSprintf(&buf, " address='%s'", addr);
- VIR_FREE(addr);
- }
-
- if (VIR_SOCKET_HAS_ADDR(&def->netmask)) {
- char *addr = virSocketFormatAddr(&def->netmask);
- if (!addr)
- goto error;
- virBufferVSprintf(&buf, " netmask='%s'", addr);
- VIR_FREE(addr);
- }
-
- virBufferAddLit(&buf, ">\n");
-
- if (def->tftproot) {
- virBufferEscapeString(&buf, " <tftp root='%s'
/>\n",
- def->tftproot);
- }
- if ((def->nranges || def->nhosts)) {
- int i;
- virBufferAddLit(&buf, " <dhcp>\n");
- for (i = 0 ; i < def->nranges ; i++) {
- char *saddr = virSocketFormatAddr(&def->ranges[i].start);
- if (!saddr)
- goto error;
- char *eaddr = virSocketFormatAddr(&def->ranges[i].end);
- if (!eaddr) {
- VIR_FREE(saddr);
- goto error;
- }
- virBufferVSprintf(&buf, " <range start='%s'
end='%s' />\n",
- saddr, eaddr);
- VIR_FREE(saddr);
- VIR_FREE(eaddr);
- }
- for (i = 0 ; i < def->nhosts ; i++) {
- virBufferAddLit(&buf, " <host ");
- if (def->hosts[i].mac)
- virBufferVSprintf(&buf, "mac='%s' ",
def->hosts[i].mac);
- if (def->hosts[i].name)
- virBufferVSprintf(&buf, "name='%s' ",
def->hosts[i].name);
- if (VIR_SOCKET_HAS_ADDR(&def->hosts[i].ip)) {
- char *ipaddr = virSocketFormatAddr(&def->hosts[i].ip);
- if (!ipaddr)
- goto error;
- virBufferVSprintf(&buf, "ip='%s' ", ipaddr);
- VIR_FREE(ipaddr);
- }
- virBufferAddLit(&buf, "/>\n");
- }
- if (def->bootfile) {
- virBufferEscapeString(&buf, " <bootp file='%s'
",
- def->bootfile);
- if (VIR_SOCKET_HAS_ADDR(&def->bootserver)) {
- char *ipaddr = virSocketFormatAddr(&def->bootserver);
- if (!ipaddr)
- goto error;
- virBufferEscapeString(&buf, "server='%s' ",
ipaddr);
- VIR_FREE(ipaddr);
- }
- virBufferAddLit(&buf, "/>\n");
- }
-
- virBufferAddLit(&buf, " </dhcp>\n");
- }
-
- virBufferAddLit(&buf, " </ip>\n");
+ for (ii = 0; ii < def->nips; ii++) {
+ if (virNetworkIpDefFormat(&buf, &def->ips[ii]) < 0)
+ goto error;
}
virBufferAddLit(&buf, "</network>\n");
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index a922d28..a51794d 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -56,6 +56,33 @@ struct _virNetworkDHCPHostDef {
virSocketAddr ip;
};
+typedef struct _virNetworkIpDef virNetworkIpDef;
+typedef virNetworkIpDef *virNetworkIpDefPtr;
+struct _virNetworkIpDef {
+ char *family; /* ipv4 or ipv6 - default is ipv4 */
+ virSocketAddr address; /* Bridge IP address */
+
+ /* The first two items below are taken directly from the XML (one
+ * or the other is given, but not both) and the 3rd is derived
+ * from the first two. When formatting XML, always use netMasktStr
+ * if it's non-NULL, but when using netmask in other code, use
+ * netmask, as it will automatically take into account prefix or
+ * natural netmasks (when no netmask or prefix is specified).
+ */
+ unsigned int prefix; /* ipv6 - only prefix allowed */
+ virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */
+
+ unsigned int nranges; /* Zero or more dhcp ranges */
+ virNetworkDHCPRangeDefPtr ranges;
+
+ unsigned int nhosts; /* Zero or more dhcp hosts */
+ virNetworkDHCPHostDefPtr hosts;
+
+ char *tftproot;
+ char *bootfile;
+ virSocketAddr bootserver;
+ };
+
typedef struct _virNetworkDef virNetworkDef;
typedef virNetworkDef *virNetworkDefPtr;
struct _virNetworkDef {
@@ -70,18 +97,8 @@ struct _virNetworkDef {
int forwardType; /* One of virNetworkForwardType constants */
char *forwardDev; /* Destination device for forwarding */
- virSocketAddr ipAddress; /* Bridge IP address */
- virSocketAddr netmask;
-
- unsigned int nranges; /* Zero or more dhcp ranges */
- virNetworkDHCPRangeDefPtr ranges;
-
- unsigned int nhosts; /* Zero or more dhcp hosts */
- virNetworkDHCPHostDefPtr hosts;
-
- char *tftproot;
- char *bootfile;
- virSocketAddr bootserver;
+ int nips;
+ virNetworkIpDefPtr ips; /* ptr to array of IP addresses on this network */
};
typedef struct _virNetworkObj virNetworkObj;
@@ -133,9 +150,12 @@ virNetworkDefPtr virNetworkDefParseNode(xmlDocPtr xml,
char *virNetworkDefFormat(const virNetworkDefPtr def);
-int virNetworkDefPrefix(const virNetworkDefPtr def);
-int virNetworkDefNetmask(const virNetworkDefPtr def,
- virSocketAddrPtr netmask);
+virNetworkIpDefPtr
+virNetworkDefGetIpByIndex(const virNetworkDefPtr def,
+ int family, int n);
+int virNetworkIpDefPrefix(const virNetworkIpDefPtr def);
+int virNetworkIpDefNetmask(const virNetworkIpDefPtr def,
+ virSocketAddrPtr netmask);
int virNetworkSaveXML(const char *configDir,
virNetworkDefPtr def,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d9ba7b1..6cb8270 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -578,15 +578,16 @@ virNetworkAssignDef;
virNetworkConfigFile;
virNetworkDefFormat;
virNetworkDefFree;
-virNetworkDefNetmask;
+virNetworkDefGetIpByIndex;
virNetworkDefParseFile;
virNetworkDefParseNode;
virNetworkDefParseString;
-virNetworkDefPrefix;
virNetworkDeleteConfig;
virNetworkFindByName;
virNetworkFindByUUID;
virNetworkLoadAllConfigs;
+virNetworkIpDefNetmask;
+virNetworkIpDefPrefix;
virNetworkObjIsDuplicate;
virNetworkObjListFree;
virNetworkObjLock;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index ba9ff96..0f8b050 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -145,8 +145,7 @@ networkFindActiveConfigs(struct network_driver *driver) {
obj->active = 1;
/* Finally try and read dnsmasq pid if any */
- if ((VIR_SOCKET_HAS_ADDR(&obj->def->ipAddress) ||
- obj->def->nranges) &&
+ if (obj->def->ips && (obj->def->nips > 0) &&
virFileReadPid(NETWORK_PID_DIR, obj->def->name,
&obj->dnsmasqPid) == 0) {
@@ -366,7 +365,7 @@ networkShutdown(void) {
static int
-networkSaveDnsmasqHostsfile(virNetworkObjPtr network,
+networkSaveDnsmasqHostsfile(virNetworkIpDefPtr ipdef,
dnsmasqContext *dctx,
bool force)
{
@@ -375,8 +374,8 @@ networkSaveDnsmasqHostsfile(virNetworkObjPtr network,
if (! force && virFileExists(dctx->hostsfile->path))
return 0;
- for (i = 0 ; i < network->def->nhosts ; i++) {
- virNetworkDHCPHostDefPtr host = &(network->def->hosts[i]);
+ for (i = 0; i < ipdef->nhosts; i++) {
+ virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
if ((host->mac) && VIR_SOCKET_HAS_ADDR(&host->ip))
dnsmasqAddDhcpHost(dctx, host->mac, &host->ip, host->name);
}
@@ -390,13 +389,14 @@ networkSaveDnsmasqHostsfile(virNetworkObjPtr network,
static int
networkBuildDnsmasqArgv(virNetworkObjPtr network,
+ virNetworkIpDefPtr ipdef,
const char *pidfile,
virCommandPtr cmd) {
int r, ret = -1;
int nbleases = 0;
char *bridgeaddr;
- if (!(bridgeaddr = virSocketFormatAddr(&network->def->ipAddress)))
+ if (!(bridgeaddr = virSocketFormatAddr(&ipdef->address)))
goto cleanup;
/*
* NB, be careful about syntax for dnsmasq options in long format.
@@ -438,18 +438,18 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
* clearly not practical
*
* virCommandAddArg(cmd, "--interface");
- * virCommandAddArg(cmd, network->def->bridge);
+ * virCommandAddArg(cmd, ipdef->bridge);
*/
virCommandAddArgList(cmd,
"--listen-address", bridgeaddr,
"--except-interface", "lo",
NULL);
- for (r = 0 ; r < network->def->nranges ; r++) {
- char *saddr = virSocketFormatAddr(&network->def->ranges[r].start);
+ for (r = 0 ; r < ipdef->nranges ; r++) {
+ char *saddr = virSocketFormatAddr(&ipdef->ranges[r].start);
if (!saddr)
goto cleanup;
- char *eaddr = virSocketFormatAddr(&network->def->ranges[r].end);
+ char *eaddr = virSocketFormatAddr(&ipdef->ranges[r].end);
if (!eaddr) {
VIR_FREE(saddr);
goto cleanup;
@@ -458,8 +458,8 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
virCommandAddArgFormat(cmd, "%s,%s", saddr, eaddr);
VIR_FREE(saddr);
VIR_FREE(eaddr);
- nbleases += virSocketGetRange(&network->def->ranges[r].start,
- &network->def->ranges[r].end);
+ nbleases += virSocketGetRange(&ipdef->ranges[r].start,
+ &ipdef->ranges[r].end);
}
/*
@@ -467,19 +467,19 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
* we have to add a special --dhcp-range option to enable the service in
* dnsmasq.
*/
- if (!network->def->nranges && network->def->nhosts) {
+ if (!ipdef->nranges && ipdef->nhosts) {
virCommandAddArg(cmd, "--dhcp-range");
virCommandAddArgFormat(cmd, "%s,static", bridgeaddr);
}
- if (network->def->nranges > 0) {
+ if (ipdef->nranges > 0) {
virCommandAddArgFormat(cmd, "--dhcp-lease-max=%d", nbleases);
}
- if (network->def->nranges || network->def->nhosts)
+ if (ipdef->nranges || ipdef->nhosts)
virCommandAddArg(cmd, "--dhcp-no-override");
- if (network->def->nhosts > 0) {
+ if (ipdef->nhosts > 0) {
dnsmasqContext *dctx = dnsmasqContextNew(network->def->name,
DNSMASQ_STATE_DIR);
if (dctx == NULL) {
@@ -487,31 +487,30 @@ networkBuildDnsmasqArgv(virNetworkObjPtr network,
goto cleanup;
}
- if (networkSaveDnsmasqHostsfile(network, dctx, false) < 0) {
+ if (networkSaveDnsmasqHostsfile(ipdef, dctx, false) < 0) {
virCommandAddArgPair(cmd, "--dhcp-hostsfile",
dctx->hostsfile->path);
}
dnsmasqContextFree(dctx);
}
- if (network->def->tftproot) {
+ if (ipdef->tftproot) {
virCommandAddArgList(cmd, "--enable-tftp",
- "--tftp-root", network->def->tftproot,
+ "--tftp-root", ipdef->tftproot,
NULL);
}
- if (network->def->bootfile) {
-
+ if (ipdef->bootfile) {
virCommandAddArg(cmd, "--dhcp-boot");
- if (VIR_SOCKET_HAS_ADDR(&network->def->bootserver)) {
- char *bootserver = virSocketFormatAddr(&network->def->bootserver);
+ if (VIR_SOCKET_HAS_ADDR(&ipdef->bootserver)) {
+ char *bootserver = virSocketFormatAddr(&ipdef->bootserver);
if (!bootserver)
goto cleanup;
virCommandAddArgFormat(cmd, "%s%s%s",
- network->def->bootfile, ",,",
bootserver);
+ ipdef->bootfile, ",,", bootserver);
VIR_FREE(bootserver);
} else {
- virCommandAddArg(cmd, network->def->bootfile);
+ virCommandAddArg(cmd, ipdef->bootfile);
}
}
@@ -521,9 +520,9 @@ cleanup:
return ret;
}
-
static int
-dhcpStartDhcpDaemon(virNetworkObjPtr network)
+dhcpStartDhcpDaemon(virNetworkObjPtr network,
+ virNetworkIpDefPtr ipdef)
{
virCommandPtr cmd = NULL;
char *pidfile = NULL;
@@ -531,7 +530,7 @@ dhcpStartDhcpDaemon(virNetworkObjPtr network)
network->dnsmasqPid = -1;
- if (!VIR_SOCKET_IS_FAMILY(&network->def->ipAddress, AF_INET)) {
+ if (!VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET)) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("cannot start dhcp daemon without IPv4
address for server"));
goto cleanup;
@@ -556,7 +555,7 @@ dhcpStartDhcpDaemon(virNetworkObjPtr network)
}
cmd = virCommandNew(DNSMASQ);
- if (networkBuildDnsmasqArgv(network, pidfile, cmd) < 0) {
+ if (networkBuildDnsmasqArgv(network, ipdef, pidfile, cmd) < 0) {
goto cleanup;
}
@@ -584,8 +583,10 @@ cleanup:
static int
networkAddMasqueradingIptablesRules(struct network_driver *driver,
- virNetworkObjPtr network) {
- int prefix = virNetworkDefPrefix(network->def);
+ virNetworkObjPtr network,
+ virNetworkIpDefPtr ipdef)
+{
+ int prefix = virNetworkIpDefPrefix(ipdef);
if (prefix < 0) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
@@ -596,7 +597,7 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
/* allow forwarding packets from the bridge interface */
if (iptablesAddForwardAllowOut(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->bridge,
network->def->forwardDev) < 0) {
@@ -608,7 +609,7 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
/* allow forwarding packets to the bridge interface if they are part of an existing
connection */
if (iptablesAddForwardAllowRelatedIn(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->bridge,
network->def->forwardDev) < 0) {
@@ -643,7 +644,7 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
/* First the generic masquerade rule for other protocols */
if (iptablesAddForwardMasquerade(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->forwardDev,
NULL) < 0) {
@@ -655,7 +656,7 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
/* UDP with a source port restriction */
if (iptablesAddForwardMasquerade(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->forwardDev,
"udp") < 0) {
@@ -667,7 +668,7 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
/* TCP with a source port restriction */
if (iptablesAddForwardMasquerade(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->forwardDev,
"tcp") < 0) {
@@ -681,25 +682,25 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
masqerr5:
iptablesRemoveForwardMasquerade(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->forwardDev,
"udp");
masqerr4:
iptablesRemoveForwardMasquerade(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->forwardDev,
NULL);
masqerr3:
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->bridge,
network->def->forwardDev);
masqerr2:
iptablesRemoveForwardAllowOut(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->bridge,
network->def->forwardDev);
@@ -709,8 +710,9 @@ networkAddMasqueradingIptablesRules(struct network_driver *driver,
static int
networkAddRoutingIptablesRules(struct network_driver *driver,
- virNetworkObjPtr network) {
- int prefix = virNetworkDefPrefix(network->def);
+ virNetworkObjPtr network,
+ virNetworkIpDefPtr ipdef) {
+ int prefix = virNetworkIpDefPrefix(ipdef);
if (prefix < 0) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
@@ -721,7 +723,7 @@ networkAddRoutingIptablesRules(struct network_driver *driver,
/* allow routing packets from the bridge interface */
if (iptablesAddForwardAllowOut(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->bridge,
network->def->forwardDev) < 0) {
@@ -733,7 +735,7 @@ networkAddRoutingIptablesRules(struct network_driver *driver,
/* allow routing packets to the bridge interface */
if (iptablesAddForwardAllowIn(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->bridge,
network->def->forwardDev) < 0) {
@@ -748,7 +750,7 @@ networkAddRoutingIptablesRules(struct network_driver *driver,
routeerr2:
iptablesRemoveForwardAllowOut(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->bridge,
network->def->forwardDev);
@@ -758,7 +760,8 @@ networkAddRoutingIptablesRules(struct network_driver *driver,
static int
networkAddIptablesRules(struct network_driver *driver,
- virNetworkObjPtr network) {
+ virNetworkObjPtr network,
+ virNetworkIpDefPtr ipdef) {
/* allow DHCP requests through to dnsmasq */
if (iptablesAddTcpInput(driver->iptables, network->def->bridge, 67) < 0)
{
@@ -791,7 +794,7 @@ networkAddIptablesRules(struct network_driver *driver,
}
/* allow TFTP requests through to dnsmasq */
- if (network->def->tftproot &&
+ if (ipdef && ipdef->tftproot &&
iptablesAddUdpInput(driver->iptables, network->def->bridge, 69) < 0)
{
networkReportError(VIR_ERR_SYSTEM_ERROR,
_("failed to add iptables rule to allow TFTP requests
from '%s'"),
@@ -824,29 +827,30 @@ networkAddIptablesRules(struct network_driver *driver,
goto err7;
}
-
- /* If masquerading is enabled, set up the rules*/
- if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT &&
- networkAddMasqueradingIptablesRules(driver, network) < 0)
- goto err8;
- /* else if routing is enabled, set up the rules*/
- else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE &&
- networkAddRoutingIptablesRules(driver, network) < 0)
- goto err8;
-
- /* If we are doing local DHCP service on this network, attempt to
- * add a rule that will fixup the checksum of DHCP response
- * packets back to the guests (but report failure without
- * aborting, since not all iptables implementations support it).
- */
-
- if ((VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) ||
- network->def->nranges) &&
- (iptablesAddOutputFixUdpChecksum(driver->iptables,
- network->def->bridge, 68) < 0)) {
- VIR_WARN("Could not add rule to fixup DHCP response checksums "
- "on network '%s'.", network->def->name);
- VIR_WARN0("May need to update iptables package & kernel to support
CHECKSUM rule.");
+ if (ipdef) {
+ /* If masquerading is enabled, set up the rules*/
+ if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT &&
+ networkAddMasqueradingIptablesRules(driver, network, ipdef) < 0)
+ goto err8;
+ /* else if routing is enabled, set up the rules*/
+ else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE &&
+ networkAddRoutingIptablesRules(driver, network, ipdef) < 0)
+ goto err8;
+
+ /* If we are doing local DHCP service on this network, attempt to
+ * add a rule that will fixup the checksum of DHCP response
+ * packets back to the guests (but report failure without
+ * aborting, since not all iptables implementations support it).
+ */
+
+ if (ipdef && (VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET) ||
+ ipdef->nranges) &&
+ (iptablesAddOutputFixUdpChecksum(driver->iptables,
+ network->def->bridge, 68) < 0)) {
+ VIR_WARN("Could not add rule to fixup DHCP response checksums "
+ "on network '%s'.", network->def->name);
+ VIR_WARN0("May need to update iptables package & kernel to support
CHECKSUM rule.");
+ }
}
return 0;
@@ -861,7 +865,7 @@ networkAddIptablesRules(struct network_driver *driver,
iptablesRemoveForwardRejectOut(driver->iptables,
network->def->bridge);
err5:
- if (network->def->tftproot) {
+ if (ipdef && ipdef->tftproot) {
iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 69);
}
err4tftp:
@@ -878,14 +882,16 @@ networkAddIptablesRules(struct network_driver *driver,
static void
networkRemoveIptablesRules(struct network_driver *driver,
- virNetworkObjPtr network) {
- if (VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) ||
- network->def->nranges) {
+ virNetworkObjPtr network,
+ virNetworkIpDefPtr ipdef) {
+
+ if (ipdef && (VIR_SOCKET_HAS_ADDR(&ipdef->address) ||
+ ipdef->nranges)) {
iptablesRemoveOutputFixUdpChecksum(driver->iptables,
network->def->bridge, 68);
}
- if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE) {
- int prefix = virNetworkDefPrefix(network->def);
+ if (ipdef && network->def->forwardType != VIR_NETWORK_FORWARD_NONE) {
+ int prefix = virNetworkIpDefPrefix(ipdef);
if (prefix < 0) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
@@ -896,34 +902,35 @@ networkRemoveIptablesRules(struct network_driver *driver,
if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
iptablesRemoveForwardMasquerade(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->forwardDev,
"tcp");
iptablesRemoveForwardMasquerade(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->forwardDev,
"udp");
iptablesRemoveForwardMasquerade(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->forwardDev,
NULL);
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->bridge,
network->def->forwardDev);
- } else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE)
+ } else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {
iptablesRemoveForwardAllowIn(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->bridge,
network->def->forwardDev);
+ }
iptablesRemoveForwardAllowOut(driver->iptables,
- &network->def->ipAddress,
+ &ipdef->address,
prefix,
network->def->bridge,
network->def->forwardDev);
@@ -932,7 +939,7 @@ error:
iptablesRemoveForwardAllowCross(driver->iptables, network->def->bridge);
iptablesRemoveForwardRejectIn(driver->iptables, network->def->bridge);
iptablesRemoveForwardRejectOut(driver->iptables, network->def->bridge);
- if (network->def->tftproot)
+ if (ipdef && ipdef->tftproot)
iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 69);
iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 53);
iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 53);
@@ -951,10 +958,18 @@ networkReloadIptablesRules(struct network_driver *driver)
virNetworkObjLock(driver->networks.objs[i]);
if (virNetworkObjIsActive(driver->networks.objs[i])) {
- networkRemoveIptablesRules(driver, driver->networks.objs[i]);
- if (networkAddIptablesRules(driver, driver->networks.objs[i]) < 0) {
- /* failed to add but already logged */
- }
+ virNetworkIpDefPtr ipv4def;
+
+ /* Find the one allowed IPv4 ip address in the definition */
+ /* Even if none is found, we still call the functions below */
+ ipv4def = virNetworkDefGetIpByIndex(driver->networks.objs[i]->def,
+ AF_INET, 0);
+ networkRemoveIptablesRules(driver, driver->networks.objs[i],
+ ipv4def);
+ if (networkAddIptablesRules(driver, driver->networks.objs[i],
+ ipv4def) < 0) {
+ /* failed to add but already logged */
+ }
}
virNetworkObjUnlock(driver->networks.objs[i]);
@@ -1028,7 +1043,8 @@ cleanup:
* other scenarios where we can ruin host network connectivity.
* XXX: Using a proper library is preferred over parsing /proc
*/
-static int networkCheckRouteCollision(virNetworkObjPtr network)
+static int networkCheckRouteCollision(virNetworkObjPtr network,
+ virNetworkIpDefPtr ipdef)
{
int ret = -1, len;
unsigned int net_dest;
@@ -1036,18 +1052,18 @@ static int networkCheckRouteCollision(virNetworkObjPtr network)
char *cur, *buf = NULL;
enum {MAX_ROUTE_SIZE = 1024*64};
- if (!VIR_SOCKET_IS_FAMILY(&network->def->ipAddress, AF_INET)) {
+ if (!VIR_SOCKET_IS_FAMILY(&ipdef->address, AF_INET)) {
/* Only support collision check for IPv4 */
return 0;
}
- if (virNetworkDefNetmask(network->def, &netmask) < 0) {
+ if (virNetworkIpDefNetmask(ipdef, &netmask) < 0) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to get netmask of '%s'"),
network->def->bridge);
}
- net_dest = (network->def->ipAddress.data.inet4.sin_addr.s_addr &
+ net_dest = (ipdef->address.data.inet4.sin_addr.s_addr &
netmask.data.inet4.sin_addr.s_addr);
/* Read whole routing table into memory */
@@ -1121,6 +1137,7 @@ static int networkStartNetworkDaemon(struct network_driver *driver,
{
int err;
virErrorPtr save_err;
+ virNetworkIpDefPtr ipv4def;
if (virNetworkObjIsActive(network)) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1128,8 +1145,11 @@ static int networkStartNetworkDaemon(struct network_driver
*driver,
return -1;
}
+ /* find the one allowed IPv4 ip address in the definition */
+ ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, 0);
+
/* Check to see if network collides with an existing route */
- if (networkCheckRouteCollision(network) < 0)
+ if (ipv4def && networkCheckRouteCollision(network, ipv4def) < 0)
return -1;
if ((err = brAddBridge(driver->brctl, network->def->bridge))) {
@@ -1158,8 +1178,8 @@ static int networkStartNetworkDaemon(struct network_driver *driver,
goto err_delbr;
}
- if (VIR_SOCKET_HAS_ADDR(&network->def->ipAddress)) {
- int prefix = virNetworkDefPrefix(network->def);
+ if (ipv4def) {
+ int prefix = virNetworkIpDefPrefix(ipv4def);
if (prefix < 0) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1169,7 +1189,7 @@ static int networkStartNetworkDaemon(struct network_driver *driver,
}
if ((err = brAddInetAddress(driver->brctl, network->def->bridge,
- &network->def->ipAddress, prefix))) {
+ &ipv4def->address, prefix))) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot set IP address on bridge
'%s'"),
network->def->bridge);
@@ -1184,7 +1204,7 @@ static int networkStartNetworkDaemon(struct network_driver *driver,
goto err_delbr;
}
- if (networkAddIptablesRules(driver, network) < 0)
+ if (ipv4def && networkAddIptablesRules(driver, network, ipv4def) < 0)
goto err_delbr1;
if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE &&
@@ -1194,12 +1214,13 @@ static int networkStartNetworkDaemon(struct network_driver
*driver,
goto err_delbr2;
}
- if ((VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) ||
- network->def->nranges) &&
- dhcpStartDhcpDaemon(network) < 0)
+ /*
+ * Start the dhcp daemon for the 1st (and only supported) ipv4
+ * address.
+ */
+ if (ipv4def && dhcpStartDhcpDaemon(network, ipv4def) < 0)
goto err_delbr2;
-
/* Persist the live configuration now we have bridge info */
if (virNetworkSaveConfig(NETWORK_STATE_DIR, network->def) < 0) {
goto err_kill;
@@ -1217,7 +1238,8 @@ static int networkStartNetworkDaemon(struct network_driver *driver,
err_delbr2:
save_err = virSaveLastError();
- networkRemoveIptablesRules(driver, network);
+ if (ipv4def)
+ networkRemoveIptablesRules(driver, network, ipv4def);
if (save_err) {
virSetError(save_err);
virFreeError(save_err);
@@ -1246,6 +1268,7 @@ static int networkShutdownNetworkDaemon(struct network_driver
*driver,
{
int err;
char *stateFile;
+ virNetworkIpDefPtr ipv4def;
VIR_INFO(_("Shutting down network '%s'"),
network->def->name);
@@ -1262,7 +1285,10 @@ static int networkShutdownNetworkDaemon(struct network_driver
*driver,
if (network->dnsmasqPid > 0)
kill(network->dnsmasqPid, SIGTERM);
- networkRemoveIptablesRules(driver, network);
+ /* find the one allowed IPv4 ip address in the definition */
+ ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, 0);
+ if (ipv4def)
+ networkRemoveIptablesRules(driver, network, ipv4def);
char ebuf[1024];
if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
@@ -1526,6 +1552,7 @@ cleanup:
static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) {
struct network_driver *driver = conn->networkPrivateData;
+ virNetworkIpDefPtr ipv4def;
virNetworkDefPtr def;
virNetworkObjPtr network = NULL;
virNetworkPtr ret = NULL;
@@ -1556,12 +1583,15 @@ static virNetworkPtr networkDefine(virConnectPtr conn, const char
*xml) {
goto cleanup;
}
- if (network->def->nhosts > 0) {
+ /* we only support dhcp on one IPv4 address per defined network */
+ ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, 0);
+
+ if (ipv4def && ipv4def->nhosts > 0) {
dnsmasqContext *dctx = dnsmasqContextNew(network->def->name,
DNSMASQ_STATE_DIR);
if (dctx == NULL)
goto cleanup;
- networkSaveDnsmasqHostsfile(network, dctx, true);
+ networkSaveDnsmasqHostsfile(ipv4def, dctx, true);
dnsmasqContextFree(dctx);
}
@@ -1577,7 +1607,8 @@ cleanup:
static int networkUndefine(virNetworkPtr net) {
struct network_driver *driver = net->conn->networkPrivateData;
- virNetworkObjPtr network = NULL;
+ virNetworkObjPtr network;
+ virNetworkIpDefPtr ipv4def;
int ret = -1;
networkDriverLock(driver);
@@ -1600,7 +1631,10 @@ static int networkUndefine(virNetworkPtr net) {
network) < 0)
goto cleanup;
- if (network->def->nhosts > 0) {
+ /* find the one allowed IPv4 ip address in the definition */
+ ipv4def = virNetworkDefGetIpByIndex(network->def, AF_INET, 0);
+
+ if (ipv4def && ipv4def->nhosts > 0) {
dnsmasqContext *dctx = dnsmasqContextNew(network->def->name,
DNSMASQ_STATE_DIR);
if (dctx == NULL)
goto cleanup;
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index 728c501..03defb5 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -7038,9 +7038,23 @@ static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr conn,
const char *
IHostNetworkInterface *networkInterface = NULL;
virNetworkDefPtr def = virNetworkDefParseString(xml);
+ virNetworkIpDefPtr ipdef;
+ virSocketAddr netmask;
if ( (!def)
- || (def->forwardType != VIR_NETWORK_FORWARD_NONE))
+ || (def->forwardType != VIR_NETWORK_FORWARD_NONE)
+ || (def->nips == 0 || !def->ips))
+ goto cleanup;
+
+ /* Look for the first IPv4 IP address definition and use that.
+ * If there weren't any IPv4 addresses, ignore the network (since it's
+ * required below to have an IPv4 address)
+ */
+ ipdef = virNetworkDefGetIpByIndex(def, AF_INET, 0);
+ if (!ipdef)
+ goto cleanup;
+
+ if (virNetworkIpDefNetmask(ipdef, &netmask) < 0)
goto cleanup;
/* the current limitation of hostonly network is that you can't
@@ -7096,9 +7110,9 @@ static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr conn,
const char *
/* Currently support only one dhcp server per network
* with contigious address space from start to end
*/
- if ((def->nranges >= 1) &&
- VIR_SOCKET_HAS_ADDR(&def->ranges[0].start) &&
- VIR_SOCKET_HAS_ADDR(&def->ranges[0].end)) {
+ if ((ipdef->nranges >= 1) &&
+ VIR_SOCKET_HAS_ADDR(&ipdef->ranges[0].start) &&
+ VIR_SOCKET_HAS_ADDR(&ipdef->ranges[0].end)) {
IDHCPServer *dhcpServer = NULL;
data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
@@ -7118,10 +7132,10 @@ static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr
conn, const char *
PRUnichar *toIPAddressUtf16 = NULL;
PRUnichar *trunkTypeUtf16 = NULL;
- ipAddressUtf16 = vboxSocketFormatAddrUtf16(data,
&def->ipAddress);
- networkMaskUtf16 = vboxSocketFormatAddrUtf16(data,
&def->netmask);
- fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data,
&def->ranges[0].start);
- toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data,
&def->ranges[0].end);
+ ipAddressUtf16 = vboxSocketFormatAddrUtf16(data,
&ipdef->address);
+ networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
+ fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data,
&ipdef->ranges[0].start);
+ toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data,
&ipdef->ranges[0].end);
if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL ||
fromIPAddressUtf16 == NULL || toIPAddressUtf16 == NULL) {
@@ -7158,13 +7172,13 @@ static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr
conn, const char *
}
}
- if ((def->nhosts >= 1) &&
- VIR_SOCKET_HAS_ADDR(&def->hosts[0].ip)) {
+ if ((ipdef->nhosts >= 1) &&
+ VIR_SOCKET_HAS_ADDR(&ipdef->hosts[0].ip)) {
PRUnichar *ipAddressUtf16 = NULL;
PRUnichar *networkMaskUtf16 = NULL;
- ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &def->hosts[0].ip);
- networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &def->netmask);
+ ipAddressUtf16 = vboxSocketFormatAddrUtf16(data,
&ipdef->hosts[0].ip);
+ networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) {
VBOX_UTF16_FREE(ipAddressUtf16);
@@ -7385,12 +7399,19 @@ static int vboxNetworkDestroy(virNetworkPtr network) {
static char *vboxNetworkDumpXML(virNetworkPtr network, int flags ATTRIBUTE_UNUSED) {
VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
virNetworkDefPtr def = NULL;
+ virNetworkIpDefPtr ipdef = NULL;
char *networkNameUtf8 = NULL;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
goto cleanup;
}
+ if (VIR_ALLOC(ipdef) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ def->ips = ipdef;
+ def->nips = 1;
if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s",
network->name) < 0) {
virReportOOMError();
@@ -7427,8 +7448,8 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags
ATTRIBUTE_UNUSE
networkNameUtf16,
&dhcpServer);
if (dhcpServer) {
- def->nranges = 1;
- if (VIR_ALLOC_N(def->ranges, def->nranges) >=0 ) {
+ ipdef->nranges = 1;
+ if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >=0 ) {
PRUnichar *ipAddressUtf16 = NULL;
PRUnichar *networkMaskUtf16 = NULL;
PRUnichar *fromIPAddressUtf16 = NULL;
@@ -7443,13 +7464,13 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags
ATTRIBUTE_UNUSE
* with contigious address space from start to end
*/
if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
- &def->ipAddress) < 0 ||
+ &ipdef->address) < 0 ||
vboxSocketParseAddrUtf16(data, networkMaskUtf16,
- &def->netmask) < 0 ||
+ &ipdef->netmask) < 0 ||
vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
- &def->ranges[0].start) < 0
||
+ &ipdef->ranges[0].start) <
0 ||
vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
- &def->ranges[0].end) < 0)
{
+ &ipdef->ranges[0].end) <
0) {
errorOccurred = true;
}
@@ -7462,16 +7483,16 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags
ATTRIBUTE_UNUSE
goto cleanup;
}
} else {
- def->nranges = 0;
+ ipdef->nranges = 0;
virReportOOMError();
}
- def->nhosts = 1;
- if (VIR_ALLOC_N(def->hosts, def->nhosts) >=0 ) {
- def->hosts[0].name = strdup(network->name);
- if (def->hosts[0].name == NULL) {
- VIR_FREE(def->hosts);
- def->nhosts = 0;
+ ipdef->nhosts = 1;
+ if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >=0 ) {
+ ipdef->hosts[0].name = strdup(network->name);
+ if (ipdef->hosts[0].name == NULL) {
+ VIR_FREE(ipdef->hosts);
+ ipdef->nhosts = 0;
virReportOOMError();
} else {
PRUnichar *macAddressUtf16 = NULL;
@@ -7481,10 +7502,10 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags
ATTRIBUTE_UNUSE
networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
networkInterface->vtbl->GetIPAddress(networkInterface,
&ipAddressUtf16);
- VBOX_UTF16_TO_UTF8(macAddressUtf16,
&def->hosts[0].mac);
+ VBOX_UTF16_TO_UTF8(macAddressUtf16,
&ipdef->hosts[0].mac);
if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
- &def->hosts[0].ip) <
0) {
+ &ipdef->hosts[0].ip) <
0) {
errorOccurred = true;
}
@@ -7496,7 +7517,7 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags
ATTRIBUTE_UNUSE
}
}
} else {
- def->nhosts = 0;
+ ipdef->nhosts = 0;
}
VBOX_RELEASE(dhcpServer);
@@ -7509,9 +7530,9 @@ static char *vboxNetworkDumpXML(virNetworkPtr network, int flags
ATTRIBUTE_UNUSE
networkInterface->vtbl->GetIPAddress(networkInterface,
&ipAddressUtf16);
if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
- &def->netmask) < 0 ||
+ &ipdef->netmask) < 0 ||
vboxSocketParseAddrUtf16(data, ipAddressUtf16,
- &def->ipAddress) < 0) {
+ &ipdef->address) < 0) {
errorOccurred = true;
}
diff --git a/tests/networkxml2xmlin/nat-network.xml
b/tests/networkxml2xmlin/nat-network.xml
index 93ab186..23f7fcb 100644
--- a/tests/networkxml2xmlin/nat-network.xml
+++ b/tests/networkxml2xmlin/nat-network.xml
@@ -10,4 +10,12 @@
<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">
+ </ip>
+ <ip family="ipv4" address="10.24.10.1">
+ </ip>
</network>
diff --git a/tests/networkxml2xmlout/nat-network.xml
b/tests/networkxml2xmlout/nat-network.xml
index 036d4fb..eb71d9e 100644
--- a/tests/networkxml2xmlout/nat-network.xml
+++ b/tests/networkxml2xmlout/nat-network.xml
@@ -10,4 +10,12 @@
<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'>
+ </ip>
+ <ip family='ipv4' address='10.24.10.1'>
+ </ip>
</network>
--
1.7.3.4