Skip to content
Snippets Groups Projects
Commit bcf185c3 authored by Shayan Hajipour's avatar Shayan Hajipour
Browse files

enhancement: L3NM IETF L3VPN service handler changed to match IETF Slice data...

enhancement: L3NM IETF L3VPN service handler changed to match IETF Slice data model received in the NBI
parent e7430b0b
No related branches found
No related tags found
1 merge request!283Resolve "(CTTC) Implement L3 VPN SBI driver compatible with IETF L3 Service Model"
......@@ -14,14 +14,20 @@
import json
import logging
from typing import Any, List, Optional, Tuple, Union
from typing import Any, List, Optional, Tuple, TypedDict, Union
from deepdiff import DeepDiff
from common.DeviceTypes import DeviceTypeEnum
from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method
from common.proto.context_pb2 import ConfigRule, DeviceId, Service
from common.tools.object_factory.ConfigRule import (
json_config_rule_delete,
json_config_rule_set,
from common.proto.context_pb2 import (
ConfigRule,
Device,
DeviceId,
Service,
ServiceConfig,
)
from common.tools.object_factory.ConfigRule import json_config_rule_delete
from common.tools.object_factory.Device import json_device_id
from common.type_checkers.Checkers import chk_type
from service.service.service_handler_api._ServiceHandler import _ServiceHandler
......@@ -32,11 +38,81 @@ from service.service.service_handler_api.Tools import (
)
from service.service.task_scheduler.TaskExecutor import TaskExecutor
from .ConfigRules import setup_config_rules
RUNNING_RESOURCE_KEY = "running_ietf_slice"
CANDIDATE_RESOURCE_KEY = "candidate_ietf_slice"
MTU = 1500
LOGGER = logging.getLogger(__name__)
METRICS_POOL = MetricsPool("Service", "Handler", labels={"handler": "l3nm_ietf_l3vpn"})
class LANPrefixesDict(TypedDict):
lan: str
lan_tag: str
class Ipv4Info(TypedDict):
src_ip: str
dst_ip: str
src_port: str
dst_port: str
vlan: str
def get_custom_config_rule(
service_config: ServiceConfig, resource_key: str
) -> Optional[ConfigRule]:
for cr in service_config.config_rules:
if (
cr.WhichOneof("config_rule") == "custom"
and cr.custom.resource_key == resource_key
):
return cr
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
)
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
)
return DeepDiff(
running_resource_value_dict,
candidate_resource_value_dict,
)
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,
)
class L3NM_IETFL3VPN_ServiceHandler(_ServiceHandler):
def __init__( # pylint: disable=super-init-not-called
self, service: Service, task_executor: TaskExecutor, **settings
......@@ -45,6 +121,43 @@ class L3NM_IETFL3VPN_ServiceHandler(_ServiceHandler):
self.__task_executor = task_executor
self.__settings_handler = SettingsHandler(service.service_config, **settings)
def __find_IP_transport_edge_endpoints(
self, endpoints
) -> Tuple[str, str, str, str, Device]:
for ep in endpoints:
device_uuid, endpoint_uuid = get_device_endpoint_uuids(ep)
device_obj = self.__task_executor.get_device(
DeviceId(**json_device_id(device_uuid))
)
device_controller = self.__task_executor.get_device_controller(device_obj)
if device_controller.device_type == DeviceTypeEnum.IP_SDN_CONTROLLER:
src_device_uuid, src_endpoint_uuid = device_uuid, endpoint_uuid
src_device_controller = device_controller
break
else:
raise Exception("No IP transport edge endpoints found")
for ep in endpoints[::-1]:
device_uuid, endpoint_uuid = get_device_endpoint_uuids(ep)
device_obj = self.__task_executor.get_device(
DeviceId(**json_device_id(device_uuid))
)
device_controller = self.__task_executor.get_device_controller(device_obj)
if device_controller.device_type == DeviceTypeEnum.IP_SDN_CONTROLLER:
dst_device_uuid, dst_endpoint_uuid = device_uuid, endpoint_uuid
dst_device_controller = device_controller
break
else:
raise Exception("No IP transport edge endpoints found")
if src_device_controller != dst_device_controller:
raise Exception("Different Src-Dst devices not supported by now")
return (
src_device_uuid,
src_endpoint_uuid,
dst_device_uuid,
dst_endpoint_uuid,
src_device_controller,
)
@metered_subclass_method(METRICS_POOL)
def SetEndpoint(
self,
......@@ -54,79 +167,136 @@ class L3NM_IETFL3VPN_ServiceHandler(_ServiceHandler):
chk_type("endpoints", endpoints, list)
if len(endpoints) < 2:
return []
service_uuid = self.__service.service_id.service_uuid.uuid
results = []
service_uuid = self.__service.service_id.service_uuid.uuid
service_config = self.__service.service_config
try:
src_device_uuid, src_endpoint_uuid = get_device_endpoint_uuids(endpoints[0])
(
src_device_uuid,
src_endpoint_uuid,
dst_device_uuid,
dst_endpoint_uuid,
controller,
) = self.__find_IP_transport_edge_endpoints(endpoints)
service_uuid = self.__service.service_id.service_uuid.uuid
service_config = self.__service.service_config
src_device_obj = self.__task_executor.get_device(
DeviceId(**json_device_id(src_device_uuid))
)
src_endpoint_obj = get_endpoint_matching(src_device_obj, src_endpoint_uuid)
for cr in src_device_obj.device_config.config_rules:
if cr.WhichOneof('config_rule') == 'custom' and cr.custom.resource_key == f'/endpoints/endpoint[{src_endpoint_obj.name}]':
src_endpoint_settings = json.loads(cr.custom.resource_value)
break
# src_endpoint_settings = self.__settings_handler.get_endpoint_settings(
# src_device_obj, src_endpoint_obj
# ).value
src_controller = self.__task_executor.get_device_controller(src_device_obj)
if src_controller is None: src_controller = src_device_obj
dst_device_uuid, dst_endpoint_uuid = get_device_endpoint_uuids(
endpoints[-1]
)
src_device_name = src_device_obj.name
dst_device_obj = self.__task_executor.get_device(
DeviceId(**json_device_id(dst_device_uuid))
)
dst_endpoint_obj = get_endpoint_matching(dst_device_obj, dst_endpoint_uuid)
dst_device_name = dst_device_obj.name
for cr in src_device_obj.device_config.config_rules:
if (
cr.WhichOneof("config_rule") == "custom"
and cr.custom.resource_key
== f"/endpoints/endpoint[{src_endpoint_obj.name}]"
):
src_endpoint_settings = json.loads(cr.custom.resource_value)
break
else:
raise Exception("Endpoint settings not found")
for cr in dst_device_obj.device_config.config_rules:
if cr.WhichOneof('config_rule') == 'custom' and cr.custom.resource_key == f'/endpoints/endpoint[{dst_endpoint_obj.name}]':
if (
cr.WhichOneof("config_rule") == "custom"
and cr.custom.resource_key
== f"/endpoints/endpoint[{dst_endpoint_obj.name}]"
):
dst_endpoint_settings = json.loads(cr.custom.resource_value)
break
# dst_endpoint_settings = self.__settings_handler.get_endpoint_settings(
# dst_device_obj, dst_endpoint_obj
# ).value
dst_controller = self.__task_executor.get_device_controller(dst_device_obj)
if dst_controller is None: dst_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
json_config_rule = json_config_rule_set(
"/services/service[{:s}]".format(service_uuid),
{
"uuid": service_uuid,
"src_device_name": src_device_obj.name,
"src_endpoint_name": src_endpoint_obj.name,
"src_site_location": src_endpoint_settings["site_location"],
"src_ipv4_lan_prefixes": src_endpoint_settings["ipv4_lan_prefixes"],
"src_ce_address": src_endpoint_settings["ce-ip"],
"src_pe_address": src_endpoint_settings["address_ip"],
"src_ce_pe_network_prefix": src_endpoint_settings["address_prefix"],
"src_mtu": src_endpoint_settings["mtu"],
"dst_device_name": dst_device_obj.name,
"dst_endpoint_name": dst_endpoint_obj.name,
"dst_site_location": dst_endpoint_settings["site_location"],
"dst_ipv4_lan_prefixes": dst_endpoint_settings["ipv4_lan_prefixes"],
"dst_ce_address": dst_endpoint_settings["ce-ip"],
"dst_pe_address": dst_endpoint_settings["address_ip"],
"dst_ce_pe_network_prefix": dst_endpoint_settings["address_prefix"],
"dst_mtu": dst_endpoint_settings["mtu"],
},
else:
raise Exception("Endpoint settings not found")
ietf_slice_running_cr = get_custom_config_rule(
service_config, RUNNING_RESOURCE_KEY
)
del controller.device_config.config_rules[:]
controller.device_config.config_rules.append(
ConfigRule(**json_config_rule)
ietf_slice_candidate_cr = get_custom_config_rule(
service_config, CANDIDATE_RESOURCE_KEY
)
if (
ietf_slice_running_cr and ietf_slice_candidate_cr
): # The request comes from the IETF Slice NBI
running_resource_value_dict = json.loads(
ietf_slice_running_cr.custom.resource_value
)
candidate_resource_value_dict = json.loads(
ietf_slice_candidate_cr.custom.resource_value
)
running_candidate_diff = get_running_candidate_ietf_slice_data_diff(
service_config
)
slice_services = candidate_resource_value_dict[
"network-slice-services"
]["slice-service"]
slice_service = slice_services[0]
sdps = slice_service["sdps"]["sdp"]
connection_groups = slice_service["connection-groups"][
"connection-group"
]
connection_group = connection_groups[0]
connecitivity_constructs = connection_group["connectivity-construct"]
connecitivity_construct = connecitivity_constructs[0]
src_sdp_idx = connecitivity_construct["p2p-sender-sdp"]
dst_sdp_idx = connecitivity_construct["p2p-receiver-sdp"]
src_sdp = next(sdp for sdp in sdps if sdp["id"] == src_sdp_idx)
dst_sdp = next(sdp for sdp in sdps if sdp["id"] == dst_sdp_idx)
src_match_criterion = src_sdp["service-match-criteria"][
"match-criterion"
][0]
dst_match_criterion = dst_sdp["service-match-criteria"][
"match-criterion"
][0]
src_match_criterion_ipv4_info = extract_match_criterion_ipv4_info(
src_match_criterion
)
dst_match_criterion_ipv4_info = extract_match_criterion_ipv4_info(
dst_match_criterion
)
src_ipv4_lan_prefixes = [
LANPrefixesDict(
lan=src_match_criterion_ipv4_info["dst_ip"],
lan_tag=src_match_criterion_ipv4_info["vlan"],
)
]
dst_ipv4_lan_prefixes = [
LANPrefixesDict(
lan=dst_match_criterion_ipv4_info["dst_ip"],
lan_tag=dst_match_criterion_ipv4_info["vlan"],
)
]
src_ce_address = src_endpoint_settings["address_ip"]
src_pe_address = src_ce_address
src_ce_address_prefix = src_endpoint_settings["address_prefix"]
dst_ce_address = dst_endpoint_settings["address_ip"]
dst_pe_address = dst_ce_address
dst_ce_address_prefix = dst_endpoint_settings["address_prefix"]
resource_value_dict = {
"uuid": service_uuid,
"src_device_name": src_device_name,
"src_endpoint_name": src_endpoint_obj.name,
"src_site_location": src_endpoint_settings["site_location"],
"src_ipv4_lan_prefixes": src_ipv4_lan_prefixes,
"src_ce_address": src_ce_address,
"src_pe_address": src_pe_address,
"src_ce_pe_network_prefix": src_ce_address_prefix,
"src_mtu": MTU,
"dst_device_name": dst_device_name,
"dst_endpoint_name": dst_endpoint_obj.name,
"dst_site_location": dst_endpoint_settings["site_location"],
"dst_ipv4_lan_prefixes": dst_ipv4_lan_prefixes,
"dst_ce_address": dst_ce_address,
"dst_pe_address": dst_pe_address,
"dst_ce_pe_network_prefix": dst_ce_address_prefix,
"dst_mtu": MTU,
}
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)
results.append(True)
except Exception as e: # pylint: disable=broad-except
LOGGER.exception(
"Unable to SetEndpoint for Service({:s})".format(str(service_uuid))
......@@ -160,7 +330,6 @@ class L3NM_IETFL3VPN_ServiceHandler(_ServiceHandler):
DeviceId(**json_device_id(dst_device_uuid))
)
dst_controller = self.__task_executor.get_device_controller(dst_device)
if (
src_controller.device_id.device_uuid.uuid
!= dst_controller.device_id.device_uuid.uuid
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment