Thanks Paulo, I have comments inline below.
On Mon, Feb 9, 2026 at 1:29 PM Paulo Guilherme Silva via dev
<[email protected]> wrote:
>
> This new engine now maintains the enum_datapath related data for ovn-ic
> daemon which was earlier maintained by the ic engine node invoked the
> enumerate_datapaths() function. The inputs to this engine node are
> en_icnb_transit_switch;
> en_icsb_datapath_binding';
> In order to achieve this, we refactor in the following way:
> * Introduce enum_datapaths_init() which initializes this data.
> * Introduce enum_datapaths_destroy() which clears this data for a
> new iteration.
> * Introduce enum_datapaths_run() which invokes the full recompute
> of the engine.
>
> This engine node becomes an input to 'ic' node.
>
> Signed-off-by: Paulo Guilherme Silva <[email protected]>
> ---
> ic/automake.mk | 2 +
> ic/en-enum-datapaths.c | 141 +++++++++++++++++++++++++++++++++++++++++
> ic/en-enum-datapaths.h | 30 +++++++++
> ic/en-ic.c | 29 +++++----
> ic/inc-proc-ic.c | 6 ++
> ic/ovn-ic.c | 82 ++++++++++++------------
> ic/ovn-ic.h | 8 +--
> lib/stopwatch-names.h | 1 +
> 8 files changed, 244 insertions(+), 55 deletions(-)
> create mode 100644 ic/en-enum-datapaths.c
> create mode 100644 ic/en-enum-datapaths.h
>
> diff --git a/ic/automake.mk b/ic/automake.mk
> index a69b1030d..2766483b7 100644
> --- a/ic/automake.mk
> +++ b/ic/automake.mk
> @@ -4,6 +4,8 @@ ic_ovn_ic_SOURCES = ic/ovn-ic.c \
> ic/ovn-ic.h \
> ic/en-ic.c \
> ic/en-ic.h \
> + ic/en-enum-datapaths.c \
> + ic/en-enum-datapaths.h \
> ic/inc-proc-ic.c \
> ic/inc-proc-ic.h
> ic_ovn_ic_LDADD = \
> diff --git a/ic/en-enum-datapaths.c b/ic/en-enum-datapaths.c
> new file mode 100644
> index 000000000..7515c0b85
> --- /dev/null
> +++ b/ic/en-enum-datapaths.c
> @@ -0,0 +1,141 @@
> +/*
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> +*/
> +
> +#include <config.h>
> +
> +#include <getopt.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +/* OVS includes. */
> +#include "openvswitch/vlog.h"
> +#include "openvswitch/shash.h"
> +#include "openvswitch/hmap.h"
> +
> +/* OVN includes. */
> +#include "ovn-ic.h"
> +#include "en-enum-datapaths.h"
> +#include "inc-proc-ic.h"
> +#include "lib/inc-proc-eng.h"
> +#include "lib/ovn-ic-sb-idl.h"
> +#include "lib/ovn-util.h"
> +#include "lib/stopwatch-names.h"
> +#include "coverage.h"
> +#include "stopwatch.h"
> +#include "stopwatch-names.h"
> +
> +VLOG_DEFINE_THIS_MODULE(en_enum_datapaths);
> +COVERAGE_DEFINE(enum_datapaths_run);
> +
> +static void
> +enum_datapath_run(const struct icsbrec_datapath_binding_table *dp_table,
> + struct ed_type_enum_datapaths *dp_data);
> +static enum ic_datapath_type
> + ic_dp_get_type(const struct icsbrec_datapath_binding *isb_dp);
> +static void enum_datapaths_init(struct ed_type_enum_datapaths *data);
> +static void enum_datapaths_destroy(struct ed_type_enum_datapaths *data);
> +static void enum_datapaths_clear(struct ed_type_enum_datapaths *data);
> +
> +void *
> +en_enum_datapaths_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED)
> +{
> + struct ed_type_enum_datapaths *data = xzalloc(sizeof *data);
> + enum_datapaths_init(data);
> + return data;
> +}
> +
> +void
> +en_enum_datapaths_cleanup(void *data)
> +{
> + enum_datapaths_destroy(data);
> +}
> +
> +enum engine_node_state
> +en_enum_datapaths_run(struct engine_node *node, void *data)
> +{
> + struct ed_type_enum_datapaths *dp_data = data;
> +
> + enum_datapaths_clear(dp_data);
> +
> + const struct icsbrec_datapath_binding_table *dp_table =
> + EN_OVSDB_GET(engine_get_input("ICSB_datapath_binding", node));
> +
> + COVERAGE_INC(enum_datapaths_run);
> + stopwatch_start(OVN_IC_ENUM_DATAPATHS_RUN_STOPWATCH_NAME, time_msec());
> + enum_datapath_run(dp_table, dp_data);
> + stopwatch_stop(OVN_IC_ENUM_DATAPATHS_RUN_STOPWATCH_NAME, time_msec());
> +
> + return EN_UPDATED;
> +}
> +
> +static void
> +enum_datapath_run(const struct icsbrec_datapath_binding_table *dp_table,
> + struct ed_type_enum_datapaths *dp_data)
> +{
> + const struct icsbrec_datapath_binding *isb_dp;
> + ICSBREC_DATAPATH_BINDING_TABLE_FOR_EACH (isb_dp, dp_table) {
> + /* 1. Adiciona Tunnel ID */
> + ovn_add_tnlid(&dp_data->dp_tnlids, isb_dp->tunnel_key);
> +
> + /* 2. Classifica o Datapath */
It appears some Portuguese has entered the code here :)
> + enum ic_datapath_type dp_type = ic_dp_get_type(isb_dp);
> + if (dp_type == IC_ROUTER) {
> + char *uuid_str = uuid_to_string(isb_dp->nb_ic_uuid);
> + shash_add(&dp_data->isb_tr_dps, uuid_str, (void *) isb_dp);
> + free(uuid_str);
> + } else {
> + shash_add(&dp_data->isb_ts_dps, isb_dp->transit_switch,
> + (void *) isb_dp);
> + }
> + }
> +}
> +
> +static enum ic_datapath_type
> +ic_dp_get_type(const struct icsbrec_datapath_binding *isb_dp)
> +{
> + if (isb_dp->type && !strcmp(isb_dp->type, "transit-router")) {
> + return IC_ROUTER;
> + }
> +
> + return IC_SWITCH;
> +}
> +
> +static void
> +enum_datapaths_init(struct ed_type_enum_datapaths *data)
> +{
> + hmap_init(&data->dp_tnlids);
> + shash_init(&data->isb_ts_dps);
> + shash_init(&data->isb_tr_dps);
> +}
> +
> +static void
> +enum_datapaths_destroy(struct ed_type_enum_datapaths *data)
> +{
> + enum_datapaths_clear(data);
There is no need to call enum_datapaths_clear() here. There is a
similar pattern employed in patches 3, 4, and 5 as well.
> + ovn_destroy_tnlids(&data->dp_tnlids);
> +
> + shash_destroy(&data->isb_ts_dps);
> + shash_destroy(&data->isb_tr_dps);
> +}
> +
> +static void
> +enum_datapaths_clear(struct ed_type_enum_datapaths *data)
> +{
> + ovn_destroy_tnlids(&data->dp_tnlids);
> + hmap_init(&data->dp_tnlids);
> +
> + shash_clear(&data->isb_ts_dps);
> + shash_clear(&data->isb_tr_dps);
> +}
> diff --git a/ic/en-enum-datapaths.h b/ic/en-enum-datapaths.h
> new file mode 100644
> index 000000000..0aff9fc89
> --- /dev/null
> +++ b/ic/en-enum-datapaths.h
> @@ -0,0 +1,30 @@
> +#ifndef EN_IC_ENUM_DATAPATHS_H
> +#define EN_IC_ENUM_DATAPATHS_H 1
> +
> +#include <config.h>
> +
> +#include <stdbool.h>
> +#include <getopt.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +/* OVS includes. */
> +#include "lib/hmapx.h"
> +#include "openvswitch/hmap.h"
> +#include "openvswitch/shash.h"
> +
> +/* OVN includes. */
> +#include "lib/inc-proc-eng.h"
> +
> +/* struct which maintains the data of the engine node enumerate datapaths. */
> +struct ed_type_enum_datapaths {
> + struct hmap dp_tnlids;
> + struct shash isb_ts_dps;
> + struct shash isb_tr_dps;
> +};
> +
> +void *en_enum_datapaths_init(struct engine_node *, struct engine_arg *);
> +enum engine_node_state en_enum_datapaths_run(struct engine_node *, void
> *data);
> +void en_enum_datapaths_cleanup(void *data);
> +
> +#endif
> \ No newline at end of file
> diff --git a/ic/en-ic.c b/ic/en-ic.c
> index ce7d5de76..16b0e12bd 100644
> --- a/ic/en-ic.c
> +++ b/ic/en-ic.c
> @@ -24,6 +24,8 @@
> /* OVN includes. */
> #include "ovn-ic.h"
> #include "en-ic.h"
> +#include "en-enum-datapaths.h"
> +#include "lib/ovn-ic-sb-idl.h"
> #include "lib/inc-proc-eng.h"
> #include "lib/ovn-util.h"
> #include "lib/stopwatch-names.h"
> @@ -152,18 +154,26 @@ enum engine_node_state
> en_ic_run(struct engine_node *node, void *data)
> {
> const struct engine_context *eng_ctx = engine_get_context();
> -
> + struct ic_data *ic_data = data;
> struct ic_input input_data;
>
> - ic_destroy(data);
> - ic_init(data);
> + struct ed_type_enum_datapaths *dp_node_data =
> + engine_get_input_data("enum_datapaths", node);
> +
> + if (!dp_node_data) {
> + return EN_UNCHANGED;
> + }
The NULL check above is unnecessary. The enum_datapaths node always
returns EN_UPDATED as its status, so the dp_node_data will always be
non-NULL.
> +
> + ic_data->dp_tnlids = &dp_node_data->dp_tnlids;
> + ic_data->isb_ts_dps = &dp_node_data->isb_ts_dps;
> + ic_data->isb_tr_dps = &dp_node_data->isb_tr_dps;
>
> ic_get_input_data(node, &input_data);
> input_data.runned_az = eng_ctx->client_ctx;
>
> COVERAGE_INC(ic_run);
> stopwatch_start(IC_OVN_DB_RUN_STOPWATCH_NAME, time_msec());
> - ovn_db_run(&input_data, data, (struct engine_context *) eng_ctx);
> + ovn_db_run(&input_data, ic_data, (struct engine_context *) eng_ctx);
> stopwatch_stop(IC_OVN_DB_RUN_STOPWATCH_NAME, time_msec());
> return EN_UPDATED;
> }
> @@ -186,17 +196,14 @@ en_ic_cleanup(void *data)
> }
>
> void
> -ic_destroy(struct ic_data *data)
> +ic_destroy(struct ic_data *data OVS_UNUSED)
> {
> - ovn_destroy_tnlids(&data->dp_tnlids);
> - shash_destroy(&data->isb_ts_dps);
> - shash_destroy(&data->isb_tr_dps);
> }
>
> void
> ic_init(struct ic_data *data)
> {
> - hmap_init(&data->dp_tnlids);
> - shash_init(&data->isb_ts_dps);
> - shash_init(&data->isb_tr_dps);
> + data->dp_tnlids = NULL;
> + data->isb_ts_dps = NULL;
> + data->isb_tr_dps = NULL;
> }
> diff --git a/ic/inc-proc-ic.c b/ic/inc-proc-ic.c
> index 0160c3a3e..d7d247e7a 100644
> --- a/ic/inc-proc-ic.c
> +++ b/ic/inc-proc-ic.c
> @@ -27,6 +27,7 @@
> #include "openvswitch/vlog.h"
> #include "inc-proc-ic.h"
> #include "en-ic.h"
> +#include "en-enum-datapaths.h"
> #include "unixctl.h"
> #include "util.h"
>
> @@ -158,6 +159,7 @@ VLOG_DEFINE_THIS_MODULE(inc_proc_ic);
> /* Define engine nodes for other nodes. They should be defined as static to
> * avoid sparse errors. */
> static ENGINE_NODE(ic, SB_WRITE);
> +static ENGINE_NODE(enum_datapaths);
>
> void
> inc_proc_ic_init(struct ovsdb_idl_loop *nb,
> @@ -167,6 +169,10 @@ inc_proc_ic_init(struct ovsdb_idl_loop *nb,
> {
> /* Define relationships between nodes where first argument is dependent
> * on the second argument */
> + engine_add_input(&en_enum_datapaths, &en_icnb_transit_switch, NULL);
> + engine_add_input(&en_enum_datapaths, &en_icsb_datapath_binding, NULL);
> +
> + engine_add_input(&en_ic, &en_enum_datapaths, NULL);
> engine_add_input(&en_ic, &en_nb_nb_global, NULL);
> engine_add_input(&en_ic, &en_nb_logical_router_static_route, NULL);
> engine_add_input(&en_ic, &en_nb_logical_router, NULL);
> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
> index 8327054de..724201616 100644
> --- a/ic/ovn-ic.c
> +++ b/ic/ovn-ic.c
> @@ -172,16 +172,6 @@ allocate_dp_key(struct hmap *dp_tnlids, bool vxlan_mode,
> const char *name)
> &hint);
> }
>
> -static enum ic_datapath_type
> -ic_dp_get_type(const struct icsbrec_datapath_binding *isb_dp)
> -{
> - if (isb_dp->type && !strcmp(isb_dp->type, "transit-router")) {
> - return IC_ROUTER;
> - }
> -
> - return IC_SWITCH;
> -}
> -
> static enum ic_port_binding_type
> ic_pb_get_type(const struct icsbrec_port_binding *isb_pb)
> {
> @@ -192,28 +182,6 @@ ic_pb_get_type(const struct icsbrec_port_binding *isb_pb)
> return IC_SWITCH_PORT;
> }
>
> -static void
> -enumerate_datapaths(struct ic_input *ic,
> - struct hmap *dp_tnlids,
> - struct shash *isb_ts_dps,
> - struct shash *isb_tr_dps)
> -{
> - const struct icsbrec_datapath_binding *isb_dp;
> - ICSBREC_DATAPATH_BINDING_TABLE_FOR_EACH (isb_dp,
> - ic->icsbrec_datapath_binding_table) {
> - ovn_add_tnlid(dp_tnlids, isb_dp->tunnel_key);
> -
> - enum ic_datapath_type dp_type = ic_dp_get_type(isb_dp);
> - if (dp_type == IC_ROUTER) {
> - char *uuid_str = uuid_to_string(isb_dp->nb_ic_uuid);
> - shash_add(isb_tr_dps, uuid_str, isb_dp);
> - free(uuid_str);
> - } else {
> - shash_add(isb_ts_dps, isb_dp->transit_switch, isb_dp);
> - }
> - }
> -}
> -
> static void
> ts_run(struct engine_context *ctx,
> struct ic_input *ic,
> @@ -275,7 +243,17 @@ ts_run(struct engine_context *ctx,
>
> const struct icsbrec_datapath_binding *isb_dp;
> isb_dp = shash_find_data(isb_ts_dps, ts->name);
> - if (isb_dp) {
> + if (!isb_dp) {
> + const struct icsbrec_datapath_binding *raw;
> + ICSBREC_DATAPATH_BINDING_TABLE_FOR_EACH (raw,
> + ic->icsbrec_datapath_binding_table) {
> + if (raw->transit_switch && !strcmp(raw->transit_switch,
> + ts->name)) {
> + isb_dp = raw;
> + break;
> + }
> + }
I'm having trouble understanding the need for this addition.
enum_datapaths should have filled in isb_ts_dps with all of the
transit switches from the datapath binding table, so I don't
understand how this loop helps.
If this loop does find a transit switch, then the else block below
will not be run. Therefore, the NB DB will not have the requested
tunnel key updated based on the transit switch config.
> + } else {
> int64_t nb_tnl_key = smap_get_int(&ls->other_config,
> "requested-tnl-key",
> 0);
> @@ -309,6 +287,24 @@ ts_run(struct engine_context *ctx,
> ic->icnbrec_transit_switch_table) {
> const struct icsbrec_datapath_binding *isb_dp =
> shash_find_and_delete(isb_ts_dps, ts->name);
> +
> + if (!isb_dp) {
> + const struct icsbrec_datapath_binding *raw_isb;
> + ICSBREC_DATAPATH_BINDING_TABLE_FOR_EACH (raw_isb,
> + ic->icsbrec_datapath_binding_table) {
> + if (raw_isb->n_nb_ic_uuid > 0 &&
> + uuid_equals(&raw_isb->nb_ic_uuid[0],
> + &ts->header_.uuid)) {
> + isb_dp = raw_isb;
> + if (isb_dp->transit_switch) {
> + shash_find_and_delete(isb_ts_dps,
> + isb_dp->transit_switch);
> + }
> + break;
> + }
> + }
> + }
I have the same question here: why would this loop be necessary if the
enum_datapaths node has populated the isb_ts_dps with all transit
switches?
> +
> if (!isb_dp) {
> /* Allocate tunnel key */
> int64_t dp_key = allocate_dp_key(dp_tnlids, vxlan_mode,
> @@ -320,6 +316,9 @@ ts_run(struct engine_context *ctx,
> isb_dp =
> icsbrec_datapath_binding_insert(ctx->ovnisb_idl_txn);
> icsbrec_datapath_binding_set_transit_switch(isb_dp,
> ts->name);
> icsbrec_datapath_binding_set_tunnel_key(isb_dp, dp_key);
> + icsbrec_datapath_binding_set_nb_ic_uuid(isb_dp,
> + &ts->header_.uuid,
> 1);
> + icsbrec_datapath_binding_set_type(isb_dp, "transit-switch");
> } else if (dp_key_refresh) {
> /* Refresh tunnel key since encap mode has changed. */
> int64_t dp_key = allocate_dp_key(dp_tnlids, vxlan_mode,
> @@ -339,9 +338,13 @@ ts_run(struct engine_context *ctx,
> }
> }
>
> - struct shash_node *node;
> - SHASH_FOR_EACH (node, isb_ts_dps) {
> - icsbrec_datapath_binding_delete(node->data);
> + struct shash_node *node, *next;
> + SHASH_FOR_EACH_SAFE (node, next, isb_ts_dps) {
> + struct icsbrec_datapath_binding *isb_dp_to_del = node->data;
> + if (isb_dp_to_del->n_nb_ic_uuid > 0) {
> + icsbrec_datapath_binding_delete(isb_dp_to_del);
> + }
> + shash_delete(isb_ts_dps, node);
> }
> }
> }
> @@ -3114,10 +3117,8 @@ ovn_db_run(struct ic_input *input_data,
> struct engine_context *eng_ctx)
> {
> gateway_run(eng_ctx, input_data);
> - enumerate_datapaths(input_data, &ic_data->dp_tnlids,
> - &ic_data->isb_ts_dps, &ic_data->isb_tr_dps);
> - ts_run(eng_ctx, input_data, &ic_data->dp_tnlids, &ic_data->isb_ts_dps);
> - tr_run(eng_ctx, input_data, &ic_data->dp_tnlids, &ic_data->isb_tr_dps);
> + ts_run(eng_ctx, input_data, ic_data->dp_tnlids, ic_data->isb_ts_dps);
> + tr_run(eng_ctx, input_data, ic_data->dp_tnlids, ic_data->isb_tr_dps);
> port_binding_run(eng_ctx, input_data);
> route_run(eng_ctx, input_data);
> sync_service_monitor(eng_ctx, input_data);
> @@ -3522,6 +3523,7 @@ main(int argc, char *argv[])
> ovn_conn_show, ovnisb_idl_loop.idl);
>
> stopwatch_create(IC_OVN_DB_RUN_STOPWATCH_NAME, SW_MS);
> + stopwatch_create(OVN_IC_ENUM_DATAPATHS_RUN_STOPWATCH_NAME, SW_MS);
>
> /* Initialize incremental processing engine for ovn-northd */
> inc_proc_ic_init(&ovnnb_idl_loop, &ovnsb_idl_loop,
> diff --git a/ic/ovn-ic.h b/ic/ovn-ic.h
> index 2c2efc046..9b0009274 100644
> --- a/ic/ovn-ic.h
> +++ b/ic/ovn-ic.h
> @@ -66,10 +66,10 @@ struct ic_input {
> };
>
> struct ic_data {
> - /* Global state for 'en-ic'. */
> - struct hmap dp_tnlids;
> - struct shash isb_ts_dps;
> - struct shash isb_tr_dps;
> + /* Global state for 'en-enum-datapaths'. */
> + struct hmap *dp_tnlids;
> + struct shash *isb_ts_dps;
> + struct shash *isb_tr_dps;
If at all possible, these three fields should be const. These fields
are created and managed by the enum_datapaths engine node, so any
other engine node should treat this data as read-only.
In this particular case, the ts_run() and tr_run() functions are
specifically not treating the isb_ts_dps and isb_tr_dps as const.
Those functions will remove items from the shash. If this can be
avoided, that would be for the best.
> };
> struct ic_state {
> bool had_lock;
> diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h
> index e933213d8..21572f023 100644
> --- a/lib/stopwatch-names.h
> +++ b/lib/stopwatch-names.h
> @@ -41,5 +41,6 @@
> #define GROUP_ECMP_ROUTE_RUN_STOPWATCH_NAME "group_ecmp_route"
>
> #define IC_OVN_DB_RUN_STOPWATCH_NAME "ovn_db_run"
> +#define OVN_IC_ENUM_DATAPATHS_RUN_STOPWATCH_NAME "enum_datapaths_run"
>
> #endif
> --
> 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
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev