Skip to content

Commit

Permalink
mmuconfig to set threshold for profiles master#2775
Browse files Browse the repository at this point in the history
Signed-off-by: Alpesh S Patel <[email protected]>
  • Loading branch information
alpeshspatel committed Sep 27, 2023
1 parent 75030e0 commit 44dbfde
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 15 deletions.
16 changes: 16 additions & 0 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5677,6 +5677,22 @@ def ecn(profile, rmax, rmin, ymax, ymin, gmax, gmin, rdrop, ydrop, gdrop, verbos
clicommon.run_command(command, display_cmd=verbose)


#
# 'mmu' command ('config mmu...')
#
@config.command()
@click.option('-p', metavar='<profile_name>', type=str, required=True, help="Profile name")
@click.option('-a', metavar='<alpha>', type=click.IntRange(-8,8), help="Set alpha for profile type dynamic")
@click.option('-s', metavar='<staticth>', type=int, help="Set staticth for profile type static")
def mmu(p, a, s):
"""mmuconfig configuration tasks"""
log.log_info("'mmuconfig -p {}' executing...".format(p))
command = "mmuconfig -p %s" % p
if a is not None: command += " -a %d" % a
if s is not None: command += " -s %d" % s
clicommon.run_command(command)


#
# 'pfc' group ('config interface pfc ...')
#
Expand Down
45 changes: 30 additions & 15 deletions scripts/mmuconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
mmuconfig is the utility to show and change mmu configuration
usage: mmuconfig [-h] [-v] [-l] [-p PROFILE] [-a ALPHA] [-vv]
usage: mmuconfig [-h] [-v] [-l] [-p PROFILE] [-a ALPHA] [-vv] [-s staticth]
optional arguments:
-h --help show this help message and exit
Expand All @@ -12,6 +12,7 @@ optional arguments:
-l --list show mmu configuration
-p --profile specify buffer profile name
-a --alpha set n for dyanmic threshold alpha 2^(n)
-s --staticth set static threshold
"""

Expand All @@ -20,14 +21,17 @@ import sys
import argparse
import tabulate
import traceback
import json

BUFFER_POOL_TABLE_NAME = "BUFFER_POOL"
BUFFER_PROFILE_TABLE_NAME = "BUFFER_PROFILE"
DEFAULT_LOSSLESS_BUFFER_PARAMETER_NAME = "DEFAULT_LOSSLESS_BUFFER_PARAMETER"

DYNAMIC_THRESHOLD = "dynamic_th"
STATIC_THRESHOLD = "static_th"
BUFFER_PROFILE_FIELDS = {
"alpha": DYNAMIC_THRESHOLD
"alpha": DYNAMIC_THRESHOLD,
"staticth" : STATIC_THRESHOLD
}

# mock the redis for unit test purposes #
Expand All @@ -44,18 +48,11 @@ except KeyError:

from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector

BUFFER_POOL_TABLE_NAME = "BUFFER_POOL"
BUFFER_PROFILE_TABLE_NAME = "BUFFER_PROFILE"

DYNAMIC_THRESHOLD = "dynamic_th"
BUFFER_PROFILE_FIELDS = {
"alpha": DYNAMIC_THRESHOLD
}

class MmuConfig(object):
def __init__(self, verbose, config):
def __init__(self, verbose, config, filename):
self.verbose = verbose
self.config = config
self.filename = filename

# Set up db connections
if self.config:
Expand Down Expand Up @@ -120,24 +117,34 @@ class MmuConfig(object):
print("No buffer profile information available")

def set(self, profile, field_alias, value):
if os.geteuid() != 0:
if os.geteuid() != 0 and os.environ.get("UTILITIES_UNIT_TESTING", "0") != "2":
sys.exit("Root privileges required for this operation")

field = BUFFER_PROFILE_FIELDS[field_alias]
buf_profs = self.db.get_table(BUFFER_PROFILE_TABLE_NAME)
v = int(value)
if field == DYNAMIC_THRESHOLD:
v = int(value)
if v < -8 or v > 8:
sys.exit("Invalid alpha value: 2^(%s)" % (value))

buf_profs = self.db.get_table(BUFFER_PROFILE_TABLE_NAME)
if profile in buf_profs and DYNAMIC_THRESHOLD not in buf_profs[profile]:
sys.exit("%s not using dynamic thresholding" % (profile))
elif field == STATIC_THRESHOLD:
if v < 0:
sys.exit("Invalid static threshold value: (%s)" % (value))

if profile in buf_profs and STATIC_THRESHOLD not in buf_profs[profile]:
sys.exit("%s not using static threshold" % (profile))
else:
sys.exit("Set field %s not supported" % (field))

if self.verbose:
print("Setting %s %s value to %s" % (profile, field, value))
self.db.mod_entry(BUFFER_PROFILE_TABLE_NAME, profile, {field: value})
if self.filename is not None:
prof_table = self.db.get_table(BUFFER_PROFILE_TABLE_NAME)
with open(self.filename, "w") as fd:
json.dump(prof_table, fd)


def main(config):
Expand All @@ -148,6 +155,7 @@ def main(config):
parser.add_argument('-l', '--list', action='store_true', help='show mmu configuration')
parser.add_argument('-p', '--profile', type=str, help='specify buffer profile name', default=None)
parser.add_argument('-a', '--alpha', type=str, help='set n for dyanmic threshold alpha 2^(n)', default=None)
parser.add_argument('-s', '--staticth', type=str, help='set static threshold', default=None)
parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0')
else:
parser = argparse.ArgumentParser(description='Show buffer state',
Expand All @@ -157,16 +165,23 @@ def main(config):
parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0')

parser.add_argument('-vv', '--verbose', action='store_true', help='verbose output', default=False)
parser.add_argument('-f', '--filename', help='file used by mock tests', type=str, default=None)

if os.environ.get("UTILITIES_UNIT_TESTING", "0") == "2":
sys.argv.extend(['-f', '/tmp/mmuconfig'])


args = parser.parse_args()

try:
mmu_cfg = MmuConfig(args.verbose, config)
mmu_cfg = MmuConfig(args.verbose, config, args.filename)
if args.list:
mmu_cfg.list()
elif config and args.profile:
if args.alpha:
mmu_cfg.set(args.profile, "alpha", args.alpha)
elif args.staticth:
mmu_cfg.set(args.profile, "staticth", args.staticth)
else:
parser.print_help()
sys.exit(1)
Expand Down
14 changes: 14 additions & 0 deletions tests/buffer_input/buffer_test_vectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,27 @@
type ingress
---- -------
Pool: ingress_lossless_pool_hbm
---- ---------
mode static
size 139458240
type ingress
---- ---------
Profile: ingress_lossy_profile
---------- ------------------
dynamic_th 3
pool ingress_lossy_pool
size 0
---------- ------------------
Profile: ingress_lossless_profile_hbm
--------- -------------------------
static_th 12121212
pool ingress_lossless_pool_hbm
size 0
--------- -------------------------
Profile: headroom_profile
---------- ---------------------
dynamic_th 0
Expand Down
112 changes: 112 additions & 0 deletions tests/mmuconfig_input/mmuconfig_test_vectors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
show_mmu_config = """\
Lossless traffic pattern:
-------------------- -
default_dynamic_th 0
over_subscribe_ratio 2
-------------------- -
Pool: egress_lossless_pool
---- --------
mode dynamic
size 13945824
type egress
---- --------
Pool: egress_lossy_pool
---- -------
mode dynamic
type egress
---- -------
Pool: ingress_lossless_pool
---- -------
mode dynamic
type ingress
---- -------
Pool: ingress_lossy_pool
---- -------
mode dynamic
type ingress
---- -------
Pool: ingress_lossless_pool_hbm
---- ---------
mode static
size 139458240
type ingress
---- ---------
Profile: ingress_lossy_profile
---------- ------------------
dynamic_th 3
pool ingress_lossy_pool
size 0
---------- ------------------
Profile: ingress_lossless_profile_hbm
--------- -------------------------
static_th 12121212
pool ingress_lossless_pool_hbm
size 0
--------- -------------------------
Profile: headroom_profile
---------- ---------------------
dynamic_th 0
pool ingress_lossless_pool
xon 18432
xoff 32768
size 51200
---------- ---------------------
Profile: alpha_profile
------------- ---------------------
dynamic_th 0
pool ingress_lossless_pool
headroom_type dynamic
------------- ---------------------
Profile: egress_lossless_profile
---------- --------------------
dynamic_th 0
pool egress_lossless_pool
size 0
---------- --------------------
Profile: egress_lossy_profile
---------- -----------------
dynamic_th 0
pool egress_lossy_pool
size 0
---------- -----------------
"""

testData = {
'mmuconfig_list' : {'cmd' : ['show'],
'args' : [],
'rc' : 0,
'rc_output': show_mmu_config
},
'mmu_cfg_static_th' : {'cmd' : ['config'],
'args' : ['-p', 'ingress_lossless_profile_hbm', '-s', '12121213'],
'rc' : 0,
'db_table' : 'BUFFER_PROFILE',
'cmp_args' : ['ingress_lossless_profile_hbm,static_th,12121213'],
'rc_msg' : ''
},
'mmu_cfg_alpha' : {'cmd' : ['config'],
'args' : ['-p', 'alpha_profile', '-a', '2'],
'rc' : 0,
'db_table' : 'BUFFER_PROFILE',
'cmp_args' : ['alpha_profile,dynamic_th,2'],
'rc_msg' : ''
},
'mmu_cfg_alpha_invalid' : {'cmd' : ['config'],
'args' : ['-p', 'alpha_profile', '-a', '12'],
'rc' : 2,
'rc_msg' : 'Usage: mmu [OPTIONS]\nTry "mmu --help" for help.\n\nError: Invalid value for "-a": 12 is not in the valid range of -8 to 8.\n'
}

}
86 changes: 86 additions & 0 deletions tests/mmuconfig_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import os
import sys
import json
import pytest

from click.testing import CliRunner
import config.main as config
import show.main as show
from utilities_common.db import Db
from .mmuconfig_input.mmuconfig_test_vectors import *

test_path = os.path.dirname(os.path.abspath(__file__))
modules_path = os.path.dirname(test_path)
scripts_path = os.path.join(modules_path, "scripts")
sys.path.insert(0, test_path)
sys.path.insert(0, modules_path)


class Testmmuconfig(object):
@classmethod
def setup_class(cls):
os.environ["PATH"] += os.pathsep + scripts_path
os.environ['UTILITIES_UNIT_TESTING'] = "2"
print("SETUP")

def test_mmu_show_config(self):
self.executor(testData['mmuconfig_list'])

def test_mmu_alpha_config(self):
self.executor(testData['mmu_cfg_alpha'])

def test_mmu_alpha_invalid_config(self):
self.executor(testData['mmu_cfg_alpha_invalid'])

def test_mmu_staticth_config(self):
self.executor(testData['mmu_cfg_static_th'])

def executor(self, input):
runner = CliRunner()

if 'db_table' in input:
db = Db()
data_list = list(db.cfgdb.get_table(input['db_table']))
input['rc_msg'] = input['rc_msg'].format(",".join(data_list))

if 'show' in input['cmd']:
exec_cmd = show.cli.commands["mmu"]
result = runner.invoke(exec_cmd, input['args'])
exit_code = result.exit_code
output = result.output
elif 'config' in input['cmd']:
exec_cmd = config.config.commands["mmu"]
result = runner.invoke(exec_cmd, input['args'], catch_exceptions=False)
exit_code = result.exit_code
output = result.output

print(exit_code)
print(output)

if input['rc'] == 0:
assert exit_code == 0
else:
assert exit_code != 0

if 'cmp_args' in input:
fd = open('/tmp/mmuconfig', 'r')
cmp_data = json.load(fd)
for args in input['cmp_args']:
profile, name, value = args.split(',')
assert(cmp_data[profile][name] == value)
fd.close()

if 'rc_msg' in input:
assert input['rc_msg'] in output

if 'rc_output' in input:
assert output == input['rc_output']


@classmethod
def teardown_class(cls):
os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1])
os.environ['UTILITIES_UNIT_TESTING'] = "0"
if os.path.isfile('/tmp/mmuconfig'):
os.remove('/tmp/mmuconfig')
print("TEARDOWN")
Loading

0 comments on commit 44dbfde

Please sign in to comment.