<br><br><div class="gmail_quote">On Mon, Feb 13, 2012 at 9:56 PM, Laine Stump <span dir="ltr"><<a href="mailto:laine@laine.org" target="_blank">laine@laine.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div>On 02/10/2012 04:09 PM, Ansis Atteka wrote:<br>
> This patch allows libvirt to add interfaces to already<br>
> existing Open vSwitch bridges. The following syntax in<br>
> domain XML file can be used:<br>
><br>
>     <interface type='bridge'><br>
>       <mac address='52:54:00:d0:3f:f2'/><br>
>       <source bridge='ovsbr'/><br>
>       <virtualport type='openvswitch'><br>
>         <parameters interfaceid='921a80cd-e6de-5a2e-db9c-ab27f15a6e1d'/><br>
>       </virtualport><br>
>       <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/><br>
>     </interface><br>
><br>
> or if libvirt should auto-generate the interfaceid use<br>
> following syntax:<br>
><br>
>     <interface type='bridge'><br>
>       <mac address='52:54:00:d0:3f:f2'/><br>
>       <source bridge='ovsbr'/><br>
>       <virtualport type='openvswitch'><br>
>       </virtualport><br>
<br>
</div>Everything in this patch looks really good - it could be pushed with<br>
just a few nits fixed (detailed later on).<br>
<br>
This bit right above which demonstrates a case where interfaceid will be<br>
autogenerated is the only concern I have left - as I mentioned before,<br>
although you're doing the auto-generate of the interfaceid exactly the<br>
same as is done for instanceid (and also uuid and macaddr), this is<br>
going to cause a problem when we get to defining networks for<br>
openvswitch. In that case, to specify that a network uses openvswitch,<br>
we'll want to do this:<br>
<br>
   <network><br>
     <name>ovs-network</name><br>
     <forward mode='bridge'/><br>
     <bridge name='ovbr0'/><br>
     <virtualport type='openvswitch'><br>
     </virtualport><br>
   </network><br></blockquote><div>I haven't put a lot of thought into this, but I guess once we get to<br>networks, we might consider to use following syntax in the network<br>XML:<br><br>      <network><br>
        <name>ovs-network</name><br>        <forward mode='bridge'/><br>        <bridge name='ovbr0' type='[openvswitch|linux|default]' /><br>      </network><br><br>This would ensure that switch from Linux to OVS bridge networks<br>
would not require any changes to existing XML config.<br><br>Anyway this is something that would require more careful thinking.<br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<br>
But because an interfaceid is auto-generated by the parser when one<br>
isn't given, and a common parser function for virtualport is used by the<br>
domain and network parsers, this will result in an interfaceid being<br>
filled in when the network is defined, which makes no sense for a<br>
<network> definition, since each interface that uses this network is<br>
supposed to have its own unique interfaceid. However, the code decides<br>
that the bridge is an openvswitch by looking for the presence of a<br>
virtualport of type='openvswitch'.<br>
<br>
I can see a couple ways out of this:<br>
<br>
1) we could add an arg to virNetDevVPortProfileParse:<br>
<br>
virNetDevVPortProfilePtr<br>
virNetDevVPortProfileParse(xmlNodePtr node, unsigned int flags);<br>
<br>
with a possible flag being VIR_NETDEV_VPORT_AUTOGEN<br>
<br>
If that flag is given, interfaceid and instanceid will be auto-generated<br>
if necessary during parse, otherwise they will be left blank.<br>
<br>
2) Rather than deciding which type of bridge we're dealing with by<br>
looking at the config, we could try to do it by direct examination of<br>
the system.<br></blockquote><div>The first thing that comes into my mind would be to use SIOCETHTOOL<br>ioctl call with cmd==ETHTOOL_GDRVINFO. Then the bridge's driver name<br>would be either "linux" or "openvswitch".<br>
</div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<br>
Something along the lines of (2) may be a good idea anyway, especially<br>
if we think about the idea of a guest that might migrate between a host<br>
that has openvswitch and one that doesn't, with the restriction that we<br>
want a persistent interfaceid for the times it's connected to an<br>
openvswitch. In that case, the interface definition would look like:<br>
<br>
    <interface type='network'><br>
      <source network='bridged-network'><br>
      <mac address='00:11:22:33:44:55'/><br>
      <virtualport type='openvswitch'/><br>
<div>        <parameters interfaceid='921a80cd-e6de-5a2e-db9c-ab27f15a6e1d'<br>
profileid='test-profile'/><br>
      </virtualport><br>
   </interface><br>
<br>
</div>(you would need to specify the virtualport in the <interface> so that it<br>
would always be the same). Of course if you migrated to a machine where<br>
bridged-network happened to describe an openvswitch, this would<br>
coincidentally work correctly. But if bridged-network described a<br>
standard linux bridge, we would be trying to do openvswitch commands on<br>
a device that wasn't an openvswitch!<br>
<br>
So, I'm wondering if there's a simple way to confirm that a device<br>
*isn't* an openvswitch without relying on calling any utilities that are<br>
part of the ovs package.<br>
<br>
I'm thinking it may be okay to push this code more or less as-is though,<br>
since it works properly for the case of straight <interface<br>
type='bridge'/>, and the changes I'm talking about are refinements that<br>
are backward compatible, and are only necessary when we add support for<br>
<network>s that use openvswitch. Any other libvirt regulars have an<br>
opinion on this?<br>
<div><div><br>
<br>
>       <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/><br>
>     </interface><br>
><br>
> It is also possible to pass an optional profileid. To do that<br>
> use following syntax:<br>
><br>
>    <interface type='bridge'><br>
>      <source bridge='ovsbr'/><br>
>      <mac address='00:55:1a:65:a2:8d'/><br>
>      <virtualport type='openvswitch'><br>
>        <parameters interfaceid='921a80cd-e6de-5a2e-db9c-ab27f15a6e1d' profileid='test-profile'/><br>
>      </virtualport><br>
>    </interface><br>
><br>
> To create Open vSwitch bridge install Open vSwitch and<br>
> run the following command:<br>
><br>
>     ovs-vsctl add-br ovsbr<br>
> ---<br>
>  <a href="http://configure.ac" target="_blank">configure.ac</a>                         |    5 +<br>
>  src/Makefile.am                      |    1 +<br>
>  src/conf/domain_conf.c               |   51 +++++++++++--<br>
>  src/conf/domain_conf.h               |    5 +-<br>
>  src/conf/netdev_vport_profile_conf.c |   47 +++++++++++-<br>
>  src/libvirt_private.syms             |    7 ++-<br>
>  src/lxc/lxc_driver.c                 |   37 +++++++--<br>
>  src/network/bridge_driver.c          |    3 +-<br>
>  src/qemu/qemu_command.c              |    5 +-<br>
>  src/qemu/qemu_hotplug.c              |   17 ++++-<br>
>  src/qemu/qemu_migration.c            |    4 +-<br>
>  src/qemu/qemu_process.c              |   10 ++-<br>
>  src/uml/uml_conf.c                   |    3 +-<br>
>  src/util/virnetdevopenvswitch.c      |  135 ++++++++++++++++++++++++++++++++++<br>
>  src/util/virnetdevopenvswitch.h      |   42 +++++++++++<br>
>  src/util/virnetdevtap.c              |   14 +++-<br>
>  src/util/virnetdevtap.h              |    5 +-<br>
>  src/util/virnetdevvportprofile.c     |    2 +<br>
>  src/util/virnetdevvportprofile.h     |    7 ++-<br>
>  19 files changed, 365 insertions(+), 35 deletions(-)<br>
>  create mode 100644 src/util/virnetdevopenvswitch.c<br>
>  create mode 100644 src/util/virnetdevopenvswitch.h<br>
><br>
> diff --git a/<a href="http://configure.ac" target="_blank">configure.ac</a> b/<a href="http://configure.ac" target="_blank">configure.ac</a><br>
> index 9fb7bfc..dca178f 100644<br>
> --- a/<a href="http://configure.ac" target="_blank">configure.ac</a><br>
> +++ b/<a href="http://configure.ac" target="_blank">configure.ac</a><br>
> @@ -213,6 +213,8 @@ AC_PATH_PROG([UDEVSETTLE], [udevsettle], [],<br>
>       [/sbin:/usr/sbin:/usr/local/sbin:$PATH])<br>
>  AC_PATH_PROG([MODPROBE], [modprobe], [],<br>
>       [/sbin:/usr/sbin:/usr/local/sbin:$PATH])<br>
> +AC_PATH_PROG([OVSVSCTL], [ovs-vsctl], [ovs-vsctl],<br>
> +     [/sbin:/usr/sbin:/usr/local/sbin:$PATH])<br>
><br>
>  AC_DEFINE_UNQUOTED([DNSMASQ],["$DNSMASQ"],<br>
>          [Location or name of the dnsmasq program])<br>
> @@ -220,6 +222,9 @@ AC_DEFINE_UNQUOTED([RADVD],["$RADVD"],<br>
>          [Location or name of the radvd program])<br>
>  AC_DEFINE_UNQUOTED([TC],["$TC"],<br>
>          [Location or name of the tc profram (see iproute2)])<br>
> +AC_DEFINE_UNQUOTED([OVSVSCTL],["$OVSVSCTL"],<br>
> +        [Location or name of the ovs-vsctl program])<br>
> +<br>
>  if test -n "$UDEVADM"; then<br>
>    AC_DEFINE_UNQUOTED([UDEVADM],["$UDEVADM"],<br>
>          [Location or name of the udevadm program])<br>
> diff --git a/src/Makefile.am b/src/Makefile.am<br>
> index a3dd847..d5f52a0 100644<br>
> --- a/src/Makefile.am<br>
> +++ b/src/Makefile.am<br>
> @@ -97,6 +97,7 @@ UTIL_SOURCES =                                                      \<br>
>               util/virnetdevbandwidth.h util/virnetdevbandwidth.c \<br>
>               util/virnetdevbridge.h util/virnetdevbridge.c   \<br>
>               util/virnetdevmacvlan.c util/virnetdevmacvlan.h \<br>
> +             util/virnetdevopenvswitch.h util/virnetdevopenvswitch.c \<br>
>               util/virnetdevtap.h util/virnetdevtap.c         \<br>
>               util/virnetdevveth.h util/virnetdevveth.c \<br>
>               util/virnetdevvportprofile.h util/virnetdevvportprofile.c \<br>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c<br>
> index a09a506..5b5db43 100644<br>
> --- a/src/conf/domain_conf.c<br>
> +++ b/src/conf/domain_conf.c<br>
> @@ -31,6 +31,7 @@<br>
>  #include <sys/time.h><br>
>  #include <strings.h><br>
><br>
> +#include "internal.h"<br>
>  #include "virterror_internal.h"<br>
>  #include "datatypes.h"<br>
>  #include "domain_conf.h"<br>
> @@ -951,6 +952,7 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def)<br>
>      switch (def->type) {<br>
>      case VIR_DOMAIN_NET_TYPE_BRIDGE:<br>
>          VIR_FREE(def->data.bridge.brname);<br>
> +        VIR_FREE(def->data.bridge.ovsPort);<br>
<br>
</div></div>We should change all occurrences of ovsPort to virtPortProfile for<br>
consistency, and to allow for future use of the portprofile here for<br>
other non-ovs scenarios.<br>
<div><div><br>
>          break;<br>
>      case VIR_DOMAIN_NET_TYPE_DIRECT:<br>
>          VIR_FREE(def->data.direct.linkdev);<br>
> @@ -994,6 +996,7 @@ void virDomainNetDefFree(virDomainNetDefPtr def)<br>
>      case VIR_DOMAIN_NET_TYPE_BRIDGE:<br>
>          VIR_FREE(def->data.bridge.brname);<br>
>          VIR_FREE(def->data.bridge.ipaddr);<br>
> +        VIR_FREE(def->data.bridge.ovsPort);<br>
>          break;<br>
><br>
>      case VIR_DOMAIN_NET_TYPE_INTERNAL:<br>
> @@ -3732,7 +3735,11 @@ virDomainActualNetDefParseXML(xmlNodePtr node,<br>
>      }<br>
><br>
>      if (actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {<br>
> -        actual->data.bridge.brname = virXPathString("string(./source[1]/@bridge)", ctxt);<br>
> +        xmlNodePtr virtPortNode = virXPathNode("./virtualport", ctxt);<br>
> +        if (virtPortNode &&<br>
> +            (!(actual->data.bridge.ovsPort =<br>
> +               virNetDevVPortProfileParse(virtPortNode))))<br>
> +            goto error;<br>
>      } else if (actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {<br>
>          xmlNodePtr virtPortNode;<br>
><br>
> @@ -3861,7 +3868,8 @@ virDomainNetDefParseXML(virCapsPtr caps,<br>
>                  mode = virXMLPropString(cur, "mode");<br>
>              } else if ((virtPort == NULL) &&<br>
>                         ((def->type == VIR_DOMAIN_NET_TYPE_DIRECT) ||<br>
> -                        (def->type == VIR_DOMAIN_NET_TYPE_NETWORK)) &&<br>
> +                        (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) ||<br>
> +                        (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE)) &&<br>
>                         xmlStrEqual(cur->name, BAD_CAST "virtualport")) {<br>
>                  if (!(virtPort = virNetDevVPortProfileParse(cur)))<br>
>                      goto error;<br>
> @@ -4000,6 +4008,8 @@ virDomainNetDefParseXML(virCapsPtr caps,<br>
>              def->data.bridge.ipaddr = address;<br>
>              address = NULL;<br>
>          }<br>
> +        def->data.bridge.ovsPort = virtPort;<br>
> +        virtPort = NULL;<br>
>          break;<br>
><br>
>      case VIR_DOMAIN_NET_TYPE_CLIENT:<br>
> @@ -10429,6 +10439,12 @@ virDomainActualNetDefFormat(virBufferPtr buf,<br>
>      case VIR_DOMAIN_NET_TYPE_BRIDGE:<br>
>          virBufferEscapeString(buf, "        <source bridge='%s'/>\n",<br>
>                                def->data.bridge.brname);<br>
> +        if (def->data.bridge.ovsPort) {<br>
> +            virBufferAdjustIndent(buf, 6);<br>
> +            if (virNetDevVPortProfileFormat(def->data.bridge.ovsPort, buf) < 0)<br>
> +                return -1;<br>
> +            virBufferAdjustIndent(buf, -6);<br>
> +        }<br>
>          break;<br>
><br>
>      case VIR_DOMAIN_NET_TYPE_DIRECT:<br>
> @@ -10516,6 +10532,12 @@ virDomainNetDefFormat(virBufferPtr buf,<br>
>          if (def->data.bridge.ipaddr)<br>
>              virBufferAsprintf(buf, "      <ip address='%s'/>\n",<br>
>                                def->data.bridge.ipaddr);<br>
> +        if (def->data.bridge.ovsPort) {<br>
> +            virBufferAdjustIndent(buf, 6);<br>
> +            if (virNetDevVPortProfileFormat(def->data.bridge.ovsPort, buf) < 0)<br>
> +                return -1;<br>
> +            virBufferAdjustIndent(buf, -6);<br>
> +        }<br>
>          break;<br>
><br>
>      case VIR_DOMAIN_NET_TYPE_SERVER:<br>
> @@ -13832,15 +13854,27 @@ virDomainNetGetActualDirectMode(virDomainNetDefPtr iface)<br>
>  }<br>
><br>
>  virNetDevVPortProfilePtr<br>
> -virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface)<br>
> +virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface)<br>
<br>
<br>
</div></div>In hindsight, renaming this function would have been better done in a<br>
separate pre-requisite patch, just to avoid clutter in this patch.<br>
<div><div><br>
<br>
>  {<br>
> -    if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)<br>
> +    switch (iface->type) {<br>
> +    case VIR_DOMAIN_NET_TYPE_DIRECT:<br>
>          return iface->data.direct.virtPortProfile;<br>
> -    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)<br>
> -        return NULL;<br>
> -    if (!iface->data.network.actual)<br>
> +    case VIR_DOMAIN_NET_TYPE_BRIDGE:<br>
> +        return iface->data.bridge.ovsPort;<br>
> +    case VIR_DOMAIN_NET_TYPE_NETWORK:<br>
> +        if (!iface->data.network.actual)<br>
> +            return NULL;<br>
> +        switch (iface->data.network.actual->type) {<br>
> +        case VIR_DOMAIN_NET_TYPE_DIRECT:<br>
> +            return iface->data.network.actual->data.direct.virtPortProfile;<br>
> +        case VIR_DOMAIN_NET_TYPE_BRIDGE:<br>
> +            return iface->data.network.actual->data.bridge.ovsPort;<br>
> +        default:<br>
> +            return NULL;<br>
> +        }<br>
> +    default:<br>
>          return NULL;<br>
> -    return iface->data.network.actual->data.direct.virtPortProfile;<br>
> +    }<br>
>  }<br>
><br>
>  virNetDevBandwidthPtr<br>
> @@ -13853,7 +13887,6 @@ virDomainNetGetActualBandwidth(virDomainNetDefPtr iface)<br>
>      return iface->bandwidth;<br>
>  }<br>
><br>
> -<br>
<br>
</div></div>stray extra whitespace change...<br>
<div><br>
>  /* Return listens[ii] from the appropriate union for the graphics<br>
>   * type, or NULL if this is an unsuitable type, or the index is out of<br>
>   * bounds. If force0 is TRUE, ii == 0, and there is no listen array,<br>
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h<br>
> index 8bb21cf..c4c3551 100644<br>
> --- a/src/conf/domain_conf.h<br>
> +++ b/src/conf/domain_conf.h<br>
> @@ -41,6 +41,7 @@<br>
>  # include "virnetdevmacvlan.h"<br>
>  # include "sysinfo.h"<br>
>  # include "virnetdevvportprofile.h"<br>
> +# include "virnetdevopenvswitch.h"<br>
>  # include "virnetdevbandwidth.h"<br>
><br>
>  /* Different types of hypervisor */<br>
> @@ -596,6 +597,7 @@ struct _virDomainActualNetDef {<br>
>      union {<br>
>          struct {<br>
>              char *brname;<br>
> +            virNetDevVPortProfilePtr ovsPort;<br>
<br>
<br>
</div>These should be named the same as they are in the existing cases<br>
(virtPortProfile), since there may be other uses for a virtPortProfile<br>
on a bridge aside from openvswitch.<br>
<div><br>
<br>
>          } bridge;<br>
>          struct {<br>
>              char *linkdev;<br>
> @@ -647,6 +649,7 @@ struct _virDomainNetDef {<br>
>          struct {<br>
>              char *brname;<br>
>              char *ipaddr;<br>
> +            virNetDevVPortProfilePtr ovsPort;<br>
<br>
</div>Likewise.<br>
<div><div><br>
>          } bridge;<br>
>          struct {<br>
>              char *name;<br>
> @@ -1875,7 +1878,7 @@ const char *virDomainNetGetActualBridgeName(virDomainNetDefPtr iface);<br>
>  const char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface);<br>
>  int virDomainNetGetActualDirectMode(virDomainNetDefPtr iface);<br>
>  virNetDevVPortProfilePtr<br>
> -virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface);<br>
> +virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface);<br>
>  virNetDevBandwidthPtr<br>
>  virDomainNetGetActualBandwidth(virDomainNetDefPtr iface);<br>
><br>
> diff --git a/src/conf/netdev_vport_profile_conf.c b/src/conf/netdev_vport_profile_conf.c<br>
> index b48b2cb..205d674 100644<br>
> --- a/src/conf/netdev_vport_profile_conf.c<br>
> +++ b/src/conf/netdev_vport_profile_conf.c<br>
> @@ -35,7 +35,8 @@<br>
>  VIR_ENUM_IMPL(virNetDevVPort, VIR_NETDEV_VPORT_PROFILE_LAST,<br>
>                "none",<br>
>                "802.1Qbg",<br>
> -              "802.1Qbh")<br>
> +              "802.1Qbh",<br>
> +              "openvswitch")<br>
><br>
><br>
>  virNetDevVPortProfilePtr<br>
> @@ -47,6 +48,7 @@ virNetDevVPortProfileParse(xmlNodePtr node)<br>
>      char *virtPortTypeIDVersion = NULL;<br>
>      char *virtPortInstanceID = NULL;<br>
>      char *virtPortProfileID = NULL;<br>
> +    char *virtPortInterfaceID = NULL;<br>
>      virNetDevVPortProfilePtr virtPort = NULL;<br>
>      xmlNodePtr cur = node->children;<br>
><br>
> @@ -76,7 +78,7 @@ virNetDevVPortProfileParse(xmlNodePtr node)<br>
>              virtPortTypeIDVersion = virXMLPropString(cur, "typeidversion");<br>
>              virtPortInstanceID = virXMLPropString(cur, "instanceid");<br>
>              virtPortProfileID = virXMLPropString(cur, "profileid");<br>
> -<br>
> +            virtPortInterfaceID = virXMLPropString(cur, "interfaceid");<br>
>              break;<br>
>          }<br>
><br>
> @@ -171,6 +173,33 @@ virNetDevVPortProfileParse(xmlNodePtr node)<br>
>              goto error;<br>
>          }<br>
>          break;<br>
> +    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:<br>
> +        if (virtPortInterfaceID != NULL) {<br>
> +            if (virUUIDParse(virtPortInterfaceID,<br>
> +                             virtPort->u.openvswitch.interfaceID)) {<br>
> +                virNetDevError(VIR_ERR_XML_ERROR, "%s",<br>
> +                                     _("cannot parse interfaceid parameter as a uuid"));<br>
> +                goto error;<br>
> +            }<br>
> +        } else {<br>
> +            if (virUUIDGenerate(virtPort->u.openvswitch.interfaceID)) {<br>
> +                virNetDevError(VIR_ERR_XML_ERROR, "%s",<br>
> +                                     _("cannot generate a random uuid for interfaceid"));<br>
> +                goto error;<br>
> +            }<br>
> +        }<br>
> +        /* profileid is not mandatory for Open vSwitch */<br>
> +        if (virtPortProfileID != NULL) {<br>
> +            if (virStrcpyStatic(virtPort->u.openvswitch.profileID,<br>
> +                                virtPortProfileID) == NULL) {<br>
> +                virNetDevError(VIR_ERR_XML_ERROR, "%s",<br>
> +                                     _("profileid parameter too long"));<br>
<br>
<br>
</div></div>I'm not sure why the existing profileID is a fixed length. If that's<br>
something that is limiting to openvswitch, we should take care of that<br>
limitation. But that shouldn't hole up this patch going in (since you're<br>
only propagating an existing practice).<br>
<div><div><br>
> +                goto error;<br>
> +            }<br>
> +        } else {<br>
> +            virtPort->u.openvswitch.profileID[0] = '\0';<br>
> +        }<br>
> +        break;<br>
><br>
>      default:<br>
>          virNetDevError(VIR_ERR_XML_ERROR,<br>
> @@ -225,6 +254,20 @@ virNetDevVPortProfileFormat(virNetDevVPortProfilePtr virtPort,<br>
>                            virtPort->u.virtPort8021Qbh.profileID);<br>
>          break;<br>
><br>
> +    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:<br>
> +        virUUIDFormat(virtPort->u.openvswitch.interfaceID,<br>
> +                      uuidstr);<br>
> +        if (virtPort->u.openvswitch.profileID[0] == '\0') {<br>
> +            virBufferAsprintf(buf, "  <parameters interfaceid='%s'/>\n",<br>
> +                              uuidstr);<br>
> +        } else {<br>
> +            virBufferAsprintf(buf, "  <parameters interfaceid='%s' "<br>
> +                              "profileid='%s'/>\n", uuidstr,<br>
> +                              virtPort->u.openvswitch.profileID);<br>
> +        }<br>
> +<br>
> +        break;<br>
> +<br>
>      default:<br>
>          virNetDevError(VIR_ERR_XML_ERROR,<br>
>                         _("unexpected virtualport type %d"), virtPort->virtPortType);<br>
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms<br>
> index 0c22dec..ad5c7d3 100644<br>
> --- a/src/libvirt_private.syms<br>
> +++ b/src/libvirt_private.syms<br>
> @@ -378,7 +378,7 @@ virDomainNetGetActualBandwidth;<br>
>  virDomainNetGetActualBridgeName;<br>
>  virDomainNetGetActualDirectDev;<br>
>  virDomainNetGetActualDirectMode;<br>
> -virDomainNetGetActualDirectVirtPortProfile;<br>
> +virDomainNetGetActualVirtPortProfile;<br>
<br>
</div></div>We like to keep these in alphabetic order, so this one will have to move<br>
down.<br>
<div><div><br>
<br>
>  virDomainNetGetActualType;<br>
>  virDomainNetIndexByMac;<br>
>  virDomainNetInsert;<br>
> @@ -1237,6 +1237,11 @@ virNetDevMacVLanCreateWithVPortProfile;<br>
>  virNetDevMacVLanDeleteWithVPortProfile;<br>
><br>
><br>
> +# virnetdevopenvswitch.h<br>
> +virNetDevOpenvswitchAddPort;<br>
> +virNetDevOpenvswitchRemovePort;<br>
> +<br>
> +<br>
>  # virnetdevtap.h<br>
>  virNetDevTapCreate;<br>
>  virNetDevTapCreateInBridgePort;<br>
> diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c<br>
> index b712da4..17e8312 100644<br>
> --- a/src/lxc/lxc_driver.c<br>
> +++ b/src/lxc/lxc_driver.c<br>
> @@ -56,6 +56,7 @@<br>
>  #include "domain_nwfilter.h"<br>
>  #include "network/bridge_driver.h"<br>
>  #include "virnetdev.h"<br>
> +#include "virnetdevtap.h"<br>
>  #include "virnodesuspend.h"<br>
>  #include "virtime.h"<br>
>  #include "virtypedparam.h"<br>
> @@ -1105,6 +1106,7 @@ static void lxcVmCleanup(lxc_driver_t *driver,<br>
>      virCgroupPtr cgroup;<br>
>      int i;<br>
>      lxcDomainObjPrivatePtr priv = vm->privateData;<br>
> +    virNetDevVPortProfilePtr vport = NULL;<br>
><br>
>      /* now that we know it's stopped call the hook if present */<br>
>      if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {<br>
> @@ -1132,10 +1134,15 @@ static void lxcVmCleanup(lxc_driver_t *driver,<br>
>      priv->monitorWatch = -1;<br>
><br>
>      for (i = 0 ; i < vm->def->nnets ; i++) {<br>
> -        ignore_value(virNetDevSetOnline(vm->def->nets[i]->ifname, false));<br>
> -        ignore_value(virNetDevVethDelete(vm->def->nets[i]->ifname));<br>
> -<br>
> -        networkReleaseActualDevice(vm->def->nets[i]);<br>
> +        virDomainNetDefPtr iface = vm->def->nets[i];<br>
> +        vport = virDomainNetGetActualVirtPortProfile(iface);<br>
> +        ignore_value(virNetDevSetOnline(iface->ifname, false));<br>
> +        if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)<br>
> +            ignore_value(virNetDevOpenvswitchRemovePort(<br>
> +                                       virDomainNetGetActualBridgeName(iface),<br>
> +                                       iface->ifname));<br>
> +        ignore_value(virNetDevVethDelete(iface->ifname));<br>
> +        networkReleaseActualDevice(iface);<br>
>      }<br>
><br>
>      virDomainConfVMNWFilterTeardown(vm);<br>
> @@ -1165,6 +1172,7 @@ static int lxcSetupInterfaceBridged(virConnectPtr conn,<br>
>      int ret = -1;<br>
>      char *parentVeth;<br>
>      char *containerVeth = NULL;<br>
> +    const virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(net);<br>
><br>
>      VIR_DEBUG("calling vethCreate()");<br>
>      parentVeth = net->ifname;<br>
> @@ -1186,7 +1194,11 @@ static int lxcSetupInterfaceBridged(virConnectPtr conn,<br>
>      if (virNetDevSetMAC(containerVeth, net->mac) < 0)<br>
>          goto cleanup;<br>
><br>
> -    if (virNetDevBridgeAddPort(brname, parentVeth) < 0)<br>
> +    if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)<br>
> +        ret = virNetDevOpenvswitchAddPort(brname, parentVeth, net->mac, vport);<br>
> +    else<br>
> +        ret = virNetDevBridgeAddPort(brname, parentVeth);<br>
> +    if (ret < 0)<br>
>          goto cleanup;<br>
><br>
>      if (virNetDevSetOnline(parentVeth, true) < 0)<br>
> @@ -1242,7 +1254,7 @@ static int lxcSetupInterfaceDirect(virConnectPtr conn,<br>
>       * and automagically dies when the container dies. So<br>
>       * we have no dev to perform disassociation with.<br>
>       */<br>
> -    prof = virDomainNetGetActualDirectVirtPortProfile(net);<br>
> +    prof = virDomainNetGetActualVirtPortProfile(net);<br>
>      if (prof) {<br>
>          lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",<br>
>                   _("Unable to set port profile on direct interfaces"));<br>
> @@ -1260,7 +1272,7 @@ static int lxcSetupInterfaceDirect(virConnectPtr conn,<br>
>              virDomainNetGetActualDirectDev(net),<br>
>              virDomainNetGetActualDirectMode(net),<br>
>              false, false, def->uuid,<br>
> -            virDomainNetGetActualDirectVirtPortProfile(net),<br>
> +            virDomainNetGetActualVirtPortProfile(net),<br>
>              &res_ifname,<br>
>              VIR_NETDEV_VPORT_PROFILE_OP_CREATE,<br>
>              driver->stateDir,<br>
> @@ -1377,8 +1389,15 @@ static int lxcSetupInterfaces(virConnectPtr conn,<br>
><br>
>  cleanup:<br>
>      if (ret != 0) {<br>
> -        for (i = 0 ; i < def->nnets ; i++)<br>
> -            networkReleaseActualDevice(def->nets[i]);<br>
> +        for (i = 0 ; i < def->nnets ; i++) {<br>
> +            virDomainNetDefPtr iface = def->nets[i];<br>
> +            virNetDevVPortProfilePtr vport = virDomainNetGetActualVirtPortProfile(iface);<br>
> +            if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)<br>
> +                ignore_value(virNetDevOpenvswitchRemovePort(<br>
> +                                        virDomainNetGetActualBridgeName(iface),<br>
> +                                        iface->ifname));<br>
> +            networkReleaseActualDevice(iface);<br>
> +        }<br>
<br>
</div></div>While going through this, I noticed what seemed to be some<br>
inconsistencies in the way lxc cleans up network interfaces (prior to<br>
your changes), but some of the code also led me to believe I don't<br>
understand everything that's going on, so I'm going to say your patches<br>
here are okay, as they don't change behavior for non-ovs bridge devices.<br>
<div><br>
>      }<br>
>      return ret;<br>
>  }<br>
> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c<br>
> index 57ebb9f..1423d3f 100644<br>
> --- a/src/network/bridge_driver.c<br>
> +++ b/src/network/bridge_driver.c<br>
> @@ -1765,7 +1765,8 @@ networkStartNetworkVirtual(struct network_driver *driver,<br>
>              goto err0;<br>
>          }<br>
>          if (virNetDevTapCreateInBridgePort(network->def->bridge,<br>
> -                                           &macTapIfName, network->def->mac, 0, false, NULL) < 0) {<br>
> +                           &macTapIfName, network->def->mac, 0,<br>
> +                           false, NULL, NULL) < 0) {<br>
<br>
</div>There's an indentation problem here.<br>
<div><div><br>
<br>
>              VIR_FREE(macTapIfName);<br>
>              goto err0;<br>
>          }<br>
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c<br>
> index 1b92aa4..591e371 100644<br>
> --- a/src/qemu/qemu_command.c<br>
> +++ b/src/qemu/qemu_command.c<br>
> @@ -154,7 +154,7 @@ qemuPhysIfaceConnect(virDomainDefPtr def,<br>
>          virDomainNetGetActualDirectDev(net),<br>
>          virDomainNetGetActualDirectMode(net),<br>
>          true, vnet_hdr, def->uuid,<br>
> -        virDomainNetGetActualDirectVirtPortProfile(net),<br>
> +        virDomainNetGetActualVirtPortProfile(net),<br>
>          &res_ifname,<br>
>          vmop, driver->stateDir,<br>
>          virDomainNetGetActualBandwidth(net));<br>
> @@ -247,7 +247,8 @@ qemuNetworkIfaceConnect(virDomainDefPtr def,<br>
>      memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);<br>
>      tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */<br>
>      err = virNetDevTapCreateInBridgePort(brname, &net->ifname, tapmac,<br>
> -                                         vnet_hdr, true, &tapfd);<br>
> +                             vnet_hdr, true, &tapfd,<br>
> +                             virDomainNetGetActualVirtPortProfile(net));<br>
>      virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0);<br>
>      if (err < 0) {<br>
>          if (template_ifname)<br>
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c<br>
> index b4870be..3b1dbbf 100644<br>
> --- a/src/qemu/qemu_hotplug.c<br>
> +++ b/src/qemu/qemu_hotplug.c<br>
> @@ -40,6 +40,7 @@<br>
>  #include "qemu_cgroup.h"<br>
>  #include "locking/domain_lock.h"<br>
>  #include "network/bridge_driver.h"<br>
> +#include "virnetdevtap.h"<br>
><br>
>  #define VIR_FROM_THIS VIR_FROM_QEMU<br>
><br>
> @@ -652,6 +653,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,<br>
>      int vhostfd = -1;<br>
>      char *nicstr = NULL;<br>
>      char *netstr = NULL;<br>
> +    virNetDevVPortProfilePtr vport = NULL;<br>
>      int ret = -1;<br>
>      virDomainDevicePCIAddress guestAddr;<br>
>      int vlan;<br>
> @@ -838,6 +840,12 @@ cleanup:<br>
>          if (iface_connected)<br>
>              virDomainConfNWFilterTeardown(net);<br>
><br>
> +        vport = virDomainNetGetActualVirtPortProfile(net);<br>
> +        if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)<br>
> +            ignore_value(virNetDevOpenvswitchRemovePort(<br>
> +                                       virDomainNetGetActualBridgeName(net),<br>
> +                                       net->ifname));<br>
<br>
</div></div>Again a small indentation problem.<br>
<div><div><br>
> +<br>
>          networkReleaseActualDevice(net);<br>
>      }<br>
><br>
> @@ -1833,6 +1841,7 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver,<br>
>      qemuDomainObjPrivatePtr priv = vm->privateData;<br>
>      int vlan;<br>
>      char *hostnet_name = NULL;<br>
> +    virNetDevVPortProfilePtr vport = NULL;<br>
><br>
>      for (i = 0 ; i < vm->def->nnets ; i++) {<br>
>          virDomainNetDefPtr net = vm->def->nets[i];<br>
> @@ -1923,7 +1932,7 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver,<br>
>                           detach->ifname, detach->mac,<br>
>                           virDomainNetGetActualDirectDev(detach),<br>
>                           virDomainNetGetActualDirectMode(detach),<br>
> -                         virDomainNetGetActualDirectVirtPortProfile(detach),<br>
> +                         virDomainNetGetActualVirtPortProfile(detach),<br>
>                           driver->stateDir));<br>
>          VIR_FREE(detach->ifname);<br>
>      }<br>
> @@ -1938,6 +1947,12 @@ int qemuDomainDetachNetDevice(struct qemud_driver *driver,<br>
>          }<br>
>      }<br>
><br>
> +    vport = virDomainNetGetActualVirtPortProfile(detach);<br>
> +    if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)<br>
> +        ignore_value(virNetDevOpenvswitchRemovePort(<br>
> +                                       virDomainNetGetActualBridgeName(detach),<br>
> +                                       detach->ifname));<br>
> +<br>
>      networkReleaseActualDevice(detach);<br>
>      if (vm->def->nnets > 1) {<br>
>          memmove(vm->def->nets + i,<br>
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c<br>
> index 12cfbde..a513b3c 100644<br>
> --- a/src/qemu/qemu_migration.c<br>
> +++ b/src/qemu/qemu_migration.c<br>
> @@ -2563,7 +2563,7 @@ qemuMigrationVPAssociatePortProfiles(virDomainDefPtr def) {<br>
>          net = def->nets[i];<br>
>          if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {<br>
>              if (virNetDevVPortProfileAssociate(net->ifname,<br>
> -                                               virDomainNetGetActualDirectVirtPortProfile(net),<br>
> +                                               virDomainNetGetActualVirtPortProfile(net),<br>
>                                                 net->mac,<br>
>                                                 virDomainNetGetActualDirectDev(net),<br>
>                                                 def->uuid,<br>
> @@ -2580,7 +2580,7 @@ err_exit:<br>
>          net = def->nets[i];<br>
>          if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT) {<br>
>              ignore_value(virNetDevVPortProfileDisassociate(net->ifname,<br>
> -                                                           virDomainNetGetActualDirectVirtPortProfile(net),<br>
> +                                                           virDomainNetGetActualVirtPortProfile(net),<br>
>                                                             net->mac,<br>
>                                                             virDomainNetGetActualDirectDev(net),<br>
>                                                             VIR_NETDEV_VPORT_PROFILE_OP_MIGRATE_IN_FINISH));<br>
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c<br>
> index 2d92d66..9bc5436 100644<br>
> --- a/src/qemu/qemu_process.c<br>
> +++ b/src/qemu/qemu_process.c<br>
> @@ -62,6 +62,7 @@<br>
>  #include "network/bridge_driver.h"<br>
>  #include "uuid.h"<br>
>  #include "virtime.h"<br>
> +#include "virnetdevtap.h"<br>
><br>
>  #define VIR_FROM_THIS VIR_FROM_QEMU<br>
><br>
> @@ -3604,6 +3605,7 @@ void qemuProcessStop(struct qemud_driver *driver,<br>
>      qemuDomainObjPrivatePtr priv = vm->privateData;<br>
>      virErrorPtr orig_err;<br>
>      virDomainDefPtr def;<br>
> +    virNetDevVPortProfilePtr vport = NULL;<br>
>      int i;<br>
>      int logfile = -1;<br>
>      char *timestamp;<br>
> @@ -3724,13 +3726,19 @@ void qemuProcessStop(struct qemud_driver *driver,<br>
>                               net->ifname, net->mac,<br>
>                               virDomainNetGetActualDirectDev(net),<br>
>                               virDomainNetGetActualDirectMode(net),<br>
> -                             virDomainNetGetActualDirectVirtPortProfile(net),<br>
> +                             virDomainNetGetActualVirtPortProfile(net),<br>
>                               driver->stateDir));<br>
>              VIR_FREE(net->ifname);<br>
>          }<br>
>          /* release the physical device (or any other resources used by<br>
>           * this interface in the network driver<br>
>           */<br>
> +        vport = virDomainNetGetActualVirtPortProfile(net);<br>
> +        if (vport && vport->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH)<br>
> +            ignore_value(virNetDevOpenvswitchRemovePort(<br>
> +                                       virDomainNetGetActualBridgeName(net),<br>
> +                                       net->ifname));<br>
> +<br>
>          networkReleaseActualDevice(net);<br>
>      }<br>
><br>
> diff --git a/src/uml/uml_conf.c b/src/uml/uml_conf.c<br>
> index 316d558..8c17578 100644<br>
> --- a/src/uml/uml_conf.c<br>
> +++ b/src/uml/uml_conf.c<br>
> @@ -142,7 +142,8 @@ umlConnectTapDevice(virConnectPtr conn,<br>
>      memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);<br>
>      tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */<br>
>      if (virNetDevTapCreateInBridgePort(bridge, &net->ifname, tapmac,<br>
> -                                       0, true, NULL) < 0) {<br>
> +                       0, true, NULL,<br>
> +                       virDomainNetGetActualVirtPortProfile(net)) < 0) {<br>
>          if (template_ifname)<br>
>              VIR_FREE(net->ifname);<br>
>          goto error;<br>
> diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c<br>
> new file mode 100644<br>
> index 0000000..24a335a<br>
> --- /dev/null<br>
> +++ b/src/util/virnetdevopenvswitch.c<br>
> @@ -0,0 +1,135 @@<br>
> +/*<br>
> + * Copyright (C) 2012 Nicira, Inc.<br>
> + *<br>
> + * This library is free software; you can redistribute it and/or<br>
> + * modify it under the terms of the GNU Lesser General Public<br>
> + * License as published by the Free Software Foundation; either<br>
> + * version 2.1 of the License, or (at your option) any later version.<br>
> + *<br>
> + * This library is distributed in the hope that it will be useful,<br>
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
> + * Lesser General Public License for more details.<br>
> + *<br>
> + * You should have received a copy of the GNU Lesser General Public<br>
> + * License along with this library; if not, write to the Free Software<br>
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA<br>
> + *<br>
> + * Authors:<br>
> + *     Dan Wendlandt <<a href="mailto:dan@nicira.com" target="_blank">dan@nicira.com</a>><br>
> + *     Kyle Mestery <<a href="mailto:kmestery@cisco.com" target="_blank">kmestery@cisco.com</a>><br>
> + *     Ansis Atteka <<a href="mailto:aatteka@nicira.com" target="_blank">aatteka@nicira.com</a>><br>
> + */<br>
> +<br>
> +#include <config.h><br>
> +<br>
> +#include "virnetdevopenvswitch.h"<br>
> +#include "command.h"<br>
> +#include "memory.h"<br>
> +#include "virterror_internal.h"<br>
> +#include "ignore-value.h"<br>
> +#include "virmacaddr.h"<br>
> +<br>
> +#define VIR_FROM_THIS VIR_FROM_NONE<br>
> +<br>
> +/**<br>
> + * virNetDevOpenvswitchAddPort:<br>
> + * @brname: the bridge name<br>
> + * @ifname: the network interface name<br>
> + * @macaddr: the mac address of the virtual interface<br>
> + * @ovsport: the ovs specific fields<br>
> + *<br>
> + * Add an interface to the OVS bridge<br>
> + *<br>
> + * Returns 0 in case of success or -1 in case of failure.<br>
> + */<br>
> +int virNetDevOpenvswitchAddPort(const char *brname, const char *ifname,<br>
> +                                   const unsigned char *macaddr,<br>
> +                                   virNetDevVPortProfilePtr ovsport)<br>
> +{<br>
> +    int ret = -1;<br>
> +    virCommandPtr cmd = NULL;<br>
> +    char macaddrstr[VIR_MAC_STRING_BUFLEN];<br>
> +    char uuidstr[VIR_UUID_STRING_BUFLEN];<br>
> +    char *attachedmac_ex_id = NULL;<br>
> +    char *ifaceid_ex_id = NULL;<br>
> +    char *profile_ex_id = NULL;<br>
> +<br>
> +    virMacAddrFormat(macaddr, macaddrstr);<br>
> +    virUUIDFormat(ovsport->u.openvswitch.interfaceID, uuidstr);<br>
> +<br>
> +    if (virAsprintf(&attachedmac_ex_id, "external-ids:attached-mac=\"%s\"",<br>
> +                    macaddrstr) < 0)<br>
<br>
</div></div>If the quotes aren't necessary, there is a "virCommandAddArgPair" that<br>
will do this for you once you've created the command:<br>
<br>
        virCommandAddArgPair(cmd, "external-ids:attached-mac", macaddrstr);<br>
<br>
(I wonder if it would be worthwhile adding a "quote the arg" (and/or<br>
"quote the arg if necessary") flag to that function (or maybe creating a<br>
new function virCommandAddArgPairQuoted).<br>
<div><div><br>
> +        goto cleanup;<br>
> +    if (virAsprintf(&ifaceid_ex_id, "external-ids:iface-id=\"%s\"",<br>
> +                    uuidstr) < 0)<br>
> +        goto cleanup;<br>
> +    if (ovsport->u.openvswitch.profileID[0] != '\0') {<br>
> +        if (virAsprintf(&profile_ex_id, "external-ids:port-profile=\"%s\"",<br>
> +                        ovsport->u.openvswitch.profileID) < 0)<br>
> +            goto cleanup;<br>
> +    }<br>
> +<br>
> +    cmd = virCommandNew(OVSVSCTL);<br>
> +    if (ovsport->u.openvswitch.profileID[0] == '\0') {<br>
> +        virCommandAddArgList(cmd, "--", "--may-exist", "add-port",<br>
> +                        brname, ifname,<br>
> +                        "--", "set", "Interface", ifname, attachedmac_ex_id,<br>
> +                        "--", "set", "Interface", ifname, ifaceid_ex_id,<br>
> +                        "--", "set", "Interface", ifname,<br>
> +                        "external-ids:iface-status=active",<br>
> +                        NULL);<br>
> +    } else {<br>
> +        virCommandAddArgList(cmd, "--", "--may-exist", "add-port",<br>
> +                        brname, ifname,<br>
> +                        "--", "set", "Interface", ifname, attachedmac_ex_id,<br>
> +                        "--", "set", "Interface", ifname, ifaceid_ex_id,<br>
> +                        "--", "set", "Interface", ifname, profile_ex_id,<br>
> +                        "--", "set", "Interface", ifname,<br>
> +                        "external-ids:iface-status=active",<br>
> +                        NULL);<br>
> +    }<br>
> +<br>
> +    if (virCommandRun(cmd, NULL) < 0) {<br>
> +        virReportSystemError(VIR_ERR_INTERNAL_ERROR,<br>
> +                             _("Unable to add port %s to OVS bridge %s"),<br>
> +                             ifname, brname);<br>
> +        goto cleanup;<br>
> +    }<br>
> +    ret = 0;<br>
> +<br>
> +    cleanup:<br>
> +        VIR_FREE(attachedmac_ex_id);<br>
> +        VIR_FREE(ifaceid_ex_id);<br>
> +        VIR_FREE(profile_ex_id);<br>
> +        virCommandFree(cmd);<br>
> +        return ret;<br>
> +}<br>
> +<br>
> +/**<br>
> + * virNetDevOpenvswitchRemovePort:<br>
> + * @ifname: the network interface name<br>
> + *<br>
> + * Deletes an interface from a OVS bridge<br>
> + *<br>
> + * Returns 0 in case of success or -1 in case of failure.<br>
> + */<br>
> +int virNetDevOpenvswitchRemovePort(const char *brname ATTRIBUTE_UNUSED, const char *ifname)<br>
> +{<br>
> +    int ret = -1;<br>
> +    virCommandPtr cmd = NULL;<br>
> +<br>
> +    cmd = virCommandNew(OVSVSCTL);<br>
> +    virCommandAddArgList(cmd, "--", "--if-exists", "del-port", ifname, NULL);<br>
> +<br>
> +    if (virCommandRun(cmd, NULL) < 0) {<br>
> +        virReportSystemError(VIR_ERR_INTERNAL_ERROR,<br>
> +                             _("Unable to delete port %s from OVS"), ifname);<br>
> +        goto cleanup;<br>
> +    }<br>
> +    ret = 0;<br>
> +<br>
> +    cleanup:<br>
> +        virCommandFree(cmd);<br>
> +        return ret;<br>
> +}<br>
> diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h<br>
> new file mode 100644<br>
> index 0000000..bca4c3e<br>
> --- /dev/null<br>
> +++ b/src/util/virnetdevopenvswitch.h<br>
> @@ -0,0 +1,42 @@<br>
> +/*<br>
> + * Copyright (C) 2012 Nicira, Inc.<br>
> + *<br>
> + * This library is free software; you can redistribute it and/or<br>
> + * modify it under the terms of the GNU Lesser General Public<br>
> + * License as published by the Free Software Foundation; either<br>
> + * version 2.1 of the License, or (at your option) any later version.<br>
> + *<br>
> + * This library is distributed in the hope that it will be useful,<br>
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
> + * Lesser General Public License for more details.<br>
> + *<br>
> + * You should have received a copy of the GNU Lesser General Public<br>
> + * License along with this library; if not, write to the Free Software<br>
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA<br>
> + *<br>
> + * Authors:<br>
> + *     Dan Wendlandt <<a href="mailto:dan@nicira.com" target="_blank">dan@nicira.com</a>><br>
> + *     Kyle Mestery <<a href="mailto:kmestery@cisco.com" target="_blank">kmestery@cisco.com</a>><br>
> + *     Ansis Atteka <<a href="mailto:aatteka@nicira.com" target="_blank">aatteka@nicira.com</a>><br>
> + */<br>
> +<br>
> +#ifndef __VIR_NETDEV_OPENVSWITCH_H__<br>
> +# define __VIR_NETDEV_OPENVSWITCH_H__<br>
> +<br>
> +# include "internal.h"<br>
> +# include "util.h"<br>
> +# include "virnetdevvportprofile.h"<br>
> +<br>
> +<br>
> +int virNetDevOpenvswitchAddPort(const char *brname,<br>
> +                                const char *ifname,<br>
> +                                const unsigned char *macaddr,<br>
> +                                virNetDevVPortProfilePtr ovsport)<br>
> +    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)<br>
> +    ATTRIBUTE_RETURN_CHECK;<br>
> +<br>
> +int virNetDevOpenvswitchRemovePort(const char *brname, const char *ifname)<br>
> +    ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;<br>
> +<br>
> +#endif /* __VIR_NETDEV_OPENVSWITCH_H__ */<br>
> diff --git a/src/util/virnetdevtap.c b/src/util/virnetdevtap.c<br>
> index 2ed53c6..cd1d4c1 100644<br>
> --- a/src/util/virnetdevtap.c<br>
> +++ b/src/util/virnetdevtap.c<br>
> @@ -25,6 +25,7 @@<br>
>  #include "virnetdevtap.h"<br>
>  #include "virnetdev.h"<br>
>  #include "virnetdevbridge.h"<br>
> +#include "virnetdevopenvswitch.h"<br>
>  #include "virterror_internal.h"<br>
>  #include "virfile.h"<br>
>  #include "virterror_internal.h"<br>
> @@ -249,6 +250,7 @@ int virNetDevTapDelete(const char *ifname ATTRIBUTE_UNUSED)<br>
>   * @macaddr: desired MAC address (VIR_MAC_BUFLEN long)<br>
>   * @vnet_hdr: whether to try enabling IFF_VNET_HDR<br>
>   * @tapfd: file descriptor return value for the new tap device<br>
> + * @ovsport: Open vSwitch specific configuration<br>
>   *<br>
>   * This function creates a new tap device on a bridge. @ifname can be either<br>
>   * a fixed name or a name template with '%d' for dynamic name allocation.<br>
> @@ -265,7 +267,8 @@ int virNetDevTapCreateInBridgePort(const char *brname,<br>
>                                     const unsigned char *macaddr,<br>
>                                     int vnet_hdr,<br>
>                                     bool up,<br>
> -                                   int *tapfd)<br>
> +                                   int *tapfd,<br>
> +                                   virNetDevVPortProfilePtr ovsport)<br>
<br>
</div></div>This arg should be named virtPortProfile for consistency (although I<br>
think that name is too long, maybe a global replace is in order sometime...)<br>
<div><div><br>
>  {<br>
>      if (virNetDevTapCreate(ifname, vnet_hdr, tapfd) < 0)<br>
>          return -1;<br>
> @@ -286,8 +289,13 @@ int virNetDevTapCreateInBridgePort(const char *brname,<br>
>      if (virNetDevSetMTUFromDevice(*ifname, brname) < 0)<br>
>          goto error;<br>
><br>
> -    if (virNetDevBridgeAddPort(brname, *ifname) < 0)<br>
> -        goto error;<br>
> +    if (ovsport) {<br>
> +        if (virNetDevOpenvswitchAddPort(brname, *ifname, macaddr, ovsport) < 0)<br>
> +            goto error;<br>
> +    } else {<br>
> +        if (virNetDevBridgeAddPort(brname, *ifname) < 0)<br>
> +            goto error;<br>
> +    }<br>
><br>
>      if (virNetDevSetOnline(*ifname, up) < 0)<br>
>          goto error;<br>
> diff --git a/src/util/virnetdevtap.h b/src/util/virnetdevtap.h<br>
> index fb35ac5..ee159f7 100644<br>
> --- a/src/util/virnetdevtap.h<br>
> +++ b/src/util/virnetdevtap.h<br>
> @@ -24,6 +24,7 @@<br>
>  # define __VIR_NETDEV_TAP_H__<br>
><br>
>  # include "internal.h"<br>
> +# include "virnetdevvportprofile.h"<br>
><br>
>  int virNetDevTapCreate(char **ifname,<br>
>                         int vnet_hdr,<br>
> @@ -38,8 +39,10 @@ int virNetDevTapCreateInBridgePort(const char *brname,<br>
>                                     const unsigned char *macaddr,<br>
>                                     int vnet_hdr,<br>
>                                     bool up,<br>
> -                                   int *tapfd)<br>
> +                                   int *tapfd,<br>
> +                                   virNetDevVPortProfilePtr ovsport)<br>
>      ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)<br>
>      ATTRIBUTE_RETURN_CHECK;<br>
><br>
> +<br>
>  #endif /* __VIR_NETDEV_TAP_H__ */<br>
> diff --git a/src/util/virnetdevvportprofile.c b/src/util/virnetdevvportprofile.c<br>
> index faadc3a..67fd7bc 100644<br>
> --- a/src/util/virnetdevvportprofile.c<br>
> +++ b/src/util/virnetdevvportprofile.c<br>
> @@ -968,6 +968,7 @@ virNetDevVPortProfileAssociate(const char *macvtap_ifname,<br>
><br>
>      switch (virtPort->virtPortType) {<br>
>      case VIR_NETDEV_VPORT_PROFILE_NONE:<br>
> +    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:<br>
>      case VIR_NETDEV_VPORT_PROFILE_LAST:<br>
>          break;<br>
><br>
> @@ -1027,6 +1028,7 @@ virNetDevVPortProfileDisassociate(const char *macvtap_ifname,<br>
><br>
>      switch (virtPort->virtPortType) {<br>
>      case VIR_NETDEV_VPORT_PROFILE_NONE:<br>
> +    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:<br>
>      case VIR_NETDEV_VPORT_PROFILE_LAST:<br>
>          break;<br>
><br>
> diff --git a/src/util/virnetdevvportprofile.h b/src/util/virnetdevvportprofile.h<br>
> index 7a8d81f..ec2d06d 100644<br>
> --- a/src/util/virnetdevvportprofile.h<br>
> +++ b/src/util/virnetdevvportprofile.h<br>
> @@ -35,6 +35,7 @@ enum virNetDevVPortProfile {<br>
>      VIR_NETDEV_VPORT_PROFILE_NONE,<br>
>      VIR_NETDEV_VPORT_PROFILE_8021QBG,<br>
>      VIR_NETDEV_VPORT_PROFILE_8021QBH,<br>
> +    VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH,<br>
><br>
>      VIR_NETDEV_VPORT_PROFILE_LAST,<br>
>  };<br>
> @@ -54,7 +55,7 @@ enum virNetDevVPortProfileOp {<br>
>  };<br>
>  VIR_ENUM_DECL(virNetDevVPortProfileOp)<br>
><br>
> -/* profile data for macvtap (VEPA) */<br>
> +/* profile data for macvtap (VEPA) and openvswitch */<br>
>  typedef struct _virNetDevVPortProfile virNetDevVPortProfile;<br>
>  typedef virNetDevVPortProfile *virNetDevVPortProfilePtr;<br>
>  struct _virNetDevVPortProfile {<br>
> @@ -69,6 +70,10 @@ struct _virNetDevVPortProfile {<br>
>          struct {<br>
>              char          profileID[LIBVIRT_IFLA_VF_PORT_PROFILE_MAX];<br>
>          } virtPort8021Qbh;<br>
> +        struct {<br>
> +            unsigned char interfaceID[VIR_UUID_BUFLEN];<br>
> +            char          profileID[LIBVIRT_IFLA_VF_PORT_PROFILE_MAX];<br>
> +        } openvswitch;<br>
>      } u;<br>
>  };<br>
><br>
<br>
</div></div>I didn't see any major problems in this version, so I'm inclined to ACK<br>
it conditioned on the nits being fixed (they're simple enough I could<br>
just take care of them while pushing it). The one thing I would like to<br>
get other opinions of before pushing is problem with auto-generating the<br>
interfaceid (just in case there's a better way to fix it that would<br>
required making a change now).<br>
<br>
--<br>
libvir-list mailing list<br>
<a href="mailto:libvir-list@redhat.com" target="_blank">libvir-list@redhat.com</a><br>
<a href="https://www.redhat.com/mailman/listinfo/libvir-list" target="_blank">https://www.redhat.com/mailman/listinfo/libvir-list</a><br>
</blockquote></div><br>