Skip to content

Commit 4374348

Browse files
authored
Apply DSCP_TO_TC_MAP from PORT_QOS_MAP|global to switch level (sonic-net#2314)
* Apply DSCP_TO_TC_MAP|AZURE to switch level Signed-off-by: bingwang <[email protected]>
1 parent 3c3bb17 commit 4374348

File tree

5 files changed

+214
-70
lines changed

5 files changed

+214
-70
lines changed

cfgmgr/buffermgr.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
using namespace std;
1717
using namespace swss;
1818

19+
#define PORT_NAME_GLOBAL "global"
20+
1921
BufferMgr::BufferMgr(DBConnector *cfgDb, DBConnector *applDb, string pg_lookup_file, const vector<string> &tableNames) :
2022
Orch(cfgDb, tableNames),
2123
m_cfgPortTable(cfgDb, CFG_PORT_TABLE_NAME),
@@ -413,6 +415,12 @@ void BufferMgr::doPortQosTableTask(Consumer &consumer)
413415
{
414416
KeyOpFieldsValuesTuple tuple = it->second;
415417
string port_name = kfvKey(tuple);
418+
if (port_name == PORT_NAME_GLOBAL)
419+
{
420+
// Ignore the entry for global level
421+
it = consumer.m_toSync.erase(it);
422+
continue;
423+
}
416424
string op = kfvOp(tuple);
417425
if (op == SET_COMMAND)
418426
{

orchagent/qosorch.cpp

+102-54
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ map<string, string> qos_to_ref_table_map = {
104104
#define DSCP_MAX_VAL 63
105105
#define EXP_MAX_VAL 7
106106

107+
#define PORT_NAME_GLOBAL "global"
108+
107109
task_process_status QosMapHandler::processWorkItem(Consumer& consumer, KeyOpFieldsValuesTuple &tuple)
108110
{
109111
SWSS_LOG_ENTER();
@@ -236,37 +238,6 @@ bool DscpToTcMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &
236238
return true;
237239
}
238240

239-
void DscpToTcMapHandler::applyDscpToTcMapToSwitch(sai_attr_id_t attr_id, sai_object_id_t map_id)
240-
{
241-
SWSS_LOG_ENTER();
242-
bool rv = true;
243-
244-
/* Query DSCP_TO_TC QoS map at switch capability */
245-
rv = gSwitchOrch->querySwitchDscpToTcCapability(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP);
246-
if (rv == false)
247-
{
248-
SWSS_LOG_ERROR("Switch level DSCP to TC QoS map configuration is not supported");
249-
return;
250-
}
251-
252-
/* Apply DSCP_TO_TC QoS map at switch */
253-
sai_attribute_t attr;
254-
attr.id = attr_id;
255-
attr.value.oid = map_id;
256-
257-
sai_status_t status = sai_switch_api->set_switch_attribute(gSwitchId, &attr);
258-
if (status != SAI_STATUS_SUCCESS)
259-
{
260-
SWSS_LOG_ERROR("Failed to apply DSCP_TO_TC QoS map to switch rv:%d", status);
261-
return;
262-
}
263-
264-
if (map_id != gQosOrch->m_globalDscpToTcMap)
265-
gQosOrch->m_globalDscpToTcMap = map_id;
266-
267-
SWSS_LOG_NOTICE("Applied DSCP_TO_TC QoS map to switch successfully");
268-
}
269-
270241
sai_object_id_t DscpToTcMapHandler::addQosItem(const vector<sai_attribute_t> &attributes)
271242
{
272243
SWSS_LOG_ENTER();
@@ -292,36 +263,13 @@ sai_object_id_t DscpToTcMapHandler::addQosItem(const vector<sai_attribute_t> &at
292263
}
293264
SWSS_LOG_DEBUG("created QosMap object:%" PRIx64, sai_object);
294265

295-
applyDscpToTcMapToSwitch(SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP, sai_object);
296-
297266
return sai_object;
298267
}
299268

300269
bool DscpToTcMapHandler::removeQosItem(sai_object_id_t sai_object)
301270
{
302271
SWSS_LOG_ENTER();
303272

304-
if (sai_object == gQosOrch->m_globalDscpToTcMap)
305-
{
306-
// The current global dscp to tc map is about to be removed.
307-
// Find another one to set to the switch or NULL in case this is the last one
308-
const auto &dscpToTcObjects = (*QosOrch::getTypeMap()[CFG_DSCP_TO_TC_MAP_TABLE_NAME]);
309-
bool found = false;
310-
for (const auto &ref : dscpToTcObjects)
311-
{
312-
if (ref.second.m_saiObjectId == sai_object)
313-
continue;
314-
SWSS_LOG_NOTICE("Current global dscp_to_tc map is about to be removed, set it to %s %" PRIx64, ref.first.c_str(), ref.second.m_saiObjectId);
315-
applyDscpToTcMapToSwitch(SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP, ref.second.m_saiObjectId);
316-
found = true;
317-
break;
318-
}
319-
if (!found)
320-
{
321-
applyDscpToTcMapToSwitch(SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP, SAI_NULL_OBJECT_ID);
322-
}
323-
}
324-
325273
SWSS_LOG_DEBUG("Removing DscpToTcMap object:%" PRIx64, sai_object);
326274
sai_status_t sai_status = sai_qos_map_api->remove_qos_map(sai_object);
327275
if (SAI_STATUS_SUCCESS != sai_status)
@@ -1717,12 +1665,112 @@ task_process_status QosOrch::handleQueueTable(Consumer& consumer, KeyOpFieldsVal
17171665
return task_process_status::task_success;
17181666
}
17191667

1668+
bool QosOrch::applyDscpToTcMapToSwitch(sai_attr_id_t attr_id, sai_object_id_t map_id)
1669+
{
1670+
SWSS_LOG_ENTER();
1671+
1672+
/* Query DSCP_TO_TC QoS map at switch capability */
1673+
bool rv = gSwitchOrch->querySwitchDscpToTcCapability(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP);
1674+
if (rv == false)
1675+
{
1676+
SWSS_LOG_ERROR("Switch level DSCP to TC QoS map configuration is not supported");
1677+
return true;
1678+
}
1679+
1680+
/* Apply DSCP_TO_TC QoS map at switch */
1681+
sai_attribute_t attr;
1682+
attr.id = attr_id;
1683+
attr.value.oid = map_id;
1684+
1685+
sai_status_t status = sai_switch_api->set_switch_attribute(gSwitchId, &attr);
1686+
if (status != SAI_STATUS_SUCCESS)
1687+
{
1688+
SWSS_LOG_ERROR("Failed to apply DSCP_TO_TC QoS map to switch rv:%d", status);
1689+
return false;
1690+
}
1691+
1692+
SWSS_LOG_NOTICE("Applied DSCP_TO_TC QoS map to switch successfully");
1693+
return true;
1694+
}
1695+
1696+
task_process_status QosOrch::handleGlobalQosMap(const string &OP, KeyOpFieldsValuesTuple &tuple)
1697+
{
1698+
SWSS_LOG_ENTER();
1699+
1700+
task_process_status task_status = task_process_status::task_success;
1701+
1702+
if (OP == DEL_COMMAND)
1703+
{
1704+
string referenced_obj;
1705+
if (!doesObjectExist(m_qos_maps, CFG_PORT_QOS_MAP_TABLE_NAME, PORT_NAME_GLOBAL, dscp_to_tc_field_name, referenced_obj))
1706+
{
1707+
return task_status;
1708+
}
1709+
// Set SAI_NULL_OBJECT_ID to switch level if PORT_QOS_MAP|global is removed
1710+
if (applyDscpToTcMapToSwitch(SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP, SAI_NULL_OBJECT_ID))
1711+
{
1712+
removeObject(m_qos_maps, CFG_PORT_QOS_MAP_TABLE_NAME, PORT_NAME_GLOBAL);
1713+
task_status = task_process_status::task_success;
1714+
SWSS_LOG_INFO("Global QoS map type %s is removed", dscp_to_tc_field_name.c_str());
1715+
}
1716+
else
1717+
{
1718+
task_status = task_process_status::task_failed;
1719+
SWSS_LOG_WARN("Failed to remove switch level QoS map type %s", dscp_to_tc_field_name.c_str());
1720+
}
1721+
return task_status;
1722+
}
1723+
1724+
for (auto it = kfvFieldsValues(tuple).begin(); it != kfvFieldsValues(tuple).end(); it++)
1725+
{
1726+
string map_type_name = fvField(*it);
1727+
string map_name = fvValue(*it);
1728+
if (map_type_name != dscp_to_tc_field_name)
1729+
{
1730+
SWSS_LOG_WARN("Qos map type %s is not supported at global level", map_type_name.c_str());
1731+
continue;
1732+
}
1733+
1734+
if (qos_to_attr_map.find(map_type_name) != qos_to_attr_map.end())
1735+
{
1736+
sai_object_id_t id;
1737+
string object_name;
1738+
ref_resolve_status status = resolveFieldRefValue(m_qos_maps, map_type_name, qos_to_ref_table_map.at(map_type_name), tuple, id, object_name);
1739+
1740+
if (status != ref_resolve_status::success)
1741+
{
1742+
SWSS_LOG_INFO("Global QoS map %s is not yet created", map_name.c_str());
1743+
task_status = task_process_status::task_need_retry;
1744+
}
1745+
1746+
if (applyDscpToTcMapToSwitch(SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP, id))
1747+
{
1748+
setObjectReference(m_qos_maps, CFG_PORT_QOS_MAP_TABLE_NAME, PORT_NAME_GLOBAL, map_type_name, object_name);
1749+
task_status = task_process_status::task_success;
1750+
SWSS_LOG_INFO("Applied QoS map type %s name %s to switch level", map_type_name.c_str(), object_name.c_str());
1751+
}
1752+
else
1753+
{
1754+
task_status = task_process_status::task_failed;
1755+
SWSS_LOG_INFO("Failed to apply QoS map type %s name %s to switch level", map_type_name.c_str(), object_name.c_str());
1756+
}
1757+
}
1758+
}
1759+
return task_status;
1760+
}
1761+
17201762
task_process_status QosOrch::handlePortQosMapTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple)
17211763
{
17221764
SWSS_LOG_ENTER();
17231765

17241766
string key = kfvKey(tuple);
17251767
string op = kfvOp(tuple);
1768+
1769+
if (key == PORT_NAME_GLOBAL)
1770+
{
1771+
return handleGlobalQosMap(op, tuple);
1772+
}
1773+
17261774
vector<string> port_names = tokenize(key, list_item_delimiter);
17271775

17281776
if (op == DEL_COMMAND)

orchagent/qosorch.h

+3-6
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ class DscpToTcMapHandler : public QosMapHandler
7878
bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector<sai_attribute_t> &attributes) override;
7979
sai_object_id_t addQosItem(const vector<sai_attribute_t> &attributes) override;
8080
bool removeQosItem(sai_object_id_t sai_object);
81-
protected:
82-
void applyDscpToTcMapToSwitch(sai_attr_id_t attr_id, sai_object_id_t sai_dscp_to_tc_map);
8381
};
8482

8583
class MplsTcToTcMapHandler : public QosMapHandler
@@ -195,11 +193,13 @@ class QosOrch : public Orch
195193
task_process_status handleExpToFcTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple);
196194
task_process_status handleTcToDscpTable(Consumer& consumer, KeyOpFieldsValuesTuple &tuple);
197195

196+
task_process_status handleGlobalQosMap(const string &op, KeyOpFieldsValuesTuple &tuple);
197+
198198
sai_object_id_t getSchedulerGroup(const Port &port, const sai_object_id_t queue_id);
199199

200200
bool applySchedulerToQueueSchedulerGroup(Port &port, size_t queue_ind, sai_object_id_t scheduler_profile_id);
201201
bool applyWredProfileToQueue(Port &port, size_t queue_ind, sai_object_id_t sai_wred_profile);
202-
202+
bool applyDscpToTcMapToSwitch(sai_attr_id_t attr_id, sai_object_id_t sai_dscp_to_tc_map);
203203
private:
204204
qos_table_handler_map m_qos_handler_map;
205205

@@ -212,9 +212,6 @@ class QosOrch : public Orch
212212

213213
std::unordered_map<sai_object_id_t, SchedulerGroupPortInfo_t> m_scheduler_group_port_info;
214214

215-
// SAI OID of the global dscp to tc map
216-
sai_object_id_t m_globalDscpToTcMap;
217-
218215
friend QosMapHandler;
219216
friend DscpToTcMapHandler;
220217
};

tests/mock_tests/qosorch_ut.cpp

+31-10
Original file line numberDiff line numberDiff line change
@@ -723,8 +723,6 @@ namespace qosorch_test
723723
static_cast<Orch *>(gQosOrch)->doTask();
724724
ASSERT_EQ(++current_sai_remove_qos_map_count, sai_remove_qos_map_count);
725725
ASSERT_EQ((*QosOrch::getTypeMap()[CFG_DSCP_TO_TC_MAP_TABLE_NAME]).count("AZURE"), 0);
726-
// Global dscp to tc map should not be cleared
727-
ASSERT_EQ((*QosOrch::getTypeMap()[CFG_DSCP_TO_TC_MAP_TABLE_NAME])["AZURE_1"].m_saiObjectId, switch_dscp_to_tc_map_id);
728726

729727
// Make sure other dependencies are not touched
730728
CheckDependency(CFG_PORT_QOS_MAP_TABLE_NAME, "Ethernet0", "pfc_to_pg_map", CFG_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE_NAME, "AZURE");
@@ -931,12 +929,9 @@ namespace qosorch_test
931929

932930
TEST_F(QosOrchTest, QosOrchTestGlobalDscpToTcMap)
933931
{
934-
// Make sure dscp to tc map is correct
935-
ASSERT_EQ((*QosOrch::getTypeMap()[CFG_DSCP_TO_TC_MAP_TABLE_NAME])["AZURE"].m_saiObjectId, switch_dscp_to_tc_map_id);
936-
937932
// Create a new dscp to tc map
938933
std::deque<KeyOpFieldsValuesTuple> entries;
939-
entries.push_back({"AZURE_1", "SET",
934+
entries.push_back({"AZURE", "SET",
940935
{
941936
{"1", "0"},
942937
{"0", "1"}
@@ -945,16 +940,42 @@ namespace qosorch_test
945940
auto consumer = dynamic_cast<Consumer *>(gQosOrch->getExecutor(CFG_DSCP_TO_TC_MAP_TABLE_NAME));
946941
consumer->addToSync(entries);
947942
entries.clear();
948-
// Drain DSCP_TO_TC_MAP table
943+
944+
entries.push_back({"global", "SET",
945+
{
946+
{"dscp_to_tc_map", "AZURE"}
947+
}});
948+
consumer = dynamic_cast<Consumer *>(gQosOrch->getExecutor(CFG_PORT_QOS_MAP_TABLE_NAME));
949+
consumer->addToSync(entries);
950+
entries.clear();
951+
952+
// Drain DSCP_TO_TC_MAP and PORT_QOS_MAP table
953+
static_cast<Orch *>(gQosOrch)->doTask();
954+
// Check DSCP_TO_TC_MAP|AZURE is applied to switch
955+
ASSERT_EQ((*QosOrch::getTypeMap()[CFG_DSCP_TO_TC_MAP_TABLE_NAME])["AZURE"].m_saiObjectId, switch_dscp_to_tc_map_id);
956+
957+
// Remove global DSCP_TO_TC_MAP
958+
entries.push_back({"global", "DEL", {}});
959+
consumer = dynamic_cast<Consumer *>(gQosOrch->getExecutor(CFG_PORT_QOS_MAP_TABLE_NAME));
960+
consumer->addToSync(entries);
961+
entries.clear();
962+
// Drain PORT_QOS_TABLE table
949963
static_cast<Orch *>(gQosOrch)->doTask();
950-
ASSERT_EQ((*QosOrch::getTypeMap()[CFG_DSCP_TO_TC_MAP_TABLE_NAME])["AZURE_1"].m_saiObjectId, switch_dscp_to_tc_map_id);
964+
// Check switch_level dscp_to_tc_map is set to NULL
965+
ASSERT_EQ(SAI_NULL_OBJECT_ID, switch_dscp_to_tc_map_id);
951966

952-
entries.push_back({"AZURE_1", "DEL", {}});
967+
entries.push_back({"AZURE", "DEL", {}});
968+
consumer = dynamic_cast<Consumer *>(gQosOrch->getExecutor(CFG_DSCP_TO_TC_MAP_TABLE_NAME));
953969
consumer->addToSync(entries);
954970
entries.clear();
971+
972+
auto current_sai_remove_qos_map_count = sai_remove_qos_map_count;
955973
// Drain DSCP_TO_TC_MAP table
956974
static_cast<Orch *>(gQosOrch)->doTask();
957-
ASSERT_EQ((*QosOrch::getTypeMap()[CFG_DSCP_TO_TC_MAP_TABLE_NAME])["AZURE"].m_saiObjectId, switch_dscp_to_tc_map_id);
975+
// Check DSCP_TO_TC_MAP|AZURE is removed, and the switch_level dscp_to_tc_map is set to NULL
976+
ASSERT_EQ(current_sai_remove_qos_map_count + 1, sai_remove_qos_map_count);
977+
ASSERT_EQ((*QosOrch::getTypeMap()[CFG_DSCP_TO_TC_MAP_TABLE_NAME]).count("AZURE"), 0);
978+
958979
}
959980

960981
TEST_F(QosOrchTest, QosOrchTestRetryFirstItem)

tests/test_qos_map.py

+70
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,76 @@ def test_port_mpls_tc(self, dvs):
370370
port_cnt = len(swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys())
371371
assert port_cnt == cnt
372372

373+
class TestDscpToTcMap(object):
374+
ASIC_QOS_MAP_STR = "ASIC_STATE:SAI_OBJECT_TYPE_QOS_MAP"
375+
ASIC_PORT_STR = "ASIC_STATE:SAI_OBJECT_TYPE_PORT"
376+
ASIC_SWITCH_STR = "ASIC_STATE:SAI_OBJECT_TYPE_SWITCH"
377+
378+
def init_test(self, dvs):
379+
dvs.setup_db()
380+
self.asic_db = dvs.get_asic_db()
381+
self.config_db = dvs.get_config_db()
382+
self.asic_qos_map_ids = self.asic_db.get_keys(self.ASIC_QOS_MAP_STR)
383+
self.asic_qos_map_count = len(self.asic_qos_map_ids)
384+
self.dscp_to_tc_table = swsscommon.Table(self.config_db.db_connection, swsscommon.CFG_DSCP_TO_TC_MAP_TABLE_NAME)
385+
self.port_qos_table = swsscommon.Table(self.config_db.db_connection, swsscommon.CFG_PORT_QOS_MAP_TABLE_NAME)
386+
387+
def get_qos_id(self):
388+
diff = set(self.asic_db.get_keys(self.ASIC_QOS_MAP_STR)) - set(self.asic_qos_map_ids)
389+
assert len(diff) <= 1
390+
return None if len(diff) == 0 else diff.pop()
391+
392+
def test_dscp_to_tc_map_applied_to_switch(self, dvs):
393+
self.init_test(dvs)
394+
dscp_to_tc_map_id = None
395+
created_new_map = False
396+
try:
397+
existing_map = self.dscp_to_tc_table.getKeys()
398+
if "AZURE" not in existing_map:
399+
# Create a DSCP_TO_TC map
400+
dscp_to_tc_map = [(str(i), str(i)) for i in range(0, 63)]
401+
self.dscp_to_tc_table.set("AZURE", swsscommon.FieldValuePairs(dscp_to_tc_map))
402+
403+
self.asic_db.wait_for_n_keys(self.ASIC_QOS_MAP_STR, self.asic_qos_map_count + 1)
404+
405+
# Get the DSCP_TO_TC map ID
406+
dscp_to_tc_map_id = self.get_qos_id()
407+
assert(dscp_to_tc_map_id is not None)
408+
409+
# Assert the expected values
410+
fvs = self.asic_db.get_entry(self.ASIC_QOS_MAP_STR, dscp_to_tc_map_id)
411+
assert(fvs.get("SAI_QOS_MAP_ATTR_TYPE") == "SAI_QOS_MAP_TYPE_DSCP_TO_TC")
412+
created_new_map = True
413+
else:
414+
for id in self.asic_qos_map_ids:
415+
fvs = self.asic_db.get_entry(self.ASIC_QOS_MAP_STR, id)
416+
if fvs.get("SAI_QOS_MAP_ATTR_TYPE") == "SAI_QOS_MAP_TYPE_DSCP_TO_TC":
417+
dscp_to_tc_map_id = id
418+
break
419+
switch_oid = dvs.getSwitchOid()
420+
# Check switch level DSCP_TO_TC_MAP doesn't before PORT_QOS_MAP|global is created
421+
fvs = self.asic_db.get_entry(self.ASIC_SWITCH_STR, switch_oid)
422+
assert("SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP" not in fvs)
423+
424+
# Insert switch level map entry
425+
self.port_qos_table.set("global", [("dscp_to_tc_map", "AZURE")])
426+
time.sleep(1)
427+
428+
# Check the switch level DSCP_TO_TC_MAP is applied
429+
fvs = self.asic_db.get_entry(self.ASIC_SWITCH_STR, switch_oid)
430+
assert(fvs.get("SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP") == dscp_to_tc_map_id)
431+
432+
# Remove the global level DSCP_TO_TC_MAP
433+
self.port_qos_table._del("global")
434+
time.sleep(1)
435+
436+
# Check the global level DSCP_TO_TC_MAP is set to SAI_
437+
fvs = self.asic_db.get_entry(self.ASIC_SWITCH_STR, switch_oid)
438+
assert(fvs.get("SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP") == "oid:0x0")
439+
finally:
440+
if created_new_map:
441+
self.dscp_to_tc_table._del("AZURE")
442+
373443

374444
# Add Dummy always-pass test at end as workaroud
375445
# for issue when Flaky fail on final test it invokes module tear-down before retrying

0 commit comments

Comments
 (0)