Skip to content

Commit

Permalink
[qos] Add EXP to TC map support (#1954)
Browse files Browse the repository at this point in the history
* [Mpls/qos] Add EXP to TC map support
  • Loading branch information
TACappleman authored Nov 5, 2021
1 parent c91a7f2 commit e14a071
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 8 deletions.
20 changes: 20 additions & 0 deletions doc/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,26 @@ instance is supported in SONiC.
```


### MPLS_TC_TO_TC_MAP
```
{
"MPLS_TC_TO_TC_MAP": {
"AZURE": {
"0": "0",
"1": "1",
"2": "1",
"3": "2",
"4": "2",
"5": "3",
"6": "3",
"7": "4"
}
}
}
```

### FLEX_COUNTER_TABLE

```
Expand Down
25 changes: 25 additions & 0 deletions doc/swss-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,16 @@ Stores information for physical switch ports managed by the switch chip. Ports t
;QOS Mappings
map_dscp_to_tc = ref_hash_key_reference
map_tc_to_queue = ref_hash_key_reference
map_mpls_tc_to_tc = ref_hash_key_reference

Example:
127.0.0.1:6379> hgetall PORT_TABLE:ETHERNET4
1) "dscp_to_tc_map"
2) "AZURE"
3) "tc_to_queue_map"
4) "AZURE"
5) "mpls_tc_to_tc_map"
6) "AZURE"

---------------------------------------------
### INTF_TABLE
Expand Down Expand Up @@ -279,6 +282,28 @@ and reflects the LAG ports into the redis under: `LAG_TABLE:<team0>:port`
9) "9"
10) "8"

---------------------------------------------
### MPLS\_TC\_TO\_TC\_MAP\_TABLE
; MPLS TC to TC map
;SAI mapping - qos_map object with SAI_QOS_MAP_ATTR_TYPE == sai_qos_map_type_t::SAI_QOS_MAP_EXP_TO_TC
key = "MPLS_TC_TO_TC_MAP_TABLE:"name
;field value
mpls_tc_value = 1*DIGIT
tc_value = 1*DIGIT

Example:
127.0.0.1:6379> hgetall "MPLS_TC_TO_TC_MAP_TABLE:AZURE"
1) "0" ;mpls_tc
2) "3" ;tc
3) "1"
4) "5"
5) "2"
6) "5"
7) "3"
8) "7"
9) "4"
10) "8"

---------------------------------------------
### SCHEDULER_TABLE
; Scheduler table
Expand Down
1 change: 1 addition & 0 deletions orchagent/orchdaemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ bool OrchDaemon::init()
CFG_TC_TO_QUEUE_MAP_TABLE_NAME,
CFG_SCHEDULER_TABLE_NAME,
CFG_DSCP_TO_TC_MAP_TABLE_NAME,
CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME,
CFG_DOT1P_TO_TC_MAP_TABLE_NAME,
CFG_QUEUE_TABLE_NAME,
CFG_PORT_QOS_MAP_TABLE_NAME,
Expand Down
59 changes: 59 additions & 0 deletions orchagent/qosorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum {
// field_name is what is expected in CONFIG_DB PORT_QOS_MAP table
map<string, sai_port_attr_t> qos_to_attr_map = {
{dscp_to_tc_field_name, SAI_PORT_ATTR_QOS_DSCP_TO_TC_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_pg_map_field_name, SAI_PORT_ATTR_QOS_TC_TO_PRIORITY_GROUP_MAP},
Expand All @@ -60,6 +61,7 @@ map<string, sai_meter_type_t> scheduler_meter_map = {

type_map QosOrch::m_qos_maps = {
{CFG_DSCP_TO_TC_MAP_TABLE_NAME, new object_reference_map()},
{CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME, new object_reference_map()},
{CFG_DOT1P_TO_TC_MAP_TABLE_NAME, new object_reference_map()},
{CFG_TC_TO_QUEUE_MAP_TABLE_NAME, new object_reference_map()},
{CFG_SCHEDULER_TABLE_NAME, new object_reference_map()},
Expand All @@ -73,6 +75,7 @@ type_map QosOrch::m_qos_maps = {

map<string, string> qos_to_ref_table_map = {
{dscp_to_tc_field_name, CFG_DSCP_TO_TC_MAP_TABLE_NAME},
{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_pg_map_field_name, CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME},
Expand Down Expand Up @@ -238,6 +241,61 @@ task_process_status QosOrch::handleDscpToTcTable(Consumer& consumer)
return dscp_tc_handler.processWorkItem(consumer);
}

bool MplsTcToTcMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector<sai_attribute_t> &attributes)
{
SWSS_LOG_ENTER();
sai_attribute_t list_attr;
sai_qos_map_list_t exp_map_list;
exp_map_list.count = (uint32_t)kfvFieldsValues(tuple).size();
exp_map_list.list = new sai_qos_map_t[exp_map_list.count]();
uint32_t ind = 0;
for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++, ind++)
{
exp_map_list.list[ind].key.mpls_exp = (uint8_t)stoi(fvField(*i));
exp_map_list.list[ind].value.tc = (uint8_t)stoi(fvValue(*i));
SWSS_LOG_DEBUG("key.exp:%d, value.tc:%d", exp_map_list.list[ind].key.mpls_exp, exp_map_list.list[ind].value.tc);
}
list_attr.id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST;
list_attr.value.qosmap.count = exp_map_list.count;
list_attr.value.qosmap.list = exp_map_list.list;
attributes.push_back(list_attr);
return true;
}

sai_object_id_t MplsTcToTcMapHandler::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.u32 = SAI_QOS_MAP_TYPE_MPLS_EXP_TO_TC;
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 exp_to_tc map. status:%d", sai_status);
return SAI_NULL_OBJECT_ID;
}
SWSS_LOG_DEBUG("created QosMap object:%" PRIx64, sai_object);
return sai_object;
}

task_process_status QosOrch::handleMplsTcToTcTable(Consumer& consumer)
{
SWSS_LOG_ENTER();
MplsTcToTcMapHandler mpls_tc_to_tc_handler;
return mpls_tc_to_tc_handler.processWorkItem(consumer);
}

bool Dot1pToTcMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector<sai_attribute_t> &attributes)
{
SWSS_LOG_ENTER();
Expand Down Expand Up @@ -760,6 +818,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_MPLS_TC_TO_TC_MAP_TABLE_NAME, &QosOrch::handleMplsTcToTcTable));
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));
Expand Down
9 changes: 9 additions & 0 deletions orchagent/qosorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "portsorch.h"

const string dscp_to_tc_field_name = "dscp_to_tc_map";
const string mpls_tc_to_tc_field_name = "mpls_tc_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";
Expand Down Expand Up @@ -70,6 +71,13 @@ class DscpToTcMapHandler : public QosMapHandler
sai_object_id_t addQosItem(const vector<sai_attribute_t> &attributes) override;
};

class MplsTcToTcMapHandler : 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;
};

class Dot1pToTcMapHandler : public QosMapHandler
{
public:
Expand Down Expand Up @@ -137,6 +145,7 @@ class QosOrch : public Orch
void initTableHandlers();

task_process_status handleDscpToTcTable(Consumer& consumer);
task_process_status handleMplsTcToTcTable(Consumer& consumer);
task_process_status handleDot1pToTcTable(Consumer& consumer);
task_process_status handlePfcPrioToPgTable(Consumer& consumer);
task_process_status handlePfcToQueueTable(Consumer& consumer);
Expand Down
107 changes: 99 additions & 8 deletions tests/test_qos_map.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import pytest
import json
import sys
import time

from swsscommon import swsscommon
Expand All @@ -18,8 +16,22 @@
"7": "7",
}

CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME = "MPLS_TC_TO_TC_MAP"
CFG_MPLS_TC_TO_TC_MAP_KEY = "AZURE_MPLS_TC"
MPLS_TC_TO_TC_MAP = {
"0": "0",
"1": "4",
"2": "1",
"3": "3",
"4": "5",
"5": "2",
"6": "7",
"7": "6",
}

CFG_PORT_QOS_MAP_TABLE_NAME = "PORT_QOS_MAP"
CFG_PORT_QOS_MAP_FIELD = "dot1p_to_tc_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_TABLE_NAME = "PORT"


Expand All @@ -39,7 +51,6 @@ def create_dot1p_profile(self):
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:
Expand All @@ -50,7 +61,6 @@ def find_dot1p_profile(self):
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:
Expand All @@ -63,7 +73,7 @@ def find_dot1p_profile(self):

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_KEY)])
fvs = swsscommon.FieldValuePairs([(CFG_PORT_QOS_DOT1P_MAP_FIELD, 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)
Expand All @@ -74,7 +84,7 @@ def apply_dot1p_profile_on_all_ports(self):
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_raw = self.find_dot1p_profile()

dot1p_tc_map = json.loads(dot1p_tc_map_raw);
for dot1p2tc in dot1p_tc_map['list']:
Expand All @@ -86,7 +96,7 @@ def test_dot1p_cfg(self, dvs):
def test_port_dot1p(self, dvs):
self.connect_dbs(dvs)
self.create_dot1p_profile()
oid, dot1p_tc_map_raw = self.find_dot1p_profile()
oid, _ = self.find_dot1p_profile()

self.apply_dot1p_profile_on_all_ports()

Expand All @@ -106,6 +116,87 @@ def test_port_dot1p(self, dvs):
assert port_cnt == cnt


class TestMplsTc(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_mpls_tc_profile(self):
tbl = swsscommon.Table(self.config_db, CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME)
fvs = swsscommon.FieldValuePairs(list(MPLS_TC_TO_TC_MAP.items()))
tbl.set(CFG_MPLS_TC_TO_TC_MAP_KEY, fvs)
time.sleep(1)


def find_mpls_tc_profile(self):
found = False
mpls_tc_tc_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":
mpls_tc_tc_map_raw = fv[1]
elif fv[0] == "SAI_QOS_MAP_ATTR_TYPE" and fv[1] == "SAI_QOS_MAP_TYPE_MPLS_EXP_TO_TC":
found = True

if found:
break

assert found == True

return (key, mpls_tc_tc_map_raw)


def apply_mpls_tc_profile_on_all_ports(self):
tbl = swsscommon.Table(self.config_db, CFG_PORT_QOS_MAP_TABLE_NAME)
fvs = swsscommon.FieldValuePairs([(CFG_PORT_QOS_MPLS_TC_MAP_FIELD, CFG_MPLS_TC_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_mpls_tc_cfg(self, dvs):
self.connect_dbs(dvs)
self.create_mpls_tc_profile()
_, mpls_tc_tc_map_raw = self.find_mpls_tc_profile()

mpls_tc_tc_map = json.loads(mpls_tc_tc_map_raw)
for mplstc2tc in mpls_tc_tc_map['list']:
mpls_tc = str(mplstc2tc['key']['mpls_exp'])
tc = str(mplstc2tc['value']['tc'])
assert tc == MPLS_TC_TO_TC_MAP[mpls_tc]


def test_port_mpls_tc(self, dvs):
self.connect_dbs(dvs)
self.create_mpls_tc_profile()
oid, _ = self.find_mpls_tc_profile()

self.apply_mpls_tc_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_MPLS_EXP_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


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

0 comments on commit e14a071

Please sign in to comment.