Commit a32bf271 authored by Georgios P. Katsikas's avatar Georgios P. Katsikas
Browse files

feat: added flexibity in SD-FABRIC library for custom L2/L3 handling

parent 50c20c5b
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -407,6 +407,8 @@ class P4FabricACLServiceHandler(_ServiceHandler):

                    # Retrieve entry from the port map
                    switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id)
                    if not switch_port_entry:
                        continue

                    # Add routing entry
                    switch_port_entry[ACL].append(map_entry)
@@ -429,9 +431,9 @@ class P4FabricACLServiceHandler(_ServiceHandler):
        switch_entry = self.__port_map[switch_name]
        assert switch_entry, f"Switch {switch_name} does not exist in the port map"
        port_key = PORT_PREFIX + str(port_id)
        assert switch_entry[port_key], f"Port with ID {port_id} does not exist in the switch map"

        if port_key in switch_entry:
            return switch_entry[port_key]
        return {}

    def _get_acl_of_switch_port(self, switch_name : str, port_id : int) -> List [Tuple]:
        switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id)
+46 −6
Original line number Diff line number Diff line
@@ -44,11 +44,14 @@ IP = "ip"
PORT = "port"                        # Dataplane port
PORT_ID = "port_id"
PORT_TYPE = "port_type"
NEXT_ID = "next_id"
VLAN_ID = "vlan_id"
RECIRCULATION_PORT_LIST = "recirculation_port_list"
PORT_LIST = "port_list"
PORT_PREFIX = "port-"
FORWARDING_TYPE = "fwd_type"
FORWARDING_LIST = "fwd_list"
ROUTING_TYPE = "routing_type"
ROUTING_LIST = "routing_list"
HOST_LIST = "host_list"
HOST_MAC = "host_mac"
@@ -90,7 +93,7 @@ CLONE_SESSION = "/clone_sessions/clone_session"
# Forwarding types
FORWARDING_TYPE_BRIDGING = 0
FORWARDING_TYPE_MPLS = 1
FORWARDING_TYPE_UNICAST_IPV4 = 2
FORWARDING_TYPE_IPV4_UNICAST = 2
FORWARDING_TYPE_IPV4_MULTICAST = 3
FORWARDING_TYPE_IPV6_UNICAST = 4
FORWARDING_TYPE_IPV6_MULTICAST = 5
@@ -99,13 +102,50 @@ FORWARDING_TYPE_UNKNOWN = 7
FORWARDING_TYPES_VALID = [
    FORWARDING_TYPE_BRIDGING,
    FORWARDING_TYPE_MPLS,
    FORWARDING_TYPE_UNICAST_IPV4,
    FORWARDING_TYPE_IPV4_UNICAST,
    FORWARDING_TYPE_IPV4_MULTICAST,
    FORWARDING_TYPE_IPV6_UNICAST,
    FORWARDING_TYPE_IPV6_MULTICAST,
    FORWARDING_TYPE_UNKNOWN
]

FORWARDING_TYPE_STR_BRIDGING = "bridging"
FORWARDING_TYPE_STR_MPLS = "mpls"
FORWARDING_TYPE_STR_IPV4_UNICAST = "ipv4-unicast"
FORWARDING_TYPE_STR_IPV4_MULTICAST = "ipv4-multicast"
FORWARDING_TYPE_STR_IPV6_UNICAST = "ipv6-unicast"
FORWARDING_TYPE_STR_IPV6_MULTICAST = "ipv6-multicast"
FORWARDING_TYPE_STR_UNKNOWN = "unknown"

FORWARDING_TYPES_STR_VALID = [
    FORWARDING_TYPE_STR_BRIDGING,
    FORWARDING_TYPE_STR_MPLS,
    FORWARDING_TYPE_STR_IPV4_UNICAST,
    FORWARDING_TYPE_STR_IPV4_MULTICAST,
    FORWARDING_TYPE_STR_IPV6_UNICAST,
    FORWARDING_TYPE_STR_IPV6_MULTICAST,
    FORWARDING_TYPE_STR_UNKNOWN
]

FWD_TYPE_MAP = {
    FORWARDING_TYPE_STR_BRIDGING       : FORWARDING_TYPE_BRIDGING,
    FORWARDING_TYPE_STR_MPLS           : FORWARDING_TYPE_MPLS,
    FORWARDING_TYPE_STR_IPV4_UNICAST   : FORWARDING_TYPE_IPV4_UNICAST,
    FORWARDING_TYPE_STR_IPV4_MULTICAST : FORWARDING_TYPE_IPV4_MULTICAST,
    FORWARDING_TYPE_STR_IPV6_UNICAST   : FORWARDING_TYPE_IPV6_UNICAST,
    FORWARDING_TYPE_STR_IPV6_MULTICAST : FORWARDING_TYPE_IPV6_MULTICAST,
    FORWARDING_TYPE_STR_UNKNOWN        : FORWARDING_TYPE_UNKNOWN
}

# Routing types
ROUTING_TYPE_STR_SIMPLE = "simple"
ROUTING_TYPE_STR_HASHED = "hashed"

ROUTING_TYPES_STR_VALID = [
    ROUTING_TYPE_STR_SIMPLE,
    ROUTING_TYPE_STR_HASHED
]

# Port types
PORT_TYPE_INT = "int"
PORT_TYPE_HOST = "host"
@@ -555,7 +595,7 @@ def rules_set_up_next_profile_hashed_output(
                'action-params': [
                    {
                        'action-param': 'port_num',
                        'action-value': str(next_id)
                        'action-value': str(next_id)  # TODO: Fix
                    }
                ]
            }
@@ -595,7 +635,7 @@ def rules_set_up_next_output_simple(
                'action-params': [
                    {
                        'action-param': 'port_num',
                        'action-value': str(next_id)
                        'action-value': str(port_id)
                    }
                ]
            }
@@ -679,7 +719,7 @@ def rules_set_up_next_profile_hashed_routing(
                'action-params': [
                    {
                        'action-param': 'port_num',
                        'action-value': str(next_id)
                        'action-value': str(next_id)  # TODO: Fix
                    },
                    {
                        'action-param': 'smac',
@@ -778,7 +818,7 @@ def rules_set_up_next_routing_simple(
                'action-params': [
                    {
                        'action-param': 'port_num',
                        'action-value': str(next_id)
                        'action-value': str(port_id)
                    },
                    {
                        'action-param': 'smac',
+101 −28
Original line number Diff line number Diff line
@@ -332,11 +332,23 @@ class P4FabricINTServiceHandler(_ServiceHandler):
                    assert sw_info[ARCH] in SUPPORTED_TARGET_ARCH_LIST, \
                        f"Switch {switch_name} - Supported P4 architectures are: {','.join(SUPPORTED_TARGET_ARCH_LIST)}"
                    assert sw_info[DPID] > 0, f"Switch {switch_name} - P4 switch dataplane ID {sw_info[DPID]} must be a positive integer"

                    fwd_type_str = sw_info[FORWARDING_TYPE]
                    assert fwd_type_str in FORWARDING_TYPES_STR_VALID, \
                        f"Switch {switch_name} - Supported forwarding types are: {','.join(FORWARDING_TYPES_STR_VALID)}"
                    fwd_type_int = FWD_TYPE_MAP[fwd_type_str]
                    assert fwd_type_int in FORWARDING_TYPES_VALID, \
                        f"Switch {switch_name} - Supported forwarding types are: {','.join(FORWARDING_TYPES_VALID)}"
                    routing_type_str = sw_info[ROUTING_TYPE]
                    assert routing_type_str in ROUTING_TYPES_STR_VALID, \
                        f"Switch {switch_name} - Supported routing types are: {','.join(ROUTING_TYPES_STR_VALID)}"

                    assert chk_address_mac(sw_info[MAC]), f"Switch {switch_name} - Invalid source Ethernet address"
                    assert chk_address_ipv4(sw_info[IP]), f"Switch {switch_name} - Invalid source IP address"
                    assert isinstance(sw_info[PORT_INT], dict), f"Switch {switch_name} - INT port object must be a map with port_id and port_type items"
                    assert sw_info[PORT_INT][PORT_ID] >= 0, f"Switch {switch_name} - Invalid P4 switch port ID"
                    assert sw_info[PORT_INT][PORT_TYPE] in PORT_TYPES_STR_VALID, f"Switch {switch_name} - Valid P4 switch port types are: {','.join(PORT_TYPES_STR_VALID)}"
                    assert sw_info[PORT_INT][NEXT_ID] >= 0, f"Switch {switch_name} - Invalid P4 switch next ID"
                    if arch_tna(sw_info[ARCH]):
                        sw_info[RECIRCULATION_PORT_LIST] = RECIRCULATION_PORTS_TNA
                        sw_info[INT_REPORT_MIRROR_ID_LIST] = INT_REPORT_MIRROR_ID_LIST_TNA
@@ -391,10 +403,13 @@ class P4FabricINTServiceHandler(_ServiceHandler):
            LOGGER.info(f"\t Device {switch_name}")
            LOGGER.info(f"\t\t|  Target P4 architecture: {switch_info[ARCH]}")
            LOGGER.info(f"\t\t|           Data plane ID: {switch_info[DPID]}")
            LOGGER.info(f"\t\t|         Forwarding type: {switch_info[FORWARDING_TYPE]}")
            LOGGER.info(f"\t\t|            Routing type: {switch_info[ROUTING_TYPE]}")
            LOGGER.info(f"\t\t|      Source MAC address: {switch_info[MAC]}")
            LOGGER.info(f"\t\t|      Source  IP address: {switch_info[IP]}")
            LOGGER.info(f"\t\t|           INT port   ID: {switch_info[PORT_INT][PORT_ID]}")
            LOGGER.info(f"\t\t|           INT port type: {switch_info[PORT_INT][PORT_TYPE]}")
            LOGGER.info(f"\t\t|           INT port next: {switch_info[PORT_INT][NEXT_ID]}")
            LOGGER.info(f"\t\t| Recirculation port list: {switch_info[RECIRCULATION_PORT_LIST]}")
            LOGGER.info(f"\t\t|   Report mirror ID list: {switch_info[INT_REPORT_MIRROR_ID_LIST]}")
        LOGGER.info(f"--- INT collector interface: {self.__int_collector_iface}")
@@ -406,12 +421,22 @@ class P4FabricINTServiceHandler(_ServiceHandler):
        LOGGER.info(f"--- INT collector  interval: {self.__int_collector_interval_s} sec")
        LOGGER.info("-----------------------------------------------------------------")

    def _get_fwd_type_of_switch(self, switch_name : str) -> int:
        fwd_type_str = self.__switch_info[switch_name][FORWARDING_TYPE]
        return FWD_TYPE_MAP[fwd_type_str]

    def _get_routing_type_of_switch(self, switch_name : str) -> int:
        return self.__switch_info[switch_name][ROUTING_TYPE]

    def _create_rules(self, device_obj : Device, action : ConfigActionEnum): # type: ignore
        dev_name = device_obj.name
        rules  = []

        fwd_type = self._get_fwd_type_of_switch(dev_name)
        routing_type = self._get_routing_type_of_switch(dev_name)

        port_id = self.__switch_info[dev_name][PORT_INT][PORT_ID]
        next_id = port_id
        next_id = self.__switch_info[dev_name][PORT_INT][NEXT_ID]
        mac_src = self.__switch_info[dev_name][MAC]
        collector_mac_dst = self.__int_collector_mac
        collector_ip_dst = self.__int_collector_ip
@@ -428,7 +453,7 @@ class P4FabricINTServiceHandler(_ServiceHandler):
            rules += rules_set_up_int_recirculation_ports(
                recirculation_port_list=self.__switch_info[dev_name][RECIRCULATION_PORT_LIST],
                port_type=PORT_TYPE_INT,
                fwd_type=FORWARDING_TYPE_UNICAST_IPV4,
                fwd_type=FORWARDING_TYPE_IPV4_UNICAST, # For INT packets, fwd type is fixed to IPv4 unicast
                vlan_id=vlan_id,
                action=action
            )
@@ -472,7 +497,7 @@ class P4FabricINTServiceHandler(_ServiceHandler):
            rules += rules_set_up_port(
                port_id=port_id,
                port_type=PORT_TYPE_HOST,
                fwd_type=FORWARDING_TYPE_BRIDGING,
                fwd_type=fwd_type,       # Normally this is bridging
                vlan_id=vlan_id,
                action=action
            )
@@ -480,7 +505,8 @@ class P4FabricINTServiceHandler(_ServiceHandler):
            LOGGER.error("Error while creating INT port rules")
            raise Exception(ex)

        ### INT port forwarding rules
        ### INT forwarding rules
        if fwd_type == FORWARDING_TYPE_BRIDGING:
            try:
                rules += rules_set_up_fwd_bridging(
                    port_id=port_id,
@@ -489,6 +515,12 @@ class P4FabricINTServiceHandler(_ServiceHandler):
                    next_id=next_id,
                    action=action
                )
            except Exception as ex:
                LOGGER.error("Error while creating INT bridging rule")
                raise Exception(ex)

        if routing_type == ROUTING_TYPE_STR_HASHED:
            try:
                rules += rules_set_up_next_profile_hashed_routing(
                    port_id=port_id,
                    next_id=next_id,
@@ -497,16 +529,57 @@ class P4FabricINTServiceHandler(_ServiceHandler):
                    action=action
                )
            except Exception as ex:
            LOGGER.error("Error while creating INT bridging rules")
                LOGGER.error("Error while creating INT next hashed profile rule")
                raise Exception(ex)
        elif routing_type == ROUTING_TYPE_STR_SIMPLE:
            try:
                rules += rules_set_up_pre_next_vlan(
                    port_id=port_id,
                    next_id=next_id,
                    vlan_id=vlan_id,
                    action=action
                )
            except Exception as ex:
                LOGGER.error("Error while creating INT pre-next VLAN rule")
                raise Exception(ex)

            try:
                rules += rules_set_up_next_output_simple(
                    port_id=port_id,
                    next_id=next_id,
                    action=action
                )
            except Exception as ex:
                LOGGER.error("Error while creating INT next output simple rule")
                raise Exception(ex)

        ### INT packet routing rules
        if routing_type == ROUTING_TYPE_STR_HASHED:
            try:
                rules += rules_set_up_next_hashed(
                    port_id=port_id,
                    next_id=next_id,
                    action=action
                )
            except Exception as ex:
                LOGGER.error("Error while creating INT next hashed routing rule")
                raise Exception(ex)
        elif routing_type == ROUTING_TYPE_STR_SIMPLE:
            try:
                ### Next routing simple
                rules += rules_set_up_next_routing_simple(
                    port_id=port_id,
                    next_id=next_id,
                    eth_src=mac_src,
                    eth_dst=collector_mac_dst,
                    action=action
                )
            except Exception as ex:
                LOGGER.error("Error while creating INT next simple routing rule")
                raise Exception(ex)

        try:
            # Routing destination
            rules += rules_set_up_routing(
                port_id=port_id,
                ipv4_dst=collector_ip_dst,
@@ -515,7 +588,7 @@ class P4FabricINTServiceHandler(_ServiceHandler):
                action=action
            )
        except Exception as ex:
            LOGGER.error("Error while creating INT routing rules")
            LOGGER.error("Error while creating static INT L3 routing rule")
            raise Exception(ex)

        return rules
+94 −31
Original line number Diff line number Diff line
@@ -102,6 +102,11 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler):
            if dev_port_key in visited:
                continue

            # Skip device ports without associated rules
            if not self._get_switch_port_in_port_map(device_name, port_id):
                LOGGER.warning(f"No rules associated with port {port_id} on device {device.name}")
                continue

            rules = []
            actual_rules = -1
            applied_rules, failed_rules = 0, -1
@@ -177,6 +182,11 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler):
            if dev_port_key in visited:
                continue

            # Skip device ports without associated rules
            if not self._get_switch_port_in_port_map(device_name, port_id):
                LOGGER.warning(f"No rules associated with port {port_id} on device {device.name}")
                continue

            rules = []
            actual_rules = -1
            applied_rules, failed_rules = 0, -1
@@ -331,6 +341,10 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler):
                    f"Switch {switch_name} - Supported P4 architectures are: {','.join(SUPPORTED_TARGET_ARCH_LIST)}"
                switch_dpid = sw_info[DPID]
                assert switch_dpid > 0, f"Switch {switch_name} - P4 switch dataplane ID {sw_info[DPID]} must be a positive integer"
                sw_info[FORWARDING_TYPE] = FORWARDING_TYPE_STR_BRIDGING
                routing_type_str = sw_info[ROUTING_TYPE]
                assert routing_type_str in ROUTING_TYPES_STR_VALID, \
                    f"Switch {switch_name} - Supported routing types are: {','.join(ROUTING_TYPES_STR_VALID)}"

                # Port list
                port_list = sw_info[PORT_LIST]
@@ -352,7 +366,7 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler):
                    self.__port_map[switch_name][port_key][PORT_ID] = port_id
                    self.__port_map[switch_name][port_key][PORT_TYPE] = port_type
                    self.__port_map[switch_name][port_key][VLAN_ID] = vlan_id
                    self.__port_map[switch_name][port_key][FORWARDING_LIST] = []
                    self.__port_map[switch_name][port_key][FORWARDING_LIST] = {}

                # Forwarding list
                fwd_list = sw_info[FORWARDING_LIST]
@@ -360,15 +374,25 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler):
                for fwd_entry in fwd_list:
                    port_id = fwd_entry[PORT_ID]
                    assert port_id >= 0, f"Invalid port ID: {port_id}"
                    next_id = fwd_entry[NEXT_ID]
                    assert next_id >= 0, f"Invalid next ID: {next_id}"
                    host_mac = fwd_entry[HOST_MAC]
                    assert chk_address_mac(host_mac), f"Invalid host MAC address {host_mac}"

                    # Retrieve entry from the port map
                    switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id)
                    if not switch_port_entry:
                        continue

                    host_facing_port = self._is_host_facing_port(switch_name, port_id)
                    LOGGER.info(f"Switch {switch_name} - Port {port_id}: Is host facing: {"True" if host_facing_port else "False"}")
                    switch_port_entry[FORWARDING_LIST].append(host_mac)
                    switch_port_entry[FORWARDING_LIST].append(
                        {
                            PORT_ID: port_id,
                            NEXT_ID: next_id,
                            HOST_MAC: host_mac
                        }
                    )
                self.__switch_info[switch_name] = sw_info

    def _print_settings(self):
@@ -378,18 +402,27 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler):
            LOGGER.info(f"\t Device {switch_name}")
            LOGGER.info(f"\t\t| Target P4 architecture: {switch_info[ARCH]}")
            LOGGER.info(f"\t\t|          Data plane ID: {switch_info[DPID]}")
            LOGGER.info(f"\t\t|        Forwarding type: {switch_info[FORWARDING_TYPE]}")
            LOGGER.info(f"\t\t|           Routing type: {switch_info[ROUTING_TYPE]}")
            LOGGER.info(f"\t\t|               Port map: {self.__port_map[switch_name]}")
        LOGGER.info("-------------------------------------------------------")

    def _get_fwd_type_of_switch(self, switch_name : str) -> int:
        fwd_type_str = self.__switch_info[switch_name][FORWARDING_TYPE]
        return FWD_TYPE_MAP[fwd_type_str]

    def _get_routing_type_of_switch(self, switch_name : str) -> int:
        return self.__switch_info[switch_name][ROUTING_TYPE]

    def _get_switch_port_in_port_map(self, switch_name : str, port_id : int) -> Dict:
        assert switch_name, "A valid switch name must be used as a key to the port map"
        assert port_id > 0, "A valid switch port ID must be used as a key to a switch's port map"
        switch_entry = self.__port_map[switch_name]
        assert switch_entry, f"Switch {switch_name} does not exist in the port map"
        port_key = PORT_PREFIX + str(port_id)
        assert switch_entry[port_key], f"Port with ID {port_id} does not exist in the switch map"

        if port_key in switch_entry:
            return switch_entry[port_key]
        return {}

    def _get_port_type_of_switch_port(self, switch_name : str, port_id : int) -> str:
        switch_port_entry = self._get_switch_port_in_port_map(switch_name, port_id)
@@ -409,8 +442,10 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler):
    def _create_rules(self, device_obj : Device, port_id : int, action : ConfigActionEnum): # type: ignore
        dev_name = device_obj.name

        # TODO: Fix
        next_id = 2 if port_id == 1 else 1
        fwd_type = self._get_fwd_type_of_switch(dev_name)
        routing_type = self._get_routing_type_of_switch(dev_name)

        vlan_id = self._get_vlan_id_of_switch_port(switch_name=dev_name, port_id=port_id)

        host_facing_port = self._is_host_facing_port(dev_name, port_id)
        LOGGER.info(f"\t | Service endpoint is host facing: {"True" if host_facing_port else "False"}")
@@ -422,27 +457,32 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler):
            if host_facing_port:
                rules += rules_set_up_port_host(
                    port=port_id,
                    vlan_id=self._get_vlan_id_of_switch_port(switch_name=dev_name, port_id=port_id),
                    action=action
                    vlan_id=vlan_id,
                    action=action,
                    fwd_type=fwd_type
                )
            else:
                rules += rules_set_up_port_switch(
                    port=port_id,
                    vlan_id=self._get_vlan_id_of_switch_port(switch_name=dev_name, port_id=port_id),
                    action=action
                    vlan_id=vlan_id,
                    action=action,
                    fwd_type=fwd_type
                )
        except Exception as ex:
            LOGGER.error("Error while creating port setup rules")
            raise Exception(ex)

        fwd_list = self._get_fwd_list_of_switch_port(switch_name=dev_name, port_id=next_id)
        for mac_dst in fwd_list:
            LOGGER.info(f"Switch {dev_name} - Port {port_id} - Creating rule for destination MAC: {mac_dst}")
        fwd_list = self._get_fwd_list_of_switch_port(switch_name=dev_name, port_id=port_id)
        for fwd_entry in fwd_list:
            next_id = fwd_entry[NEXT_ID]
            mac_dst = fwd_entry[HOST_MAC]

            LOGGER.info(f"Switch {dev_name} - Port {port_id} - Creating rule for destination MAC: {mac_dst} - Next ID: {next_id}")
            try:
                ### Bridging rules
                rules += rules_set_up_fwd_bridging(
                    port_id=port_id,
                    vlan_id=self._get_vlan_id_of_switch_port(switch_name=dev_name, port_id=port_id),
                    vlan_id=vlan_id,
                    eth_dst=mac_dst,
                    next_id=next_id,
                    action=action
@@ -453,6 +493,7 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler):

            src_list = self._get_fwd_list_of_switch_port(switch_name=dev_name, port_id=port_id)
            for mac_src in src_list:
                if routing_type == ROUTING_TYPE_STR_HASHED:
                    try:
                        ### Next profile for hashed routing
                        rules += rules_set_up_next_profile_hashed_routing(
@@ -465,7 +506,29 @@ class P4FabricL2SimpleServiceHandler(_ServiceHandler):
                    except Exception as ex:
                        LOGGER.error("Error while creating rule for next hashed profile")
                        raise Exception(ex)
                elif routing_type == ROUTING_TYPE_STR_SIMPLE:
                    try:
                        rules += rules_set_up_pre_next_vlan(
                            port_id=port_id,
                            next_id=next_id,
                            vlan_id=vlan_id,
                            action=action
                        )
                    except Exception as ex:
                        LOGGER.error("Error while creating pre-next VLAN rule")
                        raise Exception(ex)

                    try:
                        rules += rules_set_up_next_output_simple(
                            port_id=port_id,
                            next_id=next_id,
                            action=action
                        )
                    except Exception as ex:
                        LOGGER.error("Error while creating next output simple rule")
                        raise Exception(ex)

            if routing_type == ROUTING_TYPE_STR_HASHED:
                try:
                    ### Next hashed port
                    rules += rules_set_up_next_hashed(
+97 −46

File changed.

Preview size limit exceeded, changes collapsed.

Loading