Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for tc-dot1p and tc-dscp qosmap #2559

Merged
merged 7 commits into from
Feb 20, 2023
1 change: 1 addition & 0 deletions orchagent/orchdaemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
68 changes: 64 additions & 4 deletions orchagent/qosorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ map<string, sai_port_attr_t> 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},
Expand Down Expand Up @@ -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()}
};
Expand All @@ -94,6 +97,8 @@ map<string, string> 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},
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<sai_attribute_t> &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<sai_attribute_t> &attributes)
{
SWSS_LOG_ENTER();
sai_status_t sai_status;
sai_object_id_t sai_object;
vector<sai_attribute_t> 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<sai_attribute_t> &attributes)
{
SWSS_LOG_ENTER();
Expand Down Expand Up @@ -857,7 +916,7 @@ sai_object_id_t TcToPgHandler::addQosItem(const vector<sai_attribute_t> &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;
Expand Down Expand Up @@ -911,7 +970,7 @@ sai_object_id_t PfcPrioToPgHandler::addQosItem(const vector<sai_attribute_t> &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;
Expand Down Expand Up @@ -966,7 +1025,7 @@ sai_object_id_t PfcToQueueHandler::addQosItem(const vector<sai_attribute_t> &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;
Expand Down Expand Up @@ -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));
Expand Down
10 changes: 10 additions & 0 deletions orchagent/qosorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -175,6 +177,13 @@ class TcToDscpMapHandler : public QosMapHandler
sai_object_id_t addQosItem(const vector<sai_attribute_t> &attributes) override;
};

class TcToDot1pMapHandler : public QosMapHandler
{
public:
bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector<sai_attribute_t> &attributes);
sai_object_id_t addQosItem(const vector<sai_attribute_t> &attributes);
};

class QosOrch : public Orch
{
public:
Expand Down Expand Up @@ -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);

Expand Down
183 changes: 183 additions & 0 deletions tests/test_qos_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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)
Expand Down