Skip to content

Commit

Permalink
Support command show ip fib and show ipv6 fib (#2100)
Browse files Browse the repository at this point in the history
Signed-off-by: Yutong Zhang <yutongzhang@microsoft.com>

#### What I did
Support command `show ip fib` and `show ipv6 fib`to get dataplane/FIB routes from APPL_DB ROUTE_TABLE. 

#### How I did it
Add a script `fibshow` under the folder scripts/ and modify the script `main.py` under the show folder. 

#### How to verify it
By using command `show ip fib`, `show ipv6 fib`, `fibshow -4`, `fibshow -6` on dut. And it also support given a specific ip prefix like `show ipv6 fib 20c0:dfe8::/64`

#### New command output (if the output of a command-line utility has changed)
```
admin@vlab-01:~$ show ipv6 fib
  No.  Vrf    Route                Nexthop                              Ifname
-----  -----  -------------------  -----------------------------------  -----------------------------------------------------------
    1         20c0:fe28:0:80::/64  fc00::72,fc00::76,fc00::7a,fc00::7e  PortChannel101,PortChannel102,PortChannel103,PortChannel104
    2         20c0:fe28::/64       fc00::72,fc00::76,fc00::7a,fc00::7e  PortChannel101,PortChannel102,PortChannel103,PortChannel104
    3         20c0:fe30:0:80::/64                                       PortChannel101,PortChannel102,PortChannel103,PortChannel104
Total number of entries 3
......
Total number of entries 6410

admin@vlab-01:~$ fibshow -4
  No.  Vrf    Route               Nexthop                                  Ifname
-----  -----  ------------------  ---------------------------------------  -----------------------------------------------------------
    1         192.168.104.0/25    10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63  PortChannel101,PortChannel102,PortChannel103,PortChannel104
    2         192.168.104.128/25                                           PortChannel101,PortChannel102,PortChannel103,PortChannel104
    3         192.168.112.0/25    10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63
    4         192.168.120.0/25    10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63  PortChannel101,PortChannel102,PortChannel103,PortChannel104
    5  Red    192.168.112.128/25  10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63  PortChannel101,PortChannel102,PortChannel103,PortChannel104
Total number of entries 5
```


```
admin@vlab-01:~$ show ipv6 fib 20c0:fe28:0:80::/64
  No.  Vrf    Route                Nexthop                              Ifname
-----  -----  -------------------  -----------------------------------  -----------------------------------------------------------
    1         20c0:fe28:0:80::/64  fc00::72,fc00::76,fc00::7a,fc00::7e  PortChannel101,PortChannel102,PortChannel103,PortChannel104
Total number of entries 3
```
  • Loading branch information
yutongzhang-microsoft authored Mar 22, 2022
1 parent 2a982a1 commit 4681697
Show file tree
Hide file tree
Showing 9 changed files with 328 additions and 25 deletions.
4 changes: 1 addition & 3 deletions scripts/fanshow
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,15 @@ class FanShow(object):

presence = data_dict[PRESENCE_FIELD_NAME].lower()
presence = 'Present' if presence == 'true' else 'Not Present'

status = data_dict[STATUS_FIELD_NAME]
status_lower = status.lower()
if status_lower == 'true':
status = 'OK'
elif status_lower == 'false':
status = 'Not OK'

table.append((data_dict[DRAWER_FIELD_NAME], data_dict[LED_STATUS_FIELD_NAME], name, speed, data_dict[DIRECTION_FIELD_NAME], presence, status,
table.append((data_dict[DRAWER_FIELD_NAME], data_dict[LED_STATUS_FIELD_NAME], name, speed, data_dict[DIRECTION_FIELD_NAME], presence, status,
data_dict[TIMESTAMP_FIELD_NAME]))

if table:
print(tabulate(table, header, tablefmt='simple', stralign='right'))
else:
Expand Down
147 changes: 147 additions & 0 deletions scripts/fibshow
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/usr/bin/env python3

"""
Script to show dataplane/FIB entries
usage: fibshow [-ip IPADDR] v
optional arguments:
-ip IPADDR, --ipaddr IPADDR
dataplane/FIB entry for a specific address
Example of the output:
admin@str~$ fibshow -4
No. Vrf Route Nexthop Ifname
----- ------- ------------------ --------------------------------------- -----------------------------------------------------------
1 Red 192.181.8.0/25 10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63 PortChannel101,PortChannel102,PortChannel103,PortChannel104
2 192.184.56.0/25 10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63 PortChannel101,PortChannel102,PortChannel103,PortChannel104
...
Total number of entries 19
admin@str:~$ fibshow -6 -ip 20c0:b560:0:80::
No. Vrf Route Nexthop Ifname
----- ------- ------------------- ----------------------------------- -----------------------------------------------------------
1 20c0:b560:0:80::/64 fc00::72,fc00::76,fc00::7a,fc00::7e PortChannel101,PortChannel102,PortChannel103,PortChannel104
Total number of entries 1
"""
import argparse
import sys
import os
import re

# mock the redis for unit test purposes #
try: # pragma: no cover
if os.environ["UTILITIES_UNIT_TESTING"] == "1":
modules_path = os.path.join(os.path.dirname(__file__), "..")
test_path = os.path.join(modules_path, "tests")
sys.path.insert(0, modules_path)
sys.path.insert(0, test_path)
import mock_tables.dbconnector
mock_variants = { "1": 'appl_db'}
mock_db_path = os.path.join(test_path, "fibshow_input")
file_name = mock_variants[os.environ["FIBSHOW_MOCK"]]
jsonfile_asic = os.path.join(mock_db_path, file_name)
mock_tables.dbconnector.dedicated_dbs['APPL_DB'] = jsonfile_asic
except KeyError: # pragma: no cover
pass

import ipaddress

from swsscommon.swsscommon import SonicV2Connector
from tabulate import tabulate

"""
Base class for v4 and v6 FIB entries.
"""


class FibBase(object):

HEADER = ["No.", "Vrf", "Route", "Nexthop", "Ifname"]

def __init__(self):
super(FibBase, self).__init__()
self.db = SonicV2Connector(host="127.0.0.1")
self.fetch_fib_data()

def fetch_fib_data(self):
"""
Fetch FIB entries from APPL_DB
"""
self.db.connect(self.db.APPL_DB)
self.fib_entry_list = []

fib_str = self.db.keys(self.db.APPL_DB, "ROUTE_TABLE:*")
if not fib_str:
return

for s in fib_str:
fib_entry = s
fib = fib_entry.split(":", 1)[-1]
if not fib:
continue

ent = self.db.get_all(self.db.APPL_DB, s)
if not ent:
continue

self.fib_entry_list.append((fib,) + (ent["nexthop"],) + (ent["ifname"],) )
self.fib_entry_list.sort(key=lambda x: x[0])
return

def display(self, version, address):
"""
Display FIB entries from APPL_DB
"""
output = []
fdb_index = 1
for fib in self.fib_entry_list:
prefix = fib[0]

if 'VRF' in fib[0]:
vrf = re.match(r"VRF-(.*)",fib[0].split(":")[0]).group(1)
prefix = fib[0].split(":")[1]
else:
vrf = ""
ip = ipaddress.ip_address(prefix.split("/")[0])

if address is not None:
if fib[0] == address:
if ip.version == 4 and version == "-4":
output.append([fdb_index, vrf, prefix, fib[1], fib[2]])
fdb_index += 1
elif ip.version == 6 and version == "-6":
output.append([fdb_index, vrf, prefix, fib[1], fib[2]])
fdb_index += 1
break
else:
continue
else:
if ip.version == 4 and version == "-4":
output.append([fdb_index, vrf, prefix, fib[1], fib[2]])
fdb_index += 1
elif ip.version == 6 and version == "-6":
output.append([fdb_index, vrf, prefix, fib[1], fib[2]])
fdb_index += 1
print(tabulate(output, self.HEADER))
print("Total number of entries {0}".format(len(output)))

def main():

parser = argparse.ArgumentParser(description='Show dataplane/FIB entries',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-ip', '--ipaddr', type=str,
help='dataplane/FIB route for a specific address', default=None)
parser.add_argument('v', help='IP Version -4 or -6')

args = parser.parse_args()

try:
fib = FibBase()
fib.display(args.v, args.ipaddr)
except Exception as e:
print(str(e))
sys.exit(1)


if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
'scripts/fast-reboot-dump.py',
'scripts/fdbclear',
'scripts/fdbshow',
'scripts/fibshow',
'scripts/flow_counters_stat',
'scripts/gearboxutil',
'scripts/generate_dump',
Expand Down
26 changes: 26 additions & 0 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,19 @@ def protocol(verbose):
cmd = 'sudo {} -c "show ip protocol"'.format(constants.RVTYSH_COMMAND)
run_command(cmd, display_cmd=verbose)

#
# 'fib' subcommand ("show ip fib")
#
@ip.command()
@click.argument('ipaddress', required=False)
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def fib(ipaddress, verbose):
"""Show IP FIB table"""
cmd = "fibshow -4"
if ipaddress is not None:
cmd += " -ip {}".format(ipaddress)
run_command(cmd, display_cmd=verbose)


#
# 'ipv6' group ("show ipv6 ...")
Expand Down Expand Up @@ -983,6 +996,19 @@ def link_local_mode(verbose):

click.echo(tabulate(body, header, tablefmt="grid"))

#
# 'fib' subcommand ("show ipv6 fib")
#
@ipv6.command()
@click.argument('ipaddress', required=False)
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def fib(ipaddress, verbose):
"""Show IP FIB table"""
cmd = "fibshow -6"
if ipaddress is not None:
cmd += " -ip {}".format(ipaddress)
run_command(cmd, display_cmd=verbose)

#
# 'lldp' group ("show lldp ...")
#
Expand Down
5 changes: 5 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,8 @@ def setup_ip_route_commands():

return show

@pytest.fixture
def setup_fib_commands():
import show.main as show
return show

Empty file added tests/fibshow_input/__init__.py
Empty file.
34 changes: 34 additions & 0 deletions tests/fibshow_input/appl_db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"ROUTE_TABLE:192.168.104.0/25": {
"nexthop": "10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63",
"ifname" : "PortChannel101,PortChannel102,PortChannel103,PortChannel104"
},
"ROUTE_TABLE:192.168.104.128/25": {
"nexthop": "",
"ifname" : "PortChannel101,PortChannel102,PortChannel103,PortChannel104"
},
"ROUTE_TABLE:192.168.112.0/25": {
"nexthop": "10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63",
"ifname" : ""
},
"ROUTE_TABLE:VRF-Red:192.168.112.128/25": {
"nexthop": "10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63",
"ifname" : "PortChannel101,PortChannel102,PortChannel103,PortChannel104"
},
"ROUTE_TABLE:192.168.120.0/25": {
"nexthop": "10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63",
"ifname" : "PortChannel101,PortChannel102,PortChannel103,PortChannel104"
},
"ROUTE_TABLE:20c0:fe28:0:80::/64": {
"nexthop": "fc00::72,fc00::76,fc00::7a,fc00::7e",
"ifname" : "PortChannel101,PortChannel102,PortChannel103,PortChannel104"
},
"ROUTE_TABLE:20c0:fe28::/64": {
"nexthop": "fc00::72,fc00::76,fc00::7a,fc00::7e",
"ifname" : "PortChannel101,PortChannel102,PortChannel103,PortChannel104"
},
"ROUTE_TABLE:20c0:fe30:0:80::/64": {
"nexthop": "",
"ifname" : "PortChannel101,PortChannel102,PortChannel103,PortChannel104"
}
}
92 changes: 92 additions & 0 deletions tests/fibshow_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import os

import pytest

from click.testing import CliRunner

from utilities_common import multi_asic
from utilities_common import constants
from .utils import get_result_and_return_code
import show.main as show

from unittest.mock import patch

from sonic_py_common import device_info

show_ip_fib_v4 = """\
No. Vrf Route Nexthop Ifname
----- ----- ------------------ --------------------------------------- -----------------------------------------------------------
1 192.168.104.0/25 10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63 PortChannel101,PortChannel102,PortChannel103,PortChannel104
2 192.168.104.128/25 PortChannel101,PortChannel102,PortChannel103,PortChannel104
3 192.168.112.0/25 10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63
4 192.168.120.0/25 10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63 PortChannel101,PortChannel102,PortChannel103,PortChannel104
5 Red 192.168.112.128/25 10.0.0.57,10.0.0.59,10.0.0.61,10.0.0.63 PortChannel101,PortChannel102,PortChannel103,PortChannel104
Total number of entries 5
"""

show_ip_fib_v6 = """\
No. Vrf Route Nexthop Ifname
----- ----- ------------------- ----------------------------------- -----------------------------------------------------------
1 20c0:fe28:0:80::/64 fc00::72,fc00::76,fc00::7a,fc00::7e PortChannel101,PortChannel102,PortChannel103,PortChannel104
2 20c0:fe28::/64 fc00::72,fc00::76,fc00::7a,fc00::7e PortChannel101,PortChannel102,PortChannel103,PortChannel104
3 20c0:fe30:0:80::/64 PortChannel101,PortChannel102,PortChannel103,PortChannel104
Total number of entries 3
"""

root_path = os.path.dirname(os.path.abspath(__file__))
modules_path = os.path.dirname(root_path)
scripts_path = os.path.join(modules_path, "scripts")


class TestFibshow():
@pytest.fixture(scope="class", autouse=True)
def setup_class(cls):
print("SETUP")
os.environ["PATH"] += os.pathsep + scripts_path
os.environ["UTILITIES_UNIT_TESTING"] = "1"
yield
print("TEARDOWN")
os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1])
os.environ["UTILITIES_UNIT_TESTING"] = "0"

@pytest.fixture(scope="function", autouse=True)
def setUp(self):
self.runner = CliRunner()
yield
del os.environ["FIBSHOW_MOCK"]

def set_mock_variant(self, variant: str):
os.environ["FIBSHOW_MOCK"] = variant

def test_show_ip_fib(self):
self.set_mock_variant("1")
from .mock_tables import dbconnector
modules_path = os.path.join(os.path.dirname(__file__), "..")
test_path = os.path.join(modules_path, "tests")
mock_db_path = os.path.join(test_path, "fibshow_input")
jsonfile_appl = os.path.join(mock_db_path, 'appl_db')
dbconnector.dedicated_dbs['APPL_DB'] = jsonfile_appl
print(dbconnector.load_database_config())
result = self.runner.invoke(show.cli.commands["ip"].commands["fib"], [])
dbconnector.dedicated_dbs['APPL_DB'] = None
print(result.exit_code)
print(result.output)
assert result.exit_code == 0
assert result.output == show_ip_fib_v4

def test_show_ipv6_fib(self):
self.set_mock_variant("1")
from .mock_tables import dbconnector
modules_path = os.path.join(os.path.dirname(__file__), "..")
test_path = os.path.join(modules_path, "tests")
mock_db_path = os.path.join(test_path, "fibshow_input")
jsonfile_appl = os.path.join(mock_db_path, 'appl_db')
dbconnector.dedicated_dbs['APPL_DB'] = jsonfile_appl
print(dbconnector.load_database_config())
result = self.runner.invoke(show.cli.commands["ipv6"].commands["fib"], [])
dbconnector.dedicated_dbs['APPL_DB'] = None
print(result.exit_code)
print(result.output)
assert result.exit_code == 0
assert result.output == show_ip_fib_v6

Loading

0 comments on commit 4681697

Please sign in to comment.