Hello I'm trying to implement the following TODO* Update learned MAC addresses from VTEP to OVN *from [0]. I'm trying to push macs from Mcast_Macs_Local to OVN SB Mac_Binding. In Mcast_Macs_Local ip address is optional while in Mac_Binding it seems empty string is allowed but services will complain for such mac with the wolling error:
+2025-05-13T11:07:35.485Z|00048|lflow|WARN|bad 'ip' +2025-05-13T11:07:35.598Z|00051|mac_cache|WARN|Couldn't parse MAC binding: ip=, mac=02:00:00:00:00:ff So my question is Mac_Binding is the correct table which we can use for VTEP mac synchronization? [0] Update learned MAC addresses from VTEP to OVN On Tue, May 13, 2025 at 1:50 PM Vasyl Saienko <vsaie...@mirantis.com> wrote: > With this patch ovn-controller-vtep start synchronizing local > MAC database to Mac_Binding OVN SB table. Which helps to resolve > couple of problems: > > 1. Connectivity between hosts plugged to different switches. > Currently OVN does not create tunnel between hardware switches > even when they have ports plugged to same network. > With this patch ovn-controller-vtep checking for Mac_Binding > OVN SB database and setup required tunnels between switches. > > 2. OVN rely on broadcasts when send data to remote VTEP MACs. > Since now we propagate switch local MAC table to SB database, > later this information may be used by ovn-controller instances > to create direct rules for hosts discovered from remote VTEPs. > > Signed-off-by: Vasyl Saienko <vsaie...@mirantis.com> > --- > controller-vtep/ovn-controller-vtep.c | 9 + > controller-vtep/vtep.c | 301 +++++++++++++++++++++++++- > tests/ovn-controller-vtep.at | 124 ++++++++++- > 3 files changed, 425 insertions(+), 9 deletions(-) > > diff --git a/controller-vtep/ovn-controller-vtep.c > b/controller-vtep/ovn-controller-vtep.c > index 698511482..7e64bacf5 100644 > --- a/controller-vtep/ovn-controller-vtep.c > +++ b/controller-vtep/ovn-controller-vtep.c > @@ -172,6 +172,15 @@ main(int argc, char *argv[]) > ovsdb_idl_add_column(ovnsb_idl_loop.idl, > &sbrec_port_binding_col_type); > ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_up); > > + /* Listen for Mac_Binding changes, we use this table to create tunnels > + * for macs learned from other VTEPs */ > + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_mac_binding); > + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_mac); > + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_ip); > + ovsdb_idl_add_column(ovnsb_idl_loop.idl, > + &sbrec_mac_binding_col_logical_port); > + ovsdb_idl_add_column(ovnsb_idl_loop.idl, > &sbrec_mac_binding_col_datapath); > + > ovsdb_idl_set_leader_only(ovnsb_idl_loop.idl, false); > ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl); > > diff --git a/controller-vtep/vtep.c b/controller-vtep/vtep.c > index 7f5e1d606..0975b11f4 100644 > --- a/controller-vtep/vtep.c > +++ b/controller-vtep/vtep.c > @@ -42,6 +42,11 @@ struct mmr_hash_node_data { > struct shash physical_locators; > }; > > +struct lp_mac_ip_binding { > + const char *lp; > + struct shash mac_ip_lp; > +}; > + > /* > * Scans through the Binding table in ovnsb, and updates the vtep logical > * switch tunnel keys and the 'Ucast_Macs_Remote' table in the VTEP > @@ -90,7 +95,8 @@ create_pl(struct ovsdb_idl_txn *vtep_idl_txn, const char > *chassis_ip) > 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); > + vteprec_physical_locator_set_encapsulation_type(new_pl, > + VTEP_ENCAP_TYPE); > > return new_pl; > } > @@ -267,9 +273,15 @@ vtep_lswitch_run(struct shash *vtep_pbs, struct sset > *vtep_pswitches, > /* Updates the vtep 'Ucast_Macs_Remote' and 'Mcast_Macs_Remote' tables > 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 *mcast_macs_rmts, struct shash > *physical_locators, > - struct shash *vtep_lswitches, struct shash *non_vtep_pbs) > +vtep_macs_run(struct ovsdb_idl_txn *vtep_idl_txn, > + struct shash *ucast_macs_rmts, > + struct shash *mcast_macs_rmts, > + struct shash *physical_locators, > + struct shash *vtep_lswitches, > + struct shash *non_vtep_pbs, > + struct shash *vtep_pbs, > + struct shash *sbrec_lp_mac_binding, > + struct sset *vtep_pswitches) > { > struct shash_node *node; > struct hmap ls_map; > @@ -344,6 +356,14 @@ vtep_macs_run(struct ovsdb_idl_txn *vtep_idl_txn, > struct shash *ucast_macs_rmts, > continue; > } > tnl_key = peer_pb->datapath->tunnel_key; > + } else if (!strcmp(port_binding_rec->type, "external")) { > + /* External ports sits actually behind remote VTEPs > + * but port itself is bound to one of gateway nodes > + * to provide DHCP/Metadata. Skip port_binding > + * information for such ports, as its does not specify > + * real node location. Use dynamically learned Mac_Binding > + * records from remote VTEPs */ > + continue; > } else { > tnl_key = port_binding_rec->datapath->tunnel_key; > } > @@ -445,6 +465,118 @@ vtep_macs_run(struct ovsdb_idl_txn *vtep_idl_txn, > struct shash *ucast_macs_rmts, > } > } > > + /* Handle dynamically leart MACs from remote VTEPs registered in > + * Mac_Binding table. */ > + SHASH_FOR_EACH (node, vtep_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; > + > + chassis_rec = port_binding_rec->chassis; > + if (!chassis_rec) { > + continue; > + } > + > + const char *pswitch_name = smap_get(&port_binding_rec->options, > + "vtep-physical-switch"); > + /* Ignore macs learned by ourselfs */ > + if (sset_find(vtep_pswitches, pswitch_name)) { > + 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; > + } > + > + chassis_ip = get_chassis_vtep_ip(chassis_rec); > + /* Unreachable chassis, continue. */ > + if (!chassis_ip) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_INFO_RL(&rl, "VTEP tunnel encap on chassis (%s) not > found", > + chassis_rec->name); > + continue; > + } > + > + const struct vteprec_physical_locator *pl = > + shash_find_data(physical_locators, chassis_ip); > + if (!pl) { > + pl = create_pl(vtep_idl_txn, chassis_ip); > + shash_add(physical_locators, chassis_ip, pl); > + } > + > + const struct vteprec_physical_locator *ls_pl = > + shash_find_data(&ls_node->physical_locators, chassis_ip); > + if (!ls_pl) { > + struct vtep_rec_physical_locator_list_entry *ploc_entry = > + xmalloc(sizeof *ploc_entry); > + ploc_entry->vteprec_ploc = pl; > + ovs_list_push_back(&ls_node->locators_list, > + &ploc_entry->locators_node); > + shash_add(&ls_node->physical_locators, chassis_ip, pl); > + } > + > + > + struct lp_mac_ip_binding *miplpb = shash_find_data( > + sbrec_lp_mac_binding, port_binding_rec->logical_port); > + struct shash_node *miplb_node; > + if (!miplpb) { > + continue; > + } > + SHASH_FOR_EACH (miplb_node, &miplpb->mac_ip_lp) { > + const struct sbrec_mac_binding * mb = miplb_node->data; > + /* Ignore MACs from other networks (datapathese) */ > + if (port_binding_rec->datapath->tunnel_key != > + mb->datapath->tunnel_key) { > + continue; > + } > + const struct vteprec_ucast_macs_remote *umr; > + const struct sbrec_port_binding *conflict; > + > + char *mac = mb->mac; > + > + /* 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_tnlkey = xasprintf("%s_%s_%"PRId64, mac, > chassis_ip, > + tnl_key); > + umr = shash_find_data(ucast_macs_rmts, mac_ip_tnlkey); > + /* If finds the 'umr' entry for the mac, ip, and tnl_key, > deletes > + * the entry from shash so that it is not garbage collected. > + * > + * If not found, creates a new 'umr' entry. */ > + if (umr && umr->logical_switch == ls_node->vtep_ls) { > + shash_find_and_delete(ucast_macs_rmts, mac_ip_tnlkey); > + } else { > + const struct vteprec_ucast_macs_remote *new_umr; > + new_umr = create_umr(vtep_idl_txn, mac, ls_node->vtep_ls); > + vteprec_ucast_macs_remote_set_locator(new_umr, pl); > + } > + free(mac_ip_tnlkey); > + } > + } > + > /* 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); > @@ -454,7 +586,7 @@ vtep_macs_run(struct ovsdb_idl_txn *vtep_idl_txn, > struct shash *ucast_macs_rmts, > struct vtep_rec_physical_locator_list_entry *ploc_entry; > vtep_update_mmr(vtep_idl_txn, &iter->locators_list, > iter->vtep_ls, iter->mmr_ext); > - LIST_FOR_EACH_POP(ploc_entry, locators_node, > + LIST_FOR_EACH_POP (ploc_entry, locators_node, > &iter->locators_list) { > free(ploc_entry); > } > @@ -519,6 +651,123 @@ vtep_mcast_macs_cleanup(struct ovsdb_idl *vtep_idl) > > return true; > } > + > +static const struct sbrec_port_binding * > +find_pbs_for_logical_switch(struct shash *vtep_pbs, > + struct sset *vtep_pswitches, > + char *ls_name){ > + > + struct shash_node *node; > + SHASH_FOR_EACH (node, vtep_pbs) { > + const struct sbrec_port_binding *port_binding_rec = node->data; > + const char *pswitch_name = smap_get(&port_binding_rec->options, > + "vtep-physical-switch"); > + const char *lswitch_name = smap_get(&port_binding_rec->options, > + "vtep-logical-switch"); > + if (!port_binding_rec->chassis) { > + continue; > + } > + > + /* If 'port_binding_rec->chassis' exists then 'pswitch_name' > + * and 'lswitch_name' must also exist. */ > + if (!pswitch_name || !lswitch_name) { > + /* This could only happen when someone directly modifies the > + * database, (e.g. using ovn-sbctl). */ > + VLOG_ERR("logical port (%s) with no 'options:vtep-physical-" > + "switch' or 'options:vtep-logical-switch' specified " > + "is bound to chassis (%s).", > + port_binding_rec->logical_port, > + port_binding_rec->chassis->name); > + continue; > + } > + /* Make sure both logical_switch and physical_switch matches */ > + if (!strcmp(ls_name, lswitch_name)) { > + if (sset_find(vtep_pswitches, port_binding_rec->chassis->name)) > { > + return port_binding_rec; > + } > + } > + } > + return NULL; > +} > + > +/* Propagate dynamically learned MACs on local VTEPs to OVN SB. Where > + * later this information is used to create tunnels between neighbour > + * VTEPs. > +*/ > +static void > +vtep_local_macs(struct controller_vtep_ctx *ctx, > + struct shash *vtep_pbs, > + struct sset *vtep_pswitches, > + struct shash *vtep_lswitches, > + struct shash *sbrec_lp_mac_binding){ > + > + if (!ctx->ovnsb_idl_txn) { > + return; > + } > + > + ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn, > + "ovn-controller-vtep: updating > mac_binding"); > + > + const struct vteprec_ucast_macs_local *vtep_uml; > + const struct sbrec_port_binding *port_binding_rec; > + const struct sbrec_mac_binding *mb; > + > + /* Collect local unicast MACs */ > + VTEPREC_UCAST_MACS_LOCAL_FOR_EACH (vtep_uml, ctx->vtep_idl) { > + port_binding_rec = find_pbs_for_logical_switch( > + vtep_pbs, vtep_pswitches, vtep_uml->logical_switch->name); > + if (!port_binding_rec) { > + VLOG_ERR("Cannot find port_binding for dynamically learned > MAC %s " > + "in logical_switch %s", vtep_uml->MAC, > + vtep_uml->logical_switch->name); > + continue; > + } > + > + struct lp_mac_ip_binding *miplpb = shash_find_data( > + sbrec_lp_mac_binding, port_binding_rec->logical_port); > + mb = NULL; > + if (miplpb) { > + char *mac_ip_lp_key = xasprintf("%s_%s_%s", vtep_uml->MAC, > + vtep_uml->ipaddr, > + > port_binding_rec->logical_port); > + mb = shash_find_and_delete(&miplpb->mac_ip_lp, mac_ip_lp_key); > + free(mac_ip_lp_key); > + } > + > + if (!mb) { > + VLOG_DBG("Creating new mac_binding entry for mac %s", > + vtep_uml->MAC); > + mb = sbrec_mac_binding_insert(ctx->ovnsb_idl_txn); > + sbrec_mac_binding_set_mac(mb, vtep_uml->MAC); > + sbrec_mac_binding_set_logical_port( > + mb, port_binding_rec->logical_port); > + sbrec_mac_binding_set_timestamp(mb, time_wall_msec()); > + } > + sbrec_mac_binding_set_ip(mb, vtep_uml->ipaddr); > + sbrec_mac_binding_set_datapath(mb, port_binding_rec->datapath); > + } > + > + struct shash_node *node; > + struct shash_node *miplb_node; > + SHASH_FOR_EACH (node, vtep_lswitches) { > + port_binding_rec = find_pbs_for_logical_switch(vtep_pbs, > + vtep_pswitches, > + node->name); > + if (!port_binding_rec) { > + continue; > + } > + struct lp_mac_ip_binding *miplpb = shash_find_data( > + sbrec_lp_mac_binding, port_binding_rec->logical_port); > + if (!miplpb) { > + continue; > + } > + SHASH_FOR_EACH (miplb_node, &miplpb->mac_ip_lp) { > + mb = miplb_node->data; > + VLOG_DBG("Removing mac_binding for stale VTEP mac %s", > mb->mac); > + sbrec_mac_binding_delete(mb); > + } > + } > +} > > /* Updates vtep logical switch tunnel keys. */ > void > @@ -593,7 +842,7 @@ vtep_run(struct controller_vtep_ctx *ctx) > } > > /* Collects and classifies 'Port_Binding's. */ > - SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->ovnsb_idl) { > + SBREC_PORT_BINDING_FOR_EACH (port_binding_rec, ctx->ovnsb_idl) { > struct shash *target = > !strcmp(port_binding_rec->type, "vtep") ? &vtep_pbs > : &non_vtep_pbs; > @@ -605,6 +854,33 @@ vtep_run(struct controller_vtep_ctx *ctx) > shash_add(target, port_binding_rec->logical_port, > port_binding_rec); > } > > + /* Construct logical_port to mac_binding */ > + const struct sbrec_mac_binding *mb; > + struct shash sbrec_lp_mac_binding = SHASH_INITIALIZER( > + &sbrec_lp_mac_binding); > + SBREC_MAC_BINDING_FOR_EACH (mb, ctx->ovnsb_idl) { > + if (!mb->logical_port) { > + continue; > + } > + char *mac_ip_lp_key = xasprintf("%s_%s_%s", mb->mac, mb->ip, > + mb->logical_port); > + > + struct lp_mac_ip_binding *miplpb = shash_find_data( > + &sbrec_lp_mac_binding, mb->logical_port); > + if (!miplpb) { > + struct lp_mac_ip_binding *sbrec_mac_ip_lp_binding = xmalloc( > + sizeof *sbrec_mac_ip_lp_binding); > + shash_init(&sbrec_mac_ip_lp_binding->mac_ip_lp); > + sbrec_mac_ip_lp_binding->lp = mb->logical_port; > + shash_add(&sbrec_mac_ip_lp_binding->mac_ip_lp, mac_ip_lp_key, > mb); > + shash_add(&sbrec_lp_mac_binding, mb->logical_port, > + sbrec_mac_ip_lp_binding); > + } else { > + shash_add(&miplpb->mac_ip_lp, mac_ip_lp_key, mb); > + } > + free(mac_ip_lp_key); > + } > + > ovsdb_idl_txn_add_comment(ctx->vtep_idl_txn, > "ovn-controller-vtep: update logical switch > " > "tunnel keys and 'ucast_macs_remote's"); > @@ -612,7 +888,10 @@ vtep_run(struct controller_vtep_ctx *ctx) > vtep_lswitch_run(&vtep_pbs, &vtep_pswitches, &vtep_lswitches); > vtep_macs_run(ctx->vtep_idl_txn, &ucast_macs_rmts, > &mcast_macs_rmts, &physical_locators, > - &vtep_lswitches, &non_vtep_pbs); > + &vtep_lswitches, &non_vtep_pbs, &vtep_pbs, > + &sbrec_lp_mac_binding, &vtep_pswitches); > + vtep_local_macs(ctx, &vtep_pbs, &vtep_pswitches, &vtep_lswitches, > + &sbrec_lp_mac_binding); > > sset_destroy(&vtep_pswitches); > shash_destroy(&vtep_lswitches); > @@ -628,6 +907,14 @@ vtep_run(struct controller_vtep_ctx *ctx) > shash_destroy(&physical_locators); > shash_destroy(&vtep_pbs); > shash_destroy(&non_vtep_pbs); > + > + struct shash_node *lp_mb_node; > + SHASH_FOR_EACH (lp_mb_node, &sbrec_lp_mac_binding) { > + struct lp_mac_ip_binding *miplpb = lp_mb_node->data; > + shash_destroy(&miplpb->mac_ip_lp); > + free(miplpb); > + } > + shash_destroy(&sbrec_lp_mac_binding); > } > > /* Cleans up all related entries in vtep. Returns true when done (i.e. > there > diff --git a/tests/ovn-controller-vtep.at b/tests/ovn-controller-vtep.at > index d410ecd28..a0a4b89ff 100644 > --- a/tests/ovn-controller-vtep.at > +++ b/tests/ovn-controller-vtep.at > @@ -1,9 +1,10 @@ > AT_BANNER([ovn_controller_vtep]) > > -# OVN_CONTROLLER_VTEP_START(SIM_NAME) > +# OVN_CONTROLLER_VTEP_START(SIM_NAME, TUNNEL_IP) > # > # $1 - optional simulator name. If none is given, runs > ovn-controller-vtep, and > # vtep emulator in $ovs_dir. > +# $2 - optional tunnel ip. If none is given default 1.2.3.4 is used > # Starts the test with a setup with vtep device. Each test case must > first > # call this macro and ovn_start. > # > @@ -14,7 +15,9 @@ m4_define([OVN_CONTROLLER_VTEP_START], [ > AT_KEYWORDS([ovn]) > # this will cause skip when 'make check' using Windows setup. > sim="$1" > + tunnel_ip="$2" > vtep_chassis=${sim:-br-vtep} > + tunnel_ip=${tunnel_ip:-1.2.3.4} > > test -n "$sim" && as "$sim" > mkdir -p "$ovs_dir" || return 1 > @@ -41,7 +44,7 @@ m4_define([OVN_CONTROLLER_VTEP_START], [ > -- add-port $vtep_chassis p1 -- set Interface p1 type=dummy > ofport_request=2 > > dnl Start ovs-vtep. > - check vtep-ctl add-ps $vtep_chassis -- set Physical_Switch > $vtep_chassis tunnel_ips=1.2.3.4 > + check vtep-ctl add-ps $vtep_chassis -- set Physical_Switch > $vtep_chassis tunnel_ips=$tunnel_ip > AT_CHECK([ovs-vtep --log-file="$ovs_dir"/ovs-vtep.log \ > --pidfile="$ovs_dir"/ovs-vtep.pid \ > --detach --no-chdir $vtep_chassis], [0], [], > [stderr]) > @@ -86,6 +89,9 @@ AT_CHECK([ovn-nbctl lsp-set-type $2 vtep]) > AT_CHECK([ovn-nbctl lsp-set-options $2 vtep-physical-switch=$3 > vtep-logical-switch=$4]) > ]) > > +# mac learning table is hardcoded in ovs-vtep emulator > +m4_define([mac_learning_table], [1]) > + > ############################################## > > # tests chassis related updates. > @@ -509,6 +515,120 @@ AT_CHECK([vtep-ctl --columns=MAC list > Ucast_Macs_Remote | cut -d ':' -f2- | tr - > OVN_CONTROLLER_VTEP_STOP([/has already been known to be on logical > port/d]) > AT_CLEANUP > > +# Tests vtep module 'Ucast_Macs_Local' MACs propagation > +AT_SETUP([ovn-controller-vtep - vtep-macs 3]) > +ovn_start > +OVN_CONTROLLER_VTEP_START > + > +check ovn-nbctl ls-add br-test > +check ovn-nbctl ls-add br-test1 > + > +# creates a simple logical network with the vtep device and a fake hv > chassis > +# 'ch0'. > +AT_CHECK([ovn-nbctl --wait=sb sync]) > + > +# 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`"]) > +OVS_WAIT_UNTIL([test -n "`ovs-vsctl show | grep br-vtep_vtep_ls1`"]) > + > +# Simulate peer on physical port to populate Ucast_Macs_Local table > +AT_CHECK([ovs-ofctl -O OpenFlow14 add-flow br-vtep_vtep_ls1 > "cookie=0x5000,table=mac_learning_table,priority=1000,dl_dst=aa:bb:cc:dd:ee:01 > actions=output:0100-p0-l"]) > + > +# Wait Ucast_Macs_Local is updated with local MAC > +OVS_WAIT_UNTIL([test -n "`vtep-ctl list Ucast_Macs_Local | grep > aa:bb:cc:dd:ee:01`"]) > + > +# Check that OVNSB is updated with learned MAC > +OVS_WAIT_UNTIL([test -n "`ovn-sbctl find Mac_Binding > mac='"aa:bb:cc:dd:ee:01"' |grep _uuid`"]) > + > +# Plug p1 to lswitch1 > +AT_CHECK([vtep-ctl add-ls lswitch1 -- bind-ls br-vtep p1 100 lswitch1]) > +OVN_NB_ADD_VTEP_PORT([br-test1], [br-vtep_lswitch1], [br-vtep], > [lswitch1]) > +OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep > br-vtep_lswitch1`"]) > +OVS_WAIT_UNTIL([test -n "`ovs-vsctl show | grep br-vtep_vtep_ls2`"]) > + > +OVS_WAIT_UNTIL([test -n "`ovs-vsctl show |grep 0100-p1-l`"]) > + > +# Simulate peer on physical port to populate Ucast_Macs_Local table > +AT_CHECK([ovs-ofctl -O OpenFlow14 add-flow br-vtep_vtep_ls2 > "cookie=0x5000,table=mac_learning_table,priority=1000,dl_dst=aa:bb:cc:dd:ee:02 > actions=output:0100-p1-l"]) > + > +# Wait Ucast_Macs_Local is updated with local MAC > +OVS_WAIT_UNTIL([test -n "`vtep-ctl list Ucast_Macs_Local | grep > aa:bb:cc:dd:ee:02`"]) > + > +# Remove MAC from Ucast_Macs_Local > +AT_CHECK([ovs-ofctl -O OpenFlow14 del-flows br-vtep_vtep_ls1 > "table=mac_learning_table,dl_dst=aa:bb:cc:dd:ee:01"]) > + > +# Check that first MAC is removed from OVNSB, but second is still there > +OVS_WAIT_UNTIL([test -z "`ovn-sbctl find Mac_Binding > mac='"aa:bb:cc:dd:ee:01"'`"]) > +OVS_WAIT_UNTIL([test -n "`ovn-sbctl find Mac_Binding > mac='"aa:bb:cc:dd:ee:02"'`"]) > + > +# Remove second MAC from Ucast_Macs_Local > +AT_CHECK([ovs-ofctl -O OpenFlow14 del-flows br-vtep_vtep_ls2 > "table=mac_learning_table,dl_dst=aa:bb:cc:dd:ee:02"]) > + > +# Check that second MAC is removed from OVNSB > +OVS_WAIT_UNTIL([test -z "`ovn-sbctl find Mac_Binding > mac='"aa:bb:cc:dd:ee:01"'`"]) > +OVS_WAIT_UNTIL([test -z "`ovn-sbctl find Mac_Binding > mac='"aa:bb:cc:dd:ee:02"'`"]) > + > +# Start second VTEP chassis > +OVN_CONTROLLER_VTEP_START(br-vtep1, 1.2.3.5) > + > +# 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-vtep1 p0 100 lswitch0]) > +OVN_NB_ADD_VTEP_PORT([br-test], [br-vtep1_lswitch0], [br-vtep1], > [lswitch0]) > +OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep > br-vtep1_lswitch0`"]) > +OVS_WAIT_UNTIL([test -n "`ovs-vsctl show | grep br-vtep1_vtep_ls1`"]) > + > +# creates the logical switch in vtep and adds the corresponding logical > +# # # port to 'br-test'. > +AT_CHECK([vtep-ctl add-ls lswitch1 -- bind-ls br-vtep1 p1 100 lswitch1]) > +OVN_NB_ADD_VTEP_PORT([br-test1], [br-vtep1_lswitch1], [br-vtep1], > [lswitch1]) > +OVS_WAIT_UNTIL([test -n "`ovn-sbctl list Port_Binding | grep > br-vtep1_lswitch1`"]) > +OVS_WAIT_UNTIL([test -n "`ovs-vsctl show | grep br-vtep1_vtep_ls2`"]) > + > +#sleep 3000 > + > +# Wait bingins are activated > +OVS_WAIT_UNTIL([test -n "`ovs-vsctl show |grep 0100-p0-l`"]) > +OVS_WAIT_UNTIL([test -n "`ovs-vsctl show |grep 0100-p1-l`"]) > + > +# Simulate peer on physical port to populate Ucast_Macs_Local table on > br-vtep1 > +AT_CHECK([ovs-ofctl -O OpenFlow14 add-flow br-vtep1_vtep_ls1 > "cookie=0x5000,table=mac_learning_table,priority=1000,dl_dst=aa:bb:cc:dd:ff:01 > actions=output:0100-p0-l"]) > +AT_CHECK([ovs-ofctl -O OpenFlow14 add-flow br-vtep1_vtep_ls2 > "cookie=0x5000,table=mac_learning_table,priority=1000,dl_dst=aa:bb:cc:dd:ff:02 > actions=output:0100-p1-l"]) > + > +# Wait Ucast_Macs_Local is updated with local MAC > +OVS_WAIT_UNTIL([test -n "`vtep-ctl list Ucast_Macs_Local | grep > aa:bb:cc:dd:ff:01`"]) > +OVS_WAIT_UNTIL([test -n "`vtep-ctl list Ucast_Macs_Local | grep > aa:bb:cc:dd:ff:02`"]) > + > +# Switch context > +as > + > +# Make sure we see > +OVS_WAIT_UNTIL([test -n "`vtep-ctl list-remote-macs lswitch0 | grep > aa:bb:cc:dd:ff:01`"]) > +OVS_WAIT_UNTIL([test -z "`vtep-ctl list-remote-macs lswitch1 | grep > aa:bb:cc:dd:ff:01`"]) > + > +OVS_WAIT_UNTIL([test -n "`vtep-ctl list-remote-macs lswitch1 | grep > aa:bb:cc:dd:ff:02`"]) > +OVS_WAIT_UNTIL([test -z "`vtep-ctl list-remote-macs lswitch0 | grep > aa:bb:cc:dd:ff:02`"]) > + > +# Switch context to br-vtep1 > +as br-vtep1 > + > +# Remove local MACs > +AT_CHECK([ovs-ofctl -O OpenFlow14 del-flows br-vtep1_vtep_ls1 > "table=mac_learning_table,dl_dst=aa:bb:cc:dd:ff:01"]) > +AT_CHECK([ovs-ofctl -O OpenFlow14 del-flows br-vtep1_vtep_ls2 > "table=mac_learning_table,dl_dst=aa:bb:cc:dd:ff:02"]) > + > +# Switch context > +as > + > +# Ensure remote MACs gone > +OVS_WAIT_UNTIL([test -z "`vtep-ctl list-remote-macs lswitch0 | grep > aa:bb:cc:dd:ff:01`"]) > +OVS_WAIT_UNTIL([test -z "`vtep-ctl list-remote-macs lswitch1 | grep > aa:bb:cc:dd:ff:02`"]) > + > +OVN_CONTROLLER_VTEP_STOP > +AT_CLEANUP > + > # Tests vtep module 'Mcast_Macs_Remote's. > AT_SETUP([ovn-controller-vtep - vtep-Mcast_Macs_Remote]) > ovn_start > -- > 2.43.0 > > -- <https://www.mirantis.com/> Vasyl Saienko Principal DevOps Engineer vsaie...@mirantis.com <dstoltenb...@mirantis.com> +(380) 66 072 07 17 <++1+(650)+564+7038> _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev