On 4/28/25 05:34, Ales Musil via dev wrote:
The vector has the same functionality as the x2nrealloc
for insert. Use vector instead which slightly simplifies
the final code. There is one exception that wasn't converted
that's the expr_constant_set.

Signed-off-by: Ales Musil <amu...@redhat.com>
---
v3: Rebase on top of current main.
v2: Rebase on top of current main.
---
  controller/lflow.c          |  17 +++--
  controller/ovn-controller.c |   9 ++-
  include/ovn/expr.h          |   4 +-
  lib/actions.c               | 115 ++++++++++++++--------------------
  lib/expr.c                  |  56 ++++++++---------
  lib/inc-proc-eng.c          | 120 ++++++++++++++++--------------------
  lib/lb.c                    |  49 ++++++---------
  lib/lb.h                    |   4 +-
  northd/lb.c                 |   7 ++-
  northd/northd.c             |  44 +++++++------
  tests/test-ovn.c            |   3 +-
  11 files changed, 187 insertions(+), 241 deletions(-)

diff --git a/controller/lflow.c b/controller/lflow.c
index c24b2e212..0a3bf1c1c 100644
--- a/controller/lflow.c
+++ b/controller/lflow.c
@@ -925,7 +925,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow 
*lflow,
              .ip = m->as_ip,
              .mask = m->as_mask
          };
-        if (!m->n) {
+        if (vector_is_empty(&m->conjunctions)) {
              ofctrl_add_flow_metered(l_ctx_out->flow_table, ptable,
                                      lflow->priority,
                                      lflow->header_.uuid.parts[0], &m->match,
@@ -933,18 +933,16 @@ add_matches_to_flow_table(const struct sbrec_logical_flow 
*lflow,
                                      ctrl_meter_id,
                                      as_info.name ? &as_info : NULL);
          } else {
-            if (m->n > 1) {
+            if (vector_len(&m->conjunctions) > 1) {
                  ovs_assert(!as_info.name);
              }
              uint64_t conj_stubs[64 / 8];
              struct ofpbuf conj;
ofpbuf_use_stub(&conj, conj_stubs, sizeof conj_stubs);
-            for (int i = 0; i < m->n; i++) {
-                const struct cls_conjunction *src = &m->conjunctions[i];
-                struct ofpact_conjunction *dst;
-
-                dst = ofpact_put_CONJUNCTION(&conj);
+            const struct cls_conjunction *src;
+            VECTOR_FOR_EACH_PTR (&m->conjunctions, src) {
+                struct ofpact_conjunction *dst = ofpact_put_CONJUNCTION(&conj);
                  dst->id = src->id;
                  dst->clause = src->clause;
                  dst->n_clauses = src->n_clauses;
@@ -1941,9 +1939,8 @@ consider_lb_hairpin_flows(const struct ovn_controller_lb 
*lb,
      for (size_t i = 0; i < lb->n_vips; i++) {
          struct ovn_lb_vip *lb_vip = &lb->vips[i];
- for (size_t j = 0; j < lb_vip->n_backends; j++) {
-            struct ovn_lb_backend *lb_backend = &lb_vip->backends[j];
-
+        struct ovn_lb_backend *lb_backend;
+        VECTOR_FOR_EACH_PTR (&lb_vip->backends, lb_backend) {
              add_lb_vip_hairpin_flows(lb, lb_vip, lb_backend, flow_table,
                                       register_consolidation);
          }
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index 13cf1a503..a0c142329 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -2683,9 +2683,9 @@ lb_data_removed_five_tuples_add(struct ed_type_lb_data 
*lb_data,
for (size_t i = 0; i < lb->n_vips; i++) {
          struct ovn_lb_vip *vip = &lb->vips[i];
-        for (size_t j = 0; j < vip->n_backends; j++) {
-            struct ovn_lb_backend *backend = &vip->backends[j];
+ const struct ovn_lb_backend *backend;
+        VECTOR_FOR_EACH_PTR (&vip->backends, backend) {
              ovn_lb_5tuple_add(&lb_data->removed_tuples, vip, backend,
                                lb->proto);
          }
@@ -2703,10 +2703,9 @@ lb_data_removed_five_tuples_remove(struct 
ed_type_lb_data *lb_data,
for (size_t i = 0; i < lb->n_vips; i++) {
          struct ovn_lb_vip *vip = &lb->vips[i];
-        for (size_t j = 0; j < vip->n_backends; j++) {
-            struct ovn_lb_backend *backend = &vip->backends[j];
-
+ const struct ovn_lb_backend *backend;
+        VECTOR_FOR_EACH_PTR (&vip->backends, backend) {
              struct ovn_lb_5tuple tuple;
              ovn_lb_5tuple_init(&tuple, vip, backend, lb->proto);
              ovn_lb_5tuple_find_and_delete(&lb_data->removed_tuples, &tuple);
diff --git a/include/ovn/expr.h b/include/ovn/expr.h
index e54edb5bf..9621a2c09 100644
--- a/include/ovn/expr.h
+++ b/include/ovn/expr.h
@@ -60,6 +60,7 @@
  #include "openvswitch/meta-flow.h"
  #include "logical-fields.h"
  #include "smap.h"
+#include "vec.h"
struct ds;
  struct expr;
@@ -471,8 +472,7 @@ bool expr_evaluate(const struct expr *, const struct flow 
*uflow,
  struct expr_match {
      struct hmap_node hmap_node;
      struct match match;
-    struct cls_conjunction *conjunctions;
-    size_t n, allocated;
+    struct vector conjunctions; /* Vector of struct cls_conjunction. */
/* Tracked address set information. */
      char *as_name;
diff --git a/lib/actions.c b/lib/actions.c
index f6f413be2..967fca426 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -42,6 +42,7 @@
  #include "socket-util.h"
  #include "lib/ovn-util.h"
  #include "controller/lflow.h"
+#include "vec.h"
VLOG_DEFINE_THIS_MODULE(actions);
  
@@ -1208,9 +1209,7 @@ parse_ct_lb_action(struct action_context *ctx, bool 
ct_lb_mark)
add_prerequisite(ctx, "ip"); - struct ovnact_ct_lb_dst *dsts = NULL;
-    size_t allocated_dsts = 0;
-    size_t n_dsts = 0;
+    struct vector dsts = VECTOR_EMPTY_INITIALIZER(struct ovnact_ct_lb_dst);
      char *hash_fields = NULL;
      enum ovnact_ct_lb_flag ct_flag = OVNACT_CT_LB_FLAG_NONE;
@@ -1229,7 +1228,7 @@ parse_ct_lb_action(struct action_context *ctx, bool ct_lb_mark)
                  /* IPv6 address and port */
                  if (ctx->lexer->token.type != LEX_T_INTEGER
                      || ctx->lexer->token.format != LEX_F_IPV6) {
-                    free(dsts);
+                    vector_destroy(&dsts);
                      lexer_syntax_error(ctx->lexer, "expecting IPv6 address");
                      return;
                  }
@@ -1238,7 +1237,7 @@ parse_ct_lb_action(struct action_context *ctx, bool 
ct_lb_mark)
lexer_get(ctx->lexer);
                  if (!lexer_match(ctx->lexer, LEX_T_RSQUARE)) {
-                    free(dsts);
+                    vector_destroy(&dsts);
                      lexer_syntax_error(ctx->lexer, "no closing square "
                                                     "bracket");
                      return;
@@ -1246,14 +1245,14 @@ parse_ct_lb_action(struct action_context *ctx, bool 
ct_lb_mark)
                  dst.port = 0;
                  if (lexer_match(ctx->lexer, LEX_T_COLON)
                      && !action_parse_uint16(ctx, &dst.port, "port number")) {
-                    free(dsts);
+                    vector_destroy(&dsts);
                      return;
                  }
              } else {
                  if (ctx->lexer->token.type != LEX_T_INTEGER
                      || (ctx->lexer->token.format != LEX_F_IPV4
                      && ctx->lexer->token.format != LEX_F_IPV6)) {
-                    free(dsts);
+                    vector_destroy(&dsts);
                      lexer_syntax_error(ctx->lexer, "expecting IP address");
                      return;
                  }
@@ -1271,31 +1270,27 @@ parse_ct_lb_action(struct action_context *ctx, bool 
ct_lb_mark)
                  dst.port = 0;
                  if (lexer_match(ctx->lexer, LEX_T_COLON)) {
                      if (dst.family == AF_INET6) {
-                        free(dsts);
+                        vector_destroy(&dsts);;
                          lexer_syntax_error(ctx->lexer, "IPv6 address needs "
                                  "square brackets if port is included");
                          return;
                      } else if (!action_parse_uint16(ctx, &dst.port,
                                                      "port number")) {
-                        free(dsts);
+                        vector_destroy(&dsts);
                          return;
                      }
                  }
              }
              lexer_match(ctx->lexer, LEX_T_COMMA);
- /* Append to dsts. */
-            if (n_dsts >= allocated_dsts) {
-                dsts = x2nrealloc(dsts, &allocated_dsts, sizeof *dsts);
-            }
-            dsts[n_dsts++] = dst;
+            vector_push(&dsts, &dst);
          }
if (lexer_match_id(ctx->lexer, "hash_fields")) {
              if (!lexer_match(ctx->lexer, LEX_T_EQUALS) ||
                  ctx->lexer->token.type != LEX_T_STRING) {
                  lexer_syntax_error(ctx->lexer, "invalid hash_fields");
-                free(dsts);
+                vector_destroy(&dsts);
                  return;
              }
@@ -1318,8 +1313,8 @@ parse_ct_lb_action(struct action_context *ctx, bool ct_lb_mark)
      struct ovnact_ct_lb *cl = ct_lb_mark ? ovnact_put_CT_LB_MARK(ctx->ovnacts)
                                           : ovnact_put_CT_LB(ctx->ovnacts);
      cl->ltable = ctx->pp->cur_ltable + 1;
-    cl->dsts = dsts;
-    cl->n_dsts = n_dsts;
+    cl->n_dsts = vector_len(&dsts);
+    cl->dsts = vector_steal_array(&dsts);
      cl->hash_fields = hash_fields;
      cl->ct_flag = ct_flag;
  }
@@ -1542,9 +1537,7 @@ parse_select_action(struct action_context *ctx, struct 
expr_field *res_field)
          return;
      }
- struct ovnact_select_dst *dsts = NULL;
-    size_t allocated_dsts = 0;
-    size_t n_dsts = 0;
+    struct vector dsts = VECTOR_EMPTY_INITIALIZER(struct ovnact_select_dst);
      bool requires_hash_fields = false;
      char *hash_fields = NULL;
@@ -1560,14 +1553,14 @@ parse_select_action(struct action_context *ctx, struct expr_field *res_field)
      while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
          struct ovnact_select_dst dst;
          if (!action_parse_uint16(ctx, &dst.id, "id")) {
-            free(dsts);
+            vector_destroy(&dsts);
              return;
          }
dst.weight = 0;
          if (lexer_match(ctx->lexer, LEX_T_EQUALS)) {
              if (!action_parse_uint16(ctx, &dst.weight, "weight")) {
-                free(dsts);
+                vector_destroy(&dsts);
                  return;
              }
              if (dst.weight == 0) {
@@ -1581,15 +1574,11 @@ parse_select_action(struct action_context *ctx, struct 
expr_field *res_field)
lexer_match(ctx->lexer, LEX_T_COMMA); - /* Append to dsts. */
-        if (n_dsts >= allocated_dsts) {
-            dsts = x2nrealloc(dsts, &allocated_dsts, sizeof *dsts);
-        }
-        dsts[n_dsts++] = dst;
+        vector_push(&dsts, &dst);
      }
-    if (n_dsts <= 1) {
+    if (vector_len(&dsts) <= 1) {
          lexer_syntax_error(ctx->lexer, "expecting at least 2 group members");
-        free(dsts);
+        vector_destroy(&dsts);
          return;
      }
@@ -1597,14 +1586,14 @@ parse_select_action(struct action_context *ctx, struct expr_field *res_field)
          lexer_force_match(ctx->lexer, LEX_T_SEMICOLON);
          if (!lexer_match_id(ctx->lexer, "hash_fields")) {
              lexer_syntax_error(ctx->lexer, "expecting hash_fields");
-            free(dsts);
+            vector_destroy(&dsts);
              return;
          }
          if (!lexer_match(ctx->lexer, LEX_T_EQUALS) ||
              ctx->lexer->token.type != LEX_T_STRING ||
              lexer_lookahead(ctx->lexer) != LEX_T_RPAREN) {
              lexer_syntax_error(ctx->lexer, "invalid hash_fields");
-            free(dsts);
+            vector_destroy(&dsts);
              return;
          }
          hash_fields = xstrdup(ctx->lexer->token.s);
@@ -1614,8 +1603,8 @@ parse_select_action(struct action_context *ctx, struct 
expr_field *res_field)
struct ovnact_select *select = ovnact_put_SELECT(ctx->ovnacts);
      select->ltable = ctx->pp->cur_ltable + 1;
-    select->dsts = dsts;
-    select->n_dsts = n_dsts;
+    select->n_dsts = vector_len(&dsts);
+    select->dsts = vector_steal_array(&dsts);
      select->res_field = *res_field;
      select->hash_fields = hash_fields;
  }
@@ -2681,26 +2670,23 @@ parse_trigger_event(struct action_context *ctx,
lexer_match(ctx->lexer, LEX_T_COMMA); - size_t allocated_options = 0;
+    struct vector options = VECTOR_EMPTY_INITIALIZER(struct ovnact_gen_option);
      while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
-        if (event->n_options >= allocated_options) {
-            event->options = x2nrealloc(event->options, &allocated_options,
-                                     sizeof *event->options);
-        }
-
-        struct ovnact_gen_option *o = &event->options[event->n_options++];
-        memset(o, 0, sizeof *o);
-        parse_gen_opt(ctx, o,
+        struct ovnact_gen_option o = {0};
+        parse_gen_opt(ctx, &o,
                        &ctx->pp->controller_event_opts->event_opts[event_type],
                        event_to_string(event_type));
+        vector_push(&options, &o);
if (ctx->lexer->error) {
              return;
          }
-
          lexer_match(ctx->lexer, LEX_T_COMMA);
      }
+ event->n_options = vector_len(&options);
+    event->options = vector_steal_array(&options);
+
      switch (event_type) {
      case OVN_EVENT_EMPTY_LB_BACKENDS:
          validate_empty_lb_backends(ctx, event->options, event->n_options);
@@ -2838,22 +2824,21 @@ parse_put_opts(struct action_context *ctx, const struct 
expr_field *dst,
      }
      po->dst = *dst;
- size_t allocated_options = 0;
+    struct vector options = VECTOR_EMPTY_INITIALIZER(struct ovnact_gen_option);
      while (!lexer_match(ctx->lexer, LEX_T_RPAREN)) {
-        if (po->n_options >= allocated_options) {
-            po->options = x2nrealloc(po->options, &allocated_options,
-                                     sizeof *po->options);
-        }
+        struct ovnact_gen_option o = {0};
+        parse_gen_opt(ctx, &o, gen_opts, opts_type);
+        vector_push(&options, &o);
- struct ovnact_gen_option *o = &po->options[po->n_options++];
-        memset(o, 0, sizeof *o);
-        parse_gen_opt(ctx, o, gen_opts, opts_type);
          if (ctx->lexer->error) {
-            return;
+            break;
          }
lexer_match(ctx->lexer, LEX_T_COMMA);
      }
+
+    po->n_options = vector_len(&options);
+    po->options = vector_steal_array(&options);
  }
/* Parses the "put_dhcp_opts" and "put_dhcpv6_opts" actions.
@@ -4134,9 +4119,8 @@ ovnact_handle_svc_check_free(struct 
ovnact_handle_svc_check *sc OVS_UNUSED)
  static void
  parse_fwd_group_action(struct action_context *ctx)
  {
-    char *child_port, **child_port_list = NULL;
-    size_t allocated_ports = 0;
-    size_t n_child_ports = 0;
+    struct vector child_port_list = VECTOR_EMPTY_INITIALIZER(char *);
+    char *child_port = NULL;
      bool liveness = false;
if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
@@ -4165,25 +4149,18 @@ parse_fwd_group_action(struct action_context *ctx)
                  if (ctx->lexer->token.type != LEX_T_STRING) {
                      lexer_syntax_error(ctx->lexer,
                                         "expecting logical switch port");
-                    if (child_port_list) {
-                        for (int i = 0; i < n_child_ports; i++) {
-                            free(child_port_list[i]);
-                        }
-                        free(child_port_list);
+                    char *port;
+                    VECTOR_FOR_EACH (&child_port_list, port) {
+                            free(port);
                      }
+                    vector_destroy(&child_port_list);
                      return;
                  }
                  /* Parse child's logical ports */
                  child_port = xstrdup(ctx->lexer->token.s);
                  lexer_get(ctx->lexer);
                  lexer_match(ctx->lexer, LEX_T_COMMA);
-
-                if (n_child_ports >= allocated_ports) {
-                    child_port_list = x2nrealloc(child_port_list,
-                                                 &allocated_ports,
-                                                 sizeof *child_port_list);
-                }
-                child_port_list[n_child_ports++] = child_port;
+                vector_push(&child_port_list, &child_port);
              }
          }
      }
@@ -4191,8 +4168,8 @@ parse_fwd_group_action(struct action_context *ctx)
      struct ovnact_fwd_group *fwd_group = ovnact_put_FWD_GROUP(ctx->ovnacts);
      fwd_group->ltable = ctx->pp->cur_ltable + 1;
      fwd_group->liveness = liveness;
-    fwd_group->child_ports = child_port_list;
-    fwd_group->n_child_ports = n_child_ports;
+    fwd_group->n_child_ports = vector_len(&child_port_list);
+    fwd_group->child_ports = vector_steal_array(&child_port_list);
  }
static void
diff --git a/lib/expr.c b/lib/expr.c
index ecf8a6338..937fecb75 100644
--- a/lib/expr.c
+++ b/lib/expr.c
@@ -3141,16 +3141,16 @@ expr_match_new(const struct match *m, uint8_t clause, 
uint8_t n_clauses,
          match_init_catchall(&match->match);
      }
      if (conj_id) {
-        match->conjunctions = xmalloc(sizeof *match->conjunctions);
-        match->conjunctions[0].id = conj_id;
-        match->conjunctions[0].clause = clause;
-        match->conjunctions[0].n_clauses = n_clauses;
-        match->n = 1;
-        match->allocated = 1;
+        match->conjunctions =
+            VECTOR_CAPACITY_INITIALIZER(struct cls_conjunction, 1);
+        struct cls_conjunction conj = (struct cls_conjunction) {
+            .id = conj_id,
+            .clause = clause,
+            .n_clauses = n_clauses,
+        };
+        vector_push(&match->conjunctions, &conj);
      } else {
-        match->conjunctions = NULL;
-        match->n = 0;
-        match->allocated = 0;
+        match->conjunctions = VECTOR_EMPTY_INITIALIZER(struct cls_conjunction);
      }
      return match;
  }
@@ -3159,7 +3159,7 @@ void
  expr_match_destroy(struct expr_match *match)
  {
      free(match->as_name);
-    free(match->conjunctions);
+    vector_destroy(&match->conjunctions);
      free(match);
  }
@@ -3176,19 +3176,13 @@ expr_match_add(struct hmap *matches, struct expr_match *match) HMAP_FOR_EACH_WITH_HASH (m, hmap_node, hash, matches) {
          if (match_equal(&m->match, &match->match)) {
-            if (!m->n || !match->n) {
-                free(m->conjunctions);
-                m->conjunctions = NULL;
-                m->n = 0;
-                m->allocated = 0;
+            if (vector_is_empty(&m->conjunctions) ||
+                vector_is_empty(&match->conjunctions)) {
+                vector_destroy(&m->conjunctions);
              } else {
-                ovs_assert(match->n == 1);
-                if (m->n >= m->allocated) {
-                    m->conjunctions = x2nrealloc(m->conjunctions,
-                                                 &m->allocated,
-                                                 sizeof *m->conjunctions);
-                }
-                m->conjunctions[m->n++] = match->conjunctions[0];
+                ovs_assert(vector_len(&match->conjunctions) == 1);
+                vector_push(&m->conjunctions,
+                            vector_get_ptr(&match->conjunctions, 0));

Having a look at this code more closely, I think there is a potential for dangling pointers. I think the same problem exists in current code, too.

The problem is that just below this, we call expr_match_destroy(match). That results in calling vector_destroy(match->conjunctions) (in current code, it results in free(match->conjunctions)). When expr_match_add() returns, the last element of m->conjunctions points to freed memory.

              }
              if (m->as_name) {
                  /* m is combined with match. so untracked the address set. */
@@ -3461,11 +3455,11 @@ expr_matches_prepare(struct hmap *matches, uint32_t 
conj_id_ofs)
              m->match.flow.conj_id += conj_id_ofs;
          }
- for (size_t i = 0; i < m->n; i++) {
-            struct cls_conjunction *src = &m->conjunctions[i];
+        struct cls_conjunction *src;
+        VECTOR_FOR_EACH_PTR (&m->conjunctions, src) {
              src->id += conj_id_ofs;
          }
-        total_size += sizeof *m + m->allocated * sizeof *m->conjunctions;
+        total_size += sizeof *m + vector_memory_usage(&m->conjunctions);
      }
      return total_size;
  }
@@ -3503,12 +3497,12 @@ expr_matches_print(const struct hmap *matches, FILE 
*stream)
          fputs(s, stream);
          free(s);
- if (m->n) {
-            for (int i = 0; i < m->n; i++) {
-                const struct cls_conjunction *c = &m->conjunctions[i];
-                fprintf(stream, "%c conjunction(%"PRIu32", %d/%d)",
-                        i == 0 ? ':' : ',', c->id, c->clause, c->n_clauses);
-            }
+        bool first = true;
+        struct cls_conjunction *c;
+        VECTOR_FOR_EACH_PTR (&m->conjunctions, c) {
+            fprintf(stream, "%c conjunction(%"PRIu32", %d/%d)",
+                    first ? ':' : ',', c->id, c->clause, c->n_clauses);
+            first = false;
          }
          putc('\n', stream);
      }
diff --git a/lib/inc-proc-eng.c b/lib/inc-proc-eng.c
index 56dc62c4f..c410af5cd 100644
--- a/lib/inc-proc-eng.c
+++ b/lib/inc-proc-eng.c
@@ -30,6 +30,7 @@
  #include "inc-proc-eng.h"
  #include "timeval.h"
  #include "unixctl.h"
+#include "vec.h"
VLOG_DEFINE_THIS_MODULE(inc_proc_eng); @@ -37,8 +38,8 @@ static bool engine_force_recompute = false;
  static bool engine_run_canceled = false;
  static const struct engine_context *engine_context;
-static struct engine_node **engine_nodes;
-static size_t engine_n_nodes;
+static struct vector engine_nodes =
+    VECTOR_EMPTY_INITIALIZER(struct engine_node *);
static const char *engine_node_state_name[EN_STATE_MAX] = {
      [EN_STALE]     = "Stale",
@@ -93,50 +94,32 @@ engine_set_context(const struct engine_context *ctx)
  /* Builds the topologically sorted 'sorted_nodes' array starting from
   * 'node'.
   */
-static struct engine_node **
-engine_topo_sort(struct engine_node *node, struct engine_node **sorted_nodes,
-                 size_t *n_count, size_t *n_size)
+static void
+engine_topo_sort(struct engine_node *node, struct vector *sorted_nodes)
  {
      /* It's not so efficient to walk the array of already sorted nodes but
       * we know that sorting is done only once at startup so it's ok for now.
       */
-    for (size_t i = 0; i < *n_count; i++) {
-        if (sorted_nodes[i] == node) {
-            return sorted_nodes;
+    struct engine_node *sorted_node;
+    VECTOR_FOR_EACH (sorted_nodes, sorted_node) {
+        if (sorted_node == node) {
+            return;
          }
      }
for (size_t i = 0; i < node->n_inputs; i++) {
-        sorted_nodes = engine_topo_sort(node->inputs[i].node, sorted_nodes,
-                                        n_count, n_size);
-    }
-    if (*n_count == *n_size) {
-        sorted_nodes = x2nrealloc(sorted_nodes, n_size, sizeof *sorted_nodes);
+        engine_topo_sort(node->inputs[i].node, sorted_nodes);
      }
-    sorted_nodes[(*n_count)] = node;
-    (*n_count)++;
-    return sorted_nodes;
-}
-/* Return the array of topologically sorted nodes when starting from
- * 'node'. Stores the number of nodes in 'n_count'.
- */
-static struct engine_node **
-engine_get_nodes(struct engine_node *node, size_t *n_count)
-{
-    size_t n_size = 0;
-
-    *n_count = 0;
-    return engine_topo_sort(node, NULL, n_count, &n_size);
+    vector_push(sorted_nodes, &node);
  }
static void
  engine_clear_stats(struct unixctl_conn *conn, int argc OVS_UNUSED,
                     const char *argv[] OVS_UNUSED, void *arg OVS_UNUSED)
  {
-    for (size_t i = 0; i < engine_n_nodes; i++) {
-        struct engine_node *node = engine_nodes[i];
-
+    struct engine_node *node;
+    VECTOR_FOR_EACH (&engine_nodes, node) {
          memset(&node->stats, 0, sizeof node->stats);
      }
      unixctl_command_reply(conn, NULL);
@@ -150,9 +133,8 @@ engine_dump_stats(struct unixctl_conn *conn, int argc,
      const char *dump_eng_node_name = (argc > 1 ? argv[1] : NULL);
      const char *dump_stat_type = (argc > 2 ? argv[2] : NULL);
- for (size_t i = 0; i < engine_n_nodes; i++) {
-        struct engine_node *node = engine_nodes[i];
-
+    struct engine_node *node;
+    VECTOR_FOR_EACH (&engine_nodes, node) {
          if (dump_eng_node_name && strcmp(node->name, dump_eng_node_name)) {
              continue;
          }
@@ -213,14 +195,14 @@ engine_set_log_timeout_cmd(struct unixctl_conn *conn, int 
argc OVS_UNUSED,
  void
  engine_init(struct engine_node *node, struct engine_arg *arg)
  {
-    engine_nodes = engine_get_nodes(node, &engine_n_nodes);
+    engine_topo_sort(node, &engine_nodes);
- for (size_t i = 0; i < engine_n_nodes; i++) {
-        if (engine_nodes[i]->init) {
-            engine_nodes[i]->data =
-                engine_nodes[i]->init(engine_nodes[i], arg);
+    struct engine_node *sorted_node;
+    VECTOR_FOR_EACH (&engine_nodes, sorted_node) {
+        if (sorted_node->init) {
+            sorted_node->data = sorted_node->init(sorted_node, arg);
          } else {
-            engine_nodes[i]->data = NULL;
+            sorted_node->data = NULL;
          }
      }
@@ -237,19 +219,18 @@ engine_init(struct engine_node *node, struct engine_arg *arg)
  void
  engine_cleanup(void)
  {
-    for (size_t i = 0; i < engine_n_nodes; i++) {
-        if (engine_nodes[i]->clear_tracked_data) {
-            engine_nodes[i]->clear_tracked_data(engine_nodes[i]->data);
+    struct engine_node *node;
+    VECTOR_FOR_EACH (&engine_nodes, node) {
+        if (node->clear_tracked_data) {
+            node->clear_tracked_data(node->data);
          }
- if (engine_nodes[i]->cleanup) {
-            engine_nodes[i]->cleanup(engine_nodes[i]->data);
+        if (node->cleanup) {
+            node->cleanup(node->data);
          }
-        free(engine_nodes[i]->data);
+        free(node->data);
      }
-    free(engine_nodes);
-    engine_nodes = NULL;
-    engine_n_nodes = 0;
+    vector_destroy(&engine_nodes);
  }
struct engine_node *
@@ -346,8 +327,9 @@ engine_node_changed(struct engine_node *node)
  bool
  engine_has_run(void)
  {
-    for (size_t i = 0; i < engine_n_nodes; i++) {
-        if (engine_nodes[i]->state != EN_STALE) {
+    struct engine_node *node;
+    VECTOR_FOR_EACH (&engine_nodes, node) {
+        if (node->state != EN_STALE) {
              return true;
          }
      }
@@ -357,8 +339,9 @@ engine_has_run(void)
  bool
  engine_has_updated(void)
  {
-    for (size_t i = 0; i < engine_n_nodes; i++) {
-        if (engine_nodes[i]->state == EN_UPDATED) {
+    struct engine_node *node;
+    VECTOR_FOR_EACH (&engine_nodes, node) {
+        if (node->state == EN_UPDATED) {
              return true;
          }
      }
@@ -390,11 +373,12 @@ void
  engine_init_run(void)
  {
      VLOG_DBG("Initializing new run");
-    for (size_t i = 0; i < engine_n_nodes; i++) {
-        engine_set_node_state(engine_nodes[i], EN_STALE);
+    struct engine_node *node;
+    VECTOR_FOR_EACH (&engine_nodes, node) {
+        engine_set_node_state(node, EN_STALE);
- if (engine_nodes[i]->clear_tracked_data) {
-            engine_nodes[i]->clear_tracked_data(engine_nodes[i]->data);
+        if (node->clear_tracked_data) {
+            node->clear_tracked_data(node->data);
          }
      }
  }
@@ -539,11 +523,12 @@ engine_run(bool recompute_allowed)
      }
engine_run_canceled = false;
-    for (size_t i = 0; i < engine_n_nodes; i++) {
-        engine_run_node(engine_nodes[i], recompute_allowed);
+    struct engine_node *node;
+    VECTOR_FOR_EACH (&engine_nodes, node) {
+        engine_run_node(node, recompute_allowed);
- if (engine_nodes[i]->state == EN_CANCELED) {
-            engine_nodes[i]->stats.cancel++;
+        if (node->state == EN_CANCELED) {
+            node->stats.cancel++;
              engine_run_canceled = true;
              return;
          }
@@ -553,17 +538,18 @@ engine_run(bool recompute_allowed)
  bool
  engine_need_run(void)
  {
-    for (size_t i = 0; i < engine_n_nodes; i++) {
+    struct engine_node *node;
+    VECTOR_FOR_EACH (&engine_nodes, node) {
          /* Check only leaf nodes for updates. */
-        if (engine_nodes[i]->n_inputs) {
+        if (node->n_inputs) {
              continue;
          }
- engine_nodes[i]->run(engine_nodes[i], engine_nodes[i]->data);
-        engine_nodes[i]->stats.recompute++;
-        VLOG_DBG("input node: %s, state: %s", engine_nodes[i]->name,
-                 engine_node_state_name[engine_nodes[i]->state]);
-        if (engine_nodes[i]->state == EN_UPDATED) {
+        node->run(node, node->data);
+        node->stats.recompute++;
+        VLOG_DBG("input node: %s, state: %s", node->name,
+                 engine_node_state_name[node->state]);
+        if (node->state == EN_UPDATED) {
              return true;
          }
      }
diff --git a/lib/lb.c b/lib/lb.c
index 6e7a4e296..cd234adb8 100644
--- a/lib/lb.c
+++ b/lib/lb.c
@@ -77,27 +77,20 @@ static char *
  ovn_lb_backends_init_explicit(struct ovn_lb_vip *lb_vip, const char *value)
  {
      struct ds errors = DS_EMPTY_INITIALIZER;
-    size_t n_allocated_backends = 0;
      char *tokstr = xstrdup(value);
      char *save_ptr = NULL;
-    lb_vip->n_backends = 0;
+    lb_vip->backends = VECTOR_EMPTY_INITIALIZER(struct ovn_lb_backend);
for (char *token = strtok_r(tokstr, ",", &save_ptr);
          token != NULL;
          token = strtok_r(NULL, ",", &save_ptr)) {
- if (lb_vip->n_backends == n_allocated_backends) {
-            lb_vip->backends = x2nrealloc(lb_vip->backends,
-                                          &n_allocated_backends,
-                                          sizeof *lb_vip->backends);
-        }
-
-        struct ovn_lb_backend *backend = &lb_vip->backends[lb_vip->n_backends];
-        if (!ovn_lb_backend_init_explicit(lb_vip, backend, token, &errors)) {
+        struct ovn_lb_backend backend = {0};
+        if (!ovn_lb_backend_init_explicit(lb_vip, &backend, token, &errors)) {
              continue;
          }
- lb_vip->n_backends++;
+        vector_push(&lb_vip->backends, &backend);
      }
      free(tokstr);
@@ -190,31 +183,25 @@ ovn_lb_backends_init_template(struct ovn_lb_vip *lb_vip, const char *value_)
      struct ds errors = DS_EMPTY_INITIALIZER;
      char *value = xstrdup(value_);
      char *save_ptr = NULL;
-    size_t n_allocated_backends = 0;
-    lb_vip->n_backends = 0;
+    lb_vip->backends = VECTOR_EMPTY_INITIALIZER(struct ovn_lb_backend);
for (char *token = strtok_r(value, ",", &save_ptr); token;
           token = strtok_r(NULL, ",", &save_ptr)) {
- if (lb_vip->n_backends == n_allocated_backends) {
-            lb_vip->backends = x2nrealloc(lb_vip->backends,
-                                          &n_allocated_backends,
-                                          sizeof *lb_vip->backends);
-        }
- struct ovn_lb_backend *backend = &lb_vip->backends[lb_vip->n_backends];
+        struct ovn_lb_backend backend = {0};
          if (token[0] && token[0] == '^') {
-            if (!ovn_lb_backend_init_template(backend, token, &errors)) {
+            if (!ovn_lb_backend_init_template(&backend, token, &errors)) {
                  continue;
              }
          } else {
-            if (!ovn_lb_backend_init_explicit(lb_vip, backend,
+            if (!ovn_lb_backend_init_explicit(lb_vip, &backend,
                                                token, &errors)) {
                  continue;
              }
          }
- lb_vip->n_backends++;
+        vector_push(&lb_vip->backends, &backend);
      }
free(value);
@@ -292,11 +279,12 @@ ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char 
*lb_key,
  static void
  ovn_lb_backends_destroy(struct ovn_lb_vip *vip)
  {
-    for (size_t i = 0; i < vip->n_backends; i++) {
-        free(vip->backends[i].ip_str);
-        free(vip->backends[i].port_str);
+    struct ovn_lb_backend *backend;
+    VECTOR_FOR_EACH_PTR (&vip->backends, backend) {
+        free(backend->ip_str);
+        free(backend->port_str);
      }
-    free(vip->backends);
+    vector_destroy(&vip->backends);
  }
void
@@ -334,8 +322,8 @@ ovn_lb_vip_format(const struct ovn_lb_vip *vip, struct ds 
*s, bool template)
  void
  ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, struct ds *s)
  {
-    for (size_t i = 0; i < vip->n_backends; i++) {
-        struct ovn_lb_backend *backend = &vip->backends[i];
+    const struct ovn_lb_backend *backend;
+    VECTOR_FOR_EACH_PTR (&vip->backends, backend) {
          bool needs_brackets = vip->address_family == AF_INET6 &&
                                vip->port_str &&
                                !ipv6_addr_equals(&backend->ip, &in6addr_any);
@@ -349,10 +337,9 @@ ovn_lb_vip_backends_format(const struct ovn_lb_vip *vip, 
struct ds *s)
          if (backend->port_str) {
              ds_put_format(s, ":%s", backend->port_str);
          }
-        if (i != vip->n_backends - 1) {
-            ds_put_char(s, ',');
-        }
+        ds_put_char(s, ',');
      }
+    ds_chomp(s, ',');
  }
/* Formats the VIP in the way the ovn-controller expects it, that is,
diff --git a/lib/lb.h b/lib/lb.h
index b1a89d63c..ce5ad3580 100644
--- a/lib/lb.h
+++ b/lib/lb.h
@@ -24,6 +24,7 @@
  #include "ovn-util.h"
  #include "sset.h"
  #include "uuid.h"
+#include "vec.h"
struct uuid; @@ -37,8 +38,7 @@ struct ovn_lb_vip {
                            * in ovn-northd.
                            */
      bool template_vips;  /* True if the vips are templates. */
-    struct ovn_lb_backend *backends;
-    size_t n_backends;
+    struct vector backends; /* Vector of struct ovn_lb_backend. */
bool empty_backend_rej;
      int address_family;
diff --git a/northd/lb.c b/northd/lb.c
index af0c92954..ffd21c5bc 100644
--- a/northd/lb.c
+++ b/northd/lb.c
@@ -93,7 +93,7 @@ void ovn_northd_lb_vip_init(struct ovn_northd_lb_vip 
*lb_vip_nb,
                              bool template)
  {
      lb_vip_nb->backend_ips = xstrdup(backend_ips);
-    lb_vip_nb->n_backends = lb_vip->n_backends;
+    lb_vip_nb->n_backends = vector_len(&lb_vip->backends);
      lb_vip_nb->backends_nb = xcalloc(lb_vip_nb->n_backends,
                                       sizeof *lb_vip_nb->backends_nb);
      lb_vip_nb->lb_health_check =
@@ -107,8 +107,9 @@ ovn_lb_vip_backends_health_check_init(const struct 
ovn_northd_lb *lb,
  {
      struct ds key = DS_EMPTY_INITIALIZER;
- for (size_t j = 0; j < lb_vip->n_backends; j++) {
-        struct ovn_lb_backend *backend = &lb_vip->backends[j];
+    for (size_t j = 0; j < vector_len(&lb_vip->backends); j++) {
+        const struct ovn_lb_backend *backend =
+            vector_get_ptr(&lb_vip->backends, j);
          ds_clear(&key);
          ds_put_format(&key, IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)
                        ? "%s" : "[%s]", backend->ip_str);
diff --git a/northd/northd.c b/northd/northd.c
index 6f2458753..5190bc70a 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -3642,8 +3642,9 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn,
          struct ovn_lb_vip *lb_vip = &lb->vips[i];
          struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[i];
- for (size_t j = 0; j < lb_vip->n_backends; j++) {
-            struct ovn_lb_backend *backend = &lb_vip->backends[j];
+        for (size_t j = 0; j < vector_len(&lb_vip->backends); j++) {
+            const struct ovn_lb_backend *backend =
+                vector_get_ptr(&lb_vip->backends, j);
              struct ovn_northd_lb_backend *backend_nb =
                  &lb_vip_nb->backends_nb[j];
@@ -3717,8 +3718,10 @@ build_lb_vip_actions(const struct ovn_northd_lb *lb,
                       bool ls_dp,
                       const struct hmap *svc_monitor_map)
  {
-    bool reject = !lb_vip->n_backends && lb_vip->empty_backend_rej;
-    bool drop = !lb_vip->n_backends && !lb_vip->empty_backend_rej;
+    bool reject =
+        vector_is_empty(&lb_vip->backends) && lb_vip->empty_backend_rej;
+    bool drop =
+        vector_is_empty(&lb_vip->backends) && !lb_vip->empty_backend_rej;
if (ls_dp || lb->affinity_timeout) {
          const char *ip_reg =
@@ -3733,11 +3736,12 @@ build_lb_vip_actions(const struct ovn_northd_lb *lb,
      if (lb_vip_nb->lb_health_check) {
          ds_put_cstr(action, "ct_lb_mark(backends=");
+ size_t i = 0;
          size_t n_active_backends = 0;
-        for (size_t i = 0; i < lb_vip->n_backends; i++) {
-            struct ovn_lb_backend *backend = &lb_vip->backends[i];
+        const struct ovn_lb_backend *backend;
+        VECTOR_FOR_EACH_PTR (&lb_vip->backends, backend) {
              struct ovn_northd_lb_backend *backend_nb =
-                &lb_vip_nb->backends_nb[i];
+                &lb_vip_nb->backends_nb[i++];
if (!backend_nb->health_check) {
                  continue;
@@ -6081,7 +6085,7 @@ build_empty_lb_event_flow(struct ovn_lb_vip *lb_vip,
  {
      bool controller_event = lb->controller_event ||
                              controller_event_en; /* deprecated */
-    if (!controller_event || lb_vip->n_backends ||
+    if (!controller_event || !vector_is_empty(&lb_vip->backends) ||
          lb_vip->empty_backend_rej) {
          return false;
      }
@@ -7903,9 +7907,8 @@ build_lb_affinity_lr_flows(struct lflow_table *lflows,
      size_t aff_match_learn_len = aff_match_learn.length;
- for (size_t i = 0; i < lb_vip->n_backends; i++) {
-        struct ovn_lb_backend *backend = &lb_vip->backends[i];
-
+    struct ovn_lb_backend *backend;
+    VECTOR_FOR_EACH_PTR (&lb_vip->backends, backend) {
          ds_put_cstr(&aff_match_learn, backend->ip_str);
          ds_put_cstr(&aff_match, backend->ip_str);
@@ -8078,9 +8081,8 @@ build_lb_affinity_ls_flows(struct lflow_table *lflows,
      size_t aff_match_len = aff_match.length;
      size_t aff_match_learn_len = aff_match_learn.length;
- for (size_t i = 0; i < lb_vip->n_backends; i++) {
-        struct ovn_lb_backend *backend = &lb_vip->backends[i];
-
+    const struct ovn_lb_backend *backend;
+    VECTOR_FOR_EACH_PTR (&lb_vip->backends, backend) {
          ds_put_cstr(&aff_match_learn, backend->ip_str);
          ds_put_cstr(&aff_match, backend->ip_str);
@@ -11954,8 +11956,9 @@ build_distr_lrouter_nat_flows_for_lb(struct lrouter_nat_lb_flows_ctx *ctx,
       * (created by ct_lb_mark for the first rcv packet in this flow).
       */
      if (stateless_nat) {
-        if (ctx->lb_vip->n_backends) {
-            struct ovn_lb_backend *backend = &ctx->lb_vip->backends[0];
+        if (!vector_is_empty(&ctx->lb_vip->backends)) {
+            const struct ovn_lb_backend *backend =
+                vector_get_ptr(&ctx->lb_vip->backends, 0);
              bool ipv6 = !IN6_IS_ADDR_V4MAPPED(&backend->ip);
              ds_put_format(&dnat_action, "%s.dst = %s; ", ipv6 ? "ip6" : "ip4",
                            backend->ip_str);
@@ -11969,7 +11972,8 @@ build_distr_lrouter_nat_flows_for_lb(struct 
lrouter_nat_lb_flows_ctx *ctx,
          meter = copp_meter_get(COPP_REJECT, od->nbr->copp, ctx->meter_groups);
      }
- if (ctx->lb_vip->n_backends || !ctx->lb_vip->empty_backend_rej) {
+    if (!vector_is_empty(&ctx->lb_vip->backends) ||
+        !ctx->lb_vip->empty_backend_rej) {
          ds_put_format(ctx->new_match, " && is_chassis_resident(%s)",
                        dgp->cr_port->json_key);
      }
@@ -11982,7 +11986,7 @@ build_distr_lrouter_nat_flows_for_lb(struct 
lrouter_nat_lb_flows_ctx *ctx,
      ds_truncate(ctx->new_match, new_match_len);
ds_destroy(&dnat_action);
-    if (!ctx->lb_vip->n_backends) {
+    if (vector_is_empty(&ctx->lb_vip->backends)) {
          return;
      }
@@ -12174,8 +12178,8 @@ build_lrouter_nat_flows_for_lb(
       */
      ds_put_format(&undnat_match, "%s && (", ip_match);
- for (size_t i = 0; i < lb_vip->n_backends; i++) {
-        struct ovn_lb_backend *backend = &lb_vip->backends[i];
+    const struct ovn_lb_backend *backend;
+    VECTOR_FOR_EACH_PTR (&lb_vip->backends, backend) {
          ds_put_format(&undnat_match, "(%s.src == %s", ip_match,
                        backend->ip_str);
diff --git a/tests/test-ovn.c b/tests/test-ovn.c
index c4eb2a7df..1b63c05d2 100644
--- a/tests/test-ovn.c
+++ b/tests/test-ovn.c
@@ -954,7 +954,8 @@ test_tree_shape_exhaustively(struct expr *expr, struct 
shash *symtab,
                  test_rule = xmalloc(sizeof *test_rule);
                  cls_rule_init(&test_rule->cr, &m->match, 0);
                  classifier_insert(&cls, &test_rule->cr, OVS_VERSION_MIN,
-                                  m->conjunctions, m->n);
+                                  vector_get_array(&m->conjunctions),
+                                  vector_len(&m->conjunctions));
              }
          }
          for (int subst = 0; subst < 1 << (n_bits * n_nvars + n_svars);

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

Reply via email to