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@xxxxxxxxxx> + * Kyle Mestery <kmestery@xxxxxxxxx> + * Ansis Atteka <aatteka@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + * Kyle Mestery <kmestery@xxxxxxxxx> + * Ansis Atteka <aatteka@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + * Kyle Mestery <kmestery@xxxxxxxxx> + * Ansis Atteka <aatteka@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + * Kyle Mestery <kmestery@xxxxxxxxx> + * Ansis Atteka <aatteka@xxxxxxxxxx> + */ + +#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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list