Commit d2710461 authored by Leandro Campos's avatar Leandro Campos
Browse files

sap-topology updated

parent 4b1b0e60
Loading
Loading
Loading
Loading
+0 −53
Original line number Diff line number Diff line
# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from common.proto.context_pb2 import Link
from .bindings.networks.network.link import link
from .NameMapping import NameMappings
from .NetworkTypeEnum import NetworkTypeEnum

def compose_link(
    ietf_link_obj : link, link_specs : Link, name_mappings : NameMappings, network_type : NetworkTypeEnum
) -> None:
    src_endpoint_id = link_specs.link_endpoint_ids[0]
    ietf_link_obj.source.source_node = name_mappings.get_device_name(src_endpoint_id.device_id)
    ietf_link_obj.source.source_tp   = name_mappings.get_endpoint_name(src_endpoint_id)

    dst_endpoint_id = link_specs.link_endpoint_ids[-1]
    ietf_link_obj.destination.dest_node = name_mappings.get_device_name(dst_endpoint_id.device_id)
    ietf_link_obj.destination.dest_tp   = name_mappings.get_endpoint_name(dst_endpoint_id)

    ietf_link_obj.te._set_oper_status('up')

    te_link_attrs = ietf_link_obj.te.te_link_attributes
    te_link_attrs.access_type = 'point-to-point'
    te_link_attrs.admin_status = 'up'
    te_link_attrs.name = link_specs.name

    if network_type == NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY:
        link_total_cap_kbps = link_specs.attributes.total_capacity_gbps * 1e6
        link_used_cap_kbps  = link_specs.attributes.used_capacity_gbps * 1e6
        link_avail_cap_kbps = link_total_cap_kbps - link_used_cap_kbps

        te_link_attrs.max_link_bandwidth.te_bandwidth.eth_bandwidth = link_total_cap_kbps
        unresv_bw = te_link_attrs.unreserved_bandwidth.add(7)
        unresv_bw.te_bandwidth.eth_bandwidth = link_avail_cap_kbps
    elif network_type == NetworkTypeEnum.TE_OTN_TOPOLOGY:
        te_link_attrs.te_delay_metric = 1
        oduitem = te_link_attrs.max_link_bandwidth.te_bandwidth.otn.odulist.add('ietf-layer1-types:ODU0')
        oduitem.ts_number = 80

        unresv_bw = te_link_attrs.unreserved_bandwidth.add(7)
        oduitem = unresv_bw.te_bandwidth.otn.odulist.add('ietf-layer1-types:ODU0')
        oduitem.ts_number = 80
+0 −115
Original line number Diff line number Diff line
# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging, re
from common.DeviceTypes import DeviceTypeEnum
from common.proto.context_pb2 import TopologyDetails
from .bindings.networks.network import network
from .ComposeLink import compose_link
from .ComposeNode import compose_node
from .NameMapping import NameMappings
from .NetworkTypeEnum import NetworkTypeEnum, get_network_topology_type

LOGGER = logging.getLogger(__name__)

IGNORE_DEVICE_TYPES = {
    DeviceTypeEnum.CLIENT.value,
    DeviceTypeEnum.DATACENTER.value,
    DeviceTypeEnum.EMULATED_CLIENT.value,
    DeviceTypeEnum.EMULATED_DATACENTER.value,
    DeviceTypeEnum.EMULATED_IP_SDN_CONTROLLER,
    DeviceTypeEnum.EMULATED_MICROWAVE_RADIO_SYSTEM.value,
    DeviceTypeEnum.EMULATED_OPEN_LINE_SYSTEM.value,
    DeviceTypeEnum.EMULATED_XR_CONSTELLATION.value,
    DeviceTypeEnum.IP_SDN_CONTROLLER,
    DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM.value,
    DeviceTypeEnum.NETWORK.value,
    DeviceTypeEnum.OPEN_LINE_SYSTEM.value,
    DeviceTypeEnum.XR_CONSTELLATION.value,
}

IGNORE_DEVICE_NAMES = {
    NetworkTypeEnum.TE_OTN_TOPOLOGY: {
        'nce-t', '128.32.10.1', '128.32.33.5', '128.32.20.5', '128.32.20.1', '128.32.10.5',
    },
    NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY: {
        'nce-t',
    },
}

TE_TOPOLOGY_NAME = 'Huawei-Network'

def compose_network(ietf_network_obj : network, te_topology_name : str, topology_details : TopologyDetails) -> None:
    ietf_network_obj.te.name = TE_TOPOLOGY_NAME

    #te_topology_name = topology_details.name
    match = re.match(r'providerId\-([^\-]*)-clientId-([^\-]*)-topologyId-([^\-]*)', te_topology_name)
    if match is not None:
        provider_id, client_id, topology_id = match.groups()
        ietf_network_obj.te_topology_identifier.provider_id = int(provider_id)
        ietf_network_obj.te_topology_identifier.client_id   = int(client_id)
        ietf_network_obj.te_topology_identifier.topology_id = str(topology_id)
    else:
        ietf_network_obj.te_topology_identifier.provider_id = 10
        ietf_network_obj.te_topology_identifier.client_id   = 0
        ietf_network_obj.te_topology_identifier.topology_id = '0'

    ietf_network_obj.network_types.te_topology._set_present()
    # TODO: resolve setting of otn_topology/eth_tran_topology network type; not working in bindings.
    # See "../ManualFixes.py".
    topology_id = ietf_network_obj.te_topology_identifier.topology_id
    topology_id = {
        '1': NetworkTypeEnum.TE_OTN_TOPOLOGY.value,
        '2': NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY.value,
    }.get(topology_id, topology_id)
    network_type = get_network_topology_type(topology_id)
    if network_type == NetworkTypeEnum.TE_OTN_TOPOLOGY:
        #ietf_network_obj.network_types.te_topology.otn_topology._set_present()
        pass
    elif network_type == NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY:
        #ietf_network_obj.network_types.te_topology.eth_tran_topology._set_present()
        pass
    else:
        raise Exception('Unsupported TopologyId({:s})'.format(str(topology_id)))

    name_mappings = NameMappings()

    ignore_device_uuids = set()

    for device in topology_details.devices:
        device_uuid = device.device_id.device_uuid.uuid

        device_type = device.device_type
        if device_type in IGNORE_DEVICE_TYPES:
            ignore_device_uuids.add(device_uuid)
            continue

        device_name = device.name
        if device_name in IGNORE_DEVICE_NAMES.get(network_type, set()):
            ignore_device_uuids.add(device_uuid)
            continue

        ietf_node_obj = ietf_network_obj.node.add(device_name)
        compose_node(ietf_node_obj, device, name_mappings, network_type)

    for link in topology_details.links:
        link_device_uuids = {
            endpoint_id.device_id.device_uuid.uuid
            for endpoint_id in link.link_endpoint_ids
        }
        if len(ignore_device_uuids.intersection(link_device_uuids)) > 0:
            continue
        link_name = link.name
        ietf_link_obj = ietf_network_obj.link.add(link_name)
        compose_link(ietf_link_obj, link, name_mappings, network_type)
+0 −107
Original line number Diff line number Diff line
# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
from common.proto.context_pb2 import Device
from .bindings.networks.network.node import node
from .ComposeTermPoint import compose_term_point
from .NameMapping import NameMappings
from .NetworkTypeEnum import NetworkTypeEnum

LOGGER = logging.getLogger(__name__)

MAPPINGS_TE_NODE_NAME = {
    '10.0.10.1'  : 'OA',
    '10.0.20.1'  : 'P',
    '10.0.30.1'  : 'OE',
    '10.0.40.1'  : 'P',

    '128.32.10.1': 'ONT1',
    '128.32.20.1': 'ONT2',
    '128.32.33.5': 'OLT',
}

IGNORE_ENDPOINT_NAMES = {'mgmt', 'eth1'}

def compose_node(
    ietf_node_obj : node, device : Device, name_mappings : NameMappings, network_type : NetworkTypeEnum
) -> None:
    device_name = device.name

    name_mappings.store_device_name(device)

    ietf_node_obj.te_node_id = device_name

    ietf_node_obj.te._set_oper_status('up')
    ietf_node_obj.te.te_node_attributes.admin_status = 'up'
    ietf_node_obj.te.te_node_attributes.name = MAPPINGS_TE_NODE_NAME.get(device_name, device_name)

    for endpoint in device.device_endpoints:
        endpoint_name = endpoint.name
        if endpoint_name in IGNORE_ENDPOINT_NAMES: continue
        if network_type == NetworkTypeEnum.TE_OTN_TOPOLOGY and endpoint.endpoint_type != 'optical': continue

        ietf_tp_obj = ietf_node_obj.termination_point.add(endpoint_name)
        compose_term_point(ietf_tp_obj, device, endpoint, name_mappings, network_type)

    if network_type == NetworkTypeEnum.TE_OTN_TOPOLOGY:
        if device_name in {'10.0.30.1', '10.0.40.1'}:
            ntaw = ietf_node_obj.te.tunnel_termination_point.add('NTAw')
            ntaw.admin_status = 'up'
            ntaw.encoding = 'ietf-te-types:lsp-encoding-oduk'
            ntaw_llc = ntaw.local_link_connectivities.local_link_connectivity.add('500')
            ntaw_llc.is_allowed = True
            ntaw.name = '1-1-1-1-1'
            ntaw._set_oper_status('up')
            ntaw.protection_type = 'ietf-te-types:lsp-protection-unprotected'
            ntaw.switching_capability = 'ietf-te-types:switching-otn'

            ntax = ietf_node_obj.te.tunnel_termination_point.add('NTAx')
            ntax.admin_status = 'up'
            ntax.encoding = 'ietf-te-types:lsp-encoding-oduk'
            ntax_llc = ntax.local_link_connectivities.local_link_connectivity.add('501')
            ntax_llc.is_allowed = True
            ntax.name = '1-1-1-1-1'
            ntax._set_oper_status('up')
            ntax.protection_type = 'ietf-te-types:lsp-protection-unprotected'
            ntax.switching_capability = 'ietf-te-types:switching-otn'
        elif device_name in {'10.0.10.1', '10.0.20.1'}:
            ntax = ietf_node_obj.te.tunnel_termination_point.add('NTAx')
            ntax.admin_status = 'up'
            ntax.encoding = 'ietf-te-types:lsp-encoding-oduk'
            ntax_llc = ntax.local_link_connectivities.local_link_connectivity.add('501')
            ntax_llc.is_allowed = True
            ntax.name = '1-1-1-1-1'
            ntax._set_oper_status('up')
            ntax.protection_type = 'ietf-te-types:lsp-protection-unprotected'
            ntax.switching_capability = 'ietf-te-types:switching-otn'

            ntaw = ietf_node_obj.te.tunnel_termination_point.add('NTAw')
            ntaw.admin_status = 'up'
            ntaw.encoding = 'ietf-te-types:lsp-encoding-oduk'
            ntaw_llc = ntaw.local_link_connectivities.local_link_connectivity.add('500')
            ntaw_llc.is_allowed = True
            ntaw.name = '1-1-1-1-1'
            ntaw._set_oper_status('up')
            ntaw.protection_type = 'ietf-te-types:lsp-protection-unprotected'
            ntaw.switching_capability = 'ietf-te-types:switching-otn'
    elif network_type == NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY:
        if device_name in {'128.32.33.5'}:
            connectivity_matrices = ietf_node_obj.te.te_node_attributes.connectivity_matrices
            lr0 = connectivity_matrices.label_restrictions.label_restriction.add(0)
            lr0.label_start.te_label.vlanid = 21
            lr0.label_end.te_label.vlanid = 21
            lr1 = connectivity_matrices.label_restrictions.label_restriction.add(1)
            lr1.label_start.te_label.vlanid = 31
            lr1.label_end.te_label.vlanid = 31
+0 −102
Original line number Diff line number Diff line
# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
from common.proto.context_pb2 import Device, EndPoint
from .bindings.networks.network.node.termination_point import termination_point
from .NameMapping import NameMappings
from .NetworkTypeEnum import NetworkTypeEnum

MAPPINGS_TE_NAME = {
    (NetworkTypeEnum.TE_OTN_TOPOLOGY,      '10.0.10.1', '200'): '1-1-1-1-1',
    (NetworkTypeEnum.TE_OTN_TOPOLOGY,      '10.0.10.1', '500'): '1-1-1-1-1',
    (NetworkTypeEnum.TE_OTN_TOPOLOGY,      '10.0.10.1', '501'): '1-1-1-1-1',

    (NetworkTypeEnum.TE_OTN_TOPOLOGY,      '10.0.20.1', '500'): '1-1-1-1-1',
    (NetworkTypeEnum.TE_OTN_TOPOLOGY,      '10.0.20.1', '501'): '1-1-1-1-1',

    (NetworkTypeEnum.TE_OTN_TOPOLOGY,      '10.0.30.1', '200'): '1-1-1-1-1',
    (NetworkTypeEnum.TE_OTN_TOPOLOGY,      '10.0.30.1', '500'): '1-1-1-1-1',
    (NetworkTypeEnum.TE_OTN_TOPOLOGY,      '10.0.30.1', '501'): '1-1-1-1-1',

    (NetworkTypeEnum.TE_OTN_TOPOLOGY,      '10.0.40.1', '500'): '1-1-1-1-1',
    (NetworkTypeEnum.TE_OTN_TOPOLOGY,      '10.0.40.1', '501'): '1-1-1-1-1',

    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.10.1', '200'): 'endpoint:111',
    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.10.1', '500'): 'endpoint:111',
    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.10.1', '501'): 'endpoint:111',

    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.20.1', '500'): 'endpoint:111',
    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.20.1', '501'): 'endpoint:111',

    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.30.1', '200'): 'endpoint:111',
    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.30.1', '500'): 'endpoint:111',
    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.30.1', '501'): 'endpoint:111',

    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.40.1', '500'): 'endpoint:111',
    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.40.1', '501'): 'endpoint:111',

    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '128.32.33.5', '500') : 'endpoint:111',
}

MAPPINGS_TE_TP_ID = {
    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.10.1', '200'): '128.32.33.254',
    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '10.0.30.1', '200'): '172.10.33.254',

    (NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY, '128.32.33.5', '500') : '128.32.33.2',
}

LOGGER = logging.getLogger(__name__)

def compose_term_point(
    ietf_tp_obj : termination_point, device : Device, endpoint : EndPoint, name_mappings : NameMappings,
    network_type : NetworkTypeEnum
) -> None:
    name_mappings.store_endpoint_name(device, endpoint)

    device_name   = device.name
    endpoint_name = endpoint.name

    ietf_tp_obj.te_tp_id = MAPPINGS_TE_TP_ID.get((network_type, device_name, endpoint_name), endpoint_name)

    if (network_type, device_name, endpoint_name) in MAPPINGS_TE_NAME:
        ietf_tp_obj.te._set_oper_status('up')
        ietf_tp_obj.te.admin_status = 'up'
        ietf_tp_obj.te.name = MAPPINGS_TE_NAME.get((network_type, device_name, endpoint_name), endpoint_name)

    if network_type == NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY:
        if (network_type, device_name, endpoint_name) in MAPPINGS_TE_NAME:
            ietf_if_sw_cap = ietf_tp_obj.te.interface_switching_capability.add(
                'ietf-te-types:switching-l2sc ietf-te-types:lsp-encoding-ethernet'
            )
            ietf_max_lsp_bw = ietf_if_sw_cap.max_lsp_bandwidth.add('7')
            ietf_max_lsp_bw.te_bandwidth.eth_bandwidth = 10_000_000 # Kbps

        #ietf_tp_obj.eth_svc.client_facing = True

        ietf_tp_obj.eth_svc.supported_classification.port_classification = True
        outer_tag = ietf_tp_obj.eth_svc.supported_classification.vlan_classification.outer_tag
        outer_tag.supported_tag_types.append('ietf-eth-tran-types:classify-c-vlan')
        outer_tag.supported_tag_types.append('ietf-eth-tran-types:classify-s-vlan')
        outer_tag.vlan_bundling = False
        outer_tag.vlan_range = '1-4094'

    elif network_type == NetworkTypeEnum.TE_OTN_TOPOLOGY:
        #ietf_tp_obj.te.client_svc.client_facing = False

        ietf_if_sw_cap = ietf_tp_obj.te.interface_switching_capability.add(
            'ietf-te-types:switching-otn ietf-te-types:lsp-encoding-oduk'
        )
        ietf_max_lsp_bw = ietf_if_sw_cap.max_lsp_bandwidth.add('7')
        ietf_max_lsp_bw.te_bandwidth.otn.odu_type = 'ietf-layer1-types:ODU4'
+0 −73
Original line number Diff line number Diff line
# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import Dict

from .NetworkTypeEnum import NetworkTypeEnum

def manual_fixes(json_response : Dict) -> None:
    # TODO: workaround to set network types manually. Currently does not work; refine bindings.
    # Seems limitation of pyangbind using multiple augmentations and nested empty containers.
    for json_network in json_response['ietf-network:networks']['network']:
        net_te_topo_id = json_network.get('ietf-te-topology:te-topology-identifier', {}).get('topology-id')
        if net_te_topo_id is None: continue
        net_te_topo_type = json_network['network-types']['ietf-te-topology:te-topology']
        if net_te_topo_id == '1':
            network_type = NetworkTypeEnum.TE_OTN_TOPOLOGY
            net_te_topo_type['ietf-otn-topology:otn-topology'] = {}
        elif net_te_topo_id == '2':
            network_type = NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY
            net_te_topo_type['ietf-eth-te-topology:eth-tran-topology'] = {}
        else:
            network_type = None

        for json_node in json_network.get('node', []):
            for json_tp in json_node.get('ietf-network-topology:termination-point', []):
                json_tp_te = json_tp.get('ietf-te-topology:te', {})

                if network_type == NetworkTypeEnum.TE_OTN_TOPOLOGY:
                    json_tp_te_cs = json_tp_te.setdefault('ietf-otn-topology:client-svc', {})
                    json_tp_te_cs['client-facing'] = False
                elif network_type == NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY:
                    if 'ietf-eth-te-topology:eth-svc' in json_tp:
                        client_facing = json_tp['tp-id'] in {'200', '201'}
                        json_tp['ietf-eth-te-topology:eth-svc']['client-facing'] = client_facing

                # Fix value type of bandwidth
                for json_if_sw_cap in json_tp_te.get('interface-switching-capability', []):
                    for json_max_lsp_bandwidth in json_if_sw_cap.get('max-lsp-bandwidth', []):
                        json_te_bw = json_max_lsp_bandwidth.get('te-bandwidth', {})
                        if network_type == NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY:
                            if 'ietf-eth-te-topology:eth-bandwidth' in json_te_bw:
                                eth_bw = json_te_bw['ietf-eth-te-topology:eth-bandwidth']
                                if isinstance(eth_bw, str):
                                    json_te_bw['ietf-eth-te-topology:eth-bandwidth'] = int(eth_bw)

        for json_link in json_network.get('ietf-network-topology:link', []):
            json_link_te_attributes = json_link.get('ietf-te-topology:te', {}).get('te-link-attributes', {})

            # Fix value type of bandwidth
            json_te_bw = json_link_te_attributes.get('max-link-bandwidth', {}).get('te-bandwidth', {})
            if network_type == NetworkTypeEnum.TE_ETH_TRAN_TOPOLOGY:
                if 'ietf-eth-te-topology:eth-bandwidth' in json_te_bw:
                    eth_bw = json_te_bw['ietf-eth-te-topology:eth-bandwidth']
                    if isinstance(eth_bw, str):
                        json_te_bw['ietf-eth-te-topology:eth-bandwidth'] = int(eth_bw)

                for json_unresv_bandwidth in json_link_te_attributes.get('unreserved-bandwidth', []):
                    json_te_bw = json_unresv_bandwidth.get('te-bandwidth', {})
                    if 'ietf-eth-te-topology:eth-bandwidth' in json_te_bw:
                        eth_bw = json_te_bw['ietf-eth-te-topology:eth-bandwidth']
                        if isinstance(eth_bw, str):
                            json_te_bw['ietf-eth-te-topology:eth-bandwidth'] = int(eth_bw)
Loading