Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[aclorch]: add support for acl rule to match out port #810

Merged
merged 7 commits into from
Jan 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 44 additions & 4 deletions orchagent/aclorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,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 @@ -663,7 +664,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 @@ -707,6 +709,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 @@ -1228,6 +1234,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 @@ -1453,6 +1486,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);
shine4chen marked this conversation as resolved.
Show resolved Hide resolved
}

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 @@ -2407,12 +2447,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 @@ -109,7 +110,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 @@ -315,6 +317,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 @@ -157,10 +157,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