From a70a28a57796635cbb7edc56cdfa1acddb186630 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 19 May 2021 17:04:48 +0300 Subject: [PATCH 1/4] bgpd: Show BGP prefixes by community alias This includes both community/large-community. Signed-off-by: Donatas Abraitis --- bgpd/bgp_route.c | 138 +++++++++++++++++++++++++++++++++-------------- bgpd/bgp_route.h | 1 + 2 files changed, 98 insertions(+), 41 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 2c792b7abf..dd1e8471e6 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -23,6 +23,7 @@ #include #include "printfrr.h" +#include "frrstr.h" #include "prefix.h" #include "linklist.h" #include "memory.h" @@ -10570,7 +10571,6 @@ static int bgp_show_community(struct vty *vty, struct bgp *bgp, const char *comstr, int exact, afi_t afi, safi_t safi, uint8_t show_flags); - static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, struct bgp_table *table, enum bgp_show_type type, void *output_arg, char *rd, int is_last, @@ -10647,6 +10647,48 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, continue; } + if (type == bgp_show_type_community_alias) { + char *alias = output_arg; + char **communities; + int num; + bool found = false; + + if (pi->attr->community) { + frrstr_split(pi->attr->community->str, + " ", &communities, &num); + for (int i = 0; i < num; i++) { + const char *com2alias = + bgp_community2alias( + communities[i]); + if (strncmp(alias, com2alias, + strlen(com2alias)) + == 0) { + found = true; + break; + } + } + } + + if (!found && pi->attr->lcommunity) { + frrstr_split(pi->attr->lcommunity->str, + " ", &communities, &num); + for (int i = 0; i < num; i++) { + const char *com2alias = + bgp_community2alias( + communities[i]); + if (strncmp(alias, com2alias, + strlen(com2alias)) + == 0) { + found = true; + break; + } + } + } + + if (!found) + continue; + } + if (type == bgp_show_type_rpki) { if (dest_p->family == AF_INET || dest_p->family == AF_INET6) @@ -11920,9 +11962,10 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, } /* BGP route print out function with JSON */ -DEFPY (show_ip_bgp_json, - show_ip_bgp_json_cmd, - "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\ +DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, + "show [ip] bgp [ VIEWVRFNAME] [" BGP_AFI_CMD_STR + " [" BGP_SAFI_WITH_LABEL_CMD_STR + "]]\ [all$all]\ [cidr-only\ |dampening \ @@ -11933,44 +11976,41 @@ DEFPY (show_ip_bgp_json, |route-filter-translated-v4] [exact-match]\ |rpki \ |version (1-4294967295)\ + |alias WORD\ ] [json$uj [detail$detail] | wide$wide]", - SHOW_STR - IP_STR - BGP_STR - BGP_INSTANCE_HELP_STR - BGP_AFI_HELP_STR - BGP_SAFI_WITH_LABEL_HELP_STR - "Display the entries for all address families\n" - "Display only routes with non-natural netmasks\n" - "Display detailed information about dampening\n" - "Display flap statistics of routes\n" - "Display paths suppressed due to dampening\n" - "Display routes matching the communities\n" - COMMUNITY_AANN_STR - "Do not send outside local AS (well-known community)\n" - "Do not advertise to any peer (well-known community)\n" - "Do not export to next AS (well-known community)\n" - "Graceful shutdown (well-known community)\n" - "Do not export to any peer (well-known community)\n" - "Inform EBGP peers to blackhole traffic to prefix (well-known community)\n" - "Staled Long-lived Graceful Restart VPN route (well-known community)\n" - "Removed because Long-lived Graceful Restart was not enabled for VPN route (well-known community)\n" - "Should accept local VPN route if exported and imported into different VRF (well-known community)\n" - "Should accept VPN route with local nexthop (well-known community)\n" - "RT VPNv6 route filtering (well-known community)\n" - "RT VPNv4 route filtering (well-known community)\n" - "RT translated VPNv6 route filtering (well-known community)\n" - "RT translated VPNv4 route filtering (well-known community)\n" - "Exact match of the communities\n" - "RPKI route types\n" - "A valid path as determined by rpki\n" - "A invalid path as determined by rpki\n" - "A path that has no rpki data\n" - "Display prefixes with matching version numbers\n" - "Version number and above\n" - JSON_STR - "Display detailed version of JSON output\n" - "Increase table width for longer prefixes\n") + SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR + BGP_SAFI_WITH_LABEL_HELP_STR + "Display the entries for all address families\n" + "Display only routes with non-natural netmasks\n" + "Display detailed information about dampening\n" + "Display flap statistics of routes\n" + "Display paths suppressed due to dampening\n" + "Display routes matching the communities\n" COMMUNITY_AANN_STR + "Do not send outside local AS (well-known community)\n" + "Do not advertise to any peer (well-known community)\n" + "Do not export to next AS (well-known community)\n" + "Graceful shutdown (well-known community)\n" + "Do not export to any peer (well-known community)\n" + "Inform EBGP peers to blackhole traffic to prefix (well-known community)\n" + "Staled Long-lived Graceful Restart VPN route (well-known community)\n" + "Removed because Long-lived Graceful Restart was not enabled for VPN route (well-known community)\n" + "Should accept local VPN route if exported and imported into different VRF (well-known community)\n" + "Should accept VPN route with local nexthop (well-known community)\n" + "RT VPNv6 route filtering (well-known community)\n" + "RT VPNv4 route filtering (well-known community)\n" + "RT translated VPNv6 route filtering (well-known community)\n" + "RT translated VPNv4 route filtering (well-known community)\n" + "Exact match of the communities\n" + "RPKI route types\n" + "A valid path as determined by rpki\n" + "A invalid path as determined by rpki\n" + "A path that has no rpki data\n" + "Display prefixes with matching version numbers\n" + "Version number and above\n" + "Display prefixes with matching BGP community alias\n" + "BGP community alias\n" JSON_STR + "Display detailed version of JSON output\n" + "Increase table width for longer prefixes\n") { afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; @@ -11980,6 +12020,7 @@ DEFPY (show_ip_bgp_json, int exact_match = 0; char *community = NULL; char *prefix_version = NULL; + char *bgp_community_alias = NULL; bool first = true; uint8_t show_flags = 0; enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED; @@ -12056,6 +12097,12 @@ DEFPY (show_ip_bgp_json, prefix_version = argv[idx + 1]->arg; } + /* Display prefixes with matching BGP community alias */ + if (argv_find(argv, argc, "alias", &idx)) { + sh_type = bgp_show_type_community_alias; + bgp_community_alias = argv[idx + 1]->arg; + } + if (!all) { /* show bgp: AFI_IP6, show ip bgp: AFI_IP */ if (community) @@ -12066,6 +12113,10 @@ DEFPY (show_ip_bgp_json, return bgp_show(vty, bgp, afi, safi, sh_type, prefix_version, show_flags, rpki_target_state); + else if (bgp_community_alias) + return bgp_show(vty, bgp, afi, safi, sh_type, + bgp_community_alias, show_flags, + rpki_target_state); else return bgp_show(vty, bgp, afi, safi, sh_type, NULL, show_flags, rpki_target_state); @@ -12108,6 +12159,11 @@ DEFPY (show_ip_bgp_json, sh_type, prefix_version, show_flags, rpki_target_state); + else if (bgp_community_alias) + return bgp_show( + vty, bgp, afi, safi, sh_type, + bgp_community_alias, show_flags, + rpki_target_state); else bgp_show(vty, bgp, afi, safi, sh_type, NULL, show_flags, diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e58213a688..6d6008ff55 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -42,6 +42,7 @@ enum bgp_show_type { bgp_show_type_neighbor, bgp_show_type_cidr_only, bgp_show_type_prefix_longer, + bgp_show_type_community_alias, bgp_show_type_community_all, bgp_show_type_community, bgp_show_type_community_exact, From b15be1605afa5d14c7794d0dd7db49c0b147905f Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 19 May 2021 17:47:23 +0300 Subject: [PATCH 2/4] tests: Show BGP prefixes by community alias Signed-off-by: Donatas Abraitis --- .../bgp_community_alias/r1/bgpd.conf | 4 +-- .../bgp_community_alias/r2/bgpd.conf | 13 +++++++--- .../bgp_community_alias/r2/zebra.conf | 4 +++ .../test_bgp-community-alias.py | 26 ++++++++++++++++--- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/tests/topotests/bgp_community_alias/r1/bgpd.conf b/tests/topotests/bgp_community_alias/r1/bgpd.conf index 2cf84d0b70..06113bdd2a 100644 --- a/tests/topotests/bgp_community_alias/r1/bgpd.conf +++ b/tests/topotests/bgp_community_alias/r1/bgpd.conf @@ -1,7 +1,7 @@ ! -bgp community alias 65002:1 community-r2-1 +bgp community alias 65001:1 community-r2-1 bgp community alias 65002:2 community-r2-2 -bgp community alias 65002:1:1 large-community-r2-1 +bgp community alias 65001:1:1 large-community-r2-1 ! router bgp 65001 no bgp ebgp-requires-policy diff --git a/tests/topotests/bgp_community_alias/r2/bgpd.conf b/tests/topotests/bgp_community_alias/r2/bgpd.conf index 517ef70f2a..fc67ff2ad2 100644 --- a/tests/topotests/bgp_community_alias/r2/bgpd.conf +++ b/tests/topotests/bgp_community_alias/r2/bgpd.conf @@ -6,7 +6,14 @@ router bgp 65002 neighbor 192.168.1.1 route-map r1 out exit-address-family ! -route-map r1 permit 10 - set community 65002:1 65002:2 - set large-community 65002:1:1 65002:2:1 +ip prefix-list p1 permit 172.16.16.1/32 +ip prefix-list p2 permit 172.16.16.2/32 +! +route-map r1 permit 10 + match ip address prefix-list p1 + set community 65001:1 65001:2 + set large-community 65001:1:1 65001:1:2 +route-map r1 permit 20 + match ip address prefix-list p2 + set community 65002:1 65002:2 ! diff --git a/tests/topotests/bgp_community_alias/r2/zebra.conf b/tests/topotests/bgp_community_alias/r2/zebra.conf index cffe827363..a806628a8e 100644 --- a/tests/topotests/bgp_community_alias/r2/zebra.conf +++ b/tests/topotests/bgp_community_alias/r2/zebra.conf @@ -1,4 +1,8 @@ ! +int lo + ip address 172.16.16.1/32 + ip address 172.16.16.2/32 +! int r2-eth0 ip address 192.168.1.2/24 ! 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 a43e5f937e..90eeaaa731 100644 --- a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py +++ b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py @@ -84,12 +84,14 @@ def test_bgp_community_alias(): router = tgen.gears["r1"] def _bgp_converge(router): - output = json.loads(router.vtysh_cmd("show ip bgp 192.168.1.0/24 json")) + output = json.loads( + router.vtysh_cmd("show bgp ipv4 unicast 172.16.16.1/32 json") + ) expected = { "paths": [ { - "community": {"string": "community-r2-1 community-r2-2"}, - "largeCommunity": {"string": "large-community-r2-1 65002:2:1"}, + "community": {"string": "community-r2-1 65001:2"}, + "largeCommunity": {"string": "large-community-r2-1 65001:1:2"}, } ] } @@ -97,9 +99,25 @@ def test_bgp_community_alias(): test_func = functools.partial(_bgp_converge, router) success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) - assert result is None, 'Cannot see BGP community aliases "{}"'.format(router) + def _bgp_show_prefixes_by_alias(router): + output = json.loads( + router.vtysh_cmd("show bgp ipv4 unicast alias community-r2-2 json detail") + ) + expected = { + "routes": { + "172.16.16.2/32": [{"community": {"string": "65002:1 community-r2-2"}}] + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_show_prefixes_by_alias, router) + 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 "{}"'.format( + router + ) + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] From 9f977b2def6b2d542d84913f59d4e6ced15e0f1a Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 19 May 2021 18:20:08 +0300 Subject: [PATCH 3/4] doc: Show BGP prefixes by community alias Signed-off-by: Donatas Abraitis --- doc/user/bgp.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index f6aa5d1ca0..7f653cb7b7 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -2111,6 +2111,10 @@ things on the wire. Large Community: lcommunity-1 65001:123:2 Last update: Fri Apr 16 12:51:27 2021 +.. clicmd:: show bgp [afi] [safi] [all] alias WORD [wide|json] + + Display prefixes with matching BGP community alias. + .. _bgp-using-communities-in-route-map: Using Communities in Route Maps From d95a84e0a515c9d04efe0aae0da4f8f9c0d8defd Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 19 May 2021 18:24:20 +0300 Subject: [PATCH 4/4] bgpd: Show BGP community alias in JSON community list output Before: ``` "community":{ "string":"first 65001:2 65001:3", "list":[ "65001:1", "65001:2", "65001:3" ] }, ``` After: ``` "community":{ "string":"first 65001:2 65001:3", "list":[ "first", "65001:2", "65001:3" ] }, ``` Signed-off-by: Donatas Abraitis --- bgpd/bgp_community.c | 6 ++++-- bgpd/bgp_lcommunity.c | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index b034ec9f7b..2aa6a56a5e 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -451,9 +451,11 @@ static void set_community_string(struct community *com, bool make_json) val = comval & 0xFFFF; char buf[32]; snprintf(buf, sizeof(buf), "%u:%d", as, val); - strlcat(str, bgp_community2alias(buf), len); + const char *com2alias = bgp_community2alias(buf); + + strlcat(str, com2alias, len); if (make_json) { - json_string = json_object_new_string(buf); + json_string = json_object_new_string(com2alias); json_object_array_add(json_community_list, json_string); } diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index ff34937efc..fa4d4aee28 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -232,11 +232,13 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) snprintf(lcsb, sizeof(lcsb), "%u:%u:%u", global, local1, local2); - len = strlcat(str_buf, bgp_community2alias(lcsb), str_buf_sz); + const char *com2alias = bgp_community2alias(lcsb); + + len = strlcat(str_buf, com2alias, str_buf_sz); assert((unsigned int)len < str_buf_sz); if (make_json) { - json_string = json_object_new_string(lcsb); + json_string = json_object_new_string(com2alias); json_object_array_add(json_lcommunity_list, json_string); }