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

[202012] [cherry-pick] Apply DSCP_TO_TC_MAP from PORT_QOS_MAP|global to switch level #2328

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cfgmgr/buffermgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
using namespace std;
using namespace swss;

#define PORT_NAME_GLOBAL "global"

BufferMgr::BufferMgr(DBConnector *cfgDb, DBConnector *applDb, string pg_lookup_file, const vector<string> &tableNames) :
Orch(cfgDb, tableNames),
m_cfgPortTable(cfgDb, CFG_PORT_TABLE_NAME),
Expand Down Expand Up @@ -455,6 +457,12 @@ void BufferMgr::doPortQosTableTask(Consumer &consumer)
{
KeyOpFieldsValuesTuple tuple = it->second;
string port_name = kfvKey(tuple);
if (port_name == PORT_NAME_GLOBAL)
{
// Ignore the entry for global level
it = consumer.m_toSync.erase(it);
continue;
}
string op = kfvOp(tuple);
if (op == SET_COMMAND)
{
Expand Down
140 changes: 109 additions & 31 deletions orchagent/qosorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ type_map QosOrch::m_qos_maps = {
#define DSCP_MAX_VAL 63
#define EXP_MAX_VAL 7

#define PORT_NAME_GLOBAL "global"

task_process_status QosMapHandler::processWorkItem(Consumer& consumer)
{
SWSS_LOG_ENTER();
Expand Down Expand Up @@ -198,34 +200,6 @@ bool DscpToTcMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &
return true;
}

void DscpToTcMapHandler::applyDscpToTcMapToSwitch(sai_attr_id_t attr_id, sai_object_id_t map_id)
{
SWSS_LOG_ENTER();
bool rv = true;

/* Query DSCP_TO_TC QoS map at switch capability */
rv = gSwitchOrch->querySwitchDscpToTcCapability(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP);
if (rv == false)
{
SWSS_LOG_ERROR("Switch level DSCP to TC QoS map configuration is not supported");
return;
}

/* Apply DSCP_TO_TC QoS map at switch */
sai_attribute_t attr;
attr.id = attr_id;
attr.value.oid = map_id;

sai_status_t status = sai_switch_api->set_switch_attribute(gSwitchId, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("Failed to apply DSCP_TO_TC QoS map to switch rv:%d", status);
return;
}

SWSS_LOG_NOTICE("Applied DSCP_TO_TC QoS map to switch successfully");
}

sai_object_id_t DscpToTcMapHandler::addQosItem(const vector<sai_attribute_t> &attributes)
{
SWSS_LOG_ENTER();
Expand All @@ -249,13 +223,25 @@ sai_object_id_t DscpToTcMapHandler::addQosItem(const vector<sai_attribute_t> &at
SWSS_LOG_ERROR("Failed to create dscp_to_tc map. status:%d", sai_status);
return SAI_NULL_OBJECT_ID;
}
SWSS_LOG_DEBUG("created QosMap object:%" PRIx64, sai_object);

//applyDscpToTcMapToSwitch(SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP, sai_object);
SWSS_LOG_DEBUG("created QosMap object:%" PRIx64, sai_object);

return sai_object;
}

bool DscpToTcMapHandler::removeQosItem(sai_object_id_t sai_object)
{
SWSS_LOG_ENTER();

SWSS_LOG_DEBUG("Removing DscpToTcMap object:%" PRIx64, sai_object);
sai_status_t sai_status = sai_qos_map_api->remove_qos_map(sai_object);
if (SAI_STATUS_SUCCESS != sai_status)
{
SWSS_LOG_ERROR("Failed to remove DSCP_TO_TC map, status:%d", sai_status);
return false;
}
return true;
}

task_process_status QosOrch::handleDscpToTcTable(Consumer& consumer)
{
SWSS_LOG_ENTER();
Expand Down Expand Up @@ -1436,6 +1422,93 @@ task_process_status QosOrch::ResolveMapAndApplyToPort(
return task_process_status::task_success;
}

bool QosOrch::applyDscpToTcMapToSwitch(sai_attr_id_t attr_id, sai_object_id_t map_id)
{
SWSS_LOG_ENTER();

/* Query DSCP_TO_TC QoS map at switch capability */
bool rv = gSwitchOrch->querySwitchDscpToTcCapability(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP);
if (rv == false)
{
SWSS_LOG_ERROR("Switch level DSCP to TC QoS map configuration is not supported");
return true;
}

/* Apply DSCP_TO_TC QoS map at switch */
sai_attribute_t attr;
attr.id = attr_id;
attr.value.oid = map_id;

sai_status_t status = sai_switch_api->set_switch_attribute(gSwitchId, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("Failed to apply DSCP_TO_TC QoS map to switch rv:%d", status);
return false;
}

SWSS_LOG_NOTICE("Applied DSCP_TO_TC QoS map to switch successfully");
return true;
}

task_process_status QosOrch::handleGlobalQosMap(const string &OP, KeyOpFieldsValuesTuple &tuple)
{
SWSS_LOG_ENTER();

task_process_status task_status = task_process_status::task_success;

if (OP == DEL_COMMAND)
{
// Set SAI_NULL_OBJECT_ID to switch level if PORT_QOS_MAP|global is removed
if (applyDscpToTcMapToSwitch(SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP, SAI_NULL_OBJECT_ID))
{
task_status = task_process_status::task_success;
SWSS_LOG_INFO("Global QoS map type %s is removed", dscp_to_tc_field_name.c_str());
}
else
{
task_status = task_process_status::task_failed;
SWSS_LOG_WARN("Failed to remove switch level QoS map type %s", dscp_to_tc_field_name.c_str());
}
return task_status;
}

for (auto it = kfvFieldsValues(tuple).begin(); it != kfvFieldsValues(tuple).end(); it++)
{
string map_type_name = fvField(*it);
string map_name = fvValue(*it);
if (map_type_name != dscp_to_tc_field_name)
{
SWSS_LOG_WARN("Qos map type %s is not supported at global level", map_type_name.c_str());
continue;
}

if (qos_to_attr_map.find(map_type_name) != qos_to_attr_map.end())
{
sai_object_id_t id;
string object_name;
ref_resolve_status status = resolveFieldRefValue(m_qos_maps, map_type_name, tuple, id, object_name);

if (status != ref_resolve_status::success)
{
SWSS_LOG_INFO("Global QoS map %s is not yet created", map_name.c_str());
task_status = task_process_status::task_need_retry;
}

if (applyDscpToTcMapToSwitch(SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP, id))
{
task_status = task_process_status::task_success;
SWSS_LOG_INFO("Applied QoS map type %s name %s to switch level", map_type_name.c_str(), object_name.c_str());
}
else
{
task_status = task_process_status::task_failed;
SWSS_LOG_INFO("Failed to apply QoS map type %s name %s to switch level", map_type_name.c_str(), object_name.c_str());
}
}
}
return task_status;
}

task_process_status QosOrch::handlePortQosMapTable(Consumer& consumer)
{
SWSS_LOG_ENTER();
Expand All @@ -1444,6 +1517,11 @@ task_process_status QosOrch::handlePortQosMapTable(Consumer& consumer)
string key = kfvKey(tuple);
string op = kfvOp(tuple);

if (key == PORT_NAME_GLOBAL)
{
return handleGlobalQosMap(op, tuple);
}

sai_uint8_t pfc_enable = 0;
sai_uint8_t pfcwd_sw_enable = 0;
map<sai_port_attr_t, pair<string, sai_object_id_t>> update_list;
Expand Down
6 changes: 4 additions & 2 deletions orchagent/qosorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ class DscpToTcMapHandler : public QosMapHandler
public:
bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector<sai_attribute_t> &attributes) override;
sai_object_id_t addQosItem(const vector<sai_attribute_t> &attributes) override;
protected:
void applyDscpToTcMapToSwitch(sai_attr_id_t attr_id, sai_object_id_t sai_dscp_to_tc_map);
bool removeQosItem(sai_object_id_t sai_object);
};

class Dot1pToTcMapHandler : public QosMapHandler
Expand Down Expand Up @@ -167,11 +166,14 @@ class QosOrch : public Orch
task_process_status handleWredProfileTable(Consumer& consumer);
task_process_status handleTcToDscpTable(Consumer& consumer);

task_process_status handleGlobalQosMap(const string &op, KeyOpFieldsValuesTuple &tuple);

sai_object_id_t getSchedulerGroup(const Port &port, const sai_object_id_t queue_id);

bool applyMapToPort(Port &port, sai_attr_id_t attr_id, sai_object_id_t sai_dscp_to_tc_map);
bool applySchedulerToQueueSchedulerGroup(Port &port, size_t queue_ind, sai_object_id_t scheduler_profile_id);
bool applyWredProfileToQueue(Port &port, size_t queue_ind, sai_object_id_t sai_wred_profile);
bool applyDscpToTcMapToSwitch(sai_attr_id_t attr_id, sai_object_id_t sai_dscp_to_tc_map);
task_process_status ResolveMapAndApplyToPort(Port &port,sai_port_attr_t port_attr,
string field_name, KeyOpFieldsValuesTuple &tuple, string op);

Expand Down
66 changes: 66 additions & 0 deletions tests/test_qos_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,72 @@ def test_port_dot1p(self, dvs):
port_cnt = len(swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys())
assert port_cnt == cnt

class TestDscpToTcMap(object):
ASIC_QOS_MAP_STR = "ASIC_STATE:SAI_OBJECT_TYPE_QOS_MAP"
ASIC_PORT_STR = "ASIC_STATE:SAI_OBJECT_TYPE_PORT"
ASIC_SWITCH_STR = "ASIC_STATE:SAI_OBJECT_TYPE_SWITCH"

def init_test(self, dvs):
dvs.setup_db()
self.asic_db = dvs.get_asic_db()
self.config_db = dvs.get_config_db()
self.asic_qos_map_ids = self.asic_db.get_keys(self.ASIC_QOS_MAP_STR)
self.asic_qos_map_count = len(self.asic_qos_map_ids)
self.dscp_to_tc_table = swsscommon.Table(self.config_db.db_connection, swsscommon.CFG_DSCP_TO_TC_MAP_TABLE_NAME)
self.port_qos_table = swsscommon.Table(self.config_db.db_connection, swsscommon.CFG_PORT_QOS_MAP_TABLE_NAME)

def get_qos_id(self):
diff = set(self.asic_db.get_keys(self.ASIC_QOS_MAP_STR)) - set(self.asic_qos_map_ids)
assert len(diff) <= 1
return None if len(diff) == 0 else diff.pop()

def test_dscp_to_tc_map_applied_to_switch(self, dvs):
self.init_test(dvs)
dscp_to_tc_map_id = None
created_new_map = False
try:
existing_map = self.dscp_to_tc_table.getKeys()
if "AZURE" not in existing_map:
# Create a DSCP_TO_TC map
dscp_to_tc_map = [(str(i), str(i)) for i in range(0, 63)]
self.dscp_to_tc_table.set("AZURE", swsscommon.FieldValuePairs(dscp_to_tc_map))

self.asic_db.wait_for_n_keys(self.ASIC_QOS_MAP_STR, self.asic_qos_map_count + 1)

# Get the DSCP_TO_TC map ID
dscp_to_tc_map_id = self.get_qos_id()
assert(dscp_to_tc_map_id is not None)

# Assert the expected values
fvs = self.asic_db.get_entry(self.ASIC_QOS_MAP_STR, dscp_to_tc_map_id)
assert(fvs.get("SAI_QOS_MAP_ATTR_TYPE") == "SAI_QOS_MAP_TYPE_DSCP_TO_TC")
created_new_map = True
else:
for id in self.asic_qos_map_ids:
fvs = self.asic_db.get_entry(self.ASIC_QOS_MAP_STR, id)
if fvs.get("SAI_QOS_MAP_ATTR_TYPE") == "SAI_QOS_MAP_TYPE_DSCP_TO_TC":
dscp_to_tc_map_id = id
break
switch_oid = dvs.getSwitchOid()

# Insert switch level map entry
self.port_qos_table.set("global", [("dscp_to_tc_map", "[DSCP_TO_TC_MAP|AZURE]")])
time.sleep(1)

# Check the switch level DSCP_TO_TC_MAP is applied
fvs = self.asic_db.get_entry(self.ASIC_SWITCH_STR, switch_oid)
assert(fvs.get("SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP") == dscp_to_tc_map_id)

# Remove the global level DSCP_TO_TC_MAP
self.port_qos_table._del("global")
time.sleep(1)

# Check the global level DSCP_TO_TC_MAP is set to SAI_
fvs = self.asic_db.get_entry(self.ASIC_SWITCH_STR, switch_oid)
assert(fvs.get("SAI_SWITCH_ATTR_QOS_DSCP_TO_TC_MAP") == "oid:0x0")
finally:
if created_new_map:
self.dscp_to_tc_table._del("AZURE")

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