Change the en_dynamic_routes I-P node to compute a map of 'advertised routes' (struct ar_entry) instead of parsed routes. Like that we can avoid having to re-parse NAT/LB IPs when advertising them.
Fixes: cd4ad2f56179 ("northd: Redistribution of NAT/LB routes.") Signed-off-by: Dumitru Ceara <dce...@redhat.com> --- northd/en-advertised-route-sync.c | 376 +++++++++++++++++------------- northd/northd.h | 3 +- 2 files changed, 210 insertions(+), 169 deletions(-) diff --git a/northd/en-advertised-route-sync.c b/northd/en-advertised-route-sync.c index 486bcc2fd2..ebaed08b69 100644 --- a/northd/en-advertised-route-sync.c +++ b/northd/en-advertised-route-sync.c @@ -27,6 +27,102 @@ #include "openvswitch/hmap.h" #include "ovn-util.h" +struct ar_entry { + struct hmap_node hmap_node; + + const struct ovn_datapath *od; /* Datapath the route is + * advertised on. */ + const struct ovn_port *op; /* Port the route is advertised + * on. */ + char *ip_prefix; + const struct ovn_port *tracked_port; /* If set, the port whose chassis + * advertises this route with a + * higher priority. */ + enum route_source source; +}; + +/* Add a new entries to the to-be-advertised routes. + * Takes ownership of ip_prefix. */ +static struct ar_entry * +ar_entry_add_nocopy(struct hmap *routes, const struct ovn_datapath *od, + const struct ovn_port *op, char *ip_prefix, + const struct ovn_port *tracked_port, + enum route_source source) +{ + struct ar_entry *route_e = xzalloc(sizeof *route_e); + + route_e->od = od; + route_e->op = op; + route_e->ip_prefix = ip_prefix; + route_e->tracked_port = tracked_port; + route_e->source = source; + uint32_t hash = uuid_hash(&od->sb->header_.uuid); + hash = hash_string(op->sb->logical_port, hash); + hash = hash_string(ip_prefix, hash); + hmap_insert(routes, &route_e->hmap_node, hash); + + return route_e; +} + +/* Add a new entries to the to-be-advertised routes. + * Makes a copy of ip_prefix. */ +static struct ar_entry * +ar_entry_add(struct hmap *routes, const struct ovn_datapath *od, + const struct ovn_port *op, const char *ip_prefix, + const struct ovn_port *tracked_port, + enum route_source source) +{ + return ar_entry_add_nocopy(routes, od, op, xstrdup(ip_prefix), + tracked_port, source); +} + +static struct ar_entry * +ar_entry_find(struct hmap *route_map, + const struct sbrec_datapath_binding *sb_db, + const struct sbrec_port_binding *logical_port, + const char *ip_prefix, + const struct sbrec_port_binding *tracked_port) +{ + struct ar_entry *route_e; + uint32_t hash; + + hash = uuid_hash(&sb_db->header_.uuid); + hash = hash_string(logical_port->logical_port, hash); + hash = hash_string(ip_prefix, hash); + + HMAP_FOR_EACH_WITH_HASH (route_e, hmap_node, hash, route_map) { + if (!uuid_equals(&sb_db->header_.uuid, + &route_e->od->sb->header_.uuid)) { + continue; + } + if (!uuid_equals(&logical_port->header_.uuid, + &route_e->op->sb->header_.uuid)) { + continue; + } + if (strcmp(ip_prefix, route_e->ip_prefix)) { + continue; + } + + if (tracked_port) { + if (!route_e->tracked_port || + tracked_port != route_e->tracked_port->sb) { + continue; + } + } + + return route_e; + } + + return NULL; +} + +static void +ar_entry_free(struct ar_entry *route_e) +{ + free(route_e->ip_prefix); + free(route_e); +} + static void advertised_route_table_sync( struct ovsdb_idl_txn *ovnsb_txn, @@ -158,7 +254,7 @@ en_advertised_route_sync_run(struct engine_node *node, void *data OVS_UNUSED) sbrec_advertised_route_table, &lr_stateful_data->table, &routes_data->parsed_routes, - &dynamic_routes_data->parsed_routes, + &dynamic_routes_data->routes, routes_sync_data); stopwatch_stop(ADVERTISED_ROUTE_SYNC_RUN_STOPWATCH_NAME, time_msec()); @@ -184,18 +280,18 @@ build_nat_parsed_route_for_port(const struct ovn_port *advertising_op, continue; } - int plen = nat_entry_is_v6(nat) ? 128 : 32; - struct in6_addr prefix; - ip46_parse(nat->nb->external_ip, &prefix); - const struct ovn_port *tracked_port = nat->is_distributed ? ovn_port_find(ls_ports, nat->nb->logical_port) : nat->l3dgw_port; - parsed_route_add(advertising_od, NULL, &prefix, plen, false, - nat->nb->external_ip, advertising_op, 0, false, - false, NULL, ROUTE_SOURCE_NAT, &nat->nb->header_, - tracked_port, routes); + + if (!ar_entry_find(routes, advertising_od->sb, advertising_op->sb, + nat->nb->external_ip, + tracked_port ? tracked_port->sb : NULL)) { + ar_entry_add(routes, advertising_od, advertising_op, + nat->nb->external_ip, tracked_port, + ROUTE_SOURCE_NAT); + } } } @@ -294,20 +390,12 @@ build_lb_parsed_route_for_port(const struct ovn_port *advertising_op, const char *ip_address; SSET_FOR_EACH (ip_address, &lb_ips->ips_v4) { - struct in6_addr prefix; - ip46_parse(ip_address, &prefix); - parsed_route_add(advertising_od, NULL, &prefix, 32, false, - ip_address, advertising_op, 0, false, false, - NULL, ROUTE_SOURCE_LB, &advertising_op->nbrp->header_, - tracked_port, routes); + ar_entry_add(routes, advertising_od, advertising_op, + ip_address, tracked_port, ROUTE_SOURCE_LB); } SSET_FOR_EACH (ip_address, &lb_ips->ips_v6) { - struct in6_addr prefix; - ip46_parse(ip_address, &prefix); - parsed_route_add(advertising_od, NULL, &prefix, 128, false, - ip_address, advertising_op, 0, false, false, - NULL, ROUTE_SOURCE_LB, &advertising_op->nbrp->header_, - tracked_port, routes); + ar_entry_add(routes, advertising_od, advertising_op, + ip_address, tracked_port, ROUTE_SOURCE_LB); } } @@ -402,7 +490,7 @@ en_dynamic_routes_init(struct engine_node *node OVS_UNUSED, { struct dynamic_routes_data *data = xmalloc(sizeof *data); *data = (struct dynamic_routes_data) { - .parsed_routes = HMAP_INITIALIZER(&data->parsed_routes), + .routes = HMAP_INITIALIZER(&data->routes), }; return data; @@ -411,9 +499,9 @@ en_dynamic_routes_init(struct engine_node *node OVS_UNUSED, static void en_dynamic_routes_clear(struct dynamic_routes_data *data) { - struct parsed_route *r; - HMAP_FOR_EACH_POP (r, key_node, &data->parsed_routes) { - parsed_route_free(r); + struct ar_entry *ar; + HMAP_FOR_EACH_POP (ar, hmap_node, &data->routes) { + ar_entry_free(ar); } } void @@ -422,7 +510,7 @@ en_dynamic_routes_cleanup(void *data_) struct dynamic_routes_data *data = data_; en_dynamic_routes_clear(data); - hmap_destroy(&data->parsed_routes); + hmap_destroy(&data->routes); } void @@ -447,100 +535,20 @@ en_dynamic_routes_run(struct engine_node *node, void *data) } build_nat_parsed_routes(od, lr_stateful_rec->lrnat_rec, &northd_data->ls_ports, - &dynamic_routes_data->parsed_routes); + &dynamic_routes_data->routes); build_nat_connected_parsed_routes(od, &lr_stateful_data->table, &northd_data->ls_ports, - &dynamic_routes_data->parsed_routes); + &dynamic_routes_data->routes); build_lb_parsed_routes(od, lr_stateful_rec->lb_ips, - &dynamic_routes_data->parsed_routes); + &dynamic_routes_data->routes); build_lb_connected_parsed_routes(od, &lr_stateful_data->table, - &dynamic_routes_data->parsed_routes); + &dynamic_routes_data->routes); } stopwatch_stop(DYNAMIC_ROUTES_RUN_STOPWATCH_NAME, time_msec()); engine_set_node_state(node, EN_UPDATED); } -struct ar_entry { - struct hmap_node hmap_node; - - const struct ovn_datapath *od; /* Datapath the route is - * advertised on. */ - const struct ovn_port *op; /* Port the route is advertised - * on. */ - char *ip_prefix; - const struct ovn_port *tracked_port; /* If set, the port whose chassis - * advertises this route with a - * higher priority. */ -}; - -/* Add a new entries to the to-be-advertised routes. - * Takes ownership of ip_prefix. */ -static struct ar_entry * -ar_entry_add(struct hmap *routes, const struct ovn_datapath *od, - const struct ovn_port *op, char *ip_prefix, - const struct ovn_port *tracked_port) -{ - struct ar_entry *route_e = xzalloc(sizeof *route_e); - - route_e->od = od; - route_e->op = op; - route_e->ip_prefix = ip_prefix; - route_e->tracked_port = tracked_port; - uint32_t hash = uuid_hash(&od->sb->header_.uuid); - hash = hash_string(op->sb->logical_port, hash); - hash = hash_string(ip_prefix, hash); - hmap_insert(routes, &route_e->hmap_node, hash); - - return route_e; -} - -static struct ar_entry * -ar_entry_find(struct hmap *route_map, - const struct sbrec_datapath_binding *sb_db, - const struct sbrec_port_binding *logical_port, - const char *ip_prefix, - const struct sbrec_port_binding *tracked_port) -{ - struct ar_entry *route_e; - uint32_t hash; - - hash = uuid_hash(&sb_db->header_.uuid); - hash = hash_string(logical_port->logical_port, hash); - hash = hash_string(ip_prefix, hash); - - HMAP_FOR_EACH_WITH_HASH (route_e, hmap_node, hash, route_map) { - if (!uuid_equals(&sb_db->header_.uuid, - &route_e->od->sb->header_.uuid)) { - continue; - } - if (!uuid_equals(&logical_port->header_.uuid, - &route_e->op->sb->header_.uuid)) { - continue; - } - if (strcmp(ip_prefix, route_e->ip_prefix)) { - continue; - } - - if (tracked_port) { - if (!route_e->tracked_port || - tracked_port != route_e->tracked_port->sb) { - continue; - } - } - return route_e; - } - - return NULL; -} - -static void -ar_entry_free(struct ar_entry *route_e) -{ - free(route_e->ip_prefix); - free(route_e); -} - static void publish_lport_addresses(struct hmap *sync_routes, const struct ovn_datapath *od, @@ -550,16 +558,16 @@ publish_lport_addresses(struct hmap *sync_routes, { for (size_t i = 0; i < addresses->n_ipv4_addrs; i++) { const struct ipv4_netaddr *addr = &addresses->ipv4_addrs[i]; - ar_entry_add(sync_routes, od, logical_port, xstrdup(addr->addr_s), - tracking_port); + ar_entry_add(sync_routes, od, logical_port, addr->addr_s, + tracking_port, ROUTE_SOURCE_CONNECTED); } for (size_t i = 0; i < addresses->n_ipv6_addrs; i++) { if (in6_is_lla(&addresses->ipv6_addrs[i].network)) { continue; } const struct ipv6_netaddr *addr = &addresses->ipv6_addrs[i]; - ar_entry_add(sync_routes, od, logical_port, xstrdup(addr->addr_s), - tracking_port); + ar_entry_add(sync_routes, od, logical_port, addr->addr_s, + tracking_port, ROUTE_SOURCE_CONNECTED); } } @@ -640,78 +648,85 @@ publish_host_routes(struct hmap *sync_routes, } } -static void -advertised_route_table_sync_route_add( - const struct lr_stateful_table *lr_stateful_table, - struct advertised_route_sync_data *data, - struct uuidset *host_route_lrps, - struct hmap *sync_routes, - const struct parsed_route *route) +static bool +should_advertise_route(const struct lr_stateful_table *lr_stateful_table, + struct advertised_route_sync_data *data, + struct uuidset *host_route_lrps, + struct hmap *sync_routes, + const struct ovn_datapath *advertising_od, + const struct ovn_port *advertising_op, + const struct ovn_port *tracked_op, + enum route_source source) { - if (route->is_discard_route) { - return; - } - if (prefix_is_link_local(&route->prefix, route->plen)) { - return; - } - if (!route->od->dynamic_routing) { - return; + if (!advertising_od->dynamic_routing) { + return false; } enum dynamic_routing_redistribute_mode drr = - route->out_port->dynamic_routing_redistribute; - if (route->source == ROUTE_SOURCE_CONNECTED) { + advertising_op->dynamic_routing_redistribute; + + switch (source) { + case ROUTE_SOURCE_CONNECTED: if (!drr_mode_CONNECTED_is_set(drr)) { - return; + return false; } + /* If we advertise host routes, we only need to do so once per * LRP. */ - const struct uuid *lrp_uuid = &route->out_port->nbrp->header_.uuid; - if (drr_mode_CONNECTED_AS_HOST_is_set(drr) && - !uuidset_contains(host_route_lrps, lrp_uuid)) { + const struct uuid *lrp_uuid = &advertising_op->nbrp->header_.uuid; + if (drr_mode_CONNECTED_AS_HOST_is_set(drr)) { + if (uuidset_contains(host_route_lrps, lrp_uuid)) { + return false; + } uuidset_insert(host_route_lrps, lrp_uuid); publish_host_routes(sync_routes, lr_stateful_table, - route->od, route->out_port, + advertising_od, advertising_op, data); - return; + return false; } - } - if (route->source == ROUTE_SOURCE_STATIC && !drr_mode_STATIC_is_set(drr)) { - return; - } - if (route->source == ROUTE_SOURCE_NAT) { + return true; + + case ROUTE_SOURCE_STATIC: + return drr_mode_STATIC_is_set(drr); + + case ROUTE_SOURCE_NAT: if (!drr_mode_NAT_is_set(drr)) { - return; + return false; } + /* If NAT route tracks port on a different DP than the one that * advertises the route, we need to watch for changes on that DP as * well. */ - if (route->tracked_port && route->tracked_port->od != route->od) { - if (route->tracked_port->od->nbr) { + if (tracked_op && tracked_op->od != advertising_od) { + if (tracked_op->od->nbr) { uuidset_insert(&data->nb_lr, - &route->tracked_port->od->nbr->header_.uuid); - } else if (route->tracked_port->od->nbs) { + &tracked_op->od->nbr->header_.uuid); + } else if (tracked_op->od->nbs) { uuidset_insert(&data->nb_ls, - &route->tracked_port->od->nbs->header_.uuid); + &tracked_op->od->nbs->header_.uuid); } } - } - if (route->source == ROUTE_SOURCE_LB) { + return true; + + case ROUTE_SOURCE_LB: if (!drr_mode_LB_is_set(drr)) { - return; + return false; } + /* If LB route tracks port on a different DP than the one that * advertises the route, we need to watch for changes on that DP as * well. */ - if (route->tracked_port && route->tracked_port->od != route->od) { + if (tracked_op && tracked_op->od != advertising_od) { uuidset_insert(&data->nb_lr, - &route->tracked_port->od->nbr->header_.uuid); + &tracked_op->od->nbr->header_.uuid); } + return true; + + case ROUTE_SOURCE_LEARNED: + return true; } - char *ip_prefix = normalize_v46_prefix(&route->prefix, route->plen); - ar_entry_add(sync_routes, route->od, route->out_port, ip_prefix, - route->tracked_port); + OVS_NOT_REACHED(); } static void @@ -725,23 +740,48 @@ advertised_route_table_sync( { struct hmap sync_routes = HMAP_INITIALIZER(&sync_routes); struct uuidset host_route_lrps = UUIDSET_INITIALIZER(&host_route_lrps); - const struct parsed_route *route; - - struct ar_entry *route_e; /* First build the set of non-dynamic routes that need sync-ing. */ + const struct parsed_route *route; HMAP_FOR_EACH (route, key_node, routes) { - advertised_route_table_sync_route_add(lr_stateful_table, - data, &host_route_lrps, - &sync_routes, - route); + if (route->is_discard_route) { + continue; + } + + if (prefix_is_link_local(&route->prefix, route->plen)) { + continue; + } + + if (!should_advertise_route(lr_stateful_table, + data, &host_route_lrps, + &sync_routes, + route->od, route->out_port, + route->tracked_port, + route->source)) { + continue; + } + + ar_entry_add_nocopy(&sync_routes, route->od, route->out_port, + normalize_v46_prefix(&route->prefix, route->plen), + route->tracked_port, + route->source); } + /* Then add the set of dynamic routes that need sync-ing. */ - HMAP_FOR_EACH (route, key_node, dynamic_routes) { - advertised_route_table_sync_route_add(lr_stateful_table, - data, &host_route_lrps, - &sync_routes, - route); + struct ar_entry *route_e; + HMAP_FOR_EACH (route_e, hmap_node, dynamic_routes) { + if (!should_advertise_route(lr_stateful_table, + data, &host_route_lrps, + &sync_routes, + route_e->od, route_e->op, + route_e->tracked_port, + route_e->source)) { + continue; + } + + ar_entry_add(&sync_routes, route_e->od, route_e->op, + route_e->ip_prefix, route_e->tracked_port, + route_e->source); } uuidset_destroy(&host_route_lrps); diff --git a/northd/northd.h b/northd/northd.h index 12fccd7751..c221365e62 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -192,7 +192,8 @@ struct routes_data { }; struct dynamic_routes_data { - struct hmap parsed_routes; /* Stores struct parsed_route. */ + struct hmap routes; /* Stores struct ar_entry, one for each + * dynamic route. */ }; struct route_policies_data { -- 2.48.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev