bond device always need to configure the ip address and
route way address. so here we add the interface.
xml like:
<hostdev mode='subsystem' type='pci' managed='no'>
<driver name='vfio' type='bond'/>
<bond>
<ip address='192.168.122.5' family='ipv4' prefix='24'/>
<route family='ipv4' address='0.0.0.0'
gateway='192.168.122.1'/>
<interface address='52:54:00:e8:c0:f3'/>
<interface address='44:33:4c:06:f5:8e'/>
</bond>
Signed-off-by: Chen Fan <chen.fan.fnst(a)cn.fujitsu.com>
---
docs/schemas/domaincommon.rng | 21 +++++++++++
src/conf/domain_conf.c | 87 ++++++++++++++++++++++++++++++++++++-------
src/conf/domain_conf.h | 24 ++++++++----
src/conf/networkcommon_conf.c | 17 ---------
src/conf/networkcommon_conf.h | 17 +++++++++
src/qemu/qemu_agent.c | 58 +++++++++++++++++++++++++++--
6 files changed, 183 insertions(+), 41 deletions(-)
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 0cf82cb..4056cbd 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -3779,6 +3779,27 @@
<optional>
<element name="bond">
<zeroOrMore>
+ <element name="ip">
+ <attribute name="address">
+ <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>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="route"/>
+ </zeroOrMore>
+ <zeroOrMore>
<element name="interface">
<ref name="pciinterface"/>
</element>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 14bcae1..7d1cd3e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -797,6 +797,8 @@ static virClassPtr virDomainXMLOptionClass;
static void virDomainObjDispose(void *obj);
static void virDomainObjListDispose(void *obj);
static void virDomainXMLOptionClassDispose(void *obj);
+static virDomainNetIpDefPtr virDomainNetIpParseXML(xmlNodePtr node);
+
static int virDomainObjOnceInit(void)
{
@@ -1914,8 +1916,17 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
}
} else if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
virDomainHostdevSubsysPCIPtr pcisrc = &def->source.subsys.u.pci;
- if (pcisrc->device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND)
- VIR_FREE(pcisrc->macs);
+ if (pcisrc->device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) {
+ for (i = 0; i < pcisrc->net.nmacs; i++)
+ VIR_FREE(pcisrc->net.macs[i]);
+ VIR_FREE(pcisrc->net.macs);
+ for (i = 0; i < pcisrc->net.nips; i++)
+ VIR_FREE(pcisrc->net.ips[i]);
+ VIR_FREE(pcisrc->net.ips);
+ for (i = 0; i < pcisrc->net.nroutes; i++)
+ VIR_FREE(pcisrc->net.routes[i]);
+ VIR_FREE(pcisrc->net.routes);
+ }
}
break;
}
@@ -5102,26 +5113,68 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
if (device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) {
xmlNodePtr *macs = NULL;
int n = 0;
- int i;
+ size_t i;
char *macStr = NULL;
+ xmlNodePtr *ipnodes = NULL;
+ int nipnodes;
+ xmlNodePtr *routenodes = NULL;
+ int nroutenodes;
if (!(virXPathNode("./bond", ctxt))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
- _("missing <nond> node specified by bond
type"));
+ _("missing <bond> node specified by bond
type"));
goto error;
}
+ if ((nipnodes = virXPathNodeSet("./bond/ip", ctxt, &ipnodes))
< 0)
+ goto error;
+
+ if (nipnodes) {
+ for (i = 0; i < nipnodes; i++) {
+ virDomainNetIpDefPtr ip = virDomainNetIpParseXML(ipnodes[i]);
+
+ if (!ip)
+ goto error;
+
+ if (VIR_APPEND_ELEMENT(pcisrc->net.ips,
+ pcisrc->net.nips, ip) < 0) {
+ VIR_FREE(ip);
+ goto error;
+ }
+ }
+ }
+
+ if ((nroutenodes = virXPathNodeSet("./bond/route", ctxt,
&routenodes)) < 0)
+ goto error;
+
+ if (nroutenodes) {
+ for (i = 0; i < nroutenodes; i++) {
+ virNetworkRouteDefPtr route = NULL;
+
+ if (!(route = virNetworkRouteDefParseXML(_("Domain hostdev
device"),
+ routenodes[i],
+ ctxt)))
+ goto error;
+
+ if (VIR_APPEND_ELEMENT(pcisrc->net.routes,
+ pcisrc->net.nroutes, route) < 0) {
+ virNetworkRouteDefFree(route);
+ goto error;
+ }
+ }
+ }
+
if ((n = virXPathNodeSet("./bond/interface", ctxt, &macs)) <
0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot extract interface nodes"));
goto error;
}
- VIR_FREE(pcisrc->macs);
- if (VIR_ALLOC_N(pcisrc->macs, n) < 0)
+ VIR_FREE(pcisrc->net.macs);
+ if (VIR_ALLOC_N(pcisrc->net.macs, n) < 0)
goto error;
- pcisrc->nmac = n;
+ pcisrc->net.nmacs = n;
for (i = 0; i < n; i++) {
xmlNodePtr cur_node = macs[i];
@@ -5132,14 +5185,18 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
"in interface element"));
goto error;
}
- if (virMacAddrParse((const char *)macStr, &pcisrc->macs[i]) <
0) {
+
+ if (VIR_ALLOC(pcisrc->net.macs[i]) < 0)
+ goto error;
+
+ if (virMacAddrParse((const char *)macStr, pcisrc->net.macs[i]) < 0)
{
virReportError(VIR_ERR_XML_ERROR,
_("unable to parse mac address
'%s'"),
(const char *)macStr);
VIR_FREE(macStr);
goto error;
}
- if (virMacAddrIsMulticast(&pcisrc->macs[i])) {
+ if (virMacAddrIsMulticast(pcisrc->net.macs[i])) {
virReportError(VIR_ERR_XML_ERROR,
_("expected unicast mac address, found multicast
'%s'"),
(const char *)macStr);
@@ -18501,13 +18558,17 @@ virDomainHostdevDefFormatSubsys(virBufferPtr buf,
virBufferAddLit(buf, "/>\n");
}
- if (pcisrc->device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND &&
- pcisrc->nmac > 0) {
+ if (pcisrc->device == VIR_DOMAIN_HOSTDEV_PCI_DEVICE_BOND) {
virBufferAddLit(buf, "<bond>\n");
virBufferAdjustIndent(buf, 2);
- for (i = 0; i < pcisrc->nmac; i++) {
+ if (virDomainNetIpsFormat(buf, pcisrc->net.ips, pcisrc->net.nips) <
0)
+ return -1;
+ if (virDomainNetRoutesFormat(buf, pcisrc->net.routes,
pcisrc->net.nroutes) < 0)
+ return -1;
+
+ for (i = 0; i < pcisrc->net.nmacs; i++) {
virBufferAsprintf(buf, "<interface
address='%s'/>\n",
- virMacAddrFormat(&pcisrc->macs[i], macstr));
+ virMacAddrFormat(pcisrc->net.macs[i], macstr));
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</bond>\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index e62979f..723f07b 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -447,14 +447,28 @@ struct _virDomainHostdevSubsysUSB {
unsigned product;
};
+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 _virDomainHostdevSubsysPCI virDomainHostdevSubsysPCI;
typedef virDomainHostdevSubsysPCI *virDomainHostdevSubsysPCIPtr;
struct _virDomainHostdevSubsysPCI {
virDevicePCIAddress addr; /* host address */
int backend; /* enum virDomainHostdevSubsysPCIBackendType */
int device; /* enum virDomainHostdevSubsysPCIDeviceType */
- size_t nmac;
- virMacAddr* macs;
+
+ struct {
+ size_t nips;
+ virDomainNetIpDefPtr *ips;
+ size_t nroutes;
+ virNetworkRouteDefPtr *routes;
+ size_t nmacs;
+ virMacAddrPtr *macs;
+ } net;
};
typedef struct _virDomainHostdevSubsysSCSIHost virDomainHostdevSubsysSCSIHost;
@@ -507,12 +521,6 @@ 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;
diff --git a/src/conf/networkcommon_conf.c b/src/conf/networkcommon_conf.c
index 7b7a851..c11baf6 100644
--- a/src/conf/networkcommon_conf.c
+++ b/src/conf/networkcommon_conf.c
@@ -32,23 +32,6 @@
#define VIR_FROM_THIS VIR_FROM_NETWORK
-struct _virNetworkRouteDef {
- char *family; /* ipv4 or ipv6 - default is ipv4 */
- virSocketAddr address; /* Routed Network IP address */
-
- /* One or the other of the following two will be used for a given
- * Network address, but never both. The parser guarantees this.
- * The virSocketAddrGetIpPrefix() can be used to get a
- * valid prefix.
- */
- virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */
- unsigned int prefix; /* ipv6 - only prefix allowed */
- bool has_prefix; /* prefix= was specified */
- unsigned int metric; /* value for metric (defaults to 1) */
- bool has_metric; /* metric= was specified */
- virSocketAddr gateway; /* gateway IP address for ip-route */
-};
-
void
virNetworkRouteDefFree(virNetworkRouteDefPtr def)
{
diff --git a/src/conf/networkcommon_conf.h b/src/conf/networkcommon_conf.h
index 1500d0f..a9f58e8 100644
--- a/src/conf/networkcommon_conf.h
+++ b/src/conf/networkcommon_conf.h
@@ -35,6 +35,23 @@
typedef struct _virNetworkRouteDef virNetworkRouteDef;
typedef virNetworkRouteDef *virNetworkRouteDefPtr;
+struct _virNetworkRouteDef {
+ char *family; /* ipv4 or ipv6 - default is ipv4 */
+ virSocketAddr address; /* Routed Network IP address */
+
+ /* One or the other of the following two will be used for a given
+ * Network address, but never both. The parser guarantees this.
+ * The virSocketAddrGetIpPrefix() can be used to get a
+ * valid prefix.
+ */
+ virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */
+ unsigned int prefix; /* ipv6 - only prefix allowed */
+ bool has_prefix; /* prefix= was specified */
+ unsigned int metric; /* value for metric (defaults to 1) */
+ bool has_metric; /* metric= was specified */
+ virSocketAddr gateway; /* gateway IP address for ip-route */
+};
+
void
virNetworkRouteDefFree(virNetworkRouteDefPtr def);
diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c
index b8eba01..f9823e2 100644
--- a/src/qemu/qemu_agent.c
+++ b/src/qemu/qemu_agent.c
@@ -2208,11 +2208,14 @@ qemuAgentCreateBond(qemuAgentPtr mon,
virDomainInterfacePtr *interfaceInfo = NULL;
virDomainInterfacePtr interface;
virJSONValuePtr new_interface = NULL;
+ virJSONValuePtr ip_interface = NULL;
virJSONValuePtr subInterfaces = NULL;
virJSONValuePtr subInterface = NULL;
int len;
- if (!(pcisrc->nmac || pcisrc->macs))
+ if (!(pcisrc->net.nmacs &&
+ pcisrc->net.nips &&
+ pcisrc->net.nroutes))
return ret;
len = qemuAgentGetInterfaces(mon, &interfaceInfo);
@@ -2231,11 +2234,60 @@ qemuAgentCreateBond(qemuAgentPtr mon,
if (virJSONValueObjectAppendString(new_interface, "onboot",
"onboot") < 0)
goto cleanup;
+ if (virJSONValueObjectAppendString(new_interface,
+ "options",
+ "mode=active-backup miimon=100
updelay=10") < 0)
+ goto cleanup;
+
+ if (!(ip_interface = virJSONValueNewObject()))
+ goto cleanup;
+
+ if (pcisrc->net.nips) {
+ /* the first valid */
+ virSocketAddrPtr address = &pcisrc->net.ips[0]->address;
+ char *ipStr = virSocketAddrFormat(address);
+ const char *familyStr = NULL;
+
+ if (virJSONValueObjectAppendString(ip_interface, "ip-address", ipStr)
< 0)
+ goto cleanup;
+ VIR_FREE(ipStr);
+
+ if (VIR_SOCKET_ADDR_IS_FAMILY(address, AF_INET6))
+ familyStr = "ipv6";
+ else if (VIR_SOCKET_ADDR_IS_FAMILY(address, AF_INET))
+ familyStr = "ipv4";
+
+ if (familyStr)
+ if (virJSONValueObjectAppendString(ip_interface, "ip-address-type",
familyStr) < 0)
+ goto cleanup;
+ if (pcisrc->net.ips[0]->prefix != 0)
+ if (virJSONValueObjectAppendNumberInt(ip_interface, "prefix",
+ pcisrc->net.ips[0]->prefix) <
0)
+ goto cleanup;
+ }
+
+ if (pcisrc->net.nroutes) {
+ /* the first valid */
+ char *addr = NULL;
+ virSocketAddrPtr gateway = &pcisrc->net.routes[0]->gateway;
+
+ if (!(addr = virSocketAddrFormat(gateway)))
+ goto cleanup;
+ if (virJSONValueObjectAppendString(ip_interface, "gateway", addr) <
0)
+ goto cleanup;
+ VIR_FREE(addr);
+ }
+
+ if ((pcisrc->net.nroutes ||
+ pcisrc->net.nips) &&
+ virJSONValueObjectAppend(new_interface, "ip-address", ip_interface)
< 0)
+ goto cleanup;
+
if (!(subInterfaces = virJSONValueNewArray()))
goto cleanup;
- for (i = 0; i < pcisrc->nmac; i++) {
- virMacAddrFormat(&pcisrc->macs[i], macstr);
+ for (i = 0; i < pcisrc->net.nmacs; i++) {
+ virMacAddrFormat(pcisrc->net.macs[i], macstr);
interface = findInterfaceByMac(interfaceInfo, len, macstr);
if (!interface) {
goto cleanup;
--
1.9.3