On Thu, Apr 24, 2025 at 10:33:52AM +0200, Ales Musil wrote:
> On Mon, Apr 14, 2025 at 1:37 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.
> >
> > This means we can also get rid of workarounds in testcases that where
> > introduced in 9f052bdb because of this problem.
> >
> > Signed-off-by: Felix Huettner <felix.huettner@stackit.cloud>
> > ---
> >
> 
> Hi Felix,
> 
> there is only one nit that can be addressed during merge.

Hi Ales,

since i need a new version anyway i will include it in there.

> 
> v6->v7:
> >   * introduced
> >   * addressed review comments
> >
> >  controller/binding.c        | 33 ++++++++++++++++++++++++---------
> >  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 +-
> >  tests/ovn.at                | 21 ---------------------
> >  8 files changed, 60 insertions(+), 48 deletions(-)
> >
> > diff --git a/controller/binding.c b/controller/binding.c
> > index 470aa8c53..f0cc84a50 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,
> > @@ -1893,6 +1902,10 @@ consider_localport(const struct sbrec_port_binding
> > *pb,
> >          remove_related_lport(pb, b_ctx_out);
> >      }
> >
> > +    /* Add all localnet ports to local_ifaces so that we allocate ct zones
> > +     * for them. */
> > +    update_local_lports(pb->logical_port, b_ctx_out, LPORT_STATUS_BOUND);
> > +
> >      update_related_lport(pb, b_ctx_out);
> >      return true;
> >  }
> > @@ -1911,7 +1924,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 +2030,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 +2131,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 +2413,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;
> > @@ -2427,6 +2440,8 @@ consider_iface_claim(const struct ovsrec_interface
> > *iface_rec,
> >          pb = b_lport->pb;
> >      }
> >
> > +    update_local_lports(iface_id, b_ctx_out, pb ? LPORT_STATUS_BOUND :
> > +                        LPORT_STATUS_NOT_BOUND);
> >      if (!pb) {
> >          /* There is no port_binding row for this local binding. */
> >          return true;
> > 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))) {
> >
> 
> nit: Indentation
> 
> +                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 4dfb426f9..4e1623163 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
> > @@ -1291,8 +1293,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).
> > @@ -1396,7 +1399,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);
> > @@ -1416,7 +1419,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);
> > @@ -1530,7 +1533,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;
> > @@ -1542,13 +1545,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;
> >  };
> >
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index cf8cdce3a..fb68abbd1 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -15772,16 +15772,6 @@ echo $request >> hv3/third.expected
> >
> >  check_packets
> >
> > -# ct_zone allocation differs between I+P and recompute:
> > -# - In I+P an ovs interface with external-ids:iface-id set (but no
> > -#   logical_port in sb) results in no ct_zone allocated.
> > -# - In recompute, in the same case, a ct_zone is allocated - this is
> > -#   necessary to avoid flushing ct_zone if/when controller is restarted.
> > -# As migrrator has iface-id set on hv1 but is bound to hv2, we would hit
> > -# some ct-zone related differences in flows before and after recompute.
> > -# Avoid/hide this by removing iface-id on hv1.
> > -
> > -as hv1 check ovs-vsctl remove Interface migrator external-ids iface-id
> >  OVN_CLEANUP([hv1],[hv2],[hv3])
> >
> >  AT_CLEANUP
> > @@ -16172,11 +16162,6 @@ echo $request >> hv2/n1.expected
> >
> >  check_packets
> >
> > -# ct_zone allocation differs between I+P and recompute.
> > -# As migrrator has iface-id set on hv1 but is bound to hv2, we would hit
> > -# some ct-zone related differences in flows before and after recompute.
> > -# Avoid/hide this by removing iface-id on hv1.
> > -as hv1 check ovs-vsctl remove Interface migrator external-ids iface-id
> >  OVN_CLEANUP([hv1],[hv2],[hv3])
> >
> >  AT_CLEANUP
> > @@ -16733,12 +16718,6 @@ m4_define([ACTIVATION_STRATEGY_TEST],
> >      check ovn-nbctl lsp-set-options migrator requested-chassis=hv2
> >      OVS_WAIT_UNTIL([test x = x$(ovn-sbctl get Port_Binding $pb_uuid
> > options:additional-chassis-activated)])
> >
> > -    # ct_zone allocation differs between I+P and recompute.
> > -    # As migrrator has iface-id set on hv1 but is bound to hv2, we would
> > hit
> > -    # some ct-zone related differences in flows before and after
> > recompute.
> > -    # Avoid/hide this by removing iface-id on hv1.
> > -    as hv1 check ovs-vsctl remove Interface migrator external-ids iface-id
> > -
> >      OVN_CLEANUP([hv1],[hv2],[hv3])
> >
> >      AT_CLEANUP
> > --
> > 2.43.0
> >
> >
> > _______________________________________________
> > dev mailing list
> > d...@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
> >
> Other than that it looks good:
> Acked-by: Ales Musil <amu...@redhat.com>

Thanks a lot,
Felix

> 
> Thanks,
> Ales
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to