Skip to content

DPB-ACL scale tests (#30) #1243

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

Merged
merged 3 commits into from
May 4, 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
26 changes: 22 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from datetime import datetime
from swsscommon import swsscommon
from dvslib import dvs_database as dvs_db
from dvslib import dvs_acl

def ensure_system(cmd):
(rc, output) = commands.getstatusoutput(cmd)
Expand Down Expand Up @@ -243,6 +244,8 @@ def __init__(self, name=None, imgname=None, keeptb=False, fakeplatform=None):
self.flex_db = None
self.state_db = None

self.dvs_acl = None

def destroy(self):
if self.appldb:
del self.appldb
Expand Down Expand Up @@ -953,31 +956,39 @@ def get_asic_db(self):
self.asic_db = db

return self.asic_db

def get_counters_db(self):
if not self.counters_db:
self.counters_db = dvs_db.DVSDatabase(self.COUNTERS_DB_ID, self.redis_sock)

return self.counters_db

def get_config_db(self):
if not self.config_db:
self.config_db = dvs_db.DVSDatabase(self.CONFIG_DB_ID, self.redis_sock)

return self.config_db

def get_flex_db(self):
if not self.flex_db:
self.flex_db = dvs_db.DVSDatabase(self.FLEX_COUNTER_DB_ID, self.redis_sock)

return self.flex_db

def get_state_db(self):
if not self.state_db:
self.state_db = dvs_db.DVSDatabase(self.STATE_DB_ID, self.redis_sock)

return self.state_db

def get_dvs_acl(self):
if not self.dvs_acl:
self.dvs_acl = dvs_acl.DVSAcl(self.get_asic_db(),
self.get_config_db(),
self.get_state_db(),
self.get_counters_db())
return self.dvs_acl

@pytest.yield_fixture(scope="module")
def dvs(request):
name = request.config.getoption("--dvsname")
Expand All @@ -998,6 +1009,13 @@ def testlog(request, dvs):
yield testlog
dvs.runcmd("logger === finish test %s ===" % request.node.name)

@pytest.yield_fixture(scope="class")
def dvs_acl_manager(request, dvs):
request.cls.dvs_acl = dvs_acl.DVSAcl(dvs.get_asic_db(),
dvs.get_config_db(),
dvs.get_state_db(),
dvs.get_counters_db())

##################### DPB fixtures ###########################################
@pytest.yield_fixture(scope="module")
def create_dpb_config_file(dvs):
Expand Down
231 changes: 231 additions & 0 deletions tests/dvslib/dvs_acl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
class DVSAcl(object):
def __init__(self, adb, cdb, sdb, cntrdb):
self.asic_db = adb
self.config_db = cdb
self.state_db = sdb
self.counters_db = cntrdb

def create_acl_table(self, table_name, table_type, ports, stage=None):
table_attrs = {
"policy_desc": "DVS acl table test",
"type": table_type,
"ports": ",".join(ports)
}

if stage:
table_attrs["stage"] = stage

self.config_db.create_entry("ACL_TABLE", table_name, table_attrs)

def update_acl_table(self, acl_table_name, ports):
table_attrs = {
"ports": ",".join(ports)
}
self.config_db.update_entry("ACL_TABLE", acl_table_name, table_attrs)

def remove_acl_table(self, table_name):
self.config_db.delete_entry("ACL_TABLE", table_name)

def get_acl_table_group_ids(self, expt):
acl_table_groups = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP", expt)
return acl_table_groups

def get_acl_table_ids(self, expt=1):
num_keys = len(self.asic_db.default_acl_tables) + expt
keys = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE", num_keys)
for k in self.asic_db.default_acl_tables:
assert k in keys

acl_tables = [k for k in keys if k not in self.asic_db.default_acl_tables]

return acl_tables

def get_acl_table_id(self):
acl_tables = self.get_acl_table_ids()
return acl_tables[0]

def verify_acl_table_count(self, expt):
num_keys = len(self.asic_db.default_acl_tables) + expt
keys = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE", num_keys)
for k in self.asic_db.default_acl_tables:
assert k in keys

acl_tables = [k for k in keys if k not in self.asic_db.default_acl_tables]

assert len(acl_tables) == expt

def verify_acl_group_num(self, expt):
acl_table_groups = self.get_acl_table_group_ids(expt)

for group in acl_table_groups:
fvs = self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP", group)
for k, v in fvs.items():
if k == "SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE":
assert v == "SAI_ACL_STAGE_INGRESS"
elif k == "SAI_ACL_TABLE_GROUP_ATTR_ACL_BIND_POINT_TYPE_LIST":
assert v == "1:SAI_ACL_BIND_POINT_TYPE_PORT"
elif k == "SAI_ACL_TABLE_GROUP_ATTR_TYPE":
assert v == "SAI_ACL_TABLE_GROUP_TYPE_PARALLEL"
else:
assert False

def verify_acl_table_group_member(self, acl_table_group_id, acl_table_id):
self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP", acl_table_group_id)
self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE", acl_table_id)
members = self.asic_db.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER")
for m in members:
fvs = self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER", m)
fvs = dict(fvs)
if (fvs.pop("SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID") == acl_table_group_id and
fvs.pop("SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID") == acl_table_id) :
return True
assert False

def verify_acl_group_member(self, acl_group_ids, acl_table_id):
members = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER", len(acl_group_ids))

member_groups = []
for member in members:
fvs = self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER", member)
for k, v in fvs.items():
if k == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID":
assert v in acl_group_ids
member_groups.append(v)
elif k == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID":
assert v == acl_table_id
elif k == "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY":
assert True
else:
assert False

assert set(member_groups) == set(acl_group_ids)

def verify_acl_table_ports_binding(self, ports, acl_table_id):
for p in ports:
# TBD: Introduce new API in dvs_databse.py to read by field
fvs = self.counters_db.get_entry("COUNTERS_PORT_NAME_MAP", "")
fvs = dict(fvs)
port_oid = fvs.pop(p)
#port_oid = self.counters_db.hget_entry("COUNTERS_PORT_NAME_MAP", "", p)
fvs = self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT", port_oid)
fvs = dict(fvs)
acl_table_group_id = fvs.pop("SAI_PORT_ATTR_INGRESS_ACL")
self.verify_acl_table_group_member(acl_table_group_id, acl_table_id)

def verify_acl_port_binding(self, bind_ports):
acl_table_groups = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE_GROUP", len(bind_ports))

port_groups = []
for port in [self.asic_db.port_name_map[p] for p in bind_ports]:
fvs = self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT", port)
acl_table_group = fvs.pop("SAI_PORT_ATTR_INGRESS_ACL", None)
assert acl_table_group in acl_table_groups
port_groups.append(acl_table_group)

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

def create_acl_rule(self, table_name, rule_name, qualifiers, action="FORWARD", priority="2020"):
fvs = {
"priority": priority,
"PACKET_ACTION": action
}

for k, v in qualifiers.items():
fvs[k] = v

self.config_db.create_entry("ACL_RULE", "{}|{}".format(table_name, rule_name), fvs)

def remove_acl_rule(self, table_name, rule_name):
self.config_db.delete_entry("ACL_RULE", "{}|{}".format(table_name, rule_name))

def get_acl_rule_id(self):
num_keys = len(self.asic_db.default_acl_entries) + 1
keys = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY", num_keys)

acl_entries = [k for k in keys if k not in self.asic_db.default_acl_entries]
return acl_entries[0]

def verify_no_acl_rules(self):
num_keys = len(self.asic_db.default_acl_entries)
keys = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY", num_keys)
assert set(keys) == set(self.asic_db.default_acl_entries)

def verify_acl_rule(self, qualifiers, action="FORWARD", priority="2020"):
acl_rule_id = self.get_acl_rule_id()

fvs = self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY", acl_rule_id)
self._check_acl_entry(fvs, qualifiers, action, priority)

def verify_acl_rule_set(self, priorities, in_actions, expected):
num_keys = len(self.asic_db.default_acl_entries) + len(priorities)
keys = self.asic_db.wait_for_n_keys("ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY", num_keys)

acl_entries = [k for k in keys if k not in self.asic_db.default_acl_entries]
for entry in acl_entries:
rule = self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY", entry)
priority = rule.get("SAI_ACL_ENTRY_ATTR_PRIORITY", None)
assert priority in priorities
self._check_acl_entry(rule, expected[priority],
action=in_actions[priority], priority=priority)

def _check_acl_entry(self, entry, qualifiers, action, priority):
acl_table_id = self.get_acl_table_id()

for k, v in entry.items():
if k == "SAI_ACL_ENTRY_ATTR_TABLE_ID":
assert v == acl_table_id
elif k == "SAI_ACL_ENTRY_ATTR_ADMIN_STATE":
assert v == "true"
elif k == "SAI_ACL_ENTRY_ATTR_PRIORITY":
assert v == priority
elif k == "SAI_ACL_ENTRY_ATTR_ACTION_COUNTER":
assert True
elif k == "SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION":
if action == "FORWARD":
assert v == "SAI_PACKET_ACTION_FORWARD"
elif action == "DROP":
assert v == "SAI_PACKET_ACTION_DROP"
else:
assert False
elif k == "SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT":
if "REDIRECT" not in action:
assert False
elif k in qualifiers:
assert qualifiers[k](v)
else:
assert False

def get_simple_qualifier_comparator(self, expected_qualifier):
def _match_qualifier(sai_qualifier):
return expected_qualifier == sai_qualifier

return _match_qualifier

def get_port_list_comparator(self, expected_ports):
def _match_port_list(sai_port_list):
if not sai_port_list.startswith("{}:".format(len(expected_ports))):
return False
for port in expected_ports:
if self.asic_db.port_name_map[port] not in sai_port_list:
return False

return True

return _match_port_list

def get_acl_range_comparator(self, expected_type, expected_ports):
def _match_acl_range(sai_acl_range):
range_id = sai_acl_range.split(":", 1)[1]
fvs = self.asic_db.wait_for_entry("ASIC_STATE:SAI_OBJECT_TYPE_ACL_RANGE", range_id)
for k, v in fvs.items():
if k == "SAI_ACL_RANGE_ATTR_TYPE" and v == expected_type:
continue
elif k == "SAI_ACL_RANGE_ATTR_LIMIT" and v == expected_ports:
continue
else:
return False

return True

return _match_acl_range
14 changes: 14 additions & 0 deletions tests/dvslib/dvs_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ def create_entry(self, table_name, key, entry):
formatted_entry = swsscommon.FieldValuePairs(entry.items())
table.set(key, formatted_entry)

def update_entry(self, table_name, key, entry):
"""
Updates entries of an existing key in the specified table.

Args:
table_name (str): The name of the table.
key (str): The key that needs to be updated.
entry (Dict[str, str]): A set of key-value pairs to be updated.
"""

table = swsscommon.Table(self.db_connection, table_name)
formatted_entry = swsscommon.FieldValuePairs(entry.items())
table.set(key, formatted_entry)

def get_entry(self, table_name, key):
"""
Gets the entry stored at `key` in the specified table.
Expand Down
8 changes: 2 additions & 6 deletions tests/port_dpb.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def write_to_config_db(self):
("speed", speed_str),
("index", index_str)])
self._cfg_db_ptbl.set(self.get_name(), fvs)
time.sleep(1)
time.sleep(2)

def get_fvs_dict(self, fvs):
fvs_dict = {}
Expand Down Expand Up @@ -221,8 +221,6 @@ def breakin(self, dvs, port_names):
#dvs.runcmd("ip link delete " + cp.get_name())
#print "Deleted child ports:%s from config DB"%port_names

time.sleep(6)

for cp in child_ports:
assert(cp.exists_in_config_db() == False)
for cp in child_ports:
Expand All @@ -235,7 +233,6 @@ def breakin(self, dvs, port_names):
p.port_merge(child_ports)
p.write_to_config_db()
#print "Added port:%s to config DB"%p.get_name()
time.sleep(2)

p.verify_config_db()
#print "Config DB verification passed!"
Expand All @@ -254,7 +251,6 @@ def create_child_ports(self, dvs, p, num_child_ports):
cp.write_to_config_db()
child_port_names.append(cp.get_name())
#print "Added child ports:%s to config DB"%child_port_names
time.sleep(6)

for cp in child_ports:
assert(cp.exists_in_config_db() == True)
Expand All @@ -279,7 +275,7 @@ def breakout(self, dvs, port_name, num_child_ports):
# TBD, need vs lib to support hostif removal
#dvs.runcmd("ip link delete " + p.get_name())
#print "Deleted port:%s from config DB"%port_name
time.sleep(6)
time.sleep(2)

# Verify port is deleted from all DBs
assert(p.exists_in_config_db() == False)
Expand Down
Loading