[libvirt] [PATCHv2 4/4] network: make network driver vlan-aware

Laine Stump laine at laine.org
Tue Aug 14 07:15:24 UTC 2012


The network driver now looks for the vlan element in network and
portgroup objects, and logs an error at network define time if a vlan
is requested for a network type that doesn't support it. (Currently
vlan configuration is only supported for openvswitch networks, and
networks used to do hostdev assignment of SR-IOV VFs.)

At runtime, the three potential sources of vlan information are
examined in this order: interface, chosen portgroup, network, and the
first that is non-empty is used.  Another check for valid network type
is made at this time, since the interface may have requested a vlan (a
legal thing to have in the interface config, since it's not known
until runtime if the chosen network will actually support it).

Since we must also check for domains requesting vlans for unsupported
connection types even if they are type='network', and since
networkAllocateActualDevice() is being called in exactly the correct
places, and has all of the necessary information to check, I slightly
modified the logic of that function so that interfaces that aren't
type='network' don't just return immediately. Instead, they also
perform all the same validation for supported features. Because of
this, it's not necessary to make this identical check in the other
three places that would normally require it: 1) qemu domain startup,
2) qemu device hotplug, 3) lxc domain startup.

This can be seen as a first step in consolidating network-related
functionality into the network driver, rather than having copies of
the same code spread around in multiple places; this will make it
easier to split the network parts off into a separate deamon, as we've
discussed recently.
---
 src/network/bridge_driver.c | 114 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 104 insertions(+), 10 deletions(-)

diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index b784eb4..2d453d0 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -2246,6 +2246,42 @@ cleanup:
 }
 
 
+static int
+networkValidate(virNetworkDefPtr def)
+{
+    int ii;
+    bool vlanUsed, vlanAllowed;
+
+    /* The only type of networks that currently support transparent
+     * vlan configuration are those using hostdev sr-iov devices from
+     * a pool, and those using an openvswitch bridge.
+     */
+
+    vlanAllowed = (def->forwardType == VIR_NETWORK_FORWARD_BRIDGE &&
+                   def->virtPortProfile &&
+                   def->virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH);
+
+    vlanUsed = def->vlan.nTags > 0;
+    for (ii = 0; ii < def->nPortGroups && !(vlanUsed && vlanAllowed); ii++) {
+        if (def->portGroups[ii].vlan.nTags > 0)
+            vlanUsed = true;
+        if (def->forwardType == VIR_NETWORK_FORWARD_BRIDGE &&
+            def->portGroups[ii].virtPortProfile &&
+            (def->portGroups[ii].virtPortProfile->virtPortType
+             == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)) {
+            vlanAllowed = true;
+        }
+    }
+    if (vlanUsed && !vlanAllowed) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("<vlan> element specified for network %s, "
+                         "whose type doesn't support vlan configuration"),
+                       def->name);
+        return -1;
+    }
+    return 0;
+}
+
 static virNetworkPtr networkCreate(virConnectPtr conn, const char *xml) {
     struct network_driver *driver = conn->networkPrivateData;
     virNetworkDefPtr def;
@@ -2273,6 +2309,9 @@ static virNetworkPtr networkCreate(virConnectPtr conn, const char *xml) {
         virNetworkSetBridgeMacAddr(def);
     }
 
+    if (networkValidate(def) < 0)
+       goto cleanup;
+
     if (!(network = virNetworkAssignDef(&driver->networks,
                                         def)))
         goto cleanup;
@@ -2346,6 +2385,9 @@ static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) {
         }
     }
 
+    if (networkValidate(def) < 0)
+       goto cleanup;
+
     if (!(network = virNetworkAssignDef(&driver->networks,
                                         def)))
         goto cleanup;
@@ -2744,18 +2786,24 @@ int
 networkAllocateActualDevice(virDomainNetDefPtr iface)
 {
     struct network_driver *driver = driverState;
-    virNetworkObjPtr network;
-    virNetworkDefPtr netdef;
-    virPortGroupDefPtr portgroup;
-    virNetDevVPortProfilePtr virtport = NULL;
+    enum virDomainNetType actualType = iface->type;
+    virNetworkObjPtr network = NULL;
+    virNetworkDefPtr netdef = NULL;
+    virPortGroupDefPtr portgroup = NULL;
+    virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
+    virNetDevVlanPtr vlan = NULL;
     virNetworkForwardIfDefPtr dev = NULL;
     unsigned int num_virt_fns = 0;
     char **vfname = NULL;
     int ii;
     int ret = -1;
 
+    /* it's handy to have this initialized if we skip directly to validate */
+    if (iface->vlan.nTags > 0)
+        vlan = &iface->vlan;
+
     if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
-        return 0;
+        goto validate;
 
     virDomainActualNetDefFree(iface->data.network.actual);
     iface->data.network.actual = NULL;
@@ -2815,7 +2863,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface)
             goto error;
         }
 
-        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
+        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
         iface->data.network.actual->data.bridge.brname = strdup(netdef->bridge);
         if (!iface->data.network.actual->data.bridge.brname) {
             virReportOOMError();
@@ -2861,7 +2909,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface)
         }
 
         /* Set type=direct and appropriate <source mode='xxx'/> */
-        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_DIRECT;
+        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
         switch (netdef->forwardType) {
         case VIR_NETWORK_FORWARD_BRIDGE:
             iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
@@ -2999,6 +3047,49 @@ networkAllocateActualDevice(virDomainNetDefPtr iface)
     if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
         goto error;
 
+    /* copy appropriate vlan info to actualNet */
+    if (iface->vlan.nTags > 0)
+        vlan = &iface->vlan;
+    else if (portgroup && portgroup->vlan.nTags > 0)
+        vlan = &portgroup->vlan;
+    else if (netdef && netdef->vlan.nTags > 0)
+        vlan = &netdef->vlan;
+
+    if (virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
+        goto error;
+
+validate:
+    /* make sure that everything now specified for the device is
+     * actually supported on this type of network. NB: network,
+     * netdev, and iface->data.network.actual may all be NULL.
+     */
+
+    if (vlan) {
+        /* vlan configuration via libvirt is only supported for
+         * PCI Passthrough SR-IOV devices and openvswitch bridges.
+         * otherwise log an error and fail
+         */
+        if (!(actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
+              (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE &&
+               virtport && virtport->virtPortType
+               == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) {
+            if (netdef) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("an interface connecting to network '%s' "
+                                 "is requesting a vlan tag, but that is not "
+                                 "supported for this type of network"),
+                               netdef->name);
+            } else {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("an interface of type '%s' "
+                                 "is requesting a vlan tag, but that is not "
+                                 "supported for this type of connection"),
+                               virDomainNetTypeToString(iface->type));
+            }
+            goto error;
+        }
+    }
+
     if (dev) {
         /* we are now assured of success, so mark the allocation */
         dev->connections++;
@@ -3006,10 +3097,13 @@ networkAllocateActualDevice(virDomainNetDefPtr iface)
                   dev->dev, dev->connections);
     }
 
-    netdef->connections++;
-    VIR_DEBUG("Using network %s, %d connections",
-              netdef->name, netdef->connections);
+    if (netdef) {
+        netdef->connections++;
+        VIR_DEBUG("Using network %s, %d connections",
+                  netdef->name, netdef->connections);
+    }
     ret = 0;
+
 error:
     for (ii = 0; ii < num_virt_fns; ii++)
         VIR_FREE(vfname[ii]);
-- 
1.7.11.2




More information about the libvir-list mailing list