On Mon, Jul 11, 2016 at 8:14 AM, Lance Richardson <lrich...@redhat.com>
wrote:

>
>
> ----- Original Message -----
> > From: "Darrell Ball" <dlu...@gmail.com>
> > To: dlu...@gmail.com, d...@openvswitch.com
> > Sent: Monday, July 11, 2016 11:07:03 AM
> > Subject: [ovs-dev] [patch_v8] ovn: Add local router support (RFC).
> >
> > This patch adds local router support.  The idea is to do openflow rule
> > calculations and download for logical routers only on HVs where this is
> > needed.  The approach used is to do a flood fill, based local VIF
> presence
> > and factoring in logical data path associations recursively.
> >
> > The algorithm detects changes in the local and patched datapath sets
> > and triggers recalculation of the local_routers set.
> >
> > The code changes are limited to ovn-controller.
> >
> > Signed-off-by: Darrell Ball <dlu...@gmail.com>
> > ---
> >  ovn/controller/binding.c        |  34 ++++++---
> >  ovn/controller/binding.h        |   3 +-
> >  ovn/controller/lflow.c          |   4 +
> >  ovn/controller/ovn-controller.c | 157
> >  +++++++++++++++++++++++++++++++++++++---
> >  ovn/controller/ovn-controller.h |   7 ++
> >  ovn/controller/patch.c          |  38 +++++++---
> >  ovn/controller/patch.h          |   4 +-
> >  tests/ovn.at                    | 153
> >  +++++++++++++++++++++++++++++++++++++++
> >  8 files changed, 365 insertions(+), 35 deletions(-)
> >
> > diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
> > index 4704226..2feed61 100644
> > --- a/ovn/controller/binding.c
> > +++ b/ovn/controller/binding.c
> > @@ -126,7 +126,8 @@ local_datapath_lookup_by_uuid(struct hmap *hmap_p,
> const
> > struct uuid *uuid)
> >  }
> >
> >  static void
> > -remove_local_datapath(struct hmap *local_datapaths, struct
> local_datapath
> > *ld)
> > +remove_local_datapath(struct hmap *local_datapaths, struct
> local_datapath
> > *ld,
> > +                      bool *datapath_assoc_chgd)
> >  {
> >      if (ld->logical_port) {
> >          sset_find_and_delete(&all_lports, ld->logical_port);
> > @@ -136,17 +137,19 @@ remove_local_datapath(struct hmap *local_datapaths,
> > struct local_datapath *ld)
> >      hmap_remove(local_datapaths, &ld->hmap_node);
> >      hmap_remove(&local_datapaths_by_uuid, &ld->uuid_hmap_node);
> >      free(ld);
> > +    *datapath_assoc_chgd = true;
> >  }
> >
> >  static void
> >  remove_local_datapath_by_binding(struct hmap *local_datapaths,
> > -                                 const struct sbrec_port_binding
> > *binding_rec)
> > +                                 const struct sbrec_port_binding
> > *binding_rec,
> > +                                 bool *datapath_assoc_chgd)
> >  {
> >      const struct uuid *uuid = &binding_rec->header_.uuid;
> >      struct local_datapath *ld =
> >      local_datapath_lookup_by_uuid(local_datapaths,
> >                                                                uuid);
> >      if (ld) {
> > -        remove_local_datapath(local_datapaths, ld);
> > +        remove_local_datapath(local_datapaths, ld, datapath_assoc_chgd);
> >      } else {
> >          struct local_datapath *ld;
> >          HMAP_FOR_EACH (ld, hmap_node, local_datapaths) {
> > @@ -160,7 +163,7 @@ remove_local_datapath_by_binding(struct hmap
> > *local_datapaths,
> >  static void
> >  add_local_datapath(struct hmap *local_datapaths,
> >          const struct sbrec_port_binding *binding_rec,
> > -        const struct uuid *uuid)
> > +        const struct uuid *uuid, bool *datapath_assoc_chgd)
> >  {
> >      if (get_local_datapath(local_datapaths,
> >                             binding_rec->datapath->tunnel_key)) {
> > @@ -174,6 +177,7 @@ add_local_datapath(struct hmap *local_datapaths,
> >                  binding_rec->datapath->tunnel_key);
> >      hmap_insert(&local_datapaths_by_uuid, &ld->uuid_hmap_node,
> >                  uuid_hash(uuid));
> > +    *datapath_assoc_chgd = true;
> >  }
> >
> >  static void
> > @@ -191,7 +195,8 @@ static void
> >  consider_local_datapath(struct controller_ctx *ctx, struct shash
> *lports,
> >                          const struct sbrec_chassis *chassis_rec,
> >                          const struct sbrec_port_binding *binding_rec,
> > -                        struct hmap *local_datapaths)
> > +                        struct hmap *local_datapaths,
> > +                        bool *datapath_assoc_chgd)
> >  {
> >      const struct ovsrec_interface *iface_rec
> >          = shash_find_data(lports, binding_rec->logical_port);
> > @@ -203,7 +208,8 @@ consider_local_datapath(struct controller_ctx *ctx,
> > struct shash *lports,
> >              sset_add(&all_lports, binding_rec->logical_port);
> >          }
> >          add_local_datapath(local_datapaths, binding_rec,
> > -                           &binding_rec->header_.uuid);
> > +                           &binding_rec->header_.uuid,
> > +                           datapath_assoc_chgd);
> >          if (iface_rec && ctx->ovs_idl_txn) {
> >              update_qos(iface_rec, binding_rec);
> >          }
> > @@ -244,7 +250,8 @@ consider_local_datapath(struct controller_ctx *ctx,
> > struct shash *lports,
> >              sbrec_port_binding_set_chassis(binding_rec, chassis_rec);
> >              sset_add(&all_lports, binding_rec->logical_port);
> >              add_local_datapath(local_datapaths, binding_rec,
> > -                               &binding_rec->header_.uuid);
> > +                               &binding_rec->header_.uuid,
> > +                               datapath_assoc_chgd);
> >          }
> >      } else if (chassis_rec && binding_rec->chassis == chassis_rec
> >                 && strcmp(binding_rec->type, "gateway")) {
> > @@ -269,7 +276,8 @@ static struct shash lports =
> SHASH_INITIALIZER(&lports);
> >
> >  void
> >  binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge
> *br_int,
> > -            const char *chassis_id, struct hmap *local_datapaths)
> > +            const char *chassis_id, struct hmap *local_datapaths,
> > +            bool *datapath_assoc_chgd)
> >  {
> >      const struct sbrec_chassis *chassis_rec;
> >      const struct sbrec_port_binding *binding_rec;
> > @@ -297,7 +305,7 @@ binding_run(struct controller_ctx *ctx, const struct
> > ovsrec_bridge *br_int,
> >              HMAP_INITIALIZER(&keep_local_datapath_by_uuid);
> >          SBREC_PORT_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {
> >              consider_local_datapath(ctx, &lports, chassis_rec,
> binding_rec,
> > -                                    local_datapaths);
> > +                                    local_datapaths,
> datapath_assoc_chgd);
> >              struct local_datapath *ld = xzalloc(sizeof *ld);
> >              memcpy(&ld->uuid, &binding_rec->header_.uuid, sizeof
> ld->uuid);
> >              hmap_insert(&keep_local_datapath_by_uuid,
> &ld->uuid_hmap_node,
> > @@ -307,7 +315,8 @@ binding_run(struct controller_ctx *ctx, const struct
> > ovsrec_bridge *br_int,
> >          HMAP_FOR_EACH_SAFE (old_ld, next, hmap_node, local_datapaths) {
> >              if
> (!local_datapath_lookup_by_uuid(&keep_local_datapath_by_uuid,
> >                                                 &old_ld->uuid)) {
> > -                remove_local_datapath(local_datapaths, old_ld);
> > +                remove_local_datapath(local_datapaths, old_ld,
> > +                                      datapath_assoc_chgd);
> >              }
> >          }
> >          hmap_destroy(&keep_local_datapath_by_uuid);
> > @@ -315,10 +324,11 @@ binding_run(struct controller_ctx *ctx, const
> struct
> > ovsrec_bridge *br_int,
> >      } else {
> >          SBREC_PORT_BINDING_FOR_EACH_TRACKED(binding_rec,
> ctx->ovnsb_idl) {
> >              if (sbrec_port_binding_is_deleted(binding_rec)) {
> > -                remove_local_datapath_by_binding(local_datapaths,
> > binding_rec);
> > +                remove_local_datapath_by_binding(local_datapaths,
> > binding_rec,
> > +                                                 datapath_assoc_chgd);
> >              } else {
> >                  consider_local_datapath(ctx, &lports, chassis_rec,
> >                  binding_rec,
> > -                                        local_datapaths);
> > +                                        local_datapaths,
> > datapath_assoc_chgd);
> >              }
> >          }
> >      }
> > diff --git a/ovn/controller/binding.h b/ovn/controller/binding.h
> > index 8753d44..5558591 100644
> > --- a/ovn/controller/binding.h
> > +++ b/ovn/controller/binding.h
> > @@ -29,7 +29,8 @@ struct sset;
> >  void binding_register_ovs_idl(struct ovsdb_idl *);
> >  void binding_reset_processing(void);
> >  void binding_run(struct controller_ctx *, const struct ovsrec_bridge
> >  *br_int,
> > -                 const char *chassis_id, struct hmap *local_datapaths);
> > +                 const char *chassis_id, struct hmap *local_datapaths,
> > +                              bool *datapath_assoc_chgd);
> >  bool binding_cleanup(struct controller_ctx *, const char *chassis_id);
> >
> >  #endif /* ovn/binding.h */
> > diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
> > index 00d1d6e..ba0c89f 100644
> > --- a/ovn/controller/lflow.c
> > +++ b/ovn/controller/lflow.c
> > @@ -437,6 +437,10 @@ consider_logical_flow(const struct lport_index
> *lports,
> >                  return;
> >              }
> >          }
> > +    } else {
> > +        if (!get_local_router(ldp->tunnel_key)) {
> > +            return;
> > +        }
> >      }
> >
> >      /* Determine translation of logical table IDs to physical table
> IDs. */
> > diff --git a/ovn/controller/ovn-controller.c
> > b/ovn/controller/ovn-controller.c
> > index 28ee13e..e0dbb35 100644
> > --- a/ovn/controller/ovn-controller.c
> > +++ b/ovn/controller/ovn-controller.c
> > @@ -69,6 +69,15 @@ OVS_NO_RETURN static void usage(void);
> >
> >  static char *ovs_remote;
> >
> > +/* Contains "struct local_datapath" nodes whose hash values are the
> > + * tunnel_key of datapaths with at least one local port binding. */
> > +static struct hmap local_datapaths = HMAP_INITIALIZER(&local_datapaths);
> > +static struct hmap patched_datapaths =
> HMAP_INITIALIZER(&patched_datapaths);
> > +
> > +static struct lport_index lports;
> > +static struct mcgroup_index mcgroups;
> > +static struct hmap local_routers;
> > +
> >  struct local_datapath *
> >  get_local_datapath(const struct hmap *local_datapaths, uint32_t
> tunnel_key)
> >  {
> > @@ -128,6 +137,131 @@ get_bridge(struct ovsdb_idl *ovs_idl, const char
> > *br_name)
> >      return NULL;
> >  }
> >
> > +static void
> > +add_local_router(uint32_t tunnel_key)
> > +{
> > +     struct local_router *lr = get_local_router(tunnel_key);
> > +     if (lr) {
> > +             lr->stale = false;
> > +             return;
> > +     }
> > +    lr = xzalloc(sizeof *lr);
> > +    hmap_insert(&local_routers, &lr->hmap_node, tunnel_key);
> > +}
> > +
> > +static void
> > +build_local_routers(struct controller_ctx *ctx,
> > +                    struct lport_index *lports)
> > +{
> > +    /* Mark all local routers as stale for later cleanup check */
> > +    struct local_router *lr;
> > +    HMAP_FOR_EACH (lr, hmap_node, &local_routers) {
> > +        lr->stale = true;
> > +    }
> > +
> > +    /* Hopefully, no one is using more than 2 or 3 levels of
> > +     * datapath recursion */
> > +#define MAX_DATAPATH_DEPTH_SUPPORTED 10
> > +    bool flood_fill_end = false;
> > +    for (int i = 0; i < MAX_DATAPATH_DEPTH_SUPPORTED; i++) {
> > +        if (flood_fill_end) {
> > +            break;
> > +        }
> > +        flood_fill_end = true;
> > +        const struct sbrec_port_binding *binding_rec;
> > +        SBREC_PORT_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {
> > +            if ((!strcmp(binding_rec->type, "patch") ||
> > +                 !strcmp(binding_rec->type, "gateway")) &&
> > +                 binding_rec->datapath && get_patched_datapath(
> > +                     &patched_datapaths,
> > +                     binding_rec->datapath->tunnel_key)) {
> > +
> > +                const char *plp = smap_get(&binding_rec->options,
> "peer");
> > +                const struct lport_index *lports_ = lports;
> > +                const struct sbrec_port_binding *peer_binding_rec =
> > +                    lport_lookup_by_name(lports_, plp);
> > +
> > +                struct uuid key;
> > +                if (peer_binding_rec && peer_binding_rec->datapath) {
> > +                    if (get_local_datapath(&local_datapaths,
> > +                           binding_rec->datapath->tunnel_key) &&
> > +                        smap_get_uuid(
> > +                            &peer_binding_rec->datapath->external_ids,
> > +                            "logical-router", &key)) {
> > +                        add_local_router(
> > +                            peer_binding_rec->datapath->tunnel_key);
> > +                        flood_fill_end = false;
> > +                    } else if (get_local_datapath(&local_datapaths,
> > +
>  peer_binding_rec->datapath->tunnel_key)
> > &&
> > +                               smap_get_uuid(
> > +                                   &binding_rec->datapath->external_ids,
> > +                                   "logical-router", &key)) {
> > +
> add_local_router(binding_rec->datapath->tunnel_key);
> > +                        flood_fill_end = false;
> > +                    } else if (get_local_router(
> > +                                   binding_rec->datapath->tunnel_key) &&
> > +                               smap_get_uuid(
> > +
> > &peer_binding_rec->datapath->external_ids,
> > +                                   "logical-router", &key) ) {
> > +                        add_local_router(
> > +                            peer_binding_rec->datapath->tunnel_key);
> > +                        flood_fill_end = false;
> > +                    } else if (get_local_router(
> > +
>  peer_binding_rec->datapath->tunnel_key)
> > &&
> > +                               smap_get_uuid(
> > +                                   &binding_rec->datapath->external_ids,
> > +                                   "logical-router", &key)) {
> > +
> add_local_router(binding_rec->datapath->tunnel_key);
> > +                        flood_fill_end = false;
> > +                    } else if (get_local_router(
> > +
>  peer_binding_rec->datapath->tunnel_key)
> > &&
> > +                               smap_get_uuid(
> > +                                   &binding_rec->datapath->external_ids,
> > +                                   "logical-switch", &key)) {
> > +                        /* Add the logical switch to the local routers
> map,
> > +                         * as it may be a Transit LS and we need to
> continue
> > +                         * to follow the patch ports. */
> > +
> add_local_router(binding_rec->datapath->tunnel_key);
> > +                        flood_fill_end = false;
> > +                    } else if (get_local_router(
> > +                                   binding_rec->datapath->tunnel_key) &&
> > +                               smap_get_uuid(
> > +
> > &peer_binding_rec->datapath->external_ids,
> > +                                   "logical-switch", &key)) {
> > +                        /* Add the logical switch to the local routers
> map,
> > +                         * as it may be a Transit LS and we need to
> continue
> > +                         * to follow the patch ports. */
> > +                        add_local_router(
> > +                            peer_binding_rec->datapath->tunnel_key);
> > +                        flood_fill_end = false;
> > +                    }
> > +                }
> > +            }
> > +        }
> > +    }
> > +
> > +    /* Clean up stale local_routers. */
> > +    struct local_router *lr_cur_node, *lr_next_node;
> > +    HMAP_FOR_EACH_SAFE (lr_cur_node, lr_next_node, hmap_node,
> > &local_routers) {
> > +        if (lr_cur_node->stale == true) {
> > +            hmap_remove(&local_routers, &lr_cur_node->hmap_node);
> > +            free(lr_cur_node);
> > +        }
> > +    }
> > +}
> > +
> > +const struct local_router *
> > +get_local_router(uint32_t tunnel_key)
> > +{
> > +    struct hmap_node *node = hmap_first_with_hash(&local_routers,
> > +                                                  tunnel_key);
> > +
> > +    const struct local_router *local_router = node ?
> > +        CONTAINER_OF(node, struct local_router, hmap_node) : NULL;
> > +    return (local_router ? (!local_router->stale ? local_router : NULL)
> > +            : NULL);
> > +}
> > +
> >  static const struct ovsrec_bridge *
> >  create_br_int(struct controller_ctx *ctx,
> >                const struct ovsrec_open_vswitch *cfg,
> > @@ -299,14 +433,6 @@ update_ct_zones(struct sset *lports, struct hmap
> > *patched_datapaths,
> >      sset_destroy(&all_users);
> >  }
> >
> > -/* Contains "struct local_datapath" nodes whose hash values are the
> > - * tunnel_key of datapaths with at least one local port binding. */
> > -static struct hmap local_datapaths = HMAP_INITIALIZER(&local_datapaths);
> > -static struct hmap patched_datapaths =
> HMAP_INITIALIZER(&patched_datapaths);
> > -
> > -static struct lport_index lports;
> > -static struct mcgroup_index mcgroups;
> > -
> >  int
> >  main(int argc, char *argv[])
> >  {
> > @@ -392,9 +518,15 @@ main(int argc, char *argv[])
> >      unixctl_command_register("ct-zone-list", "", 0, 0,
> >                               ct_zone_list, &ct_zones);
> >
> > +    hmap_init(&local_routers);
> > +    static bool datapath_assoc_chgd;
> > +
> >      /* Main loop. */
> >      exiting = false;
> >      while (!exiting) {
> > +
> > +        datapath_assoc_chgd = false;
> > +
> >          /* Check OVN SB database. */
> >          char *new_ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
> >          if (strcmp(ovnsb_remote, new_ovnsb_remote)) {
> > @@ -425,16 +557,21 @@ main(int argc, char *argv[])
> >          if (chassis_id) {
> >              chassis_run(&ctx, chassis_id);
> >              encaps_run(&ctx, br_int, chassis_id);
> > -            binding_run(&ctx, br_int, chassis_id, &local_datapaths);
> > +            binding_run(&ctx, br_int, chassis_id, &local_datapaths,
> > +                        &datapath_assoc_chgd);
> >          }
> >
> >          if (br_int && chassis_id) {
> >              patch_run(&ctx, br_int, chassis_id, &local_datapaths,
> > -                      &patched_datapaths);
> > +                      &patched_datapaths, &datapath_assoc_chgd);
> >
> >              lport_index_fill(&lports, ctx.ovnsb_idl);
> >              mcgroup_index_fill(&mcgroups, ctx.ovnsb_idl);
> >
> > +            if (datapath_assoc_chgd) {
> > +                build_local_routers(&ctx, &lports);
> > +            }
> > +
> >              enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int);
> >
> >              pinctrl_run(&ctx, &lports, br_int, chassis_id,
> >              &local_datapaths);
> > diff --git a/ovn/controller/ovn-controller.h
> > b/ovn/controller/ovn-controller.h
> > index 470b1f5..a71d2bf 100644
> > --- a/ovn/controller/ovn-controller.h
> > +++ b/ovn/controller/ovn-controller.h
> > @@ -57,6 +57,11 @@ struct patched_datapath {
> >                   * port. */
> >  };
> >
> > +struct local_router {
> > +    struct hmap_node hmap_node;
> > +    bool stale;
> > +};
> > +
> >  struct patched_datapath *get_patched_datapath(const struct hmap *,
> >                                                uint32_t tunnel_key);
> >
> > @@ -66,6 +71,8 @@ const struct ovsrec_bridge *get_bridge(struct
> ovsdb_idl *,
> >  const struct sbrec_chassis *get_chassis(struct ovsdb_idl *,
> >                                          const char *chassis_id);
> >
> > +const struct local_router *get_local_router(uint32_t);
> > +
> >  /* Must be a bit-field ordered from most-preferred (higher number) to
> >   * least-preferred (lower number). */
> >  enum chassis_tunnel_type {
> > diff --git a/ovn/controller/patch.c b/ovn/controller/patch.c
> > index 52d9e8d..b0519fa 100644
> > --- a/ovn/controller/patch.c
> > +++ b/ovn/controller/patch.c
> > @@ -58,7 +58,8 @@ create_patch_port(struct controller_ctx *ctx,
> >                    const char *key, const char *value,
> >                    const struct ovsrec_bridge *src, const char *src_name,
> >                    const struct ovsrec_bridge *dst, const char *dst_name,
> > -                  struct shash *existing_ports)
> > +                  struct shash *existing_ports,
> > +                  bool *datapath_assoc_chgd)
> >  {
> >      for (size_t i = 0; i < src->n_ports; i++) {
> >          if (match_patch_port(src->ports[i], dst_name)) {
> > @@ -68,6 +69,10 @@ create_patch_port(struct controller_ctx *ctx,
> >          }
> >      }
> >
> > +    if (datapath_assoc_chgd) {
> > +        *datapath_assoc_chgd = true;
> > +    }
> > +
> >      ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn,
> >              "ovn-controller: creating patch port '%s' from '%s' to
> '%s'",
> >              src_name, src->name, dst->name);
> > @@ -237,10 +242,12 @@ add_bridge_mappings(struct controller_ctx *ctx,
> >
> >          char *name1 = patch_port_name(br_int->name,
> binding->logical_port);
> >          char *name2 = patch_port_name(binding->logical_port,
> br_int->name);
> > +
> >          create_patch_port(ctx, patch_port_id, binding->logical_port,
> > -                          br_int, name1, br_ln, name2, existing_ports);
> > +                          br_int, name1, br_ln, name2, existing_ports,
> > NULL);
> >          create_patch_port(ctx, patch_port_id, binding->logical_port,
> > -                          br_ln, name2, br_int, name1, existing_ports);
> > +                          br_ln, name2, br_int, name1, existing_ports,
> > NULL);
> > +
> >          free(name1);
> >          free(name2);
> >      }
> > @@ -250,7 +257,8 @@ add_bridge_mappings(struct controller_ctx *ctx,
> >
> >  static void
> >  add_patched_datapath(struct hmap *patched_datapaths,
> > -                     const struct sbrec_port_binding *binding_rec, bool
> > local)
> > +                     const struct sbrec_port_binding *binding_rec, bool
> > local,
> > +                                      bool *datapath_assoc_chgd)
> >  {
> >      struct patched_datapath *pd =
> get_patched_datapath(patched_datapaths,
> >
>  binding_rec->datapath->tunnel_key);
> > @@ -268,6 +276,7 @@ add_patched_datapath(struct hmap *patched_datapaths,
> >      /* stale is set to false. */
> >      hmap_insert(patched_datapaths, &pd->hmap_node,
> >                  binding_rec->datapath->tunnel_key);
> > +    *datapath_assoc_chgd = true;
> >  }
> >
> >  static void
> > @@ -284,7 +293,8 @@ add_logical_patch_ports_preprocess(struct hmap
> > *patched_datapaths)
> >  /* This function should cleanup stale patched datapaths and any memory
> >   * allocated for fields within a stale patched datapath. */
> >  static void
> > -add_logical_patch_ports_postprocess(struct hmap *patched_datapaths)
> > +add_logical_patch_ports_postprocess(struct hmap *patched_datapaths,
> > +                                    bool *datapath_assoc_chgd)
> >  {
> >      /* Clean up stale patched datapaths. */
> >      struct patched_datapath *pd_cur_node, *pd_next_node;
> > @@ -294,6 +304,7 @@ add_logical_patch_ports_postprocess(struct hmap
> > *patched_datapaths)
> >              hmap_remove(patched_datapaths, &pd_cur_node->hmap_node);
> >              free(pd_cur_node->key);
> >              free(pd_cur_node);
> > +            datapath_assoc_chgd = true;
> >          }
> >      }
> >  }
> > @@ -325,7 +336,8 @@ add_logical_patch_ports(struct controller_ctx *ctx,
> >                          const struct ovsrec_bridge *br_int,
> >                          const char *local_chassis_id,
> >                          struct shash *existing_ports,
> > -                        struct hmap *patched_datapaths)
> > +                        struct hmap *patched_datapaths,
> > +                        bool *datapath_assoc_chgd)
> >  {
> >      const struct sbrec_chassis *chassis_rec;
> >      chassis_rec = get_chassis(ctx->ovnsb_idl, local_chassis_id);
> > @@ -357,10 +369,11 @@ add_logical_patch_ports(struct controller_ctx *ctx,
> >              char *dst_name = patch_port_name(peer, local);
> >              create_patch_port(ctx, "ovn-logical-patch-port", local,
> >                                br_int, src_name, br_int, dst_name,
> > -                              existing_ports);
> > +                              existing_ports, datapath_assoc_chgd);
> >              free(dst_name);
> >              free(src_name);
> > -            add_patched_datapath(patched_datapaths, binding,
> local_port);
> > +            add_patched_datapath(patched_datapaths, binding, local_port,
> > +                                 datapath_assoc_chgd);
> >              if (local_port) {
> >                  if (binding->chassis != chassis_rec &&
> ctx->ovnsb_idl_txn) {
> >                      sbrec_port_binding_set_chassis(binding,
> chassis_rec);
> > @@ -368,13 +381,14 @@ add_logical_patch_ports(struct controller_ctx *ctx,
> >              }
> >          }
> >      }
> > -    add_logical_patch_ports_postprocess(patched_datapaths);
> > +    add_logical_patch_ports_postprocess(patched_datapaths,
> > +                                        datapath_assoc_chgd);
> >  }
> >
> >  void
> >  patch_run(struct controller_ctx *ctx, const struct ovsrec_bridge
> *br_int,
> >            const char *chassis_id, struct hmap *local_datapaths,
> > -          struct hmap *patched_datapaths)
> > +          struct hmap *patched_datapaths, bool *datapath_assoc_chgd)
> >  {
> >      if (!ctx->ovs_idl_txn) {
> >          return;
> > @@ -396,7 +410,7 @@ patch_run(struct controller_ctx *ctx, const struct
> > ovsrec_bridge *br_int,
> >       * should be there. */
> >      add_bridge_mappings(ctx, br_int, &existing_ports, local_datapaths,
> >      chassis_id);
> >      add_logical_patch_ports(ctx, br_int, chassis_id, &existing_ports,
> > -                            patched_datapaths);
> > +                            patched_datapaths, datapath_assoc_chgd);
> >
> >      /* Now 'existing_ports' only still contains patch ports that exist
> in
> >      the
> >       * database but shouldn't.  Delete them from the database. */
> > @@ -405,6 +419,8 @@ patch_run(struct controller_ctx *ctx, const struct
> > ovsrec_bridge *br_int,
> >          struct ovsrec_port *port = port_node->data;
> >          shash_delete(&existing_ports, port_node);
> >          remove_port(ctx, port);
> > +        /* This may rarely lead to false positives. */
> > +        *datapath_assoc_chgd = true;
> >      }
> >      shash_destroy(&existing_ports);
> >  }
> > diff --git a/ovn/controller/patch.h b/ovn/controller/patch.h
> > index 7920a48..76d141c 100644
> > --- a/ovn/controller/patch.h
> > +++ b/ovn/controller/patch.h
> > @@ -22,12 +22,14 @@
> >   * This module adds and removes patch ports between the integration
> bridge
> >   and
> >   * physical bridges, as directed by other-config:ovn-bridge-mappings. */
> >
> > +#include <stdbool.h>
> > +
> >  struct controller_ctx;
> >  struct hmap;
> >  struct ovsrec_bridge;
> >
> >  void patch_run(struct controller_ctx *, const struct ovsrec_bridge
> *br_int,
> >                 const char *chassis_id, struct hmap *local_datapaths,
> > -               struct hmap *patched_datapaths);
> > +               struct hmap *patched_datapaths, bool
> *datapath_assoc_chgd);
> >
> >  #endif /* ovn/patch.h */
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index 16262cd..8ea7e93 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -3395,3 +3395,156 @@ AT_CHECK([ovs-appctl -t ovn-controller version],
> [0],
> > [ignore])
> >  OVN_CLEANUP([hv1])
> >
> >  AT_CLEANUP
> > +
> > +AT_SETUP([ovn -- 2 HVs, 3 LS, 1 lport/LS, 2 peer LRs, local router])
> > +AT_KEYWORDS([ovnlocalrouter])
> > +AT_SKIP_IF([test $HAVE_PYTHON = no])
> > +ovn_start
> > +
> > +# This simple testcase is used to demonstrate that logical router
> > +# openflow rules are not calculated and downloaded on HV1;  this is
> > +# because HV1 has no VIFs attached.  Conversely, logical router flows
> > +# are downloaded to HV2 following a flood fill algorithm as HV2 has
> > +# at least one VIF attached and logical associations alice/R2, bob/R2
> > +# and R2/R1.
> > +
> > +# Logical network:
> > +# Two LRs - R1 and R2 that are connected to each other as peers in
> > 20.0.0.0/24
> > +# network. R1 has switch foo (192.168.1.0/24) connected to it.
> > +# R2 has alice (172.16.1.0/24) and bob (172.16.2.0/24) connected to it.
> > +
> > +ovn-nbctl ls-add foo
> > +ovn-nbctl ls-add alice
> > +ovn-nbctl ls-add bob
> > +
> > +ovn-nbctl lr-add R1
> > +ovn-nbctl lr-add R2
> > +
> > +# Connect foo to R1
> > +ovn-nbctl lrp-add R1 foo 00:00:00: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 addresses=\"00:00:00:01:02:03\"
> > +
> > +# Connect alice to R2
> > +ovn-nbctl lrp-add R2 alice 00:00:00:01:02:04 172.16.1.1/24
> > +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice
> > type=router \
> > +    options:router-port=alice addresses=\"00:00:00:01:02:04\"
> > +
> > +# Connect bob to R2
> > +ovn-nbctl lrp-add R2 bob 00:00:00:01:02:05 172.16.2.1/24
> > +ovn-nbctl lsp-add bob rp-bob -- set Logical_Switch_Port rp-bob
> type=router \
> > +    options:router-port=bob addresses=\"00:00:00:01:02:05\"
> > +
> > +# Create logical port alice1 in alice
> > +ovn-nbctl lsp-add alice alice1 \
> > +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.2"
> > +
> > +# Create logical port bob1 in bob
> > +ovn-nbctl lsp-add bob bob1 \
> > +-- lsp-set-addresses bob1 "f0:00:00:01:02:05 172.16.2.2"
> > +
> > +# Create two hypervisor and create OVS ports corresponding to logical
> ports.
> > +net_add n1
> > +
> > +sim_add hv1
> > +as hv1
> > +ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.1
> > +
> > +sim_add hv2
> > +as hv2
> > +ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.2
> > +ovs-vsctl -- add-port br-int hv2-vif1 -- \
> > +    set interface hv2-vif1 external-ids:iface-id=bob1 \
> > +    options:tx_pcap=hv2/vif1-tx.pcap \
> > +    options:rxq_pcap=hv2/vif1-rx.pcap \
> > +    ofport-request=1
> > +
> > +ovs-vsctl -- add-port br-int hv2-vif2 -- \
> > +    set interface hv2-vif2 external-ids:iface-id=alice1 \
> > +    options:tx_pcap=hv2/vif2-tx.pcap \
> > +    options:rxq_pcap=hv2/vif2-rx.pcap \
> > +    ofport-request=2
> > +
> > +
> > +# 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
> > +
> > +# Allow some time for ovn-northd and ovn-controller to catch up.
> > +# XXX This should be more systematic.
> > +sleep 1
> > +
> > +ip_to_hex() {
> > +    printf "%02x%02x%02x%02x" "$@"
> > +}
> > +trim_zeros() {
> > +    sed 's/\(00\)\{1,\}$//'
> > +}
> > +
> > +# Send ip packets between bob1 and alice1
> > +src_mac="f00000010205"
> > +dst_mac="000000010205"
> > +src_ip=`ip_to_hex 172 16 2 2`
> > +dst_ip=`ip_to_hex 172 16 1 2`
> >
> +packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000
> > +as hv2 ovs-appctl netdev-dummy/receive hv2-vif1 $packet
> > +
> > +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 "------ hv1 dump ----------"
> > +as hv1 ovs-vsctl show
> > +as hv1 ovs-ofctl show br-int
> > +as hv1 ovs-ofctl dump-flows br-int
> > +echo "------ hv2 dump ----------"
> > +as hv2 ovs-vsctl show
> > +as hv2 ovs-ofctl show br-int
> > +as hv2 ovs-ofctl dump-flows br-int
> > +
> > +# Packet to Expect at alice1
> > +src_mac="000000010204"
> > +dst_mac="f00000010204"
> > +src_ip=`ip_to_hex 172 16 2 2`
> > +dst_ip=`ip_to_hex 172 16 1 2`
> >
> +expected=${dst_mac}${src_mac}08004500001c000000003f110100${src_ip}${dst_ip}0035111100080000
> > +
> > +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv2/vif2-tx.pcap |
> trim_zeros >
> > received.packets
> > +echo $expected | trim_zeros > expout
> > +AT_CHECK([cat received.packets], [0], [expout])
> > +
>
> Hi Darrell,
>
> The following lines can be replaced with:
>
>    OVN_CLEANUP([hv1],[hv2])
>

Thanks Lance
I did notice the new macro and would fold it in for
any versions going forward.



>
> > +for sim in hv1 hv2; do
> > +    as $sim
> > +    OVS_APP_EXIT_AND_WAIT([ovn-controller])
> > +    OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
> > +    OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> > +done
> > +
> > +as ovn-sb
> > +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> > +
> > +as ovn-nb
> > +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> > +
> > +as northd
> > +OVS_APP_EXIT_AND_WAIT([ovn-northd])
> > +
> > +as main
> > +OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
> > +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
> > +
> > +AT_CLEANUP
> > --
> > 1.9.1
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > http://openvswitch.org/mailman/listinfo/dev
> >
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to