[libvirt] [PATCH] RFC Libvirt + Openvswitch

Ansis Atteka aatteka at nicira.com
Fri Feb 3 22:55:00 UTC 2012


This patch allows libvirt to add interfaces to already
existing Open vSwitch bridges. The following syntax in
domain XML file must be used:

    <interface type='bridge'>
      <mac address='52:54:00:d0:3f:f2'/>
      <source bridge='ovsbr'/>
      <virtualport type='openvswitch'>
        <parameters interfaceid='921a80cd-e6de-5a2e-db9c-ab27f15a6e1d'/>
      </virtualport>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>

or if libvirt should auto-generate the interfaceid us following syntax:

    <interface type='bridge'>
      <mac address='52:54:00:d0:3f:f2'/>
      <source bridge='ovsbr'/>
      <virtualport type='openvswitch'>
      </virtualport>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>

To create Open vSwitch bridge us following command:

    ovs-vsctl add-br ovsbr

1. This patch has been tested only on Ubuntu 11.10 with KVM
2. Auto-generated interfaceid is not persistent across libvirt reboots
---
 configure.ac                       |    5 ++
 src/Makefile.am                    |    2 +
 src/conf/domain_conf.c             |   46 ++++++++++++++
 src/conf/domain_conf.h             |    6 ++
 src/conf/netdev_openvswitch_conf.c |   94 +++++++++++++++++++++++++++++
 src/conf/netdev_openvswitch_conf.h |   39 ++++++++++++
 src/libvirt_private.syms           |   12 ++++
 src/lxc/lxc_driver.c               |   19 ++++--
 src/network/bridge_driver.c        |    3 +-
 src/qemu/qemu_command.c            |    3 +-
 src/qemu/qemu_hotplug.c            |    7 ++-
 src/qemu/qemu_process.c            |    3 +
 src/uml/uml_conf.c                 |    3 +-
 src/util/uuid.c                    |   19 ++++++
 src/util/uuid.h                    |    1 +
 src/util/virnetdevopenvswitch.c    |  114 ++++++++++++++++++++++++++++++++++++
 src/util/virnetdevopenvswitch.h    |   46 ++++++++++++++
 src/util/virnetdevtap.c            |   32 +++++++++-
 src/util/virnetdevtap.h            |    8 ++-
 19 files changed, 447 insertions(+), 15 deletions(-)
 create mode 100644 src/conf/netdev_openvswitch_conf.c
 create mode 100644 src/conf/netdev_openvswitch_conf.h
 create mode 100644 src/util/virnetdevopenvswitch.c
 create mode 100644 src/util/virnetdevopenvswitch.h

diff --git a/configure.ac b/configure.ac
index 9fb7bfc..dca178f 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 a3dd847..79a2dde 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -95,6 +95,7 @@ UTIL_SOURCES =							\
 		util/virmacaddr.h util/virmacaddr.c		\
 		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		\
@@ -136,6 +137,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 aa4b32d..abec371 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -31,6 +31,7 @@
 #include <sys/time.h>
 #include <strings.h>
 
+#include "internal.h"
 #include "virterror_internal.h"
 #include "datatypes.h"
 #include "domain_conf.h"
@@ -50,6 +51,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
@@ -952,6 +954,7 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def)
     switch (def->type) {
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
         VIR_FREE(def->data.bridge.brname);
+        VIR_FREE(def->data.bridge.ovsPort);
         break;
     case VIR_DOMAIN_NET_TYPE_DIRECT:
         VIR_FREE(def->data.direct.linkdev);
@@ -995,6 +998,7 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
         VIR_FREE(def->data.bridge.brname);
         VIR_FREE(def->data.bridge.ipaddr);
+        VIR_FREE(def->data.bridge.ovsPort);
         break;
 
     case VIR_DOMAIN_NET_TYPE_INTERNAL:
@@ -3737,7 +3741,15 @@ virDomainActualNetDefParseXML(xmlNodePtr node,
     }
 
     if (actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+        xmlNodePtr virtPortNode = virXPathNode("./virtualport", ctxt);
         actual->data.bridge.brname = virXPathString("string(./source[1]/@bridge)", ctxt);
+        if (virtPortNode && virXMLPropString(virtPortNode, "type") &&
+                STREQ(virXMLPropString(virtPortNode, "type"), "openvswitch")) {
+            if (!(actual->data.bridge.ovsPort =
+                  virNetDevOpenvswitchPortParse(virtPortNode))) {
+                goto error;
+            }
+        }
     } else if (actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
         xmlNodePtr virtPortNode;
 
@@ -3817,6 +3829,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;
@@ -3870,6 +3883,13 @@ 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_BRIDGE) &&
+                       xmlStrEqual(cur->name, BAD_CAST "virtualport") &&
+                       virXMLPropString(cur, "type") &&
+                       STREQ(virXMLPropString(cur, "type"), "openvswitch"))) {
+                if (!(ovsPort = virNetDevOpenvswitchPortParse(cur)))
+                    goto error;
             } else if ((network == NULL) &&
                        ((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
                         (def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
@@ -4005,6 +4025,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
             def->data.bridge.ipaddr = address;
             address = NULL;
         }
+        def->data.bridge.ovsPort = ovsPort;
+        ovsPort = NULL;
         break;
 
     case VIR_DOMAIN_NET_TYPE_CLIENT:
@@ -10427,6 +10449,12 @@ virDomainActualNetDefFormat(virBufferPtr buf,
     case VIR_DOMAIN_NET_TYPE_BRIDGE:
         virBufferEscapeString(buf, "        <source bridge='%s'/>\n",
                               def->data.bridge.brname);
+        if (def->data.bridge.ovsPort) {
+            virBufferAdjustIndent(buf, 6);
+            if (virNetDevOpenvswitchPortFormat(def->data.bridge.ovsPort, buf) < 0)
+                return -1;
+            virBufferAdjustIndent(buf, -6);
+        }
         break;
 
     case VIR_DOMAIN_NET_TYPE_DIRECT:
@@ -10514,6 +10542,12 @@ virDomainNetDefFormat(virBufferPtr buf,
         if (def->data.bridge.ipaddr)
             virBufferAsprintf(buf, "      <ip address='%s'/>\n",
                               def->data.bridge.ipaddr);
+        if (def->data.bridge.ovsPort) {
+            virBufferAdjustIndent(buf, 6);
+            if (virNetDevOpenvswitchPortFormat(def->data.bridge.ovsPort, buf) < 0)
+                return -1;
+            virBufferAdjustIndent(buf, -6);
+        }
         break;
 
     case VIR_DOMAIN_NET_TYPE_SERVER:
@@ -13851,6 +13885,18 @@ virDomainNetGetActualBandwidth(virDomainNetDefPtr iface)
     return iface->bandwidth;
 }
 
+virNetDevOpenvswitchPortPtr
+virDomainNetGetActualOpenvswitchPortPtr(virDomainNetDefPtr iface)
+{
+    if (iface->type != VIR_DOMAIN_NET_TYPE_BRIDGE)
+        return NULL;
+    if (iface->data.bridge.ovsPort)
+        return iface->data.bridge.ovsPort;
+    if (!iface->data.network.actual)
+        return NULL;
+    return iface->data.network.actual->data.bridge.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 0a2795d..b7eb7d1 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 */
@@ -594,6 +595,7 @@ struct _virDomainActualNetDef {
     union {
         struct {
             char *brname;
+            virNetDevOpenvswitchPortPtr ovsPort;
         } bridge;
         struct {
             char *linkdev;
@@ -645,6 +647,7 @@ struct _virDomainNetDef {
         struct {
             char *brname;
             char *ipaddr;
+            virNetDevOpenvswitchPortPtr ovsPort;
         } bridge;
         struct {
             char *name;
@@ -1877,6 +1880,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..ddae3aa
--- /dev/null
+++ b/src/conf/netdev_openvswitch_conf.c
@@ -0,0 +1,94 @@
+/*
+ * 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 at nicira.com>
+ *     Kyle Mestery <kmestery at cisco.com>
+ *     Ansis Atteka <aatteka at nicira.com>
+ */
+
+#include <config.h>
+
+#include "netdev_openvswitch_conf.h"
+#include "virterror_internal.h"
+#include "memory.h"
+#include "uuid.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)
+{
+    char *InterfaceID = NULL;
+    virNetDevOpenvswitchPortPtr ovsPort = NULL;
+    xmlNodePtr cur = node->children;
+
+    if (VIR_ALLOC(ovsPort) < 0) {
+        virReportOOMError();
+        goto error;
+    }
+
+    while (cur != NULL) {
+        if (xmlStrEqual(cur->name, BAD_CAST "parameters")) {
+            InterfaceID = virXMLPropString(cur, "interfaceid");
+            break;
+        }
+        cur = cur->next;
+    }
+
+    if (InterfaceID == NULL || (strlen(InterfaceID) == 0)) {
+        // interfaceID does not have to be a UUID,
+        // but a UUID is a reasonable default
+        if (virUUIDGenerateStr(ovsPort->InterfaceID)) {
+            virNetDevError(VIR_ERR_XML_ERROR, "%s",
+                        _("cannot generate a random uuid for interfaceid"));
+            goto error;
+        }
+    } else {
+        if (virStrcpyStatic(ovsPort->InterfaceID, InterfaceID) == NULL) {
+            virNetDevError(VIR_ERR_XML_ERROR, "%s",
+                           _("InterfaceID parameter too long"));
+            goto error;
+        }
+    }
+
+cleanup:
+    return ovsPort;
+
+error:
+    VIR_FREE(ovsPort);
+    goto cleanup;
+}
+
+
+int
+virNetDevOpenvswitchPortFormat(virNetDevOpenvswitchPortPtr ovsPort,
+                            virBufferPtr buf)
+{
+    if (ovsPort == NULL)
+        return 0;
+
+    virBufferAsprintf(buf, "<virtualport type='openvswitch'>\n");
+    virBufferAsprintf(buf, "  <parameters interfaceid='%s'/>\n",
+                      ovsPort->InterfaceID);
+    virBufferAddLit(buf, "</virtualport>\n");
+    return 0;
+}
diff --git a/src/conf/netdev_openvswitch_conf.h b/src/conf/netdev_openvswitch_conf.h
new file mode 100644
index 0000000..fd8e079
--- /dev/null
+++ b/src/conf/netdev_openvswitch_conf.h
@@ -0,0 +1,39 @@
+/*
+ * 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 at nicira.com>
+ *     Kyle Mestery <kmestery at cisco.com>
+ *     Ansis Atteka <aatteka at 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 d6ad36c..0666d5c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -379,6 +379,7 @@ virDomainNetGetActualBridgeName;
 virDomainNetGetActualDirectDev;
 virDomainNetGetActualDirectMode;
 virDomainNetGetActualDirectVirtPortProfile;
+virDomainNetGetActualOpenvswitchPortPtr;
 virDomainNetGetActualType;
 virDomainNetIndexByMac;
 virDomainNetInsert;
@@ -738,6 +739,10 @@ virShrinkN;
 virNetDevBandwidthFormat;
 virNetDevBandwidthParse;
 
+# netdev_openvswitch_conf.h
+virNetDevOpenvswitchPortFormat;
+virNetDevOpenvswitchPortParse;
+
 
 # netdev_vportprofile_conf.h
 virNetDevVPortProfileFormat;
@@ -1145,6 +1150,7 @@ virGetHostUUID;
 virSetHostUUIDStr;
 virUUIDFormat;
 virUUIDGenerate;
+virUUIDGenerateStr;
 virUUIDParse;
 
 
@@ -1237,10 +1243,16 @@ virNetDevMacVLanCreateWithVPortProfile;
 virNetDevMacVLanDeleteWithVPortProfile;
 
 
+# virnetdevopenvswitch.h
+virNetDevOpenvswitchAddPort;
+virNetDevOpenvswitchDelPort;
+
+
 # virnetdevtap.h
 virNetDevTapCreate;
 virNetDevTapCreateInBridgePort;
 virNetDevTapDelete;
+virNetDevTapDeleteInBridgePort;
 
 
 # virnetdevveth.h
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index b712da4..1fab77a 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -56,6 +56,7 @@
 #include "domain_nwfilter.h"
 #include "network/bridge_driver.h"
 #include "virnetdev.h"
+#include "virnetdevtap.h"
 #include "virnodesuspend.h"
 #include "virtime.h"
 #include "virtypedparam.h"
@@ -1132,10 +1133,12 @@ static void lxcVmCleanup(lxc_driver_t *driver,
     priv->monitorWatch = -1;
 
     for (i = 0 ; i < vm->def->nnets ; i++) {
-        ignore_value(virNetDevSetOnline(vm->def->nets[i]->ifname, false));
-        ignore_value(virNetDevVethDelete(vm->def->nets[i]->ifname));
-
-        networkReleaseActualDevice(vm->def->nets[i]);
+        virDomainNetDefPtr iface = vm->def->nets[i];
+        ignore_value(virNetDevSetOnline(iface->ifname, false));
+        ignore_value(virNetDevVethDelete(iface->ifname));
+        ignore_value(virNetDevTapDeleteInBridgePort(iface->ifname,
+                       virDomainNetGetActualOpenvswitchPortPtr(iface)));
+        networkReleaseActualDevice(iface);
     }
 
     virDomainConfVMNWFilterTeardown(vm);
@@ -1377,8 +1380,12 @@ static int lxcSetupInterfaces(virConnectPtr conn,
 
 cleanup:
     if (ret != 0) {
-        for (i = 0 ; i < def->nnets ; i++)
-            networkReleaseActualDevice(def->nets[i]);
+        for (i = 0 ; i < def->nnets ; i++) {
+            virDomainNetDefPtr iface = def->nets[i];
+            ignore_value(virNetDevTapDeleteInBridgePort(iface->ifname,
+                           virDomainNetGetActualOpenvswitchPortPtr(iface)));
+            networkReleaseActualDevice(iface);
+        }
     }
     return ret;
 }
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 57ebb9f..1423d3f 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -1765,7 +1765,8 @@ 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 0e26df1..d6a81f1 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -247,7 +247,8 @@ 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,
+                             virDomainNetGetActualOpenvswitchPortPtr(net));
     virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0);
     if (err < 0) {
         if (template_ifname)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index b4870be..85a004d 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -40,6 +40,7 @@
 #include "qemu_cgroup.h"
 #include "locking/domain_lock.h"
 #include "network/bridge_driver.h"
+#include "virnetdevtap.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -837,7 +838,8 @@ cleanup:
 
         if (iface_connected)
             virDomainConfNWFilterTeardown(net);
-
+        ignore_value(virNetDevTapDeleteInBridgePort(net->ifname,
+                       virDomainNetGetActualOpenvswitchPortPtr(net)));
         networkReleaseActualDevice(net);
     }
 
@@ -1937,7 +1939,8 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver,
                                  detach->ifname);
         }
     }
-
+    ignore_value(virNetDevTapDeleteInBridgePort(detach->ifname,
+                   virDomainNetGetActualOpenvswitchPortPtr(detach)));
     networkReleaseActualDevice(detach);
     if (vm->def->nnets > 1) {
         memmove(vm->def->nets + i,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 2d92d66..14eeef8 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -62,6 +62,7 @@
 #include "network/bridge_driver.h"
 #include "uuid.h"
 #include "virtime.h"
+#include "virnetdevtap.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -3731,6 +3732,8 @@ void qemuProcessStop(struct qemud_driver *driver,
         /* release the physical device (or any other resources used by
          * this interface in the network driver
          */
+        ignore_value(virNetDevTapDeleteInBridgePort(net->ifname,
+                       virDomainNetGetActualOpenvswitchPortPtr(net)));
         networkReleaseActualDevice(net);
     }
 
diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c
index 316d558..b8610ea 100644
--- a/src/uml/uml_conf.c
+++ b/src/uml/uml_conf.c
@@ -142,7 +142,8 @@ 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,
+                       virDomainNetGetActualOpenvswitchPortPtr(net)) < 0) {
         if (template_ifname)
             VIR_FREE(net->ifname);
         goto error;
diff --git a/src/util/uuid.c b/src/util/uuid.c
index 23822ec..d8188b7 100644
--- a/src/util/uuid.c
+++ b/src/util/uuid.c
@@ -116,6 +116,25 @@ virUUIDGenerate(unsigned char *uuid)
 }
 
 /**
+ * virUUIDGenerateString:
+ * @uuid: string of VIR_UUID_STRING_BUFLEN characters to store the UUID
+ *
+ *
+ * Generates a randomized unique identifier
+ * Returns 0 in case of success and -1 in case of failure
+ */
+int
+virUUIDGenerateStr(char *uuidstr)
+{
+    unsigned char uuid[VIR_UUID_BUFLEN];
+
+    if (virUUIDGenerate(uuid) < 0)
+        return -1;
+    virUUIDFormat(uuid, uuidstr);
+    return 0;
+}
+
+/**
  * virUUIDParse:
  * @uuidstr: zero terminated string representation of the UUID
  * @uuid: array of VIR_UUID_BUFLEN bytes to store the raw UUID
diff --git a/src/util/uuid.h b/src/util/uuid.h
index 7dbfad5..1ae7efb 100644
--- a/src/util/uuid.h
+++ b/src/util/uuid.h
@@ -30,6 +30,7 @@ int virGetHostUUID(unsigned char *host_uuid) ATTRIBUTE_NONNULL(1);
 int virUUIDIsValid(unsigned char *uuid);
 
 int virUUIDGenerate(unsigned char *uuid);
+int virUUIDGenerateStr(char *struuid);
 
 int virUUIDParse(const char *uuidstr,
                  unsigned char *uuid)
diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c
new file mode 100644
index 0000000..c5bef8d
--- /dev/null
+++ b/src/util/virnetdevopenvswitch.c
@@ -0,0 +1,114 @@
+/*
+ * 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 at nicira.com>
+ *     Kyle Mestery <kmestery at cisco.com>
+ *     Ansis Atteka <aatteka at nicira.com>
+ */
+
+#include <config.h>
+
+#include "virnetdevopenvswitch.h"
+#include "command.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "ignore-value.h"
+#include "virmacaddr.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
+ *
+ * Add an interface to the OVS bridge
+ *
+ * Returns 0 in case of success or -1 in case of failure.
+ */
+int virNetDevOpenvswitchAddPort(const char *brname, const char *ifname,
+                                   const unsigned char *macaddr,
+                                   virNetDevOpenvswitchPortPtr ovsport)
+{
+    int ret = -1;
+    virCommandPtr cmd = NULL;
+    char macaddrstr[VIR_MAC_STRING_BUFLEN];
+    char *attachedmac_ex_id = NULL;
+    char *ifaceid_ex_id = NULL;
+
+    virMacAddrFormat(macaddr, macaddrstr);
+
+    if (virAsprintf(&attachedmac_ex_id, "external-ids:attached-mac=\"%s\"",
+                    macaddrstr) < 0)
+        goto cleanup;
+    if (virAsprintf(&ifaceid_ex_id, "external-ids:iface-id=\"%s\"",
+                    ovsport->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;
+}
+
+/**
+ * virNetDevOpenvswitchDelPort:
+ * @ifname: the network interface name
+ *
+ * Deletes an interface from a OVS bridge
+ *
+ * Returns 0 in case of success or -1 in case of failure.
+ */
+int virNetDevOpenvswitchDelPort(const char *ifname)
+{
+    int ret = -1;
+    virCommandPtr cmd = NULL;
+
+    cmd = virCommandNew(OVSVSCTL);
+    virCommandAddArgList(cmd, "--", "--if-exists", "del-port", ifname, NULL);
+
+    if (virCommandRun(cmd, NULL) < 0) {
+        virReportSystemError(VIR_ERR_INTERNAL_ERROR,
+                             _("Unable to delete port %s from OVS"), ifname);
+        goto cleanup;
+    }
+    ret = 0;
+
+    cleanup:
+        virCommandFree(cmd);
+        return ret;
+}
diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h
new file mode 100644
index 0000000..210546b
--- /dev/null
+++ b/src/util/virnetdevopenvswitch.h
@@ -0,0 +1,46 @@
+/*
+ * 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 at nicira.com>
+ *     Kyle Mestery <kmestery at cisco.com>
+ *     Ansis Atteka <aatteka at nicira.com>
+ */
+
+#ifndef __VIR_NETDEV_OPENVSWITCH_H__
+# define __VIR_NETDEV_OPENVSWITCH_H__
+
+# include "internal.h"
+# include "util.h"
+
+typedef struct _virNetDevOpenvswitchPort virNetDevOpenvswitchPort;
+typedef virNetDevOpenvswitchPort *virNetDevOpenvswitchPortPtr;
+struct _virNetDevOpenvswitchPort {
+    char InterfaceID[VIR_UUID_STRING_BUFLEN];
+};
+
+int virNetDevOpenvswitchAddPort(const char *brname,
+                                const char *ifname,
+                                const unsigned char *macaddr,
+                                virNetDevOpenvswitchPortPtr ovsport)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
+    ATTRIBUTE_RETURN_CHECK;
+
+int virNetDevOpenvswitchDelPort(const char *ifname)
+    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..975bb85 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
+ * @ovsport: Open vSwitch specific configuration
  *
  * 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,7 +267,8 @@ int virNetDevTapCreateInBridgePort(const char *brname,
                                    const unsigned char *macaddr,
                                    int vnet_hdr,
                                    bool up,
-                                   int *tapfd)
+                                   int *tapfd,
+                                   virNetDevOpenvswitchPortPtr ovsport)
 {
     if (virNetDevTapCreate(ifname, vnet_hdr, tapfd) < 0)
         return -1;
@@ -286,8 +289,13 @@ int virNetDevTapCreateInBridgePort(const char *brname,
     if (virNetDevSetMTUFromDevice(*ifname, brname) < 0)
         goto error;
 
-    if (virNetDevBridgeAddPort(brname, *ifname) < 0)
-        goto error;
+    if (ovsport) {
+        if (virNetDevOpenvswitchAddPort(brname, *ifname, macaddr, ovsport) < 0)
+            goto error;
+    } else {
+        if (virNetDevBridgeAddPort(brname, *ifname) < 0)
+            goto error;
+    }
 
     if (virNetDevSetOnline(*ifname, up) < 0)
         goto error;
@@ -299,3 +307,21 @@ int virNetDevTapCreateInBridgePort(const char *brname,
 
     return errno;
 }
+
+/**
+ * virNetDevTapDeleteInBridgePort:
+ * @ifname: the interface name (or name template)
+ * @ovsport: Open vSwitch specific configuration
+ *
+ * This function detaches tap device from a bridge.
+ *
+ * Returns 0 in case of success or -1 on failure
+ */
+int virNetDevTapDeleteInBridgePort(char *ifname,
+                                   virNetDevOpenvswitchPortPtr ovsport)
+{
+    int ret = 0;
+    if (ovsport)
+        ret = virNetDevOpenvswitchDelPort(ifname);
+    return ret;
+}
diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h
index fb35ac5..5b16570 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,8 +39,13 @@ int virNetDevTapCreateInBridgePort(const char *brname,
                                    const unsigned char *macaddr,
                                    int vnet_hdr,
                                    bool up,
-                                   int *tapfd)
+                                   int *tapfd,
+                                   virNetDevOpenvswitchPortPtr ovsport)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
     ATTRIBUTE_RETURN_CHECK;
 
+int virNetDevTapDeleteInBridgePort(char *ifname,
+                                   virNetDevOpenvswitchPortPtr ovsport)
+ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+
 #endif /* __VIR_NETDEV_TAP_H__ */
-- 
1.7.5.4




More information about the libvir-list mailing list