Skip to content

Commit 8040d7e

Browse files
committed
Merge remote-tracking branch 'origin/master' into dev-banner-feature
2 parents 7a7f9f7 + 317e649 commit 8040d7e

File tree

96 files changed

+4550
-883
lines changed

Some content is hidden

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

96 files changed

+4550
-883
lines changed

README.md

+8-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ A convenient alternative is to let the SONiC build system configure a build envi
5151
5252
2. Build the sonic-utilities Python wheel package inside the Bullseye slave container, and tell the build system to keep the container alive when finished
5353
```
54-
make NOSTRETCH=1 NOBUSTER=1 KEEP_SLAVE_ON=yes target/python-wheels/bullseye/sonic_utilities-1.2-py3-none-any.whl
54+
make -f Makefile.work BLDENV=bookworm KEEP_SLAVE_ON=yes target/python-wheels/bookworm/sonic_utilities-1.2-py3-none-any.whl
5555
```
5656
5757
3. When the build finishes, your prompt will change to indicate you are inside the slave container. Change into the `src/sonic-utilities/` directory
@@ -66,13 +66,20 @@ A convenient alternative is to let the SONiC build system configure a build envi
6666
```
6767
python3 setup.py bdist_wheel
6868
```
69+
Note: This command by default will not update the wheel package in target/. To specify the destination location of wheel package, use "-d" option.
6970
7071
#### To run unit tests
7172
7273
```
7374
python3 setup.py test
7475
```
7576
77+
#### To install the package on a SONiC machine
78+
```
79+
sudo pip uninstall sonic-utilities
80+
sudo pip install YOUR_WHEEL_PACKAGE
81+
```
82+
Note: Don't use "--force-reinstall".
7683
7784
### sonic-utilities-data
7885

azure-pipelines.yml

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ stages:
2727
displayName: "Static Analysis"
2828
timeoutInMinutes: 10
2929
continueOnError: true
30-
pool: ubuntu-20.04
30+
pool: sonic-ubuntu-1c
3131
steps:
3232
- template: .azure-pipelines/pre-commit-check.yml
3333

@@ -46,6 +46,13 @@ stages:
4646
image: sonicdev-microsoft.azurecr.io:443/sonic-slave-bullseye:$(BUILD_BRANCH)
4747

4848
steps:
49+
- script: |
50+
set -ex
51+
sudo apt-get update
52+
sudo apt-get install -y python3-pip
53+
sudo pip3 install requests==2.31.0
54+
displayName: "Install dependencies"
55+
4956
- script: |
5057
sourceBranch=$(Build.SourceBranchName)
5158
if [[ "$(Build.Reason)" == "PullRequest" ]];then

config/bgp_cli.py

+192
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import click
2+
import utilities_common.cli as clicommon
3+
4+
from sonic_py_common import logger
5+
from utilities_common.bgp import (
6+
CFG_BGP_DEVICE_GLOBAL,
7+
BGP_DEVICE_GLOBAL_KEY,
8+
SYSLOG_IDENTIFIER,
9+
to_str,
10+
)
11+
12+
13+
log = logger.Logger(SYSLOG_IDENTIFIER)
14+
log.set_min_log_priority_info()
15+
16+
17+
#
18+
# BGP DB interface ----------------------------------------------------------------------------------------------------
19+
#
20+
21+
22+
def update_entry_validated(db, table, key, data, create_if_not_exists=False):
23+
""" Update entry in table and validate configuration.
24+
If attribute value in data is None, the attribute is deleted.
25+
26+
Args:
27+
db (swsscommon.ConfigDBConnector): Config DB connector object.
28+
table (str): Table name to add new entry to.
29+
key (Union[str, Tuple]): Key name in the table.
30+
data (Dict): Entry data.
31+
create_if_not_exists (bool):
32+
In case entry does not exists already a new entry
33+
is not created if this flag is set to False and
34+
creates a new entry if flag is set to True.
35+
Raises:
36+
Exception: when cfg does not satisfy YANG schema.
37+
"""
38+
39+
cfg = db.get_config()
40+
cfg.setdefault(table, {})
41+
42+
if not data:
43+
raise click.ClickException(f"No field/values to update {key}")
44+
45+
if create_if_not_exists:
46+
cfg[table].setdefault(key, {})
47+
48+
if key not in cfg[table]:
49+
raise click.ClickException(f"{key} does not exist")
50+
51+
entry_changed = False
52+
for attr, value in data.items():
53+
if value == cfg[table][key].get(attr):
54+
continue
55+
entry_changed = True
56+
if value is None:
57+
cfg[table][key].pop(attr, None)
58+
else:
59+
cfg[table][key][attr] = value
60+
61+
if not entry_changed:
62+
return
63+
64+
db.set_entry(table, key, cfg[table][key])
65+
66+
67+
#
68+
# BGP handlers --------------------------------------------------------------------------------------------------------
69+
#
70+
71+
72+
def tsa_handler(ctx, db, state):
73+
""" Handle config updates for Traffic-Shift-Away (TSA) feature """
74+
75+
table = CFG_BGP_DEVICE_GLOBAL
76+
key = BGP_DEVICE_GLOBAL_KEY
77+
data = {
78+
"tsa_enabled": state,
79+
}
80+
81+
try:
82+
update_entry_validated(db.cfgdb, table, key, data, create_if_not_exists=True)
83+
log.log_notice("Configured TSA state: {}".format(to_str(state)))
84+
except Exception as e:
85+
log.log_error("Failed to configure TSA state: {}".format(str(e)))
86+
ctx.fail(str(e))
87+
88+
89+
def wcmp_handler(ctx, db, state):
90+
""" Handle config updates for Weighted-Cost Multi-Path (W-ECMP) feature """
91+
92+
table = CFG_BGP_DEVICE_GLOBAL
93+
key = BGP_DEVICE_GLOBAL_KEY
94+
data = {
95+
"wcmp_enabled": state,
96+
}
97+
98+
try:
99+
update_entry_validated(db.cfgdb, table, key, data, create_if_not_exists=True)
100+
log.log_notice("Configured W-ECMP state: {}".format(to_str(state)))
101+
except Exception as e:
102+
log.log_error("Failed to configure W-ECMP state: {}".format(str(e)))
103+
ctx.fail(str(e))
104+
105+
106+
#
107+
# BGP device-global ---------------------------------------------------------------------------------------------------
108+
#
109+
110+
111+
@click.group(
112+
name="device-global",
113+
cls=clicommon.AliasedGroup
114+
)
115+
def DEVICE_GLOBAL():
116+
""" Configure BGP device global state """
117+
118+
pass
119+
120+
121+
#
122+
# BGP device-global tsa -----------------------------------------------------------------------------------------------
123+
#
124+
125+
126+
@DEVICE_GLOBAL.group(
127+
name="tsa",
128+
cls=clicommon.AliasedGroup
129+
)
130+
def DEVICE_GLOBAL_TSA():
131+
""" Configure Traffic-Shift-Away (TSA) feature """
132+
133+
pass
134+
135+
136+
@DEVICE_GLOBAL_TSA.command(
137+
name="enabled"
138+
)
139+
@clicommon.pass_db
140+
@click.pass_context
141+
def DEVICE_GLOBAL_TSA_ENABLED(ctx, db):
142+
""" Enable Traffic-Shift-Away (TSA) feature """
143+
144+
tsa_handler(ctx, db, "true")
145+
146+
147+
@DEVICE_GLOBAL_TSA.command(
148+
name="disabled"
149+
)
150+
@clicommon.pass_db
151+
@click.pass_context
152+
def DEVICE_GLOBAL_TSA_DISABLED(ctx, db):
153+
""" Disable Traffic-Shift-Away (TSA) feature """
154+
155+
tsa_handler(ctx, db, "false")
156+
157+
158+
#
159+
# BGP device-global w-ecmp --------------------------------------------------------------------------------------------
160+
#
161+
162+
163+
@DEVICE_GLOBAL.group(
164+
name="w-ecmp",
165+
cls=clicommon.AliasedGroup
166+
)
167+
def DEVICE_GLOBAL_WCMP():
168+
""" Configure Weighted-Cost Multi-Path (W-ECMP) feature """
169+
170+
pass
171+
172+
173+
@DEVICE_GLOBAL_WCMP.command(
174+
name="enabled"
175+
)
176+
@clicommon.pass_db
177+
@click.pass_context
178+
def DEVICE_GLOBAL_WCMP_ENABLED(ctx, db):
179+
""" Enable Weighted-Cost Multi-Path (W-ECMP) feature """
180+
181+
wcmp_handler(ctx, db, "true")
182+
183+
184+
@DEVICE_GLOBAL_WCMP.command(
185+
name="disabled"
186+
)
187+
@clicommon.pass_db
188+
@click.pass_context
189+
def DEVICE_GLOBAL_WCMP_DISABLED(ctx, db):
190+
""" Disable Weighted-Cost Multi-Path (W-ECMP) feature """
191+
192+
wcmp_handler(ctx, db, "false")

config/chassis_modules.py

100644100755
+100-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
#!/usr/sbin/env python
22

33
import click
4-
4+
import time
5+
import re
6+
import subprocess
57
import utilities_common.cli as clicommon
68

9+
TIMEOUT_SECS = 10
10+
11+
712
#
813
# 'chassis_modules' group ('config chassis_modules ...')
914
#
@@ -17,6 +22,81 @@ def modules():
1722
"""Configure chassis modules"""
1823
pass
1924

25+
26+
def get_config_module_state(db, chassis_module_name):
27+
config_db = db.cfgdb
28+
fvs = config_db.get_entry('CHASSIS_MODULE', chassis_module_name)
29+
if not fvs:
30+
return 'up'
31+
else:
32+
return fvs['admin_status']
33+
34+
35+
#
36+
# Name: check_config_module_state_with_timeout
37+
# return: True: timeout, False: not timeout
38+
#
39+
def check_config_module_state_with_timeout(ctx, db, chassis_module_name, state):
40+
counter = 0
41+
while get_config_module_state(db, chassis_module_name) != state:
42+
time.sleep(1)
43+
counter += 1
44+
if counter >= TIMEOUT_SECS:
45+
ctx.fail("get_config_module_state {} timeout".format(chassis_module_name))
46+
return True
47+
return False
48+
49+
50+
def get_asic_list_from_db(chassisdb, chassis_module_name):
51+
asic_list = []
52+
asics_keys_list = chassisdb.keys("CHASSIS_STATE_DB", "CHASSIS_FABRIC_ASIC_TABLE*")
53+
for asic_key in asics_keys_list:
54+
name = chassisdb.get("CHASSIS_STATE_DB", asic_key, "name")
55+
if name == chassis_module_name:
56+
asic_id = int(re.search(r"(\d+)$", asic_key).group())
57+
asic_list.append(asic_id)
58+
return asic_list
59+
60+
61+
#
62+
# Syntax: fabric_module_set_admin_status <chassis_module_name> <'up'/'down'>
63+
#
64+
def fabric_module_set_admin_status(db, chassis_module_name, state):
65+
chassisdb = db.db
66+
chassisdb.connect("CHASSIS_STATE_DB")
67+
asic_list = get_asic_list_from_db(chassisdb, chassis_module_name)
68+
69+
if len(asic_list) == 0:
70+
return
71+
72+
if state == "down":
73+
for asic in asic_list:
74+
click.echo("Stop swss@{} and peer services".format(asic))
75+
clicommon.run_command('sudo systemctl stop swss@{}.service'.format(asic))
76+
77+
is_active = subprocess.call(["systemctl", "is-active", "--quiet", "swss@{}.service".format(asic)])
78+
79+
if is_active == 0: # zero active, non-zero, inactive
80+
click.echo("Stop swss@{} and peer services failed".format(asic))
81+
return
82+
83+
click.echo("Delete related CAHSSIS_FABRIC_ASIC_TABLE entries")
84+
85+
for asic in asic_list:
86+
chassisdb.delete("CHASSIS_STATE_DB", "CHASSIS_FABRIC_ASIC_TABLE|asic" + str(asic))
87+
88+
# Start the services in case of the users just execute issue command "systemctl stop swss@/syncd@"
89+
# without bring down the hardware
90+
for asic in asic_list:
91+
# To address systemd service restart limit by resetting the count
92+
clicommon.run_command('sudo systemctl reset-failed swss@{}.service'.format(asic))
93+
click.echo("Start swss@{} and peer services".format(asic))
94+
clicommon.run_command('sudo systemctl start swss@{}.service'.format(asic))
95+
elif state == "up":
96+
for asic in asic_list:
97+
click.echo("Start swss@{} and peer services".format(asic))
98+
clicommon.run_command('sudo systemctl start swss@{}.service'.format(asic))
99+
20100
#
21101
# 'shutdown' subcommand ('config chassis_modules shutdown ...')
22102
#
@@ -33,8 +113,17 @@ def shutdown_chassis_module(db, chassis_module_name):
33113
not chassis_module_name.startswith("FABRIC-CARD"):
34114
ctx.fail("'module_name' has to begin with 'SUPERVISOR', 'LINE-CARD' or 'FABRIC-CARD'")
35115

116+
# To avoid duplicate operation
117+
if get_config_module_state(db, chassis_module_name) == 'down':
118+
click.echo("Module {} is already in down state".format(chassis_module_name))
119+
return
120+
121+
click.echo("Shutting down chassis module {}".format(chassis_module_name))
36122
fvs = {'admin_status': 'down'}
37123
config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs)
124+
if chassis_module_name.startswith("FABRIC-CARD"):
125+
if not check_config_module_state_with_timeout(ctx, db, chassis_module_name, 'down'):
126+
fabric_module_set_admin_status(db, chassis_module_name, 'down')
38127

39128
#
40129
# 'startup' subcommand ('config chassis_modules startup ...')
@@ -45,5 +134,15 @@ def shutdown_chassis_module(db, chassis_module_name):
45134
def startup_chassis_module(db, chassis_module_name):
46135
"""Chassis-module startup of module"""
47136
config_db = db.cfgdb
137+
ctx = click.get_current_context()
138+
139+
# To avoid duplicate operation
140+
if get_config_module_state(db, chassis_module_name) == 'up':
141+
click.echo("Module {} is already set to up state".format(chassis_module_name))
142+
return
48143

144+
click.echo("Starting up chassis module {}".format(chassis_module_name))
49145
config_db.set_entry('CHASSIS_MODULE', chassis_module_name, None)
146+
if chassis_module_name.startswith("FABRIC-CARD"):
147+
if not check_config_module_state_with_timeout(ctx, db, chassis_module_name, 'up'):
148+
fabric_module_set_admin_status(db, chassis_module_name, 'up')

0 commit comments

Comments
 (0)