This implements the changes to <network> and domain <interface> XML that were earlier specified in the RNG. Each virDomainNetDef now also potentially has a virDomainActualNetDef which is a private object (never exported/imported via the public API, and not defined in the RNG) that is used to maintain information about the physical device that was actually used for a NetDef that was of type VIR_DOMAIN_NET_TYPE_NETWORK. The virDomainActualNetDef will only be parsed/formatted if the parse/format function is called with the VIR_DOMAIN_XML_ACTUAL_NET flags set (which is only needed when saving/loading a running domain's state info to the stateDir). To prevent this flag bit from accidentally being used in the public API, a "RESERVED" placeholder was put into the public flags enum (at the same time, I noticed there was another private flag that hadn't been reserved, so I added that one, making both of these flags #defined from the public RESERVED flags, and since it was also only used in domain_conf.c, I unpolluted domain_conf.h, putting both #defines in domain_conf.c. A small change is also made to two functions in bridge_driver.c, to prevent a bridge device name and mac address from being automatically added to a network definition when it is of one of the new forward types (none of which use bridge devices managed by libvirt). --- include/libvirt/libvirt.h.in | 2 + src/conf/domain_conf.c | 276 +++++++++++++++++++++++++++++++++++- src/conf/domain_conf.h | 46 ++++++- src/conf/network_conf.c | 321 +++++++++++++++++++++++++++++++++++++----- src/conf/network_conf.h | 34 ++++- src/libvirt_private.syms | 8 +- src/network/bridge_driver.c | 28 +++- 7 files changed, 657 insertions(+), 58 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 8e20f75..b88c96e 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1112,6 +1112,8 @@ typedef enum { VIR_DOMAIN_XML_SECURE = (1 << 0), /* dump security sensitive information too */ VIR_DOMAIN_XML_INACTIVE = (1 << 1), /* dump inactive domain information */ VIR_DOMAIN_XML_UPDATE_CPU = (1 << 2), /* update guest CPU requirements according to host CPU */ + VIR_DOMAIN_XML_RESERVED1 = (1 << 30), /* reserved for internal used */ + VIR_DOMAIN_XML_RESERVED2 = (1 << 31), /* reserved for internal used */ } virDomainXMLFlags; char * virDomainGetXMLDesc (virDomainPtr domain, diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 66a7c59..d5a3387 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -489,6 +489,11 @@ VIR_ENUM_IMPL(virDomainNumatuneMemMode, VIR_DOMAIN_NUMATUNE_MEM_LAST, #define VIR_DOMAIN_XML_WRITE_FLAGS VIR_DOMAIN_XML_SECURE #define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE +/* these flags are only used internally */ +/* dump internal domain status information */ +#define VIR_DOMAIN_XML_INTERNAL_STATUS VIR_DOMAIN_XML_RESERVED1 +/* dump virDomainActualNetDef contents */ +#define VIR_DOMAIN_XML_ACTUAL_NET VIR_DOMAIN_XML_RESERVED2 static void virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED) @@ -714,6 +719,25 @@ void virDomainFSDefFree(virDomainFSDefPtr def) VIR_FREE(def); } +void +virDomainActualNetDefFree(virDomainActualNetDefPtr def) +{ + if (!def) + return; + + switch (def->type) { + case VIR_DOMAIN_NET_TYPE_BRIDGE: + VIR_FREE(def->data.bridge.brname); + break; + case VIR_DOMAIN_NET_TYPE_DIRECT: + VIR_FREE(def->data.direct.linkdev); + VIR_FREE(def->data.direct.virtPortProfile); + break; + default: + break; + } +} + void virDomainNetDefFree(virDomainNetDefPtr def) { if (!def) @@ -736,6 +760,9 @@ void virDomainNetDefFree(virDomainNetDefPtr def) case VIR_DOMAIN_NET_TYPE_NETWORK: VIR_FREE(def->data.network.name); + VIR_FREE(def->data.network.portgroup); + VIR_FREE(def->data.network.virtPortProfile); + virDomainActualNetDefFree(def->data.network.actual); break; case VIR_DOMAIN_NET_TYPE_BRIDGE: @@ -2566,6 +2593,85 @@ cleanup: goto cleanup; } +static int +virDomainActualNetDefParseXML(xmlNodePtr node, + xmlXPathContextPtr ctxt, + virDomainActualNetDefPtr *actual) +{ + int ret = -1; + xmlNodePtr save_ctxt = ctxt->node; + char *type = NULL; + char *mode = NULL; + + if (VIR_ALLOC(*actual) < 0) { + virReportOOMError(); + return -1; + } + + ctxt->node = node; + + type = virXMLPropString(node, "type"); + if (!type) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing type attribute in interface's <actual> element")); + goto error; + } + if ((int)((*actual)->type = virDomainNetTypeFromString(type)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown type '%s' in interface's <actual> element"), type); + goto error; + } + if ((*actual)->type != VIR_DOMAIN_NET_TYPE_BRIDGE && + (*actual)->type != VIR_DOMAIN_NET_TYPE_DIRECT) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unsupported type '%s' in interface's <actual> element"), + type); + goto error; + } + + if ((*actual)->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { + + (*actual)->data.bridge.brname = virXPathString("string(./source[1]/@bridge)", + ctxt); + + } else if ((*actual)->type == VIR_DOMAIN_NET_TYPE_DIRECT) { + xmlNodePtr virtPortNode; + const char *errmsg; + + (*actual)->data.direct.linkdev = virXPathString("string(./source[1]/@dev)", ctxt); + + mode = virXPathString("string(./source[1]/@mode)", ctxt); + if (mode) { + int m; + if ((m = virMacvtapModeTypeFromString(mode)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("Unkown mode '%s' in interface <actual> element"), + mode); + goto error; + } + (*actual)->data.direct.mode = m; + } + + virtPortNode = virXPathNode("./virtualport", ctxt); + if (virtPortNode && + virVirtualPortProfileParamsParseXML(virtPortNode, + &(*actual)->data.direct.virtPortProfile, + &errmsg) < 0) { + if (errmsg) + virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s in interface <actual>", + errmsg); + goto error; + } + } + + ret = 0; +error: + VIR_FREE(type); + VIR_FREE(mode); + + ctxt->node = save_ctxt; + return ret; +} /* Parse the XML definition for a network interface * @param node XML nodeset to parse for net definition @@ -2583,6 +2689,7 @@ virDomainNetDefParseXML(virCapsPtr caps, char *macaddr = NULL; char *type = NULL; char *network = NULL; + char *portgroup = NULL; char *bridge = NULL; char *dev = NULL; char *ifname = NULL; @@ -2599,6 +2706,7 @@ virDomainNetDefParseXML(virCapsPtr caps, char *mode = NULL; virNWFilterHashTablePtr filterparams = NULL; virVirtualPortProfileParamsPtr virtPort = NULL; + virDomainActualNetDefPtr actual = NULL; xmlNodePtr oldnode = ctxt->node; int ret; @@ -2630,6 +2738,7 @@ virDomainNetDefParseXML(virCapsPtr caps, (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) && (xmlStrEqual(cur->name, BAD_CAST "source"))) { network = virXMLPropString(cur, "network"); + portgroup = virXMLPropString(cur, "portgroup"); } else if ((internal == NULL) && (def->type == VIR_DOMAIN_NET_TYPE_INTERNAL) && (xmlStrEqual(cur->name, BAD_CAST "source"))) { @@ -2645,7 +2754,8 @@ virDomainNetDefParseXML(virCapsPtr caps, dev = virXMLPropString(cur, "dev"); mode = virXMLPropString(cur, "mode"); } else if ((virtPort == NULL) && - (def->type == VIR_DOMAIN_NET_TYPE_DIRECT) && + ((def->type == VIR_DOMAIN_NET_TYPE_DIRECT) || + (def->type == VIR_DOMAIN_NET_TYPE_NETWORK)) && xmlStrEqual(cur->name, BAD_CAST "virtualport")) { const char *errmsg; if (virVirtualPortProfileParamsParseXML(cur, &virtPort, &errmsg) < 0) { @@ -2697,6 +2807,12 @@ virDomainNetDefParseXML(virCapsPtr caps, if (virDomainDeviceBootParseXML(cur, &def->bootIndex, bootMap)) goto error; + } else if ((actual == NULL) && + (flags & VIR_DOMAIN_XML_ACTUAL_NET) && + (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) && + xmlStrEqual(cur->name, BAD_CAST "actual")) { + if (virDomainActualNetDefParseXML(cur, ctxt, &actual) < 0) + goto error; } } cur = cur->next; @@ -2745,6 +2861,12 @@ virDomainNetDefParseXML(virCapsPtr caps, } def->data.network.name = network; network = NULL; + def->data.network.portgroup = portgroup; + portgroup = NULL; + def->data.network.virtPortProfile = virtPort; + virtPort = NULL; + def->data.network.actual = actual; + actual = NULL; break; case VIR_DOMAIN_NET_TYPE_ETHERNET: @@ -2836,10 +2958,8 @@ virDomainNetDefParseXML(virCapsPtr caps, } else def->data.direct.mode = VIR_MACVTAP_MODE_VEPA; - if (virtPort) { - def->data.direct.virtPortProfile = virtPort; - virtPort = NULL; - } + def->data.direct.virtPortProfile = virtPort; + virtPort = NULL; def->data.direct.linkdev = dev; dev = NULL; @@ -2943,11 +3063,13 @@ cleanup: ctxt->node = oldnode; VIR_FREE(macaddr); VIR_FREE(network); + VIR_FREE(portgroup); VIR_FREE(address); VIR_FREE(port); VIR_FREE(ifname); VIR_FREE(dev); VIR_FREE(virtPort); + virDomainActualNetDefFree(actual); VIR_FREE(script); VIR_FREE(bridge); VIR_FREE(model); @@ -8421,6 +8543,67 @@ virDomainFSDefFormat(virBufferPtr buf, } static int +virDomainActualNetDefFormat(virBufferPtr buf, + virDomainActualNetDefPtr def, + int flags) { + int ret = -1; + const char *type; + const char *mode; + + if (!(def && (flags & VIR_DOMAIN_XML_INTERNAL_STATUS))) + return 0; + + type = virDomainNetTypeToString(def->type); + if (!type) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected net type %d"), def->type); + return ret; + } + + if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE && + def->type != VIR_DOMAIN_NET_TYPE_DIRECT) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected net type %s"), type); + goto error; + } + virBufferAsprintf(buf, " <actual type='%s'>\n", type); + + switch (def->type) { + case VIR_DOMAIN_NET_TYPE_BRIDGE: + if (def->data.bridge.brname) { + virBufferEscapeString(buf, " <source bridge='%s'/>\n", + def->data.bridge.brname); + } + break; + + case VIR_DOMAIN_NET_TYPE_DIRECT: + virBufferAddLit(buf, " <source"); + if (def->data.direct.linkdev) + virBufferEscapeString(buf, " dev='%s'", + def->data.direct.linkdev); + + mode = virMacvtapModeTypeToString(def->data.direct.mode); + if (!mode) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected source mode %d"), + def->data.direct.mode); + return ret; + } + virBufferAsprintf(buf, " mode='%s'/>\n", mode); + virVirtualPortProfileFormat(buf, def->data.direct.virtPortProfile, + " "); + break; + default: + break; + } + virBufferAddLit(buf, " </actual>\n"); + + ret = 0; +error: + return ret; +} + +static int virDomainNetDefFormat(virBufferPtr buf, virDomainNetDefPtr def, int flags) @@ -8443,8 +8626,17 @@ virDomainNetDefFormat(virBufferPtr buf, switch (def->type) { case VIR_DOMAIN_NET_TYPE_NETWORK: - virBufferEscapeString(buf, " <source network='%s'/>\n", + virBufferEscapeString(buf, " <source network='%s'", def->data.network.name); + if (def->data.network.portgroup) { + virBufferEscapeString(buf, " portgroup='%s'", + def->data.network.portgroup); + } + virBufferAddLit(buf, "/>\n"); + virVirtualPortProfileFormat(buf, def->data.network.virtPortProfile, + " "); + if (virDomainActualNetDefFormat(buf, def->data.network.actual, flags) < 0) + return -1; break; case VIR_DOMAIN_NET_TYPE_ETHERNET: @@ -9871,7 +10063,9 @@ int virDomainSaveStatus(virCapsPtr caps, const char *statusDir, virDomainObjPtr obj) { - int flags = VIR_DOMAIN_XML_SECURE|VIR_DOMAIN_XML_INTERNAL_STATUS; + int flags = VIR_DOMAIN_XML_SECURE | + VIR_DOMAIN_XML_INTERNAL_STATUS | + VIR_DOMAIN_XML_ACTUAL_NET; int ret = -1; char *xml; @@ -9960,7 +10154,8 @@ static virDomainObjPtr virDomainLoadStatus(virCapsPtr caps, goto error; if (!(obj = virDomainObjParseFile(caps, statusFile, - VIR_DOMAIN_XML_INTERNAL_STATUS))) + VIR_DOMAIN_XML_INTERNAL_STATUS | + VIR_DOMAIN_XML_ACTUAL_NET))) goto error; virUUIDFormat(obj->def->uuid, uuidstr); @@ -10946,3 +11141,68 @@ virDomainStateReasonFromString(virDomainState state, const char *reason) return -1; } + + +/* some access functions to gloss over the difference between NetDef + * (<interface>) and ActualNetDef (<actual>). If the NetDef has an + * ActualNetDef, return the requested value from the ActualNetDef, + * otherwise return the value from the NetDef. + */ + +int +virDomainNetGetActualType(virDomainNetDefPtr iface) +{ + if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) + return iface->type; + if (!iface->data.network.actual) + return iface->type; + return iface->data.network.actual->type; +} + +char * +virDomainNetGetActualBridgeName(virDomainNetDefPtr iface) +{ + if (iface->type == VIR_DOMAIN_NET_TYPE_BRIDGE) + return iface->data.bridge.brname; + if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) + return NULL; + if (!iface->data.network.actual) + return NULL; + return iface->data.network.actual->data.bridge.brname; +} + +char * +virDomainNetGetActualDirectDev(virDomainNetDefPtr iface) +{ + if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT) + return iface->data.direct.linkdev; + if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) + return NULL; + if (!iface->data.network.actual) + return NULL; + return iface->data.network.actual->data.direct.linkdev; +} + +int +virDomainNetGetActualDirectMode(virDomainNetDefPtr iface) +{ + if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT) + return iface->data.direct.mode; + if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) + return 0; + if (!iface->data.network.actual) + return 0; + return iface->data.network.actual->data.direct.mode; +} + +virVirtualPortProfileParamsPtr +virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface) +{ + if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT) + return iface->data.direct.virtPortProfile; + if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) + return NULL; + if (!iface->data.network.actual) + return NULL; + return iface->data.network.actual->data.direct.virtPortProfile; +} diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index f8771a9..5807e77 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1,3 +1,4 @@ + /* * domain_conf.h: domain XML processing * @@ -41,11 +42,6 @@ # include "macvtap.h" # include "sysinfo.h" -/* Private component of virDomainXMLFlags */ -typedef enum { - VIR_DOMAIN_XML_INTERNAL_STATUS = (1<<16), /* dump internal domain status information */ -} virDomainXMLInternalFlags; - /* Different types of hypervisor */ /* NB: Keep in sync with virDomainVirtTypeToString impl */ enum virDomainVirtType { @@ -348,6 +344,27 @@ enum virDomainNetVirtioTxModeType { VIR_DOMAIN_NET_VIRTIO_TX_MODE_LAST, }; +/* Config that was actually used to bring up interface, after + * resolving network reference. This is private data, only used within + * libvirt, but still must maintain backward compatibility, because + * different versions of libvirt may read the same data file. + */ +typedef struct _virDomainActualNetDef virDomainActualNetDef; +typedef virDomainActualNetDef *virDomainActualNetDefPtr; +struct _virDomainActualNetDef { + enum virDomainNetType type; + union { + struct { + char *brname; + } bridge; + struct { + char *linkdev; + int mode; /* enum virMacvtapMode from util/macvtap.h */ + virVirtualPortProfileParamsPtr virtPortProfile; + } direct; + } data; +}; + /* Stores the virtual network interface configuration */ typedef struct _virDomainNetDef virDomainNetDef; typedef virDomainNetDef *virDomainNetDefPtr; @@ -374,6 +391,17 @@ struct _virDomainNetDef { } socket; /* any of NET_CLIENT or NET_SERVER or NET_MCAST */ struct { char *name; + char *portgroup; + virVirtualPortProfileParamsPtr virtPortProfile; + /* actual has info about the currently used physical + * device (if the network is of type + * bridge/private/vepa/passthrough). This is saved in the + * domain state, but never written to persistent config, + * since it needs to be re-allocated whenever the domain + * is restarted. It is also never shown to the user, and + * the user cannot specify it in XML documents. + */ + virDomainActualNetDefPtr actual; } network; struct { char *brname; @@ -1319,6 +1347,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def); void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def); void virDomainControllerDefFree(virDomainControllerDefPtr def); void virDomainFSDefFree(virDomainFSDefPtr def); +void virDomainActualNetDefFree(virDomainActualNetDefPtr def); void virDomainNetDefFree(virDomainNetDefPtr def); void virDomainSmartcardDefFree(virDomainSmartcardDefPtr def); void virDomainChrDefFree(virDomainChrDefPtr def); @@ -1430,6 +1459,13 @@ int virDomainNetIndexByMac(virDomainDefPtr def, const unsigned char *mac); int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net); int virDomainNetRemoveByMac(virDomainDefPtr def, const unsigned char *mac); +int virDomainNetGetActualType(virDomainNetDefPtr iface); +char *virDomainNetGetActualBridgeName(virDomainNetDefPtr iface); +char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface); +int virDomainNetGetActualDirectMode(virDomainNetDefPtr iface); +virVirtualPortProfileParamsPtr +virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface); + int virDomainControllerInsert(virDomainDefPtr def, virDomainControllerDefPtr controller); void virDomainControllerInsertPreAlloced(virDomainDefPtr def, diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c index 45ddee2..3898945 100644 --- a/src/conf/network_conf.c +++ b/src/conf/network_conf.c @@ -50,7 +50,7 @@ VIR_ENUM_DECL(virNetworkForward) VIR_ENUM_IMPL(virNetworkForward, VIR_NETWORK_FORWARD_LAST, - "none", "nat", "route" ) + "none", "nat", "route", "bridge", "private", "vepa", "passthrough" ) #define virNetworkReportError(code, ...) \ virReportErrorHelper(VIR_FROM_NETWORK, code, __FILE__, \ @@ -87,6 +87,19 @@ virNetworkObjPtr virNetworkFindByName(const virNetworkObjListPtr nets, } +static void +virPortGroupDefClear(virPortGroupDefPtr def) +{ + VIR_FREE(def->name); + VIR_FREE(def->virtPortProfile); +} + +static void +virNetworkForwardIfDefClear(virNetworkForwardIfDefPtr def) +{ + VIR_FREE(def->dev); +} + static void virNetworkIpDefClear(virNetworkIpDefPtr def) { int ii; @@ -138,11 +151,21 @@ void virNetworkDefFree(virNetworkDefPtr def) VIR_FREE(def->forwardDev); VIR_FREE(def->domain); + for (ii = 0 ; ii < def->nForwardIfs && def->forwardIfs ; ii++) { + virNetworkForwardIfDefClear(&def->forwardIfs[ii]); + } + VIR_FREE(def->forwardIfs); + for (ii = 0 ; ii < def->nips && def->ips ; ii++) { virNetworkIpDefClear(&def->ips[ii]); } VIR_FREE(def->ips); + for (ii = 0; ii < def->nPortGroups && def->portGroups; ii++) { + virPortGroupDefClear(&def->portGroups[ii]); + } + VIR_FREE(def->portGroups); + virNetworkDNSDefFree(def->dns); VIR_FREE(def); @@ -735,14 +758,69 @@ error: return result; } +static int +virNetworkPortGroupParseXML(const char *networkName, + virPortGroupDefPtr def, + xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ + /* + * virPortGroupDef object is already allocated as part of an array. + * On failure clear it out, but don't free it. + */ + + xmlNodePtr save; + xmlNodePtr virtPortNode; + char *isDefault = NULL; + + int result = -1; + + save = ctxt->node; + ctxt->node = node; + + /* grab raw data from XML */ + def->name = virXPathString("string(./@name)", ctxt); + isDefault = virXPathString("string(./@default)", ctxt); + def->isDefault = isDefault && STRCASEEQ(isDefault, "yes"); + + virtPortNode = virXPathNode("./virtualport", ctxt); + if (virtPortNode) { + const char *errmsg; + if (virVirtualPortProfileParamsParseXML(virtPortNode, + &def->virtPortProfile, + &errmsg) < 0) { + if (errmsg) + virNetworkReportError(VIR_ERR_XML_ERROR, "%s (in network %s)", + errmsg, networkName); + goto error; + } + } + + result = 0; +error: + if (result < 0) { + virPortGroupDefClear(def); + } + VIR_FREE(isDefault); + + ctxt->node = save; + return result; +} + static virNetworkDefPtr virNetworkDefParseXML(xmlXPathContextPtr ctxt) { virNetworkDefPtr def; char *tmp; + char *stp = NULL; xmlNodePtr *ipNodes = NULL; + xmlNodePtr *portGroupNodes = NULL; + xmlNodePtr *forwardIfNodes = NULL; xmlNodePtr dnsNode = NULL; - int nIps; + xmlNodePtr virtPortNode = NULL; + xmlNodePtr forwardNode = NULL; + int nIps, nPortGroups, nForwardIfs; + xmlNodePtr save = ctxt->node; if (VIR_ALLOC(def) < 0) { virReportOOMError(); @@ -779,9 +857,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) /* Parse bridge information */ def->bridge = virXPathString("string(./bridge[1]/@name)", ctxt); - tmp = virXPathString("string(./bridge[1]/@stp)", ctxt); - def->stp = (tmp && STREQ(tmp, "off")) ? 0 : 1; - VIR_FREE(tmp); + stp = virXPathString("string(./bridge[1]/@stp)", ctxt); if (virXPathULong("string(./bridge[1]/@delay)", ctxt, &def->delay) < 0) def->delay = 0; @@ -805,6 +881,42 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) goto error; } + virtPortNode = virXPathNode("./virtualport", ctxt); + if (virtPortNode) { + const char *errmsg; + if (virVirtualPortProfileParamsParseXML(virtPortNode, + &def->virtPortProfile, + &errmsg) < 0) { + if (errmsg) + virNetworkReportError(VIR_ERR_XML_ERROR, "%s", errmsg); + goto error; + } + } + + nPortGroups = virXPathNodeSet("./portgroup", ctxt, &portGroupNodes); + if (nPortGroups < 0) + goto error; + + if (nPortGroups > 0) { + int ii; + + /* allocate array to hold all the portgroups */ + if (VIR_ALLOC_N(def->portGroups, nPortGroups) < 0) { + virReportOOMError(); + goto error; + } + /* parse each portgroup */ + for (ii = 0; ii < nPortGroups; ii++) { + int ret = virNetworkPortGroupParseXML(def->name, + &def->portGroups[ii], + portGroupNodes[ii], ctxt); + if (ret < 0) + goto error; + def->nPortGroups++; + } + } + VIR_FREE(portGroupNodes); + nIps = virXPathNodeSet("./ip", ctxt, &ipNodes); if (nIps < 0) goto error; @@ -828,17 +940,16 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) } VIR_FREE(ipNodes); - /* IPv4 forwarding setup */ - if (virXPathBoolean("count(./forward) > 0", ctxt)) { - if (def->nips == 0) { - virNetworkReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("Forwarding requested, but no IP address provided")); - goto error; - } - tmp = virXPathString("string(./forward[1]/@mode)", ctxt); + forwardNode = virXPathNode("./forward", ctxt); + if (!forwardNode) { + def->forwardType = VIR_NETWORK_FORWARD_NONE; + def->stp = (stp && STREQ(stp, "off")) ? 0 : 1; + } else { + ctxt->node = forwardNode; + tmp = virXPathString("string(./@mode)", ctxt); if (tmp) { if ((def->forwardType = virNetworkForwardTypeFromString(tmp)) < 0) { - virNetworkReportError(VIR_ERR_INTERNAL_ERROR, + virNetworkReportError(VIR_ERR_XML_ERROR, _("unknown forwarding type '%s'"), tmp); VIR_FREE(tmp); goto error; @@ -848,17 +959,85 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt) def->forwardType = VIR_NETWORK_FORWARD_NAT; } + def->forwardDev = virXPathString("string(./@dev)", ctxt); - def->forwardDev = virXPathString("string(./forward[1]/@dev)", ctxt); - } else { - def->forwardType = VIR_NETWORK_FORWARD_NONE; - } + switch (def->forwardType) { + case VIR_NETWORK_FORWARD_ROUTE: + case VIR_NETWORK_FORWARD_NAT: + /* It's pointless to specify L3 forwarding without specifying + * the network we're on. + */ + if (def->nips == 0) { + virNetworkReportError(VIR_ERR_XML_ERROR, + _("%s forwarding requested, but no IP address provided for network '%s'"), + virNetworkForwardTypeToString(def->forwardType), + def->name); + goto error; + } + def->stp = (stp && STREQ(stp, "off")) ? 0 : 1; + break; + case VIR_NETWORK_FORWARD_PRIVATE: + case VIR_NETWORK_FORWARD_VEPA: + case VIR_NETWORK_FORWARD_PASSTHROUGH: + if (def->bridge) { + virNetworkReportError(VIR_ERR_XML_ERROR, + _("bridge name not allowed in %s mode (network '%s'"), + virNetworkForwardTypeToString(def->forwardType), + def->name); + goto error; + } + /* Fall through to next case */ + case VIR_NETWORK_FORWARD_BRIDGE: + if (def->delay || stp) { + virNetworkReportError(VIR_ERR_XML_ERROR, + _("bridge delay/stp options only allowed in route, nat, and isolated mode, not in %s (network '%s')"), + virNetworkForwardTypeToString(def->forwardType), + def->name); + goto error; + } + /* all of these modes can use a pool of physical interfaces */ + nForwardIfs = virXPathNodeSet("./interface", ctxt, &forwardIfNodes); + if (nForwardIfs < 0) + goto error; + + if (nForwardIfs > 0) { + int ii; + /* allocate array to hold all the portgroups */ + if (VIR_ALLOC_N(def->forwardIfs, nForwardIfs) < 0) { + virReportOOMError(); + goto error; + } + + /* parse each forwardIf */ + for (ii = 0; ii < nForwardIfs; ii++) { + def->forwardIfs[ii].usageCount = 0; + def->forwardIfs[ii].dev = virXMLPropString(forwardIfNodes[ii], + "dev"); + if (!def->forwardIfs[ii].dev) { + virNetworkReportError(VIR_ERR_XML_ERROR, + _("Missing required dev attribute in network '%s' forward interface"), + def->name); + goto error; + } + def->nForwardIfs++; + } + } + VIR_FREE(forwardIfNodes); + break; + } + } + VIR_FREE(stp); + ctxt->node = save; return def; error: + VIR_FREE(stp); virNetworkDefFree(def); VIR_FREE(ipNodes); + VIR_FREE(portGroupNodes); + VIR_FREE(forwardIfNodes); + ctxt->node = save; return NULL; } @@ -1043,6 +1222,19 @@ error: return result; } +static void +virPortGroupDefFormat(virBufferPtr buf, + const virPortGroupDefPtr def) +{ + virBufferAsprintf(buf, " <portgroup name='%s'", def->name); + if (def->isDefault) { + virBufferAddLit(buf, " default='yes'"); + } + virBufferAddLit(buf, ">\n"); + virVirtualPortProfileFormat(buf, def->virtPortProfile, " "); + virBufferAddLit(buf, " </portgroup>\n"); +} + char *virNetworkDefFormat(const virNetworkDefPtr def) { virBuffer buf = VIR_BUFFER_INITIALIZER; @@ -1058,24 +1250,55 @@ char *virNetworkDefFormat(const virNetworkDefPtr def) virBufferAsprintf(&buf, " <uuid>%s</uuid>\n", uuidstr); if (def->forwardType != VIR_NETWORK_FORWARD_NONE) { + char *dev = def->forwardDev; const char *mode = virNetworkForwardTypeToString(def->forwardType); - if (mode) { - if (def->forwardDev) { - virBufferEscapeString(&buf, " <forward dev='%s'", - def->forwardDev); - } else { - virBufferAddLit(&buf, " <forward"); + if (!mode) { + virNetworkReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown forward type %d in network '%s'"), + def->forwardType, def->name); + goto error; + } + virBufferAddLit(&buf, " <forward"); + + /* Duplicate the first interface from the pool into <forward + * dev=xxx for convenience. + */ + if (!dev && def->nForwardIfs && + def->forwardIfs && def->forwardIfs[0].dev) { + dev = def->forwardIfs[0].dev; + } + if (dev) + virBufferEscapeString(&buf, " dev='%s'", dev); + virBufferAsprintf(&buf, " mode='%s'%s>\n", mode, + def->nForwardIfs ? "" : "/"); + + if (def->nForwardIfs) { + for (ii = 0; ii < def->nForwardIfs; ii++) { + if (def->forwardIfs[ii].dev) { + virBufferEscapeString(&buf, " <interface dev='%s'/>\n", + def->forwardIfs[ii].dev); + } } - virBufferAsprintf(&buf, " mode='%s'/>\n", mode); + virBufferAddLit(&buf, " </forward>\n"); } } - virBufferAddLit(&buf, " <bridge"); - if (def->bridge) - virBufferEscapeString(&buf, " name='%s'", def->bridge); - virBufferAsprintf(&buf, " stp='%s' delay='%ld' />\n", - def->stp ? "on" : "off", - def->delay); + if (def->forwardType == VIR_NETWORK_FORWARD_NONE || + def->forwardType == VIR_NETWORK_FORWARD_NAT || + def->forwardType == VIR_NETWORK_FORWARD_ROUTE) { + + virBufferAddLit(&buf, " <bridge"); + if (def->bridge) + virBufferEscapeString(&buf, " name='%s'", def->bridge); + virBufferAsprintf(&buf, " stp='%s' delay='%ld' />\n", + def->stp ? "on" : "off", + def->delay); + } else if (def->forwardType == VIR_NETWORK_FORWARD_BRIDGE && + def->bridge) { + virBufferEscapeString(&buf, " <bridge name='%s' />\n", def->bridge); + } + + if (def->mac_specified) { char macaddr[VIR_MAC_STRING_BUFLEN]; virFormatMacAddr(def->mac, macaddr); @@ -1093,6 +1316,11 @@ char *virNetworkDefFormat(const virNetworkDefPtr def) goto error; } + virVirtualPortProfileFormat(&buf, def->virtPortProfile, " "); + + for (ii = 0; ii < def->nPortGroups; ii++) + virPortGroupDefFormat(&buf, &def->portGroups[ii]); + virBufferAddLit(&buf, "</network>\n"); if (virBufferError(&buf)) @@ -1107,6 +1335,22 @@ char *virNetworkDefFormat(const virNetworkDefPtr def) return NULL; } +virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net, + const char *portgroup) +{ + int ii; + for (ii = 0; ii < net->nPortGroups; ii++) { + if (portgroup) { + if (STREQ(portgroup, net->portGroups[ii].name)) + return &net->portGroups[ii]; + } else { + if (net->portGroups[ii].isDefault) + return &net->portGroups[ii]; + } + } + return NULL; +} + int virNetworkSaveXML(const char *configDir, virNetworkDefPtr def, const char *xml) @@ -1210,11 +1454,16 @@ virNetworkObjPtr virNetworkLoadConfig(virNetworkObjListPtr nets, goto error; } - /* Generate a bridge if none is specified, but don't check for collisions - * if a bridge is hardcoded, so the network is at least defined - */ - if (virNetworkSetBridgeName(nets, def, 0)) - goto error; + if (def->forwardType == VIR_NETWORK_FORWARD_NONE || + def->forwardType == VIR_NETWORK_FORWARD_NAT || + def->forwardType == VIR_NETWORK_FORWARD_ROUTE) { + + /* Generate a bridge if none is specified, but don't check for collisions + * if a bridge is hardcoded, so the network is at least defined. + */ + if (virNetworkSetBridgeName(nets, def, 0)) + goto error; + } if (!(net = virNetworkAssignDef(nets, def))) goto error; diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index d7d2951..5df6724 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -33,11 +33,14 @@ # include "network.h" # include "util.h" -/* 2 possible types of forwarding */ enum virNetworkForwardType { VIR_NETWORK_FORWARD_NONE = 0, VIR_NETWORK_FORWARD_NAT, VIR_NETWORK_FORWARD_ROUTE, + VIR_NETWORK_FORWARD_BRIDGE, + VIR_NETWORK_FORWARD_PRIVATE, + VIR_NETWORK_FORWARD_VEPA, + VIR_NETWORK_FORWARD_PASSTHROUGH, VIR_NETWORK_FORWARD_LAST, }; @@ -107,6 +110,21 @@ struct _virNetworkIpDef { virSocketAddr bootserver; }; +typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef; +typedef virNetworkForwardIfDef *virNetworkForwardIfDefPtr; +struct _virNetworkForwardIfDef { + char *dev; /* name of device */ + int usageCount; /* how many guest interfaces are bound to this device? */ +}; + +typedef struct _virPortGroupDef virPortGroupDef; +typedef virPortGroupDef *virPortGroupDefPtr; +struct _virPortGroupDef { + char *name; + bool isDefault; + virVirtualPortProfileParamsPtr virtPortProfile; +}; + typedef struct _virNetworkDef virNetworkDef; typedef virNetworkDef *virNetworkDefPtr; struct _virNetworkDef { @@ -121,12 +139,22 @@ struct _virNetworkDef { bool mac_specified; int forwardType; /* One of virNetworkForwardType constants */ - char *forwardDev; /* Destination device for forwarding */ + char *forwardDev; /* Destination device for forwarding (if just one) */ + + /* If there are multiple forward devices (i.e. a pool of + * interfaces), they will be listed here. + */ + size_t nForwardIfs; + virNetworkForwardIfDefPtr forwardIfs; size_t nips; virNetworkIpDefPtr ips; /* ptr to array of IP addresses on this network */ virNetworkDNSDefPtr dns; /* ptr to dns related configuration */ + virVirtualPortProfileParamsPtr virtPortProfile; + + size_t nPortGroups; + virPortGroupDefPtr portGroups; }; typedef struct _virNetworkObj virNetworkObj; @@ -151,6 +179,8 @@ struct _virNetworkObjList { virNetworkObjPtr *objs; }; +virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net, + const char *portgroup); static inline int virNetworkObjIsActive(const virNetworkObjPtr net) { diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a7540d2..3b8214a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -205,6 +205,7 @@ dnsmasqSave; # domain_conf.h virDiskNameToBusDeviceIndex; virDiskNameToIndex; +virDomainActualNetDefFree; virDomainAssignDef; virDomainChrConsoleTargetTypeFromString; virDomainChrConsoleTargetTypeToString; @@ -309,6 +310,11 @@ virDomainLoadAllConfigs; virDomainMemballoonModelTypeFromString; virDomainMemballoonModelTypeToString; virDomainNetDefFree; +virDomainNetGetActualBridgeName; +virDomainNetGetActualDirectDev; +virDomainNetGetActualDirectMode; +virDomainNetGetActualType; +virDomainNetGetActualDirectVirtPortProfile; virDomainNetIndexByMac; virDomainNetInsert; virDomainNetRemoveByMac; @@ -722,7 +728,7 @@ virNetworkRemoveInactive; virNetworkSaveConfig; virNetworkSetBridgeMacAddr; virNetworkSetBridgeName; - +virPortGroupFindByName; # node_device_conf.h virNodeDevCapTypeToString; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 660dd65..cb49356 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -2169,10 +2169,18 @@ static virNetworkPtr networkCreate(virConnectPtr conn, const char *xml) { if (virNetworkObjIsDuplicate(&driver->networks, def, 1) < 0) goto cleanup; - if (virNetworkSetBridgeName(&driver->networks, def, 1)) - goto cleanup; + /* Only the three L3 network types that are configured by libvirt + * need to have a bridge device name / mac address provided + */ + if (def->forwardType == VIR_NETWORK_FORWARD_NONE || + def->forwardType == VIR_NETWORK_FORWARD_NAT || + def->forwardType == VIR_NETWORK_FORWARD_ROUTE) { - virNetworkSetBridgeMacAddr(def); + if (virNetworkSetBridgeName(&driver->networks, def, 1)) + goto cleanup; + + virNetworkSetBridgeMacAddr(def); + } if (!(network = virNetworkAssignDef(&driver->networks, def))) @@ -2214,10 +2222,18 @@ static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) { if (virNetworkObjIsDuplicate(&driver->networks, def, 0) < 0) goto cleanup; - if (virNetworkSetBridgeName(&driver->networks, def, 1)) - goto cleanup; + /* Only the three L3 network types that are configured by libvirt + * need to have a bridge device name / mac address provided + */ + if (def->forwardType == VIR_NETWORK_FORWARD_NONE || + def->forwardType == VIR_NETWORK_FORWARD_NAT || + def->forwardType == VIR_NETWORK_FORWARD_ROUTE) { - virNetworkSetBridgeMacAddr(def); + if (virNetworkSetBridgeName(&driver->networks, def, 1)) + goto cleanup; + + virNetworkSetBridgeMacAddr(def); + } if (!(network = virNetworkAssignDef(&driver->networks, def))) -- 1.7.3.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list