Skip to content

Commit 620fe95

Browse files
Shuotian Chenglguohan
Shuotian Cheng
authored andcommitted
[aclorch]: Add support for value/mask match for DSCP value (sonic-net#536)
Add the unit test test_mirror.py which currently covers: - ACL mirror table creation - mirror session activation - ACL rule DSCP with/without mask - ACL mirror table removal Signed-off-by: Shu0T1an ChenG <[email protected]>
1 parent b976487 commit 620fe95

File tree

3 files changed

+245
-3
lines changed

3 files changed

+245
-3
lines changed

orchagent/aclorch.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "schema.h"
77
#include "ipprefix.h"
88
#include "converter.h"
9+
#include "tokenize.h"
910
#include "timer.h"
1011
#include "crmorch.h"
1112

@@ -201,8 +202,19 @@ bool AclRule::validateAddMatch(string attr_name, string attr_value)
201202
}
202203
else if(attr_name == MATCH_DSCP)
203204
{
204-
value.aclfield.data.u8 = to_uint<uint8_t>(attr_value, 0, 0x3F);
205-
value.aclfield.mask.u8 = 0x3F;
205+
/* Support both exact value match and value/mask match */
206+
auto dscp_data = tokenize(attr_value, '/');
207+
208+
value.aclfield.data.u8 = to_uint<uint8_t>(dscp_data[0], 0, 0x3F);
209+
210+
if (dscp_data.size() == 2)
211+
{
212+
value.aclfield.mask.u8 = to_uint<uint8_t>(dscp_data[1], 0, 0x3F);
213+
}
214+
else
215+
{
216+
value.aclfield.mask.u8 = 0x3F;
217+
}
206218
}
207219
else if(attr_name == MATCH_IP_PROTOCOL)
208220
{

orchagent/mirrororch.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ void MirrorOrch::createEntry(const string& key, const vector<FieldValueTuple>& d
252252
}
253253
}
254254

255-
SWSS_LOG_INFO("Creating mirroring sessions %s\n", key.c_str());
255+
SWSS_LOG_NOTICE("Create mirror sessions %s", key.c_str());
256256

257257
auto session = m_syncdMirrors.find(key);
258258
if (session != m_syncdMirrors.end())

tests/test_mirror.py

+230
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# This test suite covers the functionality of mirror feature in SwSS
2+
3+
import time
4+
5+
from swsscommon import swsscommon
6+
7+
8+
class TestMirror(object):
9+
def get_acl_table_id(self, dvs):
10+
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
11+
tbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE")
12+
keys = tbl.getKeys()
13+
assert dvs.asicdb.default_acl_table in keys
14+
15+
acl_tables = [k for k in keys if k not in dvs.asicdb.default_acl_table]
16+
assert len(acl_tables) == 1
17+
18+
return acl_tables[0]
19+
20+
def get_mirror_session_id(self, dvs):
21+
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
22+
tbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION")
23+
mirror_sessions = tbl.getKeys()
24+
assert len(mirror_sessions) == 1
25+
26+
return mirror_sessions[0]
27+
28+
def test_AclMirrorTableCreation(self, dvs):
29+
pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0)
30+
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
31+
cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0)
32+
33+
bind_ports = ["Ethernet0", "Ethernet4"]
34+
tbl = swsscommon.Table(cdb, "ACL_TABLE")
35+
36+
fvs = swsscommon.FieldValuePairs([("POLICY_DESC", "MIRROR_TEST"),
37+
("TYPE", "MIRROR"),
38+
("PORTS", ",".join(bind_ports))])
39+
# create the ACL table
40+
tbl.set("EVERFLOW_TABLE", fvs)
41+
time.sleep(1)
42+
43+
# assert the table is created
44+
tbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP")
45+
acl_table_ids = tbl.getKeys()
46+
assert len(acl_table_ids) == 2
47+
48+
tbl = swsscommon.Table(cdb, "MIRROR_SESSION")
49+
fvs = swsscommon.FieldValuePairs([("src_ip", "10.1.0.32"),
50+
("dst_ip", "10.20.30.40")])
51+
# create the mirror session
52+
tbl.set("EVERFLOW_SESSION", fvs)
53+
time.sleep(1)
54+
55+
# assert the mirror session is created
56+
tbl = swsscommon.Table(pdb, "MIRROR_SESSION")
57+
mirror_sessions = tbl.getKeys()
58+
assert len(mirror_sessions) == 1
59+
60+
# assert the mirror session is inactive
61+
(status, fvs) = tbl.get(mirror_sessions[0])
62+
assert status == True
63+
assert len(fvs) == 1
64+
for fv in fvs:
65+
if fv[0] == "status":
66+
fv[1] == "inactive"
67+
68+
def test_MirrorSessionActivation(self, dvs):
69+
# assign the IP address to Ethernet0
70+
dvs.runcmd("ifconfig Ethernet0 10.0.0.0/24 up")
71+
time.sleep(1)
72+
73+
pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0)
74+
tbl = swsscommon.ProducerStateTable(pdb, "NEIGH_TABLE")
75+
fvs = swsscommon.FieldValuePairs([("NEIGH", "02:04:06:08:10:12"),
76+
("FAMILY", "IPv4")])
77+
# create the neighbor entry associated with Ethernet0
78+
tbl.set("Ethernet0:10.0.0.1", fvs)
79+
time.sleep(1)
80+
81+
# add the route of mirror session destination via the neighbor
82+
dvs.runcmd("ip route add 10.20.30.40/32 via 10.0.0.1")
83+
time.sleep(1)
84+
85+
# assert the mirror session is active
86+
tbl = swsscommon.Table(pdb, "MIRROR_SESSION")
87+
(status, fvs) = tbl.get("EVERFLOW_SESSION")
88+
assert status == True
89+
assert len(fvs) == 1
90+
for fv in fvs:
91+
if fv[0] == "status":
92+
fv[1] == "active"
93+
94+
# assert the mirror session is created
95+
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
96+
tbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION")
97+
mirror_session_ids = tbl.getKeys()
98+
assert len(mirror_session_ids) == 1
99+
100+
def test_AclRuleDscpWithoutMask(self, dvs):
101+
102+
"""
103+
hmset ACL_RULE|EVERFLOW_TABLE|EVERFLOW_DSCP_TEST_RULE_1 priority 1000 PACKET_ACTION FORWARD DSCP 48
104+
"""
105+
106+
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
107+
cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0)
108+
109+
tbl = swsscommon.Table(cdb, "ACL_RULE")
110+
fvs = swsscommon.FieldValuePairs([("PRIORITY", "1000"),
111+
("MIRROR_ACTION", "EVERFLOW_SESSION"),
112+
("DSCP", "48")])
113+
# create the ACL rule contains DSCP match field with a mask
114+
tbl.set("EVERFLOW_TABLE|EVERFLOW_DSCP_TEST_RULE_1", fvs)
115+
time.sleep(1)
116+
117+
test_acl_table_id = self.get_acl_table_id(dvs)
118+
test_mirror_session_id = self.get_mirror_session_id(dvs)
119+
120+
# assert the ACL rule is created
121+
atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY")
122+
keys = atbl.getKeys()
123+
acl_entries = [k for k in keys if k not in dvs.asicdb.default_acl_entries]
124+
assert len(acl_entries) == 1
125+
126+
# assert the ACL rule content is correct
127+
(status, fvs) = atbl.get(acl_entries[0])
128+
assert status == True
129+
assert len(fvs) == 6
130+
for fv in fvs:
131+
if fv[0] == "SAI_ACL_ENTRY_ATTR_TABLE_ID":
132+
assert fv[1] == test_acl_table_id
133+
elif fv[0] == "SAI_ACL_ENTRY_ATTR_ADMIN_STATE":
134+
assert fv[1] == "true"
135+
elif fv[0] == "SAI_ACL_ENTRY_ATTR_PRIORITY":
136+
assert fv[1] == "1000"
137+
elif fv[0] == "SAI_ACL_ENTRY_ATTR_ACTION_COUNTER":
138+
assert True
139+
elif fv[0] == "SAI_ACL_ENTRY_ATTR_FIELD_DSCP":
140+
assert fv[1] == "48&mask:0x3f"
141+
elif fv[0] == "SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS":
142+
assert fv[1] == "1:" + test_mirror_session_id
143+
else:
144+
assert False
145+
146+
# remove the ACL rule
147+
tbl._del("EVERFLOW_TABLE|EVERFLOW_DSCP_TEST_RULE_1")
148+
time.sleep(1)
149+
150+
# assert the ACL rule is removed
151+
(status, fvs) = atbl.get(acl_entries[0])
152+
assert status == False
153+
154+
def test_AclRuleDscpWithMask(self, dvs):
155+
156+
"""
157+
hmset ACL_RULE|EVERFLOW_TABLE|EVERFLOW_DSCP_TEST_RULE_2 priority 1000 PACKET_ACTION FORWARD DSCP 16/16
158+
"""
159+
160+
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
161+
cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0)
162+
163+
tbl = swsscommon.Table(cdb, "ACL_RULE")
164+
fvs = swsscommon.FieldValuePairs([("PRIORITY", "1000"),
165+
("MIRROR_ACTION", "EVERFLOW_SESSION"),
166+
("DSCP", "16/16")])
167+
# create the ACL rule contains DSCP match field with a mask
168+
tbl.set("EVERFLOW_TABLE|EVERFLOW_DSCP_TEST_RULE_2", fvs)
169+
time.sleep(1)
170+
171+
test_acl_table_id = self.get_acl_table_id(dvs)
172+
test_mirror_session_id = self.get_mirror_session_id(dvs)
173+
174+
# assert the ACL rule is created
175+
atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY")
176+
keys = atbl.getKeys()
177+
acl_entries = [k for k in keys if k not in dvs.asicdb.default_acl_entries]
178+
assert len(acl_entries) == 1
179+
180+
# assert the ACL rule content is correct
181+
(status, fvs) = atbl.get(acl_entries[0])
182+
assert status == True
183+
assert len(fvs) == 6
184+
for fv in fvs:
185+
if fv[0] == "SAI_ACL_ENTRY_ATTR_TABLE_ID":
186+
assert fv[1] == test_acl_table_id
187+
elif fv[0] == "SAI_ACL_ENTRY_ATTR_ADMIN_STATE":
188+
assert fv[1] == "true"
189+
elif fv[0] == "SAI_ACL_ENTRY_ATTR_PRIORITY":
190+
assert fv[1] == "1000"
191+
elif fv[0] == "SAI_ACL_ENTRY_ATTR_ACTION_COUNTER":
192+
assert True
193+
elif fv[0] == "SAI_ACL_ENTRY_ATTR_FIELD_DSCP":
194+
assert fv[1] == "16&mask:0x10"
195+
elif fv[0] == "SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS":
196+
assert fv[1] == "1:" + test_mirror_session_id
197+
else:
198+
assert False
199+
200+
# remove the ACL rule
201+
tbl._del("EVERFLOW_TABLE|EVERFLOW_DSCP_TEST_RULE_2")
202+
time.sleep(1)
203+
204+
# assert the ACL rule is removed
205+
(status, fvs) = atbl.get(acl_entries[0])
206+
assert status == False
207+
208+
def test_AclMirrorTableDeletion(self, dvs):
209+
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
210+
cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0)
211+
212+
tbl = swsscommon.Table(cdb, "ACL_TABLE")
213+
# remove the ACL table
214+
tbl._del("EVERFLOW_TABLE")
215+
time.sleep(1)
216+
217+
# assert the ACL table is removed
218+
tbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE")
219+
acl_table_ids = tbl.getKeys()
220+
assert len(acl_table_ids) == 1
221+
222+
tbl = swsscommon.Table(cdb, "MIRROR_SESSION")
223+
# remove the mirror session
224+
tbl._del("EVERFLOW_SESSION")
225+
time.sleep(1)
226+
227+
# assert the mirror session is created
228+
tbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION")
229+
mirror_session_ids = tbl.getKeys()
230+
assert len(mirror_session_ids) == 0

0 commit comments

Comments
 (0)