Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

threshold feature #1313

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 179 additions & 0 deletions clear/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
import sys

import click
from natsort import natsorted
from swsssdk import ConfigDBConnector
from swsssdk import SonicV2Connector
COUNTERS_BUFFER_POOL_NAME_MAP = 'COUNTERS_BUFFER_POOL_NAME_MAP'


# This is from the aliases example:
Expand Down Expand Up @@ -235,6 +239,94 @@ def clear_pwm_pg_shared():
command = 'watermarkstat -c -p -t pg_shared'
run_command(command)

@cli.group(name='buffer-pool')
def buffer_pool():
"""Clear Buffer pool WM"""
pass

@buffer_pool.command('threshold')
def clear_buffer_pool_threshold():

# connect to COUNTERS DB
counters_db = SonicV2Connector(host='127.0.0.1')
counters_db.connect(counters_db.COUNTERS_DB)

# connect to CONFIG DB
config_db = ConfigDBConnector()
config_db.connect()

buffer_pool_name_to_oid_map = counters_db.get_all(counters_db.COUNTERS_DB, COUNTERS_BUFFER_POOL_NAME_MAP)

if buffer_pool_name_to_oid_map is None:
print("Buffer pools are empty!!. Not yet created")
return

# Delete buffer pool table entries from threshold table
for buf_pool,buf_oid in natsorted(buffer_pool_name_to_oid_map.items()):
key = buf_pool
entry = config_db.get_entry('THRESHOLD_BUFFERPOOL_TABLE', key)
if entry:
config_db.set_entry('THRESHOLD_BUFFERPOOL_TABLE', key, None)

def interface_name_is_valid(interface_name):
"""Check if the interface name is valid
"""
config_db = ConfigDBConnector()
config_db.connect()
port_dict = config_db.get_table('PORT')
port_channel_dict = config_db.get_table('PORTCHANNEL')

if interface_name is not None:
if not port_dict:
click.echo("port_dict is None!")
raise click.Abort()
for port_name in port_dict.keys():
if interface_name == port_name:
return True
if port_channel_dict:
for port_channel_name in port_channel_dict.keys():
if interface_name == port_channel_name:
return True
return False


@priority_group.command('threshold')
@click.argument('port_name', metavar='<port_name>', required=False)
@click.argument('pg_index', metavar='<pg_index>', required=False, type=int)
@click.argument('threshold_type', required=False, type=click.Choice(['shared', 'headroom']))
@click.pass_context
def threshold(ctx, port_name, pg_index, threshold_type):
""" Clear priority group threshold """
# If no params are provided, clear all priority-group entries.
config_db = ConfigDBConnector()
config_db.connect()

all = False

if port_name is None and pg_index is None and threshold_type is None:
# clear all entries.
key = 'priority-group'
all = True
elif port_name is None or pg_index is None or threshold_type is None:
ctx.fail("port_name, pg_index and threshold_type are mandatory parameters.")
else:
if pg_index not in range(0, 8):
ctx.fail("priority-group must be in range 0-7")
if interface_name_is_valid(port_name) is False:
ctx.fail("Interface name is invalid!!")
key = 'priority-group' + '|' + threshold_type + '|' + port_name + '|' + str(pg_index)

if all is True:
entry_table = config_db.get_keys('THRESHOLD_TABLE')
# Clear data for all keys
for k in natsorted(entry_table):
if k[0] == 'priority-group':
config_db.set_entry('THRESHOLD_TABLE', k, None)
else:
entry = config_db.get_entry('THRESHOLD_TABLE', key)
if entry:
config_db.set_entry('THRESHOLD_TABLE', key, None)


@cli.group()
def queue():
Expand Down Expand Up @@ -301,6 +393,77 @@ def persistent_watermark():
command = 'watermarkstat -c -p -t headroom_pool'
run_command(command)

@queue.command('threshold')
@click.argument('port_name', metavar='<port_name>', required=False)
@click.argument('queue_index', metavar='<queue_index>', required=False, type=int)
@click.argument('queue_type', required=False, type=click.Choice(['unicast', 'multicast', 'cpu']))
@click.pass_context
def threshold(ctx, port_name, queue_index, queue_type):
""" Clear queue threshold for a queue on a port """
# If no params are provided, clear all priority-group entries.
config_db = ConfigDBConnector()
config_db.connect()

all = False

if port_name is None and queue_index is None and queue_type is None:
# clear all entries.
key = 'queue'
all = True
elif port_name is None or queue_index is None or queue_type is None:
ctx.fail("port_name, queue_index and queue_type are mandatory parameters.")
else:
if queue_index not in range(0, 8):
ctx.fail("queue index must be in range 0-7")
if interface_name_is_valid(port_name) is False:
ctx.fail("Interface name is invalid!!")
## Validate if queue index is supported.
counters_db = SonicV2Connector(host='127.0.0.1')
counters_db.connect(counters_db.COUNTERS_DB)

counters_queue_name_map = counters_db.get_all(counters_db.COUNTERS_DB, "COUNTERS_QUEUE_NAME_MAP")
counters_queue_type_map = counters_db.get_all(counters_db.COUNTERS_DB, "COUNTERS_QUEUE_TYPE_MAP")

if counters_queue_name_map is None or counters_queue_type_map is None:
ctx.fail("Queue maps not generated yet.")

num_uc_queues = 0
num_mc_queues = 0

for queue in counters_queue_name_map:
portstr = queue.split(':')
port = portstr[0]
if port == port_name:
if counters_queue_type_map[counters_queue_name_map[queue]] == "SAI_QUEUE_TYPE_MULTICAST":
num_mc_queues += 1
elif counters_queue_type_map[counters_queue_name_map[queue]] == "SAI_QUEUE_TYPE_UNICAST":
num_uc_queues += 1

if queue_type == 'unicast':
if queue_index not in range(0, num_uc_queues):
ctx.fail("Invalid queue index provided. Only {} unicast queues supported on port.".format(num_uc_queues))
elif queue_type == 'multicast':
if queue_index not in range(0, num_mc_queues):
ctx.fail("Invalid queue index provided. Only {} multicast queues supported on port.". format(num_mc_queues))

key = 'queue' + '|' + queue_type + '|' + port_name + '|' + str(queue_index)
if queue_type == 'cpu':
key = 'queue' + '|' + queue_type + '|' + 'CPU' + '|' + str(queue_index)
else:
key = 'queue' + '|' + queue_type + '|' + port_name + '|' + str(queue_index)


if all is True:
entry_table = config_db.get_keys('THRESHOLD_TABLE')
# Clear data for all keys
for k in natsorted(entry_table):
if k[0] == 'queue':
config_db.set_entry('THRESHOLD_TABLE', k, None)
else:
entry = config_db.get_entry('THRESHOLD_TABLE', key)
if entry:
config_db.set_entry('THRESHOLD_TABLE', key, None)

#
# 'arp' command ####
#
Expand Down Expand Up @@ -397,6 +560,22 @@ def line(target, devicename):
click.echo(output)
sys.exit(exitstatus)

@cli.group('threshold')
def threshold():
"""Clear threshold breach entries"""
pass

@threshold.command()
@click.argument('id', type=int, required=False)
def breach(id):
"""Clear threshold breach entries all | event-id"""
if id is not None:
cmd = "thresholdbreach -c -cnt {}".format(id)
else:
cmd = 'thresholdbreach -c'

run_command(cmd)

#
# 'nat' group ("clear nat ...")
#
Expand Down
149 changes: 149 additions & 0 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import re
import subprocess
import sys
import swsssdk
import threading
import time

Expand Down Expand Up @@ -766,6 +767,7 @@ def _reset_failed_services(config_db):
'snmp',
'swss',
'syncd',
'tam',
'teamd',
'telemetry'
]
Expand Down Expand Up @@ -793,6 +795,7 @@ def _restart_services(config_db):
'lldp',
'hostcfgd',
'nat',
'tam',
'sflow',
'restapi',
'telemetry'
Expand Down Expand Up @@ -3831,6 +3834,152 @@ def interval(interval):
clicommon.run_command(command)


@config.group('priority-group')
def priority_group():
""" Configure priority group thresholds """
pass

@priority_group.command('threshold')
@click.argument('port_name', metavar='<port_name>', required=True)
@click.argument('pg_index', metavar='<pg_index>', required=True, type=int)
@click.argument('threshold_type', type=click.Choice(['shared', 'headroom']))
@click.argument('threshold_value', metavar='<threshold_value>', required=True, type=int)
@click.pass_context
def threshold(ctx, port_name, pg_index, threshold_type, threshold_value):
""" Configure priority group threshold value for a priority group on a port """

config_db = ConfigDBConnector()
config_db.connect()

if pg_index not in range(0, 8):
ctx.fail("priority-group must be in range 0-7")

if threshold_value not in range(1, 101):
ctx.fail("threshold value must be in range 1-100")

if interface_name_is_valid(config_db, port_name) is False:
ctx.fail("Interface name is invalid!!")

key = 'priority-group' + '|' + threshold_type + '|' + port_name + '|' + str(pg_index)
entry = config_db.get_entry('THRESHOLD_TABLE', key)
if entry is None:
config_db.set_entry('THRESHOLD_TABLE', key, {'threshold' : threshold_value})
else:
entry_value = entry.get('threshold', [])
if entry_value != threshold_value:
config_db.mod_entry('THRESHOLD_TABLE', key, {'threshold' : threshold_value})

@config.group('queue')
def queue():
""" Configure queue thresholds """
pass

@queue.command('threshold')
@click.argument('port_name', metavar='<port_name>', required=True)
@click.argument('queue_index', metavar='<queue_index>', required=True, type=int)
@click.argument('queue_type', type=click.Choice(['unicast', 'multicast', 'CPU']))
@click.argument('threshold_value', metavar='<threshold_value>', required=True, type=int)
@click.pass_context
def threshold(ctx, port_name, queue_index, queue_type, threshold_value):
""" Configure queue threshold value for a queue on a port """
config_db = ConfigDBConnector()
config_db.connect()

if port_name != 'CPU':
if queue_index not in range(0, 8):
ctx.fail("queue index must be in range 0-7")
else:
if queue_index not in range(0, 47):
ctx.fail("CPU queue index must be in range 0-47")

if threshold_value not in range(1, 101):
ctx.fail("threshold value must be in range 1-100")

if (port_name.startswith("CPU") is False):
if interface_name_is_valid(config_db, port_name) is False:
ctx.fail("Interface name is invalid!!")

## Validate if queue index is supported.
counters_db = swsssdk.SonicV2Connector(host='127.0.0.1')
counters_db.connect(counters_db.COUNTERS_DB)

counters_queue_name_map = counters_db.get_all(counters_db.COUNTERS_DB, "COUNTERS_QUEUE_NAME_MAP")
counters_queue_type_map = counters_db.get_all(counters_db.COUNTERS_DB, "COUNTERS_QUEUE_TYPE_MAP")

if counters_queue_name_map is None or counters_queue_type_map is None:
ctx.fail("Queue maps not generated yet.")

num_uc_queues = 0
num_mc_queues = 0

for queue in counters_queue_name_map:
portstr = queue.split(':')
port = portstr[0]
if port == port_name:
if counters_queue_type_map[counters_queue_name_map[queue]] == "SAI_QUEUE_TYPE_MULTICAST":
num_mc_queues += 1
elif counters_queue_type_map[counters_queue_name_map[queue]] == "SAI_QUEUE_TYPE_UNICAST":
num_uc_queues += 1

if queue_type == 'unicast':
if queue_index not in range(0, num_uc_queues):
ctx.fail("Invalid queue index provided. Only {} unicast queues supported on port.".format(num_uc_queues))
elif queue_type == 'multicast':
if queue_index not in range(0, num_mc_queues):
ctx.fail("Invalid queue index provided. Only {} multicast queues supported on port.". format(num_mc_queues))

key = 'queue' + '|' + queue_type + '|' + port_name + '|' + str(queue_index)
if queue_type == 'CPU':
key = 'queue' + '|' + 'multicast' + '|' + 'CPU' + '|' + str(queue_index)
else:
key = 'queue' + '|' + queue_type + '|' + port_name + '|' + str(queue_index)

entry = config_db.get_entry('THRESHOLD_TABLE', key)
if entry is None:
config_db.set_entry('THRESHOLD_TABLE', key, {'threshold' : threshold_value})
else:
entry_value = entry.get('threshold', [])
if entry_value != threshold_value:
config_db.mod_entry('THRESHOLD_TABLE', key, {'threshold' : threshold_value})

@config.group('buffer-pool')
def buffer_pool():
""" Configure Buffer pool thresholds """
pass

@buffer_pool.command('threshold')
@click.argument('pool_name', metavar='<pool_name>', required=True)
@click.argument('threshold_value', metavar='<threshold_value>', required=True, type=int)
@click.pass_context
def threshold(ctx, pool_name, threshold_value):
""" Configure Buffer pool threshold value """

config_db = ConfigDBConnector()
config_db.connect()

counters_db = swsssdk.SonicV2Connector(host='127.0.0.1')
counters_db.connect(counters_db.COUNTERS_DB)

buffer_pool_name_to_oid_map = counters_db.get_all(counters_db.COUNTERS_DB, "COUNTERS_BUFFER_POOL_NAME_MAP")
if buffer_pool_name_to_oid_map is None:
ctx.fail("Buffer pools not created!!")

if pool_name not in buffer_pool_name_to_oid_map:
ctx.fail("Pool name is invalid!!")

if threshold_value not in range(1, 101):
ctx.fail("threshold value must be in range 1-100")

key = pool_name
entry = config_db.get_entry('THRESHOLD_BUFFERPOOL_TABLE', key)
if entry is None:
config_db.set_entry('THRESHOLD_BUFFERPOOL_TABLE', key, {'threshold' : threshold_value})
else:
entry_value = entry.get('threshold', [])
if entry_value != threshold_value:
config_db.mod_entry('THRESHOLD_BUFFERPOOL_TABLE', key, {'threshold' : threshold_value})


#
# 'interface_naming_mode' subgroup ('config interface_naming_mode ...')
#
Expand Down
5 changes: 5 additions & 0 deletions scripts/fast-reboot
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,11 @@ debug "Stopped sflow ..."
container kill lldp &> /dev/null || debug "Docker lldp is not running ($?) ..."
systemctl stop lldp

# Kill tam docker
debug "Stopping tam"
docker kill tam > /dev/null || true
debug "Stopped tam"

if [[ "$REBOOT_TYPE" = "fast-reboot" ]]; then
debug "Stopping teamd ..."
systemctl stop teamd
Expand Down
Loading