Skip to content

Commit

Permalink
Merge pull request #18159 from pguibert6WIND/bgp_ecommlist_count
Browse files Browse the repository at this point in the history
Bgp ecommlist count
  • Loading branch information
ton31337 authored Feb 28, 2025
2 parents e27631e + 2b71dc2 commit d49561e
Show file tree
Hide file tree
Showing 16 changed files with 655 additions and 14 deletions.
67 changes: 67 additions & 0 deletions bgpd/bgp_clist.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,11 @@ static bool community_regexp_match(struct community *com, regex_t *reg)
return rv == 0;
}

static char *ecommunity_str_get(struct ecommunity *ecom, int i)
{
return ecommunity_ecom2str_one(ecom, ECOMMUNITY_FORMAT_DISPLAY, i);
}

static char *lcommunity_str_get(struct lcommunity *lcom, int i)
{
struct lcommunity_val lcomval;
Expand Down Expand Up @@ -611,6 +616,29 @@ static bool lcommunity_regexp_include(regex_t *reg, struct lcommunity *lcom,
return false;
}

/* Internal function to perform regular expression match for a single ecommunity. */
static bool ecommunity_regexp_include(regex_t *reg, struct ecommunity *ecom, int i)
{
char *str;

/* When there is no communities attribute it is treated as empty string.
*/
if (ecom == NULL || ecom->size == 0)
str = XSTRDUP(MTYPE_ECOMMUNITY_STR, "");
else
str = ecommunity_str_get(ecom, i);

/* Regular expression match. */
if (regexec(reg, str, 0, NULL, 0) == 0) {
XFREE(MTYPE_ECOMMUNITY_STR, str);
return true;
}

XFREE(MTYPE_ECOMMUNITY_STR, str);
/* No match. */
return false;
}

static bool lcommunity_regexp_match(struct lcommunity *com, regex_t *reg)
{
const char *str;
Expand Down Expand Up @@ -697,6 +725,24 @@ bool lcommunity_list_match(struct lcommunity *lcom, struct community_list *list)
return false;
}

/* Perform exact matching. In case of expanded extended-community-list, do
* same thing as ecommunity_list_match().
*/
bool ecommunity_list_exact_match(struct ecommunity *ecom, struct community_list *list)
{
struct community_entry *entry;

for (entry = list->head; entry; entry = entry->next) {
if (entry->style == EXTCOMMUNITY_LIST_STANDARD) {
if (ecommunity_cmp(ecom, entry->u.lcom))
return entry->direct == COMMUNITY_PERMIT;
} else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED) {
if (ecommunity_regexp_match(ecom, entry->reg))
return entry->direct == COMMUNITY_PERMIT;
}
}
return false;
}

/* Perform exact matching. In case of expanded large-community-list, do
* same thing as lcommunity_list_match().
Expand Down Expand Up @@ -981,6 +1027,27 @@ bool lcommunity_list_any_match(struct lcommunity *lcom,
return false;
}

bool ecommunity_list_any_match(struct ecommunity *ecom, struct community_list *list)
{
struct community_entry *entry;
uint8_t *ptr;
uint32_t i;

for (i = 0; i < ecom->size; i++) {
ptr = ecom->val + (i * ecom->unit_size);

for (entry = list->head; entry; entry = entry->next) {
if ((entry->style == EXTCOMMUNITY_LIST_STANDARD) &&
ecommunity_include_one(entry->u.ecom, ptr))
return entry->direct == COMMUNITY_PERMIT;
if ((entry->style == EXTCOMMUNITY_LIST_EXPANDED) &&
ecommunity_regexp_include(entry->reg, ecom, i))
return entry->direct == COMMUNITY_PERMIT;
}
}
return false;
}

/* Delete all permitted large communities in the list from com. */
struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
struct community_list *list)
Expand Down
2 changes: 2 additions & 0 deletions bgpd/bgp_clist.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ extern bool lcommunity_list_match(struct lcommunity *lcom,
struct community_list *list);
extern bool community_list_exact_match(struct community *com,
struct community_list *list);
extern bool ecommunity_list_exact_match(struct ecommunity *com, struct community_list *list);
extern bool lcommunity_list_exact_match(struct lcommunity *lcom,
struct community_list *list);
extern bool community_list_any_match(struct community *com,
Expand All @@ -166,6 +167,7 @@ extern struct community *
community_list_match_delete(struct community *com, struct community_list *list);
extern bool lcommunity_list_any_match(struct lcommunity *lcom,
struct community_list *list);
extern bool ecommunity_list_any_match(struct ecommunity *ecom, struct community_list *list);
extern struct lcommunity *
lcommunity_list_match_delete(struct lcommunity *lcom,
struct community_list *list);
Expand Down
31 changes: 29 additions & 2 deletions bgpd/bgp_ecommunity.c
Original file line number Diff line number Diff line change
Expand Up @@ -1145,8 +1145,10 @@ bool ecommunity_has_route_target(struct ecommunity *ecom)
*
* Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
* 0 value displays all.
* Index is a unsigned integer value, and stands for the extended community list entry
* to display when value is not -1.
*/
char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
static char *_ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter, int index)
{
uint32_t i;
uint8_t *pnt;
Expand All @@ -1168,8 +1170,10 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
bool unk_ecom = false;
memset(encbuf, 0x00, sizeof(encbuf));

if (index != -1 && (uint32_t)index != i)
continue;
/* Space between each value. */
if (i > 0)
if (index == -1 && i > 0)
strlcat(str_buf, " ", str_size);

/* Retrieve value field */
Expand Down Expand Up @@ -1496,6 +1500,29 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
return str_buf;
}

char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
{
return _ecommunity_ecom2str(ecom, format, filter, -1);
}

char *ecommunity_ecom2str_one(struct ecommunity *ecom, int format, int number)
{
return _ecommunity_ecom2str(ecom, format, 0, number);
}

bool ecommunity_include_one(struct ecommunity *ecom, uint8_t *ptr)
{
uint32_t i;
uint8_t *ecom_ptr;

for (i = 0; i < ecom->size; i++) {
ecom_ptr = ecom->val + (i * ecom->unit_size);
if (memcmp(ptr, ecom_ptr, ecom->unit_size) == 0)
return true;
}
return false;
}

bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2)
{
uint32_t i, j;
Expand Down
4 changes: 3 additions & 1 deletion bgpd/bgp_ecommunity.h
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,11 @@ extern unsigned int ecommunity_hash_make(const void *);
extern struct ecommunity *ecommunity_str2com(const char *, int, int);
extern struct ecommunity *ecommunity_str2com_ipv6(const char *str, int type,
int keyword_included);
extern char *ecommunity_ecom2str(struct ecommunity *, int, int);
extern char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter);
extern char *ecommunity_ecom2str_one(struct ecommunity *ecom, int format, int number);
extern bool ecommunity_has_route_target(struct ecommunity *ecom);
extern void ecommunity_strfree(char **s);
extern bool ecommunity_include_one(struct ecommunity *ecom, uint8_t *ptr);
extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2);
extern bool ecommunity_match(const struct ecommunity *,
const struct ecommunity *);
Expand Down
145 changes: 137 additions & 8 deletions bgpd/bgp_routemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,65 @@ static const struct route_map_rule_cmd route_match_community_limit_cmd = {
route_match_community_limit_compile, route_match_community_limit_free
};

/* `match extcommunity-limit' */

/* Match function should return :
* - RMAP_MATCH if the bgp update extcommunity list count
* is less or equal to the configured limit.
* - RMAP_NOMATCH if the extcommunity list count is greater than the
* configured limit.
*/
static enum route_map_cmd_result_t
route_match_extcommunity_limit(void *rule, const struct prefix *prefix, void *object)
{
struct bgp_path_info *path = NULL;
struct ecommunity *piextcomm = NULL, *pi6extcomm = NULL;
uint16_t count = 0;
uint16_t *limit_rule = rule;

path = (struct bgp_path_info *)object;

piextcomm = bgp_attr_get_ecommunity(path->attr);
if (piextcomm)
count = piextcomm->size;

pi6extcomm = bgp_attr_get_ipv6_ecommunity(path->attr);
if (pi6extcomm)
count += pi6extcomm->size;

if (count <= *limit_rule)
return RMAP_MATCH;

return RMAP_NOMATCH;
}

/* Route map `extcommunity-limit' match statement. */
static void *route_match_extcommunity_limit_compile(const char *arg)
{
uint16_t *limit = NULL;
char *end = NULL;

limit = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint16_t));
*limit = strtoul(arg, &end, 10);
if (*end != '\0') {
XFREE(MTYPE_ROUTE_MAP_COMPILED, limit);
return NULL;
}
return limit;
}

/* Free route map's compiled `community-limit' value. */
static void route_match_extcommunity_limit_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}

/* Route map commands for community limit matching. */
static const struct route_map_rule_cmd route_match_extcommunity_limit_cmd = {
"extcommunity-limit", route_match_extcommunity_limit,
route_match_extcommunity_limit_compile, route_match_extcommunity_limit_free
};

static enum route_map_cmd_result_t
route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
{
Expand Down Expand Up @@ -1853,8 +1912,18 @@ route_match_ecommunity(void *rule, const struct prefix *prefix, void *object)
if (!list)
return RMAP_NOMATCH;

if (ecommunity_list_match(bgp_attr_get_ecommunity(path->attr), list))
return RMAP_MATCH;
if (rcom->exact) {
if (ecommunity_list_exact_match(bgp_attr_get_ecommunity(path->attr), list))
return RMAP_MATCH;
} else if (rcom->any) {
if (!bgp_attr_get_ecommunity(path->attr))
return RMAP_OKAY;
if (ecommunity_list_any_match(bgp_attr_get_ecommunity(path->attr), list))
return RMAP_MATCH;
} else {
if (ecommunity_list_match(bgp_attr_get_ecommunity(path->attr), list))
return RMAP_MATCH;
}

return RMAP_NOMATCH;
}
Expand All @@ -1863,11 +1932,28 @@ route_match_ecommunity(void *rule, const struct prefix *prefix, void *object)
static void *route_match_ecommunity_compile(const char *arg)
{
struct rmap_community *rcom;
int len;
char *p;

rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
rcom->name_hash = bgp_clist_hash_key(rcom->name);

p = strchr(arg, ' ');
if (p) {
len = p - arg;
rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1);
memcpy(rcom->name, arg, len);
p++;
if (*p == 'e')
rcom->exact = true;
else
rcom->any = true;
} else {
rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
rcom->exact = false;
rcom->any = false;
}

rcom->name_hash = bgp_clist_hash_key(rcom->name);
return rcom;
}

Expand Down Expand Up @@ -5861,16 +5947,19 @@ DEFUN_YANG(

DEFPY_YANG (match_ecommunity,
match_ecommunity_cmd,
"match extcommunity <(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME>",
"match extcommunity <(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]",
MATCH_STR
"Match BGP/VPN extended community list\n"
"Extended community-list number (standard)\n"
"Extended community-list number (expanded)\n"
"Extended community-list name\n")
"Extended community-list name\n"
"Do exact matching of communities\n"
"Do matching of any community\n")
{
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:match-extcommunity']";
char xpath_value[XPATH_MAXLEN];
char xpath_match[XPATH_MAXLEN];
int idx_comm_list = 2;

nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
Expand All @@ -5881,19 +5970,57 @@ DEFPY_YANG (match_ecommunity,
xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_comm_list]->arg);

snprintf(xpath_match, sizeof(xpath_match),
"%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match",
xpath);
if (exact)
nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true");
else
nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false");

snprintf(xpath_match, sizeof(xpath_match),
"%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any", xpath);
if (any)
nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true");
else
nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false");

return nb_cli_apply_changes(vty, NULL);
}


DEFPY_YANG(
match_extcommunity_limit, match_extcommunity_limit_cmd,
"[no$no] match extcommunity-limit ![(0-65535)$limit]",
NO_STR
MATCH_STR
"Match BGP extended community limit\n"
"Extended community limit number\n")
{
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:match-extcommunity-limit']";
char xpath_value[XPATH_MAXLEN];

nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, NULL);
snprintf(xpath_value, sizeof(xpath_value),
"%s/rmap-match-condition/frr-bgp-route-map:extcommunity-limit", xpath);

nb_cli_enqueue_change(vty, xpath_value, no ? NB_OP_DESTROY : NB_OP_MODIFY, limit_str);
return nb_cli_apply_changes(vty, NULL);
}


DEFUN_YANG (no_match_ecommunity,
no_match_ecommunity_cmd,
"no match extcommunity [<(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME>]",
"no match extcommunity [<(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]]",
NO_STR
MATCH_STR
"Match BGP/VPN extended community list\n"
"Extended community-list number (standard)\n"
"Extended community-list number (expanded)\n"
"Extended community-list name\n")
"Extended community-list name\n"
"Do exact matching of communities\n"
"Do matching of any community\n")
{
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:match-extcommunity']";
Expand Down Expand Up @@ -7980,6 +8107,7 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_evpn_route_type_cmd);
route_map_install_match(&route_match_evpn_rd_cmd);
route_map_install_match(&route_match_community_limit_cmd);
route_map_install_match(&route_match_extcommunity_limit_cmd);
route_map_install_match(&route_match_evpn_default_route_cmd);
route_map_install_match(&route_match_vrl_source_vrf_cmd);

Expand Down Expand Up @@ -8053,6 +8181,7 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &match_community_cmd);
install_element(RMAP_NODE, &no_match_community_cmd);
install_element(RMAP_NODE, &match_community_limit_cmd);
install_element(RMAP_NODE, &match_extcommunity_limit_cmd);
install_element(RMAP_NODE, &match_lcommunity_cmd);
install_element(RMAP_NODE, &no_match_lcommunity_cmd);
install_element(RMAP_NODE, &match_ecommunity_cmd);
Expand Down
Loading

0 comments on commit d49561e

Please sign in to comment.