Skip to content

Add CLI show commands to view bgp network, neighbors and summary on per-vrf basis #3866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4e7609a
working prototype
NavdhaJindal Apr 12, 2025
5c1b9f5
pass vrf as context
NavdhaJindal Apr 24, 2025
fc07a60
test changes for ipv6
NavdhaJindal Apr 24, 2025
406cc9e
edit summary def
NavdhaJindal Apr 24, 2025
bd019bd
remove path join from test
NavdhaJindal Apr 26, 2025
c465866
remove code duplication in ipv4
NavdhaJindal Apr 29, 2025
32ac469
remove code duplication in ipv6
NavdhaJindal Apr 29, 2025
fdc8c1f
remove new test file, merge per vrf tests
NavdhaJindal May 1, 2025
47fad2f
refactor by adding helper functions
NavdhaJindal May 3, 2025
ecd9365
refactor into helper functions
NavdhaJindal May 3, 2025
f6ab27b
refactor neighbor and network tests
NavdhaJindal May 3, 2025
d52930c
add vrf param to network_test
NavdhaJindal May 3, 2025
158d58b
add bgp summary uts
NavdhaJindal May 5, 2025
d98f2b3
change expected error message
NavdhaJindal May 5, 2025
e6175a1
fix summary UTs
NavdhaJindal May 5, 2025
822baef
rename as 'all_bgp_instances'
NavdhaJindal May 5, 2025
29affd4
update command-reference
NavdhaJindal May 6, 2025
d485d86
remove extra whitespaces
NavdhaJindal May 8, 2025
488e2a9
add test with different vnet name
NavdhaJindal May 9, 2025
85d49c4
add tests for specific vrf
NavdhaJindal May 12, 2025
06d3ae0
add vrf tests to summary
NavdhaJindal May 12, 2025
7eeb8f2
correct nits
NavdhaJindal May 12, 2025
3bc10a2
revert command-reference changes
NavdhaJindal May 12, 2025
658c036
remove spacing
NavdhaJindal May 12, 2025
f0b084a
resolve static checks
NavdhaJindal May 13, 2025
60c1eec
fix typo
NavdhaJindal May 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2540,8 +2540,7 @@ Optionally, you can specify an IP address in order to display only that particul

Click [here](#Quagga-BGP-Show-Commands) to see the example for "show ip bgp neighbors" for Quagga.


**show ip bgp network [[<ipv4-address>|<ipv4-prefix>] [(bestpath | multipath | longer-prefixes | json)]]
**show ip bgp network [[<ipv4-address>|<ipv4-prefix>] [(bestpath | multipath | longer-prefixes | json)]]**

This command displays all the details of IPv4 Border Gateway Protocol (BGP) prefixes.

Expand Down
153 changes: 119 additions & 34 deletions show/bgp_frr_v4.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
def bgp():
"""Show IPv4 BGP (Border Gateway Protocol) information"""
if device_info.is_supervisor():
subcommand = sys.argv[3]
if sys.argv[3] in "vrf":
subcommand = sys.argv[5]
else:
subcommand = sys.argv[3]
if subcommand not in "network":
# the command will be executed directly by rexec if it is not "show ip bgp network"
click.echo("Since the current device is a chassis supervisor, " +
Expand All @@ -33,9 +36,7 @@ def bgp():
@bgp.command()
@multi_asic_util.multi_asic_click_options
def summary(namespace, display):
bgp_summary = bgp_util.get_bgp_summary_from_all_bgp_instances(
constants.IPV4, namespace, display)
bgp_util.display_bgp_summary(bgp_summary=bgp_summary, af=constants.IPV4)
summary_helper(namespace, display)


# 'neighbors' subcommand ("show ip bgp neighbors")
Expand All @@ -46,17 +47,119 @@ def summary(namespace, display):
['routes', 'advertised-routes', 'received-routes']),
required=False)
@click.option('--namespace',
'-n',
'namespace',
default=None,
type=str,
show_default=True,
help='Namespace name or all',
callback=multi_asic_util.multi_asic_namespace_validation_callback)
'-n',
'namespace',
default=None,
type=str,
show_default=True,
help='Namespace name or all',
callback=multi_asic_util.multi_asic_namespace_validation_callback)
def neighbors(ipaddress, info_type, namespace):
"""Show IP (IPv4) BGP neighbors"""
neighbors_helper(ipaddress, info_type, namespace)


# 'network' subcommand ("show ip bgp network")
@bgp.command()
@click.argument('ipaddress',
metavar='[<ipv4-address>|<ipv4-prefix>]',
required=True if device_info.is_supervisor() else False)
@click.argument('info_type',
metavar='[bestpath|json|longer-prefixes|multipath]',
type=click.Choice(
['bestpath', 'json', 'longer-prefixes', 'multipath']),
required=False)
@click.option('--namespace',
'-n',
'namespace',
type=str,
show_default=True,
required=False,
help='Namespace name or all',
default="all",
callback=multi_asic_util.multi_asic_namespace_validation_callback)
def network(ipaddress, info_type, namespace):
"""Show IP (IPv4) BGP network"""
network_helper(ipaddress, info_type, namespace)


@bgp.group(cls=clicommon.AliasedGroup)
@click.argument('vrf', required=True)
@click.pass_context
def vrf(ctx, vrf):
"""Show IPv4 BGP information for a given VRF"""
pass


# 'summary' subcommand ("show ip bgp vrf <vrf/vnet name> summary")
@vrf.command('summary')
@multi_asic_util.multi_asic_click_options
@click.pass_context
def vrf_summary(ctx, namespace, display):
vrf = ctx.parent.params['vrf']
summary_helper(namespace, display, vrf)


# 'neighbors' subcommand ("show ip bgp vrf neighbors")
@vrf.command('neighbors')
@click.argument('ipaddress', required=False)
@click.argument('info_type',
type=click.Choice(
['routes', 'advertised-routes', 'received-routes']),
required=False)
@click.option('--namespace',
'-n',
'namespace',
default=None,
type=str,
show_default=True,
help='Namespace name or all',
callback=multi_asic_util.multi_asic_namespace_validation_callback)
@click.pass_context
def vrf_neighbors(ctx, ipaddress, info_type, namespace):
"""Show IP (IPv4) BGP neighbors"""
vrf = ctx.parent.params['vrf']
neighbors_helper(ipaddress, info_type, namespace, vrf)


# 'network' subcommand ("show ip bgp vrf network")
@vrf.command('network')
@click.argument('ipaddress',
metavar='[<ipv4-address>|<ipv4-prefix>]',
required=True if device_info.is_supervisor() else False)
@click.argument('info_type',
metavar='[bestpath|json|longer-prefixes|multipath]',
type=click.Choice(
['bestpath', 'json', 'longer-prefixes', 'multipath']),
required=False)
@click.option('--namespace',
'-n',
'namespace',
type=str,
show_default=True,
required=False,
help='Namespace name or all',
default="all",
callback=multi_asic_util.multi_asic_namespace_validation_callback)
@click.pass_context
def vrf_network(ctx, ipaddress, info_type, namespace):
"""Show IP (IPv4) BGP network"""
vrf = ctx.parent.params['vrf']
network_helper(ipaddress, info_type, namespace, vrf)


def summary_helper(namespace, display, vrf=None):
bgp_summary = bgp_util.get_bgp_summary_from_all_bgp_instances(
constants.IPV4, namespace, display, vrf)
bgp_util.display_bgp_summary(bgp_summary=bgp_summary, af=constants.IPV4)


def neighbors_helper(ipaddress, info_type, namespace, vrf=None):
command = 'show ip bgp'
if vrf is not None:
command += ' vrf {}'.format(vrf)
command += ' neighbor'

command = 'show ip bgp neighbor'
if ipaddress is not None:
if not bgp_util.is_ipv4_address(ipaddress):
ctx = click.get_current_context()
Expand Down Expand Up @@ -89,27 +192,10 @@ def neighbors(ipaddress, info_type, namespace):
click.echo(output.rstrip('\n'))


# 'network' subcommand ("show ip bgp network")
@bgp.command()
@click.argument('ipaddress',
metavar='[<ipv4-address>|<ipv4-prefix>]',
required=True if device_info.is_supervisor() else False)
@click.argument('info_type',
metavar='[bestpath|json|longer-prefixes|multipath]',
type=click.Choice(
['bestpath', 'json', 'longer-prefixes', 'multipath']),
required=False)
@click.option('--namespace',
'-n',
'namespace',
type=str,
show_default=True,
required=False,
help='Namespace name or all',
default="all",
callback=multi_asic_util.multi_asic_namespace_validation_callback)
def network(ipaddress, info_type, namespace):
"""Show IP (IPv4) BGP network"""
def network_helper(ipaddress, info_type, namespace, vrf=None):
command = 'show ip bgp'
if vrf is not None:
command += ' vrf {}'.format(vrf)

if device_info.is_supervisor():
# the command will be executed by rexec
Expand All @@ -125,7 +211,6 @@ def network(ipaddress, info_type, namespace):
ctx.fail('invalid namespace {}. provide namespace from list {}'
.format(namespace, multi_asic.get_namespace_list()))

command = 'show ip bgp'
if ipaddress is not None:
if '/' in ipaddress:
# For network prefixes then this all info_type(s) are available
Expand Down
149 changes: 116 additions & 33 deletions show/bgp_frr_v6.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ def bgp():
@multi_asic_util.multi_asic_click_options
def summary(namespace, display):
"""Show summarized information of IPv6 BGP state"""
bgp_summary = bgp_util.get_bgp_summary_from_all_bgp_instances(constants.IPV6, namespace,display)
bgp_util.display_bgp_summary(bgp_summary=bgp_summary, af=constants.IPV6)
summary_helper(namespace, display)


# 'neighbors' subcommand ("show ipv6 bgp neighbors")
Expand All @@ -37,15 +36,117 @@ def summary(namespace, display):
['routes', 'advertised-routes', 'received-routes']),
required=False)
@click.option('--namespace',
'-n',
'namespace',
default=None,
type=str,
show_default=True,
help='Namespace name or all',
callback=multi_asic_util.multi_asic_namespace_validation_callback)
'-n',
'namespace',
default=None,
type=str,
show_default=True,
help='Namespace name or all',
callback=multi_asic_util.multi_asic_namespace_validation_callback)
def neighbors(ipaddress, info_type, namespace):
"""Show IPv6 BGP neighbors"""
neighbors_helper(ipaddress, info_type, namespace)


# 'network' subcommand ("show ipv6 bgp network")
@bgp.command()
@click.argument('ipaddress',
metavar='[<ipv6-address>|<ipv6-prefix>]',
required=False)
@click.argument('info_type',
metavar='[bestpath|json|longer-prefixes|multipath]',
type=click.Choice(
['bestpath', 'json', 'longer-prefixes', 'multipath']),
required=False)
@click.option('--namespace',
'-n',
'namespace',
type=str,
show_default=True,
required=True if multi_asic.is_multi_asic is True else False,
help='Namespace name or all',
default=multi_asic.DEFAULT_NAMESPACE,
callback=multi_asic_util.multi_asic_namespace_validation_callback)
def network(ipaddress, info_type, namespace):
"""Show BGP ipv6 network"""
network_helper(ipaddress, info_type, namespace)


@bgp.group(cls=clicommon.AliasedGroup)
@click.argument('vrf', required=True)
@click.pass_context
def vrf(ctx, vrf):
"""Show IPv4 BGP information for a given VRF"""
pass


# 'summary' subcommand ("show ipv6 bgp summary")
@vrf.command('summary')
@multi_asic_util.multi_asic_click_options
@click.pass_context
def vrf_summary(ctx, namespace, display):
"""Show summarized information of IPv6 BGP state"""
vrf = ctx.parent.params['vrf']
summary_helper(namespace, display, vrf)


# 'neighbors' subcommand ("show ipv6 bgp vrf neighbors")
@vrf.command('neighbors')
@click.argument('ipaddress', required=False)
@click.argument('info_type',
type=click.Choice(
['routes', 'advertised-routes', 'received-routes']),
required=False)
@click.option('--namespace',
'-n',
'namespace',
default=None,
type=str,
show_default=True,
help='Namespace name or all',
callback=multi_asic_util.multi_asic_namespace_validation_callback)
@click.pass_context
def vrf_neighbors(ctx, ipaddress, info_type, namespace):
"""Show IPv6 BGP neighbors"""
vrf = ctx.parent.params['vrf']
neighbors_helper(ipaddress, info_type, namespace, vrf)


# 'network' subcommand ("show ipv6 bgp network")
@vrf.command('network')
@click.argument('ipaddress',
metavar='[<ipv6-address>|<ipv6-prefix>]',
required=False)
@click.argument('info_type',
metavar='[bestpath|json|longer-prefixes|multipath]',
type=click.Choice(
['bestpath', 'json', 'longer-prefixes', 'multipath']),
required=False)
@click.option('--namespace',
'-n',
'namespace',
type=str,
show_default=True,
required=True if multi_asic.is_multi_asic is True else False,
help='Namespace name or all',
default=multi_asic.DEFAULT_NAMESPACE,
callback=multi_asic_util.multi_asic_namespace_validation_callback)
@click.pass_context
def vrf_network(ctx, ipaddress, info_type, namespace):
"""Show BGP ipv6 network"""
vrf = ctx.parent.params['vrf']
network_helper(ipaddress, info_type, namespace, vrf)


def summary_helper(namespace, display, vrf=None):
bgp_summary = bgp_util.get_bgp_summary_from_all_bgp_instances(constants.IPV6, namespace, display, vrf)
bgp_util.display_bgp_summary(bgp_summary=bgp_summary, af=constants.IPV6)


def neighbors_helper(ipaddress, info_type, namespace, vrf=None):
command = 'show bgp'
if vrf is not None:
command += ' vrf {}'.format(vrf)

if ipaddress is not None:
if not bgp_util.is_ipv6_address(ipaddress):
Expand All @@ -68,7 +169,7 @@ def neighbors(ipaddress, info_type, namespace):
ipaddress = ""

info_type = "" if info_type is None else info_type
command = 'show bgp ipv6 neighbor {} {}'.format(
command += ' ipv6 neighbor {} {}'.format(
ipaddress, info_type)

ns_list = multi_asic.get_namespace_list(namespace)
Expand All @@ -79,29 +180,11 @@ def neighbors(ipaddress, info_type, namespace):
click.echo(output.rstrip('\n'))


# 'network' subcommand ("show ipv6 bgp network")
@bgp.command()
@click.argument('ipaddress',
metavar='[<ipv6-address>|<ipv6-prefix>]',
required=False)
@click.argument('info_type',
metavar='[bestpath|json|longer-prefixes|multipath]',
type=click.Choice(
['bestpath', 'json', 'longer-prefixes', 'multipath']),
required=False)
@click.option('--namespace',
'-n',
'namespace',
type=str,
show_default=True,
required=True if multi_asic.is_multi_asic is True else False,
help='Namespace name or all',
default=multi_asic.DEFAULT_NAMESPACE,
callback=multi_asic_util.multi_asic_namespace_validation_callback)
def network(ipaddress, info_type, namespace):
"""Show BGP ipv6 network"""

command = 'show bgp ipv6'
def network_helper(ipaddress, info_type, namespace, vrf=None):
command = 'show bgp'
if vrf is not None:
command += ' vrf {}'.format(vrf)
command += ' ipv6'

if multi_asic.is_multi_asic() and namespace not in multi_asic.get_namespace_list():
ctx = click.get_current_context()
Expand Down
Loading
Loading