Skip to content

Commit

Permalink
[MPLS][CLI] added config/show CLI for MPLS interface, MPLS CRM thresh…
Browse files Browse the repository at this point in the history
…old config, updated CLI reference manual

SONiC CLI support for MPLS:

"config interface mpls (add | remove) <if-name>"
"show interface mpls [<if-name>]"
CRM threshold configuration for mpls_inseg and mpls_nexthop
Updated SONiC CLI command reference manual.
Added unit tests for all CLI commands
  • Loading branch information
qbdwlr authored Jul 13, 2021
1 parent e8b6c5c commit 3f0b690
Show file tree
Hide file tree
Showing 13 changed files with 570 additions and 12 deletions.
50 changes: 50 additions & 0 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3949,6 +3949,56 @@ def reset(ctx, interface_name):
cmd = "sudo sfputil reset {}".format(interface_name)
clicommon.run_command(cmd)

#
# 'mpls' subgroup ('config interface mpls ...')
#

@interface.group(cls=clicommon.AbbreviationGroup)
@click.pass_context
def mpls(ctx):
"""Add or remove MPLS"""
pass

#
# 'add' subcommand
#

@mpls.command()
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.pass_context
def add(ctx, interface_name):
"""Add MPLS operation on the interface"""
config_db = ctx.obj["config_db"]
if clicommon.get_interface_naming_mode() == "alias":
interface_name = interface_alias_to_name(config_db, interface_name)
if interface_name is None:
ctx.fail("'interface_name' is None!")

table_name = get_interface_table_name(interface_name)
if table_name == "":
ctx.fail("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan]")
config_db.set_entry(table_name, interface_name, {"mpls": "enable"})

#
# 'del' subcommand
#

@mpls.command()
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.pass_context
def remove(ctx, interface_name):
"""Remove MPLS operation from the interface"""
config_db = ctx.obj["config_db"]
if clicommon.get_interface_naming_mode() == "alias":
interface_name = interface_alias_to_name(config_db, interface_name)
if interface_name is None:
ctx.fail("'interface_name' is None!")

table_name = get_interface_table_name(interface_name)
if table_name == "":
ctx.fail("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan]")
config_db.set_entry(table_name, interface_name, {"mpls": "disable"})

#
# 'vrf' subgroup ('config interface vrf ...')
#
Expand Down
45 changes: 40 additions & 5 deletions crm/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ def show_thresholds(self, resource):
if resource == 'all':
for res in ["ipv4_route", "ipv6_route", "ipv4_nexthop", "ipv6_nexthop", "ipv4_neighbor", "ipv6_neighbor",
"nexthop_group_member", "nexthop_group", "acl_table", "acl_group", "acl_entry",
"acl_counter", "fdb_entry", "ipmc_entry", "snat_entry", "dnat_entry"]:
"acl_counter", "fdb_entry", "ipmc_entry", "snat_entry", "dnat_entry", "mpls_inseg",
"mpls_nexthop"]:
try:
data.append([res, crm_info[res + "_threshold_type"], crm_info[res + "_low_threshold"], crm_info[res + "_high_threshold"]])
except KeyError:
Expand All @@ -97,7 +98,8 @@ def get_resources(self, resource):
if crm_stats:
if resource == 'all':
for res in ["ipv4_route", "ipv6_route", "ipv4_nexthop", "ipv6_nexthop", "ipv4_neighbor", "ipv6_neighbor",
"nexthop_group_member", "nexthop_group", "fdb_entry", "ipmc_entry", "snat_entry", "dnat_entry"]:
"nexthop_group_member", "nexthop_group", "fdb_entry", "ipmc_entry", "snat_entry", "dnat_entry",
"mpls_inseg", "mpls_nexthop"]:
if 'crm_stats_' + res + "_used" in crm_stats.keys() and 'crm_stats_' + res + "_available" in crm_stats.keys():
data.append([res, crm_stats['crm_stats_' + res + "_used"], crm_stats['crm_stats_' + res + "_available"]])
else:
Expand Down Expand Up @@ -262,6 +264,18 @@ def ipv6(ctx):
"""CRM resource IPv6 address-family"""
ctx.obj["crm"].addr_family = 'ipv6'

@thresholds.group()
@click.pass_context
def mpls(ctx):
"""CRM resource MPLS address-family"""
ctx.obj["crm"].addr_family = 'mpls'

@mpls.group()
@click.pass_context
def inseg(ctx):
"""CRM configuration for in-segment resource"""
ctx.obj["crm"].res_type = 'inseg'

@ipv4.group()
@click.pass_context
def route(ctx):
Expand All @@ -284,7 +298,7 @@ def nexthop(ctx):
@click.argument('value', type=click.Choice(['percentage', 'used', 'free']))
@click.pass_context
def type(ctx, value):
"""CRM threshod type configuration"""
"""CRM threshold type configuration"""
attr = ''

if ctx.obj["crm"].addr_family != None:
Expand All @@ -298,7 +312,7 @@ def type(ctx, value):
@click.argument('value', type=click.INT)
@click.pass_context
def low(ctx, value):
"""CRM low threshod configuration"""
"""CRM low threshold configuration"""
attr = ''

if ctx.obj["crm"].addr_family != None:
Expand All @@ -312,7 +326,7 @@ def low(ctx, value):
@click.argument('value', type=click.INT)
@click.pass_context
def high(ctx, value):
"""CRM high threshod configuration"""
"""CRM high threshold configuration"""
attr = ''

if ctx.obj["crm"].addr_family != None:
Expand All @@ -328,9 +342,13 @@ def high(ctx, value):
nexthop.add_command(type)
nexthop.add_command(low)
nexthop.add_command(high)
inseg.add_command(type)
inseg.add_command(low)
inseg.add_command(high)
ipv6.add_command(route)
ipv6.add_command(neighbor)
ipv6.add_command(nexthop)
mpls.add_command(nexthop)

@thresholds.group()
@click.pass_context
Expand Down Expand Up @@ -493,6 +511,21 @@ def ipv6(ctx):
"""CRM resource IPv6 address family"""
ctx.obj["crm"].addr_family = 'ipv6'

@resources.group()
@click.pass_context
def mpls(ctx):
"""CRM resource MPLS address family"""
ctx.obj["crm"].addr_family = 'mpls'

@mpls.command()
@click.pass_context
def inseg(ctx):
"""Show CRM information for in-segment resource"""
if ctx.obj["crm"].cli_mode == 'thresholds':
ctx.obj["crm"].show_thresholds('{0}_inseg'.format(ctx.obj["crm"].addr_family))
elif ctx.obj["crm"].cli_mode == 'resources':
ctx.obj["crm"].show_resources('{0}_inseg'.format(ctx.obj["crm"].addr_family))

@ipv4.command()
@click.pass_context
def route(ctx):
Expand Down Expand Up @@ -523,6 +556,7 @@ def nexthop(ctx):
ipv6.add_command(route)
ipv6.add_command(neighbor)
ipv6.add_command(nexthop)
mpls.add_command(nexthop)

@resources.group()
@click.pass_context
Expand Down Expand Up @@ -619,6 +653,7 @@ def dnat(ctx):
thresholds.add_command(fdb)
thresholds.add_command(ipv4)
thresholds.add_command(ipv6)
thresholds.add_command(mpls)
thresholds.add_command(nexthop)
thresholds.add_command(ipmc)
thresholds.add_command(snat)
Expand Down
77 changes: 77 additions & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -3095,6 +3095,7 @@ Subsequent pages explain each of these commands in detail.
breakout Show Breakout Mode information by interfaces
counters Show interface counters
description Show interface status, protocol and...
mpls Show Interface MPLS status
naming_mode Show interface naming_mode status
neighbor Show neighbor related information
portchannel Show PortChannel information
Expand Down Expand Up @@ -3334,6 +3335,36 @@ This command displays the key fields of the interfaces such as Operational Statu
Ethernet4 down up hundredGigE1/2 T0-2:hundredGigE1/30
```

**show interfaces mpls**

This command is used to display the configured MPLS state for the list of configured interfaces.

- Usage:
```
show interfaces mpls [<interface_name>]
```

- Example:
```
admin@sonic:~$ show interfaces mpls
Interface MPLS State
----------- ------------
Ethernet0 disable
Ethernet4 enable
Ethernet8 enable
Ethernet12 disable
Ethernet16 disable
Ethernet20 disable
```

- Example (to only display the MPLS state for interface Ethernet4):
```
admin@sonic:~$ show interfaces mpls Ethernet4
Interface MPLS State
----------- ------------
Ethernet4 enable
```

**show interfaces tpid**

This command displays the key fields of the interfaces such as Operational Status, Administrative Status, Alias and TPID.
Expand Down Expand Up @@ -3479,6 +3510,7 @@ This sub-section explains the following list of configuration on the interfaces.
8) advertised-speeds - to set interface advertised speeds
9) advertised-types - to set interface advertised types
10) type - to set interface type
11) mpls - To add or remove MPLS operation for the interface

From 201904 release onwards, the “config interface” command syntax is changed and the format is as follows:

Expand Down Expand Up @@ -3951,6 +3983,51 @@ For details please refer [dynamic buffer management](#dynamic-buffer-management)

Go Back To [Beginning of the document](#) or [Beginning of this section](#interfaces)

**config interface mpls add <interface_name> (Versions >= 202106)**

This command is used for adding MPLS operation on the interface.
MPLS operation for either physical, portchannel, or VLAN interface can be configured using this command.


- Usage:
```
sudo config interface mpls add --help
Usage: config interface mpls add [OPTIONS] <interface_name>
Add MPLS operation on the interface
Options:
-?, -h, --help Show this message and exit.
```

- Example:
```
admin@sonic:~$ sudo config interface mpls add Ethernet4
```

**config interface mpls remove <interface_name> (Versions >= 202106)**

This command is used for removing MPLS operation on the interface.
MPLS operation for either physical, portchannel, or VLAN interface can be configured using this command.

- Usage:
```
sudo config interface mpls remove --help
Usage: config interface mpls remove [OPTIONS] <interface_name>
Remove MPLS operation from the interface
Options:
-?, -h, --help Show this message and exit.
```

- Example:
```
admin@sonic:~$ sudo config interface mpls remove Ethernet4
```

Go Back To [Beginning of the document](#) or [Beginning of this section](#interfaces)

## Interface Naming Mode

### Interface naming mode show commands
Expand Down
46 changes: 45 additions & 1 deletion show/interfaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from tabulate import tabulate
from sonic_py_common import multi_asic
from sonic_py_common import device_info
from swsscommon.swsscommon import ConfigDBConnector
from swsscommon.swsscommon import ConfigDBConnector, SonicV2Connector
from portconfig import get_child_ports
import sonic_platform_base.sonic_sfp.sfputilhelper

Expand Down Expand Up @@ -321,6 +321,50 @@ def expected(db, interfacename):

click.echo(tabulate(body, header))

# 'mpls' subcommand ("show interfaces mpls")
@interfaces.command()
@click.argument('interfacename', required=False)
@click.pass_context
def mpls(ctx, interfacename):
"""Show Interface MPLS status"""

appl_db = SonicV2Connector()
appl_db.connect(appl_db.APPL_DB)

if interfacename is not None:
interfacename = try_convert_interfacename_from_alias(ctx, interfacename)

# Fetching data from appl_db for intfs
keys = appl_db.keys(appl_db.APPL_DB, "INTF_TABLE:*")
intfs_data = {}
for key in keys if keys else []:
tokens = key.split(":")
# Skip INTF_TABLE entries with address information
if len(tokens) != 2:
continue

if (interfacename is not None) and (interfacename != tokens[1]):
continue

mpls = appl_db.get(appl_db.APPL_DB, key, 'mpls')
if mpls is None or mpls == '':
intfs_data.update({tokens[1]: 'disable'})
else:
intfs_data.update({tokens[1]: mpls})

header = ['Interface', 'MPLS State']
body = []

# Output name and alias for all interfaces
for intf_name in natsorted(list(intfs_data.keys())):
if clicommon.get_interface_naming_mode() == "alias":
alias = clicommon.InterfaceAliasConverter().name_to_alias(intf_name)
body.append([alias, intfs_data[intf_name]])
else:
body.append([intf_name, intfs_data[intf_name]])

click.echo(tabulate(body, header))

interfaces.add_command(portchannel.portchannel)

#
Expand Down
Loading

0 comments on commit 3f0b690

Please sign in to comment.