Skip to content

Commit

Permalink
Merge pull request #18 from mssonicbld/sonicbld/202205-merge
Browse files Browse the repository at this point in the history
[code sync] Merge code from sonic-net/sonic-utilities:202205 to 202205
  • Loading branch information
mssonicbld authored Jul 14, 2023
2 parents ad65cf1 + e77f559 commit 5c7f8ca
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 26 deletions.
47 changes: 38 additions & 9 deletions scripts/portstat
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,14 @@ NStats = namedtuple("NStats", "rx_ok, rx_err, rx_drop, rx_ovr, tx_ok,\
rx_uca, rx_mca, rx_bca, rx_all,\
tx_64, tx_65_127, tx_128_255, tx_256_511, tx_512_1023, tx_1024_1518, tx_1519_2047, tx_2048_4095, tx_4096_9216, tx_9217_16383,\
tx_uca, tx_mca, tx_bca, tx_all,\
rx_jbr, rx_frag, rx_usize, rx_ovrrun")
rx_jbr, rx_frag, rx_usize, rx_ovrrun,\
fec_corr, fec_uncorr, fec_symbol_err")
header_all = ['IFACE', 'STATE', 'RX_OK', 'RX_BPS', 'RX_PPS', 'RX_UTIL', 'RX_ERR', 'RX_DRP', 'RX_OVR',
'TX_OK', 'TX_BPS', 'TX_PPS', 'TX_UTIL', 'TX_ERR', 'TX_DRP', 'TX_OVR']
header_std = ['IFACE', 'STATE', 'RX_OK', 'RX_BPS', 'RX_UTIL', 'RX_ERR', 'RX_DRP', 'RX_OVR',
'TX_OK', 'TX_BPS', 'TX_UTIL', 'TX_ERR', 'TX_DRP', 'TX_OVR']
header_errors_only = ['IFACE', 'STATE', 'RX_ERR', 'RX_DRP', 'RX_OVR', 'TX_ERR', 'TX_DRP', 'TX_OVR']
header_fec_only = ['IFACE', 'STATE', 'FEC_CORR', 'FEC_UNCORR', 'FEC_SYMBOL_ERR']
header_rates_only = ['IFACE', 'STATE', 'RX_OK', 'RX_BPS', 'RX_PPS', 'RX_UTIL', 'TX_OK', 'TX_BPS', 'TX_PPS', 'TX_UTIL']

rates_key_list = [ 'RX_BPS', 'RX_PPS', 'RX_UTIL', 'TX_BPS', 'TX_PPS', 'TX_UTIL' ]
Expand All @@ -67,7 +69,7 @@ RateStats = namedtuple("RateStats", ratestat_fields)
The order and count of statistics mentioned below needs to be in sync with the values in portstat script
So, any fields added/deleted in here should be reflected in portstat script also
"""
BUCKET_NUM = 42
BUCKET_NUM = 45
counter_bucket_dict = {
0:['SAI_PORT_STAT_IF_IN_UCAST_PKTS', 'SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS'],
1:['SAI_PORT_STAT_IF_IN_ERRORS'],
Expand Down Expand Up @@ -110,7 +112,10 @@ counter_bucket_dict = {
38:['SAI_PORT_STAT_ETHER_STATS_JABBERS'],
39:['SAI_PORT_STAT_ETHER_STATS_FRAGMENTS'],
40:['SAI_PORT_STAT_ETHER_STATS_UNDERSIZE_PKTS'],
41:['SAI_PORT_STAT_IP_IN_RECEIVES']
41:['SAI_PORT_STAT_IP_IN_RECEIVES'],
42:['SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES'],
43:['SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES'],
44:['SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS']
}

STATUS_NA = 'N/A'
Expand Down Expand Up @@ -249,7 +254,7 @@ class Portstat(object):
return STATUS_NA


def cnstat_print(self, cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail=False):
def cnstat_print(self, cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only, detail=False):
"""
Print the cnstat.
"""
Expand Down Expand Up @@ -294,6 +299,12 @@ class Portstat(object):
format_number_with_comma(data.tx_err),
format_number_with_comma(data.tx_drop),
format_number_with_comma(data.tx_ovr)))
elif fec_stats_only:
header = header_fec_only
table.append((key, self.get_port_state(key),
format_number_with_comma(data.fec_corr),
format_number_with_comma(data.fec_uncorr),
format_number_with_comma(data.fec_symbol_err)))
elif rates_only:
header = header_rates_only
table.append((key, self.get_port_state(key),
Expand Down Expand Up @@ -389,7 +400,10 @@ class Portstat(object):
print("Time Since Counters Last Cleared............... " + str(cnstat_old_dict.get('time')))


def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail=False):
def cnstat_diff_print(self, cnstat_new_dict, cnstat_old_dict,
ratestat_dict, intf_list, use_json,
print_all, errors_only, fec_stats_only,
rates_only, detail=False):
"""
Print the difference between two cnstat results.
"""
Expand Down Expand Up @@ -466,6 +480,19 @@ class Portstat(object):
format_number_with_comma(cntr.tx_err),
format_number_with_comma(cntr.tx_drop),
format_number_with_comma(cntr.tx_ovr)))
elif fec_stats_only:
header = header_fec_only
if old_cntr is not None:
table.append((key, self.get_port_state(key),
ns_diff(cntr.fec_corr, old_cntr.fec_corr),
ns_diff(cntr.fec_uncorr, old_cntr.fec_uncorr),
ns_diff(cntr.fec_symbol_err, old_cntr.fec_symbol_err)))
else:
table.append((key, self.get_port_state(key),
format_number_with_comma(cntr.fec_corr),
format_number_with_comma(cntr.fec_uncorr),
format_number_with_comma(cntr.fec_symbol_err)))

elif rates_only:
header = header_rates_only
if old_cntr is not None:
Expand Down Expand Up @@ -553,6 +580,7 @@ Examples:
parser.add_argument('-d', '--delete', action='store_true', help='Delete saved stats, either the uid or the specified tag')
parser.add_argument('-D', '--delete-all', action='store_true', help='Delete all saved stats')
parser.add_argument('-e', '--errors', action='store_true', help='Display interface errors')
parser.add_argument('-f', '--fec-stats', action='store_true', help='Display FEC related statistics')
parser.add_argument('-j', '--json', action='store_true', help='Display in JSON format')
parser.add_argument('-r', '--raw', action='store_true', help='Raw stats (unmodified output of netstat)')
parser.add_argument('-R', '--rate', action='store_true', help='Display interface rates')
Expand All @@ -569,6 +597,7 @@ Examples:
delete_saved_stats = args.delete
delete_all_stats = args.delete_all
errors_only = args.errors
fec_stats_only = args.fec_stats
rates_only = args.rate
use_json = args.json
raw_stats = args.raw
Expand Down Expand Up @@ -605,7 +634,7 @@ Examples:

# Now decide what information to display
if raw_stats:
portstat.cnstat_print(cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, rates_only)
portstat.cnstat_print(cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only)
sys.exit(0)

if save_fresh_stats:
Expand All @@ -624,21 +653,21 @@ Examples:
cnstat_cached_dict = pickle.load(open(cnstat_fqn_file, 'rb'))
if not detail:
print("Last cached time was " + str(cnstat_cached_dict.get('time')))
portstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail)
portstat.cnstat_diff_print(cnstat_dict, cnstat_cached_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only, detail)
except IOError as e:
print(e.errno, e)
else:
if tag_name:
print("\nFile '%s' does not exist" % cnstat_fqn_file)
print("Did you run 'portstat -c -t %s' to record the counters via tag %s?\n" % (tag_name, tag_name))
else:
portstat.cnstat_print(cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, rates_only, detail)
portstat.cnstat_print(cnstat_dict, ratestat_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only, detail)
else:
#wait for the specified time and then gather the new stats and output the difference.
time.sleep(wait_time_in_seconds)
print("The rates are calculated within %s seconds period" % wait_time_in_seconds)
cnstat_new_dict, ratestat_new_dict = portstat.get_cnstat_dict()
portstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, ratestat_new_dict, intf_list, use_json, print_all, errors_only, rates_only, detail)
portstat.cnstat_diff_print(cnstat_new_dict, cnstat_dict, ratestat_new_dict, intf_list, use_json, print_all, errors_only, fec_stats_only, rates_only, detail)

if __name__ == "__main__":
main()
58 changes: 56 additions & 2 deletions scripts/route_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,12 @@ def get_soc_ips(config_db):
mux_table = config_db.get_table('MUX_CABLE')
soc_ips = []
for _, mux_entry in mux_table.items():
if mux_entry.get("cable_type", "") == "active-active" and "soc_ipv4" in mux_entry:
soc_ips.append(mux_entry["soc_ipv4"])
if mux_entry.get("cable_type", "") == "active-active":
if "soc_ipv4" in mux_entry and mux_entry["soc_ipv4"]:
soc_ips.append(mux_entry["soc_ipv4"])

if "soc_ipv6" in mux_entry and mux_entry["soc_ipv6"]:
soc_ips.append(mux_entry["soc_ipv6"])

return soc_ips

Expand Down Expand Up @@ -530,6 +534,51 @@ def filter_out_soc_ip_routes(routes):
return updated_routes


def get_vlan_neighbors():
"""Return a list of VLAN neighbors."""
db = swsscommon.DBConnector(APPL_DB_NAME, 0)
print_message(syslog.LOG_DEBUG, "APPL DB connected for neighbors")
tbl = swsscommon.Table(db, 'NEIGH_TABLE')
neigh_entries = tbl.getKeys()

valid_neighs = []
for neigh_entry in neigh_entries:
if ':' in neigh_entry:
device, prefix = neigh_entry.split(':', 1)
if device.startswith("Vlan"):
valid_neighs.append(add_prefix_ifnot(prefix.lower()))

print_message(syslog.LOG_DEBUG, "Vlan neighbors:", json.dumps(valid_neighs, indent=4))
return valid_neighs


def filter_out_vlan_neigh_route_miss(rt_appl_miss, rt_asic_miss):
"""Ignore any route miss for vlan neighbor IPs."""

def _filter_out_neigh_route(routes, neighs):
updated_routes = []
ignored_routes = []
for route in routes:
if route in neighs:
ignored_routes.append(route)
else:
updated_routes.append(route)
return updated_routes, ignored_routes

config_db = swsscommon.ConfigDBConnector()
config_db.connect()

print_message(syslog.LOG_DEBUG, "Ignore vlan neighbor route miss")
if is_dualtor(config_db):
vlan_neighs = set(get_vlan_neighbors())
rt_appl_miss, ignored_rt_appl_miss = _filter_out_neigh_route(rt_appl_miss, vlan_neighs)
print_message(syslog.LOG_DEBUG, "Ignored appl route miss:", json.dumps(ignored_rt_appl_miss, indent=4))
rt_asic_miss, ignored_rt_asic_miss = _filter_out_neigh_route(rt_asic_miss, vlan_neighs)
print_message(syslog.LOG_DEBUG, "Ignored asic route miss:", json.dumps(ignored_rt_asic_miss, indent=4))

return rt_appl_miss, rt_asic_miss


def check_routes():
"""
The heart of this script which runs the checks.
Expand Down Expand Up @@ -578,6 +627,11 @@ def check_routes():
if rt_appl_miss:
rt_appl_miss = filter_out_voq_neigh_routes(rt_appl_miss)

# NOTE: On dualtor environment, ignore any route miss for the
# neighbors learned from the vlan subnet.
if rt_appl_miss or rt_asic_miss:
rt_appl_miss, rt_asic_miss = filter_out_vlan_neigh_route_miss(rt_appl_miss, rt_asic_miss)

if rt_appl_miss or rt_asic_miss:
# Look for subscribe updates for a second
adds, deletes = get_subscribe_updates(selector, subs)
Expand Down
33 changes: 25 additions & 8 deletions show/interfaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,15 +338,15 @@ def expected(db, interfacename):
@click.pass_context
def mpls(ctx, interfacename, namespace, display):
"""Show Interface MPLS status"""

#Edge case: Force show frontend interfaces on single asic
if not (multi_asic.is_multi_asic()):
if (display == 'frontend' or display == 'all' or display is None):
display = None
else:
print("Error: Invalid display option command for single asic")
return

display = "all" if interfacename else display
masic = multi_asic_util.MultiAsic(display_option=display, namespace_option=namespace)
ns_list = masic.get_ns_list_based_on_options()
Expand All @@ -372,13 +372,13 @@ def mpls(ctx, interfacename, namespace, display):
if (interfacename is not None):
if (interfacename != ifname):
continue

intf_found = True

if (display != "all"):
if ("Loopback" in ifname):
continue

if ifname.startswith("Ethernet") and multi_asic.is_port_internal(ifname, ns):
continue

Expand All @@ -391,11 +391,11 @@ def mpls(ctx, interfacename, namespace, display):
if 'mpls' not in mpls_intf or mpls_intf['mpls'] == 'disable':
intfs_data.update({ifname: 'disable'})
else:
intfs_data.update({ifname: mpls_intf['mpls']})
intfs_data.update({ifname: mpls_intf['mpls']})

# Check if interface is valid
if (interfacename is not None and not intf_found):
ctx.fail('interface {} doesn`t exist'.format(interfacename))
ctx.fail('interface {} doesn`t exist'.format(interfacename))

header = ['Interface', 'MPLS State']
body = []
Expand Down Expand Up @@ -603,6 +603,23 @@ def errors(verbose, period, namespace, display):

clicommon.run_command(cmd, display_cmd=verbose)

# 'fec-stats' subcommand ("show interfaces counters errors")
@counters.command('fec-stats')
@click.option('-p', '--period')
@multi_asic_util.multi_asic_click_options
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def fec_stats(verbose, period, namespace, display):
"""Show interface counters fec-stats"""
cmd = "portstat -f"
if period is not None:
cmd += " -p {}".format(period)

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

clicommon.run_command(cmd, display_cmd=verbose)

# 'rates' subcommand ("show interfaces counters rates")
@counters.command()
@click.option('-p', '--period')
Expand Down
2 changes: 1 addition & 1 deletion show/muxcable.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ def get_tunnel_route_per_port(db, port_tunnel_route, per_npu_configdb, per_npu_a

mux_cfg_dict = per_npu_configdb[asic_id].get_all(
per_npu_configdb[asic_id].CONFIG_DB, 'MUX_CABLE|{}'.format(port))
dest_names = ["server_ipv4", "server_ipv6", "soc_ipv4"]
dest_names = ["server_ipv4", "server_ipv6", "soc_ipv4", "soc_ipv6"]

for name in dest_names:
dest_address = mux_cfg_dict.get(name, None)
Expand Down
6 changes: 5 additions & 1 deletion tests/mock_tables/asic_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@
"ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.2.1.1\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x300000000007c\"}": {
"SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION": "SAI_PACKET_ACTION_FORWARD",
"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": "oid:0x40000000015d8"
}
},
"ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"e801::47\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x300000000007c\"}": {
"SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION": "SAI_PACKET_ACTION_FORWARD",
"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID": "oid:0x40000000015d8"
}
}
3 changes: 2 additions & 1 deletion tests/mock_tables/config_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -1808,7 +1808,8 @@
"MUX_CABLE|Ethernet4": {
"state": "auto",
"server_ipv4": "10.3.1.1",
"server_ipv6": "e801::46"
"server_ipv6": "e801::46",
"soc_ipv6": "e801::47"
},
"MUX_CABLE|Ethernet8": {
"state": "active",
Expand Down
15 changes: 12 additions & 3 deletions tests/mock_tables/counters_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,10 @@
"SAI_PORT_STAT_ETHER_OUT_PKTS_9217_TO_16383_OCTETS": "0",
"SAI_PORT_STAT_ETHER_STATS_FRAGMENTS": "0",
"SAI_PORT_STAT_ETHER_STATS_UNDERSIZE_PKTS": "0",
"SAI_PORT_STAT_ETHER_STATS_JABBERS": "0"
"SAI_PORT_STAT_ETHER_STATS_JABBERS": "0",
"SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "130402",
"SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "3",
"SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "4"
},
"COUNTERS:oid:0x1000000000013": {
"SAI_PORT_STAT_IF_IN_UCAST_PKTS": "4",
Expand Down Expand Up @@ -912,7 +915,10 @@
"SAI_PORT_STAT_ETHER_OUT_PKTS_9217_TO_16383_OCTETS": "0",
"SAI_PORT_STAT_ETHER_STATS_FRAGMENTS": "0",
"SAI_PORT_STAT_ETHER_STATS_UNDERSIZE_PKTS": "0",
"SAI_PORT_STAT_ETHER_STATS_JABBERS": "0"
"SAI_PORT_STAT_ETHER_STATS_JABBERS": "0",
"SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "110412",
"SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "1",
"SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0"
},
"COUNTERS:oid:0x1000000000014": {
"SAI_PORT_STAT_IF_IN_UCAST_PKTS": "6",
Expand Down Expand Up @@ -969,7 +975,10 @@
"SAI_PORT_STAT_ETHER_OUT_PKTS_9217_TO_16383_OCTETS": "0",
"SAI_PORT_STAT_ETHER_STATS_FRAGMENTS": "0",
"SAI_PORT_STAT_ETHER_STATS_UNDERSIZE_PKTS": "0",
"SAI_PORT_STAT_ETHER_STATS_JABBERS": "0"
"SAI_PORT_STAT_ETHER_STATS_JABBERS": "0",
"SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES": "100317",
"SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES": "0",
"SAI_PORT_STAT_IF_IN_FEC_SYMBOL_ERRORS": "0"
},
"COUNTERS:oid:0x21000000000000": {
"SAI_SWITCH_STAT_OUT_DROP_REASON_RANGE_BASE": "1000",
Expand Down
6 changes: 6 additions & 0 deletions tests/muxcable_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,11 @@
"DEST": "10.3.1.1",
"kernel": 1,
"asic": false
},
"soc_ipv6": {
"DEST": "e801::47",
"kernel": false,
"asic": 1
}
}
}
Expand All @@ -591,6 +596,7 @@
--------- ----------- -------------- -------- ------
Ethernet0 server_ipv4 10.2.1.1 added added
Ethernet4 server_ipv4 10.3.1.1 added -
Ethernet4 soc_ipv6 e801::47 - added
"""

show_muxcable_tunnel_route_expected_output_port_json="""\
Expand Down
Loading

0 comments on commit 5c7f8ca

Please sign in to comment.