On 11/4/24 10:44, Ales Musil wrote: > On Fri, Nov 1, 2024 at 2:29 PM Dumitru Ceara <dce...@redhat.com> wrote: > >> SB.MAC_Binding doesn't store a strong reference to SB.Port_Binding. >> Instead it stores the port binding 'logical_port' name. As the >> mac-binding cache in ovn-controller stored entries indexed by >> [datapath-key, port-key, ip] it meant that when processing >> SB.MAC_Binding changes (including deletion) it had to first lookup the >> corresponding SB.Port_Binding. >> >> If the logical port associated with the MAC binding is deleted in the >> same transaction then looking it up in the IDL index fails (deleted IDL >> records are not indexed). This leads to stale entries staying in the >> mac cache and in consequence to potential use after free (of the SB >> MAC_Binding record) or to crashes if the statctrl module tries to update >> timestamps of MAC_Bindings that happened to have been removed in the >> current iteration (but still linger in the cache). >> >> In practice we don't need the port-key we can simply use the port >> binding UUID as unique index. However, the same struct mac_binding type >> is used by pinctrl to temporarily efficiently store buffered packets for >> yet to be resolved MAC bindings. In those cases there's no SB >> MAC_Binding record yet so the logical ingress port tunnel_key is used as >> index. >> >> The two ways of using the MAC binding maps are orthogonal, that is, we >> will never use a single map to store both types of bindings. >> >> In order to avoid issues we now include the SB MAC_Binding UUID into the >> key of the struct mac_binding_data. >> >> Reported-at: https://issues.redhat.com/browse/FDP-906 >> Fixes: b57f60a617b4 ("controller: Add MAC cache I-P node") >> Signed-off-by: Dumitru Ceara <dce...@redhat.com> >> --- >> > > Hi Dumitru, >
Hi Ales, > thank you for the fix. There is just one small typo down below. > We should probably think about a way of decoupling pinctrl and > ovn-controller mac-cache in the future as it unfortunately doesn't > work well together. > I agree, it would be nice to follow up and split the two mac-caches. > controller/mac-cache.c | 77 ++++++++++++++++++------- >> controller/mac-cache.h | 30 +++++++--- >> controller/ovn-controller.c | 67 ++++++++++------------ >> controller/pinctrl.c | 24 +++++--- >> tests/ovn.at | 110 ++++++++++++++++++++++++++++++++++++ >> 5 files changed, 236 insertions(+), 72 deletions(-) >> >> diff --git a/controller/mac-cache.c b/controller/mac-cache.c >> index de45d7a6a5..d6ba9e20ee 100644 >> --- a/controller/mac-cache.c >> +++ b/controller/mac-cache.c >> @@ -142,21 +142,18 @@ mac_cache_thresholds_clear(struct mac_cache_data >> *data) >> } >> >> /* MAC binding. */ >> -struct mac_binding * >> +void >> mac_binding_add(struct hmap *map, struct mac_binding_data mb_data, >> long long timestamp) { >> >> struct mac_binding *mb = mac_binding_find(map, &mb_data); >> if (!mb) { >> mb = xmalloc(sizeof *mb); >> - mb->sbrec_mb = NULL; >> hmap_insert(map, &mb->hmap_node, mac_binding_data_hash(&mb_data)); >> } >> >> mb->data = mb_data; >> mb->timestamp = timestamp; >> - >> - return mb; >> } >> >> void >> @@ -181,24 +178,37 @@ mac_binding_find(const struct hmap *map, >> } >> >> bool >> -mac_binding_data_from_sbrec(struct mac_binding_data *data, >> - const struct sbrec_mac_binding *mb, >> - struct ovsdb_idl_index *sbrec_pb_by_name) >> +mac_binding_data_parse(struct mac_binding_data *data, >> + uint32_t dp_key, uint32_t port_key, >> + const char *ip_str, const char *mac_str) >> { >> - const struct sbrec_port_binding *pb = >> - lport_lookup_by_name(sbrec_pb_by_name, mb->logical_port); >> + struct eth_addr mac; >> + struct in6_addr ip; >> >> - if (!pb || !pb->datapath || !ip46_parse(mb->ip, &data->ip) || >> - !eth_addr_from_string(mb->mac, &data->mac)) { >> + if (!ip46_parse(ip_str, &ip) || !eth_addr_from_string(mac_str, &mac)) >> { >> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); >> - VLOG_WARN_RL(&rl, "Couldn't parse MAC binding: ip=%s, mac=%s, " >> - "logical_port=%s", mb->ip, mb->mac, >> mb->logical_port); >> + VLOG_WARN_RL(&rl, "Couldn't parse MAC binding: ip=%s, mac=%s", >> + ip_str, mac_str); >> return false; >> } >> >> - data->dp_key = mb->datapath->tunnel_key; >> - data->port_key = pb->tunnel_key; >> + mac_binding_data_init(data, dp_key, port_key, ip, mac); >> + return true; >> +} >> + >> +bool >> +mac_binding_data_from_sbrec(struct mac_binding_data *data, >> + const struct sbrec_mac_binding *mb) >> +{ >> + /* This explicitly sets the port_key to 0 as port_binding tunnel_keys >> + * can change. Instead use add the SB.MAC_Binding UUID as key; this >> + * makes the mac_binding_data key unique. */ >> + if (!mac_binding_data_parse(data, mb->datapath->tunnel_key, 0, >> + mb->ip, mb->mac)) { >> + return false; >> + } >> >> + data->sbrec = mb; >> return true; >> } >> >> @@ -211,6 +221,30 @@ mac_bindings_clear(struct hmap *map) >> } >> } >> >> +void >> +mac_bindings_to_string(const struct hmap *map, struct ds *out_data) >> +{ >> + struct mac_binding *mb; >> + HMAP_FOR_EACH (mb, hmap_node, map) { >> + char ip[INET6_ADDRSTRLEN]; >> + >> + if (!ipv6_string_mapped(ip, &mb->data.ip)) { >> + continue; >> + } >> + if (mb->data.sbrec) { >> + ds_put_format(out_data, "SB UUID: " UUID_FMT ", ", >> + UUID_ARGS(&mb->data.sbrec->header_.uuid)); >> + } else { >> + ds_put_cstr(out_data, "SB UUID: <none>, "); >> + } >> + ds_put_format(out_data, "datapath-key: %"PRIu32", " >> + "port-key: %"PRIu32", " >> + "ip: %s, mac: " ETH_ADDR_FMT "\n", >> + mb->data.dp_key, mb->data.port_key, >> + ip, ETH_ADDR_ARGS(mb->data.mac)); >> + } >> +} >> + >> bool >> sb_mac_binding_updated(const struct sbrec_mac_binding *mb) >> { >> @@ -382,9 +416,9 @@ mac_binding_stats_run(struct ovs_list *stats_list, >> uint64_t *req_delay, >> * used on this chassis. Also make sure that we don't update the >> * timestamp more than once during the dump period. */ >> if (stats->idle_age_ms < threshold->value && >> - (timewall_now - mb->sbrec_mb->timestamp) >= >> + (timewall_now - mb->data.sbrec->timestamp) >= >> threshold->dump_period) { >> - sbrec_mac_binding_set_timestamp(mb->sbrec_mb, timewall_now); >> + sbrec_mac_binding_set_timestamp(mb->data.sbrec, timewall_now); >> } >> >> free(stats); >> @@ -608,7 +642,9 @@ mac_cache_stats_destroy(struct ovs_list *stats_list) >> static uint32_t >> mac_binding_data_hash(const struct mac_binding_data *mb_data) >> { >> - uint32_t hash = 0; >> + uint32_t hash = mb_data->sbrec >> + ? uuid_hash(&mb_data->sbrec->header_.uuid) >> + : 0; >> >> hash = hash_add(hash, mb_data->port_key); >> hash = hash_add(hash, mb_data->dp_key); >> @@ -621,9 +657,10 @@ static inline bool >> mac_binding_data_equals(const struct mac_binding_data *a, >> const struct mac_binding_data *b) >> { >> - return a->port_key == b->port_key && >> + return a->sbrec == b->sbrec && >> + a->port_key == b->port_key && >> a->dp_key == b->dp_key && >> - ipv6_addr_equals(&a->ip, &b->ip); >> + ipv6_addr_equals(&a->ip, &b->ip); >> } >> >> static uint32_t >> diff --git a/controller/mac-cache.h b/controller/mac-cache.h >> index b94e7a1cf2..df84ef072c 100644 >> --- a/controller/mac-cache.h >> +++ b/controller/mac-cache.h >> @@ -52,6 +52,7 @@ struct mac_cache_threshold { >> >> struct mac_binding_data { >> /* Keys. */ >> + const struct sbrec_mac_binding * sbrec; /* Only the UUID is used as >> key.*/ >> > > nit: Space after *. > Ah, true, I fixed it before applying the patch. > >> uint32_t port_key; >> uint32_t dp_key; >> struct in6_addr ip; >> @@ -63,8 +64,6 @@ struct mac_binding { >> struct hmap_node hmap_node; >> /* Common data to identify MAC binding. */ >> struct mac_binding_data data; >> - /* Reference to the SB MAC binding record (Might be NULL). */ >> - const struct sbrec_mac_binding *sbrec_mb; >> /* User specified timestamp (in ms) */ >> long long timestamp; >> }; >> @@ -128,20 +127,37 @@ void mac_cache_thresholds_sync(struct mac_cache_data >> *data, >> void mac_cache_thresholds_clear(struct mac_cache_data *data); >> >> /* MAC binding. */ >> -struct mac_binding *mac_binding_add(struct hmap *map, >> - struct mac_binding_data mb_data, >> - long long timestamp); >> + >> +static inline void >> +mac_binding_data_init(struct mac_binding_data *data, >> + uint32_t dp_key, uint32_t port_key, >> + struct in6_addr ip, struct eth_addr mac) >> +{ >> + *data = (struct mac_binding_data) { >> + .sbrec = NULL, >> + .dp_key = (dp_key), >> + .port_key = (port_key), >> + .ip = (ip), >> + .mac = (mac), >> + }; >> +} >> + >> +void mac_binding_add(struct hmap *map, struct mac_binding_data mb_data, >> + long long timestamp); >> >> void mac_binding_remove(struct hmap *map, struct mac_binding *mb); >> >> struct mac_binding *mac_binding_find(const struct hmap *map, >> const struct mac_binding_data >> *mb_data); >> >> +bool mac_binding_data_parse(struct mac_binding_data *data, >> + uint32_t dp_key, uint32_t port_key, >> + const char *ip_str, const char *mac_str); >> bool mac_binding_data_from_sbrec(struct mac_binding_data *data, >> - const struct sbrec_mac_binding *mb, >> - struct ovsdb_idl_index >> *sbrec_pb_by_name); >> + const struct sbrec_mac_binding *mb); >> >> void mac_bindings_clear(struct hmap *map); >> +void mac_bindings_to_string(const struct hmap *map, struct ds *out_data); >> >> bool sb_mac_binding_updated(const struct sbrec_mac_binding *mb); >> >> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c >> index e87274121c..ab95938502 100644 >> --- a/controller/ovn-controller.c >> +++ b/controller/ovn-controller.c >> @@ -101,6 +101,7 @@ static unixctl_cb_func debug_status_execution; >> static unixctl_cb_func debug_dump_local_bindings; >> static unixctl_cb_func debug_dump_related_lports; >> static unixctl_cb_func debug_dump_local_template_vars; >> +static unixctl_cb_func debug_dump_local_mac_bindings; >> static unixctl_cb_func debug_dump_lflow_conj_ids; >> static unixctl_cb_func lflow_cache_flush_cmd; >> static unixctl_cb_func lflow_cache_show_stats_cmd; >> @@ -2932,26 +2933,22 @@ en_lb_data_cleanup(void *data) >> >> static void >> mac_binding_add_sb(struct mac_cache_data *data, >> - const struct sbrec_mac_binding *smb, >> - struct ovsdb_idl_index *sbrec_pb_by_name) >> + const struct sbrec_mac_binding *smb) >> { >> struct mac_binding_data mb_data; >> - if (!mac_binding_data_from_sbrec(&mb_data, smb, sbrec_pb_by_name)) { >> + if (!mac_binding_data_from_sbrec(&mb_data, smb)) { >> return; >> } >> >> - struct mac_binding *mb = mac_binding_add(&data->mac_bindings, >> mb_data, 0); >> - >> - mb->sbrec_mb = smb; >> + mac_binding_add(&data->mac_bindings, mb_data, 0); >> } >> >> static void >> mac_binding_remove_sb(struct mac_cache_data *data, >> - const struct sbrec_mac_binding *smb, >> - struct ovsdb_idl_index *sbrec_pb_by_name) >> + const struct sbrec_mac_binding *smb) >> { >> struct mac_binding_data mb_data; >> - if (!mac_binding_data_from_sbrec(&mb_data, smb, sbrec_pb_by_name)) { >> + if (!mac_binding_data_from_sbrec(&mb_data, smb)) { >> return; >> } >> >> @@ -2995,8 +2992,7 @@ fdb_remove_sb(struct mac_cache_data *data, const >> struct sbrec_fdb *sfdb) >> static void >> mac_cache_mb_handle_for_datapath(struct mac_cache_data *data, >> const struct sbrec_datapath_binding *dp, >> - struct ovsdb_idl_index *sbrec_mb_by_dp, >> - struct ovsdb_idl_index *sbrec_pb_by_name) >> + struct ovsdb_idl_index *sbrec_mb_by_dp) >> { >> bool has_threshold = mac_cache_threshold_find(data, dp->tunnel_key); >> >> @@ -3007,9 +3003,9 @@ mac_cache_mb_handle_for_datapath(struct >> mac_cache_data *data, >> const struct sbrec_mac_binding *mb; >> SBREC_MAC_BINDING_FOR_EACH_EQUAL (mb, mb_index_row, sbrec_mb_by_dp) { >> if (has_threshold) { >> - mac_binding_add_sb(data, mb, sbrec_pb_by_name); >> + mac_binding_add_sb(data, mb); >> } else { >> - mac_binding_remove_sb(data, mb, sbrec_pb_by_name); >> + mac_binding_remove_sb(data, mb); >> } >> } >> >> @@ -3064,10 +3060,6 @@ en_mac_cache_run(struct engine_node *node, void >> *data) >> engine_ovsdb_node_get_index( >> engine_get_input("SB_mac_binding", node), >> "datapath"); >> - struct ovsdb_idl_index *sbrec_pb_by_name = >> - engine_ovsdb_node_get_index( >> - engine_get_input("SB_port_binding", node), >> - "name"); >> struct ovsdb_idl_index *sbrec_fdb_by_dp_key = >> engine_ovsdb_node_get_index( >> engine_get_input("SB_fdb", node), >> @@ -3086,7 +3078,7 @@ en_mac_cache_run(struct engine_node *node, void >> *data) >> >> mac_cache_threshold_add(cache_data, sbrec_dp); >> mac_cache_mb_handle_for_datapath(cache_data, sbrec_dp, >> - sbrec_mb_by_dp, >> sbrec_pb_by_name); >> + sbrec_mb_by_dp); >> mac_cache_fdb_handle_for_datapath(cache_data, sbrec_dp, >> sbrec_fdb_by_dp_key); >> } >> @@ -3102,11 +3094,6 @@ mac_cache_sb_mac_binding_handler(struct engine_node >> *node, void *data) >> engine_get_input_data("runtime_data", node); >> const struct sbrec_mac_binding_table *mb_table = >> EN_OVSDB_GET(engine_get_input("SB_mac_binding", node)); >> - struct ovsdb_idl_index *sbrec_pb_by_name = >> - engine_ovsdb_node_get_index( >> - engine_get_input("SB_port_binding", node), >> - "name"); >> - >> size_t previous_size = hmap_count(&cache_data->mac_bindings); >> >> const struct sbrec_mac_binding *sbrec_mb; >> @@ -3116,8 +3103,7 @@ mac_cache_sb_mac_binding_handler(struct engine_node >> *node, void *data) >> } >> >> if (!sbrec_mac_binding_is_new(sbrec_mb)) { >> - mac_binding_remove_sb(cache_data, sbrec_mb, >> - sbrec_pb_by_name); >> + mac_binding_remove_sb(cache_data, sbrec_mb); >> } >> >> if (sbrec_mac_binding_is_deleted(sbrec_mb) || >> @@ -3128,7 +3114,7 @@ mac_cache_sb_mac_binding_handler(struct engine_node >> *node, void *data) >> >> if (mac_cache_threshold_find(cache_data, >> sbrec_mb->datapath->tunnel_key)) { >> - mac_binding_add_sb(cache_data, sbrec_mb, sbrec_pb_by_name); >> + mac_binding_add_sb(cache_data, sbrec_mb); >> } >> } >> >> @@ -3189,10 +3175,6 @@ mac_cache_runtime_data_handler(struct engine_node >> *node, void *data OVS_UNUSED) >> engine_ovsdb_node_get_index( >> engine_get_input("SB_mac_binding", node), >> "datapath"); >> - struct ovsdb_idl_index *sbrec_pb_by_name = >> - engine_ovsdb_node_get_index( >> - engine_get_input("SB_port_binding", node), >> - "name"); >> struct ovsdb_idl_index *sbrec_fdb_by_dp_key = >> engine_ovsdb_node_get_index( >> engine_get_input("SB_fdb", node), >> @@ -3217,7 +3199,7 @@ mac_cache_runtime_data_handler(struct engine_node >> *node, void *data OVS_UNUSED) >> >> HMAP_FOR_EACH (tdp, node, &rt_data->tracked_dp_bindings) { >> mac_cache_mb_handle_for_datapath(cache_data, tdp->dp, >> - sbrec_mb_by_dp, >> sbrec_pb_by_name); >> + sbrec_mb_by_dp); >> >> mac_cache_fdb_handle_for_datapath(cache_data, tdp->dp, >> sbrec_fdb_by_dp_key); >> @@ -3243,10 +3225,6 @@ mac_cache_sb_datapath_binding_handler(struct >> engine_node *node, void *data) >> engine_ovsdb_node_get_index( >> engine_get_input("SB_mac_binding", node), >> "datapath"); >> - struct ovsdb_idl_index *sbrec_pb_by_name = >> - engine_ovsdb_node_get_index( >> - engine_get_input("SB_port_binding", node), >> - "name"); >> struct ovsdb_idl_index *sbrec_fdb_by_dp_key = >> engine_ovsdb_node_get_index( >> engine_get_input("SB_fdb", node), >> @@ -3274,7 +3252,7 @@ mac_cache_sb_datapath_binding_handler(struct >> engine_node *node, void *data) >> >> SBREC_DATAPATH_BINDING_TABLE_FOR_EACH_TRACKED (sbrec_dp, dp_table) { >> mac_cache_mb_handle_for_datapath(cache_data, sbrec_dp, >> - sbrec_mb_by_dp, >> sbrec_pb_by_name); >> + sbrec_mb_by_dp); >> >> mac_cache_fdb_handle_for_datapath(cache_data, sbrec_dp, >> sbrec_fdb_by_dp_key); >> @@ -5399,6 +5377,10 @@ main(int argc, char *argv[]) >> debug_dump_local_template_vars, >> &template_vars_data->local_templates); >> >> + unixctl_command_register("debug/dump-mac-bindings", "", 0, 0, >> + debug_dump_local_mac_bindings, >> + &mac_cache_data->mac_bindings); >> + >> unixctl_command_register("debug/ignore-startup-delay", "", 0, 0, >> debug_ignore_startup_delay, NULL); >> >> @@ -6356,6 +6338,19 @@ debug_dump_local_template_vars(struct unixctl_conn >> *conn, int argc OVS_UNUSED, >> ds_destroy(&tv_str); >> } >> >> +static void >> +debug_dump_local_mac_bindings(struct unixctl_conn *conn, int argc >> OVS_UNUSED, >> + const char *argv[] OVS_UNUSED, >> + void *mac_bindings) >> +{ >> + struct ds mb_str = DS_EMPTY_INITIALIZER; >> + >> + ds_put_cstr(&mb_str, "Local MAC bindings:\n"); >> + mac_bindings_to_string(mac_bindings, &mb_str); >> + unixctl_command_reply(conn, ds_cstr(&mb_str)); >> + ds_destroy(&mb_str); >> +} >> + >> static void >> debug_ignore_startup_delay(struct unixctl_conn *conn, int argc OVS_UNUSED, >> const char *argv[] OVS_UNUSED, void *arg >> OVS_UNUSED) >> diff --git a/controller/pinctrl.c b/controller/pinctrl.c >> index dfb3130aa2..ca880a1da6 100644 >> --- a/controller/pinctrl.c >> +++ b/controller/pinctrl.c >> @@ -1539,19 +1539,20 @@ pinctrl_handle_buffered_packets(const struct >> ofputil_packet_in *pin, >> OVS_REQUIRES(pinctrl_mutex) >> { >> const struct match *md = &pin->flow_metadata; >> - struct mac_binding_data mb_data = (struct mac_binding_data) { >> - .dp_key = ntohll(md->flow.metadata), >> - .port_key = md->flow.regs[MFF_LOG_OUTPORT - MFF_REG0], >> - .mac = eth_addr_zero, >> - }; >> + struct mac_binding_data mb_data; >> + struct in6_addr ip; >> >> if (is_arp) { >> - mb_data.ip = in6_addr_mapped_ipv4(htonl(md->flow.regs[0])); >> + ip = in6_addr_mapped_ipv4(htonl(md->flow.regs[0])); >> } else { >> ovs_be128 ip6 = hton128(flow_get_xxreg(&md->flow, 0)); >> - memcpy(&mb_data.ip, &ip6, sizeof mb_data.ip); >> + memcpy(&ip, &ip6, sizeof ip); >> } >> >> + mac_binding_data_init(&mb_data, ntohll(md->flow.metadata), >> + md->flow.regs[MFF_LOG_OUTPORT - MFF_REG0], >> + ip, eth_addr_zero); >> + >> struct buffered_packets *bp = >> buffered_packets_add(&buffered_packets_ctx, >> mb_data); >> if (!bp) { >> @@ -4959,9 +4960,14 @@ run_buffered_binding(const struct >> sbrec_mac_binding_table *mac_binding_table, >> const struct sbrec_port_binding *pb = lport_lookup_by_name( >> sbrec_port_binding_by_name, smb->logical_port); >> >> + if (!pb || !pb->datapath) { >> + continue; >> + } >> + >> struct mac_binding_data mb_data; >> - if (!mac_binding_data_from_sbrec(&mb_data, smb, >> - sbrec_port_binding_by_name)) { >> + >> + if (!mac_binding_data_parse(&mb_data, smb->datapath->tunnel_key, >> + pb->tunnel_key, smb->ip, smb->mac)) { >> continue; >> } >> >> diff --git a/tests/ovn.at b/tests/ovn.at >> index 10cd7a79b9..44d58ca160 100644 >> --- a/tests/ovn.at >> +++ b/tests/ovn.at >> @@ -35168,6 +35168,116 @@ OVN_CLEANUP([hv1], [hv2]) >> AT_CLEANUP >> ]) >> >> +OVN_FOR_EACH_NORTHD([ >> +AT_SETUP([MAC binding aging - port deletion]) >> +AT_SKIP_IF([test $HAVE_SCAPY = no]) >> +ovn_start >> + >> +net_add n1 >> +sim_add hv1 >> +as hv1 >> +check ovs-vsctl add-br br-phys >> +ovn_attach n1 br-phys 192.168.0.1 >> + >> +check ovn-nbctl \ >> + -- ls-add ls1 \ >> + -- ls-add ls2 \ >> + -- lr-add lr \ >> + -- set logical_router lr options:mac_binding_age_threshold=3600 \ >> + -- lrp-add lr lr-ls1 00:00:00:00:10:00 192.168.10.1/24 \ >> + -- lrp-add lr lr-ls2 00:00:00:00:20:00 192.168.20.1/24 \ >> + -- lsp-add ls1 ls1-lr \ >> + -- lsp-set-type ls1-lr router \ >> + -- lsp-set-addresses ls1-lr router \ >> + -- lsp-set-options ls1-lr router-port=lr-ls1 \ >> + -- lsp-add ls1 vif1 \ >> + -- lsp-set-addresses vif1 "00:00:00:00:10:10 192.168.10.10" \ >> + -- lsp-add ls2 ls2-lr \ >> + -- lsp-set-type ls2-lr router \ >> + -- lsp-set-addresses ls2-lr router \ >> + -- lsp-set-options ls2-lr router-port=lr-ls2 \ >> + -- lsp-add ls2 vif2 \ >> + -- lsp-set-addresses vif2 "00:00:00:00:20:10 192.168.20.10" >> + >> +check ovs-vsctl \ >> + -- add-port br-int vif1 \ >> + -- set interface vif1 external-ids:iface-id=vif1 \ >> + -- add-port br-int vif2 \ >> + -- set interface vif2 external-ids:iface-id=vif2 >> + >> +OVN_POPULATE_ARP >> +wait_for_ports_up >> +check ovn-nbctl --wait=hv sync >> + >> +dnl Wait for pinctrl thread to be connected. >> +OVS_WAIT_UNTIL([grep pinctrl hv1/ovn-controller.log | grep -q connected]) >> + >> +send_garp() { >> + hv=$1 >> + dev=$2 >> + mac=$3 >> + ip=$4 >> + >> + packet=$(fmt_pkt "Ether(dst='ff:ff:ff:ff:ff:ff', src='${mac}')/ \ >> + ARP(op=2, hwsrc='${mac}', hwdst='${mac}', \ >> + psrc='${ip}', pdst='${ip}')") >> + as $hv ovs-appctl netdev-dummy/receive $dev $packet >> +} >> + >> +AS_BOX([Remove LRP with learnt MAC_Binding]) >> +dnl Populate MAC Binding entry. >> +send_garp hv1 vif1 00:00:00:00:10:10 192.168.10.10 >> +wait_row_count mac_binding 1 ip="192.168.10.10" logical_port="lr-ls1" >> + >> +dnl Check local mac binding cache. >> +lr_key=$(fetch_column datapath_binding tunnel_key external_ids:name=lr) >> +mb_uuid=$(fetch_column mac_binding _uuid logical_port=lr-ls1) >> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([as hv1 ovn-appctl -t ovn-controller >> debug/dump-mac-bindings], [0], [dnl >> +Local MAC bindings: >> +SB UUID: $mb_uuid, datapath-key: $lr_key, port-key: 0, ip: 192.168.10.10, >> mac: 00:00:00:00:10:10 >> +]) >> + >> +dnl Remove router port. This deletes the mac binding in the same >> transaction. >> +check ovn-nbctl --wait=hv lrp-del lr-ls1 >> + >> +dnl Check local mac binding cache - it should be empty now. >> +AT_CHECK([as hv1 ovn-appctl -t ovn-controller debug/dump-mac-bindings], >> [0], [dnl >> +Local MAC bindings: >> +]) >> + >> +AS_BOX([Change LRP tunnel-key with learnt MAC_Binding and remove LRP]) >> +dnl Re-add port. >> +check ovn-nbctl \ >> + -- set logical_router_port lr-ls2 options:requested-tnl-key=42 >> +check ovn-nbctl --wait=hv sync >> +check_column 42 Port_Binding tunnel_key logical_port=lr-ls2 >> + >> +dnl Populate MAC Binding entry. >> +send_garp hv1 vif2 00:00:00:00:20:10 192.168.20.10 >> +wait_row_count mac_binding 1 ip="192.168.20.10" logical_port="lr-ls2" >> + >> +dnl Check local mac binding cache. >> +mb_uuid=$(fetch_column mac_binding _uuid logical_port=lr-ls2) >> +OVS_WAIT_FOR_OUTPUT_UNQUOTED([as hv1 ovn-appctl -t ovn-controller >> debug/dump-mac-bindings], [0], [dnl >> +Local MAC bindings: >> +SB UUID: $mb_uuid, datapath-key: $lr_key, port-key: 0, ip: 192.168.20.10, >> mac: 00:00:00:00:20:10 >> +]) >> + >> +dnl Change LRP tunnel key. >> +check ovn-nbctl --wait=hv set logical_router_port lr-ls2 >> options:requested-tnl-key=43 >> +check_column 43 Port_Binding tunnel_key logical_port=lr-ls2 >> + >> +dnl Remove router port. This deletes the mac binding in the same >> transaction. >> +check ovn-nbctl --wait=hv lrp-del lr-ls2 >> +dnl Check local mac binding cache - it should be empty now. >> +AT_CHECK([as hv1 ovn-appctl -t ovn-controller debug/dump-mac-bindings], >> [0], [dnl >> +Local MAC bindings: >> +]) >> + >> +OVN_CLEANUP([hv1]) >> +AT_CLEANUP >> +]) >> + >> OVN_FOR_EACH_NORTHD([ >> AT_SETUP([router port type update and then remove]) >> ovn_start >> -- >> 2.46.2 >> >> > Other than that the fix looks good. > > Acked-by: Ales Musil <amu...@redhat.com> > > Thanks, > Ales Thanks, Dumitru _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev