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