diff --git a/controller/local_data.c b/controller/local_data.c index 0c301b8e89..28e7d56cba 100644 --- a/controller/local_data.c +++ b/controller/local_data.c @@ -56,6 +56,20 @@ static bool datapath_is_transit_switch(const struct sbrec_datapath_binding *); static uint64_t local_datapath_usage; +/* To be used when hmap_node.hash might be wrong e.g. tunnel_key got updated */ +struct local_datapath * +get_local_datapath_no_hash(const struct hmap *local_datapaths, + uint32_t tunnel_key) +{ + struct local_datapath *ld; + HMAP_FOR_EACH (ld, hmap_node, local_datapaths) { + if (ld->datapath->tunnel_key == tunnel_key) { + return ld; + } + } + return NULL; +} + struct local_datapath * get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key) { diff --git a/controller/local_data.h b/controller/local_data.h index 7dc53992a5..661529bd94 100644 --- a/controller/local_data.h +++ b/controller/local_data.h @@ -65,6 +65,10 @@ struct local_datapath *local_datapath_alloc( const struct sbrec_datapath_binding *); struct local_datapath *get_local_datapath(const struct hmap *, uint32_t tunnel_key); +struct local_datapath *get_local_datapath_no_hash( + const struct hmap *local_datapaths, + uint32_t tunnel_key); + bool need_add_peer_to_local( struct ovsdb_idl_index *sbrec_port_binding_by_name, diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 5c4bd7a859..8b99e0e572 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -1766,6 +1766,7 @@ runtime_data_sb_datapath_binding_handler(struct engine_node *node OVS_UNUSED, engine_get_input("SB_datapath_binding", node)); const struct sbrec_datapath_binding *dp; struct ed_type_runtime_data *rt_data = data; + struct local_datapath *ld; SBREC_DATAPATH_BINDING_TABLE_FOR_EACH_TRACKED (dp, dp_table) { if (sbrec_datapath_binding_is_deleted(dp)) { @@ -1773,6 +1774,28 @@ runtime_data_sb_datapath_binding_handler(struct engine_node *node OVS_UNUSED, dp->tunnel_key)) { return false; } + /* If the tunnel key got updated, get_local_datapath will not find + * the ld. Use get_local_datapath_no_hash which does not + * rely on the hash. + */ + if (sbrec_datapath_binding_is_updated( + dp, SBREC_DATAPATH_BINDING_COL_TUNNEL_KEY)) { + if (get_local_datapath_no_hash(&rt_data->local_datapaths, + dp->tunnel_key)) { + return false; + } + } + } else if (sbrec_datapath_binding_is_updated( + dp, SBREC_DATAPATH_BINDING_COL_TUNNEL_KEY) + && !sbrec_datapath_binding_is_new(dp)) { + /* If the tunnel key is updated, remove the entry (with a wrong + * hash) from the map. It will be (properly) added back later. + */ + if ((ld = get_local_datapath_no_hash(&rt_data->local_datapaths, + dp->tunnel_key))) { + hmap_remove(&rt_data->local_datapaths, &ld->hmap_node); + local_datapath_destroy(ld); + } } } diff --git a/tests/ovn.at b/tests/ovn.at index 7a5d09ca1f..29cb6ebcd3 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -35349,3 +35349,46 @@ OVN_CLEANUP([hv1]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([Changing tunnel_key]) +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.11 + +check ovn-nbctl --wait=hv ls-add ls \ + -- lsp-add ls lsp1 \ + -- lsp-add ls ls-lr \ + -- lr-add lr \ + -- lrp-add lr lr-ls f0:00:00:00:00:f1 192.168.1.1/24 \ + -- set Logical_Switch_Port ls-lr \ + type=router \ + options:router-port=lr-ls \ + addresses=router \ + -- lrp-set-gateway-chassis lr-ls hv1 + +sleep_controller hv1 + +check ovn-nbctl --wait=sb set Logical_Switch ls other_config:requested-tnl-key=1000 +check ovn-nbctl --wait=sb ls-del ls +wake_up_controller hv1 + +check ovn-nbctl --wait=hv sync + +check ovn-nbctl --wait=hv ls-add ls1 \ + -- lsp-add ls1 ls1-lr \ + -- lrp-add lr lr-ls1 f0:00:00:00:00:f2 192.168.2.1/24 \ + -- set Logical_Switch_Port ls1-lr type=router options:router-port=lr-ls1 addresses=router \ + -- lrp-set-gateway-chassis lr-ls1 hv1 + +check ovn-nbctl --wait=hv set Logical_Switch ls1 other_config:requested-tnl-key=1001 + +OVN_CLEANUP([hv1]) + +AT_CLEANUP +])