On 11/23/23 22:29, Dumitru Ceara wrote:
> On 11/23/23 21:45, Dumitru Ceara wrote:
>> On 10/26/23 20:15, [email protected] wrote:
>>> From: Numan Siddique <[email protected]>
>>>
>>> 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 <[email protected]>
>>> ---
>>> 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
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev