Skip to content

Commit e4367d6

Browse files
Merge branch 'sonic-net:master' into agg-voq-changes
2 parents f47c614 + d86b2b6 commit e4367d6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+6003
-1327
lines changed

clear/main.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,21 +79,21 @@ def get_command(self, ctx, cmd_name):
7979
# location (configdb?), so that we prevent the continous execution of this
8080
# bash oneliner. To be revisited once routing-stack info is tracked somewhere.
8181
def get_routing_stack():
82-
cmd0 = ["sudo", "docker", "ps"]
83-
cmd1 = ["grep", "bgp"]
84-
cmd2 = ["awk", '{print$2}']
85-
cmd3 = ["cut", "-d-", "-f3"]
86-
cmd4 = ["cut", "-d:", "-f1"]
82+
result = 'frr'
83+
84+
cmd0 = ["sudo", "docker", "ps", "--format", "{{.Image}}\t{{.Names}}"]
85+
cmd1 = ["awk", '$2 ~ /^bgp([0-9]+)?$/']
86+
cmd2 = ["cut", "-d-", "-f3"]
87+
cmd3 = ["cut", "-d:", "-f1"]
88+
cmd4 = ["head", "-n", "1"]
8789

8890
try:
8991
_, result = getstatusoutput_noshell_pipe(cmd0, cmd1, cmd2, cmd3, cmd4)
90-
9192
except OSError as e:
9293
raise OSError("Cannot detect routing-stack")
9394

9495
return (result)
9596

96-
9797
# Global Routing-Stack variable
9898
routing_stack = get_routing_stack()
9999

config/chassis_modules.py

Lines changed: 101 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,27 @@
66
import subprocess
77
import utilities_common.cli as clicommon
88
from utilities_common.chassis import is_smartswitch, get_all_dpus
9+
from datetime import datetime, timedelta
910

1011
TIMEOUT_SECS = 10
12+
TRANSITION_TIMEOUT = timedelta(seconds=240) # 4 minutes
1113

1214

15+
class StateDBHelper:
16+
def __init__(self, sonic_db):
17+
self.db = sonic_db
18+
19+
def get_entry(self, table, key):
20+
"""Fetch all fields from table|key."""
21+
redis_key = f"{table}|{key}"
22+
return self.db.get_all("STATE_DB", redis_key) or {}
23+
24+
def set_entry(self, table, key, entry):
25+
"""Set multiple fields to table|key."""
26+
redis_key = f"{table}|{key}"
27+
for field, value in entry.items():
28+
self.db.set("STATE_DB", redis_key, field, value)
29+
1330
#
1431
# 'chassis_modules' group ('config chassis_modules ...')
1532
#
@@ -24,6 +41,12 @@ def modules():
2441
pass
2542

2643

44+
def ensure_statedb_connected(db):
45+
if not hasattr(db, 'statedb'):
46+
chassisdb = db.db
47+
chassisdb.connect("STATE_DB")
48+
db.statedb = StateDBHelper(chassisdb)
49+
2750
def get_config_module_state(db, chassis_module_name):
2851
config_db = db.cfgdb
2952
fvs = config_db.get_entry('CHASSIS_MODULE', chassis_module_name)
@@ -36,6 +59,41 @@ def get_config_module_state(db, chassis_module_name):
3659
return fvs['admin_status']
3760

3861

62+
def get_state_transition_in_progress(db, chassis_module_name):
63+
ensure_statedb_connected(db)
64+
fvs = db.statedb.get_entry('CHASSIS_MODULE_TABLE', chassis_module_name)
65+
value = fvs.get('state_transition_in_progress', 'False') if fvs else 'False'
66+
return value
67+
68+
69+
def set_state_transition_in_progress(db, chassis_module_name, value):
70+
ensure_statedb_connected(db)
71+
state_db = db.statedb
72+
entry = state_db.get_entry('CHASSIS_MODULE_TABLE', chassis_module_name) or {}
73+
entry['state_transition_in_progress'] = value
74+
if value == 'True':
75+
entry['transition_start_time'] = datetime.utcnow().isoformat()
76+
else:
77+
entry.pop('transition_start_time', None)
78+
state_db.delete_field('CHASSIS_MODULE_TABLE', chassis_module_name, 'transition_start_time')
79+
state_db.set_entry('CHASSIS_MODULE_TABLE', chassis_module_name, entry)
80+
81+
82+
def is_transition_timed_out(db, chassis_module_name):
83+
ensure_statedb_connected(db)
84+
state_db = db.statedb
85+
fvs = state_db.get_entry('CHASSIS_MODULE_TABLE', chassis_module_name)
86+
if not fvs:
87+
return False
88+
start_time_str = fvs.get('transition_start_time')
89+
if not start_time_str:
90+
return False
91+
try:
92+
start_time = datetime.fromisoformat(start_time_str)
93+
except ValueError:
94+
return False
95+
return datetime.utcnow() - start_time > TRANSITION_TIMEOUT
96+
3997
#
4098
# Name: check_config_module_state_with_timeout
4199
# return: True: timeout, False: not timeout
@@ -116,20 +174,33 @@ def shutdown_chassis_module(db, chassis_module_name):
116174
config_db = db.cfgdb
117175
ctx = click.get_current_context()
118176

119-
if not chassis_module_name.startswith("SUPERVISOR") and \
120-
not chassis_module_name.startswith("LINE-CARD") and \
121-
not chassis_module_name.startswith("FABRIC-CARD") and \
122-
not chassis_module_name.startswith("DPU"):
123-
ctx.fail("'module_name' has to begin with 'SUPERVISOR', 'LINE-CARD', 'FABRIC-CARD', 'DPU'")
177+
if not chassis_module_name.startswith(("SUPERVISOR", "LINE-CARD", "FABRIC-CARD", "DPU")):
178+
ctx.fail("'module_name' has to begin with 'SUPERVISOR', 'LINE-CARD', 'FABRIC-CARD', or 'DPU'")
124179

125-
# To avoid duplicate operation
126180
if get_config_module_state(db, chassis_module_name) == 'down':
127-
click.echo("Module {} is already in down state".format(chassis_module_name))
181+
click.echo(f"Module {chassis_module_name} is already in down state")
128182
return
129183

130-
click.echo("Shutting down chassis module {}".format(chassis_module_name))
131-
fvs = {'admin_status': 'down'}
132-
config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs)
184+
if is_smartswitch():
185+
if get_state_transition_in_progress(db, chassis_module_name) == 'True':
186+
if is_transition_timed_out(db, chassis_module_name):
187+
set_state_transition_in_progress(db, chassis_module_name, 'False')
188+
click.echo(f"Previous transition for module {chassis_module_name} timed out. Proceeding with shutdown.")
189+
else:
190+
click.echo(f"Module {chassis_module_name} state transition is already in progress")
191+
return
192+
else:
193+
set_state_transition_in_progress(db, chassis_module_name, 'True')
194+
195+
click.echo(f"Shutting down chassis module {chassis_module_name}")
196+
fvs = {
197+
'admin_status': 'down',
198+
}
199+
config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs)
200+
else:
201+
click.echo(f"Shutting down chassis module {chassis_module_name}")
202+
config_db.set_entry('CHASSIS_MODULE', chassis_module_name, {'admin_status': 'down'})
203+
133204
if chassis_module_name.startswith("FABRIC-CARD"):
134205
if not check_config_module_state_with_timeout(ctx, db, chassis_module_name, 'down'):
135206
fabric_module_set_admin_status(db, chassis_module_name, 'down')
@@ -149,16 +220,32 @@ def startup_chassis_module(db, chassis_module_name):
149220
config_db = db.cfgdb
150221
ctx = click.get_current_context()
151222

152-
# To avoid duplicate operation
223+
if not chassis_module_name.startswith(("SUPERVISOR", "LINE-CARD", "FABRIC-CARD", "DPU")):
224+
ctx.fail("'module_name' has to begin with 'SUPERVISOR', 'LINE-CARD', 'FABRIC-CARD', or 'DPU'")
225+
return
226+
153227
if get_config_module_state(db, chassis_module_name) == 'up':
154-
click.echo("Module {} is already set to up state".format(chassis_module_name))
228+
click.echo(f"Module {chassis_module_name} is already set to up state")
155229
return
156230

157-
click.echo("Starting up chassis module {}".format(chassis_module_name))
158231
if is_smartswitch():
159-
fvs = {'admin_status': 'up'}
232+
if get_state_transition_in_progress(db, chassis_module_name) == 'True':
233+
if is_transition_timed_out(db, chassis_module_name):
234+
set_state_transition_in_progress(db, chassis_module_name, 'False')
235+
click.echo(f"Previous transition for module {chassis_module_name} timed out. Proceeding with startup.")
236+
else:
237+
click.echo(f"Module {chassis_module_name} state transition is already in progress")
238+
return
239+
else:
240+
set_state_transition_in_progress(db, chassis_module_name, 'True')
241+
242+
click.echo(f"Starting up chassis module {chassis_module_name}")
243+
fvs = {
244+
'admin_status': 'up',
245+
}
160246
config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs)
161247
else:
248+
click.echo(f"Starting up chassis module {chassis_module_name}")
162249
config_db.set_entry('CHASSIS_MODULE', chassis_module_name, None)
163250

164251
if chassis_module_name.startswith("FABRIC-CARD"):

config/muxcable.py

Lines changed: 5 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -277,52 +277,14 @@ def lookup_statedb_and_update_configdb(db, per_npu_statedb, config_db, port, sta
277277
port_status_dict[port_name] = 'OK'
278278

279279
def update_configdb_pck_loss_data(config_db, port, val):
280-
fvs = {}
281280
configdb_state = get_value_for_key_in_config_tbl(config_db, port, "state", "MUX_CABLE")
282-
fvs["state"] = configdb_state
283281
ipv4_value = get_value_for_key_in_config_tbl(config_db, port, "server_ipv4", "MUX_CABLE")
284-
fvs["server_ipv4"] = ipv4_value
285282
ipv6_value = get_value_for_key_in_config_tbl(config_db, port, "server_ipv6", "MUX_CABLE")
286-
fvs["server_ipv6"] = ipv6_value
287-
soc_ipv4_value = get_optional_value_for_key_in_config_tbl(config_db, port, "soc_ipv4", "MUX_CABLE")
288-
if soc_ipv4_value is not None:
289-
fvs["soc_ipv4"] = soc_ipv4_value
290-
cable_type = get_optional_value_for_key_in_config_tbl(config_db, port, "cable_type", "MUX_CABLE")
291-
if cable_type is not None:
292-
fvs["cable_type"] = cable_type
293-
prober_type_val = get_optional_value_for_key_in_config_tbl(config_db, port, "prober_type", "MUX_CABLE")
294-
if prober_type_val is not None:
295-
fvs["prober_type"] = prober_type_val
296283

297-
fvs["pck_loss_data_reset"] = val
298284
try:
299-
config_db.set_entry("MUX_CABLE", port, fvs)
300-
except ValueError as e:
301-
ctx = click.get_current_context()
302-
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
303-
304-
305-
def update_configdb_prober_type(config_db, port, val):
306-
fvs = {}
307-
configdb_state = get_value_for_key_in_config_tbl(config_db, port, "state", "MUX_CABLE")
308-
fvs["state"] = configdb_state
309-
ipv4_value = get_value_for_key_in_config_tbl(config_db, port, "server_ipv4", "MUX_CABLE")
310-
fvs["server_ipv4"] = ipv4_value
311-
ipv6_value = get_value_for_key_in_config_tbl(config_db, port, "server_ipv6", "MUX_CABLE")
312-
fvs["server_ipv6"] = ipv6_value
313-
soc_ipv4_value = get_optional_value_for_key_in_config_tbl(config_db, port, "soc_ipv4", "MUX_CABLE")
314-
if soc_ipv4_value is not None:
315-
fvs["soc_ipv4"] = soc_ipv4_value
316-
cable_type = get_optional_value_for_key_in_config_tbl(config_db, port, "cable_type", "MUX_CABLE")
317-
if cable_type is not None:
318-
fvs["cable_type"] = cable_type
319-
pck_loss_data = get_optional_value_for_key_in_config_tbl(config_db, port, "pck_loss_data_reset", "MUX_CABLE")
320-
if pck_loss_data is not None:
321-
fvs["pck_loss_data_reset"] = pck_loss_data
322-
323-
fvs["prober_type"] = val
324-
try:
325-
config_db.set_entry("MUX_CABLE", port, fvs)
285+
config_db.set_entry("MUX_CABLE", port, {"state": configdb_state,
286+
"server_ipv4": ipv4_value, "server_ipv6": ipv6_value,
287+
"pck_loss_data_reset": val})
326288
except ValueError as e:
327289
ctx = click.get_current_context()
328290
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
@@ -419,73 +381,6 @@ def mode(db, state, port, json_output):
419381
sys.exit(CONFIG_SUCCESSFUL)
420382

421383

422-
# 'muxcable' command ("config muxcable probertype hardware/software <port|all>")
423-
@muxcable.command()
424-
@click.argument('probertype', metavar='<operation_status>', required=True, type=click.Choice(["hardware", "software"]))
425-
@click.argument('port', metavar='<port_name>', required=True, default=None)
426-
@clicommon.pass_db
427-
def probertype(db, probertype, port):
428-
"""Config muxcable probertype"""
429-
430-
port = platform_sfputil_helper.get_interface_name(port, db)
431-
432-
port_table_keys = {}
433-
y_cable_asic_table_keys = {}
434-
per_npu_configdb = {}
435-
per_npu_statedb = {}
436-
437-
# Getting all front asic namespace and correspding config and state DB connector
438-
439-
namespaces = multi_asic.get_front_end_namespaces()
440-
for namespace in namespaces:
441-
asic_id = multi_asic.get_asic_index_from_namespace(namespace)
442-
# replace these with correct macros
443-
per_npu_configdb[asic_id] = ConfigDBConnector(use_unix_socket_path=True, namespace=namespace)
444-
per_npu_configdb[asic_id].connect()
445-
per_npu_statedb[asic_id] = SonicV2Connector(use_unix_socket_path=True, namespace=namespace)
446-
per_npu_statedb[asic_id].connect(per_npu_statedb[asic_id].STATE_DB)
447-
448-
port_table_keys[asic_id] = per_npu_statedb[asic_id].keys(
449-
per_npu_statedb[asic_id].STATE_DB, 'MUX_CABLE_TABLE|*')
450-
451-
if port is not None and port != "all":
452-
453-
asic_index = None
454-
if platform_sfputil is not None:
455-
asic_index = platform_sfputil.get_asic_id_for_logical_port(port)
456-
if asic_index is None:
457-
# TODO this import is only for unit test purposes, and should be removed once sonic_platform_base
458-
# is fully mocked
459-
import sonic_platform_base.sonic_sfp.sfputilhelper
460-
asic_index = sonic_platform_base.sonic_sfp.sfputilhelper.SfpUtilHelper().get_asic_id_for_logical_port(port)
461-
if asic_index is None:
462-
click.echo("Got invalid asic index for port {}, cant retreive mux status".format(port))
463-
sys.exit(CONFIG_FAIL)
464-
465-
if per_npu_statedb[asic_index] is not None:
466-
y_cable_asic_table_keys = port_table_keys[asic_index]
467-
logical_key = "MUX_CABLE_TABLE|{}".format(port)
468-
if logical_key in y_cable_asic_table_keys:
469-
update_configdb_prober_type(per_npu_configdb[asic_index], port, probertype)
470-
sys.exit(CONFIG_SUCCESSFUL)
471-
else:
472-
click.echo("this is not a valid port {} present on mux_cable".format(port))
473-
sys.exit(CONFIG_FAIL)
474-
else:
475-
click.echo("there is not a valid asic asic-{} table for this asic_index".format(asic_index))
476-
sys.exit(CONFIG_FAIL)
477-
478-
elif port == "all" and port is not None:
479-
480-
for namespace in namespaces:
481-
asic_id = multi_asic.get_asic_index_from_namespace(namespace)
482-
for key in port_table_keys[asic_id]:
483-
logical_port = key.split("|")[1]
484-
update_configdb_prober_type(per_npu_configdb[asic_id], logical_port, probertype)
485-
486-
sys.exit(CONFIG_SUCCESSFUL)
487-
488-
489384
# 'muxcable' command ("config muxcable kill-radv <enable|disable> ")
490385
@muxcable.command(short_help="Kill radv service when it is meant to be stopped, so no good-bye packet is sent for ceasing To Be an Advertising Interface")
491386
@click.argument('knob', metavar='<feature_knob>', required=True, type=click.Choice(["enable", "disable"]))
@@ -501,7 +396,8 @@ def kill_radv(db, knob):
501396
mux_lmgrd_cfg_tbl = config_db.get_table("MUX_LINKMGR")
502397
config_db.mod_entry("MUX_LINKMGR", "SERVICE_MGMT", {"kill_radv": "True" if knob == "enable" else "False"})
503398

504-
# 'muxcable' command ("config muxcable packetloss reset <port|all>")
399+
400+
#'muxcable' command ("config muxcable packetloss reset <port|all>")
505401
@muxcable.command()
506402
@click.argument('action', metavar='<action_name>', required=True, type=click.Choice(["reset"]))
507403
@click.argument('port', metavar='<port_name>', required=True, default=None)

0 commit comments

Comments
 (0)