unittest/vslib/TestSwitchMLNX2700.cpp (447 lines of code) (raw):

#include <cstdint> #include <memory> #include <string> #include <vector> #include <array> #include <gtest/gtest.h> #include "meta/Globals.h" #include "meta/sai_serialize.h" #include "ContextConfigContainer.h" #include "SwitchMLNX2700.h" using namespace saimeta; using namespace saivs; class SwitchMLNX2700Test : public ::testing::Test { public: SwitchMLNX2700Test() = default; virtual ~SwitchMLNX2700Test() = default; public: virtual void SetUp() override { m_ccc = ContextConfigContainer::getDefault(); m_cc = m_ccc->get(m_guid); m_scc = m_cc->m_scc; m_sc = m_scc->getConfig(m_scid); m_sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU; m_sc->m_switchType = SAI_VS_SWITCH_TYPE_MLNX2700; m_sc->m_bootType = SAI_VS_BOOT_TYPE_COLD; m_sc->m_useTapDevice = false; m_sc->m_laneMap = LaneMap::getDefaultLaneMap(); m_sc->m_eventQueue = std::make_shared<EventQueue>(std::make_shared<Signal>()); m_ridmgr = std::make_shared<RealObjectIdManager>(m_cc->m_guid, m_cc->m_scc); m_swid = m_ridmgr->allocateNewSwitchObjectId(Globals::getHardwareInfo(0, nullptr)); m_ss = std::make_shared<SwitchMLNX2700>(m_swid, m_ridmgr, m_sc); } virtual void TearDown() override { // Empty } protected: std::shared_ptr<ContextConfigContainer> m_ccc; std::shared_ptr<ContextConfig> m_cc; std::shared_ptr<SwitchConfigContainer> m_scc; std::shared_ptr<SwitchConfig> m_sc; std::shared_ptr<RealObjectIdManager> m_ridmgr; std::shared_ptr<SwitchStateBase> m_ss; sai_object_id_t m_swid = SAI_NULL_OBJECT_ID; const std::uint32_t m_guid = 0; // default context config id const std::uint32_t m_scid = 0; // default switch config id }; TEST_F(SwitchMLNX2700Test, portBulkAddRemove) { const std::uint32_t portCount = 32; const std::uint32_t laneCount = 4; // Generate port object ids std::vector<sai_object_id_t> oidList(portCount, SAI_NULL_OBJECT_ID); for (std::uint32_t idx = 0; idx < portCount; idx++) { oidList[idx] = m_ridmgr->allocateNewObjectId(SAI_OBJECT_TYPE_PORT, m_swid); } // Serialize port object ids std::vector<std::string> serializedOidList; for (std::uint32_t idx = 0; idx < portCount; idx++) { serializedOidList.emplace_back(sai_serialize_object_id(oidList[idx])); } // Generate port config std::vector<std::array<std::uint32_t, laneCount>> laneDataList; std::vector<std::vector<sai_attribute_t>> attrDataList; std::vector<std::uint32_t> attrCountList; std::vector<const sai_attribute_t*> attrPtrList; std::vector<sai_status_t> statusList(portCount, SAI_STATUS_SUCCESS); for (std::uint32_t idx = 0; idx < portCount * 4; idx += 4) { sai_attribute_t attr; std::vector<sai_attribute_t> attrList; std::array<std::uint32_t, laneCount> laneList = { idx, idx + 1, idx + 2, idx + 3 }; laneDataList.push_back(laneList); attr.id = SAI_PORT_ATTR_HW_LANE_LIST; attr.value.u32list.count = static_cast<std::uint32_t>(laneDataList.back().size()); attr.value.u32list.list = laneDataList.back().data(); attrList.push_back(attr); attr.id = SAI_PORT_ATTR_SPEED; attr.value.u32 = 1000; attrList.push_back(attr); attrDataList.push_back(attrList); attrCountList.push_back(static_cast<std::uint32_t>(attrDataList.back().size())); attrPtrList.push_back(attrDataList.back().data()); } // Verify port bulk add auto status = m_ss->bulkCreate( m_swid, SAI_OBJECT_TYPE_PORT, serializedOidList, attrCountList.data(), attrPtrList.data(), SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR, statusList.data() ); ASSERT_EQ(status, SAI_STATUS_SUCCESS); for (std::uint32_t i = 0; i < portCount; i++) { ASSERT_EQ(statusList.at(i), SAI_STATUS_SUCCESS); } // Verify port bulk remove status = m_ss->bulkRemove( SAI_OBJECT_TYPE_PORT, serializedOidList, SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR, statusList.data() ); ASSERT_EQ(status, SAI_STATUS_SUCCESS); for (std::uint32_t i = 0; i < portCount; i++) { ASSERT_EQ(statusList.at(i), SAI_STATUS_SUCCESS); } } TEST(SwitchMLNX2700, ctr) { auto sc = std::make_shared<SwitchConfig>(0, ""); auto signal = std::make_shared<Signal>(); auto eventQueue = std::make_shared<EventQueue>(signal); sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU; sc->m_switchType = SAI_VS_SWITCH_TYPE_MLNX2700; sc->m_bootType = SAI_VS_BOOT_TYPE_COLD; sc->m_useTapDevice = false; sc->m_laneMap = LaneMap::getDefaultLaneMap(0); sc->m_eventQueue = eventQueue; auto scc = std::make_shared<SwitchConfigContainer>(); scc->insert(sc); SwitchMLNX2700 sw( 0x2100000000, std::make_shared<RealObjectIdManager>(0, scc), sc); SwitchMLNX2700 sw2( 0x2100000000, std::make_shared<RealObjectIdManager>(0, scc), sc, nullptr); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; attr.value.booldata = true; EXPECT_EQ(sw.initialize_default_objects(1, &attr), SAI_STATUS_SUCCESS); } TEST(SwitchMLNX2700, refresh_bridge_port_list) { auto sc = std::make_shared<SwitchConfig>(0, ""); auto signal = std::make_shared<Signal>(); auto eventQueue = std::make_shared<EventQueue>(signal); sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU; sc->m_switchType = SAI_VS_SWITCH_TYPE_MLNX2700; sc->m_bootType = SAI_VS_BOOT_TYPE_COLD; sc->m_useTapDevice = false; sc->m_laneMap = LaneMap::getDefaultLaneMap(0); sc->m_eventQueue = eventQueue; auto scc = std::make_shared<SwitchConfigContainer>(); scc->insert(sc); SwitchMLNX2700 sw( 0x2100000000, std::make_shared<RealObjectIdManager>(0, scc), sc); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; attr.value.booldata = true; EXPECT_EQ(sw.initialize_default_objects(1, &attr), SAI_STATUS_SUCCESS); attr.id = SAI_SWITCH_ATTR_DEFAULT_1Q_BRIDGE_ID; attr.value.oid = SAI_NULL_OBJECT_ID; EXPECT_EQ(sw.get(SAI_OBJECT_TYPE_SWITCH, "oid:0x2100000000", 1, &attr), SAI_STATUS_SUCCESS); EXPECT_NE(attr.value.oid, SAI_NULL_OBJECT_ID); auto boid = attr.value.oid; auto sboid = sai_serialize_object_id(boid); sai_object_id_t list[128]; attr.id = SAI_BRIDGE_ATTR_PORT_LIST; attr.value.objlist.count = 128; attr.value.objlist.list = list; EXPECT_EQ(sw.get(SAI_OBJECT_TYPE_BRIDGE, sboid, 1, &attr), SAI_STATUS_SUCCESS); } static std::map<sai_object_id_t, WarmBootState> g_warmBootState; // TODO move to utils static bool getWarmBootState( _In_ const char* warmBootFile, _In_ std::shared_ptr<RealObjectIdManager> roidm) { SWSS_LOG_ENTER(); std::ifstream ifs; ifs.open(warmBootFile); if (!ifs.is_open()) { SWSS_LOG_ERROR("failed to open: %s", warmBootFile); return false; } std::string line; while (std::getline(ifs, line)) { SWSS_LOG_DEBUG("line: %s", line.c_str()); // line format: OBJECT_TYPE OBJECT_ID ATTR_ID ATTR_VALUE std::istringstream iss(line); std::string strObjectType; std::string strObjectId; std::string strAttrId; std::string strAttrValue; iss >> strObjectType >> strObjectId; if (strObjectType == SAI_VS_FDB_INFO) { /* * If we read line from fdb info set and use tap device is enabled * just parse line and repopulate fdb info set. */ FdbInfo fi = FdbInfo::deserialize(strObjectId); auto switchId = roidm->switchIdQuery(fi.m_portId); if (switchId == SAI_NULL_OBJECT_ID) { SWSS_LOG_ERROR("switchIdQuery returned NULL on fi.m_port = %s", sai_serialize_object_id(fi.m_portId).c_str()); g_warmBootState.clear(); return false; } g_warmBootState[switchId].m_switchId = switchId; g_warmBootState[switchId].m_fdbInfoSet.insert(fi); continue; } iss >> strAttrId >> strAttrValue; sai_object_meta_key_t metaKey; sai_deserialize_object_meta_key(strObjectType + ":" + strObjectId, metaKey); /* * Since all objects we are creating, then during warm boot we need to * get the biggest object index, so after warm boot we can start * generating new objects with index value not colliding with objects * loaded from warm boot scenario. We only need to consider OID * objects. */ roidm->updateWarmBootObjectIndex(metaKey.objectkey.key.object_id); // query each object for switch id auto switchId = roidm->switchIdQuery(metaKey.objectkey.key.object_id); if (switchId == SAI_NULL_OBJECT_ID) { SWSS_LOG_ERROR("switchIdQuery returned NULL on oid = %s", sai_serialize_object_id(metaKey.objectkey.key.object_id).c_str()); g_warmBootState.clear(); return false; } g_warmBootState[switchId].m_switchId = switchId; auto &objectHash = g_warmBootState[switchId].m_objectHash[metaKey.objecttype]; // will create if not exist if (objectHash.find(strObjectId) == objectHash.end()) { objectHash[strObjectId] = {}; } if (strAttrId == "NULL") { // skip empty attributes continue; } objectHash[strObjectId][strAttrId] = std::make_shared<SaiAttrWrap>(strAttrId, strAttrValue); } // NOTE notification pointers should be restored by attr_list when creating switch ifs.close(); return true; } TEST(SwitchMLNX2700, warm_update_queues) { auto sc = std::make_shared<SwitchConfig>(0, ""); auto signal = std::make_shared<Signal>(); auto eventQueue = std::make_shared<EventQueue>(signal); sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU; sc->m_switchType = SAI_VS_SWITCH_TYPE_MLNX2700; sc->m_bootType = SAI_VS_BOOT_TYPE_COLD; sc->m_useTapDevice = false; sc->m_laneMap = LaneMap::getDefaultLaneMap(0); sc->m_eventQueue = eventQueue; auto scc = std::make_shared<SwitchConfigContainer>(); scc->insert(sc); auto roidm = std::make_shared<RealObjectIdManager>(0, scc); EXPECT_TRUE(getWarmBootState("files/mlnx2700.warm.bin", roidm)); auto warmBootState = std::make_shared<WarmBootState>(g_warmBootState.at(0x2100000000)); // copy ctr SwitchMLNX2700 sw( 0x2100000000, roidm, sc, warmBootState); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; attr.value.booldata = true; EXPECT_EQ(sw.warm_boot_initialize_objects(), SAI_STATUS_SUCCESS); attr.id = SAI_SWITCH_ATTR_DEFAULT_1Q_BRIDGE_ID; attr.value.oid = SAI_NULL_OBJECT_ID; EXPECT_EQ(sw.get(SAI_OBJECT_TYPE_SWITCH, "oid:0x2100000000", 1, &attr), SAI_STATUS_SUCCESS); EXPECT_NE(attr.value.oid, SAI_NULL_OBJECT_ID); auto boid = attr.value.oid; auto sboid = sai_serialize_object_id(boid); sai_object_id_t list[128]; attr.id = SAI_BRIDGE_ATTR_PORT_LIST; attr.value.objlist.count = 128; attr.value.objlist.list = list; EXPECT_EQ(sw.get(SAI_OBJECT_TYPE_BRIDGE, sboid, 1, &attr), SAI_STATUS_SUCCESS); } TEST(SwitchMLNX2700, test_tunnel_term_capability) { auto sc = std::make_shared<SwitchConfig>(0, ""); auto signal = std::make_shared<Signal>(); auto eventQueue = std::make_shared<EventQueue>(signal); sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU; sc->m_switchType = SAI_VS_SWITCH_TYPE_MLNX2700; sc->m_bootType = SAI_VS_BOOT_TYPE_COLD; sc->m_useTapDevice = false; sc->m_laneMap = LaneMap::getDefaultLaneMap(0); sc->m_eventQueue = eventQueue; auto scc = std::make_shared<SwitchConfigContainer>(); scc->insert(sc); SwitchMLNX2700 sw( 0x2100000000, std::make_shared<RealObjectIdManager>(0, scc), sc); sai_s32_list_t enum_val_cap; int32_t list[2]; enum_val_cap.count = 2; enum_val_cap.list = list; EXPECT_EQ(sw.queryAttrEnumValuesCapability(0x2100000000, SAI_OBJECT_TYPE_TUNNEL, SAI_TUNNEL_ATTR_PEER_MODE, &enum_val_cap), SAI_STATUS_SUCCESS); EXPECT_EQ(enum_val_cap.count, 1); EXPECT_EQ(enum_val_cap.list[0], SAI_TUNNEL_PEER_MODE_P2MP); } TEST(SwitchMLNX2700, test_vlan_flood_capability) { auto sc = std::make_shared<SwitchConfig>(0, ""); auto signal = std::make_shared<Signal>(); auto eventQueue = std::make_shared<EventQueue>(signal); sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU; sc->m_switchType = SAI_VS_SWITCH_TYPE_MLNX2700; sc->m_bootType = SAI_VS_BOOT_TYPE_COLD; sc->m_useTapDevice = false; sc->m_laneMap = LaneMap::getDefaultLaneMap(0); sc->m_eventQueue = eventQueue; auto scc = std::make_shared<SwitchConfigContainer>(); scc->insert(sc); SwitchMLNX2700 sw( 0x2100000000, std::make_shared<RealObjectIdManager>(0, scc), sc); sai_s32_list_t enum_val_cap; int32_t list[4]; enum_val_cap.count = 4; enum_val_cap.list = list; EXPECT_EQ(sw.queryAttrEnumValuesCapability(0x2100000000, SAI_OBJECT_TYPE_VLAN, SAI_VLAN_ATTR_UNKNOWN_UNICAST_FLOOD_CONTROL_TYPE, &enum_val_cap), SAI_STATUS_SUCCESS); EXPECT_EQ(enum_val_cap.count, 4); int flood_types_found = 0; for (uint32_t i = 0; i < enum_val_cap.count; i++) { if (enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_ALL || enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_NONE || enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_L2MC_GROUP || enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) { flood_types_found++; } } EXPECT_EQ(flood_types_found, 4); memset(list, 0, sizeof(list)); flood_types_found = 0; enum_val_cap.count = 4; enum_val_cap.list = list; EXPECT_EQ(sw.queryAttrEnumValuesCapability(0x2100000000, SAI_OBJECT_TYPE_VLAN, SAI_VLAN_ATTR_UNKNOWN_MULTICAST_FLOOD_CONTROL_TYPE, &enum_val_cap), SAI_STATUS_SUCCESS); EXPECT_EQ(enum_val_cap.count, 4); for (uint32_t i = 0; i < enum_val_cap.count; i++) { if (enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_ALL || enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_NONE || enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_L2MC_GROUP || enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) { flood_types_found++; } } EXPECT_EQ(flood_types_found, 4); memset(list, 0, sizeof(list)); flood_types_found = 0; enum_val_cap.count = 4; enum_val_cap.list = list; EXPECT_EQ(sw.queryAttrEnumValuesCapability(0x2100000000, SAI_OBJECT_TYPE_VLAN, SAI_VLAN_ATTR_BROADCAST_FLOOD_CONTROL_TYPE, &enum_val_cap), SAI_STATUS_SUCCESS); EXPECT_EQ(enum_val_cap.count, 4); for (uint32_t i = 0; i < enum_val_cap.count; i++) { if (enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_ALL || enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_NONE || enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_L2MC_GROUP || enum_val_cap.list[i] == SAI_VLAN_FLOOD_CONTROL_TYPE_COMBINED) { flood_types_found++; } } EXPECT_EQ(flood_types_found, 4); } TEST(SwitchMLNX2700, test_port_autoneg_fec_override_support) { auto sc = std::make_shared<SwitchConfig>(0, ""); auto signal = std::make_shared<Signal>(); auto eventQueue = std::make_shared<EventQueue>(signal); sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU; sc->m_switchType = SAI_VS_SWITCH_TYPE_MLNX2700; sc->m_bootType = SAI_VS_BOOT_TYPE_COLD; sc->m_useTapDevice = false; sc->m_laneMap = LaneMap::getDefaultLaneMap(0); sc->m_eventQueue = eventQueue; auto scc = std::make_shared<SwitchConfigContainer>(); scc->insert(sc); SwitchMLNX2700 sw( 0x2100000000, std::make_shared<RealObjectIdManager>(0, scc), sc); sai_attr_capability_t attr_capability; EXPECT_EQ(sw.queryAttributeCapability(0x2100000000, SAI_OBJECT_TYPE_PORT, SAI_PORT_ATTR_AUTO_NEG_FEC_MODE_OVERRIDE, &attr_capability), SAI_STATUS_SUCCESS); EXPECT_EQ(attr_capability.create_implemented, true); EXPECT_EQ(attr_capability.set_implemented, true); EXPECT_EQ(attr_capability.get_implemented, true); } TEST(SwitchMLNX2700, test_stats_query_capability) { auto sc = std::make_shared<SwitchConfig>(0, ""); auto signal = std::make_shared<Signal>(); auto eventQueue = std::make_shared<EventQueue>(signal); sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU; sc->m_switchType = SAI_VS_SWITCH_TYPE_MLNX2700; sc->m_bootType = SAI_VS_BOOT_TYPE_COLD; sc->m_useTapDevice = false; sc->m_laneMap = LaneMap::getDefaultLaneMap(0); sc->m_eventQueue = eventQueue; auto scc = std::make_shared<SwitchConfigContainer>(); scc->insert(sc); SwitchMLNX2700 sw( 0x2100000000, std::make_shared<RealObjectIdManager>(0, scc), sc); sai_stat_capability_t capability_list[91]; sai_stat_capability_list_t stats_capability; stats_capability.count = 1; stats_capability.list = capability_list; /* Get queue stats capability */ EXPECT_EQ(sw.queryStatsCapability(0x2100000000, SAI_OBJECT_TYPE_QUEUE, &stats_capability), SAI_STATUS_BUFFER_OVERFLOW); stats_capability.count = SAI_QUEUE_STAT_DELAY_WATERMARK_NS; EXPECT_EQ(sw.queryStatsCapability(0x2100000000, SAI_OBJECT_TYPE_QUEUE, &stats_capability), SAI_STATUS_SUCCESS); /* Get port stats capability */ stats_capability.count = 1; EXPECT_EQ(sw.queryStatsCapability(0x2100000000, SAI_OBJECT_TYPE_PORT, &stats_capability), SAI_STATUS_BUFFER_OVERFLOW); stats_capability.count = 91; EXPECT_EQ(sw.queryStatsCapability(0x2100000000, SAI_OBJECT_TYPE_PORT, &stats_capability), SAI_STATUS_SUCCESS); }