The vector has the same functionality as the x2nrealloc
for insert. Use vector instead which slightly simplifies
the final code.

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.
---
 northd/en-advertised-route-sync.c |  41 ++--
 northd/en-lr-nat.c                |  17 +-
 northd/en-multicast.c             |  47 ++---
 northd/en-multicast.h             |   3 +-
 northd/northd.c                   | 321 ++++++++++++++----------------
 northd/northd.h                   |  19 +-
 6 files changed, 207 insertions(+), 241 deletions(-)

diff --git a/northd/en-advertised-route-sync.c 
b/northd/en-advertised-route-sync.c
index 0f5c5e403..75fbbd942 100644
--- a/northd/en-advertised-route-sync.c
+++ b/northd/en-advertised-route-sync.c
@@ -338,11 +338,8 @@ build_nat_connected_routes(
         struct ovn_datapath *peer_od = op->peer->od;
         ovs_assert(peer_od->nbs || peer_od->nbr);
 
-        const struct ovn_port *peer_port = NULL;
         /* This is a directly connected LR peer. */
         if (peer_od->nbr) {
-            peer_port = op->peer;
-
             const struct lr_stateful_record *peer_lr_stateful =
                 lr_stateful_table_find_by_index(lr_stateful_table,
                                                  peer_od->index);
@@ -358,16 +355,16 @@ build_nat_connected_routes(
 
         /* This peer is LSP, we need to check all connected router ports
          * for NAT.*/
-        for (size_t i = 0; i < peer_od->n_router_ports; i++) {
-            peer_port = peer_od->router_ports[i]->peer;
-            if (peer_port == op) {
+        const struct ovn_port *rp;
+        VECTOR_FOR_EACH (&peer_od->router_ports, rp) {
+            if (rp->peer == op) {
                 /* Skip advertising router. */
                 continue;
             }
 
             const struct lr_stateful_record *peer_lr_stateful =
                 lr_stateful_table_find_by_index(lr_stateful_table,
-                                                peer_port->od->index);
+                                                rp->peer->od->index);
             if (!peer_lr_stateful) {
                 continue;
             }
@@ -423,30 +420,28 @@ build_lb_connected_routes(const struct ovn_datapath *od,
         ovs_assert(peer_od->nbs || peer_od->nbr);
 
         const struct lr_stateful_record *lr_stateful_rec;
-        const struct ovn_port *peer_port = NULL;
         /* This is directly connected LR peer. */
         if (peer_od->nbr) {
             lr_stateful_rec = lr_stateful_table_find_by_index(
                 lr_stateful_table, peer_od->index);
-            peer_port = op->peer;
-            build_lb_route_for_port(op, peer_port, lr_stateful_rec->lb_ips,
+            build_lb_route_for_port(op, op->peer, lr_stateful_rec->lb_ips,
                                     routes);
             return;
         }
 
         /* This peer is LSP, we need to check all connected router ports for
          * LBs.*/
-        for (size_t i = 0; i < peer_od->n_router_ports; i++) {
-            peer_port = peer_od->router_ports[i]->peer;
-            if (peer_port == op) {
+        struct ovn_port *rp;
+        VECTOR_FOR_EACH (&peer_od->router_ports, rp) {
+            if (rp->peer == op) {
                 /* no need to check for LBs on ovn_port that initiated this
                  * function.*/
                 continue;
             }
             lr_stateful_rec = lr_stateful_table_find_by_index(
-                lr_stateful_table, peer_port->od->index);
+                lr_stateful_table, rp->peer->od->index);
 
-            build_lb_route_for_port(op, peer_port, lr_stateful_rec->lb_ips,
+            build_lb_route_for_port(op, rp->peer, lr_stateful_rec->lb_ips,
                                     routes);
         }
     }
@@ -470,14 +465,14 @@ build_lb_routes(const struct ovn_datapath *od,
          *
          * Advertise the LB IPs via all 'op' if this is a gateway router or
          * throuh all DGPs of this distributed router otherwise. */
-        struct ovn_port *op_ = NULL;
-        size_t n_tracked_ports = !od->is_gw_router ? od->n_l3dgw_ports : 1;
-        struct ovn_port **tracked_ports = !od->is_gw_router
-                                          ? od->l3dgw_ports
-                                          : &op_;
-
-        for (size_t i = 0; i < n_tracked_ports; i++) {
-            build_lb_route_for_port(op, tracked_ports[i], lb_ips, routes);
+
+        if (od->is_gw_router) {
+            build_lb_route_for_port(op, NULL, lb_ips, routes);
+        } else {
+            struct ovn_port *dgp;
+            VECTOR_FOR_EACH (&od->l3dgw_ports, dgp) {
+                build_lb_route_for_port(op, dgp, lb_ips, routes);
+            }
         }
     }
 }
diff --git a/northd/en-lr-nat.c b/northd/en-lr-nat.c
index 44009ca6f..68c4d0e29 100644
--- a/northd/en-lr-nat.c
+++ b/northd/en-lr-nat.c
@@ -295,13 +295,15 @@ lr_nat_entry_set_dgw_port(const struct ovn_datapath *od,
     /* Validate gateway_port of NAT rule. */
     nat_entry->l3dgw_port = NULL;
     if (nat->gateway_port == NULL) {
-        if (od->n_l3dgw_ports == 1) {
-            nat_entry->l3dgw_port = od->l3dgw_ports[0];
-        } else if (od->n_l3dgw_ports > 1) {
+        if (vector_len(&od->l3dgw_ports) == 1) {
+            nat_entry->l3dgw_port = vector_get(&od->l3dgw_ports, 0,
+                                               struct ovn_port *);
+        } else if (vector_len(&od->l3dgw_ports) > 1) {
             /* Find the DGP reachable for the NAT external IP. */
-            for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
-               if (lrp_find_member_ip(od->l3dgw_ports[i], nat->external_ip)) {
-                   nat_entry->l3dgw_port = od->l3dgw_ports[i];
+            struct ovn_port *dgp;
+            VECTOR_FOR_EACH (&od->l3dgw_ports, dgp) {
+               if (lrp_find_member_ip(dgp, nat->external_ip)) {
+                   nat_entry->l3dgw_port = dgp;
                    break;
                }
             }
@@ -342,7 +344,8 @@ lr_nat_entry_set_dgw_port(const struct ovn_datapath *od,
         return true;
     }
 
-    if (od->n_l3dgw_ports && nat_entry->type == DNAT_AND_SNAT &&
+    if (!vector_is_empty(&od->l3dgw_ports) &&
+        nat_entry->type == DNAT_AND_SNAT &&
         nat->logical_port && nat->external_mac) {
             nat_entry->is_distributed = true;
     }
diff --git a/northd/en-multicast.c b/northd/en-multicast.c
index 7f3a6077c..3d918f15f 100644
--- a/northd/en-multicast.c
+++ b/northd/en-multicast.c
@@ -332,8 +332,8 @@ build_mcast_groups(struct multicast_igmp_data *data,
          * The router IGMP groups are based on the groups learnt by their
          * multicast enabled peers.
          */
-        for (size_t i = 0; i < od->n_router_ports; i++) {
-            struct ovn_port *router_port = od->router_ports[i]->peer;
+        VECTOR_FOR_EACH (&od->router_ports, op) {
+            struct ovn_port *router_port = op->peer;
 
             /* If the router the port connects to doesn't have multicast
              * relay enabled or if it was already configured to flood
@@ -483,24 +483,10 @@ ovn_multicast_add_ports(struct hmap *mcgroups, struct 
ovn_datapath *od,
         hmap_insert(mcgroups, &mc->hmap_node, ovn_multicast_hash(od, group));
         mc->datapath = od;
         mc->group = group;
-        mc->n_ports = 0;
-        mc->allocated_ports = 4;
-        mc->ports = xmalloc(mc->allocated_ports * sizeof *mc->ports);
+        mc->ports = VECTOR_CAPACITY_INITIALIZER(struct ovn_port *, 4);
     }
 
-    size_t n_ports_total = mc->n_ports + n_ports;
-
-    if (n_ports_total > 2 * mc->allocated_ports) {
-        mc->allocated_ports = n_ports_total;
-        mc->ports = xrealloc(mc->ports,
-                             mc->allocated_ports * sizeof *mc->ports);
-    } else if (n_ports_total > mc->allocated_ports) {
-        mc->ports = x2nrealloc(mc->ports, &mc->allocated_ports,
-                               sizeof *mc->ports);
-    }
-
-    memcpy(&mc->ports[mc->n_ports], &ports[0], n_ports * sizeof *ports);
-    mc->n_ports += n_ports;
+    vector_push_array(&mc->ports, ports, n_ports);
 }
 
 static void
@@ -521,7 +507,7 @@ ovn_multicast_destroy(struct hmap *mcgroups, struct 
ovn_multicast *mc)
 {
     if (mc) {
         hmap_remove(mcgroups, &mc->hmap_node);
-        free(mc->ports);
+        vector_destroy(&mc->ports);
         free(mc);
     }
 }
@@ -530,12 +516,17 @@ static void
 ovn_multicast_update_sbrec(const struct ovn_multicast *mc,
                            const struct sbrec_multicast_group *sb)
 {
-    struct sbrec_port_binding **ports = xmalloc(mc->n_ports * sizeof *ports);
-    for (size_t i = 0; i < mc->n_ports; i++) {
-        ports[i] = CONST_CAST(struct sbrec_port_binding *, mc->ports[i]->sb);
+    struct vector sb_ports =
+        VECTOR_CAPACITY_INITIALIZER(struct sbrec_port_binding *,
+                                    vector_len(&mc->ports));
+
+    struct ovn_port *op;
+    VECTOR_FOR_EACH (&mc->ports, op) {
+        vector_push(&sb_ports, &op->sb);
     }
-    sbrec_multicast_group_set_ports(sb, ports, mc->n_ports);
-    free(ports);
+    sbrec_multicast_group_set_ports(sb, vector_get_array(&sb_ports),
+                                    vector_len(&sb_ports));
+    vector_destroy(&sb_ports);
 }
 
 static void
@@ -716,11 +707,11 @@ ovn_igmp_group_aggregate_ports(struct ovn_igmp_group 
*igmp_group,
         free(entry);
     }
 
-    if (igmp_group->datapath->n_localnet_ports) {
+    if (!vector_is_empty(&igmp_group->datapath->localnet_ports)) {
         ovn_multicast_add_ports(mcast_groups, igmp_group->datapath,
-                                &igmp_group->mcgroup,
-                                igmp_group->datapath->localnet_ports,
-                                igmp_group->datapath->n_localnet_ports);
+            &igmp_group->mcgroup,
+            vector_get_array(&igmp_group->datapath->localnet_ports),
+            vector_len(&igmp_group->datapath->localnet_ports));
     }
 }
 
diff --git a/northd/en-multicast.h b/northd/en-multicast.h
index 131c01d65..c1ff7820d 100644
--- a/northd/en-multicast.h
+++ b/northd/en-multicast.h
@@ -43,8 +43,7 @@ struct ovn_multicast {
     struct ovn_datapath *datapath;
     const struct multicast_group *group;
 
-    struct ovn_port **ports;
-    size_t n_ports, allocated_ports;
+    struct vector ports; /* Vector of struct ovn_port *. */
 };
 
 /*
diff --git a/northd/northd.c b/northd/northd.c
index bed05e614..464b3798a 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -499,6 +499,10 @@ ovn_datapath_create(struct hmap *datapaths, const struct 
uuid *key,
     od->lr_group = NULL;
     hmap_init(&od->ports);
     sset_init(&od->router_ips);
+    od->ls_peers = VECTOR_EMPTY_INITIALIZER(struct ovn_datapath *);
+    od->router_ports = VECTOR_EMPTY_INITIALIZER(struct ovn_port *);
+    od->l3dgw_ports = VECTOR_EMPTY_INITIALIZER(struct ovn_port *);
+    od->localnet_ports = VECTOR_EMPTY_INITIALIZER(struct ovn_port *);
     return od;
 }
 
@@ -521,10 +525,10 @@ ovn_datapath_destroy(struct hmap *datapaths, struct 
ovn_datapath *od)
         hmap_remove(datapaths, &od->key_node);
         ovn_destroy_tnlids(&od->port_tnlids);
         destroy_ipam_info(&od->ipam_info);
-        free(od->router_ports);
-        free(od->ls_peers);
-        free(od->localnet_ports);
-        free(od->l3dgw_ports);
+        vector_destroy(&od->router_ports);
+        vector_destroy(&od->ls_peers);
+        vector_destroy(&od->localnet_ports);
+        vector_destroy(&od->l3dgw_ports);
         destroy_mcast_info_for_datapath(od);
         destroy_ports_for_datapath(od);
         sset_destroy(&od->router_ips);
@@ -593,27 +597,6 @@ ovn_datapath_from_sbrec(const struct hmap *ls_datapaths,
     return NULL;
 }
 
-static void
-ovn_datapath_add_router_port(struct ovn_datapath *od, struct ovn_port *op)
-{
-    if (od->n_router_ports == od->n_allocated_router_ports) {
-        od->router_ports = x2nrealloc(od->router_ports,
-                                      &od->n_allocated_router_ports,
-                                      sizeof *od->router_ports);
-    }
-    od->router_ports[od->n_router_ports++] = op;
-}
-
-static void
-ovn_datapath_add_ls_peer(struct ovn_datapath *od, struct ovn_datapath *peer)
-{
-    if (od->n_ls_peers == od->n_allocated_ls_peers) {
-        od->ls_peers = x2nrealloc(od->ls_peers, &od->n_allocated_ls_peers,
-                                  sizeof *od->ls_peers);
-    }
-    od->ls_peers[od->n_ls_peers++] = peer;
-}
-
 static bool
 lrouter_is_enabled(const struct nbrec_logical_router *lrouter)
 {
@@ -1601,7 +1584,7 @@ ipam_add_port_addresses(struct ovn_datapath *od, struct 
ovn_port *op)
 static bool
 is_nat_gateway_port(const struct nbrec_nat *nat, const struct ovn_port *op)
 {
-    if (op->od->n_l3dgw_ports > 1
+    if (vector_len(&op->od->l3dgw_ports) > 1
         && ((!nat->gateway_port && !lrp_find_member_ip(op, nat->external_ip))
             || (nat->gateway_port && nat->gateway_port != op->nbrp))) {
         return false;
@@ -2302,12 +2285,7 @@ join_logical_ports_lsp(struct hmap *ports,
     }
 
     if (lsp_is_localnet(nbsp)) {
-       if (od->n_localnet_ports >= od->n_allocated_localnet_ports) {
-           od->localnet_ports = x2nrealloc(
-               od->localnet_ports, &od->n_allocated_localnet_ports,
-               sizeof *od->localnet_ports);
-       }
-       od->localnet_ports[od->n_localnet_ports++] = op;
+        vector_push(&od->localnet_ports, &op);
     }
 
     if (lsp_is_vtep(nbsp)) {
@@ -2456,8 +2434,8 @@ static bool
 peer_needs_cr_port_creation(struct ovn_port *op)
 {
     if ((op->nbrp->n_gateway_chassis || op->nbrp->ha_chassis_group)
-        && op->od->n_l3dgw_ports == 1 && op->peer && op->peer->nbsp
-        && !op->peer->od->n_localnet_ports) {
+        && vector_len(&op->od->l3dgw_ports) == 1 && op->peer && op->peer->nbsp
+        && vector_is_empty(&op->peer->od->localnet_ports)) {
         return true;
     }
 
@@ -2552,8 +2530,8 @@ join_logical_ports(const struct sbrec_port_binding_table 
*sbrec_pb_table,
                 continue;
             }
 
-            ovn_datapath_add_router_port(op->od, op);
-            ovn_datapath_add_ls_peer(peer->od, op->od);
+            vector_push(&op->od->router_ports, &op);
+            vector_push(&peer->od->ls_peers, &op->od);
             peer->peer = op;
             op->peer = peer;
 
@@ -2659,12 +2637,7 @@ join_logical_ports(const struct sbrec_port_binding_table 
*sbrec_pb_table,
         ovs_assert(crp);
 
         /* Add to l3dgw_ports in od, for later use during flow creation. */
-        if (od->n_l3dgw_ports == od->n_allocated_l3dgw_ports) {
-            od->l3dgw_ports = x2nrealloc(od->l3dgw_ports,
-                                        &od->n_allocated_l3dgw_ports,
-                                        sizeof *od->l3dgw_ports);
-        }
-        od->l3dgw_ports[od->n_l3dgw_ports++] = op;
+        vector_push(&od->l3dgw_ports, &op);
 
         if (op->peer && op->peer->nbsp) {
             /* Only used for the router type LSP whose peer is l3dgw_port */
@@ -2770,8 +2743,9 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, 
bool routable_only,
 
         /* Determine whether this NAT rule satisfies the conditions for
          * distributed NAT processing. */
-        if (op->od->n_l3dgw_ports && !strcmp(nat->type, "dnat_and_snat")
-            && nat->logical_port && nat->external_mac) {
+        if (!vector_is_empty(&op->od->l3dgw_ports) &&
+            !strcmp(nat->type, "dnat_and_snat") &&
+            nat->logical_port && nat->external_mac) {
             /* Distributed NAT rule. */
             if (eth_addr_from_string(nat->external_mac, &mac)) {
                 struct ds address = DS_EMPTY_INITIALIZER;
@@ -3410,8 +3384,9 @@ ovn_port_update_sbrec(struct ovsdb_idl_txn *ovnsb_txn,
             smap_clone(&options, &op->nbsp->options);
 
             if (queue_id) {
-                if (op->od->n_localnet_ports) {
-                    struct ovn_port *port = op->od->localnet_ports[0];
+                if (!vector_is_empty(&op->od->localnet_ports)) {
+                    struct ovn_port *port = vector_get(&op->od->localnet_ports,
+                                                       0, struct ovn_port *);
                     const char *physical_network = smap_get(
                             &port->nbsp->options, "network_name");
                     if (physical_network) {
@@ -4090,7 +4065,8 @@ build_lswitch_lbs_from_lrouter(struct ovn_datapaths 
*lr_datapaths,
     HMAP_FOR_EACH (lb_dps, hmap_node, lb_dps_map) {
         BITMAP_FOR_EACH_1 (index, ods_size(lr_datapaths), lb_dps->nb_lr_map) {
             struct ovn_datapath *od = lr_datapaths->array[index];
-            ovn_lb_datapaths_add_ls(lb_dps, od->n_ls_peers, od->ls_peers);
+            ovn_lb_datapaths_add_ls(lb_dps, vector_len(&od->ls_peers),
+                                    vector_get_array(&od->ls_peers));
         }
     }
 
@@ -4098,14 +4074,16 @@ build_lswitch_lbs_from_lrouter(struct ovn_datapaths 
*lr_datapaths,
     HMAP_FOR_EACH (lb_group_dps, hmap_node, lb_group_dps_map) {
         for (size_t i = 0; i < lb_group_dps->n_lr; i++) {
             struct ovn_datapath *od = lb_group_dps->lr[i];
-            ovn_lb_group_datapaths_add_ls(lb_group_dps, od->n_ls_peers,
-                                          od->ls_peers);
+            ovn_lb_group_datapaths_add_ls(lb_group_dps,
+                                          vector_len(&od->ls_peers),
+                                          vector_get_array(&od->ls_peers));
             for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) {
                 const struct uuid *lb_uuid =
                     &lb_group_dps->lb_group->lbs[j]->nlb->header_.uuid;
                 lb_dps = ovn_lb_datapaths_find(lb_dps_map, lb_uuid);
                 ovs_assert(lb_dps);
-                ovn_lb_datapaths_add_ls(lb_dps, od->n_ls_peers, od->ls_peers);
+                ovn_lb_datapaths_add_ls(lb_dps, vector_len(&od->ls_peers),
+                                        vector_get_array(&od->ls_peers));
             }
         }
     }
@@ -4170,12 +4148,13 @@ should_add_router_port_garp(const struct ovn_port *op, 
const char *chassis)
     }
 
     bool add_router_port_garp = false;
-    if (op->peer && op->peer->nbrp && op->peer->od->n_l3dgw_ports) {
+    if (op->peer && op->peer->nbrp &&
+        !vector_is_empty(&op->peer->od->l3dgw_ports)) {
         if (lrp_is_l3dgw(op->peer)) {
             add_router_port_garp = true;
         } else if (smap_get_bool(&op->peer->nbrp->options,
                                  "reside-on-redirect-chassis", false)) {
-            if (op->peer->od->n_l3dgw_ports == 1) {
+            if (vector_len(&op->peer->od->l3dgw_ports) == 1) {
                 add_router_port_garp = true;
             } else {
                 static struct vlog_rate_limit rl =
@@ -4187,10 +4166,10 @@ should_add_router_port_garp(const struct ovn_port *op, 
const char *chassis)
                                 "option can only be used when there is "
                                 "a single distributed gateway port.",
                                 op->peer->key, op->peer->od->nbr->name,
-                                op->peer->od->n_l3dgw_ports);
+                                vector_len(&op->peer->od->l3dgw_ports));
             }
         }
-    } else if (chassis && op->od->n_localnet_ports) {
+    } else if (chassis && !vector_is_empty(&op->od->localnet_ports)) {
         add_router_port_garp = true;
     }
 
@@ -4217,10 +4196,10 @@ sync_pb_for_lsp(struct ovn_port *op,
         size_t n_nats = 0;
         char **nats = NULL;
         bool l3dgw_ports = op->peer && op->peer->od &&
-                            op->peer->od->n_l3dgw_ports;
+                           !vector_is_empty(&op->peer->od->l3dgw_ports);
         if (nat_addresses && !strcmp(nat_addresses, "router")) {
             if (op->peer && op->peer->od
-                && (chassis || op->peer->od->n_l3dgw_ports)) {
+                && (chassis || !vector_is_empty(&op->peer->od->l3dgw_ports))) {
                 bool include_lb_vips = !smap_get_bool(&op->nbsp->options,
                         "exclude-lb-vips-from-garp", false);
 
@@ -4249,7 +4228,8 @@ sync_pb_for_lsp(struct ovn_port *op,
                     const struct ovn_port *l3dgw_port = (
                         lrp_is_l3dgw(op->peer)
                         ? op->peer
-                        : op->peer->od->l3dgw_ports[0]);
+                        : vector_get(&op->peer->od->l3dgw_ports, 0,
+                                     struct ovn_port *));
                     ds_put_format(&nat_addr, " is_chassis_resident(%s)",
                         l3dgw_port->cr_port->json_key);
                 }
@@ -4286,11 +4266,12 @@ sync_pb_for_lsp(struct ovn_port *op,
                                 op->peer->lrp_networks.ipv4_addrs[i].addr_s);
             }
 
-            if (op->peer->od->n_l3dgw_ports) {
+            if (!vector_is_empty(&op->peer->od->l3dgw_ports)) {
                 const struct ovn_port *l3dgw_port = (
                     lrp_is_l3dgw(op->peer)
                     ? op->peer
-                    : op->peer->od->l3dgw_ports[0]);
+                    : vector_get(&op->peer->od->l3dgw_ports, 0,
+                                 struct ovn_port *));
                 ds_put_format(&garp_info, " is_chassis_resident(%s)",
                                 l3dgw_port->cr_port->json_key);
             }
@@ -4999,8 +4980,8 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn *ovnsb_idl_txn,
         return true;
     }
 
-    bool ls_had_only_router_ports = (od->n_router_ports
-            && (od->n_router_ports == hmap_count(&od->ports)));
+    bool ls_had_only_router_ports = (!vector_is_empty(&od->router_ports)
+            && (vector_len(&od->router_ports) == hmap_count(&od->ports)));
 
     struct ovn_port *op;
     HMAP_FOR_EACH (op, dp_node, &od->ports) {
@@ -5102,8 +5083,8 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn *ovnsb_idl_txn,
         }
     }
 
-    bool ls_has_only_router_ports = (od->n_router_ports
-            && (od->n_router_ports == hmap_count(&od->ports)));
+    bool ls_has_only_router_ports = (!vector_is_empty(&od->router_ports)
+            && (vector_len(&od->router_ports)  == hmap_count(&od->ports)));
 
     /* There are lflows related to router ports that depend on whether
      * there are switch ports on the logical switch (see
@@ -5112,8 +5093,7 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn *ovnsb_idl_txn,
      * to the tracked 'updated' ovn ports so that lflow engine can
      * regenerate lflows for these router ports. */
     if (ls_had_only_router_ports != ls_has_only_router_ports) {
-        for (size_t i = 0; i < od->n_router_ports; i++) {
-            op = od->router_ports[i];
+        VECTOR_FOR_EACH (&od->router_ports, op) {
             add_op_to_northd_tracked_ports(&trk_lsps->updated, op);
         }
     }
@@ -6058,7 +6038,8 @@ build_lswitch_port_sec_op(struct ovn_port *op, struct 
lflow_table *lflows,
                                           op->key, &op->nbsp->header_,
                                           op->lflow_ref);
 
-        if (!lsp_is_localnet(op->nbsp) && !op->od->n_localnet_ports) {
+        if (!lsp_is_localnet(op->nbsp) &&
+            vector_is_empty(&op->od->localnet_ports)) {
             return;
         }
 
@@ -6073,16 +6054,15 @@ build_lswitch_port_sec_op(struct ovn_port *op, struct 
lflow_table *lflows,
                                               ds_cstr(match), ds_cstr(actions),
                                               op->key, &op->nbsp->header_,
                                               op->lflow_ref);
-        } else if (op->od->n_localnet_ports) {
+        } else if (!vector_is_empty(&op->od->localnet_ports)) {
+            const struct ovn_port *lp = vector_get(&op->od->localnet_ports, 0,
+                                                   struct ovn_port *);
             ds_put_format(match, "outport == %s && inport == %s",
-                          op->od->localnet_ports[0]->json_key,
-                          op->json_key);
+                          lp->json_key, op->json_key);
             ovn_lflow_add_with_lport_and_hint(lflows, op->od,
                     S_SWITCH_OUT_APPLY_PORT_SEC, 110,
                     ds_cstr(match), ds_cstr(actions),
-                    op->od->localnet_ports[0]->key,
-                    &op->od->localnet_ports[0]->nbsp->header_,
-                    op->lflow_ref);
+                    lp->key, &lp->nbsp->header_, op->lflow_ref);
         }
     } else if (lsp_is_router(op->nbsp)) {
         ds_put_format(actions, REGBIT_FROM_ROUTER_PORT" = 1; next;");
@@ -6304,8 +6284,8 @@ build_ls_stateful_rec_pre_acls(
      * send IP packets for some (allow) filters through the conntrack action,
      * which handles defragmentation, in order to match L4 headers. */
     if (ls_stateful_rec->has_stateful_acl) {
-        for (size_t i = 0; i < od->n_router_ports; i++) {
-            struct ovn_port *op = od->router_ports[i];
+        struct ovn_port *op;
+        VECTOR_FOR_EACH (&od->router_ports, op) {
             if (op->enable_router_port_acl) {
                 continue;
             }
@@ -6313,11 +6293,11 @@ build_ls_stateful_rec_pre_acls(
                                      S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL,
                                      110, lflows, lflow_ref);
         }
-        for (size_t i = 0; i < od->n_localnet_ports; i++) {
-            skip_port_from_conntrack(od, od->localnet_ports[i], true,
-                                     S_SWITCH_IN_PRE_ACL,
-                                     S_SWITCH_OUT_PRE_ACL,
-                                     110, lflows, lflow_ref);
+        struct ovn_port *lp;
+        VECTOR_FOR_EACH (&od->localnet_ports, lp) {
+            skip_port_from_conntrack(od, lp, true, S_SWITCH_IN_PRE_ACL,
+                                     S_SWITCH_OUT_PRE_ACL, 110, lflows,
+                                     lflow_ref);
         }
 
         /* stateless filters always take precedence over stateful ACLs. */
@@ -6515,9 +6495,9 @@ build_ls_stateful_rec_pre_lb(const struct 
ls_stateful_record *ls_stateful_rec,
                              struct lflow_table *lflows,
                              struct lflow_ref *lflow_ref)
 {
-    for (size_t i = 0; i < od->n_router_ports; i++) {
-        skip_port_from_conntrack(od, od->router_ports[i],
-                                 ls_stateful_rec->has_stateful_acl,
+    struct ovn_port *op;
+    VECTOR_FOR_EACH (&od->router_ports, op) {
+        skip_port_from_conntrack(od, op, ls_stateful_rec->has_stateful_acl,
                                  S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB,
                                  110, lflows, lflow_ref);
     }
@@ -6528,9 +6508,9 @@ build_ls_stateful_rec_pre_lb(const struct 
ls_stateful_record *ls_stateful_rec,
      * balanced.
      */
     if (!ls_stateful_rec->has_lb_vip) {
-        for (size_t i = 0; i < od->n_localnet_ports; i++) {
-            skip_port_from_conntrack(od, od->localnet_ports[i],
-                                     ls_stateful_rec->has_stateful_acl,
+        struct ovn_port *lp;
+        VECTOR_FOR_EACH (&od->localnet_ports, lp) {
+            skip_port_from_conntrack(od, lp, ls_stateful_rec->has_stateful_acl,
                                      S_SWITCH_IN_PRE_LB, S_SWITCH_OUT_PRE_LB,
                                      110, lflows, lflow_ref);
         }
@@ -8721,8 +8701,9 @@ build_vtep_hairpin(struct ovn_datapath *od, struct 
lflow_table *lflows,
     * current chassis, should be passed to next table for ARP/ND hairpin
     * processing. */
     struct ds match = DS_EMPTY_INITIALIZER;
-    for (int i = 0; i < od->n_router_ports; i++) {
-        struct ovn_port *op = od->router_ports[i]->peer;
+    struct ovn_port *rp;
+    VECTOR_FOR_EACH (&od->router_ports, rp) {
+        struct ovn_port *op = rp->peer;
         if (lrp_is_l3dgw(op)) {
             ds_clear(&match);
             ds_put_format(&match,
@@ -8825,8 +8806,9 @@ build_lrouter_groups__(struct hmap *lr_ports, struct 
ovn_datapath *od)
     /* For logical router with distributed gateway ports. If it
      * has HA_Chassis_Group associated to it in SB DB, then store the
      * ha chassis group name. */
-    for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
-        struct ovn_port *crp = od->l3dgw_ports[i]->cr_port;
+    struct ovn_port *dgp;
+    VECTOR_FOR_EACH (&od->l3dgw_ports, dgp) {
+        struct ovn_port *crp = dgp->cr_port;
         if (crp->sb->ha_chassis_group &&
             crp->sb->ha_chassis_group->n_ha_chassis > 1) {
             sset_add(&od->lr_group->ha_chassis_groups,
@@ -8852,15 +8834,16 @@ build_lrouter_groups__(struct hmap *lr_ports, struct 
ovn_datapath *od)
                 build_lrouter_groups__(lr_ports, peer_dp);
             }
         } else {
-            for (size_t j = 0; j < peer_dp->n_router_ports; j++) {
-                if (!peer_dp->router_ports[j]->peer) {
+            struct ovn_port *op;
+            VECTOR_FOR_EACH (&peer_dp->router_ports, op) {
+                if (!op->peer) {
                     /* If there is no peer port connecting to the
                     * router port, ignore it. */
                     continue;
                 }
 
                 struct ovn_datapath *router_dp;
-                router_dp = peer_dp->router_ports[j]->peer->od;
+                router_dp = op->peer->od;
                 if (router_dp == od) {
                     continue;
                 }
@@ -9056,7 +9039,7 @@ build_lswitch_rport_arp_req_flow(
     /* Send a the packet to the router pipeline.  If the switch has non-router
      * ports then flood it there as well.
      */
-    if (od->n_router_ports != od->nbs->n_ports) {
+    if (vector_len(&od->router_ports) != od->nbs->n_ports) {
         ds_put_format(&actions, "clone {outport = %s; output; }; "
                                 "outport = \""MC_FLOOD_L2"\"; output;",
                       patch_op->json_key);
@@ -9078,7 +9061,7 @@ build_lswitch_rport_arp_req_flow(
         ds_put_format(&match, "%s && !is_chassis_resident(%s)", ds_cstr(&m),
                       patch_op->cr_port->json_key);
         ds_clear(&actions);
-        if (od->n_router_ports != od->nbs->n_ports) {
+        if (vector_len(&od->router_ports) != od->nbs->n_ports) {
             ds_put_format(&actions, "clone {outport = %s; output; }; "
                                     "outport = \""MC_FLOOD_L2"\"; output;",
                           patch_op->cr_port->json_key);
@@ -9206,7 +9189,7 @@ build_lswitch_rport_arp_req_flows_for_lbnats(
      *
      * Priority: 75.
      */
-    if (sw_od->n_router_ports != sw_od->nbs->n_ports) {
+    if (vector_len(&sw_od->router_ports) != sw_od->nbs->n_ports) {
         build_lswitch_rport_arp_req_self_orig_flow(op, 75, sw_od,
                                                    lr_stateful_rec->lrnat_rec,
                                                    lflows, lflow_ref);
@@ -9496,7 +9479,7 @@ build_lswitch_dhcp_relay_flows(struct ovn_port *op,
         return;
     }
 
-    if (!op->od || !op->od->n_router_ports || !op->od->nbs) {
+    if (!op->od || vector_is_empty(&op->od->router_ports) || !op->od->nbs) {
         return;
     }
 
@@ -9566,8 +9549,8 @@ build_drop_arp_nd_flows_for_unbound_router_ports(struct 
ovn_port *op,
     struct ds match = DS_EMPTY_INITIALIZER;
 
     for (size_t i = 0; i < op->n_lsp_addrs; i++) {
-        for (size_t j = 0; j < op->od->n_router_ports; j++) {
-            struct ovn_port *rp = op->od->router_ports[j];
+        struct ovn_port *rp;
+        VECTOR_FOR_EACH (&op->od->router_ports, rp) {
             for (size_t k = 0; k < rp->n_lsp_addrs; k++) {
                 for (size_t l = 0; l < rp->lsp_addrs[k].n_ipv4_addrs; l++) {
                     ds_clear(&match);
@@ -10187,7 +10170,7 @@ build_lswitch_dhcp_options_and_response(struct ovn_port 
*op,
     }
 
     bool is_external = lsp_is_external(op->nbsp);
-    if (is_external && (!op->od->n_localnet_ports ||
+    if (is_external && (vector_is_empty(&op->od->localnet_ports) ||
                         !op->nbsp->ha_chassis_group)) {
         /* If it's an external port and there are no localnet ports
          * and if it doesn't belong to an HA chassis group ignore it. */
@@ -10196,14 +10179,13 @@ build_lswitch_dhcp_options_and_response(struct 
ovn_port *op,
 
     for (size_t i = 0; i < op->n_lsp_addrs; i++) {
         if (is_external) {
-            for (size_t j = 0; j < op->od->n_localnet_ports; j++) {
+            struct ovn_port *lp;
+            VECTOR_FOR_EACH (&op->od->localnet_ports, lp) {
                 build_dhcpv4_options_flows(
-                    op, &op->lsp_addrs[i],
-                    op->od->localnet_ports[j], is_external,
+                    op, &op->lsp_addrs[i], lp, is_external,
                     meter_groups, lflows, op->lflow_ref);
                 build_dhcpv6_options_flows(
-                    op, &op->lsp_addrs[i],
-                    op->od->localnet_ports[j], is_external,
+                    op, &op->lsp_addrs[i], lp, is_external,
                     meter_groups, lflows, op->lflow_ref);
             }
         } else {
@@ -10284,10 +10266,10 @@ build_lswitch_external_port(struct ovn_port *op,
     if (!lsp_is_external(op->nbsp)) {
         return;
     }
-    for (size_t i = 0; i < op->od->n_localnet_ports; i++) {
-        build_drop_arp_nd_flows_for_unbound_router_ports(
-            op, op->od->localnet_ports[i], lflows,
-            op->lflow_ref);
+    struct ovn_port *lp;
+    VECTOR_FOR_EACH (&op->od->localnet_ports, lp) {
+        build_drop_arp_nd_flows_for_unbound_router_ports(op, lp, lflows,
+                                                         op->lflow_ref);
     }
 }
 
@@ -10524,7 +10506,8 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op,
             ds_put_format(match, "eth.dst == %s", op->peer->lrp_networks.ea_s);
         }
 
-        if (op->peer->od->n_l3dgw_ports && op->od->n_localnet_ports) {
+        if (!vector_is_empty(&op->peer->od->l3dgw_ports) &&
+            !vector_is_empty(&op->od->localnet_ports)) {
             bool add_chassis_resident_check = false;
             const char *json_key;
             if (lrp_is_l3dgw(op->peer)) {
@@ -10545,8 +10528,9 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op,
                 add_chassis_resident_check = smap_get_bool(
                     &op->peer->nbrp->options,
                     "reside-on-redirect-chassis", false) &&
-                    op->peer->od->n_l3dgw_ports == 1;
-                json_key = op->peer->od->l3dgw_ports[0]->cr_port->json_key;
+                    vector_len(&op->peer->od->l3dgw_ports) == 1;
+                json_key = vector_get(&op->peer->od->l3dgw_ports, 0,
+                                      struct ovn_port *)->cr_port->json_key;
             }
 
             if (add_chassis_resident_check) {
@@ -12546,16 +12530,16 @@ build_lrouter_nat_flows_for_lb(
             type = LROUTER_NAT_LB_FLOW_NORMAL;
         }
 
-        if (!od->n_l3dgw_ports) {
+        if (vector_is_empty(&od->l3dgw_ports)) {
             bitmap_set1(gw_dp_bitmap[type], index);
         } else {
             /* Create stateless LB NAT rules when using multiple DGPs and
              * use_stateless_nat is true.
              */
-            bool stateless_nat = (od->n_l3dgw_ports > 1)
+            bool stateless_nat = (vector_len(&od->l3dgw_ports) > 1)
                 ? use_stateless_nat : false;
-            for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
-                struct ovn_port *dgp = od->l3dgw_ports[i];
+            struct ovn_port *dgp;
+            VECTOR_FOR_EACH (&od->l3dgw_ports, dgp) {
                 build_distr_lrouter_nat_flows_for_lb(&ctx, type, od,
                                                      lb_dps->lflow_ref, dgp,
                                                      stateless_nat);
@@ -12873,7 +12857,7 @@ lrouter_nat_get_priority(const struct ovn_datapath *od,
      * nat->logical_ip with the longest mask gets a higher
      * priority. */
     uint16_t priority = prefix_len + 1;
-    if (!od->is_gw_router && od->n_l3dgw_ports) {
+    if (!od->is_gw_router && !vector_is_empty(&od->l3dgw_ports)) {
         priority += 128;
     }
 
@@ -13560,9 +13544,9 @@ build_gateway_get_l2_hdr_size(struct ovn_port *op)
         /* Check if vlans are enabled on a localnet port running the logical
          * switch connected to this logical router.
          */
-        for (size_t i = 0; i < peer->od->n_localnet_ports; i++) {
-            struct ovn_port *localnet_port = peer->od->localnet_ports[i];
-            const struct nbrec_logical_switch_port *nbsp = localnet_port->nbsp;
+        struct ovn_port *lp;
+        VECTOR_FOR_EACH (&peer->od->localnet_ports, lp) {
+            const struct nbrec_logical_switch_port *nbsp = lp->nbsp;
 
             if (!nbsp || !nbsp->tag_request) {
                 continue;
@@ -14813,7 +14797,8 @@ build_arp_resolve_flows_for_lsp(
         return;
     }
 
-    if (op->od->n_router_ports && !lsp_is_router(op->nbsp)
+    struct ovn_port *rp;
+    if (!vector_is_empty(&op->od->router_ports) && !lsp_is_router(op->nbsp)
         && strcmp(op->nbsp->type, "virtual")) {
         /* This is a logical switch port that backs a VM or a container.
          * Extract its addresses. For each of the address, go through all
@@ -14825,12 +14810,11 @@ build_arp_resolve_flows_for_lsp(
             const char *ea_s = op->lsp_addrs[i].ea_s;
             for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs; j++) {
                 const char *ip_s = op->lsp_addrs[i].ipv4_addrs[j].addr_s;
-                for (size_t k = 0; k < op->od->n_router_ports; k++) {
+                VECTOR_FOR_EACH (&op->od->router_ports, rp) {
                     /* Get the Logical_Router_Port that the
                      * Logical_Switch_Port is connected to, as
                      * 'peer'. */
-                    struct ovn_port *peer = ovn_port_get_peer(
-                            lr_ports, op->od->router_ports[k]);
+                    struct ovn_port *peer = ovn_port_get_peer(lr_ports, rp);
                     if (!peer || !peer->nbrp) {
                         continue;
                     }
@@ -14857,12 +14841,11 @@ build_arp_resolve_flows_for_lsp(
 
             for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) {
                 const char *ip_s = op->lsp_addrs[i].ipv6_addrs[j].addr_s;
-                for (size_t k = 0; k < op->od->n_router_ports; k++) {
+                VECTOR_FOR_EACH (&op->od->router_ports, rp) {
                     /* Get the Logical_Router_Port that the
                      * Logical_Switch_Port is connected to, as
                      * 'peer'. */
-                    struct ovn_port *peer = ovn_port_get_peer(
-                            lr_ports, op->od->router_ports[k]);
+                    struct ovn_port *peer = ovn_port_get_peer(lr_ports, rp);
                     if (!peer || !peer->nbrp) {
                         continue;
                     }
@@ -14904,10 +14887,8 @@ build_arp_resolve_flows_for_lsp(
                           "dynamic_neigh_routers", false)) {
             return;
         }
-
-        for (size_t i = 0; i < op->od->n_router_ports; i++) {
-            struct ovn_port *router_port =
-                ovn_port_get_peer(lr_ports, op->od->router_ports[i]);
+        VECTOR_FOR_EACH (&op->od->router_ports, rp) {
+            struct ovn_port *router_port = ovn_port_get_peer(lr_ports,  rp);
             if (!router_port || !router_port->nbrp) {
                 continue;
             }
@@ -15165,8 +15146,9 @@ build_gateway_redirect_flows_for_lrouter(
         struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
-    for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
-        if (l3dgw_port_has_associated_vtep_lports(od->l3dgw_ports[i])) {
+    const struct ovn_port *dgp;
+    VECTOR_FOR_EACH (&od->l3dgw_ports, dgp) {
+        if (l3dgw_port_has_associated_vtep_lports(dgp)) {
             /* Skip adding redirect lflow for vtep-enabled l3dgw ports.
              * Traffic from hypervisor to VTEP (ramp) switch should go in
              * distributed manner. Only returning routed traffic must go
@@ -15179,8 +15161,8 @@ build_gateway_redirect_flows_for_lrouter(
 
         const struct ovsdb_idl_row *stage_hint = NULL;
 
-        if (od->l3dgw_ports[i]->nbrp) {
-            stage_hint = &od->l3dgw_ports[i]->nbrp->header_;
+        if (dgp->nbrp) {
+            stage_hint = &dgp->nbrp->header_;
         }
 
         /* For traffic with outport == l3dgw_port, if the
@@ -15188,11 +15170,9 @@ build_gateway_redirect_flows_for_lrouter(
          * rule, then the traffic is redirected to the central
          * instance of the l3dgw_port. */
         ds_clear(match);
-        ds_put_format(match, "outport == %s",
-                      od->l3dgw_ports[i]->json_key);
+        ds_put_format(match, "outport == %s", dgp->json_key);
         ds_clear(actions);
-        ds_put_format(actions, "outport = %s; next;",
-                      od->l3dgw_ports[i]->cr_port->json_key);
+        ds_put_format(actions, "outport = %s; next;", dgp->cr_port->json_key);
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_GW_REDIRECT, 50,
                                 ds_cstr(match), ds_cstr(actions),
                                 stage_hint, lflow_ref);
@@ -15211,8 +15191,9 @@ build_lr_gateway_redirect_flows_for_nats(
         struct lflow_ref *lflow_ref)
 {
     ovs_assert(od->nbr);
-    for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
-        if (l3dgw_port_has_associated_vtep_lports(od->l3dgw_ports[i])) {
+    const struct ovn_port *dgp;
+    VECTOR_FOR_EACH (&od->l3dgw_ports, dgp) {
+        if (l3dgw_port_has_associated_vtep_lports(dgp)) {
             /* Skip adding redirect lflow for vtep-enabled l3dgw ports.
              * Traffic from hypervisor to VTEP (ramp) switch should go in
              * distributed manner. Only returning routed traffic must go
@@ -15235,8 +15216,8 @@ build_lr_gateway_redirect_flows_for_nats(
 
             const struct ovsdb_idl_row *stage_hint = NULL;
 
-            if (od->l3dgw_ports[i]->nbrp) {
-                stage_hint = &od->l3dgw_ports[i]->nbrp->header_;
+            if (dgp->nbrp) {
+                stage_hint = &dgp->nbrp->header_;
             }
 
             struct ds match_ext = DS_EMPTY_INITIALIZER;
@@ -15823,7 +15804,7 @@ build_ipv6_input_flows_for_lrouter_port(
     }
 
     /* UDP/TCP/SCTP port unreachable */
-    if (!op->od->is_gw_router && !op->od->n_l3dgw_ports) {
+    if (!op->od->is_gw_router && vector_is_empty(&op->od->l3dgw_ports)) {
         for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) {
             ds_clear(match);
             ds_put_format(match,
@@ -16087,8 +16068,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
                       op->lrp_networks.ipv4_addrs[i].network_s,
                       op->lrp_networks.ipv4_addrs[i].plen);
 
-        if (op->od->n_l3dgw_ports && op->peer
-            && op->peer->od->n_localnet_ports) {
+        if (!vector_is_empty(&op->od->l3dgw_ports) && op->peer
+            && !vector_is_empty(&op->peer->od->localnet_ports)) {
             bool add_chassis_resident_check = false;
             const char *json_key;
             if (lrp_is_l3dgw(op)) {
@@ -16111,8 +16092,9 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
                 add_chassis_resident_check = smap_get_bool(
                     &op->nbrp->options,
                     "reside-on-redirect-chassis", false) &&
-                    op->od->n_l3dgw_ports == 1;
-                json_key = op->od->l3dgw_ports[0]->cr_port->json_key;
+                    vector_len(&op->od->l3dgw_ports) == 1;
+                json_key = vector_get(&op->od->l3dgw_ports, 0,
+                                      struct ovn_port *)->cr_port->json_key;
             }
 
             if (add_chassis_resident_check) {
@@ -16127,7 +16109,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
                                &op->nbrp->header_, lflows, lflow_ref);
     }
 
-    if (!op->od->is_gw_router && !op->od->n_l3dgw_ports) {
+    if (!op->od->is_gw_router && vector_is_empty(&op->od->l3dgw_ports)) {
         /* UDP/TCP/SCTP port unreachable. */
         for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) {
             ds_clear(match);
@@ -16321,7 +16303,7 @@ build_lrouter_in_unsnat_match(const struct ovn_datapath 
*od,
         /* Traffic received on l3dgw_port is subject to NAT. */
         ds_put_format(match, " && inport == %s", l3dgw_port->json_key);
 
-        if (!distributed_nat && od->n_l3dgw_ports) {
+        if (!distributed_nat && !vector_is_empty(&od->l3dgw_ports)) {
             /* Flows for NAT rules that are centralized are only
              * programmed on the gateway chassis. */
             ds_put_format(match, " && is_chassis_resident(%s)",
@@ -16459,7 +16441,7 @@ build_lrouter_in_dnat_flow(struct lflow_table *lflows,
 
         /* Traffic received on l3dgw_port is subject to NAT. */
         ds_put_format(match, " && inport == %s", l3dgw_port->json_key);
-        if (!distributed_nat && od->n_l3dgw_ports) {
+        if (!distributed_nat && !vector_is_empty(&od->l3dgw_ports)) {
             /* Flows for NAT rules that are centralized are only
             * programmed on the gateway chassis. */
             ds_put_format(match, " && is_chassis_resident(%s)",
@@ -16509,7 +16491,7 @@ build_lrouter_out_undnat_flow(struct lflow_table 
*lflows,
     *
     * Note that this only applies for NAT on a distributed router.
     */
-    if (!od->n_l3dgw_ports ||
+    if (vector_is_empty(&od->l3dgw_ports) ||
         !(nat_entry->type == DNAT || nat_entry->type == DNAT_AND_SNAT)) {
         return;
     }
@@ -16521,7 +16503,7 @@ build_lrouter_out_undnat_flow(struct lflow_table 
*lflows,
     ds_put_format(match, "ip && ip%c.src == %s && outport == %s",
                   is_v6 ? '6' : '4', nat->logical_ip,
                   l3dgw_port->json_key);
-    if (!distributed_nat && od->n_l3dgw_ports) {
+    if (!distributed_nat && !vector_is_empty(&od->l3dgw_ports)) {
         /* Flows for NAT rules that are centralized are only
         * programmed on the gateway chassis. */
         ds_put_format(match, " && is_chassis_resident(%s)",
@@ -16556,7 +16538,7 @@ build_lrouter_out_is_dnat_local(struct lflow_table 
*lflows,
 {
     /* Note that this only applies for NAT on a distributed router.
      */
-    if (!od->n_l3dgw_ports) {
+    if (vector_is_empty(&od->l3dgw_ports)) {
         return;
     }
 
@@ -16601,7 +16583,7 @@ build_lrouter_out_snat_match(struct lflow_table *lflows,
         ds_put_format(match, " && %s == %s",
                       is_reverse ? "inport" : "outport",
                       l3dgw_port->json_key);
-        if (od->n_l3dgw_ports) {
+        if (!vector_is_empty(&od->l3dgw_ports)) {
             ds_put_format(match, " && is_chassis_resident(\"%s\")",
                           distributed_nat
                           ? nat->logical_port
@@ -16871,7 +16853,7 @@ build_lrouter_ingress_flow(struct lflow_table *lflows,
                            struct lflow_ref *lflow_ref)
 {
     const struct nbrec_nat *nat = nat_entry->nb;
-    if (od->n_l3dgw_ports && nat_entry->type == SNAT) {
+    if (!vector_is_empty(&od->l3dgw_ports) && nat_entry->type == SNAT) {
         ds_clear(match);
         ds_put_format(
             match, "inport == %s && %s == %s",
@@ -17011,7 +16993,7 @@ build_dgp_lrouter_commit_all(const struct ovn_datapath 
*od,
                              const struct chassis_features *features,
                              struct ds *match, struct lflow_ref *lflow_ref)
 {
-    ovs_assert(od->n_l3dgw_ports);
+    ovs_assert(!vector_is_empty(&od->l3dgw_ports));
     if (!(features->ct_commit_to_zone && features->ct_next_zone)) {
         return;
     }
@@ -17155,7 +17137,7 @@ build_lrouter_nat_defrag_and_lb(
     /* NAT rules are only valid on Gateway routers and routers with
      * l3dgw_ports (router has port(s) with gateway chassis
      * specified). */
-    if (!od->is_gw_router && !od->n_l3dgw_ports) {
+    if (!od->is_gw_router && vector_is_empty(&od->l3dgw_ports)) {
         return;
     }
 
@@ -17262,7 +17244,8 @@ build_lrouter_nat_defrag_and_lb(
                             match,
                             "outport == %s && ip%s.src == %s "
                             "&& is_chassis_resident(\"%s\")",
-                            od->l3dgw_ports[0]->json_key,
+                            vector_get(&od->l3dgw_ports, 0,
+                                       const struct ovn_port *)->json_key,
                             is_v6 ? "6" : "4", nat->logical_ip,
                             nat->logical_port);
                     ds_clear(actions);
@@ -17375,7 +17358,7 @@ build_lrouter_nat_defrag_and_lb(
          * gateway port have ip.dst matching a NAT external IP, then
          * loop a clone of the packet back to the beginning of the
          * ingress pipeline with inport = outport. */
-        if (od->n_l3dgw_ports) {
+        if (!vector_is_empty(&od->l3dgw_ports)) {
             /* Distributed router. */
             ds_clear(match);
             ds_put_format(match, "ip%s.dst == %s && outport == %s",
@@ -17441,10 +17424,10 @@ build_lrouter_nat_defrag_and_lb(
             build_gw_lrouter_commit_all(od, lflows, features, lflow_ref);
         }
 
-        for (size_t i = 0; i < od->n_l3dgw_ports; i++) {
-            struct ovn_port *l3dgw_port = od->l3dgw_ports[i];
-            build_dgp_lrouter_commit_all(od, l3dgw_port, lflows,
-                                         features, match, lflow_ref);
+        const struct ovn_port *dgp;
+        VECTOR_FOR_EACH (&od->l3dgw_ports, dgp) {
+            build_dgp_lrouter_commit_all(od, dgp, lflows, features,
+                                         match, lflow_ref);
         }
     }
 
@@ -17548,8 +17531,9 @@ build_routable_flows_for_router_port(
     struct ovn_port_routable_addresses ra =
         get_op_routable_addresses(lrp, lr_stateful_rec);
 
-    for (size_t i = 0; i < peer_ls->n_router_ports; i++) {
-        struct ovn_port *router_port = peer_ls->router_ports[i]->peer;
+    struct ovn_port *op;
+    VECTOR_FOR_EACH (&peer_ls->router_ports, op) {
+        struct ovn_port *router_port = op->peer;
         struct lport_addresses *lrpaddrs = &router_port->lrp_networks;
         char *router_port_lla_s = NULL;
 
@@ -19513,12 +19497,13 @@ collect_lr_groups_for_ha_chassis_groups(const struct 
sbrec_port_binding *sb,
                                         struct hmapx *lr_groups)
 {
     struct lrouter_group *lr_group = NULL;
-    for (size_t i = 0; i < op->od->n_router_ports; i++) {
-        if (!op->od->router_ports[i]->peer) {
+    struct ovn_port *rp;
+    VECTOR_FOR_EACH (&op->od->router_ports, rp) {
+        if (!rp->peer) {
             continue;
         }
 
-        lr_group = op->od->router_ports[i]->peer->od->lr_group;
+        lr_group = rp->peer->od->lr_group;
         /* If a logical switch has multiple router ports, then
          * all the logical routers belong to the same logical
          * router group. */
diff --git a/northd/northd.h b/northd/northd.h
index d5294e9bf..5a698458f 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -26,6 +26,7 @@
 #include "simap.h"
 #include "ovs-thread.h"
 #include "en-lr-stateful.h"
+#include "vec.h"
 
 struct northd_input {
     /* Northbound table references */
@@ -365,15 +366,11 @@ struct ovn_datapath {
     uint32_t tunnel_key;
 
     /* Logical router data. */
-    struct ovn_datapath **ls_peers;
-    size_t n_ls_peers;
-    size_t n_allocated_ls_peers;
+    struct vector ls_peers; /* Vector of struct ovn_datapath *. */
     struct sset router_ips; /* Router port IPs except the IPv6 LLAs. */
 
     /* Logical switch data. */
-    struct ovn_port **router_ports;
-    size_t n_router_ports;
-    size_t n_allocated_router_ports;
+    struct vector router_ports; /* Vector of struct ovn_port *. */
 
     struct hmap port_tnlids;
     uint32_t port_key_hint;
@@ -402,9 +399,7 @@ struct ovn_datapath {
      * populated only when there is a gateway chassis or ha chassis group
      * specified for some of the ports on the logical router. Otherwise this
      * will be NULL. */
-    struct ovn_port **l3dgw_ports;
-    size_t n_l3dgw_ports;
-    size_t n_allocated_l3dgw_ports;
+    struct vector l3dgw_ports; /* Vector of struct ovn_port *. */
 
     /* router datapath has a logical port with redirect-type set to bridged. */
     bool redirect_bridged;
@@ -413,9 +408,7 @@ struct ovn_datapath {
     /* The modes contained in the nbr option "dynamic-routing-redistribute". */
     enum dynamic_routing_redistribute_mode dynamic_routing_redistribute;
 
-    struct ovn_port **localnet_ports;
-    size_t n_localnet_ports;
-    size_t n_allocated_localnet_ports;
+    struct vector localnet_ports; /* Vector of struct ovn_port *. */
 
     struct ovs_list lr_list; /* In list of logical router datapaths. */
     /* The logical router group to which this datapath belongs.
@@ -971,7 +964,7 @@ bool lrouter_port_ipv6_reachable(const struct ovn_port *,
 static inline bool
 lr_has_multiple_gw_ports(const struct ovn_datapath *od)
 {
-    return od->n_l3dgw_ports > 1 && !od->is_gw_router;
+    return vector_len(&od->l3dgw_ports) > 1 && !od->is_gw_router;
 }
 
 bool
-- 
2.49.0

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

Reply via email to