diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index b81b558d91..ab89dab61e 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2629,6 +2629,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 07b9a57c7e..def3099a99 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -6186,6 +6186,53 @@ virDomainNetIPParseXML(xmlNodePtr node)
return ret;
}
+
+/* fill in a virNetDevIPInfoPtr from the and
+ * elements found in the given XML context.
+ *
+ * return 0 on success (including none found) and -1 on failure.
+ */
+static int ATTRIBUTE_UNUSED
+virDomainNetIPInfoParseXML(const char *source,
+ xmlXPathContextPtr ctxt,
+ virNetDevIPInfoPtr def)
+{
+ xmlNodePtr *nodes = NULL;
+ virNetDevIPAddrPtr ip = NULL;
+ virNetDevIPRoutePtr route = NULL;
+ int nnodes;
+ int ret = -1;
+ size_t i;
+
+ if ((nnodes = virXPathNodeSet("./ip", ctxt, &nodes)) < 0)
+ goto cleanup;
+
+ for (i = 0; i < nnodes; i++) {
+ if (!(ip = virDomainNetIPParseXML(nodes[i])) ||
+ VIR_APPEND_ELEMENT(def->ips, def->nips, ip) < 0)
+ goto cleanup;
+ }
+ VIR_FREE(nodes);
+
+ if ((nnodes = virXPathNodeSet("./route", ctxt, &nodes)) < 0)
+ goto cleanup;
+
+ for (i = 0; i < nnodes; i++) {
+ if (!(route = virNetDevIPRouteParseXML(source, nodes[i], ctxt)) ||
+ VIR_APPEND_ELEMENT(def->routes, def->nroutes, route) < 0)
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ if (ret < 0)
+ virNetDevIPInfoClear(def);
+ VIR_FREE(ip);
+ virNetDevIPRouteFree(route);
+ VIR_FREE(nodes);
+ return ret;
+}
+
static int
virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
xmlXPathContextPtr ctxt,
@@ -20322,6 +20369,19 @@ virDomainNetRoutesFormat(virBufferPtr buf,
return 0;
}
+
+static int ATTRIBUTE_UNUSED
+virDomainNetIPInfoFormat(virBufferPtr buf,
+ virNetDevIPInfoPtr def)
+{
+ if (virDomainNetIPsFormat(buf, def->ips, def->nips) < 0)
+ return -1;
+ if (virDomainNetRoutesFormat(buf, def->routes, def->nroutes) < 0)
+ return -1;
+ return 0;
+}
+
+
static int
virDomainHostdevDefFormatSubsys(virBufferPtr buf,
virDomainHostdevDefPtr def,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b75db718e4..4617f5d5d2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1931,6 +1931,7 @@ virNetDevBridgeSetVlanFiltering;
virNetDevIPAddrAdd;
virNetDevIPAddrDel;
virNetDevIPAddrGet;
+virNetDevIPInfoClear;
virNetDevIPRouteAdd;
virNetDevIPRouteFree;
virNetDevIPRouteGetAddress;
diff --git a/src/util/virnetdevip.c b/src/util/virnetdevip.c
index 619f926782..376d4adbdb 100644
--- a/src/util/virnetdevip.c
+++ b/src/util/virnetdevip.c
@@ -845,3 +845,19 @@ virNetDevIPRouteGetGateway(virNetDevIPRoutePtr def)
return &def->gateway;
return NULL;
}
+
+/* manipulating the virNetDevIPInfo object */
+
+void
+virNetDevIPInfoClear(virNetDevIPInfoPtr ip)
+{
+ size_t i;
+
+ for (i = 0; i < ip->nips; i++)
+ VIR_FREE(ip->ips[i]);
+ VIR_FREE(ip->ips);
+
+ for (i = 0; i < ip->nroutes; i++)
+ virNetDevIPRouteFree(ip->routes[i]);
+ VIR_FREE(ip->routes);
+}
diff --git a/src/util/virnetdevip.h b/src/util/virnetdevip.h
index 7a07b73e09..be41636db5 100644
--- a/src/util/virnetdevip.h
+++ b/src/util/virnetdevip.h
@@ -47,6 +47,14 @@ typedef struct {
virSocketAddr gateway; /* gateway IP address for ip-route */
} virNetDevIPRoute, *virNetDevIPRoutePtr;
+/* A full set of all IP config info for a network device */
+typedef struct {
+ size_t nips;
+ virNetDevIPAddrPtr *ips;
+ size_t nroutes;
+ virNetDevIPRoutePtr *routes;
+} virNetDevIPInfo, *virNetDevIPInfoPtr;
+
/* manipulating/querying the netdev */
int virNetDevIPAddrAdd(const char *ifname,
virSocketAddr *addr,
@@ -76,4 +84,7 @@ int virNetDevIPRouteGetPrefix(virNetDevIPRoutePtr def);
unsigned int virNetDevIPRouteGetMetric(virNetDevIPRoutePtr def);
virSocketAddrPtr virNetDevIPRouteGetGateway(virNetDevIPRoutePtr def);
+/* virNetDevIPInfo object */
+void virNetDevIPInfoClear(virNetDevIPInfoPtr ip);
+
#endif /* __VIR_NETDEVIP_H__ */