[ovs-dev] [ovn-controller-vtep V6 5/7] ovn-controller-vtep: Add vtep module.

Alex Wang alexw at nicira.com
Mon Aug 17 00:45:07 UTC 2015


On Sun, Aug 16, 2015 at 3:00 PM, Russell Bryant <rbryant at redhat.com> wrote:

> On 08/09/2015 10:50 PM, Alex Wang wrote:
> > This commit adds the vtep module to ovn-controller-vtep.  The
> > module will scan through the Port_Binding table in OVN-SB database,
> > and update the vtep logcial switches tunnel keys.
> >
> > Signed-off-by: Alex Wang <alexw at nicira.com>
> > ---
> > V5->V6:
> > - rebase.
> >
> > V5: new patch.
> > ---
> >  ovn/controller-vtep/automake.mk           |    4 +-
> >  ovn/controller-vtep/ovn-controller-vtep.c |    3 +
> >  ovn/controller-vtep/vtep.c                |  134
> +++++++++++++++++++++++++++++
> >  ovn/controller-vtep/vtep.h                |   27 ++++++
> >  tests/ovn-controller-vtep.at              |   32 +++++++
> >  5 files changed, 199 insertions(+), 1 deletion(-)
> >  create mode 100644 ovn/controller-vtep/vtep.c
> >  create mode 100644 ovn/controller-vtep/vtep.h
> >
> > diff --git a/ovn/controller-vtep/automake.mk b/ovn/controller-vtep/
> automake.mk
> > index 33f063f..cacfae6 100644
> > --- a/ovn/controller-vtep/automake.mk
> > +++ b/ovn/controller-vtep/automake.mk
> > @@ -5,7 +5,9 @@ ovn_controller_vtep_ovn_controller_vtep_SOURCES = \
> >       ovn/controller-vtep/gateway.c \
> >       ovn/controller-vtep/gateway.h \
> >       ovn/controller-vtep/ovn-controller-vtep.c \
> > -     ovn/controller-vtep/ovn-controller-vtep.h
> > +     ovn/controller-vtep/ovn-controller-vtep.h \
> > +     ovn/controller-vtep/vtep.c \
> > +     ovn/controller-vtep/vtep.h
> >  ovn_controller_vtep_ovn_controller_vtep_LDADD = ovn/lib/libovn.la lib/
> libopenvswitch.la vtep/libvtep.la
> >  man_MANS += ovn/controller-vtep/ovn-controller-vtep.8
> >  EXTRA_DIST += ovn/controller-vtep/ovn-controller-vtep.8.xml
> > diff --git a/ovn/controller-vtep/ovn-controller-vtep.c
> b/ovn/controller-vtep/ovn-controller-vtep.c
> > index a3b0f96..9b7838a 100644
> > --- a/ovn/controller-vtep/ovn-controller-vtep.c
> > +++ b/ovn/controller-vtep/ovn-controller-vtep.c
> > @@ -39,6 +39,7 @@
> >
> >  #include "binding.h"
> >  #include "gateway.h"
> > +#include "vtep.h"
> >  #include "ovn-controller-vtep.h"
> >
> >  static unixctl_cb_func ovn_controller_vtep_exit;
> > @@ -97,6 +98,7 @@ main(int argc, char *argv[])
> >
> >          gateway_run(&ctx);
> >          binding_run(&ctx);
> > +        vtep_run(&ctx);
> >          unixctl_server_run(unixctl);
> >
> >          unixctl_server_wait(unixctl);
> > @@ -122,6 +124,7 @@ main(int argc, char *argv[])
> >           * We're done if all of them return true. */
> >          done = gateway_cleanup(&ctx);
> >          done = binding_cleanup(&ctx) && done;
> > +        done = vtep_cleanup(&ctx) && done;
> >          if (done) {
> >              poll_immediate_wake();
> >          }
> > diff --git a/ovn/controller-vtep/vtep.c b/ovn/controller-vtep/vtep.c
> > new file mode 100644
> > index 0000000..55d2e0d
> > --- /dev/null
> > +++ b/ovn/controller-vtep/vtep.c
> > @@ -0,0 +1,134 @@
> > +/* Copyright (c) 2015 Nicira, Inc.
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at:
> > + *
> > + *     http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + */
> > +
> > +#include <config.h>
> > +
> > +#include "vtep.h"
> > +
> > +#include "lib/hash.h"
> > +#include "lib/hmap.h"
> > +#include "lib/smap.h"
> > +#include "lib/util.h"
> > +#include "ovn-controller-vtep.h"
> > +#include "openvswitch/vlog.h"
> > +#include "ovn/lib/ovn-sb-idl.h"
> > +#include "vtep/vtep-idl.h"
> > +
> > +VLOG_DEFINE_THIS_MODULE(vtep);
> > +
> > +/*
> > + * Scans through the Binding table in ovnsb and updates the vtep logical
> > + * switch tunnel keys.
> > + *
> > + */
> > +
> > +/* Updates the vtep Logical_Switch table entries' tunnel keys based
> > + * on the port bindings. */
> > +static void
> > +vtep_lswitch_run(struct controller_vtep_ctx *ctx)
> > +{
> > +    struct shash vtep_lswitches = SHASH_INITIALIZER(&vtep_lswitches);
> > +    const struct sbrec_port_binding *port_binding_rec;
> > +    const struct vteprec_logical_switch *vtep_ls;
> > +
> > +    /* Stores all logical switches to 'vtep_lswitches' with name as
> key. */
> > +    VTEPREC_LOGICAL_SWITCH_FOR_EACH (vtep_ls, ctx->vtep_idl) {
> > +        shash_add(&vtep_lswitches, vtep_ls->name, vtep_ls);
> > +    }
> > +
> > +    ovsdb_idl_txn_add_comment(ctx->vtep_idl_txn,
> > +                              "ovn-controller-vtep: update logical
> switch "
> > +                              "tunnel keys");
> > +    /* Collects the logical switch bindings from port binding entries.
> > +     * Since the binding module has already guaranteed that each vtep
> > +     * logical switch is bound only to one ovn-sb logical datapath,
> > +     * we can just iterate and assign tunnel key to vtep logical
> switch. */
> > +    SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->ovnsb_idl) {
>
> What would you think about doing all of this in binding.c instead?  The
> code already iterates the port bindings there.  The port bindings table
> can easily have many thousands of entries.
>
> If you'd rather keep it logically separated like this and wait until we
> see what shows up in profiling, that's fine too, it was just a thought.
>
>

Yeah, I'd like to delay it until later when we have a better understanding
of
all things that need to access or iterate Port_Binding entries (e.g. the
update
of ucast_macs_remote/ucast_macs_local tables in VTEP database).



> > +        if (!strcmp(port_binding_rec->type, "vtep")
> > +            && port_binding_rec->chassis) {
>
> This is just a small style thing that you can ignore if you want.
>
> The whole body of this loop is within this if block.  I'd be tempted to
> reverse the condition to reduce nesting by 1 level for the main body of
> the loop.
>
>     if (strcmp(port_binding_rec->type, "vtep") ||
> !port_binding_rec->chassis) {
>         continue;
>     }
>
>     ... main body of loop ...
>
>
Sure, I'd like to adopt~



> > +            const char *lswitch_name =
> smap_get(&port_binding_rec->options,
> > +                                                "vtep-logical-switch");
> > +
> > +            /* If 'port_binding_rec->chassis' exists then 'lswitch_name'
> > +             * must also exist. */
> > +            ovs_assert(lswitch_name);
>
> It looks like a misconfiguration, or even just a race condition, could
> cause every running instance of ovs-controller-vtep to exit when it hits
> this line.  I just have to create a port with type=vtep, but not set the
> vtep-logical-switch option.  It could be that a client just didn't
> create the port, set the type, and set the options all in the same
> transaction.
>
> I think I'd just log a rate limited warning here and continue instead.



My thought is that, since 'vtep_run()' is called after 'binding_run()', any
'Port_Binding' entry with type 'vtep' and has 'chassis' column filled must
also have this 'lswitch_name'.  Regarding the situation you mentioned above,
the 'binding_run()' will not set the 'chassis' column at all.

However, on a second thought, there is still one corner case this assert
could be hit.  If user does not set the 'vtep-logical-switch' in 'options'
but
use 'ovn-sbctl' to bind the logical port with chassis...  So, I'd like to
change
that to use VLOG_ERR.


> +            vtep_ls = shash_find_and_delete(&vtep_lswitches,
> lswitch_name);
> > +            if (!vtep_ls) {
> > +                VLOG_ERR("logical port (%s) bound to non-exist vtep
> logical "
> > +                         "switch (%s), something is seriously wrong",
> > +                         port_binding_rec->logical_port, lswitch_name);
> > +            } else {
> > +                int64_t tnl_key;
> > +
> > +                tnl_key = port_binding_rec->datapath->tunnel_key;
> > +                if (vtep_ls->n_tunnel_key
> > +                    && vtep_ls->tunnel_key[0] != tnl_key) {
> > +                    VLOG_DBG("set vtep logical switch (%s) tunnel key
> from "
> > +                             "(%"PRId64") to (%"PRId64")",
> vtep_ls->name,
> > +                             vtep_ls->tunnel_key[0], tnl_key);
> > +                }
> > +                vteprec_logical_switch_set_tunnel_key(vtep_ls,
> &tnl_key, 1);
> > +            }
> > +        }
> > +    }
> > +    struct shash_node *node;
> > +    /* Resets the tunnel keys for the rest of vtep logical switches. */
> > +    SHASH_FOR_EACH (node, &vtep_lswitches) {
> > +        int64_t tnl_key = 0;
> > +
> > +        vteprec_logical_switch_set_tunnel_key(node->data, &tnl_key, 1);
> > +    }
> > +
> > +    shash_destroy(&vtep_lswitches);
> > +}
> > +
> > +/* Since we do not own any vtep logical switch, just sets their tunnel
> key
> > + * to 0. */
> > +static void
> > +vtep_lswitch_cleanup(struct ovsdb_idl *vtep_idl)
> > +{
> > +    const struct vteprec_logical_switch *vtep_ls;
> > +    int64_t tnl_key = 0;
> > +
> > +    VTEPREC_LOGICAL_SWITCH_FOR_EACH (vtep_ls, vtep_idl) {
> > +        vteprec_logical_switch_set_tunnel_key(vtep_ls, &tnl_key, 1);
> > +    }
> > +}
> > +
> > +
> > +/* Updates vtep logical switch tunnel keys. */
> > +void
> > +vtep_run(struct controller_vtep_ctx *ctx)
> > +{
> > +    if (!ctx->vtep_idl_txn) {
> > +        return;
> > +    }
> > +    vtep_lswitch_run(ctx);
> > +}
> > +
> > +/* Cleans up all created vtep related entries.  Returns true when all
> done. */
> > +bool
> > +vtep_cleanup(struct controller_vtep_ctx *ctx)
> > +{
> > +    if (!ctx->vtep_idl_txn) {
> > +        return false;
> > +    }
> > +
> > +    ovsdb_idl_txn_add_comment(ctx->vtep_idl_txn,
> > +                              "cleans up vtep configuration");
> > +    vtep_lswitch_cleanup(ctx->vtep_idl);
> > +
> > +    return true;
>
> Should vtep_switch_cleanup() return whether it had to make any changes?
>  In that case it should return false, right?
>
> Right now it's relying on the IDL to figure out if any changes will
> actually get added to the transaction or not, but it seems like you need
> to look at the old value so you can return true/false here.
>
>

Makes sense, I'll adjust accordingly,

Thanks,
Alex Wang,




> > +}
> > diff --git a/ovn/controller-vtep/vtep.h b/ovn/controller-vtep/vtep.h
> > new file mode 100644
> > index 0000000..ae6c79b
> > --- /dev/null
> > +++ b/ovn/controller-vtep/vtep.h
> > @@ -0,0 +1,27 @@
> > +/* Copyright (c) 2015 Nicira, Inc.
> > + *
> > + * Licensed under the Apache License, Version 2.0 (the "License");
> > + * you may not use this file except in compliance with the License.
> > + * You may obtain a copy of the License at:
> > + *
> > + *     http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + */
> > +
> > +
> > +#ifndef OVN_VTEP_H
> > +#define OVN_VTEP_H 1
> > +
> > +#include <stdbool.h>
> > +
> > +struct controller_vtep_ctx;
> > +
> > +void vtep_run(struct controller_vtep_ctx *);
> > +bool vtep_cleanup(struct controller_vtep_ctx *);
> > +
> > +#endif /* ovn/controller-gw/vtep.h */
> > diff --git a/tests/ovn-controller-vtep.at b/tests/ovn-controller-vtep.at
> > index 3ff0b93..ea58636 100644
> > --- a/tests/ovn-controller-vtep.at
> > +++ b/tests/ovn-controller-vtep.at
> > @@ -262,3 +262,35 @@ ${chassis_uuid}
> >
> >  OVN_CONTROLLER_VTEP_STOP(["/has already been associated with logical
> datapath/d"])
> >  AT_CLEANUP
> > +
> > +
> > +# Tests vtep module vtep logical switch tunnel key update.
> > +AT_SETUP([ovn-controller-vtep - test vtep-lswitch])
> > +OVN_CONTROLLER_VTEP_START
> > +
> > +# creates the logical switch in vtep and adds the corresponding logical
> > +# port to 'br-test'.
> > +AT_CHECK([vtep-ctl add-ls lswitch0 -- bind-ls br-vtep p0 100 lswitch0])
> > +OVN_NB_ADD_VTEP_PORT([br-test], [br-vtep_lswitch0], [br-vtep],
> [lswitch0])
> > +OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding  | grep
> br-vtep_lswitch0`"])
> > +
> > +# retrieves the expected tunnel key.
> > +datapath_uuid=$(ovn-sbctl --columns=datapath list Port_Binding
> br-vtep_lswitch0 | cut -d ':' -f2 | tr -d ' ')
> > +tunnel_key=$(ovn-sbctl --columns=tunnel_key list Datapath_Binding
> ${datapath_uuid} | cut -d ':' -f2 | tr -d ' ')
> > +OVS_WAIT_UNTIL([test -z "`vtep-ctl --columns=tunnel_key list
> Logical_Switch | grep 0`"])
> > +# checks the vtep logical switch tunnel key configuration.
> > +AT_CHECK_UNQUOTED([vtep-ctl --columns=tunnel_key list Logical_Switch |
> cut -d ':' -f2 | tr -d ' '], [0], [dnl
> > +${tunnel_key}
> > +])
> > +
> > +# changes the ovn-nb logical port type so that it is no longer
> > +# vtep port.
> > +AT_CHECK([ovn-nbctl lport-set-type br-vtep_lswitch0 void])
> > +OVS_WAIT_UNTIL([test -z "`vtep-ctl --columns=tunnel_key list
> Logical_Switch | grep 1`"])
> > +# now should see the tunnel key reset.
> > +AT_CHECK([vtep-ctl --columns=tunnel_key list Logical_Switch | cut -d
> ':' -f2 | tr -d ' '], [0], [dnl
> > +0
> > +])
> > +
> > +OVN_CONTROLLER_VTEP_STOP
> > +AT_CLEANUP
> >
>
>
> --
> Russell Bryant
>



More information about the dev mailing list