On 01/27/2012 05:58 AM, Dan Wendlandt wrote:
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...
).
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>
This is a good start!
It might be better to use the same virtualport element that is used for
the various macvtap flavors, with a different type attribute, which
would be used to determine which of attributes in the <parameters>
sub-element to use - more or less how kmestery suggested in his followup
proposing XML for network configuration. A consistency like this tends
to result in less new code / data structures.
(btw, you say that "interfaceid" is specific to openvswitch, but that's
a generic enough name that it might be useful for someone else. Or maybe
you could even re-use something from <virtualport>, maybe instanceid,
which is also unique per 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?
The ActualNetDef was invented as a way to retain the original config of
the interface at runtime, while also providing the details of what kind
of interface setup that config resulted in. So the NetDef might say the
interface type is "network", but the ActualNetDef would reflect that the
interface ended up using eth25 in direct (macvtap) private mode, for
example. The <actual> element is only used internally to keep track of
what resources are in use by a domain even in the case of libvirtd
restarting (this is stored in xml files in libvirt's "statusdir"), and
are never seen in the dumpxml returned by the libvirt public API, so you
won't find documentation for them in the public API docs.
In your case, until there is an openvswitch *network* type, the
ActualNetDef won't be used for openvswitch interfaces.
When there is an openvswitch network type, if an interface is of
type='network', then the qemu domain startup code will call
networkAllocateActualDevice(), which will look up the network, determine
its type, allocate the necessary resources, and fill in the ActualNetDef
to return to qemu. So, any resources that are specific to a particular
type of interface, or could be filled in from a portgroup entry (e.g.
bandwidth, virtualport) should also exist in the ActualNetDef, and a
helper function made that returns the value from the ActualNetDef if
it's there, or from the NetDef otherwise.
For example, a network that is forward mode='passthrough' (indicating
macvtap passthrough mode) may have a pool of devices for use by domains.
Each domain's config only says type='network' network name='mynet',
but
at connect time, networkAllocateActualDevice is called, which picks an
unused device and fills that into a new ActualNetDef (along with any
common virtualport/bandwidth info from an appropriate portgroup), and
returns that to the qemu driver. Now the qemu driver has the info that
it will use interface "ethxx" in macvtap passthrough mode (by looking at
the ActualNetDef), but the original config remains unspoiled.
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 <
http://www.nicira.com>
twitter: danwendlandt
~~~~~~~~~~~~~~~~~~~~~~~~~~~
ovs.diff
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");
you could just add an extra clause to the previous conditional. But
that's a detail for later...
} 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;
Again, I think I prefer the idea of re-using <virtualport> instead of
creating a new element type.
} 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;
+}
+
Right. Even though you claim you didn't understand it, and you wouldn't
*need* it right away, you've done a reasonable job of filling out the
actualnetdef for this new type :-)
/* 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;
If you know that the ovsPort will always be valid any time
type='openvswitch', it would make memory management/error recovery
simpler to just make this virNetDevOpenvswithcPort, rather than a
pointer to one. Normally a pointer to a struct is used if something is
optional (so NULL will indicate that it was missing from the config), or
if someone just has fun doing malloc/free calisthenics ;-)
+ } ovs;
} data;
virNetDevBandwidthPtr bandwidth;
};
@@ -628,6 +633,9 @@ struct _virDomainNetDef {
int mode; /* enum virMacvtapMode from util/macvtap.h */
virNetDevVPortProfilePtr virtPortProfile;
} direct;
+ struct {
+ virNetDevOpenvswitchPortPtr ovsPort;
Same here.
+ } 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(a)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(a)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__ */
For something this short, it may not be worth having an extra file
(requiring the extra export symbols, etc) - it could just be added to
domain_conf.h (of course someone else may be planning to split up
domain_conf.h as we speak, so...)
Of course, if you follow the advice of re-using virtualport for the
interfaceID, then you won't need this anyway.
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.
+ */
Actually you're returning -1 in case of failure. If you were going to
return errno, you should instead return -errno, which is a standard that
we're trying to adopt in all the libvirt code.
+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);
You'll need to use a different log function - virReportSystemError
expects its first arg to be a valid errno, but virCommandRun returns -1
on failure, and errno has already been reset by now.
+ 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)
I don't think I like putting something as high level as a NetDef in the
arg list of this low level utility function. All the existing parameters
are fairly generic, so the file could be easily transported to a
different project and used with little or no modification.
Instead, you might want to have something like this:
int virNetDevTapCreateInBridgePort(const char *brname,
int type;
const unsigned char *macaddr,
const char *interfaceID,
int vnet_hdr,
bool up,
int *tapfd)
Or alternately, keep the existing function clean, and write a new one using the same
building blocks.
{
+ 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)
Same here.
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
ATTRIBUTE_RETURN_CHECK;
--
libvir-list mailing list
libvir-list(a)redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list