This patch allows libvirt to add interfaces to already existing Open vSwitch bridges. The following syntax in domain XML file can 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 use 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> It is also possible to pass an optional profileid. To do that use following syntax: <interface type='bridge'> <source bridge='ovsbr'/> <mac address='00:55:1a:65:a2:8d'/> <virtualport type='openvswitch'> <parameters interfaceid='921a80cd-e6de-5a2e-db9c-ab27f15a6e1d' profileid='test-profile'/> </virtualport> </interface> To create Open vSwitch bridge install Open vSwitch and run the following command: ovs-vsctl add-br ovsbr --- configure.ac | 5 + src/Makefile.am | 1 + src/conf/domain_conf.c | 51 +++++++++++-- src/conf/domain_conf.h | 5 +- src/conf/netdev_vport_profile_conf.c | 47 +++++++++++- src/libvirt_private.syms | 7 ++- src/lxc/lxc_driver.c | 37 +++++++-- src/network/bridge_driver.c | 3 +- src/qemu/qemu_command.c | 5 +- src/qemu/qemu_hotplug.c | 17 ++++- src/qemu/qemu_migration.c | 4 +- src/qemu/qemu_process.c | 10 ++- src/uml/uml_conf.c | 3 +- src/util/virnetdevopenvswitch.c | 135 ++++++++++++++++++++++++++++++++++ src/util/virnetdevopenvswitch.h | 42 +++++++++++ src/util/virnetdevtap.c | 14 +++- src/util/virnetdevtap.h | 5 +- src/util/virnetdevvportprofile.c | 2 + src/util/virnetdevvportprofile.h | 7 ++- 19 files changed, 365 insertions(+), 35 deletions(-) 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..d5f52a0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -97,6 +97,7 @@ UTIL_SOURCES = \ util/virnetdevbandwidth.h util/virnetdevbandwidth.c \ util/virnetdevbridge.h util/virnetdevbridge.c \ util/virnetdevmacvlan.c util/virnetdevmacvlan.h \ + util/virnetdevopenvswitch.h util/virnetdevopenvswitch.c \ util/virnetdevtap.h util/virnetdevtap.c \ util/virnetdevveth.h util/virnetdevveth.c \ util/virnetdevvportprofile.h util/virnetdevvportprofile.c \ diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a09a506..5b5db43 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" @@ -951,6 +952,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); @@ -994,6 +996,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: @@ -3732,7 +3735,11 @@ virDomainActualNetDefParseXML(xmlNodePtr node, } if (actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE) { - actual->data.bridge.brname = virXPathString("string(./source[1]/@bridge)", ctxt); + xmlNodePtr virtPortNode = virXPathNode("./virtualport", ctxt); + if (virtPortNode && + (!(actual->data.bridge.ovsPort = + virNetDevVPortProfileParse(virtPortNode)))) + goto error; } else if (actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) { xmlNodePtr virtPortNode; @@ -3861,7 +3868,8 @@ virDomainNetDefParseXML(virCapsPtr caps, mode = virXMLPropString(cur, "mode"); } else if ((virtPort == NULL) && ((def->type == VIR_DOMAIN_NET_TYPE_DIRECT) || - (def->type == VIR_DOMAIN_NET_TYPE_NETWORK)) && + (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) || + (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE)) && xmlStrEqual(cur->name, BAD_CAST "virtualport")) { if (!(virtPort = virNetDevVPortProfileParse(cur))) goto error; @@ -4000,6 +4008,8 @@ virDomainNetDefParseXML(virCapsPtr caps, def->data.bridge.ipaddr = address; address = NULL; } + def->data.bridge.ovsPort = virtPort; + virtPort = NULL; break; case VIR_DOMAIN_NET_TYPE_CLIENT: @@ -10429,6 +10439,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 (virNetDevVPortProfileFormat(def->data.bridge.ovsPort, buf) < 0) + return -1; + virBufferAdjustIndent(buf, -6); + } break; case VIR_DOMAIN_NET_TYPE_DIRECT: @@ -10516,6 +10532,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 (virNetDevVPortProfileFormat(def->data.bridge.ovsPort, buf) < 0) + return -1; + virBufferAdjustIndent(buf, -6); + } break; case VIR_DOMAIN_NET_TYPE_SERVER: @@ -13832,15 +13854,27 @@ virDomainNetGetActualDirectMode(virDomainNetDefPtr iface) } virNetDevVPortProfilePtr -virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface) +virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface) { - if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT) + switch (iface->type) { + case VIR_DOMAIN_NET_TYPE_DIRECT: return iface->data.direct.virtPortProfile; - if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) - return NULL; - if (!iface->data.network.actual) + case VIR_DOMAIN_NET_TYPE_BRIDGE: + return iface->data.bridge.ovsPort; + case VIR_DOMAIN_NET_TYPE_NETWORK: + if (!iface->data.network.actual) + return NULL; + switch (iface->data.network.actual->type) { + case VIR_DOMAIN_NET_TYPE_DIRECT: + return iface->data.network.actual->data.direct.virtPortProfile; + case VIR_DOMAIN_NET_TYPE_BRIDGE: + return iface->data.network.actual->data.bridge.ovsPort; + default: + return NULL; + } + default: return NULL; - return iface->data.network.actual->data.direct.virtPortProfile; + } } virNetDevBandwidthPtr @@ -13853,7 +13887,6 @@ virDomainNetGetActualBandwidth(virDomainNetDefPtr iface) return iface->bandwidth; } - /* 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 * bounds. If force0 is TRUE, ii == 0, and there is no listen array, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8bb21cf..c4c3551 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 */ @@ -596,6 +597,7 @@ struct _virDomainActualNetDef { union { struct { char *brname; + virNetDevVPortProfilePtr ovsPort; } bridge; struct { char *linkdev; @@ -647,6 +649,7 @@ struct _virDomainNetDef { struct { char *brname; char *ipaddr; + virNetDevVPortProfilePtr ovsPort; } bridge; struct { char *name; @@ -1875,7 +1878,7 @@ const char *virDomainNetGetActualBridgeName(virDomainNetDefPtr iface); const char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface); int virDomainNetGetActualDirectMode(virDomainNetDefPtr iface); virNetDevVPortProfilePtr -virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface); +virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface); virNetDevBandwidthPtr virDomainNetGetActualBandwidth(virDomainNetDefPtr iface); diff --git a/src/conf/netdev_vport_profile_conf.c b/src/conf/netdev_vport_profile_conf.c index b48b2cb..205d674 100644 --- a/src/conf/netdev_vport_profile_conf.c +++ b/src/conf/netdev_vport_profile_conf.c @@ -35,7 +35,8 @@ VIR_ENUM_IMPL(virNetDevVPort, VIR_NETDEV_VPORT_PROFILE_LAST, "none", "802.1Qbg", - "802.1Qbh") + "802.1Qbh", + "openvswitch") virNetDevVPortProfilePtr @@ -47,6 +48,7 @@ virNetDevVPortProfileParse(xmlNodePtr node) char *virtPortTypeIDVersion = NULL; char *virtPortInstanceID = NULL; char *virtPortProfileID = NULL; + char *virtPortInterfaceID = NULL; virNetDevVPortProfilePtr virtPort = NULL; xmlNodePtr cur = node->children; @@ -76,7 +78,7 @@ virNetDevVPortProfileParse(xmlNodePtr node) virtPortTypeIDVersion = virXMLPropString(cur, "typeidversion"); virtPortInstanceID = virXMLPropString(cur, "instanceid"); virtPortProfileID = virXMLPropString(cur, "profileid"); - + virtPortInterfaceID = virXMLPropString(cur, "interfaceid"); break; } @@ -171,6 +173,33 @@ virNetDevVPortProfileParse(xmlNodePtr node) goto error; } break; + case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: + if (virtPortInterfaceID != NULL) { + if (virUUIDParse(virtPortInterfaceID, + virtPort->u.openvswitch.interfaceID)) { + virNetDevError(VIR_ERR_XML_ERROR, "%s", + _("cannot parse interfaceid parameter as a uuid")); + goto error; + } + } else { + if (virUUIDGenerate(virtPort->u.openvswitch.interfaceID)) { + virNetDevError(VIR_ERR_XML_ERROR, "%s", + _("cannot generate a random uuid for interfaceid")); + goto error; + } + } + /* profileid is not mandatory for Open vSwitch */ + if (virtPortProfileID != NULL) { + if (virStrcpyStatic(virtPort->u.openvswitch.profileID, + virtPortProfileID) == NULL) { + virNetDevError(VIR_ERR_XML_ERROR, "%s", + _("profileid parameter too long")); + goto error; + } + } else { + virtPort->u.openvswitch.profileID[0] = '\0'; + } + break; default: virNetDevError(VIR_ERR_XML_ERROR, @@ -225,6 +254,20 @@ virNetDevVPortProfileFormat(virNetDevVPortProfilePtr virtPort, virtPort->u.virtPort8021Qbh.profileID); break; + case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: + virUUIDFormat(virtPort->u.openvswitch.interfaceID, + uuidstr); + if (virtPort->u.openvswitch.profileID[0] == '\0') { + virBufferAsprintf(buf, " <parameters interfaceid='%s'/>\n", + uuidstr); + } else { + virBufferAsprintf(buf, " <parameters interfaceid='%s' " + "profileid='%s'/>\n", uuidstr, + virtPort->u.openvswitch.profileID); + } + + break; + default: virNetDevError(VIR_ERR_XML_ERROR, _("unexpected virtualport type %d"), virtPort->virtPortType); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0c22dec..ad5c7d3 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -378,7 +378,7 @@ virDomainNetGetActualBandwidth; virDomainNetGetActualBridgeName; virDomainNetGetActualDirectDev; virDomainNetGetActualDirectMode; -virDomainNetGetActualDirectVirtPortProfile; +virDomainNetGetActualVirtPortProfile; virDomainNetGetActualType; virDomainNetIndexByMac; virDomainNetInsert; @@ -1237,6 +1237,11 @@ virNetDevMacVLanCreateWithVPortProfile; virNetDevMacVLanDeleteWithVPortProfile; +# virnetdevopenvswitch.h +virNetDevOpenvswitchAddPort; +virNetDevOpenvswitchRemovePort; + + # virnetdevtap.h virNetDevTapCreate; virNetDevTapCreateInBridgePort; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index b712da4..17e8312 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" @@ -1105,6 +1106,7 @@ static void lxcVmCleanup(lxc_driver_t *driver, virCgroupPtr cgroup; int i; lxcDomainObjPrivatePtr priv = vm->privateData; + virNetDevVPortProfilePtr vport = NULL; /* now that we know it's stopped call the hook if present */ if (virHookPresent(VIR_HOOK_DRIVER_LXC)) { @@ -1132,10 +1134,15 @@ 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]; + vport = virDomainNetGetActualVirtPortProfile(iface); + ignore_value(virNetDevSetOnline(iface->ifname, false)); + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ignore_value(virNetDevOpenvswitchRemovePort( + virDomainNetGetActualBridgeName(iface), + iface->ifname)); + ignore_value(virNetDevVethDelete(iface->ifname)); + networkReleaseActualDevice(iface); } virDomainConfVMNWFilterTeardown(vm); @@ -1165,6 +1172,7 @@ static int lxcSetupInterfaceBridged(virConnectPtr conn, int ret = -1; char *parentVeth; char *containerVeth = NULL; + const virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(net); VIR_DEBUG("calling vethCreate()"); parentVeth = net->ifname; @@ -1186,7 +1194,11 @@ static int lxcSetupInterfaceBridged(virConnectPtr conn, if (virNetDevSetMAC(containerVeth, net->mac) < 0) goto cleanup; - if (virNetDevBridgeAddPort(brname, parentVeth) < 0) + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ret = virNetDevOpenvswitchAddPort(brname, parentVeth, net->mac, vport); + else + ret = virNetDevBridgeAddPort(brname, parentVeth); + if (ret < 0) goto cleanup; if (virNetDevSetOnline(parentVeth, true) < 0) @@ -1242,7 +1254,7 @@ static int lxcSetupInterfaceDirect(virConnectPtr conn, * and automagically dies when the container dies. So * we have no dev to perform disassociation with. */ - prof = virDomainNetGetActualDirectVirtPortProfile(net); + prof = virDomainNetGetActualVirtPortProfile(net); if (prof) { lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Unable to set port profile on direct interfaces")); @@ -1260,7 +1272,7 @@ static int lxcSetupInterfaceDirect(virConnectPtr conn, virDomainNetGetActualDirectDev(net), virDomainNetGetActualDirectMode(net), false, false, def->uuid, - virDomainNetGetActualDirectVirtPortProfile(net), + virDomainNetGetActualVirtPortProfile(net), &res_ifname, VIR_NETDEV_VPORT_PROFILE_OP_CREATE, driver->stateDir, @@ -1377,8 +1389,15 @@ 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]; + virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(iface); + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ignore_value(virNetDevOpenvswitchRemovePort( + virDomainNetGetActualBridgeName(iface), + iface->ifname)); + 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 1b92aa4..591e371 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -154,7 +154,7 @@ qemuPhysIfaceConnect(virDomainDefPtr def, virDomainNetGetActualDirectDev(net), virDomainNetGetActualDirectMode(net), true, vnet_hdr, def->uuid, - virDomainNetGetActualDirectVirtPortProfile(net), + virDomainNetGetActualVirtPortProfile(net), &res_ifname, vmop, driver->stateDir, virDomainNetGetActualBandwidth(net)); @@ -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, + virDomainNetGetActualVirtPortProfile(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..3b1dbbf 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 @@ -652,6 +653,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn, int vhostfd = -1; char *nicstr = NULL; char *netstr = NULL; + virNetDevVPortProfilePtr vport = NULL; int ret = -1; virDomainDevicePCIAddress guestAddr; int vlan; @@ -838,6 +840,12 @@ cleanup: if (iface_connected) virDomainConfNWFilterTeardown(net); + vport = virDomainNetGetActualVirtPortProfile(net); + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ignore_value(virNetDevOpenvswitchRemovePort( + virDomainNetGetActualBridgeName(net), + net->ifname)); + networkReleaseActualDevice(net); } @@ -1833,6 +1841,7 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver, qemuDomainObjPrivatePtr priv = vm->privateData; int vlan; char *hostnet_name = NULL; + virNetDevVPortProfilePtr vport = NULL; for (i = 0 ; i < vm->def->nnets ; i++) { virDomainNetDefPtr net = vm->def->nets[i]; @@ -1923,7 +1932,7 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver, detach->ifname, detach->mac, virDomainNetGetActualDirectDev(detach), virDomainNetGetActualDirectMode(detach), - virDomainNetGetActualDirectVirtPortProfile(detach), + virDomainNetGetActualVirtPortProfile(detach), driver->stateDir)); VIR_FREE(detach->ifname); } @@ -1938,6 +1947,12 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver, } } + vport = virDomainNetGetActualVirtPortProfile(detach); + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ignore_value(virNetDevOpenvswitchRemovePort( + virDomainNetGetActualBridgeName(detach), + detach->ifname)); + networkReleaseActualDevice(detach); if (vm->def->nnets > 1) { memmove(vm->def->nets + i, diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 12cfbde..a513b3c 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2563,7 +2563,7 @@ qemuMigrationVPAssociatePortProfiles(virDomainDefPtr def) { net = def->nets[i]; if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) { if (virNetDevVPortProfileAssociate(net->ifname, - virDomainNetGetActualDirectVirtPortProfile(net), + virDomainNetGetActualVirtPortProfile(net), net->mac, virDomainNetGetActualDirectDev(net), def->uuid, @@ -2580,7 +2580,7 @@ err_exit: net = def->nets[i]; if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) { ignore_value(virNetDevVPortProfileDisassociate(net->ifname, - virDomainNetGetActualDirectVirtPortProfile(net), + virDomainNetGetActualVirtPortProfile(net), net->mac, virDomainNetGetActualDirectDev(net), VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_FINISH)); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 2d92d66..9bc5436 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 @@ -3604,6 +3605,7 @@ void qemuProcessStop(struct qemud_driver *driver, qemuDomainObjPrivatePtr priv = vm->privateData; virErrorPtr orig_err; virDomainDefPtr def; + virNetDevVPortProfilePtr vport = NULL; int i; int logfile = -1; char *timestamp; @@ -3724,13 +3726,19 @@ void qemuProcessStop(struct qemud_driver *driver, net->ifname, net->mac, virDomainNetGetActualDirectDev(net), virDomainNetGetActualDirectMode(net), - virDomainNetGetActualDirectVirtPortProfile(net), + virDomainNetGetActualVirtPortProfile(net), driver->stateDir)); VIR_FREE(net->ifname); } /* release the physical device (or any other resources used by * this interface in the network driver */ + vport = virDomainNetGetActualVirtPortProfile(net); + if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) + ignore_value(virNetDevOpenvswitchRemovePort( + virDomainNetGetActualBridgeName(net), + net->ifname)); + networkReleaseActualDevice(net); } diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c index 316d558..8c17578 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, + virDomainNetGetActualVirtPortProfile(net)) < 0) { if (template_ifname) VIR_FREE(net->ifname); goto error; diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c new file mode 100644 index 0000000..24a335a --- /dev/null +++ b/src/util/virnetdevopenvswitch.c @@ -0,0 +1,135 @@ +/* + * 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 + * @ovsport: the ovs specific fields + * + * 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, + virNetDevVPortProfilePtr ovsport) +{ + int ret = -1; + virCommandPtr cmd = NULL; + char macaddrstr[VIR_MAC_STRING_BUFLEN]; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + char *attachedmac_ex_id = NULL; + char *ifaceid_ex_id = NULL; + char *profile_ex_id = NULL; + + virMacAddrFormat(macaddr, macaddrstr); + virUUIDFormat(ovsport->u.openvswitch.interfaceID, uuidstr); + + if (virAsprintf(&attachedmac_ex_id, "external-ids:attached-mac=\"%s\"", + macaddrstr) < 0) + goto cleanup; + if (virAsprintf(&ifaceid_ex_id, "external-ids:iface-id=\"%s\"", + uuidstr) < 0) + goto cleanup; + if (ovsport->u.openvswitch.profileID[0] != '\0') { + if (virAsprintf(&profile_ex_id, "external-ids:port-profile=\"%s\"", + ovsport->u.openvswitch.profileID) < 0) + goto cleanup; + } + + cmd = virCommandNew(OVSVSCTL); + if (ovsport->u.openvswitch.profileID[0] == '\0') { + 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); + } else { + virCommandAddArgList(cmd, "--", "--may-exist", "add-port", + brname, ifname, + "--", "set", "Interface", ifname, attachedmac_ex_id, + "--", "set", "Interface", ifname, ifaceid_ex_id, + "--", "set", "Interface", ifname, profile_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); + VIR_FREE(profile_ex_id); + virCommandFree(cmd); + return ret; +} + +/** + * virNetDevOpenvswitchRemovePort: + * @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 virNetDevOpenvswitchRemovePort(const char *brname ATTRIBUTE_UNUSED, 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..bca4c3e --- /dev/null +++ b/src/util/virnetdevopenvswitch.h @@ -0,0 +1,42 @@ +/* + * 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" +# include "virnetdevvportprofile.h" + + +int virNetDevOpenvswitchAddPort(const char *brname, + const char *ifname, + const unsigned char *macaddr, + virNetDevVPortProfilePtr ovsport) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) + ATTRIBUTE_RETURN_CHECK; + +int virNetDevOpenvswitchRemovePort(const char *brname, const char *ifname) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + +#endif /* __VIR_NETDEV_OPENVSWITCH_H__ */ diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c index 2ed53c6..cd1d4c1 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, + virNetDevVPortProfilePtr 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; diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h index fb35ac5..ee159f7 100644 --- a/src/util/virnetdevtap.h +++ b/src/util/virnetdevtap.h @@ -24,6 +24,7 @@ # define __VIR_NETDEV_TAP_H__ # include "internal.h" +# include "virnetdevvportprofile.h" int virNetDevTapCreate(char **ifname, int vnet_hdr, @@ -38,8 +39,10 @@ int virNetDevTapCreateInBridgePort(const char *brname, const unsigned char *macaddr, int vnet_hdr, bool up, - int *tapfd) + int *tapfd, + virNetDevVPortProfilePtr ovsport) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK; + #endif /* __VIR_NETDEV_TAP_H__ */ diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c index faadc3a..67fd7bc 100644 --- a/src/util/virnetdevvportprofile.c +++ b/src/util/virnetdevvportprofile.c @@ -968,6 +968,7 @@ virNetDevVPortProfileAssociate(const char *macvtap_ifname, switch (virtPort->virtPortType) { case VIR_NETDEV_VPORT_PROFILE_NONE: + case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: case VIR_NETDEV_VPORT_PROFILE_LAST: break; @@ -1027,6 +1028,7 @@ virNetDevVPortProfileDisassociate(const char *macvtap_ifname, switch (virtPort->virtPortType) { case VIR_NETDEV_VPORT_PROFILE_NONE: + case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: case VIR_NETDEV_VPORT_PROFILE_LAST: break; diff --git a/src/util/virnetdevvportprofile.h b/src/util/virnetdevvportprofile.h index 7a8d81f..ec2d06d 100644 --- a/src/util/virnetdevvportprofile.h +++ b/src/util/virnetdevvportprofile.h @@ -35,6 +35,7 @@ enum virNetDevVPortProfile { VIR_NETDEV_VPORT_PROFILE_NONE, VIR_NETDEV_VPORT_PROFILE_8021QBG, VIR_NETDEV_VPORT_PROFILE_8021QBH, + VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH, VIR_NETDEV_VPORT_PROFILE_LAST, }; @@ -54,7 +55,7 @@ enum virNetDevVPortProfileOp { }; VIR_ENUM_DECL(virNetDevVPortProfileOp) -/* profile data for macvtap (VEPA) */ +/* profile data for macvtap (VEPA) and openvswitch */ typedef struct _virNetDevVPortProfile virNetDevVPortProfile; typedef virNetDevVPortProfile *virNetDevVPortProfilePtr; struct _virNetDevVPortProfile { @@ -69,6 +70,10 @@ struct _virNetDevVPortProfile { struct { char profileID[LIBVIRT_IFLA_VF_PORT_PROFILE_MAX]; } virtPort8021Qbh; + struct { + unsigned char interfaceID[VIR_UUID_BUFLEN]; + char profileID[LIBVIRT_IFLA_VF_PORT_PROFILE_MAX]; + } openvswitch; } u; }; -- 1.7.5.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list