Skip to content

Commit b83b287

Browse files
raphaelt-nvidiavolodymyrsamotiy
authored andcommitted
[202106_rc_2_20211019] Orchagent validates mirror session queue parameter against maximum value from SAI (sonic-net#1957)
Signed-off-by: Raphael Tryster <[email protected]>
1 parent 08b05db commit b83b287

File tree

3 files changed

+77
-1
lines changed

3 files changed

+77
-1
lines changed

orchagent/mirrororch.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
#define MIRROR_SESSION_DSCP_MIN 0
4040
#define MIRROR_SESSION_DSCP_MAX 63
4141

42+
// 15 is a typical value, but if vendor's SAI does not supply the maximum value,
43+
// allow all 8-bit numbers, effectively cancelling validation by orchagent.
44+
#define MIRROR_SESSION_DEFAULT_NUM_TC 255
45+
46+
extern sai_switch_api_t *sai_switch_api;
4247
extern sai_mirror_api_t *sai_mirror_api;
4348
extern sai_port_api_t *sai_port_api;
4449

@@ -80,9 +85,26 @@ MirrorOrch::MirrorOrch(TableConnector stateDbConnector, TableConnector confDbCon
8085
m_policerOrch(policerOrch),
8186
m_mirrorTable(stateDbConnector.first, stateDbConnector.second)
8287
{
88+
sai_status_t status;
89+
sai_attribute_t attr;
90+
8391
m_portsOrch->attach(this);
8492
m_neighOrch->attach(this);
8593
m_fdbOrch->attach(this);
94+
95+
// Retrieve the number of valid values for queue, starting at 0
96+
attr.id = SAI_SWITCH_ATTR_QOS_MAX_NUMBER_OF_TRAFFIC_CLASSES;
97+
status = sai_switch_api->get_switch_attribute(gSwitchId, 1, &attr);
98+
if (status != SAI_STATUS_SUCCESS)
99+
{
100+
SWSS_LOG_WARN("Failed to get switch attribute number of traffic classes. \
101+
Use default value. rv:%d", status);
102+
m_maxNumTC = MIRROR_SESSION_DEFAULT_NUM_TC;
103+
}
104+
else
105+
{
106+
m_maxNumTC = attr.value.u8;
107+
}
86108
}
87109

88110
bool MirrorOrch::bake()
@@ -373,6 +395,11 @@ task_process_status MirrorOrch::createEntry(const string& key, const vector<Fiel
373395
else if (fvField(i) == MIRROR_SESSION_QUEUE)
374396
{
375397
entry.queue = to_uint<uint8_t>(fvValue(i));
398+
if (entry.queue >= m_maxNumTC)
399+
{
400+
SWSS_LOG_ERROR("Failed to get valid queue %s", fvValue(i).c_str());
401+
return task_process_status::task_invalid_entry;
402+
}
376403
}
377404
else if (fvField(i) == MIRROR_SESSION_POLICER)
378405
{

orchagent/mirrororch.h

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ class MirrorOrch : public Orch, public Observer, public Subject
9595
NeighOrch *m_neighOrch;
9696
FdbOrch *m_fdbOrch;
9797
PolicerOrch *m_policerOrch;
98+
// Maximum number of traffic classes starting at 0, thus queue can be 0 - m_maxNumTC-1
99+
uint8_t m_maxNumTC;
98100

99101
Table m_mirrorTable;
100102

tests/test_mirror_port_span.py

+48-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,54 @@
77
@pytest.mark.usefixtures('dvs_mirror_manager')
88
@pytest.mark.usefixtures('dvs_policer_manager')
99
class TestMirror(object):
10+
11+
def check_syslog(self, dvs, marker, log, expected_cnt):
12+
(ec, out) = dvs.runcmd(['sh', '-c', "awk \'/%s/,ENDFILE {print;}\' /var/log/syslog | grep \'%s\' | wc -l" % (marker, log)])
13+
assert out.strip() == str(expected_cnt)
14+
15+
16+
def test_PortMirrorQueue(self, dvs, testlog):
17+
"""
18+
This test covers valid and invalid values of the queue parameter. All sessions have source & dest port.
19+
Operation flow:
20+
1. Create mirror session with queue 0, verify session becomes active and error not written to log.
21+
2. Create mirror session with queue max valid value, verify session becomes active and error not written to log.
22+
3. Create mirror session with queue max valid value + 1, verify session doesnt get created and error written to log.
23+
Due to lag in table operations, verify_no_mirror is necessary at the end of each step, to ensure cleanup before next step.
24+
Note that since orchagent caches max valid value during initialization, this test cannot simulate a value from SAI, e.g.
25+
by calling setReadOnlyAttr, because orchagent has already completed initialization and would never read the simulated value.
26+
Therefore, the default value must be used, MIRROR_SESSION_DEFAULT_NUM_TC which is defined in mirrororch.cpp as 255.
27+
"""
28+
29+
session = "TEST_SESSION"
30+
dst_port = "Ethernet16"
31+
src_ports = "Ethernet12"
32+
33+
# Sub Test 1
34+
marker = dvs.add_log_marker()
35+
self.dvs_mirror.create_span_session(session, dst_port, src_ports, direction="BOTH", queue="0")
36+
self.dvs_mirror.verify_session_status(session)
37+
self.dvs_mirror.remove_mirror_session(session)
38+
self.dvs_mirror.verify_no_mirror()
39+
self.check_syslog(dvs, marker, "Failed to get valid queue 0", 0)
40+
41+
# Sub Test 2
42+
marker = dvs.add_log_marker()
43+
self.dvs_mirror.create_span_session(session, dst_port, src_ports, direction="RX", queue="254")
44+
self.dvs_mirror.verify_session_status(session)
45+
self.dvs_mirror.remove_mirror_session(session)
46+
self.dvs_mirror.verify_no_mirror()
47+
self.check_syslog(dvs, marker, "Failed to get valid queue 254", 0)
48+
49+
# Sub Test 3
50+
marker = dvs.add_log_marker()
51+
self.dvs_mirror.create_span_session(session, dst_port, src_ports, direction="TX", queue="255")
52+
self.dvs_mirror.verify_session_status(session, expected=0)
53+
self.dvs_mirror.remove_mirror_session(session)
54+
self.dvs_mirror.verify_no_mirror()
55+
self.check_syslog(dvs, marker, "Failed to get valid queue 255", 1)
56+
57+
1058
def test_PortMirrorAddRemove(self, dvs, testlog):
1159
"""
1260
This test covers the basic SPAN mirror session creation and removal operations
@@ -471,7 +519,6 @@ def test_PortLAGMirrorUpdateLAG(self, dvs, testlog):
471519
self.dvs_vlan.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_LAG", 0)
472520

473521

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

0 commit comments

Comments
 (0)