diff --git a/src/nbi/service/ietf_l2vpn/Handlers.py b/src/nbi/service/ietf_l2vpn/Handlers.py new file mode 100644 index 0000000000000000000000000000000000000000..775c0aab05222999898274cdde08cf036fd86edd --- /dev/null +++ b/src/nbi/service/ietf_l2vpn/Handlers.py @@ -0,0 +1,265 @@ +# Copyright 2022-2025 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 typing import Dict, List, Optional +from common.Constants import DEFAULT_CONTEXT_NAME +from common.proto.context_pb2 import Service, ServiceStatusEnum, ServiceTypeEnum +from common.tools.context_queries.Service import get_service_by_uuid +from common.tools.grpc.ConfigRules import update_config_rule_custom +from common.tools.grpc.Constraints import ( + update_constraint_custom_dict, update_constraint_endpoint_location, + update_constraint_endpoint_priority, update_constraint_sla_availability, + update_constraint_sla_capacity, update_constraint_sla_latency, +) +from common.tools.grpc.EndPointIds import update_endpoint_ids +from common.tools.grpc.Tools import grpc_message_to_json_string +from context.client.ContextClient import ContextClient +from service.client.ServiceClient import ServiceClient +from .Constants import ( + #DEFAULT_ADDRESS_FAMILIES, DEFAULT_BGP_AS, DEFAULT_BGP_ROUTE_TARGET, + BEARER_MAPPINGS, DEFAULT_MTU, +) + +LOGGER = logging.getLogger(__name__) + +def create_service( + service_uuid : str, context_uuid : Optional[str] = DEFAULT_CONTEXT_NAME +) -> Optional[Exception]: + # pylint: disable=no-member + service_request = Service() + service_request.service_id.context_id.context_uuid.uuid = context_uuid + service_request.service_id.service_uuid.uuid = service_uuid + service_request.service_type = ServiceTypeEnum.SERVICETYPE_L2NM + service_request.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_PLANNED + + try: + service_client = ServiceClient() + service_client.CreateService(service_request) + return None + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unhandled exception creating Service') + return e + +def process_vpn_service( + vpn_service : Dict, errors : List[Dict] +) -> None: + vpn_id = vpn_service['vpn-id'] + exc = create_service(vpn_id) + if exc is not None: errors.append({'error': str(exc)}) + + +def process_site_network_access( + site_id : str, network_access : Dict, errors : List[Dict] +) -> None: + try: + site_network_access_type = network_access['site-network-access-type'] + site_network_access_type = site_network_access_type.replace('ietf-l2vpn-svc:', '') + if site_network_access_type != 'multipoint': + MSG = 'Site Network Access Type: {:s}' + msg = MSG.format(str(network_access['site-network-access-type'])) + raise NotImplementedError(msg) + + access_role : str = network_access['vpn-attachment']['site-role'] + access_role = access_role.replace('ietf-l2vpn-svc:', '').replace('-role', '') # hub/spoke + if access_role not in {'hub', 'spoke'}: + MSG = 'Site VPN Attackment Role: {:s}' + raise NotImplementedError(MSG.format(str(network_access['site-network-access-type']))) + + device_uuid = network_access['device-reference'] + endpoint_uuid = network_access['site-network-access-id'] + service_uuid = network_access['vpn-attachment']['vpn-id'] + + encapsulation_type = network_access['connection']['encapsulation-type'] + cvlan_tag_id = network_access['connection']['tagged-interface'][encapsulation_type]['cvlan-id'] + + bearer_reference = network_access['bearer']['bearer-reference'] + + service_mtu = network_access['service']['svc-mtu'] + service_input_bandwidth = network_access['service']['svc-input-bandwidth'] + service_output_bandwidth = network_access['service']['svc-output-bandwidth'] + service_bandwidth_bps = max(service_input_bandwidth, service_output_bandwidth) + service_bandwidth_gbps = service_bandwidth_bps / 1.e9 + + max_e2e_latency_ms = None + availability = None + for qos_profile_class in network_access['service']['qos']['qos-profile']['classes']['class']: + if qos_profile_class['class-id'] != 'qos-realtime': + MSG = 'Site Network Access QoS Class Id: {:s}' + raise NotImplementedError(MSG.format(str(qos_profile_class['class-id']))) + + qos_profile_class_direction = qos_profile_class['direction'] + qos_profile_class_direction = qos_profile_class_direction.replace('ietf-l2vpn-svc:', '') + if qos_profile_class_direction != 'both': + MSG = 'Site Network Access QoS Class Direction: {:s}' + raise NotImplementedError(MSG.format(str(qos_profile_class['direction']))) + + max_e2e_latency_ms = qos_profile_class['latency']['latency-boundary'] + availability = qos_profile_class['bandwidth']['guaranteed-bw-percent'] + + network_access_diversity = network_access.get('access-diversity', {}) + diversity_constraints = network_access_diversity.get('constraints', {}).get('constraint', []) + raise_if_differs = True + diversity_constraints = { + constraint['constraint-type']:([ + target[0] + for target in constraint['target'].items() + if len(target[1]) == 1 + ][0], raise_if_differs) + for constraint in diversity_constraints + } + + network_access_availability = network_access.get('availability', {}) + access_priority : Optional[int] = network_access_availability.get('access-priority') + single_active : bool = len(network_access_availability.get('single-active', [])) > 0 + all_active : bool = len(network_access_availability.get('all-active', [])) > 0 + + mapping = BEARER_MAPPINGS.get(bearer_reference) + if mapping is None: + msg = 'Specified Bearer({:s}) is not configured.' + raise Exception(msg.format(str(bearer_reference))) + ( + device_uuid, endpoint_uuid, router_id, route_dist, sub_if_index, + address_ip, address_prefix, remote_router, circuit_id + ) = mapping + + context_client = ContextClient() + service = get_service_by_uuid( + context_client, service_uuid, context_uuid=DEFAULT_CONTEXT_NAME, rw_copy=True + ) + if service is None: + raise Exception('VPN({:s}) not found in database'.format(str(service_uuid))) + + endpoint_ids = service.service_endpoint_ids + config_rules = service.service_config.config_rules + constraints = service.service_constraints + + endpoint_id = update_endpoint_ids(endpoint_ids, device_uuid, endpoint_uuid) + + update_constraint_endpoint_location(constraints, endpoint_id, region=site_id) + if access_priority is not None: + update_constraint_endpoint_priority(constraints, endpoint_id, access_priority) + if service_bandwidth_gbps is not None: + update_constraint_sla_capacity(constraints, service_bandwidth_gbps) + if max_e2e_latency_ms is not None: + update_constraint_sla_latency(constraints, max_e2e_latency_ms) + if availability is not None: + update_constraint_sla_availability(constraints, 1, True, availability) + if len(diversity_constraints) > 0: + update_constraint_custom_dict(constraints, 'diversity', diversity_constraints) + if single_active or all_active: + # assume 1 disjoint path per endpoint/location included in service + location_endpoints = {} + for constraint in constraints: + if constraint.WhichOneof('constraint') != 'endpoint_location': continue + str_endpoint_id = grpc_message_to_json_string(constraint.endpoint_location.endpoint_id) + str_location_id = grpc_message_to_json_string(constraint.endpoint_location.location) + location_endpoints.setdefault(str_location_id, set()).add(str_endpoint_id) + num_endpoints_per_location = {len(endpoints) for endpoints in location_endpoints.values()} + num_disjoint_paths = max(num_endpoints_per_location) + update_constraint_sla_availability(constraints, num_disjoint_paths, all_active, 0.0) + + service_settings_key = '/settings' + if service_mtu is None: service_mtu = DEFAULT_MTU + update_config_rule_custom(config_rules, service_settings_key, { + 'mtu' : (service_mtu, True), + #'address_families': (DEFAULT_ADDRESS_FAMILIES, True), + #'bgp_as' : (DEFAULT_BGP_AS, True), + #'bgp_route_target': (DEFAULT_BGP_ROUTE_TARGET, True), + }) + + #ENDPOINT_SETTINGS_KEY = '/device[{:s}]/endpoint[{:s}]/vlan[{:d}]/settings' + #endpoint_settings_key = ENDPOINT_SETTINGS_KEY.format(device_uuid, endpoint_uuid, cvlan_tag_id) + ENDPOINT_SETTINGS_KEY = '/device[{:s}]/endpoint[{:s}]/settings' + endpoint_settings_key = ENDPOINT_SETTINGS_KEY.format(device_uuid, endpoint_uuid) + field_updates = {} + if router_id is not None: field_updates['router_id' ] = (router_id, True) + if route_dist is not None: field_updates['route_distinguisher'] = (route_dist, True) + if sub_if_index is not None: field_updates['sub_interface_index'] = (sub_if_index, True) + if cvlan_tag_id is not None: field_updates['vlan_id' ] = (cvlan_tag_id, True) + if address_ip is not None: field_updates['address_ip' ] = (address_ip, True) + if address_prefix is not None: field_updates['address_prefix' ] = (address_prefix, True) + if remote_router is not None: field_updates['remote_router' ] = (remote_router, True) + if circuit_id is not None: field_updates['circuit_id' ] = (circuit_id, True) + update_config_rule_custom(config_rules, endpoint_settings_key, field_updates) + + service_client = ServiceClient() + service_client.UpdateService(service) + except Exception as exc: + LOGGER.exception('Unhandled Exception') + errors.append({'error': str(exc)}) + + +def process_site(site : Dict, errors : List[Dict]) -> None: + site_id = site['site-id'] + + # this change is made for ECOC2025 demo purposes + if site['management']['type'] != 'provider-managed': + # if site['management']['type'] == 'customer-managed': + MSG = 'Site Management Type: {:s}' + raise NotImplementedError(MSG.format(str(site['management']['type']))) + + network_accesses : List[Dict] = site['site-network-accesses']['site-network-access'] + for network_access in network_accesses: + process_site_network_access(site_id, network_access, errors) + +def update_vpn(site : Dict, errors : List[Dict]) -> None: + if site['management']['type'] != 'provider-managed': + MSG = 'Site Management Type: {:s}' + raise NotImplementedError(MSG.format(str(site['management']['type']))) + + network_accesses : List[Dict] = site['site-network-accesses']['site-network-access'] + for network_access in network_accesses: + update_site_network_access(network_access, errors) + +def update_site_network_access(network_access : Dict, errors : List[Dict]) -> None: + try: + site_network_access_type = network_access['site-network-access-type'] + site_network_access_type = site_network_access_type.replace('ietf-l2vpn-svc:', '') + if site_network_access_type != 'multipoint': + MSG = 'Site Network Access Type: {:s}' + msg = MSG.format(str(network_access['site-network-access-type'])) + raise NotImplementedError(msg) + + service_uuid = network_access['vpn-attachment']['vpn-id'] + + service_input_bandwidth = network_access['service']['svc-input-bandwidth'] + service_output_bandwidth = network_access['service']['svc-output-bandwidth'] + service_bandwidth_bps = max(service_input_bandwidth, service_output_bandwidth) + service_bandwidth_gbps = service_bandwidth_bps / 1.e9 + + max_e2e_latency_ms = None + availability = None + + context_client = ContextClient() + service = get_service_by_uuid( + context_client, service_uuid, context_uuid=DEFAULT_CONTEXT_NAME, rw_copy=True + ) + if service is None: + MSG = 'VPN({:s}) not found in database' + raise Exception(MSG.format(str(service_uuid))) + + constraints = service.service_constraints + if service_bandwidth_gbps is not None: + update_constraint_sla_capacity(constraints, service_bandwidth_gbps) + if max_e2e_latency_ms is not None: + update_constraint_sla_latency(constraints, max_e2e_latency_ms) + if availability is not None: + update_constraint_sla_availability(constraints, 1, True, availability) + + service_client = ServiceClient() + service_client.UpdateService(service) + except Exception as e: # pylint: disable=broad-except + LOGGER.exception('Unhandled exception updating Service') + errors.append({'error': str(e)}) diff --git a/src/nbi/service/ietf_l2vpn/L2VPN_Service.py b/src/nbi/service/ietf_l2vpn/L2VPN_Service.py index 1df6642ecfb1006d1c4491ab679c6d6f0428c44c..070a548b50c962fe1e8c0d0646f608658e435ca9 100644 --- a/src/nbi/service/ietf_l2vpn/L2VPN_Service.py +++ b/src/nbi/service/ietf_l2vpn/L2VPN_Service.py @@ -16,14 +16,18 @@ import logging from flask import request from flask.json import jsonify from flask_restful import Resource -from common.proto.context_pb2 import SliceStatusEnum -from common.tools.context_queries.Slice import get_slice_by_uuid +from common.proto.context_pb2 import ServiceStatusEnum, ServiceTypeEnum +from common.tools.context_queries.Service import get_service_by_uuid from context.client.ContextClient import ContextClient -from slice.client.SliceClient import SliceClient +from service.client.ServiceClient import ServiceClient +from typing import Dict, List +from werkzeug.exceptions import UnsupportedMediaType from nbi.service._tools.Authentication import HTTP_AUTH from nbi.service._tools.HttpStatusCodes import ( HTTP_GATEWAYTIMEOUT, HTTP_NOCONTENT, HTTP_OK, HTTP_SERVERERROR ) +from .Handlers import update_vpn +from .YangValidator import YangValidator LOGGER = logging.getLogger(__name__) @@ -36,17 +40,21 @@ class L2VPN_Service(Resource): try: context_client = ContextClient() - target = get_slice_by_uuid(context_client, vpn_id, rw_copy=True) + target = get_service_by_uuid(context_client, vpn_id, rw_copy=True) if target is None: raise Exception('VPN({:s}) not found in database'.format(str(vpn_id))) + + if target.service_type != ServiceTypeEnum.SERVICETYPE_L2NM: + raise Exception('VPN({:s}) is not L2VPN'.format(str(vpn_id))) - if target.slice_id.slice_uuid.uuid != vpn_id: # pylint: disable=no-member - raise Exception('Slice retrieval failed. Wrong Slice Id was returned') + service_ids = {target.service_id.service_uuid.uuid, target.name} # pylint: disable=no-member + if vpn_id not in service_ids: + raise Exception('Service retrieval failed. Wrong Service Id was returned') - slice_ready_status = SliceStatusEnum.SLICESTATUS_ACTIVE - slice_status = target.slice_status.slice_status # pylint: disable=no-member - response = jsonify({}) - response.status_code = HTTP_OK if slice_status == slice_ready_status else HTTP_GATEWAYTIMEOUT + service_ready_status = ServiceStatusEnum.SERVICESTATUS_ACTIVE + service_status = target.service_status.service_status # pylint: disable=no-member + response = jsonify({'service-id': target.service_id.service_uuid.uuid}) + response.status_code = HTTP_OK if service_status == service_ready_status else HTTP_GATEWAYTIMEOUT except Exception as e: # pylint: disable=broad-except LOGGER.exception('Something went wrong Retrieving VPN({:s})'.format(str(vpn_id))) response = jsonify({'error': str(e)}) @@ -61,14 +69,17 @@ class L2VPN_Service(Resource): try: context_client = ContextClient() - target = get_slice_by_uuid(context_client, vpn_id) + target = get_service_by_uuid(context_client, vpn_id) if target is None: LOGGER.warning('VPN({:s}) not found in database. Nothing done.'.format(str(vpn_id))) + elif target.service_type != ServiceTypeEnum.SERVICETYPE_L2NM: + raise Exception('VPN({:s}) is not L2VPN'.format(str(vpn_id))) else: - if target.slice_id.slice_uuid.uuid != vpn_id: # pylint: disable=no-member - raise Exception('Slice retrieval failed. Wrong Slice Id was returned') - slice_client = SliceClient() - slice_client.DeleteSlice(target.slice_id) + service_ids = {target.service_id.service_uuid.uuid, target.name} # pylint: disable=no-member + if vpn_id not in service_ids: + raise Exception('Service retrieval failed. Wrong Service Id was returned') + service_client = ServiceClient() + service_client.DeleteService(target.service_id) response = jsonify({}) response.status_code = HTTP_NOCONTENT except Exception as e: # pylint: disable=broad-except @@ -76,3 +87,37 @@ class L2VPN_Service(Resource): response = jsonify({'error': str(e)}) response.status_code = HTTP_SERVERERROR return response + + def put(self, vpn_id : str): + #TODO: check vpn_id with request service_id in body + if not request.is_json: raise UnsupportedMediaType('JSON payload is required') + request_data: Dict = request.json + LOGGER.debug('PUT Request: {:s}'.format(str(request_data))) + + errors = list() + + if 'ietf-l2vpn-svc:l2vpn-services' in request_data: + for l2vpn_svc in request_data['ietf-l2vpn-svc:l2vpn-services']['l2vpn-svc']: + l2vpn_svc.pop('service-id', None) + l2vpn_svc_request_data = {'ietf-l2vpn-svc:l2vpn-svc': l2vpn_svc} + errors.extend(self._update_l2vpn(l2vpn_svc_request_data)) + elif 'ietf-l2vpn-svc:l2vpn-svc' in request_data: + errors.extend(self._update_l2vpn(request_data)) + else: + errors.append('Unexpected request format: {:s}'.format(str(request_data))) + + response = jsonify(errors) + response.status_code = HTTP_NOCONTENT if len(errors) == 0 else HTTP_SERVERERROR + return response + + def _update_l2vpn(self, request_data: Dict) -> List[Dict]: + yang_validator = YangValidator('ietf-l2vpn-svc') + request_data = yang_validator.parse_to_dict(request_data) + yang_validator.destroy() + + errors = list() + + for site in request_data['l2vpn-svc']['sites']['site']: + update_vpn(site, errors) + + return errors diff --git a/src/nbi/service/ietf_l2vpn/L2VPN_Services.py b/src/nbi/service/ietf_l2vpn/L2VPN_Services.py index a760bfd3a5f324757b376196aa251a48529116a4..ccdad5c547c9e564cd96e54ad524b5c0a12f70ec 100644 --- a/src/nbi/service/ietf_l2vpn/L2VPN_Services.py +++ b/src/nbi/service/ietf_l2vpn/L2VPN_Services.py @@ -18,13 +18,10 @@ from flask import request from flask.json import jsonify from flask_restful import Resource from werkzeug.exceptions import UnsupportedMediaType -from common.Constants import DEFAULT_CONTEXT_NAME -from common.proto.context_pb2 import SliceStatusEnum, Slice -from slice.client.SliceClient import SliceClient -from nbi.service._tools.HttpStatusCodes import HTTP_CREATED, HTTP_SERVERERROR -from nbi.service._tools.Validator import validate_message from nbi.service._tools.Authentication import HTTP_AUTH -from .schemas.vpn_service import SCHEMA_VPN_SERVICE +from nbi.service._tools.HttpStatusCodes import HTTP_CREATED, HTTP_SERVERERROR +from .Handlers import process_site, process_vpn_service +from .YangValidator import YangValidator LOGGER = logging.getLogger(__name__) @@ -38,24 +35,72 @@ class L2VPN_Services(Resource): if not request.is_json: raise UnsupportedMediaType('JSON payload is required') request_data : Dict = request.json LOGGER.debug('Request: {:s}'.format(str(request_data))) - validate_message(SCHEMA_VPN_SERVICE, request_data) - vpn_services : List[Dict] = request_data['ietf-l2vpn-svc:vpn-service'] - for vpn_service in vpn_services: - try: - # pylint: disable=no-member - slice_request = Slice() - slice_request.slice_id.context_id.context_uuid.uuid = DEFAULT_CONTEXT_NAME - slice_request.slice_id.slice_uuid.uuid = vpn_service['vpn-id'] - slice_request.slice_status.slice_status = SliceStatusEnum.SLICESTATUS_PLANNED - - slice_client = SliceClient() - slice_client.CreateSlice(slice_request) - - response = jsonify({}) - response.status_code = HTTP_CREATED - except Exception as e: # pylint: disable=broad-except - LOGGER.exception('Something went wrong Creating Service {:s}'.format(str(request))) - response = jsonify({'error': str(e)}) - response.status_code = HTTP_SERVERERROR + errors = list() + if 'ietf-l2vpn-svc:l2vpn-svc' in request_data: + # processing single (standard) request formatted as: + #{ + # "ietf-l2vpn-svc:l2vpn-svc": { + # "vpn-services": { + # "vpn-service": [ + errors.extend(self._process_l2vpn(request_data)) + elif 'ietf-l2vpn-svc:vpn-service' in request_data: + # processing OSM-style payload request formatted as: + #{ + # "ietf-l2vpn-svc:vpn-service": [ + vpn_services = request_data['ietf-l2vpn-svc:vpn-service'] + + # Add mandatory fields OSM RO driver skips + for vpn_service in vpn_services: + if 'ce-vlan-preservation' not in vpn_service: + vpn_service['ce-vlan-preservation'] = True + if 'ce-vlan-cos-preservation' not in vpn_service: + vpn_service['ce-vlan-cos-preservation'] = True + if 'frame-delivery' not in vpn_service: + vpn_service['frame-delivery'] = dict() + if 'multicast-gp-port-mapping' not in vpn_service['frame-delivery']: + vpn_service['frame-delivery']['multicast-gp-port-mapping'] = \ + 'ietf-l2vpn-svc:static-mapping' + + request_data = { + 'ietf-l2vpn-svc:l2vpn-svc': { + 'vpn-services': { + 'vpn-service': vpn_services + } + } + } + errors.extend(self._process_l2vpn(request_data)) + else: + errors.append('Unexpected request: {:s}'.format(str(request_data))) + + if len(errors) > 0: + LOGGER.error('Errors: {:s}'.format(str(errors))) + + response = jsonify(errors) + response.status_code = HTTP_CREATED if len(errors) == 0 else HTTP_SERVERERROR return response + + def _process_l2vpn(self, request_data : Dict) -> List[Dict]: + yang_validator = YangValidator('ietf-l2vpn-svc') + request_data = yang_validator.parse_to_dict(request_data) + yang_validator.destroy() + + errors = list() + + vpn_services = ( + request_data.get('l2vpn-svc', dict()) + .get('vpn-services', dict()) + .get('vpn-service', list()) + ) + for vpn_service in vpn_services: + process_vpn_service(vpn_service, errors) + + sites = ( + request_data.get('l2vpn-svc', dict()) + .get('sites', dict()) + .get('site', list()) + ) + for site in sites: + process_site(site, errors) + + return errors diff --git a/src/nbi/service/ietf_l2vpn/L2VPN_SiteNetworkAccesses.py b/src/nbi/service/ietf_l2vpn/L2VPN_SiteNetworkAccesses.py index fed366d1bd5c38336ea28b01d5eec1cfa1dddcdc..eb0f246e6f3bd8bcf7278c3d4eb43c6da24ed73a 100644 --- a/src/nbi/service/ietf_l2vpn/L2VPN_SiteNetworkAccesses.py +++ b/src/nbi/service/ietf_l2vpn/L2VPN_SiteNetworkAccesses.py @@ -13,144 +13,157 @@ # limitations under the License. import logging -from typing import Dict, Optional +from typing import Dict, List from flask import request from flask.json import jsonify -from flask.wrappers import Response from flask_restful import Resource from werkzeug.exceptions import UnsupportedMediaType -from common.proto.context_pb2 import Slice -from common.tools.context_queries.Slice import get_slice_by_uuid -from common.tools.grpc.ConfigRules import update_config_rule_custom -from common.tools.grpc.Constraints import ( - update_constraint_custom_dict, update_constraint_endpoint_location, update_constraint_endpoint_priority, - update_constraint_sla_availability) -from common.tools.grpc.EndPointIds import update_endpoint_ids -from common.tools.grpc.Tools import grpc_message_to_json_string +from common.proto.context_pb2 import ServiceTypeEnum +from common.tools.context_queries.Service import get_services from context.client.ContextClient import ContextClient -from slice.client.SliceClient import SliceClient from nbi.service._tools.Authentication import HTTP_AUTH -from nbi.service._tools.HttpStatusCodes import HTTP_NOCONTENT, HTTP_SERVERERROR -from nbi.service._tools.Validator import validate_message -from .schemas.site_network_access import SCHEMA_SITE_NETWORK_ACCESS -from .Constants import BEARER_MAPPINGS, DEFAULT_ADDRESS_FAMILIES, DEFAULT_BGP_AS, DEFAULT_BGP_ROUTE_TARGET, DEFAULT_MTU +from nbi.service._tools.HttpStatusCodes import ( + HTTP_CREATED, HTTP_NOCONTENT, HTTP_SERVERERROR +) +from .Handlers import process_site_network_access +from .YangValidator import YangValidator LOGGER = logging.getLogger(__name__) -def process_site_network_access(context_client : ContextClient, site_id : str, site_network_access : Dict) -> Slice: - vpn_id = site_network_access['vpn-attachment']['vpn-id'] - encapsulation_type = site_network_access['connection']['encapsulation-type'] - cvlan_id = site_network_access['connection']['tagged-interface'][encapsulation_type]['cvlan-id'] - - bearer_reference = site_network_access['bearer']['bearer-reference'] - - access_priority : Optional[int] = site_network_access.get('availability', {}).get('access-priority') - single_active : bool = len(site_network_access.get('availability', {}).get('single-active', [])) > 0 - all_active : bool = len(site_network_access.get('availability', {}).get('all-active', [])) > 0 - - diversity_constraints = site_network_access.get('access-diversity', {}).get('constraints', {}).get('constraint', []) - raise_if_differs = True - diversity_constraints = { - constraint['constraint-type']:([ - target[0] - for target in constraint['target'].items() - if len(target[1]) == 1 - ][0], raise_if_differs) - for constraint in diversity_constraints - } - - mapping = BEARER_MAPPINGS.get(bearer_reference) - if mapping is None: - msg = 'Specified Bearer({:s}) is not configured.' - raise Exception(msg.format(str(bearer_reference))) - ( - device_uuid, endpoint_uuid, router_id, route_dist, sub_if_index, - address_ip, address_prefix, remote_router, circuit_id - ) = mapping - - target = get_slice_by_uuid(context_client, vpn_id, rw_copy=True) - if target is None: raise Exception('VPN({:s}) not found in database'.format(str(vpn_id))) - - endpoint_ids = target.slice_endpoint_ids # pylint: disable=no-member - config_rules = target.slice_config.config_rules # pylint: disable=no-member - constraints = target.slice_constraints # pylint: disable=no-member - - endpoint_id = update_endpoint_ids(endpoint_ids, device_uuid, endpoint_uuid) - - service_settings_key = '/settings' - update_config_rule_custom(config_rules, service_settings_key, { - 'mtu' : (DEFAULT_MTU, True), - 'address_families': (DEFAULT_ADDRESS_FAMILIES, True), - 'bgp_as' : (DEFAULT_BGP_AS, True), - 'bgp_route_target': (DEFAULT_BGP_ROUTE_TARGET, True), - }) - - endpoint_settings_key = '/device[{:s}]/endpoint[{:s}]/settings'.format(device_uuid, endpoint_uuid) - field_updates = {} - if router_id is not None: field_updates['router_id' ] = (router_id, True) - if route_dist is not None: field_updates['route_distinguisher'] = (route_dist, True) - if sub_if_index is not None: field_updates['sub_interface_index'] = (sub_if_index, True) - if cvlan_id is not None: field_updates['vlan_id' ] = (cvlan_id, True) - if address_ip is not None: field_updates['address_ip' ] = (address_ip, True) - if address_prefix is not None: field_updates['address_prefix' ] = (address_prefix, True) - if remote_router is not None: field_updates['remote_router' ] = (remote_router, True) - if circuit_id is not None: field_updates['circuit_id' ] = (circuit_id, True) - update_config_rule_custom(config_rules, endpoint_settings_key, field_updates) - - if len(diversity_constraints) > 0: - update_constraint_custom_dict(constraints, 'diversity', diversity_constraints) - - update_constraint_endpoint_location(constraints, endpoint_id, region=site_id) - if access_priority is not None: update_constraint_endpoint_priority(constraints, endpoint_id, access_priority) - if single_active or all_active: - # assume 1 disjoint path per endpoint/location included in service/slice - location_endpoints = {} - for constraint in constraints: - if constraint.WhichOneof('constraint') != 'endpoint_location': continue - str_endpoint_id = grpc_message_to_json_string(constraint.endpoint_location.endpoint_id) - str_location_id = grpc_message_to_json_string(constraint.endpoint_location.location) - location_endpoints.setdefault(str_location_id, set()).add(str_endpoint_id) - num_endpoints_per_location = {len(endpoints) for endpoints in location_endpoints.values()} - num_disjoint_paths = max(num_endpoints_per_location) - update_constraint_sla_availability(constraints, num_disjoint_paths, all_active, 0.0) - - return target - -def process_list_site_network_access( - context_client : ContextClient, slice_client : SliceClient, site_id : str, request_data : Dict - ) -> Response: - - LOGGER.debug('Request: {:s}'.format(str(request_data))) - validate_message(SCHEMA_SITE_NETWORK_ACCESS, request_data) - - errors = [] - for site_network_access in request_data['ietf-l2vpn-svc:site-network-access']: - sna_request = process_site_network_access(context_client, site_id, site_network_access) - LOGGER.debug('sna_request = {:s}'.format(grpc_message_to_json_string(sna_request))) - try: - slice_client.UpdateSlice(sna_request) - except Exception as e: # pylint: disable=broad-except - msg = 'Something went wrong Updating VPN {:s}' - LOGGER.exception(msg.format(grpc_message_to_json_string(sna_request))) - errors.append({'error': str(e)}) - - response = jsonify(errors) - response.status_code = HTTP_NOCONTENT if len(errors) == 0 else HTTP_SERVERERROR - return response - class L2VPN_SiteNetworkAccesses(Resource): @HTTP_AUTH.login_required def post(self, site_id : str): if not request.is_json: raise UnsupportedMediaType('JSON payload is required') + request_data : Dict = request.json LOGGER.debug('Site_Id: {:s}'.format(str(site_id))) - context_client = ContextClient() - slice_client = SliceClient() - return process_list_site_network_access(context_client, slice_client, site_id, request.json) + LOGGER.debug('Request: {:s}'.format(str(request_data))) + errors = self._process_site_network_accesses(site_id, request_data) + response = jsonify(errors) + response.status_code = HTTP_CREATED if len(errors) == 0 else HTTP_SERVERERROR + return response @HTTP_AUTH.login_required def put(self, site_id : str): if not request.is_json: raise UnsupportedMediaType('JSON payload is required') + request_data : Dict = request.json LOGGER.debug('Site_Id: {:s}'.format(str(site_id))) - context_client = ContextClient() - slice_client = SliceClient() - return process_list_site_network_access(context_client, slice_client, site_id, request.json) + LOGGER.debug('Request: {:s}'.format(str(request_data))) + errors = self._process_site_network_accesses(site_id, request_data) + response = jsonify(errors) + response.status_code = HTTP_NOCONTENT if len(errors) == 0 else HTTP_SERVERERROR + return response + + def _prepare_request_payload(self, site_id : str, request_data : Dict, errors : List[Dict]) -> Dict: + if 'ietf-l2vpn-svc:l2vpn-svc' in request_data: + # processing single (standard) request formatted as: + #{"ietf-l2vpn-svc:l2vpn-svc": { + # "sites": {"site": [ + # { + # "site-id": ..., + # "site-network-accesses": {"site-network-access": [ + # { + # "network-access-id": ..., + # ... + # } + # ]} + # } + # ]} + #}} + return request_data + + if 'ietf-l2vpn-svc:site-network-access' in request_data: + # processing OSM-style payload request formatted as: + #{ + # "ietf-l2vpn-svc:site-network-access": [ + site_network_accesses = request_data['ietf-l2vpn-svc:site-network-access'] + + location_refs = set() + location_refs.add('fake-location') + + # Add mandatory fields OSM RO driver skips and fix wrong ones + for site_network_access in site_network_accesses: + if 'location-reference' in site_network_access: + location_refs.add(site_network_access['location-reference']) + else: + site_network_access['location-reference'] = 'fake-location' + + if 'connection' in site_network_access: + connection = site_network_access['connection'] + if 'encapsulation-type' in connection: + if connection['encapsulation-type'] == 'dot1q-vlan-tagged': + connection['encapsulation-type'] = 'vlan' + else: + connection['encapsulation-type'] = 'ethernet' + if 'tagged-interface' in connection: + tagged_interface = connection['tagged-interface'] + if 'dot1q-vlan-tagged' in tagged_interface: + if 'type' not in tagged_interface: + tagged_interface['type'] = 'dot1q' + + if 'oam' not in connection: + connection['oam'] = dict() + if 'md-name' not in connection['oam']: + connection['oam']['md-name'] = 'fake-md-name' + if 'md-level' not in connection['oam']: + connection['oam']['md-level'] = 0 + + if 'service' not in site_network_access: + site_network_access['service'] = dict() + if 'svc-mtu' not in site_network_access['service']: + site_network_access['service']['svc-mtu'] = 1500 + + context_client = ContextClient() + vpn_services = list() + for service in get_services(context_client): + if service.service_type != ServiceTypeEnum.SERVICETYPE_L2NM: continue + + vpn_ids = [service.service_id.service_uuid.uuid, service.name] + for vpn_id in vpn_ids: + vpn_services.append({ + 'vpn-id': vpn_id, + 'frame-delivery': { + 'multicast-gp-port-mapping': 'ietf-l2vpn-svc:static-mapping' + }, + 'ce-vlan-preservation': True, + 'ce-vlan-cos-preservation': True, + }) + + request_data = {'ietf-l2vpn-svc:l2vpn-svc': { + 'vpn-services': { + 'vpn-service': vpn_services + }, + 'sites': {'site': [{ + 'site-id': site_id, + 'default-ce-vlan-id': 1, + 'management': {'type': 'customer-managed'}, + 'locations': {'location': [ + {'location-id': location_ref} + for location_ref in location_refs + ]}, + 'site-network-accesses': { + 'site-network-access': site_network_accesses + } + }]} + }} + return request_data + + errors.append('Unexpected request: {:s}'.format(str(request_data))) + return None + + def _process_site_network_accesses(self, site_id : str, request_data : Dict) -> List[Dict]: + errors = list() + request_data = self._prepare_request_payload(site_id, request_data, errors) + if len(errors) > 0: return errors + + yang_validator = YangValidator('ietf-l2vpn-svc') + request_data = yang_validator.parse_to_dict(request_data) + yang_validator.destroy() + + site_network_accesses = ( + request_data.get('site-network-accesses', dict()) + .get('site-network-access', list()) + ) + for site_network_access in site_network_accesses: + process_site_network_access(site_id, site_network_access, errors) + + return errors diff --git a/src/nbi/service/ietf_l2vpn/YangValidator.py b/src/nbi/service/ietf_l2vpn/YangValidator.py new file mode 100644 index 0000000000000000000000000000000000000000..82bd799a7e21936317b7beb7c7eb0b55fc2720b7 --- /dev/null +++ b/src/nbi/service/ietf_l2vpn/YangValidator.py @@ -0,0 +1,36 @@ +# Copyright 2022-2025 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 libyang, os +from typing import Dict, Optional + +YANG_DIR = os.path.join(os.path.dirname(__file__), 'yang') + +class YangValidator: + def __init__(self, module_name : str) -> None: + self._yang_context = libyang.Context(YANG_DIR) + self._yang_module = self._yang_context.load_module(module_name) + self._yang_module.feature_enable_all() + + def parse_to_dict(self, message : Dict) -> Dict: + dnode : Optional[libyang.DNode] = self._yang_module.parse_data_dict( + message, validate_present=True, validate=True, strict=True + ) + if dnode is None: raise Exception('Unable to parse Message({:s})'.format(str(message))) + message = dnode.print_dict() + dnode.free() + return message + + def destroy(self) -> None: + self._yang_context.destroy() diff --git a/src/nbi/service/ietf_l2vpn/__init__.py b/src/nbi/service/ietf_l2vpn/__init__.py index da76897786930d1bea45b8139fbc04fd9e3991d4..dfc52da8b5a022bb951a2dd389a0451b11b541b0 100644 --- a/src/nbi/service/ietf_l2vpn/__init__.py +++ b/src/nbi/service/ietf_l2vpn/__init__.py @@ -25,15 +25,15 @@ URL_PREFIX = '/restconf/data/ietf-l2vpn-svc:l2vpn-svc' def register_ietf_l2vpn(nbi_app : NbiApplication): nbi_app.add_rest_api_resource( L2VPN_Services, - URL_PREFIX + '/vpn-services' + URL_PREFIX + '/vpn-services', ) nbi_app.add_rest_api_resource( L2VPN_Service, URL_PREFIX + '/vpn-services/vpn-service=', - URL_PREFIX + '/vpn-services/vpn-service=/' + URL_PREFIX + '/vpn-services/vpn-service=/', ) nbi_app.add_rest_api_resource( L2VPN_SiteNetworkAccesses, URL_PREFIX + '/sites/site=/site-network-accesses', - URL_PREFIX + '/sites/site=/site-network-accesses/' + URL_PREFIX + '/sites/site=/site-network-accesses/', ) diff --git a/src/nbi/service/ietf_l2vpn/schemas/Common.py b/src/nbi/service/ietf_l2vpn/schemas/Common.py deleted file mode 100644 index b18c54a0c58f247e60f8985985fabc2a411fdd36..0000000000000000000000000000000000000000 --- a/src/nbi/service/ietf_l2vpn/schemas/Common.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2022-2025 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. - -# String pattern for UUIDs such as '3fd942ee-2dc3-41d1-aeec-65aa85d117b2' -REGEX_UUID = r'[a-fA-F0-9]{8}\-[a-fA-F0-9]{4}\-[a-fA-F0-9]{4}\-[a-fA-F0-9]{4}\-[a-fA-F0-9]{12}' diff --git a/src/nbi/service/ietf_l2vpn/schemas/__init__.py b/src/nbi/service/ietf_l2vpn/schemas/__init__.py deleted file mode 100644 index 3ccc21c7db78aac26daa1f8c5ff8e1ffd3f35460..0000000000000000000000000000000000000000 --- a/src/nbi/service/ietf_l2vpn/schemas/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright 2022-2025 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. - diff --git a/src/nbi/service/ietf_l2vpn/schemas/site_network_access.py b/src/nbi/service/ietf_l2vpn/schemas/site_network_access.py deleted file mode 100644 index c37c20dba162ea9ba3e0e163164de1ff2c770d73..0000000000000000000000000000000000000000 --- a/src/nbi/service/ietf_l2vpn/schemas/site_network_access.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2022-2025 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. - -# Example request: -# request = {'ietf-l2vpn-svc:site-network-access': [{ -# 'network-access-id': '3fd942ee-2dc3-41d1-aeec-65aa85d117b2', -# 'vpn-attachment': {'vpn-id': '954b1b53-4a8c-406d-9eff-750ec2c9a258', -# 'site-role': 'any-to-any-role'}, -# 'connection': {'encapsulation-type': 'dot1q-vlan-tagged', 'tagged-interface': { -# 'dot1q-vlan-tagged': {'cvlan-id': 1234}}}, -# 'bearer': {'bearer-reference': '1a'} -# }]} - -from .Common import REGEX_UUID - -SCHEMA_SITE_NETWORK_ACCESS = { - '$schema': 'https://json-schema.org/draft/2020-12/schema', - 'type': 'object', - 'required': ['ietf-l2vpn-svc:site-network-access'], - 'properties': { - 'ietf-l2vpn-svc:site-network-access': { - 'type': 'array', - 'minItems': 1, - 'maxItems': 1, # by now we do not support multiple site-network-access in the same message - 'items': { - 'type': 'object', - 'required': ['network-access-id', 'vpn-attachment', 'connection', 'bearer'], - 'properties': { - 'network-access-id': {'type': 'string', 'pattern': REGEX_UUID}, - 'vpn-attachment': { - 'type': 'object', - 'required': ['vpn-id', 'site-role'], - 'properties': { - 'vpn-id': {'type': 'string', 'pattern': REGEX_UUID}, - 'site-role': {'type': 'string', 'minLength': 1}, - }, - }, - 'connection': { - 'type': 'object', - 'required': ['encapsulation-type', 'tagged-interface'], - 'properties': { - 'encapsulation-type': {'enum': ['dot1q-vlan-tagged']}, - 'tagged-interface': { - 'type': 'object', - 'required': ['dot1q-vlan-tagged'], - 'properties': { - 'dot1q-vlan-tagged': { - 'type': 'object', - 'required': ['cvlan-id'], - 'properties': { - 'cvlan-id': {'type': 'integer', 'minimum': 1, 'maximum': 4094}, - }, - }, - }, - }, - }, - }, - 'bearer': { - 'type': 'object', - 'required': ['bearer-reference'], - 'properties': { - 'bearer-reference': {'type': 'string', 'minLength': 1}, - }, - }, - }, - }, - }, - }, -} diff --git a/src/nbi/service/ietf_l2vpn/schemas/vpn_service.py b/src/nbi/service/ietf_l2vpn/schemas/vpn_service.py deleted file mode 100644 index 87321b88b4b7bf4f9d66c2032df88aa7bd879ad5..0000000000000000000000000000000000000000 --- a/src/nbi/service/ietf_l2vpn/schemas/vpn_service.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2022-2025 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. - -# Example request: -# request = {'ietf-l2vpn-svc:vpn-service': [{ -# 'vpn-id': 'c6270231-f1de-4687-b2ed-7b58f9105775', -# 'vpn-svc-type': 'vpws', -# 'svc-topo': 'any-to-any', -# 'customer-name': 'osm' -# }]} - -from .Common import REGEX_UUID - -SCHEMA_VPN_SERVICE = { - '$schema': 'https://json-schema.org/draft/2020-12/schema', - 'type': 'object', - 'required': ['ietf-l2vpn-svc:vpn-service'], - 'properties': { - 'ietf-l2vpn-svc:vpn-service': { - 'type': 'array', - 'minItems': 1, - 'maxItems': 1, # by now we do not support multiple vpn-service in the same message - 'items': { - 'type': 'object', - 'required': ['vpn-id', 'vpn-svc-type', 'svc-topo', 'customer-name'], - 'properties': { - 'vpn-id': {'type': 'string', 'pattern': REGEX_UUID}, - 'vpn-svc-type': {'enum': ['vpws', 'vpls']}, - 'svc-topo': {'enum': ['any-to-any']}, - 'customer-name': {'const': 'osm'}, - }, - } - } - }, -} diff --git a/src/nbi/service/ietf_l2vpn/yang/ietf-inet-types@2013-07-15.yang b/src/nbi/service/ietf_l2vpn/yang/ietf-inet-types@2013-07-15.yang new file mode 100644 index 0000000000000000000000000000000000000000..790bafc31dd7dc3582ef1c765fe104145b8a6016 --- /dev/null +++ b/src/nbi/service/ietf_l2vpn/yang/ietf-inet-types@2013-07-15.yang @@ -0,0 +1,459 @@ + module ietf-inet-types { + + namespace "urn:ietf:params:xml:ns:yang:ietf-inet-types"; + prefix "inet"; + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: David Kessens + + + WG Chair: Juergen Schoenwaelder + + + Editor: Juergen Schoenwaelder + "; + + description + "This module contains a collection of generally useful derived + YANG data types for Internet addresses and related things. + + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6991; see + the RFC itself for full legal notices."; + + revision 2013-07-15 { + description + "This revision adds the following new data types: + - ip-address-no-zone + - ipv4-address-no-zone + - ipv6-address-no-zone"; + reference + "RFC 6991: Common YANG Data Types"; + } + + revision 2010-09-24 { + description + "Initial revision."; + reference + "RFC 6021: Common YANG Data Types"; + } + + /*** collection of types related to protocol fields ***/ + + typedef ip-version { + type enumeration { + enum unknown { + value "0"; + description + "An unknown or unspecified version of the Internet + protocol."; + } + enum ipv4 { + value "1"; + description + "The IPv4 protocol as defined in RFC 791."; + } + enum ipv6 { + value "2"; + description + "The IPv6 protocol as defined in RFC 2460."; + } + } + description + "This value represents the version of the IP protocol. + + In the value set and its semantics, this type is equivalent + to the InetVersion textual convention of the SMIv2."; + reference + "RFC 791: Internet Protocol + RFC 2460: Internet Protocol, Version 6 (IPv6) Specification + RFC 4001: Textual Conventions for Internet Network Addresses"; + } + + typedef dscp { + type uint8 { + range "0..63"; + } + description + "The dscp type represents a Differentiated Services Code Point + that may be used for marking packets in a traffic stream. + + In the value set and its semantics, this type is equivalent + to the Dscp textual convention of the SMIv2."; + reference + "RFC 3289: Management Information Base for the Differentiated + Services Architecture + RFC 2474: Definition of the Differentiated Services Field + (DS Field) in the IPv4 and IPv6 Headers + RFC 2780: IANA Allocation Guidelines For Values In + the Internet Protocol and Related Headers"; + } + + typedef ipv6-flow-label { + type uint32 { + range "0..1048575"; + } + description + "The ipv6-flow-label type represents the flow identifier or Flow + Label in an IPv6 packet header that may be used to + discriminate traffic flows. + + In the value set and its semantics, this type is equivalent + to the IPv6FlowLabel textual convention of the SMIv2."; + reference + "RFC 3595: Textual Conventions for IPv6 Flow Label + RFC 2460: Internet Protocol, Version 6 (IPv6) Specification"; + } + + typedef port-number { + type uint16 { + range "0..65535"; + } + description + "The port-number type represents a 16-bit port number of an + Internet transport-layer protocol such as UDP, TCP, DCCP, or + SCTP. Port numbers are assigned by IANA. A current list of + all assignments is available from . + + Note that the port number value zero is reserved by IANA. In + situations where the value zero does not make sense, it can + be excluded by subtyping the port-number type. + In the value set and its semantics, this type is equivalent + to the InetPortNumber textual convention of the SMIv2."; + reference + "RFC 768: User Datagram Protocol + RFC 793: Transmission Control Protocol + RFC 4960: Stream Control Transmission Protocol + RFC 4340: Datagram Congestion Control Protocol (DCCP) + RFC 4001: Textual Conventions for Internet Network Addresses"; + } + + /*** collection of types related to autonomous systems ***/ + + typedef as-number { + type uint32; + description + "The as-number type represents autonomous system numbers + which identify an Autonomous System (AS). An AS is a set + of routers under a single technical administration, using + an interior gateway protocol and common metrics to route + packets within the AS, and using an exterior gateway + protocol to route packets to other ASes. IANA maintains + the AS number space and has delegated large parts to the + regional registries. + + Autonomous system numbers were originally limited to 16 + bits. BGP extensions have enlarged the autonomous system + number space to 32 bits. This type therefore uses an uint32 + base type without a range restriction in order to support + a larger autonomous system number space. + + In the value set and its semantics, this type is equivalent + to the InetAutonomousSystemNumber textual convention of + the SMIv2."; + reference + "RFC 1930: Guidelines for creation, selection, and registration + of an Autonomous System (AS) + RFC 4271: A Border Gateway Protocol 4 (BGP-4) + RFC 4001: Textual Conventions for Internet Network Addresses + RFC 6793: BGP Support for Four-Octet Autonomous System (AS) + Number Space"; + } + + /*** collection of types related to IP addresses and hostnames ***/ + + typedef ip-address { + type union { + type inet:ipv4-address; + type inet:ipv6-address; + } + description + "The ip-address type represents an IP address and is IP + version neutral. The format of the textual representation + implies the IP version. This type supports scoped addresses + by allowing zone identifiers in the address format."; + reference + "RFC 4007: IPv6 Scoped Address Architecture"; + } + + typedef ipv4-address { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])' + + '(%[\p{N}\p{L}]+)?'; + } + description + "The ipv4-address type represents an IPv4 address in + dotted-quad notation. The IPv4 address may include a zone + index, separated by a % sign. + + The zone index is used to disambiguate identical address + values. For link-local addresses, the zone index will + typically be the interface index number or the name of an + interface. If the zone index is not present, the default + zone of the device will be used. + + The canonical format for the zone index is the numerical + format"; + } + + typedef ipv6-address { + type string { + pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}' + + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|' + + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}' + + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))' + + '(%[\p{N}\p{L}]+)?'; + pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|' + + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)' + + '(%.+)?'; + } + description + "The ipv6-address type represents an IPv6 address in full, + mixed, shortened, and shortened-mixed notation. The IPv6 + address may include a zone index, separated by a % sign. + + The zone index is used to disambiguate identical address + values. For link-local addresses, the zone index will + typically be the interface index number or the name of an + interface. If the zone index is not present, the default + zone of the device will be used. + + The canonical format of IPv6 addresses uses the textual + representation defined in Section 4 of RFC 5952. The + canonical format for the zone index is the numerical + format as described in Section 11.2 of RFC 4007."; + reference + "RFC 4291: IP Version 6 Addressing Architecture + RFC 4007: IPv6 Scoped Address Architecture + RFC 5952: A Recommendation for IPv6 Address Text + Representation"; + } + + typedef ip-address-no-zone { + type union { + type inet:ipv4-address-no-zone; + type inet:ipv6-address-no-zone; + } + description + "The ip-address-no-zone type represents an IP address and is + IP version neutral. The format of the textual representation + implies the IP version. This type does not support scoped + addresses since it does not allow zone identifiers in the + address format."; + reference + "RFC 4007: IPv6 Scoped Address Architecture"; + } + + typedef ipv4-address-no-zone { + type inet:ipv4-address { + pattern '[0-9\.]*'; + } + description + "An IPv4 address without a zone index. This type, derived from + ipv4-address, may be used in situations where the zone is + known from the context and hence no zone index is needed."; + } + + typedef ipv6-address-no-zone { + type inet:ipv6-address { + pattern '[0-9a-fA-F:\.]*'; + } + description + "An IPv6 address without a zone index. This type, derived from + ipv6-address, may be used in situations where the zone is + known from the context and hence no zone index is needed."; + reference + "RFC 4291: IP Version 6 Addressing Architecture + RFC 4007: IPv6 Scoped Address Architecture + RFC 5952: A Recommendation for IPv6 Address Text + Representation"; + } + + typedef ip-prefix { + type union { + type inet:ipv4-prefix; + type inet:ipv6-prefix; + } + description + "The ip-prefix type represents an IP prefix and is IP + version neutral. The format of the textual representations + implies the IP version."; + } + + typedef ipv4-prefix { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])' + + '/(([0-9])|([1-2][0-9])|(3[0-2]))'; + } + description + "The ipv4-prefix type represents an IPv4 address prefix. + The prefix length is given by the number following the + slash character and must be less than or equal to 32. + + A prefix length value of n corresponds to an IP address + mask that has n contiguous 1-bits from the most + significant bit (MSB) and all other bits set to 0. + + The canonical format of an IPv4 prefix has all bits of + the IPv4 address set to zero that are not part of the + IPv4 prefix."; + } + + typedef ipv6-prefix { + type string { + pattern '((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}' + + '((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|' + + '(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\.){3}' + + '(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))' + + '(/(([0-9])|([0-9]{2})|(1[0-1][0-9])|(12[0-8])))'; + pattern '(([^:]+:){6}(([^:]+:[^:]+)|(.*\..*)))|' + + '((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)' + + '(/.+)'; + } + + description + "The ipv6-prefix type represents an IPv6 address prefix. + The prefix length is given by the number following the + slash character and must be less than or equal to 128. + + A prefix length value of n corresponds to an IP address + mask that has n contiguous 1-bits from the most + significant bit (MSB) and all other bits set to 0. + + The IPv6 address should have all bits that do not belong + to the prefix set to zero. + + The canonical format of an IPv6 prefix has all bits of + the IPv6 address set to zero that are not part of the + IPv6 prefix. Furthermore, the IPv6 address is represented + as defined in Section 4 of RFC 5952."; + reference + "RFC 5952: A Recommendation for IPv6 Address Text + Representation"; + } + + /*** collection of domain name and URI types ***/ + + typedef domain-name { + type string { + pattern + '((([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.)*' + + '([a-zA-Z0-9_]([a-zA-Z0-9\-_]){0,61})?[a-zA-Z0-9]\.?)' + + '|\.'; + length "1..253"; + } + description + "The domain-name type represents a DNS domain name. The + name SHOULD be fully qualified whenever possible. + + Internet domain names are only loosely specified. Section + 3.5 of RFC 1034 recommends a syntax (modified in Section + 2.1 of RFC 1123). The pattern above is intended to allow + for current practice in domain name use, and some possible + future expansion. It is designed to hold various types of + domain names, including names used for A or AAAA records + (host names) and other records, such as SRV records. Note + that Internet host names have a stricter syntax (described + in RFC 952) than the DNS recommendations in RFCs 1034 and + 1123, and that systems that want to store host names in + schema nodes using the domain-name type are recommended to + adhere to this stricter standard to ensure interoperability. + + The encoding of DNS names in the DNS protocol is limited + to 255 characters. Since the encoding consists of labels + prefixed by a length bytes and there is a trailing NULL + byte, only 253 characters can appear in the textual dotted + notation. + + The description clause of schema nodes using the domain-name + type MUST describe when and how these names are resolved to + IP addresses. Note that the resolution of a domain-name value + may require to query multiple DNS records (e.g., A for IPv4 + and AAAA for IPv6). The order of the resolution process and + which DNS record takes precedence can either be defined + explicitly or may depend on the configuration of the + resolver. + + Domain-name values use the US-ASCII encoding. Their canonical + format uses lowercase US-ASCII characters. Internationalized + domain names MUST be A-labels as per RFC 5890."; + reference + "RFC 952: DoD Internet Host Table Specification + RFC 1034: Domain Names - Concepts and Facilities + RFC 1123: Requirements for Internet Hosts -- Application + and Support + RFC 2782: A DNS RR for specifying the location of services + (DNS SRV) + RFC 5890: Internationalized Domain Names in Applications + (IDNA): Definitions and Document Framework"; + } + + typedef host { + type union { + type inet:ip-address; + type inet:domain-name; + } + description + "The host type represents either an IP address or a DNS + domain name."; + } + + typedef uri { + type string; + description + "The uri type represents a Uniform Resource Identifier + (URI) as defined by STD 66. + + Objects using the uri type MUST be in US-ASCII encoding, + and MUST be normalized as described by RFC 3986 Sections + 6.2.1, 6.2.2.1, and 6.2.2.2. All unnecessary + percent-encoding is removed, and all case-insensitive + characters are set to lowercase except for hexadecimal + digits, which are normalized to uppercase as described in + Section 6.2.2.1. + + The purpose of this normalization is to help provide + unique URIs. Note that this normalization is not + sufficient to provide uniqueness. Two URIs that are + textually distinct after this normalization may still be + equivalent. + + Objects using the uri type may restrict the schemes that + they permit. For example, 'data:' and 'urn:' schemes + might not be appropriate. + + A zero-length URI is not a valid URI. This can be used to + express 'URI absent' where required. + + In the value set and its semantics, this type is equivalent + to the Uri SMIv2 textual convention defined in RFC 5017."; + reference + "RFC 3986: Uniform Resource Identifier (URI): Generic Syntax + RFC 3305: Report from the Joint W3C/IETF URI Planning Interest + Group: Uniform Resource Identifiers (URIs), URLs, + and Uniform Resource Names (URNs): Clarifications + and Recommendations + RFC 5017: MIB Textual Conventions for Uniform Resource + Identifiers (URIs)"; + } + + } diff --git a/src/nbi/service/ietf_l2vpn/yang/ietf-l2vpn-svc@2018-10-09.yang b/src/nbi/service/ietf_l2vpn/yang/ietf-l2vpn-svc@2018-10-09.yang new file mode 100644 index 0000000000000000000000000000000000000000..f2f5ddfb22e30e9232e914d071062f754bd7bc3f --- /dev/null +++ b/src/nbi/service/ietf_l2vpn/yang/ietf-l2vpn-svc@2018-10-09.yang @@ -0,0 +1,3318 @@ +module ietf-l2vpn-svc { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-l2vpn-svc"; + prefix l2vpn-svc; + + import ietf-inet-types { + prefix inet; + } + import ietf-yang-types { + prefix yang; + } + import ietf-netconf-acm { + prefix nacm; + } + + organization + "IETF L2SM Working Group."; + contact + "WG Web: + WG List: + Editor: Giuseppe Fioccola + "; + description + "This YANG module defines a generic service configuration model + for Layer 2 VPN services common across all vendor + implementations. + + Copyright (c) 2018 IETF Trust and the persons + identified as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 8466; + see the RFC itself for full legal notices."; + + revision 2018-10-09 { + description + "Initial revision."; + reference + "RFC 8466: A YANG Data Model for Layer 2 Virtual Private + Network (L2VPN) Service Delivery"; + } + + feature carrierscarrier { + description + "Enables the support of carriers' carriers (CsC)."; + } + + feature ethernet-oam { + description + "Enables the support of Ethernet Service OAM."; + } + + feature extranet-vpn { + description + "Enables the support of extranet VPNs."; + } + + feature l2cp-control { + description + "Enables the support of L2CP control."; + } + + feature input-bw { + description + "Enables the support of input bandwidth in a VPN."; + } + + feature output-bw { + description + "Enables the support of output bandwidth in a VPN."; + } + + feature uni-list { + description + "Enables the support of a list of UNIs in a VPN."; + } + + feature cloud-access { + description + "Allows the VPN to connect to a Cloud Service Provider (CSP) + or an ISP."; + } + + feature oam-3ah { + description + "Enables the support of OAM 802.3ah."; + } + + feature micro-bfd { + description + "Enables the support of micro-BFD."; + } + + feature bfd { + description + "Enables the support of BFD."; + } + + feature signaling-options { + description + "Enables the support of signaling options."; + } + + feature site-diversity { + description + "Enables the support of site diversity constraints in a VPN."; + } + + feature encryption { + description + "Enables the support of encryption."; + } + + feature always-on { + description + "Enables support for the 'always-on' access constraint."; + } + + feature requested-type { + description + "Enables support for the 'requested-type' access constraint."; + } + + feature bearer-reference { + description + "Enables support for the 'bearer-reference' access + constraint."; + } + + feature qos { + description + "Enables support for QoS."; + } + + feature qos-custom { + description + "Enables the support of a custom QoS profile."; + } + + feature lag-interface { + description + "Enables LAG interfaces."; + } + + feature vlan { + description + "Enables the support of VLANs."; + } + + feature dot1q { + description + "Enables the support of dot1Q."; + } + feature qinq { + description + "Enables the support of QinQ."; + } + + feature qinany { + description + "Enables the support of QinAny."; + } + + feature vxlan { + description + "Enables the support of VXLANs."; + } + + feature lan-tag { + description + "Enables LAN tag support in a VPN."; + } + + feature target-sites { + description + "Enables the support of the 'target-sites' + match-flow parameter."; + } + + feature bum { + description + "Enables BUM capabilities in a VPN."; + } + + feature mac-loop-prevention { + description + "Enables the MAC loop-prevention capability in a VPN."; + } + + feature lacp { + description + "Enables the Link Aggregation Control Protocol (LACP) + capability in a VPN."; + } + + feature mac-addr-limit { + description + "Enables the MAC address limit capability in a VPN."; + } + + feature acl { + description + "Enables the ACL capability in a VPN."; + } + + feature cfm { + description + "Enables the 802.1ag CFM capability in a VPN."; + } + + feature y-1731 { + description + "Enables the Y.1731 capability in a VPN."; + } + + typedef svc-id { + type string; + description + "Defines the type of service component identifier."; + } + + typedef ccm-priority-type { + type uint8 { + range "0..7"; + } + description + "A 3-bit priority value to be used in the VLAN tag, + if present in the transmitted frame."; + } + + typedef control-mode { + type enumeration { + enum peer { + description + "'peer' mode, i.e., participate in the protocol towards + the CE. Peering is common for LACP and the Ethernet + Local Management Interface (E-LMI) and, occasionally, + for LLDP. For VPLSs and VPWSs, the subscriber can also + request that the SP peer enable spanning tree."; + } + enum tunnel { + description + "'tunnel' mode, i.e., pass to the egress or destination + site. For EPLs, the expectation is that L2CP frames are + tunneled."; + } + enum discard { + description + "'discard' mode, i.e., discard the frame."; + } + } + description + "Defines the type of control mode on L2CP protocols."; + } + + typedef neg-mode { + type enumeration { + enum full-duplex { + description + "Defines full-duplex mode."; + } + enum auto-neg { + description + "Defines auto-negotiation mode."; + } + } + description + "Defines the type of negotiation mode."; + } + + identity site-network-access-type { + description + "Base identity for the site-network-access type."; + } + + identity point-to-point { + base site-network-access-type; + description + "Identity for a point-to-point connection."; + } + + identity multipoint { + base site-network-access-type; + description + "Identity for a multipoint connection, e.g., + an Ethernet broadcast segment."; + } + + identity tag-type { + description + "Base identity from which all tag types are derived."; + } + + identity c-vlan { + base tag-type; + description + "A CVLAN tag, normally using the 0x8100 Ethertype."; + } + + identity s-vlan { + base tag-type; + description + "An SVLAN tag."; + } + + identity c-s-vlan { + base tag-type; + description + "Using both a CVLAN tag and an SVLAN tag."; + } + + identity multicast-tree-type { + description + "Base identity for the multicast tree type."; + } + + identity ssm-tree-type { + base multicast-tree-type; + description + "Identity for the Source-Specific Multicast (SSM) tree type."; + reference "RFC 8299: YANG Data Model for L3VPN Service Delivery"; + } + + identity asm-tree-type { + base multicast-tree-type; + description + "Identity for the Any-Source Multicast (ASM) tree type."; + reference "RFC 8299: YANG Data Model for L3VPN Service Delivery"; + } + + identity bidir-tree-type { + base multicast-tree-type; + description + "Identity for the bidirectional tree type."; + reference "RFC 8299: YANG Data Model for L3VPN Service Delivery"; + } + + identity multicast-gp-address-mapping { + description + "Identity for mapping type."; + } + + identity static-mapping { + base multicast-gp-address-mapping; + description + "Identity for static mapping, i.e., attach the interface + to the multicast group as a static member."; + } + + identity dynamic-mapping { + base multicast-gp-address-mapping; + description + "Identity for dynamic mapping, i.e., an interface was added + to the multicast group as a result of snooping."; + } + + identity tf-type { + description + "Identity for the traffic type."; + } + + identity multicast-traffic { + base tf-type; + description + "Identity for multicast traffic."; + } + + identity broadcast-traffic { + base tf-type; + description + "Identity for broadcast traffic."; + } + + identity unknown-unicast-traffic { + base tf-type; + description + "Identity for unknown unicast traffic."; + } + + identity encapsulation-type { + description + "Identity for the encapsulation type."; + } + + identity ethernet { + base encapsulation-type; + description + "Identity for Ethernet type."; + } + + identity vlan { + base encapsulation-type; + description + "Identity for the VLAN type."; + } + + identity carrierscarrier-type { + description + "Identity of the CsC type."; + } + + identity ldp { + base carrierscarrier-type; + description + "Use LDP as the signaling protocol + between the PE and the CE."; + } + + identity bgp { + base carrierscarrier-type; + description + "Use BGP (as per RFC 8277) as the signaling protocol + between the PE and the CE. + In this case, BGP must also be configured as + the routing protocol."; + } + + identity eth-inf-type { + description + "Identity of the Ethernet interface type."; + } + + identity tagged { + base eth-inf-type; + description + "Identity of the tagged interface type."; + } + + identity untagged { + base eth-inf-type; + description + "Identity of the untagged interface type."; + } + + identity lag { + base eth-inf-type; + description + "Identity of the LAG interface type."; + } + + identity bw-type { + description + "Identity of the bandwidth type."; + } + + identity bw-per-cos { + base bw-type; + description + "Bandwidth is per CoS."; + } + + identity bw-per-port { + base bw-type; + description + "Bandwidth is per site network access."; + } + + identity bw-per-site { + base bw-type; + description + "Bandwidth is per site. It is applicable to + all the site network accesses within the site."; + } + + identity bw-per-svc { + base bw-type; + description + "Bandwidth is per VPN service."; + } + + identity site-vpn-flavor { + description + "Base identity for the site VPN service flavor."; + } + + identity site-vpn-flavor-single { + base site-vpn-flavor; + description + "Identity for the site VPN service flavor. + Used when the site belongs to only one VPN."; + } + + identity site-vpn-flavor-multi { + base site-vpn-flavor; + description + "Identity for the site VPN service flavor. + Used when a logical connection of a site + belongs to multiple VPNs."; + } + identity site-vpn-flavor-nni { + base site-vpn-flavor; + description + "Identity for the site VPN service flavor. + Used to describe an NNI option A connection."; + } + + identity service-type { + description + "Base identity of the service type."; + } + + identity vpws { + base service-type; + description + "Point-to-point Virtual Private Wire Service (VPWS) + service type."; + } + + identity pwe3 { + base service-type; + description + "Pseudowire Emulation Edge to Edge (PWE3) service type."; + } + + identity ldp-l2tp-vpls { + base service-type; + description + "LDP-based or L2TP-based multipoint Virtual Private LAN + Service (VPLS) service type. This VPLS uses LDP-signaled + Pseudowires or L2TP-signaled Pseudowires."; + } + + identity bgp-vpls { + base service-type; + description + "BGP-based multipoint VPLS service type. This VPLS uses a + BGP control plane as described in RFCs 4761 and 6624."; + } + + identity vpws-evpn { + base service-type; + description + "VPWS service type using Ethernet VPNs (EVPNs) + as specified in RFC 7432."; + } + + identity pbb-evpn { + base service-type; + description + "Provider Backbone Bridge (PBB) service type using + EVPNs as specified in RFC 7432."; + } + + identity bundling-type { + description + "The base identity for the bundling type. It supports + multiple CE-VLANs associated with an L2VPN service or + all CE-VLANs associated with an L2VPN service."; + } + + identity multi-svc-bundling { + base bundling-type; + description + "Identity for multi-service bundling, i.e., + multiple CE-VLAN IDs can be associated with an + L2VPN service at a site."; + } + + identity one2one-bundling { + base bundling-type; + description + "Identity for one-to-one service bundling, i.e., + each L2VPN can be associated with only one CE-VLAN ID + at a site."; + } + + identity all2one-bundling { + base bundling-type; + description + "Identity for all-to-one bundling, i.e., all CE-VLAN IDs + are mapped to one L2VPN service."; + } + + identity color-id { + description + "Base identity of the color ID."; + } + + identity color-id-cvlan { + base color-id; + description + "Identity of the color ID based on a CVLAN."; + } + + identity cos-id { + description + "Identity of the CoS ID."; + } + + identity cos-id-pcp { + base cos-id; + description + "Identity of the CoS ID based on the + Port Control Protocol (PCP)."; + } + + identity cos-id-dscp { + base cos-id; + description + "Identity of the CoS ID based on DSCP."; + } + + identity color-type { + description + "Identity of color types."; + } + + identity green { + base color-type; + description + "Identity of the 'green' color type."; + } + + identity yellow { + base color-type; + description + "Identity of the 'yellow' color type."; + } + + identity red { + base color-type; + description + "Identity of the 'red' color type."; + } + + identity policing { + description + "Identity of the type of policing applied."; + } + + identity one-rate-two-color { + base policing; + description + "Identity of one-rate, two-color (1R2C)."; + } + + identity two-rate-three-color { + base policing; + description + "Identity of two-rate, three-color (2R3C)."; + } + + identity bum-type { + description + "Identity of the BUM type."; + } + + identity broadcast { + base bum-type; + description + "Identity of broadcast."; + } + + identity unicast { + base bum-type; + description + "Identity of unicast."; + } + + identity multicast { + base bum-type; + description + "Identity of multicast."; + } + + identity loop-prevention-type { + description + "Identity of loop prevention."; + } + + identity shut { + base loop-prevention-type; + description + "Identity of shut protection."; + } + + identity trap { + base loop-prevention-type; + description + "Identity of trap protection."; + } + identity lacp-state { + description + "Identity of the LACP state."; + } + + identity lacp-on { + base lacp-state; + description + "Identity of LACP on."; + } + + identity lacp-off { + base lacp-state; + description + "Identity of LACP off."; + } + + identity lacp-mode { + description + "Identity of the LACP mode."; + } + + identity lacp-passive { + base lacp-mode; + description + "Identity of LACP passive."; + } + + identity lacp-active { + base lacp-mode; + description + "Identity of LACP active."; + } + + identity lacp-speed { + description + "Identity of the LACP speed."; + } + + identity lacp-fast { + base lacp-speed; + description + "Identity of LACP fast."; + } + + identity lacp-slow { + base lacp-speed; + description + "Identity of LACP slow."; + } + + identity bw-direction { + description + "Identity for the bandwidth direction."; + } + + identity input-bw { + base bw-direction; + description + "Identity for the input bandwidth."; + } + + identity output-bw { + base bw-direction; + description + "Identity for the output bandwidth."; + } + + identity management { + description + "Base identity for the site management scheme."; + } + + identity co-managed { + base management; + description + "Identity for a co-managed site."; + } + + identity customer-managed { + base management; + description + "Identity for a customer-managed site."; + } + + identity provider-managed { + base management; + description + "Identity for a provider-managed site."; + } + + identity address-family { + description + "Identity for an address family."; + } + + identity ipv4 { + base address-family; + description + "Identity for an IPv4 address family."; + } + + identity ipv6 { + base address-family; + description + "Identity for an IPv6 address family."; + } + + identity vpn-topology { + description + "Base identity for the VPN topology."; + } + + identity any-to-any { + base vpn-topology; + description + "Identity for the any-to-any VPN topology."; + } + + identity hub-spoke { + base vpn-topology; + description + "Identity for the Hub-and-Spoke VPN topology."; + } + + identity hub-spoke-disjoint { + base vpn-topology; + description + "Identity for the Hub-and-Spoke VPN topology, + where Hubs cannot communicate with each other."; + } + + identity site-role { + description + "Base identity for a site type."; + } + + identity any-to-any-role { + base site-role; + description + "Site in an any-to-any L2VPN."; + } + + identity spoke-role { + base site-role; + description + "Spoke site in a Hub-and-Spoke L2VPN."; + } + + identity hub-role { + base site-role; + description + "Hub site in a Hub-and-Spoke L2VPN."; + } + + identity pm-type { + description + "Performance-monitoring type."; + } + + identity loss { + base pm-type; + description + "Loss measurement."; + } + + identity delay { + base pm-type; + description + "Delay measurement."; + } + + identity fault-alarm-defect-type { + description + "Indicates the alarm-priority defect (i.e., the + lowest-priority defect that is allowed to + generate a fault alarm)."; + } + + identity remote-rdi { + base fault-alarm-defect-type; + description + "Indicates the aggregate health + of the Remote MEPs."; + } + + identity remote-mac-error { + base fault-alarm-defect-type; + description + "Indicates that one or more of the Remote MEPs are + reporting a failure in their Port Status TLVs or + Interface Status TLVs."; + } + + identity remote-invalid-ccm { + base fault-alarm-defect-type; + description + "Indicates that at least one of the Remote MEP + state machines is not receiving valid + Continuity Check Messages (CCMs) from its Remote MEP."; + } + + identity invalid-ccm { + base fault-alarm-defect-type; + description + "Indicates that one or more invalid CCMs have been + received and that a period of time 3.5 times the length + of those CCMs' transmission intervals has not yet expired."; + } + + identity cross-connect-ccm { + base fault-alarm-defect-type; + description + "Indicates that one or more cross-connect CCMs have been + received and that 3.5 times the period of at least one of + those CCMs' transmission intervals has not yet expired."; + } + + identity frame-delivery-mode { + description + "Delivery types."; + } + + identity discard { + base frame-delivery-mode; + description + "Service frames are discarded."; + } + + identity unconditional { + base frame-delivery-mode; + description + "Service frames are unconditionally delivered to the + destination site."; + } + + identity unknown-discard { + base frame-delivery-mode; + description + "Service frames are conditionally delivered to the + destination site. Packets with unknown destination addresses + will be discarded."; + } + + identity placement-diversity { + description + "Base identity for site placement constraints."; + } + + identity bearer-diverse { + base placement-diversity; + description + "Identity for bearer diversity. + The bearers should not use common elements."; + } + + identity pe-diverse { + base placement-diversity; + description + "Identity for PE diversity."; + } + + identity pop-diverse { + base placement-diversity; + description + "Identity for POP diversity."; + } + + identity linecard-diverse { + base placement-diversity; + description + "Identity for linecard diversity."; + } + + identity same-pe { + base placement-diversity; + description + "Identity for having sites connected on the same PE."; + } + + identity same-bearer { + base placement-diversity; + description + "Identity for having sites connected using the same bearer."; + } + + identity tagged-inf-type { + description + "Identity for the tagged interface type."; + } + + identity priority-tagged { + base tagged-inf-type; + description + "Identity for the priority-tagged interface."; + } + + identity qinq { + base tagged-inf-type; + description + "Identity for the QinQ tagged interface."; + } + + identity dot1q { + base tagged-inf-type; + description + "Identity for the dot1Q VLAN tagged interface."; + } + + identity qinany { + base tagged-inf-type; + description + "Identity for the QinAny tagged interface."; + } + + identity vxlan { + base tagged-inf-type; + description + "Identity for the VXLAN tagged interface."; + } + + identity provision-model { + description + "Base identity for the provision model."; + } + + identity single-side-provision { + description + "Identity for single-sided provisioning with discovery."; + } + + identity doubled-side-provision { + description + "Identity for double-sided provisioning."; + } + + identity mac-learning-mode { + description + "MAC learning mode."; + } + + identity data-plane { + base mac-learning-mode; + description + "User MAC addresses are learned through ARP broadcast."; + } + + identity control-plane { + base mac-learning-mode; + description + "User MAC addresses are advertised through EVPN-BGP."; + } + + identity vpn-policy-filter-type { + description + "Base identity for the filter type."; + } + + identity lan { + base vpn-policy-filter-type; + description + "Identity for a LAN tag filter type."; + } + + identity mac-action { + description + "Base identity for a MAC action."; + } + + identity drop { + base mac-action; + description + "Identity for dropping a packet."; + } + + identity flood { + base mac-action; + description + "Identity for packet flooding."; + } + + identity warning { + base mac-action; + description + "Identity for sending a warning log message."; + } + + identity qos-profile-direction { + description + "Base identity for the QoS-profile direction."; + } + + identity site-to-wan { + base qos-profile-direction; + description + "Identity for the site-to-WAN direction."; + } + + identity wan-to-site { + base qos-profile-direction; + description + "Identity for the WAN-to-site direction."; + } + + identity bidirectional { + base qos-profile-direction; + description + "Identity for both the WAN-to-site direction + and the site-to-WAN direction."; + } + + identity vxlan-peer-mode { + description + "Base identity for the VXLAN peer mode."; + } + + identity static-mode { + base vxlan-peer-mode; + description + "Identity for VXLAN access in the static mode."; + } + + identity bgp-mode { + base vxlan-peer-mode; + description + "Identity for VXLAN access by BGP EVPN learning."; + } + + identity customer-application { + description + "Base identity for a customer application."; + } + identity web { + base customer-application; + description + "Identity for a web application (e.g., HTTP, HTTPS)."; + } + + identity mail { + base customer-application; + description + "Identity for a mail application."; + } + + identity file-transfer { + base customer-application; + description + "Identity for a file-transfer application + (e.g., FTP, SFTP)."; + } + + identity database { + base customer-application; + description + "Identity for a database application."; + } + + identity social { + base customer-application; + description + "Identity for a social-network application."; + } + + identity games { + base customer-application; + description + "Identity for a gaming application."; + } + + identity p2p { + base customer-application; + description + "Identity for a peer-to-peer application."; + } + + identity network-management { + base customer-application; + description + "Identity for a management application + (e.g., Telnet, syslog, SNMP)."; + } + + identity voice { + base customer-application; + description + "Identity for a voice application."; + } + + identity video { + base customer-application; + description + "Identity for a videoconference application."; + } + + identity embb { + base customer-application; + description + "Identity for the enhanced Mobile Broadband (eMBB) + application. Note that the eMBB application + requires strict threshold values for a wide variety + of network performance parameters (e.g., data rate, + latency, loss rate, reliability)."; + } + + identity urllc { + base customer-application; + description + "Identity for the Ultra-Reliable and Low Latency + Communications (URLLC) application. Note that the + URLLC application requires strict threshold values for + a wide variety of network performance parameters + (e.g., latency, reliability)."; + } + + identity mmtc { + base customer-application; + description + "Identity for the massive Machine Type + Communications (mMTC) application. Note that the + mMTC application requires strict threshold values for + a wide variety of network performance parameters + (e.g., data rate, latency, loss rate, reliability)."; + } + + grouping site-acl { + container access-control-list { + if-feature "acl"; + list mac { + key "mac-address"; + leaf mac-address { + type yang:mac-address; + description + "MAC addresses."; + } + description + "List of MAC addresses."; + } + description + "Container for the ACL."; + } + description + "Grouping that defines the ACL."; + } + + grouping site-bum { + container broadcast-unknown-unicast-multicast { + if-feature "bum"; + leaf multicast-site-type { + type enumeration { + enum receiver-only { + description + "The site only has receivers."; + } + enum source-only { + description + "The site only has sources."; + } + enum source-receiver { + description + "The site has both sources and receivers."; + } + } + default "source-receiver"; + description + "Type of multicast site."; + } + list multicast-gp-address-mapping { + key "id"; + leaf id { + type uint16; + description + "Unique identifier for the mapping."; + } + leaf vlan-id { + type uint16 { + range "0..1024"; + } + mandatory true; + description + "The VLAN ID of the multicast group. + The range of the 12-bit VLAN ID is 0 to 1024."; + } + leaf mac-gp-address { + type yang:mac-address; + mandatory true; + description + "The MAC address of the multicast group."; + } + leaf port-lag-number { + type uint32; + description + "The ports/LAGs belonging to the multicast group."; + } + description + "List of port-to-group mappings."; + } + leaf bum-overall-rate { + type uint64; + units "bps"; + description + "Overall rate for BUM."; + } + list bum-rate-per-type { + key "type"; + leaf type { + type identityref { + base bum-type; + } + description + "BUM type."; + } + leaf rate { + type uint64; + units "bps"; + description + "Rate for BUM."; + } + description + "List of limit rates for the BUM type."; + } + description + "Container of BUM configurations."; + } + description + "Grouping for BUM."; + } + + grouping site-mac-loop-prevention { + container mac-loop-prevention { + if-feature "mac-loop-prevention"; + leaf protection-type { + type identityref { + base loop-prevention-type; + } + default "trap"; + description + "Protection type. By default, the protection + type is 'trap'."; + } + leaf frequency { + type uint32; + default "5"; + description + "The number of times to detect MAC duplication, where + a 'duplicate MAC address' situation has occurred and + the duplicate MAC address has been added to a list of + duplicate MAC addresses. By default, the number of + times is 5."; + } + leaf retry-timer { + type uint32; + units "seconds"; + description + "The retry timer. When the retry timer expires, + the duplicate MAC address will be flushed from + the MAC-VRF."; + } + description + "Container of MAC loop-prevention parameters."; + } + description + "Grouping for MAC loop prevention."; + } + + grouping site-service-qos-profile { + container qos { + if-feature "qos"; + container qos-classification-policy { + list rule { + key "id"; + ordered-by user; + leaf id { + type string; + description + "A description identifying the QoS classification + policy rule."; + } + choice match-type { + default "match-flow"; + case match-flow { + container match-flow { + leaf dscp { + type inet:dscp; + description + "DSCP value."; + } + leaf dot1q { + type uint16; + description + "802.1Q matching. It is a VLAN tag added into + a frame."; + } + leaf pcp { + type uint8 { + range "0..7"; + } + description + "PCP value."; + } + leaf src-mac { + type yang:mac-address; + description + "Source MAC."; + } + leaf dst-mac { + type yang:mac-address; + description + "Destination MAC."; + } + leaf color-type { + type identityref { + base color-type; + } + description + "Color types."; + } + leaf-list target-sites { + if-feature "target-sites"; + type svc-id; + description + "Identifies a site as a traffic destination."; + } + leaf any { + type empty; + description + "Allow all."; + } + leaf vpn-id { + type svc-id; + description + "Reference to the target VPN."; + } + description + "Describes flow-matching criteria."; + } + } + case match-application { + leaf match-application { + type identityref { + base customer-application; + } + description + "Defines the application to match."; + } + } + description + "Choice for classification."; + } + leaf target-class-id { + type string; + description + "Identification of the CoS. + This identifier is internal to the + administration."; + } + description + "List of marking rules."; + } + description + "Configuration of the traffic classification policy."; + } + container qos-profile { + choice qos-profile { + description + "Choice for the QoS profile. + Can be a standard profile or a customized profile."; + case standard { + description + "Standard QoS profile."; + leaf profile { + type leafref { + path "/l2vpn-svc/vpn-profiles/" + + "valid-provider-identifiers/" + + "qos-profile-identifier"; + } + description + "QoS profile to be used."; + } + } + case custom { + description + "Customized QoS profile."; + container classes { + if-feature "qos-custom"; + list class { + key "class-id"; + leaf class-id { + type string; + description + "Identification of the CoS. This identifier is + internal to the administration."; + } + leaf direction { + type identityref { + base qos-profile-direction; + } + default "bidirectional"; + description + "The direction in which the QoS profile is + applied. By default, the direction is + bidirectional."; + } + leaf policing { + type identityref { + base policing; + } + default "one-rate-two-color"; + description + "The policing type can be either one-rate, + two-color (1R2C) or two-rate, three-color + (2R3C). By default, the policing type is + 'one-rate-two-color'."; + } + leaf byte-offset { + type uint16; + description + "Number of bytes in the service frame header + that are excluded from the QoS calculation + (e.g., extra VLAN tags)."; + } + container frame-delay { + choice flavor { + case lowest { + leaf use-lowest-latency { + type empty; + description + "The traffic class should use the path + with the lowest delay."; + } + } + case boundary { + leaf delay-bound { + type uint16; + units "milliseconds"; + description + "The traffic class should use a path + with a defined maximum delay."; + } + } + description + "Delay constraint on the traffic class."; + } + description + "Delay constraint on the traffic class."; + } + container frame-jitter { + choice flavor { + case lowest { + leaf use-lowest-jitter { + type empty; + description + "The traffic class should use the path + with the lowest jitter."; + } + } + case boundary { + leaf delay-bound { + type uint32; + units "microseconds"; + description + "The traffic class should use a path + with a defined maximum jitter."; + } + } + description + "Jitter constraint on the traffic class."; + } + description + "Jitter constraint on the traffic class."; + } + container frame-loss { + leaf rate { + type decimal64 { + fraction-digits 2; + range "0..100"; + } + units "percent"; + description + "Frame loss rate constraint on the traffic + class."; + } + description + "Container for frame loss rate."; + } + container bandwidth { + leaf guaranteed-bw-percent { + type decimal64 { + fraction-digits 5; + range "0..100"; + } + units "percent"; + mandatory true; + description + "Used to define the guaranteed bandwidth + as a percentage of the available service + bandwidth."; + } + leaf end-to-end { + type empty; + description + "Used if the bandwidth reservation + must be done on the MPLS network too."; + } + description + "Bandwidth constraint on the traffic class."; + } + description + "List of CoS entries."; + } + description + "Container for list of CoS entries."; + } + } + } + description + "Qos profile configuration."; + } + description + "QoS configuration."; + } + description + "Grouping that defines QoS parameters for a site."; + } + + grouping site-service-mpls { + container carrierscarrier { + if-feature "carrierscarrier"; + leaf signaling-type { + type identityref { + base carrierscarrier-type; + } + default "bgp"; + description + "CsC. By default, the signaling type is 'bgp'."; + } + description + "Container for CsC."; + } + description + "Grouping for CsC."; + } + + container l2vpn-svc { + container vpn-profiles { + container valid-provider-identifiers { + leaf-list cloud-identifier { + if-feature "cloud-access"; + type string; + description + "Identification of the public cloud service or + Internet service. Local to each administration."; + } + leaf-list qos-profile-identifier { + type string; + description + "Identification of the QoS profile to be used. + Local to each administration."; + } + leaf-list bfd-profile-identifier { + type string; + description + "Identification of the SP BFD profile to be used. + Local to each administration."; + } + leaf-list remote-carrier-identifier { + type string; + description + "Identification of the remote carrier name to be used. + It can be an L2VPN partner, data-center SP, or + private CSP. Local to each administration."; + } + nacm:default-deny-write; + description + "Container for valid provider identifiers."; + } + description + "Container for VPN profiles."; + } + container vpn-services { + list vpn-service { + key "vpn-id"; + leaf vpn-id { + type svc-id; + description + "Defines a service identifier."; + } + leaf vpn-svc-type { + type identityref { + base service-type; + } + default "vpws"; + description + "Service type. By default, the service type is 'vpws'."; + } + leaf customer-name { + type string; + description + "Customer name."; + } + leaf svc-topo { + type identityref { + base vpn-topology; + } + default "any-to-any"; + description + "Defines the service topology, e.g., + 'any-to-any', 'hub-spoke'."; + } + container cloud-accesses { + if-feature "cloud-access"; + list cloud-access { + key "cloud-identifier"; + leaf cloud-identifier { + type leafref { + path "/l2vpn-svc/vpn-profiles/" + + "valid-provider-identifiers" + + "/cloud-identifier"; + } + description + "Identification of the cloud service. + Local to each administration."; + } + choice list-flavor { + case permit-any { + leaf permit-any { + type empty; + description + "Allow all sites."; + } + } + case deny-any-except { + leaf-list permit-site { + type leafref { + path "/l2vpn-svc/sites/site/site-id"; + } + description + "Site ID to be authorized."; + } + } + case permit-any-except { + leaf-list deny-site { + type leafref { + path "/l2vpn-svc/sites/site/site-id"; + } + description + "Site ID to be denied."; + } + } + description + "Choice for cloud access policy. + By default, all sites in the L2VPN + MUST be authorized to access the cloud."; + } + description + "Cloud access configuration."; + } + description + "Container for cloud access configurations."; + } + container frame-delivery { + if-feature "bum"; + container customer-tree-flavors { + leaf-list tree-flavor { + type identityref { + base multicast-tree-type; + } + description + "Type of tree to be used."; + } + description + "Types of trees used by the customer."; + } + container bum-deliveries { + list bum-delivery { + key "frame-type"; + leaf frame-type { + type identityref { + base tf-type; + } + description + "Type of frame delivery. It supports unicast + frame delivery, multicast frame delivery, + and broadcast frame delivery."; + } + leaf delivery-mode { + type identityref { + base frame-delivery-mode; + } + default "unconditional"; + description + "Defines the frame delivery mode + ('unconditional' (default), 'conditional', + or 'discard'). By default, service frames are + unconditionally delivered to the destination site."; + } + description + "List of frame delivery types and modes."; + } + description + "Defines the frame delivery types and modes."; + } + leaf multicast-gp-port-mapping { + type identityref { + base multicast-gp-address-mapping; + } + mandatory true; + description + "Describes the way in which each interface is + associated with the multicast group."; + } + description + "Multicast global parameters for the VPN service."; + } + container extranet-vpns { + if-feature "extranet-vpn"; + list extranet-vpn { + key "vpn-id"; + leaf vpn-id { + type svc-id; + description + "Identifies the target VPN that the local VPN wants to + access."; + } + leaf local-sites-role { + type identityref { + base site-role; + } + default "any-to-any-role"; + description + "Describes the role of the local sites in the target + VPN topology. In the any-to-any VPN service topology, + the local sites must have the same role, which will be + 'any-to-any-role'. In the Hub-and-Spoke VPN service + topology or the Hub-and-Spoke-Disjoint VPN service + topology, the local sites must have a Hub role or a + Spoke role."; + } + description + "List of extranet VPNs to which the local VPN + is attached."; + } + description + "Container for extranet VPN configurations."; + } + leaf ce-vlan-preservation { + type boolean; + mandatory true; + description + "Preserves the CE-VLAN ID from ingress to egress, i.e., + the CE-VLAN tag of the egress frame is identical to + that of the ingress frame that yielded this + egress service frame. If all-to-one bundling within + a site is enabled, then preservation applies to all + ingress service frames. If all-to-one bundling is + disabled, then preservation applies to tagged + ingress service frames having CE-VLAN IDs 1 through 4094."; + } + leaf ce-vlan-cos-preservation { + type boolean; + mandatory true; + description + "CE VLAN CoS preservation. The PCP bits in the CE-VLAN tag + of the egress frame are identical to those of the + ingress frame that yielded this egress service frame."; + } + leaf carrierscarrier { + if-feature "carrierscarrier"; + type boolean; + default "false"; + description + "The VPN is using CsC, and so MPLS is required."; + } + description + "List of VPN services."; + } + description + "Container for VPN services."; + } + container sites { + list site { + key "site-id"; + leaf site-id { + type string; + description + "Identifier of the site."; + } + leaf site-vpn-flavor { + type identityref { + base site-vpn-flavor; + } + default "site-vpn-flavor-single"; + description + "Defines the way that the VPN multiplexing is + done, e.g., whether the site belongs to + a single VPN site or a multi-VPN site. By + default, the site belongs to a single VPN."; + } + container devices { + when "derived-from-or-self(../management/type, " + + "'l2vpn-svc:provider-managed') or " + + "derived-from-or-self(../management/type, " + + "'l2vpn-svc:co-managed')" { + description + "Applicable only for a provider-managed or + co-managed device."; + } + list device { + key "device-id"; + leaf device-id { + type string; + description + "Identifier for the device."; + } + leaf location { + type leafref { + path "../../../locations/location/location-id"; + } + mandatory true; + description + "Location of the device."; + } + container management { + when "derived-from-or-self(../../../management/type, " + + "'l2vpn-svc:co-managed')" { + description + "Applicable only for a co-managed device."; + } + leaf transport { + type identityref { + base address-family; + } + description + "Transport protocol or address family + used for management."; + } + leaf address { + when '(../ transport)' { + description + "If the address family is specified, then the + address should also be specified. If the + transport is not specified, then the address + should not be specified."; + } + type inet:ip-address; + description + "Management address."; + } + description + "Management configuration. Applicable only for a + co-managed device."; + } + description + "List of devices requested by the customer."; + } + description + "Device configurations."; + } + container management { + leaf type { + type identityref { + base management; + } + mandatory true; + description + "Management type of the connection."; + } + description + "Management configuration."; + } + container locations { + list location { + key "location-id"; + leaf location-id { + type string; + description + "Location ID."; + } + leaf address { + type string; + description + "Address (number and street) of the site."; + } + leaf postal-code { + type string; + description + "Postal code of the site. The format of 'postal-code' + is similar to the 'PC' (postal code) label format + defined in RFC 4119."; + } + leaf state { + type string; + description + "State (region) of the site. This leaf can also be used + to describe a region of a country that does not have + states."; + } + leaf city { + type string; + description + "City of the site."; + } + leaf country-code { + type string; + description + "Country of the site. The format of 'country-code' is + similar to the 'country' label defined in RFC 4119."; + } + description + "List of locations."; + } + description + "Location of the site."; + } + container site-diversity { + if-feature "site-diversity"; + container groups { + list group { + key "group-id"; + leaf group-id { + type string; + description + "The group-id to which the site belongs."; + } + description + "List of group-ids."; + } + description + "Groups to which the site belongs. + All site network accesses will inherit those group + values."; + } + description + "The type of diversity constraint."; + } + container vpn-policies { + list vpn-policy { + key "vpn-policy-id"; + leaf vpn-policy-id { + type string; + description + "Unique identifier for the VPN policy."; + } + list entries { + key "id"; + leaf id { + type string; + description + "Unique identifier for the policy entry."; + } + container filters { + list filter { + key "type"; + ordered-by user; + leaf type { + type identityref { + base vpn-policy-filter-type; + } + description + "Type of VPN policy filter."; + } + leaf-list lan-tag { + when "derived-from-or-self(../type, " + + "'l2vpn-svc:lan')" { + description + "Only applies when the VPN policy filter is a + LAN tag filter."; + } + if-feature "lan-tag"; + type uint32; + description + "List of Ethernet LAN tags to be matched. An + Ethernet LAN tag identifies a particular + broadcast domain in a VPN."; + } + description + "List of filters used on the site. This list can + be augmented."; + } + description + "If a more granular VPN attachment is necessary, + filtering can be used. If used, it permits the + splitting of site LANs among multiple VPNs. The + site LAN can be split based on either the LAN tag or + the LAN prefix. If no filter is used, all the LANs + will be part of the same VPNs with the same role."; + } + list vpn { + key "vpn-id"; + leaf vpn-id { + type leafref { + path "/l2vpn-svc/vpn-services/vpn-service/vpn-id"; + } + description + "Reference to an L2VPN."; + } + leaf site-role { + type identityref { + base site-role; + } + default "any-to-any-role"; + description + "Role of the site in the L2VPN."; + } + description + "List of VPNs with which the LAN is associated."; + } + description + "List of entries for an export policy."; + } + description + "List of VPN policies."; + } + description + "VPN policy."; + } + container service { + uses site-service-qos-profile; + uses site-service-mpls; + description + "Service parameters on the attachment."; + } + uses site-bum; + uses site-mac-loop-prevention; + uses site-acl; + leaf actual-site-start { + type yang:date-and-time; + config false; + description + "This leaf is optional. It indicates the date and time + when the service at a particular site actually started."; + } + leaf actual-site-stop { + type yang:date-and-time; + config false; + description + "This leaf is optional. It indicates the date and time + when the service at a particular site actually stopped."; + } + leaf bundling-type { + type identityref { + base bundling-type; + } + default "one2one-bundling"; + description + "Bundling type. By default, each L2VPN + can be associated with only one + CE-VLAN, i.e., one-to-one bundling is used."; + } + leaf default-ce-vlan-id { + type uint32; + mandatory true; + description + "Default CE VLAN ID set at the site level."; + } + container site-network-accesses { + list site-network-access { + key "network-access-id"; + leaf network-access-id { + type string; + description + "Identifier of network access."; + } + leaf remote-carrier-name { + when "derived-from-or-self(../../../site-vpn-flavor," + + "'l2vpn-svc:site-vpn-flavor-nni')" { + description + "Relevant when the site's VPN flavor is + 'site-vpn-flavor-nni'."; + } + type leafref { + path "/l2vpn-svc/vpn-profiles/" + + "valid-provider-identifiers" + + "/remote-carrier-identifier"; + } + description + "Remote carrier name. The 'remote-carrier-name' + parameter must be configured only when + 'site-vpn-flavor' is set to 'site-vpn-flavor-nni'. + If it is not set, it indicates that the customer + does not know the remote carrier's name + beforehand."; + } + leaf type { + type identityref { + base site-network-access-type; + } + default "point-to-point"; + description + "Describes the type of connection, e.g., + point-to-point or multipoint."; + } + choice location-flavor { + case location { + when "derived-from-or-self(../../management/type, " + + "'l2vpn-svc:customer-managed')" { + description + "Applicable only for a customer-managed device."; + } + leaf location-reference { + type leafref { + path "../../../locations/location/location-id"; + } + description + "Location of the site-network-access."; + } + } + case device { + when "derived-from-or-self(../../management/type, " + + "'l2vpn-svc:provider-managed') or " + + "derived-from-or-self(../../management/type, " + + "'l2vpn-svc:co-managed')" { + description + "Applicable only for a provider-managed + or co-managed device."; + } + leaf device-reference { + type leafref { + path "../../../devices/device/device-id"; + } + description + "Identifier of the CE to use."; + } + } + mandatory true; + description + "Choice of how to describe the site's location."; + } + container access-diversity { + if-feature "site-diversity"; + container groups { + list group { + key "group-id"; + leaf group-id { + type string; + description + "Group-id to which the site belongs."; + } + description + "List of group-ids."; + } + description + "Groups to which the site or site-network-access + belongs."; + } + container constraints { + list constraint { + key "constraint-type"; + leaf constraint-type { + type identityref { + base placement-diversity; + } + description + "The type of diversity constraint."; + } + container target { + choice target-flavor { + default "id"; + case id { + list group { + key "group-id"; + leaf group-id { + type string; + description + "The constraint will apply against this + particular group-id."; + } + description + "List of groups."; + } + } + case all-accesses { + leaf all-other-accesses { + type empty; + description + "The constraint will apply against all other + site network accesses of this site."; + } + } + case all-groups { + leaf all-other-groups { + type empty; + description + "The constraint will apply against all other + groups the customer is managing."; + } + } + description + "Choice for the group definition."; + } + description + "The constraint will apply against + this list of groups."; + } + description + "List of constraints."; + } + description + "Constraints for placing this site network access."; + } + description + "Diversity parameters."; + } + container bearer { + container requested-type { + if-feature "requested-type"; + leaf type { + type string; + description + "Type of requested bearer: Ethernet, ATM, Frame + Relay, IP Layer 2 transport, Frame Relay Data + Link Connection Identifier (DLCI), SONET/SDH, + PPP."; + } + leaf strict { + type boolean; + default "false"; + description + "Defines whether the requested type is a preference + or a strict requirement."; + } + description + "Container for requested types."; + } + leaf always-on { + if-feature "always-on"; + type boolean; + default "true"; + description + "Request for an 'always-on' access type. + For example, this could mean no dial-in access + type."; + } + leaf bearer-reference { + if-feature "bearer-reference"; + type string; + description + "An internal reference for the SP."; + } + description + "Bearer-specific parameters. To be augmented."; + } + container connection { + leaf encapsulation-type { + type identityref { + base encapsulation-type; + } + default "ethernet"; + description + "Encapsulation type. By default, the + encapsulation type is set to 'ethernet'."; + } + leaf eth-inf-type { + type identityref { + base eth-inf-type; + } + default "untagged"; + description + "Ethernet interface type. By default, the + Ethernet interface type is set to 'untagged'."; + } + container tagged-interface { + leaf type { + type identityref { + base tagged-inf-type; + } + default "priority-tagged"; + description + "Tagged interface type. By default, + the type of the tagged interface is + 'priority-tagged'."; + } + container dot1q-vlan-tagged { + when "derived-from-or-self(../type, " + + "'l2vpn-svc:dot1q')" { + description + "Only applies when the type of the tagged + interface is 'dot1q'."; + } + if-feature "dot1q"; + leaf tg-type { + type identityref { + base tag-type; + } + default "c-vlan"; + description + "Tag type. By default, the tag type is + 'c-vlan'."; + } + leaf cvlan-id { + type uint16; + mandatory true; + description + "VLAN identifier."; + } + description + "Tagged interface."; + } + container priority-tagged { + when "derived-from-or-self(../type, " + + "'l2vpn-svc:priority-tagged')" { + description + "Only applies when the type of the tagged + interface is 'priority-tagged'."; + } + leaf tag-type { + type identityref { + base tag-type; + } + default "c-vlan"; + description + "Tag type. By default, the tag type is + 'c-vlan'."; + } + description + "Priority tagged."; + } + container qinq { + when "derived-from-or-self(../type, " + + "'l2vpn-svc:qinq')" { + description + "Only applies when the type of the tagged + interface is 'qinq'."; + } + if-feature "qinq"; + leaf tag-type { + type identityref { + base tag-type; + } + default "c-s-vlan"; + description + "Tag type. By default, the tag type is + 'c-s-vlan'."; + } + leaf svlan-id { + type uint16; + mandatory true; + description + "SVLAN identifier."; + } + leaf cvlan-id { + type uint16; + mandatory true; + description + "CVLAN identifier."; + } + description + "QinQ."; + } + container qinany { + when "derived-from-or-self(../type, " + + "'l2vpn-svc:qinany')" { + description + "Only applies when the type of the tagged + interface is 'qinany'."; + } + if-feature "qinany"; + leaf tag-type { + type identityref { + base tag-type; + } + default "s-vlan"; + description + "Tag type. By default, the tag type is + 's-vlan'."; + } + leaf svlan-id { + type uint16; + mandatory true; + description + "SVLAN ID."; + } + description + "Container for QinAny."; + } + container vxlan { + when "derived-from-or-self(../type, " + + "'l2vpn-svc:vxlan')" { + description + "Only applies when the type of the tagged + interface is 'vxlan'."; + } + if-feature "vxlan"; + leaf vni-id { + type uint32; + mandatory true; + description + "VXLAN Network Identifier (VNI)."; + } + leaf peer-mode { + type identityref { + base vxlan-peer-mode; + } + default "static-mode"; + description + "Specifies the VXLAN access mode. By default, + the peer mode is set to 'static-mode'."; + } + list peer-list { + key "peer-ip"; + leaf peer-ip { + type inet:ip-address; + description + "Peer IP."; + } + description + "List of peer IP addresses."; + } + description + "QinQ."; + } + description + "Container for tagged interfaces."; + } + container untagged-interface { + leaf speed { + type uint32; + units "mbps"; + default "10"; + description + "Port speed."; + } + leaf mode { + type neg-mode; + default "auto-neg"; + description + "Negotiation mode."; + } + leaf phy-mtu { + type uint32; + units "bytes"; + description + "PHY MTU."; + } + leaf lldp { + type boolean; + default "false"; + description + "LLDP. Indicates that LLDP is supported."; + } + container oam-802.3ah-link { + if-feature "oam-3ah"; + leaf enabled { + type boolean; + default "false"; + description + "Indicates whether or not to support + OAM 802.3ah links."; + } + description + "Container for OAM 802.3ah links."; + } + leaf uni-loop-prevention { + type boolean; + default "false"; + description + "If this leaf is set to 'true', then the port + automatically goes down when a physical + loopback is detected."; + } + description + "Container of untagged interface attribute + configurations."; + } + container lag-interfaces { + if-feature "lag-interface"; + list lag-interface { + key "index"; + leaf index { + type string; + description + "LAG interface index."; + } + container lacp { + if-feature "lacp"; + leaf enabled { + type boolean; + default "false"; + description + "LACP on/off. By default, LACP is disabled."; + } + leaf mode { + type neg-mode; + description + "LACP mode. LACP modes have active mode and + passive mode ('false'). 'Active mode' means + initiating the auto-speed negotiation and + trying to form an Ethernet channel with the + other end. 'Passive mode' means not initiating + the negotiation but responding to LACP packets + initiated by the other end (e.g., full duplex + or half duplex)."; + } + leaf speed { + type uint32; + units "mbps"; + default "10"; + description + "LACP speed. By default, the LACP speed is 10 + Mbps."; + } + leaf mini-link-num { + type uint32; + description + "Defines the minimum number of links that must + be active before the aggregating link is put + into service."; + } + leaf system-priority { + type uint16; + default "32768"; + description + "Indicates the LACP priority for the system. + The range is from 0 to 65535. + The default is 32768."; + } + container micro-bfd { + if-feature "micro-bfd"; + leaf enabled { + type enumeration { + enum on { + description + "Micro-bfd on."; + } + enum off { + description + "Micro-bfd off."; + } + } + default "off"; + description + "Micro-BFD on/off. By default, micro-BFD + is set to 'off'."; + } + leaf interval { + type uint32; + units "milliseconds"; + description + "BFD interval."; + } + leaf hold-timer { + type uint32; + units "milliseconds"; + description + "BFD hold timer."; + } + description + "Container of micro-BFD configurations."; + } + container bfd { + if-feature "bfd"; + leaf enabled { + type boolean; + default "false"; + description + "BFD activation. By default, BFD is not + activated."; + } + choice holdtime { + default "fixed"; + case profile { + leaf profile-name { + type leafref { + path "/l2vpn-svc/vpn-profiles/" + + "valid-provider-identifiers" + + "/bfd-profile-identifier"; + } + description + "SP well-known profile."; + } + description + "SP well-known profile."; + } + case fixed { + leaf fixed-value { + type uint32; + units "milliseconds"; + description + "Expected hold time expressed in + milliseconds."; + } + } + description + "Choice for the hold-time flavor."; + } + description + "Container for BFD."; + } + container member-links { + list member-link { + key "name"; + leaf name { + type string; + description + "Member link name."; + } + leaf speed { + type uint32; + units "mbps"; + default "10"; + description + "Port speed."; + } + leaf mode { + type neg-mode; + default "auto-neg"; + description + "Negotiation mode."; + } + leaf link-mtu { + type uint32; + units "bytes"; + description + "Link MTU size."; + } + container oam-802.3ah-link { + if-feature "oam-3ah"; + leaf enabled { + type boolean; + default "false"; + description + "Indicates whether OAM 802.3ah links are + supported."; + } + description + "Container for OAM 802.3ah links."; + } + description + "Member link."; + } + description + "Container of the member link list."; + } + leaf flow-control { + type boolean; + default "false"; + description + "Flow control. Indicates whether flow control + is supported."; + } + leaf lldp { + type boolean; + default "false"; + description + "LLDP. Indicates whether LLDP is supported."; + } + description + "LACP."; + } + description + "List of LAG interfaces."; + } + description + "Container of LAG interface attribute + configurations."; + } + list cvlan-id-to-svc-map { + key "svc-id"; + leaf svc-id { + type leafref { + path "/l2vpn-svc/vpn-services/vpn-service/vpn-id"; + } + description + "VPN service identifier."; + } + list cvlan-id { + key "vid"; + leaf vid { + type uint16; + description + "CVLAN ID."; + } + description + "List of CVLAN-ID-to-SVC-map configurations."; + } + description + "List of CVLAN-ID-to-L2VPN-service-map + configurations."; + } + container l2cp-control { + if-feature "l2cp-control"; + leaf stp-rstp-mstp { + type control-mode; + description + "STP / Rapid STP (RSTP) / Multiple STP (MSTP) + protocol type applicable to all sites."; + } + leaf pause { + type control-mode; + description + "Pause protocol type applicable to all sites."; + } + leaf lacp-lamp { + type control-mode; + description + "LACP / Link Aggregation Marker Protocol (LAMP)."; + } + leaf link-oam { + type control-mode; + description + "Link OAM."; + } + leaf esmc { + type control-mode; + description + "Ethernet Synchronization Messaging Channel + (ESMC)."; + } + leaf l2cp-802.1x { + type control-mode; + description + "IEEE 802.1x."; + } + leaf e-lmi { + type control-mode; + description + "E-LMI."; + } + leaf lldp { + type boolean; + description + "LLDP protocol type applicable to all sites."; + } + leaf ptp-peer-delay { + type control-mode; + description + "Precision Time Protocol (PTP) peer delay."; + } + leaf garp-mrp { + type control-mode; + description + "GARP/MRP."; + } + description + "Container of L2CP control configurations."; + } + container oam { + if-feature "ethernet-oam"; + leaf md-name { + type string; + mandatory true; + description + "Maintenance domain name."; + } + leaf md-level { + type uint16 { + range "0..255"; + } + mandatory true; + description + "Maintenance domain level. The level may be + restricted in certain protocols (e.g., + protocols in Layer 0 to Layer 7)."; + } + list cfm-8021-ag { + if-feature "cfm"; + key "maid"; + leaf maid { + type string; + mandatory true; + description + "Identifies a Maintenance Association (MA)."; + } + leaf mep-id { + type uint32; + description + "Local Maintenance Entity Group End Point (MEP) + ID. The non-existence of this leaf means + that no defects are to be reported."; + } + leaf mep-level { + type uint32; + description + "Defines the MEP level. The non-existence of this + leaf means that no defects are to be reported."; + } + leaf mep-up-down { + type enumeration { + enum up { + description + "MEP up."; + } + enum down { + description + "MEP down."; + } + } + default "up"; + description + "MEP up/down. By default, MEP up is used. + The non-existence of this leaf means that + no defects are to be reported."; + } + leaf remote-mep-id { + type uint32; + description + "Remote MEP ID. The non-existence of this leaf + means that no defects are to be reported."; + } + leaf cos-for-cfm-pdus { + type uint32; + description + "CoS for CFM PDUs. The non-existence of this leaf + means that no defects are to be reported."; + } + leaf ccm-interval { + type uint32; + units "milliseconds"; + default "10000"; + description + "CCM interval. By default, the CCM interval is + 10,000 milliseconds (10 seconds)."; + } + leaf ccm-holdtime { + type uint32; + units "milliseconds"; + default "35000"; + description + "CCM hold time. By default, the CCM hold time + is 3.5 times the CCM interval."; + } + leaf alarm-priority-defect { + type identityref { + base fault-alarm-defect-type; + } + default "remote-invalid-ccm"; + description + "The lowest-priority defect that is + allowed to generate a fault alarm. By default, + 'fault-alarm-defect-type' is set to + 'remote-invalid-ccm'. The non-existence of + this leaf means that no defects are + to be reported."; + } + leaf ccm-p-bits-pri { + type ccm-priority-type; + description + "The priority parameter for CCMs transmitted by + the MEP. The non-existence of this leaf means + that no defects are to be reported."; + } + description + "List of 802.1ag CFM attributes."; + } + list y-1731 { + if-feature "y-1731"; + key "maid"; + leaf maid { + type string; + mandatory true; + description + "Identifies an MA."; + } + leaf mep-id { + type uint32; + description + "Local MEP ID. The non-existence of this leaf + means that no measurements are to be reported."; + } + leaf type { + type identityref { + base pm-type; + } + default "delay"; + description + "Performance-monitoring types. By default, the + performance-monitoring type is set to 'delay'. + The non-existence of this leaf means that no + measurements are to be reported."; + } + leaf remote-mep-id { + type uint32; + description + "Remote MEP ID. The non-existence of this + leaf means that no measurements are to be + reported."; + } + leaf message-period { + type uint32; + units "milliseconds"; + default "10000"; + description + "Defines the interval between Y.1731 + performance-monitoring messages. The message + period is expressed in milliseconds."; + } + leaf measurement-interval { + type uint32; + units "seconds"; + description + "Specifies the measurement interval for + statistics. The measurement interval is + expressed in seconds."; + } + leaf cos { + type uint32; + description + "CoS. The non-existence of this leaf means that + no measurements are to be reported."; + } + leaf loss-measurement { + type boolean; + default "false"; + description + "Indicates whether or not to enable loss + measurement. By default, loss + measurement is not enabled."; + } + leaf synthetic-loss-measurement { + type boolean; + default "false"; + description + "Indicates whether or not to enable synthetic loss + measurement. By default, synthetic loss + measurement is not enabled."; + } + container delay-measurement { + leaf enable-dm { + type boolean; + default "false"; + description + "Indicates whether or not to enable delay + measurement. By default, delay measurement + is not enabled."; + } + leaf two-way { + type boolean; + default "false"; + description + "Indicates whether delay measurement is two-way + ('true') or one-way ('false'). By default, + one-way measurement is enabled."; + } + description + "Container for delay measurement."; + } + leaf frame-size { + type uint32; + units "bytes"; + description + "Frame size. The non-existence of this leaf + means that no measurements are to be reported."; + } + leaf session-type { + type enumeration { + enum proactive { + description + "Proactive mode."; + } + enum on-demand { + description + "On-demand mode."; + } + } + default "on-demand"; + description + "Session type. By default, the session type + is 'on-demand'. The non-existence of this + leaf means that no measurements are to be + reported."; + } + description + "List of configured Y-1731 instances."; + } + description + "Container for Ethernet Service OAM."; + } + description + "Container for connection requirements."; + } + container availability { + leaf access-priority { + type uint32; + default "100"; + description + "Access priority. The higher the access-priority + value, the higher the preference will be for the + access in question."; + } + choice redundancy-mode { + case single-active { + leaf single-active { + type empty; + description + "Single-active mode."; + } + description + "In single-active mode, only one node forwards + traffic to and from the Ethernet segment."; + } + case all-active { + leaf all-active { + type empty; + description + "All-active mode."; + } + description + "In all-active mode, all nodes can forward + traffic."; + } + description + "Redundancy mode choice."; + } + description + "Container of available optional configurations."; + } + container vpn-attachment { + choice attachment-flavor { + case vpn-id { + leaf vpn-id { + type leafref { + path "/l2vpn-svc/vpn-services/vpn-service/vpn-id"; + } + description + "Reference to an L2VPN. Referencing a vpn-id + provides an easy way to attach a particular + logical access to a VPN. In this case, + the vpn-id must be configured."; + } + leaf site-role { + type identityref { + base site-role; + } + default "any-to-any-role"; + description + "Role of the site in the L2VPN. When referencing + a vpn-id, the site-role setting must be added to + express the role of the site in the target VPN + service topology."; + } + } + case vpn-policy-id { + leaf vpn-policy-id { + type leafref { + path "../../../../vpn-policies/vpn-policy/" + + "vpn-policy-id"; + } + description + "Reference to a VPN policy."; + } + } + mandatory true; + description + "Choice for the VPN attachment flavor."; + } + description + "Defines the VPN attachment of a site."; + } + container service { + container svc-bandwidth { + if-feature "input-bw"; + list bandwidth { + key "direction type"; + leaf direction { + type identityref { + base bw-direction; + } + description + "Indicates the bandwidth direction. It can be + the bandwidth download direction from the SP to + the site or the bandwidth upload direction from + the site to the SP."; + } + leaf type { + type identityref { + base bw-type; + } + description + "Bandwidth type. By default, the bandwidth type + is set to 'bw-per-cos'."; + } + leaf cos-id { + when "derived-from-or-self(../type, " + + "'l2vpn-svc:bw-per-cos')" { + description + "Relevant when the bandwidth type is set to + 'bw-per-cos'."; + } + type uint8; + description + "Identifier of the CoS, indicated by DSCP or a + CE-VLAN CoS (802.1p) value in the service frame. + If the bandwidth type is set to 'bw-per-cos', + the CoS ID MUST also be specified."; + } + leaf vpn-id { + when "derived-from-or-self(../type, " + + "'l2vpn-svc:bw-per-svc')" { + description + "Relevant when the bandwidth type is + set as bandwidth per VPN service."; + } + type svc-id; + description + "Identifies the target VPN. If the bandwidth + type is set as bandwidth per VPN service, the + vpn-id MUST be specified."; + } + leaf cir { + type uint64; + units "bps"; + mandatory true; + description + "Committed Information Rate. The maximum number + of bits that a port can receive or send over + an interface in one second."; + } + leaf cbs { + type uint64; + units "bps"; + mandatory true; + description + "Committed Burst Size (CBS). Controls the bursty + nature of the traffic. Traffic that does not + use the configured Committed Information Rate + (CIR) accumulates credits until the credits + reach the configured CBS."; + } + leaf eir { + type uint64; + units "bps"; + description + "Excess Information Rate (EIR), i.e., excess frame + delivery allowed that is not subject to an SLA. + The traffic rate can be limited by the EIR."; + } + leaf ebs { + type uint64; + units "bps"; + description + "Excess Burst Size (EBS). The bandwidth available + for burst traffic from the EBS is subject to the + amount of bandwidth that is accumulated during + periods when traffic allocated by the EIR + policy is not used."; + } + leaf pir { + type uint64; + units "bps"; + description + "Peak Information Rate, i.e., maximum frame + delivery allowed. It is equal to or less + than the sum of the CIR and the EIR."; + } + leaf pbs { + type uint64; + units "bps"; + description + "Peak Burst Size. It is measured in bytes per + second."; + } + description + "List of bandwidth values (e.g., per CoS, + per vpn-id)."; + } + description + "From the customer site's perspective, the service + input/output bandwidth of the connection or + download/upload bandwidth from the SP/site + to the site/SP."; + } + leaf svc-mtu { + type uint16; + units "bytes"; + mandatory true; + description + "SVC MTU. It is also known as the maximum + transmission unit or maximum frame size. When + a frame is larger than the MTU, it is broken + down, or fragmented, into smaller pieces by + the network protocol to accommodate the MTU + of the network. If CsC is enabled, + the requested svc-mtu leaf will refer to the + MPLS MTU and not to the link MTU."; + } + uses site-service-qos-profile; + uses site-service-mpls; + description + "Container for services."; + } + uses site-bum; + uses site-mac-loop-prevention; + uses site-acl; + container mac-addr-limit { + if-feature "mac-addr-limit"; + leaf limit-number { + type uint16; + default "2"; + description + "Maximum number of MAC addresses learned from + the subscriber for a single service instance. + The default allowed maximum number of MAC + addresses is 2."; + } + leaf time-interval { + type uint32; + units "seconds"; + default "300"; + description + "The aging time of the MAC address. By default, + the aging time is set to 300 seconds."; + } + leaf action { + type identityref { + base mac-action; + } + default "warning"; + description + "Specifies the action taken when the upper limit is + exceeded: drop the packet, flood the packet, or + simply send a warning log message. By default, + the action is set to 'warning'."; + } + description + "Container of MAC address limit configurations."; + } + description + "List of site network accesses."; + } + description + "Container of port configurations."; + } + description + "List of sites."; + } + description + "Container of site configurations."; + } + description + "Container for L2VPN services."; + } +} \ No newline at end of file diff --git a/src/nbi/service/ietf_l2vpn/yang/ietf-netconf-acm@2018-02-14.yang b/src/nbi/service/ietf_l2vpn/yang/ietf-netconf-acm@2018-02-14.yang new file mode 100644 index 0000000000000000000000000000000000000000..dc0deb8ffd29791ad80b9e3ad8244502126f2d44 --- /dev/null +++ b/src/nbi/service/ietf_l2vpn/yang/ietf-netconf-acm@2018-02-14.yang @@ -0,0 +1,468 @@ +module ietf-netconf-acm { + + namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm"; + + prefix nacm; + + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: + WG List: + + Author: Andy Bierman + + + Author: Martin Bjorklund + "; + + description + "Network Configuration Access Control Model. + + Copyright (c) 2012 - 2018 IETF Trust and the persons + identified as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD + License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 8341; see + the RFC itself for full legal notices."; + + revision "2018-02-14" { + description + "Added support for YANG 1.1 actions and notifications tied to + data nodes. Clarified how NACM extensions can be used by + other data models."; + reference + "RFC 8341: Network Configuration Access Control Model"; + } + + revision "2012-02-22" { + description + "Initial version."; + reference + "RFC 6536: Network Configuration Protocol (NETCONF) + Access Control Model"; + } + + /* + * Extension statements + */ + + extension default-deny-write { + description + "Used to indicate that the data model node + represents a sensitive security system parameter. + + If present, the NETCONF server will only allow the designated + 'recovery session' to have write access to the node. An + explicit access control rule is required for all other users. + + If the NACM module is used, then it must be enabled (i.e., + /nacm/enable-nacm object equals 'true'), or this extension + is ignored. + + The 'default-deny-write' extension MAY appear within a data + definition statement. It is ignored otherwise."; + } + + extension default-deny-all { + description + "Used to indicate that the data model node + controls a very sensitive security system parameter. + + If present, the NETCONF server will only allow the designated + 'recovery session' to have read, write, or execute access to + the node. An explicit access control rule is required for all + other users. + + If the NACM module is used, then it must be enabled (i.e., + /nacm/enable-nacm object equals 'true'), or this extension + is ignored. + + The 'default-deny-all' extension MAY appear within a data + definition statement, 'rpc' statement, or 'notification' + statement. It is ignored otherwise."; + } + + /* + * Derived types + */ + + typedef user-name-type { + type string { + length "1..max"; + } + description + "General-purpose username string."; + } + + typedef matchall-string-type { + type string { + pattern '\*'; + } + description + "The string containing a single asterisk '*' is used + to conceptually represent all possible values + for the particular leaf using this data type."; + } + + typedef access-operations-type { + type bits { + bit create { + description + "Any protocol operation that creates a + new data node."; + position 0; + } + bit read { + description + "Any protocol operation or notification that + returns the value of a data node."; + position 1; + } + bit update { + description + "Any protocol operation that alters an existing + data node."; + position 2; + } + bit delete { + description + "Any protocol operation that removes a data node."; + position 3; + } + bit exec { + description + "Execution access to the specified protocol operation."; + position 4; + } + } + description + "Access operation."; + } + + typedef group-name-type { + type string { + length "1..max"; + pattern '[^\*].*'; + } + description + "Name of administrative group to which + users can be assigned."; + } + + typedef action-type { + type enumeration { + enum permit { + description + "Requested action is permitted."; + } + enum deny { + description + "Requested action is denied."; + } + } + description + "Action taken by the server when a particular + rule matches."; + } + + typedef node-instance-identifier { + type yang:xpath1.0; + description + "Path expression used to represent a special + data node, action, or notification instance-identifier + string. + + A node-instance-identifier value is an + unrestricted YANG instance-identifier expression. + All the same rules as an instance-identifier apply, + except that predicates for keys are optional. If a key + predicate is missing, then the node-instance-identifier + represents all possible server instances for that key. + + This XML Path Language (XPath) expression is evaluated in the + following context: + + o The set of namespace declarations are those in scope on + the leaf element where this type is used. + + o The set of variable bindings contains one variable, + 'USER', which contains the name of the user of the + current session. + + o The function library is the core function library, but + note that due to the syntax restrictions of an + instance-identifier, no functions are allowed. + + o The context node is the root node in the data tree. + + The accessible tree includes actions and notifications tied + to data nodes."; + } + + /* + * Data definition statements + */ + + container nacm { + nacm:default-deny-all; + + description + "Parameters for NETCONF access control model."; + + leaf enable-nacm { + type boolean; + default "true"; + description + "Enables or disables all NETCONF access control + enforcement. If 'true', then enforcement + is enabled. If 'false', then enforcement + is disabled."; + } + + leaf read-default { + type action-type; + default "permit"; + description + "Controls whether read access is granted if + no appropriate rule is found for a + particular read request."; + } + + leaf write-default { + type action-type; + default "deny"; + description + "Controls whether create, update, or delete access + is granted if no appropriate rule is found for a + particular write request."; + } + + leaf exec-default { + type action-type; + default "permit"; + description + "Controls whether exec access is granted if no appropriate + rule is found for a particular protocol operation request."; + } + + leaf enable-external-groups { + type boolean; + default "true"; + description + "Controls whether the server uses the groups reported by the + NETCONF transport layer when it assigns the user to a set of + NACM groups. If this leaf has the value 'false', any group + names reported by the transport layer are ignored by the + server."; + } + + leaf denied-operations { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that a + protocol operation request was denied."; + } + + leaf denied-data-writes { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that a + protocol operation request to alter + a configuration datastore was denied."; + } + + leaf denied-notifications { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that + a notification was dropped for a subscription because + access to the event type was denied."; + } + + container groups { + description + "NETCONF access control groups."; + + list group { + key name; + + description + "One NACM group entry. This list will only contain + configured entries, not any entries learned from + any transport protocols."; + + leaf name { + type group-name-type; + description + "Group name associated with this entry."; + } + + leaf-list user-name { + type user-name-type; + description + "Each entry identifies the username of + a member of the group associated with + this entry."; + } + } + } + + list rule-list { + key name; + ordered-by user; + description + "An ordered collection of access control rules."; + + leaf name { + type string { + length "1..max"; + } + description + "Arbitrary name assigned to the rule-list."; + } + leaf-list group { + type union { + type matchall-string-type; + type group-name-type; + } + description + "List of administrative groups that will be + assigned the associated access rights + defined by the 'rule' list. + + The string '*' indicates that all groups apply to the + entry."; + } + + list rule { + key name; + ordered-by user; + description + "One access control rule. + + Rules are processed in user-defined order until a match is + found. A rule matches if 'module-name', 'rule-type', and + 'access-operations' match the request. If a rule + matches, the 'action' leaf determines whether or not + access is granted."; + + leaf name { + type string { + length "1..max"; + } + description + "Arbitrary name assigned to the rule."; + } + + leaf module-name { + type union { + type matchall-string-type; + type string; + } + default "*"; + description + "Name of the module associated with this rule. + + This leaf matches if it has the value '*' or if the + object being accessed is defined in the module with the + specified module name."; + } + choice rule-type { + description + "This choice matches if all leafs present in the rule + match the request. If no leafs are present, the + choice matches all requests."; + case protocol-operation { + leaf rpc-name { + type union { + type matchall-string-type; + type string; + } + description + "This leaf matches if it has the value '*' or if + its value equals the requested protocol operation + name."; + } + } + case notification { + leaf notification-name { + type union { + type matchall-string-type; + type string; + } + description + "This leaf matches if it has the value '*' or if its + value equals the requested notification name."; + } + } + case data-node { + leaf path { + type node-instance-identifier; + mandatory true; + description + "Data node instance-identifier associated with the + data node, action, or notification controlled by + this rule. + + Configuration data or state data + instance-identifiers start with a top-level + data node. A complete instance-identifier is + required for this type of path value. + + The special value '/' refers to all possible + datastore contents."; + } + } + } + + leaf access-operations { + type union { + type matchall-string-type; + type access-operations-type; + } + default "*"; + description + "Access operations associated with this rule. + + This leaf matches if it has the value '*' or if the + bit corresponding to the requested operation is set."; + } + + leaf action { + type action-type; + mandatory true; + description + "The access control action associated with the + rule. If a rule has been determined to match a + particular request, then this object is used + to determine whether to permit or deny the + request."; + } + + leaf comment { + type string; + description + "A textual description of the access rule."; + } + } + } + } +} diff --git a/src/nbi/service/ietf_l2vpn/yang/ietf-yang-types@2013-07-15.yang b/src/nbi/service/ietf_l2vpn/yang/ietf-yang-types@2013-07-15.yang new file mode 100644 index 0000000000000000000000000000000000000000..956562a7b342055127961732d8bde4be21c80d7d --- /dev/null +++ b/src/nbi/service/ietf_l2vpn/yang/ietf-yang-types@2013-07-15.yang @@ -0,0 +1,475 @@ + module ietf-yang-types { + + namespace "urn:ietf:params:xml:ns:yang:ietf-yang-types"; + prefix "yang"; + + organization + "IETF NETMOD (NETCONF Data Modeling Language) Working Group"; + + contact + "WG Web: + WG List: + + WG Chair: David Kessens + + + WG Chair: Juergen Schoenwaelder + + + Editor: Juergen Schoenwaelder + "; + + description + "This module contains a collection of generally useful derived + YANG data types. + + Copyright (c) 2013 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 6991; see + the RFC itself for full legal notices."; + + revision 2013-07-15 { + description + "This revision adds the following new data types: + - yang-identifier + - hex-string + - uuid + - dotted-quad"; + reference + "RFC 6991: Common YANG Data Types"; + } + + revision 2010-09-24 { + description + "Initial revision."; + reference + "RFC 6021: Common YANG Data Types"; + } + + /*** collection of counter and gauge types ***/ + + typedef counter32 { + type uint32; + description + "The counter32 type represents a non-negative integer + that monotonically increases until it reaches a + maximum value of 2^32-1 (4294967295 decimal), when it + wraps around and starts increasing again from zero. + + Counters have no defined 'initial' value, and thus, a + single value of a counter has (in general) no information + content. Discontinuities in the monotonically increasing + value normally occur at re-initialization of the + management system, and at other times as specified in the + description of a schema node using this type. If such + other times can occur, for example, the creation of + a schema node of type counter32 at times other than + re-initialization, then a corresponding schema node + should be defined, with an appropriate type, to indicate + the last discontinuity. + + The counter32 type should not be used for configuration + schema nodes. A default statement SHOULD NOT be used in + combination with the type counter32. + + In the value set and its semantics, this type is equivalent + to the Counter32 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 + (SMIv2)"; + } + + typedef zero-based-counter32 { + type yang:counter32; + default "0"; + description + "The zero-based-counter32 type represents a counter32 + that has the defined 'initial' value zero. + + A schema node of this type will be set to zero (0) on creation + and will thereafter increase monotonically until it reaches + a maximum value of 2^32-1 (4294967295 decimal), when it + wraps around and starts increasing again from zero. + + Provided that an application discovers a new schema node + of this type within the minimum time to wrap, it can use the + 'initial' value as a delta. It is important for a management + station to be aware of this minimum time and the actual time + between polls, and to discard data if the actual time is too + long or there is no defined minimum time. + + In the value set and its semantics, this type is equivalent + to the ZeroBasedCounter32 textual convention of the SMIv2."; + reference + "RFC 4502: Remote Network Monitoring Management Information + Base Version 2"; + } + + typedef counter64 { + type uint64; + description + "The counter64 type represents a non-negative integer + that monotonically increases until it reaches a + maximum value of 2^64-1 (18446744073709551615 decimal), + when it wraps around and starts increasing again from zero. + + Counters have no defined 'initial' value, and thus, a + single value of a counter has (in general) no information + content. Discontinuities in the monotonically increasing + value normally occur at re-initialization of the + management system, and at other times as specified in the + description of a schema node using this type. If such + other times can occur, for example, the creation of + a schema node of type counter64 at times other than + re-initialization, then a corresponding schema node + should be defined, with an appropriate type, to indicate + the last discontinuity. + + The counter64 type should not be used for configuration + schema nodes. A default statement SHOULD NOT be used in + combination with the type counter64. + + In the value set and its semantics, this type is equivalent + to the Counter64 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 + (SMIv2)"; + } + + typedef zero-based-counter64 { + type yang:counter64; + default "0"; + description + "The zero-based-counter64 type represents a counter64 that + has the defined 'initial' value zero. + + A schema node of this type will be set to zero (0) on creation + and will thereafter increase monotonically until it reaches + a maximum value of 2^64-1 (18446744073709551615 decimal), + when it wraps around and starts increasing again from zero. + + Provided that an application discovers a new schema node + of this type within the minimum time to wrap, it can use the + 'initial' value as a delta. It is important for a management + station to be aware of this minimum time and the actual time + between polls, and to discard data if the actual time is too + long or there is no defined minimum time. + + In the value set and its semantics, this type is equivalent + to the ZeroBasedCounter64 textual convention of the SMIv2."; + reference + "RFC 2856: Textual Conventions for Additional High Capacity + Data Types"; + } + + typedef gauge32 { + type uint32; + description + "The gauge32 type represents a non-negative integer, which + may increase or decrease, but shall never exceed a maximum + value, nor fall below a minimum value. The maximum value + cannot be greater than 2^32-1 (4294967295 decimal), and + the minimum value cannot be smaller than 0. The value of + a gauge32 has its maximum value whenever the information + being modeled is greater than or equal to its maximum + value, and has its minimum value whenever the information + being modeled is smaller than or equal to its minimum value. + If the information being modeled subsequently decreases + below (increases above) the maximum (minimum) value, the + gauge32 also decreases (increases). + + In the value set and its semantics, this type is equivalent + to the Gauge32 type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 + (SMIv2)"; + } + + typedef gauge64 { + type uint64; + description + "The gauge64 type represents a non-negative integer, which + may increase or decrease, but shall never exceed a maximum + value, nor fall below a minimum value. The maximum value + cannot be greater than 2^64-1 (18446744073709551615), and + the minimum value cannot be smaller than 0. The value of + a gauge64 has its maximum value whenever the information + being modeled is greater than or equal to its maximum + value, and has its minimum value whenever the information + being modeled is smaller than or equal to its minimum value. + If the information being modeled subsequently decreases + below (increases above) the maximum (minimum) value, the + gauge64 also decreases (increases). + + In the value set and its semantics, this type is equivalent + to the CounterBasedGauge64 SMIv2 textual convention defined + in RFC 2856"; + reference + "RFC 2856: Textual Conventions for Additional High Capacity + Data Types"; + } + + /*** collection of identifier-related types ***/ + + typedef object-identifier { + type string { + pattern '(([0-1](\.[1-3]?[0-9]))|(2\.(0|([1-9]\d*))))' + + '(\.(0|([1-9]\d*)))*'; + } + description + "The object-identifier type represents administratively + assigned names in a registration-hierarchical-name tree. + + Values of this type are denoted as a sequence of numerical + non-negative sub-identifier values. Each sub-identifier + value MUST NOT exceed 2^32-1 (4294967295). Sub-identifiers + are separated by single dots and without any intermediate + whitespace. + + The ASN.1 standard restricts the value space of the first + sub-identifier to 0, 1, or 2. Furthermore, the value space + of the second sub-identifier is restricted to the range + 0 to 39 if the first sub-identifier is 0 or 1. Finally, + the ASN.1 standard requires that an object identifier + has always at least two sub-identifiers. The pattern + captures these restrictions. + + Although the number of sub-identifiers is not limited, + module designers should realize that there may be + implementations that stick with the SMIv2 limit of 128 + sub-identifiers. + + This type is a superset of the SMIv2 OBJECT IDENTIFIER type + since it is not restricted to 128 sub-identifiers. Hence, + this type SHOULD NOT be used to represent the SMIv2 OBJECT + IDENTIFIER type; the object-identifier-128 type SHOULD be + used instead."; + reference + "ISO9834-1: Information technology -- Open Systems + Interconnection -- Procedures for the operation of OSI + Registration Authorities: General procedures and top + arcs of the ASN.1 Object Identifier tree"; + } + + typedef object-identifier-128 { + type object-identifier { + pattern '\d*(\.\d*){1,127}'; + } + description + "This type represents object-identifiers restricted to 128 + sub-identifiers. + + In the value set and its semantics, this type is equivalent + to the OBJECT IDENTIFIER type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 + (SMIv2)"; + } + + typedef yang-identifier { + type string { + length "1..max"; + pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*'; + pattern '.|..|[^xX].*|.[^mM].*|..[^lL].*'; + } + description + "A YANG identifier string as defined by the 'identifier' + rule in Section 12 of RFC 6020. An identifier must + start with an alphabetic character or an underscore + followed by an arbitrary sequence of alphabetic or + numeric characters, underscores, hyphens, or dots. + + A YANG identifier MUST NOT start with any possible + combination of the lowercase or uppercase character + sequence 'xml'."; + reference + "RFC 6020: YANG - A Data Modeling Language for the Network + Configuration Protocol (NETCONF)"; + } + + /*** collection of types related to date and time***/ + + typedef date-and-time { + type string { + pattern '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?' + + '(Z|[\+\-]\d{2}:\d{2})'; + } + description + "The date-and-time type is a profile of the ISO 8601 + standard for representation of dates and times using the + Gregorian calendar. The profile is defined by the + date-time production in Section 5.6 of RFC 3339. + + The date-and-time type is compatible with the dateTime XML + schema type with the following notable exceptions: + + (a) The date-and-time type does not allow negative years. + + (b) The date-and-time time-offset -00:00 indicates an unknown + time zone (see RFC 3339) while -00:00 and +00:00 and Z + all represent the same time zone in dateTime. + + (c) The canonical format (see below) of data-and-time values + differs from the canonical format used by the dateTime XML + schema type, which requires all times to be in UTC using + the time-offset 'Z'. + + This type is not equivalent to the DateAndTime textual + convention of the SMIv2 since RFC 3339 uses a different + separator between full-date and full-time and provides + higher resolution of time-secfrac. + + The canonical format for date-and-time values with a known time + zone uses a numeric time zone offset that is calculated using + the device's configured known offset to UTC time. A change of + the device's offset to UTC time will cause date-and-time values + to change accordingly. Such changes might happen periodically + in case a server follows automatically daylight saving time + (DST) time zone offset changes. The canonical format for + date-and-time values with an unknown time zone (usually + referring to the notion of local time) uses the time-offset + -00:00."; + reference + "RFC 3339: Date and Time on the Internet: Timestamps + RFC 2579: Textual Conventions for SMIv2 + XSD-TYPES: XML Schema Part 2: Datatypes Second Edition"; + } + + typedef timeticks { + type uint32; + description + "The timeticks type represents a non-negative integer that + represents the time, modulo 2^32 (4294967296 decimal), in + hundredths of a second between two epochs. When a schema + node is defined that uses this type, the description of + the schema node identifies both of the reference epochs. + + In the value set and its semantics, this type is equivalent + to the TimeTicks type of the SMIv2."; + reference + "RFC 2578: Structure of Management Information Version 2 + (SMIv2)"; + } + + typedef timestamp { + type yang:timeticks; + description + "The timestamp type represents the value of an associated + timeticks schema node at which a specific occurrence + happened. The specific occurrence must be defined in the + description of any schema node defined using this type. When + the specific occurrence occurred prior to the last time the + associated timeticks attribute was zero, then the timestamp + value is zero. Note that this requires all timestamp values + to be reset to zero when the value of the associated timeticks + attribute reaches 497+ days and wraps around to zero. + + The associated timeticks schema node must be specified + in the description of any schema node using this type. + + In the value set and its semantics, this type is equivalent + to the TimeStamp textual convention of the SMIv2."; + reference + "RFC 2579: Textual Conventions for SMIv2"; + } + + /*** collection of generic address types ***/ + + typedef phys-address { + type string { + pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?'; + } + + description + "Represents media- or physical-level addresses represented + as a sequence octets, each octet represented by two hexadecimal + numbers. Octets are separated by colons. The canonical + representation uses lowercase characters. + + In the value set and its semantics, this type is equivalent + to the PhysAddress textual convention of the SMIv2."; + reference + "RFC 2579: Textual Conventions for SMIv2"; + } + + typedef mac-address { + type string { + pattern '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}'; + } + description + "The mac-address type represents an IEEE 802 MAC address. + The canonical representation uses lowercase characters. + + In the value set and its semantics, this type is equivalent + to the MacAddress textual convention of the SMIv2."; + reference + "IEEE 802: IEEE Standard for Local and Metropolitan Area + Networks: Overview and Architecture + RFC 2579: Textual Conventions for SMIv2"; + } + + /*** collection of XML-specific types ***/ + + typedef xpath1.0 { + type string; + description + "This type represents an XPATH 1.0 expression. + + When a schema node is defined that uses this type, the + description of the schema node MUST specify the XPath + context in which the XPath expression is evaluated."; + reference + "XPATH: XML Path Language (XPath) Version 1.0"; + } + + /*** collection of string types ***/ + + typedef hex-string { + type string { + pattern '([0-9a-fA-F]{2}(:[0-9a-fA-F]{2})*)?'; + } + + description + "A hexadecimal string with octets represented as hex digits + separated by colons. The canonical representation uses + lowercase characters."; + } + + typedef uuid { + type string { + pattern '[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-' + + '[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'; + } + description + "A Universally Unique IDentifier in the string representation + defined in RFC 4122. The canonical representation uses + lowercase characters. + + The following is an example of a UUID in string representation: + f81d4fae-7dec-11d0-a765-00a0c91e6bf6 + "; + reference + "RFC 4122: A Universally Unique IDentifier (UUID) URN + Namespace"; + } + + typedef dotted-quad { + type string { + pattern + '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}' + + '([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'; + } + description + "An unsigned 32-bit number expressed in the dotted-quad + notation, i.e., four octets written as decimal numbers + and separated with the '.' (full stop) character."; + } + } diff --git a/src/nbi/service/ietf_l2vpn/yang/ietf_l2vpn_tree.txt b/src/nbi/service/ietf_l2vpn/yang/ietf_l2vpn_tree.txt new file mode 100644 index 0000000000000000000000000000000000000000..393ed7a36a943638c6bc66127a3a5b4f21fe271e --- /dev/null +++ b/src/nbi/service/ietf_l2vpn/yang/ietf_l2vpn_tree.txt @@ -0,0 +1,383 @@ +module: ietf-l2vpn-svc + +--rw l2vpn-svc + +--rw vpn-profiles + | +--rw valid-provider-identifiers + | +--rw cloud-identifier* string {cloud-access}? + | +--rw qos-profile-identifier* string + | +--rw bfd-profile-identifier* string + | +--rw remote-carrier-identifier* string + +--rw vpn-services + | +--rw vpn-service* [vpn-id] + | +--rw vpn-id svc-id + | +--rw vpn-svc-type? identityref + | +--rw customer-name? string + | +--rw svc-topo? identityref + | +--rw cloud-accesses {cloud-access}? + | | +--rw cloud-access* [cloud-identifier] + | | +--rw cloud-identifier -> /l2vpn-svc/vpn-profiles/valid-provider-identifiers/cloud-identifier + | | +--rw (list-flavor)? + | | +--:(permit-any) + | | | +--rw permit-any? empty + | | +--:(deny-any-except) + | | | +--rw permit-site* -> /l2vpn-svc/sites/site/site-id + | | +--:(permit-any-except) + | | +--rw deny-site* -> /l2vpn-svc/sites/site/site-id + | +--rw frame-delivery {bum}? + | | +--rw customer-tree-flavors + | | | +--rw tree-flavor* identityref + | | +--rw bum-deliveries + | | | +--rw bum-delivery* [frame-type] + | | | +--rw frame-type identityref + | | | +--rw delivery-mode? identityref + | | +--rw multicast-gp-port-mapping identityref + | +--rw extranet-vpns {extranet-vpn}? + | | +--rw extranet-vpn* [vpn-id] + | | +--rw vpn-id svc-id + | | +--rw local-sites-role? identityref + | +--rw ce-vlan-preservation boolean + | +--rw ce-vlan-cos-preservation boolean + | +--rw carrierscarrier? boolean {carrierscarrier}? + +--rw sites + +--rw site* [site-id] + +--rw site-id string + +--rw site-vpn-flavor? identityref + +--rw devices + | +--rw device* [device-id] + | +--rw device-id string + | +--rw location -> ../../../locations/location/location-id + | +--rw management + | +--rw transport? identityref + | +--rw address? inet:ip-address + +--rw management + | +--rw type identityref + +--rw locations + | +--rw location* [location-id] + | +--rw location-id string + | +--rw address? string + | +--rw postal-code? string + | +--rw state? string + | +--rw city? string + | +--rw country-code? string + +--rw site-diversity {site-diversity}? + | +--rw groups + | +--rw group* [group-id] + | +--rw group-id string + +--rw vpn-policies + | +--rw vpn-policy* [vpn-policy-id] + | +--rw vpn-policy-id string + | +--rw entries* [id] + | +--rw id string + | +--rw filters + | | +--rw filter* [type] + | | +--rw type identityref + | | +--rw lan-tag* uint32 {lan-tag}? + | +--rw vpn* [vpn-id] + | +--rw vpn-id -> /l2vpn-svc/vpn-services/vpn-service/vpn-id + | +--rw site-role? identityref + +--rw service + | +--rw qos {qos}? + | | +--rw qos-classification-policy + | | | +--rw rule* [id] + | | | +--rw id string + | | | +--rw (match-type)? + | | | | +--:(match-flow) + | | | | | +--rw match-flow + | | | | | +--rw dscp? inet:dscp + | | | | | +--rw dot1q? uint16 + | | | | | +--rw pcp? uint8 + | | | | | +--rw src-mac? yang:mac-address + | | | | | +--rw dst-mac? yang:mac-address + | | | | | +--rw color-type? identityref + | | | | | +--rw target-sites* svc-id {target-sites}? + | | | | | +--rw any? empty + | | | | | +--rw vpn-id? svc-id + | | | | +--:(match-application) + | | | | +--rw match-application? identityref + | | | +--rw target-class-id? string + | | +--rw qos-profile + | | +--rw (qos-profile)? + | | +--:(standard) + | | | +--rw profile? -> /l2vpn-svc/vpn-profiles/valid-provider-identifiers/qos-profile-identifier + | | +--:(custom) + | | +--rw classes {qos-custom}? + | | +--rw class* [class-id] + | | +--rw class-id string + | | +--rw direction? identityref + | | +--rw policing? identityref + | | +--rw byte-offset? uint16 + | | +--rw frame-delay + | | | +--rw (flavor)? + | | | +--:(lowest) + | | | | +--rw use-lowest-latency? empty + | | | +--:(boundary) + | | | +--rw delay-bound? uint16 + | | +--rw frame-jitter + | | | +--rw (flavor)? + | | | +--:(lowest) + | | | | +--rw use-lowest-jitter? empty + | | | +--:(boundary) + | | | +--rw delay-bound? uint32 + | | +--rw frame-loss + | | | +--rw rate? decimal64 + | | +--rw bandwidth + | | +--rw guaranteed-bw-percent decimal64 + | | +--rw end-to-end? empty + | +--rw carrierscarrier {carrierscarrier}? + | +--rw signaling-type? identityref + +--rw broadcast-unknown-unicast-multicast {bum}? + | +--rw multicast-site-type? enumeration + | +--rw multicast-gp-address-mapping* [id] + | | +--rw id uint16 + | | +--rw vlan-id uint16 + | | +--rw mac-gp-address yang:mac-address + | | +--rw port-lag-number? uint32 + | +--rw bum-overall-rate? uint64 + | +--rw bum-rate-per-type* [type] + | +--rw type identityref + | +--rw rate? uint64 + +--rw mac-loop-prevention {mac-loop-prevention}? + | +--rw protection-type? identityref + | +--rw frequency? uint32 + | +--rw retry-timer? uint32 + +--rw access-control-list {acl}? + | +--rw mac* [mac-address] + | +--rw mac-address yang:mac-address + +--ro actual-site-start? yang:date-and-time + +--ro actual-site-stop? yang:date-and-time + +--rw bundling-type? identityref + +--rw default-ce-vlan-id uint32 + +--rw site-network-accesses + +--rw site-network-access* [network-access-id] + +--rw network-access-id string + +--rw remote-carrier-name? -> /l2vpn-svc/vpn-profiles/valid-provider-identifiers/remote-carrier-identifier + +--rw type? identityref + +--rw (location-flavor) + | +--:(location) + | | +--rw location-reference? -> ../../../locations/location/location-id + | +--:(device) + | +--rw device-reference? -> ../../../devices/device/device-id + +--rw access-diversity {site-diversity}? + | +--rw groups + | | +--rw group* [group-id] + | | +--rw group-id string + | +--rw constraints + | +--rw constraint* [constraint-type] + | +--rw constraint-type identityref + | +--rw target + | +--rw (target-flavor)? + | +--:(id) + | | +--rw group* [group-id] + | | +--rw group-id string + | +--:(all-accesses) + | | +--rw all-other-accesses? empty + | +--:(all-groups) + | +--rw all-other-groups? empty + +--rw bearer + | +--rw requested-type {requested-type}? + | | +--rw type? string + | | +--rw strict? boolean + | +--rw always-on? boolean {always-on}? + | +--rw bearer-reference? string {bearer-reference}? + +--rw connection + | +--rw encapsulation-type? identityref + | +--rw eth-inf-type? identityref + | +--rw tagged-interface + | | +--rw type? identityref + | | +--rw dot1q-vlan-tagged {dot1q}? + | | | +--rw tg-type? identityref + | | | +--rw cvlan-id uint16 + | | +--rw priority-tagged + | | | +--rw tag-type? identityref + | | +--rw qinq {qinq}? + | | | +--rw tag-type? identityref + | | | +--rw svlan-id uint16 + | | | +--rw cvlan-id uint16 + | | +--rw qinany {qinany}? + | | | +--rw tag-type? identityref + | | | +--rw svlan-id uint16 + | | +--rw vxlan {vxlan}? + | | +--rw vni-id uint32 + | | +--rw peer-mode? identityref + | | +--rw peer-list* [peer-ip] + | | +--rw peer-ip inet:ip-address + | +--rw untagged-interface + | | +--rw speed? uint32 + | | +--rw mode? neg-mode + | | +--rw phy-mtu? uint32 + | | +--rw lldp? boolean + | | +--rw oam-802.3ah-link {oam-3ah}? + | | | +--rw enabled? boolean + | | +--rw uni-loop-prevention? boolean + | +--rw lag-interfaces {lag-interface}? + | | +--rw lag-interface* [index] + | | +--rw index string + | | +--rw lacp {lacp}? + | | +--rw enabled? boolean + | | +--rw mode? neg-mode + | | +--rw speed? uint32 + | | +--rw mini-link-num? uint32 + | | +--rw system-priority? uint16 + | | +--rw micro-bfd {micro-bfd}? + | | | +--rw enabled? enumeration + | | | +--rw interval? uint32 + | | | +--rw hold-timer? uint32 + | | +--rw bfd {bfd}? + | | | +--rw enabled? boolean + | | | +--rw (holdtime)? + | | | +--:(profile) + | | | | +--rw profile-name? -> /l2vpn-svc/vpn-profiles/valid-provider-identifiers/bfd-profile-identifier + | | | +--:(fixed) + | | | +--rw fixed-value? uint32 + | | +--rw member-links + | | | +--rw member-link* [name] + | | | +--rw name string + | | | +--rw speed? uint32 + | | | +--rw mode? neg-mode + | | | +--rw link-mtu? uint32 + | | | +--rw oam-802.3ah-link {oam-3ah}? + | | | +--rw enabled? boolean + | | +--rw flow-control? boolean + | | +--rw lldp? boolean + | +--rw cvlan-id-to-svc-map* [svc-id] + | | +--rw svc-id -> /l2vpn-svc/vpn-services/vpn-service/vpn-id + | | +--rw cvlan-id* [vid] + | | +--rw vid uint16 + | +--rw l2cp-control {l2cp-control}? + | | +--rw stp-rstp-mstp? control-mode + | | +--rw pause? control-mode + | | +--rw lacp-lamp? control-mode + | | +--rw link-oam? control-mode + | | +--rw esmc? control-mode + | | +--rw l2cp-802.1x? control-mode + | | +--rw e-lmi? control-mode + | | +--rw lldp? boolean + | | +--rw ptp-peer-delay? control-mode + | | +--rw garp-mrp? control-mode + | +--rw oam {ethernet-oam}? + | +--rw md-name string + | +--rw md-level uint16 + | +--rw cfm-8021-ag* [maid] {cfm}? + | | +--rw maid string + | | +--rw mep-id? uint32 + | | +--rw mep-level? uint32 + | | +--rw mep-up-down? enumeration + | | +--rw remote-mep-id? uint32 + | | +--rw cos-for-cfm-pdus? uint32 + | | +--rw ccm-interval? uint32 + | | +--rw ccm-holdtime? uint32 + | | +--rw alarm-priority-defect? identityref + | | +--rw ccm-p-bits-pri? ccm-priority-type + | +--rw y-1731* [maid] {y-1731}? + | +--rw maid string + | +--rw mep-id? uint32 + | +--rw type? identityref + | +--rw remote-mep-id? uint32 + | +--rw message-period? uint32 + | +--rw measurement-interval? uint32 + | +--rw cos? uint32 + | +--rw loss-measurement? boolean + | +--rw synthetic-loss-measurement? boolean + | +--rw delay-measurement + | | +--rw enable-dm? boolean + | | +--rw two-way? boolean + | +--rw frame-size? uint32 + | +--rw session-type? enumeration + +--rw availability + | +--rw access-priority? uint32 + | +--rw (redundancy-mode)? + | +--:(single-active) + | | +--rw single-active? empty + | +--:(all-active) + | +--rw all-active? empty + +--rw vpn-attachment + | +--rw (attachment-flavor) + | +--:(vpn-id) + | | +--rw vpn-id? -> /l2vpn-svc/vpn-services/vpn-service/vpn-id + | | +--rw site-role? identityref + | +--:(vpn-policy-id) + | +--rw vpn-policy-id? -> ../../../../vpn-policies/vpn-policy/vpn-policy-id + +--rw service + | +--rw svc-bandwidth {input-bw}? + | | +--rw bandwidth* [direction type] + | | +--rw direction identityref + | | +--rw type identityref + | | +--rw cos-id? uint8 + | | +--rw vpn-id? svc-id + | | +--rw cir uint64 + | | +--rw cbs uint64 + | | +--rw eir? uint64 + | | +--rw ebs? uint64 + | | +--rw pir? uint64 + | | +--rw pbs? uint64 + | +--rw svc-mtu uint16 + | +--rw qos {qos}? + | | +--rw qos-classification-policy + | | | +--rw rule* [id] + | | | +--rw id string + | | | +--rw (match-type)? + | | | | +--:(match-flow) + | | | | | +--rw match-flow + | | | | | +--rw dscp? inet:dscp + | | | | | +--rw dot1q? uint16 + | | | | | +--rw pcp? uint8 + | | | | | +--rw src-mac? yang:mac-address + | | | | | +--rw dst-mac? yang:mac-address + | | | | | +--rw color-type? identityref + | | | | | +--rw target-sites* svc-id {target-sites}? + | | | | | +--rw any? empty + | | | | | +--rw vpn-id? svc-id + | | | | +--:(match-application) + | | | | +--rw match-application? identityref + | | | +--rw target-class-id? string + | | +--rw qos-profile + | | +--rw (qos-profile)? + | | +--:(standard) + | | | +--rw profile? -> /l2vpn-svc/vpn-profiles/valid-provider-identifiers/qos-profile-identifier + | | +--:(custom) + | | +--rw classes {qos-custom}? + | | +--rw class* [class-id] + | | +--rw class-id string + | | +--rw direction? identityref + | | +--rw policing? identityref + | | +--rw byte-offset? uint16 + | | +--rw frame-delay + | | | +--rw (flavor)? + | | | +--:(lowest) + | | | | +--rw use-lowest-latency? empty + | | | +--:(boundary) + | | | +--rw delay-bound? uint16 + | | +--rw frame-jitter + | | | +--rw (flavor)? + | | | +--:(lowest) + | | | | +--rw use-lowest-jitter? empty + | | | +--:(boundary) + | | | +--rw delay-bound? uint32 + | | +--rw frame-loss + | | | +--rw rate? decimal64 + | | +--rw bandwidth + | | +--rw guaranteed-bw-percent decimal64 + | | +--rw end-to-end? empty + | +--rw carrierscarrier {carrierscarrier}? + | +--rw signaling-type? identityref + +--rw broadcast-unknown-unicast-multicast {bum}? + | +--rw multicast-site-type? enumeration + | +--rw multicast-gp-address-mapping* [id] + | | +--rw id uint16 + | | +--rw vlan-id uint16 + | | +--rw mac-gp-address yang:mac-address + | | +--rw port-lag-number? uint32 + | +--rw bum-overall-rate? uint64 + | +--rw bum-rate-per-type* [type] + | +--rw type identityref + | +--rw rate? uint64 + +--rw mac-loop-prevention {mac-loop-prevention}? + | +--rw protection-type? identityref + | +--rw frequency? uint32 + | +--rw retry-timer? uint32 + +--rw access-control-list {acl}? + | +--rw mac* [mac-address] + | +--rw mac-address yang:mac-address + +--rw mac-addr-limit {mac-addr-limit}? + +--rw limit-number? uint16 + +--rw time-interval? uint32 + +--rw action? identityref diff --git a/src/nbi/service/ietf_l3vpn/L3VPN_Service.py b/src/nbi/service/ietf_l3vpn/L3VPN_Service.py index 610fba692ac5aefc6b96fc6737eae3c8c63973c4..659d8c7f59a7eb865058d5d99c184ddd375f344e 100644 --- a/src/nbi/service/ietf_l3vpn/L3VPN_Service.py +++ b/src/nbi/service/ietf_l3vpn/L3VPN_Service.py @@ -16,7 +16,7 @@ import logging from flask import request from flask.json import jsonify from flask_restful import Resource -from common.proto.context_pb2 import ServiceStatusEnum +from common.proto.context_pb2 import ServiceStatusEnum, ServiceTypeEnum from common.tools.context_queries.Service import get_service_by_uuid from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient @@ -24,7 +24,7 @@ from typing import Dict, List from werkzeug.exceptions import UnsupportedMediaType from nbi.service._tools.Authentication import HTTP_AUTH from nbi.service._tools.HttpStatusCodes import ( - HTTP_GATEWAYTIMEOUT, HTTP_NOCONTENT, HTTP_OK, HTTP_SERVERERROR, HTTP_CREATED + HTTP_GATEWAYTIMEOUT, HTTP_NOCONTENT, HTTP_OK, HTTP_SERVERERROR ) from .Handlers import update_vpn from .YangValidator import YangValidator @@ -32,7 +32,7 @@ from .YangValidator import YangValidator LOGGER = logging.getLogger(__name__) class L3VPN_Service(Resource): - # @HTTP_AUTH.login_required + @HTTP_AUTH.login_required def get(self, vpn_id : str): LOGGER.debug('VPN_Id: {:s}'.format(str(vpn_id))) LOGGER.debug('Request: {:s}'.format(str(request))) @@ -43,6 +43,9 @@ class L3VPN_Service(Resource): target = get_service_by_uuid(context_client, vpn_id, rw_copy=True) if target is None: raise Exception('VPN({:s}) not found in database'.format(str(vpn_id))) + + if target.service_type != ServiceTypeEnum.SERVICETYPE_L3NM: + raise Exception('VPN({:s}) is not L3VPN'.format(str(vpn_id))) service_ids = {target.service_id.service_uuid.uuid, target.name} # pylint: disable=no-member if vpn_id not in service_ids: @@ -58,7 +61,7 @@ class L3VPN_Service(Resource): response.status_code = HTTP_SERVERERROR return response - # @HTTP_AUTH.login_required + @HTTP_AUTH.login_required def delete(self, vpn_id : str): LOGGER.debug('VPN_Id: {:s}'.format(str(vpn_id))) LOGGER.debug('Request: {:s}'.format(str(request))) @@ -69,6 +72,8 @@ class L3VPN_Service(Resource): target = get_service_by_uuid(context_client, vpn_id) if target is None: LOGGER.warning('VPN({:s}) not found in database. Nothing done.'.format(str(vpn_id))) + elif target.service_type != ServiceTypeEnum.SERVICETYPE_L3NM: + raise Exception('VPN({:s}) is not L3VPN'.format(str(vpn_id))) else: service_ids = {target.service_id.service_uuid.uuid, target.name} # pylint: disable=no-member if vpn_id not in service_ids: @@ -102,7 +107,7 @@ class L3VPN_Service(Resource): errors.append('Unexpected request format: {:s}'.format(str(request_data))) response = jsonify(errors) - response.status_code = HTTP_CREATED if len(errors) == 0 else HTTP_SERVERERROR + response.status_code = HTTP_NOCONTENT if len(errors) == 0 else HTTP_SERVERERROR return response def _update_l3vpn(self, request_data: Dict) -> List[Dict]: diff --git a/src/nbi/service/ietf_l3vpn/L3VPN_Services.py b/src/nbi/service/ietf_l3vpn/L3VPN_Services.py index 2396ae738febc635523a29726f5219fb91d6cadf..3b3426f20b37146bdbc734beefb6b7fb2f41ef7e 100644 --- a/src/nbi/service/ietf_l3vpn/L3VPN_Services.py +++ b/src/nbi/service/ietf_l3vpn/L3VPN_Services.py @@ -26,11 +26,11 @@ from .YangValidator import YangValidator LOGGER = logging.getLogger(__name__) class L3VPN_Services(Resource): - # @HTTP_AUTH.login_required + @HTTP_AUTH.login_required def get(self): return {} - # @HTTP_AUTH.login_required + @HTTP_AUTH.login_required def post(self): if not request.is_json: raise UnsupportedMediaType('JSON payload is required') request_data : Dict = request.json @@ -58,7 +58,7 @@ class L3VPN_Services(Resource): # "vpn-service": [ errors.extend(self._process_l3vpn(request_data)) else: - errors.append('unexpected request: {:s}'.format(str(request_data))) + errors.append('Unexpected request: {:s}'.format(str(request_data))) response = jsonify(errors) response.status_code = HTTP_CREATED if len(errors) == 0 else HTTP_SERVERERROR diff --git a/src/nbi/tests/test_ietf_l2vpn.py b/src/nbi/tests/test_ietf_l2vpn.py index 3ffa576dea5b30d8ff25a638da2f504980ece76f..1882a6e60a4d1d33515c3eaf246cecb65afe6c11 100644 --- a/src/nbi/tests/test_ietf_l2vpn.py +++ b/src/nbi/tests/test_ietf_l2vpn.py @@ -20,18 +20,24 @@ eventlet.monkey_patch() #pylint: disable=wrong-import-position import logging from common.Constants import DEFAULT_CONTEXT_NAME -from common.proto.context_pb2 import ContextId -from common.tools.descriptor.Loader import DescriptorLoader, check_descriptor_load_results, validate_empty_scenario +from common.proto.context_pb2 import ContextId, ServiceStatusEnum +from common.tools.context_queries.Service import get_service_by_uuid +from common.tools.descriptor.Loader import ( + DescriptorLoader, check_descriptor_load_results, validate_empty_scenario +) from common.tools.object_factory.Context import json_context_id from context.client.ContextClient import ContextClient from tests.tools.mock_osm.MockOSM import MockOSM -from .OSM_Constants import SERVICE_CONNECTION_POINTS_1, SERVICE_CONNECTION_POINTS_2, SERVICE_TYPE +from .OSM_Constants import ( + SERVICE_CONNECTION_POINTS_1, SERVICE_CONNECTION_POINTS_2, SERVICE_TYPE +) from .PrepareTestScenario import ( # pylint: disable=unused-import # be careful, order of symbols is important here! nbi_application, osm_wim, context_client ) +logging.getLogger('ro.sdn.ietfl2vpn').setLevel(logging.DEBUG) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) @@ -53,9 +59,21 @@ def test_prepare_environment(context_client : ContextClient) -> None: # pylint: assert len(response.service_ids ) == 0 assert len(response.slice_ids ) == 0 -def test_create_service(osm_wim : MockOSM): # pylint: disable=redefined-outer-name +def test_create_service(osm_wim : MockOSM, context_client : ContextClient): # pylint: disable=redefined-outer-name osm_wim.create_connectivity_service(SERVICE_TYPE, SERVICE_CONNECTION_POINTS_1) + # Emulate service activation for the test + service_uuid = list(osm_wim.conn_info.keys())[0] # this test adds a single service + + service = get_service_by_uuid( + context_client, service_uuid, rw_copy=True, include_endpoint_ids=False, + include_constraints=False, include_config_rules=False + ) + if service is None: + raise Exception('Unable to find Service({:s})'.format(str(service_uuid))) + service.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_ACTIVE + context_client.SetService(service) + def test_get_service_status(osm_wim : MockOSM): # pylint: disable=redefined-outer-name service_uuid = list(osm_wim.conn_info.keys())[0] # this test adds a single service osm_wim.get_connectivity_service_status(service_uuid)