diff --git a/dump/helper.py b/dump/helper.py index 7da893a464d7..3a882c07711e 100644 --- a/dump/helper.py +++ b/dump/helper.py @@ -1,13 +1,16 @@ import os, sys, json + def create_template_dict(dbs): """ Generate a Template which will be returned by Executor Classes """ return {db: {'keys': [], 'tables_not_found': []} for db in dbs} + def verbose_print(str): if "VERBOSE" in os.environ and os.environ["VERBOSE"] == "1": print(str) + def handle_error(err_str, excep=False): """ Handles general error conditions, if any experienced by the module, @@ -17,7 +20,7 @@ def handle_error(err_str, excep=False): raise Exception("ERROR : {}".format(err_str)) else: print("ERROR : {}".format(err_str), file = sys.stderr) - + def handle_multiple_keys_matched_error(err_str, key_to_go_with="", excep=False): if excep: diff --git a/dump/match_helper.py b/dump/match_helper.py new file mode 100644 index 000000000000..9493a8345888 --- /dev/null +++ b/dump/match_helper.py @@ -0,0 +1,85 @@ +from dump.match_infra import MatchRequest +from dump.helper import handle_multiple_keys_matched_error + +# Port Helper Methods + +def fetch_port_oid(match_engine, port_name, ns): + """ + Fetches thr relevant SAI_OBJECT_TYPE_PORT given port name + """ + req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF", key_pattern="*", field="SAI_HOSTIF_ATTR_NAME", + value=port_name, return_fields=["SAI_HOSTIF_ATTR_OBJ_ID"], ns=ns) + ret = match_engine.fetch(req) + asic_port_obj_id = "" + if not ret["error"] and len(ret["keys"]) != 0: + sai_hostif_obj_key = ret["keys"][-1] + if sai_hostif_obj_key in ret["return_values"] and "SAI_HOSTIF_ATTR_OBJ_ID" in ret["return_values"][sai_hostif_obj_key]: + asic_port_obj_id = ret["return_values"][sai_hostif_obj_key]["SAI_HOSTIF_ATTR_OBJ_ID"] + return req, asic_port_obj_id, ret + +# Vlan Helper Methods + +def fetch_vlan_oid(match_engine, vlan_name, ns): + # Convert 'Vlanxxx' to 'xxx' + if vlan_name[0:4] != "Vlan" or not vlan_name[4:].isnumeric(): + vlan_num = -1 + else: + vlan_num = int(vlan_name[4:]) + + # Find the table named "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:*" in which SAI_VLAN_ATTR_VLAN_ID = vlan_num + req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_VLAN", key_pattern="*", field="SAI_VLAN_ATTR_VLAN_ID", + value=str(vlan_num), ns=ns) + ret = match_engine.fetch(req) + vlan_oid = "" + if ret["keys"]: + vlan_oid = ret["keys"][0].split(":", 2)[-1] + return req, vlan_oid, ret + +# LAG Helper Methods + +def get_lag_members_from_cfg(match_engine, lag_name, ns): + """ + Get the members associated with a LAG from Config DB + """ + lag_members = [] + req = MatchRequest(db="CONFIG_DB", table="PORTCHANNEL_MEMBER", key_pattern=lag_name + "|*", ns=ns) + ret = match_engine.fetch(req) + for key in ret["keys"]: + lag_members.append(key.split("|")[-1]) + return req, lag_members, ret + +def get_lag_and_member_obj(match_engine, port_asic_obj, ns): + """ + Given the member port oid, fetch lag_member & lag oid's + """ + req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", key_pattern="*", field="SAI_LAG_MEMBER_ATTR_PORT_ID", + value=port_asic_obj, return_fields=["SAI_LAG_MEMBER_ATTR_LAG_ID"], ns=ns) + ret = match_engine.fetch(req) + lag_member_key = "" + lag_oid = "" + if not ret["error"] and ret["keys"]: + lag_member_key = ret["keys"][-1] + if lag_member_key in ret["return_values"] and "SAI_LAG_MEMBER_ATTR_LAG_ID" in ret["return_values"][lag_member_key]: + lag_oid = ret["return_values"][lag_member_key]["SAI_LAG_MEMBER_ATTR_LAG_ID"] + return lag_member_key, lag_oid + +def fetch_lag_oid(match_engine, lag_name, ns): + """ + Finding the relevant SAI_OBJECT_TYPE_LAG key directly from the ASIC is not possible given a LAG name + Thus, using the members to find SAI_LAG_MEMBER_ATTR_LAG_ID + """ + _, lag_members, _ = get_lag_members_from_cfg(match_engine, lag_name, ns) + lag_type_oids = set() + for port_name in lag_members: + _, port_asic_obj, _ = fetch_port_oid(match_engine, port_name, ns) + if port_asic_obj: + lag_member_key, lag_oid = get_lag_and_member_obj(match_engine, port_asic_obj, ns) + lag_type_oids.add(lag_oid) + lag_type_oid, lag_type_oids = "", list(lag_type_oids) + if lag_type_oids: + if len(lag_type_oids) > 1: + # Ideally, only one associated lag_oid should be present for a portchannel + handle_multiple_keys_matched_error("Multipe lag_oids matched for portchannel: {}, \ + lag_oids matched {}".format(lag_name, lag_type_oids), lag_type_oids[-1]) + lag_type_oid = lag_type_oids[-1] + return lag_type_oid diff --git a/dump/plugins/interface.py b/dump/plugins/interface.py new file mode 100644 index 000000000000..ffa226076e37 --- /dev/null +++ b/dump/plugins/interface.py @@ -0,0 +1,266 @@ +from sonic_py_common.interface import get_interface_table_name, get_intf_longname, VLAN_SUB_INTERFACE_SEPARATOR +from sonic_py_common.multi_asic import DEFAULT_NAMESPACE +from dump.match_infra import MatchRequest +from dump.helper import create_template_dict, handle_error +from dump.match_helper import fetch_port_oid, fetch_vlan_oid, fetch_lag_oid +from swsscommon.swsscommon import SonicDBConfig +from .executor import Executor + + +class Interface(Executor): + """ + Debug Dump Plugin for Interface Module. + Interface can be of Ethernet, PortChannel, Loopback, Vlan or SubInterface type + Human readable intf string names are supported + """ + ARG_NAME = "intf_name" + + def __init__(self, match_engine=None): + super().__init__(match_engine) + self.ns = DEFAULT_NAMESPACE + self.intf_type = "" + self.ret_temp = dict() + self.valid_cfg_tables = set(["INTERFACE", + "PORTCHANNEL_INTERFACE", + "VLAN_INTERFACE", + "LOOPBACK_INTERFACE", + "VLAN_SUB_INTERFACE"]) + + def get_all_args(self, ns=DEFAULT_NAMESPACE): + """ + Fetch all the interfaces from the valid cfg tables + """ + req = MatchRequest(db="CONFIG_DB", table="*INTERFACE", key_pattern="*", ns=ns) + ret = self.match_engine.fetch(req) + all_intfs = ret["keys"] + filtered_keys = [] + for key in all_intfs: + num_sep = key.count("|") + if num_sep == 1: + filtered_keys.append(key.split("|")[-1]) + return filtered_keys + + def execute(self, params): + self.ret_temp = create_template_dict(dbs=["CONFIG_DB", "APPL_DB", "STATE_DB", "ASIC_DB"]) + self.intf_name = params[Interface.ARG_NAME] + self.ns = params["namespace"] + # CONFIG_DB + self.intf_type = self.init_intf_config_info() + # APPL_DB + self.init_intf_appl_info() + # STATE_DB + self.init_intf_state_info() + # ASIC_DB + self.init_intf_asic_info() + return self.ret_temp + + def get_sep(self, db): + return SonicDBConfig.getSeparator(db) + + def add_intf_keys(self, db_name, table_name): + # Fetch Interface Keys + req = MatchRequest(db=db_name, table=table_name, key_pattern=self.intf_name, ns=self.ns) + ret = self.match_engine.fetch(req) + self.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) + # Fetch IP & Interface Related keys + req = MatchRequest(db=db_name, table=table_name, key_pattern=self.intf_name+self.get_sep(db_name)+"*", ns=self.ns) + ret = self.match_engine.fetch(req) + self.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"], False) + + def init_intf_config_info(self): + intf_table_name = get_interface_table_name(self.intf_name) + if not intf_table_name: + self.ret_temp["CONFIG_DB"]["tables_not_found"].extend(list(self.valid_cfg_tables)) + else: + self.add_intf_keys("CONFIG_DB", intf_table_name) + return intf_table_name + + def init_intf_appl_info(self): + self.add_intf_keys("APPL_DB", "INTF_TABLE") + + def init_intf_state_info(self): + self.add_intf_keys("STATE_DB", "INTERFACE_TABLE") + + def init_intf_asic_info(self): + """ + Fetch SAI_OBJECT_TYPE_ROUTER_INTERFACE ASIC Object for the corresponding interface + To find the relevant ASIC RIF object, this method would need the following: + 1) INTERFACE - SAI_OBJECT_TYPE_PORT oid + 2) PORTCHANNEL - SAI_OBJECT_TYPE_LAG oid + 3) VLAN - SAI_OBJECT_TYPE_VLAN + 4) SUB_INTERFACE - SAI_OBJECT_TYPE_PORT/SAI_OBJECT_TYPE_LAG & SAI_ROUTER_INTERFACE_ATTR_OUTER_VLAN_ID + """ + rif_obj = RIF.initialize(self) + rif_obj.collect() + return + +class RIF(object): + """ + Base Class for RIF type + """ + @staticmethod + def initialize(intf_obj): + if intf_obj.intf_type == "INTERFACE": + return PortRIF(intf_obj) + elif intf_obj.intf_type == "PORTCHANNEL_INTERFACE": + return LagRIF(intf_obj) + elif intf_obj.intf_type == "VLAN_INTERFACE": + return VlanRIF(intf_obj) + elif intf_obj.intf_type == "LOOPBACK_INTERFACE": + return LpbRIF(intf_obj) + elif intf_obj.intf_type == "VLAN_SUB_INTERFACE": + return SubIntfRif(intf_obj) + return RIF(intf_obj) + + def __init__(self, intf_obj): + self.intf = intf_obj + + def fetch_rif_keys_using_port_oid(self, port_oid, rfs=["SAI_ROUTER_INTERFACE_ATTR_TYPE"]): + if not port_oid: + port_oid = "INVALID" + req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE", key_pattern="*", field="SAI_ROUTER_INTERFACE_ATTR_PORT_ID", + value=port_oid, return_fields=rfs, ns=self.intf.ns) + ret = self.intf.match_engine.fetch(req) + return req, ret + + def verify_valid_rif_type(self, ret, exp_rif_type=""): + if not ret or not exp_rif_type: + return True, "" + + rif_type = "" + if not ret["error"] and ret["keys"]: + rif_key = ret["keys"][-1] + rif_type = ret.get("return_values", {}).get(rif_key, {}).get("SAI_ROUTER_INTERFACE_ATTR_TYPE", "") + + if rif_type == exp_rif_type: + return True, rif_type + else: + return False, rif_type + + def sanity_check_rif_type(self, ret, rif_oid, exp_type, str_name): + # Sanity check to see if the TYPE is SAI_ROUTER_INTERFACE_TYPE_PORT + _, recv_type = self.verify_valid_rif_type(ret, exp_type) + if exp_type != recv_type: + err_str = "TYPE Mismatch on SAI_OBJECT_TYPE_ROUTER_INTERFACE, {} oid:{}, expected type:{}, recieved type:{}" + handle_error(err_str.format(str_name, rif_oid, exp_type, recv_type), False) + return + + def collect(self): + self.intf.ret_temp["ASIC_DB"]["tables_not_found"].extend(["ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE"]) + return + + +class LpbRIF(RIF): + """ + Handler for Loopback Interface + """ + def collect(self): + # When an ip is added to Loopback interface, + # no ROUTER_INTERFACE asic obj is created, so skipping it + # and not adding to tables not found + return + + +class PortRIF(RIF): + """ + Handler for Port type Obj + """ + def collect(self): + # Get port oid from port name + _, port_oid, _ = fetch_port_oid(self.intf.match_engine, self.intf.intf_name, self.intf.ns) + # Use Port oid to get the RIF + req, ret = self.fetch_rif_keys_using_port_oid(port_oid) + rif_oids = self.intf.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) + if rif_oids: + # Sanity check to see if the TYPE is SAI_ROUTER_INTERFACE_TYPE_PORT + exp_type = "SAI_ROUTER_INTERFACE_TYPE_PORT" + self.sanity_check_rif_type(ret, rif_oids[-1], exp_type, "PORT") + + +class VlanRIF(RIF): + """ + Handler for Vlan type Obj + """ + def fetch_rif_keys_using_vlan_oid(self, vlan_oid): + if not vlan_oid: + vlan_oid = "INVALID" + req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE", key_pattern="*", field="SAI_ROUTER_INTERFACE_ATTR_VLAN_ID", + value=vlan_oid, return_fields=["SAI_ROUTER_INTERFACE_ATTR_TYPE"], ns=self.intf.ns) + ret = self.intf.match_engine.fetch(req) + return req, ret + + def collect(self): + # Get vlan oid from vlan name + _, vlan_oid, _ = fetch_vlan_oid(self.intf.match_engine, self.intf.intf_name, self.intf.ns) + # Use vlan oid to get the RIF + req, ret = self.fetch_rif_keys_using_vlan_oid(vlan_oid) + rif_oids = self.intf.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) + if rif_oids: + # Sanity check to see if the TYPE is SAI_ROUTER_INTERFACE_TYPE_VLAN + exp_type = "SAI_ROUTER_INTERFACE_TYPE_VLAN" + self.sanity_check_rif_type(ret, rif_oids[-1], exp_type, "VLAN") + + +class LagRIF(RIF): + """ + Handler for PortChannel/LAG type Obj + """ + def collect(self): + # Get lag oid from lag name + lag_oid = fetch_lag_oid(self.intf.match_engine, self.intf.intf_name, self.intf.ns) + # Use vlan oid to get the RIF + req, ret = self.fetch_rif_keys_using_port_oid(lag_oid) + rif_oids = self.intf.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) + if rif_oids: + # Sanity check to see if the TYPE is SAI_ROUTER_INTERFACE_TYPE_PORT + exp_type = "SAI_ROUTER_INTERFACE_TYPE_PORT" + self.sanity_check_rif_type(ret, rif_oids[-1], exp_type, "LAG") + + +class SubIntfRif(RIF): + """ + Handler for PortChannel/LAG type Obj + """ + def fetch_vlan_id_subintf(self, sub_intf): + req = MatchRequest(db="CONFIG_DB", table="VLAN_SUB_INTERFACE", key_pattern=sub_intf, return_fields=["vlan"], ns=self.intf.ns) + ret = self.intf.match_engine.fetch(req) + vlan_id = "" + if not ret["error"] and ret["keys"]: + key = ret["keys"][-1] + vlan_id = ret["return_values"].get(key, {}).get("vlan", "") + return vlan_id + + def collect(self): + """ + To match the RIF object, two checks have to be performed, + 1) SAI_ROUTER_INTERFACE_ATTR_PORT_ID + - This can either be SAI_OBJECT_TYPE_PORT or SAI_OBJECT_TYPE_LAG + 2) SAI_ROUTER_INTERFACE_ATTR_OUTER_VLAN_ID + - This will be Vlan Number (uint16) + """ + intf_oid = "" + parent_port, _ = self.intf.intf_name.split(VLAN_SUB_INTERFACE_SEPARATOR) + parent_port = get_intf_longname(parent_port) + vlan_id = self.fetch_vlan_id_subintf(self.intf.intf_name) + if parent_port.startswith("Eth"): + _, intf_oid, _ = fetch_port_oid(self.intf.match_engine, parent_port, self.intf.ns) + else: + intf_oid = fetch_lag_oid(self.intf.match_engine, parent_port, self.intf.ns) + + # Use vlan oid to get the RIF + return_fields = ["SAI_ROUTER_INTERFACE_ATTR_OUTER_VLAN_ID", "SAI_ROUTER_INTERFACE_ATTR_TYPE"] + req, ret = self.fetch_rif_keys_using_port_oid(intf_oid, rfs=return_fields) + + # Search for keys who has SAI_ROUTER_INTERFACE_ATTR_OUTER_VLAN_ID field + filtered_keys = [] + if not ret["error"] and len(ret['keys']) > 0: + for key in ret["keys"]: + rcv_vlan_id = ret.get("return_values", {}).get(key, {}).get("SAI_ROUTER_INTERFACE_ATTR_OUTER_VLAN_ID", "") + if rcv_vlan_id == vlan_id: + filtered_keys.append(key) + break + + rif_oids = self.intf.add_to_ret_template(req.table, req.db, filtered_keys, ret["error"]) + if rif_oids: + exp_type = "SAI_ROUTER_INTERFACE_TYPE_SUB_PORT" + self.sanity_check_rif_type(ret, rif_oids[-1], exp_type, "SUB_INTERFACE") diff --git a/dump/plugins/port.py b/dump/plugins/port.py index f3f74897a342..2cffda2fd70d 100644 --- a/dump/plugins/port.py +++ b/dump/plugins/port.py @@ -1,5 +1,6 @@ from dump.match_infra import MatchRequest from dump.helper import create_template_dict +from dump.match_helper import fetch_port_oid from .executor import Executor @@ -45,18 +46,8 @@ def init_state_port_info(self, port_name): self.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) def init_asic_hostif_info(self, port_name): - req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF", key_pattern="*", field="SAI_HOSTIF_ATTR_NAME", - value=port_name, return_fields=["SAI_HOSTIF_ATTR_OBJ_ID"], ns=self.ns) - ret = self.match_engine.fetch(req) - asic_port_obj_id = "" - - if not ret["error"] and len(ret["keys"]) != 0: - self.ret_temp[req.db]["keys"] = ret["keys"] - sai_hostif_obj_key = ret["keys"][-1] - if sai_hostif_obj_key in ret["return_values"] and "SAI_HOSTIF_ATTR_OBJ_ID" in ret["return_values"][sai_hostif_obj_key]: - asic_port_obj_id = ret["return_values"][sai_hostif_obj_key]["SAI_HOSTIF_ATTR_OBJ_ID"] - else: - self.ret_temp[req.db]["tables_not_found"] = [req.table] + req, asic_port_obj_id, ret = fetch_port_oid(self.match_engine, port_name, self.ns) + self.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) return asic_port_obj_id def init_asic_port_info(self, asic_port_obj_id): diff --git a/dump/plugins/portchannel.py b/dump/plugins/portchannel.py index b71c7c4fc3a3..659412e988ce 100644 --- a/dump/plugins/portchannel.py +++ b/dump/plugins/portchannel.py @@ -1,5 +1,6 @@ from dump.match_infra import MatchRequest from dump.helper import create_template_dict +from dump.match_helper import fetch_lag_oid from .executor import Executor @@ -25,16 +26,13 @@ def execute(self, params_dict): self.lag_name = params_dict[Portchannel.ARG_NAME] self.ns = params_dict["namespace"] # CONFIG_DB - lag_found = self.init_lag_config_info() - if lag_found: - self.init_lag_member_config_info() + self.init_lag_config_info() # APPL_DB self.init_lag_appl_info() # STATE_DB self.init_lag_state_info() # ASIC_DB - lag_type_objs_asic = self.init_lag_member_type_obj_asic_info() - self.init_lag_asic_info(lag_type_objs_asic) + self.init_lag_asic_info() return self.ret_temp def init_lag_config_info(self): @@ -42,12 +40,6 @@ def init_lag_config_info(self): ret = self.match_engine.fetch(req) return self.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) - def init_lag_member_config_info(self): - req = MatchRequest(db="CONFIG_DB", table="PORTCHANNEL_MEMBER", key_pattern=self.lag_name + "|*", ns=self.ns) - ret = self.match_engine.fetch(req) - for key in ret["keys"]: - self.lag_members.add(key.split("|")[-1]) - def init_lag_appl_info(self): req = MatchRequest(db="APPL_DB", table="LAG_TABLE", key_pattern=self.lag_name, ns=self.ns) ret = self.match_engine.fetch(req) @@ -58,47 +50,9 @@ def init_lag_state_info(self): ret = self.match_engine.fetch(req) return self.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) - def init_lag_asic_info(self, lag_type_objs_asic): - if len(lag_type_objs_asic) == 0: - self.ret_temp["ASIC_DB"]["tables_not_found"].extend(["ASIC_STATE:SAI_OBJECT_TYPE_LAG"]) - return - for lag_asic_obj in lag_type_objs_asic: - req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_LAG", key_pattern=lag_asic_obj, ns=self.ns) - ret = self.match_engine.fetch(req) - self.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) - - def init_lag_member_type_obj_asic_info(self): - """ - Finding the relevant SAI_OBJECT_TYPE_LAG key directly from the ASIC is not possible given a LAG name - Thus, using the members to find SAI_LAG_MEMBER_ATTR_LAG_ID - """ - lag_type_objs_asic = set() - for port_name in self.lag_members: - port_asic_obj = self.get_port_asic_obj(port_name) - if port_asic_obj: - lag_member_key, lag_oid = self.get_lag_and_member_obj(port_asic_obj) - lag_type_objs_asic.add(lag_oid) - return lag_type_objs_asic - - def get_port_asic_obj(self, port_name): - req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF", key_pattern="*", field="SAI_HOSTIF_ATTR_NAME", - value=port_name, return_fields=["SAI_HOSTIF_ATTR_OBJ_ID"], ns=self.ns) - ret = self.match_engine.fetch(req) - asic_port_obj_id = "" - if not ret["error"] and ret["keys"]: - sai_hostif_obj_key = ret["keys"][-1] - if sai_hostif_obj_key in ret["return_values"] and "SAI_HOSTIF_ATTR_OBJ_ID" in ret["return_values"][sai_hostif_obj_key]: - asic_port_obj_id = ret["return_values"][sai_hostif_obj_key]["SAI_HOSTIF_ATTR_OBJ_ID"] - return asic_port_obj_id - - def get_lag_and_member_obj(self, port_asic_obj): - req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER", key_pattern="*", field="SAI_LAG_MEMBER_ATTR_PORT_ID", - value=port_asic_obj, return_fields=["SAI_LAG_MEMBER_ATTR_LAG_ID"], ns=self.ns) + def init_lag_asic_info(self): + # Fetch Lag Type Asic Obj from CFG DB given lag name + lag_asic_obj = fetch_lag_oid(self.match_engine, self.lag_name, self.ns) + req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_LAG", key_pattern=lag_asic_obj, ns=self.ns) ret = self.match_engine.fetch(req) - lag_member_key = "" - lag_oid = "" - if not ret["error"] and ret["keys"]: - lag_member_key = ret["keys"][-1] - if lag_member_key in ret["return_values"] and "SAI_LAG_MEMBER_ATTR_LAG_ID" in ret["return_values"][lag_member_key]: - lag_oid = ret["return_values"][lag_member_key]["SAI_LAG_MEMBER_ATTR_LAG_ID"] - return lag_member_key, lag_oid + self.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) diff --git a/dump/plugins/vlan.py b/dump/plugins/vlan.py index 6f5c9b90a964..f3a99f4250d2 100644 --- a/dump/plugins/vlan.py +++ b/dump/plugins/vlan.py @@ -1,6 +1,7 @@ from .executor import Executor from dump.match_infra import MatchRequest from dump.helper import create_template_dict +from dump.match_helper import fetch_vlan_oid class Vlan(Executor): @@ -43,14 +44,5 @@ def init_state_vlan_info(self, vlan_name): self.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) def init_asic_vlan_info(self, vlan_name): - # Convert 'Vlanxxx' to 'xxx' - if vlan_name[0:4] != "Vlan" or not vlan_name[4:].isnumeric(): - self.ret_temp["ASIC_DB"]["tables_not_found"] =["ASIC_STATE:SAI_OBJECT_TYPE_VLAN"] - return {}, {} - vlan_num = int(vlan_name[4:]) - - # Find the table named "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:*" in which SAI_VLAN_ATTR_VLAN_ID = vlan_num - req = MatchRequest(db="ASIC_DB", table="ASIC_STATE:SAI_OBJECT_TYPE_VLAN", key_pattern="*", field="SAI_VLAN_ATTR_VLAN_ID", - value=str(vlan_num), ns=self.ns) - ret = self.match_engine.fetch(req) + req, _, ret = fetch_vlan_oid(self.match_engine, vlan_name, self.ns) self.add_to_ret_template(req.table, req.db, ret["keys"], ret["error"]) diff --git a/tests/dump_input/interface/appl_db.json b/tests/dump_input/interface/appl_db.json new file mode 100644 index 000000000000..772cc3233242 --- /dev/null +++ b/tests/dump_input/interface/appl_db.json @@ -0,0 +1,58 @@ +{ + "INTF_TABLE:Ethernet16":{ + "NULL": "NULL", + "mac_addr": "00:00:00:00:00:00" + }, + "INTF_TABLE:Ethernet16:3.3.3.1/24": { + "family": "IPv4", + "scope": "global" + }, + "INTF_TABLE:PortChannel1111": { + "NULL": "NULL", + "mac_addr": "00:00:00:00:00:00" + }, + "INTF_TABLE:PortChannel1111:1.1.1.1/24": { + "family": "IPv4", + "scope": "global" + }, + "INTF_TABLE:Vlan10": { + "NULL": "NULL", + "mac_addr": "00:00:00:00:00:00" + }, + "INTF_TABLE:Vlan10:2.2.2.1/24": { + "family": "IPv4", + "scope": "global" + }, + "INTF_TABLE:Eth0.1": { + "admin_status": "up", + "mac_addr": "00:00:00:00:00:00", + "mtu": "9100", + "vlan": "10" + }, + "INTF_TABLE:Eth0.1:9.9.9.9/24": { + "family": "IPv4", + "scope": "global" + }, + "INTF_TABLE:PortChannel1234": { + "NULL": "NULL", + "mac_addr": "00:00:00:00:00:00" + }, + "INTF_TABLE:PortChannel1234:7.7.7.1/24": { + "family": "IPv4", + "scope": "global" + }, + "INTF_TABLE:Loopback0": { + "NULL": "NULL", + "mac_addr": "00:00:00:00:00:00" + }, + "INTF_TABLE:Loopback0:10.1.0.1/32": { + "family": "IPv4", + "scope": "global" + }, + "INTF_TABLE:Eth4.1": { + "admin_status": "up", + "mac_addr": "00:00:00:00:00:00", + "mtu": "9100", + "vlan": "100" + } +} \ No newline at end of file diff --git a/tests/dump_input/interface/asic_db.json b/tests/dump_input/interface/asic_db.json new file mode 100644 index 000000000000..bbad0c9cd98e --- /dev/null +++ b/tests/dump_input/interface/asic_db.json @@ -0,0 +1,80 @@ +{ + "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd000000000a26": { + "SAI_HOSTIF_ATTR_NAME": "Ethernet16", + "SAI_HOSTIF_ATTR_OBJ_ID": "oid:0x1000000000937", + "SAI_HOSTIF_ATTR_OPER_STATUS": "true", + "SAI_HOSTIF_ATTR_TYPE": "SAI_HOSTIF_TYPE_NETDEV" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x6000000000c7c": { + "SAI_ROUTER_INTERFACE_ATTR_MTU": "9100", + "SAI_ROUTER_INTERFACE_ATTR_PORT_ID": "oid:0x1000000000937", + "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS": "1C:34:DA:1C:9F:00", + "SAI_ROUTER_INTERFACE_ATTR_TYPE": "SAI_ROUTER_INTERFACE_TYPE_PORT", + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": "oid:0x3000000000010" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_VLAN:oid:0x26000000000c78": { + "SAI_VLAN_ATTR_VLAN_ID": "10" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x6000000000c7b": { + "SAI_ROUTER_INTERFACE_ATTR_MTU": "9100", + "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS": "1C:34:DA:1C:9F:00", + "SAI_ROUTER_INTERFACE_ATTR_TYPE": "SAI_ROUTER_INTERFACE_TYPE_VLAN", + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": "oid:0x3000000000010", + "SAI_ROUTER_INTERFACE_ATTR_VLAN_ID": "oid:0x26000000000c78" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_LAG:oid:0x2000000000c73": { + "NULL": "NULL" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x6000000000c77": { + "SAI_ROUTER_INTERFACE_ATTR_MTU": "9100", + "SAI_ROUTER_INTERFACE_ATTR_PORT_ID": "oid:0x2000000000c73", + "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS": "1C:34:DA:1C:9F:00", + "SAI_ROUTER_INTERFACE_ATTR_TYPE": "SAI_ROUTER_INTERFACE_TYPE_PORT", + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": "oid:0x3000000000010" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd00000000056e": { + "SAI_HOSTIF_ATTR_NAME": "Ethernet0", + "SAI_HOSTIF_ATTR_OBJ_ID": "oid:0x1000000000528", + "SAI_HOSTIF_ATTR_OPER_STATUS": "true", + "SAI_HOSTIF_ATTR_TYPE": "SAI_HOSTIF_TYPE_NETDEV", + "SAI_HOSTIF_ATTR_VLAN_TAG": "SAI_HOSTIF_VLAN_TAG_KEEP" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005e9": { + "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V4_STATE": "true", + "SAI_ROUTER_INTERFACE_ATTR_ADMIN_V6_STATE": "true", + "SAI_ROUTER_INTERFACE_ATTR_MTU": "9100", + "SAI_ROUTER_INTERFACE_ATTR_OUTER_VLAN_ID": "10", + "SAI_ROUTER_INTERFACE_ATTR_PORT_ID": "oid:0x1000000000528", + "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS": "7C:FE:90:F5:36:40", + "SAI_ROUTER_INTERFACE_ATTR_TYPE": "SAI_ROUTER_INTERFACE_TYPE_SUB_PORT", + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": "oid:0x3000000000002" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd00000000058c": { + "SAI_HOSTIF_ATTR_NAME": "Ethernet120", + "SAI_HOSTIF_ATTR_OBJ_ID": "oid:0x1000000000318", + "SAI_HOSTIF_ATTR_OPER_STATUS": "false", + "SAI_HOSTIF_ATTR_TYPE": "SAI_HOSTIF_TYPE_NETDEV" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_LAG_MEMBER:oid:0x1b0000000005eb": { + "SAI_LAG_MEMBER_ATTR_EGRESS_DISABLE": "true", + "SAI_LAG_MEMBER_ATTR_INGRESS_DISABLE": "true", + "SAI_LAG_MEMBER_ATTR_LAG_ID": "oid:0x200000000058e", + "SAI_LAG_MEMBER_ATTR_PORT_ID": "oid:0x1000000000318" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_LAG:oid:0x200000000058e": { + "NULL": "NULL" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005ec": { + "SAI_ROUTER_INTERFACE_ATTR_MTU": "9100", + "SAI_ROUTER_INTERFACE_ATTR_PORT_ID": "oid:0x200000000058e", + "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS": "7C:FE:90:F5:36:40", + "SAI_ROUTER_INTERFACE_ATTR_TYPE": "SAI_ROUTER_INTERFACE_TYPE_PORT", + "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID": "oid:0x3000000000002" + }, + "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF:oid:0xd00000000056f": { + "SAI_HOSTIF_ATTR_NAME": "Ethernet4", + "SAI_HOSTIF_ATTR_OBJ_ID": "oid:0x1000000000529", + "SAI_HOSTIF_ATTR_OPER_STATUS": "true", + "SAI_HOSTIF_ATTR_TYPE": "SAI_HOSTIF_TYPE_NETDEV" + } +} diff --git a/tests/dump_input/interface/config_db.json b/tests/dump_input/interface/config_db.json new file mode 100644 index 000000000000..afeaccad9ff9 --- /dev/null +++ b/tests/dump_input/interface/config_db.json @@ -0,0 +1,49 @@ +{ + "INTERFACE|Ethernet16": { + "NULL" : "NULL" + }, + "INTERFACE|Ethernet16|3.3.3.1/24": { + "NULL" : "NULL" + }, + "VLAN_INTERFACE|Vlan10": { + "NULL" : "NULL" + }, + "VLAN_INTERFACE|Vlan10|2.2.2.1/24": { + "NULL" : "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel1111": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel1111|1.1.1.1/24": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel1234": { + "NULL": "NULL" + }, + "PORTCHANNEL_INTERFACE|PortChannel1234|7.7.7.1/24": { + "NULL": "NULL" + }, + "PORTCHANNEL_MEMBER|PortChannel1234|Ethernet120": { + "NULL": "NULL" + }, + "PORTCHANNEL_MEMBER|PortChannel1234|Ethernet124": { + "NULL": "NULL" + }, + "VLAN_SUB_INTERFACE|Eth0.1": { + "admin_status": "up", + "vlan": "10" + }, + "VLAN_SUB_INTERFACE|Eth0.1|9.9.9.9/24": { + "NULL": "NULL" + }, + "LOOPBACK_INTERFACE|Loopback0": { + "NULL": "NULL" + }, + "LOOPBACK_INTERFACE|Loopback0|10.1.0.1/32": { + "NULL": "NULL" + }, + "VLAN_SUB_INTERFACE|Eth4.1": { + "admin_status": "up", + "vlan": "100" + } +} diff --git a/tests/dump_input/interface/state_db.json b/tests/dump_input/interface/state_db.json new file mode 100644 index 000000000000..4d7d9e5d1fb8 --- /dev/null +++ b/tests/dump_input/interface/state_db.json @@ -0,0 +1,38 @@ +{ + "INTERFACE_TABLE|Ethernet16": { + "vrf": "" + }, + "INTERFACE_TABLE|Ethernet16|3.3.3.1/24": { + "state": "ok" + }, + "INTERFACE_TABLE|PortChannel1111": { + "vrf": "" + }, + "INTERFACE_TABLE|PortChannel1111|1.1.1.1/24": { + "state": "ok" + }, + "INTERFACE_TABLE|Vlan10": { + "vrf": "" + }, + "INTERFACE_TABLE|Vlan10|2.2.2.1/24": { + "state": "ok" + }, + "INTERFACE_TABLE|Eth0.1": { + "vrf": "" + }, + "INTERFACE_TABLE|Eth0.1|9.9.9.9/24": { + "state": "ok" + }, + "INTERFACE_TABLE|PortChannel1234": { + "vrf": "" + }, + "INTERFACE_TABLE|PortChannel1234|7.7.7.1/24": { + "state": "ok" + }, + "INTERFACE_TABLE|Loopback0": { + "vrf": "" + }, + "INTERFACE_TABLE|Loopback0|10.1.0.1/32": { + "state": "ok" + } +} diff --git a/tests/dump_tests/module_tests/interface_test.py b/tests/dump_tests/module_tests/interface_test.py new file mode 100644 index 000000000000..969272b06906 --- /dev/null +++ b/tests/dump_tests/module_tests/interface_test.py @@ -0,0 +1,207 @@ +import json +import os +import sys +import jsonpatch +import unittest +import pytest +from deepdiff import DeepDiff +from mock import patch +from dump.helper import create_template_dict, sort_lists, populate_mock +from dump.plugins.interface import Interface +from dump.match_infra import MatchEngine, ConnectionPool +from swsscommon.swsscommon import SonicV2Connector + +# Location for dedicated db's used for UT +module_tests_path = os.path.dirname(__file__) +dump_tests_path = os.path.join(module_tests_path, "../") +tests_path = os.path.join(dump_tests_path, "../") +dump_test_input = os.path.join(tests_path, "dump_input") +port_files_path = os.path.join(dump_test_input, "interface") + +# Define the mock files to read from +dedicated_dbs = {} +dedicated_dbs['CONFIG_DB'] = os.path.join(port_files_path, "config_db.json") +dedicated_dbs['APPL_DB'] = os.path.join(port_files_path, "appl_db.json") +dedicated_dbs['ASIC_DB'] = os.path.join(port_files_path, "asic_db.json") +dedicated_dbs['STATE_DB'] = os.path.join(port_files_path, "state_db.json") + + +@pytest.fixture(scope="class", autouse=True) +def match_engine(): + + print("SETUP") + os.environ["VERBOSE"] = "1" + + # Monkey Patch the SonicV2Connector Object + from ...mock_tables import dbconnector + db = SonicV2Connector() + + # popualate the db with mock data + db_names = list(dedicated_dbs.keys()) + try: + populate_mock(db, db_names, dedicated_dbs) + except Exception as e: + assert False, "Mock initialization failed: " + str(e) + + # Initialize connection pool + conn_pool = ConnectionPool() + DEF_NS = '' # Default Namespace + conn_pool.cache = {DEF_NS: {'conn': db, + 'connected_to': set(db_names)}} + + # Initialize match_engine + match_engine = MatchEngine(conn_pool) + yield match_engine + print("TEARDOWN") + os.environ["VERBOSE"] = "0" + +@pytest.mark.usefixtures("match_engine") +class TestInterfaceModule: + def test_port_type_interface(self, match_engine): + """ + Scenario: Test the flow fetching objs related to PORT_TYPE interfac + """ + params = {Interface.ARG_NAME: "Ethernet16", "namespace": ""} + m_intf = Interface(match_engine) + returned = m_intf.execute(params) + expect = create_template_dict(dbs=["CONFIG_DB", "APPL_DB", "ASIC_DB", "STATE_DB"]) + expect["CONFIG_DB"]["keys"].extend(["INTERFACE|Ethernet16", "INTERFACE|Ethernet16|3.3.3.1/24"]) + expect["APPL_DB"]["keys"].extend(["INTF_TABLE:Ethernet16", "INTF_TABLE:Ethernet16:3.3.3.1/24"]) + expect["STATE_DB"]["keys"].extend(["INTERFACE_TABLE|Ethernet16", "INTERFACE_TABLE|Ethernet16|3.3.3.1/24"]) + expect["ASIC_DB"]["keys"].append("ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x6000000000c7c") + ddiff = DeepDiff(sort_lists(returned), sort_lists(expect), ignore_order=True) + assert not ddiff, ddiff + + def test_vlan_type_interface(self, match_engine): + """ + Scenario: Test the flow fetching objs related to VLAN_TYPE interfac + """ + params = {Interface.ARG_NAME: "Vlan10", "namespace": ""} + m_intf = Interface(match_engine) + returned = m_intf.execute(params) + expect = create_template_dict(dbs=["CONFIG_DB", "APPL_DB", "ASIC_DB", "STATE_DB"]) + expect["CONFIG_DB"]["keys"].extend(["VLAN_INTERFACE|Vlan10", "VLAN_INTERFACE|Vlan10|2.2.2.1/24"]) + expect["APPL_DB"]["keys"].extend(["INTF_TABLE:Vlan10", "INTF_TABLE:Vlan10:2.2.2.1/24"]) + expect["STATE_DB"]["keys"].extend(["INTERFACE_TABLE|Vlan10", "INTERFACE_TABLE|Vlan10|2.2.2.1/24"]) + expect["ASIC_DB"]["keys"].append("ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x6000000000c7b") + ddiff = DeepDiff(sort_lists(returned), sort_lists(expect), ignore_order=True) + assert not ddiff, ddiff + + def test_lag_type_interface_no_members(self, match_engine): + """ + Scenario: Test the flow fetching objs related to LAG_TYPE iface without members + """ + params = {Interface.ARG_NAME: "PortChannel1111", "namespace": ""} + m_intf = Interface(match_engine) + returned = m_intf.execute(params) + expect = create_template_dict(dbs=["CONFIG_DB", "APPL_DB", "ASIC_DB", "STATE_DB"]) + expect["CONFIG_DB"]["keys"].extend(["PORTCHANNEL_INTERFACE|PortChannel1111", "PORTCHANNEL_INTERFACE|PortChannel1111|1.1.1.1/24"]) + expect["APPL_DB"]["keys"].extend(["INTF_TABLE:PortChannel1111", "INTF_TABLE:PortChannel1111:1.1.1.1/24"]) + expect["STATE_DB"]["keys"].extend(["INTERFACE_TABLE|PortChannel1111", "INTERFACE_TABLE|PortChannel1111|1.1.1.1/24"]) + expect["ASIC_DB"]["tables_not_found"].append("ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE") + ddiff = DeepDiff(sort_lists(returned), sort_lists(expect), ignore_order=True) + assert not ddiff, ddiff + + def test_lag_type_interface(self, match_engine): + """ + Scenario: Test the flow fetching objs related to LAG_TYPE iface + """ + params = {Interface.ARG_NAME: "PortChannel1234", "namespace": ""} + m_intf = Interface(match_engine) + returned = m_intf.execute(params) + expect = create_template_dict(dbs=["CONFIG_DB", "APPL_DB", "ASIC_DB", "STATE_DB"]) + expect["CONFIG_DB"]["keys"].extend(["PORTCHANNEL_INTERFACE|PortChannel1234", "PORTCHANNEL_INTERFACE|PortChannel1234|7.7.7.1/24"]) + expect["APPL_DB"]["keys"].extend(["INTF_TABLE:PortChannel1234", "INTF_TABLE:PortChannel1234:7.7.7.1/24"]) + expect["STATE_DB"]["keys"].extend(["INTERFACE_TABLE|PortChannel1234", "INTERFACE_TABLE|PortChannel1234|7.7.7.1/24"]) + expect["ASIC_DB"]["keys"].append("ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005ec") + ddiff = DeepDiff(sort_lists(returned), sort_lists(expect), ignore_order=True) + assert not ddiff, ddiff + + def test_subintf_type_interface(self, match_engine): + """ + Scenario: Test the flow fetching objs related to Sub-Interface iface + """ + params = {Interface.ARG_NAME: "Eth0.1", "namespace": ""} + m_intf = Interface(match_engine) + returned = m_intf.execute(params) + expect = create_template_dict(dbs=["CONFIG_DB", "APPL_DB", "ASIC_DB", "STATE_DB"]) + expect["CONFIG_DB"]["keys"].extend(["VLAN_SUB_INTERFACE|Eth0.1", "VLAN_SUB_INTERFACE|Eth0.1|9.9.9.9/24"]) + expect["APPL_DB"]["keys"].extend(["INTF_TABLE:Eth0.1", "INTF_TABLE:Eth0.1:9.9.9.9/24"]) + expect["STATE_DB"]["keys"].extend(["INTERFACE_TABLE|Eth0.1", "INTERFACE_TABLE|Eth0.1|9.9.9.9/24"]) + expect["ASIC_DB"]["keys"].append("ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x60000000005e9") + ddiff = DeepDiff(sort_lists(returned), sort_lists(expect), ignore_order=True) + assert not ddiff, ddiff + + def test_no_interface(self, match_engine): + """ + Scenario: Test the flow fetching objs related to an interface which is not present + """ + params = {Interface.ARG_NAME: "Ethernet160", "namespace": ""} + m_intf = Interface(match_engine) + returned = m_intf.execute(params) + expect = create_template_dict(dbs=["CONFIG_DB", "APPL_DB", "ASIC_DB", "STATE_DB"]) + expect["CONFIG_DB"]["tables_not_found"].extend(["INTERFACE"]) + expect["APPL_DB"]["tables_not_found"].extend(["INTF_TABLE"]) + expect["STATE_DB"]["tables_not_found"].extend(["INTERFACE_TABLE"]) + expect["ASIC_DB"]["tables_not_found"].append("ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE") + ddiff = DeepDiff(sort_lists(returned), sort_lists(expect), ignore_order=True) + assert not ddiff, ddiff + + def test_invalid_interface(self, match_engine): + """ + Scenario: Test the flow fetching objs related to an interface which is invalid + """ + params = {Interface.ARG_NAME: "Whatever", "namespace": ""} + m_intf = Interface(match_engine) + returned = m_intf.execute(params) + expect = create_template_dict(dbs=["CONFIG_DB", "APPL_DB", "ASIC_DB", "STATE_DB"]) + expect["CONFIG_DB"]["tables_not_found"].extend(["INTERFACE", + "PORTCHANNEL_INTERFACE", + "VLAN_INTERFACE", + "VLAN_SUB_INTERFACE", + "LOOPBACK_INTERFACE"]) + expect["APPL_DB"]["tables_not_found"].extend(["INTF_TABLE"]) + expect["STATE_DB"]["tables_not_found"].extend(["INTERFACE_TABLE"]) + expect["ASIC_DB"]["tables_not_found"].append("ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE") + ddiff = DeepDiff(sort_lists(returned), sort_lists(expect), ignore_order=True) + assert not ddiff, ddiff + + def test_loopback_interface(self, match_engine): + """ + Scenario: Test the flow fetching objs related to loopback iface + """ + params = {Interface.ARG_NAME: "Loopback0", "namespace": ""} + m_intf = Interface(match_engine) + returned = m_intf.execute(params) + expect = create_template_dict(dbs=["CONFIG_DB", "APPL_DB", "ASIC_DB", "STATE_DB"]) + expect["CONFIG_DB"]["keys"].extend(["LOOPBACK_INTERFACE|Loopback0", "LOOPBACK_INTERFACE|Loopback0|10.1.0.1/32"]) + expect["APPL_DB"]["keys"].extend(["INTF_TABLE:Loopback0", "INTF_TABLE:Loopback0:10.1.0.1/32"]) + expect["STATE_DB"]["keys"].extend(["INTERFACE_TABLE|Loopback0", "INTERFACE_TABLE|Loopback0|10.1.0.1/32"]) + ddiff = DeepDiff(sort_lists(returned), sort_lists(expect), ignore_order=True) + assert not ddiff, ddiff + + def test_subintf_with_invalid_vlan(self, match_engine): + """ + Scenario: Test the flow fetching objs related to a subintf with invalid vlan + """ + params = {Interface.ARG_NAME: "Eth4.1", "namespace": ""} + m_intf = Interface(match_engine) + returned = m_intf.execute(params) + expect = create_template_dict(dbs=["CONFIG_DB", "APPL_DB", "ASIC_DB", "STATE_DB"]) + expect["CONFIG_DB"]["keys"].extend(["VLAN_SUB_INTERFACE|Eth4.1"]) + expect["APPL_DB"]["keys"].extend(["INTF_TABLE:Eth4.1"]) + expect["STATE_DB"]["tables_not_found"].extend(["INTERFACE_TABLE"]) + expect["ASIC_DB"]["tables_not_found"].extend(["ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE"]) + ddiff = DeepDiff(sort_lists(returned), sort_lists(expect), ignore_order=True) + assert not ddiff, ddiff + + def test_all_args(self, match_engine): + """ + Scenario: Verify Whether the get_all_args method is working as expected + """ + params = {} + m_port = Interface(match_engine) + returned = m_port.get_all_args("") + expect = ["Ethernet16", "Vlan10", "PortChannel1111", "PortChannel1234", "Eth0.1", "Loopback0", "Eth4.1"] + ddiff = DeepDiff(expect, returned, ignore_order=True) + assert not ddiff, ddiff