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>
This commit is contained in:
Naveen Thanikachalam 2019-11-01 19:43:10 -07:00
parent 49a08bb091
commit 819a23f9fc

View File

@ -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)