diff --git a/proto/context.proto b/proto/context.proto
index 87f69132df022e2aa4a0766dc9f0a7a7fae36d59..40f54b13588ec40b244a5cfed0171069796faa59 100644
--- a/proto/context.proto
+++ b/proto/context.proto
@@ -16,6 +16,7 @@ syntax = "proto3";
package context;
import "acl.proto";
+import "ip_link.proto";
import "kpi_sample_types.proto";
service ContextService {
@@ -300,6 +301,7 @@ enum ServiceTypeEnum {
SERVICETYPE_TE = 4;
SERVICETYPE_E2E = 5;
SERVICETYPE_OPTICAL_CONNECTIVITY = 6;
+ SERVICETYPE_IPLINK = 7;
}
enum ServiceStatusEnum {
@@ -512,11 +514,17 @@ message ConfigRule_ACL {
acl.AclRuleSet rule_set = 2;
}
+message ConfigRule_IP_LINK {
+ EndPointId endpoint_id = 1;
+ ip_link.IpLinkRuleSet rule_set = 2;
+}
+
message ConfigRule {
ConfigActionEnum action = 1;
oneof config_rule {
- ConfigRule_Custom custom = 2;
- ConfigRule_ACL acl = 3;
+ ConfigRule_Custom custom = 2;
+ ConfigRule_ACL acl = 3;
+ ConfigRule_IP_LINK ip_link = 4;
}
}
diff --git a/proto/ip_link.proto b/proto/ip_link.proto
new file mode 100644
index 0000000000000000000000000000000000000000..79a5bed5adbc749ba3e200b44d2cafea6bac7615
--- /dev/null
+++ b/proto/ip_link.proto
@@ -0,0 +1,24 @@
+// Copyright 2022-2024 ETSI OSG/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.
+
+syntax = "proto3";
+package ip_link;
+
+
+
+message IpLinkRuleSet {
+ string ip = 1;
+ string mask = 3;
+ string vlan = 4;
+}
diff --git a/src/common/tools/object_factory/Service.py b/src/common/tools/object_factory/Service.py
index 32b99a31f22072874ab894de2a87ce2b7d56ba85..642aa5a032b88bc10eea99cb174f76d5b2884d0f 100644
--- a/src/common/tools/object_factory/Service.py
+++ b/src/common/tools/object_factory/Service.py
@@ -80,4 +80,14 @@ def json_service_p4_planned(
return json_service(
service_uuid, ServiceTypeEnum.SERVICETYPE_L2NM, context_id=json_context_id(context_uuid),
status=ServiceStatusEnum.SERVICESTATUS_PLANNED, endpoint_ids=endpoint_ids, constraints=constraints,
+ config_rules=config_rules)
+
+def json_service_iplink_planned(
+ service_uuid : str, endpoint_ids : List[Dict] = [], constraints : List[Dict] = [],
+ config_rules : List[Dict] = [], context_uuid : str = DEFAULT_CONTEXT_NAME
+ ):
+
+ return json_service(
+ service_uuid, ServiceTypeEnum.SERVICETYPE_IPLINK, context_id=json_context_id(context_uuid),
+ status=ServiceStatusEnum.SERVICESTATUS_PLANNED, endpoint_ids=endpoint_ids, constraints=constraints,
config_rules=config_rules)
\ No newline at end of file
diff --git a/src/common/type_checkers/Assertions.py b/src/common/type_checkers/Assertions.py
index 90b7d976b0f6fff9d478ce7b40188240a8eea2d6..94a17f4badeded0c864050a73b8516231782f3d2 100644
--- a/src/common/type_checkers/Assertions.py
+++ b/src/common/type_checkers/Assertions.py
@@ -79,6 +79,7 @@ def validate_service_type_enum(message):
'SERVICETYPE_TAPI_CONNECTIVITY_SERVICE',
'SERVICETYPE_TE',
'SERVICETYPE_E2E',
+ 'SERVICETYPE_IPLINK'
]
def validate_service_state_enum(message):
@@ -116,6 +117,7 @@ def validate_uuid(message, allow_empty=False):
CONFIG_RULE_TYPES = {
'custom',
'acl',
+ 'ip_link'
}
def validate_config_rule(message):
assert isinstance(message, dict)
diff --git a/src/context/service/database/ConfigRule.py b/src/context/service/database/ConfigRule.py
index 7d816b3e87803f71678511f4fadc6bbe7eba548e..e2b19420a617617cf1d4369befce20b9d45ff842 100644
--- a/src/context/service/database/ConfigRule.py
+++ b/src/context/service/database/ConfigRule.py
@@ -68,6 +68,9 @@ def compose_config_rules_data(
_, _, endpoint_uuid = endpoint_get_uuid(config_rule.acl.endpoint_id, allow_random=False)
rule_set_name = config_rule.acl.rule_set.name
configrule_name = '{:s}:{:s}:{:s}:{:s}'.format(parent_kind, kind.value, endpoint_uuid, rule_set_name)
+ elif kind == ConfigRuleKindEnum.IP_LINK:
+ _, _, endpoint_uuid = endpoint_get_uuid(config_rule.ip_link.endpoint_id, allow_random=False)
+ configrule_name = '{:s}:{:s}:{:s}'.format(parent_kind, kind.value, endpoint_uuid)
else:
MSG = 'Name for ConfigRule({:s}) cannot be inferred '+\
'(device_uuid={:s}, service_uuid={:s}, slice_uuid={:s})'
diff --git a/src/context/service/database/Link.py b/src/context/service/database/Link.py
index 8aa2563e4b3bb5b46ffdefe4644cdfe321f1e734..87ec27eb8bc46945807c5b902638fd8414b027ee 100644
--- a/src/context/service/database/Link.py
+++ b/src/context/service/database/Link.py
@@ -74,12 +74,12 @@ def link_set(db_engine : Engine, messagebroker : MessageBroker, request : Link)
related_topologies : List[Dict] = list()
# By default, always add link to default Context/Topology
- _,topology_uuid = topology_get_uuid(TopologyId(), allow_random=False, allow_default=True)
- related_topologies.append({
- 'topology_uuid': topology_uuid,
- 'link_uuid' : link_uuid,
- })
- topology_uuids.add(topology_uuid)
+ # _,topology_uuid = topology_get_uuid(TopologyId(), allow_random=False, allow_default=True)
+ # related_topologies.append({
+ # 'topology_uuid': topology_uuid,
+ # 'link_uuid' : link_uuid,
+ # })
+ # topology_uuids.add(topology_uuid)
link_endpoints_data : List[Dict] = list()
for i,endpoint_id in enumerate(request.link_endpoint_ids):
diff --git a/src/context/service/database/Service.py b/src/context/service/database/Service.py
index ba042fe8fd079172df66526732edbea660d2d9fa..2da31d58d2870f36a11c97378a29a875efca8725 100644
--- a/src/context/service/database/Service.py
+++ b/src/context/service/database/Service.py
@@ -88,6 +88,8 @@ def service_set(db_engine : Engine, messagebroker : MessageBroker, request : Ser
service_type = grpc_to_enum__service_type(request.service_type)
if service_type is None and request.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
service_type = "OPTICAL_CONNECTIVITY"
+ if service_type is None and request.service_type == ServiceTypeEnum.SERVICETYPE_IPLINK :
+ service_type = "IP_LINK"
service_status = grpc_to_enum__service_status(request.service_status.service_status)
diff --git a/src/context/service/database/models/ConfigRuleModel.py b/src/context/service/database/models/ConfigRuleModel.py
index f57c90b82b950e68103e1381c6ff0b118e6307df..5799934a76c0240535984ecf297b0baf54426450 100644
--- a/src/context/service/database/models/ConfigRuleModel.py
+++ b/src/context/service/database/models/ConfigRuleModel.py
@@ -21,8 +21,9 @@ from ._Base import _Base
# Enum values should match name of field in ConfigRule message
class ConfigRuleKindEnum(enum.Enum):
- CUSTOM = 'custom'
- ACL = 'acl'
+ CUSTOM = 'custom'
+ ACL = 'acl'
+ IP_LINK = 'ip_link'
class DeviceConfigRuleModel(_Base):
__tablename__ = 'device_configrule'
diff --git a/src/context/service/database/models/enums/ServiceType.py b/src/context/service/database/models/enums/ServiceType.py
index 62d5380b56803b3cc21dd1456292ec9df470cb15..bcc5aff09da2899470d6c56e82cad5a6d0f00f95 100644
--- a/src/context/service/database/models/enums/ServiceType.py
+++ b/src/context/service/database/models/enums/ServiceType.py
@@ -29,6 +29,7 @@ class ORM_ServiceTypeEnum(enum.Enum):
TE = ServiceTypeEnum.SERVICETYPE_TE
E2E = ServiceTypeEnum.SERVICETYPE_E2E
OPTICAL_CONNECTIVITY = ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY
+ IP_LINK = ServiceTypeEnum.SERVICETYPE_IPLINK
grpc_to_enum__service_type = functools.partial(
grpc_to_enum, ServiceTypeEnum, ORM_ServiceTypeEnum)
diff --git a/src/device/requirements.in b/src/device/requirements.in
index 73ea741d16dcdafd7a9be87ad79b457ccb6c5d5e..6f20b0de1c62eee000a22244f38b2ab0fd4aefd5 100644
--- a/src/device/requirements.in
+++ b/src/device/requirements.in
@@ -23,7 +23,7 @@ Flask==2.1.3
Flask-HTTPAuth==4.5.0
Flask-RESTful==0.3.9
Jinja2==3.0.3
-ncclient==0.6.13
+ncclient==0.6.15
p4runtime==1.3.0
pandas==1.5.*
paramiko==2.9.2
diff --git a/src/device/service/Tools.py b/src/device/service/Tools.py
index 91926b9e59cccac2e233ac14bbac497bbb0ac15c..8eb25578488dd0fe5b1781a0e129709b86df69fa 100644
--- a/src/device/service/Tools.py
+++ b/src/device/service/Tools.py
@@ -306,7 +306,13 @@ def compute_rules_to_add_delete(
ACL_KEY_TEMPLATE = '/device[{:s}]/endpoint[{:s}]/acl_ruleset[{:s}]'
key_or_path = ACL_KEY_TEMPLATE.format(device_uuid, endpoint_uuid, acl_ruleset_name)
context_config_rules[key_or_path] = grpc_message_to_json(config_rule.acl) # get the resource value of the acl
-
+ elif config_rule_kind == 'ip_link':
+ device_uuid = config_rule.ip_link.endpoint_id.device_id.device_uuid.uuid # get the device name
+ endpoint_uuid = config_rule.ip_link.endpoint_id.endpoint_uuid.uuid # get the endpoint name request_config_rules = []
+ ip_link_ruleset_name = config_rule.ip_link.rule_set.name # get the ip_link name
+ IP_LINK_KEY_TEMPLATE = '/device[{:s}]/endpoint[{:s}]/ip_link_ruleset[{:s}]'
+ key_or_path = IP_LINK_KEY_TEMPLATE.format(device_uuid, endpoint_uuid, ip_link_ruleset_name)
+ context_config_rules[key_or_path] = grpc_message_to_json(config_rule.ip_link) # get the resource value of the ip_link
request_config_rules = []
for config_rule in request.device_config.config_rules:
config_rule_kind = config_rule.WhichOneof('config_rule')
@@ -323,6 +329,15 @@ def compute_rules_to_add_delete(
request_config_rules.append((
config_rule.action, key_or_path, grpc_message_to_json(config_rule.acl)
))
+ elif config_rule_kind == 'ip_link': # resource management of "ip_link" rule
+ device_uuid = config_rule.ip_link.endpoint_id.device_id.device_uuid.uuid
+ endpoint_uuid = config_rule.ip_link.endpoint_id.endpoint_uuid.uuid
+ ip_link_ruleset_name = config_rule.ip_link.rule_set.name
+ IP_LINK_KEY_TEMPLATE = '/device[{:s}]/endpoint[{:s}]/ip_link_ruleset[{:s}]'
+ key_or_path = IP_LINK_KEY_TEMPLATE.format(device_uuid, endpoint_uuid, ip_link_ruleset_name)
+ request_config_rules.append((
+ config_rule.action, key_or_path, grpc_message_to_json(config_rule.ip_link)
+ ))
resources_to_set : List[Tuple[str, Any]] = [] # key, value
resources_to_delete : List[Tuple[str, Any]] = [] # key, value
diff --git a/src/pathcomp/frontend/service/algorithms/_Algorithm.py b/src/pathcomp/frontend/service/algorithms/_Algorithm.py
index 3ed2b13fb33ae06faeacc4286959a8016ca995d1..d4e4194497be44bf9eb0176bcc9014e9402e582c 100644
--- a/src/pathcomp/frontend/service/algorithms/_Algorithm.py
+++ b/src/pathcomp/frontend/service/algorithms/_Algorithm.py
@@ -23,7 +23,7 @@ from pathcomp.frontend.Config import BACKEND_URL
from .tools.EroPathToHops import eropath_to_hops
from .tools.ComposeConfigRules import (
compose_device_config_rules, compose_l2nm_config_rules, compose_l3nm_config_rules, compose_tapi_config_rules,
- generate_neighbor_endpoint_config_rules
+ generate_neighbor_endpoint_config_rules, compose_iplink_config_rules
)
from .tools.ComposeRequest import compose_device, compose_link, compose_service
from .tools.ComputeSubServices import (
@@ -182,6 +182,8 @@ class _Algorithm:
compose_l3nm_config_rules(config_rules, service.service_config.config_rules)
elif service_type == ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE:
compose_tapi_config_rules(config_rules, service.service_config.config_rules)
+ if service_type == ServiceTypeEnum.SERVICETYPE_IPLINK:
+ compose_iplink_config_rules(config_rules, service.service_config.config_rules)
else:
MSG = 'Unhandled generic Config Rules for service {:s} {:s}'
self.logger.warning(MSG.format(str(service_uuid), str(ServiceTypeEnum.Name(service_type))))
diff --git a/src/pathcomp/frontend/service/algorithms/tools/ComposeConfigRules.py b/src/pathcomp/frontend/service/algorithms/tools/ComposeConfigRules.py
index f92f9b2fff11ab585813ab59e07c463f361413d2..f96291e20b0d93fbf8102295d9ed8347e301760a 100644
--- a/src/pathcomp/frontend/service/algorithms/tools/ComposeConfigRules.py
+++ b/src/pathcomp/frontend/service/algorithms/tools/ComposeConfigRules.py
@@ -52,6 +52,10 @@ TAPI_SETTINGS_FIELD_DEFAULTS = {
'direction' : 'UNIDIRECTIONAL',
}
+IPLINK_SETTINGS_FIELD_DEFAULTS = {
+ 'mtu' : 1450,
+}
+
def find_custom_config_rule(config_rules : List, resource_name : str) -> Optional[Dict]:
resource_value : Optional[Dict] = None
for config_rule in config_rules:
@@ -103,7 +107,12 @@ def compose_tapi_config_rules(main_service_config_rules : List, subservice_confi
]
for rule_name, defaults in CONFIG_RULES:
compose_config_rules(main_service_config_rules, subservice_config_rules, rule_name, defaults)
-
+
+def compose_iplink_config_rules(main_service_config_rules : List, subservice_config_rules : List) -> None:
+ CONFIG_RULES: List[Tuple[str, dict]] = [(SETTINGS_RULE_NAME, IPLINK_SETTINGS_FIELD_DEFAULTS)]
+ for rule_name, defaults in CONFIG_RULES:
+ compose_config_rules(main_service_config_rules, subservice_config_rules, rule_name, defaults)
+
def compose_device_config_rules(
config_rules : List, subservice_config_rules : List, path_hops : List,
device_name_mapping : Dict[str, str], endpoint_name_mapping : Dict[Tuple[str, str], str]
@@ -152,6 +161,31 @@ def compose_device_config_rules(
LOGGER.debug('[compose_device_config_rules] adding acl config rule')
subservice_config_rules.append(config_rule)
+
+ elif config_rule.WhichOneof('config_rule') == 'ip_link':
+ LOGGER.debug('[compose_device_config_rules] is ip_link')
+ endpoint_id = config_rule.ip_link.endpoint_id
+ device_uuid_or_name = endpoint_id.device_id.device_uuid.uuid
+ LOGGER.debug('[compose_device_config_rules] device_uuid_or_name={:s}'.format(str(device_uuid_or_name)))
+ device_name_or_uuid = device_name_mapping.get(device_uuid_or_name, device_uuid_or_name)
+ LOGGER.debug('[compose_device_config_rules] device_name_or_uuid={:s}'.format(str(device_name_or_uuid)))
+ device_keys = {device_uuid_or_name, device_name_or_uuid}
+ if len(device_keys.intersection(devices_traversed)) == 0: continue
+
+ endpoint_uuid = endpoint_id.endpoint_uuid.uuid
+ LOGGER.debug('[compose_device_config_rules] endpoint_uuid={:s}'.format(str(endpoint_uuid)))
+ # given endpoint uuids link 'eth-1/0/20.533', remove last part after the '.'
+ endpoint_uuid_or_name = (endpoint_uuid[::-1].split('.', maxsplit=1)[-1])[::-1]
+ LOGGER.debug('[compose_device_config_rules] endpoint_uuid_or_name={:s}'.format(str(endpoint_uuid_or_name)))
+ endpoint_name_or_uuid_1 = endpoint_name_mapping[(device_uuid_or_name, endpoint_uuid_or_name)]
+ endpoint_name_or_uuid_2 = endpoint_name_mapping[(device_name_or_uuid, endpoint_uuid_or_name)]
+ endpoint_keys = {endpoint_uuid_or_name, endpoint_name_or_uuid_1, endpoint_name_or_uuid_2}
+
+ device_endpoint_keys = set(itertools.product(device_keys, endpoint_keys))
+ if len(device_endpoint_keys.intersection(endpoints_traversed)) == 0: continue
+
+ LOGGER.debug('[compose_device_config_rules] adding ip_link config rule')
+ subservice_config_rules.append(config_rule)
elif config_rule.WhichOneof('config_rule') == 'custom':
LOGGER.debug('[compose_device_config_rules] is custom')
@@ -288,48 +322,54 @@ def generate_neighbor_endpoint_config_rules(
for config_rule in config_rules:
# Only applicable, by now, to Custom Config Rules for endpoint settings
- if 'custom' not in config_rule: continue
- match = RE_ENDPOINT_SETTINGS.match(config_rule['custom']['resource_key'])
- if match is None:
- match = RE_ENDPOINT_VLAN_SETTINGS.match(config_rule['custom']['resource_key'])
- if match is None: continue
-
- resource_key_values = match.groups()
- if resource_key_values[0:2] in device_endpoint_keys_a:
- resource_key_values = list(resource_key_values)
- resource_key_values[0] = link_endpoint_b['device']
- resource_key_values[1] = link_endpoint_b['ingress_ep']
- elif resource_key_values[0:2] in device_endpoint_keys_b:
- resource_key_values = list(resource_key_values)
- resource_key_values[0] = link_endpoint_a['device']
- resource_key_values[1] = link_endpoint_a['egress_ep']
- else:
- continue
-
- device_keys = compute_device_keys(resource_key_values[0], device_name_mapping)
- device_names = {device_key for device_key in device_keys if RE_UUID.match(device_key) is None}
- if len(device_names) != 1:
- MSG = 'Unable to identify name for Device({:s}): device_keys({:s})'
- raise Exception(MSG.format(str(resource_key_values[0]), str(device_keys)))
- resource_key_values[0] = device_names.pop()
-
- endpoint_keys = compute_endpoint_keys(device_keys, resource_key_values[1], endpoint_name_mapping)
- endpoint_names = {endpoint_key for endpoint_key in endpoint_keys if RE_UUID.match(endpoint_key) is None}
- if len(endpoint_names) != 1:
- MSG = 'Unable to identify name for Endpoint({:s}): endpoint_keys({:s})'
- raise Exception(MSG.format(str(resource_key_values[1]), str(endpoint_keys)))
- resource_key_values[1] = endpoint_names.pop()
-
- resource_value : Dict = json.loads(config_rule['custom']['resource_value'])
- if 'neighbor_address' not in resource_value: continue
- resource_value['ip_address'] = resource_value.pop('neighbor_address')
-
- # remove neighbor_address also from original rule as it is already consumed
-
- resource_key_template = TMPL_ENDPOINT_VLAN_SETTINGS if len(match.groups()) == 3 else TMPL_ENDPOINT_SETTINGS
+ if 'custom' not in config_rule or 'ip_link' not in config_rule: continue
+ if 'custom' in config_rule:
+ match = RE_ENDPOINT_SETTINGS.match(config_rule['custom']['resource_key'])
+ if match is None:
+ match = RE_ENDPOINT_VLAN_SETTINGS.match(config_rule['custom']['resource_key'])
+ if match is None: continue
+ resource_key_values = match.groups()
+ if resource_key_values[0:2] in device_endpoint_keys_a:
+ resource_key_values = list(resource_key_values)
+ resource_key_values[0] = link_endpoint_b['device']
+ resource_key_values[1] = link_endpoint_b['ingress_ep']
+ elif resource_key_values[0:2] in device_endpoint_keys_b:
+ resource_key_values = list(resource_key_values)
+ resource_key_values[0] = link_endpoint_a['device']
+ resource_key_values[1] = link_endpoint_a['egress_ep']
+ else:
+ continue
+
+ device_keys = compute_device_keys(resource_key_values[0], device_name_mapping)
+ device_names = {device_key for device_key in device_keys if RE_UUID.match(device_key) is None}
+ if len(device_names) != 1:
+ MSG = 'Unable to identify name for Device({:s}): device_keys({:s})'
+ raise Exception(MSG.format(str(resource_key_values[0]), str(device_keys)))
+ resource_key_values[0] = device_names.pop()
+
+ endpoint_keys = compute_endpoint_keys(device_keys, resource_key_values[1], endpoint_name_mapping)
+ endpoint_names = {endpoint_key for endpoint_key in endpoint_keys if RE_UUID.match(endpoint_key) is None}
+ if len(endpoint_names) != 1:
+ MSG = 'Unable to identify name for Endpoint({:s}): endpoint_keys({:s})'
+ raise Exception(MSG.format(str(resource_key_values[1]), str(endpoint_keys)))
+ resource_key_values[1] = endpoint_names.pop()
+
+ resource_value : Dict = json.loads(config_rule['custom']['resource_value'])
+ if 'neighbor_address' not in resource_value: continue
+ resource_value['ip_address'] = resource_value.pop('neighbor_address')
+
+ # remove neighbor_address also from original rule as it is already consumed
+
+ resource_key_template = TMPL_ENDPOINT_VLAN_SETTINGS if len(match.groups()) == 3 else TMPL_ENDPOINT_SETTINGS
+ generated_config_rule = copy.deepcopy(config_rule)
+ generated_config_rule['custom']['resource_key'] = resource_key_template.format(*resource_key_values)
+ generated_config_rule['custom']['resource_value'] = json.dumps(resource_value)
+ generated_config_rules.append(generated_config_rule)
+ else:
+ LOGGER.debug('[generate_neighbor_endpoint_config_rules] IP_LINK: {:s}'.format(str(config_rule)))
+ resource_value : Dict = config_rule['ip_link']
generated_config_rule = copy.deepcopy(config_rule)
- generated_config_rule['custom']['resource_key'] = resource_key_template.format(*resource_key_values)
- generated_config_rule['custom']['resource_value'] = json.dumps(resource_value)
+ generated_config_rule['ip_link'] = json.dumps(resource_value)
generated_config_rules.append(generated_config_rule)
LOGGER.debug('[generate_neighbor_endpoint_config_rules] generated_config_rules={:s}'.format(str(generated_config_rules)))
diff --git a/src/pathcomp/frontend/service/algorithms/tools/ServiceTypes.py b/src/pathcomp/frontend/service/algorithms/tools/ServiceTypes.py
index 2792a86639fbd6852a41499e928de7a4131ed408..c47e1995e714bf35745ffecf2c908aae6b2bdb27 100644
--- a/src/pathcomp/frontend/service/algorithms/tools/ServiceTypes.py
+++ b/src/pathcomp/frontend/service/algorithms/tools/ServiceTypes.py
@@ -41,13 +41,15 @@ OPTICAL_DEVICE_TYPES = {
DeviceTypeEnum.OPTICAL_TRANSPONDER, DeviceTypeEnum.EMULATED_OPTICAL_TRANSPONDER,
}
-SERVICE_TYPE_L2NM = {ServiceTypeEnum.SERVICETYPE_L2NM}
-SERVICE_TYPE_L3NM = {ServiceTypeEnum.SERVICETYPE_L3NM}
-SERVICE_TYPE_LXNM = {ServiceTypeEnum.SERVICETYPE_L3NM, ServiceTypeEnum.SERVICETYPE_L2NM}
-SERVICE_TYPE_TAPI = {ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE}
+SERVICE_TYPE_L2NM = {ServiceTypeEnum.SERVICETYPE_L2NM}
+SERVICE_TYPE_L3NM = {ServiceTypeEnum.SERVICETYPE_L3NM}
+SERVICE_TYPE_LXNM = {ServiceTypeEnum.SERVICETYPE_L3NM, ServiceTypeEnum.SERVICETYPE_L2NM}
+SERVICE_TYPE_TAPI = {ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE}
+SERVICE_TYPE_IPLINK = {ServiceTypeEnum.SERVICETYPE_IPLINK}
+
def get_service_type(device_type : DeviceTypeEnum, prv_service_type : ServiceTypeEnum) -> ServiceTypeEnum:
- if device_type in PACKET_DEVICE_TYPES and prv_service_type in SERVICE_TYPE_LXNM: return prv_service_type
+ if device_type in PACKET_DEVICE_TYPES and (prv_service_type in SERVICE_TYPE_LXNM or prv_service_type in SERVICE_TYPE_IPLINK ): return prv_service_type
if device_type in L2_DEVICE_TYPES: return ServiceTypeEnum.SERVICETYPE_L2NM
if device_type in OPTICAL_DEVICE_TYPES: return ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE
if device_type in NETWORK_DEVICE_TYPES: return prv_service_type
diff --git a/src/policy/src/main/java/org/etsi/tfs/policy/Serializer.java b/src/policy/src/main/java/org/etsi/tfs/policy/Serializer.java
index 654e7b6ce1d68f6facaec8c772e16dde68e710f0..5ee68f2eda28c7445d2da7b05415c91c7d177d45 100644
--- a/src/policy/src/main/java/org/etsi/tfs/policy/Serializer.java
+++ b/src/policy/src/main/java/org/etsi/tfs/policy/Serializer.java
@@ -1177,6 +1177,8 @@ public class Serializer {
return ContextOuterClass.ServiceTypeEnum.SERVICETYPE_L3NM;
case TAPI_CONNECTIVITY_SERVICE:
return ContextOuterClass.ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE;
+ case IPLINK:
+ return ContextOuterClass.ServiceTypeEnum.SERVICETYPE_IPLINK;
case UNKNOWN:
return ContextOuterClass.ServiceTypeEnum.SERVICETYPE_UNKNOWN;
default:
@@ -1192,6 +1194,8 @@ public class Serializer {
return ServiceTypeEnum.L3NM;
case SERVICETYPE_TAPI_CONNECTIVITY_SERVICE:
return ServiceTypeEnum.TAPI_CONNECTIVITY_SERVICE;
+ case SERVICETYPE_IPLINK:
+ return ServiceTypeEnum.IPLINK;
case SERVICETYPE_UNKNOWN:
case UNRECOGNIZED:
default:
diff --git a/src/policy/target/generated-sources/grpc/context/ContextOuterClass.java b/src/policy/target/generated-sources/grpc/context/ContextOuterClass.java
index 4593770498216267b8d2f95dd728fccfbb9dc134..8eea2d6d82380b60f746942a2314057a7d3b29c2 100644
--- a/src/policy/target/generated-sources/grpc/context/ContextOuterClass.java
+++ b/src/policy/target/generated-sources/grpc/context/ContextOuterClass.java
@@ -504,6 +504,10 @@ public final class ContextOuterClass {
* SERVICETYPE_OPTICAL_CONNECTIVITY = 6;
*/
SERVICETYPE_OPTICAL_CONNECTIVITY(6),
+ /**
+ * SERVICETYPE_IPLINK = 7;
+ */
+ SERVICETYPE_IPLINK(7),
UNRECOGNIZED(-1);
/**
@@ -541,6 +545,11 @@ public final class ContextOuterClass {
*/
public static final int SERVICETYPE_OPTICAL_CONNECTIVITY_VALUE = 6;
+ /**
+ * SERVICETYPE_IPLINK = 7;
+ */
+ public static final int SERVICETYPE_IPLINK_VALUE = 7;
+
public final int getNumber() {
if (this == UNRECOGNIZED) {
throw new java.lang.IllegalArgumentException("Can't get the number of an unknown enum value.");
@@ -578,6 +587,8 @@ public final class ContextOuterClass {
return SERVICETYPE_E2E;
case 6:
return SERVICETYPE_OPTICAL_CONNECTIVITY;
+ case 7:
+ return SERVICETYPE_IPLINK;
default:
return null;
}
diff --git a/src/service/service/service_handler_api/FilterFields.py b/src/service/service/service_handler_api/FilterFields.py
index ca70fa9386e356e7e49397365701013e1d3a1697..e0811c0a9c53cb14fbd654797faf5f5e0522c4ac 100644
--- a/src/service/service/service_handler_api/FilterFields.py
+++ b/src/service/service/service_handler_api/FilterFields.py
@@ -26,7 +26,8 @@ SERVICE_TYPE_VALUES = {
ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE,
ServiceTypeEnum.SERVICETYPE_TE,
ServiceTypeEnum.SERVICETYPE_E2E,
- ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY
+ ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY,
+ ServiceTypeEnum.SERVICETYPE_IPLINK
}
DEVICE_DRIVER_VALUES = {
diff --git a/src/service/service/service_handler_api/SettingsHandler.py b/src/service/service/service_handler_api/SettingsHandler.py
index 293de54aa84be11f3c31bc1b47fce852df19a16a..8bfa1cd8a983ad20323525b38ab8d898c99dbde1 100644
--- a/src/service/service/service_handler_api/SettingsHandler.py
+++ b/src/service/service/service_handler_api/SettingsHandler.py
@@ -47,6 +47,12 @@ class SettingsHandler:
ACL_KEY_TEMPLATE = '/device[{:s}]/endpoint[{:s}]/index[{:d}]/acl_ruleset[{:s}]'
key_or_path = ACL_KEY_TEMPLATE.format(device_uuid, endpoint_name,endpoint_index, acl_ruleset_name)
value = grpc_message_to_json(config_rule.acl)
+ elif kind == 'ip_link':
+ device_uuid = config_rule.ip_link.endpoint_id.device_id.device_uuid.uuid
+ endpoint_uuid = config_rule.ip_link.endpoint_id.endpoint_uuid.uuid
+ IP_LINK_KEY_TEMPLATE = '/device[{:s}]/endpoint[{:s}]/ip_link'
+ key_or_path = IP_LINK_KEY_TEMPLATE.format(device_uuid, endpoint_uuid,)
+ value = config_rule.ip_link
else:
MSG = 'Unsupported Kind({:s}) in ConfigRule({:s})'
LOGGER.warning(MSG.format(str(kind), grpc_message_to_json_string(config_rule)))
@@ -100,6 +106,25 @@ class SettingsHandler:
if not 'index[{:d}]'.format(acl_index) in res_key: continue
acl_rules.append((res_key, res_value))
return acl_rules
+
+ def get_endpoint_ip_link(self, device : Device, endpoint : EndPoint) -> List [Tuple]:
+ endpoint_name = endpoint.name
+ device_keys = device.device_id.device_uuid.uuid, device.name
+ endpoint_keys = endpoint.endpoint_id.endpoint_uuid.uuid, endpoint.name
+ ip_links = []
+ for device_key in device_keys:
+ for endpoint_key in endpoint_keys:
+ endpoint_settings_uri = '/device[{:s}]/endpoint[{:s}]'.format(device_key, endpoint_key)
+ endpoint_settings = self.get(endpoint_settings_uri)
+ if endpoint_settings is None: continue
+ IP_LINK_KEY_TEMPLATE = '/device[{:s}]/endpoint[{:s}]/'.format(device_key, endpoint_name)
+
+ results = dump_subtree(endpoint_settings)
+ for res_key, res_value in results:
+ if not res_key.startswith(IP_LINK_KEY_TEMPLATE): continue
+ if not "ip_link" in res_key: continue
+ ip_links.append((res_key, res_value))
+ return None
def set(self, key_or_path : Union[str, List[str]], value : Any) -> None:
set_subnode_value(self.__resolver, self.__config, key_or_path, value)
diff --git a/src/service/service/service_handlers/__init__.py b/src/service/service/service_handlers/__init__.py
index 8b5e2b2834f37dc3d616907e46cf1fa5b2f1274f..a731e8176d51b32305bb13bd223e19bfb44c2b6e 100644
--- a/src/service/service/service_handlers/__init__.py
+++ b/src/service/service/service_handlers/__init__.py
@@ -27,6 +27,7 @@ from .tapi_tapi.TapiServiceHandler import TapiServiceHandler
from .tapi_xr.TapiXrServiceHandler import TapiXrServiceHandler
from .e2e_orch.E2EOrchestratorServiceHandler import E2EOrchestratorServiceHandler
from .oc.OCServiceHandler import OCServiceHandler
+from .ip_link.IP_LinkServiceHandler import IP_LinkServiceHandler
SERVICE_HANDLERS = [
(L2NMEmulatedServiceHandler, [
@@ -106,5 +107,11 @@ SERVICE_HANDLERS = [
FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY,
FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_OC,
}
- ])
+ ]),
+ (IP_LinkServiceHandler, [
+ {
+ FilterFieldEnum.SERVICE_TYPE : ServiceTypeEnum.SERVICETYPE_IPLINK,
+ FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG,
+ }
+ ]),
]
diff --git a/src/service/service/service_handlers/ip_link/ConfigRules.py b/src/service/service/service_handlers/ip_link/ConfigRules.py
new file mode 100644
index 0000000000000000000000000000000000000000..46c7877fed1044e3d029a5c9500fd5ac23ef6a3f
--- /dev/null
+++ b/src/service/service/service_handlers/ip_link/ConfigRules.py
@@ -0,0 +1,81 @@
+# Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from typing import Any, Dict, List, Optional, Tuple
+from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set
+from service.service.service_handler_api.AnyTreeTools import TreeNode
+
+def get_value(field_name : str, *containers, default=None) -> Optional[Any]:
+ if len(containers) == 0: raise Exception('No containers specified')
+ for container in containers:
+ if field_name not in container: continue
+ return container[field_name]
+ return default
+
+def setup_config_rules(
+ service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str, endpoint_name : str,
+ service_settings : TreeNode, device_settings : TreeNode, endpoint_settings : TreeNode, endpoint_acls : List [Tuple], endpoint_ip_link : List [Tuple]
+) -> List[Dict]:
+
+ if service_settings is None: return []
+ if device_settings is None: return []
+ if endpoint_settings is None: return []
+
+ json_settings : Dict = service_settings.value
+ json_device_settings : Dict = device_settings.value
+ json_endpoint_settings : Dict = endpoint_settings.value
+
+ settings = (json_settings, json_endpoint_settings, json_device_settings)
+
+ mtu = get_value('mtu', *settings, default=1450) # 1512
+
+ json_config_rules = []
+ return json_config_rules
+
+def teardown_config_rules(
+ service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str, endpoint_name : str,
+ service_settings : TreeNode, device_settings : TreeNode, endpoint_settings : TreeNode
+) -> List[Dict]:
+
+ if service_settings is None: return []
+ if device_settings is None: return []
+ if endpoint_settings is None: return []
+
+ json_settings : Dict = service_settings.value
+ json_device_settings : Dict = device_settings.value
+ json_endpoint_settings : Dict = endpoint_settings.value
+
+ settings = (json_settings, json_endpoint_settings, json_device_settings)
+
+ service_short_uuid = service_uuid.split('-')[-1]
+ network_instance_name = '{:s}-NetInst'.format(service_short_uuid)
+ #network_interface_desc = '{:s}-NetIf'.format(service_uuid)
+ #network_subinterface_desc = '{:s}-NetSubIf'.format(service_uuid)
+
+ #mtu = get_value('mtu', *settings, default=1450) # 1512
+ #address_families = json_settings.get('address_families', [] ) # ['IPV4']
+ #bgp_as = get_value('bgp_as', *settings, default=65000) # 65000
+ route_distinguisher = json_settings.get('route_distinguisher', '0:0' ) # '60001:801'
+ #sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0 ) # 1
+ #router_id = json_endpoint_settings.get('router_id', '0.0.0.0') # '10.95.0.10'
+ vlan_id = json_endpoint_settings.get('vlan_id', 1 ) # 400
+ #address_ip = json_endpoint_settings.get('address_ip', '0.0.0.0') # '2.2.2.1'
+ #address_prefix = json_endpoint_settings.get('address_prefix', 24 ) # 30
+ policy_import = json_endpoint_settings.get('policy_AZ', '2' ) # 2
+ policy_export = json_endpoint_settings.get('policy_ZA', '7' ) # 30
+
+ if_subif_name = '{:s}.{:d}'.format(endpoint_name, vlan_id)
+
+ json_config_rules = []
+ return json_config_rules
diff --git a/src/service/service/service_handlers/ip_link/IP_LinkServiceHandler.py b/src/service/service/service_handlers/ip_link/IP_LinkServiceHandler.py
new file mode 100644
index 0000000000000000000000000000000000000000..832b386c54694d652400238b58333f0721a2bfd1
--- /dev/null
+++ b/src/service/service/service_handlers/ip_link/IP_LinkServiceHandler.py
@@ -0,0 +1,164 @@
+# Copyright 2022-2024 ETSI OSG/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 json, logging
+from typing import Any, List, Optional, Tuple, Union
+from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method
+from common.proto.context_pb2 import ConfigRule, DeviceId, Service
+from common.tools.object_factory.Device import json_device_id
+from common.type_checkers.Checkers import chk_type
+from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching
+from service.service.service_handler_api._ServiceHandler import _ServiceHandler
+from service.service.service_handler_api.SettingsHandler import SettingsHandler
+from service.service.task_scheduler.TaskExecutor import TaskExecutor
+from .ConfigRules import setup_config_rules, teardown_config_rules
+
+LOGGER = logging.getLogger(__name__)
+
+METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'l3nm_openconfig'})
+
+class IP_LinkServiceHandler(_ServiceHandler):
+ def __init__( # pylint: disable=super-init-not-called
+ self, service : Service, task_executor : TaskExecutor, **settings
+ ) -> None:
+ self.__service = service
+ self.__task_executor = task_executor
+ self.__settings_handler = SettingsHandler(service.service_config, **settings)
+
+ @metered_subclass_method(METRICS_POOL)
+ def SetEndpoint(
+ self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None
+ ) -> List[Union[bool, Exception]]:
+ chk_type('endpoints', endpoints, list)
+ if len(endpoints) == 0: return []
+
+ service_uuid = self.__service.service_id.service_uuid.uuid
+ settings = self.__settings_handler.get('/settings')
+
+ results = []
+ for endpoint in endpoints:
+ try:
+ device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint)
+
+ device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
+ device_settings = self.__settings_handler.get_device_settings(device_obj)
+ endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid)
+ endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj)
+ endpoint_acls = self.__settings_handler.get_endpoint_acls(device_obj, endpoint_obj)
+ endpoint_ip_link = self.__settings_handler.get_endpoint_ip_link(device_obj, endpoint_obj)
+ endpoint_name = endpoint_obj.name
+ json_config_rules = setup_config_rules(
+ service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name,
+ settings, device_settings, endpoint_settings, endpoint_acls, endpoint_ip_link)
+
+ if len(json_config_rules) > 0:
+ del device_obj.device_config.config_rules[:]
+ for json_config_rule in json_config_rules:
+ device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule))
+ self.__task_executor.configure_device(device_obj)
+
+ results.append(True)
+ except Exception as e: # pylint: disable=broad-except
+ LOGGER.exception('Unable to SetEndpoint({:s})'.format(str(endpoint)))
+ results.append(e)
+
+ return results
+
+ @metered_subclass_method(METRICS_POOL)
+ def DeleteEndpoint(
+ self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None
+ ) -> List[Union[bool, Exception]]:
+ chk_type('endpoints', endpoints, list)
+ if len(endpoints) == 0: return []
+
+ service_uuid = self.__service.service_id.service_uuid.uuid
+ settings = self.__settings_handler.get('/settings')
+
+ results = []
+ for endpoint in endpoints:
+ try:
+ device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint)
+
+ device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
+ device_settings = self.__settings_handler.get_device_settings(device_obj)
+ endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid)
+ endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj)
+ endpoint_name = endpoint_obj.name
+
+ json_config_rules = teardown_config_rules(
+ service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name,
+ settings, device_settings, endpoint_settings)
+
+ if len(json_config_rules) > 0:
+ del device_obj.device_config.config_rules[:]
+ for json_config_rule in json_config_rules:
+ device_obj.device_config.config_rules.append(ConfigRule(**json_config_rule))
+ self.__task_executor.configure_device(device_obj)
+
+ results.append(True)
+ except Exception as e: # pylint: disable=broad-except
+ LOGGER.exception('Unable to DeleteEndpoint({:s})'.format(str(endpoint)))
+ results.append(e)
+
+ return results
+
+ @metered_subclass_method(METRICS_POOL)
+ def SetConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+ chk_type('constraints', constraints, list)
+ if len(constraints) == 0: return []
+
+ msg = '[SetConstraint] Method not implemented. Constraints({:s}) are being ignored.'
+ LOGGER.warning(msg.format(str(constraints)))
+ return [True for _ in range(len(constraints))]
+
+ @metered_subclass_method(METRICS_POOL)
+ def DeleteConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+ chk_type('constraints', constraints, list)
+ if len(constraints) == 0: return []
+
+ msg = '[DeleteConstraint] Method not implemented. Constraints({:s}) are being ignored.'
+ LOGGER.warning(msg.format(str(constraints)))
+ return [True for _ in range(len(constraints))]
+
+ @metered_subclass_method(METRICS_POOL)
+ def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+ chk_type('resources', resources, list)
+ if len(resources) == 0: return []
+
+ results = []
+ for resource in resources:
+ try:
+ resource_value = json.loads(resource[1])
+ self.__settings_handler.set(resource[0], resource_value)
+ results.append(True)
+ except Exception as e: # pylint: disable=broad-except
+ LOGGER.exception('Unable to SetConfig({:s})'.format(str(resource)))
+ results.append(e)
+
+ return results
+
+ @metered_subclass_method(METRICS_POOL)
+ def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+ chk_type('resources', resources, list)
+ if len(resources) == 0: return []
+
+ results = []
+ for resource in resources:
+ try:
+ self.__settings_handler.delete(resource[0])
+ except Exception as e: # pylint: disable=broad-except
+ LOGGER.exception('Unable to DeleteConfig({:s})'.format(str(resource)))
+ results.append(e)
+
+ return results
diff --git a/src/service/service/service_handlers/ip_link/__init__.py b/src/service/service/service_handlers/ip_link/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ee6f7071f145e06c3aeaefc09a43ccd88e619e3
--- /dev/null
+++ b/src/service/service/service_handlers/ip_link/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2024 ETSI OSG/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/ztp/target/generated-sources/grpc/context/ContextOuterClass.java b/src/ztp/target/generated-sources/grpc/context/ContextOuterClass.java
index 4593770498216267b8d2f95dd728fccfbb9dc134..8eea2d6d82380b60f746942a2314057a7d3b29c2 100644
--- a/src/ztp/target/generated-sources/grpc/context/ContextOuterClass.java
+++ b/src/ztp/target/generated-sources/grpc/context/ContextOuterClass.java
@@ -504,6 +504,10 @@ public final class ContextOuterClass {
* SERVICETYPE_OPTICAL_CONNECTIVITY = 6;
*/
SERVICETYPE_OPTICAL_CONNECTIVITY(6),
+ /**
+ * SERVICETYPE_IPLINK = 7;
+ */
+ SERVICETYPE_IPLINK(7),
UNRECOGNIZED(-1);
/**
@@ -541,6 +545,11 @@ public final class ContextOuterClass {
*/
public static final int SERVICETYPE_OPTICAL_CONNECTIVITY_VALUE = 6;
+ /**
+ * SERVICETYPE_IPLINK = 7;
+ */
+ public static final int SERVICETYPE_IPLINK_VALUE = 7;
+
public final int getNumber() {
if (this == UNRECOGNIZED) {
throw new java.lang.IllegalArgumentException("Can't get the number of an unknown enum value.");
@@ -578,6 +587,8 @@ public final class ContextOuterClass {
return SERVICETYPE_E2E;
case 6:
return SERVICETYPE_OPTICAL_CONNECTIVITY;
+ case 7:
+ return SERVICETYPE_IPLINK;
default:
return null;
}