On Fri, Oct 16, 2026 at 1:21 PM Mark Michelson <[email protected]> wrote:
>
> On Thu, Oct 15, 2026 at 10:35 AM Jacob Tanenbaum <[email protected]> wrote:
> >
> >
> > I looked into this and there is no issue with waiting for a local_datapath 
> > to open this gate. If there are no local RE datapaths there is nothing for 
> > route_exchange_run do
> >
> > on the install side - no local datapaths means no VRFs created, no 
> > re_nl_sync_routes() calls, no Learned_Route writes
> > on the cleanup side - loops iterate on 
> > _maintained_route_tables/_mainted_vrfs, which are re-initialized empty at 
> > every start so no cleanup
> >
> >
> > There was some confusion as to whether we needed to clean up routes that 
> > were once local to this machine and that functionality did not exist in the 
> > old code or in this patch.
> > We only cleanup route_tables/vrfs that the current running ovn-controller 
> > process has seen.
>
> Thanks for the explanation Jacob. Since this is fixing the problem and
> not introducing any regressions,
>
> Acked-by: Mark Michelson <[email protected]>

I pushed the change to main. The change does not apply cleanly on
branch-26.09 or branch-26.03. Can you post patches that will apply on
those branches?

>
> >
> > On Wed, Oct 14, 2026 at 9:32 AM Jacob Tanenbaum <[email protected]> wrote:
> >>
> >>
> >>
> >> On Tue, Oct 13, 2026 at 3:09 PM Mark Michelson <[email protected]> wrote:
> >>>
> >>> On Sun, Oct 11, 2026 at 8:48 PM Jacob Tanenbaum <[email protected]> 
> >>> wrote:
> >>> >
> >>> >
> >>> >
> >>> > On Thu, Oct 8, 2026 at 3:42 PM Mark Michelson <[email protected]> 
> >>> > wrote:
> >>> >>
> >>> >> Hi Jacob, I had a look at this, and I think I get the gist of what's
> >>> >> happening. I have a question below.
> >>> >>
> >>> >> On Fri, Oct 2, 2026 at 9:13 AM Jacob Tanenbaum via dev
> >>> >> <[email protected]> wrote:
> >>> >> >
> >>> >> > On restart, ovn-controller monitored the whole cluster's
> >>> >> > Advertised_Route table at startup, and only ran its kernel route
> >>> >> > sync once all of it had been read.  The whole-cluster pull added
> >>> >> > measurable startup latency in large deployments, and the guard was
> >>> >> > coarser than it needed to be: the controller only ever deletes
> >>> >> > routes that it installed itself, and it only needs the advertised
> >>> >> > routes of the local route-exchange datapaths to know which ones
> >>> >> > those are.
> >>> >> >
> >>> >> > Monitor no Advertised_Route rows at startup.  Once local datapaths
> >>> >> > are known the monitor condition is already scoped to them, so the
> >>> >> > dump the controller waits for is small.
> >>> >> >
> >>> >> > Defer the route-exchange kernel sync until the controller can be
> >>> >> > confident that the Advertised_Route view is complete: the
> >>> >> > condition seqno shows the dump was delivered, and the current
> >>> >> > condition either covers the local route-exchange datapaths, or no
> >>> >> > local route-exchange datapaths remain and the initial sync has
> >>> >> > already run.  The kernel routes persist across the deferral, so
> >>> >> > none are lost.  The datapath set changing or a southbound
> >>> >> > reconnect re-arms the gate.
> >>> >> >
> >>> >> > The condition covering the local datapaths is what keeps this
> >>> >> > safe.  Waiting only on the condition seqno could arm the sync
> >>> >> > against the initial empty condition, and the first sync would
> >>> >> > then delete the routes installed before the restart.
> >>> >> >
> >>> >> > With no local route-exchange datapaths there is no scoped dump to
> >>> >> > wait for, so once the initial sync has run the view is complete
> >>> >> > and the sync may run to clean up the VRFs and routes of the
> >>> >> > removed datapaths.  Deferring it instead would leak the VRF and
> >>> >> > routes of the last removed dynamic-routing router.
> >>> >> >
> >>> >> > The dynamic-routing system test now checks that the deferred sync
> >>> >> > is enabled after a restart and that the installed OVN routes
> >>> >> > survive a --restart of the controller.
> >>> >> >
> >>> >> > Reported-at: https://redhat.atlassian.net/browse/FDP-3992
> >>> >> > Assisted-by: Qwen3.8-27B-FP8, opencode
> >>> >> > Signed-off-by: Jacob Tanenbaum <[email protected]>
> >>> >> >
> >>> >> > ---
> >>> >> >   v2:
> >>> >> >     * Fixed issues with the sb_monitor_all case
> >>> >> >     * Fixed the update to ovn-inc-proc-graph-dump.at
> >>> >> >     * Allow the route sync to run once the local route-exchange
> >>> >> >       datapath set becomes empty, so the VRF and routes of the
> >>> >> >       last removed dynamic-routing router are cleaned up.
> >>> >> > ---
> >>> >> >  NEWS                             |   4 +
> >>> >> >  TODO.rst                         |   5 --
> >>> >> >  controller/ovn-controller.c      | 126 
> >>> >> > +++++++++++++++++++++++++++++--
> >>> >> >  tests/ovn-inc-proc-graph-dump.at |   3 +-
> >>> >> >  tests/system-ovn.at              |  11 ++-
> >>> >> >  5 files changed, 137 insertions(+), 12 deletions(-)
> >>> >> >
> >>> >> > diff --git a/NEWS b/NEWS
> >>> >> > index 7f94d0b14..207c5a03c 100644
> >>> >> > --- a/NEWS
> >>> >> > +++ b/NEWS
> >>> >> > @@ -19,6 +19,10 @@ Post v26.09.0
> >>> >> >     - Removed OVN's ovs-bugtool plugin and helper scripts.
> >>> >> >     - Removed ovn-sim utility scripts.
> >>> >> >     - Removed ovn-docker utility scripts.
> >>> >> > +   - ovn-controller no longer monitors the whole cluster's 
> >>> >> > Advertised_Route
> >>> >> > +     table at startup; it defers its kernel route updates until the 
> >>> >> > initial
> >>> >> > +     dump of the advertised routes of the local route-exchange 
> >>> >> > datapaths is
> >>> >> > +     complete.
> >>> >> >
> >>> >> >  OVN v26.09.0 - xxx xx xxxx
> >>> >> >  --------------------------
> >>> >> > diff --git a/TODO.rst b/TODO.rst
> >>> >> > index 023eb27f6..dc55c8895 100644
> >>> >> > --- a/TODO.rst
> >>> >> > +++ b/TODO.rst
> >>> >> > @@ -145,11 +145,6 @@ OVN To-do List
> >>> >> >    * Add incremental processing of en_dynamic_routes for stateful 
> >>> >> > configuration
> >>> >> >      changes.
> >>> >> >
> >>> >> > -  * The ovn-controller currently loads all Advertised_Route entries 
> >>> >> > on startup.
> >>> >> > -    This is to prevent deleting our routes on restart. If we defer 
> >>> >> > updating
> >>> >> > -    routes until we are sure to have loaded all necessary 
> >>> >> > Advertised_Routes
> >>> >> > -    this could be changed.
> >>> >> > -
> >>> >> >    * Improve handling of the Learned_Route table in ovn-controller 
> >>> >> > conditional
> >>> >> >      monitoring; once a new local datapath is added we need to wait 
> >>> >> > for
> >>> >> >      monitoring conditions to update before we actually try to learn 
> >>> >> > routes.
> >>> >> > diff --git a/controller/ovn-controller.c 
> >>> >> > b/controller/ovn-controller.c
> >>> >> > index d57ff316d..f5ee8b75a 100644
> >>> >> > --- a/controller/ovn-controller.c
> >>> >> > +++ b/controller/ovn-controller.c
> >>> >> > @@ -176,6 +176,16 @@ struct controller_engine_ctx {
> >>> >> >      struct if_status_mgr *if_mgr;
> >>> >> >      const unsigned int *ovnsb_expected_cond_seqno;
> >>> >> >      const bool *sb_monitor_all;
> >>> >> > +    /* True once every table that the current monitor conditions 
> >>> >> > request has
> >>> >> > +     * been fully received (the SB condition seqno has caught up).  
> >>> >> > The
> >>> >> > +     * route-exchange node uses this to defer its destructive 
> >>> >> > kernel sync
> >>> >> > +     * until the data it relies on is complete. */
> >>> >> > +    bool sb_all_data_loaded;
> >>> >> > +    /* True once the Advertised_Route monitor condition covers the 
> >>> >> > local
> >>> >> > +     * route-exchange datapaths (or, in monitor-all mode, 
> >>> >> > everything).  It is
> >>> >> > +     * false for the initial empty condition that is used before 
> >>> >> > any local
> >>> >> > +     * datapath is known. */
> >>> >> > +    bool sb_ar_condition_scoped;
> >>> >> >  };
> >>> >> >
> >>> >> >  /* Pending packet to be injected into connected OVS. */
> >>> >> > @@ -360,11 +370,13 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl,
> >>> >> >          sbrec_port_binding_add_clause_type(&pb, OVSDB_F_EQ, 
> >>> >> > "l2gateway");
> >>> >> >          sbrec_port_binding_add_clause_type(&pb, OVSDB_F_EQ, 
> >>> >> > "l3gateway");
> >>> >> >
> >>> >> > -        /* Monitor all advertised routes during startup.
> >>> >> > -         * Otherwise, once we claim a port on startup we do not yet 
> >>> >> > know the
> >>> >> > -         * routes to advertise and might wrongly delete already 
> >>> >> > installed
> >>> >> > -         * ones. */
> >>> >> > -        ovsdb_idl_condition_add_clause_true(&ar);
> >>> >> > +        /* Do not monitor any Advertised_Route rows during startup. 
> >>> >> > The
> >>> >> > +         * route-exchange node defers its destructive kernel sync 
> >>> >> > until it has
> >>> >> > +         * seen the initial dump of the advertised routes of the 
> >>> >> > local
> >>> >> > +         * route-exchange datapaths, so there is no risk of 
> >>> >> > deleting routes
> >>> >> > +         * we installed previously. Once local datapaths are known 
> >>> >> > the
> >>> >> > +         * condition is scoped to them (below), which avoids 
> >>> >> > pulling the whole
> >>> >> > +         * cluster's advertised routes on startup. */
> >>> >> >      }
> >>> >> >      if (local_ifaces) {
> >>> >> >          const char *name;
> >>> >> > @@ -773,6 +785,11 @@ update_sb_db(struct ovsdb_idl *ovs_idl, struct 
> >>> >> > ovsdb_idl *ovnsb_idl,
> >>> >> >          if (sb_cond_seqno) {
> >>> >> >              *sb_cond_seqno = next_cond_seqno;
> >>> >> >          }
> >>> >> > +        /* In monitor-all mode the Advertised_Route condition 
> >>> >> > matches
> >>> >> > +         * everything, so it already covers the local datapaths. */
> >>> >> > +        if (ctx) {
> >>> >> > +            ctx->sb_ar_condition_scoped = true;
> >>> >> > +        }
> >>> >> >      }
> >>> >> >      if (monitor_all_p) {
> >>> >> >          *monitor_all_p = monitor_all;
> >>> >> > @@ -5739,6 +5756,22 @@ struct ed_type_route_exchange {
> >>> >> >      bool sb_changes_pending;
> >>> >> >      /* What the last run learned from the kernel routing tables. */
> >>> >> >      struct route_exchange_state *state;
> >>> >> > +    /* True once the initial Advertised_Route dump for the local
> >>> >> > +     * route-exchange datapaths is complete.  Until then the 
> >>> >> > destructive
> >>> >> > +     * kernel sync is deferred so that we cannot delete routes that 
> >>> >> > we
> >>> >> > +     * installed previously but that are not yet present in our 
> >>> >> > (partial)
> >>> >> > +     * view of the SB database. */
> >>> >> > +    bool initial_routes_loaded;
> >>> >> > +    /* True once the first armed kernel sync has run.  Unlike
> >>> >> > +     * initial_routes_loaded, it is not cleared when the local
> >>> >> > +     * route-exchange datapath set changes or on SB reconnect, so 
> >>> >> > the
> >>> >> > +     * sync can still run (to clean up VRFs and routes) once the set
> >>> >> > +     * becomes empty.  The start-up danger window in which an empty
> >>> >> > +     * Advertised_Route view would delete routes installed before 
> >>> >> > the
> >>> >> > +     * restart is guarded by sb_all_data_loaded, which is false both
> >>> >> > +     * during the start-up bootstrap and while the Advertised_Route
> >>> >> > +     * table is reloaded after an SB reconnect. */
> >>> >> > +    bool initial_sync_completed;
> >>> >> >  };
> >>> >> >
> >>> >> >  static void
> >>> >> > @@ -5789,6 +5822,51 @@ en_route_exchange_run(struct engine_node 
> >>> >> > *node, void *data)
> >>> >> >          return EN_STALE;
> >>> >> >      }
> >>> >> >
> >>> >> > +    struct ed_type_route *route_data =
> >>> >> > +        engine_get_input_data("route", node);
> >>> >> > +    struct controller_engine_ctx *ctrl_ctx =
> >>> >> > +        engine_get_context()->client_ctx;
> >>> >> > +
> >>> >> > +    /* The set of local route-exchange datapaths selects the 
> >>> >> > Advertised_Route
> >>> >> > +     * rows that are relevant to this chassis.  Until the initial 
> >>> >> > dump of
> >>> >> > +     * exactly those rows is complete, we must not run the 
> >>> >> > destructive kernel
> >>> >> > +     * sync: it deletes every OVN route it does not see, so a 
> >>> >> > partial view
> >>> >> > +     * would delete routes we installed before a restart that have 
> >>> >> > not
> >>> >> > +     * reached our view yet.  With no local route-exchange 
> >>> >> > datapaths there is
> >>> >> > +     * no scoped dump to wait for, so once the first armed sync has 
> >>> >> > run the
> >>> >> > +     * view is complete and the sync may run to clean up the VRFs 
> >>> >> > and routes
> >>> >> > +     * of the removed datapaths. */
> >>> >> > +    bool have_local_re_datapaths =
> >>> >> > +        !hmap_is_empty(&route_data->announce_routes);
> >>> >> > +    bool ready = ctrl_ctx->sb_all_data_loaded
> >>> >> > +                 && (have_local_re_datapaths
> >>> >> > +                     ? ctrl_ctx->sb_ar_condition_scoped
> >>> >>
> >>> >> I might be missing something, but I don't understand the need for the
> >>> >> sb_ar_condition_scoped boolean.
> >>> >>
> >>> >> Here, if route_data has announce_routes, then we determine readiness
> >>> >> by checking if sb_ar_condition_scoped is true. sb_ar_condition_scoped
> >>> >> will be true under two circumstances:
> >>> >> 1) monitor_all is enabled.
> >>> >> 2) There are local_datapaths in runtime_data.
> >>> >>
> >>> >> For (1), we can, for all intents and purposes, think of
> >>> >> sb_ar_condition_scoped as being always true.
> >>> >> For (2), in order for route_data to have announce_routes, it had to
> >>> >> set those based on local_datapaths from the runtime_data.
> >>> >>
> >>> >> I did notice that sb_ar_condition_scoped can be set to false if the
> >>> >> IDL disconnects from the OVSDB server. We set the var false, then on
> >>> >> the next engine run, we'll potentially set it back to true for one of
> >>> >> the two reasons listed above after the engine run is complete. This
> >>> >> means that if the IDL disconnects, then we can have one of two
> >>> >> situations occur during the first engine run after reconnecting:
> >>> >>
> >>> >> 1) The recompute results in no route_data->announce_routes.
> >>> >> 2) The recompute results in route_data->announce_routes being true.
> >>> >>
> >>> >> In case (1), we may determine ourselves ready since
> >>> >> re->initial_sync_completed may have been set true on a previous call
> >>> >> to en_route_exchange_run(). In case (2), we'll always see ourselves as
> >>> >> unready since sb_ar_condition_scoped was set false before the engine
> >>> >> run.
> >>> >>
> >>> >> To me this seems strange. If the main issue is about startup latency,
> >>> >> then why would we declare ourselves unready in the situation where we
> >>> >> disconnect from the OVSDB server, and the next engine run after
> >>> >> reconnecting results in announce_routes being present? Moreover, why
> >>> >> would we consider ourselves ready if there are no announce_routes?
> >>> >>
> >>> >> IMO, I think the ready boolean should be set as:
> >>> >>
> >>> >> bool ready = ctrl_ctx->sb_all_data_loaded && (have_local_re_datapaths
> >>> >> || re->initial_sync_completed);
> >>> >>
> >>> >> This way, we won't run if the OVSDB monitor conditions are out of
> >>> >> whack. On startup, we'll run as soon as announce_routes are detected
> >>> >> as present for the first time. Then on any IDL disconnects, since we
> >>> >> finished an initial sync, we'll declare ourselves ready every time
> >>> >> from then on. This would allow us to get rid of the
> >>> >> sb_ar_condition_scoped field altogether.
> >>> >>
> >>> >> What do you think?
> >>> >
> >>> >
> >>> > I think we need sb_ar_condition_scoped.
> >>> >
> >>> > sb_all_data_loaded represents if the dump of the current sb condition is
> >>> > complete while sb_ar_condition_scoped is if the current condition is
> >>> > one that actually selects the local datapaths route exchange
> >>> > rows.
> >>> >
> >>> > At startup we initially add no monitor for advertised routes and build 
> >>> > up the advertised route condition
> >>> > per local datapath on runs of update_sb_monitors().  So it is possible 
> >>> > that all the data for the current
> >>> > condition is loaded but none of the advertised routes are because we 
> >>> > have no condition for them. The
> >>> > issue is ordering, On the iteration where a local route_exchange 
> >>> > datapath first appears in the engine's view,
> >>> > the engine already sees announce_routes non-empty, but the IDL's 
> >>> > effective AR condition is still the last
> >>> > iterations, the empty one, so sb_ar_condition_scoped is still false. 
> >>> > Then update_sb_monitors() runs after the
> >>> > engine_run() which updates sb_ar_condition_scoped and we can be sure we 
> >>> > have all the needed data in the next
> >>> > iteration. Does that make sense?
> >>>
> >>> OK, I get it now. I didn't realize that update_sb_monitors() was
> >>> dynamically updating what we were monitoring. The idea is that on
> >>> engine_run 1, a SB datapath may get classified as "local". However, on
> >>> this first run, we are not monitoring the Advertised_Route table for
> >>> routes pertaining to this datapath. After the engine run completes,
> >>> update_sb_monitors() adds a monitor for Advertised_Routes for that
> >>> particular datapath so that the next IDL run can potentially pull in
> >>> the Advertised_Routes for that datapath. This way, on engine_run 2, we
> >>> know that the Advertised_Routes are being monitored for this datapath.
> >>> The sb_ar_condition_scoped variable gets set true when we have local
> >>> datapaths, and therefore we are now known to be monitoring the
> >>> Advertised_Route table in some capacity. The idea is that if any rows
> >>> of Advertised_Route are being monitored at all, then it is safe for
> >>> en_route_exchange_run() to continue.
> >>>
> >>> This makes a lot more sense now, and it also now has made me think of
> >>> a different potential issue we could see. What happens if we restart
> >>> and there are no local datapaths for quite a long time? We could be
> >>> put in a position where we are keeping dead routes around that should
> >>> be deleted. Should there be some sort of failsafe added so that if
> >>> some period of time passes after startup with no local_datapaths, we
> >>> can assume that our routes are dead and we should delete them?
> >>
> >>
> >> I hadn't considered that; let me investigate and get back to you.
> >>
> >>>
> >>>
> >>> >
> >>> >
> >>> >>
> >>> >>
> >>> >> > +                     : re->initial_sync_completed);
> >>> >> > +
> >>> >> > +    if (re->initial_routes_loaded && !ready) {
> >>> >> > +        /* The set of local route-exchange datapaths changed or the 
> >>> >> > SB
> >>> >> > +         * connection reset; defer the destructive sync again until 
> >>> >> > the new
> >>> >> > +         * scoped dump is complete. */
> >>> >> > +        re->initial_routes_loaded = false;
> >>> >> > +        VLOG_INFO("Route-exchange datapath set changed; deferring 
> >>> >> > route "
> >>> >> > +                  "sync until the Advertised_Route dump 
> >>> >> > completes.");
> >>> >> > +        return EN_UNCHANGED;
> >>> >> > +    }
> >>> >> > +    if (!re->initial_routes_loaded) {
> >>> >> > +        if (!ready) {
> >>> >> > +            return EN_UNCHANGED;   /* still loading; kernel 
> >>> >> > untouched */
> >>> >> > +        }
> >>> >> > +        re->initial_routes_loaded = true;
> >>> >> > +        /* Past the start-up danger window from now on: the view 
> >>> >> > has been
> >>> >> > +         * complete enough to run the destructive sync once, so a 
> >>> >> > later
> >>> >> > +         * transition to an empty local route-exchange datapath set 
> >>> >> > (the
> >>> >> > +         * last dynamic-routing router removed) may run it to clean 
> >>> >> > up. */
> >>> >> > +        re->initial_sync_completed = true;
> >>> >> > +        VLOG_INFO("Advertised_Route dump complete for local 
> >>> >> > route-exchange "
> >>> >> > +                  "datapaths; enabling route sync.");
> >>> >> > +        /* Fall through: run once now to reconcile the kernel. */
> >>> >> > +    }
> >>> >> > +
> >>> >> >      vector_clear(&rt_notify->watches);
> >>> >> >
> >>> >> >      struct route_exchange_ctx_in r_ctx_in;
> >>> >> > @@ -5811,6 +5889,13 @@ route_exchange_route_table_handler(struct 
> >>> >> > engine_node *node, void *data)
> >>> >> >      struct ed_type_route_table_notify *rt_notify =
> >>> >> >          engine_get_input_data("route_table_notify", node);
> >>> >> >
> >>> >> > +    /* While the initial dump is still pending the full run has not 
> >>> >> > happened
> >>> >> > +     * yet, so no kernel route watches are registered and nothing 
> >>> >> > was lost.
> >>> >> > +     * The first armed run reconciles the kernel from scratch. */
> >>> >> > +    if (!re->initial_routes_loaded) {
> >>> >> > +        return EN_HANDLED_UNCHANGED;
> >>> >> > +    }
> >>> >> > +
> >>> >> >      /* We were not told about every change, so the routes we know 
> >>> >> > of are not
> >>> >> >       * necessarily the ones the kernel has. */
> >>> >> >      if (rt_notify->resync) {
> >>> >> > @@ -7394,6 +7479,10 @@ inc_proc_ovn_controller_init(
> >>> >> >      engine_add_input(&en_route_exchange, &en_route_exchange_status, 
> >>> >> > NULL);
> >>> >> >      engine_add_input(&en_route_exchange, &en_sb_ro,
> >>> >> >                       route_exchange_sb_ro_handler);
> >>> >> > +    /* Re-evaluate the initial-dump readiness gate whenever the SB 
> >>> >> > monitor
> >>> >> > +     * conditions change (including the final ack of the scoped
> >>> >> > +     * Advertised_Route dump). */
> >>> >> > +    engine_add_input(&en_route_exchange, &en_sb_cond_seqno, NULL);
> >>> >> >
> >>> >> >      engine_add_input(&en_addr_sets, &en_sb_address_set,
> >>> >> >                       addr_sets_sb_address_set_handler);
> >>> >> > @@ -8171,6 +8260,8 @@ main(int argc, char *argv[])
> >>> >> >          .if_mgr = if_status_mgr_create(),
> >>> >> >          .ovnsb_expected_cond_seqno = &ovnsb_expected_cond_seqno,
> >>> >> >          .sb_monitor_all = &sb_monitor_all,
> >>> >> > +        .sb_all_data_loaded = false,
> >>> >> > +        .sb_ar_condition_scoped = false,
> >>> >> >      };
> >>> >> >      struct if_status_mgr *if_mgr = ctrl_engine_ctx.if_mgr;
> >>> >> >
> >>> >> > @@ -8240,6 +8331,10 @@ main(int argc, char *argv[])
> >>> >> >              if (!new_ovnsb_cond_seqno) {
> >>> >> >                  VLOG_INFO("OVNSB IDL reconnected, force 
> >>> >> > recompute.");
> >>> >> >                  engine_set_force_recompute();
> >>> >> > +                /* The monitor conditions are re-applied on 
> >>> >> > reconnect, so the
> >>> >> > +                 * previously scoped Advertised_Route condition no 
> >>> >> > longer
> >>> >> > +                 * holds. */
> >>> >> > +                ctrl_engine_ctx.sb_ar_condition_scoped = false;
> >>> >> >              }
> >>> >> >              ovnsb_cond_seqno = new_ovnsb_cond_seqno;
> >>> >> >          }
> >>> >> > @@ -8254,6 +8349,18 @@ main(int argc, char *argv[])
> >>> >> >              daemon_started_recently_ignore();
> >>> >> >          }
> >>> >> >
> >>> >> > +        /* Whether the rows selected by the current monitor 
> >>> >> > conditions are all
> >>> >> > +         * present in the IDL.  This is recomputed every loop 
> >>> >> > iteration so
> >>> >> > +         * that engine nodes can rely on it being up to date for the
> >>> >> > +         * conditions that were applied so far.
> >>> >> > +         * If we have sb_monitor_all that means we have all data 
> >>> >> > that we would
> >>> >> > +         * ever need. */
> >>> >> > +        ctrl_engine_ctx.sb_all_data_loaded =
> >>> >> > +            sb_monitor_all ||
> >>> >> > +            (ovnsb_cond_seqno == ovnsb_expected_cond_seqno
> >>> >> > +             && ovnsb_expected_cond_seqno != UINT_MAX
> >>> >> > +             && ovnsb_cond_seqno != 0);
> >>> >> > +
> >>> >> >          struct engine_context eng_ctx = {
> >>> >> >              .ovs_idl_txn = ovs_idl_txn,
> >>> >> >              .ovnsb_idl_txn = ovnsb_idl_txn,
> >>> >> > @@ -8574,6 +8681,15 @@ main(int argc, char *argv[])
> >>> >> >                                      
> >>> >> > &runtime_data->lbinding_data.bindings,
> >>> >> >                                      &runtime_data->local_datapaths,
> >>> >> >                                      sb_monitor_all);
> >>> >> > +                            /* The Advertised_Route condition now 
> >>> >> > covers the
> >>> >> > +                             * local datapaths (or everything, in
> >>> >> > +                             * monitor-all mode).  If there are no 
> >>> >> > local
> >>> >> > +                             * datapaths yet, there is nothing to 
> >>> >> > cover and
> >>> >> > +                             * the empty condition is sufficient. */
> >>> >> > +                            ctrl_engine_ctx.sb_ar_condition_scoped =
> >>> >> > +                                sb_monitor_all ||
> >>> >> > +                                !hmap_is_empty(
> >>> >> > +                                    &runtime_data->local_datapaths);
> >>> >> >                              bool condition_changed = 
> >>> >> > ovnsb_cond_seqno !=
> >>> >> >                                                       
> >>> >> > ovnsb_expected_cond_seqno;
> >>> >> >                              if (had_all_data && condition_changed) {
> >>> >> > diff --git a/tests/ovn-inc-proc-graph-dump.at 
> >>> >> > b/tests/ovn-inc-proc-graph-dump.at
> >>> >> > index 8348c3467..a388f3d25 100644
> >>> >> > --- a/tests/ovn-inc-proc-graph-dump.at
> >>> >> > +++ b/tests/ovn-inc-proc-graph-dump.at
> >>> >> > @@ -469,6 +469,7 @@ digraph "Incremental-Processing-Engine" {
> >>> >> >         SB_learned_route [[style=filled, shape=box, fillcolor=white, 
> >>> >> > label="SB_learned_route"]];
> >>> >> >         route_table_notify [[style=filled, shape=box, 
> >>> >> > fillcolor=white, label="route_table_notify"]];
> >>> >> >         route_exchange_status [[style=filled, shape=box, 
> >>> >> > fillcolor=white, label="route_exchange_status"]];
> >>> >> > +       sb_cond_seqno [[style=filled, shape=box, fillcolor=white, 
> >>> >> > label="sb_cond_seqno"]];
> >>> >> >         route_exchange [[style=filled, shape=box, fillcolor=white, 
> >>> >> > label="route_exchange"]];
> >>> >> >         OVS_open_vswitch -> route_exchange [[label=""]];
> >>> >> >         SB_chassis -> route_exchange [[label=""]];
> >>> >> > @@ -478,6 +479,7 @@ digraph "Incremental-Processing-Engine" {
> >>> >> >         route_table_notify -> route_exchange 
> >>> >> > [[label="route_exchange_route_table_handler"]];
> >>> >> >         route_exchange_status -> route_exchange [[label=""]];
> >>> >> >         sb_ro -> route_exchange 
> >>> >> > [[label="route_exchange_sb_ro_handler"]];
> >>> >> > +       sb_cond_seqno -> route_exchange [[label=""]];
> >>> >> >         garp_rarp [[style=filled, shape=box, fillcolor=white, 
> >>> >> > label="garp_rarp"]];
> >>> >> >         OVS_open_vswitch -> garp_rarp [[label=""]];
> >>> >> >         SB_chassis -> garp_rarp [[label=""]];
> >>> >> > @@ -497,7 +499,6 @@ digraph "Incremental-Processing-Engine" {
> >>> >> >         SB_acl_id [[style=filled, shape=box, fillcolor=white, 
> >>> >> > label="SB_acl_id"]];
> >>> >> >         acl_id [[style=filled, shape=box, fillcolor=white, 
> >>> >> > label="acl_id"]];
> >>> >> >         SB_acl_id -> acl_id [[label=""]];
> >>> >> > -       sb_cond_seqno [[style=filled, shape=box, fillcolor=white, 
> >>> >> > label="sb_cond_seqno"]];
> >>> >> >         datapaths_updated [[style=filled, shape=box, 
> >>> >> > fillcolor=white, label="datapaths_updated"]];
> >>> >> >         sb_cond_seqno -> datapaths_updated 
> >>> >> > [[label="datapaths_update_sb_cond_handler"]];
> >>> >> >         runtime_data -> datapaths_updated 
> >>> >> > [[label="datapaths_updated_runtime_data_handler"]];
> >>> >> > diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> >>> >> > index 13e62bf9b..e0f1c6f0d 100644
> >>> >> > --- a/tests/system-ovn.at
> >>> >> > +++ b/tests/system-ovn.at
> >>> >> > @@ -15739,6 +15739,12 @@ blackhole 198.51.100.0/24 proto ovn metric 
> >>> >> > 1000
> >>> >> >  233.253.0.0/24 via 192.168.20.20 dev hv1-mll proto zebra metric 30 
> >>> >> > onlink
> >>> >> >  233.253.0.0/24 via 192.168.20.20 dev hv1-mll proto zebra metric 40 
> >>> >> > onlink])
> >>> >> >
> >>> >> > +# Route exchange defers its kernel sync until the initial 
> >>> >> > Advertised_Route
> >>> >> > +# dump for the local route-exchange datapaths is complete. The 
> >>> >> > routes above
> >>> >> > +# can only be installed once that happens, so verify the deferred 
> >>> >> > sync was
> >>> >> > +# actually enabled.
> >>> >> > +OVS_WAIT_UNTIL([test "$(grep -c 'Advertised_Route dump complete for 
> >>> >> > local route-exchange datapaths' ovn-controller.log)" -ge 1])
> >>> >> > +
> >>> >> >  # Changing the vrf name will switch to the new one.
> >>> >> >  # The old vrf will be removed.
> >>> >> >  check ovn-nbctl --wait=hv set Logical_Router_Port internet-phys \
> >>> >> > @@ -15757,7 +15763,10 @@ blackhole 198.51.100.0/24 proto ovn metric 
> >>> >> > 1000
> >>> >> >  233.253.0.0/24 via 192.168.20.20 dev hv1-mll proto zebra metric 30 
> >>> >> > onlink
> >>> >> >  233.253.0.0/24 via 192.168.20.20 dev hv1-mll proto zebra metric 40 
> >>> >> > onlink])
> >>> >> >
> >>> >> > -# Stopping with --restart will not touch the routes.
> >>> >> > +# Stopping with --restart will not touch the routes. While the 
> >>> >> > restarted
> >>> >> > +# controller loads its Advertised_Routes the kernel sync is 
> >>> >> > deferred, so a
> >>> >> > +# controller that synced from a partial view would have deleted the 
> >>> >> > OVN routes
> >>> >> > +# below; verify they all survive the restart.
> >>> >> >  OVN_CONTROLLER_EXIT([],[--restart])
> >>> >> >  OVN_ROUTE_EQUAL([ovnvrf1338], [dnl
> >>> >> >  blackhole 192.0.2.1 proto ovn metric 100
> >>> >> > --
> >>> >> > 2.55.0
> >>> >> >
> >>> >> > _______________________________________________
> >>> >> > dev mailing list
> >>> >> > [email protected]
> >>> >> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >>> >> >
> >>> >>
> >>>

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

Reply via email to