On Wed, Apr 30, 2025 at 7:54 AM Ales Musil <amu...@redhat.com> wrote:

> Replace several lists in the controller code with vectors. The change
> allows us to avoid small allocations just to keep to have the list
> reference. The vector can store elements directly and allocates in
> batches rather than one by one. This also simplifies the code to some
> extent.
>
> Signed-off-by: Ales Musil <amu...@redhat.com>
> Acked-by: Mark Michelson <mmich...@redhat.com>
> ---
> v4: Rebase on top of current main.
>     Add ack from Mark.
> v3: Rebase on top of current main.
> v2: Rebase on top of current main.
> ---
>  controller/binding.c                |  70 ++++------
>  controller/mirror.c                 |  60 ++++-----
>  controller/ofctrl-seqno.c           | 193 +++++++++++++---------------
>  controller/ofctrl-seqno.h           |  11 +-
>  controller/ovn-controller.c         |   2 +-
>  controller/physical.c               |  79 ++++--------
>  controller/route-exchange-netlink.c |  33 ++---
>  controller/route-exchange-netlink.h |   6 +-
>  controller/route-exchange.c         |  10 +-
>  controller/test-ofctrl-seqno.c      |  27 ++--
>  10 files changed, 204 insertions(+), 287 deletions(-)
>
> diff --git a/controller/binding.c b/controller/binding.c
> index 9aec6708f..f5091d2cf 100644
> --- a/controller/binding.c
> +++ b/controller/binding.c
> @@ -2168,16 +2168,14 @@ binding_run(struct binding_ctx_in *b_ctx_in,
> struct binding_ctx_out *b_ctx_out)
>          build_local_bindings(b_ctx_in, b_ctx_out);
>      }
>
> -    struct ovs_list localnet_lports =
> OVS_LIST_INITIALIZER(&localnet_lports);
> -    struct ovs_list external_lports =
> OVS_LIST_INITIALIZER(&external_lports);
> -    struct ovs_list multichassis_ports = OVS_LIST_INITIALIZER(
> -
> &multichassis_ports);
> -    struct ovs_list vtep_lports = OVS_LIST_INITIALIZER(&vtep_lports);
> -
> -    struct lport {
> -        struct ovs_list list_node;
> -        const struct sbrec_port_binding *pb;
> -    };
> +    struct vector localnet_lports =
> +        VECTOR_EMPTY_INITIALIZER(struct sbrec_port_binding *);
> +    struct vector external_lports =
> +        VECTOR_EMPTY_INITIALIZER(struct sbrec_port_binding *);
> +    struct vector multichassis_ports =
> +        VECTOR_EMPTY_INITIALIZER(struct sbrec_port_binding *);
> +    struct vector vtep_lports =
> +        VECTOR_EMPTY_INITIALIZER(struct sbrec_port_binding *);
>
>      /* Run through each binding record to see if it is resident on this
>       * chassis and update the binding accordingly.  This includes both
> @@ -2202,9 +2200,7 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct
> binding_ctx_out *b_ctx_out)
>
>          case LP_VTEP:
>              update_related_lport(pb, b_ctx_out);
> -            struct lport *vtep_lport = xmalloc(sizeof *vtep_lport);
> -            vtep_lport->pb = pb;
> -            ovs_list_push_back(&vtep_lports, &vtep_lport->list_node);
> +            vector_push(&vtep_lports, &pb);
>              break;
>
>          case LP_LOCALPORT:
> @@ -2214,11 +2210,7 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct
> binding_ctx_out *b_ctx_out)
>          case LP_VIF:
>              consider_vif_lport(pb, b_ctx_in, b_ctx_out, NULL);
>              if (pb->additional_chassis) {
> -                struct lport *multichassis_lport = xmalloc(
> -                    sizeof *multichassis_lport);
> -                multichassis_lport->pb = pb;
> -                ovs_list_push_back(&multichassis_ports,
> -                                   &multichassis_lport->list_node);
> +                vector_push(&multichassis_ports, &pb);
>              }
>              break;
>
> @@ -2248,17 +2240,12 @@ binding_run(struct binding_ctx_in *b_ctx_in,
> struct binding_ctx_out *b_ctx_out)
>
>          case LP_EXTERNAL:
>              consider_external_lport(pb, b_ctx_in, b_ctx_out);
> -            struct lport *ext_lport = xmalloc(sizeof *ext_lport);
> -            ext_lport->pb = pb;
> -            ovs_list_push_back(&external_lports, &ext_lport->list_node);
> +            vector_push(&external_lports, &pb);
>              break;
>
> -        case LP_LOCALNET: {
> -            struct lport *lnet_lport = xmalloc(sizeof *lnet_lport);
> -            lnet_lport->pb = pb;
> -            ovs_list_push_back(&localnet_lports, &lnet_lport->list_node);
> +        case LP_LOCALNET:
> +            vector_push(&localnet_lports, &pb);
>              break;
> -        }
>
>          case LP_REMOTE:
>              /* Remote ports are related, since we can have rules in the
> @@ -2283,41 +2270,36 @@ binding_run(struct binding_ctx_in *b_ctx_in,
> struct binding_ctx_out *b_ctx_out)
>      /* Run through each localnet lport list to see if it is a localnet
> port
>       * on local datapaths discovered from above loop, and handles it
>       * accordingly. */
> -    struct lport *lnet_lport;
> -    LIST_FOR_EACH_POP (lnet_lport, list_node, &localnet_lports) {
> -        consider_localnet_lport(lnet_lport->pb, b_ctx_out);
> -        update_ld_localnet_port(lnet_lport->pb, &bridge_mappings,
> +    VECTOR_FOR_EACH (&localnet_lports, pb) {
> +        consider_localnet_lport(pb, b_ctx_out);
> +        update_ld_localnet_port(pb, &bridge_mappings,
>                                  b_ctx_out->local_datapaths);
> -        free(lnet_lport);
>      }
> +    vector_destroy(&localnet_lports);
>
>      /* Run through external lport list to see if there are external ports
>       * on local datapaths discovered from above loop, and update the
>       * corresponding local datapath accordingly. */
> -    struct lport *ext_lport;
> -    LIST_FOR_EACH_POP (ext_lport, list_node, &external_lports) {
> -        update_ld_external_ports(ext_lport->pb,
> b_ctx_out->local_datapaths);
> -        free(ext_lport);
> +    VECTOR_FOR_EACH (&external_lports, pb) {
> +        update_ld_external_ports(pb, b_ctx_out->local_datapaths);
>      }
> +    vector_destroy(&external_lports);
>
>      /* Run through multichassis lport list to see if there are ports
>       * on local datapaths discovered from above loop, and update the
>       * corresponding local datapath accordingly. */
> -    struct lport *multichassis_lport;
> -    LIST_FOR_EACH_POP (multichassis_lport, list_node,
> &multichassis_ports) {
> -        update_ld_multichassis_ports(multichassis_lport->pb,
> -                                     b_ctx_out->local_datapaths);
> -        free(multichassis_lport);
> +    VECTOR_FOR_EACH (&multichassis_ports, pb) {
> +        update_ld_multichassis_ports(pb, b_ctx_out->local_datapaths);
>      }
> +    vector_destroy(&multichassis_ports);
>
>      /* Run through vtep lport list to see if there are vtep ports
>       * on local datapaths discovered from above loop, and update the
>       * corresponding local datapath accordingly. */
> -    struct lport *vtep_lport;
> -    LIST_FOR_EACH_POP (vtep_lport, list_node, &vtep_lports) {
> -        update_ld_vtep_port(vtep_lport->pb, b_ctx_out->local_datapaths);
> -        free(vtep_lport);
> +    VECTOR_FOR_EACH (&vtep_lports, pb) {
> +        update_ld_vtep_port(pb, b_ctx_out->local_datapaths);
>      }
> +    vector_destroy(&vtep_lports);
>
>      shash_destroy(&bridge_mappings);
>      /* Remove stale QoS entries. */
> diff --git a/controller/mirror.c b/controller/mirror.c
> index 2f1c811a0..62b4ac98a 100644
> --- a/controller/mirror.c
> +++ b/controller/mirror.c
> @@ -30,6 +30,7 @@
>  #include "binding.h"
>  #include "lib/ovn-sb-idl.h"
>  #include "mirror.h"
> +#include "vec.h"
>
>  VLOG_DEFINE_THIS_MODULE(port_mirror);
>
> @@ -37,14 +38,8 @@ struct ovn_mirror {
>      char *name;
>      const struct sbrec_mirror *sb_mirror;
>      const struct ovsrec_mirror *ovs_mirror;
> -    struct ovs_list mirror_src_lports;
> -    struct ovs_list mirror_dst_lports;
> -};
> -
> -struct mirror_lport {
> -    struct ovs_list list_node;
> -
> -    struct local_binding *lbinding;
> +    struct vector mirror_src_lports; /* Vector of struct local_binding *.
> */
> +    struct vector mirror_dst_lports; /* Vector of struct local_binding *.
> */
>  };
>
>  static struct ovn_mirror *ovn_mirror_create(char *mirror_name);
> @@ -238,8 +233,8 @@ ovn_mirror_create(char *mirror_name)
>  {
>      struct ovn_mirror *m = xzalloc(sizeof *m);
>      m->name = xstrdup(mirror_name);
> -    ovs_list_init(&m->mirror_src_lports);
> -    ovs_list_init(&m->mirror_dst_lports);
> +    m->mirror_src_lports = VECTOR_EMPTY_INITIALIZER(struct local_binding
> *);
> +    m->mirror_dst_lports = VECTOR_EMPTY_INITIALIZER(struct local_binding
> *);
>      return m;
>  }
>
> @@ -259,15 +254,8 @@ static void
>  ovn_mirror_delete(struct ovn_mirror *m)
>  {
>      free(m->name);
> -    struct mirror_lport *m_lport;
> -    LIST_FOR_EACH_POP (m_lport, list_node, &m->mirror_src_lports) {
> -        free(m_lport);
> -    }
> -
> -    LIST_FOR_EACH_POP (m_lport, list_node, &m->mirror_dst_lports) {
> -        free(m_lport);
> -    }
> -
> +    vector_destroy(&m->mirror_src_lports);
> +    vector_destroy(&m->mirror_dst_lports);
>      free(m);
>  }
>
> @@ -276,16 +264,12 @@ ovn_mirror_add_lport(struct ovn_mirror *m, struct
> local_binding *lbinding)
>  {
>      if (!strcmp(m->sb_mirror->filter, "from-lport") ||
>          !strcmp(m->sb_mirror->filter, "both")) {
> -        struct mirror_lport *m_lport = xzalloc(sizeof *m_lport);
> -        m_lport->lbinding = lbinding;
> -        ovs_list_push_back(&m->mirror_src_lports, &m_lport->list_node);
> +        vector_push(&m->mirror_src_lports, &lbinding);
>      }
>
>      if (!strcmp(m->sb_mirror->filter, "to-lport") ||
>          !strcmp(m->sb_mirror->filter, "both")) {
> -        struct mirror_lport *m_lport = xzalloc(sizeof *m_lport);
> -        m_lport->lbinding = lbinding;
> -        ovs_list_push_back(&m->mirror_dst_lports, &m_lport->list_node);
> +        vector_push(&m->mirror_dst_lports, &lbinding);
>      }
>  }
>
> @@ -350,8 +334,8 @@ sync_ovn_mirror(struct ovn_mirror *m, struct
> ovsdb_idl_txn *ovs_idl_txn,
>          return;
>      }
>
> -    if (ovs_list_is_empty(&m->mirror_src_lports) &&
> -            ovs_list_is_empty(&m->mirror_dst_lports)) {
> +    if (vector_is_empty(&m->mirror_src_lports) &&
> +        vector_is_empty(&m->mirror_dst_lports)) {
>          /* Nothing to do. */
>          return;
>      }
> @@ -399,8 +383,8 @@ should_delete_ovs_mirror(struct ovn_mirror *m)
>          return true;
>      }
>
> -    return (ovs_list_is_empty(&m->mirror_src_lports) &&
> -            ovs_list_is_empty(&m->mirror_dst_lports));
> +    return (vector_is_empty(&m->mirror_src_lports) &&
> +            vector_is_empty(&m->mirror_dst_lports));
>  }
>
>  static const struct ovsrec_port *
> @@ -474,18 +458,18 @@ create_ovs_mirror(struct ovn_mirror *m, struct
> ovsdb_idl_txn *ovs_idl_txn,
>  static void
>  sync_ovs_mirror_ports(struct ovn_mirror *m, const struct ovsrec_bridge
> *br_int)
>  {
> -    struct mirror_lport *m_lport;
> +    struct local_binding *lbinding;
>
> -    if (ovs_list_is_empty(&m->mirror_src_lports)) {
> +    if (vector_is_empty(&m->mirror_src_lports)) {
>          ovsrec_mirror_set_select_src_port(m->ovs_mirror, NULL, 0);
>      } else {
> -        size_t n_lports = ovs_list_size(&m->mirror_src_lports);
> +        size_t n_lports = vector_len(&m->mirror_src_lports);
>          struct ovsrec_port **ovs_ports = xmalloc(sizeof *ovs_ports *
> n_lports);
>
>          size_t i = 0;
> -        LIST_FOR_EACH (m_lport, list_node, &m->mirror_src_lports) {
> +        VECTOR_FOR_EACH (&m->mirror_src_lports, lbinding) {
>              const struct ovsrec_port *p =
> -                get_iface_port(m_lport->lbinding->iface, br_int);
> +                get_iface_port(lbinding->iface, br_int);
>              ovs_assert(p);
>              ovs_ports[i++] = (struct ovsrec_port *) p;
>          }
> @@ -494,16 +478,16 @@ sync_ovs_mirror_ports(struct ovn_mirror *m, const
> struct ovsrec_bridge *br_int)
>          free(ovs_ports);
>      }
>
> -    if (ovs_list_is_empty(&m->mirror_dst_lports)) {
> +    if (vector_is_empty(&m->mirror_dst_lports)) {
>          ovsrec_mirror_set_select_dst_port(m->ovs_mirror, NULL, 0);
>      } else {
> -        size_t n_lports = ovs_list_size(&m->mirror_dst_lports);
> +        size_t n_lports = vector_len(&m->mirror_dst_lports);
>          struct ovsrec_port **ovs_ports = xmalloc(sizeof *ovs_ports *
> n_lports);
>
>          size_t i = 0;
> -        LIST_FOR_EACH (m_lport, list_node, &m->mirror_dst_lports) {
> +        VECTOR_FOR_EACH (&m->mirror_dst_lports, lbinding) {
>              const struct ovsrec_port *p =
> -                get_iface_port(m_lport->lbinding->iface, br_int);
> +                get_iface_port(lbinding->iface, br_int);
>              ovs_assert(p);
>              ovs_ports[i++] = (struct ovsrec_port *) p;
>          }
> diff --git a/controller/ofctrl-seqno.c b/controller/ofctrl-seqno.c
> index 95373aa57..83c17c0e5 100644
> --- a/controller/ofctrl-seqno.c
> +++ b/controller/ofctrl-seqno.c
> @@ -19,13 +19,15 @@
>  #include "ofctrl-seqno.h"
>  #include "openvswitch/list.h"
>  #include "util.h"
> +#include "vec.h"
> +
> +#define VECTOR_THRESHOLD 1024
>
>  /* A sequence number update request, i.e., when the barrier corresponding
> to
>   * the 'flow_cfg' sequence number is replied to by OVS then it is safe
>   * to inform the application that the 'req_cfg' seqno has been processed.
>   */
>  struct ofctrl_seqno_update {
> -    struct ovs_list list_node; /* In 'ofctrl_seqno_updates'. */
>      size_t seqno_type;         /* Application specific seqno type.
>                                  * Relevant only for 'req_cfg'.
>                                  */
> @@ -37,14 +39,15 @@ struct ofctrl_seqno_update {
>  };
>
>  /* List of in flight sequence number updates. */
> -static struct ovs_list ofctrl_seqno_updates;
> +static struct vector ofctrl_seqno_updates =
> +    VECTOR_EMPTY_INITIALIZER(struct ofctrl_seqno_update);
>
>  /* Last sequence number request sent to OVS. */
>  static uint64_t ofctrl_req_seqno;
>
>  /* State of seqno requests for a given application seqno type. */
>  struct ofctrl_seqno_state {
> -    struct ovs_list acked_cfgs; /* Acked requests since the last time the
> +    struct vector acked_cfgs;   /* Acked requests since the last time the
>                                   * application consumed acked requests.
>                                   */
>      uint64_t cur_cfg;           /* Last acked application seqno. */
> @@ -52,20 +55,11 @@ struct ofctrl_seqno_state {
>  };
>
>  /* Per application seqno type states. */
> -static size_t n_ofctrl_seqno_states;
> -static struct ofctrl_seqno_state *ofctrl_seqno_states;
> -
> -/* ofctrl_acked_seqnos related static function prototypes. */
> -static void ofctrl_acked_seqnos_init(struct ofctrl_acked_seqnos *seqnos,
> -                                     uint64_t last_acked);
> -static void ofctrl_acked_seqnos_add(struct ofctrl_acked_seqnos *seqnos,
> -                                    uint64_t val);
> +static struct vector ofctrl_seqno_states =
> +    VECTOR_EMPTY_INITIALIZER(struct ofctrl_seqno_state);
>
> -/* ofctrl_seqno_update related static function prototypes. */
> -static void ofctrl_seqno_update_create__(size_t seqno_type, uint64_t
> req_cfg);
> -static void ofctrl_seqno_update_list_destroy(struct ovs_list *seqno_list);
> -static void ofctrl_seqno_cfg_run(size_t seqno_type,
> -                                 struct ofctrl_seqno_update *update);
> +/* ofctrl_seqno_state related static function prototypes. */
> +static struct ofctrl_seqno_state *ofctrl_seqno_state_get(size_t
> seqno_type);
>
>  /* Returns the collection of acked ofctrl_seqno_update requests of type
>   * 'seqno_type'.  It's the responsibility of the caller to free memory by
> @@ -74,17 +68,17 @@ static void ofctrl_seqno_cfg_run(size_t seqno_type,
>  struct ofctrl_acked_seqnos *
>  ofctrl_acked_seqnos_get(size_t seqno_type)
>  {
> -    struct ofctrl_acked_seqnos *acked_seqnos = xmalloc(sizeof
> *acked_seqnos);
> -    struct ofctrl_seqno_state *state = &ofctrl_seqno_states[seqno_type];
> -    struct ofctrl_seqno_update *update;
> +    struct ofctrl_seqno_state *state = ofctrl_seqno_state_get(seqno_type);
>
> -    ofctrl_acked_seqnos_init(acked_seqnos, state->cur_cfg);
> +    struct ofctrl_acked_seqnos *acked_seqnos = xmalloc(sizeof
> *acked_seqnos);
> +    acked_seqnos->acked = vector_clone(&state->acked_cfgs);
> +    acked_seqnos->last_acked = state->cur_cfg;
>
> -    ovs_assert(seqno_type < n_ofctrl_seqno_states);
> -    LIST_FOR_EACH_POP (update, list_node, &state->acked_cfgs) {
> -        ofctrl_acked_seqnos_add(acked_seqnos, update->req_cfg);
> -        free(update);
> +    vector_clear(&state->acked_cfgs);
> +    if (vector_capacity(&state->acked_cfgs) >= VECTOR_THRESHOLD) {
> +        vector_shrink_to_fit(&state->acked_cfgs);
>      }
> +
>      return acked_seqnos;
>  }
>
> @@ -95,11 +89,7 @@ ofctrl_acked_seqnos_destroy(struct ofctrl_acked_seqnos
> *seqnos)
>          return;
>      }
>
> -    struct ofctrl_ack_seqno *seqno_node;
> -    HMAP_FOR_EACH_POP (seqno_node, node, &seqnos->acked) {
> -        free(seqno_node);
> -    }
> -    hmap_destroy(&seqnos->acked);
> +    vector_destroy(&seqnos->acked);
>      free(seqnos);
>  }
>
> @@ -108,40 +98,52 @@ bool
>  ofctrl_acked_seqnos_contains(const struct ofctrl_acked_seqnos *seqnos,
>                               uint64_t val)
>  {
> -    struct ofctrl_ack_seqno *sn;
> +    if (vector_is_empty(&seqnos->acked)) {
> +        return false;
> +    }
> +
> +    size_t low = 0;
> +    size_t high = vector_len(&seqnos->acked) -1;
> +    uint64_t *acked = vector_get_array(&seqnos->acked);
>
> -    HMAP_FOR_EACH_WITH_HASH (sn, node, hash_uint64(val), &seqnos->acked) {
> -        if (sn->seqno == val) {
> +    while (low <= high) {
> +        size_t mid = low + (high - low) / 2;
> +
> +        if (acked[mid] == val) {
>              return true;
>          }
> +
> +        if (acked[mid] >= acked[low]) {
> +            if (val >= acked[low] && val < acked[mid]) {
> +                high = mid - 1;
> +            } else {
> +                low = mid + 1;
> +            }
> +        } else {
> +            if (val > acked[mid] && val <= acked[high]) {
> +                low = mid + 1;
> +            } else {
> +                high = mid - 1;
> +            }
> +        }
>      }
> -    return false;
> -}
>
> -void
> -ofctrl_seqno_init(void)
> -{
> -    ovs_list_init(&ofctrl_seqno_updates);
> +    return false;
>  }
>
>  /* Adds a new type of application specific seqno updates. */
>  size_t
>  ofctrl_seqno_add_type(void)
>  {
> -    size_t new_type = n_ofctrl_seqno_states;
> -    n_ofctrl_seqno_states++;
> -
> -    struct ofctrl_seqno_state *new_states =
> -        xzalloc(n_ofctrl_seqno_states * sizeof *new_states);
> +    size_t new_type = vector_len(&ofctrl_seqno_states);
>
> -    for (size_t i = 0; i < n_ofctrl_seqno_states - 1; i++) {
> -        ovs_list_move(&new_states[i].acked_cfgs,
> -                      &ofctrl_seqno_states[i].acked_cfgs);
> -    }
> -    ovs_list_init(&new_states[new_type].acked_cfgs);
> +    struct ofctrl_seqno_state state = (struct ofctrl_seqno_state) {
> +        .acked_cfgs = VECTOR_EMPTY_INITIALIZER(uint64_t),
> +        .cur_cfg = 0,
> +        .req_cfg = 0,
> +    };
> +    vector_push(&ofctrl_seqno_states, &state);
>
> -    free(ofctrl_seqno_states);
> -    ofctrl_seqno_states = new_states;
>      return new_type;
>  }
>
> @@ -151,9 +153,7 @@ ofctrl_seqno_add_type(void)
>  void
>  ofctrl_seqno_update_create(size_t seqno_type, uint64_t new_cfg)
>  {
> -    ovs_assert(seqno_type < n_ofctrl_seqno_states);
> -
> -    struct ofctrl_seqno_state *state = &ofctrl_seqno_states[seqno_type];
> +    struct ofctrl_seqno_state *state = ofctrl_seqno_state_get(seqno_type);
>
>      /* If new_cfg didn't change since the last request there should
> already
>       * be an update pending.
> @@ -163,7 +163,14 @@ ofctrl_seqno_update_create(size_t seqno_type,
> uint64_t new_cfg)
>      }
>
>      state->req_cfg = new_cfg;
> -    ofctrl_seqno_update_create__(seqno_type, new_cfg);
> +
> +    ofctrl_req_seqno++;
> +    struct ofctrl_seqno_update update = (struct ofctrl_seqno_update) {
> +        .seqno_type = seqno_type,
> +        .flow_cfg = ofctrl_req_seqno,
> +        .req_cfg = new_cfg,
> +    };
> +    vector_push(&ofctrl_seqno_updates, &update);
>  }
>
>  /* Should be called when the application is certain that all OVS flow
> updates
> @@ -173,14 +180,25 @@ ofctrl_seqno_update_create(size_t seqno_type,
> uint64_t new_cfg)
>  void
>  ofctrl_seqno_run(uint64_t flow_cfg)
>  {
> +    size_t index = 0;
> +
>      struct ofctrl_seqno_update *update;
> -    LIST_FOR_EACH_SAFE (update, list_node, &ofctrl_seqno_updates) {
> +    VECTOR_FOR_EACH_PTR (&ofctrl_seqno_updates, update) {
>          if (flow_cfg < update->flow_cfg) {
>              break;
>          }
> +        struct ofctrl_seqno_state *state =
> +            ofctrl_seqno_state_get(update->seqno_type);
> +        state->cur_cfg = update->req_cfg;
> +        vector_push(&state->acked_cfgs, &update->req_cfg);
> +
> +        index++;
> +    }
> +
> +    vector_remove_block(&ofctrl_seqno_updates, 0, index);
>
> -        ovs_list_remove(&update->list_node);
> -        ofctrl_seqno_cfg_run(update->seqno_type, update);
> +    if (vector_capacity(&ofctrl_seqno_updates) >= VECTOR_THRESHOLD) {
> +        vector_shrink_to_fit(&ofctrl_seqno_updates);
>      }
>  }
>
> @@ -197,58 +215,31 @@ ofctrl_seqno_get_req_cfg(void)
>  void
>  ofctrl_seqno_flush(void)
>  {
> -    for (size_t i = 0; i < n_ofctrl_seqno_states; i++) {
> -
> ofctrl_seqno_update_list_destroy(&ofctrl_seqno_states[i].acked_cfgs);
> -    }
> -    ofctrl_seqno_update_list_destroy(&ofctrl_seqno_updates);
> -    ofctrl_req_seqno = 0;
> -}
> -
> -static void
> -ofctrl_acked_seqnos_init(struct ofctrl_acked_seqnos *seqnos,
> -                         uint64_t last_acked)
> -{
> -    hmap_init(&seqnos->acked);
> -    seqnos->last_acked = last_acked;
> -}
> +    vector_clear(&ofctrl_seqno_updates);
>
> -static void
> -ofctrl_acked_seqnos_add(struct ofctrl_acked_seqnos *seqnos, uint64_t val)
> -{
> -    seqnos->last_acked = val;
> -
> -    struct ofctrl_ack_seqno *sn = xmalloc(sizeof *sn);
> -    hmap_insert(&seqnos->acked, &sn->node, hash_uint64(val));
> -    sn->seqno = val;
> -}
> -
> -static void
> -ofctrl_seqno_update_create__(size_t seqno_type, uint64_t req_cfg)
> -{
> -    struct ofctrl_seqno_update *update = xmalloc(sizeof *update);
> +    struct ofctrl_seqno_state *state;
> +    VECTOR_FOR_EACH_PTR (&ofctrl_seqno_states, state) {
> +        vector_clear(&state->acked_cfgs);
> +    }
>
> -    ofctrl_req_seqno++;
> -    ovs_list_push_back(&ofctrl_seqno_updates, &update->list_node);
> -    update->seqno_type = seqno_type;
> -    update->flow_cfg = ofctrl_req_seqno;
> -    update->req_cfg = req_cfg;
> +    ofctrl_req_seqno = 0;
>  }
>
> -static void
> -ofctrl_seqno_update_list_destroy(struct ovs_list *seqno_list)
> +void
> +ofctrl_seqno_destroy(void)
>  {
> -    struct ofctrl_seqno_update *update;
> +    vector_destroy(&ofctrl_seqno_updates);
>
> -    LIST_FOR_EACH_POP (update, list_node, seqno_list) {
> -        free(update);
> +    struct ofctrl_seqno_state *state;
> +    VECTOR_FOR_EACH_PTR (&ofctrl_seqno_states, state) {
> +        vector_destroy(&state->acked_cfgs);
>      }
> +    vector_destroy(&ofctrl_seqno_states);
>  }
>
> -static void
> -ofctrl_seqno_cfg_run(size_t seqno_type, struct ofctrl_seqno_update
> *update)
> +static struct ofctrl_seqno_state *
> +ofctrl_seqno_state_get(size_t seqno_type)
>  {
> -    ovs_assert(seqno_type < n_ofctrl_seqno_states);
> -    ovs_list_push_back(&ofctrl_seqno_states[seqno_type].acked_cfgs,
> -                       &update->list_node);
> -    ofctrl_seqno_states[seqno_type].cur_cfg = update->req_cfg;
> +    ovs_assert(seqno_type < vector_len(&ofctrl_seqno_states));
> +    return vector_get_ptr(&ofctrl_seqno_states, seqno_type);
>  }
> diff --git a/controller/ofctrl-seqno.h b/controller/ofctrl-seqno.h
> index adcc5a0d3..faa97cc53 100644
> --- a/controller/ofctrl-seqno.h
> +++ b/controller/ofctrl-seqno.h
> @@ -19,31 +19,26 @@
>  #include <stdint.h>
>
>  #include <openvswitch/hmap.h>
> +#include "vec.h"
>
>  /* Collection of acked ofctrl_seqno_update requests and the most recent
>   * 'last_acked' value.
>   */
>  struct ofctrl_acked_seqnos {
> -    struct hmap acked;
> +    struct vector acked;
>      uint64_t last_acked;
>  };
>
> -/* Acked application specific seqno.  Stored in
> ofctrl_acked_seqnos.acked. */
> -struct ofctrl_ack_seqno {
> -    struct hmap_node node;
> -    uint64_t seqno;
> -};
> -
>  struct ofctrl_acked_seqnos *ofctrl_acked_seqnos_get(size_t seqno_type);
>  void ofctrl_acked_seqnos_destroy(struct ofctrl_acked_seqnos *seqnos);
>  bool ofctrl_acked_seqnos_contains(const struct ofctrl_acked_seqnos
> *seqnos,
>                                    uint64_t val);
>
> -void ofctrl_seqno_init(void);
>  size_t ofctrl_seqno_add_type(void);
>  void ofctrl_seqno_update_create(size_t seqno_type, uint64_t new_cfg);
>  void ofctrl_seqno_run(uint64_t flow_cfg);
>  uint64_t ofctrl_seqno_get_req_cfg(void);
>  void ofctrl_seqno_flush(void);
> +void ofctrl_seqno_destroy(void);
>
>  #endif /* controller/ofctrl-seqno.h */
> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> index 180b8a8d2..1cf5bb45f 100644
> --- a/controller/ovn-controller.c
> +++ b/controller/ovn-controller.c
> @@ -5926,7 +5926,6 @@ main(int argc, char *argv[])
>
>      ofctrl_init(&lflow_output_data->group_table,
>                  &lflow_output_data->meter_table);
> -    ofctrl_seqno_init();
>
>      unixctl_command_register("group-table-list", "", 0, 0,
>                               extend_table_list,
> @@ -6640,6 +6639,7 @@ loop_done:
>      free(ovn_version);
>      lflow_destroy();
>      ofctrl_destroy();
> +    ofctrl_seqno_destroy();
>      pinctrl_destroy();
>      binding_destroy();
>      patch_destroy();
> diff --git a/controller/physical.c b/controller/physical.c
> index a17d792c3..65b4c7335 100644
> --- a/controller/physical.c
> +++ b/controller/physical.c
> @@ -64,11 +64,6 @@ struct zone_ids {
>      int snat;                   /* MFF_LOG_SNAT_ZONE. */
>  };
>
> -struct tunnel {
> -    struct ovs_list list_node;
> -    const struct chassis_tunnel *tun;
> -};
> -
>  static void
>  load_logical_ingress_metadata(const struct sbrec_port_binding *binding,
>                                const struct zone_ids *zone_ids,
> @@ -415,16 +410,14 @@ find_additional_encap_for_chassis(const struct
> sbrec_port_binding *pb,
>      return NULL;
>  }
>
> -static struct ovs_list *
> +static struct vector
>  get_remote_tunnels(const struct sbrec_port_binding *binding,
>                     const struct physical_ctx *ctx,
>                     const char *local_encap_ip)
>  {
> +    struct vector tunnels =
> +        VECTOR_EMPTY_INITIALIZER(const struct chassis_tunnel *);
>      const struct chassis_tunnel *tun;
> -
> -    struct ovs_list *tunnels = xmalloc(sizeof *tunnels);
> -    ovs_list_init(tunnels);
> -
>      if (binding->chassis && binding->chassis != ctx->chassis) {
>          tun = get_port_binding_tun(binding->encap, binding->chassis,
>                  ctx->chassis_tunnels, local_encap_ip);
> @@ -435,9 +428,7 @@ get_remote_tunnels(const struct sbrec_port_binding
> *binding,
>                       "for port %s.",
>                  binding->chassis->name, binding->logical_port);
>          } else {
> -            struct tunnel *tun_elem = xmalloc(sizeof *tun_elem);
> -            tun_elem->tun = tun;
> -            ovs_list_push_back(tunnels, &tun_elem->list_node);
> +            vector_push(&tunnels, &tun);
>          }
>      }
>
> @@ -459,9 +450,7 @@ get_remote_tunnels(const struct sbrec_port_binding
> *binding,
>                  binding->additional_chassis[i]->name,
> binding->logical_port);
>              continue;
>          }
> -        struct tunnel *tun_elem = xmalloc(sizeof *tun_elem);
> -        tun_elem->tun = tun;
> -        ovs_list_push_back(tunnels, &tun_elem->list_node);
> +        vector_push(&tunnels, &tun);
>      }
>      return tunnels;
>  }
> @@ -482,8 +471,8 @@ put_remote_port_redirect_overlay(const struct
> sbrec_port_binding *binding,
>
>          match_set_reg_masked(match, MFF_LOG_ENCAP_ID - MFF_REG0, i << 16,
>                               (uint32_t) 0xFFFF << 16);
> -        struct ovs_list *tuns = get_remote_tunnels(binding, ctx,
> encap_ip);
> -        if (!ovs_list_is_empty(tuns)) {
> +        struct vector tuns = get_remote_tunnels(binding, ctx, encap_ip);
> +        if (!vector_is_empty(&tuns)) {
>              bool is_vtep_port = type == LP_VTEP;
>              /* rewrite MFF_IN_PORT to bypass OpenFlow loopback check for
> ARP/ND
>               * responder in L3 networks. */
> @@ -492,24 +481,18 @@ put_remote_port_redirect_overlay(const struct
> sbrec_port_binding *binding,
>                           ofpacts_clone);
>              }
>
> -            struct tunnel *tun;
> -            LIST_FOR_EACH (tun, list_node, tuns) {
> -                put_encapsulation(ctx->mff_ovn_geneve, tun->tun,
> -                                  binding->datapath, port_key,
> is_vtep_port,
> -                                  ofpacts_clone);
> -                ofpact_put_OUTPUT(ofpacts_clone)->port = tun->tun->ofport;
> +            const struct chassis_tunnel *tun;
> +            VECTOR_FOR_EACH (&tuns, tun) {
> +                put_encapsulation(ctx->mff_ovn_geneve, tun,
> binding->datapath,
> +                                  port_key, is_vtep_port, ofpacts_clone);
> +                ofpact_put_OUTPUT(ofpacts_clone)->port = tun->ofport;
>              }
>              put_resubmit(OFTABLE_LOCAL_OUTPUT, ofpacts_clone);
>              ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 100,
>                              binding->header_.uuid.parts[0], match,
>                              ofpacts_clone, &binding->header_.uuid);
>          }
> -        struct tunnel *tun_elem;
> -        LIST_FOR_EACH_POP (tun_elem, list_node, tuns) {
> -            free(tun_elem);
> -        }
> -        free(tuns);
> -
> +        vector_destroy(&tuns);
>          ofpbuf_delete(ofpacts_clone);
>      }
>  }
> @@ -1612,7 +1595,7 @@ get_tunnel_overhead(struct chassis_tunnel const *tun)
>
>  static uint16_t
>  get_effective_mtu(const struct sbrec_port_binding *mcp,
> -                  struct ovs_list *remote_tunnels,
> +                  struct vector *remote_tunnels,
>                    const struct if_status_mgr *if_mgr)
>  {
>      /* Use interface MTU as a base for calculation */
> @@ -1624,9 +1607,9 @@ get_effective_mtu(const struct sbrec_port_binding
> *mcp,
>
>      /* Iterate over all peer tunnels and find the biggest tunnel overhead
> */
>      uint16_t overhead = 0;
> -    struct tunnel *tun;
> -    LIST_FOR_EACH (tun, list_node, remote_tunnels) {
> -        overhead = MAX(overhead, get_tunnel_overhead(tun->tun));
> +    const struct chassis_tunnel *tun;
> +    VECTOR_FOR_EACH (remote_tunnels, tun) {
> +        overhead = MAX(overhead, get_tunnel_overhead(tun));
>      }
>      if (!overhead) {
>          return 0;
> @@ -1656,7 +1639,7 @@ handle_pkt_too_big_for_ip_version(struct
> ovn_desired_flow_table *flow_table,
>
>  static void
>  handle_pkt_too_big(struct ovn_desired_flow_table *flow_table,
> -                   struct ovs_list *remote_tunnels,
> +                   struct vector *remote_tunnels,
>                     const struct sbrec_port_binding *binding,
>                     const struct sbrec_port_binding *mcp,
>                     const struct if_status_mgr *if_mgr)
> @@ -1681,9 +1664,9 @@ enforce_tunneling_for_multichassis_ports(
>          return;
>      }
>
> -    struct ovs_list *tuns = get_remote_tunnels(binding, ctx, NULL);
> -    if (ovs_list_is_empty(tuns)) {
> -        free(tuns);
> +    struct vector tuns = get_remote_tunnels(binding, ctx, NULL);
> +    if (vector_is_empty(&tuns)) {
> +        vector_destroy(&tuns);
>          return;
>      }
>
> @@ -1708,26 +1691,20 @@ enforce_tunneling_for_multichassis_ports(
>          match_outport_dp_and_port_keys(&match, dp_key, port_key);
>          match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, mcp->tunnel_key);
>
> -        struct tunnel *tun;
> -        LIST_FOR_EACH (tun, list_node, tuns) {
> -            put_encapsulation(ctx->mff_ovn_geneve, tun->tun,
> -                              binding->datapath, port_key, is_vtep_port,
> -                              &ofpacts);
> -            ofpact_put_OUTPUT(&ofpacts)->port = tun->tun->ofport;
> +        const struct chassis_tunnel *tun;
> +        VECTOR_FOR_EACH (&tuns, tun) {
> +            put_encapsulation(ctx->mff_ovn_geneve, tun, binding->datapath,
> +                              port_key, is_vtep_port, &ofpacts);
> +            ofpact_put_OUTPUT(&ofpacts)->port = tun->ofport;
>          }
>          ofctrl_add_flow(flow_table, OFTABLE_REMOTE_OUTPUT, 110,
>                          binding->header_.uuid.parts[0], &match, &ofpacts,
>                          &binding->header_.uuid);
>          ofpbuf_uninit(&ofpacts);
>
> -        handle_pkt_too_big(flow_table, tuns, binding, mcp, ctx->if_mgr);
> -    }
> -
> -    struct tunnel *tun_elem;
> -    LIST_FOR_EACH_POP (tun_elem, list_node, tuns) {
> -        free(tun_elem);
> +        handle_pkt_too_big(flow_table, &tuns, binding, mcp, ctx->if_mgr);
>      }
> -    free(tuns);
> +    vector_destroy(&tuns);
>  }
>
>  static void
> diff --git a/controller/route-exchange-netlink.c
> b/controller/route-exchange-netlink.c
> index ad0c25989..83deb13e6 100644
> --- a/controller/route-exchange-netlink.c
> +++ b/controller/route-exchange-netlink.c
> @@ -31,6 +31,7 @@
>  #include "ovn-util.h"
>  #include "route-table.h"
>  #include "route.h"
> +#include "vec.h"
>
>  #include "route-exchange-netlink.h"
>
> @@ -188,19 +189,10 @@ re_nl_delete_route(uint32_t table_id, const struct
> in6_addr *dst,
>      return modify_route(RTM_DELROUTE, 0, table_id, dst, plen, priority);
>  }
>
> -void
> -re_nl_learned_routes_destroy(struct ovs_list *learned_routes)
> -{
> -    struct re_nl_received_route_node *rr;
> -    LIST_FOR_EACH_POP (rr, list_node, learned_routes) {
> -        free(rr);
> -    }
> -}
> -
>  struct route_msg_handle_data {
>      const struct sbrec_datapath_binding *db;
>      struct hmapx *routes_to_advertise;
> -    struct ovs_list *learned_routes;
> +    struct vector *learned_routes;
>      const struct hmap *routes;
>  };
>
> @@ -227,14 +219,17 @@ handle_route_msg(const struct route_table_msg *msg,
> void *data)
>                   * As we just want to learn remote routes we do not need
> it.*/
>                  continue;
>              }
> -            struct re_nl_received_route_node *rr = xmalloc(sizeof *rr);
> -            rr->db = handle_data->db;
> -            rr->prefix = rd->rta_dst;
> -            rr->plen = rd->rtm_dst_len;
> -            rr->nexthop = nexthop->addr;
> -            memcpy(rr->ifname, nexthop->ifname, IFNAMSIZ);
> -            rr->ifname[IFNAMSIZ] = 0;
> -            ovs_list_push_back(handle_data->learned_routes,
> &rr->list_node);
> +            struct re_nl_received_route_node rr;
> +            rr = (struct re_nl_received_route_node) {
> +                .db = handle_data->db,
> +                .prefix = rd->rta_dst,
> +                .plen = rd->rtm_dst_len,
> +                .nexthop = nexthop->addr,
> +            };
> +            memcpy(rr.ifname, nexthop->ifname, IFNAMSIZ);
> +            rr.ifname[IFNAMSIZ] = '\0';
> +
> +            vector_push(handle_data->learned_routes, &rr);
>          }
>          return;
>      }
> @@ -266,7 +261,7 @@ handle_route_msg(const struct route_table_msg *msg,
> void *data)
>
>  void
>  re_nl_sync_routes(uint32_t table_id, const struct hmap *routes,
> -                  struct ovs_list *learned_routes,
> +                  struct vector *learned_routes,
>                    const struct sbrec_datapath_binding *db)
>  {
>      struct hmapx routes_to_advertise =
> HMAPX_INITIALIZER(&routes_to_advertise);
> diff --git a/controller/route-exchange-netlink.h
> b/controller/route-exchange-netlink.h
> index de59d87a5..e37cfe711 100644
> --- a/controller/route-exchange-netlink.h
> +++ b/controller/route-exchange-netlink.h
> @@ -19,7 +19,6 @@
>  #define ROUTE_EXCHANGE_NETLINK_H 1
>
>  #include <stdint.h>
> -#include "openvswitch/list.h"
>  #include <netinet/in.h>
>  #include <net/if.h>
>
> @@ -31,10 +30,10 @@
>
>  struct in6_addr;
>  struct hmap;
> +struct vector;
>
>  struct re_nl_received_route_node {
>      const struct sbrec_datapath_binding *db;
> -    struct ovs_list list_node;
>      struct in6_addr prefix;
>      unsigned int plen;
>      struct in6_addr nexthop;
> @@ -52,9 +51,8 @@ int re_nl_delete_route(uint32_t table_id, const struct
> in6_addr *dst,
>
>  void re_nl_dump(uint32_t table_id);
>
> -void re_nl_learned_routes_destroy(struct ovs_list *learned_routes);
>  void re_nl_sync_routes(uint32_t table_id, const struct hmap *routes,
> -                       struct ovs_list *learned_routes,
> +                       struct vector *learned_routes,
>                         const struct sbrec_datapath_binding *db);
>
>  void re_nl_cleanup_routes(uint32_t table_id);
> diff --git a/controller/route-exchange.c b/controller/route-exchange.c
> index 98ce93d43..79a046f60 100644
> --- a/controller/route-exchange.c
> +++ b/controller/route-exchange.c
> @@ -132,7 +132,7 @@ route_lookup(struct hmap *route_map,
>  }
>
>  static void
> -sb_sync_learned_routes(const struct ovs_list *learned_routes,
> +sb_sync_learned_routes(const struct vector *learned_routes,
>                         const struct sbrec_datapath_binding *datapath,
>                         const struct smap *bound_ports,
>                         struct ovsdb_idl_txn *ovnsb_idl_txn,
> @@ -160,7 +160,7 @@ sb_sync_learned_routes(const struct ovs_list
> *learned_routes,
>      sbrec_learned_route_index_destroy_row(filter);
>
>      struct re_nl_received_route_node *learned_route;
> -    LIST_FOR_EACH (learned_route, list_node, learned_routes) {
> +    VECTOR_FOR_EACH_PTR (learned_routes, learned_route) {
>          char *ip_prefix = normalize_v46_prefix(&learned_route->prefix,
>                                                 learned_route->plen);
>          char *nexthop = normalize_v46(&learned_route->nexthop);
> @@ -240,8 +240,8 @@ route_exchange_run(const struct route_exchange_ctx_in
> *r_ctx_in,
>
>          maintained_route_table_add(table_id);
>
> -        struct ovs_list received_routes =
> -            OVS_LIST_INITIALIZER(&received_routes);
> +        struct vector received_routes =
> +            VECTOR_EMPTY_INITIALIZER(struct re_nl_received_route_node);
>
>          re_nl_sync_routes(ad->db->tunnel_key, &ad->routes,
>                            &received_routes, ad->db);
> @@ -254,7 +254,7 @@ route_exchange_run(const struct route_exchange_ctx_in
> *r_ctx_in,
>          route_table_add_watch_request(&r_ctx_out->route_table_watches,
>                                        table_id);
>
> -        re_nl_learned_routes_destroy(&received_routes);
> +        vector_destroy(&received_routes);
>      }
>
>      /* Remove routes in tables previously maintained by us. */
> diff --git a/controller/test-ofctrl-seqno.c
> b/controller/test-ofctrl-seqno.c
> index cd3821e04..7d478c033 100644
> --- a/controller/test-ofctrl-seqno.c
> +++ b/controller/test-ofctrl-seqno.c
> @@ -22,12 +22,6 @@
>
>  #include "ofctrl-seqno.h"
>
> -static void
> -test_init(void)
> -{
> -    ofctrl_seqno_init();
> -}
> -
>  static int
>  test_seqno_compare(size_t a, size_t b, void *values_)
>  {
> @@ -55,20 +49,20 @@ test_dump_acked_seqnos(size_t seqno_type)
>      printf("ofctrl-seqno-type: %"PRIuSIZE"\n", seqno_type);
>      printf("  last-acked %"PRIu64"\n", acked_seqnos->last_acked);
>
> -    size_t n_acked = hmap_count(&acked_seqnos->acked);
> +    size_t n_acked = vector_len(&acked_seqnos->acked);
>      uint64_t *acked = xmalloc(n_acked * sizeof *acked);
> -    struct ofctrl_ack_seqno *ack_seqno;
>      size_t i = 0;
>
>      /* A bit hacky but ignoring overflows the "total of all seqno + 1"
> should
>       * be a number that is not part of the acked seqnos.
>       */
>      uint64_t total_seqno = 1;
> -    HMAP_FOR_EACH (ack_seqno, node, &acked_seqnos->acked) {
> -        ovs_assert(ofctrl_acked_seqnos_contains(acked_seqnos,
> -                                                ack_seqno->seqno));
> -        total_seqno += ack_seqno->seqno;
> -        acked[i++] = ack_seqno->seqno;
> +
> +    uint64_t ack_seqno;
> +    VECTOR_FOR_EACH (&acked_seqnos->acked, ack_seqno) {
> +        ovs_assert(ofctrl_acked_seqnos_contains(acked_seqnos, ack_seqno));
> +        total_seqno += ack_seqno;
> +        acked[i++] = ack_seqno;
>      }
>      ovs_assert(!ofctrl_acked_seqnos_contains(acked_seqnos, total_seqno));
>
> @@ -87,14 +81,14 @@ test_ofctrl_seqno_add_type(struct ovs_cmdl_context
> *ctx)
>  {
>      unsigned int n_types;
>
> -    test_init();
> -
>      if (!test_read_uint_value(ctx, 1, "n_types", &n_types)) {
>          return;
>      }
>      for (unsigned int i = 0; i < n_types; i++) {
>          printf("%"PRIuSIZE"\n", ofctrl_seqno_add_type());
>      }
> +
> +    ofctrl_seqno_destroy();
>  }
>
>  static void
> @@ -105,7 +99,6 @@ test_ofctrl_seqno_ack_seqnos(struct ovs_cmdl_context
> *ctx)
>      unsigned int n_types;
>      unsigned int n_acks;
>
> -    test_init();
>      bool batch_acks = !strcmp(ctx->argv[1], "true");
>
>      if (!test_read_uint_value(ctx, shift++, "n_types", &n_types)) {
> @@ -157,6 +150,8 @@ test_ofctrl_seqno_ack_seqnos(struct ovs_cmdl_context
> *ctx)
>              test_dump_acked_seqnos(st);
>          }
>      }
> +
> +    ofctrl_seqno_destroy();
>  }
>
>  static void
> --
> 2.49.0
>
>
Recheck-request: github-robot
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to