diff --git a/src/common/type_checkers/Checkers.py b/src/common/type_checkers/Checkers.py index 694f1410212137347badbba759cac1a64b1e1c92..e797d64414847aabb402f0bbec17dd65f9c7ec6b 100644 --- a/src/common/type_checkers/Checkers.py +++ b/src/common/type_checkers/Checkers.py @@ -140,6 +140,15 @@ def chk_address_ipv4(ip_addr : str): except ValueError: return False +def chk_prefix_len_ipv4(ip_prefix_len : int): + """ + Check whether input integer is a valid IPv4 address prefix length. + + :param ip_prefix_len: IPv4 address prefix length + :return: boolean status + """ + return 0 <= ip_prefix_len <= 32 + def chk_address_ipv6(ip_addr : str): """ Check whether input string is a valid IPv6 address or not. diff --git a/src/service/service/service_handlers/p4_fabric_tna_commons/p4_fabric_tna_commons.py b/src/service/service/service_handlers/p4_fabric_tna_commons/p4_fabric_tna_commons.py index 4b60f91185aa739fbf182bdf070516389c409e5b..a97bce07fb77cfda222eb2485018b944e6569f4c 100644 --- a/src/service/service/service_handlers/p4_fabric_tna_commons/p4_fabric_tna_commons.py +++ b/src/service/service/service_handlers/p4_fabric_tna_commons/p4_fabric_tna_commons.py @@ -24,19 +24,37 @@ SD-Fabric docs: https://docs.sd-fabric.org/master/index.html import time import logging import struct -from common.proto.context_pb2 import ConfigActionEnum, ConfigRule -from common.tools.object_factory.ConfigRule import json_config_rule -from common.type_checkers.Checkers import chk_address_mac, chk_vlan_id, \ - chk_address_ipv4, chk_transport_port from random import randint from typing import List, Tuple +from common.proto.context_pb2 import ConfigActionEnum, ConfigRule, Device, EndPoint +from common.tools.object_factory.ConfigRule import json_config_rule +from common.type_checkers.Checkers import chk_address_mac, chk_vlan_id, \ + chk_address_ipv4, chk_prefix_len_ipv4, chk_transport_port +from service.service.task_scheduler.TaskExecutor import TaskExecutor LOGGER = logging.getLogger(__name__) # Common service handler settings -TARGET_P4_ARCH = "target_p4_arch" -SWITCH_DATAPLANE_ID_MAP = "switch_dataplane_id_map" +SWITCH_INFO = "switch_info" +ARCH = "arch" +DPID = "dpid" +MAC = "mac" +IP = "ip" +PORT = "port" # Dataplane port +PORT_ID = "port_id" +PORT_TYPE = "port_type" VLAN_ID = "vlan_id" +RECIRCULATION_PORT_LIST = "recirculation_port_list" +PORT_LIST = "port_list" +PORT_PREFIX = "port-" +ROUTING_LIST = "routing_list" +MAC_SRC = "mac_src" +MAC_DST = "mac_dst" +IPV4_SRC = "ipv4_src" +IPV4_DST = "ipv4_dst" +IPV4_PREFIX_LEN = "ipv4_prefix_len" +TRN_PORT_SRC = "trn_port_src" # Transport network port (TCP, UDP) +TRN_PORT_DST = "trn_port_dst" # P4 architectures TARGET_ARCH_TNA = "tna" @@ -140,7 +158,7 @@ def generate_random_mac() -> str: return mac_str -def prefix_to_hex_mask(prefix_len): +def prefix_to_hex_mask(prefix_len : int) -> str: # Calculate the binary mask binary_mask = (1 << 32) - (1 << (32 - prefix_len)) @@ -156,6 +174,30 @@ def sleep_for(time_sec : int) -> None: assert time_sec > 0, "Invalid sleep period in seconds" time.sleep(time_sec) +def find_port_id_in_endpoint(endpoint : EndPoint, target_endpoint_uuid : str) -> int: # type: ignore + assert endpoint, "Invalid device endpoint" + endpoint_uuid = endpoint.endpoint_id.endpoint_uuid.uuid + assert endpoint_uuid, "Invalid device endpoint UUID" + if endpoint_uuid == target_endpoint_uuid: + try: + dpid = int(endpoint.name) # P4 devices have integer dataplane port IDs + assert dpid > 0, "Invalid device endpoint DPID" + except Exception as ex: + LOGGER.error(ex) + return -1 + return dpid + + return -1 + +def find_port_id_in_endpoint_list(endpoint_list : List, target_endpoint_uuid : str) -> int: + assert endpoint_list, "Invalid device endpoint list" + for endpoint in endpoint_list: + result = find_port_id_in_endpoint(endpoint, target_endpoint_uuid) + if result != -1: + return result + + return -1 + ################################################################################################################ ### Rule generation methods ################################################################################################################ @@ -173,6 +215,9 @@ def rules_set_up_port_ingress( assert port_type.lower() in PORT_TYPES_STR_VALID, "Invalid port type to configure ingress port" assert chk_vlan_id(vlan_id), "Invalid VLAN ID to configure ingress port" + # VLAN support if 1 + vlan_is_valid = 1 if vlan_id != VLAN_DEF else 0 + rule_no = cache_rule(TABLE_INGRESS_VLAN, action) port_type_int = PORT_TYPE_MAP[port_type.lower()] @@ -192,7 +237,7 @@ def rules_set_up_port_ingress( }, { 'match-field': 'vlan_is_valid', - 'match-value': '0' + 'match-value': str(vlan_is_valid) } ], 'action-name': 'FabricIngress.filtering.permit_with_internal_vlan', @@ -270,7 +315,7 @@ def rules_set_up_fwd_classifier( 'match-value': str(ingress_port) }, { - 'match-field': 'eth_type', + 'match-field': 'ip_eth_type', 'match-value': eth_type } ], @@ -278,10 +323,10 @@ def rules_set_up_fwd_classifier( 'action-params': [ { 'action-param': 'fwd_type', - 'action-value': str(FORWARDING_TYPE_UNICAST_IPV4) + 'action-value': str(fwd_type) }, ], - 'priority': 10 + 'priority': 1 } ) ) @@ -294,7 +339,7 @@ def rules_set_up_port( fwd_type : int, vlan_id : int, action : ConfigActionEnum, # type: ignore - eth_type=ETHER_TYPE_IPV4): + eth_type=ETHER_TYPE_IPV4) -> List [Tuple]: rules_list = [] rules_list.extend( @@ -377,12 +422,8 @@ def rules_set_up_fwd_bridging( def rules_set_up_next_output_simple( egress_port : int, - eth_src : str, - eth_dst : str, action : ConfigActionEnum) -> List [Tuple]: # type: ignore assert egress_port >= 0, "Invalid outport to configure next output simple" - assert chk_address_mac(eth_src), "Invalid source Ethernet address to configure next output simple" - assert chk_address_mac(eth_dst), "Invalid destination Ethernet address to configure next output simple" rule_no = cache_rule(TABLE_NEXT_SIMPLE, action) @@ -478,9 +519,11 @@ def rules_set_up_next_output_hashed( def rules_set_up_routing( ipv4_dst : str, + ipv4_prefix_len : int, egress_port : int, action : ConfigActionEnum) -> List [Tuple]: # type: ignore assert chk_address_ipv4(ipv4_dst), "Invalid destination IPv4 address to configure routing" + assert chk_prefix_len_ipv4(ipv4_prefix_len), "Invalid IPv4 prefix length" assert egress_port >= 0, "Invalid outport to configure routing" rule_no = cache_rule(TABLE_ROUTING_V4, action) @@ -495,7 +538,7 @@ def rules_set_up_routing( 'match-fields': [ { 'match-field': 'ipv4_dst', - 'match-value': ipv4_dst + 'match-value': ipv4_dst + "/" + str(ipv4_prefix_len) } ], 'action-name': 'FabricIngress.forwarding.set_next_id_routing_v4', @@ -694,11 +737,14 @@ def rules_set_up_acl_filter_host( ingress_port : int, ip_address : str, prefix_len : int, + ip_direction : str, action : ConfigActionEnum) -> List [Tuple]: # type: ignore assert ingress_port >= 0, "Invalid ingress port to configure ACL" assert chk_address_ipv4(ip_address), "Invalid IP address to configure ACL" assert 0 < prefix_len <= 32, "Invalid IP address prefix length to configure ACL" + ip_match = "ipv4_src" if ip_direction == "src" else "ipv4_dst" + prefix_len_hex = prefix_to_hex_mask(prefix_len) rule_no = cache_rule(TABLE_ACL, action) @@ -716,7 +762,7 @@ def rules_set_up_acl_filter_host( 'match-value': str(ingress_port) }, { - 'match-field': 'ipv4_src', + 'match-field': ip_match, 'match-value': '%s&&&%s' % (ip_address, prefix_len_hex) } ], @@ -732,10 +778,13 @@ def rules_set_up_acl_filter_host( def rules_set_up_acl_filter_port( ingress_port : int, transport_port : int, + transport_direction : str, action : ConfigActionEnum) -> List [Tuple]: # type: ignore assert ingress_port >= 0, "Invalid ingress port to configure ACL" assert chk_transport_port(transport_port), "Invalid transport port to configure ACL" + trn_match = "l4_sport" if transport_direction == "src" else "l4_dport" + rule_no = cache_rule(TABLE_ACL, action) rules_acl = [] @@ -751,7 +800,7 @@ def rules_set_up_acl_filter_port( 'match-value': str(ingress_port) }, { - 'match-field': 'l4_dport', + 'match-field': trn_match, 'match-value': str(transport_port) } ], @@ -772,7 +821,10 @@ def rules_set_up_acl_filter_port( ### Rule management methods ################################################################################################################ -def apply_rules(task_executor, device_obj, json_config_rules): +def apply_rules( + task_executor : TaskExecutor, + device_obj : Device, # type: ignore + json_config_rules : List): # type: ignore applied_rules = 0 failed_rules = 0 total_rules = len(json_config_rules) @@ -802,9 +854,9 @@ def apply_rules(task_executor, device_obj, json_config_rules): except Exception as ex: LOGGER.error("Error while applying rule #{}: {}".format(i, ex)) failed_rules += 1 + raise Exception(ex) - LOGGER.info("Batch rules: {}/{} applied".format(applied_rules, total_rules)) - LOGGER.info("Batch rules: {}/{} failed".format(failed_rules, total_rules)) + LOGGER.debug("Batch rules: {}/{} applied".format(applied_rules, total_rules)) return applied_rules, failed_rules diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py index 51fc42a5a5ea06d5abaa49946a154d0c38f6de8b..8f797882f86f4d53c61da22964909ab1a808ba53 100644 --- a/src/service/service/task_scheduler/TaskExecutor.py +++ b/src/service/service/task_scheduler/TaskExecutor.py @@ -203,7 +203,7 @@ class TaskExecutor: self, service_id : ServiceId, config_key : str, config_value : str ): service_configRule = ServiceConfigRule() - service_configRule.service_id.CopyFrom( service_id) + service_configRule.service_id.CopyFrom(service_id) service_configRule.configrule_custom.resource_key = config_key service_configRule.configrule_custom.resource_value = config_value try: diff --git a/src/tests/tools/test_tools_p4.py b/src/tests/tools/test_tools_p4.py index 4557fef61e1f495706a28a5b5646ff97edcfaa54..65257aefc0e0a52e2b1df4753c7ecef1416581d1 100644 --- a/src/tests/tools/test_tools_p4.py +++ b/src/tests/tools/test_tools_p4.py @@ -28,9 +28,9 @@ P4_DEV_NB = 1 CONNECTION_RULES = 3 ENDPOINT_RULES = 3 INT_RULES = 19 -L2_RULES = 8 -L3_RULES = 8 -ACL_RULES = 1 +L2_RULES = 10 +L3_RULES = 4 +ACL_RULES = 2 DATAPLANE_RULES_NB_INT_B1 = 5 DATAPLANE_RULES_NB_INT_B2 = 6