Skip to content

Commit 9df5b8a

Browse files
committed
[Fast-linkup] Added CLIs for config/show
Signed-off-by: Yair Raviv <[email protected]>
1 parent 1ae65e3 commit 9df5b8a

File tree

10 files changed

+545
-1
lines changed

10 files changed

+545
-1
lines changed

config/main.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4905,6 +4905,119 @@ def interface(ctx, namespace):
49054905
config_db = ConfigDBConnector(use_unix_socket_path=True, namespace=str(namespace))
49064906
config_db.connect()
49074907
ctx.obj = {'config_db': config_db, 'namespace': str(namespace)}
4908+
4909+
4910+
@config.group(cls=clicommon.AliasedGroup, name='switch-fast-linkup', context_settings=CONTEXT_SETTINGS)
4911+
@click.pass_context
4912+
def switch_fast_linkup_group(ctx):
4913+
"""Configure fast link-up global configuration parameters"""
4914+
pass
4915+
4916+
4917+
# 'global' subcommand
4918+
@switch_fast_linkup_group.command(name='global')
4919+
@click.option('--polling-time', type=int, required=False, help='Polling time (sec)')
4920+
@click.option('--guard-time', type=int, required=False, help='Guard time (sec)')
4921+
@click.option('--ber', '--ber-threshold', type=int, required=False, help='BER threshold exponent (e.g., 12 for 1e-12)')
4922+
@clicommon.pass_db
4923+
def switch_fast_linkup_global_cmd(db, polling_time, guard_time, ber):
4924+
"""Configure global fast link-up feature parameters"""
4925+
if polling_time is None and guard_time is None and ber is None:
4926+
raise click.UsageError('Failed to configure fast link-up global: no options are provided')
4927+
# Read capability and ranges from STATE_DB for validation
4928+
state = db.db
4929+
cap_tbl = state.STATE_DB
4930+
entry = state.get_all(cap_tbl, 'SWITCH_CAPABILITY|switch') or {}
4931+
if entry.get('FAST_LINKUP_CAPABLE', 'false') != 'true':
4932+
raise click.ClickException('Fast link-up is not supported on this platform')
4933+
4934+
def _parse_range(s):
4935+
try:
4936+
parts = (s or '').split(',')
4937+
return int(parts[0]), int(parts[1])
4938+
except Exception:
4939+
return None
4940+
poll_range = _parse_range(entry.get('FAST_LINKUP_POLLING_TIMER_RANGE'))
4941+
guard_range = _parse_range(entry.get('FAST_LINKUP_GUARD_TIMER_RANGE'))
4942+
4943+
# Load existing configuration to preserve unspecified values
4944+
existing = db.cfgdb.get_entry('SWITCH_FAST_LINKUP', 'GLOBAL') or {}
4945+
4946+
def to_int(val):
4947+
try:
4948+
return int(val)
4949+
except Exception:
4950+
return None
4951+
4952+
polling_time = polling_time if polling_time is not None else to_int(existing.get('polling_time'))
4953+
guard_time = guard_time if guard_time is not None else to_int(existing.get('guard_time'))
4954+
ber = ber if ber is not None else to_int(existing.get('ber_threshold'))
4955+
4956+
data = {}
4957+
if polling_time is not None:
4958+
if poll_range and not (poll_range[0] <= int(polling_time) <= poll_range[1]):
4959+
raise click.ClickException('polling_time {} out of supported range [{}, {}]'.format(
4960+
polling_time, poll_range[0], poll_range[1]))
4961+
data['polling_time'] = str(polling_time)
4962+
if guard_time is not None:
4963+
if guard_range and not (guard_range[0] <= int(guard_time) <= guard_range[1]):
4964+
raise click.ClickException('guard_time {} out of supported range [{}, {}]'.format(
4965+
guard_time, guard_range[0], guard_range[1]))
4966+
data['guard_time'] = str(guard_time)
4967+
if ber is not None:
4968+
if ber < 1 or ber > 255:
4969+
raise click.ClickException('ber_threshold {} out of supported range [1, 255]'.format(ber))
4970+
data['ber_threshold'] = str(ber)
4971+
try:
4972+
db.cfgdb.set_entry('SWITCH_FAST_LINKUP', 'GLOBAL', data)
4973+
4974+
log.log_notice('Configured fast link-up global: {}'.format(data))
4975+
except Exception as e:
4976+
log.log_error('Failed to configure fast link-up global: {}'.format(str(e)))
4977+
raise SystemExit(1)
4978+
4979+
4980+
# 'fast-linkup' subcommand
4981+
@interface.command('fast-linkup')
4982+
@click.argument('interface_name', metavar='<interface_name>', required=True)
4983+
@click.argument(
4984+
'mode',
4985+
metavar='<enabled|disabled|true|false|on|off>',
4986+
required=True,
4987+
type=click.Choice(['enabled', 'disabled', 'true', 'false', 'on', 'off'])
4988+
)
4989+
@click.option('-v', '--verbose', is_flag=True, help='Enable verbose output')
4990+
@click.pass_context
4991+
def fast_linkup(ctx, interface_name, mode, verbose):
4992+
"""Enable/disable fast link-up on an interface"""
4993+
config_db = ctx.obj['config_db']
4994+
4995+
if clicommon.get_interface_naming_mode() == 'alias':
4996+
interface_name = interface_alias_to_name(config_db, interface_name)
4997+
if interface_name is None:
4998+
ctx.fail("'interface_name' is None!")
4999+
if not interface_name_is_valid(config_db, interface_name):
5000+
ctx.fail('Error: Interface name is invalid. Please enter a valid interface name')
5001+
5002+
# Read capability from STATE_DB for validation
5003+
if ctx.obj['namespace'] is DEFAULT_NAMESPACE:
5004+
state_db = SonicV2Connector(use_unix_socket_path=True)
5005+
else:
5006+
state_db = SonicV2Connector(use_unix_socket_path=True, namespace=ctx.obj['namespace'])
5007+
state_db.connect(state_db.STATE_DB, False)
5008+
fast_linkup_capable = state_db.get(state_db.STATE_DB, 'SWITCH_CAPABILITY|switch', 'FAST_LINKUP_CAPABLE')
5009+
if fast_linkup_capable != 'true':
5010+
raise click.ClickException('Fast link-up is not supported on this platform')
5011+
5012+
log.log_info("'interface fast-linkup {} {}' executing...".format(interface_name, mode))
5013+
if ctx.obj['namespace'] is DEFAULT_NAMESPACE:
5014+
command = ['portconfig', '-p', str(interface_name), '-fl', str(mode)]
5015+
else:
5016+
command = ['portconfig', '-p', str(interface_name), '-fl', str(mode), '-n', str(ctx.obj['namespace'])]
5017+
5018+
if verbose:
5019+
command += ['-vv']
5020+
clicommon.run_command(command, display_cmd=verbose)
49085021
#
49095022
# 'startup' subcommand
49105023
#

doc/Command-Reference.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5323,6 +5323,92 @@ This command is used to manage switch hash algorithm global configuration.
53235323
admin@sonic:~$ config switch-hash global lag-hash-algorithm 'CRC'
53245324
```
53255325

5326+
## Fast Link-Up
5327+
5328+
This section documents the commands to configure and display the Fast Link-Up feature.
5329+
5330+
### Fast Link-Up Show Commands
5331+
5332+
**show switch-fast-linkup global**
5333+
5334+
Display switch Fast Link-Up global configuration.
5335+
5336+
- Usage:
5337+
```bash
5338+
show switch-fast-linkup global [--json]
5339+
```
5340+
5341+
- Examples:
5342+
```bash
5343+
admin@sonic:~$ show switch-fast-linkup global
5344+
Field Value
5345+
------------- -----
5346+
polling_time 60
5347+
guard_time 10
5348+
ber_threshold 12
5349+
```
5350+
5351+
**show interfaces fast-linkup status**
5352+
5353+
Display per-interface Fast Link-Up mode.
5354+
5355+
- Usage:
5356+
```bash
5357+
show interfaces fast-linkup status
5358+
```
5359+
5360+
- Example:
5361+
```bash
5362+
admin@sonic:~$ show interfaces fast-linkup status
5363+
Interface fast_linkup
5364+
----------- -----------
5365+
Ethernet0 true
5366+
Ethernet4 false
5367+
```
5368+
5369+
### Fast Link-Up Config Commands
5370+
5371+
**config switch-fast-linkup global**
5372+
5373+
Configure the switch Fast Link-Up global parameters.
5374+
5375+
- Usage:
5376+
```bash
5377+
config switch-fast-linkup global [--polling-time <sec>] [--guard-time <sec>] [--ber <exp>]
5378+
```
5379+
5380+
- Parameters:
5381+
- _polling-time_: time in seconds to attempt fast link-up (uint16).
5382+
- _guard-time_: time in seconds link must stay up with low BER to keep fast link-up (uint8).
5383+
- _ber_: BER threshold exponent (uint8). Example: 12 means 1e-12.
5384+
5385+
- Validation:
5386+
- Reads `SWITCH_CAPABILITY|switch` from STATE_DB. Fails if `FAST_LINKUP_CAPABLE != true`.
5387+
- If ranges are present, rejects out-of-range `polling_time`/`guard_time`.
5388+
5389+
- Examples:
5390+
```bash
5391+
admin@sonic:~$ config switch-fast-linkup global --polling-time 60 --guard-time 10 --ber 12
5392+
```
5393+
5394+
**config interface fast-linkup**
5395+
5396+
Enable/disable Fast Link-Up per interface.
5397+
5398+
- Usage:
5399+
```bash
5400+
config interface fast-linkup <interface_name> <enabled|disabled>
5401+
```
5402+
5403+
- Behavior:
5404+
- Writes `PORT|<interface_name>:fast_linkup` as `true` (enabled) or `false` (disabled).
5405+
5406+
- Examples:
5407+
```bash
5408+
admin@sonic:~$ config interface fast-linkup Ethernet0 enabled
5409+
admin@sonic:~$ config interface fast-linkup Ethernet4 disabled
5410+
```
5411+
53265412
## Interfaces
53275413

53285414
### Interface Show Commands

scripts/portconfig

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ portconfig is the utility to show and change ECN configuration
66
usage: portconfig [-h] [-v] [-s] [-f] [-m] [-tp] [-p PROFILE] [-gmin GREEN_MIN]
77
[-gmax GREEN_MAX] [-ymin YELLOW_MIN] [-ymax YELLOW_MAX]
88
[-rmin RED_MIN] [-rmax RED_MAX] [-vv] [-n namespace]
9+
[-fl FAST_LINKUP]
910
1011
optional arguments:
1112
-h --help show this help message and exit
@@ -22,6 +23,7 @@ optional arguments:
2223
-t --interface-type port interface type
2324
-T --adv-interface-types port advertised interface types
2425
-lt --link-training port link training mode
26+
-fl --fast-linkup port fast link-up mode (enabled/disabled)
2527
-P --tx-power 400G ZR modulet target Tx output power (dBm)
2628
-F --laser-freq 400G ZR module 75GHz grid frequency (GHz)
2729
"""
@@ -56,6 +58,7 @@ PORT_ADV_SPEEDS_CONFIG_FIELD_NAME = "adv_speeds"
5658
PORT_INTERFACE_TYPE_CONFIG_FIELD_NAME = "interface_type"
5759
PORT_ADV_INTERFACE_TYPES_CONFIG_FIELD_NAME = "adv_interface_types"
5860
PORT_LINK_TRAINING_CONFIG_FIELD_NAME = "link_training"
61+
PORT_FAST_LINKUP_CONFIG_FIELD_NAME = "fast_linkup"
5962
PORT_XCVR_LASER_FREQ_FIELD_NAME = "laser_freq"
6063
PORT_XCVR_TX_POWER_FIELD_NAME = "tx_power"
6164
PORT_CHANNEL_TABLE_NAME = "PORTCHANNEL"
@@ -325,6 +328,24 @@ class portconfig(object):
325328
else:
326329
raise Exception("System not ready to accept TPID config. Please try again later.")
327330

331+
def set_fast_linkup(self, port, mode):
332+
if self.is_lag:
333+
raise Exception("Invalid port %s" % (port))
334+
if self.verbose:
335+
print("Setting fast-linkup %s on port %s" % (mode, port))
336+
337+
# Normalize accepted modes
338+
normalized = str(mode).strip().lower()
339+
if normalized in ['enabled', 'on', 'true']:
340+
value = 'true'
341+
elif normalized in ['disabled', 'off', 'false']:
342+
value = 'false'
343+
else:
344+
print('Invalid fast-linkup mode specified: {}'.format(mode))
345+
print('Valid modes: enabled, disabled')
346+
exit(1)
347+
self.db.mod_entry(PORT_TABLE_NAME, port, {PORT_FAST_LINKUP_CONFIG_FIELD_NAME: value})
348+
328349

329350
def main():
330351
parser = argparse.ArgumentParser(description='Set SONiC port parameters',
@@ -349,6 +370,8 @@ def main():
349370
help = 'port advertised interface types', default=None)
350371
parser.add_argument('-lt', '--link-training', type = str, required = False,
351372
help = 'port link training mode', default=None)
373+
parser.add_argument('-fl', '--fast-linkup', type=str, required=False,
374+
help='port fast link-up mode (enabled|disabled)', default=None)
352375
parser.add_argument('-P', '--tx-power', type=float, required=False,
353376
help='Tx output power(dBm)', default=None)
354377
parser.add_argument('-F', '--laser-freq', type=int, required=False,
@@ -363,7 +386,7 @@ def main():
363386
port.list_params(args.port)
364387
elif args.speed or args.fec or args.mtu or args.link_training or args.autoneg or args.adv_speeds or \
365388
args.interface_type or args.adv_interface_types or args.tpid or \
366-
args.tx_power or args.laser_freq:
389+
args.tx_power or args.laser_freq or args.fast_linkup:
367390
if args.speed:
368391
port.set_speed(args.port, args.speed)
369392
if args.fec:
@@ -374,6 +397,8 @@ def main():
374397
port.set_link_training(args.port, args.link_training)
375398
if args.autoneg:
376399
port.set_autoneg(args.port, args.autoneg)
400+
if args.fast_linkup:
401+
port.set_fast_linkup(args.port, args.fast_linkup)
377402
if args.adv_speeds:
378403
port.set_adv_speeds(args.port, args.adv_speeds)
379404
if args.interface_type:

show/interfaces/__init__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,3 +1214,28 @@ def tablelize(keys):
12141214

12151215
header = ['Interface', 'DHCP Mitigation Rate']
12161216
click.echo(tabulate(tablelize(keys), header, tablefmt="simple", stralign='left'))
1217+
1218+
1219+
#
1220+
# fast-linkup group (show interfaces fast-linkup ...)
1221+
#
1222+
1223+
1224+
@interfaces.group(name='fast-linkup', cls=clicommon.AliasedGroup)
1225+
def fast_linkup():
1226+
"""Show interface fast-linkup information"""
1227+
pass
1228+
1229+
1230+
@fast_linkup.command(name='status')
1231+
@click.pass_context
1232+
def fast_linkup_status(ctx):
1233+
"""show interfaces fast-linkup status"""
1234+
config_db = ConfigDBConnector()
1235+
config_db.connect()
1236+
ports = config_db.get_table('PORT') or {}
1237+
rows = []
1238+
for ifname, entry in natsorted(ports.items()):
1239+
fast_linkup = entry.get('fast_linkup', 'false')
1240+
rows.append([ifname, fast_linkup])
1241+
click.echo(tabulate(rows, headers=['Interface', 'fast_linkup'], tablefmt='outline'))

show/main.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2871,6 +2871,30 @@ def banner(db):
28712871
click.echo(tabulate(messages, headers=hdrs, tablefmt='simple', missingval=''))
28722872

28732873

2874+
#
2875+
# 'switch-fast-linkup' command group ("show switch-fast-linkup ...")
2876+
#
2877+
@cli.group(cls=clicommon.AliasedGroup, name='switch-fast-linkup', context_settings=CONTEXT_SETTINGS)
2878+
@click.pass_context
2879+
def switch_fast_linkup_group(ctx):
2880+
"""Show fast link-up feature configuration (global)"""
2881+
pass
2882+
2883+
2884+
@switch_fast_linkup_group.command(name='global')
2885+
@click.option('--json', 'json_output', is_flag=True, default=False, help='JSON output')
2886+
@click.pass_context
2887+
def show_fast_linkup_global(ctx, json_output):
2888+
db = Db()
2889+
data = db.cfgdb.get_entry('SWITCH_FAST_LINKUP', 'GLOBAL') or {}
2890+
if json_output:
2891+
import json
2892+
click.echo(json.dumps(data, indent=2))
2893+
return
2894+
rows = [[k, v] for k, v in data.items()]
2895+
click.echo(tabulate(rows, headers=['Field', 'Value'], tablefmt='grid'))
2896+
2897+
28742898
# Load plugins and register them
28752899
helper = util_base.UtilHelper()
28762900
helper.load_and_register_plugins(plugins, cli)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"SWITCH_FAST_LINKUP|GLOBAL": {
3+
"polling_time": "60",
4+
"guard_time": "10",
5+
"ber_threshold": "12"
6+
}
7+
}
8+
9+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"PORT|Ethernet0": {
3+
"admin_status": "up",
4+
"fast_linkup": "true"
5+
},
6+
"PORT|Ethernet4": {
7+
"admin_status": "up",
8+
"fast_linkup": "false"
9+
}
10+
}
11+
12+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"SWITCH_CAPABILITY|switch": {
3+
"FAST_LINKUP_CAPABLE": "false"
4+
}
5+
}
6+
7+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"SWITCH_CAPABILITY|switch": {
3+
"FAST_LINKUP_CAPABLE": "true",
4+
"FAST_LINKUP_POLLING_TIMER_RANGE": "5,120",
5+
"FAST_LINKUP_GUARD_TIMER_RANGE": "1,20"
6+
}
7+
}
8+
9+

0 commit comments

Comments
 (0)