From c271546860af1fe04a49b91f8c60e1720ee97b2e Mon Sep 17 00:00:00 2001 From: hajipour <shajipour@cttc.es> Date: Fri, 27 Dec 2024 22:04:46 +0100 Subject: [PATCH] integration: several integrations to match the requirements of L3VPN service handler --- .../l3slice_ietfslice/ConfigRules.py | 49 +- .../L3SliceIETFSliceServiceHandler.py | 984 ++++++++++-------- 2 files changed, 611 insertions(+), 422 deletions(-) diff --git a/src/service/service/service_handlers/l3slice_ietfslice/ConfigRules.py b/src/service/service/service_handlers/l3slice_ietfslice/ConfigRules.py index 23f3e8159..cd6072e85 100644 --- a/src/service/service/service_handlers/l3slice_ietfslice/ConfigRules.py +++ b/src/service/service/service_handlers/l3slice_ietfslice/ConfigRules.py @@ -20,7 +20,6 @@ from common.tools.object_factory.ConfigRule import ( json_config_rule_set, ) from context.client.ContextClient import ContextClient -from service.service.service_handler_api.AnyTreeTools import TreeNode def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]: @@ -30,11 +29,19 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]: src_ac_node_id: str = json_settings["src_ac_node_id"] src_ac_ep_id: str = json_settings["src_ac_ep_id"] src_vlan: str = json_settings["src_vlan"] + src_source_ip_prefix: str = json_settings["src_source_ip_prefix"] + src_source_tcp_port: str = json_settings["src_source_tcp_port"] + src_destination_ip_prefix: str = json_settings["src_destination_ip_prefix"] + src_destination_tcp_port: str = json_settings["src_destination_tcp_port"] dst_node_id: str = json_settings["dst_node_id"] dst_mgmt_ip_address: str = json_settings["dst_mgmt_ip_address"] dst_ac_node_id: str = json_settings["dst_ac_node_id"] dst_ac_ep_id: str = json_settings["dst_ac_ep_id"] dst_vlan: str = json_settings["dst_vlan"] + dst_source_ip_prefix: str = json_settings["dst_source_ip_prefix"] + dst_source_tcp_port: str = json_settings["dst_source_tcp_port"] + dst_destination_ip_prefix: str = json_settings["dst_destination_ip_prefix"] + dst_destination_tcp_port: str = json_settings["dst_destination_tcp_port"] slice_id: str = json_settings["slice_id"] delay: str = json_settings["delay"] bandwidth: str = json_settings["bandwidth"] @@ -54,6 +61,22 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]: "type": "ietf-network-slice-service:vlan", "value": [src_vlan], }, + { + "type": "ietf-network-slice-service:source-ip-prefix", + "value": [src_source_ip_prefix], + }, + { + "type": "ietf-network-slice-service:source-tcp-port", + "value": [src_source_tcp_port], + }, + { + "type": "ietf-network-slice-service:destination-ip-prefix", + "value": [src_destination_ip_prefix], + }, + { + "type": "ietf-network-slice-service:destination-tcp-port", + "value": [src_destination_tcp_port], + }, ], "target-connection-group-id": "line1", } @@ -83,6 +106,22 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]: "type": "ietf-network-slice-service:vlan", "value": [dst_vlan], }, + { + "type": "ietf-network-slice-service:source-ip-prefix", + "value": [dst_source_ip_prefix], + }, + { + "type": "ietf-network-slice-service:source-tcp-port", + "value": [dst_source_tcp_port], + }, + { + "type": "ietf-network-slice-service:destination-ip-prefix", + "value": [dst_destination_ip_prefix], + }, + { + "type": "ietf-network-slice-service:destination-tcp-port", + "value": [dst_destination_tcp_port], + }, ], "target-connection-group-id": "line1", } @@ -108,8 +147,8 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]: "connectivity-construct": [ { "id": 1, - "p2mp-sender-sdp": "1", - "p2mp-receiver-sdp": ["2"], + "p2p-sender-sdp": "1", + "p2p-receiver-sdp": "2", "service-slo-sle-policy": { "slo-policy": { "metric-bound": [ @@ -134,8 +173,8 @@ def setup_config_rules(service_uuid: str, json_settings: Dict) -> List[Dict]: }, { "id": 2, - "p2mp-sender-sdp": "2", - "p2mp-receiver-sdp": ["1"], + "p2p-sender-sdp": "2", + "p2p-receiver-sdp": "1", "service-slo-sle-policy": { "slo-policy": { "metric-bound": [ diff --git a/src/service/service/service_handlers/l3slice_ietfslice/L3SliceIETFSliceServiceHandler.py b/src/service/service/service_handlers/l3slice_ietfslice/L3SliceIETFSliceServiceHandler.py index e584283a4..fa4ebd35d 100644 --- a/src/service/service/service_handlers/l3slice_ietfslice/L3SliceIETFSliceServiceHandler.py +++ b/src/service/service/service_handlers/l3slice_ietfslice/L3SliceIETFSliceServiceHandler.py @@ -15,7 +15,7 @@ import json import logging import re -from typing import Any, List, Optional, Tuple, Union +from typing import Any, Dict, List, Optional, Tuple, TypedDict, Union from deepdiff import DeepDiff @@ -37,6 +37,21 @@ from .ConfigRules import ( teardown_config_rules, ) + +class Ipv4Info(TypedDict): + src_ip: str + dst_ip: str + src_port: str + dst_port: str + vlan: str + + +class DeviceEpInfo(TypedDict): + ipv4_info: Ipv4Info + node_name: str + endpoint_name: str + + RUNNING_RESOURCE_KEY = "running_ietf_slice" CANDIDATE_RESOURCE_KEY = "candidate_ietf_slice" @@ -62,6 +77,53 @@ METRICS_POOL = MetricsPool( RAISE_IF_DIFFERS = True +def extract_source_destination_device_endpoint_info( + device_ep_pairs: list, connection_group: Dict +) -> Tuple[DeviceEpInfo, DeviceEpInfo]: + connectivity_construct = connection_group["connectivity-construct"][0] + sender_sdp = connectivity_construct["p2p-sender-sdp"] + if sender_sdp == device_ep_pairs[0][4]: + ... + elif sender_sdp == device_ep_pairs[1][4]: + device_ep_pairs = device_ep_pairs[::-1] + else: + raise Exception("Sender SDP not found in device_ep_pairs") + source_device_ep_info = DeviceEpInfo( + ipv4_info=device_ep_pairs[0][5], + node_name=device_ep_pairs[0][2], + endpoint_name=device_ep_pairs[0][3], + ) + destination_device_ep_info = DeviceEpInfo( + ipv4_info=device_ep_pairs[1][5], + node_name=device_ep_pairs[1][2], + endpoint_name=device_ep_pairs[1][3], + ) + return source_device_ep_info, destination_device_ep_info + + +def extract_match_criterion_ipv4_info( + match_criterion: Dict, +) -> Ipv4Info: + for type_value in match_criterion["match-type"]: + if type_value["type"] == "ietf-network-slice-service:source-ip-prefix": + src_ip = type_value["value"][0].split("/")[0] + elif type_value["type"] == "ietf-network-slice-service:destination-ip-prefix": + dst_ip = type_value["value"][0].split("/")[0] + elif type_value["type"] == "ietf-network-slice-service:source-tcp-port": + src_port = type_value["value"][0] + elif type_value["type"] == "ietf-network-slice-service:destination-tcp-port": + dst_port = type_value["value"][0] + elif type_value["type"] == "ietf-network-slice-service:vlan": + vlan = type_value["value"][0] + return Ipv4Info( + src_ip=src_ip, + dst_ip=dst_ip, + src_port=src_port, + dst_port=dst_port, + vlan=vlan, + ) + + def get_custom_config_rule( service_config: ServiceConfig, resource_key: str ) -> Optional[ConfigRule]: @@ -73,7 +135,7 @@ def get_custom_config_rule( return cr -def get_running_candidate_ietf_slice_data_diff(service_config: ServiceConfig) -> dict: +def get_running_candidate_ietf_slice_data_diff(service_config: ServiceConfig) -> Dict: running_ietf_slice_cr = get_custom_config_rule(service_config, RUNNING_RESOURCE_KEY) running_resource_value_dict = json.loads( running_ietf_slice_cr.custom.resource_value @@ -84,16 +146,9 @@ def get_running_candidate_ietf_slice_data_diff(service_config: ServiceConfig) -> candidate_resource_value_dict = json.loads( candidate_ietf_slice_cr.custom.resource_value ) - return ( - DeepDiff( - running_resource_value_dict, - candidate_resource_value_dict, - ), - DeepDiff( - running_resource_value_dict, - candidate_resource_value_dict, - ignore_order=True, - ), + return DeepDiff( + running_resource_value_dict, + candidate_resource_value_dict, ) @@ -114,64 +169,107 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler): chk_type("endpoints", endpoints, list) if len(endpoints) == 0: return [] - service_uuid = self.__service.service_id.service_uuid.uuid - service_config = self.__service.service_config - src_device_uuid, src_endpoint_uuid = get_device_endpoint_uuids(endpoints[0]) - src_device_obj = self.__task_executor.get_device( - DeviceId(**json_device_id(src_device_uuid)) - ) - src_device_name = src_device_obj.name - src_controller = self.__task_executor.get_device_controller(src_device_obj) - dst_device_uuid, dst_endpoint_uuid = get_device_endpoint_uuids(endpoints[-1]) - dst_device_obj = self.__task_executor.get_device( - DeviceId(**json_device_id(dst_device_uuid)) - ) - dst_device_name = dst_device_obj.name - dst_controller = self.__task_executor.get_device_controller(dst_device_obj) - if ( - src_controller.device_id.device_uuid.uuid - != dst_controller.device_id.device_uuid.uuid - ): - raise Exception("Different Src-Dst devices not supported by now") - controller = src_controller - context_client = ContextClient() - edge_device_names = [src_device_name, dst_device_name] - link_list = context_client.ListLinks(Empty()) - links = link_list.links - max_delay = 1e9 - packet_loss = 1.0 - bandwidth = 0.0 - device_ep_pairs = [] - sdp_ids = [] - running_candidate_diff, running_candidate_diff_no_order = ( - get_running_candidate_ietf_slice_data_diff(service_config) - ) - candidate_ietf_slice_cr = get_custom_config_rule( - service_config, CANDIDATE_RESOURCE_KEY - ) - candidate_resource_value_dict = json.loads( - candidate_ietf_slice_cr.custom.resource_value - ) - running_ietf_slice_cr = get_custom_config_rule( - service_config, RUNNING_RESOURCE_KEY - ) - running_resource_value_dict = json.loads( - running_ietf_slice_cr.custom.resource_value - ) - LOGGER.debug(f"P46: {candidate_resource_value_dict}") - LOGGER.debug(f"P47: {running_resource_value_dict}") - LOGGER.debug(f"P41: {running_candidate_diff}") - LOGGER.debug(f"P45: {running_candidate_diff_no_order}") - if not running_candidate_diff: # Slice Creation - slice_services = candidate_resource_value_dict["network-slice-services"][ - "slice-service" - ] - slice_service = slice_services[0] - sdps = slice_service["sdps"]["sdp"] - operation_type = "create" - sdp_ids = [sdp["node-id"] for sdp in sdps] - for sdp in sdps: - node_id = sdp["node-id"] + + results = [] + try: + service_config = self.__service.service_config + src_device_uuid, src_endpoint_uuid = get_device_endpoint_uuids(endpoints[0]) + src_device_obj = self.__task_executor.get_device( + DeviceId(**json_device_id(src_device_uuid)) + ) + src_device_name = src_device_obj.name + src_controller = self.__task_executor.get_device_controller(src_device_obj) + dst_device_uuid, dst_endpoint_uuid = get_device_endpoint_uuids( + endpoints[-1] + ) + dst_device_obj = self.__task_executor.get_device( + DeviceId(**json_device_id(dst_device_uuid)) + ) + dst_device_name = dst_device_obj.name + dst_controller = self.__task_executor.get_device_controller(dst_device_obj) + if ( + src_controller.device_id.device_uuid.uuid + != dst_controller.device_id.device_uuid.uuid + ): + raise Exception("Different Src-Dst devices not supported by now") + controller = src_controller + context_client = ContextClient() + edge_device_names = [src_device_name, dst_device_name] + link_list = context_client.ListLinks(Empty()) + links = link_list.links + max_delay = 1e9 + packet_loss = 1.0 + bandwidth = 0.0 + device_ep_pairs = [] + sdp_ids = [] + running_candidate_diff = get_running_candidate_ietf_slice_data_diff( + service_config + ) + candidate_ietf_slice_cr = get_custom_config_rule( + service_config, CANDIDATE_RESOURCE_KEY + ) + candidate_resource_value_dict = json.loads( + candidate_ietf_slice_cr.custom.resource_value + ) + running_ietf_slice_cr = get_custom_config_rule( + service_config, RUNNING_RESOURCE_KEY + ) + running_resource_value_dict = json.loads( + running_ietf_slice_cr.custom.resource_value + ) + slice_name = running_resource_value_dict["network-slice-services"]['slice-service'][0]['id'] + if not running_candidate_diff: # Slice Creation + slice_services = candidate_resource_value_dict[ + "network-slice-services" + ]["slice-service"] + slice_service = slice_services[0] + sdps = slice_service["sdps"]["sdp"] + operation_type = "create" + sdp_ids = [sdp["node-id"] for sdp in sdps] + for sdp in sdps: + node_id = sdp["node-id"] + for link in links: + ( + device_obj_name_1, + ep_name_1, + device_obj_1, + device_obj_name_2, + ep_name_2, + device_obj_2, + ) = get_link_ep_device_names(link, context_client) + if ( + device_obj_name_1 == node_id + and device_obj_name_2 in edge_device_names + ): + del edge_device_names[ + edge_device_names.index(device_obj_name_2) + ] + match_criteria = sdp["service-match-criteria"][ + "match-criterion" + ] + if len(match_criteria) != 1: + raise Exception( + "Only one match criteria allowed for initial slice creation" + ) + match_criterion = match_criteria[0] + ipv4_info = extract_match_criterion_ipv4_info( + match_criterion + ) + device_ep_pairs.append( + ( + node_id, + ep_name_1, + device_obj_name_2, + ep_name_2, + sdp["id"], + ipv4_info, + ) + ) + target_connection_group_id = match_criterion[ + "target-connection-group-id" + ] + del sdp_ids[sdp_ids.index(node_id)] + break for link in links: ( device_obj_name_1, @@ -182,359 +280,411 @@ class L3NMSliceIETFSliceServiceHandler(_ServiceHandler): device_obj_2, ) = get_link_ep_device_names(link, context_client) if ( - device_obj_name_1 == node_id - and device_obj_name_2 in edge_device_names + device_obj_name_1 == edge_device_names[0] + and device_obj_2.controller_id != device_obj_1.controller_id ): - device_ep_pairs.append( - (node_id, ep_name_1, device_obj_name_2, ep_name_2) - ) - del edge_device_names[ - edge_device_names.index(device_obj_name_2) - ] - match_criteria = sdp["service-match-criteria"][ - "match-criterion" - ] - vlan_id = set() - for match in match_criteria: - for type_value in match["match-type"]: - if ( - type_value["type"] - == "ietf-network-slice-service:vlan" - ): - vlan_id.add(type_value["value"][0]) - if len(vlan_id) != 1: - raise Exception("one vlan id found in SDP match criteria") - src_vlan = list(vlan_id)[0] - del sdp_ids[sdp_ids.index(node_id)] + for sdp in sdps: + if sdp["node-id"] != sdp_ids[0]: + continue + match_criteria = sdp["service-match-criteria"][ + "match-criterion" + ] + if len(match_criteria) != 1: + raise Exception( + "Only one match criteria allowed for initial slice creation" + ) + match_criterion = match_criteria[0] + ipv4_info = extract_match_criterion_ipv4_info( + match_criterion + ) + device_ep_pairs.append( + ( + device_obj_name_2, + ep_name_2, + device_obj_name_1, + ep_name_1, + sdp["id"], + ipv4_info, + ) + ) break - for link in links: - ( - device_obj_name_1, - ep_name_1, - device_obj_1, - device_obj_name_2, - ep_name_2, - device_obj_2, - ) = get_link_ep_device_names(link, context_client) - if ( - device_obj_name_1 == edge_device_names[0] - and device_obj_2.controller_id != device_obj_1.controller_id - ): - device_ep_pairs.append( - (device_obj_name_2, ep_name_2, device_obj_name_1, ep_name_1) - ) - for sdp in sdps: - if sdp["node-id"] != sdp_ids[0]: - continue - match_criteria = sdp["service-match-criteria"][ - "match-criterion" - ] - vlan_id = set() - for match in match_criteria: - for type_value in match["match-type"]: - if ( - type_value["type"] - == "ietf-network-slice-service:vlan" - ): - vlan_id.add(type_value["value"][0]) - if len(vlan_id) != 1: - raise Exception("one vlan id found in SDP match criteria") - dst_vlan = list(vlan_id)[0] - break - else: - raise Exception("sdp between the domains not found") - elif "iterable_item_added" in running_candidate_diff: # new SDP added - slice_services = candidate_resource_value_dict["network-slice-services"][ - "slice-service" - ] - slice_service = slice_services[0] - sdps = slice_service["sdps"]["sdp"] - operation_type = "update" - added_items = { - "sdp": {"sdp_idx": None, "value": {}}, - "connection_group": {"connection_group_idx": None, "value": {}}, - "match_criterion": { - "sdp_idx": None, - "match_criterion_idx": None, - "value": {}, - }, - } - for added_key, added_value in running_candidate_diff[ - "iterable_item_added" - ].items(): - sdp_match = SDP_DIFF_RE.match(added_key) - connection_group_match = CONNECTION_GROUP_DIFF_RE.match(added_key) - match_criterion_match = MATCH_CRITERION_DIFF_RE.match(added_key) - if sdp_match: - added_items["sdp"] = { - "sdp_idx": int(sdp_match.groups()[0]), - "value": added_value, - } - elif connection_group_match: - added_items["connection_group"] = { - "connection_group_idx": int(connection_group_match.groups()[0]), - "value": added_value, - } - elif match_criterion_match: - added_items["match_criterion"] = { - "sdp_idx": int(match_criterion_match.groups()[0]), - "match_criterion_idx": int(match_criterion_match.groups()[1]), - "value": added_value, - } - new_sdp = sdps[added_items["sdp"]["sdp_idx"]] - src_sdp_name = new_sdp["node-id"] - dst_sdp_idx = sdps[added_items["match_criterion"]["sdp_idx"]]["id"] - dst_sdp_name = sdps[added_items["match_criterion"]["sdp_idx"]]["node-id"] - for link in links: - ( - device_obj_name_1, - ep_name_1, - device_obj_1, - device_obj_name_2, - ep_name_2, - device_obj_2, - ) = get_link_ep_device_names(link, context_client) - if ( - device_obj_name_1 == src_sdp_name - and device_obj_2.controller_id != device_obj_1.controller_id - ): - device_ep_pairs.append( - (device_obj_name_2, ep_name_2, device_obj_name_1, ep_name_1) - ) - for sdp in sdps: - if sdp["node-id"] != src_sdp_name: - continue - match_criteria = sdp["service-match-criteria"][ - "match-criterion" - ] - vlan_id = set() - for match in match_criteria: - for type_value in match["match-type"]: - if ( - type_value["type"] - == "ietf-network-slice-service:vlan" - ): - vlan_id.add(type_value["value"][0]) - if len(vlan_id) != 1: - raise Exception("one vlan id found in SDP match criteria") - src_vlan = list(vlan_id)[0] - break - else: - raise Exception("sdp between the domains not found") - for link in links: - ( - device_obj_name_1, - ep_name_1, - device_obj_1, - device_obj_name_2, - ep_name_2, - device_obj_2, - ) = get_link_ep_device_names(link, context_client) - if ( - device_obj_name_1 == dst_sdp_name - and device_obj_2.controller_id != device_obj_1.controller_id - ): - device_ep_pairs.append( - (device_obj_name_2, ep_name_2, device_obj_name_1, ep_name_1) - ) - for sdp in sdps: - if sdp["node-id"] != dst_sdp_name: - continue - match_criteria = sdp["service-match-criteria"][ - "match-criterion" - ] - vlan_id = set() - for match in match_criteria: - for type_value in match["match-type"]: - if ( - type_value["type"] - == "ietf-network-slice-service:vlan" - ): - vlan_id.add(type_value["value"][0]) - if len(vlan_id) != 1: - raise Exception("one vlan id found in SDP match criteria") - dst_vlan = list(vlan_id)[0] - break - else: - raise Exception("sdp between the domains not found") - elif "iterable_item_removed" in running_candidate_diff: # an SDP removed - slice_services = running_resource_value_dict["network-slice-services"][ - "slice-service" - ] - slice_service = slice_services[0] - sdps = slice_service["sdps"]["sdp"] - operation_type = "update" - added_items = { - "sdp": {"sdp_idx": None, "value": {}}, - "connection_group": {"connection_group_idx": None, "value": {}}, - "match_criterion": { - "sdp_idx": None, - "match_criterion_idx": None, - "value": {}, - }, - } - for added_key, added_value in running_candidate_diff[ - "iterable_item_removed" - ].items(): - sdp_match = SDP_DIFF_RE.match(added_key) - connection_group_match = CONNECTION_GROUP_DIFF_RE.match(added_key) - match_criterion_match = MATCH_CRITERION_DIFF_RE.match(added_key) - LOGGER.debug( - f"P40: {sdp_match} *{connection_group_match}* {match_criterion_match}" - ) - if sdp_match: - added_items["sdp"] = { - "sdp_idx": int(sdp_match.groups()[0]), - "value": added_value, - } - elif connection_group_match: - added_items["connection_group"] = { - "connection_group_idx": int(connection_group_match.groups()[0]), - "value": added_value, - } - elif match_criterion_match: - added_items["match_criterion"] = { - "sdp_idx": int(match_criterion_match.groups()[0]), - "match_criterion_idx": int(match_criterion_match.groups()[1]), - "value": added_value, - } - new_sdp = sdps[added_items["sdp"]["sdp_idx"]] - src_sdp_name = new_sdp["node-id"] - dst_sdp_idx = sdps[added_items["match_criterion"]["sdp_idx"]]["id"] - dst_sdp_name = sdps[added_items["match_criterion"]["sdp_idx"]]["node-id"] - for link in links: - ( - device_obj_name_1, - ep_name_1, - device_obj_1, - device_obj_name_2, - ep_name_2, - device_obj_2, - ) = get_link_ep_device_names(link, context_client) - if ( - device_obj_name_1 == src_sdp_name - and device_obj_2.controller_id != device_obj_1.controller_id - ): - device_ep_pairs.append( - (device_obj_name_2, ep_name_2, device_obj_name_1, ep_name_1) - ) - for sdp in sdps: - if sdp["node-id"] != src_sdp_name: - continue - match_criteria = sdp["service-match-criteria"][ - "match-criterion" - ] - vlan_id = set() - LOGGER.debug(f"P81: {match_criteria}") - for match in match_criteria: - for type_value in match["match-type"]: - if ( - type_value["type"] - == "ietf-network-slice-service:vlan" - ): - vlan_id.add(type_value["value"][0]) - LOGGER.debug(f"P82: {vlan_id}") - if len(vlan_id) != 1: - raise Exception("one vlan id found in SDP match criteria") - src_vlan = list(vlan_id)[0] - break - else: - raise Exception("sdp between the domains not found") - for link in links: - ( - device_obj_name_1, - ep_name_1, - device_obj_1, - device_obj_name_2, - ep_name_2, - device_obj_2, - ) = get_link_ep_device_names(link, context_client) - if ( - device_obj_name_1 == dst_sdp_name - and device_obj_2.controller_id != device_obj_1.controller_id - ): - device_ep_pairs.append( - (device_obj_name_2, ep_name_2, device_obj_name_1, ep_name_1) - ) - for sdp in sdps: - if sdp["node-id"] != dst_sdp_name: - continue - match_criteria = sdp["service-match-criteria"][ - "match-criterion" - ] - LOGGER.debug(f"P83: {match_criteria}") - vlan_id = set() - for match in match_criteria: - for type_value in match["match-type"]: - if ( - type_value["type"] - == "ietf-network-slice-service:vlan" - ): - vlan_id.add(type_value["value"][0]) - - LOGGER.debug(f"P84: {vlan_id}") - if len(vlan_id) != 1: - raise Exception("one vlan id found in SDP match criteria") - dst_vlan = list(vlan_id)[0] - break - else: - raise Exception("sdp between the domains not found") - connection_groups = slice_service["connection-groups"]["connection-group"] - for cg in connection_groups: - for cc in cg["connectivity-construct"]: - for metric_bound in cc["service-slo-sle-policy"]["slo-policy"][ - "metric-bound" - ]: + else: + raise Exception("sdp between the domains not found") + elif "iterable_item_added" in running_candidate_diff: # new SDP added + slice_services = candidate_resource_value_dict[ + "network-slice-services" + ]["slice-service"] + slice_service = slice_services[0] + sdps = slice_service["sdps"]["sdp"] + operation_type = "update" + added_items = { + "sdp": {"sdp_idx": None, "value": {}}, + "connection_group": {"connection_group_idx": None, "value": {}}, + "match_criterion": { + "sdp_idx": None, + "match_criterion_idx": None, + "value": {}, + }, + } + for added_key, added_value in running_candidate_diff[ + "iterable_item_added" + ].items(): + sdp_match = SDP_DIFF_RE.match(added_key) + connection_group_match = CONNECTION_GROUP_DIFF_RE.match(added_key) + match_criterion_match = MATCH_CRITERION_DIFF_RE.match(added_key) + if sdp_match: + added_items["sdp"] = { + "sdp_idx": int(sdp_match.groups()[0]), + "value": added_value, + } + elif connection_group_match: + added_items["connection_group"] = { + "connection_group_idx": int( + connection_group_match.groups()[0] + ), + "value": added_value, + } + elif match_criterion_match: + added_items["match_criterion"] = { + "sdp_idx": int(match_criterion_match.groups()[0]), + "match_criterion_idx": int( + match_criterion_match.groups()[1] + ), + "value": added_value, + } + new_sdp = sdps[added_items["sdp"]["sdp_idx"]] + src_sdp_name = new_sdp["node-id"] + dst_sdp_idx = sdps[added_items["match_criterion"]["sdp_idx"]]["id"] + dst_sdp_name = sdps[added_items["match_criterion"]["sdp_idx"]][ + "node-id" + ] + for link in links: + ( + device_obj_name_1, + ep_name_1, + device_obj_1, + device_obj_name_2, + ep_name_2, + device_obj_2, + ) = get_link_ep_device_names(link, context_client) if ( - metric_bound["metric-type"] - == "ietf-network-slice-service:one-way-delay-maximum" - and metric_bound["metric-unit"] == "milliseconds" + device_obj_name_1 == src_sdp_name + and device_obj_2.controller_id != device_obj_1.controller_id ): - metric_value = int(metric_bound["bound"]) - if metric_value < max_delay: - max_delay = metric_value - elif ( - metric_bound["metric-type"] - == "ietf-network-slice-service:two-way-packet-loss" - and metric_bound["metric-unit"] == "percentage" + for sdp in sdps: + if sdp["node-id"] != src_sdp_name: + continue + match_criteria = sdp["service-match-criteria"][ + "match-criterion" + ] + if len(match_criteria) != 1: + raise Exception( + "Only one match criteria allowed for initial slice creation" + ) + match_criterion = match_criteria[0] + ipv4_info = extract_match_criterion_ipv4_info( + match_criterion + ) + device_ep_pairs.append( + ( + device_obj_name_2, + ep_name_2, + device_obj_name_1, + ep_name_1, + sdp["id"], + ipv4_info, + ) + ) + target_connection_group_id = match_criterion[ + "target-connection-group-id" + ] + break + else: + raise Exception("sdp between the domains not found") + for link in links: + ( + device_obj_name_1, + ep_name_1, + device_obj_1, + device_obj_name_2, + ep_name_2, + device_obj_2, + ) = get_link_ep_device_names(link, context_client) + if ( + device_obj_name_1 == dst_sdp_name + and device_obj_2.controller_id != device_obj_1.controller_id ): - metric_value = float(metric_bound["percentile-value"]) - if metric_value < packet_loss: - packet_loss = metric_value - elif ( - metric_bound["metric-type"] - == "ietf-network-slice-service:one-way-bandwidth" - and metric_bound["metric-unit"] == "Mbps" + for sdp in sdps: + if sdp["node-id"] != dst_sdp_name: + continue + match_criteria = sdp["service-match-criteria"][ + "match-criterion" + ] + vlan_id = set() + for match in match_criteria: + for type_value in match["match-type"]: + if ( + type_value["type"] + == "ietf-network-slice-service:vlan" + ): + vlan_id.add(type_value["value"][0]) + if len(vlan_id) != 1: + raise Exception( + "one vlan id found in SDP match criteria" + ) + match_criterion = match_criteria[ + added_items["match_criterion"]["match_criterion_idx"] + ] + ipv4_info = extract_match_criterion_ipv4_info( + match_criterion + ) + device_ep_pairs.append( + ( + device_obj_name_2, + ep_name_2, + device_obj_name_1, + ep_name_1, + sdp["id"], + ipv4_info, + ) + ) + break + else: + raise Exception("sdp between the domains not found") + elif "iterable_item_removed" in running_candidate_diff: # an SDP removed + slice_services = running_resource_value_dict["network-slice-services"][ + "slice-service" + ] + slice_service = slice_services[0] + sdps = slice_service["sdps"]["sdp"] + operation_type = "update" + removed_items = { + "sdp": {"sdp_idx": None, "value": {}}, + "connection_group": {"connection_group_idx": None, "value": {}}, + "match_criterion": { + "sdp_idx": None, + "match_criterion_idx": None, + "value": {}, + }, + } + for added_key, added_value in running_candidate_diff[ + "iterable_item_removed" + ].items(): + sdp_match = SDP_DIFF_RE.match(added_key) + connection_group_match = CONNECTION_GROUP_DIFF_RE.match(added_key) + match_criterion_match = MATCH_CRITERION_DIFF_RE.match(added_key) + if sdp_match: + removed_items["sdp"] = { + "sdp_idx": int(sdp_match.groups()[0]), + "value": added_value, + } + elif connection_group_match: + removed_items["connection_group"] = { + "connection_group_idx": int( + connection_group_match.groups()[0] + ), + "value": added_value, + } + elif match_criterion_match: + removed_items["match_criterion"] = { + "sdp_idx": int(match_criterion_match.groups()[0]), + "match_criterion_idx": int( + match_criterion_match.groups()[1] + ), + "value": added_value, + } + new_sdp = sdps[removed_items["sdp"]["sdp_idx"]] + src_sdp_name = new_sdp["node-id"] + dst_sdp_idx = sdps[removed_items["match_criterion"]["sdp_idx"]]["id"] + dst_sdp_name = sdps[removed_items["match_criterion"]["sdp_idx"]][ + "node-id" + ] + for link in links: + ( + device_obj_name_1, + ep_name_1, + device_obj_1, + device_obj_name_2, + ep_name_2, + device_obj_2, + ) = get_link_ep_device_names(link, context_client) + if ( + device_obj_name_1 == src_sdp_name + and device_obj_2.controller_id != device_obj_1.controller_id ): - metric_value = float(metric_bound["bound"]) - bandwidth += metric_value - results = [] - resource_value_dict = { - "uuid": service_uuid, - "operation_type": operation_type, - "src_node_id": device_ep_pairs[0][2], - "src_mgmt_ip_address": device_ep_pairs[0][2], - "src_ac_node_id": device_ep_pairs[0][2], - "src_ac_ep_id": device_ep_pairs[0][3], - "src_vlan": src_vlan, - "dst_node_id": device_ep_pairs[1][2], - "dst_mgmt_ip_address": device_ep_pairs[1][2], - "dst_ac_node_id": device_ep_pairs[1][2], - "dst_ac_ep_id": device_ep_pairs[1][3], - "dst_vlan": dst_vlan, - "slice_id": service_uuid, - "delay": max_delay, - "bandwidth": bandwidth, - "packet_loss": packet_loss, - } - - json_config_rules = setup_config_rules(service_uuid, resource_value_dict) - del controller.device_config.config_rules[:] - for jcr in json_config_rules: - controller.device_config.config_rules.append(ConfigRule(**jcr)) - self.__task_executor.configure_device(controller) - # except Exception as e: # pylint: disable=broad-except - # results.append(e) + for sdp in sdps: + if sdp["node-id"] != src_sdp_name: + continue + match_criteria = sdp["service-match-criteria"][ + "match-criterion" + ] + if len(match_criteria) != 1: + raise Exception( + "Only one match criteria allowed for new SDP addition" + ) + match_criterion = match_criteria[0] + ipv4_info = extract_match_criterion_ipv4_info( + match_criterion + ) + device_ep_pairs.append( + ( + device_obj_name_2, + ep_name_2, + device_obj_name_1, + ep_name_1, + sdp["id"], + ipv4_info, + ) + ) + target_connection_group_id = match_criterion[ + "target-connection-group-id" + ] + break + else: + raise Exception("sdp between the domains not found") + for link in links: + ( + device_obj_name_1, + ep_name_1, + device_obj_1, + device_obj_name_2, + ep_name_2, + device_obj_2, + ) = get_link_ep_device_names(link, context_client) + if ( + device_obj_name_1 == dst_sdp_name + and device_obj_2.controller_id != device_obj_1.controller_id + ): + for sdp in sdps: + if sdp["node-id"] != dst_sdp_name: + continue + match_criteria = sdp["service-match-criteria"][ + "match-criterion" + ] + vlan_id = set() + for match in match_criteria: + for type_value in match["match-type"]: + if ( + type_value["type"] + == "ietf-network-slice-service:vlan" + ): + vlan_id.add(type_value["value"][0]) + if len(vlan_id) != 1: + raise Exception( + "one vlan id found in SDP match criteria" + ) + match_criterion = match_criteria[ + removed_items["match_criterion"]["match_criterion_idx"] + ] + ipv4_info = extract_match_criterion_ipv4_info( + match_criterion + ) + device_ep_pairs.append( + ( + device_obj_name_2, + ep_name_2, + device_obj_name_1, + ep_name_1, + sdp["id"], + ipv4_info, + ) + ) + break + else: + raise Exception("sdp between the domains not found") + connection_groups = slice_service["connection-groups"]["connection-group"] + for cg in connection_groups: + for cc in cg["connectivity-construct"]: + for metric_bound in cc["service-slo-sle-policy"]["slo-policy"][ + "metric-bound" + ]: + if ( + metric_bound["metric-type"] + == "ietf-network-slice-service:one-way-delay-maximum" + and metric_bound["metric-unit"] == "milliseconds" + ): + metric_value = int(metric_bound["bound"]) + if metric_value < max_delay: + max_delay = metric_value + elif ( + metric_bound["metric-type"] + == "ietf-network-slice-service:two-way-packet-loss" + and metric_bound["metric-unit"] == "percentage" + ): + metric_value = float(metric_bound["percentile-value"]) + if metric_value < packet_loss: + packet_loss = metric_value + elif ( + metric_bound["metric-type"] + == "ietf-network-slice-service:one-way-bandwidth" + and metric_bound["metric-unit"] == "Mbps" + ): + metric_value = float(metric_bound["bound"]) + bandwidth += metric_value + if ( + len( + candidate_resource_value_dict["network-slice-services"][ + "slice-service" + ][0]["connection-groups"]["connection-group"] + ) + == 0 + ): + operation_type = "delete" + target_connection_group = next( + cg for cg in connection_groups if cg["id"] == target_connection_group_id + ) + source_device_ep_info, destination_device_ep_info = ( + extract_source_destination_device_endpoint_info( + device_ep_pairs, target_connection_group + ) + ) + resource_value_dict = { + "uuid": slice_name, + "operation_type": operation_type, + "src_node_id": source_device_ep_info["node_name"], + "src_mgmt_ip_address": source_device_ep_info["node_name"], + "src_ac_node_id": source_device_ep_info["node_name"], + "src_ac_ep_id": source_device_ep_info["endpoint_name"], + "src_vlan": source_device_ep_info["ipv4_info"]["vlan"], + "src_source_ip_prefix": source_device_ep_info["ipv4_info"]["src_ip"], + "src_source_tcp_port": source_device_ep_info["ipv4_info"]["src_port"], + "src_destination_ip_prefix": source_device_ep_info["ipv4_info"][ + "dst_ip" + ], + "src_destination_tcp_port": source_device_ep_info["ipv4_info"][ + "dst_port" + ], + "dst_node_id": destination_device_ep_info["node_name"], + "dst_mgmt_ip_address": destination_device_ep_info["node_name"], + "dst_ac_node_id": destination_device_ep_info["node_name"], + "dst_ac_ep_id": destination_device_ep_info["endpoint_name"], + "dst_vlan": destination_device_ep_info["ipv4_info"]["vlan"], + "dst_source_ip_prefix": destination_device_ep_info["ipv4_info"][ + "src_ip" + ], + "dst_source_tcp_port": destination_device_ep_info["ipv4_info"][ + "src_port" + ], + "dst_destination_ip_prefix": destination_device_ep_info["ipv4_info"][ + "dst_ip" + ], + "dst_destination_tcp_port": destination_device_ep_info["ipv4_info"][ + "dst_port" + ], + "slice_id": slice_name, + "delay": max_delay, + "bandwidth": bandwidth, + "packet_loss": packet_loss, + } + + json_config_rules = setup_config_rules(slice_name, resource_value_dict) + del controller.device_config.config_rules[:] + for jcr in json_config_rules: + controller.device_config.config_rules.append(ConfigRule(**jcr)) + self.__task_executor.configure_device(controller) + except Exception as e: # pylint: disable=broad-except + raise e + results.append(e) return results @metered_subclass_method(METRICS_POOL) -- GitLab