Skip to content

Commit

Permalink
[CLI][PFC] Add multi ASIC options for pfcstat and 'show pfc counters' (
Browse files Browse the repository at this point in the history
…#1057)

* Add multi ASIC options for pfcstat and 'show pfc counters'
            Options:
                        -d, --display [all|frontend]    Show internal interfaces  [default:frontend]
                        -n, --namespace [asic0|asic1|asic2|asic3|asic4|asic5]
* Added unit tests for 'pfcstat' show commands.
  • Loading branch information
smaheshm authored Aug 27, 2020
1 parent 58c2961 commit 62e44d9
Show file tree
Hide file tree
Showing 7 changed files with 455 additions and 68 deletions.
102 changes: 80 additions & 22 deletions scripts/pfcstat
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@

#####################################################################
#
# pfcstat is a tool for summarizing Priority-based Flow Control (PFC) statistics.
# pfcstat is a tool for summarizing Priority-based Flow Control (PFC) statistics.
#
#####################################################################

import swsssdk
import sys
import argparse
import cPickle as pickle
Expand All @@ -17,6 +16,24 @@ from collections import namedtuple, OrderedDict
from natsort import natsorted
from tabulate import tabulate

from sonic_py_common.multi_asic import get_external_ports
from utilities_common import multi_asic as multi_asic_util
from utilities_common import constants

# mock the redis for unit test purposes #
try:
if os.environ["UTILITIES_UNIT_TESTING"] == "2":
modules_path = os.path.join(os.path.dirname(__file__), "..")
tests_path = os.path.join(modules_path, "tests")
sys.path.insert(0, modules_path)
sys.path.insert(0, tests_path)
import mock_tables.dbconnector
if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic":
import mock_tables.mock_multi_asic
mock_tables.dbconnector.load_namespace_config()

except KeyError:
pass

PStats = namedtuple("PStats", "pfc0, pfc1, pfc2, pfc3, pfc4, pfc5, pfc6, pfc7")
header_Rx = ['Port Rx', 'PFC0', 'PFC1', 'PFC2', 'PFC3', 'PFC4', 'PFC5', 'PFC6', 'PFC7']
Expand Down Expand Up @@ -51,11 +68,14 @@ COUNTER_TABLE_PREFIX = "COUNTERS:"
COUNTERS_PORT_NAME_MAP = "COUNTERS_PORT_NAME_MAP"

class Pfcstat(object):
def __init__(self):
self.db = swsssdk.SonicV2Connector(host='127.0.0.1')
self.db.connect(self.db.COUNTERS_DB)

def get_cnstat(self, rx):
def __init__(self, namespace, display):
self.multi_asic = multi_asic_util.MultiAsic(display, namespace)
self.db = None
self.config_db = None
self.cnstat_dict = OrderedDict()

@multi_asic_util.run_on_multi_asic
def collect_cnstat(self, rx):
"""
Get the counters info from database.
"""
Expand All @@ -70,7 +90,9 @@ class Pfcstat(object):
bucket_dict = counter_bucket_tx_dict
for counter_name, pos in bucket_dict.iteritems():
full_table_id = COUNTER_TABLE_PREFIX + table_id
counter_data = self.db.get(self.db.COUNTERS_DB, full_table_id, counter_name)
counter_data = self.db.get(
self.db.COUNTERS_DB, full_table_id, counter_name
)
if counter_data is None:
fields[pos] = STATUS_NA
else:
Expand All @@ -79,15 +101,34 @@ class Pfcstat(object):
return cntr

# Get the info from database
counter_port_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_PORT_NAME_MAP)
counter_port_name_map = self.db.get_all(
self.db.COUNTERS_DB, COUNTERS_PORT_NAME_MAP
)
if counter_port_name_map is None:
return
display_ports_set = set(counter_port_name_map.keys())
if self.multi_asic.display_option == constants.DISPLAY_EXTERNAL:
display_ports_set = get_external_ports(
display_ports_set, self.multi_asic.current_namespace
)
# Build a dictionary of the stats
cnstat_dict = OrderedDict()
cnstat_dict['time'] = datetime.datetime.now()
if counter_port_name_map is None:
return cnstat_dict
for port in natsorted(counter_port_name_map):
cnstat_dict[port] = get_counters(counter_port_name_map[port])
return cnstat_dict
if counter_port_name_map is not None:
for port in natsorted(counter_port_name_map):
if port in display_ports_set:
cnstat_dict[port] = get_counters(
counter_port_name_map[port]
)
self.cnstat_dict.update(cnstat_dict)

def get_cnstat(self, rx):
"""
Get the counters info from database.
"""
self.cnstat_dict.clear()
self.collect_cnstat(rx)
return self.cnstat_dict

def cnstat_print(self, cnstat_dict, rx):
"""
Expand Down Expand Up @@ -163,10 +204,22 @@ Examples:
pfcstat
pfcstat -c
pfcstat -d
pfcstat -n asic1
pfcstat -s all -n asic0
""")

parser.add_argument('-c', '--clear', action='store_true', help='Clear previous stats and save new ones')
parser.add_argument('-d', '--delete', action='store_true', help='Delete saved stats')
parser.add_argument( '-c', '--clear', action='store_true',
help='Clear previous stats and save new ones'
)
parser.add_argument(
'-d', '--delete', action='store_true', help='Delete saved stats'
)
parser.add_argument('-s', '--show', default=constants.DISPLAY_EXTERNAL,
help='Display all interfaces or only external interfaces'
)
parser.add_argument('-n', '--namespace', default=None,
help='Display interfaces for specific namespace'
)
args = parser.parse_args()

save_fresh_stats = args.clear
Expand All @@ -175,15 +228,20 @@ Examples:
uid = str(os.getuid())
cnstat_file = uid

cnstat_dir = "/tmp/pfcstat-" + uid
cnstat_fqn_file_rx = cnstat_dir + "/" + cnstat_file + "rx"
cnstat_fqn_file_tx = cnstat_dir + "/" + cnstat_file + "tx"
cnstat_dir = os.path.join(os.sep, "tmp", "pfcstat-{}".format(uid))
cnstat_fqn_file_rx = os.path.join(cnstat_dir, "{}rx".format(cnstat_file))
cnstat_fqn_file_tx = os.path.join(cnstat_dir, "{}tx".format(cnstat_file))

# if '-c' option is provided get stats from all (frontend and backend) ports
if save_fresh_stats:
args.namespace = None
args.show = constants.DISPLAY_ALL

pfcstat = Pfcstat()
pfcstat = Pfcstat(args.namespace, args.show)

if delete_all_stats:
for file in os.listdir(cnstat_dir):
os.remove(cnstat_dir + "/" + file)
os.remove(os.path.join(cnstat_dir, file))

try:
os.rmdir(cnstat_dir)
Expand Down Expand Up @@ -235,7 +293,7 @@ Examples:
else:
pfcstat.cnstat_print(cnstat_dict_rx, True)

print()
print("")

"""
Print the counters of pfc tx counter
Expand Down
11 changes: 8 additions & 3 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
from swsssdk import ConfigDBConnector
from swsssdk import SonicV2Connector
from tabulate import tabulate
from utilities_common.db import Db

import utilities_common.cli as clicommon
from utilities_common.db import Db
from utilities_common.multi_asic import multi_asic_click_options

import mlnx
import feature
Expand Down Expand Up @@ -366,11 +368,14 @@ def pfc():

# 'counters' subcommand ("show interfaces pfccounters")
@pfc.command()
@multi_asic_click_options
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def counters(verbose):
def counters(namespace, display, verbose):
"""Show pfc counters"""

cmd = "pfcstat"
cmd = "pfcstat -s {}".format(display)
if namespace is not None:
cmd += " -n {}".format(namespace)

run_command(cmd, display_cmd=verbose)

Expand Down
85 changes: 78 additions & 7 deletions tests/mock_tables/asic0/counters_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,27 +123,98 @@
"SAI_PORT_STAT_IF_IN_ERRORS": "10",
"SAI_PORT_STAT_IF_IN_DISCARDS": "100",
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "80",
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "20"
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "20",
"SAI_PORT_STAT_PFC_0_RX_PKTS": "20",
"SAI_PORT_STAT_PFC_1_RX_PKTS": "21",
"SAI_PORT_STAT_PFC_2_RX_PKTS": "22",
"SAI_PORT_STAT_PFC_3_RX_PKTS": "23",
"SAI_PORT_STAT_PFC_4_RX_PKTS": "24",
"SAI_PORT_STAT_PFC_5_RX_PKTS": "25",
"SAI_PORT_STAT_PFC_6_RX_PKTS": "26",
"SAI_PORT_STAT_PFC_7_RX_PKTS": "27",
"SAI_PORT_STAT_PFC_0_TX_PKTS": "400",
"SAI_PORT_STAT_PFC_1_TX_PKTS": "201",
"SAI_PORT_STAT_PFC_2_TX_PKTS": "202",
"SAI_PORT_STAT_PFC_3_TX_PKTS": "203",
"SAI_PORT_STAT_PFC_4_TX_PKTS": "204",
"SAI_PORT_STAT_PFC_5_TX_PKTS": "205",
"SAI_PORT_STAT_PFC_6_TX_PKTS": "206",
"SAI_PORT_STAT_PFC_7_TX_PKTS": "207"
},
"COUNTERS:oid:0x1000000000004": {
"SAI_PORT_STAT_IF_IN_ERRORS": "0",
"SAI_PORT_STAT_IF_IN_DISCARDS": "1000",
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800",
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100"
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100",
"SAI_PORT_STAT_PFC_0_RX_PKTS": "40",
"SAI_PORT_STAT_PFC_1_RX_PKTS": "41",
"SAI_PORT_STAT_PFC_2_RX_PKTS": "42",
"SAI_PORT_STAT_PFC_3_RX_PKTS": "43",
"SAI_PORT_STAT_PFC_4_RX_PKTS": "44",
"SAI_PORT_STAT_PFC_5_RX_PKTS": "45",
"SAI_PORT_STAT_PFC_6_RX_PKTS": "46",
"SAI_PORT_STAT_PFC_7_RX_PKTS": "47",
"SAI_PORT_STAT_PFC_0_TX_PKTS": "400",
"SAI_PORT_STAT_PFC_1_TX_PKTS": "401",
"SAI_PORT_STAT_PFC_2_TX_PKTS": "402",
"SAI_PORT_STAT_PFC_3_TX_PKTS": "403",
"SAI_PORT_STAT_PFC_4_TX_PKTS": "404",
"SAI_PORT_STAT_PFC_5_TX_PKTS": "405",
"SAI_PORT_STAT_PFC_6_TX_PKTS": "406",
"SAI_PORT_STAT_PFC_7_TX_PKTS": "407"
},
"COUNTERS:oid:0x1000000000006": {
"SAI_PORT_STAT_IF_IN_ERRORS": "100",
"SAI_PORT_STAT_IF_IN_DISCARDS": "10",
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "10",
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "0"
"SAI_PORT_STAT_IF_IN_ERRORS": "0",
"SAI_PORT_STAT_IF_IN_DISCARDS": "1000",
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800",
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100",
"SAI_PORT_STAT_PFC_0_RX_PKTS": "60",
"SAI_PORT_STAT_PFC_1_RX_PKTS": "61",
"SAI_PORT_STAT_PFC_2_RX_PKTS": "62",
"SAI_PORT_STAT_PFC_3_RX_PKTS": "63",
"SAI_PORT_STAT_PFC_4_RX_PKTS": "64",
"SAI_PORT_STAT_PFC_5_RX_PKTS": "65",
"SAI_PORT_STAT_PFC_6_RX_PKTS": "66",
"SAI_PORT_STAT_PFC_7_RX_PKTS": "67",
"SAI_PORT_STAT_PFC_0_TX_PKTS": "600",
"SAI_PORT_STAT_PFC_1_TX_PKTS": "601",
"SAI_PORT_STAT_PFC_2_TX_PKTS": "602",
"SAI_PORT_STAT_PFC_3_TX_PKTS": "603",
"SAI_PORT_STAT_PFC_4_TX_PKTS": "604",
"SAI_PORT_STAT_PFC_5_TX_PKTS": "605",
"SAI_PORT_STAT_PFC_6_TX_PKTS": "606",
"SAI_PORT_STAT_PFC_7_TX_PKTS": "607"
},
"COUNTERS:oid:0x1000000000008": {
"SAI_PORT_STAT_IF_IN_ERRORS": "0",
"SAI_PORT_STAT_IF_IN_DISCARDS": "1000",
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800",
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100",
"SAI_PORT_STAT_PFC_0_RX_PKTS": "80",
"SAI_PORT_STAT_PFC_1_RX_PKTS": "81",
"SAI_PORT_STAT_PFC_2_RX_PKTS": "82",
"SAI_PORT_STAT_PFC_3_RX_PKTS": "83",
"SAI_PORT_STAT_PFC_4_RX_PKTS": "84",
"SAI_PORT_STAT_PFC_5_RX_PKTS": "85",
"SAI_PORT_STAT_PFC_6_RX_PKTS": "86",
"SAI_PORT_STAT_PFC_7_RX_PKTS": "87",
"SAI_PORT_STAT_PFC_0_TX_PKTS": "800",
"SAI_PORT_STAT_PFC_1_TX_PKTS": "801",
"SAI_PORT_STAT_PFC_2_TX_PKTS": "802",
"SAI_PORT_STAT_PFC_3_TX_PKTS": "803",
"SAI_PORT_STAT_PFC_4_TX_PKTS": "804",
"SAI_PORT_STAT_PFC_5_TX_PKTS": "805",
"SAI_PORT_STAT_PFC_6_TX_PKTS": "806",
"SAI_PORT_STAT_PFC_7_TX_PKTS": "807"
},
"COUNTERS:oid:0x21000000000000": {
"SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE": "1000"
},
"COUNTERS_PORT_NAME_MAP": {
"Ethernet0": "oid:0x1000000000002",
"Ethernet4": "oid:0x1000000000004",
"Ethernet8": "oid:0x1000000000006"
"Ethernet-BP0": "oid:0x1000000000006",
"Ethernet-BP4": "oid:0x1000000000008"
},
"COUNTERS_LAG_NAME_MAP": {
"PortChannel0001": "oid:0x60000000005a1",
Expand Down
54 changes: 51 additions & 3 deletions tests/mock_tables/counters_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,19 +123,67 @@
"SAI_PORT_STAT_IF_IN_ERRORS": "10",
"SAI_PORT_STAT_IF_IN_DISCARDS": "100",
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "80",
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "20"
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "20",
"SAI_PORT_STAT_PFC_0_RX_PKTS": "0",
"SAI_PORT_STAT_PFC_1_RX_PKTS": "0",
"SAI_PORT_STAT_PFC_2_RX_PKTS": "0",
"SAI_PORT_STAT_PFC_3_RX_PKTS": "0",
"SAI_PORT_STAT_PFC_4_RX_PKTS": "0",
"SAI_PORT_STAT_PFC_5_RX_PKTS": "0",
"SAI_PORT_STAT_PFC_6_RX_PKTS": "0",
"SAI_PORT_STAT_PFC_7_RX_PKTS": "0",
"SAI_PORT_STAT_PFC_0_TX_PKTS": "0",
"SAI_PORT_STAT_PFC_1_TX_PKTS": "0",
"SAI_PORT_STAT_PFC_2_TX_PKTS": "0",
"SAI_PORT_STAT_PFC_3_TX_PKTS": "0",
"SAI_PORT_STAT_PFC_4_TX_PKTS": "0",
"SAI_PORT_STAT_PFC_5_TX_PKTS": "0",
"SAI_PORT_STAT_PFC_6_TX_PKTS": "0",
"SAI_PORT_STAT_PFC_7_TX_PKTS": "0"
},
"COUNTERS:oid:0x1000000000004": {
"SAI_PORT_STAT_IF_IN_ERRORS": "0",
"SAI_PORT_STAT_IF_IN_DISCARDS": "1000",
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800",
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100"
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100",
"SAI_PORT_STAT_PFC_0_RX_PKTS": "40",
"SAI_PORT_STAT_PFC_1_RX_PKTS": "41",
"SAI_PORT_STAT_PFC_2_RX_PKTS": "42",
"SAI_PORT_STAT_PFC_3_RX_PKTS": "43",
"SAI_PORT_STAT_PFC_4_RX_PKTS": "44",
"SAI_PORT_STAT_PFC_5_RX_PKTS": "45",
"SAI_PORT_STAT_PFC_6_RX_PKTS": "46",
"SAI_PORT_STAT_PFC_7_RX_PKTS": "47",
"SAI_PORT_STAT_PFC_0_TX_PKTS": "400",
"SAI_PORT_STAT_PFC_1_TX_PKTS": "401",
"SAI_PORT_STAT_PFC_2_TX_PKTS": "402",
"SAI_PORT_STAT_PFC_3_TX_PKTS": "403",
"SAI_PORT_STAT_PFC_4_TX_PKTS": "404",
"SAI_PORT_STAT_PFC_5_TX_PKTS": "405",
"SAI_PORT_STAT_PFC_6_TX_PKTS": "406",
"SAI_PORT_STAT_PFC_7_TX_PKTS": "407"
},
"COUNTERS:oid:0x1000000000006": {
"SAI_PORT_STAT_IF_IN_ERRORS": "100",
"SAI_PORT_STAT_IF_IN_DISCARDS": "10",
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "10",
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "0"
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "0",
"SAI_PORT_STAT_PFC_0_RX_PKTS": "80",
"SAI_PORT_STAT_PFC_1_RX_PKTS": "81",
"SAI_PORT_STAT_PFC_2_RX_PKTS": "82",
"SAI_PORT_STAT_PFC_3_RX_PKTS": "83",
"SAI_PORT_STAT_PFC_4_RX_PKTS": "84",
"SAI_PORT_STAT_PFC_5_RX_PKTS": "85",
"SAI_PORT_STAT_PFC_6_RX_PKTS": "86",
"SAI_PORT_STAT_PFC_7_RX_PKTS": "87",
"SAI_PORT_STAT_PFC_0_TX_PKTS": "800",
"SAI_PORT_STAT_PFC_1_TX_PKTS": "801",
"SAI_PORT_STAT_PFC_2_TX_PKTS": "802",
"SAI_PORT_STAT_PFC_3_TX_PKTS": "803",
"SAI_PORT_STAT_PFC_4_TX_PKTS": "804",
"SAI_PORT_STAT_PFC_5_TX_PKTS": "805",
"SAI_PORT_STAT_PFC_6_TX_PKTS": "806",
"SAI_PORT_STAT_PFC_7_TX_PKTS": "807"
},
"COUNTERS:oid:0x21000000000000": {
"SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE": "1000"
Expand Down
Loading

0 comments on commit 62e44d9

Please sign in to comment.