On Thursday 13 November 2014 10:33:01 Cédric Bosdonnat wrote: > 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. I totally agree with this patch. IP configuration must be separated from device type and connection configuration. ACK > --- > docs/formatdomain.html.in | 22 ++++ > docs/schemas/domaincommon.rng | 16 ++- > src/conf/domain_conf.c | 149 > ++++++++++++++++++++---- src/conf/domain_conf.h | > 15 ++- > src/libvirt_private.syms | 1 + > src/openvz/openvz_conf.c | 2 +- > src/openvz/openvz_driver.c | 7 +- > src/qemu/qemu_driver.c | 29 ++++- > src/qemu/qemu_hotplug.c | 5 +- > src/uml/uml_conf.c | 2 +- > src/vbox/vbox_common.c | 6 +- > src/xenconfig/xen_common.c | 21 ++-- > src/xenconfig/xen_sxpr.c | 18 ++- > tests/lxcxml2xmldata/lxc-idmap.xml | 2 + > tests/openvzutilstest.c | 2 +- > tests/sexpr2xmldata/sexpr2xml-bridge-ipaddr.xml | 2 +- > tests/sexpr2xmldata/sexpr2xml-net-routed.xml | 2 +- > 17 files changed, 242 insertions(+), 59 deletions(-) > > diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in > index d4189e6..d414371 100644 > --- a/docs/formatdomain.html.in > +++ b/docs/formatdomain.html.in > @@ -4283,6 +4283,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 6863ec6..cd82461 100644 > --- a/docs/schemas/domaincommon.rng > +++ b/docs/schemas/domaincommon.rng > @@ -2295,14 +2295,24 @@ > <empty/> > </element> > </optional> > - <optional> > + <zeroOrMore> > <element name="ip"> > <attribute name="address"> > - <ref name="ipv4Addr"/> > + <ref name="ipAddr"/> > </attribute> > + <optional> > + <attribute name="family"> > + <ref name="addr-family"/> > + </attribute> > + </optional> > + <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 8c00dd1..44741a9 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++) > + VIR_FREE(def->ips[i]); > + VIR_FREE(def->ips); > + > virDomainDeviceInfoClear(&def->info); > > VIR_FREE(def->filter); > @@ -4667,6 +4671,58 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, > return ret; > } > > +static virDomainNetIpDefPtr > +virDomainNetIpParseXML(xmlNodePtr node) > +{ > + /* Parse the prefix in every case */ > + virDomainNetIpDefPtr ip = NULL; > + char *prefixStr = NULL; > + unsigned int prefixValue = 0; > + char *familyStr = NULL; > + int family = AF_UNSPEC; > + char *address = NULL; > + > + if (!(prefixStr = virXMLPropString(node, "prefix")) || > + (virStrToLong_ui(prefixStr, NULL, 10, &prefixValue) < 0)) { > + // Don't shout, just warn as some old config may not have a prefix > + VIR_WARN("Missing or invalid network prefix"); > + } > + > + if (!(address = virXMLPropString(node, "address"))) { > + virReportError(VIR_ERR_INVALID_ARG, "%s", > + _("Missing network address")); > + goto error; > + } > + > + familyStr = virXMLPropString(node, "family"); > + if (familyStr && STREQ(familyStr, "ipv4")) > + family = AF_INET; > + else if (familyStr && STREQ(familyStr, "ipv6")) > + family = AF_INET6; > + else > + family = virSocketAddrNumericFamily(address); > + > + if (VIR_ALLOC(ip) < 0) > + goto error; > + > + if (virSocketAddrParse(&ip->address, address, family) < 0) { > + virReportError(VIR_ERR_INVALID_ARG, > + _("Failed to parse IP address: '%s'"), > + address); > + goto error; > + } > + ip->prefix = prefixValue; > + > + return ip; > + > + error: > + VIR_FREE(prefixStr); > + VIR_FREE(familyStr); > + VIR_FREE(address); > + VIR_FREE(ip); > + return NULL; > +} > + > static int > virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED, > xmlXPathContextPtr ctxt, > @@ -7077,6 +7133,31 @@ virDomainActualNetDefParseXML(xmlNodePtr node, > #define NET_MODEL_CHARS \ > "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-" > > + > +int > +virDomainNetAppendIpAddress(virDomainNetDefPtr def, > + const char *address, > + int family, > + unsigned int prefix) > +{ > + virDomainNetIpDefPtr ipDef = NULL; > + if (VIR_ALLOC(ipDef) < 0) > + return -1; > + > + if (virSocketAddrParse(&ipDef->address, address, family) < 0) > + goto error; > + ipDef->prefix = prefix; > + > + if (VIR_APPEND_ELEMENT(def->ips, def->nips, ipDef) < 0) > + goto error; > + > + return 0; > + > + error: > + VIR_FREE(ipDef); > + return -1; > +} > + > /* Parse the XML definition for a network interface > * @param node XML nodeset to parse for net definition > * @return 0 on success, -1 on failure > @@ -7124,6 +7205,9 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, > virDomainActualNetDefPtr actual = NULL; > xmlNodePtr oldnode = ctxt->node; > int ret, val; > + size_t i; > + size_t nips = 0; > + virDomainNetIpDefPtr *ips = NULL; > > if (VIR_ALLOC(def) < 0) > return NULL; > @@ -7212,11 +7296,14 @@ 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")) { > + virDomainNetIpDefPtr ip = NULL; > + > + if (!(ip = virDomainNetIpParseXML(cur))) > + goto error; > + > + if (VIR_APPEND_ELEMENT(ips, nips, ip) < 0) > + goto error; > } else if (!ifname && > xmlStrEqual(cur->name, BAD_CAST "target")) { > ifname = virXMLPropString(cur, "dev"); > @@ -7416,10 +7503,6 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, > def->data.ethernet.dev = dev; > dev = NULL; > } > - if (address != NULL) { > - def->data.ethernet.ipaddr = address; > - address = NULL; > - } > break; > > case VIR_DOMAIN_NET_TYPE_BRIDGE: > @@ -7431,10 +7514,6 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, > } > def->data.bridge.brname = bridge; > bridge = NULL; > - if (address != NULL) { > - def->data.bridge.ipaddr = address; > - address = NULL; > - } > break; > > case VIR_DOMAIN_NET_TYPE_CLIENT: > @@ -7531,6 +7610,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; > @@ -7793,6 +7877,7 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, > VIR_FREE(linkstate); > VIR_FREE(addrtype); > VIR_FREE(trustGuestRxFilters); > + VIR_FREE(ips); > virNWFilterHashTableFree(filterparams); > > return def; > @@ -16753,6 +16838,30 @@ virDomainFSDefFormat(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++) { > + virSocketAddrPtr address = &ips[i]->address; > + char *ipStr = virSocketAddrFormat(address); > + const char *familyStr = NULL; > + if (VIR_SOCKET_ADDR_IS_FAMILY(address, AF_INET6)) > + familyStr = "ipv6"; > + else if (VIR_SOCKET_ADDR_IS_FAMILY(address, AF_INET)) > + familyStr = "ipv4"; > + virBufferAsprintf(buf, "<ip address='%s'", > + ipStr); > + if (familyStr) > + virBufferAsprintf(buf, " family='%s'", familyStr); > + if (ips[i]->prefix != 0) > + virBufferAsprintf(buf, " prefix='%u'", ips[i]->prefix); > + virBufferAddLit(buf, "/>\n"); > + } > +} > + > static int > virDomainHostdevDefFormatSubsys(virBufferPtr buf, > virDomainHostdevDefPtr def, > @@ -16980,7 +17089,6 @@ virDomainActualNetDefContentsFormat(virBufferPtr > buf, return 0; > } > > - > /* virDomainActualNetDefFormat() - format the ActualNetDef > * info inside an <actual> element, as required for internal storage > * of domain status > @@ -17217,9 +17325,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: > @@ -17237,10 +17342,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: > @@ -17288,6 +17389,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 530a3ca..fbf6067 100644 > --- a/src/conf/domain_conf.h > +++ b/src/conf/domain_conf.h > @@ -471,6 +471,13 @@ typedef enum { > VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST > } virDomainHostdevCapsType; > > +typedef struct _virDomainNetIpDef virDomainNetIpDef; > +typedef virDomainNetIpDef *virDomainNetIpDefPtr; > +struct _virDomainNetIpDef { > + virSocketAddr address; /* ipv4 or ipv6 address */ > + unsigned int prefix; /* number of 1 bits in the net mask */ > +}; > + > typedef struct _virDomainHostdevCaps virDomainHostdevCaps; > typedef virDomainHostdevCaps *virDomainHostdevCapsPtr; > struct _virDomainHostdevCaps { > @@ -932,7 +939,6 @@ struct _virDomainNetDef { > union { > struct { > char *dev; > - char *ipaddr; > } ethernet; > virDomainChrSourceDefPtr vhostuser; > struct { > @@ -954,7 +960,6 @@ struct _virDomainNetDef { > } network; > struct { > char *brname; > - char *ipaddr; > } bridge; > struct { > char *name; > @@ -984,6 +989,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 > @@ -2522,6 +2529,10 @@ virNetDevBandwidthPtr > virDomainNetGetActualBandwidth(virDomainNetDefPtr iface); > virNetDevVlanPtr virDomainNetGetActualVlan(virDomainNetDefPtr iface); > bool virDomainNetGetActualTrustGuestRxFilters(virDomainNetDefPtr iface); > +int virDomainNetAppendIpAddress(virDomainNetDefPtr def, > + const char *address, > + int family, > + unsigned int prefix); > > int virDomainControllerInsert(virDomainDefPtr def, > virDomainControllerDefPtr controller) > diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms > index 0864618..8d02438 100644 > --- a/src/libvirt_private.syms > +++ b/src/libvirt_private.syms > @@ -321,6 +321,7 @@ virDomainLockFailureTypeFromString; > virDomainLockFailureTypeToString; > virDomainMemballoonModelTypeFromString; > virDomainMemballoonModelTypeToString; > +virDomainNetAppendIpAddress; > virDomainNetDefFormat; > virDomainNetDefFree; > virDomainNetFind; > diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c > index 856c9f5..b6fdc37 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, AF_UNSPEC, 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 a0346b4..273bac1 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,10 @@ 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) { > /* --ipadd ip */ > - virCommandAddArgList(cmd, "--ipadd", net->data.ethernet.ipaddr, > NULL); + char *ipStr = virSocketAddrFormat(&net->ips[0]->address); + > virCommandAddArgList(cmd, "--ipadd", ipStr, NULL); > } > > /* TODO: processing NAT and physical device */ > diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c > index acf2b9a..2863db4 100644 > --- a/src/qemu/qemu_driver.c > +++ b/src/qemu/qemu_driver.c > @@ -6352,6 +6352,8 @@ static char > *qemuConnectDomainXMLToNative(virConnectPtr conn, (brname = > virDomainNetGetActualBridgeName(net))) { > > char *brnamecopy; > + size_t j; > + > if (VIR_STRDUP(brnamecopy, brname) < 0) > goto cleanup; > > @@ -6362,20 +6364,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++) { > + VIR_FREE(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++) { > + VIR_FREE(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)); > @@ -6383,18 +6396,24 @@ 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++) { > + VIR_FREE(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; > + size_t nips = net->nips; > + virDomainNetIpDefPtr *ips = net->ips; > > 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; > + net->nips = nips; > + net->ips = ips; > } > > VIR_FREE(net->virtPortProfile); > diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c > index 13bcd88..60a6fd9 100644 > --- a/src/qemu/qemu_hotplug.c > +++ b/src/qemu/qemu_hotplug.c > @@ -2101,8 +2101,9 @@ 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)) { > + olddev->nips == 0 || newdev->nips == 0 || > + !virSocketAddrEqual(&olddev->ips[0]->address, > + &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 cd5b478..fa1e12d 100644 > --- a/src/vbox/vbox_common.c > +++ b/src/vbox/vbox_common.c > @@ -1307,7 +1307,11 @@ 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) > { > + char *ipStr = > virSocketAddrFormat(&def->nets[i]->ips[0]->address); + > VIR_DEBUG("NIC(%zu): ipaddr: %s", i, ipStr); > + VIR_FREE(ipStr); > + } > } > > gVBoxAPI.UIMachine.GetNetworkAdapter(machine, i, &adapter); > diff --git a/src/xenconfig/xen_common.c b/src/xenconfig/xen_common.c > index 32954f3..bcb3bd3 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, AF_INET, 0) < > 0) + goto cleanup; > > if (script && script[0] && > VIR_STRDUP(net->script, script) < 0) > @@ -1225,16 +1222,22 @@ 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) { > + char *ipStr = virSocketAddrFormat(&net->ips[0]->address); > + virBufferAsprintf(&buf, ",ip=%s", ipStr); > + VIR_FREE(ipStr); > + } > 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) { > + char *ipStr = virSocketAddrFormat(&net->ips[0]->address); > + virBufferAsprintf(&buf, ",ip=%s", ipStr); > + VIR_FREE(ipStr); > + } > break; > > case VIR_DOMAIN_NET_TYPE_NETWORK: > diff --git a/src/xenconfig/xen_sxpr.c b/src/xenconfig/xen_sxpr.c > index 6623ea8..caeb464 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, AF_UNSPEC, > 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, AF_UNSPEC, > 0) < 0) goto cleanup; > } > > @@ -1898,8 +1898,11 @@ 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) { > + char *ipStr = virSocketAddrFormat(&def->ips[0]->address); > + virBufferEscapeSexpr(buf, "(ip '%s')", ipStr); > + VIR_FREE(ipStr); > + } > break; > > case VIR_DOMAIN_NET_TYPE_NETWORK: > @@ -1932,8 +1935,11 @@ 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) { > + char *ipStr = virSocketAddrFormat(&def->ips[0]->address); > + virBufferEscapeSexpr(buf, "(ip '%s')", ipStr); > + VIR_FREE(ipStr); > + } > break; > > case VIR_DOMAIN_NET_TYPE_VHOSTUSER: > diff --git a/tests/lxcxml2xmldata/lxc-idmap.xml > b/tests/lxcxml2xmldata/lxc-idmap.xml index 946d363..d011927 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' family='ipv4' prefix='24'/> > + <ip address='192.168.122.13' family='ipv4' prefix='24'/> > <target dev='veth0'/> > <guest dev='eth2'/> > </interface> > diff --git a/tests/openvzutilstest.c b/tests/openvzutilstest.c > index ed2c098..bcf48db 100644 > --- a/tests/openvzutilstest.c > +++ b/tests/openvzutilstest.c > @@ -95,7 +95,7 @@ testReadNetworkConf(const void *data ATTRIBUTE_UNUSED) > " <devices>\n" > " <interface type='ethernet'>\n" > " <mac address='00:00:00:00:00:00'/>\n" > - " <ip address='194.44.18.88'/>\n" > + " <ip address='194.44.18.88' family='ipv4'/>\n" > " </interface>\n" > " <interface type='bridge'>\n" > " <mac address='00:18:51:c1:05:ee'/>\n" > diff --git a/tests/sexpr2xmldata/sexpr2xml-bridge-ipaddr.xml > b/tests/sexpr2xmldata/sexpr2xml-bridge-ipaddr.xml index 9b5cc3a..25a29fd > 100644 > --- a/tests/sexpr2xmldata/sexpr2xml-bridge-ipaddr.xml > +++ b/tests/sexpr2xmldata/sexpr2xml-bridge-ipaddr.xml > @@ -24,7 +24,7 @@ > <interface type='bridge'> > <mac address='00:11:22:33:44:55'/> > <source bridge='xenbr2'/> > - <ip address='192.0.2.1'/> > + <ip address='192.0.2.1' family='ipv4'/> > <script path='vif-bridge'/> > <target dev='vif6.0'/> > </interface> > diff --git a/tests/sexpr2xmldata/sexpr2xml-net-routed.xml > b/tests/sexpr2xmldata/sexpr2xml-net-routed.xml index 0ab3b6d..c03e40b > 100644 > --- a/tests/sexpr2xmldata/sexpr2xml-net-routed.xml > +++ b/tests/sexpr2xmldata/sexpr2xml-net-routed.xml > @@ -23,7 +23,7 @@ > </disk> > <interface type='ethernet'> > <mac address='00:11:22:33:44:55'/> > - <ip address='172.14.5.6'/> > + <ip address='172.14.5.6' family='ipv4'/> > <script path='vif-routed'/> > <target dev='vif6.0'/> > </interface> -- Dmitry Guryanov -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list