Skip to content
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

[fdbshow] Adding more options for fdbshow and show mac #1982

Merged
merged 10 commits into from
Jan 18, 2022
156 changes: 94 additions & 62 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -8814,90 +8814,122 @@ This command displays the MAC (FDB) entries either in full or partial as given b
1) show mac - displays the full table
2) show mac -v <vlanid> - displays the MACs learnt on the particular VLAN ID.
3) show mac -p <port> - displays the MACs learnt on the particular port.
4) show mac -a <mac-address> - display the MACs that match a specific mac-address
5) show mac -t <type> - display the MACs that match a specific type (static/dynamic)
6) show mac -c - display the count of MAC addresses

To show the default MAC address aging time on the switch.

- Usage:
```
show mac [-v <vlan_id>] [-p <port_name>]
show mac [-v <vlan_id>] [-p <port_name>] [-a <mac_address>] [-t <type>] [-c]
```

- Example:
```
admin@sonic:~$ show mac
No. Vlan MacAddress Port
----- ------ ----------------- -----------
1 1000 E2:8C:56:85:4A:CD Ethernet192
2 1000 A0:1B:5E:47:C9:76 Ethernet192
3 1000 AA:54:EF:2C:EE:30 Ethernet192
4 1000 A4:3F:F2:17:A3:FC Ethernet192
5 1000 0C:FC:01:72:29:91 Ethernet192
6 1000 48:6D:01:7E:C9:FD Ethernet192
7 1000 1C:6B:7E:34:5F:A6 Ethernet192
8 1000 EE:81:D9:7B:93:A9 Ethernet192
9 1000 CC:F8:8D:BB:85:E2 Ethernet192
10 1000 0A:52:B3:9C:FB:6C Ethernet192
11 1000 C6:E2:72:02:D1:23 Ethernet192
12 1000 8A:C9:5C:25:E9:28 Ethernet192
13 1000 5E:CD:34:E4:94:18 Ethernet192
14 1000 7E:49:1F:B5:91:B5 Ethernet192
15 1000 AE:DD:67:F3:09:5A Ethernet192
16 1000 DC:2F:D1:08:4B:DE Ethernet192
17 1000 50:96:23:AD:F1:65 Ethernet192
18 1000 C6:C9:5E:AE:24:42 Ethernet192
No. Vlan MacAddress Port Type
----- ------ ----------------- ----------- -------
1 1000 E2:8C:56:85:4A:CD Ethernet192 Dynamic
2 1000 A0:1B:5E:47:C9:76 Ethernet192 Dynamic
3 1000 AA:54:EF:2C:EE:30 Ethernet192 Dynamic
4 1000 A4:3F:F2:17:A3:FC Ethernet192 Dynamic
5 1000 0C:FC:01:72:29:91 Ethernet192 Dynamic
6 1000 48:6D:01:7E:C9:FD Ethernet192 Dynamic
7 1000 1C:6B:7E:34:5F:A6 Ethernet192 Dynamic
8 1000 EE:81:D9:7B:93:A9 Ethernet192 Dynamic
9 1000 CC:F8:8D:BB:85:E2 Ethernet192 Dynamic
10 1000 0A:52:B3:9C:FB:6C Ethernet192 Dynamic
11 1000 C6:E2:72:02:D1:23 Ethernet192 Dynamic
12 1000 8A:C9:5C:25:E9:28 Ethernet192 Dynamic
13 1000 5E:CD:34:E4:94:18 Ethernet192 Dynamic
14 1000 7E:49:1F:B5:91:B5 Ethernet192 Dynamic
15 1000 AE:DD:67:F3:09:5A Ethernet192 Dynamic
16 1000 DC:2F:D1:08:4B:DE Ethernet192 Dynamic
17 1000 50:96:23:AD:F1:65 Ethernet192 Static
18 1000 C6:C9:5E:AE:24:42 Ethernet192 Static
dgsudharsan marked this conversation as resolved.
Show resolved Hide resolved
Total number of entries 18
```

Optionally, you can specify a VLAN ID or interface name in order to display only that particular entries
Optionally, you can specify a VLAN ID or interface name or type or mac-address in order to display only that particular entries

- Examples:
```
admin@sonic:~$ show mac -v 1000
No. Vlan MacAddress Port
----- ------ ----------------- -----------
1 1000 E2:8C:56:85:4A:CD Ethernet192
2 1000 A0:1B:5E:47:C9:76 Ethernet192
3 1000 AA:54:EF:2C:EE:30 Ethernet192
4 1000 A4:3F:F2:17:A3:FC Ethernet192
5 1000 0C:FC:01:72:29:91 Ethernet192
6 1000 48:6D:01:7E:C9:FD Ethernet192
7 1000 1C:6B:7E:34:5F:A6 Ethernet192
8 1000 EE:81:D9:7B:93:A9 Ethernet192
9 1000 CC:F8:8D:BB:85:E2 Ethernet192
10 1000 0A:52:B3:9C:FB:6C Ethernet192
11 1000 C6:E2:72:02:D1:23 Ethernet192
12 1000 8A:C9:5C:25:E9:28 Ethernet192
13 1000 5E:CD:34:E4:94:18 Ethernet192
14 1000 7E:49:1F:B5:91:B5 Ethernet192
15 1000 AE:DD:67:F3:09:5A Ethernet192
16 1000 DC:2F:D1:08:4B:DE Ethernet192
17 1000 50:96:23:AD:F1:65 Ethernet192
18 1000 C6:C9:5E:AE:24:42 Ethernet192
No. Vlan MacAddress Port Type
----- ------ ----------------- ----------- -------
1 1000 E2:8C:56:85:4A:CD Ethernet192 Dynamic
2 1000 A0:1B:5E:47:C9:76 Ethernet192 Dynamic
3 1000 AA:54:EF:2C:EE:30 Ethernet192 Dynamic
4 1000 A4:3F:F2:17:A3:FC Ethernet192 Dynamic
5 1000 0C:FC:01:72:29:91 Ethernet192 Dynamic
6 1000 48:6D:01:7E:C9:FD Ethernet192 Dynamic
7 1000 1C:6B:7E:34:5F:A6 Ethernet192 Dynamic
8 1000 EE:81:D9:7B:93:A9 Ethernet192 Dynamic
9 1000 CC:F8:8D:BB:85:E2 Ethernet192 Dynamic
10 1000 0A:52:B3:9C:FB:6C Ethernet192 Dynamic
11 1000 C6:E2:72:02:D1:23 Ethernet192 Dynamic
12 1000 8A:C9:5C:25:E9:28 Ethernet192 Dynamic
13 1000 5E:CD:34:E4:94:18 Ethernet192 Dynamic
14 1000 7E:49:1F:B5:91:B5 Ethernet192 Dynamic
15 1000 AE:DD:67:F3:09:5A Ethernet192 Dynamic
16 1000 DC:2F:D1:08:4B:DE Ethernet192 Dynamic
17 1000 50:96:23:AD:F1:65 Ethernet192 Static
18 1000 C6:C9:5E:AE:24:42 Ethernet192 Static
Total number of entries 18
```
```
admin@sonic:~$ show mac -p Ethernet192
No. Vlan MacAddress Port
----- ------ ----------------- -----------
1 1000 E2:8C:56:85:4A:CD Ethernet192
2 1000 A0:1B:5E:47:C9:76 Ethernet192
3 1000 AA:54:EF:2C:EE:30 Ethernet192
4 1000 A4:3F:F2:17:A3:FC Ethernet192
5 1000 0C:FC:01:72:29:91 Ethernet192
6 1000 48:6D:01:7E:C9:FD Ethernet192
7 1000 1C:6B:7E:34:5F:A6 Ethernet192
8 1000 EE:81:D9:7B:93:A9 Ethernet192
9 1000 CC:F8:8D:BB:85:E2 Ethernet192
10 1000 0A:52:B3:9C:FB:6C Ethernet192
11 1000 C6:E2:72:02:D1:23 Ethernet192
12 1000 8A:C9:5C:25:E9:28 Ethernet192
13 1000 5E:CD:34:E4:94:18 Ethernet192
14 1000 7E:49:1F:B5:91:B5 Ethernet192
15 1000 AE:DD:67:F3:09:5A Ethernet192
16 1000 DC:2F:D1:08:4B:DE Ethernet192
17 1000 50:96:23:AD:F1:65 Ethernet192
18 1000 C6:C9:5E:AE:24:42 Ethernet192
No. Vlan MacAddress Port Type
----- ------ ----------------- ----------- -------
1 1000 E2:8C:56:85:4A:CD Ethernet192 Dynamic
2 1000 A0:1B:5E:47:C9:76 Ethernet192 Dynamic
3 1000 AA:54:EF:2C:EE:30 Ethernet192 Dynamic
4 1000 A4:3F:F2:17:A3:FC Ethernet192 Dynamic
5 1000 0C:FC:01:72:29:91 Ethernet192 Dynamic
6 1000 48:6D:01:7E:C9:FD Ethernet192 Dynamic
7 1000 1C:6B:7E:34:5F:A6 Ethernet192 Dynamic
8 1000 EE:81:D9:7B:93:A9 Ethernet192 Dynamic
9 1000 CC:F8:8D:BB:85:E2 Ethernet192 Dynamic
10 1000 0A:52:B3:9C:FB:6C Ethernet192 Dynamic
11 1000 C6:E2:72:02:D1:23 Ethernet192 Dynamic
12 1000 8A:C9:5C:25:E9:28 Ethernet192 Dynamic
13 1000 5E:CD:34:E4:94:18 Ethernet192 Dynamic
14 1000 7E:49:1F:B5:91:B5 Ethernet192 Dynamic
15 1000 AE:DD:67:F3:09:5A Ethernet192 Dynamic
16 1000 DC:2F:D1:08:4B:DE Ethernet192 Dynamic
17 1000 50:96:23:AD:F1:65 Ethernet192 Static
18 1000 C6:C9:5E:AE:24:42 Ethernet192 Static
Total number of entries 18
```
```
admin@sonic:~$ show mac -a E2:8C:56:85:4A:CD
No. Vlan MacAddress Port Type
----- ------ ----------------- ----------- -------
1 1000 E2:8C:56:85:4A:CD Ethernet192 Dynamic
Total number of entries 1
```
```
admin@sonic:~$ show mac -t Static
No. Vlan MacAddress Port Type
----- ------ ----------------- ----------- -------
2 1000 50:96:23:AD:F1:65 Ethernet192 Static
2 1000 C6:C9:5E:AE:24:42 Ethernet192 Static
Total number of entries 2
```
```
admin@sonic:~$ show mac -c
Copy link
Contributor

@qiluo-msft qiluo-msft Jan 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

show mac -c

Is it same as show mac | grep Total? Not add much value. #Closed

Copy link
Collaborator Author

@dgsudharsan dgsudharsan Jan 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Qi,
I wrote a script and this would save a good amount of time in scaled configuration
Script is as below

date
fdbshow -c
date
fdbshow | grep Total
date

Output: -c takes 8 seconds whereas with grep the time taken is 14 seconds.

Wed 12 Jan 2022 05:30:23 AM UTC
Total number of entries 30747
Wed 12 Jan 2022 05:30:31 AM UTC
Total number of entries 30747
Wed 12 Jan 2022 05:30:45 AM UTC

In some scenarios it almost halves the time taken. On another note most of the options could be replaced by simple grep. The point of having them is performance as well as ease of use to the user. Most other operating systems do have these options and hence it makes beneficial to add this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering why it is so slow to grep. The only difference is collecting and printing a table. Is tabulate the slowest procedure?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Tabulate appears to be the bottleneck especially with bulk configurations. I prefer having the count option as is.

Total number of entries 18
```

**show mac aging-time**

This command displays the default mac aging time on the switch

```
admin@sonic:~$ show mac aging-time
Aging time for switch is 600 seconds
```
dgsudharsan marked this conversation as resolved.
Show resolved Hide resolved

**sonic-clear fdb all**

Expand Down
87 changes: 58 additions & 29 deletions scripts/fdbshow
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import argparse
import json
import sys
import os
import re

# mock the redis for unit test purposes #
try: # pragma: no cover
Expand All @@ -43,7 +44,9 @@ try: # pragma: no cover
"2": 'asic_db_def_vlan',
"3": 'asic_db_no_fdb',
"4": 'asic_db_no_bridge',
"5": 'asic_db_fetch_except'}
"5": 'asic_db_fetch_except',
"6": 'asic_db_no_static',
"7": 'asic_db_mac_case'}
mock_db_path = os.path.join(test_path, "fdbshow_input")
file_name = mock_variants[os.environ["FDBSHOW_MOCK"]]
jsonfile_asic = os.path.join(mock_db_path, file_name)
Expand All @@ -53,15 +56,13 @@ try: # pragma: no cover
except KeyError: # pragma: no cover
pass

from natsort import natsorted
from swsssdk import port_util
from swsscommon.swsscommon import SonicV2Connector
from tabulate import tabulate

class FdbShow(object):

HEADER = ['No.', 'Vlan', 'MacAddress', 'Port', 'Type']
FDB_COUNT = 0

def __init__(self):
super(FdbShow,self).__init__()
Expand Down Expand Up @@ -135,53 +136,81 @@ class FdbShow(object):
return


def get_iter_index(self, key_value, pos=0):
"""
Get the starting index of matched entry
"""
if pos != 0:
self.bridge_mac_list = natsorted(self.bridge_mac_list, key = lambda x: x[pos])

keys = [r[pos] for r in self.bridge_mac_list]
return keys.index(key_value)


def display(self, vlan, port):
def display(self, vlan, port, address, entry_type, count):
"""
Display the FDB entries for specified vlan/port.
@todo: - PortChannel support
"""
output = []

if vlan is not None:
vlan = int(vlan)
s_index = self.get_iter_index(vlan)
self.bridge_mac_list = [fdb for fdb in self.bridge_mac_list[s_index:]
if fdb[0] == vlan]
if port is not None:
s_index = self.get_iter_index(port, 2)
self.bridge_mac_list = [fdb for fdb in self.bridge_mac_list[s_index:]
if fdb[2] == port]
vlan_val = int(vlan)

if address is not None:
address = address.upper()

for fdb in self.bridge_mac_list:
self.FDB_COUNT += 1
output.append([self.FDB_COUNT, fdb[0], fdb[1], fdb[2], fdb[3]])
if entry_type is not None:
entry_type = entry_type.capitalize()

print(tabulate(output, self.HEADER))
print("Total number of entries {0}".format(self.FDB_COUNT))
self.bridge_mac_list = [fdb for fdb in self.bridge_mac_list
if (vlan is None or fdb[0] == vlan_val) and
(port is None or fdb[2] == port) and
(address is None or fdb[1] == address) and
(entry_type is None or fdb[3] == entry_type)]

if not count:
fdb_index = 1
for fdb in self.bridge_mac_list:
output.append([fdb_index, fdb[0], fdb[1], fdb[2], fdb[3]])
fdb_index += 1
print(tabulate(output, self.HEADER))

print("Total number of entries {0}".format(len(self.bridge_mac_list)))

def validate_params(self, vlan, port, address, entry_type):
if vlan is not None:
if not vlan.isnumeric():
print("Error: Invalid vlan id {0}".format(vlan))
return False

vlan_val = int(vlan)
if (vlan_val not in range(1,4096)):
print("Error: Invalid vlan id {0}".format(vlan))
return False

if port is not None and port not in self.if_name_map:
print("Error: Invalid port {0}".format(port))
return False

if address is not None:
mac_addr_pattern ="^([0-9A-Fa-f]{2}[:]){5}([0-9A-Fa-f]{2})$"
if not re.match(mac_addr_pattern, address):
print("Error: Invalid mac address {0}".format(address))
return False

if entry_type is not None and entry_type.capitalize() not in ["Static", "Dynamic"]:
print("Error: Invalid type {0}". format(entry_type))
return False

return True

def main():

parser = argparse.ArgumentParser(description='Display ASIC FDB entries',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-p', '--port', type=str, help='FDB learned on specific port: Ethernet0', default=None)
parser.add_argument('-v', '--vlan', type=str, help='FDB learned on specific Vlan: 1001', default=None)
parser.add_argument('-a', '--address', type=str, help='FDB display based on specific mac address', default=None)
parser.add_argument('-t', '--type', type=str, help='FDB display of specific type of mac address', default=None)
parser.add_argument('-c', '--count', action='store_true', help='FDB display count of mac address')
args = parser.parse_args()

try:
fdb = FdbShow()
fdb.display(args.vlan, args.port)
if not fdb.validate_params(args.vlan, args.port, args.address, args.type):
sys.exit(1)

fdb.display(args.vlan, args.port, args.address, args.type, args.count)
except Exception as e:
print(str(e))
sys.exit(1)
Expand Down
38 changes: 36 additions & 2 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -722,13 +722,20 @@ def pwm_headroom_pool():
# 'mac' command ("show mac ...")
#

@cli.command()
@cli.group(cls=clicommon.AliasedGroup, invoke_without_command="true")
@click.pass_context
@click.option('-v', '--vlan')
@click.option('-p', '--port')
@click.option('-a', '--address')
@click.option('-t', '--type')
@click.option('-c', '--count', is_flag=True)
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def mac(vlan, port, verbose):
def mac(ctx, vlan, port, address, type, count, verbose):
"""Show MAC (FDB) entries"""

if ctx.invoked_subcommand is not None:
return

cmd = "fdbshow"

if vlan is not None:
Expand All @@ -737,8 +744,35 @@ def mac(vlan, port, verbose):
if port is not None:
cmd += " -p {}".format(port)

if address is not None:
cmd += " -a {}".format(address)

if type is not None:
cmd += " -t {}".format(type)

if count:
cmd += " -c"

run_command(cmd, display_cmd=verbose)

@mac.command('aging-time')
@click.pass_context
def aging_time(ctx):
app_db = SonicV2Connector()
app_db.connect(app_db.APPL_DB)
table = "SWITCH_TABLE*"
keys = app_db.keys(app_db.APPL_DB, table)

if not keys:
click.echo("Aging time not configured for the switch")
return

for key in keys:
fdb_aging_time = app_db.get(app_db.APPL_DB, key, 'fdb_aging_time')
if fdb_aging_time is not None:
click.echo("Aging time for {} is {} seconds".format(key.split(':')[-1], fdb_aging_time))
else:
click.echo("Aging time not configured for the {}".format(key.split(':')[-1]))
dgsudharsan marked this conversation as resolved.
Show resolved Hide resolved
#
# 'show route-map' command ("show route-map")
#
Expand Down
5 changes: 5 additions & 0 deletions tests/fdbshow_input/appl_db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"SWITCH_TABLE:switch": {
"fdb_aging_time" : "600"
}
}
5 changes: 5 additions & 0 deletions tests/fdbshow_input/appl_db_no_age.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"SWITCH_TABLE:switch": {
"ecmp_hash_seed" : "600"
}
}
Loading