Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# 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'), <DeviceLayerEnum.OPTICAL_CONTROLLER: 1>, [
# {'device': 'TN-OLS', 'ingress_ep': '833760219d0f', 'egress_ep': 'cf176771a4b9'}
# ], []),
# (UUID('c2e57966-5d82-4705-a5fe-44cf6487219e'), <DeviceLayerEnum.PACKET_DEVICE: 30>, [
# {'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>, [
# {'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
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))
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_device_type = None
prv_manager_uuid = 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)))
_,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)
if action == StackActionEnum.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])
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.TERMINATE_CONNECTION:
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_device_uuid = device_uuid
prv_device_type = device_type
prv_manager_uuid = manager_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]