Add the possibility to have more than one IP address configured for a
domain network interface. IP addresses can also have a prefix to define
the corresponding netmask.
---
docs/formatdomain.html.in | 22 +++++++
docs/schemas/domaincommon.rng | 11 +++-
src/conf/domain_conf.c | 123 +++++++++++++++++++++++++++++++------
src/conf/domain_conf.h | 16 ++++-
src/libvirt_private.syms | 2 +
src/openvz/openvz_conf.c | 2 +-
src/openvz/openvz_driver.c | 6 +-
src/qemu/qemu_driver.c | 25 ++++++--
src/qemu/qemu_hotplug.c | 6 +-
src/uml/uml_conf.c | 2 +-
src/vbox/vbox_common.c | 3 +-
src/xenconfig/xen_common.c | 15 ++---
src/xenconfig/xen_sxpr.c | 12 ++--
tests/lxcxml2xmldata/lxc-idmap.xml | 2 +
14 files changed, 195 insertions(+), 52 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 0099ce7..8e3a522 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -4240,6 +4240,28 @@ qemu-kvm -net nic,model=? /dev/null
<span class="since">Since 0.9.5</span>
</p>
+ <h5><a name="ipconfig">IP configuration</a></h5>
+<pre>
+ ...
+ <devices>
+ <interface type='network'>
+ <source network='default'/>
+ <target dev='vnet0'/>
+ <b><ip address='192.168.122.5'
prefix='24'/></b>
+ </interface>
+ </devices>
+ ...
+</pre>
+
+ <p>
+ <span class="since">Since 1.2.10</span> the network devices can
be provided
+ zero or more IP addresses to set
+ on the target device. Note that some hypervisors or network device types
+ will simply ignore them or only use the first one. The
<code>address</code>
+ attribute can hold either an IPv4 or IPv6 address. The
<code>prefix</code>
+ is not mandatory since some hypervisors do not handle it.
+ </p>
+
<h5><a name="elementVhostuser">vhost-user
interface</a></h5>
<p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 20d81ae..a82d705 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2290,14 +2290,19 @@
<empty/>
</element>
</optional>
- <optional>
+ <zeroOrMore>
<element name="ip">
<attribute name="address">
- <ref name="ipv4Addr"/>
+ <ref name="ipAddr"/>
</attribute>
+ <optional>
+ <attribute name="prefix">
+ <ref name="ipPrefix"/>
+ </attribute>
+ </optional>
<empty/>
</element>
- </optional>
+ </zeroOrMore>
<optional>
<element name="script">
<attribute name="path">
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b5c761f..c7ab962 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1367,6 +1367,8 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def)
void virDomainNetDefFree(virDomainNetDefPtr def)
{
+ size_t i;
+
if (!def)
return;
@@ -1375,7 +1377,6 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_ETHERNET:
VIR_FREE(def->data.ethernet.dev);
- VIR_FREE(def->data.ethernet.ipaddr);
break;
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
@@ -1396,7 +1397,6 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
case VIR_DOMAIN_NET_TYPE_BRIDGE:
VIR_FREE(def->data.bridge.brname);
- VIR_FREE(def->data.bridge.ipaddr);
break;
case VIR_DOMAIN_NET_TYPE_INTERNAL:
@@ -1424,6 +1424,10 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
VIR_FREE(def->ifname_guest);
VIR_FREE(def->ifname_guest_actual);
+ for (i = 0; i < def->nips; i++)
+ virDomainNetIpDefFree(def->ips[i]);
+ VIR_FREE(def->ips);
+
virDomainDeviceInfoClear(&def->info);
VIR_FREE(def->filter);
@@ -1435,6 +1439,12 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
VIR_FREE(def);
}
+void virDomainNetIpDefFree(virDomainNetIpDefPtr def)
+{
+ VIR_FREE(def->address);
+ VIR_FREE(def);
+}
+
void ATTRIBUTE_NONNULL(1)
virDomainChrSourceDefClear(virDomainChrSourceDefPtr def)
{
@@ -6927,6 +6937,29 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
#define NET_MODEL_CHARS \
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
+
+int
+virDomainNetAppendIpAddress(virDomainNetDefPtr def,
+ const char *address,
+ unsigned int prefix)
+{
+ virDomainNetIpDefPtr ipDef = NULL;
+ if (VIR_ALLOC(ipDef) < 0)
+ return -1;
+
+ if (VIR_STRDUP(ipDef->address, address) < 0)
+ return -1;
+
+ ipDef->prefix = prefix;
+
+ if (VIR_APPEND_ELEMENT(def->ips, def->nips, ipDef) < 0) {
+ virDomainNetIpDefFree(ipDef);
+ return -1;
+ }
+
+ return 0;
+}
+
/* Parse the XML definition for a network interface
* @param node XML nodeset to parse for net definition
* @return 0 on success, -1 on failure
@@ -6974,6 +7007,10 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
virDomainActualNetDefPtr actual = NULL;
xmlNodePtr oldnode = ctxt->node;
int ret, val;
+ unsigned int prefix = 0;
+ size_t i;
+ size_t nips = 0;
+ virDomainNetIpDefPtr *ips = NULL;
if (VIR_ALLOC(def) < 0)
return NULL;
@@ -7062,11 +7099,44 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
xmlStrEqual(cur->name, BAD_CAST "source")) {
address = virXMLPropString(cur, "address");
port = virXMLPropString(cur, "port");
- } else if (!address &&
- (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
- def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
- xmlStrEqual(cur->name, BAD_CAST "ip")) {
- address = virXMLPropString(cur, "address");
+ } else if (xmlStrEqual(cur->name, BAD_CAST "ip")) {
+ /* Parse the prefix in every case */
+ char *prefixStr = NULL;
+ unsigned int prefixValue = 0;
+
+ if ((prefixStr = virXMLPropString(cur, "prefix")) &&
+ (virStrToLong_ui(prefixStr, NULL, 10, &prefixValue) < 0)) {
+
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("Invalid network prefix: '%s'"),
+ prefixStr);
+ VIR_FREE(prefixStr);
+ goto error;
+ }
+ VIR_FREE(prefixStr);
+
+ /* Previous behavior: make sure this address it the first one
+ in the resulting list */
+ if (!address &&
+ (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
+ def->type == VIR_DOMAIN_NET_TYPE_BRIDGE)) {
+
+ address = virXMLPropString(cur, "address");
+ prefix = prefixValue;
+ } else {
+ /* All other <ip/> elements will be added after */
+ virDomainNetIpDefPtr ip = NULL;
+
+ if (VIR_ALLOC(ip) < 0)
+ goto error;
+
+ ip->address = virXMLPropString(cur, "address");
+ ip->prefix = prefixValue;
+
+ if (ip->address != NULL &&
+ VIR_APPEND_ELEMENT(ips, nips, ip) < 0)
+ goto error;
+ }
} else if (!ifname &&
xmlStrEqual(cur->name, BAD_CAST "target")) {
ifname = virXMLPropString(cur, "dev");
@@ -7267,8 +7337,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
dev = NULL;
}
if (address != NULL) {
- def->data.ethernet.ipaddr = address;
- address = NULL;
+ virDomainNetAppendIpAddress(def, address, prefix);
+ VIR_FREE(address);
}
break;
@@ -7282,8 +7352,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
def->data.bridge.brname = bridge;
bridge = NULL;
if (address != NULL) {
- def->data.bridge.ipaddr = address;
- address = NULL;
+ virDomainNetAppendIpAddress(def, address, prefix);
+ VIR_FREE(address);
}
break;
@@ -7381,6 +7451,11 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
break;
}
+ for (i = 0; i < nips; i++) {
+ if (VIR_APPEND_ELEMENT(def->ips, def->nips, ips[i]) < 0)
+ goto error;
+ }
+
if (script != NULL) {
def->script = script;
script = NULL;
@@ -7643,6 +7718,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
VIR_FREE(linkstate);
VIR_FREE(addrtype);
VIR_FREE(trustGuestRxFilters);
+ VIR_FREE(ips);
virNWFilterHashTableFree(filterparams);
return def;
@@ -16631,6 +16707,21 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf,
return 0;
}
+static void
+virDomainNetIpsFormat(virBufferPtr buf, virDomainNetIpDefPtr *ips, size_t nips)
+{
+ size_t i;
+
+ /* Output IP addresses */
+ for (i = 0; i < nips; i++) {
+ virBufferAsprintf(buf, "<ip address='%s'",
+ ips[i]->address);
+ if (ips[i]->prefix != 0)
+ virBufferAsprintf(buf, " prefix='%u'", ips[i]->prefix);
+ virBufferAddLit(buf, "/>\n");
+ }
+}
+
static int
virDomainHostdevDefFormatCaps(virBufferPtr buf,
virDomainHostdevDefPtr def)
@@ -16736,7 +16827,6 @@ virDomainActualNetDefContentsFormat(virBufferPtr buf,
return 0;
}
-
/* virDomainActualNetDefFormat() - format the ActualNetDef
* info inside an <actual> element, as required for internal storage
* of domain status
@@ -16973,9 +17063,6 @@ virDomainNetDefFormat(virBufferPtr buf,
case VIR_DOMAIN_NET_TYPE_ETHERNET:
virBufferEscapeString(buf, "<source dev='%s'/>\n",
def->data.ethernet.dev);
- if (def->data.ethernet.ipaddr)
- virBufferAsprintf(buf, "<ip address='%s'/>\n",
- def->data.ethernet.ipaddr);
break;
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
@@ -16992,10 +17079,6 @@ virDomainNetDefFormat(virBufferPtr buf,
case VIR_DOMAIN_NET_TYPE_BRIDGE:
virBufferEscapeString(buf, "<source
bridge='%s'/>\n",
def->data.bridge.brname);
- if (def->data.bridge.ipaddr) {
- virBufferAsprintf(buf, "<ip address='%s'/>\n",
- def->data.bridge.ipaddr);
- }
break;
case VIR_DOMAIN_NET_TYPE_SERVER:
@@ -17043,6 +17126,8 @@ virDomainNetDefFormat(virBufferPtr buf,
return -1;
}
+ virDomainNetIpsFormat(buf, def->ips, def->nips);
+
virBufferEscapeString(buf, "<script path='%s'/>\n",
def->script);
if (def->ifname &&
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index afa3da6..6ecf639 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -471,6 +471,15 @@ typedef enum {
VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST
} virDomainHostdevCapsType;
+typedef struct _virDomainNetIpDef virDomainNetIpDef;
+typedef virDomainNetIpDef *virDomainNetIpDefPtr;
+struct _virDomainNetIpDef {
+ char *address; /* ipv4 or ipv6 address */
+ unsigned int prefix; /* number of 1 bits in the net mask */
+};
+
+void virDomainNetIpDefFree(virDomainNetIpDefPtr def);
+
typedef struct _virDomainHostdevCaps virDomainHostdevCaps;
typedef virDomainHostdevCaps *virDomainHostdevCapsPtr;
struct _virDomainHostdevCaps {
@@ -925,7 +934,6 @@ struct _virDomainNetDef {
union {
struct {
char *dev;
- char *ipaddr;
} ethernet;
virDomainChrSourceDefPtr vhostuser;
struct {
@@ -947,7 +955,6 @@ struct _virDomainNetDef {
} network;
struct {
char *brname;
- char *ipaddr;
} bridge;
struct {
char *name;
@@ -977,6 +984,8 @@ struct _virDomainNetDef {
virNetDevVlan vlan;
int trustGuestRxFilters; /* enum virTristateBool */
int linkstate;
+ size_t nips;
+ virDomainNetIpDefPtr *ips;
};
/* Used for prefix of ifname of any network name generated dynamically
@@ -2513,6 +2522,9 @@ virNetDevBandwidthPtr
virDomainNetGetActualBandwidth(virDomainNetDefPtr iface);
virNetDevVlanPtr virDomainNetGetActualVlan(virDomainNetDefPtr iface);
bool virDomainNetGetActualTrustGuestRxFilters(virDomainNetDefPtr iface);
+int virDomainNetAppendIpAddress(virDomainNetDefPtr def,
+ const char *address,
+ unsigned int prefix);
int virDomainControllerInsert(virDomainDefPtr def,
virDomainControllerDefPtr controller)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d6265ac..b55bf35 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -321,6 +321,7 @@ virDomainLockFailureTypeFromString;
virDomainLockFailureTypeToString;
virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
+virDomainNetAppendIpAddress;
virDomainNetDefFormat;
virDomainNetDefFree;
virDomainNetFind;
@@ -336,6 +337,7 @@ virDomainNetGetActualType;
virDomainNetGetActualVirtPortProfile;
virDomainNetGetActualVlan;
virDomainNetInsert;
+virDomainNetIpDefFree;
virDomainNetRemove;
virDomainNetRemoveHostdev;
virDomainNetTypeToString;
diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c
index 856c9f5..ea45e96 100644
--- a/src/openvz/openvz_conf.c
+++ b/src/openvz/openvz_conf.c
@@ -230,7 +230,7 @@ openvzReadNetworkConf(virDomainDefPtr def,
goto error;
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
- if (VIR_STRDUP(net->data.ethernet.ipaddr, token) < 0)
+ if (virDomainNetAppendIpAddress(net, token, 0) < 0)
goto error;
if (VIR_APPEND_ELEMENT_COPY(def->nets, def->nnets, net) < 0)
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index b62273a..a0dfbee 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -855,7 +855,7 @@ openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
(net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
- net->data.ethernet.ipaddr == NULL)) {
+ net->nips == 0)) {
virBuffer buf = VIR_BUFFER_INITIALIZER;
int veid = openvzGetVEID(vpsid);
@@ -906,9 +906,9 @@ openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
virCommandAddArg(cmd, "--netif_add");
virCommandAddArgBuffer(cmd, &buf);
} else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
- net->data.ethernet.ipaddr != NULL) {
+ net->nips > 0 && net->ips[0]->address != NULL) {
/* --ipadd ip */
- virCommandAddArgList(cmd, "--ipadd", net->data.ethernet.ipaddr,
NULL);
+ virCommandAddArgList(cmd, "--ipadd", net->ips[0]->address,
NULL);
}
/* TODO: processing NAT and physical device */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 7c9b1ab..6da9ceb 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6261,6 +6261,8 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
(brname = virDomainNetGetActualBridgeName(net))) {
char *brnamecopy;
+ size_t j;
+
if (VIR_STRDUP(brnamecopy, brname) < 0)
goto cleanup;
@@ -6271,20 +6273,31 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
net->script = NULL;
net->data.ethernet.dev = brnamecopy;
- net->data.ethernet.ipaddr = NULL;
+ for (j = 0; j < net->nips; j++) {
+ virDomainNetIpDefFree(net->ips[j]);
+ }
+ VIR_FREE(net->ips);
+ net->nips = 0;
+
} else {
/* actualType is either NETWORK or DIRECT. In either
* case, the best we can do is NULL everything out.
*/
+ size_t j;
virDomainActualNetDefFree(net->data.network.actual);
memset(net, 0, sizeof(*net));
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
net->script = NULL;
net->data.ethernet.dev = NULL;
- net->data.ethernet.ipaddr = NULL;
+ for (j = 0; j < net->nips; j++) {
+ virDomainNetIpDefFree(net->ips[j]);
+ }
+ VIR_FREE(net->ips);
+ net->nips = 0;
}
} else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
+ size_t j;
VIR_FREE(net->data.direct.linkdev);
memset(net, 0, sizeof(*net));
@@ -6292,18 +6305,20 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
net->script = NULL;
net->data.ethernet.dev = NULL;
- net->data.ethernet.ipaddr = NULL;
+ for (j = 0; j < net->nips; j++) {
+ virDomainNetIpDefFree(net->ips[j]);
+ }
+ VIR_FREE(net->ips);
+ net->nips = 0;
} else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
char *script = net->script;
char *brname = net->data.bridge.brname;
- char *ipaddr = net->data.bridge.ipaddr;
memset(net, 0, sizeof(*net));
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
net->script = script;
net->data.ethernet.dev = brname;
- net->data.ethernet.ipaddr = ipaddr;
}
VIR_FREE(net->virtPortProfile);
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 1e504ec..3b31b77 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2090,8 +2090,10 @@ qemuDomainChangeNet(virQEMUDriverPtr driver,
case VIR_DOMAIN_NET_TYPE_ETHERNET:
if (STRNEQ_NULLABLE(olddev->data.ethernet.dev,
newdev->data.ethernet.dev) ||
- STRNEQ_NULLABLE(olddev->data.ethernet.ipaddr,
- newdev->data.ethernet.ipaddr)) {
+ STRNEQ_NULLABLE(olddev->nips > 0 ? olddev->ips[0]->address
+ : "",
+ newdev->nips > 0 ? newdev->ips[0]->address
+ : "")) {
needReconnect = true;
}
break;
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index a99e8e9..ac6a7da 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -175,7 +175,7 @@ umlBuildCommandLineNet(virConnectPtr conn,
if (def->ifname) {
virBufferAdd(&buf, def->ifname, -1);
}
- if (def->data.ethernet.ipaddr) {
+ if (def->nips > 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("IP address not supported for ethernet
interface"));
goto error;
diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
index 44270ff..ffc450f 100644
--- a/src/vbox/vbox_common.c
+++ b/src/vbox/vbox_common.c
@@ -1322,7 +1322,8 @@ vboxAttachNetwork(virDomainDefPtr def, vboxGlobalData *data,
IMachine *machine)
} else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
VIR_DEBUG("NIC(%zu): brname: %s", i,
def->nets[i]->data.bridge.brname);
VIR_DEBUG("NIC(%zu): script: %s", i, def->nets[i]->script);
- VIR_DEBUG("NIC(%zu): ipaddr: %s", i,
def->nets[i]->data.bridge.ipaddr);
+ if (def->nets[i]->nips > 0)
+ VIR_DEBUG("NIC(%zu): ipaddr: %s", i,
def->nets[i]->ips[0]->address);
}
gVBoxAPI.UIMachine.GetNetworkAdapter(machine, i, &adapter);
diff --git a/src/xenconfig/xen_common.c b/src/xenconfig/xen_common.c
index 32954f3..8347cf7 100644
--- a/src/xenconfig/xen_common.c
+++ b/src/xenconfig/xen_common.c
@@ -922,12 +922,9 @@ xenParseVif(virConfPtr conf, virDomainDefPtr def)
if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
if (bridge[0] && VIR_STRDUP(net->data.bridge.brname, bridge)
< 0)
goto cleanup;
- if (ip[0] && VIR_STRDUP(net->data.bridge.ipaddr, ip) < 0)
- goto cleanup;
- } else {
- if (ip[0] && VIR_STRDUP(net->data.ethernet.ipaddr, ip) <
0)
- goto cleanup;
}
+ if (ip[0] && virDomainNetAppendIpAddress(net, ip, 0) < 0)
+ goto cleanup;
if (script && script[0] &&
VIR_STRDUP(net->script, script) < 0)
@@ -1225,16 +1222,16 @@ xenFormatNet(virConnectPtr conn,
switch (net->type) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
virBufferAsprintf(&buf, ",bridge=%s", net->data.bridge.brname);
- if (net->data.bridge.ipaddr)
- virBufferAsprintf(&buf, ",ip=%s", net->data.bridge.ipaddr);
+ if (net->nips > 0)
+ virBufferAsprintf(&buf, ",ip=%s", net->ips[0]->address);
virBufferAsprintf(&buf, ",script=%s", DEFAULT_VIF_SCRIPT);
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
if (net->script)
virBufferAsprintf(&buf, ",script=%s", net->script);
- if (net->data.ethernet.ipaddr)
- virBufferAsprintf(&buf, ",ip=%s",
net->data.ethernet.ipaddr);
+ if (net->nips > 0)
+ virBufferAsprintf(&buf, ",ip=%s", net->ips[0]->address);
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:
diff --git a/src/xenconfig/xen_sxpr.c b/src/xenconfig/xen_sxpr.c
index 6623ea8..8e64afb 100644
--- a/src/xenconfig/xen_sxpr.c
+++ b/src/xenconfig/xen_sxpr.c
@@ -565,14 +565,14 @@ xenParseSxprNets(virDomainDefPtr def,
VIR_STRDUP(net->script, tmp2) < 0)
goto cleanup;
tmp = sexpr_node(node, "device/vif/ip");
- if (VIR_STRDUP(net->data.bridge.ipaddr, tmp) < 0)
+ if (tmp && virDomainNetAppendIpAddress(net, tmp, 0) < 0)
goto cleanup;
} else {
net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
if (VIR_STRDUP(net->script, tmp2) < 0)
goto cleanup;
tmp = sexpr_node(node, "device/vif/ip");
- if (VIR_STRDUP(net->data.ethernet.ipaddr, tmp) < 0)
+ if (tmp && virDomainNetAppendIpAddress(net, tmp, 0) < 0)
goto cleanup;
}
@@ -1898,8 +1898,8 @@ xenFormatSxprNet(virConnectPtr conn,
script = def->script;
virBufferEscapeSexpr(buf, "(script '%s')", script);
- if (def->data.bridge.ipaddr != NULL)
- virBufferEscapeSexpr(buf, "(ip '%s')",
def->data.bridge.ipaddr);
+ if (def->nips > 0)
+ virBufferEscapeSexpr(buf, "(ip '%s')",
def->ips[0]->address);
break;
case VIR_DOMAIN_NET_TYPE_NETWORK:
@@ -1932,8 +1932,8 @@ xenFormatSxprNet(virConnectPtr conn,
if (def->script)
virBufferEscapeSexpr(buf, "(script '%s')",
def->script);
- if (def->data.ethernet.ipaddr != NULL)
- virBufferEscapeSexpr(buf, "(ip '%s')",
def->data.ethernet.ipaddr);
+ if (def->nips > 0)
+ virBufferEscapeSexpr(buf, "(ip '%s')",
def->ips[0]->address);
break;
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
diff --git a/tests/lxcxml2xmldata/lxc-idmap.xml b/tests/lxcxml2xmldata/lxc-idmap.xml
index 946d363..a52da0b 100644
--- a/tests/lxcxml2xmldata/lxc-idmap.xml
+++ b/tests/lxcxml2xmldata/lxc-idmap.xml
@@ -28,6 +28,8 @@
<interface type='bridge'>
<mac address='00:16:3e:0f:ef:8a'/>
<source bridge='bri0'/>
+ <ip address='192.168.122.12' prefix='24'/>
+ <ip address='192.168.122.13' prefix='24'/>
<target dev='veth0'/>
<guest dev='eth2'/>
</interface>
--
1.8.4.5