On Wed, Dec 13, 2023 at 8:54 AM Dumitru Ceara <dce...@redhat.com> wrote:
>
> On 11/28/23 03:37, num...@ovn.org wrote:
> > From: Numan Siddique <num...@ovn.org>
> >
> > Signed-off-by: Numan Siddique <num...@ovn.org>
> > ---
> >  northd/en-lflow.c        |  29 +++
> >  northd/en-lflow.h        |   1 +
> >  northd/en-lr-stateful.c  |  39 ++++-
> >  northd/en-lr-stateful.h  |  26 +++
> >  northd/inc-proc-northd.c |   3 +-
> >  northd/northd.c          | 370 ++++++++++++++++++++++-----------------
> >  northd/northd.h          |  10 ++
> >  tests/ovn-northd.at      |  48 ++---
> >  8 files changed, 336 insertions(+), 190 deletions(-)
> >
> > diff --git a/northd/en-lflow.c b/northd/en-lflow.c
> > index 13284b5556..09748f570b 100644
> > --- a/northd/en-lflow.c
> > +++ b/northd/en-lflow.c
> > @@ -164,6 +164,35 @@ lflow_port_group_handler(struct engine_node *node, 
> > void *data OVS_UNUSED)
> >      return true;
> >  }
> >
> > +bool
> > +lflow_lr_stateful_handler(struct engine_node *node, void *data)
> > +{
> > +    struct ed_type_lr_stateful *lr_sful_data =
>
> I don't really like the 'lr_sful_data' abbreviation.  What about
> 'stateful_data', it's one character longer?  Or even 'lr_stateful_data'?
>
> I now realize that this is used in a lot of places throughout
> the series.  I don't want to generate a lot of extra work just to
> rename it so I'll leave it up to you.
>

In v4,  I've changed  'sful' to 'stateful' where it is used.


> > +        engine_get_input_data("lr_stateful", node);
> > +
> > +    if (!lr_stateful_has_tracked_data(&lr_sful_data->trk_data)
> > +        || lr_sful_data->trk_data.vip_nats_changed) {
> > +        return false;
> > +    }
> > +
> > +    const struct engine_context *eng_ctx = engine_get_context();
> > +    struct lflow_data *lflow_data = data;
> > +
> > +    struct lflow_input lflow_input;
>
> Nit: I'd add an empty line here and remove the one above (to group
> all declarations).

Ack.  Done in v4.


>
> > +    lflow_get_input_data(node, &lflow_input);
> > +
> > +    if (!lflow_handle_lr_stateful_changes(eng_ctx->ovnsb_idl_txn,
> > +                                          &lr_sful_data->trk_data,
> > +                                          &lflow_input,
> > +                                          lflow_data->lflow_table)) {
> > +        return false;
> > +    }
> > +
> > +    engine_set_node_state(node, EN_UPDATED);
> > +
> > +    return true;
> > +}
> > +
> >  void *en_lflow_init(struct engine_node *node OVS_UNUSED,
> >                       struct engine_arg *arg OVS_UNUSED)
> >  {
> > diff --git a/northd/en-lflow.h b/northd/en-lflow.h
> > index f7325c56b1..1d813a2a29 100644
> > --- a/northd/en-lflow.h
> > +++ b/northd/en-lflow.h
> > @@ -20,5 +20,6 @@ void *en_lflow_init(struct engine_node *node, struct 
> > engine_arg *arg);
> >  void en_lflow_cleanup(void *data);
> >  bool lflow_northd_handler(struct engine_node *, void *data);
> >  bool lflow_port_group_handler(struct engine_node *, void *data);
> > +bool lflow_lr_stateful_handler(struct engine_node *, void *data);
> >
> >  #endif /* EN_LFLOW_H */
> > diff --git a/northd/en-lr-stateful.c b/northd/en-lr-stateful.c
> > index a54749ad93..8e025f057e 100644
> > --- a/northd/en-lr-stateful.c
> > +++ b/northd/en-lr-stateful.c
> > @@ -39,6 +39,7 @@
> >  #include "lib/ovn-sb-idl.h"
> >  #include "lib/ovn-util.h"
> >  #include "lib/stopwatch-names.h"
> > +#include "lflow-mgr.h"
> >  #include "northd.h"
> >
> >  VLOG_DEFINE_THIS_MODULE(en_lr_stateful);
> > @@ -81,7 +82,7 @@ static void remove_lrouter_lb_reachable_ips(struct 
> > lr_stateful_record *,
> >                                              enum 
> > lb_neighbor_responder_mode,
> >                                              const struct sset *lb_ips_v4,
> >                                              const struct sset *lb_ips_v6);
> > -static void lr_stateful_build_vip_nats(struct lr_stateful_record *);
> > +static bool lr_stateful_build_vip_nats(struct lr_stateful_record *);
> >
> >  /* 'lr_stateful' engine node manages the NB logical router LB data.
> >   */
> > @@ -110,6 +111,7 @@ en_lr_stateful_clear_tracked_data(void *data_)
> >      struct ed_type_lr_stateful *data = (struct ed_type_lr_stateful *) 
> > data_;
> >
> >      hmapx_clear(&data->trk_data.crupdated);
> > +    data->trk_data.vip_nats_changed = false;
> >  }
> >
> >  void
> > @@ -190,6 +192,10 @@ lr_stateful_lb_data_handler(struct engine_node *node, 
> > void *data_)
> >
> >              /* Add the lr_sful_rec rec to the tracking data. */
> >              hmapx_add(&data->trk_data.crupdated, lr_sful_rec);
> > +
> > +            if (!sset_is_empty(&lr_sful_rec->vip_nats)) {
> > +                data->trk_data.vip_nats_changed = true;
> > +            }
> >              continue;
> >          }
> >
> > @@ -298,7 +304,9 @@ lr_stateful_lb_data_handler(struct engine_node *node, 
> > void *data_)
> >           * vip nats. */
> >          HMAPX_FOR_EACH (hmapx_node, &data->trk_data.crupdated) {
> >              lr_sful_rec = hmapx_node->data;
> > -            lr_stateful_build_vip_nats(lr_sful_rec);
> > +            if (lr_stateful_build_vip_nats(lr_sful_rec)) {
> > +                data->trk_data.vip_nats_changed = true;
> > +            }
> >              lr_sful_rec->has_lb_vip = od_has_lb_vip(lr_sful_rec->od);
> >          }
> >
> > @@ -335,8 +343,13 @@ lr_stateful_lr_nat_handler(struct engine_node *node, 
> > void *data_)
> >                                              lrnat_rec,
> >                                              input_data.lb_datapaths_map,
> >                                              
> > input_data.lbgrp_datapaths_map);
> > +            if (!sset_is_empty(&lr_sful_rec->vip_nats)) {
> > +                data->trk_data.vip_nats_changed = true;
> > +            }
> >          } else {
> > -            lr_stateful_build_vip_nats(lr_sful_rec);
> > +            if (lr_stateful_build_vip_nats(lr_sful_rec)) {
> > +                data->trk_data.vip_nats_changed = true;
> > +            }
> >          }
> >
> >          /* Add the lr_sful_rec rec to the tracking data. */
> > @@ -435,6 +448,7 @@ lr_stateful_record_create(struct lr_stateful_table 
> > *table,
> >      lr_sful_rec->od = lrnat_rec->od;
> >      lr_stateful_record_init(lr_sful_rec, lb_datapaths_map,
> >                                 lbgrp_datapaths_map);
> > +    lr_sful_rec->lflow_ref = lflow_ref_alloc(lr_sful_rec->od->nbr->name);
> >
> >      hmap_insert(&table->entries, &lr_sful_rec->key_node,
> >                  uuid_hash(&lr_sful_rec->od->nbr->header_.uuid));
> > @@ -449,6 +463,7 @@ lr_stateful_record_destroy(struct lr_stateful_record 
> > *lr_sful_rec)
> >      ovn_lb_ip_set_destroy(lr_sful_rec->lb_ips);
> >      lr_sful_rec->lb_ips = NULL;
> >      sset_destroy(&lr_sful_rec->vip_nats);
> > +    lflow_ref_destroy(lr_sful_rec->lflow_ref);
> >      free(lr_sful_rec);
> >  }
> >
> > @@ -515,7 +530,7 @@ lr_stateful_record_init(struct lr_stateful_record 
> > *lr_sful_rec,
> >
> >      sset_init(&lr_sful_rec->vip_nats);
> >
> > -    if (!nbr->n_nat) {
> > +    if (nbr->n_nat) {
>
> Is this a bug fix for a previous patch in the series?  I think this belongs 
> in patch
> 05/16 ("northd: Add a new engine 'lr_stateful' to manage lr's stateful 
> data.").

Good catch.  Fixed in v4.


>
> >          lr_stateful_build_vip_nats(lr_sful_rec);
> >      }
> >
> > @@ -629,10 +644,12 @@ remove_lrouter_lb_reachable_ips(struct 
> > lr_stateful_record *lr_sful_rec,
> >      }
> >  }
> >
> > -static void
> > +static bool
> >  lr_stateful_build_vip_nats(struct lr_stateful_record *lr_sful_rec)
> >  {
> > -    sset_clear(&lr_sful_rec->vip_nats);
> > +    struct sset old_vip_nats = SSET_INITIALIZER(&old_vip_nats);
> > +    sset_swap(&lr_sful_rec->vip_nats, &old_vip_nats);
> > +
> >      const char *external_ip;
> >      SSET_FOR_EACH (external_ip, &lr_sful_rec->lrnat_rec->external_ips) {
> >          bool is_vip_nat = false;
> > @@ -648,4 +665,14 @@ lr_stateful_build_vip_nats(struct lr_stateful_record 
> > *lr_sful_rec)
> >              sset_add(&lr_sful_rec->vip_nats, external_ip);
> >          }
> >      }
> > +
> > +    bool vip_nats_changed =
> > +        sset_count(&lr_sful_rec->vip_nats) != sset_count(&old_vip_nats);
> > +    if (!vip_nats_changed) {
> > +        vip_nats_changed = !sset_equals(&lr_sful_rec->vip_nats,
> > +                                        &old_vip_nats);
> > +    }
>
> It's enough to write:
>
> bool vip_nats_changed = !sset_equals(&lr_sful_rec->vip_nats,
>                                      &old_vip_nats);
>
> Tha'ts because sset_equals() checks internally first if both args
> have the same length.

Ack.  Done in v4.


>
> > +    sset_destroy(&old_vip_nats);
> > +
> > +    return vip_nats_changed;
> >  }
> > diff --git a/northd/en-lr-stateful.h b/northd/en-lr-stateful.h
> > index 0571e057f8..077de1bad1 100644
> > --- a/northd/en-lr-stateful.h
> > +++ b/northd/en-lr-stateful.h
> > @@ -32,6 +32,7 @@
> >
> >  struct ovn_datapath;
> >  struct lr_nat_record;
> > +struct lflow_ref;
> >
> >  /* lr_stateful_table:  This represents a table of logical routers with
> >   *                     stateful related data.
> > @@ -56,6 +57,27 @@ struct lr_stateful_record {
> >
> >      /* sset of vips which are also part of lr nats. */
> >      struct sset vip_nats;
> > +
> > +    /* 'lflow_ref' is used to reference logical flows generated for
> > +     * this lr_lb_nat_data record.
> > +     *
> > +     * This data is initialized and destroyed by the en_lr_lb_nat_data 
> > node,
> > +     * but populated and used only by the en_lflow node. Ideally this data
> > +     * should be maintained as part of en_lflow's data.  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 lflow_ref 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 lflow_ref *lflow_ref;
> >  };
> >
> >  struct lr_stateful_table {
> > @@ -75,6 +97,10 @@ struct lr_stateful_table {
> >  struct lr_stateful_tracked_data {
> >      /* Created or updated logical router with LB and/or NAT data. */
> >      struct hmapx crupdated; /* Stores 'struct lr_stateful_record'. */
> > +
> > +    /* Indicates if any router's NATs changed which were also LB vips
> > +     * or vice versa. */
> > +    bool vip_nats_changed;
>
> We also need to update the lr_stateful_has_tracked_data() function to
> take into account this extra state we're tracking.  I think it should
> be:
>
> static inline bool
> lr_stateful_has_tracked_data(struct lr_stateful_tracked_data *trk_data) {
>     return !hmapx_is_empty(&trk_data->crupdated)
>            || trk_data->vip_nats_changed;
> }
>
> this to account for updated LR/LB-group associations (without new LBs).
>
> Otherwise, in lr_stateful_lb_data_handler() below, we don't call
> "engine_set_node_state(node, EN_UPDATED);" if an existing LB is
> associated to a router and changes the "vip_nats".

Good catch.  Addressed in v4.


>
> >  };
> >
> >  struct ed_type_lr_stateful {
> > diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> > index 0e17bfe2e6..8be413200e 100644
> > --- a/northd/inc-proc-northd.c
> > +++ b/northd/inc-proc-northd.c
> > @@ -228,11 +228,12 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> >      engine_add_input(&en_lflow, &en_sb_logical_flow, NULL);
> >      engine_add_input(&en_lflow, &en_sb_multicast_group, NULL);
> >      engine_add_input(&en_lflow, &en_sb_igmp_group, NULL);
> > -    engine_add_input(&en_lflow, &en_lr_stateful, NULL);
> >      engine_add_input(&en_lflow, &en_ls_stateful, NULL);
> >      engine_add_input(&en_lflow, &en_sb_logical_dp_group, NULL);
> > +    engine_add_input(&en_lflow, &en_ls_stateful, NULL);
>
> This is a duplicate.  Probably a typo.

Yes.  Fixed in v4.



>
> >      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_stateful, 
> > lflow_lr_stateful_handler);
> >
> >      engine_add_input(&en_sync_to_sb_addr_set, &en_nb_address_set,
> >                       sync_to_sb_addr_set_nb_address_set_handler);
> > diff --git a/northd/northd.c b/northd/northd.c
> > index f56916b3da..235b9e100f 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -1227,7 +1227,7 @@ ovn_port_create(struct hmap *ports, const char *key,
> >
> >      op->lflow_ref = lflow_ref_alloc(key);
> >      op->stateful_lflow_ref = lflow_ref_alloc(key);
> > -
> > +    op->routable_lflow_ref = lflow_ref_alloc(key);
> >      return op;
> >  }
> >
> > @@ -1268,6 +1268,7 @@ ovn_port_destroy_orphan(struct ovn_port *port)
> >      free(port->key);
> >      lflow_ref_destroy(port->lflow_ref);
> >      lflow_ref_destroy(port->stateful_lflow_ref);
> > +    lflow_ref_destroy(port->routable_lflow_ref);
> >
> >      free(port);
> >  }
> > @@ -12832,63 +12833,6 @@ build_ip_routing_flows_for_lrp(
> >      }
> >  }
> >
> > -/* Logical router ingress table IP_ROUTING : IP Routing.
> > - *
> > - * For the LSP 'op' of type router, if there are logical router ports other
> > - * than the LSP's peer connected to the logical switch, then for routable
> > - * addresses (such as NAT IPs, LB VIPs, etc.) on each of the connected 
> > router
> > - * ports, add routes to the LSP's peer router.
> > - */
> > -static void
> > -build_ip_routing_flows_for_router_type_lsp(
> > -        struct ovn_port *op, const struct lr_stateful_table *lr_sful_table,
> > -        const struct hmap *lr_ports, struct lflow_table *lflows,
> > -        struct lflow_ref *lflow_ref)
> > -{
> > -    ovs_assert(op->nbsp);
> > -    if (!lsp_is_router(op->nbsp)) {
> > -        return;
> > -    }
> > -
> > -    struct ovn_port *peer = ovn_port_get_peer(lr_ports, op);
> > -    if (!peer || !peer->nbrp || !peer->lrp_networks.n_ipv4_addrs
> > -        || !op->od->n_router_ports) {
> > -        return;
> > -    }
> > -
> > -    for (int i = 0; i < op->od->n_router_ports; i++) {
> > -        struct ovn_port *router_port = ovn_port_get_peer(
> > -                lr_ports, op->od->router_ports[i]);
> > -        if (!router_port || !router_port->nbrp || router_port == peer) {
> > -            continue;
> > -        }
> > -
> > -        const struct lr_stateful_record *lr_sful_rec =
> > -            lr_stateful_table_find_by_index(lr_sful_table,
> > -                                            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_sful_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,
> > -                            lflow_ref);
> > -                }
> > -            }
> > -            destroy_routable_addresses(&ra);
> > -        }
> > -    }
> > -
> > -}
> > -
> >  static void
> >  build_static_route_flows_for_lrouter(
> >          struct ovn_datapath *od, const struct chassis_features *features,
> > @@ -13130,42 +13074,6 @@ build_arp_resolve_flows_for_lrouter(
> >                                 lflow_ref);
> >  }
> >
> > -static void
> > -routable_addresses_to_lflows(struct lflow_table *lflows,
> > -                             struct ovn_port *router_port,
> > -                             struct ovn_port *peer,
> > -                             const struct lr_stateful_record *lr_sful_rec,
> > -                             struct ds *match, struct ds *actions,
> > -                             struct lflow_ref *lflow_ref)
> > -{
> > -    struct ovn_port_routable_addresses ra =
> > -        get_op_routable_addresses(router_port, lr_sful_rec);
> > -    if (!ra.n_addrs) {
> > -        return;
> > -    }
> > -
> > -    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++) {
> > -            if (!first) {
> > -                ds_put_cstr(match, ", ");
> > -            }
> > -            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);
> > -        ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE, 100,
> > -                      ds_cstr(match), ds_cstr(actions), lflow_ref);
> > -    }
> > -    destroy_routable_addresses(&ra);
> > -}
> > -
> >  /* Local router ingress table ARP_RESOLVE: ARP Resolution.
> >   *
> >   * Any unicast packet that reaches this table is an IP packet whose
> > @@ -13408,52 +13316,6 @@ build_arp_resolve_flows_for_lsp(
> >      }
> >  }
> >
> > -static void
> > -build_arp_resolve_flows_for_lsp_routable_addresses(
> > -        struct ovn_port *op, struct lflow_table *lflows,
> > -        const struct hmap *lr_ports,
> > -        const struct lr_stateful_table *lr_sful_table,
> > -        struct ds *match, struct ds *actions,
> > -        struct lflow_ref *lflow_ref)
> > -{
> > -    if (!lsp_is_router(op->nbsp)) {
> > -        return;
> > -    }
> > -
> > -    struct ovn_port *peer = ovn_port_get_peer(lr_ports, op);
> > -    if (!peer || !peer->nbrp) {
> > -        return;
> > -    }
> > -
> > -    if (peer->od->nbr &&
> > -        smap_get_bool(&peer->od->nbr->options,
> > -                      "dynamic_neigh_routers", false)) {
> > -        return;
> > -    }
> > -
> > -    for (size_t i = 0; i < op->od->n_router_ports; i++) {
> > -        struct ovn_port *router_port =
> > -            ovn_port_get_peer(lr_ports, op->od->router_ports[i]);
> > -        if (!router_port || !router_port->nbrp) {
> > -            continue;
> > -        }
> > -
> > -        /* Skip the router port under consideration. */
> > -        if (router_port == peer) {
> > -            continue;
> > -        }
> > -
> > -        if (smap_get(&peer->od->nbr->options, "chassis") || peer->cr_port) 
> > {
> > -            const struct lr_stateful_record *lr_sful_rec;
> > -            lr_sful_rec = lr_stateful_table_find_by_index(lr_sful_table,
> > -                                                    
> > router_port->od->index);
> > -            routable_addresses_to_lflows(lflows, router_port, peer,
> > -                                         lr_sful_rec, match, actions,
> > -                                         lflow_ref);
> > -        }
> > -    }
> > -}
> > -
> >  static void
> >  build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu,
> >                              struct lflow_table *lflows,
> > @@ -15670,8 +15532,6 @@ static void
> >  build_lsp_lflows_for_lbnats(struct ovn_port *lsp,
> >                              struct ovn_port *lrp_peer,
> >                              const struct lr_stateful_record *lr_sful_rec,
> > -                            const struct lr_stateful_table *lr_sful_table,
> > -                            const struct hmap *lr_ports,
> >                              struct lflow_table *lflows,
> >                              struct ds *match,
> >                              struct ds *actions,
> > @@ -15681,19 +15541,101 @@ build_lsp_lflows_for_lbnats(struct ovn_port *lsp,
> >      build_lswitch_rport_arp_req_flows_for_lbnats(
> >          lrp_peer, lr_sful_rec, lsp->od, lsp,
> >          lflows, &lsp->nbsp->header_, lflow_ref);
> > -    build_ip_routing_flows_for_router_type_lsp(lsp, lr_sful_table,
> > -                                               lr_ports, lflows,
> > -                                               lflow_ref);
> > -    build_arp_resolve_flows_for_lsp_routable_addresses(
> > -        lsp, lflows, lr_ports, lr_sful_table, match, actions, lflow_ref);
> >      build_lswitch_ip_unicast_lookup_for_nats(lsp, lr_sful_rec, lflows,
> >                                               match, actions, lflow_ref);
> >  }
> >
> > +/* Logical router ingress table IP_ROUTING : IP Routing.
> > + *
> > + * For the LRP 'lrp's peer's logical switch, if there are logical router
> > + * ports ('peer_lrp's) other than the 'lrp', then for routable addresses
> > + * (such as NAT IPs, LB VIPs, etc.) of the 'lrp' add routes to the
> > + * peer_lrp's datapath.
> > + */
> > +static void
> > +build_routable_flows_for_router_port(
> > +    struct ovn_port *lrp, const struct lr_stateful_record *lr_sful_rec,
> > +    struct lflow_table *lflows,
> > +    struct ds *match,
> > +    struct ds *actions,
> > +    struct lflow_ref *lflow_ref)
> > +{
> > +    ovs_assert(lrp->nbrp && lrp->od == lr_sful_rec->od);
> > +
> > +    struct ovn_port *lsp_peer = lrp->peer;
> > +    if (!lsp_peer || !lsp_peer->nbsp) {
> > +        return;
> > +    }
> > +
> > +    struct ovn_datapath *peer_ls = lsp_peer->od;
> > +    ovs_assert(peer_ls->nbs);
> > +
> > +    struct ovn_port_routable_addresses ra =
> > +        get_op_routable_addresses(lrp, lr_sful_rec);
> > +
> > +    struct ovn_port *router_port;
> > +
> > +    for (size_t i = 0; i < peer_ls->n_router_ports; i++) {
> > +        router_port = peer_ls->router_ports[i]->peer;
> > +
> > +        if (router_port == lrp) {
> > +            continue;
> > +        }
> > +
> > +        if (lrp->nbrp->ha_chassis_group ||
> > +                lrp->nbrp->n_gateway_chassis) {
> > +            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, router_port->od, router_port,
> > +                            router_port->lrp_networks.ipv4_addrs[0].addr_s,
> > +                            laddrs->ipv4_addrs[k].network_s,
> > +                            laddrs->ipv4_addrs[k].plen, NULL, false, 0,
> > +                            &router_port->nbrp->header_, false,
> > +                            ROUTE_PRIO_OFFSET_CONNECTED,
> > +                            lflow_ref);
> > +                }
> > +            }
> > +        }
> > +
> > +        bool dynamic_neigh_router =
> > +            smap_get_bool(&router_port->od->nbr->options,
> > +                          "dynamic_neigh_routers", false);
> > +
> > +        if (!dynamic_neigh_router &&
> > +            (router_port->od->is_gw_router || router_port->cr_port)) {
> > +
> > +            for (size_t k = 0; k < ra.n_addrs; k++) {
> > +                ds_clear(match);
> > +                ds_put_format(match, "outport == %s && "
> > +                              REG_NEXT_HOP_IPV4" == {",
> > +                              router_port->json_key);
> > +                bool first = true;
> > +                for (size_t j = 0; j < ra.laddrs[k].n_ipv4_addrs; j++) {
> > +                    if (!first) {
> > +                        ds_put_cstr(match, ", ");
> > +                    }
> > +                    ds_put_cstr(match, ra.laddrs[k].ipv4_addrs[j].addr_s);
> > +                    first = false;
> > +                }
> > +                ds_put_cstr(match, "}");
> > +
> > +                ds_clear(actions);
> > +                ds_put_format(actions, "eth.dst = %s; next;",
> > +                              ra.laddrs[k].ea_s);
> > +                ovn_lflow_add(lflows, router_port->od, 
> > S_ROUTER_IN_ARP_RESOLVE,
> > +                              100, ds_cstr(match), ds_cstr(actions),
> > +                              lflow_ref);
> > +            }
> > +        }
> > +    }
> > +
> > +    destroy_routable_addresses(&ra);
> > +}
> > +
> >  static void
> >  build_lbnat_lflows_iterate_by_lsp(struct ovn_port *op,
> >                                    const struct lr_stateful_table 
> > *lr_sful_table,
> > -                                  const struct hmap *lr_ports,
> >                                    struct ds *match,
> >                                    struct ds *actions,
> >                                    struct lflow_table *lflows,
> > @@ -15711,8 +15653,8 @@ build_lbnat_lflows_iterate_by_lsp(struct ovn_port 
> > *op,
> >      ovs_assert(lr_sful_rec);
> >
> >      build_lsp_lflows_for_lbnats(op, op->peer, lr_sful_rec,
> > -                                lr_sful_table, lr_ports, lflows,
> > -                                match, actions, lflow_ref);
> > +                                lflows,match, actions,
> > +                                lflow_ref);
> >  }
> >
> >  static void
> > @@ -15762,7 +15704,8 @@ build_lbnat_lflows_iterate_by_lrp(struct ovn_port 
> > *op,
> >                                    struct ds *match,
> >                                    struct ds *actions,
> >                                    struct lflow_table *lflows,
> > -                                  struct lflow_ref *lflow_ref)
> > +                                  struct lflow_ref *lflow_ref,
> > +                                  struct lflow_ref *routable_lflow_ref)
> >  {
> >      ovs_assert(op->nbrp);
> >
> > @@ -15773,6 +15716,9 @@ build_lbnat_lflows_iterate_by_lrp(struct ovn_port 
> > *op,
> >
> >      build_lrp_lflows_for_lbnats(op, lr_sful_rec, meter_groups, match,
> >                                  actions, lflows, lflow_ref);
> > +
> > +    build_routable_flows_for_router_port(op, lr_sful_rec, lflows, match,
> > +                                         actions, routable_lflow_ref);
> >  }
> >
> >  static void
> > @@ -15787,15 +15733,15 @@ build_lr_stateful_flows(const struct 
> > lr_stateful_record *lr_sful_rec,
> >  {
> >      build_lrouter_nat_defrag_and_lb(lr_sful_rec, lflows, ls_ports, 
> > lr_ports,
> >                                      match, actions, meter_groups, features,
> > -                                    NULL);
> > +                                    lr_sful_rec->lflow_ref);
> >      build_lr_gateway_redirect_flows_for_nats(lr_sful_rec->od,
> >                                               lr_sful_rec->lrnat_rec, 
> > lflows,
> >                                               match, actions,
> > -                                             NULL);
> > +                                             lr_sful_rec->lflow_ref);
> >      build_lrouter_arp_nd_for_datapath(lr_sful_rec->od,
> >                                        lr_sful_rec->lrnat_rec, lflows,
> >                                        meter_groups,
> > -                                      NULL);
> > +                                      lr_sful_rec->lflow_ref);
> >  }
> >
> >  static void
> > @@ -16026,7 +15972,6 @@ build_lflows_thread(void *arg)
> >                                                               &lsi->actions,
> >                                                               lsi->lflows);
> >                      build_lbnat_lflows_iterate_by_lsp(op, 
> > lsi->lr_sful_table,
> > -                                                      lsi->lr_ports,
> >                                                        &lsi->match,
> >                                                        &lsi->actions,
> >                                                        lsi->lflows,
> > @@ -16048,7 +15993,8 @@ build_lflows_thread(void *arg)
> >                                                        &lsi->match,
> >                                                        &lsi->actions,
> >                                                        lsi->lflows,
> > -                                                      
> > op->stateful_lflow_ref);
> > +                                                      
> > op->stateful_lflow_ref,
> > +                                                      
> > op->routable_lflow_ref);
> >                  }
> >              }
> >              for (bnum = control->id;
> > @@ -16280,9 +16226,9 @@ build_lswitch_and_lrouter_flows(const struct 
> > ovn_datapaths *ls_datapaths,
> >                                                       &lsi.match,
> >                                                       &lsi.actions,
> >                                                       lsi.lflows);
> > -            build_lbnat_lflows_iterate_by_lsp(op, lsi.lr_sful_table, 
> > lsi.lr_ports,
> > -                                              &lsi.match, &lsi.actions,
> > -                                              lsi.lflows,
> > +            build_lbnat_lflows_iterate_by_lsp(op, lsi.lr_sful_table,
> > +                                              &lsi.match,
> > +                                              &lsi.actions, lsi.lflows,
> >                                                op->stateful_lflow_ref);
> >          }
> >          HMAP_FOR_EACH (op, key_node, lr_ports) {
> > @@ -16292,7 +16238,8 @@ build_lswitch_and_lrouter_flows(const struct 
> > ovn_datapaths *ls_datapaths,
> >                                                &lsi.match,
> >                                                &lsi.actions,
> >                                                lsi.lflows,
> > -                                              op->stateful_lflow_ref);
> > +                                              op->stateful_lflow_ref,
> > +                                              op->routable_lflow_ref);
> >          }
> >          stopwatch_stop(LFLOWS_PORTS_STOPWATCH_NAME, time_msec());
> >          stopwatch_start(LFLOWS_LBS_STOPWATCH_NAME, time_msec());
> > @@ -16485,12 +16432,24 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn,
> >  void
> >  reset_lflow_refs_for_northd_resources(struct lflow_input *lflow_input)
> >  {
> > +    const struct lr_stateful_record *lr_sful_rec;
> >      struct ovn_lb_datapaths *lb_dps;
> >      struct ovn_port *op;
> >
> > +    LR_STATEFUL_TABLE_FOR_EACH (lr_sful_rec, lflow_input->lr_sful_table) {
> > +        lflow_ref_reset(lr_sful_rec->lflow_ref);
> > +    }
> > +
> >      HMAP_FOR_EACH (op, key_node, lflow_input->ls_ports) {
> >          lflow_ref_reset(op->lflow_ref);
> >          lflow_ref_reset(op->stateful_lflow_ref);
> > +        lflow_ref_reset(op->routable_lflow_ref);
> > +    }
> > +
> > +    HMAP_FOR_EACH (op, key_node, lflow_input->lr_ports) {
> > +        lflow_ref_reset(op->lflow_ref);
> > +        lflow_ref_reset(op->stateful_lflow_ref);
> > +        lflow_ref_reset(op->routable_lflow_ref);
> >      }
> >
> >      HMAP_FOR_EACH (lb_dps, hmap_node, lflow_input->lb_datapaths_map) {
> > @@ -16547,11 +16506,10 @@ lflow_handle_northd_port_changes(struct 
> > ovsdb_idl_txn *ovnsb_txn,
> >              ovs_assert(lr_sful_rec);
> >              lflow_ref_clear_lflows(op->stateful_lflow_ref);
> >              build_lsp_lflows_for_lbnats(op, op->peer, lr_sful_rec,
> > -                                        lflow_input->lr_sful_table,
> > -                                        lflow_input->lr_ports,
> >                                          lflows, &match, &actions,
> >                                          op->stateful_lflow_ref);
> > -            lflow_ref_sync_lflows_to_sb(op->stateful_lflow_ref, lflows, 
> > ovnsb_txn,
> > +            lflow_ref_sync_lflows_to_sb(op->stateful_lflow_ref, lflows,
> > +                             ovnsb_txn,
> >                               lflow_input->ls_datapaths,
> >                               lflow_input->lr_datapaths,
> >                               lflow_input->ovn_internal_version_changed,
> > @@ -16705,6 +16663,92 @@ lflow_handle_northd_lb_changes(struct 
> > ovsdb_idl_txn *ovnsb_txn,
> >      return true;
> >  }
> >
> > +bool
> > +lflow_handle_lr_stateful_changes(struct ovsdb_idl_txn *ovnsb_txn,
> > +                                struct lr_stateful_tracked_data *trk_data,
> > +                                struct lflow_input *lflow_input,
> > +                                struct lflow_table *lflows)
> > +{
> > +    struct lr_stateful_record *lr_sful_rec;
> > +    struct hmapx_node *hmapx_node;
> > +
> > +    HMAPX_FOR_EACH (hmapx_node, &trk_data->crupdated) {
> > +        lr_sful_rec = hmapx_node->data;
> > +
> > +        lflow_ref_clear_lflows(lr_sful_rec->lflow_ref);
> > +
> > +        /* Generate new lflows. */
> > +        struct ds match = DS_EMPTY_INITIALIZER;
> > +        struct ds actions = DS_EMPTY_INITIALIZER;
> > +
> > +        build_lr_stateful_flows(lr_sful_rec, lflows, lflow_input->ls_ports,
> > +                                lflow_input->lr_ports, &match, &actions,
> > +                                lflow_input->meter_groups,
> > +                                lflow_input->features);
> > +
> > +        /* Sync the new flows to SB. */
> > +        lflow_ref_sync_lflows_to_sb(lr_sful_rec->lflow_ref, lflows, 
> > ovnsb_txn,
> > +                             lflow_input->ls_datapaths,
> > +                             lflow_input->lr_datapaths,
> > +                             lflow_input->ovn_internal_version_changed,
> > +                             lflow_input->sbrec_logical_flow_table,
> > +                             lflow_input->sbrec_logical_dp_group_table);
> > +
> > +        struct ovn_port *op;
> > +        HMAP_FOR_EACH (op, dp_node, &lr_sful_rec->od->ports) {
> > +            lflow_ref_clear_lflows(op->stateful_lflow_ref);
> > +            lflow_ref_clear_lflows_for_all_dps(op->routable_lflow_ref,
> > +                                        
> > ods_size(lflow_input->ls_datapaths),
> > +                                        
> > ods_size(lflow_input->lr_datapaths));
> > +
> > +            build_lbnat_lflows_iterate_by_lrp(op, 
> > lflow_input->lr_sful_table,
> > +                                              lflow_input->meter_groups,
> > +                                              &match, &actions,
> > +                                              lflows,
> > +                                              op->stateful_lflow_ref,
> > +                                              op->routable_lflow_ref);
> > +
> > +            lflow_ref_sync_lflows_to_sb(op->stateful_lflow_ref, lflows,
> > +                            ovnsb_txn,
> > +                            lflow_input->ls_datapaths,
> > +                            lflow_input->lr_datapaths,
> > +                            lflow_input->ovn_internal_version_changed,
> > +                            lflow_input->sbrec_logical_flow_table,
> > +                            lflow_input->sbrec_logical_dp_group_table);
> > +
> > +            lflow_ref_sync_lflows_to_sb(op->routable_lflow_ref, lflows,
> > +                            ovnsb_txn, lflow_input->ls_datapaths,
> > +                            lflow_input->lr_datapaths,
> > +                            lflow_input->ovn_internal_version_changed,
> > +                            lflow_input->sbrec_logical_flow_table,
> > +                            lflow_input->sbrec_logical_dp_group_table);
> > +
> > +            if (op->peer && op->peer->nbsp) {
> > +                lflow_ref_clear_lflows(op->peer->stateful_lflow_ref);
> > +
> > +                build_lbnat_lflows_iterate_by_lsp(op->peer,
> > +                                                lflow_input->lr_sful_table,
> > +                                                &match, &actions,
> > +                                                lflows,
> > +                                                
> > op->peer->stateful_lflow_ref);
> > +
> > +                lflow_ref_sync_lflows_to_sb(op->peer->stateful_lflow_ref,
> > +                            lflows, ovnsb_txn,
> > +                            lflow_input->ls_datapaths,
> > +                            lflow_input->lr_datapaths,
> > +                            lflow_input->ovn_internal_version_changed,
> > +                            lflow_input->sbrec_logical_flow_table,
> > +                            lflow_input->sbrec_logical_dp_group_table);
> > +            }
> > +        }
> > +
> > +        ds_destroy(&match);
> > +        ds_destroy(&actions);
> > +    }
> > +
> > +    return true;
> > +}
> > +
> >  static bool
> >  mirror_needs_update(const struct nbrec_mirror *nb_mirror,
> >                      const struct sbrec_mirror *sb_mirror)
> > diff --git a/northd/northd.h b/northd/northd.h
> > index 863bcce001..6adf06c26f 100644
> > --- a/northd/northd.h
> > +++ b/northd/northd.h
> > @@ -688,9 +688,13 @@ struct ovn_port {
> >       * 'stateful_lflow_ref' is used for logical switch ports of type
> >       * 'patch/router' to referenece logical flows generated fo this 
> > ovn_port
> >       *  from the 'lr_stateful' record of the peer port's datapath.
> > +     *
> > +     * 'routable_lflow_ref' is used to reference logical flows generated 
> > for
> > +     * the routable ips of a logical router port.
> >       */
> >      struct lflow_ref *lflow_ref;
> >      struct lflow_ref *stateful_lflow_ref;
> > +    struct lflow_ref *routable_lflow_ref;
> >  };
> >
> >  void ovnnb_db_run(struct northd_input *input_data,
> > @@ -715,6 +719,8 @@ void northd_indices_create(struct northd_data *data,
> >                             struct ovsdb_idl *ovnsb_idl);
> >
> >  struct lflow_table;
> > +struct lr_stateful_tracked_data;
> > +
> >  void build_lflows(struct ovsdb_idl_txn *ovnsb_txn,
> >                    struct lflow_input *input_data,
> >                    struct lflow_table *);
> > @@ -728,6 +734,10 @@ bool lflow_handle_northd_lb_changes(struct 
> > ovsdb_idl_txn *ovnsb_txn,
> >                                      struct tracked_lbs *,
> >                                      struct lflow_input *,
> >                                      struct lflow_table *lflows);
> > +bool lflow_handle_lr_stateful_changes(struct ovsdb_idl_txn *,
> > +                                      struct lr_stateful_tracked_data *,
> > +                                      struct lflow_input *,
> > +                                      struct lflow_table *lflows);
> >  bool northd_handle_sb_port_binding_changes(
> >      const struct sbrec_port_binding_table *, struct hmap *ls_ports,
> >      struct hmap *lr_ports);
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index 50d88fecd5..f517057534 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -12,6 +12,7 @@ m4_define([_DUMP_DB_TABLES], [
> >      ovn-sbctl list meter >> $1
> >      ovn-sbctl list meter_band >> $1
> >      ovn-sbctl list port_group >> $1
> > +    ovn-sbctl dump-flows > lflows_$1
> >  ])
> >
> >  # CHECK_NO_CHANGE_AFTER_RECOMPUTE
> > @@ -10687,7 +10688,7 @@ 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_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10697,7 +10698,7 @@ check ovn-nbctl --wait=sb set load_balancer lb1 
> > vips:'"10.0.0.10:80"'='"10.0.0.1
> >  check_engine_stats lb_data norecompute compute
> >  check_engine_stats northd norecompute compute
> >  check_engine_stats lr_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10707,7 +10708,7 @@ 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_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10717,7 +10718,7 @@ 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_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10727,7 +10728,7 @@ 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_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10735,6 +10736,7 @@ check as northd ovn-appctl -t NORTHD_TYPE 
> > inc-engine/clear-stats
> >  check ovn-nbctl --wait=sb lr-lb-del lr0 lb1
> >  check_engine_stats lb_data norecompute compute
> >  check_engine_stats northd recompute nocompute
> > +check_engine_stats lr_stateful recompute nocompute
> >  check_engine_stats lflow recompute nocompute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> > @@ -10850,7 +10852,7 @@ 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_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10860,7 +10862,7 @@ check ovn-nbctl --wait=sb set load_balancer lb1 
> > vips:'"10.0.0.10:80"'='"10.0.0.1
> >  check_engine_stats lb_data norecompute compute
> >  check_engine_stats northd norecompute compute
> >  check_engine_stats lr_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10870,7 +10872,7 @@ 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_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10880,7 +10882,7 @@ 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_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10890,7 +10892,7 @@ 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_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10971,7 +10973,7 @@ 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_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -10999,7 +11001,7 @@ 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_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_lb recompute compute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -11177,7 +11179,7 @@ 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 norecompute compute
> >  check_engine_stats lr_nat norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_pb recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -11186,7 +11188,7 @@ 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 norecompute compute
> >  check_engine_stats lr_nat norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_pb recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -11196,7 +11198,7 @@ check ovn-nbctl --wait=sb set NAT . 
> > external_ip=172.168.0.120
> >  check_engine_stats northd norecompute compute
> >  check_engine_stats lr_nat norecompute compute
> >  check_engine_stats lr_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_pb recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -11206,7 +11208,7 @@ check ovn-nbctl --wait=sb set NAT . 
> > logical_ip=10.0.0.10
> >  check_engine_stats northd norecompute compute
> >  check_engine_stats lr_nat norecompute compute
> >  check_engine_stats lr_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_pb recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -11216,7 +11218,7 @@ check ovn-nbctl --wait=sb set NAT . type=snat
> >  check_engine_stats northd norecompute compute
> >  check_engine_stats lr_nat norecompute compute
> >  check_engine_stats lr_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_pb recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -11226,7 +11228,7 @@ check ovn-nbctl --wait=sb lr-nat-add lr0 
> > dnat_and_snat 172.168.0.110 10.0.0.4 sw
> >  check_engine_stats northd norecompute compute
> >  check_engine_stats lr_nat norecompute compute
> >  check_engine_stats lr_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_pb recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -11237,7 +11239,7 @@ check ovn-nbctl --wait=sb set NAT $nat2_uuid 
> > external_mac='"30:54:00:00:00:04"'
> >  check_engine_stats northd norecompute compute
> >  check_engine_stats lr_nat norecompute compute
> >  check_engine_stats lr_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_pb recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > @@ -11258,6 +11260,8 @@ check_engine_stats sync_to_sb_pb recompute nocompute
> >  check_engine_stats lflow recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > +# lflow engine should recompute since the nat ip 172.168.0.150
> > +# 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.150 
> > 10.0.0.41
> >  check_engine_stats northd norecompute compute
> > @@ -11267,6 +11271,8 @@ check_engine_stats sync_to_sb_pb recompute nocompute
> >  check_engine_stats lflow recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > +# lflow engine should recompute since the deleted nat ip 172.168.0.150
> > +# is a lb vip.
> >  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 norecompute compute
> > @@ -11276,6 +11282,8 @@ check_engine_stats sync_to_sb_pb recompute nocompute
> >  check_engine_stats lflow recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
> > +# lflow engine should recompute since the deleted nat ip 172.168.0.140
> > +# is a lb vip.
> >  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 norecompute compute
> > @@ -11291,7 +11299,7 @@ check ovn-nbctl --wait=sb clear logical_router lr0 
> > nat
> >  check_engine_stats northd norecompute compute
> >  check_engine_stats lr_nat norecompute compute
> >  check_engine_stats lr_stateful norecompute compute
> > -check_engine_stats lflow recompute nocompute
> > +check_engine_stats lflow norecompute compute
> >  check_engine_stats sync_to_sb_pb recompute nocompute
> >  CHECK_NO_CHANGE_AFTER_RECOMPUTE
> >
>
> Regards,
> Dumitru
>
>
>
> _______________________________________________
> dev mailing list
> d...@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>

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

Reply via email to