/*
* Display EVPN neighbor summary.
*/
-DEFUN(show_bgp_l2vpn_evpn_summary,
- show_bgp_l2vpn_evpn_summary_cmd,
- "show bgp [vrf VRFNAME] l2vpn evpn summary [established|failed] [wide] [json]",
- SHOW_STR
- BGP_STR
+DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
+ "show bgp [vrf VRFNAME] l2vpn evpn summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [wide] [json]",
+ SHOW_STR BGP_STR
"bgp vrf\n"
- "vrf name\n"
- L2VPN_HELP_STR
- EVPN_HELP_STR
+ "vrf name\n" L2VPN_HELP_STR EVPN_HELP_STR
"Summary of BGP neighbor status\n"
"Show only sessions in Established state\n"
"Show only sessions not in Established state\n"
- "Increase table width for longer output\n"
- JSON_STR)
+ "Show only the specified neighbor session\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on BGP configured interface\n"
+ "Show only the specified remote AS sessions\n"
+ "AS number\n"
+ "Internal (iBGP) AS sessions\n"
+ "External (eBGP) AS sessions\n"
+ "Increase table width for longer output\n" JSON_STR)
{
int idx_vrf = 0;
int idx = 0;
char *vrf = NULL;
+ char *neighbor = NULL;
+ as_t as = 0; /* 0 means AS filter not set */
+ int as_type = AS_UNSPECIFIED;
uint8_t show_flags = 0;
if (argv_find(argv, argc, "vrf", &idx_vrf))
if (argv_find(argv, argc, "established", &idx))
SET_FLAG(show_flags, BGP_SHOW_OPT_ESTABLISHED);
+
+ if (argv_find(argv, argc, "neighbor", &idx))
+ neighbor = argv[idx + 1]->arg;
+
+ if (argv_find(argv, argc, "remote-as", &idx)) {
+ if (argv[idx + 1]->arg[0] == 'i')
+ as_type = AS_INTERNAL;
+ else if (argv[idx + 1]->arg[0] == 'e')
+ as_type = AS_EXTERNAL;
+ else
+ as = (as_t)atoi(argv[idx + 1]->arg);
+ }
+
if (argv_find(argv, argc, "wide", &idx))
SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
if (use_json(argc, argv))
SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
- return bgp_show_summary_vty(vty, vrf, AFI_L2VPN, SAFI_EVPN, show_flags);
+ return bgp_show_summary_vty(vty, vrf, AFI_L2VPN, SAFI_EVPN, neighbor,
+ as_type, as, show_flags);
}
int bgp_evpn_cli_parse_type(int *type, struct cmd_token **argv, int argc)
return stripped;
}
+/* Determine whether var peer should be filtered out of the summary. */
+static bool bgp_show_summary_is_peer_filtered(struct peer *peer,
+ struct peer *fpeer, int as_type,
+ as_t as)
+{
+
+ /* filter neighbor XXXX */
+ if (fpeer && fpeer != peer)
+ return true;
+
+ /* filter remote-as (internal|external) */
+ if (as_type != AS_UNSPECIFIED) {
+ if (peer->as_type == AS_SPECIFIED) {
+ if (as_type == AS_INTERNAL) {
+ if (peer->as != peer->local_as)
+ return true;
+ } else if (peer->as == peer->local_as)
+ return true;
+ } else if (as_type != peer->as_type)
+ return true;
+ } else if (as && as != peer->as) /* filter remote-as XXX */
+ return true;
+
+ return false;
+}
+
/* Show BGP peer's summary information. */
static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
+ struct peer *fpeer, int as_type, as_t as,
uint8_t show_flags)
{
struct peer *peer;
json = json_object_new_object();
json_peers = json_object_new_object();
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ if (bgp_show_summary_is_peer_filtered(peer, fpeer,
+ as_type, as)) {
+ count++;
+ continue;
+ }
+
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
continue;
* characters are needed for the Neighbor column
*/
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ if (bgp_show_summary_is_peer_filtered(peer, fpeer,
+ as_type, as)) {
+ count++;
+ continue;
+ }
+
if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
continue;
if (use_json) {
json_peer = NULL;
+ if (bgp_show_summary_is_peer_filtered(peer, fpeer,
+ as_type, as))
+ continue;
+
if (show_failed &&
bgp_has_peer_failed(peer, afi, safi)) {
json_peer = json_object_new_object();
json_object_object_add(json_peers, peer->host,
json_peer);
} else {
+ if (bgp_show_summary_is_peer_filtered(peer, fpeer,
+ as_type, as))
+ continue;
if (show_failed &&
bgp_has_peer_failed(peer, afi, safi)) {
bgp_show_failed_summary(vty, bgp, peer, NULL,
if (show_established
&& bgp_has_peer_failed(peer, afi, safi))
continue;
-
memset(dn_flag, '\0', sizeof(dn_flag));
if (peer_dynamic_neighbor(peer)) {
dn_flag[0] = '*';
}
static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
- int safi, uint8_t show_flags)
+ int safi, struct peer *fpeer, int as_type,
+ as_t as, uint8_t show_flags)
{
int is_first = 1;
int afi_wildcard = (afi == AFI_MAX);
false));
}
}
- bgp_show_summary(vty, bgp, afi, safi,
- show_flags);
+ bgp_show_summary(vty, bgp, afi, safi, fpeer,
+ as_type, as, show_flags);
}
safi++;
if (!safi_wildcard)
}
static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
- safi_t safi, uint8_t show_flags)
+ safi_t safi,
+ const char *neighbor,
+ int as_type, as_t as,
+ uint8_t show_flags)
{
struct listnode *node, *nnode;
struct bgp *bgp;
+ struct peer *fpeer = NULL;
int is_first = 1;
bool nbr_output = false;
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
? VRF_DEFAULT_NAME
: bgp->name);
}
- bgp_show_summary_afi_safi(vty, bgp, afi, safi, show_flags);
+ if (neighbor) {
+ fpeer = peer_lookup_in_view(vty, bgp, neighbor,
+ use_json);
+ if (!fpeer)
+ continue;
+ }
+ bgp_show_summary_afi_safi(vty, bgp, afi, safi, fpeer, as_type,
+ as, show_flags);
}
if (use_json)
}
int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
- safi_t safi, uint8_t show_flags)
+ safi_t safi, const char *neighbor, int as_type,
+ as_t as, uint8_t show_flags)
{
struct bgp *bgp;
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+ struct peer *fpeer = NULL;
if (name) {
if (strmatch(name, "all")) {
bgp_show_all_instances_summary_vty(vty, afi, safi,
- show_flags);
+ neighbor, as_type,
+ as, show_flags);
return CMD_SUCCESS;
} else {
bgp = bgp_lookup_by_name(name);
return CMD_WARNING;
}
- bgp_show_summary_afi_safi(vty, bgp, afi, safi,
- show_flags);
+ if (neighbor) {
+ fpeer = peer_lookup_in_view(vty, bgp, neighbor,
+ use_json);
+ if (!fpeer)
+ return CMD_WARNING;
+ }
+ bgp_show_summary_afi_safi(vty, bgp, afi, safi, fpeer,
+ as_type, as, show_flags);
return CMD_SUCCESS;
}
}
bgp = bgp_get_default();
- if (bgp)
- bgp_show_summary_afi_safi(vty, bgp, afi, safi, show_flags);
- else {
+ if (bgp) {
+ if (neighbor) {
+ fpeer = peer_lookup_in_view(vty, bgp, neighbor,
+ use_json);
+ if (!fpeer)
+ return CMD_WARNING;
+ }
+ bgp_show_summary_afi_safi(vty, bgp, afi, safi, fpeer, as_type,
+ as, show_flags);
+ } else {
if (use_json)
vty_out(vty, "{}\n");
else
}
/* `show [ip] bgp summary' commands. */
-DEFPY (show_ip_bgp_summary,
- show_ip_bgp_summary_cmd,
- "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] [all$all] summary [established|failed] [wide] [json$uj]",
- 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"
- "Summary of BGP neighbor status\n"
- "Show only sessions in Established state\n"
- "Show only sessions not in Established state\n"
- "Increase table width for longer output\n"
- JSON_STR)
+DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
+ "show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR
+ " [" BGP_SAFI_WITH_LABEL_CMD_STR
+ "]] [all$all] summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [wide] [json$uj]",
+ 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"
+ "Summary of BGP neighbor status\n"
+ "Show only sessions in Established state\n"
+ "Show only sessions not in Established state\n"
+ "Show only the specified neighbor session\n"
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on BGP configured interface\n"
+ "Show only the specified remote AS sessions\n"
+ "AS number\n"
+ "Internal (iBGP) AS sessions\n"
+ "External (eBGP) AS sessions\n"
+ "Increase table width for longer output\n" JSON_STR)
{
char *vrf = NULL;
afi_t afi = AFI_MAX;
safi_t safi = SAFI_MAX;
+ as_t as = 0; /* 0 means AS filter not set */
+ int as_type = AS_UNSPECIFIED;
uint8_t show_flags = 0;
int idx = 0;
if (argv_find(argv, argc, "established", &idx))
SET_FLAG(show_flags, BGP_SHOW_OPT_ESTABLISHED);
+ if (argv_find(argv, argc, "remote-as", &idx)) {
+ if (argv[idx + 1]->arg[0] == 'i')
+ as_type = AS_INTERNAL;
+ else if (argv[idx + 1]->arg[0] == 'e')
+ as_type = AS_EXTERNAL;
+ else
+ as = (as_t)atoi(argv[idx + 1]->arg);
+ }
+
if (argv_find(argv, argc, "wide", &idx))
SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
if (argv_find(argv, argc, "json", &idx))
SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
- return bgp_show_summary_vty(vty, vrf, afi, safi, show_flags);
+ return bgp_show_summary_vty(vty, vrf, afi, safi, neighbor, as_type, as,
+ show_flags);
}
const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json)
int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv,
int argc, struct bgp **bgp, bool use_json);
extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
- safi_t safi, uint8_t show_flags);
+ safi_t safi, const char *neighbor, int as_type,
+ as_t as, uint8_t show_flags);
extern int bgp_clear_star_soft_in(const char *name, char *errmsg,
size_t errmsg_len);
extern int bgp_clear_star_soft_out(const char *name, char *errmsg,
Show a bgp peer summary for peers that are succesfully exchanging routes
for the specified address family, and subsequent address-family.
+.. clicmd:: show bgp [afi] [safi] [all] summary neighbor [PEER] [json]
+
+ Show a bgp summary for the specified peer, address family, and
+ subsequent address-family. The neighbor filter can be used in combination
+ with the failed, established filters.
+
+.. clicmd:: show bgp [afi] [safi] [all] summary remote-as <internal|external|ASN> [json]
+
+ Show a bgp peer summary for the specified remote-as ASN or type (``internal``
+ for iBGP and ``external`` for eBGP sessions), address family, and subsequent
+ address-family. The remote-as filter can be used in combination with the
+ failed, established filters.
+
.. clicmd:: show bgp [afi] [safi] [neighbor [PEER] [routes|advertised-routes|received-routes] [json]
This command shows information on a specific BGP peer of the relevant
refTableFile = "%s/r%s/show_ip_bgp_summary.ref" % (thisDir, i)
if os.path.isfile(refTableFile):
# Read expected result from file
- expected = open(refTableFile).read().rstrip()
- # Fix newlines (make them all the same)
- expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+ expected_original = open(refTableFile).read().rstrip()
- # Actual output from router
- actual = (
- net["r%s" % i]
- .cmd('vtysh -c "show ip bgp summary" 2> /dev/null')
- .rstrip()
- )
- # Mask out "using XXiXX bytes" portion. They are random...
- actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual)
- # Mask out "using XiXXX KiB" portion. They are random...
- actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual)
- #
- # Remove extra summaries which exist with newer versions
- #
- # Remove summary lines (changed recently)
- actual = re.sub(r"Total number.*", "", actual)
- actual = re.sub(r"Displayed.*", "", actual)
- # Remove IPv4 Unicast Summary (Title only)
- actual = re.sub(r"IPv4 Unicast Summary:", "", actual)
- # Remove IPv4 Multicast Summary (all of it)
- actual = re.sub(r"IPv4 Multicast Summary:", "", actual)
- actual = re.sub(r"No IPv4 Multicast neighbor is configured", "", actual)
- # Remove IPv4 VPN Summary (all of it)
- actual = re.sub(r"IPv4 VPN Summary:", "", actual)
- actual = re.sub(r"No IPv4 VPN neighbor is configured", "", actual)
- # Remove IPv4 Encap Summary (all of it)
- actual = re.sub(r"IPv4 Encap Summary:", "", actual)
- actual = re.sub(r"No IPv4 Encap neighbor is configured", "", actual)
- # Remove Unknown Summary (all of it)
- actual = re.sub(r"Unknown Summary:", "", actual)
- actual = re.sub(r"No Unknown neighbor is configured", "", actual)
+ for filter in ["", "remote-as internal", "remote-as external",
+ "remote-as 100", "remote-as 123",
+ "neighbor 192.168.7.10", "neighbor 192.168.7.10",
+ "neighbor fc00:0:0:8::1000",
+ "neighbor 10.0.0.1"]:
+ # Actual output from router
+ actual = (
+ net["r%s" % i]
+ .cmd('vtysh -c "show ip bgp summary ' + filter + '" 2> /dev/null')
+ .rstrip()
+ )
+ # Mask out "using XXiXX bytes" portion. They are random...
+ actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual)
+ # Mask out "using XiXXX KiB" portion. They are random...
+ actual = re.sub(r"using [0-9]+ KiB", "using XXXX KiB", actual)
- actual = re.sub(r"IPv4 labeled-unicast Summary:", "", actual)
- actual = re.sub(
- r"No IPv4 labeled-unicast neighbor is configured", "", actual
- )
+ # Remove extra summaries which exist with newer versions
- # Strip empty lines
- actual = actual.lstrip()
- actual = actual.rstrip()
- #
- # Fix newlines (make them all the same)
- actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+ # Remove summary lines (changed recently)
+ actual = re.sub(r"Total number.*", "", actual)
+ actual = re.sub(r"Displayed.*", "", actual)
+ # Remove IPv4 Unicast Summary (Title only)
+ actual = re.sub(r"IPv4 Unicast Summary:", "", actual)
+ # Remove IPv4 Multicast Summary (all of it)
+ actual = re.sub(r"IPv4 Multicast Summary:", "", actual)
+ actual = re.sub(r"No IPv4 Multicast neighbor is configured", "", actual)
+ # Remove IPv4 VPN Summary (all of it)
+ actual = re.sub(r"IPv4 VPN Summary:", "", actual)
+ actual = re.sub(r"No IPv4 VPN neighbor is configured", "", actual)
+ # Remove IPv4 Encap Summary (all of it)
+ actual = re.sub(r"IPv4 Encap Summary:", "", actual)
+ actual = re.sub(r"No IPv4 Encap neighbor is configured", "", actual)
+ # Remove Unknown Summary (all of it)
+ actual = re.sub(r"Unknown Summary:", "", actual)
+ actual = re.sub(r"No Unknown neighbor is configured", "", actual)
+
+ actual = re.sub(r"IPv4 labeled-unicast Summary:", "", actual)
+ actual = re.sub(
+ r"No IPv4 labeled-unicast neighbor is configured", "", actual
+ )
- # Generate Diff
- diff = topotest.get_textdiff(
- actual,
- expected,
- title1="actual SHOW IP BGP SUMMARY",
- title2="expected SHOW IP BGP SUMMARY",
- )
+ expected = expected_original
+ # apply filters on expected output
+ if "internal" in filter or "remote-as 100" in filter:
+ expected = re.sub(r".+\s+200\s+.+", "", expected)
+ elif "external" in filter:
+ expected = re.sub(r".+\s+100\s+.+Active.+", "", expected)
+ elif "remote-as 123" in filter:
+ expected = re.sub(
+ r"(192.168.7.(1|2)0|fc00:0:0:8::(1|2)000).+Active.+",
+ "", expected
+ )
+ elif "192.168.7.10" in filter:
+ expected = re.sub(
+ r"(192.168.7.20|fc00:0:0:8::(1|2)000).+Active.+",
+ "", expected
+ )
+ elif "fc00:0:0:8::1000" in filter:
+ expected = re.sub(
+ r"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+",
+ "", expected
+ )
+ elif "10.0.0.1" in filter:
+ expected = "No such neighbor in this view/vrf"
+
+ # Strip empty lines
+ actual = actual.lstrip().rstrip()
+ expected = expected.lstrip().rstrip()
+ actual = re.sub(r"\n+", "\n", actual)
+ expected = re.sub(r"\n+", "\n", expected)
+
+ # reapply initial formatting
+ actual = re.sub(r"KiB of memory\n", "KiB of memory\n\n", actual)
+ expected = re.sub(r"KiB of memory\n", "KiB of memory\n\n", expected)
+
+ # realign expected neighbor columns if needed
+ try:
+ idx_actual = re.search(r"\n(Neighbor\s+V\s+)", actual).group(1).find("V")
+ idx_expected = re.search(r"\n(Neighbor\s+V\s+)", expected).group(1).find("V")
+ idx_diff = idx_expected - idx_actual
+ if idx_diff > 0:
+ # Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
+ expected = re.sub(" " * idx_diff + "V ", "V ", expected)
+ # 192.168.7.10 4 100 0 0 0 0 0 never Active
+ expected = re.sub(" " * idx_diff + "4 ", "4 ", expected)
+ except AttributeError:
+ pass
- # Empty string if it matches, otherwise diff contains unified diff
- if diff:
- sys.stderr.write(
- "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i, diff)
+ # Fix newlines (make them all the same)
+ actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
+ expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
+
+ # Generate Diff
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="actual SHOW IP BGP SUMMARY " + filter.upper() ,
+ title2="expected SHOW IP BGP SUMMARY " + filter.upper(),
)
- failures += 1
- else:
- print("r%s ok" % i)
- assert failures == 0, "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (
- i,
- diff,
- )
+ # Empty string if it matches, otherwise diff contains unified diff
+ if diff:
+ sys.stderr.write(
+ "r%s failed SHOW IP BGP SUMMARY check:\n%s\n" % (i, diff)
+ )
+ failures += 1
+ else:
+ print("r%s ok" % i)
+
+ assert failures == 0, "SHOW IP BGP SUMMARY failed for router r%s:\n%s" % (
+ i,
+ diff,
+ )
+
+ # Actual output from router
+ actual = (
+ net["r%s" % i]
+ .cmd('vtysh -c "show ip bgp summary" 2> /dev/null')
+ .rstrip()
+ )
# Make sure that all daemons are running
for i in range(1, 2):