Skip to content

Commit 2a2d7b6

Browse files
committed
feat: support namespace arg for show mac
1 parent aa52db8 commit 2a2d7b6

File tree

7 files changed

+138
-13
lines changed

7 files changed

+138
-13
lines changed

doc/Command-Reference.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -11827,12 +11827,13 @@ This command displays the MAC (FDB) entries either in full or partial as given b
1182711827
4) show mac -a <mac-address> - display the MACs that match a specific mac-address
1182811828
5) show mac -t <type> - display the MACs that match a specific type (static/dynamic)
1182911829
6) show mac -c - display the count of MAC addresses
11830+
7) show mac -n <namespace> - display the MACs that belong to a specific namespace
1183011831

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

1183311834
- Usage:
1183411835
```
11835-
show mac [-v <vlan_id>] [-p <port_name>] [-a <mac_address>] [-t <type>] [-c]
11836+
show mac [-v <vlan_id>] [-p <port_name>] [-a <mac_address>] [-t <type>] [-c] [-n <namespace>]
1183611837
```
1183711838

1183811839
- Example:
@@ -11931,6 +11932,14 @@ Optionally, you can specify a VLAN ID or interface name or type or mac-address i
1193111932
admin@sonic:~$ show mac -c
1193211933
Total number of entries 18
1193311934
```
11935+
```
11936+
admin@sonic:~$ show mac -n asic0
11937+
No. Vlan MacAddress Port Type
11938+
----- ------ ----------------- ----------- -------
11939+
2 1000 50:96:23:AD:F1:65 Ethernet192 Static
11940+
2 1000 C6:C9:5E:AE:24:42 Ethernet192 Static
11941+
Total number of entries 2
11942+
```
1193411943

1193511944
**show mac aging-time**
1193611945

scripts/fdbshow

+36-11
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,18 @@ import sys
3232
import os
3333
import re
3434

35+
from utilities_common.general import load_db_config
36+
3537
# mock the redis for unit test purposes #
3638
try: # pragma: no cover
37-
if os.environ["UTILITIES_UNIT_TESTING"] == "1":
39+
if os.environ["UTILITIES_UNIT_TESTING"] == "1":
3840
modules_path = os.path.join(os.path.dirname(__file__), "..")
3941
test_path = os.path.join(modules_path, "tests")
4042
sys.path.insert(0, modules_path)
4143
sys.path.insert(0, test_path)
42-
import mock_tables.dbconnector
44+
from tests.mock_tables import dbconnector
45+
46+
if os.environ["FDBSHOW_UNIT_TESTING"] == "1":
4347
mock_variants = { "1": 'asic_db',
4448
"2": 'asic_db_def_vlan',
4549
"3": 'asic_db_no_fdb',
@@ -50,23 +54,34 @@ try: # pragma: no cover
5054
mock_db_path = os.path.join(test_path, "fdbshow_input")
5155
file_name = mock_variants[os.environ["FDBSHOW_MOCK"]]
5256
jsonfile_asic = os.path.join(mock_db_path, file_name)
53-
mock_tables.dbconnector.dedicated_dbs['ASIC_DB'] = jsonfile_asic
57+
dbconnector.dedicated_dbs['ASIC_DB'] = jsonfile_asic
5458
jsonfile_counters = os.path.join(mock_db_path, 'counters_db')
55-
mock_tables.dbconnector.dedicated_dbs['COUNTERS_DB'] = jsonfile_counters
59+
dbconnector.dedicated_dbs['COUNTERS_DB'] = jsonfile_counters
60+
61+
if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic":
62+
import tests.mock_tables.mock_multi_asic
63+
dbconnector.load_namespace_config()
5664
except KeyError: # pragma: no cover
5765
pass
5866

59-
from sonic_py_common import port_util
60-
from swsscommon.swsscommon import SonicV2Connector
67+
from sonic_py_common import port_util, multi_asic
68+
from swsscommon.swsscommon import SonicV2Connector, SonicDBConfig
6169
from tabulate import tabulate
6270

6371
class FdbShow(object):
6472

6573
HEADER = ['No.', 'Vlan', 'MacAddress', 'Port', 'Type']
6674

67-
def __init__(self):
75+
def __init__(self, namespace=None):
6876
super(FdbShow,self).__init__()
69-
self.db = SonicV2Connector(host="127.0.0.1")
77+
if namespace is not None:
78+
if not SonicDBConfig.isGlobalInit():
79+
SonicDBConfig.load_sonic_global_db_config()
80+
81+
self.db = SonicV2Connector(use_unix_socket_path=True, namespace=namespace)
82+
else:
83+
self.db = SonicV2Connector(host="127.0.0.1")
84+
7085
self.if_name_map, \
7186
self.if_oid_map = port_util.get_interface_oid_map(self.db)
7287
self.if_br_oid_map = port_util.get_bridge_port_map(self.db)
@@ -169,7 +184,7 @@ class FdbShow(object):
169184

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

172-
def validate_params(self, vlan, port, address, entry_type):
187+
def validate_params(self, vlan, port, address, entry_type, namespace):
173188
if vlan is not None:
174189
if not vlan.isnumeric():
175190
print("Error: Invalid vlan id {0}".format(vlan))
@@ -194,6 +209,15 @@ class FdbShow(object):
194209
print("Error: Invalid type {0}". format(entry_type))
195210
return False
196211

212+
if namespace is not None:
213+
if not multi_asic.is_multi_asic():
214+
print("Error: Namespace is not supported in single asic")
215+
return False
216+
217+
if namespace not in multi_asic.get_namespace_list():
218+
print("Error: Invalid namespace {0}".format(namespace))
219+
return False
220+
197221
return True
198222

199223
def main():
@@ -205,11 +229,12 @@ def main():
205229
parser.add_argument('-a', '--address', type=str, help='FDB display based on specific mac address', default=None)
206230
parser.add_argument('-t', '--type', type=str, help='FDB display of specific type of mac address', default=None)
207231
parser.add_argument('-c', '--count', action='store_true', help='FDB display count of mac address')
232+
parser.add_argument('-n', '--namespace', type=str, help='Namespace name or all', default=None)
208233
args = parser.parse_args()
209234

210235
try:
211-
fdb = FdbShow()
212-
if not fdb.validate_params(args.vlan, args.port, args.address, args.type):
236+
fdb = FdbShow(namespace=args.namespace)
237+
if not fdb.validate_params(args.vlan, args.port, args.address, args.type, args.namespace):
213238
sys.exit(1)
214239

215240
fdb.display(args.vlan, args.port, args.address, args.type, args.count)

show/main.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -1121,7 +1121,15 @@ def pwm_headroom_pool(namespace):
11211121
@click.option('-t', '--type')
11221122
@click.option('-c', '--count', is_flag=True)
11231123
@click.option('--verbose', is_flag=True, help="Enable verbose output")
1124-
def mac(ctx, vlan, port, address, type, count, verbose):
1124+
@click.option('-n',
1125+
'--namespace',
1126+
'namespace',
1127+
default=None,
1128+
type=str,
1129+
show_default=True,
1130+
help='Namespace name or all',
1131+
callback=multi_asic_util.multi_asic_namespace_validation_callback)
1132+
def mac(ctx, vlan, port, address, type, count, verbose, namespace):
11251133
"""Show MAC (FDB) entries"""
11261134

11271135
if ctx.invoked_subcommand is not None:
@@ -1144,6 +1152,9 @@ def mac(ctx, vlan, port, address, type, count, verbose):
11441152
if count:
11451153
cmd += ["-c"]
11461154

1155+
if namespace is not None:
1156+
cmd += ['-n', str(namespace)]
1157+
11471158
run_command(cmd, display_cmd=verbose)
11481159

11491160
@mac.command('aging-time')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
show_mac_masic_asic0_output = """\
2+
No. Vlan MacAddress Port Type
3+
----- ------ ----------------- --------- -------
4+
1 2 11:22:33:44:55:66 Ethernet0 Dynamic
5+
Total number of entries 1
6+
"""
7+
8+
test_data = {
9+
"show_mac_masic_asic0": {
10+
"cmd": "mac",
11+
"args": "-n asic0",
12+
"expected_output": show_mac_masic_asic0_output,
13+
}
14+
}

tests/fdbshow_test.py

+2
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,12 @@ def setup_class(cls):
148148
print("SETUP")
149149
os.environ["PATH"] += os.pathsep + scripts_path
150150
os.environ["UTILITIES_UNIT_TESTING"] = "1"
151+
os.environ["FDBSHOW_UNIT_TESTING"] = "1"
151152
yield
152153
print("TEARDOWN")
153154
os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1])
154155
os.environ["UTILITIES_UNIT_TESTING"] = "0"
156+
os.environ["FDBSHOW_UNIT_TESTING"] = "0"
155157

156158
@pytest.fixture(scope="function", autouse=True)
157159
def setUp(self):

tests/mock_tables/asic0/asic_db.json

+14
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,19 @@
22
"ASIC_STATE:SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000": {
33
"SAI_SWITCH_ATTR_INIT_SWITCH": "true",
44
"SAI_SWITCH_ATTR_SRC_MAC_ADDRESS": "DE:AD:BE:EF:CA:FE"
5+
},
6+
"ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT:oid:0x3a0000000005cb": {
7+
"SAI_BRIDGE_PORT_ATTR_TYPE": "SAI_BRIDGE_PORT_TYPE_PORT",
8+
"SAI_BRIDGE_PORT_ATTR_PORT_ID": "oid:0x1000000000002",
9+
"SAI_BRIDGE_PORT_ATTR_ADMIN_STATE": "true",
10+
"SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE": "SAI_BRIDGE_PORT_FDB_LEARNING_MODE_HW"
11+
},
12+
"ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:{\"bvid\":\"oid:0x260000000005c5\",\"mac\":\"11:22:33:44:55:66\",\"switch_id\":\"oid:0x21000000000000\"}": {
13+
"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID": "oid:0x3a0000000005cb",
14+
"SAI_FDB_ENTRY_ATTR_TYPE": "SAI_FDB_ENTRY_TYPE_DYNAMIC",
15+
"SAI_FDB_ENTRY_ATTR_PACKET_ACTION": "SAI_PACKET_ACTION_FORWARD"
16+
},
17+
"ASIC_STATE:SAI_OBJECT_TYPE_VLAN:oid:0x260000000005c5": {
18+
"SAI_VLAN_ATTR_VLAN_ID": "2"
519
}
620
}

tests/multi_asic_fdbshow_test.py

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import os
2+
import sys
3+
4+
from click.testing import CliRunner
5+
6+
from tests.fdbshow_input.fdbshow_masic_test_vectors import show_mac_masic_asic0_output, test_data
7+
from tests.utils import get_result_and_return_code
8+
9+
test_path = os.path.dirname(os.path.abspath(__file__))
10+
modules_path = os.path.dirname(test_path)
11+
scripts_path = os.path.join(modules_path, "scripts")
12+
sys.path.insert(0, test_path)
13+
sys.path.insert(0, modules_path)
14+
15+
16+
class TestFdbshowMultiAsic(object):
17+
@classmethod
18+
def setup_class(cls):
19+
os.environ["PATH"] += os.pathsep + scripts_path
20+
os.environ['UTILITIES_UNIT_TESTING'] = "1"
21+
os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic"
22+
print("SETUP")
23+
24+
def test_show_mac_masic_asic0(self):
25+
return_code, result = get_result_and_return_code([
26+
'fdbshow', '-n', 'asic0'
27+
])
28+
print("return_code: {}".format(return_code))
29+
print("result: {}".format(result))
30+
assert return_code == 0
31+
assert result == show_mac_masic_asic0_output
32+
33+
self.command_executor(test_data["show_mac_masic_asic0"])
34+
35+
@classmethod
36+
def teardown_class(cls):
37+
os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1])
38+
os.environ['UTILITIES_UNIT_TESTING'] = "0"
39+
os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = ""
40+
print("TEARDOWN")
41+
42+
@staticmethod
43+
def command_executor(test_case_data):
44+
import show.main as show
45+
runner = CliRunner()
46+
result = runner.invoke(show.cli.commands["mac"], test_case_data["args"])
47+
print("result.exit_code: {}".format(result.exit_code))
48+
print("result.output: {}".format(result.output))
49+
assert result.exit_code == 0
50+
assert result.output == test_case_data["expected_output"]

0 commit comments

Comments
 (0)