Skip to content

Commit ffaace8

Browse files
arista-hpandyakenneth-arista
authored andcommitted
Enhanced multi-asic support for mmuconfig
- Resolve pre-commit errors - Remove use_unix_socket_path argument from DB connectors - Support multiple namespace when none specified - Refactor tests to use the testData dict - Delete single_asic_mmuconfig_test.py - Replace argparse with click in mmuconfig - Add support for namespace in show and config - Modified multi-asic tests to use show/config cli
1 parent 5dd2cd6 commit ffaace8

File tree

6 files changed

+379
-153
lines changed

6 files changed

+379
-153
lines changed

config/main.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -6422,13 +6422,26 @@ def ecn(profile, rmax, rmin, ymax, ymin, gmax, gmin, rdrop, ydrop, gdrop, verbos
64226422
@config.command()
64236423
@click.option('-p', metavar='<profile_name>', type=str, required=True, help="Profile name")
64246424
@click.option('-a', metavar='<alpha>', type=click.IntRange(-8,8), help="Set alpha for profile type dynamic")
6425-
@click.option('-s', metavar='<staticth>', type=int, help="Set staticth for profile type static")
6426-
def mmu(p, a, s):
6425+
@click.option('-s', metavar='<staticth>', type=click.IntRange(min=0), help="Set staticth for profile type static")
6426+
@click.option('--verbose', '-vv', is_flag=True, help="Enable verbose output")
6427+
@click.option('--namespace',
6428+
'-n',
6429+
'namespace',
6430+
default=None,
6431+
type=str,
6432+
show_default=True,
6433+
help='Namespace name or all',
6434+
callback=multi_asic_util.multi_asic_namespace_validation_callback)
6435+
def mmu(p, a, s, namespace, verbose):
64276436
"""mmuconfig configuration tasks"""
64286437
log.log_info("'mmuconfig -p {}' executing...".format(p))
64296438
command = ['mmuconfig', '-p', str(p)]
64306439
if a is not None: command += ['-a', str(a)]
64316440
if s is not None: command += ['-s', str(s)]
6441+
if namespace is not None:
6442+
command += ['-n', str(namespace)]
6443+
if verbose:
6444+
command += ['-vv']
64326445
clicommon.run_command(command)
64336446

64346447

scripts/mmuconfig

+61-83
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,23 @@ optional arguments:
1818

1919
import os
2020
import sys
21-
import argparse
21+
import click
2222
import tabulate
2323
import traceback
2424
import json
2525
from utilities_common.general import load_db_config
2626
from sonic_py_common import multi_asic
27+
from utilities_common import multi_asic as multi_asic_util
2728

2829
BUFFER_POOL_TABLE_NAME = "BUFFER_POOL"
2930
BUFFER_PROFILE_TABLE_NAME = "BUFFER_PROFILE"
3031
DEFAULT_LOSSLESS_BUFFER_PARAMETER_NAME = "DEFAULT_LOSSLESS_BUFFER_PARAMETER"
3132

3233
DYNAMIC_THRESHOLD = "dynamic_th"
34+
DYNAMIC_THRESHOLD_MIN = -8
35+
DYNAMIC_THRESHOLD_MAX = 8
3336
STATIC_THRESHOLD = "static_th"
37+
STATIC_THRESHOLD_MIN = 0
3438
BUFFER_PROFILE_FIELDS = {
3539
"alpha": DYNAMIC_THRESHOLD,
3640
"staticth" : STATIC_THRESHOLD
@@ -47,6 +51,9 @@ try:
4751
if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic":
4852
import mock_tables.mock_multi_asic
4953
mock_tables.dbconnector.load_namespace_config()
54+
else:
55+
mock_tables.dbconnector.load_database_config()
56+
5057
except KeyError:
5158
pass
5259

@@ -58,43 +65,37 @@ class MmuConfig(object):
5865
self.config = config
5966
self.filename = filename
6067
self.namespace = namespace
68+
self.multi_asic = multi_asic_util.MultiAsic(namespace_option=namespace)
69+
self.config_db = None
70+
self.db = None
6171

62-
self.use_unix_socket_path = self.namespace != None
63-
64-
# Set up db connections
65-
if self.config:
66-
self.db = ConfigDBConnector(namespace=namespace, use_unix_socket_path=self.use_unix_socket_path)
67-
self.db.connect()
68-
else:
69-
self.db = SonicV2Connector(namespace=namespace, use_unix_socket_path=self.use_unix_socket_path)
70-
self.db.connect(self.db.STATE_DB, False)
72+
# For unit testing
73+
self.updated_profile_table = {}
7174

7275
def get_table(self, tablename):
7376
if self.config:
74-
return self.db.get_table(tablename)
77+
return self.config_db.get_table(tablename)
7578

7679
entries = {}
77-
for ns in multi_asic.get_namespace_list(self.namespace):
78-
db = SonicV2Connector(namespace=ns, use_unix_socket_path=True)
79-
db.connect(db.STATE_DB, False)
80-
keys = db.keys(db.STATE_DB, tablename + '*')
81-
82-
if keys:
83-
for key in keys:
84-
entries[key.split('|')[1]] = db.get_all(db.STATE_DB, key)
80+
keys = self.db.keys(self.db.STATE_DB, tablename + '*')
8581

86-
if not entries:
82+
if not keys:
8783
return None
8884

85+
for key in keys:
86+
entries[key.split('|')[1]] = self.db.get_all(self.db.STATE_DB, key)
87+
8988
return entries
9089

90+
@multi_asic_util.run_on_multi_asic
9191
def list(self):
92+
namespace_str = f" for namespace {self.multi_asic.current_namespace}" if multi_asic.is_multi_asic() else ''
9293
lossless_traffic_pattern = self.get_table(DEFAULT_LOSSLESS_BUFFER_PARAMETER_NAME)
9394
if lossless_traffic_pattern:
9495
for _, pattern in lossless_traffic_pattern.items():
9596
config = []
9697

97-
print("Lossless traffic pattern:")
98+
print(f"Lossless traffic pattern{namespace_str}:")
9899
for field, value in pattern.items():
99100
config.append([field, value])
100101
print(tabulate.tabulate(config) + "\n")
@@ -104,108 +105,88 @@ class MmuConfig(object):
104105
for pool_name, pool_data in buf_pools.items():
105106
config = []
106107

107-
print("Pool: " + pool_name)
108+
print(f"Pool{namespace_str}: " + pool_name)
108109
for field, value in pool_data.items():
109110
config.append([field, value])
110111
print(tabulate.tabulate(config) + "\n")
111112
if self.verbose:
112113
print("Total pools: %d\n\n" % len(buf_pools))
113114
else:
114-
print("No buffer pool information available")
115+
print(f"No buffer pool information available{namespace_str}")
115116

116117
buf_profs = self.get_table(BUFFER_PROFILE_TABLE_NAME)
117118
if buf_profs:
118119
for prof_name, prof_data in buf_profs.items():
119120
config = []
120121

121-
print("Profile: " + prof_name)
122+
print(f"Profile{namespace_str}: " + prof_name)
122123
for field, value in prof_data.items():
123124
config.append([field, value])
124125
print(tabulate.tabulate(config) + "\n")
125126
if self.verbose:
126127
print("Total profiles: %d" % len(buf_profs))
127128
else:
128-
print("No buffer profile information available")
129+
print(f"No buffer profile information available{namespace_str}")
129130

131+
@multi_asic_util.run_on_multi_asic
130132
def set(self, profile, field_alias, value):
133+
namespace_str = f" for namespace {self.multi_asic.current_namespace}" if multi_asic.is_multi_asic() else ''
131134
if os.geteuid() != 0 and os.environ.get("UTILITIES_UNIT_TESTING", "0") != "2":
132135
sys.exit("Root privileges required for this operation")
133136

134-
if not self.namespace and multi_asic.is_multi_asic():
135-
sys.exit("Namespace must be specified for this operation")
136-
137137
field = BUFFER_PROFILE_FIELDS[field_alias]
138-
buf_profs = self.db.get_table(BUFFER_PROFILE_TABLE_NAME)
139-
v = int(value)
138+
buf_profs = self.config_db.get_table(BUFFER_PROFILE_TABLE_NAME)
140139
if field == DYNAMIC_THRESHOLD:
141-
if v < -8 or v > 8:
142-
sys.exit("Invalid alpha value: 2^(%s)" % (value))
143-
144140
if profile in buf_profs and DYNAMIC_THRESHOLD not in buf_profs[profile]:
145141
sys.exit("%s not using dynamic thresholding" % (profile))
146142
elif field == STATIC_THRESHOLD:
147-
if v < 0:
148-
sys.exit("Invalid static threshold value: (%s)" % (value))
149-
150143
if profile in buf_profs and STATIC_THRESHOLD not in buf_profs[profile]:
151144
sys.exit("%s not using static threshold" % (profile))
152145
else:
153146
sys.exit("Set field %s not supported" % (field))
154147

155148
if self.verbose:
156-
print("Setting %s %s value to %s" % (profile, field, value))
157-
self.db.mod_entry(BUFFER_PROFILE_TABLE_NAME, profile, {field: value})
149+
print("Setting %s %s value to %s%s" % (profile, field, value, namespace_str))
150+
self.config_db.mod_entry(BUFFER_PROFILE_TABLE_NAME, profile, {field: value})
158151
if self.filename is not None:
159-
prof_table = self.db.get_table(BUFFER_PROFILE_TABLE_NAME)
152+
self.updated_profile_table[self.multi_asic.current_namespace] = self.config_db.get_table(BUFFER_PROFILE_TABLE_NAME)
160153
with open(self.filename, "w") as fd:
161-
json.dump(prof_table, fd)
162-
163-
164-
def main(config):
165-
if config:
166-
parser = argparse.ArgumentParser(description='Show and change: mmu configuration',
167-
formatter_class=argparse.RawTextHelpFormatter)
168-
169-
parser.add_argument('-l', '--list', action='store_true', help='show mmu configuration')
170-
parser.add_argument('-p', '--profile', type=str, help='specify buffer profile name', default=None)
171-
parser.add_argument('-a', '--alpha', type=str, help='set n for dyanmic threshold alpha 2^(n)', default=None)
172-
parser.add_argument('-s', '--staticth', type=str, help='set static threshold', default=None)
173-
parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0')
174-
else:
175-
parser = argparse.ArgumentParser(description='Show buffer state',
176-
formatter_class=argparse.RawTextHelpFormatter)
177-
178-
parser.add_argument('-l', '--list', action='store_true', help='show buffer state')
179-
parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0')
180-
181-
parser.add_argument('-n', '--namespace', type=str, help='Namespace name', default=None)
182-
parser.add_argument('-vv', '--verbose', action='store_true', help='verbose output', default=False)
183-
parser.add_argument('-f', '--filename', help='file used by mock tests', type=str, default=None)
184-
154+
json.dump(self.updated_profile_table, fd)
155+
156+
@click.command(help='Show and change: mmu configuration')
157+
@click.option('-l', '--list', 'show_config', is_flag=True, help='show mmu configuration')
158+
@click.option('-p', '--profile', type=str, help='specify buffer profile name', default=None)
159+
@click.option('-a', '--alpha', type=click.IntRange(DYNAMIC_THRESHOLD_MIN, DYNAMIC_THRESHOLD_MAX), help='set n for dyanmic threshold alpha 2^(n)', default=None)
160+
@click.option('-s', '--staticth', type=click.IntRange(min=STATIC_THRESHOLD_MIN), help='set static threshold', default=None)
161+
@click.option('-n', '--namespace', type=click.Choice(multi_asic.get_namespace_list()), help='Namespace name or skip for all', default=None)
162+
@click.option('-vv', '--verbose', is_flag=True, help='verbose output', default=False)
163+
@click.version_option(version='1.0')
164+
def main(show_config, profile, alpha, staticth, namespace, verbose):
165+
# A test file created for unit test purposes
166+
filename=None
185167
if os.environ.get("UTILITIES_UNIT_TESTING", "0") == "2":
186-
sys.argv.extend(['-f', '/tmp/mmuconfig'])
187-
168+
filename = '/tmp/mmuconfig'
188169

189-
args = parser.parse_args()
170+
# Buffershow and mmuconfig cmds share this script
171+
# Buffershow cmd cannot modify configs hence config is set to False
172+
config = True if sys.argv[0].split('/')[-1] == "mmuconfig" else False
190173

191174
try:
192175
load_db_config()
193-
namespaces = multi_asic.get_namespace_list()
176+
mmu_cfg = MmuConfig(verbose, config, filename, namespace)
194177

195-
if args.namespace and args.namespace not in namespaces:
196-
print("Invalid namespace: Namespace must be one of", *namespaces)
197-
sys.exit(1)
198-
199-
mmu_cfg = MmuConfig(args.verbose, config, args.filename, args.namespace)
200-
if args.list:
178+
# Both mmuconfig and buffershow have access to show_config option
179+
if show_config:
201180
mmu_cfg.list()
202-
elif config and args.profile:
203-
if args.alpha:
204-
mmu_cfg.set(args.profile, "alpha", args.alpha)
205-
elif args.staticth:
206-
mmu_cfg.set(args.profile, "staticth", args.staticth)
181+
# Buffershow cannot modify profiles
182+
elif config and profile:
183+
if alpha:
184+
mmu_cfg.set(profile, "alpha", alpha)
185+
elif staticth:
186+
mmu_cfg.set(profile, "staticth", staticth)
207187
else:
208-
parser.print_help()
188+
ctx = click.get_current_context()
189+
click.echo(ctx.get_help())
209190
sys.exit(1)
210191

211192
except Exception as e:
@@ -214,7 +195,4 @@ def main(config):
214195
sys.exit(1)
215196

216197
if __name__ == "__main__":
217-
if sys.argv[0].split('/')[-1] == "mmuconfig":
218-
main(True)
219-
else:
220-
main(False)
198+
main()

show/main.py

+30-3
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,6 @@ def cli(ctx):
291291
load_db_config()
292292
ctx.obj = Db()
293293

294-
295294
# Add groups from other modules
296295
cli.add_command(acl.acl)
297296
cli.add_command(chassis_modules.chassis)
@@ -2030,9 +2029,22 @@ def boot():
20302029
# 'mmu' command ("show mmu")
20312030
#
20322031
@cli.command('mmu')
2033-
def mmu():
2032+
@click.option('--namespace',
2033+
'-n',
2034+
'namespace',
2035+
default=None,
2036+
type=str,
2037+
show_default=True,
2038+
help='Namespace name or all',
2039+
callback=multi_asic_util.multi_asic_namespace_validation_callback)
2040+
@click.option('--verbose', '-vv', is_flag=True, help="Enable verbose output")
2041+
def mmu(namespace, verbose):
20342042
"""Show mmu configuration"""
20352043
cmd = ['mmuconfig', '-l']
2044+
if namespace is not None:
2045+
cmd += ['-n', str(namespace)]
2046+
if verbose:
2047+
cmd += ['-vv']
20362048
run_command(cmd)
20372049

20382050
#
@@ -2046,10 +2058,25 @@ def buffer():
20462058
#
20472059
# 'configuration' command ("show buffer command")
20482060
#
2061+
2062+
20492063
@buffer.command()
2050-
def configuration():
2064+
@click.option('--namespace',
2065+
'-n',
2066+
'namespace',
2067+
default=None,
2068+
type=str,
2069+
show_default=True,
2070+
help='Namespace name or all',
2071+
callback=multi_asic_util.multi_asic_namespace_validation_callback)
2072+
@click.option('--verbose', '-vv', is_flag=True, help="Enable verbose output")
2073+
def configuration(namespace, verbose):
20512074
"""show buffer configuration"""
20522075
cmd = ['mmuconfig', '-l']
2076+
if namespace is not None:
2077+
cmd += ['-n', str(namespace)]
2078+
if verbose:
2079+
cmd += ['-vv']
20532080
run_command(cmd)
20542081

20552082
#

0 commit comments

Comments
 (0)