Skip to content
Snippets Groups Projects
Commit ae072b22 authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

PathComp component - Frontend:

- Corrected endpoint-to-link datastructure
- Improved identification of config rules by device/endpoint uuid/name
- Assumed links are unidirectional
- Rewritten sub-serice computation logic to consider intermediate controllers
- Rewritten method eropath_to_hops based on new endpoint-to-link datastructure
- Minor bug resolutions
- Updated test pathcomp temporary code
parent 79f603af
No related branches found
No related tags found
2 merge requests!142Release TeraFlowSDN 2.1,!71OFC'23 + IETF L2VPN Device Driver + Device Controllers + Multiple small improvements
Showing
with 568 additions and 403 deletions
......@@ -25,6 +25,10 @@ from .tools.ComposeRequest import compose_device, compose_link, compose_service
from .tools.ComputeSubServices import (
convert_explicit_path_hops_to_connections, convert_explicit_path_hops_to_plain_connection)
SRC_END = 'src'
DST_END = 'dst'
SENSE = [SRC_END, DST_END]
class _Algorithm:
def __init__(self, algorithm_id : str, sync_paths : bool, class_name=__name__) -> None:
# algorithm_id: algorithm to be executed
......@@ -44,7 +48,7 @@ class _Algorithm:
self.endpoint_name_mapping : Dict[Tuple[str, str], str] = dict()
self.link_list : List[Dict] = list()
self.link_dict : Dict[str, Tuple[Dict, Link]] = dict()
self.endpoint_to_link_dict : Dict[Tuple[str, str], Tuple[Dict, Link]] = dict()
self.endpoint_to_link_dict : Dict[Tuple[str, str, str], Tuple[Dict, Link]] = dict()
self.service_list : List[Dict] = list()
self.service_dict : Dict[Tuple[str, str], Tuple[Dict, Service]] = dict()
......@@ -86,11 +90,11 @@ class _Algorithm:
link_uuid = json_link['link_Id']
self.link_dict[link_uuid] = (json_link, grpc_link)
for link_endpoint_id in json_link['link_endpoint_ids']:
for i,link_endpoint_id in enumerate(json_link['link_endpoint_ids']):
link_endpoint_id = link_endpoint_id['endpoint_id']
device_uuid = link_endpoint_id['device_id']
endpoint_uuid = link_endpoint_id['endpoint_uuid']
endpoint_key = (device_uuid, endpoint_uuid)
endpoint_key = (device_uuid, endpoint_uuid, SENSE[i])
link_tuple = (json_link, grpc_link)
self.endpoint_to_link_dict[endpoint_key] = link_tuple
......@@ -175,7 +179,9 @@ class _Algorithm:
MSG = 'Unhandled generic Config Rules for service {:s} {:s}'
self.logger.warning(MSG.format(str(service_uuid), str(ServiceTypeEnum.Name(service_type))))
compose_device_config_rules(config_rules, service.service_config.config_rules, path_hops)
compose_device_config_rules(
config_rules, service.service_config.config_rules, path_hops,
self.device_name_mapping, self.endpoint_name_mapping)
if path_hops is not None and len(path_hops) > 0:
ingress_endpoint_id = service.service_endpoint_ids.add()
......@@ -214,7 +220,7 @@ class _Algorithm:
if no_path_issue is not None:
# no path found: leave connection with no endpoints
# no_path_issue == 1 => no path due to a constraint
grpc_services[service_key] = grpc_orig_service
grpc_services[orig_service_key] = grpc_orig_service
continue
orig_config_rules = grpc_orig_service.service_config.config_rules
......
......@@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json, re
from typing import Dict, List, Optional
import itertools, json, re
from typing import Dict, List, Optional, Tuple
from common.proto.context_pb2 import ConfigRule
from common.tools.object_factory.ConfigRule import json_config_rule_set
......@@ -71,7 +71,11 @@ def compose_l3nm_config_rules(main_service_config_rules : List, subservice_confi
def compose_tapi_config_rules(main_service_config_rules : List, subservice_config_rules : List) -> None:
compose_config_rules(main_service_config_rules, subservice_config_rules, TAPI_SETTINGS_FIELD_DEFAULTS)
def compose_device_config_rules(config_rules : List, subservice_config_rules : List, path_hops : List) -> None:
def compose_device_config_rules(
config_rules : List, subservice_config_rules : List, path_hops : List,
device_name_mapping : Dict[str, str], endpoint_name_mapping : Dict[Tuple[str, str], str]
) -> None:
endpoints_traversed = set()
for path_hop in path_hops:
device_uuid_or_name = path_hop['device']
......@@ -82,8 +86,16 @@ def compose_device_config_rules(config_rules : List, subservice_config_rules : L
if config_rule.WhichOneof('config_rule') != 'custom': continue
match = DEV_EP_SETTINGS.match(config_rule.custom.resource_key)
if match is None: continue
device_uuid_or_name = match.group(1)
device_name_or_uuid = device_name_mapping[device_uuid_or_name]
device_keys = {device_uuid_or_name, device_name_or_uuid}
endpoint_uuid_or_name = match.group(2)
dev_ep_kep = (device_uuid_or_name, endpoint_uuid_or_name)
if dev_ep_kep not in endpoints_traversed: continue
endpoint_name_or_uuid_1 = endpoint_name_mapping[(device_uuid_or_name, endpoint_uuid_or_name)]
endpoint_name_or_uuid_2 = endpoint_name_mapping[(device_name_or_uuid, endpoint_uuid_or_name)]
endpoint_keys = {endpoint_uuid_or_name, endpoint_name_or_uuid_1, endpoint_name_or_uuid_2}
device_endpoint_keys = set(itertools.product(device_keys, endpoint_keys))
if len(device_endpoint_keys.intersection(endpoints_traversed)) == 0: continue
subservice_config_rules.append(config_rule)
......@@ -118,11 +118,11 @@ def compose_link(grpc_link : Link) -> Dict:
for link_endpoint_id in grpc_link.link_endpoint_ids
]
forwarding_direction = LinkForwardingDirection.BIDIRECTIONAL.value
forwarding_direction = LinkForwardingDirection.UNIDIRECTIONAL.value
total_potential_capacity = compose_capacity(200, CapacityUnit.MBPS.value)
available_capacity = compose_capacity(200, CapacityUnit.MBPS.value)
cost_characteristics = compose_cost_characteristics('linkcost', '1', '0')
latency_characteristics = compose_latency_characteristics('2')
latency_characteristics = compose_latency_characteristics('1')
return {
'link_Id': link_uuid, 'link_endpoint_ids': endpoint_ids, 'forwarding_direction': forwarding_direction,
......
......@@ -30,145 +30,41 @@
# ]
#
# connections=[
# (UUID('7548edf7-ee7c-4adf-ac0f-c7a0c0dfba8e'), ServiceTypeEnum.TAPI, [
# (UUID('7548edf7-ee7c-4adf-ac0f-c7a0c0dfba8e'), ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE, [
# {'device': 'TN-OLS', 'ingress_ep': '833760219d0f', 'egress_ep': 'cf176771a4b9'}
# ], []),
# (UUID('c2e57966-5d82-4705-a5fe-44cf6487219e'), ServiceTypeEnum.L2NM, [
# (UUID('c2e57966-5d82-4705-a5fe-44cf6487219e'), ServiceTypeEnum.SERVICETYPE_L2NM, [
# {'device': 'CS1-GW1', 'ingress_ep': '10/1', 'egress_ep': '1/2'},
# {'device': 'TN-R2', 'ingress_ep': '1/2', 'egress_ep': '2/1'},
# {'device': 'TN-R3', 'ingress_ep': '2/1', 'egress_ep': '1/1'},
# {'device': 'CS2-GW1', 'ingress_ep': '1/1', 'egress_ep': '10/1'}
# ], [UUID('7548edf7-ee7c-4adf-ac0f-c7a0c0dfba8e')]),
# (UUID('1e205c82-f6ea-4977-9e97-dc27ef1f4802'), ServiceTypeEnum.L2NM, [
# (UUID('1e205c82-f6ea-4977-9e97-dc27ef1f4802'), ServiceTypeEnum.SERVICETYPE_L2NM, [
# {'device': 'DC1-GW', 'ingress_ep': 'int', 'egress_ep': 'eth1'},
# {'device': 'DC2-GW', 'ingress_ep': 'eth1', 'egress_ep': 'int'}
# ], [UUID('c2e57966-5d82-4705-a5fe-44cf6487219e')])
# ]
import enum, json, queue, uuid
import logging, queue, uuid
from typing import Dict, List, Optional, Tuple
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import Device, ServiceTypeEnum
from .ResourceGroups import IGNORED_DEVICE_TYPES, get_resource_classification
from .ServiceTypes import get_service_type
class StackActionEnum(enum.Enum):
PATH_INGRESS = 'ingress'
CREATE_CONNECTION = 'create'
APPEND_PATH_HOP = 'append'
CHAIN_CONNECTION = 'chain'
TERMINATE_CONNECTION = 'terminate'
def is_datacenter(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.DATACENTER, DeviceTypeEnum.EMULATED_DATACENTER}
def is_packet_router(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.PACKET_ROUTER, DeviceTypeEnum.EMULATED_PACKET_ROUTER}
def is_packet_switch(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.PACKET_SWITCH, DeviceTypeEnum.EMULATED_PACKET_SWITCH}
def is_packet_device(dev_type : Optional[DeviceTypeEnum]) -> bool:
return is_packet_router(dev_type) or is_packet_switch(dev_type)
def is_tfs_controller(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.TERAFLOWSDN_CONTROLLER}
def is_mw_controller(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM, DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM}
def is_ipm_controller(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.XR_CONSTELLATION, DeviceTypeEnum.EMULATED_XR_CONSTELLATION}
def is_ols_controller(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.OPEN_LINE_SYSTEM, DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM}
def is_subdevice(dev_manager : Optional[str]) -> bool:
return dev_manager is not None
def is_subdevice_equal(dev_manager_a : Optional[str], dev_manager_b : Optional[str]) -> bool:
if dev_manager_a is None and dev_manager_b is None: return True
if dev_manager_a is not None and dev_manager_b is not None: return dev_manager_a == dev_manager_b
return False
def get_action(
prv_type : Optional[DeviceTypeEnum], prv_manager : Optional[str],
cur_type : DeviceTypeEnum, cur_manager : Optional[str]
) -> StackActionEnum:
if prv_type is None:
return StackActionEnum.PATH_INGRESS
if is_datacenter(prv_type):
if is_packet_device(cur_type): return StackActionEnum.CREATE_CONNECTION
if is_tfs_controller(cur_type): return StackActionEnum.CREATE_CONNECTION
if is_packet_device(prv_type):
if is_datacenter(cur_type): return StackActionEnum.TERMINATE_CONNECTION
if is_packet_device(cur_type):
if is_subdevice_equal(cur_manager, prv_manager): return StackActionEnum.APPEND_PATH_HOP
if is_subdevice(prv_manager) and not is_subdevice(cur_manager): return StackActionEnum.TERMINATE_CONNECTION
if not is_subdevice(prv_manager) and is_subdevice(cur_manager): return StackActionEnum.CREATE_CONNECTION
if is_mw_controller(cur_type) and not is_subdevice(cur_manager): return StackActionEnum.CREATE_CONNECTION
if is_ols_controller(cur_type) and not is_subdevice(cur_manager): return StackActionEnum.CREATE_CONNECTION
if is_tfs_controller(cur_type) and is_subdevice(cur_manager): return StackActionEnum.CREATE_CONNECTION
if is_mw_controller(prv_type) or is_ols_controller(prv_type):
if is_packet_device(cur_type): return StackActionEnum.TERMINATE_CONNECTION
if is_tfs_controller(prv_type):
if is_tfs_controller(cur_type) and is_subdevice_equal(prv_manager, cur_manager): return StackActionEnum.APPEND_PATH_HOP
if is_datacenter(cur_type): return StackActionEnum.TERMINATE_CONNECTION
if is_packet_device(cur_type): return StackActionEnum.TERMINATE_CONNECTION
if is_mw_controller(cur_type) or is_ols_controller(cur_type): return StackActionEnum.CHAIN_CONNECTION
str_fields = ', '.join([
'prv_type={:s}'.format(str(prv_type)), 'prv_manager={:s}'.format(str(prv_manager)),
'cur_type={:s}'.format(str(cur_type)), 'cur_manager={:s}'.format(str(cur_manager)),
])
raise Exception('Undefined Action for ({:s})'.format(str_fields))
def get_device_manager_uuid(device : Device) -> Optional[str]:
for config_rule in device.device_config.config_rules:
if config_rule.WhichOneof('config_rule') != 'custom': continue
if config_rule.custom.resource_key != '_manager': continue
device_manager_id = json.loads(config_rule.custom.resource_value)
return device_manager_id['uuid']
return None
def get_device_type(
grpc_device : Device, device_dict : Dict[str, Tuple[Dict, Device]], device_manager_uuid : Optional[str]
) -> DeviceTypeEnum:
if device_manager_uuid is None:
return DeviceTypeEnum._value2member_map_[grpc_device.device_type] # pylint: disable=no-member
device_manager_tuple = device_dict.get(device_manager_uuid)
if device_manager_tuple is None: raise Exception('Device({:s}) not found'.format(str(device_manager_uuid)))
_,grpc_device = device_manager_tuple
return DeviceTypeEnum._value2member_map_[grpc_device.device_type] # pylint: disable=no-member
SERVICE_TYPE_LXNM = {ServiceTypeEnum.SERVICETYPE_L3NM, ServiceTypeEnum.SERVICETYPE_L2NM}
def get_service_type(device_type : DeviceTypeEnum, prv_service_type : ServiceTypeEnum) -> ServiceTypeEnum:
if is_tfs_controller(device_type) or is_packet_router(device_type):
if prv_service_type in SERVICE_TYPE_LXNM: return prv_service_type
if is_packet_switch(device_type) or is_mw_controller(device_type):
if prv_service_type == ServiceTypeEnum.SERVICETYPE_L2NM: return prv_service_type
if is_ols_controller(device_type) or is_ipm_controller(device_type):
return ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE
str_fields = ', '.join([
'device_type={:s}'.format(str(device_type)),
])
raise Exception('Undefined Service Type for ({:s})'.format(str_fields))
LOGGER = logging.getLogger(__name__)
def convert_explicit_path_hops_to_connections(
path_hops : List[Dict], device_dict : Dict[str, Tuple[Dict, Device]],
main_service_uuid : str, main_service_type : ServiceTypeEnum
) -> List[Tuple[str, int, List[str], List[str]]]:
LOGGER.debug('path_hops={:s}'.format(str(path_hops)))
connection_stack = queue.LifoQueue()
connections : List[Tuple[str, int, List[str], List[str]]] = list()
prv_device_uuid = None
prv_device_type = None
prv_manager_uuid = None
prv_res_class : Tuple[Optional[int], Optional[DeviceTypeEnum], Optional[str]] = None, None, None
for path_hop in path_hops:
device_uuid = path_hop['device']
......@@ -177,29 +73,35 @@ def convert_explicit_path_hops_to_connections(
if device_tuple is None: raise Exception('Device({:s}) not found'.format(str(device_uuid)))
_,grpc_device = device_tuple
manager_uuid = get_device_manager_uuid(grpc_device)
device_type = get_device_type(grpc_device, device_dict, manager_uuid)
action = get_action(prv_device_type, prv_manager_uuid, device_type, manager_uuid)
res_class = get_resource_classification(grpc_device, device_dict)
if res_class[1] in IGNORED_DEVICE_TYPES: continue
if action == StackActionEnum.PATH_INGRESS:
if prv_res_class[0] is None:
# path ingress
connection_stack.put((main_service_uuid, main_service_type, [path_hop], []))
elif action == StackActionEnum.CREATE_CONNECTION:
connection_uuid = str(uuid.uuid4())
prv_service_type = connection_stack.queue[-1][1]
service_type = get_service_type(device_type, prv_service_type)
connection_stack.put((connection_uuid, service_type, [path_hop], []))
elif action == StackActionEnum.APPEND_PATH_HOP:
connection_stack.queue[-1][2].append(path_hop)
elif action == StackActionEnum.CHAIN_CONNECTION:
connection = connection_stack.get()
connections.append(connection)
connection_stack.queue[-1][3].append(connection[0])
elif prv_res_class[0] > res_class[0]:
# create underlying connection
connection_uuid = str(uuid.uuid4())
prv_service_type = connection_stack.queue[-1][1]
service_type = get_service_type(device_type, prv_service_type)
service_type = get_service_type(res_class[1], prv_service_type)
connection_stack.put((connection_uuid, service_type, [path_hop], []))
elif action == StackActionEnum.TERMINATE_CONNECTION:
elif prv_res_class[0] == res_class[0]:
# same resource group kind
if prv_res_class[1] == res_class[1] and prv_res_class[2] == res_class[2]:
# same device type and device manager: connection continues
connection_stack.queue[-1][2].append(path_hop)
else:
# different device type or device manager: chain connections
connection = connection_stack.get()
connections.append(connection)
connection_stack.queue[-1][3].append(connection[0])
connection_uuid = str(uuid.uuid4())
prv_service_type = connection_stack.queue[-1][1]
service_type = get_service_type(res_class[1], prv_service_type)
connection_stack.put((connection_uuid, service_type, [path_hop], []))
elif prv_res_class[0] < res_class[0]:
# underlying connection ended
connection = connection_stack.get()
connections.append(connection)
connection_stack.queue[-1][3].append(connection[0])
......@@ -208,11 +110,11 @@ def convert_explicit_path_hops_to_connections(
raise Exception('Uncontrolled condition')
prv_device_uuid = device_uuid
prv_device_type = device_type
prv_manager_uuid = manager_uuid
prv_res_class = res_class
# path egress
connections.append(connection_stack.get())
LOGGER.debug('connections={:s}'.format(str(connections)))
assert connection_stack.empty()
return connections
......
......@@ -43,13 +43,17 @@
#
import logging
from typing import Dict, List
from typing import Dict, List, Tuple
from common.proto.context_pb2 import Link
LOGGER = logging.getLogger(__name__)
def eropath_to_hops(ero_path : List[Dict], endpoint_to_link_dict : Dict) -> List[Dict]:
def eropath_to_hops(
ero_path : List[Dict], endpoint_to_link_dict : Dict[Tuple[str, str, str], Tuple[Dict, Link]]
) -> List[Dict]:
try:
path_hops = []
num_ero_hops = len(ero_path)
for endpoint in ero_path:
device_uuid = endpoint['device_id']
endpoint_uuid = endpoint['endpoint_uuid']
......@@ -59,23 +63,17 @@ def eropath_to_hops(ero_path : List[Dict], endpoint_to_link_dict : Dict) -> List
continue
last_hop = path_hops[-1]
if (last_hop['device'] == device_uuid):
if ('ingress_ep' not in last_hop) or ('egress_ep' in last_hop): continue
last_hop['egress_ep'] = endpoint_uuid
continue
if last_hop['device'] != device_uuid: raise Exception('Malformed path')
last_hop['egress_ep'] = endpoint_uuid
if num_ero_hops - 1 == len(path_hops): break
endpoint_key = (last_hop['device'], last_hop['egress_ep'])
link_tuple = endpoint_to_link_dict.get(endpoint_key)
ingress = next(iter([
ep_id for ep_id in link_tuple[0]['link_endpoint_ids']
if (ep_id['endpoint_id']['device_id'] == device_uuid) and\
(ep_id['endpoint_id']['endpoint_uuid'] != endpoint_uuid)
]), None)
if ingress['endpoint_id']['device_id'] != device_uuid: raise Exception('Malformed path')
link_tuple = endpoint_to_link_dict[(device_uuid, endpoint_uuid, 'src')]
if link_tuple is None: raise Exception('Malformed path')
ingress = link_tuple[0]['link_endpoint_ids'][-1]
path_hops.append({
'device': ingress['endpoint_id']['device_id'],
'ingress_ep': ingress['endpoint_id']['endpoint_uuid'],
'egress_ep': endpoint_uuid,
'ingress_ep': ingress['endpoint_id']['endpoint_uuid']
})
return path_hops
except:
......
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from typing import Dict, Optional, Tuple
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import Device
from common.tools.grpc.Tools import grpc_message_to_json_string
DEVICE_TYPE_TO_DEEPNESS = {
DeviceTypeEnum.EMULATED_DATACENTER.value : 90,
DeviceTypeEnum.DATACENTER.value : 90,
DeviceTypeEnum.NETWORK.value : 90,
DeviceTypeEnum.TERAFLOWSDN_CONTROLLER.value : 80,
DeviceTypeEnum.EMULATED_PACKET_ROUTER.value : 70,
DeviceTypeEnum.PACKET_ROUTER.value : 70,
DeviceTypeEnum.EMULATED_PACKET_SWITCH.value : 60,
DeviceTypeEnum.PACKET_SWITCH.value : 60,
DeviceTypeEnum.EMULATED_P4_SWITCH.value : 60,
DeviceTypeEnum.P4_SWITCH.value : 60,
DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM.value : 40,
DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM.value : 40,
DeviceTypeEnum.EMULATED_XR_CONSTELLATION.value : 40,
DeviceTypeEnum.XR_CONSTELLATION.value : 40,
DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM.value : 30,
DeviceTypeEnum.OPEN_LINE_SYSTEM.value : 30,
DeviceTypeEnum.EMULATED_PACKET_RADIO_ROUTER.value : 10,
DeviceTypeEnum.PACKET_RADIO_ROUTER.value : 10,
DeviceTypeEnum.EMULATED_OPTICAL_TRANSPONDER.value : 10,
DeviceTypeEnum.OPTICAL_TRANSPONDER.value : 10,
DeviceTypeEnum.EMULATED_OPTICAL_ROADM.value : 10,
DeviceTypeEnum.OPTICAL_ROADM.value : 10,
DeviceTypeEnum.EMULATED_OPTICAL_SPLITTER.value : 0,
}
IGNORED_DEVICE_TYPES = {DeviceTypeEnum.EMULATED_OPTICAL_SPLITTER}
def get_device_manager_uuid(
device : Device
) -> Optional[str]:
for config_rule in device.device_config.config_rules:
if config_rule.WhichOneof('config_rule') != 'custom': continue
if config_rule.custom.resource_key != '_manager': continue
device_manager_id = json.loads(config_rule.custom.resource_value)
return device_manager_id['uuid']
return None
def _map_device_type(device : Device) -> DeviceTypeEnum:
device_type = DeviceTypeEnum._value2member_map_.get(device.device_type) # pylint: disable=no-member
if device_type is None:
MSG = 'Unsupported DeviceType({:s}) for Device({:s})'
raise Exception(MSG.format(str(device.device_type), grpc_message_to_json_string(device)))
return device_type
def _map_resource_to_deepness(device_type : DeviceTypeEnum) -> int:
deepness = DEVICE_TYPE_TO_DEEPNESS.get(device_type.value)
if deepness is None: raise Exception('Unsupported DeviceType({:s})'.format(str(device_type.value)))
return deepness
def get_device_type(
device : Device, device_dict : Dict[str, Tuple[Dict, Device]], device_manager_uuid : Optional[str]
) -> DeviceTypeEnum:
if device_manager_uuid is None: return _map_device_type(device)
device_manager_tuple = device_dict.get(device_manager_uuid)
if device_manager_tuple is None: raise Exception('Device({:s}) not found'.format(str(device_manager_uuid)))
_,device = device_manager_tuple
return _map_device_type(device)
def get_resource_classification(
device : Device, device_dict : Dict[str, Tuple[Dict, Device]]
) -> Tuple[int, DeviceTypeEnum, Optional[str]]:
device_manager_uuid = get_device_manager_uuid(device)
device_type = get_device_type(device, device_dict, device_manager_uuid)
resource_deepness = _map_resource_to_deepness(device_type)
return resource_deepness, device_type, device_manager_uuid
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import ServiceTypeEnum
PACKET_DEVICE_TYPES = {
DeviceTypeEnum.TERAFLOWSDN_CONTROLLER,
DeviceTypeEnum.PACKET_ROUTER, DeviceTypeEnum.EMULATED_PACKET_ROUTER,
DeviceTypeEnum.PACKET_SWITCH, DeviceTypeEnum.EMULATED_PACKET_SWITCH,
}
L2_DEVICE_TYPES = {
DeviceTypeEnum.PACKET_SWITCH, DeviceTypeEnum.EMULATED_PACKET_SWITCH,
DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM, DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM,
DeviceTypeEnum.PACKET_RADIO_ROUTER, DeviceTypeEnum.EMULATED_PACKET_RADIO_ROUTER,
DeviceTypeEnum.P4_SWITCH, DeviceTypeEnum.EMULATED_P4_SWITCH,
}
OPTICAL_DEVICE_TYPES = {
DeviceTypeEnum.OPEN_LINE_SYSTEM, DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM,
DeviceTypeEnum.XR_CONSTELLATION, DeviceTypeEnum.EMULATED_XR_CONSTELLATION,
DeviceTypeEnum.OPTICAL_ROADM, DeviceTypeEnum.EMULATED_OPTICAL_ROADM,
DeviceTypeEnum.OPTICAL_TRANSPONDER, DeviceTypeEnum.EMULATED_OPTICAL_TRANSPONDER,
}
SERVICE_TYPE_L2NM = {ServiceTypeEnum.SERVICETYPE_L2NM}
SERVICE_TYPE_L3NM = {ServiceTypeEnum.SERVICETYPE_L3NM}
SERVICE_TYPE_LXNM = {ServiceTypeEnum.SERVICETYPE_L3NM, ServiceTypeEnum.SERVICETYPE_L2NM}
SERVICE_TYPE_TAPI = {ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE}
def get_service_type(device_type : DeviceTypeEnum, prv_service_type : ServiceTypeEnum) -> ServiceTypeEnum:
if device_type in PACKET_DEVICE_TYPES and prv_service_type in SERVICE_TYPE_LXNM: return prv_service_type
if device_type in L2_DEVICE_TYPES: return ServiceTypeEnum.SERVICETYPE_L2NM
if device_type in OPTICAL_DEVICE_TYPES: return ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE
str_fields = ', '.join([
'device_type={:s}'.format(str(device_type)),
'prv_service_type={:s}'.format(str(prv_service_type)),
])
raise Exception('Undefined Service Type for ({:s})'.format(str_fields))
......@@ -30,167 +30,41 @@
# ]
#
# connections=[
# (UUID('7548edf7-ee7c-4adf-ac0f-c7a0c0dfba8e'), <DeviceLayerEnum.OPTICAL_CONTROLLER: 1>, [
# (UUID('7548edf7-ee7c-4adf-ac0f-c7a0c0dfba8e'), ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE, [
# {'device': 'TN-OLS', 'ingress_ep': '833760219d0f', 'egress_ep': 'cf176771a4b9'}
# ], []),
# (UUID('c2e57966-5d82-4705-a5fe-44cf6487219e'), <DeviceLayerEnum.PACKET_DEVICE: 30>, [
# (UUID('c2e57966-5d82-4705-a5fe-44cf6487219e'), ServiceTypeEnum.SERVICETYPE_L2NM, [
# {'device': 'CS1-GW1', 'ingress_ep': '10/1', 'egress_ep': '1/2'},
# {'device': 'TN-R2', 'ingress_ep': '1/2', 'egress_ep': '2/1'},
# {'device': 'TN-R3', 'ingress_ep': '2/1', 'egress_ep': '1/1'},
# {'device': 'CS2-GW1', 'ingress_ep': '1/1', 'egress_ep': '10/1'}
# ], [UUID('7548edf7-ee7c-4adf-ac0f-c7a0c0dfba8e')]),
# (UUID('1e205c82-f6ea-4977-9e97-dc27ef1f4802'), <DeviceLayerEnum.APPLICATION_DEVICE: 40>, [
# (UUID('1e205c82-f6ea-4977-9e97-dc27ef1f4802'), ServiceTypeEnum.SERVICETYPE_L2NM, [
# {'device': 'DC1-GW', 'ingress_ep': 'int', 'egress_ep': 'eth1'},
# {'device': 'DC2-GW', 'ingress_ep': 'eth1', 'egress_ep': 'int'}
# ], [UUID('c2e57966-5d82-4705-a5fe-44cf6487219e')])
# ]
import enum, json, queue, uuid
import logging, queue, uuid
from typing import Dict, List, Optional, Tuple
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import Device, ServiceTypeEnum #, DeviceDriverEnum as grpc_DeviceDriverEnum
#from .ConstantsMappings import DEVICE_TYPE_TO_LAYER, DeviceLayerEnum
class StackActionEnum(enum.Enum):
PATH_INGRESS = 'ingress'
CREATE_CONNECTION = 'create'
APPEND_PATH_HOP = 'append'
CHAIN_CONNECTION = 'chain'
TERMINATE_CONNECTION = 'terminate'
#class DeviceDriverEnum(enum.IntEnum):
# EMULATED = grpc_DeviceDriverEnum.DEVICEDRIVER_UNDEFINED
# OPENCONFIG = grpc_DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG
# TRANSPORT_API = grpc_DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API
# P4 = grpc_DeviceDriverEnum.DEVICEDRIVER_P4
# IETF_NETWORK_TOPOLOGY = grpc_DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY
# ONF_TR_352 = grpc_DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352
# XR = grpc_DeviceDriverEnum.DEVICEDRIVER_XR
# IETF_L2VPN = grpc_DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN
def is_datacenter(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.DATACENTER, DeviceTypeEnum.EMULATED_DATACENTER}
def is_packet_router(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.PACKET_ROUTER, DeviceTypeEnum.EMULATED_PACKET_ROUTER}
def is_packet_switch(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.PACKET_SWITCH, DeviceTypeEnum.EMULATED_PACKET_SWITCH}
def is_packet_device(dev_type : Optional[DeviceTypeEnum]) -> bool:
return is_packet_router(dev_type) or is_packet_switch(dev_type)
def is_tfs_controller(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.TERAFLOWSDN_CONTROLLER}
def is_mw_controller(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM, DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM}
def is_ipm_controller(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.XR_CONSTELLATION, DeviceTypeEnum.EMULATED_XR_CONSTELLATION}
def is_ols_controller(dev_type : Optional[DeviceTypeEnum]) -> bool:
return dev_type in {DeviceTypeEnum.OPEN_LINE_SYSTEM, DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM}
def is_subdevice(dev_manager : Optional[str]) -> bool:
return dev_manager is not None
def is_subdevice_equal(dev_manager_a : Optional[str], dev_manager_b : Optional[str]) -> bool:
if dev_manager_a is None and dev_manager_b is None: return True
if dev_manager_a is not None and dev_manager_b is not None: return dev_manager_a == dev_manager_b
return False
#def has_driver(dev_drivers : List[DeviceDriverEnum], dev_driver : DeviceDriverEnum) -> bool:
# return dev_driver in dev_drivers
def get_action(
prv_type : Optional[DeviceTypeEnum], prv_manager : Optional[str],
cur_type : DeviceTypeEnum, cur_manager : Optional[str]
) -> StackActionEnum:
if prv_type is None:
return StackActionEnum.PATH_INGRESS
if is_datacenter(prv_type):
if is_packet_device(cur_type): return StackActionEnum.CREATE_CONNECTION
if is_tfs_controller(cur_type): return StackActionEnum.CREATE_CONNECTION
if is_packet_device(prv_type):
if is_datacenter(cur_type): return StackActionEnum.TERMINATE_CONNECTION
if is_packet_device(cur_type):
if is_subdevice_equal(cur_manager, prv_manager): return StackActionEnum.APPEND_PATH_HOP
if is_subdevice(prv_manager) and not is_subdevice(cur_manager): return StackActionEnum.TERMINATE_CONNECTION
if not is_subdevice(prv_manager) and is_subdevice(cur_manager): return StackActionEnum.CREATE_CONNECTION
if is_mw_controller(cur_type) and not is_subdevice(cur_manager): return StackActionEnum.CREATE_CONNECTION
if is_ols_controller(cur_type) and not is_subdevice(cur_manager): return StackActionEnum.CREATE_CONNECTION
if is_tfs_controller(cur_type) and is_subdevice(cur_manager): return StackActionEnum.CREATE_CONNECTION
if is_mw_controller(prv_type) or is_ols_controller(prv_type):
if is_packet_device(cur_type): return StackActionEnum.TERMINATE_CONNECTION
if is_tfs_controller(prv_type):
if is_tfs_controller(cur_type) and is_subdevice_equal(prv_manager, cur_manager): return StackActionEnum.APPEND_PATH_HOP
if is_datacenter(cur_type): return StackActionEnum.TERMINATE_CONNECTION
if is_packet_device(cur_type): return StackActionEnum.TERMINATE_CONNECTION
if is_mw_controller(cur_type) or is_ols_controller(cur_type): return StackActionEnum.CHAIN_CONNECTION
str_fields = ', '.join([
'prv_type={:s}'.format(str(prv_type)), 'prv_manager={:s}'.format(str(prv_manager)),
'cur_type={:s}'.format(str(cur_type)), 'cur_manager={:s}'.format(str(cur_manager)),
])
raise Exception('Undefined Action for ({:s})'.format(str_fields))
def get_device_manager_uuid(device : Device) -> Optional[str]:
for config_rule in device.device_config.config_rules:
if config_rule.WhichOneof('config_rule') != 'custom': continue
if config_rule.custom.resource_key != '_manager': continue
device_manager_id = json.loads(config_rule.custom.resource_value)
return device_manager_id['uuid']
return None
def get_device_type(
grpc_device : Device, device_dict : Dict[str, Tuple[Dict, Device]], device_manager_uuid : Optional[str]
) -> DeviceTypeEnum:
if device_manager_uuid is None:
return DeviceTypeEnum._value2member_map_[grpc_device.device_type] # pylint: disable=no-member
device_manager_tuple = device_dict.get(device_manager_uuid)
if device_manager_tuple is None: raise Exception('Device({:s}) not found'.format(str(device_manager_uuid)))
_,grpc_device = device_manager_tuple
return DeviceTypeEnum._value2member_map_[grpc_device.device_type] # pylint: disable=no-member
#manager_drivers = set(grpc_device.device_drivers)
#if DeviceDriverEnum.DEVICEDRIVER_IETF_L2VPN in manager_drivers:
# device_layer = DeviceLayerEnum.MAC_LAYER_CONTROLLER
#else:
# device_type = json_device['device_type']
# device_layer = DEVICE_TYPE_TO_LAYER.get(device_type)
# if device_layer is None: raise Exception('Undefined Layer for DeviceType({:s})'.format(str(device_type)))
SERVICE_TYPE_LXNM = {ServiceTypeEnum.SERVICETYPE_L3NM, ServiceTypeEnum.SERVICETYPE_L2NM}
def get_service_type(device_type : DeviceTypeEnum, prv_service_type : ServiceTypeEnum) -> ServiceTypeEnum:
if is_tfs_controller(device_type) or is_packet_router(device_type):
if prv_service_type in SERVICE_TYPE_LXNM: return prv_service_type
if is_packet_switch(device_type) or is_mw_controller(device_type):
if prv_service_type == ServiceTypeEnum.SERVICETYPE_L2NM: return prv_service_type
if is_ols_controller(device_type) or is_ipm_controller(device_type):
return ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE
str_fields = ', '.join([
'device_type={:s}'.format(str(device_type)),
])
raise Exception('Undefined Service Type for ({:s})'.format(str_fields))
from common.proto.context_pb2 import Device, ServiceTypeEnum
from .ResourceGroups import IGNORED_DEVICE_TYPES, get_resource_classification
from .ServiceTypes import get_service_type
LOGGER = logging.getLogger(__name__)
def convert_explicit_path_hops_to_connections(
path_hops : List[Dict], device_dict : Dict[str, Tuple[Dict, Device]],
main_service_uuid : str, main_service_type : ServiceTypeEnum
) -> List[Tuple[str, int, List[str], List[str]]]:
LOGGER.debug('path_hops={:s}'.format(str(path_hops)))
connection_stack = queue.LifoQueue()
connections : List[Tuple[str, int, List[str], List[str]]] = list()
prv_device_uuid = None
prv_device_type = None
prv_manager_uuid = None
prv_res_class : Tuple[Optional[int], Optional[DeviceTypeEnum], Optional[str]] = None, None, None
for path_hop in path_hops:
device_uuid = path_hop['device']
......@@ -199,29 +73,35 @@ def convert_explicit_path_hops_to_connections(
if device_tuple is None: raise Exception('Device({:s}) not found'.format(str(device_uuid)))
_,grpc_device = device_tuple
manager_uuid = get_device_manager_uuid(grpc_device)
device_type = get_device_type(grpc_device, device_dict, manager_uuid)
action = get_action(prv_device_type, prv_manager_uuid, device_type, manager_uuid)
res_class = get_resource_classification(grpc_device, device_dict)
if res_class[1] in IGNORED_DEVICE_TYPES: continue
if action == StackActionEnum.PATH_INGRESS:
if prv_res_class[0] is None:
# path ingress
connection_stack.put((main_service_uuid, main_service_type, [path_hop], []))
elif action == StackActionEnum.CREATE_CONNECTION:
connection_uuid = str(uuid.uuid4())
prv_service_type = connection_stack.queue[-1][1]
service_type = get_service_type(device_type, prv_service_type)
connection_stack.put((connection_uuid, service_type, [path_hop], []))
elif action == StackActionEnum.APPEND_PATH_HOP:
connection_stack.queue[-1][2].append(path_hop)
elif action == StackActionEnum.CHAIN_CONNECTION:
connection = connection_stack.get()
connections.append(connection)
connection_stack.queue[-1][3].append(connection[0])
elif prv_res_class[0] > res_class[0]:
# create underlying connection
connection_uuid = str(uuid.uuid4())
prv_service_type = connection_stack.queue[-1][1]
service_type = get_service_type(device_type, prv_service_type)
service_type = get_service_type(res_class[1], prv_service_type)
connection_stack.put((connection_uuid, service_type, [path_hop], []))
elif action == StackActionEnum.TERMINATE_CONNECTION:
elif prv_res_class[0] == res_class[0]:
# same resource group kind
if prv_res_class[1] == res_class[1] and prv_res_class[2] == res_class[2]:
# same device type and device manager: connection continues
connection_stack.queue[-1][2].append(path_hop)
else:
# different device type or device manager: chain connections
connection = connection_stack.get()
connections.append(connection)
connection_stack.queue[-1][3].append(connection[0])
connection_uuid = str(uuid.uuid4())
prv_service_type = connection_stack.queue[-1][1]
service_type = get_service_type(res_class[1], prv_service_type)
connection_stack.put((connection_uuid, service_type, [path_hop], []))
elif prv_res_class[0] < res_class[0]:
# underlying connection ended
connection = connection_stack.get()
connections.append(connection)
connection_stack.queue[-1][3].append(connection[0])
......@@ -230,11 +110,11 @@ def convert_explicit_path_hops_to_connections(
raise Exception('Uncontrolled condition')
prv_device_uuid = device_uuid
prv_device_type = device_type
prv_manager_uuid = manager_uuid
prv_res_class = res_class
# path egress
connections.append(connection_stack.get())
LOGGER.debug('connections={:s}'.format(str(connections)))
assert connection_stack.empty()
return connections
......
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from typing import Dict, Optional, Tuple
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import Device
from common.tools.grpc.Tools import grpc_message_to_json_string
DEVICE_TYPE_TO_DEEPNESS = {
DeviceTypeEnum.EMULATED_DATACENTER.value : 90,
DeviceTypeEnum.DATACENTER.value : 90,
DeviceTypeEnum.NETWORK.value : 90,
DeviceTypeEnum.TERAFLOWSDN_CONTROLLER.value : 80,
DeviceTypeEnum.EMULATED_PACKET_ROUTER.value : 70,
DeviceTypeEnum.PACKET_ROUTER.value : 70,
DeviceTypeEnum.EMULATED_PACKET_SWITCH.value : 60,
DeviceTypeEnum.PACKET_SWITCH.value : 60,
DeviceTypeEnum.EMULATED_P4_SWITCH.value : 60,
DeviceTypeEnum.P4_SWITCH.value : 60,
DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM.value : 40,
DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM.value : 40,
DeviceTypeEnum.EMULATED_XR_CONSTELLATION.value : 40,
DeviceTypeEnum.XR_CONSTELLATION.value : 40,
DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM.value : 30,
DeviceTypeEnum.OPEN_LINE_SYSTEM.value : 30,
DeviceTypeEnum.EMULATED_PACKET_RADIO_ROUTER.value : 10,
DeviceTypeEnum.PACKET_RADIO_ROUTER.value : 10,
DeviceTypeEnum.EMULATED_OPTICAL_TRANSPONDER.value : 10,
DeviceTypeEnum.OPTICAL_TRANSPONDER.value : 10,
DeviceTypeEnum.EMULATED_OPTICAL_ROADM.value : 10,
DeviceTypeEnum.OPTICAL_ROADM.value : 10,
DeviceTypeEnum.EMULATED_OPTICAL_SPLITTER.value : 0,
}
IGNORED_DEVICE_TYPES = {DeviceTypeEnum.EMULATED_OPTICAL_SPLITTER}
def get_device_manager_uuid(
device : Device
) -> Optional[str]:
for config_rule in device.device_config.config_rules:
if config_rule.WhichOneof('config_rule') != 'custom': continue
if config_rule.custom.resource_key != '_manager': continue
device_manager_id = json.loads(config_rule.custom.resource_value)
return device_manager_id['uuid']
return None
def _map_device_type(device : Device) -> DeviceTypeEnum:
device_type = DeviceTypeEnum._value2member_map_.get(device.device_type) # pylint: disable=no-member
if device_type is None:
MSG = 'Unsupported DeviceType({:s}) for Device({:s})'
raise Exception(MSG.format(str(device.device_type), grpc_message_to_json_string(device)))
return device_type
def _map_resource_to_deepness(device_type : DeviceTypeEnum) -> int:
deepness = DEVICE_TYPE_TO_DEEPNESS.get(device_type.value)
if deepness is None: raise Exception('Unsupported DeviceType({:s})'.format(str(device_type.value)))
return deepness
def get_device_type(
device : Device, device_dict : Dict[str, Tuple[Dict, Device]], device_manager_uuid : Optional[str]
) -> DeviceTypeEnum:
if device_manager_uuid is None: return _map_device_type(device)
device_manager_tuple = device_dict.get(device_manager_uuid)
if device_manager_tuple is None: raise Exception('Device({:s}) not found'.format(str(device_manager_uuid)))
_,device = device_manager_tuple
return _map_device_type(device)
def get_resource_classification(
device : Device, device_dict : Dict[str, Tuple[Dict, Device]]
) -> Tuple[int, DeviceTypeEnum, Optional[str]]:
device_manager_uuid = get_device_manager_uuid(device)
device_type = get_device_type(device, device_dict, device_manager_uuid)
resource_deepness = _map_resource_to_deepness(device_type)
return resource_deepness, device_type, device_manager_uuid
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import ServiceTypeEnum
PACKET_DEVICE_TYPES = {
DeviceTypeEnum.TERAFLOWSDN_CONTROLLER,
DeviceTypeEnum.PACKET_ROUTER, DeviceTypeEnum.EMULATED_PACKET_ROUTER,
DeviceTypeEnum.PACKET_SWITCH, DeviceTypeEnum.EMULATED_PACKET_SWITCH,
}
L2_DEVICE_TYPES = {
DeviceTypeEnum.PACKET_SWITCH, DeviceTypeEnum.EMULATED_PACKET_SWITCH,
DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM, DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM,
DeviceTypeEnum.PACKET_RADIO_ROUTER, DeviceTypeEnum.EMULATED_PACKET_RADIO_ROUTER,
DeviceTypeEnum.P4_SWITCH, DeviceTypeEnum.EMULATED_P4_SWITCH,
}
OPTICAL_DEVICE_TYPES = {
DeviceTypeEnum.OPEN_LINE_SYSTEM, DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM,
DeviceTypeEnum.XR_CONSTELLATION, DeviceTypeEnum.EMULATED_XR_CONSTELLATION,
DeviceTypeEnum.OPTICAL_ROADM, DeviceTypeEnum.EMULATED_OPTICAL_ROADM,
DeviceTypeEnum.OPTICAL_TRANSPONDER, DeviceTypeEnum.EMULATED_OPTICAL_TRANSPONDER,
}
SERVICE_TYPE_L2NM = {ServiceTypeEnum.SERVICETYPE_L2NM}
SERVICE_TYPE_L3NM = {ServiceTypeEnum.SERVICETYPE_L3NM}
SERVICE_TYPE_LXNM = {ServiceTypeEnum.SERVICETYPE_L3NM, ServiceTypeEnum.SERVICETYPE_L2NM}
SERVICE_TYPE_TAPI = {ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE}
def get_service_type(device_type : DeviceTypeEnum, prv_service_type : ServiceTypeEnum) -> ServiceTypeEnum:
if device_type in PACKET_DEVICE_TYPES and prv_service_type in SERVICE_TYPE_LXNM: return prv_service_type
if device_type in L2_DEVICE_TYPES: return ServiceTypeEnum.SERVICETYPE_L2NM
if device_type in OPTICAL_DEVICE_TYPES: return ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE
str_fields = ', '.join([
'device_type={:s}'.format(str(device_type)),
'prv_service_type={:s}'.format(str(prv_service_type)),
])
raise Exception('Undefined Service Type for ({:s})'.format(str_fields))
......@@ -15,101 +15,56 @@
import json
from typing import Dict, Tuple
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import ConfigActionEnum, Device
path_hops = [
{'device': 'DC1', 'ingress_ep': 'int', 'egress_ep': 'eth1'},
{'device': 'PE1', 'ingress_ep': '1/1', 'egress_ep': '1/2'},
{'device': 'MW1-2', 'ingress_ep': '172.18.0.1:1', 'egress_ep': '172.18.0.2:1'},
{'device': 'R1', 'ingress_ep': '1/1', 'egress_ep': '1/3'},
{'device': 'OLS', 'ingress_ep': 'aade6001-f00b-5e2f-a357-6a0a9d3de870', 'egress_ep': '0ef74f99-1acc-57bd-ab9d-4b958b06c513'},
{'device': 'R2', 'ingress_ep': '1/1', 'egress_ep': '1/2'},
{'device': 'PE3', 'ingress_ep': '1/1', 'egress_ep': '1/2'},
{'device': 'DC2', 'ingress_ep': 'eth1', 'egress_ep': 'int'}
{'device': 'DC1', 'ingress_ep': 'int', 'egress_ep': 'eth1' },
{'device': 'PE1', 'ingress_ep': '1/1', 'egress_ep': '1/2' },
{'device': 'MW1-2', 'ingress_ep': '172.18.0.1:1', 'egress_ep': '172.18.0.2:1' },
{'device': 'HUB1', 'ingress_ep': '1/1', 'egress_ep': 'XR-T1' },
{'device': 'splitter', 'ingress_ep': 'common', 'egress_ep': 'leaf1' },
{'device': 'OLS', 'ingress_ep': 'node_1_port_13-input', 'egress_ep': 'node_4_port_13-output'},
{'device': 'LEAF2', 'ingress_ep': 'XR-T1', 'egress_ep': '1/1' },
{'device': 'PE4', 'ingress_ep': '1/1', 'egress_ep': '1/2' },
{'device': 'DC2', 'ingress_ep': 'eth2', 'egress_ep': 'int' }
]
device_dict = {
'R3': {'device_Id': 'R3', 'device_type': 'emu-packet-router', 'device_endpoints': [
{'endpoint_id': {'device_id': 'R3', 'endpoint_uuid': '1/1'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'R3', 'endpoint_uuid': '1/2'}, 'endpoint_type': 'copper/internal'}
]},
'PE4': {'device_Id': 'PE4', 'device_type': 'emu-packet-router', 'device_endpoints': [
{'endpoint_id': {'device_id': 'PE4', 'endpoint_uuid': 'mgmt'}, 'endpoint_type': 'mgmt'},
{'endpoint_id': {'device_id': 'PE4', 'endpoint_uuid': '1/1'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'PE4', 'endpoint_uuid': '1/2'}, 'endpoint_type': 'copper/internal'}
]},
'PE2': {'device_Id': 'PE2', 'device_type': 'emu-packet-router', 'device_endpoints': [
{'endpoint_id': {'device_id': 'PE2', 'endpoint_uuid': '1/1'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'PE2', 'endpoint_uuid': 'mgmt'}, 'endpoint_type': 'mgmt'},
{'endpoint_id': {'device_id': 'PE2', 'endpoint_uuid': '1/2'}, 'endpoint_type': 'copper/internal'}
]},
'R1': {'device_Id': 'R1', 'device_type': 'emu-packet-router', 'device_endpoints': [
{'endpoint_id': {'device_id': 'R1', 'endpoint_uuid': '1/1'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'R1', 'endpoint_uuid': '1/3'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'R1', 'endpoint_uuid': '1/2'}, 'endpoint_type': 'copper/internal'}
]},
'PE3': {'device_Id': 'PE3', 'device_type': 'emu-packet-router', 'device_endpoints': [
{'endpoint_id': {'device_id': 'PE3', 'endpoint_uuid': '1/1'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'PE3', 'endpoint_uuid': '1/2'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'PE3', 'endpoint_uuid': 'mgmt'}, 'endpoint_type': 'mgmt'}
]},
'OLS': {'device_Id': 'OLS', 'device_type': 'emu-open-line-system', 'device_endpoints': [
{'endpoint_id': {'device_id': 'OLS', 'endpoint_uuid': '0ef74f99-1acc-57bd-ab9d-4b958b06c513'}, 'endpoint_type': 'optical'},
{'endpoint_id': {'device_id': 'OLS', 'endpoint_uuid': '50296d99-58cc-5ce7-82f5-fc8ee4eec2ec'}, 'endpoint_type': 'optical'},
{'endpoint_id': {'device_id': 'OLS', 'endpoint_uuid': 'aade6001-f00b-5e2f-a357-6a0a9d3de870'}, 'endpoint_type': 'optical'},
{'endpoint_id': {'device_id': 'OLS', 'endpoint_uuid': 'eb287d83-f05e-53ec-ab5a-adf6bd2b5418'}, 'endpoint_type': 'optical'}
]},
'PE1': {'device_Id': 'PE1', 'device_type': 'emu-packet-router', 'device_endpoints': [
{'endpoint_id': {'device_id': 'PE1', 'endpoint_uuid': '1/2'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'PE1', 'endpoint_uuid': 'mgmt'}, 'endpoint_type': 'mgmt'},
{'endpoint_id': {'device_id': 'PE1', 'endpoint_uuid': '1/1'}, 'endpoint_type': 'copper/internal'}
]},
'DC2': {'device_Id': 'DC2', 'device_type': 'emu-datacenter', 'device_endpoints': [
{'endpoint_id': {'device_id': 'DC2', 'endpoint_uuid': 'eth1'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'DC2', 'endpoint_uuid': 'eth2'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'DC2', 'endpoint_uuid': 'int'}, 'endpoint_type': 'copper/internal'}
]},
'MW1-2': {'device_Id': 'MW1-2', 'device_type': 'emu-microwave-radio-system', 'device_endpoints': [
{'endpoint_id': {'device_id': 'MW1-2', 'endpoint_uuid': '172.18.0.1:1'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'MW1-2', 'endpoint_uuid': '172.18.0.2:1'}, 'endpoint_type': 'copper/internal'}
]},
'MW3-4': {'device_Id': 'MW3-4', 'device_type': 'emu-microwave-radio-system', 'device_endpoints': [
{'endpoint_id': {'device_id': 'MW3-4', 'endpoint_uuid': '172.18.0.3:1'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'MW3-4', 'endpoint_uuid': '172.18.0.4:1'}, 'endpoint_type': 'copper/internal'}
]},
'TFS': {'device_Id': 'TFS', 'device_type': 'teraflowsdn', 'device_endpoints': [
{'endpoint_id': {'device_id': 'TFS', 'endpoint_uuid': 'mgmt'}, 'endpoint_type': 'mgmt'}
]},
'R2': {'device_Id': 'R2', 'device_type': 'emu-packet-router', 'device_endpoints': [
{'endpoint_id': {'device_id': 'R2', 'endpoint_uuid': '1/2'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'R2', 'endpoint_uuid': '1/1'}, 'endpoint_type': 'copper/internal'}
]},
'DC1': {'device_Id': 'DC1', 'device_type': 'emu-datacenter', 'device_endpoints': [
{'endpoint_id': {'device_id': 'DC1', 'endpoint_uuid': 'int'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'DC1', 'endpoint_uuid': 'eth1'}, 'endpoint_type': 'copper/internal'},
{'endpoint_id': {'device_id': 'DC1', 'endpoint_uuid': 'eth2'}, 'endpoint_type': 'copper/internal'}
]},
}
device_data = {
'TFS' : {'manager_uuid': None, 'device_type': DeviceTypeEnum.TERAFLOWSDN_CONTROLLER },
'IPM' : {'manager_uuid': None, 'device_type': DeviceTypeEnum.XR_CONSTELLATION },
'OLS' : {'manager_uuid': None, 'device_type': DeviceTypeEnum.OPEN_LINE_SYSTEM },
'MW1-2' : {'manager_uuid': None, 'device_type': DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM },
'MW3-4' : {'manager_uuid': None, 'device_type': DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM },
MANAGED_DEVICES = {'PE1', 'PE2', 'PE3', 'PE4'}
MANAGER = 'TFS'
'DC1' : {'manager_uuid': None, 'device_type': DeviceTypeEnum.EMULATED_DATACENTER },
'DC2' : {'manager_uuid': None, 'device_type': DeviceTypeEnum.EMULATED_DATACENTER },
def process_device(json_device) -> Tuple[Dict, Device]:
device_uuid = json_device['device_Id']
'PE1' : {'manager_uuid': 'TFS', 'device_type': DeviceTypeEnum.PACKET_ROUTER },
'PE2' : {'manager_uuid': 'TFS', 'device_type': DeviceTypeEnum.PACKET_ROUTER },
'PE3' : {'manager_uuid': 'TFS', 'device_type': DeviceTypeEnum.PACKET_ROUTER },
'PE4' : {'manager_uuid': 'TFS', 'device_type': DeviceTypeEnum.PACKET_ROUTER },
grpc_device = Device()
grpc_device.device_id.device_uuid.uuid = device_uuid
grpc_device.device_type = json_device['device_type']
'HUB1' : {'manager_uuid': 'IPM', 'device_type': DeviceTypeEnum.PACKET_ROUTER },
'LEAF1' : {'manager_uuid': 'IPM', 'device_type': DeviceTypeEnum.PACKET_ROUTER },
'LEAF2' : {'manager_uuid': 'IPM', 'device_type': DeviceTypeEnum.PACKET_ROUTER },
if device_uuid in MANAGED_DEVICES:
config_rule = grpc_device.device_config.config_rules.add()
'splitter': {'manager_uuid': None, 'device_type': DeviceTypeEnum.EMULATED_OPTICAL_SPLITTER},
}
def process_device(device_uuid, json_device) -> Tuple[Dict, Device]:
grpc_device = Device()
grpc_device.device_id.device_uuid.uuid = device_uuid # pylint: disable=no-member
grpc_device.device_type = json_device['device_type'].value
manager_uuid = json_device.get('manager_uuid')
if manager_uuid is not None:
config_rule = grpc_device.device_config.config_rules.add() # pylint: disable=no-member
config_rule.action = ConfigActionEnum.CONFIGACTION_SET
config_rule.custom.resource_key = '_manager'
config_rule.custom.resource_value = json.dumps({'uuid': MANAGER})
config_rule.custom.resource_value = json.dumps({'uuid': manager_uuid})
return json_device, grpc_device
device_dict = {
device_uuid:process_device(json_device)
for device_uuid,json_device in device_dict.items()
device_uuid:process_device(device_uuid, json_device)
for device_uuid,json_device in device_data.items()
}
# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Convert the path defined as explicit hops with ingress and egress endpoints per device into a set of connections and
# compute the dependencies among them.
#
# Example:
# o-- int DC1 eth1 -- 10/1 CS1 1/2 -- 1/2 R2 2/1 -- a7.. OLS 60.. -- 2/1 R3 1/1 -- 1/1 CS2 10/1 -- eth1 DC2 int --o
# APP PKT PKT CTRL PKT PKT APP
#
# path_hops = [
# {'device': 'DC1-GW', 'ingress_ep': 'int', 'egress_ep': 'eth1'},
# {'device': 'CS1-GW1', 'ingress_ep': '10/1', 'egress_ep': '1/2'},
# {'device': 'TN-R2', 'ingress_ep': '1/2', 'egress_ep': '2/1'},
# {'device': 'TN-OLS', 'ingress_ep': 'a7a80b23a703', 'egress_ep': '60519106029e'},
# {'device': 'TN-R3', 'ingress_ep': '2/1', 'egress_ep': '1/1'},
# {'device': 'CS2-GW1', 'ingress_ep': '1/1', 'egress_ep': '10/1'},
# {'device': 'DC2-GW', 'ingress_ep': 'eth1', 'egress_ep': 'int'}
# ]
#
# connections=[
# (UUID('7548edf7-ee7c-4adf-ac0f-c7a0c0dfba8e'), ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE, [
# {'device': 'TN-OLS', 'ingress_ep': '833760219d0f', 'egress_ep': 'cf176771a4b9'}
# ], []),
# (UUID('c2e57966-5d82-4705-a5fe-44cf6487219e'), ServiceTypeEnum.SERVICETYPE_L2NM, [
# {'device': 'CS1-GW1', 'ingress_ep': '10/1', 'egress_ep': '1/2'},
# {'device': 'TN-R2', 'ingress_ep': '1/2', 'egress_ep': '2/1'},
# {'device': 'TN-R3', 'ingress_ep': '2/1', 'egress_ep': '1/1'},
# {'device': 'CS2-GW1', 'ingress_ep': '1/1', 'egress_ep': '10/1'}
# ], [UUID('7548edf7-ee7c-4adf-ac0f-c7a0c0dfba8e')]),
# (UUID('1e205c82-f6ea-4977-9e97-dc27ef1f4802'), ServiceTypeEnum.SERVICETYPE_L2NM, [
# {'device': 'DC1-GW', 'ingress_ep': 'int', 'egress_ep': 'eth1'},
# {'device': 'DC2-GW', 'ingress_ep': 'eth1', 'egress_ep': 'int'}
# ], [UUID('c2e57966-5d82-4705-a5fe-44cf6487219e')])
# ]
import enum, json, logging, queue, uuid
from typing import Dict, List, Optional, Tuple
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import Device, ServiceTypeEnum
from test_pathcomp.ResourceGroups import ResourceGroupKindEnum
from .ConstantsMappings import DEVICE_TYPE_TO_LAYER, DeviceLayerEnum
def convert_explicit_path_hops_to_connections(
path_hops : List[Dict], device_dict : Dict[str, Tuple[Dict, Device]],
main_service_uuid : str, main_service_type : ServiceTypeEnum
) -> List[Tuple[str, int, List[str], List[str]]]:
connection_stack = queue.LifoQueue()
connections : List[Tuple[str, int, List[str], List[str]]] = list()
prv_device_uuid = None
prv_resource_group : Optional[Tuple[ResourceGroupKindEnum, DeviceTypeEnum, str]] = None
for path_hop in path_hops:
device_uuid = path_hop['device']
if prv_device_uuid == device_uuid: continue
device_tuple = device_dict.get(device_uuid)
if device_tuple is None: raise Exception('Device({:s}) not found'.format(str(device_uuid)))
json_device,_ = device_tuple
device_type = json_device['device_type']
resource_group = DEVICE_TYPE_TO_LAYER.get(device_type)
if resource_group is None: raise Exception('Undefined Layer for DeviceType({:s})'.format(str(device_type)))
if prv_resource_group is None:
# path ingress
connection_stack.put((main_service_uuid, main_service_type, [path_hop], []))
elif prv_resource_group > resource_group:
# underlying connection begins
connection_uuid = str(uuid.uuid4())
connection_stack.put((connection_uuid, resource_group, [path_hop], []))
elif prv_resource_group == resource_group:
# same connection continues
connection_stack.queue[-1][2].append(path_hop)
elif prv_resource_group < resource_group:
# underlying connection ended
connection = connection_stack.get()
connections.append(connection)
connection_stack.queue[-1][3].append(connection[0])
connection_stack.queue[-1][2].append(path_hop)
else:
raise Exception('Uncontrolled condition')
prv_resource_group = resource_group
prv_device_uuid = device_uuid
# path egress
connections.append(connection_stack.get())
assert connection_stack.empty()
return connections
def convert_explicit_path_hops_to_plain_connection(
path_hops : List[Dict], main_service_uuid : str, main_service_type : ServiceTypeEnum
) -> List[Tuple[str, int, List[str], List[str]]]:
connection : Tuple[str, int, List[str], List[str]] = \
(main_service_uuid, main_service_type, [], [])
prv_device_uuid = None
for path_hop in path_hops:
device_uuid = path_hop['device']
if prv_device_uuid == device_uuid: continue
connection[2].append(path_hop)
prv_device_uuid = device_uuid
return [connection]
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