[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [RFC Incomplete Patch] Libvirt + Openvswitch



Hello all,

I know of many people who want to spin up VMs using libvirt + kvm/qemu and attach those VMs to an openvswitch bridge (see: http://www.openvswitch.org).   However, the only way I know of to get this working is a kludge that uses to tap devices along with <interface type="ethernet"> while running ovs-vsctl outside of libvirt.  Even worse, doing this on RHEL/Fedora seems to require privilege tweaks (e.g., running qemu as root, not dropping capabilities), which may not be acceptable for production deployments (see:  http://fedoraproject.org/wiki/How_to_debug_Virtualization_problems#Errors_using_.3Cinterface_type.3D.27ethernet.27.2F.3E ).

So I would like to start taking steps toward better libvirt/openvswitch integration.  My initial step has the fairly limit goal of enabling kvm/qemu VM NICs to attach to an openvswitch bridge in much the same way VM NIC can already attached to the linux bridge.  For example, specifying:

<interface type="openvswitch">
<source bridge="br0"/>
<mac address="ca:fe:de;ad:be:ef"/>
</interface> 

I also wanted to add a new child element of <interface> that can be used to specify some OVS specific configuration.  To start, I just want to expose a single 'interfaceid' value (this parameter is specific to openvswitch).  Extending the previous example:

<interface type="openvswitch">
<source bridge="br0"/>
<mac address="ca:fe:de;ad:be:ef"/>
<openvswitchport interfaceid="interface-xyz"/> 
</interface> 

For this first step (see attached patch), I am only targeting the model where the OVS bridge has been created externally ahead of time.  I am not tackling any of the "network" logic that actually creates/destroys bridges, as it is not needed for my target use case. 

A couple notes about the attached patch:
- I haven't actually run this code.  I was just poking around the libvirt code to learn about it and figured that a diff was the most concrete way to propose what I was thinking of doing.  I would be curious for pointers about big chunks of work that I may have missed (for example, I haven't added any tests yet). 
- the code was modeled on the network interface "bandwidth" code, that calls out to 'tc' to configure bandwidth rates.  Ideally we would be able to make direct C calls to OVS (and we plan to make that possible in the future), but calling an external utility right now is the only viable path. 
- no attention was paid to style guidelines.  Will do that before any real submission.  
- I wasn't very clear on the notion of an "actual" net def, as opposed to a normal net def.  What's the best place to look for documentation on this?  

Anyway, I'm primarily looking for feedback about whether I'm barking up the right tree before I spend time debugging or polishing the patch, so I would appreciate thoughts, advice, etc.  Thanks,

Dan


--
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dan Wendlandt 
Nicira Networks: www.nicira.com
twitter: danwendlandt
~~~~~~~~~~~~~~~~~~~~~~~~~~~

diff --git a/configure.ac b/configure.ac
index 6709ebf..709128d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -213,6 +213,8 @@ AC_PATH_PROG([UDEVSETTLE], [udevsettle], [],
 	[/sbin:/usr/sbin:/usr/local/sbin:$PATH])
 AC_PATH_PROG([MODPROBE], [modprobe], [],
 	[/sbin:/usr/sbin:/usr/local/sbin:$PATH])
+AC_PATH_PROG([OVSVSCTL], [ovs-vsctl], [ovs-vsctl],
+	[/sbin:/usr/sbin:/usr/local/sbin:$PATH])
 
 AC_DEFINE_UNQUOTED([DNSMASQ],["$DNSMASQ"],
         [Location or name of the dnsmasq program])
@@ -220,6 +222,9 @@ AC_DEFINE_UNQUOTED([RADVD],["$RADVD"],
         [Location or name of the radvd program])
 AC_DEFINE_UNQUOTED([TC],["$TC"],
         [Location or name of the tc profram (see iproute2)])
+AC_DEFINE_UNQUOTED([OVSVSCTL],["$OVSVSCTL"],
+        [Location or name of the ovs-vsctl program])
+
 if test -n "$UDEVADM"; then
   AC_DEFINE_UNQUOTED([UDEVADM],["$UDEVADM"],
         [Location or name of the udevadm program])
diff --git a/src/Makefile.am b/src/Makefile.am
index a44446f..679a060 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -94,6 +94,7 @@ UTIL_SOURCES =							\
 		util/virkeymaps.h				\
 		util/virnetdev.h util/virnetdev.c		\
 		util/virnetdevbandwidth.h util/virnetdevbandwidth.c \
+		util/virnetdevopenvswitch.h util/virnetdevopenvswitch.c \
 		util/virnetdevbridge.h util/virnetdevbridge.c	\
 		util/virnetdevmacvlan.c util/virnetdevmacvlan.h	\
 		util/virnetdevtap.h util/virnetdevtap.c		\
@@ -133,6 +134,7 @@ LOCK_DRIVER_SANLOCK_SOURCES = \
 
 NETDEV_CONF_SOURCES =						\
 		conf/netdev_bandwidth_conf.h conf/netdev_bandwidth_conf.c \
+		conf/netdev_openvswitch_conf.h conf/netdev_openvswitch_conf.c \
 		conf/netdev_vport_profile_conf.h conf/netdev_vport_profile_conf.c
 
 # XML configuration format handling sources
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e872396..eafcd9a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -50,6 +50,7 @@
 #include "count-one-bits.h"
 #include "secret_conf.h"
 #include "netdev_vport_profile_conf.h"
+#include "netdev_openvswitch_conf.h"
 #include "netdev_bandwidth_conf.h"
 
 #define VIR_FROM_THIS VIR_FROM_DOMAIN
@@ -279,6 +280,7 @@ VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
               "network",
               "bridge",
               "internal",
+              "openvswitch",
               "direct")
 
 VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
@@ -945,6 +947,10 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def)
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
         VIR_FREE(def->data.bridge.brname);
         break;
+    case VIR_DOMAIN_NET_TYPE_OPENVSWITCH:
+        VIR_FREE(def->data.ovs.ovsPort->brname);
+        VIR_FREE(def->data.ovs.ovsPort->InterfaceID);
+        VIR_FREE(def->data.ovs.ovsPort);
     case VIR_DOMAIN_NET_TYPE_DIRECT:
         VIR_FREE(def->data.direct.linkdev);
         VIR_FREE(def->data.direct.virtPortProfile);
@@ -998,6 +1004,12 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
         VIR_FREE(def->data.direct.virtPortProfile);
         break;
 
+    case VIR_DOMAIN_NET_TYPE_OPENVSWITCH:
+        VIR_FREE(def->data.ovs.ovsPort->brname);
+        VIR_FREE(def->data.ovs.ovsPort->InterfaceID);
+        VIR_FREE(def->data.ovs.ovsPort);
+        break;
+
     case VIR_DOMAIN_NET_TYPE_USER:
     case VIR_DOMAIN_NET_TYPE_LAST:
         break;
@@ -3606,6 +3618,7 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
         goto error;
     }
     if (actual->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
+        actual->type != VIR_DOMAIN_NET_TYPE_OPENVSWITCH &&
         actual->type != VIR_DOMAIN_NET_TYPE_DIRECT &&
         actual->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -3616,6 +3629,14 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
 
     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_OPENVSWITCH) {
+        actual->data.bridge.brname = virXPathString("string(./source[1]/@bridge)", ctxt);
+
+        xmlNodePtr ovsPortNode = virXPathNode("./openvswitchport", ctxt);
+        if (ovsPortNode &&
+            (!(actual->data.ovs.ovsPort =
+               virNetDevOpenvswitchPortParse(ovsPortNode))))
+            goto error;
     } else if (actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
         xmlNodePtr virtPortNode;
 
@@ -3695,6 +3716,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
     char *linkstate = NULL;
     virNWFilterHashTablePtr filterparams = NULL;
     virNetDevVPortProfilePtr virtPort = NULL;
+    virNetDevOpenvswitchPortPtr ovsPort = NULL;
     virDomainActualNetDefPtr actual = NULL;
     xmlNodePtr oldnode = ctxt->node;
     int ret;
@@ -3736,6 +3758,10 @@ virDomainNetDefParseXML(virCapsPtr caps,
                        (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
                        (xmlStrEqual(cur->name, BAD_CAST "source"))) {
                 bridge = virXMLPropString(cur, "bridge");
+            } else if ((network == NULL) &&
+                       (def->type == VIR_DOMAIN_NET_TYPE_OPENVSWITCH) &&
+                       (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+                bridge = virXMLPropString(cur, "bridge");
             } else if ((dev == NULL) &&
                        (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET ||
                         def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
@@ -3748,6 +3774,11 @@ virDomainNetDefParseXML(virCapsPtr caps,
                        xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
                 if (!(virtPort = virNetDevVPortProfileParse(cur)))
                     goto error;
+            } else if ((ovsPort == NULL) &&
+                       ((def->type == VIR_DOMAIN_NET_TYPE_OPENVSWITCH) &&
+                       xmlStrEqual(cur->name, BAD_CAST "openvswitchport"))) {
+                if (!(ovsPort = virNetDevOpenvswitchPortParse(cur)))
+                    goto error;
             } else if ((network == NULL) &&
                        ((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
                         (def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
@@ -3885,6 +3916,14 @@ virDomainNetDefParseXML(virCapsPtr caps,
         }
         break;
 
+    case VIR_DOMAIN_NET_TYPE_OPENVSWITCH:
+        if (bridge == NULL) {
+            virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+    _("No <source> 'bridge' attribute specified with <interface type='openvswitch'/>"));
+            goto error;
+        }
+        break;
+
     case VIR_DOMAIN_NET_TYPE_CLIENT:
     case VIR_DOMAIN_NET_TYPE_SERVER:
     case VIR_DOMAIN_NET_TYPE_MCAST:
@@ -10279,6 +10318,7 @@ virDomainActualNetDefFormat(virBufferPtr buf,
     }
 
     if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
+        def->type != VIR_DOMAIN_NET_TYPE_OPENVSWITCH &&
         def->type != VIR_DOMAIN_NET_TYPE_DIRECT &&
         def->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -10312,6 +10352,14 @@ virDomainActualNetDefFormat(virBufferPtr buf,
             goto error;
         virBufferAdjustIndent(buf, -8);
         break;
+    case VIR_DOMAIN_NET_TYPE_OPENVSWITCH:
+        virBufferEscapeString(buf, "      <source bridge='%s'/>\n",
+                              def->data.ovs.ovsPort->brname);
+        virBufferAdjustIndent(buf, 6);
+        if (virNetDevOpenvswitchPortFormat(def->data.ovs.ovsPort, buf) < 0)
+            return -1;
+        virBufferAdjustIndent(buf, -6);
+        break;
     default:
         break;
     }
@@ -10408,6 +10456,14 @@ virDomainNetDefFormat(virBufferPtr buf,
         virBufferAdjustIndent(buf, -6);
         break;
 
+    case VIR_DOMAIN_NET_TYPE_OPENVSWITCH:
+        virBufferEscapeString(buf, "      <source bridge='%s'/>\n",
+                              def->data.ovs.ovsPort->brname);
+        virBufferAdjustIndent(buf, 6);
+        if (virNetDevOpenvswitchPortFormat(def->data.ovs.ovsPort, buf) < 0)
+            return -1;
+        virBufferAdjustIndent(buf, -6);
+        break;
     case VIR_DOMAIN_NET_TYPE_USER:
     case VIR_DOMAIN_NET_TYPE_LAST:
         break;
@@ -13729,6 +13785,18 @@ virDomainNetGetActualBandwidth(virDomainNetDefPtr iface)
     return iface->bandwidth;
 }
 
+virNetDevOpenvswitchPortPtr
+virDomainNetGetActualOpenvswitchPortPtr(virDomainNetDefPtr iface)
+{
+    if (iface->type == VIR_DOMAIN_NET_TYPE_OPENVSWITCH)
+        return iface->data.ovs.ovsPort;
+    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
+        return NULL;
+    if (!iface->data.network.actual)
+        return NULL;
+    return iface->data.network.actual->data.ovs.ovsPort;
+}
+
 
 /* Return listens[ii] from the appropriate union for the graphics
  * type, or NULL if this is an unsuitable type, or the index is out of
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 3b522a9..5d0cfcd 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -41,6 +41,7 @@
 # include "virnetdevmacvlan.h"
 # include "sysinfo.h"
 # include "virnetdevvportprofile.h"
+# include "virnetdevopenvswitch.h"
 # include "virnetdevbandwidth.h"
 
 /* Different types of hypervisor */
@@ -525,6 +526,7 @@ enum virDomainNetType {
     VIR_DOMAIN_NET_TYPE_BRIDGE,
     VIR_DOMAIN_NET_TYPE_INTERNAL,
     VIR_DOMAIN_NET_TYPE_DIRECT,
+    VIR_DOMAIN_NET_TYPE_OPENVSWITCH,
 
     VIR_DOMAIN_NET_TYPE_LAST,
 };
@@ -574,6 +576,9 @@ struct _virDomainActualNetDef {
             int mode; /* enum virMacvtapMode from util/macvtap.h */
             virNetDevVPortProfilePtr virtPortProfile;
         } direct;
+        struct {
+            virNetDevOpenvswitchPortPtr ovsPort;
+        } ovs;
     } data;
     virNetDevBandwidthPtr bandwidth;
 };
@@ -628,6 +633,9 @@ struct _virDomainNetDef {
             int mode; /* enum virMacvtapMode from util/macvtap.h */
             virNetDevVPortProfilePtr virtPortProfile;
         } direct;
+        struct {
+            virNetDevOpenvswitchPortPtr ovsPort;
+        } ovs;
     } data;
     struct {
         bool sndbuf_specified;
@@ -1860,6 +1868,9 @@ virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface);
 virNetDevBandwidthPtr
 virDomainNetGetActualBandwidth(virDomainNetDefPtr iface);
 
+virNetDevOpenvswitchPortPtr
+virDomainNetGetActualOpenvswitchPortPtr(virDomainNetDefPtr iface);
+
 int virDomainControllerInsert(virDomainDefPtr def,
                               virDomainControllerDefPtr controller);
 void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
diff --git a/src/conf/netdev_openvswitch_conf.c b/src/conf/netdev_openvswitch_conf.c
new file mode 100644
index 0000000..f83b8bf
--- /dev/null
+++ b/src/conf/netdev_openvswitch_conf.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 Nicira, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Authors:
+ *     Dan Wendlandt <dan nicira com>
+ */
+
+#include <config.h>
+
+#include "netdev_openvswitch_conf.h"
+#include "virterror_internal.h"
+#include "memory.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+#define virNetDevError(code, ...)                                       \
+    virReportErrorHelper(VIR_FROM_THIS, code, __FILE__,                 \
+                         __FUNCTION__, __LINE__, __VA_ARGS__)
+
+
+virNetDevOpenvswitchPortPtr
+virNetDevOpenvswitchPortParse(xmlNodePtr node)
+{
+    virNetDevOpenvswitchPortPtr ovsPort = NULL;
+    xmlNodePtr cur = node->children;
+
+    if (VIR_ALLOC(ovsPort) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    ovsPort->InterfaceID = virXMLPropString(node, "interfaceid");
+
+    if (!ovsPort->InterfaceID || strlen(ovsPort->InterfaceID) == 0) {
+        // interfaceID does not have to be a UUID,
+        // but a UUID is a reasonable default
+        virAlloc(ovsPort->InterfaceID, VIR_UUID_STRING_BUFLEN);
+        if (virUUIDGenerate(ovsPort->InterfaceID)) {
+                    virNetDevError(VIR_ERR_XML_ERROR, "%s",
+                                         _("cannot generate a random uuid for interfaceid"));
+                    goto error;
+        }
+    }
+
+cleanup:
+    return ovsPort;
+
+error:
+    VIR_FREE(ovsPort);
+    goto cleanup;
+}
+
+
+int
+virNetDevOpenvswitchPortFormat(virNetDevOpenvswitchPortPtr ovsPort,
+                            virBufferPtr buf)
+{
+    if (ovsPort)
+        virBufferAsprintf(buf, "<openvswitchport interfaceid='%s'/>\n",
+                                                    ovsPort->InterfaceID);
+    return 0;
+}
diff --git a/src/conf/netdev_openvswitch_conf.h b/src/conf/netdev_openvswitch_conf.h
new file mode 100644
index 0000000..d0d077b
--- /dev/null
+++ b/src/conf/netdev_openvswitch_conf.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 Nicira, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Authors:
+ *     Dan Wendlandt <dan nicira com>
+ */
+
+#ifndef __VIR_NETDEV_OPENVSWITCH_CONF_H__
+# define __VIR_NETDEV_OPENVSWITCH_CONF_H__
+
+# include "internal.h"
+# include "virnetdevopenvswitch.h"
+# include "buf.h"
+# include "xml.h"
+
+virNetDevOpenvswitchPortPtr
+virNetDevOpenvswitchPortParse(xmlNodePtr node);
+
+int
+virNetDevOpenvswitchPortFormat(virNetDevOpenvswitchPortPtr ovsPort,
+                            virBufferPtr buf);
+
+
+#endif /* __VIR_NETDEV_OPENVSWITCH_CONF_H__ */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 04ae35c..1aa78a7 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -378,6 +378,7 @@ virDomainNetGetActualBridgeName;
 virDomainNetGetActualDirectDev;
 virDomainNetGetActualDirectMode;
 virDomainNetGetActualDirectVirtPortProfile;
+virDomainNetGetActualOpenvswitchPortPtr;
 virDomainNetGetActualType;
 virDomainNetIndexByMac;
 virDomainNetInsert;
@@ -741,6 +742,10 @@ nlComm;
 virNetDevBandwidthFormat;
 virNetDevBandwidthParse;
 
+# netdev_openvswitch_conf.h
+virNetDevOpenvswitchPortFormat;
+virNetDevOpenvswitchPortParse;
+
 
 # netdev_vportprofile_conf.h
 virNetDevVPortProfileFormat;
@@ -1238,6 +1243,10 @@ virNetDevMacVLanCreateWithVPortProfile;
 virNetDevMacVLanDeleteWithVPortProfile;
 
 
+# virnetdevopenvswitch.h
+virNetDevOpenvswitchAddPort;
+
+
 # virnetdevtap.h
 virNetDevTapCreate;
 virNetDevTapCreateInBridgePort;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 5d0d528..d4989c8 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1766,7 +1766,7 @@ networkStartNetworkVirtual(struct network_driver *driver,
             goto err0;
         }
         if (virNetDevTapCreateInBridgePort(network->def->bridge,
-                                           &macTapIfName, network->def->mac, 0, false, NULL) < 0) {
+                           &macTapIfName, network->def->mac, 0, false, NULL, NULL) < 0) {
             VIR_FREE(macTapIfName);
             goto err0;
         }
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index aaccf62..6f411c8 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -221,6 +221,13 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
             virReportOOMError();
             return -1;
         }
+    } else if (actualType == VIR_DOMAIN_NET_TYPE_OPENVSWITCH) {
+        virNetDevOpenvswitchPortPtr p =
+               virDomainNetGetActualOpenvswitchPortPtr(net);
+        if (!(brname = strdup(p->brname))) {
+            virReportOOMError();
+            return -1;
+        }
     } else {
         qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         _("Network type %d is not supported"),
@@ -247,7 +254,7 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,
     memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
     tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
     err = virNetDevTapCreateInBridgePort(brname, &net->ifname, tapmac,
-                                         vnet_hdr, true, &tapfd);
+                                         vnet_hdr, true, &tapfd, net);
     virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0);
     if (err < 0) {
         if (template_ifname)
@@ -2539,6 +2546,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
     switch (netType) {
     case VIR_DOMAIN_NET_TYPE_NETWORK:
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
+    case VIR_DOMAIN_NET_TYPE_OPENVSWITCH:
     case VIR_DOMAIN_NET_TYPE_DIRECT:
         virBufferAddLit(&buf, "tap");
         virBufferAsprintf(&buf, "%cfd=%s", type_sep, tapfd);
@@ -2587,6 +2595,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
         case VIR_DOMAIN_NET_TYPE_ETHERNET:
         case VIR_DOMAIN_NET_TYPE_NETWORK:
         case VIR_DOMAIN_NET_TYPE_BRIDGE:
+        case VIR_DOMAIN_NET_TYPE_OPENVSWITCH:
         case VIR_DOMAIN_NET_TYPE_INTERNAL:
         case VIR_DOMAIN_NET_TYPE_DIRECT:
         case VIR_DOMAIN_NET_TYPE_LAST:
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index 316d558..4ad2d90 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -142,7 +142,7 @@ umlConnectTapDevice(virConnectPtr conn,
     memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
     tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
     if (virNetDevTapCreateInBridgePort(bridge, &net->ifname, tapmac,
-                                       0, true, NULL) < 0) {
+                                       0, true, NULL, net) < 0) {
         if (template_ifname)
             VIR_FREE(net->ifname);
         goto error;
@@ -238,6 +238,7 @@ umlBuildCommandLineNet(virConnectPtr conn,
     }
 
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
+    case VIR_DOMAIN_NET_TYPE_OPENVSWITCH:
         if (umlConnectTapDevice(conn, vm, def,
                                 def->data.bridge.brname) < 0)
             goto error;
diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c
new file mode 100644
index 0000000..0c96116
--- /dev/null
+++ b/src/util/virnetdevopenvswitch.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2012 Nicira, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Authors:
+ *     Dan Wendlandt <dan nicira  com>
+ */
+
+#include <config.h>
+
+#include "virnetdevopenvswitch.h"
+#include "command.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "ignore-value.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+/**
+ * virNetDevOpenvswitchAddPort:
+ * @brname: the bridge name
+ * @ifname: the network interface name
+ * @macaddr: the mac address of the virtual interface
+ *
+ * Adds an interface to an OVS bridge
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+int virNetDevOpenvswitchAddPort(const char *brname, const char *ifname,
+                                   const unsigned char *macaddr,
+                                   virNetDevOpenvswitchPortPtr ovs_port)
+{
+    int ret = -1;
+    virCommandPtr cmd = NULL;
+    char *attachedmac_ex_id = NULL;
+    char *ifaceid_ex_id = NULL;
+
+    if (virAsprintf(&attachedmac_ex_id, "external-ids:attached-mac=%s", macaddr) < 0)
+        goto cleanup;
+    if (virAsprintf(&ifaceid_ex_id, "external-ids:iface-id=%s", ovs_port->InterfaceID) < 0)
+        goto cleanup;
+
+    cmd = virCommandNew(OVSVSCTL);
+    virCommandAddArgList(cmd, "--", "--may-exist", "add-port",
+                        brname, ifname,
+                        "--", "set", "Interface", ifname, attachedmac_ex_id,
+                        "--", "set", "Interface", ifname, ifaceid_ex_id,
+                        "--", "set", "Interface", ifname,
+                        "external-ids:iface-status=active",
+                        NULL);
+
+    if (virCommandRun(cmd, NULL) < 0)
+    {
+        virReportSystemError(VIR_ERR_INTERNAL_ERROR,
+                             _("Unable to add port %s to OVS bridge %s"), ifname, brname);
+        goto cleanup;
+    }
+    ret = 0;
+
+    cleanup:
+        VIR_FREE(attachedmac_ex_id);
+        VIR_FREE(ifaceid_ex_id);
+        virCommandFree(cmd);
+        return ret;
+}
+
diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h
new file mode 100644
index 0000000..bc6ecb3
--- /dev/null
+++ b/src/util/virnetdevopenvswitch.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 Nicira, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Authors:
+ *     Dan Wendlandt <dan nicira  com>
+ */
+
+#ifndef __VIR_NETDEV_OPENVSWITCH_H__
+# define __VIR_NETDEV_OPENVSWITCH_H__
+
+# include "internal.h"
+
+typedef struct _virNetDevOpenvswitchPort virNetDevOpenvswitchPort;
+typedef virNetDevOpenvswitchPort *virNetDevOpenvswitchPortPtr;
+struct _virNetDevOpenvswitchPort {
+    char *brname;
+    char *InterfaceID;
+};
+
+int virNetDevOpenvswitchAddPort(const char *brname, const char *ifname,
+                                   const unsigned char *macaddr,
+                                   virNetDevOpenvswitchPortPtr ovs_port)
+
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
+
+#endif /* __VIR_NETDEV_OPENVSWITCH_H__ */
diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c
index 2ed53c6..3368051 100644
--- a/src/util/virnetdevtap.c
+++ b/src/util/virnetdevtap.c
@@ -25,6 +25,7 @@
 #include "virnetdevtap.h"
 #include "virnetdev.h"
 #include "virnetdevbridge.h"
+#include "virnetdevopenvswitch.h"
 #include "virterror_internal.h"
 #include "virfile.h"
 #include "virterror_internal.h"
@@ -249,6 +250,7 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED)
  * @macaddr: desired MAC address (VIR_MAC_BUFLEN long)
  * @vnet_hdr: whether to try enabling IFF_VNET_HDR
  * @tapfd: file descriptor return value for the new tap device
+ * @net: the net descriptor
  *
  * This function creates a new tap device on a bridge. @ifname can be either
  * a fixed name or a name template with '%d' for dynamic name allocation.
@@ -265,8 +267,16 @@ int virNetDevTapCreateInBridgePort(const char *brname,
                                    const unsigned char *macaddr,
                                    int vnet_hdr,
                                    bool up,
-                                   int *tapfd)
+                                   int *tapfd,
+                                   virDomainNetDefPtr net)
 {
+    int actualType;
+
+    if (net)
+        actualType = virDomainNetGetActualType(net);
+    else
+        actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
+
     if (virNetDevTapCreate(ifname, vnet_hdr, tapfd) < 0)
         return -1;
 
@@ -286,8 +296,14 @@ int virNetDevTapCreateInBridgePort(const char *brname,
     if (virNetDevSetMTUFromDevice(*ifname, brname) < 0)
         goto error;
 
-    if (virNetDevBridgeAddPort(brname, *ifname) < 0)
-        goto error;
+    if (actualType == VIR_DOMAIN_NET_TYPE_OPENVSWITCH) {
+        virNetDevOpenvswitchPortPtr p = virDomainNetGetActualOpenvswitchPortPtr(net);
+        if (virNetDevOpenvswitchAddPort(brname, *ifname, macaddr, p) < 0)
+            goto error;
+    } else {
+        if (virNetDevBridgeAddPort(brname, *ifname) < 0)
+            goto error;
+    }
 
     if (virNetDevSetOnline(*ifname, up) < 0)
         goto error;
diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h
index fb35ac5..e0be898 100644
--- a/src/util/virnetdevtap.h
+++ b/src/util/virnetdevtap.h
@@ -24,6 +24,7 @@
 # define __VIR_NETDEV_TAP_H__
 
 # include "internal.h"
+# include "conf/domain_conf.h"
 
 int virNetDevTapCreate(char **ifname,
                        int vnet_hdr,
@@ -38,7 +39,8 @@ int virNetDevTapCreateInBridgePort(const char *brname,
                                    const unsigned char *macaddr,
                                    int vnet_hdr,
                                    bool up,
-                                   int *tapfd)
+                                   int *tapfd,
+                                   virDomainNetDefPtr net)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
     ATTRIBUTE_RETURN_CHECK;
 

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]