Message ID | 20231026181504.3367058-1-numans@ovn.org |
---|---|
State | Changes Requested |
Headers | show |
Series | northd lflow incremental processing | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | warning | apply and check: warning |
ovsrobot/github-robot-_Build_and_Test | success | github build: passed |
ovsrobot/github-robot-_ovn-kubernetes | success | github build: passed |
On Thu, Oct 26, 2023 at 11:16 AM <numans@ovn.org> wrote: > > From: Numan Siddique <numans@ovn.org> > > This new engine now maintains the load balancer and NAT data of a > logical router which was earlier part of northd engine node data. > The main inputs to this engine are: > - northd node > - lr-nat node nit: According to the implementation, the node has lb_data as input, too. Thanks, Han > > A record for each logical router is maintained in the 'lr_lb_nats' > hmap table and this record > - stores the lb related data > - embeds the 'lr-nat' record. > > This engine node becomes an input to 'lflow' node. > > Signed-off-by: Numan Siddique <numans@ovn.org> > --- > lib/stopwatch-names.h | 1 + > northd/automake.mk | 2 + > northd/en-lflow.c | 4 + > northd/en-lr-lb-nat-data.c | 654 +++++++++++++++++++++++++++++++++++++ > northd/en-lr-lb-nat-data.h | 93 ++++++ > northd/en-lr-nat.h | 3 + > northd/en-sync-sb.c | 50 +-- > northd/inc-proc-northd.c | 13 +- > northd/northd.c | 640 ++++++++++++------------------------ > northd/northd.h | 137 +++++++- > tests/ovn-northd.at | 110 +++++-- > 11 files changed, 1212 insertions(+), 495 deletions(-) > create mode 100644 northd/en-lr-lb-nat-data.c > create mode 100644 northd/en-lr-lb-nat-data.h > > diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h > index 0a16da211e..7d85acdaea 100644 > --- a/lib/stopwatch-names.h > +++ b/lib/stopwatch-names.h > @@ -33,5 +33,6 @@ > #define PORT_GROUP_RUN_STOPWATCH_NAME "port_group_run" > #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" > #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" > +#define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" > > #endif > diff --git a/northd/automake.mk b/northd/automake.mk > index ae367a2a8b..4116c487df 100644 > --- a/northd/automake.mk > +++ b/northd/automake.mk > @@ -26,6 +26,8 @@ northd_ovn_northd_SOURCES = \ > northd/en-lb-data.h \ > northd/en-lr-nat.c \ > northd/en-lr-nat.h \ > + northd/en-lr-lb-nat-data.c \ > + northd/en-lr-lb-nat-data.h \ > northd/inc-proc-northd.c \ > northd/inc-proc-northd.h \ > northd/ipam.c \ > diff --git a/northd/en-lflow.c b/northd/en-lflow.c > index 22f398d419..9cb0ead3f0 100644 > --- a/northd/en-lflow.c > +++ b/northd/en-lflow.c > @@ -20,6 +20,7 @@ > > #include "en-lflow.h" > #include "en-lr-nat.h" > +#include "en-lr-lb-nat-data.h" > #include "en-northd.h" > #include "en-meters.h" > > @@ -43,6 +44,8 @@ lflow_get_input_data(struct engine_node *node, > engine_get_input_data("sync_meters", node); > struct ed_type_lr_nat_data *lr_nat_data = > engine_get_input_data("lr_nat", node); > + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > + engine_get_input_data("lr_lb_nat_data", node); > > lflow_input->nbrec_bfd_table = > EN_OVSDB_GET(engine_get_input("NB_bfd", node)); > @@ -66,6 +69,7 @@ lflow_get_input_data(struct engine_node *node, > lflow_input->lr_ports = &northd_data->lr_ports; > lflow_input->ls_port_groups = &pg_data->ls_port_groups; > lflow_input->lr_nats = &lr_nat_data->lr_nats; > + lflow_input->lr_lbnats = &lr_lb_nat_data->lr_lbnats; > lflow_input->meter_groups = &sync_meters_data->meter_groups; > lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map; > lflow_input->svc_monitor_map = &northd_data->svc_monitor_map; > diff --git a/northd/en-lr-lb-nat-data.c b/northd/en-lr-lb-nat-data.c > new file mode 100644 > index 0000000000..19b638ce0b > --- /dev/null > +++ b/northd/en-lr-lb-nat-data.c > @@ -0,0 +1,654 @@ > +/* > + * Copyright (c) 2023, Red Hat, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#include <config.h> > + > +#include <getopt.h> > +#include <stdlib.h> > +#include <stdio.h> > + > +/* OVS includes */ > +#include "include/openvswitch/hmap.h" > +#include "lib/bitmap.h" > +#include "lib/socket-util.h" > +#include "lib/uuidset.h" > +#include "openvswitch/util.h" > +#include "openvswitch/vlog.h" > +#include "stopwatch.h" > + > +/* OVN includes */ > +#include "en-lb-data.h" > +#include "en-lr-lb-nat-data.h" > +#include "en-lr-nat.h" > +#include "lib/inc-proc-eng.h" > +#include "lib/lb.h" > +#include "lib/ovn-nb-idl.h" > +#include "lib/ovn-sb-idl.h" > +#include "lib/ovn-util.h" > +#include "lib/stopwatch-names.h" > +#include "northd.h" > + > +VLOG_DEFINE_THIS_MODULE(en_lr_lb_nat_data); > + > +/* Static function declarations. */ > +static void lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *); > +static void lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *); > +static void lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *); > +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_( > + const struct lr_lb_nat_data_table *, const struct nbrec_logical_router *); > +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index_( > + const struct lr_lb_nat_data_table *table, size_t od_index); > + > +static void lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *, > + const struct lr_nat_table *, > + const struct ovn_datapaths *lr_datapaths, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map); > + > +static struct lr_lb_nat_data_input lr_lb_nat_data_get_input_data( > + struct engine_node *); > + > +static struct lr_lb_nat_data_record *lr_lb_nat_data_record_create( > + struct lr_lb_nat_data_table *, const struct lr_nat_record *, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map); > +static void lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *); > +static void lr_lb_nat_data_record_init( > + struct lr_lb_nat_data_record *, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map); > + > +static void build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, > + const struct ovn_northd_lb *); > +static void add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *, > + enum lb_neighbor_responder_mode, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6); > +static void remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, > + enum lb_neighbor_responder_mode, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6); > +static void lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *); > + > +/* 'lr_lb_nat_data' engine node manages the NB logical router LB data. > + */ > +void * > +en_lr_lb_nat_data_init(struct engine_node *node OVS_UNUSED, > + struct engine_arg *arg OVS_UNUSED) > +{ > + struct ed_type_lr_lb_nat_data *data = xzalloc(sizeof *data); > + lr_lb_nat_data_table_init(&data->lr_lbnats); > + hmapx_init(&data->tracked_data.crupdated); > + hmapx_init(&data->tracked_data.deleted); > + return data; > +} > + > +void > +en_lr_lb_nat_data_cleanup(void *data_) > +{ > + struct ed_type_lr_lb_nat_data *data = > + (struct ed_type_lr_lb_nat_data *) data_; > + lr_lb_nat_data_table_destroy(&data->lr_lbnats); > + hmapx_destroy(&data->tracked_data.crupdated); > + hmapx_destroy(&data->tracked_data.deleted); > +} > + > +void > +en_lr_lb_nat_data_clear_tracked_data(void *data_) > +{ > + struct ed_type_lr_lb_nat_data *data = > + (struct ed_type_lr_lb_nat_data *) data_; > + > + struct hmapx_node *hmapx_node; > + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { > + lr_lb_nat_data_record_destroy(hmapx_node->data); > + hmapx_delete(&data->tracked_data.deleted, hmapx_node); > + } > + > + hmapx_clear(&data->tracked_data.crupdated); > + data->tracked = false; > +} > + > +void > +en_lr_lb_nat_data_run(struct engine_node *node, void *data_) > +{ > + struct lr_lb_nat_data_input input_data = > + lr_lb_nat_data_get_input_data(node); > + struct ed_type_lr_lb_nat_data *data = data_; > + > + stopwatch_start(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); > + > + lr_lb_nat_data_table_clear(&data->lr_lbnats); > + lr_lb_nat_data_table_build(&data->lr_lbnats, input_data.lr_nats, > + input_data.lr_datapaths, > + input_data.lb_datapaths_map, > + input_data.lbgrp_datapaths_map); > + > + stopwatch_stop(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); > + engine_set_node_state(node, EN_UPDATED); > +} > + > +bool > +lr_lb_nat_data_northd_handler(struct engine_node *node, void *data OVS_UNUSED) > +{ > + struct northd_data *northd_data = engine_get_input_data("northd", node); > + if (!northd_data->change_tracked) { > + return false; > + } > + > + return true; > +} > + > +bool > +lr_lb_nat_data_lb_data_handler(struct engine_node *node, void *data_) > +{ > + struct ed_type_lb_data *lb_data = engine_get_input_data("lb_data", node); > + if (!lb_data->tracked) { > + return false; > + } > + > + struct ed_type_lr_lb_nat_data *data = > + (struct ed_type_lr_lb_nat_data *) data_; > + struct lr_lb_nat_data_input input_data = > + lr_lb_nat_data_get_input_data(node); > + struct lr_lb_nat_data_record *lr_lbnat_rec; > + size_t index; > + > + const struct tracked_lb_data *trk_lb_data = &lb_data->tracked_lb_data; > + const struct ovn_lb_group_datapaths *lbgrp_dps; > + const struct crupdated_lbgrp *crupdated_lbgrp; > + const struct crupdated_od_lb_data *codlb; > + const struct ovn_lb_datapaths *lb_dps; > + const struct crupdated_lb *clb; > + const struct ovn_northd_lb *lb; > + const struct ovn_datapath *od; > + > + LIST_FOR_EACH (codlb, list_node, &trk_lb_data->crupdated_lr_lbs) { > + od = ovn_datapath_find(&input_data.lr_datapaths->datapaths, > + &codlb->od_uuid); > + ovs_assert(od); > + > + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, od->nbr); > + if (!lr_lbnat_rec) { > + const struct lr_nat_record *lrnat_rec = lr_nat_table_find_by_index( > + input_data.lr_nats, od->index); > + ovs_assert(lrnat_rec); > + > + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, > + lrnat_rec, > + input_data.lb_datapaths_map, > + input_data.lbgrp_datapaths_map); > + > + /* Add the lr_lbnat_rec rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > + continue; > + } > + > + struct uuidset_node *uuidnode; > + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbs) { > + lb_dps = ovn_lb_datapaths_find( > + input_data.lb_datapaths_map, &uuidnode->uuid); > + ovs_assert(lb_dps); > + > + /* Add the lb_ips of lb_dps to the od. */ > + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > + } > + > + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbgrps) { > + lbgrp_dps = ovn_lb_group_datapaths_find( > + input_data.lbgrp_datapaths_map, &uuidnode->uuid); > + ovs_assert(lbgrp_dps); > + > + for (size_t j = 0; j < lbgrp_dps->lb_group->n_lbs; j++) { > + const struct uuid *lb_uuid > + = &lbgrp_dps->lb_group->lbs[j]->nlb->header_.uuid; > + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, > + lb_uuid); > + ovs_assert(lb_dps); > + > + /* Add the lb_ips of lb_dps to the od. */ > + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > + } > + } > + > + /* Add the lr_lbnat_rec rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > + } > + > + HMAP_FOR_EACH (clb, hmap_node, &trk_lb_data->crupdated_lbs) { > + lb = clb->lb; > + const struct uuid *lb_uuid = &lb->nlb->header_.uuid; > + > + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, lb_uuid); > + ovs_assert(lb_dps); > + > + BITMAP_FOR_EACH_1 (index, ods_size(input_data.lr_datapaths), > + lb_dps->nb_lr_map) { > + od = input_data.lr_datapaths->array[index]; > + > + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, > + od->nbr); > + ovs_assert(lr_lbnat_rec); > + > + /* Update the od->lb_ips with the deleted and inserted > + * vips (if any). */ > + remove_ips_from_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, > + &clb->deleted_vips_v4, > + &clb->deleted_vips_v6); > + add_ips_to_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, > + &clb->inserted_vips_v4, > + &clb->inserted_vips_v6); > + > + remove_lrouter_lb_reachable_ips(lr_lbnat_rec, lb->neigh_mode, > + &clb->deleted_vips_v4, > + &clb->deleted_vips_v6); > + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, > + &clb->inserted_vips_v4, > + &clb->inserted_vips_v6); > + > + /* Add the lr_lbnat_rec rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > + } > + } > + > + HMAP_FOR_EACH (crupdated_lbgrp, hmap_node, > + &trk_lb_data->crupdated_lbgrps) { > + const struct uuid *lb_uuid = &crupdated_lbgrp->lbgrp->uuid; > + > + lbgrp_dps = ovn_lb_group_datapaths_find(input_data.lbgrp_datapaths_map, > + lb_uuid); > + ovs_assert(lbgrp_dps); > + > + struct hmapx_node *hnode; > + HMAPX_FOR_EACH (hnode, &crupdated_lbgrp->assoc_lbs) { > + lb = hnode->data; > + lb_uuid = &lb->nlb->header_.uuid; > + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, > + lb_uuid); > + ovs_assert(lb_dps); > + for (size_t i = 0; i < lbgrp_dps->n_lr; i++) { > + od = lbgrp_dps->lr[i]; > + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, > + od->nbr); > + ovs_assert(lr_lbnat_rec); > + /* Add the lb_ips of lb_dps to the lr lb data. */ > + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > + > + /* Add the lr_lbnat_rec rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > + } > + } > + } > + > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > + struct hmapx_node *hmapx_node; > + /* For all the modified lr_lb_nat_data records (re)build the > + * vip nats. */ > + HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { > + lr_lb_nat_data_build_vip_nats(hmapx_node->data); > + } > + > + data->tracked = true; > + engine_set_node_state(node, EN_UPDATED); > + } > + > + return true; > +} > + > +bool > +lr_lb_nat_data_lr_nat_handler(struct engine_node *node, void *data_) > +{ > + struct ed_type_lr_nat_data *lr_nat_data = > + engine_get_input_data("lr_nat", node); > + > + if (!lr_nat_data->tracked > + || !hmapx_is_empty(&lr_nat_data->tracked_data.deleted)) { > + return false; > + } > + > + struct ed_type_lr_lb_nat_data *data = > + (struct ed_type_lr_lb_nat_data *) data_; > + struct lr_lb_nat_data_input input_data = > + lr_lb_nat_data_get_input_data(node); > + const struct lr_nat_record *lrnat_rec; > + struct lr_lb_nat_data_record *lr_lbnat_rec; > + struct hmapx_node *hmapx_node; > + > + HMAPX_FOR_EACH (hmapx_node, &lr_nat_data->tracked_data.crupdated) { > + lrnat_rec = hmapx_node->data; > + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, > + lrnat_rec->od->nbr); > + if (!lr_lbnat_rec) { > + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, > + lrnat_rec, > + input_data.lb_datapaths_map, > + input_data.lbgrp_datapaths_map); > + } else { > + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > + } > + > + /* Add the lr_lbnat_rec rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > + } > + > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > + data->tracked = true; > + engine_set_node_state(node, EN_UPDATED); > + } > + > + return true; > +} > + > +const struct lr_lb_nat_data_record * > +lr_lb_nat_data_table_find_by_index(const struct lr_lb_nat_data_table *table, > + size_t od_index) > +{ > + return lr_lb_nat_data_table_find_by_index_(table, od_index); > +} > + > +/* static functions. */ > +static void > +lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *table) > +{ > + *table = (struct lr_lb_nat_data_table) { > + .entries = HMAP_INITIALIZER(&table->entries), > + }; > +} > + > +static void > +lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *table) > +{ > + lr_lb_nat_data_table_clear(table); > + hmap_destroy(&table->entries); > +} > + > +static void > +lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *table) > +{ > + struct lr_lb_nat_data_record *lr_lbnat_rec; > + HMAP_FOR_EACH_POP (lr_lbnat_rec, key_node, &table->entries) { > + lr_lb_nat_data_record_destroy(lr_lbnat_rec); > + } > + > + free(table->array); > + table->array = NULL; > +} > + > +static void > +lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *table, > + const struct lr_nat_table *lr_nats, > + const struct ovn_datapaths *lr_datapaths, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map) > +{ > + table->array = xrealloc(table->array, > + ods_size(lr_datapaths) * sizeof *table->array); > + const struct lr_nat_record *lrnat_rec; > + LR_NAT_TABLE_FOR_EACH (lrnat_rec, lr_nats) { > + lr_lb_nat_data_record_create(table, lrnat_rec, lb_datapaths_map, > + lbgrp_datapaths_map); > + } > +} > + > +static struct lr_lb_nat_data_record * > +lr_lb_nat_data_table_find_(const struct lr_lb_nat_data_table *table, > + const struct nbrec_logical_router *nbr) > +{ > + struct lr_lb_nat_data_record *lr_lbnat_rec; > + > + HMAP_FOR_EACH_WITH_HASH (lr_lbnat_rec, key_node, > + uuid_hash(&nbr->header_.uuid), &table->entries) { > + if (nbr == lr_lbnat_rec->od->nbr) { > + return lr_lbnat_rec; > + } > + } > + return NULL; > +} > + > +static struct lr_lb_nat_data_record * > +lr_lb_nat_data_table_find_by_index_(const struct lr_lb_nat_data_table *table, > + size_t od_index) > +{ > + ovs_assert(od_index <= hmap_count(&table->entries)); > + return table->array[od_index]; > +} > + > +static struct lr_lb_nat_data_record * > +lr_lb_nat_data_record_create(struct lr_lb_nat_data_table *table, > + const struct lr_nat_record *lrnat_rec, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map) > +{ > + struct lr_lb_nat_data_record *lr_lbnat_rec = xzalloc(sizeof *lr_lbnat_rec); > + lr_lbnat_rec->lrnat_rec = lrnat_rec; > + lr_lbnat_rec->od = lrnat_rec->od; > + lr_lb_nat_data_record_init(lr_lbnat_rec, lb_datapaths_map, > + lbgrp_datapaths_map); > + > + hmap_insert(&table->entries, &lr_lbnat_rec->key_node, > + uuid_hash(&lr_lbnat_rec->od->nbr->header_.uuid)); > + > + table->array[lr_lbnat_rec->od->index] = lr_lbnat_rec; > + return lr_lbnat_rec; > +} > + > +static void > +lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *lr_lbnat_rec) > +{ > + ovn_lb_ip_set_destroy(lr_lbnat_rec->lb_ips); > + lr_lbnat_rec->lb_ips = NULL; > + sset_destroy(&lr_lbnat_rec->vip_nats); > + free(lr_lbnat_rec); > +} > + > +static void > +lr_lb_nat_data_record_init(struct lr_lb_nat_data_record *lr_lbnat_rec, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map) > +{ > + const struct nbrec_load_balancer_group *nbrec_lb_group; > + const struct ovn_lb_group_datapaths *lb_group_dps; > + const struct ovn_lb_datapaths *lb_dps; > + > + /* Checking load balancer groups first, starting from the largest one, > + * to more efficiently copy IP sets. */ > + size_t largest_group = 0; > + > + const struct nbrec_logical_router *nbr = lr_lbnat_rec->od->nbr; > + for (size_t i = 1; i < nbr->n_load_balancer_group; i++) { > + if (nbr->load_balancer_group[i]->n_load_balancer > > + nbr->load_balancer_group[largest_group]->n_load_balancer) { > + largest_group = i; > + } > + } > + > + for (size_t i = 0; i < nbr->n_load_balancer_group; i++) { > + size_t idx = (i + largest_group) % nbr->n_load_balancer_group; > + > + nbrec_lb_group = nbr->load_balancer_group[idx]; > + const struct uuid *lbgrp_uuid = &nbrec_lb_group->header_.uuid; > + > + lb_group_dps = > + ovn_lb_group_datapaths_find(lbgrp_datapaths_map, > + lbgrp_uuid); > + ovs_assert(lb_group_dps); > + > + if (!lr_lbnat_rec->lb_ips) { > + lr_lbnat_rec->lb_ips = > + ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); > + } else { > + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, > + lb_group_dps->lb_group->lbs[j]); > + } > + } > + > + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > + build_lrouter_lb_reachable_ips(lr_lbnat_rec, > + lb_group_dps->lb_group->lbs[j]); > + } > + } > + > + if (!lr_lbnat_rec->lb_ips) { > + lr_lbnat_rec->lb_ips = ovn_lb_ip_set_create(); > + } > + > + for (size_t i = 0; i < nbr->n_load_balancer; i++) { > + const struct uuid *lb_uuid = > + &nbr->load_balancer[i]->header_.uuid; > + lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); > + ovs_assert(lb_dps); > + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > + } > + > + sset_init(&lr_lbnat_rec->vip_nats); > + > + if (!nbr->n_nat) { > + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > + } > +} > + > +static struct lr_lb_nat_data_input > +lr_lb_nat_data_get_input_data(struct engine_node *node) > +{ > + struct northd_data *northd_data = engine_get_input_data("northd", node); > + struct ed_type_lr_nat_data *lr_nat_data = > + engine_get_input_data("lr_nat", node); > + > + return (struct lr_lb_nat_data_input) { > + .lr_datapaths = &northd_data->lr_datapaths, > + .lb_datapaths_map = &northd_data->lb_datapaths_map, > + .lbgrp_datapaths_map = &northd_data->lb_group_datapaths_map, > + .lr_nats = &lr_nat_data->lr_nats, > + }; > +} > + > +static void > +build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, > + const struct ovn_northd_lb *lb) > +{ > + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, &lb->ips_v4, > + &lb->ips_v6); > +} > + > +static void > +add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *lr_lbnat_rec, > + enum lb_neighbor_responder_mode neigh_mode, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6) > +{ > + /* If configured to not reply to any neighbor requests for all VIPs > + * return early. > + */ > + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > + return; > + } > + > + const char *ip_address; > + > + /* If configured to reply to neighbor requests for all VIPs force them > + * all to be considered "reachable". > + */ > + if (neigh_mode == LB_NEIGH_RESPOND_ALL) { > + SSET_FOR_EACH (ip_address, lb_ips_v4) { > + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, ip_address); > + } > + SSET_FOR_EACH (ip_address, lb_ips_v6) { > + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, ip_address); > + } > + > + return; > + } > + > + /* Otherwise, a VIP is reachable if there's at least one router > + * subnet that includes it. > + */ > + ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); > + > + SSET_FOR_EACH (ip_address, lb_ips_v4) { > + struct ovn_port *op; > + ovs_be32 vip_ip4; > + if (ip_parse(ip_address, &vip_ip4)) { > + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { > + if (lrouter_port_ipv4_reachable(op, vip_ip4)) { > + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, > + ip_address); > + break; > + } > + } > + } > + } > + > + SSET_FOR_EACH (ip_address, lb_ips_v6) { > + struct ovn_port *op; > + struct in6_addr vip; > + if (ipv6_parse(ip_address, &vip)) { > + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { > + if (lrouter_port_ipv6_reachable(op, &vip)) { > + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, > + ip_address); > + break; > + } > + } > + } > + } > +} > + > +static void > +remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, > + enum lb_neighbor_responder_mode neigh_mode, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6) > +{ > + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > + return; > + } > + > + const char *ip_address; > + SSET_FOR_EACH (ip_address, lb_ips_v4) { > + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v4_reachable, > + ip_address); > + } > + SSET_FOR_EACH (ip_address, lb_ips_v6) { > + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v6_reachable, > + ip_address); > + } > +} > + > +static void > +lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *lr_lbnat_rec) > +{ > + sset_clear(&lr_lbnat_rec->vip_nats); > + const char *external_ip; > + SSET_FOR_EACH (external_ip, &lr_lbnat_rec->lrnat_rec->external_ips) { > + bool is_vip_nat = false; > + if (addr_is_ipv6(external_ip)) { > + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, > + external_ip); > + } else { > + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, > + external_ip); > + } > + > + if (is_vip_nat) { > + sset_add(&lr_lbnat_rec->vip_nats, external_ip); > + } > + } > +} > diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h > new file mode 100644 > index 0000000000..9029aee339 > --- /dev/null > +++ b/northd/en-lr-lb-nat-data.h > @@ -0,0 +1,93 @@ > +/* > + * Copyright (c) 2023, Red Hat, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > +#ifndef EN_LR_LB_NAT_DATA_H > +#define EN_LR_LB_NAT_DATA_H 1 > + > +#include <stdint.h> > + > +/* OVS includes. */ > +#include "lib/hmapx.h" > +#include "openvswitch/hmap.h" > +#include "sset.h" > + > +/* OVN includes. */ > +#include "lib/inc-proc-eng.h" > +#include "lib/lb.h" > +#include "lib/ovn-nb-idl.h" > +#include "lib/ovn-sb-idl.h" > +#include "lib/ovn-util.h" > + > +struct ovn_datapath; > +struct lr_nat_record; > + > +struct lr_lb_nat_data_record { > + struct hmap_node key_node; /* Index on 'nbr->header_.uuid'. */ > + > + const struct ovn_datapath *od; > + const struct lr_nat_record *lrnat_rec; > + > + /* Load Balancer vIPs relevant for this datapath. */ > + struct ovn_lb_ip_set *lb_ips; > + > + /* sset of vips which are also part of lr nats. */ > + struct sset vip_nats; > +}; > + > +struct lr_lb_nat_data_table { > + struct hmap entries; > + > + /* The array index of each element in 'entries'. */ > + struct lr_lb_nat_data_record **array; > +}; > + > +#define LR_LB_NAT_DATA_TABLE_FOR_EACH(LR_LB_NAT_REC, TABLE) \ > + HMAP_FOR_EACH (LR_LB_NAT_REC, key_node, &(TABLE)->entries) > + > +struct lr_lb_nat_data_tracked_data { > + /* Created or updated logical router with LB data. */ > + struct hmapx crupdated; /* Stores 'struct lr_lb_nat_data_record'. */ > + > + /* Deleted logical router with LB data. */ > + struct hmapx deleted; /* Stores 'struct lr_lb_nat_data_record'. */ > +}; > + > +struct ed_type_lr_lb_nat_data { > + struct lr_lb_nat_data_table lr_lbnats; > + > + bool tracked; > + struct lr_lb_nat_data_tracked_data tracked_data; > +}; > + > +struct lr_lb_nat_data_input { > + const struct ovn_datapaths *lr_datapaths; > + const struct hmap *lb_datapaths_map; > + const struct hmap *lbgrp_datapaths_map; > + const struct lr_nat_table *lr_nats; > +}; > + > +void *en_lr_lb_nat_data_init(struct engine_node *, struct engine_arg *); > +void en_lr_lb_nat_data_cleanup(void *data); > +void en_lr_lb_nat_data_clear_tracked_data(void *data); > +void en_lr_lb_nat_data_run(struct engine_node *, void *data); > + > +bool lr_lb_nat_data_northd_handler(struct engine_node *, void *data); > +bool lr_lb_nat_data_lr_nat_handler(struct engine_node *, void *data); > +bool lr_lb_nat_data_lb_data_handler(struct engine_node *, void *data); > + > +const struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index( > + const struct lr_lb_nat_data_table *, size_t od_index); > + > +#endif /* EN_LR_LB_NAT_DATA_H */ > \ No newline at end of file > diff --git a/northd/en-lr-nat.h b/northd/en-lr-nat.h > index 01a16a21aa..2e3f285d12 100644 > --- a/northd/en-lr-nat.h > +++ b/northd/en-lr-nat.h > @@ -89,6 +89,9 @@ struct lr_nat_table { > const struct lr_nat_record * lr_nat_table_find_by_index( > const struct lr_nat_table *, size_t od_index); > > +#define LR_NAT_TABLE_FOR_EACH(LR_NAT_REC, TABLE) \ > + HMAP_FOR_EACH (LR_NAT_REC, key_node, &(TABLE)->entries) > + > /* Incremental processing implementation. */ > struct lr_nat_input { > /* Northbound table references. */ > diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c > index 10ade620e7..7c22949f74 100644 > --- a/northd/en-sync-sb.c > +++ b/northd/en-sync-sb.c > @@ -22,6 +22,7 @@ > #include "openvswitch/util.h" > > #include "en-lr-nat.h" > +#include "en-lr-lb-nat-data.h" > #include "en-sync-sb.h" > #include "lib/inc-proc-eng.h" > #include "lib/lb.h" > @@ -41,7 +42,7 @@ static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > const struct nbrec_address_set_table *, > const struct nbrec_port_group_table *, > const struct sbrec_address_set_table *, > - const struct ovn_datapaths *lr_datapaths); > + const struct lr_lb_nat_data_table *); > static const struct sbrec_address_set *sb_address_set_lookup_by_name( > struct ovsdb_idl_index *, const char *name); > static void update_sb_addr_set(struct sorted_array *, > @@ -87,11 +88,11 @@ en_sync_to_sb_addr_set_run(struct engine_node *node, void *data OVS_UNUSED) > EN_OVSDB_GET(engine_get_input("SB_address_set", node)); > > const struct engine_context *eng_ctx = engine_get_context(); > - struct northd_data *northd_data = engine_get_input_data("northd", node); > - > + const struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > + engine_get_input_data("lr_lb_nat_data", node); > sync_addr_sets(eng_ctx->ovnsb_idl_txn, nb_address_set_table, > nb_port_group_table, sb_address_set_table, > - &northd_data->lr_datapaths); > + &lr_lb_nat_data->lr_lbnats); > > engine_set_node_state(node, EN_UPDATED); > } > @@ -288,10 +289,12 @@ en_sync_to_sb_pb_run(struct engine_node *node, void *data OVS_UNUSED) > { > const struct engine_context *eng_ctx = engine_get_context(); > struct northd_data *northd_data = engine_get_input_data("northd", node); > - struct ed_type_lr_nat_data *lr_nat_data = > - engine_get_input_data("lr_nat", node); > + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > + engine_get_input_data("lr_lb_nat_data", node); > + > sync_pbs(eng_ctx->ovnsb_idl_txn, &northd_data->ls_ports, > - &northd_data->lr_ports, &lr_nat_data->lr_nats); > + &northd_data->lr_ports, > + &lr_lb_nat_data->lr_lbnats); > engine_set_node_state(node, EN_UPDATED); > } > > @@ -316,11 +319,12 @@ sync_to_sb_pb_northd_handler(struct engine_node *node, void *data OVS_UNUSED) > return false; > } > > - struct ed_type_lr_nat_data *lr_nat_data = > - engine_get_input_data("lr_nat", node); > + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > + engine_get_input_data("lr_lb_nat_data", node); > > if (!sync_pbs_for_northd_changed_ovn_ports( > - &nd->trk_northd_changes.trk_ovn_ports, &lr_nat_data->lr_nats)) { > + &nd->trk_northd_changes.trk_ovn_ports, > + &lr_lb_nat_data->lr_lbnats)) { > return false; > } > > @@ -366,7 +370,7 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > const struct nbrec_address_set_table *nb_address_set_table, > const struct nbrec_port_group_table *nb_port_group_table, > const struct sbrec_address_set_table *sb_address_set_table, > - const struct ovn_datapaths *lr_datapaths) > + const struct lr_lb_nat_data_table *lr_lbnats) > { > struct shash sb_address_sets = SHASH_INITIALIZER(&sb_address_sets); > > @@ -410,16 +414,14 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > } > > /* Sync router load balancer VIP generated address sets. */ > - struct ovn_datapath *od; > - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { > - ovs_assert(od->nbr); > - > - if (sset_count(&od->lb_ips->ips_v4_reachable)) { > - char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key, > - AF_INET); > + const struct lr_lb_nat_data_record *lrlb_rec; > + LR_LB_NAT_DATA_TABLE_FOR_EACH (lrlb_rec, lr_lbnats) { > + if (sset_count(&lrlb_rec->lb_ips->ips_v4_reachable)) { > + char *ipv4_addrs_name = > + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET); > > struct sorted_array ipv4_addrs_sorted = > - sorted_array_from_sset(&od->lb_ips->ips_v4_reachable); > + sorted_array_from_sset(&lrlb_rec->lb_ips->ips_v4_reachable); > > sync_addr_set(ovnsb_txn, ipv4_addrs_name, > &ipv4_addrs_sorted, &sb_address_sets); > @@ -427,11 +429,11 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > free(ipv4_addrs_name); > } > > - if (sset_count(&od->lb_ips->ips_v6_reachable)) { > - char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key, > - AF_INET6); > - struct sorted_array ipv6_addrs_sorted = > - sorted_array_from_sset(&od->lb_ips->ips_v6_reachable); > + if (sset_count(&lrlb_rec->lb_ips->ips_v6_reachable)) { > + char *ipv6_addrs_name = > + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET6); > + struct sorted_array ipv6_addrs_sorted = sorted_array_from_sset( > + &lrlb_rec->lb_ips->ips_v6_reachable); > > sync_addr_set(ovnsb_txn, ipv6_addrs_name, > &ipv6_addrs_sorted, &sb_address_sets); > diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c > index 2bd66b8808..369a151fa3 100644 > --- a/northd/inc-proc-northd.c > +++ b/northd/inc-proc-northd.c > @@ -31,6 +31,7 @@ > #include "openvswitch/vlog.h" > #include "inc-proc-northd.h" > #include "en-lb-data.h" > +#include "en-lr-lb-nat-data.h" > #include "en-lr-nat.h" > #include "en-northd.h" > #include "en-lflow.h" > @@ -148,6 +149,7 @@ static ENGINE_NODE(sync_to_sb_lb, "sync_to_sb_lb"); > static ENGINE_NODE(sync_to_sb_pb, "sync_to_sb_pb"); > static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data"); > static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_nat, "lr_nat"); > +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_lb_nat_data, "lr_lb_nat_data"); > > void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > struct ovsdb_idl_loop *sb) > @@ -196,6 +198,13 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_lr_nat, &en_nb_logical_router, > lr_nat_logical_router_handler); > > + engine_add_input(&en_lr_lb_nat_data, &en_northd, > + lr_lb_nat_data_northd_handler); > + engine_add_input(&en_lr_lb_nat_data, &en_lr_nat, > + lr_lb_nat_data_lr_nat_handler); > + engine_add_input(&en_lr_lb_nat_data, &en_lb_data, > + lr_lb_nat_data_lb_data_handler); > + > engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL); > engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL); > engine_add_input(&en_mac_binding_aging, &en_northd, NULL); > @@ -220,12 +229,14 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); > engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); > engine_add_input(&en_lflow, &en_lr_nat, NULL); > + engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); > > engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, > sync_to_sb_addr_set_nb_address_set_handler); > engine_add_input(&en_sync_to_sb_addr_set, &en_nb_port_group, > sync_to_sb_addr_set_nb_port_group_handler); > engine_add_input(&en_sync_to_sb_addr_set, &en_northd, NULL); > + engine_add_input(&en_sync_to_sb_addr_set, &en_lr_lb_nat_data, NULL); > engine_add_input(&en_sync_to_sb_addr_set, &en_sb_address_set, NULL); > > engine_add_input(&en_port_group, &en_nb_port_group, > @@ -243,7 +254,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > > engine_add_input(&en_sync_to_sb_pb, &en_northd, > sync_to_sb_pb_northd_handler); > - engine_add_input(&en_sync_to_sb_pb, &en_lr_nat, NULL); > + engine_add_input(&en_sync_to_sb_pb, &en_lr_lb_nat_data, NULL); > > /* en_sync_to_sb engine node syncs the SB database tables from > * the NB database tables. > diff --git a/northd/northd.c b/northd/northd.c > index 44c9c3d729..24df14c0de 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -44,6 +44,7 @@ > #include "northd.h" > #include "en-lb-data.h" > #include "en-lr-nat.h" > +#include "en-lr-lb-nat-data.h" > #include "lib/ovn-parallel-hmap.h" > #include "ovn/actions.h" > #include "ovn/features.h" > @@ -617,13 +618,6 @@ init_lb_for_datapath(struct ovn_datapath *od) > } > } > > -static void > -destroy_lb_for_datapath(struct ovn_datapath *od) > -{ > - ovn_lb_ip_set_destroy(od->lb_ips); > - od->lb_ips = NULL; > -} > - > /* A group of logical router datapaths which are connected - either > * directly or indirectly. > * Each logical router can belong to only one group. */ > @@ -676,7 +670,6 @@ ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od) > destroy_ipam_info(&od->ipam_info); > free(od->router_ports); > free(od->ls_peers); > - destroy_lb_for_datapath(od); > free(od->localnet_ports); > free(od->l3dgw_ports); > destroy_mcast_info_for_datapath(od); > @@ -1311,121 +1304,6 @@ struct lflow_ref_node { > struct ovn_lflow *lflow; > }; > > -/* A logical switch port or logical router port. > - * > - * In steady state, an ovn_port points to a northbound Logical_Switch_Port > - * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a > - * southbound Port_Binding record (via 'sb'). As the state of the system > - * changes, join_logical_ports() may determine that there is a new LSP or LRP > - * that has no corresponding Port_Binding record (in which case build_ports()) > - * will create the missing Port_Binding) or that a Port_Binding record exists > - * that has no coresponding LSP (in which case build_ports() will delete the > - * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port > - * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. > - * > - * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but > - * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). > - */ > -struct ovn_port { > - /* Port name aka key. > - * > - * This is ordinarily the same as nbsp->name or nbrp->name and > - * sb->logical_port. (A distributed gateway port creates a "derived" > - * ovn_port with key "cr-%s" % nbrp->name.) */ > - struct hmap_node key_node; /* Index on 'key'. */ > - char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ > - char *json_key; /* 'key', quoted for use in JSON. */ > - > - const struct sbrec_port_binding *sb; /* May be NULL. */ > - > - uint32_t tunnel_key; > - > - /* Logical switch port data. */ > - const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ > - > - struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ > - unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ > - unsigned int n_lsp_non_router_addrs; /* Number of elements from the > - * beginning of 'lsp_addrs' extracted > - * directly from LSP 'addresses'. */ > - > - struct lport_addresses *ps_addrs; /* Port security addresses. */ > - unsigned int n_ps_addrs; > - > - bool lsp_can_be_inc_processed; /* If it can be incrementally processed when > - the port changes. */ > - > - /* Logical router port data. */ > - const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ > - > - struct lport_addresses lrp_networks; > - > - struct ovn_port_routable_addresses routables; > - > - /* Logical port multicast data. */ > - struct mcast_port_info mcast_info; > - > - /* At most one of l3dgw_port and cr_port can be not NULL. */ > - > - /* This is set to a distributed gateway port if and only if this ovn_port > - * is "derived" from it. Otherwise this is set to NULL. The derived > - * ovn_port represents the instance of distributed gateway port on the > - * gateway chassis.*/ > - struct ovn_port *l3dgw_port; > - > - /* This is set to the "derived" chassis-redirect port of this port if and > - * only if this port is a distributed gateway port. Otherwise this is set > - * to NULL. */ > - struct ovn_port *cr_port; > - > - bool has_unknown; /* If the addresses have 'unknown' defined. */ > - > - bool has_bfd; > - > - /* The port's peer: > - * > - * - A switch port S of type "router" has a router port R as a peer, > - * and R in turn has S has its peer. > - * > - * - Two connected logical router ports have each other as peer. > - * > - * - Other kinds of ports have no peer. */ > - struct ovn_port *peer; > - > - struct ovn_datapath *od; > - > - struct ovs_list list; /* In list of similar records. */ > - > - struct hmap_node dp_node; /* Node in od->ports. */ > - > - struct lport_addresses proxy_arp_addrs; > - > - /* Temporarily used for traversing a list (or hmap) of ports. */ > - bool visited; > - > - /* List of struct lflow_ref_node that points to the lflows generated by > - * this ovn_port. > - * > - * This data is initialized and destroyed by the en_northd node, but > - * populated and used only by the en_lflow node. Ideally this data should > - * be maintained as part of en_lflow's data (struct lflow_data): a hash > - * index from ovn_port key to lflows. However, it would be less efficient > - * and more complex: > - * > - * 1. It would require an extra search (using the index) to find the > - * lflows. > - * > - * 2. Building the index needs to be thread-safe, using either a global > - * lock which is obviously less efficient, or hash-based lock array which > - * is more complex. > - * > - * Adding the list here is more straightforward. The drawback is that we > - * need to keep in mind that this data belongs to en_lflow node, so never > - * access it from any other nodes. > - */ > - struct ovs_list lflows; > -}; > - > static bool lsp_can_be_inc_processed(const struct nbrec_logical_switch_port *); > > static bool > @@ -1450,16 +1328,21 @@ destroy_routable_addresses(struct ovn_port_routable_addresses *ra) > } > > static char **get_nat_addresses(const struct ovn_port *op, size_t *n, > - bool routable_only, bool include_lb_ips); > + bool routable_only, bool include_lb_ips, > + const struct lr_lb_nat_data_record *); > > -static void > -assign_routable_addresses(struct ovn_port *op) > +static struct ovn_port_routable_addresses > +get_op_routable_addresses(struct ovn_port *op, > + const struct lr_lb_nat_data_record *lr_lbnat_rec) > { > size_t n; > - char **nats = get_nat_addresses(op, &n, true, true); > + char **nats = get_nat_addresses(op, &n, true, true, lr_lbnat_rec); > > if (!nats) { > - return; > + return (struct ovn_port_routable_addresses) { > + .laddrs = NULL, > + .n_addrs = 0, > + }; > } > > struct lport_addresses *laddrs = xcalloc(n, sizeof(*laddrs)); > @@ -1475,9 +1358,15 @@ assign_routable_addresses(struct ovn_port *op) > } > free(nats); > > - /* Everything seems to have worked out */ > - op->routables.laddrs = laddrs; > - op->routables.n_addrs = n_addrs; > + if (!n_addrs) { > + free(laddrs); > + laddrs = NULL; > + } > + > + return (struct ovn_port_routable_addresses) { > + .laddrs = laddrs, > + .n_addrs = n_addrs, > + }; > } > > > @@ -1537,8 +1426,6 @@ ovn_port_destroy_orphan(struct ovn_port *port) > } > free(port->ps_addrs); > > - destroy_routable_addresses(&port->routables); > - > destroy_lport_addresses(&port->lrp_networks); > destroy_lport_addresses(&port->proxy_arp_addrs); > free(port->json_key); > @@ -2580,9 +2467,7 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, > sizeof *od->l3dgw_ports); > } > od->l3dgw_ports[od->n_l3dgw_ports++] = op; > - > - assign_routable_addresses(op); > - } > + } > } > } > > @@ -2679,7 +2564,8 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, > * and must free the returned array when it is no longer needed. */ > static char ** > get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, > - bool include_lb_ips) > + bool include_lb_ips, > + const struct lr_lb_nat_data_record *lr_lbnat_rec) > { > size_t n_nats = 0; > struct eth_addr mac; > @@ -2764,23 +2650,25 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, > } > } > > - if (include_lb_ips) { > + if (include_lb_ips && lr_lbnat_rec) { > const char *ip_address; > if (routable_only) { > - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4_routable) { > + SSET_FOR_EACH (ip_address, > + &lr_lbnat_rec->lb_ips->ips_v4_routable) { > ds_put_format(&c_addresses, " %s", ip_address); > central_ip_address = true; > } > - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6_routable) { > + SSET_FOR_EACH (ip_address, > + &lr_lbnat_rec->lb_ips->ips_v6_routable) { > ds_put_format(&c_addresses, " %s", ip_address); > central_ip_address = true; > } > } else { > - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4) { > + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v4) { > ds_put_format(&c_addresses, " %s", ip_address); > central_ip_address = true; > } > - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6) { > + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v6) { > ds_put_format(&c_addresses, " %s", ip_address); > central_ip_address = true; > } > @@ -3851,21 +3739,8 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, > HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { > ovs_assert(od->nbr); > > - /* Checking load balancer groups first, starting from the largest one, > - * to more efficiently copy IP sets. */ > - size_t largest_group = 0; > - > - for (size_t i = 1; i < od->nbr->n_load_balancer_group; i++) { > - if (od->nbr->load_balancer_group[i]->n_load_balancer > > - od->nbr->load_balancer_group[largest_group]->n_load_balancer) { > - largest_group = i; > - } > - } > - > for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { > - size_t idx = (i + largest_group) % od->nbr->n_load_balancer_group; > - > - nbrec_lb_group = od->nbr->load_balancer_group[idx]; > + nbrec_lb_group = od->nbr->load_balancer_group[i]; > const struct uuid *lb_group_uuid = &nbrec_lb_group->header_.uuid; > > lb_group_dps = > @@ -3873,20 +3748,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, > lb_group_uuid); > ovs_assert(lb_group_dps); > ovn_lb_group_datapaths_add_lr(lb_group_dps, od); > - > - if (!od->lb_ips) { > - od->lb_ips = > - ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); > - } else { > - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > - build_lrouter_lb_ips(od->lb_ips, > - lb_group_dps->lb_group->lbs[j]); > - } > - } > - } > - > - if (!od->lb_ips) { > - od->lb_ips = ovn_lb_ip_set_create(); > } > > for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { > @@ -3895,7 +3756,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, > lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); > ovs_assert(lb_dps); > ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > } > } > > @@ -3949,102 +3809,6 @@ build_lb_svcs( > } > } > > -static bool lrouter_port_ipv4_reachable(const struct ovn_port *op, > - ovs_be32 addr); > -static bool lrouter_port_ipv6_reachable(const struct ovn_port *op, > - const struct in6_addr *addr); > - > -static void > -add_neigh_ips_to_lrouter(struct ovn_datapath *od, > - enum lb_neighbor_responder_mode neigh_mode, > - const struct sset *lb_ips_v4, > - const struct sset *lb_ips_v6) > -{ > - /* If configured to not reply to any neighbor requests for all VIPs > - * return early. > - */ > - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > - return; > - } > - > - const char *ip_address; > - > - /* If configured to reply to neighbor requests for all VIPs force them > - * all to be considered "reachable". > - */ > - if (neigh_mode == LB_NEIGH_RESPOND_ALL) { > - SSET_FOR_EACH (ip_address, lb_ips_v4) { > - sset_add(&od->lb_ips->ips_v4_reachable, ip_address); > - } > - SSET_FOR_EACH (ip_address, lb_ips_v6) { > - sset_add(&od->lb_ips->ips_v6_reachable, ip_address); > - } > - > - return; > - } > - > - /* Otherwise, a VIP is reachable if there's at least one router > - * subnet that includes it. > - */ > - ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); > - > - SSET_FOR_EACH (ip_address, lb_ips_v4) { > - struct ovn_port *op; > - ovs_be32 vip_ip4; > - if (ip_parse(ip_address, &vip_ip4)) { > - HMAP_FOR_EACH (op, dp_node, &od->ports) { > - if (lrouter_port_ipv4_reachable(op, vip_ip4)) { > - sset_add(&od->lb_ips->ips_v4_reachable, > - ip_address); > - break; > - } > - } > - } > - } > - > - SSET_FOR_EACH (ip_address, lb_ips_v6) { > - struct ovn_port *op; > - struct in6_addr vip; > - if (ipv6_parse(ip_address, &vip)) { > - HMAP_FOR_EACH (op, dp_node, &od->ports) { > - if (lrouter_port_ipv6_reachable(op, &vip)) { > - sset_add(&od->lb_ips->ips_v6_reachable, > - ip_address); > - break; > - } > - } > - } > - } > -} > - > -static void > -remove_lrouter_lb_reachable_ips(struct ovn_datapath *od, > - enum lb_neighbor_responder_mode neigh_mode, > - const struct sset *lb_ips_v4, > - const struct sset *lb_ips_v6) > -{ > - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > - return; > - } > - > - const char *ip_address; > - SSET_FOR_EACH (ip_address, lb_ips_v4) { > - sset_find_and_delete(&od->lb_ips->ips_v4_reachable, ip_address); > - } > - SSET_FOR_EACH (ip_address, lb_ips_v6) { > - sset_find_and_delete(&od->lb_ips->ips_v6_reachable, ip_address); > - } > -} > - > -static void > -build_lrouter_lb_reachable_ips(struct ovn_datapath *od, > - const struct ovn_northd_lb *lb) > -{ > - add_neigh_ips_to_lrouter(od, lb->neigh_mode, &lb->ips_v4, > - &lb->ips_v6); > -} > - > - > static void > build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) > { > @@ -4066,43 +3830,6 @@ build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) > } > } > > -static void > -build_lrouter_lbs_reachable_ips(struct ovn_datapaths *lr_datapaths, > - struct hmap *lb_dps_map, > - struct hmap *lb_group_dps_map) > -{ > - struct ovn_datapath *od; > - > - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { > - if (!od->nbr) { > - continue; > - } > - > - for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { > - struct ovn_lb_datapaths *lb_dps = > - ovn_lb_datapaths_find(lb_dps_map, > - &od->nbr->load_balancer[i]->header_.uuid); > - ovs_assert(lb_dps); > - build_lrouter_lb_reachable_ips(od, lb_dps->lb); > - } > - > - for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { > - const struct nbrec_load_balancer_group *nbrec_lb_group = > - od->nbr->load_balancer_group[i]; > - struct ovn_lb_group_datapaths *lb_group_dps; > - > - lb_group_dps = > - ovn_lb_group_datapaths_find(lb_group_dps_map, > - &nbrec_lb_group->header_.uuid); > - ovs_assert(lb_group_dps); > - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > - build_lrouter_lb_reachable_ips(od, > - lb_group_dps->lb_group->lbs[j]); > - } > - } > - } > -} > - > static void > build_lswitch_lbs_from_lrouter(struct ovn_datapaths *lr_datapaths, > struct hmap *lb_dps_map, > @@ -4166,8 +3893,6 @@ build_lb_port_related_data( > struct hmap *svc_monitor_map) > { > build_lrouter_lbs_check(lr_datapaths); > - build_lrouter_lbs_reachable_ips(lr_datapaths, lb_dps_map, > - lb_group_dps_map); > build_lb_svcs(ovnsb_txn, sbrec_service_monitor_table, ls_ports, lb_dps_map, > svc_monitor_lsps, svc_monitor_map); > build_lswitch_lbs_from_lrouter(lr_datapaths, lb_dps_map, lb_group_dps_map); > @@ -4533,7 +4258,8 @@ check_sb_lb_duplicates(const struct sbrec_load_balancer_table *table) > * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it > * only syncs the nat column of port binding corresponding to the 'op->nbsp' */ > static void > -sync_pb_for_lsp(struct ovn_port *op) > +sync_pb_for_lsp(struct ovn_port *op, > + const struct lr_lb_nat_data_table *lr_lbnats) > { > ovs_assert(op->nbsp); > > @@ -4552,10 +4278,17 @@ sync_pb_for_lsp(struct ovn_port *op) > if (nat_addresses && !strcmp(nat_addresses, "router")) { > if (op->peer && op->peer->od > && (chassis || op->peer->od->n_l3dgw_ports)) { > - bool exclude_lb_vips = smap_get_bool(&op->nbsp->options, > + bool include_lb_vips = !smap_get_bool(&op->nbsp->options, > "exclude-lb-vips-from-garp", false); > + > + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; > + > + if (include_lb_vips) { > + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index( > + lr_lbnats, op->peer->od->index); > + } > nats = get_nat_addresses(op->peer, &n_nats, false, > - !exclude_lb_vips); > + include_lb_vips, lr_lbnat_rec); > } > } else if (nat_addresses && (chassis || l3dgw_ports)) { > struct lport_addresses laddrs; > @@ -4662,7 +4395,8 @@ sync_pb_for_lsp(struct ovn_port *op) > * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it > * only sets the port binding options column for the router ports */ > static void > -sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) > +sync_pb_for_lrp(struct ovn_port *op, > + const struct lr_lb_nat_data_table *lr_lbnats) > { > ovs_assert(op->nbrp); > > @@ -4671,14 +4405,14 @@ sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) > > const char *chassis_name = smap_get(&op->od->nbr->options, "chassis"); > if (is_cr_port(op)) { > - const struct lr_nat_record *lrnat_rec = > - lr_nat_table_find_by_index(lr_nats, op->od->index); > - ovs_assert(lrnat_rec); > + const struct lr_lb_nat_data_record *lr_lbnat_rec = > + lr_lb_nat_data_table_find_by_index(lr_lbnats, op->od->index); > + ovs_assert(lr_lbnat_rec); > > smap_add(&new, "distributed-port", op->nbrp->name); > > bool always_redirect = > - !lrnat_rec->has_distributed_nat && > + !lr_lbnat_rec->lrnat_rec->has_distributed_nat && > !l3dgw_port_has_associated_vtep_lports(op->l3dgw_port); > > const char *redirect_type = smap_get(&op->nbrp->options, > @@ -4729,17 +4463,18 @@ static void ovn_update_ipv6_opt_for_op(struct ovn_port *op); > * the logical switch ports. */ > void > sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, > - struct hmap *lr_ports, const struct lr_nat_table *lr_nats) > + struct hmap *lr_ports, > + const struct lr_lb_nat_data_table *lr_lbnats) > { > ovs_assert(ovnsb_idl_txn); > > struct ovn_port *op; > HMAP_FOR_EACH (op, key_node, ls_ports) { > - sync_pb_for_lsp(op); > + sync_pb_for_lsp(op, lr_lbnats); > } > > HMAP_FOR_EACH (op, key_node, lr_ports) { > - sync_pb_for_lrp(op, lr_nats); > + sync_pb_for_lrp(op, lr_lbnats); > } > > ovn_update_ipv6_options(lr_ports); > @@ -4748,17 +4483,18 @@ sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, > /* Sync the SB Port bindings for the added and updated logical switch ports > * of the tracked northd engine data. */ > bool > -sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, > - const struct lr_nat_table *lr_nats) > +sync_pbs_for_northd_changed_ovn_ports( > + struct tracked_ovn_ports *trk_ovn_ports, > + const struct lr_lb_nat_data_table *lr_lbnats) > { > struct hmapx_node *hmapx_node; > struct ovn_port *op; > HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->created) { > op = hmapx_node->data; > if (op->nbsp) { > - sync_pb_for_lsp(op); > + sync_pb_for_lsp(op, lr_lbnats); > } else { > - sync_pb_for_lrp(op, lr_nats); > + sync_pb_for_lrp(op, lr_lbnats); > ovn_update_ipv6_opt_for_op(op); > } > } > @@ -4766,9 +4502,9 @@ sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, > HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->updated) { > op = hmapx_node->data; > if (op->nbsp) { > - sync_pb_for_lsp(op); > + sync_pb_for_lsp(op, lr_lbnats); > } else { > - sync_pb_for_lrp(op, lr_nats); > + sync_pb_for_lrp(op, lr_lbnats); > ovn_update_ipv6_opt_for_op(op); > } > } > @@ -5475,20 +5211,24 @@ fail: > } > > /* Returns true if the logical router has changes which can be > - * incrementally handled. > + * incrementally handled or the changes can be ignored. > * Presently supports i-p for the below changes: > * - load balancers and load balancer groups. > + * > + * Presently below changes are ignored: > + * - router NAT changes - as the engine node lr-nat handles it. > */ > static bool > -lr_changes_can_be_handled( > +lr_changes_can_be_handled_or_ignored( > const struct nbrec_logical_router *lr) > { > /* Check if the columns are changed in this row. */ > enum nbrec_logical_router_column_id col; > for (col = 0; col < NBREC_LOGICAL_ROUTER_N_COLUMNS; col++) { > if (nbrec_logical_router_is_updated(lr, col)) { > - if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER || > - col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP) { > + if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER > + || col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP > + || col == NBREC_LOGICAL_ROUTER_COL_NAT) { > continue; > } > return false; > @@ -5507,12 +5247,6 @@ lr_changes_can_be_handled( > OVSDB_IDL_CHANGE_MODIFY) > 0) { > return false; > } > - for (size_t i = 0; i < lr->n_nat; i++) { > - if (nbrec_nat_row_get_seqno(lr->nat[i], > - OVSDB_IDL_CHANGE_MODIFY) > 0) { > - return false; > - } > - } > for (size_t i = 0; i < lr->n_policies; i++) { > if (nbrec_logical_router_policy_row_get_seqno(lr->policies[i], > OVSDB_IDL_CHANGE_MODIFY) > 0) { > @@ -5528,14 +5262,15 @@ lr_changes_can_be_handled( > return true; > } > > -/* Return true if changes are handled incrementally, false otherwise. > +/* Return true if changes are handled incrementally or can be safely > + * ignored (because those changes are handled by other engine nodes), > + * false otherwise. > * When there are any changes, try to track what's exactly changed and set > * northd_data->change_tracked accordingly: change tracked - true, otherwise, > * false. > * Note: Changes to load balancer and load balancer groups associated with > * the logical routers are handled separately in the lb_data change > - * handlers (northd_handle_lb_data_changes_pre_od and > - * northd_handle_lb_data_changes_post_od). > + * handler (northd_handle_lb_data_changes). > * */ > bool > northd_handle_lr_changes(const struct northd_input *ni, > @@ -5550,9 +5285,11 @@ northd_handle_lr_changes(const struct northd_input *ni, > goto fail; > } > > - /* Presently only able to handle load balancer and > - * load balancer group changes. */ > - if (!lr_changes_can_be_handled(changed_lr)) { > + /* Presently > + * - only able to handle load balancer and load balancer group > + changes. > + * - and ignore NAT changes */ > + if (!lr_changes_can_be_handled_or_ignored(changed_lr)) { > goto fail; > } > } > @@ -5804,10 +5541,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > ovs_assert(lb_dps); > ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > > - /* Add the lb_ips of lb_dps to the od. */ > - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > - build_lrouter_lb_reachable_ips(od, lb_dps->lb); > - > /* Add the lb to the northd tracked data. */ > hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); > } > @@ -5826,10 +5559,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > ovs_assert(lb_dps); > ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > > - /* Add the lb_ips of lb_dps to the od. */ > - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > - build_lrouter_lb_reachable_ips(od, lb_dps->lb); > - > /* Add the lb to the northd tracked data. */ > hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); > } > @@ -5865,22 +5594,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > /* Re-evaluate 'od->has_lb_vip' */ > init_lb_for_datapath(od); > > - /* Update the od->lb_ips with the deleted and inserted > - * vips (if any). */ > - remove_ips_from_lb_ip_set(od->lb_ips, lb->routable, > - &clb->deleted_vips_v4, > - &clb->deleted_vips_v6); > - add_ips_to_lb_ip_set(od->lb_ips, lb->routable, > - &clb->inserted_vips_v4, > - &clb->inserted_vips_v6); > - > - remove_lrouter_lb_reachable_ips(od, lb->neigh_mode, > - &clb->deleted_vips_v4, > - &clb->deleted_vips_v6); > - add_neigh_ips_to_lrouter(od, lb->neigh_mode, > - &clb->inserted_vips_v4, > - &clb->inserted_vips_v6); > - > /* Add the lr datapath to the northd tracked data. */ > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > } > @@ -5908,9 +5621,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > /* Re-evaluate 'od->has_lb_vip' */ > init_lb_for_datapath(od); > > - /* Add the lb_ips of lb_dps to the od. */ > - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > - > /* Add the lr datapath to the northd tracked data. */ > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > } > @@ -9202,7 +8912,7 @@ arp_nd_ns_match(const char *ips, int addr_family, struct ds *match) > /* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the > * IPs configured on the router port. > */ > -static bool > +bool > lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) > { > for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > @@ -9218,7 +8928,7 @@ lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) > /* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the > * IPs configured on the router port. > */ > -static bool > +bool > lrouter_port_ipv6_reachable(const struct ovn_port *op, > const struct in6_addr *addr) > { > @@ -9284,6 +8994,7 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, > struct ovn_datapath *sw_od, > struct ovn_port *sw_op, > const struct lr_nat_table *lr_nats, > + const struct lr_lb_nat_data_table *lr_lbnats, > struct hmap *lflows, > const struct ovsdb_idl_row *stage_hint) > { > @@ -9299,32 +9010,38 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, > * router port. > * Priority: 80. > */ > - > - const char *ip_addr; > - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v4_reachable) { > - ovs_be32 ipv4_addr; > - > - /* Check if the ovn port has a network configured on which we could > - * expect ARP requests for the LB VIP. > - */ > - if (ip_parse(ip_addr, &ipv4_addr) && > - lrouter_port_ipv4_reachable(op, ipv4_addr)) { > - build_lswitch_rport_arp_req_flow( > - ip_addr, AF_INET, sw_op, sw_od, 80, lflows, > - stage_hint); > + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; > + if (op->od->nbr->n_load_balancer || op->od->nbr->n_load_balancer_group) { > + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, > + op->od->index); > + ovs_assert(lr_lbnat_rec); > + > + const char *ip_addr; > + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v4_reachable) { > + ovs_be32 ipv4_addr; > + > + /* Check if the ovn port has a network configured on which we could > + * expect ARP requests for the LB VIP. > + */ > + if (ip_parse(ip_addr, &ipv4_addr) && > + lrouter_port_ipv4_reachable(op, ipv4_addr)) { > + build_lswitch_rport_arp_req_flow( > + ip_addr, AF_INET, sw_op, sw_od, 80, lflows, > + stage_hint); > + } > } > - } > - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v6_reachable) { > - struct in6_addr ipv6_addr; > + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v6_reachable) { > + struct in6_addr ipv6_addr; > > - /* Check if the ovn port has a network configured on which we could > - * expect NS requests for the LB VIP. > - */ > - if (ipv6_parse(ip_addr, &ipv6_addr) && > - lrouter_port_ipv6_reachable(op, &ipv6_addr)) { > - build_lswitch_rport_arp_req_flow( > - ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, > - stage_hint); > + /* Check if the ovn port has a network configured on which we could > + * expect NS requests for the LB VIP. > + */ > + if (ipv6_parse(ip_addr, &ipv6_addr) && > + lrouter_port_ipv6_reachable(op, &ipv6_addr)) { > + build_lswitch_rport_arp_req_flow( > + ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, > + stage_hint); > + } > } > } > > @@ -9374,13 +9091,15 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, > * expect ARP requests/NS for the DNAT external_ip. > */ > if (nat_entry_is_v6(nat_entry)) { > - if (!sset_contains(&op->od->lb_ips->ips_v6, nat->external_ip)) { > + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, > + nat->external_ip)) { > build_lswitch_rport_arp_req_flow( > nat->external_ip, AF_INET6, sw_op, sw_od, 80, lflows, > stage_hint); > } > } else { > - if (!sset_contains(&op->od->lb_ips->ips_v4, nat->external_ip)) { > + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, > + nat->external_ip)) { > build_lswitch_rport_arp_req_flow( > nat->external_ip, AF_INET, sw_op, sw_od, 80, lflows, > stage_hint); > @@ -10441,6 +10160,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, > static void > build_lswitch_ip_unicast_lookup(struct ovn_port *op, > const struct lr_nat_table *lr_nats, > + const struct lr_lb_nat_data_table *lr_lbnats, > struct hmap *lflows, > struct ds *actions, > struct ds *match) > @@ -10456,7 +10176,8 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op, > */ > if (lsp_is_router(op->nbsp)) { > build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lr_nats, > - lflows, &op->nbsp->header_); > + lr_lbnats, lflows, > + &op->nbsp->header_); > } > > for (size_t i = 0; i < op->nbsp->n_addresses; i++) { > @@ -12646,6 +12367,7 @@ build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op, > static void > build_lrouter_drop_own_dest(struct ovn_port *op, > const struct lr_nat_record *lrnat_rec, > + const struct lr_lb_nat_data_record *lr_lbnat_rec, > enum ovn_stage stage, > uint16_t priority, bool drop_snat_ip, > struct hmap *lflows) > @@ -12658,8 +12380,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, > > bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, > ip); > - bool router_ip_in_lb_ips = > - !!sset_find(&op->od->lb_ips->ips_v4, ip); > + bool router_ip_in_lb_ips = (lr_lbnat_rec && > + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v4, > + ip)); > bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || > router_ip_in_lb_ips)); > > @@ -12688,8 +12411,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, > > bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, > ip); > - bool router_ip_in_lb_ips = > - !!sset_find(&op->od->lb_ips->ips_v6, ip); > + bool router_ip_in_lb_ips = (lr_lbnat_rec && > + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v6, > + ip)); > bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || > router_ip_in_lb_ips)); > > @@ -13401,7 +13125,8 @@ build_ip_routing_flows_for_lrp( > */ > static void > build_ip_routing_flows_for_router_type_lsp( > - struct ovn_port *op, const struct hmap *lr_ports, struct hmap *lflows) > + struct ovn_port *op, const struct lr_lb_nat_data_table *lr_lbnats, > + const struct hmap *lr_ports, struct hmap *lflows) > { > ovs_assert(op->nbsp); > if (!lsp_is_router(op->nbsp)) { > @@ -13409,7 +13134,8 @@ build_ip_routing_flows_for_router_type_lsp( > } > > struct ovn_port *peer = ovn_port_get_peer(lr_ports, op); > - if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs) { > + if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs > + || !op->od->n_router_ports) { > return; > } > > @@ -13420,19 +13146,29 @@ build_ip_routing_flows_for_router_type_lsp( > continue; > } > > - struct ovn_port_routable_addresses *ra = &router_port->routables; > - for (size_t j = 0; j < ra->n_addrs; j++) { > - struct lport_addresses *laddrs = &ra->laddrs[j]; > - for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { > - add_route(lflows, peer->od, peer, > - peer->lrp_networks.ipv4_addrs[0].addr_s, > - laddrs->ipv4_addrs[k].network_s, > - laddrs->ipv4_addrs[k].plen, NULL, false, 0, > - &peer->nbrp->header_, false, > - ROUTE_PRIO_OFFSET_CONNECTED); > + const struct lr_lb_nat_data_record *lr_lbnat_rec = > + lr_lb_nat_data_table_find_by_index(lr_lbnats, > + router_port->od->index); > + > + if (router_port->nbrp->ha_chassis_group || > + router_port->nbrp->n_gateway_chassis) { > + struct ovn_port_routable_addresses ra = > + get_op_routable_addresses(router_port, lr_lbnat_rec); > + for (size_t j = 0; j < ra.n_addrs; j++) { > + struct lport_addresses *laddrs = &ra.laddrs[j]; > + for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { > + add_route(lflows, peer->od, peer, > + peer->lrp_networks.ipv4_addrs[0].addr_s, > + laddrs->ipv4_addrs[k].network_s, > + laddrs->ipv4_addrs[k].plen, NULL, false, 0, > + &peer->nbrp->header_, false, > + ROUTE_PRIO_OFFSET_CONNECTED); > + } > } > + destroy_routable_addresses(&ra); > } > } > + > } > > static void > @@ -13656,33 +13392,36 @@ build_arp_resolve_flows_for_lrouter( > > static void > routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, > - struct ovn_port *peer, struct ds *match, > - struct ds *actions) > + struct ovn_port *peer, > + const struct lr_lb_nat_data_record *lr_lbnat_rec, > + struct ds *match, struct ds *actions) > { > - struct ovn_port_routable_addresses *ra = &router_port->routables; > - if (!ra->n_addrs) { > + struct ovn_port_routable_addresses ra = > + get_op_routable_addresses(router_port, lr_lbnat_rec); > + if (!ra.n_addrs) { > return; > } > > - for (size_t i = 0; i < ra->n_addrs; i++) { > + for (size_t i = 0; i < ra.n_addrs; i++) { > ds_clear(match); > ds_put_format(match, "outport == %s && "REG_NEXT_HOP_IPV4" == {", > peer->json_key); > bool first = true; > - for (size_t j = 0; j < ra->laddrs[i].n_ipv4_addrs; j++) { > + for (size_t j = 0; j < ra.laddrs[i].n_ipv4_addrs; j++) { > if (!first) { > ds_put_cstr(match, ", "); > } > - ds_put_cstr(match, ra->laddrs[i].ipv4_addrs[j].addr_s); > + ds_put_cstr(match, ra.laddrs[i].ipv4_addrs[j].addr_s); > first = false; > } > ds_put_cstr(match, "}"); > > ds_clear(actions); > - ds_put_format(actions, "eth.dst = %s; next;", ra->laddrs[i].ea_s); > + ds_put_format(actions, "eth.dst = %s; next;", ra.laddrs[i].ea_s); > ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100, > ds_cstr(match), ds_cstr(actions)); > } > + destroy_routable_addresses(&ra); > } > > /* Local router ingress table ARP_RESOLVE: ARP Resolution. > @@ -13699,6 +13438,7 @@ routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, > static void > build_arp_resolve_flows_for_lrp( > struct ovn_port *op, const struct lr_nat_record *lrnat_rec, > + const struct lr_lb_nat_data_record *lr_lbnat_rec, > struct hmap *lflows, struct ds *match, struct ds *actions) > { > ovs_assert(op->nbrp); > @@ -13775,8 +13515,8 @@ build_arp_resolve_flows_for_lrp( > * > * Priority 2. > */ > - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_ARP_RESOLVE, 2, > - true, lflows); > + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, > + S_ROUTER_IN_ARP_RESOLVE, 2, true, lflows); > } > > /* This function adds ARP resolve flows related to a LSP. */ > @@ -13784,6 +13524,7 @@ static void > build_arp_resolve_flows_for_lsp( > struct ovn_port *op, struct hmap *lflows, > const struct hmap *lr_ports, > + const struct lr_lb_nat_data_table *lr_lbnats, > struct ds *match, struct ds *actions) > { > ovs_assert(op->nbsp); > @@ -13927,8 +13668,11 @@ build_arp_resolve_flows_for_lsp( > > if (smap_get(&peer->od->nbr->options, "chassis") > || peer->cr_port) { > + const struct lr_lb_nat_data_record *lr_lbnat_rec; > + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, > + router_port->od->index); > routable_addresses_to_lflows(lflows, router_port, peer, > - match, actions); > + lr_lbnat_rec, match, actions); > } > } > } > @@ -14648,6 +14392,7 @@ static void > build_lrouter_ipv4_ip_input(struct ovn_port *op, > struct hmap *lflows, > const struct lr_nat_record *lrnat_rec, > + const struct lr_lb_nat_data_record *lr_lbnat_rec, > struct ds *match, struct ds *actions, > const struct shash *meter_groups) > { > @@ -14772,7 +14517,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, > &op->nbrp->header_, lflows); > } > > - if (sset_count(&op->od->lb_ips->ips_v4_reachable)) { > + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v4_reachable)) { > ds_clear(match); > if (is_l3dgw_port(op)) { > ds_put_format(match, "is_chassis_resident(%s)", > @@ -14788,7 +14533,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, > free(lb_ips_v4_as); > } > > - if (sset_count(&op->od->lb_ips->ips_v6_reachable)) { > + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v6_reachable)) { > ds_clear(match); > > if (is_l3dgw_port(op)) { > @@ -14890,8 +14635,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, > * Priority 60. > */ > if (!lrnat_rec->lb_force_snat_router_ip) { > - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_IP_INPUT, 60, > - false, lflows); > + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, > + S_ROUTER_IN_IP_INPUT, 60, false, lflows); > } > /* ARP / ND handling for external IP addresses. > * > @@ -16030,6 +15775,7 @@ struct lswitch_flow_build_info { > const struct hmap *lr_ports; > const struct ls_port_group_table *ls_port_groups; > const struct lr_nat_table *lr_nats; > + const struct lr_lb_nat_data_table *lr_lbnats; > struct hmap *lflows; > struct hmap *igmp_groups; > const struct shash *meter_groups; > @@ -16113,14 +15859,15 @@ build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od, > * switch port. > */ > static void > -build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, > - const struct hmap *ls_ports, > - const struct hmap *lr_ports, > - const struct lr_nat_table *lr_nats, > - const struct shash *meter_groups, > - struct ds *match, > - struct ds *actions, > - struct hmap *lflows) > +build_lswitch_and_lrouter_iterate_by_lsp( > + struct ovn_port *op, const struct hmap *ls_ports, > + const struct hmap *lr_ports, > + const struct lr_nat_table *lr_nats, > + const struct lr_lb_nat_data_table *lr_lbnats, > + const struct shash *meter_groups, > + struct ds *match, > + struct ds *actions, > + struct hmap *lflows) > { > ovs_assert(op->nbsp); > start_collecting_lflows(); > @@ -16133,11 +15880,14 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, > meter_groups, actions, match); > build_lswitch_dhcp_options_and_response(op, lflows, meter_groups); > build_lswitch_external_port(op, lflows); > - build_lswitch_ip_unicast_lookup(op, lr_nats, lflows, actions, match); > + build_lswitch_ip_unicast_lookup(op, lr_nats, lr_lbnats, lflows, actions, > + match); > > /* Build Logical Router Flows. */ > - build_ip_routing_flows_for_router_type_lsp(op, lr_ports, lflows); > - build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, match, actions); > + build_ip_routing_flows_for_router_type_lsp(op, lr_lbnats, lr_ports, > + lflows); > + build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, lr_lbnats, > + match, actions); > > link_ovn_port_to_lflows(op, &collected_lflows); > end_collecting_lflows(); > @@ -16156,6 +15906,8 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, > lsi->lr_nats, op->od->index); > ovs_assert(lrnet_rec); > > + const struct lr_lb_nat_data_record *lr_lbnat_rec = > + lr_lb_nat_data_table_find_by_index(lsi->lr_lbnats, op->od->index); > build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > &lsi->actions); > build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > @@ -16163,15 +15915,15 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, > build_ip_routing_flows_for_lrp(op, lsi->lflows); > build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > &lsi->actions, lsi->meter_groups); > - build_arp_resolve_flows_for_lrp(op, lrnet_rec, lsi->lflows, &lsi->match, > - &lsi->actions); > + build_arp_resolve_flows_for_lrp(op, lrnet_rec, lr_lbnat_rec, lsi->lflows, > + &lsi->match, &lsi->actions); > build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > &lsi->actions); > build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match); > build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows, > &lsi->match, &lsi->actions, > lsi->meter_groups); > - build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, > + build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, lr_lbnat_rec, > &lsi->match, &lsi->actions, lsi->meter_groups); > build_lrouter_force_snat_flows_op(op, lrnet_rec, lsi->lflows, &lsi->match, > &lsi->actions); > @@ -16234,6 +15986,7 @@ build_lflows_thread(void *arg) > build_lswitch_and_lrouter_iterate_by_lsp(op, lsi->ls_ports, > lsi->lr_ports, > lsi->lr_nats, > + lsi->lr_lbnats, > lsi->meter_groups, > &lsi->match, > &lsi->actions, > @@ -16344,6 +16097,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > const struct hmap *lr_ports, > const struct ls_port_group_table *ls_pgs, > const struct lr_nat_table *lr_nats, > + const struct lr_lb_nat_data_table *lr_lbnats, > struct hmap *lflows, > struct hmap *igmp_groups, > const struct shash *meter_groups, > @@ -16374,6 +16128,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > lsiv[index].lr_ports = lr_ports; > lsiv[index].ls_port_groups = ls_pgs; > lsiv[index].lr_nats = lr_nats; > + lsiv[index].lr_lbnats = lr_lbnats; > lsiv[index].igmp_groups = igmp_groups; > lsiv[index].meter_groups = meter_groups; > lsiv[index].lb_dps_map = lb_dps_map; > @@ -16409,6 +16164,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > .lr_ports = lr_ports, > .ls_port_groups = ls_pgs, > .lr_nats = lr_nats, > + .lr_lbnats = lr_lbnats, > .lflows = lflows, > .igmp_groups = igmp_groups, > .meter_groups = meter_groups, > @@ -16437,6 +16193,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > build_lswitch_and_lrouter_iterate_by_lsp(op, lsi.ls_ports, > lsi.lr_ports, > lsi.lr_nats, > + lsi.lr_lbnats, > lsi.meter_groups, > &lsi.match, &lsi.actions, > lsi.lflows); > @@ -16558,6 +16315,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, > input_data->lr_ports, > input_data->ls_port_groups, > input_data->lr_nats, > + input_data->lr_lbnats, > lflows, > &igmp_groups, > input_data->meter_groups, > @@ -17038,6 +16796,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, > build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, > lflow_input->lr_ports, > lflow_input->lr_nats, > + lflow_input->lr_lbnats, > lflow_input->meter_groups, > &match, &actions, > lflows); > @@ -17076,6 +16835,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, > build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, > lflow_input->lr_ports, > lflow_input->lr_nats, > + lflow_input->lr_lbnats, > lflow_input->meter_groups, > &match, &actions, > lflows); > diff --git a/northd/northd.h b/northd/northd.h > index 564729ebcc..7c446f5758 100644 > --- a/northd/northd.h > +++ b/northd/northd.h > @@ -179,6 +179,7 @@ struct lflow_input { > const struct hmap *lr_ports; > const struct ls_port_group_table *ls_port_groups; > const struct lr_nat_table *lr_nats; > + const struct lr_lb_nat_data_table *lr_lbnats; > const struct shash *meter_groups; > const struct hmap *lb_datapaths_map; > const struct hmap *bfd_connections; > @@ -318,9 +319,6 @@ struct ovn_datapath { > /* router datapath has a logical port with redirect-type set to bridged. */ > bool redirect_bridged; > > - /* Load Balancer vIPs relevant for this datapath. */ > - struct ovn_lb_ip_set *lb_ips; > - > struct ovn_port **localnet_ports; > size_t n_localnet_ports; > > @@ -337,6 +335,119 @@ struct ovn_datapath { > const struct ovn_datapath *ovn_datapath_find(const struct hmap *datapaths, > const struct uuid *uuid); > > +/* A logical switch port or logical router port. > + * > + * In steady state, an ovn_port points to a northbound Logical_Switch_Port > + * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a > + * southbound Port_Binding record (via 'sb'). As the state of the system > + * changes, join_logical_ports() may determine that there is a new LSP or LRP > + * that has no corresponding Port_Binding record (in which case build_ports()) > + * will create the missing Port_Binding) or that a Port_Binding record exists > + * that has no coresponding LSP (in which case build_ports() will delete the > + * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port > + * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. > + * > + * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but > + * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). > + */ > +struct ovn_port { > + /* Port name aka key. > + * > + * This is ordinarily the same as nbsp->name or nbrp->name and > + * sb->logical_port. (A distributed gateway port creates a "derived" > + * ovn_port with key "cr-%s" % nbrp->name.) */ > + struct hmap_node key_node; /* Index on 'key'. */ > + char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ > + char *json_key; /* 'key', quoted for use in JSON. */ > + > + const struct sbrec_port_binding *sb; /* May be NULL. */ > + > + uint32_t tunnel_key; > + > + /* Logical switch port data. */ > + const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ > + > + struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ > + unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ > + unsigned int n_lsp_non_router_addrs; /* Number of elements from the > + * beginning of 'lsp_addrs' extracted > + * directly from LSP 'addresses'. */ > + > + struct lport_addresses *ps_addrs; /* Port security addresses. */ > + unsigned int n_ps_addrs; > + > + bool lsp_can_be_inc_processed; /* If it can be incrementally processed when > + the port changes. */ > + > + /* Logical router port data. */ > + const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ > + > + struct lport_addresses lrp_networks; > + > + /* Logical port multicast data. */ > + struct mcast_port_info mcast_info; > + > + /* At most one of l3dgw_port and cr_port can be not NULL. */ > + > + /* This is set to a distributed gateway port if and only if this ovn_port > + * is "derived" from it. Otherwise this is set to NULL. The derived > + * ovn_port represents the instance of distributed gateway port on the > + * gateway chassis.*/ > + struct ovn_port *l3dgw_port; > + > + /* This is set to the "derived" chassis-redirect port of this port if and > + * only if this port is a distributed gateway port. Otherwise this is set > + * to NULL. */ > + struct ovn_port *cr_port; > + > + bool has_unknown; /* If the addresses have 'unknown' defined. */ > + > + bool has_bfd; > + > + /* The port's peer: > + * > + * - A switch port S of type "router" has a router port R as a peer, > + * and R in turn has S has its peer. > + * > + * - Two connected logical router ports have each other as peer. > + * > + * - Other kinds of ports have no peer. */ > + struct ovn_port *peer; > + > + struct ovn_datapath *od; > + > + struct ovs_list list; /* In list of similar records. */ > + > + struct hmap_node dp_node; /* Node in od->ports. */ > + > + struct lport_addresses proxy_arp_addrs; > + > + /* Temporarily used for traversing a list (or hmap) of ports. */ > + bool visited; > + > + /* List of struct lflow_ref_node that points to the lflows generated by > + * this ovn_port. > + * > + * This data is initialized and destroyed by the en_northd node, but > + * populated and used only by the en_lflow node. Ideally this data should > + * be maintained as part of en_lflow's data (struct lflow_data): a hash > + * index from ovn_port key to lflows. However, it would be less efficient > + * and more complex: > + * > + * 1. It would require an extra search (using the index) to find the > + * lflows. > + * > + * 2. Building the index needs to be thread-safe, using either a global > + * lock which is obviously less efficient, or hash-based lock array which > + * is more complex. > + * > + * Adding the list here is more straightforward. The drawback is that we > + * need to keep in mind that this data belongs to en_lflow node, so never > + * access it from any other nodes. > + */ > + struct ovs_list lflows; > +}; > + > void ovnnb_db_run(struct northd_input *input_data, > struct northd_data *data, > struct ovsdb_idl_txn *ovnnb_txn, > @@ -396,13 +507,27 @@ void sync_lbs(struct ovsdb_idl_txn *, const struct sbrec_load_balancer_table *, > struct chassis_features *chassis_features); > bool check_sb_lb_duplicates(const struct sbrec_load_balancer_table *); > > +struct lr_lb_nat_data_table; > void sync_pbs(struct ovsdb_idl_txn *, struct hmap *ls_ports, > - struct hmap *lr_ports, const struct lr_nat_table *); > -bool sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *, > - const struct lr_nat_table *); > + struct hmap *lr_ports, > + const struct lr_lb_nat_data_table *); > +bool sync_pbs_for_northd_changed_ovn_ports( > + struct tracked_ovn_ports *, > + const struct lr_lb_nat_data_table *); > > bool northd_has_tracked_data(struct northd_tracked_data *); > bool northd_has_only_ports_in_tracked_data(struct northd_tracked_data *); > bool northd_has_lbs_in_tracked_data(struct northd_tracked_data *); > > +/* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the > + * IPs configured on the router port. > + */ > +bool lrouter_port_ipv4_reachable(const struct ovn_port *, ovs_be32 addr); > + > +/* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the > + * IPs configured on the router port. > + */ > +bool lrouter_port_ipv6_reachable(const struct ovn_port *, > + const struct in6_addr *); > + > #endif /* NORTHD_H */ > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > index b7f9cb5689..8fc5cd1d60 100644 > --- a/tests/ovn-northd.at > +++ b/tests/ovn-northd.at > @@ -10416,18 +10416,21 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:10.0.0.3=sw0-p1:10.0.0.2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > check ovn-nbctl --wait=sb set load_balancer . options:foo=bar > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > check ovn-nbctl --wait=sb -- lb-add lb2 20.0.0.10:80 20.0.0.20:80 -- lb-add lb3 30.0.0.10:80 30.0.0.20:80 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10437,6 +10440,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb -- lb-del lb2 -- lb-del lb3 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10450,6 +10454,7 @@ AT_CHECK([ovn-nbctl --wait=sb \ > ]) > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10467,6 +10472,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear Load_Balancer . health_check > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10481,6 +10487,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10489,6 +10496,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > # A LB applied to a switch/router triggers: > # - a recompute in the first iteration (handling northd change) > @@ -10501,6 +10509,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='" 10.0.0.100:80"' > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10510,6 +10519,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10519,6 +10529,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10528,6 +10539,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10537,6 +10549,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-del sw0 lb1 > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10547,6 +10560,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 -- lsp-add sw0 sw0p1 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > > @@ -10567,6 +10581,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-lb-add lr0 lb1 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10576,6 +10591,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='" 10.0.0.100:80"' > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10585,6 +10601,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10594,6 +10611,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10603,6 +10621,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10632,6 +10651,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb add load_balancer_group . load_Balancer $lb1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10639,6 +10659,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear load_balancer_group . load_Balancer > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10655,6 +10676,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > > @@ -10671,6 +10693,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='" 10.0.0.100:80"' > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10680,6 +10703,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10689,6 +10713,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10698,6 +10723,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10713,6 +10739,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl add logical_router lr0 load_balancer_group $lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10722,6 +10749,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='" 10.0.0.100:80"' > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10731,6 +10759,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10740,6 +10769,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10749,6 +10779,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10757,6 +10788,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear logical_router lr0 load_balancer_group > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > > @@ -10765,6 +10797,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > > @@ -10773,6 +10806,7 @@ check ovn-nbctl --wait=sb clear logical_switch sw0 load_balancer_group -- \ > destroy load_balancer_group $lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb compute compute > > @@ -10796,6 +10830,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > lbg1_uuid=$(ovn-nbctl --wait=sb create load_balancer_group name=lbg1) > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow norecompute nocompute > check_engine_stats sync_to_sb_lb norecompute nocompute > > @@ -10803,6 +10838,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer_group . load_balancer="$lb2_uuid,$lb3_uuid,$lb4_uuid" > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10810,6 +10846,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set logical_switch sw0 load_balancer_group=$lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10818,6 +10855,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set logical_router lr1 load_balancer_group=$lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10826,6 +10864,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-add sw0 lb2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10834,6 +10873,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-add sw0 lb3 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10843,6 +10883,7 @@ check ovn-nbctl --wait=sb lr-lb-add lr1 lb1 > check ovn-nbctl --wait=sb lr-lb-add lr1 lb2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10851,6 +10892,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-del sw0 lb2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10859,6 +10901,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-lb-del lr1 lb2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10869,6 +10912,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-del lb4 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10879,6 +10923,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-del lb2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10887,6 +10932,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb remove load_balancer_group . load_balancer $lb3_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11019,6 +11065,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-add lr0 > check_engine_stats northd recompute nocompute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11031,6 +11078,7 @@ check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 > # for the SB port binding change. > check_engine_stats northd recompute compute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11042,6 +11090,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 > check_engine_stats northd recompute nocompute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11067,6 +11116,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl set logical_router_port lr0-sw0 options:foo=bar > check_engine_stats northd recompute nocompute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11076,8 +11126,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # engine nodes. > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11085,8 +11135,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Update the NAT options column > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set NAT . options:foo=bar > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11094,8 +11144,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Update the NAT external_ip column > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set NAT . external_ip=172.168.0.120 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11103,8 +11154,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Update the NAT logical_ip column > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set NAT . logical_ip=10.0.0.10 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11112,8 +11164,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Update the NAT type > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set NAT . type=snat > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11121,8 +11174,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Create a dnat_and_snat NAT with external_mac and logical_port > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 sw0p1 30:54:00:00:00:03 > -check_engine_stats northd recompute compute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11131,8 +11185,9 @@ nat2_uuid=$(ovn-nbctl --bare --columns _uuid find nat logical_ip=10.0.0.4) > > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set NAT $nat2_uuid external_mac='"30:54:00:00:00:04"' > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11147,32 +11202,36 @@ check ovn-nbctl lr-lb-add lr0 lb2 > # is a lb vip. > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.140 10.0.0.20 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.150 10.0.0.41 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.150 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.140 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11180,8 +11239,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Delete the NAT > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear logical_router lr0 nat > -check_engine_stats northd recompute compute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11191,6 +11251,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-policy-add lr0 10 "ip4.src == 10.0.0.3" reroute 172.168.0.101,172.168.0.102 > check_engine_stats northd recompute nocompute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11199,6 +11260,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-policy-del lr0 10 "ip4.src == 10.0.0.3" > check_engine_stats northd recompute nocompute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > -- > 2.41.0 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
On 10/26/23 20:15, numans@ovn.org wrote: > From: Numan Siddique <numans@ovn.org> > > This new engine now maintains the load balancer and NAT data of a > logical router which was earlier part of northd engine node data. > The main inputs to this engine are: > - northd node > - lr-nat node > > A record for each logical router is maintained in the 'lr_lb_nats' > hmap table and this record > - stores the lb related data > - embeds the 'lr-nat' record. > > This engine node becomes an input to 'lflow' node. > > Signed-off-by: Numan Siddique <numans@ovn.org> > --- > lib/stopwatch-names.h | 1 + > northd/automake.mk | 2 + > northd/en-lflow.c | 4 + > northd/en-lr-lb-nat-data.c | 654 +++++++++++++++++++++++++++++++++++++ > northd/en-lr-lb-nat-data.h | 93 ++++++ > northd/en-lr-nat.h | 3 + > northd/en-sync-sb.c | 50 +-- > northd/inc-proc-northd.c | 13 +- > northd/northd.c | 640 ++++++++++++------------------------ > northd/northd.h | 137 +++++++- > tests/ovn-northd.at | 110 +++++-- > 11 files changed, 1212 insertions(+), 495 deletions(-) > create mode 100644 northd/en-lr-lb-nat-data.c > create mode 100644 northd/en-lr-lb-nat-data.h > > diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h > index 0a16da211e..7d85acdaea 100644 > --- a/lib/stopwatch-names.h > +++ b/lib/stopwatch-names.h > @@ -33,5 +33,6 @@ > #define PORT_GROUP_RUN_STOPWATCH_NAME "port_group_run" > #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" > #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" > +#define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" > > #endif > diff --git a/northd/automake.mk b/northd/automake.mk > index ae367a2a8b..4116c487df 100644 > --- a/northd/automake.mk > +++ b/northd/automake.mk > @@ -26,6 +26,8 @@ northd_ovn_northd_SOURCES = \ > northd/en-lb-data.h \ > northd/en-lr-nat.c \ > northd/en-lr-nat.h \ > + northd/en-lr-lb-nat-data.c \ > + northd/en-lr-lb-nat-data.h \ > northd/inc-proc-northd.c \ > northd/inc-proc-northd.h \ > northd/ipam.c \ > diff --git a/northd/en-lflow.c b/northd/en-lflow.c > index 22f398d419..9cb0ead3f0 100644 > --- a/northd/en-lflow.c > +++ b/northd/en-lflow.c > @@ -20,6 +20,7 @@ > > #include "en-lflow.h" > #include "en-lr-nat.h" > +#include "en-lr-lb-nat-data.h" > #include "en-northd.h" > #include "en-meters.h" > > @@ -43,6 +44,8 @@ lflow_get_input_data(struct engine_node *node, > engine_get_input_data("sync_meters", node); > struct ed_type_lr_nat_data *lr_nat_data = > engine_get_input_data("lr_nat", node); > + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > + engine_get_input_data("lr_lb_nat_data", node); > > lflow_input->nbrec_bfd_table = > EN_OVSDB_GET(engine_get_input("NB_bfd", node)); > @@ -66,6 +69,7 @@ lflow_get_input_data(struct engine_node *node, > lflow_input->lr_ports = &northd_data->lr_ports; > lflow_input->ls_port_groups = &pg_data->ls_port_groups; > lflow_input->lr_nats = &lr_nat_data->lr_nats; > + lflow_input->lr_lbnats = &lr_lb_nat_data->lr_lbnats; > lflow_input->meter_groups = &sync_meters_data->meter_groups; > lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map; > lflow_input->svc_monitor_map = &northd_data->svc_monitor_map; > diff --git a/northd/en-lr-lb-nat-data.c b/northd/en-lr-lb-nat-data.c > new file mode 100644 > index 0000000000..19b638ce0b > --- /dev/null > +++ b/northd/en-lr-lb-nat-data.c > @@ -0,0 +1,654 @@ > +/* > + * Copyright (c) 2023, Red Hat, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#include <config.h> > + > +#include <getopt.h> > +#include <stdlib.h> > +#include <stdio.h> > + > +/* OVS includes */ > +#include "include/openvswitch/hmap.h" > +#include "lib/bitmap.h" > +#include "lib/socket-util.h" > +#include "lib/uuidset.h" > +#include "openvswitch/util.h" > +#include "openvswitch/vlog.h" > +#include "stopwatch.h" > + > +/* OVN includes */ > +#include "en-lb-data.h" > +#include "en-lr-lb-nat-data.h" > +#include "en-lr-nat.h" > +#include "lib/inc-proc-eng.h" > +#include "lib/lb.h" > +#include "lib/ovn-nb-idl.h" > +#include "lib/ovn-sb-idl.h" > +#include "lib/ovn-util.h" > +#include "lib/stopwatch-names.h" > +#include "northd.h" > + > +VLOG_DEFINE_THIS_MODULE(en_lr_lb_nat_data); > + > +/* Static function declarations. */ > +static void lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *); > +static void lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *); > +static void lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *); > +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_( > + const struct lr_lb_nat_data_table *, const struct nbrec_logical_router *); > +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index_( > + const struct lr_lb_nat_data_table *table, size_t od_index); > + > +static void lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *, > + const struct lr_nat_table *, > + const struct ovn_datapaths *lr_datapaths, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map); > + > +static struct lr_lb_nat_data_input lr_lb_nat_data_get_input_data( > + struct engine_node *); > + > +static struct lr_lb_nat_data_record *lr_lb_nat_data_record_create( > + struct lr_lb_nat_data_table *, const struct lr_nat_record *, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map); > +static void lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *); > +static void lr_lb_nat_data_record_init( > + struct lr_lb_nat_data_record *, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map); > + > +static void build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, > + const struct ovn_northd_lb *); > +static void add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *, > + enum lb_neighbor_responder_mode, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6); > +static void remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, > + enum lb_neighbor_responder_mode, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6); > +static void lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *); > + > +/* 'lr_lb_nat_data' engine node manages the NB logical router LB data. > + */ > +void * > +en_lr_lb_nat_data_init(struct engine_node *node OVS_UNUSED, > + struct engine_arg *arg OVS_UNUSED) > +{ > + struct ed_type_lr_lb_nat_data *data = xzalloc(sizeof *data); > + lr_lb_nat_data_table_init(&data->lr_lbnats); > + hmapx_init(&data->tracked_data.crupdated); > + hmapx_init(&data->tracked_data.deleted); > + return data; > +} > + > +void > +en_lr_lb_nat_data_cleanup(void *data_) > +{ > + struct ed_type_lr_lb_nat_data *data = > + (struct ed_type_lr_lb_nat_data *) data_; > + lr_lb_nat_data_table_destroy(&data->lr_lbnats); > + hmapx_destroy(&data->tracked_data.crupdated); > + hmapx_destroy(&data->tracked_data.deleted); > +} > + > +void > +en_lr_lb_nat_data_clear_tracked_data(void *data_) > +{ > + struct ed_type_lr_lb_nat_data *data = > + (struct ed_type_lr_lb_nat_data *) data_; > + > + struct hmapx_node *hmapx_node; > + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { > + lr_lb_nat_data_record_destroy(hmapx_node->data); > + hmapx_delete(&data->tracked_data.deleted, hmapx_node); > + } > + > + hmapx_clear(&data->tracked_data.crupdated); > + data->tracked = false; > +} > + > +void > +en_lr_lb_nat_data_run(struct engine_node *node, void *data_) > +{ > + struct lr_lb_nat_data_input input_data = > + lr_lb_nat_data_get_input_data(node); > + struct ed_type_lr_lb_nat_data *data = data_; > + > + stopwatch_start(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); > + > + lr_lb_nat_data_table_clear(&data->lr_lbnats); > + lr_lb_nat_data_table_build(&data->lr_lbnats, input_data.lr_nats, > + input_data.lr_datapaths, > + input_data.lb_datapaths_map, > + input_data.lbgrp_datapaths_map); > + > + stopwatch_stop(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); > + engine_set_node_state(node, EN_UPDATED); > +} > + > +bool > +lr_lb_nat_data_northd_handler(struct engine_node *node, void *data OVS_UNUSED) > +{ > + struct northd_data *northd_data = engine_get_input_data("northd", node); > + if (!northd_data->change_tracked) { > + return false; > + } > + > + return true; > +} > + > +bool > +lr_lb_nat_data_lb_data_handler(struct engine_node *node, void *data_) > +{ > + struct ed_type_lb_data *lb_data = engine_get_input_data("lb_data", node); > + if (!lb_data->tracked) { > + return false; > + } > + > + struct ed_type_lr_lb_nat_data *data = > + (struct ed_type_lr_lb_nat_data *) data_; > + struct lr_lb_nat_data_input input_data = > + lr_lb_nat_data_get_input_data(node); > + struct lr_lb_nat_data_record *lr_lbnat_rec; > + size_t index; > + > + const struct tracked_lb_data *trk_lb_data = &lb_data->tracked_lb_data; > + const struct ovn_lb_group_datapaths *lbgrp_dps; > + const struct crupdated_lbgrp *crupdated_lbgrp; > + const struct crupdated_od_lb_data *codlb; > + const struct ovn_lb_datapaths *lb_dps; > + const struct crupdated_lb *clb; > + const struct ovn_northd_lb *lb; > + const struct ovn_datapath *od; > + > + LIST_FOR_EACH (codlb, list_node, &trk_lb_data->crupdated_lr_lbs) { > + od = ovn_datapath_find(&input_data.lr_datapaths->datapaths, > + &codlb->od_uuid); > + ovs_assert(od); > + > + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, od->nbr); > + if (!lr_lbnat_rec) { > + const struct lr_nat_record *lrnat_rec = lr_nat_table_find_by_index( > + input_data.lr_nats, od->index); > + ovs_assert(lrnat_rec); > + > + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, > + lrnat_rec, > + input_data.lb_datapaths_map, > + input_data.lbgrp_datapaths_map); > + > + /* Add the lr_lbnat_rec rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > + continue; > + } > + > + struct uuidset_node *uuidnode; > + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbs) { > + lb_dps = ovn_lb_datapaths_find( > + input_data.lb_datapaths_map, &uuidnode->uuid); > + ovs_assert(lb_dps); > + > + /* Add the lb_ips of lb_dps to the od. */ > + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > + } > + > + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbgrps) { > + lbgrp_dps = ovn_lb_group_datapaths_find( > + input_data.lbgrp_datapaths_map, &uuidnode->uuid); > + ovs_assert(lbgrp_dps); > + > + for (size_t j = 0; j < lbgrp_dps->lb_group->n_lbs; j++) { > + const struct uuid *lb_uuid > + = &lbgrp_dps->lb_group->lbs[j]->nlb->header_.uuid; > + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, > + lb_uuid); > + ovs_assert(lb_dps); > + > + /* Add the lb_ips of lb_dps to the od. */ > + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > + } > + } > + > + /* Add the lr_lbnat_rec rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > + } > + > + HMAP_FOR_EACH (clb, hmap_node, &trk_lb_data->crupdated_lbs) { > + lb = clb->lb; > + const struct uuid *lb_uuid = &lb->nlb->header_.uuid; > + > + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, lb_uuid); > + ovs_assert(lb_dps); > + > + BITMAP_FOR_EACH_1 (index, ods_size(input_data.lr_datapaths), > + lb_dps->nb_lr_map) { > + od = input_data.lr_datapaths->array[index]; > + > + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, > + od->nbr); > + ovs_assert(lr_lbnat_rec); > + > + /* Update the od->lb_ips with the deleted and inserted > + * vips (if any). */ > + remove_ips_from_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, > + &clb->deleted_vips_v4, > + &clb->deleted_vips_v6); > + add_ips_to_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, > + &clb->inserted_vips_v4, > + &clb->inserted_vips_v6); > + > + remove_lrouter_lb_reachable_ips(lr_lbnat_rec, lb->neigh_mode, > + &clb->deleted_vips_v4, > + &clb->deleted_vips_v6); > + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, > + &clb->inserted_vips_v4, > + &clb->inserted_vips_v6); > + > + /* Add the lr_lbnat_rec rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > + } > + } > + > + HMAP_FOR_EACH (crupdated_lbgrp, hmap_node, > + &trk_lb_data->crupdated_lbgrps) { > + const struct uuid *lb_uuid = &crupdated_lbgrp->lbgrp->uuid; > + > + lbgrp_dps = ovn_lb_group_datapaths_find(input_data.lbgrp_datapaths_map, > + lb_uuid); > + ovs_assert(lbgrp_dps); > + > + struct hmapx_node *hnode; > + HMAPX_FOR_EACH (hnode, &crupdated_lbgrp->assoc_lbs) { > + lb = hnode->data; > + lb_uuid = &lb->nlb->header_.uuid; > + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, > + lb_uuid); > + ovs_assert(lb_dps); > + for (size_t i = 0; i < lbgrp_dps->n_lr; i++) { > + od = lbgrp_dps->lr[i]; > + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, > + od->nbr); > + ovs_assert(lr_lbnat_rec); > + /* Add the lb_ips of lb_dps to the lr lb data. */ > + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > + > + /* Add the lr_lbnat_rec rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > + } > + } > + } > + > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > + struct hmapx_node *hmapx_node; > + /* For all the modified lr_lb_nat_data records (re)build the > + * vip nats. */ > + HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { > + lr_lb_nat_data_build_vip_nats(hmapx_node->data); > + } > + > + data->tracked = true; > + engine_set_node_state(node, EN_UPDATED); > + } > + > + return true; > +} > + > +bool > +lr_lb_nat_data_lr_nat_handler(struct engine_node *node, void *data_) > +{ > + struct ed_type_lr_nat_data *lr_nat_data = > + engine_get_input_data("lr_nat", node); > + > + if (!lr_nat_data->tracked > + || !hmapx_is_empty(&lr_nat_data->tracked_data.deleted)) { > + return false; > + } > + > + struct ed_type_lr_lb_nat_data *data = > + (struct ed_type_lr_lb_nat_data *) data_; > + struct lr_lb_nat_data_input input_data = > + lr_lb_nat_data_get_input_data(node); > + const struct lr_nat_record *lrnat_rec; > + struct lr_lb_nat_data_record *lr_lbnat_rec; > + struct hmapx_node *hmapx_node; > + > + HMAPX_FOR_EACH (hmapx_node, &lr_nat_data->tracked_data.crupdated) { > + lrnat_rec = hmapx_node->data; > + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, > + lrnat_rec->od->nbr); > + if (!lr_lbnat_rec) { > + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, > + lrnat_rec, > + input_data.lb_datapaths_map, > + input_data.lbgrp_datapaths_map); > + } else { > + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > + } > + > + /* Add the lr_lbnat_rec rec to the tracking data. */ > + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > + } > + > + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > + data->tracked = true; > + engine_set_node_state(node, EN_UPDATED); > + } > + > + return true; > +} > + > +const struct lr_lb_nat_data_record * > +lr_lb_nat_data_table_find_by_index(const struct lr_lb_nat_data_table *table, > + size_t od_index) > +{ > + return lr_lb_nat_data_table_find_by_index_(table, od_index); > +} > + > +/* static functions. */ > +static void > +lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *table) > +{ > + *table = (struct lr_lb_nat_data_table) { > + .entries = HMAP_INITIALIZER(&table->entries), > + }; > +} > + > +static void > +lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *table) > +{ > + lr_lb_nat_data_table_clear(table); > + hmap_destroy(&table->entries); > +} > + > +static void > +lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *table) > +{ > + struct lr_lb_nat_data_record *lr_lbnat_rec; > + HMAP_FOR_EACH_POP (lr_lbnat_rec, key_node, &table->entries) { > + lr_lb_nat_data_record_destroy(lr_lbnat_rec); > + } > + > + free(table->array); > + table->array = NULL; > +} > + > +static void > +lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *table, > + const struct lr_nat_table *lr_nats, > + const struct ovn_datapaths *lr_datapaths, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map) > +{ > + table->array = xrealloc(table->array, > + ods_size(lr_datapaths) * sizeof *table->array); > + const struct lr_nat_record *lrnat_rec; > + LR_NAT_TABLE_FOR_EACH (lrnat_rec, lr_nats) { > + lr_lb_nat_data_record_create(table, lrnat_rec, lb_datapaths_map, > + lbgrp_datapaths_map); > + } > +} > + > +static struct lr_lb_nat_data_record * > +lr_lb_nat_data_table_find_(const struct lr_lb_nat_data_table *table, > + const struct nbrec_logical_router *nbr) > +{ > + struct lr_lb_nat_data_record *lr_lbnat_rec; > + > + HMAP_FOR_EACH_WITH_HASH (lr_lbnat_rec, key_node, > + uuid_hash(&nbr->header_.uuid), &table->entries) { > + if (nbr == lr_lbnat_rec->od->nbr) { > + return lr_lbnat_rec; > + } > + } > + return NULL; > +} > + > +static struct lr_lb_nat_data_record * > +lr_lb_nat_data_table_find_by_index_(const struct lr_lb_nat_data_table *table, > + size_t od_index) > +{ > + ovs_assert(od_index <= hmap_count(&table->entries)); > + return table->array[od_index]; > +} > + > +static struct lr_lb_nat_data_record * > +lr_lb_nat_data_record_create(struct lr_lb_nat_data_table *table, > + const struct lr_nat_record *lrnat_rec, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map) > +{ > + struct lr_lb_nat_data_record *lr_lbnat_rec = xzalloc(sizeof *lr_lbnat_rec); > + lr_lbnat_rec->lrnat_rec = lrnat_rec; > + lr_lbnat_rec->od = lrnat_rec->od; > + lr_lb_nat_data_record_init(lr_lbnat_rec, lb_datapaths_map, > + lbgrp_datapaths_map); > + > + hmap_insert(&table->entries, &lr_lbnat_rec->key_node, > + uuid_hash(&lr_lbnat_rec->od->nbr->header_.uuid)); > + > + table->array[lr_lbnat_rec->od->index] = lr_lbnat_rec; > + return lr_lbnat_rec; > +} > + > +static void > +lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *lr_lbnat_rec) > +{ > + ovn_lb_ip_set_destroy(lr_lbnat_rec->lb_ips); > + lr_lbnat_rec->lb_ips = NULL; > + sset_destroy(&lr_lbnat_rec->vip_nats); > + free(lr_lbnat_rec); > +} > + > +static void > +lr_lb_nat_data_record_init(struct lr_lb_nat_data_record *lr_lbnat_rec, > + const struct hmap *lb_datapaths_map, > + const struct hmap *lbgrp_datapaths_map) > +{ > + const struct nbrec_load_balancer_group *nbrec_lb_group; > + const struct ovn_lb_group_datapaths *lb_group_dps; > + const struct ovn_lb_datapaths *lb_dps; > + > + /* Checking load balancer groups first, starting from the largest one, > + * to more efficiently copy IP sets. */ > + size_t largest_group = 0; > + > + const struct nbrec_logical_router *nbr = lr_lbnat_rec->od->nbr; > + for (size_t i = 1; i < nbr->n_load_balancer_group; i++) { > + if (nbr->load_balancer_group[i]->n_load_balancer > > + nbr->load_balancer_group[largest_group]->n_load_balancer) { > + largest_group = i; > + } > + } > + > + for (size_t i = 0; i < nbr->n_load_balancer_group; i++) { > + size_t idx = (i + largest_group) % nbr->n_load_balancer_group; > + > + nbrec_lb_group = nbr->load_balancer_group[idx]; > + const struct uuid *lbgrp_uuid = &nbrec_lb_group->header_.uuid; > + > + lb_group_dps = > + ovn_lb_group_datapaths_find(lbgrp_datapaths_map, > + lbgrp_uuid); > + ovs_assert(lb_group_dps); > + > + if (!lr_lbnat_rec->lb_ips) { > + lr_lbnat_rec->lb_ips = > + ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); > + } else { > + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, > + lb_group_dps->lb_group->lbs[j]); > + } > + } > + > + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > + build_lrouter_lb_reachable_ips(lr_lbnat_rec, > + lb_group_dps->lb_group->lbs[j]); > + } > + } > + > + if (!lr_lbnat_rec->lb_ips) { > + lr_lbnat_rec->lb_ips = ovn_lb_ip_set_create(); > + } > + > + for (size_t i = 0; i < nbr->n_load_balancer; i++) { > + const struct uuid *lb_uuid = > + &nbr->load_balancer[i]->header_.uuid; > + lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); > + ovs_assert(lb_dps); > + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > + } > + > + sset_init(&lr_lbnat_rec->vip_nats); > + > + if (!nbr->n_nat) { > + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > + } > +} > + > +static struct lr_lb_nat_data_input > +lr_lb_nat_data_get_input_data(struct engine_node *node) > +{ > + struct northd_data *northd_data = engine_get_input_data("northd", node); > + struct ed_type_lr_nat_data *lr_nat_data = > + engine_get_input_data("lr_nat", node); > + > + return (struct lr_lb_nat_data_input) { > + .lr_datapaths = &northd_data->lr_datapaths, > + .lb_datapaths_map = &northd_data->lb_datapaths_map, > + .lbgrp_datapaths_map = &northd_data->lb_group_datapaths_map, > + .lr_nats = &lr_nat_data->lr_nats, > + }; > +} > + > +static void > +build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, > + const struct ovn_northd_lb *lb) > +{ > + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, &lb->ips_v4, > + &lb->ips_v6); > +} > + > +static void > +add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *lr_lbnat_rec, > + enum lb_neighbor_responder_mode neigh_mode, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6) > +{ > + /* If configured to not reply to any neighbor requests for all VIPs > + * return early. > + */ > + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > + return; > + } > + > + const char *ip_address; > + > + /* If configured to reply to neighbor requests for all VIPs force them > + * all to be considered "reachable". > + */ > + if (neigh_mode == LB_NEIGH_RESPOND_ALL) { > + SSET_FOR_EACH (ip_address, lb_ips_v4) { > + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, ip_address); > + } > + SSET_FOR_EACH (ip_address, lb_ips_v6) { > + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, ip_address); > + } > + > + return; > + } > + > + /* Otherwise, a VIP is reachable if there's at least one router > + * subnet that includes it. > + */ > + ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); > + > + SSET_FOR_EACH (ip_address, lb_ips_v4) { > + struct ovn_port *op; > + ovs_be32 vip_ip4; > + if (ip_parse(ip_address, &vip_ip4)) { > + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { > + if (lrouter_port_ipv4_reachable(op, vip_ip4)) { > + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, > + ip_address); > + break; > + } > + } > + } > + } > + > + SSET_FOR_EACH (ip_address, lb_ips_v6) { > + struct ovn_port *op; > + struct in6_addr vip; > + if (ipv6_parse(ip_address, &vip)) { > + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { > + if (lrouter_port_ipv6_reachable(op, &vip)) { > + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, > + ip_address); > + break; > + } > + } > + } > + } > +} > + > +static void > +remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, > + enum lb_neighbor_responder_mode neigh_mode, > + const struct sset *lb_ips_v4, > + const struct sset *lb_ips_v6) > +{ > + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > + return; > + } > + > + const char *ip_address; > + SSET_FOR_EACH (ip_address, lb_ips_v4) { > + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v4_reachable, > + ip_address); > + } > + SSET_FOR_EACH (ip_address, lb_ips_v6) { > + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v6_reachable, > + ip_address); > + } > +} > + > +static void > +lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *lr_lbnat_rec) > +{ > + sset_clear(&lr_lbnat_rec->vip_nats); > + const char *external_ip; > + SSET_FOR_EACH (external_ip, &lr_lbnat_rec->lrnat_rec->external_ips) { > + bool is_vip_nat = false; > + if (addr_is_ipv6(external_ip)) { > + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, > + external_ip); > + } else { > + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, > + external_ip); > + } > + > + if (is_vip_nat) { > + sset_add(&lr_lbnat_rec->vip_nats, external_ip); > + } > + } > +} > diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h > new file mode 100644 > index 0000000000..9029aee339 > --- /dev/null > +++ b/northd/en-lr-lb-nat-data.h > @@ -0,0 +1,93 @@ > +/* > + * Copyright (c) 2023, Red Hat, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > +#ifndef EN_LR_LB_NAT_DATA_H > +#define EN_LR_LB_NAT_DATA_H 1 > + > +#include <stdint.h> > + > +/* OVS includes. */ > +#include "lib/hmapx.h" > +#include "openvswitch/hmap.h" > +#include "sset.h" > + > +/* OVN includes. */ > +#include "lib/inc-proc-eng.h" > +#include "lib/lb.h" > +#include "lib/ovn-nb-idl.h" > +#include "lib/ovn-sb-idl.h" > +#include "lib/ovn-util.h" > + > +struct ovn_datapath; > +struct lr_nat_record; > + > +struct lr_lb_nat_data_record { > + struct hmap_node key_node; /* Index on 'nbr->header_.uuid'. */ > + > + const struct ovn_datapath *od; > + const struct lr_nat_record *lrnat_rec; > + > + /* Load Balancer vIPs relevant for this datapath. */ > + struct ovn_lb_ip_set *lb_ips; > + > + /* sset of vips which are also part of lr nats. */ > + struct sset vip_nats; > +}; > + > +struct lr_lb_nat_data_table { > + struct hmap entries; > + > + /* The array index of each element in 'entries'. */ > + struct lr_lb_nat_data_record **array; > +}; > + > +#define LR_LB_NAT_DATA_TABLE_FOR_EACH(LR_LB_NAT_REC, TABLE) \ > + HMAP_FOR_EACH (LR_LB_NAT_REC, key_node, &(TABLE)->entries) > + > +struct lr_lb_nat_data_tracked_data { > + /* Created or updated logical router with LB data. */ > + struct hmapx crupdated; /* Stores 'struct lr_lb_nat_data_record'. */ > + > + /* Deleted logical router with LB data. */ > + struct hmapx deleted; /* Stores 'struct lr_lb_nat_data_record'. */ > +}; > + > +struct ed_type_lr_lb_nat_data { > + struct lr_lb_nat_data_table lr_lbnats; > + > + bool tracked; > + struct lr_lb_nat_data_tracked_data tracked_data; Same comment about 'tracked' as in the previous commit, we can probably remove it. Which brings me to the following question, we don't really use lr_lb_nat_data_tracked_data->deleted anywhere; we never add anything to it. Is it on purpose, should we just delete it? Or is it a bug? Thanks, Dumitru > +}; > + > +struct lr_lb_nat_data_input { > + const struct ovn_datapaths *lr_datapaths; > + const struct hmap *lb_datapaths_map; > + const struct hmap *lbgrp_datapaths_map; > + const struct lr_nat_table *lr_nats; > +}; > + > +void *en_lr_lb_nat_data_init(struct engine_node *, struct engine_arg *); > +void en_lr_lb_nat_data_cleanup(void *data); > +void en_lr_lb_nat_data_clear_tracked_data(void *data); > +void en_lr_lb_nat_data_run(struct engine_node *, void *data); > + > +bool lr_lb_nat_data_northd_handler(struct engine_node *, void *data); > +bool lr_lb_nat_data_lr_nat_handler(struct engine_node *, void *data); > +bool lr_lb_nat_data_lb_data_handler(struct engine_node *, void *data); > + > +const struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index( > + const struct lr_lb_nat_data_table *, size_t od_index); > + > +#endif /* EN_LR_LB_NAT_DATA_H */ > \ No newline at end of file > diff --git a/northd/en-lr-nat.h b/northd/en-lr-nat.h > index 01a16a21aa..2e3f285d12 100644 > --- a/northd/en-lr-nat.h > +++ b/northd/en-lr-nat.h > @@ -89,6 +89,9 @@ struct lr_nat_table { > const struct lr_nat_record * lr_nat_table_find_by_index( > const struct lr_nat_table *, size_t od_index); > > +#define LR_NAT_TABLE_FOR_EACH(LR_NAT_REC, TABLE) \ > + HMAP_FOR_EACH (LR_NAT_REC, key_node, &(TABLE)->entries) > + > /* Incremental processing implementation. */ > struct lr_nat_input { > /* Northbound table references. */ > diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c > index 10ade620e7..7c22949f74 100644 > --- a/northd/en-sync-sb.c > +++ b/northd/en-sync-sb.c > @@ -22,6 +22,7 @@ > #include "openvswitch/util.h" > > #include "en-lr-nat.h" > +#include "en-lr-lb-nat-data.h" > #include "en-sync-sb.h" > #include "lib/inc-proc-eng.h" > #include "lib/lb.h" > @@ -41,7 +42,7 @@ static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > const struct nbrec_address_set_table *, > const struct nbrec_port_group_table *, > const struct sbrec_address_set_table *, > - const struct ovn_datapaths *lr_datapaths); > + const struct lr_lb_nat_data_table *); > static const struct sbrec_address_set *sb_address_set_lookup_by_name( > struct ovsdb_idl_index *, const char *name); > static void update_sb_addr_set(struct sorted_array *, > @@ -87,11 +88,11 @@ en_sync_to_sb_addr_set_run(struct engine_node *node, void *data OVS_UNUSED) > EN_OVSDB_GET(engine_get_input("SB_address_set", node)); > > const struct engine_context *eng_ctx = engine_get_context(); > - struct northd_data *northd_data = engine_get_input_data("northd", node); > - > + const struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > + engine_get_input_data("lr_lb_nat_data", node); > sync_addr_sets(eng_ctx->ovnsb_idl_txn, nb_address_set_table, > nb_port_group_table, sb_address_set_table, > - &northd_data->lr_datapaths); > + &lr_lb_nat_data->lr_lbnats); > > engine_set_node_state(node, EN_UPDATED); > } > @@ -288,10 +289,12 @@ en_sync_to_sb_pb_run(struct engine_node *node, void *data OVS_UNUSED) > { > const struct engine_context *eng_ctx = engine_get_context(); > struct northd_data *northd_data = engine_get_input_data("northd", node); > - struct ed_type_lr_nat_data *lr_nat_data = > - engine_get_input_data("lr_nat", node); > + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > + engine_get_input_data("lr_lb_nat_data", node); > + > sync_pbs(eng_ctx->ovnsb_idl_txn, &northd_data->ls_ports, > - &northd_data->lr_ports, &lr_nat_data->lr_nats); > + &northd_data->lr_ports, > + &lr_lb_nat_data->lr_lbnats); > engine_set_node_state(node, EN_UPDATED); > } > > @@ -316,11 +319,12 @@ sync_to_sb_pb_northd_handler(struct engine_node *node, void *data OVS_UNUSED) > return false; > } > > - struct ed_type_lr_nat_data *lr_nat_data = > - engine_get_input_data("lr_nat", node); > + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > + engine_get_input_data("lr_lb_nat_data", node); > > if (!sync_pbs_for_northd_changed_ovn_ports( > - &nd->trk_northd_changes.trk_ovn_ports, &lr_nat_data->lr_nats)) { > + &nd->trk_northd_changes.trk_ovn_ports, > + &lr_lb_nat_data->lr_lbnats)) { > return false; > } > > @@ -366,7 +370,7 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > const struct nbrec_address_set_table *nb_address_set_table, > const struct nbrec_port_group_table *nb_port_group_table, > const struct sbrec_address_set_table *sb_address_set_table, > - const struct ovn_datapaths *lr_datapaths) > + const struct lr_lb_nat_data_table *lr_lbnats) > { > struct shash sb_address_sets = SHASH_INITIALIZER(&sb_address_sets); > > @@ -410,16 +414,14 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > } > > /* Sync router load balancer VIP generated address sets. */ > - struct ovn_datapath *od; > - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { > - ovs_assert(od->nbr); > - > - if (sset_count(&od->lb_ips->ips_v4_reachable)) { > - char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key, > - AF_INET); > + const struct lr_lb_nat_data_record *lrlb_rec; > + LR_LB_NAT_DATA_TABLE_FOR_EACH (lrlb_rec, lr_lbnats) { > + if (sset_count(&lrlb_rec->lb_ips->ips_v4_reachable)) { > + char *ipv4_addrs_name = > + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET); > > struct sorted_array ipv4_addrs_sorted = > - sorted_array_from_sset(&od->lb_ips->ips_v4_reachable); > + sorted_array_from_sset(&lrlb_rec->lb_ips->ips_v4_reachable); > > sync_addr_set(ovnsb_txn, ipv4_addrs_name, > &ipv4_addrs_sorted, &sb_address_sets); > @@ -427,11 +429,11 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > free(ipv4_addrs_name); > } > > - if (sset_count(&od->lb_ips->ips_v6_reachable)) { > - char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key, > - AF_INET6); > - struct sorted_array ipv6_addrs_sorted = > - sorted_array_from_sset(&od->lb_ips->ips_v6_reachable); > + if (sset_count(&lrlb_rec->lb_ips->ips_v6_reachable)) { > + char *ipv6_addrs_name = > + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET6); > + struct sorted_array ipv6_addrs_sorted = sorted_array_from_sset( > + &lrlb_rec->lb_ips->ips_v6_reachable); > > sync_addr_set(ovnsb_txn, ipv6_addrs_name, > &ipv6_addrs_sorted, &sb_address_sets); > diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c > index 2bd66b8808..369a151fa3 100644 > --- a/northd/inc-proc-northd.c > +++ b/northd/inc-proc-northd.c > @@ -31,6 +31,7 @@ > #include "openvswitch/vlog.h" > #include "inc-proc-northd.h" > #include "en-lb-data.h" > +#include "en-lr-lb-nat-data.h" > #include "en-lr-nat.h" > #include "en-northd.h" > #include "en-lflow.h" > @@ -148,6 +149,7 @@ static ENGINE_NODE(sync_to_sb_lb, "sync_to_sb_lb"); > static ENGINE_NODE(sync_to_sb_pb, "sync_to_sb_pb"); > static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data"); > static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_nat, "lr_nat"); > +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_lb_nat_data, "lr_lb_nat_data"); > > void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > struct ovsdb_idl_loop *sb) > @@ -196,6 +198,13 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_lr_nat, &en_nb_logical_router, > lr_nat_logical_router_handler); > > + engine_add_input(&en_lr_lb_nat_data, &en_northd, > + lr_lb_nat_data_northd_handler); > + engine_add_input(&en_lr_lb_nat_data, &en_lr_nat, > + lr_lb_nat_data_lr_nat_handler); > + engine_add_input(&en_lr_lb_nat_data, &en_lb_data, > + lr_lb_nat_data_lb_data_handler); > + > engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL); > engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL); > engine_add_input(&en_mac_binding_aging, &en_northd, NULL); > @@ -220,12 +229,14 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); > engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); > engine_add_input(&en_lflow, &en_lr_nat, NULL); > + engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); > > engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, > sync_to_sb_addr_set_nb_address_set_handler); > engine_add_input(&en_sync_to_sb_addr_set, &en_nb_port_group, > sync_to_sb_addr_set_nb_port_group_handler); > engine_add_input(&en_sync_to_sb_addr_set, &en_northd, NULL); > + engine_add_input(&en_sync_to_sb_addr_set, &en_lr_lb_nat_data, NULL); > engine_add_input(&en_sync_to_sb_addr_set, &en_sb_address_set, NULL); > > engine_add_input(&en_port_group, &en_nb_port_group, > @@ -243,7 +254,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > > engine_add_input(&en_sync_to_sb_pb, &en_northd, > sync_to_sb_pb_northd_handler); > - engine_add_input(&en_sync_to_sb_pb, &en_lr_nat, NULL); > + engine_add_input(&en_sync_to_sb_pb, &en_lr_lb_nat_data, NULL); > > /* en_sync_to_sb engine node syncs the SB database tables from > * the NB database tables. > diff --git a/northd/northd.c b/northd/northd.c > index 44c9c3d729..24df14c0de 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -44,6 +44,7 @@ > #include "northd.h" > #include "en-lb-data.h" > #include "en-lr-nat.h" > +#include "en-lr-lb-nat-data.h" > #include "lib/ovn-parallel-hmap.h" > #include "ovn/actions.h" > #include "ovn/features.h" > @@ -617,13 +618,6 @@ init_lb_for_datapath(struct ovn_datapath *od) > } > } > > -static void > -destroy_lb_for_datapath(struct ovn_datapath *od) > -{ > - ovn_lb_ip_set_destroy(od->lb_ips); > - od->lb_ips = NULL; > -} > - > /* A group of logical router datapaths which are connected - either > * directly or indirectly. > * Each logical router can belong to only one group. */ > @@ -676,7 +670,6 @@ ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od) > destroy_ipam_info(&od->ipam_info); > free(od->router_ports); > free(od->ls_peers); > - destroy_lb_for_datapath(od); > free(od->localnet_ports); > free(od->l3dgw_ports); > destroy_mcast_info_for_datapath(od); > @@ -1311,121 +1304,6 @@ struct lflow_ref_node { > struct ovn_lflow *lflow; > }; > > -/* A logical switch port or logical router port. > - * > - * In steady state, an ovn_port points to a northbound Logical_Switch_Port > - * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a > - * southbound Port_Binding record (via 'sb'). As the state of the system > - * changes, join_logical_ports() may determine that there is a new LSP or LRP > - * that has no corresponding Port_Binding record (in which case build_ports()) > - * will create the missing Port_Binding) or that a Port_Binding record exists > - * that has no coresponding LSP (in which case build_ports() will delete the > - * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port > - * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. > - * > - * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but > - * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). > - */ > -struct ovn_port { > - /* Port name aka key. > - * > - * This is ordinarily the same as nbsp->name or nbrp->name and > - * sb->logical_port. (A distributed gateway port creates a "derived" > - * ovn_port with key "cr-%s" % nbrp->name.) */ > - struct hmap_node key_node; /* Index on 'key'. */ > - char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ > - char *json_key; /* 'key', quoted for use in JSON. */ > - > - const struct sbrec_port_binding *sb; /* May be NULL. */ > - > - uint32_t tunnel_key; > - > - /* Logical switch port data. */ > - const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ > - > - struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ > - unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ > - unsigned int n_lsp_non_router_addrs; /* Number of elements from the > - * beginning of 'lsp_addrs' extracted > - * directly from LSP 'addresses'. */ > - > - struct lport_addresses *ps_addrs; /* Port security addresses. */ > - unsigned int n_ps_addrs; > - > - bool lsp_can_be_inc_processed; /* If it can be incrementally processed when > - the port changes. */ > - > - /* Logical router port data. */ > - const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ > - > - struct lport_addresses lrp_networks; > - > - struct ovn_port_routable_addresses routables; > - > - /* Logical port multicast data. */ > - struct mcast_port_info mcast_info; > - > - /* At most one of l3dgw_port and cr_port can be not NULL. */ > - > - /* This is set to a distributed gateway port if and only if this ovn_port > - * is "derived" from it. Otherwise this is set to NULL. The derived > - * ovn_port represents the instance of distributed gateway port on the > - * gateway chassis.*/ > - struct ovn_port *l3dgw_port; > - > - /* This is set to the "derived" chassis-redirect port of this port if and > - * only if this port is a distributed gateway port. Otherwise this is set > - * to NULL. */ > - struct ovn_port *cr_port; > - > - bool has_unknown; /* If the addresses have 'unknown' defined. */ > - > - bool has_bfd; > - > - /* The port's peer: > - * > - * - A switch port S of type "router" has a router port R as a peer, > - * and R in turn has S has its peer. > - * > - * - Two connected logical router ports have each other as peer. > - * > - * - Other kinds of ports have no peer. */ > - struct ovn_port *peer; > - > - struct ovn_datapath *od; > - > - struct ovs_list list; /* In list of similar records. */ > - > - struct hmap_node dp_node; /* Node in od->ports. */ > - > - struct lport_addresses proxy_arp_addrs; > - > - /* Temporarily used for traversing a list (or hmap) of ports. */ > - bool visited; > - > - /* List of struct lflow_ref_node that points to the lflows generated by > - * this ovn_port. > - * > - * This data is initialized and destroyed by the en_northd node, but > - * populated and used only by the en_lflow node. Ideally this data should > - * be maintained as part of en_lflow's data (struct lflow_data): a hash > - * index from ovn_port key to lflows. However, it would be less efficient > - * and more complex: > - * > - * 1. It would require an extra search (using the index) to find the > - * lflows. > - * > - * 2. Building the index needs to be thread-safe, using either a global > - * lock which is obviously less efficient, or hash-based lock array which > - * is more complex. > - * > - * Adding the list here is more straightforward. The drawback is that we > - * need to keep in mind that this data belongs to en_lflow node, so never > - * access it from any other nodes. > - */ > - struct ovs_list lflows; > -}; > - > static bool lsp_can_be_inc_processed(const struct nbrec_logical_switch_port *); > > static bool > @@ -1450,16 +1328,21 @@ destroy_routable_addresses(struct ovn_port_routable_addresses *ra) > } > > static char **get_nat_addresses(const struct ovn_port *op, size_t *n, > - bool routable_only, bool include_lb_ips); > + bool routable_only, bool include_lb_ips, > + const struct lr_lb_nat_data_record *); > > -static void > -assign_routable_addresses(struct ovn_port *op) > +static struct ovn_port_routable_addresses > +get_op_routable_addresses(struct ovn_port *op, > + const struct lr_lb_nat_data_record *lr_lbnat_rec) > { > size_t n; > - char **nats = get_nat_addresses(op, &n, true, true); > + char **nats = get_nat_addresses(op, &n, true, true, lr_lbnat_rec); > > if (!nats) { > - return; > + return (struct ovn_port_routable_addresses) { > + .laddrs = NULL, > + .n_addrs = 0, > + }; > } > > struct lport_addresses *laddrs = xcalloc(n, sizeof(*laddrs)); > @@ -1475,9 +1358,15 @@ assign_routable_addresses(struct ovn_port *op) > } > free(nats); > > - /* Everything seems to have worked out */ > - op->routables.laddrs = laddrs; > - op->routables.n_addrs = n_addrs; > + if (!n_addrs) { > + free(laddrs); > + laddrs = NULL; > + } > + > + return (struct ovn_port_routable_addresses) { > + .laddrs = laddrs, > + .n_addrs = n_addrs, > + }; > } > > > @@ -1537,8 +1426,6 @@ ovn_port_destroy_orphan(struct ovn_port *port) > } > free(port->ps_addrs); > > - destroy_routable_addresses(&port->routables); > - > destroy_lport_addresses(&port->lrp_networks); > destroy_lport_addresses(&port->proxy_arp_addrs); > free(port->json_key); > @@ -2580,9 +2467,7 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, > sizeof *od->l3dgw_ports); > } > od->l3dgw_ports[od->n_l3dgw_ports++] = op; > - > - assign_routable_addresses(op); > - } > + } > } > } > > @@ -2679,7 +2564,8 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, > * and must free the returned array when it is no longer needed. */ > static char ** > get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, > - bool include_lb_ips) > + bool include_lb_ips, > + const struct lr_lb_nat_data_record *lr_lbnat_rec) > { > size_t n_nats = 0; > struct eth_addr mac; > @@ -2764,23 +2650,25 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, > } > } > > - if (include_lb_ips) { > + if (include_lb_ips && lr_lbnat_rec) { > const char *ip_address; > if (routable_only) { > - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4_routable) { > + SSET_FOR_EACH (ip_address, > + &lr_lbnat_rec->lb_ips->ips_v4_routable) { > ds_put_format(&c_addresses, " %s", ip_address); > central_ip_address = true; > } > - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6_routable) { > + SSET_FOR_EACH (ip_address, > + &lr_lbnat_rec->lb_ips->ips_v6_routable) { > ds_put_format(&c_addresses, " %s", ip_address); > central_ip_address = true; > } > } else { > - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4) { > + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v4) { > ds_put_format(&c_addresses, " %s", ip_address); > central_ip_address = true; > } > - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6) { > + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v6) { > ds_put_format(&c_addresses, " %s", ip_address); > central_ip_address = true; > } > @@ -3851,21 +3739,8 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, > HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { > ovs_assert(od->nbr); > > - /* Checking load balancer groups first, starting from the largest one, > - * to more efficiently copy IP sets. */ > - size_t largest_group = 0; > - > - for (size_t i = 1; i < od->nbr->n_load_balancer_group; i++) { > - if (od->nbr->load_balancer_group[i]->n_load_balancer > > - od->nbr->load_balancer_group[largest_group]->n_load_balancer) { > - largest_group = i; > - } > - } > - > for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { > - size_t idx = (i + largest_group) % od->nbr->n_load_balancer_group; > - > - nbrec_lb_group = od->nbr->load_balancer_group[idx]; > + nbrec_lb_group = od->nbr->load_balancer_group[i]; > const struct uuid *lb_group_uuid = &nbrec_lb_group->header_.uuid; > > lb_group_dps = > @@ -3873,20 +3748,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, > lb_group_uuid); > ovs_assert(lb_group_dps); > ovn_lb_group_datapaths_add_lr(lb_group_dps, od); > - > - if (!od->lb_ips) { > - od->lb_ips = > - ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); > - } else { > - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > - build_lrouter_lb_ips(od->lb_ips, > - lb_group_dps->lb_group->lbs[j]); > - } > - } > - } > - > - if (!od->lb_ips) { > - od->lb_ips = ovn_lb_ip_set_create(); > } > > for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { > @@ -3895,7 +3756,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, > lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); > ovs_assert(lb_dps); > ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > } > } > > @@ -3949,102 +3809,6 @@ build_lb_svcs( > } > } > > -static bool lrouter_port_ipv4_reachable(const struct ovn_port *op, > - ovs_be32 addr); > -static bool lrouter_port_ipv6_reachable(const struct ovn_port *op, > - const struct in6_addr *addr); > - > -static void > -add_neigh_ips_to_lrouter(struct ovn_datapath *od, > - enum lb_neighbor_responder_mode neigh_mode, > - const struct sset *lb_ips_v4, > - const struct sset *lb_ips_v6) > -{ > - /* If configured to not reply to any neighbor requests for all VIPs > - * return early. > - */ > - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > - return; > - } > - > - const char *ip_address; > - > - /* If configured to reply to neighbor requests for all VIPs force them > - * all to be considered "reachable". > - */ > - if (neigh_mode == LB_NEIGH_RESPOND_ALL) { > - SSET_FOR_EACH (ip_address, lb_ips_v4) { > - sset_add(&od->lb_ips->ips_v4_reachable, ip_address); > - } > - SSET_FOR_EACH (ip_address, lb_ips_v6) { > - sset_add(&od->lb_ips->ips_v6_reachable, ip_address); > - } > - > - return; > - } > - > - /* Otherwise, a VIP is reachable if there's at least one router > - * subnet that includes it. > - */ > - ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); > - > - SSET_FOR_EACH (ip_address, lb_ips_v4) { > - struct ovn_port *op; > - ovs_be32 vip_ip4; > - if (ip_parse(ip_address, &vip_ip4)) { > - HMAP_FOR_EACH (op, dp_node, &od->ports) { > - if (lrouter_port_ipv4_reachable(op, vip_ip4)) { > - sset_add(&od->lb_ips->ips_v4_reachable, > - ip_address); > - break; > - } > - } > - } > - } > - > - SSET_FOR_EACH (ip_address, lb_ips_v6) { > - struct ovn_port *op; > - struct in6_addr vip; > - if (ipv6_parse(ip_address, &vip)) { > - HMAP_FOR_EACH (op, dp_node, &od->ports) { > - if (lrouter_port_ipv6_reachable(op, &vip)) { > - sset_add(&od->lb_ips->ips_v6_reachable, > - ip_address); > - break; > - } > - } > - } > - } > -} > - > -static void > -remove_lrouter_lb_reachable_ips(struct ovn_datapath *od, > - enum lb_neighbor_responder_mode neigh_mode, > - const struct sset *lb_ips_v4, > - const struct sset *lb_ips_v6) > -{ > - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > - return; > - } > - > - const char *ip_address; > - SSET_FOR_EACH (ip_address, lb_ips_v4) { > - sset_find_and_delete(&od->lb_ips->ips_v4_reachable, ip_address); > - } > - SSET_FOR_EACH (ip_address, lb_ips_v6) { > - sset_find_and_delete(&od->lb_ips->ips_v6_reachable, ip_address); > - } > -} > - > -static void > -build_lrouter_lb_reachable_ips(struct ovn_datapath *od, > - const struct ovn_northd_lb *lb) > -{ > - add_neigh_ips_to_lrouter(od, lb->neigh_mode, &lb->ips_v4, > - &lb->ips_v6); > -} > - > - > static void > build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) > { > @@ -4066,43 +3830,6 @@ build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) > } > } > > -static void > -build_lrouter_lbs_reachable_ips(struct ovn_datapaths *lr_datapaths, > - struct hmap *lb_dps_map, > - struct hmap *lb_group_dps_map) > -{ > - struct ovn_datapath *od; > - > - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { > - if (!od->nbr) { > - continue; > - } > - > - for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { > - struct ovn_lb_datapaths *lb_dps = > - ovn_lb_datapaths_find(lb_dps_map, > - &od->nbr->load_balancer[i]->header_.uuid); > - ovs_assert(lb_dps); > - build_lrouter_lb_reachable_ips(od, lb_dps->lb); > - } > - > - for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { > - const struct nbrec_load_balancer_group *nbrec_lb_group = > - od->nbr->load_balancer_group[i]; > - struct ovn_lb_group_datapaths *lb_group_dps; > - > - lb_group_dps = > - ovn_lb_group_datapaths_find(lb_group_dps_map, > - &nbrec_lb_group->header_.uuid); > - ovs_assert(lb_group_dps); > - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > - build_lrouter_lb_reachable_ips(od, > - lb_group_dps->lb_group->lbs[j]); > - } > - } > - } > -} > - > static void > build_lswitch_lbs_from_lrouter(struct ovn_datapaths *lr_datapaths, > struct hmap *lb_dps_map, > @@ -4166,8 +3893,6 @@ build_lb_port_related_data( > struct hmap *svc_monitor_map) > { > build_lrouter_lbs_check(lr_datapaths); > - build_lrouter_lbs_reachable_ips(lr_datapaths, lb_dps_map, > - lb_group_dps_map); > build_lb_svcs(ovnsb_txn, sbrec_service_monitor_table, ls_ports, lb_dps_map, > svc_monitor_lsps, svc_monitor_map); > build_lswitch_lbs_from_lrouter(lr_datapaths, lb_dps_map, lb_group_dps_map); > @@ -4533,7 +4258,8 @@ check_sb_lb_duplicates(const struct sbrec_load_balancer_table *table) > * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it > * only syncs the nat column of port binding corresponding to the 'op->nbsp' */ > static void > -sync_pb_for_lsp(struct ovn_port *op) > +sync_pb_for_lsp(struct ovn_port *op, > + const struct lr_lb_nat_data_table *lr_lbnats) > { > ovs_assert(op->nbsp); > > @@ -4552,10 +4278,17 @@ sync_pb_for_lsp(struct ovn_port *op) > if (nat_addresses && !strcmp(nat_addresses, "router")) { > if (op->peer && op->peer->od > && (chassis || op->peer->od->n_l3dgw_ports)) { > - bool exclude_lb_vips = smap_get_bool(&op->nbsp->options, > + bool include_lb_vips = !smap_get_bool(&op->nbsp->options, > "exclude-lb-vips-from-garp", false); > + > + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; > + > + if (include_lb_vips) { > + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index( > + lr_lbnats, op->peer->od->index); > + } > nats = get_nat_addresses(op->peer, &n_nats, false, > - !exclude_lb_vips); > + include_lb_vips, lr_lbnat_rec); > } > } else if (nat_addresses && (chassis || l3dgw_ports)) { > struct lport_addresses laddrs; > @@ -4662,7 +4395,8 @@ sync_pb_for_lsp(struct ovn_port *op) > * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it > * only sets the port binding options column for the router ports */ > static void > -sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) > +sync_pb_for_lrp(struct ovn_port *op, > + const struct lr_lb_nat_data_table *lr_lbnats) > { > ovs_assert(op->nbrp); > > @@ -4671,14 +4405,14 @@ sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) > > const char *chassis_name = smap_get(&op->od->nbr->options, "chassis"); > if (is_cr_port(op)) { > - const struct lr_nat_record *lrnat_rec = > - lr_nat_table_find_by_index(lr_nats, op->od->index); > - ovs_assert(lrnat_rec); > + const struct lr_lb_nat_data_record *lr_lbnat_rec = > + lr_lb_nat_data_table_find_by_index(lr_lbnats, op->od->index); > + ovs_assert(lr_lbnat_rec); > > smap_add(&new, "distributed-port", op->nbrp->name); > > bool always_redirect = > - !lrnat_rec->has_distributed_nat && > + !lr_lbnat_rec->lrnat_rec->has_distributed_nat && > !l3dgw_port_has_associated_vtep_lports(op->l3dgw_port); > > const char *redirect_type = smap_get(&op->nbrp->options, > @@ -4729,17 +4463,18 @@ static void ovn_update_ipv6_opt_for_op(struct ovn_port *op); > * the logical switch ports. */ > void > sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, > - struct hmap *lr_ports, const struct lr_nat_table *lr_nats) > + struct hmap *lr_ports, > + const struct lr_lb_nat_data_table *lr_lbnats) > { > ovs_assert(ovnsb_idl_txn); > > struct ovn_port *op; > HMAP_FOR_EACH (op, key_node, ls_ports) { > - sync_pb_for_lsp(op); > + sync_pb_for_lsp(op, lr_lbnats); > } > > HMAP_FOR_EACH (op, key_node, lr_ports) { > - sync_pb_for_lrp(op, lr_nats); > + sync_pb_for_lrp(op, lr_lbnats); > } > > ovn_update_ipv6_options(lr_ports); > @@ -4748,17 +4483,18 @@ sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, > /* Sync the SB Port bindings for the added and updated logical switch ports > * of the tracked northd engine data. */ > bool > -sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, > - const struct lr_nat_table *lr_nats) > +sync_pbs_for_northd_changed_ovn_ports( > + struct tracked_ovn_ports *trk_ovn_ports, > + const struct lr_lb_nat_data_table *lr_lbnats) > { > struct hmapx_node *hmapx_node; > struct ovn_port *op; > HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->created) { > op = hmapx_node->data; > if (op->nbsp) { > - sync_pb_for_lsp(op); > + sync_pb_for_lsp(op, lr_lbnats); > } else { > - sync_pb_for_lrp(op, lr_nats); > + sync_pb_for_lrp(op, lr_lbnats); > ovn_update_ipv6_opt_for_op(op); > } > } > @@ -4766,9 +4502,9 @@ sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, > HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->updated) { > op = hmapx_node->data; > if (op->nbsp) { > - sync_pb_for_lsp(op); > + sync_pb_for_lsp(op, lr_lbnats); > } else { > - sync_pb_for_lrp(op, lr_nats); > + sync_pb_for_lrp(op, lr_lbnats); > ovn_update_ipv6_opt_for_op(op); > } > } > @@ -5475,20 +5211,24 @@ fail: > } > > /* Returns true if the logical router has changes which can be > - * incrementally handled. > + * incrementally handled or the changes can be ignored. > * Presently supports i-p for the below changes: > * - load balancers and load balancer groups. > + * > + * Presently below changes are ignored: > + * - router NAT changes - as the engine node lr-nat handles it. > */ > static bool > -lr_changes_can_be_handled( > +lr_changes_can_be_handled_or_ignored( > const struct nbrec_logical_router *lr) > { > /* Check if the columns are changed in this row. */ > enum nbrec_logical_router_column_id col; > for (col = 0; col < NBREC_LOGICAL_ROUTER_N_COLUMNS; col++) { > if (nbrec_logical_router_is_updated(lr, col)) { > - if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER || > - col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP) { > + if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER > + || col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP > + || col == NBREC_LOGICAL_ROUTER_COL_NAT) { > continue; > } > return false; > @@ -5507,12 +5247,6 @@ lr_changes_can_be_handled( > OVSDB_IDL_CHANGE_MODIFY) > 0) { > return false; > } > - for (size_t i = 0; i < lr->n_nat; i++) { > - if (nbrec_nat_row_get_seqno(lr->nat[i], > - OVSDB_IDL_CHANGE_MODIFY) > 0) { > - return false; > - } > - } > for (size_t i = 0; i < lr->n_policies; i++) { > if (nbrec_logical_router_policy_row_get_seqno(lr->policies[i], > OVSDB_IDL_CHANGE_MODIFY) > 0) { > @@ -5528,14 +5262,15 @@ lr_changes_can_be_handled( > return true; > } > > -/* Return true if changes are handled incrementally, false otherwise. > +/* Return true if changes are handled incrementally or can be safely > + * ignored (because those changes are handled by other engine nodes), > + * false otherwise. > * When there are any changes, try to track what's exactly changed and set > * northd_data->change_tracked accordingly: change tracked - true, otherwise, > * false. > * Note: Changes to load balancer and load balancer groups associated with > * the logical routers are handled separately in the lb_data change > - * handlers (northd_handle_lb_data_changes_pre_od and > - * northd_handle_lb_data_changes_post_od). > + * handler (northd_handle_lb_data_changes). > * */ > bool > northd_handle_lr_changes(const struct northd_input *ni, > @@ -5550,9 +5285,11 @@ northd_handle_lr_changes(const struct northd_input *ni, > goto fail; > } > > - /* Presently only able to handle load balancer and > - * load balancer group changes. */ > - if (!lr_changes_can_be_handled(changed_lr)) { > + /* Presently > + * - only able to handle load balancer and load balancer group > + changes. > + * - and ignore NAT changes */ > + if (!lr_changes_can_be_handled_or_ignored(changed_lr)) { > goto fail; > } > } > @@ -5804,10 +5541,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > ovs_assert(lb_dps); > ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > > - /* Add the lb_ips of lb_dps to the od. */ > - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > - build_lrouter_lb_reachable_ips(od, lb_dps->lb); > - > /* Add the lb to the northd tracked data. */ > hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); > } > @@ -5826,10 +5559,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > ovs_assert(lb_dps); > ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > > - /* Add the lb_ips of lb_dps to the od. */ > - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > - build_lrouter_lb_reachable_ips(od, lb_dps->lb); > - > /* Add the lb to the northd tracked data. */ > hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); > } > @@ -5865,22 +5594,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > /* Re-evaluate 'od->has_lb_vip' */ > init_lb_for_datapath(od); > > - /* Update the od->lb_ips with the deleted and inserted > - * vips (if any). */ > - remove_ips_from_lb_ip_set(od->lb_ips, lb->routable, > - &clb->deleted_vips_v4, > - &clb->deleted_vips_v6); > - add_ips_to_lb_ip_set(od->lb_ips, lb->routable, > - &clb->inserted_vips_v4, > - &clb->inserted_vips_v6); > - > - remove_lrouter_lb_reachable_ips(od, lb->neigh_mode, > - &clb->deleted_vips_v4, > - &clb->deleted_vips_v6); > - add_neigh_ips_to_lrouter(od, lb->neigh_mode, > - &clb->inserted_vips_v4, > - &clb->inserted_vips_v6); > - > /* Add the lr datapath to the northd tracked data. */ > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > } > @@ -5908,9 +5621,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > /* Re-evaluate 'od->has_lb_vip' */ > init_lb_for_datapath(od); > > - /* Add the lb_ips of lb_dps to the od. */ > - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > - > /* Add the lr datapath to the northd tracked data. */ > hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > } > @@ -9202,7 +8912,7 @@ arp_nd_ns_match(const char *ips, int addr_family, struct ds *match) > /* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the > * IPs configured on the router port. > */ > -static bool > +bool > lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) > { > for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > @@ -9218,7 +8928,7 @@ lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) > /* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the > * IPs configured on the router port. > */ > -static bool > +bool > lrouter_port_ipv6_reachable(const struct ovn_port *op, > const struct in6_addr *addr) > { > @@ -9284,6 +8994,7 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, > struct ovn_datapath *sw_od, > struct ovn_port *sw_op, > const struct lr_nat_table *lr_nats, > + const struct lr_lb_nat_data_table *lr_lbnats, > struct hmap *lflows, > const struct ovsdb_idl_row *stage_hint) > { > @@ -9299,32 +9010,38 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, > * router port. > * Priority: 80. > */ > - > - const char *ip_addr; > - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v4_reachable) { > - ovs_be32 ipv4_addr; > - > - /* Check if the ovn port has a network configured on which we could > - * expect ARP requests for the LB VIP. > - */ > - if (ip_parse(ip_addr, &ipv4_addr) && > - lrouter_port_ipv4_reachable(op, ipv4_addr)) { > - build_lswitch_rport_arp_req_flow( > - ip_addr, AF_INET, sw_op, sw_od, 80, lflows, > - stage_hint); > + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; > + if (op->od->nbr->n_load_balancer || op->od->nbr->n_load_balancer_group) { > + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, > + op->od->index); > + ovs_assert(lr_lbnat_rec); > + > + const char *ip_addr; > + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v4_reachable) { > + ovs_be32 ipv4_addr; > + > + /* Check if the ovn port has a network configured on which we could > + * expect ARP requests for the LB VIP. > + */ > + if (ip_parse(ip_addr, &ipv4_addr) && > + lrouter_port_ipv4_reachable(op, ipv4_addr)) { > + build_lswitch_rport_arp_req_flow( > + ip_addr, AF_INET, sw_op, sw_od, 80, lflows, > + stage_hint); > + } > } > - } > - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v6_reachable) { > - struct in6_addr ipv6_addr; > + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v6_reachable) { > + struct in6_addr ipv6_addr; > > - /* Check if the ovn port has a network configured on which we could > - * expect NS requests for the LB VIP. > - */ > - if (ipv6_parse(ip_addr, &ipv6_addr) && > - lrouter_port_ipv6_reachable(op, &ipv6_addr)) { > - build_lswitch_rport_arp_req_flow( > - ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, > - stage_hint); > + /* Check if the ovn port has a network configured on which we could > + * expect NS requests for the LB VIP. > + */ > + if (ipv6_parse(ip_addr, &ipv6_addr) && > + lrouter_port_ipv6_reachable(op, &ipv6_addr)) { > + build_lswitch_rport_arp_req_flow( > + ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, > + stage_hint); > + } > } > } > > @@ -9374,13 +9091,15 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, > * expect ARP requests/NS for the DNAT external_ip. > */ > if (nat_entry_is_v6(nat_entry)) { > - if (!sset_contains(&op->od->lb_ips->ips_v6, nat->external_ip)) { > + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, > + nat->external_ip)) { > build_lswitch_rport_arp_req_flow( > nat->external_ip, AF_INET6, sw_op, sw_od, 80, lflows, > stage_hint); > } > } else { > - if (!sset_contains(&op->od->lb_ips->ips_v4, nat->external_ip)) { > + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, > + nat->external_ip)) { > build_lswitch_rport_arp_req_flow( > nat->external_ip, AF_INET, sw_op, sw_od, 80, lflows, > stage_hint); > @@ -10441,6 +10160,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, > static void > build_lswitch_ip_unicast_lookup(struct ovn_port *op, > const struct lr_nat_table *lr_nats, > + const struct lr_lb_nat_data_table *lr_lbnats, > struct hmap *lflows, > struct ds *actions, > struct ds *match) > @@ -10456,7 +10176,8 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op, > */ > if (lsp_is_router(op->nbsp)) { > build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lr_nats, > - lflows, &op->nbsp->header_); > + lr_lbnats, lflows, > + &op->nbsp->header_); > } > > for (size_t i = 0; i < op->nbsp->n_addresses; i++) { > @@ -12646,6 +12367,7 @@ build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op, > static void > build_lrouter_drop_own_dest(struct ovn_port *op, > const struct lr_nat_record *lrnat_rec, > + const struct lr_lb_nat_data_record *lr_lbnat_rec, > enum ovn_stage stage, > uint16_t priority, bool drop_snat_ip, > struct hmap *lflows) > @@ -12658,8 +12380,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, > > bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, > ip); > - bool router_ip_in_lb_ips = > - !!sset_find(&op->od->lb_ips->ips_v4, ip); > + bool router_ip_in_lb_ips = (lr_lbnat_rec && > + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v4, > + ip)); > bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || > router_ip_in_lb_ips)); > > @@ -12688,8 +12411,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, > > bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, > ip); > - bool router_ip_in_lb_ips = > - !!sset_find(&op->od->lb_ips->ips_v6, ip); > + bool router_ip_in_lb_ips = (lr_lbnat_rec && > + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v6, > + ip)); > bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || > router_ip_in_lb_ips)); > > @@ -13401,7 +13125,8 @@ build_ip_routing_flows_for_lrp( > */ > static void > build_ip_routing_flows_for_router_type_lsp( > - struct ovn_port *op, const struct hmap *lr_ports, struct hmap *lflows) > + struct ovn_port *op, const struct lr_lb_nat_data_table *lr_lbnats, > + const struct hmap *lr_ports, struct hmap *lflows) > { > ovs_assert(op->nbsp); > if (!lsp_is_router(op->nbsp)) { > @@ -13409,7 +13134,8 @@ build_ip_routing_flows_for_router_type_lsp( > } > > struct ovn_port *peer = ovn_port_get_peer(lr_ports, op); > - if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs) { > + if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs > + || !op->od->n_router_ports) { > return; > } > > @@ -13420,19 +13146,29 @@ build_ip_routing_flows_for_router_type_lsp( > continue; > } > > - struct ovn_port_routable_addresses *ra = &router_port->routables; > - for (size_t j = 0; j < ra->n_addrs; j++) { > - struct lport_addresses *laddrs = &ra->laddrs[j]; > - for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { > - add_route(lflows, peer->od, peer, > - peer->lrp_networks.ipv4_addrs[0].addr_s, > - laddrs->ipv4_addrs[k].network_s, > - laddrs->ipv4_addrs[k].plen, NULL, false, 0, > - &peer->nbrp->header_, false, > - ROUTE_PRIO_OFFSET_CONNECTED); > + const struct lr_lb_nat_data_record *lr_lbnat_rec = > + lr_lb_nat_data_table_find_by_index(lr_lbnats, > + router_port->od->index); > + > + if (router_port->nbrp->ha_chassis_group || > + router_port->nbrp->n_gateway_chassis) { > + struct ovn_port_routable_addresses ra = > + get_op_routable_addresses(router_port, lr_lbnat_rec); > + for (size_t j = 0; j < ra.n_addrs; j++) { > + struct lport_addresses *laddrs = &ra.laddrs[j]; > + for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { > + add_route(lflows, peer->od, peer, > + peer->lrp_networks.ipv4_addrs[0].addr_s, > + laddrs->ipv4_addrs[k].network_s, > + laddrs->ipv4_addrs[k].plen, NULL, false, 0, > + &peer->nbrp->header_, false, > + ROUTE_PRIO_OFFSET_CONNECTED); > + } > } > + destroy_routable_addresses(&ra); > } > } > + > } > > static void > @@ -13656,33 +13392,36 @@ build_arp_resolve_flows_for_lrouter( > > static void > routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, > - struct ovn_port *peer, struct ds *match, > - struct ds *actions) > + struct ovn_port *peer, > + const struct lr_lb_nat_data_record *lr_lbnat_rec, > + struct ds *match, struct ds *actions) > { > - struct ovn_port_routable_addresses *ra = &router_port->routables; > - if (!ra->n_addrs) { > + struct ovn_port_routable_addresses ra = > + get_op_routable_addresses(router_port, lr_lbnat_rec); > + if (!ra.n_addrs) { > return; > } > > - for (size_t i = 0; i < ra->n_addrs; i++) { > + for (size_t i = 0; i < ra.n_addrs; i++) { > ds_clear(match); > ds_put_format(match, "outport == %s && "REG_NEXT_HOP_IPV4" == {", > peer->json_key); > bool first = true; > - for (size_t j = 0; j < ra->laddrs[i].n_ipv4_addrs; j++) { > + for (size_t j = 0; j < ra.laddrs[i].n_ipv4_addrs; j++) { > if (!first) { > ds_put_cstr(match, ", "); > } > - ds_put_cstr(match, ra->laddrs[i].ipv4_addrs[j].addr_s); > + ds_put_cstr(match, ra.laddrs[i].ipv4_addrs[j].addr_s); > first = false; > } > ds_put_cstr(match, "}"); > > ds_clear(actions); > - ds_put_format(actions, "eth.dst = %s; next;", ra->laddrs[i].ea_s); > + ds_put_format(actions, "eth.dst = %s; next;", ra.laddrs[i].ea_s); > ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100, > ds_cstr(match), ds_cstr(actions)); > } > + destroy_routable_addresses(&ra); > } > > /* Local router ingress table ARP_RESOLVE: ARP Resolution. > @@ -13699,6 +13438,7 @@ routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, > static void > build_arp_resolve_flows_for_lrp( > struct ovn_port *op, const struct lr_nat_record *lrnat_rec, > + const struct lr_lb_nat_data_record *lr_lbnat_rec, > struct hmap *lflows, struct ds *match, struct ds *actions) > { > ovs_assert(op->nbrp); > @@ -13775,8 +13515,8 @@ build_arp_resolve_flows_for_lrp( > * > * Priority 2. > */ > - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_ARP_RESOLVE, 2, > - true, lflows); > + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, > + S_ROUTER_IN_ARP_RESOLVE, 2, true, lflows); > } > > /* This function adds ARP resolve flows related to a LSP. */ > @@ -13784,6 +13524,7 @@ static void > build_arp_resolve_flows_for_lsp( > struct ovn_port *op, struct hmap *lflows, > const struct hmap *lr_ports, > + const struct lr_lb_nat_data_table *lr_lbnats, > struct ds *match, struct ds *actions) > { > ovs_assert(op->nbsp); > @@ -13927,8 +13668,11 @@ build_arp_resolve_flows_for_lsp( > > if (smap_get(&peer->od->nbr->options, "chassis") > || peer->cr_port) { > + const struct lr_lb_nat_data_record *lr_lbnat_rec; > + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, > + router_port->od->index); > routable_addresses_to_lflows(lflows, router_port, peer, > - match, actions); > + lr_lbnat_rec, match, actions); > } > } > } > @@ -14648,6 +14392,7 @@ static void > build_lrouter_ipv4_ip_input(struct ovn_port *op, > struct hmap *lflows, > const struct lr_nat_record *lrnat_rec, > + const struct lr_lb_nat_data_record *lr_lbnat_rec, > struct ds *match, struct ds *actions, > const struct shash *meter_groups) > { > @@ -14772,7 +14517,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, > &op->nbrp->header_, lflows); > } > > - if (sset_count(&op->od->lb_ips->ips_v4_reachable)) { > + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v4_reachable)) { > ds_clear(match); > if (is_l3dgw_port(op)) { > ds_put_format(match, "is_chassis_resident(%s)", > @@ -14788,7 +14533,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, > free(lb_ips_v4_as); > } > > - if (sset_count(&op->od->lb_ips->ips_v6_reachable)) { > + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v6_reachable)) { > ds_clear(match); > > if (is_l3dgw_port(op)) { > @@ -14890,8 +14635,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, > * Priority 60. > */ > if (!lrnat_rec->lb_force_snat_router_ip) { > - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_IP_INPUT, 60, > - false, lflows); > + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, > + S_ROUTER_IN_IP_INPUT, 60, false, lflows); > } > /* ARP / ND handling for external IP addresses. > * > @@ -16030,6 +15775,7 @@ struct lswitch_flow_build_info { > const struct hmap *lr_ports; > const struct ls_port_group_table *ls_port_groups; > const struct lr_nat_table *lr_nats; > + const struct lr_lb_nat_data_table *lr_lbnats; > struct hmap *lflows; > struct hmap *igmp_groups; > const struct shash *meter_groups; > @@ -16113,14 +15859,15 @@ build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od, > * switch port. > */ > static void > -build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, > - const struct hmap *ls_ports, > - const struct hmap *lr_ports, > - const struct lr_nat_table *lr_nats, > - const struct shash *meter_groups, > - struct ds *match, > - struct ds *actions, > - struct hmap *lflows) > +build_lswitch_and_lrouter_iterate_by_lsp( > + struct ovn_port *op, const struct hmap *ls_ports, > + const struct hmap *lr_ports, > + const struct lr_nat_table *lr_nats, > + const struct lr_lb_nat_data_table *lr_lbnats, > + const struct shash *meter_groups, > + struct ds *match, > + struct ds *actions, > + struct hmap *lflows) > { > ovs_assert(op->nbsp); > start_collecting_lflows(); > @@ -16133,11 +15880,14 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, > meter_groups, actions, match); > build_lswitch_dhcp_options_and_response(op, lflows, meter_groups); > build_lswitch_external_port(op, lflows); > - build_lswitch_ip_unicast_lookup(op, lr_nats, lflows, actions, match); > + build_lswitch_ip_unicast_lookup(op, lr_nats, lr_lbnats, lflows, actions, > + match); > > /* Build Logical Router Flows. */ > - build_ip_routing_flows_for_router_type_lsp(op, lr_ports, lflows); > - build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, match, actions); > + build_ip_routing_flows_for_router_type_lsp(op, lr_lbnats, lr_ports, > + lflows); > + build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, lr_lbnats, > + match, actions); > > link_ovn_port_to_lflows(op, &collected_lflows); > end_collecting_lflows(); > @@ -16156,6 +15906,8 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, > lsi->lr_nats, op->od->index); > ovs_assert(lrnet_rec); > > + const struct lr_lb_nat_data_record *lr_lbnat_rec = > + lr_lb_nat_data_table_find_by_index(lsi->lr_lbnats, op->od->index); > build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > &lsi->actions); > build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > @@ -16163,15 +15915,15 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, > build_ip_routing_flows_for_lrp(op, lsi->lflows); > build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > &lsi->actions, lsi->meter_groups); > - build_arp_resolve_flows_for_lrp(op, lrnet_rec, lsi->lflows, &lsi->match, > - &lsi->actions); > + build_arp_resolve_flows_for_lrp(op, lrnet_rec, lr_lbnat_rec, lsi->lflows, > + &lsi->match, &lsi->actions); > build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > &lsi->actions); > build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match); > build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows, > &lsi->match, &lsi->actions, > lsi->meter_groups); > - build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, > + build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, lr_lbnat_rec, > &lsi->match, &lsi->actions, lsi->meter_groups); > build_lrouter_force_snat_flows_op(op, lrnet_rec, lsi->lflows, &lsi->match, > &lsi->actions); > @@ -16234,6 +15986,7 @@ build_lflows_thread(void *arg) > build_lswitch_and_lrouter_iterate_by_lsp(op, lsi->ls_ports, > lsi->lr_ports, > lsi->lr_nats, > + lsi->lr_lbnats, > lsi->meter_groups, > &lsi->match, > &lsi->actions, > @@ -16344,6 +16097,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > const struct hmap *lr_ports, > const struct ls_port_group_table *ls_pgs, > const struct lr_nat_table *lr_nats, > + const struct lr_lb_nat_data_table *lr_lbnats, > struct hmap *lflows, > struct hmap *igmp_groups, > const struct shash *meter_groups, > @@ -16374,6 +16128,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > lsiv[index].lr_ports = lr_ports; > lsiv[index].ls_port_groups = ls_pgs; > lsiv[index].lr_nats = lr_nats; > + lsiv[index].lr_lbnats = lr_lbnats; > lsiv[index].igmp_groups = igmp_groups; > lsiv[index].meter_groups = meter_groups; > lsiv[index].lb_dps_map = lb_dps_map; > @@ -16409,6 +16164,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > .lr_ports = lr_ports, > .ls_port_groups = ls_pgs, > .lr_nats = lr_nats, > + .lr_lbnats = lr_lbnats, > .lflows = lflows, > .igmp_groups = igmp_groups, > .meter_groups = meter_groups, > @@ -16437,6 +16193,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > build_lswitch_and_lrouter_iterate_by_lsp(op, lsi.ls_ports, > lsi.lr_ports, > lsi.lr_nats, > + lsi.lr_lbnats, > lsi.meter_groups, > &lsi.match, &lsi.actions, > lsi.lflows); > @@ -16558,6 +16315,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, > input_data->lr_ports, > input_data->ls_port_groups, > input_data->lr_nats, > + input_data->lr_lbnats, > lflows, > &igmp_groups, > input_data->meter_groups, > @@ -17038,6 +16796,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, > build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, > lflow_input->lr_ports, > lflow_input->lr_nats, > + lflow_input->lr_lbnats, > lflow_input->meter_groups, > &match, &actions, > lflows); > @@ -17076,6 +16835,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, > build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, > lflow_input->lr_ports, > lflow_input->lr_nats, > + lflow_input->lr_lbnats, > lflow_input->meter_groups, > &match, &actions, > lflows); > diff --git a/northd/northd.h b/northd/northd.h > index 564729ebcc..7c446f5758 100644 > --- a/northd/northd.h > +++ b/northd/northd.h > @@ -179,6 +179,7 @@ struct lflow_input { > const struct hmap *lr_ports; > const struct ls_port_group_table *ls_port_groups; > const struct lr_nat_table *lr_nats; > + const struct lr_lb_nat_data_table *lr_lbnats; > const struct shash *meter_groups; > const struct hmap *lb_datapaths_map; > const struct hmap *bfd_connections; > @@ -318,9 +319,6 @@ struct ovn_datapath { > /* router datapath has a logical port with redirect-type set to bridged. */ > bool redirect_bridged; > > - /* Load Balancer vIPs relevant for this datapath. */ > - struct ovn_lb_ip_set *lb_ips; > - > struct ovn_port **localnet_ports; > size_t n_localnet_ports; > > @@ -337,6 +335,119 @@ struct ovn_datapath { > const struct ovn_datapath *ovn_datapath_find(const struct hmap *datapaths, > const struct uuid *uuid); > > +/* A logical switch port or logical router port. > + * > + * In steady state, an ovn_port points to a northbound Logical_Switch_Port > + * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a > + * southbound Port_Binding record (via 'sb'). As the state of the system > + * changes, join_logical_ports() may determine that there is a new LSP or LRP > + * that has no corresponding Port_Binding record (in which case build_ports()) > + * will create the missing Port_Binding) or that a Port_Binding record exists > + * that has no coresponding LSP (in which case build_ports() will delete the > + * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port > + * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. > + * > + * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but > + * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). > + */ > +struct ovn_port { > + /* Port name aka key. > + * > + * This is ordinarily the same as nbsp->name or nbrp->name and > + * sb->logical_port. (A distributed gateway port creates a "derived" > + * ovn_port with key "cr-%s" % nbrp->name.) */ > + struct hmap_node key_node; /* Index on 'key'. */ > + char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ > + char *json_key; /* 'key', quoted for use in JSON. */ > + > + const struct sbrec_port_binding *sb; /* May be NULL. */ > + > + uint32_t tunnel_key; > + > + /* Logical switch port data. */ > + const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ > + > + struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ > + unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ > + unsigned int n_lsp_non_router_addrs; /* Number of elements from the > + * beginning of 'lsp_addrs' extracted > + * directly from LSP 'addresses'. */ > + > + struct lport_addresses *ps_addrs; /* Port security addresses. */ > + unsigned int n_ps_addrs; > + > + bool lsp_can_be_inc_processed; /* If it can be incrementally processed when > + the port changes. */ > + > + /* Logical router port data. */ > + const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ > + > + struct lport_addresses lrp_networks; > + > + /* Logical port multicast data. */ > + struct mcast_port_info mcast_info; > + > + /* At most one of l3dgw_port and cr_port can be not NULL. */ > + > + /* This is set to a distributed gateway port if and only if this ovn_port > + * is "derived" from it. Otherwise this is set to NULL. The derived > + * ovn_port represents the instance of distributed gateway port on the > + * gateway chassis.*/ > + struct ovn_port *l3dgw_port; > + > + /* This is set to the "derived" chassis-redirect port of this port if and > + * only if this port is a distributed gateway port. Otherwise this is set > + * to NULL. */ > + struct ovn_port *cr_port; > + > + bool has_unknown; /* If the addresses have 'unknown' defined. */ > + > + bool has_bfd; > + > + /* The port's peer: > + * > + * - A switch port S of type "router" has a router port R as a peer, > + * and R in turn has S has its peer. > + * > + * - Two connected logical router ports have each other as peer. > + * > + * - Other kinds of ports have no peer. */ > + struct ovn_port *peer; > + > + struct ovn_datapath *od; > + > + struct ovs_list list; /* In list of similar records. */ > + > + struct hmap_node dp_node; /* Node in od->ports. */ > + > + struct lport_addresses proxy_arp_addrs; > + > + /* Temporarily used for traversing a list (or hmap) of ports. */ > + bool visited; > + > + /* List of struct lflow_ref_node that points to the lflows generated by > + * this ovn_port. > + * > + * This data is initialized and destroyed by the en_northd node, but > + * populated and used only by the en_lflow node. Ideally this data should > + * be maintained as part of en_lflow's data (struct lflow_data): a hash > + * index from ovn_port key to lflows. However, it would be less efficient > + * and more complex: > + * > + * 1. It would require an extra search (using the index) to find the > + * lflows. > + * > + * 2. Building the index needs to be thread-safe, using either a global > + * lock which is obviously less efficient, or hash-based lock array which > + * is more complex. > + * > + * Adding the list here is more straightforward. The drawback is that we > + * need to keep in mind that this data belongs to en_lflow node, so never > + * access it from any other nodes. > + */ > + struct ovs_list lflows; > +}; > + > void ovnnb_db_run(struct northd_input *input_data, > struct northd_data *data, > struct ovsdb_idl_txn *ovnnb_txn, > @@ -396,13 +507,27 @@ void sync_lbs(struct ovsdb_idl_txn *, const struct sbrec_load_balancer_table *, > struct chassis_features *chassis_features); > bool check_sb_lb_duplicates(const struct sbrec_load_balancer_table *); > > +struct lr_lb_nat_data_table; > void sync_pbs(struct ovsdb_idl_txn *, struct hmap *ls_ports, > - struct hmap *lr_ports, const struct lr_nat_table *); > -bool sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *, > - const struct lr_nat_table *); > + struct hmap *lr_ports, > + const struct lr_lb_nat_data_table *); > +bool sync_pbs_for_northd_changed_ovn_ports( > + struct tracked_ovn_ports *, > + const struct lr_lb_nat_data_table *); > > bool northd_has_tracked_data(struct northd_tracked_data *); > bool northd_has_only_ports_in_tracked_data(struct northd_tracked_data *); > bool northd_has_lbs_in_tracked_data(struct northd_tracked_data *); > > +/* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the > + * IPs configured on the router port. > + */ > +bool lrouter_port_ipv4_reachable(const struct ovn_port *, ovs_be32 addr); > + > +/* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the > + * IPs configured on the router port. > + */ > +bool lrouter_port_ipv6_reachable(const struct ovn_port *, > + const struct in6_addr *); > + > #endif /* NORTHD_H */ > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > index b7f9cb5689..8fc5cd1d60 100644 > --- a/tests/ovn-northd.at > +++ b/tests/ovn-northd.at > @@ -10416,18 +10416,21 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:10.0.0.3=sw0-p1:10.0.0.2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > check ovn-nbctl --wait=sb set load_balancer . options:foo=bar > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > check ovn-nbctl --wait=sb -- lb-add lb2 20.0.0.10:80 20.0.0.20:80 -- lb-add lb3 30.0.0.10:80 30.0.0.20:80 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10437,6 +10440,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb -- lb-del lb2 -- lb-del lb3 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10450,6 +10454,7 @@ AT_CHECK([ovn-nbctl --wait=sb \ > ]) > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10467,6 +10472,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear Load_Balancer . health_check > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10481,6 +10487,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10489,6 +10496,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > # A LB applied to a switch/router triggers: > # - a recompute in the first iteration (handling northd change) > @@ -10501,6 +10509,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10510,6 +10519,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10519,6 +10529,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10528,6 +10539,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10537,6 +10549,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-del sw0 lb1 > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10547,6 +10560,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 -- lsp-add sw0 sw0p1 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > > @@ -10567,6 +10581,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-lb-add lr0 lb1 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10576,6 +10591,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10585,6 +10601,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10594,6 +10611,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10603,6 +10621,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10632,6 +10651,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb add load_balancer_group . load_Balancer $lb1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10639,6 +10659,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear load_balancer_group . load_Balancer > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10655,6 +10676,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > > @@ -10671,6 +10693,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10680,6 +10703,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10689,6 +10713,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10698,6 +10723,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10713,6 +10739,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl add logical_router lr0 load_balancer_group $lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10722,6 +10749,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10731,6 +10759,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10740,6 +10769,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10749,6 +10779,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10757,6 +10788,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear logical_router lr0 load_balancer_group > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > > @@ -10765,6 +10797,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > > @@ -10773,6 +10806,7 @@ check ovn-nbctl --wait=sb clear logical_switch sw0 load_balancer_group -- \ > destroy load_balancer_group $lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb compute compute > > @@ -10796,6 +10830,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > lbg1_uuid=$(ovn-nbctl --wait=sb create load_balancer_group name=lbg1) > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow norecompute nocompute > check_engine_stats sync_to_sb_lb norecompute nocompute > > @@ -10803,6 +10838,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set load_balancer_group . load_balancer="$lb2_uuid,$lb3_uuid,$lb4_uuid" > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > > @@ -10810,6 +10846,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set logical_switch sw0 load_balancer_group=$lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10818,6 +10855,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set logical_router lr1 load_balancer_group=$lbg1_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10826,6 +10864,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-add sw0 lb2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10834,6 +10873,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-add sw0 lb3 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10843,6 +10883,7 @@ check ovn-nbctl --wait=sb lr-lb-add lr1 lb1 > check ovn-nbctl --wait=sb lr-lb-add lr1 lb2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10851,6 +10892,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb ls-lb-del sw0 lb2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10859,6 +10901,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-lb-del lr1 lb2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10869,6 +10912,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-del lb4 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10879,6 +10923,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lb-del lb2 > check_engine_stats lb_data norecompute compute > check_engine_stats northd norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -10887,6 +10932,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb remove load_balancer_group . load_balancer $lb3_uuid > check_engine_stats lb_data norecompute compute > check_engine_stats northd recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_lb recompute compute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11019,6 +11065,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-add lr0 > check_engine_stats northd recompute nocompute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11031,6 +11078,7 @@ check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 > # for the SB port binding change. > check_engine_stats northd recompute compute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11042,6 +11090,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 > check_engine_stats northd recompute nocompute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11067,6 +11116,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl set logical_router_port lr0-sw0 options:foo=bar > check_engine_stats northd recompute nocompute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11076,8 +11126,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # engine nodes. > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11085,8 +11135,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Update the NAT options column > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set NAT . options:foo=bar > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11094,8 +11144,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Update the NAT external_ip column > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set NAT . external_ip=172.168.0.120 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11103,8 +11154,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Update the NAT logical_ip column > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set NAT . logical_ip=10.0.0.10 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11112,8 +11164,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Update the NAT type > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set NAT . type=snat > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11121,8 +11174,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Create a dnat_and_snat NAT with external_mac and logical_port > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 sw0p1 30:54:00:00:00:03 > -check_engine_stats northd recompute compute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11131,8 +11185,9 @@ nat2_uuid=$(ovn-nbctl --bare --columns _uuid find nat logical_ip=10.0.0.4) > > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb set NAT $nat2_uuid external_mac='"30:54:00:00:00:04"' > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11147,32 +11202,36 @@ check ovn-nbctl lr-lb-add lr0 lb2 > # is a lb vip. > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.140 10.0.0.20 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.150 10.0.0.41 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.150 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.140 > -check_engine_stats northd recompute nocompute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11180,8 +11239,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > # Delete the NAT > check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb clear logical_router lr0 nat > -check_engine_stats northd recompute compute > -check_engine_stats lr_nat recompute nocompute > +check_engine_stats northd norecompute compute > +check_engine_stats lr_nat norecompute compute > +check_engine_stats lr_lb_nat_data norecompute compute > check_engine_stats lflow recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11191,6 +11251,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-policy-add lr0 10 "ip4.src == 10.0.0.3" reroute 172.168.0.101,172.168.0.102 > check_engine_stats northd recompute nocompute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE > @@ -11199,6 +11260,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > check ovn-nbctl --wait=sb lr-policy-del lr0 10 "ip4.src == 10.0.0.3" > check_engine_stats northd recompute nocompute > check_engine_stats lr_nat recompute nocompute > +check_engine_stats lr_lb_nat_data recompute nocompute > check_engine_stats sync_to_sb_pb recompute nocompute > check_engine_stats lflow recompute nocompute > CHECK_NO_CHANGE_AFTER_RECOMPUTE
On 11/23/23 21:45, Dumitru Ceara wrote: > On 10/26/23 20:15, numans@ovn.org wrote: >> From: Numan Siddique <numans@ovn.org> >> >> This new engine now maintains the load balancer and NAT data of a >> logical router which was earlier part of northd engine node data. >> The main inputs to this engine are: >> - northd node >> - lr-nat node >> >> A record for each logical router is maintained in the 'lr_lb_nats' >> hmap table and this record >> - stores the lb related data >> - embeds the 'lr-nat' record. >> >> This engine node becomes an input to 'lflow' node. >> >> Signed-off-by: Numan Siddique <numans@ovn.org> >> --- >> lib/stopwatch-names.h | 1 + >> northd/automake.mk | 2 + >> northd/en-lflow.c | 4 + >> northd/en-lr-lb-nat-data.c | 654 +++++++++++++++++++++++++++++++++++++ >> northd/en-lr-lb-nat-data.h | 93 ++++++ >> northd/en-lr-nat.h | 3 + >> northd/en-sync-sb.c | 50 +-- >> northd/inc-proc-northd.c | 13 +- >> northd/northd.c | 640 ++++++++++++------------------------ >> northd/northd.h | 137 +++++++- >> tests/ovn-northd.at | 110 +++++-- >> 11 files changed, 1212 insertions(+), 495 deletions(-) >> create mode 100644 northd/en-lr-lb-nat-data.c >> create mode 100644 northd/en-lr-lb-nat-data.h >> >> diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h >> index 0a16da211e..7d85acdaea 100644 >> --- a/lib/stopwatch-names.h >> +++ b/lib/stopwatch-names.h >> @@ -33,5 +33,6 @@ >> #define PORT_GROUP_RUN_STOPWATCH_NAME "port_group_run" >> #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" >> #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" >> +#define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" >> >> #endif >> diff --git a/northd/automake.mk b/northd/automake.mk >> index ae367a2a8b..4116c487df 100644 >> --- a/northd/automake.mk >> +++ b/northd/automake.mk >> @@ -26,6 +26,8 @@ northd_ovn_northd_SOURCES = \ >> northd/en-lb-data.h \ >> northd/en-lr-nat.c \ >> northd/en-lr-nat.h \ >> + northd/en-lr-lb-nat-data.c \ >> + northd/en-lr-lb-nat-data.h \ >> northd/inc-proc-northd.c \ >> northd/inc-proc-northd.h \ >> northd/ipam.c \ >> diff --git a/northd/en-lflow.c b/northd/en-lflow.c >> index 22f398d419..9cb0ead3f0 100644 >> --- a/northd/en-lflow.c >> +++ b/northd/en-lflow.c >> @@ -20,6 +20,7 @@ >> >> #include "en-lflow.h" >> #include "en-lr-nat.h" >> +#include "en-lr-lb-nat-data.h" >> #include "en-northd.h" >> #include "en-meters.h" >> >> @@ -43,6 +44,8 @@ lflow_get_input_data(struct engine_node *node, >> engine_get_input_data("sync_meters", node); >> struct ed_type_lr_nat_data *lr_nat_data = >> engine_get_input_data("lr_nat", node); >> + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = >> + engine_get_input_data("lr_lb_nat_data", node); >> >> lflow_input->nbrec_bfd_table = >> EN_OVSDB_GET(engine_get_input("NB_bfd", node)); >> @@ -66,6 +69,7 @@ lflow_get_input_data(struct engine_node *node, >> lflow_input->lr_ports = &northd_data->lr_ports; >> lflow_input->ls_port_groups = &pg_data->ls_port_groups; >> lflow_input->lr_nats = &lr_nat_data->lr_nats; >> + lflow_input->lr_lbnats = &lr_lb_nat_data->lr_lbnats; >> lflow_input->meter_groups = &sync_meters_data->meter_groups; >> lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map; >> lflow_input->svc_monitor_map = &northd_data->svc_monitor_map; >> diff --git a/northd/en-lr-lb-nat-data.c b/northd/en-lr-lb-nat-data.c >> new file mode 100644 >> index 0000000000..19b638ce0b >> --- /dev/null >> +++ b/northd/en-lr-lb-nat-data.c >> @@ -0,0 +1,654 @@ >> +/* >> + * Copyright (c) 2023, Red Hat, Inc. >> + * >> + * Licensed under the Apache License, Version 2.0 (the "License"); >> + * you may not use this file except in compliance with the License. >> + * You may obtain a copy of the License at: >> + * >> + * http://www.apache.org/licenses/LICENSE-2.0 >> + * >> + * Unless required by applicable law or agreed to in writing, software >> + * distributed under the License is distributed on an "AS IS" BASIS, >> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >> + * See the License for the specific language governing permissions and >> + * limitations under the License. >> + */ >> + >> +#include <config.h> >> + >> +#include <getopt.h> >> +#include <stdlib.h> >> +#include <stdio.h> >> + >> +/* OVS includes */ >> +#include "include/openvswitch/hmap.h" >> +#include "lib/bitmap.h" >> +#include "lib/socket-util.h" >> +#include "lib/uuidset.h" >> +#include "openvswitch/util.h" >> +#include "openvswitch/vlog.h" >> +#include "stopwatch.h" >> + >> +/* OVN includes */ >> +#include "en-lb-data.h" >> +#include "en-lr-lb-nat-data.h" >> +#include "en-lr-nat.h" >> +#include "lib/inc-proc-eng.h" >> +#include "lib/lb.h" >> +#include "lib/ovn-nb-idl.h" >> +#include "lib/ovn-sb-idl.h" >> +#include "lib/ovn-util.h" >> +#include "lib/stopwatch-names.h" >> +#include "northd.h" >> + >> +VLOG_DEFINE_THIS_MODULE(en_lr_lb_nat_data); >> + >> +/* Static function declarations. */ >> +static void lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *); >> +static void lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *); >> +static void lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *); >> +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_( >> + const struct lr_lb_nat_data_table *, const struct nbrec_logical_router *); >> +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index_( >> + const struct lr_lb_nat_data_table *table, size_t od_index); >> + >> +static void lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *, >> + const struct lr_nat_table *, >> + const struct ovn_datapaths *lr_datapaths, >> + const struct hmap *lb_datapaths_map, >> + const struct hmap *lbgrp_datapaths_map); >> + >> +static struct lr_lb_nat_data_input lr_lb_nat_data_get_input_data( >> + struct engine_node *); >> + >> +static struct lr_lb_nat_data_record *lr_lb_nat_data_record_create( >> + struct lr_lb_nat_data_table *, const struct lr_nat_record *, >> + const struct hmap *lb_datapaths_map, >> + const struct hmap *lbgrp_datapaths_map); >> +static void lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *); >> +static void lr_lb_nat_data_record_init( >> + struct lr_lb_nat_data_record *, >> + const struct hmap *lb_datapaths_map, >> + const struct hmap *lbgrp_datapaths_map); >> + >> +static void build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, >> + const struct ovn_northd_lb *); >> +static void add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *, >> + enum lb_neighbor_responder_mode, >> + const struct sset *lb_ips_v4, >> + const struct sset *lb_ips_v6); >> +static void remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, >> + enum lb_neighbor_responder_mode, >> + const struct sset *lb_ips_v4, >> + const struct sset *lb_ips_v6); >> +static void lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *); >> + >> +/* 'lr_lb_nat_data' engine node manages the NB logical router LB data. >> + */ >> +void * >> +en_lr_lb_nat_data_init(struct engine_node *node OVS_UNUSED, >> + struct engine_arg *arg OVS_UNUSED) >> +{ >> + struct ed_type_lr_lb_nat_data *data = xzalloc(sizeof *data); >> + lr_lb_nat_data_table_init(&data->lr_lbnats); >> + hmapx_init(&data->tracked_data.crupdated); >> + hmapx_init(&data->tracked_data.deleted); >> + return data; >> +} >> + >> +void >> +en_lr_lb_nat_data_cleanup(void *data_) >> +{ >> + struct ed_type_lr_lb_nat_data *data = >> + (struct ed_type_lr_lb_nat_data *) data_; >> + lr_lb_nat_data_table_destroy(&data->lr_lbnats); >> + hmapx_destroy(&data->tracked_data.crupdated); >> + hmapx_destroy(&data->tracked_data.deleted); >> +} >> + >> +void >> +en_lr_lb_nat_data_clear_tracked_data(void *data_) >> +{ >> + struct ed_type_lr_lb_nat_data *data = >> + (struct ed_type_lr_lb_nat_data *) data_; >> + >> + struct hmapx_node *hmapx_node; >> + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { >> + lr_lb_nat_data_record_destroy(hmapx_node->data); >> + hmapx_delete(&data->tracked_data.deleted, hmapx_node); >> + } >> + >> + hmapx_clear(&data->tracked_data.crupdated); >> + data->tracked = false; >> +} >> + >> +void >> +en_lr_lb_nat_data_run(struct engine_node *node, void *data_) >> +{ >> + struct lr_lb_nat_data_input input_data = >> + lr_lb_nat_data_get_input_data(node); >> + struct ed_type_lr_lb_nat_data *data = data_; >> + >> + stopwatch_start(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); >> + >> + lr_lb_nat_data_table_clear(&data->lr_lbnats); >> + lr_lb_nat_data_table_build(&data->lr_lbnats, input_data.lr_nats, >> + input_data.lr_datapaths, >> + input_data.lb_datapaths_map, >> + input_data.lbgrp_datapaths_map); >> + >> + stopwatch_stop(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); >> + engine_set_node_state(node, EN_UPDATED); >> +} >> + >> +bool >> +lr_lb_nat_data_northd_handler(struct engine_node *node, void *data OVS_UNUSED) >> +{ >> + struct northd_data *northd_data = engine_get_input_data("northd", node); >> + if (!northd_data->change_tracked) { >> + return false; >> + } >> + >> + return true; >> +} >> + >> +bool >> +lr_lb_nat_data_lb_data_handler(struct engine_node *node, void *data_) >> +{ >> + struct ed_type_lb_data *lb_data = engine_get_input_data("lb_data", node); >> + if (!lb_data->tracked) { >> + return false; >> + } >> + >> + struct ed_type_lr_lb_nat_data *data = >> + (struct ed_type_lr_lb_nat_data *) data_; >> + struct lr_lb_nat_data_input input_data = >> + lr_lb_nat_data_get_input_data(node); >> + struct lr_lb_nat_data_record *lr_lbnat_rec; >> + size_t index; >> + >> + const struct tracked_lb_data *trk_lb_data = &lb_data->tracked_lb_data; >> + const struct ovn_lb_group_datapaths *lbgrp_dps; >> + const struct crupdated_lbgrp *crupdated_lbgrp; >> + const struct crupdated_od_lb_data *codlb; >> + const struct ovn_lb_datapaths *lb_dps; >> + const struct crupdated_lb *clb; >> + const struct ovn_northd_lb *lb; >> + const struct ovn_datapath *od; >> + >> + LIST_FOR_EACH (codlb, list_node, &trk_lb_data->crupdated_lr_lbs) { >> + od = ovn_datapath_find(&input_data.lr_datapaths->datapaths, >> + &codlb->od_uuid); >> + ovs_assert(od); >> + >> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, od->nbr); >> + if (!lr_lbnat_rec) { >> + const struct lr_nat_record *lrnat_rec = lr_nat_table_find_by_index( >> + input_data.lr_nats, od->index); >> + ovs_assert(lrnat_rec); >> + >> + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, >> + lrnat_rec, >> + input_data.lb_datapaths_map, >> + input_data.lbgrp_datapaths_map); >> + >> + /* Add the lr_lbnat_rec rec to the tracking data. */ >> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); >> + continue; >> + } >> + >> + struct uuidset_node *uuidnode; >> + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbs) { >> + lb_dps = ovn_lb_datapaths_find( >> + input_data.lb_datapaths_map, &uuidnode->uuid); >> + ovs_assert(lb_dps); >> + >> + /* Add the lb_ips of lb_dps to the od. */ >> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); >> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); >> + } >> + >> + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbgrps) { >> + lbgrp_dps = ovn_lb_group_datapaths_find( >> + input_data.lbgrp_datapaths_map, &uuidnode->uuid); >> + ovs_assert(lbgrp_dps); >> + >> + for (size_t j = 0; j < lbgrp_dps->lb_group->n_lbs; j++) { >> + const struct uuid *lb_uuid >> + = &lbgrp_dps->lb_group->lbs[j]->nlb->header_.uuid; >> + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, >> + lb_uuid); >> + ovs_assert(lb_dps); >> + >> + /* Add the lb_ips of lb_dps to the od. */ >> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); >> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); >> + } >> + } >> + >> + /* Add the lr_lbnat_rec rec to the tracking data. */ >> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); >> + } >> + >> + HMAP_FOR_EACH (clb, hmap_node, &trk_lb_data->crupdated_lbs) { >> + lb = clb->lb; >> + const struct uuid *lb_uuid = &lb->nlb->header_.uuid; >> + >> + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, lb_uuid); >> + ovs_assert(lb_dps); >> + >> + BITMAP_FOR_EACH_1 (index, ods_size(input_data.lr_datapaths), >> + lb_dps->nb_lr_map) { >> + od = input_data.lr_datapaths->array[index]; >> + >> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, >> + od->nbr); >> + ovs_assert(lr_lbnat_rec); >> + >> + /* Update the od->lb_ips with the deleted and inserted >> + * vips (if any). */ >> + remove_ips_from_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, >> + &clb->deleted_vips_v4, >> + &clb->deleted_vips_v6); >> + add_ips_to_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, >> + &clb->inserted_vips_v4, >> + &clb->inserted_vips_v6); >> + >> + remove_lrouter_lb_reachable_ips(lr_lbnat_rec, lb->neigh_mode, >> + &clb->deleted_vips_v4, >> + &clb->deleted_vips_v6); >> + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, >> + &clb->inserted_vips_v4, >> + &clb->inserted_vips_v6); >> + >> + /* Add the lr_lbnat_rec rec to the tracking data. */ >> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); >> + } >> + } >> + >> + HMAP_FOR_EACH (crupdated_lbgrp, hmap_node, >> + &trk_lb_data->crupdated_lbgrps) { >> + const struct uuid *lb_uuid = &crupdated_lbgrp->lbgrp->uuid; >> + >> + lbgrp_dps = ovn_lb_group_datapaths_find(input_data.lbgrp_datapaths_map, >> + lb_uuid); >> + ovs_assert(lbgrp_dps); >> + >> + struct hmapx_node *hnode; >> + HMAPX_FOR_EACH (hnode, &crupdated_lbgrp->assoc_lbs) { >> + lb = hnode->data; >> + lb_uuid = &lb->nlb->header_.uuid; >> + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, >> + lb_uuid); >> + ovs_assert(lb_dps); >> + for (size_t i = 0; i < lbgrp_dps->n_lr; i++) { >> + od = lbgrp_dps->lr[i]; >> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, >> + od->nbr); >> + ovs_assert(lr_lbnat_rec); >> + /* Add the lb_ips of lb_dps to the lr lb data. */ >> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); >> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); >> + >> + /* Add the lr_lbnat_rec rec to the tracking data. */ >> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); >> + } >> + } >> + } >> + >> + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { >> + struct hmapx_node *hmapx_node; >> + /* For all the modified lr_lb_nat_data records (re)build the >> + * vip nats. */ >> + HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { >> + lr_lb_nat_data_build_vip_nats(hmapx_node->data); >> + } >> + >> + data->tracked = true; >> + engine_set_node_state(node, EN_UPDATED); >> + } >> + >> + return true; >> +} >> + >> +bool >> +lr_lb_nat_data_lr_nat_handler(struct engine_node *node, void *data_) >> +{ >> + struct ed_type_lr_nat_data *lr_nat_data = >> + engine_get_input_data("lr_nat", node); >> + >> + if (!lr_nat_data->tracked >> + || !hmapx_is_empty(&lr_nat_data->tracked_data.deleted)) { >> + return false; >> + } >> + >> + struct ed_type_lr_lb_nat_data *data = >> + (struct ed_type_lr_lb_nat_data *) data_; >> + struct lr_lb_nat_data_input input_data = >> + lr_lb_nat_data_get_input_data(node); >> + const struct lr_nat_record *lrnat_rec; >> + struct lr_lb_nat_data_record *lr_lbnat_rec; >> + struct hmapx_node *hmapx_node; >> + >> + HMAPX_FOR_EACH (hmapx_node, &lr_nat_data->tracked_data.crupdated) { >> + lrnat_rec = hmapx_node->data; >> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, >> + lrnat_rec->od->nbr); >> + if (!lr_lbnat_rec) { >> + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, >> + lrnat_rec, >> + input_data.lb_datapaths_map, >> + input_data.lbgrp_datapaths_map); >> + } else { >> + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); >> + } >> + >> + /* Add the lr_lbnat_rec rec to the tracking data. */ >> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); >> + } >> + >> + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { >> + data->tracked = true; >> + engine_set_node_state(node, EN_UPDATED); >> + } >> + >> + return true; >> +} >> + >> +const struct lr_lb_nat_data_record * >> +lr_lb_nat_data_table_find_by_index(const struct lr_lb_nat_data_table *table, >> + size_t od_index) >> +{ >> + return lr_lb_nat_data_table_find_by_index_(table, od_index); >> +} >> + >> +/* static functions. */ >> +static void >> +lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *table) >> +{ >> + *table = (struct lr_lb_nat_data_table) { >> + .entries = HMAP_INITIALIZER(&table->entries), >> + }; >> +} >> + >> +static void >> +lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *table) >> +{ >> + lr_lb_nat_data_table_clear(table); >> + hmap_destroy(&table->entries); >> +} >> + >> +static void >> +lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *table) >> +{ >> + struct lr_lb_nat_data_record *lr_lbnat_rec; >> + HMAP_FOR_EACH_POP (lr_lbnat_rec, key_node, &table->entries) { >> + lr_lb_nat_data_record_destroy(lr_lbnat_rec); >> + } >> + >> + free(table->array); >> + table->array = NULL; >> +} >> + >> +static void >> +lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *table, >> + const struct lr_nat_table *lr_nats, >> + const struct ovn_datapaths *lr_datapaths, >> + const struct hmap *lb_datapaths_map, >> + const struct hmap *lbgrp_datapaths_map) >> +{ >> + table->array = xrealloc(table->array, >> + ods_size(lr_datapaths) * sizeof *table->array); >> + const struct lr_nat_record *lrnat_rec; >> + LR_NAT_TABLE_FOR_EACH (lrnat_rec, lr_nats) { >> + lr_lb_nat_data_record_create(table, lrnat_rec, lb_datapaths_map, >> + lbgrp_datapaths_map); >> + } >> +} >> + >> +static struct lr_lb_nat_data_record * >> +lr_lb_nat_data_table_find_(const struct lr_lb_nat_data_table *table, >> + const struct nbrec_logical_router *nbr) >> +{ >> + struct lr_lb_nat_data_record *lr_lbnat_rec; >> + >> + HMAP_FOR_EACH_WITH_HASH (lr_lbnat_rec, key_node, >> + uuid_hash(&nbr->header_.uuid), &table->entries) { >> + if (nbr == lr_lbnat_rec->od->nbr) { >> + return lr_lbnat_rec; >> + } >> + } >> + return NULL; >> +} >> + >> +static struct lr_lb_nat_data_record * >> +lr_lb_nat_data_table_find_by_index_(const struct lr_lb_nat_data_table *table, >> + size_t od_index) >> +{ >> + ovs_assert(od_index <= hmap_count(&table->entries)); >> + return table->array[od_index]; >> +} >> + >> +static struct lr_lb_nat_data_record * >> +lr_lb_nat_data_record_create(struct lr_lb_nat_data_table *table, >> + const struct lr_nat_record *lrnat_rec, >> + const struct hmap *lb_datapaths_map, >> + const struct hmap *lbgrp_datapaths_map) >> +{ >> + struct lr_lb_nat_data_record *lr_lbnat_rec = xzalloc(sizeof *lr_lbnat_rec); >> + lr_lbnat_rec->lrnat_rec = lrnat_rec; >> + lr_lbnat_rec->od = lrnat_rec->od; >> + lr_lb_nat_data_record_init(lr_lbnat_rec, lb_datapaths_map, >> + lbgrp_datapaths_map); >> + >> + hmap_insert(&table->entries, &lr_lbnat_rec->key_node, >> + uuid_hash(&lr_lbnat_rec->od->nbr->header_.uuid)); >> + >> + table->array[lr_lbnat_rec->od->index] = lr_lbnat_rec; >> + return lr_lbnat_rec; >> +} >> + >> +static void >> +lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *lr_lbnat_rec) >> +{ >> + ovn_lb_ip_set_destroy(lr_lbnat_rec->lb_ips); >> + lr_lbnat_rec->lb_ips = NULL; >> + sset_destroy(&lr_lbnat_rec->vip_nats); >> + free(lr_lbnat_rec); >> +} >> + >> +static void >> +lr_lb_nat_data_record_init(struct lr_lb_nat_data_record *lr_lbnat_rec, >> + const struct hmap *lb_datapaths_map, >> + const struct hmap *lbgrp_datapaths_map) >> +{ >> + const struct nbrec_load_balancer_group *nbrec_lb_group; >> + const struct ovn_lb_group_datapaths *lb_group_dps; >> + const struct ovn_lb_datapaths *lb_dps; >> + >> + /* Checking load balancer groups first, starting from the largest one, >> + * to more efficiently copy IP sets. */ >> + size_t largest_group = 0; >> + >> + const struct nbrec_logical_router *nbr = lr_lbnat_rec->od->nbr; >> + for (size_t i = 1; i < nbr->n_load_balancer_group; i++) { >> + if (nbr->load_balancer_group[i]->n_load_balancer > >> + nbr->load_balancer_group[largest_group]->n_load_balancer) { >> + largest_group = i; >> + } >> + } >> + >> + for (size_t i = 0; i < nbr->n_load_balancer_group; i++) { >> + size_t idx = (i + largest_group) % nbr->n_load_balancer_group; >> + >> + nbrec_lb_group = nbr->load_balancer_group[idx]; >> + const struct uuid *lbgrp_uuid = &nbrec_lb_group->header_.uuid; >> + >> + lb_group_dps = >> + ovn_lb_group_datapaths_find(lbgrp_datapaths_map, >> + lbgrp_uuid); >> + ovs_assert(lb_group_dps); >> + >> + if (!lr_lbnat_rec->lb_ips) { >> + lr_lbnat_rec->lb_ips = >> + ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); >> + } else { >> + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { >> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, >> + lb_group_dps->lb_group->lbs[j]); >> + } >> + } >> + >> + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { >> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, >> + lb_group_dps->lb_group->lbs[j]); >> + } >> + } >> + >> + if (!lr_lbnat_rec->lb_ips) { >> + lr_lbnat_rec->lb_ips = ovn_lb_ip_set_create(); >> + } >> + >> + for (size_t i = 0; i < nbr->n_load_balancer; i++) { >> + const struct uuid *lb_uuid = >> + &nbr->load_balancer[i]->header_.uuid; >> + lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); >> + ovs_assert(lb_dps); >> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); >> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); >> + } >> + >> + sset_init(&lr_lbnat_rec->vip_nats); >> + >> + if (!nbr->n_nat) { >> + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); >> + } >> +} >> + >> +static struct lr_lb_nat_data_input >> +lr_lb_nat_data_get_input_data(struct engine_node *node) >> +{ >> + struct northd_data *northd_data = engine_get_input_data("northd", node); >> + struct ed_type_lr_nat_data *lr_nat_data = >> + engine_get_input_data("lr_nat", node); >> + >> + return (struct lr_lb_nat_data_input) { >> + .lr_datapaths = &northd_data->lr_datapaths, >> + .lb_datapaths_map = &northd_data->lb_datapaths_map, >> + .lbgrp_datapaths_map = &northd_data->lb_group_datapaths_map, >> + .lr_nats = &lr_nat_data->lr_nats, >> + }; >> +} >> + >> +static void >> +build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, >> + const struct ovn_northd_lb *lb) >> +{ >> + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, &lb->ips_v4, >> + &lb->ips_v6); >> +} >> + >> +static void >> +add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *lr_lbnat_rec, >> + enum lb_neighbor_responder_mode neigh_mode, >> + const struct sset *lb_ips_v4, >> + const struct sset *lb_ips_v6) >> +{ >> + /* If configured to not reply to any neighbor requests for all VIPs >> + * return early. >> + */ >> + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { >> + return; >> + } >> + >> + const char *ip_address; >> + >> + /* If configured to reply to neighbor requests for all VIPs force them >> + * all to be considered "reachable". >> + */ >> + if (neigh_mode == LB_NEIGH_RESPOND_ALL) { >> + SSET_FOR_EACH (ip_address, lb_ips_v4) { >> + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, ip_address); >> + } >> + SSET_FOR_EACH (ip_address, lb_ips_v6) { >> + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, ip_address); >> + } >> + >> + return; >> + } >> + >> + /* Otherwise, a VIP is reachable if there's at least one router >> + * subnet that includes it. >> + */ >> + ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); >> + >> + SSET_FOR_EACH (ip_address, lb_ips_v4) { >> + struct ovn_port *op; >> + ovs_be32 vip_ip4; >> + if (ip_parse(ip_address, &vip_ip4)) { >> + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { >> + if (lrouter_port_ipv4_reachable(op, vip_ip4)) { >> + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, >> + ip_address); >> + break; >> + } >> + } >> + } >> + } >> + >> + SSET_FOR_EACH (ip_address, lb_ips_v6) { >> + struct ovn_port *op; >> + struct in6_addr vip; >> + if (ipv6_parse(ip_address, &vip)) { >> + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { >> + if (lrouter_port_ipv6_reachable(op, &vip)) { >> + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, >> + ip_address); >> + break; >> + } >> + } >> + } >> + } >> +} >> + >> +static void >> +remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, >> + enum lb_neighbor_responder_mode neigh_mode, >> + const struct sset *lb_ips_v4, >> + const struct sset *lb_ips_v6) >> +{ >> + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { >> + return; >> + } >> + >> + const char *ip_address; >> + SSET_FOR_EACH (ip_address, lb_ips_v4) { >> + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v4_reachable, >> + ip_address); >> + } >> + SSET_FOR_EACH (ip_address, lb_ips_v6) { >> + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v6_reachable, >> + ip_address); >> + } >> +} >> + >> +static void >> +lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *lr_lbnat_rec) >> +{ >> + sset_clear(&lr_lbnat_rec->vip_nats); >> + const char *external_ip; >> + SSET_FOR_EACH (external_ip, &lr_lbnat_rec->lrnat_rec->external_ips) { >> + bool is_vip_nat = false; >> + if (addr_is_ipv6(external_ip)) { >> + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, >> + external_ip); >> + } else { >> + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, >> + external_ip); >> + } >> + >> + if (is_vip_nat) { >> + sset_add(&lr_lbnat_rec->vip_nats, external_ip); >> + } >> + } >> +} >> diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h >> new file mode 100644 >> index 0000000000..9029aee339 >> --- /dev/null >> +++ b/northd/en-lr-lb-nat-data.h >> @@ -0,0 +1,93 @@ >> +/* >> + * Copyright (c) 2023, Red Hat, Inc. >> + * >> + * Licensed under the Apache License, Version 2.0 (the "License"); >> + * you may not use this file except in compliance with the License. >> + * You may obtain a copy of the License at: >> + * >> + * http://www.apache.org/licenses/LICENSE-2.0 >> + * >> + * Unless required by applicable law or agreed to in writing, software >> + * distributed under the License is distributed on an "AS IS" BASIS, >> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >> + * See the License for the specific language governing permissions and >> + * limitations under the License. >> + */ >> +#ifndef EN_LR_LB_NAT_DATA_H >> +#define EN_LR_LB_NAT_DATA_H 1 >> + >> +#include <stdint.h> >> + >> +/* OVS includes. */ >> +#include "lib/hmapx.h" >> +#include "openvswitch/hmap.h" >> +#include "sset.h" >> + >> +/* OVN includes. */ >> +#include "lib/inc-proc-eng.h" >> +#include "lib/lb.h" >> +#include "lib/ovn-nb-idl.h" >> +#include "lib/ovn-sb-idl.h" >> +#include "lib/ovn-util.h" >> + >> +struct ovn_datapath; >> +struct lr_nat_record; >> + >> +struct lr_lb_nat_data_record { >> + struct hmap_node key_node; /* Index on 'nbr->header_.uuid'. */ >> + >> + const struct ovn_datapath *od; >> + const struct lr_nat_record *lrnat_rec; >> + >> + /* Load Balancer vIPs relevant for this datapath. */ >> + struct ovn_lb_ip_set *lb_ips; >> + >> + /* sset of vips which are also part of lr nats. */ >> + struct sset vip_nats; >> +}; >> + >> +struct lr_lb_nat_data_table { >> + struct hmap entries; >> + >> + /* The array index of each element in 'entries'. */ >> + struct lr_lb_nat_data_record **array; >> +}; >> + >> +#define LR_LB_NAT_DATA_TABLE_FOR_EACH(LR_LB_NAT_REC, TABLE) \ >> + HMAP_FOR_EACH (LR_LB_NAT_REC, key_node, &(TABLE)->entries) >> + >> +struct lr_lb_nat_data_tracked_data { >> + /* Created or updated logical router with LB data. */ >> + struct hmapx crupdated; /* Stores 'struct lr_lb_nat_data_record'. */ >> + >> + /* Deleted logical router with LB data. */ >> + struct hmapx deleted; /* Stores 'struct lr_lb_nat_data_record'. */ >> +}; >> + >> +struct ed_type_lr_lb_nat_data { >> + struct lr_lb_nat_data_table lr_lbnats; >> + >> + bool tracked; >> + struct lr_lb_nat_data_tracked_data tracked_data; > > Same comment about 'tracked' as in the previous commit, we can probably > remove it. > > Which brings me to the following question, we don't really use > lr_lb_nat_data_tracked_data->deleted anywhere; we never add anything to > it. Is it on purpose, should we just delete it? Or is it a bug? > > Thanks, > Dumitru > >> +}; >> + >> +struct lr_lb_nat_data_input { >> + const struct ovn_datapaths *lr_datapaths; >> + const struct hmap *lb_datapaths_map; >> + const struct hmap *lbgrp_datapaths_map; >> + const struct lr_nat_table *lr_nats; >> +}; >> + >> +void *en_lr_lb_nat_data_init(struct engine_node *, struct engine_arg *); >> +void en_lr_lb_nat_data_cleanup(void *data); >> +void en_lr_lb_nat_data_clear_tracked_data(void *data); >> +void en_lr_lb_nat_data_run(struct engine_node *, void *data); >> + >> +bool lr_lb_nat_data_northd_handler(struct engine_node *, void *data); >> +bool lr_lb_nat_data_lr_nat_handler(struct engine_node *, void *data); >> +bool lr_lb_nat_data_lb_data_handler(struct engine_node *, void *data); >> + >> +const struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index( >> + const struct lr_lb_nat_data_table *, size_t od_index); >> + >> +#endif /* EN_LR_LB_NAT_DATA_H */ >> \ No newline at end of file No newline at end of file. >> diff --git a/northd/en-lr-nat.h b/northd/en-lr-nat.h >> index 01a16a21aa..2e3f285d12 100644 >> --- a/northd/en-lr-nat.h >> +++ b/northd/en-lr-nat.h >> @@ -89,6 +89,9 @@ struct lr_nat_table { >> const struct lr_nat_record * lr_nat_table_find_by_index( >> const struct lr_nat_table *, size_t od_index); >> >> +#define LR_NAT_TABLE_FOR_EACH(LR_NAT_REC, TABLE) \ >> + HMAP_FOR_EACH (LR_NAT_REC, key_node, &(TABLE)->entries) >> + >> /* Incremental processing implementation. */ >> struct lr_nat_input { >> /* Northbound table references. */ >> diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c >> index 10ade620e7..7c22949f74 100644 >> --- a/northd/en-sync-sb.c >> +++ b/northd/en-sync-sb.c >> @@ -22,6 +22,7 @@ >> #include "openvswitch/util.h" >> >> #include "en-lr-nat.h" >> +#include "en-lr-lb-nat-data.h" >> #include "en-sync-sb.h" >> #include "lib/inc-proc-eng.h" >> #include "lib/lb.h" >> @@ -41,7 +42,7 @@ static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, >> const struct nbrec_address_set_table *, >> const struct nbrec_port_group_table *, >> const struct sbrec_address_set_table *, >> - const struct ovn_datapaths *lr_datapaths); >> + const struct lr_lb_nat_data_table *); >> static const struct sbrec_address_set *sb_address_set_lookup_by_name( >> struct ovsdb_idl_index *, const char *name); >> static void update_sb_addr_set(struct sorted_array *, >> @@ -87,11 +88,11 @@ en_sync_to_sb_addr_set_run(struct engine_node *node, void *data OVS_UNUSED) >> EN_OVSDB_GET(engine_get_input("SB_address_set", node)); >> >> const struct engine_context *eng_ctx = engine_get_context(); >> - struct northd_data *northd_data = engine_get_input_data("northd", node); >> - >> + const struct ed_type_lr_lb_nat_data *lr_lb_nat_data = >> + engine_get_input_data("lr_lb_nat_data", node); >> sync_addr_sets(eng_ctx->ovnsb_idl_txn, nb_address_set_table, >> nb_port_group_table, sb_address_set_table, >> - &northd_data->lr_datapaths); >> + &lr_lb_nat_data->lr_lbnats); >> >> engine_set_node_state(node, EN_UPDATED); >> } >> @@ -288,10 +289,12 @@ en_sync_to_sb_pb_run(struct engine_node *node, void *data OVS_UNUSED) >> { >> const struct engine_context *eng_ctx = engine_get_context(); >> struct northd_data *northd_data = engine_get_input_data("northd", node); >> - struct ed_type_lr_nat_data *lr_nat_data = >> - engine_get_input_data("lr_nat", node); >> + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = >> + engine_get_input_data("lr_lb_nat_data", node); >> + >> sync_pbs(eng_ctx->ovnsb_idl_txn, &northd_data->ls_ports, >> - &northd_data->lr_ports, &lr_nat_data->lr_nats); >> + &northd_data->lr_ports, >> + &lr_lb_nat_data->lr_lbnats); >> engine_set_node_state(node, EN_UPDATED); >> } >> >> @@ -316,11 +319,12 @@ sync_to_sb_pb_northd_handler(struct engine_node *node, void *data OVS_UNUSED) >> return false; >> } >> >> - struct ed_type_lr_nat_data *lr_nat_data = >> - engine_get_input_data("lr_nat", node); >> + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = >> + engine_get_input_data("lr_lb_nat_data", node); >> >> if (!sync_pbs_for_northd_changed_ovn_ports( >> - &nd->trk_northd_changes.trk_ovn_ports, &lr_nat_data->lr_nats)) { >> + &nd->trk_northd_changes.trk_ovn_ports, >> + &lr_lb_nat_data->lr_lbnats)) { >> return false; >> } >> >> @@ -366,7 +370,7 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, >> const struct nbrec_address_set_table *nb_address_set_table, >> const struct nbrec_port_group_table *nb_port_group_table, >> const struct sbrec_address_set_table *sb_address_set_table, >> - const struct ovn_datapaths *lr_datapaths) >> + const struct lr_lb_nat_data_table *lr_lbnats) >> { >> struct shash sb_address_sets = SHASH_INITIALIZER(&sb_address_sets); >> >> @@ -410,16 +414,14 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, >> } >> >> /* Sync router load balancer VIP generated address sets. */ >> - struct ovn_datapath *od; >> - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { >> - ovs_assert(od->nbr); >> - >> - if (sset_count(&od->lb_ips->ips_v4_reachable)) { >> - char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key, >> - AF_INET); >> + const struct lr_lb_nat_data_record *lrlb_rec; >> + LR_LB_NAT_DATA_TABLE_FOR_EACH (lrlb_rec, lr_lbnats) { >> + if (sset_count(&lrlb_rec->lb_ips->ips_v4_reachable)) { >> + char *ipv4_addrs_name = >> + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET); >> >> struct sorted_array ipv4_addrs_sorted = >> - sorted_array_from_sset(&od->lb_ips->ips_v4_reachable); >> + sorted_array_from_sset(&lrlb_rec->lb_ips->ips_v4_reachable); >> >> sync_addr_set(ovnsb_txn, ipv4_addrs_name, >> &ipv4_addrs_sorted, &sb_address_sets); >> @@ -427,11 +429,11 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, >> free(ipv4_addrs_name); >> } >> >> - if (sset_count(&od->lb_ips->ips_v6_reachable)) { >> - char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key, >> - AF_INET6); >> - struct sorted_array ipv6_addrs_sorted = >> - sorted_array_from_sset(&od->lb_ips->ips_v6_reachable); >> + if (sset_count(&lrlb_rec->lb_ips->ips_v6_reachable)) { >> + char *ipv6_addrs_name = >> + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET6); >> + struct sorted_array ipv6_addrs_sorted = sorted_array_from_sset( >> + &lrlb_rec->lb_ips->ips_v6_reachable); >> >> sync_addr_set(ovnsb_txn, ipv6_addrs_name, >> &ipv6_addrs_sorted, &sb_address_sets); >> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c >> index 2bd66b8808..369a151fa3 100644 >> --- a/northd/inc-proc-northd.c >> +++ b/northd/inc-proc-northd.c >> @@ -31,6 +31,7 @@ >> #include "openvswitch/vlog.h" >> #include "inc-proc-northd.h" >> #include "en-lb-data.h" >> +#include "en-lr-lb-nat-data.h" >> #include "en-lr-nat.h" >> #include "en-northd.h" >> #include "en-lflow.h" >> @@ -148,6 +149,7 @@ static ENGINE_NODE(sync_to_sb_lb, "sync_to_sb_lb"); >> static ENGINE_NODE(sync_to_sb_pb, "sync_to_sb_pb"); >> static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data"); >> static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_nat, "lr_nat"); >> +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_lb_nat_data, "lr_lb_nat_data"); >> >> void inc_proc_northd_init(struct ovsdb_idl_loop *nb, >> struct ovsdb_idl_loop *sb) >> @@ -196,6 +198,13 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, >> engine_add_input(&en_lr_nat, &en_nb_logical_router, >> lr_nat_logical_router_handler); >> >> + engine_add_input(&en_lr_lb_nat_data, &en_northd, >> + lr_lb_nat_data_northd_handler); >> + engine_add_input(&en_lr_lb_nat_data, &en_lr_nat, >> + lr_lb_nat_data_lr_nat_handler); >> + engine_add_input(&en_lr_lb_nat_data, &en_lb_data, >> + lr_lb_nat_data_lb_data_handler); >> + >> engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL); >> engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL); >> engine_add_input(&en_mac_binding_aging, &en_northd, NULL); >> @@ -220,12 +229,14 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, >> engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); >> engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); >> engine_add_input(&en_lflow, &en_lr_nat, NULL); >> + engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); >> >> engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, >> sync_to_sb_addr_set_nb_address_set_handler); >> engine_add_input(&en_sync_to_sb_addr_set, &en_nb_port_group, >> sync_to_sb_addr_set_nb_port_group_handler); >> engine_add_input(&en_sync_to_sb_addr_set, &en_northd, NULL); >> + engine_add_input(&en_sync_to_sb_addr_set, &en_lr_lb_nat_data, NULL); >> engine_add_input(&en_sync_to_sb_addr_set, &en_sb_address_set, NULL); >> >> engine_add_input(&en_port_group, &en_nb_port_group, >> @@ -243,7 +254,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, >> >> engine_add_input(&en_sync_to_sb_pb, &en_northd, >> sync_to_sb_pb_northd_handler); >> - engine_add_input(&en_sync_to_sb_pb, &en_lr_nat, NULL); >> + engine_add_input(&en_sync_to_sb_pb, &en_lr_lb_nat_data, NULL); >> >> /* en_sync_to_sb engine node syncs the SB database tables from >> * the NB database tables. >> diff --git a/northd/northd.c b/northd/northd.c >> index 44c9c3d729..24df14c0de 100644 >> --- a/northd/northd.c >> +++ b/northd/northd.c >> @@ -44,6 +44,7 @@ >> #include "northd.h" >> #include "en-lb-data.h" >> #include "en-lr-nat.h" >> +#include "en-lr-lb-nat-data.h" >> #include "lib/ovn-parallel-hmap.h" >> #include "ovn/actions.h" >> #include "ovn/features.h" >> @@ -617,13 +618,6 @@ init_lb_for_datapath(struct ovn_datapath *od) >> } >> } >> >> -static void >> -destroy_lb_for_datapath(struct ovn_datapath *od) >> -{ >> - ovn_lb_ip_set_destroy(od->lb_ips); >> - od->lb_ips = NULL; >> -} >> - >> /* A group of logical router datapaths which are connected - either >> * directly or indirectly. >> * Each logical router can belong to only one group. */ >> @@ -676,7 +670,6 @@ ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od) >> destroy_ipam_info(&od->ipam_info); >> free(od->router_ports); >> free(od->ls_peers); >> - destroy_lb_for_datapath(od); >> free(od->localnet_ports); >> free(od->l3dgw_ports); >> destroy_mcast_info_for_datapath(od); >> @@ -1311,121 +1304,6 @@ struct lflow_ref_node { >> struct ovn_lflow *lflow; >> }; >> >> -/* A logical switch port or logical router port. >> - * >> - * In steady state, an ovn_port points to a northbound Logical_Switch_Port >> - * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a >> - * southbound Port_Binding record (via 'sb'). As the state of the system >> - * changes, join_logical_ports() may determine that there is a new LSP or LRP >> - * that has no corresponding Port_Binding record (in which case build_ports()) >> - * will create the missing Port_Binding) or that a Port_Binding record exists >> - * that has no coresponding LSP (in which case build_ports() will delete the >> - * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port >> - * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. >> - * >> - * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but >> - * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). >> - */ >> -struct ovn_port { >> - /* Port name aka key. >> - * >> - * This is ordinarily the same as nbsp->name or nbrp->name and >> - * sb->logical_port. (A distributed gateway port creates a "derived" >> - * ovn_port with key "cr-%s" % nbrp->name.) */ >> - struct hmap_node key_node; /* Index on 'key'. */ >> - char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ >> - char *json_key; /* 'key', quoted for use in JSON. */ >> - >> - const struct sbrec_port_binding *sb; /* May be NULL. */ >> - >> - uint32_t tunnel_key; >> - >> - /* Logical switch port data. */ >> - const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ >> - >> - struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ >> - unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ >> - unsigned int n_lsp_non_router_addrs; /* Number of elements from the >> - * beginning of 'lsp_addrs' extracted >> - * directly from LSP 'addresses'. */ >> - >> - struct lport_addresses *ps_addrs; /* Port security addresses. */ >> - unsigned int n_ps_addrs; >> - >> - bool lsp_can_be_inc_processed; /* If it can be incrementally processed when >> - the port changes. */ >> - >> - /* Logical router port data. */ >> - const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ >> - >> - struct lport_addresses lrp_networks; >> - >> - struct ovn_port_routable_addresses routables; >> - >> - /* Logical port multicast data. */ >> - struct mcast_port_info mcast_info; >> - >> - /* At most one of l3dgw_port and cr_port can be not NULL. */ >> - >> - /* This is set to a distributed gateway port if and only if this ovn_port >> - * is "derived" from it. Otherwise this is set to NULL. The derived >> - * ovn_port represents the instance of distributed gateway port on the >> - * gateway chassis.*/ >> - struct ovn_port *l3dgw_port; >> - >> - /* This is set to the "derived" chassis-redirect port of this port if and >> - * only if this port is a distributed gateway port. Otherwise this is set >> - * to NULL. */ >> - struct ovn_port *cr_port; >> - >> - bool has_unknown; /* If the addresses have 'unknown' defined. */ >> - >> - bool has_bfd; >> - >> - /* The port's peer: >> - * >> - * - A switch port S of type "router" has a router port R as a peer, >> - * and R in turn has S has its peer. >> - * >> - * - Two connected logical router ports have each other as peer. >> - * >> - * - Other kinds of ports have no peer. */ >> - struct ovn_port *peer; >> - >> - struct ovn_datapath *od; >> - >> - struct ovs_list list; /* In list of similar records. */ >> - >> - struct hmap_node dp_node; /* Node in od->ports. */ >> - >> - struct lport_addresses proxy_arp_addrs; >> - >> - /* Temporarily used for traversing a list (or hmap) of ports. */ >> - bool visited; >> - >> - /* List of struct lflow_ref_node that points to the lflows generated by >> - * this ovn_port. >> - * >> - * This data is initialized and destroyed by the en_northd node, but >> - * populated and used only by the en_lflow node. Ideally this data should >> - * be maintained as part of en_lflow's data (struct lflow_data): a hash >> - * index from ovn_port key to lflows. However, it would be less efficient >> - * and more complex: >> - * >> - * 1. It would require an extra search (using the index) to find the >> - * lflows. >> - * >> - * 2. Building the index needs to be thread-safe, using either a global >> - * lock which is obviously less efficient, or hash-based lock array which >> - * is more complex. >> - * >> - * Adding the list here is more straightforward. The drawback is that we >> - * need to keep in mind that this data belongs to en_lflow node, so never >> - * access it from any other nodes. >> - */ >> - struct ovs_list lflows; >> -}; >> - >> static bool lsp_can_be_inc_processed(const struct nbrec_logical_switch_port *); >> >> static bool >> @@ -1450,16 +1328,21 @@ destroy_routable_addresses(struct ovn_port_routable_addresses *ra) >> } >> >> static char **get_nat_addresses(const struct ovn_port *op, size_t *n, >> - bool routable_only, bool include_lb_ips); >> + bool routable_only, bool include_lb_ips, >> + const struct lr_lb_nat_data_record *); >> >> -static void >> -assign_routable_addresses(struct ovn_port *op) >> +static struct ovn_port_routable_addresses >> +get_op_routable_addresses(struct ovn_port *op, >> + const struct lr_lb_nat_data_record *lr_lbnat_rec) >> { >> size_t n; >> - char **nats = get_nat_addresses(op, &n, true, true); >> + char **nats = get_nat_addresses(op, &n, true, true, lr_lbnat_rec); >> >> if (!nats) { >> - return; >> + return (struct ovn_port_routable_addresses) { >> + .laddrs = NULL, >> + .n_addrs = 0, >> + }; >> } >> >> struct lport_addresses *laddrs = xcalloc(n, sizeof(*laddrs)); >> @@ -1475,9 +1358,15 @@ assign_routable_addresses(struct ovn_port *op) >> } >> free(nats); >> >> - /* Everything seems to have worked out */ >> - op->routables.laddrs = laddrs; >> - op->routables.n_addrs = n_addrs; >> + if (!n_addrs) { >> + free(laddrs); >> + laddrs = NULL; >> + } >> + >> + return (struct ovn_port_routable_addresses) { >> + .laddrs = laddrs, >> + .n_addrs = n_addrs, >> + }; >> } >> >> >> @@ -1537,8 +1426,6 @@ ovn_port_destroy_orphan(struct ovn_port *port) >> } >> free(port->ps_addrs); >> >> - destroy_routable_addresses(&port->routables); >> - >> destroy_lport_addresses(&port->lrp_networks); >> destroy_lport_addresses(&port->proxy_arp_addrs); >> free(port->json_key); >> @@ -2580,9 +2467,7 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, >> sizeof *od->l3dgw_ports); >> } >> od->l3dgw_ports[od->n_l3dgw_ports++] = op; >> - >> - assign_routable_addresses(op); >> - } >> + } >> } >> } >> >> @@ -2679,7 +2564,8 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, >> * and must free the returned array when it is no longer needed. */ >> static char ** >> get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, >> - bool include_lb_ips) >> + bool include_lb_ips, >> + const struct lr_lb_nat_data_record *lr_lbnat_rec) >> { >> size_t n_nats = 0; >> struct eth_addr mac; >> @@ -2764,23 +2650,25 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, >> } >> } >> >> - if (include_lb_ips) { >> + if (include_lb_ips && lr_lbnat_rec) { >> const char *ip_address; >> if (routable_only) { >> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4_routable) { >> + SSET_FOR_EACH (ip_address, >> + &lr_lbnat_rec->lb_ips->ips_v4_routable) { >> ds_put_format(&c_addresses, " %s", ip_address); >> central_ip_address = true; >> } >> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6_routable) { >> + SSET_FOR_EACH (ip_address, >> + &lr_lbnat_rec->lb_ips->ips_v6_routable) { >> ds_put_format(&c_addresses, " %s", ip_address); >> central_ip_address = true; >> } >> } else { >> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4) { >> + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v4) { >> ds_put_format(&c_addresses, " %s", ip_address); >> central_ip_address = true; >> } >> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6) { >> + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v6) { >> ds_put_format(&c_addresses, " %s", ip_address); >> central_ip_address = true; >> } >> @@ -3851,21 +3739,8 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, >> HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { >> ovs_assert(od->nbr); >> >> - /* Checking load balancer groups first, starting from the largest one, >> - * to more efficiently copy IP sets. */ >> - size_t largest_group = 0; >> - >> - for (size_t i = 1; i < od->nbr->n_load_balancer_group; i++) { >> - if (od->nbr->load_balancer_group[i]->n_load_balancer > >> - od->nbr->load_balancer_group[largest_group]->n_load_balancer) { >> - largest_group = i; >> - } >> - } >> - >> for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { >> - size_t idx = (i + largest_group) % od->nbr->n_load_balancer_group; >> - >> - nbrec_lb_group = od->nbr->load_balancer_group[idx]; >> + nbrec_lb_group = od->nbr->load_balancer_group[i]; >> const struct uuid *lb_group_uuid = &nbrec_lb_group->header_.uuid; >> >> lb_group_dps = >> @@ -3873,20 +3748,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, >> lb_group_uuid); >> ovs_assert(lb_group_dps); >> ovn_lb_group_datapaths_add_lr(lb_group_dps, od); >> - >> - if (!od->lb_ips) { >> - od->lb_ips = >> - ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); >> - } else { >> - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { >> - build_lrouter_lb_ips(od->lb_ips, >> - lb_group_dps->lb_group->lbs[j]); >> - } >> - } >> - } >> - >> - if (!od->lb_ips) { >> - od->lb_ips = ovn_lb_ip_set_create(); >> } >> >> for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { >> @@ -3895,7 +3756,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, >> lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); >> ovs_assert(lb_dps); >> ovn_lb_datapaths_add_lr(lb_dps, 1, &od); >> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); >> } >> } >> >> @@ -3949,102 +3809,6 @@ build_lb_svcs( >> } >> } >> >> -static bool lrouter_port_ipv4_reachable(const struct ovn_port *op, >> - ovs_be32 addr); >> -static bool lrouter_port_ipv6_reachable(const struct ovn_port *op, >> - const struct in6_addr *addr); >> - >> -static void >> -add_neigh_ips_to_lrouter(struct ovn_datapath *od, >> - enum lb_neighbor_responder_mode neigh_mode, >> - const struct sset *lb_ips_v4, >> - const struct sset *lb_ips_v6) >> -{ >> - /* If configured to not reply to any neighbor requests for all VIPs >> - * return early. >> - */ >> - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { >> - return; >> - } >> - >> - const char *ip_address; >> - >> - /* If configured to reply to neighbor requests for all VIPs force them >> - * all to be considered "reachable". >> - */ >> - if (neigh_mode == LB_NEIGH_RESPOND_ALL) { >> - SSET_FOR_EACH (ip_address, lb_ips_v4) { >> - sset_add(&od->lb_ips->ips_v4_reachable, ip_address); >> - } >> - SSET_FOR_EACH (ip_address, lb_ips_v6) { >> - sset_add(&od->lb_ips->ips_v6_reachable, ip_address); >> - } >> - >> - return; >> - } >> - >> - /* Otherwise, a VIP is reachable if there's at least one router >> - * subnet that includes it. >> - */ >> - ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); >> - >> - SSET_FOR_EACH (ip_address, lb_ips_v4) { >> - struct ovn_port *op; >> - ovs_be32 vip_ip4; >> - if (ip_parse(ip_address, &vip_ip4)) { >> - HMAP_FOR_EACH (op, dp_node, &od->ports) { >> - if (lrouter_port_ipv4_reachable(op, vip_ip4)) { >> - sset_add(&od->lb_ips->ips_v4_reachable, >> - ip_address); >> - break; >> - } >> - } >> - } >> - } >> - >> - SSET_FOR_EACH (ip_address, lb_ips_v6) { >> - struct ovn_port *op; >> - struct in6_addr vip; >> - if (ipv6_parse(ip_address, &vip)) { >> - HMAP_FOR_EACH (op, dp_node, &od->ports) { >> - if (lrouter_port_ipv6_reachable(op, &vip)) { >> - sset_add(&od->lb_ips->ips_v6_reachable, >> - ip_address); >> - break; >> - } >> - } >> - } >> - } >> -} >> - >> -static void >> -remove_lrouter_lb_reachable_ips(struct ovn_datapath *od, >> - enum lb_neighbor_responder_mode neigh_mode, >> - const struct sset *lb_ips_v4, >> - const struct sset *lb_ips_v6) >> -{ >> - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { >> - return; >> - } >> - >> - const char *ip_address; >> - SSET_FOR_EACH (ip_address, lb_ips_v4) { >> - sset_find_and_delete(&od->lb_ips->ips_v4_reachable, ip_address); >> - } >> - SSET_FOR_EACH (ip_address, lb_ips_v6) { >> - sset_find_and_delete(&od->lb_ips->ips_v6_reachable, ip_address); >> - } >> -} >> - >> -static void >> -build_lrouter_lb_reachable_ips(struct ovn_datapath *od, >> - const struct ovn_northd_lb *lb) >> -{ >> - add_neigh_ips_to_lrouter(od, lb->neigh_mode, &lb->ips_v4, >> - &lb->ips_v6); >> -} >> - >> - >> static void >> build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) >> { >> @@ -4066,43 +3830,6 @@ build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) >> } >> } >> >> -static void >> -build_lrouter_lbs_reachable_ips(struct ovn_datapaths *lr_datapaths, >> - struct hmap *lb_dps_map, >> - struct hmap *lb_group_dps_map) >> -{ >> - struct ovn_datapath *od; >> - >> - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { >> - if (!od->nbr) { >> - continue; >> - } >> - >> - for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { >> - struct ovn_lb_datapaths *lb_dps = >> - ovn_lb_datapaths_find(lb_dps_map, >> - &od->nbr->load_balancer[i]->header_.uuid); >> - ovs_assert(lb_dps); >> - build_lrouter_lb_reachable_ips(od, lb_dps->lb); >> - } >> - >> - for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { >> - const struct nbrec_load_balancer_group *nbrec_lb_group = >> - od->nbr->load_balancer_group[i]; >> - struct ovn_lb_group_datapaths *lb_group_dps; >> - >> - lb_group_dps = >> - ovn_lb_group_datapaths_find(lb_group_dps_map, >> - &nbrec_lb_group->header_.uuid); >> - ovs_assert(lb_group_dps); >> - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { >> - build_lrouter_lb_reachable_ips(od, >> - lb_group_dps->lb_group->lbs[j]); >> - } >> - } >> - } >> -} >> - >> static void >> build_lswitch_lbs_from_lrouter(struct ovn_datapaths *lr_datapaths, >> struct hmap *lb_dps_map, >> @@ -4166,8 +3893,6 @@ build_lb_port_related_data( >> struct hmap *svc_monitor_map) >> { >> build_lrouter_lbs_check(lr_datapaths); >> - build_lrouter_lbs_reachable_ips(lr_datapaths, lb_dps_map, >> - lb_group_dps_map); >> build_lb_svcs(ovnsb_txn, sbrec_service_monitor_table, ls_ports, lb_dps_map, >> svc_monitor_lsps, svc_monitor_map); >> build_lswitch_lbs_from_lrouter(lr_datapaths, lb_dps_map, lb_group_dps_map); >> @@ -4533,7 +4258,8 @@ check_sb_lb_duplicates(const struct sbrec_load_balancer_table *table) >> * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it >> * only syncs the nat column of port binding corresponding to the 'op->nbsp' */ >> static void >> -sync_pb_for_lsp(struct ovn_port *op) >> +sync_pb_for_lsp(struct ovn_port *op, >> + const struct lr_lb_nat_data_table *lr_lbnats) >> { >> ovs_assert(op->nbsp); >> >> @@ -4552,10 +4278,17 @@ sync_pb_for_lsp(struct ovn_port *op) >> if (nat_addresses && !strcmp(nat_addresses, "router")) { >> if (op->peer && op->peer->od >> && (chassis || op->peer->od->n_l3dgw_ports)) { >> - bool exclude_lb_vips = smap_get_bool(&op->nbsp->options, >> + bool include_lb_vips = !smap_get_bool(&op->nbsp->options, >> "exclude-lb-vips-from-garp", false); >> + >> + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; >> + >> + if (include_lb_vips) { >> + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index( >> + lr_lbnats, op->peer->od->index); >> + } >> nats = get_nat_addresses(op->peer, &n_nats, false, >> - !exclude_lb_vips); >> + include_lb_vips, lr_lbnat_rec); >> } >> } else if (nat_addresses && (chassis || l3dgw_ports)) { >> struct lport_addresses laddrs; >> @@ -4662,7 +4395,8 @@ sync_pb_for_lsp(struct ovn_port *op) >> * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it >> * only sets the port binding options column for the router ports */ >> static void >> -sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) >> +sync_pb_for_lrp(struct ovn_port *op, >> + const struct lr_lb_nat_data_table *lr_lbnats) >> { >> ovs_assert(op->nbrp); >> >> @@ -4671,14 +4405,14 @@ sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) >> >> const char *chassis_name = smap_get(&op->od->nbr->options, "chassis"); >> if (is_cr_port(op)) { >> - const struct lr_nat_record *lrnat_rec = >> - lr_nat_table_find_by_index(lr_nats, op->od->index); >> - ovs_assert(lrnat_rec); >> + const struct lr_lb_nat_data_record *lr_lbnat_rec = >> + lr_lb_nat_data_table_find_by_index(lr_lbnats, op->od->index); >> + ovs_assert(lr_lbnat_rec); >> >> smap_add(&new, "distributed-port", op->nbrp->name); >> >> bool always_redirect = >> - !lrnat_rec->has_distributed_nat && >> + !lr_lbnat_rec->lrnat_rec->has_distributed_nat && >> !l3dgw_port_has_associated_vtep_lports(op->l3dgw_port); >> >> const char *redirect_type = smap_get(&op->nbrp->options, >> @@ -4729,17 +4463,18 @@ static void ovn_update_ipv6_opt_for_op(struct ovn_port *op); >> * the logical switch ports. */ >> void >> sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, >> - struct hmap *lr_ports, const struct lr_nat_table *lr_nats) >> + struct hmap *lr_ports, >> + const struct lr_lb_nat_data_table *lr_lbnats) >> { >> ovs_assert(ovnsb_idl_txn); >> >> struct ovn_port *op; >> HMAP_FOR_EACH (op, key_node, ls_ports) { >> - sync_pb_for_lsp(op); >> + sync_pb_for_lsp(op, lr_lbnats); >> } >> >> HMAP_FOR_EACH (op, key_node, lr_ports) { >> - sync_pb_for_lrp(op, lr_nats); >> + sync_pb_for_lrp(op, lr_lbnats); >> } >> >> ovn_update_ipv6_options(lr_ports); >> @@ -4748,17 +4483,18 @@ sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, >> /* Sync the SB Port bindings for the added and updated logical switch ports >> * of the tracked northd engine data. */ >> bool >> -sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, >> - const struct lr_nat_table *lr_nats) >> +sync_pbs_for_northd_changed_ovn_ports( >> + struct tracked_ovn_ports *trk_ovn_ports, >> + const struct lr_lb_nat_data_table *lr_lbnats) >> { >> struct hmapx_node *hmapx_node; >> struct ovn_port *op; >> HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->created) { >> op = hmapx_node->data; >> if (op->nbsp) { >> - sync_pb_for_lsp(op); >> + sync_pb_for_lsp(op, lr_lbnats); >> } else { >> - sync_pb_for_lrp(op, lr_nats); >> + sync_pb_for_lrp(op, lr_lbnats); >> ovn_update_ipv6_opt_for_op(op); >> } >> } >> @@ -4766,9 +4502,9 @@ sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, >> HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->updated) { >> op = hmapx_node->data; >> if (op->nbsp) { >> - sync_pb_for_lsp(op); >> + sync_pb_for_lsp(op, lr_lbnats); >> } else { >> - sync_pb_for_lrp(op, lr_nats); >> + sync_pb_for_lrp(op, lr_lbnats); >> ovn_update_ipv6_opt_for_op(op); >> } >> } >> @@ -5475,20 +5211,24 @@ fail: >> } >> >> /* Returns true if the logical router has changes which can be >> - * incrementally handled. >> + * incrementally handled or the changes can be ignored. >> * Presently supports i-p for the below changes: >> * - load balancers and load balancer groups. >> + * >> + * Presently below changes are ignored: >> + * - router NAT changes - as the engine node lr-nat handles it. >> */ >> static bool >> -lr_changes_can_be_handled( >> +lr_changes_can_be_handled_or_ignored( >> const struct nbrec_logical_router *lr) >> { >> /* Check if the columns are changed in this row. */ >> enum nbrec_logical_router_column_id col; >> for (col = 0; col < NBREC_LOGICAL_ROUTER_N_COLUMNS; col++) { >> if (nbrec_logical_router_is_updated(lr, col)) { >> - if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER || >> - col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP) { >> + if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER >> + || col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP >> + || col == NBREC_LOGICAL_ROUTER_COL_NAT) { >> continue; >> } >> return false; >> @@ -5507,12 +5247,6 @@ lr_changes_can_be_handled( >> OVSDB_IDL_CHANGE_MODIFY) > 0) { >> return false; >> } >> - for (size_t i = 0; i < lr->n_nat; i++) { >> - if (nbrec_nat_row_get_seqno(lr->nat[i], >> - OVSDB_IDL_CHANGE_MODIFY) > 0) { >> - return false; >> - } >> - } >> for (size_t i = 0; i < lr->n_policies; i++) { >> if (nbrec_logical_router_policy_row_get_seqno(lr->policies[i], >> OVSDB_IDL_CHANGE_MODIFY) > 0) { >> @@ -5528,14 +5262,15 @@ lr_changes_can_be_handled( >> return true; >> } >> >> -/* Return true if changes are handled incrementally, false otherwise. >> +/* Return true if changes are handled incrementally or can be safely >> + * ignored (because those changes are handled by other engine nodes), >> + * false otherwise. >> * When there are any changes, try to track what's exactly changed and set >> * northd_data->change_tracked accordingly: change tracked - true, otherwise, >> * false. >> * Note: Changes to load balancer and load balancer groups associated with >> * the logical routers are handled separately in the lb_data change >> - * handlers (northd_handle_lb_data_changes_pre_od and >> - * northd_handle_lb_data_changes_post_od). >> + * handler (northd_handle_lb_data_changes). >> * */ >> bool >> northd_handle_lr_changes(const struct northd_input *ni, >> @@ -5550,9 +5285,11 @@ northd_handle_lr_changes(const struct northd_input *ni, >> goto fail; >> } >> >> - /* Presently only able to handle load balancer and >> - * load balancer group changes. */ >> - if (!lr_changes_can_be_handled(changed_lr)) { >> + /* Presently >> + * - only able to handle load balancer and load balancer group >> + changes. >> + * - and ignore NAT changes */ >> + if (!lr_changes_can_be_handled_or_ignored(changed_lr)) { >> goto fail; >> } >> } >> @@ -5804,10 +5541,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, >> ovs_assert(lb_dps); >> ovn_lb_datapaths_add_lr(lb_dps, 1, &od); >> >> - /* Add the lb_ips of lb_dps to the od. */ >> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); >> - build_lrouter_lb_reachable_ips(od, lb_dps->lb); >> - >> /* Add the lb to the northd tracked data. */ >> hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); >> } >> @@ -5826,10 +5559,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, >> ovs_assert(lb_dps); >> ovn_lb_datapaths_add_lr(lb_dps, 1, &od); >> >> - /* Add the lb_ips of lb_dps to the od. */ >> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); >> - build_lrouter_lb_reachable_ips(od, lb_dps->lb); >> - >> /* Add the lb to the northd tracked data. */ >> hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); >> } >> @@ -5865,22 +5594,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, >> /* Re-evaluate 'od->has_lb_vip' */ >> init_lb_for_datapath(od); >> >> - /* Update the od->lb_ips with the deleted and inserted >> - * vips (if any). */ >> - remove_ips_from_lb_ip_set(od->lb_ips, lb->routable, >> - &clb->deleted_vips_v4, >> - &clb->deleted_vips_v6); >> - add_ips_to_lb_ip_set(od->lb_ips, lb->routable, >> - &clb->inserted_vips_v4, >> - &clb->inserted_vips_v6); >> - >> - remove_lrouter_lb_reachable_ips(od, lb->neigh_mode, >> - &clb->deleted_vips_v4, >> - &clb->deleted_vips_v6); >> - add_neigh_ips_to_lrouter(od, lb->neigh_mode, >> - &clb->inserted_vips_v4, >> - &clb->inserted_vips_v6); >> - >> /* Add the lr datapath to the northd tracked data. */ >> hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); >> } >> @@ -5908,9 +5621,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, >> /* Re-evaluate 'od->has_lb_vip' */ >> init_lb_for_datapath(od); >> >> - /* Add the lb_ips of lb_dps to the od. */ >> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); >> - >> /* Add the lr datapath to the northd tracked data. */ >> hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); >> } >> @@ -9202,7 +8912,7 @@ arp_nd_ns_match(const char *ips, int addr_family, struct ds *match) >> /* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the >> * IPs configured on the router port. >> */ >> -static bool >> +bool >> lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) >> { >> for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { >> @@ -9218,7 +8928,7 @@ lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) >> /* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the >> * IPs configured on the router port. >> */ >> -static bool >> +bool >> lrouter_port_ipv6_reachable(const struct ovn_port *op, >> const struct in6_addr *addr) >> { >> @@ -9284,6 +8994,7 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, >> struct ovn_datapath *sw_od, >> struct ovn_port *sw_op, >> const struct lr_nat_table *lr_nats, >> + const struct lr_lb_nat_data_table *lr_lbnats, >> struct hmap *lflows, >> const struct ovsdb_idl_row *stage_hint) >> { >> @@ -9299,32 +9010,38 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, >> * router port. >> * Priority: 80. >> */ >> - >> - const char *ip_addr; >> - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v4_reachable) { >> - ovs_be32 ipv4_addr; >> - >> - /* Check if the ovn port has a network configured on which we could >> - * expect ARP requests for the LB VIP. >> - */ >> - if (ip_parse(ip_addr, &ipv4_addr) && >> - lrouter_port_ipv4_reachable(op, ipv4_addr)) { >> - build_lswitch_rport_arp_req_flow( >> - ip_addr, AF_INET, sw_op, sw_od, 80, lflows, >> - stage_hint); >> + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; >> + if (op->od->nbr->n_load_balancer || op->od->nbr->n_load_balancer_group) { >> + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, >> + op->od->index); >> + ovs_assert(lr_lbnat_rec); >> + >> + const char *ip_addr; >> + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v4_reachable) { >> + ovs_be32 ipv4_addr; >> + >> + /* Check if the ovn port has a network configured on which we could >> + * expect ARP requests for the LB VIP. >> + */ >> + if (ip_parse(ip_addr, &ipv4_addr) && >> + lrouter_port_ipv4_reachable(op, ipv4_addr)) { >> + build_lswitch_rport_arp_req_flow( >> + ip_addr, AF_INET, sw_op, sw_od, 80, lflows, >> + stage_hint); >> + } >> } >> - } >> - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v6_reachable) { >> - struct in6_addr ipv6_addr; >> + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v6_reachable) { >> + struct in6_addr ipv6_addr; >> >> - /* Check if the ovn port has a network configured on which we could >> - * expect NS requests for the LB VIP. >> - */ >> - if (ipv6_parse(ip_addr, &ipv6_addr) && >> - lrouter_port_ipv6_reachable(op, &ipv6_addr)) { >> - build_lswitch_rport_arp_req_flow( >> - ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, >> - stage_hint); >> + /* Check if the ovn port has a network configured on which we could >> + * expect NS requests for the LB VIP. >> + */ >> + if (ipv6_parse(ip_addr, &ipv6_addr) && >> + lrouter_port_ipv6_reachable(op, &ipv6_addr)) { >> + build_lswitch_rport_arp_req_flow( >> + ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, >> + stage_hint); >> + } >> } >> } >> >> @@ -9374,13 +9091,15 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, >> * expect ARP requests/NS for the DNAT external_ip. >> */ >> if (nat_entry_is_v6(nat_entry)) { >> - if (!sset_contains(&op->od->lb_ips->ips_v6, nat->external_ip)) { >> + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, >> + nat->external_ip)) { >> build_lswitch_rport_arp_req_flow( >> nat->external_ip, AF_INET6, sw_op, sw_od, 80, lflows, >> stage_hint); >> } >> } else { >> - if (!sset_contains(&op->od->lb_ips->ips_v4, nat->external_ip)) { >> + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, >> + nat->external_ip)) { >> build_lswitch_rport_arp_req_flow( >> nat->external_ip, AF_INET, sw_op, sw_od, 80, lflows, >> stage_hint); >> @@ -10441,6 +10160,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, >> static void >> build_lswitch_ip_unicast_lookup(struct ovn_port *op, >> const struct lr_nat_table *lr_nats, >> + const struct lr_lb_nat_data_table *lr_lbnats, >> struct hmap *lflows, >> struct ds *actions, >> struct ds *match) >> @@ -10456,7 +10176,8 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op, >> */ >> if (lsp_is_router(op->nbsp)) { >> build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lr_nats, >> - lflows, &op->nbsp->header_); >> + lr_lbnats, lflows, >> + &op->nbsp->header_); >> } >> >> for (size_t i = 0; i < op->nbsp->n_addresses; i++) { >> @@ -12646,6 +12367,7 @@ build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op, >> static void >> build_lrouter_drop_own_dest(struct ovn_port *op, >> const struct lr_nat_record *lrnat_rec, >> + const struct lr_lb_nat_data_record *lr_lbnat_rec, >> enum ovn_stage stage, >> uint16_t priority, bool drop_snat_ip, >> struct hmap *lflows) >> @@ -12658,8 +12380,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, >> >> bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, >> ip); >> - bool router_ip_in_lb_ips = >> - !!sset_find(&op->od->lb_ips->ips_v4, ip); >> + bool router_ip_in_lb_ips = (lr_lbnat_rec && >> + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v4, >> + ip)); >> bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || >> router_ip_in_lb_ips)); >> >> @@ -12688,8 +12411,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, >> >> bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, >> ip); >> - bool router_ip_in_lb_ips = >> - !!sset_find(&op->od->lb_ips->ips_v6, ip); >> + bool router_ip_in_lb_ips = (lr_lbnat_rec && >> + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v6, >> + ip)); >> bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || >> router_ip_in_lb_ips)); >> >> @@ -13401,7 +13125,8 @@ build_ip_routing_flows_for_lrp( >> */ >> static void >> build_ip_routing_flows_for_router_type_lsp( >> - struct ovn_port *op, const struct hmap *lr_ports, struct hmap *lflows) >> + struct ovn_port *op, const struct lr_lb_nat_data_table *lr_lbnats, >> + const struct hmap *lr_ports, struct hmap *lflows) >> { >> ovs_assert(op->nbsp); >> if (!lsp_is_router(op->nbsp)) { >> @@ -13409,7 +13134,8 @@ build_ip_routing_flows_for_router_type_lsp( >> } >> >> struct ovn_port *peer = ovn_port_get_peer(lr_ports, op); >> - if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs) { >> + if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs >> + || !op->od->n_router_ports) { >> return; >> } >> >> @@ -13420,19 +13146,29 @@ build_ip_routing_flows_for_router_type_lsp( >> continue; >> } >> >> - struct ovn_port_routable_addresses *ra = &router_port->routables; >> - for (size_t j = 0; j < ra->n_addrs; j++) { >> - struct lport_addresses *laddrs = &ra->laddrs[j]; >> - for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { >> - add_route(lflows, peer->od, peer, >> - peer->lrp_networks.ipv4_addrs[0].addr_s, >> - laddrs->ipv4_addrs[k].network_s, >> - laddrs->ipv4_addrs[k].plen, NULL, false, 0, >> - &peer->nbrp->header_, false, >> - ROUTE_PRIO_OFFSET_CONNECTED); >> + const struct lr_lb_nat_data_record *lr_lbnat_rec = >> + lr_lb_nat_data_table_find_by_index(lr_lbnats, >> + router_port->od->index); >> + >> + if (router_port->nbrp->ha_chassis_group || >> + router_port->nbrp->n_gateway_chassis) { >> + struct ovn_port_routable_addresses ra = >> + get_op_routable_addresses(router_port, lr_lbnat_rec); >> + for (size_t j = 0; j < ra.n_addrs; j++) { >> + struct lport_addresses *laddrs = &ra.laddrs[j]; >> + for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { >> + add_route(lflows, peer->od, peer, >> + peer->lrp_networks.ipv4_addrs[0].addr_s, >> + laddrs->ipv4_addrs[k].network_s, >> + laddrs->ipv4_addrs[k].plen, NULL, false, 0, >> + &peer->nbrp->header_, false, >> + ROUTE_PRIO_OFFSET_CONNECTED); >> + } >> } >> + destroy_routable_addresses(&ra); >> } >> } >> + >> } >> >> static void >> @@ -13656,33 +13392,36 @@ build_arp_resolve_flows_for_lrouter( >> >> static void >> routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, >> - struct ovn_port *peer, struct ds *match, >> - struct ds *actions) >> + struct ovn_port *peer, >> + const struct lr_lb_nat_data_record *lr_lbnat_rec, >> + struct ds *match, struct ds *actions) >> { >> - struct ovn_port_routable_addresses *ra = &router_port->routables; >> - if (!ra->n_addrs) { >> + struct ovn_port_routable_addresses ra = >> + get_op_routable_addresses(router_port, lr_lbnat_rec); >> + if (!ra.n_addrs) { >> return; >> } >> >> - for (size_t i = 0; i < ra->n_addrs; i++) { >> + for (size_t i = 0; i < ra.n_addrs; i++) { >> ds_clear(match); >> ds_put_format(match, "outport == %s && "REG_NEXT_HOP_IPV4" == {", >> peer->json_key); >> bool first = true; >> - for (size_t j = 0; j < ra->laddrs[i].n_ipv4_addrs; j++) { >> + for (size_t j = 0; j < ra.laddrs[i].n_ipv4_addrs; j++) { >> if (!first) { >> ds_put_cstr(match, ", "); >> } >> - ds_put_cstr(match, ra->laddrs[i].ipv4_addrs[j].addr_s); >> + ds_put_cstr(match, ra.laddrs[i].ipv4_addrs[j].addr_s); >> first = false; >> } >> ds_put_cstr(match, "}"); >> >> ds_clear(actions); >> - ds_put_format(actions, "eth.dst = %s; next;", ra->laddrs[i].ea_s); >> + ds_put_format(actions, "eth.dst = %s; next;", ra.laddrs[i].ea_s); >> ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100, >> ds_cstr(match), ds_cstr(actions)); >> } >> + destroy_routable_addresses(&ra); >> } >> >> /* Local router ingress table ARP_RESOLVE: ARP Resolution. >> @@ -13699,6 +13438,7 @@ routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, >> static void >> build_arp_resolve_flows_for_lrp( >> struct ovn_port *op, const struct lr_nat_record *lrnat_rec, >> + const struct lr_lb_nat_data_record *lr_lbnat_rec, >> struct hmap *lflows, struct ds *match, struct ds *actions) >> { >> ovs_assert(op->nbrp); >> @@ -13775,8 +13515,8 @@ build_arp_resolve_flows_for_lrp( >> * >> * Priority 2. >> */ >> - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_ARP_RESOLVE, 2, >> - true, lflows); >> + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, >> + S_ROUTER_IN_ARP_RESOLVE, 2, true, lflows); >> } >> >> /* This function adds ARP resolve flows related to a LSP. */ >> @@ -13784,6 +13524,7 @@ static void >> build_arp_resolve_flows_for_lsp( >> struct ovn_port *op, struct hmap *lflows, >> const struct hmap *lr_ports, >> + const struct lr_lb_nat_data_table *lr_lbnats, >> struct ds *match, struct ds *actions) >> { >> ovs_assert(op->nbsp); >> @@ -13927,8 +13668,11 @@ build_arp_resolve_flows_for_lsp( >> >> if (smap_get(&peer->od->nbr->options, "chassis") >> || peer->cr_port) { >> + const struct lr_lb_nat_data_record *lr_lbnat_rec; >> + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, >> + router_port->od->index); >> routable_addresses_to_lflows(lflows, router_port, peer, >> - match, actions); >> + lr_lbnat_rec, match, actions); >> } >> } >> } >> @@ -14648,6 +14392,7 @@ static void >> build_lrouter_ipv4_ip_input(struct ovn_port *op, >> struct hmap *lflows, >> const struct lr_nat_record *lrnat_rec, >> + const struct lr_lb_nat_data_record *lr_lbnat_rec, >> struct ds *match, struct ds *actions, >> const struct shash *meter_groups) >> { >> @@ -14772,7 +14517,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, >> &op->nbrp->header_, lflows); >> } >> >> - if (sset_count(&op->od->lb_ips->ips_v4_reachable)) { >> + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v4_reachable)) { >> ds_clear(match); >> if (is_l3dgw_port(op)) { >> ds_put_format(match, "is_chassis_resident(%s)", >> @@ -14788,7 +14533,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, >> free(lb_ips_v4_as); >> } >> >> - if (sset_count(&op->od->lb_ips->ips_v6_reachable)) { >> + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v6_reachable)) { >> ds_clear(match); >> >> if (is_l3dgw_port(op)) { >> @@ -14890,8 +14635,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, >> * Priority 60. >> */ >> if (!lrnat_rec->lb_force_snat_router_ip) { >> - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_IP_INPUT, 60, >> - false, lflows); >> + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, >> + S_ROUTER_IN_IP_INPUT, 60, false, lflows); >> } >> /* ARP / ND handling for external IP addresses. >> * >> @@ -16030,6 +15775,7 @@ struct lswitch_flow_build_info { >> const struct hmap *lr_ports; >> const struct ls_port_group_table *ls_port_groups; >> const struct lr_nat_table *lr_nats; >> + const struct lr_lb_nat_data_table *lr_lbnats; >> struct hmap *lflows; >> struct hmap *igmp_groups; >> const struct shash *meter_groups; >> @@ -16113,14 +15859,15 @@ build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od, >> * switch port. >> */ >> static void >> -build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, >> - const struct hmap *ls_ports, >> - const struct hmap *lr_ports, >> - const struct lr_nat_table *lr_nats, >> - const struct shash *meter_groups, >> - struct ds *match, >> - struct ds *actions, >> - struct hmap *lflows) >> +build_lswitch_and_lrouter_iterate_by_lsp( >> + struct ovn_port *op, const struct hmap *ls_ports, >> + const struct hmap *lr_ports, >> + const struct lr_nat_table *lr_nats, >> + const struct lr_lb_nat_data_table *lr_lbnats, >> + const struct shash *meter_groups, >> + struct ds *match, >> + struct ds *actions, >> + struct hmap *lflows) >> { >> ovs_assert(op->nbsp); >> start_collecting_lflows(); >> @@ -16133,11 +15880,14 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, >> meter_groups, actions, match); >> build_lswitch_dhcp_options_and_response(op, lflows, meter_groups); >> build_lswitch_external_port(op, lflows); >> - build_lswitch_ip_unicast_lookup(op, lr_nats, lflows, actions, match); >> + build_lswitch_ip_unicast_lookup(op, lr_nats, lr_lbnats, lflows, actions, >> + match); >> >> /* Build Logical Router Flows. */ >> - build_ip_routing_flows_for_router_type_lsp(op, lr_ports, lflows); >> - build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, match, actions); >> + build_ip_routing_flows_for_router_type_lsp(op, lr_lbnats, lr_ports, >> + lflows); >> + build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, lr_lbnats, >> + match, actions); >> >> link_ovn_port_to_lflows(op, &collected_lflows); >> end_collecting_lflows(); >> @@ -16156,6 +15906,8 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, >> lsi->lr_nats, op->od->index); >> ovs_assert(lrnet_rec); >> >> + const struct lr_lb_nat_data_record *lr_lbnat_rec = >> + lr_lb_nat_data_table_find_by_index(lsi->lr_lbnats, op->od->index); >> build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, >> &lsi->actions); >> build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, >> @@ -16163,15 +15915,15 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, >> build_ip_routing_flows_for_lrp(op, lsi->lflows); >> build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, >> &lsi->actions, lsi->meter_groups); >> - build_arp_resolve_flows_for_lrp(op, lrnet_rec, lsi->lflows, &lsi->match, >> - &lsi->actions); >> + build_arp_resolve_flows_for_lrp(op, lrnet_rec, lr_lbnat_rec, lsi->lflows, >> + &lsi->match, &lsi->actions); >> build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, >> &lsi->actions); >> build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match); >> build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows, >> &lsi->match, &lsi->actions, >> lsi->meter_groups); >> - build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, >> + build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, lr_lbnat_rec, >> &lsi->match, &lsi->actions, lsi->meter_groups); >> build_lrouter_force_snat_flows_op(op, lrnet_rec, lsi->lflows, &lsi->match, >> &lsi->actions); >> @@ -16234,6 +15986,7 @@ build_lflows_thread(void *arg) >> build_lswitch_and_lrouter_iterate_by_lsp(op, lsi->ls_ports, >> lsi->lr_ports, >> lsi->lr_nats, >> + lsi->lr_lbnats, >> lsi->meter_groups, >> &lsi->match, >> &lsi->actions, >> @@ -16344,6 +16097,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, >> const struct hmap *lr_ports, >> const struct ls_port_group_table *ls_pgs, >> const struct lr_nat_table *lr_nats, >> + const struct lr_lb_nat_data_table *lr_lbnats, >> struct hmap *lflows, >> struct hmap *igmp_groups, >> const struct shash *meter_groups, >> @@ -16374,6 +16128,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, >> lsiv[index].lr_ports = lr_ports; >> lsiv[index].ls_port_groups = ls_pgs; >> lsiv[index].lr_nats = lr_nats; >> + lsiv[index].lr_lbnats = lr_lbnats; >> lsiv[index].igmp_groups = igmp_groups; >> lsiv[index].meter_groups = meter_groups; >> lsiv[index].lb_dps_map = lb_dps_map; >> @@ -16409,6 +16164,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, >> .lr_ports = lr_ports, >> .ls_port_groups = ls_pgs, >> .lr_nats = lr_nats, >> + .lr_lbnats = lr_lbnats, >> .lflows = lflows, >> .igmp_groups = igmp_groups, >> .meter_groups = meter_groups, >> @@ -16437,6 +16193,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, >> build_lswitch_and_lrouter_iterate_by_lsp(op, lsi.ls_ports, >> lsi.lr_ports, >> lsi.lr_nats, >> + lsi.lr_lbnats, >> lsi.meter_groups, >> &lsi.match, &lsi.actions, >> lsi.lflows); >> @@ -16558,6 +16315,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, >> input_data->lr_ports, >> input_data->ls_port_groups, >> input_data->lr_nats, >> + input_data->lr_lbnats, >> lflows, >> &igmp_groups, >> input_data->meter_groups, >> @@ -17038,6 +16796,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, >> build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, >> lflow_input->lr_ports, >> lflow_input->lr_nats, >> + lflow_input->lr_lbnats, >> lflow_input->meter_groups, >> &match, &actions, >> lflows); >> @@ -17076,6 +16835,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, >> build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, >> lflow_input->lr_ports, >> lflow_input->lr_nats, >> + lflow_input->lr_lbnats, >> lflow_input->meter_groups, >> &match, &actions, >> lflows); >> diff --git a/northd/northd.h b/northd/northd.h >> index 564729ebcc..7c446f5758 100644 >> --- a/northd/northd.h >> +++ b/northd/northd.h >> @@ -179,6 +179,7 @@ struct lflow_input { >> const struct hmap *lr_ports; >> const struct ls_port_group_table *ls_port_groups; >> const struct lr_nat_table *lr_nats; >> + const struct lr_lb_nat_data_table *lr_lbnats; >> const struct shash *meter_groups; >> const struct hmap *lb_datapaths_map; >> const struct hmap *bfd_connections; >> @@ -318,9 +319,6 @@ struct ovn_datapath { >> /* router datapath has a logical port with redirect-type set to bridged. */ >> bool redirect_bridged; >> >> - /* Load Balancer vIPs relevant for this datapath. */ >> - struct ovn_lb_ip_set *lb_ips; >> - >> struct ovn_port **localnet_ports; >> size_t n_localnet_ports; >> >> @@ -337,6 +335,119 @@ struct ovn_datapath { >> const struct ovn_datapath *ovn_datapath_find(const struct hmap *datapaths, >> const struct uuid *uuid); >> >> +/* A logical switch port or logical router port. >> + * >> + * In steady state, an ovn_port points to a northbound Logical_Switch_Port >> + * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a >> + * southbound Port_Binding record (via 'sb'). As the state of the system >> + * changes, join_logical_ports() may determine that there is a new LSP or LRP >> + * that has no corresponding Port_Binding record (in which case build_ports()) >> + * will create the missing Port_Binding) or that a Port_Binding record exists >> + * that has no coresponding LSP (in which case build_ports() will delete the >> + * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port >> + * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. >> + * >> + * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but >> + * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). >> + */ >> +struct ovn_port { >> + /* Port name aka key. >> + * >> + * This is ordinarily the same as nbsp->name or nbrp->name and >> + * sb->logical_port. (A distributed gateway port creates a "derived" >> + * ovn_port with key "cr-%s" % nbrp->name.) */ >> + struct hmap_node key_node; /* Index on 'key'. */ >> + char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ >> + char *json_key; /* 'key', quoted for use in JSON. */ >> + >> + const struct sbrec_port_binding *sb; /* May be NULL. */ >> + >> + uint32_t tunnel_key; >> + >> + /* Logical switch port data. */ >> + const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ >> + >> + struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ >> + unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ >> + unsigned int n_lsp_non_router_addrs; /* Number of elements from the >> + * beginning of 'lsp_addrs' extracted >> + * directly from LSP 'addresses'. */ >> + >> + struct lport_addresses *ps_addrs; /* Port security addresses. */ >> + unsigned int n_ps_addrs; >> + >> + bool lsp_can_be_inc_processed; /* If it can be incrementally processed when >> + the port changes. */ >> + >> + /* Logical router port data. */ >> + const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ >> + >> + struct lport_addresses lrp_networks; >> + >> + /* Logical port multicast data. */ >> + struct mcast_port_info mcast_info; >> + >> + /* At most one of l3dgw_port and cr_port can be not NULL. */ >> + >> + /* This is set to a distributed gateway port if and only if this ovn_port >> + * is "derived" from it. Otherwise this is set to NULL. The derived >> + * ovn_port represents the instance of distributed gateway port on the >> + * gateway chassis.*/ >> + struct ovn_port *l3dgw_port; >> + >> + /* This is set to the "derived" chassis-redirect port of this port if and >> + * only if this port is a distributed gateway port. Otherwise this is set >> + * to NULL. */ >> + struct ovn_port *cr_port; >> + >> + bool has_unknown; /* If the addresses have 'unknown' defined. */ >> + >> + bool has_bfd; >> + >> + /* The port's peer: >> + * >> + * - A switch port S of type "router" has a router port R as a peer, >> + * and R in turn has S has its peer. >> + * >> + * - Two connected logical router ports have each other as peer. >> + * >> + * - Other kinds of ports have no peer. */ >> + struct ovn_port *peer; >> + >> + struct ovn_datapath *od; >> + >> + struct ovs_list list; /* In list of similar records. */ >> + >> + struct hmap_node dp_node; /* Node in od->ports. */ >> + >> + struct lport_addresses proxy_arp_addrs; >> + >> + /* Temporarily used for traversing a list (or hmap) of ports. */ >> + bool visited; >> + >> + /* List of struct lflow_ref_node that points to the lflows generated by >> + * this ovn_port. >> + * >> + * This data is initialized and destroyed by the en_northd node, but >> + * populated and used only by the en_lflow node. Ideally this data should >> + * be maintained as part of en_lflow's data (struct lflow_data): a hash >> + * index from ovn_port key to lflows. However, it would be less efficient >> + * and more complex: >> + * >> + * 1. It would require an extra search (using the index) to find the >> + * lflows. >> + * >> + * 2. Building the index needs to be thread-safe, using either a global >> + * lock which is obviously less efficient, or hash-based lock array which >> + * is more complex. >> + * >> + * Adding the list here is more straightforward. The drawback is that we >> + * need to keep in mind that this data belongs to en_lflow node, so never >> + * access it from any other nodes. >> + */ >> + struct ovs_list lflows; >> +}; >> + >> void ovnnb_db_run(struct northd_input *input_data, >> struct northd_data *data, >> struct ovsdb_idl_txn *ovnnb_txn, >> @@ -396,13 +507,27 @@ void sync_lbs(struct ovsdb_idl_txn *, const struct sbrec_load_balancer_table *, >> struct chassis_features *chassis_features); >> bool check_sb_lb_duplicates(const struct sbrec_load_balancer_table *); >> >> +struct lr_lb_nat_data_table; >> void sync_pbs(struct ovsdb_idl_txn *, struct hmap *ls_ports, >> - struct hmap *lr_ports, const struct lr_nat_table *); >> -bool sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *, >> - const struct lr_nat_table *); >> + struct hmap *lr_ports, >> + const struct lr_lb_nat_data_table *); >> +bool sync_pbs_for_northd_changed_ovn_ports( >> + struct tracked_ovn_ports *, >> + const struct lr_lb_nat_data_table *); >> >> bool northd_has_tracked_data(struct northd_tracked_data *); >> bool northd_has_only_ports_in_tracked_data(struct northd_tracked_data *); >> bool northd_has_lbs_in_tracked_data(struct northd_tracked_data *); >> >> +/* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the >> + * IPs configured on the router port. >> + */ >> +bool lrouter_port_ipv4_reachable(const struct ovn_port *, ovs_be32 addr); >> + >> +/* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the >> + * IPs configured on the router port. >> + */ >> +bool lrouter_port_ipv6_reachable(const struct ovn_port *, >> + const struct in6_addr *); >> + >> #endif /* NORTHD_H */ >> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at >> index b7f9cb5689..8fc5cd1d60 100644 >> --- a/tests/ovn-northd.at >> +++ b/tests/ovn-northd.at >> @@ -10416,18 +10416,21 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:10.0.0.3=sw0-p1:10.0.0.2 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> >> check ovn-nbctl --wait=sb set load_balancer . options:foo=bar >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> >> check ovn-nbctl --wait=sb -- lb-add lb2 20.0.0.10:80 20.0.0.20:80 -- lb-add lb3 30.0.0.10:80 30.0.0.20:80 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> >> @@ -10437,6 +10440,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb -- lb-del lb2 -- lb-del lb3 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> >> @@ -10450,6 +10454,7 @@ AT_CHECK([ovn-nbctl --wait=sb \ >> ]) >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> >> @@ -10467,6 +10472,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb clear Load_Balancer . health_check >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> >> @@ -10481,6 +10487,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> >> @@ -10489,6 +10496,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> # A LB applied to a switch/router triggers: >> # - a recompute in the first iteration (handling northd change) >> @@ -10501,6 +10509,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10510,6 +10519,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10519,6 +10529,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10528,6 +10539,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10537,6 +10549,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb ls-lb-del sw0 lb1 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10547,6 +10560,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 -- lsp-add sw0 sw0p1 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> >> @@ -10567,6 +10581,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-lb-add lr0 lb1 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10576,6 +10591,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10585,6 +10601,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10594,6 +10611,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10603,6 +10621,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10632,6 +10651,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb add load_balancer_group . load_Balancer $lb1_uuid >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> >> @@ -10639,6 +10659,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb clear load_balancer_group . load_Balancer >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> >> @@ -10655,6 +10676,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> >> @@ -10671,6 +10693,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10680,6 +10703,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10689,6 +10713,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10698,6 +10723,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10713,6 +10739,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl add logical_router lr0 load_balancer_group $lbg1_uuid >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10722,6 +10749,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10731,6 +10759,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10740,6 +10769,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10749,6 +10779,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10757,6 +10788,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb clear logical_router lr0 load_balancer_group >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> >> @@ -10765,6 +10797,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> >> @@ -10773,6 +10806,7 @@ check ovn-nbctl --wait=sb clear logical_switch sw0 load_balancer_group -- \ >> destroy load_balancer_group $lbg1_uuid >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb compute compute >> >> @@ -10796,6 +10830,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> lbg1_uuid=$(ovn-nbctl --wait=sb create load_balancer_group name=lbg1) >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow norecompute nocompute >> check_engine_stats sync_to_sb_lb norecompute nocompute >> >> @@ -10803,6 +10838,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set load_balancer_group . load_balancer="$lb2_uuid,$lb3_uuid,$lb4_uuid" >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> >> @@ -10810,6 +10846,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set logical_switch sw0 load_balancer_group=$lbg1_uuid >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10818,6 +10855,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set logical_router lr1 load_balancer_group=$lbg1_uuid >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10826,6 +10864,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb ls-lb-add sw0 lb2 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10834,6 +10873,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb ls-lb-add sw0 lb3 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10843,6 +10883,7 @@ check ovn-nbctl --wait=sb lr-lb-add lr1 lb1 >> check ovn-nbctl --wait=sb lr-lb-add lr1 lb2 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10851,6 +10892,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb ls-lb-del sw0 lb2 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10859,6 +10901,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-lb-del lr1 lb2 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10869,6 +10912,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lb-del lb4 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10879,6 +10923,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lb-del lb2 >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -10887,6 +10932,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb remove load_balancer_group . load_balancer $lb3_uuid >> check_engine_stats lb_data norecompute compute >> check_engine_stats northd recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_lb recompute compute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11019,6 +11065,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-add lr0 >> check_engine_stats northd recompute nocompute >> check_engine_stats lr_nat recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> check_engine_stats lflow recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11031,6 +11078,7 @@ check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 >> # for the SB port binding change. >> check_engine_stats northd recompute compute >> check_engine_stats lr_nat recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> check_engine_stats lflow recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11042,6 +11090,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 >> check_engine_stats northd recompute nocompute >> check_engine_stats lr_nat recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> check_engine_stats lflow recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11067,6 +11116,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl set logical_router_port lr0-sw0 options:foo=bar >> check_engine_stats northd recompute nocompute >> check_engine_stats lr_nat recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> check_engine_stats lflow recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11076,8 +11126,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >> # engine nodes. >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 >> -check_engine_stats northd recompute nocompute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11085,8 +11135,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >> # Update the NAT options column >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set NAT . options:foo=bar >> -check_engine_stats northd recompute nocompute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11094,8 +11144,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >> # Update the NAT external_ip column >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set NAT . external_ip=172.168.0.120 >> -check_engine_stats northd recompute nocompute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11103,8 +11154,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >> # Update the NAT logical_ip column >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set NAT . logical_ip=10.0.0.10 >> -check_engine_stats northd recompute nocompute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11112,8 +11164,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >> # Update the NAT type >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set NAT . type=snat >> -check_engine_stats northd recompute nocompute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11121,8 +11174,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >> # Create a dnat_and_snat NAT with external_mac and logical_port >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 sw0p1 30:54:00:00:00:03 >> -check_engine_stats northd recompute compute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11131,8 +11185,9 @@ nat2_uuid=$(ovn-nbctl --bare --columns _uuid find nat logical_ip=10.0.0.4) >> >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb set NAT $nat2_uuid external_mac='"30:54:00:00:00:04"' >> -check_engine_stats northd recompute nocompute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11147,32 +11202,36 @@ check ovn-nbctl lr-lb-add lr0 lb2 >> # is a lb vip. >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.140 10.0.0.20 >> -check_engine_stats northd recompute nocompute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats sync_to_sb_pb recompute nocompute >> check_engine_stats lflow recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.150 10.0.0.41 >> -check_engine_stats northd recompute nocompute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats sync_to_sb_pb recompute nocompute >> check_engine_stats lflow recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.150 >> -check_engine_stats northd recompute nocompute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats sync_to_sb_pb recompute nocompute >> check_engine_stats lflow recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.140 >> -check_engine_stats northd recompute nocompute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats sync_to_sb_pb recompute nocompute >> check_engine_stats lflow recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11180,8 +11239,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >> # Delete the NAT >> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb clear logical_router lr0 nat >> -check_engine_stats northd recompute compute >> -check_engine_stats lr_nat recompute nocompute >> +check_engine_stats northd norecompute compute >> +check_engine_stats lr_nat norecompute compute >> +check_engine_stats lr_lb_nat_data norecompute compute >> check_engine_stats lflow recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11191,6 +11251,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-policy-add lr0 10 "ip4.src == 10.0.0.3" reroute 172.168.0.101,172.168.0.102 >> check_engine_stats northd recompute nocompute >> check_engine_stats lr_nat recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> check_engine_stats lflow recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE >> @@ -11199,6 +11260,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >> check ovn-nbctl --wait=sb lr-policy-del lr0 10 "ip4.src == 10.0.0.3" >> check_engine_stats northd recompute nocompute >> check_engine_stats lr_nat recompute nocompute >> +check_engine_stats lr_lb_nat_data recompute nocompute >> check_engine_stats sync_to_sb_pb recompute nocompute >> check_engine_stats lflow recompute nocompute >> CHECK_NO_CHANGE_AFTER_RECOMPUTE
On 11/23/23 22:29, Dumitru Ceara wrote: > On 11/23/23 21:45, Dumitru Ceara wrote: >> On 10/26/23 20:15, numans@ovn.org wrote: >>> From: Numan Siddique <numans@ovn.org> >>> >>> This new engine now maintains the load balancer and NAT data of a >>> logical router which was earlier part of northd engine node data. >>> The main inputs to this engine are: >>> - northd node >>> - lr-nat node >>> >>> A record for each logical router is maintained in the 'lr_lb_nats' >>> hmap table and this record >>> - stores the lb related data >>> - embeds the 'lr-nat' record. >>> >>> This engine node becomes an input to 'lflow' node. >>> >>> Signed-off-by: Numan Siddique <numans@ovn.org> >>> --- >>> lib/stopwatch-names.h | 1 + >>> northd/automake.mk | 2 + >>> northd/en-lflow.c | 4 + >>> northd/en-lr-lb-nat-data.c | 654 +++++++++++++++++++++++++++++++++++++ >>> northd/en-lr-lb-nat-data.h | 93 ++++++ >>> northd/en-lr-nat.h | 3 + >>> northd/en-sync-sb.c | 50 +-- >>> northd/inc-proc-northd.c | 13 +- >>> northd/northd.c | 640 ++++++++++++------------------------ >>> northd/northd.h | 137 +++++++- >>> tests/ovn-northd.at | 110 +++++-- >>> 11 files changed, 1212 insertions(+), 495 deletions(-) >>> create mode 100644 northd/en-lr-lb-nat-data.c >>> create mode 100644 northd/en-lr-lb-nat-data.h >>> >>> diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h >>> index 0a16da211e..7d85acdaea 100644 >>> --- a/lib/stopwatch-names.h >>> +++ b/lib/stopwatch-names.h >>> @@ -33,5 +33,6 @@ >>> #define PORT_GROUP_RUN_STOPWATCH_NAME "port_group_run" >>> #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" >>> #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" >>> +#define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" >>> >>> #endif >>> diff --git a/northd/automake.mk b/northd/automake.mk >>> index ae367a2a8b..4116c487df 100644 >>> --- a/northd/automake.mk >>> +++ b/northd/automake.mk >>> @@ -26,6 +26,8 @@ northd_ovn_northd_SOURCES = \ >>> northd/en-lb-data.h \ >>> northd/en-lr-nat.c \ >>> northd/en-lr-nat.h \ >>> + northd/en-lr-lb-nat-data.c \ >>> + northd/en-lr-lb-nat-data.h \ >>> northd/inc-proc-northd.c \ >>> northd/inc-proc-northd.h \ >>> northd/ipam.c \ >>> diff --git a/northd/en-lflow.c b/northd/en-lflow.c >>> index 22f398d419..9cb0ead3f0 100644 >>> --- a/northd/en-lflow.c >>> +++ b/northd/en-lflow.c >>> @@ -20,6 +20,7 @@ >>> >>> #include "en-lflow.h" >>> #include "en-lr-nat.h" >>> +#include "en-lr-lb-nat-data.h" >>> #include "en-northd.h" >>> #include "en-meters.h" >>> >>> @@ -43,6 +44,8 @@ lflow_get_input_data(struct engine_node *node, >>> engine_get_input_data("sync_meters", node); >>> struct ed_type_lr_nat_data *lr_nat_data = >>> engine_get_input_data("lr_nat", node); >>> + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = >>> + engine_get_input_data("lr_lb_nat_data", node); >>> >>> lflow_input->nbrec_bfd_table = >>> EN_OVSDB_GET(engine_get_input("NB_bfd", node)); >>> @@ -66,6 +69,7 @@ lflow_get_input_data(struct engine_node *node, >>> lflow_input->lr_ports = &northd_data->lr_ports; >>> lflow_input->ls_port_groups = &pg_data->ls_port_groups; >>> lflow_input->lr_nats = &lr_nat_data->lr_nats; >>> + lflow_input->lr_lbnats = &lr_lb_nat_data->lr_lbnats; >>> lflow_input->meter_groups = &sync_meters_data->meter_groups; >>> lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map; >>> lflow_input->svc_monitor_map = &northd_data->svc_monitor_map; >>> diff --git a/northd/en-lr-lb-nat-data.c b/northd/en-lr-lb-nat-data.c >>> new file mode 100644 >>> index 0000000000..19b638ce0b >>> --- /dev/null >>> +++ b/northd/en-lr-lb-nat-data.c >>> @@ -0,0 +1,654 @@ >>> +/* >>> + * Copyright (c) 2023, Red Hat, Inc. >>> + * >>> + * Licensed under the Apache License, Version 2.0 (the "License"); >>> + * you may not use this file except in compliance with the License. >>> + * You may obtain a copy of the License at: >>> + * >>> + * http://www.apache.org/licenses/LICENSE-2.0 >>> + * >>> + * Unless required by applicable law or agreed to in writing, software >>> + * distributed under the License is distributed on an "AS IS" BASIS, >>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >>> + * See the License for the specific language governing permissions and >>> + * limitations under the License. >>> + */ >>> + >>> +#include <config.h> >>> + >>> +#include <getopt.h> >>> +#include <stdlib.h> >>> +#include <stdio.h> >>> + >>> +/* OVS includes */ >>> +#include "include/openvswitch/hmap.h" >>> +#include "lib/bitmap.h" >>> +#include "lib/socket-util.h" >>> +#include "lib/uuidset.h" >>> +#include "openvswitch/util.h" >>> +#include "openvswitch/vlog.h" >>> +#include "stopwatch.h" >>> + >>> +/* OVN includes */ >>> +#include "en-lb-data.h" >>> +#include "en-lr-lb-nat-data.h" >>> +#include "en-lr-nat.h" >>> +#include "lib/inc-proc-eng.h" >>> +#include "lib/lb.h" >>> +#include "lib/ovn-nb-idl.h" >>> +#include "lib/ovn-sb-idl.h" >>> +#include "lib/ovn-util.h" >>> +#include "lib/stopwatch-names.h" >>> +#include "northd.h" >>> + >>> +VLOG_DEFINE_THIS_MODULE(en_lr_lb_nat_data); >>> + >>> +/* Static function declarations. */ >>> +static void lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *); >>> +static void lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *); >>> +static void lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *); >>> +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_( >>> + const struct lr_lb_nat_data_table *, const struct nbrec_logical_router *); >>> +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index_( >>> + const struct lr_lb_nat_data_table *table, size_t od_index); >>> + >>> +static void lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *, >>> + const struct lr_nat_table *, >>> + const struct ovn_datapaths *lr_datapaths, >>> + const struct hmap *lb_datapaths_map, >>> + const struct hmap *lbgrp_datapaths_map); >>> + >>> +static struct lr_lb_nat_data_input lr_lb_nat_data_get_input_data( >>> + struct engine_node *); >>> + >>> +static struct lr_lb_nat_data_record *lr_lb_nat_data_record_create( >>> + struct lr_lb_nat_data_table *, const struct lr_nat_record *, >>> + const struct hmap *lb_datapaths_map, >>> + const struct hmap *lbgrp_datapaths_map); >>> +static void lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *); >>> +static void lr_lb_nat_data_record_init( >>> + struct lr_lb_nat_data_record *, >>> + const struct hmap *lb_datapaths_map, >>> + const struct hmap *lbgrp_datapaths_map); >>> + >>> +static void build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, >>> + const struct ovn_northd_lb *); >>> +static void add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *, >>> + enum lb_neighbor_responder_mode, >>> + const struct sset *lb_ips_v4, >>> + const struct sset *lb_ips_v6); >>> +static void remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, >>> + enum lb_neighbor_responder_mode, >>> + const struct sset *lb_ips_v4, >>> + const struct sset *lb_ips_v6); >>> +static void lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *); >>> + >>> +/* 'lr_lb_nat_data' engine node manages the NB logical router LB data. >>> + */ >>> +void * >>> +en_lr_lb_nat_data_init(struct engine_node *node OVS_UNUSED, >>> + struct engine_arg *arg OVS_UNUSED) >>> +{ >>> + struct ed_type_lr_lb_nat_data *data = xzalloc(sizeof *data); >>> + lr_lb_nat_data_table_init(&data->lr_lbnats); >>> + hmapx_init(&data->tracked_data.crupdated); >>> + hmapx_init(&data->tracked_data.deleted); >>> + return data; >>> +} >>> + >>> +void >>> +en_lr_lb_nat_data_cleanup(void *data_) >>> +{ >>> + struct ed_type_lr_lb_nat_data *data = >>> + (struct ed_type_lr_lb_nat_data *) data_; >>> + lr_lb_nat_data_table_destroy(&data->lr_lbnats); >>> + hmapx_destroy(&data->tracked_data.crupdated); >>> + hmapx_destroy(&data->tracked_data.deleted); >>> +} >>> + >>> +void >>> +en_lr_lb_nat_data_clear_tracked_data(void *data_) >>> +{ >>> + struct ed_type_lr_lb_nat_data *data = >>> + (struct ed_type_lr_lb_nat_data *) data_; >>> + >>> + struct hmapx_node *hmapx_node; >>> + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { >>> + lr_lb_nat_data_record_destroy(hmapx_node->data); >>> + hmapx_delete(&data->tracked_data.deleted, hmapx_node); >>> + } >>> + >>> + hmapx_clear(&data->tracked_data.crupdated); >>> + data->tracked = false; >>> +} >>> + >>> +void >>> +en_lr_lb_nat_data_run(struct engine_node *node, void *data_) >>> +{ >>> + struct lr_lb_nat_data_input input_data = >>> + lr_lb_nat_data_get_input_data(node); >>> + struct ed_type_lr_lb_nat_data *data = data_; >>> + >>> + stopwatch_start(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); >>> + >>> + lr_lb_nat_data_table_clear(&data->lr_lbnats); >>> + lr_lb_nat_data_table_build(&data->lr_lbnats, input_data.lr_nats, >>> + input_data.lr_datapaths, >>> + input_data.lb_datapaths_map, >>> + input_data.lbgrp_datapaths_map); >>> + >>> + stopwatch_stop(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); Unfortunately, this doesn't do anything if the stopwatch wasn't created before. We're missing a stopwatch_create(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, .. ) in ovn-northd.c. I see now the most recently added two stopwatches (port groups and meters) also don't do that. I'll post a patch for that. Thanks, Dumitru >>> + engine_set_node_state(node, EN_UPDATED); >>> +} >>> + >>> +bool >>> +lr_lb_nat_data_northd_handler(struct engine_node *node, void *data OVS_UNUSED) >>> +{ >>> + struct northd_data *northd_data = engine_get_input_data("northd", node); >>> + if (!northd_data->change_tracked) { >>> + return false; >>> + } >>> + >>> + return true; >>> +} >>> + >>> +bool >>> +lr_lb_nat_data_lb_data_handler(struct engine_node *node, void *data_) >>> +{ >>> + struct ed_type_lb_data *lb_data = engine_get_input_data("lb_data", node); >>> + if (!lb_data->tracked) { >>> + return false; >>> + } >>> + >>> + struct ed_type_lr_lb_nat_data *data = >>> + (struct ed_type_lr_lb_nat_data *) data_; >>> + struct lr_lb_nat_data_input input_data = >>> + lr_lb_nat_data_get_input_data(node); >>> + struct lr_lb_nat_data_record *lr_lbnat_rec; >>> + size_t index; >>> + >>> + const struct tracked_lb_data *trk_lb_data = &lb_data->tracked_lb_data; >>> + const struct ovn_lb_group_datapaths *lbgrp_dps; >>> + const struct crupdated_lbgrp *crupdated_lbgrp; >>> + const struct crupdated_od_lb_data *codlb; >>> + const struct ovn_lb_datapaths *lb_dps; >>> + const struct crupdated_lb *clb; >>> + const struct ovn_northd_lb *lb; >>> + const struct ovn_datapath *od; >>> + >>> + LIST_FOR_EACH (codlb, list_node, &trk_lb_data->crupdated_lr_lbs) { >>> + od = ovn_datapath_find(&input_data.lr_datapaths->datapaths, >>> + &codlb->od_uuid); >>> + ovs_assert(od); >>> + >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, od->nbr); >>> + if (!lr_lbnat_rec) { >>> + const struct lr_nat_record *lrnat_rec = lr_nat_table_find_by_index( >>> + input_data.lr_nats, od->index); >>> + ovs_assert(lrnat_rec); >>> + >>> + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, >>> + lrnat_rec, >>> + input_data.lb_datapaths_map, >>> + input_data.lbgrp_datapaths_map); >>> + >>> + /* Add the lr_lbnat_rec rec to the tracking data. */ >>> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); >>> + continue; >>> + } >>> + >>> + struct uuidset_node *uuidnode; >>> + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbs) { >>> + lb_dps = ovn_lb_datapaths_find( >>> + input_data.lb_datapaths_map, &uuidnode->uuid); >>> + ovs_assert(lb_dps); >>> + >>> + /* Add the lb_ips of lb_dps to the od. */ >>> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); >>> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); >>> + } >>> + >>> + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbgrps) { >>> + lbgrp_dps = ovn_lb_group_datapaths_find( >>> + input_data.lbgrp_datapaths_map, &uuidnode->uuid); >>> + ovs_assert(lbgrp_dps); >>> + >>> + for (size_t j = 0; j < lbgrp_dps->lb_group->n_lbs; j++) { >>> + const struct uuid *lb_uuid >>> + = &lbgrp_dps->lb_group->lbs[j]->nlb->header_.uuid; >>> + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, >>> + lb_uuid); >>> + ovs_assert(lb_dps); >>> + >>> + /* Add the lb_ips of lb_dps to the od. */ >>> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); >>> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); >>> + } >>> + } >>> + >>> + /* Add the lr_lbnat_rec rec to the tracking data. */ >>> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); >>> + } >>> + >>> + HMAP_FOR_EACH (clb, hmap_node, &trk_lb_data->crupdated_lbs) { >>> + lb = clb->lb; >>> + const struct uuid *lb_uuid = &lb->nlb->header_.uuid; >>> + >>> + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, lb_uuid); >>> + ovs_assert(lb_dps); >>> + >>> + BITMAP_FOR_EACH_1 (index, ods_size(input_data.lr_datapaths), >>> + lb_dps->nb_lr_map) { >>> + od = input_data.lr_datapaths->array[index]; >>> + >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, >>> + od->nbr); >>> + ovs_assert(lr_lbnat_rec); >>> + >>> + /* Update the od->lb_ips with the deleted and inserted >>> + * vips (if any). */ >>> + remove_ips_from_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, >>> + &clb->deleted_vips_v4, >>> + &clb->deleted_vips_v6); >>> + add_ips_to_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, >>> + &clb->inserted_vips_v4, >>> + &clb->inserted_vips_v6); >>> + >>> + remove_lrouter_lb_reachable_ips(lr_lbnat_rec, lb->neigh_mode, >>> + &clb->deleted_vips_v4, >>> + &clb->deleted_vips_v6); >>> + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, >>> + &clb->inserted_vips_v4, >>> + &clb->inserted_vips_v6); >>> + >>> + /* Add the lr_lbnat_rec rec to the tracking data. */ >>> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); >>> + } >>> + } >>> + >>> + HMAP_FOR_EACH (crupdated_lbgrp, hmap_node, >>> + &trk_lb_data->crupdated_lbgrps) { >>> + const struct uuid *lb_uuid = &crupdated_lbgrp->lbgrp->uuid; >>> + >>> + lbgrp_dps = ovn_lb_group_datapaths_find(input_data.lbgrp_datapaths_map, >>> + lb_uuid); >>> + ovs_assert(lbgrp_dps); >>> + >>> + struct hmapx_node *hnode; >>> + HMAPX_FOR_EACH (hnode, &crupdated_lbgrp->assoc_lbs) { >>> + lb = hnode->data; >>> + lb_uuid = &lb->nlb->header_.uuid; >>> + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, >>> + lb_uuid); >>> + ovs_assert(lb_dps); >>> + for (size_t i = 0; i < lbgrp_dps->n_lr; i++) { >>> + od = lbgrp_dps->lr[i]; >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, >>> + od->nbr); >>> + ovs_assert(lr_lbnat_rec); >>> + /* Add the lb_ips of lb_dps to the lr lb data. */ >>> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); >>> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); >>> + >>> + /* Add the lr_lbnat_rec rec to the tracking data. */ >>> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); >>> + } >>> + } >>> + } >>> + >>> + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { >>> + struct hmapx_node *hmapx_node; >>> + /* For all the modified lr_lb_nat_data records (re)build the >>> + * vip nats. */ >>> + HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { >>> + lr_lb_nat_data_build_vip_nats(hmapx_node->data); >>> + } >>> + >>> + data->tracked = true; >>> + engine_set_node_state(node, EN_UPDATED); >>> + } >>> + >>> + return true; >>> +} >>> + >>> +bool >>> +lr_lb_nat_data_lr_nat_handler(struct engine_node *node, void *data_) >>> +{ >>> + struct ed_type_lr_nat_data *lr_nat_data = >>> + engine_get_input_data("lr_nat", node); >>> + >>> + if (!lr_nat_data->tracked >>> + || !hmapx_is_empty(&lr_nat_data->tracked_data.deleted)) { >>> + return false; >>> + } >>> + >>> + struct ed_type_lr_lb_nat_data *data = >>> + (struct ed_type_lr_lb_nat_data *) data_; >>> + struct lr_lb_nat_data_input input_data = >>> + lr_lb_nat_data_get_input_data(node); >>> + const struct lr_nat_record *lrnat_rec; >>> + struct lr_lb_nat_data_record *lr_lbnat_rec; >>> + struct hmapx_node *hmapx_node; >>> + >>> + HMAPX_FOR_EACH (hmapx_node, &lr_nat_data->tracked_data.crupdated) { >>> + lrnat_rec = hmapx_node->data; >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, >>> + lrnat_rec->od->nbr); >>> + if (!lr_lbnat_rec) { >>> + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, >>> + lrnat_rec, >>> + input_data.lb_datapaths_map, >>> + input_data.lbgrp_datapaths_map); >>> + } else { >>> + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); >>> + } >>> + >>> + /* Add the lr_lbnat_rec rec to the tracking data. */ >>> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); >>> + } >>> + >>> + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { >>> + data->tracked = true; >>> + engine_set_node_state(node, EN_UPDATED); >>> + } >>> + >>> + return true; >>> +} >>> + >>> +const struct lr_lb_nat_data_record * >>> +lr_lb_nat_data_table_find_by_index(const struct lr_lb_nat_data_table *table, >>> + size_t od_index) >>> +{ >>> + return lr_lb_nat_data_table_find_by_index_(table, od_index); >>> +} >>> + >>> +/* static functions. */ >>> +static void >>> +lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *table) >>> +{ >>> + *table = (struct lr_lb_nat_data_table) { >>> + .entries = HMAP_INITIALIZER(&table->entries), >>> + }; >>> +} >>> + >>> +static void >>> +lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *table) >>> +{ >>> + lr_lb_nat_data_table_clear(table); >>> + hmap_destroy(&table->entries); >>> +} >>> + >>> +static void >>> +lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *table) >>> +{ >>> + struct lr_lb_nat_data_record *lr_lbnat_rec; >>> + HMAP_FOR_EACH_POP (lr_lbnat_rec, key_node, &table->entries) { >>> + lr_lb_nat_data_record_destroy(lr_lbnat_rec); >>> + } >>> + >>> + free(table->array); >>> + table->array = NULL; >>> +} >>> + >>> +static void >>> +lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *table, >>> + const struct lr_nat_table *lr_nats, >>> + const struct ovn_datapaths *lr_datapaths, >>> + const struct hmap *lb_datapaths_map, >>> + const struct hmap *lbgrp_datapaths_map) >>> +{ >>> + table->array = xrealloc(table->array, >>> + ods_size(lr_datapaths) * sizeof *table->array); >>> + const struct lr_nat_record *lrnat_rec; >>> + LR_NAT_TABLE_FOR_EACH (lrnat_rec, lr_nats) { >>> + lr_lb_nat_data_record_create(table, lrnat_rec, lb_datapaths_map, >>> + lbgrp_datapaths_map); >>> + } >>> +} >>> + >>> +static struct lr_lb_nat_data_record * >>> +lr_lb_nat_data_table_find_(const struct lr_lb_nat_data_table *table, >>> + const struct nbrec_logical_router *nbr) >>> +{ >>> + struct lr_lb_nat_data_record *lr_lbnat_rec; >>> + >>> + HMAP_FOR_EACH_WITH_HASH (lr_lbnat_rec, key_node, >>> + uuid_hash(&nbr->header_.uuid), &table->entries) { >>> + if (nbr == lr_lbnat_rec->od->nbr) { >>> + return lr_lbnat_rec; >>> + } >>> + } >>> + return NULL; >>> +} >>> + >>> +static struct lr_lb_nat_data_record * >>> +lr_lb_nat_data_table_find_by_index_(const struct lr_lb_nat_data_table *table, >>> + size_t od_index) >>> +{ >>> + ovs_assert(od_index <= hmap_count(&table->entries)); >>> + return table->array[od_index]; >>> +} >>> + >>> +static struct lr_lb_nat_data_record * >>> +lr_lb_nat_data_record_create(struct lr_lb_nat_data_table *table, >>> + const struct lr_nat_record *lrnat_rec, >>> + const struct hmap *lb_datapaths_map, >>> + const struct hmap *lbgrp_datapaths_map) >>> +{ >>> + struct lr_lb_nat_data_record *lr_lbnat_rec = xzalloc(sizeof *lr_lbnat_rec); >>> + lr_lbnat_rec->lrnat_rec = lrnat_rec; >>> + lr_lbnat_rec->od = lrnat_rec->od; >>> + lr_lb_nat_data_record_init(lr_lbnat_rec, lb_datapaths_map, >>> + lbgrp_datapaths_map); >>> + >>> + hmap_insert(&table->entries, &lr_lbnat_rec->key_node, >>> + uuid_hash(&lr_lbnat_rec->od->nbr->header_.uuid)); >>> + >>> + table->array[lr_lbnat_rec->od->index] = lr_lbnat_rec; >>> + return lr_lbnat_rec; >>> +} >>> + >>> +static void >>> +lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *lr_lbnat_rec) >>> +{ >>> + ovn_lb_ip_set_destroy(lr_lbnat_rec->lb_ips); >>> + lr_lbnat_rec->lb_ips = NULL; >>> + sset_destroy(&lr_lbnat_rec->vip_nats); >>> + free(lr_lbnat_rec); >>> +} >>> + >>> +static void >>> +lr_lb_nat_data_record_init(struct lr_lb_nat_data_record *lr_lbnat_rec, >>> + const struct hmap *lb_datapaths_map, >>> + const struct hmap *lbgrp_datapaths_map) >>> +{ >>> + const struct nbrec_load_balancer_group *nbrec_lb_group; >>> + const struct ovn_lb_group_datapaths *lb_group_dps; >>> + const struct ovn_lb_datapaths *lb_dps; >>> + >>> + /* Checking load balancer groups first, starting from the largest one, >>> + * to more efficiently copy IP sets. */ >>> + size_t largest_group = 0; >>> + >>> + const struct nbrec_logical_router *nbr = lr_lbnat_rec->od->nbr; >>> + for (size_t i = 1; i < nbr->n_load_balancer_group; i++) { >>> + if (nbr->load_balancer_group[i]->n_load_balancer > >>> + nbr->load_balancer_group[largest_group]->n_load_balancer) { >>> + largest_group = i; >>> + } >>> + } >>> + >>> + for (size_t i = 0; i < nbr->n_load_balancer_group; i++) { >>> + size_t idx = (i + largest_group) % nbr->n_load_balancer_group; >>> + >>> + nbrec_lb_group = nbr->load_balancer_group[idx]; >>> + const struct uuid *lbgrp_uuid = &nbrec_lb_group->header_.uuid; >>> + >>> + lb_group_dps = >>> + ovn_lb_group_datapaths_find(lbgrp_datapaths_map, >>> + lbgrp_uuid); >>> + ovs_assert(lb_group_dps); >>> + >>> + if (!lr_lbnat_rec->lb_ips) { >>> + lr_lbnat_rec->lb_ips = >>> + ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); >>> + } else { >>> + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { >>> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, >>> + lb_group_dps->lb_group->lbs[j]); >>> + } >>> + } >>> + >>> + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { >>> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, >>> + lb_group_dps->lb_group->lbs[j]); >>> + } >>> + } >>> + >>> + if (!lr_lbnat_rec->lb_ips) { >>> + lr_lbnat_rec->lb_ips = ovn_lb_ip_set_create(); >>> + } >>> + >>> + for (size_t i = 0; i < nbr->n_load_balancer; i++) { >>> + const struct uuid *lb_uuid = >>> + &nbr->load_balancer[i]->header_.uuid; >>> + lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); >>> + ovs_assert(lb_dps); >>> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); >>> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); >>> + } >>> + >>> + sset_init(&lr_lbnat_rec->vip_nats); >>> + >>> + if (!nbr->n_nat) { >>> + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); >>> + } >>> +} >>> + >>> +static struct lr_lb_nat_data_input >>> +lr_lb_nat_data_get_input_data(struct engine_node *node) >>> +{ >>> + struct northd_data *northd_data = engine_get_input_data("northd", node); >>> + struct ed_type_lr_nat_data *lr_nat_data = >>> + engine_get_input_data("lr_nat", node); >>> + >>> + return (struct lr_lb_nat_data_input) { >>> + .lr_datapaths = &northd_data->lr_datapaths, >>> + .lb_datapaths_map = &northd_data->lb_datapaths_map, >>> + .lbgrp_datapaths_map = &northd_data->lb_group_datapaths_map, >>> + .lr_nats = &lr_nat_data->lr_nats, >>> + }; >>> +} >>> + >>> +static void >>> +build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, >>> + const struct ovn_northd_lb *lb) >>> +{ >>> + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, &lb->ips_v4, >>> + &lb->ips_v6); >>> +} >>> + >>> +static void >>> +add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *lr_lbnat_rec, >>> + enum lb_neighbor_responder_mode neigh_mode, >>> + const struct sset *lb_ips_v4, >>> + const struct sset *lb_ips_v6) >>> +{ >>> + /* If configured to not reply to any neighbor requests for all VIPs >>> + * return early. >>> + */ >>> + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { >>> + return; >>> + } >>> + >>> + const char *ip_address; >>> + >>> + /* If configured to reply to neighbor requests for all VIPs force them >>> + * all to be considered "reachable". >>> + */ >>> + if (neigh_mode == LB_NEIGH_RESPOND_ALL) { >>> + SSET_FOR_EACH (ip_address, lb_ips_v4) { >>> + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, ip_address); >>> + } >>> + SSET_FOR_EACH (ip_address, lb_ips_v6) { >>> + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, ip_address); >>> + } >>> + >>> + return; >>> + } >>> + >>> + /* Otherwise, a VIP is reachable if there's at least one router >>> + * subnet that includes it. >>> + */ >>> + ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); >>> + >>> + SSET_FOR_EACH (ip_address, lb_ips_v4) { >>> + struct ovn_port *op; >>> + ovs_be32 vip_ip4; >>> + if (ip_parse(ip_address, &vip_ip4)) { >>> + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { >>> + if (lrouter_port_ipv4_reachable(op, vip_ip4)) { >>> + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, >>> + ip_address); >>> + break; >>> + } >>> + } >>> + } >>> + } >>> + >>> + SSET_FOR_EACH (ip_address, lb_ips_v6) { >>> + struct ovn_port *op; >>> + struct in6_addr vip; >>> + if (ipv6_parse(ip_address, &vip)) { >>> + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { >>> + if (lrouter_port_ipv6_reachable(op, &vip)) { >>> + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, >>> + ip_address); >>> + break; >>> + } >>> + } >>> + } >>> + } >>> +} >>> + >>> +static void >>> +remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, >>> + enum lb_neighbor_responder_mode neigh_mode, >>> + const struct sset *lb_ips_v4, >>> + const struct sset *lb_ips_v6) >>> +{ >>> + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { >>> + return; >>> + } >>> + >>> + const char *ip_address; >>> + SSET_FOR_EACH (ip_address, lb_ips_v4) { >>> + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v4_reachable, >>> + ip_address); >>> + } >>> + SSET_FOR_EACH (ip_address, lb_ips_v6) { >>> + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v6_reachable, >>> + ip_address); >>> + } >>> +} >>> + >>> +static void >>> +lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *lr_lbnat_rec) >>> +{ >>> + sset_clear(&lr_lbnat_rec->vip_nats); >>> + const char *external_ip; >>> + SSET_FOR_EACH (external_ip, &lr_lbnat_rec->lrnat_rec->external_ips) { >>> + bool is_vip_nat = false; >>> + if (addr_is_ipv6(external_ip)) { >>> + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, >>> + external_ip); >>> + } else { >>> + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, >>> + external_ip); >>> + } >>> + >>> + if (is_vip_nat) { >>> + sset_add(&lr_lbnat_rec->vip_nats, external_ip); >>> + } >>> + } >>> +} >>> diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h >>> new file mode 100644 >>> index 0000000000..9029aee339 >>> --- /dev/null >>> +++ b/northd/en-lr-lb-nat-data.h >>> @@ -0,0 +1,93 @@ >>> +/* >>> + * Copyright (c) 2023, Red Hat, Inc. >>> + * >>> + * Licensed under the Apache License, Version 2.0 (the "License"); >>> + * you may not use this file except in compliance with the License. >>> + * You may obtain a copy of the License at: >>> + * >>> + * http://www.apache.org/licenses/LICENSE-2.0 >>> + * >>> + * Unless required by applicable law or agreed to in writing, software >>> + * distributed under the License is distributed on an "AS IS" BASIS, >>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >>> + * See the License for the specific language governing permissions and >>> + * limitations under the License. >>> + */ >>> +#ifndef EN_LR_LB_NAT_DATA_H >>> +#define EN_LR_LB_NAT_DATA_H 1 >>> + >>> +#include <stdint.h> >>> + >>> +/* OVS includes. */ >>> +#include "lib/hmapx.h" >>> +#include "openvswitch/hmap.h" >>> +#include "sset.h" >>> + >>> +/* OVN includes. */ >>> +#include "lib/inc-proc-eng.h" >>> +#include "lib/lb.h" >>> +#include "lib/ovn-nb-idl.h" >>> +#include "lib/ovn-sb-idl.h" >>> +#include "lib/ovn-util.h" >>> + >>> +struct ovn_datapath; >>> +struct lr_nat_record; >>> + >>> +struct lr_lb_nat_data_record { >>> + struct hmap_node key_node; /* Index on 'nbr->header_.uuid'. */ >>> + >>> + const struct ovn_datapath *od; >>> + const struct lr_nat_record *lrnat_rec; >>> + >>> + /* Load Balancer vIPs relevant for this datapath. */ >>> + struct ovn_lb_ip_set *lb_ips; >>> + >>> + /* sset of vips which are also part of lr nats. */ >>> + struct sset vip_nats; >>> +}; >>> + >>> +struct lr_lb_nat_data_table { >>> + struct hmap entries; >>> + >>> + /* The array index of each element in 'entries'. */ >>> + struct lr_lb_nat_data_record **array; >>> +}; >>> + >>> +#define LR_LB_NAT_DATA_TABLE_FOR_EACH(LR_LB_NAT_REC, TABLE) \ >>> + HMAP_FOR_EACH (LR_LB_NAT_REC, key_node, &(TABLE)->entries) >>> + >>> +struct lr_lb_nat_data_tracked_data { >>> + /* Created or updated logical router with LB data. */ >>> + struct hmapx crupdated; /* Stores 'struct lr_lb_nat_data_record'. */ >>> + >>> + /* Deleted logical router with LB data. */ >>> + struct hmapx deleted; /* Stores 'struct lr_lb_nat_data_record'. */ >>> +}; >>> + >>> +struct ed_type_lr_lb_nat_data { >>> + struct lr_lb_nat_data_table lr_lbnats; >>> + >>> + bool tracked; >>> + struct lr_lb_nat_data_tracked_data tracked_data; >> >> Same comment about 'tracked' as in the previous commit, we can probably >> remove it. >> >> Which brings me to the following question, we don't really use >> lr_lb_nat_data_tracked_data->deleted anywhere; we never add anything to >> it. Is it on purpose, should we just delete it? Or is it a bug? >> >> Thanks, >> Dumitru >> >>> +}; >>> + >>> +struct lr_lb_nat_data_input { >>> + const struct ovn_datapaths *lr_datapaths; >>> + const struct hmap *lb_datapaths_map; >>> + const struct hmap *lbgrp_datapaths_map; >>> + const struct lr_nat_table *lr_nats; >>> +}; >>> + >>> +void *en_lr_lb_nat_data_init(struct engine_node *, struct engine_arg *); >>> +void en_lr_lb_nat_data_cleanup(void *data); >>> +void en_lr_lb_nat_data_clear_tracked_data(void *data); >>> +void en_lr_lb_nat_data_run(struct engine_node *, void *data); >>> + >>> +bool lr_lb_nat_data_northd_handler(struct engine_node *, void *data); >>> +bool lr_lb_nat_data_lr_nat_handler(struct engine_node *, void *data); >>> +bool lr_lb_nat_data_lb_data_handler(struct engine_node *, void *data); >>> + >>> +const struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index( >>> + const struct lr_lb_nat_data_table *, size_t od_index); >>> + >>> +#endif /* EN_LR_LB_NAT_DATA_H */ >>> \ No newline at end of file > > No newline at end of file. > >>> diff --git a/northd/en-lr-nat.h b/northd/en-lr-nat.h >>> index 01a16a21aa..2e3f285d12 100644 >>> --- a/northd/en-lr-nat.h >>> +++ b/northd/en-lr-nat.h >>> @@ -89,6 +89,9 @@ struct lr_nat_table { >>> const struct lr_nat_record * lr_nat_table_find_by_index( >>> const struct lr_nat_table *, size_t od_index); >>> >>> +#define LR_NAT_TABLE_FOR_EACH(LR_NAT_REC, TABLE) \ >>> + HMAP_FOR_EACH (LR_NAT_REC, key_node, &(TABLE)->entries) >>> + >>> /* Incremental processing implementation. */ >>> struct lr_nat_input { >>> /* Northbound table references. */ >>> diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c >>> index 10ade620e7..7c22949f74 100644 >>> --- a/northd/en-sync-sb.c >>> +++ b/northd/en-sync-sb.c >>> @@ -22,6 +22,7 @@ >>> #include "openvswitch/util.h" >>> >>> #include "en-lr-nat.h" >>> +#include "en-lr-lb-nat-data.h" >>> #include "en-sync-sb.h" >>> #include "lib/inc-proc-eng.h" >>> #include "lib/lb.h" >>> @@ -41,7 +42,7 @@ static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, >>> const struct nbrec_address_set_table *, >>> const struct nbrec_port_group_table *, >>> const struct sbrec_address_set_table *, >>> - const struct ovn_datapaths *lr_datapaths); >>> + const struct lr_lb_nat_data_table *); >>> static const struct sbrec_address_set *sb_address_set_lookup_by_name( >>> struct ovsdb_idl_index *, const char *name); >>> static void update_sb_addr_set(struct sorted_array *, >>> @@ -87,11 +88,11 @@ en_sync_to_sb_addr_set_run(struct engine_node *node, void *data OVS_UNUSED) >>> EN_OVSDB_GET(engine_get_input("SB_address_set", node)); >>> >>> const struct engine_context *eng_ctx = engine_get_context(); >>> - struct northd_data *northd_data = engine_get_input_data("northd", node); >>> - >>> + const struct ed_type_lr_lb_nat_data *lr_lb_nat_data = >>> + engine_get_input_data("lr_lb_nat_data", node); >>> sync_addr_sets(eng_ctx->ovnsb_idl_txn, nb_address_set_table, >>> nb_port_group_table, sb_address_set_table, >>> - &northd_data->lr_datapaths); >>> + &lr_lb_nat_data->lr_lbnats); >>> >>> engine_set_node_state(node, EN_UPDATED); >>> } >>> @@ -288,10 +289,12 @@ en_sync_to_sb_pb_run(struct engine_node *node, void *data OVS_UNUSED) >>> { >>> const struct engine_context *eng_ctx = engine_get_context(); >>> struct northd_data *northd_data = engine_get_input_data("northd", node); >>> - struct ed_type_lr_nat_data *lr_nat_data = >>> - engine_get_input_data("lr_nat", node); >>> + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = >>> + engine_get_input_data("lr_lb_nat_data", node); >>> + >>> sync_pbs(eng_ctx->ovnsb_idl_txn, &northd_data->ls_ports, >>> - &northd_data->lr_ports, &lr_nat_data->lr_nats); >>> + &northd_data->lr_ports, >>> + &lr_lb_nat_data->lr_lbnats); >>> engine_set_node_state(node, EN_UPDATED); >>> } >>> >>> @@ -316,11 +319,12 @@ sync_to_sb_pb_northd_handler(struct engine_node *node, void *data OVS_UNUSED) >>> return false; >>> } >>> >>> - struct ed_type_lr_nat_data *lr_nat_data = >>> - engine_get_input_data("lr_nat", node); >>> + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = >>> + engine_get_input_data("lr_lb_nat_data", node); >>> >>> if (!sync_pbs_for_northd_changed_ovn_ports( >>> - &nd->trk_northd_changes.trk_ovn_ports, &lr_nat_data->lr_nats)) { >>> + &nd->trk_northd_changes.trk_ovn_ports, >>> + &lr_lb_nat_data->lr_lbnats)) { >>> return false; >>> } >>> >>> @@ -366,7 +370,7 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, >>> const struct nbrec_address_set_table *nb_address_set_table, >>> const struct nbrec_port_group_table *nb_port_group_table, >>> const struct sbrec_address_set_table *sb_address_set_table, >>> - const struct ovn_datapaths *lr_datapaths) >>> + const struct lr_lb_nat_data_table *lr_lbnats) >>> { >>> struct shash sb_address_sets = SHASH_INITIALIZER(&sb_address_sets); >>> >>> @@ -410,16 +414,14 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, >>> } >>> >>> /* Sync router load balancer VIP generated address sets. */ >>> - struct ovn_datapath *od; >>> - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { >>> - ovs_assert(od->nbr); >>> - >>> - if (sset_count(&od->lb_ips->ips_v4_reachable)) { >>> - char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key, >>> - AF_INET); >>> + const struct lr_lb_nat_data_record *lrlb_rec; >>> + LR_LB_NAT_DATA_TABLE_FOR_EACH (lrlb_rec, lr_lbnats) { >>> + if (sset_count(&lrlb_rec->lb_ips->ips_v4_reachable)) { >>> + char *ipv4_addrs_name = >>> + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET); >>> >>> struct sorted_array ipv4_addrs_sorted = >>> - sorted_array_from_sset(&od->lb_ips->ips_v4_reachable); >>> + sorted_array_from_sset(&lrlb_rec->lb_ips->ips_v4_reachable); >>> >>> sync_addr_set(ovnsb_txn, ipv4_addrs_name, >>> &ipv4_addrs_sorted, &sb_address_sets); >>> @@ -427,11 +429,11 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, >>> free(ipv4_addrs_name); >>> } >>> >>> - if (sset_count(&od->lb_ips->ips_v6_reachable)) { >>> - char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key, >>> - AF_INET6); >>> - struct sorted_array ipv6_addrs_sorted = >>> - sorted_array_from_sset(&od->lb_ips->ips_v6_reachable); >>> + if (sset_count(&lrlb_rec->lb_ips->ips_v6_reachable)) { >>> + char *ipv6_addrs_name = >>> + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET6); >>> + struct sorted_array ipv6_addrs_sorted = sorted_array_from_sset( >>> + &lrlb_rec->lb_ips->ips_v6_reachable); >>> >>> sync_addr_set(ovnsb_txn, ipv6_addrs_name, >>> &ipv6_addrs_sorted, &sb_address_sets); >>> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c >>> index 2bd66b8808..369a151fa3 100644 >>> --- a/northd/inc-proc-northd.c >>> +++ b/northd/inc-proc-northd.c >>> @@ -31,6 +31,7 @@ >>> #include "openvswitch/vlog.h" >>> #include "inc-proc-northd.h" >>> #include "en-lb-data.h" >>> +#include "en-lr-lb-nat-data.h" >>> #include "en-lr-nat.h" >>> #include "en-northd.h" >>> #include "en-lflow.h" >>> @@ -148,6 +149,7 @@ static ENGINE_NODE(sync_to_sb_lb, "sync_to_sb_lb"); >>> static ENGINE_NODE(sync_to_sb_pb, "sync_to_sb_pb"); >>> static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data"); >>> static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_nat, "lr_nat"); >>> +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_lb_nat_data, "lr_lb_nat_data"); >>> >>> void inc_proc_northd_init(struct ovsdb_idl_loop *nb, >>> struct ovsdb_idl_loop *sb) >>> @@ -196,6 +198,13 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, >>> engine_add_input(&en_lr_nat, &en_nb_logical_router, >>> lr_nat_logical_router_handler); >>> >>> + engine_add_input(&en_lr_lb_nat_data, &en_northd, >>> + lr_lb_nat_data_northd_handler); >>> + engine_add_input(&en_lr_lb_nat_data, &en_lr_nat, >>> + lr_lb_nat_data_lr_nat_handler); >>> + engine_add_input(&en_lr_lb_nat_data, &en_lb_data, >>> + lr_lb_nat_data_lb_data_handler); >>> + >>> engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL); >>> engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL); >>> engine_add_input(&en_mac_binding_aging, &en_northd, NULL); >>> @@ -220,12 +229,14 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, >>> engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); >>> engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); >>> engine_add_input(&en_lflow, &en_lr_nat, NULL); >>> + engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); >>> >>> engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, >>> sync_to_sb_addr_set_nb_address_set_handler); >>> engine_add_input(&en_sync_to_sb_addr_set, &en_nb_port_group, >>> sync_to_sb_addr_set_nb_port_group_handler); >>> engine_add_input(&en_sync_to_sb_addr_set, &en_northd, NULL); >>> + engine_add_input(&en_sync_to_sb_addr_set, &en_lr_lb_nat_data, NULL); >>> engine_add_input(&en_sync_to_sb_addr_set, &en_sb_address_set, NULL); >>> >>> engine_add_input(&en_port_group, &en_nb_port_group, >>> @@ -243,7 +254,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, >>> >>> engine_add_input(&en_sync_to_sb_pb, &en_northd, >>> sync_to_sb_pb_northd_handler); >>> - engine_add_input(&en_sync_to_sb_pb, &en_lr_nat, NULL); >>> + engine_add_input(&en_sync_to_sb_pb, &en_lr_lb_nat_data, NULL); >>> >>> /* en_sync_to_sb engine node syncs the SB database tables from >>> * the NB database tables. >>> diff --git a/northd/northd.c b/northd/northd.c >>> index 44c9c3d729..24df14c0de 100644 >>> --- a/northd/northd.c >>> +++ b/northd/northd.c >>> @@ -44,6 +44,7 @@ >>> #include "northd.h" >>> #include "en-lb-data.h" >>> #include "en-lr-nat.h" >>> +#include "en-lr-lb-nat-data.h" >>> #include "lib/ovn-parallel-hmap.h" >>> #include "ovn/actions.h" >>> #include "ovn/features.h" >>> @@ -617,13 +618,6 @@ init_lb_for_datapath(struct ovn_datapath *od) >>> } >>> } >>> >>> -static void >>> -destroy_lb_for_datapath(struct ovn_datapath *od) >>> -{ >>> - ovn_lb_ip_set_destroy(od->lb_ips); >>> - od->lb_ips = NULL; >>> -} >>> - >>> /* A group of logical router datapaths which are connected - either >>> * directly or indirectly. >>> * Each logical router can belong to only one group. */ >>> @@ -676,7 +670,6 @@ ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od) >>> destroy_ipam_info(&od->ipam_info); >>> free(od->router_ports); >>> free(od->ls_peers); >>> - destroy_lb_for_datapath(od); >>> free(od->localnet_ports); >>> free(od->l3dgw_ports); >>> destroy_mcast_info_for_datapath(od); >>> @@ -1311,121 +1304,6 @@ struct lflow_ref_node { >>> struct ovn_lflow *lflow; >>> }; >>> >>> -/* A logical switch port or logical router port. >>> - * >>> - * In steady state, an ovn_port points to a northbound Logical_Switch_Port >>> - * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a >>> - * southbound Port_Binding record (via 'sb'). As the state of the system >>> - * changes, join_logical_ports() may determine that there is a new LSP or LRP >>> - * that has no corresponding Port_Binding record (in which case build_ports()) >>> - * will create the missing Port_Binding) or that a Port_Binding record exists >>> - * that has no coresponding LSP (in which case build_ports() will delete the >>> - * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port >>> - * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. >>> - * >>> - * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but >>> - * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). >>> - */ >>> -struct ovn_port { >>> - /* Port name aka key. >>> - * >>> - * This is ordinarily the same as nbsp->name or nbrp->name and >>> - * sb->logical_port. (A distributed gateway port creates a "derived" >>> - * ovn_port with key "cr-%s" % nbrp->name.) */ >>> - struct hmap_node key_node; /* Index on 'key'. */ >>> - char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ >>> - char *json_key; /* 'key', quoted for use in JSON. */ >>> - >>> - const struct sbrec_port_binding *sb; /* May be NULL. */ >>> - >>> - uint32_t tunnel_key; >>> - >>> - /* Logical switch port data. */ >>> - const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ >>> - >>> - struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ >>> - unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ >>> - unsigned int n_lsp_non_router_addrs; /* Number of elements from the >>> - * beginning of 'lsp_addrs' extracted >>> - * directly from LSP 'addresses'. */ >>> - >>> - struct lport_addresses *ps_addrs; /* Port security addresses. */ >>> - unsigned int n_ps_addrs; >>> - >>> - bool lsp_can_be_inc_processed; /* If it can be incrementally processed when >>> - the port changes. */ >>> - >>> - /* Logical router port data. */ >>> - const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ >>> - >>> - struct lport_addresses lrp_networks; >>> - >>> - struct ovn_port_routable_addresses routables; >>> - >>> - /* Logical port multicast data. */ >>> - struct mcast_port_info mcast_info; >>> - >>> - /* At most one of l3dgw_port and cr_port can be not NULL. */ >>> - >>> - /* This is set to a distributed gateway port if and only if this ovn_port >>> - * is "derived" from it. Otherwise this is set to NULL. The derived >>> - * ovn_port represents the instance of distributed gateway port on the >>> - * gateway chassis.*/ >>> - struct ovn_port *l3dgw_port; >>> - >>> - /* This is set to the "derived" chassis-redirect port of this port if and >>> - * only if this port is a distributed gateway port. Otherwise this is set >>> - * to NULL. */ >>> - struct ovn_port *cr_port; >>> - >>> - bool has_unknown; /* If the addresses have 'unknown' defined. */ >>> - >>> - bool has_bfd; >>> - >>> - /* The port's peer: >>> - * >>> - * - A switch port S of type "router" has a router port R as a peer, >>> - * and R in turn has S has its peer. >>> - * >>> - * - Two connected logical router ports have each other as peer. >>> - * >>> - * - Other kinds of ports have no peer. */ >>> - struct ovn_port *peer; >>> - >>> - struct ovn_datapath *od; >>> - >>> - struct ovs_list list; /* In list of similar records. */ >>> - >>> - struct hmap_node dp_node; /* Node in od->ports. */ >>> - >>> - struct lport_addresses proxy_arp_addrs; >>> - >>> - /* Temporarily used for traversing a list (or hmap) of ports. */ >>> - bool visited; >>> - >>> - /* List of struct lflow_ref_node that points to the lflows generated by >>> - * this ovn_port. >>> - * >>> - * This data is initialized and destroyed by the en_northd node, but >>> - * populated and used only by the en_lflow node. Ideally this data should >>> - * be maintained as part of en_lflow's data (struct lflow_data): a hash >>> - * index from ovn_port key to lflows. However, it would be less efficient >>> - * and more complex: >>> - * >>> - * 1. It would require an extra search (using the index) to find the >>> - * lflows. >>> - * >>> - * 2. Building the index needs to be thread-safe, using either a global >>> - * lock which is obviously less efficient, or hash-based lock array which >>> - * is more complex. >>> - * >>> - * Adding the list here is more straightforward. The drawback is that we >>> - * need to keep in mind that this data belongs to en_lflow node, so never >>> - * access it from any other nodes. >>> - */ >>> - struct ovs_list lflows; >>> -}; >>> - >>> static bool lsp_can_be_inc_processed(const struct nbrec_logical_switch_port *); >>> >>> static bool >>> @@ -1450,16 +1328,21 @@ destroy_routable_addresses(struct ovn_port_routable_addresses *ra) >>> } >>> >>> static char **get_nat_addresses(const struct ovn_port *op, size_t *n, >>> - bool routable_only, bool include_lb_ips); >>> + bool routable_only, bool include_lb_ips, >>> + const struct lr_lb_nat_data_record *); >>> >>> -static void >>> -assign_routable_addresses(struct ovn_port *op) >>> +static struct ovn_port_routable_addresses >>> +get_op_routable_addresses(struct ovn_port *op, >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec) >>> { >>> size_t n; >>> - char **nats = get_nat_addresses(op, &n, true, true); >>> + char **nats = get_nat_addresses(op, &n, true, true, lr_lbnat_rec); >>> >>> if (!nats) { >>> - return; >>> + return (struct ovn_port_routable_addresses) { >>> + .laddrs = NULL, >>> + .n_addrs = 0, >>> + }; >>> } >>> >>> struct lport_addresses *laddrs = xcalloc(n, sizeof(*laddrs)); >>> @@ -1475,9 +1358,15 @@ assign_routable_addresses(struct ovn_port *op) >>> } >>> free(nats); >>> >>> - /* Everything seems to have worked out */ >>> - op->routables.laddrs = laddrs; >>> - op->routables.n_addrs = n_addrs; >>> + if (!n_addrs) { >>> + free(laddrs); >>> + laddrs = NULL; >>> + } >>> + >>> + return (struct ovn_port_routable_addresses) { >>> + .laddrs = laddrs, >>> + .n_addrs = n_addrs, >>> + }; >>> } >>> >>> >>> @@ -1537,8 +1426,6 @@ ovn_port_destroy_orphan(struct ovn_port *port) >>> } >>> free(port->ps_addrs); >>> >>> - destroy_routable_addresses(&port->routables); >>> - >>> destroy_lport_addresses(&port->lrp_networks); >>> destroy_lport_addresses(&port->proxy_arp_addrs); >>> free(port->json_key); >>> @@ -2580,9 +2467,7 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, >>> sizeof *od->l3dgw_ports); >>> } >>> od->l3dgw_ports[od->n_l3dgw_ports++] = op; >>> - >>> - assign_routable_addresses(op); >>> - } >>> + } >>> } >>> } >>> >>> @@ -2679,7 +2564,8 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, >>> * and must free the returned array when it is no longer needed. */ >>> static char ** >>> get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, >>> - bool include_lb_ips) >>> + bool include_lb_ips, >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec) >>> { >>> size_t n_nats = 0; >>> struct eth_addr mac; >>> @@ -2764,23 +2650,25 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, >>> } >>> } >>> >>> - if (include_lb_ips) { >>> + if (include_lb_ips && lr_lbnat_rec) { >>> const char *ip_address; >>> if (routable_only) { >>> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4_routable) { >>> + SSET_FOR_EACH (ip_address, >>> + &lr_lbnat_rec->lb_ips->ips_v4_routable) { >>> ds_put_format(&c_addresses, " %s", ip_address); >>> central_ip_address = true; >>> } >>> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6_routable) { >>> + SSET_FOR_EACH (ip_address, >>> + &lr_lbnat_rec->lb_ips->ips_v6_routable) { >>> ds_put_format(&c_addresses, " %s", ip_address); >>> central_ip_address = true; >>> } >>> } else { >>> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4) { >>> + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v4) { >>> ds_put_format(&c_addresses, " %s", ip_address); >>> central_ip_address = true; >>> } >>> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6) { >>> + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v6) { >>> ds_put_format(&c_addresses, " %s", ip_address); >>> central_ip_address = true; >>> } >>> @@ -3851,21 +3739,8 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, >>> HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { >>> ovs_assert(od->nbr); >>> >>> - /* Checking load balancer groups first, starting from the largest one, >>> - * to more efficiently copy IP sets. */ >>> - size_t largest_group = 0; >>> - >>> - for (size_t i = 1; i < od->nbr->n_load_balancer_group; i++) { >>> - if (od->nbr->load_balancer_group[i]->n_load_balancer > >>> - od->nbr->load_balancer_group[largest_group]->n_load_balancer) { >>> - largest_group = i; >>> - } >>> - } >>> - >>> for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { >>> - size_t idx = (i + largest_group) % od->nbr->n_load_balancer_group; >>> - >>> - nbrec_lb_group = od->nbr->load_balancer_group[idx]; >>> + nbrec_lb_group = od->nbr->load_balancer_group[i]; >>> const struct uuid *lb_group_uuid = &nbrec_lb_group->header_.uuid; >>> >>> lb_group_dps = >>> @@ -3873,20 +3748,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, >>> lb_group_uuid); >>> ovs_assert(lb_group_dps); >>> ovn_lb_group_datapaths_add_lr(lb_group_dps, od); >>> - >>> - if (!od->lb_ips) { >>> - od->lb_ips = >>> - ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); >>> - } else { >>> - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { >>> - build_lrouter_lb_ips(od->lb_ips, >>> - lb_group_dps->lb_group->lbs[j]); >>> - } >>> - } >>> - } >>> - >>> - if (!od->lb_ips) { >>> - od->lb_ips = ovn_lb_ip_set_create(); >>> } >>> >>> for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { >>> @@ -3895,7 +3756,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, >>> lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); >>> ovs_assert(lb_dps); >>> ovn_lb_datapaths_add_lr(lb_dps, 1, &od); >>> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); >>> } >>> } >>> >>> @@ -3949,102 +3809,6 @@ build_lb_svcs( >>> } >>> } >>> >>> -static bool lrouter_port_ipv4_reachable(const struct ovn_port *op, >>> - ovs_be32 addr); >>> -static bool lrouter_port_ipv6_reachable(const struct ovn_port *op, >>> - const struct in6_addr *addr); >>> - >>> -static void >>> -add_neigh_ips_to_lrouter(struct ovn_datapath *od, >>> - enum lb_neighbor_responder_mode neigh_mode, >>> - const struct sset *lb_ips_v4, >>> - const struct sset *lb_ips_v6) >>> -{ >>> - /* If configured to not reply to any neighbor requests for all VIPs >>> - * return early. >>> - */ >>> - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { >>> - return; >>> - } >>> - >>> - const char *ip_address; >>> - >>> - /* If configured to reply to neighbor requests for all VIPs force them >>> - * all to be considered "reachable". >>> - */ >>> - if (neigh_mode == LB_NEIGH_RESPOND_ALL) { >>> - SSET_FOR_EACH (ip_address, lb_ips_v4) { >>> - sset_add(&od->lb_ips->ips_v4_reachable, ip_address); >>> - } >>> - SSET_FOR_EACH (ip_address, lb_ips_v6) { >>> - sset_add(&od->lb_ips->ips_v6_reachable, ip_address); >>> - } >>> - >>> - return; >>> - } >>> - >>> - /* Otherwise, a VIP is reachable if there's at least one router >>> - * subnet that includes it. >>> - */ >>> - ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); >>> - >>> - SSET_FOR_EACH (ip_address, lb_ips_v4) { >>> - struct ovn_port *op; >>> - ovs_be32 vip_ip4; >>> - if (ip_parse(ip_address, &vip_ip4)) { >>> - HMAP_FOR_EACH (op, dp_node, &od->ports) { >>> - if (lrouter_port_ipv4_reachable(op, vip_ip4)) { >>> - sset_add(&od->lb_ips->ips_v4_reachable, >>> - ip_address); >>> - break; >>> - } >>> - } >>> - } >>> - } >>> - >>> - SSET_FOR_EACH (ip_address, lb_ips_v6) { >>> - struct ovn_port *op; >>> - struct in6_addr vip; >>> - if (ipv6_parse(ip_address, &vip)) { >>> - HMAP_FOR_EACH (op, dp_node, &od->ports) { >>> - if (lrouter_port_ipv6_reachable(op, &vip)) { >>> - sset_add(&od->lb_ips->ips_v6_reachable, >>> - ip_address); >>> - break; >>> - } >>> - } >>> - } >>> - } >>> -} >>> - >>> -static void >>> -remove_lrouter_lb_reachable_ips(struct ovn_datapath *od, >>> - enum lb_neighbor_responder_mode neigh_mode, >>> - const struct sset *lb_ips_v4, >>> - const struct sset *lb_ips_v6) >>> -{ >>> - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { >>> - return; >>> - } >>> - >>> - const char *ip_address; >>> - SSET_FOR_EACH (ip_address, lb_ips_v4) { >>> - sset_find_and_delete(&od->lb_ips->ips_v4_reachable, ip_address); >>> - } >>> - SSET_FOR_EACH (ip_address, lb_ips_v6) { >>> - sset_find_and_delete(&od->lb_ips->ips_v6_reachable, ip_address); >>> - } >>> -} >>> - >>> -static void >>> -build_lrouter_lb_reachable_ips(struct ovn_datapath *od, >>> - const struct ovn_northd_lb *lb) >>> -{ >>> - add_neigh_ips_to_lrouter(od, lb->neigh_mode, &lb->ips_v4, >>> - &lb->ips_v6); >>> -} >>> - >>> - >>> static void >>> build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) >>> { >>> @@ -4066,43 +3830,6 @@ build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) >>> } >>> } >>> >>> -static void >>> -build_lrouter_lbs_reachable_ips(struct ovn_datapaths *lr_datapaths, >>> - struct hmap *lb_dps_map, >>> - struct hmap *lb_group_dps_map) >>> -{ >>> - struct ovn_datapath *od; >>> - >>> - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { >>> - if (!od->nbr) { >>> - continue; >>> - } >>> - >>> - for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { >>> - struct ovn_lb_datapaths *lb_dps = >>> - ovn_lb_datapaths_find(lb_dps_map, >>> - &od->nbr->load_balancer[i]->header_.uuid); >>> - ovs_assert(lb_dps); >>> - build_lrouter_lb_reachable_ips(od, lb_dps->lb); >>> - } >>> - >>> - for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { >>> - const struct nbrec_load_balancer_group *nbrec_lb_group = >>> - od->nbr->load_balancer_group[i]; >>> - struct ovn_lb_group_datapaths *lb_group_dps; >>> - >>> - lb_group_dps = >>> - ovn_lb_group_datapaths_find(lb_group_dps_map, >>> - &nbrec_lb_group->header_.uuid); >>> - ovs_assert(lb_group_dps); >>> - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { >>> - build_lrouter_lb_reachable_ips(od, >>> - lb_group_dps->lb_group->lbs[j]); >>> - } >>> - } >>> - } >>> -} >>> - >>> static void >>> build_lswitch_lbs_from_lrouter(struct ovn_datapaths *lr_datapaths, >>> struct hmap *lb_dps_map, >>> @@ -4166,8 +3893,6 @@ build_lb_port_related_data( >>> struct hmap *svc_monitor_map) >>> { >>> build_lrouter_lbs_check(lr_datapaths); >>> - build_lrouter_lbs_reachable_ips(lr_datapaths, lb_dps_map, >>> - lb_group_dps_map); >>> build_lb_svcs(ovnsb_txn, sbrec_service_monitor_table, ls_ports, lb_dps_map, >>> svc_monitor_lsps, svc_monitor_map); >>> build_lswitch_lbs_from_lrouter(lr_datapaths, lb_dps_map, lb_group_dps_map); >>> @@ -4533,7 +4258,8 @@ check_sb_lb_duplicates(const struct sbrec_load_balancer_table *table) >>> * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it >>> * only syncs the nat column of port binding corresponding to the 'op->nbsp' */ >>> static void >>> -sync_pb_for_lsp(struct ovn_port *op) >>> +sync_pb_for_lsp(struct ovn_port *op, >>> + const struct lr_lb_nat_data_table *lr_lbnats) >>> { >>> ovs_assert(op->nbsp); >>> >>> @@ -4552,10 +4278,17 @@ sync_pb_for_lsp(struct ovn_port *op) >>> if (nat_addresses && !strcmp(nat_addresses, "router")) { >>> if (op->peer && op->peer->od >>> && (chassis || op->peer->od->n_l3dgw_ports)) { >>> - bool exclude_lb_vips = smap_get_bool(&op->nbsp->options, >>> + bool include_lb_vips = !smap_get_bool(&op->nbsp->options, >>> "exclude-lb-vips-from-garp", false); >>> + >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; >>> + >>> + if (include_lb_vips) { >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index( >>> + lr_lbnats, op->peer->od->index); >>> + } >>> nats = get_nat_addresses(op->peer, &n_nats, false, >>> - !exclude_lb_vips); >>> + include_lb_vips, lr_lbnat_rec); >>> } >>> } else if (nat_addresses && (chassis || l3dgw_ports)) { >>> struct lport_addresses laddrs; >>> @@ -4662,7 +4395,8 @@ sync_pb_for_lsp(struct ovn_port *op) >>> * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it >>> * only sets the port binding options column for the router ports */ >>> static void >>> -sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) >>> +sync_pb_for_lrp(struct ovn_port *op, >>> + const struct lr_lb_nat_data_table *lr_lbnats) >>> { >>> ovs_assert(op->nbrp); >>> >>> @@ -4671,14 +4405,14 @@ sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) >>> >>> const char *chassis_name = smap_get(&op->od->nbr->options, "chassis"); >>> if (is_cr_port(op)) { >>> - const struct lr_nat_record *lrnat_rec = >>> - lr_nat_table_find_by_index(lr_nats, op->od->index); >>> - ovs_assert(lrnat_rec); >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec = >>> + lr_lb_nat_data_table_find_by_index(lr_lbnats, op->od->index); >>> + ovs_assert(lr_lbnat_rec); >>> >>> smap_add(&new, "distributed-port", op->nbrp->name); >>> >>> bool always_redirect = >>> - !lrnat_rec->has_distributed_nat && >>> + !lr_lbnat_rec->lrnat_rec->has_distributed_nat && >>> !l3dgw_port_has_associated_vtep_lports(op->l3dgw_port); >>> >>> const char *redirect_type = smap_get(&op->nbrp->options, >>> @@ -4729,17 +4463,18 @@ static void ovn_update_ipv6_opt_for_op(struct ovn_port *op); >>> * the logical switch ports. */ >>> void >>> sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, >>> - struct hmap *lr_ports, const struct lr_nat_table *lr_nats) >>> + struct hmap *lr_ports, >>> + const struct lr_lb_nat_data_table *lr_lbnats) >>> { >>> ovs_assert(ovnsb_idl_txn); >>> >>> struct ovn_port *op; >>> HMAP_FOR_EACH (op, key_node, ls_ports) { >>> - sync_pb_for_lsp(op); >>> + sync_pb_for_lsp(op, lr_lbnats); >>> } >>> >>> HMAP_FOR_EACH (op, key_node, lr_ports) { >>> - sync_pb_for_lrp(op, lr_nats); >>> + sync_pb_for_lrp(op, lr_lbnats); >>> } >>> >>> ovn_update_ipv6_options(lr_ports); >>> @@ -4748,17 +4483,18 @@ sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, >>> /* Sync the SB Port bindings for the added and updated logical switch ports >>> * of the tracked northd engine data. */ >>> bool >>> -sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, >>> - const struct lr_nat_table *lr_nats) >>> +sync_pbs_for_northd_changed_ovn_ports( >>> + struct tracked_ovn_ports *trk_ovn_ports, >>> + const struct lr_lb_nat_data_table *lr_lbnats) >>> { >>> struct hmapx_node *hmapx_node; >>> struct ovn_port *op; >>> HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->created) { >>> op = hmapx_node->data; >>> if (op->nbsp) { >>> - sync_pb_for_lsp(op); >>> + sync_pb_for_lsp(op, lr_lbnats); >>> } else { >>> - sync_pb_for_lrp(op, lr_nats); >>> + sync_pb_for_lrp(op, lr_lbnats); >>> ovn_update_ipv6_opt_for_op(op); >>> } >>> } >>> @@ -4766,9 +4502,9 @@ sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, >>> HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->updated) { >>> op = hmapx_node->data; >>> if (op->nbsp) { >>> - sync_pb_for_lsp(op); >>> + sync_pb_for_lsp(op, lr_lbnats); >>> } else { >>> - sync_pb_for_lrp(op, lr_nats); >>> + sync_pb_for_lrp(op, lr_lbnats); >>> ovn_update_ipv6_opt_for_op(op); >>> } >>> } >>> @@ -5475,20 +5211,24 @@ fail: >>> } >>> >>> /* Returns true if the logical router has changes which can be >>> - * incrementally handled. >>> + * incrementally handled or the changes can be ignored. >>> * Presently supports i-p for the below changes: >>> * - load balancers and load balancer groups. >>> + * >>> + * Presently below changes are ignored: >>> + * - router NAT changes - as the engine node lr-nat handles it. >>> */ >>> static bool >>> -lr_changes_can_be_handled( >>> +lr_changes_can_be_handled_or_ignored( >>> const struct nbrec_logical_router *lr) >>> { >>> /* Check if the columns are changed in this row. */ >>> enum nbrec_logical_router_column_id col; >>> for (col = 0; col < NBREC_LOGICAL_ROUTER_N_COLUMNS; col++) { >>> if (nbrec_logical_router_is_updated(lr, col)) { >>> - if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER || >>> - col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP) { >>> + if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER >>> + || col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP >>> + || col == NBREC_LOGICAL_ROUTER_COL_NAT) { >>> continue; >>> } >>> return false; >>> @@ -5507,12 +5247,6 @@ lr_changes_can_be_handled( >>> OVSDB_IDL_CHANGE_MODIFY) > 0) { >>> return false; >>> } >>> - for (size_t i = 0; i < lr->n_nat; i++) { >>> - if (nbrec_nat_row_get_seqno(lr->nat[i], >>> - OVSDB_IDL_CHANGE_MODIFY) > 0) { >>> - return false; >>> - } >>> - } >>> for (size_t i = 0; i < lr->n_policies; i++) { >>> if (nbrec_logical_router_policy_row_get_seqno(lr->policies[i], >>> OVSDB_IDL_CHANGE_MODIFY) > 0) { >>> @@ -5528,14 +5262,15 @@ lr_changes_can_be_handled( >>> return true; >>> } >>> >>> -/* Return true if changes are handled incrementally, false otherwise. >>> +/* Return true if changes are handled incrementally or can be safely >>> + * ignored (because those changes are handled by other engine nodes), >>> + * false otherwise. >>> * When there are any changes, try to track what's exactly changed and set >>> * northd_data->change_tracked accordingly: change tracked - true, otherwise, >>> * false. >>> * Note: Changes to load balancer and load balancer groups associated with >>> * the logical routers are handled separately in the lb_data change >>> - * handlers (northd_handle_lb_data_changes_pre_od and >>> - * northd_handle_lb_data_changes_post_od). >>> + * handler (northd_handle_lb_data_changes). >>> * */ >>> bool >>> northd_handle_lr_changes(const struct northd_input *ni, >>> @@ -5550,9 +5285,11 @@ northd_handle_lr_changes(const struct northd_input *ni, >>> goto fail; >>> } >>> >>> - /* Presently only able to handle load balancer and >>> - * load balancer group changes. */ >>> - if (!lr_changes_can_be_handled(changed_lr)) { >>> + /* Presently >>> + * - only able to handle load balancer and load balancer group >>> + changes. >>> + * - and ignore NAT changes */ >>> + if (!lr_changes_can_be_handled_or_ignored(changed_lr)) { >>> goto fail; >>> } >>> } >>> @@ -5804,10 +5541,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, >>> ovs_assert(lb_dps); >>> ovn_lb_datapaths_add_lr(lb_dps, 1, &od); >>> >>> - /* Add the lb_ips of lb_dps to the od. */ >>> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); >>> - build_lrouter_lb_reachable_ips(od, lb_dps->lb); >>> - >>> /* Add the lb to the northd tracked data. */ >>> hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); >>> } >>> @@ -5826,10 +5559,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, >>> ovs_assert(lb_dps); >>> ovn_lb_datapaths_add_lr(lb_dps, 1, &od); >>> >>> - /* Add the lb_ips of lb_dps to the od. */ >>> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); >>> - build_lrouter_lb_reachable_ips(od, lb_dps->lb); >>> - >>> /* Add the lb to the northd tracked data. */ >>> hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); >>> } >>> @@ -5865,22 +5594,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, >>> /* Re-evaluate 'od->has_lb_vip' */ >>> init_lb_for_datapath(od); >>> >>> - /* Update the od->lb_ips with the deleted and inserted >>> - * vips (if any). */ >>> - remove_ips_from_lb_ip_set(od->lb_ips, lb->routable, >>> - &clb->deleted_vips_v4, >>> - &clb->deleted_vips_v6); >>> - add_ips_to_lb_ip_set(od->lb_ips, lb->routable, >>> - &clb->inserted_vips_v4, >>> - &clb->inserted_vips_v6); >>> - >>> - remove_lrouter_lb_reachable_ips(od, lb->neigh_mode, >>> - &clb->deleted_vips_v4, >>> - &clb->deleted_vips_v6); >>> - add_neigh_ips_to_lrouter(od, lb->neigh_mode, >>> - &clb->inserted_vips_v4, >>> - &clb->inserted_vips_v6); >>> - >>> /* Add the lr datapath to the northd tracked data. */ >>> hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); >>> } >>> @@ -5908,9 +5621,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, >>> /* Re-evaluate 'od->has_lb_vip' */ >>> init_lb_for_datapath(od); >>> >>> - /* Add the lb_ips of lb_dps to the od. */ >>> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); >>> - >>> /* Add the lr datapath to the northd tracked data. */ >>> hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); >>> } >>> @@ -9202,7 +8912,7 @@ arp_nd_ns_match(const char *ips, int addr_family, struct ds *match) >>> /* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the >>> * IPs configured on the router port. >>> */ >>> -static bool >>> +bool >>> lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) >>> { >>> for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { >>> @@ -9218,7 +8928,7 @@ lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) >>> /* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the >>> * IPs configured on the router port. >>> */ >>> -static bool >>> +bool >>> lrouter_port_ipv6_reachable(const struct ovn_port *op, >>> const struct in6_addr *addr) >>> { >>> @@ -9284,6 +8994,7 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, >>> struct ovn_datapath *sw_od, >>> struct ovn_port *sw_op, >>> const struct lr_nat_table *lr_nats, >>> + const struct lr_lb_nat_data_table *lr_lbnats, >>> struct hmap *lflows, >>> const struct ovsdb_idl_row *stage_hint) >>> { >>> @@ -9299,32 +9010,38 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, >>> * router port. >>> * Priority: 80. >>> */ >>> - >>> - const char *ip_addr; >>> - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v4_reachable) { >>> - ovs_be32 ipv4_addr; >>> - >>> - /* Check if the ovn port has a network configured on which we could >>> - * expect ARP requests for the LB VIP. >>> - */ >>> - if (ip_parse(ip_addr, &ipv4_addr) && >>> - lrouter_port_ipv4_reachable(op, ipv4_addr)) { >>> - build_lswitch_rport_arp_req_flow( >>> - ip_addr, AF_INET, sw_op, sw_od, 80, lflows, >>> - stage_hint); >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; >>> + if (op->od->nbr->n_load_balancer || op->od->nbr->n_load_balancer_group) { >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, >>> + op->od->index); >>> + ovs_assert(lr_lbnat_rec); >>> + >>> + const char *ip_addr; >>> + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v4_reachable) { >>> + ovs_be32 ipv4_addr; >>> + >>> + /* Check if the ovn port has a network configured on which we could >>> + * expect ARP requests for the LB VIP. >>> + */ >>> + if (ip_parse(ip_addr, &ipv4_addr) && >>> + lrouter_port_ipv4_reachable(op, ipv4_addr)) { >>> + build_lswitch_rport_arp_req_flow( >>> + ip_addr, AF_INET, sw_op, sw_od, 80, lflows, >>> + stage_hint); >>> + } >>> } >>> - } >>> - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v6_reachable) { >>> - struct in6_addr ipv6_addr; >>> + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v6_reachable) { >>> + struct in6_addr ipv6_addr; >>> >>> - /* Check if the ovn port has a network configured on which we could >>> - * expect NS requests for the LB VIP. >>> - */ >>> - if (ipv6_parse(ip_addr, &ipv6_addr) && >>> - lrouter_port_ipv6_reachable(op, &ipv6_addr)) { >>> - build_lswitch_rport_arp_req_flow( >>> - ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, >>> - stage_hint); >>> + /* Check if the ovn port has a network configured on which we could >>> + * expect NS requests for the LB VIP. >>> + */ >>> + if (ipv6_parse(ip_addr, &ipv6_addr) && >>> + lrouter_port_ipv6_reachable(op, &ipv6_addr)) { >>> + build_lswitch_rport_arp_req_flow( >>> + ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, >>> + stage_hint); >>> + } >>> } >>> } >>> >>> @@ -9374,13 +9091,15 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, >>> * expect ARP requests/NS for the DNAT external_ip. >>> */ >>> if (nat_entry_is_v6(nat_entry)) { >>> - if (!sset_contains(&op->od->lb_ips->ips_v6, nat->external_ip)) { >>> + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, >>> + nat->external_ip)) { >>> build_lswitch_rport_arp_req_flow( >>> nat->external_ip, AF_INET6, sw_op, sw_od, 80, lflows, >>> stage_hint); >>> } >>> } else { >>> - if (!sset_contains(&op->od->lb_ips->ips_v4, nat->external_ip)) { >>> + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, >>> + nat->external_ip)) { >>> build_lswitch_rport_arp_req_flow( >>> nat->external_ip, AF_INET, sw_op, sw_od, 80, lflows, >>> stage_hint); >>> @@ -10441,6 +10160,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, >>> static void >>> build_lswitch_ip_unicast_lookup(struct ovn_port *op, >>> const struct lr_nat_table *lr_nats, >>> + const struct lr_lb_nat_data_table *lr_lbnats, >>> struct hmap *lflows, >>> struct ds *actions, >>> struct ds *match) >>> @@ -10456,7 +10176,8 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op, >>> */ >>> if (lsp_is_router(op->nbsp)) { >>> build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lr_nats, >>> - lflows, &op->nbsp->header_); >>> + lr_lbnats, lflows, >>> + &op->nbsp->header_); >>> } >>> >>> for (size_t i = 0; i < op->nbsp->n_addresses; i++) { >>> @@ -12646,6 +12367,7 @@ build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op, >>> static void >>> build_lrouter_drop_own_dest(struct ovn_port *op, >>> const struct lr_nat_record *lrnat_rec, >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec, >>> enum ovn_stage stage, >>> uint16_t priority, bool drop_snat_ip, >>> struct hmap *lflows) >>> @@ -12658,8 +12380,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, >>> >>> bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, >>> ip); >>> - bool router_ip_in_lb_ips = >>> - !!sset_find(&op->od->lb_ips->ips_v4, ip); >>> + bool router_ip_in_lb_ips = (lr_lbnat_rec && >>> + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v4, >>> + ip)); >>> bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || >>> router_ip_in_lb_ips)); >>> >>> @@ -12688,8 +12411,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, >>> >>> bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, >>> ip); >>> - bool router_ip_in_lb_ips = >>> - !!sset_find(&op->od->lb_ips->ips_v6, ip); >>> + bool router_ip_in_lb_ips = (lr_lbnat_rec && >>> + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v6, >>> + ip)); >>> bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || >>> router_ip_in_lb_ips)); >>> >>> @@ -13401,7 +13125,8 @@ build_ip_routing_flows_for_lrp( >>> */ >>> static void >>> build_ip_routing_flows_for_router_type_lsp( >>> - struct ovn_port *op, const struct hmap *lr_ports, struct hmap *lflows) >>> + struct ovn_port *op, const struct lr_lb_nat_data_table *lr_lbnats, >>> + const struct hmap *lr_ports, struct hmap *lflows) >>> { >>> ovs_assert(op->nbsp); >>> if (!lsp_is_router(op->nbsp)) { >>> @@ -13409,7 +13134,8 @@ build_ip_routing_flows_for_router_type_lsp( >>> } >>> >>> struct ovn_port *peer = ovn_port_get_peer(lr_ports, op); >>> - if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs) { >>> + if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs >>> + || !op->od->n_router_ports) { >>> return; >>> } >>> >>> @@ -13420,19 +13146,29 @@ build_ip_routing_flows_for_router_type_lsp( >>> continue; >>> } >>> >>> - struct ovn_port_routable_addresses *ra = &router_port->routables; >>> - for (size_t j = 0; j < ra->n_addrs; j++) { >>> - struct lport_addresses *laddrs = &ra->laddrs[j]; >>> - for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { >>> - add_route(lflows, peer->od, peer, >>> - peer->lrp_networks.ipv4_addrs[0].addr_s, >>> - laddrs->ipv4_addrs[k].network_s, >>> - laddrs->ipv4_addrs[k].plen, NULL, false, 0, >>> - &peer->nbrp->header_, false, >>> - ROUTE_PRIO_OFFSET_CONNECTED); >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec = >>> + lr_lb_nat_data_table_find_by_index(lr_lbnats, >>> + router_port->od->index); >>> + >>> + if (router_port->nbrp->ha_chassis_group || >>> + router_port->nbrp->n_gateway_chassis) { >>> + struct ovn_port_routable_addresses ra = >>> + get_op_routable_addresses(router_port, lr_lbnat_rec); >>> + for (size_t j = 0; j < ra.n_addrs; j++) { >>> + struct lport_addresses *laddrs = &ra.laddrs[j]; >>> + for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { >>> + add_route(lflows, peer->od, peer, >>> + peer->lrp_networks.ipv4_addrs[0].addr_s, >>> + laddrs->ipv4_addrs[k].network_s, >>> + laddrs->ipv4_addrs[k].plen, NULL, false, 0, >>> + &peer->nbrp->header_, false, >>> + ROUTE_PRIO_OFFSET_CONNECTED); >>> + } >>> } >>> + destroy_routable_addresses(&ra); >>> } >>> } >>> + >>> } >>> >>> static void >>> @@ -13656,33 +13392,36 @@ build_arp_resolve_flows_for_lrouter( >>> >>> static void >>> routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, >>> - struct ovn_port *peer, struct ds *match, >>> - struct ds *actions) >>> + struct ovn_port *peer, >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec, >>> + struct ds *match, struct ds *actions) >>> { >>> - struct ovn_port_routable_addresses *ra = &router_port->routables; >>> - if (!ra->n_addrs) { >>> + struct ovn_port_routable_addresses ra = >>> + get_op_routable_addresses(router_port, lr_lbnat_rec); >>> + if (!ra.n_addrs) { >>> return; >>> } >>> >>> - for (size_t i = 0; i < ra->n_addrs; i++) { >>> + for (size_t i = 0; i < ra.n_addrs; i++) { >>> ds_clear(match); >>> ds_put_format(match, "outport == %s && "REG_NEXT_HOP_IPV4" == {", >>> peer->json_key); >>> bool first = true; >>> - for (size_t j = 0; j < ra->laddrs[i].n_ipv4_addrs; j++) { >>> + for (size_t j = 0; j < ra.laddrs[i].n_ipv4_addrs; j++) { >>> if (!first) { >>> ds_put_cstr(match, ", "); >>> } >>> - ds_put_cstr(match, ra->laddrs[i].ipv4_addrs[j].addr_s); >>> + ds_put_cstr(match, ra.laddrs[i].ipv4_addrs[j].addr_s); >>> first = false; >>> } >>> ds_put_cstr(match, "}"); >>> >>> ds_clear(actions); >>> - ds_put_format(actions, "eth.dst = %s; next;", ra->laddrs[i].ea_s); >>> + ds_put_format(actions, "eth.dst = %s; next;", ra.laddrs[i].ea_s); >>> ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100, >>> ds_cstr(match), ds_cstr(actions)); >>> } >>> + destroy_routable_addresses(&ra); >>> } >>> >>> /* Local router ingress table ARP_RESOLVE: ARP Resolution. >>> @@ -13699,6 +13438,7 @@ routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, >>> static void >>> build_arp_resolve_flows_for_lrp( >>> struct ovn_port *op, const struct lr_nat_record *lrnat_rec, >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec, >>> struct hmap *lflows, struct ds *match, struct ds *actions) >>> { >>> ovs_assert(op->nbrp); >>> @@ -13775,8 +13515,8 @@ build_arp_resolve_flows_for_lrp( >>> * >>> * Priority 2. >>> */ >>> - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_ARP_RESOLVE, 2, >>> - true, lflows); >>> + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, >>> + S_ROUTER_IN_ARP_RESOLVE, 2, true, lflows); >>> } >>> >>> /* This function adds ARP resolve flows related to a LSP. */ >>> @@ -13784,6 +13524,7 @@ static void >>> build_arp_resolve_flows_for_lsp( >>> struct ovn_port *op, struct hmap *lflows, >>> const struct hmap *lr_ports, >>> + const struct lr_lb_nat_data_table *lr_lbnats, >>> struct ds *match, struct ds *actions) >>> { >>> ovs_assert(op->nbsp); >>> @@ -13927,8 +13668,11 @@ build_arp_resolve_flows_for_lsp( >>> >>> if (smap_get(&peer->od->nbr->options, "chassis") >>> || peer->cr_port) { >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec; >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, >>> + router_port->od->index); >>> routable_addresses_to_lflows(lflows, router_port, peer, >>> - match, actions); >>> + lr_lbnat_rec, match, actions); >>> } >>> } >>> } >>> @@ -14648,6 +14392,7 @@ static void >>> build_lrouter_ipv4_ip_input(struct ovn_port *op, >>> struct hmap *lflows, >>> const struct lr_nat_record *lrnat_rec, >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec, >>> struct ds *match, struct ds *actions, >>> const struct shash *meter_groups) >>> { >>> @@ -14772,7 +14517,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, >>> &op->nbrp->header_, lflows); >>> } >>> >>> - if (sset_count(&op->od->lb_ips->ips_v4_reachable)) { >>> + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v4_reachable)) { >>> ds_clear(match); >>> if (is_l3dgw_port(op)) { >>> ds_put_format(match, "is_chassis_resident(%s)", >>> @@ -14788,7 +14533,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, >>> free(lb_ips_v4_as); >>> } >>> >>> - if (sset_count(&op->od->lb_ips->ips_v6_reachable)) { >>> + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v6_reachable)) { >>> ds_clear(match); >>> >>> if (is_l3dgw_port(op)) { >>> @@ -14890,8 +14635,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, >>> * Priority 60. >>> */ >>> if (!lrnat_rec->lb_force_snat_router_ip) { >>> - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_IP_INPUT, 60, >>> - false, lflows); >>> + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, >>> + S_ROUTER_IN_IP_INPUT, 60, false, lflows); >>> } >>> /* ARP / ND handling for external IP addresses. >>> * >>> @@ -16030,6 +15775,7 @@ struct lswitch_flow_build_info { >>> const struct hmap *lr_ports; >>> const struct ls_port_group_table *ls_port_groups; >>> const struct lr_nat_table *lr_nats; >>> + const struct lr_lb_nat_data_table *lr_lbnats; >>> struct hmap *lflows; >>> struct hmap *igmp_groups; >>> const struct shash *meter_groups; >>> @@ -16113,14 +15859,15 @@ build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od, >>> * switch port. >>> */ >>> static void >>> -build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, >>> - const struct hmap *ls_ports, >>> - const struct hmap *lr_ports, >>> - const struct lr_nat_table *lr_nats, >>> - const struct shash *meter_groups, >>> - struct ds *match, >>> - struct ds *actions, >>> - struct hmap *lflows) >>> +build_lswitch_and_lrouter_iterate_by_lsp( >>> + struct ovn_port *op, const struct hmap *ls_ports, >>> + const struct hmap *lr_ports, >>> + const struct lr_nat_table *lr_nats, >>> + const struct lr_lb_nat_data_table *lr_lbnats, >>> + const struct shash *meter_groups, >>> + struct ds *match, >>> + struct ds *actions, >>> + struct hmap *lflows) >>> { >>> ovs_assert(op->nbsp); >>> start_collecting_lflows(); >>> @@ -16133,11 +15880,14 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, >>> meter_groups, actions, match); >>> build_lswitch_dhcp_options_and_response(op, lflows, meter_groups); >>> build_lswitch_external_port(op, lflows); >>> - build_lswitch_ip_unicast_lookup(op, lr_nats, lflows, actions, match); >>> + build_lswitch_ip_unicast_lookup(op, lr_nats, lr_lbnats, lflows, actions, >>> + match); >>> >>> /* Build Logical Router Flows. */ >>> - build_ip_routing_flows_for_router_type_lsp(op, lr_ports, lflows); >>> - build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, match, actions); >>> + build_ip_routing_flows_for_router_type_lsp(op, lr_lbnats, lr_ports, >>> + lflows); >>> + build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, lr_lbnats, >>> + match, actions); >>> >>> link_ovn_port_to_lflows(op, &collected_lflows); >>> end_collecting_lflows(); >>> @@ -16156,6 +15906,8 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, >>> lsi->lr_nats, op->od->index); >>> ovs_assert(lrnet_rec); >>> >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec = >>> + lr_lb_nat_data_table_find_by_index(lsi->lr_lbnats, op->od->index); >>> build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, >>> &lsi->actions); >>> build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, >>> @@ -16163,15 +15915,15 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, >>> build_ip_routing_flows_for_lrp(op, lsi->lflows); >>> build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, >>> &lsi->actions, lsi->meter_groups); >>> - build_arp_resolve_flows_for_lrp(op, lrnet_rec, lsi->lflows, &lsi->match, >>> - &lsi->actions); >>> + build_arp_resolve_flows_for_lrp(op, lrnet_rec, lr_lbnat_rec, lsi->lflows, >>> + &lsi->match, &lsi->actions); >>> build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, >>> &lsi->actions); >>> build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match); >>> build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows, >>> &lsi->match, &lsi->actions, >>> lsi->meter_groups); >>> - build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, >>> + build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, lr_lbnat_rec, >>> &lsi->match, &lsi->actions, lsi->meter_groups); >>> build_lrouter_force_snat_flows_op(op, lrnet_rec, lsi->lflows, &lsi->match, >>> &lsi->actions); >>> @@ -16234,6 +15986,7 @@ build_lflows_thread(void *arg) >>> build_lswitch_and_lrouter_iterate_by_lsp(op, lsi->ls_ports, >>> lsi->lr_ports, >>> lsi->lr_nats, >>> + lsi->lr_lbnats, >>> lsi->meter_groups, >>> &lsi->match, >>> &lsi->actions, >>> @@ -16344,6 +16097,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, >>> const struct hmap *lr_ports, >>> const struct ls_port_group_table *ls_pgs, >>> const struct lr_nat_table *lr_nats, >>> + const struct lr_lb_nat_data_table *lr_lbnats, >>> struct hmap *lflows, >>> struct hmap *igmp_groups, >>> const struct shash *meter_groups, >>> @@ -16374,6 +16128,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, >>> lsiv[index].lr_ports = lr_ports; >>> lsiv[index].ls_port_groups = ls_pgs; >>> lsiv[index].lr_nats = lr_nats; >>> + lsiv[index].lr_lbnats = lr_lbnats; >>> lsiv[index].igmp_groups = igmp_groups; >>> lsiv[index].meter_groups = meter_groups; >>> lsiv[index].lb_dps_map = lb_dps_map; >>> @@ -16409,6 +16164,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, >>> .lr_ports = lr_ports, >>> .ls_port_groups = ls_pgs, >>> .lr_nats = lr_nats, >>> + .lr_lbnats = lr_lbnats, >>> .lflows = lflows, >>> .igmp_groups = igmp_groups, >>> .meter_groups = meter_groups, >>> @@ -16437,6 +16193,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, >>> build_lswitch_and_lrouter_iterate_by_lsp(op, lsi.ls_ports, >>> lsi.lr_ports, >>> lsi.lr_nats, >>> + lsi.lr_lbnats, >>> lsi.meter_groups, >>> &lsi.match, &lsi.actions, >>> lsi.lflows); >>> @@ -16558,6 +16315,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, >>> input_data->lr_ports, >>> input_data->ls_port_groups, >>> input_data->lr_nats, >>> + input_data->lr_lbnats, >>> lflows, >>> &igmp_groups, >>> input_data->meter_groups, >>> @@ -17038,6 +16796,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, >>> build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, >>> lflow_input->lr_ports, >>> lflow_input->lr_nats, >>> + lflow_input->lr_lbnats, >>> lflow_input->meter_groups, >>> &match, &actions, >>> lflows); >>> @@ -17076,6 +16835,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, >>> build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, >>> lflow_input->lr_ports, >>> lflow_input->lr_nats, >>> + lflow_input->lr_lbnats, >>> lflow_input->meter_groups, >>> &match, &actions, >>> lflows); >>> diff --git a/northd/northd.h b/northd/northd.h >>> index 564729ebcc..7c446f5758 100644 >>> --- a/northd/northd.h >>> +++ b/northd/northd.h >>> @@ -179,6 +179,7 @@ struct lflow_input { >>> const struct hmap *lr_ports; >>> const struct ls_port_group_table *ls_port_groups; >>> const struct lr_nat_table *lr_nats; >>> + const struct lr_lb_nat_data_table *lr_lbnats; >>> const struct shash *meter_groups; >>> const struct hmap *lb_datapaths_map; >>> const struct hmap *bfd_connections; >>> @@ -318,9 +319,6 @@ struct ovn_datapath { >>> /* router datapath has a logical port with redirect-type set to bridged. */ >>> bool redirect_bridged; >>> >>> - /* Load Balancer vIPs relevant for this datapath. */ >>> - struct ovn_lb_ip_set *lb_ips; >>> - >>> struct ovn_port **localnet_ports; >>> size_t n_localnet_ports; >>> >>> @@ -337,6 +335,119 @@ struct ovn_datapath { >>> const struct ovn_datapath *ovn_datapath_find(const struct hmap *datapaths, >>> const struct uuid *uuid); >>> >>> +/* A logical switch port or logical router port. >>> + * >>> + * In steady state, an ovn_port points to a northbound Logical_Switch_Port >>> + * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a >>> + * southbound Port_Binding record (via 'sb'). As the state of the system >>> + * changes, join_logical_ports() may determine that there is a new LSP or LRP >>> + * that has no corresponding Port_Binding record (in which case build_ports()) >>> + * will create the missing Port_Binding) or that a Port_Binding record exists >>> + * that has no coresponding LSP (in which case build_ports() will delete the >>> + * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port >>> + * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. >>> + * >>> + * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but >>> + * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). >>> + */ >>> +struct ovn_port { >>> + /* Port name aka key. >>> + * >>> + * This is ordinarily the same as nbsp->name or nbrp->name and >>> + * sb->logical_port. (A distributed gateway port creates a "derived" >>> + * ovn_port with key "cr-%s" % nbrp->name.) */ >>> + struct hmap_node key_node; /* Index on 'key'. */ >>> + char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ >>> + char *json_key; /* 'key', quoted for use in JSON. */ >>> + >>> + const struct sbrec_port_binding *sb; /* May be NULL. */ >>> + >>> + uint32_t tunnel_key; >>> + >>> + /* Logical switch port data. */ >>> + const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ >>> + >>> + struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ >>> + unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ >>> + unsigned int n_lsp_non_router_addrs; /* Number of elements from the >>> + * beginning of 'lsp_addrs' extracted >>> + * directly from LSP 'addresses'. */ >>> + >>> + struct lport_addresses *ps_addrs; /* Port security addresses. */ >>> + unsigned int n_ps_addrs; >>> + >>> + bool lsp_can_be_inc_processed; /* If it can be incrementally processed when >>> + the port changes. */ >>> + >>> + /* Logical router port data. */ >>> + const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ >>> + >>> + struct lport_addresses lrp_networks; >>> + >>> + /* Logical port multicast data. */ >>> + struct mcast_port_info mcast_info; >>> + >>> + /* At most one of l3dgw_port and cr_port can be not NULL. */ >>> + >>> + /* This is set to a distributed gateway port if and only if this ovn_port >>> + * is "derived" from it. Otherwise this is set to NULL. The derived >>> + * ovn_port represents the instance of distributed gateway port on the >>> + * gateway chassis.*/ >>> + struct ovn_port *l3dgw_port; >>> + >>> + /* This is set to the "derived" chassis-redirect port of this port if and >>> + * only if this port is a distributed gateway port. Otherwise this is set >>> + * to NULL. */ >>> + struct ovn_port *cr_port; >>> + >>> + bool has_unknown; /* If the addresses have 'unknown' defined. */ >>> + >>> + bool has_bfd; >>> + >>> + /* The port's peer: >>> + * >>> + * - A switch port S of type "router" has a router port R as a peer, >>> + * and R in turn has S has its peer. >>> + * >>> + * - Two connected logical router ports have each other as peer. >>> + * >>> + * - Other kinds of ports have no peer. */ >>> + struct ovn_port *peer; >>> + >>> + struct ovn_datapath *od; >>> + >>> + struct ovs_list list; /* In list of similar records. */ >>> + >>> + struct hmap_node dp_node; /* Node in od->ports. */ >>> + >>> + struct lport_addresses proxy_arp_addrs; >>> + >>> + /* Temporarily used for traversing a list (or hmap) of ports. */ >>> + bool visited; >>> + >>> + /* List of struct lflow_ref_node that points to the lflows generated by >>> + * this ovn_port. >>> + * >>> + * This data is initialized and destroyed by the en_northd node, but >>> + * populated and used only by the en_lflow node. Ideally this data should >>> + * be maintained as part of en_lflow's data (struct lflow_data): a hash >>> + * index from ovn_port key to lflows. However, it would be less efficient >>> + * and more complex: >>> + * >>> + * 1. It would require an extra search (using the index) to find the >>> + * lflows. >>> + * >>> + * 2. Building the index needs to be thread-safe, using either a global >>> + * lock which is obviously less efficient, or hash-based lock array which >>> + * is more complex. >>> + * >>> + * Adding the list here is more straightforward. The drawback is that we >>> + * need to keep in mind that this data belongs to en_lflow node, so never >>> + * access it from any other nodes. >>> + */ >>> + struct ovs_list lflows; >>> +}; >>> + >>> void ovnnb_db_run(struct northd_input *input_data, >>> struct northd_data *data, >>> struct ovsdb_idl_txn *ovnnb_txn, >>> @@ -396,13 +507,27 @@ void sync_lbs(struct ovsdb_idl_txn *, const struct sbrec_load_balancer_table *, >>> struct chassis_features *chassis_features); >>> bool check_sb_lb_duplicates(const struct sbrec_load_balancer_table *); >>> >>> +struct lr_lb_nat_data_table; >>> void sync_pbs(struct ovsdb_idl_txn *, struct hmap *ls_ports, >>> - struct hmap *lr_ports, const struct lr_nat_table *); >>> -bool sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *, >>> - const struct lr_nat_table *); >>> + struct hmap *lr_ports, >>> + const struct lr_lb_nat_data_table *); >>> +bool sync_pbs_for_northd_changed_ovn_ports( >>> + struct tracked_ovn_ports *, >>> + const struct lr_lb_nat_data_table *); >>> >>> bool northd_has_tracked_data(struct northd_tracked_data *); >>> bool northd_has_only_ports_in_tracked_data(struct northd_tracked_data *); >>> bool northd_has_lbs_in_tracked_data(struct northd_tracked_data *); >>> >>> +/* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the >>> + * IPs configured on the router port. >>> + */ >>> +bool lrouter_port_ipv4_reachable(const struct ovn_port *, ovs_be32 addr); >>> + >>> +/* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the >>> + * IPs configured on the router port. >>> + */ >>> +bool lrouter_port_ipv6_reachable(const struct ovn_port *, >>> + const struct in6_addr *); >>> + >>> #endif /* NORTHD_H */ >>> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at >>> index b7f9cb5689..8fc5cd1d60 100644 >>> --- a/tests/ovn-northd.at >>> +++ b/tests/ovn-northd.at >>> @@ -10416,18 +10416,21 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:10.0.0.3=sw0-p1:10.0.0.2 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> >>> check ovn-nbctl --wait=sb set load_balancer . options:foo=bar >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> >>> check ovn-nbctl --wait=sb -- lb-add lb2 20.0.0.10:80 20.0.0.20:80 -- lb-add lb3 30.0.0.10:80 30.0.0.20:80 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> >>> @@ -10437,6 +10440,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb -- lb-del lb2 -- lb-del lb3 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> >>> @@ -10450,6 +10454,7 @@ AT_CHECK([ovn-nbctl --wait=sb \ >>> ]) >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> >>> @@ -10467,6 +10472,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb clear Load_Balancer . health_check >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> >>> @@ -10481,6 +10487,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> >>> @@ -10489,6 +10496,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> # A LB applied to a switch/router triggers: >>> # - a recompute in the first iteration (handling northd change) >>> @@ -10501,6 +10509,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10510,6 +10519,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10519,6 +10529,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10528,6 +10539,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10537,6 +10549,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb ls-lb-del sw0 lb1 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10547,6 +10560,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 -- lsp-add sw0 sw0p1 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> >>> @@ -10567,6 +10581,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-lb-add lr0 lb1 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10576,6 +10591,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10585,6 +10601,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10594,6 +10611,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10603,6 +10621,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10632,6 +10651,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb add load_balancer_group . load_Balancer $lb1_uuid >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> >>> @@ -10639,6 +10659,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb clear load_balancer_group . load_Balancer >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> >>> @@ -10655,6 +10676,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> >>> @@ -10671,6 +10693,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10680,6 +10703,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10689,6 +10713,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10698,6 +10723,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10713,6 +10739,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl add logical_router lr0 load_balancer_group $lbg1_uuid >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10722,6 +10749,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10731,6 +10759,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10740,6 +10769,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10749,6 +10779,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10757,6 +10788,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb clear logical_router lr0 load_balancer_group >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> >>> @@ -10765,6 +10797,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> >>> @@ -10773,6 +10806,7 @@ check ovn-nbctl --wait=sb clear logical_switch sw0 load_balancer_group -- \ >>> destroy load_balancer_group $lbg1_uuid >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb compute compute >>> >>> @@ -10796,6 +10830,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> lbg1_uuid=$(ovn-nbctl --wait=sb create load_balancer_group name=lbg1) >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow norecompute nocompute >>> check_engine_stats sync_to_sb_lb norecompute nocompute >>> >>> @@ -10803,6 +10838,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set load_balancer_group . load_balancer="$lb2_uuid,$lb3_uuid,$lb4_uuid" >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> >>> @@ -10810,6 +10846,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set logical_switch sw0 load_balancer_group=$lbg1_uuid >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10818,6 +10855,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set logical_router lr1 load_balancer_group=$lbg1_uuid >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10826,6 +10864,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb ls-lb-add sw0 lb2 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10834,6 +10873,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb ls-lb-add sw0 lb3 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10843,6 +10883,7 @@ check ovn-nbctl --wait=sb lr-lb-add lr1 lb1 >>> check ovn-nbctl --wait=sb lr-lb-add lr1 lb2 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10851,6 +10892,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb ls-lb-del sw0 lb2 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10859,6 +10901,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-lb-del lr1 lb2 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10869,6 +10912,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lb-del lb4 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10879,6 +10923,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lb-del lb2 >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -10887,6 +10932,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb remove load_balancer_group . load_balancer $lb3_uuid >>> check_engine_stats lb_data norecompute compute >>> check_engine_stats northd recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_lb recompute compute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11019,6 +11065,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-add lr0 >>> check_engine_stats northd recompute nocompute >>> check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11031,6 +11078,7 @@ check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 >>> # for the SB port binding change. >>> check_engine_stats northd recompute compute >>> check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11042,6 +11090,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 >>> check_engine_stats northd recompute nocompute >>> check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11067,6 +11116,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl set logical_router_port lr0-sw0 options:foo=bar >>> check_engine_stats northd recompute nocompute >>> check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11076,8 +11126,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> # engine nodes. >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 >>> -check_engine_stats northd recompute nocompute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11085,8 +11135,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> # Update the NAT options column >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set NAT . options:foo=bar >>> -check_engine_stats northd recompute nocompute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11094,8 +11144,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> # Update the NAT external_ip column >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set NAT . external_ip=172.168.0.120 >>> -check_engine_stats northd recompute nocompute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11103,8 +11154,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> # Update the NAT logical_ip column >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set NAT . logical_ip=10.0.0.10 >>> -check_engine_stats northd recompute nocompute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11112,8 +11164,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> # Update the NAT type >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set NAT . type=snat >>> -check_engine_stats northd recompute nocompute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11121,8 +11174,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> # Create a dnat_and_snat NAT with external_mac and logical_port >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 sw0p1 30:54:00:00:00:03 >>> -check_engine_stats northd recompute compute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11131,8 +11185,9 @@ nat2_uuid=$(ovn-nbctl --bare --columns _uuid find nat logical_ip=10.0.0.4) >>> >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb set NAT $nat2_uuid external_mac='"30:54:00:00:00:04"' >>> -check_engine_stats northd recompute nocompute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11147,32 +11202,36 @@ check ovn-nbctl lr-lb-add lr0 lb2 >>> # is a lb vip. >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.140 10.0.0.20 >>> -check_engine_stats northd recompute nocompute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.150 10.0.0.41 >>> -check_engine_stats northd recompute nocompute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.150 >>> -check_engine_stats northd recompute nocompute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.140 >>> -check_engine_stats northd recompute nocompute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11180,8 +11239,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> # Delete the NAT >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb clear logical_router lr0 nat >>> -check_engine_stats northd recompute compute >>> -check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats northd norecompute compute >>> +check_engine_stats lr_nat norecompute compute >>> +check_engine_stats lr_lb_nat_data norecompute compute >>> check_engine_stats lflow recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11191,6 +11251,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-policy-add lr0 10 "ip4.src == 10.0.0.3" reroute 172.168.0.101,172.168.0.102 >>> check_engine_stats northd recompute nocompute >>> check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE >>> @@ -11199,6 +11260,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats >>> check ovn-nbctl --wait=sb lr-policy-del lr0 10 "ip4.src == 10.0.0.3" >>> check_engine_stats northd recompute nocompute >>> check_engine_stats lr_nat recompute nocompute >>> +check_engine_stats lr_lb_nat_data recompute nocompute >>> check_engine_stats sync_to_sb_pb recompute nocompute >>> check_engine_stats lflow recompute nocompute >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE
On Fri, Nov 24, 2023 at 5:52 AM Dumitru Ceara <dceara@redhat.com> wrote: > > On 11/23/23 22:29, Dumitru Ceara wrote: > > On 11/23/23 21:45, Dumitru Ceara wrote: > >> On 10/26/23 20:15, numans@ovn.org wrote: > >>> From: Numan Siddique <numans@ovn.org> > >>> > >>> This new engine now maintains the load balancer and NAT data of a > >>> logical router which was earlier part of northd engine node data. > >>> The main inputs to this engine are: > >>> - northd node > >>> - lr-nat node > >>> > >>> A record for each logical router is maintained in the 'lr_lb_nats' > >>> hmap table and this record > >>> - stores the lb related data > >>> - embeds the 'lr-nat' record. > >>> > >>> This engine node becomes an input to 'lflow' node. > >>> > >>> Signed-off-by: Numan Siddique <numans@ovn.org> > >>> --- > >>> lib/stopwatch-names.h | 1 + > >>> northd/automake.mk | 2 + > >>> northd/en-lflow.c | 4 + > >>> northd/en-lr-lb-nat-data.c | 654 +++++++++++++++++++++++++++++++++++++ > >>> northd/en-lr-lb-nat-data.h | 93 ++++++ > >>> northd/en-lr-nat.h | 3 + > >>> northd/en-sync-sb.c | 50 +-- > >>> northd/inc-proc-northd.c | 13 +- > >>> northd/northd.c | 640 ++++++++++++------------------------ > >>> northd/northd.h | 137 +++++++- > >>> tests/ovn-northd.at | 110 +++++-- > >>> 11 files changed, 1212 insertions(+), 495 deletions(-) > >>> create mode 100644 northd/en-lr-lb-nat-data.c > >>> create mode 100644 northd/en-lr-lb-nat-data.h > >>> > >>> diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h > >>> index 0a16da211e..7d85acdaea 100644 > >>> --- a/lib/stopwatch-names.h > >>> +++ b/lib/stopwatch-names.h > >>> @@ -33,5 +33,6 @@ > >>> #define PORT_GROUP_RUN_STOPWATCH_NAME "port_group_run" > >>> #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" > >>> #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" > >>> +#define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" > >>> > >>> #endif > >>> diff --git a/northd/automake.mk b/northd/automake.mk > >>> index ae367a2a8b..4116c487df 100644 > >>> --- a/northd/automake.mk > >>> +++ b/northd/automake.mk > >>> @@ -26,6 +26,8 @@ northd_ovn_northd_SOURCES = \ > >>> northd/en-lb-data.h \ > >>> northd/en-lr-nat.c \ > >>> northd/en-lr-nat.h \ > >>> + northd/en-lr-lb-nat-data.c \ > >>> + northd/en-lr-lb-nat-data.h \ > >>> northd/inc-proc-northd.c \ > >>> northd/inc-proc-northd.h \ > >>> northd/ipam.c \ > >>> diff --git a/northd/en-lflow.c b/northd/en-lflow.c > >>> index 22f398d419..9cb0ead3f0 100644 > >>> --- a/northd/en-lflow.c > >>> +++ b/northd/en-lflow.c > >>> @@ -20,6 +20,7 @@ > >>> > >>> #include "en-lflow.h" > >>> #include "en-lr-nat.h" > >>> +#include "en-lr-lb-nat-data.h" > >>> #include "en-northd.h" > >>> #include "en-meters.h" > >>> > >>> @@ -43,6 +44,8 @@ lflow_get_input_data(struct engine_node *node, > >>> engine_get_input_data("sync_meters", node); > >>> struct ed_type_lr_nat_data *lr_nat_data = > >>> engine_get_input_data("lr_nat", node); > >>> + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > >>> + engine_get_input_data("lr_lb_nat_data", node); > >>> > >>> lflow_input->nbrec_bfd_table = > >>> EN_OVSDB_GET(engine_get_input("NB_bfd", node)); > >>> @@ -66,6 +69,7 @@ lflow_get_input_data(struct engine_node *node, > >>> lflow_input->lr_ports = &northd_data->lr_ports; > >>> lflow_input->ls_port_groups = &pg_data->ls_port_groups; > >>> lflow_input->lr_nats = &lr_nat_data->lr_nats; > >>> + lflow_input->lr_lbnats = &lr_lb_nat_data->lr_lbnats; > >>> lflow_input->meter_groups = &sync_meters_data->meter_groups; > >>> lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map; > >>> lflow_input->svc_monitor_map = &northd_data->svc_monitor_map; > >>> diff --git a/northd/en-lr-lb-nat-data.c b/northd/en-lr-lb-nat-data.c > >>> new file mode 100644 > >>> index 0000000000..19b638ce0b > >>> --- /dev/null > >>> +++ b/northd/en-lr-lb-nat-data.c > >>> @@ -0,0 +1,654 @@ > >>> +/* > >>> + * Copyright (c) 2023, Red Hat, Inc. > >>> + * > >>> + * Licensed under the Apache License, Version 2.0 (the "License"); > >>> + * you may not use this file except in compliance with the License. > >>> + * You may obtain a copy of the License at: > >>> + * > >>> + * http://www.apache.org/licenses/LICENSE-2.0 > >>> + * > >>> + * Unless required by applicable law or agreed to in writing, software > >>> + * distributed under the License is distributed on an "AS IS" BASIS, > >>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > >>> + * See the License for the specific language governing permissions and > >>> + * limitations under the License. > >>> + */ > >>> + > >>> +#include <config.h> > >>> + > >>> +#include <getopt.h> > >>> +#include <stdlib.h> > >>> +#include <stdio.h> > >>> + > >>> +/* OVS includes */ > >>> +#include "include/openvswitch/hmap.h" > >>> +#include "lib/bitmap.h" > >>> +#include "lib/socket-util.h" > >>> +#include "lib/uuidset.h" > >>> +#include "openvswitch/util.h" > >>> +#include "openvswitch/vlog.h" > >>> +#include "stopwatch.h" > >>> + > >>> +/* OVN includes */ > >>> +#include "en-lb-data.h" > >>> +#include "en-lr-lb-nat-data.h" > >>> +#include "en-lr-nat.h" > >>> +#include "lib/inc-proc-eng.h" > >>> +#include "lib/lb.h" > >>> +#include "lib/ovn-nb-idl.h" > >>> +#include "lib/ovn-sb-idl.h" > >>> +#include "lib/ovn-util.h" > >>> +#include "lib/stopwatch-names.h" > >>> +#include "northd.h" > >>> + > >>> +VLOG_DEFINE_THIS_MODULE(en_lr_lb_nat_data); > >>> + > >>> +/* Static function declarations. */ > >>> +static void lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *); > >>> +static void lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *); > >>> +static void lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *); > >>> +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_( > >>> + const struct lr_lb_nat_data_table *, const struct nbrec_logical_router *); > >>> +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index_( > >>> + const struct lr_lb_nat_data_table *table, size_t od_index); > >>> + > >>> +static void lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *, > >>> + const struct lr_nat_table *, > >>> + const struct ovn_datapaths *lr_datapaths, > >>> + const struct hmap *lb_datapaths_map, > >>> + const struct hmap *lbgrp_datapaths_map); > >>> + > >>> +static struct lr_lb_nat_data_input lr_lb_nat_data_get_input_data( > >>> + struct engine_node *); > >>> + > >>> +static struct lr_lb_nat_data_record *lr_lb_nat_data_record_create( > >>> + struct lr_lb_nat_data_table *, const struct lr_nat_record *, > >>> + const struct hmap *lb_datapaths_map, > >>> + const struct hmap *lbgrp_datapaths_map); > >>> +static void lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *); > >>> +static void lr_lb_nat_data_record_init( > >>> + struct lr_lb_nat_data_record *, > >>> + const struct hmap *lb_datapaths_map, > >>> + const struct hmap *lbgrp_datapaths_map); > >>> + > >>> +static void build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, > >>> + const struct ovn_northd_lb *); > >>> +static void add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *, > >>> + enum lb_neighbor_responder_mode, > >>> + const struct sset *lb_ips_v4, > >>> + const struct sset *lb_ips_v6); > >>> +static void remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, > >>> + enum lb_neighbor_responder_mode, > >>> + const struct sset *lb_ips_v4, > >>> + const struct sset *lb_ips_v6); > >>> +static void lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *); > >>> + > >>> +/* 'lr_lb_nat_data' engine node manages the NB logical router LB data. > >>> + */ > >>> +void * > >>> +en_lr_lb_nat_data_init(struct engine_node *node OVS_UNUSED, > >>> + struct engine_arg *arg OVS_UNUSED) > >>> +{ > >>> + struct ed_type_lr_lb_nat_data *data = xzalloc(sizeof *data); > >>> + lr_lb_nat_data_table_init(&data->lr_lbnats); > >>> + hmapx_init(&data->tracked_data.crupdated); > >>> + hmapx_init(&data->tracked_data.deleted); > >>> + return data; > >>> +} > >>> + > >>> +void > >>> +en_lr_lb_nat_data_cleanup(void *data_) > >>> +{ > >>> + struct ed_type_lr_lb_nat_data *data = > >>> + (struct ed_type_lr_lb_nat_data *) data_; > >>> + lr_lb_nat_data_table_destroy(&data->lr_lbnats); > >>> + hmapx_destroy(&data->tracked_data.crupdated); > >>> + hmapx_destroy(&data->tracked_data.deleted); > >>> +} > >>> + > >>> +void > >>> +en_lr_lb_nat_data_clear_tracked_data(void *data_) > >>> +{ > >>> + struct ed_type_lr_lb_nat_data *data = > >>> + (struct ed_type_lr_lb_nat_data *) data_; > >>> + > >>> + struct hmapx_node *hmapx_node; > >>> + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { > >>> + lr_lb_nat_data_record_destroy(hmapx_node->data); > >>> + hmapx_delete(&data->tracked_data.deleted, hmapx_node); > >>> + } > >>> + > >>> + hmapx_clear(&data->tracked_data.crupdated); > >>> + data->tracked = false; > >>> +} > >>> + > >>> +void > >>> +en_lr_lb_nat_data_run(struct engine_node *node, void *data_) > >>> +{ > >>> + struct lr_lb_nat_data_input input_data = > >>> + lr_lb_nat_data_get_input_data(node); > >>> + struct ed_type_lr_lb_nat_data *data = data_; > >>> + > >>> + stopwatch_start(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); > >>> + > >>> + lr_lb_nat_data_table_clear(&data->lr_lbnats); > >>> + lr_lb_nat_data_table_build(&data->lr_lbnats, input_data.lr_nats, > >>> + input_data.lr_datapaths, > >>> + input_data.lb_datapaths_map, > >>> + input_data.lbgrp_datapaths_map); > >>> + > >>> + stopwatch_stop(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); > > Unfortunately, this doesn't do anything if the stopwatch wasn't created > before. We're missing a > stopwatch_create(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, .. ) in ovn-northd.c. > > I see now the most recently added two stopwatches (port groups and > meters) also don't do that. I'll post a patch for that. Thanks for spotting this. Addressed in v3. > > Thanks, > Dumitru > > >>> + engine_set_node_state(node, EN_UPDATED); > >>> +} > >>> + > >>> +bool > >>> +lr_lb_nat_data_northd_handler(struct engine_node *node, void *data OVS_UNUSED) > >>> +{ > >>> + struct northd_data *northd_data = engine_get_input_data("northd", node); > >>> + if (!northd_data->change_tracked) { > >>> + return false; > >>> + } > >>> + > >>> + return true; > >>> +} > >>> + > >>> +bool > >>> +lr_lb_nat_data_lb_data_handler(struct engine_node *node, void *data_) > >>> +{ > >>> + struct ed_type_lb_data *lb_data = engine_get_input_data("lb_data", node); > >>> + if (!lb_data->tracked) { > >>> + return false; > >>> + } > >>> + > >>> + struct ed_type_lr_lb_nat_data *data = > >>> + (struct ed_type_lr_lb_nat_data *) data_; > >>> + struct lr_lb_nat_data_input input_data = > >>> + lr_lb_nat_data_get_input_data(node); > >>> + struct lr_lb_nat_data_record *lr_lbnat_rec; > >>> + size_t index; > >>> + > >>> + const struct tracked_lb_data *trk_lb_data = &lb_data->tracked_lb_data; > >>> + const struct ovn_lb_group_datapaths *lbgrp_dps; > >>> + const struct crupdated_lbgrp *crupdated_lbgrp; > >>> + const struct crupdated_od_lb_data *codlb; > >>> + const struct ovn_lb_datapaths *lb_dps; > >>> + const struct crupdated_lb *clb; > >>> + const struct ovn_northd_lb *lb; > >>> + const struct ovn_datapath *od; > >>> + > >>> + LIST_FOR_EACH (codlb, list_node, &trk_lb_data->crupdated_lr_lbs) { > >>> + od = ovn_datapath_find(&input_data.lr_datapaths->datapaths, > >>> + &codlb->od_uuid); > >>> + ovs_assert(od); > >>> + > >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, od->nbr); > >>> + if (!lr_lbnat_rec) { > >>> + const struct lr_nat_record *lrnat_rec = lr_nat_table_find_by_index( > >>> + input_data.lr_nats, od->index); > >>> + ovs_assert(lrnat_rec); > >>> + > >>> + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, > >>> + lrnat_rec, > >>> + input_data.lb_datapaths_map, > >>> + input_data.lbgrp_datapaths_map); > >>> + > >>> + /* Add the lr_lbnat_rec rec to the tracking data. */ > >>> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > >>> + continue; > >>> + } > >>> + > >>> + struct uuidset_node *uuidnode; > >>> + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbs) { > >>> + lb_dps = ovn_lb_datapaths_find( > >>> + input_data.lb_datapaths_map, &uuidnode->uuid); > >>> + ovs_assert(lb_dps); > >>> + > >>> + /* Add the lb_ips of lb_dps to the od. */ > >>> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > >>> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > >>> + } > >>> + > >>> + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbgrps) { > >>> + lbgrp_dps = ovn_lb_group_datapaths_find( > >>> + input_data.lbgrp_datapaths_map, &uuidnode->uuid); > >>> + ovs_assert(lbgrp_dps); > >>> + > >>> + for (size_t j = 0; j < lbgrp_dps->lb_group->n_lbs; j++) { > >>> + const struct uuid *lb_uuid > >>> + = &lbgrp_dps->lb_group->lbs[j]->nlb->header_.uuid; > >>> + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, > >>> + lb_uuid); > >>> + ovs_assert(lb_dps); > >>> + > >>> + /* Add the lb_ips of lb_dps to the od. */ > >>> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > >>> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > >>> + } > >>> + } > >>> + > >>> + /* Add the lr_lbnat_rec rec to the tracking data. */ > >>> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > >>> + } > >>> + > >>> + HMAP_FOR_EACH (clb, hmap_node, &trk_lb_data->crupdated_lbs) { > >>> + lb = clb->lb; > >>> + const struct uuid *lb_uuid = &lb->nlb->header_.uuid; > >>> + > >>> + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, lb_uuid); > >>> + ovs_assert(lb_dps); > >>> + > >>> + BITMAP_FOR_EACH_1 (index, ods_size(input_data.lr_datapaths), > >>> + lb_dps->nb_lr_map) { > >>> + od = input_data.lr_datapaths->array[index]; > >>> + > >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, > >>> + od->nbr); > >>> + ovs_assert(lr_lbnat_rec); > >>> + > >>> + /* Update the od->lb_ips with the deleted and inserted > >>> + * vips (if any). */ > >>> + remove_ips_from_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, > >>> + &clb->deleted_vips_v4, > >>> + &clb->deleted_vips_v6); > >>> + add_ips_to_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, > >>> + &clb->inserted_vips_v4, > >>> + &clb->inserted_vips_v6); > >>> + > >>> + remove_lrouter_lb_reachable_ips(lr_lbnat_rec, lb->neigh_mode, > >>> + &clb->deleted_vips_v4, > >>> + &clb->deleted_vips_v6); > >>> + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, > >>> + &clb->inserted_vips_v4, > >>> + &clb->inserted_vips_v6); > >>> + > >>> + /* Add the lr_lbnat_rec rec to the tracking data. */ > >>> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > >>> + } > >>> + } > >>> + > >>> + HMAP_FOR_EACH (crupdated_lbgrp, hmap_node, > >>> + &trk_lb_data->crupdated_lbgrps) { > >>> + const struct uuid *lb_uuid = &crupdated_lbgrp->lbgrp->uuid; > >>> + > >>> + lbgrp_dps = ovn_lb_group_datapaths_find(input_data.lbgrp_datapaths_map, > >>> + lb_uuid); > >>> + ovs_assert(lbgrp_dps); > >>> + > >>> + struct hmapx_node *hnode; > >>> + HMAPX_FOR_EACH (hnode, &crupdated_lbgrp->assoc_lbs) { > >>> + lb = hnode->data; > >>> + lb_uuid = &lb->nlb->header_.uuid; > >>> + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, > >>> + lb_uuid); > >>> + ovs_assert(lb_dps); > >>> + for (size_t i = 0; i < lbgrp_dps->n_lr; i++) { > >>> + od = lbgrp_dps->lr[i]; > >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, > >>> + od->nbr); > >>> + ovs_assert(lr_lbnat_rec); > >>> + /* Add the lb_ips of lb_dps to the lr lb data. */ > >>> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > >>> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > >>> + > >>> + /* Add the lr_lbnat_rec rec to the tracking data. */ > >>> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > >>> + } > >>> + } > >>> + } > >>> + > >>> + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > >>> + struct hmapx_node *hmapx_node; > >>> + /* For all the modified lr_lb_nat_data records (re)build the > >>> + * vip nats. */ > >>> + HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { > >>> + lr_lb_nat_data_build_vip_nats(hmapx_node->data); > >>> + } > >>> + > >>> + data->tracked = true; > >>> + engine_set_node_state(node, EN_UPDATED); > >>> + } > >>> + > >>> + return true; > >>> +} > >>> + > >>> +bool > >>> +lr_lb_nat_data_lr_nat_handler(struct engine_node *node, void *data_) > >>> +{ > >>> + struct ed_type_lr_nat_data *lr_nat_data = > >>> + engine_get_input_data("lr_nat", node); > >>> + > >>> + if (!lr_nat_data->tracked > >>> + || !hmapx_is_empty(&lr_nat_data->tracked_data.deleted)) { > >>> + return false; > >>> + } > >>> + > >>> + struct ed_type_lr_lb_nat_data *data = > >>> + (struct ed_type_lr_lb_nat_data *) data_; > >>> + struct lr_lb_nat_data_input input_data = > >>> + lr_lb_nat_data_get_input_data(node); > >>> + const struct lr_nat_record *lrnat_rec; > >>> + struct lr_lb_nat_data_record *lr_lbnat_rec; > >>> + struct hmapx_node *hmapx_node; > >>> + > >>> + HMAPX_FOR_EACH (hmapx_node, &lr_nat_data->tracked_data.crupdated) { > >>> + lrnat_rec = hmapx_node->data; > >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, > >>> + lrnat_rec->od->nbr); > >>> + if (!lr_lbnat_rec) { > >>> + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, > >>> + lrnat_rec, > >>> + input_data.lb_datapaths_map, > >>> + input_data.lbgrp_datapaths_map); > >>> + } else { > >>> + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > >>> + } > >>> + > >>> + /* Add the lr_lbnat_rec rec to the tracking data. */ > >>> + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); > >>> + } > >>> + > >>> + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { > >>> + data->tracked = true; > >>> + engine_set_node_state(node, EN_UPDATED); > >>> + } > >>> + > >>> + return true; > >>> +} > >>> + > >>> +const struct lr_lb_nat_data_record * > >>> +lr_lb_nat_data_table_find_by_index(const struct lr_lb_nat_data_table *table, > >>> + size_t od_index) > >>> +{ > >>> + return lr_lb_nat_data_table_find_by_index_(table, od_index); > >>> +} > >>> + > >>> +/* static functions. */ > >>> +static void > >>> +lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *table) > >>> +{ > >>> + *table = (struct lr_lb_nat_data_table) { > >>> + .entries = HMAP_INITIALIZER(&table->entries), > >>> + }; > >>> +} > >>> + > >>> +static void > >>> +lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *table) > >>> +{ > >>> + lr_lb_nat_data_table_clear(table); > >>> + hmap_destroy(&table->entries); > >>> +} > >>> + > >>> +static void > >>> +lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *table) > >>> +{ > >>> + struct lr_lb_nat_data_record *lr_lbnat_rec; > >>> + HMAP_FOR_EACH_POP (lr_lbnat_rec, key_node, &table->entries) { > >>> + lr_lb_nat_data_record_destroy(lr_lbnat_rec); > >>> + } > >>> + > >>> + free(table->array); > >>> + table->array = NULL; > >>> +} > >>> + > >>> +static void > >>> +lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *table, > >>> + const struct lr_nat_table *lr_nats, > >>> + const struct ovn_datapaths *lr_datapaths, > >>> + const struct hmap *lb_datapaths_map, > >>> + const struct hmap *lbgrp_datapaths_map) > >>> +{ > >>> + table->array = xrealloc(table->array, > >>> + ods_size(lr_datapaths) * sizeof *table->array); > >>> + const struct lr_nat_record *lrnat_rec; > >>> + LR_NAT_TABLE_FOR_EACH (lrnat_rec, lr_nats) { > >>> + lr_lb_nat_data_record_create(table, lrnat_rec, lb_datapaths_map, > >>> + lbgrp_datapaths_map); > >>> + } > >>> +} > >>> + > >>> +static struct lr_lb_nat_data_record * > >>> +lr_lb_nat_data_table_find_(const struct lr_lb_nat_data_table *table, > >>> + const struct nbrec_logical_router *nbr) > >>> +{ > >>> + struct lr_lb_nat_data_record *lr_lbnat_rec; > >>> + > >>> + HMAP_FOR_EACH_WITH_HASH (lr_lbnat_rec, key_node, > >>> + uuid_hash(&nbr->header_.uuid), &table->entries) { > >>> + if (nbr == lr_lbnat_rec->od->nbr) { > >>> + return lr_lbnat_rec; > >>> + } > >>> + } > >>> + return NULL; > >>> +} > >>> + > >>> +static struct lr_lb_nat_data_record * > >>> +lr_lb_nat_data_table_find_by_index_(const struct lr_lb_nat_data_table *table, > >>> + size_t od_index) > >>> +{ > >>> + ovs_assert(od_index <= hmap_count(&table->entries)); > >>> + return table->array[od_index]; > >>> +} > >>> + > >>> +static struct lr_lb_nat_data_record * > >>> +lr_lb_nat_data_record_create(struct lr_lb_nat_data_table *table, > >>> + const struct lr_nat_record *lrnat_rec, > >>> + const struct hmap *lb_datapaths_map, > >>> + const struct hmap *lbgrp_datapaths_map) > >>> +{ > >>> + struct lr_lb_nat_data_record *lr_lbnat_rec = xzalloc(sizeof *lr_lbnat_rec); > >>> + lr_lbnat_rec->lrnat_rec = lrnat_rec; > >>> + lr_lbnat_rec->od = lrnat_rec->od; > >>> + lr_lb_nat_data_record_init(lr_lbnat_rec, lb_datapaths_map, > >>> + lbgrp_datapaths_map); > >>> + > >>> + hmap_insert(&table->entries, &lr_lbnat_rec->key_node, > >>> + uuid_hash(&lr_lbnat_rec->od->nbr->header_.uuid)); > >>> + > >>> + table->array[lr_lbnat_rec->od->index] = lr_lbnat_rec; > >>> + return lr_lbnat_rec; > >>> +} > >>> + > >>> +static void > >>> +lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *lr_lbnat_rec) > >>> +{ > >>> + ovn_lb_ip_set_destroy(lr_lbnat_rec->lb_ips); > >>> + lr_lbnat_rec->lb_ips = NULL; > >>> + sset_destroy(&lr_lbnat_rec->vip_nats); > >>> + free(lr_lbnat_rec); > >>> +} > >>> + > >>> +static void > >>> +lr_lb_nat_data_record_init(struct lr_lb_nat_data_record *lr_lbnat_rec, > >>> + const struct hmap *lb_datapaths_map, > >>> + const struct hmap *lbgrp_datapaths_map) > >>> +{ > >>> + const struct nbrec_load_balancer_group *nbrec_lb_group; > >>> + const struct ovn_lb_group_datapaths *lb_group_dps; > >>> + const struct ovn_lb_datapaths *lb_dps; > >>> + > >>> + /* Checking load balancer groups first, starting from the largest one, > >>> + * to more efficiently copy IP sets. */ > >>> + size_t largest_group = 0; > >>> + > >>> + const struct nbrec_logical_router *nbr = lr_lbnat_rec->od->nbr; > >>> + for (size_t i = 1; i < nbr->n_load_balancer_group; i++) { > >>> + if (nbr->load_balancer_group[i]->n_load_balancer > > >>> + nbr->load_balancer_group[largest_group]->n_load_balancer) { > >>> + largest_group = i; > >>> + } > >>> + } > >>> + > >>> + for (size_t i = 0; i < nbr->n_load_balancer_group; i++) { > >>> + size_t idx = (i + largest_group) % nbr->n_load_balancer_group; > >>> + > >>> + nbrec_lb_group = nbr->load_balancer_group[idx]; > >>> + const struct uuid *lbgrp_uuid = &nbrec_lb_group->header_.uuid; > >>> + > >>> + lb_group_dps = > >>> + ovn_lb_group_datapaths_find(lbgrp_datapaths_map, > >>> + lbgrp_uuid); > >>> + ovs_assert(lb_group_dps); > >>> + > >>> + if (!lr_lbnat_rec->lb_ips) { > >>> + lr_lbnat_rec->lb_ips = > >>> + ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); > >>> + } else { > >>> + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > >>> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, > >>> + lb_group_dps->lb_group->lbs[j]); > >>> + } > >>> + } > >>> + > >>> + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > >>> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, > >>> + lb_group_dps->lb_group->lbs[j]); > >>> + } > >>> + } > >>> + > >>> + if (!lr_lbnat_rec->lb_ips) { > >>> + lr_lbnat_rec->lb_ips = ovn_lb_ip_set_create(); > >>> + } > >>> + > >>> + for (size_t i = 0; i < nbr->n_load_balancer; i++) { > >>> + const struct uuid *lb_uuid = > >>> + &nbr->load_balancer[i]->header_.uuid; > >>> + lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); > >>> + ovs_assert(lb_dps); > >>> + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); > >>> + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); > >>> + } > >>> + > >>> + sset_init(&lr_lbnat_rec->vip_nats); > >>> + > >>> + if (!nbr->n_nat) { > >>> + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); > >>> + } > >>> +} > >>> + > >>> +static struct lr_lb_nat_data_input > >>> +lr_lb_nat_data_get_input_data(struct engine_node *node) > >>> +{ > >>> + struct northd_data *northd_data = engine_get_input_data("northd", node); > >>> + struct ed_type_lr_nat_data *lr_nat_data = > >>> + engine_get_input_data("lr_nat", node); > >>> + > >>> + return (struct lr_lb_nat_data_input) { > >>> + .lr_datapaths = &northd_data->lr_datapaths, > >>> + .lb_datapaths_map = &northd_data->lb_datapaths_map, > >>> + .lbgrp_datapaths_map = &northd_data->lb_group_datapaths_map, > >>> + .lr_nats = &lr_nat_data->lr_nats, > >>> + }; > >>> +} > >>> + > >>> +static void > >>> +build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, > >>> + const struct ovn_northd_lb *lb) > >>> +{ > >>> + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, &lb->ips_v4, > >>> + &lb->ips_v6); > >>> +} > >>> + > >>> +static void > >>> +add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *lr_lbnat_rec, > >>> + enum lb_neighbor_responder_mode neigh_mode, > >>> + const struct sset *lb_ips_v4, > >>> + const struct sset *lb_ips_v6) > >>> +{ > >>> + /* If configured to not reply to any neighbor requests for all VIPs > >>> + * return early. > >>> + */ > >>> + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > >>> + return; > >>> + } > >>> + > >>> + const char *ip_address; > >>> + > >>> + /* If configured to reply to neighbor requests for all VIPs force them > >>> + * all to be considered "reachable". > >>> + */ > >>> + if (neigh_mode == LB_NEIGH_RESPOND_ALL) { > >>> + SSET_FOR_EACH (ip_address, lb_ips_v4) { > >>> + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, ip_address); > >>> + } > >>> + SSET_FOR_EACH (ip_address, lb_ips_v6) { > >>> + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, ip_address); > >>> + } > >>> + > >>> + return; > >>> + } > >>> + > >>> + /* Otherwise, a VIP is reachable if there's at least one router > >>> + * subnet that includes it. > >>> + */ > >>> + ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); > >>> + > >>> + SSET_FOR_EACH (ip_address, lb_ips_v4) { > >>> + struct ovn_port *op; > >>> + ovs_be32 vip_ip4; > >>> + if (ip_parse(ip_address, &vip_ip4)) { > >>> + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { > >>> + if (lrouter_port_ipv4_reachable(op, vip_ip4)) { > >>> + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, > >>> + ip_address); > >>> + break; > >>> + } > >>> + } > >>> + } > >>> + } > >>> + > >>> + SSET_FOR_EACH (ip_address, lb_ips_v6) { > >>> + struct ovn_port *op; > >>> + struct in6_addr vip; > >>> + if (ipv6_parse(ip_address, &vip)) { > >>> + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { > >>> + if (lrouter_port_ipv6_reachable(op, &vip)) { > >>> + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, > >>> + ip_address); > >>> + break; > >>> + } > >>> + } > >>> + } > >>> + } > >>> +} > >>> + > >>> +static void > >>> +remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, > >>> + enum lb_neighbor_responder_mode neigh_mode, > >>> + const struct sset *lb_ips_v4, > >>> + const struct sset *lb_ips_v6) > >>> +{ > >>> + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > >>> + return; > >>> + } > >>> + > >>> + const char *ip_address; > >>> + SSET_FOR_EACH (ip_address, lb_ips_v4) { > >>> + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v4_reachable, > >>> + ip_address); > >>> + } > >>> + SSET_FOR_EACH (ip_address, lb_ips_v6) { > >>> + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v6_reachable, > >>> + ip_address); > >>> + } > >>> +} > >>> + > >>> +static void > >>> +lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *lr_lbnat_rec) > >>> +{ > >>> + sset_clear(&lr_lbnat_rec->vip_nats); > >>> + const char *external_ip; > >>> + SSET_FOR_EACH (external_ip, &lr_lbnat_rec->lrnat_rec->external_ips) { > >>> + bool is_vip_nat = false; > >>> + if (addr_is_ipv6(external_ip)) { > >>> + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, > >>> + external_ip); > >>> + } else { > >>> + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, > >>> + external_ip); > >>> + } > >>> + > >>> + if (is_vip_nat) { > >>> + sset_add(&lr_lbnat_rec->vip_nats, external_ip); > >>> + } > >>> + } > >>> +} > >>> diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h > >>> new file mode 100644 > >>> index 0000000000..9029aee339 > >>> --- /dev/null > >>> +++ b/northd/en-lr-lb-nat-data.h > >>> @@ -0,0 +1,93 @@ > >>> +/* > >>> + * Copyright (c) 2023, Red Hat, Inc. > >>> + * > >>> + * Licensed under the Apache License, Version 2.0 (the "License"); > >>> + * you may not use this file except in compliance with the License. > >>> + * You may obtain a copy of the License at: > >>> + * > >>> + * http://www.apache.org/licenses/LICENSE-2.0 > >>> + * > >>> + * Unless required by applicable law or agreed to in writing, software > >>> + * distributed under the License is distributed on an "AS IS" BASIS, > >>> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > >>> + * See the License for the specific language governing permissions and > >>> + * limitations under the License. > >>> + */ > >>> +#ifndef EN_LR_LB_NAT_DATA_H > >>> +#define EN_LR_LB_NAT_DATA_H 1 > >>> + > >>> +#include <stdint.h> > >>> + > >>> +/* OVS includes. */ > >>> +#include "lib/hmapx.h" > >>> +#include "openvswitch/hmap.h" > >>> +#include "sset.h" > >>> + > >>> +/* OVN includes. */ > >>> +#include "lib/inc-proc-eng.h" > >>> +#include "lib/lb.h" > >>> +#include "lib/ovn-nb-idl.h" > >>> +#include "lib/ovn-sb-idl.h" > >>> +#include "lib/ovn-util.h" > >>> + > >>> +struct ovn_datapath; > >>> +struct lr_nat_record; > >>> + > >>> +struct lr_lb_nat_data_record { > >>> + struct hmap_node key_node; /* Index on 'nbr->header_.uuid'. */ > >>> + > >>> + const struct ovn_datapath *od; > >>> + const struct lr_nat_record *lrnat_rec; > >>> + > >>> + /* Load Balancer vIPs relevant for this datapath. */ > >>> + struct ovn_lb_ip_set *lb_ips; > >>> + > >>> + /* sset of vips which are also part of lr nats. */ > >>> + struct sset vip_nats; > >>> +}; > >>> + > >>> +struct lr_lb_nat_data_table { > >>> + struct hmap entries; > >>> + > >>> + /* The array index of each element in 'entries'. */ > >>> + struct lr_lb_nat_data_record **array; > >>> +}; > >>> + > >>> +#define LR_LB_NAT_DATA_TABLE_FOR_EACH(LR_LB_NAT_REC, TABLE) \ > >>> + HMAP_FOR_EACH (LR_LB_NAT_REC, key_node, &(TABLE)->entries) > >>> + > >>> +struct lr_lb_nat_data_tracked_data { > >>> + /* Created or updated logical router with LB data. */ > >>> + struct hmapx crupdated; /* Stores 'struct lr_lb_nat_data_record'. */ > >>> + > >>> + /* Deleted logical router with LB data. */ > >>> + struct hmapx deleted; /* Stores 'struct lr_lb_nat_data_record'. */ > >>> +}; > >>> + > >>> +struct ed_type_lr_lb_nat_data { > >>> + struct lr_lb_nat_data_table lr_lbnats; > >>> + > >>> + bool tracked; > >>> + struct lr_lb_nat_data_tracked_data tracked_data; > >> > >> Same comment about 'tracked' as in the previous commit, we can probably > >> remove it. > >> > >> Which brings me to the following question, we don't really use > >> lr_lb_nat_data_tracked_data->deleted anywhere; we never add anything to > >> it. Is it on purpose, should we just delete it? Or is it a bug? It was on purpose. I removed it in v3. > >> > >> Thanks, > >> Dumitru > >> > >>> +}; > >>> + > >>> +struct lr_lb_nat_data_input { > >>> + const struct ovn_datapaths *lr_datapaths; > >>> + const struct hmap *lb_datapaths_map; > >>> + const struct hmap *lbgrp_datapaths_map; > >>> + const struct lr_nat_table *lr_nats; > >>> +}; > >>> + > >>> +void *en_lr_lb_nat_data_init(struct engine_node *, struct engine_arg *); > >>> +void en_lr_lb_nat_data_cleanup(void *data); > >>> +void en_lr_lb_nat_data_clear_tracked_data(void *data); > >>> +void en_lr_lb_nat_data_run(struct engine_node *, void *data); > >>> + > >>> +bool lr_lb_nat_data_northd_handler(struct engine_node *, void *data); > >>> +bool lr_lb_nat_data_lr_nat_handler(struct engine_node *, void *data); > >>> +bool lr_lb_nat_data_lb_data_handler(struct engine_node *, void *data); > >>> + > >>> +const struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index( > >>> + const struct lr_lb_nat_data_table *, size_t od_index); > >>> + > >>> +#endif /* EN_LR_LB_NAT_DATA_H */ > >>> \ No newline at end of file > > > > No newline at end of file. Ack. Addressed in v3. Thanks Numan > > > >>> diff --git a/northd/en-lr-nat.h b/northd/en-lr-nat.h > >>> index 01a16a21aa..2e3f285d12 100644 > >>> --- a/northd/en-lr-nat.h > >>> +++ b/northd/en-lr-nat.h > >>> @@ -89,6 +89,9 @@ struct lr_nat_table { > >>> const struct lr_nat_record * lr_nat_table_find_by_index( > >>> const struct lr_nat_table *, size_t od_index); > >>> > >>> +#define LR_NAT_TABLE_FOR_EACH(LR_NAT_REC, TABLE) \ > >>> + HMAP_FOR_EACH (LR_NAT_REC, key_node, &(TABLE)->entries) > >>> + > >>> /* Incremental processing implementation. */ > >>> struct lr_nat_input { > >>> /* Northbound table references. */ > >>> diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c > >>> index 10ade620e7..7c22949f74 100644 > >>> --- a/northd/en-sync-sb.c > >>> +++ b/northd/en-sync-sb.c > >>> @@ -22,6 +22,7 @@ > >>> #include "openvswitch/util.h" > >>> > >>> #include "en-lr-nat.h" > >>> +#include "en-lr-lb-nat-data.h" > >>> #include "en-sync-sb.h" > >>> #include "lib/inc-proc-eng.h" > >>> #include "lib/lb.h" > >>> @@ -41,7 +42,7 @@ static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > >>> const struct nbrec_address_set_table *, > >>> const struct nbrec_port_group_table *, > >>> const struct sbrec_address_set_table *, > >>> - const struct ovn_datapaths *lr_datapaths); > >>> + const struct lr_lb_nat_data_table *); > >>> static const struct sbrec_address_set *sb_address_set_lookup_by_name( > >>> struct ovsdb_idl_index *, const char *name); > >>> static void update_sb_addr_set(struct sorted_array *, > >>> @@ -87,11 +88,11 @@ en_sync_to_sb_addr_set_run(struct engine_node *node, void *data OVS_UNUSED) > >>> EN_OVSDB_GET(engine_get_input("SB_address_set", node)); > >>> > >>> const struct engine_context *eng_ctx = engine_get_context(); > >>> - struct northd_data *northd_data = engine_get_input_data("northd", node); > >>> - > >>> + const struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > >>> + engine_get_input_data("lr_lb_nat_data", node); > >>> sync_addr_sets(eng_ctx->ovnsb_idl_txn, nb_address_set_table, > >>> nb_port_group_table, sb_address_set_table, > >>> - &northd_data->lr_datapaths); > >>> + &lr_lb_nat_data->lr_lbnats); > >>> > >>> engine_set_node_state(node, EN_UPDATED); > >>> } > >>> @@ -288,10 +289,12 @@ en_sync_to_sb_pb_run(struct engine_node *node, void *data OVS_UNUSED) > >>> { > >>> const struct engine_context *eng_ctx = engine_get_context(); > >>> struct northd_data *northd_data = engine_get_input_data("northd", node); > >>> - struct ed_type_lr_nat_data *lr_nat_data = > >>> - engine_get_input_data("lr_nat", node); > >>> + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > >>> + engine_get_input_data("lr_lb_nat_data", node); > >>> + > >>> sync_pbs(eng_ctx->ovnsb_idl_txn, &northd_data->ls_ports, > >>> - &northd_data->lr_ports, &lr_nat_data->lr_nats); > >>> + &northd_data->lr_ports, > >>> + &lr_lb_nat_data->lr_lbnats); > >>> engine_set_node_state(node, EN_UPDATED); > >>> } > >>> > >>> @@ -316,11 +319,12 @@ sync_to_sb_pb_northd_handler(struct engine_node *node, void *data OVS_UNUSED) > >>> return false; > >>> } > >>> > >>> - struct ed_type_lr_nat_data *lr_nat_data = > >>> - engine_get_input_data("lr_nat", node); > >>> + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = > >>> + engine_get_input_data("lr_lb_nat_data", node); > >>> > >>> if (!sync_pbs_for_northd_changed_ovn_ports( > >>> - &nd->trk_northd_changes.trk_ovn_ports, &lr_nat_data->lr_nats)) { > >>> + &nd->trk_northd_changes.trk_ovn_ports, > >>> + &lr_lb_nat_data->lr_lbnats)) { > >>> return false; > >>> } > >>> > >>> @@ -366,7 +370,7 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > >>> const struct nbrec_address_set_table *nb_address_set_table, > >>> const struct nbrec_port_group_table *nb_port_group_table, > >>> const struct sbrec_address_set_table *sb_address_set_table, > >>> - const struct ovn_datapaths *lr_datapaths) > >>> + const struct lr_lb_nat_data_table *lr_lbnats) > >>> { > >>> struct shash sb_address_sets = SHASH_INITIALIZER(&sb_address_sets); > >>> > >>> @@ -410,16 +414,14 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > >>> } > >>> > >>> /* Sync router load balancer VIP generated address sets. */ > >>> - struct ovn_datapath *od; > >>> - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { > >>> - ovs_assert(od->nbr); > >>> - > >>> - if (sset_count(&od->lb_ips->ips_v4_reachable)) { > >>> - char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key, > >>> - AF_INET); > >>> + const struct lr_lb_nat_data_record *lrlb_rec; > >>> + LR_LB_NAT_DATA_TABLE_FOR_EACH (lrlb_rec, lr_lbnats) { > >>> + if (sset_count(&lrlb_rec->lb_ips->ips_v4_reachable)) { > >>> + char *ipv4_addrs_name = > >>> + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET); > >>> > >>> struct sorted_array ipv4_addrs_sorted = > >>> - sorted_array_from_sset(&od->lb_ips->ips_v4_reachable); > >>> + sorted_array_from_sset(&lrlb_rec->lb_ips->ips_v4_reachable); > >>> > >>> sync_addr_set(ovnsb_txn, ipv4_addrs_name, > >>> &ipv4_addrs_sorted, &sb_address_sets); > >>> @@ -427,11 +429,11 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, > >>> free(ipv4_addrs_name); > >>> } > >>> > >>> - if (sset_count(&od->lb_ips->ips_v6_reachable)) { > >>> - char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key, > >>> - AF_INET6); > >>> - struct sorted_array ipv6_addrs_sorted = > >>> - sorted_array_from_sset(&od->lb_ips->ips_v6_reachable); > >>> + if (sset_count(&lrlb_rec->lb_ips->ips_v6_reachable)) { > >>> + char *ipv6_addrs_name = > >>> + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET6); > >>> + struct sorted_array ipv6_addrs_sorted = sorted_array_from_sset( > >>> + &lrlb_rec->lb_ips->ips_v6_reachable); > >>> > >>> sync_addr_set(ovnsb_txn, ipv6_addrs_name, > >>> &ipv6_addrs_sorted, &sb_address_sets); > >>> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c > >>> index 2bd66b8808..369a151fa3 100644 > >>> --- a/northd/inc-proc-northd.c > >>> +++ b/northd/inc-proc-northd.c > >>> @@ -31,6 +31,7 @@ > >>> #include "openvswitch/vlog.h" > >>> #include "inc-proc-northd.h" > >>> #include "en-lb-data.h" > >>> +#include "en-lr-lb-nat-data.h" > >>> #include "en-lr-nat.h" > >>> #include "en-northd.h" > >>> #include "en-lflow.h" > >>> @@ -148,6 +149,7 @@ static ENGINE_NODE(sync_to_sb_lb, "sync_to_sb_lb"); > >>> static ENGINE_NODE(sync_to_sb_pb, "sync_to_sb_pb"); > >>> static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data"); > >>> static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_nat, "lr_nat"); > >>> +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_lb_nat_data, "lr_lb_nat_data"); > >>> > >>> void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > >>> struct ovsdb_idl_loop *sb) > >>> @@ -196,6 +198,13 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > >>> engine_add_input(&en_lr_nat, &en_nb_logical_router, > >>> lr_nat_logical_router_handler); > >>> > >>> + engine_add_input(&en_lr_lb_nat_data, &en_northd, > >>> + lr_lb_nat_data_northd_handler); > >>> + engine_add_input(&en_lr_lb_nat_data, &en_lr_nat, > >>> + lr_lb_nat_data_lr_nat_handler); > >>> + engine_add_input(&en_lr_lb_nat_data, &en_lb_data, > >>> + lr_lb_nat_data_lb_data_handler); > >>> + > >>> engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL); > >>> engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL); > >>> engine_add_input(&en_mac_binding_aging, &en_northd, NULL); > >>> @@ -220,12 +229,14 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > >>> engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); > >>> engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); > >>> engine_add_input(&en_lflow, &en_lr_nat, NULL); > >>> + engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); > >>> > >>> engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, > >>> sync_to_sb_addr_set_nb_address_set_handler); > >>> engine_add_input(&en_sync_to_sb_addr_set, &en_nb_port_group, > >>> sync_to_sb_addr_set_nb_port_group_handler); > >>> engine_add_input(&en_sync_to_sb_addr_set, &en_northd, NULL); > >>> + engine_add_input(&en_sync_to_sb_addr_set, &en_lr_lb_nat_data, NULL); > >>> engine_add_input(&en_sync_to_sb_addr_set, &en_sb_address_set, NULL); > >>> > >>> engine_add_input(&en_port_group, &en_nb_port_group, > >>> @@ -243,7 +254,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, > >>> > >>> engine_add_input(&en_sync_to_sb_pb, &en_northd, > >>> sync_to_sb_pb_northd_handler); > >>> - engine_add_input(&en_sync_to_sb_pb, &en_lr_nat, NULL); > >>> + engine_add_input(&en_sync_to_sb_pb, &en_lr_lb_nat_data, NULL); > >>> > >>> /* en_sync_to_sb engine node syncs the SB database tables from > >>> * the NB database tables. > >>> diff --git a/northd/northd.c b/northd/northd.c > >>> index 44c9c3d729..24df14c0de 100644 > >>> --- a/northd/northd.c > >>> +++ b/northd/northd.c > >>> @@ -44,6 +44,7 @@ > >>> #include "northd.h" > >>> #include "en-lb-data.h" > >>> #include "en-lr-nat.h" > >>> +#include "en-lr-lb-nat-data.h" > >>> #include "lib/ovn-parallel-hmap.h" > >>> #include "ovn/actions.h" > >>> #include "ovn/features.h" > >>> @@ -617,13 +618,6 @@ init_lb_for_datapath(struct ovn_datapath *od) > >>> } > >>> } > >>> > >>> -static void > >>> -destroy_lb_for_datapath(struct ovn_datapath *od) > >>> -{ > >>> - ovn_lb_ip_set_destroy(od->lb_ips); > >>> - od->lb_ips = NULL; > >>> -} > >>> - > >>> /* A group of logical router datapaths which are connected - either > >>> * directly or indirectly. > >>> * Each logical router can belong to only one group. */ > >>> @@ -676,7 +670,6 @@ ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od) > >>> destroy_ipam_info(&od->ipam_info); > >>> free(od->router_ports); > >>> free(od->ls_peers); > >>> - destroy_lb_for_datapath(od); > >>> free(od->localnet_ports); > >>> free(od->l3dgw_ports); > >>> destroy_mcast_info_for_datapath(od); > >>> @@ -1311,121 +1304,6 @@ struct lflow_ref_node { > >>> struct ovn_lflow *lflow; > >>> }; > >>> > >>> -/* A logical switch port or logical router port. > >>> - * > >>> - * In steady state, an ovn_port points to a northbound Logical_Switch_Port > >>> - * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a > >>> - * southbound Port_Binding record (via 'sb'). As the state of the system > >>> - * changes, join_logical_ports() may determine that there is a new LSP or LRP > >>> - * that has no corresponding Port_Binding record (in which case build_ports()) > >>> - * will create the missing Port_Binding) or that a Port_Binding record exists > >>> - * that has no coresponding LSP (in which case build_ports() will delete the > >>> - * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port > >>> - * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. > >>> - * > >>> - * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but > >>> - * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). > >>> - */ > >>> -struct ovn_port { > >>> - /* Port name aka key. > >>> - * > >>> - * This is ordinarily the same as nbsp->name or nbrp->name and > >>> - * sb->logical_port. (A distributed gateway port creates a "derived" > >>> - * ovn_port with key "cr-%s" % nbrp->name.) */ > >>> - struct hmap_node key_node; /* Index on 'key'. */ > >>> - char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ > >>> - char *json_key; /* 'key', quoted for use in JSON. */ > >>> - > >>> - const struct sbrec_port_binding *sb; /* May be NULL. */ > >>> - > >>> - uint32_t tunnel_key; > >>> - > >>> - /* Logical switch port data. */ > >>> - const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ > >>> - > >>> - struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ > >>> - unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ > >>> - unsigned int n_lsp_non_router_addrs; /* Number of elements from the > >>> - * beginning of 'lsp_addrs' extracted > >>> - * directly from LSP 'addresses'. */ > >>> - > >>> - struct lport_addresses *ps_addrs; /* Port security addresses. */ > >>> - unsigned int n_ps_addrs; > >>> - > >>> - bool lsp_can_be_inc_processed; /* If it can be incrementally processed when > >>> - the port changes. */ > >>> - > >>> - /* Logical router port data. */ > >>> - const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ > >>> - > >>> - struct lport_addresses lrp_networks; > >>> - > >>> - struct ovn_port_routable_addresses routables; > >>> - > >>> - /* Logical port multicast data. */ > >>> - struct mcast_port_info mcast_info; > >>> - > >>> - /* At most one of l3dgw_port and cr_port can be not NULL. */ > >>> - > >>> - /* This is set to a distributed gateway port if and only if this ovn_port > >>> - * is "derived" from it. Otherwise this is set to NULL. The derived > >>> - * ovn_port represents the instance of distributed gateway port on the > >>> - * gateway chassis.*/ > >>> - struct ovn_port *l3dgw_port; > >>> - > >>> - /* This is set to the "derived" chassis-redirect port of this port if and > >>> - * only if this port is a distributed gateway port. Otherwise this is set > >>> - * to NULL. */ > >>> - struct ovn_port *cr_port; > >>> - > >>> - bool has_unknown; /* If the addresses have 'unknown' defined. */ > >>> - > >>> - bool has_bfd; > >>> - > >>> - /* The port's peer: > >>> - * > >>> - * - A switch port S of type "router" has a router port R as a peer, > >>> - * and R in turn has S has its peer. > >>> - * > >>> - * - Two connected logical router ports have each other as peer. > >>> - * > >>> - * - Other kinds of ports have no peer. */ > >>> - struct ovn_port *peer; > >>> - > >>> - struct ovn_datapath *od; > >>> - > >>> - struct ovs_list list; /* In list of similar records. */ > >>> - > >>> - struct hmap_node dp_node; /* Node in od->ports. */ > >>> - > >>> - struct lport_addresses proxy_arp_addrs; > >>> - > >>> - /* Temporarily used for traversing a list (or hmap) of ports. */ > >>> - bool visited; > >>> - > >>> - /* List of struct lflow_ref_node that points to the lflows generated by > >>> - * this ovn_port. > >>> - * > >>> - * This data is initialized and destroyed by the en_northd node, but > >>> - * populated and used only by the en_lflow node. Ideally this data should > >>> - * be maintained as part of en_lflow's data (struct lflow_data): a hash > >>> - * index from ovn_port key to lflows. However, it would be less efficient > >>> - * and more complex: > >>> - * > >>> - * 1. It would require an extra search (using the index) to find the > >>> - * lflows. > >>> - * > >>> - * 2. Building the index needs to be thread-safe, using either a global > >>> - * lock which is obviously less efficient, or hash-based lock array which > >>> - * is more complex. > >>> - * > >>> - * Adding the list here is more straightforward. The drawback is that we > >>> - * need to keep in mind that this data belongs to en_lflow node, so never > >>> - * access it from any other nodes. > >>> - */ > >>> - struct ovs_list lflows; > >>> -}; > >>> - > >>> static bool lsp_can_be_inc_processed(const struct nbrec_logical_switch_port *); > >>> > >>> static bool > >>> @@ -1450,16 +1328,21 @@ destroy_routable_addresses(struct ovn_port_routable_addresses *ra) > >>> } > >>> > >>> static char **get_nat_addresses(const struct ovn_port *op, size_t *n, > >>> - bool routable_only, bool include_lb_ips); > >>> + bool routable_only, bool include_lb_ips, > >>> + const struct lr_lb_nat_data_record *); > >>> > >>> -static void > >>> -assign_routable_addresses(struct ovn_port *op) > >>> +static struct ovn_port_routable_addresses > >>> +get_op_routable_addresses(struct ovn_port *op, > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec) > >>> { > >>> size_t n; > >>> - char **nats = get_nat_addresses(op, &n, true, true); > >>> + char **nats = get_nat_addresses(op, &n, true, true, lr_lbnat_rec); > >>> > >>> if (!nats) { > >>> - return; > >>> + return (struct ovn_port_routable_addresses) { > >>> + .laddrs = NULL, > >>> + .n_addrs = 0, > >>> + }; > >>> } > >>> > >>> struct lport_addresses *laddrs = xcalloc(n, sizeof(*laddrs)); > >>> @@ -1475,9 +1358,15 @@ assign_routable_addresses(struct ovn_port *op) > >>> } > >>> free(nats); > >>> > >>> - /* Everything seems to have worked out */ > >>> - op->routables.laddrs = laddrs; > >>> - op->routables.n_addrs = n_addrs; > >>> + if (!n_addrs) { > >>> + free(laddrs); > >>> + laddrs = NULL; > >>> + } > >>> + > >>> + return (struct ovn_port_routable_addresses) { > >>> + .laddrs = laddrs, > >>> + .n_addrs = n_addrs, > >>> + }; > >>> } > >>> > >>> > >>> @@ -1537,8 +1426,6 @@ ovn_port_destroy_orphan(struct ovn_port *port) > >>> } > >>> free(port->ps_addrs); > >>> > >>> - destroy_routable_addresses(&port->routables); > >>> - > >>> destroy_lport_addresses(&port->lrp_networks); > >>> destroy_lport_addresses(&port->proxy_arp_addrs); > >>> free(port->json_key); > >>> @@ -2580,9 +2467,7 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, > >>> sizeof *od->l3dgw_ports); > >>> } > >>> od->l3dgw_ports[od->n_l3dgw_ports++] = op; > >>> - > >>> - assign_routable_addresses(op); > >>> - } > >>> + } > >>> } > >>> } > >>> > >>> @@ -2679,7 +2564,8 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, > >>> * and must free the returned array when it is no longer needed. */ > >>> static char ** > >>> get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, > >>> - bool include_lb_ips) > >>> + bool include_lb_ips, > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec) > >>> { > >>> size_t n_nats = 0; > >>> struct eth_addr mac; > >>> @@ -2764,23 +2650,25 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, > >>> } > >>> } > >>> > >>> - if (include_lb_ips) { > >>> + if (include_lb_ips && lr_lbnat_rec) { > >>> const char *ip_address; > >>> if (routable_only) { > >>> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4_routable) { > >>> + SSET_FOR_EACH (ip_address, > >>> + &lr_lbnat_rec->lb_ips->ips_v4_routable) { > >>> ds_put_format(&c_addresses, " %s", ip_address); > >>> central_ip_address = true; > >>> } > >>> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6_routable) { > >>> + SSET_FOR_EACH (ip_address, > >>> + &lr_lbnat_rec->lb_ips->ips_v6_routable) { > >>> ds_put_format(&c_addresses, " %s", ip_address); > >>> central_ip_address = true; > >>> } > >>> } else { > >>> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4) { > >>> + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v4) { > >>> ds_put_format(&c_addresses, " %s", ip_address); > >>> central_ip_address = true; > >>> } > >>> - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6) { > >>> + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v6) { > >>> ds_put_format(&c_addresses, " %s", ip_address); > >>> central_ip_address = true; > >>> } > >>> @@ -3851,21 +3739,8 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, > >>> HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { > >>> ovs_assert(od->nbr); > >>> > >>> - /* Checking load balancer groups first, starting from the largest one, > >>> - * to more efficiently copy IP sets. */ > >>> - size_t largest_group = 0; > >>> - > >>> - for (size_t i = 1; i < od->nbr->n_load_balancer_group; i++) { > >>> - if (od->nbr->load_balancer_group[i]->n_load_balancer > > >>> - od->nbr->load_balancer_group[largest_group]->n_load_balancer) { > >>> - largest_group = i; > >>> - } > >>> - } > >>> - > >>> for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { > >>> - size_t idx = (i + largest_group) % od->nbr->n_load_balancer_group; > >>> - > >>> - nbrec_lb_group = od->nbr->load_balancer_group[idx]; > >>> + nbrec_lb_group = od->nbr->load_balancer_group[i]; > >>> const struct uuid *lb_group_uuid = &nbrec_lb_group->header_.uuid; > >>> > >>> lb_group_dps = > >>> @@ -3873,20 +3748,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, > >>> lb_group_uuid); > >>> ovs_assert(lb_group_dps); > >>> ovn_lb_group_datapaths_add_lr(lb_group_dps, od); > >>> - > >>> - if (!od->lb_ips) { > >>> - od->lb_ips = > >>> - ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); > >>> - } else { > >>> - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > >>> - build_lrouter_lb_ips(od->lb_ips, > >>> - lb_group_dps->lb_group->lbs[j]); > >>> - } > >>> - } > >>> - } > >>> - > >>> - if (!od->lb_ips) { > >>> - od->lb_ips = ovn_lb_ip_set_create(); > >>> } > >>> > >>> for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { > >>> @@ -3895,7 +3756,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, > >>> lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); > >>> ovs_assert(lb_dps); > >>> ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > >>> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > >>> } > >>> } > >>> > >>> @@ -3949,102 +3809,6 @@ build_lb_svcs( > >>> } > >>> } > >>> > >>> -static bool lrouter_port_ipv4_reachable(const struct ovn_port *op, > >>> - ovs_be32 addr); > >>> -static bool lrouter_port_ipv6_reachable(const struct ovn_port *op, > >>> - const struct in6_addr *addr); > >>> - > >>> -static void > >>> -add_neigh_ips_to_lrouter(struct ovn_datapath *od, > >>> - enum lb_neighbor_responder_mode neigh_mode, > >>> - const struct sset *lb_ips_v4, > >>> - const struct sset *lb_ips_v6) > >>> -{ > >>> - /* If configured to not reply to any neighbor requests for all VIPs > >>> - * return early. > >>> - */ > >>> - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > >>> - return; > >>> - } > >>> - > >>> - const char *ip_address; > >>> - > >>> - /* If configured to reply to neighbor requests for all VIPs force them > >>> - * all to be considered "reachable". > >>> - */ > >>> - if (neigh_mode == LB_NEIGH_RESPOND_ALL) { > >>> - SSET_FOR_EACH (ip_address, lb_ips_v4) { > >>> - sset_add(&od->lb_ips->ips_v4_reachable, ip_address); > >>> - } > >>> - SSET_FOR_EACH (ip_address, lb_ips_v6) { > >>> - sset_add(&od->lb_ips->ips_v6_reachable, ip_address); > >>> - } > >>> - > >>> - return; > >>> - } > >>> - > >>> - /* Otherwise, a VIP is reachable if there's at least one router > >>> - * subnet that includes it. > >>> - */ > >>> - ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); > >>> - > >>> - SSET_FOR_EACH (ip_address, lb_ips_v4) { > >>> - struct ovn_port *op; > >>> - ovs_be32 vip_ip4; > >>> - if (ip_parse(ip_address, &vip_ip4)) { > >>> - HMAP_FOR_EACH (op, dp_node, &od->ports) { > >>> - if (lrouter_port_ipv4_reachable(op, vip_ip4)) { > >>> - sset_add(&od->lb_ips->ips_v4_reachable, > >>> - ip_address); > >>> - break; > >>> - } > >>> - } > >>> - } > >>> - } > >>> - > >>> - SSET_FOR_EACH (ip_address, lb_ips_v6) { > >>> - struct ovn_port *op; > >>> - struct in6_addr vip; > >>> - if (ipv6_parse(ip_address, &vip)) { > >>> - HMAP_FOR_EACH (op, dp_node, &od->ports) { > >>> - if (lrouter_port_ipv6_reachable(op, &vip)) { > >>> - sset_add(&od->lb_ips->ips_v6_reachable, > >>> - ip_address); > >>> - break; > >>> - } > >>> - } > >>> - } > >>> - } > >>> -} > >>> - > >>> -static void > >>> -remove_lrouter_lb_reachable_ips(struct ovn_datapath *od, > >>> - enum lb_neighbor_responder_mode neigh_mode, > >>> - const struct sset *lb_ips_v4, > >>> - const struct sset *lb_ips_v6) > >>> -{ > >>> - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { > >>> - return; > >>> - } > >>> - > >>> - const char *ip_address; > >>> - SSET_FOR_EACH (ip_address, lb_ips_v4) { > >>> - sset_find_and_delete(&od->lb_ips->ips_v4_reachable, ip_address); > >>> - } > >>> - SSET_FOR_EACH (ip_address, lb_ips_v6) { > >>> - sset_find_and_delete(&od->lb_ips->ips_v6_reachable, ip_address); > >>> - } > >>> -} > >>> - > >>> -static void > >>> -build_lrouter_lb_reachable_ips(struct ovn_datapath *od, > >>> - const struct ovn_northd_lb *lb) > >>> -{ > >>> - add_neigh_ips_to_lrouter(od, lb->neigh_mode, &lb->ips_v4, > >>> - &lb->ips_v6); > >>> -} > >>> - > >>> - > >>> static void > >>> build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) > >>> { > >>> @@ -4066,43 +3830,6 @@ build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) > >>> } > >>> } > >>> > >>> -static void > >>> -build_lrouter_lbs_reachable_ips(struct ovn_datapaths *lr_datapaths, > >>> - struct hmap *lb_dps_map, > >>> - struct hmap *lb_group_dps_map) > >>> -{ > >>> - struct ovn_datapath *od; > >>> - > >>> - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { > >>> - if (!od->nbr) { > >>> - continue; > >>> - } > >>> - > >>> - for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { > >>> - struct ovn_lb_datapaths *lb_dps = > >>> - ovn_lb_datapaths_find(lb_dps_map, > >>> - &od->nbr->load_balancer[i]->header_.uuid); > >>> - ovs_assert(lb_dps); > >>> - build_lrouter_lb_reachable_ips(od, lb_dps->lb); > >>> - } > >>> - > >>> - for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { > >>> - const struct nbrec_load_balancer_group *nbrec_lb_group = > >>> - od->nbr->load_balancer_group[i]; > >>> - struct ovn_lb_group_datapaths *lb_group_dps; > >>> - > >>> - lb_group_dps = > >>> - ovn_lb_group_datapaths_find(lb_group_dps_map, > >>> - &nbrec_lb_group->header_.uuid); > >>> - ovs_assert(lb_group_dps); > >>> - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { > >>> - build_lrouter_lb_reachable_ips(od, > >>> - lb_group_dps->lb_group->lbs[j]); > >>> - } > >>> - } > >>> - } > >>> -} > >>> - > >>> static void > >>> build_lswitch_lbs_from_lrouter(struct ovn_datapaths *lr_datapaths, > >>> struct hmap *lb_dps_map, > >>> @@ -4166,8 +3893,6 @@ build_lb_port_related_data( > >>> struct hmap *svc_monitor_map) > >>> { > >>> build_lrouter_lbs_check(lr_datapaths); > >>> - build_lrouter_lbs_reachable_ips(lr_datapaths, lb_dps_map, > >>> - lb_group_dps_map); > >>> build_lb_svcs(ovnsb_txn, sbrec_service_monitor_table, ls_ports, lb_dps_map, > >>> svc_monitor_lsps, svc_monitor_map); > >>> build_lswitch_lbs_from_lrouter(lr_datapaths, lb_dps_map, lb_group_dps_map); > >>> @@ -4533,7 +4258,8 @@ check_sb_lb_duplicates(const struct sbrec_load_balancer_table *table) > >>> * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it > >>> * only syncs the nat column of port binding corresponding to the 'op->nbsp' */ > >>> static void > >>> -sync_pb_for_lsp(struct ovn_port *op) > >>> +sync_pb_for_lsp(struct ovn_port *op, > >>> + const struct lr_lb_nat_data_table *lr_lbnats) > >>> { > >>> ovs_assert(op->nbsp); > >>> > >>> @@ -4552,10 +4278,17 @@ sync_pb_for_lsp(struct ovn_port *op) > >>> if (nat_addresses && !strcmp(nat_addresses, "router")) { > >>> if (op->peer && op->peer->od > >>> && (chassis || op->peer->od->n_l3dgw_ports)) { > >>> - bool exclude_lb_vips = smap_get_bool(&op->nbsp->options, > >>> + bool include_lb_vips = !smap_get_bool(&op->nbsp->options, > >>> "exclude-lb-vips-from-garp", false); > >>> + > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; > >>> + > >>> + if (include_lb_vips) { > >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index( > >>> + lr_lbnats, op->peer->od->index); > >>> + } > >>> nats = get_nat_addresses(op->peer, &n_nats, false, > >>> - !exclude_lb_vips); > >>> + include_lb_vips, lr_lbnat_rec); > >>> } > >>> } else if (nat_addresses && (chassis || l3dgw_ports)) { > >>> struct lport_addresses laddrs; > >>> @@ -4662,7 +4395,8 @@ sync_pb_for_lsp(struct ovn_port *op) > >>> * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it > >>> * only sets the port binding options column for the router ports */ > >>> static void > >>> -sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) > >>> +sync_pb_for_lrp(struct ovn_port *op, > >>> + const struct lr_lb_nat_data_table *lr_lbnats) > >>> { > >>> ovs_assert(op->nbrp); > >>> > >>> @@ -4671,14 +4405,14 @@ sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) > >>> > >>> const char *chassis_name = smap_get(&op->od->nbr->options, "chassis"); > >>> if (is_cr_port(op)) { > >>> - const struct lr_nat_record *lrnat_rec = > >>> - lr_nat_table_find_by_index(lr_nats, op->od->index); > >>> - ovs_assert(lrnat_rec); > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec = > >>> + lr_lb_nat_data_table_find_by_index(lr_lbnats, op->od->index); > >>> + ovs_assert(lr_lbnat_rec); > >>> > >>> smap_add(&new, "distributed-port", op->nbrp->name); > >>> > >>> bool always_redirect = > >>> - !lrnat_rec->has_distributed_nat && > >>> + !lr_lbnat_rec->lrnat_rec->has_distributed_nat && > >>> !l3dgw_port_has_associated_vtep_lports(op->l3dgw_port); > >>> > >>> const char *redirect_type = smap_get(&op->nbrp->options, > >>> @@ -4729,17 +4463,18 @@ static void ovn_update_ipv6_opt_for_op(struct ovn_port *op); > >>> * the logical switch ports. */ > >>> void > >>> sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, > >>> - struct hmap *lr_ports, const struct lr_nat_table *lr_nats) > >>> + struct hmap *lr_ports, > >>> + const struct lr_lb_nat_data_table *lr_lbnats) > >>> { > >>> ovs_assert(ovnsb_idl_txn); > >>> > >>> struct ovn_port *op; > >>> HMAP_FOR_EACH (op, key_node, ls_ports) { > >>> - sync_pb_for_lsp(op); > >>> + sync_pb_for_lsp(op, lr_lbnats); > >>> } > >>> > >>> HMAP_FOR_EACH (op, key_node, lr_ports) { > >>> - sync_pb_for_lrp(op, lr_nats); > >>> + sync_pb_for_lrp(op, lr_lbnats); > >>> } > >>> > >>> ovn_update_ipv6_options(lr_ports); > >>> @@ -4748,17 +4483,18 @@ sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, > >>> /* Sync the SB Port bindings for the added and updated logical switch ports > >>> * of the tracked northd engine data. */ > >>> bool > >>> -sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, > >>> - const struct lr_nat_table *lr_nats) > >>> +sync_pbs_for_northd_changed_ovn_ports( > >>> + struct tracked_ovn_ports *trk_ovn_ports, > >>> + const struct lr_lb_nat_data_table *lr_lbnats) > >>> { > >>> struct hmapx_node *hmapx_node; > >>> struct ovn_port *op; > >>> HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->created) { > >>> op = hmapx_node->data; > >>> if (op->nbsp) { > >>> - sync_pb_for_lsp(op); > >>> + sync_pb_for_lsp(op, lr_lbnats); > >>> } else { > >>> - sync_pb_for_lrp(op, lr_nats); > >>> + sync_pb_for_lrp(op, lr_lbnats); > >>> ovn_update_ipv6_opt_for_op(op); > >>> } > >>> } > >>> @@ -4766,9 +4502,9 @@ sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, > >>> HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->updated) { > >>> op = hmapx_node->data; > >>> if (op->nbsp) { > >>> - sync_pb_for_lsp(op); > >>> + sync_pb_for_lsp(op, lr_lbnats); > >>> } else { > >>> - sync_pb_for_lrp(op, lr_nats); > >>> + sync_pb_for_lrp(op, lr_lbnats); > >>> ovn_update_ipv6_opt_for_op(op); > >>> } > >>> } > >>> @@ -5475,20 +5211,24 @@ fail: > >>> } > >>> > >>> /* Returns true if the logical router has changes which can be > >>> - * incrementally handled. > >>> + * incrementally handled or the changes can be ignored. > >>> * Presently supports i-p for the below changes: > >>> * - load balancers and load balancer groups. > >>> + * > >>> + * Presently below changes are ignored: > >>> + * - router NAT changes - as the engine node lr-nat handles it. > >>> */ > >>> static bool > >>> -lr_changes_can_be_handled( > >>> +lr_changes_can_be_handled_or_ignored( > >>> const struct nbrec_logical_router *lr) > >>> { > >>> /* Check if the columns are changed in this row. */ > >>> enum nbrec_logical_router_column_id col; > >>> for (col = 0; col < NBREC_LOGICAL_ROUTER_N_COLUMNS; col++) { > >>> if (nbrec_logical_router_is_updated(lr, col)) { > >>> - if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER || > >>> - col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP) { > >>> + if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER > >>> + || col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP > >>> + || col == NBREC_LOGICAL_ROUTER_COL_NAT) { > >>> continue; > >>> } > >>> return false; > >>> @@ -5507,12 +5247,6 @@ lr_changes_can_be_handled( > >>> OVSDB_IDL_CHANGE_MODIFY) > 0) { > >>> return false; > >>> } > >>> - for (size_t i = 0; i < lr->n_nat; i++) { > >>> - if (nbrec_nat_row_get_seqno(lr->nat[i], > >>> - OVSDB_IDL_CHANGE_MODIFY) > 0) { > >>> - return false; > >>> - } > >>> - } > >>> for (size_t i = 0; i < lr->n_policies; i++) { > >>> if (nbrec_logical_router_policy_row_get_seqno(lr->policies[i], > >>> OVSDB_IDL_CHANGE_MODIFY) > 0) { > >>> @@ -5528,14 +5262,15 @@ lr_changes_can_be_handled( > >>> return true; > >>> } > >>> > >>> -/* Return true if changes are handled incrementally, false otherwise. > >>> +/* Return true if changes are handled incrementally or can be safely > >>> + * ignored (because those changes are handled by other engine nodes), > >>> + * false otherwise. > >>> * When there are any changes, try to track what's exactly changed and set > >>> * northd_data->change_tracked accordingly: change tracked - true, otherwise, > >>> * false. > >>> * Note: Changes to load balancer and load balancer groups associated with > >>> * the logical routers are handled separately in the lb_data change > >>> - * handlers (northd_handle_lb_data_changes_pre_od and > >>> - * northd_handle_lb_data_changes_post_od). > >>> + * handler (northd_handle_lb_data_changes). > >>> * */ > >>> bool > >>> northd_handle_lr_changes(const struct northd_input *ni, > >>> @@ -5550,9 +5285,11 @@ northd_handle_lr_changes(const struct northd_input *ni, > >>> goto fail; > >>> } > >>> > >>> - /* Presently only able to handle load balancer and > >>> - * load balancer group changes. */ > >>> - if (!lr_changes_can_be_handled(changed_lr)) { > >>> + /* Presently > >>> + * - only able to handle load balancer and load balancer group > >>> + changes. > >>> + * - and ignore NAT changes */ > >>> + if (!lr_changes_can_be_handled_or_ignored(changed_lr)) { > >>> goto fail; > >>> } > >>> } > >>> @@ -5804,10 +5541,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > >>> ovs_assert(lb_dps); > >>> ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > >>> > >>> - /* Add the lb_ips of lb_dps to the od. */ > >>> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > >>> - build_lrouter_lb_reachable_ips(od, lb_dps->lb); > >>> - > >>> /* Add the lb to the northd tracked data. */ > >>> hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); > >>> } > >>> @@ -5826,10 +5559,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > >>> ovs_assert(lb_dps); > >>> ovn_lb_datapaths_add_lr(lb_dps, 1, &od); > >>> > >>> - /* Add the lb_ips of lb_dps to the od. */ > >>> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > >>> - build_lrouter_lb_reachable_ips(od, lb_dps->lb); > >>> - > >>> /* Add the lb to the northd tracked data. */ > >>> hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); > >>> } > >>> @@ -5865,22 +5594,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > >>> /* Re-evaluate 'od->has_lb_vip' */ > >>> init_lb_for_datapath(od); > >>> > >>> - /* Update the od->lb_ips with the deleted and inserted > >>> - * vips (if any). */ > >>> - remove_ips_from_lb_ip_set(od->lb_ips, lb->routable, > >>> - &clb->deleted_vips_v4, > >>> - &clb->deleted_vips_v6); > >>> - add_ips_to_lb_ip_set(od->lb_ips, lb->routable, > >>> - &clb->inserted_vips_v4, > >>> - &clb->inserted_vips_v6); > >>> - > >>> - remove_lrouter_lb_reachable_ips(od, lb->neigh_mode, > >>> - &clb->deleted_vips_v4, > >>> - &clb->deleted_vips_v6); > >>> - add_neigh_ips_to_lrouter(od, lb->neigh_mode, > >>> - &clb->inserted_vips_v4, > >>> - &clb->inserted_vips_v6); > >>> - > >>> /* Add the lr datapath to the northd tracked data. */ > >>> hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > >>> } > >>> @@ -5908,9 +5621,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, > >>> /* Re-evaluate 'od->has_lb_vip' */ > >>> init_lb_for_datapath(od); > >>> > >>> - /* Add the lb_ips of lb_dps to the od. */ > >>> - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); > >>> - > >>> /* Add the lr datapath to the northd tracked data. */ > >>> hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); > >>> } > >>> @@ -9202,7 +8912,7 @@ arp_nd_ns_match(const char *ips, int addr_family, struct ds *match) > >>> /* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the > >>> * IPs configured on the router port. > >>> */ > >>> -static bool > >>> +bool > >>> lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) > >>> { > >>> for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { > >>> @@ -9218,7 +8928,7 @@ lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) > >>> /* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the > >>> * IPs configured on the router port. > >>> */ > >>> -static bool > >>> +bool > >>> lrouter_port_ipv6_reachable(const struct ovn_port *op, > >>> const struct in6_addr *addr) > >>> { > >>> @@ -9284,6 +8994,7 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, > >>> struct ovn_datapath *sw_od, > >>> struct ovn_port *sw_op, > >>> const struct lr_nat_table *lr_nats, > >>> + const struct lr_lb_nat_data_table *lr_lbnats, > >>> struct hmap *lflows, > >>> const struct ovsdb_idl_row *stage_hint) > >>> { > >>> @@ -9299,32 +9010,38 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, > >>> * router port. > >>> * Priority: 80. > >>> */ > >>> - > >>> - const char *ip_addr; > >>> - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v4_reachable) { > >>> - ovs_be32 ipv4_addr; > >>> - > >>> - /* Check if the ovn port has a network configured on which we could > >>> - * expect ARP requests for the LB VIP. > >>> - */ > >>> - if (ip_parse(ip_addr, &ipv4_addr) && > >>> - lrouter_port_ipv4_reachable(op, ipv4_addr)) { > >>> - build_lswitch_rport_arp_req_flow( > >>> - ip_addr, AF_INET, sw_op, sw_od, 80, lflows, > >>> - stage_hint); > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; > >>> + if (op->od->nbr->n_load_balancer || op->od->nbr->n_load_balancer_group) { > >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, > >>> + op->od->index); > >>> + ovs_assert(lr_lbnat_rec); > >>> + > >>> + const char *ip_addr; > >>> + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v4_reachable) { > >>> + ovs_be32 ipv4_addr; > >>> + > >>> + /* Check if the ovn port has a network configured on which we could > >>> + * expect ARP requests for the LB VIP. > >>> + */ > >>> + if (ip_parse(ip_addr, &ipv4_addr) && > >>> + lrouter_port_ipv4_reachable(op, ipv4_addr)) { > >>> + build_lswitch_rport_arp_req_flow( > >>> + ip_addr, AF_INET, sw_op, sw_od, 80, lflows, > >>> + stage_hint); > >>> + } > >>> } > >>> - } > >>> - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v6_reachable) { > >>> - struct in6_addr ipv6_addr; > >>> + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v6_reachable) { > >>> + struct in6_addr ipv6_addr; > >>> > >>> - /* Check if the ovn port has a network configured on which we could > >>> - * expect NS requests for the LB VIP. > >>> - */ > >>> - if (ipv6_parse(ip_addr, &ipv6_addr) && > >>> - lrouter_port_ipv6_reachable(op, &ipv6_addr)) { > >>> - build_lswitch_rport_arp_req_flow( > >>> - ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, > >>> - stage_hint); > >>> + /* Check if the ovn port has a network configured on which we could > >>> + * expect NS requests for the LB VIP. > >>> + */ > >>> + if (ipv6_parse(ip_addr, &ipv6_addr) && > >>> + lrouter_port_ipv6_reachable(op, &ipv6_addr)) { > >>> + build_lswitch_rport_arp_req_flow( > >>> + ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, > >>> + stage_hint); > >>> + } > >>> } > >>> } > >>> > >>> @@ -9374,13 +9091,15 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, > >>> * expect ARP requests/NS for the DNAT external_ip. > >>> */ > >>> if (nat_entry_is_v6(nat_entry)) { > >>> - if (!sset_contains(&op->od->lb_ips->ips_v6, nat->external_ip)) { > >>> + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, > >>> + nat->external_ip)) { > >>> build_lswitch_rport_arp_req_flow( > >>> nat->external_ip, AF_INET6, sw_op, sw_od, 80, lflows, > >>> stage_hint); > >>> } > >>> } else { > >>> - if (!sset_contains(&op->od->lb_ips->ips_v4, nat->external_ip)) { > >>> + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, > >>> + nat->external_ip)) { > >>> build_lswitch_rport_arp_req_flow( > >>> nat->external_ip, AF_INET, sw_op, sw_od, 80, lflows, > >>> stage_hint); > >>> @@ -10441,6 +10160,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, > >>> static void > >>> build_lswitch_ip_unicast_lookup(struct ovn_port *op, > >>> const struct lr_nat_table *lr_nats, > >>> + const struct lr_lb_nat_data_table *lr_lbnats, > >>> struct hmap *lflows, > >>> struct ds *actions, > >>> struct ds *match) > >>> @@ -10456,7 +10176,8 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op, > >>> */ > >>> if (lsp_is_router(op->nbsp)) { > >>> build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lr_nats, > >>> - lflows, &op->nbsp->header_); > >>> + lr_lbnats, lflows, > >>> + &op->nbsp->header_); > >>> } > >>> > >>> for (size_t i = 0; i < op->nbsp->n_addresses; i++) { > >>> @@ -12646,6 +12367,7 @@ build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op, > >>> static void > >>> build_lrouter_drop_own_dest(struct ovn_port *op, > >>> const struct lr_nat_record *lrnat_rec, > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec, > >>> enum ovn_stage stage, > >>> uint16_t priority, bool drop_snat_ip, > >>> struct hmap *lflows) > >>> @@ -12658,8 +12380,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, > >>> > >>> bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, > >>> ip); > >>> - bool router_ip_in_lb_ips = > >>> - !!sset_find(&op->od->lb_ips->ips_v4, ip); > >>> + bool router_ip_in_lb_ips = (lr_lbnat_rec && > >>> + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v4, > >>> + ip)); > >>> bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || > >>> router_ip_in_lb_ips)); > >>> > >>> @@ -12688,8 +12411,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, > >>> > >>> bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, > >>> ip); > >>> - bool router_ip_in_lb_ips = > >>> - !!sset_find(&op->od->lb_ips->ips_v6, ip); > >>> + bool router_ip_in_lb_ips = (lr_lbnat_rec && > >>> + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v6, > >>> + ip)); > >>> bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || > >>> router_ip_in_lb_ips)); > >>> > >>> @@ -13401,7 +13125,8 @@ build_ip_routing_flows_for_lrp( > >>> */ > >>> static void > >>> build_ip_routing_flows_for_router_type_lsp( > >>> - struct ovn_port *op, const struct hmap *lr_ports, struct hmap *lflows) > >>> + struct ovn_port *op, const struct lr_lb_nat_data_table *lr_lbnats, > >>> + const struct hmap *lr_ports, struct hmap *lflows) > >>> { > >>> ovs_assert(op->nbsp); > >>> if (!lsp_is_router(op->nbsp)) { > >>> @@ -13409,7 +13134,8 @@ build_ip_routing_flows_for_router_type_lsp( > >>> } > >>> > >>> struct ovn_port *peer = ovn_port_get_peer(lr_ports, op); > >>> - if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs) { > >>> + if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs > >>> + || !op->od->n_router_ports) { > >>> return; > >>> } > >>> > >>> @@ -13420,19 +13146,29 @@ build_ip_routing_flows_for_router_type_lsp( > >>> continue; > >>> } > >>> > >>> - struct ovn_port_routable_addresses *ra = &router_port->routables; > >>> - for (size_t j = 0; j < ra->n_addrs; j++) { > >>> - struct lport_addresses *laddrs = &ra->laddrs[j]; > >>> - for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { > >>> - add_route(lflows, peer->od, peer, > >>> - peer->lrp_networks.ipv4_addrs[0].addr_s, > >>> - laddrs->ipv4_addrs[k].network_s, > >>> - laddrs->ipv4_addrs[k].plen, NULL, false, 0, > >>> - &peer->nbrp->header_, false, > >>> - ROUTE_PRIO_OFFSET_CONNECTED); > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec = > >>> + lr_lb_nat_data_table_find_by_index(lr_lbnats, > >>> + router_port->od->index); > >>> + > >>> + if (router_port->nbrp->ha_chassis_group || > >>> + router_port->nbrp->n_gateway_chassis) { > >>> + struct ovn_port_routable_addresses ra = > >>> + get_op_routable_addresses(router_port, lr_lbnat_rec); > >>> + for (size_t j = 0; j < ra.n_addrs; j++) { > >>> + struct lport_addresses *laddrs = &ra.laddrs[j]; > >>> + for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { > >>> + add_route(lflows, peer->od, peer, > >>> + peer->lrp_networks.ipv4_addrs[0].addr_s, > >>> + laddrs->ipv4_addrs[k].network_s, > >>> + laddrs->ipv4_addrs[k].plen, NULL, false, 0, > >>> + &peer->nbrp->header_, false, > >>> + ROUTE_PRIO_OFFSET_CONNECTED); > >>> + } > >>> } > >>> + destroy_routable_addresses(&ra); > >>> } > >>> } > >>> + > >>> } > >>> > >>> static void > >>> @@ -13656,33 +13392,36 @@ build_arp_resolve_flows_for_lrouter( > >>> > >>> static void > >>> routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, > >>> - struct ovn_port *peer, struct ds *match, > >>> - struct ds *actions) > >>> + struct ovn_port *peer, > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec, > >>> + struct ds *match, struct ds *actions) > >>> { > >>> - struct ovn_port_routable_addresses *ra = &router_port->routables; > >>> - if (!ra->n_addrs) { > >>> + struct ovn_port_routable_addresses ra = > >>> + get_op_routable_addresses(router_port, lr_lbnat_rec); > >>> + if (!ra.n_addrs) { > >>> return; > >>> } > >>> > >>> - for (size_t i = 0; i < ra->n_addrs; i++) { > >>> + for (size_t i = 0; i < ra.n_addrs; i++) { > >>> ds_clear(match); > >>> ds_put_format(match, "outport == %s && "REG_NEXT_HOP_IPV4" == {", > >>> peer->json_key); > >>> bool first = true; > >>> - for (size_t j = 0; j < ra->laddrs[i].n_ipv4_addrs; j++) { > >>> + for (size_t j = 0; j < ra.laddrs[i].n_ipv4_addrs; j++) { > >>> if (!first) { > >>> ds_put_cstr(match, ", "); > >>> } > >>> - ds_put_cstr(match, ra->laddrs[i].ipv4_addrs[j].addr_s); > >>> + ds_put_cstr(match, ra.laddrs[i].ipv4_addrs[j].addr_s); > >>> first = false; > >>> } > >>> ds_put_cstr(match, "}"); > >>> > >>> ds_clear(actions); > >>> - ds_put_format(actions, "eth.dst = %s; next;", ra->laddrs[i].ea_s); > >>> + ds_put_format(actions, "eth.dst = %s; next;", ra.laddrs[i].ea_s); > >>> ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100, > >>> ds_cstr(match), ds_cstr(actions)); > >>> } > >>> + destroy_routable_addresses(&ra); > >>> } > >>> > >>> /* Local router ingress table ARP_RESOLVE: ARP Resolution. > >>> @@ -13699,6 +13438,7 @@ routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, > >>> static void > >>> build_arp_resolve_flows_for_lrp( > >>> struct ovn_port *op, const struct lr_nat_record *lrnat_rec, > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec, > >>> struct hmap *lflows, struct ds *match, struct ds *actions) > >>> { > >>> ovs_assert(op->nbrp); > >>> @@ -13775,8 +13515,8 @@ build_arp_resolve_flows_for_lrp( > >>> * > >>> * Priority 2. > >>> */ > >>> - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_ARP_RESOLVE, 2, > >>> - true, lflows); > >>> + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, > >>> + S_ROUTER_IN_ARP_RESOLVE, 2, true, lflows); > >>> } > >>> > >>> /* This function adds ARP resolve flows related to a LSP. */ > >>> @@ -13784,6 +13524,7 @@ static void > >>> build_arp_resolve_flows_for_lsp( > >>> struct ovn_port *op, struct hmap *lflows, > >>> const struct hmap *lr_ports, > >>> + const struct lr_lb_nat_data_table *lr_lbnats, > >>> struct ds *match, struct ds *actions) > >>> { > >>> ovs_assert(op->nbsp); > >>> @@ -13927,8 +13668,11 @@ build_arp_resolve_flows_for_lsp( > >>> > >>> if (smap_get(&peer->od->nbr->options, "chassis") > >>> || peer->cr_port) { > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec; > >>> + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, > >>> + router_port->od->index); > >>> routable_addresses_to_lflows(lflows, router_port, peer, > >>> - match, actions); > >>> + lr_lbnat_rec, match, actions); > >>> } > >>> } > >>> } > >>> @@ -14648,6 +14392,7 @@ static void > >>> build_lrouter_ipv4_ip_input(struct ovn_port *op, > >>> struct hmap *lflows, > >>> const struct lr_nat_record *lrnat_rec, > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec, > >>> struct ds *match, struct ds *actions, > >>> const struct shash *meter_groups) > >>> { > >>> @@ -14772,7 +14517,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, > >>> &op->nbrp->header_, lflows); > >>> } > >>> > >>> - if (sset_count(&op->od->lb_ips->ips_v4_reachable)) { > >>> + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v4_reachable)) { > >>> ds_clear(match); > >>> if (is_l3dgw_port(op)) { > >>> ds_put_format(match, "is_chassis_resident(%s)", > >>> @@ -14788,7 +14533,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, > >>> free(lb_ips_v4_as); > >>> } > >>> > >>> - if (sset_count(&op->od->lb_ips->ips_v6_reachable)) { > >>> + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v6_reachable)) { > >>> ds_clear(match); > >>> > >>> if (is_l3dgw_port(op)) { > >>> @@ -14890,8 +14635,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, > >>> * Priority 60. > >>> */ > >>> if (!lrnat_rec->lb_force_snat_router_ip) { > >>> - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_IP_INPUT, 60, > >>> - false, lflows); > >>> + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, > >>> + S_ROUTER_IN_IP_INPUT, 60, false, lflows); > >>> } > >>> /* ARP / ND handling for external IP addresses. > >>> * > >>> @@ -16030,6 +15775,7 @@ struct lswitch_flow_build_info { > >>> const struct hmap *lr_ports; > >>> const struct ls_port_group_table *ls_port_groups; > >>> const struct lr_nat_table *lr_nats; > >>> + const struct lr_lb_nat_data_table *lr_lbnats; > >>> struct hmap *lflows; > >>> struct hmap *igmp_groups; > >>> const struct shash *meter_groups; > >>> @@ -16113,14 +15859,15 @@ build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od, > >>> * switch port. > >>> */ > >>> static void > >>> -build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, > >>> - const struct hmap *ls_ports, > >>> - const struct hmap *lr_ports, > >>> - const struct lr_nat_table *lr_nats, > >>> - const struct shash *meter_groups, > >>> - struct ds *match, > >>> - struct ds *actions, > >>> - struct hmap *lflows) > >>> +build_lswitch_and_lrouter_iterate_by_lsp( > >>> + struct ovn_port *op, const struct hmap *ls_ports, > >>> + const struct hmap *lr_ports, > >>> + const struct lr_nat_table *lr_nats, > >>> + const struct lr_lb_nat_data_table *lr_lbnats, > >>> + const struct shash *meter_groups, > >>> + struct ds *match, > >>> + struct ds *actions, > >>> + struct hmap *lflows) > >>> { > >>> ovs_assert(op->nbsp); > >>> start_collecting_lflows(); > >>> @@ -16133,11 +15880,14 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, > >>> meter_groups, actions, match); > >>> build_lswitch_dhcp_options_and_response(op, lflows, meter_groups); > >>> build_lswitch_external_port(op, lflows); > >>> - build_lswitch_ip_unicast_lookup(op, lr_nats, lflows, actions, match); > >>> + build_lswitch_ip_unicast_lookup(op, lr_nats, lr_lbnats, lflows, actions, > >>> + match); > >>> > >>> /* Build Logical Router Flows. */ > >>> - build_ip_routing_flows_for_router_type_lsp(op, lr_ports, lflows); > >>> - build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, match, actions); > >>> + build_ip_routing_flows_for_router_type_lsp(op, lr_lbnats, lr_ports, > >>> + lflows); > >>> + build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, lr_lbnats, > >>> + match, actions); > >>> > >>> link_ovn_port_to_lflows(op, &collected_lflows); > >>> end_collecting_lflows(); > >>> @@ -16156,6 +15906,8 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, > >>> lsi->lr_nats, op->od->index); > >>> ovs_assert(lrnet_rec); > >>> > >>> + const struct lr_lb_nat_data_record *lr_lbnat_rec = > >>> + lr_lb_nat_data_table_find_by_index(lsi->lr_lbnats, op->od->index); > >>> build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > >>> &lsi->actions); > >>> build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > >>> @@ -16163,15 +15915,15 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, > >>> build_ip_routing_flows_for_lrp(op, lsi->lflows); > >>> build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > >>> &lsi->actions, lsi->meter_groups); > >>> - build_arp_resolve_flows_for_lrp(op, lrnet_rec, lsi->lflows, &lsi->match, > >>> - &lsi->actions); > >>> + build_arp_resolve_flows_for_lrp(op, lrnet_rec, lr_lbnat_rec, lsi->lflows, > >>> + &lsi->match, &lsi->actions); > >>> build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, > >>> &lsi->actions); > >>> build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match); > >>> build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows, > >>> &lsi->match, &lsi->actions, > >>> lsi->meter_groups); > >>> - build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, > >>> + build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, lr_lbnat_rec, > >>> &lsi->match, &lsi->actions, lsi->meter_groups); > >>> build_lrouter_force_snat_flows_op(op, lrnet_rec, lsi->lflows, &lsi->match, > >>> &lsi->actions); > >>> @@ -16234,6 +15986,7 @@ build_lflows_thread(void *arg) > >>> build_lswitch_and_lrouter_iterate_by_lsp(op, lsi->ls_ports, > >>> lsi->lr_ports, > >>> lsi->lr_nats, > >>> + lsi->lr_lbnats, > >>> lsi->meter_groups, > >>> &lsi->match, > >>> &lsi->actions, > >>> @@ -16344,6 +16097,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > >>> const struct hmap *lr_ports, > >>> const struct ls_port_group_table *ls_pgs, > >>> const struct lr_nat_table *lr_nats, > >>> + const struct lr_lb_nat_data_table *lr_lbnats, > >>> struct hmap *lflows, > >>> struct hmap *igmp_groups, > >>> const struct shash *meter_groups, > >>> @@ -16374,6 +16128,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > >>> lsiv[index].lr_ports = lr_ports; > >>> lsiv[index].ls_port_groups = ls_pgs; > >>> lsiv[index].lr_nats = lr_nats; > >>> + lsiv[index].lr_lbnats = lr_lbnats; > >>> lsiv[index].igmp_groups = igmp_groups; > >>> lsiv[index].meter_groups = meter_groups; > >>> lsiv[index].lb_dps_map = lb_dps_map; > >>> @@ -16409,6 +16164,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > >>> .lr_ports = lr_ports, > >>> .ls_port_groups = ls_pgs, > >>> .lr_nats = lr_nats, > >>> + .lr_lbnats = lr_lbnats, > >>> .lflows = lflows, > >>> .igmp_groups = igmp_groups, > >>> .meter_groups = meter_groups, > >>> @@ -16437,6 +16193,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, > >>> build_lswitch_and_lrouter_iterate_by_lsp(op, lsi.ls_ports, > >>> lsi.lr_ports, > >>> lsi.lr_nats, > >>> + lsi.lr_lbnats, > >>> lsi.meter_groups, > >>> &lsi.match, &lsi.actions, > >>> lsi.lflows); > >>> @@ -16558,6 +16315,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, > >>> input_data->lr_ports, > >>> input_data->ls_port_groups, > >>> input_data->lr_nats, > >>> + input_data->lr_lbnats, > >>> lflows, > >>> &igmp_groups, > >>> input_data->meter_groups, > >>> @@ -17038,6 +16796,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, > >>> build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, > >>> lflow_input->lr_ports, > >>> lflow_input->lr_nats, > >>> + lflow_input->lr_lbnats, > >>> lflow_input->meter_groups, > >>> &match, &actions, > >>> lflows); > >>> @@ -17076,6 +16835,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, > >>> build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, > >>> lflow_input->lr_ports, > >>> lflow_input->lr_nats, > >>> + lflow_input->lr_lbnats, > >>> lflow_input->meter_groups, > >>> &match, &actions, > >>> lflows); > >>> diff --git a/northd/northd.h b/northd/northd.h > >>> index 564729ebcc..7c446f5758 100644 > >>> --- a/northd/northd.h > >>> +++ b/northd/northd.h > >>> @@ -179,6 +179,7 @@ struct lflow_input { > >>> const struct hmap *lr_ports; > >>> const struct ls_port_group_table *ls_port_groups; > >>> const struct lr_nat_table *lr_nats; > >>> + const struct lr_lb_nat_data_table *lr_lbnats; > >>> const struct shash *meter_groups; > >>> const struct hmap *lb_datapaths_map; > >>> const struct hmap *bfd_connections; > >>> @@ -318,9 +319,6 @@ struct ovn_datapath { > >>> /* router datapath has a logical port with redirect-type set to bridged. */ > >>> bool redirect_bridged; > >>> > >>> - /* Load Balancer vIPs relevant for this datapath. */ > >>> - struct ovn_lb_ip_set *lb_ips; > >>> - > >>> struct ovn_port **localnet_ports; > >>> size_t n_localnet_ports; > >>> > >>> @@ -337,6 +335,119 @@ struct ovn_datapath { > >>> const struct ovn_datapath *ovn_datapath_find(const struct hmap *datapaths, > >>> const struct uuid *uuid); > >>> > >>> +/* A logical switch port or logical router port. > >>> + * > >>> + * In steady state, an ovn_port points to a northbound Logical_Switch_Port > >>> + * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a > >>> + * southbound Port_Binding record (via 'sb'). As the state of the system > >>> + * changes, join_logical_ports() may determine that there is a new LSP or LRP > >>> + * that has no corresponding Port_Binding record (in which case build_ports()) > >>> + * will create the missing Port_Binding) or that a Port_Binding record exists > >>> + * that has no coresponding LSP (in which case build_ports() will delete the > >>> + * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port > >>> + * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. > >>> + * > >>> + * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but > >>> + * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). > >>> + */ > >>> +struct ovn_port { > >>> + /* Port name aka key. > >>> + * > >>> + * This is ordinarily the same as nbsp->name or nbrp->name and > >>> + * sb->logical_port. (A distributed gateway port creates a "derived" > >>> + * ovn_port with key "cr-%s" % nbrp->name.) */ > >>> + struct hmap_node key_node; /* Index on 'key'. */ > >>> + char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ > >>> + char *json_key; /* 'key', quoted for use in JSON. */ > >>> + > >>> + const struct sbrec_port_binding *sb; /* May be NULL. */ > >>> + > >>> + uint32_t tunnel_key; > >>> + > >>> + /* Logical switch port data. */ > >>> + const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ > >>> + > >>> + struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ > >>> + unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ > >>> + unsigned int n_lsp_non_router_addrs; /* Number of elements from the > >>> + * beginning of 'lsp_addrs' extracted > >>> + * directly from LSP 'addresses'. */ > >>> + > >>> + struct lport_addresses *ps_addrs; /* Port security addresses. */ > >>> + unsigned int n_ps_addrs; > >>> + > >>> + bool lsp_can_be_inc_processed; /* If it can be incrementally processed when > >>> + the port changes. */ > >>> + > >>> + /* Logical router port data. */ > >>> + const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ > >>> + > >>> + struct lport_addresses lrp_networks; > >>> + > >>> + /* Logical port multicast data. */ > >>> + struct mcast_port_info mcast_info; > >>> + > >>> + /* At most one of l3dgw_port and cr_port can be not NULL. */ > >>> + > >>> + /* This is set to a distributed gateway port if and only if this ovn_port > >>> + * is "derived" from it. Otherwise this is set to NULL. The derived > >>> + * ovn_port represents the instance of distributed gateway port on the > >>> + * gateway chassis.*/ > >>> + struct ovn_port *l3dgw_port; > >>> + > >>> + /* This is set to the "derived" chassis-redirect port of this port if and > >>> + * only if this port is a distributed gateway port. Otherwise this is set > >>> + * to NULL. */ > >>> + struct ovn_port *cr_port; > >>> + > >>> + bool has_unknown; /* If the addresses have 'unknown' defined. */ > >>> + > >>> + bool has_bfd; > >>> + > >>> + /* The port's peer: > >>> + * > >>> + * - A switch port S of type "router" has a router port R as a peer, > >>> + * and R in turn has S has its peer. > >>> + * > >>> + * - Two connected logical router ports have each other as peer. > >>> + * > >>> + * - Other kinds of ports have no peer. */ > >>> + struct ovn_port *peer; > >>> + > >>> + struct ovn_datapath *od; > >>> + > >>> + struct ovs_list list; /* In list of similar records. */ > >>> + > >>> + struct hmap_node dp_node; /* Node in od->ports. */ > >>> + > >>> + struct lport_addresses proxy_arp_addrs; > >>> + > >>> + /* Temporarily used for traversing a list (or hmap) of ports. */ > >>> + bool visited; > >>> + > >>> + /* List of struct lflow_ref_node that points to the lflows generated by > >>> + * this ovn_port. > >>> + * > >>> + * This data is initialized and destroyed by the en_northd node, but > >>> + * populated and used only by the en_lflow node. Ideally this data should > >>> + * be maintained as part of en_lflow's data (struct lflow_data): a hash > >>> + * index from ovn_port key to lflows. However, it would be less efficient > >>> + * and more complex: > >>> + * > >>> + * 1. It would require an extra search (using the index) to find the > >>> + * lflows. > >>> + * > >>> + * 2. Building the index needs to be thread-safe, using either a global > >>> + * lock which is obviously less efficient, or hash-based lock array which > >>> + * is more complex. > >>> + * > >>> + * Adding the list here is more straightforward. The drawback is that we > >>> + * need to keep in mind that this data belongs to en_lflow node, so never > >>> + * access it from any other nodes. > >>> + */ > >>> + struct ovs_list lflows; > >>> +}; > >>> + > >>> void ovnnb_db_run(struct northd_input *input_data, > >>> struct northd_data *data, > >>> struct ovsdb_idl_txn *ovnnb_txn, > >>> @@ -396,13 +507,27 @@ void sync_lbs(struct ovsdb_idl_txn *, const struct sbrec_load_balancer_table *, > >>> struct chassis_features *chassis_features); > >>> bool check_sb_lb_duplicates(const struct sbrec_load_balancer_table *); > >>> > >>> +struct lr_lb_nat_data_table; > >>> void sync_pbs(struct ovsdb_idl_txn *, struct hmap *ls_ports, > >>> - struct hmap *lr_ports, const struct lr_nat_table *); > >>> -bool sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *, > >>> - const struct lr_nat_table *); > >>> + struct hmap *lr_ports, > >>> + const struct lr_lb_nat_data_table *); > >>> +bool sync_pbs_for_northd_changed_ovn_ports( > >>> + struct tracked_ovn_ports *, > >>> + const struct lr_lb_nat_data_table *); > >>> > >>> bool northd_has_tracked_data(struct northd_tracked_data *); > >>> bool northd_has_only_ports_in_tracked_data(struct northd_tracked_data *); > >>> bool northd_has_lbs_in_tracked_data(struct northd_tracked_data *); > >>> > >>> +/* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the > >>> + * IPs configured on the router port. > >>> + */ > >>> +bool lrouter_port_ipv4_reachable(const struct ovn_port *, ovs_be32 addr); > >>> + > >>> +/* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the > >>> + * IPs configured on the router port. > >>> + */ > >>> +bool lrouter_port_ipv6_reachable(const struct ovn_port *, > >>> + const struct in6_addr *); > >>> + > >>> #endif /* NORTHD_H */ > >>> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > >>> index b7f9cb5689..8fc5cd1d60 100644 > >>> --- a/tests/ovn-northd.at > >>> +++ b/tests/ovn-northd.at > >>> @@ -10416,18 +10416,21 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:10.0.0.3=sw0-p1:10.0.0.2 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> > >>> check ovn-nbctl --wait=sb set load_balancer . options:foo=bar > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> > >>> check ovn-nbctl --wait=sb -- lb-add lb2 20.0.0.10:80 20.0.0.20:80 -- lb-add lb3 30.0.0.10:80 30.0.0.20:80 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> > >>> @@ -10437,6 +10440,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb -- lb-del lb2 -- lb-del lb3 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> > >>> @@ -10450,6 +10454,7 @@ AT_CHECK([ovn-nbctl --wait=sb \ > >>> ]) > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> > >>> @@ -10467,6 +10472,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb clear Load_Balancer . health_check > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> > >>> @@ -10481,6 +10487,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> > >>> @@ -10489,6 +10496,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> # A LB applied to a switch/router triggers: > >>> # - a recompute in the first iteration (handling northd change) > >>> @@ -10501,6 +10509,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10510,6 +10519,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10519,6 +10529,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10528,6 +10539,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10537,6 +10549,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb ls-lb-del sw0 lb1 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10547,6 +10560,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 -- lsp-add sw0 sw0p1 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> > >>> @@ -10567,6 +10581,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-lb-add lr0 lb1 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10576,6 +10591,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10585,6 +10601,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10594,6 +10611,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10603,6 +10621,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10632,6 +10651,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb add load_balancer_group . load_Balancer $lb1_uuid > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> > >>> @@ -10639,6 +10659,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb clear load_balancer_group . load_Balancer > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> > >>> @@ -10655,6 +10676,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> > >>> @@ -10671,6 +10693,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10680,6 +10703,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10689,6 +10713,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10698,6 +10723,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10713,6 +10739,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl add logical_router lr0 load_balancer_group $lbg1_uuid > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10722,6 +10749,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10731,6 +10759,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb clear load_Balancer lb1 vips > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10740,6 +10769,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10749,6 +10779,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10757,6 +10788,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb clear logical_router lr0 load_balancer_group > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> > >>> @@ -10765,6 +10797,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> > >>> @@ -10773,6 +10806,7 @@ check ovn-nbctl --wait=sb clear logical_switch sw0 load_balancer_group -- \ > >>> destroy load_balancer_group $lbg1_uuid > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb compute compute > >>> > >>> @@ -10796,6 +10830,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> lbg1_uuid=$(ovn-nbctl --wait=sb create load_balancer_group name=lbg1) > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow norecompute nocompute > >>> check_engine_stats sync_to_sb_lb norecompute nocompute > >>> > >>> @@ -10803,6 +10838,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set load_balancer_group . load_balancer="$lb2_uuid,$lb3_uuid,$lb4_uuid" > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> > >>> @@ -10810,6 +10846,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set logical_switch sw0 load_balancer_group=$lbg1_uuid > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10818,6 +10855,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set logical_router lr1 load_balancer_group=$lbg1_uuid > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10826,6 +10864,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb ls-lb-add sw0 lb2 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10834,6 +10873,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb ls-lb-add sw0 lb3 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10843,6 +10883,7 @@ check ovn-nbctl --wait=sb lr-lb-add lr1 lb1 > >>> check ovn-nbctl --wait=sb lr-lb-add lr1 lb2 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10851,6 +10892,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb ls-lb-del sw0 lb2 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10859,6 +10901,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-lb-del lr1 lb2 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10869,6 +10912,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lb-del lb4 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10879,6 +10923,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lb-del lb2 > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -10887,6 +10932,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb remove load_balancer_group . load_balancer $lb3_uuid > >>> check_engine_stats lb_data norecompute compute > >>> check_engine_stats northd recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_lb recompute compute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11019,6 +11065,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-add lr0 > >>> check_engine_stats northd recompute nocompute > >>> check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11031,6 +11078,7 @@ check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 > >>> # for the SB port binding change. > >>> check_engine_stats northd recompute compute > >>> check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11042,6 +11090,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 > >>> check_engine_stats northd recompute nocompute > >>> check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11067,6 +11116,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl set logical_router_port lr0-sw0 options:foo=bar > >>> check_engine_stats northd recompute nocompute > >>> check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11076,8 +11126,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> # engine nodes. > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 > >>> -check_engine_stats northd recompute nocompute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11085,8 +11135,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> # Update the NAT options column > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set NAT . options:foo=bar > >>> -check_engine_stats northd recompute nocompute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11094,8 +11144,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> # Update the NAT external_ip column > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set NAT . external_ip=172.168.0.120 > >>> -check_engine_stats northd recompute nocompute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11103,8 +11154,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> # Update the NAT logical_ip column > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set NAT . logical_ip=10.0.0.10 > >>> -check_engine_stats northd recompute nocompute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11112,8 +11164,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> # Update the NAT type > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set NAT . type=snat > >>> -check_engine_stats northd recompute nocompute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11121,8 +11174,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> # Create a dnat_and_snat NAT with external_mac and logical_port > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 sw0p1 30:54:00:00:00:03 > >>> -check_engine_stats northd recompute compute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11131,8 +11185,9 @@ nat2_uuid=$(ovn-nbctl --bare --columns _uuid find nat logical_ip=10.0.0.4) > >>> > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb set NAT $nat2_uuid external_mac='"30:54:00:00:00:04"' > >>> -check_engine_stats northd recompute nocompute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11147,32 +11202,36 @@ check ovn-nbctl lr-lb-add lr0 lb2 > >>> # is a lb vip. > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.140 10.0.0.20 > >>> -check_engine_stats northd recompute nocompute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.150 10.0.0.41 > >>> -check_engine_stats northd recompute nocompute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.150 > >>> -check_engine_stats northd recompute nocompute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.140 > >>> -check_engine_stats northd recompute nocompute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11180,8 +11239,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> # Delete the NAT > >>> check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb clear logical_router lr0 nat > >>> -check_engine_stats northd recompute compute > >>> -check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats northd norecompute compute > >>> +check_engine_stats lr_nat norecompute compute > >>> +check_engine_stats lr_lb_nat_data norecompute compute > >>> check_engine_stats lflow recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11191,6 +11251,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-policy-add lr0 10 "ip4.src == 10.0.0.3" reroute 172.168.0.101,172.168.0.102 > >>> check_engine_stats northd recompute nocompute > >>> check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > >>> @@ -11199,6 +11260,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats > >>> check ovn-nbctl --wait=sb lr-policy-del lr0 10 "ip4.src == 10.0.0.3" > >>> check_engine_stats northd recompute nocompute > >>> check_engine_stats lr_nat recompute nocompute > >>> +check_engine_stats lr_lb_nat_data recompute nocompute > >>> check_engine_stats sync_to_sb_pb recompute nocompute > >>> check_engine_stats lflow recompute nocompute > >>> CHECK_NO_CHANGE_AFTER_RECOMPUTE > > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev >
diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h index 0a16da211e..7d85acdaea 100644 --- a/lib/stopwatch-names.h +++ b/lib/stopwatch-names.h @@ -33,5 +33,6 @@ #define PORT_GROUP_RUN_STOPWATCH_NAME "port_group_run" #define SYNC_METERS_RUN_STOPWATCH_NAME "sync_meters_run" #define LR_NAT_RUN_STOPWATCH_NAME "lr_nat_run" +#define LR_LB_NAT_DATA_RUN_STOPWATCH_NAME "lr_lb_nat_data" #endif diff --git a/northd/automake.mk b/northd/automake.mk index ae367a2a8b..4116c487df 100644 --- a/northd/automake.mk +++ b/northd/automake.mk @@ -26,6 +26,8 @@ northd_ovn_northd_SOURCES = \ northd/en-lb-data.h \ northd/en-lr-nat.c \ northd/en-lr-nat.h \ + northd/en-lr-lb-nat-data.c \ + northd/en-lr-lb-nat-data.h \ northd/inc-proc-northd.c \ northd/inc-proc-northd.h \ northd/ipam.c \ diff --git a/northd/en-lflow.c b/northd/en-lflow.c index 22f398d419..9cb0ead3f0 100644 --- a/northd/en-lflow.c +++ b/northd/en-lflow.c @@ -20,6 +20,7 @@ #include "en-lflow.h" #include "en-lr-nat.h" +#include "en-lr-lb-nat-data.h" #include "en-northd.h" #include "en-meters.h" @@ -43,6 +44,8 @@ lflow_get_input_data(struct engine_node *node, engine_get_input_data("sync_meters", node); struct ed_type_lr_nat_data *lr_nat_data = engine_get_input_data("lr_nat", node); + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = + engine_get_input_data("lr_lb_nat_data", node); lflow_input->nbrec_bfd_table = EN_OVSDB_GET(engine_get_input("NB_bfd", node)); @@ -66,6 +69,7 @@ lflow_get_input_data(struct engine_node *node, lflow_input->lr_ports = &northd_data->lr_ports; lflow_input->ls_port_groups = &pg_data->ls_port_groups; lflow_input->lr_nats = &lr_nat_data->lr_nats; + lflow_input->lr_lbnats = &lr_lb_nat_data->lr_lbnats; lflow_input->meter_groups = &sync_meters_data->meter_groups; lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map; lflow_input->svc_monitor_map = &northd_data->svc_monitor_map; diff --git a/northd/en-lr-lb-nat-data.c b/northd/en-lr-lb-nat-data.c new file mode 100644 index 0000000000..19b638ce0b --- /dev/null +++ b/northd/en-lr-lb-nat-data.c @@ -0,0 +1,654 @@ +/* + * Copyright (c) 2023, Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <config.h> + +#include <getopt.h> +#include <stdlib.h> +#include <stdio.h> + +/* OVS includes */ +#include "include/openvswitch/hmap.h" +#include "lib/bitmap.h" +#include "lib/socket-util.h" +#include "lib/uuidset.h" +#include "openvswitch/util.h" +#include "openvswitch/vlog.h" +#include "stopwatch.h" + +/* OVN includes */ +#include "en-lb-data.h" +#include "en-lr-lb-nat-data.h" +#include "en-lr-nat.h" +#include "lib/inc-proc-eng.h" +#include "lib/lb.h" +#include "lib/ovn-nb-idl.h" +#include "lib/ovn-sb-idl.h" +#include "lib/ovn-util.h" +#include "lib/stopwatch-names.h" +#include "northd.h" + +VLOG_DEFINE_THIS_MODULE(en_lr_lb_nat_data); + +/* Static function declarations. */ +static void lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *); +static void lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *); +static void lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *); +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_( + const struct lr_lb_nat_data_table *, const struct nbrec_logical_router *); +static struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index_( + const struct lr_lb_nat_data_table *table, size_t od_index); + +static void lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *, + const struct lr_nat_table *, + const struct ovn_datapaths *lr_datapaths, + const struct hmap *lb_datapaths_map, + const struct hmap *lbgrp_datapaths_map); + +static struct lr_lb_nat_data_input lr_lb_nat_data_get_input_data( + struct engine_node *); + +static struct lr_lb_nat_data_record *lr_lb_nat_data_record_create( + struct lr_lb_nat_data_table *, const struct lr_nat_record *, + const struct hmap *lb_datapaths_map, + const struct hmap *lbgrp_datapaths_map); +static void lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *); +static void lr_lb_nat_data_record_init( + struct lr_lb_nat_data_record *, + const struct hmap *lb_datapaths_map, + const struct hmap *lbgrp_datapaths_map); + +static void build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, + const struct ovn_northd_lb *); +static void add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *, + enum lb_neighbor_responder_mode, + const struct sset *lb_ips_v4, + const struct sset *lb_ips_v6); +static void remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *, + enum lb_neighbor_responder_mode, + const struct sset *lb_ips_v4, + const struct sset *lb_ips_v6); +static void lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *); + +/* 'lr_lb_nat_data' engine node manages the NB logical router LB data. + */ +void * +en_lr_lb_nat_data_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + struct ed_type_lr_lb_nat_data *data = xzalloc(sizeof *data); + lr_lb_nat_data_table_init(&data->lr_lbnats); + hmapx_init(&data->tracked_data.crupdated); + hmapx_init(&data->tracked_data.deleted); + return data; +} + +void +en_lr_lb_nat_data_cleanup(void *data_) +{ + struct ed_type_lr_lb_nat_data *data = + (struct ed_type_lr_lb_nat_data *) data_; + lr_lb_nat_data_table_destroy(&data->lr_lbnats); + hmapx_destroy(&data->tracked_data.crupdated); + hmapx_destroy(&data->tracked_data.deleted); +} + +void +en_lr_lb_nat_data_clear_tracked_data(void *data_) +{ + struct ed_type_lr_lb_nat_data *data = + (struct ed_type_lr_lb_nat_data *) data_; + + struct hmapx_node *hmapx_node; + HMAPX_FOR_EACH_SAFE (hmapx_node, &data->tracked_data.deleted) { + lr_lb_nat_data_record_destroy(hmapx_node->data); + hmapx_delete(&data->tracked_data.deleted, hmapx_node); + } + + hmapx_clear(&data->tracked_data.crupdated); + data->tracked = false; +} + +void +en_lr_lb_nat_data_run(struct engine_node *node, void *data_) +{ + struct lr_lb_nat_data_input input_data = + lr_lb_nat_data_get_input_data(node); + struct ed_type_lr_lb_nat_data *data = data_; + + stopwatch_start(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); + + lr_lb_nat_data_table_clear(&data->lr_lbnats); + lr_lb_nat_data_table_build(&data->lr_lbnats, input_data.lr_nats, + input_data.lr_datapaths, + input_data.lb_datapaths_map, + input_data.lbgrp_datapaths_map); + + stopwatch_stop(LR_LB_NAT_DATA_RUN_STOPWATCH_NAME, time_msec()); + engine_set_node_state(node, EN_UPDATED); +} + +bool +lr_lb_nat_data_northd_handler(struct engine_node *node, void *data OVS_UNUSED) +{ + struct northd_data *northd_data = engine_get_input_data("northd", node); + if (!northd_data->change_tracked) { + return false; + } + + return true; +} + +bool +lr_lb_nat_data_lb_data_handler(struct engine_node *node, void *data_) +{ + struct ed_type_lb_data *lb_data = engine_get_input_data("lb_data", node); + if (!lb_data->tracked) { + return false; + } + + struct ed_type_lr_lb_nat_data *data = + (struct ed_type_lr_lb_nat_data *) data_; + struct lr_lb_nat_data_input input_data = + lr_lb_nat_data_get_input_data(node); + struct lr_lb_nat_data_record *lr_lbnat_rec; + size_t index; + + const struct tracked_lb_data *trk_lb_data = &lb_data->tracked_lb_data; + const struct ovn_lb_group_datapaths *lbgrp_dps; + const struct crupdated_lbgrp *crupdated_lbgrp; + const struct crupdated_od_lb_data *codlb; + const struct ovn_lb_datapaths *lb_dps; + const struct crupdated_lb *clb; + const struct ovn_northd_lb *lb; + const struct ovn_datapath *od; + + LIST_FOR_EACH (codlb, list_node, &trk_lb_data->crupdated_lr_lbs) { + od = ovn_datapath_find(&input_data.lr_datapaths->datapaths, + &codlb->od_uuid); + ovs_assert(od); + + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, od->nbr); + if (!lr_lbnat_rec) { + const struct lr_nat_record *lrnat_rec = lr_nat_table_find_by_index( + input_data.lr_nats, od->index); + ovs_assert(lrnat_rec); + + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, + lrnat_rec, + input_data.lb_datapaths_map, + input_data.lbgrp_datapaths_map); + + /* Add the lr_lbnat_rec rec to the tracking data. */ + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); + continue; + } + + struct uuidset_node *uuidnode; + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbs) { + lb_dps = ovn_lb_datapaths_find( + input_data.lb_datapaths_map, &uuidnode->uuid); + ovs_assert(lb_dps); + + /* Add the lb_ips of lb_dps to the od. */ + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); + } + + UUIDSET_FOR_EACH (uuidnode, &codlb->assoc_lbgrps) { + lbgrp_dps = ovn_lb_group_datapaths_find( + input_data.lbgrp_datapaths_map, &uuidnode->uuid); + ovs_assert(lbgrp_dps); + + for (size_t j = 0; j < lbgrp_dps->lb_group->n_lbs; j++) { + const struct uuid *lb_uuid + = &lbgrp_dps->lb_group->lbs[j]->nlb->header_.uuid; + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, + lb_uuid); + ovs_assert(lb_dps); + + /* Add the lb_ips of lb_dps to the od. */ + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); + } + } + + /* Add the lr_lbnat_rec rec to the tracking data. */ + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); + } + + HMAP_FOR_EACH (clb, hmap_node, &trk_lb_data->crupdated_lbs) { + lb = clb->lb; + const struct uuid *lb_uuid = &lb->nlb->header_.uuid; + + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, lb_uuid); + ovs_assert(lb_dps); + + BITMAP_FOR_EACH_1 (index, ods_size(input_data.lr_datapaths), + lb_dps->nb_lr_map) { + od = input_data.lr_datapaths->array[index]; + + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, + od->nbr); + ovs_assert(lr_lbnat_rec); + + /* Update the od->lb_ips with the deleted and inserted + * vips (if any). */ + remove_ips_from_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, + &clb->deleted_vips_v4, + &clb->deleted_vips_v6); + add_ips_to_lb_ip_set(lr_lbnat_rec->lb_ips, lb->routable, + &clb->inserted_vips_v4, + &clb->inserted_vips_v6); + + remove_lrouter_lb_reachable_ips(lr_lbnat_rec, lb->neigh_mode, + &clb->deleted_vips_v4, + &clb->deleted_vips_v6); + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, + &clb->inserted_vips_v4, + &clb->inserted_vips_v6); + + /* Add the lr_lbnat_rec rec to the tracking data. */ + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); + } + } + + HMAP_FOR_EACH (crupdated_lbgrp, hmap_node, + &trk_lb_data->crupdated_lbgrps) { + const struct uuid *lb_uuid = &crupdated_lbgrp->lbgrp->uuid; + + lbgrp_dps = ovn_lb_group_datapaths_find(input_data.lbgrp_datapaths_map, + lb_uuid); + ovs_assert(lbgrp_dps); + + struct hmapx_node *hnode; + HMAPX_FOR_EACH (hnode, &crupdated_lbgrp->assoc_lbs) { + lb = hnode->data; + lb_uuid = &lb->nlb->header_.uuid; + lb_dps = ovn_lb_datapaths_find(input_data.lb_datapaths_map, + lb_uuid); + ovs_assert(lb_dps); + for (size_t i = 0; i < lbgrp_dps->n_lr; i++) { + od = lbgrp_dps->lr[i]; + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, + od->nbr); + ovs_assert(lr_lbnat_rec); + /* Add the lb_ips of lb_dps to the lr lb data. */ + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); + + /* Add the lr_lbnat_rec rec to the tracking data. */ + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); + } + } + } + + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { + struct hmapx_node *hmapx_node; + /* For all the modified lr_lb_nat_data records (re)build the + * vip nats. */ + HMAPX_FOR_EACH (hmapx_node, &data->tracked_data.crupdated) { + lr_lb_nat_data_build_vip_nats(hmapx_node->data); + } + + data->tracked = true; + engine_set_node_state(node, EN_UPDATED); + } + + return true; +} + +bool +lr_lb_nat_data_lr_nat_handler(struct engine_node *node, void *data_) +{ + struct ed_type_lr_nat_data *lr_nat_data = + engine_get_input_data("lr_nat", node); + + if (!lr_nat_data->tracked + || !hmapx_is_empty(&lr_nat_data->tracked_data.deleted)) { + return false; + } + + struct ed_type_lr_lb_nat_data *data = + (struct ed_type_lr_lb_nat_data *) data_; + struct lr_lb_nat_data_input input_data = + lr_lb_nat_data_get_input_data(node); + const struct lr_nat_record *lrnat_rec; + struct lr_lb_nat_data_record *lr_lbnat_rec; + struct hmapx_node *hmapx_node; + + HMAPX_FOR_EACH (hmapx_node, &lr_nat_data->tracked_data.crupdated) { + lrnat_rec = hmapx_node->data; + lr_lbnat_rec = lr_lb_nat_data_table_find_(&data->lr_lbnats, + lrnat_rec->od->nbr); + if (!lr_lbnat_rec) { + lr_lbnat_rec = lr_lb_nat_data_record_create(&data->lr_lbnats, + lrnat_rec, + input_data.lb_datapaths_map, + input_data.lbgrp_datapaths_map); + } else { + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); + } + + /* Add the lr_lbnat_rec rec to the tracking data. */ + hmapx_add(&data->tracked_data.crupdated, lr_lbnat_rec); + } + + if (!hmapx_is_empty(&data->tracked_data.crupdated)) { + data->tracked = true; + engine_set_node_state(node, EN_UPDATED); + } + + return true; +} + +const struct lr_lb_nat_data_record * +lr_lb_nat_data_table_find_by_index(const struct lr_lb_nat_data_table *table, + size_t od_index) +{ + return lr_lb_nat_data_table_find_by_index_(table, od_index); +} + +/* static functions. */ +static void +lr_lb_nat_data_table_init(struct lr_lb_nat_data_table *table) +{ + *table = (struct lr_lb_nat_data_table) { + .entries = HMAP_INITIALIZER(&table->entries), + }; +} + +static void +lr_lb_nat_data_table_destroy(struct lr_lb_nat_data_table *table) +{ + lr_lb_nat_data_table_clear(table); + hmap_destroy(&table->entries); +} + +static void +lr_lb_nat_data_table_clear(struct lr_lb_nat_data_table *table) +{ + struct lr_lb_nat_data_record *lr_lbnat_rec; + HMAP_FOR_EACH_POP (lr_lbnat_rec, key_node, &table->entries) { + lr_lb_nat_data_record_destroy(lr_lbnat_rec); + } + + free(table->array); + table->array = NULL; +} + +static void +lr_lb_nat_data_table_build(struct lr_lb_nat_data_table *table, + const struct lr_nat_table *lr_nats, + const struct ovn_datapaths *lr_datapaths, + const struct hmap *lb_datapaths_map, + const struct hmap *lbgrp_datapaths_map) +{ + table->array = xrealloc(table->array, + ods_size(lr_datapaths) * sizeof *table->array); + const struct lr_nat_record *lrnat_rec; + LR_NAT_TABLE_FOR_EACH (lrnat_rec, lr_nats) { + lr_lb_nat_data_record_create(table, lrnat_rec, lb_datapaths_map, + lbgrp_datapaths_map); + } +} + +static struct lr_lb_nat_data_record * +lr_lb_nat_data_table_find_(const struct lr_lb_nat_data_table *table, + const struct nbrec_logical_router *nbr) +{ + struct lr_lb_nat_data_record *lr_lbnat_rec; + + HMAP_FOR_EACH_WITH_HASH (lr_lbnat_rec, key_node, + uuid_hash(&nbr->header_.uuid), &table->entries) { + if (nbr == lr_lbnat_rec->od->nbr) { + return lr_lbnat_rec; + } + } + return NULL; +} + +static struct lr_lb_nat_data_record * +lr_lb_nat_data_table_find_by_index_(const struct lr_lb_nat_data_table *table, + size_t od_index) +{ + ovs_assert(od_index <= hmap_count(&table->entries)); + return table->array[od_index]; +} + +static struct lr_lb_nat_data_record * +lr_lb_nat_data_record_create(struct lr_lb_nat_data_table *table, + const struct lr_nat_record *lrnat_rec, + const struct hmap *lb_datapaths_map, + const struct hmap *lbgrp_datapaths_map) +{ + struct lr_lb_nat_data_record *lr_lbnat_rec = xzalloc(sizeof *lr_lbnat_rec); + lr_lbnat_rec->lrnat_rec = lrnat_rec; + lr_lbnat_rec->od = lrnat_rec->od; + lr_lb_nat_data_record_init(lr_lbnat_rec, lb_datapaths_map, + lbgrp_datapaths_map); + + hmap_insert(&table->entries, &lr_lbnat_rec->key_node, + uuid_hash(&lr_lbnat_rec->od->nbr->header_.uuid)); + + table->array[lr_lbnat_rec->od->index] = lr_lbnat_rec; + return lr_lbnat_rec; +} + +static void +lr_lb_nat_data_record_destroy(struct lr_lb_nat_data_record *lr_lbnat_rec) +{ + ovn_lb_ip_set_destroy(lr_lbnat_rec->lb_ips); + lr_lbnat_rec->lb_ips = NULL; + sset_destroy(&lr_lbnat_rec->vip_nats); + free(lr_lbnat_rec); +} + +static void +lr_lb_nat_data_record_init(struct lr_lb_nat_data_record *lr_lbnat_rec, + const struct hmap *lb_datapaths_map, + const struct hmap *lbgrp_datapaths_map) +{ + const struct nbrec_load_balancer_group *nbrec_lb_group; + const struct ovn_lb_group_datapaths *lb_group_dps; + const struct ovn_lb_datapaths *lb_dps; + + /* Checking load balancer groups first, starting from the largest one, + * to more efficiently copy IP sets. */ + size_t largest_group = 0; + + const struct nbrec_logical_router *nbr = lr_lbnat_rec->od->nbr; + for (size_t i = 1; i < nbr->n_load_balancer_group; i++) { + if (nbr->load_balancer_group[i]->n_load_balancer > + nbr->load_balancer_group[largest_group]->n_load_balancer) { + largest_group = i; + } + } + + for (size_t i = 0; i < nbr->n_load_balancer_group; i++) { + size_t idx = (i + largest_group) % nbr->n_load_balancer_group; + + nbrec_lb_group = nbr->load_balancer_group[idx]; + const struct uuid *lbgrp_uuid = &nbrec_lb_group->header_.uuid; + + lb_group_dps = + ovn_lb_group_datapaths_find(lbgrp_datapaths_map, + lbgrp_uuid); + ovs_assert(lb_group_dps); + + if (!lr_lbnat_rec->lb_ips) { + lr_lbnat_rec->lb_ips = + ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); + } else { + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, + lb_group_dps->lb_group->lbs[j]); + } + } + + for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { + build_lrouter_lb_reachable_ips(lr_lbnat_rec, + lb_group_dps->lb_group->lbs[j]); + } + } + + if (!lr_lbnat_rec->lb_ips) { + lr_lbnat_rec->lb_ips = ovn_lb_ip_set_create(); + } + + for (size_t i = 0; i < nbr->n_load_balancer; i++) { + const struct uuid *lb_uuid = + &nbr->load_balancer[i]->header_.uuid; + lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); + ovs_assert(lb_dps); + build_lrouter_lb_ips(lr_lbnat_rec->lb_ips, lb_dps->lb); + build_lrouter_lb_reachable_ips(lr_lbnat_rec, lb_dps->lb); + } + + sset_init(&lr_lbnat_rec->vip_nats); + + if (!nbr->n_nat) { + lr_lb_nat_data_build_vip_nats(lr_lbnat_rec); + } +} + +static struct lr_lb_nat_data_input +lr_lb_nat_data_get_input_data(struct engine_node *node) +{ + struct northd_data *northd_data = engine_get_input_data("northd", node); + struct ed_type_lr_nat_data *lr_nat_data = + engine_get_input_data("lr_nat", node); + + return (struct lr_lb_nat_data_input) { + .lr_datapaths = &northd_data->lr_datapaths, + .lb_datapaths_map = &northd_data->lb_datapaths_map, + .lbgrp_datapaths_map = &northd_data->lb_group_datapaths_map, + .lr_nats = &lr_nat_data->lr_nats, + }; +} + +static void +build_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, + const struct ovn_northd_lb *lb) +{ + add_neigh_ips_to_lrouter(lr_lbnat_rec, lb->neigh_mode, &lb->ips_v4, + &lb->ips_v6); +} + +static void +add_neigh_ips_to_lrouter(struct lr_lb_nat_data_record *lr_lbnat_rec, + enum lb_neighbor_responder_mode neigh_mode, + const struct sset *lb_ips_v4, + const struct sset *lb_ips_v6) +{ + /* If configured to not reply to any neighbor requests for all VIPs + * return early. + */ + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { + return; + } + + const char *ip_address; + + /* If configured to reply to neighbor requests for all VIPs force them + * all to be considered "reachable". + */ + if (neigh_mode == LB_NEIGH_RESPOND_ALL) { + SSET_FOR_EACH (ip_address, lb_ips_v4) { + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, ip_address); + } + SSET_FOR_EACH (ip_address, lb_ips_v6) { + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, ip_address); + } + + return; + } + + /* Otherwise, a VIP is reachable if there's at least one router + * subnet that includes it. + */ + ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); + + SSET_FOR_EACH (ip_address, lb_ips_v4) { + struct ovn_port *op; + ovs_be32 vip_ip4; + if (ip_parse(ip_address, &vip_ip4)) { + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { + if (lrouter_port_ipv4_reachable(op, vip_ip4)) { + sset_add(&lr_lbnat_rec->lb_ips->ips_v4_reachable, + ip_address); + break; + } + } + } + } + + SSET_FOR_EACH (ip_address, lb_ips_v6) { + struct ovn_port *op; + struct in6_addr vip; + if (ipv6_parse(ip_address, &vip)) { + HMAP_FOR_EACH (op, dp_node, &lr_lbnat_rec->od->ports) { + if (lrouter_port_ipv6_reachable(op, &vip)) { + sset_add(&lr_lbnat_rec->lb_ips->ips_v6_reachable, + ip_address); + break; + } + } + } + } +} + +static void +remove_lrouter_lb_reachable_ips(struct lr_lb_nat_data_record *lr_lbnat_rec, + enum lb_neighbor_responder_mode neigh_mode, + const struct sset *lb_ips_v4, + const struct sset *lb_ips_v6) +{ + if (neigh_mode == LB_NEIGH_RESPOND_NONE) { + return; + } + + const char *ip_address; + SSET_FOR_EACH (ip_address, lb_ips_v4) { + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v4_reachable, + ip_address); + } + SSET_FOR_EACH (ip_address, lb_ips_v6) { + sset_find_and_delete(&lr_lbnat_rec->lb_ips->ips_v6_reachable, + ip_address); + } +} + +static void +lr_lb_nat_data_build_vip_nats(struct lr_lb_nat_data_record *lr_lbnat_rec) +{ + sset_clear(&lr_lbnat_rec->vip_nats); + const char *external_ip; + SSET_FOR_EACH (external_ip, &lr_lbnat_rec->lrnat_rec->external_ips) { + bool is_vip_nat = false; + if (addr_is_ipv6(external_ip)) { + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, + external_ip); + } else { + is_vip_nat = sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, + external_ip); + } + + if (is_vip_nat) { + sset_add(&lr_lbnat_rec->vip_nats, external_ip); + } + } +} diff --git a/northd/en-lr-lb-nat-data.h b/northd/en-lr-lb-nat-data.h new file mode 100644 index 0000000000..9029aee339 --- /dev/null +++ b/northd/en-lr-lb-nat-data.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023, Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef EN_LR_LB_NAT_DATA_H +#define EN_LR_LB_NAT_DATA_H 1 + +#include <stdint.h> + +/* OVS includes. */ +#include "lib/hmapx.h" +#include "openvswitch/hmap.h" +#include "sset.h" + +/* OVN includes. */ +#include "lib/inc-proc-eng.h" +#include "lib/lb.h" +#include "lib/ovn-nb-idl.h" +#include "lib/ovn-sb-idl.h" +#include "lib/ovn-util.h" + +struct ovn_datapath; +struct lr_nat_record; + +struct lr_lb_nat_data_record { + struct hmap_node key_node; /* Index on 'nbr->header_.uuid'. */ + + const struct ovn_datapath *od; + const struct lr_nat_record *lrnat_rec; + + /* Load Balancer vIPs relevant for this datapath. */ + struct ovn_lb_ip_set *lb_ips; + + /* sset of vips which are also part of lr nats. */ + struct sset vip_nats; +}; + +struct lr_lb_nat_data_table { + struct hmap entries; + + /* The array index of each element in 'entries'. */ + struct lr_lb_nat_data_record **array; +}; + +#define LR_LB_NAT_DATA_TABLE_FOR_EACH(LR_LB_NAT_REC, TABLE) \ + HMAP_FOR_EACH (LR_LB_NAT_REC, key_node, &(TABLE)->entries) + +struct lr_lb_nat_data_tracked_data { + /* Created or updated logical router with LB data. */ + struct hmapx crupdated; /* Stores 'struct lr_lb_nat_data_record'. */ + + /* Deleted logical router with LB data. */ + struct hmapx deleted; /* Stores 'struct lr_lb_nat_data_record'. */ +}; + +struct ed_type_lr_lb_nat_data { + struct lr_lb_nat_data_table lr_lbnats; + + bool tracked; + struct lr_lb_nat_data_tracked_data tracked_data; +}; + +struct lr_lb_nat_data_input { + const struct ovn_datapaths *lr_datapaths; + const struct hmap *lb_datapaths_map; + const struct hmap *lbgrp_datapaths_map; + const struct lr_nat_table *lr_nats; +}; + +void *en_lr_lb_nat_data_init(struct engine_node *, struct engine_arg *); +void en_lr_lb_nat_data_cleanup(void *data); +void en_lr_lb_nat_data_clear_tracked_data(void *data); +void en_lr_lb_nat_data_run(struct engine_node *, void *data); + +bool lr_lb_nat_data_northd_handler(struct engine_node *, void *data); +bool lr_lb_nat_data_lr_nat_handler(struct engine_node *, void *data); +bool lr_lb_nat_data_lb_data_handler(struct engine_node *, void *data); + +const struct lr_lb_nat_data_record *lr_lb_nat_data_table_find_by_index( + const struct lr_lb_nat_data_table *, size_t od_index); + +#endif /* EN_LR_LB_NAT_DATA_H */ \ No newline at end of file diff --git a/northd/en-lr-nat.h b/northd/en-lr-nat.h index 01a16a21aa..2e3f285d12 100644 --- a/northd/en-lr-nat.h +++ b/northd/en-lr-nat.h @@ -89,6 +89,9 @@ struct lr_nat_table { const struct lr_nat_record * lr_nat_table_find_by_index( const struct lr_nat_table *, size_t od_index); +#define LR_NAT_TABLE_FOR_EACH(LR_NAT_REC, TABLE) \ + HMAP_FOR_EACH (LR_NAT_REC, key_node, &(TABLE)->entries) + /* Incremental processing implementation. */ struct lr_nat_input { /* Northbound table references. */ diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c index 10ade620e7..7c22949f74 100644 --- a/northd/en-sync-sb.c +++ b/northd/en-sync-sb.c @@ -22,6 +22,7 @@ #include "openvswitch/util.h" #include "en-lr-nat.h" +#include "en-lr-lb-nat-data.h" #include "en-sync-sb.h" #include "lib/inc-proc-eng.h" #include "lib/lb.h" @@ -41,7 +42,7 @@ static void sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, const struct nbrec_address_set_table *, const struct nbrec_port_group_table *, const struct sbrec_address_set_table *, - const struct ovn_datapaths *lr_datapaths); + const struct lr_lb_nat_data_table *); static const struct sbrec_address_set *sb_address_set_lookup_by_name( struct ovsdb_idl_index *, const char *name); static void update_sb_addr_set(struct sorted_array *, @@ -87,11 +88,11 @@ en_sync_to_sb_addr_set_run(struct engine_node *node, void *data OVS_UNUSED) EN_OVSDB_GET(engine_get_input("SB_address_set", node)); const struct engine_context *eng_ctx = engine_get_context(); - struct northd_data *northd_data = engine_get_input_data("northd", node); - + const struct ed_type_lr_lb_nat_data *lr_lb_nat_data = + engine_get_input_data("lr_lb_nat_data", node); sync_addr_sets(eng_ctx->ovnsb_idl_txn, nb_address_set_table, nb_port_group_table, sb_address_set_table, - &northd_data->lr_datapaths); + &lr_lb_nat_data->lr_lbnats); engine_set_node_state(node, EN_UPDATED); } @@ -288,10 +289,12 @@ en_sync_to_sb_pb_run(struct engine_node *node, void *data OVS_UNUSED) { const struct engine_context *eng_ctx = engine_get_context(); struct northd_data *northd_data = engine_get_input_data("northd", node); - struct ed_type_lr_nat_data *lr_nat_data = - engine_get_input_data("lr_nat", node); + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = + engine_get_input_data("lr_lb_nat_data", node); + sync_pbs(eng_ctx->ovnsb_idl_txn, &northd_data->ls_ports, - &northd_data->lr_ports, &lr_nat_data->lr_nats); + &northd_data->lr_ports, + &lr_lb_nat_data->lr_lbnats); engine_set_node_state(node, EN_UPDATED); } @@ -316,11 +319,12 @@ sync_to_sb_pb_northd_handler(struct engine_node *node, void *data OVS_UNUSED) return false; } - struct ed_type_lr_nat_data *lr_nat_data = - engine_get_input_data("lr_nat", node); + struct ed_type_lr_lb_nat_data *lr_lb_nat_data = + engine_get_input_data("lr_lb_nat_data", node); if (!sync_pbs_for_northd_changed_ovn_ports( - &nd->trk_northd_changes.trk_ovn_ports, &lr_nat_data->lr_nats)) { + &nd->trk_northd_changes.trk_ovn_ports, + &lr_lb_nat_data->lr_lbnats)) { return false; } @@ -366,7 +370,7 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, const struct nbrec_address_set_table *nb_address_set_table, const struct nbrec_port_group_table *nb_port_group_table, const struct sbrec_address_set_table *sb_address_set_table, - const struct ovn_datapaths *lr_datapaths) + const struct lr_lb_nat_data_table *lr_lbnats) { struct shash sb_address_sets = SHASH_INITIALIZER(&sb_address_sets); @@ -410,16 +414,14 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, } /* Sync router load balancer VIP generated address sets. */ - struct ovn_datapath *od; - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { - ovs_assert(od->nbr); - - if (sset_count(&od->lb_ips->ips_v4_reachable)) { - char *ipv4_addrs_name = lr_lb_address_set_name(od->tunnel_key, - AF_INET); + const struct lr_lb_nat_data_record *lrlb_rec; + LR_LB_NAT_DATA_TABLE_FOR_EACH (lrlb_rec, lr_lbnats) { + if (sset_count(&lrlb_rec->lb_ips->ips_v4_reachable)) { + char *ipv4_addrs_name = + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET); struct sorted_array ipv4_addrs_sorted = - sorted_array_from_sset(&od->lb_ips->ips_v4_reachable); + sorted_array_from_sset(&lrlb_rec->lb_ips->ips_v4_reachable); sync_addr_set(ovnsb_txn, ipv4_addrs_name, &ipv4_addrs_sorted, &sb_address_sets); @@ -427,11 +429,11 @@ sync_addr_sets(struct ovsdb_idl_txn *ovnsb_txn, free(ipv4_addrs_name); } - if (sset_count(&od->lb_ips->ips_v6_reachable)) { - char *ipv6_addrs_name = lr_lb_address_set_name(od->tunnel_key, - AF_INET6); - struct sorted_array ipv6_addrs_sorted = - sorted_array_from_sset(&od->lb_ips->ips_v6_reachable); + if (sset_count(&lrlb_rec->lb_ips->ips_v6_reachable)) { + char *ipv6_addrs_name = + lr_lb_address_set_name(lrlb_rec->od->tunnel_key, AF_INET6); + struct sorted_array ipv6_addrs_sorted = sorted_array_from_sset( + &lrlb_rec->lb_ips->ips_v6_reachable); sync_addr_set(ovnsb_txn, ipv6_addrs_name, &ipv6_addrs_sorted, &sb_address_sets); diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c index 2bd66b8808..369a151fa3 100644 --- a/northd/inc-proc-northd.c +++ b/northd/inc-proc-northd.c @@ -31,6 +31,7 @@ #include "openvswitch/vlog.h" #include "inc-proc-northd.h" #include "en-lb-data.h" +#include "en-lr-lb-nat-data.h" #include "en-lr-nat.h" #include "en-northd.h" #include "en-lflow.h" @@ -148,6 +149,7 @@ static ENGINE_NODE(sync_to_sb_lb, "sync_to_sb_lb"); static ENGINE_NODE(sync_to_sb_pb, "sync_to_sb_pb"); static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data"); static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_nat, "lr_nat"); +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_lb_nat_data, "lr_lb_nat_data"); void inc_proc_northd_init(struct ovsdb_idl_loop *nb, struct ovsdb_idl_loop *sb) @@ -196,6 +198,13 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_lr_nat, &en_nb_logical_router, lr_nat_logical_router_handler); + engine_add_input(&en_lr_lb_nat_data, &en_northd, + lr_lb_nat_data_northd_handler); + engine_add_input(&en_lr_lb_nat_data, &en_lr_nat, + lr_lb_nat_data_lr_nat_handler); + engine_add_input(&en_lr_lb_nat_data, &en_lb_data, + lr_lb_nat_data_lb_data_handler); + engine_add_input(&en_mac_binding_aging, &en_nb_nb_global, NULL); engine_add_input(&en_mac_binding_aging, &en_sb_mac_binding, NULL); engine_add_input(&en_mac_binding_aging, &en_northd, NULL); @@ -220,12 +229,14 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_lflow, &en_northd, lflow_northd_handler); engine_add_input(&en_lflow, &en_port_group, lflow_port_group_handler); engine_add_input(&en_lflow, &en_lr_nat, NULL); + engine_add_input(&en_lflow, &en_lr_lb_nat_data, NULL); engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set, sync_to_sb_addr_set_nb_address_set_handler); engine_add_input(&en_sync_to_sb_addr_set, &en_nb_port_group, sync_to_sb_addr_set_nb_port_group_handler); engine_add_input(&en_sync_to_sb_addr_set, &en_northd, NULL); + engine_add_input(&en_sync_to_sb_addr_set, &en_lr_lb_nat_data, NULL); engine_add_input(&en_sync_to_sb_addr_set, &en_sb_address_set, NULL); engine_add_input(&en_port_group, &en_nb_port_group, @@ -243,7 +254,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_sync_to_sb_pb, &en_northd, sync_to_sb_pb_northd_handler); - engine_add_input(&en_sync_to_sb_pb, &en_lr_nat, NULL); + engine_add_input(&en_sync_to_sb_pb, &en_lr_lb_nat_data, NULL); /* en_sync_to_sb engine node syncs the SB database tables from * the NB database tables. diff --git a/northd/northd.c b/northd/northd.c index 44c9c3d729..24df14c0de 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -44,6 +44,7 @@ #include "northd.h" #include "en-lb-data.h" #include "en-lr-nat.h" +#include "en-lr-lb-nat-data.h" #include "lib/ovn-parallel-hmap.h" #include "ovn/actions.h" #include "ovn/features.h" @@ -617,13 +618,6 @@ init_lb_for_datapath(struct ovn_datapath *od) } } -static void -destroy_lb_for_datapath(struct ovn_datapath *od) -{ - ovn_lb_ip_set_destroy(od->lb_ips); - od->lb_ips = NULL; -} - /* A group of logical router datapaths which are connected - either * directly or indirectly. * Each logical router can belong to only one group. */ @@ -676,7 +670,6 @@ ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od) destroy_ipam_info(&od->ipam_info); free(od->router_ports); free(od->ls_peers); - destroy_lb_for_datapath(od); free(od->localnet_ports); free(od->l3dgw_ports); destroy_mcast_info_for_datapath(od); @@ -1311,121 +1304,6 @@ struct lflow_ref_node { struct ovn_lflow *lflow; }; -/* A logical switch port or logical router port. - * - * In steady state, an ovn_port points to a northbound Logical_Switch_Port - * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a - * southbound Port_Binding record (via 'sb'). As the state of the system - * changes, join_logical_ports() may determine that there is a new LSP or LRP - * that has no corresponding Port_Binding record (in which case build_ports()) - * will create the missing Port_Binding) or that a Port_Binding record exists - * that has no coresponding LSP (in which case build_ports() will delete the - * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port - * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. - * - * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but - * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). - */ -struct ovn_port { - /* Port name aka key. - * - * This is ordinarily the same as nbsp->name or nbrp->name and - * sb->logical_port. (A distributed gateway port creates a "derived" - * ovn_port with key "cr-%s" % nbrp->name.) */ - struct hmap_node key_node; /* Index on 'key'. */ - char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ - char *json_key; /* 'key', quoted for use in JSON. */ - - const struct sbrec_port_binding *sb; /* May be NULL. */ - - uint32_t tunnel_key; - - /* Logical switch port data. */ - const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ - - struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ - unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ - unsigned int n_lsp_non_router_addrs; /* Number of elements from the - * beginning of 'lsp_addrs' extracted - * directly from LSP 'addresses'. */ - - struct lport_addresses *ps_addrs; /* Port security addresses. */ - unsigned int n_ps_addrs; - - bool lsp_can_be_inc_processed; /* If it can be incrementally processed when - the port changes. */ - - /* Logical router port data. */ - const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ - - struct lport_addresses lrp_networks; - - struct ovn_port_routable_addresses routables; - - /* Logical port multicast data. */ - struct mcast_port_info mcast_info; - - /* At most one of l3dgw_port and cr_port can be not NULL. */ - - /* This is set to a distributed gateway port if and only if this ovn_port - * is "derived" from it. Otherwise this is set to NULL. The derived - * ovn_port represents the instance of distributed gateway port on the - * gateway chassis.*/ - struct ovn_port *l3dgw_port; - - /* This is set to the "derived" chassis-redirect port of this port if and - * only if this port is a distributed gateway port. Otherwise this is set - * to NULL. */ - struct ovn_port *cr_port; - - bool has_unknown; /* If the addresses have 'unknown' defined. */ - - bool has_bfd; - - /* The port's peer: - * - * - A switch port S of type "router" has a router port R as a peer, - * and R in turn has S has its peer. - * - * - Two connected logical router ports have each other as peer. - * - * - Other kinds of ports have no peer. */ - struct ovn_port *peer; - - struct ovn_datapath *od; - - struct ovs_list list; /* In list of similar records. */ - - struct hmap_node dp_node; /* Node in od->ports. */ - - struct lport_addresses proxy_arp_addrs; - - /* Temporarily used for traversing a list (or hmap) of ports. */ - bool visited; - - /* List of struct lflow_ref_node that points to the lflows generated by - * this ovn_port. - * - * This data is initialized and destroyed by the en_northd node, but - * populated and used only by the en_lflow node. Ideally this data should - * be maintained as part of en_lflow's data (struct lflow_data): a hash - * index from ovn_port key to lflows. However, it would be less efficient - * and more complex: - * - * 1. It would require an extra search (using the index) to find the - * lflows. - * - * 2. Building the index needs to be thread-safe, using either a global - * lock which is obviously less efficient, or hash-based lock array which - * is more complex. - * - * Adding the list here is more straightforward. The drawback is that we - * need to keep in mind that this data belongs to en_lflow node, so never - * access it from any other nodes. - */ - struct ovs_list lflows; -}; - static bool lsp_can_be_inc_processed(const struct nbrec_logical_switch_port *); static bool @@ -1450,16 +1328,21 @@ destroy_routable_addresses(struct ovn_port_routable_addresses *ra) } static char **get_nat_addresses(const struct ovn_port *op, size_t *n, - bool routable_only, bool include_lb_ips); + bool routable_only, bool include_lb_ips, + const struct lr_lb_nat_data_record *); -static void -assign_routable_addresses(struct ovn_port *op) +static struct ovn_port_routable_addresses +get_op_routable_addresses(struct ovn_port *op, + const struct lr_lb_nat_data_record *lr_lbnat_rec) { size_t n; - char **nats = get_nat_addresses(op, &n, true, true); + char **nats = get_nat_addresses(op, &n, true, true, lr_lbnat_rec); if (!nats) { - return; + return (struct ovn_port_routable_addresses) { + .laddrs = NULL, + .n_addrs = 0, + }; } struct lport_addresses *laddrs = xcalloc(n, sizeof(*laddrs)); @@ -1475,9 +1358,15 @@ assign_routable_addresses(struct ovn_port *op) } free(nats); - /* Everything seems to have worked out */ - op->routables.laddrs = laddrs; - op->routables.n_addrs = n_addrs; + if (!n_addrs) { + free(laddrs); + laddrs = NULL; + } + + return (struct ovn_port_routable_addresses) { + .laddrs = laddrs, + .n_addrs = n_addrs, + }; } @@ -1537,8 +1426,6 @@ ovn_port_destroy_orphan(struct ovn_port *port) } free(port->ps_addrs); - destroy_routable_addresses(&port->routables); - destroy_lport_addresses(&port->lrp_networks); destroy_lport_addresses(&port->proxy_arp_addrs); free(port->json_key); @@ -2580,9 +2467,7 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, sizeof *od->l3dgw_ports); } od->l3dgw_ports[od->n_l3dgw_ports++] = op; - - assign_routable_addresses(op); - } + } } } @@ -2679,7 +2564,8 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table, * and must free the returned array when it is no longer needed. */ static char ** get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, - bool include_lb_ips) + bool include_lb_ips, + const struct lr_lb_nat_data_record *lr_lbnat_rec) { size_t n_nats = 0; struct eth_addr mac; @@ -2764,23 +2650,25 @@ get_nat_addresses(const struct ovn_port *op, size_t *n, bool routable_only, } } - if (include_lb_ips) { + if (include_lb_ips && lr_lbnat_rec) { const char *ip_address; if (routable_only) { - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4_routable) { + SSET_FOR_EACH (ip_address, + &lr_lbnat_rec->lb_ips->ips_v4_routable) { ds_put_format(&c_addresses, " %s", ip_address); central_ip_address = true; } - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6_routable) { + SSET_FOR_EACH (ip_address, + &lr_lbnat_rec->lb_ips->ips_v6_routable) { ds_put_format(&c_addresses, " %s", ip_address); central_ip_address = true; } } else { - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v4) { + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v4) { ds_put_format(&c_addresses, " %s", ip_address); central_ip_address = true; } - SSET_FOR_EACH (ip_address, &op->od->lb_ips->ips_v6) { + SSET_FOR_EACH (ip_address, &lr_lbnat_rec->lb_ips->ips_v6) { ds_put_format(&c_addresses, " %s", ip_address); central_ip_address = true; } @@ -3851,21 +3739,8 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { ovs_assert(od->nbr); - /* Checking load balancer groups first, starting from the largest one, - * to more efficiently copy IP sets. */ - size_t largest_group = 0; - - for (size_t i = 1; i < od->nbr->n_load_balancer_group; i++) { - if (od->nbr->load_balancer_group[i]->n_load_balancer > - od->nbr->load_balancer_group[largest_group]->n_load_balancer) { - largest_group = i; - } - } - for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { - size_t idx = (i + largest_group) % od->nbr->n_load_balancer_group; - - nbrec_lb_group = od->nbr->load_balancer_group[idx]; + nbrec_lb_group = od->nbr->load_balancer_group[i]; const struct uuid *lb_group_uuid = &nbrec_lb_group->header_.uuid; lb_group_dps = @@ -3873,20 +3748,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, lb_group_uuid); ovs_assert(lb_group_dps); ovn_lb_group_datapaths_add_lr(lb_group_dps, od); - - if (!od->lb_ips) { - od->lb_ips = - ovn_lb_ip_set_clone(lb_group_dps->lb_group->lb_ips); - } else { - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { - build_lrouter_lb_ips(od->lb_ips, - lb_group_dps->lb_group->lbs[j]); - } - } - } - - if (!od->lb_ips) { - od->lb_ips = ovn_lb_ip_set_create(); } for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { @@ -3895,7 +3756,6 @@ build_lb_datapaths(const struct hmap *lbs, const struct hmap *lb_groups, lb_dps = ovn_lb_datapaths_find(lb_datapaths_map, lb_uuid); ovs_assert(lb_dps); ovn_lb_datapaths_add_lr(lb_dps, 1, &od); - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); } } @@ -3949,102 +3809,6 @@ build_lb_svcs( } } -static bool lrouter_port_ipv4_reachable(const struct ovn_port *op, - ovs_be32 addr); -static bool lrouter_port_ipv6_reachable(const struct ovn_port *op, - const struct in6_addr *addr); - -static void -add_neigh_ips_to_lrouter(struct ovn_datapath *od, - enum lb_neighbor_responder_mode neigh_mode, - const struct sset *lb_ips_v4, - const struct sset *lb_ips_v6) -{ - /* If configured to not reply to any neighbor requests for all VIPs - * return early. - */ - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { - return; - } - - const char *ip_address; - - /* If configured to reply to neighbor requests for all VIPs force them - * all to be considered "reachable". - */ - if (neigh_mode == LB_NEIGH_RESPOND_ALL) { - SSET_FOR_EACH (ip_address, lb_ips_v4) { - sset_add(&od->lb_ips->ips_v4_reachable, ip_address); - } - SSET_FOR_EACH (ip_address, lb_ips_v6) { - sset_add(&od->lb_ips->ips_v6_reachable, ip_address); - } - - return; - } - - /* Otherwise, a VIP is reachable if there's at least one router - * subnet that includes it. - */ - ovs_assert(neigh_mode == LB_NEIGH_RESPOND_REACHABLE); - - SSET_FOR_EACH (ip_address, lb_ips_v4) { - struct ovn_port *op; - ovs_be32 vip_ip4; - if (ip_parse(ip_address, &vip_ip4)) { - HMAP_FOR_EACH (op, dp_node, &od->ports) { - if (lrouter_port_ipv4_reachable(op, vip_ip4)) { - sset_add(&od->lb_ips->ips_v4_reachable, - ip_address); - break; - } - } - } - } - - SSET_FOR_EACH (ip_address, lb_ips_v6) { - struct ovn_port *op; - struct in6_addr vip; - if (ipv6_parse(ip_address, &vip)) { - HMAP_FOR_EACH (op, dp_node, &od->ports) { - if (lrouter_port_ipv6_reachable(op, &vip)) { - sset_add(&od->lb_ips->ips_v6_reachable, - ip_address); - break; - } - } - } - } -} - -static void -remove_lrouter_lb_reachable_ips(struct ovn_datapath *od, - enum lb_neighbor_responder_mode neigh_mode, - const struct sset *lb_ips_v4, - const struct sset *lb_ips_v6) -{ - if (neigh_mode == LB_NEIGH_RESPOND_NONE) { - return; - } - - const char *ip_address; - SSET_FOR_EACH (ip_address, lb_ips_v4) { - sset_find_and_delete(&od->lb_ips->ips_v4_reachable, ip_address); - } - SSET_FOR_EACH (ip_address, lb_ips_v6) { - sset_find_and_delete(&od->lb_ips->ips_v6_reachable, ip_address); - } -} - -static void -build_lrouter_lb_reachable_ips(struct ovn_datapath *od, - const struct ovn_northd_lb *lb) -{ - add_neigh_ips_to_lrouter(od, lb->neigh_mode, &lb->ips_v4, - &lb->ips_v6); -} - - static void build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) { @@ -4066,43 +3830,6 @@ build_lrouter_lbs_check(const struct ovn_datapaths *lr_datapaths) } } -static void -build_lrouter_lbs_reachable_ips(struct ovn_datapaths *lr_datapaths, - struct hmap *lb_dps_map, - struct hmap *lb_group_dps_map) -{ - struct ovn_datapath *od; - - HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { - if (!od->nbr) { - continue; - } - - for (size_t i = 0; i < od->nbr->n_load_balancer; i++) { - struct ovn_lb_datapaths *lb_dps = - ovn_lb_datapaths_find(lb_dps_map, - &od->nbr->load_balancer[i]->header_.uuid); - ovs_assert(lb_dps); - build_lrouter_lb_reachable_ips(od, lb_dps->lb); - } - - for (size_t i = 0; i < od->nbr->n_load_balancer_group; i++) { - const struct nbrec_load_balancer_group *nbrec_lb_group = - od->nbr->load_balancer_group[i]; - struct ovn_lb_group_datapaths *lb_group_dps; - - lb_group_dps = - ovn_lb_group_datapaths_find(lb_group_dps_map, - &nbrec_lb_group->header_.uuid); - ovs_assert(lb_group_dps); - for (size_t j = 0; j < lb_group_dps->lb_group->n_lbs; j++) { - build_lrouter_lb_reachable_ips(od, - lb_group_dps->lb_group->lbs[j]); - } - } - } -} - static void build_lswitch_lbs_from_lrouter(struct ovn_datapaths *lr_datapaths, struct hmap *lb_dps_map, @@ -4166,8 +3893,6 @@ build_lb_port_related_data( struct hmap *svc_monitor_map) { build_lrouter_lbs_check(lr_datapaths); - build_lrouter_lbs_reachable_ips(lr_datapaths, lb_dps_map, - lb_group_dps_map); build_lb_svcs(ovnsb_txn, sbrec_service_monitor_table, ls_ports, lb_dps_map, svc_monitor_lsps, svc_monitor_map); build_lswitch_lbs_from_lrouter(lr_datapaths, lb_dps_map, lb_group_dps_map); @@ -4533,7 +4258,8 @@ check_sb_lb_duplicates(const struct sbrec_load_balancer_table *table) * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it * only syncs the nat column of port binding corresponding to the 'op->nbsp' */ static void -sync_pb_for_lsp(struct ovn_port *op) +sync_pb_for_lsp(struct ovn_port *op, + const struct lr_lb_nat_data_table *lr_lbnats) { ovs_assert(op->nbsp); @@ -4552,10 +4278,17 @@ sync_pb_for_lsp(struct ovn_port *op) if (nat_addresses && !strcmp(nat_addresses, "router")) { if (op->peer && op->peer->od && (chassis || op->peer->od->n_l3dgw_ports)) { - bool exclude_lb_vips = smap_get_bool(&op->nbsp->options, + bool include_lb_vips = !smap_get_bool(&op->nbsp->options, "exclude-lb-vips-from-garp", false); + + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; + + if (include_lb_vips) { + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index( + lr_lbnats, op->peer->od->index); + } nats = get_nat_addresses(op->peer, &n_nats, false, - !exclude_lb_vips); + include_lb_vips, lr_lbnat_rec); } } else if (nat_addresses && (chassis || l3dgw_ports)) { struct lport_addresses laddrs; @@ -4662,7 +4395,8 @@ sync_pb_for_lsp(struct ovn_port *op) * Caller should make sure that the OVN SB IDL txn is not NULL. Presently it * only sets the port binding options column for the router ports */ static void -sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) +sync_pb_for_lrp(struct ovn_port *op, + const struct lr_lb_nat_data_table *lr_lbnats) { ovs_assert(op->nbrp); @@ -4671,14 +4405,14 @@ sync_pb_for_lrp(struct ovn_port *op, const struct lr_nat_table *lr_nats) const char *chassis_name = smap_get(&op->od->nbr->options, "chassis"); if (is_cr_port(op)) { - const struct lr_nat_record *lrnat_rec = - lr_nat_table_find_by_index(lr_nats, op->od->index); - ovs_assert(lrnat_rec); + const struct lr_lb_nat_data_record *lr_lbnat_rec = + lr_lb_nat_data_table_find_by_index(lr_lbnats, op->od->index); + ovs_assert(lr_lbnat_rec); smap_add(&new, "distributed-port", op->nbrp->name); bool always_redirect = - !lrnat_rec->has_distributed_nat && + !lr_lbnat_rec->lrnat_rec->has_distributed_nat && !l3dgw_port_has_associated_vtep_lports(op->l3dgw_port); const char *redirect_type = smap_get(&op->nbrp->options, @@ -4729,17 +4463,18 @@ static void ovn_update_ipv6_opt_for_op(struct ovn_port *op); * the logical switch ports. */ void sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, - struct hmap *lr_ports, const struct lr_nat_table *lr_nats) + struct hmap *lr_ports, + const struct lr_lb_nat_data_table *lr_lbnats) { ovs_assert(ovnsb_idl_txn); struct ovn_port *op; HMAP_FOR_EACH (op, key_node, ls_ports) { - sync_pb_for_lsp(op); + sync_pb_for_lsp(op, lr_lbnats); } HMAP_FOR_EACH (op, key_node, lr_ports) { - sync_pb_for_lrp(op, lr_nats); + sync_pb_for_lrp(op, lr_lbnats); } ovn_update_ipv6_options(lr_ports); @@ -4748,17 +4483,18 @@ sync_pbs(struct ovsdb_idl_txn *ovnsb_idl_txn, struct hmap *ls_ports, /* Sync the SB Port bindings for the added and updated logical switch ports * of the tracked northd engine data. */ bool -sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, - const struct lr_nat_table *lr_nats) +sync_pbs_for_northd_changed_ovn_ports( + struct tracked_ovn_ports *trk_ovn_ports, + const struct lr_lb_nat_data_table *lr_lbnats) { struct hmapx_node *hmapx_node; struct ovn_port *op; HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->created) { op = hmapx_node->data; if (op->nbsp) { - sync_pb_for_lsp(op); + sync_pb_for_lsp(op, lr_lbnats); } else { - sync_pb_for_lrp(op, lr_nats); + sync_pb_for_lrp(op, lr_lbnats); ovn_update_ipv6_opt_for_op(op); } } @@ -4766,9 +4502,9 @@ sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *trk_ovn_ports, HMAPX_FOR_EACH (hmapx_node, &trk_ovn_ports->updated) { op = hmapx_node->data; if (op->nbsp) { - sync_pb_for_lsp(op); + sync_pb_for_lsp(op, lr_lbnats); } else { - sync_pb_for_lrp(op, lr_nats); + sync_pb_for_lrp(op, lr_lbnats); ovn_update_ipv6_opt_for_op(op); } } @@ -5475,20 +5211,24 @@ fail: } /* Returns true if the logical router has changes which can be - * incrementally handled. + * incrementally handled or the changes can be ignored. * Presently supports i-p for the below changes: * - load balancers and load balancer groups. + * + * Presently below changes are ignored: + * - router NAT changes - as the engine node lr-nat handles it. */ static bool -lr_changes_can_be_handled( +lr_changes_can_be_handled_or_ignored( const struct nbrec_logical_router *lr) { /* Check if the columns are changed in this row. */ enum nbrec_logical_router_column_id col; for (col = 0; col < NBREC_LOGICAL_ROUTER_N_COLUMNS; col++) { if (nbrec_logical_router_is_updated(lr, col)) { - if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER || - col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP) { + if (col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER + || col == NBREC_LOGICAL_ROUTER_COL_LOAD_BALANCER_GROUP + || col == NBREC_LOGICAL_ROUTER_COL_NAT) { continue; } return false; @@ -5507,12 +5247,6 @@ lr_changes_can_be_handled( OVSDB_IDL_CHANGE_MODIFY) > 0) { return false; } - for (size_t i = 0; i < lr->n_nat; i++) { - if (nbrec_nat_row_get_seqno(lr->nat[i], - OVSDB_IDL_CHANGE_MODIFY) > 0) { - return false; - } - } for (size_t i = 0; i < lr->n_policies; i++) { if (nbrec_logical_router_policy_row_get_seqno(lr->policies[i], OVSDB_IDL_CHANGE_MODIFY) > 0) { @@ -5528,14 +5262,15 @@ lr_changes_can_be_handled( return true; } -/* Return true if changes are handled incrementally, false otherwise. +/* Return true if changes are handled incrementally or can be safely + * ignored (because those changes are handled by other engine nodes), + * false otherwise. * When there are any changes, try to track what's exactly changed and set * northd_data->change_tracked accordingly: change tracked - true, otherwise, * false. * Note: Changes to load balancer and load balancer groups associated with * the logical routers are handled separately in the lb_data change - * handlers (northd_handle_lb_data_changes_pre_od and - * northd_handle_lb_data_changes_post_od). + * handler (northd_handle_lb_data_changes). * */ bool northd_handle_lr_changes(const struct northd_input *ni, @@ -5550,9 +5285,11 @@ northd_handle_lr_changes(const struct northd_input *ni, goto fail; } - /* Presently only able to handle load balancer and - * load balancer group changes. */ - if (!lr_changes_can_be_handled(changed_lr)) { + /* Presently + * - only able to handle load balancer and load balancer group + changes. + * - and ignore NAT changes */ + if (!lr_changes_can_be_handled_or_ignored(changed_lr)) { goto fail; } } @@ -5804,10 +5541,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, ovs_assert(lb_dps); ovn_lb_datapaths_add_lr(lb_dps, 1, &od); - /* Add the lb_ips of lb_dps to the od. */ - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); - build_lrouter_lb_reachable_ips(od, lb_dps->lb); - /* Add the lb to the northd tracked data. */ hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); } @@ -5826,10 +5559,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, ovs_assert(lb_dps); ovn_lb_datapaths_add_lr(lb_dps, 1, &od); - /* Add the lb_ips of lb_dps to the od. */ - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); - build_lrouter_lb_reachable_ips(od, lb_dps->lb); - /* Add the lb to the northd tracked data. */ hmapx_add(&nd_changes->trk_lbs.crupdated, lb_dps); } @@ -5865,22 +5594,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, /* Re-evaluate 'od->has_lb_vip' */ init_lb_for_datapath(od); - /* Update the od->lb_ips with the deleted and inserted - * vips (if any). */ - remove_ips_from_lb_ip_set(od->lb_ips, lb->routable, - &clb->deleted_vips_v4, - &clb->deleted_vips_v6); - add_ips_to_lb_ip_set(od->lb_ips, lb->routable, - &clb->inserted_vips_v4, - &clb->inserted_vips_v6); - - remove_lrouter_lb_reachable_ips(od, lb->neigh_mode, - &clb->deleted_vips_v4, - &clb->deleted_vips_v6); - add_neigh_ips_to_lrouter(od, lb->neigh_mode, - &clb->inserted_vips_v4, - &clb->inserted_vips_v6); - /* Add the lr datapath to the northd tracked data. */ hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); } @@ -5908,9 +5621,6 @@ northd_handle_lb_data_changes(struct tracked_lb_data *trk_lb_data, /* Re-evaluate 'od->has_lb_vip' */ init_lb_for_datapath(od); - /* Add the lb_ips of lb_dps to the od. */ - build_lrouter_lb_ips(od->lb_ips, lb_dps->lb); - /* Add the lr datapath to the northd tracked data. */ hmapx_add(&nd_changes->lr_with_changed_lbs.crupdated, od); } @@ -9202,7 +8912,7 @@ arp_nd_ns_match(const char *ips, int addr_family, struct ds *match) /* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the * IPs configured on the router port. */ -static bool +bool lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) { for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { @@ -9218,7 +8928,7 @@ lrouter_port_ipv4_reachable(const struct ovn_port *op, ovs_be32 addr) /* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the * IPs configured on the router port. */ -static bool +bool lrouter_port_ipv6_reachable(const struct ovn_port *op, const struct in6_addr *addr) { @@ -9284,6 +8994,7 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, struct ovn_datapath *sw_od, struct ovn_port *sw_op, const struct lr_nat_table *lr_nats, + const struct lr_lb_nat_data_table *lr_lbnats, struct hmap *lflows, const struct ovsdb_idl_row *stage_hint) { @@ -9299,32 +9010,38 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, * router port. * Priority: 80. */ - - const char *ip_addr; - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v4_reachable) { - ovs_be32 ipv4_addr; - - /* Check if the ovn port has a network configured on which we could - * expect ARP requests for the LB VIP. - */ - if (ip_parse(ip_addr, &ipv4_addr) && - lrouter_port_ipv4_reachable(op, ipv4_addr)) { - build_lswitch_rport_arp_req_flow( - ip_addr, AF_INET, sw_op, sw_od, 80, lflows, - stage_hint); + const struct lr_lb_nat_data_record *lr_lbnat_rec = NULL; + if (op->od->nbr->n_load_balancer || op->od->nbr->n_load_balancer_group) { + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, + op->od->index); + ovs_assert(lr_lbnat_rec); + + const char *ip_addr; + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v4_reachable) { + ovs_be32 ipv4_addr; + + /* Check if the ovn port has a network configured on which we could + * expect ARP requests for the LB VIP. + */ + if (ip_parse(ip_addr, &ipv4_addr) && + lrouter_port_ipv4_reachable(op, ipv4_addr)) { + build_lswitch_rport_arp_req_flow( + ip_addr, AF_INET, sw_op, sw_od, 80, lflows, + stage_hint); + } } - } - SSET_FOR_EACH (ip_addr, &op->od->lb_ips->ips_v6_reachable) { - struct in6_addr ipv6_addr; + SSET_FOR_EACH (ip_addr, &lr_lbnat_rec->lb_ips->ips_v6_reachable) { + struct in6_addr ipv6_addr; - /* Check if the ovn port has a network configured on which we could - * expect NS requests for the LB VIP. - */ - if (ipv6_parse(ip_addr, &ipv6_addr) && - lrouter_port_ipv6_reachable(op, &ipv6_addr)) { - build_lswitch_rport_arp_req_flow( - ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, - stage_hint); + /* Check if the ovn port has a network configured on which we could + * expect NS requests for the LB VIP. + */ + if (ipv6_parse(ip_addr, &ipv6_addr) && + lrouter_port_ipv6_reachable(op, &ipv6_addr)) { + build_lswitch_rport_arp_req_flow( + ip_addr, AF_INET6, sw_op, sw_od, 80, lflows, + stage_hint); + } } } @@ -9374,13 +9091,15 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, * expect ARP requests/NS for the DNAT external_ip. */ if (nat_entry_is_v6(nat_entry)) { - if (!sset_contains(&op->od->lb_ips->ips_v6, nat->external_ip)) { + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v6, + nat->external_ip)) { build_lswitch_rport_arp_req_flow( nat->external_ip, AF_INET6, sw_op, sw_od, 80, lflows, stage_hint); } } else { - if (!sset_contains(&op->od->lb_ips->ips_v4, nat->external_ip)) { + if (!lr_lbnat_rec || !sset_contains(&lr_lbnat_rec->lb_ips->ips_v4, + nat->external_ip)) { build_lswitch_rport_arp_req_flow( nat->external_ip, AF_INET, sw_op, sw_od, 80, lflows, stage_hint); @@ -10441,6 +10160,7 @@ build_lswitch_ip_mcast_igmp_mld(struct ovn_igmp_group *igmp_group, static void build_lswitch_ip_unicast_lookup(struct ovn_port *op, const struct lr_nat_table *lr_nats, + const struct lr_lb_nat_data_table *lr_lbnats, struct hmap *lflows, struct ds *actions, struct ds *match) @@ -10456,7 +10176,8 @@ build_lswitch_ip_unicast_lookup(struct ovn_port *op, */ if (lsp_is_router(op->nbsp)) { build_lswitch_rport_arp_req_flows(op->peer, op->od, op, lr_nats, - lflows, &op->nbsp->header_); + lr_lbnats, lflows, + &op->nbsp->header_); } for (size_t i = 0; i < op->nbsp->n_addresses; i++) { @@ -12646,6 +12367,7 @@ build_lrouter_port_nat_arp_nd_flow(struct ovn_port *op, static void build_lrouter_drop_own_dest(struct ovn_port *op, const struct lr_nat_record *lrnat_rec, + const struct lr_lb_nat_data_record *lr_lbnat_rec, enum ovn_stage stage, uint16_t priority, bool drop_snat_ip, struct hmap *lflows) @@ -12658,8 +12380,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, ip); - bool router_ip_in_lb_ips = - !!sset_find(&op->od->lb_ips->ips_v4, ip); + bool router_ip_in_lb_ips = (lr_lbnat_rec && + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v4, + ip)); bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || router_ip_in_lb_ips)); @@ -12688,8 +12411,9 @@ build_lrouter_drop_own_dest(struct ovn_port *op, bool router_ip_in_snat_ips = !!shash_find(&lrnat_rec->snat_ips, ip); - bool router_ip_in_lb_ips = - !!sset_find(&op->od->lb_ips->ips_v6, ip); + bool router_ip_in_lb_ips = (lr_lbnat_rec && + !!sset_find(&lr_lbnat_rec->lb_ips->ips_v6, + ip)); bool drop_router_ip = (drop_snat_ip == (router_ip_in_snat_ips || router_ip_in_lb_ips)); @@ -13401,7 +13125,8 @@ build_ip_routing_flows_for_lrp( */ static void build_ip_routing_flows_for_router_type_lsp( - struct ovn_port *op, const struct hmap *lr_ports, struct hmap *lflows) + struct ovn_port *op, const struct lr_lb_nat_data_table *lr_lbnats, + const struct hmap *lr_ports, struct hmap *lflows) { ovs_assert(op->nbsp); if (!lsp_is_router(op->nbsp)) { @@ -13409,7 +13134,8 @@ build_ip_routing_flows_for_router_type_lsp( } struct ovn_port *peer = ovn_port_get_peer(lr_ports, op); - if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs) { + if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs + || !op->od->n_router_ports) { return; } @@ -13420,19 +13146,29 @@ build_ip_routing_flows_for_router_type_lsp( continue; } - struct ovn_port_routable_addresses *ra = &router_port->routables; - for (size_t j = 0; j < ra->n_addrs; j++) { - struct lport_addresses *laddrs = &ra->laddrs[j]; - for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { - add_route(lflows, peer->od, peer, - peer->lrp_networks.ipv4_addrs[0].addr_s, - laddrs->ipv4_addrs[k].network_s, - laddrs->ipv4_addrs[k].plen, NULL, false, 0, - &peer->nbrp->header_, false, - ROUTE_PRIO_OFFSET_CONNECTED); + const struct lr_lb_nat_data_record *lr_lbnat_rec = + lr_lb_nat_data_table_find_by_index(lr_lbnats, + router_port->od->index); + + if (router_port->nbrp->ha_chassis_group || + router_port->nbrp->n_gateway_chassis) { + struct ovn_port_routable_addresses ra = + get_op_routable_addresses(router_port, lr_lbnat_rec); + for (size_t j = 0; j < ra.n_addrs; j++) { + struct lport_addresses *laddrs = &ra.laddrs[j]; + for (size_t k = 0; k < laddrs->n_ipv4_addrs; k++) { + add_route(lflows, peer->od, peer, + peer->lrp_networks.ipv4_addrs[0].addr_s, + laddrs->ipv4_addrs[k].network_s, + laddrs->ipv4_addrs[k].plen, NULL, false, 0, + &peer->nbrp->header_, false, + ROUTE_PRIO_OFFSET_CONNECTED); + } } + destroy_routable_addresses(&ra); } } + } static void @@ -13656,33 +13392,36 @@ build_arp_resolve_flows_for_lrouter( static void routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, - struct ovn_port *peer, struct ds *match, - struct ds *actions) + struct ovn_port *peer, + const struct lr_lb_nat_data_record *lr_lbnat_rec, + struct ds *match, struct ds *actions) { - struct ovn_port_routable_addresses *ra = &router_port->routables; - if (!ra->n_addrs) { + struct ovn_port_routable_addresses ra = + get_op_routable_addresses(router_port, lr_lbnat_rec); + if (!ra.n_addrs) { return; } - for (size_t i = 0; i < ra->n_addrs; i++) { + for (size_t i = 0; i < ra.n_addrs; i++) { ds_clear(match); ds_put_format(match, "outport == %s && "REG_NEXT_HOP_IPV4" == {", peer->json_key); bool first = true; - for (size_t j = 0; j < ra->laddrs[i].n_ipv4_addrs; j++) { + for (size_t j = 0; j < ra.laddrs[i].n_ipv4_addrs; j++) { if (!first) { ds_put_cstr(match, ", "); } - ds_put_cstr(match, ra->laddrs[i].ipv4_addrs[j].addr_s); + ds_put_cstr(match, ra.laddrs[i].ipv4_addrs[j].addr_s); first = false; } ds_put_cstr(match, "}"); ds_clear(actions); - ds_put_format(actions, "eth.dst = %s; next;", ra->laddrs[i].ea_s); + ds_put_format(actions, "eth.dst = %s; next;", ra.laddrs[i].ea_s); ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100, ds_cstr(match), ds_cstr(actions)); } + destroy_routable_addresses(&ra); } /* Local router ingress table ARP_RESOLVE: ARP Resolution. @@ -13699,6 +13438,7 @@ routable_addresses_to_lflows(struct hmap *lflows, struct ovn_port *router_port, static void build_arp_resolve_flows_for_lrp( struct ovn_port *op, const struct lr_nat_record *lrnat_rec, + const struct lr_lb_nat_data_record *lr_lbnat_rec, struct hmap *lflows, struct ds *match, struct ds *actions) { ovs_assert(op->nbrp); @@ -13775,8 +13515,8 @@ build_arp_resolve_flows_for_lrp( * * Priority 2. */ - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_ARP_RESOLVE, 2, - true, lflows); + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, + S_ROUTER_IN_ARP_RESOLVE, 2, true, lflows); } /* This function adds ARP resolve flows related to a LSP. */ @@ -13784,6 +13524,7 @@ static void build_arp_resolve_flows_for_lsp( struct ovn_port *op, struct hmap *lflows, const struct hmap *lr_ports, + const struct lr_lb_nat_data_table *lr_lbnats, struct ds *match, struct ds *actions) { ovs_assert(op->nbsp); @@ -13927,8 +13668,11 @@ build_arp_resolve_flows_for_lsp( if (smap_get(&peer->od->nbr->options, "chassis") || peer->cr_port) { + const struct lr_lb_nat_data_record *lr_lbnat_rec; + lr_lbnat_rec = lr_lb_nat_data_table_find_by_index(lr_lbnats, + router_port->od->index); routable_addresses_to_lflows(lflows, router_port, peer, - match, actions); + lr_lbnat_rec, match, actions); } } } @@ -14648,6 +14392,7 @@ static void build_lrouter_ipv4_ip_input(struct ovn_port *op, struct hmap *lflows, const struct lr_nat_record *lrnat_rec, + const struct lr_lb_nat_data_record *lr_lbnat_rec, struct ds *match, struct ds *actions, const struct shash *meter_groups) { @@ -14772,7 +14517,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, &op->nbrp->header_, lflows); } - if (sset_count(&op->od->lb_ips->ips_v4_reachable)) { + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v4_reachable)) { ds_clear(match); if (is_l3dgw_port(op)) { ds_put_format(match, "is_chassis_resident(%s)", @@ -14788,7 +14533,7 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, free(lb_ips_v4_as); } - if (sset_count(&op->od->lb_ips->ips_v6_reachable)) { + if (lr_lbnat_rec && sset_count(&lr_lbnat_rec->lb_ips->ips_v6_reachable)) { ds_clear(match); if (is_l3dgw_port(op)) { @@ -14890,8 +14635,8 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op, * Priority 60. */ if (!lrnat_rec->lb_force_snat_router_ip) { - build_lrouter_drop_own_dest(op, lrnat_rec, S_ROUTER_IN_IP_INPUT, 60, - false, lflows); + build_lrouter_drop_own_dest(op, lrnat_rec, lr_lbnat_rec, + S_ROUTER_IN_IP_INPUT, 60, false, lflows); } /* ARP / ND handling for external IP addresses. * @@ -16030,6 +15775,7 @@ struct lswitch_flow_build_info { const struct hmap *lr_ports; const struct ls_port_group_table *ls_port_groups; const struct lr_nat_table *lr_nats; + const struct lr_lb_nat_data_table *lr_lbnats; struct hmap *lflows; struct hmap *igmp_groups; const struct shash *meter_groups; @@ -16113,14 +15859,15 @@ build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od, * switch port. */ static void -build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, - const struct hmap *ls_ports, - const struct hmap *lr_ports, - const struct lr_nat_table *lr_nats, - const struct shash *meter_groups, - struct ds *match, - struct ds *actions, - struct hmap *lflows) +build_lswitch_and_lrouter_iterate_by_lsp( + struct ovn_port *op, const struct hmap *ls_ports, + const struct hmap *lr_ports, + const struct lr_nat_table *lr_nats, + const struct lr_lb_nat_data_table *lr_lbnats, + const struct shash *meter_groups, + struct ds *match, + struct ds *actions, + struct hmap *lflows) { ovs_assert(op->nbsp); start_collecting_lflows(); @@ -16133,11 +15880,14 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, meter_groups, actions, match); build_lswitch_dhcp_options_and_response(op, lflows, meter_groups); build_lswitch_external_port(op, lflows); - build_lswitch_ip_unicast_lookup(op, lr_nats, lflows, actions, match); + build_lswitch_ip_unicast_lookup(op, lr_nats, lr_lbnats, lflows, actions, + match); /* Build Logical Router Flows. */ - build_ip_routing_flows_for_router_type_lsp(op, lr_ports, lflows); - build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, match, actions); + build_ip_routing_flows_for_router_type_lsp(op, lr_lbnats, lr_ports, + lflows); + build_arp_resolve_flows_for_lsp(op, lflows, lr_ports, lr_lbnats, + match, actions); link_ovn_port_to_lflows(op, &collected_lflows); end_collecting_lflows(); @@ -16156,6 +15906,8 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, lsi->lr_nats, op->od->index); ovs_assert(lrnet_rec); + const struct lr_lb_nat_data_record *lr_lbnat_rec = + lr_lb_nat_data_table_find_by_index(lsi->lr_lbnats, op->od->index); build_adm_ctrl_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, &lsi->actions); build_neigh_learning_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, @@ -16163,15 +15915,15 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, build_ip_routing_flows_for_lrp(op, lsi->lflows); build_ND_RA_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, &lsi->actions, lsi->meter_groups); - build_arp_resolve_flows_for_lrp(op, lrnet_rec, lsi->lflows, &lsi->match, - &lsi->actions); + build_arp_resolve_flows_for_lrp(op, lrnet_rec, lr_lbnat_rec, lsi->lflows, + &lsi->match, &lsi->actions); build_egress_delivery_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, &lsi->actions); build_dhcpv6_reply_flows_for_lrouter_port(op, lsi->lflows, &lsi->match); build_ipv6_input_flows_for_lrouter_port(op, lsi->lflows, &lsi->match, &lsi->actions, lsi->meter_groups); - build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, + build_lrouter_ipv4_ip_input(op, lsi->lflows, lrnet_rec, lr_lbnat_rec, &lsi->match, &lsi->actions, lsi->meter_groups); build_lrouter_force_snat_flows_op(op, lrnet_rec, lsi->lflows, &lsi->match, &lsi->actions); @@ -16234,6 +15986,7 @@ build_lflows_thread(void *arg) build_lswitch_and_lrouter_iterate_by_lsp(op, lsi->ls_ports, lsi->lr_ports, lsi->lr_nats, + lsi->lr_lbnats, lsi->meter_groups, &lsi->match, &lsi->actions, @@ -16344,6 +16097,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, const struct hmap *lr_ports, const struct ls_port_group_table *ls_pgs, const struct lr_nat_table *lr_nats, + const struct lr_lb_nat_data_table *lr_lbnats, struct hmap *lflows, struct hmap *igmp_groups, const struct shash *meter_groups, @@ -16374,6 +16128,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, lsiv[index].lr_ports = lr_ports; lsiv[index].ls_port_groups = ls_pgs; lsiv[index].lr_nats = lr_nats; + lsiv[index].lr_lbnats = lr_lbnats; lsiv[index].igmp_groups = igmp_groups; lsiv[index].meter_groups = meter_groups; lsiv[index].lb_dps_map = lb_dps_map; @@ -16409,6 +16164,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, .lr_ports = lr_ports, .ls_port_groups = ls_pgs, .lr_nats = lr_nats, + .lr_lbnats = lr_lbnats, .lflows = lflows, .igmp_groups = igmp_groups, .meter_groups = meter_groups, @@ -16437,6 +16193,7 @@ build_lswitch_and_lrouter_flows(const struct ovn_datapaths *ls_datapaths, build_lswitch_and_lrouter_iterate_by_lsp(op, lsi.ls_ports, lsi.lr_ports, lsi.lr_nats, + lsi.lr_lbnats, lsi.meter_groups, &lsi.match, &lsi.actions, lsi.lflows); @@ -16558,6 +16315,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, input_data->lr_ports, input_data->ls_port_groups, input_data->lr_nats, + input_data->lr_lbnats, lflows, &igmp_groups, input_data->meter_groups, @@ -17038,6 +16796,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, lflow_input->lr_ports, lflow_input->lr_nats, + lflow_input->lr_lbnats, lflow_input->meter_groups, &match, &actions, lflows); @@ -17076,6 +16835,7 @@ lflow_handle_northd_port_changes(struct ovsdb_idl_txn *ovnsb_txn, build_lswitch_and_lrouter_iterate_by_lsp(op, lflow_input->ls_ports, lflow_input->lr_ports, lflow_input->lr_nats, + lflow_input->lr_lbnats, lflow_input->meter_groups, &match, &actions, lflows); diff --git a/northd/northd.h b/northd/northd.h index 564729ebcc..7c446f5758 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -179,6 +179,7 @@ struct lflow_input { const struct hmap *lr_ports; const struct ls_port_group_table *ls_port_groups; const struct lr_nat_table *lr_nats; + const struct lr_lb_nat_data_table *lr_lbnats; const struct shash *meter_groups; const struct hmap *lb_datapaths_map; const struct hmap *bfd_connections; @@ -318,9 +319,6 @@ struct ovn_datapath { /* router datapath has a logical port with redirect-type set to bridged. */ bool redirect_bridged; - /* Load Balancer vIPs relevant for this datapath. */ - struct ovn_lb_ip_set *lb_ips; - struct ovn_port **localnet_ports; size_t n_localnet_ports; @@ -337,6 +335,119 @@ struct ovn_datapath { const struct ovn_datapath *ovn_datapath_find(const struct hmap *datapaths, const struct uuid *uuid); +/* A logical switch port or logical router port. + * + * In steady state, an ovn_port points to a northbound Logical_Switch_Port + * record (via 'nbsp') *or* a Logical_Router_Port record (via 'nbrp'), and to a + * southbound Port_Binding record (via 'sb'). As the state of the system + * changes, join_logical_ports() may determine that there is a new LSP or LRP + * that has no corresponding Port_Binding record (in which case build_ports()) + * will create the missing Port_Binding) or that a Port_Binding record exists + * that has no coresponding LSP (in which case build_ports() will delete the + * spurious Port_Binding). Thus, after build_ports() runs, any given ovn_port + * will have 'sb' nonnull, and 'nbsp' xor 'nbrp' nonnull. + * + * Ordinarily there is only one ovn_port that points to a given LSP or LRP (but + * distributed gateway ports point a "derived" ovn_port to a duplicate LRP). + */ +struct ovn_port { + /* Port name aka key. + * + * This is ordinarily the same as nbsp->name or nbrp->name and + * sb->logical_port. (A distributed gateway port creates a "derived" + * ovn_port with key "cr-%s" % nbrp->name.) */ + struct hmap_node key_node; /* Index on 'key'. */ + char *key; /* nbsp->name, nbrp->name, sb->logical_port. */ + char *json_key; /* 'key', quoted for use in JSON. */ + + const struct sbrec_port_binding *sb; /* May be NULL. */ + + uint32_t tunnel_key; + + /* Logical switch port data. */ + const struct nbrec_logical_switch_port *nbsp; /* May be NULL. */ + + struct lport_addresses *lsp_addrs; /* Logical switch port addresses. */ + unsigned int n_lsp_addrs; /* Total length of lsp_addrs. */ + unsigned int n_lsp_non_router_addrs; /* Number of elements from the + * beginning of 'lsp_addrs' extracted + * directly from LSP 'addresses'. */ + + struct lport_addresses *ps_addrs; /* Port security addresses. */ + unsigned int n_ps_addrs; + + bool lsp_can_be_inc_processed; /* If it can be incrementally processed when + the port changes. */ + + /* Logical router port data. */ + const struct nbrec_logical_router_port *nbrp; /* May be NULL. */ + + struct lport_addresses lrp_networks; + + /* Logical port multicast data. */ + struct mcast_port_info mcast_info; + + /* At most one of l3dgw_port and cr_port can be not NULL. */ + + /* This is set to a distributed gateway port if and only if this ovn_port + * is "derived" from it. Otherwise this is set to NULL. The derived + * ovn_port represents the instance of distributed gateway port on the + * gateway chassis.*/ + struct ovn_port *l3dgw_port; + + /* This is set to the "derived" chassis-redirect port of this port if and + * only if this port is a distributed gateway port. Otherwise this is set + * to NULL. */ + struct ovn_port *cr_port; + + bool has_unknown; /* If the addresses have 'unknown' defined. */ + + bool has_bfd; + + /* The port's peer: + * + * - A switch port S of type "router" has a router port R as a peer, + * and R in turn has S has its peer. + * + * - Two connected logical router ports have each other as peer. + * + * - Other kinds of ports have no peer. */ + struct ovn_port *peer; + + struct ovn_datapath *od; + + struct ovs_list list; /* In list of similar records. */ + + struct hmap_node dp_node; /* Node in od->ports. */ + + struct lport_addresses proxy_arp_addrs; + + /* Temporarily used for traversing a list (or hmap) of ports. */ + bool visited; + + /* List of struct lflow_ref_node that points to the lflows generated by + * this ovn_port. + * + * This data is initialized and destroyed by the en_northd node, but + * populated and used only by the en_lflow node. Ideally this data should + * be maintained as part of en_lflow's data (struct lflow_data): a hash + * index from ovn_port key to lflows. However, it would be less efficient + * and more complex: + * + * 1. It would require an extra search (using the index) to find the + * lflows. + * + * 2. Building the index needs to be thread-safe, using either a global + * lock which is obviously less efficient, or hash-based lock array which + * is more complex. + * + * Adding the list here is more straightforward. The drawback is that we + * need to keep in mind that this data belongs to en_lflow node, so never + * access it from any other nodes. + */ + struct ovs_list lflows; +}; + void ovnnb_db_run(struct northd_input *input_data, struct northd_data *data, struct ovsdb_idl_txn *ovnnb_txn, @@ -396,13 +507,27 @@ void sync_lbs(struct ovsdb_idl_txn *, const struct sbrec_load_balancer_table *, struct chassis_features *chassis_features); bool check_sb_lb_duplicates(const struct sbrec_load_balancer_table *); +struct lr_lb_nat_data_table; void sync_pbs(struct ovsdb_idl_txn *, struct hmap *ls_ports, - struct hmap *lr_ports, const struct lr_nat_table *); -bool sync_pbs_for_northd_changed_ovn_ports(struct tracked_ovn_ports *, - const struct lr_nat_table *); + struct hmap *lr_ports, + const struct lr_lb_nat_data_table *); +bool sync_pbs_for_northd_changed_ovn_ports( + struct tracked_ovn_ports *, + const struct lr_lb_nat_data_table *); bool northd_has_tracked_data(struct northd_tracked_data *); bool northd_has_only_ports_in_tracked_data(struct northd_tracked_data *); bool northd_has_lbs_in_tracked_data(struct northd_tracked_data *); +/* Returns 'true' if the IPv4 'addr' is on the same subnet with one of the + * IPs configured on the router port. + */ +bool lrouter_port_ipv4_reachable(const struct ovn_port *, ovs_be32 addr); + +/* Returns 'true' if the IPv6 'addr' is on the same subnet with one of the + * IPs configured on the router port. + */ +bool lrouter_port_ipv6_reachable(const struct ovn_port *, + const struct in6_addr *); + #endif /* NORTHD_H */ diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index b7f9cb5689..8fc5cd1d60 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -10416,18 +10416,21 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:10.0.0.3=sw0-p1:10.0.0.2 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute check ovn-nbctl --wait=sb set load_balancer . options:foo=bar check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute check ovn-nbctl --wait=sb -- lb-add lb2 20.0.0.10:80 20.0.0.20:80 -- lb-add lb3 30.0.0.10:80 30.0.0.20:80 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute @@ -10437,6 +10440,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb -- lb-del lb2 -- lb-del lb3 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute @@ -10450,6 +10454,7 @@ AT_CHECK([ovn-nbctl --wait=sb \ ]) check_engine_stats lb_data norecompute compute check_engine_stats northd recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute @@ -10467,6 +10472,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb clear Load_Balancer . health_check check_engine_stats lb_data norecompute compute check_engine_stats northd recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute @@ -10481,6 +10487,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 check_engine_stats lb_data norecompute compute check_engine_stats northd recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute @@ -10489,6 +10496,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute # A LB applied to a switch/router triggers: # - a recompute in the first iteration (handling northd change) @@ -10501,6 +10509,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10510,6 +10519,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb clear load_Balancer lb1 vips check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10519,6 +10529,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10528,6 +10539,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10537,6 +10549,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb ls-lb-del sw0 lb1 check_engine_stats lb_data norecompute compute check_engine_stats northd recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10547,6 +10560,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 -- lsp-add sw0 sw0p1 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute @@ -10567,6 +10581,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-lb-add lr0 lb1 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10576,6 +10591,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10585,6 +10601,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb clear load_Balancer lb1 vips check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10594,6 +10611,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10603,6 +10621,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10632,6 +10651,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb add load_balancer_group . load_Balancer $lb1_uuid check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute @@ -10639,6 +10659,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb clear load_balancer_group . load_Balancer check_engine_stats lb_data norecompute compute check_engine_stats northd recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute @@ -10655,6 +10676,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute @@ -10671,6 +10693,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10680,6 +10703,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb clear load_Balancer lb1 vips check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10689,6 +10713,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10698,6 +10723,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10713,6 +10739,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl add logical_router lr0 load_balancer_group $lbg1_uuid check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10722,6 +10749,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.100:80"' check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10731,6 +10759,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb clear load_Balancer lb1 vips check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10740,6 +10769,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10749,6 +10779,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10757,6 +10788,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb clear logical_router lr0 load_balancer_group check_engine_stats lb_data norecompute compute check_engine_stats northd recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute @@ -10765,6 +10797,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute @@ -10773,6 +10806,7 @@ check ovn-nbctl --wait=sb clear logical_switch sw0 load_balancer_group -- \ destroy load_balancer_group $lbg1_uuid check_engine_stats lb_data norecompute compute check_engine_stats northd recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb compute compute @@ -10796,6 +10830,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats lbg1_uuid=$(ovn-nbctl --wait=sb create load_balancer_group name=lbg1) check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow norecompute nocompute check_engine_stats sync_to_sb_lb norecompute nocompute @@ -10803,6 +10838,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set load_balancer_group . load_balancer="$lb2_uuid,$lb3_uuid,$lb4_uuid" check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute @@ -10810,6 +10846,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set logical_switch sw0 load_balancer_group=$lbg1_uuid check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10818,6 +10855,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set logical_router lr1 load_balancer_group=$lbg1_uuid check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10826,6 +10864,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb ls-lb-add sw0 lb2 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10834,6 +10873,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb ls-lb-add sw0 lb3 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10843,6 +10883,7 @@ check ovn-nbctl --wait=sb lr-lb-add lr1 lb1 check ovn-nbctl --wait=sb lr-lb-add lr1 lb2 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10851,6 +10892,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb ls-lb-del sw0 lb2 check_engine_stats lb_data norecompute compute check_engine_stats northd recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10859,6 +10901,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-lb-del lr1 lb2 check_engine_stats lb_data norecompute compute check_engine_stats northd recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10869,6 +10912,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lb-del lb4 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10879,6 +10923,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lb-del lb2 check_engine_stats lb_data norecompute compute check_engine_stats northd norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -10887,6 +10932,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb remove load_balancer_group . load_balancer $lb3_uuid check_engine_stats lb_data norecompute compute check_engine_stats northd recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_lb recompute compute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11019,6 +11065,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-add lr0 check_engine_stats northd recompute nocompute check_engine_stats lr_nat recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute check_engine_stats lflow recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11031,6 +11078,7 @@ check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 # for the SB port binding change. check_engine_stats northd recompute compute check_engine_stats lr_nat recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute check_engine_stats lflow recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11042,6 +11090,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 check_engine_stats northd recompute nocompute check_engine_stats lr_nat recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute check_engine_stats lflow recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11067,6 +11116,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl set logical_router_port lr0-sw0 options:foo=bar check_engine_stats northd recompute nocompute check_engine_stats lr_nat recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute check_engine_stats lflow recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11076,8 +11126,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE # engine nodes. check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 -check_engine_stats northd recompute nocompute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11085,8 +11135,8 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE # Update the NAT options column check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set NAT . options:foo=bar -check_engine_stats northd recompute nocompute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11094,8 +11144,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE # Update the NAT external_ip column check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set NAT . external_ip=172.168.0.120 -check_engine_stats northd recompute nocompute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11103,8 +11154,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE # Update the NAT logical_ip column check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set NAT . logical_ip=10.0.0.10 -check_engine_stats northd recompute nocompute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11112,8 +11164,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE # Update the NAT type check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set NAT . type=snat -check_engine_stats northd recompute nocompute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11121,8 +11174,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE # Create a dnat_and_snat NAT with external_mac and logical_port check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.110 10.0.0.4 sw0p1 30:54:00:00:00:03 -check_engine_stats northd recompute compute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11131,8 +11185,9 @@ nat2_uuid=$(ovn-nbctl --bare --columns _uuid find nat logical_ip=10.0.0.4) check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb set NAT $nat2_uuid external_mac='"30:54:00:00:00:04"' -check_engine_stats northd recompute nocompute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11147,32 +11202,36 @@ check ovn-nbctl lr-lb-add lr0 lb2 # is a lb vip. check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.140 10.0.0.20 -check_engine_stats northd recompute nocompute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats sync_to_sb_pb recompute nocompute check_engine_stats lflow recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-nat-add lr0 dnat_and_snat 172.168.0.150 10.0.0.41 -check_engine_stats northd recompute nocompute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats sync_to_sb_pb recompute nocompute check_engine_stats lflow recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.150 -check_engine_stats northd recompute nocompute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats sync_to_sb_pb recompute nocompute check_engine_stats lflow recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-nat-del lr0 dnat_and_snat 172.168.0.140 -check_engine_stats northd recompute nocompute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats sync_to_sb_pb recompute nocompute check_engine_stats lflow recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11180,8 +11239,9 @@ CHECK_NO_CHANGE_AFTER_RECOMPUTE # Delete the NAT check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb clear logical_router lr0 nat -check_engine_stats northd recompute compute -check_engine_stats lr_nat recompute nocompute +check_engine_stats northd norecompute compute +check_engine_stats lr_nat norecompute compute +check_engine_stats lr_lb_nat_data norecompute compute check_engine_stats lflow recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11191,6 +11251,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-policy-add lr0 10 "ip4.src == 10.0.0.3" reroute 172.168.0.101,172.168.0.102 check_engine_stats northd recompute nocompute check_engine_stats lr_nat recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute check_engine_stats lflow recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -11199,6 +11260,7 @@ check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats check ovn-nbctl --wait=sb lr-policy-del lr0 10 "ip4.src == 10.0.0.3" check_engine_stats northd recompute nocompute check_engine_stats lr_nat recompute nocompute +check_engine_stats lr_lb_nat_data recompute nocompute check_engine_stats sync_to_sb_pb recompute nocompute check_engine_stats lflow recompute nocompute CHECK_NO_CHANGE_AFTER_RECOMPUTE