On 8/6/25 7:40 PM, Mark Michelson via dev wrote: > Calling sbrec_datapath_binding_insert() returns a pointer to the > datapath binding that will be inserted once the transaction is > committed. This pointer is only valid until the point the transaction is > committed. At that point, the IDL will free the pointer and it is no > longer valid. Caching this pointer, therefore, is dangerous, since you > could be holding a pointer to freed data. Once the IDL runs again, it > will provide a permanent pointer to the datapath binding, which is safe > to cache. > > This patch introduces a wrapper structure, ovn_datapath_binding. This > wrapper structure is safe to cache since it is not deleted by the IDL. > The inner sbrec_datapath_binding pointer can be updated by datapath > syncing nodes when the IDL provides a new datapath binding pointer. > > This particular patch does nothing other than to introduce the structure > and cache it where necessary. Upcoming commits will cause datapath > syncing nodes to update their inner pointers as necessary, making > downstream engine node caching safe. > > Signed-off-by: Mark Michelson <mmich...@redhat.com> > --- > v13 > * This is the first version of the series with this patch. > ---
Hi Mark, > northd/aging.c | 8 ++--- > northd/datapath-sync.h | 21 ++++++++++++ > northd/en-advertised-route-sync.c | 10 +++--- > northd/en-datapath-logical-router.c | 4 ++- > northd/en-datapath-logical-router.h | 3 +- > northd/en-datapath-logical-switch.c | 4 ++- > northd/en-datapath-logical-switch.h | 3 +- > northd/en-multicast.c | 4 +-- > northd/en-port-group.c | 2 +- > northd/lflow-mgr.c | 4 +-- > northd/northd.c | 50 ++++++++++++++--------------- > northd/northd.h | 2 +- > 12 files changed, 71 insertions(+), 44 deletions(-) > > diff --git a/northd/aging.c b/northd/aging.c > index aa62a90dc..6afeeacff 100644 > --- a/northd/aging.c > +++ b/northd/aging.c > @@ -412,7 +412,7 @@ en_mac_binding_aging_run(struct engine_node *node, void > *data OVS_UNUSED) > HMAP_FOR_EACH (od, key_node, &northd_data->lr_datapaths.datapaths) { > ovs_assert(od->nbr); > > - if (!od->sb) { > + if (!od->dp->sb_dp) { > continue; > } > > @@ -425,7 +425,7 @@ en_mac_binding_aging_run(struct engine_node *node, void > *data OVS_UNUSED) > > aging_context_set_threshold(&ctx, &threshold_config); > > - mac_binding_aging_run_for_datapath(od->sb, > + mac_binding_aging_run_for_datapath(od->dp->sb_dp, > sbrec_mac_binding_by_datapath, > &ctx); > threshold_config_destroy(&threshold_config); > @@ -544,7 +544,7 @@ en_fdb_aging_run(struct engine_node *node, void *data > OVS_UNUSED) > HMAP_FOR_EACH (od, key_node, &northd_data->ls_datapaths.datapaths) { > ovs_assert(od->nbs); > > - if (!od->sb) { > + if (!od->dp->sb_dp) { > continue; > } > > @@ -553,7 +553,7 @@ en_fdb_aging_run(struct engine_node *node, void *data > OVS_UNUSED) > threshold_config.default_threshold = > smap_get_uint(&od->nbs->other_config, "fdb_age_threshold", 0); > aging_context_set_threshold(&ctx, &threshold_config); > - fdb_run_for_datapath(od->sb, sbrec_fdb_by_dp_key, &ctx); > + fdb_run_for_datapath(od->dp->sb_dp, sbrec_fdb_by_dp_key, &ctx); > > if (aging_context_is_at_limit(&ctx)) { > /* Schedule the next run after specified delay. */ > diff --git a/northd/datapath-sync.h b/northd/datapath-sync.h > index 246500c7b..aa374dd15 100644 > --- a/northd/datapath-sync.h > +++ b/northd/datapath-sync.h > @@ -74,6 +74,27 @@ struct ovn_synced_datapaths { > struct hmap synced_dps; > }; > > +/* This is a simple wrapper for a southbound datapath binding. Its purpose > + * is to allow for engine nodes to cache datapath binding pointers safely. > + * > + * When an sbrec_datapath_binding is inserted into the southbound > + * database, the pointer from sbrec_datapath_binding_insert() is not > + * safe to cache. The pointer is freed when the IDL loop is run and > + * the transaction is committed. Once the next IDL loop is run and the > + * southbound database sends an update message with the newly-inserted > + * datapath binding, the pointer provided by the IDL is now safe to cache > + * until the datapath binding is deleted. > + * > + * Engine nodes can safely cache an ovn_datapath_binding, though. The > + * reason is that datapath syncing nodes will update the inner sb_dp > + * pointer to be the permanent version of the pointer once the IDL > + * provides the pointer. So long as the outer ovn_datapath_binding is > + * what is cached, it is perfectly safe. > + */ > +struct ovn_datapath_binding { > + const struct sbrec_datapath_binding *sb_dp; > +}; > + As discussed a bit offline, we could just use pointers to 'struct ovn_synced_datapath' instead. We have them available every time we create 'struct ovn_datapath' and they're (a bit more than) wrappers on top of raw 'const struct sbrec_datapath_binding *'. > struct ovn_unsynced_datapath *ovn_unsynced_datapath_alloc( > const char *name, enum ovn_datapath_type type, > uint32_t requested_tunnel_key, const struct ovsdb_idl_row *nb_row); > diff --git a/northd/en-advertised-route-sync.c > b/northd/en-advertised-route-sync.c > index e75ab15c5..b2eeefa85 100644 > --- a/northd/en-advertised-route-sync.c > +++ b/northd/en-advertised-route-sync.c > @@ -56,7 +56,7 @@ ar_entry_add_nocopy(struct hmap *routes, const struct > ovn_datapath *od, > route_e->ip_prefix = ip_prefix; > route_e->tracked_port = tracked_port; > route_e->source = source; > - uint32_t hash = uuid_hash(&od->sb->header_.uuid); > + uint32_t hash = uuid_hash(&od->dp->sb_dp->header_.uuid); > hash = hash_string(op->sb->logical_port, hash); > hash = hash_string(ip_prefix, hash); > hmap_insert(routes, &route_e->hmap_node, hash); > @@ -92,7 +92,7 @@ ar_entry_find(struct hmap *route_map, > > HMAP_FOR_EACH_WITH_HASH (route_e, hmap_node, hash, route_map) { > if (!uuid_equals(&sb_db->header_.uuid, > - &route_e->od->sb->header_.uuid)) { > + &route_e->od->dp->sb_dp->header_.uuid)) { > continue; > } > if (!uuid_equals(&logical_port->header_.uuid, > @@ -281,7 +281,7 @@ build_nat_route_for_port(const struct ovn_port > *advertising_op, > ? ovn_port_find(ls_ports, nat->nb->logical_port) > : nat->l3dgw_port; > > - if (!ar_entry_find(routes, advertising_od->sb, advertising_op->sb, > + if (!ar_entry_find(routes, advertising_od->dp->sb_dp, > advertising_op->sb, > nat->nb->external_ip, > tracked_port ? tracked_port->sb : NULL)) { > ar_entry_add(routes, advertising_od, advertising_op, > @@ -767,7 +767,7 @@ advertised_route_table_sync( > > const struct sbrec_port_binding *tracked_pb = > route_e->tracked_port ? route_e->tracked_port->sb : NULL; > - if (ar_entry_find(&sync_routes, route_e->od->sb, route_e->op->sb, > + if (ar_entry_find(&sync_routes, route_e->od->dp->sb_dp, > route_e->op->sb, > route_e->ip_prefix, tracked_pb)) { > /* We could already have advertised route entry for LRP IP that > * corresponds to "snat" when "connected-as-host" is combined > @@ -802,7 +802,7 @@ advertised_route_table_sync( > HMAP_FOR_EACH_POP (route_e, hmap_node, &sync_routes) { > const struct sbrec_advertised_route *sr = > sbrec_advertised_route_insert(ovnsb_txn); > - sbrec_advertised_route_set_datapath(sr, route_e->od->sb); > + sbrec_advertised_route_set_datapath(sr, route_e->od->dp->sb_dp); > sbrec_advertised_route_set_logical_port(sr, route_e->op->sb); > sbrec_advertised_route_set_ip_prefix(sr, route_e->ip_prefix); > if (route_e->tracked_port) { > diff --git a/northd/en-datapath-logical-router.c > b/northd/en-datapath-logical-router.c > index 86c3eb365..d15907d6b 100644 > --- a/northd/en-datapath-logical-router.c > +++ b/northd/en-datapath-logical-router.c > @@ -172,7 +172,9 @@ en_datapath_synced_logical_router_run(struct engine_node > *node , void *data) > *lr = (struct ovn_synced_logical_router) { > .nb = CONTAINER_OF(sdp->nb_row, struct nbrec_logical_router, > header_), > - .sb = sdp->sb_dp, > + .dp = (struct ovn_datapath_binding) { > + .sb_dp = sdp->sb_dp, > + } > }; > hmap_insert(&router_map->synced_routers, &lr->hmap_node, > uuid_hash(&lr->nb->header_.uuid)); > diff --git a/northd/en-datapath-logical-router.h > b/northd/en-datapath-logical-router.h > index 31e70fbf5..ce1b321e5 100644 > --- a/northd/en-datapath-logical-router.h > +++ b/northd/en-datapath-logical-router.h > @@ -18,6 +18,7 @@ > #define EN_DATAPATH_LOGICAL_ROUTER_H > > #include "lib/inc-proc-eng.h" > +#include "datapath-sync.h" > #include "openvswitch/hmap.h" > > void *en_datapath_logical_router_init(struct engine_node *, > @@ -30,7 +31,7 @@ void en_datapath_logical_router_cleanup(void *data); > struct ovn_synced_logical_router { > struct hmap_node hmap_node; > const struct nbrec_logical_router *nb; > - const struct sbrec_datapath_binding *sb; > + struct ovn_datapath_binding dp; > }; > > struct ovn_synced_logical_router_map { > diff --git a/northd/en-datapath-logical-switch.c > b/northd/en-datapath-logical-switch.c > index 23fa9725f..3a6cd2e0a 100644 > --- a/northd/en-datapath-logical-switch.c > +++ b/northd/en-datapath-logical-switch.c > @@ -166,7 +166,9 @@ en_datapath_synced_logical_switch_run(struct engine_node > *node , void *data) > *lsw = (struct ovn_synced_logical_switch) { > .nb = CONTAINER_OF(sdp->nb_row, struct nbrec_logical_switch, > header_), > - .sb = sdp->sb_dp, > + .dp = (struct ovn_datapath_binding) { > + .sb_dp = sdp->sb_dp, > + }, > }; > hmap_insert(&switch_map->synced_switches, &lsw->hmap_node, > uuid_hash(&lsw->nb->header_.uuid)); > diff --git a/northd/en-datapath-logical-switch.h > b/northd/en-datapath-logical-switch.h > index 1bd5fea83..55928d705 100644 > --- a/northd/en-datapath-logical-switch.h > +++ b/northd/en-datapath-logical-switch.h > @@ -18,6 +18,7 @@ > #define EN_DATAPATH_LOGICAL_SWITCH_H > > #include "lib/inc-proc-eng.h" > +#include "datapath-sync.h" > #include "openvswitch/hmap.h" > > void *en_datapath_logical_switch_init(struct engine_node *, > @@ -30,7 +31,7 @@ void en_datapath_logical_switch_cleanup(void *data); > struct ovn_synced_logical_switch { > struct hmap_node hmap_node; > const struct nbrec_logical_switch *nb; > - const struct sbrec_datapath_binding *sb; > + struct ovn_datapath_binding dp; > }; > > struct ovn_synced_logical_switch_map { > diff --git a/northd/en-multicast.c b/northd/en-multicast.c > index d51db557e..fb34c55f5 100644 > --- a/northd/en-multicast.c > +++ b/northd/en-multicast.c > @@ -434,7 +434,7 @@ sync_multicast_groups_to_sb( > continue; > } > > - sbmc = create_sb_multicast_group(ovnsb_txn, mc->datapath->sb, > + sbmc = create_sb_multicast_group(ovnsb_txn, mc->datapath->dp->sb_dp, > mc->group->name, mc->group->key); > ovn_multicast_update_sbrec(mc, sbmc); > } > @@ -579,7 +579,7 @@ ovn_igmp_group_add(struct ovsdb_idl_index > *sbrec_mcast_group_by_name_dp, > const struct sbrec_multicast_group *mcgroup = > mcast_group_lookup(sbrec_mcast_group_by_name_dp, > address_s, > - datapath->sb); > + datapath->dp->sb_dp); > > igmp_group->datapath = datapath; > igmp_group->address = *address; > diff --git a/northd/en-port-group.c b/northd/en-port-group.c > index 4fc1a4f24..b2dd4aa59 100644 > --- a/northd/en-port-group.c > +++ b/northd/en-port-group.c > @@ -255,7 +255,7 @@ ls_port_group_process(struct ls_port_group_table > *ls_port_groups, > struct ls_port_group *ls_pg = > ls_port_group_table_find(ls_port_groups, od->nbs); > if (!ls_pg) { > - ls_pg = ls_port_group_create(ls_port_groups, od->nbs, od->sb); > + ls_pg = ls_port_group_create(ls_port_groups, od->nbs, > od->dp->sb_dp); > } > > struct ls_port_group_record *ls_pg_rec = > diff --git a/northd/lflow-mgr.c b/northd/lflow-mgr.c > index 18b88cf9e..28156c1e1 100644 > --- a/northd/lflow-mgr.c > +++ b/northd/lflow-mgr.c > @@ -1118,7 +1118,7 @@ sync_lflow_to_sb(struct ovn_lflow *lflow, > } > > if (lflow->od) { > - sbrec_logical_flow_set_logical_datapath(sbflow, lflow->od->sb); > + sbrec_logical_flow_set_logical_datapath(sbflow, > lflow->od->dp->sb_dp); > sbrec_logical_flow_set_logical_dp_group(sbflow, NULL); > } else { > sbrec_logical_flow_set_logical_datapath(sbflow, NULL); > @@ -1226,7 +1226,7 @@ ovn_sb_insert_or_update_logical_dp_group( > > sb = xmalloc(bitmap_count1(dpg_bitmap, ods_size(datapaths)) * sizeof > *sb); > BITMAP_FOR_EACH_1 (index, ods_size(datapaths), dpg_bitmap) { > - sb[n++] = datapaths->array[index]->sb; > + sb[n++] = datapaths->array[index]->dp->sb_dp; > } > if (!dp_group) { > struct uuid dpg_uuid = uuid_random(); > diff --git a/northd/northd.c b/northd/northd.c > index 4d5ed6701..992c18d23 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -518,11 +518,11 @@ static struct ovn_datapath * > ovn_datapath_create(struct hmap *datapaths, const struct uuid *key, > const struct nbrec_logical_switch *nbs, > const struct nbrec_logical_router *nbr, > - const struct sbrec_datapath_binding *sb) > + const struct ovn_datapath_binding *dp) > { > struct ovn_datapath *od = xzalloc(sizeof *od); > od->key = *key; > - od->sb = sb; > + od->dp = dp; > od->nbs = nbs; > od->nbr = nbr; > hmap_init(&od->port_tnlids); > @@ -537,7 +537,7 @@ ovn_datapath_create(struct hmap *datapaths, const struct > uuid *key, > od->localnet_ports = VECTOR_EMPTY_INITIALIZER(struct ovn_port *); > od->lb_with_stateless_mode = false; > od->ipam_info_initialized = false; > - od->tunnel_key = sb->tunnel_key; > + od->tunnel_key = dp->sb_dp->tunnel_key; > init_mcast_info_for_datapath(od); > return od; > } > @@ -628,7 +628,7 @@ ovn_datapath_from_sbrec(const struct hmap *ls_datapaths, > } > > struct ovn_datapath *od = ovn_datapath_find_(dps, &key); > - if (od && (od->sb == sb)) { > + if (od && (od->dp->sb_dp == sb)) { > return od; > } > > @@ -747,7 +747,7 @@ store_mcast_info_for_switch_datapath(const struct > sbrec_ip_multicast *sb, > { > struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw; > > - sbrec_ip_multicast_set_datapath(sb, od->sb); > + sbrec_ip_multicast_set_datapath(sb, od->dp->sb_dp); > sbrec_ip_multicast_set_enabled(sb, &mcast_sw_info->enabled, 1); > sbrec_ip_multicast_set_querier(sb, &mcast_sw_info->querier, 1); > sbrec_ip_multicast_set_table_size(sb, &mcast_sw_info->table_size, 1); > @@ -856,7 +856,7 @@ build_datapaths(const struct > ovn_synced_logical_switch_map *ls_map, > struct ovn_datapath *od = > ovn_datapath_create(&ls_datapaths->datapaths, > &ls->nb->header_.uuid, > - ls->nb, NULL, ls->sb); > + ls->nb, NULL, &ls->dp); This is a problem because we pass a pointer to a field of 'ls' (struct ovn_synced_logical_switch) and the 'ls' record gets freed before the next incremental processing run. This results in use after free. > init_ipam_info_for_datapath(od); > if (smap_get_bool(&od->nbs->other_config, > "enable-stateless-acl-with-lb", > @@ -870,7 +870,7 @@ build_datapaths(const struct > ovn_synced_logical_switch_map *ls_map, > struct ovn_datapath *od = > ovn_datapath_create(&lr_datapaths->datapaths, > &lr->nb->header_.uuid, > - NULL, lr->nb, lr->sb); > + NULL, lr->nb, &lr->dp); Same here. That's mainly why the CI is red with this patch. > if (smap_get(&od->nbr->options, "chassis")) { > od->is_gw_router = true; > } > @@ -1441,7 +1441,7 @@ create_mirror_port(struct ovn_port *op, struct hmap > *ports, > struct ovs_list *both_dbs, struct ovs_list *nb_only, > const struct nbrec_mirror *nb_mirror) > { > - char *mp_name = ovn_mirror_port_name(ovn_datapath_name(op->od->sb), > + char *mp_name = > ovn_mirror_port_name(ovn_datapath_name(op->od->dp->sb_dp), > nb_mirror->sink); > struct ovn_port *mp = ovn_port_find(ports, mp_name); > struct ovn_port *target_port = ovn_port_find(ports, nb_mirror->sink); > @@ -1485,7 +1485,7 @@ join_logical_ports_lsp(struct hmap *ports, > = VLOG_RATE_LIMIT_INIT(5, 1); > VLOG_WARN_RL(&rl, "duplicate logical port %s", name); > return NULL; > - } else if (op && (!op->sb || op->sb->datapath == od->sb)) { > + } else if (op && (!op->sb || op->sb->datapath == od->dp->sb_dp)) { > /* > * Handle cases where lport type was explicitly changed > * in the NBDB, in such cases: > @@ -1582,7 +1582,7 @@ join_logical_ports_lrp(struct hmap *ports, > name); > destroy_lport_addresses(lrp_networks); > return NULL; > - } else if (op && (!op->sb || op->sb->datapath == od->sb)) { > + } else if (op && (!op->sb || op->sb->datapath == od->dp->sb_dp)) { > ovn_port_set_nb(op, NULL, nbrp); > ovs_list_remove(&op->list); > ovs_list_push_back(both, &op->list); > @@ -1655,7 +1655,7 @@ create_cr_port(struct ovn_port *op, struct hmap *ports, > op->nbsp ? op->nbsp->name : op->nbrp->name); > > struct ovn_port *crp = ovn_port_find(ports, redirect_name); > - if (crp && crp->sb && crp->sb->datapath == op->od->sb) { > + if (crp && crp->sb && crp->sb->datapath == op->od->dp->sb_dp) { > ovn_port_set_nb(crp, op->nbsp, op->nbrp); > ovs_list_remove(&crp->list); > ovs_list_push_back(both_dbs, &crp->list); > @@ -2513,7 +2513,7 @@ ovn_port_update_sbrec(struct ovsdb_idl_txn *ovnsb_txn, > unsigned long *queue_id_bitmap, > struct sset *active_ha_chassis_grps) > { > - sbrec_port_binding_set_datapath(op->sb, op->od->sb); > + sbrec_port_binding_set_datapath(op->sb, op->od->dp->sb_dp); > if (op->nbrp) { > /* Note: SB port binding options for router ports are set in > * sync_pbs(). */ > @@ -3829,7 +3829,7 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn, > /* When reusing stale Port_Bindings, make sure that stale > * Mac_Bindings are purged. > */ > - if (op->od->sb != op->sb->datapath) { > + if (op->od->dp->sb_dp != op->sb->datapath) { > remove_mac_bindings = true; > } > if (op->nbsp) { > @@ -5340,7 +5340,7 @@ build_mirror_lflows(struct ovn_port *op, > } > > char *serving_port_name = ovn_mirror_port_name( > - ovn_datapath_name(op->od->sb), > + ovn_datapath_name(op->od->dp->sb_dp), > mirror->sink); > > struct ovn_port *serving_port = ovn_port_find(ls_ports, > @@ -18037,13 +18037,13 @@ lflow_handle_northd_port_changes(struct > ovsdb_idl_txn *ovnsb_txn, > > const struct sbrec_multicast_group *sbmc_flood = > mcast_group_lookup(lflow_input->sbrec_mcast_group_by_name_dp, > - MC_FLOOD, op->od->sb); > + MC_FLOOD, op->od->dp->sb_dp); > const struct sbrec_multicast_group *sbmc_flood_l2 = > mcast_group_lookup(lflow_input->sbrec_mcast_group_by_name_dp, > - MC_FLOOD_L2, op->od->sb); > + MC_FLOOD_L2, op->od->dp->sb_dp); > const struct sbrec_multicast_group *sbmc_unknown = > mcast_group_lookup(lflow_input->sbrec_mcast_group_by_name_dp, > - MC_UNKNOWN, op->od->sb); > + MC_UNKNOWN, op->od->dp->sb_dp); > > struct ds match = DS_EMPTY_INITIALIZER; > struct ds actions = DS_EMPTY_INITIALIZER; > @@ -18083,13 +18083,13 @@ lflow_handle_northd_port_changes(struct > ovsdb_idl_txn *ovnsb_txn, > /* Update SB multicast groups for the new port. */ > if (!sbmc_flood) { > sbmc_flood = create_sb_multicast_group(ovnsb_txn, > - op->od->sb, MC_FLOOD, OVN_MCAST_FLOOD_TUNNEL_KEY); > + op->od->dp->sb_dp, MC_FLOOD, OVN_MCAST_FLOOD_TUNNEL_KEY); > } > sbrec_multicast_group_update_ports_addvalue(sbmc_flood, op->sb); > > if (!sbmc_flood_l2) { > sbmc_flood_l2 = create_sb_multicast_group(ovnsb_txn, > - op->od->sb, MC_FLOOD_L2, > + op->od->dp->sb_dp, MC_FLOOD_L2, > OVN_MCAST_FLOOD_L2_TUNNEL_KEY); > } > sbrec_multicast_group_update_ports_addvalue(sbmc_flood_l2, op->sb); > @@ -18097,7 +18097,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn > *ovnsb_txn, > if (op->has_unknown) { > if (!sbmc_unknown) { > sbmc_unknown = create_sb_multicast_group(ovnsb_txn, > - op->od->sb, MC_UNKNOWN, > + op->od->dp->sb_dp, MC_UNKNOWN, > OVN_MCAST_UNKNOWN_TUNNEL_KEY); > } > sbrec_multicast_group_update_ports_addvalue(sbmc_unknown, > @@ -18418,7 +18418,7 @@ sync_dns_entries(struct ovsdb_idl_txn *ovnsb_txn, > dns_info->n_sbs++; > dns_info->sbs = xrealloc(dns_info->sbs, > dns_info->n_sbs * sizeof > *dns_info->sbs); > - dns_info->sbs[dns_info->n_sbs - 1] = od->sb; > + dns_info->sbs[dns_info->n_sbs - 1] = od->dp->sb_dp; > } > } > > @@ -18535,7 +18535,7 @@ build_ip_mcast(struct ovsdb_idl_txn *ovnsb_txn, > ovs_assert(od->nbs); > > const struct sbrec_ip_multicast *ip_mcast = > - ip_mcast_lookup(sbrec_ip_mcast_by_dp, od->sb); > + ip_mcast_lookup(sbrec_ip_mcast_by_dp, od->dp->sb_dp); > > if (!ip_mcast) { > ip_mcast = sbrec_ip_multicast_insert(ovnsb_txn); > @@ -18576,7 +18576,7 @@ build_static_mac_binding_table( > } > > struct ovn_port *op = ovn_port_find(lr_ports, nb_smb->logical_port); > - if (!op || !op->nbrp || !op->od || !op->od->sb) { > + if (!op || !op->nbrp || !op->od || !op->od->dp->sb_dp) { > sbrec_static_mac_binding_delete(sb_smb); > } > } > @@ -18588,7 +18588,7 @@ build_static_mac_binding_table( > struct ovn_port *op = ovn_port_find(lr_ports, nb_smb->logical_port); > if (op && op->nbrp) { > struct ovn_datapath *od = op->od; > - if (od && od->sb) { > + if (od && od->dp->sb_dp) { > const struct uuid *nb_uuid = &nb_smb->header_.uuid; > const struct sbrec_static_mac_binding *mb = > sbrec_static_mac_binding_table_get_for_uuid( > @@ -18603,7 +18603,7 @@ build_static_mac_binding_table( > sbrec_static_mac_binding_set_mac(mb, nb_smb->mac); > sbrec_static_mac_binding_set_override_dynamic_mac(mb, > nb_smb->override_dynamic_mac); > - sbrec_static_mac_binding_set_datapath(mb, od->sb); > + sbrec_static_mac_binding_set_datapath(mb, od->dp->sb_dp); > } else { > /* Update existing entry if there is a change*/ > if (strcmp(mb->mac, nb_smb->mac)) { > diff --git a/northd/northd.h b/northd/northd.h > index 2f1b8ceb5..e223a54da 100644 > --- a/northd/northd.h > +++ b/northd/northd.h > @@ -369,7 +369,7 @@ struct ovn_datapath { > > const struct nbrec_logical_switch *nbs; /* May be NULL. */ > const struct nbrec_logical_router *nbr; /* May be NULL. */ > - const struct sbrec_datapath_binding *sb; /* May be NULL. */ > + const struct ovn_datapath_binding *dp; /* May be NULL. */ > > struct ovs_list list; /* In list of similar records. */ > Regards, Dumitru _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev