Skip to content

Commit 90efd62

Browse files
authored
[Show | Command Reference] Add Port breakout Show Command (sonic-net#859)
**- What I did** Implemented show interface breakout sub-command to show the port capability and the current breakout mode. Available commands are mentioned below. ``` show interfaces breakout --help show interfaces breakout current-mode ``` **- How I did it** using platform.json, hwsku.json and config-db BREAKOUT_CFG table. **- How to verify it** ``` admin@lnos-x1-a-fab01:~$ show interfaces breakout --help Usage: show interfaces breakout [OPTIONS] COMMAND [ARGS]... Show interface breakout Options: -?, -h, --help Show this message and exit. Commands: current-mode Show interface breakout current-mode ``` ``` admin@lnos-x1-a-fab01:~$ show interfaces breakout { "Ethernet0": { "index": "1,1,1,1", "default_brkout_mode": "1x100G[40G]", "child ports": "Ethernet0", "child port speed": "100G", "breakout_modes": "1x100G[40G],2x50G,4x25G[10G]", "Current Breakout Mode": "1x100G[40G]", "lanes": "65,66,67,68", "alias_at_lanes": "Eth1/1, Eth1/2, Eth1/3, Eth1/4" }, "Ethernet4": { "index": "2,2,2,2", "default_brkout_mode": "1x100G[40G]", "child ports": "Ethernet4,Ethernet5,Ethernet6,Ethernet7", "child port speed": "25G,10G,25G,25G", "breakout_modes": "1x100G[40G],2x50G,4x25G[10G]", "Current Breakout Mode": "4x25G", "lanes": "69,70,71,72", "alias_at_lanes": "Eth2/1, Eth2/2, Eth2/3, Eth2/4" }, "Ethernet8": { "index": "3,3,3,3", "default_brkout_mode": "1x100G[40G]", "child ports": "Ethernet8", "child port speed": "100G", "breakout_modes": "1x100G[40G],2x50G,4x25G[10G]", "Current Breakout Mode": "1x100G[40G]", "lanes": "73,74,75,76", "alias_at_lanes": "Eth3/1, Eth3/2, Eth3/3, Eth3/4" },... continue } ``` ``` admin@lnos-x1-a-fab01:~$ show interfaces breakout current-mode Ethernet0 +-------------+-------------------------+ | Interface | Current Breakout Mode | +=============+=========================+ | Ethernet0 | 4x25G[10G] | +-------------+-------------------------+ ``` ``` admin@lnos-x1-a-fab01:~$ show interfaces breakout current-mode +-------------+-------------------------+ | Interface | Current Breakout Mode | +=============+=========================+ | Ethernet0 | 4x25G[10G] | +-------------+-------------------------+ | Ethernet4 | 4x25G[10G] | +-------------+-------------------------+ | Ethernet8 | 4x25G[10G] | +-------------+-------------------------+ ``` Signed-off-by: Sangita Maity <[email protected]>
1 parent fa19b4c commit 90efd62

File tree

4 files changed

+236
-0
lines changed

4 files changed

+236
-0
lines changed

doc/Command-Reference.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2345,6 +2345,7 @@ Subsequent pages explain each of these commands in detail.
23452345
-?, -h, --help Show this message and exit.
23462346

23472347
Commands:
2348+
breakout Show Breakout Mode information by interfaces
23482349
counters Show interface counters
23492350
description Show interface status, protocol and...
23502351
naming_mode Show interface naming_mode status
@@ -2354,6 +2355,56 @@ Subsequent pages explain each of these commands in detail.
23542355
transceiver Show SFP Transceiver information
23552356
```
23562357
2358+
**show interfaces breakout**
2359+
2360+
This show command displays the port capability for all interfaces i.e. index, lanes, default_brkout_mode, breakout_modes(i.e. all the available breakout modes) and brkout_mode (i.e. current breakout mode). To display current breakout mode, "current-mode" subcommand can be used.For a single interface, provide the interface name with the sub-command.
2361+
2362+
- Usage:
2363+
```
2364+
show interfaces breakout
2365+
show interfaces breakout current-mode
2366+
show interfaces breakout current-mode <interface_name>
2367+
```
2368+
2369+
- Example:
2370+
```
2371+
admin@lnos-x1-a-fab01:~$ show interfaces breakout
2372+
{
2373+
"Ethernet0": {
2374+
"index": "1,1,1,1",
2375+
"default_brkout_mode": "1x100G[40G]",
2376+
"child ports": "Ethernet0",
2377+
"child port speed": "100G",
2378+
"breakout_modes": "1x100G[40G],2x50G,4x25G[10G]",
2379+
"Current Breakout Mode": "1x100G[40G]",
2380+
"lanes": "65,66,67,68",
2381+
"alias_at_lanes": "Eth1/1, Eth1/2, Eth1/3, Eth1/4"
2382+
},... continue
2383+
}
2384+
2385+
The "current-mode" subcommand is used to display current breakout mode for all interfaces.
2386+
2387+
admin@lnos-x1-a-fab01:~$ show interfaces breakout current-mode
2388+
+-------------+-------------------------+
2389+
| Interface | Current Breakout Mode |
2390+
+=============+=========================+
2391+
| Ethernet0 | 4x25G[10G] |
2392+
+-------------+-------------------------+
2393+
| Ethernet4 | 4x25G[10G] |
2394+
+-------------+-------------------------+
2395+
| Ethernet8 | 4x25G[10G] |
2396+
+-------------+-------------------------+
2397+
| Ethernet12 | 4x25G[10G] |
2398+
+-------------+-------------------------+
2399+
2400+
admin@lnos-x1-a-fab01:~$ show interfaces breakout current-mode Ethernet0
2401+
+-------------+-------------------------+
2402+
| Interface | Current Breakout Mode |
2403+
+=============+=========================+
2404+
| Ethernet0 | 4x25G[10G] |
2405+
+-------------+-------------------------+
2406+
```
2407+
23572408
**show interfaces counters**
23582409
23592410
This show command displays packet counters for all interfaces since the last time the counters were cleared. To display l3 counters "rif" subcommand can be used. There is no facility to display counters for one specific l2 interface. For l3 interfaces a single interface output mode is present. Optional argument "-a" provides two additional columns - RX-PPS and TX_PPS.

show/main.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import sys
1010
import ipaddress
1111
from pkg_resources import parse_version
12+
from collections import OrderedDict
1213

1314
import click
1415
from natsort import natsorted
@@ -17,10 +18,16 @@
1718
import sonic_device_util
1819
from swsssdk import ConfigDBConnector
1920
from swsssdk import SonicV2Connector
21+
from portconfig import get_child_ports
2022

2123
import mlnx
2224

25+
# Global Variable
26+
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
27+
PLATFORM_JSON = 'platform.json'
28+
HWSKU_JSON = 'hwsku.json'
2329
SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
30+
PORT_STR = "Ethernet"
2431

2532
VLAN_SUB_INTERFACE_SEPARATOR = '.'
2633

@@ -181,6 +188,15 @@ def get_routing_stack():
181188
# Global Routing-Stack variable
182189
routing_stack = get_routing_stack()
183190

191+
# Read given JSON file
192+
def readJsonFile(fileName):
193+
try:
194+
with open(fileName) as f:
195+
result = json.load(f)
196+
except Exception as e:
197+
click.echo(str(e))
198+
raise click.Abort()
199+
return result
184200

185201
def run_command(command, display_cmd=False, return_cmd=False):
186202
if display_cmd:
@@ -789,6 +805,101 @@ def alias(interfacename):
789805

790806
click.echo(tabulate(body, header))
791807

808+
809+
#
810+
# 'breakout' group ###
811+
#
812+
@interfaces.group(invoke_without_command=True)
813+
@click.pass_context
814+
def breakout(ctx):
815+
"""Show Breakout Mode information by interfaces"""
816+
# Reading data from Redis configDb
817+
config_db = ConfigDBConnector()
818+
config_db.connect()
819+
ctx.obj = {'db': config_db}
820+
821+
try:
822+
curBrkout_tbl = config_db.get_table('BREAKOUT_CFG')
823+
except Exception as e:
824+
click.echo("Breakout table is not present in Config DB")
825+
raise click.Abort()
826+
827+
if ctx.invoked_subcommand is None:
828+
829+
# Get HWSKU and Platform information
830+
hw_info_dict = get_hw_info_dict()
831+
platform = hw_info_dict['platform']
832+
hwsku = hw_info_dict['hwsku']
833+
834+
# Get port capability from platform and hwsku related files
835+
platformFile = "{}/{}/{}".format(PLATFORM_ROOT_PATH, platform, PLATFORM_JSON)
836+
platformDict = readJsonFile(platformFile)['interfaces']
837+
hwskuDict = readJsonFile("{}/{}/{}/{}".format(PLATFORM_ROOT_PATH, platform, hwsku, HWSKU_JSON))['interfaces']
838+
839+
if not platformDict or not hwskuDict:
840+
click.echo("Can not load port config from {} or {} file".format(PLATFORM_JSON, HWSKU_JSON))
841+
raise click.Abort()
842+
843+
for port_name in platformDict.keys():
844+
curBrkout_mode = curBrkout_tbl[port_name]["brkout_mode"]
845+
846+
# Update deafult breakout mode and current breakout mode to platformDict
847+
platformDict[port_name].update(hwskuDict[port_name])
848+
platformDict[port_name]["Current Breakout Mode"] = curBrkout_mode
849+
850+
# List all the child ports if present
851+
child_portDict = get_child_ports(port_name, curBrkout_mode, platformFile)
852+
if not child_portDict:
853+
click.echo("Cannot find ports from {} file ".format(PLATFORM_JSON))
854+
raise click.Abort()
855+
856+
child_ports = natsorted(child_portDict.keys())
857+
858+
children, speeds = [], []
859+
# Update portname and speed of child ports if present
860+
for port in child_ports:
861+
speed = config_db.get_entry('PORT', port).get('speed')
862+
if speed is not None:
863+
speeds.append(str(int(speed)//1000)+'G')
864+
children.append(port)
865+
866+
platformDict[port_name]["child ports"] = ",".join(children)
867+
platformDict[port_name]["child port speeds"] = ",".join(speeds)
868+
869+
# Sorted keys by name in natural sort Order for human readability
870+
parsed = OrderedDict((k, platformDict[k]) for k in natsorted(platformDict.keys()))
871+
click.echo(json.dumps(parsed, indent=4))
872+
873+
# 'breakout current-mode' subcommand ("show interfaces breakout current-mode")
874+
@breakout.command('current-mode')
875+
@click.argument('interface', metavar='<interface_name>', required=False, type=str)
876+
@click.pass_context
877+
def currrent_mode(ctx, interface):
878+
"""Show current Breakout mode Info by interface(s)"""
879+
880+
config_db = ctx.obj['db']
881+
882+
header = ['Interface', 'Current Breakout Mode']
883+
body = []
884+
885+
try:
886+
curBrkout_tbl = config_db.get_table('BREAKOUT_CFG')
887+
except Exception as e:
888+
click.echo("Breakout table is not present in Config DB")
889+
raise click.Abort()
890+
891+
# Show current Breakout Mode of user prompted interface
892+
if interface is not None:
893+
body.append([interface, str(curBrkout_tbl[interface]['brkout_mode'])])
894+
click.echo(tabulate(body, header, tablefmt="grid"))
895+
return
896+
897+
# Show current Breakout Mode for all interfaces
898+
for name in natsorted(curBrkout_tbl.keys()):
899+
body.append([name, str(curBrkout_tbl[name]['brkout_mode'])])
900+
click.echo(tabulate(body, header, tablefmt="grid"))
901+
902+
792903
#
793904
# 'neighbor' group ###
794905
#

sonic-utilities-tests/mock_tables/config_db.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
{
2+
"BREAKOUT_CFG|Ethernet0": {
3+
"brkout_mode": "4x25G[10G]"
4+
},
5+
"BREAKOUT_CFG|Ethernet4": {
6+
"brkout_mode": "2x50G"
7+
},
8+
"BREAKOUT_CFG|Ethernet8": {
9+
"brkout_mode": "1x100G[40G]"
10+
},
211
"PORT|Ethernet0": {
312
"alias": "etp1",
413
"lanes": "0,1,2,3",
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import os
2+
import sys
3+
from click.testing import CliRunner
4+
from unittest import TestCase
5+
from swsssdk import ConfigDBConnector
6+
7+
test_path = os.path.dirname(os.path.abspath(__file__))
8+
modules_path = os.path.dirname(test_path)
9+
sys.path.insert(0, test_path)
10+
sys.path.insert(0, modules_path)
11+
12+
import mock_tables.dbconnector
13+
import show.main as show
14+
15+
# Expected output for 'show breakout current-mode'
16+
current_mode_all_output = ''+ \
17+
"""+-------------+-------------------------+
18+
| Interface | Current Breakout Mode |
19+
+=============+=========================+
20+
| Ethernet0 | 4x25G[10G] |
21+
+-------------+-------------------------+
22+
| Ethernet4 | 2x50G |
23+
+-------------+-------------------------+
24+
| Ethernet8 | 1x100G[40G] |
25+
+-------------+-------------------------+
26+
"""
27+
28+
# Expected output for 'show breakout current-mode Ethernet0'
29+
current_mode_intf_output = ''+ \
30+
"""+-------------+-------------------------+
31+
| Interface | Current Breakout Mode |
32+
+=============+=========================+
33+
| Ethernet0 | 4x25G[10G] |
34+
+-------------+-------------------------+
35+
"""
36+
37+
class TestBreakout(TestCase):
38+
@classmethod
39+
def setup_class(cls):
40+
print("SETUP")
41+
os.environ["UTILITIES_UNIT_TESTING"] = "1"
42+
43+
def setUp(self):
44+
self.runner = CliRunner()
45+
self.config_db = ConfigDBConnector()
46+
self.config_db.connect()
47+
self.obj = {'db': self.config_db}
48+
49+
# Test 'show interfaces breakout current-mode'
50+
def test_all_intf_current_mode(self):
51+
result = self.runner.invoke(show.cli.commands["interfaces"].commands["breakout"].commands["current-mode"], [], obj=self.obj)
52+
print(sys.stderr, result.output)
53+
assert result.output == current_mode_all_output
54+
55+
# Test 'show interfaces breakout current-mode Ethernet0'
56+
def test_single_intf_current_mode(self):
57+
result = self.runner.invoke(show.cli.commands["interfaces"].commands["breakout"].commands["current-mode"], ["Ethernet0"], obj=self.obj)
58+
print(sys.stderr, result.output)
59+
assert result.output == current_mode_intf_output
60+
61+
@classmethod
62+
def teardown_class(cls):
63+
print("TEARDOWN")
64+
os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1])
65+
os.environ["UTILITIES_UNIT_TESTING"] = "0"

0 commit comments

Comments
 (0)