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 CLI changes. #665

Closed
wants to merge 6 commits into from
Closed
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
113 changes: 113 additions & 0 deletions clear/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import os
import subprocess
from click_default_group import DefaultGroup
from natsort import natsorted
from swsssdk import ConfigDBConnector

try:
# noinspection PyPep8Naming
Expand Down Expand Up @@ -245,6 +247,63 @@ def clear_pwm_pg_shared():
command = 'watermarkstat -c -p -t pg_shared'
run_command(command)

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 @@ -287,6 +346,44 @@ def clear_pwm_q_multi():
command = 'watermarkstat -c -p -t q_shared_multi'
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']))
@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!!")
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 @@ -380,6 +477,22 @@ def line(linenum):
cmd = "consutil clear " + str(linenum)
run_command(cmd)


@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
75 changes: 74 additions & 1 deletion config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ def _stop_services():
'pmon',
'bgp',
'hostcfgd',
'tam',
'nat'
]

Expand All @@ -492,7 +493,8 @@ def _reset_failed_services():
'syncd',
'teamd',
'nat',
'sflow'
'sflow',
'tam'
]
execute_systemctl(services_to_reset, SYSTEMCTL_ACTION_RESET_FAILED)

Expand All @@ -511,6 +513,7 @@ def _restart_services():
'lldp',
'hostcfgd',
'nat',
'tam',
'sflow',
]

Expand Down Expand Up @@ -2279,6 +2282,75 @@ def naming_mode_alias():
"""Set CLI interface naming mode to ALIAS (Vendor port alias)"""
set_interface_naming_mode('alias')

@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']))
@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 queue_index not in range(0, 8):
ctx.fail("queue index 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 = '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()
def ztp():
""" Configure Zero Touch Provisioning """
Expand Down Expand Up @@ -2314,6 +2386,7 @@ def enable(enable):
command = "ztp enable"
run_command(command, display_cmd=True)


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

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

if [[ "$REBOOT_TYPE" = "fast-reboot" ]]; then
# Kill teamd processes inside of teamd container with SIGUSR2 to allow them to send last LACP frames
# We call `docker kill teamd` to ensure the container stops as quickly as possible,
Expand Down
120 changes: 120 additions & 0 deletions scripts/thresholdbreach
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/python

############################################################################
#
# thresholdbreach is a tool for displaying threshold breaches.
#
############################################################################

import argparse
import getopt
import json
import sys
import swsssdk
from natsort import natsorted
from tabulate import tabulate
from swsssdk import ConfigDBConnector


THRESHOLD_BREACH_TABLE_PREFIX = "THRESHOLD_BREACH"
header = ['Event-id', 'Buffer', 'Type', 'Port', 'Index', 'Breach Value(%)', 'Breach Value(bytes)', 'Time-stamp']

class Thresholdbreach(object):

def __init__(self):
# connect COUNTER DB
self.counters_db = ConfigDBConnector()
self.counters_db.db_connect('COUNTERS_DB')

def get_threshold_breach_info(self, k):
breach_data = {}
key = THRESHOLD_BREACH_TABLE_PREFIX + ':' + k
# k is of the format "breach-report:1". Extract event-id "1"
id = k.split(':')
eventid = id[1]
breach_data['eventid'] = eventid
data = self.counters_db.get_all(self.counters_db.COUNTERS_DB, key)
if data is not None:
breach_data['buffer'] = data['buffer']
breach_data['type'] = data['type']
breach_data['port'] = data['port']
breach_data['index'] = data['index']
breach_data['breach_value'] = data['breach_value']
breach_data['time-stamp'] = data['time-stamp']
if data['type'] == 'shared':
breach_data['counter'] = data['SAI_INGRESS_PRIORITY_GROUP_STAT_SHARED_WATERMARK_BYTES']
elif data['type'] == 'headroom':
breach_data['counter'] = data['SAI_INGRESS_PRIORITY_GROUP_STAT_XOFF_ROOM_WATERMARK_BYTES']
elif data['type'] == 'unicast':
breach_data['counter'] = data['SAI_QUEUE_STAT_SHARED_WATERMARK_BYTES']
elif data['type'] == 'multicast':
breach_data['counter'] = data['SAI_QUEUE_STAT_SHARED_WATERMARK_BYTES']
return breach_data

def get_print_all_threshold_breach(self, count):
table_data = self.counters_db.get_keys(THRESHOLD_BREACH_TABLE_PREFIX)
# Get data for all keys
table = []
iter = 0
maxcount = int(count)

for k in natsorted(table_data, reverse=True):
if (maxcount != 0) and (iter == maxcount):
break

if k == "event-id":
continue

iter = iter + 1
data = self.get_threshold_breach_info(k)
table.append((data['eventid'], data['buffer'], data['type'], data['port'], data['index'],
data['breach_value'], data['counter'], data['time-stamp']))

print tabulate(table, header, tablefmt='simple', stralign='right')
return

def clear_all_threshold_breach(self, count):
if count is 0:
table_data = self.counters_db.get_keys(THRESHOLD_BREACH_TABLE_PREFIX)
# Get data for all keys
for k in natsorted(table_data):
self.counters_db.set_entry(THRESHOLD_BREACH_TABLE_PREFIX, k, None)
else:
key = "breach-report" + ":" + str(count)
entry = self.counters_db.get_entry(THRESHOLD_BREACH_TABLE_PREFIX, key)
if entry:
self.counters_db.set_entry(THRESHOLD_BREACH_TABLE_PREFIX, key, None)
return

def main():

parser = argparse.ArgumentParser(description='Display the queue/pg threshold breaches',
version='1.0.0',
formatter_class=argparse.RawTextHelpFormatter,
epilog=""")
Examples:
thresholdbreach
thresholdbreach -c
thresholdbreach -cnt count
""")

parser.add_argument('-c', '--clear', action='store_true', help='Clear threshold breach entries')
parser.add_argument('-cnt', '--count', required=False, help='Display threshold breach entries as per count')
args = parser.parse_args()

thresholdbreach = Thresholdbreach()
count = 0

if args.clear:
if args.count:
count = args.count
thresholdbreach.clear_all_threshold_breach(count)
else:
if args.count:
count = args.count
thresholdbreach.get_print_all_threshold_breach(count)

sys.exit(0)

if __name__ == "__main__":
main()
Loading