Skip to content

Commit

Permalink
[portstat]: Combine ADMIN and OPER fields (sonic-net#130)
Browse files Browse the repository at this point in the history
- Move back to one column of port state to be compatible with old parsers
- The current state field has four choices: U, D, X, and N/A.

  U means the port is admin + oper status UP
  D means the port is admin UP but oper DOWN
  X means the port is admin DOWN and disabled
  N/A for the rest abnormal scenarios

- Refactor the code

Signed-off-by: Shu0T1an ChenG <shuche@microsoft.com>
  • Loading branch information
Shuotian Cheng authored Oct 17, 2017
1 parent 6103ce8 commit 9913106
Showing 1 changed file with 60 additions and 77 deletions.
137 changes: 60 additions & 77 deletions scripts/portstat
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ PORT_RATE = 40

NStats = namedtuple("NStats", "rx_ok, rx_err, rx_drop, rx_ovr, tx_ok,\
tx_err, tx_drop, tx_ovr, rx_byt, tx_byt")
header_all = ['Iface', 'ADMIN', 'OPER', 'RX_OK', 'RX_BPS', 'RX_PPS', 'RX_UTIL', 'RX_ERR', 'RX_DRP', 'RX_OVR',
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 = ['Iface', 'ADMIN', 'OPER', 'RX_OK', 'RX_BPS', 'RX_UTIL', 'RX_ERR', 'RX_DRP', 'RX_OVR',
header = ['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']

counter_bucket_dict = {
Expand All @@ -48,11 +48,20 @@ counter_bucket_dict = {
'SAI_PORT_STAT_IF_OUT_OCTETS': 9
}

STATUS_NA = 'N/A'

COUNTER_TABLE_PREFIX = "COUNTERS:"
COUNTERS_PORT_NAME_MAP = "COUNTERS_PORT_NAME_MAP"

PORT_STATUS_TABLE_PREFIX = "PORT_TABLE:"
PORT_OPER_STATUS_FIELD = "oper_status"
PORT_ADMIN_STATUS_FIELD = "admin_status"
PORT_STATUS_VALUE_UP = 'UP'
PORT_STATUS_VALUE_DOWN = 'DOWN'

PORT_STATE_UP = 'U'
PROT_STATE_DOWN = 'D'
PORT_STATE_DISABLED = 'X'

class Portstat(object):
def __init__(self):
Expand All @@ -73,8 +82,8 @@ class Portstat(object):
full_table_id = COUNTER_TABLE_PREFIX + table_id
counter_data = self.db.get(self.db.COUNTERS_DB, full_table_id, counter_name)
if counter_data is None:
fields[pos] = "N/A"
elif fields[pos] != "N/A":
fields[pos] = STATUS_NA
elif fields[pos] != STATUS_NA:
fields[pos] = str(int(fields[pos]) + int(counter_data))
cntr = NStats._make(fields)
return cntr
Expand All @@ -90,67 +99,40 @@ class Portstat(object):
cnstat_dict[port] = get_counters(counter_port_name_map[port])
return cnstat_dict

def get_port_status(self, port_name, status_type):
def get_port_state(self, port_name):
"""
Get the port status
Get the port state
"""
full_table_id = PORT_STATUS_TABLE_PREFIX + port_name
status = self.db.get(self.db.APPL_DB, full_table_id, status_type)
if status is None:
return "N/A"
admin_state = self.db.get(self.db.APPL_DB, full_table_id, PORT_ADMIN_STATUS_FIELD)
oper_state = self.db.get(self.db.APPL_DB, full_table_id, PORT_OPER_STATUS_FIELD)
if admin_state is None or oper_state is None:
return STATUS_NA
elif admin_state.upper() == PORT_STATUS_VALUE_DOWN:
return PORT_STATE_DISABLED
elif admin_state.upper() == PORT_STATUS_VALUE_UP and oper_state.upper() == PORT_STATUS_VALUE_UP:
return PORT_STATE_UP
elif admin_state.upper() == PORT_STATUS_VALUE_UP and oper_state.upper() == PORT_STATUS_VALUE_DOWN:
return PORT_STATE_DOWN
else:
return status
return STATUS_NA

def table_as_json(self, table, print_all):
"""
Print table as json format.
"""
output = {}

# Build a dictionary where the if_name is the key and the value is
# a dictionary that holds MTU, TX_DRP, etc
if print_all:
for line in table:
if_name = line[0]

# Build a dictionary where the if_name is the key and the value is
# a dictionary that holds MTU, TX_DRP, etc
output[if_name] = {
header_all[1] : line[1],
header_all[2] : line[2],
header_all[3] : line[3],
header_all[4] : line[4],
header_all[5] : line[5],
header_all[6] : line[6],
header_all[7] : line[7],
header_all[8] : line[8],
header_all[9] : line[9],
header_all[10] : line[10],
header_all[11] : line[11],
header_all[12] : line[12],
header_all[13] : line[13],
header_all[14] : line[14],
header_all[15] : line[15]
}
output[if_name] = {header_all[i]: line[i] for i in range(1, len(header_all))}
else:
for line in table:
if_name = line[0]

# Build a dictionary where the if_name is the key and the value is
# a dictionary that holds MTU, TX_DRP, etc
output[if_name] = {
header[1] : line[1],
header[2] : line[2],
header[3] : line[3],
header[4] : line[4],
header[5] : line[5],
header[6] : line[6],
header[7] : line[7],
header[8] : line[8],
header[9] : line[9],
header[10] : line[10],
header[11] : line[11],
header[12] : line[12],
header[13] : line[13]
}
output[if_name] = {header[i]: line[i] for i in range(1, len(header))}

return json.dumps(output, indent=4, sort_keys=True)

Expand All @@ -165,16 +147,16 @@ class Portstat(object):
continue

if print_all:
table.append((key, self.get_port_status(key, PORT_ADMIN_STATUS_FIELD), self.get_port_status(key, PORT_OPER_STATUS_FIELD),
data.rx_ok, "N/A", "N/A", "N/A", data.rx_err,
table.append((key, self.get_port_state(key),
data.rx_ok, STATUS_NA, STATUS_NA, STATUS_NA, data.rx_err,
data.rx_drop, data.rx_ovr,
data.tx_ok, "N/A", "N/A", "N/A", data.tx_err,
data.tx_ok, STATUS_NA, STATUS_NA, STATUS_NA, data.tx_err,
data.tx_drop, data.tx_ovr))
else:
table.append((key, self.get_port_status(key, PORT_ADMIN_STATUS_FIELD), self.get_port_status(key, PORT_OPER_STATUS_FIELD),
data.rx_ok, "N/A", "N/A", data.rx_err,
table.append((key, self.get_port_state(key),
data.rx_ok, STATUS_NA, STATUS_NA, data.rx_err,
data.rx_drop, data.rx_ovr,
data.tx_ok, "N/A", "N/A", data.tx_err,
data.tx_ok, STATUS_NA, STATUS_NA, data.tx_err,
data.tx_drop, data.tx_ovr))


Expand All @@ -195,8 +177,8 @@ class Portstat(object):
"""
Calculate the diff.
"""
if newstr == "N/A" or oldstr == "N/A":
return "N/A"
if newstr == STATUS_NA or oldstr == STATUS_NA:
return STATUS_NA
else:
new, old = int(newstr), int(oldstr)
return '{:,}'.format(new - old)
Expand All @@ -205,8 +187,8 @@ class Portstat(object):
"""
Calculate the byte rate.
"""
if newstr == "N/A" or oldstr == "N/A":
return "N/A"
if newstr == STATUS_NA or oldstr == STATUS_NA:
return STATUS_NA
else:
rate = int(ns_diff(newstr, oldstr).replace(',',''))/delta
if rate > 1024*1024*10:
Expand All @@ -221,8 +203,8 @@ class Portstat(object):
"""
Calculate the packet rate.
"""
if newstr == "N/A" or oldstr == "N/A":
return "N/A"
if newstr == STATUS_NA or oldstr == STATUS_NA:
return STATUS_NA
else:
rate = int(ns_diff(newstr, oldstr).replace(',',''))/delta
return "{:.2f}".format(rate)+'/s'
Expand All @@ -231,8 +213,8 @@ class Portstat(object):
"""
Calculate the util.
"""
if newstr == "N/A" or oldstr == "N/A":
return "N/A"
if newstr == STATUS_NA or oldstr == STATUS_NA:
return STATUS_NA
else:
rate = int(ns_diff(newstr, oldstr).replace(',',''))/delta
util = rate/(PORT_RATE*1024*1024*1024/8.0)*100
Expand All @@ -251,7 +233,7 @@ class Portstat(object):

if print_all:
if old_cntr is not None:
table.append((key, self.get_port_status(key, PORT_ADMIN_STATUS_FIELD), self.get_port_status(key, PORT_OPER_STATUS_FIELD),
table.append((key, self.get_port_state(key),
ns_diff(cntr.rx_ok, old_cntr.rx_ok),
ns_brate(cntr.rx_byt, old_cntr.rx_byt, time_gap),
ns_prate(cntr.rx_ok, old_cntr.rx_ok, time_gap),
Expand All @@ -267,24 +249,24 @@ class Portstat(object):
ns_diff(cntr.tx_drop, old_cntr.tx_drop),
ns_diff(cntr.tx_ovr, old_cntr.tx_ovr)))
else:
table.append((key, self.get_port_status(key, PORT_ADMIN_STATUS_FIELD), self.get_port_status(key, PORT_OPER_STATUS_FIELD),
table.append((key, self.get_port_state(key),
cntr.rx_ok,
"N/A",
"N/A",
"N/A",
STATUS_NA,
STATUS_NA,
STATUS_NA,
cntr.rx_err,
cntr.rx_drop,
cntr.rx_ovr,
cntr.tx_ok,
"N/A",
"N/A",
"N/A",
STATUS_NA,
STATUS_NA,
STATUS_NA,
cntr.tx_err,
cntr.tx_drop,
cntr.tx_err))
else:
if old_cntr is not None:
table.append((key, self.get_port_status(key, PORT_ADMIN_STATUS_FIELD), self.get_port_status(key, PORT_OPER_STATUS_FIELD),
table.append((key, self.get_port_state(key),
ns_diff(cntr.rx_ok, old_cntr.rx_ok),
ns_brate(cntr.rx_byt, old_cntr.rx_byt, time_gap),
ns_util(cntr.rx_byt, old_cntr.rx_byt, time_gap),
Expand All @@ -298,16 +280,16 @@ class Portstat(object):
ns_diff(cntr.tx_drop, old_cntr.tx_drop),
ns_diff(cntr.tx_ovr, old_cntr.tx_ovr)))
else:
table.append((key, self.get_port_status(key, PORT_ADMIN_STATUS_FIELD), self.get_port_status(key, PORT_OPER_STATUS_FIELD),
table.append((key, self.get_port_state(key),
cntr.rx_ok,
"N/A",
"N/A",
STATUS_NA,
STATUS_NA,
cntr.rx_err,
cntr.rx_drop,
cntr.rx_ovr,
cntr.tx_ok,
"N/A",
"N/A",
STATUS_NA,
STATUS_NA,
cntr.tx_err,
cntr.tx_drop,
cntr.tx_err))
Expand All @@ -322,10 +304,11 @@ class Portstat(object):


def main():
parser = argparse.ArgumentParser(description='Wrapper for netstat',
parser = argparse.ArgumentParser(description='Display the ports state and counters',
version='1.0.0',
formatter_class=argparse.RawTextHelpFormatter,
epilog="""
Port state: (U)-Up (D)-Down (X)-Disabled
Examples:
portstat -c -t test
portstat -t test
Expand Down

0 comments on commit 9913106

Please sign in to comment.