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

[CLI][PFC] Add multi ASIC options for pfcstat and 'show pfc counters' #1057

Merged
merged 9 commits into from
Aug 27, 2020
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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think pfcstat -c should clear stats on all ports and all namespace and save all ports stats in the cached file.
If not, it might lead to confusing output.
For example. if user does the following sequence

  • pfcstat -c
    Since the internal ports stats are not cleared, they will not be reset to zero,
  • pfcstat -s all
    External ports stats will start from zero while the Internal ports will still have the old value. This might lead to confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's right, will change it. By default non-show commands should apply to all ports and namespaces, and should not have an option for 'namespace' or 'display'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at it further. It doesn't really clear the stats from counters DB. It updates that stats in "/tmp" and prints the diff from previous values. Since the script takes multiple arguments the 'namespace', 'display' also applies to '-c' arg. We can ignore '-c' option when 'namespace' is provided, but this will work as is as all the keys are different. Meaning, if a user runs '-c' with a namespace option and then runs -c with a different namespace option or no namespace, the command will output the 'diff' in counts for the cached ports, and prints as is for un-cached ports or new ports with counts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the prints the "Last cached time was " which might me misleading since some of the ports were not cached.

The change I'm making is to collect stats from all ports when '-c' option is provided. In short the 'namespace' option will be ignored silently when '-c' arg is specified. Comments?

Copy link
Contributor

@arlakshm arlakshm Aug 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine with this. I don't think we will be adding the multi asic options to sonic-clear commands. So the util script will not get the namespace or display, so we should be ok. I follow the similar approach for show interface counters

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use '-c' with a namespace and then use the display for another namespace, the problem we have is the cached time that we display will be incorrect because we aren't actually caching any of those ports info.
Either we ignore the namespace for '-c' option and get the stats for all ports and write them to the file or we need to maintain separate files for the namespaces

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore my comment. saw your change

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("")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just to add a 'line' between tx and rx outputs.


"""
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 @@ -495,11 +497,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