Skip to content

Commit

Permalink
[acl-loader] Support for ACL table type L3V4V6
Browse files Browse the repository at this point in the history
Support a new ACL table type called L3V4V6.
This table supports both v4 and v6 Match types.
Add unit tests for this new ACL table type.

HLD: sonic-net/SONiC#1267

Signed-off-by: Ravi(Marvell) [email protected]
  • Loading branch information
rck-innovium committed Apr 16, 2023
1 parent d17d124 commit b200fc6
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 5 deletions.
28 changes: 25 additions & 3 deletions acl_loader/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class AclLoader(object):
"ETHERTYPE_LLDP": 0x88CC,
"ETHERTYPE_VLAN": 0x8100,
"ETHERTYPE_ROCE": 0x8915,
"ETHERTYPE_ARP": 0x0806,
"ETHERTYPE_ARP": 0x0806,
"ETHERTYPE_IPV4": 0x0800,
"ETHERTYPE_IPV6": 0x86DD,
"ETHERTYPE_MPLS": 0x8847
Expand Down Expand Up @@ -346,6 +346,14 @@ def is_table_l3v6(self, tname):
"""
return self.tables_db_info[tname]["type"].upper() == "L3V6"

def is_table_l3v4v6(self, tname):
"""
Check if ACL table type is L3V4V6
:param tname: ACL table name
:return: True if table type is L3V4V6 else False
"""
return self.tables_db_info[tname]["type"].upper() == "L3V4V6"

def is_table_l3(self, tname):
"""
Check if ACL table type is L3
Expand Down Expand Up @@ -509,6 +517,8 @@ def convert_ip(self, table_name, rule_idx, rule):
# "IP_ICMP" we need to pick the correct protocol number for the IP version
if rule.ip.config.protocol == "IP_ICMP" and self.is_table_ipv6(table_name):
rule_props["IP_PROTOCOL"] = self.ip_protocol_map["IP_ICMPV6"]
elif rule.ip.config.protocol == "IP_ICMP" and self.is_table_l3v4v6(table_name) and rule.l2.config.ethertype == "ETHERTYPE_IPV6":
rule_props["IP_PROTOCOL"] = self.ip_protocol_map["IP_ICMPV6"]
else:
rule_props["IP_PROTOCOL"] = self.ip_protocol_map[rule.ip.config.protocol]
else:
Expand Down Expand Up @@ -544,7 +554,7 @@ def convert_ip(self, table_name, rule_idx, rule):
def convert_icmp(self, table_name, rule_idx, rule):
rule_props = {}

is_table_v6 = self.is_table_ipv6(table_name)
is_table_v6 = self.is_table_ipv6(table_name) or (self.is_table_l3v4v6(table_name) and rule.l2.config.ethertype == "ETHERTYPE_IPV6")
type_key = "ICMPV6_TYPE" if is_table_v6 else "ICMP_TYPE"
code_key = "ICMPV6_CODE" if is_table_v6 else "ICMP_CODE"

Expand Down Expand Up @@ -651,7 +661,17 @@ def convert_rule_to_db_schema(self, table_name, rule):
rule_props["PRIORITY"] = str(self.max_priority - rule_idx)

# setup default ip type match to dataplane acl (could be overriden by rule later)
if self.is_table_l3v6(table_name):
if self.is_table_l3v4v6(table_name):
# ETHERTYPE must be passed and it should be one of IPv4 or IPv6
try:
ether_type = rule.l2.config.ethertype
except Exception as e:
raise AclLoaderException("l2:ethertype must be provided for rule #{} in table:{} of type L3V4V6".format(rule_idx, table_name))
if ether_type not in ["ETHERTYPE_IPV4", "ETHERTYPE_IPV6"]:
# Ether type must be v4 or v6 to match IP fields, L4 (TCP/UDP) fields or ICMP fields
if rule.ip or rule.transport or rule.icmp:
raise AclLoaderException("ethertype={} is neither ETHERTYPE_IPV4 nor ETHERTYPE_IPV6 for IP rule #{} in table:{} type L3V4V6".format(rule.l2.config.ethertype, rule_idx, table_name))
elif self.is_table_l3v6(table_name):
rule_props["IP_TYPE"] = "IPV6ANY" # ETHERTYPE is not supported for DATAACLV6
elif self.is_table_l3(table_name):
rule_props["ETHER_TYPE"] = str(self.ethertype_map["ETHERTYPE_IPV4"])
Expand Down Expand Up @@ -679,6 +699,8 @@ def deny_rule(self, table_name):
rule_props["PACKET_ACTION"] = "DROP"
if self.is_table_ipv6(table_name):
rule_props["IP_TYPE"] = "IPV6ANY" # ETHERTYPE is not supported for DATAACLV6
elif self.is_table_l3v4v6(table_name):
rule_props["IP_TYPE"] = "IP" # Drop both v4 and v6 packets
else:
rule_props["ETHER_TYPE"] = str(self.ethertype_map["ETHERTYPE_IPV4"])
return rule_data
Expand Down
84 changes: 84 additions & 0 deletions tests/acl_input/acl1.json
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,90 @@
}
}
}
},
"DATAACLV4V6": {
"acl-entries": {
"acl-entry": {
"1": {
"config": {
"sequence-id": 1
},
"actions": {
"config": {
"forwarding-action": "ACCEPT"
}
},
"l2": {
"config": {
"vlan-id": "369",
"ethertype": "ETHERTYPE_IPV4"
}
},
"ip": {
"config": {
"protocol": "IP_TCP",
"source-ip-address": "20.0.0.2/32",
"destination-ip-address": "30.0.0.3/32"
}
}
},
"2": {
"config": {
"sequence-id": 2
},
"actions": {
"config": {
"forwarding-action": "ACCEPT"
}
},
"l2": {
"config": {
"ethertype": "ETHERTYPE_IPV6"
}
},
"ip": {
"config": {
"protocol": "IP_ICMP",
"source-ip-address": "::1/128",
"destination-ip-address": "::1/128"
}
},
"icmp": {
"config": {
"type": "1",
"code": "0"
}
}
},
"3": {
"config": {
"sequence-id": 3
},
"actions": {
"config": {
"forwarding-action": "ACCEPT"
}
},
"l2": {
"config": {
"ethertype": "ETHERTYPE_IPV6"
}
},
"ip": {
"config": {
"protocol": "IP_ICMP",
"source-ip-address": "::1/128",
"destination-ip-address": "::1/128"
}
},
"icmp": {
"config": {
"type": "128"
}
}
}
}
}
}
}
}
Expand Down
86 changes: 86 additions & 0 deletions tests/acl_input/illegal_v4v6_rule_no_ethertype.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"acl": {
"acl-sets": {
"acl-set": {
"DATAACLV4V6": {
"acl-entries": {
"acl-entry": {
"1": {
"config": {
"sequence-id": 1
},
"actions": {
"config": {
"forwarding-action": "ACCEPT"
}
},
"ip": {
"config": {
"protocol": "IP_TCP",
"source-ip-address": "20.0.0.2/32",
"destination-ip-address": "30.0.0.3/32"
}
}
},
"2": {
"config": {
"sequence-id": 2
},
"actions": {
"config": {
"forwarding-action": "ACCEPT"
}
},
"l2": {
"config": {
"ethertype": "ETHERTYPE_IPV6"
}
},
"ip": {
"config": {
"protocol": "IP_ICMP",
"source-ip-address": "::1/128",
"destination-ip-address": "::1/128"
}
},
"icmp": {
"config": {
"type": "1",
"code": "0"
}
}
},
"3": {
"config": {
"sequence-id": 3
},
"actions": {
"config": {
"forwarding-action": "ACCEPT"
}
},
"l2": {
"config": {
"ethertype": "ETHERTYPE_IPV6"
}
},
"ip": {
"config": {
"protocol": "IP_ICMP",
"source-ip-address": "::1/128",
"destination-ip-address": "::1/128"
}
},
"icmp": {
"config": {
"type": "128"
}
}
}
}
}
}
}
}
}
}
41 changes: 40 additions & 1 deletion tests/acl_loader_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def test_acl_empty(self):

def test_valid(self):
yang_acl = AclLoader.parse_acl_json(os.path.join(test_path, 'acl_input/acl1.json'))
assert len(yang_acl.acl.acl_sets.acl_set) == 6
assert len(yang_acl.acl.acl_sets.acl_set) == 7

def test_invalid(self):
with pytest.raises(AclLoaderException):
Expand Down Expand Up @@ -95,6 +95,40 @@ def test_ethertype_translation(self, acl_loader):
"PRIORITY": "9997"
}

def test_v4_rule_inv4v6_table(self, acl_loader):
acl_loader.rules_info = {}
acl_loader.load_rules_from_file(os.path.join(test_path, 'acl_input/acl1.json'))
assert acl_loader.rules_info[("DATAACLV4V6", "RULE_1")]
assert acl_loader.rules_info[("DATAACLV4V6", "RULE_1")] == {
"VLAN_ID": 369,
"ETHER_TYPE": 2048,
"IP_PROTOCOL": 6,
"SRC_IP": "20.0.0.2/32",
"DST_IP": "30.0.0.3/32",
"PACKET_ACTION": "FORWARD",
"PRIORITY": "9999"
}

def test_v6_rule_inv4v6_table(self, acl_loader):
acl_loader.rules_info = {}
acl_loader.load_rules_from_file(os.path.join(test_path, 'acl_input/acl1.json'))
assert acl_loader.rules_info[("DATAACLV4V6", "RULE_2")]
assert acl_loader.rules_info[("DATAACLV4V6", "RULE_2")] == {
"ETHER_TYPE": 34525,
"IP_PROTOCOL": 58,
"SRC_IPV6": "::1/128",
"DST_IPV6": "::1/128",
"PACKET_ACTION": "FORWARD",
"PRIORITY": "9998",
'ICMPV6_CODE': 0,
'ICMPV6_TYPE': 1
}

def test_rule_without_ethertype_inv4v6(self, acl_loader):
acl_loader.rules_info = {}
acl_loader.load_rules_from_file(os.path.join(test_path, 'acl_input/illegal_v4v6_rule_no_ethertype.json'))
assert not acl_loader.rules_info.get("RULE_1")

def test_icmp_translation(self, acl_loader):
acl_loader.rules_info = {}
acl_loader.load_rules_from_file(os.path.join(test_path, 'acl_input/acl1.json'))
Expand Down Expand Up @@ -148,6 +182,11 @@ def test_ingress_default_deny_rule(self, acl_loader):
'PACKET_ACTION': 'DROP',
'IP_TYPE': 'IPV6ANY'
}
assert acl_loader.rules_info[('DATAACLV4V6', 'DEFAULT_RULE')] == {
'PRIORITY': '1',
'PACKET_ACTION': 'DROP',
'IP_TYPE': 'IP'
}

def test_egress_no_default_deny_rule(self, acl_loader):
acl_loader.rules_info = {}
Expand Down
2 changes: 1 addition & 1 deletion tests/aclshow_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
# Expected output for aclshow -r RULE_4,RULE_6 -vv
rule4_rule6_verbose_output = '' + \
"""Reading ACL info...
Total number of ACL Tables: 12
Total number of ACL Tables: 13
Total number of ACL Rules: 21
RULE NAME TABLE NAME PRIO PACKETS COUNT BYTES COUNT
Expand Down
11 changes: 11 additions & 0 deletions tests/mock_tables/config_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,17 @@
"type": "L3",
"stage": "ingress"
},
"ACL_TABLE|DATAACLV4V6": {
"expireat": 1602451533.237415,
"ttl": -0.001,
"type": "hash",
"value": {
"policy_desc": "DATAACLV4V6",
"ports@": "PortChannel0002,PortChannel0005,PortChannel0008,PortChannel0011,PortChannel0014,PortChannel0017,PortChannel0020,PortChannel0023,Ethernet64,Ethernet68,Ethernet72,Ethernet76,Ethernet80,Ethernet84,Ethernet88,Ethernet92,Ethernet96,Ethernet100,Ethernet104,Ethernet108,Ethernet112,Ethernet116,Ethernet120,Ethernet124",
"stage": "ingress",
"type": "L3V4V6"
}
},
"ACL_TABLE|EVERFLOW": {
"policy_desc": "EVERFLOW",
"ports@": "PortChannel0002,PortChannel0005,PortChannel0008,PortChannel0011,PortChannel0014,PortChannel0017,PortChannel0020,PortChannel0023,Ethernet100,Ethernet104,Ethernet92,Ethernet96,Ethernet84,Ethernet88,Ethernet76,Ethernet80,Ethernet108,Ethernet112,Ethernet64,Ethernet120,Ethernet116,Ethernet124,Ethernet72,Ethernet68",
Expand Down

0 comments on commit b200fc6

Please sign in to comment.