Skip to content

Commit

Permalink
[aclorch]: add support for acl rule to match out port (#810)
Browse files Browse the repository at this point in the history
ACL rule can match out port. Out port could be port intf , lag or vlan.

Signed-off-by: shine.chen <[email protected]>
  • Loading branch information
shine4chen authored and lguohan committed Jan 30, 2020
1 parent 8f4c54a commit c6a8a04
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 6 deletions.
48 changes: 44 additions & 4 deletions orchagent/aclorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ static acl_table_type_lookup_t aclTableTypeLookUp =
{ TABLE_TYPE_MIRROR_DSCP, ACL_TABLE_MIRROR_DSCP },
{ TABLE_TYPE_CTRLPLANE, ACL_TABLE_CTRLPLANE },
{ TABLE_TYPE_DTEL_FLOW_WATCHLIST, ACL_TABLE_DTEL_FLOW_WATCHLIST },
{ TABLE_TYPE_DTEL_DROP_WATCHLIST, ACL_TABLE_DTEL_DROP_WATCHLIST }
{ TABLE_TYPE_DTEL_DROP_WATCHLIST, ACL_TABLE_DTEL_DROP_WATCHLIST },
{ TABLE_TYPE_MCLAG, ACL_TABLE_MCLAG }
};

static acl_stage_type_lookup_t aclStageLookUp =
Expand Down Expand Up @@ -659,7 +660,8 @@ shared_ptr<AclRule> AclRule::makeShared(acl_table_type_t type, AclOrch *acl, Mir
type != ACL_TABLE_MIRRORV6 &&
type != ACL_TABLE_MIRROR_DSCP &&
type != ACL_TABLE_DTEL_FLOW_WATCHLIST &&
type != ACL_TABLE_DTEL_DROP_WATCHLIST)
type != ACL_TABLE_DTEL_DROP_WATCHLIST &&
type != ACL_TABLE_MCLAG)
{
throw runtime_error("Unknown table type");
}
Expand Down Expand Up @@ -703,6 +705,10 @@ shared_ptr<AclRule> AclRule::makeShared(acl_table_type_t type, AclOrch *acl, Mir
throw runtime_error("DTel feature is not enabled. Watchlists cannot be configured");
}
}
else if (type == ACL_TABLE_MCLAG)
{
return make_shared<AclRuleMclag>(acl, rule, table, type);
}

throw runtime_error("Wrong combination of table type and action in rule " + rule);
}
Expand Down Expand Up @@ -1230,6 +1236,33 @@ void AclRuleMirror::update(SubjectType type, void *cntx)
}
}

AclRuleMclag::AclRuleMclag(AclOrch *aclOrch, string rule, string table, acl_table_type_t type, bool createCounter) :
AclRuleL3(aclOrch, rule, table, type, createCounter)
{
}

bool AclRuleMclag::validateAddMatch(string attr_name, string attr_value)
{
if (attr_name != MATCH_IP_TYPE && attr_name != MATCH_OUT_PORTS)
{
return false;
}

return AclRule::validateAddMatch(attr_name, attr_value);
}

bool AclRuleMclag::validate()
{
SWSS_LOG_ENTER();

if (m_matches.size() == 0)
{
return false;
}

return true;
}

bool AclTable::validate()
{
if (type == ACL_TABLE_CTRLPLANE)
Expand Down Expand Up @@ -1455,6 +1488,13 @@ bool AclTable::create()
table_attrs.push_back(attr);
}

if (type == ACL_TABLE_MCLAG)
{
attr.id = SAI_ACL_TABLE_ATTR_FIELD_OUT_PORTS;
attr.value.booldata = true;
table_attrs.push_back(attr);
}

sai_status_t status = sai_acl_api->create_acl_table(&m_oid, gSwitchId, (uint32_t)table_attrs.size(), table_attrs.data());

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

string table_name = consumer.getTableName();

if (table_name == CFG_ACL_TABLE_TABLE_NAME)
if (table_name == CFG_ACL_TABLE_TABLE_NAME || table_name == APP_ACL_TABLE_TABLE_NAME)
{
unique_lock<mutex> lock(m_countersMutex);
doAclTableTask(consumer);
}
else if (table_name == CFG_ACL_RULE_TABLE_NAME)
else if (table_name == CFG_ACL_RULE_TABLE_NAME || table_name == APP_ACL_RULE_TABLE_NAME)
{
unique_lock<mutex> lock(m_countersMutex);
doAclRuleTask(consumer);
Expand Down
12 changes: 11 additions & 1 deletion orchagent/aclorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#define TABLE_TYPE_CTRLPLANE "CTRLPLANE"
#define TABLE_TYPE_DTEL_FLOW_WATCHLIST "DTEL_FLOW_WATCHLIST"
#define TABLE_TYPE_DTEL_DROP_WATCHLIST "DTEL_DROP_WATCHLIST"
#define TABLE_TYPE_MCLAG "MCLAG"

#define RULE_PRIORITY "PRIORITY"
#define MATCH_IN_PORTS "IN_PORTS"
Expand Down Expand Up @@ -111,7 +112,8 @@ typedef enum
ACL_TABLE_PFCWD,
ACL_TABLE_CTRLPLANE,
ACL_TABLE_DTEL_FLOW_WATCHLIST,
ACL_TABLE_DTEL_DROP_WATCHLIST
ACL_TABLE_DTEL_DROP_WATCHLIST,
ACL_TABLE_MCLAG
} acl_table_type_t;

typedef map<string, acl_table_type_t> acl_table_type_lookup_t;
Expand Down Expand Up @@ -317,6 +319,14 @@ class AclRuleDTelDropWatchListEntry: public AclRule
DTelOrch *m_pDTelOrch;
};

class AclRuleMclag: public AclRuleL3
{
public:
AclRuleMclag(AclOrch *m_pAclOrch, string rule, string table, acl_table_type_t type, bool createCounter = false);
bool validateAddMatch(string attr_name, string attr_value);
bool validate();
};

class AclTable {
sai_object_id_t m_oid;
AclOrch *m_pAclOrch;
Expand Down
6 changes: 5 additions & 1 deletion orchagent/orchdaemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,14 @@ bool OrchDaemon::init()

TableConnector confDbAclTable(m_configDb, CFG_ACL_TABLE_TABLE_NAME);
TableConnector confDbAclRuleTable(m_configDb, CFG_ACL_RULE_TABLE_NAME);
TableConnector appDbAclTable(m_applDb, APP_ACL_TABLE_TABLE_NAME);
TableConnector appDbAclRuleTable(m_applDb, APP_ACL_RULE_TABLE_NAME);

vector<TableConnector> acl_table_connectors = {
confDbAclTable,
confDbAclRuleTable
confDbAclRuleTable,
appDbAclTable,
appDbAclRuleTable
};

vector<string> dtel_tables = {
Expand Down
199 changes: 199 additions & 0 deletions tests/test_acl_mclag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
from swsscommon import swsscommon
import time
import re
import json

class TestMclagAcl(object):
def setup_db(self, dvs):
self.pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0)
self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)

def create_entry(self, tbl, key, pairs):
fvs = swsscommon.FieldValuePairs(pairs)
tbl.set(key, fvs)
time.sleep(1)

def remove_entry(self, tbl, key):
tbl._del(key)
time.sleep(1)

def create_entry_tbl(self, db, table, key, pairs):
tbl = swsscommon.Table(db, table)
self.create_entry(tbl, key, pairs)

def remove_entry_tbl(self, db, table, key):
tbl = swsscommon.Table(db, table)
self.remove_entry(tbl, key)

def create_entry_pst(self, db, table, key, pairs):
tbl = swsscommon.ProducerStateTable(db, table)
self.create_entry(tbl, key, pairs)

def remove_entry_pst(self, db, table, key):
tbl = swsscommon.ProducerStateTable(db, table)
self.remove_entry(tbl, key)

def get_acl_table_id(self, dvs):
tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE")
keys = tbl.getKeys()

for k in dvs.asicdb.default_acl_tables:
assert k in keys

acl_tables = [k for k in keys if k not in dvs.asicdb.default_acl_tables]
if len(acl_tables) == 1:
return acl_tables[0]
else:
return None

def verify_acl_group_num(self, expt):
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP")
acl_table_groups = atbl.getKeys()
assert len(acl_table_groups) == expt

for k in acl_table_groups:
(status, fvs) = atbl.get(k)
assert status == True
for fv in fvs:
if fv[0] == "SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE":
assert fv[1] == "SAI_ACL_STAGE_INGRESS"
elif fv[0] == "SAI_ACL_TABLE_GROUP_ATTR_ACL_BIND_POINT_TYPE_LIST":
assert fv[1] == "1:SAI_ACL_BIND_POINT_TYPE_PORT"
elif fv[0] == "SAI_ACL_TABLE_GROUP_ATTR_TYPE":
assert fv[1] == "SAI_ACL_TABLE_GROUP_TYPE_PARALLEL"
else:
assert False

def verify_acl_group_member(self, acl_group_ids, acl_table_id):
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER")
keys = atbl.getKeys()

member_groups = []
for k in keys:
(status, fvs) = atbl.get(k)
assert status == True
assert len(fvs) == 3
for fv in fvs:
if fv[0] == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID":
assert fv[1] in acl_group_ids
member_groups.append(fv[1])
elif fv[0] == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID":
assert fv[1] == acl_table_id
elif fv[0] == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY":
assert True
else:
assert False

assert set(member_groups) == set(acl_group_ids)

def verify_acl_port_binding(self, dvs, bind_ports):
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP")
acl_table_groups = atbl.getKeys()
assert len(acl_table_groups) == len(bind_ports)

atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_PORT")
port_groups = []
for p in [dvs.asicdb.portnamemap[portname] for portname in bind_ports]:
(status, fvs) = atbl.get(p)
for fv in fvs:
if fv[0] == "SAI_PORT_ATTR_INGRESS_ACL":
assert fv[1] in acl_table_groups
port_groups.append(fv[1])

assert len(port_groups) == len(bind_ports)
assert set(port_groups) == set(acl_table_groups)

def test_AclTableCreation(self, dvs, testlog):
"""
hmset ACL_TABLE_TABLE:mclag policy_desc "Mclag egress port isolate acl" type MCLAG ports Ethernet0,Ethernet4
"""
self.setup_db(dvs)

# create ACL_TABLE_TABLE in app db
bind_ports = ["Ethernet0", "Ethernet4"]
self.create_entry_pst(
self.pdb,
"ACL_TABLE_TABLE", "mclag",
[
("policy_desc", "Mclag egress port isolate acl"),
("type", "MCLAG"),
("ports", ",".join(bind_ports)),
]
)

# check acl table in asic db
acl_table_id = self.get_acl_table_id(dvs)
assert acl_table_id is not None

# check acl table group in asic db
self.verify_acl_group_num(2)

# get acl table group ids and verify the id numbers
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP")
acl_group_ids = atbl.getKeys()
assert len(acl_group_ids) == 2

# check acl table group member
self.verify_acl_group_member(acl_group_ids, acl_table_id)

# check port binding
self.verify_acl_port_binding(dvs, bind_ports)

def test_AclRuleOutPorts(self, dvs, testlog):
"""
hmset ACL_RULE_TABLE:mclag:mclag IP_TYPE ANY PACKET_ACTION DROP OUT_PORTS Ethernet8,Ethernet12
"""
self.setup_db(dvs)

# create acl rule
bind_ports = ["Ethernet8", "Ethernet12"]
self.create_entry_pst(
self.pdb,
"ACL_RULE_TABLE", "mclag:mclag",
[
("IP_TYPE", "ANY"),
("PACKET_ACTION", "DROP"),
("OUT_PORTS", ",".join(bind_ports)),
]
)

# check acl rule table in asic db
acl_table_id = self.get_acl_table_id(dvs)

atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY")
keys = atbl.getKeys()

acl_entry = [k for k in keys if k not in dvs.asicdb.default_acl_entries]
assert len(acl_entry) == 1

(status, fvs) = atbl.get(acl_entry[0])
assert status == True

value = dict(fvs)
assert value["SAI_ACL_ENTRY_ATTR_TABLE_ID"] == acl_table_id
assert value["SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION"] == "SAI_PACKET_ACTION_DROP"
assert value["SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE"] == "SAI_ACL_IP_TYPE_ANY&mask:0xffffffffffffffff"
out_ports = value["SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS"]
assert out_ports.startswith("2:")
assert dvs.asicdb.portnamemap["Ethernet8"] in out_ports
assert dvs.asicdb.portnamemap["Ethernet12"] in out_ports

# remove acl rule
self.remove_entry_pst(
self.pdb,
"ACL_RULE_TABLE", "mclag:mclag"
)

# check acl rule in asic db
(status, fvs) = atbl.get(acl_entry[0])
assert status == False

# remove acl
self.remove_entry_pst(
self.pdb,
"ACL_TABLE_TABLE", "mclag:mclag"
)

# check acl in asic db
acl_table_id = self.get_acl_table_id(dvs)
assert acl_table_id is None

0 comments on commit c6a8a04

Please sign in to comment.