On 12 July 2017 at 06:36, Miguel Angel Ajo Pelayo <majop...@redhat.com>
wrote:

> This patch in the series still has the race condition where all the chassis
> the Gateway_Chassis list of a chassisredirect port will try to fight for
> the chassis column of Port_Binding. Other than that it works.
>
> Later, the "ovn: l3ha, make is_chassis_active aware of gateway_chassis"
> fixes
> this behaviour where only MASTER chassis will bind the port in the SBDB.
>
> As long as the whole series is applied at once this must be ok.
>

Miguel,
 For your series, have you run: make check-kernel TESTSUITEFLAGS="-k ovn".


>
>
> On Wed, Jul 12, 2017 at 3:12 PM, Miguel Angel Ajo <majop...@redhat.com>
> wrote:
>
> > From: "majop...@redhat.com" <majop...@redhat.com>
> >
> > This patch handles multiple gateway_chassis within chassisredirect
> > ports. All the gateway_chassis within chassisredirect port
> > will implement the rules to de-encapsulate incoming packets
> > for such port (please note that later patches in the series
> > will make is_chassis_redirect conditionals aware of the
> > MASTER/BACKUP status of the chassis).
> >
> > Hosts targeting a remote chassisredirect port will setup a
> > bundle(active_backup, ..) action to each tunnel port, in the given
> > priority order. Following patches will enable BFD to detect
> > when a remote gateway chassis is no longer reachable.
> >
> > Co-authored-by: Venkata Anil Kommaddi <vkomm...@redhat.com>
> > Signed-off-by: Miguel Angel Ajo <majop...@redhat.com>
> > Signed-off-by: Venkata Anil Kommaddi <vkomm...@redhat.com>
> > ---
> >  ovn/controller/automake.mk      |   2 +
> >  ovn/controller/binding.c        |  13 +-
> >  ovn/controller/binding.h        |   1 +
> >  ovn/controller/gchassis.c       | 176 +++++++++++++++++++++
> >  ovn/controller/gchassis.h       |  63 ++++++++
> >  ovn/controller/lflow.c          |   7 +-
> >  ovn/controller/lport.h          |   4 +
> >  ovn/controller/ovn-controller.c |  16 +-
> >  ovn/controller/physical.c       | 130 +++++++++++++---
> >  ovn/controller/physical.h       |   4 +-
> >  ovn/northd/ovn-northd.c         |   8 +-
> >  tests/ovn-northd.at             |   2 -
> >  tests/ovn.at                    | 329 ++++++++++++++++++++++++++++++
> > +++++++++-
> >  13 files changed, 718 insertions(+), 37 deletions(-)
> >  create mode 100644 ovn/controller/gchassis.c
> >  create mode 100644 ovn/controller/gchassis.h
> >
> > diff --git a/ovn/controller/automake.mk b/ovn/controller/automake.mk
> > index 8c6a787..d3828f5 100644
> > --- a/ovn/controller/automake.mk
> > +++ b/ovn/controller/automake.mk
> > @@ -6,6 +6,8 @@ ovn_controller_ovn_controller_SOURCES = \
> >         ovn/controller/chassis.h \
> >         ovn/controller/encaps.c \
> >         ovn/controller/encaps.h \
> > +       ovn/controller/gchassis.c \
> > +       ovn/controller/gchassis.h \
> >         ovn/controller/lflow.c \
> >         ovn/controller/lflow.h \
> >         ovn/controller/lport.c \
> > diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
> > index 11145dd..cc4563d 100644
> > --- a/ovn/controller/binding.c
> > +++ b/ovn/controller/binding.c
> > @@ -15,6 +15,7 @@
> >
> >  #include <config.h>
> >  #include "binding.h"
> > +#include "gchassis.h"
> >  #include "lflow.h"
> >  #include "lport.h"
> >
> > @@ -26,6 +27,7 @@
> >  #include "lib/vswitch-idl.h"
> >  #include "openvswitch/hmap.h"
> >  #include "openvswitch/vlog.h"
> > +#include "ovn/lib/chassis-index.h"
> >  #include "ovn/lib/ovn-sb-idl.h"
> >  #include "ovn-controller.h"
> >
> > @@ -394,12 +396,15 @@ consider_local_datapath(struct controller_ctx *ctx,
> >                                 false, local_datapaths);
> >          }
> >      } else if (!strcmp(binding_rec->type, "chassisredirect")) {
> > -        const char *chassis_id = smap_get(&binding_rec->options,
> > -                                          "redirect-chassis");
> > -        our_chassis = chassis_id && !strcmp(chassis_id,
> > chassis_rec->name);
> > -        if (our_chassis) {
> > +        if (gateway_chassis_in_pb_contains(binding_rec, chassis_rec)) {
> >              add_local_datapath(ldatapaths, lports,
> binding_rec->datapath,
> >                                 false, local_datapaths);
> > +            /* XXX this should only be set to true if our chassis
> > +             * (chassis_rec) is the master for this chassisredirect port
> > +             * but for now we'll bind it only when not bound, this is
> > +             * handled in subsequent patches */
> > +            our_chassis = !binding_rec->chassis ||
> > +                chassis_rec == binding_rec->chassis;
> >          }
> >      } else if (!strcmp(binding_rec->type, "l3gateway")) {
> >          const char *chassis_id = smap_get(&binding_rec->options,
> > diff --git a/ovn/controller/binding.h b/ovn/controller/binding.h
> > index 3bfa7d1..136b3a7 100644
> > --- a/ovn/controller/binding.h
> > +++ b/ovn/controller/binding.h
> > @@ -20,6 +20,7 @@
> >  #include <stdbool.h>
> >
> >  struct controller_ctx;
> > +struct chassis_index;
> >  struct hmap;
> >  struct ldatapath_index;
> >  struct lport_index;
> > diff --git a/ovn/controller/gchassis.c b/ovn/controller/gchassis.c
> > new file mode 100644
> > index 0000000..f165f59
> > --- /dev/null
> > +++ b/ovn/controller/gchassis.c
> > @@ -0,0 +1,176 @@
> > +/* Copyright (c) 2017, Red Hat, 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 "gchassis.h"
> > +#include "lport.h"
> > +#include "openvswitch/vlog.h"
> > +#include "ovn/lib/chassis-index.h"
> > +#include "ovn/lib/ovn-sb-idl.h"
> > +
> > +VLOG_DEFINE_THIS_MODULE(gchassis);
> > +
> > +/* gateway_chassis ordering
> > + */
> > +static int
> > +compare_chassis_prio_(const void *a_, const void *b_)
> > +{
> > +    const struct gateway_chassis *gc_a = a_;
> > +    const struct gateway_chassis *gc_b = b_;
> > +    int prio_diff = gc_b->db->priority - gc_a->db->priority;
> > +    if (!prio_diff) {
> > +        return strcmp(gc_b->db->name, gc_a->db->name);
> > +    }
> > +    return prio_diff;
> > +}
> > +
> > +struct ovs_list*
> > +gateway_chassis_get_ordered(const struct sbrec_port_binding *binding,
> > +                            const struct chassis_index *chassis_index)
> > +{
> > +    const char *redir_chassis_str;
> > +    const struct sbrec_chassis *redirect_chassis = NULL;
> > +
> > +    /* XXX: redirect-chassis SBDB option handling is supported for
> > backwards
> > +     * compatibility with N-1 version of ovn-northd. This support can
> > +     * be removed in OVS 2.9 where Gateway_Chassis list on the port
> > binding
> > +     * will always be populated by northd */
> > +    redir_chassis_str = smap_get(&binding->options, "redirect-chassis");
> > +
> > +    if (redir_chassis_str) {
> > +        redirect_chassis = chassis_lookup_by_name(chassis_index,
> > +                                                  redir_chassis_str);
> > +        if (!redirect_chassis) {
> > +            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1,
> 1);
> > +            VLOG_WARN_RL(&rl, "chassis name (%s) in redirect-chassis
> > option "
> > +                              "of logical port %s not known",
> > +                              redir_chassis_str, binding->logical_port);
> > +        }
> > +    }
> > +
> > +    if (!redirect_chassis && binding->n_gateway_chassis == 0) {
> > +        return NULL;
> > +    }
> > +
> > +    struct gateway_chassis *gateway_chassis = NULL;
> > +    int n = 0;
> > +
> > +    if (binding->n_gateway_chassis) {
> > +        gateway_chassis = xmalloc(sizeof *gateway_chassis *
> > +                                  binding->n_gateway_chassis);
> > +        for (n = 0; n < binding->n_gateway_chassis; n++) {
> > +            gateway_chassis[n].db = binding->gateway_chassis[n];
> > +            gateway_chassis[n].virtual_gwc = false;
> > +        }
> > +        qsort(gateway_chassis, n, sizeof *gateway_chassis,
> > +              compare_chassis_prio_);
> > +    } else if (redirect_chassis) {
> > +        /* When only redirect_chassis is available, return a single
> > +         * virtual entry that it's not on OVSDB, this way the code
> > +         * handling the returned list will be uniform, regardless
> > +         * of gateway_chassis being populated or redirect-chassis option
> > +         * being used */
> > +        gateway_chassis = xmalloc(sizeof *gateway_chassis);
> > +        struct sbrec_gateway_chassis *gwc =
> > +            xzalloc(sizeof *gateway_chassis->db);
> > +        sbrec_gateway_chassis_init(gwc);
> > +        gwc->name = xasprintf("%s_%s", binding->logical_port,
> > +                                       redirect_chassis->name);
> > +        gwc->chassis = CONST_CAST(struct sbrec_chassis *,
> > redirect_chassis);
> > +        gateway_chassis->db = gwc;
> > +        gateway_chassis->virtual_gwc = true;
> > +        n++;
> > +    }
> > +
> > +    struct ovs_list *list = NULL;
> > +    if (n) {
> > +        list = xmalloc(sizeof *list);
> > +        ovs_list_init(list);
> > +
> > +        int i;
> > +        for (i = 0; i < n; i++) {
> > +            ovs_list_push_back(list, &gateway_chassis[i].node);
> > +        }
> > +    }
> > +
> > +    return list;
> > +}
> > +
> > +bool
> > +gateway_chassis_contains(struct ovs_list *gateway_chassis,
> > +                         const struct sbrec_chassis *chassis) {
> > +    struct gateway_chassis *chassis_item;
> > +    if (gateway_chassis) {
> > +        LIST_FOR_EACH (chassis_item, node, gateway_chassis) {
> > +            if (chassis_item->db->chassis
> > +                && !strcmp(chassis_item->db->chassis->name,
> > chassis->name)) {
> > +                return true;
> > +            }
> > +        }
> > +    }
> > +    return false;
> > +}
> > +
> > +void
> > +gateway_chassis_destroy(struct ovs_list *list)
> > +{
> > +    if (!list) {
> > +        return;
> > +    }
> > +
> > +    /* XXX: This loop is for backwards compatibility with
> redirect-chassis
> > +     * which we insert as a single virtual Gateway_Chassis on the
> ordered
> > +     * list */
> > +    struct gateway_chassis *chassis_item;
> > +    LIST_FOR_EACH (chassis_item, node, list) {
> > +        if (chassis_item->virtual_gwc) {
> > +            free(chassis_item->db->name);
> > +            free(CONST_CAST(struct sbrec_gateway_chassis *,
> > chassis_item->db));
> > +        }
> > +    }
> > +
> > +    free(ovs_list_front(list));
> > +    free(list);
> > +}
> > +
> > +bool
> > +gateway_chassis_in_pb_contains(const struct sbrec_port_binding
> *binding,
> > +                               const struct sbrec_chassis *chassis)
> > +{
> > +    if (!binding || !chassis) {
> > +        return false;
> > +    }
> > +
> > +    /* XXX: redirect-chassis handling for backwards compatibility,
> > +     * with older ovs-northd during upgrade phase, can be removed
> > +     * for OVS 2.9 */
> > +    const char *redirect_chassis = smap_get(&binding->options,
> > +                                            "redirect-chassis");
> > +    if (binding->n_gateway_chassis) {
> > +        int n;
> > +        for (n=0; n < binding->n_gateway_chassis; n++) {
> > +            if (binding->gateway_chassis[n]->chassis
> > +                && !strcmp(binding->gateway_chassis[n]->chassis->name,
> > +                           chassis->name)) {
> > +                return true;
> > +            }
> > +        }
> > +    } else if (redirect_chassis) {
> > +        return !strcmp(redirect_chassis, chassis->name);
> > +    }
> > +
> > +    return false;
> > +}
> > diff --git a/ovn/controller/gchassis.h b/ovn/controller/gchassis.h
> > new file mode 100644
> > index 0000000..46d5e42
> > --- /dev/null
> > +++ b/ovn/controller/gchassis.h
> > @@ -0,0 +1,63 @@
> > +/* Copyright (c) 2017 Red Hat, 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_GCHASSIS_H
> > +#define OVN_GCHASSIS_H 1
> > +
> > +#include <stdint.h>
> > +#include "lib/uuid.h"
> > +#include "openvswitch/hmap.h"
> > +#include "openvswitch/list.h"
> > +
> > +struct chassis_index;
> > +struct ovsdb_idl;
> > +struct sbrec_chassis;
> > +struct sbrec_gateway_chassis;
> > +struct sbrec_port_binding;
> > +
> > +
> > +/* Gateway_Chassis management
> > + * ==========================
> > + *
> > + * The following structure and methods handle ordering of
> Gateway_Chassis
> > + * entries in a chassisredirect port. And parsing redirect-chassis
> option
> > + * for backwards compatibility with older (N-1 version of ovn-northd).
> > + */
> > +struct gateway_chassis {
> > +    struct ovs_list node;
> > +    const struct sbrec_gateway_chassis *db; /* sbrec row for the gwc */
> > +    bool virtual_gwc; /* db entry not from SBDB, but from
> > redirect-chassis */
> > +};
> > +
> > +/* Gets, and orders by priority/name the list of Gateway_Chassis */
> > +struct ovs_list *gateway_chassis_get_ordered(
> > +        const struct sbrec_port_binding *binding,
> > +        const struct chassis_index *chassis_index);
> > +
> > +/* Checks if an specific chassis is contained in the gateway_chassis
> > + * list */
> > +bool gateway_chassis_contains(struct ovs_list *gateway_chassis,
> > +                              const struct sbrec_chassis *chassis);
> > +
> > +/* Destroy a gateway_chassis list from memory */
> > +void gateway_chassis_destroy(struct ovs_list *list);
> > +
> > +/* Checks if a chassis is referenced in the port_binding gateway_chassis
> > + * list or redirect-chassis option (backwards compatibility) */
> > +bool gateway_chassis_in_pb_contains(
> > +        const struct sbrec_port_binding *binding,
> > +        const struct sbrec_chassis *chassis);
> > +
> > +#endif /* ovn/controller/gchassis.h */
> > diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
> > index b1b4b23..8cc5e7e 100644
> > --- a/ovn/controller/lflow.c
> > +++ b/ovn/controller/lflow.c
> > @@ -14,6 +14,7 @@
> >   */
> >
> >  #include <config.h>
> > +#include "gchassis.h"
> >  #include "lflow.h"
> >  #include "lport.h"
> >  #include "ofctrl.h"
> > @@ -96,7 +97,11 @@ is_chassis_resident_cb(const void *c_aux_, const char
> > *port_name)
> >
> >      const struct sbrec_port_binding *pb
> >          = lport_lookup_by_name(c_aux->lports, port_name);
> > -    return pb && pb->chassis && pb->chassis == c_aux->chassis;
> > +    if (pb && pb->chassis && pb->chassis == c_aux->chassis) {
> > +        return true;
> > +    } else {
> > +        return gateway_chassis_in_pb_contains(pb, c_aux->chassis);
> > +    }
> >  }
> >
> >  static bool
> > diff --git a/ovn/controller/lport.h b/ovn/controller/lport.h
> > index fe0e430..8937ecb 100644
> > --- a/ovn/controller/lport.h
> > +++ b/ovn/controller/lport.h
> > @@ -17,10 +17,14 @@
> >  #define OVN_LPORT_H 1
> >
> >  #include <stdint.h>
> > +#include "lib/uuid.h"
> >  #include "openvswitch/hmap.h"
> > +#include "openvswitch/list.h"
> >
> >  struct ovsdb_idl;
> > +struct sbrec_chassis;
> >  struct sbrec_datapath_binding;
> > +struct sbrec_port_binding;
> >
> >  /* Database indexes.
> >   * =================
> > diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-
> > controller.c
> > index 45a670b..9fceeca 100644
> > --- a/ovn/controller/ovn-controller.c
> > +++ b/ovn/controller/ovn-controller.c
> > @@ -40,6 +40,7 @@
> >  #include "openvswitch/vconn.h"
> >  #include "openvswitch/vlog.h"
> >  #include "ovn/actions.h"
> > +#include "ovn/lib/chassis-index.h"
> >  #include "ovn/lib/ovn-sb-idl.h"
> >  #include "ovn/lib/ovn-util.h"
> >  #include "patch.h"
> > @@ -148,6 +149,10 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl,
> >      struct ovsdb_idl_condition mg = OVSDB_IDL_CONDITION_INIT(&mg);
> >      struct ovsdb_idl_condition dns = OVSDB_IDL_CONDITION_INIT(&dns);
> >      sbrec_port_binding_add_clause_type(&pb, OVSDB_F_EQ, "patch");
> > +    /* XXX: We can optimize this, if we find a way to only monitor
> > +     * ports that have a Gateway_Chassis that point's to our own
> > +     * chassis */
> > +    sbrec_port_binding_add_clause_type(&pb, OVSDB_F_EQ,
> > "chassisredirect");
> >      if (chassis) {
> >          /* This should be mostly redundant with the other clauses for
> port
> >           * bindings, but it allows us to catch any ports that are
> > assigned to
> > @@ -165,10 +170,6 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl,
> >          sbrec_port_binding_add_clause_options(&pb, OVSDB_F_INCLUDES,
> > &l2);
> >          const struct smap l3 = SMAP_CONST1(&l3, "l3gateway-chassis",
> id);
> >          sbrec_port_binding_add_clause_options(&pb, OVSDB_F_INCLUDES,
> > &l3);
> > -        const struct smap redirect = SMAP_CONST1(&redirect,
> > -                                                 "redirect-chassis",
> id);
> > -        sbrec_port_binding_add_clause_options(&pb, OVSDB_F_INCLUDES,
> > -                                              &redirect);
> >      }
> >      if (local_ifaces) {
> >          const char *name;
> > @@ -627,9 +628,12 @@ main(int argc, char *argv[])
> >          struct ldatapath_index ldatapaths;
> >          struct lport_index lports;
> >          struct mcgroup_index mcgroups;
> > +        struct chassis_index chassis_index;
> > +
> >          ldatapath_index_init(&ldatapaths, ctx.ovnsb_idl);
> >          lport_index_init(&lports, ctx.ovnsb_idl);
> >          mcgroup_index_init(&mcgroups, ctx.ovnsb_idl);
> > +        chassis_index_init(&chassis_index, ctx.ovnsb_idl);
> >
> >          const struct sbrec_chassis *chassis = NULL;
> >          if (chassis_id) {
> > @@ -662,7 +666,8 @@ main(int argc, char *argv[])
> >
> >                      physical_run(&ctx, mff_ovn_geneve,
> >                                   br_int, chassis, &ct_zones, &lports,
> > -                                 &flow_table, &local_datapaths,
> > &local_lports);
> > +                                 &flow_table, &local_datapaths,
> > &local_lports,
> > +                                 &chassis_index);
> >
> >                      ofctrl_put(&flow_table, &pending_ct_zones,
> >                                 get_nb_cfg(ctx.ovnsb_idl));
> > @@ -709,6 +714,7 @@ main(int argc, char *argv[])
> >          mcgroup_index_destroy(&mcgroups);
> >          lport_index_destroy(&lports);
> >          ldatapath_index_destroy(&ldatapaths);
> > +        chassis_index_destroy(&chassis_index);
> >
> >          sset_destroy(&local_lports);
> >
> > diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
> > index 4f0011f..0588d00 100644
> > --- a/ovn/controller/physical.c
> > +++ b/ovn/controller/physical.c
> > @@ -17,16 +17,21 @@
> >  #include "binding.h"
> >  #include "byte-order.h"
> >  #include "flow.h"
> > +#include "gchassis.h"
> >  #include "lflow.h"
> >  #include "lport.h"
> > +#include "lib/bundle.h"
> >  #include "lib/poll-loop.h"
> > +#include "lib/uuid.h"
> >  #include "ofctrl.h"
> > +#include "openvswitch/list.h"
> >  #include "openvswitch/hmap.h"
> >  #include "openvswitch/match.h"
> >  #include "openvswitch/ofp-actions.h"
> >  #include "openvswitch/ofpbuf.h"
> >  #include "openvswitch/vlog.h"
> >  #include "ovn-controller.h"
> > +#include "ovn/lib/chassis-index.h"
> >  #include "ovn/lib/ovn-sb-idl.h"
> >  #include "ovn/lib/ovn-util.h"
> >  #include "physical.h"
> > @@ -289,6 +294,7 @@ static void
> >  consider_port_binding(enum mf_field_id mff_ovn_geneve,
> >                        const struct simap *ct_zones,
> >                        const struct lport_index *lports,
> > +                      const struct chassis_index *chassis_index,
> >                        struct hmap *local_datapaths,
> >                        const struct sbrec_port_binding *binding,
> >                        const struct sbrec_chassis *chassis,
> > @@ -353,8 +359,18 @@ consider_port_binding(enum mf_field_id
> mff_ovn_geneve,
> >          return;
> >      }
> >
> > +    struct ovs_list *gateway_chassis
> > +        = gateway_chassis_get_ordered(binding, chassis_index);
> > +
> > +    /* XXX: later in the series we should insert the next flows only
> > +     * on the active chassis, and not on all of them. This is useful to
> > +     * check that the BFD implementation on following patches has
> > +     * an effect and routes packet by the chassis which is responding,
> > +     * but later on we should not create those flows on all the
> > +     * chassis of the gateway_chassis list */
> >      if (!strcmp(binding->type, "chassisredirect")
> > -        && binding->chassis == chassis) {
> > +        && (binding->chassis == chassis
> > +            || gateway_chassis_contains(gateway_chassis, chassis))) {
> >
> >          /* Table 33, priority 100.
> >           * =======================
> > @@ -413,7 +429,8 @@ consider_port_binding(enum mf_field_id
> mff_ovn_geneve,
> >
> >          ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, 0,
> >                          &match, ofpacts_p);
> > -        return;
> > +
> > +        goto out;
> >      }
> >
> >      /* Find the OpenFlow port for the logical port, as 'ofport'.  This
> is
> > @@ -442,7 +459,7 @@ consider_port_binding(enum mf_field_id
> mff_ovn_geneve,
> >      bool is_remote = false;
> >      if (binding->parent_port && *binding->parent_port) {
> >          if (!binding->tag) {
> > -            return;
> > +            goto out;
> >          }
> >          ofport = u16_to_ofp(simap_get(&localvif_to_ofport,
> >                                        binding->parent_port));
> > @@ -460,27 +477,34 @@ consider_port_binding(enum mf_field_id
> > mff_ovn_geneve,
> >          }
> >      }
> >
> > +    bool is_ha_remote = false;
> >      const struct chassis_tunnel *tun = NULL;
> >      const struct sbrec_port_binding *localnet_port =
> >          get_localnet_port(local_datapaths, dp_key);
> >      if (!ofport) {
> >          /* It is remote port, may be reached by tunnel or localnet port
> */
> >          is_remote = true;
> > -        if (!binding->chassis) {
> > -            return;
> > -        }
> >          if (localnet_port) {
> >              ofport = u16_to_ofp(simap_get(&localvif_to_ofport,
> >                                            localnet_port->logical_port));
> >              if (!ofport) {
> > -                return;
> > +                goto out;
> >              }
> >          } else {
> > -            tun = chassis_tunnel_find(binding->chassis->name);
> > -            if (!tun) {
> > -                return;
> > +            if (!gateway_chassis || ovs_list_is_short(gateway_chassis))
> {
> > +                /* It's on a single remote chassis */
> > +                if (!binding->chassis) {
> > +                    goto out;
> > +                }
> > +                tun = chassis_tunnel_find(binding->chassis->name);
> > +                if (!tun) {
> > +                    goto out;
> > +                }
> > +                ofport = tun->ofport;
> > +            } else {
> > +                /* It's distributed across the "gateway_chassis" list */
> > +                is_ha_remote = true;
> >              }
> > -            ofport = tun->ofport;
> >          }
> >      }
> >
> > @@ -575,7 +599,7 @@ consider_port_binding(enum mf_field_id
> mff_ovn_geneve,
> >          }
> >          ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 100, 0,
> >                          &match, ofpacts_p);
> > -    } else if (!tun) {
> > +    } else if (!tun && !is_ha_remote) {
> >          /* Remote port connected by localnet port */
> >          /* Table 33, priority 100.
> >           * =======================
> > @@ -615,14 +639,84 @@ consider_port_binding(enum mf_field_id
> > mff_ovn_geneve,
> >          match_set_metadata(&match, htonll(dp_key));
> >          match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
> >
> > -        put_encapsulation(mff_ovn_geneve, tun, binding->datapath,
> > -                          port_key, ofpacts_p);
> > +        if (!is_ha_remote) {
> > +            /* Setup encapsulation */
> > +            put_encapsulation(mff_ovn_geneve, tun, binding->datapath,
> > +                              port_key, ofpacts_p);
> > +            /* Output to tunnel. */
> > +            ofpact_put_OUTPUT(ofpacts_p)->port = ofport;
> > +        } else {
> > +            struct gateway_chassis *gwc;
> > +            /* Make sure all tunnel endpoints use the same
> encapsulation,
> > +             * and set it up */
> > +            LIST_FOR_EACH (gwc, node, gateway_chassis) {
> > +                if (gwc->db->chassis) {
> > +                    if (!tun) {
> > +                        tun = chassis_tunnel_find(gwc->db->
> > chassis->name);
> > +                    } else {
> > +                        struct chassis_tunnel *chassis_tunnel =
> > +                            chassis_tunnel_find(gwc->db->
> chassis->name);
> > +                        if (chassis_tunnel &&
> > +                            tun->type != chassis_tunnel->type) {
> > +                            static struct vlog_rate_limit rl =
> > +                                VLOG_RATE_LIMIT_INIT(1, 1);
> > +                            VLOG_ERR_RL(&rl, "Port %s has
> Gateway_Chassis
> > "
> > +                                             "with mixed encapsulations,
> > only "
> > +                                             "uniform encapsulations
> are "
> > +                                             "supported.",
> > +                                        binding->logical_port);
> > +                            goto out;
> > +                        }
> > +                    }
> > +                }
> > +            }
> > +            if (!tun) {
> > +                static struct vlog_rate_limit rl =
> > VLOG_RATE_LIMIT_INIT(1, 1);
> > +                VLOG_ERR_RL(&rl, "No tunnel endpoint found for gateways
> > in "
> > +                                 "Gateway_Chassis of port %s",
> > +                            binding->logical_port);
> > +                goto out;
> > +            }
> >
> > -        /* Output to tunnel. */
> > -        ofpact_put_OUTPUT(ofpacts_p)->port = ofport;
> > +            put_encapsulation(mff_ovn_geneve, tun, binding->datapath,
> > +                              port_key, ofpacts_p);
> > +
> > +            /* Output to tunnels with active/backup */
> > +            struct ofpact_bundle *bundle = ofpact_put_BUNDLE(ofpacts_p);
> > +
> > +            LIST_FOR_EACH (gwc, node, gateway_chassis) {
> > +                if (gwc->db->chassis) {
> > +                    tun = chassis_tunnel_find(gwc->db->chassis->name);
> > +                    if (!tun) {
> > +                        continue;
> > +                    }
> > +                    if (bundle->n_slaves >= BUNDLE_MAX_SLAVES) {
> > +                        static struct vlog_rate_limit rl =
> > +                                VLOG_RATE_LIMIT_INIT(1, 1);
> > +                        VLOG_WARN_RL(&rl, "Remote endpoints for port
> > beyond "
> > +                                          "BUNDLE_MAX_SLAVES");
> > +                        break;
> > +                    }
> > +                    ofpbuf_put(ofpacts_p, &tun->ofport,
> > +                               sizeof tun->ofport);
> > +                    bundle->n_slaves++;
> > +                }
> > +            }
> > +
> > +            ofpact_finish_BUNDLE(ofpacts_p, &bundle);
> > +            bundle->algorithm = NX_BD_ALG_ACTIVE_BACKUP;
> > +            /* Although ACTIVE_BACKUP bundle algorithm seems to ignore
> > +             * the next two fields, those are always set */
> > +            bundle->basis = 0;
> > +            bundle->fields = NX_HASH_FIELDS_ETH_SRC;
> > +        }
> >          ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 100, 0,
> >                          &match, ofpacts_p);
> >      }
> > +out:
> > +    if (gateway_chassis) {
> > +        gateway_chassis_destroy(gateway_chassis);
> > +    }
> >  }
> >
> >  static void
> > @@ -770,7 +864,8 @@ physical_run(struct controller_ctx *ctx, enum
> > mf_field_id mff_ovn_geneve,
> >               const struct sbrec_chassis *chassis,
> >               const struct simap *ct_zones, struct lport_index *lports,
> >               struct hmap *flow_table, struct hmap *local_datapaths,
> > -             const struct sset *local_lports)
> > +             const struct sset *local_lports,
> > +             struct chassis_index *chassis_index)
> >  {
> >
> >      /* This bool tracks physical mapping changes. */
> > @@ -892,6 +987,7 @@ physical_run(struct controller_ctx *ctx, enum
> > mf_field_id mff_ovn_geneve,
> >      const struct sbrec_port_binding *binding;
> >      SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
> >          consider_port_binding(mff_ovn_geneve, ct_zones, lports,
> > +                              chassis_index,
> >                                local_datapaths, binding, chassis,
> >                                &ofpacts, flow_table);
> >      }
> > diff --git a/ovn/controller/physical.h b/ovn/controller/physical.h
> > index 66aa80e..9019621 100644
> > --- a/ovn/controller/physical.h
> > +++ b/ovn/controller/physical.h
> > @@ -33,6 +33,7 @@ struct ovsdb_idl;
> >  struct ovsrec_bridge;
> >  struct simap;
> >  struct sset;
> > +struct chassis_index;
> >
> >  /* OVN Geneve option information.
> >   *
> > @@ -47,6 +48,7 @@ void physical_run(struct controller_ctx *, enum
> > mf_field_id mff_ovn_geneve,
> >                    const struct sbrec_chassis *chassis,
> >                    const struct simap *ct_zones, struct lport_index *,
> >                    struct hmap *flow_table, struct hmap *local_datapaths,
> > -                  const struct sset *local_lports);
> > +                  const struct sset *local_lports,
> > +                  struct chassis_index *chassis_index);
> >
> >  #endif /* ovn/physical.h */
> > diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
> > index 990d268..9a1e6c1 100644
> > --- a/ovn/northd/ovn-northd.c
> > +++ b/ovn/northd/ovn-northd.c
> > @@ -1869,13 +1869,9 @@ ovn_port_update_sbrec(struct northd_context *ctx,
> >                  }
> >
> >              } else if (redirect_chassis) {
> > -                /* XXX: Keep the "redirect-chassis" option on the
> > Port_Binding
> > -                 * for compatibility purposes until ovn-controller
> > implements
> > -                 * Gateway_Chassis handling */
> > -                smap_add(&new, "redirect-chassis", redirect_chassis);
> > -
> >                  /* Handle ports that had redirect-chassis option
> attached
> > -                 * to them for backwards compatibility */
> > +                 * to them, and for backwards compatibility convert them
> > +                 * to a single Gateway_Chassis entry */
> >                  const struct sbrec_chassis *chassis =
> >                      chassis_lookup_by_name(chassis_index,
> > redirect_chassis);
> >                  if (chassis) {
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index d0e8bcd..fc9eda8 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -73,8 +73,6 @@ ovn-nbctl --wait=sb lrp-add R1 bob 00:00:02:01:02:03
> > 172.16.1.1/24 \
> >
> >  gwc1_uuid=`ovn-sbctl --bare --columns _uuid find Gateway_Chassis
> > name="bob_gw1"`
> >
> > -AT_CHECK([ovn-sbctl --bare --columns options find port_binding
> > logical_port="cr-bob" | grep 'redirect-chassis=gw1' | wc -l], [0], [1
> > -])
> >  AT_CHECK([ovn-sbctl --bare --columns gateway_chassis find port_binding
> > logical_port="cr-bob" | grep $gwc1_uuid | wc -l], [0], [1
> >  ])
> >
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index f3e6b4b..0cbbc27 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -6812,6 +6812,189 @@ OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
> >  OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> >  AT_CLEANUP
> >
> > +AT_SETUP([ovn -- packet test with HA distributed router gateway port])
> > +AT_SKIP_IF([test $HAVE_PYTHON = no])
> > +ovn_start
> > +
> > +net_add n1
> > +
> > +sim_add hv1
> > +as hv1
> > +ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.1
> > +ovs-vsctl -- add-port br-int hv1-vif1 -- \
> > +    set interface hv1-vif1 external-ids:iface-id=foo1 \
> > +    options:tx_pcap=hv1/vif1-tx.pcap \
> > +    options:rxq_pcap=hv1/vif1-rx.pcap \
> > +    ofport-request=1
> > +
> > +sim_add gw1
> > +as gw1
> > +ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.2
> > +
> > +sim_add gw2
> > +as gw2
> > +ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.4
> > +
> > +sim_add ext1
> > +as ext1
> > +ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.3
> > +ovs-vsctl -- add-port br-int ext1-vif1 -- \
> > +    set interface ext1-vif1 external-ids:iface-id=outside1 \
> > +    options:tx_pcap=ext1/vif1-tx.pcap \
> > +    options:rxq_pcap=ext1/vif1-rx.pcap \
> > +    ofport-request=1
> > +
> > +# Pre-populate the hypervisors' ARP tables so that we don't lose any
> > +# packets for ARP resolution (native tunneling doesn't queue packets
> > +# for ARP resolution).
> > +ovn_populate_arp
> > +
> > +ovn-nbctl create Logical_Router name=R1
> > +
> > +ovn-nbctl ls-add foo
> > +ovn-nbctl ls-add alice
> > +ovn-nbctl ls-add outside
> > +
> > +# Connect foo to R1
> > +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24
> > +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
> > +    type=router options:router-port=foo \
> > +    -- lsp-set-addresses rp-foo router
> > +
> > +# Connect alice to R1 as distributed router gateway port on gw1
> > +ovn-nbctl lrp-add R1 alice 00:00:02:01:02:03 172.16.1.1/24
> > +
> > +ovn-nbctl \
> > +    --id=@gc0 create Gateway_Chassis name=alice_gw1 \
> > +                                     chassis_name=gw1 \
> > +                                     priority=20 -- \
> > +    --id=@gc1 create Gateway_Chassis name=alice_gw2 \
> > +                                     chassis_name=gw2 \
> > +                                     priority=10 -- \
> > +    set Logical_Router_Port alice 'gateway_chassis=[@gc0,@gc1]'
> > +
> > +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
> > +    type=router options:router-port=alice \
> > +    -- lsp-set-addresses rp-alice router
> > +
> > +# Create logical port foo1 in foo
> > +ovn-nbctl lsp-add foo foo1 \
> > +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
> > +
> > +# Create logical port outside1 in outside
> > +ovn-nbctl lsp-add outside outside1 \
> > +-- lsp-set-addresses outside1 "f0:00:00:01:02:04 172.16.1.3"
> > +
> > +# Create localnet port in alice
> > +ovn-nbctl lsp-add alice ln-alice
> > +ovn-nbctl lsp-set-addresses ln-alice unknown
> > +ovn-nbctl lsp-set-type ln-alice localnet
> > +ovn-nbctl lsp-set-options ln-alice network_name=phys
> > +
> > +# Create localnet port in outside
> > +ovn-nbctl lsp-add outside ln-outside
> > +ovn-nbctl lsp-set-addresses ln-outside unknown
> > +ovn-nbctl lsp-set-type ln-outside localnet
> > +ovn-nbctl lsp-set-options ln-outside network_name=phys
> > +
> > +# Create bridge-mappings on gw1, gw2 and ext1, hv1 doesn't need
> > +# mapping to the external network, is the one generating packets
> > +as gw1 ovs-vsctl set open . external-ids:ovn-bridge-
> mappings=phys:br-phys
> > +as gw2 ovs-vsctl set open . external-ids:ovn-bridge-
> mappings=phys:br-phys
> > +as ext1 ovs-vsctl set open . external-ids:ovn-bridge-
> > mappings=phys:br-phys
> > +
> > +AT_CHECK([ovn-nbctl --timeout=3 --wait=sb sync], [0], [ignore])
> > +
> > +# Allow some time for ovn-northd and ovn-controller to catch up.
> > +# XXX This should be more systematic.
> > +sleep 2
> > +
> > +ip_to_hex() {
> > +    printf "%02x%02x%02x%02x" "$@"
> > +}
> > +
> > +reset_pcap_file() {
> > +    local iface=$1
> > +    local pcap_file=$2
> > +    ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \
> > +options:rxq_pcap=dummy-rx.pcap
> > +    rm -f ${pcap_file}*.pcap
> > +    ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-
> tx.pcap
> > \
> > +options:rxq_pcap=${pcap_file}-rx.pcap
> > +}
> > +
> > +test_ip_packet()
> > +{
> > +    local active_gw=$1
> > +    local backup_gw=$2
> > +
> > +    # Send ip packet between foo1 and outside1
> > +    src_mac="f00000010203" # foo1 mac
> > +    dst_mac="000001010203" # rp-foo mac (internal router leg)
> > +    src_ip=`ip_to_hex 192 168 1 2`
> > +    dst_ip=`ip_to_hex 172 16 1 3`
> > +    packet=${dst_mac}${src_mac}08004500001c0000000040110000${
> > src_ip}${dst_ip}0035111100080000
> > +
> > +    # ARP request packet to expect at outside1
> > +    #arp_request=ffffffffffff${src_mac}08060001080006040001${
> > src_mac}${src_ip}000000000000${dst_ip}
> > +
> > +    as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
> > +
> > +    # Send ARP reply from outside1 back to the router
> > +    # XXX: note, we could avoid this if we plug this port into a netns
> > +    # and setup the IP address into the port, so the kernel would simply
> > reply
> > +    src_mac="000002010203"
> > +    reply_mac="f00000010204"
> > +    dst_ip=`ip_to_hex 172 16 1 3`
> > +    src_ip=`ip_to_hex 172 16 1 1`
> > +    arp_reply=${src_mac}${reply_mac}08060001080006040002${
> > reply_mac}${dst_ip}${src_mac}${src_ip}
> > +
> > +    as ext1 ovs-appctl netdev-dummy/receive ext1-vif1 $arp_reply
> > +
> > +    # Packet to Expect at ext1 chassis, outside1 port
> > +    src_mac="000002010203"
> > +    dst_mac="f00000010204"
> > +    src_ip=`ip_to_hex 192 168 1 2`
> > +    dst_ip=`ip_to_hex 172 16 1 3`
> > +    expected=${dst_mac}${src_mac}08004500001c000000003f110100${
> > src_ip}${dst_ip}0035111100080000
> > +    echo $expected > ext1-vif1.expected
> > +
> > +    as $active_gw reset_pcap_file br-phys_n1 $active_gw/br-phys_n1
> > +    as $backup_gw reset_pcap_file br-phys_n1 $backup_gw/br-phys_n1
> > +    as ext1 reset_pcap_file ext1-vif1 ext1/vif1
> > +
> > +    # Resend packet from foo1 to outside1
> > +    as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet
> > +
> > +    sleep 1
> > +
> > +    OVN_CHECK_PACKETS([ext1/vif1-tx.pcap], [ext1-vif1.expected])
> > +    $PYTHON "$top_srcdir/utilities/ovs-pcap.in"
> > $active_gw/br-phys_n1-tx.pcap  > packets
> > +    AT_CHECK([grep $expected packets | sort], [0], [expout])
> > +    $PYTHON "$top_srcdir/utilities/ovs-pcap.in"
> > $backup_gw/br-phys_n1-tx.pcap  > packets
> > +    AT_CHECK([grep $expected packets | sort], [0], [])
> > +}
> > +
> > +test_ip_packet gw1 gw2
> > +
> > +ovn-nbctl --wait=hv \
> > +    --id=@gc0 create Gateway_Chassis name=alice_gw1 \
> > +                                     chassis_name=gw1 \
> > +                                     priority=10 -- \
> > +    --id=@gc1 create Gateway_Chassis name=alice_gw2 \
> > +                                     chassis_name=gw2 \
> > +                                     priority=20 -- \
> > +    set Logical_Router_Port alice 'gateway_chassis=[@gc0,@gc1]'
> > +
> > +test_ip_packet gw2 gw1
> > +
> > +OVN_CLEANUP([hv1],[gw1],[gw2],[ext1])
> > +AT_CLEANUP
> > +
> >  AT_SETUP([ovn -- 1 LR with distributed router gateway port])
> >  AT_SKIP_IF([test $HAVE_PYTHON = no])
> >  ovn_start
> > @@ -6937,7 +7120,11 @@ ovn-sbctl dump-flows
> >  echo "---------------------"
> >  ovn-sbctl list chassis
> >  ovn-sbctl list encap
> > -echo "---------------------"
> > +echo "------ Gateway_Chassis dump (SBDB) -------"
> > +ovn-sbctl list Gateway_Chassis
> > +echo "------ Port_Binding chassisredirect -------"
> > +ovn-sbctl find Port_Binding type=chassisredirect
> > +echo "-------------------------------------------"
> >
> >  echo "------ hv1 dump ----------"
> >  as hv1 ovs-ofctl show br-int
> > @@ -6950,6 +7137,7 @@ as hv3 ovs-ofctl show br-int
> >  as hv3 ovs-ofctl dump-flows br-int
> >  echo "--------------------------"
> >
> > +
> >  # Check that redirect mapping is programmed only on hv2
> >  AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=33 | grep
> > =0x3,metadata=0x1 | wc -l], [0], [0
> >  ])
> > @@ -7504,3 +7692,142 @@ done
> >  OVN_CLEANUP([hv1],[hv2])
> >
> >  AT_CLEANUP
> > +
> > +AT_SETUP([ovn -- 1 LR with HA distributed router gateway port])
> > +AT_SKIP_IF([test $HAVE_PYTHON = no])
> > +ovn_start
> > +
> > +net_add n1
> > +
> > +# create gateways with external network connectivity
> > +
> > +for i in 1 2; do
> > +    sim_add gw$i
> > +    as gw$i
> > +    ovs-vsctl add-br br-phys
> > +    ovn_attach n1 br-phys 192.168.0.$i
> > +    ovs-vsctl set open . external-ids:ovn-bridge-mappings=phys:br-phys
> > +done
> > +
> > +ovn-nbctl ls-add inside
> > +ovn-nbctl ls-add outside
> > +
> > +# create hypervisors with a vif port each to an internal network
> > +
> > +for i in 1 2; do
> > +    sim_add hv$i
> > +    as hv$i
> > +    ovs-vsctl add-br br-phys
> > +    ovn_attach n1 br-phys 192.168.0.1$i
> > +    ovs-vsctl -- add-port br-int hv$i-vif1 -- \
> > +        set interface hv$i-vif1 external-ids:iface-id=inside$i \
> > +        options:tx_pcap=hv$i/vif1-tx.pcap \
> > +        options:rxq_pcap=hv$i/vif1-rx.pcap \
> > +        ofport-request=1
> > +
> > +        ovn-nbctl lsp-add inside inside$i \
> > +            -- lsp-set-addresses inside$i "f0:00:00:01:22:$i
> > 192.168.1.10$i"
> > +
> > +done
> > +
> > +ovn_populate_arp
> > +
> > +ovn-nbctl create Logical_Router name=R1
> > +
> > +# Connect inside to R1
> > +ovn-nbctl lrp-add R1 inside 00:00:01:01:02:03 192.168.1.1/24
> > +ovn-nbctl lsp-add inside rp-inside -- set Logical_Switch_Port rp-inside
> \
> > +    type=router options:router-port=inside \
> > +    -- lsp-set-addresses rp-inside router
> > +
> > +# Connect outside to R1 as distributed router gateway port on gw1+gw2
> > +ovn-nbctl lrp-add R1 outside 00:00:02:01:02:04 192.168.0.101/24
> > +
> > +ovn-nbctl --id=@gc0 create Gateway_Chassis \
> > +                    name=outside_gw1 chassis_name=gw1 priority=20 -- \
> > +          --id=@gc1 create Gateway_Chassis \
> > +                    name=outside_gw2 chassis_name=gw2 priority=10 -- \
> > +          set Logical_Router_Port outside 'gateway_chassis=[@gc0,@gc1]'
> > +
> > +ovn-nbctl lsp-add outside rp-outside -- set Logical_Switch_Port
> > rp-outside \
> > +    type=router options:router-port=outside \
> > +    -- lsp-set-addresses rp-outside router
> > +
> > +# Create localnet port in outside
> > +ovn-nbctl lsp-add outside ln-outside
> > +ovn-nbctl lsp-set-addresses ln-outside unknown
> > +ovn-nbctl lsp-set-type ln-outside localnet
> > +ovn-nbctl lsp-set-options ln-outside network_name=phys
> > +
> > +# Allow some time for ovn-northd and ovn-controller to catch up.
> > +# XXX This should be more systematic.
> > +ovn-nbctl --wait=hv sync
> > +
> > +echo "---------NB dump-----"
> > +ovn-nbctl show
> > +echo "---------------------"
> > +ovn-nbctl list logical_router
> > +echo "---------------------"
> > +ovn-nbctl list logical_router_port
> > +echo "---------------------"
> > +
> > +echo "---------SB dump-----"
> > +ovn-sbctl list datapath_binding
> > +echo "---------------------"
> > +ovn-sbctl list port_binding
> > +echo "---------------------"
> > +ovn-sbctl dump-flows
> > +echo "---------------------"
> > +ovn-sbctl list chassis
> > +ovn-sbctl list encap
> > +echo "---------------------"
> > +echo "------ Gateway_Chassis dump (SBDB) -------"
> > +ovn-sbctl list Gateway_Chassis
> > +echo "------ Port_Binding chassisredirect -------"
> > +ovn-sbctl find Port_Binding type=chassisredirect
> > +echo "-------------------------------------------"
> > +
> > +
> > +hv1_gw1_ofport=$(as hv1 ovs-vsctl --bare --columns ofport find Interface
> > name=ovn-gw1-0)
> > +hv1_gw2_ofport=$(as hv1 ovs-vsctl --bare --columns ofport find Interface
> > name=ovn-gw2-0)
> > +hv2_gw1_ofport=$(as hv2 ovs-vsctl --bare --columns ofport find Interface
> > name=ovn-gw1-0)
> > +hv2_gw2_ofport=$(as hv2 ovs-vsctl --bare --columns ofport find Interface
> > name=ovn-gw2-0)
> > +
> > +echo $hv1_gw1_ofport
> > +echo $hv1_gw2_ofport
> > +echo $hv2_gw1_ofport
> > +echo $hv2_gw2_ofport
> > +
> > +echo "--- hv1 ---"
> > +as hv1 ovs-ofctl dump-flows br-int table=32
> > +
> > +echo "--- hv2 ---"
> > +as hv2 ovs-ofctl dump-flows br-int table=32
> > +
> > +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=32 | grep
> > active_backup | grep slaves:$hv1_gw1_ofport,$hv1_gw2_ofport | wc -l],
> > [0], [1
> > +])
> > +
> > +AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=32 | grep
> > active_backup | grep slaves:$hv2_gw1_ofport,$hv2_gw2_ofport | wc -l],
> > [0], [1
> > +])
> > +
> > +# set higher priority to gw2 instead of gw1, and check for changes
> > +
> > +ovn-nbctl --id=@gc0 create Gateway_Chassis \
> > +                    name=outside_gw1 chassis_name=gw1 priority=10 -- \
> > +          --id=@gc1 create Gateway_Chassis \
> > +                    name=outside_gw2 chassis_name=gw2 priority=20 -- \
> > +          set Logical_Router_Port outside 'gateway_chassis=[@gc0,@gc1]'
> > +
> > +# XXX: Let the change propagate down to the ovn-controllers
> > +ovn-nbctl --wait=hv sync
> > +
> > +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=32 | grep
> > active_backup | grep slaves:$hv1_gw2_ofport,$hv1_gw1_ofport | wc -l],
> > [0], [1
> > +])
> > +
> > +AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=32 | grep
> > active_backup | grep slaves:$hv2_gw2_ofport,$hv2_gw1_ofport | wc -l],
> > [0], [1
> > +])
> > +
> > +
> > +OVN_CLEANUP([gw1],[gw2],[hv1],[hv2])
> > +
> > +AT_CLEANUP
> > --
> > 1.8.3.1
> >
> >
> _______________________________________________
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to