On Wed, Jul 10, 2024 at 11:24 AM Lorenzo Bianconi
<[email protected]> wrote:
>
> Introduce bfd, static_routes and route_policies nodes to northd I-P
> engine to track bfd connections and northd static_route/policy_route
> changes.
>
> Acked-by: Numan Siddique <[email protected]>
> Reported-at: https://issues.redhat.com/browse/FDP-600
> Signed-off-by: Lorenzo Bianconi <[email protected]>
> ---
> Changes since v5:
> - remove bfd_mutex
> Changes since v4:
> - introduce bfd_nb_sync node and ger rid of bfd_consumer routine
> Changes since v3:
> - fix bfd_northd_change_handler logic
> - fix route_policies_northd_change_handler logic
> - fix static_routes_northd_change_handler logic
> - add unit-tests
> - cosmetics
> Changes since v2:
> - add incremental processing routines
> - split bfd_consumer node in static_routes and route_policies nodes
> Changes since v1:
> - add incremental processing logic for bfd_consumer node to avoid a full
> recompute
> ---
> northd/en-lflow.c | 25 +-
> northd/en-northd.c | 215 ++++++++++++++
> northd/en-northd.h | 23 ++
> northd/inc-proc-northd.c | 37 ++-
> northd/northd.c | 592 +++++++++++++++++++++++++++------------
> northd/northd.h | 63 ++++-
> tests/ovn-northd.at | 56 ++++
> 7 files changed, 808 insertions(+), 203 deletions(-)
>
> diff --git a/northd/en-lflow.c b/northd/en-lflow.c
> index c4b927fb8..3dba5034b 100644
> --- a/northd/en-lflow.c
> +++ b/northd/en-lflow.c
> @@ -41,6 +41,11 @@ lflow_get_input_data(struct engine_node *node,
> struct lflow_input *lflow_input)
> {
> struct northd_data *northd_data = engine_get_input_data("northd", node);
> + struct bfd_data *bfd_data = engine_get_input_data("bfd", node);
> + struct static_routes_data *static_routes_data =
> + engine_get_input_data("static_routes", node);
> + struct route_policies_data *route_policies_data =
> + engine_get_input_data("route_policies", node);
> struct port_group_data *pg_data =
> engine_get_input_data("port_group", node);
> struct sync_meters_data *sync_meters_data =
> @@ -50,10 +55,6 @@ lflow_get_input_data(struct engine_node *node,
> struct ed_type_ls_stateful *ls_stateful_data =
> engine_get_input_data("ls_stateful", node);
>
> - lflow_input->nbrec_bfd_table =
> - EN_OVSDB_GET(engine_get_input("NB_bfd", node));
> - lflow_input->sbrec_bfd_table =
> - EN_OVSDB_GET(engine_get_input("SB_bfd", node));
> lflow_input->sbrec_logical_flow_table =
> EN_OVSDB_GET(engine_get_input("SB_logical_flow", node));
> lflow_input->sbrec_multicast_group_table =
> @@ -78,7 +79,10 @@ lflow_get_input_data(struct engine_node *node,
> lflow_input->meter_groups = &sync_meters_data->meter_groups;
> lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map;
> lflow_input->svc_monitor_map = &northd_data->svc_monitor_map;
> - lflow_input->bfd_connections = NULL;
> + lflow_input->bfd_connections = &bfd_data->bfd_connections;
> + lflow_input->parsed_routes = &static_routes_data->parsed_routes;
> + lflow_input->route_tables = &static_routes_data->route_tables;
> + lflow_input->route_policies = &route_policies_data->route_policies;
>
> struct ed_type_global_config *global_config =
> engine_get_input_data("global_config", node);
> @@ -95,25 +99,14 @@ void en_lflow_run(struct engine_node *node, void *data)
> struct lflow_input lflow_input;
> lflow_get_input_data(node, &lflow_input);
>
> - struct hmap bfd_connections = HMAP_INITIALIZER(&bfd_connections);
> - lflow_input.bfd_connections = &bfd_connections;
> -
> stopwatch_start(BUILD_LFLOWS_STOPWATCH_NAME, time_msec());
>
> struct lflow_data *lflow_data = data;
> lflow_table_clear(lflow_data->lflow_table);
> lflow_reset_northd_refs(&lflow_input);
>
> - build_bfd_table(eng_ctx->ovnsb_idl_txn,
> - lflow_input.nbrec_bfd_table,
> - lflow_input.sbrec_bfd_table,
> - lflow_input.lr_ports,
> - &bfd_connections);
> build_lflows(eng_ctx->ovnsb_idl_txn, &lflow_input,
> lflow_data->lflow_table);
> - bfd_cleanup_connections(lflow_input.nbrec_bfd_table,
> - &bfd_connections);
> - hmap_destroy(&bfd_connections);
> stopwatch_stop(BUILD_LFLOWS_STOPWATCH_NAME, time_msec());
>
> engine_set_node_state(node, EN_UPDATED);
> diff --git a/northd/en-northd.c b/northd/en-northd.c
> index 4479b4aff..7595c6f5f 100644
> --- a/northd/en-northd.c
> +++ b/northd/en-northd.c
> @@ -236,6 +236,162 @@ northd_global_config_handler(struct engine_node *node,
> void *data OVS_UNUSED)
> return true;
> }
>
> +bool
> +route_policies_northd_change_handler(struct engine_node *node,
> + void *data OVS_UNUSED)
> +{
> + struct northd_data *northd_data = engine_get_input_data("northd", node);
> + if (!northd_has_tracked_data(&northd_data->trk_data)) {
> + return false;
> + }
> +
> + /* This node uses the below data from the en_northd engine node.
> + * See (lr_stateful_get_input_data())
> + * 1. northd_data->lr_datapaths
> + * This data gets updated when a logical router is created or
> deleted.
> + * northd engine node presently falls back to full recompute when
> + * this happens and so does this node.
> + * Note: When we add I-P to the created/deleted logical routers, we
> + * need to revisit this handler.
> + *
> + * This node also accesses the route policies of the logical router.
> + * When these route policies get updated, en_northd engine
> recomputes
> + * and so does this node.
> + * Note: When we add I-P to handle route policies changes, we need
> + * to revisit this handler.
> + */
> + return true;
> +}
> +
> +void
> +en_route_policies_run(struct engine_node *node, void *data)
> +{
> + struct northd_data *northd_data = engine_get_input_data("northd", node);
> + struct route_policies_data *route_policies_data = data;
> +
> + route_policies_destroy(data);
> + route_policies_init(data);
> +
> + struct ovn_datapath *od;
> + HMAP_FOR_EACH (od, key_node, &northd_data->lr_datapaths.datapaths) {
> + build_route_policies(od, &northd_data->lr_ports,
> + &route_policies_data->route_policies,
> + &route_policies_data->bfd_active_connections);
> + }
> +
> + engine_set_node_state(node, EN_UPDATED);
> +}
> +
> +bool
> +static_routes_northd_change_handler(struct engine_node *node,
> + void *data OVS_UNUSED)
> +{
> + struct northd_data *northd_data = engine_get_input_data("northd", node);
> + if (!northd_has_tracked_data(&northd_data->trk_data)) {
> + return false;
> + }
> +
> + /* This node uses the below data from the en_northd engine node.
> + * See (lr_stateful_get_input_data())
> + * 1. northd_data->lr_datapaths
> + * This data gets updated when a logical router is created or
> deleted.
> + * northd engine node presently falls back to full recompute when
> + * this happens and so does this node.
> + * Note: When we add I-P to the created/deleted logical routers, we
> + * need to revisit this handler.
> + *
> + * This node also accesses the static routes of the logical router.
> + * When these static routes gets updated, en_northd engine
> recomputes
> + * and so does this node.
> + * Note: When we add I-P to handle static routes changes, we need
> + * to revisit this handler.
> + */
> + return true;
> +}
> +
> +void
> +en_static_routes_run(struct engine_node *node, void *data)
> +{
> +
> + struct northd_data *northd_data = engine_get_input_data("northd", node);
> + struct static_routes_data *static_routes_data = data;
> +
> + static_routes_destroy(data);
> + static_routes_init(data);
> +
> + struct ovn_datapath *od;
> + HMAP_FOR_EACH (od, key_node, &northd_data->lr_datapaths.datapaths) {
> + for (int i = 0; i < od->nbr->n_ports; i++) {
> + const char *route_table_name =
> + smap_get(&od->nbr->ports[i]->options, "route_table");
> + get_route_table_id(&static_routes_data->route_tables,
> + route_table_name);
> + }
> +
> + build_parsed_routes(od, &northd_data->lr_ports,
> + &static_routes_data->parsed_routes,
> + &static_routes_data->route_tables,
> + &static_routes_data->bfd_active_connections);
> + }
> +
> + engine_set_node_state(node, EN_UPDATED);
> +}
> +
> +bool
> +bfd_northd_change_handler(struct engine_node *node,
> + void *data OVS_UNUSED)
> +{
> + struct northd_data *northd_data = engine_get_input_data("northd", node);
> + if (!northd_has_tracked_data(&northd_data->trk_data)) {
> + return false;
> + }
> +
> + /* This node uses the below data from the en_northd engine node.
> + * See (lr_stateful_get_input_data())
> + * 1. northd_data->lr_datapaths
This node uses northd_data->lr_ports, not lr_datapaths.
> + * This data gets updated when a logical router is created or
> deleted.
> + * northd engine node presently falls back to full recompute when
> + * this happens and so does this node.
> + * Note: When we add I-P to the created/deleted logical routers, we
> + * need to revisit this handler.
> + */
> + return true;
> +}
> +
> +void
> +en_bfd_run(struct engine_node *node, void *data)
> +{
> + struct northd_data *northd_data = engine_get_input_data("northd", node);
> + struct bfd_data *bfd_data = data;
> + const struct engine_context *eng_ctx = engine_get_context();
> + const struct nbrec_bfd_table *nbrec_bfd_table =
> + EN_OVSDB_GET(engine_get_input("NB_bfd", node));
> + const struct sbrec_bfd_table *sbrec_bfd_table =
> + EN_OVSDB_GET(engine_get_input("SB_bfd", node));
> +
> + bfd_destroy(data);
> + bfd_init(data);
> + build_bfd_table(eng_ctx->ovnsb_idl_txn, nbrec_bfd_table, sbrec_bfd_table,
> + &northd_data->lr_ports, &bfd_data->bfd_connections);
> + engine_set_node_state(node, EN_UPDATED);
> +}
> +
> +void
> +en_bfd_nb_sync_run(struct engine_node *node OVS_UNUSED,
> + void *data OVS_UNUSED)
> +{
> + struct route_policies_data *route_policies_data
> + = engine_get_input_data("route_policies", node);
> + struct static_routes_data *static_routes_data
> + = engine_get_input_data("static_routes", node);
> + const struct nbrec_bfd_table *nbrec_bfd_table =
> + EN_OVSDB_GET(engine_get_input("NB_bfd", node));
> +
> + bfd_connections_cleanup(nbrec_bfd_table,
> + &static_routes_data->bfd_active_connections,
> + &route_policies_data->bfd_active_connections);
> +}
> +
> void
> *en_northd_init(struct engine_node *node OVS_UNUSED,
> struct engine_arg *arg OVS_UNUSED)
> @@ -247,6 +403,42 @@ void
> return data;
> }
>
> +void
> +*en_route_policies_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED)
> +{
> + struct route_policies_data *data = xzalloc(sizeof *data);
> +
> + route_policies_init(data);
> + return data;
> +}
> +
> +void
> +*en_static_routes_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED)
> +{
> + struct static_routes_data *data = xzalloc(sizeof *data);
> +
> + static_routes_init(data);
> + return data;
> +}
> +
> +void
> +*en_bfd_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED)
> +{
> + struct bfd_data *data = xzalloc(sizeof *data);
> +
> + bfd_init(data);
> + return data;
> +}
> +
> +void *en_bfd_nb_sync_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED)
> +{
> + return NULL;
> +}
> +
> void
> en_northd_cleanup(void *data)
> {
> @@ -259,3 +451,26 @@ en_northd_clear_tracked_data(void *data_)
> struct northd_data *data = data_;
> destroy_northd_data_tracked_changes(data);
> }
> +
> +void
> +en_route_policies_cleanup(void *data)
> +{
> + route_policies_destroy(data);
> +}
> +
> +void
> +en_static_routes_cleanup(void *data)
> +{
> + static_routes_destroy(data);
> +}
> +
> +void
> +en_bfd_cleanup(void *data)
> +{
> + bfd_destroy(data);
> +}
> +
> +void
> +en_bfd_nb_sync_cleanup(void *data OVS_UNUSED)
> +{
> +}
> diff --git a/northd/en-northd.h b/northd/en-northd.h
> index 9b7bda32a..53b671331 100644
> --- a/northd/en-northd.h
> +++ b/northd/en-northd.h
> @@ -19,5 +19,28 @@ bool northd_nb_logical_switch_handler(struct engine_node
> *, void *data);
> bool northd_nb_logical_router_handler(struct engine_node *, void *data);
> bool northd_sb_port_binding_handler(struct engine_node *, void *data);
> bool northd_lb_data_handler(struct engine_node *, void *data);
> +void *en_static_routes_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED);
> +void en_route_policies_cleanup(void *data);
> +bool route_policies_northd_change_handler(struct engine_node *node,
> + void *data OVS_UNUSED);
> +void en_route_policies_run(struct engine_node *node, void *data);
> +void *en_route_policies_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED);
> +void en_static_routes_cleanup(void *data);
> +bool static_routes_northd_change_handler(struct engine_node *node,
> + void *data OVS_UNUSED);
> +void en_static_routes_run(struct engine_node *node, void *data);
> +void *en_bfd_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED);
> +void en_bfd_cleanup(void *data);
> +bool bfd_northd_change_handler(struct engine_node *node,
> + void *data OVS_UNUSED);
> +void en_bfd_run(struct engine_node *node, void *data);
> +void *en_bfd_nb_sync_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED);
> +void en_bfd_nb_sync_run(struct engine_node *node OVS_UNUSED,
> + void *data OVS_UNUSED);
> +void en_bfd_nb_sync_cleanup(void *data OVS_UNUSED);
>
> #endif /* EN_NORTHD_H */
> diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> index d56e9783a..9d4d928d1 100644
> --- a/northd/inc-proc-northd.c
> +++ b/northd/inc-proc-northd.c
> @@ -61,7 +61,9 @@ static unixctl_cb_func chassis_features_list;
> NB_NODE(meter, "meter") \
> NB_NODE(bfd, "bfd") \
> NB_NODE(static_mac_binding, "static_mac_binding") \
> - NB_NODE(chassis_template_var, "chassis_template_var")
> + NB_NODE(chassis_template_var, "chassis_template_var") \
> + NB_NODE(logical_router_static_route, "logical_router_static_route") \
> + NB_NODE(logical_router_policy, "logical_router_policy")
>
> enum nb_engine_node {
> #define NB_NODE(NAME, NAME_STR) NB_##NAME,
> @@ -155,6 +157,10 @@ static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data,
> "lb_data");
> static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_nat, "lr_nat");
> static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lr_stateful, "lr_stateful");
> static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(ls_stateful, "ls_stateful");
> +static ENGINE_NODE(route_policies, "route_policies");
> +static ENGINE_NODE(static_routes, "static_routes");
> +static ENGINE_NODE(bfd, "bfd");
> +static ENGINE_NODE(bfd_nb_sync, "bfd_nb_sync");
>
> void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> struct ovsdb_idl_loop *sb)
> @@ -237,18 +243,43 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> engine_add_input(&en_fdb_aging, &en_global_config,
> node_global_config_handler);
>
> + engine_add_input(&en_bfd, &en_nb_bfd, NULL);
> + engine_add_input(&en_bfd, &en_nb_logical_router_policy, NULL);
> + engine_add_input(&en_bfd, &en_nb_logical_router_static_route, NULL);
I don't see any use of en_nb_logical_router_policy and
en_nb_logical_router_static_route data from this node.
> + engine_add_input(&en_bfd, &en_sb_bfd, NULL);
> + engine_add_input(&en_bfd, &en_northd, bfd_northd_change_handler);
> +
> + engine_add_input(&en_route_policies, &en_bfd, NULL);
> + engine_add_input(&en_route_policies, &en_nb_bfd, NULL);
> + engine_add_input(&en_route_policies, &en_nb_logical_router_policy, NULL);
I don't see any use of all the 3 inputs above from this node.
> + engine_add_input(&en_route_policies, &en_northd,
> + route_policies_northd_change_handler);
> +
> + engine_add_input(&en_static_routes, &en_bfd, NULL);
> + engine_add_input(&en_static_routes, &en_nb_bfd, NULL);
> + engine_add_input(&en_static_routes,
> + &en_nb_logical_router_static_route, NULL);
Same as above.
After removing the above mentioned unused inputs, the code still
compiles and all test cases passed. Did I miss anything?
Thanks,
Han
> + engine_add_input(&en_static_routes, &en_northd,
> + static_routes_northd_change_handler);
> +
> + engine_add_input(&en_bfd_nb_sync, &en_nb_bfd, NULL);
> + engine_add_input(&en_bfd_nb_sync, &en_static_routes, NULL);
> + engine_add_input(&en_bfd_nb_sync, &en_route_policies, NULL);
> +
> engine_add_input(&en_sync_meters, &en_nb_acl, NULL);
> engine_add_input(&en_sync_meters, &en_nb_meter, NULL);
> engine_add_input(&en_sync_meters, &en_sb_meter, NULL);
>
> - engine_add_input(&en_lflow, &en_nb_bfd, NULL);
> engine_add_input(&en_lflow, &en_nb_acl, NULL);
> engine_add_input(&en_lflow, &en_sync_meters, NULL);
> - engine_add_input(&en_lflow, &en_sb_bfd, NULL);
> 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_sb_logical_dp_group, NULL);
> + engine_add_input(&en_lflow, &en_bfd, NULL);
> + engine_add_input(&en_lflow, &en_bfd_nb_sync, NULL);
> + engine_add_input(&en_lflow, &en_route_policies, NULL);
> + engine_add_input(&en_lflow, &en_static_routes, NULL);
> engine_add_input(&en_lflow, &en_global_config,
> node_global_config_handler);
> engine_add_input(&en_lflow, &en_northd, lflow_northd_handler);
> diff --git a/northd/northd.c b/northd/northd.c
> index 6898daa00..be6cee5bf 100644
> --- a/northd/northd.c
> +++ b/northd/northd.c
> @@ -9728,9 +9728,33 @@ struct bfd_entry {
>
> const struct sbrec_bfd *sb_bt;
>
> - bool ref;
> + char *logical_port;
> + char *dst_ip;
> + bool stale;
> };
>
> +static struct bfd_entry *
> +bfd_alloc_entry(struct hmap *bfd_connections,
> + const char *logical_port, const char *dst_ip)
> +{
> + struct bfd_entry *bfd_e = xzalloc(sizeof *bfd_e);
> + bfd_e->logical_port = xstrdup(logical_port);
> + bfd_e->dst_ip = xstrdup(dst_ip);
> + uint32_t hash = hash_string(dst_ip, 0);
> + hash = hash_string(logical_port, hash);
> + hmap_insert(bfd_connections, &bfd_e->hmap_node, hash);
> +
> + return bfd_e;
> +}
> +
> +static void
> +bfd_erase_entry(struct bfd_entry *bfd_e)
> +{
> + free(bfd_e->logical_port);
> + free(bfd_e->dst_ip);
> + free(bfd_e);
> +}
> +
> static struct bfd_entry *
> bfd_port_lookup(const struct hmap *bfd_map, const char *logical_port,
> const char *dst_ip)
> @@ -9741,36 +9765,31 @@ bfd_port_lookup(const struct hmap *bfd_map, const
> char *logical_port,
> hash = hash_string(dst_ip, 0);
> hash = hash_string(logical_port, hash);
> HMAP_FOR_EACH_WITH_HASH (bfd_e, hmap_node, hash, bfd_map) {
> - if (!strcmp(bfd_e->sb_bt->logical_port, logical_port) &&
> - !strcmp(bfd_e->sb_bt->dst_ip, dst_ip)) {
> + if (!strcmp(bfd_e->logical_port, logical_port) &&
> + !strcmp(bfd_e->dst_ip, dst_ip)) {
> return bfd_e;
> }
> }
> +
> return NULL;
> }
>
> void
> -bfd_cleanup_connections(const struct nbrec_bfd_table *nbrec_bfd_table,
> - struct hmap *bfd_map)
> +bfd_connections_cleanup(const struct nbrec_bfd_table *nbrec_bfd_table,
> + struct hmap *static_route_bfd_connections,
> + struct hmap *route_policy_bfd_connections)
> {
> const struct nbrec_bfd *nb_bt;
> - struct bfd_entry *bfd_e;
> -
> NBREC_BFD_TABLE_FOR_EACH (nb_bt, nbrec_bfd_table) {
> - bfd_e = bfd_port_lookup(bfd_map, nb_bt->logical_port, nb_bt->dst_ip);
> - if (!bfd_e) {
> - continue;
> - }
> -
> - if (!bfd_e->ref && strcmp(nb_bt->status, "admin_down")) {
> + if (strcmp(nb_bt->status, "admin_down") &&
> + !bfd_port_lookup(static_route_bfd_connections,
> + nb_bt->logical_port, nb_bt->dst_ip) &&
> + !bfd_port_lookup(route_policy_bfd_connections,
> + nb_bt->logical_port, nb_bt->dst_ip)) {
> /* no user for this bfd connection */
> nbrec_bfd_set_status(nb_bt, "admin_down");
> }
> }
> -
> - HMAP_FOR_EACH_POP (bfd_e, hmap_node, bfd_map) {
> - free(bfd_e);
> - }
> }
>
> #define BFD_DEF_MINTX 1000 /* 1s */
> @@ -9839,20 +9858,25 @@ build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn,
> const struct sbrec_bfd_table *sbrec_bfd_table,
> const struct hmap *lr_ports, struct hmap *bfd_connections)
> {
> - struct hmap sb_only = HMAP_INITIALIZER(&sb_only);
> - const struct sbrec_bfd *sb_bt;
> - unsigned long *bfd_src_ports;
> - struct bfd_entry *bfd_e;
> - uint32_t hash;
> + if (!ovnsb_txn) {
> + return;
> + }
>
> - bfd_src_ports = bitmap_allocate(BFD_UDP_SRC_PORT_LEN);
> + unsigned long *bfd_src_ports = bitmap_allocate(BFD_UDP_SRC_PORT_LEN);
> + struct bfd_entry *bfd_e;
>
> + /* align bfd map to sb db */
> + const struct sbrec_bfd *sb_bt;
> SBREC_BFD_TABLE_FOR_EACH (sb_bt, sbrec_bfd_table) {
> - bfd_e = xmalloc(sizeof *bfd_e);
> + bfd_e = bfd_port_lookup(bfd_connections, sb_bt->logical_port,
> + sb_bt->dst_ip);
> + if (!bfd_e) {
> + bfd_e = bfd_alloc_entry(bfd_connections, sb_bt->logical_port,
> + sb_bt->dst_ip);
> + }
> bfd_e->sb_bt = sb_bt;
> - hash = hash_string(sb_bt->dst_ip, 0);
> - hash = hash_string(sb_bt->logical_port, hash);
> - hmap_insert(&sb_only, &bfd_e->hmap_node, hash);
> + bfd_e->stale = true;
> + /* we need to check if this entry is even in the BFD nb db table */
> bitmap_set1(bfd_src_ports, sb_bt->src_port - BFD_UDP_SRC_PORT_START);
> }
>
> @@ -9864,7 +9888,13 @@ build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn,
> }
>
> struct ovn_port *op = ovn_port_find(lr_ports, nb_bt->logical_port);
> - bfd_e = bfd_port_lookup(&sb_only, nb_bt->logical_port,
> nb_bt->dst_ip);
> + if (!op || !op->sb) {
> + /* skip not bounded ports */
> + continue;
> + }
> +
> + bfd_e = bfd_port_lookup(bfd_connections, nb_bt->logical_port,
> + nb_bt->dst_ip);
> if (!bfd_e) {
> int udp_src = bfd_get_unused_port(bfd_src_ports);
> if (udp_src < 0) {
> @@ -9877,7 +9907,7 @@ build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn,
> sbrec_bfd_set_disc(sb_bt, 1 + random_uint32());
> sbrec_bfd_set_src_port(sb_bt, udp_src);
> sbrec_bfd_set_status(sb_bt, nb_bt->status);
> - if (op && op->sb && op->sb->chassis) {
> + if (op->sb->chassis) {
> sbrec_bfd_set_chassis_name(sb_bt, op->sb->chassis->name);
> }
>
> @@ -9888,7 +9918,12 @@ build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn,
> int d_mult = nb_bt->n_detect_mult ? nb_bt->detect_mult[0]
> : BFD_DEF_DETECT_MULT;
> sbrec_bfd_set_detect_mult(sb_bt, d_mult);
> +
> + bfd_e = bfd_alloc_entry(bfd_connections, nb_bt->logical_port,
> + nb_bt->dst_ip);
> + bfd_e->sb_bt = sb_bt;
> } else {
> + bfd_e->stale = false;
> if (strcmp(bfd_e->sb_bt->status, nb_bt->status)) {
> if (!strcmp(nb_bt->status, "admin_down") ||
> !strcmp(bfd_e->sb_bt->status, "admin_down")) {
> @@ -9897,18 +9932,13 @@ build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn,
> nbrec_bfd_set_status(nb_bt, bfd_e->sb_bt->status);
> }
> }
> +
> build_bfd_update_sb_conf(nb_bt, bfd_e->sb_bt);
> - if (op && op->sb && op->sb->chassis &&
> - strcmp(op->sb->chassis->name, bfd_e->sb_bt->chassis_name)) {
> + if (op->sb->chassis &&
> + !strcmp(op->sb->chassis->name, bfd_e->sb_bt->chassis_name)) {
> sbrec_bfd_set_chassis_name(bfd_e->sb_bt,
> op->sb->chassis->name);
> }
> -
> - hmap_remove(&sb_only, &bfd_e->hmap_node);
> - bfd_e->ref = false;
> - hash = hash_string(bfd_e->sb_bt->dst_ip, 0);
> - hash = hash_string(bfd_e->sb_bt->logical_port, hash);
> - hmap_insert(bfd_connections, &bfd_e->hmap_node, hash);
> }
>
> if (op) {
> @@ -9916,16 +9946,20 @@ build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn,
> }
> }
>
> - HMAP_FOR_EACH_POP (bfd_e, hmap_node, &sb_only) {
> - struct ovn_port *op = ovn_port_find(lr_ports,
> - bfd_e->sb_bt->logical_port);
> + HMAP_FOR_EACH_SAFE (bfd_e, hmap_node, bfd_connections) {
> + if (!bfd_e->stale) {
> + continue;
> + }
> +
> + struct ovn_port *op = ovn_port_find(lr_ports, bfd_e->logical_port);
> if (op) {
> op->has_bfd = false;
> }
> +
> + hmap_remove(bfd_connections, &bfd_e->hmap_node);
> sbrec_bfd_delete(bfd_e->sb_bt);
> - free(bfd_e);
> + bfd_erase_entry(bfd_e);
> }
> - hmap_destroy(&sb_only);
>
> bitmap_free(bfd_src_ports);
> }
> @@ -9965,13 +9999,9 @@ get_outport_for_routing_policy_nexthop(struct
> ovn_datapath *od,
> return NULL;
> }
>
> -static struct ovs_mutex bfd_lock = OVS_MUTEX_INITIALIZER;
> -
> -static bool check_bfd_state(
> - const struct nbrec_logical_router_policy *rule,
> - const struct hmap *bfd_connections,
> - struct ovn_port *out_port,
> - const char *nexthop)
> +static bool check_bfd_state(const struct nbrec_logical_router_policy *rule,
> + struct ovn_port *out_port, const char *nexthop,
> + struct hmap *bfd_active_connections)
> {
> struct in6_addr nexthop_v6;
> bool is_nexthop_v6 = ipv6_parse(nexthop, &nexthop_v6);
> @@ -9997,20 +10027,16 @@ static bool check_bfd_state(
> continue;
> }
>
> - struct bfd_entry *bfd_e = bfd_port_lookup(bfd_connections,
> - nb_bt->logical_port,
> - nb_bt->dst_ip);
> - ovs_mutex_lock(&bfd_lock);
> - if (bfd_e) {
> - bfd_e->ref = true;
> - }
> -
> if (!strcmp(nb_bt->status, "admin_down")) {
> nbrec_bfd_set_status(nb_bt, "down");
> }
>
> + if (!bfd_port_lookup(bfd_active_connections, nb_bt->logical_port,
> + nb_bt->dst_ip)) {
> + bfd_alloc_entry(bfd_active_connections, nb_bt->logical_port,
> + nb_bt->dst_ip);
> + }
> ret = strcmp(nb_bt->status, "down");
> - ovs_mutex_unlock(&bfd_lock);
> break;
> }
>
> @@ -10019,20 +10045,22 @@ static bool check_bfd_state(
>
> static void
> build_routing_policy_flow(struct lflow_table *lflows, struct ovn_datapath
> *od,
> - const struct hmap *lr_ports,
> - const struct nbrec_logical_router_policy *rule,
> - const struct hmap *bfd_connections,
> + const struct hmap *lr_ports, struct route_policy
> *rp,
> const struct ovsdb_idl_row *stage_hint,
> struct lflow_ref *lflow_ref)
> {
> + const struct nbrec_logical_router_policy *rule = rp->rule;
> struct ds match = DS_EMPTY_INITIALIZER;
> struct ds actions = DS_EMPTY_INITIALIZER;
>
> if (!strcmp(rule->action, "reroute")) {
> ovs_assert(rule->n_nexthops <= 1);
>
> - char *nexthop =
> - (rule->n_nexthops == 1 ? rule->nexthops[0] : rule->nexthop);
> + if (!rp->n_valid_nexthops) {
> + return;
> + }
> +
> + char *nexthop = rp->valid_nexthops[0];
> struct ovn_port *out_port = get_outport_for_routing_policy_nexthop(
> od, lr_ports, rule->priority, nexthop);
> if (!out_port) {
> @@ -10048,10 +10076,6 @@ build_routing_policy_flow(struct lflow_table
> *lflows, struct ovn_datapath *od,
> return;
> }
>
> - if (!check_bfd_state(rule, bfd_connections, out_port, nexthop)) {
> - return;
> - }
> -
> uint32_t pkt_mark = smap_get_uint(&rule->options, "pkt_mark", 0);
> if (pkt_mark) {
> ds_put_format(&actions, "pkt.mark = %u; ", pkt_mark);
> @@ -10094,19 +10118,18 @@ static void
> build_ecmp_routing_policy_flows(struct lflow_table *lflows,
> struct ovn_datapath *od,
> const struct hmap *lr_ports,
> - const struct nbrec_logical_router_policy
> *rule,
> - const struct hmap *bfd_connections,
> + struct route_policy *rp,
> uint16_t ecmp_group_id,
> struct lflow_ref *lflow_ref)
> {
> - ovs_assert(rule->n_nexthops > 1);
> -
> bool nexthops_is_ipv4 = true;
> + const struct nbrec_logical_router_policy *rule = rp->rule;
> + ovs_assert(rule->n_nexthops > 1);
>
> /* Check that all the nexthops belong to the same addr family before
> * adding logical flows. */
> - for (uint16_t i = 0; i < rule->n_nexthops; i++) {
> - bool is_ipv4 = strchr(rule->nexthops[i], '.') ? true : false;
> + for (uint16_t i = 0; i < rp->n_valid_nexthops; i++) {
> + bool is_ipv4 = strchr(rp->valid_nexthops[i], '.') ? true : false;
>
> if (i == 0) {
> nexthops_is_ipv4 = is_ipv4;
> @@ -10117,7 +10140,7 @@ build_ecmp_routing_policy_flows(struct lflow_table
> *lflows,
> VLOG_WARN_RL(&rl, "nexthop [%s] of the router policy with "
> "the match [%s] do not belong to the same address "
> "family as other next hops",
> - rule->nexthops[i], rule->match);
> + rp->valid_nexthops[i], rule->match);
> return;
> }
> }
> @@ -10125,40 +10148,30 @@ build_ecmp_routing_policy_flows(struct lflow_table
> *lflows,
> struct ds match = DS_EMPTY_INITIALIZER;
> struct ds actions = DS_EMPTY_INITIALIZER;
>
> - size_t *valid_nexthops = xcalloc(rule->n_nexthops, sizeof
> *valid_nexthops);
> - size_t n_valid_nexthops = 0;
> -
> - for (size_t i = 0; i < rule->n_nexthops; i++) {
> + for (size_t i = 0; i < rp->n_valid_nexthops; i++) {
> struct ovn_port *out_port = get_outport_for_routing_policy_nexthop(
> - od, lr_ports, rule->priority, rule->nexthops[i]);
> + od, lr_ports, rule->priority, rp->valid_nexthops[i]);
> if (!out_port) {
> goto cleanup;
> }
>
> const char *lrp_addr_s =
> - find_lrp_member_ip(out_port, rule->nexthops[i]);
> + find_lrp_member_ip(out_port, rp->valid_nexthops[i]);
> if (!lrp_addr_s) {
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> VLOG_WARN_RL(&rl, "lrp_addr not found for routing policy "
> " priority %"PRId64" nexthop %s",
> - rule->priority, rule->nexthops[i]);
> + rule->priority, rp->valid_nexthops[i]);
> goto cleanup;
> }
>
> - if (!check_bfd_state(rule, bfd_connections, out_port,
> - rule->nexthops[i])) {
> - continue;
> - }
> -
> - valid_nexthops[n_valid_nexthops++] = i + 1;
> -
> ds_clear(&actions);
> uint32_t pkt_mark = smap_get_uint(&rule->options, "pkt_mark", 0);
> if (pkt_mark) {
> ds_put_format(&actions, "pkt.mark = %u; ", pkt_mark);
> }
>
> - bool is_ipv4 = strchr(rule->nexthops[i], '.') ? true : false;
> + bool is_ipv4 = strchr(rp->valid_nexthops[i], '.') ? true : false;
>
> ds_put_format(&actions, "%s = %s; "
> "%s = %s; "
> @@ -10167,7 +10180,7 @@ build_ecmp_routing_policy_flows(struct lflow_table
> *lflows,
> "flags.loopback = 1; "
> "next;",
> is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6,
> - rule->nexthops[i],
> + rp->valid_nexthops[i],
> is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6,
> lrp_addr_s,
> out_port->lrp_networks.ea_s,
> @@ -10183,37 +10196,30 @@ build_ecmp_routing_policy_flows(struct lflow_table
> *lflows,
> lflow_ref);
> }
>
> - if (!n_valid_nexthops) {
> - goto cleanup;
> - }
> -
> ds_clear(&actions);
> - if (n_valid_nexthops > 1) {
> + if (rp->n_valid_nexthops > 1) {
> ds_put_format(&actions, "%s = %"PRIu16
> "; %s = select(", REG_ECMP_GROUP_ID, ecmp_group_id,
> REG_ECMP_MEMBER_ID);
>
> - for (size_t i = 0; i < n_valid_nexthops; i++) {
> + for (size_t i = 0; i < rp->n_valid_nexthops; i++) {
> if (i > 0) {
> ds_put_cstr(&actions, ", ");
> }
>
> - ds_put_format(&actions, "%"PRIuSIZE, valid_nexthops[i]);
> + ds_put_format(&actions, "%"PRIuSIZE, i + 1);
> }
> ds_put_cstr(&actions, ");");
> } else {
> ds_put_format(&actions, "%s = %"PRIu16
> - "; %s = %"PRIuSIZE"; next;", REG_ECMP_GROUP_ID,
> - ecmp_group_id, REG_ECMP_MEMBER_ID,
> - valid_nexthops[0]);
> + "; %s = 1; next;", REG_ECMP_GROUP_ID,
> + ecmp_group_id, REG_ECMP_MEMBER_ID);
> }
> ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY,
> rule->priority, rule->match,
> ds_cstr(&actions), &rule->header_,
> lflow_ref);
> -
> cleanup:
> - free(valid_nexthops);
> ds_destroy(&match);
> ds_destroy(&actions);
> }
> @@ -10238,7 +10244,7 @@ route_table_add(struct simap *route_tables, const
> char *route_table_name)
> return rtb_id;
> }
>
> -static uint32_t
> +uint32_t
> get_route_table_id(struct simap *route_tables, const char *route_table_name)
> {
> if (!route_table_name || !route_table_name[0]) {
> @@ -10279,18 +10285,6 @@ build_route_table_lflow(struct ovn_datapath *od,
> struct lflow_table *lflows,
> ds_destroy(&actions);
> }
>
> -struct parsed_route {
> - struct ovs_list list_node;
> - struct in6_addr prefix;
> - unsigned int plen;
> - bool is_src_route;
> - uint32_t route_table_id;
> - uint32_t hash;
> - const struct nbrec_logical_router_static_route *route;
> - bool ecmp_symmetric_reply;
> - bool is_discard_route;
> -};
> -
> static uint32_t
> route_hash(struct parsed_route *route)
> {
> @@ -10305,11 +10299,52 @@ find_static_route_outport(struct ovn_datapath *od,
> const struct hmap *lr_ports,
>
> /* Parse and validate the route. Return the parsed route if successful.
> * Otherwise return NULL. */
> +
> static struct parsed_route *
> +parsed_route_lookup(struct hmap *routes, size_t hash,
> + struct parsed_route *new_pr)
> +{
> + struct parsed_route *pr;
> + HMAP_FOR_EACH_WITH_HASH (pr, key_node, hash, routes) {
> + if (pr->plen != new_pr->plen) {
> + continue;
> + }
> +
> + if (memcmp(&pr->prefix, &new_pr->prefix, sizeof(struct in6_addr))) {
> + continue;
> + }
> +
> + if (pr->is_src_route != new_pr->is_src_route) {
> + continue;
> + }
> +
> + if (pr->route_table_id != new_pr->route_table_id) {
> + continue;
> + }
> +
> + if (pr->route != new_pr->route) {
> + continue;
> + }
> +
> + if (pr->ecmp_symmetric_reply != new_pr->ecmp_symmetric_reply) {
> + continue;
> + }
> +
> + if (pr->is_discard_route != new_pr->is_discard_route) {
> + continue;
> + }
> +
> + return pr;
> + }
> +
> + return NULL;
> +}
> +
> +static void
> parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports,
> - struct ovs_list *routes, struct simap *route_tables,
> + struct hmap *routes, struct simap *route_tables,
> const struct nbrec_logical_router_static_route *route,
> - const struct hmap *bfd_connections)
> + struct hmap *bfd_active_connections)
> {
> /* Verify that the next hop is an IP address with an all-ones mask. */
> struct in6_addr nexthop;
> @@ -10322,7 +10357,7 @@ parsed_routes_add(struct ovn_datapath *od, const
> struct hmap *lr_ports,
> VLOG_WARN_RL(&rl, "bad 'nexthop' %s in static route "
> UUID_FMT, route->nexthop,
> UUID_ARGS(&route->header_.uuid));
> - return NULL;
> + return;
> }
> if ((IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 32) ||
> (!IN6_IS_ADDR_V4MAPPED(&nexthop) && plen != 128)) {
> @@ -10330,7 +10365,7 @@ parsed_routes_add(struct ovn_datapath *od, const
> struct hmap *lr_ports,
> VLOG_WARN_RL(&rl, "bad next hop mask %s in static route "
> UUID_FMT, route->nexthop,
> UUID_ARGS(&route->header_.uuid));
> - return NULL;
> + return;
> }
> }
>
> @@ -10341,7 +10376,7 @@ parsed_routes_add(struct ovn_datapath *od, const
> struct hmap *lr_ports,
> VLOG_WARN_RL(&rl, "bad 'ip_prefix' %s in static route "
> UUID_FMT, route->ip_prefix,
> UUID_ARGS(&route->header_.uuid));
> - return NULL;
> + return;
> }
>
> /* Verify that ip_prefix and nexthop have same address familiy. */
> @@ -10352,7 +10387,7 @@ parsed_routes_add(struct ovn_datapath *od, const
> struct hmap *lr_ports,
> " %s and 'nexthop' %s in static route "UUID_FMT,
> route->ip_prefix, route->nexthop,
> UUID_ARGS(&route->header_.uuid));
> - return NULL;
> + return;
> }
> }
>
> @@ -10361,52 +10396,75 @@ parsed_routes_add(struct ovn_datapath *od, const
> struct hmap *lr_ports,
> !find_static_route_outport(od, lr_ports, route,
> IN6_IS_ADDR_V4MAPPED(&prefix),
> NULL, NULL)) {
> - return NULL;
> + return;
> }
>
> const struct nbrec_bfd *nb_bt = route->bfd;
> if (nb_bt && !strcmp(nb_bt->dst_ip, route->nexthop)) {
> - struct bfd_entry *bfd_e;
> -
> - bfd_e = bfd_port_lookup(bfd_connections, nb_bt->logical_port,
> - nb_bt->dst_ip);
> - ovs_mutex_lock(&bfd_lock);
> - if (bfd_e) {
> - bfd_e->ref = true;
> - }
> -
> if (!strcmp(nb_bt->status, "admin_down")) {
> nbrec_bfd_set_status(nb_bt, "down");
> }
>
> + if (!bfd_port_lookup(bfd_active_connections, nb_bt->logical_port,
> + nb_bt->dst_ip)) {
> + bfd_alloc_entry(bfd_active_connections, nb_bt->logical_port,
> + nb_bt->dst_ip);
> + }
> +
> if (!strcmp(nb_bt->status, "down")) {
> - ovs_mutex_unlock(&bfd_lock);
> - return NULL;
> + return;
> }
> - ovs_mutex_unlock(&bfd_lock);
> }
>
> - struct parsed_route *pr = xzalloc(sizeof *pr);
> - pr->prefix = prefix;
> - pr->plen = plen;
> - pr->route_table_id = get_route_table_id(route_tables,
> route->route_table);
> - pr->is_src_route = (route->policy && !strcmp(route->policy,
> - "src-ip"));
> - pr->hash = route_hash(pr);
> - pr->route = route;
> - pr->ecmp_symmetric_reply = smap_get_bool(&route->options,
> - "ecmp_symmetric_reply", false);
> - pr->is_discard_route = is_discard_route;
> - ovs_list_insert(routes, &pr->list_node);
> - return pr;
> + struct parsed_route *new_pr = xzalloc(sizeof *new_pr);
> + new_pr->prefix = prefix;
> + new_pr->plen = plen;
> + new_pr->route_table_id = get_route_table_id(route_tables,
> + route->route_table);
> + new_pr->is_src_route = (route->policy &&
> + !strcmp(route->policy, "src-ip"));
> + new_pr->hash = route_hash(new_pr);
> + new_pr->route = route;
> + new_pr->nbr = od->nbr;
> + new_pr->ecmp_symmetric_reply = smap_get_bool(&route->options,
> + "ecmp_symmetric_reply",
> + false);
> + new_pr->is_discard_route = is_discard_route;
> +
> + size_t hash = uuid_hash(&od->key);
> + struct parsed_route *pr = parsed_route_lookup(routes, hash, new_pr);
> + if (!pr) {
> + hmap_insert(routes, &new_pr->key_node, hash);
> + } else {
> + pr->stale = false;
> + free(new_pr);
> + }
> }
>
> -static void
> -parsed_routes_destroy(struct ovs_list *routes)
> +void
> +build_parsed_routes(struct ovn_datapath *od, const struct hmap *lr_ports,
> + struct hmap *routes, struct simap *route_tables,
> + struct hmap *bfd_active_connections)
> {
> struct parsed_route *pr;
> - LIST_FOR_EACH_SAFE (pr, list_node, routes) {
> - ovs_list_remove(&pr->list_node);
> + HMAP_FOR_EACH (pr, key_node, routes) {
> + if (pr->nbr == od->nbr) {
> + pr->stale = true;
> + }
> + }
> +
> + for (int i = 0; i < od->nbr->n_static_routes; i++) {
> + parsed_routes_add(od, lr_ports, routes, route_tables,
> + od->nbr->static_routes[i],
> + bfd_active_connections);
> + }
> +
> + HMAP_FOR_EACH_SAFE (pr, key_node, routes) {
> + if (!pr->stale) {
> + continue;
> + }
> +
> + hmap_remove(routes, &pr->key_node);
> free(pr);
> }
> }
> @@ -12719,7 +12777,8 @@ static void
> build_static_route_flows_for_lrouter(
> struct ovn_datapath *od, const struct chassis_features *features,
> struct lflow_table *lflows, const struct hmap *lr_ports,
> - const struct hmap *bfd_connections,
> + struct hmap *parsed_routes,
> + struct simap *route_tables,
> struct lflow_ref *lflow_ref)
> {
> ovs_assert(od->nbr);
> @@ -12733,22 +12792,16 @@ build_static_route_flows_for_lrouter(
>
> struct hmap ecmp_groups = HMAP_INITIALIZER(&ecmp_groups);
> struct hmap unique_routes = HMAP_INITIALIZER(&unique_routes);
> - struct ovs_list parsed_routes = OVS_LIST_INITIALIZER(&parsed_routes);
> - struct simap route_tables = SIMAP_INITIALIZER(&route_tables);
> struct ecmp_groups_node *group;
>
> for (int i = 0; i < od->nbr->n_ports; i++) {
> build_route_table_lflow(od, lflows, od->nbr->ports[i],
> - &route_tables, lflow_ref);
> + route_tables, lflow_ref);
> }
>
> - for (int i = 0; i < od->nbr->n_static_routes; i++) {
> - struct parsed_route *route =
> - parsed_routes_add(od, lr_ports, &parsed_routes, &route_tables,
> - od->nbr->static_routes[i], bfd_connections);
> - if (!route) {
> - continue;
> - }
> + struct parsed_route *route;
> + HMAP_FOR_EACH_WITH_HASH (route, key_node, uuid_hash(&od->key),
> + parsed_routes) {
> group = ecmp_groups_find(&ecmp_groups, route);
> if (group) {
> ecmp_groups_add_route(group, route);
> @@ -12777,8 +12830,6 @@ build_static_route_flows_for_lrouter(
> }
> ecmp_groups_destroy(&ecmp_groups);
> unique_routes_destroy(&unique_routes);
> - parsed_routes_destroy(&parsed_routes);
> - simap_destroy(&route_tables);
> }
>
> /* IP Multicast lookup. Here we set the output port, adjust TTL and
> @@ -12885,6 +12936,113 @@ build_mcast_lookup_flows_for_lrouter(
> }
> }
>
> +static struct route_policy *
> +route_policies_lookup(struct hmap *route_policies, size_t hash,
> + struct route_policy *new_rp)
> +{
> + struct route_policy *rp;
> + HMAP_FOR_EACH_WITH_HASH (rp, key_node, hash, route_policies) {
> + if (rp->rule != new_rp->rule) {
> + continue;
> + }
> +
> + if (rp->n_valid_nexthops != new_rp->n_valid_nexthops) {
> + continue;
> + }
> +
> + size_t i;
> + for (i = 0; i < new_rp->n_valid_nexthops; i++) {
> + size_t j;
> +
> + for (j = 0; j < rp->n_valid_nexthops; j++) {
> + if (!strcmp(new_rp->valid_nexthops[i],
> + rp->valid_nexthops[j])) {
> + break;
> + }
> + }
> +
> + if (j == rp->n_valid_nexthops) {
> + break;
> + }
> + }
> +
> + if (i == new_rp->n_valid_nexthops) {
> + return rp;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +void
> +build_route_policies(struct ovn_datapath *od, struct hmap *lr_ports,
> + struct hmap *route_policies,
> + struct hmap *bfd_active_connections)
> +{
> + struct route_policy *rp;
> +
> + HMAP_FOR_EACH (rp, key_node, route_policies) {
> + if (rp->nbr == od->nbr) {
> + rp->stale = true;
> + }
> + }
> +
> + for (int i = 0; i < od->nbr->n_policies; i++) {
> + const struct nbrec_logical_router_policy *rule =
> od->nbr->policies[i];
> + size_t n_valid_nexthops = 0;
> + char **valid_nexthops = NULL;
> +
> + if (!strcmp(rule->action, "reroute")) {
> + size_t n_nexthops = rule->n_nexthops ? rule->n_nexthops : 1;
> +
> + valid_nexthops = xcalloc(n_nexthops, sizeof *valid_nexthops);
> + for (size_t j = 0; j < n_nexthops; j++) {
> + char *nexthop = rule->n_nexthops
> + ? rule->nexthops[j] : rule->nexthop;
> + struct ovn_port *out_port =
> + get_outport_for_routing_policy_nexthop(
> + od, lr_ports, rule->priority, nexthop);
> + if (!out_port || !check_bfd_state(rule, out_port, nexthop,
> + bfd_active_connections)) {
> + continue;
> + }
> + valid_nexthops[n_valid_nexthops++] = nexthop;
> + }
> +
> + if (!n_valid_nexthops) {
> + free(valid_nexthops);
> + continue;
> + }
> + }
> +
> + struct route_policy *new_rp = xzalloc(sizeof *new_rp);
> + new_rp->rule = rule;
> + new_rp->n_valid_nexthops = n_valid_nexthops;
> + new_rp->valid_nexthops = valid_nexthops;
> + new_rp->nbr = od->nbr;
> +
> + size_t hash = uuid_hash(&od->key);
> + rp = route_policies_lookup(route_policies, hash, new_rp);
> + if (!rp) {
> + hmap_insert(route_policies, &new_rp->key_node, hash);
> + } else {
> + rp->stale = false;
> + free(valid_nexthops);
> + free(new_rp);
> + }
> + }
> +
> + HMAP_FOR_EACH_SAFE (rp, key_node, route_policies) {
> + if (!rp->stale) {
> + continue;
> + }
> +
> + hmap_remove(route_policies, &rp->key_node);
> + free(rp->valid_nexthops);
> + free(rp);
> + }
> +}
> +
> /* Logical router ingress table POLICY: Policy.
> *
> * A packet that arrives at this table is an IP packet that should be
> @@ -12898,7 +13056,7 @@ static void
> build_ingress_policy_flows_for_lrouter(
> struct ovn_datapath *od, struct lflow_table *lflows,
> const struct hmap *lr_ports,
> - const struct hmap *bfd_connections,
> + struct hmap *route_policies,
> struct lflow_ref *lflow_ref)
> {
> ovs_assert(od->nbr);
> @@ -12915,21 +13073,20 @@ build_ingress_policy_flows_for_lrouter(
>
> /* Convert routing policies to flows. */
> uint16_t ecmp_group_id = 1;
> - for (int i = 0; i < od->nbr->n_policies; i++) {
> - const struct nbrec_logical_router_policy *rule
> - = od->nbr->policies[i];
> + struct route_policy *rp;
> + HMAP_FOR_EACH_WITH_HASH (rp, key_node, uuid_hash(&od->key),
> + route_policies) {
> + const struct nbrec_logical_router_policy *rule = rp->rule;
> bool is_ecmp_reroute =
> (!strcmp(rule->action, "reroute") && rule->n_nexthops > 1);
>
> if (is_ecmp_reroute) {
> - build_ecmp_routing_policy_flows(lflows, od, lr_ports, rule,
> - bfd_connections, ecmp_group_id,
> - lflow_ref);
> + build_ecmp_routing_policy_flows(lflows, od, lr_ports, rp,
> + ecmp_group_id, lflow_ref);
> ecmp_group_id++;
> } else {
> - build_routing_policy_flow(lflows, od, lr_ports, rule,
> - bfd_connections, &rule->header_,
> - lflow_ref);
> + build_routing_policy_flow(lflows, od, lr_ports, rp,
> + &rule->header_, lflow_ref);
> }
> }
> }
> @@ -15864,6 +16021,9 @@ struct lswitch_flow_build_info {
> struct ds actions;
> size_t thread_lflow_counter;
> const char *svc_monitor_mac;
> + struct hmap *parsed_routes;
> + struct hmap *route_policies;
> + struct simap *route_tables;
> };
>
> /* Helper function to combine all lflow generation which is iterated by
> @@ -15910,12 +16070,13 @@ build_lswitch_and_lrouter_iterate_by_lr(struct
> ovn_datapath *od,
> build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows, NULL);
> build_static_route_flows_for_lrouter(od, lsi->features,
> lsi->lflows, lsi->lr_ports,
> - lsi->bfd_connections,
> + lsi->parsed_routes,
> + lsi->route_tables,
> NULL);
> build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match,
> &lsi->actions, NULL);
> build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports,
> - lsi->bfd_connections, NULL);
> + lsi->route_policies, NULL);
> build_arp_resolve_flows_for_lrouter(od, lsi->lflows, NULL);
> build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports,
> &lsi->match, &lsi->actions,
> @@ -16231,7 +16392,10 @@ build_lswitch_and_lrouter_flows(
> const struct hmap *svc_monitor_map,
> const struct hmap *bfd_connections,
> const struct chassis_features *features,
> - const char *svc_monitor_mac)
> + const char *svc_monitor_mac,
> + struct hmap *parsed_routes,
> + struct hmap *route_policies,
> + struct simap *route_tables)
> {
>
> char *svc_check_match = xasprintf("eth.dst == %s", svc_monitor_mac);
> @@ -16265,6 +16429,9 @@ build_lswitch_and_lrouter_flows(
> lsiv[index].svc_check_match = svc_check_match;
> lsiv[index].thread_lflow_counter = 0;
> lsiv[index].svc_monitor_mac = svc_monitor_mac;
> + lsiv[index].parsed_routes = parsed_routes;
> + lsiv[index].route_tables = route_tables;
> + lsiv[index].route_policies = route_policies;
> ds_init(&lsiv[index].match);
> ds_init(&lsiv[index].actions);
>
> @@ -16305,6 +16472,9 @@ build_lswitch_and_lrouter_flows(
> .features = features,
> .svc_check_match = svc_check_match,
> .svc_monitor_mac = svc_monitor_mac,
> + .parsed_routes = parsed_routes,
> + .route_tables = route_tables,
> + .route_policies = route_policies,
> .match = DS_EMPTY_INITIALIZER,
> .actions = DS_EMPTY_INITIALIZER,
> };
> @@ -16466,7 +16636,10 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn,
> input_data->svc_monitor_map,
> input_data->bfd_connections,
> input_data->features,
> - input_data->svc_monitor_mac);
> + input_data->svc_monitor_mac,
> + input_data->parsed_routes,
> + input_data->route_policies,
> + input_data->route_tables);
>
> if (parallelization_state == STATE_INIT_HASH_SIZES) {
> parallelization_state = STATE_USE_PARALLELIZATION;
> @@ -17542,6 +17715,27 @@ northd_init(struct northd_data *data)
> init_northd_tracked_data(data);
> }
>
> +void
> +route_policies_init(struct route_policies_data *data)
> +{
> + hmap_init(&data->route_policies);
> + hmap_init(&data->bfd_active_connections);
> +}
> +
> +void
> +static_routes_init(struct static_routes_data *data)
> +{
> + hmap_init(&data->parsed_routes);
> + simap_init(&data->route_tables);
> + hmap_init(&data->bfd_active_connections);
> +}
> +
> +void
> +bfd_init(struct bfd_data *data)
> +{
> + hmap_init(&data->bfd_connections);
> +}
> +
> void
> northd_destroy(struct northd_data *data)
> {
> @@ -17581,6 +17775,48 @@ northd_destroy(struct northd_data *data)
> destroy_northd_tracked_data(data);
> }
>
> +static void
> +__bfd_destroy(struct hmap *bfd_connections)
> +{
> + struct bfd_entry *bfd_e;
> +
> + HMAP_FOR_EACH_POP (bfd_e, hmap_node, bfd_connections) {
> + bfd_erase_entry(bfd_e);
> + }
> + hmap_destroy(bfd_connections);
> +}
> +
> +void
> +bfd_destroy(struct bfd_data *data)
> +{
> + __bfd_destroy(&data->bfd_connections);
> +}
> +
> +void
> +route_policies_destroy(struct route_policies_data *data)
> +{
> + struct route_policy *rp;
> + HMAP_FOR_EACH_POP (rp, key_node, &data->route_policies) {
> + free(rp->valid_nexthops);
> + free(rp);
> + };
> + hmap_destroy(&data->route_policies);
> + __bfd_destroy(&data->bfd_active_connections);
> +}
> +
> +void
> +static_routes_destroy(struct static_routes_data *data)
> +{
> + struct parsed_route *r;
> + HMAP_FOR_EACH_POP (r, key_node, &data->parsed_routes) {
> + free(r);
> + }
> + hmap_destroy(&data->parsed_routes);
> +
> + simap_destroy(&data->route_tables);
> + __bfd_destroy(&data->bfd_active_connections);
> +}
> +
> void
> ovnnb_db_run(struct northd_input *input_data,
> struct northd_data *data,
> diff --git a/northd/northd.h b/northd/northd.h
> index d4a8d75ab..6eb529589 100644
> --- a/northd/northd.h
> +++ b/northd/northd.h
> @@ -23,6 +23,7 @@
> #include "northd/en-port-group.h"
> #include "northd/ipam.h"
> #include "openvswitch/hmap.h"
> +#include "simap.h"
> #include "ovs-thread.h"
>
> struct northd_input {
> @@ -160,14 +161,34 @@ struct northd_data {
> struct northd_tracked_data trk_data;
> };
>
> +struct route_policy {
> + struct hmap_node key_node;
> + const struct nbrec_logical_router_policy *rule;
> + size_t n_valid_nexthops;
> + char **valid_nexthops;
> + const struct nbrec_logical_router *nbr;
> + bool stale;
> +};
> +
> +struct static_routes_data {
> + struct hmap parsed_routes;
> + struct simap route_tables;
> + struct hmap bfd_active_connections;
> +};
> +
> +struct route_policies_data {
> + struct hmap route_policies;
> + struct hmap bfd_active_connections;
> +};
> +
> +struct bfd_data {
> + struct hmap bfd_connections;
> +};
> +
> struct lr_nat_table;
>
> struct lflow_input {
> - /* Northbound table references */
> - const struct nbrec_bfd_table *nbrec_bfd_table;
> -
> /* Southbound table references */
> - const struct sbrec_bfd_table *sbrec_bfd_table;
> const struct sbrec_logical_flow_table *sbrec_logical_flow_table;
> const struct sbrec_multicast_group_table *sbrec_multicast_group_table;
> const struct sbrec_igmp_group_table *sbrec_igmp_group_table;
> @@ -190,6 +211,9 @@ struct lflow_input {
> const struct hmap *svc_monitor_map;
> bool ovn_internal_version_changed;
> const char *svc_monitor_mac;
> + struct hmap *parsed_routes;
> + struct hmap *route_policies;
> + struct simap *route_tables;
> };
>
> extern int parallelization_state;
> @@ -653,6 +677,20 @@ struct ovn_port {
> struct lflow_ref *stateful_lflow_ref;
> };
>
> +struct parsed_route {
> + struct hmap_node key_node;
> + struct in6_addr prefix;
> + unsigned int plen;
> + bool is_src_route;
> + uint32_t route_table_id;
> + uint32_t hash;
> + const struct nbrec_logical_router_static_route *route;
> + bool ecmp_symmetric_reply;
> + bool is_discard_route;
> + const struct nbrec_logical_router *nbr;
> + bool stale;
> +};
> +
> void ovnnb_db_run(struct northd_input *input_data,
> struct northd_data *data,
> struct ovsdb_idl_txn *ovnnb_txn,
> @@ -674,6 +712,17 @@ void northd_init(struct northd_data *data);
> void northd_indices_create(struct northd_data *data,
> struct ovsdb_idl *ovnsb_idl);
>
> +void route_policies_init(struct route_policies_data *);
> +void route_policies_destroy(struct route_policies_data *);
> +void build_parsed_routes(struct ovn_datapath *, const struct hmap *,
> + struct hmap *, struct simap *, struct hmap *);
> +uint32_t get_route_table_id(struct simap *, const char *);
> +void static_routes_init(struct static_routes_data *);
> +void static_routes_destroy(struct static_routes_data *);
> +
> +void bfd_init(struct bfd_data *);
> +void bfd_destroy(struct bfd_data *);
> +
> struct lflow_table;
> struct lr_stateful_tracked_data;
> struct ls_stateful_tracked_data;
> @@ -711,13 +760,15 @@ bool northd_handle_lb_data_changes(struct
> tracked_lb_data *,
> struct hmap *lbgrp_datapaths_map,
> struct northd_tracked_data *);
>
> +void build_route_policies(struct ovn_datapath *, struct hmap *, struct hmap
> *,
> + struct hmap *);
> +void bfd_connections_cleanup(const struct nbrec_bfd_table *, struct hmap *,
> + struct hmap *);
> void build_bfd_table(struct ovsdb_idl_txn *ovnsb_txn,
> const struct nbrec_bfd_table *,
> const struct sbrec_bfd_table *,
> const struct hmap *lr_ports,
> struct hmap *bfd_connections);
> -void bfd_cleanup_connections(const struct nbrec_bfd_table *,
> - struct hmap *bfd_map);
> void run_update_worker_pool(int n_threads);
>
> const struct ovn_datapath *northd_get_datapath_for_port(
> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> index a389d1988..a84fb6fab 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 list bfd >> $1
> ovn-sbctl dump-flows > lflows_$1
> ])
>
> @@ -3858,6 +3859,7 @@ for i in $(seq 1 9); do
> check ovn-nbctl --wait=sb lsp-set-addresses sw$i-r0 00:00:00:00:00:0$i
> done
>
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> uuid=$(ovn-nbctl create bfd logical_port=r0-sw1 dst_ip=192.168.1.2
> status=down min_tx=250 min_rx=250 detect_mult=10)
> ovn-nbctl create bfd logical_port=r0-sw2 dst_ip=192.168.2.2 status=down
> min_tx=500 min_rx=500 detect_mult=20
> ovn-nbctl create bfd logical_port=r0-sw3 dst_ip=192.168.3.2 status=down
> @@ -3870,6 +3872,13 @@ wait_row_count bfd 1 logical_port=r0-sw2
> detect_mult=20 dst_ip=192.168.2.2 \
> wait_row_count bfd 1 logical_port=r0-sw3 detect_mult=5 dst_ip=192.168.3.2 \
> min_rx=1000 min_tx=1000 status=admin_down
>
> +check_engine_stats northd norecompute nocompute
> +check_engine_stats bfd recompute nocompute
> +check_engine_stats lflow recompute nocompute
> +check_engine_stats northd_output norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +
> uuid=$(fetch_column nb:bfd _uuid logical_port=r0-sw1)
> check ovn-nbctl set bfd $uuid min_tx=1000 min_rx=1000 detect_mult=100
>
> @@ -3878,10 +3887,25 @@ check ovn-nbctl clear bfd $uuid_2 min_rx
> wait_row_count bfd 1 logical_port=r0-sw2 min_rx=1000
> wait_row_count bfd 1 logical_port=r0-sw1 min_rx=1000 min_tx=1000
> detect_mult=100
>
> +check_engine_stats northd norecompute nocompute
> +check_engine_stats bfd recompute nocompute
> +check_engine_stats lflow recompute nocompute
> +check_engine_stats northd_output norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +
> check ovn-nbctl --bfd=$uuid lr-route-add r0 100.0.0.0/8 192.168.1.2
> wait_column down bfd status logical_port=r0-sw1
> AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.1.2 | grep -q bfd],[0])
>
> +check_engine_stats northd recompute nocompute
> +check_engine_stats bfd recompute nocompute
> +check_engine_stats static_routes recompute nocompute
> +check_engine_stats lflow recompute nocompute
> +check_engine_stats northd_output norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +
> check ovn-nbctl --bfd lr-route-add r0 200.0.0.0/8 192.168.2.2
> wait_column down bfd status logical_port=r0-sw2
> AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.2.2 | grep -q bfd],[0])
> @@ -3890,10 +3914,26 @@ check ovn-nbctl --bfd lr-route-add r0 240.0.0.0/8
> 192.168.5.2 r0-sw5
> wait_column down bfd status logical_port=r0-sw5
> AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.5.2 | grep -q bfd],[0])
>
> +check_engine_stats northd recompute nocompute
> +check_engine_stats bfd recompute nocompute
> +check_engine_stats static_routes recompute nocompute
> +check_engine_stats lflow recompute nocompute
> +check_engine_stats northd_output norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +
> check ovn-nbctl --bfd --policy=src-ip lr-route-add r0 192.168.6.1/32
> 192.168.10.10 r0-sw6
> wait_column down bfd status logical_port=r0-sw6
> AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.6.1 | grep -q bfd],[0])
>
> +check_engine_stats northd recompute nocompute
> +check_engine_stats bfd recompute nocompute
> +check_engine_stats route_policies recompute nocompute
> +check_engine_stats lflow recompute nocompute
> +check_engine_stats northd_output norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +
> check ovn-nbctl --bfd --policy=src-ip lr-route-add r0 192.168.7.1/32
> 192.168.10.10 r0-sw7
> wait_column down bfd status logical_port=r0-sw7
> AT_CHECK([ovn-nbctl lr-route-list r0 | grep 192.168.7.1 | grep -q bfd],[0])
> @@ -3921,6 +3961,14 @@ wait_column down bfd status logical_port=r0-sw8
> bfd_route_policy_uuid=$(fetch_column nb:bfd _uuid logical_port=r0-sw8)
> AT_CHECK([ovn-nbctl list logical_router_policy | grep -q
> $bfd_route_policy_uuid])
>
> +check_engine_stats northd recompute nocompute
> +check_engine_stats bfd recompute nocompute
> +check_engine_stats static_routes recompute nocompute
> +check_engine_stats lflow recompute nocompute
> +check_engine_stats northd_output norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +
> check ovn-nbctl lr-policy-del r0
> check ovn-nbctl --bfd lr-policy-add r0 100 "ip4.src == 2.3.4.0/24" reroute
> 192.168.9.2,192.168.9.3,192.168.9.4
>
> @@ -3928,6 +3976,14 @@ wait_column down bfd status dst_ip=192.168.9.2
> wait_column down bfd status dst_ip=192.168.9.3
> wait_column down bfd status dst_ip=192.168.9.4
>
> +check_engine_stats northd recompute nocompute
> +check_engine_stats bfd recompute nocompute
> +check_engine_stats route_policies recompute nocompute
> +check_engine_stats lflow recompute nocompute
> +check_engine_stats northd_output norecompute compute
> +CHECK_NO_CHANGE_AFTER_RECOMPUTE
> +check as northd ovn-appctl -t ovn-northd inc-engine/clear-stats
> +
> bfd_route_policy_uuid=$(fetch_column nb:bfd _uuid logical_port=r0-sw9)
> AT_CHECK([ovn-nbctl list logical_router_policy | sed s/,//g | grep -q
> "$bfd_route_policy_uuid"])
>
> --
> 2.45.2
>
> _______________________________________________
> 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