Skip to content

Commit

Permalink
[Show | Command Reference] Add Port breakout Show Command (sonic-net#859
Browse files Browse the repository at this point in the history
)

**- 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 <sangitamaity0211@gmail.com>
  • Loading branch information
samaity authored Jun 25, 2020
1 parent fa19b4c commit 90efd62
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 0 deletions.
51 changes: 51 additions & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2345,6 +2345,7 @@ Subsequent pages explain each of these commands in detail.
-?, -h, --help Show this message and exit.

Commands:
breakout Show Breakout Mode information by interfaces
counters Show interface counters
description Show interface status, protocol and...
naming_mode Show interface naming_mode status
Expand All @@ -2354,6 +2355,56 @@ Subsequent pages explain each of these commands in detail.
transceiver Show SFP Transceiver information
```
**show interfaces breakout**
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.
- Usage:
```
show interfaces breakout
show interfaces breakout current-mode
show interfaces breakout current-mode <interface_name>
```
- Example:
```
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"
},... continue
}

The "current-mode" subcommand is used to display current breakout mode for all interfaces.

admin@lnos-x1-a-fab01:~$ show interfaces breakout current-mode
+-------------+-------------------------+
| Interface | Current Breakout Mode |
+=============+=========================+
| Ethernet0 | 4x25G[10G] |
+-------------+-------------------------+
| Ethernet4 | 4x25G[10G] |
+-------------+-------------------------+
| Ethernet8 | 4x25G[10G] |
+-------------+-------------------------+
| Ethernet12 | 4x25G[10G] |
+-------------+-------------------------+

admin@lnos-x1-a-fab01:~$ show interfaces breakout current-mode Ethernet0
+-------------+-------------------------+
| Interface | Current Breakout Mode |
+=============+=========================+
| Ethernet0 | 4x25G[10G] |
+-------------+-------------------------+
```
**show interfaces counters**
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.
Expand Down
111 changes: 111 additions & 0 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import sys
import ipaddress
from pkg_resources import parse_version
from collections import OrderedDict

import click
from natsort import natsorted
Expand All @@ -17,10 +18,16 @@
import sonic_device_util
from swsssdk import ConfigDBConnector
from swsssdk import SonicV2Connector
from portconfig import get_child_ports

import mlnx

# Global Variable
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
PLATFORM_JSON = 'platform.json'
HWSKU_JSON = 'hwsku.json'
SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
PORT_STR = "Ethernet"

VLAN_SUB_INTERFACE_SEPARATOR = '.'

Expand Down Expand Up @@ -181,6 +188,15 @@ def get_routing_stack():
# Global Routing-Stack variable
routing_stack = get_routing_stack()

# Read given JSON file
def readJsonFile(fileName):
try:
with open(fileName) as f:
result = json.load(f)
except Exception as e:
click.echo(str(e))
raise click.Abort()
return result

def run_command(command, display_cmd=False, return_cmd=False):
if display_cmd:
Expand Down Expand Up @@ -789,6 +805,101 @@ def alias(interfacename):

click.echo(tabulate(body, header))


#
# 'breakout' group ###
#
@interfaces.group(invoke_without_command=True)
@click.pass_context
def breakout(ctx):
"""Show Breakout Mode information by interfaces"""
# Reading data from Redis configDb
config_db = ConfigDBConnector()
config_db.connect()
ctx.obj = {'db': config_db}

try:
curBrkout_tbl = config_db.get_table('BREAKOUT_CFG')
except Exception as e:
click.echo("Breakout table is not present in Config DB")
raise click.Abort()

if ctx.invoked_subcommand is None:

# Get HWSKU and Platform information
hw_info_dict = get_hw_info_dict()
platform = hw_info_dict['platform']
hwsku = hw_info_dict['hwsku']

# Get port capability from platform and hwsku related files
platformFile = "{}/{}/{}".format(PLATFORM_ROOT_PATH, platform, PLATFORM_JSON)
platformDict = readJsonFile(platformFile)['interfaces']
hwskuDict = readJsonFile("{}/{}/{}/{}".format(PLATFORM_ROOT_PATH, platform, hwsku, HWSKU_JSON))['interfaces']

if not platformDict or not hwskuDict:
click.echo("Can not load port config from {} or {} file".format(PLATFORM_JSON, HWSKU_JSON))
raise click.Abort()

for port_name in platformDict.keys():
curBrkout_mode = curBrkout_tbl[port_name]["brkout_mode"]

# Update deafult breakout mode and current breakout mode to platformDict
platformDict[port_name].update(hwskuDict[port_name])
platformDict[port_name]["Current Breakout Mode"] = curBrkout_mode

# List all the child ports if present
child_portDict = get_child_ports(port_name, curBrkout_mode, platformFile)
if not child_portDict:
click.echo("Cannot find ports from {} file ".format(PLATFORM_JSON))
raise click.Abort()

child_ports = natsorted(child_portDict.keys())

children, speeds = [], []
# Update portname and speed of child ports if present
for port in child_ports:
speed = config_db.get_entry('PORT', port).get('speed')
if speed is not None:
speeds.append(str(int(speed)//1000)+'G')
children.append(port)

platformDict[port_name]["child ports"] = ",".join(children)
platformDict[port_name]["child port speeds"] = ",".join(speeds)

# Sorted keys by name in natural sort Order for human readability
parsed = OrderedDict((k, platformDict[k]) for k in natsorted(platformDict.keys()))
click.echo(json.dumps(parsed, indent=4))

# 'breakout current-mode' subcommand ("show interfaces breakout current-mode")
@breakout.command('current-mode')
@click.argument('interface', metavar='<interface_name>', required=False, type=str)
@click.pass_context
def currrent_mode(ctx, interface):
"""Show current Breakout mode Info by interface(s)"""

config_db = ctx.obj['db']

header = ['Interface', 'Current Breakout Mode']
body = []

try:
curBrkout_tbl = config_db.get_table('BREAKOUT_CFG')
except Exception as e:
click.echo("Breakout table is not present in Config DB")
raise click.Abort()

# Show current Breakout Mode of user prompted interface
if interface is not None:
body.append([interface, str(curBrkout_tbl[interface]['brkout_mode'])])
click.echo(tabulate(body, header, tablefmt="grid"))
return

# Show current Breakout Mode for all interfaces
for name in natsorted(curBrkout_tbl.keys()):
body.append([name, str(curBrkout_tbl[name]['brkout_mode'])])
click.echo(tabulate(body, header, tablefmt="grid"))


#
# 'neighbor' group ###
#
Expand Down
9 changes: 9 additions & 0 deletions sonic-utilities-tests/mock_tables/config_db.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
{
"BREAKOUT_CFG|Ethernet0": {
"brkout_mode": "4x25G[10G]"
},
"BREAKOUT_CFG|Ethernet4": {
"brkout_mode": "2x50G"
},
"BREAKOUT_CFG|Ethernet8": {
"brkout_mode": "1x100G[40G]"
},
"PORT|Ethernet0": {
"alias": "etp1",
"lanes": "0,1,2,3",
Expand Down
65 changes: 65 additions & 0 deletions sonic-utilities-tests/show_breakout_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import os
import sys
from click.testing import CliRunner
from unittest import TestCase
from swsssdk import ConfigDBConnector

test_path = os.path.dirname(os.path.abspath(__file__))
modules_path = os.path.dirname(test_path)
sys.path.insert(0, test_path)
sys.path.insert(0, modules_path)

import mock_tables.dbconnector
import show.main as show

# Expected output for 'show breakout current-mode'
current_mode_all_output = ''+ \
"""+-------------+-------------------------+
| Interface | Current Breakout Mode |
+=============+=========================+
| Ethernet0 | 4x25G[10G] |
+-------------+-------------------------+
| Ethernet4 | 2x50G |
+-------------+-------------------------+
| Ethernet8 | 1x100G[40G] |
+-------------+-------------------------+
"""

# Expected output for 'show breakout current-mode Ethernet0'
current_mode_intf_output = ''+ \
"""+-------------+-------------------------+
| Interface | Current Breakout Mode |
+=============+=========================+
| Ethernet0 | 4x25G[10G] |
+-------------+-------------------------+
"""

class TestBreakout(TestCase):
@classmethod
def setup_class(cls):
print("SETUP")
os.environ["UTILITIES_UNIT_TESTING"] = "1"

def setUp(self):
self.runner = CliRunner()
self.config_db = ConfigDBConnector()
self.config_db.connect()
self.obj = {'db': self.config_db}

# Test 'show interfaces breakout current-mode'
def test_all_intf_current_mode(self):
result = self.runner.invoke(show.cli.commands["interfaces"].commands["breakout"].commands["current-mode"], [], obj=self.obj)
print(sys.stderr, result.output)
assert result.output == current_mode_all_output

# Test 'show interfaces breakout current-mode Ethernet0'
def test_single_intf_current_mode(self):
result = self.runner.invoke(show.cli.commands["interfaces"].commands["breakout"].commands["current-mode"], ["Ethernet0"], obj=self.obj)
print(sys.stderr, result.output)
assert result.output == current_mode_intf_output

@classmethod
def teardown_class(cls):
print("TEARDOWN")
os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1])
os.environ["UTILITIES_UNIT_TESTING"] = "0"

0 comments on commit 90efd62

Please sign in to comment.