mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 14:42:06 +00:00
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:
parent
49a08bb091
commit
819a23f9fc
276
lib/routemap.c
276
lib/routemap.c
@ -50,6 +50,15 @@ DEFINE_QOBJ_TYPE(route_map)
|
|||||||
#define IPv4_MATCH_RULE "ip "
|
#define IPv4_MATCH_RULE "ip "
|
||||||
#define IPv6_MATCH_RULE "ipv6 "
|
#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 route_map_pentry_dep {
|
||||||
struct prefix_list_entry *pentry;
|
struct prefix_list_entry *pentry;
|
||||||
const char *plist_name;
|
const char *plist_name;
|
||||||
@ -976,14 +985,12 @@ void route_map_index_delete(struct route_map_index *index, int notify)
|
|||||||
|
|
||||||
/* Free route match. */
|
/* Free route match. */
|
||||||
while ((rule = index->match_list.head) != NULL) {
|
while ((rule = index->match_list.head) != NULL) {
|
||||||
if (strncmp(rule->cmd->str, IPv4_PREFIX_LIST,
|
if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str))
|
||||||
strlen(IPv4_PREFIX_LIST)) == 0)
|
|
||||||
route_map_pfx_tbl_update(
|
route_map_pfx_tbl_update(
|
||||||
RMAP_EVENT_PLIST_DELETED,
|
RMAP_EVENT_PLIST_DELETED,
|
||||||
index, AFI_IP,
|
index, AFI_IP,
|
||||||
rule->rule_str);
|
rule->rule_str);
|
||||||
else if (strncmp(rule->cmd->str, IPv6_PREFIX_LIST,
|
else if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str))
|
||||||
strlen(IPv6_PREFIX_LIST)) == 0)
|
|
||||||
route_map_pfx_tbl_update(
|
route_map_pfx_tbl_update(
|
||||||
RMAP_EVENT_PLIST_DELETED,
|
RMAP_EVENT_PLIST_DELETED,
|
||||||
index, AFI_IP6,
|
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
|
* has been delete to the route-map index, update
|
||||||
* the route-map's prefix table.
|
* the route-map's prefix table.
|
||||||
*/
|
*/
|
||||||
if (strncmp(match_name, IPv4_PREFIX_LIST,
|
if (IS_RULE_IPv4_PREFIX_LIST(match_name))
|
||||||
strlen(IPv4_PREFIX_LIST)) == 0)
|
|
||||||
route_map_pfx_tbl_update(
|
route_map_pfx_tbl_update(
|
||||||
RMAP_EVENT_PLIST_DELETED,
|
RMAP_EVENT_PLIST_DELETED,
|
||||||
index, AFI_IP,
|
index, AFI_IP,
|
||||||
rule->rule_str);
|
rule->rule_str);
|
||||||
else if (strncmp(match_name, IPv6_PREFIX_LIST,
|
else if (IS_RULE_IPv6_PREFIX_LIST(match_name))
|
||||||
strlen(IPv6_PREFIX_LIST)) == 0)
|
|
||||||
route_map_pfx_tbl_update(
|
route_map_pfx_tbl_update(
|
||||||
RMAP_EVENT_PLIST_DELETED,
|
RMAP_EVENT_PLIST_DELETED,
|
||||||
index, AFI_IP6,
|
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
|
* has been added to the route-map index, update
|
||||||
* the route-map's prefix table.
|
* the route-map's prefix table.
|
||||||
*/
|
*/
|
||||||
if (strncmp(match_name, IPv4_PREFIX_LIST,
|
if (IS_RULE_IPv4_PREFIX_LIST(match_name)) {
|
||||||
strlen(IPv4_PREFIX_LIST)) == 0) {
|
|
||||||
route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED,
|
route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED,
|
||||||
index, AFI_IP,
|
index, AFI_IP,
|
||||||
match_arg);
|
match_arg);
|
||||||
} else if (strncmp(match_name, IPv6_PREFIX_LIST,
|
} else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) {
|
||||||
strlen(IPv6_PREFIX_LIST)) == 0) {
|
|
||||||
route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED,
|
route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED,
|
||||||
index, AFI_IP6,
|
index, AFI_IP6,
|
||||||
match_arg);
|
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
|
* match rule is present, remove this index from the IPv6
|
||||||
* default route's trie node.
|
* default route's trie node.
|
||||||
*/
|
*/
|
||||||
if (strncmp(match_name, IPv4_MATCH_RULE,
|
if (IS_IPv4_RULE(match_name))
|
||||||
strlen(IPv4_MATCH_RULE)) == 0)
|
|
||||||
route_map_del_plist_entries(AFI_IP6, index,
|
route_map_del_plist_entries(AFI_IP6, index,
|
||||||
NULL, NULL);
|
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
|
* match rule is present, remove this index from the IPv4
|
||||||
* default route's trie node.
|
* default route's trie node.
|
||||||
*/
|
*/
|
||||||
else if (strncmp(match_name, IPv6_MATCH_RULE,
|
else if (IS_IPv6_RULE(match_name))
|
||||||
strlen(IPv6_MATCH_RULE)) == 0)
|
|
||||||
route_map_del_plist_entries(AFI_IP, index,
|
route_map_del_plist_entries(AFI_IP, index,
|
||||||
NULL, NULL);
|
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
|
* has been delete to the route-map index, update
|
||||||
* the route-map's prefix table.
|
* the route-map's prefix table.
|
||||||
*/
|
*/
|
||||||
if (strncmp(match_name, IPv4_PREFIX_LIST,
|
if (IS_RULE_IPv4_PREFIX_LIST(match_name)) {
|
||||||
strlen(IPv4_PREFIX_LIST)) == 0) {
|
|
||||||
route_map_pfx_tbl_update(
|
route_map_pfx_tbl_update(
|
||||||
RMAP_EVENT_PLIST_DELETED,
|
RMAP_EVENT_PLIST_DELETED,
|
||||||
index, AFI_IP,
|
index, AFI_IP,
|
||||||
match_arg);
|
match_arg);
|
||||||
} else if (strncmp(match_name, IPv6_PREFIX_LIST,
|
} else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) {
|
||||||
strlen(IPv6_PREFIX_LIST)) == 0) {
|
|
||||||
route_map_pfx_tbl_update(
|
route_map_pfx_tbl_update(
|
||||||
RMAP_EVENT_PLIST_DELETED,
|
RMAP_EVENT_PLIST_DELETED,
|
||||||
index, AFI_IP6,
|
index, AFI_IP6,
|
||||||
@ -1664,6 +1663,130 @@ route_map_apply_match(struct route_map_rule_list *match_list,
|
|||||||
return ret;
|
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
|
static int
|
||||||
route_map_candidate_list_cmp(struct route_map_index *idx1,
|
route_map_candidate_list_cmp(struct route_map_index *idx1,
|
||||||
struct route_map_index *idx2)
|
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;
|
match_list = &index->match_list;
|
||||||
for (rule = match_list->head; rule; rule = rule->next)
|
for (rule = match_list->head; rule; rule = rule->next)
|
||||||
if (strncmp(rule->cmd->str, IPv4_MATCH_RULE,
|
if (IS_IPv4_RULE(rule->cmd->str))
|
||||||
strlen(IPv4_MATCH_RULE)) == 0)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -1857,8 +1979,7 @@ route_map_is_ipv6_rule_present(struct route_map_index *index)
|
|||||||
|
|
||||||
match_list = &index->match_list;
|
match_list = &index->match_list;
|
||||||
for (rule = match_list->head; rule; rule = rule->next)
|
for (rule = match_list->head; rule; rule = rule->next)
|
||||||
if (strncmp(rule->cmd->str, IPv6_MATCH_RULE,
|
if (IS_IPv6_RULE(rule->cmd->str))
|
||||||
strlen(IPv6_MATCH_RULE)) == 0)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -1895,15 +2016,14 @@ route_map_add_plist_entries(afi_t afi,
|
|||||||
match_list = &index->match_list;
|
match_list = &index->match_list;
|
||||||
|
|
||||||
for (match = match_list->head; match; match = match->next) {
|
for (match = match_list->head; match; match = match->next) {
|
||||||
if (strncmp(
|
if (afi == AFI_IP) {
|
||||||
match->cmd->str,
|
if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str))
|
||||||
(afi == AFI_IP) ? IPv4_PREFIX_LIST :
|
plist_rule_is_present = true;
|
||||||
IPv6_PREFIX_LIST,
|
break;
|
||||||
strlen((afi == AFI_IP) ?
|
} else {
|
||||||
IPv4_PREFIX_LIST : IPv6_PREFIX_LIST))
|
if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str))
|
||||||
== 0) {
|
plist_rule_is_present = true;
|
||||||
plist_rule_is_present = true;
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1974,15 +2094,14 @@ route_map_del_plist_entries(afi_t afi,
|
|||||||
match_list = &index->match_list;
|
match_list = &index->match_list;
|
||||||
|
|
||||||
for (match = match_list->head; match; match = match->next) {
|
for (match = match_list->head; match; match = match->next) {
|
||||||
if (strncmp(
|
if (afi == AFI_IP) {
|
||||||
match->cmd->str,
|
if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str))
|
||||||
(afi == AFI_IP) ? IPv4_PREFIX_LIST :
|
plist_rule_is_present = true;
|
||||||
IPv6_PREFIX_LIST,
|
break;
|
||||||
strlen((afi == AFI_IP) ?
|
} else {
|
||||||
IPv4_PREFIX_LIST : IPv6_PREFIX_LIST))
|
if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str))
|
||||||
== 0) {
|
plist_rule_is_present = true;
|
||||||
plist_rule_is_present = true;
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2220,18 +2339,16 @@ route_map_pentry_process_dependency(struct hash_backet *backet,
|
|||||||
for (match = match_list->head; match; match = match->next) {
|
for (match = match_list->head; match; match = match->next) {
|
||||||
if (strcmp(match->rule_str, pentry_dep->plist_name)
|
if (strcmp(match->rule_str, pentry_dep->plist_name)
|
||||||
== 0) {
|
== 0) {
|
||||||
if ((strncmp(match->cmd->str, IPv4_PREFIX_LIST,
|
if (IS_RULE_IPv4_PREFIX_LIST(
|
||||||
strlen(IPv4_PREFIX_LIST)) == 0) &&
|
match->cmd->str) &&
|
||||||
family == AF_INET) {
|
family == AF_INET) {
|
||||||
route_map_pentry_update(
|
route_map_pentry_update(
|
||||||
pentry_dep->event,
|
pentry_dep->event,
|
||||||
pentry_dep->plist_name,
|
pentry_dep->plist_name,
|
||||||
index,
|
index,
|
||||||
pentry_dep->pentry);
|
pentry_dep->pentry);
|
||||||
} else if ((strncmp(match->cmd->str,
|
} else if (IS_RULE_IPv6_PREFIX_LIST(
|
||||||
IPv6_PREFIX_LIST,
|
match->cmd->str) &&
|
||||||
strlen(IPv6_PREFIX_LIST))
|
|
||||||
== 0) &&
|
|
||||||
family == AF_INET6) {
|
family == AF_INET6) {
|
||||||
route_map_pentry_update(
|
route_map_pentry_update(
|
||||||
pentry_dep->event,
|
pentry_dep->event,
|
||||||
@ -2330,9 +2447,10 @@ route_map_result_t route_map_apply(struct route_map *map,
|
|||||||
static int recursion = 0;
|
static int recursion = 0;
|
||||||
enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
|
enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
|
||||||
route_map_result_t ret = RMAP_PERMITMATCH;
|
route_map_result_t ret = RMAP_PERMITMATCH;
|
||||||
struct route_map_index *index;
|
struct route_map_index *index = NULL;
|
||||||
struct route_map_rule *set;
|
struct route_map_rule *set = NULL;
|
||||||
char buf[PREFIX_STRLEN];
|
char buf[PREFIX_STRLEN];
|
||||||
|
bool skip_match_clause = false;
|
||||||
|
|
||||||
if (recursion > RMAP_RECURSION_LIMIT) {
|
if (recursion > RMAP_RECURSION_LIMIT) {
|
||||||
flog_warn(
|
flog_warn(
|
||||||
@ -2349,18 +2467,56 @@ route_map_result_t route_map_apply(struct route_map *map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
map->applied++;
|
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) {
|
if ((!map->optimization_disabled) &&
|
||||||
zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s",
|
(map->ipv4_prefix_table ||
|
||||||
map->name, index->pref,
|
map->ipv6_prefix_table)) {
|
||||||
prefix2str(prefix, buf, sizeof(buf)),
|
index = route_map_get_index(map, prefix,
|
||||||
route_map_cmd_result_str(match_ret));
|
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 */
|
/* Now we apply the matrix from above */
|
||||||
if (match_ret == RMAP_NOOP)
|
if (match_ret == RMAP_NOOP)
|
||||||
|
Loading…
Reference in New Issue
Block a user