In order to support incremental processing of route changes we need to extract the ecmp grouping to before the actual lflow generation.
Signed-off-by: Felix Huettner <[email protected]> --- lib/stopwatch-names.h | 1 + northd/automake.mk | 2 + northd/en-group-ecmp-route.c | 289 +++++++++++++++++++++++++++++++++ northd/en-group-ecmp-route.h | 79 +++++++++ northd/en-learned-route-sync.c | 11 -- northd/en-lflow.c | 6 +- northd/inc-proc-northd.c | 8 +- northd/northd.c | 209 ++---------------------- northd/northd.h | 2 +- tests/ovn-northd.at | 19 +++ 10 files changed, 416 insertions(+), 210 deletions(-) create mode 100644 northd/en-group-ecmp-route.c create mode 100644 northd/en-group-ecmp-route.h diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h index 13aa5e7bf..f3a931c40 100644 --- a/lib/stopwatch-names.h +++ b/lib/stopwatch-names.h @@ -37,5 +37,6 @@ #define ADVERTISED_ROUTE_SYNC_RUN_STOPWATCH_NAME "advertised_route_sync" #define LEARNED_ROUTE_SYNC_RUN_STOPWATCH_NAME "learned_route_sync" #define DYNAMIC_ROUTES_RUN_STOPWATCH_NAME "dynamic_routes" +#define GROUP_ECMP_ROUTE_RUN_STOPWATCH_NAME "group_ecmp_route" #endif diff --git a/northd/automake.mk b/northd/automake.mk index c5772e03c..9a7165529 100644 --- a/northd/automake.mk +++ b/northd/automake.mk @@ -44,6 +44,8 @@ northd_ovn_northd_SOURCES = \ northd/en-advertised-route-sync.h \ northd/en-learned-route-sync.c \ northd/en-learned-route-sync.h \ + northd/en-group-ecmp-route.c \ + northd/en-group-ecmp-route.h \ northd/inc-proc-northd.c \ northd/inc-proc-northd.h \ northd/ipam.c \ diff --git a/northd/en-group-ecmp-route.c b/northd/en-group-ecmp-route.c new file mode 100644 index 000000000..e8a882004 --- /dev/null +++ b/northd/en-group-ecmp-route.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2025, STACKIT GmbH & Co. KG + * + * 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 <stdbool.h> + +#include "openvswitch/vlog.h" +#include "stopwatch.h" +#include "northd.h" + +#include "en-group-ecmp-route.h" +#include "en-learned-route-sync.h" +#include "lib/stopwatch-names.h" +#include "openvswitch/hmap.h" + +VLOG_DEFINE_THIS_MODULE(en_group_ecmp_route); + +static void +ecmp_groups_destroy(struct hmap *ecmp_groups) +{ + struct ecmp_groups_node *eg; + HMAP_FOR_EACH_SAFE (eg, hmap_node, ecmp_groups) { + struct ecmp_route_list_node *er; + LIST_FOR_EACH_SAFE (er, list_node, &eg->route_list) { + ovs_list_remove(&er->list_node); + free(er); + } + hmap_remove(ecmp_groups, &eg->hmap_node); + sset_destroy(&eg->selection_fields); + free(eg); + } + hmap_destroy(ecmp_groups); +} + +static void +unique_routes_destroy(struct hmap *unique_routes) +{ + struct unique_routes_node *ur; + HMAP_FOR_EACH_SAFE (ur, hmap_node, unique_routes) { + hmap_remove(unique_routes, &ur->hmap_node); + free(ur); + } + hmap_destroy(unique_routes); +} + +static void +group_ecmp_route_clear(struct group_ecmp_route_data *data) +{ + struct group_ecmp_route_node *n; + HMAP_FOR_EACH_POP (n, hmap_node, &data->routes) { + unique_routes_destroy(&n->unique_routes); + ecmp_groups_destroy(&n->ecmp_groups); + free(n); + } +} + +static void +group_ecmp_route_init(struct group_ecmp_route_data *data) +{ + hmap_init(&data->routes); +} + +void *en_group_ecmp_route_init(struct engine_node *node OVS_UNUSED, + struct engine_arg *arg OVS_UNUSED) +{ + struct group_ecmp_route_data *data = xmalloc(sizeof *data); + group_ecmp_route_init(data); + return data; +} + +void en_group_ecmp_route_cleanup(void *_data) +{ + struct group_ecmp_route_data *data = _data; + group_ecmp_route_clear(data); + hmap_destroy(&data->routes); +} + +void +en_group_ecmp_route_clear_tracked_data(void *data OVS_UNUSED) +{ +} + +struct group_ecmp_route_node * +group_ecmp_route_lookup(const struct group_ecmp_route_data *data, + const struct ovn_datapath *od) +{ + struct group_ecmp_route_node *n; + size_t hash = uuid_hash(&od->key); + HMAP_FOR_EACH_WITH_HASH (n, hmap_node, hash, &data->routes) { + if (n->od == od) { + return n; + } + } + return NULL; +} + +static struct group_ecmp_route_node * +group_ecmp_route_add(struct group_ecmp_route_data *data, + const struct ovn_datapath *od) +{ + struct group_ecmp_route_node *n = group_ecmp_route_lookup(data, od); + if (n) { + return n; + } + + size_t hash = uuid_hash(&od->key); + n = xmalloc(sizeof *n); + n->od = od; + hmap_init(&n->ecmp_groups); + hmap_init(&n->unique_routes); + hmap_insert(&data->routes, &n->hmap_node, hash); + return n; +} + +static void +unique_routes_add(struct group_ecmp_route_node *gn, + const struct parsed_route *route) +{ + struct unique_routes_node *ur = xmalloc(sizeof *ur); + ur->route = route; + hmap_insert(&gn->unique_routes, &ur->hmap_node, route->hash); +} + +/* Remove the unique_routes_node from the group, and return the parsed_route + * pointed by the removed node. */ +static const struct parsed_route * +unique_routes_remove(struct group_ecmp_route_node *gn, + const struct parsed_route *route) +{ + struct unique_routes_node *ur; + HMAP_FOR_EACH_WITH_HASH (ur, hmap_node, route->hash, &gn->unique_routes) { + if (ipv6_addr_equals(&route->prefix, &ur->route->prefix) && + route->plen == ur->route->plen && + route->is_src_route == ur->route->is_src_route && + route->source == ur->route->source && + route->route_table_id == ur->route->route_table_id) { + hmap_remove(&gn->unique_routes, &ur->hmap_node); + const struct parsed_route *existed_route = ur->route; + free(ur); + return existed_route; + } + } + return NULL; +} + +static void +ecmp_groups_add_route(struct ecmp_groups_node *group, + const struct parsed_route *route) +{ + if (group->route_count == UINT16_MAX) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "too many routes in a single ecmp group."); + return; + } + + struct ecmp_route_list_node *er = xmalloc(sizeof *er); + er->route = route; + er->id = ++group->route_count; + + if (group->route_count == 1) { + sset_clone(&group->selection_fields, &route->ecmp_selection_fields); + } else { + sset_intersect(&group->selection_fields, + &route->ecmp_selection_fields); + } + + ovs_list_insert(&group->route_list, &er->list_node); +} + +static struct ecmp_groups_node * +ecmp_groups_add(struct group_ecmp_route_node *gn, + const struct parsed_route *route) +{ + if (hmap_count(&gn->ecmp_groups) == UINT16_MAX) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "too many ecmp groups."); + return NULL; + } + + struct ecmp_groups_node *eg = xzalloc(sizeof *eg); + hmap_insert(&gn->ecmp_groups, &eg->hmap_node, route->hash); + + eg->id = hmap_count(&gn->ecmp_groups); + eg->prefix = route->prefix; + eg->plen = route->plen; + eg->is_src_route = route->is_src_route; + eg->source = route->source; + eg->route_table_id = route->route_table_id; + sset_init(&eg->selection_fields); + ovs_list_init(&eg->route_list); + ecmp_groups_add_route(eg, route); + + return eg; +} + +static struct ecmp_groups_node * +ecmp_groups_find(struct group_ecmp_route_node *gn, + const struct parsed_route *route) +{ + struct ecmp_groups_node *eg; + HMAP_FOR_EACH_WITH_HASH (eg, hmap_node, route->hash, &gn->ecmp_groups) { + if (ipv6_addr_equals(&eg->prefix, &route->prefix) && + eg->plen == route->plen && + eg->is_src_route == route->is_src_route && + eg->route_table_id == route->route_table_id && + eg->source == route->source) { + return eg; + } + } + return NULL; +} + +static void +add_route(struct group_ecmp_route_data *data, const struct parsed_route *pr) +{ + struct group_ecmp_route_node *gn = group_ecmp_route_add(data, pr->od); + + if (pr->source == ROUTE_SOURCE_CONNECTED) { + unique_routes_add(gn, pr); + return; + } + + struct ecmp_groups_node *group = ecmp_groups_find(gn, pr); + if (group) { + ecmp_groups_add_route(group, pr); + } else { + const struct parsed_route *existed_route = + unique_routes_remove(gn, pr); + if (existed_route) { + group = ecmp_groups_add(gn, existed_route); + if (group) { + ecmp_groups_add_route(group, pr); + } + } else if (pr->ecmp_symmetric_reply) { + /* Traffic for symmetric reply routes has to be conntracked + * even if there is only one next-hop, in case another next-hop + * is added later. */ + ecmp_groups_add(gn, pr); + } else { + unique_routes_add(gn, pr); + } + } +} + +static void +group_ecmp_route(struct group_ecmp_route_data *data, + const struct routes_data *routes_data, + const struct learned_route_sync_data *learned_route_data) +{ + const struct parsed_route *pr; + HMAP_FOR_EACH (pr, key_node, &routes_data->parsed_routes) { + add_route(data, pr); + } + + HMAP_FOR_EACH (pr, key_node, &learned_route_data->parsed_routes) { + add_route(data, pr); + } +} + +void en_group_ecmp_route_run(struct engine_node *node, void *_data) +{ + struct group_ecmp_route_data *data = _data; + group_ecmp_route_clear(data); + + struct routes_data *routes_data + = engine_get_input_data("routes", node); + struct learned_route_sync_data *learned_route_data + = engine_get_input_data("learned_route_sync", node); + + stopwatch_start(GROUP_ECMP_ROUTE_RUN_STOPWATCH_NAME, time_msec()); + + group_ecmp_route(data, routes_data, learned_route_data); + + stopwatch_stop(GROUP_ECMP_ROUTE_RUN_STOPWATCH_NAME, time_msec()); + engine_set_node_state(node, EN_UPDATED); +} diff --git a/northd/en-group-ecmp-route.h b/northd/en-group-ecmp-route.h new file mode 100644 index 000000000..c84bb11ee --- /dev/null +++ b/northd/en-group-ecmp-route.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, STACKIT GmbH & Co. KG + * + * 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. + */ +#ifndef EN_GROUP_ECMP_ROUTE_H +#define EN_GROUP_ECMP_ROUTE_H 1 + +#include "lib/inc-proc-eng.h" +#include "openvswitch/hmap.h" +#include "openvswitch/list.h" +#include "northd/northd.h" +#include <netinet/in.h> + +struct ecmp_route_list_node { + struct ovs_list list_node; + uint16_t id; /* starts from 1 */ + const struct parsed_route *route; +}; + +struct ecmp_groups_node { + struct hmap_node hmap_node; /* In ecmp_groups */ + uint16_t id; /* starts from 1 */ + struct in6_addr prefix; + unsigned int plen; + bool is_src_route; + enum route_source source; + uint32_t route_table_id; + uint16_t route_count; + struct ovs_list route_list; /* Contains ecmp_route_list_node */ + struct sset selection_fields; +}; + +struct unique_routes_node { + struct hmap_node hmap_node; + const struct parsed_route *route; +}; + +struct group_ecmp_route_node { + struct hmap_node hmap_node; + + /* The datapath for which this node is relevant. */ + const struct ovn_datapath *od; + + /* Contains all routes that are part of an ecmp group. + * Contains struct ecmp_groups_node. */ + struct hmap ecmp_groups; + + /* Contains all routes that are not part of an ecmp group. + * Contains struct unique_routes_node. */ + struct hmap unique_routes; +}; + +struct group_ecmp_route_data { + /* Contains struct group_ecmp_route_node. + * Each entry represents the routes of a single datapath. */ + struct hmap routes; +}; + +void *en_group_ecmp_route_init(struct engine_node *, struct engine_arg *); +void en_group_ecmp_route_cleanup(void *data); +void en_group_ecmp_route_clear_tracked_data(void *data); +void en_group_ecmp_route_run(struct engine_node *, void *data); + +struct group_ecmp_route_node * group_ecmp_route_lookup( + const struct group_ecmp_route_data *data, + const struct ovn_datapath *od); + +#endif /* EN_GROUP_ECMP_ROUTE_H */ diff --git a/northd/en-learned-route-sync.c b/northd/en-learned-route-sync.c index 312141208..ae698a632 100644 --- a/northd/en-learned-route-sync.c +++ b/northd/en-learned-route-sync.c @@ -31,7 +31,6 @@ VLOG_DEFINE_THIS_MODULE(en_learned_route_sync); static void routes_table_sync( const struct sbrec_learned_route_table *sbrec_learned_route_table, - const struct hmap *parsed_routes, const struct hmap *lr_ports, const struct ovn_datapaths *lr_datapaths, struct hmap *parsed_routes_out); @@ -128,8 +127,6 @@ en_learned_route_sync_run(struct engine_node *node, void *data) routes_sync_clear(data); struct learned_route_sync_data *routes_sync_data = data; - struct routes_data *routes_data - = engine_get_input_data("routes", node); const struct sbrec_learned_route_table *sbrec_learned_route_table = EN_OVSDB_GET(engine_get_input("SB_learned_route", node)); struct northd_data *northd_data = engine_get_input_data("northd", node); @@ -137,7 +134,6 @@ en_learned_route_sync_run(struct engine_node *node, void *data) stopwatch_start(LEARNED_ROUTE_SYNC_RUN_STOPWATCH_NAME, time_msec()); routes_table_sync(sbrec_learned_route_table, - &routes_data->parsed_routes, &northd_data->lr_ports, &northd_data->lr_datapaths, &routes_sync_data->parsed_routes); @@ -217,7 +213,6 @@ parse_route_from_sbrec_route(struct hmap *parsed_routes_out, static void routes_table_sync( const struct sbrec_learned_route_table *sbrec_learned_route_table, - const struct hmap *parsed_routes, const struct hmap *lr_ports, const struct ovn_datapaths *lr_datapaths, struct hmap *parsed_routes_out) @@ -234,12 +229,6 @@ routes_table_sync( sb_route); } - - const struct parsed_route *route; - HMAP_FOR_EACH (route, key_node, parsed_routes) { - hmap_insert(parsed_routes_out, &parsed_route_clone(route)->key_node, - parsed_route_hash(route)); - } } static struct parsed_route * diff --git a/northd/en-lflow.c b/northd/en-lflow.c index b79dcf95c..f0117d078 100644 --- a/northd/en-lflow.c +++ b/northd/en-lflow.c @@ -48,8 +48,8 @@ lflow_get_input_data(struct engine_node *node, engine_get_input_data("bfd_sync", node); struct routes_data *routes_data = engine_get_input_data("routes", node); - struct learned_route_sync_data *learned_route_sync_data = - engine_get_input_data("learned_route_sync", node); + struct group_ecmp_route_data *group_ecmp_route_data = + engine_get_input_data("group_ecmp_route", node); struct route_policies_data *route_policies_data = engine_get_input_data("route_policies", node); struct port_group_data *pg_data = @@ -86,7 +86,7 @@ lflow_get_input_data(struct engine_node *node, lflow_input->lb_datapaths_map = &northd_data->lb_datapaths_map; lflow_input->svc_monitor_map = &northd_data->svc_monitor_map; lflow_input->bfd_ports = &bfd_sync_data->bfd_ports; - lflow_input->parsed_routes = &learned_route_sync_data->parsed_routes; + lflow_input->route_data = group_ecmp_route_data; lflow_input->route_tables = &routes_data->route_tables; lflow_input->route_policies = &route_policies_data->route_policies; lflow_input->igmp_groups = &multicat_igmp_data->igmp_groups; diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c index bf0fbc62b..712aebaa1 100644 --- a/northd/inc-proc-northd.c +++ b/northd/inc-proc-northd.c @@ -46,6 +46,7 @@ #include "en-acl-ids.h" #include "en-advertised-route-sync.h" #include "en-learned-route-sync.h" +#include "en-group-ecmp-route.h" #include "unixctl.h" #include "util.h" @@ -177,6 +178,7 @@ static ENGINE_NODE(advertised_route_sync, "advertised_route_sync"); static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(learned_route_sync, "learned_route_sync"); static ENGINE_NODE(dynamic_routes, "dynamic_routes"); +static ENGINE_NODE_WITH_CLEAR_TRACK_DATA(group_ecmp_route, "group_ecmp_route"); void inc_proc_northd_init(struct ovsdb_idl_loop *nb, struct ovsdb_idl_loop *sb) @@ -307,12 +309,14 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, engine_add_input(&en_advertised_route_sync, &en_northd, advertised_route_sync_northd_change_handler); - engine_add_input(&en_learned_route_sync, &en_routes, NULL); engine_add_input(&en_learned_route_sync, &en_sb_learned_route, learned_route_sync_learned_route_change_handler); engine_add_input(&en_learned_route_sync, &en_northd, learned_route_sync_northd_change_handler); + engine_add_input(&en_group_ecmp_route, &en_routes, NULL); + engine_add_input(&en_group_ecmp_route, &en_learned_route_sync, 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); @@ -333,7 +337,7 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, /* XXX: This causes a full lflow recompute on each change to any route. * At least for learned routes we should add incremental processing here. * */ - engine_add_input(&en_lflow, &en_learned_route_sync, NULL); + engine_add_input(&en_lflow, &en_group_ecmp_route, NULL); engine_add_input(&en_lflow, &en_global_config, node_global_config_handler); diff --git a/northd/northd.c b/northd/northd.c index 52bb67c0e..893e4c8fb 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -45,6 +45,7 @@ #include "memory.h" #include "northd.h" #include "en-global-config.h" +#include "en-group-ecmp-route.h" #include "en-lb-data.h" #include "en-lr-nat.h" #include "en-lr-stateful.h" @@ -11538,154 +11539,6 @@ build_lb_parsed_routes(const struct ovn_datapath *od, } } -struct ecmp_route_list_node { - struct ovs_list list_node; - uint16_t id; /* starts from 1 */ - const struct parsed_route *route; -}; - -struct ecmp_groups_node { - struct hmap_node hmap_node; /* In ecmp_groups */ - uint16_t id; /* starts from 1 */ - struct in6_addr prefix; - unsigned int plen; - bool is_src_route; - enum route_source source; - uint32_t route_table_id; - uint16_t route_count; - struct ovs_list route_list; /* Contains ecmp_route_list_node */ - struct sset selection_fields; -}; - -static void -ecmp_groups_add_route(struct ecmp_groups_node *group, - const struct parsed_route *route) -{ - if (group->route_count == UINT16_MAX) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "too many routes in a single ecmp group."); - return; - } - - struct ecmp_route_list_node *er = xmalloc(sizeof *er); - er->route = route; - er->id = ++group->route_count; - - if (group->route_count == 1) { - sset_clone(&group->selection_fields, &route->ecmp_selection_fields); - } else { - sset_intersect(&group->selection_fields, - &route->ecmp_selection_fields); - } - - ovs_list_insert(&group->route_list, &er->list_node); -} - -static struct ecmp_groups_node * -ecmp_groups_add(struct hmap *ecmp_groups, - const struct parsed_route *route) -{ - if (hmap_count(ecmp_groups) == UINT16_MAX) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "too many ecmp groups."); - return NULL; - } - - struct ecmp_groups_node *eg = xzalloc(sizeof *eg); - hmap_insert(ecmp_groups, &eg->hmap_node, route->hash); - - eg->id = hmap_count(ecmp_groups); - eg->prefix = route->prefix; - eg->plen = route->plen; - eg->is_src_route = route->is_src_route; - eg->source = route->source; - eg->route_table_id = route->route_table_id; - sset_init(&eg->selection_fields); - ovs_list_init(&eg->route_list); - ecmp_groups_add_route(eg, route); - - return eg; -} - -static struct ecmp_groups_node * -ecmp_groups_find(struct hmap *ecmp_groups, struct parsed_route *route) -{ - struct ecmp_groups_node *eg; - HMAP_FOR_EACH_WITH_HASH (eg, hmap_node, route->hash, ecmp_groups) { - if (ipv6_addr_equals(&eg->prefix, &route->prefix) && - eg->plen == route->plen && - eg->is_src_route == route->is_src_route && - eg->route_table_id == route->route_table_id && - eg->source == route->source) { - return eg; - } - } - return NULL; -} - -static void -ecmp_groups_destroy(struct hmap *ecmp_groups) -{ - struct ecmp_groups_node *eg; - HMAP_FOR_EACH_SAFE (eg, hmap_node, ecmp_groups) { - struct ecmp_route_list_node *er; - LIST_FOR_EACH_SAFE (er, list_node, &eg->route_list) { - ovs_list_remove(&er->list_node); - free(er); - } - hmap_remove(ecmp_groups, &eg->hmap_node); - sset_destroy(&eg->selection_fields); - free(eg); - } - hmap_destroy(ecmp_groups); -} - -struct unique_routes_node { - struct hmap_node hmap_node; - const struct parsed_route *route; -}; - -static void -unique_routes_add(struct hmap *unique_routes, - const struct parsed_route *route) -{ - struct unique_routes_node *ur = xmalloc(sizeof *ur); - ur->route = route; - hmap_insert(unique_routes, &ur->hmap_node, route->hash); -} - -/* Remove the unique_routes_node from the hmap, and return the parsed_route - * pointed by the removed node. */ -static const struct parsed_route * -unique_routes_remove(struct hmap *unique_routes, - const struct parsed_route *route) -{ - struct unique_routes_node *ur; - HMAP_FOR_EACH_WITH_HASH (ur, hmap_node, route->hash, unique_routes) { - if (ipv6_addr_equals(&route->prefix, &ur->route->prefix) && - route->plen == ur->route->plen && - route->is_src_route == ur->route->is_src_route && - route->source == ur->route->source && - route->route_table_id == ur->route->route_table_id) { - hmap_remove(unique_routes, &ur->hmap_node); - const struct parsed_route *existed_route = ur->route; - free(ur); - return existed_route; - } - } - return NULL; -} - -static void -unique_routes_destroy(struct hmap *unique_routes) -{ - struct unique_routes_node *ur; - HMAP_FOR_EACH_SAFE (ur, hmap_node, unique_routes) { - hmap_remove(unique_routes, &ur->hmap_node); - free(ur); - } - hmap_destroy(unique_routes); -} static char * build_route_prefix_s(const struct in6_addr *prefix, unsigned int plen) @@ -13969,7 +13822,7 @@ build_ip_routing_pre_flows_for_lrouter(struct ovn_datapath *od, static void build_route_flows_for_lrouter( struct ovn_datapath *od, struct lflow_table *lflows, - struct hmap *parsed_routes, + const struct group_ecmp_route_data *route_data, struct simap *route_tables, const struct sset *bfd_ports, struct lflow_ref *lflow_ref) { @@ -13982,47 +13835,19 @@ build_route_flows_for_lrouter( REG_ECMP_GROUP_ID" == 0", "next;", lflow_ref); - struct hmap ecmp_groups = HMAP_INITIALIZER(&ecmp_groups); - struct hmap unique_routes = HMAP_INITIALIZER(&unique_routes); - 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); } - struct parsed_route *route; - HMAP_FOR_EACH_WITH_HASH (route, key_node, uuid_hash(&od->key), - parsed_routes) { - if (od != route->od) { - continue; - } - if (route->source == ROUTE_SOURCE_CONNECTED) { - unique_routes_add(&unique_routes, route); - continue; - } - group = ecmp_groups_find(&ecmp_groups, route); - if (group) { - ecmp_groups_add_route(group, route); - } else { - const struct parsed_route *existed_route = - unique_routes_remove(&unique_routes, route); - if (existed_route) { - group = ecmp_groups_add(&ecmp_groups, existed_route); - if (group) { - ecmp_groups_add_route(group, route); - } - } else if (route->ecmp_symmetric_reply) { - /* Traffic for symmetric reply routes has to be conntracked - * even if there is only one next-hop, in case another next-hop - * is added later. */ - ecmp_groups_add(&ecmp_groups, route); - } else { - unique_routes_add(&unique_routes, route); - } - } + const struct group_ecmp_route_node *route_node = + group_ecmp_route_lookup(route_data, od); + if (!route_node) { + return; } - HMAP_FOR_EACH (group, hmap_node, &ecmp_groups) { + + struct ecmp_groups_node *group; + HMAP_FOR_EACH (group, hmap_node, &route_node->ecmp_groups) { /* add a flow in IP_ROUTING, and one flow for each member in * IP_ROUTING_ECMP. */ build_ecmp_route_flow(lflows, od, group, lflow_ref, NULL); @@ -14037,11 +13862,9 @@ build_route_flows_for_lrouter( } } const struct unique_routes_node *ur; - HMAP_FOR_EACH (ur, hmap_node, &unique_routes) { + HMAP_FOR_EACH (ur, hmap_node, &route_node->unique_routes) { build_route_flow(lflows, od, ur->route, bfd_ports, lflow_ref); } - ecmp_groups_destroy(&ecmp_groups); - unique_routes_destroy(&unique_routes); } static void @@ -17600,7 +17423,7 @@ struct lswitch_flow_build_info { size_t thread_lflow_counter; const char *svc_monitor_mac; const struct sampling_app_table *sampling_apps; - struct hmap *parsed_routes; + const struct group_ecmp_route_data *route_data; struct hmap *route_policies; struct simap *route_tables; const struct sbrec_acl_id_table *sbrec_acl_id_table; @@ -17650,7 +17473,7 @@ build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od, build_ND_RA_flows_for_lrouter(od, lsi->lflows, NULL); build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows, NULL); build_route_flows_for_lrouter(od, lsi->lflows, - lsi->parsed_routes, lsi->route_tables, + lsi->route_data, lsi->route_tables, lsi->bfd_ports, NULL); build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match, NULL); build_ingress_policy_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports, @@ -17960,7 +17783,7 @@ build_lswitch_and_lrouter_flows( const struct chassis_features *features, const char *svc_monitor_mac, const struct sampling_app_table *sampling_apps, - struct hmap *parsed_routes, + const struct group_ecmp_route_data *route_data, struct hmap *route_policies, struct simap *route_tables, const struct sbrec_acl_id_table *sbrec_acl_id_table) @@ -17997,7 +17820,7 @@ build_lswitch_and_lrouter_flows( lsiv[index].thread_lflow_counter = 0; lsiv[index].svc_monitor_mac = svc_monitor_mac; lsiv[index].sampling_apps = sampling_apps; - lsiv[index].parsed_routes = parsed_routes; + lsiv[index].route_data = route_data; lsiv[index].route_tables = route_tables; lsiv[index].route_policies = route_policies; lsiv[index].sbrec_acl_id_table = sbrec_acl_id_table; @@ -18040,7 +17863,7 @@ build_lswitch_and_lrouter_flows( .svc_check_match = svc_check_match, .svc_monitor_mac = svc_monitor_mac, .sampling_apps = sampling_apps, - .parsed_routes = parsed_routes, + .route_data = route_data, .route_tables = route_tables, .route_policies = route_policies, .match = DS_EMPTY_INITIALIZER, @@ -18208,7 +18031,7 @@ void build_lflows(struct ovsdb_idl_txn *ovnsb_txn, input_data->features, input_data->svc_monitor_mac, input_data->sampling_apps, - input_data->parsed_routes, + input_data->route_data, input_data->route_policies, input_data->route_tables, input_data->sbrec_acl_id_table); diff --git a/northd/northd.h b/northd/northd.h index 9402e4a4b..b83efdb63 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -236,7 +236,7 @@ struct lflow_input { bool ovn_internal_version_changed; const char *svc_monitor_mac; const struct sampling_app_table *sampling_apps; - struct hmap *parsed_routes; + struct group_ecmp_route_data *route_data; struct hmap *route_policies; struct simap *route_tables; struct hmap *igmp_groups; diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index bb77f2abc..8d77b3534 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -15516,6 +15516,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15530,6 +15531,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15540,6 +15542,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15549,6 +15552,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15559,6 +15563,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15568,6 +15573,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15577,6 +15583,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15587,6 +15594,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15597,6 +15605,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15607,6 +15616,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15617,6 +15627,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15631,6 +15642,7 @@ check_engine_compute northd unchanged check_engine_compute routes unchanged check_engine_compute advertised_route_sync unchanged check_engine_compute learned_route_sync incremental +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15641,6 +15653,7 @@ check_engine_compute northd unchanged check_engine_compute routes unchanged check_engine_compute advertised_route_sync unchanged check_engine_compute learned_route_sync incremental +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15651,6 +15664,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15661,6 +15675,7 @@ check_engine_compute northd incremental check_engine_compute routes incremental check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync incremental +check_engine_compute group_ecmp_route unchanged check_engine_compute lflow incremental CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15674,6 +15689,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15683,6 +15699,7 @@ check_engine_compute northd incremental check_engine_compute routes incremental check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync incremental +check_engine_compute group_ecmp_route unchanged check_engine_compute lflow incremental CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15692,6 +15709,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE @@ -15701,6 +15719,7 @@ check_engine_compute northd recompute check_engine_compute routes recompute check_engine_compute advertised_route_sync recompute check_engine_compute learned_route_sync recompute +check_engine_compute group_ecmp_route recompute check_engine_compute lflow recompute CHECK_NO_CHANGE_AFTER_RECOMPUTE -- 2.48.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
