diff mbox

[ovs-dev,RFC,v4,2/6] dpif-netlink: break out code to add compat and non-compat vports

Message ID 20170118194515.1307-3-e@erig.me
State Superseded
Headers show

Commit Message

Eric Garver Jan. 18, 2017, 7:45 p.m. UTC
From: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>

The vport type for adding tunnels is now compatibility code and any new features
from tunnels must configure the tunnel as an interface using the tunnel metadata
support.

In order to be able to add those tunnels, we need to add code to create the
tunnels and add them as NETDEV vports. And when there is no support to create
them, we need to use the compatibility code and add them as tunnel vports.

When removing those tunnels, we need to remove the interfaces as well, and
detecting the right type might be important, at least to distinguish the tunnel
vports that we should remove and the interfaces that we shouldn't.

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>
---
 lib/dpif-netlink.c | 201 +++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 148 insertions(+), 53 deletions(-)

Comments

Joe Stringer Feb. 2, 2017, 10:39 p.m. UTC | #1
On 18 January 2017 at 11:45, Eric Garver <e@erig.me> wrote:
> From: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>
>
> The vport type for adding tunnels is now compatibility code and any new features
> from tunnels must configure the tunnel as an interface using the tunnel metadata
> support.
>
> In order to be able to add those tunnels, we need to add code to create the
> tunnels and add them as NETDEV vports. And when there is no support to create
> them, we need to use the compatibility code and add them as tunnel vports.
>
> When removing those tunnels, we need to remove the interfaces as well, and
> detecting the right type might be important, at least to distinguish the tunnel
> vports that we should remove and the interfaces that we shouldn't.
>
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>

This patch involves refactoring as well as the base changes to
add/remove the new tunnel types. It's always easier to review if
functional changes are proposed separately from refactoring/cosmetic.
(I recognize the new functions don't do anything, but they still
combine with the refactoring). That said, with some minor changes this
looks OK to me.

Acked-by: Joe Stringer <joe@ovn.org>

> ---
>  lib/dpif-netlink.c | 201 +++++++++++++++++++++++++++++++++++++++--------------
>  1 file changed, 148 insertions(+), 53 deletions(-)
>
> diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
> index c8b0e37f9365..e6459f358989 100644
> --- a/lib/dpif-netlink.c
> +++ b/lib/dpif-netlink.c
> @@ -781,10 +781,8 @@ get_vport_type(const struct dpif_netlink_vport *vport)
>  }
>
>  static enum ovs_vport_type
> -netdev_to_ovs_vport_type(const struct netdev *netdev)
> +netdev_to_ovs_vport_type(const char *type)
>  {
> -    const char *type = netdev_get_type(netdev);
> -
>      if (!strcmp(type, "tap") || !strcmp(type, "system")) {
>          return OVS_VPORT_TYPE_NETDEV;
>      } else if (!strcmp(type, "internal")) {
> @@ -805,19 +803,14 @@ netdev_to_ovs_vport_type(const struct netdev *netdev)
>  }
>
>  static int
> -dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
> +dpif_netlink_port_add__(struct dpif_netlink *dpif, const char *name,
> +                        enum ovs_vport_type type,
> +                        struct ofpbuf *options,
>                          odp_port_t *port_nop)
>      OVS_REQ_WRLOCK(dpif->upcall_lock)
>  {
> -    const struct netdev_tunnel_config *tnl_cfg;
> -    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
> -    const char *name = netdev_vport_get_dpif_port(netdev,
> -                                                  namebuf, sizeof namebuf);
> -    const char *type = netdev_get_type(netdev);
>      struct dpif_netlink_vport request, reply;
>      struct ofpbuf *buf;
> -    uint64_t options_stub[64 / 8];
> -    struct ofpbuf options;
>      struct nl_sock **socksp = NULL;
>      uint32_t *upcall_pids;
>      int error = 0;
> @@ -832,17 +825,80 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
>      dpif_netlink_vport_init(&request);
>      request.cmd = OVS_VPORT_CMD_NEW;
>      request.dp_ifindex = dpif->dp_ifindex;
> -    request.type = netdev_to_ovs_vport_type(netdev);
> -    if (request.type == OVS_VPORT_TYPE_UNSPEC) {
> +    request.type = type;
> +    request.name = name;
> +
> +    request.port_no = *port_nop;
> +    upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers);
> +    request.n_upcall_pids = socksp ? dpif->n_handlers : 1;
> +    request.upcall_pids = upcall_pids;
> +
> +    if (options) {
> +        request.options = options->data;
> +        request.options_len = options->size;
> +    }
> +
> +    error = dpif_netlink_vport_transact(&request, &reply, &buf);
> +    if (!error) {
> +        *port_nop = reply.port_no;
> +    } else {
> +        if (error == EBUSY && *port_nop != ODPP_NONE) {
> +            VLOG_INFO("%s: requested port %"PRIu32" is in use",
> +                      dpif_name(&dpif->dpif), *port_nop);
> +        }
> +
> +        vport_del_socksp(dpif, socksp);
> +        goto exit;
> +    }
> +
> +    if (socksp) {
> +        error = vport_add_channels(dpif, *port_nop, socksp);
> +        if (error) {
> +            VLOG_INFO("%s: could not add channel for port %s",
> +                      dpif_name(&dpif->dpif), name);
> +
> +            /* Delete the port. */
> +            dpif_netlink_vport_init(&request);
> +            request.cmd = OVS_VPORT_CMD_DEL;
> +            request.dp_ifindex = dpif->dp_ifindex;
> +            request.port_no = *port_nop;
> +            dpif_netlink_vport_transact(&request, NULL, NULL);
> +            vport_del_socksp(dpif, socksp);
> +            goto exit;
> +        }
> +    }
> +    free(socksp);
> +
> +exit:
> +    ofpbuf_delete(buf);
> +    free(upcall_pids);
> +
> +    return error;
> +}
> +
> +static int
> +dpif_netlink_port_add_compat(struct dpif_netlink *dpif, struct netdev *netdev,
> +                             odp_port_t *port_nop)
> +    OVS_REQ_WRLOCK(dpif->upcall_lock)
> +{
> +    const struct netdev_tunnel_config *tnl_cfg;
> +    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
> +    const char *name = netdev_vport_get_dpif_port(netdev,
> +                                                  namebuf, sizeof namebuf);
> +    const char *type = netdev_get_type(netdev);
> +    uint64_t options_stub[64 / 8];
> +    struct ofpbuf options;
> +    enum ovs_vport_type ovs_type;
> +
> +    ovs_type = netdev_to_ovs_vport_type(netdev_get_type(netdev));
> +    if (ovs_type == OVS_VPORT_TYPE_UNSPEC) {
>          VLOG_WARN_RL(&error_rl, "%s: cannot create port `%s' because it has "
>                       "unsupported type `%s'",
>                       dpif_name(&dpif->dpif), name, type);
> -        vport_del_socksp(dpif, socksp);
>          return EINVAL;
>      }
> -    request.name = name;
>
> -    if (request.type == OVS_VPORT_TYPE_NETDEV) {
> +    if (ovs_type == OVS_VPORT_TYPE_NETDEV) {
>  #ifdef _WIN32
>          /* XXX : Map appropiate Windows handle */
>  #else
> @@ -851,7 +907,7 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
>      }
>
>  #ifdef _WIN32
> -    if (request.type == OVS_VPORT_TYPE_INTERNAL) {
> +    if (ovs_type == OVS_VPORT_TYPE_INTERNAL) {
>          if (!create_wmi_port(name)){
>              VLOG_ERR("Could not create wmi internal port with name:%s", name);
>              vport_del_socksp(dpif, socksp);
> @@ -879,50 +935,77 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
>              }
>              nl_msg_end_nested(&options, ext_ofs);
>          }
> -        request.options = options.data;
> -        request.options_len = options.size;
> +        return dpif_netlink_port_add__(dpif, name, ovs_type, &options,
> +                                       port_nop);
> +    } else {
> +        return dpif_netlink_port_add__(dpif, name, ovs_type, NULL, port_nop);
>      }
>
> -    request.port_no = *port_nop;
> -    upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers);
> -    request.n_upcall_pids = socksp ? dpif->n_handlers : 1;
> -    request.upcall_pids = upcall_pids;
> +}
>
> -    error = dpif_netlink_vport_transact(&request, &reply, &buf);
> -    if (!error) {
> -        *port_nop = reply.port_no;
> -    } else {
> -        if (error == EBUSY && *port_nop != ODPP_NONE) {
> -            VLOG_INFO("%s: requested port %"PRIu32" is in use",
> -                      dpif_name(&dpif->dpif), *port_nop);
> -        }
> +static int
> +dpif_netlink_port_query__(const struct dpif_netlink *dpif, odp_port_t port_no,
> +                          const char *port_name, struct dpif_port *dpif_port);

Could you put this declaration at the top of the file?

>
> -        vport_del_socksp(dpif, socksp);
> -        goto exit;
> +static int
> +dpif_netlink_port_create(struct netdev *netdev)
> +{
> +    switch (netdev_to_ovs_vport_type(netdev_get_type(netdev))) {
> +    case OVS_VPORT_TYPE_VXLAN:
> +    case OVS_VPORT_TYPE_GRE:
> +    case OVS_VPORT_TYPE_GENEVE:
> +    case OVS_VPORT_TYPE_NETDEV:
> +    case OVS_VPORT_TYPE_INTERNAL:
> +    case OVS_VPORT_TYPE_LISP:
> +    case OVS_VPORT_TYPE_STT:
> +    case OVS_VPORT_TYPE_UNSPEC:
> +    case __OVS_VPORT_TYPE_MAX:
> +    default:
> +        return EOPNOTSUPP;
>      }
> +    return 0;
> +}
>
> -    if (socksp) {
> -        error = vport_add_channels(dpif, *port_nop, socksp);
> -        if (error) {
> -            VLOG_INFO("%s: could not add channel for port %s",
> -                      dpif_name(&dpif->dpif), name);
> -
> -            /* Delete the port. */
> -            dpif_netlink_vport_init(&request);
> -            request.cmd = OVS_VPORT_CMD_DEL;
> -            request.dp_ifindex = dpif->dp_ifindex;
> -            request.port_no = *port_nop;
> -            dpif_netlink_vport_transact(&request, NULL, NULL);
> -            vport_del_socksp(dpif, socksp);
> -            goto exit;
> -        }
> +static int
> +dpif_netlink_port_destroy(const char *name OVS_UNUSED, const char *type)
> +{
> +    switch (netdev_to_ovs_vport_type(type)) {
> +    case OVS_VPORT_TYPE_VXLAN:
> +    case OVS_VPORT_TYPE_GRE:
> +    case OVS_VPORT_TYPE_GENEVE:
> +    case OVS_VPORT_TYPE_NETDEV:
> +    case OVS_VPORT_TYPE_INTERNAL:
> +    case OVS_VPORT_TYPE_LISP:
> +    case OVS_VPORT_TYPE_STT:
> +    case OVS_VPORT_TYPE_UNSPEC:
> +    case __OVS_VPORT_TYPE_MAX:
> +    default:
> +        return EOPNOTSUPP;
>      }
> -    free(socksp);
> +    return 0;
> +}
>
> -exit:
> -    ofpbuf_delete(buf);
> -    free(upcall_pids);
> +static int
> +dpif_netlink_port_create_and_add(struct dpif_netlink *dpif,
> +                                 struct netdev *netdev, odp_port_t *port_nop)
> +    OVS_REQ_WRLOCK(dpif->upcall_lock)
> +{
> +    int error;
> +    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
> +    const char *name = netdev_vport_get_dpif_port(netdev,
> +                                                  namebuf, sizeof namebuf);
> +
> +    error = dpif_netlink_port_create(netdev);
> +    if (error) {
> +        return error;
> +    }
>
> +    error = dpif_netlink_port_add__(dpif, name, OVS_VPORT_TYPE_NETDEV, NULL,
> +                                    port_nop);
> +    if (error) {
> +        VLOG_DBG("failed to add port, destroying: %d", error);
> +        dpif_netlink_port_destroy(name, netdev_get_type(netdev));
> +    }
>      return error;
>  }
>
> @@ -934,7 +1017,10 @@ dpif_netlink_port_add(struct dpif *dpif_, struct netdev *netdev,
>      int error;
>
>      fat_rwlock_wrlock(&dpif->upcall_lock);
> -    error = dpif_netlink_port_add__(dpif, netdev, port_nop);
> +    error = dpif_netlink_port_create_and_add(dpif, netdev, port_nop);
> +    if (error == EOPNOTSUPP) {
> +        error = dpif_netlink_port_add_compat(dpif, netdev, port_nop);
> +    }
>      fat_rwlock_unlock(&dpif->upcall_lock);
>
>      return error;
> @@ -946,6 +1032,12 @@ dpif_netlink_port_del__(struct dpif_netlink *dpif, odp_port_t port_no)
>  {
>      struct dpif_netlink_vport vport;
>      int error;
> +    struct dpif_port dpif_port;
> +
> +    error = dpif_netlink_port_query__(dpif, port_no, NULL, &dpif_port);
> +    if (error) {
> +        return error;
> +    }

I see that the windows code also does this, perhaps we could drop the
call from the windows-only piece?

>
>      dpif_netlink_vport_init(&vport);
>      vport.cmd = OVS_VPORT_CMD_DEL;
> @@ -965,6 +1057,9 @@ dpif_netlink_port_del__(struct dpif_netlink *dpif, odp_port_t port_no)
>
>      vport_del_channels(dpif, port_no);
>
> +    dpif_netlink_port_destroy(dpif_port.name, dpif_port.type);

Should we check the error here?
Eric Garver Feb. 3, 2017, 8:42 p.m. UTC | #2
On Thu, Feb 02, 2017 at 02:39:30PM -0800, Joe Stringer wrote:
> On 18 January 2017 at 11:45, Eric Garver <e@erig.me> wrote:
> > From: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>
> >
> > The vport type for adding tunnels is now compatibility code and any new features
> > from tunnels must configure the tunnel as an interface using the tunnel metadata
> > support.
> >
> > In order to be able to add those tunnels, we need to add code to create the
> > tunnels and add them as NETDEV vports. And when there is no support to create
> > them, we need to use the compatibility code and add them as tunnel vports.
> >
> > When removing those tunnels, we need to remove the interfaces as well, and
> > detecting the right type might be important, at least to distinguish the tunnel
> > vports that we should remove and the interfaces that we shouldn't.
> >
> > Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com>
> 
> This patch involves refactoring as well as the base changes to
> add/remove the new tunnel types. It's always easier to review if
> functional changes are proposed separately from refactoring/cosmetic.
> (I recognize the new functions don't do anything, but they still
> combine with the refactoring). That said, with some minor changes this
> looks OK to me.

Understood. I'll have a go at spitting this patch.

> Acked-by: Joe Stringer <joe@ovn.org>
> 
> > ---
> >  lib/dpif-netlink.c | 201 +++++++++++++++++++++++++++++++++++++++--------------
> >  1 file changed, 148 insertions(+), 53 deletions(-)
> >
> > diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
> > index c8b0e37f9365..e6459f358989 100644
> > --- a/lib/dpif-netlink.c
> > +++ b/lib/dpif-netlink.c
> > @@ -781,10 +781,8 @@ get_vport_type(const struct dpif_netlink_vport *vport)
> >  }
> >
> >  static enum ovs_vport_type
> > -netdev_to_ovs_vport_type(const struct netdev *netdev)
> > +netdev_to_ovs_vport_type(const char *type)
> >  {
> > -    const char *type = netdev_get_type(netdev);
> > -
> >      if (!strcmp(type, "tap") || !strcmp(type, "system")) {
> >          return OVS_VPORT_TYPE_NETDEV;
> >      } else if (!strcmp(type, "internal")) {
> > @@ -805,19 +803,14 @@ netdev_to_ovs_vport_type(const struct netdev *netdev)
> >  }
> >
> >  static int
> > -dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
> > +dpif_netlink_port_add__(struct dpif_netlink *dpif, const char *name,
> > +                        enum ovs_vport_type type,
> > +                        struct ofpbuf *options,
> >                          odp_port_t *port_nop)
> >      OVS_REQ_WRLOCK(dpif->upcall_lock)
> >  {
> > -    const struct netdev_tunnel_config *tnl_cfg;
> > -    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
> > -    const char *name = netdev_vport_get_dpif_port(netdev,
> > -                                                  namebuf, sizeof namebuf);
> > -    const char *type = netdev_get_type(netdev);
> >      struct dpif_netlink_vport request, reply;
> >      struct ofpbuf *buf;
> > -    uint64_t options_stub[64 / 8];
> > -    struct ofpbuf options;
> >      struct nl_sock **socksp = NULL;
> >      uint32_t *upcall_pids;
> >      int error = 0;
> > @@ -832,17 +825,80 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
> >      dpif_netlink_vport_init(&request);
> >      request.cmd = OVS_VPORT_CMD_NEW;
> >      request.dp_ifindex = dpif->dp_ifindex;
> > -    request.type = netdev_to_ovs_vport_type(netdev);
> > -    if (request.type == OVS_VPORT_TYPE_UNSPEC) {
> > +    request.type = type;
> > +    request.name = name;
> > +
> > +    request.port_no = *port_nop;
> > +    upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers);
> > +    request.n_upcall_pids = socksp ? dpif->n_handlers : 1;
> > +    request.upcall_pids = upcall_pids;
> > +
> > +    if (options) {
> > +        request.options = options->data;
> > +        request.options_len = options->size;
> > +    }
> > +
> > +    error = dpif_netlink_vport_transact(&request, &reply, &buf);
> > +    if (!error) {
> > +        *port_nop = reply.port_no;
> > +    } else {
> > +        if (error == EBUSY && *port_nop != ODPP_NONE) {
> > +            VLOG_INFO("%s: requested port %"PRIu32" is in use",
> > +                      dpif_name(&dpif->dpif), *port_nop);
> > +        }
> > +
> > +        vport_del_socksp(dpif, socksp);
> > +        goto exit;
> > +    }
> > +
> > +    if (socksp) {
> > +        error = vport_add_channels(dpif, *port_nop, socksp);
> > +        if (error) {
> > +            VLOG_INFO("%s: could not add channel for port %s",
> > +                      dpif_name(&dpif->dpif), name);
> > +
> > +            /* Delete the port. */
> > +            dpif_netlink_vport_init(&request);
> > +            request.cmd = OVS_VPORT_CMD_DEL;
> > +            request.dp_ifindex = dpif->dp_ifindex;
> > +            request.port_no = *port_nop;
> > +            dpif_netlink_vport_transact(&request, NULL, NULL);
> > +            vport_del_socksp(dpif, socksp);
> > +            goto exit;
> > +        }
> > +    }
> > +    free(socksp);
> > +
> > +exit:
> > +    ofpbuf_delete(buf);
> > +    free(upcall_pids);
> > +
> > +    return error;
> > +}
> > +
> > +static int
> > +dpif_netlink_port_add_compat(struct dpif_netlink *dpif, struct netdev *netdev,
> > +                             odp_port_t *port_nop)
> > +    OVS_REQ_WRLOCK(dpif->upcall_lock)
> > +{
> > +    const struct netdev_tunnel_config *tnl_cfg;
> > +    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
> > +    const char *name = netdev_vport_get_dpif_port(netdev,
> > +                                                  namebuf, sizeof namebuf);
> > +    const char *type = netdev_get_type(netdev);
> > +    uint64_t options_stub[64 / 8];
> > +    struct ofpbuf options;
> > +    enum ovs_vport_type ovs_type;
> > +
> > +    ovs_type = netdev_to_ovs_vport_type(netdev_get_type(netdev));
> > +    if (ovs_type == OVS_VPORT_TYPE_UNSPEC) {
> >          VLOG_WARN_RL(&error_rl, "%s: cannot create port `%s' because it has "
> >                       "unsupported type `%s'",
> >                       dpif_name(&dpif->dpif), name, type);
> > -        vport_del_socksp(dpif, socksp);
> >          return EINVAL;
> >      }
> > -    request.name = name;
> >
> > -    if (request.type == OVS_VPORT_TYPE_NETDEV) {
> > +    if (ovs_type == OVS_VPORT_TYPE_NETDEV) {
> >  #ifdef _WIN32
> >          /* XXX : Map appropiate Windows handle */
> >  #else
> > @@ -851,7 +907,7 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
> >      }
> >
> >  #ifdef _WIN32
> > -    if (request.type == OVS_VPORT_TYPE_INTERNAL) {
> > +    if (ovs_type == OVS_VPORT_TYPE_INTERNAL) {
> >          if (!create_wmi_port(name)){
> >              VLOG_ERR("Could not create wmi internal port with name:%s", name);
> >              vport_del_socksp(dpif, socksp);
> > @@ -879,50 +935,77 @@ dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
> >              }
> >              nl_msg_end_nested(&options, ext_ofs);
> >          }
> > -        request.options = options.data;
> > -        request.options_len = options.size;
> > +        return dpif_netlink_port_add__(dpif, name, ovs_type, &options,
> > +                                       port_nop);
> > +    } else {
> > +        return dpif_netlink_port_add__(dpif, name, ovs_type, NULL, port_nop);
> >      }
> >
> > -    request.port_no = *port_nop;
> > -    upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers);
> > -    request.n_upcall_pids = socksp ? dpif->n_handlers : 1;
> > -    request.upcall_pids = upcall_pids;
> > +}
> >
> > -    error = dpif_netlink_vport_transact(&request, &reply, &buf);
> > -    if (!error) {
> > -        *port_nop = reply.port_no;
> > -    } else {
> > -        if (error == EBUSY && *port_nop != ODPP_NONE) {
> > -            VLOG_INFO("%s: requested port %"PRIu32" is in use",
> > -                      dpif_name(&dpif->dpif), *port_nop);
> > -        }
> > +static int
> > +dpif_netlink_port_query__(const struct dpif_netlink *dpif, odp_port_t port_no,
> > +                          const char *port_name, struct dpif_port *dpif_port);
> 
> Could you put this declaration at the top of the file?
> 
> >
> > -        vport_del_socksp(dpif, socksp);
> > -        goto exit;
> > +static int
> > +dpif_netlink_port_create(struct netdev *netdev)
> > +{
> > +    switch (netdev_to_ovs_vport_type(netdev_get_type(netdev))) {
> > +    case OVS_VPORT_TYPE_VXLAN:
> > +    case OVS_VPORT_TYPE_GRE:
> > +    case OVS_VPORT_TYPE_GENEVE:
> > +    case OVS_VPORT_TYPE_NETDEV:
> > +    case OVS_VPORT_TYPE_INTERNAL:
> > +    case OVS_VPORT_TYPE_LISP:
> > +    case OVS_VPORT_TYPE_STT:
> > +    case OVS_VPORT_TYPE_UNSPEC:
> > +    case __OVS_VPORT_TYPE_MAX:
> > +    default:
> > +        return EOPNOTSUPP;
> >      }
> > +    return 0;
> > +}
> >
> > -    if (socksp) {
> > -        error = vport_add_channels(dpif, *port_nop, socksp);
> > -        if (error) {
> > -            VLOG_INFO("%s: could not add channel for port %s",
> > -                      dpif_name(&dpif->dpif), name);
> > -
> > -            /* Delete the port. */
> > -            dpif_netlink_vport_init(&request);
> > -            request.cmd = OVS_VPORT_CMD_DEL;
> > -            request.dp_ifindex = dpif->dp_ifindex;
> > -            request.port_no = *port_nop;
> > -            dpif_netlink_vport_transact(&request, NULL, NULL);
> > -            vport_del_socksp(dpif, socksp);
> > -            goto exit;
> > -        }
> > +static int
> > +dpif_netlink_port_destroy(const char *name OVS_UNUSED, const char *type)
> > +{
> > +    switch (netdev_to_ovs_vport_type(type)) {
> > +    case OVS_VPORT_TYPE_VXLAN:
> > +    case OVS_VPORT_TYPE_GRE:
> > +    case OVS_VPORT_TYPE_GENEVE:
> > +    case OVS_VPORT_TYPE_NETDEV:
> > +    case OVS_VPORT_TYPE_INTERNAL:
> > +    case OVS_VPORT_TYPE_LISP:
> > +    case OVS_VPORT_TYPE_STT:
> > +    case OVS_VPORT_TYPE_UNSPEC:
> > +    case __OVS_VPORT_TYPE_MAX:
> > +    default:
> > +        return EOPNOTSUPP;
> >      }
> > -    free(socksp);
> > +    return 0;
> > +}
> >
> > -exit:
> > -    ofpbuf_delete(buf);
> > -    free(upcall_pids);
> > +static int
> > +dpif_netlink_port_create_and_add(struct dpif_netlink *dpif,
> > +                                 struct netdev *netdev, odp_port_t *port_nop)
> > +    OVS_REQ_WRLOCK(dpif->upcall_lock)
> > +{
> > +    int error;
> > +    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
> > +    const char *name = netdev_vport_get_dpif_port(netdev,
> > +                                                  namebuf, sizeof namebuf);
> > +
> > +    error = dpif_netlink_port_create(netdev);
> > +    if (error) {
> > +        return error;
> > +    }
> >
> > +    error = dpif_netlink_port_add__(dpif, name, OVS_VPORT_TYPE_NETDEV, NULL,
> > +                                    port_nop);
> > +    if (error) {
> > +        VLOG_DBG("failed to add port, destroying: %d", error);
> > +        dpif_netlink_port_destroy(name, netdev_get_type(netdev));
> > +    }
> >      return error;
> >  }
> >
> > @@ -934,7 +1017,10 @@ dpif_netlink_port_add(struct dpif *dpif_, struct netdev *netdev,
> >      int error;
> >
> >      fat_rwlock_wrlock(&dpif->upcall_lock);
> > -    error = dpif_netlink_port_add__(dpif, netdev, port_nop);
> > +    error = dpif_netlink_port_create_and_add(dpif, netdev, port_nop);
> > +    if (error == EOPNOTSUPP) {
> > +        error = dpif_netlink_port_add_compat(dpif, netdev, port_nop);
> > +    }
> >      fat_rwlock_unlock(&dpif->upcall_lock);
> >
> >      return error;
> > @@ -946,6 +1032,12 @@ dpif_netlink_port_del__(struct dpif_netlink *dpif, odp_port_t port_no)
> >  {
> >      struct dpif_netlink_vport vport;
> >      int error;
> > +    struct dpif_port dpif_port;
> > +
> > +    error = dpif_netlink_port_query__(dpif, port_no, NULL, &dpif_port);
> > +    if (error) {
> > +        return error;
> > +    }
> 
> I see that the windows code also does this, perhaps we could drop the
> call from the windows-only piece?
> 
> >
> >      dpif_netlink_vport_init(&vport);
> >      vport.cmd = OVS_VPORT_CMD_DEL;
> > @@ -965,6 +1057,9 @@ dpif_netlink_port_del__(struct dpif_netlink *dpif, odp_port_t port_no)
> >
> >      vport_del_channels(dpif, port_no);
> >
> > +    dpif_netlink_port_destroy(dpif_port.name, dpif_port.type);
> 
> Should we check the error here?
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff mbox

Patch

diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index c8b0e37f9365..e6459f358989 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -781,10 +781,8 @@  get_vport_type(const struct dpif_netlink_vport *vport)
 }
 
 static enum ovs_vport_type
-netdev_to_ovs_vport_type(const struct netdev *netdev)
+netdev_to_ovs_vport_type(const char *type)
 {
-    const char *type = netdev_get_type(netdev);
-
     if (!strcmp(type, "tap") || !strcmp(type, "system")) {
         return OVS_VPORT_TYPE_NETDEV;
     } else if (!strcmp(type, "internal")) {
@@ -805,19 +803,14 @@  netdev_to_ovs_vport_type(const struct netdev *netdev)
 }
 
 static int
-dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
+dpif_netlink_port_add__(struct dpif_netlink *dpif, const char *name,
+                        enum ovs_vport_type type,
+                        struct ofpbuf *options,
                         odp_port_t *port_nop)
     OVS_REQ_WRLOCK(dpif->upcall_lock)
 {
-    const struct netdev_tunnel_config *tnl_cfg;
-    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
-    const char *name = netdev_vport_get_dpif_port(netdev,
-                                                  namebuf, sizeof namebuf);
-    const char *type = netdev_get_type(netdev);
     struct dpif_netlink_vport request, reply;
     struct ofpbuf *buf;
-    uint64_t options_stub[64 / 8];
-    struct ofpbuf options;
     struct nl_sock **socksp = NULL;
     uint32_t *upcall_pids;
     int error = 0;
@@ -832,17 +825,80 @@  dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
     dpif_netlink_vport_init(&request);
     request.cmd = OVS_VPORT_CMD_NEW;
     request.dp_ifindex = dpif->dp_ifindex;
-    request.type = netdev_to_ovs_vport_type(netdev);
-    if (request.type == OVS_VPORT_TYPE_UNSPEC) {
+    request.type = type;
+    request.name = name;
+
+    request.port_no = *port_nop;
+    upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers);
+    request.n_upcall_pids = socksp ? dpif->n_handlers : 1;
+    request.upcall_pids = upcall_pids;
+
+    if (options) {
+        request.options = options->data;
+        request.options_len = options->size;
+    }
+
+    error = dpif_netlink_vport_transact(&request, &reply, &buf);
+    if (!error) {
+        *port_nop = reply.port_no;
+    } else {
+        if (error == EBUSY && *port_nop != ODPP_NONE) {
+            VLOG_INFO("%s: requested port %"PRIu32" is in use",
+                      dpif_name(&dpif->dpif), *port_nop);
+        }
+
+        vport_del_socksp(dpif, socksp);
+        goto exit;
+    }
+
+    if (socksp) {
+        error = vport_add_channels(dpif, *port_nop, socksp);
+        if (error) {
+            VLOG_INFO("%s: could not add channel for port %s",
+                      dpif_name(&dpif->dpif), name);
+
+            /* Delete the port. */
+            dpif_netlink_vport_init(&request);
+            request.cmd = OVS_VPORT_CMD_DEL;
+            request.dp_ifindex = dpif->dp_ifindex;
+            request.port_no = *port_nop;
+            dpif_netlink_vport_transact(&request, NULL, NULL);
+            vport_del_socksp(dpif, socksp);
+            goto exit;
+        }
+    }
+    free(socksp);
+
+exit:
+    ofpbuf_delete(buf);
+    free(upcall_pids);
+
+    return error;
+}
+
+static int
+dpif_netlink_port_add_compat(struct dpif_netlink *dpif, struct netdev *netdev,
+                             odp_port_t *port_nop)
+    OVS_REQ_WRLOCK(dpif->upcall_lock)
+{
+    const struct netdev_tunnel_config *tnl_cfg;
+    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
+    const char *name = netdev_vport_get_dpif_port(netdev,
+                                                  namebuf, sizeof namebuf);
+    const char *type = netdev_get_type(netdev);
+    uint64_t options_stub[64 / 8];
+    struct ofpbuf options;
+    enum ovs_vport_type ovs_type;
+
+    ovs_type = netdev_to_ovs_vport_type(netdev_get_type(netdev));
+    if (ovs_type == OVS_VPORT_TYPE_UNSPEC) {
         VLOG_WARN_RL(&error_rl, "%s: cannot create port `%s' because it has "
                      "unsupported type `%s'",
                      dpif_name(&dpif->dpif), name, type);
-        vport_del_socksp(dpif, socksp);
         return EINVAL;
     }
-    request.name = name;
 
-    if (request.type == OVS_VPORT_TYPE_NETDEV) {
+    if (ovs_type == OVS_VPORT_TYPE_NETDEV) {
 #ifdef _WIN32
         /* XXX : Map appropiate Windows handle */
 #else
@@ -851,7 +907,7 @@  dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
     }
 
 #ifdef _WIN32
-    if (request.type == OVS_VPORT_TYPE_INTERNAL) {
+    if (ovs_type == OVS_VPORT_TYPE_INTERNAL) {
         if (!create_wmi_port(name)){
             VLOG_ERR("Could not create wmi internal port with name:%s", name);
             vport_del_socksp(dpif, socksp);
@@ -879,50 +935,77 @@  dpif_netlink_port_add__(struct dpif_netlink *dpif, struct netdev *netdev,
             }
             nl_msg_end_nested(&options, ext_ofs);
         }
-        request.options = options.data;
-        request.options_len = options.size;
+        return dpif_netlink_port_add__(dpif, name, ovs_type, &options,
+                                       port_nop);
+    } else {
+        return dpif_netlink_port_add__(dpif, name, ovs_type, NULL, port_nop);
     }
 
-    request.port_no = *port_nop;
-    upcall_pids = vport_socksp_to_pids(socksp, dpif->n_handlers);
-    request.n_upcall_pids = socksp ? dpif->n_handlers : 1;
-    request.upcall_pids = upcall_pids;
+}
 
-    error = dpif_netlink_vport_transact(&request, &reply, &buf);
-    if (!error) {
-        *port_nop = reply.port_no;
-    } else {
-        if (error == EBUSY && *port_nop != ODPP_NONE) {
-            VLOG_INFO("%s: requested port %"PRIu32" is in use",
-                      dpif_name(&dpif->dpif), *port_nop);
-        }
+static int
+dpif_netlink_port_query__(const struct dpif_netlink *dpif, odp_port_t port_no,
+                          const char *port_name, struct dpif_port *dpif_port);
 
-        vport_del_socksp(dpif, socksp);
-        goto exit;
+static int
+dpif_netlink_port_create(struct netdev *netdev)
+{
+    switch (netdev_to_ovs_vport_type(netdev_get_type(netdev))) {
+    case OVS_VPORT_TYPE_VXLAN:
+    case OVS_VPORT_TYPE_GRE:
+    case OVS_VPORT_TYPE_GENEVE:
+    case OVS_VPORT_TYPE_NETDEV:
+    case OVS_VPORT_TYPE_INTERNAL:
+    case OVS_VPORT_TYPE_LISP:
+    case OVS_VPORT_TYPE_STT:
+    case OVS_VPORT_TYPE_UNSPEC:
+    case __OVS_VPORT_TYPE_MAX:
+    default:
+        return EOPNOTSUPP;
     }
+    return 0;
+}
 
-    if (socksp) {
-        error = vport_add_channels(dpif, *port_nop, socksp);
-        if (error) {
-            VLOG_INFO("%s: could not add channel for port %s",
-                      dpif_name(&dpif->dpif), name);
-
-            /* Delete the port. */
-            dpif_netlink_vport_init(&request);
-            request.cmd = OVS_VPORT_CMD_DEL;
-            request.dp_ifindex = dpif->dp_ifindex;
-            request.port_no = *port_nop;
-            dpif_netlink_vport_transact(&request, NULL, NULL);
-            vport_del_socksp(dpif, socksp);
-            goto exit;
-        }
+static int
+dpif_netlink_port_destroy(const char *name OVS_UNUSED, const char *type)
+{
+    switch (netdev_to_ovs_vport_type(type)) {
+    case OVS_VPORT_TYPE_VXLAN:
+    case OVS_VPORT_TYPE_GRE:
+    case OVS_VPORT_TYPE_GENEVE:
+    case OVS_VPORT_TYPE_NETDEV:
+    case OVS_VPORT_TYPE_INTERNAL:
+    case OVS_VPORT_TYPE_LISP:
+    case OVS_VPORT_TYPE_STT:
+    case OVS_VPORT_TYPE_UNSPEC:
+    case __OVS_VPORT_TYPE_MAX:
+    default:
+        return EOPNOTSUPP;
     }
-    free(socksp);
+    return 0;
+}
 
-exit:
-    ofpbuf_delete(buf);
-    free(upcall_pids);
+static int
+dpif_netlink_port_create_and_add(struct dpif_netlink *dpif,
+                                 struct netdev *netdev, odp_port_t *port_nop)
+    OVS_REQ_WRLOCK(dpif->upcall_lock)
+{
+    int error;
+    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
+    const char *name = netdev_vport_get_dpif_port(netdev,
+                                                  namebuf, sizeof namebuf);
+
+    error = dpif_netlink_port_create(netdev);
+    if (error) {
+        return error;
+    }
 
+    error = dpif_netlink_port_add__(dpif, name, OVS_VPORT_TYPE_NETDEV, NULL,
+                                    port_nop);
+    if (error) {
+        VLOG_DBG("failed to add port, destroying: %d", error);
+        dpif_netlink_port_destroy(name, netdev_get_type(netdev));
+    }
     return error;
 }
 
@@ -934,7 +1017,10 @@  dpif_netlink_port_add(struct dpif *dpif_, struct netdev *netdev,
     int error;
 
     fat_rwlock_wrlock(&dpif->upcall_lock);
-    error = dpif_netlink_port_add__(dpif, netdev, port_nop);
+    error = dpif_netlink_port_create_and_add(dpif, netdev, port_nop);
+    if (error == EOPNOTSUPP) {
+        error = dpif_netlink_port_add_compat(dpif, netdev, port_nop);
+    }
     fat_rwlock_unlock(&dpif->upcall_lock);
 
     return error;
@@ -946,6 +1032,12 @@  dpif_netlink_port_del__(struct dpif_netlink *dpif, odp_port_t port_no)
 {
     struct dpif_netlink_vport vport;
     int error;
+    struct dpif_port dpif_port;
+
+    error = dpif_netlink_port_query__(dpif, port_no, NULL, &dpif_port);
+    if (error) {
+        return error;
+    }
 
     dpif_netlink_vport_init(&vport);
     vport.cmd = OVS_VPORT_CMD_DEL;
@@ -965,6 +1057,9 @@  dpif_netlink_port_del__(struct dpif_netlink *dpif, odp_port_t port_no)
 
     vport_del_channels(dpif, port_no);
 
+    dpif_netlink_port_destroy(dpif_port.name, dpif_port.type);
+    dpif_port_destroy(&dpif_port);
+
     return error;
 }