Hi Paulo, Tiago

Same rename problem as in 07/14.
Leak on transit switch's rename.

Regards,
Lucas

Em qua., 2 de set. de 2026 às 18:19, Paulo Guilherme Silva
<[email protected]> escreveu:

> Add the incremental change handlers for the en_ts node: an NB
> Logical_Switch change that is not a transit-switch mirror is a no-op, and
> transit-switch changes are reconciled per transit switch (scoped) instead
> of forcing a full recompute of every transit switch.
>
> Assisted-by: Claude Opus 4.8, Claude Code
> Co-authored-by: Tiago Matos <[email protected]>
> Signed-off-by: Tiago Matos <[email protected]>
> Signed-off-by: Paulo Guilherme Silva <[email protected]>
> ---
>  ic/en-ts.c       | 135 +++++++++++++++++++++++++++++++++++++++++++++++
>  ic/en-ts.h       |   9 ++++
>  ic/inc-proc-ic.c |  21 +++++---
>  3 files changed, 159 insertions(+), 6 deletions(-)
>
> diff --git a/ic/en-ts.c b/ic/en-ts.c
> index d983e6bb0..93a53fe92 100644
> --- a/ic/en-ts.c
> +++ b/ic/en-ts.c
> @@ -68,6 +68,141 @@ en_ts_run(struct engine_node *node, void *data
> OVS_UNUSED)
>      return EN_UPDATED;
>  }
>
> +/* Returns the ic_context, or NULL when there is no availability zone yet
> (in
> + * which case the caller should report EN_HANDLED_UNCHANGED). */
> +static struct ic_context *
> +ts_handler_ctx(struct engine_node *node)
> +{
> +    struct ic_context *ctx = engine_get_context()->client_ctx;
> +    const struct ed_type_az *az = engine_get_input_data("az", node);
> +    return az->runned_az ? ctx : NULL;
> +}
> +
> +/* Runs the scoped NB-mirror sync for the collected transit-switch scope
> and
> + * maps it to an engine result.  ts_sync_scope() gates the NB mirror on
> the
> + * ovnnb_txn it needs, exactly as the full recompute does. */
> +static enum engine_input_handler_result
> +ts_scope_finish(struct ic_context *ctx, struct sset *ts_scope)
> +{
> +    if (sset_is_empty(ts_scope)) {
> +        return EN_HANDLED_UNCHANGED;
> +    }
> +
> +    struct shash isb_ts_dps;
> +    collect_ts_datapaths(ctx, &isb_ts_dps);
> +    ts_sync_scope(ctx, &isb_ts_dps, ts_scope);
> +    shash_destroy(&isb_ts_dps);
> +
> +    return EN_HANDLED_UPDATED;
> +}
> +
> +/* IC-NB Transit_Switch: a new/deleted/renamed transit switch must have
> its NB
> + * mirror reconciled.  A deletion is honoured via the scoped GC in
> + * ts_sync_scope() (the deleted row's name stays in scope but is absent
> from
> + * IC-NB, so its mirror leftover is removed). */
> +enum engine_input_handler_result
> +en_ts_icnb_transit_switch_handler(struct engine_node *node,
> +                                  void *data OVS_UNUSED)
> +{
> +    struct ic_context *ctx = ts_handler_ctx(node);
> +    if (!ctx) {
> +        return EN_HANDLED_UNCHANGED;
> +    }
> +
> +    const struct icnbrec_transit_switch_table *tbl =
> +        EN_OVSDB_GET(engine_get_input("ICNB_transit_switch", node));
> +    struct sset ts_scope = SSET_INITIALIZER(&ts_scope);
> +    const struct icnbrec_transit_switch *ts;
> +    ICNBREC_TRANSIT_SWITCH_TABLE_FOR_EACH_TRACKED (ts, tbl) {
> +        sset_add(&ts_scope, ts->name);
> +    }
> +
> +    enum engine_input_handler_result ret = ts_scope_finish(ctx,
> &ts_scope);
> +    sset_destroy(&ts_scope);
> +    return ret;
> +}
> +
> +/* Only transit-switch mirror logical switches (other_config:interconn-ts)
> + * affect en_ts.  A change to such a logical switch reconciles that
> transit
> + * switch (re-creating the mirror if it was deleted externally); any other
> + * logical switch is irrelevant to en_ts, so its change is a no-op,
> avoiding a
> + * recompute on unrelated NB Logical_Switch updates. */
> +enum engine_input_handler_result
> +en_ts_nb_logical_switch_handler(struct engine_node *node,
> +                                void *data OVS_UNUSED)
> +{
> +    struct ic_context *ctx = ts_handler_ctx(node);
> +    if (!ctx) {
> +        return EN_HANDLED_UNCHANGED;
> +    }
> +
> +    const struct nbrec_logical_switch_table *tbl =
> +        EN_OVSDB_GET(engine_get_input("NB_logical_switch", node));
> +    struct sset ts_scope = SSET_INITIALIZER(&ts_scope);
> +    const struct nbrec_logical_switch *ls;
> +    NBREC_LOGICAL_SWITCH_TABLE_FOR_EACH_TRACKED (ls, tbl) {
> +        const char *ts_name = smap_get(&ls->other_config, "interconn-ts");
> +        if (ts_name) {
> +            sset_add(&ts_scope, ts_name);
> +        }
> +    }
> +
> +    enum engine_input_handler_result ret = ts_scope_finish(ctx,
> &ts_scope);
> +    sset_destroy(&ts_scope);
> +    return ret;
> +}
> +
> +/* IC-SB Datapath_Binding: when a transit switch's datapath tunnel key is
> + * (re)assigned by en_tunnel_key, the NB Logical_Switch mirror's
> + * other_config:requested-tnl-key must be updated to the committed
> value.  This
> + * is what synchronizes the key after a global tunnel-key refresh (an
> IC-NB
> + * vxlan_mode change reallocates the datapath key into the VXLAN range in
> + * IC-SB, but the NB value only catches up on a follow-up iteration).
> + *
> + * Only transit-switch bindings have an NB mirror; transit routers
> (IC_ROUTER)
> + * are irrelevant.  Deletions are ignored: a transit switch removal is
> + * reconciled through en_ts_icnb_transit_switch_handler and the scoped GC
> in
> + * ts_sync_scope().
> + *
> + * Newly *inserted* bindings are also ignored, on purpose.  en_tunnel_key
> + * inserts the binding and already publishes its freshly-allocated key to
> the
> + * mirror in the same iteration; reacting to that insert here would
> re-sync the
> + * transit switch while its mirror (if just created by
> + * en_ts_icnb_transit_switch_handler) is still uncommitted -
> find_ts_in_nb()'s
> + * index does not see the txn-local insert, so a duplicate NB
> Logical_Switch
> + * would be created.  Here we only react to a tunnel-key *modify* on an
> + * already-existing binding (the vxlan refresh), whose mirror already
> + * exists. */
> +enum engine_input_handler_result
> +en_ts_icsb_datapath_binding_handler(struct engine_node *node,
> +                                    void *data OVS_UNUSED)
> +{
> +    struct ic_context *ctx = ts_handler_ctx(node);
> +    if (!ctx) {
> +        return EN_HANDLED_UNCHANGED;
> +    }
> +
> +    const struct icsbrec_datapath_binding_table *tbl =
> +        EN_OVSDB_GET(engine_get_input("ICSB_datapath_binding", node));
> +    struct sset ts_scope = SSET_INITIALIZER(&ts_scope);
> +    const struct icsbrec_datapath_binding *isb_dp;
> +    ICSBREC_DATAPATH_BINDING_TABLE_FOR_EACH_TRACKED (isb_dp, tbl) {
> +        if (icsbrec_datapath_binding_is_deleted(isb_dp) ||
> +            icsbrec_datapath_binding_is_new(isb_dp) ||
> +            ic_dp_get_type(isb_dp) != IC_SWITCH) {
> +            continue;
> +        }
> +        if (ovsdb_idl_track_is_updated(&isb_dp->header_,
> +                    &icsbrec_datapath_binding_col_tunnel_key)) {
> +            sset_add(&ts_scope, isb_dp->transit_switch);
> +        }
> +    }
> +
> +    enum engine_input_handler_result ret = ts_scope_finish(ctx,
> &ts_scope);
> +    sset_destroy(&ts_scope);
> +    return ret;
> +}
> +
>  void *
>  en_ts_init(struct engine_node *node OVS_UNUSED,
>             struct engine_arg *arg OVS_UNUSED)
> diff --git a/ic/en-ts.h b/ic/en-ts.h
> index cf33d9ab6..32bdfedb0 100644
> --- a/ic/en-ts.h
> +++ b/ic/en-ts.h
> @@ -21,4 +21,13 @@ enum engine_node_state en_ts_run(struct engine_node
> *node, void *data);
>  void *en_ts_init(struct engine_node *node, struct engine_arg *arg);
>  void en_ts_cleanup(void *data);
>
> +enum engine_input_handler_result
> +en_ts_icnb_transit_switch_handler(struct engine_node *node, void *data);
> +
> +enum engine_input_handler_result
> +en_ts_nb_logical_switch_handler(struct engine_node *node, void *data);
> +
> +enum engine_input_handler_result
> +en_ts_icsb_datapath_binding_handler(struct engine_node *node, void *data);
> +
>  #endif /* EN_IC_TS_H */
> diff --git a/ic/inc-proc-ic.c b/ic/inc-proc-ic.c
> index a30ddf367..89135fc5d 100644
> --- a/ic/inc-proc-ic.c
> +++ b/ic/inc-proc-ic.c
> @@ -218,14 +218,23 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb,
>      engine_add_input(&en_gateway, &en_sb_encap, NULL);
>
>      /* en_ts: sync transit switches to their AZ NB Logical_Switch mirrors.
> +     *
>       * en_ts builds its own transit-switch IC-SB Datapath_Binding map
> each run
> -     * and only maintains the NB mirror; IC-SB Datapath_Binding
> creation/keying
> -     * is owned by en_tunnel_key (downstream). */
> +     * (local data, never shared) and only maintains the NB mirror.  IC-SB
> +     * Datapath_Binding creation/keying is owned by en_tunnel_key
> (downstream),
> +     * so en_ts no longer allocates tunnel keys.  en_icsb_datapath_binding
> +     * drives the follow-up NB requested-tnl-key sync after en_tunnel_key
> +     * (re)assigns a key - notably the global refresh from an IC-NB
> vxlan_mode
> +     * change (see en_ts_icsb_datapath_binding_handler). */
>      engine_add_input(&en_ts, &en_az, NULL);
> -    engine_add_input(&en_ts, &en_icsb_datapath_binding, NULL);
> -    engine_add_input(&en_ts, &en_icnb_ic_nb_global, NULL);
> -    engine_add_input(&en_ts, &en_icnb_transit_switch, NULL);
> -    engine_add_input(&en_ts, &en_nb_logical_switch, NULL);
> +    engine_add_input(&en_ts, &en_icsb_datapath_binding,
> +                     en_ts_icsb_datapath_binding_handler);
> +    engine_add_input(&en_ts, &en_icnb_ic_nb_global,
> +                     ic_nb_global_options_handler);
> +    engine_add_input(&en_ts, &en_icnb_transit_switch,
> +                     en_ts_icnb_transit_switch_handler);
> +    engine_add_input(&en_ts, &en_nb_logical_switch,
> +                     en_ts_nb_logical_switch_handler);
>      engine_add_input(&en_ts, &en_icsb_encap, NULL);
>
>      /* en_tr: sync transit routers to their AZ NB Logical_Router mirrors.
> --
> 2.34.1
>
>
> --
>
>
>
>
> _'Esta mensagem é direcionada apenas para os endereços constantes no
> cabeçalho inicial. Se você não está listado nos endereços constantes no
> cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa
> mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas
> estão
> imediatamente anuladas e proibidas'._
>
>
> * **'Apesar do Magazine Luiza tomar
> todas as precauções razoáveis para assegurar que nenhum vírus esteja
> presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por
> quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*
>
>
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>

-- 




_‘Esta mensagem é direcionada apenas para os endereços constantes no 
cabeçalho inicial. Se você não está listado nos endereços constantes no 
cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa 
mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão 
imediatamente anuladas e proibidas’._


* **‘Apesar do Magazine Luiza tomar 
todas as precauções razoáveis para assegurar que nenhum vírus esteja 
presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por 
quaisquer perdas ou danos causados por esse e-mail ou por seus anexos’.*



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

Reply via email to