diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index d431557b5c..c4d6ea5b61 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -54,6 +54,8 @@ orchagent_SOURCES = \ watermarkorch.cpp \ policerorch.cpp \ sfloworch.cpp \ + tam.cpp \ + thresholdorch.cpp \ chassisorch.cpp \ debugcounterorch.cpp \ natorch.cpp diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 26ff1f0301..8bc1f01aca 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -22,6 +22,7 @@ extern sai_object_id_t gSwitchId; extern bool gSaiRedisLogRotate; extern void syncd_apply_view(); + /* * Global orch daemon variables */ @@ -270,6 +271,12 @@ bool OrchDaemon::init() TableConnector stateDbSwitchTable(m_stateDb, "SWITCH_CAPABILITY"); gAclOrch = new AclOrch(acl_table_connectors, stateDbSwitchTable, gPortsOrch, mirror_orch, gNeighOrch, gRouteOrch, dtel_orch); + vector thresOrch_tables = { + CFG_THRESHOLD_TABLE_NAME + }; + + ThresholdOrch *thres_orch = new ThresholdOrch(m_configDb, thresOrch_tables, gPortsOrch); + m_orchList.push_back(gFdbOrch); m_orchList.push_back(mirror_orch); m_orchList.push_back(gAclOrch); @@ -281,8 +288,10 @@ bool OrchDaemon::init() m_orchList.push_back(cfg_vnet_rt_orch); m_orchList.push_back(vnet_orch); m_orchList.push_back(vnet_rt_orch); + m_orchList.push_back(thres_orch); m_orchList.push_back(gNatOrch); + m_select = new Select(); vector flex_counter_tables = { diff --git a/orchagent/orchdaemon.h b/orchagent/orchdaemon.h index 3094692df6..6f003dca02 100644 --- a/orchagent/orchdaemon.h +++ b/orchagent/orchdaemon.h @@ -30,6 +30,7 @@ #include "sfloworch.h" #include "debugcounterorch.h" #include "directory.h" +#include "thresholdorch.h" #include "natorch.h" using namespace swss; diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 4eadcf34f9..fc5cd25ca4 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -1813,6 +1813,11 @@ void PortsOrch::doPortTask(Consumer &consumer) if (!m_initDone) { m_initDone = true; + /* PG and queue maps per port need to be created + * after this step for the threshold feature. + */ + generateQueueMap(); + generatePriorityGroupMap(); SWSS_LOG_INFO("Get PortInitDone notification from portsyncd."); } diff --git a/orchagent/saihelper.cpp b/orchagent/saihelper.cpp index ec990d605e..fd7e3074d6 100644 --- a/orchagent/saihelper.cpp +++ b/orchagent/saihelper.cpp @@ -41,6 +41,7 @@ sai_mirror_api_t* sai_mirror_api; sai_fdb_api_t* sai_fdb_api; sai_dtel_api_t* sai_dtel_api; sai_bmtor_api_t* sai_bmtor_api; +sai_tam_api_t* sai_tam_api; sai_samplepacket_api_t* sai_samplepacket_api; sai_debug_counter_api_t* sai_debug_counter_api; sai_nat_api_t* sai_nat_api; @@ -133,6 +134,7 @@ void initSaiApi() sai_api_query(SAI_API_ACL, (void **)&sai_acl_api); sai_api_query(SAI_API_DTEL, (void **)&sai_dtel_api); sai_api_query((sai_api_t)SAI_API_BMTOR, (void **)&sai_bmtor_api); + sai_api_query(SAI_API_TAM, (void **)&sai_tam_api); sai_api_query(SAI_API_SAMPLEPACKET, (void **)&sai_samplepacket_api); sai_api_query(SAI_API_DEBUG_COUNTER, (void **)&sai_debug_counter_api); sai_api_query(SAI_API_NAT, (void **)&sai_nat_api); @@ -162,6 +164,7 @@ void initSaiApi() sai_log_set(SAI_API_ACL, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_DTEL, SAI_LOG_LEVEL_NOTICE); sai_log_set((sai_api_t)SAI_API_BMTOR, SAI_LOG_LEVEL_NOTICE); + sai_log_set(SAI_API_TAM, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_SAMPLEPACKET, SAI_LOG_LEVEL_NOTICE); sai_log_set(SAI_API_DEBUG_COUNTER, SAI_LOG_LEVEL_NOTICE); sai_log_set((sai_api_t)SAI_API_NAT, SAI_LOG_LEVEL_NOTICE); diff --git a/orchagent/tam.cpp b/orchagent/tam.cpp new file mode 100644 index 0000000000..ea562406aa --- /dev/null +++ b/orchagent/tam.cpp @@ -0,0 +1,643 @@ +/* + * Copyright 2019 Broadcom Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "logger.h" +#include "tokenize.h" +#include "orch.h" +#include "table.h" +#include "tam.h" +#include "portsorch.h" +#include "notifier.h" +#include "sai_serialize.h" +#include "observer.h" + +extern sai_tam_api_t* sai_tam_api; +extern sai_object_id_t gSwitchId; + +Tam::Tam() +{ + SWSS_LOG_ENTER(); +} + +/* Create a TAM report object. + * + */ +bool Tam::tamReportCreate(sai_tam_report_type_t report_type, sai_object_id_t *tam_report_obj) +{ + sai_attribute_t tam_report_attr; + sai_status_t status; + + if (tam_report_obj == NULL) + { + return false; + } + + /* Create a TAM report object. */ + tam_report_attr.id = SAI_TAM_REPORT_ATTR_TYPE; + tam_report_attr.value.s32 = report_type; + status = sai_tam_api->create_tam_report(tam_report_obj, gSwitchId, 1, &tam_report_attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to create telemetry report type object."); + return false; + } + return true; +} + +/* Delete a TAM report object. + * + */ +bool Tam::tamReportDelete(sai_object_id_t tam_report_obj) +{ + sai_status_t status; + /* Delete the TAM report object. */ + status = sai_tam_api->remove_tam_report(tam_report_obj); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to remove TAM report type object."); + return false; + } + return true; +} + +/* + * Create TAM event action object. + */ +bool Tam::tamEventActionCreate(sai_object_id_t tam_report_obj, sai_object_id_t *tam_event_action_obj) +{ + sai_attribute_t attr; + sai_status_t status; + + if (tam_event_action_obj == NULL) + { + return false; + } + + attr.id = SAI_TAM_EVENT_ACTION_ATTR_REPORT_TYPE; + attr.value.oid = tam_report_obj; + + status = sai_tam_api->create_tam_event_action(tam_event_action_obj, gSwitchId, + 1, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add TAM event action object."); + return false; + } + return true; +} + +/* + * Delete TAM event action object. + */ +bool Tam::tamEventActionDelete(sai_object_id_t tam_event_action_obj) +{ + sai_status_t status; + + status = sai_tam_api->remove_tam_event_action(tam_event_action_obj); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add TAM event action object."); + return false; + } + return true; +} + +/* + * Create TAM event object. + */ +bool Tam::tamEventCreate(sai_tam_event_type_t type, sai_object_id_t tam_event_action_obj, + sai_object_id_t tam_collector_obj, sai_object_id_t tam_thd_obj, + sai_object_id_t *tam_event_obj) +{ + sai_attribute_t attr; + sai_status_t status; + vector tam_event_attrs; + + if (tam_event_obj == NULL) + { + return false; + } + + attr.id = SAI_TAM_EVENT_ATTR_TYPE; + attr.value.s32 = type; + tam_event_attrs.push_back(attr); + + vector tam_event_list; + tam_event_list.push_back(tam_event_action_obj); + attr.id = SAI_TAM_EVENT_ATTR_ACTION_LIST; + attr.value.objlist.count = (uint32_t)tam_event_list.size(); + attr.value.objlist.list = tam_event_list.data(); + tam_event_attrs.push_back(attr); + + vector tam_collector_list; + tam_collector_list.push_back(tam_collector_obj); + attr.id = SAI_TAM_EVENT_ATTR_COLLECTOR_LIST; + attr.value.objlist.count = (uint32_t)tam_collector_list.size();; + attr.value.objlist.list = tam_collector_list.data(); + tam_event_attrs.push_back(attr); + + attr.id = SAI_TAM_EVENT_ATTR_THRESHOLD; + attr.value.oid = tam_thd_obj; + tam_event_attrs.push_back(attr); + + status = sai_tam_api->create_tam_event(tam_event_obj, gSwitchId, + (uint32_t)tam_event_attrs.size(), + tam_event_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add TAM event object."); + return false; + } + return true; +} + +/* + * Delete TAM event object. + */ +bool Tam::tamEventDelete(sai_object_id_t tam_event_obj) +{ + sai_status_t status; + + status = sai_tam_api->remove_tam_event(tam_event_obj); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add TAM event object."); + return false; + } + return true; +} + + +/* Create TAM telemetry type object. + * + */ +bool Tam::tamTelemetryTypeCreate(sai_object_id_t tam_report_obj, + sai_object_id_t *tam_telemetry_type_obj) +{ + sai_attribute_t attr; + sai_status_t status; + vector tam_telemetry_type_attrs; + + if (tam_telemetry_type_obj == NULL) + { + return false; + } + + /* Create TAM telemetry type object. */ + /* Setup attributes. */ + attr.id = SAI_TAM_TEL_TYPE_ATTR_TAM_TELEMETRY_TYPE; + attr.value.s32 = SAI_TAM_TELEMETRY_TYPE_SWITCH; + tam_telemetry_type_attrs.push_back(attr); + + attr.id = SAI_TAM_TEL_TYPE_ATTR_REPORT_ID; + attr.value.oid = tam_report_obj; + tam_telemetry_type_attrs.push_back(attr); + + attr.id = SAI_TAM_TEL_TYPE_ATTR_SWITCH_ENABLE_MMU_STATS; + attr.value.booldata = true; + tam_telemetry_type_attrs.push_back(attr); + + status = sai_tam_api->create_tam_tel_type(tam_telemetry_type_obj, gSwitchId, + (uint32_t)tam_telemetry_type_attrs.size(), + tam_telemetry_type_attrs.data() ); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add telemetry type."); + return false; + } + return true; +} + +/* Delete TAM telemetry type object. + * + */ +bool Tam::tamTelemetryTypeDelete(sai_object_id_t tam_telemetry_type_obj) +{ + sai_status_t status; + + /* Delete the TAM telemetry type object. */ + status = sai_tam_api->remove_tam_tel_type(tam_telemetry_type_obj); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to remove telemetry type object."); + return false; + } + return true; +} + +/* + * Create a TAM transport object. + */ +bool Tam::tamTransportCreate(int dstPort, int srcPort, sai_object_id_t *tam_transport_obj) +{ + sai_attribute_t attr; + sai_status_t status; + vector tam_transport_attrs; + + if (tam_transport_obj == NULL) + { + return false; + } + + /* Create TAM transport object */ + /* Setup attributes. */ + attr.id = SAI_TAM_TRANSPORT_ATTR_TRANSPORT_TYPE; + attr.value.s32 = SAI_TAM_TRANSPORT_TYPE_UDP; + tam_transport_attrs.push_back(attr); + + attr.id = SAI_TAM_TRANSPORT_ATTR_SRC_PORT; + attr.value.s32 = srcPort; + tam_transport_attrs.push_back(attr); + + attr.id = SAI_TAM_TRANSPORT_ATTR_DST_PORT; + attr.value.s32 = dstPort; + tam_transport_attrs.push_back(attr); + + status = sai_tam_api->create_tam_transport(tam_transport_obj, gSwitchId, + (uint32_t)tam_transport_attrs.size(), + tam_transport_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add TAM transport"); + return false; + } + + return true; +} + +/* Delete TAM transport object. + * + */ +bool Tam::tamTransportDelete(sai_object_id_t tam_transport_obj) +{ + sai_status_t status; + + /* Delete the TAM transport object. */ + status = sai_tam_api->remove_tam_transport(tam_transport_obj); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to remove transport object."); + return false; + } + return true; +} + +/* + * Create TAM collector object. + */ +bool Tam::tamCollectorCreate(sai_ip_address_t src_ip_addr, sai_ip_address_t dst_ip_addr, + sai_object_id_t tam_transport_obj, sai_object_id_t *tam_collector_obj) +{ + sai_attribute_t attr; + sai_status_t status; + vector tam_collector_attrs; + + if (tam_collector_obj == NULL) + { + return false; + } + + attr.id = SAI_TAM_COLLECTOR_ATTR_SRC_IP; + attr.value.ipaddr = src_ip_addr; + tam_collector_attrs.push_back(attr); + + attr.id = SAI_TAM_COLLECTOR_ATTR_DST_IP; + attr.value.ipaddr = dst_ip_addr; + tam_collector_attrs.push_back(attr); + + attr.id = SAI_TAM_COLLECTOR_ATTR_TRANSPORT; + attr.value.oid = tam_transport_obj; + tam_collector_attrs.push_back(attr); + + attr.id = SAI_TAM_COLLECTOR_ATTR_DSCP_VALUE; + attr.value.u8 = 0; + tam_collector_attrs.push_back(attr); + + status = sai_tam_api->create_tam_collector(tam_collector_obj, gSwitchId, + (uint32_t)tam_collector_attrs.size(), + tam_collector_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add TAM collector object."); + return false; + } + + return true; +} + +/* Delete TAM collector object. + * + */ +bool Tam::tamCollectorDelete(sai_object_id_t tam_collector_obj) +{ + sai_status_t status; + + /* Delete the TAM collector object. */ + status = sai_tam_api->remove_tam_collector(tam_collector_obj); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to remove TAM collector object."); + return false; + } + return true; +} + +/* + * Create TAM telemetry object. + */ +bool Tam::tamTelemetryCreate(int interval, sai_object_id_t tam_telemetry_type_obj, + sai_object_id_t tam_collector_obj, sai_object_id_t *tam_telemetry_obj) +{ + sai_attribute_t attr; + vector tam_telemetry_attrs; + sai_status_t status; + + if (tam_telemetry_obj == NULL) + { + return false; + } + + /* TAM periodic report to be configured + * with interval = 0 i.e send a report + * right away. Create a TAM object. + */ + vector tam_list; + tam_list.push_back(tam_telemetry_type_obj); + attr.id = SAI_TAM_TELEMETRY_ATTR_TAM_TYPE_LIST; + attr.value.objlist.count = (uint32_t)tam_list.size(); + attr.value.objlist.list = tam_list.data(); + tam_telemetry_attrs.push_back(attr); + + vector collector_list; + collector_list.push_back(tam_collector_obj); + attr.id = SAI_TAM_TELEMETRY_ATTR_COLLECTOR_LIST; + attr.value.objlist.count = (uint32_t)collector_list.size(); + attr.value.objlist.list = collector_list.data(); + tam_telemetry_attrs.push_back(attr); + + attr.id = SAI_TAM_TELEMETRY_ATTR_TAM_REPORTING_UNIT; + attr.value.s32 = SAI_TAM_REPORTING_UNIT_SEC; + tam_telemetry_attrs.push_back(attr); + + attr.id = SAI_TAM_TELEMETRY_ATTR_REPORTING_INTERVAL; + /* Hardcode interval to 0. */ + attr.value.s32 = 0; + tam_telemetry_attrs.push_back(attr); + status = sai_tam_api->create_tam_telemetry(tam_telemetry_obj, gSwitchId, + (uint32_t)tam_telemetry_attrs.size(), + tam_telemetry_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add TAM telemetry object."); + return false; + } + + return true; +} + +/* Delete TAM telemetry object. + * + */ +bool Tam::tamTelemetryDelete(sai_object_id_t tam_telemetry_obj) +{ + sai_status_t status; + + /* Delete the TAM telemetry object. */ + status = sai_tam_api->remove_tam_telemetry(tam_telemetry_obj); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to remove TAM telemetry object."); + return false; + } + return true; +} + +/* + * Create TAM threshold event object. + */ +bool Tam::tamEventThresholdCreate(int threshold, sai_object_id_t *tam_event_threshold_obj) +{ + sai_status_t status; + sai_attribute_t attr; + vector tam_event_thd_attrs; + + attr.id = SAI_TAM_EVENT_THRESHOLD_ATTR_ABS_VALUE; + attr.value.u32 = threshold; + tam_event_thd_attrs.push_back(attr); + + attr.id = SAI_TAM_EVENT_THRESHOLD_ATTR_UNIT; + attr.value.u32 = SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT; + tam_event_thd_attrs.push_back(attr); + + status = sai_tam_api->create_tam_event_threshold(tam_event_threshold_obj, gSwitchId, + (uint32_t)tam_event_thd_attrs.size(), + tam_event_thd_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add TAM event threshold object."); + return false; + } + + return true; +} + +/* + * Delete TAM threshold event object. + */ +bool Tam::tamEventThresholdDelete(sai_object_id_t tam_event_threshold_obj) +{ + sai_status_t status; + + /* Delete the TAM threshold evnet object. */ + status = sai_tam_api->remove_tam_event_threshold(tam_event_threshold_obj); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to remove TAM event threshold object."); + return false; + } + return true; +} + +/* + * Create TAM object. + */ +bool Tam::tamCreate(sai_tam_bind_point_type_t bind_point, sai_tam_attr_t attr_type, + sai_object_id_t tam_telemetry_event_obj, sai_object_id_t *tam_obj) +{ + sai_attribute_t attr; + vector tam_attrs; + sai_status_t status; + + if (tam_obj == NULL) + { + return false; + } + + /* Create a TAM object. */ + vector tam_list; + tam_list.push_back(tam_telemetry_event_obj); + attr.id = attr_type; + attr.value.objlist.count = (uint32_t)tam_list.size(); + attr.value.objlist.list = tam_list.data(); + tam_attrs.push_back(attr); + + vector bind_list; + bind_list.push_back(bind_point); + attr.id = SAI_TAM_ATTR_TAM_BIND_POINT_TYPE_LIST; + attr.value.s32list.count = (uint32_t)bind_list.size(); + attr.value.s32list.list = bind_list.data(); + tam_attrs.push_back(attr); + + status = sai_tam_api->create_tam(tam_obj, gSwitchId, + (uint32_t)tam_attrs.size(), + tam_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add TAM object."); + return false; + } + + return true; +} + +/* Delete TAM object. + * + */ +bool Tam::tamDelete(sai_object_id_t tam_obj) +{ + sai_status_t status; + + /* Delete the TAM object. */ + status = sai_tam_api->remove_tam(tam_obj); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to remove TAM telemetry object."); + return false; + } + return true; +} + +/* + * Create TAM INT object. + */ +bool Tam::tamIntCreate(uint32_t device_id, sai_object_id_t tam_report_obj, + bool sampling_enable, sai_object_id_t tam_sampling_obj, + bool collector_enable, sai_object_id_t tam_collector_obj, + sai_object_id_t *tam_int_obj) +{ + sai_attribute_t attr; + sai_status_t status; + vector tam_int_attrs; + + if (tam_int_obj == NULL) + { + return false; + } + + /* Configure TAM INT attributes. */ + attr.id = SAI_TAM_INT_ATTR_TYPE; + attr.value.s32 = SAI_TAM_INT_TYPE_IFA1; + tam_int_attrs.push_back(attr); + + attr.id = SAI_TAM_INT_ATTR_DEVICE_ID; + attr.value.u32 = device_id; + tam_int_attrs.push_back(attr); + + attr.id = SAI_TAM_INT_ATTR_INT_PRESENCE_TYPE; + attr.value.u32 = SAI_TAM_INT_PRESENCE_TYPE_PB; + tam_int_attrs.push_back(attr); + + attr.id = SAI_TAM_INT_ATTR_INT_PRESENCE_PB1; + attr.value.u32 = 0xAAAAAAAA; + tam_int_attrs.push_back(attr); + + attr.id = SAI_TAM_INT_ATTR_INT_PRESENCE_PB2; + attr.value.u32 = 0xBBBBBBBB; + tam_int_attrs.push_back(attr); + + attr.id = SAI_TAM_INT_ATTR_INLINE; + attr.value.booldata = false; + tam_int_attrs.push_back(attr); + + attr.id = SAI_TAM_INT_ATTR_MAX_HOP_COUNT; + attr.value.u8 = 32; + tam_int_attrs.push_back(attr); + + attr.id = SAI_TAM_INT_ATTR_MAX_LENGTH; + attr.value.u8 = 255; + tam_int_attrs.push_back(attr); + + attr.id = SAI_TAM_INT_ATTR_REPORT_ID; + attr.value.oid = tam_report_obj; + tam_int_attrs.push_back(attr); + + if (true == sampling_enable) + { + attr.id = SAI_TAM_INT_ATTR_INGRESS_SAMPLEPACKET_ENABLE; + attr.value.oid = tam_sampling_obj; + tam_int_attrs.push_back(attr); + } + + if (true == collector_enable) + { + sai_attribute_t tam_attr_list[1]; + memset(tam_attr_list, 0, sizeof(sai_attribute_t)); + tam_attr_list[0].value.objlist.list = (sai_object_id_t *)calloc(1,sizeof(sai_object_id_t)); + tam_attr_list[0].id = SAI_TAM_INT_ATTR_COLLECTOR_LIST; + tam_attr_list[0].value.objlist.count = 1; + tam_attr_list[0].value.objlist.list[0] = tam_collector_obj; + + tam_int_attrs.push_back(tam_attr_list[0]); + } + + /* Create a TAM INT object. */ + status = sai_tam_api->create_tam_int(tam_int_obj, gSwitchId, + (uint32_t)tam_int_attrs.size(), + tam_int_attrs.data()); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to add TAM INT object."); + return false; + } + + SWSS_LOG_DEBUG("Created TAM INT object OID:0x%lx", *tam_int_obj); + return true; +} + +/* Delete TAM INT object. + * + */ +bool Tam::tamIntDelete(sai_object_id_t tam_int_obj) +{ + sai_status_t status; + + /* Delete the TAM INT object. */ + status = sai_tam_api->remove_tam_int(tam_int_obj); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to remove TAM INT telemetry object."); + return false; + } + + SWSS_LOG_DEBUG("Deleted TAM INT object OID:0x%lx", tam_int_obj); + return true; +} diff --git a/orchagent/tam.h b/orchagent/tam.h new file mode 100644 index 0000000000..c1286d4e09 --- /dev/null +++ b/orchagent/tam.h @@ -0,0 +1,70 @@ +/* + * Copyright 2019 Broadcom Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SWSS_TAM_H +#define SWSS_TAM_H + +#include +#include +#include +#include "orch.h" +#include "observer.h" +#include "portsorch.h" + +class Tam +{ +public: + Tam(); + ~Tam() + { + } + + /* SAI TAM handlers. */ + bool tamReportCreate(sai_tam_report_type_t report_type, sai_object_id_t *tam_report_obj); + bool tamReportDelete(sai_object_id_t tam_report_obj); + bool tamTelemetryTypeCreate(sai_object_id_t tam_report_obj, + sai_object_id_t *tam_telemetry_type_obj); + bool tamTelemetryTypeDelete(sai_object_id_t tam_telemetry_type_obj); + bool tamTransportCreate(int dstPort, int srcPort, sai_object_id_t *tam_transport_obj); + bool tamTransportDelete(sai_object_id_t tam_transport_obj); + bool tamCollectorCreate(sai_ip_address_t src_ip_addr, sai_ip_address_t dst_ip_addr, + sai_object_id_t tam_transport_obj, sai_object_id_t *tam_collector_obj); + bool tamCollectorDelete(sai_object_id_t tam_collector_obj); + bool tamTelemetryCreate(int interval, sai_object_id_t tam_telemetry_type_obj, + sai_object_id_t tam_collector_obj, sai_object_id_t *tam_telemetry_obj); + bool tamTelemetryDelete(sai_object_id_t tam_telemetry_obj); + bool tamEventThresholdCreate(int threshold, sai_object_id_t *tam_event_threshold_obj); + bool tamEventThresholdDelete(sai_object_id_t tam_event_threshold_obj); + bool tamCreate(sai_tam_bind_point_type_t bind_point, sai_tam_attr_t attry_type, + sai_object_id_t tam_telemetry_event_obj, sai_object_id_t *tam_obj); + bool tamDelete(sai_object_id_t tam_obj); + bool tamEventActionCreate(sai_object_id_t tam_report_obj, + sai_object_id_t *tam_event_action_obj); + bool tamEventActionDelete(sai_object_id_t tam_event_action_obj); + bool tamEventCreate(sai_tam_event_type_t type, sai_object_id_t tam_event_action_obj, + sai_object_id_t tam_collector_obj, sai_object_id_t tam_thd_obj, sai_object_id_t *tam_event_obj); + bool tamEventDelete(sai_object_id_t tam_event_obj); + bool tamIntCreate(uint32_t device_id, sai_object_id_t tam_report_obj, + bool sampling_enable, sai_object_id_t tam_sampling_obj, + bool collector_enable, sai_object_id_t tam_collector_obj, + sai_object_id_t *tam_int_obj); + bool tamIntDelete(sai_object_id_t tam_int_obj); + +private: + +}; +#endif /* SWSS_TAM_H */ + diff --git a/orchagent/thresholdorch.cpp b/orchagent/thresholdorch.cpp new file mode 100644 index 0000000000..328698dbbc --- /dev/null +++ b/orchagent/thresholdorch.cpp @@ -0,0 +1,902 @@ +#include +#include +#include +#include +#include + +#include "logger.h" +#include "tokenize.h" +#include "orch.h" +#include "table.h" +#include "thresholdorch.h" +#include "portsorch.h" +#include "notifier.h" +#include "sai_serialize.h" +#include "observer.h" +#include "swssnet.h" + +extern sai_object_id_t gSwitchId; +extern PortsOrch* gPortsOrch; +extern sai_tam_api_t* sai_tam_api; +extern sai_port_api_t* sai_port_api; +extern sai_buffer_api_t* sai_buffer_api; +extern sai_queue_api_t* sai_queue_api; +extern sai_switch_api_t* sai_switch_api; + +ThresholdOrch::ThresholdOrch(DBConnector *db, vector &tableNames, PortsOrch *port) : + Orch(db, tableNames), + m_portsOrch(port) +{ + + SWSS_LOG_ENTER(); + m_portsOrch->attach(this); + + /* Initialize SAI objects to NULL object ID. */ + m_tamReport = SAI_NULL_OBJECT_ID; + m_tamEventAction = SAI_NULL_OBJECT_ID; + m_tamTransport = SAI_NULL_OBJECT_ID; + m_tamCollector = SAI_NULL_OBJECT_ID; +} + +ThresholdOrch::~ThresholdOrch() +{ + m_portsOrch->detach(this); + + /* Delete TAM objects. */ + if (m_tamReport != SAI_NULL_OBJECT_ID) + { + (void) tamReportDelete(m_tamReport); + } + + if (m_tamEventAction != SAI_NULL_OBJECT_ID) + { + (void) tamEventActionDelete(m_tamEventAction); + } + + if (m_tamTransport != SAI_NULL_OBJECT_ID) + { + (void) tamTransportDelete(m_tamTransport); + } + + if (m_tamCollector != SAI_NULL_OBJECT_ID) + { + (void) tamCollectorDelete(m_tamCollector); + } +} + +bool ThresholdOrch::createCommonTamObjects() +{ + if (m_tamReport == SAI_NULL_OBJECT_ID) + { + /* Create TAM report type object. */ + if (tamReportCreate(SAI_TAM_REPORT_TYPE_PROTO, &m_tamReport) != true) + { + SWSS_LOG_ERROR("Unable to create TAM report object."); + return false; + } + } + + if (m_tamEventAction == SAI_NULL_OBJECT_ID) + { + /* Create TAM event object */ + if (tamEventActionCreate(m_tamReport, &m_tamEventAction) != true) + { + SWSS_LOG_ERROR("Unable to create TAM event action object."); + return false; + } + } + + if (m_tamTransport == SAI_NULL_OBJECT_ID) + { + /* Create TAM transport object */ + if (tamTransportCreate(THRESHOLD_ORCH_SAI_TAM_THRESHOLD_DST_PORT, THRESHOLD_ORCH_SAI_TAM_TRANSPORT_SRC_PORT, + &m_tamTransport ) != true) + { + SWSS_LOG_ERROR("Unable to create TAM transport object."); + return false; + } + } + + if (m_tamCollector == SAI_NULL_OBJECT_ID) + { + /* Create TAM collector object */ + /* Using a random source ip */ + sai_ip_address_t src_ip_addr; + sai_ip_address_t dst_ip_addr; + IpAddress src_ip(0x0a0a0a0a); + IpAddress dst_ip(0x7f000001); + + copy (dst_ip_addr, dst_ip); + copy (src_ip_addr, src_ip); + + if (tamCollectorCreate(src_ip_addr, dst_ip_addr, m_tamTransport, &m_tamCollector) != true) + { + SWSS_LOG_ERROR("Unable to create TAM collector object."); + return false; + } + } + + return true; +} + + +void ThresholdOrch::update(SubjectType type, void *cntx) +{ + SWSS_LOG_ENTER(); + + assert(cntx); + + switch(type) { + default: + break; + } + + return; +} + +/* + * Add TAM threshold table entry. + */ +bool ThresholdOrch::addTamThdObjEntry(uint32_t threshold) +{ + sai_object_id_t tamThdObj; + thresTamThdObjData tamThdData; + + /* New threshold TAM object. */ + if (tamEventThresholdCreate(threshold, &tamThdObj) != true) + { + SWSS_LOG_ERROR("Unable to create event threshold object."); + return false; + } + + /* Add an entry to threshold table. */ + tamThdData.m_thresTamThd = tamThdObj; + tamThdData.ref_cnt = 0; + m_thresTamThdTable[threshold] = tamThdData; + return true; +} + +/* + * Delete TAM threshold table entry. + */ +bool ThresholdOrch::deleteTamThdObjEntry(uint32_t threshold) +{ + if (tamEventThresholdDelete(m_thresTamThdTable[threshold].m_thresTamThd) != true) + { + SWSS_LOG_ERROR("Unable to delete event threshold object."); + return false; + } + + /* Update the threshold table. */ + m_thresTamThdTable.erase(threshold); + + return true; +} + +/* + * Add TAM object table entry. + */ +bool ThresholdOrch::addTamObjEntry(thresTamObjEntry tamObjEntry) +{ + sai_object_id_t tamThdObj; + uint32_t threshold = tamObjEntry.threshold; + sai_tam_event_type_t type = tamObjEntry.type; + thresTamObjData tamEntryData; + sai_tam_bind_point_type_t bindPoint = bindPointType.at(type); + bool thdCreated = false; + + /* Check if a TAM threshold object exists. */ + if (m_thresTamThdTable.find(threshold) == m_thresTamThdTable.end()) + { + /* New threshold object table entry. */ + if (addTamThdObjEntry(threshold) != true) + { + SWSS_LOG_ERROR("Unable to add threshold table entry."); + return false; + } + thdCreated = true; + } + + tamThdObj = m_thresTamThdTable[threshold].m_thresTamThd; + + /* Create common TAM objects */ + if ((m_tamEventAction == SAI_NULL_OBJECT_ID) || (m_tamCollector == SAI_NULL_OBJECT_ID)) + { + if (createCommonTamObjects() != true) + { + SWSS_LOG_ERROR("Unable to create tam event object."); + /* Destroy the threshold event object created earlier. */ + if (thdCreated == true) + (void) deleteTamThdObjEntry(threshold); + return false; + } + } + + /* Create a new TAM object entry */ + + /* Create TAM event object. */ + if (tamEventCreate(type, m_tamEventAction, + m_tamCollector, tamThdObj, &tamEntryData.m_thresTamEvent) != true) + { + SWSS_LOG_ERROR("Unable to create tam event object."); + /* Destroy the threshold event object created earlier. */ + if (thdCreated == true) + (void) deleteTamThdObjEntry(threshold); + return false; + } + + /* Create TAM object. */ + if (tamCreate(bindPoint, SAI_TAM_ATTR_EVENT_OBJECTS_LIST, + tamEntryData.m_thresTamEvent, &tamEntryData.m_thresTam) != true) + { + SWSS_LOG_ERROR("Unable to create tam object."); + /* Destroy TAM event object and threshold object. */ + (void) tamEventDelete(tamEntryData.m_thresTamEvent); + if (thdCreated == true) + (void) deleteTamThdObjEntry(threshold); + return false; + } + + /* Create TAM table entry. */ + m_thresTamTable[tamObjEntry] = tamEntryData; + + /* Increase ref count of threshold object. */ + m_thresTamThdTable[threshold].ref_cnt++; + + return true; +} + +/* + * Delete TAM object table entry. + */ +bool ThresholdOrch::deleteTamObjEntry(thresTamObjEntry tamObjEntry) +{ + thresTamObjData tamEntryData = m_thresTamTable[tamObjEntry]; + + /* Destroy TAM object */ + if (tamDelete(tamEntryData.m_thresTam) != true) + { + SWSS_LOG_ERROR("Unable to delete TAM object."); + return false; + } + + /* Destroy TAM event object */ + if (tamEventDelete(tamEntryData.m_thresTamEvent) != true) + { + SWSS_LOG_ERROR("Unable to delete TAM event object."); + return false; + } + + /* Delete entry from TAM object table. */ + m_thresTamTable.erase(tamObjEntry); + + /* Decrement threshold ref cnt */ + m_thresTamThdTable[tamObjEntry.threshold].ref_cnt--; + if (m_thresTamThdTable[tamObjEntry.threshold].ref_cnt == 0) + { + /* Delete threshold table entry */ + if (deleteTamThdObjEntry(tamObjEntry.threshold) != true) + { + SWSS_LOG_ERROR("Unable to delete TAM threshold object entry."); + return false; + } + } + + return true; +} + +/* + * Bind TAM object to bind points. + */ +bool ThresholdOrch::thresTamObjBind(thresEventType_t thresType, string alias, uint32_t index, + sai_object_id_t tamObj) +{ + sai_attribute_t attr; + vectorlist; + uint32_t qid; + sai_status_t status; + Port port; + + SWSS_LOG_ENTER(); + + if (!gPortsOrch->getPort(alias, port)) + { + SWSS_LOG_ERROR("Unable to get port data for port %s", alias.c_str()); + return false; + } + + list.clear(); + if (tamObj != SAI_NULL_OBJECT_ID) + { + list.push_back(tamObj); + } + attr.value.objlist.count = (uint32_t)list.size(); + attr.value.objlist.list = list.data(); + + /* Port class maintains per port pgs, queues etc. + * Use the data to get appropriate sai_object_id_t + */ + if ((thresType == THRES_EVENT_TYPE_IPG_SHARED) || + (thresType == THRES_EVENT_TYPE_IPG_HEADROOM)) + { + attr.id = SAI_INGRESS_PRIORITY_GROUP_ATTR_TAM; + /* Bind a TAM object to port, pg pair. */ + /* Port has been validated in doTask(), go ahead and use the data. */ + status = sai_buffer_api->set_ingress_priority_group_attribute(port.m_priority_group_ids[index], + &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to set ingress port priority group attribute TAM object."); + return false; + } + } + else if ((thresType == THRES_EVENT_TYPE_QUEUE_UNICAST) + || (thresType == THRES_EVENT_TYPE_QUEUE_MULTICAST)) + { + attr.id = SAI_QUEUE_ATTR_TAM_OBJECT; + + /* Bind a TAM object to port, queue pair. */ + if ((thresType == THRES_EVENT_TYPE_QUEUE_UNICAST)) + { + qid = index; + } + else if ((thresType == THRES_EVENT_TYPE_QUEUE_MULTICAST)) + { + /* MCQ - multicast queues start after unicast queues. + * Hence, multicast queue index = queue index + num_uc_queues. + */ + int num_uc_queues = 0; + sai_attribute_t queue_attr; + + queue_attr.id = SAI_QUEUE_ATTR_TYPE; + queue_attr.value.s32 = 0; + + for (qid = 0; qid < port.m_queue_ids.size(); qid++) + { + /* Get queue type. */ + status = sai_queue_api->get_queue_attribute(port.m_queue_ids[qid], 1, &queue_attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get queue type and index for queue %u rv:%d", qid, status); + return false; + } + + if (queue_attr.value.s32 == SAI_QUEUE_TYPE_UNICAST) + { + num_uc_queues++; + } + } + + /* Multicast queues start after unicast queues. */ + qid = num_uc_queues + index; + } + + /* UCQ - first 8/10 queues of a port are unicast. + * CPUQ - 8 queues, map to queue index logically. + */ + status = sai_queue_api->set_queue_attribute(port.m_queue_ids[qid], &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Unable to set port queue attribute."); + return false; + } + } + + return true; +} + +/* + * Unbind TAM object to bind points. + */ +bool ThresholdOrch::thresTamObjUnbind(thresEventType_t type, string alias, uint32_t index) +{ + return thresTamObjBind(type, alias, index, SAI_NULL_OBJECT_ID); +} + +sai_tam_event_type_t ThresholdOrch::getTamEventType(thresEventType_t type) +{ + sai_tam_event_type_t tamEventType; + + if (type == THRES_EVENT_TYPE_IPG_SHARED) + { + tamEventType = SAI_TAM_EVENT_TYPE_IPG_SHARED; + } + else if (type == THRES_EVENT_TYPE_IPG_HEADROOM) + { + tamEventType = SAI_TAM_EVENT_TYPE_IPG_XOFF_ROOM; + } + else + { + tamEventType = SAI_TAM_EVENT_TYPE_QUEUE_THRESHOLD; + } + + return tamEventType; +} + +/* + * Add and bind TAM entry. + * If a TAM entry exists, the bind point is updated. + */ +bool ThresholdOrch::addBindTamEntry(thresEventType_t eventType, string alias, uint32_t index, + uint32_t threshold) +{ + sai_tam_event_type_t type = getTamEventType(eventType); + thresTamObjEntry tamEntry = {threshold, type}; + thresTamObjData tamEntryData; + bool tamCreated = false; + + /* Check if there is an existing TAM object for config. */ + /* Key is */ + if (m_thresTamTable.find(tamEntry) == m_thresTamTable.end()) + { + /* No existing TAM object, need to create a new one. */ + if (addTamObjEntry(tamEntry) != true) + { + SWSS_LOG_ERROR("Unable to create TAM object table entry."); + return false; + } + tamCreated = true; + } + + tamEntryData = m_thresTamTable[tamEntry]; + + /* Bind TAM object to bind points */ + if (thresTamObjBind(eventType, alias, index, + tamEntryData.m_thresTam) != true) + { + SWSS_LOG_ERROR("Unable to bind TAM object"); + /* Delete TAM object */ + if (tamCreated == true) + (void) deleteTamObjEntry(tamEntry); + return false; + } + + bind_list_t bind = {eventType, alias, index}; + + /* Update bind list of TAM entry */ + m_thresTamTable[tamEntry].bind_list.push_back(bind); + return true; +} + +/* + * Update existing port realm entry. + */ +bool ThresholdOrch::updateCfgThreshold(thresEventType_t eventType, string alias, uint32_t index, + uint32_t cfgThreshold, uint32_t threshold) +{ + sai_tam_event_type_t type = getTamEventType(eventType); + thresTamObjEntry tamEntry = {cfgThreshold, type}; + thresTamObjData *tamEntryData; + + SWSS_LOG_ENTER(); + + /* Find the TAM object. */ + if (m_thresTamTable.find(tamEntry) == m_thresTamTable.end()) + { + SWSS_LOG_ERROR("Realm entry exists but TAM object entry does not exist"); + return false; + } + + tamEntryData = &m_thresTamTable[tamEntry]; + + /* Unbind and proceed. */ + if (thresTamObjUnbind(eventType, alias, index) != true) + { + SWSS_LOG_ERROR("Unable to unbind TAM object."); + return false; + } + + /* Check if there are other bind points for this TAM object. */ + if (tamEntryData->bind_list.size() > 1) + { + /* Find the entry in vector */ + for (vector::iterator it = tamEntryData->bind_list.begin(); + it != tamEntryData->bind_list.end(); ++it) + { + if (it->type == eventType && + it->alias == alias && it->index == index) + { + tamEntryData->bind_list.erase(it); + break; + } + } + } + else + { + /* Delete the TAM object itself */ + if (deleteTamObjEntry(tamEntry) != true) + { + SWSS_LOG_ERROR("Unable to delete TAM object entry."); + } + } + + SWSS_LOG_DEBUG("Applying new threshold %d to entry", threshold); + + /* Apply the new threshold */ + tamEntry.threshold = threshold; + tamEntry.type = type; + + /* Check if there is an existing TAM object for config. */ + /* Key is */ + if (m_thresTamTable.find(tamEntry) == m_thresTamTable.end()) + { + SWSS_LOG_DEBUG("New Tam entry being added thres %d, type %d.", threshold, type); + + /* No existing TAM object, need to create a new one. */ + if (addTamObjEntry(tamEntry) != true) + { + SWSS_LOG_ERROR("Unable to create TAM object table entry."); + return false; + } + } + + tamEntryData = &m_thresTamTable[tamEntry]; + + /* Bind TAM object to bind points */ + if (thresTamObjBind(eventType, alias, index, tamEntryData->m_thresTam) != true) + { + SWSS_LOG_ERROR("Unable to bind TAM object."); + /* Delete TAM object */ + (void) deleteTamObjEntry(tamEntry); + return false; + } + + bind_list_t bind = {eventType, alias, index}; + /* Update bind list of TAM entry */ + m_thresTamTable[tamEntry].bind_list.push_back(bind); + + return true; +} + +/* + * Add/update threshold configuration. + */ +bool ThresholdOrch::addUpdateThresEntry(thresEventType_t eventType, string alias, uint32_t index, + uint32_t threshold) +{ + /* Get realm type */ + thresEntry entry = {eventType, alias, index}; + + SWSS_LOG_ENTER(); + + if (m_thresTable.find(entry) == m_thresTable.end()) + { + /* New thres entry. */ + if (addBindTamEntry(eventType, alias, index, + threshold) != true) + { + SWSS_LOG_ERROR("Unable to add/bind TAM entry."); + return false; + } + + /* Create the new realm entry. */ + m_thresTable[entry] = threshold; + + return true; + } + + SWSS_LOG_DEBUG("Received an update for existing entry, Old threshold %d, new %d", m_thresTable[entry], threshold); + + /* Update existing realm entry. + * Remove existing config and apply new configuration. + */ + if (threshold == m_thresTable[entry]) + { + /* Configuration already exists. Return success */ + SWSS_LOG_DEBUG("Received threshold update for same threshold value %d - %d.", m_thresTable[entry], threshold); + return true; + } + + if (updateCfgThreshold(entry.type, entry.alias, entry.index, + m_thresTable[entry], threshold) != true) + { + SWSS_LOG_ERROR("Unable to update threshold table entry."); + return false; + } + + /* Update thres entry. */ + m_thresTable[entry] = threshold; + + return true; +} + +/* + * Remove threshold configuration. + */ +bool ThresholdOrch::removeThresEntry(thresEventType_t eventType, string alias, uint32_t index) +{ + sai_tam_event_type_t type = getTamEventType(eventType); + thresEntry entry = {eventType, alias, index}; + uint32_t threshold; + + /* Sequence of removal is: + * Find TAM object, check bind_list. + * Unbind from TAM object and if bind_list is 0 after + * remove TAM object and threshold if ref_cnt is 0. + * Finally, remove the entry from port/global realm table. + */ + /* Find the realm entry. */ + if (m_thresTable.find(entry) == m_thresTable.end()) + { + SWSS_LOG_ERROR("Unable to find the threshold entry."); + /* Return true here so that the event gets erased. */ + return true; + } + + threshold = m_thresTable[entry]; + + thresTamObjEntry tamEntry = {threshold, type}; + thresTamObjData *tamEntryData; + + /* Find the TAM object. */ + if (m_thresTamTable.find(tamEntry) == m_thresTamTable.end()) + { + SWSS_LOG_ERROR("Realm entry exists but TAM object entry does not exist"); + return false; + } + + /* Unbind and proceed. */ + if (thresTamObjUnbind(eventType, alias, index) != true) + { + SWSS_LOG_ERROR("Unable to unbind TAM object."); + return false; + } + + tamEntryData = &m_thresTamTable[tamEntry]; + + /* Check if there are other bind points for this TAM object. */ + if (tamEntryData->bind_list.size() > 1) + { + /* Find the entry in vector */ + for (vector::iterator it = tamEntryData->bind_list.begin(); + it != tamEntryData->bind_list.end(); ++it) + { + if (it->type == eventType && + it->alias == alias && it->index == index) + { + tamEntryData->bind_list.erase(it); + break; + } + } + + /* Find and elete entry from bind list */ + // tamEntryData.bind_list.erase(bindList); + } + else + { + /* Delete the TAM object itself */ + if (deleteTamObjEntry(tamEntry) != true) + { + SWSS_LOG_ERROR("Unable to delete TAM object entry."); + } + } + + /* Delete the realm entry. */ + m_thresTable.erase(entry); + + return true; +} + +thresEventType_t getThresEventType(string group, string statType) +{ + thresEventType_t type; + + if (group == "priority-group" && statType == "shared") + { + type = THRES_EVENT_TYPE_IPG_SHARED; + } + else if (group == "priority-group" && statType == "headroom") + { + type = THRES_EVENT_TYPE_IPG_HEADROOM; + } + else if (group == "queue" && statType == "unicast") + { + type = THRES_EVENT_TYPE_QUEUE_UNICAST; + } + else + { + type = THRES_EVENT_TYPE_QUEUE_MULTICAST; + } + + return type; +} + +bool thresholdValidate (uint32_t threshold) +{ + /* Validate the threshold value. + * As of now, threshold is configured as a + * percentage of buffer utilization. + */ + if ((threshold < THRESHOLD_MIN) || (threshold > THRESHOLD_MAX)) + { + SWSS_LOG_ERROR("Invalid threshold %d received.", threshold); + return false; + } + return true; +} + +bool thresholdIndexValidate (uint32_t index, thresEventType_t eventType, Port port) +{ + uint32_t len = 0; + + if ((eventType == THRES_EVENT_TYPE_IPG_SHARED) || + (eventType == THRES_EVENT_TYPE_IPG_HEADROOM)) + { + len = (uint32_t)port.m_priority_group_ids.size(); + } + else if ((eventType == THRES_EVENT_TYPE_QUEUE_UNICAST) || + (THRES_EVENT_TYPE_QUEUE_MULTICAST)) + { + len = (uint32_t)port.m_queue_ids.size(); + } + else + { + SWSS_LOG_ERROR("Invalid eventType received."); + return false; + } + + if (index > (len - 1)) + { + SWSS_LOG_ERROR("Invalid threshold index received %d.", index); + return false; + } + + return true; +} + +/* Threshold table updates. */ +void ThresholdOrch::doThresholdTask(Consumer& consumer) +{ + /* Retrieve attributes from table. */ + thresEventType_t eventType; + string alias, group, type; + uint32_t index; + Port port; + + SWSS_LOG_ENTER(); + + /* Read the key value tuples from Consumer */ + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + /* For every entry read from the queue, + * extract data and call handler to handle data. + * If required to wait for an event, keep event in queue + * and continue. + */ + auto &t = it->second; + + /* Extract key */ + /* key can be of format priority-group|shared|Ethernet1|3 + * or queue|unicast|Ethernet5|3 + */ + vector keys = tokenize(kfvKey(t), config_db_key_delimiter); + + if (keys.size() != 4) + { + /* Invalid table entry */ + SWSS_LOG_ERROR("Wrong format of table CFG_THRESHOLD_TABLE_NAME." ); + it = consumer.m_toSync.erase(it); + continue; + } + + if ((keys[0] != "priority-group") && (keys[0] != "queue")) + { + /* Log and erase event. */ + SWSS_LOG_ERROR("Invalid buffer %s in key on THRESHOLD_TABLE ", keys[0].c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + + /* Validate keys */ + if (keys[0] == "priority-group" && + ((keys[1] != "shared") && (keys[1] != "headroom"))) + { + SWSS_LOG_ERROR("Invalid buffer/buffer_type %s/%s in key on THRESHOLD_TABLE ", + keys[0].c_str(), keys[1].c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + else if (keys[0] == "queue" && + ((keys[1] != "unicast") && (keys[1] != "multicast"))) + { + SWSS_LOG_ERROR("Invalid buffer/buffer_type %s/%s in key on THRESHOLD_TABLE ", + keys[0].c_str(), keys[1].c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + + eventType = getThresEventType(keys[0], keys[1]); + + alias = keys[2]; + + /* Verify the port information. */ + if (!gPortsOrch->isPortReady()) + { + /* Ports not ready yet. Skip over. */ + it++; + continue; + } + + if (!gPortsOrch->getPort(alias, port)) + { + /* Port not available. Skip over. */ + it++; + continue; + } + + index = (uint32_t)stoul(keys[3]); + + if (thresholdIndexValidate(index, eventType, port) != true) + { + /* Invalid index, delete event and proceed. */ + it = consumer.m_toSync.erase(it); + SWSS_LOG_ERROR("Invalid index %d received in key %s.", index, kfvKey(t).c_str()); + continue; + } + + string op = kfvOp(t); + if (op == SET_COMMAND) + { + uint32_t threshold = 0; + SWSS_LOG_DEBUG("Received SET command for THRESHOLD_TABLE, key %s", kfvKey(t).c_str()); + + for (auto i : kfvFieldsValues(t)) + { + + if (fvField(i) == "threshold") + { + threshold = stoi(fvValue(i)); + } + } + + if (thresholdValidate(threshold) != true) + { + /* Invalid threshold, delete event and proceed. */ + it = consumer.m_toSync.erase(it); + SWSS_LOG_ERROR("Invalid threshold %d received in key %s.", threshold, kfvKey(t).c_str()); + continue; + } + + if (addUpdateThresEntry(eventType, alias, index, threshold) != true) + { + /* Retry configuration next time. */ + it++; + continue; + } + } + else if (op == DEL_COMMAND) + { + SWSS_LOG_DEBUG("Received DEL command for THRESHOLD_TABLE, key %s", kfvKey(t).c_str()); + if (removeThresEntry(eventType, alias, index) != true) + { + /* Leave event in queue and + * retry next time. + */ + it++; + continue; + } + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); + } + + /* Erase event. */ + it = consumer.m_toSync.erase(it); + } +} + +void ThresholdOrch::doTask(Consumer& consumer) +{ + SWSS_LOG_ENTER(); + + string table_name = consumer.getTableName(); + + /* Hand-off processing for each table to appropriate handler. */ + if (table_name == CFG_THRESHOLD_TABLE_NAME) + { + doThresholdTask(consumer); + } +} + diff --git a/orchagent/thresholdorch.h b/orchagent/thresholdorch.h new file mode 100644 index 0000000000..df3f5c765c --- /dev/null +++ b/orchagent/thresholdorch.h @@ -0,0 +1,169 @@ +#ifndef SWSS_THRESHOLDORCH_H +#define SWSS_THRESHOLDORCH_H + +#include +#include +#include +#include "orch.h" +#include "observer.h" +#include "portsorch.h" +#include "tam.h" + +#define CLEAR_NOTIFICATION 0 + +#define THRESHOLD_ORCH_SAI_TAM_TRANSPORT_SRC_PORT 7070 +#define THRESHOLD_ORCH_SAI_TAM_THRESHOLD_DST_PORT 9171 +#define THRESHOLD_MIN 1 +#define THRESHOLD_MAX 100 + +/* Threshold bind point . */ +enum thresBindPoint_t +{ + THRES_BIND_POINT_PRIORITY_GROUP, + THRES_BIND_POINT_QUEUE +}; + +/* Threshold event type */ +enum thresEventType_t +{ + THRES_EVENT_TYPE_IPG_SHARED, + THRES_EVENT_TYPE_IPG_HEADROOM, + THRES_EVENT_TYPE_QUEUE_UNICAST, + THRES_EVENT_TYPE_QUEUE_MULTICAST +}; + +/* Map to convert string to realm */ +static const std::map thresGroupString = +{ + { "priority-group", THRES_BIND_POINT_PRIORITY_GROUP,}, + { "queue", THRES_BIND_POINT_QUEUE} +}; + +/* Map to convert thres event type to bind point */ +static const map bindPointType = +{ + {SAI_TAM_EVENT_TYPE_IPG_SHARED, SAI_TAM_BIND_POINT_TYPE_IPG}, + {SAI_TAM_EVENT_TYPE_IPG_XOFF_ROOM, SAI_TAM_BIND_POINT_TYPE_IPG}, + {SAI_TAM_EVENT_TYPE_QUEUE_THRESHOLD, SAI_TAM_BIND_POINT_TYPE_QUEUE} +}; + +/* Threshold entry. */ +struct thresEntry +{ + thresEventType_t type; + string alias; + uint32_t index; + + bool operator<(const thresEntry &o) const + { + return tie(type, alias, index) < tie(o.type, o.alias, o.index); + } + + bool operator==(const thresEntry &o) const + { + return ((type == o.type) && (alias == o.alias) && (index == o.index)); + } +}; + +/* TAM object entry. */ +struct thresTamObjEntry +{ + uint32_t threshold; + sai_tam_event_type_t type; + + bool operator<(const thresTamObjEntry &o) const + { + return tie(threshold, type) < tie(o.threshold, o.type); + } + + bool operator==(const thresTamObjEntry &o) const + { + return (threshold == o.threshold) && (type == o.type); + } +}; + +/* Bind list of TAM entry */ +struct bind_list_t +{ + /* Using thresEvent type here to be able + * to find out type of queue (unicast/multicast). + */ + thresEventType_t type; + string alias; + uint32_t index; +}; + +/* TAM object data entry. */ +struct thresTamObjData +{ + sai_object_id_t m_thresTamEvent; + sai_object_id_t m_thresTam; + + vector bind_list; +}; + +/* threshold object table. */ +struct thresTamThdObjData +{ + sai_object_id_t m_thresTamThd; + uint32_t ref_cnt; +}; + +typedef map thresTable; +typedef map tamObjTable; +typedef map tamThdObjTable; + +class ThresholdOrch : public Orch, public Observer, public Subject, public Tam +{ +public: + ThresholdOrch(DBConnector *db, vector &tableNames, PortsOrch *port); + ~ThresholdOrch(); + + /* Orch infra to receive table updates and notifications. */ + void doTask(Consumer& consumer); +#if CLEAR_NOTIFICATION + void doTask(NotificationConsumer& consumer); +#endif + + /* Threshold doTask */ + void doThresholdTask(Consumer& consumer); + + /* Handle updates from portsorch. */ + void update(SubjectType type, void *cntx); + + thresEventType_t getthresEventType(string thresGroup, string statType); + + /* threshold config APIs */ + bool addUpdateThresEntry(thresEventType_t type, string alias, uint32_t index, uint32_t threshold); + bool removeThresEntry(thresEventType_t type, string alias, uint32_t index); + +private: + PortsOrch *m_portsOrch; + + /* TAM report object for proto. */ + sai_object_id_t m_tamReport; + sai_object_id_t m_tamEventAction; + sai_object_id_t m_tamTransport; + sai_object_id_t m_tamCollector; + + /* thres realm tables. */ + thresTable m_thresTable; + tamObjTable m_thresTamTable; + tamThdObjTable m_thresTamThdTable; + + bool addTamThdObjEntry(uint32_t threshold); + bool deleteTamThdObjEntry(uint32_t threshold); + bool addTamObjEntry(thresTamObjEntry tamObjEntry); + bool deleteTamObjEntry(thresTamObjEntry tamObjEntry); + bool thresTamObjBind(thresEventType_t thresType, string alias, uint32_t index, + sai_object_id_t tamObj); + bool thresTamObjUnbind(thresEventType_t type, string alias, uint32_t index); + sai_tam_event_type_t getTamEventType(thresEventType_t type); + bool addBindTamEntry(thresEventType_t eventType, string alias, uint32_t index, + uint32_t threshold); + bool updateCfgThreshold(thresEventType_t eventType, string alias, uint32_t index, + uint32_t cfgThreshold, uint32_t threshold); + bool createCommonTamObjects(); +}; +#endif /* SWSS_THRESHOLDORCH_H */ + diff --git a/tests/test_threshold.py b/tests/test_threshold.py new file mode 100644 index 0000000000..48775c0b72 --- /dev/null +++ b/tests/test_threshold.py @@ -0,0 +1,1065 @@ +from swsscommon import swsscommon +import os +import re +import time +import json +import redis +import pytest + +class TestThreshold(object): + + def setup_db(self, dvs): + self.cfgdb = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + self.asicdb = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + self.threstbl = swsscommon.Table(self.cfgdb, "THRESHOLD_TABLE") + + ## clean up all cfg, asic db entries. + entries = self.threstbl.getKeys() + for key in entries: + self.threstbl._del(key) + + tbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT") + entries = tbl.getKeys() + for key in entries: + tbl._del(key) + + tbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM") + entries = tbl.getKeys() + for key in entries: + tbl._del(key) + + tbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT_THRESHOLD") + entries = tbl.getKeys() + for key in entries: + tbl._del(key) + + ## Clean up syslog. + dvs.runcmd(['sh', '-c', "echo 0 > /var/log/syslog"]) + + def get_cfg_db_key(self, buffer, buffer_type, port, index): + key = buffer + "|" + buffer_type + "|" + port + "|" + index + return key + + def set_threshold(self, key, threshold): + ## Set the CONFIG_DB entry. + fvs = swsscommon.FieldValuePairs([("threshold", str(threshold))]) + self.threstbl.set(key, fvs) + time.sleep(1) + + def remove_threshold(self, key): + ## Remove the configured CONFIG_DB entry. + self.threstbl._del(key) + time.sleep(1) + + def thresAsicDbValidateTamReport(self, type): + tbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_REPORT") + entries = tbl.getKeys() + assert len(entries) == 1 + + for key in entries: + (status, fvs) = tbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_TAM_REPORT_ATTR_TYPE": + assert fv[1] == type + return True + + def thresAsicDbValidateTamTransport(self, type, sport, dport): + tbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_TRANSPORT") + entries = tbl.getKeys() + assert len(entries) == 1 + + for key in entries: + (status, fvs) = tbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_TAM_TRANSPORT_ATTR_TRANSPORT_TYPE": + assert fv[1] == type + elif fv[0] == "SAI_TAM_TRANSPORT_ATTR_SRC_PORT": + assert fv[1] == sport + elif fv[0] == "SAI_TAM_TRANSPORT_ATTR_DST_PORT": + assert fv[1] == dport + else: + assert False + return True + + def thresAsicDbValidateTamCollector(self, sip, dip): + tbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_COLLECTOR") + entries = tbl.getKeys() + assert len(entries) == 1 + + ## Get transport oid. + transtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_TRANSPORT") + transoid = transtbl.getKeys() + + for key in entries: + (status, fvs) = tbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_TAM_COLLECTOR_ATTR_SRC_IP": + assert fv[1] == sip + elif fv[0] == "SAI_TAM_COLLECTOR_ATTR_DST_IP": + assert fv[1] == dip + elif fv[0] == "SAI_TAM_COLLECTOR_ATTR_TRANSPORT": + assert fv[1] == transoid[0] + elif fv[0] == "SAI_TAM_COLLECTOR_ATTR_DSCP_VALUE": + assert fv[1] == "0" + else: + assert False + + return True + + def thresAsicDbValidateTamEventAction(self): + tbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT_ACTION") + entries = tbl.getKeys() + assert len(entries) == 1 + + ## Get transport oid. + reportbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_REPORT") + reportOid = reportbl.getKeys() + + for key in entries: + (status, fvs) = tbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_TAM_EVENT_ACTION_ATTR_REPORT_TYPE": + assert fv[1] == reportOid[0] + else: + assert False + return True + + def thresAsicDbValidateTamEvent(self, type, threshOid): + tbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT") + entries = tbl.getKeys() + + ## Get action oid. + actiontbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT_ACTION") + actionOid = actiontbl.getKeys() + assert len(actionOid) == 1 + + collectortbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_COLLECTOR") + collectorOid = collectortbl.getKeys() + assert len(collectorOid) == 1 + + + tameventOid = "" + for key in entries: + eventtypefound = False + eventactionfound = False + collectorfound = False + thresholdfound = False + (status, fvs) = tbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_TAM_EVENT_ATTR_TYPE": + if fv[1] == type: + eventtypefound = True + elif fv[0] == "SAI_TAM_EVENT_ATTR_ACTION_LIST": + if fv[1] == "1" + ":" + actionOid[0]: + eventactionfound = True + elif fv[0] == "SAI_TAM_EVENT_ATTR_COLLECTOR_LIST": + if fv[1] == "1" + ":" + collectorOid[0]: + collectorfound = True + elif fv[0] == "SAI_TAM_EVENT_ATTR_THRESHOLD": + if fv[1] == threshOid: + thresholdfound = True + else: + assert False + + if eventtypefound == True and eventactionfound == True and collectorfound == True and thresholdfound == True: + tameventOid = key + + return tameventOid + + def thresAsicDbValidateTam(self, tameventOid, bindPoint): + tbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM") + entries = tbl.getKeys() + + tamOid = "" + for key in entries: + eventfound = False + bindfound = False + (status, fvs) = tbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_TAM_ATTR_EVENT_OBJECTS_LIST": + if fv[1] == "1" + ":" + tameventOid: + eventfound = True + elif fv[0] == "SAI_TAM_ATTR_TAM_BIND_POINT_TYPE_LIST": + if fv[1] == "1" + ":" + bindPoint: + bindfound = True + else: + assert False + + if eventfound is True and bindfound is True: + tamOid = key + return tamOid + + def thresAsicDbValidateTamEventThreshold(self, value, mode): + tbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT_THRESHOLD") + entries = tbl.getKeys() + + threshoid = "" + for key in entries: + (status, fvs) = tbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_TAM_EVENT_THRESHOLD_ATTR_UNIT": + assert fv[1] == mode + elif fv[0] == "SAI_TAM_EVENT_THRESHOLD_ATTR_ABS_VALUE": + if fv[1] == value: + threshoid = key + else: + assert False + + return threshoid + + def thresAsicDbValidateCommon(self): + self.thresAsicDbValidateTamReport("SAI_TAM_REPORT_TYPE_PROTO") + self.thresAsicDbValidateTamEventAction() + self.thresAsicDbValidateTamTransport("SAI_TAM_TRANSPORT_TYPE_UDP", "7070", "9171") + #self.thresAsicDbValidateTamCollector("10.10.10.10", "127.0.0.1") + self.thresAsicDbValidateTamCollector("10.10.10.10", "1.0.0.127") + + return True + + def test_ThresEntrySetReceived(self, dvs): + + self.setup_db(dvs) + marker = dvs.add_log_marker() + ## Set log level to DEBUG. + dvs.runcmd("swssloglevel -l DEBUG -c orchagent") + + ## Set threshold entry. + key = self.get_cfg_db_key("priority-group", "shared", "Ethernet20", "7") + threshold = 20 + self.set_threshold(key, threshold) + + ## Check syslog to see if SET received by orch. + (exitcode, num) = dvs.runcmd(['sh', '-c', 'cat /var/log/syslog | grep "Received SET command for THRESHOLD_TABLE" | wc -l'] ) + assert num.strip() >= str(1) + + # cleanup + self.remove_threshold(key) + + def test_ThresEntryDelReceived(self, dvs): + + self.setup_db(dvs) + ## Set log level to DEBUG. + dvs.runcmd("swssloglevel -l DEBUG -c orchagent") + + ## Set and delete threshold entry. + key = self.get_cfg_db_key("priority-group", "shared", "Ethernet20", "7") + threshold = 20 + self.set_threshold(key, threshold) + self.remove_threshold(key) + + ## Check syslog to see if SET received by orch. + (exitcode, num) = dvs.runcmd(['sh', '-c', 'cat /var/log/syslog | grep "Received DEL command for THRESHOLD_TABLE" | wc -l'] ) + assert num.strip() >= str(1) + + def test_ThresEntryInvalidBuffer(self, dvs): + + self.setup_db(dvs) + + ## Set and delete threshold entry. + key = self.get_cfg_db_key("buffer-pool ", "shared", "Ethernet20", "7") + threshold = 20 + self.set_threshold(key, threshold) + + ## Check syslog to see if orch detected an error on key. + (exitcode, num) = dvs.runcmd(['sh', '-c', 'cat /var/log/syslog | grep "Invalid buffer buffer-pool" | wc -l'] ) + assert num.strip() == str(1) + + def test_ThresEntryInvalidBufferType(self, dvs): + + self.setup_db(dvs) + + ## Set and delete threshold entry. + key = self.get_cfg_db_key("priority-group", "unicast", "Ethernet20", "7") + threshold = 30 + self.set_threshold(key, threshold) + + ## Check syslog to see if orch detected an error on key. + (exitcode, num) = dvs.runcmd(['sh', '-c', 'cat /var/log/syslog | grep "Invalid buffer/buffer_type priority-group/unicast" | wc -l'] ) + assert num.strip() == str(1) + + def test_ThresEntryInvalidBufferType1(self, dvs): + + self.setup_db(dvs) + + ## Set and delete threshold entry. + key = self.get_cfg_db_key("queue", "shared", "Ethernet20", "7") + threshold = 30 + self.set_threshold(key, threshold) + + ## Check syslog to see if orch detected an error on key. + (exitcode, num) = dvs.runcmd(['sh', '-c', 'cat /var/log/syslog | grep "Invalid buffer/buffer_type queue/shared" | wc -l'] ) + assert num.strip() == str(1) + + def test_ThresEntryInvalidNumKeys(self, dvs): + + self.setup_db(dvs) + + ## Set and delete threshold entry. + key = "queue" + "|" + "unicast" + "|" + "Ethernet20" +"|" + "7" + "|" + "new" + threshold = 30 + self.set_threshold(key, threshold) + + ## Check syslog to see if orch detected an error on key. + (exitcode, num) = dvs.runcmd(['sh', '-c', 'cat /var/log/syslog | grep "Wrong format of table CFG_THRESHOLD_TABLE_NAME" | wc -l'] ) + assert num.strip() == str(1) + + def test_ThresEntryInvalidIndex(self, dvs): + + self.setup_db(dvs) + + ## Set and delete threshold entry. + key = self.get_cfg_db_key("queue", "unicast", "Ethernet20", "30") + threshold = 30 + self.set_threshold(key, threshold) + + ## Check syslog to see if orch detected an error on key. + (exitcode, num) = dvs.runcmd(['sh', '-c', 'cat /var/log/syslog | grep "Invalid index 30 received in key" | wc -l'] ) + assert num.strip() == str(1) + + def test_ThresEntryInvalidThreshold(self, dvs): + + self.setup_db(dvs) + + ## Set and delete threshold entry. + key = self.get_cfg_db_key("queue", "unicast", "Ethernet20", "3") + threshold = 0 + self.set_threshold(key, threshold) + + ## Check syslog to see if orch detected an error on key. + (exitcode, num) = dvs.runcmd(['sh', '-c', 'cat /var/log/syslog | grep "Invalid threshold 0 received in key" | wc -l'] ) + assert num.strip() == str(1) + + def test_ThresEntryInvalidThresholdMax(self, dvs): + + self.setup_db(dvs) + + ## Set and delete threshold entry. + key = self.get_cfg_db_key("queue", "unicast", "Ethernet20", "3") + threshold = 101 + self.set_threshold(key, threshold) + + ## Check syslog to see if orch detected an error on key. + (exitcode, num) = dvs.runcmd(['sh', '-c', 'cat /var/log/syslog | grep "Invalid threshold 101 received in key" | wc -l'] ) + assert num.strip() == str(1) + + def test_ThresPgSharedConfigure(self, dvs): + self.setup_db(dvs) + + dvs.runcmd("swssloglevel -l NOTICE -c orchagent") + ## Set CONFIG_DB entry. + key = self.get_cfg_db_key("priority-group", "shared", "Ethernet40", "7") + threshold = 10 + self.set_threshold(key, threshold) + + ## Validate TAM objects in ASIC_DB. + assert self.thresAsicDbValidateCommon() == True + + ## Validate threshold object + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid != "" + + ## Validate Tam event object. + tamEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_IPG_SHARED", threshOid) + assert tamEventOid != "" + + ## Validate Tam object + tamOid = self.thresAsicDbValidateTam(tamEventOid, "SAI_TAM_BIND_POINT_TYPE_IPG") + + ## Validate the bind point + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_INGRESS_PRIORITY_GROUP_ATTR_TAM": + if fv[1] == "1" + ":" + tamOid: + entryfound = True + + assert entryfound == True + # cleanup + self.remove_threshold(key) + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + def test_ThresPgHeadroomConfigure(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry. + key = self.get_cfg_db_key("priority-group", "headroom", "Ethernet40", "7") + threshold = 40 + self.set_threshold(key, threshold) + + ## Validate TAM objects in ASIC_DB. + assert self.thresAsicDbValidateCommon() == True + + ## Validate threshold object + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid != "" + + ## Validate Tam event object. + tamEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_IPG_XOFF_ROOM", threshOid) + assert tamEventOid != "" + + ## Validate Tam object + tamOid = self.thresAsicDbValidateTam(tamEventOid, "SAI_TAM_BIND_POINT_TYPE_IPG") + + ## Validate the bind point + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_INGRESS_PRIORITY_GROUP_ATTR_TAM": + if fv[1] == "1" + ":" + tamOid: + entryfound = True + + assert entryfound == True + + # cleanup + self.remove_threshold(key) + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + def test_ThresQueueUnicastConfigure(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry. + key = self.get_cfg_db_key("queue", "unicast", "Ethernet40", "1") + threshold = 87 + self.set_threshold(key, threshold) + + ## Validate TAM objects in ASIC_DB. + assert self.thresAsicDbValidateCommon() == True + + ## Validate threshold object + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid != "" + + ## Validate Tam event object. + tamEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_QUEUE_THRESHOLD", threshOid) + assert tamEventOid != "" + + ## Validate Tam object + tamOid = self.thresAsicDbValidateTam(tamEventOid, "SAI_TAM_BIND_POINT_TYPE_QUEUE") + assert tamOid != "" + + ## Validate the bind point + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_QUEUE") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_QUEUE_ATTR_TAM_OBJECT": + if fv[1] == "1" + ":" + tamOid: + entryfound = True + + assert entryfound == True + + # cleanup + self.remove_threshold(key) + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + def test_ThresCfgDeletePgShared(self, dvs): + self.setup_db(dvs) + + key = self.get_cfg_db_key("priority-group", "shared", "Ethernet32", "5") + threshold = 56 + self.set_threshold(key, threshold) + + self.remove_threshold(key) + + ## Validate TAM objects in ASIC_DB. + ## Common objects still remain. + assert self.thresAsicDbValidateCommon() == True + + ## No entries for the other entries. + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid == "" + + ## Check for TAM event object. + tameventtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT") + entries = tameventtbl.getKeys() + assert len(entries) == 0 + + ## Check for Tam object. + tamtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM") + entries = tamtbl.getKeys() + assert len(entries) == 0 + + ## Validate the bind point + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_INGRESS_PRIORITY_GROUP_ATTR_TAM": + print(key) + print(fvs) + if fv[1] != "0:null": + entryfound = True + + assert entryfound == False + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + def test_ThresCfgDeletePgHeadroom(self, dvs): + self.setup_db(dvs) + + key = self.get_cfg_db_key("priority-group", "headroom", "Ethernet32", "5") + threshold = 65 + self.set_threshold(key, threshold) + + self.remove_threshold(key) + + ## Validate TAM objects in ASIC_DB. + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid == "" + + ## Check for TAM event object. + tameventtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT") + entries = tameventtbl.getKeys() + assert len(entries) == 0 + + ## Check for Tam object. + tamtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM") + entries = tamtbl.getKeys() + assert len(entries) == 0 + + ## Validate the bind point + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_INGRESS_PRIORITY_GROUP_ATTR_TAM": + if fv[1] != "0:null": + entryfound = True + + assert entryfound == False + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + def test_ThresCfgDeleteQueueUnicast(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry to use the same threshold value for 2 different realms.. + key = self.get_cfg_db_key("queue", "unicast", "Ethernet32", "5") + threshold = 86 + self.set_threshold(key, threshold) + + self.remove_threshold(key) + + ## Validate TAM objects in ASIC_DB. + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid == "" + + ## Check for TAM event object. + tameventtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT") + entries = tameventtbl.getKeys() + assert len(entries) == 0 + + ## Check for Tam object. + tamtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM") + entries = tamtbl.getKeys() + assert len(entries) == 0 + + ## Validate the bind point + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_QUEUE") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_QUEUE_ATTR_TAM_OBJECT": + if fv[1] != "0:null": + entryfound = True + + assert entryfound == False + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + + + def test_ThresCfgDeleteSameThresholdOnOneBuffer(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry to use the same threshold value for 2 different realms.. + key = self.get_cfg_db_key("queue", "unicast", "Ethernet32", "6") + threshold = 86 + self.set_threshold(key, threshold) + + key1 = self.get_cfg_db_key("priority-group", "shared", "Ethernet32", "5") + self.set_threshold(key1, threshold) + + self.remove_threshold(key) + + ## Validate TAM objects in ASIC_DB. + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid != "" + + ## Check for TAM event object. + tamqueueEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_QUEUE_THRESHOLD", threshOid) + assert tamqueueEventOid == "" + + ## Check for TAM event object for PG. + tampgEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_IPG_SHARED", threshOid) + assert tampgEventOid != "" + + ## Validate Tam object for PG + tampgOid = self.thresAsicDbValidateTam(tampgEventOid, "SAI_TAM_BIND_POINT_TYPE_IPG") + assert tampgOid != "" + + ## Validate the bind point for queue + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_QUEUE") + entries = bindtbl.getKeys() + + entryfound = False + cnt = 0 + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_QUEUE_ATTR_TAM_OBJECT": + assert fv[1] == "0:null" + + + entryfound = False + + ## Validate the bind point for IPG + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_INGRESS_PRIORITY_GROUP_ATTR_TAM": + if fv[1] == "1" + ":" + tampgOid: + entryfound = True + + assert entryfound == True + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + + def test_ThresCfgUpdateThreshold(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry to use the same threshold value for 2 different realms.. + key = self.get_cfg_db_key("priority-group", "shared", "Ethernet40", "5") + threshold = 56 + self.set_threshold(key, threshold) + + threshold = 78 + self.set_threshold(key, threshold) + + time.sleep(5) + + ## Validate TAM objects in ASIC_DB. + assert self.thresAsicDbValidateCommon() == True + + ## Validate threshold object + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid != "" + + ## Validate that previous threshold object is not present. + threshOldOid = self.thresAsicDbValidateTamEventThreshold(str(56), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOldOid == "" + + ## Validate Tam event object. + tamEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_IPG_SHARED", threshOid) + assert tamEventOid != "" + + ## Validate Tam object + tamOid = self.thresAsicDbValidateTam(tamEventOid, "SAI_TAM_BIND_POINT_TYPE_IPG") + assert tamOid != "" + + ## Validate the bind point + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_INGRESS_PRIORITY_GROUP_ATTR_TAM": + print(key) + print(fvs) + if fv[1] == "1" + ":" + tamOid: + entryfound = True + + assert entryfound == True + # cleanup + self.remove_threshold(key) + + def test_ThresCfgSameThresholdOnDiffBuffers(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry to use the same threshold value for 2 different realms.. + key = self.get_cfg_db_key("queue", "unicast", "Ethernet40", "7") + threshold = 34 + self.set_threshold(key, threshold) + + key1 = self.get_cfg_db_key("priority-group", "shared", "Ethernet40", "6") + self.set_threshold(key1, threshold) + + ## Validate TAM objects in ASIC_DB. + assert self.thresAsicDbValidateCommon() == True + + ## Validate threshold object + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid != "" + + ## Validate Tam event object for queue. + tamqueueEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_QUEUE_THRESHOLD", threshOid) + assert tamqueueEventOid != "" + + ## Validate Tam event object for PG. + tampgEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_IPG_SHARED", threshOid) + assert tampgEventOid != "" + + ## Validate Tam object for queue + tamqueueOid = self.thresAsicDbValidateTam(tamqueueEventOid, "SAI_TAM_BIND_POINT_TYPE_QUEUE") + assert tamqueueOid != "" + + ## Validate Tam object for PG + tampgOid = self.thresAsicDbValidateTam(tampgEventOid, "SAI_TAM_BIND_POINT_TYPE_IPG") + assert tampgOid != "" + + ## Validate the bind point for queue + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_QUEUE") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_QUEUE_ATTR_TAM_OBJECT": + if fv[1] == "1" + ":" + tamqueueOid: + entryfound = True + + assert entryfound == True + + + ## Validate bind point for PG + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_INGRESS_PRIORITY_GROUP_ATTR_TAM": + if fv[1] == "1" + ":" + tampgOid: + entryfound = True + + assert entryfound == True + + # cleanup + self.remove_threshold(key) + self.remove_threshold(key1) + + + def test_ThresCfgSameThresholdOnPGBuffer(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry to use the same threshold value for 2 different realms.. + key = self.get_cfg_db_key("priority-group", "shared", "Ethernet40", "4") + threshold = 34 + self.set_threshold(key, threshold) + + key1 = self.get_cfg_db_key("priority-group", "headroom", "Ethernet32", "6") + self.set_threshold(key1, threshold) + + ## Validate TAM objects in ASIC_DB. + assert self.thresAsicDbValidateCommon() == True + + ## Validate threshold object + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid != "" + + ## Validate Tam event object for PG shared. + tamsharedEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_IPG_SHARED", threshOid) + assert tamsharedEventOid != "" + + ## Validate Tam event object for PG headroom. + tamxoffEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_IPG_XOFF_ROOM", threshOid) + assert tamxoffEventOid != "" + + ## Validate Tam object for PG shared + tamsharedOid = self.thresAsicDbValidateTam(tamsharedEventOid, "SAI_TAM_BIND_POINT_TYPE_IPG") + assert tamsharedOid != "" + + ## Validate Tam object for PG headroom + tamxoffOid = self.thresAsicDbValidateTam(tamxoffEventOid, "SAI_TAM_BIND_POINT_TYPE_IPG") + assert tamxoffOid != "" + + ## Validate the bind point for PG shared + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP") + entries = bindtbl.getKeys() + + entrysharedfound = False + entryxofffound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_INGRESS_PRIORITY_GROUP_ATTR_TAM": + if fv[1] == "1" + ":" + tamsharedOid: + entrysharedfound = True + elif fv[1] == "1" + ":" + tamxoffOid: + entryxofffound = True + + entryfound = entrysharedfound and entryxofffound + assert entryfound == True + + # cleanup + self.remove_threshold(key) + self.remove_threshold(key1) + + def test_ThresCfgSameThresholdOnBufferBufferType(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry to use the same threshold value for 2 different realms.. + key = self.get_cfg_db_key("priority-group", "shared", "Ethernet32", "5") + threshold = 43 + self.set_threshold(key, threshold) + + key1 = self.get_cfg_db_key("priority-group", "shared", "Ethernet32", "6") + self.set_threshold(key1, threshold) + + + ## Validate TAM objects in ASIC_DB. + assert self.thresAsicDbValidateCommon() == True + + ## Validate threshold object + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid != "" + + ## Validate Tam event object for PG. + tampgEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_IPG_SHARED", threshOid) + assert tampgEventOid != "" + + ## Validate Tam object for PG + tampgOid = self.thresAsicDbValidateTam(tampgEventOid, "SAI_TAM_BIND_POINT_TYPE_IPG") + assert tampgOid != "" + + ## Validate bind point for PG + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP") + entries = bindtbl.getKeys() + + entryfound = False + cnt = 0 + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_INGRESS_PRIORITY_GROUP_ATTR_TAM": + if fv[1] == "1" + ":" + tampgOid: + entryfound = True + cnt += 1 + + assert entryfound == True + assert cnt == 2 + + # cleanup + self.remove_threshold(key) + self.remove_threshold(key1) + +""" + + def test_ThresCfgDeleteQueueMulticast(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry to use the same threshold value for 2 different realms.. + key = self.get_cfg_db_key("queue", "multicast", "Ethernet32", "5") + threshold = 86 + self.set_threshold(key, threshold) + + self.remove_threshold(key) + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + ## Validate TAM objects in ASIC_DB. + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid == "" + + ## Check for TAM event object. + tameventtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT") + entries = tameventtbl.getKeys() + assert len(entries) == 0 + + ## Check for Tam object. + tamtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM") + entries = tamtbl.getKeys() + assert len(entries) == 0 + + ## Validate the bind point + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_QUEUE") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_QUEUE_ATTR_TAM_OBJECT": + if fv[1] != "0:null": + entryfound = True + + assert entryfound == False + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + def test_ThresCfgDeleteSameThreshold(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry to use the same threshold value for 2 different realms.. + key = self.get_cfg_db_key("queue", "multicast", "Ethernet32", "5") + threshold = 86 + self.set_threshold(key, threshold) + + key1 = self.get_cfg_db_key("queue", "unicast", "Ethernet32", "5") + self.set_threshold(key1, threshold) + + self.remove_threshold(key) + self.remove_threshold(key1) + + ## Validate TAM objects in ASIC_DB. + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid == "" + + ## Check for TAM event object. + tameventtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM_EVENT") + entries = tameventtbl.getKeys() + assert len(entries) == 0 + + ## Check for Tam object. + tamtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_TAM") + entries = tamtbl.getKeys() + assert len(entries) == 0 + + ## Validate the bind point + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_QUEUE") + entries = bindtbl.getKeys() + + entryfound = False + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_QUEUE_ATTR_TAM_OBJECT": + if fv[1] != "0:null": + entryfound = True + + assert entryfound == False + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + def test_ThresQueueMulticastConfigure(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry. + key = self.get_cfg_db_key("queue", "multicast", "Ethernet40", "5") + threshold = 34 + self.set_threshold(key, threshold) + + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + ## Validate TAM objects in ASIC_DB. + assert self.thresAsicDbValidateCommon() == True + + ## Validate threshold object + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid != "" + + ## Validate Tam event object. + tamEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_QUEUE_THRESHOLD", threshOid) + assert tamEventOid != "" + + ## Validate Tam object. Bind cannot be tested on vs since get QUEUE_TYPE + ## is not implemented on vs.Check if TAM object is created successfully. + tamOid = self.thresAsicDbValidateTam(tamEventOid, "SAI_TAM_BIND_POINT_TYPE_QUEUE") + assert tamOid != "" + (exitcode, output) = dvs.runcmd("redis-cli -n 1 keys *TAM*") + print(output) + + + + def test_ThresCfgSameThresholdOnBuffer(self, dvs): + self.setup_db(dvs) + + ## Set CONFIG_DB entry to use the same threshold value for 2 different realms.. + key = self.get_cfg_db_key("queue", "multicast", "Ethernet40", "5") + threshold = 34 + self.set_threshold(key, threshold) + + key = self.get_cfg_db_key("queue", "unicast", "Ethernet40", "6") + self.set_threshold(key, threshold) + + ## Validate TAM objects in ASIC_DB. + assert self.thresAsicDbValidateCommon() == True + + ## Validate threshold object + threshOid = self.thresAsicDbValidateTamEventThreshold(str(threshold), "SAI_TAM_EVENT_THRESHOLD_UNIT_PERCENT") + assert threshOid != "" + + ## Validate Tam event object for queue. + tamqueueEventOid = self.thresAsicDbValidateTamEvent("SAI_TAM_EVENT_TYPE_QUEUE_THRESHOLD", threshOid) + assert tamqueueEventOid != "" + + ## Validate Tam object for queue + tamqueueOid = self.thresAsicDbValidateTam(tamqueueEventOid, "SAI_TAM_BIND_POINT_TYPE_QUEUE") + assert tamqueueOid != "" + + ## Validate the bind point for queue + bindtbl = swsscommon.Table(self.asicdb, "ASIC_STATE:SAI_OBJECT_TYPE_QUEUE") + entries = bindtbl.getKeys() + + entryfound = False + cnt = 0 + for key in entries: + (status, fvs) = bindtbl.get(key) + assert status == True + for fv in fvs: + if fv[0] == "SAI_QUEUE_ATTR_TAM_OBJECT": + if fv[1] == "1" + ":" + tamqueueOid: + entryfound = True + cnt += 1 + + ## Bind cannot be tested on vs for multicast queue since get QUEUE_TYPE + ## is not implemented on vs.Check if TAM object is created successfully. + + assert entryfound == True + assert cnt == 1 +"""