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