diff options
author | Naveen Thanikachalam <nthanikachal@vmware.com> | 2019-11-02 03:43:10 +0100 |
---|---|---|
committer | Naveen Thanikachalam <nthanikachal@vmware.com> | 2020-02-18 11:08:29 +0100 |
commit | 819a23f9fc99872aa4c3a137d374ede7d12e56c0 (patch) | |
tree | 2f0e3120eed9dd6bded8857407c1403a4db18596 /lib | |
parent | lib: Optimizing route-maps - Part-1 (diff) | |
download | frr-819a23f9fc99872aa4c3a137d374ede7d12e56c0.tar.xz frr-819a23f9fc99872aa4c3a137d374ede7d12e56c0.zip |
lib: Optimizing route-maps - Part-2
This commit introduces the logic that computes the best-match route-map index
for a given prefix.
Signed-off-by: NaveenThanikachalam <nthanikachal@vmware.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/routemap.c | 278 |
1 files changed, 217 insertions, 61 deletions
diff --git a/lib/routemap.c b/lib/routemap.c index e3d5c9168..964346741 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -50,6 +50,15 @@ DEFINE_QOBJ_TYPE(route_map) #define IPv4_MATCH_RULE "ip " #define IPv6_MATCH_RULE "ipv6 " +#define IS_RULE_IPv4_PREFIX_LIST(S) (strncmp(S, IPv4_PREFIX_LIST, \ + strlen(IPv4_PREFIX_LIST)) == 0) +#define IS_RULE_IPv6_PREFIX_LIST(S) (strncmp(S, IPv6_PREFIX_LIST, \ + strlen(IPv6_PREFIX_LIST)) == 0) + +#define IS_IPv4_RULE(S) (strncmp(S, IPv4_MATCH_RULE, \ + strlen(IPv4_MATCH_RULE)) == 0) +#define IS_IPv6_RULE(S) (strncmp(S, IPv6_MATCH_RULE, \ + strlen(IPv6_MATCH_RULE)) == 0) struct route_map_pentry_dep { struct prefix_list_entry *pentry; const char *plist_name; @@ -976,14 +985,12 @@ void route_map_index_delete(struct route_map_index *index, int notify) /* Free route match. */ while ((rule = index->match_list.head) != NULL) { - if (strncmp(rule->cmd->str, IPv4_PREFIX_LIST, - strlen(IPv4_PREFIX_LIST)) == 0) + if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str)) route_map_pfx_tbl_update( RMAP_EVENT_PLIST_DELETED, index, AFI_IP, rule->rule_str); - else if (strncmp(rule->cmd->str, IPv6_PREFIX_LIST, - strlen(IPv6_PREFIX_LIST)) == 0) + else if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str)) route_map_pfx_tbl_update( RMAP_EVENT_PLIST_DELETED, index, AFI_IP6, @@ -1326,14 +1333,12 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, * has been delete to the route-map index, update * the route-map's prefix table. */ - if (strncmp(match_name, IPv4_PREFIX_LIST, - strlen(IPv4_PREFIX_LIST)) == 0) + if (IS_RULE_IPv4_PREFIX_LIST(match_name)) route_map_pfx_tbl_update( RMAP_EVENT_PLIST_DELETED, index, AFI_IP, rule->rule_str); - else if (strncmp(match_name, IPv6_PREFIX_LIST, - strlen(IPv6_PREFIX_LIST)) == 0) + else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) route_map_pfx_tbl_update( RMAP_EVENT_PLIST_DELETED, index, AFI_IP6, @@ -1371,13 +1376,11 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, * has been added to the route-map index, update * the route-map's prefix table. */ - if (strncmp(match_name, IPv4_PREFIX_LIST, - strlen(IPv4_PREFIX_LIST)) == 0) { + if (IS_RULE_IPv4_PREFIX_LIST(match_name)) { route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP, match_arg); - } else if (strncmp(match_name, IPv6_PREFIX_LIST, - strlen(IPv6_PREFIX_LIST)) == 0) { + } else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) { route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP6, match_arg); @@ -1389,8 +1392,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, * match rule is present, remove this index from the IPv6 * default route's trie node. */ - if (strncmp(match_name, IPv4_MATCH_RULE, - strlen(IPv4_MATCH_RULE)) == 0) + if (IS_IPv4_RULE(match_name)) route_map_del_plist_entries(AFI_IP6, index, NULL, NULL); @@ -1401,8 +1403,7 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, * match rule is present, remove this index from the IPv4 * default route's trie node. */ - else if (strncmp(match_name, IPv6_MATCH_RULE, - strlen(IPv6_MATCH_RULE)) == 0) + else if (IS_IPv6_RULE(match_name)) route_map_del_plist_entries(AFI_IP, index, NULL, NULL); } @@ -1459,14 +1460,12 @@ enum rmap_compile_rets route_map_delete_match(struct route_map_index *index, * has been delete to the route-map index, update * the route-map's prefix table. */ - if (strncmp(match_name, IPv4_PREFIX_LIST, - strlen(IPv4_PREFIX_LIST)) == 0) { + if (IS_RULE_IPv4_PREFIX_LIST(match_name)) { route_map_pfx_tbl_update( RMAP_EVENT_PLIST_DELETED, index, AFI_IP, match_arg); - } else if (strncmp(match_name, IPv6_PREFIX_LIST, - strlen(IPv6_PREFIX_LIST)) == 0) { + } else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) { route_map_pfx_tbl_update( RMAP_EVENT_PLIST_DELETED, index, AFI_IP6, @@ -1664,6 +1663,130 @@ route_map_apply_match(struct route_map_rule_list *match_list, return ret; } +static struct list * +route_map_get_index_list(struct route_node **rn, + const struct prefix *prefix, + struct route_table *table) +{ + struct route_node *tmp_rn = NULL; + + if (!(*rn)) { + *rn = route_node_match(table, prefix); + + if (!(*rn)) + return NULL; + + if ((*rn)->info) + return (struct list *)((*rn)->info); + + /* If rn->info is NULL, get the parent. + * Store the rn in tmp_rn and unlock it later. + */ + tmp_rn = *rn; + } + + do { + *rn = (*rn)->parent; + if (tmp_rn) + route_unlock_node(tmp_rn); + + if (!(*rn)) + break; + + if ((*rn)->info) { + route_lock_node(*rn); + return (struct list *)((*rn)->info); + } + } while (!(*rn)->info); + + return NULL; +} + +/* + * This function returns the route-map index that best matches the prefix. + */ +static struct route_map_index * +route_map_get_index(struct route_map *map, + const struct prefix *prefix, + route_map_object_t type, + void *object, + uint8_t *match_ret) +{ + int ret = 0; + struct list *candidate_rmap_list = NULL; + struct route_node *rn = NULL; + struct listnode *ln = NULL, *nn = NULL; + struct route_map_index *index = NULL, *best_index = NULL; + struct route_map_index *head_index = NULL; + struct route_table *table = NULL; + unsigned char family = prefix->family; + + if (family == AF_INET) + table = map->ipv4_prefix_table; + else + table = map->ipv6_prefix_table; + + if (!table) + return NULL; + + do { + candidate_rmap_list = route_map_get_index_list(&rn, prefix, + table); + if (!rn) + break; + + /* If the index at the head of the list is of seq higher + * than that in best_index, ignore the list and get the + * parent node's list. + */ + head_index = (struct route_map_index *) + (listgetdata(listhead(candidate_rmap_list))); + if (best_index && head_index && + (best_index->pref < head_index->pref)) { + route_unlock_node(rn); + continue; + } + + for (ALL_LIST_ELEMENTS(candidate_rmap_list, ln, nn, index)) { + /* If the index is of seq higher than that in + * best_index, ignore the list and get the parent + * node's list. + */ + if (best_index && (best_index->pref < index->pref)) + break; + + ret = route_map_apply_match( + &index->match_list, + prefix, type, object); + + if (ret == RMAP_MATCH) { + *match_ret = ret; + best_index = index; + break; + } else if (ret == RMAP_NOOP) { + /* + * If match_ret is denymatch, even if we see + * more noops, we retain this return value and + * return this eventually if there are no + * matches. + */ + if (*match_ret != RMAP_NOMATCH) + *match_ret = ret; + } else { + /* + * ret is RMAP_NOMATCH. + */ + *match_ret = ret; + } + } + + route_unlock_node(rn); + + } while (rn); + + return best_index; +} + static int route_map_candidate_list_cmp(struct route_map_index *idx1, struct route_map_index *idx2) @@ -1839,8 +1962,7 @@ route_map_is_ip_rule_present(struct route_map_index *index) match_list = &index->match_list; for (rule = match_list->head; rule; rule = rule->next) - if (strncmp(rule->cmd->str, IPv4_MATCH_RULE, - strlen(IPv4_MATCH_RULE)) == 0) + if (IS_IPv4_RULE(rule->cmd->str)) return true; return false; @@ -1857,8 +1979,7 @@ route_map_is_ipv6_rule_present(struct route_map_index *index) match_list = &index->match_list; for (rule = match_list->head; rule; rule = rule->next) - if (strncmp(rule->cmd->str, IPv6_MATCH_RULE, - strlen(IPv6_MATCH_RULE)) == 0) + if (IS_IPv6_RULE(rule->cmd->str)) return true; return false; @@ -1895,15 +2016,14 @@ route_map_add_plist_entries(afi_t afi, match_list = &index->match_list; for (match = match_list->head; match; match = match->next) { - if (strncmp( - match->cmd->str, - (afi == AFI_IP) ? IPv4_PREFIX_LIST : - IPv6_PREFIX_LIST, - strlen((afi == AFI_IP) ? - IPv4_PREFIX_LIST : IPv6_PREFIX_LIST)) - == 0) { - plist_rule_is_present = true; - break; + if (afi == AFI_IP) { + if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) + plist_rule_is_present = true; + break; + } else { + if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) + plist_rule_is_present = true; + break; } } @@ -1974,15 +2094,14 @@ route_map_del_plist_entries(afi_t afi, match_list = &index->match_list; for (match = match_list->head; match; match = match->next) { - if (strncmp( - match->cmd->str, - (afi == AFI_IP) ? IPv4_PREFIX_LIST : - IPv6_PREFIX_LIST, - strlen((afi == AFI_IP) ? - IPv4_PREFIX_LIST : IPv6_PREFIX_LIST)) - == 0) { - plist_rule_is_present = true; - break; + if (afi == AFI_IP) { + if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) + plist_rule_is_present = true; + break; + } else { + if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) + plist_rule_is_present = true; + break; } } @@ -2220,18 +2339,16 @@ route_map_pentry_process_dependency(struct hash_backet *backet, for (match = match_list->head; match; match = match->next) { if (strcmp(match->rule_str, pentry_dep->plist_name) == 0) { - if ((strncmp(match->cmd->str, IPv4_PREFIX_LIST, - strlen(IPv4_PREFIX_LIST)) == 0) && + if (IS_RULE_IPv4_PREFIX_LIST( + match->cmd->str) && family == AF_INET) { route_map_pentry_update( pentry_dep->event, pentry_dep->plist_name, index, pentry_dep->pentry); - } else if ((strncmp(match->cmd->str, - IPv6_PREFIX_LIST, - strlen(IPv6_PREFIX_LIST)) - == 0) && + } else if (IS_RULE_IPv6_PREFIX_LIST( + match->cmd->str) && family == AF_INET6) { route_map_pentry_update( pentry_dep->event, @@ -2330,9 +2447,10 @@ route_map_result_t route_map_apply(struct route_map *map, static int recursion = 0; enum route_map_cmd_result_t match_ret = RMAP_NOMATCH; route_map_result_t ret = RMAP_PERMITMATCH; - struct route_map_index *index; - struct route_map_rule *set; + struct route_map_index *index = NULL; + struct route_map_rule *set = NULL; char buf[PREFIX_STRLEN]; + bool skip_match_clause = false; if (recursion > RMAP_RECURSION_LIMIT) { flog_warn( @@ -2349,18 +2467,56 @@ route_map_result_t route_map_apply(struct route_map *map, } map->applied++; - for (index = map->head; index; index = index->next) { - /* Apply this index. */ - index->applied++; - match_ret = route_map_apply_match(&index->match_list, prefix, - type, object); - - if (rmap_debug) { - zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s", - map->name, index->pref, - prefix2str(prefix, buf, sizeof(buf)), - route_map_cmd_result_str(match_ret)); + + if ((!map->optimization_disabled) && + (map->ipv4_prefix_table || + map->ipv6_prefix_table)) { + index = route_map_get_index(map, prefix, + type, object, + (uint8_t *)&match_ret); + if (index) { + if (rmap_debug) + zlog_debug( + "Best match route-map: %s, sequence: %d for pfx: %s, result: %s", + map->name, index->pref, + prefix2str(prefix, buf, sizeof(buf)), + route_map_cmd_result_str(match_ret)); + } else { + if (rmap_debug) + zlog_debug("No match for pfx: %s in route-map: %s, result: %s", + prefix2str(prefix, buf, sizeof(buf)), + map->name, + route_map_cmd_result_str(match_ret)); + /* + * No index matches this prefix. Return deny unless, + * match_ret = RMAP_NOOP. + */ + if (match_ret == RMAP_NOOP) + ret = RMAP_PERMITMATCH; + else + ret = RMAP_DENYMATCH; + goto route_map_apply_end; } + skip_match_clause = true; + } else { + index = map->head; + } + + for (; index; index = index->next) { + if (skip_match_clause == false) { + /* Apply this index. */ + match_ret = route_map_apply_match(&index->match_list, + prefix, type, object); + if (rmap_debug) { + zlog_debug( + "Route-map: %s, sequence: %d, prefix: %s, result: %s", + map->name, index->pref, + prefix2str(prefix, buf, sizeof(buf)), + route_map_cmd_result_str(match_ret)); + } + } else + skip_match_clause = false; + /* Now we apply the matrix from above */ if (match_ret == RMAP_NOOP) |