From b1b5b297e5ffb3e33306d0294f01d4e5c8159b8d Mon Sep 17 00:00:00 2001 From: mint570 <70396898+mint570@users.noreply.github.com> Date: Thu, 2 Dec 2021 15:25:15 -0800 Subject: [PATCH] Initial p4orch pytest code. (#2054) *Added p4orch VS pytest Co-authored-by: Runming Wu --- tests/p4rt/acl.py | 206 ++++ tests/p4rt/l3.py | 348 ++++++ tests/p4rt/test_l3.py | 1845 ++++++++++++++++++++++++++++++++ tests/p4rt/test_p4rt_acl.py | 1253 ++++++++++++++++++++++ tests/p4rt/test_p4rt_mirror.py | 220 ++++ tests/p4rt/util.py | 135 +++ 6 files changed, 4007 insertions(+) create mode 100644 tests/p4rt/acl.py create mode 100644 tests/p4rt/l3.py create mode 100644 tests/p4rt/test_l3.py create mode 100644 tests/p4rt/test_p4rt_acl.py create mode 100644 tests/p4rt/test_p4rt_mirror.py create mode 100644 tests/p4rt/util.py diff --git a/tests/p4rt/acl.py b/tests/p4rt/acl.py new file mode 100644 index 000000000000..283ba95ce665 --- /dev/null +++ b/tests/p4rt/acl.py @@ -0,0 +1,206 @@ +# Lint as: python3 +from swsscommon import swsscommon + +import util + +INGRESS_STAGE = "SAI_ACL_STAGE_INGRESS" +EGRESS_STAGE = "SAI_ACL_STAGE_EGRESS" +PRE_INGRESS_STAGE = "SAI_ACL_STAGE_PRE_INGRESS" + +class P4RtAclTableDefinitionWrapper(util.DBInterface): + """Interface to interact with APP DB and ASIC DB tables for P4RT ACL table definition object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE" + SAI_ATTR_MATCH_ETHER_TYPE = "SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE" + SAI_ATTR_MATCH_IP_TYPE = "SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE" + SAI_ATTR_MATCH_DST_MAC = "SAI_ACL_TABLE_ATTR_FIELD_DST_MAC" + SAI_ATTR_MATCH_SRC_IPV6_WORD3 = "SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD3" + SAI_ATTR_MATCH_SRC_IPV6_WORD2 = "SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2" + SAI_ATTR_MATCH_UDF_GROUP_MIN = "SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_MIN" + SAI_ATTR_MATCH_UDF_GROUP_1 = "SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_1" + SAI_ATTR_ACTION_TYPE_LIST = "SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST" + SAI_ACL_TABLE_ATTR_ACL_STAGE = "SAI_ACL_TABLE_ATTR_ACL_STAGE" + SAI_ACL_TABLE_ATTR_SIZE = "SAI_ACL_TABLE_ATTR_SIZE" + + # table name in APP_DB and attribute fields + APP_DB_TBL_NAME = swsscommon.APP_P4RT_TABLE_NAME + TBL_NAME = swsscommon.APP_P4RT_ACL_TABLE_DEFINITION_NAME + STAGE_FIELD = "stage" + PRIORITY_FIELD = "priority" + SIZE_FIELD = "size" + MATCH_FIELD_ETHER_TYPE = "match/ether_type" + MATCH_FIELD_ETHER_DST = "match/ether_dst" + MATCH_FIELD_IS_IP = "match/is_ip" + MATCH_FIELD_IS_IPV4 = "match/is_ipv4" + MATCH_FIELD_IS_IPV6 = "match/is_ipv6" + MATCH_FIELD_IS_ARP = "match/is_arp" + MATCH_FIELD_SRC_IPV6_64BIT = "match/src_ipv6_64bit" + MATCH_FIELD_ARP_TPA = "match/arp_tpa" + ACTION_COPY_AND_SET_TC = "action/copy_and_set_tc" + ACTION_PUNT_AND_SET_TC = "action/punt_and_set_tc" + ACTION_SET_QOS_QUEUE = "action/qos_queue" + METER_UNIT = "meter/unit" + COUNTER_UNIT = "counter/unit" + + +class P4RtAclRuleWrapper(util.DBInterface): + """Interface to interact with APP DB and ASIC DB tables for P4RT ACL entry object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY" + SAI_ATTR_TABLE_ID = "SAI_ACL_ENTRY_ATTR_TABLE_ID" + SAI_ATTR_PRIORITY = "SAI_ACL_ENTRY_ATTR_PRIORITY" + SAI_ATTR_ADMIN_STATE = "SAI_ACL_ENTRY_ATTR_ADMIN_STATE" + SAI_ATTR_SET_POLICER = "SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER" + SAI_ATTR_COUNTER = "SAI_ACL_ENTRY_ATTR_ACTION_COUNTER" + SAI_ATTR_MATCH_ETHER_TYPE = "SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE" + SAI_ATTR_MATCH_IP_TYPE = "SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE" + SAI_ATTR_MATCH_DST_MAC = "SAI_ACL_ENTRY_ATTR_FIELD_DST_MAC" + SAI_ATTR_MATCH_SRC_IPV6_WORD3 = "SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6_WORD3" + SAI_ATTR_MATCH_SRC_IPV6_WORD2 = "SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6_WORD2" + SAI_ATTR_MATCH_UDF_GROUP_MIN = "SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN" + SAI_ATTR_MATCH_UDF_GROUP_1 = "SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1" + SAI_ATTR_ACTION_PACKET_ACTION = "SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION" + SAI_ATTR_ACTION_SET_TC = "SAI_ACL_ENTRY_ATTR_ACTION_SET_TC" + SAI_ATTR_ACTION_SET_USER_TRAP_ID = "SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID" + + # table name in APP_DB and attribute fields + APP_DB_TBL_NAME = swsscommon.APP_P4RT_TABLE_NAME + ACTION = "action" + METER_CIR = "meter/cir" + METER_CBURST = "meter/cburst" + METER_PIR = "meter/pir" + METER_PBURST = "meter/pburst" + + +class P4RtAclCounterWrapper(util.DBInterface): + """Interface to interact with APP DB and ASIC DB tables for P4RT ACL counter object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_ACL_COUNTER" + SAI_ATTR_TABLE_ID = "SAI_ACL_COUNTER_ATTR_TABLE_ID" + SAI_ATTR_ENABLE_BYTE_COUNT = "SAI_ACL_COUNTER_ATTR_ENABLE_BYTE_COUNT" + SAI_ATTR_ENABLE_PACKET_COUNT = "SAI_ACL_COUNTER_ATTR_ENABLE_PACKET_COUNT" + + +class P4RtAclMeterWrapper(util.DBInterface): + """Interface in ASIC DB tables for P4RT ACL policer object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_POLICER" + SAI_ATTR_METER_TYPE = "SAI_POLICER_ATTR_METER_TYPE" + SAI_ATTR_METER_MODE = "SAI_POLICER_ATTR_MODE" + SAI_ATTR_METER_CBS = "SAI_POLICER_ATTR_CBS" + SAI_ATTR_METER_CIR = "SAI_POLICER_ATTR_CIR" + SAI_ATTR_METER_PBS = "SAI_POLICER_ATTR_PBS" + SAI_ATTR_METER_PIR = "SAI_POLICER_ATTR_PIR" + SAI_ATTR_GREEN_PACKET_ACTION = "SAI_POLICER_ATTR_GREEN_PACKET_ACTION" + SAI_ATTR_RED_PACKET_ACTION = "SAI_POLICER_ATTR_RED_PACKET_ACTION" + SAI_ATTR_YELLOW_PACKET_ACTION = "SAI_POLICER_ATTR_YELLOW_PACKET_ACTION" + + +class P4RtAclGroupWrapper(util.DBInterface): + """Interface in ASIC DB tables for P4RT ACL group object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP" + SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE = "SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE" + SAI_ACL_TABLE_GROUP_ATTR_TYPE = "SAI_ACL_TABLE_GROUP_ATTR_TYPE" + SAI_ACL_TABLE_ATTR_ACL_BIND_POINT_TYPE_LIST = "SAI_ACL_TABLE_ATTR_ACL_BIND_POINT_TYPE_LIST" + + def get_group_oids_by_stage(self, stage): + tbl = swsscommon.Table(self.asic_db, self.ASIC_DB_TBL_NAME) + keys = tbl.getKeys() + group_oids = [] + for key in keys: + (status, fvs) = tbl.get(key) + assert status == True + for name, val in fvs: + if name == self.SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE and val == stage: + group_oids.append(key) + break + return group_oids + + +class P4RtAclGroupMemberWrapper(util.DBInterface): + """Interface in ASIC DB tables for P4RT ACL group member object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER" + SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID = "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID" + SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID = "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID" + SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY = "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY" + + +class P4RtUserDefinedTrapWrapper(util.DBInterface): + """Interface in ASIC DB tables for SAI user defined trap object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP" + SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TRAP_GROUP = "SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TRAP_GROUP" + SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TYPE = "SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TYPE" + + +class P4RtTrapGroupWrapper(util.DBInterface): + """Interface in APPL and ASIC DB tables for SAI trap group object.""" + + # table name in APPL_DB and attribute fields + APP_DB_TBL_NAME = "COPP_TABLE" + TBL_NAME_PREFIX = "trap.group.cpu.queue." + QUEUE = "queue" + HOSTIF_NAME = "genetlink_name" + HOSTIF_GENETLINK_MCGRP_NAME = "genetlink_mcgrp_name" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TRAP_GROUP" + SAI_HOSTIF_TRAP_GROUP_ATTR_QUEUE = "SAI_HOSTIF_TRAP_GROUP_ATTR_QUEUE" + + +class P4RtHostifWrapper(util.DBInterface): + """Interface in ASIC DB tables for SAI hostif object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF" + SAI_HOSTIF_ATTR_TYPE = "SAI_HOSTIF_ATTR_TYPE" + SAI_HOSTIF_ATTR_NAME = "SAI_HOSTIF_ATTR_NAME" + SAI_HOSTIF_ATTR_GENETLINK_MCGRP_NAME = "SAI_HOSTIF_ATTR_GENETLINK_MCGRP_NAME" + + +class P4RtHostifTableEntryWrapper(util.DBInterface): + """Interface in ASIC DB tables for SAI hostif table entry object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF_TABLE_ENTRY" + SAI_HOSTIF_TABLE_ENTRY_ATTR_TYPE = "SAI_HOSTIF_TABLE_ENTRY_ATTR_TYPE" + SAI_HOSTIF_TABLE_ENTRY_ATTR_TRAP_ID = "SAI_HOSTIF_TABLE_ENTRY_ATTR_TRAP_ID" + SAI_HOSTIF_TABLE_ENTRY_ATTR_CHANNEL_TYPE = "SAI_HOSTIF_TABLE_ENTRY_ATTR_CHANNEL_TYPE" + SAI_HOSTIF_TABLE_ENTRY_ATTR_HOST_IF = "SAI_HOSTIF_TABLE_ENTRY_ATTR_HOST_IF" + +class P4RtUdfGroupWrapper(util.DBInterface): + """Interface in ASIC DB tables for SAI UDF Group object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_UDF_GROUP" + SAI_UDF_GROUP_ATTR_TYPE = "SAI_UDF_GROUP_ATTR_TYPE" + SAI_UDF_GROUP_ATTR_LENGTH = "SAI_UDF_GROUP_ATTR_LENGTH" + + SAI_UDF_GROUP_TYPE_GENERIC = "SAI_UDF_GROUP_TYPE_GENERIC" + + +class P4RtUdfMatchWrapper(util.DBInterface): + """Interface in ASIC DB tables for SAI UDF Match object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_UDF_MATCH" + + +class P4RtUdfWrapper(util.DBInterface): + """Interface in ASIC DB tables for SAI UDF object.""" + + # table name in ASIC_DB and SAI constants + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_UDF" + SAI_UDF_ATTR_MATCH_ID = "SAI_UDF_ATTR_MATCH_ID" + SAI_UDF_ATTR_GROUP_ID = "SAI_UDF_ATTR_GROUP_ID" + SAI_UDF_ATTR_BASE = "SAI_UDF_ATTR_BASE" + SAI_UDF_ATTR_OFFSET = "SAI_UDF_ATTR_OFFSET" diff --git a/tests/p4rt/l3.py b/tests/p4rt/l3.py new file mode 100644 index 000000000000..c5f656aa2efd --- /dev/null +++ b/tests/p4rt/l3.py @@ -0,0 +1,348 @@ +from swsscommon import swsscommon + +import util +import json + + +class P4RtRouterInterfaceWrapper(util.DBInterface): + """Interface to interact with APP DB and ASIC DB tables for P4RT router interface object.""" + + # database and SAI constants + APP_DB_TBL_NAME = swsscommon.APP_P4RT_TABLE_NAME + TBL_NAME = swsscommon.APP_P4RT_ROUTER_INTERFACE_TABLE_NAME + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE" + SAI_ATTR_SRC_MAC = "SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS" + SAI_ATTR_TYPE = "SAI_ROUTER_INTERFACE_ATTR_TYPE" + SAI_ATTR_TYPE_PORT = "SAI_ROUTER_INTERFACE_TYPE_PORT" + SAI_ATTR_MTU = "SAI_ROUTER_INTERFACE_ATTR_MTU" + SAI_ATTR_PORT_ID = "SAI_ROUTER_INTERFACE_ATTR_PORT_ID" + SAI_ATTR_DEFAULT_MTU = "9100" + + # attribute fields for router interface object + PORT_FIELD = "port" + SRC_MAC_FIELD = "src_mac" + + # default router interface attribute values + DEFAULT_ROUTER_INTERFACE_ID = "16" + DEFAULT_PORT_ID = "Ethernet8" + DEFAULT_SRC_MAC = "00:11:22:33:44:55" + DEFAULT_ACTION = "set_port_and_src_mac" + + def generate_app_db_key(self, router_interface_id): + d = {} + d[util.prepend_match_field("router_interface_id") + ] = router_interface_id + key = json.dumps(d, separators=(",", ":")) + return self.TBL_NAME + ":" + key + + # create default router interface + def create_router_interface(self, + router_interace_id=None, port_id=None, + src_mac=None, action=None): + router_interface_id = router_interace_id or self.DEFAULT_ROUTER_INTERFACE_ID + port_id = port_id or self.DEFAULT_PORT_ID + src_mac = src_mac or self.DEFAULT_SRC_MAC + action = action or self.DEFAULT_ACTION + attr_list = [(util.prepend_param_field(self.PORT_FIELD), port_id), + (util.prepend_param_field(self.SRC_MAC_FIELD), src_mac), + (self.ACTION_FIELD, action)] + router_intf_key = self.generate_app_db_key(router_interface_id) + self.set_app_db_entry(router_intf_key, attr_list) + return router_interface_id, router_intf_key, attr_list + + +class P4RtNeighborWrapper(util.DBInterface): + """Interface to interact with APP DB and ASIC DB tables for P4RT neighbor object.""" + + # database and SAI constants + APP_DB_TBL_NAME = swsscommon.APP_P4RT_TABLE_NAME + TBL_NAME = swsscommon.APP_P4RT_NEIGHBOR_TABLE_NAME + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_NEIGHBOR_ENTRY" + SAI_ATTR_DST_MAC = "SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS" + + # attribute fields for neighbor object + DST_MAC_FIELD = "dst_mac" + + # default neighbor attribute values + DEFAULT_ROUTER_INTERFACE_ID = "16" + DEFAULT_IPV4_NEIGHBOR_ID = "12.0.0.1" + DEFAULT_IPV6_NEIGHBOR_ID = "fe80::21a:11ff:fe17:5f80" + DEFAULT_DST_MAC = "00:02:03:04:05:06" + DEFAULT_ACTION = "set_dst_mac" + + def generate_app_db_key(self, router_interface_id, neighbor_id): + d = {} + d[util.prepend_match_field("router_interface_id") + ] = router_interface_id + d[util.prepend_match_field("neighbor_id")] = neighbor_id + key = json.dumps(d, separators=(",", ":")) + return self.TBL_NAME + ":" + key + + # create default neighbor + def create_neighbor(self, router_interface_id=None, neighbor_id=None, + dst_mac=None, action=None, ipv4=True): + router_interface_id = router_interface_id or self.DEFAULT_ROUTER_INTERFACE_ID + neighbor_id = neighbor_id or (self.DEFAULT_IPV4_NEIGHBOR_ID if ipv4 + else self.DEFAULT_IPV6_NEIGHBOR_ID) + dst_mac = dst_mac or self.DEFAULT_DST_MAC + action = action or self.DEFAULT_ACTION + attr_list = [(util.prepend_param_field(self.DST_MAC_FIELD), dst_mac), + (self.ACTION_FIELD, action)] + neighbor_key = self.generate_app_db_key( + router_interface_id, neighbor_id) + self.set_app_db_entry(neighbor_key, attr_list) + return neighbor_id, neighbor_key, attr_list + + +class P4RtNextHopWrapper(util.DBInterface): + """Interface to interact with APP DB and ASIC DB tables for P4RT nexthop object.""" + + # database and SAI constants + APP_DB_TBL_NAME = swsscommon.APP_P4RT_TABLE_NAME + TBL_NAME = swsscommon.APP_P4RT_NEXTHOP_TABLE_NAME + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP" + SAI_ATTR_TYPE = "SAI_NEXT_HOP_ATTR_TYPE" + SAI_ATTR_IP = "SAI_NEXT_HOP_ATTR_IP" + SAI_ATTR_ROUTER_INTF_OID = "SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID" + + # attribute fields for nexthop object + RIF_FIELD = "router_interface_id" + NEIGHBOR_ID_FIELD = "neighbor_id" + + # default next hop attribute values + DEFAULT_ACTION = "set_nexthop" + DEFAULT_NEXTHOP_ID = "8" + DEFAULT_ROUTER_INTERFACE_ID = "16" + DEFAULT_IPV4_NEIGHBOR_ID = "12.0.0.1" + DEFAULT_IPV6_NEIGHBOR_ID = "fe80::21a:11ff:fe17:5f80" + + def generate_app_db_key(self, nexthop_id): + d = {} + d[util.prepend_match_field("nexthop_id")] = nexthop_id + key = json.dumps(d, separators=(",", ":")) + return self.TBL_NAME + ":" + key + + # create default next hop + def create_next_hop(self, router_interface_id=None, neighbor_id=None, + action=None, nexthop_id=None, ipv4=True): + action = action or self.DEFAULT_ACTION + router_interface_id = router_interface_id or self.DEFAULT_ROUTER_INTERFACE_ID + if ipv4 is True: + neighbor_id = neighbor_id or self.DEFAULT_IPV4_NEIGHBOR_ID + else: + neighbor_id = neighbor_id or self.DEFAULT_IPV6_NEIGHBOR_ID + nexthop_id = nexthop_id or self.DEFAULT_NEXTHOP_ID + attr_list = [(util.prepend_param_field(self.RIF_FIELD), router_interface_id), + (util.prepend_param_field(self.NEIGHBOR_ID_FIELD), neighbor_id), + (self.ACTION_FIELD, action)] + nexthop_key = self.generate_app_db_key(nexthop_id) + self.set_app_db_entry(nexthop_key, attr_list) + return nexthop_id, nexthop_key, attr_list + + # Fetch oid of the first newly created nexthop from created nexthops in ASIC + # db. This API should only be used when only one oid is expected to be + # created after the original entries. + # Original nexthop entries in asic db must be fetched using + # 'get_original_redis_entries' before fetching oid of newly created nexthop. + def get_newly_created_nexthop_oid(self): + nexthop_oid = None + nexthop_entries = util.get_keys(self.asic_db, self.ASIC_DB_TBL_NAME) + for key in nexthop_entries: + if key not in self._original_entries["{}:{}".format(self.asic_db, + self.ASIC_DB_TBL_NAME)]: + nexthop_oid = key + break + return nexthop_oid + + +class P4RtWcmpGroupWrapper(util.DBInterface): + """Interface to interact with APP DB and ASIC DB tables for P4RT wcmp group object.""" + + # database and SAI constants + APP_DB_TBL_NAME = swsscommon.APP_P4RT_TABLE_NAME + TBL_NAME = swsscommon.APP_P4RT_WCMP_GROUP_TABLE_NAME + ASIC_DB_GROUP_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP" + SAI_ATTR_GROUP_TYPE = "SAI_NEXT_HOP_GROUP_ATTR_TYPE" + SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP = "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP" + ASIC_DB_GROUP_MEMBER_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER" + SAI_ATTR_GROUP_MEMBER_NEXTHOP_GROUP_ID = "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID" + SAI_ATTR_GROUP_MEMBER_NEXTHOP_ID = "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID" + SAI_ATTR_GROUP_MEMBER_WEIGHT = "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT" + + # attribute fields for wcmp group object + NEXTHOP_ID_FIELD = "nexthop_id" + WEIGHT_FIELD = "weight" + WATCH_PORT_FIELD = "watch_port" + ACTION_FIELD = "action" + ACTIONS_FIELD = "actions" + + # default wcmp group attributes + DEFAULT_WCMP_GROUP_ID = "group-a" + DEFAULT_WEIGHT = 2 + DEFAULT_ACTION = "set_nexthop_id" + DEFAULT_NEXTHOP_ID = "8" + DEFAULT_WATCH_PORT = "" + + # Fetch the oid of the first newly created wcmp group from created wcmp groups + # in AISC db. This API should only be used when only one oid is expected to be + # created after the original entries. + # Original wcmp group entries in asic db must be fetched using + # 'get_original_redis_entries' before fetching oid of newly created wcmp group. + def get_newly_created_wcmp_group_oid(self): + wcmp_group_oid = None + wcmp_group_entries = util.get_keys( + self.asic_db, self.ASIC_DB_GROUP_TBL_NAME) + for key in wcmp_group_entries: + if key not in self._original_entries["{}:{}".format( + self.asic_db, self.ASIC_DB_GROUP_TBL_NAME)]: + wcmp_group_oid = key + break + return wcmp_group_oid + + # Fetch key for the first newly created wcmp group member from created group + # members in ASIC db. This API should only be used when only one key is + # expected to be created after the original entries. + # Original wcmp group member entries in asic db must be fetched using + # 'get_original_redis_entries' before fetching asic db key of newly created + # wcmp group member. + def get_newly_created_wcmp_group_member_asic_db_key(self): + asic_db_wcmp_group_member_key = None + wcmp_group_member_entries = util.get_keys(self.asic_db, + self.ASIC_DB_GROUP_MEMBER_TBL_NAME) + for key in wcmp_group_member_entries: + if key not in self._original_entries["{}:{}".format( + self.asic_db, self.ASIC_DB_GROUP_MEMBER_TBL_NAME)]: + asic_db_wcmp_group_member_key = key + break + return asic_db_wcmp_group_member_key + + def generate_app_db_key(self, group_id): + d = {} + d[util.prepend_match_field("wcmp_group_id")] = group_id + key = json.dumps(d, separators=(",", ":")) + return self.TBL_NAME + ":" + key + + # create default wcmp group + def create_wcmp_group(self, nexthop_id=None, wcmp_group_id=None, + action=None, weight=None, watch_port=None): + wcmp_group_id = wcmp_group_id or self.DEFAULT_WCMP_GROUP_ID + weight = weight or self.DEFAULT_WEIGHT + action = action or self.DEFAULT_ACTION + nexthop_id = nexthop_id or self.DEFAULT_NEXTHOP_ID + watch_port = watch_port or self.DEFAULT_WATCH_PORT + action1 = {util.prepend_param_field(self.NEXTHOP_ID_FIELD): nexthop_id, + self.WEIGHT_FIELD: weight, self.ACTION_FIELD: action, + self.WATCH_PORT_FIELD: watch_port} + actions = [action1] + attr_list = [(self.ACTIONS_FIELD, json.dumps(actions))] + wcmp_group_key = self.generate_app_db_key(wcmp_group_id) + self.set_app_db_entry(wcmp_group_key, attr_list) + return wcmp_group_id, wcmp_group_key, attr_list + + def get_original_appl_db_entries_count(self): + return len(self._original_entries["%s:%s" % (self.appl_db, + (self.APP_DB_TBL_NAME + ":" + + self.TBL_NAME))]) + + def get_original_appl_state_db_entries_count(self): + return len(self._original_entries["%s:%s" % (self.appl_state_db, + (self.APP_DB_TBL_NAME + ":" + + self.TBL_NAME))]) + + def get_original_asic_db_group_entries_count(self): + return len(self._original_entries["%s:%s" % (self.asic_db, + self.ASIC_DB_GROUP_TBL_NAME)]) + + def get_original_asic_db_member_entries_count(self): + return len(self._original_entries["%s:%s" % (self.asic_db, + self.ASIC_DB_GROUP_MEMBER_TBL_NAME)]) + + +class P4RtRouteWrapper(util.DBInterface): + """Interface to interact with APP DB and ASIC DB tables for P4RT route object.""" + + # database and SAI constants + APP_DB_TBL_NAME = swsscommon.APP_P4RT_TABLE_NAME + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY" + SAI_ATTR_PACKET_ACTION = "SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION" + SAI_ATTR_PACKET_ACTION_FORWARD = "SAI_PACKET_ACTION_FORWARD" + SAI_ATTR_PACKET_ACTION_DROP = "SAI_PACKET_ACTION_DROP" + SAI_ATTR_NEXTHOP_ID = "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID" + + # attribute fields for route object + NEXTHOP_ID_FIELD = "nexthop_id" + WCMP_GROUP_ID_FIELD = "wcmp_group_id" + + # default route attribute values + DEFAULT_ACTION = "set_nexthop_id" + DEFAULT_NEXTHOP_ID = "8" + DEFAULT_WCMP_GROUP_ID = "group-a" + DEFAULT_VRF_ID = "b4-traffic" + DEFAULT_DST = "10.11.12.0/24" + + def generate_app_db_key(self, vrf_id, dst): + assert self.ip_type is not None + d = {} + d[util.prepend_match_field("vrf_id")] = vrf_id + if self.ip_type == "IPV4": + d[util.prepend_match_field("ipv4_dst")] = dst + else: + d[util.prepend_match_field("ipv6_dst")] = dst + key = json.dumps(d, separators=(",", ":")) + return self.TBL_NAME + ":" + key + + def set_ip_type(self, ip_type): + assert ip_type in ("IPV4", "IPV6") + self.ip_type = ip_type + self.TBL_NAME = "FIXED_" + ip_type + "_TABLE" + + # Create default route. + def create_route(self, nexthop_id=None, wcmp_group_id=None, action=None, + vrf_id=None, dst=None): + action = action or self.DEFAULT_ACTION + vrf_id = vrf_id or self.DEFAULT_VRF_ID + dst = dst or self.DEFAULT_DST + if action == "set_wcmp_group_id": + wcmp_group_id = wcmp_group_id or self.DEFAULT_WCMP_GROUP_ID + attr_list = [(self.ACTION_FIELD, action), + (util.prepend_param_field( + self.WCMP_GROUP_ID_FIELD), wcmp_group_id)] + elif action == "set_nexthop_id": + nexthop_id = nexthop_id or self.DEFAULT_NEXTHOP_ID + attr_list = [(self.ACTION_FIELD, action), + (util.prepend_param_field(self.NEXTHOP_ID_FIELD), + nexthop_id)] + else: + attr_list = [(self.ACTION_FIELD, action)] + route_key = self.generate_app_db_key(vrf_id, dst) + self.set_app_db_entry(route_key, attr_list) + return route_key, attr_list + + # Fetch the asic_db_key for the first newly created route entry from created + # routes in ASIC db. This API should only be used when only one key is + # expected to be created after original entries. + # Original route entries in asic db must be fetched using + # 'get_original_redis_entries' before fetching asic db key of newly created + # route. + def get_newly_created_asic_db_key(self): + route_entries = util.get_keys(self.asic_db, self.ASIC_DB_TBL_NAME) + for key in route_entries: + if key not in self._original_entries["%s:%s" % (self.asic_db, + self.ASIC_DB_TBL_NAME)]: + asic_db_key = key + break + return asic_db_key + + def get_original_appl_db_entries_count(self): + return len(self._original_entries["%s:%s" % (self.appl_db, + (self.APP_DB_TBL_NAME + ":" + + self.TBL_NAME))]) + + def get_original_appl_state_db_entries_count(self): + return len(self._original_entries["%s:%s" % (self.appl_state_db, + (self.APP_DB_TBL_NAME + ":" + + self.TBL_NAME))]) + + def get_original_asic_db_entries_count(self): + return len(self._original_entries["%s:%s" % (self.asic_db, + self.ASIC_DB_TBL_NAME)]) diff --git a/tests/p4rt/test_l3.py b/tests/p4rt/test_l3.py new file mode 100644 index 000000000000..dbd6ae9781c6 --- /dev/null +++ b/tests/p4rt/test_l3.py @@ -0,0 +1,1845 @@ +from swsscommon import swsscommon + +import pytest +import json +import util +import l3 +import test_vrf + + +class TestP4RTL3(object): + + def _set_up(self, dvs): + self._p4rt_router_intf_obj = l3.P4RtRouterInterfaceWrapper() + self._p4rt_neighbor_obj = l3.P4RtNeighborWrapper() + self._p4rt_nexthop_obj = l3.P4RtNextHopWrapper() + self._p4rt_route_obj = l3.P4RtRouteWrapper() + self._p4rt_wcmp_group_obj = l3.P4RtWcmpGroupWrapper() + self._vrf_obj = test_vrf.TestVrf() + + self._p4rt_router_intf_obj.set_up_databases(dvs) + self._p4rt_neighbor_obj.set_up_databases(dvs) + self._p4rt_nexthop_obj.set_up_databases(dvs) + self._p4rt_route_obj.set_up_databases(dvs) + self._p4rt_wcmp_group_obj.set_up_databases(dvs) + self.response_consumer = swsscommon.NotificationConsumer( + self._p4rt_route_obj.appl_db, "APPL_DB_P4RT_TABLE_RESPONSE_CHANNEL") + + def _set_vrf(self, dvs): + # Create VRF. + self._vrf_obj.setup_db(dvs) + self.vrf_id = "b4-traffic" + self.vrf_state = self._vrf_obj.vrf_create(dvs, self.vrf_id, [], {}) + + def _clean_vrf(self, dvs): + # Remove VRF. + self._vrf_obj.vrf_remove(dvs, self.vrf_id, self.vrf_state) + + def test_IPv4RouteWithNexthopAddUpdateDeletePass(self, dvs, testlog): + # Initialize L3 objects and database connectors. + self._set_up(dvs) + self._set_vrf(dvs) + + # Set IP type for route object. + self._p4rt_route_obj.set_ip_type("IPV4") + + # Maintain list of original Application and ASIC DB entries before + # adding new route. + db_list = ((self._p4rt_nexthop_obj.asic_db, + self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME),) + self._p4rt_nexthop_obj.get_original_redis_entries(db_list) + db_list = ((self._p4rt_route_obj.appl_db, + "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, + self._p4rt_route_obj.TBL_NAME)), + (self._p4rt_route_obj.appl_state_db, + "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, + self._p4rt_route_obj.TBL_NAME)), + (self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME)) + self._p4rt_route_obj.get_original_redis_entries(db_list) + + # Fetch the original key to oid information from Redis DB. + key_to_oid_helper = util.KeyToOidDBHelper(dvs) + _, original_key_oid_info = key_to_oid_helper.get_db_info() + + # Create router interface. + router_interface_id, router_intf_key, attr_list = ( + self._p4rt_router_intf_obj.create_router_interface() + ) + util.verify_response(self.response_consumer, router_intf_key, + attr_list, "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count = 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create neighbor. + neighbor_id, neighbor_key, attr_list = ( + self._p4rt_neighbor_obj.create_neighbor() + ) + util.verify_response(self.response_consumer, neighbor_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create nexthop. + nexthop_id, nexthop_key, attr_list = ( + self._p4rt_nexthop_obj.create_next_hop() + ) + util.verify_response(self.response_consumer, nexthop_key, attr_list, + "SWSS_RC_SUCCESS") + # get nexthop_oid of newly created nexthop + nexthop_oid = self._p4rt_nexthop_obj.get_newly_created_nexthop_oid() + assert nexthop_oid is not None + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create route entry. + route_key, attr_list = self._p4rt_route_obj.create_route(nexthop_id) + util.verify_response(self.response_consumer, route_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Query application database for route entries. + route_entries = util.get_keys( + self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for newly created route key. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query application state database for route entries. + state_route_entries = util.get_keys( + self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(state_route_entries) == ( + self._p4rt_route_obj.get_original_appl_state_db_entries_count() + 1 + ) + + # Query application state database for newly created route key. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query ASIC database for route entries. + route_entries = util.get_keys(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_asic_db_entries_count() + 1 + ) + + # Query ASIC database for newly created route key. + asic_db_key = self._p4rt_route_obj.get_newly_created_asic_db_key() + assert asic_db_key is not None + (status, fvs) = util.get_key(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME, + asic_db_key) + assert status == True + attr_list = [(self._p4rt_route_obj.SAI_ATTR_NEXTHOP_ID, nexthop_oid)] + util.verify_attr(fvs, attr_list) + + # Update route entry. + route_key, attr_list = self._p4rt_route_obj.create_route(action="drop") + util.verify_response(self.response_consumer, route_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count did not change in Redis DB. + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Query application database for route entries. + route_entries = util.get_keys( + self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for the updated route key. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == True + attr_list_appl_db = [(self._p4rt_route_obj.ACTION_FIELD, "drop"), + (util.prepend_param_field(self._p4rt_route_obj.NEXTHOP_ID_FIELD), nexthop_id)] + util.verify_attr(fvs, attr_list_appl_db) + + # Query application state database for route entries. + state_route_entries = util.get_keys( + self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(state_route_entries) == ( + self._p4rt_route_obj.get_original_appl_state_db_entries_count() + 1 + ) + + # Query application state database for the updated route key. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query ASIC database for route entries. + route_entries = util.get_keys(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_asic_db_entries_count() + 1 + ) + + # Query ASIC database for the updated route key. + asic_db_key = self._p4rt_route_obj.get_newly_created_asic_db_key() + assert asic_db_key is not None + (status, fvs) = util.get_key(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME, + asic_db_key) + assert status == True + attr_list = [(self._p4rt_route_obj.SAI_ATTR_NEXTHOP_ID, "oid:0x0"), + (self._p4rt_route_obj.SAI_ATTR_PACKET_ACTION, self._p4rt_route_obj.SAI_ATTR_PACKET_ACTION_DROP)] + util.verify_attr(fvs, attr_list) + + # Remove route entry. + self._p4rt_route_obj.remove_app_db_entry(route_key) + util.verify_response( + self.response_consumer, route_key, [], "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Remove nexthop. + self._p4rt_nexthop_obj.remove_app_db_entry(nexthop_key) + util.verify_response(self.response_consumer, nexthop_key, [], + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Remove neighbor. + self._p4rt_neighbor_obj.remove_app_db_entry(neighbor_key) + util.verify_response(self.response_consumer, neighbor_key, [], + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Remove router interface. + self._p4rt_router_intf_obj.remove_app_db_entry(router_intf_key) + util.verify_response( + self.response_consumer, router_intf_key, [], "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count is same as the original count. + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + + # Query application database for route entries. + route_entries = util.get_keys( + self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_appl_db_entries_count() + ) + + # Verify that the route_key no longer exists in application database. + (status, fsv) = util.get_key(self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == False + + # Query application state database for route entries. + state_route_entries = util.get_keys( + self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(state_route_entries) == ( + self._p4rt_route_obj.get_original_appl_state_db_entries_count() + ) + + # Verify that the route_key no longer exists in application state + # database. + (status, fsv) = util.get_key(self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == False + + # Query ASIC database for route entries. + route_entries = util.get_keys(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_asic_db_entries_count() + ) + + # Verify that removed route no longer exists in ASIC database. + (status, fvs) = util.get_key(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME, + asic_db_key) + assert status == False + self._clean_vrf(dvs) + + def test_IPv6WithWcmpRouteAddUpdateDeletePass(self, dvs, testlog): + # Initialize L3 objects and database connectors. + self._set_up(dvs) + self._set_vrf(dvs) + + # Set IP type for route object. + self._p4rt_route_obj.set_ip_type("IPV6") + + # Maintain list of original Application and ASIC DB entries before + # adding new route. + db_list = ((self._p4rt_route_obj.appl_db, + "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, + self._p4rt_route_obj.TBL_NAME)), + (self._p4rt_route_obj.appl_state_db, + "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, + self._p4rt_route_obj.TBL_NAME)), + (self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME)) + self._p4rt_route_obj.get_original_redis_entries(db_list) + db_list = ((self._p4rt_nexthop_obj.asic_db, + self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME),) + self._p4rt_nexthop_obj.get_original_redis_entries(db_list) + db_list = ((self._p4rt_wcmp_group_obj.appl_db, + "%s:%s" % (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + self._p4rt_wcmp_group_obj.TBL_NAME)), + (self._p4rt_wcmp_group_obj.appl_state_db, + "%s:%s" % (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + self._p4rt_wcmp_group_obj.TBL_NAME)), + (self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME), + (self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME)) + self._p4rt_wcmp_group_obj.get_original_redis_entries(db_list) + + # Fetch the original key to oid information from Redis DB. + key_to_oid_helper = util.KeyToOidDBHelper(dvs) + _, original_key_oid_info = key_to_oid_helper.get_db_info() + + # Create router interface. + router_interface_id, router_intf_key, attr_list = ( + self._p4rt_router_intf_obj.create_router_interface() + ) + util.verify_response(self.response_consumer, router_intf_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count = 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create neighbor. + neighbor_id, neighbor_key, attr_list = ( + self._p4rt_neighbor_obj.create_neighbor(ipv4=False) + ) + util.verify_response(self.response_consumer, neighbor_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create nexthop. + nexthop_id, nexthop_key, attr_list = ( + self._p4rt_nexthop_obj.create_next_hop(ipv4=False) + ) + util.verify_response(self.response_consumer, nexthop_key, attr_list, + "SWSS_RC_SUCCESS") + # Get the oid of the newly created nexthop. + nexthop_oid = self._p4rt_nexthop_obj.get_newly_created_nexthop_oid() + assert nexthop_oid is not None + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create wcmp group. + wcmp_group_id, wcmp_group_key, attr_list = ( + self._p4rt_wcmp_group_obj.create_wcmp_group() + ) + util.verify_response(self.response_consumer, wcmp_group_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 2 in Redis DB + # (1 each for WCMP group and member). + count += 2 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Query application database for wcmp group entries. + wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for newly created wcmp group key. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query application state database for wcmp group entries. + state_wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(state_wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + + 1 + ) + + # Query application state database for newly created wcmp group key. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query ASIC database for wcmp group entries. + wcmp_group_entries = util.get_keys(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_group_entries_count() + + 1 + ) + + # Query ASIC database for newly created wcmp group oid. + wcmp_group_oid = self._p4rt_wcmp_group_obj.get_newly_created_wcmp_group_oid() + assert wcmp_group_oid is not None + attr_list = [(self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_TYPE, + self._p4rt_wcmp_group_obj.SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP)] + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, + wcmp_group_oid) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query ASIC database for wcmp group member entries. + wcmp_group_member_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME) + assert len(wcmp_group_member_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + + 1 + ) + + # Query ASIC database for newly crated wcmp group member key. + asic_db_group_member_key = ( + self._p4rt_wcmp_group_obj.get_newly_created_wcmp_group_member_asic_db_key() + ) + assert asic_db_group_member_key is not None + attr_list = [(self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_NEXTHOP_GROUP_ID, + wcmp_group_oid), + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_NEXTHOP_ID, + nexthop_oid), + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_WEIGHT, + str(self._p4rt_wcmp_group_obj.DEFAULT_WEIGHT))] + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME, + asic_db_group_member_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Create route entry. + route_key, attr_list = self._p4rt_route_obj.create_route( + wcmp_group_id=wcmp_group_id, action="set_wcmp_group_id", dst="2001:db8::/32") + util.verify_response(self.response_consumer, route_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Query application database for route entries. + route_entries = util.get_keys( + self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for newly created route key. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query application state database for route entries. + state_route_entries = util.get_keys( + self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(state_route_entries) == ( + self._p4rt_route_obj.get_original_appl_state_db_entries_count() + 1 + ) + + # Query application state database for newly created route key. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query ASIC database for route entries. + route_entries = util.get_keys(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_asic_db_entries_count() + 1 + ) + + # Query ASIC database for newly created route key. + asic_db_key = self._p4rt_route_obj.get_newly_created_asic_db_key() + assert asic_db_key is not None + (status, fvs) = util.get_key(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME, + asic_db_key) + assert status == True + attr_list = [ + (self._p4rt_route_obj.SAI_ATTR_NEXTHOP_ID, wcmp_group_oid)] + util.verify_attr(fvs, attr_list) + + # Update route entry. + route_key, attr_list = self._p4rt_route_obj.create_route( + action="drop", dst="2001:db8::/32") + util.verify_response(self.response_consumer, route_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count did not change in Redis DB. + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Query application database for route entries. + route_entries = util.get_keys( + self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for the updated route key. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == True + attr_list_appl_db = [(self._p4rt_route_obj.ACTION_FIELD, "drop"), + (util.prepend_param_field(self._p4rt_route_obj.WCMP_GROUP_ID_FIELD), wcmp_group_id)] + util.verify_attr(fvs, attr_list_appl_db) + + # Query application state database for route entries. + state_route_entries = util.get_keys( + self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(state_route_entries) == ( + self._p4rt_route_obj.get_original_appl_state_db_entries_count() + 1 + ) + + # Query application state database for the updated route key. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query ASIC database for route entries. + route_entries = util.get_keys(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_asic_db_entries_count() + 1 + ) + + # Query ASIC database for the updated route key. + asic_db_key = self._p4rt_route_obj.get_newly_created_asic_db_key() + assert asic_db_key is not None + (status, fvs) = util.get_key(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME, + asic_db_key) + assert status == True + attr_list = [(self._p4rt_route_obj.SAI_ATTR_NEXTHOP_ID, "oid:0x0"), + (self._p4rt_route_obj.SAI_ATTR_PACKET_ACTION, self._p4rt_route_obj.SAI_ATTR_PACKET_ACTION_DROP)] + util.verify_attr(fvs, attr_list) + + # Remove route entry. + self._p4rt_route_obj.remove_app_db_entry(route_key) + util.verify_response( + self.response_consumer, route_key, [], "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Remove wcmp group entry. + self._p4rt_wcmp_group_obj.remove_app_db_entry(wcmp_group_key) + util.verify_response(self.response_consumer, wcmp_group_key, [], + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count decremented by 2 in Redis DB + # (1 each for WCMP group and member). + count -= 2 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Remove nexthop. + self._p4rt_nexthop_obj.remove_app_db_entry(nexthop_key) + util.verify_response(self.response_consumer, nexthop_key, [], + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Remove neighbor. + self._p4rt_neighbor_obj.remove_app_db_entry(neighbor_key) + util.verify_response(self.response_consumer, neighbor_key, [], + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Remove router interface. + self._p4rt_router_intf_obj.remove_app_db_entry(router_intf_key) + util.verify_response( + self.response_consumer, router_intf_key, [], "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count is same as original count. + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + + # Query application database for route entries. + route_entries = util.get_keys( + self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_appl_db_entries_count() + ) + + # Verify that the route_key no longer exists in application database. + (status, fsv) = util.get_key(self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == False + + # Query application state database for route entries. + state_route_entries = util.get_keys( + self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(state_route_entries) == ( + self._p4rt_route_obj.get_original_appl_state_db_entries_count() + ) + + # Verify that the route_key no longer exists in application state + # database. + (status, fsv) = util.get_key(self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == False + + # Query ASIC database for route entries. + route_entries = util.get_keys(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_asic_db_entries_count() + ) + + # Verify that removed route no longer exists in ASIC database. + (status, fvs) = util.get_key(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME, + asic_db_key) + assert status == False + + # Query application database for wcmp group entries. + wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_db_entries_count() + ) + + # Verify that the route_key no longer exists in application database. + (status, fsv) = util.get_key(self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == False + + # Query application state database for wcmp group entries. + state_wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(state_wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + ) + + # Verify that the wcmp_group_key no longer exists in application state + # database. + (status, fsv) = util.get_key(self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == False + + # Query ASIC database for wcmp group entries. + wcmp_group_entries = util.get_keys(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_group_entries_count() + ) + + # Verify that removed wcmp group no longer exists in ASIC database. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, + wcmp_group_oid) + assert status == False + + # Query ASIC database for wcmp group member entries. + wcmp_group_member_entries = util.get_keys(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME) + assert len(wcmp_group_member_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + ) + + # Verify that removed wcmp group member no longer exists in ASIC + # database. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME, + asic_db_group_member_key) + assert status == False + + self._clean_vrf(dvs) + + def test_IPv4RouteAddWithInvalidNexthopFail(self, dvs, testlog): + marker = dvs.add_log_marker() + + # Initialize L3 objects and database connectors. + self._set_up(dvs) + self._set_vrf(dvs) + + # Set IP type for route object. + self._p4rt_route_obj.set_ip_type("IPV4") + + # Maintain list of original Application and ASIC DB entries before + # adding new route. + db_list = ((self._p4rt_route_obj.appl_db, + "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, + self._p4rt_route_obj.TBL_NAME)), + (self._p4rt_route_obj.appl_state_db, + "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, + self._p4rt_route_obj.TBL_NAME)), + (self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME)) + self._p4rt_route_obj.get_original_redis_entries(db_list) + + # Create route entry using invalid nexthop (expect failure). + route_key, attr_list = self._p4rt_route_obj.create_route() + err_log = "[OrchAgent] Nexthop ID '8' does not exist" + util.verify_response(self.response_consumer, route_key, attr_list, + "SWSS_RC_NOT_FOUND", err_log) + + # Query application database for route entries. + route_entries = util.get_keys( + self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for newly created route key. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query application database for route entries (no new route entry + # expected). + state_route_entries = util.get_keys( + self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(state_route_entries) == ( + self._p4rt_route_obj.get_original_appl_state_db_entries_count() + ) + + # Verify that the newly added route key does not exist in application + # state db. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == False + + # Query ASIC database for route entries (no new ASIC DB entry should be + # created for route entry). + route_entries = util.get_keys(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_asic_db_entries_count() + ) + + # Remove route entry (expect failure). + self._p4rt_route_obj.remove_app_db_entry(route_key) + err_log = "[OrchAgent] Route entry does not exist" + util.verify_response( + self.response_consumer, route_key, [], "SWSS_RC_NOT_FOUND", err_log) + self._clean_vrf(dvs) + + def test_IPv6RouteAddWithInvalidWcmpFail(self, dvs, testlog): + marker = dvs.add_log_marker() + + # Initialize L3 objects and database connectors. + self._set_up(dvs) + self._set_vrf(dvs) + + # Set IP type for route object. + self._p4rt_route_obj.set_ip_type("IPV6") + + # Maintain list of original Application and ASIC DB entries before + # adding new route. + db_list = ((self._p4rt_route_obj.appl_db, + "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, + self._p4rt_route_obj.TBL_NAME)), + (self._p4rt_route_obj.appl_state_db, + "%s:%s" % (self._p4rt_route_obj.APP_DB_TBL_NAME, + self._p4rt_route_obj.TBL_NAME)), + (self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME)) + self._p4rt_route_obj.get_original_redis_entries(db_list) + + # Create route entry using invalid wcmp group (expect failure). + route_key, attr_list = self._p4rt_route_obj.create_route( + action="set_wcmp_group_id", wcmp_group_id="8") + err_log = "[OrchAgent] WCMP group '8' does not exist" + util.verify_response(self.response_consumer, route_key, attr_list, + "SWSS_RC_NOT_FOUND", err_log) + + # Query application database for route entries + route_entries = util.get_keys(self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for newly created route key. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query application state database for route entries (no new APPL STATE DB + # entry should be created for route entry). + state_route_entries = util.get_keys(self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME + ":" + self._p4rt_route_obj.TBL_NAME) + assert len(state_route_entries) == ( + self._p4rt_route_obj.get_original_appl_state_db_entries_count() + ) + + # Verify that newly created route key does not exist in application + # state db. + (status, fvs) = util.get_key(self._p4rt_route_obj.appl_state_db, + self._p4rt_route_obj.APP_DB_TBL_NAME, + route_key) + assert status == False + + # Query ASIC database for route entries (no new ASIC DB entry should be + # created for route entry). + route_entries = util.get_keys(self._p4rt_route_obj.asic_db, + self._p4rt_route_obj.ASIC_DB_TBL_NAME) + assert len(route_entries) == ( + self._p4rt_route_obj.get_original_asic_db_entries_count() + ) + + # Remove route entry (expect failure). + self._p4rt_route_obj.remove_app_db_entry(route_key) + err_log = "[OrchAgent] Route entry does not exist" + util.verify_response( + self.response_consumer, route_key, [], "SWSS_RC_NOT_FOUND", err_log) + self._clean_vrf(dvs) + + def test_PruneAndRestoreNextHop(self, dvs, testlog): + # Initialize L3 objects and database connectors. + self._set_up(dvs) + cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + # Maintain original WCMP group entries for ASIC DB. + db_list = ((self._p4rt_wcmp_group_obj.appl_db, + "%s:%s" % (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + self._p4rt_wcmp_group_obj.TBL_NAME)), + (self._p4rt_wcmp_group_obj.appl_state_db, + "%s:%s" % (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + self._p4rt_wcmp_group_obj.TBL_NAME)), + (self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME), + (self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME)) + self._p4rt_wcmp_group_obj.get_original_redis_entries(db_list) + db_list = ((self._p4rt_nexthop_obj.asic_db, + self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME),) + self._p4rt_nexthop_obj.get_original_redis_entries(db_list) + + # Fetch the original key to oid information from Redis DB. + key_to_oid_helper = util.KeyToOidDBHelper(dvs) + _, original_key_oid_info = key_to_oid_helper.get_db_info() + + # Bring up port under test. + port_name = "Ethernet0" + if_name = "eth0" + util.initialize_interface(dvs, port_name, "10.0.0.0/31") + util.set_interface_status(dvs, if_name, "up") + + # Create router interface. + router_interface_id, router_intf_key, attr_list = ( + self._p4rt_router_intf_obj.create_router_interface() + ) + util.verify_response( + self.response_consumer, router_intf_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count = 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create neighbor. + neighbor_id, neighbor_key, attr_list = ( + self._p4rt_neighbor_obj.create_neighbor() + ) + util.verify_response( + self.response_consumer, neighbor_key, attr_list, "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create nexthop. + nexthop_id, nexthop_key, attr_list = ( + self._p4rt_nexthop_obj.create_next_hop() + ) + util.verify_response( + self.response_consumer, nexthop_key, attr_list, "SWSS_RC_SUCCESS") + # Get nexthop_oid of newly created nexthop. + nexthop_oid = self._p4rt_nexthop_obj.get_newly_created_nexthop_oid() + assert nexthop_oid is not None + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create wcmp group with one member. + wcmp_group_id, wcmp_group_key, attr_list = ( + self._p4rt_wcmp_group_obj.create_wcmp_group(watch_port=port_name) + ) + util.verify_response( + self.response_consumer, wcmp_group_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 2 in Redis DB + # (1 each for WCMP group and member). + count += 2 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Query application database for wcmp group entries. + wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for newly created wcmp group key. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query application state database for wcmp group entries. + state_wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(state_wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + + 1 + ) + + # Query application state database for newly created wcmp group key. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query ASIC database for wcmp group entries. + wcmp_group_entries = util.get_keys(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_group_entries_count() + + 1 + ) + + # Query ASIC database for newly created wcmp group oid. + wcmp_group_oid = self._p4rt_wcmp_group_obj.get_newly_created_wcmp_group_oid() + assert wcmp_group_oid is not None + (status, fvs) = util.get_key( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, + wcmp_group_oid + ) + assert status == True + asic_attr_list = [ + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_TYPE, + (self._p4rt_wcmp_group_obj. + SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP)) + ] + util.verify_attr(fvs, asic_attr_list) + + # Query ASIC database for newly created wcmp group member key. + asic_db_group_member_key = self._p4rt_wcmp_group_obj.get_newly_created_wcmp_group_member_asic_db_key() + assert asic_db_group_member_key is not None + (status, fvs) = util.get_key( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME, + asic_db_group_member_key + ) + assert status == True + asic_attr_list = [ + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_NEXTHOP_GROUP_ID, + wcmp_group_oid), + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_NEXTHOP_ID, + nexthop_oid), + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_WEIGHT, + str(self._p4rt_wcmp_group_obj.DEFAULT_WEIGHT)) + ] + util.verify_attr(fvs, asic_attr_list) + + # Force oper-down for the associated port. + util.set_interface_status(dvs, if_name) + + # Check ASIC DB to verify that associated member for watch_port is + # pruned. + wcmp_group_member_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME + ) + assert len(wcmp_group_member_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + ) + + # Check APPL STATE DB to verify no change. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Force oper-up for associated port. + util.set_interface_status(dvs, if_name, "up") + + # Check pruned next hop member is restored in ASIC DB. + wcmp_group_member_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME + ) + assert len(wcmp_group_member_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + + 1 + ) + asic_db_group_member_key = self._p4rt_wcmp_group_obj.get_newly_created_wcmp_group_member_asic_db_key() + assert asic_db_group_member_key is not None + (status, fvs) = util.get_key( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME, + asic_db_group_member_key + ) + assert status == True + util.verify_attr(fvs, asic_attr_list) + + # Delete WCMP group member. + self._p4rt_wcmp_group_obj.remove_app_db_entry(wcmp_group_key) + + # Verify that P4RT key to OID count decremented by 2 in Redis DB + # (1 each for WCMP group and member). + count -= 2 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Verify that APPL STATE DB is now updated. + state_wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_state_db, + (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + + self._p4rt_wcmp_group_obj.TBL_NAME)) + assert len(state_wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + ) + + # Delete next hop. + self._p4rt_nexthop_obj.remove_app_db_entry(nexthop_key) + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Delete neighbor. + self._p4rt_neighbor_obj.remove_app_db_entry(neighbor_key) + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Delete router interface. + self._p4rt_router_intf_obj.remove_app_db_entry(router_intf_key) + + # Verify that P4RT key to OID count is same as the original count. + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + + def test_PruneNextHopOnWarmBoot(self, dvs, testlog): + # Initialize L3 objects and database connectors. + self._set_up(dvs) + cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + # Maintain original WCMP group entries for ASIC DB. + db_list = ((self._p4rt_wcmp_group_obj.appl_db, + "%s:%s" % (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + self._p4rt_wcmp_group_obj.TBL_NAME)), + (self._p4rt_wcmp_group_obj.appl_state_db, + "%s:%s" % (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + self._p4rt_wcmp_group_obj.TBL_NAME)), + (self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME), + (self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME)) + self._p4rt_wcmp_group_obj.get_original_redis_entries(db_list) + db_list = ((self._p4rt_nexthop_obj.asic_db, + self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME),) + self._p4rt_nexthop_obj.get_original_redis_entries(db_list) + + # Fetch the original key to oid information from Redis DB. + key_to_oid_helper = util.KeyToOidDBHelper(dvs) + _, original_key_oid_info = key_to_oid_helper.get_db_info() + + # Bring up port under test. + port_name = "Ethernet0" + if_name = "eth0" + util.initialize_interface(dvs, port_name, "10.0.0.0/31") + util.set_interface_status(dvs, if_name, "up") + + # Create router interface. + router_interface_id, router_intf_key, attr_list = ( + self._p4rt_router_intf_obj.create_router_interface() + ) + util.verify_response( + self.response_consumer, router_intf_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count = 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create neighbor. + neighbor_id, neighbor_key, attr_list = ( + self._p4rt_neighbor_obj.create_neighbor() + ) + util.verify_response( + self.response_consumer, neighbor_key, attr_list, "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create nexthop. + nexthop_id, nexthop_key, attr_list = ( + self._p4rt_nexthop_obj.create_next_hop() + ) + util.verify_response( + self.response_consumer, nexthop_key, attr_list, "SWSS_RC_SUCCESS") + # Get nexthop_oid of newly created nexthop. + nexthop_oid = self._p4rt_nexthop_obj.get_newly_created_nexthop_oid() + assert nexthop_oid is not None + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create wcmp group with one member. + wcmp_group_id, wcmp_group_key, attr_list = ( + self._p4rt_wcmp_group_obj.create_wcmp_group(watch_port=port_name) + ) + util.verify_response( + self.response_consumer, wcmp_group_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 2 in Redis DB + # (1 each for WCMP group and member). + count += 2 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Query application database for wcmp group entries. + wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for newly created wcmp group key. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query application state database for wcmp group entries. + state_wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(state_wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + + 1 + ) + + # Query application state database for newly created wcmp group key. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query ASIC database for wcmp group entries. + wcmp_group_entries = util.get_keys(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_group_entries_count() + + 1 + ) + + # Query ASIC database for newly created wcmp group oid. + wcmp_group_oid = self._p4rt_wcmp_group_obj.get_newly_created_wcmp_group_oid() + assert wcmp_group_oid is not None + (status, fvs) = util.get_key( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, + wcmp_group_oid + ) + assert status == True + asic_attr_list = [ + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_TYPE, + (self._p4rt_wcmp_group_obj. + SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP)) + ] + util.verify_attr(fvs, asic_attr_list) + + # Query ASIC database for wcmp group member entries. + wcmp_group_member_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME + ) + assert len(wcmp_group_member_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + + 1 + ) + + # Query ASIC database for newly created wcmp group member key. + asic_db_group_member_key = self._p4rt_wcmp_group_obj.get_newly_created_wcmp_group_member_asic_db_key() + assert asic_db_group_member_key is not None + (status, fvs) = util.get_key( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME, + asic_db_group_member_key + ) + assert status == True + asic_attr_list = [ + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_NEXTHOP_GROUP_ID, + wcmp_group_oid), + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_NEXTHOP_ID, + nexthop_oid), + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_WEIGHT, + str(self._p4rt_wcmp_group_obj.DEFAULT_WEIGHT)) + ] + util.verify_attr(fvs, asic_attr_list) + + # Bring down the port. + util.set_interface_status(dvs, if_name) + + # Execute the warm reboot. + dvs.runcmd("config warm_restart enable swss") + dvs.stop_swss() + dvs.start_swss() + + # Make sure the system is stable. + dvs.check_swss_ready() + + # Verify that the associated next hop is pruned in ASIC DB. + wcmp_group_member_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME + ) + assert len(wcmp_group_member_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + ) + + # Delete WCMP group member. + self._p4rt_wcmp_group_obj.remove_app_db_entry(wcmp_group_key) + + # Verify that P4RT key to OID count decremented by 2 in Redis DB + # (1 each for WCMP group and member). + count -= 2 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Verify that APPL STATE DB is updated. + state_wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_state_db, + (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + + self._p4rt_wcmp_group_obj.TBL_NAME)) + assert len(state_wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + ) + + # Delete next hop. + self._p4rt_nexthop_obj.remove_app_db_entry(nexthop_key) + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Delete neighbor. + self._p4rt_neighbor_obj.remove_app_db_entry(neighbor_key) + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Delete router interface. + self._p4rt_router_intf_obj.remove_app_db_entry(router_intf_key) + + # Verify that P4RT key to OID count is same as the original count. + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + + def test_CreateWcmpMemberForOperUpWatchportOnly(self, dvs, testlog): + # Initialize L3 objects and database connectors. + self._set_up(dvs) + cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + # Maintain original WCMP group entries for ASIC DB. + db_list = ((self._p4rt_wcmp_group_obj.appl_db, + "%s:%s" % (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + self._p4rt_wcmp_group_obj.TBL_NAME)), + (self._p4rt_wcmp_group_obj.appl_state_db, + "%s:%s" % (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + self._p4rt_wcmp_group_obj.TBL_NAME)), + (self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME), + (self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME)) + self._p4rt_wcmp_group_obj.get_original_redis_entries(db_list) + db_list = ((self._p4rt_nexthop_obj.asic_db, + self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME),) + self._p4rt_nexthop_obj.get_original_redis_entries(db_list) + + # Fetch the original key to oid information from Redis DB. + key_to_oid_helper = util.KeyToOidDBHelper(dvs) + _, original_key_oid_info = key_to_oid_helper.get_db_info() + + # Force oper-down on port under test. + port_name = "Ethernet0" + if_name = "eth0" + util.initialize_interface(dvs, port_name, "10.0.0.0/31") + util.set_interface_status(dvs, if_name) + + # Create router interface. + router_interface_id, router_intf_key, attr_list = ( + self._p4rt_router_intf_obj.create_router_interface() + ) + util.verify_response( + self.response_consumer, router_intf_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count = 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create neighbor. + neighbor_id, neighbor_key, attr_list = ( + self._p4rt_neighbor_obj.create_neighbor() + ) + util.verify_response( + self.response_consumer, neighbor_key, attr_list, "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create nexthop. + nexthop_id, nexthop_key, attr_list = ( + self._p4rt_nexthop_obj.create_next_hop() + ) + util.verify_response( + self.response_consumer, nexthop_key, attr_list, "SWSS_RC_SUCCESS") + # Get nexthop_oid of newly created nexthop. + nexthop_oid = self._p4rt_nexthop_obj.get_newly_created_nexthop_oid() + assert nexthop_oid is not None + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create wcmp group with one member. + wcmp_group_id, wcmp_group_key, attr_list = ( + self._p4rt_wcmp_group_obj.create_wcmp_group(watch_port=port_name) + ) + util.verify_response( + self.response_consumer, wcmp_group_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB + # (WCMP group member is not created for operationally down watchport). + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Query application database for wcmp group entries. + wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for newly created wcmp group key. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query application state database for wcmp group entries. + state_wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(state_wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + 1 + ) + + # Query application state database for newly created wcmp group key. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query ASIC database for wcmp group entries. + wcmp_group_entries = util.get_keys(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_group_entries_count() + + 1 + ) + + # Query ASIC database for newly created wcmp group oid. + wcmp_group_oid = self._p4rt_wcmp_group_obj.get_newly_created_wcmp_group_oid() + assert wcmp_group_oid is not None + (status, fvs) = util.get_key( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, + wcmp_group_oid + ) + assert status == True + asic_attr_list = [ + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_TYPE, + (self._p4rt_wcmp_group_obj. + SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP)) + ] + util.verify_attr(fvs, asic_attr_list) + + # Query ASIC database for wcmp group member entries (expect no entry). + wcmp_group_member_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME + ) + assert len(wcmp_group_member_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + ) + + # Bring up the port. + util.set_interface_status(dvs, if_name, "up") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB + # (WCMP group member is now expected to be created in SAI due to + # watchport now being operationally up) + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Verify that next hop member is now created in SAI. + wcmp_group_member_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME + ) + assert len(wcmp_group_member_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + + 1 + ) + asic_db_group_member_key = self._p4rt_wcmp_group_obj.get_newly_created_wcmp_group_member_asic_db_key() + assert asic_db_group_member_key is not None + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.asic_db, + (self._p4rt_wcmp_group_obj. + ASIC_DB_GROUP_MEMBER_TBL_NAME), + asic_db_group_member_key) + assert status == True + asic_attr_list = [ + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_NEXTHOP_GROUP_ID, + wcmp_group_oid), + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_NEXTHOP_ID, + nexthop_oid), + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_MEMBER_WEIGHT, + str(self._p4rt_wcmp_group_obj.DEFAULT_WEIGHT)) + ] + util.verify_attr(fvs, asic_attr_list) + + # Delete WCMP group member. + self._p4rt_wcmp_group_obj.remove_app_db_entry(wcmp_group_key) + + # Verify that P4RT key to OID count decremented by 2 in Redis DB + # (1 each for WCMP group and member). + count -= 2 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Verify that APPL STATE DB is updated. + state_wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_state_db, + (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + + self._p4rt_wcmp_group_obj.TBL_NAME)) + assert len(state_wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + ) + + # Delete next hop. + self._p4rt_nexthop_obj.remove_app_db_entry(nexthop_key) + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Delete neighbor. + self._p4rt_neighbor_obj.remove_app_db_entry(neighbor_key) + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Delete router interface. + self._p4rt_router_intf_obj.remove_app_db_entry(router_intf_key) + + # Verify that P4RT key to OID count is same as the original count. + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + + def test_RemovePrunedWcmpGroupMember(self, dvs, testlog): + # Initialize L3 objects and database connectors. + self._set_up(dvs) + cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + # Maintain original WCMP group entries for ASIC DB. + db_list = ((self._p4rt_wcmp_group_obj.appl_db, + "%s:%s" % (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + self._p4rt_wcmp_group_obj.TBL_NAME)), + (self._p4rt_wcmp_group_obj.appl_state_db, + "%s:%s" % (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + self._p4rt_wcmp_group_obj.TBL_NAME)), + (self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME), + (self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME)) + self._p4rt_wcmp_group_obj.get_original_redis_entries(db_list) + db_list = ((self._p4rt_nexthop_obj.asic_db, + self._p4rt_nexthop_obj.ASIC_DB_TBL_NAME),) + self._p4rt_nexthop_obj.get_original_redis_entries(db_list) + + # Fetch the original key to oid information from Redis DB. + key_to_oid_helper = util.KeyToOidDBHelper(dvs) + _, original_key_oid_info = key_to_oid_helper.get_db_info() + + # Force oper-down on port under test. + port_name = "Ethernet0" + if_name = "eth0" + util.initialize_interface(dvs, port_name, "10.0.0.0/31") + util.set_interface_status(dvs, if_name) + + # Create router interface. + router_interface_id, router_intf_key, attr_list = ( + self._p4rt_router_intf_obj.create_router_interface() + ) + util.verify_response( + self.response_consumer, router_intf_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count = 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create neighbor. + neighbor_id, neighbor_key, attr_list = ( + self._p4rt_neighbor_obj.create_neighbor() + ) + util.verify_response( + self.response_consumer, neighbor_key, attr_list, "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create nexthop. + nexthop_id, nexthop_key, attr_list = ( + self._p4rt_nexthop_obj.create_next_hop() + ) + util.verify_response( + self.response_consumer, nexthop_key, attr_list, "SWSS_RC_SUCCESS") + # Get nexthop_oid of newly created nexthop. + nexthop_oid = self._p4rt_nexthop_obj.get_newly_created_nexthop_oid() + assert nexthop_oid is not None + + # Verify that P4RT key to OID count incremented by 1 in Redis DB. + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Create wcmp group with one member. + wcmp_group_id, wcmp_group_key, attr_list = ( + self._p4rt_wcmp_group_obj.create_wcmp_group(watch_port=port_name) + ) + util.verify_response( + self.response_consumer, wcmp_group_key, attr_list, + "SWSS_RC_SUCCESS") + + # Verify that P4RT key to OID count incremented by 1 in Redis DB + # (WCMP group member is not created for operationally down watchport). + count += 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Query application database for wcmp group entries. + wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_db_entries_count() + 1 + ) + + # Query application database for newly created wcmp group key. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query application state database for wcmp group entries. + state_wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + self._p4rt_wcmp_group_obj.TBL_NAME) + assert len(state_wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + 1 + ) + + # Query application state database for newly created wcmp group key. + (status, fvs) = util.get_key(self._p4rt_wcmp_group_obj.appl_state_db, + self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME, + wcmp_group_key) + assert status == True + util.verify_attr(fvs, attr_list) + + # Query ASIC database for wcmp group entries. + wcmp_group_entries = util.get_keys(self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_group_entries_count() + + 1 + ) + + # Query ASIC database for newly created wcmp group oid. + wcmp_group_oid = self._p4rt_wcmp_group_obj.get_newly_created_wcmp_group_oid() + assert wcmp_group_oid is not None + (status, fvs) = util.get_key( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME, + wcmp_group_oid + ) + assert status == True + asic_attr_list = [ + (self._p4rt_wcmp_group_obj.SAI_ATTR_GROUP_TYPE, + (self._p4rt_wcmp_group_obj. + SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP)) + ] + util.verify_attr(fvs, asic_attr_list) + + # Query ASIC database for wcmp group member entries. + wcmp_group_member_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME + ) + assert len(wcmp_group_member_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + + 1 + ) + + # Query ASIC database for wcmp group member entries (expect no entry). + wcmp_group_member_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME + ) + assert len( + wcmp_group_member_entries) == self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + + # Delete the pruned wcmp group member. + self._p4rt_wcmp_group_obj.remove_app_db_entry(wcmp_group_key) + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Verify that APPL STATE DB is updated. + state_wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.appl_state_db, + (self._p4rt_wcmp_group_obj.APP_DB_TBL_NAME + ":" + + self._p4rt_wcmp_group_obj.TBL_NAME)) + assert len(state_wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_appl_state_db_entries_count() + ) + + # Verify that ASIC DB is updated. + wcmp_group_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_TBL_NAME + ) + assert len(wcmp_group_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_group_entries_count() + ) + wcmp_group_member_entries = util.get_keys( + self._p4rt_wcmp_group_obj.asic_db, + self._p4rt_wcmp_group_obj.ASIC_DB_GROUP_MEMBER_TBL_NAME + ) + assert len(wcmp_group_member_entries) == ( + self._p4rt_wcmp_group_obj.get_original_asic_db_member_entries_count() + ) + + # Delete next hop. + self._p4rt_nexthop_obj.remove_app_db_entry(nexthop_key) + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Delete neighbor. + self._p4rt_neighbor_obj.remove_app_db_entry(neighbor_key) + + # Verify that P4RT key to OID count decremented by 1 in Redis DB. + count -= 1 + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) + count + + # Delete router interface. + self._p4rt_router_intf_obj.remove_app_db_entry(router_intf_key) + + # Verify that P4RT key to OID count is same as the original count. + status, fvs = key_to_oid_helper.get_db_info() + assert status == True + assert len(fvs) == len(original_key_oid_info) diff --git a/tests/p4rt/test_p4rt_acl.py b/tests/p4rt/test_p4rt_acl.py new file mode 100644 index 000000000000..201a38f9789f --- /dev/null +++ b/tests/p4rt/test_p4rt_acl.py @@ -0,0 +1,1253 @@ +# Lint as: python3 +from swsscommon import swsscommon + +import pytest +import util +import acl + + +def get_exist_entry(dvs, table): + db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + tbl = swsscommon.Table(db, table) + entries = list(tbl.getKeys()) + return entries[0] + + +def verify_selected_attr_vals(db, table, key, expected_attrs): + tbl = swsscommon.Table(db, table) + keys = tbl.getKeys() + assert key in keys, "The desired key is not presented" + + status, fvs = tbl.get(key) + assert status, "Got an error when get a key" + + fv_dict = dict(fvs) + + for attr_name, expected_val in expected_attrs: + assert attr_name in fv_dict, "Attribute %s not found in %s" % (attr_name, key) + assert fv_dict[attr_name] == expected_val, "Wrong value %s for the attribute %s = %s" % ( + fv_dict[attr_name], + attr_name, + expected_val, + ) + + +class TestP4RTAcl(object): + def _set_up(self, dvs): + self._p4rt_acl_table_definition_obj = acl.P4RtAclTableDefinitionWrapper() + self._p4rt_acl_group_obj = acl.P4RtAclGroupWrapper() + self._p4rt_acl_group_member_obj = acl.P4RtAclGroupMemberWrapper() + self._p4rt_acl_rule_obj = acl.P4RtAclRuleWrapper() + self._p4rt_acl_counter_obj = acl.P4RtAclCounterWrapper() + self._p4rt_acl_meter_obj = acl.P4RtAclMeterWrapper() + self._p4rt_trap_group_obj = acl.P4RtTrapGroupWrapper() + self._p4rt_user_trap_obj = acl.P4RtUserDefinedTrapWrapper() + self._p4rt_hostif_obj = acl.P4RtHostifWrapper() + self._p4rt_hostif_table_entry_obj = acl.P4RtHostifTableEntryWrapper() + self._p4rt_udf_group_obj = acl.P4RtUdfGroupWrapper() + self._p4rt_udf_match_obj = acl.P4RtUdfMatchWrapper() + self._p4rt_udf_obj = acl.P4RtUdfWrapper() + + self._p4rt_acl_group_member_obj.set_up_databases(dvs) + self._p4rt_acl_group_obj.set_up_databases(dvs) + self._p4rt_acl_table_definition_obj.set_up_databases(dvs) + self._p4rt_acl_rule_obj.set_up_databases(dvs) + self._p4rt_acl_counter_obj.set_up_databases(dvs) + self._p4rt_acl_meter_obj.set_up_databases(dvs) + self._p4rt_trap_group_obj.set_up_databases(dvs) + self._p4rt_user_trap_obj.set_up_databases(dvs) + self._p4rt_hostif_obj.set_up_databases(dvs) + self._p4rt_hostif_table_entry_obj.set_up_databases(dvs) + self._p4rt_udf_group_obj.set_up_databases(dvs) + self._p4rt_udf_match_obj.set_up_databases(dvs) + self._p4rt_udf_obj.set_up_databases(dvs) + + self.response_consumer = swsscommon.NotificationConsumer( + self._p4rt_acl_table_definition_obj.appl_db, "APPL_DB_P4RT_TABLE_RESPONSE_CHANNEL" + ) + + @pytest.mark.skip(reason="p4orch is not enabled") + def test_AclRulesAddUpdateDelPass(self, dvs, testlog): + # initialize ACL table objects and database connectors + self._set_up(dvs) + + # maintain list of original Application and ASIC DB entries before adding + # new ACL table + original_appl_acl_tables = util.get_keys( + self._p4rt_acl_table_definition_obj.appl_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME + + ":" + + self._p4rt_acl_table_definition_obj.TBL_NAME, + ) + original_appl_state_acl_tables = util.get_keys( + self._p4rt_acl_table_definition_obj.appl_state_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME + + ":" + + self._p4rt_acl_table_definition_obj.TBL_NAME, + ) + original_asic_acl_tables = util.get_keys( + self._p4rt_acl_table_definition_obj.asic_db, + self._p4rt_acl_table_definition_obj.ASIC_DB_TBL_NAME, + ) + original_asic_udf_groups = util.get_keys( + self._p4rt_udf_group_obj.asic_db, self._p4rt_udf_group_obj.ASIC_DB_TBL_NAME + ) + original_asic_udf_matches = util.get_keys( + self._p4rt_udf_match_obj.asic_db, self._p4rt_udf_match_obj.ASIC_DB_TBL_NAME + ) + original_asic_udfs = util.get_keys( + self._p4rt_udf_obj.asic_db, self._p4rt_udf_obj.ASIC_DB_TBL_NAME + ) + + # query ASIC database for ACL groups + acl_groups_asic_keys = util.get_keys( + self._p4rt_acl_group_obj.asic_db, self._p4rt_acl_group_obj.ASIC_DB_TBL_NAME + ) + assert ( + len(acl_groups_asic_keys) == 3 + ) # INGRESS, EGRESS and PRE_INGRESS bind to SWITCH + switch_oid = get_exist_entry(dvs, "ASIC_STATE:SAI_OBJECT_TYPE_SWITCH") + # Ingress + ingress_group_oids = self._p4rt_acl_group_obj.get_group_oids_by_stage( + acl.INGRESS_STAGE + ) + assert len(ingress_group_oids) == 1 + # Egress + egress_group_oids = self._p4rt_acl_group_obj.get_group_oids_by_stage( + acl.EGRESS_STAGE + ) + assert len(egress_group_oids) == 1 + # Pre_ingress + pre_ingress_group_oids = self._p4rt_acl_group_obj.get_group_oids_by_stage( + acl.PRE_INGRESS_STAGE + ) + assert len(pre_ingress_group_oids) == 1 + verify_selected_attr_vals( + self._p4rt_acl_group_obj.asic_db, + "ASIC_STATE:SAI_OBJECT_TYPE_SWITCH", + switch_oid, + [("SAI_SWITCH_ATTR_PRE_INGRESS_ACL", pre_ingress_group_oids[0]), + ("SAI_SWITCH_ATTR_INGRESS_ACL",ingress_group_oids[0]), + ("SAI_SWITCH_ATTR_EGRESS_ACL", egress_group_oids[0])], + ) + + # Verify APP DB trap groups for QOS_QUEUE + genetlink_name = "genl_packet" + genetlink_mcgrp_name = "packets" + + for queue_num in range(1, 9): + attr_list = [ + (self._p4rt_trap_group_obj.QUEUE, str(queue_num)), + (self._p4rt_trap_group_obj.HOSTIF_NAME, genetlink_name), + ( + self._p4rt_trap_group_obj.HOSTIF_GENETLINK_MCGRP_NAME, + genetlink_mcgrp_name, + ), + ] + + # query application database for trap group + (status, fvs) = util.get_key( + self._p4rt_trap_group_obj.appl_db, + self._p4rt_trap_group_obj.APP_DB_TBL_NAME, + self._p4rt_trap_group_obj.TBL_NAME_PREFIX + str(queue_num), + ) + assert status == True + util.verify_attr(fvs, attr_list) + + # create ACL table + table_name = "ACL_PUNT_TABLE_RULE_TEST" + stage = "INGRESS" + priority = "234" + size = "123" + ether_type = '{"kind":"sai_field","sai_field":"SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE","format":"HEX_STRING","bitwidth":8}' + ether_dst = '{"kind":"sai_field","sai_field":"SAI_ACL_TABLE_ATTR_FIELD_DST_MAC","format":"MAC","bitwidth":48}' + is_ip = '{"kind":"sai_field","sai_field":"SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE/IP","format":"HEX_STRING","bitwidth":1}' + is_ipv4 = '{"kind":"sai_field","sai_field":"SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE/IPV4ANY","format":"HEX_STRING","bitwidth":1}' + is_ipv6 = '{"kind":"sai_field","sai_field":"SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE/IPV6ANY","format":"HEX_STRING","bitwidth":1}' + is_arp = '{"kind":"sai_field","sai_field":"SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE/ARP","format":"HEX_STRING","bitwidth":1}' + arp_tpa = """{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32, + \"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"bitwidth\":16,\"offset\":24}, + {\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"bitwidth\":16,\"offset\":26}]} + """ + src_ipv6_64bit = """{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64, + \"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32}, + {\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":32}]} + """ + meter_unit = "PACKETS" + counter_unit = "BOTH" + copy_and_set_tc = '[{"action":"SAI_PACKET_ACTION_COPY"},{"action":"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC","param":"traffic_class"}]' + punt_and_set_tc = '[{"action":"SAI_PACKET_ACTION_TRAP","packet_color":"SAI_PACKET_COLOR_RED"},{"action":"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC","param":"traffic_class"}]' + qos_queue = '[{"action":"SAI_PACKET_ACTION_TRAP"},{"action":"QOS_QUEUE","param":"cpu_queue"}]' + + attr_list = [ + (self._p4rt_acl_table_definition_obj.STAGE_FIELD, stage), + (self._p4rt_acl_table_definition_obj.PRIORITY_FIELD, priority), + (self._p4rt_acl_table_definition_obj.SIZE_FIELD, size), + (self._p4rt_acl_table_definition_obj.MATCH_FIELD_ETHER_DST, ether_dst), + (self._p4rt_acl_table_definition_obj.MATCH_FIELD_ETHER_TYPE, ether_type), + (self._p4rt_acl_table_definition_obj.MATCH_FIELD_IS_IP, is_ip), + (self._p4rt_acl_table_definition_obj.MATCH_FIELD_IS_IPV4, is_ipv4), + (self._p4rt_acl_table_definition_obj.MATCH_FIELD_IS_IPV6, is_ipv6), + (self._p4rt_acl_table_definition_obj.MATCH_FIELD_IS_ARP, is_arp), + ( + self._p4rt_acl_table_definition_obj.MATCH_FIELD_SRC_IPV6_64BIT, + src_ipv6_64bit, + ), + (self._p4rt_acl_table_definition_obj.MATCH_FIELD_ARP_TPA, arp_tpa), + ( + self._p4rt_acl_table_definition_obj.ACTION_COPY_AND_SET_TC, + copy_and_set_tc, + ), + ( + self._p4rt_acl_table_definition_obj.ACTION_PUNT_AND_SET_TC, + punt_and_set_tc, + ), + (self._p4rt_acl_table_definition_obj.ACTION_SET_QOS_QUEUE, qos_queue), + (self._p4rt_acl_table_definition_obj.METER_UNIT, meter_unit), + (self._p4rt_acl_table_definition_obj.COUNTER_UNIT, counter_unit), + ] + + self._p4rt_acl_table_definition_obj.set_app_db_entry( + self._p4rt_acl_table_definition_obj.TBL_NAME + ":" + table_name, attr_list + ) + util.verify_response( + self.response_consumer, + self._p4rt_acl_table_definition_obj.TBL_NAME + ":" + table_name, + attr_list, + "SWSS_RC_SUCCESS", + ) + + # query application database for ACL tables + acl_tables = util.get_keys( + self._p4rt_acl_table_definition_obj.appl_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME + + ":" + + self._p4rt_acl_table_definition_obj.TBL_NAME, + ) + assert len(acl_tables) == len(original_appl_acl_tables) + 1 + + # query application database for newly created ACL table + (status, fvs) = util.get_key( + self._p4rt_acl_table_definition_obj.appl_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME + + ":" + + self._p4rt_acl_table_definition_obj.TBL_NAME, + table_name, + ) + assert status == True + util.verify_attr(fvs, attr_list) + + # query application state database for ACL tables + state_acl_tables = util.get_keys( + self._p4rt_acl_table_definition_obj.appl_state_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME + + ":" + + self._p4rt_acl_table_definition_obj.TBL_NAME, + ) + assert len(state_acl_tables) == len(original_appl_state_acl_tables) + 1 + + # query application state database for newly created ACL table + (status, fvs) = util.get_key( + self._p4rt_acl_table_definition_obj.appl_state_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME + + ":" + + self._p4rt_acl_table_definition_obj.TBL_NAME, + table_name, + ) + assert status == True + util.verify_attr(fvs, attr_list) + + # query ASIC database for default UDF wildcard match + udf_match_asic_db_key = original_asic_udf_matches[0] + + (status, fvs) = util.get_key( + self._p4rt_udf_match_obj.asic_db, + self._p4rt_udf_match_obj.ASIC_DB_TBL_NAME, + udf_match_asic_db_key, + ) + assert status == True + attr_list = [("NULL", "NULL")] + util.verify_attr(fvs, attr_list) + + # query ASIC database for UDF groups + udf_groups_asic = util.get_keys( + self._p4rt_udf_group_obj.asic_db, self._p4rt_udf_group_obj.ASIC_DB_TBL_NAME + ) + assert len(udf_groups_asic) == len(original_asic_udf_groups) + 2 + + # query ASIC database for newly created UDF groups + udf_groups_asic_db_keys = [ + key for key in udf_groups_asic if key not in original_asic_udf_groups + ] + assert len(udf_groups_asic_db_keys) == 2 + udf_groups_asic_db_keys.sort() + udf_group_min_asic_db_key = udf_groups_asic_db_keys[0] + udf_group_1_asic_db_key = udf_groups_asic_db_keys[1] + + (status, fvs) = util.get_key( + self._p4rt_udf_group_obj.asic_db, + self._p4rt_udf_group_obj.ASIC_DB_TBL_NAME, + udf_group_min_asic_db_key, + ) + assert status == True + attr_list = [ + ( + self._p4rt_udf_group_obj.SAI_UDF_GROUP_ATTR_TYPE, + self._p4rt_udf_group_obj.SAI_UDF_GROUP_TYPE_GENERIC, + ), + (self._p4rt_udf_group_obj.SAI_UDF_GROUP_ATTR_LENGTH, "2"), + ] + util.verify_attr(fvs, attr_list) + + (status, fvs) = util.get_key( + self._p4rt_udf_group_obj.asic_db, + self._p4rt_udf_group_obj.ASIC_DB_TBL_NAME, + udf_group_1_asic_db_key, + ) + assert status == True + attr_list = [ + ( + self._p4rt_udf_group_obj.SAI_UDF_GROUP_ATTR_TYPE, + self._p4rt_udf_group_obj.SAI_UDF_GROUP_TYPE_GENERIC, + ), + (self._p4rt_udf_group_obj.SAI_UDF_GROUP_ATTR_LENGTH, "2"), + ] + util.verify_attr(fvs, attr_list) + + # query ASIC database for UDFs + udfs_asic = util.get_keys( + self._p4rt_udf_obj.asic_db, self._p4rt_udf_obj.ASIC_DB_TBL_NAME + ) + assert len(udfs_asic) == len(original_asic_udfs) + 2 + + # query ASIC database for newly created UDFs + udfs_asic_db_keys = [key for key in udfs_asic if key not in original_asic_udfs] + assert len(udfs_asic_db_keys) == 2 + udfs_asic_db_keys.sort() + udf_0_asic_db_key = udfs_asic_db_keys[0] + udf_1_asic_db_key = udfs_asic_db_keys[1] + + (status, fvs) = util.get_key( + self._p4rt_udf_obj.asic_db, + self._p4rt_udf_obj.ASIC_DB_TBL_NAME, + udf_0_asic_db_key, + ) + assert status == True + attr_list = [ + (self._p4rt_udf_obj.SAI_UDF_ATTR_MATCH_ID, udf_match_asic_db_key), + (self._p4rt_udf_obj.SAI_UDF_ATTR_GROUP_ID, udf_group_min_asic_db_key), + (self._p4rt_udf_obj.SAI_UDF_ATTR_OFFSET, "24"), + (self._p4rt_udf_obj.SAI_UDF_ATTR_BASE, "SAI_UDF_BASE_L3"), + ] + util.verify_attr(fvs, attr_list) + + (status, fvs) = util.get_key( + self._p4rt_udf_obj.asic_db, + self._p4rt_udf_obj.ASIC_DB_TBL_NAME, + udf_1_asic_db_key, + ) + assert status == True + attr_list = [ + (self._p4rt_udf_obj.SAI_UDF_ATTR_MATCH_ID, udf_match_asic_db_key), + (self._p4rt_udf_obj.SAI_UDF_ATTR_GROUP_ID, udf_group_1_asic_db_key), + (self._p4rt_udf_obj.SAI_UDF_ATTR_OFFSET, "26"), + (self._p4rt_udf_obj.SAI_UDF_ATTR_BASE, "SAI_UDF_BASE_L3"), + ] + util.verify_attr(fvs, attr_list) + + # query ASIC database for ACL tables + acl_asic_tables = util.get_keys( + self._p4rt_acl_table_definition_obj.asic_db, + self._p4rt_acl_table_definition_obj.ASIC_DB_TBL_NAME, + ) + assert len(acl_asic_tables) == len(original_asic_acl_tables) + 1 + + # query ASIC database for newly created ACL table + table_asic_db_keys = [ + key for key in acl_asic_tables if key not in original_asic_acl_tables + ] + assert len(table_asic_db_keys) == 1 + table_asic_db_key = table_asic_db_keys[0] + + (status, fvs) = util.get_key( + self._p4rt_acl_table_definition_obj.asic_db, + self._p4rt_acl_table_definition_obj.ASIC_DB_TBL_NAME, + table_asic_db_key, + ) + assert status == True + attr_list = [ + ( + self._p4rt_acl_table_definition_obj.SAI_ACL_TABLE_ATTR_ACL_STAGE, + "SAI_ACL_STAGE_INGRESS", + ), + (self._p4rt_acl_table_definition_obj.SAI_ACL_TABLE_ATTR_SIZE, size), + (self._p4rt_acl_table_definition_obj.SAI_ATTR_MATCH_ETHER_TYPE, "true"), + (self._p4rt_acl_table_definition_obj.SAI_ATTR_MATCH_IP_TYPE, "true"), + (self._p4rt_acl_table_definition_obj.SAI_ATTR_MATCH_DST_MAC, "true"), + (self._p4rt_acl_table_definition_obj.SAI_ATTR_MATCH_SRC_IPV6_WORD3, "true"), + (self._p4rt_acl_table_definition_obj.SAI_ATTR_MATCH_SRC_IPV6_WORD2, "true"), + ( + self._p4rt_acl_table_definition_obj.SAI_ATTR_MATCH_UDF_GROUP_MIN, + udf_group_min_asic_db_key, + ), + ( + self._p4rt_acl_table_definition_obj.SAI_ATTR_MATCH_UDF_GROUP_1, + udf_group_1_asic_db_key, + ), + ( + self._p4rt_acl_table_definition_obj.SAI_ATTR_ACTION_TYPE_LIST, + "1:SAI_ACL_ACTION_TYPE_COUNTER", + ), + ] + util.verify_attr(fvs, attr_list) + + # maintain list of original Application and ASIC DB ACL entries before adding + # new ACL rule + original_appl_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + original_appl_state_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + original_asic_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME + ) + original_asic_acl_counters = util.get_keys( + self._p4rt_acl_counter_obj.asic_db, + self._p4rt_acl_counter_obj.ASIC_DB_TBL_NAME, + ) + original_asic_acl_meters = util.get_keys( + self._p4rt_acl_meter_obj.asic_db, self._p4rt_acl_meter_obj.ASIC_DB_TBL_NAME + ) + + # create ACL rule 1 + rule_json_key1 = '{"match/ether_type":"0x0800","match/ether_dst":"00:1a:11:17:5f:80","match/src_ipv6_64bit":"fdf8:f53b:82e4::","match/arp_tpa":"0xff665543","priority":100}' + action = "copy_and_set_tc" + meter_cir = "80" + meter_cbs = "80" + meter_pir = "200" + meter_pbs = "200" + table_name_with_rule_key1 = table_name + ":" + rule_json_key1 + + attr_list = [ + (self._p4rt_acl_rule_obj.ACTION, action), + ("param/traffic_class", "1"), + (self._p4rt_acl_rule_obj.METER_CIR, meter_cir), + (self._p4rt_acl_rule_obj.METER_CBURST, meter_cbs), + (self._p4rt_acl_rule_obj.METER_PIR, meter_pir), + (self._p4rt_acl_rule_obj.METER_PBURST, meter_pbs), + ] + + self._p4rt_acl_rule_obj.set_app_db_entry(table_name_with_rule_key1, attr_list) + util.verify_response( + self.response_consumer, + table_name_with_rule_key1, + attr_list, + "SWSS_RC_SUCCESS", + ) + + # query application database for ACL rules + acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(acl_rules) == len(original_appl_acl_rules) + 1 + + # query application database for newly created ACL rule + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, + table_name_with_rule_key1, + ) + assert status == True + util.verify_attr(fvs, attr_list) + + # query application state database for ACL rules + state_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(state_acl_rules) == len(original_appl_state_acl_rules) + 1 + + # query application state database for newly created ACL rule + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, + table_name_with_rule_key1, + ) + assert status == True + util.verify_attr(fvs, attr_list) + + # query ASIC database for ACL counters + acl_asic_counters = util.get_keys( + self._p4rt_acl_counter_obj.asic_db, + self._p4rt_acl_counter_obj.ASIC_DB_TBL_NAME, + ) + assert len(acl_asic_counters) == len(original_asic_acl_counters) + 1 + + # query ASIC database for newly created ACL counter + counter_asic_db_keys = [ + key for key in acl_asic_counters if key not in original_asic_acl_counters + ] + assert len(counter_asic_db_keys) == 1 + counter_asic_db_key1 = counter_asic_db_keys[0] + + (status, fvs) = util.get_key( + self._p4rt_acl_counter_obj.asic_db, + self._p4rt_acl_counter_obj.ASIC_DB_TBL_NAME, + counter_asic_db_key1, + ) + assert status == True + attr_list = [ + (self._p4rt_acl_counter_obj.SAI_ATTR_ENABLE_PACKET_COUNT, "true"), + (self._p4rt_acl_counter_obj.SAI_ATTR_ENABLE_BYTE_COUNT, "true"), + (self._p4rt_acl_counter_obj.SAI_ATTR_TABLE_ID, table_asic_db_key), + ] + util.verify_attr(fvs, attr_list) + + # query ASIC database for ACL meters + acl_asic_meters = util.get_keys( + self._p4rt_acl_meter_obj.asic_db, self._p4rt_acl_meter_obj.ASIC_DB_TBL_NAME + ) + assert len(acl_asic_meters) == len(original_asic_acl_meters) + 1 + + # query ASIC database for newly created ACL meter + meter_asic_db_keys = [ + key for key in acl_asic_meters if key not in original_asic_acl_meters + ] + assert len(meter_asic_db_keys) == 1 + meter_asic_db_key1 = meter_asic_db_keys[0] + + (status, fvs) = util.get_key( + self._p4rt_acl_meter_obj.asic_db, + self._p4rt_acl_meter_obj.ASIC_DB_TBL_NAME, + meter_asic_db_key1, + ) + assert status == True + attr_list = [ + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_TYPE, "SAI_METER_TYPE_PACKETS"), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_MODE, "SAI_POLICER_MODE_TR_TCM"), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_CIR, meter_cir), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_CBS, meter_cbs), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_PIR, meter_pir), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_PBS, meter_pbs), + ] + util.verify_attr(fvs, attr_list) + + # query ASIC database for ACL rules + acl_asic_rules = util.get_keys( + self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME + ) + assert len(acl_asic_rules) == len(original_asic_acl_rules) + 1 + + # query ASIC database for newly created ACL rule + rule_asic_db_keys = [ + key for key in acl_asic_rules if key not in original_asic_acl_rules + ] + assert len(rule_asic_db_keys) == 1 + rule_asic_db_key1 = rule_asic_db_keys[0] + + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.asic_db, + self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME, + rule_asic_db_key1, + ) + assert status == True + attr_list = [ + (self._p4rt_acl_rule_obj.SAI_ATTR_ACTION_SET_TC, "1"), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_ACTION_PACKET_ACTION, + "SAI_PACKET_ACTION_COPY", + ), + (self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_ETHER_TYPE, "2048&mask:0xffff"), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_IP_TYPE, + "SAI_ACL_IP_TYPE_ANY&mask:0xffffffffffffffff", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_DST_MAC, + "00:1A:11:17:5F:80&mask:FF:FF:FF:FF:FF:FF", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_SRC_IPV6_WORD3, + "fdf8:f53b::&mask:ffff:ffff::", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_SRC_IPV6_WORD2, + "0:0:82e4::&mask:0:0:ffff:ffff::", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_UDF_GROUP_MIN, + "2:255,102&mask:2:0xff,0xff", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_UDF_GROUP_1, + "2:85,67&mask:2:0xff,0xff", + ), + (self._p4rt_acl_rule_obj.SAI_ATTR_TABLE_ID, table_asic_db_key), + (self._p4rt_acl_rule_obj.SAI_ATTR_SET_POLICER, meter_asic_db_key1), + (self._p4rt_acl_rule_obj.SAI_ATTR_COUNTER, counter_asic_db_key1), + (self._p4rt_acl_rule_obj.SAI_ATTR_ADMIN_STATE, "true"), + (self._p4rt_acl_rule_obj.SAI_ATTR_PRIORITY, "100"), + ] + util.verify_attr(fvs, attr_list) + + # Update action and meter of rule 1 to punt_and_set_tc + rule_json_key1 = '{"match/ether_type":"0x0800","match/ether_dst":"00:1a:11:17:5f:80","match/src_ipv6_64bit":"fdf8:f53b:82e4::","match/arp_tpa":"0xff665543","priority":100}' + action = "punt_and_set_tc" + meter_cir = "100" + meter_cbs = "100" + meter_pir = "400" + meter_pbs = "400" + table_name_with_rule_key1 = table_name + ":" + rule_json_key1 + + attr_list = [ + (self._p4rt_acl_rule_obj.ACTION, action), + ("param/traffic_class", "2"), + (self._p4rt_acl_rule_obj.METER_CIR, meter_cir), + (self._p4rt_acl_rule_obj.METER_CBURST, meter_cbs), + (self._p4rt_acl_rule_obj.METER_PIR, meter_pir), + (self._p4rt_acl_rule_obj.METER_PBURST, meter_pbs), + ] + + self._p4rt_acl_rule_obj.set_app_db_entry(table_name_with_rule_key1, attr_list) + util.verify_response( + self.response_consumer, + table_name_with_rule_key1, + attr_list, + "SWSS_RC_SUCCESS", + ) + + # query application database for ACL rules + acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(acl_rules) == len(original_appl_acl_rules) + 1 + + # query application database for updated ACL rule + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, + table_name_with_rule_key1, + ) + assert status == True + util.verify_attr(fvs, attr_list) + + # query application state database for ACL rules + state_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(state_acl_rules) == len(original_appl_state_acl_rules) + 1 + + # query application state database for updated ACL rule + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, + table_name_with_rule_key1, + ) + assert status == True + util.verify_attr(fvs, attr_list) + + # query ASIC database for ACL counters + acl_asic_counters = util.get_keys( + self._p4rt_acl_counter_obj.asic_db, + self._p4rt_acl_counter_obj.ASIC_DB_TBL_NAME, + ) + assert len(acl_asic_counters) == len(original_asic_acl_counters) + 1 + + # query ASIC database for the ACL counter + counter_asic_db_keys = [ + key for key in acl_asic_counters if key not in original_asic_acl_counters + ] + assert len(counter_asic_db_keys) == 1 + counter_asic_db_key1 = counter_asic_db_keys[0] + + (status, fvs) = util.get_key( + self._p4rt_acl_counter_obj.asic_db, + self._p4rt_acl_counter_obj.ASIC_DB_TBL_NAME, + counter_asic_db_key1, + ) + assert status == True + attr_list = [ + (self._p4rt_acl_counter_obj.SAI_ATTR_ENABLE_PACKET_COUNT, "true"), + (self._p4rt_acl_counter_obj.SAI_ATTR_ENABLE_BYTE_COUNT, "true"), + (self._p4rt_acl_counter_obj.SAI_ATTR_TABLE_ID, table_asic_db_key), + ] + util.verify_attr(fvs, attr_list) + + # query ASIC database for ACL meters + acl_asic_meters = util.get_keys( + self._p4rt_acl_meter_obj.asic_db, self._p4rt_acl_meter_obj.ASIC_DB_TBL_NAME + ) + assert len(acl_asic_meters) == len(original_asic_acl_meters) + 1 + + # query ASIC database for updated ACL meter + meter_asic_db_keys = [ + key for key in acl_asic_meters if key not in original_asic_acl_meters + ] + assert len(meter_asic_db_keys) == 1 + meter_asic_db_key1 = meter_asic_db_keys[0] + + (status, fvs) = util.get_key( + self._p4rt_acl_meter_obj.asic_db, + self._p4rt_acl_meter_obj.ASIC_DB_TBL_NAME, + meter_asic_db_key1, + ) + assert status == True + attr_list = [ + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_TYPE, "SAI_METER_TYPE_PACKETS"), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_MODE, "SAI_POLICER_MODE_TR_TCM"), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_CIR, meter_cir), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_CBS, meter_cbs), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_PIR, meter_pir), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_PBS, meter_pbs), + ( + self._p4rt_acl_meter_obj.SAI_ATTR_RED_PACKET_ACTION, + "SAI_PACKET_ACTION_TRAP", + ), + ] + util.verify_attr(fvs, attr_list) + + # query ASIC database for ACL rules + acl_asic_rules = util.get_keys( + self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME + ) + assert len(acl_asic_rules) == len(original_asic_acl_rules) + 1 + + # query ASIC database for updated ACL rule + rule_asic_db_keys = [ + key for key in acl_asic_rules if key not in original_asic_acl_rules + ] + assert len(rule_asic_db_keys) == 1 + rule_asic_db_key1 = rule_asic_db_keys[0] + + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.asic_db, + self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME, + rule_asic_db_key1, + ) + assert status == True + attr_list = [ + (self._p4rt_acl_rule_obj.SAI_ATTR_ACTION_SET_TC, "2"), + (self._p4rt_acl_rule_obj.SAI_ATTR_ACTION_PACKET_ACTION, "disabled"), + (self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_ETHER_TYPE, "2048&mask:0xffff"), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_IP_TYPE, + "SAI_ACL_IP_TYPE_ANY&mask:0xffffffffffffffff", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_DST_MAC, + "00:1A:11:17:5F:80&mask:FF:FF:FF:FF:FF:FF", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_SRC_IPV6_WORD3, + "fdf8:f53b::&mask:ffff:ffff::", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_SRC_IPV6_WORD2, + "0:0:82e4::&mask:0:0:ffff:ffff::", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_UDF_GROUP_MIN, + "2:255,102&mask:2:0xff,0xff", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_UDF_GROUP_1, + "2:85,67&mask:2:0xff,0xff", + ), + (self._p4rt_acl_rule_obj.SAI_ATTR_TABLE_ID, table_asic_db_key), + (self._p4rt_acl_rule_obj.SAI_ATTR_SET_POLICER, meter_asic_db_key1), + (self._p4rt_acl_rule_obj.SAI_ATTR_COUNTER, counter_asic_db_key1), + (self._p4rt_acl_rule_obj.SAI_ATTR_ADMIN_STATE, "true"), + (self._p4rt_acl_rule_obj.SAI_ATTR_PRIORITY, "100"), + ] + util.verify_attr(fvs, attr_list) + + # create ACL rule 2 with QOS_QUEUE action + rule_json_key2 = '{"match/is_ip":"0x1","match/ether_type":"0x0800 & 0xFFFF","match/ether_dst":"AA:BB:CC:DD:EE:FF & FF:FF:FF:FF:FF:FF","priority":100}' + action = "qos_queue" + meter_cir = "80" + meter_cbs = "80" + meter_pir = "200" + meter_pbs = "200" + table_name_with_rule_key2 = table_name + ":" + rule_json_key2 + + attr_list = [ + (self._p4rt_acl_rule_obj.ACTION, action), + ("param/cpu_queue", "5"), + (self._p4rt_acl_rule_obj.METER_CIR, meter_cir), + (self._p4rt_acl_rule_obj.METER_CBURST, meter_cbs), + (self._p4rt_acl_rule_obj.METER_PIR, meter_pir), + (self._p4rt_acl_rule_obj.METER_PBURST, meter_pbs), + ] + + self._p4rt_acl_rule_obj.set_app_db_entry(table_name_with_rule_key2, attr_list) + util.verify_response( + self.response_consumer, + table_name_with_rule_key2, + attr_list, + "SWSS_RC_SUCCESS", + ) + + # query application database for ACL rules + acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(acl_rules) == len(original_appl_acl_rules) + 2 + + # query application database for newly created ACL rule + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, + table_name_with_rule_key2, + ) + assert status == True + util.verify_attr(fvs, attr_list) + + # query application state database for ACL rules + state_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(state_acl_rules) == len(original_appl_state_acl_rules) + 2 + + # query application state database for newly created ACL rule + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, + table_name_with_rule_key2, + ) + assert status == True + util.verify_attr(fvs, attr_list) + + # query ASIC database for ACL counters + acl_asic_counters = util.get_keys( + self._p4rt_acl_counter_obj.asic_db, + self._p4rt_acl_counter_obj.ASIC_DB_TBL_NAME, + ) + assert len(acl_asic_counters) == len(original_asic_acl_counters) + 2 + + # query ASIC database for newly created ACL counter + counter_asic_db_keys = [ + key + for key in acl_asic_counters + if key not in original_asic_acl_counters and key != counter_asic_db_key1 + ] + assert len(counter_asic_db_keys) == 1 + counter_asic_db_key2 = counter_asic_db_keys[0] + + (status, fvs) = util.get_key( + self._p4rt_acl_counter_obj.asic_db, + self._p4rt_acl_counter_obj.ASIC_DB_TBL_NAME, + counter_asic_db_key2, + ) + assert status == True + attr_list = [ + (self._p4rt_acl_counter_obj.SAI_ATTR_ENABLE_PACKET_COUNT, "true"), + (self._p4rt_acl_counter_obj.SAI_ATTR_ENABLE_BYTE_COUNT, "true"), + (self._p4rt_acl_counter_obj.SAI_ATTR_TABLE_ID, table_asic_db_key), + ] + util.verify_attr(fvs, attr_list) + + # query ASIC database for ACL meters + acl_asic_meters = util.get_keys( + self._p4rt_acl_meter_obj.asic_db, self._p4rt_acl_meter_obj.ASIC_DB_TBL_NAME + ) + assert len(acl_asic_meters) == len(original_asic_acl_meters) + 2 + + # query ASIC database for newly created ACL meter + meter_asic_db_keys = [ + key + for key in acl_asic_meters + if key not in original_asic_acl_meters and key != meter_asic_db_key1 + ] + assert len(meter_asic_db_keys) == 1 + meter_asic_db_key2 = meter_asic_db_keys[0] + + (status, fvs) = util.get_key( + self._p4rt_acl_meter_obj.asic_db, + self._p4rt_acl_meter_obj.ASIC_DB_TBL_NAME, + meter_asic_db_key2, + ) + assert status == True + attr_list = [ + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_TYPE, "SAI_METER_TYPE_PACKETS"), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_MODE, "SAI_POLICER_MODE_TR_TCM"), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_CIR, meter_cir), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_CBS, meter_cbs), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_PIR, meter_pir), + (self._p4rt_acl_meter_obj.SAI_ATTR_METER_PBS, meter_pbs), + ] + util.verify_attr(fvs, attr_list) + + # query ASIC database for trap groups + trap_group_keys = util.get_keys( + self._p4rt_trap_group_obj.asic_db, + self._p4rt_trap_group_obj.ASIC_DB_TBL_NAME, + ) + # default trap groups in and one trap groups per cpu queue + # are defined in files/image_config/copp/copp_cfg.j2 + # get trap group with cpu queue num 5 + for key in trap_group_keys: + (status, fvs) = util.get_key( + self._p4rt_trap_group_obj.asic_db, + self._p4rt_trap_group_obj.ASIC_DB_TBL_NAME, + key, + ) + assert status == True + if fvs[0][1] == "5": + trap_group_asic_db_key = key + break + + # query ASIC database for user defined traps + user_trap_keys = util.get_keys( + self._p4rt_user_trap_obj.asic_db, self._p4rt_user_trap_obj.ASIC_DB_TBL_NAME + ) + assert len(user_trap_keys) == 8 + + # get user trap with trap group oid + for key in user_trap_keys: + (status, fvs) = util.get_key( + self._p4rt_user_trap_obj.asic_db, + self._p4rt_user_trap_obj.ASIC_DB_TBL_NAME, + key, + ) + assert status == True + if ( + fvs[0][1] == trap_group_asic_db_key + or fvs[1][1] == trap_group_asic_db_key + ): + user_trap_asic_db_key = key + break + + # query ASIC database for ACL rules + acl_asic_rules = util.get_keys( + self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME + ) + assert len(acl_asic_rules) == len(original_asic_acl_rules) + 2 + + # query ASIC database for newly created ACL rule + rule_asic_db_keys = [ + key + for key in acl_asic_rules + if key not in original_asic_acl_rules and key != rule_asic_db_key1 + ] + assert len(rule_asic_db_keys) == 1 + rule_asic_db_key2 = rule_asic_db_keys[0] + + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.asic_db, + self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME, + rule_asic_db_key2, + ) + assert status == True + attr_list = [ + ( + self._p4rt_acl_rule_obj.SAI_ATTR_ACTION_SET_USER_TRAP_ID, + user_trap_asic_db_key, + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_ACTION_PACKET_ACTION, + "SAI_PACKET_ACTION_TRAP", + ), + (self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_ETHER_TYPE, "2048&mask:0xffff"), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_IP_TYPE, + "SAI_ACL_IP_TYPE_IP&mask:0xffffffffffffffff", + ), + ( + self._p4rt_acl_rule_obj.SAI_ATTR_MATCH_DST_MAC, + "AA:BB:CC:DD:EE:FF&mask:FF:FF:FF:FF:FF:FF", + ), + (self._p4rt_acl_rule_obj.SAI_ATTR_TABLE_ID, table_asic_db_key), + (self._p4rt_acl_rule_obj.SAI_ATTR_SET_POLICER, meter_asic_db_key2), + (self._p4rt_acl_rule_obj.SAI_ATTR_COUNTER, counter_asic_db_key2), + (self._p4rt_acl_rule_obj.SAI_ATTR_ADMIN_STATE, "true"), + (self._p4rt_acl_rule_obj.SAI_ATTR_PRIORITY, "100"), + ] + util.verify_attr(fvs, attr_list) + + # remove ACL rule 1 + self._p4rt_acl_rule_obj.remove_app_db_entry(table_name_with_rule_key1) + util.verify_response( + self.response_consumer, table_name_with_rule_key1, [], "SWSS_RC_SUCCESS" + ) + + # query application database for ACL rules + acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(acl_rules) == len(original_appl_acl_rules) + 1 + + # verify that the ACL rule no longer exists in application database + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME, + table_name_with_rule_key1, + ) + assert status == False + + # query application state database for ACL rules + state_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(state_acl_rules) == len(original_appl_state_acl_rules) + 1 + + # verify that the ACL rule no longer exists in application state database + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME, + table_name_with_rule_key1, + ) + assert status == False + + # query ASIC database for ACL rules + acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME + ) + assert len(acl_rules) == len(original_asic_acl_rules) + 1 + + # verify that removed ACL rule no longer exists in ASIC database + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.asic_db, + self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME, + rule_asic_db_key1, + ) + assert status == False + + # verify that removed ACL counter no longer exists in ASIC database + (status, fvs) = util.get_key( + self._p4rt_acl_counter_obj.asic_db, + self._p4rt_acl_counter_obj.ASIC_DB_TBL_NAME, + counter_asic_db_key1, + ) + assert status == False + + # verify that removed ACL meter no longer exists in ASIC database + (status, fvs) = util.get_key( + self._p4rt_acl_meter_obj.asic_db, + self._p4rt_acl_meter_obj.ASIC_DB_TBL_NAME, + meter_asic_db_key1, + ) + assert status == False + + # remove ACL rule 2 + self._p4rt_acl_rule_obj.remove_app_db_entry(table_name_with_rule_key2) + util.verify_response( + self.response_consumer, table_name_with_rule_key2, [], "SWSS_RC_SUCCESS" + ) + + # query application database for ACL rules + acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(acl_rules) == len(original_appl_acl_rules) + + # verify that the ACL rule no longer exists in application database + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME, + table_name_with_rule_key2, + ) + assert status == False + + # query application state database for ACL rules + state_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(state_acl_rules) == len(original_appl_state_acl_rules) + + # verify that the ACL rule no longer exists in application state database + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME, + table_name_with_rule_key2, + ) + assert status == False + + # query ASIC database for ACL rules + acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME + ) + assert len(acl_rules) == len(original_asic_acl_rules) + + # verify that removed ACL rule no longer exists in ASIC database + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.asic_db, + self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME, + rule_asic_db_key2, + ) + assert status == False + + # verify that removed ACL counter no longer exists in ASIC database + (status, fvs) = util.get_key( + self._p4rt_acl_counter_obj.asic_db, + self._p4rt_acl_counter_obj.ASIC_DB_TBL_NAME, + counter_asic_db_key2, + ) + assert status == False + + # verify that removed ACL meter no longer exists in ASIC database + (status, fvs) = util.get_key( + self._p4rt_acl_meter_obj.asic_db, + self._p4rt_acl_meter_obj.ASIC_DB_TBL_NAME, + meter_asic_db_key2, + ) + assert status == False + + # remove ACL table + self._p4rt_acl_table_definition_obj.remove_app_db_entry( + self._p4rt_acl_table_definition_obj.TBL_NAME + ":" + table_name + ) + util.verify_response( + self.response_consumer, + self._p4rt_acl_table_definition_obj.TBL_NAME + ":" + table_name, + [], + "SWSS_RC_SUCCESS", + ) + + # query application database for ACL tables + acl_tables = util.get_keys( + self._p4rt_acl_table_definition_obj.appl_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME + + ":" + + self._p4rt_acl_table_definition_obj.TBL_NAME, + ) + assert len(acl_tables) == len(original_appl_acl_tables) + + # verify that the ACL table no longer exists in application database + (status, fvs) = util.get_key( + self._p4rt_acl_table_definition_obj.appl_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, + self._p4rt_acl_table_definition_obj.TBL_NAME + ":" + table_name, + ) + assert status == False + + # query application state database for ACL tables + state_acl_tables = util.get_keys( + self._p4rt_acl_table_definition_obj.appl_state_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME + + ":" + + self._p4rt_acl_table_definition_obj.TBL_NAME, + ) + assert len(state_acl_tables) == len(original_appl_state_acl_tables) + + # verify that the ACL table no longer exists in application state database + (status, fvs) = util.get_key( + self._p4rt_acl_table_definition_obj.appl_state_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, + self._p4rt_acl_table_definition_obj.TBL_NAME + ":" + table_name, + ) + assert status == False + + # query ASIC database for ACL tables + acl_tables = util.get_keys( + self._p4rt_acl_table_definition_obj.asic_db, + self._p4rt_acl_table_definition_obj.ASIC_DB_TBL_NAME, + ) + assert len(acl_tables) == len(original_asic_acl_tables) + + # verify that removed ACL table no longer exists in ASIC database + (status, fvs) = util.get_key( + self._p4rt_acl_table_definition_obj.asic_db, + self._p4rt_acl_table_definition_obj.ASIC_DB_TBL_NAME, + table_asic_db_key, + ) + assert status == False + + def test_AclRuleAddWithoutTableDefinitionFails(self, dvs, testlog): + # initialize ACL table objects and database connectors + self._set_up(dvs) + + # maintain list of original Application and ASIC DB ACL entries before adding + # new ACL rule + table_name = "ACL_PUNT_TABLE_RULE_TEST" + original_appl_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + original_appl_state_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + original_asic_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME + ) + + # create ACL rule + rule_json_key = '{"match/ether_type":"0x0800","match/ether_dst":"00:1a:11:17:5f:80","match/src_ipv6_64bit":"fdf8:f53b:82e4::","match/arp_tpa":"0xff665543","priority":100}' + action = "copy_and_set_tc" + meter_cir = "80" + meter_cbs = "80" + meter_pir = "200" + meter_pbs = "200" + table_name_with_rule_key = table_name + ":" + rule_json_key + + attr_list = [ + (self._p4rt_acl_rule_obj.ACTION, action), + ("param/traffic_class", "1"), + (self._p4rt_acl_rule_obj.METER_CIR, meter_cir), + (self._p4rt_acl_rule_obj.METER_CBURST, meter_cbs), + (self._p4rt_acl_rule_obj.METER_PIR, meter_pir), + (self._p4rt_acl_rule_obj.METER_PBURST, meter_pbs), + ] + + self._p4rt_acl_rule_obj.set_app_db_entry(table_name_with_rule_key, attr_list) + util.verify_response( + self.response_consumer, + table_name_with_rule_key, + attr_list, + "SWSS_RC_INVALID_PARAM", + "[OrchAgent] Failed to find P4Orch Manager for ACL_PUNT_TABLE_RULE_TEST P4RT DB table", + ) + + # query application database for ACL rules + acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(acl_rules) == len(original_appl_acl_rules) + 1 + + # query application database for newly created ACL rule + (status, fvs) = util.get_key( + self._p4rt_acl_rule_obj.appl_db, + self._p4rt_acl_table_definition_obj.APP_DB_TBL_NAME, + table_name_with_rule_key, + ) + assert status == True + util.verify_attr(fvs, attr_list) + + # query application state database for ACL rules + state_acl_rules = util.get_keys( + self._p4rt_acl_rule_obj.appl_state_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME + ":" + table_name, + ) + assert len(state_acl_rules) == len(original_appl_state_acl_rules) + + # query ASIC database for ACL rules + acl_asic_rules = util.get_keys( + self._p4rt_acl_rule_obj.asic_db, self._p4rt_acl_rule_obj.ASIC_DB_TBL_NAME + ) + assert len(acl_asic_rules) == len(original_asic_acl_rules) + + # query ASIC database for newly created ACL rule + rule_asic_db_keys = [ + key for key in acl_asic_rules if key not in original_asic_acl_rules + ] + assert len(rule_asic_db_keys) == 0 + + # cleanup application database + tbl = swsscommon.Table( + self._p4rt_acl_table_definition_obj.appl_db, + self._p4rt_acl_rule_obj.APP_DB_TBL_NAME, + ) + tbl._del(table_name_with_rule_key) diff --git a/tests/p4rt/test_p4rt_mirror.py b/tests/p4rt/test_p4rt_mirror.py new file mode 100644 index 000000000000..c62574929350 --- /dev/null +++ b/tests/p4rt/test_p4rt_mirror.py @@ -0,0 +1,220 @@ +from swsscommon import swsscommon + +import util +import json + +class P4RtMirrorSessionWrapper(util.DBInterface): + """Interface to interact with APP DB and ASIC DB tables for P4RT mirror session object.""" + + # database and SAI constants + APP_DB_TBL_NAME = swsscommon.APP_P4RT_TABLE_NAME + TBL_NAME = swsscommon.APP_P4RT_MIRROR_SESSION_TABLE_NAME + ACTION = "action" + PORT = "port" + SRC_IP = "src_ip" + DST_IP = "dst_ip" + SRC_MAC = "src_mac" + DST_MAC = "dst_mac" + TTL = "ttl" + TOS = "tos" + + ASIC_DB_TBL_NAME = "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION" + SAI_MIRROR_SESSION_ATTR_MONITOR_PORT = "SAI_MIRROR_SESSION_ATTR_MONITOR_PORT" + SAI_MIRROR_SESSION_ATTR_TYPE = "SAI_MIRROR_SESSION_ATTR_TYPE" + SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE = "SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE" + SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION = "SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION" + SAI_MIRROR_SESSION_ATTR_TOS = "SAI_MIRROR_SESSION_ATTR_TOS" + SAI_MIRROR_SESSION_ATTR_TTL = "SAI_MIRROR_SESSION_ATTR_TTL" + SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS = "SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS" + SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS = "SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS" + SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS = "SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS" + SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS = "SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS" + SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE = "SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE" + + def generate_app_db_key(self, mirror_session_id): + d = {} + d[util.prepend_match_field("mirror_session_id")] = mirror_session_id + key = json.dumps(d, separators=(",", ":")) + return self.TBL_NAME + ":" + key + +class TestP4RTMirror(object): + def _set_up(self, dvs): + self._p4rt_mirror_session_wrapper = P4RtMirrorSessionWrapper() + self._p4rt_mirror_session_wrapper.set_up_databases(dvs) + self._response_consumer = swsscommon.NotificationConsumer( + self._p4rt_mirror_session_wrapper.appl_db, "APPL_DB_P4RT_TABLE_RESPONSE_CHANNEL") + + def test_MirrorSessionAddModifyAndDelete(self, dvs, testlog): + # Initialize database connectors + self._set_up(dvs) + + # Maintain list of original Application and ASIC DB entries before adding + # new mirror session + original_appl_mirror_entries = util.get_keys( + self._p4rt_mirror_session_wrapper.appl_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME + ":" + self._p4rt_mirror_session_wrapper.TBL_NAME) + original_appl_state_mirror_entries = util.get_keys( + self._p4rt_mirror_session_wrapper.appl_state_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME + ":" + self._p4rt_mirror_session_wrapper.TBL_NAME) + original_asic_mirror_entries = util.get_keys( + self._p4rt_mirror_session_wrapper.asic_db, self._p4rt_mirror_session_wrapper.ASIC_DB_TBL_NAME) + + # 1. Create mirror session + mirror_session_id = "mirror_session1" + action = "mirror_as_ipv4_erspan" + port = "Ethernet8" + src_ip = "10.206.196.31" + dst_ip = "172.20.0.203" + src_mac = "00:02:03:04:05:06" + dst_mac = "00:1A:11:17:5F:80" + ttl = "0x40" + tos = "0x00" + + attr_list_in_app_db = [(self._p4rt_mirror_session_wrapper.ACTION, action), + (util.prepend_param_field(self._p4rt_mirror_session_wrapper.PORT), port), + (util.prepend_param_field(self._p4rt_mirror_session_wrapper.SRC_IP), src_ip), + (util.prepend_param_field(self._p4rt_mirror_session_wrapper.DST_IP), dst_ip), + (util.prepend_param_field(self._p4rt_mirror_session_wrapper.SRC_MAC), src_mac), + (util.prepend_param_field(self._p4rt_mirror_session_wrapper.DST_MAC), dst_mac), + (util.prepend_param_field(self._p4rt_mirror_session_wrapper.TTL), ttl), + (util.prepend_param_field(self._p4rt_mirror_session_wrapper.TOS), tos)] + mirror_session_key = self._p4rt_mirror_session_wrapper.generate_app_db_key( + mirror_session_id) + self._p4rt_mirror_session_wrapper.set_app_db_entry( + mirror_session_key, attr_list_in_app_db) + util.verify_response( + self._response_consumer, mirror_session_key, attr_list_in_app_db, "SWSS_RC_SUCCESS") + + # Query application database for mirror entries + appl_mirror_entries = util.get_keys( + self._p4rt_mirror_session_wrapper.appl_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME + ":" + self._p4rt_mirror_session_wrapper.TBL_NAME) + assert len(appl_mirror_entries) == len(original_appl_mirror_entries) + 1 + + # Query application database for newly created mirror key + (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.appl_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME, + mirror_session_key) + assert status == True + util.verify_attr(fvs, attr_list_in_app_db) + + # Query application state database for mirror entries + appl_state_mirror_entries = util.get_keys( + self._p4rt_mirror_session_wrapper.appl_state_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME + ":" + self._p4rt_mirror_session_wrapper.TBL_NAME) + assert len(appl_state_mirror_entries) == len(original_appl_state_mirror_entries) + 1 + + # Query application state database for newly created mirror key + (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.appl_state_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME, + mirror_session_key) + assert status == True + util.verify_attr(fvs, attr_list_in_app_db) + + # Query ASIC database for mirror entries + asic_mirror_entries = util.get_keys(self._p4rt_mirror_session_wrapper.asic_db, + self._p4rt_mirror_session_wrapper.ASIC_DB_TBL_NAME) + assert len(asic_mirror_entries) == len(original_asic_mirror_entries) + 1 + + # Query ASIC database for newly created mirror key + asic_db_key = None + for key in asic_mirror_entries: + # Get newly created entry + if key not in original_asic_mirror_entries: + asic_db_key = key + break + assert asic_db_key is not None + (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.asic_db, + self._p4rt_mirror_session_wrapper.ASIC_DB_TBL_NAME, + asic_db_key) + assert status == True + + # Get oid of Ethernet8 + port_oid = util.get_port_oid_by_name(dvs, port) + assert port_oid != None + + expected_attr_list_in_asic_db = [ + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_MONITOR_PORT, port_oid), + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_TYPE, "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE"), + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE, "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL"), + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION, "4"), # MIRROR_SESSION_DEFAULT_IP_HDR_VER + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_TOS, "0"), + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_TTL, "64"), + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS, src_ip), + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS, dst_ip), + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS, src_mac), + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS, dst_mac), + (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE, "35006") # GRE_PROTOCOL_ERSPAN 0x88be + ] + util.verify_attr(fvs, expected_attr_list_in_asic_db) + + # 2. Modify the existing mirror session. + new_dst_mac = "00:1A:11:17:5F:FF" + attr_list_in_app_db[5] = (util.prepend_param_field(self._p4rt_mirror_session_wrapper.DST_MAC), new_dst_mac) + self._p4rt_mirror_session_wrapper.set_app_db_entry( + mirror_session_key, attr_list_in_app_db) + util.verify_response( + self._response_consumer, mirror_session_key, attr_list_in_app_db, "SWSS_RC_SUCCESS") + + # Query application database for the modified mirror key + (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.appl_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME, + mirror_session_key) + assert status == True + util.verify_attr(fvs, attr_list_in_app_db) + + # Query application state database for the modified mirror key + (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.appl_state_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME, + mirror_session_key) + assert status == True + util.verify_attr(fvs, attr_list_in_app_db) + + # Query ASIC DB about the modified mirror session. + expected_attr_list_in_asic_db[9] = (self._p4rt_mirror_session_wrapper.SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS, new_dst_mac) + (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.asic_db, + self._p4rt_mirror_session_wrapper.ASIC_DB_TBL_NAME, + asic_db_key) + assert status == True + util.verify_attr(fvs, expected_attr_list_in_asic_db) + + # 3. Delete the mirror session. + self._p4rt_mirror_session_wrapper.remove_app_db_entry( + mirror_session_key) + util.verify_response( + self._response_consumer, mirror_session_key, [], "SWSS_RC_SUCCESS") + + # Query application database for mirror entries + appl_mirror_entries = util.get_keys( + self._p4rt_mirror_session_wrapper.appl_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME + ":" + self._p4rt_mirror_session_wrapper.TBL_NAME) + assert len(appl_mirror_entries) == len(original_appl_mirror_entries) + + # Query application database for the deleted mirror key + (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.appl_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME, + mirror_session_key) + assert status == False + + # Query application state database for mirror entries + appl_state_mirror_entries = util.get_keys( + self._p4rt_mirror_session_wrapper.appl_state_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME + ":" + self._p4rt_mirror_session_wrapper.TBL_NAME) + assert len(appl_state_mirror_entries) == len(original_appl_state_mirror_entries) + + # Query application state database for the deleted mirror key + (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.appl_state_db, + self._p4rt_mirror_session_wrapper.APP_DB_TBL_NAME, + mirror_session_key) + assert status == False + + # Query ASIC database for mirror entries + asic_mirror_entries = util.get_keys(self._p4rt_mirror_session_wrapper.asic_db, + self._p4rt_mirror_session_wrapper.ASIC_DB_TBL_NAME) + assert len(asic_mirror_entries) == len(original_asic_mirror_entries) + + # Query ASIC state database for the deleted mirror key + (status, fvs) = util.get_key(self._p4rt_mirror_session_wrapper.asic_db, + self._p4rt_mirror_session_wrapper.ASIC_DB_TBL_NAME, + asic_db_key) + assert status == False diff --git a/tests/p4rt/util.py b/tests/p4rt/util.py new file mode 100644 index 000000000000..831c7a5cbec5 --- /dev/null +++ b/tests/p4rt/util.py @@ -0,0 +1,135 @@ +""" Defines common P4RT utility functions.""" +from swsscommon import swsscommon + +import time + + +def _set_up_appl_db(dvs): + """ Initializes application database connector.""" + return swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0) + + +def _set_up_asic_db(dvs): + """ Initializes ASIC database connector.""" + return swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + + +def _set_up_appl_state_db(dvs): + """ Initializes APPL STATE database connector.""" + return swsscommon.DBConnector(swsscommon.APPL_STATE_DB, dvs.redis_sock, 0) + + +def get_keys(db, tbl_name): + """ Retrieves keys from given database and table.""" + tbl = swsscommon.Table(db, tbl_name) + return tbl.getKeys() + + +def get_key(db, tbl_name, key): + """ Retrieves entry corresponding to given key in given database and table.""" + tbl = swsscommon.Table(db, tbl_name) + return tbl.get(key) + + +def verify_attr(fvs, attr_list): + """ Verifies attribute list for given key in a database table.""" + assert len(fvs) == len(attr_list) + d = dict(attr_list) + for fv in fvs: + if fv[0] in d: + assert fv[1] == d[fv[0]] + else: + assert False + +def prepend_match_field(match_field): + return "match/" + match_field + +def prepend_param_field(param_field): + return "param/" + param_field + +def verify_response(consumer, key, attr_list, status, err_message = "SWSS_RC_SUCCESS"): + """ Verifies a response.""" + consumer.readData() + (op, data, values) = consumer.pop() + assert data == key + assert op == status + assert len(values) >= 1 + assert values[0][0] == "err_str" + assert values[0][1] == err_message + values = values[1:] + verify_attr(values, attr_list) + + +def check_syslog(dvs, marker, process, err_log, expected_cnt): + """ Checks syslog on dvs docker. + + Scans /var/log/syslog for expected count (expected_cnt) of the error + log(err_log). Filters Logs starting at timestamp marked by "marker" based on + the given process. + """ + (exitcode, num) = dvs.runcmd([ + "sh", "-c", + "awk \'/%s/,ENDFILE {print;}\' /var/log/syslog | grep %s | grep -E \'%s\' | wc -l" + % (marker, process, err_log) + ]) + assert num.strip() == str(expected_cnt) + +def get_port_oid_by_name(dvs, port_name): + counters_db = swsscommon.DBConnector(swsscommon.COUNTERS_DB, dvs.redis_sock, 0) + port_map_tbl = swsscommon.Table(counters_db, "COUNTERS_PORT_NAME_MAP") + port_oid = None + for k in port_map_tbl.get("")[1]: + if k[0] == port_name: + port_oid = k[1] + return port_oid + +def initialize_interface(dvs, port_name, ip): + dvs.runcmd("config interface startup {}".format(port_name)) + dvs.runcmd("config interface ip add {} {}".format(port_name, ip)) + +def set_interface_status(dvs, if_name, status = "down", server = 0): + dvs.servers[0].runcmd("ip link set {} dev {}".format(status, if_name)) == 0 + time.sleep(1) + +class DBInterface(object): + """ Interface to interact with different redis databases on dvs.""" + + # common attribute fields for L3 objects + ACTION_FIELD = "action" + + def set_up_databases(self, dvs): + self.appl_db = _set_up_appl_db(dvs) + self.asic_db = _set_up_asic_db(dvs) + self.appl_state_db = _set_up_appl_state_db(dvs) + + def set_app_db_entry(self, key, attr_list): + fvs = swsscommon.FieldValuePairs(attr_list) + tbl = swsscommon.ProducerStateTable(self.appl_db, self.APP_DB_TBL_NAME) + tbl.set(key, fvs) + time.sleep(1) + + def remove_app_db_entry(self, key): + tbl = swsscommon.ProducerStateTable(self.appl_db, self.APP_DB_TBL_NAME) + tbl._del(key) + time.sleep(1) + + # Get list of original entries in redis on init. + def get_original_redis_entries(self, db_list): + self._original_entries = {} + for i in db_list: + db = i[0] + table = i[1] + self._original_entries["{}:{}".format(db, table)]= get_keys(db, table) + +class KeyToOidDBHelper(object): + """Provides helper APIs for P4RT key to OID mapping in Redis DB.""" + + # Table name in Redis DB for the mapping. + TBL_NAME = "P4RT_KEY_TO_OID" + KEY = "" + + def __init__(self, dvs): + self.table = swsscommon.Table(_set_up_appl_state_db(dvs), self.TBL_NAME) + + def get_db_info(self): + return self.table.get(self.KEY)