Skip to content

Commit

Permalink
Merge branch 'bmpcli_cfg' of https://github.com/FengPan-Frank/sonic-u…
Browse files Browse the repository at this point in the history
…tilities into bmpcli_cfg
  • Loading branch information
FengPan-Frank committed Sep 5, 2024
2 parents 61f1780 + 6f9e926 commit 5dec52d
Show file tree
Hide file tree
Showing 101 changed files with 6,490 additions and 1,863 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ A convenient alternative is to let the SONiC build system configure a build envi

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
```
make NOSTRETCH=1 NOBUSTER=1 KEEP_SLAVE_ON=yes target/python-wheels/bullseye/sonic_utilities-1.2-py3-none-any.whl
make -f Makefile.work BLDENV=bookworm KEEP_SLAVE_ON=yes target/python-wheels/bookworm/sonic_utilities-1.2-py3-none-any.whl
```

3. When the build finishes, your prompt will change to indicate you are inside the slave container. Change into the `src/sonic-utilities/` directory
Expand All @@ -66,13 +66,20 @@ A convenient alternative is to let the SONiC build system configure a build envi
```
python3 setup.py bdist_wheel
```
Note: This command by default will not update the wheel package in target/. To specify the destination location of wheel package, use "-d" option.

#### To run unit tests

```
python3 setup.py test
```

#### To install the package on a SONiC machine
```
sudo pip uninstall sonic-utilities
sudo pip install YOUR_WHEEL_PACKAGE
```
Note: Don't use "--force-reinstall".

### sonic-utilities-data

Expand Down
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ stages:
displayName: "Static Analysis"
timeoutInMinutes: 10
continueOnError: true
pool: ubuntu-20.04
pool: sonic-ubuntu-1c
steps:
- template: .azure-pipelines/pre-commit-check.yml

Expand Down
192 changes: 192 additions & 0 deletions config/bgp_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import click
import utilities_common.cli as clicommon

from sonic_py_common import logger
from utilities_common.bgp import (
CFG_BGP_DEVICE_GLOBAL,
BGP_DEVICE_GLOBAL_KEY,
SYSLOG_IDENTIFIER,
to_str,
)


log = logger.Logger(SYSLOG_IDENTIFIER)
log.set_min_log_priority_info()


#
# BGP DB interface ----------------------------------------------------------------------------------------------------
#


def update_entry_validated(db, table, key, data, create_if_not_exists=False):
""" Update entry in table and validate configuration.
If attribute value in data is None, the attribute is deleted.
Args:
db (swsscommon.ConfigDBConnector): Config DB connector object.
table (str): Table name to add new entry to.
key (Union[str, Tuple]): Key name in the table.
data (Dict): Entry data.
create_if_not_exists (bool):
In case entry does not exists already a new entry
is not created if this flag is set to False and
creates a new entry if flag is set to True.
Raises:
Exception: when cfg does not satisfy YANG schema.
"""

cfg = db.get_config()
cfg.setdefault(table, {})

if not data:
raise click.ClickException(f"No field/values to update {key}")

if create_if_not_exists:
cfg[table].setdefault(key, {})

if key not in cfg[table]:
raise click.ClickException(f"{key} does not exist")

entry_changed = False
for attr, value in data.items():
if value == cfg[table][key].get(attr):
continue
entry_changed = True
if value is None:
cfg[table][key].pop(attr, None)
else:
cfg[table][key][attr] = value

if not entry_changed:
return

db.set_entry(table, key, cfg[table][key])


#
# BGP handlers --------------------------------------------------------------------------------------------------------
#


def tsa_handler(ctx, db, state):
""" Handle config updates for Traffic-Shift-Away (TSA) feature """

table = CFG_BGP_DEVICE_GLOBAL
key = BGP_DEVICE_GLOBAL_KEY
data = {
"tsa_enabled": state,
}

try:
update_entry_validated(db.cfgdb, table, key, data, create_if_not_exists=True)
log.log_notice("Configured TSA state: {}".format(to_str(state)))
except Exception as e:
log.log_error("Failed to configure TSA state: {}".format(str(e)))
ctx.fail(str(e))


def wcmp_handler(ctx, db, state):
""" Handle config updates for Weighted-Cost Multi-Path (W-ECMP) feature """

table = CFG_BGP_DEVICE_GLOBAL
key = BGP_DEVICE_GLOBAL_KEY
data = {
"wcmp_enabled": state,
}

try:
update_entry_validated(db.cfgdb, table, key, data, create_if_not_exists=True)
log.log_notice("Configured W-ECMP state: {}".format(to_str(state)))
except Exception as e:
log.log_error("Failed to configure W-ECMP state: {}".format(str(e)))
ctx.fail(str(e))


#
# BGP device-global ---------------------------------------------------------------------------------------------------
#


@click.group(
name="device-global",
cls=clicommon.AliasedGroup
)
def DEVICE_GLOBAL():
""" Configure BGP device global state """

pass


#
# BGP device-global tsa -----------------------------------------------------------------------------------------------
#


@DEVICE_GLOBAL.group(
name="tsa",
cls=clicommon.AliasedGroup
)
def DEVICE_GLOBAL_TSA():
""" Configure Traffic-Shift-Away (TSA) feature """

pass


@DEVICE_GLOBAL_TSA.command(
name="enabled"
)
@clicommon.pass_db
@click.pass_context
def DEVICE_GLOBAL_TSA_ENABLED(ctx, db):
""" Enable Traffic-Shift-Away (TSA) feature """

tsa_handler(ctx, db, "true")


@DEVICE_GLOBAL_TSA.command(
name="disabled"
)
@clicommon.pass_db
@click.pass_context
def DEVICE_GLOBAL_TSA_DISABLED(ctx, db):
""" Disable Traffic-Shift-Away (TSA) feature """

tsa_handler(ctx, db, "false")


#
# BGP device-global w-ecmp --------------------------------------------------------------------------------------------
#


@DEVICE_GLOBAL.group(
name="w-ecmp",
cls=clicommon.AliasedGroup
)
def DEVICE_GLOBAL_WCMP():
""" Configure Weighted-Cost Multi-Path (W-ECMP) feature """

pass


@DEVICE_GLOBAL_WCMP.command(
name="enabled"
)
@clicommon.pass_db
@click.pass_context
def DEVICE_GLOBAL_WCMP_ENABLED(ctx, db):
""" Enable Weighted-Cost Multi-Path (W-ECMP) feature """

wcmp_handler(ctx, db, "true")


@DEVICE_GLOBAL_WCMP.command(
name="disabled"
)
@clicommon.pass_db
@click.pass_context
def DEVICE_GLOBAL_WCMP_DISABLED(ctx, db):
""" Disable Weighted-Cost Multi-Path (W-ECMP) feature """

wcmp_handler(ctx, db, "false")
101 changes: 100 additions & 1 deletion config/chassis_modules.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
#!/usr/sbin/env python

import click

import time
import re
import subprocess
import utilities_common.cli as clicommon

TIMEOUT_SECS = 10


#
# 'chassis_modules' group ('config chassis_modules ...')
#
Expand All @@ -17,6 +22,81 @@ def modules():
"""Configure chassis modules"""
pass


def get_config_module_state(db, chassis_module_name):
config_db = db.cfgdb
fvs = config_db.get_entry('CHASSIS_MODULE', chassis_module_name)
if not fvs:
return 'up'
else:
return fvs['admin_status']


#
# Name: check_config_module_state_with_timeout
# return: True: timeout, False: not timeout
#
def check_config_module_state_with_timeout(ctx, db, chassis_module_name, state):
counter = 0
while get_config_module_state(db, chassis_module_name) != state:
time.sleep(1)
counter += 1
if counter >= TIMEOUT_SECS:
ctx.fail("get_config_module_state {} timeout".format(chassis_module_name))
return True
return False


def get_asic_list_from_db(chassisdb, chassis_module_name):
asic_list = []
asics_keys_list = chassisdb.keys("CHASSIS_STATE_DB", "CHASSIS_FABRIC_ASIC_TABLE*")
for asic_key in asics_keys_list:
name = chassisdb.get("CHASSIS_STATE_DB", asic_key, "name")
if name == chassis_module_name:
asic_id = int(re.search(r"(\d+)$", asic_key).group())
asic_list.append(asic_id)
return asic_list


#
# Syntax: fabric_module_set_admin_status <chassis_module_name> <'up'/'down'>
#
def fabric_module_set_admin_status(db, chassis_module_name, state):
chassisdb = db.db
chassisdb.connect("CHASSIS_STATE_DB")
asic_list = get_asic_list_from_db(chassisdb, chassis_module_name)

if len(asic_list) == 0:
return

if state == "down":
for asic in asic_list:
click.echo("Stop swss@{} and peer services".format(asic))
clicommon.run_command('sudo systemctl stop swss@{}.service'.format(asic))

is_active = subprocess.call(["systemctl", "is-active", "--quiet", "swss@{}.service".format(asic)])

if is_active == 0: # zero active, non-zero, inactive
click.echo("Stop swss@{} and peer services failed".format(asic))
return

click.echo("Delete related CAHSSIS_FABRIC_ASIC_TABLE entries")

for asic in asic_list:
chassisdb.delete("CHASSIS_STATE_DB", "CHASSIS_FABRIC_ASIC_TABLE|asic" + str(asic))

# Start the services in case of the users just execute issue command "systemctl stop swss@/syncd@"
# without bring down the hardware
for asic in asic_list:
# To address systemd service restart limit by resetting the count
clicommon.run_command('sudo systemctl reset-failed swss@{}.service'.format(asic))
click.echo("Start swss@{} and peer services".format(asic))
clicommon.run_command('sudo systemctl start swss@{}.service'.format(asic))
elif state == "up":
for asic in asic_list:
click.echo("Start swss@{} and peer services".format(asic))
clicommon.run_command('sudo systemctl start swss@{}.service'.format(asic))

#
# 'shutdown' subcommand ('config chassis_modules shutdown ...')
#
Expand All @@ -33,8 +113,17 @@ def shutdown_chassis_module(db, chassis_module_name):
not chassis_module_name.startswith("FABRIC-CARD"):
ctx.fail("'module_name' has to begin with 'SUPERVISOR', 'LINE-CARD' or 'FABRIC-CARD'")

# To avoid duplicate operation
if get_config_module_state(db, chassis_module_name) == 'down':
click.echo("Module {} is already in down state".format(chassis_module_name))
return

click.echo("Shutting down chassis module {}".format(chassis_module_name))
fvs = {'admin_status': 'down'}
config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs)
if chassis_module_name.startswith("FABRIC-CARD"):
if not check_config_module_state_with_timeout(ctx, db, chassis_module_name, 'down'):
fabric_module_set_admin_status(db, chassis_module_name, 'down')

#
# 'startup' subcommand ('config chassis_modules startup ...')
Expand All @@ -45,5 +134,15 @@ def shutdown_chassis_module(db, chassis_module_name):
def startup_chassis_module(db, chassis_module_name):
"""Chassis-module startup of module"""
config_db = db.cfgdb
ctx = click.get_current_context()

# To avoid duplicate operation
if get_config_module_state(db, chassis_module_name) == 'up':
click.echo("Module {} is already set to up state".format(chassis_module_name))
return

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

0 comments on commit 5dec52d

Please sign in to comment.