From f66abeda6a6e67b40b997b779ec3a6a362632fc1 Mon Sep 17 00:00:00 2001 From: Divya Mukundan <118740570+dmukun@users.noreply.github.com> Date: Mon, 20 Feb 2023 07:43:47 +0530 Subject: [PATCH] Support for tc-dot1p and tc-dscp qosmap (#2559) * Support for tc-dot1p and tc-dscp qosmap --- orchagent/orchdaemon.cpp | 1 + orchagent/qosorch.cpp | 68 ++++++++++++++- orchagent/qosorch.h | 10 +++ tests/test_qos_map.py | 183 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 258 insertions(+), 4 deletions(-) diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 5f432502566d..2b7564fc0751 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -235,6 +235,7 @@ bool OrchDaemon::init() CFG_PFC_PRIORITY_TO_QUEUE_MAP_TABLE_NAME, CFG_DSCP_TO_FC_MAP_TABLE_NAME, CFG_EXP_TO_FC_MAP_TABLE_NAME, + CFG_TC_TO_DOT1P_MAP_TABLE_NAME, CFG_TC_TO_DSCP_MAP_TABLE_NAME }; gQosOrch = new QosOrch(m_configDb, qos_tables); diff --git a/orchagent/qosorch.cpp b/orchagent/qosorch.cpp index 515d591e00a1..f10b44f58c23 100644 --- a/orchagent/qosorch.cpp +++ b/orchagent/qosorch.cpp @@ -58,6 +58,8 @@ map qos_to_attr_map = { {mpls_tc_to_tc_field_name, SAI_PORT_ATTR_QOS_MPLS_EXP_TO_TC_MAP}, {dot1p_to_tc_field_name, SAI_PORT_ATTR_QOS_DOT1P_TO_TC_MAP}, {tc_to_queue_field_name, SAI_PORT_ATTR_QOS_TC_TO_QUEUE_MAP}, + {tc_to_dot1p_field_name, SAI_PORT_ATTR_QOS_TC_AND_COLOR_TO_DOT1P_MAP}, + {tc_to_dscp_field_name, SAI_PORT_ATTR_QOS_TC_AND_COLOR_TO_DSCP_MAP}, {tc_to_pg_map_field_name, SAI_PORT_ATTR_QOS_TC_TO_PRIORITY_GROUP_MAP}, {pfc_to_pg_map_name, SAI_PORT_ATTR_QOS_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP}, {pfc_to_queue_map_name, SAI_PORT_ATTR_QOS_PFC_PRIORITY_TO_QUEUE_MAP}, @@ -85,6 +87,7 @@ type_map QosOrch::m_qos_maps = { {CFG_PFC_PRIORITY_TO_QUEUE_MAP_TABLE_NAME, new object_reference_map()}, {CFG_DSCP_TO_FC_MAP_TABLE_NAME, new object_reference_map()}, {CFG_EXP_TO_FC_MAP_TABLE_NAME, new object_reference_map()}, + {CFG_TC_TO_DOT1P_MAP_TABLE_NAME, new object_reference_map()}, {CFG_TC_TO_DSCP_MAP_TABLE_NAME, new object_reference_map()}, {APP_TUNNEL_DECAP_TABLE_NAME, new object_reference_map()} }; @@ -94,6 +97,8 @@ map qos_to_ref_table_map = { {mpls_tc_to_tc_field_name, CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME}, {dot1p_to_tc_field_name, CFG_DOT1P_TO_TC_MAP_TABLE_NAME}, {tc_to_queue_field_name, CFG_TC_TO_QUEUE_MAP_TABLE_NAME}, + {tc_to_dot1p_field_name, CFG_TC_TO_DOT1P_MAP_TABLE_NAME}, + {tc_to_dscp_field_name, CFG_TC_TO_DSCP_MAP_TABLE_NAME}, {tc_to_pg_map_field_name, CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME}, {pfc_to_pg_map_name, CFG_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE_NAME}, {pfc_to_queue_map_name, CFG_PFC_PRIORITY_TO_QUEUE_MAP_TABLE_NAME}, @@ -178,7 +183,7 @@ task_process_status QosMapHandler::processWorkItem(Consumer& consumer, KeyOpFiel } if (!removeQosItem(sai_object)) { - SWSS_LOG_ERROR("Failed to remove dscp_to_tc map. db name:%s sai object:%" PRIx64, qos_object_name.c_str(), sai_object); + SWSS_LOG_ERROR("Failed to remove QoS map. db name:%s sai object:%" PRIx64, qos_object_name.c_str(), sai_object); return task_process_status::task_failed; } auto it_to_delete = (QosOrch::getTypeMap()[qos_map_type_name])->find(qos_object_name); @@ -470,6 +475,60 @@ task_process_status QosOrch::handleTcToQueueTable(Consumer& consumer, KeyOpField return tc_queue_handler.processWorkItem(consumer, tuple); } +//Functions for TC-to-DOT1P qos map handling +bool TcToDot1pMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_attribute_t list_attr; + sai_qos_map_list_t tc_map_list; + tc_map_list.count = (uint32_t)kfvFieldsValues(tuple).size(); + tc_map_list.list = new sai_qos_map_t[tc_map_list.count](); + uint32_t ind = 0; + for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++, ind++) + { + tc_map_list.list[ind].key.tc = (uint8_t)stoi(fvField(*i)); + tc_map_list.list[ind].value.dot1p = (uint8_t)stoi(fvValue(*i)); + } + list_attr.id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST; + list_attr.value.qosmap.count = tc_map_list.count; + list_attr.value.qosmap.list = tc_map_list.list; + attributes.push_back(list_attr); + return true; +} + +sai_object_id_t TcToDot1pMapHandler::addQosItem(const vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_status_t sai_status; + sai_object_id_t sai_object; + vector qos_map_attrs; + sai_attribute_t qos_map_attr; + + qos_map_attr.id = SAI_QOS_MAP_ATTR_TYPE; + qos_map_attr.value.s32 = SAI_QOS_MAP_TYPE_TC_AND_COLOR_TO_DOT1P; + qos_map_attrs.push_back(qos_map_attr); + + qos_map_attr.id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST; + qos_map_attr.value.qosmap.count = attributes[0].value.qosmap.count; + qos_map_attr.value.qosmap.list = attributes[0].value.qosmap.list; + qos_map_attrs.push_back(qos_map_attr); + + sai_status = sai_qos_map_api->create_qos_map(&sai_object, gSwitchId, (uint32_t)qos_map_attrs.size(), qos_map_attrs.data()); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to create tc_to_dot1p qos map. status:%d", sai_status); + return SAI_NULL_OBJECT_ID; + } + return sai_object; +} + +task_process_status QosOrch::handleTcToDot1pTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple) +{ + SWSS_LOG_ENTER(); + TcToDot1pMapHandler tc_dot1p_handler; + return tc_dot1p_handler.processWorkItem(consumer, tuple); +} + void WredMapHandler::freeAttribResources(vector &attributes) { SWSS_LOG_ENTER(); @@ -857,7 +916,7 @@ sai_object_id_t TcToPgHandler::addQosItem(const vector &attribu sai_status = sai_qos_map_api->create_qos_map(&sai_object, gSwitchId, (uint32_t)qos_map_attrs.size(), qos_map_attrs.data()); if (SAI_STATUS_SUCCESS != sai_status) { - SWSS_LOG_ERROR("Failed to create tc_to_queue map. status:%d", sai_status); + SWSS_LOG_ERROR("Failed to create tc_to_pg map. status:%d", sai_status); return SAI_NULL_OBJECT_ID; } return sai_object; @@ -911,7 +970,7 @@ sai_object_id_t PfcPrioToPgHandler::addQosItem(const vector &at sai_status = sai_qos_map_api->create_qos_map(&sai_object, gSwitchId, (uint32_t)qos_map_attrs.size(), qos_map_attrs.data()); if (SAI_STATUS_SUCCESS != sai_status) { - SWSS_LOG_ERROR("Failed to create tc_to_queue map. status:%d", sai_status); + SWSS_LOG_ERROR("Failed to create pfc_priority_to_queue map. status:%d", sai_status); return SAI_NULL_OBJECT_ID; } return sai_object; @@ -966,7 +1025,7 @@ sai_object_id_t PfcToQueueHandler::addQosItem(const vector &att sai_status = sai_qos_map_api->create_qos_map(&sai_object, gSwitchId, (uint32_t)qos_map_attrs.size(), qos_map_attrs.data()); if (SAI_STATUS_SUCCESS != sai_status) { - SWSS_LOG_ERROR("Failed to create tc_to_queue map. status:%d", sai_status); + SWSS_LOG_ERROR("Failed to create pfc_priority_to_queue map. status:%d", sai_status); return SAI_NULL_OBJECT_ID; } return sai_object; @@ -1274,6 +1333,7 @@ void QosOrch::initTableHandlers() m_qos_handler_map.insert(qos_handler_pair(CFG_DSCP_TO_FC_MAP_TABLE_NAME, &QosOrch::handleDscpToFcTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_EXP_TO_FC_MAP_TABLE_NAME, &QosOrch::handleExpToFcTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_TC_TO_DSCP_MAP_TABLE_NAME, &QosOrch::handleTcToDscpTable)); + m_qos_handler_map.insert(qos_handler_pair(CFG_TC_TO_DOT1P_MAP_TABLE_NAME, &QosOrch::handleTcToDot1pTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME, &QosOrch::handleTcToPgTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE_NAME, &QosOrch::handlePfcPrioToPgTable)); diff --git a/orchagent/qosorch.h b/orchagent/qosorch.h index f677e68a01bc..8079e45bc0b1 100644 --- a/orchagent/qosorch.h +++ b/orchagent/qosorch.h @@ -17,6 +17,8 @@ const string pfc_enable_name = "pfc_enable"; const string pfcwd_sw_enable_name = "pfcwd_sw_enable"; const string tc_to_pg_map_field_name = "tc_to_pg_map"; const string tc_to_queue_field_name = "tc_to_queue_map"; +const string tc_to_dot1p_field_name = "tc_to_dot1p_map"; +const string tc_to_dscp_field_name = "tc_to_dscp_map"; const string scheduler_field_name = "scheduler"; const string red_max_threshold_field_name = "red_max_threshold"; const string red_min_threshold_field_name = "red_min_threshold"; @@ -175,6 +177,13 @@ class TcToDscpMapHandler : public QosMapHandler sai_object_id_t addQosItem(const vector &attributes) override; }; +class TcToDot1pMapHandler : public QosMapHandler +{ +public: + bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector &attributes); + sai_object_id_t addQosItem(const vector &attributes); +}; + class QosOrch : public Orch { public: @@ -209,6 +218,7 @@ class QosOrch : public Orch task_process_status handleDscpToFcTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple); task_process_status handleExpToFcTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple); task_process_status handleTcToDscpTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple); + task_process_status handleTcToDot1pTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple); task_process_status handleGlobalQosMap(const string &op, KeyOpFieldsValuesTuple &tuple); diff --git a/tests/test_qos_map.py b/tests/test_qos_map.py index 39c6c717cab3..905b0dacaa77 100644 --- a/tests/test_qos_map.py +++ b/tests/test_qos_map.py @@ -3,6 +3,32 @@ from swsscommon import swsscommon +CFG_TC_TO_DSCP_MAP_TABLE_NAME = "TC_TO_DSCP_MAP" +CFG_TC_TO_DSCP_MAP_KEY = "AZURE" +TC_TO_DSCP_MAP = { + "0": "20", + "1": "16", + "2": "5", + "3": "43", + "4": "34", + "5": "52", + "6": "61", + "7": "17", +} + +CFG_TC_TO_DOT1P_MAP_TABLE_NAME = "TC_TO_DOT1P_MAP" +CFG_TC_TO_DOT1P_MAP_KEY = "AZURE" +TC_TO_DOT1P_MAP = { + "0": "0", + "1": "6", + "2": "5", + "3": "3", + "4": "4", + "5": "2", + "6": "1", + "7": "7", +} + CFG_DOT1P_TO_TC_MAP_TABLE_NAME = "DOT1P_TO_TC_MAP" CFG_DOT1P_TO_TC_MAP_KEY = "AZURE" DOT1P_TO_TC_MAP = { @@ -32,9 +58,166 @@ CFG_PORT_QOS_MAP_TABLE_NAME = "PORT_QOS_MAP" CFG_PORT_QOS_DOT1P_MAP_FIELD = "dot1p_to_tc_map" CFG_PORT_QOS_MPLS_TC_MAP_FIELD = "mpls_tc_to_tc_map" +CFG_PORT_QOS_TC_DOT1P_MAP_FIELD = "tc_to_dot1p_map" +CFG_PORT_QOS_TC_DSCP_MAP_FIELD = "tc_to_dscp_map" CFG_PORT_TABLE_NAME = "PORT" +#Tests for TC-to-DSCP qos map configuration +class TestTcDscp(object): + def connect_dbs(self, dvs): + self.asic_db = swsscommon.DBConnector(1, dvs.redis_sock, 0) + self.config_db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + def create_tc_dscp_profile(self): + tbl = swsscommon.Table(self.config_db, CFG_TC_TO_DSCP_MAP_TABLE_NAME) + fvs = swsscommon.FieldValuePairs(list(TC_TO_DSCP_MAP.items())) + tbl.set(CFG_TC_TO_DSCP_MAP_KEY, fvs) + time.sleep(1) + + def find_tc_dscp_profile(self): + found = False + tc_dscp_map_raw = None + tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_QOS_MAP") + keys = tbl.getKeys() + for key in keys: + (status, fvs) = tbl.get(key) + assert status == True + + for fv in fvs: + if fv[0] == "SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST": + tc_dscp_map_raw = fv[1] + elif fv[0] == "SAI_QOS_MAP_ATTR_TYPE" and fv[1] == "SAI_QOS_MAP_TYPE_TC_AND_COLOR_TO_DSCP": + found = True + + if found: + break + + assert found == True + + return (key, tc_dscp_map_raw) + + def apply_tc_dscp_profile_on_all_ports(self): + tbl = swsscommon.Table(self.config_db, CFG_PORT_QOS_MAP_TABLE_NAME) + fvs = swsscommon.FieldValuePairs([(CFG_PORT_QOS_TC_DSCP_MAP_FIELD, CFG_TC_TO_DSCP_MAP_KEY)]) + ports = swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys() + for port in ports: + tbl.set(port, fvs) + + time.sleep(1) + + + def test_tc_dscp_cfg(self, dvs): + self.connect_dbs(dvs) + self.create_tc_dscp_profile() + _, tc_dscp_map_raw = self.find_tc_dscp_profile() + + tc_dscp_map = json.loads(tc_dscp_map_raw) + for tc2dscp in tc_dscp_map['list']: + tc_val = str(tc2dscp['key']['tc']) + dscp_val = str(tc2dscp['value']['dscp']) + assert dscp_val == TC_TO_DSCP_MAP[tc_val] + + def test_port_tc_dscp(self, dvs): + self.connect_dbs(dvs) + self.create_tc_dscp_profile() + oid, _ = self.find_tc_dscp_profile() + + self.apply_tc_dscp_profile_on_all_ports() + + cnt = 0 + tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_PORT") + keys = tbl.getKeys() + for key in keys: + (status, fvs) = tbl.get(key) + assert status == True + + for fv in fvs: + if fv[0] == "SAI_PORT_ATTR_QOS_TC_AND_COLOR_TO_DSCP_MAP": + cnt += 1 + assert fv[1] == oid + + port_cnt = len(swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys()) + assert port_cnt == cnt + + +#Tests for TC-to-Dot1p qos map configuration +class TestTcDot1p(object): + def connect_dbs(self, dvs): + self.asic_db = swsscommon.DBConnector(1, dvs.redis_sock, 0) + self.config_db = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + def create_tc_dot1p_profile(self): + tbl = swsscommon.Table(self.config_db, CFG_TC_TO_DOT1P_MAP_TABLE_NAME) + fvs = swsscommon.FieldValuePairs(list(TC_TO_DOT1P_MAP.items())) + tbl.set(CFG_TC_TO_DOT1P_MAP_KEY, fvs) + time.sleep(1) + + def find_tc_dot1p_profile(self): + found = False + tc_dot1p_map_raw = None + tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_QOS_MAP") + keys = tbl.getKeys() + for key in keys: + (status, fvs) = tbl.get(key) + assert status == True + + for fv in fvs: + if fv[0] == "SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST": + tc_dot1p_map_raw = fv[1] + elif fv[0] == "SAI_QOS_MAP_ATTR_TYPE" and fv[1] == "SAI_QOS_MAP_TYPE_TC_AND_COLOR_TO_DOT1P": + found = True + + if found: + break + + assert found == True + + return (key, tc_dot1p_map_raw) + + def apply_tc_dot1p_profile_on_all_ports(self): + tbl = swsscommon.Table(self.config_db, CFG_PORT_QOS_MAP_TABLE_NAME) + fvs = swsscommon.FieldValuePairs([(CFG_PORT_QOS_TC_DOT1P_MAP_FIELD, CFG_TC_TO_DOT1P_MAP_KEY)]) + ports = swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys() + for port in ports: + tbl.set(port, fvs) + + time.sleep(1) + + + def test_tc_dot1p_cfg(self, dvs): + self.connect_dbs(dvs) + self.create_tc_dot1p_profile() + _, tc_dot1p_map_raw = self.find_tc_dot1p_profile() + + tc_dot1p_map = json.loads(tc_dot1p_map_raw) + for tc2dot1p in tc_dot1p_map['list']: + tc_val = str(tc2dot1p['key']['tc']) + dot1p_val = str(tc2dot1p['value']['dot1p']) + assert dot1p_val == TC_TO_DOT1P_MAP[tc_val] + + def test_port_tc_dot1p(self, dvs): + self.connect_dbs(dvs) + self.create_tc_dot1p_profile() + oid, _ = self.find_tc_dot1p_profile() + + self.apply_tc_dot1p_profile_on_all_ports() + + cnt = 0 + tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_PORT") + keys = tbl.getKeys() + for key in keys: + (status, fvs) = tbl.get(key) + assert status == True + + for fv in fvs: + if fv[0] == "SAI_PORT_ATTR_QOS_TC_AND_COLOR_TO_DOT1P_MAP": + cnt += 1 + assert fv[1] == oid + + port_cnt = len(swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys()) + assert port_cnt == cnt +#Tests for Dot1p-to-TC qos map configuration class TestDot1p(object): def connect_dbs(self, dvs): self.asic_db = swsscommon.DBConnector(1, dvs.redis_sock, 0)