[libvirt] [PATCH] vepa: parsing for 802.1Qb{g|h} XML

Stefan Berger stefanb at us.ibm.com
Mon May 10 23:57:37 UTC 2010


Below is David Alan's original patch with lots of changes. 

In particular, it now parses the following XML and stored the data
internally. No sending of netlink messages has been implemented here.

   <interface type='direct'>
      <source dev='static' mode='vepa'/>
      <model type='virtio'/>
      <vsi managerid='12' typeid='0x123456' typeidversion='1'
           instanceid='fa9b7fff-b0a0-4893-8e0e-beef4ff18f8f' />
      <filterref filter='clean-traffic'/>
    </interface>

    <interface type='direct'>
      <source dev='static' mode='vepa'/>
      <model type='virtio'/>
      <vsi profileid='my_profile'/>
    </interface>

I'd suggest to use this patch as a base for sending out netlink
messages.

Signed-off-by: Stefan Berger <stefanb at us.ibm.com>


>From a945107f047c7cd71f9c1b74fd74c47d8cdc3670 Mon Sep 17 00:00:00 2001
From: David Allan <dallan at redhat.com>
Date: Fri, 12 Mar 2010 13:25:04 -0500
Subject: [PATCH 1/1] POC of port profile id support

* Modified schema per DanPB's feedback
* Added test for modified schema
---
 docs/schemas/domain.rng                |   57 +++++++++++++++++++
 src/conf/domain_conf.c                 |   97
+++++++++++++++++++++++++++++++++
 src/conf/domain_conf.h                 |   31 ++++++++++
 src/qemu/qemu_conf.c                   |   11 ---
 src/qemu/qemu_conf.h                   |    2 
 src/qemu/qemu_driver.c                 |   14 +---
 src/util/macvtap.c                     |   89
+++++++++++++++++++++++++-----
 src/util/macvtap.h                     |    7 +-
 tests/domainschemadata/portprofile.xml |   22 +++++++
 9 files changed, 292 insertions(+), 38 deletions(-)
 create mode 100644 tests/domainschemadata/portprofile.xml

Index: libvirt-acl/docs/schemas/domain.rng
===================================================================
--- libvirt-acl.orig/docs/schemas/domain.rng
+++ libvirt-acl/docs/schemas/domain.rng
@@ -817,6 +817,9 @@
               </optional>
               <empty/>
             </element>
+            <optional>
+              <ref name="vsiProfile"/>
+            </optional>
             <ref name="interface-options"/>
           </interleave>
         </group>
@@ -902,6 +905,33 @@
       </optional>
     </interleave>
   </define>
+  <define name="vsiProfile">
+    <choice>
+      <group>
+        <element name="vsi">
+          <attribute name="managerid">
+            <ref name="uint8range"/>
+          </attribute>
+          <attribute name="typeid">
+            <ref name="uint24range"/>
+          </attribute>
+          <attribute name="typeidversion">
+            <ref name="uint8range"/>
+          </attribute>
+          <attribute name="instanceid">
+            <ref name="UUID"/>
+          </attribute>
+        </element>
+      </group>
+      <group>
+        <element name="vsi">
+          <attribute name="profileid">
+            <ref name="vsiProfileID"/>
+          </attribute>
+        </element>
+      </group>
+    </choice>
+  </define>
   <!--
       An emulator description is just a path to the binary used for the
task
     -->
@@ -1769,4 +1799,31 @@
       <param name="pattern">[a-zA-Z0-9_\.:]+</param>
     </data>
   </define>
+  <define name="uint8range">
+    <choice>
+      <data type="string">
+        <param name="pattern">0x[0-9a-fA-F]{1,2}</param>
+      </data>
+      <data type="int">
+        <param name="minInclusive">0</param>
+        <param name="maxInclusive">255</param>
+      </data>
+    </choice>
+  </define>
+  <define name="uint24range">
+    <choice>
+      <data type="string">
+        <param name="pattern">0x[0-9a-fA-F]{1,6}</param>
+      </data>
+      <data type="int">
+        <param name="minInclusive">0</param>
+        <param name="maxInclusive">16777215</param>
+      </data>
+    </choice>
+  </define>
+  <define name="vsiProfileID">
+    <data type="string">
+      <param name="maxLength">39</param>
+    </data>
+  </define>
 </grammar>
Index: libvirt-acl/src/conf/domain_conf.c
===================================================================
--- libvirt-acl.orig/src/conf/domain_conf.c
+++ libvirt-acl/src/conf/domain_conf.c
@@ -1831,7 +1831,13 @@ virDomainNetDefParseXML(virCapsPtr caps,
     char *internal = NULL;
     char *devaddr = NULL;
     char *mode = NULL;
+    char *vsiManagerID = NULL;
+    char *vsiTypeID = NULL;
+    char *vsiTypeIDVersion = NULL;
+    char *vsiInstanceID = NULL;
+    char *vsiProfileID = NULL;
     virNWFilterHashTablePtr filterparams = NULL;
+    virVSIProfileDefPtr vsi;
 
     if (VIR_ALLOC(def) < 0) {
         virReportOOMError();
@@ -1873,6 +1879,20 @@ virDomainNetDefParseXML(virCapsPtr caps,
                        xmlStrEqual(cur->name, BAD_CAST "source")) {
                 dev  = virXMLPropString(cur, "dev");
                 mode = virXMLPropString(cur, "mode");
+            } else if ((vsiManagerID == NULL) &&
+                       (vsiTypeID == NULL) &&
+                       (vsiTypeIDVersion == NULL) &&
+                       (vsiInstanceID == NULL) &&
+                       (vsiProfileID == NULL) &&
+                       (def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
+                       xmlStrEqual(cur->name, BAD_CAST "vsi")) {
+                vsiManagerID = virXMLPropString(cur, "managerid");
+                vsiTypeID = virXMLPropString(cur, "typeid");
+                vsiTypeIDVersion = virXMLPropString(cur,
"typeidversion");
+                vsiInstanceID = virXMLPropString(cur, "instanceid");
+#ifdef IFLA_VF_PORT_PROFILE_MAX
+                vsiProfileID = virXMLPropString(cur, "profileid");
+#endif
             } else if ((network == NULL) &&
                        ((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
                         (def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
@@ -2049,6 +2069,51 @@ virDomainNetDefParseXML(virCapsPtr caps,
         } else
             def->data.direct.mode =
VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA;
 
+        vsi = &def->data.direct.vsiProfile;
+
+#ifdef IFLA_VF_PORT_PROFILE_MAX
+        if (vsiProfileID != NULL) {
+            if (virStrcpyStatic(vsi->u.vsi8021Qbh.profileID,
+                                vsiProfileID) != NULL) {
+                vsi->vsiType = VIR_VSI_8021QBH;
+                break;
+            }
+        }
+#endif
+
+        while (vsiManagerID     != NULL && vsiTypeID     != NULL &&
+               vsiTypeIDVersion != NULL && vsiInstanceID != NULL) {
+            unsigned int val;
+
+            if ((virStrToLong_ui(vsiManagerID, NULL, 10, &val) &&
+                 virStrToLong_ui(vsiManagerID, NULL, 16, &val)   ) ||
+                val > 0xff)
+                break;
+
+            vsi->u.vsi8021Qbg.managerID = (uint8_t)val;
+
+            if ((virStrToLong_ui(vsiTypeID, NULL, 10, &val) &&
+                 virStrToLong_ui(vsiTypeID, NULL, 16, &val)   ) ||
+                val > 0xffffff)
+                break;
+
+            vsi->u.vsi8021Qbg.typeID = (uint32_t)val;
+
+            if ((virStrToLong_ui(vsiTypeIDVersion, NULL, 10, &val) &&
+                 virStrToLong_ui(vsiTypeIDVersion, NULL, 16, &val)   )
||
+                val > 0xff)
+                break;
+
+            vsi->u.vsi8021Qbg.typeIDVersion = (uint8_t)val;
+
+            if (virUUIDParse(vsiInstanceID,
+
def->data.direct.vsiProfile.u.vsi8021Qbg.instanceID))
+                break;
+
+            vsi->vsiType = VIR_VSI_8021QBG;
+            break;
+        }
+
         def->data.direct.linkdev = dev;
         dev = NULL;
 
@@ -2114,6 +2179,11 @@ cleanup:
     VIR_FREE(internal);
     VIR_FREE(devaddr);
     VIR_FREE(mode);
+    VIR_FREE(vsiManagerID);
+    VIR_FREE(vsiTypeID);
+    VIR_FREE(vsiTypeIDVersion);
+    VIR_FREE(vsiInstanceID);
+    VIR_FREE(vsiProfileID);
     virNWFilterHashTableFree(filterparams);
 
     return def;
@@ -5076,6 +5146,8 @@ virDomainNetDefFormat(virBufferPtr buf,
 {
     const char *type = virDomainNetTypeToString(def->type);
     char *attrs;
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    virVSIProfileDefPtr vsi;
 
     if (!type) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -5141,6 +5213,31 @@ virDomainNetDefFormat(virBufferPtr buf,
         virBufferVSprintf(buf, " mode='%s'",

virDomainNetdevMacvtapTypeToString(def->data.direct.mode));
         virBufferAddLit(buf, "/>\n");
+        vsi = &def->data.direct.vsiProfile;
+        switch (vsi->vsiType) {
+        case VIR_VSI_INVALID:
+            break;
+
+        case VIR_VSI_8021QBG:
+
virUUIDFormat(def->data.direct.vsiProfile.u.vsi8021Qbg.instanceID,
+                          uuidstr);
+            virBufferVSprintf(buf,
+                              "      <vsi managerid='%d' typeid='%d' "
+                              "typeidversion='%d' instanceid='%s'/>\n",
+                              vsi->u.vsi8021Qbg.managerID,
+                              vsi->u.vsi8021Qbg.typeID,
+                              vsi->u.vsi8021Qbg.typeIDVersion,
+                              uuidstr);
+            break;
+
+#ifdef IFLA_VF_PORT_PROFILE_MAX
+        case VIR_VSI_8021QBH:
+            virBufferVSprintf(buf,
+                              "      <vsi profileid='%s'/>\n",
+                              vsi->u.vsi8021Qbh.profileID);
+            break;
+#endif
+        }
         break;
 
     case VIR_DOMAIN_NET_TYPE_USER:
Index: libvirt-acl/src/conf/domain_conf.h
===================================================================
--- libvirt-acl.orig/src/conf/domain_conf.h
+++ libvirt-acl/src/conf/domain_conf.h
@@ -259,6 +259,36 @@ enum virDomainNetdevMacvtapType {
 };
 
 
+#define IFLA_VF_PORT_PROFILE_MAX 40
+enum virVSIType {
+    VIR_VSI_INVALID,
+    VIR_VSI_8021QBG,
+#ifdef IFLA_VF_PORT_PROFILE_MAX
+    VIR_VSI_8021QBH,
+#endif
+};
+
+/* profile data for macvtap (VEPA) */
+typedef struct _virVSIProfileDef virVSIProfileDef;
+typedef virVSIProfileDef *virVSIProfileDefPtr;
+struct _virVSIProfileDef {
+    enum virVSIType   vsiType;
+    union {
+        struct {
+            uint8_t       managerID;
+            uint32_t      typeID; // 24 bit valid
+            uint8_t       typeIDVersion;
+            unsigned char instanceID[VIR_UUID_BUFLEN];
+        } vsi8021Qbg;
+#ifdef IFLA_VF_PORT_PROFILE_MAX
+        struct {
+            char          profileID[IFLA_VF_PORT_PROFILE_MAX];
+        } vsi8021Qbh;
+#endif
+    } u;
+};
+
+
 /* Stores the virtual network interface configuration */
 typedef struct _virDomainNetDef virDomainNetDef;
 typedef virDomainNetDef *virDomainNetDefPtr;
@@ -290,6 +320,7 @@ struct _virDomainNetDef {
         struct {
             char *linkdev;
             int mode;
+            virVSIProfileDef vsiProfile;
         } direct;
     } data;
     char *ifname;
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -43,6 +43,7 @@
 
 # include "util.h"
 # include "memory.h"
+# include "logging.h"
 # include "macvtap.h"
 # include "interface.h"
 # include "conf/domain_conf.h"
@@ -57,6 +58,13 @@
 # define MACVTAP_NAME_PREFIX	"macvtap"
 # define MACVTAP_NAME_PATTERN	"macvtap%d"
 
+
+# define PREASSOCIATE                           0x00
+# define PREASSOCIATE_WITH_RESOURCE_RESERVATION 0x01
+# define ASSOCIATE                              0x02
+# define DEASSOCIATE                            0x03
+
+
 static int nlOpen(void)
 {
     int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
@@ -569,6 +577,45 @@ configMacvtapTap(int tapfd, int vnet_hdr
 }
 
 
+static int
+setPortProfileId(const char *linkdev ATTRIBUTE_UNUSED,
+                 unsigned char *mac ATTRIBUTE_UNUSED,
+                 int mode ATTRIBUTE_UNUSED,
+                 const virVSIProfileDefPtr profile ATTRIBUTE_UNUSED)
+{
+    return 0;
+}
+
+static int
+associatePortProfileId(const char *linkdev,
+                       unsigned char *mac,
+                       int mode,
+                       const virVSIProfileDefPtr profile)
+{
+    VIR_DEBUG("Associating port profile '%p' on link device '%s' mode %
d ",
+              profile, linkdev, mode);
+
+    return setPortProfileId(linkdev,
+                            mac,
+                            ASSOCIATE,
+                            profile);
+}
+
+
+static int
+disassociatePortProfileId(const char *linkdev,
+                          unsigned char *mac,
+                          const virVSIProfileDefPtr profile)
+{
+    VIR_DEBUG("Disassociating port profile id '%p' on link device '%s'
",
+              profile, linkdev);
+
+    return setPortProfileId(linkdev,
+                            mac,
+                            DEASSOCIATE,
+                            profile);
+}
+
 /**
  * openMacvtapTap:
  * Create an instance of a macvtap device and open its tap character
@@ -589,9 +636,7 @@ configMacvtapTap(int tapfd, int vnet_hdr
  */
 int
 openMacvtapTap(const char *tgifname,
-               const unsigned char *macaddress,
-               const char *linkdev,
-               int mode,
+               virDomainNetDefPtr net,
                char **res_ifname,
                int vnet_hdr)
 {
@@ -599,7 +644,7 @@ openMacvtapTap(const char *tgifname,
     int c, rc;
     char ifname[IFNAMSIZ];
     int retries, do_retry = 0;
-    uint32_t macvtapMode = macvtapModeFromInt(mode);
+    uint32_t macvtapMode = macvtapModeFromInt(net->data.direct.mode);
     const char *cr_ifname;
     int ifindex;
 
@@ -616,7 +661,7 @@ openMacvtapTap(const char *tgifname,
             return -1;
         }
         cr_ifname = tgifname;
-        rc = link_add(type, macaddress, 6, tgifname, linkdev,
+        rc = link_add(type, net->mac, 6, tgifname,
net->data.direct.linkdev,
                       macvtapMode, &do_retry);
         if (rc)
             return -1;
@@ -626,7 +671,8 @@ create_name:
         for (c = 0; c < 8192; c++) {
             snprintf(ifname, sizeof(ifname), MACVTAP_NAME_PATTERN, c);
             if (ifaceGetIndex(false, ifname, &ifindex) == ENODEV) {
-                rc = link_add(type, macaddress, 6, ifname, linkdev,
+                rc = link_add(type, net->mac, 6, ifname,
+                              net->data.direct.linkdev,
                               macvtapMode, &do_retry);
                 if (rc == 0)
                     break;
@@ -639,6 +685,13 @@ create_name:
         cr_ifname = ifname;
     }
 
+    rc = associatePortProfileId(net->data.direct.linkdev,
+                                net->mac,
+                                net->data.direct.mode,
+                                &net->data.direct.vsiProfile);
+    if (rc != 0)
+        goto link_del_exit;
+
     rc = ifaceUp(cr_ifname);
     if (rc != 0) {
         virReportSystemError(errno,
@@ -647,7 +700,7 @@ create_name:
                              "MAC address"),
                              cr_ifname);
         rc = -1;
-        goto link_del_exit;
+        goto disassociate_exit;
     }
 
     rc = openTap(cr_ifname, 10);
@@ -656,14 +709,19 @@ create_name:
         if (configMacvtapTap(rc, vnet_hdr) < 0) {
             close(rc);
             rc = -1;
-            goto link_del_exit;
+            goto disassociate_exit;
         }
         *res_ifname = strdup(cr_ifname);
     } else
-        goto link_del_exit;
+        goto disassociate_exit;
 
     return rc;
 
+disassociate_exit:
+    disassociatePortProfileId(net->data.direct.linkdev,
+                              net->mac,
+                              &net->data.direct.vsiProfile);
+
 link_del_exit:
     link_del(cr_ifname);
 
@@ -672,15 +730,20 @@ link_del_exit:
 
 
 /**
- * delMacvtapByName:
- * @ifname : The name of the macvtap interface
+ * delMacvtap:
+ * @net: pointer to virDomainNetDef object
  *
  * Delete an interface given its name.
  */
 void
-delMacvtap(const char *ifname)
+delMacvtap(virDomainNetDefPtr net)
 {
-    link_del(ifname);
+    if (net->ifname) {
+        disassociatePortProfileId(net->data.direct.linkdev,
+                                  net->mac,
+                                  &net->data.direct.vsiProfile);
+        link_del(net->ifname);
+    }
 }
 
 #endif
Index: libvirt-acl/src/util/macvtap.h
===================================================================
--- libvirt-acl.orig/src/util/macvtap.h
+++ libvirt-acl/src/util/macvtap.h
@@ -27,15 +27,14 @@
 # if defined(WITH_MACVTAP)
 
 #  include "internal.h"
+#  include "conf/domain_conf.h"
 
 int openMacvtapTap(const char *ifname,
-                   const unsigned char *macaddress,
-                   const char *linkdev,
-                   int mode,
+                   virDomainNetDefPtr net,
                    char **res_ifname,
                    int vnet_hdr);
 
-void delMacvtap(const char *ifname);
+void delMacvtap(virDomainNetDefPtr net);
 
 # endif /* WITH_MACVTAP */
 
Index: libvirt-acl/tests/domainschemadata/portprofile.xml
===================================================================
--- /dev/null
+++ libvirt-acl/tests/domainschemadata/portprofile.xml
@@ -0,0 +1,27 @@
+<domain type='lxc'>
+  <name>portprofile</name>
+  <uuid>00000000-0000-0000-0000-000000000000</uuid>
+  <memory>1048576</memory>
+    <os>
+        <type>exe</type>
+        <init>/sh</init>
+    </os>
+  <devices>
+    <interface type='direct'>
+      <source dev='eth0' mode='vepa'/>
+      <vsi managerid='12' typeid='1193046' typeidversion='1'
+      instanceid='fa9b7fff-b0a0-4893-8e0e-beef4ff18f8f'/>
+    </interface>
+    <interface type='direct'>
+      <source dev='eth0' mode='vepa'/>
+      <vsi profileid='my_profile'/>
+    </interface>
+    <interface type='direct'>
+      <source dev='eth0' mode='vepa'/>
+      <vsi/>
+    </interface>
+    <interface type='direct'>
+      <source dev='eth0' mode='vepa'/>
+    </interface>
+  </devices>
+</domain>
Index: libvirt-acl/src/qemu/qemu_conf.h
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.h
+++ libvirt-acl/src/qemu/qemu_conf.h
@@ -271,8 +271,6 @@ qemudOpenVhostNet(virDomainNetDefPtr net
 int qemudPhysIfaceConnect(virConnectPtr conn,
                           struct qemud_driver *driver,
                           virDomainNetDefPtr net,
-                          char *linkdev,
-                          int brmode,
                           unsigned long long qemuCmdFlags);
 
 int         qemudProbeMachineTypes      (const char *binary,
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -3585,10 +3585,8 @@ static void qemudShutdownVMDaemon(struct
     def = vm->def;
     for (i = 0; i < def->nnets; i++) {
         virDomainNetDefPtr net = def->nets[i];
-        if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
-            if (net->ifname)
-                delMacvtap(net->ifname);
-        }
+        if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT)
+            delMacvtap(net);
     }
 #endif
 
@@ -7175,8 +7173,6 @@ static int qemudDomainAttachNetDevice(vi
         }
 
         if ((tapfd = qemudPhysIfaceConnect(conn, driver, net,
-                                           net->data.direct.linkdev,
-                                           net->data.direct.mode,
                                            qemuCmdFlags)) < 0)
             return -1;
     }
@@ -8146,10 +8142,8 @@ qemudDomainDetachNetDevice(struct qemud_
     virNWFilterTearNWFilter(detach);
 
 #if WITH_MACVTAP
-    if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
-        if (detach->ifname)
-            delMacvtap(detach->ifname);
-    }
+    if (detach->type == VIR_DOMAIN_NET_TYPE_DIRECT)
+        delMacvtap(detach);
 #endif
 
     if ((driver->macFilter) && (detach->ifname != NULL)) {
Index: libvirt-acl/src/qemu/qemu_conf.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_conf.c
+++ libvirt-acl/src/qemu/qemu_conf.c
@@ -1465,8 +1465,6 @@ int
 qemudPhysIfaceConnect(virConnectPtr conn,
                       struct qemud_driver *driver,
                       virDomainNetDefPtr net,
-                      char *linkdev,
-                      int brmode,
                       unsigned long long qemuCmdFlags)
 {
     int rc;
@@ -1479,8 +1477,7 @@ qemudPhysIfaceConnect(virConnectPtr conn
         net->model && STREQ(net->model, "virtio"))
         vnet_hdr = 1;
 
-    rc = openMacvtapTap(net->ifname, net->mac, linkdev, brmode,
-                        &res_ifname, vnet_hdr);
+    rc = openMacvtapTap(net->ifname, net, &res_ifname, vnet_hdr);
     if (rc >= 0) {
         VIR_FREE(net->ifname);
         net->ifname = res_ifname;
@@ -1500,15 +1497,13 @@ qemudPhysIfaceConnect(virConnectPtr conn
             if (err) {
                 close(rc);
                 rc = -1;
-                delMacvtap(net->ifname);
+                delMacvtap(net);
             }
         }
     }
 #else
     (void)conn;
     (void)net;
-    (void)linkdev;
-    (void)brmode;
     (void)qemuCmdFlags;
     (void)driver;
     qemuReportError(VIR_ERR_INTERNAL_ERROR,
@@ -4130,8 +4125,6 @@ int qemudBuildCommandLine(virConnectPtr 
                     goto no_memory;
             } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
                 int tapfd = qemudPhysIfaceConnect(conn, driver, net,
-
net->data.direct.linkdev,
-
net->data.direct.mode,
                                                   qemuCmdFlags);
                 if (tapfd < 0)
                     goto error;




More information about the libvir-list mailing list