Skip to content
Merged
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
91 changes: 82 additions & 9 deletions scripts/wredstat
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class WredstatWrapper(object):
self.db = None

@multi_asic_util.run_on_multi_asic
def run(self, save_fresh_stats, port_to_show_stats, json_opt, non_zero):
def run(self, save_fresh_stats, port_to_show_stats, json_opt, non_zero, summary):
wredstat = Wredstat(self.multi_asic.current_namespace, self.db, self.voq)
if save_fresh_stats:
wredstat.save_fresh_stats()
Expand All @@ -108,7 +108,7 @@ class WredstatWrapper(object):
if port_to_show_stats!=None:
wredstat.get_print_port_stat(port_to_show_stats, json_opt, non_zero)
else:
wredstat.get_print_all_stat(json_opt, non_zero)
wredstat.get_print_all_stat(json_opt, non_zero, summary)


class Wredstat(object):
Expand Down Expand Up @@ -293,7 +293,62 @@ class Wredstat(object):
print(tabulate(table, hdr, tablefmt='simple', stralign='right'))
print()

def get_print_all_stat(self, json_opt, non_zero):
def _to_int(self, val):
if val is None:
return 0
s = str(val).strip()
if s == "" or s.upper() == "N/A":
return 0
try:
return int(s)
except (TypeError, ValueError):
return 0


def aggregate_from_json_output(self, json_output):
"""
json_output: { port: { ... queue_key: {queueindex, ... counters ...}, ... }, ... }

Returns:
{ queueindex: {queueindex, queuetype, wredDrppacket, wredDrpbytes, ecnpacket, ecnbytes}, ... }
"""
agg = {}

for port, port_blob in (json_output or {}).items():
if not isinstance(port_blob, dict):
continue

# Some implementations nest under a key like "cnstat" or similar.
# We'll aggregate from:
# - port_blob directly
# - and if present, one level of nested dicts
candidate_dicts = [port_blob]
for _, maybe_nested in port_blob.items():
if isinstance(maybe_nested, dict):
candidate_dicts.append(maybe_nested)

for d in candidate_dicts:
for key, data in d.items():
if not isinstance(data, dict):
continue
if key == 'time':
continue

agg.setdefault(key, {
"wredDrppacket": 0,
"wredDrpbytes": 0,
"ecnpacket": 0,
"ecnbytes": 0,
})

agg[key]["wredDrppacket"] += self._to_int(data.get("wreddroppacket"))
agg[key]["wredDrpbytes"] += self._to_int(data.get("wreddropbytes"))
agg[key]["ecnpacket"] += self._to_int(data.get("ecnmarkedpacket"))
agg[key]["ecnbytes"] += self._to_int(data.get("ecnmarkedbytes"))

return agg

def get_print_all_stat(self, json_opt, non_zero, summary):
"""
Get stat for each port
If JSON option is True, collect data for each port and
Expand All @@ -308,23 +363,39 @@ class Wredstat(object):
if os.path.isfile(cnstat_fqn_file_name):
try:
cnstat_cached_dict = json.load(open(cnstat_fqn_file_name, 'r'))
if json_opt:
if json_opt or summary:
json_output[port].update({"cached_time":cnstat_cached_dict.get('time')})
json_output.update(self.cnstat_diff_print(port, cnstat_dict, cnstat_cached_dict, json_opt, non_zero))
json_output.update(self.cnstat_diff_print(port, cnstat_dict, cnstat_cached_dict, True, non_zero))
else:
print(port + " Last cached time was " + str(cnstat_cached_dict.get('time')))
self.cnstat_diff_print(port, cnstat_dict, cnstat_cached_dict, json_opt, non_zero)
except IOError as e:
print(e.errno, e)
else:
if json_opt:
json_output.update(self.cnstat_print(port, cnstat_dict, json_opt, non_zero))
if json_opt or summary:
json_output.update(self.cnstat_print(port, cnstat_dict, True, non_zero))
else:
self.cnstat_print(port, cnstat_dict, json_opt, non_zero)

if json_opt:
if json_opt and not summary:
print(json_dump(json_output))

if summary:
agg = self.aggregate_from_json_output(json_output)
if json_opt:
print(json_dump(agg))
else:
table = []
for key, data in agg.items():
table.append((key,
data['wredDrppacket'],
data['wredDrpbytes'],
data['ecnpacket'],
data['ecnbytes']))
hdr = voq_header[1:] if self.voq else header[1:]
print(tabulate(table, hdr, tablefmt='simple', stralign='right'))
print()

def get_print_port_stat(self, port, json_opt, non_zero):
"""
Get stat for the port
Expand Down Expand Up @@ -393,13 +464,15 @@ Examples:
parser.add_argument('-V', '--voq', action='store_true', help='display voq stats')
parser.add_argument('-nz', '--non_zero', action='store_true', help='display non-zero wred queue stats')
parser.add_argument('-n', '--namespace', default=None, help='Display queue counters for specific namespace')
parser.add_argument('-s', '--summary', action='store_true', help='Print summary in JSON format')
args = parser.parse_args()

save_fresh_stats = args.clear
delete_stats = args.delete
voq = args.voq
json_opt = args.json_opt
namespace = args.namespace
summary = args.summary
non_zero = args.non_zero

port_to_show_stats = args.port
Expand All @@ -413,7 +486,7 @@ Examples:
cache.remove()

wredstat_wrapper = WredstatWrapper(namespace, voq)
wredstat_wrapper.run(save_fresh_stats, port_to_show_stats, json_opt, non_zero)
wredstat_wrapper.run(save_fresh_stats, port_to_show_stats, json_opt, non_zero, summary)

sys.exit(0)

Expand Down
6 changes: 5 additions & 1 deletion show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,8 @@ def counters(interfacename, namespace, display, all, trim, voq, nonzero, json, v
@click.option('--json', is_flag=True, help="JSON output")
@click.option('--voq', is_flag=True, help="VOQ counters")
@click.option('-nz', '--nonzero', is_flag=True, help="Non Zero Counters")
def wredcounters(interfacename, namespace, display, verbose, json, voq, nonzero):
@click.option('--summary', is_flag=True, help="Summary counters")
def wredcounters(interfacename, namespace, display, verbose, json, voq, nonzero, summary):
"""Show queue wredcounters"""

cmd = ["wredstat"]
Expand All @@ -836,6 +837,9 @@ def wredcounters(interfacename, namespace, display, verbose, json, voq, nonzero)
if nonzero:
cmd += ["-nz"]

if summary:
cmd += ["-s"]

run_command(cmd, display_cmd=verbose)

#
Expand Down
Loading
Loading