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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list