diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index af5edaa028..2c4f2126b2 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -129,6 +129,7 @@ bool OrchDaemon::init() CFG_TC_TO_QUEUE_MAP_TABLE_NAME, CFG_SCHEDULER_TABLE_NAME, CFG_DSCP_TO_TC_MAP_TABLE_NAME, + CFG_DOT1P_TO_TC_MAP_TABLE_NAME, CFG_QUEUE_TABLE_NAME, CFG_PORT_QOS_MAP_TABLE_NAME, CFG_WRED_PROFILE_TABLE_NAME, diff --git a/orchagent/qosorch.cpp b/orchagent/qosorch.cpp index 12783468fb..4e92275d79 100644 --- a/orchagent/qosorch.cpp +++ b/orchagent/qosorch.cpp @@ -2,6 +2,7 @@ #include "qosorch.h" #include "logger.h" #include "crmorch.h" +#include "sai_serialize.h" #include #include @@ -41,8 +42,10 @@ enum { RED_DROP_PROBABILITY_SET = (1U << 2) }; +// field_name is what is expected in CONFIG_DB PORT_QOS_MAP table map qos_to_attr_map = { {dscp_to_tc_field_name, SAI_PORT_ATTR_QOS_DSCP_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_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}, @@ -51,6 +54,7 @@ map qos_to_attr_map = { type_map QosOrch::m_qos_maps = { {CFG_DSCP_TO_TC_MAP_TABLE_NAME, new object_map()}, + {CFG_DOT1P_TO_TC_MAP_TABLE_NAME, new object_map()}, {CFG_TC_TO_QUEUE_MAP_TABLE_NAME, new object_map()}, {CFG_SCHEDULER_TABLE_NAME, new object_map()}, {CFG_WRED_PROFILE_TABLE_NAME, new object_map()}, @@ -216,6 +220,75 @@ task_process_status QosOrch::handleDscpToTcTable(Consumer& consumer) return dscp_tc_handler.processWorkItem(consumer); } +bool Dot1pToTcMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector &attributes) +{ + SWSS_LOG_ENTER(); + sai_qos_map_list_t dot1p_map_list; + + // Allocated resources are freed in freeAttribResources() call + dot1p_map_list.list = new sai_qos_map_t[kfvFieldsValues(tuple).size()]; + int i = 0; + for (const auto &fv : kfvFieldsValues(tuple)) + { + try + { + dot1p_map_list.list[i].key.dot1p = static_cast(stoi(fvField(fv))); + dot1p_map_list.list[i].value.tc = static_cast(stoi(fvValue(fv))); + } + catch (const std::invalid_argument &e) + { + SWSS_LOG_ERROR("Invalid dot1p to tc argument %s:%s to %s()", fvField(fv).c_str(), fvValue(fv).c_str(), e.what()); + continue; + } + catch (const std::out_of_range &e) + { + SWSS_LOG_ERROR("Out of range dot1p to tc argument %s:%s to %s()", fvField(fv).c_str(), fvValue(fv).c_str(), e.what()); + continue; + } + + i++; + } + dot1p_map_list.count = static_cast(i); + + sai_attribute_t attr; + attr.id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST; + attr.value.qosmap.count = dot1p_map_list.count; + attr.value.qosmap.list = dot1p_map_list.list; + attributes.push_back(attr); + + return true; +} + +sai_object_id_t Dot1pToTcMapHandler::addQosItem(const vector &attributes) +{ + SWSS_LOG_ENTER(); + vector attrs; + + sai_attribute_t attr; + attr.id = SAI_QOS_MAP_ATTR_TYPE; + attr.value.u32 = SAI_QOS_MAP_TYPE_DOT1P_TO_TC; + attrs.push_back(attr); + + attrs.push_back(attributes[0]); + + sai_object_id_t object_id; + sai_status_t sai_status = sai_qos_map_api->create_qos_map(&object_id, gSwitchId, (uint32_t)attrs.size(), attrs.data()); + if (SAI_STATUS_SUCCESS != sai_status) + { + SWSS_LOG_ERROR("Failed to create dot1p_to_tc map. status: %s", sai_serialize_status(sai_status).c_str()); + return SAI_NULL_OBJECT_ID; + } + SWSS_LOG_DEBUG("created QosMap object: 0x%lx", object_id); + return object_id; +} + +task_process_status QosOrch::handleDot1pToTcTable(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + Dot1pToTcMapHandler dot1p_tc_handler; + return dot1p_tc_handler.processWorkItem(consumer); +} + bool TcToQueueMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector &attributes) { SWSS_LOG_ENTER(); @@ -800,6 +873,7 @@ void QosOrch::initTableHandlers() { SWSS_LOG_ENTER(); m_qos_handler_map.insert(qos_handler_pair(CFG_DSCP_TO_TC_MAP_TABLE_NAME, &QosOrch::handleDscpToTcTable)); + m_qos_handler_map.insert(qos_handler_pair(CFG_DOT1P_TO_TC_MAP_TABLE_NAME, &QosOrch::handleDot1pToTcTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_TC_TO_QUEUE_MAP_TABLE_NAME, &QosOrch::handleTcToQueueTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_SCHEDULER_TABLE_NAME, &QosOrch::handleSchedulerTable)); m_qos_handler_map.insert(qos_handler_pair(CFG_QUEUE_TABLE_NAME, &QosOrch::handleQueueTable)); diff --git a/orchagent/qosorch.h b/orchagent/qosorch.h index 079260c5d5..88ed96d914 100644 --- a/orchagent/qosorch.h +++ b/orchagent/qosorch.h @@ -8,6 +8,7 @@ #include "portsorch.h" const string dscp_to_tc_field_name = "dscp_to_tc_map"; +const string dot1p_to_tc_field_name = "dot1p_to_tc_map"; const string pfc_to_pg_map_name = "pfc_to_pg_map"; const string pfc_to_queue_map_name = "pfc_to_queue_map"; const string pfc_enable_name = "pfc_enable"; @@ -65,8 +66,15 @@ class QosMapHandler class DscpToTcMapHandler : public QosMapHandler { public: - bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector &attributes); - sai_object_id_t addQosItem(const vector &attributes); + bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector &attributes) override; + sai_object_id_t addQosItem(const vector &attributes) override; +}; + +class Dot1pToTcMapHandler : public QosMapHandler +{ +public: + bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector &attributes) override; + sai_object_id_t addQosItem(const vector &attributes) override; }; class TcToQueueMapHandler : public QosMapHandler @@ -134,6 +142,7 @@ class QosOrch : public Orch void initTableHandlers(); task_process_status handleDscpToTcTable(Consumer& consumer); + task_process_status handleDot1pToTcTable(Consumer& consumer); task_process_status handlePfcPrioToPgTable(Consumer& consumer); task_process_status handlePfcToQueueTable(Consumer& consumer); task_process_status handlePortQosMapTable(Consumer& consumer); diff --git a/tests/test_qos_map.py b/tests/test_qos_map.py new file mode 100644 index 0000000000..03ff0c63e3 --- /dev/null +++ b/tests/test_qos_map.py @@ -0,0 +1,105 @@ +import pytest +import json +import sys +import time +from swsscommon import swsscommon + +CFG_DOT1P_TO_TC_MAP_TABLE_NAME = "DOT1P_TO_TC_MAP" +CFG_DOT1P_TO_TC_MAP_KEY = "AZURE" +DOT1P_TO_TC_MAP = { + "0": "0", + "1": "6", + "2": "5", + "3": "3", + "4": "4", + "5": "2", + "6": "1", + "7": "7", +} + +CFG_PORT_QOS_MAP_TABLE_NAME = "PORT_QOS_MAP" +CFG_PORT_QOS_MAP_FIELD = "dot1p_to_tc_map" +CFG_PORT_TABLE_NAME = "PORT" + + +class TestDot1p(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_dot1p_profile(self): + tbl = swsscommon.Table(self.config_db, CFG_DOT1P_TO_TC_MAP_TABLE_NAME) + fvs = swsscommon.FieldValuePairs(DOT1P_TO_TC_MAP.items()) + tbl.set(CFG_DOT1P_TO_TC_MAP_KEY, fvs) + time.sleep(1) + + + def find_dot1p_profile(self): + found = False + dot1p_tc_map_raw = None + dot1p_tc_map_key = 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": + dot1p_tc_map_raw = fv[1] + elif fv[0] == "SAI_QOS_MAP_ATTR_TYPE" and fv[1] == "SAI_QOS_MAP_TYPE_DOT1P_TO_TC": + dot1p_tc_map_key = key + found = True + + if found: + break + + assert found == True + + return (key, dot1p_tc_map_raw) + + + def apply_dot1p_profile_on_all_ports(self): + tbl = swsscommon.Table(self.config_db, CFG_PORT_QOS_MAP_TABLE_NAME) + fvs = swsscommon.FieldValuePairs([(CFG_PORT_QOS_MAP_FIELD, "[" + CFG_DOT1P_TO_TC_MAP_TABLE_NAME + "|" + CFG_DOT1P_TO_TC_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_dot1p_cfg(self, dvs): + self.connect_dbs(dvs) + self.create_dot1p_profile() + oid, dot1p_tc_map_raw = self.find_dot1p_profile() + + dot1p_tc_map = json.loads(dot1p_tc_map_raw); + for dot1p2tc in dot1p_tc_map['list']: + dot1p = str(dot1p2tc['key']['dot1p']) + tc = str(dot1p2tc['value']['tc']) + assert tc == DOT1P_TO_TC_MAP[dot1p] + + + def test_port_dot1p(self, dvs): + self.connect_dbs(dvs) + self.create_dot1p_profile() + oid, dot1p_tc_map_raw = self.find_dot1p_profile() + + self.apply_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_DOT1P_TO_TC_MAP": + cnt += 1 + assert fv[1] == oid + + port_cnt = len(swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys()) + assert port_cnt == cnt