Skip to content

Commit

Permalink
feat: add state to install criteo sonic-utilities
Browse files Browse the repository at this point in the history
Note: currently these scripts are in criteo-sonic-utilities repository.
They will be removed from it.
  • Loading branch information
kpetremann committed Aug 16, 2023
1 parent 7f00ae2 commit a15026f
Show file tree
Hide file tree
Showing 5 changed files with 802 additions and 0 deletions.
156 changes: 156 additions & 0 deletions states/utilities/201911/criteo_fdbshow
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#!/usr/bin/python
"""
This file is a modified version fdbshow in https://github.com/sonic-net/sonic-utilities
It adds JSON output support.
Script to show MAC/FDB entries learnt in Hardware / fixed from fdbshow in 201911
In long term, this will be replaced by the official sonic-utilies version (in python3).
usage: criteo_fdbshow [-p PORT] [-v VLAN]
optional arguments:
-p, --port FDB learned on specific port: Ethernet0
-v, --vlan FDB learned on specific Vlan: 1000
Examples of the output:
$ ./criteo_fdbshow -v 1234
[{"MacAddress": "00:53:00:01:02:03", "No.": 1, "Vlan": 1234, "Type": "Dynamic", "Port": "Ethernet0"}, 000]
$ ./criteo_fdbshow -p Ethernet0
[{"MacAddress": "00:53:00:01:02:03", "No.": 1, "Vlan": 1234, "Type": "Dynamic", "Port": "Ethernet0"}, ...]
"""
import argparse
import json
import sys

from natsort import natsorted
from swsssdk import SonicV2Connector, port_util

class FdbShow(object):

HEADER = ['No.', 'Vlan', 'MacAddress', 'Port', 'Type']
FDB_COUNT = 0

def __init__(self):
super(FdbShow,self).__init__()
self.db = SonicV2Connector(host="127.0.0.1")
self.if_name_map, \
self.if_oid_map = port_util.get_interface_oid_map(self.db)
self.if_br_oid_map = port_util.get_bridge_port_map(self.db)
self.fetch_fdb_data()
return

def fetch_fdb_data(self):
"""
Fetch FDB entries from ASIC DB.
FDB entries are sorted on "VlanID" and stored as a list of tuples
"""
self.db.connect(self.db.ASIC_DB)
self.bridge_mac_list = []

fdb_str = self.db.keys('ASIC_DB', "ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*")
if not fdb_str:
return

if self.if_br_oid_map is None:
return

oid_pfx = len("oid:0x")
for s in fdb_str:
fdb_entry = s.decode()
fdb = json.loads(fdb_entry .split(":", 2)[-1])
if not fdb:
continue

ent = self.db.get_all('ASIC_DB', s, blocking=True)
br_port_id = ent[b"SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID"][oid_pfx:]
ent_type = ent[b"SAI_FDB_ENTRY_ATTR_TYPE"]
fdb_type = ['Dynamic','Static'][ent_type == "SAI_FDB_ENTRY_TYPE_STATIC"]
if br_port_id not in self.if_br_oid_map:
continue
port_id = self.if_br_oid_map[br_port_id]
if port_id in self.if_oid_map:
if_name = self.if_oid_map[port_id]
else:
if_name = port_id
if 'vlan' in fdb:
vlan_id = fdb["vlan"]
elif 'bvid' in fdb:
try:
vlan_id = port_util.get_vlan_id_from_bvid(self.db, fdb["bvid"])
if vlan_id is None:
# the situation could be faced if the system has an FDB entries,
# which are linked to default Vlan(caused by untagged trafic)
continue
except:
vlan_id = fdb["bvid"]
# print "Failed to get Vlan id for bvid {}\n".format(fdb["bvid"])

try:
self.bridge_mac_list.append((int(vlan_id),) + (fdb["mac"],) + (if_name,) + (fdb_type,))
except ValueError:
continue

self.bridge_mac_list.sort(key = lambda x: x[0])
return


def get_iter_index(self, key_value=0, pos=0):
"""
Get the starting index of matched entry
"""
if pos != 0:
self.bridge_mac_list = natsorted(self.bridge_mac_list, key = lambda x: x[pos])

if key_value == 0:
return 0

keys = [r[pos] for r in self.bridge_mac_list]
return keys.index(key_value)


def display(self, vlan, port):
"""
Display the FDB entries for specified vlan/port.
@todo: - PortChannel support
"""
output = []

if vlan is not None:
vlan = int(vlan)
s_index = self.get_iter_index(vlan)
self.bridge_mac_list = [fdb for fdb in self.bridge_mac_list[s_index:]
if fdb[0] == vlan]
if port is not None:
s_index = self.get_iter_index(port, 2)
self.bridge_mac_list = [fdb for fdb in self.bridge_mac_list[s_index:]
if fdb[2] == port]

for fdb in self.bridge_mac_list:
self.FDB_COUNT += 1
entry = [self.FDB_COUNT, fdb[0], fdb[1], fdb[2], fdb[3]]
zipped_entry = dict(zip(self.HEADER, entry))
output.append(zipped_entry)

print json.dumps(output)


def main():
parser = argparse.ArgumentParser(description='Display ASIC FDB entries',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-p', '--port', type=str, help='FDB learned on specific port: Ethernet0', default=None)
parser.add_argument('-v', '--vlan', type=str, help='FDB learned on specific Vlan: 1001', default=None)
# the -j arg is not used, it is just here to ensure compatibility with the >= 202205 script version
parser.add_argument('-j', '--json', action='store_true', help='JSON output')
args = parser.parse_args()

try:
fdb = FdbShow()
fdb.display(args.vlan, args.port)
except Exception as e:
print e.message
sys.exit(1)

if __name__ == "__main__":
main()
189 changes: 189 additions & 0 deletions states/utilities/201911/criteo_intf_information
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
#!/usr/bin/python
"""
This file is derivated from scripts in https://github.com/sonic-net/sonic-utilities
It merges several interface information into a single command.
"""

import json
import swsssdk
import sys
import re
from swsssdk import ConfigDBConnector


PORT_STATUS_TABLE_PREFIX = "PORT_TABLE:"
PORT_TRANSCEIVER_TABLE_PREFIX = "TRANSCEIVER_INFO|"
PORT_TRANSCEIVER_DOM_TABLE_PREFIX = "TRANSCEIVER_DOM_SENSOR|"
PORT_LANES_STATUS = "lanes"
PORT_ALIAS = "alias"
PORT_OPER_STATUS = "oper_status"
PORT_ADMIN_STATUS = "admin_status"
PORT_SPEED = "speed"
PORT_MTU_STATUS = "mtu"
PORT_DESCRIPTION = "description"
PORT_OPTICS_TYPE = "type"
PORT_OPTICS_MODEL = "modelname"
PORT_OPTICS_MANUFACTURER = "manufacturename"
PORT_OPTICS_SENSOR_RX = "rx{}power"
PORT_OPTICS_SENSOR_TX = "tx{}power"
PORT_PFC_ASYM_STATUS = "pfc_asym"


def db_connect_configdb():
"""
Connect to configdb
"""
config_db = ConfigDBConnector()
if config_db is None:
return None
config_db.connect()
return config_db


def get_frontpanel_port_list(config_db):
ports_dict = config_db.get_table('PORT')
front_panel_ports_list = []
for port in ports_dict.iterkeys():
front_panel_ports_list.append(port)
return front_panel_ports_list


def db_connect_appl():
appl_db = swsssdk.SonicV2Connector(host='127.0.0.1')
if appl_db is None:
return None
appl_db.connect(appl_db.APPL_DB)
return appl_db


def appl_db_keys_get(appl_db, front_panel_ports_list, intf_name):
"""
Get APPL_DB Keys
"""
if intf_name is None:
appl_db_keys = appl_db.keys(appl_db.APPL_DB, "PORT_TABLE:*")
elif intf_name in front_panel_ports_list:
appl_db_keys = appl_db.keys(appl_db.APPL_DB, "PORT_TABLE:%s" % intf_name)
else:
return None
return appl_db_keys


def appl_db_port_status_get(appl_db, intf_name, status_type):
"""
Get the port status
"""
full_table_id = PORT_STATUS_TABLE_PREFIX + intf_name
status = appl_db.get(appl_db.APPL_DB, full_table_id, status_type)
if status is None:
return "N/A"
if status_type == PORT_SPEED and status != "N/A":
status = '{}G'.format(status[:-3])
return status


def db_connect_state():
"""
Connect to REDIS STATE DB and get optics info
"""
state_db = swsssdk.SonicV2Connector(host='127.0.0.1')
if state_db is None:
return None
state_db.connect(state_db.STATE_DB, False) # Make one attempt only
return state_db


def state_db_port_optics_get(state_db, intf_name, field):
"""
Get optic info for port
"""
full_table_id = PORT_TRANSCEIVER_TABLE_PREFIX + intf_name
info = state_db.get(state_db.STATE_DB, full_table_id, field)
if info is None:
return "N/A"
return info


def state_db_port_optics_sensors_get(state_db, intf_name, field):
"""
Get optic sensor info for port
"""
full_table_id = PORT_TRANSCEIVER_DOM_TABLE_PREFIX + intf_name
info = state_db.get(state_db.STATE_DB, full_table_id, field)
if info is None:
return "N/A"
return info


class IntfInformation(object):

def display_intf_information(self, appl_db_keys, front_panel_ports_list):
"""
Get information related to an interface
"""

i = {}
key = []
interfaces = {}

#
# Iterate through all the keys and append port's associated state to
# the result table.
#
for i in appl_db_keys:
key = re.split(':', i, maxsplit=1)[-1].strip()

if key in front_panel_ports_list:
lanes = appl_db_port_status_get(self.appl_db, key, PORT_LANES_STATUS)
nb_lanes = len(lanes.split(","))

interfaces[key] = {
"alias": appl_db_port_status_get(self.appl_db, key, PORT_ALIAS),
"description": appl_db_port_status_get(self.appl_db, key, PORT_DESCRIPTION),
"admin_status": appl_db_port_status_get(self.appl_db, key, PORT_ADMIN_STATUS),
"oper_status": appl_db_port_status_get(self.appl_db, key, PORT_OPER_STATUS),
"lanes": lanes,
"speed": appl_db_port_status_get(self.appl_db, key, PORT_SPEED),
"mtu": appl_db_port_status_get(self.appl_db, key, PORT_MTU_STATUS),
"optic_type": state_db_port_optics_get(self.state_db, key, PORT_OPTICS_TYPE),
"optic_model": state_db_port_optics_get(self.state_db, key, PORT_OPTICS_MODEL),
"optic_manufacturer": state_db_port_optics_get(self.state_db, key, PORT_OPTICS_MANUFACTURER),
}

for i in range(1, nb_lanes + 1):
interfaces[key]["rx{}_power".format(i)] = state_db_port_optics_sensors_get(self.state_db, key, PORT_OPTICS_SENSOR_RX.format(i))
interfaces[key]["tx{}_power".format(i)] = state_db_port_optics_sensors_get(self.state_db, key, PORT_OPTICS_SENSOR_TX.format(i))


print json.dumps(interfaces)

def __init__(self, intf_name):

self.config_db = db_connect_configdb()
self.state_db = db_connect_state()
self.appl_db = db_connect_appl()
if self.appl_db is None:
return
if self.config_db is None:
return
self.front_panel_ports_list = get_frontpanel_port_list(self.config_db)
appl_db_keys = appl_db_keys_get(self.appl_db, self.front_panel_ports_list, intf_name)
if appl_db_keys is None:
return

self.display_intf_information(appl_db_keys, self.front_panel_ports_list)


def main(args):
if len(args) == 0:
print "No valid arguments provided"
return

intf_name = args[1] if len(args) == 2 else None

IntfInformation(intf_name)

sys.exit(0)

if __name__ == "__main__":
main(sys.argv)
Loading

0 comments on commit a15026f

Please sign in to comment.