Skip to content

Commit

Permalink
Add DPB-ACL scale tests (sonic-net#1243)
Browse files Browse the repository at this point in the history
* Add DPB ACL test cases
* Move common ACL test code to dvs_common

Co-authored-by: Vasant <vapatil@linkedin.com>
  • Loading branch information
vasant17 and Vasant authored May 4, 2020
1 parent 3829053 commit e1a5e9a
Show file tree
Hide file tree
Showing 6 changed files with 563 additions and 465 deletions.
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

0 comments on commit e1a5e9a

Please sign in to comment.