From f4dd829679f33495622a9f3d40c9a5aca925df72 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Mon, 9 Aug 2021 13:34:57 +0300 Subject: [PATCH 1/2] bgpd: BGP extended [l]community-list regexp match must work with aliases We have to convert BGP alias to numerical format to compare in regexp. Signed-off-by: Donatas Abraitis --- bgpd/bgp_clist.c | 5 +++-- bgpd/bgp_community_alias.c | 40 ++++++++++++++++++++++++++++++++++++++ bgpd/bgp_community_alias.h | 2 ++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 50122ad7da..fd8f51fed3 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -33,6 +33,7 @@ #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_lcommunity.h" +#include "bgpd/bgp_community_alias.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_clist.h" @@ -557,7 +558,7 @@ static bool community_regexp_match(struct community *com, regex_t *reg) str = community_str(com, false); /* Regular expression match. */ - if (regexec(reg, str, 0, NULL, 0) == 0) + if (regexec(reg, bgp_alias2community_str(str), 0, NULL, 0) == 0) return true; /* No match. */ @@ -627,7 +628,7 @@ static bool lcommunity_regexp_match(struct lcommunity *com, regex_t *reg) str = lcommunity_str(com, false); /* Regular expression match. */ - if (regexec(reg, str, 0, NULL, 0) == 0) + if (regexec(reg, bgp_alias2community_str(str), 0, NULL, 0) == 0) return true; /* No match. */ diff --git a/bgpd/bgp_community_alias.c b/bgpd/bgp_community_alias.c index f770ebdd5d..5f45e19a3b 100644 --- a/bgpd/bgp_community_alias.c +++ b/bgpd/bgp_community_alias.c @@ -20,6 +20,7 @@ #include "memory.h" #include "lib/jhash.h" +#include "frrstr.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_community_alias.h" @@ -153,6 +154,45 @@ const char *bgp_community2alias(char *community) return community; } +const char *bgp_alias2community(char *alias) +{ + struct community_alias ca; + struct community_alias *find; + + memset(&ca, 0, sizeof(ca)); + strlcpy(ca.alias, alias, sizeof(ca.alias)); + + find = bgp_ca_alias_lookup(&ca); + if (find) + return find->community; + + return alias; +} + +/* Communities structs have `->str` which is used + * for vty outputs and extended BGP community lists + * with regexp. + * This is a helper to convert already aliased version + * of communities into numerical-only format. + */ +const char *bgp_alias2community_str(const char *str) +{ + char **aliases; + int num; + + frrstr_split(str, " ", &aliases, &num); + const char *communities[num + 1]; + + for (int i = 0; i < num; i++) { + communities[i] = + XSTRDUP(MTYPE_TMP, bgp_alias2community(aliases[i])); + XFREE(MTYPE_TMP, aliases[i]); + } + XFREE(MTYPE_TMP, aliases); + + return frrstr_join(communities, num, " "); +} + static int bgp_community_alias_vector_walker(struct hash_bucket *bucket, void *data) { diff --git a/bgpd/bgp_community_alias.h b/bgpd/bgp_community_alias.h index ab8ed06ee6..fc9eb9f9e4 100644 --- a/bgpd/bgp_community_alias.h +++ b/bgpd/bgp_community_alias.h @@ -42,6 +42,8 @@ extern void bgp_ca_community_delete(struct community_alias *ca); extern void bgp_ca_alias_delete(struct community_alias *ca); extern int bgp_community_alias_write(struct vty *vty); extern const char *bgp_community2alias(char *community); +extern const char *bgp_alias2community(char *alias); +extern const char *bgp_alias2community_str(const char *str); extern void bgp_community_alias_command_completion_setup(void); #endif /* FRR_BGP_COMMUNITY_ALIAS_H */ From 947a27f5aefac98b24146f8a7db65891c0f48038 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Mon, 9 Aug 2021 15:37:37 +0300 Subject: [PATCH 2/2] tests: Make sure BGP filters by community lists work with community alias Signed-off-by: Donatas Abraitis --- tests/topotests/bgp_community_alias/r1/bgpd.conf | 2 ++ .../bgp_community_alias/test_bgp-community-alias.py | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/tests/topotests/bgp_community_alias/r1/bgpd.conf b/tests/topotests/bgp_community_alias/r1/bgpd.conf index a6366204e8..13b57ad243 100644 --- a/tests/topotests/bgp_community_alias/r1/bgpd.conf +++ b/tests/topotests/bgp_community_alias/r1/bgpd.conf @@ -3,6 +3,8 @@ bgp community alias 65001:1 community-r2-1 bgp community alias 65002:2 community-r2-2 bgp community alias 65001:1:1 large-community-r2-1 ! +bgp large-community-list expanded r2 seq 5 permit _65001:1:1_ +! router bgp 65001 no bgp ebgp-requires-policy neighbor 192.168.1.2 remote-as external diff --git a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py index 6aadff1cfa..26933a7992 100644 --- a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py +++ b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py @@ -138,6 +138,17 @@ def test_bgp_community_alias(): success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP prefixes by community alias at r1" + def _bgp_show_prefixes_by_large_community_list(router): + output = json.loads( + router.vtysh_cmd("show bgp ipv4 unicast large-community-list r2 json") + ) + expected = {"routes": {"172.16.16.1/32": [{"valid": True}]}} + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_show_prefixes_by_large_community_list, router) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Cannot see BGP prefixes by large community list at r1" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:]