From c2d832ac9556f0f27c947163e3a767c571c26e10 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 17 Nov 2023 08:39:33 +0200 Subject: [PATCH] bgpd: Add an ability to filter UPDATEs using neighbor with prefix-list Before this patch we didn't have an option to filter debug UPDATE messages by specifying an arbitrary prefix, prefix-list or so. We had/have only an option to specify: ``` * debug bgp updates in 10.0.0.1 * debug bgp updates prefix 10.0.1.0/24 ``` Now adding: ``` * debug bgp updates 10.0.0.1 prefix-list plist ``` CLI output: ``` r2# show debugging MGMT debugging status: Zebra debugging status: BGP debugging status: BGP updates debugging is on (inbound) for 192.168.2.6 with prefix-list debug Staticd debugging status r2# show running-config | include prefix-list debug debug bgp updates in 192.168.2.6 prefix-list debug r2# ``` Logs: ``` BGP: [PCFFM-WMARW] 192.168.2.3(r3) rcvd UPDATE wlen 0 attrlen 28 alen 5 BGP: [PCFFM-WMARW] 192.168.2.3(r3) rcvd UPDATE wlen 0 attrlen 28 alen 4 BGP: [PCFFM-WMARW] 192.168.2.3(r3) rcvd UPDATE wlen 0 attrlen 0 alen 0 BGP: [M59KS-A3ZXZ] bgp_update_receive: rcvd End-of-RIB for IPv4 Unicast from 192.168.2.3 in vrf default BGP: [PCFFM-WMARW] 192.168.2.4(r4) rcvd UPDATE wlen 0 attrlen 28 alen 5 BGP: [PCFFM-WMARW] 192.168.2.4(r4) rcvd UPDATE wlen 0 attrlen 28 alen 4 BGP: [PCFFM-WMARW] 192.168.2.4(r4) rcvd UPDATE wlen 0 attrlen 0 alen 0 BGP: [M59KS-A3ZXZ] bgp_update_receive: rcvd End-of-RIB for IPv4 Unicast from 192.168.2.4 in vrf default BGP: [PCFFM-WMARW] 192.168.1.1(r1) rcvd UPDATE wlen 0 attrlen 29 alen 5 BGP: [PCFFM-WMARW] 192.168.2.6(r6) rcvd UPDATE wlen 0 attrlen 28 alen 5 BGP: [XXWBM-V772F] 192.168.2.6(r6) rcvd UPDATE w/ attr: nexthop 192.168.2.6, origin ?, metric 0, path 65006 BGP: [YCKEM-GB33T] 192.168.2.6(r6) rcvd 172.16.16.254/32 IPv4 unicast <<<<<<<<<<<< BGP: [PCFFM-WMARW] 192.168.2.6(r6) rcvd UPDATE wlen 0 attrlen 28 alen 4 BGP: [PCFFM-WMARW] 192.168.2.6(r6) rcvd UPDATE wlen 0 attrlen 0 alen 0 BGP: [M59KS-A3ZXZ] bgp_update_receive: rcvd End-of-RIB for IPv4 Unicast from 192.168.2.6 in vrf default BGP: [PCFFM-WMARW] 192.168.2.5(r5) rcvd UPDATE wlen 0 attrlen 28 alen 5 BGP: [PCFFM-WMARW] 192.168.2.5(r5) rcvd UPDATE wlen 0 attrlen 28 alen 4 BGP: [PCFFM-WMARW] 192.168.2.5(r5) rcvd UPDATE wlen 0 attrlen 0 alen 0 BGP: [M59KS-A3ZXZ] bgp_update_receive: rcvd End-of-RIB for IPv4 Unicast from 192.168.2.5 in vrf default BGP: [PCFFM-WMARW] 192.168.1.1(r1) rcvd UPDATE wlen 0 attrlen 29 alen 5 BGP: [PCFFM-WMARW] 192.168.7.7(r7) rcvd UPDATE wlen 0 attrlen 0 alen 0 BGP: [M59KS-A3ZXZ] bgp_update_receive: rcvd End-of-RIB for IPv4 Unicast from 192.168.7.7 in vrf default ``` Signed-off-by: Donatas Abraitis --- bgpd/bgp_debug.c | 130 +++++++++++++++++++++++++++++++---------------- bgpd/bgp_debug.h | 1 + 2 files changed, 86 insertions(+), 45 deletions(-) diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 123a1cacf3fe..059f921ed10a 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -216,6 +216,7 @@ static void bgp_debug_list_free(struct list *list) listnode_delete(list, filter); prefix_free(&filter->p); XFREE(MTYPE_BGP_DEBUG_STR, filter->host); + XFREE(MTYPE_BGP_DEBUG_STR, filter->plist_name); XFREE(MTYPE_BGP_DEBUG_FILTER, filter); } } @@ -238,6 +239,10 @@ static void bgp_debug_list_print(struct vty *vty, const char *desc, if (filter->host) vty_out(vty, " %s", filter->host); + if (filter->plist_name) + vty_out(vty, " with prefix-list %s", + filter->plist_name); + if (filter->p && filter->p->family == AF_EVPN) bgp_debug_print_evpn_prefix(vty, "", filter->p); else if (filter->p) @@ -261,7 +266,11 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, if (list && !list_isempty(list)) { for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { - if (filter->host) { + if (filter->host && filter->plist_name) { + vty_out(vty, "%s %s prefix-list %s\n", desc, + filter->host, filter->plist_name); + write++; + } else if (filter->host) { vty_out(vty, "%s %s\n", desc, filter->host); write++; } @@ -286,7 +295,8 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, } static void bgp_debug_list_add_entry(struct list *list, const char *host, - const struct prefix *p) + const struct prefix *p, + const char *plist_name) { struct bgp_debug_filter *filter; @@ -302,6 +312,9 @@ static void bgp_debug_list_add_entry(struct list *list, const char *host, prefix_copy(filter->p, p); } + if (plist_name) + filter->plist_name = XSTRDUP(MTYPE_BGP_DEBUG_STR, plist_name); + listnode_add(list, filter); } @@ -315,6 +328,7 @@ static bool bgp_debug_list_remove_entry(struct list *list, const char *host, if (host && strcmp(filter->host, host) == 0) { listnode_delete(list, filter); XFREE(MTYPE_BGP_DEBUG_STR, filter->host); + XFREE(MTYPE_BGP_DEBUG_STR, filter->plist_name); XFREE(MTYPE_BGP_DEBUG_FILTER, filter); return true; } else if (p && filter->p->prefixlen == p->prefixlen @@ -330,16 +344,20 @@ static bool bgp_debug_list_remove_entry(struct list *list, const char *host, } static bool bgp_debug_list_has_entry(struct list *list, const char *host, - const struct prefix *p) + const struct prefix *p, + const char *plist_name) { struct bgp_debug_filter *filter; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { - if (host) { - if (strcmp(filter->host, host) == 0) { + if (host && plist_name) { + if (strmatch(filter->host, host) && filter->plist_name && + strmatch(filter->plist_name, plist_name)) + return true; + } else if (host) { + if (strmatch(filter->host, host)) return true; - } } else if (p) { if (filter->p->prefixlen == p->prefixlen && prefix_match(filter->p, p)) { @@ -353,7 +371,7 @@ static bool bgp_debug_list_has_entry(struct list *list, const char *host, bool bgp_debug_peer_updout_enabled(char *host) { - return (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, + return (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, NULL, NULL)); } @@ -780,14 +798,15 @@ DEFUN (debug_bgp_neighbor_events_peer, bgp_debug_neighbor_events_peers = list_new(); if (bgp_debug_list_has_entry(bgp_debug_neighbor_events_peers, host, - NULL)) { + NULL, NULL)) { vty_out(vty, "BGP neighbor-events debugging is already enabled for %s\n", host); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_neighbor_events_peers, host, NULL); + bgp_debug_list_add_entry(bgp_debug_neighbor_events_peers, host, NULL, + NULL); if (vty->node == CONFIG_NODE) DEBUG_ON(neighbor_events, NEIGHBOR_EVENTS); @@ -927,14 +946,15 @@ DEFUN (debug_bgp_keepalive_peer, if (!bgp_debug_keepalive_peers) bgp_debug_keepalive_peers = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_keepalive_peers, host, NULL)) { + if (bgp_debug_list_has_entry(bgp_debug_keepalive_peers, host, NULL, + NULL)) { vty_out(vty, "BGP keepalive debugging is already enabled for %s\n", host); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_keepalive_peers, host, NULL); + bgp_debug_list_add_entry(bgp_debug_keepalive_peers, host, NULL, NULL); if (vty->node == CONFIG_NODE) DEBUG_ON(keepalive, KEEPALIVE); @@ -1015,15 +1035,16 @@ DEFPY (debug_bgp_bestpath_prefix, if (!bgp_debug_bestpath_prefixes) bgp_debug_bestpath_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL, - prefix)) { + if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL, prefix, + NULL)) { vty_out(vty, "BGP bestpath debugging is already enabled for %s\n", prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix); + bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix, + NULL); if (vty->node == CONFIG_NODE) { DEBUG_ON(bestpath, BESTPATH); @@ -1150,9 +1171,9 @@ DEFUN (debug_bgp_update_direct, return CMD_SUCCESS; } -DEFUN (debug_bgp_update_direct_peer, +DEFPY (debug_bgp_update_direct_peer, debug_bgp_update_direct_peer_cmd, - "debug bgp updates ", + "debug bgp updates [prefix-list PREFIXLIST_NAME$plist]", DEBUG_STR BGP_STR "BGP updates\n" @@ -1160,7 +1181,9 @@ DEFUN (debug_bgp_update_direct_peer, "Outbound updates\n" "BGP neighbor IP address to debug\n" "BGP IPv6 neighbor to debug\n" - "BGP neighbor on interface to debug\n") + "BGP neighbor on interface to debug\n" + "Use prefix-list to filter prefixes to debug\n" + "Name of prefix-list\n") { int idx_in_out = 3; int idx_peer = 4; @@ -1180,7 +1203,7 @@ DEFUN (debug_bgp_update_direct_peer, if (inbound) { if (bgp_debug_list_has_entry(bgp_debug_update_in_peers, host, - NULL)) { + NULL, plist)) { vty_out(vty, "BGP inbound update debugging is already enabled for %s\n", host); @@ -1190,7 +1213,7 @@ DEFUN (debug_bgp_update_direct_peer, else { if (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, - NULL)) { + NULL, plist)) { vty_out(vty, "BGP outbound update debugging is already enabled for %s\n", host); @@ -1199,14 +1222,15 @@ DEFUN (debug_bgp_update_direct_peer, } if (inbound) - bgp_debug_list_add_entry(bgp_debug_update_in_peers, host, NULL); + bgp_debug_list_add_entry(bgp_debug_update_in_peers, host, NULL, + plist); else { struct peer *peer; struct peer_af *paf; int afidx; - bgp_debug_list_add_entry(bgp_debug_update_out_peers, host, - NULL); + bgp_debug_list_add_entry(bgp_debug_update_out_peers, host, NULL, + plist); peer = bgp_find_peer(vty, host); if (peer) { @@ -1283,7 +1307,7 @@ DEFUN (no_debug_bgp_update_direct, DEFUN (no_debug_bgp_update_direct_peer, no_debug_bgp_update_direct_peer_cmd, - "no debug bgp updates ", + "no debug bgp updates [prefix-list PREFIXLIST_NAME]", NO_STR DEBUG_STR BGP_STR @@ -1292,7 +1316,9 @@ DEFUN (no_debug_bgp_update_direct_peer, "Outbound updates\n" "BGP neighbor IP address to debug\n" "BGP IPv6 neighbor to debug\n" - "BGP neighbor on interface to debug\n") + "BGP neighbor on interface to debug\n" + "Use prefix-list to filter prefixes to debug\n" + "Name of prefix-list\n") { int idx_in_out = 4; int idx_peer = 5; @@ -1414,15 +1440,15 @@ DEFPY (debug_bgp_update_prefix_afi_safi, if (!bgp_debug_update_prefixes) bgp_debug_update_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, - &argv_p)) { + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, &argv_p, + NULL)) { vty_out(vty, "BGP updates debugging is already enabled for %pFX\n", &argv_p); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p); + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p, NULL); if (vty->node == CONFIG_NODE) { DEBUG_ON(update, UPDATE_PREFIX); @@ -1510,14 +1536,15 @@ DEFPY (debug_bgp_update_prefix, if (!bgp_debug_update_prefixes) bgp_debug_update_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix)) { + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix, + NULL)) { vty_out(vty, "BGP updates debugging is already enabled for %s\n", prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix); + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix, NULL); if (vty->node == CONFIG_NODE) { DEBUG_ON(update, UPDATE_PREFIX); @@ -1647,13 +1674,14 @@ DEFPY (debug_bgp_zebra_prefix, if (!bgp_debug_zebra_prefixes) bgp_debug_zebra_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix)) { + if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix, + NULL)) { vty_out(vty, "BGP zebra debugging is already enabled for %s\n", prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix); + bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix, NULL); if (vty->node == CONFIG_NODE) DEBUG_ON(zebra, ZEBRA); @@ -2510,7 +2538,8 @@ static int bgp_debug_per_prefix(const struct prefix *p, /* Return true if this peer is on the per_peer_list of peers to debug * for BGP_DEBUG_TYPE */ -static bool bgp_debug_per_peer(char *host, unsigned long term_bgp_debug_type, +static bool bgp_debug_per_peer(char *host, const struct prefix *p, + unsigned long term_bgp_debug_type, unsigned int BGP_DEBUG_TYPE, struct list *per_peer_list) { @@ -2522,17 +2551,28 @@ static bool bgp_debug_per_peer(char *host, unsigned long term_bgp_debug_type, if (!per_peer_list || list_isempty(per_peer_list)) return true; - else { - if (!host) - return false; + if (!host) + return false; - for (ALL_LIST_ELEMENTS(per_peer_list, node, nnode, - filter)) - if (strcmp(filter->host, host) == 0) - return true; + for (ALL_LIST_ELEMENTS(per_peer_list, node, nnode, filter)) + if (strmatch(filter->host, host) && + filter->plist_name && p) { + struct prefix_list *plist; + afi_t afi = family2afi(p->family); - return false; - } + plist = prefix_list_lookup(afi, + filter->plist_name); + + if (!plist) + continue; + + return prefix_list_apply(plist, p) == + PREFIX_PERMIT; + } else if (strmatch(filter->host, host)) { + return true; + } + + return false; } return false; @@ -2545,7 +2585,7 @@ bool bgp_debug_neighbor_events(const struct peer *peer) if (peer) host = peer->host; - return bgp_debug_per_peer(host, term_bgp_debug_neighbor_events, + return bgp_debug_per_peer(host, NULL, term_bgp_debug_neighbor_events, BGP_DEBUG_NEIGHBOR_EVENTS, bgp_debug_neighbor_events_peers); } @@ -2557,7 +2597,7 @@ bool bgp_debug_keepalive(const struct peer *peer) if (peer) host = peer->host; - return bgp_debug_per_peer(host, term_bgp_debug_keepalive, + return bgp_debug_per_peer(host, NULL, term_bgp_debug_keepalive, BGP_DEBUG_KEEPALIVE, bgp_debug_keepalive_peers); } @@ -2571,7 +2611,7 @@ bool bgp_debug_update(const struct peer *peer, const struct prefix *p, host = peer->host; if (inbound) { - if (bgp_debug_per_peer(host, term_bgp_debug_update, + if (bgp_debug_per_peer(host, p, term_bgp_debug_update, BGP_DEBUG_UPDATE_IN, bgp_debug_update_in_peers)) return true; @@ -2579,7 +2619,7 @@ bool bgp_debug_update(const struct peer *peer, const struct prefix *p, /* outbound */ else { - if (bgp_debug_per_peer(host, term_bgp_debug_update, + if (bgp_debug_per_peer(host, p, term_bgp_debug_update, BGP_DEBUG_UPDATE_OUT, bgp_debug_update_out_peers)) return true; diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 118325e0a34e..4e930c244ce4 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -96,6 +96,7 @@ extern struct list *bgp_debug_zebra_prefixes; struct bgp_debug_filter { char *host; + char *plist_name; struct prefix *p; };