From 7b5d6eeb7dc2175888eb94d4c5b274920c33f6a0 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Mon, 21 Feb 2022 16:02:18 +0100 Subject: [PATCH 01/16] Create a script to generate a Topology - add init viewer class Issue-ID: OAM-249 Change-Id: I5802a0b49832bffafd436dd8529066fa7d28cfdf Signed-off-by: demx8as6 --- .../view/network_viewer.py | 96 ++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 code/network-topology-instance-generator/view/network_viewer.py diff --git a/code/network-topology-instance-generator/view/network_viewer.py b/code/network-topology-instance-generator/view/network_viewer.py new file mode 100644 index 0000000..dc6037a --- /dev/null +++ b/code/network-topology-instance-generator/view/network_viewer.py @@ -0,0 +1,96 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Provides functions to convert the Network into different formats +""" + +import encodings +import json +from lxml import etree +from model.python.tapi_common_context import TapiCommonContext + + +class NetworkViewer: + """ + This class contains all functions converting the Network into different formats + """ + __network: TapiCommonContext = None + + # constructor + def __init__(self, network: TapiCommonContext): + self.__network = network + + # json format + + def json(self) -> 'NetworkViewer': + """ + Getter returns the class as json object + :return The class itsself, as it is json serializable + """ + return self + + def show_as_json(self) -> dict: + """ + Method printing the class in json format. + """ + print(self.__network.json()) + + def show(self): + """ + Method printing the network + """ + print(self.__network) + + def save(self, filename: str): + """ + Method saving the class content to a file in json format. + :param filename: A valid path to a file on the system. + :type filename: string + """ + with open(filename, "w", encoding='utf-8') as json_file: + output = self.__network.json() + json.dump(output, json_file, + ensure_ascii=False, indent=2) + for key in ["Node", "Link"]: + print(key + "s:", len(output + ["tapi-common:context"] + ["tapi-topology:topology-context"] + ["topology"][0][key.lower()]) + ) + print("File '" + filename + "' saved!") + + def svg(self, filename: str): + """ + Method saving the class content to a file in xml/svg format. + + :param filename: A valid path to a file on the system. + :type filename: string + """ + root = self.__network.svg(0, 0) + root.addprevious( + etree.ProcessingInstruction("xml-stylesheet", + 'href="svg.style.css" type="text/css"') + ) + etree.ElementTree(root).write(filename, + encoding="utf-8", + xml_declaration=True, + doctype=( + '' + ), + pretty_print=True + ) + print("File '" + filename + "' saved!") -- 2.16.6 From ee1b01c924e9652dfec3ed1bd6d43f0e9e55f776 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Mon, 21 Feb 2022 16:27:18 +0100 Subject: [PATCH 02/16] Create a script to generate a Topology - add tapi common context generation IssueID: OAM-249 Change-Id: I3653d04a74b4b29ab30de53ff8386fc0862980ef Signed-off-by: demx8as6 --- .../model/python/tapi_common_context.py | 127 +++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_common_context.py diff --git a/code/network-topology-instance-generator/model/python/tapi_common_context.py b/code/network-topology-instance-generator/model/python/tapi_common_context.py new file mode 100644 index 0000000..7c96391 --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_common_context.py @@ -0,0 +1,127 @@ +#!/usr/bin/python + +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module for a class representing a TAPI Common Context +""" +from typing import Dict, Union +import uuid +from xml.dom.minidom import Element +from lxml import etree +from model.python.tapi_topology_context import TapiTopologyContext +from model.python.top import Top + + +class TapiCommonContext(Top): + """ + Class representing a TAPI Common Context object. + """ + + __configuration: dict = {} + __context: TapiTopologyContext = None + __data: dict = { + "tapi-common:context": { + "uuid": str(uuid.uuid4()), + "name": [{"value-name": "context-name", + "value": "Generated Topology"}]}} + + # constructor + def __init__(self, configuration: Dict[str, Union[str, Dict[str, int]]]): + super().__init__(configuration) + self.__configuration = configuration + self.__context = TapiTopologyContext(configuration) + + # getter + def configuration(self) -> Dict[str, Dict]: + """ + Getter for a json object representing the TAPI Common Context. + :return TAPI Common Context as json object. + """ + return self.__configuration + + def data(self) -> Dict: + """ + Getter for a json object representing the TAPI Common Context. + :return TAPI Common Context as json object. + """ + return self.__data + + def json(self) -> Dict: + """ + Getter for a json object representing the TAPI Topology Context. + :return TAPI Common Context as json object. + """ + result = self.data().copy() + if self.__context is not None: + result["tapi-common:context"].update(self.__context.json()) + return result + + def identifier(self) -> str: + """ + Getter returning the TAPI common context identifier. + :return Object identifier as string + """ + return self.__data["tapi-common:context"]["uuid"] + + def name(self) -> str: + """ + Getter for object name. + :return Human readable string as name. + """ + return self.data()["tapi-common:context"]["name"][0]["value"] + + def __svg_width(self) -> int: + p = self.configuration()['network']['pattern'] + return (p['smo'] * p['near-rt-ric'] * p['o-cu'] * p['o-du'] * p['fronthaul-gateway'] * p['o-ru'] * p['user-equipment'] + 1) * 2*2*self.FONTSIZE + + def __svg_height(self) -> int: + return (8 * 11 + 6) * self.FONTSIZE + + def svg(self, x, y) -> etree.Element: + """ + Getter for a xml/svg Element object representing the TAPI Topology Context. + :return TAPI Common Context as SVG object. + """ + root: Element = etree.Element( + "svg", + width=str(self.__svg_width()), + height=str(self.__svg_height()), + viewBox=" ".join([ + str(-3*self.FONTSIZE), + str(-3*self.FONTSIZE), + str(self.__svg_width()), + str(self.__svg_height())] + ), + xmlns="http://www.w3.org/2000/svg" + ) + desc=etree.Element("desc") + desc.text="\n context: " + self.identifier() + "\n name: " + self.name() + root.append(desc) + + title=etree.Element("title") + title.text=self.configuration()["network"]["name"] + root.append(title) + + root.append(self.__context.svg(x, y)) + return root + + def topology_context(self) -> TapiTopologyContext: + """ + Getter for next level object (TapiTopologyContext). + :return TAPI Topology Context + """ + return self.__context -- 2.16.6 From 7ab6befba0e51bd0c4f0ac0045f967ad11353b9c Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:40:02 +0100 Subject: [PATCH 03/16] Create a script to generate a Topology - add tapi topology context generation Issue-ID: OAM-249 Change-Id: Ia63d7d655640901a06a2fba080788b7379f4e227 Signed-off-by: demx8as6 --- .../model/python/tapi_topology_context.py | 94 ++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_topology_context.py diff --git a/code/network-topology-instance-generator/model/python/tapi_topology_context.py b/code/network-topology-instance-generator/model/python/tapi_topology_context.py new file mode 100644 index 0000000..bf04dce --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_topology_context.py @@ -0,0 +1,94 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module for the TAPI Topology Context +""" +from typing import Dict, List, Union +from lxml import etree +from model.python.tapi_topology import TapiTopology +from model.python.top import Top + + +class TapiTopologyContext(Top): + """ + Class providing a TAPI Topology Context object + """ + + __data: Dict[str, Dict[str, List]] = { + "tapi-topology:topology-context": { + "topology": []}} + __tapi_topology: List[TapiTopology] = [] + + # constructor + def __init__(self, configuration: Dict[str, Union[str, Dict[str, int]]]): + super().__init__(configuration) + topology = TapiTopology(configuration) + self.__tapi_topology.append(topology) + + # getter + def configuration(self) -> dict: + """ + Getter for a json object representing the TAPI Topology Context initail + configuration. + :return TAPI Topology Context configuration as json object. + """ + return self.__configuration + + def data(self) -> dict: + """ + Getter for a json object representing the TAPI Topology Context. + :return TAPI Topology Context as json object. + """ + return self.__data + + def name(self) -> str: + """ + Getter returning the container name. + :return Static string + """ + return "tapi-topology:topology-context" + + def identifier(self) -> str: + """ + Getter returning the container name which acts as identifier + :return Static string + """ + return self.name() + + def json(self) -> dict: + """ + Getter for a json object representing the TAPI Topology Context. + :return TAPI Topology Context as json object. + """ + result = self.__data.copy() + for topology in self.__tapi_topology: + result["tapi-topology:topology-context"]["topology"].append( + topology.json()) + return result + + def svg(self, x, y) -> etree.Element: + """ + Getter for a xml Element object representing the TAPI Topology Context. + :return TAPI Topology Context as svg object. + """ + group = etree.Element("g") + title = etree.Element("title") + title.text = "\n context: " + self.identifier() + "\n name: " + self.name() + group.append(title) + + for topology in self.__tapi_topology: + group.append(topology.svg(x, y)) + return group -- 2.16.6 From c3b5ba6a8b36c41d550b9b0faf3e1bc316b34a21 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:41:35 +0100 Subject: [PATCH 04/16] Create a script to generate a Topology - add tapi topology generation Issue-ID: OAM-249 Change-Id: Ic2d34b2951be07780e1c318ff751ec8c78c95cfe Signed-off-by: demx8as6 --- .../model/python/tapi_topology.py | 702 +++++++++++++++++++++ 1 file changed, 702 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_topology.py diff --git a/code/network-topology-instance-generator/model/python/tapi_topology.py b/code/network-topology-instance-generator/model/python/tapi_topology.py new file mode 100644 index 0000000..803dd1b --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_topology.py @@ -0,0 +1,702 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing the main class for this project for a TAPI Topology. +""" +import uuid +from typing import Dict, List, Union +from lxml import etree + +from model.python.top import Top +from model.python.tapi_node import TapiNode +from model.python.tapi_node_smo import TapiNodeSmo +from model.python.tapi_node_o_cloud import TapiNodeOCloud +from model.python.tapi_node_near_rt_ric import TapiNodeNearRtRic +from model.python.tapi_node_o_cu_cp import TapiNodeOCuCp +from model.python.tapi_node_o_cu_up import TapiNodeOCuUp +from model.python.tapi_node_o_du import TapiNodeODu +from model.python.tapi_node_fronthaul_gateway import TapiNodeFronthaulGateway +from model.python.tapi_node_o_ru import TapiNodeORu +from model.python.tapi_node_user_equipment import TapiNodeUserEquipment +from model.python.tapi_link import TapiLink + + +class TapiTopology(Top): + """ + Class representing a TAPI Topology + """ + + __data: Dict[str, Union[str, List[Union[Dict, TapiNode, TapiLink]]]] = None + __configuration: dict = None + + # constructor + def __init__(self, configuration: dict): + super().__init__(configuration) + self.__configuration = configuration + self.__data = { + "uuid": str(uuid.uuid4()), + "name": [{ + "value-name": "network-name", + "value": configuration['network']['name']}], + "layer-protocol-name": ["ETH"], + "node": [], + "link": []} + + topology_structure: dict = configuration['network']['pattern'] + network_function_type: str = next(iter(topology_structure)) + count: int = configuration['network']['pattern'][network_function_type] + + if network_function_type == "smo": + self.__create_smos(None, topology_structure, count) + elif network_function_type == "near-rt-ric": + self.__create_near_rt_rics(None, topology_structure, count) + elif network_function_type == "o-cu": + self.__create_o_cus(None, topology_structure, count) + elif network_function_type == "o-du": + self.__create_o_dus(None, topology_structure, count) + elif network_function_type == "o-ru": + self.__create_o_rus(None, topology_structure, count) + elif network_function_type == "ue": + self.__create_ues(None, topology_structure, count) + else: + print("Unknown network function type", network_function_type) + + # getter + def configuration(self) -> dict: + """ + Getter for a json object representing the TAPI Topology configuration. + :return TAPI Topology configuration as json object. + """ + return self.__configuration + + def data(self) -> dict: + """ + Getter for a json object representing the TAPI Topology. + :return TAPI Topology as json object. + """ + return self.__data + + def identifier(self) -> str: + """ + Getter returning the TAPI Topology identifier. + :return Object identifier as UUID. + """ + return self.__data["uuid"] + + def name(self) -> str: + """ + Getter for TAPI Topology name. The TAPI topology is a representation of + the network. Therefore, the TAPI Topology name has the same value as the + Network name. + :return TAPI Topology name as string. + """ + return self.__configuration['network']['name'] + + def json(self) -> dict: + """ + Getter for a json object representing the TAPI Topology. + :return TAPI Topology Context as json object. + """ + result = self.data().copy() + + # nodes handling + result["node"] = [] + for node in self.__data["node"]: + result["node"].append(node.json()) + + # link handling + result["link"] = [] + for link in self.__data["link"]: + result["link"].append(link.json()) + + return result + + def svg(self, svg_x: int, svg_y: int) -> etree.Element: + """ + Getter for a xml Element object representing the TAPI Topology Context. + :return TAPI Topology Context as svg object. + """ + group = etree.Element("g") + title = etree.Element("title") + title.text = "\n TAPI Topology \n id: " + \ + self.identifier() # + "\n name: " + self.name() + group.append(title) + + # nodes handling + index_per_type: Dict = {} + svg_nodes = [] + for node in self.__data["node"]: + if type(node) in index_per_type: + index_per_type[type(node)] = index_per_type[type(node)] + 1 + else: + index_per_type[type(node)] = 0 + index = index_per_type[type(node)] + node_x = svg_x + \ + index*self.__svg_dynamic_x_offset_by_node_type(type(node)) + \ + self.__svg_static_x_offset_by_node_type(type(node)) + node_y = svg_y + self.__svg_y_offset_by_node_type(type(node)) + svg_nodes.append(node.svg(node_x, node_y)) + # group.append(node.svg(node_x, node_y)) + + # handling and drawing links + for link in self.__data["link"]: + group.append(link.svg(0, 0)) + + # drawing nodes + for svg_node in svg_nodes: + group.append(svg_node) + + return group + + def __svg_static_x_offset_by_node_type(self, node_type) -> int: + """ + Mapping function from node types to y position in svg + return: int value + """ + pattern = self.configuration()['network']['pattern'] + padding = 0 # self.FONTSIZE + width_unit = (2 * 2 * self.FONTSIZE + padding) + + ru = (pattern['user-equipment']-1) * width_unit / 2 + fhgw = (pattern['o-ru'] * + pattern['user-equipment'] - 1) * width_unit / 2 + odu = (pattern['fronthaul-gateway'] * pattern['o-ru'] * pattern['user-equipment'] + - 1) * width_unit/2 + ocu = (pattern['o-du'] * pattern['fronthaul-gateway'] * pattern['o-ru'] * pattern['user-equipment'] + - 1) * width_unit / 2 + ric = (pattern['near-rt-ric'] * pattern['o-du'] * pattern['fronthaul-gateway'] * pattern['o-ru'] * pattern['user-equipment'] + - 1) * width_unit / 2 + smo = (pattern['smo'] * pattern['near-rt-ric'] * pattern['o-du'] * pattern['fronthaul-gateway'] * pattern['o-ru'] * pattern['user-equipment'] + -0.5) * width_unit + + x_mapping: Dict[type, int] = { + TapiNodeSmo: smo, + TapiNodeOCloud: ric, + TapiNodeNearRtRic: ric, + TapiNodeOCuCp: ocu - 12.5*self.FONTSIZE, + TapiNodeOCuUp: ocu + 12.5*self.FONTSIZE, + TapiNodeODu: odu, + TapiNodeFronthaulGateway: fhgw, + TapiNodeORu: ru, + TapiNodeUserEquipment: 0 + } + if node_type in x_mapping: + return x_mapping[node_type] + return 0 + + def __svg_dynamic_x_offset_by_node_type(self, node_type) -> int: + """ + Mapping function from node types to y position in svg + return: int value + """ + padding = 0 + pattern = self.configuration()['network']['pattern'] + width_unit = (2 * 2 * self.FONTSIZE + padding) + x_mapping: Dict[type, int] = { + TapiNodeSmo: pattern['near-rt-ric'] * pattern['o-cu'] * pattern['o-du'] * pattern['fronthaul-gateway'] * pattern['o-ru'] * pattern['user-equipment'], + TapiNodeOCloud: pattern['o-cu'] * pattern['o-du'] * pattern['fronthaul-gateway'] * pattern['o-ru'] * pattern['user-equipment'], + TapiNodeNearRtRic: pattern['o-cu'] * pattern['o-du'] * pattern['fronthaul-gateway'] * pattern['o-ru'] * pattern['user-equipment'], + TapiNodeOCuCp: pattern['o-du'] * pattern['fronthaul-gateway'] * pattern['o-ru'] * pattern['user-equipment'], + TapiNodeOCuUp: pattern['o-du'] * pattern['fronthaul-gateway'] * pattern['o-ru'] * pattern['user-equipment'], + TapiNodeODu: pattern['fronthaul-gateway'] * pattern['o-ru'] * pattern['user-equipment'], + TapiNodeFronthaulGateway: pattern['o-ru'] * pattern['user-equipment'], + TapiNodeORu: pattern['user-equipment'], + TapiNodeUserEquipment: 1 + } + if node_type in x_mapping: + return x_mapping[node_type] * width_unit + return 0 + + def __svg_y_offset_by_node_type(self, node_type) -> int: + """ + Mapping function from node types to y position in svg + return: int value + """ + offset = 11*self.FONTSIZE + y_mapping: Dict[type, int] = { + TapiNodeSmo: 0 * offset, + TapiNodeOCloud: 1 * offset, + TapiNodeNearRtRic: 2 * offset, + TapiNodeOCuCp: 3.5 * offset - 4 * self.FONTSIZE, + TapiNodeOCuUp: 3.5 * offset + 4 * self.FONTSIZE, + TapiNodeODu: 5 * offset, + TapiNodeFronthaulGateway: 6 * offset, + TapiNodeORu: 7 * offset, + TapiNodeUserEquipment: 8 * offset + } + if node_type in y_mapping: + return y_mapping[node_type] + return 0 + + # methods + def add_node(self, node: TapiNode): + """ + Method adding a TAPI node to TAPI Topology. + :return TAPI Topology object. + """ + self.__data["node"].append(node) + return self + + def add_link(self, link: TapiLink): + """ + Method adding a TAPI node to TAPI Topology. + :return TAPI Topology object. + """ + self.__data["link"].append(link) + return self + + def __create_smos(self, parent: TapiNode, topology_structure: dict, count: int): + """ + Method adding a TAPI node to TAPI Topology. + :param parent: A TAPI node which acts a a parent node in the topology. + :param topology_structure: Information about the next topology levels. + :param count: Number of instance to be created + :return TAPI Topology object. + """ + current_type = "smo" + next_type = "near-rt-ric" + for local_id in range(count): + prefix = "" + + if parent is not None: + prefix = parent.data()["name"][1]["value"] + config = {"node": {"localId": prefix + str(local_id), + "type": current_type, + "function": "o-ran-sc-topology-common:"+current_type}} + node = TapiNodeSmo(parent, config) + self.add_node(node) + + # add O-Clouds + if "o-cloud" in topology_structure: + structure = topology_structure.copy() + self.__create_o_clouds( + node, structure, structure["o-cloud"]) + + if next_type in topology_structure: + structure = topology_structure.copy() + if current_type in structure: + del structure["o-cloud"] + if current_type in structure: + del structure[current_type] + self.__create_near_rt_rics( + node, structure, structure[next_type]) + + return self + + def __create_o_clouds(self, parent: TapiNode, topology_structure: dict, count: int): + """ + Method adding a TAPI node to TAPI Topology. + :param parent: A TAPI node which acts a a parent node in the topology. + :param topology_structure: Information about the next topology levels. + :param count: Number of instance to be created + :return TAPI Topology object. + """ + current_type = "o-cloud" + for local_id in range(count): + # add node + prefix = "" + if parent is not None: + prefix = parent.json()["name"][1]["value"] + function = "o-ran-sc-topology-common:"+current_type + node_configuration = {"node": {"localId": prefix + str(local_id), + "type": current_type, + "function": function}} + node = TapiNodeOCloud(parent, node_configuration) + self.add_node(node) + + # add links + # O2 + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "o2-rest", + "provider": node, + "consumer": parent + } + self.add_link(TapiLink(link_configuration)) + return self + + def __create_near_rt_rics(self, parent: TapiNode, topology_structure: dict, count: int): + """ + Method adding a TAPI node to TAPI Topology. + :param parent: A TAPI node which acts a a parent node in the topology. + :param topology_structure: Information about the next topology levels. + :param count: Number of instance to be created + :return TAPI Topology object. + """ + current_type = "near-rt-ric" + next_type = "o-cu" + for local_id in range(count): + # add node + prefix = "" + if parent is not None: + prefix = parent.json()["name"][1]["value"] + function = "o-ran-sc-topology-common:"+current_type + node_configuration = {"node": {"localId": prefix + str(local_id), + "type": current_type, + "function": function}} + node = TapiNodeNearRtRic(parent, node_configuration) + self.add_node(node) + + # add links + # A1 + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "a1-rest", + "provider": node, + "consumer": parent + } + self.add_link(TapiLink(link_configuration)) + + # O1 NETCONF + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "o1-netconf", + "provider": node, + "consumer": parent + } + self.add_link(TapiLink(link_configuration)) + + # O1 FILE + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "o1-file", + "provider": node, + "consumer": parent + } + self.add_link(TapiLink(link_configuration)) + + # O1 VES + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "o1-ves", + "provider": parent, + "consumer": node + } + self.add_link(TapiLink(link_configuration)) + + # continue + if next_type in topology_structure: + structure = topology_structure.copy() + if current_type in structure: + del structure[current_type] + self.__create_o_cus(node, structure, structure[next_type]) + + return self + + def __function_identity(self, function_type: str, plane: str) -> str: + """ + Method to calculate the Function IDENTITY + """ + return "".join([ + "o-ran-sc-topology-common:", + function_type, + "-", + plane + ]) + + def __create_o_cus(self, parent: TapiNode, topology_structure: dict, count: int): + """ + Method adding a TAPI node to TAPI Topology. + :param parent: A TAPI node which acts a a parent node in the topology. + :param topology_structure: Information about the next topology levels. + :param count: Number of instance to be created + :return TAPI Topology object. + """ + current_type = "o-cu" + next_type = "o-du" + for local_id in range(count): + prefix = "" + if parent is not None: + prefix = parent.data()["name"][1]["value"] + + node: Dict[str, Union[TapiNodeOCuCp, TapiNodeOCuUp]] = {} + for plane in ["cp", "up"]: + config = {"node": {"localId": prefix + str(local_id), + "type": "-".join([current_type, plane]), + "function": self.__function_identity(current_type, plane)}} + classes: Dict[str, Union[TapiNodeOCuCp, TapiNodeOCuUp]] = { + "cp": TapiNodeOCuCp, + "up": TapiNodeOCuUp} + node[plane] = classes[plane](parent, config) + self.add_node(node[plane]) + + # add links + # E2 + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "e2-rest", + "provider": node[plane], + "consumer": parent + } + self.add_link(TapiLink(link_configuration)) + + # O1 NETCONF + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "o1-netconf", + "provider": node[plane], + "consumer": parent.parent() + } + self.add_link(TapiLink(link_configuration)) + + # O1 FILE + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "o1-file", + "provider": node[plane], + "consumer": parent.parent() + } + self.add_link(TapiLink(link_configuration)) + + # O1 VES + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "o1-ves", + "provider": parent.parent(), + "consumer": node[plane] + } + self.add_link(TapiLink(link_configuration)) + + # continue + # E1 Interface between O-CU-UP and O-CU-CP + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "e1-unknown", + "provider": node["up"], + "consumer": node["cp"] + } + self.add_link(TapiLink(link_configuration)) + + if next_type in topology_structure: + structure = topology_structure.copy() + if current_type in structure: + del structure[current_type] + self.__create_o_dus( + node, structure, structure[next_type]) + return self + + def __create_o_dus(self, parents: Dict[str, TapiNode], topology_structure: dict, count: int): + """ + Method adding a TAPI node to TAPI Topology. + :param parent: A TAPI node which acts a a parent node in the topology. + :param topology_structure: Information about the next topology levels. + :param count: Number of instance to be created + :return TAPI Topology object. + """ + current_type = "o-du" + next_type = "fronthaul-gateway" + for local_id in range(count): + prefix = "000" + if parents["cp"] is not None: + prefix = parents["cp"].data()["name"][1]["value"] + config = {"node": {"localId": prefix + str(local_id), + "type": current_type, + "function": "o-ran-sc-topology-common:"+current_type}} + node = TapiNodeODu(parents["cp"], config) + self.add_node(node) + + for plane, parent in parents.items(): + + # add links + # E2 + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "e2-rest", + "provider": node, + "consumer": parent.parent() + } + self.add_link(TapiLink(link_configuration)) + + # O1 NETCONF + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "o1-netconf", + "provider": node, + "consumer": parent.parent().parent() + } + self.add_link(TapiLink(link_configuration)) + + # O1 FILE + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "o1-file", + "provider": node, + "consumer": parent.parent().parent() + } + self.add_link(TapiLink(link_configuration)) + + # O1 VES + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "o1-ves", + "provider": parent.parent().parent(), + "consumer": node + } + self.add_link(TapiLink(link_configuration)) + + # F1 User Plane or Control Plane + interfaces: Dict[str, str] = {"cp": "f1-c", "up": "f1-u"} + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": interfaces[plane]+"-unknown", + "provider": node, + "consumer": parent + } + self.add_link(TapiLink(link_configuration)) + + # continue + if next_type in topology_structure: + structure = topology_structure.copy() + if current_type in structure: + del structure[current_type] + self.__create_fronthaul_gateways( + node, structure, structure[next_type]) + return self + + def __create_fronthaul_gateways(self, parent: TapiNode, topology_structure: dict, count: int): + """ + Method adding a TAPI node to TAPI Topology. + :param parent: A TAPI node which acts a a parent node in the topology. + :param topology_structure: Information about the next topology levels. + :param count: Number of instance to be created + :return TAPI Topology object. + """ + current_type = "fronthaul-gateway" + next_type = "o-ru" + for local_id in range(count): + prefix = "" + if parent is not None: + prefix = parent.data()["name"][1]["value"] + node_configuration = { + "node": { + "localId": prefix + str(local_id), + "type": current_type, + "function": "o-ran-sc-topology-common:"+current_type, + "southbound-nep-count": topology_structure[next_type] + } + } + node = TapiNodeFronthaulGateway(parent, node_configuration) + self.add_node(node) + + # add links + + # Eth NBI + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "oam-netconf", + "provider": node, + "consumer": parent.parent().parent().parent() + } + self.add_link(TapiLink(link_configuration)) + + # Eth SBI + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "eth-ofh", + "provider": node, + "consumer": parent + } + self.add_link(TapiLink(link_configuration)) + + # continue + if next_type in topology_structure: + structure = topology_structure.copy() + if current_type in structure: + del structure[current_type] + self.__create_o_rus(node, structure, structure[next_type]) + return self + + def __create_o_rus(self, parent: TapiNode, topology_structure: dict, count: int): + """ + Method adding a TAPI node to TAPI Topology. + :param parent: A TAPI node which acts a a parent node in the topology. + :param topology_structure: Information about the next topology levels. + :param count: Number of instance to be created + :return TAPI Topology object. + """ + current_type = "o-ru" + next_type = "user-equipment" + for local_id in range(count): + prefix = "" + if parent is not None: + prefix = parent.data()["name"][1]["value"] + config = {"node": {"localId": prefix + str(local_id), + "type": current_type, + "function": "o-ran-sc-topology-common:"+current_type}} + node = TapiNodeORu(parent, config) + self.add_node(node) + + # add links + + # O1 NETCONF + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "ofh-netconf", + "provider": node, + "consumer": parent.parent().parent().parent().parent() + } + self.add_link(TapiLink(link_configuration)) + + # OFH M-Plane to O-DU via fronthaul-gateway + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "ofh-netconf", + "provider": node, + "consumer": parent + } + self.add_link(TapiLink(link_configuration)) + + # continue + if next_type in topology_structure: + structure = topology_structure.copy() + if current_type in structure: + del structure[current_type] + self.__create_ues(node, structure, structure[next_type]) + return self + + def __create_ues(self, parent: TapiNode, topology_structure: dict, count: int): + """ + Method adding a TAPI node to TAPI Topology. + :param parent: A TAPI node which acts a a parent node in the topology. + :param topology_structure: Information about the next topology levels. + :param count: Number of instance to be created + :return TAPI Topology object. + """ + current_type = "user-equipment" + for local_id in range(count): + prefix = "" + if parent is not None: + prefix = parent.data()["name"][1]["value"] + config = {"node": {"localId": prefix + str(local_id), + "type": current_type, + "function": "o-ran-sc-topology-common:"+current_type}} + node = TapiNodeUserEquipment(parent, config) + self.add_node(node) + + # add links + # Uu unknown + link_configuration = { + "topology_reference": self.data()["uuid"], + "name_prefix": "uu-unknown", + "provider": parent, + "consumer": node + } + self.add_link(TapiLink(link_configuration)) + + if "key" in topology_structure: + print("Implement missing topology level.") + + return self -- 2.16.6 From d7a950fc14c5dd9e27336051fb0ac9b61f83397b Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:42:31 +0100 Subject: [PATCH 05/16] Create a script to generate a Topology - add (abstract) tapi node generation Issue-ID: OAM-249 Change-Id: Ic67de8b49c3e82f221d610078863f4a1d15d2194 Signed-off-by: demx8as6 --- .../model/python/tapi_node.py | 341 +++++++++++++++++++++ 1 file changed, 341 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_node.py diff --git a/code/network-topology-instance-generator/model/python/tapi_node.py b/code/network-topology-instance-generator/model/python/tapi_node.py new file mode 100644 index 0000000..20da86d --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_node.py @@ -0,0 +1,341 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing the class for a TAPI Node. +""" +import uuid +from typing import Dict +from lxml import etree +from model.python.svg.near_tr_ric import NearRtRic +from model.python.svg.o_cloud import OCloud +from model.python.svg.o_cu_cp import OCuCp +from model.python.svg.o_cu_up import OCuUp +from model.python.svg.o_du import ODu +from model.python.svg.fronthaul_gateway import FronthaulGateway +from model.python.svg.node import Node +from model.python.tapi_node_edge_point import TapiNodeEdgePoint +from model.python.top import Top + + +class TapiNode(Top): + """ + Class representing a TAPI Node. + """ + + __data: dict = {} + __configuration: dict = {} + __parent: 'TapiNode' = None + __width: int = 0 # default SVG width, should be overritten by constructor + + # constructor + def __init__(self, parent: 'TapiNode', configuration: dict): + super().__init__(configuration) + self.__parent = parent + self.__configuration = configuration + self.width((4 + 1) * (2.2*self.FONTSIZE)) # 4x nep + self.__data = { + "uuid": str(uuid.uuid4()), + "name": [ + { + "value-name": "topology-node-name", + "value": self.name() + }, + { + "value-name": "topology-node-local-id", + "value": configuration['node']['localId'] + } + ], + "owned-node-edge-point": [], + "administrative-state": "LOCKED", + "operational-state": "ENABLED", + "lifecycle-state": "INSTALLED", + "layer-protocol-name": ["ETH"], + "cost-characteristic": [ + { + "cost-name": "cost", + "cost-algorithm": "alg1", + "cost-value": "value-1" + } + ], + "latency-characteristic": [{ + "traffic-property-name": "property-1", + "queing-latency-characteristic": "queue-1", + "fixed-latency-characteristic": "latency-1", + "jitter-characteristic": "jitter-1", + "wander-characteristic": "wander-1" + }], + "o-ran-sc-topology:function": configuration['node']['function'], + "o-ran-sc-topology:geolocation": { + "longitude": "0", + "latitude": "0", + "altitude": "20000" + } + } + + # getter + def x_offset_by_cep_name(self, name: str, local_id: int) -> int: + cep_of_interest = len(self.data()['owned-node-edge-point'])-2 + mapping: Dict[str, int] = { + "o2-rest-consumer": -4*6*self.FONTSIZE, + "a1-rest-consumer": -2*6*self.FONTSIZE, + "oam-netconf-consumer": -0*6*self.FONTSIZE, + "o1-ves-provider": 2*6*self.FONTSIZE, + "o1-file-consumer": 4*6*self.FONTSIZE, + + "o2-rest-provider": 0*self.FONTSIZE, + "a1-rest-provider": -8*self.FONTSIZE, + "e2-rest-consumer": 0*self.FONTSIZE, + + "f1-c-unknown-consumer": 0*self.FONTSIZE, + "f1-u-unknown-consumer": 0*self.FONTSIZE, + + "e1-unknown-provider": -5*2*self.FONTSIZE, + "e1-unknown-consumer": 5*2*self.FONTSIZE, + + "e2-rest-provider": -4*2*self.FONTSIZE, + "f1-c-unknown-provider": -2*2*self.FONTSIZE, + "f1-u-unknown-provider": 2*2*self.FONTSIZE, + "f1-unknown-provider": -2*2*self.FONTSIZE, + "o1-netconf-provider": 4*self.FONTSIZE, + "o1-ves-consumer": 8*self.FONTSIZE, + "o1-file-provider": 12*self.FONTSIZE, + "ofh-netconf-consumer": -2*self.FONTSIZE, + + "eth-ofh-provider": -2*self.FONTSIZE, + "oam-netconf-provider": 2*self.FONTSIZE, + # "eth-ofh-consumer": -(len(self.data()['owned-node-edg + # e-point']) - 2)/2 * 2 * self.FONTSIZE, + "eth-ofh-consumer": 0-(cep_of_interest/2)*4*self.FONTSIZE + 2*self.FONTSIZE, + + "ofh-netconf-provider": 0*self.FONTSIZE, + "uu-unknown-provider": 0*self.FONTSIZE, + + "uu-unknown-consumer": 0*self.FONTSIZE + } + if name in mapping: + return mapping[name] + 4*self.FONTSIZE * local_id + + print("Node: CEP name", name, "for x postion calculation not found") + return 0 + + def y_offset_by_cep_name(self, name: str) -> int: + mapping: Dict[str, int] = { + "o2-rest-consumer": 3*self.FONTSIZE, + "a1-rest-consumer": 3*self.FONTSIZE, + "oam-netconf-consumer": 3*self.FONTSIZE, + "o1-ves-provider": 3*self.FONTSIZE, + "o1-file-consumer": 3*self.FONTSIZE, + + "o2-rest-provider": -3*self.FONTSIZE, + "a1-rest-provider": -3*self.FONTSIZE, + "e2-rest-consumer": 3*self.FONTSIZE, + + "e1-unknown-provider": 1*self.FONTSIZE, + "e1-unknown-consumer": 1*self.FONTSIZE, + + "f1-c-unknown-consumer": 3*self.FONTSIZE, + "f1-u-unknown-consumer": 3*self.FONTSIZE, + "f1-unknown-consumer": 3*self.FONTSIZE, + + "e2-rest-provider": -3*self.FONTSIZE, + "f1-c-unknown-provider": -3*self.FONTSIZE, + "f1-u-unknown-provider": -3*self.FONTSIZE, + "f1-unknown-provider": -3*self.FONTSIZE, + "o1-netconf-provider": -3*self.FONTSIZE, + "o1-ves-consumer": -3*self.FONTSIZE, + "o1-file-provider": -3*self.FONTSIZE, + "ofh-netconf-consumer": 3*self.FONTSIZE, + + "eth-ofh-provider": -3*self.FONTSIZE, + "oam-netconf-provider": -3*self.FONTSIZE, + "eth-ofh-consumer": +3*self.FONTSIZE, + + "ofh-netconf-provider": -3*self.FONTSIZE, + "uu-unknown-provider": 3*self.FONTSIZE, + + "uu-unknown-consumer": -3*self.FONTSIZE + } + if name in mapping: + return mapping[name] + + print("Node: CEP name", name, "for y postion calculation not found") + return 0 + + def configuration(self) -> dict: + """ + Getter for a json object representing the TAPI Node configuration. + :return TAPI Node configuration as json object. + """ + return self.__configuration + + def data(self) -> dict: + """ + Getter for a json object representing the TAPI Link. + :return TAPI Link as json object. + """ + return self.__data + + def local_id(self) -> int: + return self.configuration()["node"]["localId"] + + def function(self) -> str: + """ + Getter returning the network-function type + :return The type of the network-function as yang IDENTITY. + """ + return self.__configuration['node']['function'] + + def function_label(self) -> str: + """ + Getter returning the network-function label + :return The type of the network-function as human readable string. + """ + mapping = { + "o-ran-sc-topology-common:smo": "SMO", + "o-ran-sc-topology-common:o-cloud": "O-Cloud", + "o-ran-sc-topology-common:near-rt-ric": "Near-RT-RIC", + "o-ran-sc-topology-common:o-cu": "O-CU", + "o-ran-sc-topology-common:o-cu-cp": "O-CU-CP", + "o-ran-sc-topology-common:o-cu-up": "O-CU-UP", + "o-ran-sc-topology-common:o-du": "O-DU", + "o-ran-sc-topology-common:fronthaul-gateway": "FHGW", + "o-ran-sc-topology-common:o-ru": "O-RU", + "o-ran-sc-topology-common:user-equipment": "UE" + } + if mapping[self.function()]: + return mapping[self.function()] + else: + return self.function() + + def identifier(self) -> str: + """ + Getter returning the TAPI Node identifier. + :return Object identifier as UUID. + """ + return self.__data["uuid"] + + def json(self) -> dict: + """ + Getter for a json object representing the TAPI Node. + :return TAPI Node as json object. + """ + result = self.__data.copy() + result['owned-node-edge-point'] = [] + for nep in self.__data['owned-node-edge-point']: + result['owned-node-edge-point'].append(nep.json()) + return result + + def name(self) -> str: + """ + Getter for TAPI Node name. + :return TAPI Node as json object. + """ + return "".join([ + self.__configuration['node']['type'], + "-", + str(self.__configuration['node']['localId']) + ]) + + def node_edge_point_by_cep_name(self, cep_name, local_id) -> TapiNodeEdgePoint: + """ + Method returning a NEP based on a given interface name + :param interface_name: Search string + :return The NEP uuid or "not found" + """ + result = [] + for nep in self.__data["owned-node-edge-point"]: + for cep in nep.connection_edge_points(): + if cep.name() == cep_name: + result.append(nep) + if len(result) == 0: + for nep in self.__data["owned-node-edge-point"]: + print("# Check", cep_name, nep.json()["name"][0]["value"], nep.json()[ + "tapi-connectivity:cep-list"]["connection-end-point"][0]["name"][0]["value"]) + if len(result) > 1: + for nep in result: + if nep.name().endswith(str(local_id[-1])): + return nep + return result[0] + + def parent(self) -> 'TapiNode': + """ + Getter for a TAPI Node object representing the TAPI Node configuration. + :return TAPI Node configuration as json object. + """ + return self.__parent + + def svg(self, x: int, y: int) -> etree.Element: + """ + Getter for a xml Element object representing the TAPI Node. + :return TAPI Node as svg object. + """ + self.__svg_x = x + self.__svg_y = y + + svg_nep = None + if type(self).__name__ == "TapiNodeSmo": + svg_nep = Node(self, x, y) + elif type(self).__name__ == "TapiNodeOCloud": + svg_nep = OCloud(self, x, y) + elif type(self).__name__ == "TapiNodeNearRtRic": + svg_nep = NearRtRic(self, x, y) + elif type(self).__name__ == "TapiNodeOCuCp": + svg_nep = OCuCp(self, x, y) + elif type(self).__name__ == "TapiNodeOCuUp": + svg_nep = OCuUp(self, x, y) + elif type(self).__name__ == "TapiNodeODu": + svg_nep = ODu(self, x, y) + elif type(self).__name__ == "TapiNodeFronthaulGateway": + svg_nep = FronthaulGateway(self, x, y) + # elif type(self).__name__ == "TapiNodeORu": + # svg_nep = Node(self, x, y) + # elif type(self).__name__ == "TapiNodeUserEquipment": + # svg_nep = Node(self, x, y) + else: + svg_nep = Node(self, x, y) + + group: etree.Element = svg_nep.svg_element() + + for nep in self.data()['owned-node-edge-point']: + localId = 0 + if "local-id" in nep.configuration()["nodeEdgePoint"]: + localId = nep.configuration()["nodeEdgePoint"]["local-id"] + + nep_x = x + \ + self.x_offset_by_cep_name( + nep.connection_edge_points()[0].name(), localId) + nep_y = y + \ + self.y_offset_by_cep_name( + nep.connection_edge_points()[0].name()) + group.append(nep.svg(nep_x, nep_y)) + return group + + def width(self, width: int) -> None: + """ + Setter for the SVG width in px. + :param width as integer with unit "px" (pixel) + """ + self.__width = width + + # methods + + def add(self, nep: TapiNodeEdgePoint) -> 'TapiNode': + """ + Method adding a TAPI Node Edge Point object. + :return TAPI Node as object. + """ + self.__data['owned-node-edge-point'].append(nep) + return self -- 2.16.6 From 5a9c54ac4f3b080b0473ee006c679cc8825911a7 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:43:12 +0100 Subject: [PATCH 06/16] Create a script to generate a Topology - add (abstract) tapi link generation Issue-ID: OAM-249 Change-Id: I70a924ba6716b5c37c78a938a96f5c7befd2ddb1 Signed-off-by: demx8as6 --- .../model/python/tapi_link.py | 144 +++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_link.py diff --git a/code/network-topology-instance-generator/model/python/tapi_link.py b/code/network-topology-instance-generator/model/python/tapi_link.py new file mode 100644 index 0000000..d930d55 --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_link.py @@ -0,0 +1,144 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module for the class representing a TAPI Link +""" +from typing import Dict, Union +import uuid +from lxml import etree +from model.python.link_config import LinkConfig +from model.python.top import Top + + +class TapiLink(Top): + """ + Class representing a TAPI Link object. + """ + + __data: dict = {} + __configuration: dict = {} + + # constructor + def __init__(self, configuration: dict): + super().__init__(configuration) + self.__configuration = configuration + self.__link_configuration = LinkConfig( + topology_reference=configuration["topology_reference"], + name_prefix=configuration["name_prefix"], + provider=configuration["provider"], + consumer=configuration["consumer"] + ) + link_data = self.__link_configuration.json() + self.__data = { + "uuid": str(uuid.uuid4()), + "name": [{ + "value-name": "topology-link-name", + "value": link_data['link']['name'] + }], + "transitioned-layer-protocol-name": ["inETH", "outETH"], + "administrative-state": "LOCKED", + "operational-state": "ENABLED", + "direction": "BIDIRECTIONAL", + "lifecycle-state": "INSTALLED", + "node-edge-point": [ + link_data['link']['a'], + link_data['link']['z'] + ], + "latency-characteristic": [{ + "traffic-property-name": "property-1", + "queing-latency-characteristic": "queue-1", + "fixed-latency-characteristic": "latency-1", + "jitter-characteristic": "jitter-1", + "wander-characteristic": "wander-1" + }], + "layer-protocol-name": ["ETH"], + "risk-characteristic": [{ + "risk-characteristic-name": "risk-name", + "risk-identifier-list": [ + "risk-1"]}], + "validation-mechanism": [{ + "validation-mechanism": "mechanism-1", + "validation-robustness": "very-robust", + "layer-protocol-adjacency-validated": "validated"}], + "cost-characteristic": [{ + "cost-name": "cost", + "cost-algorithm": "alg1", + "cost-value": "value-1"}]} + + # getter + def configuration(self) -> Dict[str, Dict]: + """ + Getter for a json object representing the initial configuration of a TAPI Link. + :return TAPI Link configuration as json object. + """ + return self.__configuration + + def data(self) -> dict: + """ + Getter for a json object representing the TAPI Link. + :return TAPI Link as json object. + """ + return self.__data + + def json(self) -> dict: + """ + Getter for a json object representing the TAPI Link. + :return TAPI Link as json object. + """ + return self.data() + + def identifier(self) -> str: + """ + Getter returning the TAPI Link identifier. + :return Object identifier as UUID. + """ + return self.__data["uuid"] + + def name(self) -> str: + """ + Getter for TAPI Link name. + :return TAPI Link as json object. + """ + return self.__link_configuration.json()['link']['name'] + + def svg(self, svg_x: int, svg_y: int) -> etree.Element: + """ + Getter for a xml Element object representing the TAPI Link. + :return TAPI Link as svg object. + """ + + group = etree.Element("g") + group.attrib["class"] = "link" + title = etree.Element("title") + title.text = "\n TAPI Link\n id: " + \ + self.identifier() + "\n name: " + self.name() + group.append(title) + + # cubic bezier curves + source_x = self.__link_configuration.consumer_node_edge_point().svg_x() + source_y = self.__link_configuration.consumer_node_edge_point().svg_y() + target_x = self.__link_configuration.provider_node_edge_point().svg_x() + target_y = self.__link_configuration.provider_node_edge_point().svg_y() + + path = etree.Element("path") + path.attrib["d"] = " ".join(["M", str(source_x), str(source_y), + "C", str(source_x), str(target_y), + str(target_x), str(source_y), + str(target_x), str(target_y)]) + path.attrib["class"] = "link" + group.append(path) + + return group -- 2.16.6 From 53960109a8633dfdb8b8f8ba4e1541b22bbe49fc Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:44:26 +0100 Subject: [PATCH 07/16] Create a script to generate a Topology - add link configuration helper class Issue-ID: OAM-249 Change-Id: Ie71a0096d07922c6c305c95a12943b1806f5ca0f Signed-off-by: demx8as6 --- .../model/python/link_config.py | 154 +++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/link_config.py diff --git a/code/network-topology-instance-generator/model/python/link_config.py b/code/network-topology-instance-generator/model/python/link_config.py new file mode 100644 index 0000000..d33edcc --- /dev/null +++ b/code/network-topology-instance-generator/model/python/link_config.py @@ -0,0 +1,154 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module to construct the input configuration for a TAPI link object. +""" +from typing import Dict +from model.python.tapi_node import TapiNode +from model.python.tapi_node_edge_point import TapiNodeEdgePoint +from model.python.top import Top + + +class LinkConfig(Top): + """ + Class containing methods creating an link configuration object. + """ + + __topology_reference = "unknown" + __name_prefix: str = "unknown" + __consumer: TapiNode = None + __provider: TapiNode = None + + __data: dict = {"link": { + "name": "noName", + "a": {}, + "z": {} + }} + + # constructor + def __init__(self, topology_reference: str, name_prefix: str, + provider: TapiNode, consumer: TapiNode): + super().__init__({}) + self.__topology_reference = topology_reference + self.__name_prefix = name_prefix + self.__consumer = consumer + self.__provider = provider + + self.data = {"link": { + "name": self.name(), + "a": { + "topology-uuid": topology_reference, + "node-uuid": consumer.data()["uuid"], + "node-edge-point-uuid": + self.consumer_node_edge_point().identifier() + + }, + "z": { + "topology-uuid": topology_reference, + "node-uuid": provider.data()["uuid"], + "node-edge-point-uuid": + self.provider_node_edge_point().identifier() + } + }} + + def configuration(self) -> Dict[str, Dict[str, Dict]]: + """ + Getter returning the configuration. + :return Link identifier as string + """ + return {"configuration": { + "topology-reference:": self.__topology_reference, + "name_prefix": self.__name_prefix, + "provider": self.__provider.json(), + "consumer": self.__consumer.json() + }} + + def data(self) -> Dict[str, Dict]: + """ + Getter returning the link data of the link. + :return Link confguation data as json object + """ + return self.__data + + def identifier(self) -> str: + """ + Getter returning the link configuration identifier of the link. + :return Link identifier as string + """ + return "--".join([ + self.__consumer.identifier(), + self.__provider.identifier(), + ]) + + def name(self) -> str: + """ + Getter returning the name of the link. + :return Link name as string + """ + if self.__consumer: + return "|".join([ + self.__name_prefix.upper(), + self.__consumer.name(), + "->", + self.__provider.name(), + "" + ]) + return "" + + def json(self) -> dict: + """ + Getter for the json represention of this object. + :return JSON object of link configuration + """ + return self.data + + def consumer_node_edge_point(self) -> TapiNodeEdgePoint: + name_prefix = self.__name_prefix + + # exception for O-RAN Fronthaul Management plane to SMO + if self.__consumer.function() == "o-ran-sc-topology-common:smo" and \ + self.__provider.function() == "o-ran-sc-topology-common:o-ru" and \ + name_prefix == "ofh-netconf": # "open-fronthaul-m-plane-netconf": + name_prefix = "oam-netconf" + + # exception for O-RAN Gateway plane to SMO + if self.__consumer.function() == "o-ran-sc-topology-common:smo" and \ + name_prefix == "o1-netconf": # "open-fronthaul-m-plane-netconf": + name_prefix = "oam-netconf" + + # exception for O-RU to FHGW + if self.__provider.function() == "o-ran-sc-topology-common:fronthaul-gateway" and \ + name_prefix == "eth-ofh": # "open-fronthaul-m-plane-netconf": + name_prefix = "ofh-netconf" + + # exception for O-RU to FHGW + if self.__consumer.function() == "o-ran-sc-topology-common:fronthaul-gateway" and \ + name_prefix == "ofh-netconf": # "open-fronthaul-m-plane-netconf": + name_prefix = "eth-ofh" + + cep_name = name_prefix.lower() + "-consumer" + return self.__consumer.node_edge_point_by_cep_name(cep_name, self.__provider.local_id()) + + def provider_node_edge_point(self) -> TapiNodeEdgePoint: + name_prefix = self.__name_prefix + + cep_name = name_prefix.lower() + "-provider" + # exception for f1-c and f1-u + split = name_prefix.lower().split("-") + if len(split) == 3: + cep_name = "-".join([split[0], split[2], "provider"]) + + return self.__provider.node_edge_point_by_cep_name(cep_name, self.__consumer.local_id()) -- 2.16.6 From 65fa7565953545945f3f69c81e0ea2626af7368f Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:45:21 +0100 Subject: [PATCH 08/16] Create a script to generate a Topology - add tapi node generation for SMO Issue-ID: OAM-249 Change-Id: I8f5c7b0b5aa71b6e1ba7b163e474d364221ae2de Signed-off-by: demx8as6 --- .../model/python/tapi_node_smo.py | 165 +++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_node_smo.py diff --git a/code/network-topology-instance-generator/model/python/tapi_node_smo.py b/code/network-topology-instance-generator/model/python/tapi_node_smo.py new file mode 100644 index 0000000..87e0d07 --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_node_smo.py @@ -0,0 +1,165 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing a class representing a SMO as TAPI Node. +""" +from typing import List +from lxml import etree +from model.python.tapi_node import TapiNode +from model.python.tapi_node_edge_point import TapiNodeEdgePoint + + +class TapiNodeSmo(TapiNode): + """ + Class representing a SMO as TAPI Node + """ + __width: 0 + + # constructor + def __init__(self, parent: TapiNode, config): + super().__init__(parent, config) + + # add O2 consumer interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "o2", "cep": [{"protocol": "REST", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add A1 consumer interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "a1", "cep": [{"protocol": "REST", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add O1/OAM NetConf Consumer interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "oam", "cep": [{"protocol": "NETCONF", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add O1 VES Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "o1", "cep": [{"protocol": "VES", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add O1 File Transfer Consumer interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "o1", "cep": [{"protocol": "FILE", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + def __smo_component(self, x: int, y: int, label: str) -> etree.Element: + group = etree.Element("g") + group.attrib["class"] = " ".join(["node", label]) + + width = (2 + 2) * (2.2*self.FONTSIZE) + height = 2 * (2*self.FONTSIZE) + + rect = etree.Element("rect") + rect.attrib["x"] = str(int(x - width/2)) + rect.attrib["y"] = str(int(y - height/2)) + rect.attrib["width"] = str(int(width)) + rect.attrib["height"] = str(int(height)) + rect.attrib["rx"] = str(self.FONTSIZE) + rect.attrib["class"] = " ".join(["node", label]) + group.append(rect) + + labelElement = etree.Element('text') + labelElement.attrib['x'] = str(x) + # +4px for font-size 14px (think of chars like 'gjy') + labelElement.attrib['y'] = str(y + 4) + labelElement.attrib['class'] = " ".join(["node", label]) + labelElement.text = label.upper() + group.append(labelElement) + return group + + def svg(self, x: int, y: int) -> etree.Element: + """ + Getter for a xml Element object representing the TAPI Node. + :return TAPI Node as svg object. + """ + super().svg(x, y) + + components = ["o2-controller", "non-rt-ric", "oam-controller", + "ves-collector", "file-server"] + + group = etree.Element("g") + group.attrib["class"] = "node" + title = etree.Element("title") + title.text = "\n TAPI Node\n id: " + \ + self.identifier() + "\n name: " + self.name() + group.append(title) + + width = (len(components)*5 +1) * (2.2*self.FONTSIZE) + height = 2 * (2.2*self.FONTSIZE) + + rect = etree.Element("rect") + rect.attrib["x"] = str(int(x - width/2)) + rect.attrib["y"] = str(int(y - height/2)) + rect.attrib["width"] = str(int(width)) + rect.attrib["height"] = str(int(height)) + rect.attrib["rx"] = str(self.FONTSIZE) + rect.attrib["class"] = " ".join( + ["node", self.function_label().lower()]) + group.append(rect) + + label = etree.Element('text') + label.attrib['x'] = str(x) + # +4px for font-size 14px (think of chars like 'gjy') + label.attrib['y'] = str(y + 4) + label.attrib['class'] = " ".join( + ["node", self.function_label().lower()]) + label.text = self.function_label() + group.append(label) + + for component in components: + x_mapping = { + "o2-controller": -4*6*self.FONTSIZE, + "non-rt-ric": -2*6*self.FONTSIZE, + "oam-controller": -0*6*self.FONTSIZE, + "ves-collector": +2*6*self.FONTSIZE, + "file-server": +4*6*self.FONTSIZE + } + comp_x = x + x_mapping[component] + comp_y = y-0*self.FONTSIZE + group.append(self.__smo_component(comp_x, comp_y, component)) + + for nep in self.data()['owned-node-edge-point']: + nep_x = x + \ + super().x_offset_by_cep_name( + nep.connection_edge_points()[0].name(), 0) + nep_y = y + \ + super().y_offset_by_cep_name( + nep.connection_edge_points()[0].name()) + group.append(nep.svg(nep_x, nep_y)) + + return group -- 2.16.6 From 8af41aa6fe52651c25c06bada46665247d674e7e Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:45:56 +0100 Subject: [PATCH 09/16] Create a script to generate a Topology - add tapi node generation for NearRtRic Issue-ID: OAM-249 Change-Id: Icbd58c99bdfe9cda8dc61c132833a16c224e1251 Signed-off-by: demx8as6 --- .../model/python/tapi_node_near_rt_ric.py | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_node_near_rt_ric.py diff --git a/code/network-topology-instance-generator/model/python/tapi_node_near_rt_ric.py b/code/network-topology-instance-generator/model/python/tapi_node_near_rt_ric.py new file mode 100644 index 0000000..96d09ba --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_node_near_rt_ric.py @@ -0,0 +1,60 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing a class representing a Near RT RIC as TAPI Node. +""" +from model.python.tapi_node import TapiNode +from model.python.tapi_node_edge_point import TapiNodeEdgePoint + + +class TapiNodeNearRtRic(TapiNode): + """ + Class representing a Near RT RIC as TAPI Node. + """ + + # constructor + def __init__(self, parent, config): + super().__init__(parent, config) + # add A1 provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "a1", "cep": [{"protocol": "REST", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add E2 Consumer interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "e2", "cep": [{"protocol": "REST", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add O1/OAM NetConf Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "o1", "cep": [ + {"protocol": "NETCONF", "role": "provider"}, + {"protocol": "VES", "role": "consumer"}, + {"protocol": "FILE", "role": "provider"} + ] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) -- 2.16.6 From a2b96a699757984c40c5043f1f16c379770de2a5 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:46:22 +0100 Subject: [PATCH 10/16] Create a script to generate a Topology - add tapi node generation for O-Cloud provider Issue-ID: OAM-249 Change-Id: I2b780791d32c9a5a39f8f1a8a54b4a8f63820877 Signed-off-by: demx8as6 --- .../model/python/tapi_node_o_cloud.py | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_node_o_cloud.py diff --git a/code/network-topology-instance-generator/model/python/tapi_node_o_cloud.py b/code/network-topology-instance-generator/model/python/tapi_node_o_cloud.py new file mode 100644 index 0000000..dcbb53a --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_node_o_cloud.py @@ -0,0 +1,40 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing a class representing a Near RT RIC as TAPI Node. +""" +from model.python.tapi_node import TapiNode +from model.python.tapi_node_edge_point import TapiNodeEdgePoint + + +class TapiNodeOCloud(TapiNode): + """ + Class representing a O-Cloud as TAPI Node. + """ + + # constructor + def __init__(self, parent, config): + super().__init__(parent, config) + super().width( (18 + 1) * (2*self.FONTSIZE) ) + + # add A1 provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "o2", "cep": [{"protocol": "REST", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) -- 2.16.6 From 70c480603bb4cb6c5566920026cda2fd2e0f44c0 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:47:04 +0100 Subject: [PATCH 11/16] Create a script to generate a Topology - add tapi node generation for O-CU-CP Issue-ID: OAM-249 Change-Id: I3e34b47ee026e02e3f600dad5dcae2007f9fc8b6 Signed-off-by: demx8as6 --- .../model/python/tapi_node_o_cu_cp.py | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_node_o_cu_cp.py diff --git a/code/network-topology-instance-generator/model/python/tapi_node_o_cu_cp.py b/code/network-topology-instance-generator/model/python/tapi_node_o_cu_cp.py new file mode 100644 index 0000000..c0525ee --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_node_o_cu_cp.py @@ -0,0 +1,70 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing a class representing an O-RAN Centralized Unit as TAPI Node. +""" +from model.python.tapi_node import TapiNode +from model.python.tapi_node_edge_point import TapiNodeEdgePoint + + +class TapiNodeOCuCp(TapiNode): + """ + Class representing a O-RAN Centralized Unit as TAPI Node. + """ + # constructor + + def __init__(self, parent, config): + super().__init__(parent, config) + + # add E2 Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "e2", "cep":[{"protocol": "REST", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add O1/OAM NetConf Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "o1", "cep": [ + {"protocol": "NETCONF", "role": "provider"}, + {"protocol": "VES", "role": "consumer"}, + {"protocol": "FILE", "role": "provider"} + ] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add F1 CP Consumer interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "f1-c", "cep":[{"protocol": "unknown", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add E1 Consumer interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "e1", "cep":[{"protocol": "unknown", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) -- 2.16.6 From 3897453977a2f789b6f7b5fd51257f44722393c1 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:47:25 +0100 Subject: [PATCH 12/16] Create a script to generate a Topology - add tapi node generation for O-CU-CP Issue-ID: OAM-249 Change-Id: I8a7ccc5f4094ce2efda9984a52e8d38f5cd8352a Signed-off-by: demx8as6 --- .../model/python/tapi_node_o_cu_up.py | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_node_o_cu_up.py diff --git a/code/network-topology-instance-generator/model/python/tapi_node_o_cu_up.py b/code/network-topology-instance-generator/model/python/tapi_node_o_cu_up.py new file mode 100644 index 0000000..81d781e --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_node_o_cu_up.py @@ -0,0 +1,70 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing a class representing an O-RAN Centralized Unit as TAPI Node. +""" +from model.python.tapi_node import TapiNode +from model.python.tapi_node_edge_point import TapiNodeEdgePoint + + +class TapiNodeOCuUp(TapiNode): + """ + Class representing a O-RAN Centralized Unit as TAPI Node. + """ + # constructor + + def __init__(self, parent, config): + super().__init__(parent, config) + + # add E2 Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "e2", "cep":[{"protocol": "REST", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add O1/OAM NetConf Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "o1", "cep": [ + {"protocol": "NETCONF", "role": "provider"}, + {"protocol": "VES", "role": "consumer"}, + {"protocol": "FILE", "role": "provider"} + ] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add F1 UP Consumer interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "f1-u", "cep":[{"protocol": "unknown", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add E1 Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "e1", "cep":[{"protocol": "unknown", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) -- 2.16.6 From d63f9020a7e060bcfda6ef5629fb156dedb35f88 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:48:09 +0100 Subject: [PATCH 13/16] Create a script to generate a Topology - add tapi node generation for O-DU Issue-ID: OAM-249 Change-Id: I9913efd0bc836b2304c0e288fbc0b5b09eb92bc4 Signed-off-by: demx8as6 --- .../model/python/tapi_node_o_du.py | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_node_o_du.py diff --git a/code/network-topology-instance-generator/model/python/tapi_node_o_du.py b/code/network-topology-instance-generator/model/python/tapi_node_o_du.py new file mode 100644 index 0000000..d458ed1 --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_node_o_du.py @@ -0,0 +1,70 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing a class representing an O-RAN Distributed Unit as TAPI Node. +""" +from model.python.tapi_node import TapiNode +from model.python.tapi_node_edge_point import TapiNodeEdgePoint + + +class TapiNodeODu(TapiNode): + """ + Class representing a O-RAN Distributed Unit as TAPI Node. + """ + # constructor + + def __init__(self, parent, config): + super().__init__(parent, config) + + # add E2 Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "e2", "cep":[{"protocol": "REST", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add O1/OAM NetConf Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "o1", "cep": [ + {"protocol": "NETCONF", "role": "provider"}, + {"protocol": "VES", "role": "consumer"}, + {"protocol": "FILE", "role": "provider"} + ] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add F1 CP Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "f1", "cep":[{"protocol": "unknown", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add OpenFronthaul Consumer interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "ofh", "cep":[{"protocol": "netconf", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) -- 2.16.6 From f9d035e8b17ef4229a2defeec6ba1ea0f75a6176 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:49:08 +0100 Subject: [PATCH 14/16] Create a script to generate a Topology - add tapi node generation for Fronthaul Gateway Issue-ID: OAM-249 Change-Id: Ic3f3b5997bd0871b945446e6ec5c7cea075e37af Signed-off-by: demx8as6 --- .../model/python/tapi_node_fronthaul_gateway.py | 63 ++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_node_fronthaul_gateway.py diff --git a/code/network-topology-instance-generator/model/python/tapi_node_fronthaul_gateway.py b/code/network-topology-instance-generator/model/python/tapi_node_fronthaul_gateway.py new file mode 100644 index 0000000..ca2e4a6 --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_node_fronthaul_gateway.py @@ -0,0 +1,63 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing a class representing an O-RAN Radio Unit as TAPI Node. +""" +from model.python.tapi_node import TapiNode +from model.python.tapi_node_edge_point import TapiNodeEdgePoint + + +class TapiNodeFronthaulGateway(TapiNode): + """ + Class representing a O-RAN Fronthaul Gateway as TAPI Node. + """ + + # constructor + def __init__(self, parent, configuration): + super().__init__(parent, configuration) + + count = max(2, configuration["node"]["southbound-nep-count"]) + super().width((count + 1) * (2*self.FONTSIZE)) + + # add Ethernet Northbound provider + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "eth", "cep": [{"protocol": "ofh", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add OAM provider + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "oam", "cep": [{"protocol": "netconf", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add Ethernet Southbound consumer + for nep_index in range(configuration["node"]["southbound-nep-count"]): + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "local-id": nep_index, + "interface": "eth", + "cep": [{"protocol": "ofh", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) -- 2.16.6 From 6a7494d6b0f6f96d6521afc30a7ae1ff3f98ba06 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:49:35 +0100 Subject: [PATCH 15/16] Create a script to generate a Topology - add tapi node generation for O-RU Issue-ID: OAM-249 Change-Id: Id9ecb5ce3b90a359e57f61bb2c760e83cafc427b Signed-off-by: demx8as6 --- .../model/python/tapi_node_o_ru.py | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_node_o_ru.py diff --git a/code/network-topology-instance-generator/model/python/tapi_node_o_ru.py b/code/network-topology-instance-generator/model/python/tapi_node_o_ru.py new file mode 100644 index 0000000..d5993fc --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_node_o_ru.py @@ -0,0 +1,50 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing a class representing an O-RAN Radio Unit as TAPI Node. +""" +from model.python.tapi_node import TapiNode +from model.python.tapi_node_edge_point import TapiNodeEdgePoint + + +class TapiNodeORu(TapiNode): + """ + Class representing a O-RAN Radio Unit as TAPI Node. + """ + + # constructor + def __init__(self, parent, config): + super().__init__(parent, config) + + super().width( (1 + 1) * (2*self.FONTSIZE) ) # 1x nep + + # add OpenFronthaul Management Plane/OAM NetConf Provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "ofh", "cep":[{"protocol": "NETCONF", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + + # add air provider interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "uu", "cep":[{"protocol": "unknown", "role": "provider"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) -- 2.16.6 From 6ec1674f1e877a032c475397b0bd40925dd9f4b1 Mon Sep 17 00:00:00 2001 From: demx8as6 Date: Tue, 22 Feb 2022 12:50:00 +0100 Subject: [PATCH 16/16] Create a script to generate a Topology - add tapi node generation for User Equipment Issue-ID: OAM-249 Change-Id: I874637be348751fa64f909cfe39d1b1c36a8d66a Signed-off-by: demx8as6 --- .../model/python/tapi_node_user_equipment.py | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 code/network-topology-instance-generator/model/python/tapi_node_user_equipment.py diff --git a/code/network-topology-instance-generator/model/python/tapi_node_user_equipment.py b/code/network-topology-instance-generator/model/python/tapi_node_user_equipment.py new file mode 100644 index 0000000..48543bd --- /dev/null +++ b/code/network-topology-instance-generator/model/python/tapi_node_user_equipment.py @@ -0,0 +1,42 @@ +# Copyright 2022 highstreet technologies GmbH +# +# 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. + +#!/usr/bin/python +""" +Module containing a class representing a User Equipment as TAPI Node. +""" +from model.python.tapi_node import TapiNode +from model.python.tapi_node_edge_point import TapiNodeEdgePoint + + +class TapiNodeUserEquipment(TapiNode): + """ + Class representing a User Equipment as TAPI Node + """ + + # constructor + def __init__(self, parent, config): + super().__init__(parent, config) + + super().width( (1 + 1) * (2*self.FONTSIZE) ) # 1x nep + + # add air consumer interface + nep_configuration = { + "parent": self.identifier(), + "nodeEdgePoint": { + "interface": "uu", "cep":[{"protocol": "unknown", "role": "consumer"}] + } + } + self.add(TapiNodeEdgePoint(nep_configuration)) + -- 2.16.6