Skip to content

Commit e14a071

Browse files
authored
[qos] Add EXP to TC map support (#1954)
* [Mpls/qos] Add EXP to TC map support
1 parent c91a7f2 commit e14a071

File tree

6 files changed

+213
-8
lines changed

6 files changed

+213
-8
lines changed

doc/Configuration.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,26 @@ instance is supported in SONiC.
742742
743743
```
744744

745+
746+
### MPLS_TC_TO_TC_MAP
747+
```
748+
{
749+
"MPLS_TC_TO_TC_MAP": {
750+
"AZURE": {
751+
"0": "0",
752+
"1": "1",
753+
"2": "1",
754+
"3": "2",
755+
"4": "2",
756+
"5": "3",
757+
"6": "3",
758+
"7": "4"
759+
}
760+
}
761+
}
762+
763+
```
764+
745765
### FLEX_COUNTER_TABLE
746766

747767
```

doc/swss-schema.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,16 @@ Stores information for physical switch ports managed by the switch chip. Ports t
3131
;QOS Mappings
3232
map_dscp_to_tc = ref_hash_key_reference
3333
map_tc_to_queue = ref_hash_key_reference
34+
map_mpls_tc_to_tc = ref_hash_key_reference
3435

3536
Example:
3637
127.0.0.1:6379> hgetall PORT_TABLE:ETHERNET4
3738
1) "dscp_to_tc_map"
3839
2) "AZURE"
3940
3) "tc_to_queue_map"
4041
4) "AZURE"
42+
5) "mpls_tc_to_tc_map"
43+
6) "AZURE"
4144

4245
---------------------------------------------
4346
### INTF_TABLE
@@ -279,6 +282,28 @@ and reflects the LAG ports into the redis under: `LAG_TABLE:<team0>:port`
279282
9) "9"
280283
10) "8"
281284

285+
---------------------------------------------
286+
### MPLS\_TC\_TO\_TC\_MAP\_TABLE
287+
; MPLS TC to TC map
288+
;SAI mapping - qos_map object with SAI_QOS_MAP_ATTR_TYPE == sai_qos_map_type_t::SAI_QOS_MAP_EXP_TO_TC
289+
key = "MPLS_TC_TO_TC_MAP_TABLE:"name
290+
;field value
291+
mpls_tc_value = 1*DIGIT
292+
tc_value = 1*DIGIT
293+
294+
Example:
295+
127.0.0.1:6379> hgetall "MPLS_TC_TO_TC_MAP_TABLE:AZURE"
296+
1) "0" ;mpls_tc
297+
2) "3" ;tc
298+
3) "1"
299+
4) "5"
300+
5) "2"
301+
6) "5"
302+
7) "3"
303+
8) "7"
304+
9) "4"
305+
10) "8"
306+
282307
---------------------------------------------
283308
### SCHEDULER_TABLE
284309
; Scheduler table

orchagent/orchdaemon.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ bool OrchDaemon::init()
186186
CFG_TC_TO_QUEUE_MAP_TABLE_NAME,
187187
CFG_SCHEDULER_TABLE_NAME,
188188
CFG_DSCP_TO_TC_MAP_TABLE_NAME,
189+
CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME,
189190
CFG_DOT1P_TO_TC_MAP_TABLE_NAME,
190191
CFG_QUEUE_TABLE_NAME,
191192
CFG_PORT_QOS_MAP_TABLE_NAME,

orchagent/qosorch.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ enum {
4545
// field_name is what is expected in CONFIG_DB PORT_QOS_MAP table
4646
map<string, sai_port_attr_t> qos_to_attr_map = {
4747
{dscp_to_tc_field_name, SAI_PORT_ATTR_QOS_DSCP_TO_TC_MAP},
48+
{mpls_tc_to_tc_field_name, SAI_PORT_ATTR_QOS_MPLS_EXP_TO_TC_MAP},
4849
{dot1p_to_tc_field_name, SAI_PORT_ATTR_QOS_DOT1P_TO_TC_MAP},
4950
{tc_to_queue_field_name, SAI_PORT_ATTR_QOS_TC_TO_QUEUE_MAP},
5051
{tc_to_pg_map_field_name, SAI_PORT_ATTR_QOS_TC_TO_PRIORITY_GROUP_MAP},
@@ -60,6 +61,7 @@ map<string, sai_meter_type_t> scheduler_meter_map = {
6061

6162
type_map QosOrch::m_qos_maps = {
6263
{CFG_DSCP_TO_TC_MAP_TABLE_NAME, new object_reference_map()},
64+
{CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME, new object_reference_map()},
6365
{CFG_DOT1P_TO_TC_MAP_TABLE_NAME, new object_reference_map()},
6466
{CFG_TC_TO_QUEUE_MAP_TABLE_NAME, new object_reference_map()},
6567
{CFG_SCHEDULER_TABLE_NAME, new object_reference_map()},
@@ -73,6 +75,7 @@ type_map QosOrch::m_qos_maps = {
7375

7476
map<string, string> qos_to_ref_table_map = {
7577
{dscp_to_tc_field_name, CFG_DSCP_TO_TC_MAP_TABLE_NAME},
78+
{mpls_tc_to_tc_field_name, CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME},
7679
{dot1p_to_tc_field_name, CFG_DOT1P_TO_TC_MAP_TABLE_NAME},
7780
{tc_to_queue_field_name, CFG_TC_TO_QUEUE_MAP_TABLE_NAME},
7881
{tc_to_pg_map_field_name, CFG_TC_TO_PRIORITY_GROUP_MAP_TABLE_NAME},
@@ -238,6 +241,61 @@ task_process_status QosOrch::handleDscpToTcTable(Consumer& consumer)
238241
return dscp_tc_handler.processWorkItem(consumer);
239242
}
240243

244+
bool MplsTcToTcMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector<sai_attribute_t> &attributes)
245+
{
246+
SWSS_LOG_ENTER();
247+
sai_attribute_t list_attr;
248+
sai_qos_map_list_t exp_map_list;
249+
exp_map_list.count = (uint32_t)kfvFieldsValues(tuple).size();
250+
exp_map_list.list = new sai_qos_map_t[exp_map_list.count]();
251+
uint32_t ind = 0;
252+
for (auto i = kfvFieldsValues(tuple).begin(); i != kfvFieldsValues(tuple).end(); i++, ind++)
253+
{
254+
exp_map_list.list[ind].key.mpls_exp = (uint8_t)stoi(fvField(*i));
255+
exp_map_list.list[ind].value.tc = (uint8_t)stoi(fvValue(*i));
256+
SWSS_LOG_DEBUG("key.exp:%d, value.tc:%d", exp_map_list.list[ind].key.mpls_exp, exp_map_list.list[ind].value.tc);
257+
}
258+
list_attr.id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST;
259+
list_attr.value.qosmap.count = exp_map_list.count;
260+
list_attr.value.qosmap.list = exp_map_list.list;
261+
attributes.push_back(list_attr);
262+
return true;
263+
}
264+
265+
sai_object_id_t MplsTcToTcMapHandler::addQosItem(const vector<sai_attribute_t> &attributes)
266+
{
267+
SWSS_LOG_ENTER();
268+
sai_status_t sai_status;
269+
sai_object_id_t sai_object;
270+
vector<sai_attribute_t> qos_map_attrs;
271+
272+
sai_attribute_t qos_map_attr;
273+
qos_map_attr.id = SAI_QOS_MAP_ATTR_TYPE;
274+
qos_map_attr.value.u32 = SAI_QOS_MAP_TYPE_MPLS_EXP_TO_TC;
275+
qos_map_attrs.push_back(qos_map_attr);
276+
277+
qos_map_attr.id = SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST;
278+
qos_map_attr.value.qosmap.count = attributes[0].value.qosmap.count;
279+
qos_map_attr.value.qosmap.list = attributes[0].value.qosmap.list;
280+
qos_map_attrs.push_back(qos_map_attr);
281+
282+
sai_status = sai_qos_map_api->create_qos_map(&sai_object, gSwitchId, (uint32_t)qos_map_attrs.size(), qos_map_attrs.data());
283+
if (SAI_STATUS_SUCCESS != sai_status)
284+
{
285+
SWSS_LOG_ERROR("Failed to create exp_to_tc map. status:%d", sai_status);
286+
return SAI_NULL_OBJECT_ID;
287+
}
288+
SWSS_LOG_DEBUG("created QosMap object:%" PRIx64, sai_object);
289+
return sai_object;
290+
}
291+
292+
task_process_status QosOrch::handleMplsTcToTcTable(Consumer& consumer)
293+
{
294+
SWSS_LOG_ENTER();
295+
MplsTcToTcMapHandler mpls_tc_to_tc_handler;
296+
return mpls_tc_to_tc_handler.processWorkItem(consumer);
297+
}
298+
241299
bool Dot1pToTcMapHandler::convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector<sai_attribute_t> &attributes)
242300
{
243301
SWSS_LOG_ENTER();
@@ -760,6 +818,7 @@ void QosOrch::initTableHandlers()
760818
{
761819
SWSS_LOG_ENTER();
762820
m_qos_handler_map.insert(qos_handler_pair(CFG_DSCP_TO_TC_MAP_TABLE_NAME, &QosOrch::handleDscpToTcTable));
821+
m_qos_handler_map.insert(qos_handler_pair(CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME, &QosOrch::handleMplsTcToTcTable));
763822
m_qos_handler_map.insert(qos_handler_pair(CFG_DOT1P_TO_TC_MAP_TABLE_NAME, &QosOrch::handleDot1pToTcTable));
764823
m_qos_handler_map.insert(qos_handler_pair(CFG_TC_TO_QUEUE_MAP_TABLE_NAME, &QosOrch::handleTcToQueueTable));
765824
m_qos_handler_map.insert(qos_handler_pair(CFG_SCHEDULER_TABLE_NAME, &QosOrch::handleSchedulerTable));

orchagent/qosorch.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "portsorch.h"
99

1010
const string dscp_to_tc_field_name = "dscp_to_tc_map";
11+
const string mpls_tc_to_tc_field_name = "mpls_tc_to_tc_map";
1112
const string dot1p_to_tc_field_name = "dot1p_to_tc_map";
1213
const string pfc_to_pg_map_name = "pfc_to_pg_map";
1314
const string pfc_to_queue_map_name = "pfc_to_queue_map";
@@ -70,6 +71,13 @@ class DscpToTcMapHandler : public QosMapHandler
7071
sai_object_id_t addQosItem(const vector<sai_attribute_t> &attributes) override;
7172
};
7273

74+
class MplsTcToTcMapHandler : public QosMapHandler
75+
{
76+
public:
77+
bool convertFieldValuesToAttributes(KeyOpFieldsValuesTuple &tuple, vector<sai_attribute_t> &attributes) override;
78+
sai_object_id_t addQosItem(const vector<sai_attribute_t> &attributes) override;
79+
};
80+
7381
class Dot1pToTcMapHandler : public QosMapHandler
7482
{
7583
public:
@@ -137,6 +145,7 @@ class QosOrch : public Orch
137145
void initTableHandlers();
138146

139147
task_process_status handleDscpToTcTable(Consumer& consumer);
148+
task_process_status handleMplsTcToTcTable(Consumer& consumer);
140149
task_process_status handleDot1pToTcTable(Consumer& consumer);
141150
task_process_status handlePfcPrioToPgTable(Consumer& consumer);
142151
task_process_status handlePfcToQueueTable(Consumer& consumer);

tests/test_qos_map.py

Lines changed: 99 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import pytest
21
import json
3-
import sys
42
import time
53

64
from swsscommon import swsscommon
@@ -18,8 +16,22 @@
1816
"7": "7",
1917
}
2018

19+
CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME = "MPLS_TC_TO_TC_MAP"
20+
CFG_MPLS_TC_TO_TC_MAP_KEY = "AZURE_MPLS_TC"
21+
MPLS_TC_TO_TC_MAP = {
22+
"0": "0",
23+
"1": "4",
24+
"2": "1",
25+
"3": "3",
26+
"4": "5",
27+
"5": "2",
28+
"6": "7",
29+
"7": "6",
30+
}
31+
2132
CFG_PORT_QOS_MAP_TABLE_NAME = "PORT_QOS_MAP"
22-
CFG_PORT_QOS_MAP_FIELD = "dot1p_to_tc_map"
33+
CFG_PORT_QOS_DOT1P_MAP_FIELD = "dot1p_to_tc_map"
34+
CFG_PORT_QOS_MPLS_TC_MAP_FIELD = "mpls_tc_to_tc_map"
2335
CFG_PORT_TABLE_NAME = "PORT"
2436

2537

@@ -39,7 +51,6 @@ def create_dot1p_profile(self):
3951
def find_dot1p_profile(self):
4052
found = False
4153
dot1p_tc_map_raw = None
42-
dot1p_tc_map_key = None
4354
tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_QOS_MAP")
4455
keys = tbl.getKeys()
4556
for key in keys:
@@ -50,7 +61,6 @@ def find_dot1p_profile(self):
5061
if fv[0] == "SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST":
5162
dot1p_tc_map_raw = fv[1]
5263
elif fv[0] == "SAI_QOS_MAP_ATTR_TYPE" and fv[1] == "SAI_QOS_MAP_TYPE_DOT1P_TO_TC":
53-
dot1p_tc_map_key = key
5464
found = True
5565

5666
if found:
@@ -63,7 +73,7 @@ def find_dot1p_profile(self):
6373

6474
def apply_dot1p_profile_on_all_ports(self):
6575
tbl = swsscommon.Table(self.config_db, CFG_PORT_QOS_MAP_TABLE_NAME)
66-
fvs = swsscommon.FieldValuePairs([(CFG_PORT_QOS_MAP_FIELD, CFG_DOT1P_TO_TC_MAP_KEY)])
76+
fvs = swsscommon.FieldValuePairs([(CFG_PORT_QOS_DOT1P_MAP_FIELD, CFG_DOT1P_TO_TC_MAP_KEY)])
6777
ports = swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys()
6878
for port in ports:
6979
tbl.set(port, fvs)
@@ -74,7 +84,7 @@ def apply_dot1p_profile_on_all_ports(self):
7484
def test_dot1p_cfg(self, dvs):
7585
self.connect_dbs(dvs)
7686
self.create_dot1p_profile()
77-
oid, dot1p_tc_map_raw = self.find_dot1p_profile()
87+
_, dot1p_tc_map_raw = self.find_dot1p_profile()
7888

7989
dot1p_tc_map = json.loads(dot1p_tc_map_raw);
8090
for dot1p2tc in dot1p_tc_map['list']:
@@ -86,7 +96,7 @@ def test_dot1p_cfg(self, dvs):
8696
def test_port_dot1p(self, dvs):
8797
self.connect_dbs(dvs)
8898
self.create_dot1p_profile()
89-
oid, dot1p_tc_map_raw = self.find_dot1p_profile()
99+
oid, _ = self.find_dot1p_profile()
90100

91101
self.apply_dot1p_profile_on_all_ports()
92102

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

108118

119+
class TestMplsTc(object):
120+
def connect_dbs(self, dvs):
121+
self.asic_db = swsscommon.DBConnector(1, dvs.redis_sock, 0)
122+
self.config_db = swsscommon.DBConnector(4, dvs.redis_sock, 0)
123+
124+
125+
def create_mpls_tc_profile(self):
126+
tbl = swsscommon.Table(self.config_db, CFG_MPLS_TC_TO_TC_MAP_TABLE_NAME)
127+
fvs = swsscommon.FieldValuePairs(list(MPLS_TC_TO_TC_MAP.items()))
128+
tbl.set(CFG_MPLS_TC_TO_TC_MAP_KEY, fvs)
129+
time.sleep(1)
130+
131+
132+
def find_mpls_tc_profile(self):
133+
found = False
134+
mpls_tc_tc_map_raw = None
135+
tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_QOS_MAP")
136+
keys = tbl.getKeys()
137+
for key in keys:
138+
(status, fvs) = tbl.get(key)
139+
assert status == True
140+
141+
for fv in fvs:
142+
if fv[0] == "SAI_QOS_MAP_ATTR_MAP_TO_VALUE_LIST":
143+
mpls_tc_tc_map_raw = fv[1]
144+
elif fv[0] == "SAI_QOS_MAP_ATTR_TYPE" and fv[1] == "SAI_QOS_MAP_TYPE_MPLS_EXP_TO_TC":
145+
found = True
146+
147+
if found:
148+
break
149+
150+
assert found == True
151+
152+
return (key, mpls_tc_tc_map_raw)
153+
154+
155+
def apply_mpls_tc_profile_on_all_ports(self):
156+
tbl = swsscommon.Table(self.config_db, CFG_PORT_QOS_MAP_TABLE_NAME)
157+
fvs = swsscommon.FieldValuePairs([(CFG_PORT_QOS_MPLS_TC_MAP_FIELD, CFG_MPLS_TC_TO_TC_MAP_KEY)])
158+
ports = swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys()
159+
for port in ports:
160+
tbl.set(port, fvs)
161+
162+
time.sleep(1)
163+
164+
165+
def test_mpls_tc_cfg(self, dvs):
166+
self.connect_dbs(dvs)
167+
self.create_mpls_tc_profile()
168+
_, mpls_tc_tc_map_raw = self.find_mpls_tc_profile()
169+
170+
mpls_tc_tc_map = json.loads(mpls_tc_tc_map_raw)
171+
for mplstc2tc in mpls_tc_tc_map['list']:
172+
mpls_tc = str(mplstc2tc['key']['mpls_exp'])
173+
tc = str(mplstc2tc['value']['tc'])
174+
assert tc == MPLS_TC_TO_TC_MAP[mpls_tc]
175+
176+
177+
def test_port_mpls_tc(self, dvs):
178+
self.connect_dbs(dvs)
179+
self.create_mpls_tc_profile()
180+
oid, _ = self.find_mpls_tc_profile()
181+
182+
self.apply_mpls_tc_profile_on_all_ports()
183+
184+
cnt = 0
185+
tbl = swsscommon.Table(self.asic_db, "ASIC_STATE:SAI_OBJECT_TYPE_PORT")
186+
keys = tbl.getKeys()
187+
for key in keys:
188+
(status, fvs) = tbl.get(key)
189+
assert status == True
190+
191+
for fv in fvs:
192+
if fv[0] == "SAI_PORT_ATTR_QOS_MPLS_EXP_TO_TC_MAP":
193+
cnt += 1
194+
assert fv[1] == oid
195+
196+
port_cnt = len(swsscommon.Table(self.config_db, CFG_PORT_TABLE_NAME).getKeys())
197+
assert port_cnt == cnt
198+
199+
109200
# Add Dummy always-pass test at end as workaroud
110201
# for issue when Flaky fail on final test it invokes module tear-down before retrying
111202
def test_nonflaky_dummy():

0 commit comments

Comments
 (0)