Skip to content

Commit ba60bc6

Browse files
amitpawar12hdwhdw
authored andcommitted
[Snappi] Support for DUT statistics - Interface counters, PFC counters, and Queue counters. (sonic-net#13848)
Description of PR Support to pull the DUT statistics, namely interface counters, PFC counters and Queue counters. This support will enable users to pull the DUT statistics run-time and capture them in form of dictionary for further processing. Summary: Fixes # (issue) sonic-net#13843 Approach What is the motivation for this PR? Currently, there is no one stop-place to fetch the DUT statistics and use them for verification, especially the SNAPPI testcases. There should be some way to pull the DUT statistics ( at least important ones) and use them for verification. How did you do it? Clear counters: Common function to clear interface, PFC and queue counter stats. Interface counters: Ability to fetch the interface counters for a given DUT and port. Returns dictionary with keys - Rx and Tx packet count, Rx and Tx failures (Error + drops + ovr), and Rx and Tx throughput in Mbps. PFC counters: Ability to fetch the PFC counters for a given DUT and port. Returns dictionary with keys - Rx and Tx PFC for the given DUT, port and priority. Queue counters: Ability to fetch the Queue counters for a given DUT and port. Internally calls get_egress_queue_count for all the priorities. Returns dictionary with as key with transmitted packets as counter. How did you verify/test it? These functions are called as part of new testcases for PFC-ECN. for dut, port in dutport_list: f_stats = update_dict(m, f_stats, interface_stats(dut, port)) f_stats = update_dict(m, f_stats, get_pfc_count(dut, port)) f_stats = update_dict(m, f_stats, get_queue_count(dut, port)) These are then used to create CSV with raw DUT statistics and then to summarize the test in the end. co-authorized by: [email protected]
1 parent 2456a39 commit ba60bc6

1 file changed

Lines changed: 134 additions & 7 deletions

File tree

tests/common/snappi_tests/common_helpers.py

Lines changed: 134 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from tests.common.mellanox_data import is_mellanox_device as isMellanoxDevice
1919
from ipaddress import IPv6Network, IPv6Address
2020
from random import getrandbits
21+
from tests.common.portstat_utilities import parse_portstat
22+
from collections import defaultdict
2123

2224

2325
def increment_ip_address(ip, incr=1):
@@ -959,14 +961,22 @@ def get_egress_queue_count(duthost, port, priority):
959961
Returns:
960962
tuple (int, int): total count of packets and bytes in the queue
961963
"""
962-
raw_out = duthost.shell("show queue counters {} | sed -n '/UC{}/p'".format(port, priority))['stdout']
963-
total_pkts = raw_out.split()[2] if 2 < len(raw_out.split()) else "0"
964-
if total_pkts == "N/A":
965-
total_pkts = "0"
964+
# If DUT is multi-asic, asic will be used.
965+
if duthost.is_multi_asic:
966+
asic = duthost.get_port_asic_instance(port).get_asic_namespace()
967+
raw_out = duthost.shell("sudo ip netns exec {} show queue counters {} | sed -n '/UC{}/p'".
968+
format(asic, port, priority))['stdout']
969+
total_pkts = "0" if raw_out.split()[2] == "N/A" else raw_out.split()[2]
970+
total_bytes = "0" if raw_out.split()[3] == "N/A" else raw_out.split()[3]
971+
else:
972+
raw_out = duthost.shell("show queue counters {} | sed -n '/UC{}/p'".format(port, priority))['stdout']
973+
total_pkts = raw_out.split()[2] if 2 < len(raw_out.split()) else "0"
974+
if total_pkts == "N/A":
975+
total_pkts = "0"
966976

967-
total_bytes = raw_out.split()[3] if 3 < len(raw_out.split()) else "0"
968-
if total_bytes == "N/A":
969-
total_bytes = "0"
977+
total_bytes = raw_out.split()[3] if 3 < len(raw_out.split()) else "0"
978+
if total_bytes == "N/A":
979+
total_bytes = "0"
970980

971981
return int(total_pkts.replace(',', '')), int(total_bytes.replace(',', ''))
972982

@@ -1061,3 +1071,120 @@ def start_pfcwd_fwd(duthost, asic_value=None):
10611071
stop_pfcwd(duthost, asic_value)
10621072
duthost.shell('sudo ip netns exec {} pfcwd start --action forward 200 --restoration-time 200'.
10631073
format(asic_value))
1074+
1075+
1076+
def clear_counters(duthost, port):
1077+
"""
1078+
Clear PFC, Queuecounters, Drop and generic counters from SONiC CLI.
1079+
Args:
1080+
duthost (Ansible host instance): Device under test
1081+
port (str): port name
1082+
Returns:
1083+
None
1084+
"""
1085+
1086+
duthost.shell("sudo sonic-clear counters \n")
1087+
duthost.shell("sudo sonic-clear pfccounters \n")
1088+
duthost.shell("sudo sonic-clear priority-group drop counters \n")
1089+
duthost.shell("sonic-clear counters \n")
1090+
duthost.shell("sonic-clear pfccounters \n")
1091+
1092+
if (duthost.is_multi_asic):
1093+
asic = duthost.get_port_asic_instance(port).get_asic_namespace()
1094+
duthost.shell("sudo ip netns exec {} sonic-clear queuecounters \n".format(asic))
1095+
duthost.shell("sudo ip netns exec {} sonic-clear dropcounters \n".format(asic))
1096+
else:
1097+
duthost.shell("sonic-clear queuecounters \n")
1098+
duthost.shell("sonic-clear dropcounters \n")
1099+
1100+
1101+
def get_interface_stats(duthost, port):
1102+
"""
1103+
Get the Rx and Tx port failures, throughput and pkts from SONiC CLI.
1104+
This is the equivalent of the "show interface counters" command.
1105+
Args:
1106+
duthost (Ansible host instance): device under test
1107+
port (str): port name
1108+
Returns:
1109+
i_stats (dict): Returns various parameters for given DUT and port.
1110+
"""
1111+
# Initializing nested dictionary i_stats
1112+
i_stats = defaultdict(dict)
1113+
i_stats[duthost.hostname][port] = {}
1114+
1115+
n_out = parse_portstat(duthost.command('portstat -i {}'.format(port))['stdout_lines'])[port]
1116+
# rx_err, rx_ovr and rx_drp are counted in single counter rx_fail
1117+
# tx_err, tx_ovr and tx_drp are counted in single counter tx_fail
1118+
rx_err = ['rx_err', 'rx_ovr', 'rx_drp']
1119+
tx_err = ['tx_err', 'tx_ovr', 'tx_drp']
1120+
rx_fail = 0
1121+
tx_fail = 0
1122+
for m in rx_err:
1123+
rx_fail = rx_fail + int(n_out[m].replace(',', ''))
1124+
for m in tx_err:
1125+
tx_fail = tx_fail + int(n_out[m].replace(',', ''))
1126+
1127+
# Any throughput below 1MBps is measured as 0 for simplicity.
1128+
thrput = n_out['rx_bps']
1129+
if thrput.split(' ')[1] == 'MB/s' and (thrput.split(' ')[0]) != '0.00':
1130+
i_stats[duthost.hostname][port]['rx_thrput_Mbps'] = float(thrput.split(' ')[0]) * 8
1131+
else:
1132+
i_stats[duthost.hostname][port]['rx_thrput_Mbps'] = 0
1133+
thrput = n_out['tx_bps']
1134+
if thrput.split(' ')[1] == 'MB/s' and (thrput.split(' ')[0]) != '0.00':
1135+
i_stats[duthost.hostname][port]['tx_thrput_Mbps'] = float(thrput.split(' ')[0]) * 8
1136+
else:
1137+
i_stats[duthost.hostname][port]['rx_thrput_Mbps'] = 0
1138+
1139+
i_stats[duthost.hostname][port]['rx_pkts'] = int(n_out['rx_ok'].replace(',', ''))
1140+
i_stats[duthost.hostname][port]['tx_pkts'] = int(n_out['tx_ok'].replace(',', ''))
1141+
i_stats[duthost.hostname][port]['rx_fail'] = rx_fail
1142+
i_stats[duthost.hostname][port]['tx_fail'] = tx_fail
1143+
1144+
return i_stats
1145+
1146+
1147+
def get_queue_count_all_prio(duthost, port):
1148+
"""
1149+
Get the egress queue count in packets and bytes for a given port and priority from SONiC CLI.
1150+
This is the equivalent of the "show queue counters" command.
1151+
Args:
1152+
duthost (Ansible host instance): device under test
1153+
port (str): port name
1154+
Returns:
1155+
queue_dict (dict): key-value with key=dut+port+prio and value=queue count
1156+
"""
1157+
# Initializing nested dictionary queue_dict
1158+
queue_dict = defaultdict(dict)
1159+
queue_dict[duthost.hostname][port] = {}
1160+
1161+
# Preparing the dictionary for all 7 priority queues.
1162+
for priority in range(7):
1163+
total_pkts, _ = get_egress_queue_count(duthost, port, priority)
1164+
queue_dict[duthost.hostname][port]['prio_' + str(priority)] = total_pkts
1165+
1166+
return queue_dict
1167+
1168+
1169+
def get_pfc_count(duthost, port):
1170+
"""
1171+
Get the PFC frame count for a given port from SONiC CLI
1172+
Args:
1173+
duthost (Ansible host instance): device under test
1174+
port (str): port name
1175+
Returns:
1176+
pfc_dict (dict) : Returns Rx and Tx PFC for the given DUT and interface.
1177+
"""
1178+
pfc_dict = defaultdict(dict)
1179+
pfc_dict[duthost.hostname][port] = {}
1180+
raw_out = duthost.shell("show pfc counters | sed -n '/Port Tx/,/^$/p' | grep '{} '".format(port))['stdout']
1181+
pause_frame_count = raw_out.split()
1182+
for m in range(1, len(pause_frame_count)):
1183+
pfc_dict[duthost.hostname][port]['tx_pfc_'+str(m-1)] = int(pause_frame_count[m].replace(',', ''))
1184+
1185+
raw_out = duthost.shell("show pfc counters | sed -n '/Port Rx/,/^$/p' | grep '{} '".format(port))['stdout']
1186+
pause_frame_count = raw_out.split()
1187+
for m in range(1, len(pause_frame_count)):
1188+
pfc_dict[duthost.hostname][port]['rx_pfc_'+str(m-1)] = int(pause_frame_count[m].replace(',', ''))
1189+
1190+
return pfc_dict

0 commit comments

Comments
 (0)