[ovs-dev] [ovn-controller-vtep V6 6/7] ovn-controller-vtep: Extend vtep module to install Ucast_Macs_Remote.

Russell Bryant rbryant at redhat.com
Sun Aug 16 22:26:01 UTC 2015


On 08/09/2015 10:50 PM, Alex Wang wrote:
> This commit extends the vtep module to support creating the
> 'Ucast_Macs_Remote' table entries in the vtep database for
> MAC addresses on the ovn logical ports.
> 
> Signed-off-by: Alex Wang <alexw at nicira.com>
> ---
> V5->V6:
> - rebase.
> 
> V4->V5:
> - rebase on top of master.
> - rewrite the feature since a lot have changed.
> 
> V3->V4:
> - add logic to remove Ucast_Macs_Remote for non-existent MACs.
> 
> V2->V3:
> - rebase to master.
> 
> PATCH->V2:
> - split into separate commit.
> - few optimizations.
> ---
>  ovn/controller-vtep/vtep.c   |  329 ++++++++++++++++++++++++++++++++++++------
>  tests/ovn-controller-vtep.at |  136 +++++++++++++++++
>  2 files changed, 418 insertions(+), 47 deletions(-)
> 
> diff --git a/ovn/controller-vtep/vtep.c b/ovn/controller-vtep/vtep.c
> index 55d2e0d..1545b39 100644
> --- a/ovn/controller-vtep/vtep.c
> +++ b/ovn/controller-vtep/vtep.c
> @@ -19,7 +19,8 @@
>  
>  #include "lib/hash.h"
>  #include "lib/hmap.h"
> -#include "lib/smap.h"
> +#include "lib/shash.h"
> +#include "lib/sset.h"
>  #include "lib/util.h"
>  #include "ovn-controller-vtep.h"
>  #include "openvswitch/vlog.h"
> @@ -29,69 +30,239 @@
>  VLOG_DEFINE_THIS_MODULE(vtep);
>  
>  /*
> - * Scans through the Binding table in ovnsb and updates the vtep logical
> - * switch tunnel keys.
> + * Scans through the Binding table in ovnsb, and updates the vtep logical
> + * switch tunnel keys and the 'Ucast_Macs_Remote' table in the VTEP
> + * database.
>   *
>   */
>  
> +/* Searches the 'chassis_rec->encaps' for the first vtep tunnel
> + * configuration, returns the 'ip'. */
> +static const char *
> +get_chassis_vtep_ip(const struct sbrec_chassis *chassis_rec)
> +{
> +    if (chassis_rec) {
> +        size_t i;
> +
> +        for (i = 0; i < chassis_rec->n_encaps; i++) {
> +            if (!strcmp(chassis_rec->encaps[i]->type, "vxlan")) {
> +                return chassis_rec->encaps[i]->ip;
> +            }
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
> +/* Creates a new 'Ucast_Macs_Remote'. */
> +static struct vteprec_ucast_macs_remote *
> +create_umr(struct ovsdb_idl_txn *vtep_idl_txn, const char *mac,
> +           const struct vteprec_logical_switch *vtep_ls)
> +{
> +    struct vteprec_ucast_macs_remote *new_umr;
> +
> +    new_umr = vteprec_ucast_macs_remote_insert(vtep_idl_txn);
> +    vteprec_ucast_macs_remote_set_MAC(new_umr, mac);
> +    vteprec_ucast_macs_remote_set_logical_switch(new_umr, vtep_ls);
> +
> +    return new_umr;
> +}
> +
> +/* Creates a new 'Physical_Locator'. */
> +static struct vteprec_physical_locator *
> +create_pl(struct ovsdb_idl_txn *vtep_idl_txn, const char *chassis_ip)
> +{
> +    struct vteprec_physical_locator *new_pl;
> +
> +    new_pl = vteprec_physical_locator_insert(vtep_idl_txn);
> +    vteprec_physical_locator_set_dst_ip(new_pl, chassis_ip);
> +    vteprec_physical_locator_set_encapsulation_type(new_pl, VTEP_ENCAP_TYPE);
> +
> +    return new_pl;
> +}
> +
> +
>  /* Updates the vtep Logical_Switch table entries' tunnel keys based
>   * on the port bindings. */
>  static void
> -vtep_lswitch_run(struct controller_vtep_ctx *ctx)
> +vtep_lswitch_run(struct shash *vtep_pbs, struct shash *vtep_lswitches)
>  {
> -    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);
> -    }
> +    struct sset used_ls = SSET_INITIALIZER(&used_ls);
> +    struct shash_node *node;
>  
> -    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) {
> -        if (!strcmp(port_binding_rec->type, "vtep")
> -            && port_binding_rec->chassis) {
> -            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);
> -            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);
> -                }
> +    SHASH_FOR_EACH (node, vtep_pbs) {
> +        const struct sbrec_port_binding *port_binding_rec = node->data;
> +        const char *lswitch_name = smap_get(&port_binding_rec->options,
> +                                            "vtep-logical-switch");
> +        const struct vteprec_logical_switch *vtep_ls;
> +
> +        /* 'lswitch_name' must exist. */
> +        ovs_assert(lswitch_name);
> +        vtep_ls = shash_find_data(vtep_lswitches, lswitch_name);
> +        if (!vtep_ls) {
> +            /* This could only happen when someone is messing up
> +             * using ovn-sbctl command. */
> +            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);
>              }
> +            /* sset will ignore duplicates. */
> +            sset_add(&used_ls, lswitch_name);
>          }
>      }
> +    /* Resets the tunnel keys for unused vtep logical switches. */
> +    SHASH_FOR_EACH (node, vtep_lswitches) {
> +        const struct vteprec_logical_switch *vtep_ls = node->data;
> +        if (!sset_find(&used_ls, vtep_ls->name)) {
> +            int64_t tnl_key = 0;
> +            vteprec_logical_switch_set_tunnel_key(node->data, &tnl_key, 1);
> +        }
> +    }
> +    sset_destroy(&used_ls);
> +}
> +
> +/* Updates the vtep 'Ucast_Macs_Remote' table based on non-vtep port
> + * bindings. */
> +static void
> +vtep_macs_run(struct ovsdb_idl_txn *vtep_idl_txn, struct shash *ucast_macs_rmts,
> +              struct shash *physical_locators, struct shash *vtep_lswitches,
> +              struct shash *other_pbs)
> +{
>      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;
> +    struct hmap ls_map;
> +
> +    /* Maps from ovn logical datapath tunnel key (which is also the vtep
> +     * logical switch tunnel key) to the corresponding vtep logical switch
> +     * instance.  Also, the shash map 'added_macs' is used for checking
> +     * duplicated MAC addresses in the same ovn logical datapath. */
> +    struct ls_hash_node {
> +        struct hmap_node hmap_node;
> +
> +        const struct vteprec_logical_switch *vtep_ls;
> +        struct shash added_macs;
> +    };
> +
> +    hmap_init(&ls_map);
> +    SHASH_FOR_EACH (node, vtep_lswitches) {
> +        struct ls_hash_node *ls_node = xmalloc(sizeof *ls_node);
>  
> -        vteprec_logical_switch_set_tunnel_key(node->data, &tnl_key, 1);
> +        ls_node->vtep_ls = node->data;
> +        shash_init(&ls_node->added_macs);
> +        hmap_insert(&ls_map, &ls_node->hmap_node,
> +                    hash_uint64((uint64_t) ls_node->vtep_ls->tunnel_key[0]));
>      }
>  
> -    shash_destroy(&vtep_lswitches);
> +    SHASH_FOR_EACH (node, other_pbs) {
> +        const struct sbrec_port_binding *port_binding_rec = node->data;
> +        const struct sbrec_chassis *chassis_rec;
> +        struct ls_hash_node *ls_node;
> +        const char *chassis_ip;
> +        int64_t tnl_key;
> +        int i;

This is pretty pedantic, but I'd make this size_t.

> +
> +        chassis_rec = port_binding_rec->chassis;
> +        chassis_ip = get_chassis_vtep_ip(chassis_rec);
> +
> +        /* Unreachable chassis, continue. */
> +        if (!chassis_ip) {
> +            continue;
> +        }
> +
> +        tnl_key = port_binding_rec->datapath->tunnel_key;
> +        HMAP_FOR_EACH_WITH_HASH (ls_node, hmap_node,
> +                                 hash_uint64((uint64_t) tnl_key),
> +                                 &ls_map) {
> +            if (ls_node->vtep_ls->tunnel_key[0] == tnl_key) {
> +                break;
> +            }
> +        }
> +        /* If 'ls_node' is NULL, that means no vtep logical switch is
> +         * attached to the corresponding ovn logical datapath, so pass. */
> +        if (!ls_node) {
> +            continue;
> +        }

I don't think ls_node is guaranteed to be NULL here, even when the loop
ends normally (without a break).

> +
> +        for (i = 0; i < port_binding_rec->n_mac; i++) {
> +            const struct vteprec_ucast_macs_remote *umr;
> +            const struct vteprec_physical_locator *pl;
> +            const struct sbrec_port_binding *conflict;
> +            char *mac = port_binding_rec->mac[i];
> +
> +            /* xxx Need to address this. */
> +            if (!strcmp(mac, "unknown")) {
> +                continue;
> +            }

Thanks for noting this.  I was wondering how this was going to work.
I'm fine leaving it as a todo item for now though.

> +
> +            /* Checks for duplicate MAC in the same vtep logical switch. */
> +            conflict = shash_find_data(&ls_node->added_macs, mac);
> +            if (conflict) {
> +                VLOG_WARN("MAC address (%s) has already been known to be "
> +                          "on logical port (%s) in the same logical "
> +                          "datapath, so just ignore this logical port (%s)",
> +                          mac, conflict->logical_port,
> +                          port_binding_rec->logical_port);
> +                continue;
> +            }
> +            shash_add(&ls_node->added_macs, mac, port_binding_rec);
> +
> +            char *mac_ip = xasprintf("%s%s", mac, chassis_ip);
> +            umr = shash_find_data(ucast_macs_rmts, mac_ip);
> +            /* If finds the 'umr' entry for the mac and ip, deletes the
> +             * entry from shash so that it is not gargage collected.
> +             *
> +             * If not found, creates a new 'umr' entry.
> +             *
> +             * If vtep logical switch does not match, the logical port
> +             * owning the MAC may be moved to a new ovn logical datapath.
> +             * In that case, just creates a new umr entry for the MAC.
> +             * The old one will be garbage collected. */
> +            if (umr && umr->logical_switch == ls_node->vtep_ls) {
> +                shash_find_and_delete(ucast_macs_rmts, mac_ip);
> +            } else {
> +                const struct vteprec_ucast_macs_remote *new_umr;
> +
> +                new_umr = create_umr(vtep_idl_txn, mac, ls_node->vtep_ls);
> +                pl = shash_find_data(physical_locators, chassis_ip);
> +                if (pl) {
> +                    vteprec_ucast_macs_remote_set_locator(new_umr, pl);
> +                } else {
> +                    const struct vteprec_physical_locator *new_pl;
> +
> +                    new_pl = create_pl(vtep_idl_txn, chassis_ip);
> +                    vteprec_ucast_macs_remote_set_locator(new_umr, new_pl);
> +                    /* Updates the 'physical_locators'. */
> +                    shash_add(physical_locators, chassis_ip, new_pl);
> +                }
> +            }
> +            free(mac_ip);
> +        }
> +    }
> +
> +    /* Removes all remaining 'umr's, since they do not exist anymore. */
> +    SHASH_FOR_EACH (node, ucast_macs_rmts) {
> +        vteprec_ucast_macs_remote_delete(node->data);
> +    }
> +    struct ls_hash_node *iter, *next;
> +    HMAP_FOR_EACH_SAFE (iter, next, hmap_node, &ls_map) {
> +        hmap_remove(&ls_map, &iter->hmap_node);
> +        shash_destroy(&iter->added_macs);
> +        free(iter);
> +    }
> +    hmap_destroy(&ls_map);
>  }
>  
>  /* Since we do not own any vtep logical switch, just sets their tunnel key
> @@ -107,6 +278,19 @@ vtep_lswitch_cleanup(struct ovsdb_idl *vtep_idl)
>      }
>  }
>  
> +/* Removes all entries in the 'Ucast_Macs_Remote' table in vtep database.
> + * Returns true when all done. */
> +static bool
> +vtep_macs_cleanup(struct ovsdb_idl *vtep_idl)
> +{
> +    const struct vteprec_ucast_macs_remote *umr;
> +
> +    VTEPREC_UCAST_MACS_REMOTE_FOR_EACH (umr, vtep_idl) {
> +        vteprec_ucast_macs_remote_delete(umr);
> +        return false;
> +    }
> +    return true;
> +}
>  
>  /* Updates vtep logical switch tunnel keys. */
>  void
> @@ -115,7 +299,59 @@ vtep_run(struct controller_vtep_ctx *ctx)
>      if (!ctx->vtep_idl_txn) {
>          return;
>      }
> -    vtep_lswitch_run(ctx);
> +
> +    struct shash vtep_lswitches = SHASH_INITIALIZER(&vtep_lswitches);
> +    struct shash ucast_macs_rmts = SHASH_INITIALIZER(&ucast_macs_rmts);
> +    struct shash physical_locators = SHASH_INITIALIZER(&physical_locators);
> +    struct shash vtep_pbs = SHASH_INITIALIZER(&vtep_pbs);
> +    struct shash other_pbs = SHASH_INITIALIZER(&other_pbs);
> +    const struct vteprec_logical_switch *vtep_ls;
> +    const struct vteprec_ucast_macs_remote *umr;
> +    const struct vteprec_physical_locator *pl;
> +    const struct sbrec_port_binding *port_binding_rec;
> +
> +    /* Collects 'Logical_Switch's. */
> +    VTEPREC_LOGICAL_SWITCH_FOR_EACH (vtep_ls, ctx->vtep_idl) {
> +        shash_add(&vtep_lswitches, vtep_ls->name, vtep_ls);
> +    }
> +
> +    /* Collects 'Ucast_Macs_Remote's. */
> +    VTEPREC_UCAST_MACS_REMOTE_FOR_EACH (umr, ctx->vtep_idl) {
> +        char *mac_ip =
> +            xasprintf("%s%s", umr->MAC,
> +                     umr->locator ? umr->locator->dst_ip : "");
> +
> +        shash_add(&ucast_macs_rmts, mac_ip, umr);
> +        free(mac_ip);
> +    }
> +    /* Collects 'Physical_Locator's. */
> +    VTEPREC_PHYSICAL_LOCATOR_FOR_EACH (pl, ctx->vtep_idl) {
> +        shash_add(&physical_locators, pl->dst_ip, pl);
> +    }
> +    /* Collects and classifies 'Port_Binding's. */
> +    SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->ovnsb_idl) {
> +        struct shash *target =
> +            !strcmp(port_binding_rec->type, "vtep") ? &vtep_pbs : &other_pbs;
> +
> +        if (!port_binding_rec->chassis) {
> +            continue;
> +        }
> +        shash_add(target, port_binding_rec->logical_port, port_binding_rec);
> +    }
> +
> +    ovsdb_idl_txn_add_comment(ctx->vtep_idl_txn,
> +                              "ovn-controller-vtep: update logical switch "
> +                              "tunnel keys and 'ucast_macs_remote's");
> +
> +    vtep_lswitch_run(&vtep_pbs, &vtep_lswitches);
> +    vtep_macs_run(ctx->vtep_idl_txn, &ucast_macs_rmts, &physical_locators,
> +                  &vtep_lswitches, &other_pbs);
> +
> +    shash_destroy(&vtep_lswitches);
> +    shash_destroy(&ucast_macs_rmts);
> +    shash_destroy(&physical_locators);
> +    shash_destroy(&vtep_pbs);
> +    shash_destroy(&other_pbs);
>  }
>  
>  /* Cleans up all created vtep related entries.  Returns true when all done. */
> @@ -129,6 +365,5 @@ vtep_cleanup(struct controller_vtep_ctx *ctx)
>      ovsdb_idl_txn_add_comment(ctx->vtep_idl_txn,
>                                "cleans up vtep configuration");
>      vtep_lswitch_cleanup(ctx->vtep_idl);
> -
> -    return true;
> +    return vtep_macs_cleanup(ctx->vtep_idl);
>  }
> diff --git a/tests/ovn-controller-vtep.at b/tests/ovn-controller-vtep.at
> index ea58636..8d8b7c4 100644
> --- a/tests/ovn-controller-vtep.at
> +++ b/tests/ovn-controller-vtep.at
> @@ -294,3 +294,139 @@ AT_CHECK([vtep-ctl --columns=tunnel_key list Logical_Switch | cut -d ':' -f2 | t
>  
>  OVN_CONTROLLER_VTEP_STOP
>  AT_CLEANUP
> +
> +
> +# Tests vtep module 'Ucast_Macs_Remote's.
> +AT_SETUP([ovn-controller-vtep - test vtep-macs 1])
> +OVN_CONTROLLER_VTEP_START
> +
> +# creates a simple logical network with the vtep device and a fake hv chassis
> +# 'ch0'.
> +AT_CHECK([ovn-nbctl lport-add br-test vif0])
> +AT_CHECK([ovn-nbctl lport-set-macs vif0 f0:ab:cd:ef:01:02])
> +AT_CHECK([ovn-sbctl chassis-add ch0 vxlan 1.2.3.5])
> +AT_CHECK([ovn-sbctl lport-bind vif0 ch0])
> +
> +# 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`"])
> +
> +# adds another lswitch 'br-void' in ovn-nb database.
> +AT_CHECK([ovn-nbctl lswitch-add br-void])
> +# adds fake hv chassis 'ch1'.
> +AT_CHECK([ovn-nbctl lport-add br-void vif1])
> +AT_CHECK([ovn-nbctl lport-set-macs vif1 f0:ab:cd:ef:01:02])
> +AT_CHECK([ovn-sbctl chassis-add ch1 vxlan 1.2.3.6])
> +AT_CHECK([ovn-sbctl lport-bind vif1 ch1])
> +OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep vif1`"])
> +
> +# checks Ucast_Macs_Remote creation.
> +OVS_WAIT_UNTIL([test -n "`vtep-ctl list Ucast_Macs_Remote | grep _uuid`"])
> +AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' '], [0], [dnl
> +"f0:ab:cd:ef:01:02"
> +])
> +
> +# checks physical locator creation.
> +OVS_WAIT_UNTIL([test -n "`vtep-ctl list Physical_Locator | grep _uuid`"])
> +AT_CHECK([vtep-ctl --columns=dst_ip list Physical_Locator | cut -d ':' -f2 | tr -d ' ' | grep -v 1.2.3.4 | sed '/^$/d'], [0], [dnl
> +"1.2.3.5"
> +])
> +
> +# checks tunnel creation by ovs-vtep.
> +OVS_WAIT_UNTIL([test -n "`ovs-vsctl list Interface bfd1.2.3.5`"])
> +AT_CHECK([ovs-vsctl --columns=options list Interface bfd1.2.3.5 | cut -d ':' -f2 | tr -d ' '], [0], [dnl
> +{remote_ip="1.2.3.5"}
> +])
> +
> +# adds another mac to lport.
> +AT_CHECK([ovn-nbctl lport-set-macs vif0 f0:ab:cd:ef:01:02 f0:ab:cd:ef:01:03])
> +OVS_WAIT_UNTIL([test -n "`vtep-ctl list Ucast_Macs_Remote | grep 03`"])
> +AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' ' | sort], [0], [dnl
> +
> +"f0:ab:cd:ef:01:02"
> +"f0:ab:cd:ef:01:03"
> +])
> +
> +# removes one mac to lport.
> +AT_CHECK([ovn-nbctl lport-set-macs vif0 f0:ab:cd:ef:01:03])
> +OVS_WAIT_UNTIL([test -z "`vtep-ctl --columns=MAC list Ucast_Macs_Remote | grep 02`"])
> +AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' ' | sort], [0], [dnl
> +"f0:ab:cd:ef:01:03"
> +])
> +
> +# migrates mac to lport vif1 on 'br-void'.
> +AT_CHECK([ovn-nbctl lport-set-macs vif0])
> +AT_CHECK([ovn-nbctl lport-set-macs vif1 f0:ab:cd:ef:01:03])
> +OVS_WAIT_UNTIL([test -z "`vtep-ctl --columns=MAC list Ucast_Macs_Remote | grep 03`"])
> +AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' ' | sort], [0], [dnl
> +])
> +
> +OVN_CONTROLLER_VTEP_STOP
> +AT_CLEANUP
> +
> +
> +# Tests vtep module 'Ucast_Macs_Remote's (corner cases).
> +AT_SETUP([ovn-controller-vtep - test vtep-macs 2])
> +OVN_CONTROLLER_VTEP_START
> +
> +# creates a simple logical network with the vtep device and a fake hv chassis
> +# 'ch0'.
> +AT_CHECK([ovn-nbctl lport-add br-test vif0])
> +AT_CHECK([ovn-nbctl lport-set-macs vif0 f0:ab:cd:ef:01:02])
> +AT_CHECK([ovn-sbctl chassis-add ch0 vxlan 1.2.3.5])
> +AT_CHECK([ovn-sbctl lport-bind vif0 ch0])
> +
> +# creates another vif in the same logical switch with duplicate mac.
> +AT_CHECK([ovn-nbctl lport-add br-test vif1])
> +AT_CHECK([ovn-nbctl lport-set-macs vif1 f0:ab:cd:ef:01:02])
> +AT_CHECK([ovn-sbctl lport-bind vif1 ch0])
> +
> +# 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`"])
> +
> +# checks Ucast_Macs_Remote creation.  Should still only be one entry, since duplicate
> +# mac in the same logical switch is not allowed.
> +OVS_WAIT_UNTIL([test -n "`vtep-ctl list Ucast_Macs_Remote | grep _uuid`"])
> +AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' '], [0], [dnl
> +"f0:ab:cd:ef:01:02"
> +])
> +# confirms the warning log.
> +OVS_WAIT_UNTIL([test -n "`grep WARN ovn-controller-vtep.log`"])
> +AT_CHECK([sed -n 's/^.*\(|WARN|.*\)$/\1/p' ovn-controller-vtep.log | sed 's/([[-_:0-9a-z]][[-_:0-9a-z]]*)/()/g' | uniq], [0], [dnl
> +|WARN|MAC address () has already been known to be on logical port () in the same logical datapath, so just ignore this logical port ()
> +])
> +
> +# deletes vif1.
> +AT_CHECK([ovn-nbctl lport-del vif1])
> +
> +# adds another lswitch 'br-void' in ovn-nb database.
> +AT_CHECK([ovn-nbctl lswitch-add br-void])
> +# adds fake hv chassis 'ch1' and vif1 with same mac address as vif0.
> +AT_CHECK([ovn-nbctl lport-add br-void vif1])
> +AT_CHECK([ovn-nbctl lport-set-macs vif1 f0:ab:cd:ef:01:02])
> +AT_CHECK([ovn-sbctl chassis-add ch1 vxlan 1.2.3.6])
> +AT_CHECK([ovn-sbctl lport-bind vif1 ch1])
> +OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep vif1`"])
> +
> +# creates another logical switch in vtep and adds the corresponding logical
> +# port to 'br-void'.
> +AT_CHECK([vtep-ctl add-ls lswitch1 -- bind-ls br-vtep p0 200 lswitch1])
> +OVN_NB_ADD_VTEP_PORT([br-void], [br-void_lswitch1], [br-vtep], [lswitch1])
> +OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding  | grep br-void_lswitch1`"])
> +
> +# checks Ucast_Macs_Remote creation.  Should see two entries since it is allowed
> +# to have duplicate macs in different logical switches.
> +OVS_WAIT_UNTIL([test `vtep-ctl --columns=MAC list Ucast_Macs_Remote | grep 02 | wc -l` -gt 1])
> +AT_CHECK([vtep-ctl --columns=MAC list Ucast_Macs_Remote | cut -d ':' -f2- | tr -d ' ' | sort], [0], [dnl
> +
> +"f0:ab:cd:ef:01:02"
> +"f0:ab:cd:ef:01:02"
> +])
> +
> +OVN_CONTROLLER_VTEP_STOP(["/has already been known to be on logical port/d"])
> +AT_CLEANUP
> 


-- 
Russell Bryant



More information about the dev mailing list