Skip to content

Commit c6a8a04

Browse files
shine4chenlguohan
authored andcommitted
[aclorch]: add support for acl rule to match out port (#810)
ACL rule can match out port. Out port could be port intf , lag or vlan. Signed-off-by: shine.chen <[email protected]>
1 parent 8f4c54a commit c6a8a04

File tree

4 files changed

+259
-6
lines changed

4 files changed

+259
-6
lines changed

orchagent/aclorch.cpp

+44-4
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ static acl_table_type_lookup_t aclTableTypeLookUp =
107107
{ TABLE_TYPE_MIRROR_DSCP, ACL_TABLE_MIRROR_DSCP },
108108
{ TABLE_TYPE_CTRLPLANE, ACL_TABLE_CTRLPLANE },
109109
{ TABLE_TYPE_DTEL_FLOW_WATCHLIST, ACL_TABLE_DTEL_FLOW_WATCHLIST },
110-
{ TABLE_TYPE_DTEL_DROP_WATCHLIST, ACL_TABLE_DTEL_DROP_WATCHLIST }
110+
{ TABLE_TYPE_DTEL_DROP_WATCHLIST, ACL_TABLE_DTEL_DROP_WATCHLIST },
111+
{ TABLE_TYPE_MCLAG, ACL_TABLE_MCLAG }
111112
};
112113

113114
static acl_stage_type_lookup_t aclStageLookUp =
@@ -659,7 +660,8 @@ shared_ptr<AclRule> AclRule::makeShared(acl_table_type_t type, AclOrch *acl, Mir
659660
type != ACL_TABLE_MIRRORV6 &&
660661
type != ACL_TABLE_MIRROR_DSCP &&
661662
type != ACL_TABLE_DTEL_FLOW_WATCHLIST &&
662-
type != ACL_TABLE_DTEL_DROP_WATCHLIST)
663+
type != ACL_TABLE_DTEL_DROP_WATCHLIST &&
664+
type != ACL_TABLE_MCLAG)
663665
{
664666
throw runtime_error("Unknown table type");
665667
}
@@ -703,6 +705,10 @@ shared_ptr<AclRule> AclRule::makeShared(acl_table_type_t type, AclOrch *acl, Mir
703705
throw runtime_error("DTel feature is not enabled. Watchlists cannot be configured");
704706
}
705707
}
708+
else if (type == ACL_TABLE_MCLAG)
709+
{
710+
return make_shared<AclRuleMclag>(acl, rule, table, type);
711+
}
706712

707713
throw runtime_error("Wrong combination of table type and action in rule " + rule);
708714
}
@@ -1230,6 +1236,33 @@ void AclRuleMirror::update(SubjectType type, void *cntx)
12301236
}
12311237
}
12321238

1239+
AclRuleMclag::AclRuleMclag(AclOrch *aclOrch, string rule, string table, acl_table_type_t type, bool createCounter) :
1240+
AclRuleL3(aclOrch, rule, table, type, createCounter)
1241+
{
1242+
}
1243+
1244+
bool AclRuleMclag::validateAddMatch(string attr_name, string attr_value)
1245+
{
1246+
if (attr_name != MATCH_IP_TYPE && attr_name != MATCH_OUT_PORTS)
1247+
{
1248+
return false;
1249+
}
1250+
1251+
return AclRule::validateAddMatch(attr_name, attr_value);
1252+
}
1253+
1254+
bool AclRuleMclag::validate()
1255+
{
1256+
SWSS_LOG_ENTER();
1257+
1258+
if (m_matches.size() == 0)
1259+
{
1260+
return false;
1261+
}
1262+
1263+
return true;
1264+
}
1265+
12331266
bool AclTable::validate()
12341267
{
12351268
if (type == ACL_TABLE_CTRLPLANE)
@@ -1455,6 +1488,13 @@ bool AclTable::create()
14551488
table_attrs.push_back(attr);
14561489
}
14571490

1491+
if (type == ACL_TABLE_MCLAG)
1492+
{
1493+
attr.id = SAI_ACL_TABLE_ATTR_FIELD_OUT_PORTS;
1494+
attr.value.booldata = true;
1495+
table_attrs.push_back(attr);
1496+
}
1497+
14581498
sai_status_t status = sai_acl_api->create_acl_table(&m_oid, gSwitchId, (uint32_t)table_attrs.size(), table_attrs.data());
14591499

14601500
if (status == SAI_STATUS_SUCCESS)
@@ -2454,12 +2494,12 @@ void AclOrch::doTask(Consumer &consumer)
24542494

24552495
string table_name = consumer.getTableName();
24562496

2457-
if (table_name == CFG_ACL_TABLE_TABLE_NAME)
2497+
if (table_name == CFG_ACL_TABLE_TABLE_NAME || table_name == APP_ACL_TABLE_TABLE_NAME)
24582498
{
24592499
unique_lock<mutex> lock(m_countersMutex);
24602500
doAclTableTask(consumer);
24612501
}
2462-
else if (table_name == CFG_ACL_RULE_TABLE_NAME)
2502+
else if (table_name == CFG_ACL_RULE_TABLE_NAME || table_name == APP_ACL_RULE_TABLE_NAME)
24632503
{
24642504
unique_lock<mutex> lock(m_countersMutex);
24652505
doAclRuleTask(consumer);

orchagent/aclorch.h

+11-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#define TABLE_TYPE_CTRLPLANE "CTRLPLANE"
3434
#define TABLE_TYPE_DTEL_FLOW_WATCHLIST "DTEL_FLOW_WATCHLIST"
3535
#define TABLE_TYPE_DTEL_DROP_WATCHLIST "DTEL_DROP_WATCHLIST"
36+
#define TABLE_TYPE_MCLAG "MCLAG"
3637

3738
#define RULE_PRIORITY "PRIORITY"
3839
#define MATCH_IN_PORTS "IN_PORTS"
@@ -111,7 +112,8 @@ typedef enum
111112
ACL_TABLE_PFCWD,
112113
ACL_TABLE_CTRLPLANE,
113114
ACL_TABLE_DTEL_FLOW_WATCHLIST,
114-
ACL_TABLE_DTEL_DROP_WATCHLIST
115+
ACL_TABLE_DTEL_DROP_WATCHLIST,
116+
ACL_TABLE_MCLAG
115117
} acl_table_type_t;
116118

117119
typedef map<string, acl_table_type_t> acl_table_type_lookup_t;
@@ -317,6 +319,14 @@ class AclRuleDTelDropWatchListEntry: public AclRule
317319
DTelOrch *m_pDTelOrch;
318320
};
319321

322+
class AclRuleMclag: public AclRuleL3
323+
{
324+
public:
325+
AclRuleMclag(AclOrch *m_pAclOrch, string rule, string table, acl_table_type_t type, bool createCounter = false);
326+
bool validateAddMatch(string attr_name, string attr_value);
327+
bool validate();
328+
};
329+
320330
class AclTable {
321331
sai_object_id_t m_oid;
322332
AclOrch *m_pAclOrch;

orchagent/orchdaemon.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,14 @@ bool OrchDaemon::init()
176176

177177
TableConnector confDbAclTable(m_configDb, CFG_ACL_TABLE_TABLE_NAME);
178178
TableConnector confDbAclRuleTable(m_configDb, CFG_ACL_RULE_TABLE_NAME);
179+
TableConnector appDbAclTable(m_applDb, APP_ACL_TABLE_TABLE_NAME);
180+
TableConnector appDbAclRuleTable(m_applDb, APP_ACL_RULE_TABLE_NAME);
179181

180182
vector<TableConnector> acl_table_connectors = {
181183
confDbAclTable,
182-
confDbAclRuleTable
184+
confDbAclRuleTable,
185+
appDbAclTable,
186+
appDbAclRuleTable
183187
};
184188

185189
vector<string> dtel_tables = {

tests/test_acl_mclag.py

+199
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
from swsscommon import swsscommon
2+
import time
3+
import re
4+
import json
5+
6+
class TestMclagAcl(object):
7+
def setup_db(self, dvs):
8+
self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0)
9+
self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
10+
11+
def create_entry(self, tbl, key, pairs):
12+
fvs = swsscommon.FieldValuePairs(pairs)
13+
tbl.set(key, fvs)
14+
time.sleep(1)
15+
16+
def remove_entry(self, tbl, key):
17+
tbl._del(key)
18+
time.sleep(1)
19+
20+
def create_entry_tbl(self, db, table, key, pairs):
21+
tbl = swsscommon.Table(db, table)
22+
self.create_entry(tbl, key, pairs)
23+
24+
def remove_entry_tbl(self, db, table, key):
25+
tbl = swsscommon.Table(db, table)
26+
self.remove_entry(tbl, key)
27+
28+
def create_entry_pst(self, db, table, key, pairs):
29+
tbl = swsscommon.ProducerStateTable(db, table)
30+
self.create_entry(tbl, key, pairs)
31+
32+
def remove_entry_pst(self, db, table, key):
33+
tbl = swsscommon.ProducerStateTable(db, table)
34+
self.remove_entry(tbl, key)
35+
36+
def get_acl_table_id(self, dvs):
37+
tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE")
38+
keys = tbl.getKeys()
39+
40+
for k in dvs.asicdb.default_acl_tables:
41+
assert k in keys
42+
43+
acl_tables = [k for k in keys if k not in dvs.asicdb.default_acl_tables]
44+
if len(acl_tables) == 1:
45+
return acl_tables[0]
46+
else:
47+
return None
48+
49+
def verify_acl_group_num(self, expt):
50+
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP")
51+
acl_table_groups = atbl.getKeys()
52+
assert len(acl_table_groups) == expt
53+
54+
for k in acl_table_groups:
55+
(status, fvs) = atbl.get(k)
56+
assert status == True
57+
for fv in fvs:
58+
if fv[0] == "SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE":
59+
assert fv[1] == "SAI_ACL_STAGE_INGRESS"
60+
elif fv[0] == "SAI_ACL_TABLE_GROUP_ATTR_ACL_BIND_POINT_TYPE_LIST":
61+
assert fv[1] == "1:SAI_ACL_BIND_POINT_TYPE_PORT"
62+
elif fv[0] == "SAI_ACL_TABLE_GROUP_ATTR_TYPE":
63+
assert fv[1] == "SAI_ACL_TABLE_GROUP_TYPE_PARALLEL"
64+
else:
65+
assert False
66+
67+
def verify_acl_group_member(self, acl_group_ids, acl_table_id):
68+
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER")
69+
keys = atbl.getKeys()
70+
71+
member_groups = []
72+
for k in keys:
73+
(status, fvs) = atbl.get(k)
74+
assert status == True
75+
assert len(fvs) == 3
76+
for fv in fvs:
77+
if fv[0] == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID":
78+
assert fv[1] in acl_group_ids
79+
member_groups.append(fv[1])
80+
elif fv[0] == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID":
81+
assert fv[1] == acl_table_id
82+
elif fv[0] == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY":
83+
assert True
84+
else:
85+
assert False
86+
87+
assert set(member_groups) == set(acl_group_ids)
88+
89+
def verify_acl_port_binding(self, dvs, bind_ports):
90+
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP")
91+
acl_table_groups = atbl.getKeys()
92+
assert len(acl_table_groups) == len(bind_ports)
93+
94+
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_PORT")
95+
port_groups = []
96+
for p in [dvs.asicdb.portnamemap[portname] for portname in bind_ports]:
97+
(status, fvs) = atbl.get(p)
98+
for fv in fvs:
99+
if fv[0] == "SAI_PORT_ATTR_INGRESS_ACL":
100+
assert fv[1] in acl_table_groups
101+
port_groups.append(fv[1])
102+
103+
assert len(port_groups) == len(bind_ports)
104+
assert set(port_groups) == set(acl_table_groups)
105+
106+
def test_AclTableCreation(self, dvs, testlog):
107+
"""
108+
hmset ACL_TABLE_TABLE:mclag policy_desc "Mclag egress port isolate acl" type MCLAG ports Ethernet0,Ethernet4
109+
"""
110+
self.setup_db(dvs)
111+
112+
# create ACL_TABLE_TABLE in app db
113+
bind_ports = ["Ethernet0", "Ethernet4"]
114+
self.create_entry_pst(
115+
self.pdb,
116+
"ACL_TABLE_TABLE", "mclag",
117+
[
118+
("policy_desc", "Mclag egress port isolate acl"),
119+
("type", "MCLAG"),
120+
("ports", ",".join(bind_ports)),
121+
]
122+
)
123+
124+
# check acl table in asic db
125+
acl_table_id = self.get_acl_table_id(dvs)
126+
assert acl_table_id is not None
127+
128+
# check acl table group in asic db
129+
self.verify_acl_group_num(2)
130+
131+
# get acl table group ids and verify the id numbers
132+
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP")
133+
acl_group_ids = atbl.getKeys()
134+
assert len(acl_group_ids) == 2
135+
136+
# check acl table group member
137+
self.verify_acl_group_member(acl_group_ids, acl_table_id)
138+
139+
# check port binding
140+
self.verify_acl_port_binding(dvs, bind_ports)
141+
142+
def test_AclRuleOutPorts(self, dvs, testlog):
143+
"""
144+
hmset ACL_RULE_TABLE:mclag:mclag IP_TYPE ANY PACKET_ACTION DROP OUT_PORTS Ethernet8,Ethernet12
145+
"""
146+
self.setup_db(dvs)
147+
148+
# create acl rule
149+
bind_ports = ["Ethernet8", "Ethernet12"]
150+
self.create_entry_pst(
151+
self.pdb,
152+
"ACL_RULE_TABLE", "mclag:mclag",
153+
[
154+
("IP_TYPE", "ANY"),
155+
("PACKET_ACTION", "DROP"),
156+
("OUT_PORTS", ",".join(bind_ports)),
157+
]
158+
)
159+
160+
# check acl rule table in asic db
161+
acl_table_id = self.get_acl_table_id(dvs)
162+
163+
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY")
164+
keys = atbl.getKeys()
165+
166+
acl_entry = [k for k in keys if k not in dvs.asicdb.default_acl_entries]
167+
assert len(acl_entry) == 1
168+
169+
(status, fvs) = atbl.get(acl_entry[0])
170+
assert status == True
171+
172+
value = dict(fvs)
173+
assert value["SAI_ACL_ENTRY_ATTR_TABLE_ID"] == acl_table_id
174+
assert value["SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION"] == "SAI_PACKET_ACTION_DROP"
175+
assert value["SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE"] == "SAI_ACL_IP_TYPE_ANY&mask:0xffffffffffffffff"
176+
out_ports = value["SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS"]
177+
assert out_ports.startswith("2:")
178+
assert dvs.asicdb.portnamemap["Ethernet8"] in out_ports
179+
assert dvs.asicdb.portnamemap["Ethernet12"] in out_ports
180+
181+
# remove acl rule
182+
self.remove_entry_pst(
183+
self.pdb,
184+
"ACL_RULE_TABLE", "mclag:mclag"
185+
)
186+
187+
# check acl rule in asic db
188+
(status, fvs) = atbl.get(acl_entry[0])
189+
assert status == False
190+
191+
# remove acl
192+
self.remove_entry_pst(
193+
self.pdb,
194+
"ACL_TABLE_TABLE", "mclag:mclag"
195+
)
196+
197+
# check acl in asic db
198+
acl_table_id = self.get_acl_table_id(dvs)
199+
assert acl_table_id is None

0 commit comments

Comments
 (0)