On Tue, Apr 08, 2025 at 07:45:01AM +0200, Ales Musil via dev wrote: > On Mon, Apr 7, 2025 at 5:17 PM Felix Huettner <felix.huettner@stackit.cloud> > wrote: > > > On Mon, Apr 07, 2025 at 11:15:32AM +0200, Felix Huettner via dev wrote: > > > On Thu, Apr 03, 2025 at 12:35:22PM +0200, Ales Musil wrote: > > > > On Thu, Mar 20, 2025 at 1:01 PM Felix Huettner via dev < > > > > ovs-dev@openvswitch.org> wrote: > > > > > > > > > Previously local ports that had an external_id:iface-id set would > > get a > > > > > ct-zone assigned on recompute, independent if there is a matching > > > > > southbound port_binding for them or if this port_binding can actually > > > > > reside on the local chassis. > > > > > However during incremental processing this was not the case and only > > > > > bound local ports would have their ct zone added or removed (as only > > > > > they are included in tracked_dp_bindings). > > > > > > > > > > To fix this we add a status enum to local_lports that defines if > > there > > > > > is a matching port_binding or not. > > > > > The ct_zones engine node no only considers local_lports that are > > backed > > > > > by some port_binding entry. > > > > > > > > > > Signed-off-by: Felix Huettner <felix.huettner@stackit.cloud> > > > > > --- > > > > > > > > > > > > > Hi Felix, > > > > > > > > thank you for the patch. There are some workaround in tests > > > > introduced by 9f052bdb [0]. Could please try to remove those > > > > workaround as part of this patch to see if it helps? > > > > > > Hi Ales, > > > > > > thanks a lot. > > > I'll remove them in the next version. > > > > > > > > > > > Also I have some concerns with the approach. See down below. > > > > > > > > v6->v7: introduced > > > > > > > > > > controller/binding.c | 29 ++++++++++++++++++++--------- > > > > > controller/binding.h | 8 +++++++- > > > > > controller/ct-zone.c | 19 ++++++++++++++----- > > > > > controller/ct-zone.h | 2 +- > > > > > controller/ovn-controller.c | 21 ++++++++++++--------- > > > > > controller/physical.h | 2 +- > > > > > controller/route.h | 2 +- > > > > > 7 files changed, 56 insertions(+), 27 deletions(-) > > > > > > > > > > diff --git a/controller/binding.c b/controller/binding.c > > > > > index 470aa8c53..a080b1041 100644 > > > > > --- a/controller/binding.c > > > > > +++ b/controller/binding.c > > > > > @@ -654,11 +654,19 @@ update_ld_localnet_port(const struct > > > > > sbrec_port_binding *binding_rec, > > > > > * Also track if the set has changed. > > > > > */ > > > > > static void > > > > > -update_local_lports(const char *iface_id, struct binding_ctx_out > > *b_ctx) > > > > > +update_local_lports(const char *iface_id, struct binding_ctx_out > > *b_ctx, > > > > > + enum binding_local_lport_status status) > > > > > { > > > > > - if (sset_add(b_ctx->local_lports, iface_id) != NULL) { > > > > > - b_ctx->local_lports_changed = true; > > > > > + struct simap_node *node = simap_find(b_ctx->local_lports, > > iface_id); > > > > > + if (node && node->data == status) { > > > > > + return; > > > > > } > > > > > + if (node) { > > > > > + node->data = status; > > > > > + } else { > > > > > + simap_put(b_ctx->local_lports, iface_id, status); > > > > > + } > > > > > + b_ctx->local_lports_changed = true; > > > > > } > > > > > > > > > > /* Remove an interface ID from the set of local lports. Also track > > if the > > > > > @@ -667,7 +675,7 @@ update_local_lports(const char *iface_id, struct > > > > > binding_ctx_out *b_ctx) > > > > > static void > > > > > remove_local_lports(const char *iface_id, struct binding_ctx_out > > *b_ctx) > > > > > { > > > > > - if (sset_find_and_delete(b_ctx->local_lports, iface_id)) { > > > > > + if (simap_find_and_delete(b_ctx->local_lports, iface_id)) { > > > > > b_ctx->local_lports_changed = true; > > > > > } > > > > > } > > > > > @@ -1603,7 +1611,8 @@ consider_vif_lport_(const struct > > sbrec_port_binding > > > > > *pb, > > > > > b_ctx_out->local_datapaths, > > > > > b_ctx_out->tracked_dp_bindings); > > > > > update_related_lport(pb, b_ctx_out); > > > > > - update_local_lports(pb->logical_port, b_ctx_out); > > > > > + update_local_lports(pb->logical_port, b_ctx_out, > > > > > + LPORT_STATUS_BOUND); > > > > > if (binding_lport_update_port_sec(b_lport, pb) && > > > > > b_ctx_out->tracked_dp_bindings) { > > > > > tracked_datapath_lport_add(pb, > > TRACKED_RESOURCE_UPDATED, > > > > > @@ -1911,7 +1920,7 @@ consider_nonvif_lport_(const struct > > > > > sbrec_port_binding *pb, > > > > > pb->datapath->tunnel_key); > > > > > > > > > > if (our_chassis) { > > > > > - update_local_lports(pb->logical_port, b_ctx_out); > > > > > + update_local_lports(pb->logical_port, b_ctx_out, > > > > > LPORT_STATUS_BOUND); > > > > > if (!ld) { > > > > > > > add_local_datapath(b_ctx_in->sbrec_datapath_binding_by_key, > > > > > > > b_ctx_in->sbrec_port_binding_by_datapath, > > > > > @@ -2017,7 +2026,7 @@ consider_localnet_lport(const struct > > > > > sbrec_port_binding *pb, > > > > > > > > > > /* Add all localnet ports to local_ifaces so that we allocate > > ct zones > > > > > * for them. */ > > > > > - update_local_lports(pb->logical_port, b_ctx_out); > > > > > + update_local_lports(pb->logical_port, b_ctx_out, > > LPORT_STATUS_BOUND); > > > > > > > > > > add_or_del_qos_port(pb->logical_port, true); > > > > > update_related_lport(pb, b_ctx_out); > > > > > @@ -2118,7 +2127,8 @@ build_local_bindings(struct binding_ctx_in > > *b_ctx_in, > > > > > iface_rec->name); > > > > > } > > > > > > > > > > - update_local_lports(iface_id, b_ctx_out); > > > > > + update_local_lports(iface_id, b_ctx_out, > > > > > + LPORT_STATUS_NOT_BOUND); > > > > > smap_replace(b_ctx_out->local_iface_ids, > > iface_rec->name, > > > > > iface_id); > > > > > } else if (smap_get_bool(&iface_rec->external_ids, > > > > > @@ -2399,7 +2409,6 @@ consider_iface_claim(const struct > > ovsrec_interface > > > > > *iface_rec, > > > > > struct binding_ctx_in *b_ctx_in, > > > > > struct binding_ctx_out *b_ctx_out) > > > > > { > > > > > - update_local_lports(iface_id, b_ctx_out); > > > > > smap_replace(b_ctx_out->local_iface_ids, iface_rec->name, > > iface_id); > > > > > > > > > > struct shash *local_bindings = > > &b_ctx_out->lbinding_data->bindings; > > > > > @@ -2429,8 +2438,10 @@ consider_iface_claim(const struct > > ovsrec_interface > > > > > *iface_rec, > > > > > > > > > > if (!pb) { > > > > > /* There is no port_binding row for this local binding. */ > > > > > + update_local_lports(iface_id, b_ctx_out, > > LPORT_STATUS_NOT_BOUND); > > > > > return true; > > > > > } > > > > > + update_local_lports(iface_id, b_ctx_out, LPORT_STATUS_BOUND); > > > > > > > > > > > > > nit: there could be single function call above the if statement: > > > > > > > > update_local_lports(iface_id, b_ctx_out, pb ? LPORT_STATUS_BOUND : > > > > LPORT_STATUS_NOT_BOUND); > > > > > > Ok, will update that. > > > > > > > > > > > > > > > > > > > > > /* Check if iface-id-ver just becomes correct */ > > > > > struct smap *external_ids_old = > > > > > diff --git a/controller/binding.h b/controller/binding.h > > > > > index 00dd9dbf5..8a5c6996c 100644 > > > > > --- a/controller/binding.h > > > > > +++ b/controller/binding.h > > > > > @@ -71,6 +71,12 @@ struct related_lports { > > > > > */ > > > > > }; > > > > > > > > > > +enum binding_local_lport_status { > > > > > + LPORT_STATUS_NOT_BOUND, /* Set if just iface-id is set but the > > port is > > > > > + not in sb. */ > > > > > + LPORT_STATUS_BOUND, /* Set if the port is in sb and locally > > relevant. > > > > > */ > > > > > +}; > > > > > + > > > > > void related_lports_init(struct related_lports *); > > > > > void related_lports_destroy(struct related_lports *); > > > > > > > > > > @@ -81,7 +87,7 @@ struct binding_ctx_out { > > > > > struct local_binding_data *lbinding_data; > > > > > > > > > > /* sset of (potential) local lports. */ > > > > > - struct sset *local_lports; > > > > > + struct simap *local_lports; > > > > > /* Track if local_lports have been updated. */ > > > > > bool local_lports_changed; > > > > > > > > > > diff --git a/controller/ct-zone.c b/controller/ct-zone.c > > > > > index 469a8fc54..cf8f92b41 100644 > > > > > --- a/controller/ct-zone.c > > > > > +++ b/controller/ct-zone.c > > > > > @@ -167,7 +167,7 @@ out: > > > > > } > > > > > > > > > > void > > > > > -ct_zones_update(const struct sset *local_lports, > > > > > +ct_zones_update(const struct simap *local_lports, > > > > > const struct ovsrec_open_vswitch_table *ovs_table, > > > > > const struct hmap *local_datapaths, struct > > ct_zone_ctx > > > > > *ctx) > > > > > { > > > > > @@ -178,9 +178,11 @@ ct_zones_update(const struct sset *local_lports, > > > > > unsigned long *unreq_snat_zones_map = > > bitmap_allocate(MAX_CT_ZONES); > > > > > struct simap unreq_snat_zones = > > SIMAP_INITIALIZER(&unreq_snat_zones); > > > > > > > > > > - const char *local_lport; > > > > > - SSET_FOR_EACH (local_lport, local_lports) { > > > > > - sset_add(&all_users, local_lport); > > > > > + const struct simap_node *sinode; > > > > > + SIMAP_FOR_EACH (sinode, local_lports) { > > > > > + if (sinode->data == LPORT_STATUS_BOUND) { > > > > > + sset_add(&all_users, sinode->name); > > > > > + } > > > > > > > > > } > > > > > > > > > > /* Local patched datapath (gateway routers) need zones > > assigned. */ > > > > > @@ -217,7 +219,14 @@ ct_zones_update(const struct sset *local_lports, > > > > > SHASH_FOR_EACH_SAFE (node, &ctx->current) { > > > > > struct ct_zone *ct_zone = node->data; > > > > > if (!sset_contains(&all_users, node->name)) { > > > > > - ct_zone_remove(ctx, node->name); > > > > > + /* If we started recently and do not monitor all db > > entries > > > > > then we > > > > > + * might not have yet learned a port binding entry to > > the > > > > > port. > > > > > + * In this case we skip removing the zone until we > > either > > > > > know the > > > > > + * port binding or we are sure the zone is no longer > > needed. > > > > > */ > > > > > + if (!(daemon_started_recently() && > > > > > + simap_contains(local_lports, node->name))) { > > > > > > > > > > > > > The logic here worries me, ovn-controller guarantees that it won't > > > > flush zones for ports after restart. However, this might not be the > > > > case anymore after this patch. The started_recently adds some delay > > > > which is finite. Also looking at the code, who will actually trigger > > > > recompute of the ct_zones node? We might not clear the port zones > > > > until something else triggers ct_zone node. > > > > > > Isn't this something that is generally valid for all uses of > > > daemon_started_recently? > > > I mean once it returns true we will also start unplugging ports, > > > independent if we actually have all data or not. So maybe this would > > > just extend this "problem" to also ct zones. > > > I'm not sure if there is a nice other option, until we have a way of > > > knowing when all data has been loaded. > > > > Yes we would extend that behavior to CT zones, but that doesn't mean > it's the right thing to do. TBF the reason to talk about this was to > spark the discussion about potential ideas how to deal with this > which seems to be successful. > > > > > > For the recompute part we previously did not have the issue, since the > > > code that waits does run outside the engine. > > > However we could probably trigger a general recompute once the > > > started_recently timer elapses. > > > > That might be very costly to just run full recompute once > we are done with the waiting. > > > > > > > > Let me know what you think. > > > > Hi Ales, > > > > i thought more about this and maybe have an idea how we can generally > > improve the daemon_started_recently. > > > > If we have monitor-all enabled then we can generally say > > daemon_started_recently should return true once we got our initial > > monitoring updates. > > > > If monitor-all is disabled we would need a few more steps: > > 1. Get the initial data from southbound > > 2. Run the engine > > 3. Update the monitor conditions > > 4. Wait for the data with the new monitoring conditions in place > > > > > > In case the ovsdb-server supports monitor_cond or monitor_cond_since > > (which probably all of them do by now) we also know that the initial > > monitor data is sent as part of the reply to the monitor request. This > > is at least what i learned during experimenting, i hope that holds > > generally. > > > We would need to make sure that this is the case to not potentially > break combinations with older ovs releases.
Hi Ales, at least as part of the documentation of the method this should not happen. Also i think that monitor_cond is in since at least ovs v2.6, so i guess everyone should have that by now. > > > > > > When we call ovsdb_idl_get_condition_seqno in the ovn-controller main > > loop we can compare that against the monitor condition ids previously > > set (we get that from update_sb_monitors) and if they are equal we know > > we have up-to-data data available in the idl. > > This means for monitor-all we are now good to process changes. > > For non-monitor-all we would need to go though the above states to get > > accurate monitor definitions. > > > > That would allow us to get rid of the time and iteration sensitive > > method that is currently used by daemon_started_recently. Also since > > then the condition of daemon_started_recently is only depending on the > > sb connection we trigger computes/recomputes automatically anyway. > > > > Does that sound valid to you and would it also resolve your above > > concerns? > > > > That definitely sounds like something worth pursuing, thank you for > looking into this. I'll submit a proposal in the next version. Thanks, Felix > > > > > > Thanks a lot, > > Felix > > > > > > > > Thanks a lot, > > > Felix > > > > > > > > > > > > > > > > + ct_zone_remove(ctx, node->name); > > > > > + } > > > > > } else if (!simap_find(&req_snat_zones, node->name)) { > > > > > if (ct_zone->zone < min_ct_zone || ct_zone->zone > > > > > > max_ct_zone) { > > > > > ct_zone_remove(ctx, node->name); > > > > > diff --git a/controller/ct-zone.h b/controller/ct-zone.h > > > > > index 6df03975c..cc313d423 100644 > > > > > --- a/controller/ct-zone.h > > > > > +++ b/controller/ct-zone.h > > > > > @@ -70,7 +70,7 @@ void ct_zones_restore(struct ct_zone_ctx *ctx, > > > > > const struct ovsrec_open_vswitch_table > > *ovs_table, > > > > > const struct sbrec_datapath_binding_table > > *dp_table, > > > > > const struct ovsrec_bridge *br_int); > > > > > -void ct_zones_update(const struct sset *local_lports, > > > > > +void ct_zones_update(const struct simap *local_lports, > > > > > const struct ovsrec_open_vswitch_table > > *ovs_table, > > > > > const struct hmap *local_datapaths, > > > > > struct ct_zone_ctx *ctx); > > > > > diff --git a/controller/ovn-controller.c > > b/controller/ovn-controller.c > > > > > index a54db35ae..1ce076a04 100644 > > > > > --- a/controller/ovn-controller.c > > > > > +++ b/controller/ovn-controller.c > > > > > @@ -218,7 +218,7 @@ static char *get_file_system_id(void) > > > > > static unsigned int > > > > > update_sb_monitors(struct ovsdb_idl *ovnsb_idl, > > > > > const struct sbrec_chassis *chassis, > > > > > - const struct sset *local_ifaces, > > > > > + const struct simap *local_ifaces, > > > > > const struct shash *local_bindings, > > > > > struct hmap *local_datapaths, > > > > > bool monitor_all) > > > > > @@ -358,7 +358,9 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, > > > > > const char *name; > > > > > > > > > > ovs_assert(local_bindings); > > > > > - SSET_FOR_EACH (name, local_ifaces) { > > > > > + const struct simap_node *n; > > > > > + SIMAP_FOR_EACH (n, local_ifaces) { > > > > > + name = n->name; > > > > > /* Skip the VIFs we bound already, we should have a > > local > > > > > datapath > > > > > * for those. */ > > > > > const struct sbrec_port_binding *local_pb > > > > > @@ -1277,8 +1279,9 @@ struct ed_type_runtime_data { > > > > > * hypervisor. These logical ports include the VIFs (and their > > child > > > > > * logical ports, if any) that belong to VMs running on the > > > > > hypervisor, > > > > > * l2gateway ports for which options:l2gateway-chassis > > designates the > > > > > - * local hypervisor, and localnet ports. */ > > > > > - struct sset local_lports; > > > > > + * local hypervisor, and localnet ports. > > > > > + * The value is mapped to enum binding_local_lport_status. */ > > > > > + struct simap local_lports; > > > > > > > > > > /* Port bindings that are relevant to the local chassis (VIFs > > bound > > > > > * localy, patch ports). > > > > > @@ -1382,7 +1385,7 @@ en_runtime_data_init(struct engine_node *node > > > > > OVS_UNUSED, > > > > > struct ed_type_runtime_data *data = xzalloc(sizeof *data); > > > > > > > > > > hmap_init(&data->local_datapaths); > > > > > - sset_init(&data->local_lports); > > > > > + simap_init(&data->local_lports); > > > > > related_lports_init(&data->related_lports); > > > > > sset_init(&data->active_tunnels); > > > > > hmap_init(&data->qos_map); > > > > > @@ -1402,7 +1405,7 @@ en_runtime_data_cleanup(void *data) > > > > > { > > > > > struct ed_type_runtime_data *rt_data = data; > > > > > > > > > > - sset_destroy(&rt_data->local_lports); > > > > > + simap_destroy(&rt_data->local_lports); > > > > > related_lports_destroy(&rt_data->related_lports); > > > > > sset_destroy(&rt_data->active_tunnels); > > > > > destroy_qos_map(&rt_data->qos_map); > > > > > @@ -1516,7 +1519,7 @@ en_runtime_data_run(struct engine_node *node, > > void > > > > > *data) > > > > > struct hmap *local_datapaths = &rt_data->local_datapaths; > > > > > struct shash *local_active_ipv6_pd = > > > > > &rt_data->local_active_ports_ipv6_pd; > > > > > struct shash *local_active_ras = > > &rt_data->local_active_ports_ras; > > > > > - struct sset *local_lports = &rt_data->local_lports; > > > > > + struct simap *local_lports = &rt_data->local_lports; > > > > > struct sset *active_tunnels = &rt_data->active_tunnels; > > > > > > > > > > static bool first_run = true; > > > > > @@ -1528,13 +1531,13 @@ en_runtime_data_run(struct engine_node > > *node, void > > > > > *data) > > > > > shash_clear(local_active_ipv6_pd); > > > > > shash_clear(local_active_ras); > > > > > local_binding_data_destroy(&rt_data->lbinding_data); > > > > > - sset_destroy(local_lports); > > > > > + simap_destroy(local_lports); > > > > > related_lports_destroy(&rt_data->related_lports); > > > > > sset_destroy(active_tunnels); > > > > > destroy_qos_map(&rt_data->qos_map); > > > > > smap_destroy(&rt_data->local_iface_ids); > > > > > hmap_init(local_datapaths); > > > > > - sset_init(local_lports); > > > > > + simap_init(local_lports); > > > > > related_lports_init(&rt_data->related_lports); > > > > > sset_init(active_tunnels); > > > > > hmap_init(&rt_data->qos_map); > > > > > diff --git a/controller/physical.h b/controller/physical.h > > > > > index 1a126ce8d..77831e536 100644 > > > > > --- a/controller/physical.h > > > > > +++ b/controller/physical.h > > > > > @@ -60,7 +60,7 @@ struct physical_ctx { > > > > > const struct sset *active_tunnels; > > > > > const struct if_status_mgr *if_mgr; > > > > > struct hmap *local_datapaths; > > > > > - struct sset *local_lports; > > > > > + struct simap *local_lports; > > > > > const struct shash *ct_zones; > > > > > enum mf_field_id mff_ovn_geneve; > > > > > struct shash *local_bindings; > > > > > diff --git a/controller/route.h b/controller/route.h > > > > > index 5047ce202..15323d357 100644 > > > > > --- a/controller/route.h > > > > > +++ b/controller/route.h > > > > > @@ -37,7 +37,7 @@ struct route_ctx_in { > > > > > const char *dynamic_routing_port_mapping; > > > > > const struct sset *active_tunnels; > > > > > const struct hmap *local_datapaths; > > > > > - const struct sset *local_lports; > > > > > + const struct simap *local_lports; > > > > > struct shash *local_bindings; > > > > > }; > > > > > > > > > > -- > > > > > 2.43.0 > > > > > > > > > > > > > > > _______________________________________________ > > > > > dev mailing list > > > > > d...@openvswitch.org > > > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > > > > > > > > > > > [0] > > > > > > https://github.com/ovn-org/ovn/commit/9f052bdb2b969b13f8165d9bf465ec0852832750 > > > > > > > > Thanks, > > > > Ales > > > _______________________________________________ > > > dev mailing list > > > d...@openvswitch.org > > > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > > > > Regards, > Ales > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev