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
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
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@xxxxxxxxxx> + */ + +#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@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 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@xxxxxxxxxxx> + */ + +#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@xxxxxxxxxxx> + */ + +#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;
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list