]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
conf: support abstracted interface info in domain interface XML
authorLaine Stump <laine@laine.org>
Sun, 26 Jun 2011 08:09:00 +0000 (04:09 -0400)
committerLaine Stump <laine@laine.org>
Thu, 21 Jul 2011 18:46:44 +0000 (14:46 -0400)
the domain XML <interface> element is updated in the following ways:

1) <virtualportprofile> can be specified when source type='network'
(previously it was only valid for source type='direct')

2) A new attribute "portgroup" has been added to the <source>
element. When source type='network' (the only time portgroup is
recognized), extra configuration information will be taken from the
<portgroup> element of the given name in the network definition.

3) 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 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_INTERNAL_ACTUAL_NET flag set (which is only needed when
saving/loading a running domain's state info to the stateDir).

cfg.mk
docs/formatdomain.html.in
docs/schemas/domain.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
src/libvirt_private.syms
tests/qemuxml2argvdata/qemuxml2argv-net-virtio-network-portgroup.xml [new file with mode: 0644]
tests/qemuxml2xmltest.c

diff --git a/cfg.mk b/cfg.mk
index 0a624f1592b0bcc0f74ad07c42eea14e69e60ffc..3024181e2f034bfabca547ae683e13347eed9e4c 100644 (file)
--- a/cfg.mk
+++ b/cfg.mk
@@ -97,6 +97,7 @@ useless_free_options =                                \
   --name=virCommandFree                                \
   --name=virConfFreeList                       \
   --name=virConfFreeValue                      \
+  --name=virDomainActualNetDefFree             \
   --name=virDomainChrDefFree                   \
   --name=virDomainChrSourceDefFree             \
   --name=virDomainControllerDefFree            \
index 8c5c4c996522121fe6d551056ecff7c0c7e69bc7..83146ed7cfbd3cb2a369c8b631828019dea664ac 100644 (file)
     <p>
       <strong><em>
       This is the recommended config for general guest connectivity on
-      hosts with dynamic / wireless networking configs
+      hosts with dynamic / wireless networking configs (or multi-host
+      environments where the host hardware details are described
+      separately in a <code>&lt;network&gt;</code>
+      definition <span class="since">Since 0.9.4</span>).
       </em></strong>
     </p>
 
     <p>
-      Provides a virtual network using a bridge device in the host.
-      Depending on the virtual network configuration, the network may be
-      totally isolated, NAT'ing to an explicit network device, or NAT'ing to
-      the default route. DHCP and DNS are provided on the virtual network in
-      all cases and the IP range can be determined by examining the virtual
-      network config with '<code>virsh net-dumpxml [networkname]</code>'.
-      There is one virtual network called 'default' setup out
-      of the box which does NAT'ing to the default route and has an IP range of
-      <code>192.168.122.0/255.255.255.0</code>. Each guest will have an
-      associated tun device created with a name of vnetN, which can also be
-      overridden with the &lt;target&gt; element (see
+
+      Provides a connection whose details are described by the named
+      network definition. Depending on the virtual network's "forward
+      mode" configuration, the network may be totally isolated
+      (no <code>&lt;forward&gt;</code> element given), NAT'ing to an
+      explicit network device or to the default route
+      (<code>&lt;forward mode='nat'&gt;</code>), routed with no NAT
+      (<code>&lt;forward mode='route'/&gt;</code>), or connected
+      directly to one of the host's network interfaces (via macvtap)
+      or bridge devices ((<code>&lt;forward
+      mode='bridge|private|vepa|passthrough'/&gt;</code> <span class="since">Since
+      0.9.4</span>)
+    </p>
+    <p>
+      For networks with a forward mode of bridge, private, vepa, and
+      passthrough, it is assumed that the host has any necessary DNS
+      and DHCP services already setup outside the scope of libvirt. In
+      the case of isolated, nat, and routed networks, DHCP and DNS are
+      provided on the virtual network by libvirt, and the IP range can
+      be determined by examining the virtual network config with
+      '<code>virsh net-dumpxml [networkname]</code>'. There is one
+      virtual network called 'default' setup out of the box which does
+      NAT'ing to the default route and has an IP range
+      of <code>192.168.122.0/255.255.255.0</code>. Each guest will
+      have an associated tun device created with a name of vnetN,
+      which can also be overridden with the &lt;target&gt; element
+      (see
       <a href="#elementsNICSTargetOverride">overriding the target element</a>).
     </p>
+    <p>
+      When the source of an interface is a network,
+      a <code>portgroup</code> can be specified along with the name of
+      the network; one network may have multiple portgroups defined,
+      with each portgroup containing slightly different configuration
+      information for different classes of network
+      connections. <span class="since">Since 0.9.4</span>). Also,
+      similar to <code>direct</code> network connections (described
+      below), a connection of type <code>network</code> may specify
+      a <code>virtportprofile</code> element, with configuration data
+      to be forwarded to a vepa or 802.1Qbh compliant switch.
+    </p>
 
 <pre>
   ...
     &lt;/interface&gt;
     ...
     &lt;interface type='network'&gt;
-      &lt;source network='default'/&gt;
+      &lt;source network='default' portgroup='engineering'/&gt;
       &lt;target dev='vnet7'/&gt;
       &lt;mac address="00:11:22:33:44:55"/&gt;
+      &lt;virtualport type='802.1Qbg'&gt;
+        &lt;parameters managerid='11' typeid='1193047' typeidversion='2' instanceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/&gt;
+      &lt;/virtualport&gt;
+
     &lt;/interface&gt;
   &lt;/devices&gt;
   ...</pre>
index 564ff68420773c5aac1f0c1afdd47f3e75f028f5..43326ab05af591874eddf6051515a223847df89e 100644 (file)
               <attribute name="network">
                 <ref name="deviceName"/>
               </attribute>
+              <optional>
+                <attribute name="portgroup">
+                  <ref name="deviceName"/>
+                </attribute>
+              </optional>
               <empty/>
             </element>
+            <optional>
+              <ref name="virtualPortProfile"/>
+            </optional>
             <ref name="interface-options"/>
           </interleave>
         </group>
index 039b47897c60fd3c44671107661ba35344019a64..919a75a76299afe573674e10934dafd0d7dad6e7 100644 (file)
  * verify that it doesn't overflow an unsigned int when shifting */
 verify(VIR_DOMAIN_VIRT_LAST <= 32);
 
-/* Private flag used internally by virDomainSaveStatus and
- * virDomainObjParseFile.  */
+/* Private flags used internally by virDomainSaveStatus and
+ * virDomainLoadStatus. */
 typedef enum {
    VIR_DOMAIN_XML_INTERNAL_STATUS = (1<<16), /* dump internal domain status information */
+   VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET = (1<<17), /* dump/parse <actual> element */
 } virDomainXMLInternalFlags;
 
 VIR_ENUM_IMPL(virDomainTaint, VIR_DOMAIN_TAINT_LAST,
@@ -734,6 +735,27 @@ 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;
+    }
+
+    VIR_FREE(def);
+}
+
 void virDomainNetDefFree(virDomainNetDefPtr def)
 {
     if (!def)
@@ -756,6 +778,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:
@@ -2586,6 +2611,81 @@ cleanup:
     goto cleanup;
 }
 
+static int
+virDomainActualNetDefParseXML(xmlNodePtr node,
+                              xmlXPathContextPtr ctxt,
+                              virDomainActualNetDefPtr *def)
+{
+    virDomainActualNetDefPtr actual = NULL;
+    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 ((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;
+
+        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 &&
+            virVirtualPortProfileParseXML(virtPortNode,
+                                                &actual->data.direct.virtPortProfile) < 0) {
+            goto error;
+        }
+    }
+
+    *def = actual;
+    actual = NULL;
+    ret = 0;
+error:
+    VIR_FREE(type);
+    VIR_FREE(mode);
+    virDomainActualNetDefFree(actual);
+
+    ctxt->node = save_ctxt;
+    return ret;
+}
 
 /* Parse the XML definition for a network interface
  * @param node XML nodeset to parse for net definition
@@ -2603,6 +2703,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;
@@ -2619,6 +2720,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
     char *mode = NULL;
     virNWFilterHashTablePtr filterparams = NULL;
     virVirtualPortProfileParamsPtr virtPort = NULL;
+    virDomainActualNetDefPtr actual = NULL;
     xmlNodePtr oldnode = ctxt->node;
     int ret;
 
@@ -2650,6 +2752,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"))) {
@@ -2665,7 +2768,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")) {
                 if (virVirtualPortProfileParseXML(cur, &virtPort) < 0)
                     goto error;
@@ -2713,6 +2817,12 @@ virDomainNetDefParseXML(virCapsPtr caps,
                 if (virDomainDeviceBootParseXML(cur, &def->bootIndex,
                                                 bootMap))
                     goto error;
+            } else if ((actual == NULL) &&
+                       (flags & VIR_DOMAIN_XML_INTERNAL_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;
@@ -2761,6 +2871,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:
@@ -2956,11 +3072,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);
@@ -8536,6 +8654,67 @@ virDomainFSDefFormat(virBufferPtr buf,
     return 0;
 }
 
+static int
+virDomainActualNetDefFormat(virBufferPtr buf,
+                            virDomainActualNetDefPtr def)
+{
+    int ret = -1;
+    const char *type;
+    const char *mode;
+
+    if (!def)
+        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,
@@ -8559,8 +8738,18 @@ 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 ((flags & VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET) &&
+            (virDomainActualNetDefFormat(buf, def->data.network.actual) < 0))
+            return -1;
         break;
 
     case VIR_DOMAIN_NET_TYPE_ETHERNET:
@@ -9445,9 +9634,11 @@ virDomainHostdevDefFormat(virBufferPtr buf,
      VIR_DOMAIN_XML_INACTIVE |                  \
      VIR_DOMAIN_XML_UPDATE_CPU)
 
-verify((VIR_DOMAIN_XML_INTERNAL_STATUS & DUMPXML_FLAGS) == 0);
+verify(((VIR_DOMAIN_XML_INTERNAL_STATUS |
+         VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET)
+        & DUMPXML_FLAGS) == 0);
 
-/* This internal version can accept VIR_DOMAIN_XML_INTERNAL_STATUS,
+/* This internal version can accept VIR_DOMAIN_XML_INTERNAL_*,
  * whereas the public version cannot.  */
 static char *
 virDomainDefFormatInternal(virDomainDefPtr def,
@@ -9459,7 +9650,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
     const char *type = NULL;
     int n, allones = 1;
 
-    virCheckFlags(DUMPXML_FLAGS | VIR_DOMAIN_XML_INTERNAL_STATUS, NULL);
+    virCheckFlags(DUMPXML_FLAGS |
+                  VIR_DOMAIN_XML_INTERNAL_STATUS |
+                  VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET,
+                  NULL);
 
     if (!(type = virDomainVirtTypeToString(def->virtType))) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -10024,7 +10218,10 @@ int virDomainSaveStatus(virCapsPtr caps,
                         const char *statusDir,
                         virDomainObjPtr obj)
 {
-    unsigned int flags = VIR_DOMAIN_XML_SECURE|VIR_DOMAIN_XML_INTERNAL_STATUS;
+    unsigned int flags = (VIR_DOMAIN_XML_SECURE |
+                          VIR_DOMAIN_XML_INTERNAL_STATUS |
+                          VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET);
+
     int ret = -1;
     char *xml;
 
@@ -10115,7 +10312,8 @@ static virDomainObjPtr virDomainLoadStatus(virCapsPtr caps,
         goto error;
 
     if (!(obj = virDomainObjParseFile(caps, statusFile, expectedVirtTypes,
-                                      VIR_DOMAIN_XML_INTERNAL_STATUS)))
+                                      VIR_DOMAIN_XML_INTERNAL_STATUS |
+                                      VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET)))
         goto error;
 
     virUUIDFormat(obj->def->uuid, uuidstr);
@@ -11112,3 +11310,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;
+}
index 0e6354bfced1dfc1f470ac87ae578bec12f44a6c..551946b79b798a29192e94ed7c73ea8093a48295 100644 (file)
@@ -343,6 +343,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 {
+    int type; /* enum virDomainNetType */
+    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;
@@ -369,6 +390,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;
@@ -1340,6 +1372,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);
@@ -1450,6 +1483,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,
index f96fbb9ffdaa1e6e22be95f8b590fec0a810841c..f8b6abfa3347819948bfbc9e254fcc7b6e87f778 100644 (file)
@@ -228,6 +228,7 @@ virDomainAuditVcpu;
 # domain_conf.h
 virDiskNameToBusDeviceIndex;
 virDiskNameToIndex;
+virDomainActualNetDefFree;
 virDomainAssignDef;
 virDomainChrConsoleTargetTypeFromString;
 virDomainChrConsoleTargetTypeToString;
@@ -334,6 +335,11 @@ virDomainLoadAllConfigs;
 virDomainMemballoonModelTypeFromString;
 virDomainMemballoonModelTypeToString;
 virDomainNetDefFree;
+virDomainNetGetActualBridgeName;
+virDomainNetGetActualDirectDev;
+virDomainNetGetActualDirectMode;
+virDomainNetGetActualType;
+virDomainNetGetActualDirectVirtPortProfile;
 virDomainNetIndexByMac;
 virDomainNetInsert;
 virDomainNetRemoveByMac;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-virtio-network-portgroup.xml b/tests/qemuxml2argvdata/qemuxml2argv-net-virtio-network-portgroup.xml
new file mode 100644 (file)
index 0000000..0f6e076
--- /dev/null
@@ -0,0 +1,33 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory>219136</memory>
+  <currentMemory>219136</currentMemory>
+  <vcpu>1</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'/>
+    <interface type='network'>
+      <mac address='00:11:22:33:44:55'/>
+      <source network='rednet' portgroup='bob'/>
+      <virtualport type='802.1Qbg'>
+        <parameters managerid='11' typeid='1193047' typeidversion='2' instanceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/>
+      </virtualport>
+      <model type='virtio'/>
+    </interface>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
index f22872f6d97a3b833571c5ad3c093c4476c8630f..6b1fbf501863518737eafa7159a2b3471a9df8ea 100644 (file)
@@ -158,6 +158,7 @@ mymain(void)
     DO_TEST("net-virtio-device");
     DO_TEST("net-eth");
     DO_TEST("net-eth-ifname");
+    DO_TEST("net-virtio-network-portgroup");
     DO_TEST("sound");
 
     DO_TEST("serial-vc");