On Tue, Oct 6, 2026 at 1:51 PM Mark Michelson via dev <
[email protected]> wrote:

> With this change, en-lflow will now incrementally process logical router
> policy changes.
>
> The lflow_ref is scoped to the datapath on which logical router policies
> are attached. In the case that any logical router policies are added or
> deleted on an existing logical router all of the policies on that
> logical router will have their logical flows rebuilt and resynced.
>

router policy processing. The only change that
  outport_key = out_port->nbrp->name at en-route-policies.c:296) and
                              │    actually makes a difference is if the
logical router ports change, and
  a string copy (src_addr, en-route-policies.c:298). They never hold
                              │    there are "reroute" policies installed
on the log



>
> Signed-off-by: Mark Michelson <[email protected]>
> ---
>  northd/en-lflow.c                | 33 ++++++++++++++++++++++++++++++++
>  northd/en-lflow.h                |  2 ++
>  northd/inc-proc-northd.c         |  3 ++-
>  northd/northd.c                  | 30 +++++++++++++++++++++++++++++
>  northd/northd.h                  |  6 ++++++
>  tests/ovn-inc-proc-graph-dump.at |  2 +-
>  tests/ovn-northd.at              | 20 +++++++++++--------
>  7 files changed, 86 insertions(+), 10 deletions(-)
>
> diff --git a/northd/en-lflow.c b/northd/en-lflow.c
> index b5204a8f2..1bf8da227 100644
> --- a/northd/en-lflow.c
> +++ b/northd/en-lflow.c
> @@ -311,6 +311,39 @@ lflow_ic_learned_svc_mons_handler(struct engine_node
> *node,
>      return EN_HANDLED_UPDATED;
>  }
>
> +enum engine_input_handler_result
> +lflow_route_policies_handler(struct engine_node *node,
> +                             void *data)
> +{
> +    struct route_policies_data *rp_data =
> +        engine_get_input_data("route_policies", node);
> +
> +    if (!rp_data->trk.has_tracked) {
> +        return EN_UNHANDLED;
> +    }
> +
> +    if (!rp_data->trk.has_tracked_policies) {
> +        /* en-route-policies computed incrementally, but there
> +         * were no changes to any of the policies. Therefore,
> +         * there is no need for en-lflow to take action.
> +         */
> +        return EN_HANDLED_UNCHANGED;
> +    }
> +
> +    struct lflow_data *lflow_data = data;
> +
> +    struct lflow_input lflow_input;
> +    lflow_get_input_data(node, &lflow_input);
> +
> +    if (!lflow_handle_route_policies_changes(
> +            rp_data, &lflow_input, lflow_data->lflow_table,
> +            &lflow_data->trk_data.dirty_lflow_refs)) {
> +        return EN_UNHANDLED;
> +    }
> +
> +    return EN_HANDLED_UPDATED;
> +}
> +
>  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 fd3f2427f..26dd5c9e9 100644
> --- a/northd/en-lflow.h
> +++ b/northd/en-lflow.h
> @@ -38,4 +38,6 @@ enum engine_input_handler_result
>  lflow_group_ecmp_route_change_handler(struct engine_node *node, void
> *data);
>  enum engine_input_handler_result
>  lflow_ic_learned_svc_mons_handler(struct engine_node *node, void *data);
> +enum engine_input_handler_result
> +lflow_route_policies_handler(struct engine_node *node, void *data);
>  #endif /* EN_LFLOW_H */
> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> index 0fde77032..603590697 100644
> --- a/northd/inc-proc-northd.c
> +++ b/northd/inc-proc-northd.c
> @@ -400,7 +400,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
>      engine_add_input(&en_lflow, &en_sync_meters, NULL);
>      engine_add_input(&en_lflow, &en_sb_multicast_group, NULL);
>      engine_add_input(&en_lflow, &en_bfd_sync, NULL);
> -    engine_add_input(&en_lflow, &en_route_policies, NULL);
> +    engine_add_input(&en_lflow, &en_route_policies,
> +                     lflow_route_policies_handler);
>      /* Route changes are propagated to en_lflow through the
> en_group_ecmp_route
>       * input.  Any change to en_routes also triggers en_group_ecmp_route
> (via
>       * group_ecmp_route_routes_change_handler), which then triggers
> en_lflow.
> diff --git a/northd/northd.c b/northd/northd.c
> index 3fa84963d..996eb2747 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -21067,6 +21067,36 @@ lflow_handle_ls_stateful_changes(struct
> ls_stateful_tracked_data *trk_data,
>      }
>  }
>
> +bool
> +lflow_handle_route_policies_changes(struct route_policies_data *rp_data,
> +                                    struct lflow_input *lflow_input,
> +                                    struct lflow_table *lflows,
> +                                    struct hmapx *dirty_lflow_refs)
> +{
> +    struct hmapx_node *hmapx_node;
> +    struct datapath_route_policies *dp_rp;
> +    HMAPX_FOR_EACH (hmapx_node, &rp_data->trk.deleted_policies) {
> +        dp_rp = hmapx_node->data;
> +        lflow_ref_unlink_lflows(dp_rp->lflow_ref, lflows);
> +        hmapx_add(dirty_lflow_refs, dp_rp->lflow_ref);
> +    }
> +
> +    HMAPX_FOR_EACH (hmapx_node, &rp_data->trk.new_policies) {
> +        dp_rp = hmapx_node->data;
> +        struct ovn_datapath *od =
> +            sparse_array_get(&lflow_input->lr_datapaths->dps,
> dp_rp->dp_index);
> +        if (!od) {
> +            return false;
> +        }
>

Is the "if (!od)" check required? new_policy entries are produced by
en_route_policies  from od->sdp->index which is the same index used to put
datapaths in lr_datapaths
and the full-recompute loop does not check for datapath existence.





> +        lflow_ref_unlink_lflows(dp_rp->lflow_ref, lflows);
> +        build_ingress_policy_flows_for_lrouter(
> +            od, lflows, &dp_rp->route_policies, dp_rp->lflow_ref);
> +        hmapx_add(dirty_lflow_refs, dp_rp->lflow_ref);
> +    }
> +
> +    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 fb7d3e44e..a8985b603 100644
> --- a/northd/northd.h
> +++ b/northd/northd.h
> @@ -1017,6 +1017,12 @@ bool northd_handle_lb_data_changes(struct
> tracked_lb_data *,
>  void bfd_table_sync(struct ovsdb_idl_txn *,
>                      const struct hmap *, struct hmap *,
>                      struct sset *);
> +struct route_policies_data;
> +bool lflow_handle_route_policies_changes(struct route_policies_data
> *rp_data,
> +                                         struct lflow_input *lflow_input,
> +                                         struct lflow_table *lflows,
> +                                         struct hmapx *dirty_lflow_refs);
> +
>  void build_bfd_map(const struct nbrec_bfd_table *,
>                     const struct sbrec_bfd_table *, struct hmap *,
>                     const struct uuidset *);
> diff --git a/tests/ovn-inc-proc-graph-dump.at b/tests/
> ovn-inc-proc-graph-dump.at
> index 5686e0208..8cd199b11 100644
> --- a/tests/ovn-inc-proc-graph-dump.at
> +++ b/tests/ovn-inc-proc-graph-dump.at
> @@ -183,7 +183,7 @@ digraph "Incremental-Processing-Engine" {
>         sync_meters -> lflow [[label=""]];
>         SB_multicast_group -> lflow [[label=""]];
>         bfd_sync -> lflow [[label=""]];
> -       route_policies -> lflow [[label=""]];
> +       route_policies -> lflow [[label="lflow_route_policies_handler"]];
>         routes -> lflow [[label="engine_noop_handler"]];
>         group_ecmp_route -> lflow
> [[label="lflow_group_ecmp_route_change_handler"]];
>         global_config -> lflow [[label="node_global_config_handler"]];
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index e11ebc6d5..ffc387aa5 100644
> --- a/tests/ovn-northd.at
> +++ b/tests/ovn-northd.at
> @@ -4690,7 +4690,11 @@ AT_CHECK([ovn-nbctl list logical_router_policy |
> grep -q $bfd_route_policy_uuid]
>
>  check_engine_stats northd norecompute incremental
>  check_engine_stats route_policies norecompute compute
> -check_engine_stats lflow recompute nocompute
> +# The BFD changes trigger a recompute of en-lflow, since en-routes cannot
> +# incrementally handle BFD changes. However, en-lflow is able to
> incrementally
> +# handle the added logical router policy. This is why we see both
> recompute
> +# and compute true for en-lflow.
> +check_engine_stats lflow recompute compute
>  check_engine_stats northd_output norecompute compute
>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>  check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> @@ -24656,7 +24660,7 @@ check_engine_stats sync_from_sb norecompute
> nocompute
>  check_engine_stats sync_to_sb_lb norecompute compute
>  check_engine_stats route_policies norecompute compute
>  check_engine_stats bfd_sync recompute nocompute
> -check_engine_stats lflow recompute nocompute
> +check_engine_stats lflow norecompute compute
>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>
>  # Change router Policy to use explicit output port.
> @@ -24684,7 +24688,7 @@ check_engine_stats sync_from_sb norecompute
> nocompute
>  check_engine_stats sync_to_sb_lb norecompute compute
>  check_engine_stats route_policies norecompute compute
>  check_engine_stats bfd_sync recompute nocompute
> -check_engine_stats lflow recompute nocompute
> +check_engine_stats lflow norecompute compute
>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>
>  check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> @@ -24710,7 +24714,7 @@ check_engine_stats sync_from_sb norecompute
> nocompute
>  check_engine_stats sync_to_sb_lb norecompute compute
>  check_engine_stats route_policies norecompute compute
>  check_engine_stats bfd_sync recompute nocompute
> -check_engine_stats lflow recompute nocompute
> +check_engine_stats lflow norecompute compute
>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>
>  # From this point on, operations we perform may result in
> @@ -24729,7 +24733,7 @@ check ovn-nbctl --wait=sb sync
>  check_engine_stats northd norecompute compute
>  check_engine_stats route_policies norecompute compute
>  check_engine_stats bfd_sync recompute nocompute
> -check_engine_stats lflow recompute nocompute
> +check_engine_stats lflow norecompute compute
>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>
>  # Invalidate the policy by changing it to a jump policy but not
> @@ -24741,7 +24745,7 @@ check ovn-nbctl set Logical_Router_Policy
> $policy_uuid action=jump
>  check_engine_stats northd norecompute compute
>  check_engine_stats route_policies norecompute compute
>  check_engine_stats bfd_sync recompute nocompute
> -check_engine_stats lflow recompute nocompute
> +check_engine_stats lflow norecompute compute
>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>
>  # Un-invalidate the policy by changing it back to an allow policy.
> @@ -24751,7 +24755,7 @@ check ovn-nbctl set Logical_Router_Policy
> $policy_uuid action=allow
>  check_engine_stats northd norecompute compute
>  check_engine_stats route_policies norecompute compute
>  check_engine_stats bfd_sync recompute nocompute
> -check_engine_stats lflow recompute nocompute
> +check_engine_stats lflow norecompute compute
>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>
>  # Add a new logical router with an invalid policy in the same transaction
> @@ -24777,7 +24781,7 @@ check ovn-nbctl --wait=sb lr-del lr1
>  check_engine_stats northd norecompute compute
>  check_engine_stats route_policies norecompute compute
>  check_engine_stats bfd_sync recompute nocompute
> -check_engine_stats lflow recompute nocompute
> +check_engine_stats lflow norecompute compute
>  CHECK_NO_CHANGE_AFTER_RECOMPUTE
>
>  OVN_CLEANUP_NORTHD
> --
> 2.55.0
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>


Thanks,
Jacob Tanenbaum
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to