diff --git a/.gitignore b/.gitignore
index a0ac78095a9f275ae35060a584c5df2151aa7d0e..db47387c8c8ff9900a59107642221960134aa1f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,7 @@ MANIFEST
 #  Usually these files are written by a python script from a template
 #  before PyInstaller builds the exe, so as to inject date/other infos into it.
 *.manifest
+.manifest/
 *.spec
 
 # Installer logs
diff --git a/proto/context.proto b/proto/context.proto
index d3888e77b0256f63fb4b4eb10b987137057a0aa7..bb769a5a2cc37c7137be1da5f4e47edf41628f5e 100644
--- a/proto/context.proto
+++ b/proto/context.proto
@@ -77,13 +77,19 @@ service ContextService {
 
  
   // ------------------------------ Experimental -----------------------------
-  rpc GetOpticalConfig   (Empty          ) returns (OpticalConfigList     ) {}
-  rpc SetOpticalConfig   (OpticalConfig  ) returns (OpticalConfigId       ) {}
-  rpc SelectOpticalConfig(OpticalConfigId) returns (OpticalConfig         ) {}
+  rpc GetOpticalConfig       (Empty            ) returns (OpticalConfigList) {}
+  rpc SetOpticalConfig       (OpticalConfig    ) returns (OpticalConfigId  ) {}
+  rpc UpdateOpticalConfig    (OpticalConfig    ) returns (OpticalConfigId  ) {}
+  rpc SelectOpticalConfig    (OpticalConfigId  ) returns (OpticalConfig    ) {}
+  rpc DeleteOpticalConfig    (OpticalConfigId  ) returns (Empty            ) {}
+  rpc DeleteOpticalChannel   (OpticalConfig    ) returns (Empty            ) {}
 
-  rpc SetOpticalLink     (OpticalLink    ) returns (Empty                 ) {}
-  rpc GetOpticalLink     (OpticalLinkId  ) returns (OpticalLink           ) {}
-  rpc GetFiber           (FiberId        ) returns (Fiber                 ) {}
+  rpc SetOpticalLink         (OpticalLink      ) returns (Empty            ) {}
+  rpc GetOpticalLink         (LinkId           ) returns (OpticalLink      ) {}
+  rpc DeleteOpticalLink      (LinkId           ) returns (Empty            ) {}
+  rpc GetOpticalLinkList     (Empty            ) returns (OpticalLinkList  ) {}
+
+  rpc DeleteServiceConfigRule(ServiceConfigRule) returns (Empty            ) {}
 }
 
 // ----- Generic -------------------------------------------------------------------------------------------------------
@@ -148,6 +154,7 @@ message Topology {
   string name = 2;
   repeated DeviceId device_ids = 3;
   repeated LinkId link_ids = 4;
+  repeated LinkId optical_link_ids = 5;
 }
 
 message TopologyDetails {
@@ -155,6 +162,7 @@ message TopologyDetails {
   string name = 2;
   repeated Device devices = 3;
   repeated Link links = 4;
+  repeated OpticalLink optical_links = 5;
 }
 
 message TopologyIdList {
@@ -653,45 +661,57 @@ message OpticalConfigId {
 message OpticalConfig {
   OpticalConfigId opticalconfig_id = 1;
   string config = 2;
+  DeviceId device_id = 3;
 }
 
 message OpticalConfigList {
   repeated OpticalConfig opticalconfigs = 1;
 }
 
+message OpticalConfigEvent {
+  Event event = 1;
+  OpticalConfigId opticalconfig_id = 2;
+}
+
+
 // ---- Optical Link ----
 
-message OpticalLinkId {
-  Uuid optical_link_uuid = 1;
+message OpticalEndPointId {
+  DeviceId device_id = 2;
+  Uuid endpoint_uuid = 3;
 }
 
-message FiberId {
-  Uuid fiber_uuid = 1;
-}
 
-message Fiber {
-  string ID = 10;
-  string src_port = 1;
-  string dst_port = 2;
-  string local_peer_port =  3;
-  string remote_peer_port = 4;
-  repeated int32 c_slots = 5;
-  repeated int32 l_slots = 6;
-  repeated int32 s_slots = 7;
-  float length = 8;
-  bool used = 9;
-  FiberId fiber_uuid = 11;
- 
+message OpticalLinkList {
+  repeated OpticalLink optical_links = 1;
 }
+
+
+
 message OpticalLinkDetails {
   float length = 1;
-  string source = 2;
-  string target = 3;
-  repeated Fiber fibers = 4;
+  string src_port = 2;
+  string dst_port = 3;
+  string local_peer_port = 4;
+  string remote_peer_port = 5 ;
+  bool used = 6 ; 
+  map<string, int32> c_slots = 7;
+  map<string, int32> l_slots = 8;
+  map<string, int32> s_slots = 9;
 }
 
 message OpticalLink {
   string name = 1;
-  OpticalLinkDetails details = 2;
-  OpticalLinkId optical_link_uuid = 3;
+  OpticalLinkDetails optical_details = 2;
+  LinkId link_id = 3;
+  repeated EndPointId link_endpoint_ids=4;
+}
+
+
+
+////////////////// Config Rule Delete ////////////
+
+message ServiceConfigRule {
+  ServiceId service_id =1;
+  ConfigRule_Custom configrule_custom =2;
 }
diff --git a/proto/openconfig_device.proto b/proto/optical_device.proto
similarity index 64%
rename from proto/openconfig_device.proto
rename to proto/optical_device.proto
index 8ed3a900b6b157e096308c9f476e3c0ab1f575c1..39eb92e4420bf28979b5da9d93ec9264a07dacb3 100644
--- a/proto/openconfig_device.proto
+++ b/proto/optical_device.proto
@@ -13,11 +13,13 @@
 // limitations under the License.
 
 syntax = "proto3";
-package openconfig_device;
+package optical_device;
 
 import "context.proto";
 
 service OpenConfigService {
-  rpc AddOpenConfigDevice   (context.OpticalConfig) returns (context.OpticalConfigId) {}
-  rpc ConfigureOpticalDevice(context.OpticalConfig) returns (context.Empty          ) {}
+  rpc AddOpenConfigDevice   (context.OpticalConfig    ) returns (context.OpticalConfigId) {}
+  rpc ConfigureOpticalDevice(context.OpticalConfig    ) returns (context.Empty          ) {}
+  rpc DisableOpticalDevice  (context.OpticalConfig    ) returns (context.Empty          ) {}
+  rpc GetDeviceConfiguration(context.OpticalConfigList) returns (context.Empty          ) {}
 }
diff --git a/scripts/run_tests_locally-device-gnmi-openconfig.sh b/scripts/run_tests_locally-device-gnmi-openconfig.sh
new file mode 100755
index 0000000000000000000000000000000000000000..92e8448126f53a7f34b97c480585fea25f2b0411
--- /dev/null
+++ b/scripts/run_tests_locally-device-gnmi-openconfig.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# 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.
+
+
+PROJECTDIR=`pwd`
+
+cd $PROJECTDIR/src
+RCFILE=$PROJECTDIR/coverage/.coveragerc
+
+# Run unitary tests and analyze coverage of code at same time
+# helpful pytest flags: --log-level=INFO -o log_cli=true --verbose --maxfail=1 --durations=0
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    device/tests/gnmi_openconfig/test_unitary_gnmi_openconfig.py
diff --git a/scripts/run_tests_locally-device-openconfig-arista-l2vpn.sh b/scripts/run_tests_locally-device-openconfig-arista-l2vpn.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9e151dd3e4c482d90342af91de0cbb018fb1bf78
--- /dev/null
+++ b/scripts/run_tests_locally-device-openconfig-arista-l2vpn.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# 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.
+
+
+PROJECTDIR=`pwd`
+
+cd $PROJECTDIR/src
+RCFILE=$PROJECTDIR/coverage/.coveragerc
+
+# Run unitary tests and analyze coverage of code at same time
+# helpful pytest flags: --log-level=INFO -o log_cli=true --verbose --maxfail=1 --durations=0
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO -o log_cli=true --verbose \
+    device/tests/test_unitary_openconfig_arista_l2vpn.py
diff --git a/src/automation/client/PolicyClient.py b/src/automation/client/PolicyClient.py
index f2b25f2429d790c9cb25b5d70e1e737594586133..f7b6412a62670d0be2caa1460f7fab5ffec6fccd 100644
--- a/src/automation/client/PolicyClient.py
+++ b/src/automation/client/PolicyClient.py
@@ -19,7 +19,7 @@ from common.proto.policy_pb2 import PolicyRuleService, PolicyRuleState
 from common.proto.policy_pb2_grpc import PolicyServiceStub
 from common.tools.client.RetryDecorator import retry, delay_exponential
 from common.tools.grpc.Tools import grpc_message_to_json_string
-from common.proto.openconfig_device_pb2_grpc import OpenConfigServiceStub
+
 LOGGER = logging.getLogger(__name__)
 MAX_RETRIES = 15
 DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0)
@@ -40,7 +40,6 @@ class PolicyClient:
     def connect(self):
         self.channel = grpc.insecure_channel(self.endpoint)
         self.stub = PolicyServiceStub(self.channel)
-        self.openconfig_stub=OpenConfigServiceStub(self.channel)
 
     def close(self):
         if self.channel is not None: self.channel.close()
diff --git a/src/common/tools/context_queries/OpticalConfig.py b/src/common/tools/context_queries/OpticalConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..bd697599cdd674ad2dca9ac8d38100333e315ea3
--- /dev/null
+++ b/src/common/tools/context_queries/OpticalConfig.py
@@ -0,0 +1,66 @@
+# 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 common.method_wrappers.ServiceExceptions import InvalidArgumentsException
+from typing import Optional, Union
+from uuid import UUID, uuid4, uuid5
+
+# Generate a UUIDv5-like from the SHA-1 of "TFS" and no namespace to be used as the NAMESPACE for all
+# the context UUIDs generated. For efficiency purposes, the UUID is hardcoded; however, it is produced
+# using the following code:
+#    from hashlib import sha1
+#    from uuid import UUID
+#    hash = sha1(bytes('TFS', 'utf-8')).digest()
+#    NAMESPACE_TFS = UUID(bytes=hash[:16], version=5)
+NAMESPACE_TFS = UUID('200e3a1f-2223-534f-a100-758e29c37f40')
+
+def get_uuid_from_string(str_uuid_or_name : Union[str, UUID], prefix_for_name : Optional[str] = None) -> str:
+    # if UUID given, assume it is already a valid UUID
+    if isinstance(str_uuid_or_name, UUID): return str_uuid_or_name
+    if not isinstance(str_uuid_or_name, str):
+        MSG = 'Parameter({:s}) cannot be used to produce a UUID'
+        raise Exception(MSG.format(str(repr(str_uuid_or_name))))
+    try:
+        # try to parse as UUID
+        return str(UUID(str_uuid_or_name))
+    except: # pylint: disable=bare-except
+        # produce a UUID within TFS namespace from parameter
+        if prefix_for_name is not None:
+            str_uuid_or_name = '{:s}/{:s}'.format(prefix_for_name, str_uuid_or_name)
+        return str(uuid5(NAMESPACE_TFS, str_uuid_or_name))
+
+def get_uuid_random() -> str:
+    # Generate random UUID. No need to use namespace since "namespace + random = random".
+    return str(uuid4())
+
+def device_get_uuid (device_name) : 
+    if (len(device_name)> 0):
+        return  get_uuid_from_string(device_name)
+    raise InvalidArgumentsException([
+        ('name', device_name),
+    ], extra_details=['Device Name is required to produce Device UUID'])
+
+
+def opticalconfig_get_uuid(
+    device_name : str = '', allow_random : bool = False
+) -> str:
+    if len(device_name) > 0:
+        device_uuid= device_get_uuid(device_name=device_name)
+        return get_uuid_from_string(f"{device_uuid}_opticalconfig")
+    if allow_random: return get_uuid_random()
+
+    raise InvalidArgumentsException([
+        ('name', device_name),
+    ], extra_details=['At least one is required to produce a OpticalConfig UUID'])
diff --git a/src/common/tools/descriptor/Loader.py b/src/common/tools/descriptor/Loader.py
index 2fcc5b63a66ae3c3e96ab774d34958a110f0454a..958536f26c3c63468f1af4a6d14130b6e12fd08f 100644
--- a/src/common/tools/descriptor/Loader.py
+++ b/src/common/tools/descriptor/Loader.py
@@ -38,7 +38,7 @@ from typing import Any, Dict, List, Optional, Tuple, Union
 from common.proto.context_pb2 import (
     Connection, Context, ContextId, Device, DeviceId, Empty,
     Link, LinkId, Service, ServiceId, Slice, SliceId,
-    Topology, TopologyId
+    Topology, TopologyId , OpticalLink
 )
 from common.tools.object_factory.Context import json_context_id
 from context.client.ContextClient import ContextClient
@@ -128,15 +128,16 @@ class DescriptorLoader:
 
         self.__num_workers = num_workers
 
-        self.__dummy_mode  = self.__descriptors.get('dummy_mode' , False)
-        self.__contexts    = self.__descriptors.get('contexts'   , [])
-        self.__topologies  = self.__descriptors.get('topologies' , [])
-        self.__devices     = self.__descriptors.get('devices'    , [])
-        self.__links       = self.__descriptors.get('links'      , [])
-        self.__services    = self.__descriptors.get('services'   , [])
-        self.__slices      = self.__descriptors.get('slices'     , [])
-        self.__ietf_slices = self.__descriptors.get('ietf-network-slice-service:network-slice-services', {})
-        self.__connections = self.__descriptors.get('connections', [])
+        self.__dummy_mode    = self.__descriptors.get('dummy_mode' ,  False)
+        self.__contexts      = self.__descriptors.get('contexts'   ,  [])
+        self.__topologies    = self.__descriptors.get('topologies' ,  [])
+        self.__devices       = self.__descriptors.get('devices'    ,  [])
+        self.__links         = self.__descriptors.get('links'      ,  [])
+        self.__services      = self.__descriptors.get('services'   ,  [])
+        self.__slices        = self.__descriptors.get('slices'     ,  [])
+        self.__ietf_slices   = self.__descriptors.get('ietf-network-slice-service:network-slice-services', {})
+        self.__connections   = self.__descriptors.get('connections',  [])
+        self.__optical_links = self.__descriptors.get('optical_links',[])
 
         if len(self.__ietf_slices) > 0:
             for slice_service in self.__ietf_slices["slice-service"]:
@@ -285,6 +286,9 @@ class DescriptorLoader:
 
     @property
     def num_connections(self) -> int: return len(self.__connections)
+    
+    @property
+    def optical_links(self) -> List[Dict]: return self.__optical_links
 
     def process(self) -> TypeResults:
         # Format CustomConfigRules in Devices, Services and Slices provided in JSON format
@@ -348,16 +352,17 @@ class DescriptorLoader:
         self.__svc_cli.connect()
         self.__slc_cli.connect()
 
-        self._process_descr('context',    'add',    self.__ctx_cli.SetContext,      Context,  self.__contexts_add  )
-        self._process_descr('topology',   'add',    self.__ctx_cli.SetTopology,     Topology, self.__topologies_add)
-        self._process_descr('controller', 'add',    self.__dev_cli.AddDevice,       Device,   controllers_add      )
-        self._process_descr('device',     'add',    self.__dev_cli.AddDevice,       Device,   network_devices_add  )
-        self._process_descr('device',     'config', self.__dev_cli.ConfigureDevice, Device,   self.__devices_config)
-        self._process_descr('link',       'add',    self.__ctx_cli.SetLink,         Link,     self.__links         )
-        self._process_descr('service',    'add',    self.__svc_cli.CreateService,   Service,  self.__services_add  )
-        self._process_descr('service',    'update', self.__svc_cli.UpdateService,   Service,  self.__services      )
-        self._process_descr('slice',      'add',    self.__slc_cli.CreateSlice,     Slice,    self.__slices_add    )
-        self._process_descr('slice',      'update', self.__slc_cli.UpdateSlice,     Slice,    self.__slices        )
+        self._process_descr('context',    'add',    self.__ctx_cli.SetContext,      Context,     self.__contexts_add  )
+        self._process_descr('topology',   'add',    self.__ctx_cli.SetTopology,     Topology,    self.__topologies_add)
+        self._process_descr('controller', 'add',    self.__dev_cli.AddDevice,       Device,      controllers_add      )
+        self._process_descr('device',     'add',    self.__dev_cli.AddDevice,       Device,      network_devices_add  )
+        self._process_descr('device',     'config', self.__dev_cli.ConfigureDevice, Device,      self.__devices_config)
+        self._process_descr('link',       'add',    self.__ctx_cli.SetLink,         Link,        self.__links         )
+        self._process_descr('service',    'add',    self.__svc_cli.CreateService,   Service,     self.__services_add  )
+        self._process_descr('service',    'update', self.__svc_cli.UpdateService,   Service,     self.__services      )
+        self._process_descr('slice',      'add',    self.__slc_cli.CreateSlice,     Slice,       self.__slices_add    )
+        self._process_descr('slice',      'update', self.__slc_cli.UpdateSlice,     Slice,       self.__slices        )
+        self._process_descr('link',       'add',    self.__ctx_cli.SetOpticalLink,  OpticalLink, self.__optical_links )
 
         # By default the Context component automatically assigns devices and links to topologies based on their
         # endpoints, and assigns topologies, services, and slices to contexts based on their identifiers.
diff --git a/src/common/tools/object_factory/EndPoint.py b/src/common/tools/object_factory/EndPoint.py
index 85a5d4494184567447d6d16fa7df2c530106c6ba..faf1accd37ebdc32b382a1cca16ccbeb510099f9 100644
--- a/src/common/tools/object_factory/EndPoint.py
+++ b/src/common/tools/object_factory/EndPoint.py
@@ -43,13 +43,14 @@ def json_endpoint_ids(
 
 def json_endpoint(
         device_id : Dict, endpoint_uuid : str, endpoint_type : str, topology_id : Optional[Dict] = None,
-        kpi_sample_types : List[int] = [], location : Optional[Dict] = None
+        name : Optional[str] = None, kpi_sample_types : List[int] = [], location : Optional[Dict] = None
     ):
 
     result = {
         'endpoint_id': json_endpoint_id(device_id, endpoint_uuid, topology_id=topology_id),
         'endpoint_type': endpoint_type,
     }
+    if name is not None: result['name'] = name
     if kpi_sample_types is not None and len(kpi_sample_types) > 0:
         result['kpi_sample_types'] = copy.deepcopy(kpi_sample_types)
     if location is not None:
diff --git a/src/common/tools/object_factory/OpticalLink.py b/src/common/tools/object_factory/OpticalLink.py
new file mode 100644
index 0000000000000000000000000000000000000000..765cfac22d2aa6a168e01e41df393cc2b693a32f
--- /dev/null
+++ b/src/common/tools/object_factory/OpticalLink.py
@@ -0,0 +1,40 @@
+# 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 copy
+
+def convert_to_dict(single_val:int)->dict:
+    slot= dict()
+    bin_num = bin(single_val)
+    sliced_num=bin_num[2:]
+    for i in range(len(sliced_num)):
+        slot[str(i+1)]=int(sliced_num[i])
+    return slot
+
+def correct_slot(dic: dict) -> dict:
+    _dict = copy.deepcopy(dic)
+    keys_list = list(_dict.keys())
+    if len(keys_list) < 20:
+        num_keys = [int(i) for i in keys_list]
+        if num_keys[-1] != 20:
+            missed_keys = []
+            diff = 20 - len(num_keys)
+            #print(f"diff {diff}")
+            for i in range(diff+1):
+                missed_keys.append(num_keys[-1]+i)
+            #print(f"missed_keys {missed_keys}")
+            for key in missed_keys :
+                _dict[key]=1
+            #print(f"result {_dict}")
+    return _dict
diff --git a/src/common/type_checkers/Assertions.py b/src/common/type_checkers/Assertions.py
index 3934c9d89568be90129bb766c61b55a532d2f0b3..498a85349c4c9d68bc8c64c5d174595cb98c1cef 100644
--- a/src/common/type_checkers/Assertions.py
+++ b/src/common/type_checkers/Assertions.py
@@ -451,7 +451,7 @@ def validate_slice(message):
 
 def validate_topology(message, num_devices=None, num_links=None):
     assert isinstance(message, dict)
-    assert len(message.keys()) == 4
+    assert len(message.keys()) == 5
     assert 'topology_id' in message
     validate_topology_id(message['topology_id'])
     assert 'name' in message
@@ -464,6 +464,10 @@ def validate_topology(message, num_devices=None, num_links=None):
     assert isinstance(message['link_ids'], list)
     if num_links is not None: assert len(message['link_ids']) == num_links
     for link_id in message['link_ids']: validate_link_id(link_id)
+    assert 'optical_link_ids' in message
+    assert isinstance(message['optical_link_ids'], list)
+    #if num_links is not None: assert len(message['optical_link_ids']) == num_links
+    for link_id in message['optical_link_ids']: validate_link_id(link_id)
 
 def validate_endpoint(message):
     assert isinstance(message, dict)
diff --git a/src/context/client/ContextClient.py b/src/context/client/ContextClient.py
index 2776a0d294e9a9ee7b00e46bfd3fbb068133741f..35f9121b33f60034340cbe2492e1bd26a622f6e7 100644
--- a/src/context/client/ContextClient.py
+++ b/src/context/client/ContextClient.py
@@ -24,10 +24,10 @@ from common.proto.context_pb2 import (
     Device, DeviceEvent, DeviceFilter, DeviceId, DeviceIdList, DeviceList,
     Empty, EndPointIdList, EndPointNameList,
     Link, LinkEvent, LinkId, LinkIdList, LinkList,
-    Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList,
+    OpticalConfig, OpticalConfigId, OpticalConfigList , OpticalLink, OpticalLinkList,
+    Service, ServiceConfigRule, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList,
     Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList,
     Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList,
-    OpticalConfig, OpticalConfigId, OpticalConfigList
 )
 from common.proto.context_pb2_grpc import ContextServiceStub
 from common.proto.context_policy_pb2_grpc import ContextPolicyServiceStub
@@ -447,6 +447,14 @@ class ContextClient:
         response = self.stub.SetOpticalConfig(request)
         LOGGER.debug('SetOpticalConfig result: {:s}'.format(grpc_message_to_json_string(response)))
         return response
+    
+    @RETRY_DECORATOR
+    def UpdateOpticalConfig(self, request : OpticalConfig) -> OpticalConfigId:
+        LOGGER.debug('SetOpticalConfig request: {:s}'.format(grpc_message_to_json_string(request)))
+        response_future = self.stub.UpdateOpticalConfig.future(request)
+        response = response_future.result()
+        LOGGER.debug('SetOpticalConfig result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
 
     @RETRY_DECORATOR
     def GetOpticalConfig(self, request : Empty) -> OpticalConfigList:
@@ -461,3 +469,55 @@ class ContextClient:
         response = self.stub.SelectOpticalConfig(request)
         LOGGER.debug('SelectOpticalConfig result: {:s}'.format(grpc_message_to_json_string(response)))
         return response
+    
+    @RETRY_DECORATOR
+    def DeleteOpticalConfig(self,request : OpticalConfigId) -> Empty:
+        LOGGER.debug('DeleteOpticalConfig request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.stub.DeleteOpticalConfig(request)
+        LOGGER.debug('DeleteOpticalConfig result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
+    
+    @RETRY_DECORATOR
+    def DeleteOpticalChannel(self,request : OpticalConfig) -> Empty:
+        LOGGER.debug('DeleteOpticalChannel request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.stub.DeleteOpticalChannel(request)
+        LOGGER.debug('DeleteOpticalChannel result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
+    
+    #--------------------------- Optical Link ------------------------
+    def GetOpticalLinkList(self, request: Empty) -> OpticalLinkList:
+        LOGGER.debug('ListOpticalLinks request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.stub.GetOpticalLinkList(request)
+        LOGGER.debug('ListOpticalLinks result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
+
+    @RETRY_DECORATOR
+    def GetOpticalLink(self, request: LinkId) -> OpticalLink:
+        LOGGER.debug('GetOpticalLink request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.stub.GetOpticalLink(request)
+        LOGGER.debug('GetOpticalLink result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
+
+    @RETRY_DECORATOR
+    def SetOpticalLink(self, request: OpticalLink) -> LinkId:
+        LOGGER.debug('SetOpticalLink request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.stub.SetOpticalLink(request)
+        LOGGER.debug('SetOpticalLink result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
+
+    @RETRY_DECORATOR
+    def DeleteOpticalLink(self, request: LinkId) -> Empty:
+        LOGGER.debug('RemoveOpticalLink request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.stub.DeleteOpticalLink(request)
+        LOGGER.debug('RemoveOpticalLink result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
+    
+    
+    # --------------------------------- Service ConfigRule Deletion ------------------
+    
+    @RETRY_DECORATOR
+    def DeleteServiceConfigRule(self, request: ServiceConfigRule) -> Empty:
+        LOGGER.debug('ServiceConfigRule Delete request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.stub.DeleteServiceConfigRule(request)
+        LOGGER.debug('ServiceConfigRule Delete result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py
index be32372108e059625801d14c660d18cbe0df677f..09d16b0f8a80f956a32f7e074e3bbe5582b3b26c 100644
--- a/src/context/service/ContextServiceServicerImpl.py
+++ b/src/context/service/ContextServiceServicerImpl.py
@@ -24,29 +24,51 @@ from common.proto.context_pb2 import (
     Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList,
     Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList,
     Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList,
-    OpticalConfigList, OpticalConfigId, OpticalConfig
+    OpticalConfigList, OpticalConfigId, OpticalConfig, OpticalLink, OpticalLinkList,
+    ServiceConfigRule
 )
 from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule
 from common.proto.context_pb2_grpc import ContextServiceServicer
 from common.proto.context_policy_pb2_grpc import ContextPolicyServiceServicer
 from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method
 from .database.Connection import (
-    connection_delete, connection_get, connection_list_ids, connection_list_objs, connection_set)
-from .database.Context import context_delete, context_get, context_list_ids, context_list_objs, context_set
-from .database.Device import device_delete, device_get, device_list_ids, device_list_objs, device_select, device_set
+    connection_delete, connection_get, connection_list_ids, connection_list_objs, connection_set
+)
+from .database.Context import (
+    context_delete, context_get, context_list_ids, context_list_objs, context_set
+)
+from .database.Device import (
+    device_delete, device_get, device_list_ids, device_list_objs, device_select, device_set
+)
 from .database.EndPoint import endpoint_list_names
 from .database.Events import EventTopicEnum, consume_events
-from .database.Link import link_delete, link_get, link_list_ids, link_list_objs, link_set
+from .database.Link import (
+    link_delete, link_get, link_list_ids, link_list_objs, link_set
+)
 from .database.PolicyRule import (
-    policyrule_delete, policyrule_get, policyrule_list_ids, policyrule_list_objs, policyrule_set)
+    policyrule_delete, policyrule_get, policyrule_list_ids, policyrule_list_objs,
+    policyrule_set
+)
 from .database.Service import (
-    service_delete, service_get, service_list_ids, service_list_objs, service_select, service_set, service_unset)
+    service_delete, service_get, service_list_ids, service_list_objs, service_select,
+    service_set, service_unset
+)
 from .database.Slice import (
-    slice_delete, slice_get, slice_list_ids, slice_list_objs, slice_select, slice_set, slice_unset)
+    slice_delete, slice_get, slice_list_ids, slice_list_objs, slice_select,
+    slice_set, slice_unset
+)
 from .database.Topology import (
-    topology_delete, topology_get, topology_get_details, topology_list_ids, topology_list_objs, topology_set)
-from .database.OpticalConfig import set_opticalconfig, select_opticalconfig, get_opticalconfig
-
+    topology_delete, topology_get, topology_get_details, topology_list_ids,
+    topology_list_objs, topology_set
+)
+from .database.OpticalConfig import (
+    set_opticalconfig, select_opticalconfig, get_opticalconfig, delete_opticalconfig,
+    update_opticalconfig, delete_opticalchannel
+)
+from .database.OpticalLink import (
+    optical_link_delete, optical_link_get, optical_link_list_objs, optical_link_set
+)
+from .database.ConfigRule import delete_config_rule
 LOGGER = logging.getLogger(__name__)
 
 METRICS_POOL = MetricsPool('Context', 'RPC')
@@ -312,7 +334,48 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer
         result = set_opticalconfig(self.db_engine, request)
         return OpticalConfigId(**result)
 
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def UpdateOpticalConfig(self, request : OpticalConfig, context : grpc.ServicerContext) -> OpticalConfigId:
+        result = update_opticalconfig(self.db_engine, request)
+        return OpticalConfigId(**result)
+
     @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
     def SelectOpticalConfig(self, request : OpticalConfigId, context : grpc.ServicerContext) -> OpticalConfig:
         result = select_opticalconfig(self.db_engine, request)
-        return OpticalConfig(config=result.config, opticalconfig_id=result.opticalconfig_id)
+        optical_config_id = OpticalConfigId()
+        device_id = DeviceId()
+        optical_config_id.CopyFrom(result.opticalconfig_id)
+        device_id.CopyFrom(result.device_id)
+        return OpticalConfig(config=result.config, opticalconfig_id=optical_config_id , device_id=device_id)
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def DeleteOpticalConfig(self, request : OpticalConfigId, context : grpc.ServicerContext) -> Empty:
+        delete_opticalconfig(self.db_engine, self.messagebroker, request)
+        return Empty()
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def DeleteOpticalChannel(self, request : OpticalConfig, context : grpc.ServicerContext) -> Empty:
+        delete_opticalchannel(self.db_engine, self.messagebroker, request)
+        return Empty()
+
+    #--------------------- Experimental Optical Link -------------------
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def GetOpticalLinkList(self, request : Empty, context : grpc.ServicerContext) -> OpticalLinkList:
+        return optical_link_list_objs(self.db_engine)
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def GetOpticalLink(self, request : LinkId, context : grpc.ServicerContext) -> OpticalLink:
+        return optical_link_get(self.db_engine, request)
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def SetOpticalLink(self, request : Link, context : grpc.ServicerContext) -> LinkId:
+        return optical_link_set(self.db_engine, self.messagebroker, request)
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def DeleteOpticalLink(self, request : LinkId, context : grpc.ServicerContext) -> Empty:
+        return optical_link_delete(self.db_engine, self.messagebroker, request)
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def DeleteServiceConfigRule(self, request : ServiceConfigRule, context : grpc.ServicerContext) -> Empty:
+        return delete_config_rule(self.db_engine,  request)
diff --git a/src/context/service/database/ConfigRule.py b/src/context/service/database/ConfigRule.py
index 7d816b3e87803f71678511f4fadc6bbe7eba548e..0201d2672e0cd47f208e7569f9d34eae6e4601a8 100644
--- a/src/context/service/database/ConfigRule.py
+++ b/src/context/service/database/ConfigRule.py
@@ -16,15 +16,18 @@ import datetime, json, logging
 from sqlalchemy import delete
 #from sqlalchemy.dialects import postgresql
 from sqlalchemy.dialects.postgresql import insert
+from sqlalchemy.engine import Engine
 from sqlalchemy.orm import Session
 from typing import Dict, List, Optional, Set
-from common.proto.context_pb2 import ConfigRule
+from common.proto.context_pb2 import ConfigRule, ServiceConfigRule, Empty
 from common.tools.grpc.Tools import grpc_message_to_json_string
 from .models.enums.ConfigAction import ORM_ConfigActionEnum, grpc_to_enum__config_action
 from .models.ConfigRuleModel import (
     ConfigRuleKindEnum, DeviceConfigRuleModel, ServiceConfigRuleModel, SliceConfigRuleModel)
 from .uuids._Builder import get_uuid_from_string
 from .uuids.EndPoint import endpoint_get_uuid
+from sqlalchemy_cockroachdb import run_transaction
+from sqlalchemy.orm import Session, sessionmaker
 
 LOGGER = logging.getLogger(__name__)
 
@@ -149,3 +152,16 @@ def upsert_config_rules(
         upsert_affected = any([(updated_at > created_at) for created_at,updated_at in configrule_updates])
 
     return delete_affected or upsert_affected
+
+
+def delete_config_rule(db_engine : Engine, request : ServiceConfigRule):
+    config_rule = request.configrule_custom
+    service_id  = request.service_id
+    parent_uuid = service_id.service_uuid.uuid
+    configrule_name = 'service:custom:{:s}'.format( config_rule.resource_key)
+    configrule_uuid = get_uuid_from_string(configrule_name, prefix_for_name=parent_uuid)
+    def callback(session : Session) -> bool:
+        num_deleted = session.query(ServiceConfigRuleModel).filter_by(configrule_uuid=configrule_uuid).delete()
+        return num_deleted > 0
+    deleted = run_transaction(sessionmaker(bind=db_engine), callback)
+    return Empty()
diff --git a/src/context/service/database/Device.py b/src/context/service/database/Device.py
index beeae59c5967723f2cccfa365fca67dd3acd0096..4713b8e0744df39e6d9227e02f909571bd159a37 100644
--- a/src/context/service/database/Device.py
+++ b/src/context/service/database/Device.py
@@ -106,6 +106,7 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi
     topology_uuids.add(topology_uuid)
 
     is_oc_driver = DeviceDriverEnum.DEVICEDRIVER_OC in set(request.device_drivers)
+    #optical_endpoints_data : List[Dict] = list()
 
     endpoints_data : List[Dict] = list()
     for i, endpoint in enumerate(request.device_endpoints):
@@ -136,6 +137,18 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi
             'created_at'       : now,
             'updated_at'       : now,
         })
+        # # ------------------- Experimental -----------------------
+       
+        # if is_oc_driver:
+            
+        #     optical_endpoints_data.append({
+        #             'endpoint_uuid'    : endpoint_uuid,
+        #             'device_uuid'      : endpoint_device_uuid,
+        #             'name'             : endpoint_name,
+        #             'endpoint_type'    : endpoint.endpoint_type,
+        #             'created_at'       : now,
+        #             'updated_at'       : now,
+        #     })
 
         if endpoint_topology_uuid not in topology_uuids:
             related_topologies.append({
@@ -191,6 +204,23 @@ def device_set(db_engine : Engine, messagebroker : MessageBroker, request : Devi
             stmt = stmt.returning(EndPointModel.created_at, EndPointModel.updated_at)
             endpoint_updates = session.execute(stmt).fetchall()
             updated_endpoints = any([(updated_at > created_at) for created_at,updated_at in endpoint_updates])
+        
+        #---------------------- Experimental ---------------------------------
+        
+        # if len(optical_endpoints_data) > 0:
+        #     LOGGER.info(f"Optical endpoint data_ device_model {optical_endpoints_data}")
+        #     stmt = insert(OpticalEndPointModel).values(optical_endpoints_data)
+        #     stmt = stmt.on_conflict_do_update(
+        #         index_elements=[OpticalEndPointModel.endpoint_uuid],
+        #         set_=dict(
+        #             name             = stmt.excluded.name,
+        #             endpoint_type    = stmt.excluded.endpoint_type,
+        #             updated_at       = stmt.excluded.updated_at,
+        #         )
+        #     )
+        #     stmt = stmt.returning(OpticalEndPointModel.created_at, OpticalEndPointModel.updated_at)
+        #     optical_endpoint_updates = session.execute(stmt).fetchall()
+        #     updated_optical_endpoints = any([(updated_at > created_at) for created_at,updated_at in endpoint_updates])    
 
         device_topology_ids = []
         if not updated or len(related_topologies) > 1:
diff --git a/src/context/service/database/Events.py b/src/context/service/database/Events.py
index a88a4656a8cf078d2b90fe3a0c0ea22a4ec15a75..46688775eaabd5ab428ff9f0e77de52d25c9af41 100644
--- a/src/context/service/database/Events.py
+++ b/src/context/service/database/Events.py
@@ -17,27 +17,32 @@ from typing import Dict, Iterator, Set
 from common.message_broker.Message import Message
 from common.message_broker.MessageBroker import MessageBroker
 from common.proto.context_pb2 import (
-    ConnectionEvent, ContextEvent, DeviceEvent, EventTypeEnum, LinkEvent, ServiceEvent, SliceEvent, TopologyEvent)
+    ConnectionEvent, ContextEvent, DeviceEvent, EventTypeEnum, LinkEvent,
+    ServiceEvent, SliceEvent, TopologyEvent, OpticalConfigEvent
+)
 
 class EventTopicEnum(enum.Enum):
-    CONNECTION  = 'connection'
-    CONTEXT     = 'context'
-    DEVICE      = 'device'
-    LINK        = 'link'
-    POLICY_RULE = 'policy-rule'
-    SERVICE     = 'service'
-    SLICE       = 'slice'
-    TOPOLOGY    = 'topology'
+    CONNECTION    = 'connection'
+    CONTEXT       = 'context'
+    DEVICE        = 'device'
+    LINK          = 'link'
+    POLICY_RULE   = 'policy-rule'
+    SERVICE       = 'service'
+    SLICE         = 'slice'
+    TOPOLOGY      = 'topology'
+    OPTICALCONFIG = 'optical-config'
+  
 
 TOPIC_TO_EVENTCLASS = {
-    EventTopicEnum.CONNECTION.value  : ConnectionEvent,
-    EventTopicEnum.CONTEXT.value     : ContextEvent,
-    EventTopicEnum.DEVICE.value      : DeviceEvent,
-    EventTopicEnum.LINK.value        : LinkEvent,
-    #EventTopicEnum.POLICY_RULE.value : PolicyRuleEvent,  # Not defined in proto files
-    EventTopicEnum.SERVICE.value     : ServiceEvent,
-    EventTopicEnum.SLICE.value       : SliceEvent,
-    EventTopicEnum.TOPOLOGY.value    : TopologyEvent,
+    EventTopicEnum.CONNECTION.value    : ConnectionEvent,
+    EventTopicEnum.CONTEXT.value       : ContextEvent,
+    EventTopicEnum.DEVICE.value        : DeviceEvent,
+    EventTopicEnum.LINK.value          : LinkEvent,
+    #EventTopicEnum.POLICY_RULE.value   : PolicyRuleEvent,  # Not defined in proto files
+    EventTopicEnum.SERVICE.value       : ServiceEvent,
+    EventTopicEnum.SLICE.value         : SliceEvent,
+    EventTopicEnum.TOPOLOGY.value      : TopologyEvent,
+    EventTopicEnum.OPTICALCONFIG.value : OpticalConfigEvent,
 }
 
 CONSUME_TIMEOUT = 0.5 # seconds
@@ -61,6 +66,9 @@ def notify_event_topology(messagebroker : MessageBroker, event_type : EventTypeE
 def notify_event_device(messagebroker : MessageBroker, event_type : EventTypeEnum, device_id : Dict) -> None:
     notify_event(messagebroker, EventTopicEnum.DEVICE, event_type, {'device_id': device_id})
 
+def notify_event_opticalconfig(messagebroker : MessageBroker, event_type : EventTypeEnum, opticalconfig_id : Dict) -> None:
+    notify_event(messagebroker, EventTopicEnum.DEVICE, event_type, {'opticalconfig_id': opticalconfig_id})
+
 def notify_event_link(messagebroker : MessageBroker, event_type : EventTypeEnum, link_id : Dict) -> None:
     notify_event(messagebroker, EventTopicEnum.LINK, event_type, {'link_id': link_id})
 
diff --git a/src/context/service/database/OpticalConfig.py b/src/context/service/database/OpticalConfig.py
index 663c3bd0b16ac8af20cb1acf9176764d719b3046..ad38751eef9c73b734c13feeeabbc3329d58df0d 100644
--- a/src/context/service/database/OpticalConfig.py
+++ b/src/context/service/database/OpticalConfig.py
@@ -14,11 +14,19 @@
 
 import json, logging
 from sqlalchemy.dialects.postgresql import insert
+from common.message_broker.MessageBroker import MessageBroker
+from common.DeviceTypes import DeviceTypeEnum
 from sqlalchemy.engine import Engine
 from sqlalchemy.orm import Session, sessionmaker
 from sqlalchemy_cockroachdb import run_transaction
-from common.proto.context_pb2 import OpticalConfig, OpticalConfigId
-from .models.OpticalConfigModel import OpticalConfigModel
+from common.proto.context_pb2 import OpticalConfig, OpticalConfigId, Empty, EventTypeEnum
+from .models.OpticalConfig.OpticalConfigModel import OpticalConfigModel
+from .models.OpticalConfig.TransponderModel import  TransponderTypeModel, OpticalChannelModel
+from .models.OpticalConfig.RoadmModel import RoadmTypeModel, ChannelModel
+from .uuids.OpticalConfig import (
+    channel_get_uuid, opticalconfig_get_uuid, transponder_get_uuid, roadm_get_uuid
+)
+from .Events import notify_event_opticalconfig
 
 LOGGER = logging.getLogger(__name__)
 
@@ -28,8 +36,10 @@ def get_opticalconfig(db_engine : Engine):
         results = session.query(OpticalConfigModel).all()
         for obj in results:
             optical_config = OpticalConfig()
-            optical_config.config = json.dump(obj.config)
-            optical_config.opticalconfig_id.opticalconfig_uuid = obj.opticalconfig_uuid
+            optical_config.config = json.dumps(obj.dump())
+            ids_obj = obj.dump_id()
+            optical_config.opticalconfig_id.opticalconfig_uuid = ids_obj["opticalconfig_uuid"]
+            optical_config.device_id.device_uuid.uuid=ids_obj["device_uuid"]
             optical_configs.append(optical_config)
         return optical_configs
     obj = run_transaction(sessionmaker(bind=db_engine), callback)
@@ -37,33 +47,323 @@ def get_opticalconfig(db_engine : Engine):
 
 def set_opticalconfig(db_engine : Engine, request : OpticalConfig):
     opticalconfig_id = OpticalConfigId()
-    opticalconfig_id.opticalconfig_uuid = request.opticalconfig_id.opticalconfig_uuid
-    my_config_data = []
+    device_id = request.device_id
+    device_uuid =  request.device_id.device_uuid.uuid
+    channels = []
+    transponder = []
+    roadms = []
+    channel_namespace = None
+    OpticalConfig_data = []
+    config_type=None
+    #is_transpondre=False
+    opticalconfig_uuid = opticalconfig_get_uuid(device_id) 
+
     if request.config:
-        channels = []
-        transceivers = []
         config = json.loads(request.config)
-        if 'channels' in config and len(config['channels']) > 0:
-            channels = [channel['name']['index'] for channel in config['channels']]
-        if 'transceivers' in config and len(config['transceivers']['transceiver']) > 0:
-            transceivers = [transceiver for transceiver in config['transceivers']['transceiver']]
-
-        my_config_data = [
-            {
-                "opticalconfig_uuid": request.opticalconfig_id.opticalconfig_uuid,
-                "channels"          : channels,
-                "transcievers"      : transceivers,
-                "interfaces"        : json.dumps(config["interfaces"]["interface"]),
-                "channel_namespace" : config["channel_namespace"],
-                "endpoints"         : [json.dumps(endpoint) for endpoint in config["endpoints"]],
-                "frequency"         : config["frequency"] if "frequency" in config  else 0,
-                "operational_mode"  : config["operational_mode"] if "operational_mode" in config else 0,
-                "output_power"      : config["output_power"] if "output_power" in config else '',
-            }
-        ]
+        if 'channel_namespace' in config:
+            channel_namespace=config['channel_namespace']
+        if "type" in config:
+            config_type= config["type"]
+            if config_type == DeviceTypeEnum.OPTICAL_TRANSPONDER._value_:
+                is_transpondre = True
+                transceivers = []
+                if channel_namespace is None and  'channel_namespace' in config:
+                    channel_namespace=config['channel_namespace']
+                if 'transceivers' in config and len(config['transceivers']['transceiver']) > 0:
+                    transceivers = [transceiver for transceiver in config ['transceivers']['transceiver']]
+                if 'channels' in config and len(config['channels']) > 0:
+                    #channels = [channel['name']['index'] for channel in config['channels']]
+                    for channel_params in config['channels']:
+                        channels.append({
+                            # "opticalconfig_uuid":opticalconfig_uuid,
+                            "transponder_uuid"   : transponder_get_uuid(device_id),
+                            "channel_uuid"       : channel_get_uuid(channel_params['name']['index'],device_uuid),
+                            "channel_name"       : channel_params['name']['index'],
+                            "frequency"          : int(channel_params["frequency"]) if "frequency" in channel_params  else 0,
+                            "operational_mode"   : int(channel_params["operational-mode"]) if "operational-mode" in channel_params else 0,
+                            "target_output_power": channel_params["target-output-power"] if "target-output-power" in channel_params else '',
+                            "status"             : channel_params["status"] if "status" in channel_params else ""
+                        })
+
+                transponder.append({
+                    "transponder_uuid"  : transponder_get_uuid(device_id),
+                    "transcievers"      : transceivers,
+                    "interfaces"        : None,
+                    "opticalconfig_uuid": opticalconfig_uuid,
+                })
+
+            if config_type == DeviceTypeEnum.OPTICAL_ROADM._value_:
+                if channel_namespace is None and  'channel_namespace' in config:
+                    channel_namespace=config['channel_namespace']
+                if 'media_channels' in config and len(config['media_channels']) > 0:
+                    #channels = [channel['name']['index'] for channel in config['channels']]
+                    channel_num = 0
+                    for channel_params in config['media_channels']:
+                        channel_index = channel_params['channel_index'] if channel_params['channel_index'] is not None else None
+                        channels.append({
+                            # "opticalconfig_uuid":opticalconfig_uuid,
+                            "roadm_uuid"          : roadm_get_uuid(device_id),
+                            "channel_uuid"        : channel_get_uuid(f'media_channel_{channel_index}',device_uuid),
+                            "band_name"           : channel_params['band_name'],
+                            "lower_frequency"     : int(channel_params["lower_frequency"]) if "lower_frequency" in channel_params  else 0,
+                            "upper_frequency"     : int(channel_params["upper_frequency"]) if "upper_frequency" in channel_params  else 0,
+                            "dest_port"           : channel_params["dest_port"] if "dest_port" in channel_params else '',
+                            "src_port"            : channel_params["src_port"] if "src_port" in channel_params else '',
+                            "status"              : channel_params["status"] if "status" in channel_params else "",
+                            "type"                : 'media_channel',
+                            "optical_band_parent" : str(channel_params['optical_band_parent']) if 'optical_band_parent' in channel_params else None,
+                            "channel_index"       : channel_index if channel_index is not None else None,
+                        })
+                if 'optical_bands' in config and len(config['optical_bands']) > 0:
+                    #channels = [channel['name']['index'] for channel in config['channels']]
+                    channel_num = 0
+                    for channel_params in config['optical_bands']:
+                        channel_num += 1
+                        channels.append({
+                            # "opticalconfig_uuid":opticalconfig_uuid,
+                            "roadm_uuid"         : roadm_get_uuid(device_id),
+                            "channel_uuid"       : channel_get_uuid(f'optical_bands_{channel_num}',device_uuid),
+                            "band_name"          : channel_params['band_name'],
+                            "lower_frequency"    : int(channel_params["lower_frequency"]) if "lower_frequency" in channel_params  else 0,
+                            "upper_frequency"    : int(channel_params["upper_frequency"]) if "upper_frequency" in channel_params  else 0,
+                            "dest_port"          : channel_params["dest_port"] if "dest_port" in channel_params else '',
+                            "src_port"           : channel_params["src_port"] if "src_port" in channel_params else '',
+                            "status"             : channel_params["status"] if "status" in channel_params else "",
+                            "type"               : 'optical_band',
+                            "channel_index"      : channel_params['channel_index'] if 'channel_index' in channel_params else None,
+                            "optical_band_parent": None
+                        })
+
+                roadms.append({
+                    "roadm_uuid"         : roadm_get_uuid(device_id),
+                    "opticalconfig_uuid" : opticalconfig_uuid,
+                })
+
+        OpticalConfig_data.append({
+            "opticalconfig_uuid" : opticalconfig_uuid,
+            # "transcievers"      : transceivers,
+            # "interfaces"        :"",
+            "channel_namespace" : channel_namespace ,
+            "endpoints"         : [json.dumps(endpoint) for endpoint in config.get("endpoints",[])],
+            "device_uuid": device_uuid,
+            "type":config_type
+        })
+
+    def callback(session:Session)->bool:
+        stmt = insert(OpticalConfigModel).values(OpticalConfig_data)
+        stmt = stmt.on_conflict_do_update(
+            index_elements=[OpticalConfigModel.opticalconfig_uuid],
+            set_=dict(
+                channel_namespace=stmt.excluded.channel_namespace
+            )
+        )
+        stmt = stmt.returning(OpticalConfigModel.opticalconfig_uuid)
+        opticalconfig_id = session.execute(stmt).fetchone()
+        if config_type == DeviceTypeEnum.OPTICAL_TRANSPONDER._value_:
+            if (len(transponder)>0):
+                stmt = insert(TransponderTypeModel).values(transponder)
+                stmt = stmt.on_conflict_do_update(
+                        index_elements=[TransponderTypeModel.transponder_uuid],
+                        set_=dict(
+                            transcievers= stmt.excluded.transcievers ,
+                        )
+                        
+                    )
+                stmt = stmt.returning(TransponderTypeModel.transponder_uuid)
+                transponder_id = session.execute(stmt).fetchone()
+
+            if (len(channels) > 0):
+                stmt = insert(OpticalChannelModel).values(channels)
+                stmt = stmt.on_conflict_do_update(
+                    index_elements=[OpticalChannelModel.channel_uuid],
+                    set_=dict(
+                        channel_name= stmt.excluded.channel_name ,
+                        frequency = stmt.excluded.frequency,
+                        operational_mode=stmt.excluded.operational_mode,
+                        target_output_power=stmt.excluded.target_output_power,
+                    )
+                )
+                stmt = stmt.returning(OpticalChannelModel.channel_uuid)
+                opticalChannel_id = session.execute(stmt).fetchone()
+
+        if config_type == DeviceTypeEnum.OPTICAL_ROADM._value_:
+            if len(roadms) > 0:
+                stmt = insert(RoadmTypeModel).values(roadms)
+                stmt = stmt.on_conflict_do_update(
+                        index_elements=[RoadmTypeModel.roadm_uuid],
+                        set_=dict(
+                            circuits=stmt.excluded.circuits
+                        )
+                    )
+                stmt = stmt.returning(RoadmTypeModel.roadm_uuid)
+                roadm_id = session.execute(stmt).fetchone()
+
+            if (channels is not None and  len(channels) > 0):
+                stmt = insert(ChannelModel).values(channels)
+                stmt = stmt.on_conflict_do_update(
+                    index_elements=[ChannelModel.channel_uuid ],
+                    set_=dict(
+                        band_name           = stmt.excluded.band_name ,
+                        lower_frequency     = stmt.excluded.lower_frequency,
+                        upper_frequency     = stmt.excluded.upper_frequency,
+                        type                = stmt.excluded.type,
+                        status              = stmt.excluded.status,
+                        dest_port           = stmt.excluded.dest_port,
+                        src_port            = stmt.excluded.src_port,
+                        channel_index       = stmt.excluded.channel_index,
+                        optical_band_parent = stmt.excluded.optical_band_parent
+                    )
+                )
+                stmt = stmt.returning(ChannelModel.channel_uuid)
+                opticalChannel_id = session.execute(stmt).fetchone()
+
+    opticalconfig_id = run_transaction(sessionmaker(bind=db_engine), callback)
+    return {'opticalconfig_uuid': opticalconfig_id}
+
+def update_opticalconfig(db_engine : Engine, request : OpticalConfig):
+    opticalconfig_id = OpticalConfigId()
+    device_id = request.device_id
+    device_uuid =  request.device_id.device_uuid.uuid
+    channels = []
+    transponder=[]
+    roadms=[]
+    channel_namespace= None
+    OpticalConfig_data = []
+    config_type=None
+    #is_transpondre=False
+    opticalconfig_uuid =opticalconfig_get_uuid(device_id) 
+
+    if request.config :
+        config = json.loads(request.config)
+
+        if  'new_config' in config:
+            if 'type' in config:
+                config_type = config['type']
+            if "type" in config['new_config'] and config_type is None:
+                config_type = config['new_config']["type"]    
+            if 'channel_namespace' in config['new_config']:
+                channel_namespace = config['new_config'] ['channel_namespace']
+
+            if config_type == DeviceTypeEnum.OPTICAL_TRANSPONDER._value_:
+                is_transpondre = True
+                transceivers = []
+                if channel_namespace is None and  'channel_namespace' in config:
+                    channel_namespace=config['channel_namespace']
+
+                if 'transceivers' in config['new_config'] and len(config['new_config']['transceivers']['transceiver']) > 0:
+                    transceivers = [transceiver for transceiver in config['new_config'] ['transceivers']['transceiver']]
+                    
+                if 'channels' in config['new_config'] and len(config['new_config']['channels']) > 0:
+                    #channels = [channel['name']['index'] for channel in config['channels']]
+            
+                    for channel_params in config['new_config']['channels']:
+                        channels.append({
+                            # "opticalconfig_uuid":opticalconfig_uuid,
+                            "transponder_uuid"    : transponder_get_uuid(device_id),
+                            "channel_uuid"        : channel_get_uuid(channel_params['name']['index'],device_uuid),
+                            "channel_name"        : channel_params['name']['index'],
+                            "frequency"           : int(channel_params["frequency"]) if "frequency" in channel_params  else 0,
+                            "operational_mode"    : int(channel_params["operational-mode"]) if "operational-mode" in channel_params else 0,
+                            "target_output_power" : channel_params["target-output-power"] if "target-output-power" in channel_params else '',
+                            "status"              : channel_params["status"] if "status" in channel_params else ""
+                        })
+                elif 'flow_handled' in config and 'new_config' in config :
+                    target_config = config['new_config']
+                    dest_pair = None
+                    src = None
+                    dst = None
+                    src_pair = config['flow_handled'][0]
+                    
+                    src, dst = src_pair
+                    if src_pair is None and len(config['flow_handled'])>1 :
+                        dest_pair = config['flow_handled'][1]
+                        src, dst = dest_pair
+                    channel_index = src if src is not None and src !='0' else dst
+                    channel_name = f"channel-{channel_index}"
+                    channels.append({
+                        # "opticalconfig_uuid":opticalconfig_uuid,
+                        "transponder_uuid"    : transponder_get_uuid(device_id),
+                        "channel_uuid"        : channel_get_uuid(channel_name,device_uuid),
+                        "channel_name"        : channel_name,
+                        "frequency"           : int(target_config["frequency"]) if "frequency" in target_config  else 0,
+                        "operational_mode"    : int(target_config["operational-mode"]) if "operational-mode" in target_config else 0,
+                        "target_output_power" : target_config["target-output-power"] if "target-output-power" in target_config else '',
+                        "status"              : target_config["status"] if "status" in target_config else ""
+                    })
+
+                transponder.append({
+                    "transponder_uuid"  : transponder_get_uuid(device_id),
+                    "transcievers"      : transceivers,
+                    "interfaces"        : None,
+                    "opticalconfig_uuid": opticalconfig_uuid,
+                })
+
+            if config_type == DeviceTypeEnum.OPTICAL_ROADM._value_:
+                if channel_namespace is None and  'channel_namespace' in config['new_config']:
+                    channel_namespace=config['new_config']['channel_namespace']
+                if 'is_opticalband' in config and not config['is_opticalband']:
+                    #channels = [channel['name']['index'] for channel in config['channels']]
+                    if 'flow_handled' in config  and len(config['flow_handled'])>0 :
+                        num = 0    
+                        flow_id = config["new_config"]["flow_id"] if 'flow_id' in config['new_config'] else None
+                        for flow in config['flow_handled']:
+                            src_port, dest_port = flow
+                            channel_index = flow_id + num
+                            num += 1
+                            channels.append({
+                                # "opticalconfig_uuid":opticalconfig_uuid,
+                                "roadm_uuid"          : roadm_get_uuid(device_id),
+                                "channel_uuid"        : channel_get_uuid(f'media_channel_{channel_index}',device_uuid),
+                                "band_name"           : config['new_config']['band_type'],
+                                "lower_frequency"     : int(int(config['new_config']['frequency']) - (int(config['new_config']['band'])/2)) if "frequency" in config['new_config']  else 0,
+                                "upper_frequency"     : int(int(config['new_config']['frequency']) + (int(config['new_config']['band'])/2)) if "frequency" in config['new_config']  else 0,
+                                "dest_port"           : dest_port,
+                                "src_port"            : src_port,
+                                "status"              : config['new_config']["status"] if "status" in config['new_config'] else "",
+                                "type"                : 'media_channel',
+                                "optical_band_parent" : str( config['new_config']['ob_id']) if 'ob_id' in config['new_config'] else None,
+                                "channel_index"       : str(channel_index) if channel_index is not None else None
+                            })
+                if 'is_opticalband' in config and config['is_opticalband']:
+                    #channels = [channel['name']['index'] for channel in config['channels']]
+                    if 'flow_handled' in config and len(config['flow_handled']) > 0:
+                        ob_id = config['new_config']['ob_id'] if 'ob_id' in config['new_config'] else None
+                        num = 0
+                        for flow in config['flow_handled']:
+                            src_port, dest_port = flow
+                            channel_index = ob_id + num
+                            num += 1
+                            channels.append({
+                                # "opticalconfig_uuid":opticalconfig_uuid,
+                                "roadm_uuid"      : roadm_get_uuid(device_id),
+                                "channel_uuid"    : channel_get_uuid(f'optical_bands_{channel_index}',device_uuid),
+                                "band_name"       : config['new_config']['band_type'],
+                                "lower_frequency" : int(config['new_config']["low-freq"]) if "low-freq" in config['new_config']  else 0,
+                                "upper_frequency" : int(config['new_config']["up-freq"]) if "up-freq" in config['new_config']  else 0,
+                                "dest_port"       : dest_port,
+                                "src_port"        : src_port,
+                                "status"          : config['new_config']["status"] if "status" in config['new_config'] else "",
+                                "type"            : 'optical_band',
+                                "channel_index"   : str( channel_index) if channel_index is not None else None
+                            })
+
+                roadms.append({
+                    "roadm_uuid"        : roadm_get_uuid(device_id),
+                    "opticalconfig_uuid": opticalconfig_uuid,
+                })
+
+        OpticalConfig_data.append({
+            "opticalconfig_uuid": opticalconfig_uuid,
+            # "transcievers"      : transceivers,
+            # "interfaces"        :"",
+            "channel_namespace" : channel_namespace ,
+            "endpoints"         : [json.dumps(endpoint) for endpoint in config['new_config'].get("endpoints",[])],
+            "device_uuid"       : device_uuid,
+            "type"              : config_type
+        })
 
     def callback(session:Session)->bool:
-        stmt = insert(OpticalConfigModel).values(my_config_data)
+        stmt = insert(OpticalConfigModel).values(OpticalConfig_data)
         stmt = stmt.on_conflict_do_update(
             index_elements=[OpticalConfigModel.opticalconfig_uuid],
             set_=dict(
@@ -71,11 +371,66 @@ def set_opticalconfig(db_engine : Engine, request : OpticalConfig):
             )
         )
         stmt = stmt.returning(OpticalConfigModel.opticalconfig_uuid)
-        id = session.execute(stmt).fetchone()
+        opticalconfig_id = session.execute(stmt).fetchone()
+        if config_type == DeviceTypeEnum.OPTICAL_TRANSPONDER._value_:
+            if (len(transponder)>0):
+                stmt = insert(TransponderTypeModel).values(transponder)
+                stmt = stmt.on_conflict_do_update(
+                    index_elements=[TransponderTypeModel.transponder_uuid],
+                    set_=dict(
+                        transcievers= stmt.excluded.transcievers,
+                    )
+                )
+                stmt = stmt.returning(TransponderTypeModel.transponder_uuid)
+                transponder_id = session.execute(stmt).fetchone()
+
+            if len(channels) > 0:
+                stmt = insert(OpticalChannelModel).values(channels)
+                stmt = stmt.on_conflict_do_update(
+                    index_elements=[OpticalChannelModel.channel_uuid ],
+                    set_=dict(
+                        channel_name= stmt.excluded.channel_name ,
+                        frequency = stmt.excluded.frequency,
+                        operational_mode=stmt.excluded.operational_mode,
+                        target_output_power=stmt.excluded.target_output_power,
+                        status = stmt.excluded.status,
+                    )
+                )
+                stmt = stmt.returning(OpticalChannelModel.channel_uuid)
+                opticalChannel_id = session.execute(stmt).fetchone()
+        if config_type == DeviceTypeEnum.OPTICAL_ROADM._value_:
+            if len(roadms) > 0:
+                stmt = insert(RoadmTypeModel).values(roadms)
+                stmt = stmt.on_conflict_do_update(
+                    index_elements=[RoadmTypeModel.roadm_uuid],
+                    set_=dict(
+                        circuits=stmt.excluded.circuits
+                    )
+                )
+                stmt = stmt.returning(RoadmTypeModel.roadm_uuid)
+                roadm_id = session.execute(stmt).fetchone()
+                
+            if (channels is not None and  len(channels) > 0):
+                stmt = insert(ChannelModel).values(channels)
+                stmt = stmt.on_conflict_do_update(
+                    index_elements=[ChannelModel.channel_uuid ],
+                    set_=dict(
+                        band_name= stmt.excluded.band_name ,
+                        lower_frequency = stmt.excluded.lower_frequency,
+                        upper_frequency = stmt.excluded.upper_frequency,
+                        type=stmt.excluded.type,
+                        status=stmt.excluded.status,
+                        dest_port=stmt.excluded.dest_port,
+                        src_port=stmt.excluded.src_port,
+                    )
+                )
+                stmt = stmt.returning(ChannelModel.channel_uuid)
+                opticalChannel_id = session.execute(stmt).fetchone()
+
     opticalconfig_id = run_transaction(sessionmaker(bind=db_engine), callback)
     return {'opticalconfig_uuid': opticalconfig_id}
 
-def select_opticalconfig(db_engine:Engine,request:OpticalConfigId):
+def select_opticalconfig(db_engine : Engine, request : OpticalConfigId):
     def callback(session : Session) -> OpticalConfig:
         result = OpticalConfig()
         stmt = session.query(OpticalConfigModel)
@@ -83,6 +438,102 @@ def select_opticalconfig(db_engine:Engine,request:OpticalConfigId):
         obj = stmt.first()
         if obj is not None:
             result.config = json.dumps(obj.dump())
-            result.opticalconfig_id.opticalconfig_uuid = obj.opticalconfig_uuid
+            ids_obj = obj.dump_id()
+            result.opticalconfig_id.opticalconfig_uuid = ids_obj["opticalconfig_uuid"]
+            result.device_id.device_uuid.uuid=ids_obj["device_uuid"]
         return result
     return run_transaction(sessionmaker(bind=db_engine, expire_on_commit=False), callback)
+
+def delete_opticalconfig(db_engine : Engine, messagebroker : MessageBroker, request : OpticalConfigId):
+    opticalconfig_uuid = request.opticalconfig_uuid
+    def callback(session : Session):
+        #query = session.query(OpticalConfigModel)
+        num_deleted = session.query(OpticalConfigModel).filter_by(opticalconfig_uuid=opticalconfig_uuid).delete()
+        return num_deleted > 0
+    deleted = run_transaction(sessionmaker(bind=db_engine), callback)
+    if deleted:
+        notify_event_opticalconfig(messagebroker, EventTypeEnum.EVENTTYPE_REMOVE, opticalconfig_uuid)
+    return Empty()
+
+def delete_opticalchannel(db_engine : Engine, messagebroker : MessageBroker, request : OpticalConfig):
+    config = json.loads(request.config)
+    device_id = request.device_id
+    device_uuid =  request.device_id.device_uuid.uuid
+    opticalconfig_uuid = request.opticalconfig_id.opticalconfig_uuid
+    channels = []
+    config_type = None
+
+    if "type" in config :
+        config_type= config["type"]    
+    if 'new_config' in config:
+        if config_type == DeviceTypeEnum.OPTICAL_TRANSPONDER._value_:  
+            for flow in config['flow']:
+                src,dest = flow
+                channel_index= src if src is not None and  src!='0' else dest
+                channel_name= f"channel-{channel_index}"
+                channels.append({
+                    # "opticalconfig_uuid":opticalconfig_uuid,
+                    "transponder_uuid"   : transponder_get_uuid(device_id),
+                    "channel_uuid"       : channel_get_uuid(channel_name ,device_uuid),
+                    "channel_name"       : channel_name ,
+                    "frequency"          : 0,
+                    "operational_mode"   : None,
+                    "target_output_power": None,
+                    "status"             : "DISABLED"
+                })
+        elif config_type == DeviceTypeEnum.OPTICAL_ROADM._value_:
+            channel_num = 0
+            if 'flow' in config :
+                if 'is_opticalband' in config:
+                    if config['is_opticalband']:
+                        ob_id = config['new_config']['ob_id'] if 'ob_id' in config['new_config'] else None
+                        if len(config['flow']) == 0:
+                            channel_index = ob_id + channel_num
+                            channel_name = f'optical_bands_{channel_index}' 
+                            channels.append(channel_get_uuid(channel_name, device_uuid))
+                        else:
+                            for flow in config['flow']:
+                                channel_index = ob_id+channel_num
+                                channel_num +=1
+                                channel_name = f'optical_bands_{channel_index}' 
+                                channels.append(channel_get_uuid(channel_name, device_uuid))
+                    else:
+                        if config['flow'] == 0:
+                            channel_num = 1
+                            channel_name = f'media_channel_{channel_num}'
+                            channels.append(channel_get_uuid(channel_name, device_uuid))
+                        else:
+                            for flow in config['flow']:
+                                channel_num += 1
+                                channel_name = f'media_channel_{channel_num}'
+                                channels.append(channel_get_uuid(channel_name, device_uuid))
+
+    def callback(session : Session):
+        all_suceed = []
+        if config_type == DeviceTypeEnum.OPTICAL_ROADM._value_:
+            for channel_uuid in channels:
+                num_deleted = session.query(ChannelModel).filter_by(channel_uuid=channel_uuid).delete()
+                all_suceed.append(num_deleted > 0)
+        elif config_type == DeviceTypeEnum.OPTICAL_TRANSPONDER._value_:
+            if len(channels) > 0:
+                stmt = insert(OpticalChannelModel).values(channels)
+                stmt = stmt.on_conflict_do_update(
+                    index_elements=[OpticalChannelModel.channel_uuid ],
+                    set_=dict(
+                        channel_name= stmt.excluded.channel_name ,
+                        frequency = stmt.excluded.frequency,
+                        operational_mode=stmt.excluded.operational_mode,
+                        target_output_power=stmt.excluded.target_output_power,
+                        status=stmt.excluded.status
+                    )
+                )
+                stmt = stmt.returning(OpticalChannelModel.channel_uuid)
+                opticalChannel_id = session.execute(stmt).fetchone()
+                all_suceed.append(True)
+        return all_suceed
+
+    all_deleted = run_transaction(sessionmaker(bind=db_engine), callback)
+    for stat in all_deleted:
+        if not stat: return
+    notify_event_opticalconfig(messagebroker, EventTypeEnum.EVENTTYPE_REMOVE, opticalconfig_uuid)
+    return Empty()
diff --git a/src/context/service/database/OpticalLink.py b/src/context/service/database/OpticalLink.py
new file mode 100644
index 0000000000000000000000000000000000000000..93f43ef34497cb353f50a9b001da8ec4a6f5f92f
--- /dev/null
+++ b/src/context/service/database/OpticalLink.py
@@ -0,0 +1,183 @@
+# 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 datetime, logging
+from sqlalchemy.dialects.postgresql import insert
+from sqlalchemy.engine import Engine
+from sqlalchemy.orm import Session, selectinload, sessionmaker
+from sqlalchemy_cockroachdb import run_transaction
+from typing import Dict, List, Optional, Set, Tuple
+from common.proto.context_pb2 import (
+    Empty, EventTypeEnum, OpticalLink, LinkId, OpticalLinkList, TopologyId
+)
+from common.message_broker.MessageBroker import MessageBroker
+from common.method_wrappers.ServiceExceptions import NotFoundException
+from common.tools.object_factory.Link import json_link_id
+from .models.OpticalLinkModel import OpticalLinkModel,OpticalLinkEndPointModel 
+from .models.TopologyModel import TopologyOpticalLinkModel, TopologyModel
+from .uuids.EndPoint import endpoint_get_uuid
+from .uuids.Link import link_get_uuid
+from .uuids.Topology import topology_get_uuid
+from .Events import notify_event_link
+
+LOGGER = logging.getLogger(__name__)
+
+
+def optical_link_list_objs(db_engine : Engine) -> OpticalLinkList:
+    def callback(session : Session) -> List[Dict]:
+        obj_list : List[OpticalLinkModel] = session.query(OpticalLinkModel)\
+            .options(selectinload(OpticalLinkModel.opticallink_endpoints))\
+            .all()
+        return [obj.dump() for obj in obj_list]
+    links = run_transaction(sessionmaker(bind=db_engine), callback)
+    return OpticalLinkList(optical_links=links)
+
+def optical_link_get(db_engine : Engine, request : LinkId) -> OpticalLink:
+    link_uuid = link_get_uuid(request, allow_random=False)
+    def callback(session : Session) -> Optional[Dict]:
+        obj : Optional[OpticalLinkModel] = session.query(OpticalLinkModel)\
+            .options(selectinload(OpticalLinkModel.opticallink_endpoints))\
+            .filter_by(opticallink_uuid=link_uuid).one_or_none()
+        return None if obj is None else obj.dump()
+    obj = run_transaction(sessionmaker(bind=db_engine), callback)
+    if obj is None:
+        raw_link_uuid = request.link_uuid.uuid
+        raise NotFoundException('Optical Link', raw_link_uuid, extra_details=[
+            'link_uuid generated was: {:s}'.format(link_uuid)
+        ])
+    return OpticalLink(**obj)
+
+def optical_link_set(db_engine : Engine, messagebroker : MessageBroker, request : OpticalLink) -> LinkId:
+    raw_link_uuid = request.link_id.link_uuid.uuid
+    raw_link_name = request.name
+    link_name = raw_link_uuid if len(raw_link_name) == 0 else raw_link_name
+    link_uuid = link_get_uuid(request.link_id, link_name=link_name, allow_random=True)
+
+    now = datetime.datetime.utcnow()
+
+    # By default, always add link to default Context/Topology
+    topology_uuids : Set[str] = set()
+    related_topologies : List[Dict] = list()
+    _,topology_uuid = topology_get_uuid(TopologyId(), allow_random=False, allow_default=True)
+    related_topologies.append({
+        'topology_uuid': topology_uuid,
+        'optical_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):
+        endpoint_topology_uuid, endpoint_device_uuid, endpoint_uuid = endpoint_get_uuid(
+              endpoint_id, endpoint_name="", allow_random=True)
+
+        link_endpoints_data.append({
+            'link_uuid'    : link_uuid,
+            'endpoint_uuid': endpoint_uuid,
+           
+        })
+
+        if endpoint_topology_uuid not in topology_uuids:
+            related_topologies.append({
+                'topology_uuid': endpoint_topology_uuid,
+                'optical_link_uuid'    : link_uuid,
+            })
+            topology_uuids.add(endpoint_topology_uuid)
+
+    optical_link_data = [{
+        'opticallink_uuid'     : link_uuid,
+        'name'                 : link_name,
+        'created_at'           : now,
+        'updated_at'           : now,
+        'length'               : request.optical_details.length,
+        "src_port"             : request.optical_details.src_port,
+        "dst_port"             : request.optical_details.dst_port,
+        "local_peer_port"      : request.optical_details.local_peer_port,
+        "remote_peer_port"     : request.optical_details.remote_peer_port,
+        "used"                 : request.optical_details.used,
+        "c_slots"              : request.optical_details.c_slots ,
+        "l_slots"              : request.optical_details.l_slots,
+        "s_slots"              : request.optical_details.s_slots,
+    }]
+
+    def callback(session : Session) -> Tuple[bool, List[Dict]]:
+        stmt = insert(OpticalLinkModel).values(optical_link_data)
+        stmt = stmt.on_conflict_do_update(
+            index_elements=[OpticalLinkModel.opticallink_uuid],
+            set_=dict(
+                updated_at          = stmt.excluded.updated_at,
+                src_port            = stmt.excluded.src_port,
+                dst_port            = stmt.excluded.dst_port,  
+                local_peer_port     = stmt.excluded.local_peer_port,
+                remote_peer_port    = stmt.excluded.remote_peer_port,
+                used                = stmt.excluded.used ,
+                c_slots             = stmt.excluded.c_slots,
+                l_slots             = stmt.excluded.l_slots,
+                s_slots             = stmt.excluded.s_slots
+            )
+        )
+        stmt = stmt.returning(OpticalLinkModel.created_at, OpticalLinkModel.updated_at)
+        created_at,updated_at = session.execute(stmt).fetchone()
+        updated = updated_at > created_at
+
+        updated_endpoints = False
+        if len(link_endpoints_data) > 0:
+            stmt = insert(OpticalLinkEndPointModel).values(link_endpoints_data)
+            stmt = stmt.on_conflict_do_nothing(
+                index_elements=[OpticalLinkEndPointModel.link_uuid, OpticalLinkEndPointModel.endpoint_uuid]
+            )
+            link_endpoint_inserts = session.execute(stmt)
+            updated_endpoints = int(link_endpoint_inserts.rowcount) > 0
+
+        if not updated or len(related_topologies) > 1:
+            # Only update topology-link relations when link is created (not updated) or when endpoint_ids are
+            # modified (len(related_topologies) > 1).
+            stmt = insert(TopologyOpticalLinkModel).values(related_topologies)
+            stmt = stmt.on_conflict_do_nothing(
+                index_elements=[TopologyOpticalLinkModel.topology_uuid, TopologyOpticalLinkModel.optical_link_uuid]
+            )
+            stmt = stmt.returning(TopologyOpticalLinkModel.topology_uuid)
+            topology_uuids = session.execute(stmt).fetchall()
+
+            #LOGGER.warning('RAW topology_uuids={:s}'.format(str(topology_uuids)))
+            if len(topology_uuids) > 0:
+                topology_uuids = [topology_uuid[0] for topology_uuid in topology_uuids]
+                #LOGGER.warning('NEW topology_uuids={:s}'.format(str(topology_uuids)))
+                query = session.query(TopologyModel)
+                query = query.filter(TopologyModel.topology_uuid.in_(topology_uuids))
+                link_topologies : List[TopologyModel] = query.all()
+                link_topology_ids = [obj.dump_id() for obj in link_topologies]
+                #LOGGER.warning('link_topology_ids={:s}'.format(str(link_topology_ids)))
+        return updated or updated_endpoints
+
+    updated = run_transaction(sessionmaker(bind=db_engine), callback )
+    link_id = json_link_id(link_uuid)
+    event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE
+    notify_event_link(messagebroker, event_type, link_id)
+
+    return LinkId(**link_id)
+
+def optical_link_delete(db_engine : Engine, messagebroker : MessageBroker, request : LinkId) -> Empty:
+    link_uuid = link_get_uuid(request, allow_random=False)
+
+    def callback(session : Session) -> bool:
+        num_deleted = session.query(OpticalLinkModel).filter_by(opticallink_uuid=link_uuid).delete()
+        return num_deleted > 0
+    deleted = run_transaction(sessionmaker(bind=db_engine), callback)
+
+    link_id = json_link_id(link_uuid)
+    if deleted:
+        notify_event_link(messagebroker, EventTypeEnum.EVENTTYPE_REMOVE, link_id)
+
+    return Empty()
diff --git a/src/context/service/database/Topology.py b/src/context/service/database/Topology.py
index e1c59ea118915e2ad0d69d4b8cacf59c354b8297..7dc1b60f977fb4447fa86a47a48d0335270c8f1a 100644
--- a/src/context/service/database/Topology.py
+++ b/src/context/service/database/Topology.py
@@ -27,7 +27,8 @@ from common.tools.object_factory.Topology import json_topology_id
 from context.Config import ALLOW_EXPLICIT_ADD_DEVICE_TO_TOPOLOGY, ALLOW_EXPLICIT_ADD_LINK_TO_TOPOLOGY
 from .models.DeviceModel import DeviceModel
 from .models.LinkModel import LinkModel
-from .models.TopologyModel import TopologyDeviceModel, TopologyLinkModel, TopologyModel
+from .models.OpticalLinkModel import OpticalLinkModel
+from .models.TopologyModel import TopologyDeviceModel, TopologyLinkModel, TopologyModel, TopologyOpticalLinkModel
 from .uuids.Context import context_get_uuid
 from .uuids.Device import device_get_uuid
 from .uuids.Link import link_get_uuid
@@ -79,6 +80,7 @@ def topology_get_details(db_engine : Engine, request : TopologyId) -> TopologyDe
         obj : Optional[TopologyModel] = session.query(TopologyModel)\
             .options(selectinload(TopologyModel.topology_devices, TopologyDeviceModel.device, DeviceModel.endpoints))\
             .options(selectinload(TopologyModel.topology_links, TopologyLinkModel.link, LinkModel.link_endpoints))\
+            .options(selectinload(TopologyModel.topology_optical_links, TopologyOpticalLinkModel.optical_link, OpticalLinkModel.opticallink_endpoints))\
             .filter_by(topology_uuid=topology_uuid).one_or_none()
             #.options(selectinload(DeviceModel.components))\
         return None if obj is None else obj.dump_details()
diff --git a/src/context/service/database/models/DeviceModel.py b/src/context/service/database/models/DeviceModel.py
index 2aeb90dfdeaa57ba96ff9c9ed095f363c5f8f0fb..0613caba6a433d4440908f4f796c26349f8d9af7 100644
--- a/src/context/service/database/models/DeviceModel.py
+++ b/src/context/service/database/models/DeviceModel.py
@@ -34,10 +34,11 @@ class DeviceModel(_Base):
     updated_at                = Column(DateTime, nullable=False)
 
     #topology_devices = relationship('TopologyDeviceModel', back_populates='device')
-    config_rules = relationship('DeviceConfigRuleModel', passive_deletes=True) # lazy='joined', back_populates='device'
-    endpoints    = relationship('EndPointModel', passive_deletes=True) # lazy='joined', back_populates='device'
-    components   = relationship('ComponentModel', passive_deletes=True) # lazy='joined', back_populates='device' 
-    controller   = relationship('DeviceModel', remote_side=[device_uuid], passive_deletes=True) # lazy='joined', back_populates='device'
+    config_rules   = relationship('DeviceConfigRuleModel', passive_deletes=True) # lazy='joined', back_populates='device'
+    endpoints      = relationship('EndPointModel', passive_deletes=True) # lazy='joined', back_populates='device'
+    components     = relationship('ComponentModel', passive_deletes=True) # lazy='joined', back_populates='device' 
+    controller     = relationship('DeviceModel', remote_side=[device_uuid], passive_deletes=True) # lazy='joined', back_populates='device'
+    optical_config = relationship('OpticalConfigModel', passive_deletes=True)
 
     def dump_id(self) -> Dict:
         return {'device_uuid': {'uuid': self.device_uuid}}
diff --git a/src/context/service/database/models/EndPointModel.py b/src/context/service/database/models/EndPointModel.py
index 6355f14af453b3695bb688285aa19c8641aac4c0..37a03393bd6a571d8587be7f9c345097971d5111 100644
--- a/src/context/service/database/models/EndPointModel.py
+++ b/src/context/service/database/models/EndPointModel.py
@@ -33,8 +33,9 @@ class EndPointModel(_Base):
     updated_at        = Column(DateTime, nullable=False)
     endpoint_location = Column(String, nullable=True)
 
-    device            = relationship('DeviceModel',          back_populates='endpoints') # lazy='selectin'
-    topology          = relationship('TopologyModel', lazy='selectin')
+    device                 = relationship('DeviceModel',              back_populates='endpoints') # lazy='selectin'
+    topology               = relationship('TopologyModel',            lazy='selectin')
+    optical_link_endpoints = relationship('OpticalLinkEndPointModel', back_populates='endpoint' )
     #link_endpoints    = relationship('LinkEndPointModel',    back_populates='endpoint' )
     #service_endpoints = relationship('ServiceEndPointModel', back_populates='endpoint' )
 
diff --git a/src/context/service/database/models/OpticalConfig/OpticalConfigModel.py b/src/context/service/database/models/OpticalConfig/OpticalConfigModel.py
new file mode 100644
index 0000000000000000000000000000000000000000..fa77898337055c88edc120aa53e517ffcd6ed2b1
--- /dev/null
+++ b/src/context/service/database/models/OpticalConfig/OpticalConfigModel.py
@@ -0,0 +1,64 @@
+# 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
+from sqlalchemy import Column, String, ForeignKey
+from sqlalchemy.dialects.postgresql import ARRAY
+from sqlalchemy.orm import relationship
+from context.service.database.models._Base import _Base
+
+class OpticalConfigModel(_Base):
+    __tablename__ = 'optical_config'
+    opticalconfig_uuid = Column(String, primary_key=True)
+    channel_namespace  = Column(String, nullable=True)
+    endpoints          = Column(ARRAY(String), nullable=True)
+    type               = Column(String,nullable=False)
+
+    # transcievers   = Column(ARRAY(String), nullable=True)
+    # interfaces     = Column(String, nullable=True)
+    # channels       = relationship("OpticalChannelModel")
+    transponders   = relationship("TransponderTypeModel")
+    roadms         = relationship("RoadmTypeModel")
+
+    device_uuid = Column(ForeignKey("device.device_uuid",ondelete="CASCADE"),index=True ,nullable=False)
+    device = relationship("DeviceModel",  back_populates='optical_config')
+
+    def dump_id (self ):
+        return {
+            "opticalconfig_uuid":self.opticalconfig_uuid,
+            "device_uuid" :self.device_uuid
+        }
+
+    def dump(self):
+        obj={
+            # "channels"          : [channel.dump() for channel in self.channels],
+            # "transceivers"      : {"transceiver": [transciever for transciever in self.transcievers]},
+            # "interfaces"        : {"interface":json.loads(self.interfaces) if self.interfaces else ''},
+            "channel_namespace" : self.channel_namespace,
+            "endpoints"         : [json.loads(endpoint) for endpoint in self.endpoints if endpoint],
+            "device_name"       : self.device.device_name,
+            "type"              : self.type
+        }
+        if self.type =="optical-transponder" :
+            channels= [transponer.dump() for transponer in self.transponders ][0]
+            obj['channels']=channels['channels'] if 'channels' in channels else None
+            obj['transceivers']=channels['transceivers'] if 'transceivers' in channels else None
+            obj['interfaces']=channels['interfaces'] if 'interfaces' in channels else None
+            obj['trasponder_uuid']=channels['trasponder_uuid'] if 'trasponder_uuid' in channels else None
+            
+        if self.type =="optical-roadm" :
+            channels=[roadms.dump() for roadms in self.roadms ][0]
+            obj['channels']=channels['channels'] if 'channels' in channels else None
+            obj['roadm_uuid']=channels['roadm_uuid'] if 'roadm_uuid' in channels else None
+        return obj
diff --git a/src/context/service/database/models/OpticalConfig/RoadmModel.py b/src/context/service/database/models/OpticalConfig/RoadmModel.py
new file mode 100644
index 0000000000000000000000000000000000000000..31ebf4cfabb2b91252b3c80884d47b93d07db033
--- /dev/null
+++ b/src/context/service/database/models/OpticalConfig/RoadmModel.py
@@ -0,0 +1,74 @@
+# 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 sqlalchemy import Column, String, Integer , ForeignKey
+from sqlalchemy.orm import relationship
+from context.service.database.models._Base import _Base
+
+class RoadmTypeModel (_Base):
+    __tablename__      = 'roadm_type'
+    roadm_uuid         = Column(String, primary_key=True)
+    circuits           = Column(String, nullable=True)
+    opticalconfig_uuid = Column(ForeignKey('optical_config.opticalconfig_uuid', ondelete='CASCADE'), index=True, nullable=False)
+    channels           = relationship("ChannelModel")
+    opticalconfig      = relationship('OpticalConfigModel', back_populates='roadms')
+
+    def dump_id (self): 
+        return {
+            "roadm_uuid" : self.roadm_uuid
+        }
+
+    def dump (self):
+        return {
+            "channels"   : [channel.dump() for channel in self.channels],
+            "roadm_uuid" : self.dump_id(),
+        }
+
+class ChannelModel(_Base):
+    __tablename__ = 'channel'
+
+    channel_uuid        = Column(String,  primary_key=True)
+    band_name           = Column(String,  nullable=True)
+    lower_frequency     = Column(Integer, nullable=True)
+    upper_frequency     = Column(Integer, nullable=True)
+    channel_index       = Column(String,  nullable=True)
+    status              = Column(String,  nullable=True)
+    src_port            = Column(String,  nullable=True)
+    dest_port           = Column(String,  nullable=True)
+    type                = Column(String,  nullable=False)
+    optical_band_parent = Column(String,  nullable=True)
+    roadm_uuid          = Column(ForeignKey('roadm_type.roadm_uuid', ondelete='CASCADE'), nullable=False)
+
+    roadm      = relationship('RoadmTypeModel',back_populates='channels')
+
+    # opticalconfig_uuid = Column(ForeignKey('optical_config.opticalconfig_uuid', ondelete='CASCADE'), primary_key=True)
+    # opticalconfig      = relationship('OpticalConfigModel', back_populates='channels')
+
+    def dump_id (self ):
+        return {
+            "channel_uuid": self.channel_uuid
+        }
+
+    def dump(self):
+        return {
+            "band_name"           : self.band_name,
+            "lower_frequency"     : self.lower_frequency,
+            "upper_frequency"     : self.upper_frequency,
+            "type"                : self.type,
+            "src_port"            : self.src_port,
+            "dest_port"           : self.dest_port,
+            "status"              : self.status,
+            "optical_band_parent" : self.optical_band_parent,
+            "channel_index"       : self.channel_index,
+        }
diff --git a/src/context/service/database/models/OpticalConfig/TransponderModel.py b/src/context/service/database/models/OpticalConfig/TransponderModel.py
new file mode 100644
index 0000000000000000000000000000000000000000..33e509d354b257d380d61c9795e86fdce7a68348
--- /dev/null
+++ b/src/context/service/database/models/OpticalConfig/TransponderModel.py
@@ -0,0 +1,72 @@
+# 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
+from sqlalchemy import Column, String, Integer , ForeignKey
+from sqlalchemy.dialects.postgresql import ARRAY
+from sqlalchemy.orm import relationship
+from context.service.database.models._Base import _Base
+
+class TransponderTypeModel (_Base):
+    __tablename__ = 'transponder_type'
+
+    transponder_uuid   = Column(String, primary_key=True)
+    transcievers       = Column(ARRAY(String), nullable=True)
+    interfaces         = Column(String, nullable=True)
+    opticalconfig_uuid = Column(ForeignKey('optical_config.opticalconfig_uuid', ondelete='CASCADE'), index=True, nullable=False)
+
+    channels           = relationship("OpticalChannelModel")
+    opticalconfig      = relationship('OpticalConfigModel', back_populates='transponders')
+
+    def dump_id (self): 
+        return {
+            "transponder_uuid": self.transponder_uuid
+        }
+
+    def dump (self):
+        return {
+            "channels"        : [channel.dump() for channel in self.channels],
+            "transceivers"    : {"transceiver": [transciever for transciever in self.transcievers]},
+            "interfaces"      : {"interface":json.loads(self.interfaces) if self.interfaces else ''},
+            "trasponder_uuid" : self.dump_id()
+        }
+
+class OpticalChannelModel(_Base):
+    __tablename__ = 'optical_channel'
+
+    channel_uuid        = Column(String,  primary_key=True)
+    channel_name        = Column(String,  nullable=True)
+    frequency           = Column(Integer, nullable=True)
+    operational_mode    = Column(Integer, nullable=True)
+    status              = Column(String,  nullable=True)
+    target_output_power = Column(String,  nullable=True)
+    transponder_uuid    = Column(ForeignKey('transponder_type.transponder_uuid', ondelete='CASCADE'), nullable=False)
+    transponder         = relationship('TransponderTypeModel', back_populates='channels')
+
+    # opticalconfig_uuid = Column(ForeignKey('optical_config.opticalconfig_uuid', ondelete='CASCADE'), primary_key=True)
+    # opticalconfig      = relationship('OpticalConfigModel', back_populates='channels')
+
+    def dump_id (self ):
+        return {
+            "channel_uuid": self.channel_uuid
+        }
+
+    def dump(self):
+        return {
+            "name"                : {'index':self.channel_name},
+            "frequency"           : self.frequency,
+            "target-output-power" : self.target_output_power,
+            "operational-mode"    : self.operational_mode,
+            "status"              : self.status,
+        }
diff --git a/src/context/service/database/models/OpticalConfig/__init__.py b/src/context/service/database/models/OpticalConfig/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..bbfc943b68af13a11e562abbc8680ade71db8f02
--- /dev/null
+++ b/src/context/service/database/models/OpticalConfig/__init__.py
@@ -0,0 +1,13 @@
+# 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/context/service/database/models/OpticalConfigModel.py b/src/context/service/database/models/OpticalConfigModel.py
deleted file mode 100644
index d7274da17070e0f21774d8173abcfad12e1dcae7..0000000000000000000000000000000000000000
--- a/src/context/service/database/models/OpticalConfigModel.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# 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
-from sqlalchemy import Column, String, Integer
-from sqlalchemy.dialects.postgresql import ARRAY
-from ._Base import _Base
-
-class OpticalConfigModel(_Base):
-    __tablename__ = 'optical_config'
-    opticalconfig_uuid = Column(String, primary_key=True)
-    channels           = Column(ARRAY(String), nullable=True)
-    transcievers       = Column(ARRAY(String), nullable=True)
-    interfaces         = Column(String, nullable=True)
-    channel_namespace  = Column(String, nullable=True)
-    endpoints          = Column(ARRAY(String), nullable=True)
-    frequency          = Column(Integer, nullable=True)
-    operational_mode   = Column(Integer, nullable=True)
-    output_power       = Column(String, nullable=True)
-
-    def dump(self):
-        return {
-            "channels"          : [{'name': {'index': channel}} for channel in self.channels],
-            "transceivers"      : {"transceiver": [transciever for transciever in self.transcievers]},
-            "interfaces"        : {"interface": json.loads(self.interfaces)},
-            "channel_namespace" : self.channel_namespace,
-            "endpoints"         : [json.loads(endpoint) for endpoint in self.endpoints],
-            "frequency"         : self.frequency,
-            "output_power"      : self.output_power,
-            "operational_mode"  : self.operational_mode,
-        }
diff --git a/src/context/service/database/models/OpticalLinkModel.py b/src/context/service/database/models/OpticalLinkModel.py
new file mode 100644
index 0000000000000000000000000000000000000000..6db1b316160aeb3f01d6d70b74338ba67d9b528a
--- /dev/null
+++ b/src/context/service/database/models/OpticalLinkModel.py
@@ -0,0 +1,74 @@
+# 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 sqlalchemy import Column, DateTime, ForeignKey, Integer, String ,Boolean
+from sqlalchemy.dialects.postgresql import UUID
+from sqlalchemy.orm import relationship
+from typing import Dict
+from ._Base import _Base
+from .Slot import C_Slot ,S_Slot , L_Slot
+
+class OpticalLinkModel(_Base):
+    __tablename__ = 'opticallink'
+
+    opticallink_uuid          = Column(UUID(as_uuid=False), primary_key=True)
+    name                      = Column(String, nullable=False)
+    created_at                = Column(DateTime, nullable=False)
+    updated_at                = Column(DateTime, nullable=False)
+    length                    = Column(Integer, nullable=True)
+    src_port                  = Column(String, nullable=True)
+    dst_port                  = Column(String, nullable=True)
+    local_peer_port           = Column(String, nullable=True)
+    remote_peer_port          = Column(String, nullable=True)
+    used                      = Column(Boolean ,nullable=True)
+    c_slots                   = Column (C_Slot,nullable=True)
+    l_slots                   = Column (L_Slot,nullable=True)
+    s_slots                   = Column (S_Slot,nullable=True)
+    opticallink_endpoints     = relationship('OpticalLinkEndPointModel')
+    topology_optical_links    = relationship('TopologyOpticalLinkModel', back_populates='optical_link')
+
+    def dump_id(self) -> Dict:
+        return {'link_uuid': {'uuid': self.opticallink_uuid}}
+
+    def dump(self) -> Dict:
+        result = {
+            'link_id'            : self.dump_id(),
+            'name'               : self.name,
+            'optical_details'    : {
+                'length'           : self.length,
+                'src_port'         : self.src_port,
+                'dst_port'         : self.dst_port,
+                'local_peer_port'  : self.local_peer_port,
+                'remote_peer_port' : self.remote_peer_port,
+                'used'             : self.used,
+                'c_slots'          : self.c_slots if self.c_slots is not None else {},
+                'l_slots'          : self.l_slots if self.l_slots is not None else {},
+                's_slots'          : self.s_slots if self.s_slots is not None else {},
+            },
+            'link_endpoint_ids' : [
+                optical_endpoint.endpoint.dump_id()
+                for optical_endpoint in self.opticallink_endpoints
+            ],
+        }
+        return result
+
+class OpticalLinkEndPointModel(_Base):
+    __tablename__ = 'opticallink_endpoint'
+
+    link_uuid     = Column(ForeignKey('opticallink.opticallink_uuid', ondelete='CASCADE' ), primary_key=True)
+    endpoint_uuid = Column(ForeignKey('endpoint.endpoint_uuid',       ondelete='RESTRICT'), primary_key=True, index=True)
+
+    optical_link  = relationship('OpticalLinkModel', back_populates='opticallink_endpoints')
+    endpoint      = relationship('EndPointModel',    lazy='selectin')
diff --git a/src/context/service/database/models/Slot.py b/src/context/service/database/models/Slot.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d8602bd40464eafa8a6234881b100c73134bed7
--- /dev/null
+++ b/src/context/service/database/models/Slot.py
@@ -0,0 +1,80 @@
+# 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 sqlalchemy.types import  TypeDecorator, Integer
+
+class SlotType(TypeDecorator):
+    impl = Integer
+
+    def process_bind_param(self, value, dialect):
+        if value is not None:
+            bin_num = "0b"
+            for i,(key,val) in enumerate(value.items()):
+                bin_num =bin_num + f"{val}"
+            int_num = int(bin_num,2)  
+        return int_num
+
+    def process_result_value(self, value, dialect):
+        if value is not None:
+            slot = dict()
+            bin_num = bin(value)
+            sliced_num = bin_num[2:]
+            for i in range(len(sliced_num)):
+                slot[str(i+1)]=int(sliced_num[i])
+        return slot
+
+class C_Slot(SlotType):
+    start_point = 0
+
+    def process_result_value(self, value, dialect):
+        if value is not None:
+            slot = dict()
+            bin_num = bin(value)
+            sliced_num = bin_num[2:]
+            if (len(sliced_num) != 20) :
+                for i in range(0,20 - len(sliced_num)):
+                    sliced_num = '0' + sliced_num
+            for i in range(len(sliced_num)):
+                slot[str(self.start_point+i+1)]=int(sliced_num[i])
+        return slot
+
+class L_Slot (SlotType):
+    start_point = 100
+
+    def process_result_value(self, value, dialect):
+        if value is not None:
+            slot = dict()
+            bin_num = bin(value)
+            sliced_num = bin_num[2:]
+            if (len(sliced_num) != 20) :
+                for i in range(0,20 - len(sliced_num)):
+                    sliced_num='0'+sliced_num
+            for i in range(len(sliced_num)):
+                slot[str(self.start_point+i+1)]=int(sliced_num[i])
+        return slot
+
+class S_Slot (SlotType):
+    start_point = 500
+
+    def process_result_value(self, value, dialect):
+        if value is not None:
+            slot= dict()
+            bin_num = bin(value)
+            sliced_num=bin_num[2:]
+            if (len(sliced_num) != 20) :
+                for i in range(0,20 - len(sliced_num)):
+                    sliced_num='0'+sliced_num
+            for i in range(len(sliced_num)):
+                slot[str(self.start_point+i+1)]=int(sliced_num[i])
+        return slot
diff --git a/src/context/service/database/models/TopologyModel.py b/src/context/service/database/models/TopologyModel.py
index 995abab3a40bfacb446360c55c784b0a5f4207ec..cd731ed60efd6be266dea4bf3c9847bbceb0370e 100644
--- a/src/context/service/database/models/TopologyModel.py
+++ b/src/context/service/database/models/TopologyModel.py
@@ -27,9 +27,10 @@ class TopologyModel(_Base):
     created_at    = Column(DateTime, nullable=False)
     updated_at    = Column(DateTime, nullable=False)
 
-    context          = relationship('ContextModel', back_populates='topologies', lazy='selectin')
-    topology_devices = relationship('TopologyDeviceModel') # back_populates='topology'
-    topology_links   = relationship('TopologyLinkModel'  ) # back_populates='topology'
+    context                = relationship('ContextModel', back_populates='topologies', lazy='selectin')
+    topology_devices       = relationship('TopologyDeviceModel') # back_populates='topology'
+    topology_links         = relationship('TopologyLinkModel'  ) # back_populates='topology'
+    topology_optical_links = relationship("TopologyOpticalLinkModel")
 
     def dump_id(self) -> Dict:
         return {
@@ -39,10 +40,11 @@ class TopologyModel(_Base):
 
     def dump(self) -> Dict:
         return {
-            'topology_id': self.dump_id(),
-            'name'       : self.topology_name,
-            'device_ids' : [{'device_uuid': {'uuid': td.device_uuid}} for td in self.topology_devices],
-            'link_ids'   : [{'link_uuid'  : {'uuid': tl.link_uuid  }} for tl in self.topology_links  ],
+            'topology_id'     : self.dump_id(),
+            'name'            : self.topology_name,
+            'device_ids'      : [{'device_uuid': {'uuid': td.device_uuid      }} for td in self.topology_devices      ],
+            'link_ids'        : [{'link_uuid'  : {'uuid': tl.link_uuid        }} for tl in self.topology_links        ],
+            'optical_link_ids': [{'link_uuid'  : {'uuid': to.optical_link_uuid}} for to in self.topology_optical_links],
         }
 
     def dump_details(self) -> Dict:
@@ -54,11 +56,16 @@ class TopologyModel(_Base):
             tl.link.dump()
             for tl in self.topology_links
         ]
+        optical_links=[
+            ol.optical_link.dump() 
+            for ol in self.topology_optical_links
+        ]
         return {
-            'topology_id': self.dump_id(),
-            'name'       : self.topology_name,
-            'devices'    : devices,
-            'links'      : links,
+            'topology_id'  : self.dump_id(),
+            'name'         : self.topology_name,
+            'devices'      : devices,
+            'links'        : links,
+            'optical_links': optical_links,
         }
 
 class TopologyDeviceModel(_Base):
@@ -78,3 +85,14 @@ class TopologyLinkModel(_Base):
 
     topology = relationship('TopologyModel', lazy='selectin', viewonly=True) # back_populates='topology_links'
     link     = relationship('LinkModel',     lazy='selectin') # back_populates='topology_links'
+
+#---------------------------------------- Experimental ---------------------------------------
+
+class TopologyOpticalLinkModel(_Base):
+    __tablename__ = 'topology_optical_link'
+
+    topology_uuid     = Column(ForeignKey('topology.topology_uuid',       ondelete='RESTRICT'), primary_key=True, index=True)
+    optical_link_uuid = Column(ForeignKey('opticallink.opticallink_uuid', ondelete='CASCADE' ), primary_key=True, index=True)
+
+    topology     = relationship('TopologyModel',    lazy='selectin', viewonly=True) # back_populates='topology_optical_links'
+    optical_link = relationship('OpticalLinkModel', lazy='selectin') # back_populates='topology_optical_links'
diff --git a/src/context/service/database/uuids/OpticalConfig.py b/src/context/service/database/uuids/OpticalConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..f2cd443a983d5b37009ddc1c2dc821dce960ddb8
--- /dev/null
+++ b/src/context/service/database/uuids/OpticalConfig.py
@@ -0,0 +1,64 @@
+# 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 common.method_wrappers.ServiceExceptions import InvalidArgumentsException
+from common.proto.context_pb2 import DeviceId
+from ._Builder import get_uuid_from_string, get_uuid_random
+
+def channel_get_uuid(
+    channel_name : str , device_id : str, allow_random : bool = False
+) -> str:
+    if len(channel_name) > 0:
+        return get_uuid_from_string(channel_name) + device_id
+    if allow_random: return get_uuid_random()
+
+    raise InvalidArgumentsException([
+        ('channel uuid', channel_name),
+    ], extra_details=['Channel name is required to produce a channel UUID'])
+
+def transponder_get_uuid(
+    opticalconfig_id : str, allow_random : bool = False
+) -> str:
+    if opticalconfig_id is not None:
+        return get_uuid_from_string(f"{opticalconfig_id}-transponder")
+    if allow_random: return get_uuid_random()
+
+    raise InvalidArgumentsException([
+        ('transponder uuid', opticalconfig_id),
+       
+    ], extra_details=['opticalconfig id is required to produce a transponder UUID'])
+
+def roadm_get_uuid(
+    opticalconfig_id : str, allow_random : bool = False
+) -> str:
+    if opticalconfig_id is not None:
+        return get_uuid_from_string(f"{opticalconfig_id}-roadm")
+    if allow_random: return get_uuid_random()
+
+    raise InvalidArgumentsException([
+        ('roadm uuid', opticalconfig_id),
+       
+    ], extra_details=['opticalconfig id is required to produce a roadm UUID'])
+
+def opticalconfig_get_uuid(
+    device_id : DeviceId, allow_random : bool = False
+) -> str:
+    device_uuid = device_id.device_uuid.uuid
+    if (len(device_uuid)>0):
+        return get_uuid_from_string(f"{device_uuid}_opticalconfig")
+    if allow_random: return get_uuid_random()
+
+    raise InvalidArgumentsException([
+        ('DeviceId ', device_id),
+    ], extra_details=['device_id is required to produce a OpticalConfig UUID'])
diff --git a/src/context/service/database/uuids/OpticalEndPoint.py b/src/context/service/database/uuids/OpticalEndPoint.py
new file mode 100644
index 0000000000000000000000000000000000000000..fedafd6f470af174a6c4701e330f93fea00a5a3f
--- /dev/null
+++ b/src/context/service/database/uuids/OpticalEndPoint.py
@@ -0,0 +1,38 @@
+# 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 Tuple
+from common.proto.context_pb2 import EndPointId
+from common.method_wrappers.ServiceExceptions import InvalidArgumentsException
+from ._Builder import get_uuid_from_string, get_uuid_random
+from .Device import device_get_uuid
+
+def optical_endpoint_get_uuid(
+    endpoint_id : EndPointId, endpoint_name : str = '', allow_random : bool = False
+) -> Tuple[str, str, str]:
+    device_uuid = device_get_uuid(endpoint_id.device_id, allow_random=False)
+    raw_endpoint_uuid = endpoint_id.endpoint_uuid.uuid
+    if len(raw_endpoint_uuid) > 0:
+        prefix_for_name = '{:s}'.format( device_uuid)
+        return  device_uuid, get_uuid_from_string(raw_endpoint_uuid, prefix_for_name=prefix_for_name)
+    if len(endpoint_name) > 0:
+        prefix_for_name = '{:s}'.format( device_uuid)
+        return  device_uuid, get_uuid_from_string(endpoint_name, prefix_for_name=prefix_for_name)
+    if allow_random:
+        return device_uuid, get_uuid_random()
+
+    raise InvalidArgumentsException([
+        ('optical_endpoint_id.endpoint_uuid.uuid', raw_endpoint_uuid),
+        ('name', endpoint_name),
+    ], extra_details=['At least one is required to produce a OpticalEndPoint UUID'])
diff --git a/src/context/service/database/uuids/OpticalLink.py b/src/context/service/database/uuids/OpticalLink.py
new file mode 100644
index 0000000000000000000000000000000000000000..152686423aa808194f0582075557e6133e405071
--- /dev/null
+++ b/src/context/service/database/uuids/OpticalLink.py
@@ -0,0 +1,32 @@
+# 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 common.method_wrappers.ServiceExceptions import InvalidArgumentsException
+from common.proto.context_pb2 import LinkId
+from ._Builder import get_uuid_from_string, get_uuid_random
+
+optical_detail_sp = "Optical_link_detail"
+
+def opticaldetail_get_uuid(
+    link_id : LinkId,allow_random=False
+) -> str:
+    link_uuid = link_id.link_uuid.uuid
+    if len(link_uuid) > 0:
+        str_uuid=f"{link_uuid}{optical_detail_sp}"
+        return get_uuid_from_string(str_uuid)
+
+    if allow_random: return get_uuid_random()
+    raise InvalidArgumentsException([
+        ('link_id.link_uuid.uuid', link_uuid),
+    ], extra_details=['At least one is required to produce a Optical Link Detail UUID'])
diff --git a/src/device/Dockerfile b/src/device/Dockerfile
index 42bf4335cc6b0c6337c166dae8680e18d46d1360..31dffddc40a6c9dc3dca8f0f155ac543fd10b12d 100644
--- a/src/device/Dockerfile
+++ b/src/device/Dockerfile
@@ -16,9 +16,24 @@ FROM python:3.9-slim
 
 # Install dependencies
 RUN apt-get --yes --quiet --quiet update && \
-    apt-get --yes --quiet --quiet install wget g++ git && \
+    apt-get --yes --quiet --quiet install wget g++ git build-essential cmake libpcre2-dev python3-dev python3-cffi && \
     rm -rf /var/lib/apt/lists/*
 
+# Download, build and install libyang. Note that APT package is outdated
+# - Ref: https://github.com/CESNET/libyang
+# - Ref: https://github.com/CESNET/libyang-python/
+RUN mkdir -p /var/libyang
+RUN git clone https://github.com/CESNET/libyang.git /var/libyang
+WORKDIR /var/libyang
+RUN git fetch
+RUN git checkout v2.1.148
+RUN mkdir -p /var/libyang/build
+WORKDIR /var/libyang/build
+RUN cmake -D CMAKE_BUILD_TYPE:String="Release" ..
+RUN make
+RUN make install
+RUN ldconfig
+
 # Set Python to show logs as they occur
 ENV PYTHONUNBUFFERED=0
 
@@ -62,17 +77,30 @@ RUN python3 -m pip install -r requirements.txt
 
 # Add component files into working directory
 WORKDIR /var/teraflow
+COPY src/device/. device/
 COPY src/context/__init__.py context/__init__.py
 COPY src/context/client/. context/client/
 COPY src/monitoring/__init__.py monitoring/__init__.py
 COPY src/monitoring/client/. monitoring/client/
-COPY src/device/. device/
 
+# Clone test mock tools
 RUN mkdir -p tests/tools/mock_ietf_actn_sdn_ctrl
 RUN touch tests/__init__.py
 RUN touch tests/tools/__init__.py
 RUN touch tests/tools/mock_ietf_actn_sdn_ctrl/__init__.py
 COPY src/tests/tools/mock_ietf_actn_sdn_ctrl/. tests/tools/mock_ietf_actn_sdn_ctrl/
 
+# Clone OpenConfig YANG models
+RUN mkdir -p /var/teraflow/device/service/drivers/gnmi_openconfig/git/openconfig/public
+RUN mkdir -p /tmp/openconfig
+RUN git clone https://github.com/openconfig/public.git /tmp/openconfig
+WORKDIR /tmp/openconfig
+RUN git fetch
+RUN git checkout v4.4.0
+RUN mv /tmp/openconfig/release /var/teraflow/device/service/drivers/gnmi_openconfig/git/openconfig/public
+RUN mv /tmp/openconfig/third_party /var/teraflow/device/service/drivers/gnmi_openconfig/git/openconfig/public
+RUN rm -rf /tmp/openconfig
+WORKDIR /var/teraflow
+
 # Start the service
 ENTRYPOINT ["python", "-m", "device.service"]
diff --git a/src/device/client/DeviceClient.py b/src/device/client/DeviceClient.py
index d479b21cd1223e06abb48213cecc23db4fd651dc..8397b89b8c43917a5a22dee2ed3ad5ec0d105aae 100644
--- a/src/device/client/DeviceClient.py
+++ b/src/device/client/DeviceClient.py
@@ -15,12 +15,16 @@
 import grpc, logging
 from common.Constants import ServiceNameEnum
 from common.Settings import get_service_host, get_service_port_grpc
-from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty,OpticalConfig,OpticalConfigId
+from common.proto.context_pb2 import (
+    Device, DeviceConfig, DeviceId, Empty,
+    OpticalConfig, OpticalConfigId, OpticalConfigList
+)
 from common.proto.device_pb2 import MonitoringSettings
 from common.proto.device_pb2_grpc import DeviceServiceStub
+from common.proto.optical_device_pb2_grpc import OpenConfigServiceStub
 from common.tools.client.RetryDecorator import retry, delay_exponential
 from common.tools.grpc.Tools import grpc_message_to_json_string
-from common.proto.openconfig_device_pb2_grpc import OpenConfigServiceStub
+
 LOGGER = logging.getLogger(__name__)
 MAX_RETRIES = 15
 DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0)
@@ -41,12 +45,13 @@ class DeviceClient:
     def connect(self):
         self.channel = grpc.insecure_channel(self.endpoint)
         self.stub = DeviceServiceStub(self.channel)
-        self.openconfig_stub=OpenConfigServiceStub(self.channel)
+        self.openconfig_stub = OpenConfigServiceStub(self.channel)
 
     def close(self):
         if self.channel is not None: self.channel.close()
         self.channel = None
         self.stub = None
+        self.openconfig_stub = None
 
     @RETRY_DECORATOR
     def AddDevice(self, request : Device) -> DeviceId:
@@ -82,8 +87,21 @@ class DeviceClient:
         response = self.stub.MonitorDeviceKpi(request)
         LOGGER.debug('MonitorDeviceKpi result: {:s}'.format(grpc_message_to_json_string(response)))
         return response
+
     def ConfigureOpticalDevice(self, request : OpticalConfig) -> OpticalConfigId:
         LOGGER.debug('ConfigureOpticalDevice request: {:s}'.format(grpc_message_to_json_string(request)))
         response = self.openconfig_stub.ConfigureOpticalDevice(request)
         LOGGER.debug('ConfigureOpticalDevice result: {:s}'.format(grpc_message_to_json_string(response)))
         return response
+
+    def GetDeviceConfiguration(self, request : OpticalConfigList) -> Empty:
+        LOGGER.debug('ConfigureOpticalDevice request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.openconfig_stub.GetDeviceConfiguration(request)
+        LOGGER.debug('ConfigureOpticalDevice result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
+
+    def DisableOpticalDevice(self, request : OpticalConfig) -> Empty:
+        LOGGER.debug('DisableOpticalDevice request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.openconfig_stub.DisableOpticalDevice(request)
+        LOGGER.debug('DisableOpticalDevice result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
diff --git a/src/device/requirements.in b/src/device/requirements.in
index bf5e6a2b3128f438a7c044c3f3cf9ee393de2265..a4d818b52b494f2ef6cc0938d69ddb133ab40859 100644
--- a/src/device/requirements.in
+++ b/src/device/requirements.in
@@ -12,9 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
 anytree==2.8.0
 APScheduler==3.10.1
+bitarray==2.8.*
 cryptography==36.0.2
 deepdiff==6.7.*
 deepmerge==1.1.*
@@ -22,26 +22,27 @@ deepmerge==1.1.*
 Flask==2.1.3
 Flask-HTTPAuth==4.5.0
 Flask-RESTful==0.3.9
+ipaddress
 Jinja2==3.0.3
-numpy<2.0.0
+libyang==2.8.0
+macaddress
 ncclient==0.6.15
+numpy<2.0.0
 p4runtime==1.3.0
 pandas==1.5.*
 paramiko==2.9.2
+pyang==2.6.*
+git+https://github.com/robshakir/pyangbind.git
 python-json-logger==2.0.2
 #pytz==2021.3
 #redis==4.1.2
 requests==2.27.1
 requests-mock==1.9.3
-xmltodict==0.12.0
 tabulate
-ipaddress
-macaddress
-yattag
-pyang==2.6.0
-git+https://github.com/robshakir/pyangbind.git
 websockets==10.4
 werkzeug==2.3.7
+xmltodict==0.12.0
+yattag
 
 # pip's dependency resolver does not take into account installed packages.
 # p4runtime does not specify the version of grpcio/protobuf it needs, so it tries to install latest one
diff --git a/src/device/service/DeviceService.py b/src/device/service/DeviceService.py
index 1769a16afb49aab6cb986b49e3ca74b9f3b572be..cac36f62230e42ffd8fbbcba242cadb46486b050 100644
--- a/src/device/service/DeviceService.py
+++ b/src/device/service/DeviceService.py
@@ -16,7 +16,7 @@ import os
 from common.Constants import ServiceNameEnum
 from common.Settings import get_service_port_grpc
 from common.proto.device_pb2_grpc import add_DeviceServiceServicer_to_server
-from common.proto.openconfig_device_pb2_grpc import add_OpenConfigServiceServicer_to_server
+from common.proto.optical_device_pb2_grpc import add_OpenConfigServiceServicer_to_server
 from common.tools.service.GenericGrpcService import GenericGrpcService
 from device.Config import LOAD_ALL_DEVICE_DRIVERS
 from .driver_api.DriverInstanceCache import DriverInstanceCache
diff --git a/src/device/service/DeviceServiceServicerImpl.py b/src/device/service/DeviceServiceServicerImpl.py
index 7546c225e67fd3122ec845b3154606eddb7cd9ff..6e6fa6a9311751888d51e053e323a63d810dad4e 100644
--- a/src/device/service/DeviceServiceServicerImpl.py
+++ b/src/device/service/DeviceServiceServicerImpl.py
@@ -33,9 +33,11 @@ from .driver_api.DriverInstanceCache import DriverInstanceCache, get_driver
 from .monitoring.MonitoringLoops import MonitoringLoops
 from .ErrorMessages import ERROR_MISSING_DRIVER, ERROR_MISSING_KPI
 from .Tools import (
-    check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules, deconfigure_rules,
-    get_device_controller_uuid, populate_config_rules, populate_endpoint_monitoring_resources, populate_endpoints,
-    populate_initial_config_rules, subscribe_kpi, unsubscribe_kpi, update_endpoints)
+    check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules,
+    deconfigure_rules, get_device_controller_uuid, populate_config_rules,
+    populate_endpoint_monitoring_resources, populate_endpoints, populate_initial_config_rules,
+    subscribe_kpi, unsubscribe_kpi, update_endpoints
+)
 
 LOGGER = logging.getLogger(__name__)
 
@@ -60,8 +62,7 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
         device_uuid = request.device_id.device_uuid.uuid
 
         connection_config_rules = check_connect_rules(request.device_config)
-        if request.device_drivers[0] != DeviceDriverEnum.DEVICEDRIVER_OC:
-            check_no_endpoints(request.device_endpoints)
+        check_no_endpoints(request.device_endpoints)
 
         t1 = time.time()
 
@@ -107,18 +108,24 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
             # (which controller is in charge of which sub-device).
             new_sub_devices : Dict[str, Device] = dict()
             new_sub_links : Dict[str, Link] = dict()
+            
+            #----- Experimental ------------
+            new_optical_configs : Dict[str, OpticalConfig] = dict()
 
             if len(device.device_endpoints) == 0:
                 t5 = time.time()
                 # created from request, populate endpoints using driver
                 errors.extend(populate_endpoints(
-                    device, driver, self.monitoring_loops, new_sub_devices, new_sub_links))
+                    device, driver, self.monitoring_loops, new_sub_devices, new_sub_links,
+                    new_optical_configs
+                ))
                 t6 = time.time()
                 t_pop_endpoints = t6 - t5
             else:
                 t_pop_endpoints = None
 
-            if len(device.device_config.config_rules) == len(connection_config_rules):
+            is_optical_device = request.device_drivers[0] == DeviceDriverEnum.DEVICEDRIVER_OC
+            if len(device.device_config.config_rules) == len(connection_config_rules) and not is_optical_device:
                 # created from request, populate config rules using driver
                 t7 = time.time()
                 errors.extend(populate_config_rules(device, driver))
@@ -143,13 +150,15 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
             else:
                 # ZTP is not deployed; assume the device is ready while onboarding and set them as enabled.
                 device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
-           
-            # temporary line 
-            if request.device_drivers[0] == DeviceDriverEnum.DEVICEDRIVER_OC and len(request.device_endpoints) > 0:
+
+            # temporary line
+            if  is_optical_device:
                 #for endpoint in request.device_endpoints:
                 #    #endpoint.endpoint_id.device_id.CopyFrom(device.device_id)
                 #    pass
-                device.device_endpoints.extend(request.device_endpoints)
+
+                if 'new_optical_config' in new_optical_configs and 'opticalconfig' in new_optical_configs["new_optical_config"]:
+                    context_client.SetOpticalConfig(new_optical_configs["new_optical_config"]['opticalconfig'])
 
             device_id = context_client.SetDevice(device)
 
diff --git a/src/device/service/OpenConfigServicer.py b/src/device/service/OpenConfigServicer.py
index 1dddade18e171380132ed4e5850dfbc7e180b4d8..bee2d4d5ccf6a5757b854f2d8b2275c4da64758f 100644
--- a/src/device/service/OpenConfigServicer.py
+++ b/src/device/service/OpenConfigServicer.py
@@ -16,7 +16,8 @@ import grpc, logging, json
 from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method
 from common.method_wrappers.ServiceExceptions import NotFoundException
 from common.proto.context_pb2 import (
-    Device, DeviceId, DeviceOperationalStatusEnum, Empty, OpticalConfig, OpticalConfig
+    Device, DeviceId, DeviceOperationalStatusEnum, Empty, OpticalConfig,
+    OpticalConfig, OpticalConfigList
 )
 from common.proto.device_pb2_grpc import DeviceServiceServicer
 from common.tools.context_queries.Device import get_device
@@ -75,21 +76,103 @@ class OpenConfigServicer(DeviceServiceServicer):
 
     @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
     def ConfigureOpticalDevice (self, request : OpticalConfig, context : grpc.ServicerContext) -> Empty:
-        device_uuid = request.opticalconfig_id.opticalconfig_uuid
-        resources=[]
-        config =json.loads(request.config)
+        device_uuid = request.device_id.device_uuid.uuid
+        resources : list[dict] = []
+        is_all_good = True
+        config = json.loads(request.config)
+        results = None
+
+        try:
+            context_client = ContextClient()
+            device = get_device(
+                context_client, device_uuid, rw_copy=True, include_endpoints=True, include_components=False,
+                include_config_rules=False)
+            if device is None:
+                raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice')
+            resources, conditions = extract_resources(config=config, device=device)
+
+            driver : _Driver = get_driver(self.driver_instance_cache, device)
+            results = driver.SetConfig(resources=resources,conditions=conditions)
+            for result in results:
+                if not result :
+                    is_all_good = False
+
+            if is_all_good:
+                #driver.GetConfig(resource_keys=[])   
+                config = json.loads(request.config)
+                handled_flow = next((i for i in resources if i['resource_key'] == 'handled_flow'), None)
+                if handled_flow is not None and len(handled_flow) > 0:
+                    config['flow_handled'] = handled_flow['value']
+                    request.config=json.dumps(config) 
+                context_client.UpdateOpticalConfig(request) 
+                context_client.close()    
+        except Exception as e:
+            LOGGER.info("error in configuring %s",e)    
+        return Empty()
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def GetDeviceConfiguration (self, request : OpticalConfigList, context : grpc.ServicerContext) -> Empty:
+        context_client = ContextClient()
+
+        for configs in request.opticalconfigs:
+            device_uuid = configs.device_id.device_uuid.uuid
+            try:
+                device = get_device(
+                    context_client, device_uuid, rw_copy=True, include_endpoints=True, include_components=False,
+                    include_config_rules=False)
+                if device is None:
+                    raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice')
+                driver : _Driver = get_driver(self.driver_instance_cache, device)
+                results = driver.GetConfig(resource_keys=[]) 
+                for resource_data in results :
+                    resource_key, resource_value = resource_data
+                    if resource_key.startswith('/opticalconfigs/opticalconfig/'):
+                        if 'opticalconfig' in resource_value:
+                            context_client.SetOpticalConfig(resource_value['opticalconfig'])
+
+                #TODO: add a control with the NETCONF get
+                #driver.GetConfig(resource_keys=filter_fields)
+            except Exception as e:
+                LOGGER.info("error in configuring %s",e)                
+        context_client.close()
+        return Empty()
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def DisableOpticalDevice (self, request : OpticalConfig, context : grpc.ServicerContext) -> Empty:
+        roadm_configuration = None
+        device_uuid = request.device_id.device_uuid.uuid
+        resources : list[dict] = []
+        is_all_good = True
+        config = json.loads(request.config)
+
         try:
             context_client = ContextClient()
             device = get_device(
                 context_client, device_uuid, rw_copy=True, include_endpoints=True, include_components=False,
                 include_config_rules=False)
+
             if device is None:
                 raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice')
-            resources,conditions=extract_resources(config=config,device=device)
+
+            resources, conditions = extract_resources(config=config, device=device)
+
             driver : _Driver = get_driver(self.driver_instance_cache, device)
-            result = driver.SetConfig(resources=resources,conditions=conditions)
-            #TODO: add a control with the NETCONF get
-            #driver.GetConfig(resource_keys=filter_fields)
+            if  'edit_type' in conditions and conditions['edit_type'] == 'optical-band':
+                roadm_configuration = driver.GetConfig()
+                for resource_data in roadm_configuration:
+                    resource_key, resource_value = resource_data
+                    if resource_key.startswith('/opticalconfigs/opticalconfig/'):
+                        roadm_configuration=resource_value["opticalconfig"]
+            results = driver.DeleteConfig(resources=resources,conditions=conditions,optical_device_configuration=roadm_configuration)
+            for result in results:
+                if not result :
+                    is_all_good = False
+
+            if is_all_good:
+                config = json.loads(request.config)
+                if "new_config" in config :
+                    context_client.DeleteOpticalChannel(request) 
+                    context_client.close()    
         except Exception as e:
-                LOGGER.info("error in configuring %s",e)    
+            LOGGER.info("error in Disable configuring %s",e)    
         return Empty()
diff --git a/src/device/service/Tools.py b/src/device/service/Tools.py
index 91926b9e59cccac2e233ac14bbac497bbb0ac15c..967a6a8c19ca4da763f29bfa164f50ad88d27363 100644
--- a/src/device/service/Tools.py
+++ b/src/device/service/Tools.py
@@ -17,7 +17,9 @@ from typing import Any, Dict, List, Optional, Tuple, Union
 from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME
 from common.DeviceTypes import DeviceTypeEnum
 from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException
-from common.proto.context_pb2 import ConfigActionEnum, ConfigRule_ACL, Device, DeviceConfig, EndPoint, Link, Location
+from common.proto.context_pb2 import (
+    ConfigActionEnum, ConfigRule_ACL, Device, DeviceConfig, EndPoint, Link, Location, OpticalConfig
+)
 from common.proto.device_pb2 import MonitoringSettings
 from common.proto.kpi_sample_types_pb2 import KpiSampleType
 from common.tools.grpc.ConfigRules import update_config_rule_custom
@@ -26,7 +28,8 @@ from common.type_checkers.Checkers import chk_length, chk_type
 from .driver_api._Driver import _Driver, RESOURCE_ENDPOINTS
 from .monitoring.MonitoringLoops import MonitoringLoops
 from .ErrorMessages import (
-    ERROR_BAD_RESOURCE, ERROR_DELETE, ERROR_GET, ERROR_GET_INIT, ERROR_MISSING_KPI, ERROR_SAMPLETYPE, ERROR_SET,
+    ERROR_BAD_RESOURCE, ERROR_DELETE, ERROR_GET, ERROR_GET_INIT,
+    ERROR_MISSING_KPI, ERROR_SAMPLETYPE, ERROR_SET,
     ERROR_SUBSCRIBE, ERROR_UNSUBSCRIBE, ERROR_UNSUP_RESOURCE
 )
 
@@ -106,7 +109,8 @@ def get_device_controller_uuid(device : Device) -> Optional[str]:
 
 def populate_endpoints(
     device : Device, driver : _Driver, monitoring_loops : MonitoringLoops,
-    new_sub_devices : Dict[str, Device], new_sub_links : Dict[str, Link]
+    new_sub_devices : Dict[str, Device], new_sub_links : Dict[str, Link],
+    new_optical_configs : Dict[str, OpticalConfig]
 ) -> List[str]:
     device_uuid = device.device_id.device_uuid.uuid
     device_name = device.name
@@ -237,6 +241,9 @@ def populate_endpoints(
                 _sub_link_endpoint_id.device_id.device_uuid.uuid = device_uuid
                 _sub_link_endpoint_id.endpoint_uuid.uuid = endpoint_uuid
 
+        # ----------Experimental --------------
+        elif resource_key.startswith('/opticalconfigs/opticalconfig/'):
+            new_optical_configs["new_optical_config"]=resource_value
         else:
             errors.append(ERROR_UNSUP_RESOURCE.format(device_uuid=device_uuid, resource_data=str(resource_data)))
             continue
@@ -454,7 +461,7 @@ def update_endpoints(src_device : Device, dst_device : Device) -> None:
 
 def get_edit_target(device : Device, is_opticalband : bool) -> str:
     if is_opticalband: return 'optical-band'
-    if device.device_type == DeviceTypeEnum.OPTICAL_ROADM: return 'media-channel'
+    if device.device_type == DeviceTypeEnum.OPTICAL_ROADM._value_: return 'media-channel'
     return 'optical-channel'
 
 def is_key_existed(key : str, keys_dic = dict, key_name_to_use = None) -> dict:
@@ -468,18 +475,20 @@ def is_key_existed(key : str, keys_dic = dict, key_name_to_use = None) -> dict:
         dic['value'] = None
     return dic
 
-def extract_resources(config : dict, device : Device) -> list:
+def extract_resources(config : dict, device : Device) -> list[list[dict], dict]:
     conditions = {}
-    resources = []
+    resources : list[dict] = []
     resources.append(is_key_existed('channel_namespace', config))
     resources.append(is_key_existed('add_transceiver', config))
     is_opticalband = config.get('is_opticalband', False)
     conditions['is_opticalband'] = is_opticalband
     conditions['edit_type'] = get_edit_target(device, is_opticalband)
+
     if 'flow' in config:
         #for tuple_value in config['flow'][device.name]:
         source_vals = []
         dest_vals = []
+        handled_flow = []
         for tuple_value in config['flow']:
             source_port = None 
             destination_port = None
@@ -492,9 +501,10 @@ def extract_resources(config : dict, device : Device) -> list:
                 dst_endpoint_obj = get_endpoint_matching(device, destination_port_uuid)
                 destination_port = dst_endpoint_obj.name
             dest_vals.append(destination_port)
-        resources.append({'resource_key': 'source_port',      'value': source_vals})
-        resources.append({'resource_key': 'destination_port', 'value': dest_vals  })
-
+            handled_flow.append((source_port, destination_port))
+        resources.append({'resource_key': 'source_port',      'value': source_vals })
+        resources.append({'resource_key': 'destination_port', 'value': dest_vals   })
+        resources.append({'resource_key': 'handled_flow',     'value': handled_flow})
     if 'new_config' in config:
         lower_frequency = None
         upper_frequency = None
@@ -502,15 +512,15 @@ def extract_resources(config : dict, device : Device) -> list:
         resources.append(is_key_existed('frequency',           keys_dic=config['new_config']))
         resources.append(is_key_existed('operational-mode',    keys_dic=config['new_config']))
         resources.append(is_key_existed('line-port',           keys_dic=config['new_config']))
+        resources.append(is_key_existed('status',              keys_dic=config['new_config'] , key_name_to_use="admin-state"))
         resources.append(is_key_existed('band_type', keys_dic=config['new_config'], key_name_to_use='name'))
         resources.append(is_key_existed('ob_id',     keys_dic=config['new_config'], key_name_to_use='optical-band-parent'))
-        resources.append(is_key_existed('name',      keys_dic=config['new_config'], key_name_to_use='channel_name'))
+        #resources.append(is_key_existed('name',      keys_dic=config['new_config'], key_name_to_use='channel_name'))
         if not is_opticalband:
             if 'frequency' in config['new_config'] and 'band' in config['new_config'] and conditions['edit_type'] == 'media-channel':
-                lower_frequency = int(int(config['new_config']['frequency']) - (int(config['new_config']['band'])/2))
-                upper_frequency = int(int(config['new_config']['frequency']) + (int(config['new_config']['band'])/2))
-                #lower_frequency = (config['new_config']['frequency'] - config['new_config']['band'])/2
-                #upper_frequency = (config['new_config']['frequency'] + config['new_config']['band'])/2
+                if config['new_config']['frequency'] is not None and config['new_config']['band'] is not None:
+                    lower_frequency = int(int(config['new_config']['frequency']) - (int(config['new_config']['band'])/2)+1)
+                    upper_frequency = int(int(config['new_config']['frequency']) + (int(config['new_config']['band'])/2))
                 resources.append(is_key_existed('flow_id', keys_dic=config['new_config'], key_name_to_use='index'))
                 #resources.append({'resource_key':'index','value':config['new_config']['flow_id'] if 'flow_id' in config['new_config'] else None})
         else:
diff --git a/src/device/service/drivers/gnmi_openconfig/DeltaSampleCache.py b/src/device/service/drivers/gnmi_openconfig/DeltaSampleCache.py
index daf04be5a1ff82a79031d8c3ffe19da10739fbcb..140efe84038ed5117d6c7924b188a7dc7dbd7958 100644
--- a/src/device/service/drivers/gnmi_openconfig/DeltaSampleCache.py
+++ b/src/device/service/drivers/gnmi_openconfig/DeltaSampleCache.py
@@ -13,13 +13,15 @@
 # limitations under the License.
 
 import copy
-from typing import Any, Dict, Tuple, Union
+from typing import Any, Dict, Optional, Tuple, Union
 
 class DeltaSampleCache:
     def __init__(self) -> None:
         self._previous_samples : Dict[str, Tuple[float, Union[int, float]]] = dict()
 
-    def get_delta(self, path : str, current_timestamp : float, current_value : Any) -> None:
+    def get_delta(
+        self, path : str, current_timestamp : float, current_value : Any
+    ) -> Optional[Tuple[float, Optional[Any]]]:
         previous_sample = copy.deepcopy(self._previous_samples.get(path))
         self._previous_samples[path] = current_timestamp, current_value
 
@@ -30,6 +32,10 @@ class DeltaSampleCache:
 
         delta_value = max(0, current_value - previous_value)
         delay = current_timestamp - previous_timestamp
-        delta_sample = current_timestamp, delta_value / delay
-
-        return delta_sample
+        if delay < 1.e-12:
+            # return a special value meaning, at that timestamp,
+            # computed value is not a number, e.g., division by zero
+            # also, recover previuos samples to do not miss any packet/byte
+            self._previous_samples[path] = previous_sample
+            return current_timestamp, None
+        return current_timestamp, delta_value / delay
diff --git a/src/device/service/drivers/gnmi_openconfig/GnmiSessionHandler.py b/src/device/service/drivers/gnmi_openconfig/GnmiSessionHandler.py
index 4428fb81ca304d20ee4b3bce259924278400249f..3668c6a3eeb4ab31e2ee01517efaab157c98f8d1 100644
--- a/src/device/service/drivers/gnmi_openconfig/GnmiSessionHandler.py
+++ b/src/device/service/drivers/gnmi_openconfig/GnmiSessionHandler.py
@@ -19,7 +19,8 @@ from common.type_checkers.Checkers import chk_float, chk_length, chk_string, chk
 from .gnmi.gnmi_pb2_grpc import gNMIStub
 from .gnmi.gnmi_pb2 import Encoding, GetRequest, SetRequest, UpdateResult   # pylint: disable=no-name-in-module
 from .handlers import ALL_RESOURCE_KEYS, compose, get_path, parse
-from .tools.Capabilities import get_supported_encodings
+from .handlers.YangHandler import YangHandler
+from .tools.Capabilities import check_capabilities
 from .tools.Channel import get_grpc_channel
 from .tools.Path import path_from_string, path_to_string #, compose_path
 from .tools.Subscriptions import Subscriptions
@@ -39,12 +40,22 @@ class GnmiSessionHandler:
         self._use_tls   = settings.get('use_tls', False)
         self._channel : Optional[grpc.Channel] = None
         self._stub : Optional[gNMIStub] = None
+        self._yang_handler = None
         self._monit_thread = None
-        self._supported_encodings = None
+        self._yang_handler = YangHandler()
         self._subscriptions = Subscriptions()
         self._in_subscriptions = queue.Queue()
         self._out_samples = queue.Queue()
 
+    def __del__(self) -> None:
+        self._logger.info('Destroying YangValidator...')
+        if self._yang_handler is not None:
+            self._logger.debug('yang_validator.data:')
+            for path, dnode in self._yang_handler.get_data_paths().items():
+                self._logger.debug('  {:s}: {:s}'.format(str(path), json.dumps(dnode.print_dict())))
+            self._yang_handler.destroy()
+        self._logger.info('DONE')
+
     @property
     def subscriptions(self): return self._subscriptions
 
@@ -58,8 +69,7 @@ class GnmiSessionHandler:
         with self._lock:
             self._channel = get_grpc_channel(self._address, self._port, self._use_tls, self._logger)
             self._stub = gNMIStub(self._channel)
-            self._supported_encodings = get_supported_encodings(
-                self._stub, self._username, self._password, timeout=120)
+            check_capabilities(self._stub, self._username, self._password, timeout=120)
             self._monit_thread = MonitoringThread(
                 self._stub, self._logger, self._settings, self._in_subscriptions, self._out_samples)
             self._monit_thread.start()
@@ -96,13 +106,15 @@ class GnmiSessionHandler:
                 self._logger.exception(MSG.format(str_resource_name, str(resource_key)))
                 parsing_results.append((resource_key, e)) # if validation fails, store the exception
 
+        self._logger.debug('parsing_results={:s}'.format(str(parsing_results)))
+
         if len(parsing_results) > 0:
             return parsing_results
 
         metadata = [('username', self._username), ('password', self._password)]
         timeout = None # GNMI_SUBSCRIPTION_TIMEOUT = int(sampling_duration)
         get_reply = self._stub.Get(get_request, metadata=metadata, timeout=timeout)
-        #self._logger.info('get_reply={:s}'.format(grpc_message_to_json_string(get_reply)))
+        self._logger.debug('get_reply={:s}'.format(grpc_message_to_json_string(get_reply)))
 
         results = []
         #results[str_filter] = [i, None, False]  # (index, value, processed?)
@@ -119,7 +131,7 @@ class GnmiSessionHandler:
             #    resource_key_tuple[2] = True
 
             for update in notification.update:
-                #self._logger.info('update={:s}'.format(grpc_message_to_json_string(update)))
+                self._logger.debug('update={:s}'.format(grpc_message_to_json_string(update)))
                 str_path = path_to_string(update.path)
                 #resource_key_tuple = results.get(str_path)
                 #if resource_key_tuple is None:
@@ -130,10 +142,10 @@ class GnmiSessionHandler:
                     value = decode_value(update.val)
                     #resource_key_tuple[1] = value
                     #resource_key_tuple[2] = True
-                    results.extend(parse(str_path, value))
+                    results.extend(parse(str_path, value, self._yang_handler))
                 except Exception as e: # pylint: disable=broad-except
-                    MSG = 'Exception processing notification {:s}'
-                    self._logger.exception(MSG.format(grpc_message_to_json_string(notification)))
+                    MSG = 'Exception processing update {:s}'
+                    self._logger.exception(MSG.format(grpc_message_to_json_string(update)))
                     results.append((str_path, e)) # if validation fails, store the exception
 
         #_results = sorted(results.items(), key=lambda x: x[1][0])
@@ -158,31 +170,34 @@ class GnmiSessionHandler:
 
         set_request = SetRequest()
         #for resource_key in resource_keys:
+        resources_requested = list()
         for resource_key, resource_value in resources:
-            self._logger.info('---1')
-            self._logger.info(str(resource_key))
-            self._logger.info(str(resource_value))
+            #self._logger.info('---1')
+            #self._logger.info(str(resource_key))
+            #self._logger.info(str(resource_value))
             #resource_tuple = resource_tuples.get(resource_key)
             #if resource_tuple is None: continue
             #_, value, exists, operation_done = resource_tuple
             if isinstance(resource_value, str): resource_value = json.loads(resource_value)
-            str_path, str_data = compose(resource_key, resource_value, delete=False)
-            self._logger.info('---3')
-            self._logger.info(str(str_path))
-            self._logger.info(str(str_data))
+            str_path, str_data = compose(resource_key, resource_value, self._yang_handler, delete=False)
+            if str_path is None: continue # nothing to set
+            #self._logger.info('---3')
+            #self._logger.info(str(str_path))
+            #self._logger.info(str(str_data))
             set_request_list = set_request.update #if exists else set_request.replace
             set_request_entry = set_request_list.add()
             set_request_entry.path.CopyFrom(path_from_string(str_path))
             set_request_entry.val.json_val = str_data.encode('UTF-8')
+            resources_requested.append((resource_key, resource_value))
 
-        self._logger.info('set_request={:s}'.format(grpc_message_to_json_string(set_request)))
+        self._logger.debug('set_request={:s}'.format(grpc_message_to_json_string(set_request)))
         metadata = [('username', self._username), ('password', self._password)]
         timeout = None # GNMI_SUBSCRIPTION_TIMEOUT = int(sampling_duration)
         set_reply = self._stub.Set(set_request, metadata=metadata, timeout=timeout)
-        self._logger.info('set_reply={:s}'.format(grpc_message_to_json_string(set_reply)))
+        self._logger.debug('set_reply={:s}'.format(grpc_message_to_json_string(set_reply)))
 
         results = []
-        for (resource_key, resource_value), update_result in zip(resources, set_reply.response):
+        for (resource_key, resource_value), update_result in zip(resources_requested, set_reply.response):
             operation = update_result.op
             if operation == UpdateResult.UPDATE:
                 results.append((resource_key, True))
@@ -227,30 +242,34 @@ class GnmiSessionHandler:
 
         set_request = SetRequest()
         #for resource_key in resource_keys:
+        resources_requested = list()
         for resource_key, resource_value in resources:
-            self._logger.info('---1')
-            self._logger.info(str(resource_key))
-            self._logger.info(str(resource_value))
+            #self._logger.info('---1')
+            #self._logger.info(str(resource_key))
+            #self._logger.info(str(resource_value))
             #resource_tuple = resource_tuples.get(resource_key)
             #if resource_tuple is None: continue
             #_, value, exists, operation_done = resource_tuple
             #if not exists: continue
             if isinstance(resource_value, str): resource_value = json.loads(resource_value)
-            str_path, str_data = compose(resource_key, resource_value, delete=True)
-            self._logger.info('---3')
-            self._logger.info(str(str_path))
-            self._logger.info(str(str_data))
+            # pylint: disable=unused-variable
+            str_path, str_data = compose(resource_key, resource_value, self._yang_handler, delete=True)
+            if str_path is None: continue # nothing to do with this resource_key
+            #self._logger.info('---3')
+            #self._logger.info(str(str_path))
+            #self._logger.info(str(str_data))
             set_request_entry = set_request.delete.add()
             set_request_entry.CopyFrom(path_from_string(str_path))
+            resources_requested.append((resource_key, resource_value))
 
-        self._logger.info('set_request={:s}'.format(grpc_message_to_json_string(set_request)))
+        self._logger.debug('set_request={:s}'.format(grpc_message_to_json_string(set_request)))
         metadata = [('username', self._username), ('password', self._password)]
         timeout = None # GNMI_SUBSCRIPTION_TIMEOUT = int(sampling_duration)
         set_reply = self._stub.Set(set_request, metadata=metadata, timeout=timeout)
-        self._logger.info('set_reply={:s}'.format(grpc_message_to_json_string(set_reply)))
+        self._logger.debug('set_reply={:s}'.format(grpc_message_to_json_string(set_reply)))
 
         results = []
-        for (resource_key, resource_value), update_result in zip(resources, set_reply.response):
+        for (resource_key, resource_value), update_result in zip(resources_requested, set_reply.response):
             operation = update_result.op
             if operation == UpdateResult.DELETE:
                 results.append((resource_key, True))
diff --git a/src/device/service/drivers/gnmi_openconfig/MonitoringThread.py b/src/device/service/drivers/gnmi_openconfig/MonitoringThread.py
index 8bf6704a854542b3a085af05d55391e23c8d224f..505c2f009cc7a2ab312e062f1ad82bd01d4c183e 100644
--- a/src/device/service/drivers/gnmi_openconfig/MonitoringThread.py
+++ b/src/device/service/drivers/gnmi_openconfig/MonitoringThread.py
@@ -94,9 +94,14 @@ class MonitoringThread(threading.Thread):
         subscriptions = []
         while not self._terminate.is_set():
             try:
-                subscription = self._in_subscriptions.get(block=True, timeout=0.1)
+                # Some devices do not support to process multiple
+                # SubscriptionList requests in a bidirectional channel.
+                # Increased timeout to 5 seconds assuming it should
+                # bring enough time to receive all the subscriptions in
+                # the queue and process them in bulk.
+                subscription = self._in_subscriptions.get(block=True, timeout=5.0)
                 operation, resource_key, sampling_duration, sampling_interval = subscription   # pylint: disable=unused-variable
-                if operation != 'subscribe': continue # Unsubscribe not supported by gNM, needs to cancel entire connection
+                if operation != 'subscribe': continue # Unsubscribe not supported by gNMI, needs to cancel entire connection
                 # options.timeout = int(sampling_duration)
                 #_path = parse_xpath(resource_key)
                 path = path_from_string(resource_key)
@@ -107,15 +112,15 @@ class MonitoringThread(threading.Thread):
                 subscriptions.append(subscription)
             except queue.Empty:
                 if len(subscriptions) == 0: continue
-                #self._logger.warning('[generate_requests] process')
+                self._logger.debug('[generate_requests] process')
                 prefix = path_from_string(GNMI_PATH_PREFIX) if GNMI_PATH_PREFIX is not None else None
                 qos = QOSMarking(marking=GNMI_QOS_MARKING) if GNMI_QOS_MARKING is not None else None
                 subscriptions_list = SubscriptionList(
                     prefix=prefix, mode=GNMI_SUBSCRIPTION_LIST_MODE, allow_aggregation=GNMI_ALLOW_AGGREGATION,
                     encoding=GNMI_ENCODING, subscription=subscriptions, qos=qos)
                 subscribe_request = SubscribeRequest(subscribe=subscriptions_list)
-                #str_subscribe_request = grpc_message_to_json_string(subscribe_request)
-                #self._logger.warning('[generate_requests] subscribe_request={:s}'.format(str_subscribe_request))
+                str_subscribe_request = grpc_message_to_json_string(subscribe_request)
+                self._logger.debug('[generate_requests] subscribe_request={:s}'.format(str_subscribe_request))
                 yield subscribe_request
                 subscriptions = []
             except: # pylint: disable=bare-except
@@ -134,7 +139,7 @@ class MonitoringThread(threading.Thread):
             self._response_iterator = self._stub.Subscribe(request_iterator, metadata=metadata, timeout=timeout)
             for subscribe_response in self._response_iterator:
                 str_subscribe_response = grpc_message_to_json_string(subscribe_response)
-                self._logger.warning('[run] subscribe_response={:s}'.format(str_subscribe_response))
+                self._logger.debug('[run] subscribe_response={:s}'.format(str_subscribe_response))
                 update = subscribe_response.update
                 timestamp_device = float(update.timestamp) / 1.e9
                 timestamp_local = datetime.timestamp(datetime.utcnow())
@@ -145,25 +150,37 @@ class MonitoringThread(threading.Thread):
                 else:
                     # might be clocks are not synchronized, use local timestamp
                     timestamp = timestamp_local
+                str_prefix = path_to_string(update.prefix) if len(update.prefix.elem) > 0 else ''
                 for update_entry in update.update:
                     str_path = path_to_string(update_entry.path)
+                    if len(str_prefix) > 0:
+                        str_path = '{:s}/{:s}'.format(str_prefix, str_path)
+                        str_path = str_path.replace('//', '/')
+                    if str_path.startswith('/interfaces/'):
+                        # Add namespace, if missing
+                        str_path_parts = str_path.split('/')
+                        str_path_parts[1] = 'openconfig-interfaces:interfaces'
+                        str_path = '/'.join(str_path_parts)
                     #if str_path != '/system/name/host-name': continue
                     #counter_name = update_entry.path[-1].name
                     value_type = update_entry.val.WhichOneof('value')
                     value = getattr(update_entry.val, value_type)
-                    if re.match(r'^[0-9]+$', value) is not None:
-                        value = int(value)
-                    elif re.match(r'^[0-9]*\.[0-9]*$', value) is not None:
-                        value = float(value)
-                    else:
-                        value = str(value)
+                    if isinstance(value, str):
+                        if re.match(r'^[0-9]+$', value) is not None:
+                            value = int(value)
+                        elif re.match(r'^[0-9]*\.[0-9]*$', value) is not None:
+                            value = float(value)
+                        else:
+                            value = str(value)
                     delta_sample = self._delta_sample_cache.get_delta(str_path, timestamp, value)
                     if delta_sample is None:
                         sample = (timestamp, str_path, value)
                     else:
                         sample = (delta_sample[0], str_path, delta_sample[1])
-                    self._logger.warning('[run] sample={:s}'.format(str(sample)))
-                    self._out_samples.put_nowait(sample)
+                    self._logger.debug('[run] sample={:s}'.format(str(sample)))
+                    if sample[2] is not None:
+                        # Skip not-a-number (e.g., division by zero) samples
+                        self._out_samples.put_nowait(sample)
         except grpc.RpcError as e:
             if e.code() != grpc.StatusCode.CANCELLED: raise                 # pylint: disable=no-member
             if e.details() != 'Locally cancelled by application!': raise    # pylint: disable=no-member
diff --git a/src/device/service/drivers/gnmi_openconfig/clone-yang-models.sh b/src/device/service/drivers/gnmi_openconfig/clone-yang-models.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b41fc6bbba60bf18c0cccebdb3536c3f96372c39
--- /dev/null
+++ b/src/device/service/drivers/gnmi_openconfig/clone-yang-models.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# 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.
+
+BASE_PATH=~/tfs-ctrl/src/device/service/drivers/gnmi_openconfig
+GIT_BASE_PATH=${BASE_PATH}/git/openconfig
+
+rm -rf ${GIT_BASE_PATH}
+
+OC_PUBLIC_PATH=${GIT_BASE_PATH}/public
+mkdir -p ${OC_PUBLIC_PATH}
+git clone https://github.com/openconfig/public.git ${OC_PUBLIC_PATH}
+
+#OC_HERCULES_PATH=${GIT_BASE_PATH}/hercules
+#mkdir -p ${OC_HERCULES_PATH}
+#git clone https://github.com/openconfig/hercules.git ${OC_HERCULES_PATH}
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/Component.py b/src/device/service/drivers/gnmi_openconfig/handlers/Component.py
index 5ac8754c6081245f79f28b89e026d5a859bc363a..e669872fb5e675ea5490b5e36376ceced4e296ee 100644
--- a/src/device/service/drivers/gnmi_openconfig/handlers/Component.py
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/Component.py
@@ -12,45 +12,52 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import logging
+import json, logging, re # libyang
 from typing import Any, Dict, List, Tuple
 from common.proto.kpi_sample_types_pb2 import KpiSampleType
 from ._Handler import _Handler
+from .YangHandler import YangHandler
 
 LOGGER = logging.getLogger(__name__)
 
-PATH_IF_CTR = "/interfaces/interface[name={:s}]/state/counters/{:s}"
+PATH_IF_CTR = '/openconfig-interfaces:interfaces/interface[name={:s}]/state/counters/{:s}'
 
+#pylint: disable=abstract-method
 class ComponentHandler(_Handler):
     def get_resource_key(self) -> str: return '/endpoints/endpoint'
-    def get_path(self) -> str: return '/components/component'
+    def get_path(self) -> str: return '/openconfig-platform:components'
 
-    def parse(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
-        #LOGGER.info('json_data = {:s}'.format(json.dumps(json_data)))
-        json_component_list : List[Dict] = json_data.get('component', [])
-        response = []
-        for json_component in json_component_list:
-            #LOGGER.info('json_component = {:s}'.format(json.dumps(json_component)))
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('json_data = {:s}'.format(json.dumps(json_data)))
 
-            endpoint = {}
+        yang_components_path = self.get_path()
+        json_data_valid = yang_handler.parse_to_dict(yang_components_path, json_data, fmt='json')
 
-            component_type = json_component.get('state', {}).get('type')
-            if component_type is None: continue
-            component_type = component_type.replace('oc-platform-types:', '')
-            component_type = component_type.replace('openconfig-platform-types:', '')
-            if component_type not in {'PORT'}: continue
-            endpoint['type'] = '-'
+        entries = []
+        for component in json_data_valid['components']['component']:
+            LOGGER.debug('component={:s}'.format(str(component)))
+
+            component_name = component['name']
+            #component_config = component.get('config', {})
 
-            #LOGGER.info('PORT json_component = {:s}'.format(json.dumps(json_component)))
+            #yang_components : libyang.DContainer = yang_handler.get_data_path(yang_components_path)
+            #yang_component_path = 'component[name="{:s}"]'.format(component_name)
+            #yang_component : libyang.DContainer = yang_components.create_path(yang_component_path)
+            #yang_component.merge_data_dict(component, strict=True, validate=False)
 
-            component_name = json_component.get('name')
-            if component_name is None: continue
+            component_state = component.get('state', {})
+            component_type = component_state.get('type')
+            if component_type is None: continue
+            component_type = component_type.split(':')[-1]
+            if component_type not in {'PORT'}: continue
 
             # TODO: improve mapping between interface name and component name
             # By now, computed by time for the sake of saving time for the Hackfest.
-            interface_name = component_name.lower().replace('-port', '')
+            interface_name = re.sub(r'\-[pP][oO][rR][tT]', '', component_name)
 
-            endpoint['uuid'] = interface_name
+            endpoint = {'uuid': interface_name, 'type': '-'}
             endpoint['sample_types'] = {
                 KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED     : PATH_IF_CTR.format(interface_name, 'in-octets' ),
                 KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED  : PATH_IF_CTR.format(interface_name, 'out-octets'),
@@ -58,6 +65,6 @@ class ComponentHandler(_Handler):
                 KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED: PATH_IF_CTR.format(interface_name, 'out-pkts'  ),
             }
 
-            if len(endpoint) == 0: continue
-            response.append(('/endpoints/endpoint[{:s}]'.format(endpoint['uuid']), endpoint))
-        return response
+            entries.append(('/endpoints/endpoint[{:s}]'.format(endpoint['uuid']), endpoint))
+
+        return entries
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/Interface.py b/src/device/service/drivers/gnmi_openconfig/handlers/Interface.py
index e97855aa8b97fc855b07848f1a7f0c7e93717a70..03cfc6ff15e0490aee99be89c3ff1e9327dddf15 100644
--- a/src/device/service/drivers/gnmi_openconfig/handlers/Interface.py
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/Interface.py
@@ -12,20 +12,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import json, logging
+import json, libyang, logging
 from typing import Any, Dict, List, Tuple
 from ._Handler import _Handler
-from .Tools import dict_get_first
+from .Tools import get_bool, get_int, get_str
+from .YangHandler import YangHandler
 
 LOGGER = logging.getLogger(__name__)
 
 class InterfaceHandler(_Handler):
-    def get_resource_key(self) -> str: return '/interface'
-    def get_path(self) -> str: return '/interfaces/interface'
+    def get_resource_key(self) -> str: return '/interface/subinterface'
+    def get_path(self) -> str: return '/openconfig-interfaces:interfaces'
 
-    def compose(self, resource_key : str, resource_value : Dict, delete : bool = False) -> Tuple[str, str]:
-        if_name          = str (resource_value['name'                         ])    # ethernet-1/1
-        sif_index        = int (resource_value.get('sub_if_index'       , 0   ))    # 0
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        if_name   = get_str(resource_value, 'name'    )  # ethernet-1/1
+        sif_index = get_int(resource_value, 'index', 0)  # 0
 
         if delete:
             PATH_TMPL = '/interfaces/interface[name={:s}]/subinterfaces/subinterface[index={:d}]'
@@ -33,216 +36,159 @@ class InterfaceHandler(_Handler):
             str_data = json.dumps({})
             return str_path, str_data
 
-        if_enabled       = bool(resource_value.get('enabled'            , True))    # True/False
-        sif_enabled      = bool(resource_value.get('sub_if_enabled'     , True))    # True/False
-        sif_ipv4_enabled = bool(resource_value.get('sub_if_ipv4_enabled', True))    # True/False
-        sif_ipv4_address = str (resource_value['sub_if_ipv4_address'          ])    # 172.16.0.1
-        sif_ipv4_prefix  = int (resource_value['sub_if_ipv4_prefix'           ])    # 24
+        enabled        = get_bool(resource_value, 'enabled',  True) # True/False
+        #if_type        = get_str (resource_value, 'type'         ) # 'l3ipvlan'
+        vlan_id        = get_int (resource_value, 'vlan_id',      ) # 127
+        address_ip     = get_str (resource_value, 'address_ip'    ) # 172.16.0.1
+        address_prefix = get_int (resource_value, 'address_prefix') # 24
+        mtu            = get_int (resource_value, 'mtu'           ) # 1500
+
+        yang_ifs : libyang.DContainer = yang_handler.get_data_path('/openconfig-interfaces:interfaces')
+        yang_if_path = 'interface[name="{:s}"]'.format(if_name)
+        yang_if : libyang.DContainer = yang_ifs.create_path(yang_if_path)
+        yang_if.create_path('config/name',    if_name   )
+        if enabled is not None: yang_if.create_path('config/enabled', enabled)
+        if mtu     is not None: yang_if.create_path('config/mtu',     mtu)
+
+        yang_sifs : libyang.DContainer = yang_if.create_path('subinterfaces')
+        yang_sif_path = 'subinterface[index="{:d}"]'.format(sif_index)
+        yang_sif : libyang.DContainer = yang_sifs.create_path(yang_sif_path)
+        yang_sif.create_path('config/index', sif_index)
+        if enabled is not None: yang_sif.create_path('config/enabled', enabled)
+
+        if vlan_id is not None:
+            yang_subif_vlan : libyang.DContainer = yang_sif.create_path('openconfig-vlan:vlan')
+            yang_subif_vlan.create_path('match/single-tagged/config/vlan-id', vlan_id)
+
+        yang_ipv4 : libyang.DContainer = yang_sif.create_path('openconfig-if-ip:ipv4')
+        if enabled is not None: yang_ipv4.create_path('config/enabled', enabled)
+
+        if address_ip is not None and address_prefix is not None:
+            yang_ipv4_addrs : libyang.DContainer = yang_ipv4.create_path('addresses')
+            yang_ipv4_addr_path = 'address[ip="{:s}"]'.format(address_ip)
+            yang_ipv4_addr : libyang.DContainer = yang_ipv4_addrs.create_path(yang_ipv4_addr_path)
+            yang_ipv4_addr.create_path('config/ip',            address_ip)
+            yang_ipv4_addr.create_path('config/prefix-length', address_prefix)
+            if mtu is not None: yang_ipv4_addr.create_path('config/mtu', mtu)
 
         str_path = '/interfaces/interface[name={:s}]'.format(if_name)
-        str_data = json.dumps({
-            'name': if_name,
-            'config': {'name': if_name, 'enabled': if_enabled},
-            'subinterfaces': {
-                'subinterface': {
-                    'index': sif_index,
-                    'config': {'index': sif_index, 'enabled': sif_enabled},
-                    'ipv4': {
-                        'config': {'enabled': sif_ipv4_enabled},
-                        'addresses': {
-                            'address': {
-                                'ip': sif_ipv4_address,
-                                'config': {'ip': sif_ipv4_address, 'prefix_length': sif_ipv4_prefix},
-                            }
-                        }
-                    }
-                }
-            }
-        })
+        str_data = yang_if.print_mem('json')
+        json_data = json.loads(str_data)
+        json_data = json_data['openconfig-interfaces:interface'][0]
+        str_data = json.dumps(json_data)
         return str_path, str_data
 
-    def parse(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
-        #LOGGER.info('json_data = {:s}'.format(json.dumps(json_data)))
-        json_interface_list : List[Dict] = json_data.get('interface', [])
-
-        response = []
-        for json_interface in json_interface_list:
-            #LOGGER.info('json_interface = {:s}'.format(json.dumps(json_interface)))
-
-            interface = {}
-
-            interface_name = json_interface.get('name')
-            if interface_name is None:
-                LOGGER.info('DISCARDED json_interface = {:s}'.format(json.dumps(json_interface)))
-                continue
-            interface['name'] = interface_name
-
-            CONFIG_FIELDS = ('config', 'openconfig-interface:config', 'oci:config')
-            json_config : Dict = dict_get_first(json_interface, CONFIG_FIELDS, default={})
-
-            STATE_FIELDS = ('state', 'openconfig-interface:state', 'oci:state')
-            json_state : Dict = dict_get_first(json_interface, STATE_FIELDS, default={})
-
-            interface_type = json_config.get('type')
-            if interface_type is None: interface_type = json_state.get('type')
-            if interface_type is None:
-                LOGGER.info('DISCARDED json_interface = {:s}'.format(json.dumps(json_interface)))
-                continue
-            interface_type = interface_type.replace('ianaift:', '')
-            interface_type = interface_type.replace('iana-if-type:', '')
-            interface['type'] = interface_type
-
-            interface_mtu = json_config.get('mtu')
-            if interface_mtu is None: interface_mtu = json_state.get('mtu')
-            if interface_mtu is not None: interface['mtu'] = int(interface_mtu)
-
-            interface_enabled = json_config.get('enabled')
-            if interface_enabled is None: interface_enabled = json_state.get('enabled')
-            interface['enabled'] = False if interface_enabled is None else bool(interface_enabled)
-
-            interface_management = json_config.get('management')
-            if interface_management is None: interface_management = json_state.get('management')
-            interface['management'] = False if interface_management is None else bool(interface_management)
-
-            interface_descr = json_interface.get('config', {}).get('description')
-            if interface_descr is not None: interface['description'] = interface_descr
-
-            json_subinterfaces = json_interface.get('subinterfaces', {})
-            json_subinterface_list : List[Dict] = json_subinterfaces.get('subinterface', [])
-
-            for json_subinterface in json_subinterface_list:
-                #LOGGER.info('json_subinterface = {:s}'.format(json.dumps(json_subinterface)))
-
-                subinterface = {}
-
-                subinterface_index = json_subinterface.get('state', {}).get('index')
-                if subinterface_index is None: continue
-                subinterface['index'] = int(subinterface_index)
-
-                subinterface_name = json_subinterface.get('state', {}).get('name')
-                if subinterface_name is None: continue
-                subinterface['name'] = subinterface_name
-
-                subinterface_enabled = json_subinterface.get('state', {}).get('enabled', False)
-                subinterface['enabled'] = bool(subinterface_enabled)
-
-                VLAN_FIELDS = ('vlan', 'openconfig-vlan:vlan', 'ocv:vlan')
-                json_vlan = dict_get_first(json_subinterface, VLAN_FIELDS, default={})
-
-                MATCH_FIELDS = ('match', 'openconfig-vlan:match', 'ocv:match')
-                json_vlan = dict_get_first(json_vlan, MATCH_FIELDS, default={})
-
-                SIN_TAG_FIELDS = ('single-tagged', 'openconfig-vlan:single-tagged', 'ocv:single-tagged')
-                json_vlan = dict_get_first(json_vlan, SIN_TAG_FIELDS, default={})
-
-                CONFIG_FIELDS = ('config', 'openconfig-vlan:config', 'ocv:config')
-                json_vlan = dict_get_first(json_vlan, CONFIG_FIELDS, default={})
-
-                VLAN_ID_FIELDS = ('vlan-id', 'openconfig-vlan:vlan-id', 'ocv:vlan-id')
-                subinterface_vlan_id = dict_get_first(json_vlan, VLAN_ID_FIELDS)
-                if subinterface_vlan_id is not None: subinterface['vlan_id'] = subinterface_vlan_id
-
-
-                # TODO: implement support for multiple IP addresses per subinterface
-
-                IPV4_FIELDS = ('ipv4', 'openconfig-if-ip:ipv4', 'ociip:ipv4')
-                json_ipv4 = dict_get_first(json_subinterface, IPV4_FIELDS, default={})
-                
-                IPV4_ADDRESSES_FIELDS = ('addresses', 'openconfig-if-ip:addresses', 'ociip:addresses')
-                json_ipv4_addresses = dict_get_first(json_ipv4, IPV4_ADDRESSES_FIELDS, default={})
-
-                IPV4_ADDRESS_FIELDS = ('address', 'openconfig-if-ip:address', 'ociip:address')
-                json_ipv4_address_list : List[Dict] = dict_get_first(json_ipv4_addresses, IPV4_ADDRESS_FIELDS, default=[])
-
-                #ipv4_addresses = []
-                for json_ipv4_address in json_ipv4_address_list:
-                    #LOGGER.info('json_ipv4_address = {:s}'.format(json.dumps(json_ipv4_address)))
-
-                    STATE_FIELDS = ('state', 'openconfig-if-ip:state', 'ociip:state')
-                    json_ipv4_address_state = dict_get_first(json_ipv4_address, STATE_FIELDS, default={})
-
-                    #ipv4_address = {}
-
-                    #ORIGIN_FIELDS = ('origin', 'openconfig-if-ip:origin', 'ociip:origin')
-                    #ipv4_address_origin = dict_get_first(json_ipv4_address_state, ORIGIN_FIELDS, default={})
-                    #if ipv4_address_origin is not None: ipv4_address['origin'] = ipv4_address_origin
-
-                    IP_FIELDS = ('ip', 'openconfig-if-ip:ip', 'ociip:ip')
-                    ipv4_address_ip = dict_get_first(json_ipv4_address_state, IP_FIELDS)
-                    #if ipv4_address_ip is not None: ipv4_address['address_ip'] = ipv4_address_ip
-                    if ipv4_address_ip is not None: subinterface['address_ip'] = ipv4_address_ip
-
-                    PREFIX_FIELDS = ('prefix-length', 'openconfig-if-ip:prefix-length', 'ociip:prefix-length')
-                    ipv4_address_prefix = dict_get_first(json_ipv4_address_state, PREFIX_FIELDS)
-                    #if ipv4_address_prefix is not None: ipv4_address['address_prefix'] = int(ipv4_address_prefix)
-                    if ipv4_address_prefix is not None: subinterface['address_prefix'] = int(ipv4_address_prefix)
-
-                    #if len(ipv4_address) == 0: continue
-                    #ipv4_addresses.append(ipv4_address)
-
-                #subinterface['ipv4_addresses'] = ipv4_addresses
-
-                if len(subinterface) == 0: continue
-                resource_key = '/interface[{:s}]/subinterface[{:s}]'.format(interface['name'], str(subinterface['index']))
-                response.append((resource_key, subinterface))
-
-            if len(interface) == 0: continue
-            response.append(('/interface[{:s}]'.format(interface['name']), interface))
-
-        return response
-
-    def parse_counters(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
-        LOGGER.info('[parse_counters] json_data = {:s}'.format(json.dumps(json_data)))
-        json_interface_list : List[Dict] = json_data.get('interface', [])
-
-        response = []
-        for json_interface in json_interface_list:
-            LOGGER.info('[parse_counters] json_interface = {:s}'.format(json.dumps(json_interface)))
-
-            interface = {}
-
-            NAME_FIELDS = ('name', 'openconfig-interface:name', 'oci:name')
-            interface_name = dict_get_first(json_interface, NAME_FIELDS)
-            if interface_name is None: continue
-            interface['name'] = interface_name
-
-            STATE_FIELDS = ('state', 'openconfig-interface:state', 'oci:state')
-            json_state = dict_get_first(json_interface, STATE_FIELDS, default={})
-
-            COUNTERS_FIELDS = ('counters', 'openconfig-interface:counters', 'oci:counters')
-            json_counters = dict_get_first(json_state, COUNTERS_FIELDS, default={})
-
-            IN_PKTS_FIELDS = ('in-pkts', 'openconfig-interface:in-pkts', 'oci:in-pkts')
-            interface_in_pkts = dict_get_first(json_counters, IN_PKTS_FIELDS)
-            if interface_in_pkts is not None: interface['in-pkts'] = int(interface_in_pkts)
-
-            IN_OCTETS_FIELDS = ('in-octets', 'openconfig-interface:in-octets', 'oci:in-octets')
-            interface_in_octets = dict_get_first(json_counters, IN_OCTETS_FIELDS)
-            if interface_in_octets is not None: interface['in-octets'] = int(interface_in_octets)
-
-            IN_ERRORS_FIELDS = ('in-errors', 'openconfig-interface:in-errors', 'oci:in-errors')
-            interface_in_errors = dict_get_first(json_counters, IN_ERRORS_FIELDS)
-            if interface_in_errors is not None: interface['in-errors'] = int(interface_in_errors)
-
-            OUT_OCTETS_FIELDS = ('out-octets', 'openconfig-interface:out-octets', 'oci:out-octets')
-            interface_out_octets = dict_get_first(json_counters, OUT_OCTETS_FIELDS)
-            if interface_out_octets is not None: interface['out-octets'] = int(interface_out_octets)
-
-            OUT_PKTS_FIELDS = ('out-pkts', 'openconfig-interface:out-pkts', 'oci:out-pkts')
-            interface_out_pkts = dict_get_first(json_counters, OUT_PKTS_FIELDS)
-            if interface_out_pkts is not None: interface['out-pkts'] = int(interface_out_pkts)
-
-            OUT_ERRORS_FIELDS = ('out-errors', 'openconfig-interface:out-errors', 'oci:out-errors')
-            interface_out_errors = dict_get_first(json_counters, OUT_ERRORS_FIELDS)
-            if interface_out_errors is not None: interface['out-errors'] = int(interface_out_errors)
-
-            OUT_DISCARDS_FIELDS = ('out-discards', 'openconfig-interface:out-discards', 'oci:out-discards')
-            interface_out_discards = dict_get_first(json_counters, OUT_DISCARDS_FIELDS)
-            if interface_out_discards is not None: interface['out-discards'] = int(interface_out_discards)
-
-            #LOGGER.info('[parse_counters] interface = {:s}'.format(str(interface)))
-
-            if len(interface) == 0: continue
-            response.append(('/interface[{:s}]'.format(interface['name']), interface))
-
-        return response
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('json_data = {:s}'.format(json.dumps(json_data)))
+
+        yang_interfaces_path = self.get_path()
+        json_data_valid = yang_handler.parse_to_dict(yang_interfaces_path, json_data, fmt='json')
+
+        entries = []
+        for interface in json_data_valid['interfaces']['interface']:
+            LOGGER.debug('interface={:s}'.format(str(interface)))
+
+            interface_name = interface['name']
+            interface_config = interface.get('config', {})
+
+            #yang_interfaces : libyang.DContainer = yang_handler.get_data_path(yang_interfaces_path)
+            #yang_interface_path = 'interface[name="{:s}"]'.format(interface_name)
+            #yang_interface : libyang.DContainer = yang_interfaces.create_path(yang_interface_path)
+            #yang_interface.merge_data_dict(interface, strict=True, validate=False)
+
+            interface_state = interface.get('state', {})
+            interface_type = interface_state.get('type')
+            if interface_type is None: continue
+            interface_type = interface_type.split(':')[-1]
+            if interface_type not in {'ethernetCsmacd'}: continue
+
+            _interface = {
+                'name'         : interface_name,
+                'type'         : interface_type,
+                'mtu'          : interface_state['mtu'],
+                'admin-status' : interface_state['admin-status'],
+                'oper-status'  : interface_state['oper-status'],
+                'management'   : interface_state['management'],
+            }
+            if not interface_state['management'] and 'ifindex' in interface_state:
+                _interface['ifindex'] = interface_state['ifindex']
+            if 'description' in interface_config:
+                _interface['description'] = interface_config['description']
+            if 'enabled' in interface_config:
+                _interface['enabled'] = interface_config['enabled']
+            if 'hardware-port' in interface_state:
+                _interface['hardware-port'] = interface_state['hardware-port']
+            if 'transceiver' in interface_state:
+                _interface['transceiver'] = interface_state['transceiver']
+
+            entry_interface_key = '/interface[{:s}]'.format(interface_name)
+            entries.append((entry_interface_key, _interface))
+
+            if interface_type == 'ethernetCsmacd':
+                ethernet_state = interface['ethernet']['state']
+
+                _ethernet = {
+                    'mac-address'           : ethernet_state['mac-address'],
+                    'hw-mac-address'        : ethernet_state['hw-mac-address'],
+                    'port-speed'            : ethernet_state['port-speed'].split(':')[-1],
+                    'negotiated-port-speed' : ethernet_state['negotiated-port-speed'].split(':')[-1],
+                }
+                entry_ethernet_key = '{:s}/ethernet'.format(entry_interface_key)
+                entries.append((entry_ethernet_key, _ethernet))
+
+            subinterfaces = interface.get('subinterfaces', {}).get('subinterface', [])
+            for subinterface in subinterfaces:
+                LOGGER.debug('subinterface={:s}'.format(str(subinterface)))
+
+                subinterface_index = subinterface['index']
+                subinterface_state = subinterface.get('state', {})
+
+                _subinterface = {'index': subinterface_index}
+                if 'name' in subinterface_state:
+                    _subinterface['name'] = subinterface_state['name']
+                if 'enabled' in subinterface_state:
+                    _subinterface['enabled'] = subinterface_state['enabled']
+
+                if 'vlan' in subinterface:
+                    vlan = subinterface['vlan']
+                    vlan_match = vlan['match']
+
+                    single_tagged = vlan_match.pop('single-tagged', None)
+                    if single_tagged is not None:
+                        single_tagged_config = single_tagged['config']
+                        vlan_id = single_tagged_config['vlan-id']
+                        _subinterface['vlan_id'] = vlan_id
+
+                    if len(vlan_match) > 0:
+                        raise Exception('Unsupported VLAN schema: {:s}'.format(str(vlan)))
+
+                ipv4_addresses = subinterface.get('ipv4', {}).get('addresses', {}).get('address', [])
+                if len(ipv4_addresses) > 1:
+                    raise Exception('Multiple IPv4 Addresses not supported: {:s}'.format(str(ipv4_addresses)))
+                for ipv4_address in ipv4_addresses:
+                    LOGGER.debug('ipv4_address={:s}'.format(str(ipv4_address)))
+                    _subinterface['address_ip'] = ipv4_address['ip']
+                    ipv4_address_state = ipv4_address.get('state', {})
+                    #if 'origin' in ipv4_address_state:
+                    #    _subinterface['origin'] = ipv4_address_state['origin']
+                    if 'prefix-length' in ipv4_address_state:
+                        _subinterface['address_prefix'] = ipv4_address_state['prefix-length']
+
+                ipv6_addresses = subinterface.get('ipv6', {}).get('addresses', {}).get('address', [])
+                if len(ipv6_addresses) > 1:
+                    raise Exception('Multiple IPv6 Addresses not supported: {:s}'.format(str(ipv6_addresses)))
+                for ipv6_address in ipv6_addresses:
+                    LOGGER.debug('ipv6_address={:s}'.format(str(ipv6_address)))
+                    _subinterface['address_ipv6'] = ipv6_address['ip']
+                    ipv6_address_state = ipv6_address.get('state', {})
+                    #if 'origin' in ipv6_address_state:
+                    #    _subinterface['origin_ipv6'] = ipv6_address_state['origin']
+                    if 'prefix-length' in ipv6_address_state:
+                        _subinterface['address_prefix_ipv6'] = ipv6_address_state['prefix-length']
+
+                entry_subinterface_key = '{:s}/subinterface[{:d}]'.format(entry_interface_key, subinterface_index)
+                entries.append((entry_subinterface_key, _subinterface))
+
+        return entries
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/InterfaceCounter.py b/src/device/service/drivers/gnmi_openconfig/handlers/InterfaceCounter.py
index 502868c2204553d30e7cdd529184cf994d03fd21..ae6d86c43addf4f3083b9900796365b3e0601620 100644
--- a/src/device/service/drivers/gnmi_openconfig/handlers/InterfaceCounter.py
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/InterfaceCounter.py
@@ -12,69 +12,53 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import json, logging
+import json, libyang, logging
 from typing import Any, Dict, List, Tuple
 from ._Handler import _Handler
-from .Tools import dict_get_first
+from .YangHandler import YangHandler
 
 LOGGER = logging.getLogger(__name__)
 
+#pylint: disable=abstract-method
 class InterfaceCounterHandler(_Handler):
     def get_resource_key(self) -> str: return '/interface/counters'
-    def get_path(self) -> str: return '/interfaces/interface/state/counters'
-
-    def parse(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
-        LOGGER.info('[parse] json_data = {:s}'.format(json.dumps(json_data)))
-        json_interface_list : List[Dict] = json_data.get('interface', [])
-
-        response = []
-        for json_interface in json_interface_list:
-            LOGGER.info('[parse] json_interface = {:s}'.format(json.dumps(json_interface)))
-
-            interface = {}
-
-            NAME_FIELDS = ('name', 'openconfig-interface:name', 'oci:name')
-            interface_name = dict_get_first(json_interface, NAME_FIELDS)
-            if interface_name is None: continue
-            interface['name'] = interface_name
-
-            STATE_FIELDS = ('state', 'openconfig-interface:state', 'oci:state')
-            json_state = dict_get_first(json_interface, STATE_FIELDS, default={})
-
-            COUNTERS_FIELDS = ('counters', 'openconfig-interface:counters', 'oci:counters')
-            json_counters = dict_get_first(json_state, COUNTERS_FIELDS, default={})
-
-            IN_PKTS_FIELDS = ('in-pkts', 'openconfig-interface:in-pkts', 'oci:in-pkts')
-            interface_in_pkts = dict_get_first(json_counters, IN_PKTS_FIELDS)
-            if interface_in_pkts is not None: interface['in-pkts'] = int(interface_in_pkts)
-
-            IN_OCTETS_FIELDS = ('in-octets', 'openconfig-interface:in-octets', 'oci:in-octets')
-            interface_in_octets = dict_get_first(json_counters, IN_OCTETS_FIELDS)
-            if interface_in_octets is not None: interface['in-octets'] = int(interface_in_octets)
-
-            IN_ERRORS_FIELDS = ('in-errors', 'openconfig-interface:in-errors', 'oci:in-errors')
-            interface_in_errors = dict_get_first(json_counters, IN_ERRORS_FIELDS)
-            if interface_in_errors is not None: interface['in-errors'] = int(interface_in_errors)
-
-            OUT_OCTETS_FIELDS = ('out-octets', 'openconfig-interface:out-octets', 'oci:out-octets')
-            interface_out_octets = dict_get_first(json_counters, OUT_OCTETS_FIELDS)
-            if interface_out_octets is not None: interface['out-octets'] = int(interface_out_octets)
-
-            OUT_PKTS_FIELDS = ('out-pkts', 'openconfig-interface:out-pkts', 'oci:out-pkts')
-            interface_out_pkts = dict_get_first(json_counters, OUT_PKTS_FIELDS)
-            if interface_out_pkts is not None: interface['out-pkts'] = int(interface_out_pkts)
-
-            OUT_ERRORS_FIELDS = ('out-errors', 'openconfig-interface:out-errors', 'oci:out-errors')
-            interface_out_errors = dict_get_first(json_counters, OUT_ERRORS_FIELDS)
-            if interface_out_errors is not None: interface['out-errors'] = int(interface_out_errors)
-
-            OUT_DISCARDS_FIELDS = ('out-discards', 'openconfig-interface:out-discards', 'oci:out-discards')
-            interface_out_discards = dict_get_first(json_counters, OUT_DISCARDS_FIELDS)
-            if interface_out_discards is not None: interface['out-discards'] = int(interface_out_discards)
-
-            #LOGGER.info('[parse] interface = {:s}'.format(str(interface)))
-
-            if len(interface) == 0: continue
-            response.append(('/interface[{:s}]'.format(interface['name']), interface))
-
-        return response
+    def get_path(self) -> str: return '/openconfig-interfaces:interfaces/interface/state/counters'
+
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('json_data = {:s}'.format(json.dumps(json_data)))
+
+        yang_interfaces_path = self.get_path()
+        json_data_valid = yang_handler.parse_to_dict(yang_interfaces_path, json_data, fmt='json')
+
+        entries = []
+        for interface in json_data_valid['interfaces']['interface']:
+            LOGGER.debug('interface={:s}'.format(str(interface)))
+
+            interface_name = interface['name']
+            interface_counters = interface.get('state', {}).get('counters', {})
+            _interface = {
+                'name'              : interface_name,
+                'in-broadcast-pkts' : interface_counters['in_broadcast_pkts' ],
+                'in-discards'       : interface_counters['in_discards'       ],
+                'in-errors'         : interface_counters['in_errors'         ],
+                'in-fcs-errors'     : interface_counters['in_fcs_errors'     ],
+                'in-multicast-pkts' : interface_counters['in_multicast_pkts' ],
+                'in-octets'         : interface_counters['in_octets'         ],
+                'in-pkts'           : interface_counters['in_pkts'           ],
+                'in-unicast-pkts'   : interface_counters['in_unicast_pkts'   ],
+                'out-broadcast-pkts': interface_counters['out_broadcast_pkts'],
+                'out-discards'      : interface_counters['out_discards'      ],
+                'out-errors'        : interface_counters['out_errors'        ],
+                'out-multicast-pkts': interface_counters['out_multicast_pkts'],
+                'out-octets'        : interface_counters['out_octets'        ],
+                'out-pkts'          : interface_counters['out_pkts'          ],
+                'out-unicast-pkts'  : interface_counters['out_unicast_pkts'  ],
+            }
+            LOGGER.debug('interface = {:s}'.format(str(interface)))
+
+            entry_interface_key = '/interface[{:s}]'.format(interface_name)
+            entries.append((entry_interface_key, _interface))
+
+        return entries
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstance.py b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstance.py
index d522eec964b2c6beffe953075411dbba2594eaa4..f1d1c56b4023a1250263aaf0995975d815eb5fec 100644
--- a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstance.py
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstance.py
@@ -12,18 +12,39 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import json, logging
+import json, libyang, logging
 from typing import Any, Dict, List, Tuple
 from ._Handler import _Handler
+from .Tools import get_str
+from .YangHandler import YangHandler
 
 LOGGER = logging.getLogger(__name__)
 
+MAP_NETWORK_INSTANCE_TYPE = {
+    # special routing instance; acts as default/global routing instance for a network device
+    'DEFAULT': 'openconfig-network-instance-types:DEFAULT_INSTANCE',
+
+    # private L3-only routing instance; formed of one or more RIBs
+    'L3VRF': 'openconfig-network-instance-types:L3VRF',
+
+    # private L2-only switch instance; formed of one or more L2 forwarding tables
+    'L2VSI': 'openconfig-network-instance-types:L2VSI',
+
+    # private L2-only forwarding instance; point to point connection between two endpoints
+    'L2P2P': 'openconfig-network-instance-types:L2P2P',
+
+    # private Layer 2 and Layer 3 forwarding instance
+    'L2L3': 'openconfig-network-instance-types:L2L3',
+}
+
 class NetworkInstanceHandler(_Handler):
     def get_resource_key(self) -> str: return '/network_instance'
-    def get_path(self) -> str: return '/network-instances/network-instance'
+    def get_path(self) -> str: return '/openconfig-network-instance:network-instances'
 
-    def compose(self, resource_key : str, resource_value : Dict, delete : bool = False) -> Tuple[str, str]:
-        ni_name   = str(resource_value['name'])   # test-svc
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        ni_name = get_str(resource_value, 'name') # test-svc
 
         if delete:
             PATH_TMPL = '/network-instances/network-instance[name={:s}]'
@@ -31,32 +52,124 @@ class NetworkInstanceHandler(_Handler):
             str_data = json.dumps({})
             return str_path, str_data
 
-        ni_type   = str(resource_value['type'])   # L3VRF / L2VSI / ...
+        ni_type = get_str(resource_value, 'type') # L3VRF / L2VSI / ...
+        ni_type = MAP_NETWORK_INSTANCE_TYPE.get(ni_type, ni_type)
+
+        str_path = '/network-instances/network-instance[name={:s}]'.format(ni_name)
+        #str_data = json.dumps({
+        #    'name': ni_name,
+        #    'config': {'name': ni_name, 'type': ni_type},
+        #})
 
-        # not works: [FailedPrecondition] unsupported identifier 'DIRECTLY_CONNECTED'
-        #protocols = [self._compose_directly_connected()]
+        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
+        yang_ni_path = 'network-instance[name="{:s}"]'.format(ni_name)
+        yang_ni : libyang.DContainer = yang_nis.create_path(yang_ni_path)
+        yang_ni.create_path('config/name', ni_name)
+        yang_ni.create_path('config/type', ni_type)
 
-        MAP_OC_NI_TYPE = {
-            'L3VRF': 'openconfig-network-instance-types:L3VRF',
-        }
-        ni_type = MAP_OC_NI_TYPE.get(ni_type, ni_type)
+        # 'DIRECTLY_CONNECTED' is implicitly added
+        #'protocols': {'protocol': protocols},
 
-        str_path = '/network-instances/network-instance[name={:s}]'.format(ni_name)
-        str_data = json.dumps({
-            'name': ni_name,
-            'config': {'name': ni_name, 'type': ni_type},
-            #'protocols': {'protocol': protocols},
-        })
+        str_data = yang_ni.print_mem('json')
+        json_data = json.loads(str_data)
+        json_data = json_data['openconfig-network-instance:network-instance'][0]
+        str_data = json.dumps(json_data)
         return str_path, str_data
 
-    def _compose_directly_connected(self, name=None, enabled=True) -> Dict:
-        identifier = 'DIRECTLY_CONNECTED'
-        if name is None: name = 'DIRECTLY_CONNECTED'
-        return {
-            'identifier': identifier, 'name': name,
-            'config': {'identifier': identifier, 'name': name, 'enabled': enabled},
-        }
-
-    def parse(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
-        response = []
-        return response
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('json_data = {:s}'.format(json.dumps(json_data)))
+
+        # Arista Parsing Fixes:
+        # - Default instance comes with mpls/signaling-protocols/rsvp-te/global/hellos/state/hello-interval set to 0
+        #   overwrite with .../hellos/config/hello-interval
+        network_instances = json_data.get('openconfig-network-instance:network-instance', [])
+        for network_instance in network_instances:
+            if network_instance['name'] != 'default': continue
+            mpls_rsvp_te = network_instance.get('mpls', {}).get('signaling-protocols', {}).get('rsvp-te', {})
+            mpls_rsvp_te_hellos = mpls_rsvp_te.get('global', {}).get('hellos', {})
+            hello_interval = mpls_rsvp_te_hellos.get('config', {}).get('hello-interval', 9000)
+            mpls_rsvp_te_hellos.get('state', {})['hello-interval'] = hello_interval
+
+        yang_network_instances_path = self.get_path()
+        json_data_valid = yang_handler.parse_to_dict(yang_network_instances_path, json_data, fmt='json', strict=False)
+
+        entries = []
+        for network_instance in json_data_valid['network-instances']['network-instance']:
+            LOGGER.debug('network_instance={:s}'.format(str(network_instance)))
+            ni_name = network_instance['name']
+
+            ni_config = network_instance['config']
+            ni_type = ni_config['type'].split(':')[-1]
+
+            _net_inst = {'name': ni_name, 'type': ni_type}
+            entry_net_inst_key = '/network_instance[{:s}]'.format(ni_name)
+            entries.append((entry_net_inst_key, _net_inst))
+
+            ni_interfaces = network_instance.get('interfaces', {}).get('interface', [])
+            for ni_interface in ni_interfaces:
+                #ni_if_id     = ni_interface['id']
+                ni_if_config = ni_interface['config']
+                ni_if_name   = ni_if_config['interface']
+                ni_sif_index = ni_if_config['subinterface']
+                ni_if_id     = '{:s}.{:d}'.format(ni_if_name, ni_sif_index)
+
+                _interface = {'name': ni_name, 'id': ni_if_id, 'if_name': ni_if_name, 'sif_index': ni_sif_index}
+                entry_interface_key = '{:s}/interface[{:s}]'.format(entry_net_inst_key, ni_if_id)
+                entries.append((entry_interface_key, _interface))
+
+            ni_protocols = network_instance.get('protocols', {}).get('protocol', [])
+            for ni_protocol in ni_protocols:
+                ni_protocol_id = ni_protocol['identifier'].split(':')[-1]
+                ni_protocol_name = ni_protocol['name']
+
+                _protocol = {'name': ni_name, 'identifier': ni_protocol_id, 'protocol_name': ni_protocol_name}
+                entry_protocol_key = '{:s}/protocols[{:s}]'.format(entry_net_inst_key, ni_protocol_id)
+                entries.append((entry_protocol_key, _protocol))
+
+                if ni_protocol_id == 'STATIC':
+                    static_routes = ni_protocol.get('static-routes', {}).get('static', [])
+                    for static_route in static_routes:
+                        static_route_prefix = static_route['prefix']
+                        for next_hop in static_route.get('next-hops', {}).get('next-hop', []):
+                            static_route_metric = next_hop['config']['metric']
+                            _static_route = {
+                                'prefix'  : static_route_prefix,
+                                'index'   : next_hop['index'],
+                                'next_hop': next_hop['config']['next-hop'],
+                                'metric'  : static_route_metric,
+                            }
+                            _static_route.update(_protocol)
+                            entry_static_route_key = '{:s}/static_route[{:s}:{:d}]'.format(
+                                entry_protocol_key, static_route_prefix, static_route_metric
+                            )
+                            entries.append((entry_static_route_key, _static_route))
+
+            ni_tables = network_instance.get('tables', {}).get('table', [])
+            for ni_table in ni_tables:
+                ni_table_protocol = ni_table['protocol'].split(':')[-1]
+                ni_table_address_family = ni_table['address-family'].split(':')[-1]
+                _table = {'protocol': ni_table_protocol, 'address_family': ni_table_address_family}
+                entry_table_key = '{:s}/table[{:s},{:s}]'.format(
+                    entry_net_inst_key, ni_table_protocol, ni_table_address_family
+                )
+                entries.append((entry_table_key, _table))
+
+            ni_vlans = network_instance.get('vlans', {}).get('vlan', [])
+            for ni_vlan in ni_vlans:
+                ni_vlan_id = ni_vlan['vlan-id']
+
+                #ni_vlan_config = ni_vlan['config']
+                ni_vlan_state = ni_vlan['state']
+                ni_vlan_name = ni_vlan_state['name']
+
+                _members = [
+                    member['state']['interface']
+                    for member in ni_vlan.get('members', {}).get('member', [])
+                ]
+                _vlan = {'vlan_id': ni_vlan_id, 'name': ni_vlan_name, 'members': _members}
+                entry_vlan_key = '{:s}/vlan[{:d}]'.format(entry_net_inst_key, ni_vlan_id)
+                entries.append((entry_vlan_key, _vlan))
+
+        return entries
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceInterface.py b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceInterface.py
index cc22618bc4179ba6eabdd2b4232b8cbfb92f1587..5e5ea9bf0bdc38b09d3959e8b6ecfc3534319817 100644
--- a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceInterface.py
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceInterface.py
@@ -12,35 +12,62 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import json, logging
+import json, libyang, logging
 from typing import Any, Dict, List, Tuple
 from ._Handler import _Handler
+from .Tools import get_int, get_str
+from .YangHandler import YangHandler
 
 LOGGER = logging.getLogger(__name__)
 
+IS_CEOS = True
+
 class NetworkInstanceInterfaceHandler(_Handler):
     def get_resource_key(self) -> str: return '/network_instance/interface'
-    def get_path(self) -> str: return '/network-instances/network-instance/interfaces'
+    def get_path(self) -> str: return '/openconfig-network-instance:network-instances/network-instance/interfaces'
+
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        ni_name   = get_str(resource_value, 'name'           ) # test-svc
+        ni_if_id  = get_str(resource_value, 'id'             ) # ethernet-1/1.0
+        if_name   = get_str(resource_value, 'interface'      ) # ethernet-1/1
+        sif_index = get_int(resource_value, 'subinterface', 0) # 0
 
-    def compose(self, resource_key : str, resource_value : Dict, delete : bool = False) -> Tuple[str, str]:
-        ni_name   = str(resource_value['name'     ])    # test-svc
-        if_name   = str(resource_value['if_name'  ])    # ethernet-1/1
-        sif_index = int(resource_value['sif_index'])    # 0
-        if_id     = '{:s}.{:d}'.format(if_name, sif_index)
+        if IS_CEOS: ni_if_id = if_name
 
         if delete:
             PATH_TMPL = '/network-instances/network-instance[name={:s}]/interfaces/interface[id={:s}]'
-            str_path = PATH_TMPL.format(ni_name, if_id)
+            str_path = PATH_TMPL.format(ni_name, ni_if_id)
             str_data = json.dumps({})
             return str_path, str_data
 
-        str_path = '/network-instances/network-instance[name={:s}]/interfaces/interface[id={:s}]'.format(ni_name, if_id)
-        str_data = json.dumps({
-            'id': if_id,
-            'config': {'id': if_id, 'interface': if_name, 'subinterface': sif_index},
-        })
+        str_path = '/network-instances/network-instance[name={:s}]/interfaces/interface[id={:s}]'.format(
+            ni_name, ni_if_id
+        )
+        #str_data = json.dumps({
+        #    'id': if_id,
+        #    'config': {'id': if_id, 'interface': if_name, 'subinterface': sif_index},
+        #})
+
+        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
+        yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name))
+        yang_ni_ifs : libyang.DContainer = yang_ni.create_path('interfaces')
+        yang_ni_if_path = 'interface[id="{:s}"]'.format(ni_if_id)
+        yang_ni_if : libyang.DContainer = yang_ni_ifs.create_path(yang_ni_if_path)
+        yang_ni_if.create_path('config/id',           ni_if_id)
+        yang_ni_if.create_path('config/interface',    if_name)
+        yang_ni_if.create_path('config/subinterface', sif_index)
+
+        str_data = yang_ni_if.print_mem('json')
+        json_data = json.loads(str_data)
+        json_data = json_data['openconfig-network-instance:interface'][0]
+        str_data = json.dumps(json_data)
         return str_path, str_data
 
-    def parse(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('[parse] json_data = {:s}'.format(str(json_data)))
         response = []
         return response
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceProtocol.py b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceProtocol.py
new file mode 100644
index 0000000000000000000000000000000000000000..f155fa1ca5c0a990abf18ab1c78059673d94e04e
--- /dev/null
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceProtocol.py
@@ -0,0 +1,79 @@
+# 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, libyang, logging
+from typing import Any, Dict, List, Tuple
+from ._Handler import _Handler
+from .Tools import get_str
+from .YangHandler import YangHandler
+
+LOGGER = logging.getLogger(__name__)
+
+class NetworkInstanceProtocolHandler(_Handler):
+    def get_resource_key(self) -> str: return '/network_instance/protocols'
+    def get_path(self) -> str:
+        return '/openconfig-network-instance:network-instances/network-instance/protocols/protocol'
+
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        ni_name    = get_str(resource_value, 'name'  )          # test-svc
+        identifier = get_str(resource_value, 'identifier')      # 'STATIC'
+        proto_name = get_str(resource_value, 'protocol_name')   # 'STATIC'
+
+        if ':' not in identifier:
+            identifier = 'openconfig-policy-types:{:s}'.format(identifier)
+        PATH_TMPL = '/network-instances/network-instance[name={:s}]/protocols/protocol[identifier={:s}][name={:s}]'
+        str_path = PATH_TMPL.format(ni_name, identifier, proto_name)
+
+        if delete:
+            str_data = json.dumps({})
+            return str_path, str_data
+
+        #str_data = json.dumps({
+        #    'identifier': identifier, 'name': name,
+        #    'config': {'identifier': identifier, 'name': name, 'enabled': True},
+        #    'static_routes': {'static': [{
+        #        'prefix': prefix,
+        #        'config': {'prefix': prefix},
+        #        'next_hops': {
+        #            'next-hop': [{
+        #                'index': next_hop_index,
+        #                'config': {'index': next_hop_index, 'next_hop': next_hop}
+        #            }]
+        #        }
+        #    }]}
+        #})
+
+        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
+        yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name))
+        yang_ni_prs : libyang.DContainer = yang_ni.create_path('protocols')
+        yang_ni_pr_path = 'protocol[identifier="{:s}"][name="{:s}"]'.format(identifier, proto_name)
+        yang_ni_pr : libyang.DContainer = yang_ni_prs.create_path(yang_ni_pr_path)
+        yang_ni_pr.create_path('config/identifier', identifier)
+        yang_ni_pr.create_path('config/name',       proto_name)
+        yang_ni_pr.create_path('config/enabled',    True      )
+
+        str_data = yang_ni_pr.print_mem('json')
+        json_data = json.loads(str_data)
+        json_data = json_data['openconfig-network-instance:protocol'][0]
+        str_data = json.dumps(json_data)
+        return str_path, str_data
+
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('[parse] json_data = {:s}'.format(str(json_data)))
+        response = []
+        return response
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py
index 6294f9c9bf46b3b60da48f19c08ad57f096fa39b..9f80b647b8e1188c80609dbdb47bbe9ea0d68b5f 100644
--- a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py
@@ -12,50 +12,90 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import json, logging
+import json, libyang, logging
 from typing import Any, Dict, List, Tuple
 from ._Handler import _Handler
+from .Tools import get_int, get_str
+from .YangHandler import YangHandler
 
 LOGGER = logging.getLogger(__name__)
 
 class NetworkInstanceStaticRouteHandler(_Handler):
-    def get_resource_key(self) -> str: return '/network_instance/static_route'
-    def get_path(self) -> str: return '/network-instances/network-instance/static_route'
+    def get_resource_key(self) -> str: return '/network_instance/protocols/static_route'
+    def get_path(self) -> str:
+        return '/openconfig-network-instance:network-instances/network-instance/protocols/protocol/static-routes'
 
-    def compose(self, resource_key : str, resource_value : Dict, delete : bool = False) -> Tuple[str, str]:
-        ni_name        = str(resource_value['name'                 ]) # test-svc
-        prefix         = str(resource_value['prefix'               ]) # '172.0.1.0/24'
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
+        ni_name    = get_str(resource_value, 'name'  )          # test-svc
+        identifier = get_str(resource_value, 'identifier')      # 'STATIC'
+        proto_name = get_str(resource_value, 'protocol_name')   # 'STATIC'
+        prefix     = get_str(resource_value, 'prefix')          # '172.0.1.0/24'
+
+        if ':' not in identifier:
+            identifier = 'openconfig-policy-types:{:s}'.format(identifier)
 
-        identifier = 'STATIC'
-        name = 'static'
         if delete:
             PATH_TMPL  = '/network-instances/network-instance[name={:s}]/protocols'
             PATH_TMPL += '/protocol[identifier={:s}][name={:s}]/static-routes/static[prefix={:s}]'
-            str_path = PATH_TMPL.format(ni_name, identifier, name, prefix)
+            str_path = PATH_TMPL.format(ni_name, identifier, proto_name, prefix)
             str_data = json.dumps({})
             return str_path, str_data
 
-        next_hop       = str(resource_value['next_hop'             ]) # '172.0.0.1'
-        next_hop_index = int(resource_value.get('next_hop_index', 0)) # 0
+        next_hop = get_str(resource_value, 'next_hop')  # '172.0.0.1'
+        metric   = get_int(resource_value, 'metric'  )  # 20
+        index    = get_str(resource_value, 'index'   )  # AUTO_1_172-0-0-1
+        if index is None:
+            index = 'AUTO_{:d}_{:s}'.format(metric, next_hop)
 
         PATH_TMPL = '/network-instances/network-instance[name={:s}]/protocols/protocol[identifier={:s}][name={:s}]'
-        str_path = PATH_TMPL.format(ni_name, identifier, name)
-        str_data = json.dumps({
-            'identifier': identifier, 'name': name,
-            'config': {'identifier': identifier, 'name': name, 'enabled': True},
-            'static_routes': {'static': [{
-                'prefix': prefix,
-                'config': {'prefix': prefix},
-                'next_hops': {
-                    'next-hop': [{
-                        'index': next_hop_index,
-                        'config': {'index': next_hop_index, 'next_hop': next_hop}
-                    }]
-                }
-            }]}
-        })
+        str_path = PATH_TMPL.format(ni_name, identifier, proto_name)
+        #str_data = json.dumps({
+        #    'identifier': identifier, 'name': name,
+        #    'config': {'identifier': identifier, 'name': name, 'enabled': True},
+        #    'static_routes': {'static': [{
+        #        'prefix': prefix,
+        #        'config': {'prefix': prefix},
+        #        'next_hops': {
+        #            'next-hop': [{
+        #                'index': next_hop_index,
+        #                'config': {'index': next_hop_index, 'next_hop': next_hop}
+        #            }]
+        #        }
+        #    }]}
+        #})
+
+        yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances')
+        yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name))
+        yang_ni_prs : libyang.DContainer = yang_ni.create_path('protocols')
+        yang_ni_pr_path = 'protocol[identifier="{:s}"][name="{:s}"]'.format(identifier, proto_name)
+        yang_ni_pr : libyang.DContainer = yang_ni_prs.create_path(yang_ni_pr_path)
+        yang_ni_pr.create_path('config/identifier', identifier)
+        yang_ni_pr.create_path('config/name',       proto_name)
+        yang_ni_pr.create_path('config/enabled',    True      )
+
+        yang_ni_pr_srs : libyang.DContainer = yang_ni_pr.create_path('static-routes')
+        yang_ni_pr_sr_path = 'static[prefix="{:s}"]'.format(prefix)
+        yang_ni_pr_sr : libyang.DContainer = yang_ni_pr_srs.create_path(yang_ni_pr_sr_path)
+        yang_ni_pr_sr.create_path('config/prefix', prefix)
+
+        yang_ni_pr_sr_nhs : libyang.DContainer = yang_ni_pr_sr.create_path('next-hops')
+        yang_ni_pr_sr_nh_path = 'next-hop[index="{:s}"]'.format(index)
+        yang_ni_pr_sr_nh : libyang.DContainer = yang_ni_pr_sr_nhs.create_path(yang_ni_pr_sr_nh_path)
+        yang_ni_pr_sr_nh.create_path('config/index',    index)
+        yang_ni_pr_sr_nh.create_path('config/next-hop', next_hop)
+        yang_ni_pr_sr_nh.create_path('config/metric',   metric)
+
+        str_data = yang_ni_pr.print_mem('json')
+        json_data = json.loads(str_data)
+        json_data = json_data['openconfig-network-instance:protocol'][0]
+        str_data = json.dumps(json_data)
         return str_path, str_data
 
-    def parse(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
+        LOGGER.debug('[parse] json_data = {:s}'.format(str(json_data)))
         response = []
         return response
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/Tools.py b/src/device/service/drivers/gnmi_openconfig/handlers/Tools.py
index 358c7de9fa3b9c46c4a7c70142deb1c2ab396ad0..f258de926d44c48a655eab877eeb0350df511b69 100644
--- a/src/device/service/drivers/gnmi_openconfig/handlers/Tools.py
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/Tools.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 import re
-from typing import Any, Dict, Iterable
+from typing import Any, Callable, Dict, Iterable, Optional
 
 RE_REMOVE_FILTERS = re.compile(r'\[[^\]]+\]')
 RE_REMOVE_NAMESPACES = re.compile(r'\/[a-zA-Z0-9\_\-]+:')
@@ -23,8 +23,39 @@ def get_schema(resource_key : str):
     resource_key = RE_REMOVE_NAMESPACES.sub('/', resource_key)
     return resource_key
 
-def dict_get_first(d : Dict, field_names : Iterable[str], default=None) -> Any:
-    for field_name in field_names:
-        if field_name not in d: continue
-        return d[field_name]
+def container_get_first(
+    container : Dict[str, Any], key_name : str, namespace : Optional[str]=None, namespaces : Iterable[str]=tuple(),
+    default : Optional[Any] = None
+) -> Any:
+    value = container.get(key_name)
+    if value is not None: return value
+
+    if namespace is not None:
+        if len(namespaces) > 0:
+            raise Exception('At maximum, one of namespace or namespaces can be specified')
+        namespaces = (namespace,)
+
+    for namespace in namespaces:
+        namespace_key_name = '{:s}:{:s}'.format(namespace, key_name)
+        if namespace_key_name in container: return container[namespace_key_name]
+
     return default
+
+def get_value(
+    resource_value : Dict, field_name : str, cast_func : Callable = lambda x:x, default : Optional[Any] = None
+) -> Optional[Any]:
+    field_value = resource_value.get(field_name, default)
+    if field_value is not None: field_value = cast_func(field_value)
+    return field_value
+
+def get_bool(resource_value : Dict, field_name : bool, default : Optional[Any] = None) -> bool:
+    return get_value(resource_value, field_name, cast_func=bool, default=default)
+
+def get_float(resource_value : Dict, field_name : float, default : Optional[Any] = None) -> float:
+    return get_value(resource_value, field_name, cast_func=float, default=default)
+
+def get_int(resource_value : Dict, field_name : int, default : Optional[Any] = None) -> int:
+    return get_value(resource_value, field_name, cast_func=int, default=default)
+
+def get_str(resource_value : Dict, field_name : str, default : Optional[Any] = None) -> str:
+    return get_value(resource_value, field_name, cast_func=str, default=default)
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/YangHandler.py b/src/device/service/drivers/gnmi_openconfig/handlers/YangHandler.py
new file mode 100644
index 0000000000000000000000000000000000000000..944dfa60781162d841c5da12813a4581c282471b
--- /dev/null
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/YangHandler.py
@@ -0,0 +1,110 @@
+# 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, libyang, logging, os
+from typing import Dict, Optional
+
+YANG_BASE_PATH = os.path.join(os.path.dirname(__file__), '..', 'git', 'openconfig', 'public')
+YANG_SEARCH_PATHS = ':'.join([
+    os.path.join(YANG_BASE_PATH, 'release'),
+    os.path.join(YANG_BASE_PATH, 'third_party'),
+])
+
+YANG_MODULES = [
+    'iana-if-type',
+    'openconfig-bgp-types',
+    'openconfig-vlan-types',
+
+    'openconfig-interfaces',
+    'openconfig-if-8021x',
+    'openconfig-if-aggregate',
+    'openconfig-if-ethernet-ext',
+    'openconfig-if-ethernet',
+    'openconfig-if-ip-ext',
+    'openconfig-if-ip',
+    'openconfig-if-poe',
+    'openconfig-if-sdn-ext',
+    'openconfig-if-tunnel',
+
+    'openconfig-vlan',
+
+    'openconfig-types',
+    'openconfig-policy-types',
+    'openconfig-mpls-types',
+    'openconfig-network-instance-types',
+    'openconfig-network-instance',
+
+    'openconfig-platform',
+    'openconfig-platform-controller-card',
+    'openconfig-platform-cpu',
+    'openconfig-platform-ext',
+    'openconfig-platform-fabric',
+    'openconfig-platform-fan',
+    'openconfig-platform-integrated-circuit',
+    'openconfig-platform-linecard',
+    'openconfig-platform-pipeline-counters',
+    'openconfig-platform-port',
+    'openconfig-platform-psu',
+    'openconfig-platform-software',
+    'openconfig-platform-transceiver',
+    'openconfig-platform-types',
+]
+
+LOGGER = logging.getLogger(__name__)
+
+class YangHandler:
+    def __init__(self) -> None:
+        self._yang_context = libyang.Context(YANG_SEARCH_PATHS)
+        self._loaded_modules = set()
+        for yang_module_name in YANG_MODULES:
+            LOGGER.info('Loading module: {:s}'.format(str(yang_module_name)))
+            self._yang_context.load_module(yang_module_name).feature_enable_all()
+            self._loaded_modules.add(yang_module_name)
+        self._data_path_instances = dict()
+
+    def get_data_paths(self) -> Dict[str, libyang.DNode]:
+        return self._data_path_instances
+
+    def get_data_path(self, path : str) -> libyang.DNode:
+        data_path_instance = self._data_path_instances.get(path)
+        if data_path_instance is None:
+            data_path_instance = self._yang_context.create_data_path(path)
+            self._data_path_instances[path] = data_path_instance
+        return data_path_instance
+
+    def parse_to_dict(
+        self, request_path : str, json_data : Dict, fmt : str = 'json', strict : bool = True
+    ) -> Dict:
+        if fmt != 'json': raise Exception('Unsupported format: {:s}'.format(str(fmt)))
+        LOGGER.debug('request_path = {:s}'.format(str(request_path)))
+        LOGGER.debug('json_data = {:s}'.format(str(json_data)))
+        LOGGER.debug('format = {:s}'.format(str(fmt)))
+
+        parent_path_parts = list(filter(lambda s: len(s) > 0, request_path.split('/')))
+        for parent_path_part in reversed(parent_path_parts):
+            json_data = {parent_path_part: json_data}
+        str_data = json.dumps(json_data)
+
+        dnode : Optional[libyang.DNode] = self._yang_context.parse_data_mem(
+            str_data, fmt, strict=strict, parse_only=True, #validate_present=True, #validate=True,
+        )
+        if dnode is None: raise Exception('Unable to parse Data({:s})'.format(str(json_data)))
+
+        parsed = dnode.print_dict()
+        LOGGER.debug('parsed = {:s}'.format(json.dumps(parsed)))
+        dnode.free()
+        return parsed
+
+    def destroy(self) -> None:
+        self._yang_context.destroy()
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/_Handler.py b/src/device/service/drivers/gnmi_openconfig/handlers/_Handler.py
index f051c43534ab4e1d6c15a34ae2070067034ba9e1..215a4d499e534ca9797c487adb0c798487a4a7cf 100644
--- a/src/device/service/drivers/gnmi_openconfig/handlers/_Handler.py
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/_Handler.py
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 from typing import Any, Dict, List, Tuple
+from .YangHandler import YangHandler
 
 class _Handler:
     def get_resource_key(self) -> str:
@@ -23,10 +24,14 @@ class _Handler:
         # Retrieve the OpenConfig path schema used to interrogate the device
         raise NotImplementedError()
 
-    def compose(self, resource_key : str, resource_value : Dict, delete : bool = False) -> Tuple[str, str]:
+    def compose(
+        self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False
+    ) -> Tuple[str, str]:
         # Compose a Set/Delete message based on the resource_key/resource_value fields, and the delete flag
         raise NotImplementedError()
 
-    def parse(self, json_data : Dict) -> List[Tuple[str, Dict[str, Any]]]:
+    def parse(
+        self, json_data : Dict, yang_handler : YangHandler
+    ) -> List[Tuple[str, Dict[str, Any]]]:
         # Parse a Reply from the device and return a list of resource_key/resource_value pairs
         raise NotImplementedError()
diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/__init__.py b/src/device/service/drivers/gnmi_openconfig/handlers/__init__.py
index 4ff8e8b38b4a76ba9bb0d2b91fb70b54b06a170e..b36313bb2030ed9d07f1f3c198ea9447a0cafbaa 100644
--- a/src/device/service/drivers/gnmi_openconfig/handlers/__init__.py
+++ b/src/device/service/drivers/gnmi_openconfig/handlers/__init__.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 import logging
-from typing import Dict, List, Optional, Tuple, Union
+from typing import Any, Dict, List, Optional, Tuple, Union
 from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES
 from ._Handler import _Handler
 from .Component import ComponentHandler
@@ -21,8 +21,10 @@ from .Interface import InterfaceHandler
 from .InterfaceCounter import InterfaceCounterHandler
 from .NetworkInstance import NetworkInstanceHandler
 from .NetworkInstanceInterface import NetworkInstanceInterfaceHandler
+from .NetworkInstanceProtocol import NetworkInstanceProtocolHandler
 from .NetworkInstanceStaticRoute import NetworkInstanceStaticRouteHandler
 from .Tools import get_schema
+from .YangHandler import YangHandler
 
 LOGGER = logging.getLogger(__name__)
 
@@ -31,6 +33,7 @@ ifaceh = InterfaceHandler()
 ifctrh = InterfaceCounterHandler()
 nih    = NetworkInstanceHandler()
 niifh  = NetworkInstanceInterfaceHandler()
+niph   = NetworkInstanceProtocolHandler()
 nisrh  = NetworkInstanceStaticRouteHandler()
 
 ALL_RESOURCE_KEYS = [
@@ -46,9 +49,10 @@ RESOURCE_KEY_MAPPER = {
 }
 
 PATH_MAPPER = {
-    '/components'        : comph.get_path(),
-    '/interfaces'        : ifaceh.get_path(),
-    '/network-instances' : nih.get_path(),
+    '/components'           : comph.get_path(),
+    '/components/component' : comph.get_path(),
+    '/interfaces'           : ifaceh.get_path(),
+    '/network-instances'    : nih.get_path(),
 }
 
 RESOURCE_KEY_TO_HANDLER = {
@@ -57,6 +61,7 @@ RESOURCE_KEY_TO_HANDLER = {
     ifctrh.get_resource_key() : ifctrh,
     nih.get_resource_key()    : nih,
     niifh.get_resource_key()  : niifh,
+    niph.get_resource_key()   : niph,
     nisrh.get_resource_key()  : nisrh,
 }
 
@@ -66,11 +71,13 @@ PATH_TO_HANDLER = {
     ifctrh.get_path() : ifctrh,
     nih.get_path()    : nih,
     niifh.get_path()  : niifh,
+    niph.get_path()   : niph,
     nisrh.get_path()  : nisrh,
 }
 
 def get_handler(
-    resource_key : Optional[str] = None, path : Optional[str] = None, raise_if_not_found=True
+    resource_key : Optional[str] = None, path : Optional[str] = None,
+    raise_if_not_found=True
 ) -> Optional[_Handler]:
     if (resource_key is None) == (path is None):
         MSG = 'Exactly one of resource_key({:s}) or path({:s}) must be specified'
@@ -88,16 +95,24 @@ def get_handler(
         path_schema = PATH_MAPPER.get(path_schema, path_schema)
         handler = PATH_TO_HANDLER.get(path_schema)
         if handler is None and raise_if_not_found:
-            MSG = 'Handler not found: resource_key={:s} resource_key_schema={:s}'
+            MSG = 'Handler not found: path={:s} path_schema={:s}'
             # pylint: disable=broad-exception-raised
-            raise Exception(MSG.format(str(resource_key), str(resource_key_schema)))
+            raise Exception(MSG.format(str(path), str(path_schema)))
     return handler
 
 def get_path(resource_key : str) -> str:
-    return get_handler(resource_key=resource_key).get_path()
+    handler = get_handler(resource_key=resource_key)
+    return handler.get_path()
 
-def parse(str_path : str, value : Union[Dict, List]):
-    return get_handler(path=str_path).parse(value)
+def parse(
+    str_path : str, value : Union[Dict, List], yang_handler : YangHandler
+) -> List[Tuple[str, Dict[str, Any]]]:
+    handler = get_handler(path=str_path)
+    return handler.parse(value, yang_handler)
 
-def compose(resource_key : str, resource_value : Union[Dict, List], delete : bool = False) -> Tuple[str, str]:
-    return get_handler(resource_key=resource_key).compose(resource_key, resource_value, delete=delete)
+def compose(
+    resource_key : str, resource_value : Union[Dict, List],
+    yang_handler : YangHandler, delete : bool = False
+) -> Tuple[str, str]:
+    handler = get_handler(resource_key=resource_key)
+    return handler.compose(resource_key, resource_value, yang_handler, delete=delete)
diff --git a/src/device/service/drivers/gnmi_openconfig/tools/Capabilities.py b/src/device/service/drivers/gnmi_openconfig/tools/Capabilities.py
index 093a96233f26399be4e224a48a78ea6329da4304..66b30da9832e661b35e1f13b3e3a47c7a50098cb 100644
--- a/src/device/service/drivers/gnmi_openconfig/tools/Capabilities.py
+++ b/src/device/service/drivers/gnmi_openconfig/tools/Capabilities.py
@@ -17,7 +17,7 @@ from common.tools.grpc.Tools import grpc_message_to_json
 from ..gnmi.gnmi_pb2 import CapabilityRequest   # pylint: disable=no-name-in-module
 from ..gnmi.gnmi_pb2_grpc import gNMIStub
 
-def get_supported_encodings(
+def check_capabilities(
     stub : gNMIStub, username : str, password : str, timeout : Optional[int] = None
 ) -> Set[Union[str, int]]:
     metadata = [('username', username), ('password', password)]
@@ -25,6 +25,17 @@ def get_supported_encodings(
     reply = stub.Capabilities(req, metadata=metadata, timeout=timeout)
 
     data = grpc_message_to_json(reply)
+
+    gnmi_version = data.get('gNMI_version')
+    if gnmi_version is None or gnmi_version != '0.7.0':
+        raise Exception('Unsupported gNMI version: {:s}'.format(str(gnmi_version)))
+
+    #supported_models = {
+    #    supported_model['name']: supported_model['version']
+    #    for supported_model in data.get('supported_models', [])
+    #}
+    # TODO: check supported models and versions
+
     supported_encodings = {
         supported_encoding
         for supported_encoding in data.get('supported_encodings', [])
@@ -33,4 +44,6 @@ def get_supported_encodings(
     if len(supported_encodings) == 0:
         # pylint: disable=broad-exception-raised
         raise Exception('No supported encodings found')
-    return supported_encodings
+    if 'JSON_IETF' not in supported_encodings:
+        # pylint: disable=broad-exception-raised
+        raise Exception('JSON_IETF encoding not supported')
diff --git a/src/device/service/drivers/gnmi_openconfig/tools/Path.py b/src/device/service/drivers/gnmi_openconfig/tools/Path.py
index 7ce0631dada58ce581900c974a0b24d170df2f39..1955fc4d94eff0106d324a067809f93151da5699 100644
--- a/src/device/service/drivers/gnmi_openconfig/tools/Path.py
+++ b/src/device/service/drivers/gnmi_openconfig/tools/Path.py
@@ -19,8 +19,8 @@ from ..gnmi.gnmi_pb2 import Path, PathElem
 RE_PATH_SPLIT = re.compile(r'/(?=(?:[^\[\]]|\[[^\[\]]+\])*$)')
 RE_PATH_KEYS = re.compile(r'\[(.*?)\]')
 
-def path_from_string(path='/'):
-    if not path: return Path(elem=[])
+def path_from_string(path='/'): #, origin='openconfig'
+    if not path: return Path(elem=[]) #, origin=origin
 
     if path[0] == '/':
         if path[-1] == '/':
@@ -40,7 +40,7 @@ def path_from_string(path='/'):
         dict_keys = dict(x.split('=', 1) for x in elem_keys)
         path.append(PathElem(name=elem_name, key=dict_keys))
 
-    return Path(elem=path)
+    return Path(elem=path) #, origin=origin
 
 def path_to_string(path : Path) -> str:
     path_parts = list()
diff --git a/src/device/service/drivers/gnmi_openconfig/tools/Value.py b/src/device/service/drivers/gnmi_openconfig/tools/Value.py
index 077bdd40ec8859202b8e8e6053b731339edfe7fe..325dacd51b8b1157ea63ff71eed1f9a758d56c3b 100644
--- a/src/device/service/drivers/gnmi_openconfig/tools/Value.py
+++ b/src/device/service/drivers/gnmi_openconfig/tools/Value.py
@@ -13,9 +13,36 @@
 # limitations under the License.
 
 import base64, json
-from typing import Any
+from typing import Any, Dict, List, Union
 from ..gnmi.gnmi_pb2 import TypedValue
 
+REMOVE_NAMESPACES = (
+    'arista-intf-augments',
+    'arista-netinst-augments',
+    'openconfig-hercules-platform',
+)
+
+def remove_fields(key : str) -> bool:
+    parts = key.split(':')
+    if len(parts) == 1: return False
+    namespace = parts[0].lower()
+    return namespace in REMOVE_NAMESPACES
+
+def recursive_remove_keys(container : Union[Dict, List, Any]) -> None:
+    if isinstance(container, dict):
+        remove_keys = [
+            key
+            for key in container.keys()
+            if remove_fields(key)
+        ]
+        for key in remove_keys:
+            container.pop(key, None)
+        for value in container.values():
+            recursive_remove_keys(value)
+    elif isinstance(container, list):
+        for value in container:
+            recursive_remove_keys(value)
+
 def decode_value(value : TypedValue) -> Any:
     encoding = value.WhichOneof('value')
     if encoding == 'json_val':
@@ -31,9 +58,13 @@ def decode_value(value : TypedValue) -> Any:
         raise NotImplementedError()
         #return value
     elif encoding == 'json_ietf_val':
-        value : str = value.json_ietf_val
+        str_value : str = value.json_ietf_val.decode('UTF-8')
         try:
-            return json.loads(value)
+            # Cleanup and normalize the records according to OpenConfig
+            #str_value = str_value.replace('openconfig-platform-types:', 'oc-platform-types:')
+            json_value = json.loads(str_value)
+            recursive_remove_keys(json_value)
+            return json_value
         except json.decoder.JSONDecodeError:
             # Assume is Base64-encoded
             b_b64_value = value.encode('UTF-8')
diff --git a/src/device/service/drivers/oc_driver/OCDriver.py b/src/device/service/drivers/oc_driver/OCDriver.py
index 89dc791f6982239c3eb878662b02f7f845c6746b..087e58b7673e752d208eaa82b30a697e4eb8d08c 100644
--- a/src/device/service/drivers/oc_driver/OCDriver.py
+++ b/src/device/service/drivers/oc_driver/OCDriver.py
@@ -13,33 +13,31 @@
 # limitations under the License.
 
 import json
-import anytree, copy, logging, pytz, queue, re, threading
+import logging, pytz, queue, re, threading
 #import lxml.etree as ET
-from datetime import datetime, timedelta
-from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
+from typing import Any, List, Tuple, Union
 from apscheduler.executors.pool import ThreadPoolExecutor
-import xml.etree.ElementTree as ET
-from apscheduler.job import Job
 from apscheduler.jobstores.memory import MemoryJobStore
 from apscheduler.schedulers.background import BackgroundScheduler
 from ncclient.manager import Manager, connect_ssh
 from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method
 from common.tools.client.RetryDecorator import delay_exponential
-from common.type_checkers.Checkers import chk_length, chk_string, chk_type, chk_float
+from common.type_checkers.Checkers import  chk_type
 from device.service.driver_api.Exceptions import UnsupportedResourceKeyException
 from device.service.driver_api._Driver import _Driver
-from device.service.driver_api.AnyTreeTools import TreeNode, get_subnode, set_subnode_value #dump_subtree
+from device.service.driver_api.AnyTreeTools import TreeNode
+from .templates.VPN.common import seperate_port_config
 #from .Tools import xml_pretty_print, xml_to_dict, xml_to_file
-from .templates.Interfaces.interfaces import interface_template
-from .templates.VPN.physical import  create_optical_channel,add_transceiver,create_media_channel,create_optical_band
+from .templates.VPN.roadms import (
+    create_optical_band, disable_media_channel, delete_optical_band, create_media_channel_v2
+)
+from .templates.VPN.transponder import edit_optical_channel, change_optical_channel_status
 from .RetryDecorator import retry
 from context.client.ContextClient import ContextClient
-from common.proto.context_pb2 import (
-    OpticalConfig,
-    ConfigActionEnum, Device, DeviceDriverEnum, DeviceId, DeviceList, DeviceOperationalStatusEnum, Empty
-    ,OpticalConfigId,Uuid)
-from .templates.Tools import extractor
-from .Tools import generate_uuid_from_numbers
+from common.proto.context_pb2 import OpticalConfig
+from .templates.descovery_tool.transponders import transponder_values_extractor
+from .templates.descovery_tool.roadms import roadm_values_extractor, openroadm_values_extractor
+
 DEBUG_MODE = False
 logging.getLogger('ncclient.manager').setLevel(logging.DEBUG if DEBUG_MODE else logging.WARNING)
 logging.getLogger('ncclient.transport.ssh').setLevel(logging.DEBUG if DEBUG_MODE else logging.WARNING)
@@ -56,13 +54,14 @@ RE_GET_ENDPOINT_FROM_INTERFACE_XPATH = re.compile(r".*interface\[oci\:name\='([^
 
 SAMPLE_EVICTION_SECONDS = 30.0 # seconds
 SAMPLE_RESOURCE_KEY = 'interfaces/interface/state/counters'
-filter_fields= ["frequency","target-output-power","interface","operational-mode","line-port"]
+transponder_filter_fields = ["frequency", "target-output-power", "operational-mode", "line-port", "admin-state"]
 MAX_RETRIES = 15
 DELAY_FUNCTION = delay_exponential(initial=0.01, increment=2.0, maximum=5.0)
 RETRY_DECORATOR = retry(max_retries=MAX_RETRIES, delay_function=DELAY_FUNCTION, prepare_method_name='connect')
 context_client= ContextClient()
 port_xml_filter=f"/components/component[state[type='oc-platform-types:PORT']]/*"
 transceiver_xml_filter="/components/component[state[type='oc-platform-types:TRANSCEIVER']]/*"
+
 class NetconfSessionHandler:
     def __init__(self, address : str, port : int, **settings) -> None:
         self.__lock = threading.RLock()
@@ -83,6 +82,7 @@ class NetconfSessionHandler:
         self.__manager_params   = settings.get('manager_params', {})
         self.__nc_params        = settings.get('nc_params', {})
         self.__message_renderer = settings.get('message_renderer','jinja')
+      
         self.__manager : Manager   = None
         self.__candidate_supported = False
        
@@ -109,10 +109,10 @@ class NetconfSessionHandler:
 
     @property
     def vendor(self): return self.__vendor
-    
+
     @property
     def version(self): return self.__version
-    
+
     @property
     def message_renderer(self): return self.__message_renderer
 
@@ -120,7 +120,6 @@ class NetconfSessionHandler:
     def get(self, filter=None, with_defaults=None): # pylint: disable=redefined-builtin
         with self.__lock:
             config=self.__manager.get(filter=filter, with_defaults=with_defaults)
-        
             return config
 
     @RETRY_DECORATOR
@@ -128,14 +127,16 @@ class NetconfSessionHandler:
         self, config, target='running', default_operation=None, test_option=None,
         error_option=None, format='xml'                                             # pylint: disable=redefined-builtin
     ):
-        
-
-        
+        response = None
         with self.__lock:
             response= self.__manager.edit_config(
                 config, target=target, default_operation=default_operation, test_option=test_option,
                 error_option=error_option, format=format)
-           
+
+        str_respones = str(response)  
+        if re.search(r'<ok/>', str_respones):
+           return True
+        return False
 
     @RETRY_DECORATOR
     def locked(self, target):
@@ -144,7 +145,7 @@ class NetconfSessionHandler:
     @RETRY_DECORATOR
     def commit(self, confirmed=False, timeout=None, persist=None, persist_id=None):
         return self.__manager.commit(confirmed=confirmed, timeout=timeout, persist=persist, persist_id=persist_id)
-    
+
 DRIVER_NAME = 'oc'
 METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME})
 def edit_config(                                                                                                            # edit the configuration of openconfig devices
@@ -153,80 +154,80 @@ def edit_config(
     commit_per_rule=False, target='running', default_operation='merge', test_option=None, error_option=None,
     format='xml' 
 ):
-    #str_method = 'DeleteConfig' if delete else 'SetConfig'
+    str_method = 'DeleteConfig' if delete else 'SetConfig'
     results = []
 
     str_config_messages=[]
-   
-
-    if (conditions['edit_type']=='optical-channel'):
-        #transponder
-        str_config_messages =  create_optical_channel(resources)
-    elif (conditions['edit_type']=='optical-band'):
-        #roadm optical-band
-        str_config_messages = create_optical_band(resources)   
-    else :
-        #roadm media-channel
-        str_config_messages=create_media_channel(resources)
-    
-    
-        
+    if str_method == 'SetConfig':
+        if (conditions['edit_type']=='optical-channel'):
+            #transponder
+            str_config_messages =  edit_optical_channel(resources)
+        elif (conditions['edit_type']=='optical-band'):
+            #roadm optical-band
+            str_config_messages = create_optical_band(resources)   
+        else :
+            #roadm media-channel
+            str_config_messages=create_media_channel_v2(resources)
+    #Disabling of the Configuration         
+    else:
+        # Device type is Transponder
+        if (conditions['edit_type'] == "optical-channel"):
+            _,ports,_=seperate_port_config(resources)
+            str_config_messages=change_optical_channel_status(state="DISABLED",ports=ports)
+            
+        #  Device type is Roadm     
+        elif (conditions['edit_type']=='optical-band'):    
+            str_config_messages=delete_optical_band(resources)
+        else :
+            str_config_messages=disable_media_channel(resources)
+
     for str_config_message in str_config_messages:  
-            # configuration of the received templates 
-            if str_config_message is None: raise UnsupportedResourceKeyException("CONFIG")
-        
-            netconf_handler.edit_config(                                                                               # configure the device
-                config=str_config_message, target=target, default_operation=default_operation,
-                test_option=test_option, error_option=error_option, format=format)
-            if commit_per_rule:
-                netconf_handler.commit()                                                                               # configuration commit
-        
+        # configuration of the received templates 
+        if str_config_message is None: raise UnsupportedResourceKeyException("CONFIG")
+        result= netconf_handler.edit_config(                                                                               # configure the device
+            config=str_config_message, target=target, default_operation=default_operation,
+            test_option=test_option, error_option=error_option, format=format)
+        if commit_per_rule:
+            netconf_handler.commit()                                                                               # configuration commit
+
         #results[i] = True
-    results.append(True)
-   
+            results.append(result)
+
+    return results         
 
 class OCDriver(_Driver):
     def __init__(self, address : str, port : int,device_uuid=None, **settings) -> None:
         super().__init__(DRIVER_NAME, address, port, **settings)
         self.__logger = logging.getLogger('{:s}:[{:s}:{:s}]'.format(str(__name__), str(self.address), str(self.port)))
         self.__lock = threading.Lock()
-        #self.__initial = TreeNode('.')
-        #self.__running = TreeNode('.')
-        self.__subscriptions = TreeNode('.')
+
         self.__started = threading.Event()
         self.__terminate = threading.Event()
-        self.__scheduler = BackgroundScheduler(daemon=True) # scheduler used to emulate sampling events
+        self.__scheduler = BackgroundScheduler(daemon=True)
         self.__scheduler.configure(
             jobstores = {'default': MemoryJobStore()},
-            executors = {'default': ThreadPoolExecutor(max_workers=1)}, # important! 1 = avoid concurrent requests
+            executors = {'default': ThreadPoolExecutor(max_workers=1)}, 
             job_defaults = {'coalesce': False, 'max_instances': 3},
             timezone=pytz.utc)
         self._temp_address=f"{address}{port}"
-        self.__out_samples = queue.Queue()
+       
         self.__netconf_handler = NetconfSessionHandler(self.address, self.port, **(self.settings))
-      
-        self.__device_uuid=device_uuid
-      
+        self.__type = self.settings.get("type","optical-transponder")
+        self.__device_uuid = device_uuid
         self.Connect()
-        #self.GetConfig()
-        #self.__samples_cache = SamplesCache(self.__netconf_handler, self.__logger)
-
+        
     def Connect(self) -> bool:
         with self.__lock:
             if self.__started.is_set(): return True
             self.__netconf_handler.connect()
-            # Connect triggers activation of sampling events that will be scheduled based on subscriptions
             self.__scheduler.start()
             self.__started.set()
             return True
 
     def Disconnect(self) -> bool:
         with self.__lock:
-            # Trigger termination of loops and processes
             self.__terminate.set()
-            # If not started, assume it is already disconnected
             if not self.__started.is_set(): return True
-            # Disconnect triggers deactivation of sampling events
             self.__scheduler.shutdown()
             self.__netconf_handler.disconnect()
             return True
@@ -238,78 +239,90 @@ class OCDriver(_Driver):
 
     @metered_subclass_method(METRICS_POOL)
     def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]:
-   
-       
         chk_type('resources', resource_keys, list)
         results = []
         opticalConfig= OpticalConfig()
-        j=0
-        
+
         with self.__lock:
-           
-     
-            context_client.connect()
-            config={}
-            channels_lst=[]
-            transceivers={}
-          
+            config = {}
+            transceivers = {}
+            oc_values = {}
+            ports_result = []
+            oc_values["type"] = self.__type
             try:
                 xml_data = self.__netconf_handler.get().data_xml
-                transceivers,interfaces,channels_lst,channel_namespace,endpoints=extractor(data_xml=xml_data,resource_keys=filter_fields,dic=config)     
-                            
-         
+                if self.__type == "optical-transponder":
+                    extracted_values = transponder_values_extractor(
+                        data_xml=xml_data, resource_keys=transponder_filter_fields, dic=config
+                    )
+                    transceivers, optical_channels_params, channel_namespace, endpoints, ports_result = extracted_values
+                    oc_values["channels"] = optical_channels_params
+                    oc_values["transceivers"] = transceivers     
+                    oc_values["channel_namespace"] = channel_namespace
+                    oc_values["endpoints"] = endpoints
+                    oc_values["ports"] = ports_result
+                elif (self.__type =='openroadm'):
+                   extracted_values=openroadm_values_extractor(data_xml=xml_data, resource_keys=[], dic=oc_values)
+                   ports_result = extracted_values[1]
+                else:
+                    extracted_values = roadm_values_extractor(data_xml=xml_data, resource_keys=[], dic=config)
+                    ports_result = extracted_values[0]
+                    oc_values['optical_bands']=extracted_values[1]
+                    oc_values['media_channels']=extracted_values[2]
+
+                #results.append((resource_key, e)) # if validation fails, store the exception    
+
+            #///////////////////////// store optical configurtaion  ////////////////////////////////////////////////////////
+
+                opticalConfig.config=json.dumps(oc_values)
+                if self.__device_uuid is not None:
+                    opticalConfig.device_id.device_uuid.uuid=self.__device_uuid
+                results.append((f"/opticalconfigs/opticalconfig/{self.__device_uuid}",{"opticalconfig":opticalConfig}))
+                # context_client.connect()    
+                # config_id=context_client.SetOpticalConfig(opticalConfig)
+                # context_client.close()
             except Exception as e: # pylint: disable=broad-except
-                        MSG = 'Exception retrieving {:s}'
-                        self.__logger.info("error from getConfig %s",e)
-                        self.__logger.exception(MSG.format(e))
-                        #results.append((resource_key, e)) # if validation fails, store the exception    
-          
-          #///////////////////////// divider ////////////////////////////////////////////////////////
-            
-            
-            value_dic={}
-            value_dic["channels"]=channels_lst
-            value_dic["transceivers"]=transceivers  
-            value_dic["interfaces"]=interfaces        
-            value_dic["channel_namespace"]=channel_namespace
-            value_dic["endpoints"]=endpoints
-           
-            opticalConfig.config=json.dumps(value_dic)
-            opticalConfig.opticalconfig_id.opticalconfig_uuid=self.__device_uuid if self.__device_uuid is not None else ""
-            config_id=context_client.SetOpticalConfig(opticalConfig)
-           
-            context_client.close()   
-                
+                MSG = 'Exception retrieving {:s}'
+                self.__logger.info("error from getConfig %s",e)
+                self.__logger.exception(MSG.format(e))
+
+        if len(ports_result) > 0: results.extend(ports_result)
         return results
 
     @metered_subclass_method(METRICS_POOL)
     def SetConfig(self, resources : List[Tuple[str, Any]],conditions:dict) -> List[Union[bool, Exception]]:
         if len(resources) == 0: return []
-        results=[]
+        results = []
         with self.__lock:
-             if self.__netconf_handler.use_candidate:
-                 with self.__netconf_handler.locked(target='candidate'):
-                     results = edit_config(
-                         self.__netconf_handler, self.__logger, resources,conditions, target='candidate',
-                         commit_per_rule=self.__netconf_handler.commit_per_rule
-                         ,)
-             else:
-                 results = edit_config(self.__netconf_handler, self.__logger, resources,conditions=conditions
-                                    )
+            if self.__netconf_handler.use_candidate:
+                with self.__netconf_handler.locked(target='candidate'):
+                    results = edit_config(
+                        self.__netconf_handler, self.__logger, resources, conditions, target='candidate',
+                        commit_per_rule=self.__netconf_handler.commit_per_rule
+                    )
+            else:
+                results = edit_config(
+                    self.__netconf_handler, self.__logger, resources, conditions=conditions
+                )
         return results
 
     @metered_subclass_method(METRICS_POOL)
-    def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+    def DeleteConfig(
+        self, resources : List[Tuple[str, Any]], conditions : dict,
+        optical_device_configuration = None
+    ) -> List[Union[bool, Exception]]:
         chk_type('resources', resources, list)
         if len(resources) == 0: return []
+
         with self.__lock:
             if self.__netconf_handler.use_candidate:
                 with self.__netconf_handler.locked(target='candidate'):
                     results = edit_config(
                         self.__netconf_handler, self.__logger, resources, target='candidate', delete=True,
-                        commit_per_rule=self.__netconf_handler.commit_per_rule)
+                        commit_per_rule=self.__netconf_handler.commit_per_rule, conditions=conditions
+                    )
             else:
-                results = edit_config(self.__netconf_handler, self.__logger, resources, delete=True)
+                results = edit_config(
+                    self.__netconf_handler, self.__logger, resources, delete=True, conditions=conditions
+                )
         return results
-
-  
diff --git a/src/device/service/drivers/oc_driver/templates/Interfaces/interfaces.py b/src/device/service/drivers/oc_driver/templates/Interfaces/interfaces.py
index 87ba8835ac6f7ad66a709be90195e6597bc2bf6c..b8c3812f292270b63dbe1391d922cbd989415458 100644
--- a/src/device/service/drivers/oc_driver/templates/Interfaces/interfaces.py
+++ b/src/device/service/drivers/oc_driver/templates/Interfaces/interfaces.py
@@ -14,6 +14,7 @@
 
 from yattag import Doc, indent
 import logging
+
 def interface_template (interface_data:dict) :
     data={"name":"eth0","ip":"192.168.1.1","prefix-length":'24'}
     doc, tag, text = Doc().tagtext()
@@ -31,13 +32,10 @@ def interface_template (interface_data:dict) :
                             with tag('config'):
                                 with tag('ip'):text(interface_data["ip"])
                                 with tag('prefix-length'):text(interface_data["prefix-length"])
-                            
+
     result = indent(
                 doc.getvalue(),
                 indentation = ' '*2,
                 newline = '\r\n'
             )        
-    logging.info("interfaces %s",result)
-    return result           
-                    
-                    
\ No newline at end of file
+    return result
diff --git a/src/device/service/drivers/oc_driver/templates/Tools.py b/src/device/service/drivers/oc_driver/templates/Tools.py
index 98086adf7bcc1877ca719fec6ef3f7b9dc890941..92607aca88c1581218c97484c7dfcc87831b5912 100644
--- a/src/device/service/drivers/oc_driver/templates/Tools.py
+++ b/src/device/service/drivers/oc_driver/templates/Tools.py
@@ -19,6 +19,7 @@ from typing import Collection, Dict, Any
 
 from yattag import Doc, indent
 from .VPN.physical import create_optical_channel
+
 def add_value_from_tag(target : Dict, field_name: str, field_value : ET.Element, cast=None) -> None:
     if isinstance(field_value,str) or field_value is None or field_value.text is None: return
     field_value = field_value.text
@@ -55,9 +56,32 @@ def generate_templates(resource_key: str, resource_value: str, channel:str) -> s
     data['name']=channel
     data['resource_key']=resource_key
     data['value']=resource_value
-    result_templates.append(create_physical_config(data))
+    #result_templates.append(create_physical_config(data))
 
     return result_templates
+
+
+def extract_status (dic:dict,resource_key:str,xml_data:str,channel_name:str):
+    
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    channel_name=channel_name if 'index'  not in channel_name else channel_name['index']
+    index=None
+    if channel_name.find('-') != -1 :
+        index= channel_name.split("-")[1]
+    
+   
+    namespaces = { "td": "http://openconfig.net/yang/terminal-device"}
+    channels  = root.findall(f".//td:terminal-device/td:logical-channels/td:channel",namespaces) 
+    for channel in channels : 
+       
+        index_ele= channel.find(f".//td:config[td:index='{index}']/td:{resource_key}",namespaces)
+        if index_ele is not None :
+           dic["status"]=index_ele.text
+           print(index_ele.text)
+    return dic
+
+
 def extract_channel_xmlns (data_xml:str,is_opticalband:bool):
     xml_bytes = data_xml.encode("utf-8")
     root = ET.fromstring(xml_bytes) 
@@ -88,6 +112,7 @@ def extract_channel_xmlns (data_xml:str,is_opticalband:bool):
         
    
     return namespace
+  
 def extract_channels_based_on_channelnamespace (xml_data:str,channel_namespace:str,is_opticalband:bool):
     xml_bytes = xml_data.encode("utf-8")
     root = ET.fromstring(xml_bytes)
@@ -122,6 +147,7 @@ def extract_channels_based_on_channelnamespace (xml_data:str,channel_namespace:s
         # Retrieve port-name for dest
 
     return channels
+  
 def extract_channels_based_on_type (xml_data:str):
     xml_bytes = xml_data.encode("utf-8")
     root = ET.fromstring(xml_bytes)
@@ -140,9 +166,10 @@ def extract_channels_based_on_type (xml_data:str):
     return channel_names            
     
 def extract_value(resource_key:str,xml_data:str,dic:dict,channel_name:str,channel_namespace:str):
+ 
     xml_bytes = xml_data.encode("utf-8")
     root = ET.fromstring(xml_bytes)
-
+    channel_name=channel_name if 'index'  not in channel_name else channel_name['index']
     namespace = {'oc': 'http://openconfig.net/yang/platform',
               'td': channel_namespace}
 
@@ -153,10 +180,13 @@ def extract_value(resource_key:str,xml_data:str,dic:dict,channel_name:str,channe
       if (parameter is not None):
         value = parameter.text
         dic[resource_key]=value
+      else :
+           logging.info("parameter is None")    
       
     else:
+       logging.info("element is None")     
        print(" element not found.")
-       
+  
     return dic  
 
 
@@ -192,6 +222,7 @@ def extract_tranceiver (data_xml:str,dic:dict):
     component_names = [component.text for component in transceiver_components]
     dic['transceiver']=component_names
     return dic
+  
 def extract_interface (xml_data:str,dic:dict):
     xml_bytes = xml_data.encode("utf-8")
     root = ET.fromstring(xml_bytes)
@@ -214,6 +245,7 @@ def extract_interface (xml_data:str,dic:dict):
     else :
         dic['interface']={}   
     return dic
+  
 def has_opticalbands(xml_data:str):
     xml_bytes = xml_data.encode("utf-8")
     root = ET.fromstring(xml_bytes)
@@ -226,32 +258,237 @@ def has_opticalbands(xml_data:str):
     else :
       has_opticalbands=False
     return has_opticalbands
+  
+def extract_ports_based_on_type (xml_data:str):
+    pattern = r':\s*PORT\b'
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    namespace = {'oc': 'http://openconfig.net/yang/platform', 'typex': 'http://openconfig.net/yang/platform-types'}
+    ports = []
+    components = root.findall(".//oc:state[oc:type]",namespace)
+    for component in components:
+         type_ele = component.find(".//oc:type",namespace)
+         match = re.search(pattern, type_ele.text)
+         if match is not None :
+            name_element= component.find(".//oc:name",namespace)
+            port_name =name_element.text       
+            port_index=name_element.text.split("-")[1]
+            port = (port_name,port_index)
+            ports.append(port)
+    return ports  
     
-def extractor(data_xml:str,resource_keys:list,dic:dict):
+def transponder_values_extractor(data_xml:str,resource_keys:list,dic:dict):
    
     endpoints=[]
     is_opticalband=has_opticalbands(xml_data=data_xml)
-   
     channel_namespace=extract_channel_xmlns(data_xml=data_xml,is_opticalband=is_opticalband)
     # channel_names=extract_channels_based_on_type(xml_data=data_xml) 
     # if len(channel_names)==0 :
     channel_names= extract_channels_based_on_channelnamespace(xml_data=data_xml,channel_namespace=channel_namespace,is_opticalband=is_opticalband)
-   
-    lst_dic=[]
+    ports = extract_ports_based_on_type(data_xml)
+    optical_channels_params=[]
+    ports_result=[]
     if (is_opticalband):
         endpoints=channel_names
     else:
             
         for channel_name in channel_names:
             dic={}
-            for resource_key in resource_keys :
+            for resource_key in resource_keys  :
                 
-                if (resource_key != 'interface'):
-                    dic=extract_value(dic=dic,resource_key=resource_key,xml_data=data_xml,channel_name=channel_name,channel_namespace=channel_namespace)  
+                if (resource_key != 'admin-state'):
+                  
+                    dic=extract_value(dic=dic,resource_key=resource_key,xml_data=data_xml
+                                      ,channel_name=channel_name,channel_namespace=channel_namespace)  
+                else : 
+                    dic = extract_status(dic=dic,resource_key=resource_key,xml_data=data_xml, channel_name=channel_name) 
             dic["name"]=channel_name
             endpoints.append({"endpoint_uuid":{"uuid":channel_name}})
-            lst_dic.append(dic)                
-    transceivers_dic=extract_tranceiver(data_xml=data_xml,dic={})
-    interfaces_dic=extract_interface(xml_data=data_xml,dic={})
+            optical_channels_params.append(dic)                
+    #transceivers_dic=extract_tranceiver(data_xml=data_xml,dic={})
+    transceivers_dic={"transceiver":[]}
+    #interfaces_dic=extract_interface(xml_data=data_xml,dic={})
+    if len(ports)>0 :
+      for port in ports :
+        endpoint_name,endpoint_id=port
+        resource_key = '/endpoints/endpoint[{:s}]'.format(endpoint_id)
+        resource_value = {'uuid': endpoint_id, 'type':endpoint_name}
+        ports_result.append((resource_key, resource_value))
+      
+   
+    return [transceivers_dic,optical_channels_params,channel_namespace,endpoints,ports_result]
+  
+#########################################################################  
+  
+#################################### ROADMAs ############################
+  
+##########################################################################  
+
+def extract_roadm_ports (xml_data:str):
+  
+    ports =[]
+    pattern1 = r'\bMG_ON_OPTICAL_PORT_WAVEBAND\b'
+    pattern2 = r'\bMG_ON_OPTICAL_PORT_MEDIACHANNEL\b'
+    pattern3 = r'\bINPUT\b'
+    pattern4 = r'\bOUTPUT\b'
+    
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    with open('xml.log', 'w') as f:
+         print(xml_bytes, file=f)
+    
+
+    namespace = {'oc': 'http://openconfig.net/yang/platform'}
+    ports_wb_in = []
+    ports_mc_in = []
+    ports_wb_out = []
+    ports_mc_out = []
+    components = root.findall('.//oc:component',namespace)
+    print(f"component {components}")
+    
+    
+    for component  in components:
+       
+        properties = component.find(".//oc:properties",namespace)
+        name_element= component.find(".//oc:name",namespace)
+        print(name_element.text)
+        if (properties is not None):
+            wb_x = 0
+            mc_x = 0
+            in_x = 0
+            out_x = 0
+            for property in properties :
+                value = property.find(".//oc:value",namespace)
+                if (re.search(pattern1,value.text)):
+                    wb_x = 1
+                elif (re.search(pattern2,value.text)):
+                    mc_x = 1
+                elif (re.search(pattern3,value.text)):
+                    in_x = 1
+                elif (re.search(pattern4,value.text)):
+                    out_x = 1
+            if wb_x == 1:
+                if in_x ==1:
+                    ports_wb_in.append(name_element.text)
+                elif out_x == 1:
+                    ports_wb_out.append(name_element.text)
+            if mc_x == 1:
+                if in_x ==1:
+                    ports_mc_in.append(name_element.text)
+                elif out_x == 1:
+                    ports_mc_out.append(name_element.text)
+            
+    return ports_wb_in, ports_wb_out, ports_mc_in, ports_mc_out                
+
+
+  
+def roadm_values_extractor (data_xml:str,resource_keys:list,dic:dict):
+    ports_result=[]
+    ports_wb_in, ports_wb_out, ports_mc_in, ports_mc_out = extract_roadm_ports(data_xml)
+     
+    #if len(ports)>0 :
+    #    for port in ports :
+    #    
+    #        resource_key = '/endpoints/endpoint[{:s}]'.format(port)
+    #        resource_value = {'uuid': port, 'type':'MG_ON_OPTICAL_PORT_WAVEBAND'}
+    #        ports_result.append((resource_key, resource_value))
+    if len(ports_wb_in)>0 :
+        for port in ports_wb_in:
+        
+            resource_key = '/endpoints/endpoint[{:s}]'.format(port)
+            resource_value = {'uuid': port, 'type':'MG_ON_OPTICAL_PORT_WAVEBAND'}
+            ports_result.append((resource_key, resource_value))
+      
+    return [ports_result]   
+ 
+ 
+ 
+ #/////////////// OpenRoadm //////////////
+ 
+ 
+def extract_roadm_circuits_pack (xml_data:str):
+  
    
-    return [transceivers_dic,interfaces_dic,lst_dic,channel_namespace,endpoints]
\ No newline at end of file
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    # with open('xml.log', 'w') as f:
+    #      print(xml_bytes, file=f)
+    
+    
+    namespace = {'oc': "http://org/openroadm/device"}
+    
+    circuits = root.findall('.//oc:circuit-packs',namespace)
+  
+    circuits_list =[]
+    # print(f"component {components}")
+    
+    if (circuits is not None):
+        circuit_info ={}
+        for circuit  in circuits:
+        
+            circuit_name = circuit.find(".//oc:circuit-pack-name",namespace)
+            circuit_type=circuit.find(".//oc:circuit-pack-type",namespace)
+            circuit_adminstrative_status=circuit.find(".//oc:administrative-state",namespace)
+            circuit_equipment_state=circuit.find("./oc:equipment-state",namespace)
+            circuit_mode=circuit.find("./oc:circuit-pack-mode",namespace)
+            slot= circuit.find("./oc:slot",namespace)
+            shelf= circuit.find("./oc:shelf",namespace)
+            ports = circuit.findall("./oc:ports",namespace)
+           
+            circuit_ports=[]
+            if (ports is not None):
+                
+                for port in ports :
+                    port_info={}
+                    port_name=port.find('./oc:port-name',namespace)
+                    port_qual= port.find("./oc:port-qual",namespace)
+                   
+                    if port_name is not None :
+                        port_info["port_name"]=port_name.text
+                    if port_qual is not None :
+                        port_info["port_qual"]=port_qual.text
+                    circuit_ports.append(port_info)            
+            if (circuit_name is not None):
+                circuit_info["circuit_name"]=circuit_name.text
+            if (circuit_type is not None):
+                circuit_info["circuit_type"]=circuit_type.text
+            if (circuit_adminstrative_status is not None):
+                circuit_info["circuit_adminstrative_status"]=circuit_adminstrative_status.text
+            if (circuit_equipment_state is not None):
+                circuit_info["circuit_equipment_state"]=circuit_equipment_state.text
+            if (circuit_mode is not None):
+                circuit_info["circuit_mode"]=circuit_mode.text
+            if (slot is not None):
+                circuit_info["slot"]=slot.text
+            if (shelf is not None):
+                circuit_info["shelf"]=shelf.text
+            circuit_info["ports"]=circuit_ports 
+                                   
+            circuits_list.append(circuit_info)   
+          
+        
+    return circuits_list                
+
+
+
+def extract_openroadm_info(xml_data:str):
+    roadm_info={"node-id":None,"node-number":None,"node-type":None,'clli':None}
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    namespace = {'oc': "http://org/openroadm/device"}
+    info = root.findall('.//oc:info',namespace)
+    if info is not None :
+        for i in info :
+            node_id= i.find('.//oc:node-id',namespace)
+            node_number= i.find('.//oc:node-number',namespace)
+            node_type=i.find('.//oc:node-type',namespace)
+            clli=i.find('.//oc:clli',namespace)
+            if (node_id is not None):
+                roadm_info['node-id']=node_id.text
+            if (node_number is not None):
+                roadm_info['node-number']=node_number.text
+            if (node_type is not None):
+                roadm_info['node-type']=node_type.text
+            if (clli is not None):
+                roadm_info['clli']=clli.text
+    return roadm_info                    
diff --git a/src/device/service/drivers/oc_driver/templates/VPN/common.py b/src/device/service/drivers/oc_driver/templates/VPN/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..d84afc5563ad9cf1fbc7fda44800b90876ee302e
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/VPN/common.py
@@ -0,0 +1,55 @@
+# 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.
+
+
+def seperate_port_config(resources:list,unwanted_keys=[])->list[list,dict,str]:
+    config=[]
+    ports={}
+    index=None
+    for item in resources :
+        if len(unwanted_keys)>0:
+            if (item['value'] is not None and (item['resource_key']  not in unwanted_keys)):
+                config.append({'resource_key':item['resource_key'], 'value':item['value']} )
+        #if (item['resource_key'] == 'destination_port' or item['resource_key'] == 'source_port') and item['value'] is not None:
+        #     ports[item['resource_key']]=item['value']
+        if (item['resource_key'] == 'destination_port' or item['resource_key'] == 'source_port'):
+            ports[item['resource_key']]=item['value']
+        if (item['resource_key']=='index' and item['value'] is not None)     :
+            index=item['value']
+      
+    return [config,ports,index]
+
+def extract_ports (resources:list):
+    if len(resources) ==0 :return 
+    ports=[]
+    flow=next((i for i in resources if i['resource_key']=='handled_flow'),None)
+    if flow is not None:
+        ports = flow['value']
+    return ports 
+
+def filter_config(resources:list,unwanted_keys=[])->list[list,dict,str]:
+    config=[]
+    ports=()
+    index=None
+    for item in resources :
+        if len(unwanted_keys)>0:
+            if (item['value'] is not None and (item['resource_key']  not in unwanted_keys)):
+                config.append({'resource_key':item['resource_key'], 'value':item['value']} )
+        if (item['resource_key']=='index' and item['value'] is not None)     :
+            index=item['value']        
+        #if (item['resource_key'] == 'destination_port' or item['resource_key'] == 'source_port') and item['value'] is not None:
+        #     ports[item['resource_key']]=item['value']
+    ports = extract_ports(resources=resources)
+      
+    return [config,ports,index]
diff --git a/src/device/service/drivers/oc_driver/templates/VPN/physical.py b/src/device/service/drivers/oc_driver/templates/VPN/physical.py
index 0db6ffa5065ad3013250c3bde4dd160d8c12a498..11e6df5d99f8d365eeaeec3960da52f28c717551 100644
--- a/src/device/service/drivers/oc_driver/templates/VPN/physical.py
+++ b/src/device/service/drivers/oc_driver/templates/VPN/physical.py
@@ -34,14 +34,14 @@ def seperate_port_config(resources:list,unwanted_keys:list[str])->list[list,dict
     return [config,ports,index]
 
 
-def create_optical_channel(resources):
+def create_optical_channel(resources:list[dict],ports:list[dict],config:list[dict] ):
   
-    unwanted_keys=['destination_port','source_port','channel_namespace','optical-band-parent','index', 'name']
+    #unwanted_keys=['destination_port','source_port','channel_namespace','optical-band-parent','index', 'name','admin-state']
     results =[]
-    data={"name":i["value"] for i in resources if i["resource_key"]=="channel_name"}
+    data ={}
     data["channel_namespace"]=next((i["value"] for i in resources if i["resource_key"] == "channel_namespace"), None)
-    config,ports,index=seperate_port_config(resources,unwanted_keys=unwanted_keys)
-    
+    #config,ports,index=seperate_port_config(resources,unwanted_keys=unwanted_keys)
+
     port_val = ""
     if 'destination_port' in ports and ports['destination_port'][0] is not None:
         port_val = ports['destination_port'][0]
@@ -57,10 +57,18 @@ def create_optical_channel(resources):
                 with tag('name'):text("channel-{}".format(port_val))
                 with tag('config'):
                     with tag('name'):text("channel-{}".format(port_val))
-                with tag('optical-channel',xmlns=data["channel_namespace"]):
+                #with tag('optical-channel', xmlns="http://example.com/flexscale-terminal-device"):
+                with tag('optical-channel', xmlns=data["channel_namespace"]):
                     with tag('config'):
                         for resource in config:
                             with tag(resource['resource_key']):text(resource['value'])
+    #    with tag('terminal-device', xmlns="http://openconfig.net/yang/terminal-device"):
+    #        with tag('logical-channels'):
+    #            with tag('channel'):
+    #                with tag('index'):text("{}".format(port_val))
+    #                with tag('config'):
+    #                    with tag('index'):text("{}".format(port_val))
+    #                    with tag('admin-state'):text("ENABLED")
     result = indent(
         doc.getvalue(),
         indentation = ' '*2,
@@ -119,6 +127,7 @@ def create_optical_band (resources) :
     results =[]
     unwanted_keys=['destination_port','source_port','channel_namespace','frequency','optical-band-parent']
     config,ports,index= seperate_port_config(resources,unwanted_keys=unwanted_keys)
+  
     doc, tag, text = Doc().tagtext()
     #with tag('config'):
     with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
@@ -166,6 +175,7 @@ def create_media_channel (resources):
         results=[]
         unwanted_keys=['destination_port','source_port','channel_namespace','frequency','operational-mode', 'optical-band-parent']
         config,ports,index= seperate_port_config(resources,unwanted_keys=unwanted_keys)
+    
         doc, tag, text = Doc().tagtext()
         #with tag('config'):
         with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
@@ -206,5 +216,49 @@ def create_media_channel (resources):
         results.append(result)
         return results
              
-                
-     
\ No newline at end of file
+
+def change_optical_channel_status (channel_name:str,state:str,ports:list[dict]) :
+    port_val=""
+    if 'destination_port' in ports and ports['destination_port'][0] is not None:
+        port_val = ports['destination_port'][0]
+    else:
+        port_val = ports['source_port'][0]
+
+    results=[]
+    doc, tag, text = Doc().tagtext()
+    #with tag('config'):
+    with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+      
+        with tag('terminal-device',xmlns="http://openconfig.net/yang/terminal-device"):
+            with tag("logical-channels"):
+                with tag('channel'):
+                    with tag('index'):text("{}".format(port_val))
+                    with tag('config'):
+                        with tag('admin-state'):text("{}".format(state))
+                       
+    result = indent(
+        doc.getvalue(),
+        indentation = ' '*2,
+        newline = ''
+    )
+    results.append(result)
+
+
+    return results
+
+
+def edit_optical_channel (resources:list[dict]):
+    unwanted_keys=['destination_port','source_port','channel_namespace','optical-band-parent','index', 'name','admin-state']
+    config,ports,index=seperate_port_config(resources,unwanted_keys=unwanted_keys)
+    results = []
+    channel_name=next((i["value"] for i in resources if i["resource_key"]=="channel_name" and i["value"] != None),None)
+    admin_state= next((i["value"] for i in resources if i["resource_key"]== "admin-state" and i["value"] != None) , None)
+    
+ 
+    if channel_name is not None :
+        if (admin_state is not None):
+            results.extend(change_optical_channel_status(channel_name=channel_name,state=admin_state,ports=ports))
+    if admin_state is None :        
+        results.extend(create_optical_channel(resources=resources,ports=ports,config=config)  )
+    
+    return results
diff --git a/src/device/service/drivers/oc_driver/templates/VPN/roadms.py b/src/device/service/drivers/oc_driver/templates/VPN/roadms.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e076588cc160cf22d773476119f8e91001a5053
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/VPN/roadms.py
@@ -0,0 +1,357 @@
+# 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 yattag import Doc, indent
+import logging
+from .common  import seperate_port_config ,filter_config
+
+
+
+
+def create_media_channel_old (resources):
+        optical_band_namespaces="http://flex-scale-project.eu/yang/flex-scale-mg-on"
+        results=[]
+        unwanted_keys=['destination_port','source_port','channel_namespace'
+                       ,'frequency','operational-mode','target-output-power',
+                       "admin-state","flow_handled","channel_num"]
+        config,ports,index= seperate_port_config(resources,unwanted_keys=unwanted_keys)
+        
+
+        doc, tag, text = Doc().tagtext()
+        #with tag('config'):
+        with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+            with tag('wavelength-router', xmlns="http://openconfig.net/yang/wavelength-router"):
+                with tag('media-channels'):
+                    n = 0
+                    if 'destination_port' in ports:
+                        n = len(ports['destination_port'])
+                    else:
+                        n = len(ports['source_port'])
+                    for i in range(0, n):
+                        #with tag('channel', operation="create"):
+                        with tag('channel'):
+                            with tag('index'):text(str(int(index)+i))
+                            with tag('config'):
+                                #with tag('index'):text(index)
+                                for resource in config:
+                                   
+                                    if resource['resource_key'] == "index":
+                                        with tag('index'):text(str(int(index)+i))
+                                    elif resource['resource_key']== 'optical-band-parent'    :
+                                        with tag('optical-band-parent',xmlns=optical_band_namespaces):text(resource['value'])
+                                    else:
+                                        with tag(resource['resource_key']):text(resource['value'])
+                            if ('destination_port' in ports) and (ports['destination_port'][i] is not None):         
+                                with tag('dest'):
+                                    with tag('config'):  
+                                        with tag('port-name'):text(ports['destination_port'][i])   
+                            if ('source_port' in ports) and (ports['source_port'][i] is not None):                    
+                                with tag('source'):
+                                        with tag('config'):  
+                                            with tag('port-name'):text(ports['source_port'][i])     
+                            
+                            
+        result = indent(
+                    doc.getvalue(),
+                    indentation = ' '*2,
+                    newline = ''
+                )
+        results.append(result)
+        return results
+             
+ 
+ 
+ 
+def create_media_channel (resources):
+        optical_band_namespaces="http://flex-scale-project.eu/yang/flex-scale-mg-on"
+        results=[]
+        unwanted_keys=['destination_port','source_port','channel_namespace'
+                       ,'frequency','operational-mode','target-output-power',
+                       "admin-state","handled_flow","channel_num"]
+      
+        config,ports,index=filter_config(resources,unwanted_keys)
+
+        doc, tag, text = Doc().tagtext()
+        #with tag('config'):
+        with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+            with tag('wavelength-router', xmlns="http://openconfig.net/yang/wavelength-router"):
+                with tag('media-channels'):
+                    n = 0
+                 
+                    for flow in ports:
+                        src,dest=flow
+                        #with tag('channel', operation="create"):
+                        with tag('channel'):
+                            with tag('index'):text(str(int(index)+n))
+                            with tag('config'):
+                                #with tag('index'):text(index)
+                                for resource in config:
+                                   
+                                    if resource['resource_key'] == "index":
+                                        with tag('index'):text(str(int(index)+n))
+                                    elif resource['resource_key']== 'optical-band-parent'    :
+                                        with tag('optical-band-parent',xmlns=optical_band_namespaces):text(resource['value'])
+                                    else:
+                                        with tag(resource['resource_key']):text(resource['value'])
+                            if dest is not None and dest != '0':         
+                                with tag('dest'):
+                                    with tag('config'):  
+                                        with tag('port-name'):text(dest)   
+                            if src is not None and src != '0':                    
+                                with tag('source'):
+                                        with tag('config'):  
+                                            with tag('port-name'):text(src)     
+                        n+=1    
+                            
+        result = indent(
+                    doc.getvalue(),
+                    indentation = ' '*2,
+                    newline = ''
+                )
+        results.append(result)
+        return results
+             
+                
+ 
+
+         
+def create_media_channel_v2 (resources):
+    optical_band_namespaces="http://flex-scale-project.eu/yang/flex-scale-mg-on"
+    results=[]
+    unwanted_keys=['destination_port','source_port','channel_namespace'
+                ,'frequency','operational-mode','target-output-power',
+               "handled_flow","channel_num"]
+
+    config,ports,index=filter_config(resources,unwanted_keys)
+
+    n = 0
+    for flow in ports:
+        doc, tag, text = Doc().tagtext()
+        with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+            with tag('wavelength-router', xmlns="http://openconfig.net/yang/wavelength-router"):
+                    with tag('media-channels'):
+                        
+                    
+                            src,dest=flow
+                            with tag('channel', operation="create"):
+                            #with tag('channel'):
+                                with tag('index'):text(str(int(index)+n))
+                                with tag('config'):
+                                    #with tag('index'):text(index)
+                                    for resource in config:
+                                        
+                                        if resource['resource_key'] == "index":
+                                            with tag('index'):text(str(int(index)+n))
+                                        elif resource['resource_key']== 'optical-band-parent'    :
+                                            with tag('optical-band-parent',xmlns=optical_band_namespaces):text(int(resource['value'])+int(n))
+                                        elif resource['resource_key']== 'admin-state'    :
+                                            with tag('admin-status'):text(resource['value'])
+                                        else:
+                                            with tag(resource['resource_key']):text(resource['value'])
+                                    
+                            
+                                if src is not None and src != '0':                    
+                                    with tag('source'):
+                                            with tag('config'):  
+                                                with tag('port-name'):text(src)     
+                                if dest is not None and dest != '0':                    
+                                    with tag('dest'):
+                                            with tag('config'):  
+                                                with tag('port-name'):text(dest)     
+        n+=1    
+                            
+        result = indent(
+                    doc.getvalue(),
+                    indentation = ' '*2,
+                    newline = ''
+                )
+        results.append(result)
+    return results
+        
+                
+
+
+def create_optical_band_old (resources) :
+    results =[]
+    unwanted_keys=['destination_port','source_port','channel_namespace','frequency','optical-band-parent','flow_handled']
+    config,ports,index= seperate_port_config(resources,unwanted_keys=unwanted_keys)
+  
+    doc, tag, text = Doc().tagtext()
+    #with tag('config'):
+    with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+      with tag('wavelength-router', xmlns="http://openconfig.net/yang/wavelength-router"):
+        with tag('optical-bands',xmlns="http://flex-scale-project.eu/yang/flex-scale-mg-on"):
+            n = 0
+            if 'destination_port' in ports:
+                n = len(ports['destination_port'])
+            else:
+                n = len(ports['source_port'])
+            for i in range(0, n):
+                #with tag('optical-band', operation="create"):
+                with tag('optical-band'):
+                    if index is not None:
+                        with tag('index'):text(str(int(index)+i))
+                    with tag('config'):
+                        #if index is not None:
+                        #    with tag('index'):text(str(int(index)+i))
+                        for resource in config:       
+                            if resource['resource_key'] == "index":
+                                with tag('index'):text(str(int(index)+i))
+                            else:
+                                with tag(resource['resource_key']):text(resource['value'])
+                        with tag('admin-status'):text('ENABLED')       
+                        #with tag('fiber-parent'):text(ports['destination_port'] if 'destination_port' in ports else ports['source_port'])       
+                    if ('destination_port' in ports) and (ports['destination_port'][i] is not None):        
+                        with tag('dest'):
+                            with tag('config'):
+                                with tag('port-name'):text(ports['destination_port'][i])
+                    if ('source_port' in ports) and (ports['source_port'][i] is not None):        
+                        with tag('source'):
+                            with tag('config'):  
+                                with tag('port-name'):text(ports['source_port'][i])   
+                            
+                                
+    result = indent(
+                doc.getvalue(),
+                indentation = ' '*2,
+                newline = ''
+            )
+    results.append(result)
+    return results
+
+
+
+
+def create_optical_band (resources) :
+    results =[]
+    unwanted_keys=['destination_port','source_port','channel_namespace','frequency','optical-band-parent','handled_flow']
+    config,ports,index= filter_config(resources,unwanted_keys=unwanted_keys)
+
+    #with tag('config'):
+    n = 0
+    for flow in ports:
+        doc, tag, text = Doc().tagtext()
+        with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+            with tag('wavelength-router', xmlns="http://openconfig.net/yang/wavelength-router"):
+                with tag('optical-bands',xmlns="http://flex-scale-project.eu/yang/flex-scale-mg-on"):
+                   
+                
+                        #with tag('optical-band', operation="create"):
+                        src,dest=flow
+
+                        with tag('optical-band'):
+                            if index is not None:
+                                with tag('index'):text(str(int(index)+n))
+                            with tag('config'):
+                                #if index is not None:
+                                #    with tag('index'):text(str(int(index)+i))
+                                for resource in config:       
+                                    if resource['resource_key'] == "index":
+                                        with tag('index'):text(str(int(index)+n))
+                                    else:
+                                        with tag(resource['resource_key']):text(resource['value'])
+                                with tag('admin-status'):text('ENABLED')       
+                                #with tag('fiber-parent'):text(ports['destination_port'] if 'destination_port' in ports else ports['source_port'])       
+                            if dest is not None and dest != '0':        
+                                with tag('dest'):
+                                    with tag('config'):
+                                        with tag('port-name'):text(dest)
+                            if src is not None and src !='0':        
+                                with tag('source'):
+                                    with tag('config'):  
+                                        with tag('port-name'):text(src)   
+        n +=1                
+                                
+                                
+        result = indent(
+                    doc.getvalue(),
+                    indentation = ' '*2,
+                    newline = ''
+                )
+        results.append(result)
+    return results
+
+
+def disable_media_channel (resources):
+    
+    results=[]
+    unwanted_keys=['destination_port','source_port','channel_namespace','frequency','operational-mode', 'optical-band-parent']
+    config,ports,index= seperate_port_config(resources,unwanted_keys=unwanted_keys)
+    
+    doc, tag, text = Doc().tagtext()
+    #with tag('config'):
+    with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+      with tag('wavelength-router', xmlns="http://openconfig.net/yang/wavelength-router"):
+        with tag('media-channels'):
+            with tag("channel",operation="delete"):
+                with tag('index'):text(str(int(index)))
+                with tag('config'):
+                    with tag('index'):text(str(int(index)))
+                            
+    result = indent(
+                doc.getvalue(),
+                indentation = ' '*2,
+                newline = ''
+            )
+    results.append(result)
+    return results
+                        
+def disable_optical_band (resources:list,state:str):
+    results=[]
+    unwanted_keys=['destination_port','source_port','channel_namespace','frequency','operational-mode', 'optical-band-parent']
+    config,ports,index= seperate_port_config(resources,unwanted_keys=unwanted_keys)
+    doc, tag, text = Doc().tagtext()
+    #with tag('config'):
+    with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+      with tag('wavelength-router', xmlns="http://openconfig.net/yang/wavelength-router"):
+        with tag('optical-bands',xmlns="http://flex-scale-project.eu/yang/flex-scale-mg-on"):
+            with tag('optical-band'):
+                if index is not None:
+                    with tag('index'):text(index)
+                with tag('config'):
+                    with tag('index'):text(index)
+                    with tag('admin-status'):text(state)  
+    result = indent(
+                doc.getvalue(),
+                indentation = ' '*2,
+                newline = ''
+            )
+    results.append(result)
+    return results                          
+
+
+def delete_optical_band (resources:list):
+    results=[]
+    unwanted_keys=['destination_port','source_port','channel_namespace','frequency','operational-mode', 'optical-band-parent']
+    config,ports,index= seperate_port_config(resources,unwanted_keys=unwanted_keys)
+    doc, tag, text = Doc().tagtext()
+    #with tag('config'):
+    with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+      with tag('wavelength-router', xmlns="http://openconfig.net/yang/wavelength-router"):
+        with tag('optical-bands',xmlns="http://flex-scale-project.eu/yang/flex-scale-mg-on"):
+            with tag('optical-band',operation="delete"):
+                if index is not None:
+                    with tag('index'):text(index)
+                with tag('config'):
+                    with tag('index'):text(index)
+                   
+    result = indent(
+                doc.getvalue(),
+                indentation = ' '*2,
+                newline = ''
+            )
+    results.append(result)
+    return results
diff --git a/src/device/service/drivers/oc_driver/templates/VPN/transponder.py b/src/device/service/drivers/oc_driver/templates/VPN/transponder.py
new file mode 100644
index 0000000000000000000000000000000000000000..a41c7e9a0853a371bf1f6d8d343913c52f9365ac
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/VPN/transponder.py
@@ -0,0 +1,157 @@
+# 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 yattag import Doc, indent
+import logging
+
+from .common  import seperate_port_config
+
+def add_transceiver (transceiver_name:str):
+ 
+    doc, tag, text = Doc().tagtext()
+    with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+        with tag('components', xmlns="http://openconfig.net/yang/platform"):
+            with tag('component'):
+                with tag('name'):text(transceiver_name)
+                with tag("config"):
+                    with tag('name'):text(transceiver_name)
+                with tag("state"):
+                    with tag('name'):text(transceiver_name) 
+                    with tag("type",('xmlns:oc-platform-types',"http://openconfig.net/yang/platform-types")):text("oc-platform-types:TRANSCEIVER")
+                with tag("transceiver",xmlns="http://openconfig.net/yang/platform/transceiver"):
+                    with tag("config"):
+                        with tag("enabled"):text("true")
+                        with tag("form-factor-preconf",("xmlns:oc-opt-types","http://openconfig.net/yang/transport-types")):text("oc-opt-types:QSFP56_DD_TYPE1")
+                        with tag("ethernet-pmd-preconf",("xmlns:oc-opt-types","http://openconfig.net/yang/transport-types")):text("oc-opt-types:ETH_400GBASE_ZR")
+                        with tag("fec-mode",("xmlns:oc-platform-types","http://openconfig.net/yang/platform-types")):text("oc-platform-types:FEC_AUTO")
+                        with tag("module-functional-type",("xmlns:oc-opt-types","http://openconfig.net/yang/transport-types")):text("oc-opt-types:TYPE_DIGITAL_COHERENT_OPTIC")
+                    with tag("state"):
+                        with tag("enabled"):text("true")
+                        with tag("form-factor-preconf",("xmlns:oc-opt-types","http://openconfig.net/yang/transport-types")):text("oc-opt-types:QSFP56_DD_TYPE1")
+                        with tag("ethernet-pmd-preconf",("xmlns:oc-opt-types","http://openconfig.net/yang/transport-types")):text("oc-opt-types:ETH_400GBASE_ZR")
+                        with tag("fec-mode",("xmlns:oc-platform-types","http://openconfig.net/yang/platform-types")):text("oc-platform-types:FEC_AUTO")
+                        with tag("module-functional-type",("xmlns:oc-opt-types","http://openconfig.net/yang/transport-types")):text("oc-opt-types:TYPE_DIGITAL_COHERENT_OPTIC")
+                        with tag("vendor"):text("Cisco")
+                        with tag("vendor-part"):text("400zr-QSFP-DD")
+                        with tag("vendor-rev"):text("01")
+                        with tag("serial-no"):text("1567321")
+                    with tag("physical-channels"):
+                        with tag("channel"):
+                            with tag("index"):text("1")
+                            with tag("config"):
+                                with tag("index"):text("1")
+                                with tag("associated-optical-channel"):text("channel-4")    
+    result = indent(
+                doc.getvalue(),
+                indentation = ' '*2,
+                newline = ''
+            )
+         
+   
+    return result               
+    
+
+def create_optical_channel(resources:list[dict],ports:list[dict],config:list[dict] ):
+  
+    #unwanted_keys=['destination_port','source_port','channel_namespace','optical-band-parent','index', 'name','admin-state']
+    results =[]
+    data ={}
+    data["channel_namespace"]=next((i["value"] for i in resources if i["resource_key"] == "channel_namespace"), None)
+    #config,ports,index=seperate_port_config(resources,unwanted_keys=unwanted_keys)
+
+    port_val = ""
+    if 'destination_port' in ports and ports['destination_port'][0] is not None:
+        port_val = ports['destination_port'][0]
+    else:
+        port_val = ports['source_port'][0]
+
+    
+    doc, tag, text = Doc().tagtext()
+    #with tag('config'):
+    with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+        with tag('components', xmlns="http://openconfig.net/yang/platform"):
+            with tag('component'):
+                with tag('name'):text("channel-{}".format(port_val))
+                with tag('config'):
+                    with tag('name'):text("channel-{}".format(port_val))
+                with tag('optical-channel',xmlns=data["channel_namespace"]):
+                    with tag('config'):
+                        for resource in config:
+                            with tag(resource['resource_key']):text(resource['value'])
+        with tag('terminal-device', xmlns="http://openconfig.net/yang/terminal-device"):
+            with tag('logical-channels'):
+                with tag('channel'):
+                    with tag('index'):text("{}".format(port_val))
+                    with tag('config'):
+                        with tag('index'):text("{}".format(port_val))
+                        with tag('admin-state'):text("ENABLED")
+    result = indent(
+        doc.getvalue(),
+        indentation = ' '*2,
+        newline = ''
+    )
+    results.append(result)
+
+
+    return results
+
+
+def change_optical_channel_status (state:str,ports:list[dict]) :
+    port_val=""
+    if 'destination_port' in ports and ports['destination_port'][0] is not None:
+        port_val = ports['destination_port'][0]
+    else:
+        port_val = ports['source_port'][0]
+
+    results=[]
+    doc, tag, text = Doc().tagtext()
+    #with tag('config'):
+    with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+      
+        with tag('terminal-device',xmlns="http://openconfig.net/yang/terminal-device"):
+            with tag("logical-channels"):
+                with tag('channel'):
+                    with tag('index'):text("{}".format(port_val))
+                    with tag('config'):
+                        with tag('admin-state'):text("{}".format(state))
+                       
+    result = indent(
+        doc.getvalue(),
+        indentation = ' '*2,
+        newline = ''
+    )
+    results.append(result)
+
+
+    return results
+
+
+def edit_optical_channel (resources:list[dict]):
+
+    unwanted_keys=['destination_port','source_port','channel_namespace'
+                   ,'optical-band-parent','index', 'name','admin-state','handled_flow']
+    config,ports,index=seperate_port_config(resources,unwanted_keys=unwanted_keys)
+    results = []
+    # channel_name=next((i["value"] for i in resources if i["resource_key"]=="channel_name" and i["value"] != None),None)
+    # admin_state= next((i["value"] for i in resources if i["resource_key"]== "admin-state" and i["value"] != None) , None)
+    
+
+
+    # results.extend(change_optical_channel_status(state=admin_state,ports=ports))
+    # else :    
+
+    results.extend(create_optical_channel(resources=resources,ports=ports,config=config)  )
+    
+    return results
diff --git a/src/device/service/drivers/oc_driver/templates/descovery_tool/roadms.py b/src/device/service/drivers/oc_driver/templates/descovery_tool/roadms.py
new file mode 100644
index 0000000000000000000000000000000000000000..e27fd923a4d3ec4a69b810667545d5bcae235269
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/descovery_tool/roadms.py
@@ -0,0 +1,260 @@
+# 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 re
+import lxml.etree as ET
+
+def extract_channel_xmlns (data_xml:str,is_opticalband:bool):
+    xml_bytes = data_xml.encode("utf-8")
+    root = ET.fromstring(xml_bytes) 
+ 
+    namespace=None
+    channels=None
+  
+    if (not is_opticalband) :
+      
+        optical_channel_namespaces = {
+        'ns': 'urn:ietf:params:xml:ns:netconf:base:1.0',
+          'oc': 'http://openconfig.net/yang/platform',
+        }
+       
+        channels= root.find('.//{*}optical-channel',optical_channel_namespaces)
+        if channels is not None :
+          optical_channel_namespace = channels.tag.replace("optical-channel", "")
+          namespace=optical_channel_namespace.replace("{", "").replace("}", "")
+    else :       
+        optical_band_namespaces= {
+          'oc':'http://openconfig.net/yang/wavelength-router'
+        }
+        
+        channels= root.find('.//{*}optical-bands',optical_band_namespaces)
+        if channels is not None: 
+          optical_channel_namespace = channels.tag.replace("optical-bands", "")
+          namespace=optical_channel_namespace.replace("{", "").replace("}", "")
+    return namespace
+
+def extract_optical_bands (data_xml:str,namespace:str):
+    namespaces={"oc":namespace}
+    xml_bytes = data_xml.encode("utf-8")
+    root = ET.fromstring(xml_bytes) 
+    op_bands=[]
+    optical_bands= root.find('.//oc:optical-bands',namespaces)
+
+    if optical_bands is not None :
+        optical_bands_ele= optical_bands.findall('.//oc:optical-band',namespaces)
+
+        for optical_band in optical_bands_ele:
+            band_ele=optical_band.find('.//oc:name',namespaces)
+            lower_freq_ele=optical_band.find('.//oc:lower-frequency',namespaces)
+            upper_freq_ele=optical_band.find('.//oc:upper-frequency',namespaces)
+            admin_status_ele=optical_band.find('.//oc:admin-status',namespaces)
+            source_ele=optical_band.find('.//oc:source/oc:config/oc:port-name',namespaces)
+            dest_ele=optical_band.find('.//oc:dest/oc:config/oc:port-name',namespaces)
+            channel_index= optical_band.find('.//oc:index',namespaces)
+            op_band_obj={
+                'band_name':band_ele.text if band_ele is not None else None,
+                'lower_frequency':lower_freq_ele.text if lower_freq_ele is not None else None,
+                'upper_frequency':upper_freq_ele.text if upper_freq_ele is not None else None,
+                'status':admin_status_ele.text if admin_status_ele is not None else None,
+                'src_port':source_ele.text if source_ele is not None else None,
+                'dest_port':dest_ele.text if dest_ele is not None else None,
+                "channel_index":channel_index.text if channel_index is not None else None
+            }
+            op_bands.append(op_band_obj)
+        
+    return op_bands
+        
+def extract_media_channels (data_xml:str):
+    optical_band_namespaces="http://flex-scale-project.eu/yang/flex-scale-mg-on"
+    namespaces={"oc":"http://openconfig.net/yang/wavelength-router",'ob_parent':optical_band_namespaces}
+    xml_bytes = data_xml.encode("utf-8")
+    root = ET.fromstring(xml_bytes) 
+    media_channels= root.find(f'.//oc:media-channels',namespaces)
+    op_bands=[]
+    if media_channels is not None :
+        media_channels_ele= media_channels.findall('.//oc:channel',namespaces)
+        for optical_band in media_channels_ele:
+            band_ele=optical_band.find('.//oc:name',namespaces)
+            lower_freq_ele=optical_band.find('.//oc:lower-frequency',namespaces)
+            upper_freq_ele=optical_band.find('.//oc:upper-frequency',namespaces)
+            admin_status_ele=optical_band.find('.//oc:admin-status',namespaces)
+            source_ele=optical_band.find('.//oc:source/oc:config/oc:port-name',namespaces)
+            dest_ele=optical_band.find('.//oc:dest/oc:config/oc:port-name',namespaces)
+            ob_parent=optical_band.find('.//ob_parent:optical-band-parent',namespaces)
+            channel_index= optical_band.find('.//oc:index',namespaces)
+            op_band_obj={
+                'band_name':band_ele.text if band_ele is not None else None,
+                'lower_frequency':lower_freq_ele.text if lower_freq_ele is not None else None,
+                'upper_frequency':upper_freq_ele.text if upper_freq_ele is not None else None,
+                'status':admin_status_ele.text if admin_status_ele is not None else None,
+                'src_port':source_ele.text if source_ele is not None else None,
+                'dest_port':dest_ele.text if dest_ele is not None else None,
+                'optical_band_parent':ob_parent.text if ob_parent is not None else None,
+                'channel_index':channel_index.text if channel_index is not None else None
+            }
+            op_bands.append(op_band_obj)
+
+    return op_bands
+
+def extract_roadm_ports_old (xml_data:str):
+    ports =[]
+    pattern = r'\bMG_ON_OPTICAL_PORT_WAVEBAND\b'
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    with open('xml.log', 'w') as f:
+         print(xml_bytes, file=f)
+
+    namespace = {'oc': 'http://openconfig.net/yang/platform'}
+    ports = []
+    components = root.findall('.//oc:component',namespace)
+    print(f"component {components}")
+
+    for component  in components:
+        properties = component.find(".//oc:properties",namespace)
+        if (properties is not None):
+            for property in properties :
+                value = property.find(".//oc:value",namespace)
+                if (re.search(pattern,value.text)):
+                    name_element= component.find(".//oc:name",namespace)
+                    ports.append(name_element.text)
+    return ports     
+
+def extract_roadm_ports (xml_data:str):
+    ports =[]
+    pattern2=r'\bMG_ON_PORT_TYPE'
+    pattern = r'\bMG_ON_OPTICAL_PORT_WAVEBAND\b'
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+
+    namespace = {'oc': 'http://openconfig.net/yang/platform'}
+    ports = []
+    components = root.findall('.//oc:component',namespace)
+    #print(f"component {components}")
+
+    for component  in components:
+        properties = component.find(".//oc:properties",namespace)
+        if (properties is not None):
+            for property in properties :
+                value = property.find(".//oc:value",namespace)
+                name= property.find('.//oc:name',namespace)
+                if (re.search(pattern2,name.text)):
+                   value = property.find(".//oc:value",namespace)
+                   name_element= component.find(".//oc:name",namespace)
+                   print('value',value.text)
+                   ports.append((name_element.text,value.text))
+    return ports                
+
+def roadm_values_extractor (data_xml:str,resource_keys:list,dic:dict):
+    ports_result=[]
+    ports = extract_roadm_ports(data_xml)
+    namespcae= extract_channel_xmlns(data_xml,True)
+    optical_bands=extract_optical_bands(data_xml=data_xml,namespace=namespcae)
+    media_cahannels=extract_media_channels(data_xml)
+    if len(ports)>0 :
+        for port in ports :
+            name,type=port
+            resource_key = '/endpoints/endpoint[{:s}]'.format(name)
+            resource_value = {'uuid': name, 'type':type}
+            ports_result.append((resource_key, resource_value))
+    return [ports_result,optical_bands,media_cahannels]   
+
+#/////////////// OpenRoadm //////////////
+
+def extract_roadm_circuits_pack (xml_data:str):
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    # with open('xml.log', 'w') as f:
+    #      print(xml_bytes, file=f)
+
+    namespace = {'oc': "http://org/openroadm/device"}
+    circuits = root.findall('.//oc:circuit-packs',namespace)
+    circuits_list =[]
+    # print(f"component {components}")
+    if (circuits is not None):
+        for circuit  in circuits:
+            circuit_info ={}
+            circuit_ports=[]
+            circuit_name = circuit.find(".//oc:circuit-pack-name",namespace)
+            circuit_type=circuit.find(".//oc:circuit-pack-type",namespace)
+            circuit_adminstrative_status=circuit.find(".//oc:administrative-state",namespace)
+            circuit_equipment_state=circuit.find("./oc:equipment-state",namespace)
+            circuit_mode=circuit.find("./oc:circuit-pack-mode",namespace)
+            slot= circuit.find("./oc:slot",namespace)
+            shelf= circuit.find("./oc:shelf",namespace)
+            ports = circuit.findall("./oc:ports",namespace)
+
+            if (ports is not None):
+                for port in ports :
+                    port_info={}
+                    port_name=port.find('./oc:port-name',namespace)
+                    port_qual= port.find("./oc:port-qual",namespace)
+                    if port_name is not None :
+                        port_info["port_name"]=port_name.text
+                    if port_qual is not None :
+                        port_info["port_qual"]=port_qual.text
+                    circuit_ports.append(port_info)            
+            if (circuit_name is not None):
+                circuit_info["circuit_name"]=circuit_name.text
+            if (circuit_type is not None):
+                circuit_info["circuit_type"]=circuit_type.text
+            if (circuit_adminstrative_status is not None):
+                circuit_info["circuit_adminstrative_status"]=circuit_adminstrative_status.text
+            if (circuit_equipment_state is not None):
+                circuit_info["circuit_equipment_state"]=circuit_equipment_state.text
+            if (circuit_mode is not None):
+                circuit_info["circuit_mode"]=circuit_mode.text
+            if (slot is not None):
+                circuit_info["slot"]=slot.text
+            if (shelf is not None):
+                circuit_info["shelf"]=shelf.text
+            circuit_info["ports"]=circuit_ports 
+            circuits_list.append(circuit_info)   
+    return circuits_list            
+
+def extract_openroadm_info(xml_data:str):
+    roadm_info={"node-id":None,"node-number":None,"node-type":None,'clli':None}
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    namespace = {'oc': "http://org/openroadm/device"}
+    info = root.findall('.//oc:info',namespace)
+    if info is not None :
+        for i in info :
+            node_id= i.find('.//oc:node-id',namespace)
+            node_number= i.find('.//oc:node-number',namespace)
+            node_type=i.find('.//oc:node-type',namespace)
+            clli=i.find('.//oc:clli',namespace)
+            if (node_id is not None):
+                roadm_info['node-id']=node_id.text
+            if (node_number is not None):
+                roadm_info['node-number']=node_number.text
+            if (node_type is not None):
+                roadm_info['node-type']=node_type.text
+            if (clli is not None):
+                roadm_info['clli']=clli.text
+    return roadm_info             
+
+def  openroadm_values_extractor (data_xml:str,resource_keys:list,dic:dict):
+    ports_result=[]
+    openroadm_info= extract_openroadm_info(data_xml)
+    circuits_list = extract_roadm_circuits_pack(data_xml)
+    dic["openroadm_info"]=openroadm_info
+    dic["circuits"]=circuits_list
+
+    for circuit in circuits_list :
+        for port in circuit['ports']:
+            if port is not None and  'port_name' in port :
+                resource_key = '/endpoints/endpoint[{:s}]'.format(port["port_name"])
+                resource_value = {'uuid': port["port_name"], 'type':port["port_qual"] if "port_qual" in port else None}
+                ports_result.append((resource_key, resource_value))
+    return [dic,ports_result]            
diff --git a/src/device/service/drivers/oc_driver/templates/descovery_tool/transponders.py b/src/device/service/drivers/oc_driver/templates/descovery_tool/transponders.py
new file mode 100644
index 0000000000000000000000000000000000000000..e0ffc12ffd63f2e5b32ea4c7a813acee7d146c58
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/descovery_tool/transponders.py
@@ -0,0 +1,301 @@
+# 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 re,logging
+import json
+import lxml.etree as ET
+from typing import Collection, Dict, Any
+
+
+
+def add_value_from_tag(target : Dict, field_name: str, field_value : ET.Element, cast=None) -> None:
+    if isinstance(field_value,str) or field_value is None or field_value.text is None: return
+    field_value = field_value.text
+    if cast is not None: field_value = cast(field_value)
+    target[field_name] = field_value
+
+def add_value_from_collection(target : Dict, field_name: str, field_value : Collection) -> None:
+    if field_value is None or len(field_value) == 0: return
+    target[field_name] = field_value
+
+
+def generate_templates(resource_key: str, resource_value: str, channel:str) -> str:    # template management to be configured
+
+    result_templates = []
+    data={}
+    data['name']=channel
+    data['resource_key']=resource_key
+    data['value']=resource_value
+    #result_templates.append(create_physical_config(data))
+
+    return result_templates
+
+
+def extract_status (dic:dict,resource_key:str,xml_data:str,channel_name:str):
+    
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    channel_name=channel_name if 'index'  not in channel_name else channel_name['index']
+    index=None
+    if channel_name.find('-') != -1 :
+        index= channel_name.split("-")[1]
+    
+   
+    namespaces = { "td": "http://openconfig.net/yang/terminal-device"}
+    channels  = root.findall(f".//td:terminal-device/td:logical-channels/td:channel",namespaces) 
+    for channel in channels : 
+       
+        index_ele= channel.find(f".//td:config[td:index='{index}']/td:{resource_key}",namespaces)
+        if index_ele is not None :
+           dic["status"]=index_ele.text
+           print(index_ele.text)
+    return dic
+
+
+def extract_channel_xmlns (data_xml:str,is_opticalband:bool):
+    xml_bytes = data_xml.encode("utf-8")
+    root = ET.fromstring(xml_bytes) 
+ 
+    namespace=None
+    channels=None
+  
+    if (not is_opticalband) :
+      
+        optical_channel_namespaces = {
+        'ns': 'urn:ietf:params:xml:ns:netconf:base:1.0',
+          'oc': 'http://openconfig.net/yang/platform',
+        }
+       
+        channels= root.find('.//{*}optical-channel',optical_channel_namespaces)
+        if channels is not None :
+          optical_channel_namespace = channels.tag.replace("optical-channel", "")
+          namespace=optical_channel_namespace.replace("{", "").replace("}", "")
+    else :       
+        optical_band_namespaces= {
+          'oc':'http://openconfig.net/yang/wavelength-router'
+        }
+        
+        channels= root.find('.//{*}optical-bands',optical_band_namespaces)
+        if channels is not None: 
+          optical_channel_namespace = channels.tag.replace("optical-bands", "")
+          namespace=optical_channel_namespace.replace("{", "").replace("}", "")
+        
+   
+    return namespace
+  
+def extract_channels_based_on_channelnamespace (xml_data:str,channel_namespace:str,is_opticalband:bool):
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    channels=[]
+   
+    # Find the component names whose children include the "optical-channel" element
+    if (not is_opticalband):
+       namespace = {'namespace': 'http://openconfig.net/yang/platform','cn':channel_namespace}
+
+       component_names = root.findall('.//namespace:component[cn:optical-channel]',namespace)
+
+      # Extract and print the component names
+       for component in component_names:
+          component_name = component.find('namespace:name', namespace).text 
+          channels.append({"index":component_name})
+    else :
+        namespaces = {
+              'wr': 'http://openconfig.net/yang/wavelength-router',
+              'fs': channel_namespace
+        }
+       
+        wl = root.findall('.//fs:optical-band',namespaces=namespaces)
+  
+        for component in wl :
+                index=component.find('.//fs:index',namespaces).text
+                dest_port_name = component.find('.//fs:dest/fs:config/fs:port-name', namespaces).text
+
+        # Retrieve port-name for source (assuming it exists in the XML structure)
+                source_port_name = component.find('.//fs:source/fs:config/fs:port-name', namespaces).text
+                channels.append({"index":index,"endpoints":(source_port_name,dest_port_name)})
+             
+        # Retrieve port-name for dest
+
+    return channels
+  
+def extract_channels_based_on_type (xml_data:str):
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+
+    namespace = {'oc': 'http://openconfig.net/yang/platform', 'typex': 'http://openconfig.net/yang/platform-types'}
+    channel_names = []
+    components = root.findall('.//oc:component', namespace)
+    for component in components:
+      
+        type_element = component.find('.//oc:state/oc:type[.="oc-opt-types:OPTICAL_CHANNEL"]',namespaces=namespace)
+    
+        if type_element is not None and type_element.text == 'oc-opt-types:OPTICAL_CHANNEL':
+            name_element = component.find('oc:name', namespace)
+            if name_element is not None:
+                channel_names.append(name_element.text)
+    return channel_names            
+    
+def extract_value(resource_key:str,xml_data:str,dic:dict,channel_name:str,channel_namespace:str):
+ 
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    channel_name=channel_name if 'index'  not in channel_name else channel_name['index']
+    namespace = {'oc': 'http://openconfig.net/yang/platform',
+              'td': channel_namespace}
+
+    element = root.find(f'.//oc:component[oc:name="{channel_name}"]', namespace)
+
+    if element is not None:
+      parameter= element.find(f'.//td:{resource_key}',namespace)
+      if (parameter is not None):
+        value = parameter.text
+        dic[resource_key]=value
+      else :
+           logging.info("parameter is None")    
+      
+    else:
+       logging.info("element is None")     
+       print(" element not found.")
+      
+    return dic  
+
+
+def extract_port_value (xml_string:list,port_name:str):
+
+    xml_bytes = xml_string.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+
+    namespace = {"oc": "http://openconfig.net/yang/platform"}
+    component=root.find(f".//oc:component[oc:name='{port_name}']", namespace)
+    onos_index = component.find(
+        f".//oc:property//oc:state/oc:name[.='onos-index']/../oc:value", namespace
+    ).text
+  
+    return (port_name,onos_index)
+            
+           
+
+  
+def extract_tranceiver (data_xml:str,dic:dict):
+    xml_bytes = data_xml.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    namespaces = {
+      'ns': 'urn:ietf:params:xml:ns:netconf:base:1.0',
+      'oc': 'http://openconfig.net/yang/platform',
+      'oc-terminal': 'http://openconfig.net/yang/terminal-device',
+      'oc-platform-types': 'http://openconfig.net/yang/platform-types'
+    }
+
+ 
+    transceiver_components = root.findall('.//oc:component/oc:state/[oc:type="oc-platform-types:TRANSCEIVER"]../oc:state/oc:name', namespaces)
+   
+    component_names = [component.text for component in transceiver_components]
+    dic['transceiver']=component_names
+    return dic
+  
+def extract_interface (xml_data:str,dic:dict):
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    namespaces = {
+    'ns': 'urn:ietf:params:xml:ns:netconf:base:1.0',
+    'oc': 'http://openconfig.net/yang/interfaces',
+    }
+    ip_namespaces = {
+    'oc': 'http://openconfig.net/yang/interfaces',
+    'ip': 'http://openconfig.net/yang/interfaces/ip',
+    }
+
+    interfaces = root.findall('.//oc:interfaces/oc:interface', namespaces)
+    interface_names = [interface.find('oc:name', namespaces).text for interface in interfaces]
+    interface_enabled=[interface.find('oc:config/oc:enabled', namespaces).text for interface in interfaces]
+    ip_address_element = root.find('.//ip:ip', ip_namespaces)
+    interface_prefix_length=root.find('.//ip:prefix-length',ip_namespaces)
+    if (len(interface_names) > 0):
+       dic['interface']={"name":interface_names[0],'ip':ip_address_element.text,'enabled':interface_enabled[0],"prefix-length":interface_prefix_length.text}
+    else :
+        dic['interface']={}   
+    return dic
+  
+def has_opticalbands(xml_data:str):
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+ 
+    has_opticalbands=False
+    elements= root.find('.//{*}optical-bands')
+
+    if (elements is not None and len(elements) >0):
+      has_opticalbands=True
+    else :
+      has_opticalbands=False
+    return has_opticalbands
+  
+def extract_ports_based_on_type (xml_data:str):
+    pattern = r':\s*PORT\b'
+    xml_bytes = xml_data.encode("utf-8")
+    root = ET.fromstring(xml_bytes)
+    namespace = {'oc': 'http://openconfig.net/yang/platform', 'typex': 'http://openconfig.net/yang/platform-types'}
+    ports = []
+    components = root.findall(".//oc:state[oc:type]",namespace)
+    for component in components:
+         type_ele = component.find(".//oc:type",namespace)
+         match = re.search(pattern, type_ele.text)
+         if match is not None :
+            name_element= component.find(".//oc:name",namespace)
+            port_name =name_element.text       
+            port_index=name_element.text.split("-")[1]
+            port = (port_name,port_index)
+            ports.append(port)
+    return ports  
+    
+def transponder_values_extractor(data_xml:str,resource_keys:list,dic:dict):
+   
+    endpoints=[]
+    is_opticalband=has_opticalbands(xml_data=data_xml)
+    channel_namespace=extract_channel_xmlns(data_xml=data_xml,is_opticalband=is_opticalband)
+    # channel_names=extract_channels_based_on_type(xml_data=data_xml) 
+    # if len(channel_names)==0 :
+    channel_names= extract_channels_based_on_channelnamespace(xml_data=data_xml,channel_namespace=channel_namespace,is_opticalband=is_opticalband)
+
+    ports = extract_ports_based_on_type(data_xml)
+    optical_channels_params=[]
+    ports_result=[]
+    if (is_opticalband):
+        endpoints=channel_names
+    else:
+            
+        for channel_name in channel_names:
+            dic={}
+            for resource_key in resource_keys  :
+                
+                if (resource_key != 'admin-state'):
+                  
+                    dic=extract_value(dic=dic,resource_key=resource_key,xml_data=data_xml
+                                      ,channel_name=channel_name,channel_namespace=channel_namespace)  
+                else : 
+                    dic = extract_status(dic=dic,resource_key=resource_key,xml_data=data_xml, channel_name=channel_name) 
+            dic["name"]=channel_name
+            endpoints.append({"endpoint_uuid":{"uuid":channel_name}})
+            optical_channels_params.append(dic)                
+    #transceivers_dic=extract_tranceiver(data_xml=data_xml,dic={})
+    transceivers_dic={"transceiver":[]}
+    #interfaces_dic=extract_interface(xml_data=data_xml,dic={})
+    if len(ports)>0 :
+      for port in ports :
+        endpoint_name,endpoint_id=port
+        resource_key = '/endpoints/endpoint[{:s}]'.format(endpoint_id)
+        resource_value = {'uuid': endpoint_id, 'type':endpoint_name}
+        ports_result.append((resource_key, resource_value))
+      
+   
+    return [transceivers_dic,optical_channels_params,channel_namespace,endpoints,ports_result]
diff --git a/src/tests/p4/__init__.py b/src/device/tests/gnmi_openconfig/__init__.py
similarity index 100%
rename from src/tests/p4/__init__.py
rename to src/device/tests/gnmi_openconfig/__init__.py
diff --git a/src/device/tests/gnmi_openconfig/storage/Storage.py b/src/device/tests/gnmi_openconfig/storage/Storage.py
new file mode 100644
index 0000000000000000000000000000000000000000..ba3596be791e0bc8a473596e6c238eb87fe21f89
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/storage/Storage.py
@@ -0,0 +1,23 @@
+# 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 .StorageEndpoints import StorageEndpoints
+from .StorageInterface import StorageInterface
+from .StorageNetworkInstance import StorageNetworkInstance
+
+class Storage:
+    def __init__(self) -> None:
+        self.endpoints         = StorageEndpoints()
+        self.interfaces        = StorageInterface()
+        self.network_instances = StorageNetworkInstance()
diff --git a/src/device/tests/gnmi_openconfig/storage/StorageEndpoints.py b/src/device/tests/gnmi_openconfig/storage/StorageEndpoints.py
new file mode 100644
index 0000000000000000000000000000000000000000..9876c8019317e33e58a64a86a477ea06c1ce76a9
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/storage/StorageEndpoints.py
@@ -0,0 +1,75 @@
+# 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 re
+from typing import Dict, List, Tuple
+from .Tools import compose_resources
+
+RE_RESKEY_ENDPOINT = re.compile(r'^\/endpoints\/endpoint\[([^\]]+)\]$')
+
+ENDPOINT_PACKET_SAMPLE_TYPES : Dict[int, str] = {
+    101: '/openconfig-interfaces:interfaces/interface[name={:s}]/state/counters/out-pkts',
+    102: '/openconfig-interfaces:interfaces/interface[name={:s}]/state/counters/in-pkts',
+    201: '/openconfig-interfaces:interfaces/interface[name={:s}]/state/counters/out-octets',
+    202: '/openconfig-interfaces:interfaces/interface[name={:s}]/state/counters/in-octets',
+}
+
+class Endpoints:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/endpoints/endpoint[{:s}]', ['uuid', 'type', 'sample_types']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[str, Dict] = dict()
+
+    def add(self, ep_uuid : str, resource_value : Dict) -> None:
+        item = self._items.setdefault(ep_uuid, dict())
+        item['uuid'] = ep_uuid
+
+        for _, field_names in Endpoints.STRUCT:
+            field_names = set(field_names)
+            item.update({k:v for k,v in resource_value.items() if k in field_names})
+
+        item['sample_types'] = {
+            sample_type_id : sample_type_path.format(ep_uuid)
+            for sample_type_id, sample_type_path in ENDPOINT_PACKET_SAMPLE_TYPES.items()
+        }
+
+    def get(self, ep_uuid : str) -> Dict:
+        return self._items.get(ep_uuid)
+
+    def remove(self, ep_uuid : str) -> None:
+        self._items.pop(ep_uuid, None)
+    
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, Endpoints.STRUCT)
+
+class StorageEndpoints:
+    def __init__(self) -> None:
+        self.endpoints = Endpoints()
+
+    def populate(self, resources : List[Tuple[str, Dict]]) -> None:
+        for resource_key, resource_value in resources:
+            match = RE_RESKEY_ENDPOINT.match(resource_key)
+            if match is not None:
+                self.endpoints.add(match.group(1), resource_value)
+                continue
+
+            MSG = 'Unhandled Resource Key: {:s} => {:s}'
+            raise Exception(MSG.format(str(resource_key), str(resource_value)))
+
+    def get_expected_config(self) -> List[Tuple[str, Dict]]:
+        expected_config = list()
+        expected_config.extend(self.endpoints.compose_resources())
+        return expected_config
diff --git a/src/device/tests/gnmi_openconfig/storage/StorageInterface copy.py b/src/device/tests/gnmi_openconfig/storage/StorageInterface copy.py
new file mode 100644
index 0000000000000000000000000000000000000000..1929ced36b9c597656d4f6022616c78c78539a6a
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/storage/StorageInterface copy.py	
@@ -0,0 +1,134 @@
+# 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 re
+from typing import Dict, List, Tuple
+from .Tools import compose_resources
+
+PREFIX = r'^\/interface\[([^\]]+)\]'
+RE_RESKEY_INTERFACE    = re.compile(PREFIX + r'$')
+RE_RESKEY_ETHERNET     = re.compile(PREFIX + r'\/ethernet$')
+RE_RESKEY_SUBINTERFACE = re.compile(PREFIX + r'\/subinterface\[([^\]]+)\]$')
+#RE_RESKEY_IPV4_ADDRESS = re.compile(PREFIX + r'\/subinterface\[([^\]]+)\]\/ipv4\[([^\]]+)\]$')
+
+class Interfaces:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/interface[{:s}]', ['name', 'type', 'admin-status', 'oper-status', 'management', 'mtu', 'ifindex',
+                              'hardware-port', 'transceiver']),
+        ('/interface[{:s}]/ethernet', ['port-speed', 'negotiated-port-speed', 'mac-address', 'hw-mac-address']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[str, Dict] = dict()
+
+    def add(self, if_name : str, resource_value : Dict) -> None:
+        item = self._items.setdefault(if_name, dict())
+        item['name'] = if_name
+        for _, field_names in Interfaces.STRUCT:
+            field_names = set(field_names)
+            item.update({k:v for k,v in resource_value.items() if k in field_names})
+
+    def get(self, if_name : str) -> Dict:
+        return self._items.get(if_name)
+
+    def remove(self, if_name : str) -> None:
+        self._items.pop(if_name, None)
+    
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, Interfaces.STRUCT)
+
+class SubInterfaces:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/interface[{:s}]/subinterface[{:d}]', ['index']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[Tuple[str, int], Dict] = dict()
+
+    def add(self, if_name : str, subif_index : int) -> None:
+        item = self._items.setdefault((if_name, subif_index), dict())
+        item['index'] = subif_index
+
+    def get(self, if_name : str, subif_index : int) -> Dict:
+        return self._items.get((if_name, subif_index))
+
+    def remove(self, if_name : str, subif_index : int) -> None:
+        self._items.pop((if_name, subif_index), None)
+    
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, SubInterfaces.STRUCT)
+
+class IPv4Addresses:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/interface[{:s}]/subinterface[{:d}]', ['index', 'address_ip', 'address_prefix', 'origin']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[Tuple[str, int], Dict] = dict()
+
+    def add(self, if_name : str, subif_index : int, ipv4_address : str, resource_value : Dict) -> None:
+        item = self._items.setdefault((if_name, subif_index), dict())
+        item['index'         ] = subif_index
+        item['address_ip'    ] = ipv4_address
+        item['origin'        ] = resource_value.get('origin')
+        item['address_prefix'] = resource_value.get('prefix')
+
+    def get(self, if_name : str, subif_index : int, ipv4_address : str) -> Dict:
+        return self._items.get((if_name, subif_index))
+
+    def remove(self, if_name : str, subif_index : int, ipv4_address : str) -> None:
+        self._items.pop((if_name, subif_index), None)
+
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, IPv4Addresses.STRUCT)
+
+class StorageInterface:
+    def __init__(self) -> None:
+        self.interfaces     = Interfaces()
+        self.subinterfaces  = SubInterfaces()
+        self.ipv4_addresses = IPv4Addresses()
+
+    def populate(self, resources : List[Tuple[str, Dict]]) -> None:
+        for resource_key, resource_value in resources:
+            match = RE_RESKEY_INTERFACE.match(resource_key)
+            if match is not None:
+                self.interfaces.add(match.group(1), resource_value)
+                continue
+
+            match = RE_RESKEY_ETHERNET.match(resource_key)
+            if match is not None:
+                self.interfaces.add(match.group(1), resource_value)
+                continue
+
+            match = RE_RESKEY_SUBINTERFACE.match(resource_key)
+            if match is not None:
+                self.subinterfaces.add(match.group(1), int(match.group(2)))
+                address_ip = resource_value.get('address_ip')
+                self.ipv4_addresses.add(match.group(1), int(match.group(2)), address_ip, resource_value)
+                continue
+
+            #match = RE_RESKEY_IPV4_ADDRESS.match(resource_key)
+            #if match is not None:
+            #    self.ipv4_addresses.add(match.group(1), int(match.group(2)), match.group(3), resource_value)
+            #    continue
+
+            MSG = 'Unhandled Resource Key: {:s} => {:s}'
+            raise Exception(MSG.format(str(resource_key), str(resource_value)))
+
+    def get_expected_config(self) -> List[Tuple[str, Dict]]:
+        expected_config = list()
+        expected_config.extend(self.interfaces.compose_resources())
+        #expected_config.extend(self.subinterfaces.compose_resources())
+        expected_config.extend(self.ipv4_addresses.compose_resources())
+        return expected_config
diff --git a/src/device/tests/gnmi_openconfig/storage/StorageInterface.py b/src/device/tests/gnmi_openconfig/storage/StorageInterface.py
new file mode 100644
index 0000000000000000000000000000000000000000..f07677c123048774326d61c88df61e66c254b612
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/storage/StorageInterface.py
@@ -0,0 +1,131 @@
+# 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 re
+from typing import Dict, List, Tuple
+from .Tools import compose_resources
+
+PREFIX = r'^\/interface\[([^\]]+)\]'
+RE_RESKEY_INTERFACE    = re.compile(PREFIX + r'$')
+RE_RESKEY_ETHERNET     = re.compile(PREFIX + r'\/ethernet$')
+RE_RESKEY_SUBINTERFACE = re.compile(PREFIX + r'\/subinterface\[([^\]]+)\]$')
+RE_RESKEY_IPV4_ADDRESS = re.compile(PREFIX + r'\/subinterface\[([^\]]+)\]\/ipv4\[([^\]]+)\]$')
+
+class Interfaces:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/interface[{:s}]', ['name', 'type', 'admin-status', 'oper-status', 'management', 'mtu', 'ifindex',
+                              'hardware-port', 'transceiver']),
+        ('/interface[{:s}]/ethernet', ['port-speed', 'negotiated-port-speed', 'mac-address', 'hw-mac-address']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[str, Dict] = dict()
+
+    def add(self, if_name : str, resource_value : Dict) -> None:
+        item = self._items.setdefault(if_name, dict())
+        item['name'] = if_name
+        for _, field_names in Interfaces.STRUCT:
+            field_names = set(field_names)
+            item.update({k:v for k,v in resource_value.items() if k in field_names})
+
+    def get(self, if_name : str) -> Dict:
+        return self._items.get(if_name)
+
+    def remove(self, if_name : str) -> None:
+        self._items.pop(if_name, None)
+    
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, Interfaces.STRUCT)
+
+class SubInterfaces:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/interface[{:s}]/subinterface[{:d}]', ['index']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[Tuple[str, int], Dict] = dict()
+
+    def add(self, if_name : str, subif_index : int) -> None:
+        item = self._items.setdefault((if_name, subif_index), dict())
+        item['index'] = subif_index
+
+    def get(self, if_name : str, subif_index : int) -> Dict:
+        return self._items.get((if_name, subif_index))
+
+    def remove(self, if_name : str, subif_index : int) -> None:
+        self._items.pop((if_name, subif_index), None)
+    
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, SubInterfaces.STRUCT)
+
+class IPv4Addresses:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/interface[{:s}]/subinterface[{:d}]/ipv4[{:s}]', ['ip', 'origin', 'prefix']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[Tuple[str, int, str], Dict] = dict()
+
+    def add(self, if_name : str, subif_index : int, ipv4_address : str, resource_value : Dict) -> None:
+        item = self._items.setdefault((if_name, subif_index, ipv4_address), dict())
+        item['ip'    ] = ipv4_address
+        item['origin'] = resource_value.get('origin')
+        item['prefix'] = resource_value.get('prefix')
+
+    def get(self, if_name : str, subif_index : int, ipv4_address : str) -> Dict:
+        return self._items.get((if_name, subif_index, ipv4_address))
+
+    def remove(self, if_name : str, subif_index : int, ipv4_address : str) -> None:
+        self._items.pop((if_name, subif_index, ipv4_address), None)
+
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, IPv4Addresses.STRUCT)
+
+class StorageInterface:
+    def __init__(self) -> None:
+        self.interfaces     = Interfaces()
+        self.subinterfaces  = SubInterfaces()
+        self.ipv4_addresses = IPv4Addresses()
+
+    def populate(self, resources : List[Tuple[str, Dict]]) -> None:
+        for resource_key, resource_value in resources:
+            match = RE_RESKEY_INTERFACE.match(resource_key)
+            if match is not None:
+                self.interfaces.add(match.group(1), resource_value)
+                continue
+
+            match = RE_RESKEY_ETHERNET.match(resource_key)
+            if match is not None:
+                self.interfaces.add(match.group(1), resource_value)
+                continue
+
+            match = RE_RESKEY_SUBINTERFACE.match(resource_key)
+            if match is not None:
+                self.subinterfaces.add(match.group(1), int(match.group(2)))
+                continue
+
+            match = RE_RESKEY_IPV4_ADDRESS.match(resource_key)
+            if match is not None:
+                self.ipv4_addresses.add(match.group(1), int(match.group(2)), match.group(3), resource_value)
+                continue
+
+            MSG = 'Unhandled Resource Key: {:s} => {:s}'
+            raise Exception(MSG.format(str(resource_key), str(resource_value)))
+
+    def get_expected_config(self) -> List[Tuple[str, Dict]]:
+        expected_config = list()
+        expected_config.extend(self.interfaces.compose_resources())
+        expected_config.extend(self.subinterfaces.compose_resources())
+        expected_config.extend(self.ipv4_addresses.compose_resources())
+        return expected_config
diff --git a/src/device/tests/gnmi_openconfig/storage/StorageNetworkInstance.py b/src/device/tests/gnmi_openconfig/storage/StorageNetworkInstance.py
new file mode 100644
index 0000000000000000000000000000000000000000..642099aba80542dd93a504c11778a91be615799f
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/storage/StorageNetworkInstance.py
@@ -0,0 +1,218 @@
+# 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 re
+from typing import Dict, List, Tuple
+from .Tools import compose_resources
+
+PREFIX = r'^\/network\_instance\[([^\]]+)\]'
+RE_RESKEY_NET_INST     = re.compile(PREFIX + r'$')
+RE_RESKEY_INTERFACE    = re.compile(PREFIX + r'\/interface\[([^\]]+)\]$')
+RE_RESKEY_PROTOCOL     = re.compile(PREFIX + r'\/protocol\[([^\]]+)\]$')
+RE_RESKEY_PROTO_STATIC = re.compile(PREFIX + r'\/protocol\[([^\]]+)\]\/static\_routes\[([^\]]+)\]$')
+RE_RESKEY_TABLE        = re.compile(PREFIX + r'\/table\[([^\,]+)\,([^\]]+)\]$')
+RE_RESKEY_VLAN         = re.compile(PREFIX + r'\/vlan\[([^\]]+)\]$')
+
+class NetworkInstances:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/network_instance[{:s}]', ['name', 'type']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[str, Dict] = dict()
+
+    def add(self, ni_name : str, resource_value : Dict) -> None:
+        item = self._items.setdefault(ni_name, dict())
+        item['name'] = ni_name
+        item['type'] = resource_value.get('type')
+
+    def get(self, ni_name : str) -> Dict:
+        return self._items.get(ni_name)
+
+    def remove(self, ni_name : str) -> None:
+        self._items.pop(ni_name, None)
+    
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, NetworkInstances.STRUCT)
+
+class Interfaces:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/network_instance[{:s}]/interface[{:s}.{:d}]', ['name', 'id', 'if_name', 'sif_index']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[Tuple[str, str], Dict] = dict()
+
+    def add(self, ni_name : str, if_name : str, sif_index : int) -> None:
+        item = self._items.setdefault((ni_name, if_name, sif_index), dict())
+        item['name'     ] = ni_name
+        item['id'       ] = '{:s}.{:d}'.format(if_name, sif_index)
+        item['if_name'  ] = if_name
+        item['sif_index'] = sif_index
+
+    def get(self, ni_name : str, if_name : str, sif_index : int) -> Dict:
+        return self._items.get((ni_name, if_name, sif_index))
+
+    def remove(self, ni_name : str, if_name : str, sif_index : int) -> None:
+        self._items.pop((ni_name, if_name, sif_index), None)
+
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, Interfaces.STRUCT)
+
+class Protocols:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/network_instance[{:s}]/protocol[{:s}]', ['id', 'name']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[Tuple[str, str], Dict] = dict()
+
+    def add(self, ni_name : str, protocol : str) -> None:
+        item = self._items.setdefault((ni_name, protocol), dict())
+        item['id'  ] = protocol
+        item['name'] = protocol
+
+    def get(self, ni_name : str, protocol : str) -> Dict:
+        return self._items.get((ni_name, protocol))
+
+    def remove(self, ni_name : str, protocol : str) -> None:
+        self._items.pop((ni_name, protocol), None)
+
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, Protocols.STRUCT)
+
+class StaticRoutes:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/network_instance[{:s}]/protocol[{:s}]/static_routes[{:s}]', ['prefix', 'next_hops']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[Tuple[str, str, str], Dict] = dict()
+
+    def add(self, ni_name : str, protocol : str, prefix : str, resource_value : Dict) -> None:
+        item = self._items.setdefault((ni_name, protocol, prefix), dict())
+        item['prefix'   ] = prefix
+        item['next_hops'] = resource_value.get('next_hops')
+
+    def get(self, ni_name : str, protocol : str, prefix : str) -> Dict:
+        return self._items.get((ni_name, protocol, prefix))
+
+    def remove(self, ni_name : str, protocol : str, prefix : str) -> None:
+        self._items.pop((ni_name, protocol, prefix), None)
+
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, StaticRoutes.STRUCT)
+
+class Tables:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/network_instance[{:s}]/table[{:s},{:s}]', ['protocol', 'address_family']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[Tuple[str, str, str], Dict] = dict()
+
+    def add(self, ni_name : str, protocol : str, address_family : str) -> None:
+        item = self._items.setdefault((ni_name, protocol, address_family), dict())
+        item['protocol'      ] = protocol
+        item['address_family'] = address_family
+
+    def get(self, ni_name : str, protocol : str, address_family : str) -> Dict:
+        return self._items.get((ni_name, protocol, address_family))
+
+    def remove(self, ni_name : str, protocol : str, address_family : str) -> None:
+        self._items.pop((ni_name, protocol, address_family), None)
+
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, Tables.STRUCT)
+
+class Vlans:
+    STRUCT : List[Tuple[str, List[str]]] = [
+        ('/network_instance[{:s}]/vlan[{:d}]', ['vlan_id', 'name', 'members']),
+    ]
+
+    def __init__(self) -> None:
+        self._items : Dict[Tuple[str, int], Dict] = dict()
+
+    def add(self, ni_name : str, vlan_id : int, resource_value : Dict) -> None:
+        item = self._items.setdefault((ni_name, vlan_id), dict())
+        item['vlan_id'] = vlan_id
+        item['name'   ] = resource_value.get('name')
+        item['members'] = sorted(resource_value.get('members'))
+
+    def get(self, ni_name : str, vlan_id : int) -> Dict:
+        return self._items.get((ni_name, vlan_id))
+
+    def remove(self, ni_name : str, vlan_id : int) -> None:
+        self._items.pop((ni_name, vlan_id), None)
+
+    def compose_resources(self) -> List[Dict]:
+        return compose_resources(self._items, Vlans.STRUCT)
+
+class StorageNetworkInstance:
+    def __init__(self) -> None:
+        self.network_instances = NetworkInstances()
+        self.interfaces        = Interfaces()
+        self.protocols         = Protocols()
+        self.protocol_static   = StaticRoutes()
+        self.tables            = Tables()
+        self.vlans             = Vlans()
+
+    def populate(self, resources : List[Tuple[str, Dict]]) -> None:
+        for resource_key, resource_value in resources:
+            match = RE_RESKEY_NET_INST.match(resource_key)
+            if match is not None:
+                self.network_instances.add(match.group(1), resource_value)
+                continue
+
+            match = RE_RESKEY_INTERFACE.match(resource_key)
+            if match is not None:
+                if_id = match.group(2)
+                if_id_parts = if_id.split('.')
+                if_name = if_id_parts[0]
+                sif_index = 0 if len(if_id_parts) == 1 else int(if_id_parts[1])
+                self.interfaces.add(match.group(1), if_name, sif_index)
+                continue
+
+            match = RE_RESKEY_PROTOCOL.match(resource_key)
+            if match is not None:
+                self.protocols.add(match.group(1), match.group(2))
+                continue
+
+            match = RE_RESKEY_PROTO_STATIC.match(resource_key)
+            if match is not None:
+                self.protocol_static.add(match.group(1), match.group(2), match.group(3), resource_value)
+                continue
+
+            match = RE_RESKEY_TABLE.match(resource_key)
+            if match is not None:
+                self.tables.add(match.group(1), match.group(2), match.group(3))
+                continue
+
+            match = RE_RESKEY_VLAN.match(resource_key)
+            if match is not None:
+                self.vlans.add(match.group(1), int(match.group(2)), resource_value)
+                continue
+
+            MSG = 'Unhandled Resource Key: {:s} => {:s}'
+            raise Exception(MSG.format(str(resource_key), str(resource_value)))
+
+    def get_expected_config(self) -> List[Tuple[str, Dict]]:
+        expected_config = list()
+        expected_config.extend(self.network_instances.compose_resources())
+        expected_config.extend(self.interfaces.compose_resources())
+        expected_config.extend(self.protocols.compose_resources())
+        expected_config.extend(self.protocol_static.compose_resources())
+        expected_config.extend(self.tables.compose_resources())
+        expected_config.extend(self.vlans.compose_resources())
+        return expected_config
diff --git a/src/device/tests/gnmi_openconfig/storage/Tools.py b/src/device/tests/gnmi_openconfig/storage/Tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..0e26417d98ccd40ec9685c56de253d0a414475e3
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/storage/Tools.py
@@ -0,0 +1,33 @@
+# 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 Dict, List, Tuple
+
+def compose_resources(
+    storage : Dict[Tuple, Dict], config_struct : List[Tuple[str, List[str]]]
+) -> List[Dict]:
+    expected_config = list()
+
+    for resource_key_fields, resource_value_data in storage.items():
+        for resource_key_template, resource_key_field_names in config_struct:
+            if isinstance(resource_key_fields, (str, int, float, bool)): resource_key_fields = (resource_key_fields,)
+            resource_key = resource_key_template.format(*resource_key_fields)
+            resource_value = {
+                field_name : resource_value_data[field_name]
+                for field_name in resource_key_field_names
+                if field_name in resource_value_data and resource_value_data[field_name] is not None
+            }
+            expected_config.append((resource_key, resource_value))
+
+    return expected_config
diff --git a/src/tests/p4/tests/__init__.py b/src/device/tests/gnmi_openconfig/storage/__init__.py
similarity index 100%
rename from src/tests/p4/tests/__init__.py
rename to src/device/tests/gnmi_openconfig/storage/__init__.py
diff --git a/src/device/tests/gnmi_openconfig/test_unitary_gnmi_oc_arista_l2vpn.py b/src/device/tests/gnmi_openconfig/test_unitary_gnmi_oc_arista_l2vpn.py
new file mode 100644
index 0000000000000000000000000000000000000000..b09d7186b684d15172c25714d2df6458442f9e80
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/test_unitary_gnmi_oc_arista_l2vpn.py
@@ -0,0 +1,576 @@
+# 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, os, pytest, time
+from typing import Dict, Tuple
+os.environ['DEVICE_EMULATED_ONLY'] = 'YES'
+
+# pylint: disable=wrong-import-position
+from device.service.drivers.gnmi_openconfig.GnmiOpenConfigDriver import GnmiOpenConfigDriver
+#from device.service.driver_api._Driver import (
+#    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_SERVICES
+#)
+
+logging.basicConfig(level=logging.DEBUG)
+#logging.getLogger('ncclient.operations.rpc').setLevel(logging.INFO)
+#logging.getLogger('ncclient.transport.parser').setLevel(logging.INFO)
+
+LOGGER = logging.getLogger(__name__)
+
+
+##### DRIVERS FIXTURE ##################################################################################################
+
+DEVICES = {
+    'SW1': {'address': '172.20.20.101', 'port': 6030, 'settings': {
+        'username': 'admin', 'password': 'admin',
+        'vendor': None, 'force_running': False, 'hostkey_verify': False, 'look_for_keys': False, 'allow_agent': False,
+        'commit_per_rule': True, 'device_params': {'name': 'default'}, 'manager_params': {'timeout' : 120}
+    }},
+    'SW2': {'address': '10.1.1.87', 'port': 830, 'settings': {
+        'username': 'ocnos', 'password': 'ocnos',
+        'vendor': None, 'force_running': False, 'hostkey_verify': False, 'look_for_keys': False, 'allow_agent': False,
+        'commit_per_rule': True, 'device_params': {'name': 'default'}, 'manager_params': {'timeout' : 120}
+    }},
+}
+
+@pytest.fixture(scope='session')
+def drivers() -> Dict[str, OpenConfigDriver]:
+    _drivers : Dict[str, OpenConfigDriver] = dict()
+    for device_name, driver_params in DEVICES.items():
+        driver = OpenConfigDriver(driver_params['address'], driver_params['port'], **(driver_params['settings']))
+        driver.Connect()
+        _drivers[device_name] = driver
+    yield _drivers
+    time.sleep(1)
+    for _,driver in _drivers.items():
+        driver.Disconnect()
+
+
+def network_instance(ni_name, ni_type, ni_router_id=None, ni_route_distinguisher=None) -> Tuple[str, Dict]:
+    path = '/network_instance[{:s}]'.format(ni_name)
+    data = {'name': ni_name, 'type': ni_type}
+    if ni_router_id is not None: data['router_id'] = ni_router_id
+    if ni_route_distinguisher is not None: data['route_distinguisher'] = ni_route_distinguisher
+    return path, json.dumps(data)
+
+def network_instance_add_protocol_bgp(ni_name, ni_type, ni_router_id, ni_bgp_as, neighbors=[]) -> Tuple[str, Dict]:
+    path = '/network_instance[{:s}]/protocols[BGP]'.format(ni_name)
+    data = {
+        'name': ni_name, 'type': ni_type, 'router_id': ni_router_id, 'identifier': 'BGP',
+        'protocol_name': ni_bgp_as, 'as': ni_bgp_as
+    }
+    if len(neighbors) > 0:
+        data['neighbors'] = [
+            {'ip_address': neighbor_ip_address, 'remote_as': neighbor_remote_as}
+            for neighbor_ip_address, neighbor_remote_as in neighbors
+        ]
+    return path, json.dumps(data)
+
+def network_instance_add_protocol_direct(ni_name, ni_type) -> Tuple[str, Dict]:
+    path = '/network_instance[{:s}]/protocols[DIRECTLY_CONNECTED]'.format(ni_name)
+    data = {
+        'name': ni_name, 'type': ni_type, 'identifier': 'DIRECTLY_CONNECTED',
+        'protocol_name': 'DIRECTLY_CONNECTED'
+    }
+    return path, json.dumps(data)
+
+def network_instance_add_protocol_static(ni_name, ni_type) -> Tuple[str, Dict]:
+    path = '/network_instance[{:s}]/protocols[STATIC]'.format(ni_name)
+    data = {
+        'name': ni_name, 'type': ni_type, 'identifier': 'STATIC',
+        'protocol_name': 'STATIC'
+    }
+    return path, json.dumps(data)
+
+#def network_instance_static_route(ni_name, prefix, next_hop, next_hop_index=0) -> Tuple[str, Dict]:
+#    path = '/network_instance[{:s}]/static_route[{:s}]'.format(ni_name, prefix)
+#    data = {'name': ni_name, 'prefix': prefix, 'next_hop': next_hop, 'next_hop_index': next_hop_index}
+#    return path, json.dumps(data)
+
+def network_instance_add_table_connection(
+    ni_name, src_protocol, dst_protocol, address_family, default_import_policy, bgp_as=None
+) -> Tuple[str, Dict]:
+    path = '/network_instance[{:s}]/table_connections[{:s}][{:s}][{:s}]'.format(
+        ni_name, src_protocol, dst_protocol, address_family
+    )
+    data = {
+        'name': ni_name, 'src_protocol': src_protocol, 'dst_protocol': dst_protocol,
+        'address_family': address_family, 'default_import_policy': default_import_policy,
+    }
+    if bgp_as is not None: data['as'] = bgp_as
+    return path, json.dumps(data)
+
+def interface(
+    name, index, description=None, if_type=None, vlan_id=None, mtu=None, ipv4_address_prefix=None, enabled=None
+) -> Tuple[str, Dict]:
+    path = '/interface[{:s}]/subinterface[{:d}]'.format(name, index)
+    data = {'name': name, 'index': index}
+    if description is not None: data['description'] = description
+    if if_type     is not None: data['type'       ] = if_type
+    if vlan_id     is not None: data['vlan_id'    ] = vlan_id
+    if mtu         is not None: data['mtu'        ] = mtu
+    if enabled     is not None: data['enabled'    ] = enabled
+    if ipv4_address_prefix is not None:
+        ipv4_address, ipv4_prefix = ipv4_address_prefix
+        data['address_ip'    ] = ipv4_address
+        data['address_prefix'] = ipv4_prefix
+    return path, json.dumps(data)
+
+def network_instance_interface(ni_name, ni_type, if_name, if_index) -> Tuple[str, Dict]:
+    path = '/network_instance[{:s}]/interface[{:s}.{:d}]'.format(ni_name, if_name, if_index)
+    data = {'name': ni_name, 'type': ni_type, 'id': if_name, 'interface': if_name, 'subinterface': if_index}
+    return path, json.dumps(data)
+
+def test_configure(drivers : Dict[str, OpenConfigDriver]):
+    #resources_to_get = []
+    #resources_to_get = [RESOURCE_ENDPOINTS]
+    #resources_to_get = [RESOURCE_INTERFACES]
+    #resources_to_get = [RESOURCE_NETWORK_INSTANCES]
+    #resources_to_get = [RESOURCE_ROUTING_POLICIES]
+    #resources_to_get = [RESOURCE_SERVICES]
+    #LOGGER.info('resources_to_get = {:s}'.format(str(resources_to_get)))
+    #results_getconfig = driver.GetConfig(resources_to_get)
+    #LOGGER.info('results_getconfig = {:s}'.format(str(results_getconfig)))
+
+    csgw1_resources_to_set = [
+        network_instance('ecoc24', 'L3VRF', '192.168.150.1', '65001:1'),
+        network_instance_add_protocol_direct('ecoc24', 'L3VRF'),
+        network_instance_add_protocol_static('ecoc24', 'L3VRF'),
+        network_instance_add_protocol_bgp('ecoc24', 'L3VRF', '192.168.150.1', '65001', neighbors=[
+            ('192.168.150.2', '65001')
+        ]),
+        network_instance_add_table_connection('ecoc24', 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+        network_instance_add_table_connection('ecoc24', 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+    
+        interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500),
+        network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
+        interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.10.1', 24), enabled=True),
+    
+        interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500),
+        network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+        interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.150.1', 24), enabled=True),
+    ]
+    LOGGER.info('CSGW1 resources_to_set = {:s}'.format(str(csgw1_resources_to_set)))
+    results_setconfig = drivers['CSGW1'].SetConfig(csgw1_resources_to_set)
+    LOGGER.info('CSGW1 results_setconfig = {:s}'.format(str(results_setconfig)))
+
+    csgw2_resources_to_set = [
+        network_instance('ecoc24', 'L3VRF', '192.168.150.2', '65001:1'),
+        network_instance_add_protocol_direct('ecoc24', 'L3VRF'),
+        network_instance_add_protocol_static('ecoc24', 'L3VRF'),
+        network_instance_add_protocol_bgp('ecoc24', 'L3VRF', '192.168.150.2', '65001', neighbors=[
+            ('192.168.150.1', '65001')
+        ]),
+        network_instance_add_table_connection('ecoc24', 'DIRECTLY_CONNECTED', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+        network_instance_add_table_connection('ecoc24', 'STATIC', 'BGP', 'IPV4', 'ACCEPT_ROUTE', bgp_as='65001'),
+    
+        interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500),
+        network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
+        interface('ce1', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.20.1', 24), enabled=True),
+    
+        interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500),
+        network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+        interface('xe5', 0, if_type='ethernetCsmacd', mtu=1500, ipv4_address_prefix=('192.168.150.2', 24), enabled=True),
+    ]
+    LOGGER.info('CSGW2 resources_to_set = {:s}'.format(str(csgw2_resources_to_set)))
+    results_setconfig = drivers['CSGW2'].SetConfig(csgw2_resources_to_set)
+    LOGGER.info('CSGW2 results_setconfig = {:s}'.format(str(results_setconfig)))
+
+    csgw1_resources_to_delete = [
+        network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
+        network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+        #interface('ce1', 0),
+        #interface('xe5', 0),
+        network_instance('ecoc24', 'L3VRF'),
+    ]
+    LOGGER.info('CSGW1 resources_to_delete = {:s}'.format(str(csgw1_resources_to_delete)))
+    results_deleteconfig = drivers['CSGW1'].DeleteConfig(csgw1_resources_to_delete)
+    LOGGER.info('CSGW1 results_deleteconfig = {:s}'.format(str(results_deleteconfig)))
+
+    csgw2_resources_to_delete = [
+        network_instance_interface('ecoc24', 'L3VRF', 'ce1', 0),
+        network_instance_interface('ecoc24', 'L3VRF', 'xe5', 0),
+        #interface('ce1', 0),
+        #interface('xe5', 0),
+        network_instance('ecoc24', 'L3VRF'),
+    ]
+    LOGGER.info('CSGW2 resources_to_delete = {:s}'.format(str(csgw2_resources_to_delete)))
+    results_deleteconfig = drivers['CSGW2'].DeleteConfig(csgw2_resources_to_delete)
+    LOGGER.info('CSGW2 results_deleteconfig = {:s}'.format(str(results_deleteconfig)))
+
+
+
+
+
+
+# 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 os
+os.environ['DEVICE_EMULATED_ONLY'] = 'YES'
+
+# pylint: disable=wrong-import-position
+import logging, pytest, time
+from typing import Dict, List
+from device.service.driver_api._Driver import (
+    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES,
+    RESOURCE_ROUTING_POLICIES, RESOURCE_SERVICES
+)
+from device.service.drivers.gnmi_openconfig.GnmiOpenConfigDriver import GnmiOpenConfigDriver
+from .storage.Storage import Storage
+from .tools.manage_config import (
+    check_config_endpoints, check_config_interfaces, check_config_network_instances, del_config, get_config, set_config
+)
+from .tools.check_updates import check_updates
+from .tools.request_composers import (
+    interface, network_instance, network_instance_interface, network_instance_static_route
+)
+
+logging.basicConfig(level=logging.DEBUG)
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+
+##### DRIVER FIXTURE ###################################################################################################
+
+DRIVER_SETTING_ADDRESS  = '172.20.20.101'
+DRIVER_SETTING_PORT     = 6030
+DRIVER_SETTING_USERNAME = 'admin'
+DRIVER_SETTING_PASSWORD = 'admin'
+DRIVER_SETTING_USE_TLS  = False
+
+@pytest.fixture(scope='session')
+def driver() -> GnmiOpenConfigDriver:
+    _driver = GnmiOpenConfigDriver(
+        DRIVER_SETTING_ADDRESS, DRIVER_SETTING_PORT,
+        username=DRIVER_SETTING_USERNAME,
+        password=DRIVER_SETTING_PASSWORD,
+        use_tls=DRIVER_SETTING_USE_TLS,
+    )
+    _driver.Connect()
+    yield _driver
+    time.sleep(1)
+    _driver.Disconnect()
+
+
+##### STORAGE FIXTURE ##################################################################################################
+
+@pytest.fixture(scope='session')
+def storage() -> Dict:
+    yield Storage()
+
+
+##### NETWORK INSTANCE DETAILS #########################################################################################
+
+NETWORK_INSTANCES = [
+    {
+        'name': 'test-l3-svc',
+        'type': 'L3VRF',
+        'interfaces': [
+            {'name': 'Ethernet1',  'index': 0, 'ipv4_addr': '192.168.1.1',  'ipv4_prefix': 24, 'enabled': True},
+            {'name': 'Ethernet10', 'index': 0, 'ipv4_addr': '192.168.10.1', 'ipv4_prefix': 24, 'enabled': True},
+        ],
+        'static_routes': [
+            {'prefix': '172.0.0.0/24', 'next_hop': '172.16.0.2', 'metric': 1},
+            {'prefix': '172.2.0.0/24', 'next_hop': '172.16.0.3', 'metric': 1},
+        ]
+    },
+    #{
+    #    'name': 'test-l2-svc',
+    #    'type': 'L2VSI',
+    #    'interfaces': [
+    #        {'name': 'Ethernet2', 'index': 0, 'ipv4_addr': '192.168.1.1',  'ipv4_prefix': 24, 'enabled': True},
+    #        {'name': 'Ethernet4', 'index': 0, 'ipv4_addr': '192.168.10.1', 'ipv4_prefix': 24, 'enabled': True},
+    #    ],
+    #    'static_routes': [
+    #        {'prefix': '172.0.0.0/24', 'next_hop': '172.16.0.2', 'metric': 1},
+    #        {'prefix': '172.2.0.0/24', 'next_hop': '172.16.0.3', 'metric': 1},
+    #    ]
+    #}
+]
+
+
+##### TEST METHODS #####################################################################################################
+
+def test_get_endpoints(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    results_getconfig = get_config(driver, [RESOURCE_ENDPOINTS])
+    storage.endpoints.populate(results_getconfig)
+    check_config_endpoints(driver, storage)
+
+
+def test_get_interfaces(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    results_getconfig = get_config(driver, [RESOURCE_INTERFACES])
+    storage.interfaces.populate(results_getconfig)
+    check_config_interfaces(driver, storage)
+
+
+def test_get_network_instances(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    results_getconfig = get_config(driver, [RESOURCE_NETWORK_INSTANCES])
+    storage.network_instances.populate(results_getconfig)
+    check_config_network_instances(driver, storage)
+
+
+def test_set_network_instances(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    check_config_network_instances(driver, storage)
+
+    resources_to_set = list()
+    ni_names = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        ni_type = ni['type']
+        resources_to_set.append(network_instance(ni_name, ni_type))
+        ni_names.append(ni_name)
+        storage.network_instances.network_instances.add(ni_name, {'type': ni_type})
+        storage.network_instances.protocols.add(ni_name, 'DIRECTLY_CONNECTED')
+        storage.network_instances.tables.add(ni_name, 'DIRECTLY_CONNECTED', 'IPV4')
+        storage.network_instances.tables.add(ni_name, 'DIRECTLY_CONNECTED', 'IPV6')
+
+    results_setconfig = set_config(driver, resources_to_set)
+    check_updates(results_setconfig, '/network_instance[{:s}]', ni_names)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_add_interfaces_to_network_instance(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    check_config_network_instances(driver, storage)
+
+    resources_to_set = list()
+    ni_if_names = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        for ni_if in ni.get('interfaces', list()):
+            if_name     = ni_if['name' ]
+            subif_index = ni_if['index']
+            resources_to_set.append(network_instance_interface(ni_name, if_name, subif_index))
+            ni_if_names.append((ni_name, '{:s}.{:d}'.format(if_name, subif_index)))
+            storage.network_instances.interfaces.add(ni_name, if_name, subif_index)
+
+    results_setconfig = set_config(driver, resources_to_set)
+    check_updates(results_setconfig, '/network_instance[{:s}]/interface[{:s}]', ni_if_names)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_set_interfaces(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    check_config_network_instances(driver, storage)
+
+    resources_to_set = list()
+    if_names = list()
+    for ni in NETWORK_INSTANCES:
+        for ni_if in ni.get('interfaces', list()):
+            if_name      = ni_if['name'       ]
+            subif_index  = ni_if['index'      ]
+            ipv4_address = ni_if['ipv4_addr'  ]
+            ipv4_prefix  = ni_if['ipv4_prefix']
+            enabled      = ni_if['enabled'    ]
+            resources_to_set.append(interface(
+                if_name, subif_index, ipv4_address, ipv4_prefix, enabled
+            ))
+            if_names.append(if_name)
+            storage.interfaces.ipv4_addresses.add(if_name, subif_index, ipv4_address, {
+                'origin' : 'STATIC', 'prefix': ipv4_prefix
+            })
+            default_vlan = storage.network_instances.vlans.get('default', 1)
+            default_vlan_members : List[str] = default_vlan.setdefault('members', list())
+            if if_name in default_vlan_members: default_vlan_members.remove(if_name)
+
+    results_setconfig = set_config(driver, resources_to_set)
+    check_updates(results_setconfig, '/interface[{:s}]', if_names)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_set_network_instance_static_routes(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    check_config_network_instances(driver, storage)
+
+    resources_to_set = list()
+    ni_sr_prefixes = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        for ni_sr in ni.get('static_routes', list()):
+            ni_sr_prefix   = ni_sr['prefix'  ]
+            ni_sr_next_hop = ni_sr['next_hop']
+            ni_sr_metric   = ni_sr['metric'  ]
+            ni_sr_next_hop_index = 'AUTO_{:d}_{:s}'.format(ni_sr_metric, '-'.join(ni_sr_next_hop.split('.')))
+            resources_to_set.append(network_instance_static_route(
+                ni_name, ni_sr_prefix, ni_sr_next_hop_index, ni_sr_next_hop, metric=ni_sr_metric
+            ))
+            ni_sr_prefixes.append((ni_name, ni_sr_prefix))
+            storage.network_instances.protocols.add(ni_name, 'STATIC')
+            storage.network_instances.protocol_static.add(ni_name, 'STATIC', ni_sr_prefix, {
+                'prefix': ni_sr_prefix, 'next_hops': {
+                    ni_sr_next_hop_index: {'next_hop': ni_sr_next_hop, 'metric': ni_sr_metric}
+                }
+            })
+            storage.network_instances.tables.add(ni_name, 'STATIC', 'IPV4')
+            storage.network_instances.tables.add(ni_name, 'STATIC', 'IPV6')
+
+    results_setconfig = set_config(driver, resources_to_set)
+    check_updates(results_setconfig, '/network_instance[{:s}]/static_route[{:s}]', ni_sr_prefixes)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_del_network_instance_static_routes(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    check_config_network_instances(driver, storage)
+
+    resources_to_delete = list()
+    ni_sr_prefixes = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        for ni_sr in ni.get('static_routes', list()):
+            ni_sr_prefix   = ni_sr['prefix'  ]
+            ni_sr_next_hop = ni_sr['next_hop']
+            ni_sr_metric   = ni_sr['metric'  ]
+            ni_sr_next_hop_index = 'AUTO_{:d}_{:s}'.format(ni_sr_metric, '-'.join(ni_sr_next_hop.split('.')))
+            resources_to_delete.append(network_instance_static_route(
+                ni_name, ni_sr_prefix, ni_sr_next_hop_index, ni_sr_next_hop, metric=ni_sr_metric
+            ))
+            ni_sr_prefixes.append((ni_name, ni_sr_prefix))
+
+            storage.network_instances.protocols.remove(ni_name, 'STATIC')
+            storage.network_instances.protocol_static.remove(ni_name, 'STATIC', ni_sr_prefix)
+            storage.network_instances.tables.remove(ni_name, 'STATIC', 'IPV4')
+            storage.network_instances.tables.remove(ni_name, 'STATIC', 'IPV6')
+
+    results_deleteconfig = del_config(driver, resources_to_delete)
+    check_updates(results_deleteconfig, '/network_instance[{:s}]/static_route[{:s}]', ni_sr_prefixes)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    #check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_del_interfaces(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    #check_config_network_instances(driver, storage)
+
+    resources_to_delete = list()
+    if_names = list()
+    for ni in NETWORK_INSTANCES:
+        for ni_if in ni.get('interfaces', list()):
+            if_name      = ni_if['name'       ]
+            subif_index  = ni_if['index'      ]
+            ipv4_address = ni_if['ipv4_addr'  ]
+            ipv4_prefix  = ni_if['ipv4_prefix']
+            enabled      = ni_if['enabled'    ]
+            resources_to_delete.append(interface(if_name, subif_index, ipv4_address, ipv4_prefix, enabled))
+            if_names.append(if_name)
+            storage.interfaces.ipv4_addresses.remove(if_name, subif_index, ipv4_address)
+            default_vlan = storage.network_instances.vlans.get('default', 1)
+            default_vlan_members : List[str] = default_vlan.setdefault('members', list())
+            if if_name not in default_vlan_members: default_vlan_members.append(if_name)
+
+    results_deleteconfig = del_config(driver, resources_to_delete)
+    check_updates(results_deleteconfig, '/interface[{:s}]', if_names)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    #check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_del_interfaces_from_network_instance(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    #check_config_network_instances(driver, storage)
+
+    resources_to_delete = list()
+    ni_if_names = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        for ni_if in ni.get('interfaces', list()):
+            if_name     = ni_if['name' ]
+            subif_index = ni_if['index']
+            resources_to_delete.append(network_instance_interface(ni_name, if_name, subif_index))
+            ni_if_names.append((ni_name, '{:s}.{:d}'.format(if_name, subif_index)))
+            storage.network_instances.interfaces.remove(ni_name, if_name, subif_index)
+
+    results_deleteconfig = del_config(driver, resources_to_delete)
+    check_updates(results_deleteconfig, '/network_instance[{:s}]/interface[{:s}]', ni_if_names)
+    
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    #check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_del_network_instances(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    #check_config_network_instances(driver, storage)
+
+    resources_to_delete = list()
+    ni_names = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        ni_type = ni['type']
+        resources_to_delete.append(network_instance(ni_name, ni_type))
+        ni_names.append(ni_name)
+        storage.network_instances.network_instances.remove(ni_name)
+        storage.network_instances.protocols.remove(ni_name, 'DIRECTLY_CONNECTED')
+        storage.network_instances.tables.remove(ni_name, 'DIRECTLY_CONNECTED', 'IPV4')
+        storage.network_instances.tables.remove(ni_name, 'DIRECTLY_CONNECTED', 'IPV6')
+
+    results_deleteconfig = del_config(driver, resources_to_delete)
+    check_updates(results_deleteconfig, '/network_instance[{:s}]', ni_names)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
diff --git a/src/device/tests/gnmi_openconfig/test_unitary_gnmi_openconfig.py b/src/device/tests/gnmi_openconfig/test_unitary_gnmi_openconfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..1ec2e2f5f808ad5caa12c7dd1effb927bc4dd068
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/test_unitary_gnmi_openconfig.py
@@ -0,0 +1,360 @@
+# 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 os
+os.environ['DEVICE_EMULATED_ONLY'] = 'YES'
+
+# pylint: disable=wrong-import-position
+import logging, pytest, time
+from typing import Dict, List
+from device.service.driver_api._Driver import (
+    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES,
+    RESOURCE_ROUTING_POLICIES, RESOURCE_SERVICES
+)
+from device.service.drivers.gnmi_openconfig.GnmiOpenConfigDriver import GnmiOpenConfigDriver
+from .storage.Storage import Storage
+from .tools.manage_config import (
+    check_config_endpoints, check_config_interfaces, check_config_network_instances, del_config, get_config, set_config
+)
+from .tools.check_updates import check_updates
+from .tools.request_composers import (
+    interface, network_instance, network_instance_interface, network_instance_static_route
+)
+
+logging.basicConfig(level=logging.DEBUG)
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+
+##### DRIVER FIXTURE ###################################################################################################
+
+DRIVER_SETTING_ADDRESS  = '172.20.20.101'
+DRIVER_SETTING_PORT     = 6030
+DRIVER_SETTING_USERNAME = 'admin'
+DRIVER_SETTING_PASSWORD = 'admin'
+DRIVER_SETTING_USE_TLS  = False
+
+@pytest.fixture(scope='session')
+def driver() -> GnmiOpenConfigDriver:
+    _driver = GnmiOpenConfigDriver(
+        DRIVER_SETTING_ADDRESS, DRIVER_SETTING_PORT,
+        username=DRIVER_SETTING_USERNAME,
+        password=DRIVER_SETTING_PASSWORD,
+        use_tls=DRIVER_SETTING_USE_TLS,
+    )
+    _driver.Connect()
+    yield _driver
+    time.sleep(1)
+    _driver.Disconnect()
+
+
+##### STORAGE FIXTURE ##################################################################################################
+
+@pytest.fixture(scope='session')
+def storage() -> Dict:
+    yield Storage()
+
+
+##### NETWORK INSTANCE DETAILS #########################################################################################
+
+NETWORK_INSTANCES = [
+    {
+        'name': 'test-l3-svc',
+        'type': 'L3VRF',
+        'interfaces': [
+            {'name': 'Ethernet1',  'index': 0, 'ipv4_addr': '192.168.1.1',  'ipv4_prefix': 24, 'enabled': True},
+            {'name': 'Ethernet10', 'index': 0, 'ipv4_addr': '192.168.10.1', 'ipv4_prefix': 24, 'enabled': True},
+        ],
+        'static_routes': [
+            {'prefix': '172.0.0.0/24', 'next_hop': '172.16.0.2', 'metric': 1},
+            {'prefix': '172.2.0.0/24', 'next_hop': '172.16.0.3', 'metric': 1},
+        ]
+    },
+    #{
+    #    'name': 'test-l2-svc',
+    #    'type': 'L2VSI',
+    #    'interfaces': [
+    #        {'name': 'Ethernet2', 'index': 0, 'ipv4_addr': '192.168.1.1',  'ipv4_prefix': 24, 'enabled': True},
+    #        {'name': 'Ethernet4', 'index': 0, 'ipv4_addr': '192.168.10.1', 'ipv4_prefix': 24, 'enabled': True},
+    #    ],
+    #    'static_routes': [
+    #        {'prefix': '172.0.0.0/24', 'next_hop': '172.16.0.2', 'metric': 1},
+    #        {'prefix': '172.2.0.0/24', 'next_hop': '172.16.0.3', 'metric': 1},
+    #    ]
+    #}
+]
+
+
+##### TEST METHODS #####################################################################################################
+
+def test_get_endpoints(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    results_getconfig = get_config(driver, [RESOURCE_ENDPOINTS])
+    storage.endpoints.populate(results_getconfig)
+    check_config_endpoints(driver, storage)
+
+
+def test_get_interfaces(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    results_getconfig = get_config(driver, [RESOURCE_INTERFACES])
+    storage.interfaces.populate(results_getconfig)
+    check_config_interfaces(driver, storage)
+
+
+def test_get_network_instances(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    results_getconfig = get_config(driver, [RESOURCE_NETWORK_INSTANCES])
+    storage.network_instances.populate(results_getconfig)
+    check_config_network_instances(driver, storage)
+
+
+def test_set_network_instances(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    check_config_network_instances(driver, storage)
+
+    resources_to_set = list()
+    ni_names = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        ni_type = ni['type']
+        resources_to_set.append(network_instance(ni_name, ni_type))
+        ni_names.append(ni_name)
+        storage.network_instances.network_instances.add(ni_name, {'type': ni_type})
+        storage.network_instances.protocols.add(ni_name, 'DIRECTLY_CONNECTED')
+        storage.network_instances.tables.add(ni_name, 'DIRECTLY_CONNECTED', 'IPV4')
+        storage.network_instances.tables.add(ni_name, 'DIRECTLY_CONNECTED', 'IPV6')
+
+    results_setconfig = set_config(driver, resources_to_set)
+    check_updates(results_setconfig, '/network_instance[{:s}]', ni_names)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_add_interfaces_to_network_instance(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    check_config_network_instances(driver, storage)
+
+    resources_to_set = list()
+    ni_if_names = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        for ni_if in ni.get('interfaces', list()):
+            if_name     = ni_if['name' ]
+            subif_index = ni_if['index']
+            resources_to_set.append(network_instance_interface(ni_name, if_name, subif_index))
+            ni_if_names.append((ni_name, '{:s}.{:d}'.format(if_name, subif_index)))
+            storage.network_instances.interfaces.add(ni_name, if_name, subif_index)
+
+    results_setconfig = set_config(driver, resources_to_set)
+    check_updates(results_setconfig, '/network_instance[{:s}]/interface[{:s}]', ni_if_names)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_set_interfaces(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    check_config_network_instances(driver, storage)
+
+    resources_to_set = list()
+    if_names = list()
+    for ni in NETWORK_INSTANCES:
+        for ni_if in ni.get('interfaces', list()):
+            if_name      = ni_if['name'       ]
+            subif_index  = ni_if['index'      ]
+            ipv4_address = ni_if['ipv4_addr'  ]
+            ipv4_prefix  = ni_if['ipv4_prefix']
+            enabled      = ni_if['enabled'    ]
+            resources_to_set.append(interface(
+                if_name, subif_index, ipv4_address, ipv4_prefix, enabled
+            ))
+            if_names.append(if_name)
+            storage.interfaces.ipv4_addresses.add(if_name, subif_index, ipv4_address, {
+                'origin' : 'STATIC', 'prefix': ipv4_prefix
+            })
+            default_vlan = storage.network_instances.vlans.get('default', 1)
+            default_vlan_members : List[str] = default_vlan.setdefault('members', list())
+            if if_name in default_vlan_members: default_vlan_members.remove(if_name)
+
+    results_setconfig = set_config(driver, resources_to_set)
+    check_updates(results_setconfig, '/interface[{:s}]', if_names)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_set_network_instance_static_routes(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    check_config_network_instances(driver, storage)
+
+    resources_to_set = list()
+    ni_sr_prefixes = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        for ni_sr in ni.get('static_routes', list()):
+            ni_sr_prefix   = ni_sr['prefix'  ]
+            ni_sr_next_hop = ni_sr['next_hop']
+            ni_sr_metric   = ni_sr['metric'  ]
+            ni_sr_next_hop_index = 'AUTO_{:d}_{:s}'.format(ni_sr_metric, '-'.join(ni_sr_next_hop.split('.')))
+            resources_to_set.append(network_instance_static_route(
+                ni_name, ni_sr_prefix, ni_sr_next_hop_index, ni_sr_next_hop, metric=ni_sr_metric
+            ))
+            ni_sr_prefixes.append((ni_name, ni_sr_prefix))
+            storage.network_instances.protocols.add(ni_name, 'STATIC')
+            storage.network_instances.protocol_static.add(ni_name, 'STATIC', ni_sr_prefix, {
+                'prefix': ni_sr_prefix, 'next_hops': {
+                    ni_sr_next_hop_index: {'next_hop': ni_sr_next_hop, 'metric': ni_sr_metric}
+                }
+            })
+            storage.network_instances.tables.add(ni_name, 'STATIC', 'IPV4')
+            storage.network_instances.tables.add(ni_name, 'STATIC', 'IPV6')
+
+    results_setconfig = set_config(driver, resources_to_set)
+    check_updates(results_setconfig, '/network_instance[{:s}]/static_route[{:s}]', ni_sr_prefixes)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_del_network_instance_static_routes(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    check_config_network_instances(driver, storage)
+
+    resources_to_delete = list()
+    ni_sr_prefixes = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        for ni_sr in ni.get('static_routes', list()):
+            ni_sr_prefix   = ni_sr['prefix'  ]
+            ni_sr_next_hop = ni_sr['next_hop']
+            ni_sr_metric   = ni_sr['metric'  ]
+            ni_sr_next_hop_index = 'AUTO_{:d}_{:s}'.format(ni_sr_metric, '-'.join(ni_sr_next_hop.split('.')))
+            resources_to_delete.append(network_instance_static_route(
+                ni_name, ni_sr_prefix, ni_sr_next_hop_index, ni_sr_next_hop, metric=ni_sr_metric
+            ))
+            ni_sr_prefixes.append((ni_name, ni_sr_prefix))
+
+            storage.network_instances.protocols.remove(ni_name, 'STATIC')
+            storage.network_instances.protocol_static.remove(ni_name, 'STATIC', ni_sr_prefix)
+            storage.network_instances.tables.remove(ni_name, 'STATIC', 'IPV4')
+            storage.network_instances.tables.remove(ni_name, 'STATIC', 'IPV6')
+
+    results_deleteconfig = del_config(driver, resources_to_delete)
+    check_updates(results_deleteconfig, '/network_instance[{:s}]/static_route[{:s}]', ni_sr_prefixes)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    #check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_del_interfaces(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    #check_config_network_instances(driver, storage)
+
+    resources_to_delete = list()
+    if_names = list()
+    for ni in NETWORK_INSTANCES:
+        for ni_if in ni.get('interfaces', list()):
+            if_name      = ni_if['name'       ]
+            subif_index  = ni_if['index'      ]
+            ipv4_address = ni_if['ipv4_addr'  ]
+            ipv4_prefix  = ni_if['ipv4_prefix']
+            enabled      = ni_if['enabled'    ]
+            resources_to_delete.append(interface(if_name, subif_index, ipv4_address, ipv4_prefix, enabled))
+            if_names.append(if_name)
+            storage.interfaces.ipv4_addresses.remove(if_name, subif_index, ipv4_address)
+            default_vlan = storage.network_instances.vlans.get('default', 1)
+            default_vlan_members : List[str] = default_vlan.setdefault('members', list())
+            if if_name not in default_vlan_members: default_vlan_members.append(if_name)
+
+    results_deleteconfig = del_config(driver, resources_to_delete)
+    check_updates(results_deleteconfig, '/interface[{:s}]', if_names)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    #check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_del_interfaces_from_network_instance(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    #check_config_network_instances(driver, storage)
+
+    resources_to_delete = list()
+    ni_if_names = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        for ni_if in ni.get('interfaces', list()):
+            if_name     = ni_if['name' ]
+            subif_index = ni_if['index']
+            resources_to_delete.append(network_instance_interface(ni_name, if_name, subif_index))
+            ni_if_names.append((ni_name, '{:s}.{:d}'.format(if_name, subif_index)))
+            storage.network_instances.interfaces.remove(ni_name, if_name, subif_index)
+
+    results_deleteconfig = del_config(driver, resources_to_delete)
+    check_updates(results_deleteconfig, '/network_instance[{:s}]/interface[{:s}]', ni_if_names)
+    
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    #check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
+
+
+def test_del_network_instances(
+    driver : GnmiOpenConfigDriver,  # pylint: disable=redefined-outer-name
+    storage : Storage,              # pylint: disable=redefined-outer-name
+) -> None:
+    check_config_interfaces(driver, storage)
+    #check_config_network_instances(driver, storage)
+
+    resources_to_delete = list()
+    ni_names = list()
+    for ni in NETWORK_INSTANCES:
+        ni_name = ni['name']
+        ni_type = ni['type']
+        resources_to_delete.append(network_instance(ni_name, ni_type))
+        ni_names.append(ni_name)
+        storage.network_instances.network_instances.remove(ni_name)
+        storage.network_instances.protocols.remove(ni_name, 'DIRECTLY_CONNECTED')
+        storage.network_instances.tables.remove(ni_name, 'DIRECTLY_CONNECTED', 'IPV4')
+        storage.network_instances.tables.remove(ni_name, 'DIRECTLY_CONNECTED', 'IPV6')
+
+    results_deleteconfig = del_config(driver, resources_to_delete)
+    check_updates(results_deleteconfig, '/network_instance[{:s}]', ni_names)
+
+    check_config_interfaces(driver, storage, max_retries=10, retry_delay=2.0)
+    check_config_network_instances(driver, storage, max_retries=10, retry_delay=2.0)
diff --git a/src/device/tests/gnmi_openconfig/tools/__init__.py b/src/device/tests/gnmi_openconfig/tools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ee6f7071f145e06c3aeaefc09a43ccd88e619e3
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/tools/__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/device/tests/gnmi_openconfig/tools/check_updates.py b/src/device/tests/gnmi_openconfig/tools/check_updates.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e120ab89ac508623ef27b6e6a6f792b6c565840
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/tools/check_updates.py
@@ -0,0 +1,22 @@
+# 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 Iterable, List, Tuple
+
+def check_updates(results : Iterable[Tuple[str, bool]], format_str : str, item_ids : List[Tuple]) -> None:
+    results = set(results)
+    assert len(results) == len(item_ids)
+    for item_id_fields in item_ids:
+        if isinstance(item_id_fields, (str, int, float, bool)): item_id_fields = (item_id_fields,)
+        assert (format_str.format(*item_id_fields), True) in results
diff --git a/src/device/tests/gnmi_openconfig/tools/manage_config.py b/src/device/tests/gnmi_openconfig/tools/manage_config.py
new file mode 100644
index 0000000000000000000000000000000000000000..6dc485bf256236bf9438536e9182181f784faacd
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/tools/manage_config.py
@@ -0,0 +1,103 @@
+# 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 copy, deepdiff, logging, time
+from typing import Callable, Dict, List, Tuple, Union
+from device.service.driver_api._Driver import (
+    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES,
+    RESOURCE_ROUTING_POLICIES, RESOURCE_SERVICES
+)
+from device.service.drivers.gnmi_openconfig.GnmiOpenConfigDriver import GnmiOpenConfigDriver
+from device.tests.gnmi_openconfig.storage.Storage import Storage
+from .result_config_adapters import adapt_endpoint, adapt_interface, adapt_network_instance
+
+LOGGER = logging.getLogger(__name__)
+
+def get_config(driver : GnmiOpenConfigDriver, resources_to_get : List[str]) -> List[Tuple[str, Dict]]:
+    LOGGER.info('[get_config] resources_to_get = {:s}'.format(str(resources_to_get)))
+    results_getconfig = driver.GetConfig(resources_to_get)
+    LOGGER.info('[get_config] results_getconfig = {:s}'.format(str(results_getconfig)))
+    return results_getconfig
+
+def set_config(
+    driver : GnmiOpenConfigDriver, resources_to_set : List[Tuple[str, Dict]]
+) -> List[Tuple[str, Union[bool, Exception]]]:
+    LOGGER.info('[set_config] resources_to_set = {:s}'.format(str(resources_to_set)))
+    results_setconfig = driver.SetConfig(resources_to_set)
+    LOGGER.info('[set_config] results_setconfig = {:s}'.format(str(results_setconfig)))
+    return results_setconfig
+
+def del_config(
+    driver : GnmiOpenConfigDriver, resources_to_delete : List[Tuple[str, Dict]]
+) -> List[Tuple[str, Union[bool, Exception]]]:
+    LOGGER.info('resources_to_delete = {:s}'.format(str(resources_to_delete)))
+    results_deleteconfig = driver.DeleteConfig(resources_to_delete)
+    LOGGER.info('results_deleteconfig = {:s}'.format(str(results_deleteconfig)))
+    return results_deleteconfig
+
+def check_expected_config(
+    driver : GnmiOpenConfigDriver, resources_to_get : List[str], expected_config : List[Dict],
+    func_adapt_returned_config : Callable[[Tuple[str, Dict]], Tuple[str, Dict]] = lambda x: x,
+    max_retries : int = 1, retry_delay : float = 0.5
+) -> List[Dict]:
+    LOGGER.info('expected_config = {:s}'.format(str(expected_config)))
+
+    num_retry = 0
+    return_data = None
+    while num_retry < max_retries:
+        results_getconfig = get_config(driver, resources_to_get)
+        return_data = copy.deepcopy(results_getconfig)
+
+        results_getconfig = [
+            func_adapt_returned_config(resource_key, resource_value)
+            for resource_key, resource_value in results_getconfig
+        ]
+
+        diff_data = deepdiff.DeepDiff(sorted(expected_config), sorted(results_getconfig))
+        num_diffs = len(diff_data)
+        if num_diffs == 0: break
+        # let the device take some time to reconfigure
+        time.sleep(retry_delay)
+        num_retry += 1
+
+    if num_diffs > 0: LOGGER.error('Differences[{:d}]:\n{:s}'.format(num_diffs, str(diff_data.pretty())))
+    assert num_diffs == 0
+    return return_data
+
+def check_config_endpoints(
+    driver : GnmiOpenConfigDriver, storage : Storage,
+    max_retries : int = 1, retry_delay : float = 0.5
+) -> List[Dict]:
+    return check_expected_config(
+        driver, [RESOURCE_ENDPOINTS], storage.endpoints.get_expected_config(),
+        adapt_endpoint, max_retries=max_retries, retry_delay=retry_delay
+    )
+
+def check_config_interfaces(
+    driver : GnmiOpenConfigDriver, storage : Storage,
+    max_retries : int = 1, retry_delay : float = 0.5
+) -> List[Dict]:
+    return check_expected_config(
+        driver, [RESOURCE_INTERFACES], storage.interfaces.get_expected_config(),
+        adapt_interface, max_retries=max_retries, retry_delay=retry_delay
+    )
+
+def check_config_network_instances(
+    driver : GnmiOpenConfigDriver, storage : Storage,
+    max_retries : int = 1, retry_delay : float = 0.5
+) -> List[Dict]:
+    return check_expected_config(
+        driver, [RESOURCE_NETWORK_INSTANCES], storage.network_instances.get_expected_config(),
+        adapt_network_instance, max_retries=max_retries, retry_delay=retry_delay
+    )
diff --git a/src/device/tests/gnmi_openconfig/tools/request_composers copy.py b/src/device/tests/gnmi_openconfig/tools/request_composers copy.py
new file mode 100644
index 0000000000000000000000000000000000000000..9545e156df2c88ea1c86f094b770e09328b368e6
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/tools/request_composers copy.py	
@@ -0,0 +1,46 @@
+# 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 Dict, Tuple
+
+def interface(if_name, sif_index, ipv4_address, ipv4_prefix, enabled) -> Tuple[str, Dict]:
+    str_path = '/interface[{:s}]'.format(if_name)
+    str_data = {
+        'name': if_name, 'enabled': enabled, 'sub_if_index': sif_index, 'sub_if_enabled': enabled,
+        'sub_if_ipv4_enabled': enabled, 'sub_if_ipv4_address': ipv4_address, 'sub_if_ipv4_prefix': ipv4_prefix
+    }
+    return str_path, str_data
+
+def network_instance(ni_name, ni_type) -> Tuple[str, Dict]:
+    str_path = '/network_instance[{:s}]'.format(ni_name)
+    str_data = {
+        'name': ni_name, 'type': ni_type
+    }
+    return str_path, str_data
+
+def network_instance_static_route(ni_name, prefix, next_hop_index, next_hop, metric=1) -> Tuple[str, Dict]:
+    str_path = '/network_instance[{:s}]/static_route[{:s}]'.format(ni_name, prefix)
+    str_data = {
+        'name': ni_name, 'identifier': 'STATIC', 'protocol_name': 'STATIC',
+        'prefix': prefix, 'index': next_hop_index, 'next_hop': next_hop, 'metric': metric
+    }
+    return str_path, str_data
+
+def network_instance_interface(ni_name, if_name, sif_index) -> Tuple[str, Dict]:
+    ni_if_id = '{:s}.{:d}'.format(if_name, sif_index)
+    str_path = '/network_instance[{:s}]/interface[{:s}]'.format(ni_name, ni_if_id)
+    str_data = {
+        'name': ni_name, 'id': ni_if_id, 'interface': if_name, 'subinterface': sif_index
+    }
+    return str_path, str_data
diff --git a/src/device/tests/gnmi_openconfig/tools/request_composers.py b/src/device/tests/gnmi_openconfig/tools/request_composers.py
new file mode 100644
index 0000000000000000000000000000000000000000..d80709114bdf36c1e634047256c7e42d638de3c5
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/tools/request_composers.py
@@ -0,0 +1,44 @@
+# 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 Dict, Tuple
+
+def interface(if_name, sif_index, ipv4_address, ipv4_prefix, enabled) -> Tuple[str, Dict]:
+    str_path = '/interface[{:s}]'.format(if_name)
+    str_data = {
+        'name': if_name, 'enabled': enabled, 'sub_if_index': sif_index, 'sub_if_enabled': enabled,
+        'sub_if_ipv4_enabled': enabled, 'sub_if_ipv4_address': ipv4_address, 'sub_if_ipv4_prefix': ipv4_prefix
+    }
+    return str_path, str_data
+
+def network_instance(ni_name, ni_type) -> Tuple[str, Dict]:
+    str_path = '/network_instance[{:s}]'.format(ni_name)
+    str_data = {
+        'name': ni_name, 'type': ni_type
+    }
+    return str_path, str_data
+
+def network_instance_static_route(ni_name, prefix, next_hop_index, next_hop, metric=1) -> Tuple[str, Dict]:
+    str_path = '/network_instance[{:s}]/static_route[{:s}]'.format(ni_name, prefix)
+    str_data = {
+        'name': ni_name, 'prefix': prefix, 'next_hop_index': next_hop_index, 'next_hop': next_hop, 'metric': metric
+    }
+    return str_path, str_data
+
+def network_instance_interface(ni_name, if_name, sif_index) -> Tuple[str, Dict]:
+    str_path = '/network_instance[{:s}]/interface[{:s}.{:d}]'.format(ni_name, if_name, sif_index)
+    str_data = {
+        'name': ni_name, 'if_name': if_name, 'sif_index': sif_index
+    }
+    return str_path, str_data
diff --git a/src/device/tests/gnmi_openconfig/tools/result_config_adapters.py b/src/device/tests/gnmi_openconfig/tools/result_config_adapters.py
new file mode 100644
index 0000000000000000000000000000000000000000..db7d5735d05eba9e4b8a2bec3b2763bdb3c3cc42
--- /dev/null
+++ b/src/device/tests/gnmi_openconfig/tools/result_config_adapters.py
@@ -0,0 +1,29 @@
+# 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 re
+from typing import Dict, Tuple
+
+def adapt_endpoint(resource_key : str, resource_value : Dict) -> Tuple[str, Dict]:
+    return resource_key, resource_value
+
+def adapt_interface(resource_key : str, resource_value : Dict) -> Tuple[str, Dict]:
+    return resource_key, resource_value
+
+def adapt_network_instance(resource_key : str, resource_value : Dict) -> Tuple[str, Dict]:
+    match = re.match(r'^\/network\_instance\[([^\]]+)\]\/vlan\[([^\]]+)\]$', resource_key)
+    if match is not None:
+        members = resource_value.get('members')
+        if len(members) > 0: resource_value['members'] = sorted(members)
+    return resource_key, resource_value
diff --git a/src/device/tests/test_gnmi.py b/src/device/tests/test_gnmi.py
deleted file mode 100644
index ebd026a206ddf9444d30c01e8ac2d097307cc0db..0000000000000000000000000000000000000000
--- a/src/device/tests/test_gnmi.py
+++ /dev/null
@@ -1,115 +0,0 @@
-# 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 logging, os, sys, time
-from typing import Dict, Tuple
-os.environ['DEVICE_EMULATED_ONLY'] = 'YES'
-from device.service.drivers.gnmi_openconfig.GnmiOpenConfigDriver import GnmiOpenConfigDriver # pylint: disable=wrong-import-position
-#from device.service.driver_api._Driver import (
-#    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_SERVICES
-#)
-
-logging.basicConfig(level=logging.DEBUG)
-LOGGER = logging.getLogger(__name__)
-LOGGER.setLevel(logging.DEBUG)
-
-# +---+---------------------------+--------------+---------------------------------+-------+---------+--------------------+--------------+
-# | # |           Name            | Container ID |              Image              | Kind  |  State  |    IPv4 Address    | IPv6 Address |
-# +---+---------------------------+--------------+---------------------------------+-------+---------+--------------------+--------------+
-# | 1 | clab-tfs-scenario-client1 | a8d48ec3265a | ghcr.io/hellt/network-multitool | linux | running | 172.100.100.201/24 | N/A          |
-# | 2 | clab-tfs-scenario-client2 | fc88436d2b32 | ghcr.io/hellt/network-multitool | linux | running | 172.100.100.202/24 | N/A          |
-# | 3 | clab-tfs-scenario-srl1    | b995b9bdadda | ghcr.io/nokia/srlinux           | srl   | running | 172.100.100.101/24 | N/A          |
-# | 4 | clab-tfs-scenario-srl2    | aacfc38cc376 | ghcr.io/nokia/srlinux           | srl   | running | 172.100.100.102/24 | N/A          |
-# +---+---------------------------+--------------+---------------------------------+-------+---------+--------------------+--------------+
-
-def interface(if_name, sif_index, ipv4_address, ipv4_prefix, enabled) -> Tuple[str, Dict]:
-    str_path = '/interface[{:s}]'.format(if_name)
-    str_data = {'name': if_name, 'enabled': enabled, 'sub_if_index': sif_index, 'sub_if_enabled': enabled,
-                'sub_if_ipv4_enabled': enabled, 'sub_if_ipv4_address': ipv4_address, 'sub_if_ipv4_prefix': ipv4_prefix}
-    return str_path, str_data
-
-def network_instance(ni_name, ni_type) -> Tuple[str, Dict]:
-    str_path = '/network_instance[{:s}]'.format(ni_name)
-    str_data = {'name': ni_name, 'type': ni_type}
-    return str_path, str_data
-
-def network_instance_static_route(ni_name, prefix, next_hop, next_hop_index=0) -> Tuple[str, Dict]:
-    str_path = '/network_instance[{:s}]/static_route[{:s}]'.format(ni_name, prefix)
-    str_data = {'name': ni_name, 'prefix': prefix, 'next_hop': next_hop, 'next_hop_index': next_hop_index}
-    return str_path, str_data
-
-def network_instance_interface(ni_name, if_name, sif_index) -> Tuple[str, Dict]:
-    str_path = '/network_instance[{:s}]/interface[{:s}.{:d}]'.format(ni_name, if_name, sif_index)
-    str_data = {'name': ni_name, 'if_name': if_name, 'sif_index': sif_index}
-    return str_path, str_data
-
-def main():
-    driver_settings = {
-        'protocol': 'gnmi',
-        'username': 'admin',
-        'password': 'NokiaSrl1!',
-        'use_tls' : True,
-    }
-    driver = GnmiOpenConfigDriver('172.100.100.102', 57400, **driver_settings)
-    driver.Connect()
-
-    #resources_to_get = []
-    #resources_to_get = [RESOURCE_ENDPOINTS]
-    #resources_to_get = [RESOURCE_INTERFACES]
-    #resources_to_get = [RESOURCE_NETWORK_INSTANCES]
-    #resources_to_get = [RESOURCE_ROUTING_POLICIES]
-    #resources_to_get = [RESOURCE_SERVICES]
-    #LOGGER.info('resources_to_get = {:s}'.format(str(resources_to_get)))
-    #results_getconfig = driver.GetConfig(resources_to_get)
-    #LOGGER.info('results_getconfig = {:s}'.format(str(results_getconfig)))
-
-    #resources_to_set = [
-    #    network_instance('test-svc', 'L3VRF'),
-    #
-    #    interface('ethernet-1/1', 0, '172.16.0.1', 24, True),
-    #    network_instance_interface('test-svc', 'ethernet-1/1', 0),
-    #
-    #    interface('ethernet-1/2', 0, '172.0.0.1', 24, True),
-    #    network_instance_interface('test-svc', 'ethernet-1/2', 0),
-    #
-    #    network_instance_static_route('test-svc', '172.0.0.0/24', '172.16.0.2'),
-    #    network_instance_static_route('test-svc', '172.2.0.0/24', '172.16.0.3'),
-    #]
-    #LOGGER.info('resources_to_set = {:s}'.format(str(resources_to_set)))
-    #results_setconfig = driver.SetConfig(resources_to_set)
-    #LOGGER.info('results_setconfig = {:s}'.format(str(results_setconfig)))
-
-    resources_to_delete = [
-        #network_instance_static_route('d35fc1d9', '172.0.0.0/24', '172.16.0.2'),
-        #network_instance_static_route('d35fc1d9', '172.2.0.0/24', '172.16.0.3'),
-    
-        #network_instance_interface('d35fc1d9', 'ethernet-1/1', 0),
-        #network_instance_interface('d35fc1d9', 'ethernet-1/2', 0),
-    
-        interface('ethernet-1/1', 0, '172.16.1.1', 24, True),
-        interface('ethernet-1/2', 0, '172.0.0.2', 24, True),
-    
-        network_instance('20f66fb5', 'L3VRF'),
-    ]
-    LOGGER.info('resources_to_delete = {:s}'.format(str(resources_to_delete)))
-    results_deleteconfig = driver.DeleteConfig(resources_to_delete)
-    LOGGER.info('results_deleteconfig = {:s}'.format(str(results_deleteconfig)))
-
-    time.sleep(1)
-
-    driver.Disconnect()
-    return 0
-
-if __name__ == '__main__':
-    sys.exit(main())
diff --git a/src/monitoring/service/EventTools.py b/src/monitoring/service/EventTools.py
index 7820f11c86e87f543087c88704572e1a169c6e7d..2ad31c9cb7df68e2b57d280aa5cdcf356376d8c6 100644
--- a/src/monitoring/service/EventTools.py
+++ b/src/monitoring/service/EventTools.py
@@ -108,12 +108,15 @@ class EventsDeviceCollector:
                         if config_rule.action != ConfigActionEnum.CONFIGACTION_SET: continue
                         if config_rule.WhichOneof('config_rule') != 'custom': continue
                         str_resource_key = str(config_rule.custom.resource_key)
-                        if not str_resource_key.startswith('/interface['): continue
-                        json_resource_value = json.loads(config_rule.custom.resource_value)
-                        if 'name' not in json_resource_value: continue
-                        if 'enabled' not in json_resource_value: continue
-                        if not json_resource_value['enabled']: continue
-                        enabled_endpoint_names.add(json_resource_value['name'])
+                        if str_resource_key.startswith('/interface[') or str_resource_key.startswith('/endpoints/endpoint['):
+                            json_resource_value = json.loads(config_rule.custom.resource_value)
+                            if 'name' not in json_resource_value: continue
+                            if 'enabled' in json_resource_value:
+                                if not json_resource_value['enabled']: continue
+                                enabled_endpoint_names.add(json_resource_value['name'])
+                            if 'oper-status' in json_resource_value:
+                                if str(json_resource_value['oper-status']).upper() != 'UP': continue
+                                enabled_endpoint_names.add(json_resource_value['name'])
 
                     endpoints_monitored = self._device_endpoint_monitored.setdefault(device_uuid, dict())
                     for endpoint in device.device_endpoints:
@@ -127,7 +130,10 @@ class EventsDeviceCollector:
                         endpoint_was_monitored = endpoints_monitored.get(endpoint_uuid, False)
                         endpoint_is_enabled = (endpoint_name_or_uuid in enabled_endpoint_names)
 
-                        if not endpoint_was_monitored and endpoint_is_enabled:
+                        if not endpoint_was_monitored and not endpoint_is_enabled:
+                            # endpoint is idle, do nothing
+                            pass
+                        elif not endpoint_was_monitored and endpoint_is_enabled:
                             # activate
                             for value in endpoint.kpi_sample_types:
                                 if value == KPISAMPLETYPE_UNKNOWN: continue
diff --git a/src/nbi/service/rest_server/nbi_plugins/ietf_l3vpn/Handlers.py b/src/nbi/service/rest_server/nbi_plugins/ietf_l3vpn/Handlers.py
index f7329cb35666f423e85f99510e5f89a82e89b7f8..1f399070aa2dbd0f9b22d32e15574b7bc38315ff 100644
--- a/src/nbi/service/rest_server/nbi_plugins/ietf_l3vpn/Handlers.py
+++ b/src/nbi/service/rest_server/nbi_plugins/ietf_l3vpn/Handlers.py
@@ -195,11 +195,17 @@ def process_site(site : Dict, errors : List[Dict]) -> None:
 
     # site_static_routing: (lan-range, lan-prefix-len, lan-tag) => next-hop
     site_static_routing : Dict[Tuple[str, str], str] = {}
-    for rt_proto in site['routing-protocols']['routing-protocol']:
+    site_routing_protocols : Dict = site.get('routing-protocols', dict())
+    site_routing_protocol : List = site_routing_protocols.get('routing-protocol', list())
+    for rt_proto in site_routing_protocol:
         if rt_proto['type'] != 'ietf-l3vpn-svc:static':
             MSG = 'Site Routing Protocol Type: {:s}'
             raise NotImplementedError(MSG.format(str(rt_proto['type'])))
-        for ipv4_rt in rt_proto['static']['cascaded-lan-prefixes']['ipv4-lan-prefixes']:
+        
+        rt_proto_static : Dict = rt_proto.get('static', dict())
+        rt_proto_static_clps : Dict = rt_proto_static.get('cascaded-lan-prefixes', dict())
+        rt_proto_static_clps_v4 = rt_proto_static_clps.get('ipv4-lan-prefixes', list())
+        for ipv4_rt in rt_proto_static_clps_v4:
             lan_range, lan_prefix = ipv4_rt['lan'].split('/')
             lan_prefix = int(lan_prefix)
             lan_tag   = int(ipv4_rt['lan-tag'].replace('vlan', ''))
diff --git a/src/nbi/service/rest_server/nbi_plugins/ietf_l3vpn/L3VPN_Service.py b/src/nbi/service/rest_server/nbi_plugins/ietf_l3vpn/L3VPN_Service.py
index a313677c12203c1621b920f3fcb7f6ff0c281bfb..47fb05d5571b440e867e776a753f556c3130b119 100644
--- a/src/nbi/service/rest_server/nbi_plugins/ietf_l3vpn/L3VPN_Service.py
+++ b/src/nbi/service/rest_server/nbi_plugins/ietf_l3vpn/L3VPN_Service.py
@@ -44,7 +44,7 @@ class L3VPN_Service(Resource):
 
             service_ready_status = ServiceStatusEnum.SERVICESTATUS_ACTIVE
             service_status = target.service_status.service_status # pylint: disable=no-member
-            response = jsonify({})
+            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)))
diff --git a/src/opticalcontroller/OpticalController.py b/src/opticalcontroller/OpticalController.py
index 0febb7b1f470bf86dc30754c1db2af262779a25d..97e097c8a94382b71903b4a57ab66382beec5eb2 100644
--- a/src/opticalcontroller/OpticalController.py
+++ b/src/opticalcontroller/OpticalController.py
@@ -12,19 +12,21 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import time
 from flask import Flask
 from flask import render_template
 from flask_restplus import Resource, Api
-
 from tools import *
 from variables import *
 from RSA import RSA
-import time
-import logging
+from common.proto.context_pb2 import TopologyId
+from google.protobuf.json_format import MessageToDict
 
 
+global rsa
+global links_dict
 rsa = None
-LOGGER = logging.getLogger(__name__)
+
 
 app = Flask(__name__)
 api = Api(app, version='1.0', title='Optical controller API',
@@ -47,7 +49,7 @@ class AddLightpath(Resource):
     @staticmethod
     def put(src, dst, bitrate, bidir=1):
 
-        LOGGER.info("INFO: New Lightpath request from {} to {} with rate {} ".format(src, dst, bitrate))
+        print("INFO: New Lightpath request from {} to {} with rate {} ".format(src, dst, bitrate))
         t0 = time.time()*1000.0
         if debug:
             rsa.g.printGraph()
@@ -56,9 +58,9 @@ class AddLightpath(Resource):
             flow_id = rsa.rsa_computation(src, dst, bitrate, bidir)
             if rsa.db_flows[flow_id]["op-mode"] == 0:
                 return 'No path found', 404
-            t1 = time.time()*1000.0
+            t1 = time.time() * 1000.0
             elapsed = t1 - t0
-            LOGGER.info("INFO: time elapsed = {} ms".format(elapsed))
+            print("INFO: time elapsed = {} ms".format(elapsed))
             return rsa.db_flows[flow_id], 200
         else:
             return "Error", 404
@@ -74,18 +76,15 @@ class AddLightpath(Resource):
 @optical.response(404, 'Error, not found')
 class AddFlexLightpath(Resource):
     @staticmethod
-    def put(src, dst, bitrate,bidir=1, band=None):
-        
+    def put(src, dst, bitrate, bidir=1, band=None):
+
         print("INFO: New FlexLightpath request from {} to {} with rate {} ".format(src, dst, bitrate))
-        LOGGER.info("INFO: New FlexLightpath request from {} to {} with rate {} ".format(src, dst, bitrate))
         t0 = time.time()*1000.0
         if debug:
             rsa.g.printGraph()
 
         if rsa is not None:
             flow_id, optical_band_id = rsa.rsa_fs_computation(src, dst, bitrate, bidir, band)
-            print (f"flow_id {flow_id} and optical_band_id {optical_band_id} ")
-            LOGGER.debug('flow_id={:s} rsa.db_flows={:s}'.format(str(flow_id), str(rsa.db_flows)))
             if flow_id is not None:
                 if rsa.db_flows[flow_id]["op-mode"] == 0:
                     return 'No path found', 404
@@ -100,52 +99,125 @@ class AddFlexLightpath(Resource):
                 else:
                     t1 = time.time() * 1000.0
                     elapsed = t1 - t0
-                    LOGGER.info("INFO: time elapsed = {} ms".format(elapsed))
+                    print("INFO: time elapsed = {} ms".format(elapsed))
 
                     return rsa.optical_bands[optical_band_id], 200
         else:
             return "Error", 404
 
-@optical.route('/DelFlexLightpath/<int:flow_id>/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>')
+
+# @optical.route('/DelFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>')
+@optical.route('/DelFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>')
+@optical.route('/DelFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:o_band_id>/<int:flow_id>')
 @optical.response(200, 'Success')
 @optical.response(404, 'Error, not found')
-class DelLightpath(Resource):
+class DelFLightpath(Resource):
     @staticmethod
-    def delete(flow_id, src, dst, bitrate, o_band_id):
-        if flow_id in rsa.db_flows.keys():
-            flow = rsa.db_flows[flow_id]
-            bidir = flow["bidir"]
-            match1 = flow["src"] == src and flow["dst"] == dst and flow["bitrate"] == bitrate
-            if bidir:
-                match2 = flow["src"] == dst and flow["dst"] == src and flow["bitrate"] == bitrate
-                if match1 or match2:
-                    ob_id = flow["parent_opt_band"]
-                    rsa.del_flow(flow, ob_id)
-                    rsa.db_flows[flow_id]["is_active"] = False
-                    rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id)
-                    if rsa.optical_bands[ob_id]["reverse_optical_band_id"] != 0:
-                        rev_ob_id = rsa.optical_bands[ob_id]["reverse_optical_band_id"]
-                        rsa.optical_bands[rev_ob_id]["served_lightpaths"].remove(flow_id)
-
-                    if debug:
-                       LOGGER.info(links_dict)
-                    return "flow {} deleted".format(flow_id), 200
+    def delete( src, dst, bitrate, o_band_id,flow_id=None):
+            flow = None
+            match1=False
+            ob_id=None
+            if flow_id is not None:
+     
+                if flow_id in rsa.db_flows.keys():
+                   flow = rsa.db_flows[flow_id]
+                   match1 = flow["src"] == src and flow["dst"] == dst and flow["bitrate"] == bitrate
+                   ob_id = flow["parent_opt_band"]
+                   flow['is_active']=False
+            if flow is not None:
+                
+            
+                bidir = flow["bidir"]
+              
+                if bidir:
+                    match2 = flow["src"] == dst and flow["dst"] == src and flow["bitrate"] == bitrate
+                    if match1 or match2:
+                        ob_id = flow["parent_opt_band"]
+                        rsa.del_flow(flow, ob_id)
+                        rsa.db_flows[flow_id]["is_active"] = False
+                        if flow_id in rsa.optical_bands[ob_id]["served_lightpaths"].remove:
+                           rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id)
+                        #if rsa.optical_bands[ob_id]["reverse_optical_band_id"] != 0:
+                        #    rev_ob_id = rsa.optical_bands[ob_id]["reverse_optical_band_id"]
+                        #    rsa.optical_bands[rev_ob_id]["served_lightpaths"].remove(flow_id)
+
+                        if debug:
+                            print(rsa.links_dict)
+                        return "flow {} deleted".format(flow_id), 200
+                    else:
+                        return "flow {} not matching".format(flow_id), 404
                 else:
-                    return "flow {} not matching".format(flow_id), 404
+                    if match1:
+                        # if delete_band !=0 and ob_id is not None:
+                        #     print(f"delete_lightpath {delete_band} and ob_id {ob_id}")
+                        #     if len( rsa.optical_bands[ob_id]["served_lightpaths"]) != 0:
+                        #         return "DELETE_NOT_ALLOWED" ,400
+                        rsa.del_flow(flow,flow_id,ob_id)
+
+                        if debug:
+                            print(f"vor ob_id {ob_id} rsa.optical_bands  {rsa.optical_bands[ob_id]}")
+                            print(f"rsa.links_dict {rsa.links_dict}")
+                        return "flow {} deleted".format(flow_id), 200
+                    else:
+                        return "flow {} not matching".format(flow_id), 404
             else:
-                if match1:
-                    ob_id = flow["parent_opt_band"]
-                    rsa.del_flow(flow, ob_id)
-                    rsa.db_flows[flow_id]["is_active"] = False
-                    rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id)
-                    if debug:
-                       LOGGER.info(links_dict)
-                    return "flow {} deleted".format(flow_id), 200
-                else:
-                    return "flow {} not matching".format(flow_id), 404
-        else:
-            return "flow id {} does not exist".format(flow_id), 404
+                return "flow id {} does not exist".format(flow_id), 404
+
 
+@optical.route('/DelOpticalBand/<string:src>/<string:dst>/<int:o_band_id>',methods=['DELETE'])
+@optical.response(200, 'Success')
+@optical.response(404, 'Error, not found')
+class DelOpticalBand(Resource):
+    @staticmethod
+    def delete( src, dst, o_band_id):
+            flow = None
+
+            ob_id=None
+            if o_band_id is not None :            
+            
+                if o_band_id in  rsa.optical_bands.keys():
+                    flow=rsa.optical_bands[o_band_id]
+                    #match1 = flow["src"] == src and flow["dst"] == dst 
+                    ob_id=o_band_id 
+              
+                if flow is not None:
+                
+            
+                    bidir = flow["bidir"]
+                
+                    if bidir:
+                        match2 = flow["src"] == dst and flow["dst"] == src and flow["bitrate"] 
+                        if match1 or match2:
+                            ob_id = flow["parent_opt_band"]
+                            #rsa.del_flow(flow, ob_id)
+                            rsa.optical_bands[ob_id]["is_active"] = False
+                            # if flow_id in rsa.optical_bands[ob_id]["served_lightpaths"].remove:
+                            #    rsa.optical_bands[ob_id]["served_lightpaths"].remove(flow_id)
+                            #if rsa.optical_bands[ob_id]["reverse_optical_band_id"] != 0:
+                            #    rev_ob_id = rsa.optical_bands[ob_id]["reverse_optical_band_id"]
+                            #    rsa.optical_bands[rev_ob_id]["served_lightpaths"].remove(flow_id)
+
+                            if debug:
+                                print(rsa.links_dict)
+                            return "ob_id {} deleted".format(ob_id), 200
+                        else:
+                            return "ob_id {} not matching".format(ob_id), 404
+                    else:
+                        if ob_id is not None:
+                        
+                            if len( rsa.optical_bands[ob_id]["served_lightpaths"]) != 0:
+                                return "DELETE_NOT_ALLOWED" ,400
+
+                        rsa.del_band(flow,ob_id)
+                        if debug:
+                            print(f"vor ob_id {ob_id} rsa.optical_bands  {rsa.optical_bands[ob_id]}")
+                            print(f"rsa.links_dict {rsa.links_dict}")
+                        return "ob_id {} deleted".format(ob_id), 200
+                       
+                else :
+                    return "flow for ob_id {} not found".format(ob_id),400        
+            else:
+                return "ob_id  {} does not exist".format(ob_id), 404
 
 
 @optical.route('/DelLightpath/<int:flow_id>/<string:src>/<string:dst>/<int:bitrate>')
@@ -162,7 +234,7 @@ class DelLightpath(Resource):
                 rsa.del_flow(flow)
                 rsa.db_flows[flow_id]["is_active"] = False
                 if debug:
-                   LOGGER.info(links_dict)
+                    print(rsa.links_dict)
                 return "flow {} deleted".format(flow_id), 200
             else:
                 return "flow {} not matching".format(flow_id), 404
@@ -178,22 +250,21 @@ class GetFlows(Resource):
     def get():
         try:
             if debug:
-               LOGGER.info(rsa.db_flows)
+                print(rsa.db_flows)
             return rsa.db_flows, 200
         except:
             return "Error", 404
 
+
 @optical.route('/GetOpticalBands')
 @optical.response(200, 'Success')
 @optical.response(404, 'Error, not found')
 class GetBands(Resource):
     @staticmethod
     def get():
-        print("Getting ")
-        LOGGER.info("Getting")
         try:
             if debug:
-               LOGGER.info(rsa.optical_bands)
+                print(rsa.optical_bands)
             return rsa.optical_bands, 200
         except:
             return "Error", 404
@@ -208,7 +279,7 @@ class GetBand(Resource):
         for ob_idx in rsa.optical_bands.keys():
             if str(ob_idx) == str(ob_id):
                 if debug:
-                   LOGGER.info(rsa.optical_bands[ob_id])
+                    print(rsa.optical_bands[ob_id])
                 return rsa.optical_bands[ob_idx], 200
         return {}, 404
 
@@ -219,28 +290,73 @@ class GetBand(Resource):
 class GetFlows(Resource):
     @staticmethod
     def get():
-        global links_dict
+        global rsa
+        #global links_dict
+        links = None
+        if rsa is not None :
+           links = rsa.links_dict
         try:
             if debug:
-               LOGGER.info(links_dict)
-            return links_dict, 200
+                print(links)
+            return links, 200
         except:
             return "Error", 404
 
 
-if __name__ == '__main__':
+@optical.route('/GetTopology/<path:context_id>/<path:topology_id>',methods=['GET'])
+@optical.response(200, 'Success')
+@optical.response(404, 'Error, not found')
+class GetTopology(Resource):
+    @staticmethod
+    def get(context_id:str,topology_id:str):
+        
+        global rsa
     
+        if (rsa is not None):
+            return "Opticalcontroller is synchronised" ,200
+        topog_id = TopologyId()
+        topog_id.topology_uuid.uuid=topology_id
+        topog_id.context_id.context_uuid.uuid=context_id
+        
+        try:
+            links_dict = {"optical_links": []}
+            node_dict = {}
+            topo, nodes = readTopologyDataFromContext(topog_id)
+
+            for link in topo: 
+                link_dict_type = MessageToDict(link, preserving_proto_field_name=True)
+
+                if "c_slots" in link_dict_type["optical_details"]:
+                    link_dict_type["optical_details"]["c_slots"] = link_dict_type["optical_details"]["c_slots"]
+
+                if "l_slots" in link_dict_type["optical_details"]:
+                    link_dict_type["optical_details"]["l_slots"] = link_dict_type["optical_details"]["l_slots"]
+
+                if "s_slots" in link_dict_type["optical_details"]:
+                    link_dict_type["optical_details"]["s_slots"] = link_dict_type["optical_details"]["s_slots"]
+
+                links_dict["optical_links"].append(link_dict_type)
+
+            for device in nodes :
+                dev_dic = {
+                    "id":device.device_id.device_uuid.uuid,
+                    #"ip":f"10.30.2.{207+i}",
+                    #"port":"50001",
+                    "type":"OC-ROADM" if device.device_type =="optical-roadm" else "OC-TP",
+                    "driver": "OpticalOC"
+                }
+                node_dict[device.name] = dev_dic
+                #i+=1
+                #print(f"refresh_optical controller optical_links_dict= {links_dict}")
+                #print(f"refresh_optical controller node_dict  {node_dict}")
+
+            rsa = RSA(node_dict, links_dict)
+            if debug:
+                print(rsa.init_link_slots2())
+            return "ok", 200
+        except Exception as e:
+            print(f"err {e}")
+            return "Error", 400
 
-    # Start metrics server
-
-    LOGGER.info('Starting...')
-
-
-
-    nodes_dict, links_dict = readTopologyData(nodes_json, topology_json)
-
-    #topologies, links = getTopology()
-    #print("topologies{} and devices {}".format(topologies,links))
-    rsa = RSA(nodes_dict, links_dict)
-
-    app.run(host='0.0.0.0', port=10060, debug=True)
+if __name__ == '__main__':
+    app.run(host='0.0.0.0', port=10060)
diff --git a/src/opticalcontroller/README.md b/src/opticalcontroller/README.md
index 5fd94c59e51cbd78dd76a7db0f24aaaec4ebd9db..f121055cec91470646b9885bfe90db137027f472 100644
--- a/src/opticalcontroller/README.md
+++ b/src/opticalcontroller/README.md
@@ -1,17 +1,20 @@
-# optical-controller
-This a framework to implement the optical controller for the RMSA algorithm.
+# Optical Controller
+
+This is a framework to test the optical controller for the RMSA algorithm in an isolated manner.
+
+![Reference Architecture](images/topo.png)
+
+```bash
 #create a venv
 python -m venv venv
 
-in linux
+# in linux
 source venv/Scripts/activate
 
-in windows
+# in windows
 venv\Scripts\activate
 
-pip install -r requirements_opt.txt
+pip install -r requirements_optical_ctrl_test.txt
 
 python OpticalController.py
-![Reference Architecture](images/topo.png)
-
-
+```
diff --git a/src/opticalcontroller/RSA.py b/src/opticalcontroller/RSA.py
index b15357c98242ad6b18d4068b6f0aa1cb08852d7a..61a74edbecc2ac635398ee8482800514295e9473 100644
--- a/src/opticalcontroller/RSA.py
+++ b/src/opticalcontroller/RSA.py
@@ -26,15 +26,15 @@ class RSA():
         self.flow_id = 0
         self.opt_band_id = 0
         self.db_flows = {}
-        self.initGraph()
+        self.initGraph2()
         self.c_slot_number = 0
         self.l_slot_number = 0
         self.s_slot_number = 0
         self.optical_bands = {}
 
-    def init_link_slots(self, testing):
-        if not testing:
-            for l in self.links_dict["links"]:
+    def init_link_slots(self):
+        if full_links:
+            for l in self.links_dict["optical_links"]:
                 for fib in l["optical_link"]["details"]["fibers"]:
                     #fib = self.links_dict[l]["fibers"][f]
                     if len(fib["c_slots"]) > 0:
@@ -45,7 +45,7 @@ class RSA():
                         fib["s_slots"] = list(range(0, Ns))
                     if debug:
                         print(fib)
-        for l1 in self.links_dict["links"]:
+        for l1 in self.links_dict["optical_links"]:
 
             for fib1 in l1["optical_link"]["details"]["fibers"]:
                 #fib1 = self.links_dict[l1]["details"]["fibers"][f1]
@@ -58,11 +58,35 @@ class RSA():
             break
         return "{},{},{}".format(self.c_slot_number, self.l_slot_number, self.s_slot_number)
 
+    def init_link_slots2(self):
+        if full_links:
+            for l in self.links_dict["optical_links"]:
+                fib = l["optical_details"]
+                #fib = self.links_dict[l]["fibers"][f]
+                if len(fib["c_slots"]) > 0:
+                    for c in range(0, Nc):
+                        fib["c_slots"][c] = 1
+                if len(fib["l_slots"]) > 0:
+                    for c in range(0, Nl):
+                        fib["l_slots"][c] = 1
+                if len(fib["s_slots"]) > 0:
+                    for c in range(0, Ns):
+                        fib["s_slots"][c] = 1
+                if debug:
+                    print(fib)
+        for l1 in self.links_dict["optical_links"]:
+            fib1 = l1["optical_details"]
+            self.c_slot_number = len(fib1["c_slots"].keys())
+            self.l_slot_number = len(fib1["l_slots"].keys())
+            self.s_slot_number = len(fib1["s_slots"].keys())
+            break
+        return "{},{},{}".format(self.c_slot_number, self.l_slot_number, self.s_slot_number)
+
     def initGraph(self):
         self.g = dijsktra.Graph()
         for n in self.nodes_dict:
             self.g.add_vertex(n)
-        for l in self.links_dict["links"]:
+        for l in self.links_dict["optical_links"]:
             if debug:
                 print(l)
             [s, d] = l["optical_link"]["name"].split('-')
@@ -74,6 +98,24 @@ class RSA():
         if debug:
             self.g.printGraph()
 
+    def initGraph2(self):
+     
+        self.g = dijsktra.Graph()
+     
+        for n in self.nodes_dict:
+            self.g.add_vertex(n)
+        for l in self.links_dict["optical_links"]:
+            if debug:
+                print(l)
+            [s, d] = l["name"].split('-')
+            ps = l["optical_details"]["src_port"]
+            pd = l["optical_details"]["dst_port"]
+            self.g.add_edge(s, d, ps, pd, 1)
+
+        print("INFO: Graph initiated.2")
+        if debug:
+            self.g.printGraph()
+
     def compute_path(self, src, dst):
         path = dijsktra.shortest_path(self.g, self.g.get_vertex(src), self.g.get_vertex(dst))
         print("INFO: Path from {} to {} with distance: {}".format(src, dst, self.g.get_vertex(dst).get_distance()))
@@ -95,7 +137,7 @@ class RSA():
         self.g.reset_graph()
         return links, path
 
-    def get_slots(self, links, slots, optical_band_id = None):
+    def get_slots(self, links, slots, optical_band_id=None):
 
         if isinstance(slots, int):
             val_c = slots
@@ -120,38 +162,40 @@ class RSA():
             add = links[0]
         if self.nodes_dict[dst_2]["type"] == "OC-TP":
             drop = links[-1]
-
+        found = 0
         for l in links:
             c_slots[l] = []
             l_slots[l] = []
             s_slots[l] = []
-            found = 0
-            for link in self.links_dict["links"]:
-                if link["optical_link"]["name"] == l:
-                    #for f in self.links_dict[l]['fibers'].keys():
-                    for fib in link["optical_link"]["details"]["fibers"]:
-                        if l == add:
-                            if 'used' in fib:
-                                if fib["used"]:
-                                    #if debug:
-                                    print("WARNING!!!: link {}, fiber {} is already in use".format(l, fib["ID"]))
-                                    continue
-                        if l == drop:
-                            if 'used' in fib:
-                                if fib["used"]:
-                                    #if debug:
-                                    print("WARNING!!!: link {}, fiber {} is already in use".format(l, fib["ID"]))
-                                    continue
-                        if len(fib["c_slots"]) > 0:
-                            c_slots[l] = combine(c_slots[l], consecutives(fib["c_slots"], val_c))
-                        if len(fib["l_slots"]) > 0:
-                            l_slots[l] = combine(l_slots[l], consecutives(fib["l_slots"], val_l))
-                        if len(fib["s_slots"]) > 0:
-                            s_slots[l] = combine(s_slots[l], consecutives(fib["s_slots"], val_s))
-                        if debug:
-                            print(l, c_slots[l])
-                        found = 1
-            if found == 0:
+
+            link = self.get_link_by_name(l)
+            fib = link["optical_details"]
+            if l == add:
+                if 'used' in fib:
+                    if fib["used"]:
+                        #if debug:
+                        print("WARNING!!!: link {}, is already in use".format(l))
+                        return [], [], []
+            if l == drop:
+                if 'used' in fib:
+                    if fib["used"]:
+                        #if debug:
+                        print("WARNING!!!: link {} is already in use".format(l))
+                        return [], [], []
+            c_found = l_found = s_found = 0
+            if len(fib["c_slots"].keys()) > 0:
+                #c_slots[l] = combine(c_slots[l], consecutives(fib["c_slots"], val_c))
+                c_slots[l] = combine(c_slots[l], consecutives(fib["c_slots"], val_c))
+                c_found = 1
+            if len(fib["l_slots"].keys()) > 0:
+                l_slots[l] = combine(l_slots[l], consecutives(fib["l_slots"], val_l))
+                l_found = 1
+            if len(fib["s_slots"].keys()) > 0:
+                s_slots[l] = combine(s_slots[l], consecutives(fib["s_slots"], val_s))
+                s_found = 1
+            if debug:
+                print(l, c_slots[l])
+            if c_found == 0 and l_found == 0 and s_found == 0:
                 return [], [], []
 
         keys = list(c_slots.keys())
@@ -185,60 +229,100 @@ class RSA():
                 c_sts = common_slots(a_c, b_c)
                 l_sts = common_slots(a_l, b_l)
                 s_sts = common_slots(a_s, b_s)
+                '''
+             if len(fib["l_slots"]) > 0:
+                l_slots[l] = combine(l_slots[l], consecutives(fib["l_slots"], val_l))
+                l_found = 1'''
         if optical_band_id is not None:
             if "c_slots" in self.optical_bands[optical_band_id].keys():
                 if len(self.optical_bands[optical_band_id]["c_slots"]) > 0:
                     a_c = c_sts
-                    b_c = self.optical_bands[optical_band_id]["c_slots"]
+                    #MOD
+                    b_c = consecutives(self.optical_bands[optical_band_id]["c_slots"], val_c)
+                    #b_c = self.optical_bands[optical_band_id]["c_slots"]
                     c_sts = common_slots(a_c, b_c)
-                else:
-                    c_sts = []
             else:
                 c_sts = []
             if "l_slots" in self.optical_bands[optical_band_id].keys():
                 if len(self.optical_bands[optical_band_id]["l_slots"]) > 0:
                     a_l = l_sts
-                    b_l = self.optical_bands[optical_band_id]["l_slots"]
+                    b_l = consecutives(self.optical_bands[optical_band_id]["l_slots"], val_c)
                     l_sts = common_slots(a_l, b_l)
-                else:
-                    l_sts = []
             else:
                 l_sts = []
             if "s_slots" in self.optical_bands[optical_band_id].keys():
                 if len(self.optical_bands[optical_band_id]["s_slots"]) > 0:
                     a_s = s_sts
-                    b_s = self.optical_bands[optical_band_id]["s_slots"]
+                    b_s = consecutives(str_list_to_int(self.optical_bands[optical_band_id]["s_slots"].keys()), val_c)
                     s_sts = common_slots(a_s, b_s)
-                else:
-                    s_sts = []
             else:
                 s_sts = []
 
         return c_sts, l_sts, s_sts
 
     def update_link(self, fib, slots, band):
+        #print(fib)
         for i in slots:
-            fib[band].remove(i)
+            fib[band][str(i)] = 0
         if 'used' in fib:
             fib['used'] = True
+        print(f"fib updated {fib}")    
+        #print(fib)
+        
+    def update_link_2(self, fib, slots, band,link):
+        #print(fib)
+        for i in slots:
+            fib[band][str(i)] = 0
+        if 'used' in fib:
+            fib['used'] = True
+      
+        set_link_update(fib,link)  
+        #print(fib)    
 
     def update_optical_band(self, optical_band_id, slots, band):
         for i in slots:
-            self.optical_bands[optical_band_id][band].remove(i)
+            self.optical_bands[optical_band_id][band][str(i)] = 0
+
+    def augment_optical_band(self, optical_band_id, slots, band):
+        for i in slots:
+            self.optical_bands[optical_band_id][band][str(i)] = 1
 
     def restore_link(self, fib, slots, band):
         for i in slots:
-            fib[band].append(int(i))
+            fib[band][str(i)] = 1
         if 'used' in fib:
             fib['used'] = False
-        fib[band].sort()
+        #fib[band].sort()
+        
+    def restore_link_2(self, fib, slots, band,link):
+        print("start restoring link")
+        for i in slots:
+            fib[band][str(i)] = 1
+        if 'used' in fib:
+            fib['used'] = False
+        #fib[band].keys().sort()    
+        set_link_update(fib,link,test="restoration") 
 
     def restore_optical_band(self, optical_band_id, slots, band):
         for i in slots:
-            self.optical_bands[optical_band_id][band].append(int(i))
-        self.optical_bands[optical_band_id][band].sort()
-
-    def del_flow(self, flow, o_b_id = None):
+            self.optical_bands[optical_band_id][band][str(i)] = 1
+            
+            #self.optical_bands[optical_band_id][band].append(int(i))
+        #self.optical_bands[optical_band_id][band].sort()
+
+    def restore_optical_band_2(self, optical_band_id, slots, band ,links):
+        print(f"example of  band { band}")
+        print(f"example of slots {slots}")
+        print(f"example of self.optical_bands_before { self.optical_bands}")
+        for i in slots:
+            self.optical_bands[optical_band_id][band][str(i)] = 1
+        print(f"example of self.optical_bands_after { self.optical_bands}")    
+       
+        #link_name=    self.optical_bands[optical_band_id]['links'][0] 
+        #link = self.get_link_by_name(link_name)    
+        #update_optical_band(optical_bands=self.optical_bands,optical_band_id=optical_band_id,band=band,link=link)
+
+    def del_flow(self, flow,flow_id, o_b_id = None):
         flows = flow["flows"]
         band = flow["band_type"]
         slots = flow["slots"]
@@ -249,22 +333,123 @@ class RSA():
         path = flow["path"]
         links = flow["links"]
         bidir = flow["bidir"]
+        flow_id = flow["flow_id"]
 
-        for l in fiber_f.keys():
+        for l in links:
             if debug:
                 print(l)
-                print(fiber_f[l])
             #link = self.links_dict[l]
             #f = fiber_f[l]
             #fib = link['fibers'][f]
-            fib = self.get_fiber_details(l, fiber_f[l])
-            if not list_in_list(slots, fib[band]):
-                self.restore_link(fib, slots, band)
+            fib = self.get_link_by_name(l)["optical_details"]
+         
+            self.restore_link(fib, slots, band)
+            if debug:
+                print(fib[band])
+
+        if o_b_id is not None:
+            if debug:
+                print("restoring OB")
+            print(f"invoking restore_optical_band o_b_id: {o_b_id} , slots {slots} , band {band} ")    
+            self.restore_optical_band(o_b_id, slots, band)
+            if flow_id in self.optical_bands[o_b_id]["served_lightpaths"]:
+                if flow_id in self.optical_bands[o_b_id]["served_lightpaths"]:
+                    self.optical_bands[o_b_id]["served_lightpaths"].remove(flow_id)
+
+            #self.restore_optical_band_2(o_b_id, slots, band,links)
+
+        if bidir:
+            for l in links:
+                r_l = reverse_link(l)
+                if debug:
+                    print(r_l)
+                # link = self.links_dict[l]
+                # f = fiber_f[l]
+                # fib = link['fibers'][f]
+                fib = self.get_link_by_name(r_l)["optical_details"]
+                if list_in_list(slots, str_list_to_int(fib[band].keys())):
+                    self.restore_link(fib, slots, band, link=l)
+                    if debug:
+                        print(fib[band])
+            '''
+            for rl in fiber_b.keys():
                 if debug:
-                    print(fib[band])
+                    print(rl)
+                    print(fiber_b[rl])
+                #rlink = self.links_dict[rl]
+                #rf = fiber_b[rl]
+                #rfib = rlink['fibers'][rf]
+                rfib = self.get_fiber_details(rl, fiber_b[rl])
+                if not list_in_list(slots, rfib[band]):
+                    self.restore_link(rfib, slots, band)
+                    if debug:
+                        print(rfib[band])
+            '''
+            #changed according to TFS development
+            #if o_b_id is not None:
+            #    rev_o_band_id = self.optical_bands[o_b_id]["reverse_optical_band_id"]
+            #    self.restore_optical_band(rev_o_band_id, slots, band)
+        return True
+    
+    
+    def del_band(self, flow, o_b_id = None):
+        print(f"delete band {flow} ")
+
+        flows = flow["flows"]
+        band = None
+        #slots = flow["slots"]
+        fiber_f = flow["fiber_forward"]
+        fiber_b = flow["fiber_backward"]
+        op = flow["op-mode"]
+        n_slots = 0
+        path = flow["path"]
+        bidir = flow["bidir"]
+        links =  []
         if o_b_id is not None:
+           links= self.optical_bands[o_b_id]["links"]
+           band = self.optical_bands[o_b_id]["band_type"]
+           n_slots =self.optical_bands[o_b_id]["n_slots"]
+           if n_slots > 0: 
+               slots=[i+1 for i in range(n_slots)]
+       
+        for l in links:
+            if debug:
+                print(l)
+            #link = self.links_dict[l]
+            #f = fiber_f[l]
+            #fib = link['fibers'][f]
+            fib = self.get_link_by_name(l)["optical_details"]
+            print(f"del_flow_fib {fib } and band {band}")
+            print(f"del_flow { str_list_to_int(fib[band].keys())}")
+          
+            print(f"invoking restore_link_2 fib: {fib} , slots {slots} , band {band} ")
+            self.restore_link(fib, slots, band)
+            self.optical_bands[o_b_id]["is_active"]=False
+           
+            if debug:
+                print(fib[band])
+            
+        if o_b_id is not None:
+            
+            if debug:
+                print("restoring OB")
+            print(f"invoking restore_optical_band o_b_id: {o_b_id} , slots {slots} , band {band} ")    
             self.restore_optical_band(o_b_id, slots, band)
+            #self.restore_optical_band_2(o_b_id, slots, band,links)
         if bidir:
+            for l in links:
+                r_l = reverse_link(l)
+                if debug:
+                    print(r_l)
+                # link = self.links_dict[l]
+                # f = fiber_f[l]
+                # fib = link['fibers'][f]
+                fib = self.get_link_by_name(r_l)["optical_details"]
+                if list_in_list(slots, str_list_to_int(fib[band].keys())):
+                    self.restore_link(fib, slots, band, link=l)
+                    if debug:
+                        print(fib[band])
+            '''
             for rl in fiber_b.keys():
                 if debug:
                     print(rl)
@@ -277,17 +462,26 @@ class RSA():
                     self.restore_link(rfib, slots, band)
                     if debug:
                         print(rfib[band])
+            '''
             #changed according to TFS development
             #if o_b_id is not None:
             #    rev_o_band_id = self.optical_bands[o_b_id]["reverse_optical_band_id"]
             #    self.restore_optical_band(rev_o_band_id, slots, band)
         return True
 
+    def del_handler(self, flow,flow_id, o_b_id = None,delete_band=0):
+        print(f" del_handler flow {flow} flow_id {flow_id}  o_b_id {o_b_id} delete_band {delete_band}")
+        if delete_band != 0:
+            print(f"delete band del_band")
+            self.del_band(flow,flow_id,o_b_id=o_b_id)
+        else :
+            self.del_flow(flow,flow_id=flow_id,o_b_id=o_b_id)   
+
     def get_fibers_forward(self, links, slots, band):
         fiber_list = {}
         add = links[0]
         drop = links[-1]
-        print(links)
+        #print(links)
         '''
         for link in self.links_dict["links"]:
             if link["optical_link"]["name"] == l:
@@ -296,85 +490,99 @@ class RSA():
 
         '''
         for l in links:
-            for link in self.links_dict["links"]:
-                if link["optical_link"]["name"] == l:
-                    for fib in link["optical_link"]["details"]["fibers"]:
-                        #for f in self.links_dict[l]['fibers'].keys():
-                        #for fib in l["optical_link"]["details"]["fibers"]:
-                        #fib = self.links_dict[l]['fibers'][f]
-                        if l == add:
-                            if 'used' in fib:
-                                if fib["used"]:
-                                    if debug:
-                                        print("link {}, fiber {} is already in use".format(l, fib["ID"]))
-                                    continue
-                        if l == drop:
-                            if 'used' in fib:
-                                if fib["used"]:
-                                    if debug:
-                                        print("link {}, fiber {} is already in use".format(l, fib["ID"]))
-                                    continue
-                        if list_in_list(slots, fib[band]):
-                            fiber_list[l] = fib["ID"]
-                            self.update_link(fib, slots, band)
-                            break
+            for link in self.links_dict["optical_links"]:
+                print(f"tracking link info {link}")    
+                if link["name"] == l:
+                    fib = link["optical_details"]
+                    #for f in self.links_dict[l]['fibers'].keys():
+                    #for fib in l["optical_link"]["details"]["fibers"]:
+                    #fib = self.links_dict[l]['fibers'][f]
+                    if l == add:
+                        if 'used' in fib:
+                            if fib["used"]:
+                                if debug:
+                                    print("link {} is already in use".format(l))
+                                continue
+                    if l == drop:
+                        if 'used' in fib:
+                            if fib["used"]:
+                                if debug:
+                                    print("link {} is already in use".format(l))
+                                continue
+                    if list_in_list(slots, str_list_to_int(fib[band].keys())):
+                        #fiber_list[l] = fib["ID"]
+                        #self.update_link(fib, slots, band)
+                        self.update_link_2(fib,slots,band,link)
+                        break
         print("INFO: Path forward computation completed")
         return fiber_list
 
     def get_link_by_name (self, key):
-        result = None
-        for link in self.links_dict["links"]:
-            if link["optical_link"]["name"] == key:
+        for link in self.links_dict["optical_links"]:
+            if link["name"] == key:
                 if debug:
                     print(link)
-                result = link
                 break
-        return result
+        return link
 
     def get_fiber_details(self, link_key, fiber_id):
-        for link in self.links_dict["links"]:
-            if link["optical_link"]["name"] == link_key:
+        for link in self.links_dict["optical_links"]:
+            if link["name"] == link_key:
                 if debug:
                     print(link)
-                for fib in link["optical_link"]["details"]["fibers"]:
+                for fib in link["optical_details"]:
                     if fib["ID"] == fiber_id:
                         return fib
         return None
 
-
-    def get_fibers_backward(self, links, fibers, slots, band):
+    def get_fibers_backward(self, links, slots, band):
         fiber_list = {}
         #r_drop = reverse_link(links[0])
         #r_add = reverse_link(links[-1])
-        for l in fibers.keys():
-            fib = self.get_fiber_details(l, fibers[l])
+        for l in links:
+            fib = self.get_link_by_name(l)["optical_details"]
             '''
             link = self.get_link_by_name(l)
             #port = self.links_dict[l]["fibers"][fibers[l]]["src_port"]
             for fib in link["optical_link"]["details"]["fibers"]:
                 if fib["ID"] == fibers[l]:
             '''
-            port = fib["src_port"]
+            s_port = fib["src_port"]
+            d_port = fib["dst_port"]
+
+            if debug:
+                print(l, s_port, d_port)
+
             r_l = reverse_link(l)
             r_link = self.get_link_by_name(r_l)
+            if debug:
+                print(r_l)
+
             #for f in r_link["fibers"].keys():
-            for r_fib in r_link["optical_link"]["details"]["fibers"]:
-                if r_fib["remote_peer_port"] == port:
-                    if list_in_list(slots, r_fib[band]):
-                        fiber_list[r_l] = r_fib["ID"]
-                        self.update_link(r_fib, slots, band)
+            r_fib = r_link["optical_details"]
+            if r_fib["remote_peer_port"] == s_port and r_fib["local_peer_port"] == d_port:
+                if list_in_list(slots, str_list_to_int(r_fib[band].keys())):
+                    #fiber_list[r_l] = r_fib["ID"]
+                    self.update_link(r_fib, slots, band)
         print("INFO: Path backward computation completed")
         return fiber_list
 
+    #function invoked for lightpaths and OB
     def select_slots_and_ports(self, links, n_slots, c, l, s, bidir):
         if debug:
-            print(self.links_dict)
+            print (links, n_slots, c, l, s, bidir, self.c_slot_number, self.l_slot_number, self.s_slot_number)
         band, slots = slot_selection(c, l, s, n_slots, self.c_slot_number, self.l_slot_number, self.s_slot_number)
+        if debug:
+            print (band, slots)
         if band is None:
             print("No slots available in the three bands")
-            return None, None, None
-        if debug:
-            print(band, slots)
+            #return None, None, None, {}, {}
+            return None, None, None, {}, {}
+        
+        self.get_fibers_forward(links, slots, band)
+        if bidir:
+            self.get_fibers_backward(links, slots, band)
+        '''
         fibers_f = self.get_fibers_forward(links, slots, band)
 
         fibers_b = []
@@ -385,6 +593,7 @@ class RSA():
             print(fibers_f)
             print("backward")
             print(fibers_b)
+        '''
         add = links[0]
         drop = links[-1]
         inport = "0"
@@ -394,18 +603,22 @@ class RSA():
         t_flows = {}
         #if len(links) == 1:
 
-        for lx in fibers_f:
-            if lx == add:
+        for llx in links:
+            if llx == add:
                 inport = "0"
                 r_outport = "0"
-            if lx == drop:
+            if llx == drop:
                 outport = "0"
                 r_inport = "0"
+            '''
             f = fibers_f[lx]
-            src, dst = lx.split("-")
+            
             fibx = self.get_fiber_details(lx, f)
+            '''
+            src, dst = llx.split("-")
             #outport = self.links_dict[lx]['fibers'][f]["src_port"]
-            outport = fibx["src_port"]
+            lx = self.get_link_by_name(llx)["optical_details"]
+            outport = lx["src_port"]
 
             t_flows[src] = {}
             t_flows[src]["f"] = {}
@@ -414,14 +627,14 @@ class RSA():
 
             if bidir:
                 #r_inport = self.links_dict[lx]['fibers'][f]["local_peer_port"]
-                r_inport = fibx["local_peer_port"]
+                r_inport = lx["local_peer_port"]
                 t_flows[src]["b"] = {"in": r_inport, "out": r_outport}
 
             #inport = self.links_dict[lx]['fibers'][f]["dst_port"]
-            inport = fibx["dst_port"]
+            inport = lx["dst_port"]
             if bidir:
                 #r_outport = self.links_dict[lx]['fibers'][f]["remote_peer_port"]
-                r_outport = fibx["remote_peer_port"]
+                r_outport = lx["remote_peer_port"]
             t_flows[dst] = {}
             t_flows[dst]["f"] = {}
             t_flows[dst]["b"] = {}
@@ -436,8 +649,9 @@ class RSA():
             print(t_flows)
         print("INFO: Flow matrix computed")
 
-        return t_flows, band, slots, fibers_f, fibers_b
+        return t_flows, band, slots, {}, {}
 
+    #function ivoked for fs lightpaths only
     def select_slots_and_ports_fs(self, links, n_slots, c, l, s, bidir, o_band_id):
         if debug:
             print(self.links_dict)
@@ -447,22 +661,20 @@ class RSA():
             return None, None, None, None, None
         if debug:
             print(band, slots)
-        fibers_f = self.get_fibers_forward(links, slots, band)
-        self.update_optical_band(o_band_id, slots, band)
-        fibers_b = []
+        self.get_fibers_forward(links, slots, band)
         if bidir:
-            fibers_b = self.get_fibers_backward(links, fibers_f, slots, band)
+            self.get_fibers_backward(links, slots, band)
+
+        #fibers_f = self.get_fibers_forward(links, slots, band)
+        self.update_optical_band(o_band_id, slots, band)
+        #fibers_b = []
+        #if bidir:
+        #    fibers_b = self.get_fibers_backward(links, fibers_f, slots, band)
         '''
 
             rev_o_band_id = self.optical_bands[o_band_id]["reverse_optical_band_id"]
             self.update_optical_band(rev_o_band_id, slots, band)
         '''
-        if debug:
-            print("forward")
-            print(fibers_f)
-            if bidir:
-                print("backward")
-                print(fibers_b)
         add = links[0]
         drop = links[-1]
         port_0 = "0"
@@ -470,11 +682,10 @@ class RSA():
         t_flows = {}
 
         #flows_add_side
-        f = fibers_f[add]
         src, dst = add.split("-")
-        fibx = self.get_fiber_details(add, f)
+        lx = self.get_link_by_name(add)["optical_details"]
         #outport = self.links_dict[add]['fibers'][f]["src_port"]
-        outport = fibx["src_port"]
+        outport = lx["src_port"]
         #T1 rules
         t_flows[src] = {}
         t_flows[src]["f"] = {}
@@ -482,7 +693,7 @@ class RSA():
         t_flows[src]["f"] = {"in": port_0, "out": outport}
         if bidir:
             #r_inport = self.links_dict[add]['fibers'][f]["local_peer_port"]
-            r_inport = fibx["local_peer_port"]
+            r_inport = lx["local_peer_port"]
             t_flows[src]["b"] = {"in": r_inport, "out": port_0}
 
         #R1 rules
@@ -490,27 +701,26 @@ class RSA():
         t_flows[dst]["f"] = {}
         t_flows[dst]["b"] = {}
         #inport = self.links_dict[add]['fibers'][f]["dst_port"]
-        inport = fibx["dst_port"]
+        inport = lx["dst_port"]
         opt_band_src_port = self.optical_bands[o_band_id]["src_port"]
         t_flows[dst]["f"] = {"in": inport, "out": opt_band_src_port}
         #to modify to peer ports
         if bidir:
             #r_inport = self.links_dict[add]['fibers'][f]["local_peer_port"]
-            r_inport = fibx["local_peer_port"]
+            r_inport = lx["local_peer_port"]
             t_flows[src]["b"] = {"in": r_inport, "out": port_0}
         if bidir:
             rev_opt_band_dst_port = self.optical_bands[o_band_id]["rev_dst_port"]
             #r_outport = self.links_dict[add]['fibers'][f]["remote_peer_port"]
-            r_outport = fibx["remote_peer_port"]
+            r_outport = lx["remote_peer_port"]
             t_flows[dst]["b"] = {"in": rev_opt_band_dst_port, "out": r_outport}
 
         #flows_drop_side
         # R2 rules
-        f = fibers_f[drop]
+        ly = self.get_link_by_name(drop)["optical_details"]
         src, dst = drop.split("-")
-        fiby = self.get_fiber_details(drop, f)
         #outport = self.links_dict[drop]['fibers'][f]["src_port"]
-        outport = fiby["src_port"]
+        outport = ly["src_port"]
 
         t_flows[src] = {}
         t_flows[src]["f"] = {}
@@ -520,17 +730,17 @@ class RSA():
         if bidir:
             rev_opt_band_src_port = self.optical_bands[o_band_id]["rev_src_port"]
             #r_inport = self.links_dict[drop]['fibers'][f]["local_peer_port"]
-            r_inport = fiby["local_peer_port"]
+            r_inport = ly["local_peer_port"]
             t_flows[src]["b"] = {"in": r_inport, "out": rev_opt_band_src_port}
         t_flows[dst] = {}
         t_flows[dst]["f"] = {}
         t_flows[dst]["b"] = {}
         #inport = self.links_dict[drop]['fibers'][f]["dst_port"]
-        inport = fiby["dst_port"]
+        inport = ly["dst_port"]
         t_flows[dst]["f"] = {"in": inport, "out": port_0}
         if bidir:
             #r_inport = self.links_dict[drop]['fibers'][f]["remote_peer_port"]
-            r_inport = fiby["remote_peer_port"]
+            r_inport = ly["remote_peer_port"]
             t_flows[dst]["b"] = {"in": port_0, "out": r_inport}
 
         if debug:
@@ -540,7 +750,7 @@ class RSA():
             print(t_flows)
         print("INFO: Flow matrix computed for Flex Lightpath")
 
-        return t_flows, band, slots, fibers_f, fibers_b
+        return t_flows, band, slots, {}, {}
 
     def rsa_computation(self, src, dst, rate, bidir):
         self.flow_id += 1
@@ -565,7 +775,7 @@ class RSA():
         if len(c_slots) > 0 or len(l_slots) > 0 or len(s_slots) > 0:
             flow_list, band_range, slots, fiber_f, fiber_b = self.select_slots_and_ports(links, num_slots, c_slots,
                                                                                          l_slots, s_slots, bidir)
-            f0, band = freqency_converter(band_range, slots)
+            f0, band = frequency_converter(band_range, slots)
             if debug:
                 print(f0, band)
             print("INFO: RSA completed for normal wavelenght connection")
@@ -675,50 +885,43 @@ class RSA():
             print(s_slots)
         if len(c_slots) > 0 or len(l_slots) > 0 or len(s_slots) > 0:
             flow_list, band_range, slots, fiber_f, fiber_b = self.select_slots_and_ports(links, num_slots, c_slots, l_slots, s_slots, bidir)
-            f0, band = freqency_converter(band_range, slots)
-            print(flow_list, band_range, slots, fiber_f, fiber_b)
-            '''
-
-            flow_list_b = {}
-            rev_path = path.copy()
-            rev_path.reverse()
-            rev_links = reverse_links(links)
-            if bidir:
-                for dev_x in flow_list.keys():
-                    flow_list_b[dev_x] = {}
-                    flow_list_b[dev_x]["f"] = flow_list[dev_x]["b"]
-                    del flow_list[dev_x]["b"]
-                    rev_path = path.copy()
-            '''
+            if debug:
+                print(flow_list, band_range, slots, fiber_f, fiber_b)
+            f0, band = frequency_converter(band_range, slots)
             if debug:
                 print(f0, band)
             print("INFO: RSA completed for optical band")
             if flow_list is None:
                 self.null_values(self.flow_id)
                 return self.flow_id, []
-            slots_i = []
+            #slots_i = []
+            #for i in slots:
+            #    slots_i.append(int(i))
+            slots_i = {}
             for i in slots:
-                slots_i.append(int(i))
+                slots_i[str(i)] = 1
 
             # return links, path, flow_list, band_range, slots, fiber_f, fiber_b, op, num_slots, f0, band
             #        links, path, flows, bx, slots, fiber_f, fiber_b, op, n_slots, f0, band
+            if debug:
+                print(links)
             if len(flow_list) > 0:
                 src_port = flow_list[path[0]]['f']['out']
                 dst_port = flow_list[path[-1]]['f']['in']
-                print(flow_list)
-            if len(fiber_f.keys()) == 1:
-                link_x = list(fiber_f.keys())[0]
+                if debug:
+                    print(flow_list)
+            if len(links) == 1:
                 #fib_x = fiber_f[link_x]
                 #rev_dst_port = self.links_dict[link_x]['fibers'][fib_x]["local_peer_port"]
                 #rev_src_port = self.links_dict[link_x]['fibers'][fib_x]["remote_peer_port"]
-                fibx = self.get_fiber_details(link_x, fiber_f[link_x])
+                fibx = self.get_link_by_name(links[0])["optical_details"]
                 rev_dst_port = fibx["local_peer_port"]
                 rev_src_port = fibx["remote_peer_port"]
             else:
-                link_in = list(fiber_f.keys())[0]
-                link_out = list(fiber_f.keys())[-1]
-                fib_inx = self.get_fiber_details(link_in, fiber_f[link_in])
-                fib_outx = self.get_fiber_details(link_out, fiber_f[link_out])
+                link_in = links[0]
+                link_out = links[-1]
+                fib_inx = self.get_link_by_name(link_in)["optical_details"]
+                fib_outx = self.get_link_by_name(link_out)["optical_details"]
                 rev_dst_port = fib_inx["local_peer_port"]
                 rev_src_port = fib_outx["remote_peer_port"]
 
@@ -790,6 +993,7 @@ class RSA():
                 return self.flow_id, []
             optical_band_id, temp_links = self.create_optical_band(links, path, bidir, num_slots_ob)
             return None, optical_band_id
+        print("INFO: TP to TP connection")
         self.flow_id += 1
         self.db_flows[self.flow_id] = {}
         self.db_flows[self.flow_id]["flow_id"] = self.flow_id
@@ -797,7 +1001,7 @@ class RSA():
         self.db_flows[self.flow_id]["dst"] = dst
         self.db_flows[self.flow_id]["bitrate"] = rate
         self.db_flows[self.flow_id]["bidir"] = bidir
-        print("INFO: TP to TP connection")
+
         if band is None:
             temp_links2 = []
             temp_path = []
@@ -816,13 +1020,16 @@ class RSA():
                 temp_path.append(roadm_dst)
                 temp_path.append(t_dst)
                 existing_ob = self.get_optical_bands(roadm_src, roadm_dst)
-               
 
                 if len(existing_ob) > 0:
                     print("INFO: Evaluating existing OB  {}".format(existing_ob))
                     #first checking in existing OB
                     ob_found = 0
                     for ob_id in existing_ob:
+                        if "is_active" in self.optical_bands[ob_id].keys():
+                            is_active = self.optical_bands[ob_id]["is_active"]
+                            if not is_active:
+                                continue
                         op, num_slots = map_rate_to_slot(rate)
                         if debug:
                             print(temp_links2)
@@ -836,7 +1043,7 @@ class RSA():
                                                                                                             c_slots,
                                                                                                             l_slots, s_slots, bidir,
                                                                                                             ob_id)
-                            f0, band = freqency_converter(band_range, slots)
+                            f0, band = frequency_converter(band_range, slots)
                             if debug:
                                 print(f0, band)
                             print("INFO: RSA completed for Flex Lightpath with OB already in place")
@@ -871,6 +1078,75 @@ class RSA():
                             return self.flow_id, ob_id
                         else:
                             print("not enough slots")
+                            print("trying to extend OB {}".format(ob_id))
+                            new_slots = self.extend_optical_band(ob_id, band=None)
+
+                            if len(new_slots) > 0:
+                                band_type = self.optical_bands[ob_id]["band_type"]
+                                c_slots = []
+                                l_slots = []
+                                s_slots = []
+                                if band_type == "c_slots":
+                                    c_slots = new_slots
+                                elif band_type == "l_slots":
+                                    l_slots = new_slots
+                                else:
+                                    s_slots = new_slots
+                                op, num_slots = map_rate_to_slot(rate)
+                                if debug:
+                                    print(temp_links2)
+                                c_slots, l_slots, s_slots = self.get_slots(temp_links2, num_slots, ob_id)
+                                if debug:
+                                    print(c_slots)
+                                    print(l_slots)
+                                    print(s_slots)
+                                #print(c_slots)
+                                #print(l_slots)
+                                #print(s_slots)
+                                if len(c_slots) >= num_slots or len(l_slots) >= num_slots or len(s_slots) >= num_slots:
+                                    flow_list, band_range, slots, fiber_f, fiber_b = self.select_slots_and_ports_fs(
+                                        temp_links2, num_slots,
+                                        c_slots,
+                                        l_slots, s_slots, bidir,
+                                        ob_id)
+                                    f0, band = frequency_converter(band_range, slots)
+                                    if debug:
+                                        print(f0, band)
+                                    print("INFO: RSA completed for Flex Lightpath with OB already in place")
+                                    if flow_list is None:
+                                        self.null_values(self.flow_id)
+                                        continue
+                                    slots_i = []
+                                    for i in slots:
+                                        slots_i.append(int(i))
+                                    # return links, path, flow_list, band_range, slots, fiber_f, fiber_b, op, num_slots, f0, band
+                                    #        links, path, flows, bx, slots, fiber_f, fiber_b, op, n_slots, f0, band
+                                    self.db_flows[self.flow_id]["flows"] = flow_list
+                                    self.db_flows[self.flow_id]["band_type"] = band_range
+                                    self.db_flows[self.flow_id]["slots"] = slots_i
+                                    self.db_flows[self.flow_id]["fiber_forward"] = fiber_f
+                                    self.db_flows[self.flow_id]["fiber_backward"] = fiber_b
+                                    self.db_flows[self.flow_id]["op-mode"] = op
+                                    self.db_flows[self.flow_id]["n_slots"] = num_slots
+                                    self.db_flows[self.flow_id]["links"] = temp_links2
+                                    self.db_flows[self.flow_id]["path"] = temp_path
+                                    self.db_flows[self.flow_id]["band"] = band
+                                    self.db_flows[self.flow_id]["freq"] = f0
+                                    self.db_flows[self.flow_id]["is_active"] = True
+                                    self.db_flows[self.flow_id]["parent_opt_band"] = ob_id
+                                    self.db_flows[self.flow_id]["new_optical_band"] = 1
+                                    #self.db_flows[self.flow_id]["new_optical_band"] = 2
+                                    self.optical_bands[ob_id]["served_lightpaths"].append(self.flow_id)
+                                    '''
+                                    if bidir:
+                                        rev_ob_id = self.optical_bands[ob_id]["reverse_optical_band_id"]
+                                        self.optical_bands[rev_ob_id]["served_lightpaths"].append(self.flow_id)
+                                    '''
+                                    return self.flow_id, ob_id
+                                else:
+                                    print("it is not possible to allocate connection in extended OB {}".format(ob_id))
+                                    
+
         if band is None:
             print("INFO: Not existing optical-band meeting the requirements")
         else:
@@ -879,14 +1155,6 @@ class RSA():
         links, path = self.compute_path(src, dst)
         optical_band_id, temp_links = self.create_optical_band(links, path, bidir, num_slots_ob)
         op, num_slots = map_rate_to_slot(rate)
-        # self.flow_id += 1
-        # self.db_flows[self.flow_id] = {}
-        # self.db_flows[self.flow_id]["flow_id"] = self.flow_id
-        # self.db_flows[self.flow_id]["src"] = src
-        # self.db_flows[self.flow_id]["dst"] = dst
-        # self.db_flows[self.flow_id]["bitrate"] = rate
-        # self.db_flows[self.flow_id]["bidir"] = bidir
-
         if debug:
             print(temp_links)
         c_slots, l_slots, s_slots = self.get_slots(temp_links, num_slots, optical_band_id)
@@ -897,7 +1165,7 @@ class RSA():
         if len(c_slots) > 0 or len(l_slots) > 0 or len(s_slots) > 0:
             flow_list, band_range, slots, fiber_f, fiber_b = self.select_slots_and_ports_fs(temp_links, num_slots, c_slots,
                                                                                             l_slots, s_slots, bidir, optical_band_id)
-            f0, band = freqency_converter(band_range, slots)
+            f0, band = frequency_converter(band_range, slots)
             if debug:
                 print(f0, band)
             print("INFO: RSA completed for FLex Lightpath with new OB")
@@ -929,3 +1197,42 @@ class RSA():
                 self.optical_bands[rev_ob_id]["served_lightpaths"].append(self.flow_id)
             '''
         return self.flow_id, optical_band_id
+
+    def extend_optical_band(self, ob_id, band=None):
+        ob = self.optical_bands[ob_id]
+        links = ob["links"]
+        old_band = ob["band"]
+        band_type = ob["band_type"]
+        f0 = ob["freq"]
+        slots = ob[band_type]
+        if band is None:
+            num_slots_ob = map_band_to_slot(old_band/1000.0)
+        else:
+            num_slots_ob = map_band_to_slot(band)
+        new_slots = []
+        for l in links:
+            link = self.get_link_by_name(l)
+            fib = link["optical_details"][band_type]
+            #s_slots = get_side_slots_on_link(link, band_type, num_slots_ob, slots)
+            s_slots, s_num = get_side_slots_on_link(fib, num_slots_ob, slots)
+            print("NEW SLOTS {}".format(s_slots))
+            if len(new_slots) == 0:
+                new_slots = s_slots
+            else:
+                if len(new_slots) < s_num:
+                    new_slots = list_in_list(new_slots, s_slots)
+        print("NEW SLOTS {}".format(new_slots))
+        self.augment_optical_band(ob_id, new_slots, band_type)
+        new_band = int(len(new_slots)*12.5*1000)
+        print("{}, {},{},{} ".format(old_band, f0, len(new_slots), new_band))
+        final_band = old_band + new_band
+        final_f0 = int(f0 + new_band/2)
+        print("{}, {}".format(final_band, final_f0))
+        ob["band"] = final_band
+        ob["freq"] = final_f0
+        for link_x in links:
+            link = self.get_link_by_name(link_x)
+            fib = link["optical_details"]
+            self.update_link(fib, new_slots, band_type)
+           
+        return new_slots
diff --git a/src/opticalcontroller/__init__.py b/src/opticalcontroller/__init__.py
index bbfc943b68af13a11e562abbc8680ade71db8f02..3ee6f7071f145e06c3aeaefc09a43ccd88e619e3 100644
--- a/src/opticalcontroller/__init__.py
+++ b/src/opticalcontroller/__init__.py
@@ -11,3 +11,4 @@
 # 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/opticalcontroller/json_files/nodes.json b/src/opticalcontroller/json_files/nodes.json
deleted file mode 100644
index 60f017c19d7c7a578c0ddfc2225cab742deb0026..0000000000000000000000000000000000000000
--- a/src/opticalcontroller/json_files/nodes.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
-    "R1":{
-        "id":0,
-        "ip":"10.30.2.207",
-        "port":"50001",
-        "type":"OC-ROADM",
-        "driver": "OpticalOC"
-    },
-
-    "R2":{
-        "id":1,
-        "ip":"10.30.2.208",
-        "port":"50001",
-        "type":"OC-ROADM",
-        "driver": "OpticalOC"
-    },
-
-    "R3":{
-        "id":2,
-        "ip":"10.30.2.209",
-        "port":"50001",
-        "type":"OC-ROADM",
-        "driver": "OpticalOC"
-    },
-    "T1":{
-        "id":3,
-        "ip":"10.30.2.210",
-        "port":"50001",
-        "type":"OC-TP",
-        "driver": "OpticalOC"
-    },
-    "T2":{
-        "id":4,
-        "ip":"10.30.2.211",
-        "port":"50001",
-        "type":"OC-TP",
-        "driver": "OpticalOC"
-    }
-}
diff --git a/src/opticalcontroller/json_files/optical_TFSworking.json b/src/opticalcontroller/json_files/optical_TFSworking.json
deleted file mode 100644
index ff1841eeea9df1e73bcfb25d07f19d64554f11e1..0000000000000000000000000000000000000000
--- a/src/opticalcontroller/json_files/optical_TFSworking.json
+++ /dev/null
@@ -1,486 +0,0 @@
-{
-  "R1-R2": {
-    "length": 80,
-    "source": "d1",
-    "target": "d1",
-    "fibers": {
-      "d1-1": {
-        "length": 80,
-        "src_port": "3",
-        "dst_port": "14",
-        "local_peer_port": "13",
-        "remote_peer_port": "4",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R2-R1": {
-    "length": 80,
-    "source": "d1",
-    "target": "d1",
-    "fibers": {
-      "d1-1": {
-        "length": 80,
-        "src_port": "4",
-        "dst_port": "13",
-        "local_peer_port": "14",
-        "remote_peer_port": "3",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "T1-R1": {
-    "length": 0,
-    "source": "muxT",
-    "target": "srgR",
-    "fibers": {
-      "M1": {
-        "length": 0,
-        "src_port": "1",
-        "dst_port": "12",
-        "local_peer_port": "1",
-        "remote_peer_port": "2",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R1-T1": {
-    "length": 0,
-    "source": "srgT",
-    "target": "muxR",
-    "fibers": {
-      "S1": {
-        "length": 0,
-        "src_port": "2",
-        "dst_port": "1",
-        "local_peer_port": "12",
-        "remote_peer_port": "1",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "T2-R2": {
-    "length": 0,
-    "source": "muxT",
-    "target": "srgR",
-    "fibers": {
-      "M1": {
-        "length": 0,
-        "src_port": "6",
-        "dst_port": "15",
-        "local_peer_port": "6",
-        "remote_peer_port": "5",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R2-T2": {
-    "length": 0,
-    "source": "srgT",
-    "target": "muxR",
-    "fibers": {
-      "S1": {
-        "length": 0,
-        "src_port": "5",
-        "dst_port": "6",
-        "local_peer_port": "15",
-        "remote_peer_port": "6",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  }
-}
diff --git a/src/opticalcontroller/json_files/optical_topoTFS.json b/src/opticalcontroller/json_files/optical_topoTFS.json
deleted file mode 100644
index 7dea474cd676b7c699cffc1c180e14598b987473..0000000000000000000000000000000000000000
--- a/src/opticalcontroller/json_files/optical_topoTFS.json
+++ /dev/null
@@ -1,1836 +0,0 @@
-{
-  "R1-R2": {
-    "length": 80,
-    "source": "d1",
-    "target": "d1",
-    "fibers": {
-      "d1-1": {
-        "length": 80,
-        "src_port": "101",
-        "dst_port": "201",
-        "local_peer_port": "201",
-        "remote_peer_port": "101",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "d1-2": {
-        "length": 80,
-        "src_port": "102",
-        "dst_port": "202",
-        "local_peer_port": "202",
-        "remote_peer_port": "102",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R2-R1": {
-    "length": 80,
-    "source": "d1",
-    "target": "d1",
-    "fibers": {
-      "d1-1": {
-        "length": 80,
-        "src_port": "101",
-        "dst_port": "201",
-        "local_peer_port": "201",
-        "remote_peer_port": "101",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "d1-2": {
-        "length": 80,
-        "src_port": "102",
-        "dst_port": "202",
-        "local_peer_port": "202",
-        "remote_peer_port": "102",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R1-R3": {
-    "length": 80,
-    "source": "d2",
-    "target": "d1",
-    "fibers": {
-      "d2-1": {
-        "length": 80,
-        "src_port": "103",
-        "dst_port": "201",
-        "local_peer_port": "203",
-        "remote_peer_port": "101",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "d2-2": {
-        "length": 80,
-        "src_port": "104",
-        "dst_port": "202",
-        "local_peer_port": "204",
-        "remote_peer_port": "102",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R3-R1": {
-    "length": 80,
-    "source": "d1",
-    "target": "d2",
-    "fibers": {
-      "d1-1": {
-        "length": 80,
-        "src_port": "101",
-        "dst_port": "203",
-        "local_peer_port": "201",
-        "remote_peer_port": "103",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "d1-2": {
-        "length": 80,
-        "src_port": "102",
-        "dst_port": "204",
-        "local_peer_port": "202",
-        "remote_peer_port": "104",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R2-R3": {
-    "length": 80,
-    "source": "d2",
-    "target": "d2",
-    "fibers": {
-      "d2-1": {
-        "length": 80,
-        "src_port": "103",
-        "dst_port": "203",
-        "local_peer_port": "203",
-        "remote_peer_port": "103",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "d2-2": {
-        "length": 80,
-        "src_port": "104",
-        "dst_port": "204",
-        "local_peer_port": "204",
-        "remote_peer_port": "104",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R3-R2": {
-    "length": 80,
-    "source": "d2",
-    "target": "d2",
-    "fibers": {
-      "d2-1": {
-        "length": 80,
-        "src_port": "103",
-        "dst_port": "203",
-        "local_peer_port": "203",
-        "remote_peer_port": "103",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "d2-2": {
-        "length": 80,
-        "src_port": "104",
-        "dst_port": "204",
-        "local_peer_port": "204",
-        "remote_peer_port": "104",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "T1-R1": {
-    "length": 0,
-    "source": "muxT",
-    "target": "srgR",
-    "fibers": {
-      "M1": {
-        "length": 0,
-        "src_port": "1",
-        "dst_port": "2001",
-        "local_peer_port": "1",
-        "remote_peer_port": "1001",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "M2": {
-        "length": 0,
-        "src_port": "2",
-        "dst_port": "2002",
-        "local_peer_port": "2",
-        "remote_peer_port": "1002",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "M3": {
-        "length": 0,
-        "src_port": "3",
-        "dst_port": "2003",
-        "local_peer_port": "3",
-        "remote_peer_port": "1003",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R1-T1": {
-    "length": 0,
-    "source": "srgT",
-    "target": "muxR",
-    "fibers": {
-      "S1": {
-        "length": 0,
-        "src_port": "1001",
-        "dst_port": "1",
-        "local_peer_port": "2001",
-        "remote_peer_port": "1",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "S2": {
-        "length": 0,
-        "src_port": "1002",
-        "dst_port": "2",
-        "local_peer_port": "2002",
-        "remote_peer_port": "2",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "S3": {
-        "length": 0,
-        "src_port": "1003",
-        "dst_port": "3",
-        "local_peer_port": "2003",
-        "remote_peer_port": "3",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "T2-R2": {
-    "length": 0,
-    "source": "muxT",
-    "target": "srgR",
-    "fibers": {
-      "M1": {
-        "length": 0,
-        "src_port": "1",
-        "dst_port": "2001",
-        "local_peer_port": "1",
-        "remote_peer_port": "1001",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "M2": {
-        "length": 0,
-        "src_port": "2",
-        "dst_port": "2002",
-        "local_peer_port": "2",
-        "remote_peer_port": "1002",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "M3": {
-        "length": 0,
-        "src_port": "3",
-        "dst_port": "2003",
-        "local_peer_port": "3",
-        "remote_peer_port": "1003",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R2-T2": {
-    "length": 0,
-    "source": "srgT",
-    "target": "muxR",
-    "fibers": {
-      "S1": {
-        "length": 0,
-        "src_port": "1001",
-        "dst_port": "1",
-        "local_peer_port": "2001",
-        "remote_peer_port": "1",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "S2": {
-        "length": 0,
-        "src_port": "1002",
-        "dst_port": "2",
-        "local_peer_port": "2002",
-        "remote_peer_port": "2",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "S3": {
-        "length": 0,
-        "src_port": "1003",
-        "dst_port": "3",
-        "local_peer_port": "2003",
-        "remote_peer_port": "3",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  }
-}
diff --git a/src/opticalcontroller/json_files/tfs.json b/src/opticalcontroller/json_files/tfs.json
deleted file mode 100644
index 31803b893b5639e957be33465599573baa475ca2..0000000000000000000000000000000000000000
--- a/src/opticalcontroller/json_files/tfs.json
+++ /dev/null
@@ -1,686 +0,0 @@
-{
-	"links": [
-		{
-			"link_id": {
-				"link_uuid": {
-					"uuid": "T1->R1"
-				}
-			},
-			"link_endpoint_ids": [
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "T1"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "1"
-					}
-				},
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "R1"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "12"
-					}
-				}
-			],
-			"optical_link": {
-				"name": "T1-R1",
-				"details": {
-					"length": 0,
-					"source": "muxT",
-					"target": "srgR",
-					"fibers": [
-						{
-							"ID": "M1",
-							"length": 0,
-							"src_port": "1",
-							"dst_port": "12",
-							"local_peer_port": "1",
-							"remote_peer_port": "2",
-							"used": false,
-							"c_slots": [
-								1,
-								2,
-								3,
-								4,
-								5,
-								6,
-								7,
-								8,
-								9,
-								10,
-								11,
-								12,
-								13,
-								14,
-								15,
-								16,
-								17,
-								18,
-								19,
-								20
-							],
-							"l_slots": [
-								101,
-								102,
-								103,
-								104,
-								105,
-								106,
-								107,
-								108,
-								109,
-								110,
-								111,
-								112,
-								113,
-								114,
-								115,
-								116,
-								117,
-								118,
-								119,
-								120
-							],
-							"s_slots": [
-								501,
-								502,
-								503,
-								504,
-								505,
-								506,
-								507,
-								508,
-								509,
-								510,
-								511,
-								512,
-								513,
-								514,
-								515,
-								516,
-								517,
-								518,
-								519,
-								520
-							]
-						}
-					]
-				}
-			}
-		},
-		{
-			"link_id": {
-				"link_uuid": {
-					"uuid": "R1->T1"
-				}
-			},
-			"link_endpoint_ids": [
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "R1"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "2"
-					}
-				},
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "T1"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "1"
-					}
-				}
-			],
-            "optical_link": {
-				"name": "R1-T1",
-				"details": {
-					"length": 0,
-					"source": "srgT",
-					"target": "muxT",
-					"fibers": [
-						{
-							"ID": "M1",
-							"length": 0,
-							"src_port": "2",
-							"dst_port": "1",
-							"local_peer_port": "12",
-							"remote_peer_port": "1",
-							"used": false,
-							"c_slots": [
-								1,
-								2,
-								3,
-								4,
-								5,
-								6,
-								7,
-								8,
-								9,
-								10,
-								11,
-								12,
-								13,
-								14,
-								15,
-								16,
-								17,
-								18,
-								19,
-								20
-							],
-							"l_slots": [
-								101,
-								102,
-								103,
-								104,
-								105,
-								106,
-								107,
-								108,
-								109,
-								110,
-								111,
-								112,
-								113,
-								114,
-								115,
-								116,
-								117,
-								118,
-								119,
-								120
-							],
-							"s_slots": [
-								501,
-								502,
-								503,
-								504,
-								505,
-								506,
-								507,
-								508,
-								509,
-								510,
-								511,
-								512,
-								513,
-								514,
-								515,
-								516,
-								517,
-								518,
-								519,
-								520
-							]
-						}
-					]
-				}
-			}
-		},
-		{
-			"link_id": {
-				"link_uuid": {
-					"uuid": "R1->R2"
-				}
-			},
-			"link_endpoint_ids": [
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "R1"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "3"
-					}
-				},
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "R2"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "14"
-					}
-				}
-			],
-            "optical_link": {
-				"name": "R1-R2",
-				"details": {
-					"length": 0,
-					"source": "D1",
-					"target": "D1",
-					"fibers": [
-						{
-							"ID": "D11",
-							"length": 0,
-							"src_port": "3",
-							"dst_port": "14",
-							"local_peer_port": "13",
-							"remote_peer_port": "4",
-							"c_slots": [
-								1,
-								2,
-								3,
-								4,
-								5,
-								6,
-								7,
-								8,
-								9,
-								10,
-								11,
-								12,
-								13,
-								14,
-								15,
-								16,
-								17,
-								18,
-								19,
-								20
-							],
-							"l_slots": [
-								101,
-								102,
-								103,
-								104,
-								105,
-								106,
-								107,
-								108,
-								109,
-								110,
-								111,
-								112,
-								113,
-								114,
-								115,
-								116,
-								117,
-								118,
-								119,
-								120
-							],
-							"s_slots": [
-								501,
-								502,
-								503,
-								504,
-								505,
-								506,
-								507,
-								508,
-								509,
-								510,
-								511,
-								512,
-								513,
-								514,
-								515,
-								516,
-								517,
-								518,
-								519,
-								520
-							]
-						}
-					]
-				}
-			}
-		},
-		{
-		"link_id": {
-				"link_uuid": {
-					"uuid": "R2->R1"
-				}
-			},
-			"link_endpoint_ids": [
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "R2"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "4"
-					}
-				},
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "R1"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "13"
-					}
-				}
-			],
-            "optical_link": {
-				"name": "R2-R1",
-				"details": {
-					"length": 0,
-					"source": "D1",
-					"target": "D1",
-					"fibers": [
-						{
-							"ID": "D11",
-							"length": 0,
-							"src_port": "4",
-							"dst_port": "13",
-							"local_peer_port": "14",
-							"remote_peer_port": "3",
-							"c_slots": [
-								1,
-								2,
-								3,
-								4,
-								5,
-								6,
-								7,
-								8,
-								9,
-								10,
-								11,
-								12,
-								13,
-								14,
-								15,
-								16,
-								17,
-								18,
-								19,
-								20
-							],
-							"l_slots": [
-								101,
-								102,
-								103,
-								104,
-								105,
-								106,
-								107,
-								108,
-								109,
-								110,
-								111,
-								112,
-								113,
-								114,
-								115,
-								116,
-								117,
-								118,
-								119,
-								120
-							],
-							"s_slots": [
-								501,
-								502,
-								503,
-								504,
-								505,
-								506,
-								507,
-								508,
-								509,
-								510,
-								511,
-								512,
-								513,
-								514,
-								515,
-								516,
-								517,
-								518,
-								519,
-								520
-							]
-						}
-					]
-				}
-			}
-		},
-		{
-			"link_id": {
-				"link_uuid": {
-					"uuid": "T2->R2"
-				}
-			},
-			"link_endpoint_ids": [
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "T2"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "6"
-					}
-				},
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "R2"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "15"
-					}
-				}
-			],
-            "optical_link": {
-				"name": "T2-R2",
-				"details": {
-					"length": 0,
-					"source": "srgT",
-					"target": "muxT",
-					"fibers": [
-						{
-							"ID": "M1",
-							"length": 0,
-							"src_port": "6",
-							"dst_port": "15",
-							"local_peer_port": "6",
-							"remote_peer_port": "5",
-							"used": false,
-							"c_slots": [
-								1,
-								2,
-								3,
-								4,
-								5,
-								6,
-								7,
-								8,
-								9,
-								10,
-								11,
-								12,
-								13,
-								14,
-								15,
-								16,
-								17,
-								18,
-								19,
-								20
-							],
-							"l_slots": [
-								101,
-								102,
-								103,
-								104,
-								105,
-								106,
-								107,
-								108,
-								109,
-								110,
-								111,
-								112,
-								113,
-								114,
-								115,
-								116,
-								117,
-								118,
-								119,
-								120
-							],
-							"s_slots": [
-								501,
-								502,
-								503,
-								504,
-								505,
-								506,
-								507,
-								508,
-								509,
-								510,
-								511,
-								512,
-								513,
-								514,
-								515,
-								516,
-								517,
-								518,
-								519,
-								520
-							]
-						}
-					]
-				}
-			}
-		},
-		{
-			"link_id": {
-				"link_uuid": {
-					"uuid": "R2->T2"
-				}
-			},
-			"link_endpoint_ids": [
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "R2"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "5"
-					}
-				},
-				{
-					"device_id": {
-						"device_uuid": {
-							"uuid": "T2"
-						}
-					},
-					"endpoint_uuid": {
-						"uuid": "6"
-					}
-				}
-			],
-            "optical_link": {
-				"name": "R2-T2",
-				"details": {
-					"length": 0,
-					"source": "srgT",
-					"target": "muxT",
-					"fibers": [
-						{
-							"ID": "M1",
-							"length": 0,
-							"src_port": "5",
-							"dst_port": "6",
-							"local_peer_port": "15",
-							"remote_peer_port": "6",
-							"used": false,
-							"c_slots": [
-								1,
-								2,
-								3,
-								4,
-								5,
-								6,
-								7,
-								8,
-								9,
-								10,
-								11,
-								12,
-								13,
-								14,
-								15,
-								16,
-								17,
-								18,
-								19,
-								20
-							],
-							"l_slots": [
-								101,
-								102,
-								103,
-								104,
-								105,
-								106,
-								107,
-								108,
-								109,
-								110,
-								111,
-								112,
-								113,
-								114,
-								115,
-								116,
-								117,
-								118,
-								119,
-								120
-							],
-							"s_slots": [
-								501,
-								502,
-								503,
-								504,
-								505,
-								506,
-								507,
-								508,
-								509,
-								510,
-								511,
-								512,
-								513,
-								514,
-								515,
-								516,
-								517,
-								518,
-								519,
-								520
-							]
-						}
-					]
-				}
-			}
-		}
-	]
-}
\ No newline at end of file
diff --git a/src/opticalcontroller/json_files/topo_2_links.json b/src/opticalcontroller/json_files/topo_2_links.json
deleted file mode 100644
index 02165938ce675071a4ff4c3424e3b53244d40810..0000000000000000000000000000000000000000
--- a/src/opticalcontroller/json_files/topo_2_links.json
+++ /dev/null
@@ -1,1530 +0,0 @@
-{
-  "R1-R3": {
-    "length": 80,
-    "source": "d2",
-    "target": "d1",
-    "fibers": {
-      "d2-1": {
-        "length": 80,
-        "src_port": "103",
-        "dst_port": "201",
-        "local_peer_port": "203",
-        "remote_peer_port": "101",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "d2-2": {
-        "length": 80,
-        "src_port": "104",
-        "dst_port": "202",
-        "local_peer_port": "204",
-        "remote_peer_port": "102",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R3-R1": {
-    "length": 80,
-    "source": "d1",
-    "target": "d2",
-    "fibers": {
-      "d1-1": {
-        "length": 80,
-        "src_port": "101",
-        "dst_port": "203",
-        "local_peer_port": "201",
-        "remote_peer_port": "103",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "d1-2": {
-        "length": 80,
-        "src_port": "102",
-        "dst_port": "204",
-        "local_peer_port": "202",
-        "remote_peer_port": "104",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R2-R3": {
-    "length": 80,
-    "source": "d2",
-    "target": "d2",
-    "fibers": {
-      "d2-1": {
-        "length": 80,
-        "src_port": "103",
-        "dst_port": "203",
-        "local_peer_port": "203",
-        "remote_peer_port": "103",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "d2-2": {
-        "length": 80,
-        "src_port": "104",
-        "dst_port": "204",
-        "local_peer_port": "204",
-        "remote_peer_port": "104",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R3-R2": {
-    "length": 80,
-    "source": "d2",
-    "target": "d2",
-    "fibers": {
-      "d2-1": {
-        "length": 80,
-        "src_port": "103",
-        "dst_port": "203",
-        "local_peer_port": "203",
-        "remote_peer_port": "103",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "d2-2": {
-        "length": 80,
-        "src_port": "104",
-        "dst_port": "204",
-        "local_peer_port": "204",
-        "remote_peer_port": "104",
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "T1-R1": {
-    "length": 0,
-    "source": "muxT",
-    "target": "srgR",
-    "fibers": {
-      "M1": {
-        "length": 0,
-        "src_port": "1",
-        "dst_port": "2001",
-        "local_peer_port": "1",
-        "remote_peer_port": "1001",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "M2": {
-        "length": 0,
-        "src_port": "2",
-        "dst_port": "2002",
-        "local_peer_port": "2",
-        "remote_peer_port": "1002",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "M3": {
-        "length": 0,
-        "src_port": "3",
-        "dst_port": "2003",
-        "local_peer_port": "3",
-        "remote_peer_port": "1003",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R1-T1": {
-    "length": 0,
-    "source": "srgT",
-    "target": "muxR",
-    "fibers": {
-      "S1": {
-        "length": 0,
-        "src_port": "1001",
-        "dst_port": "1",
-        "local_peer_port": "2001",
-        "remote_peer_port": "1",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "S2": {
-        "length": 0,
-        "src_port": "1002",
-        "dst_port": "2",
-        "local_peer_port": "2002",
-        "remote_peer_port": "2",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "S3": {
-        "length": 0,
-        "src_port": "1003",
-        "dst_port": "3",
-        "local_peer_port": "2003",
-        "remote_peer_port": "3",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "T2-R2": {
-    "length": 0,
-    "source": "muxT",
-    "target": "srgR",
-    "fibers": {
-      "M1": {
-        "length": 0,
-        "src_port": "1",
-        "dst_port": "2001",
-        "local_peer_port": "1",
-        "remote_peer_port": "1001",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "M2": {
-        "length": 0,
-        "src_port": "2",
-        "dst_port": "2002",
-        "local_peer_port": "2",
-        "remote_peer_port": "1002",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "M3": {
-        "length": 0,
-        "src_port": "3",
-        "dst_port": "2003",
-        "local_peer_port": "3",
-        "remote_peer_port": "1003",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  },
-  "R2-T2": {
-    "length": 0,
-    "source": "srgT",
-    "target": "muxR",
-    "fibers": {
-      "S1": {
-        "length": 0,
-        "src_port": "1001",
-        "dst_port": "1",
-        "local_peer_port": "2001",
-        "remote_peer_port": "1",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "S2": {
-        "length": 0,
-        "src_port": "1002",
-        "dst_port": "2",
-        "local_peer_port": "2002",
-        "remote_peer_port": "2",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      },
-      "S3": {
-        "length": 0,
-        "src_port": "1003",
-        "dst_port": "3",
-        "local_peer_port": "2003",
-        "remote_peer_port": "3",
-        "used": false,
-        "c_slots": [
-          1,
-          2,
-          3,
-          4,
-          5,
-          6,
-          7,
-          8,
-          9,
-          10,
-          11,
-          12,
-          13,
-          14,
-          15,
-          16,
-          17,
-          18,
-          19,
-          20
-        ],
-        "l_slots": [
-          101,
-          102,
-          103,
-          104,
-          105,
-          106,
-          107,
-          108,
-          109,
-          110,
-          111,
-          112,
-          113,
-          114,
-          115,
-          116,
-          117,
-          118,
-          119,
-          120
-        ],
-        "s_slots": [
-          501,
-          502,
-          503,
-          504,
-          505,
-          506,
-          507,
-          508,
-          509,
-          510,
-          511,
-          512,
-          513,
-          514,
-          515,
-          516,
-          517,
-          518,
-          519,
-          520
-        ]
-      }
-    }
-  }
-}
diff --git a/src/opticalcontroller/json_files/topology-optical.json b/src/opticalcontroller/json_files/topology-optical.json
deleted file mode 100644
index e2453b654d53fc3200570ce9c2b17effc964bd25..0000000000000000000000000000000000000000
--- a/src/opticalcontroller/json_files/topology-optical.json
+++ /dev/null
@@ -1,252 +0,0 @@
-{
-    "r1-r2": {
-        "length": 80,
-        "source" : "d1",
-        "target" : "d1",
-        "fibers" : {
-            "d1-1": {
-                "src_port": "1T",
-                "dst_port": "1R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "d1-2":{
-                "src_port": "2T",
-                "dst_port": "2R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            }
-        }
-    },
-    "r2-r1": {
-        "length": 80,
-        "source" : "d1",
-        "target" : "d1",
-        "fibers" : {
-            "d1-1" : {
-                "src_port": "1T",
-                "dst_port": "1R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "d1-2" : {
-                "src_port": "2T",
-                 "dst_port": "2R",
-                 "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                 "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                 "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            }
-        }
-    },
-    "r1-r3": {
-        "length": 80,
-        "source" : "d2",
-        "target" : "d1",
-        "fibers" : {
-            "d2-1":{
-                "src_port": "3T",
-                "dst_port": "1R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "d2-2":{
-                "src_port": "4T",
-                "dst_port": "2R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            }
-        }
-    },
-    "r3-r1": {
-        "length": 80,
-        "source" : "d1",
-        "target" : "d2",
-        "fibers" : {
-            "d1-1": {
-                "src_port": "1T",
-                "dst_port": "3R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-                },
-            "d1-2": {
-                "src_port": "2T",
-                "dst_port": "4R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            }
-        }
-    },
-    "r2-r3": {
-        "length": 80,
-        "source" : "d2",
-        "target" : "d2",
-        "fibers" : {
-            "d2-1": {
-                "src_port": "3T",
-                "dst_port": "3R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "d2-2": {
-                "src_port": "4T",
-                "dst_port": "4R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            }
-        }
-    },
-    "r3-r2": {
-        "length": 80,
-        "source" : "d2",
-        "target" : "d2",
-        "fibers" : {
-            "d2-1": {
-                "src_port": "3T",
-                "dst_port": "3R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "d2-2":{
-                "src_port": "4T",
-                "dst_port": "4R",
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            }
-        }
-    },
-    "t1-r1": {
-        "length": 0,
-        "source" : "muxT",
-        "target" : "srgR",
-        "fibers" : {
-            "M1": {
-                "src_port": "1",
-                "dst_port": "101R",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "M2": {
-                "src_port": "2",
-                "dst_port": "102R",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "M3": {
-                "src_port": "3",
-                "dst_port": "103R",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            }
-        }
-    },
-    "r1-t1": {
-        "length": 0,
-        "source" : "srgT",
-        "target" : "muxR",
-        "fibers" : {
-            "S1": {
-                "src_port": "101T",
-                "dst_port": "1",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "S2": {
-                "src_port": "102T",
-                "dst_port": "2",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "S3": {
-                "src_port": "103T",
-                "dst_port": "3",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            }
-        }
-    },
-    "t2-r2": {
-        "length": 0,
-        "source" : "muxT",
-        "target" : "srgR",
-        "fibers" : {
-            "M1": {
-                "src_port": "1",
-                "dst_port": "101R",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "M2": {
-                "src_port": "2",
-                "dst_port": "102R",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "M3": {
-                "src_port": "3",
-                "dst_port": "103R",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            }
-        }
-    },
-    "r2-t2": {
-        "length": 0,
-        "source" : "srgT",
-        "target" : "muxR",
-        "fibers" : {
-            "S1": {
-                "src_port": "101T",
-                "dst_port": "1",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "S2": {
-                "src_port": "102T",
-                "dst_port": "2",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            },
-            "S3": {
-                "src_port": "103T",
-                "dst_port": "3",
-                "used": false,
-                "c_slots": {"1": 1, "2": 1, "3": 1, "4": 1},
-                "l_slots": {"101": 1, "102": 1, "103": 1, "104": 1},
-                "s_slots": {"1001": 1, "1002": 1, "1003": 1, "1004": 1}
-            }
-        }
-    }
-}
diff --git a/src/opticalcontroller/json_files/topology-optical2.json b/src/opticalcontroller/json_files/topology-optical2.json
deleted file mode 100644
index fe8e9866bcc64d52b2f49089ce03af47d72df9d0..0000000000000000000000000000000000000000
--- a/src/opticalcontroller/json_files/topology-optical2.json
+++ /dev/null
@@ -1,324 +0,0 @@
-{
-    "r1-r2": {
-        "length": 80,
-        "source" : "d1",
-        "target" : "d1",
-        "fibers" : {
-            "d1-1": {
-                "length": 80,
-                "src_port": "1T",
-                "dst_port": "1R",
-                "local_peer_port": "1R",
-                "remote_peer_port": "1T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "d1-2":{
-                "length": 80,
-                "src_port": "2T",
-                "dst_port": "2R",
-                "local_peer_port": "2R",
-                "remote_peer_port": "2T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            }
-        }
-    },
-    "r2-r1": {
-        "length": 80,
-        "source" : "d1",
-        "target" : "d1",
-        "fibers" : {
-            "d1-1" : {
-                "length": 80,
-                "src_port": "1T",
-                "dst_port": "1R",
-                "local_peer_port": "1R",
-                "remote_peer_port": "1T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "d1-2" : {
-                "length": 80,
-                "src_port": "2T",
-                "dst_port": "2R",
-                "local_peer_port": "2R",
-                "remote_peer_port": "2T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            }
-        }
-    },
-    "r1-r3": {
-        "length": 80,
-        "source" : "d2",
-        "target" : "d1",
-        "fibers" : {
-            "d2-1":{
-                "length": 80,
-                "src_port": "3T",
-                "dst_port": "1R",
-                "local_peer_port": "3R",
-                "remote_peer_port": "1T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "d2-2":{
-                "length": 80,
-                "src_port": "4T",
-                "dst_port": "2R",
-                "local_peer_port": "4R",
-                "remote_peer_port": "2T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            }
-        }
-    },
-    "r3-r1": {
-        "length": 80,
-        "source" : "d1",
-        "target" : "d2",
-        "fibers" : {
-            "d1-1": {
-                "length": 80,
-                "src_port": "1T",
-                "dst_port": "3R",
-                "local_peer_port": "1R",
-                "remote_peer_port": "3T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-                },
-            "d1-2": {
-                "length": 80,
-                "src_port": "2T",
-                "dst_port": "4R",
-                "local_peer_port": "2R",
-                "remote_peer_port": "4T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            }
-        }
-    },
-    "r2-r3": {
-        "length": 80,
-        "source" : "d2",
-        "target" : "d2",
-        "fibers" : {
-            "d2-1": {
-                "length": 80,
-                "src_port": "3T",
-                "dst_port": "3R",
-                "local_peer_port": "3R",
-                "remote_peer_port": "3T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "d2-2": {
-                "length": 80,
-                "src_port": "4T",
-                "dst_port": "4R",
-                "local_peer_port": "4R",
-                "remote_peer_port": "4T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            }
-        }
-    },
-    "r3-r2": {
-        "length": 80,
-        "source" : "d2",
-        "target" : "d2",
-        "fibers" : {
-            "d2-1": {
-                "length": 80,
-                "src_port": "3T",
-                "dst_port": "3R",
-                "local_peer_port": "3R",
-                "remote_peer_port": "3T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "d2-2":{
-                "length": 80,
-                "src_port": "4T",
-                "dst_port": "4R",
-                "local_peer_port": "4R",
-                "remote_peer_port": "4T",
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            }
-        }
-    },
-    "t1-r1": {
-        "length": 0,
-        "source" : "muxT",
-        "target" : "srgR",
-        "fibers" : {
-            "M1": {
-                "length": 0,
-                "src_port": "1",
-                "dst_port": "101R",
-                "local_peer_port": "1",
-                "remote_peer_port": "101T",
-                "used": false,
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "M2": {
-                "length": 0,
-                "src_port": "2",
-                "dst_port": "102R",
-                "local_peer_port": "2",
-                "remote_peer_port": "102T",
-                "used": false,
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "M3": {
-                "length": 0,
-                "src_port": "3",
-                "dst_port": "103R",
-                "local_peer_port": "3",
-                "remote_peer_port": "103T",
-                "used": false,
-                "c_slots": [],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            }
-        }
-    },
-    "r1-t1": {
-        "length": 0,
-        "source" : "srgT",
-        "target" : "muxR",
-        "fibers" : {
-            "S1": {
-                "length": 0,
-                "src_port": "101T",
-                "dst_port": "1",
-                "local_peer_port": "101R",
-                "remote_peer_port": "1",
-                "used": false,
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "S2": {
-                "length": 0,
-                "src_port": "102T",
-                "dst_port": "2",
-                "local_peer_port": "102T",
-                "remote_peer_port": "2",
-                "used": false,
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "S3": {
-                "length": 0,
-                "src_port": "103T",
-                "dst_port": "3",
-                "local_peer_port": "103R",
-                "remote_peer_port": "3",
-                "used": false,
-                "c_slots": [],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            }
-        }
-    },
-    "t2-r2": {
-        "length": 0,
-        "source" : "muxT",
-        "target" : "srgR",
-        "fibers" : {
-            "M1": {
-                "length": 0,
-                "src_port": "1",
-                "dst_port": "101R",
-                "local_peer_port": "1",
-                "remote_peer_port": "101T",
-                "used": false,
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "M2": {
-                "length": 0,
-                "src_port": "2",
-                "dst_port": "102R",
-                "local_peer_port": "2",
-                "remote_peer_port": "102T",
-                "used": false,
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "M3": {
-                "length": 0,
-                "src_port": "3",
-                "dst_port": "103R",
-                "local_peer_port": "3",
-                "remote_peer_port": "103T",
-                "used": false,
-                "c_slots": [],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            }
-        }
-    },
-    "r2-t2": {
-        "length": 0,
-        "source" : "srgT",
-        "target" : "muxR",
-        "fibers" : {
-            "S1": {
-                "length": 0,
-                "src_port": "101T",
-                "dst_port": "1",
-                "local_peer_port": "101R",
-                "remote_peer_port": "1",
-                "used": false,
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "S2": {
-                "length": 0,
-                "src_port": "102T",
-                "dst_port": "2",
-                "local_peer_port": "102R",
-                "remote_peer_port": "2",
-                "used": false,
-                "c_slots": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            },
-            "S3": {
-                "length": 0,
-                "src_port": "103T",
-                "dst_port": "3",
-                "local_peer_port": "103R",
-                "remote_peer_port": "3",
-                "used": false,
-                "c_slots": [],
-                "l_slots": [101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119 ,120],
-                "s_slots": [501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519 ,520]
-            }
-        }
-    }
-}
diff --git a/src/opticalcontroller/requirements.in b/src/opticalcontroller/requirements.in
index 4732ee635a60b8320e25cd2c26388d1cfdfd25cc..15b3ca3a465efe5c9b7f5a217b1f5658a738405c 100644
--- a/src/opticalcontroller/requirements.in
+++ b/src/opticalcontroller/requirements.in
@@ -12,10 +12,25 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+aniso8601==9.0.1
+attrs==23.1.0
+blinker==1.6.2
+click==8.1.7
+colorama==0.4.6
 Flask==1.1.2
 flask-restplus==0.13.0
+importlib-metadata==6.8.0
+importlib-resources==6.0.1
 itsdangerous==1.1.0
 Jinja2==2.11.3
+jsonschema==4.19.0
+jsonschema-specifications==2023.7.1
 MarkupSafe==1.1.1
-numpy<2.0.0
+numpy==1.23.0
+pkgutil-resolve-name==1.3.10
+pytz==2023.3.post1
+referencing==0.30.2
+rpds-py==0.10.3
+six==1.16.0
 Werkzeug==0.16.1
+zipp==3.16.2
diff --git a/src/opticalcontroller/requirements_optical_ctrl_test.txt b/src/opticalcontroller/requirements_optical_ctrl_test.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0b1947bee2c7f1e89491dff4f7589d3465d28c38
--- /dev/null
+++ b/src/opticalcontroller/requirements_optical_ctrl_test.txt
@@ -0,0 +1,21 @@
+# 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.
+
+Flask==1.1.2
+flask-restplus==0.13.0
+itsdangerous==1.1.0
+Jinja2==2.11.3
+MarkupSafe==1.1.1
+numpy==1.23.0
+Werkzeug==0.16.1
diff --git a/src/opticalcontroller/tools.py b/src/opticalcontroller/tools.py
index a173856b8e7bd00a0e538cd3893e1c762edff8c8..08441f5c0010de1be503ee307410431ddfee54ab 100644
--- a/src/opticalcontroller/tools.py
+++ b/src/opticalcontroller/tools.py
@@ -12,9 +12,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import json
 import numpy as np
 from variables import  *
-import json
+from common.proto.context_pb2 import TopologyId , LinkId , OpticalLink , OpticalLinkDetails
+from common.tools.object_factory.OpticalLink import correct_slot
+from context.client.ContextClient import ContextClient
 
 
 def common_slots(a, b):
@@ -24,9 +27,11 @@ def common_slots(a, b):
 def map_modulation_to_op(mod):
     if mod == "DP-QPSK":
         return 1
-    if mod == "DP-16QAM":
-        return 7
-    if mod == "DP-64QAM":
+    elif mod == "DP-8QAM":
+        return 4
+    elif mod == "DP-16QAM":
+        return 8
+    elif mod == "DP-32QAM":
         return 10
 
 
@@ -40,13 +45,19 @@ def map_rate_to_slot(rate):
         slots = 4
         op = map_modulation_to_op(mod)
         return op, slots
-    if rate == 400:
+    elif rate == 400:
+        mod = "DP-8QAM"
+        slots = 4
+        op = map_modulation_to_op(mod)
+        return op, slots
+    elif rate == 800:
         mod = "DP-16QAM"
-        slots = 8
+        #todo: check slot width
+        slots = 8#12 (150GHz)
         op = map_modulation_to_op(mod)
         return op, slots
-    if rate == 1000:
-        mod = "DP-64QAM"
+    elif rate == 1000:
+        mod = "DP-32QAM"
         slots = 18
         op = map_modulation_to_op(mod)
         return op, slots
@@ -54,21 +65,34 @@ def map_rate_to_slot(rate):
         return 2, 5
 
 
-def consecutives(x, val):
+def consecutives(link, val):
     res = []
     temp = []
+    x1 = list(link.keys())
+    x = str_list_to_int(x1)
     x.sort()
-    temp.append(x[0])
-    y = 1
+    y = 0
+    if debug:
+        print("BLACK")
+        print(link)
+        print(x)
+        print(x[0])
+    if link[str(x[0])] == 1:
+        temp.append(int(x[0]))
+        y = 1
     for i in range(1, len(x)):
-        if x[i] == x[i - 1] + 1:
+        if (int(x[i]) == int(x[i - 1]) + 1) and link[str(x[i])] == 1:
             y += 1
-            temp.append(x[i])
+            temp.append(int(x[i]))
         else:
             if y >= val:
                 res.extend(temp)
-            temp = [x[i]]
-            y = 1
+            if link[str(x[i])] == 1:
+                temp = [int(x[i])]
+                y = 1
+            else:
+                temp = []
+                y = 0
         if i == len(x) - 1 and y >= val:
             res.extend(temp)
     return res
@@ -83,6 +107,14 @@ def combine(ls1, ls2):
     return temp
 
 
+def str_list_to_int(str_list):
+    int_list = []
+    for i in str_list:
+        int_list.append(int(i))
+    int_list.sort()
+    return int_list
+
+
 def list_in_list(a, b):
     # convert list A to numpy array
     a_arr = np.array(a)
@@ -112,7 +144,30 @@ def get_slot_frequency(b, n):
         return Fl + n * 12.5
 
 
-def freqency_converter(b, slots):
+def get_side_slots_on_link(link, val, old_slots):
+    #link = l["optical_details"][band]
+    x = list(old_slots.keys())
+    y = list(link.keys())
+    keys = str_list_to_int(x)
+    keys.sort()
+    #print("AAAA")
+    #print(link, val, old_slots, keys)
+    #print(x)
+    starting_slot = keys[-1]
+    num = 0
+    res = []
+    #print(starting_slot)
+    for slot_id in range(starting_slot, len(y)):
+        if link[y[slot_id]] == 1:
+            num += 1
+            res.append(int(y[slot_id]))
+        else:
+            return res, 0
+        if num == val or slot_id == len(y) - 1:
+            return res, num
+
+
+def frequency_converter(b, slots):
     l = len(slots)
     if debug:
         print(slots)
@@ -135,14 +190,24 @@ def freqency_converter(b, slots):
 
 
 def readTopologyData(nodes, topology):
-        nodes_file = open(nodes, 'r')
-        topo_file = open(topology, 'r')
-        nodes = json.load(nodes_file)
-        topo = json.load(topo_file)
-        print(topo)
-        nodes_file.close()
-        topo_file.close()
-        return nodes, topo
+    nodes_file = open(nodes, 'r')
+    topo_file = open(topology, 'r')
+    nodes = json.load(nodes_file)
+    topo = json.load(topo_file)
+    #print(topo)
+    nodes_file.close()
+    topo_file.close()
+    return nodes, topo
+
+    
+def readTopologyDataFromContext(topology_id:TopologyId): 
+    ctx_client = ContextClient()
+    ctx_client.connect()
+    topo_details = ctx_client.GetTopologyDetails(topology_id)
+    topo = topo_details.optical_links
+    nodes = topo_details.devices
+    ctx_client.close()
+    return topo , nodes
 
 
 def reverse_links(links):
@@ -154,23 +219,26 @@ def reverse_links(links):
         result.append("{}-{}".format(b, a))
     return result
 
+
 def get_links_from_node(topology, node):
     result = {}
-    for link in topology["links"]:
-        if "{}-".format(node) in link["optical_link"]["name"]:
-            result[link["optical_link"]["name"]] = link
+    for link in topology["optical_links"]:
+        if "{}-".format(node) in link["name"]:
+            result[link["name"]] = link
     return result
 
+
 def get_links_to_node(topology, node):
     result = {}
-    for link in topology["links"]:
-        if "-{}".format(node) in link["optical_link"]["name"]:
-            result[link["optical_link"]["name"]] = link
+    for link in topology["optical_links"]:
+        if "-{}".format(node) in link["name"]:
+            result[link["name"]] = link
     return result
 
 
 def slot_selection(c, l, s, n_slots, Nc, Nl, Ns):
     # First Fit
+    
     if isinstance(n_slots, int):
         slot_c = n_slots
         slot_l = n_slots
@@ -183,7 +251,75 @@ def slot_selection(c, l, s, n_slots, Nc, Nl, Ns):
         return "c_slots", c[0: slot_c]
     elif len(l) >= slot_l:
         return "l_slots", l[0: slot_l]
-    elif len(l) >= slot_s:
+    elif len(s) >= slot_s:
         return "s_slots", s[0: slot_s]
     else:
         return None, None
+
+def handle_slot (slot_field, slot):
+    for key,value in slot.items() :
+        slot_field[key]=value
+
+
+      
+def update_optical_band (optical_bands,optical_band_id,band,link):
+    key_list = optical_bands[optical_band_id][band].keys()
+    corrected_slots=optical_bands[optical_band_id][band]
+    print(f"band {band}")
+    print(f"corrected_slots_before {corrected_slots}")
+    if (len(key_list) < 20):
+        corrected_slots=correct_slot(optical_bands[optical_band_id][band])
+        
+    fib={}
+    print(f"corrected_slots_after {corrected_slots}")    
+    fib['c_slots']=link['optical_details']['c_slots']
+    fib['l_slots']=link['optical_details']['l_slots']
+    fib['s_slots']=link['optical_details']['s_slots']
+      
+    fib[band]=corrected_slots
+    fib["src_port"]=optical_bands[optical_band_id]['src_port']
+    fib["dst_port"]=optical_bands[optical_band_id]['dst_port']
+    fib["local_peer_port"]=link["optical_details"]["local_peer_port"]
+    fib["remote_peer_port"]=link["optical_details"]["remote_peer_port"]
+    set_link_update(fib,link,test=f"restoring_optical_band {link['link_id']}")
+    
+def set_link_update (fib:dict,link:dict,test="updating"):
+    
+    print(f"invoked from {test}")
+    print(f"fib updated {fib}")  
+    optical_link = OpticalLink()
+    linkId = LinkId()
+    linkId.link_uuid.uuid=link["link_id"]["link_uuid"]["uuid"]
+    optical_details = OpticalLinkDetails()
+    optical_link.optical_details.length=0
+    if "src_port" in fib :
+       optical_link.optical_details.src_port=fib["src_port"]
+    if "dst_port" in fib :   
+       optical_link.optical_details.dst_port=fib["dst_port"]
+    if "local_peer_port" in fib :   
+       optical_link.optical_details.local_peer_port=fib['local_peer_port']
+    if "remote_peer_port" in fib:   
+       optical_link.optical_details.remote_peer_port=fib['remote_peer_port']
+       
+    optical_link.optical_details.used=fib['used'] if 'used' in fib else False
+    if "c_slots" in fib :
+        
+        handle_slot( optical_link.optical_details.c_slots,fib["c_slots"])
+    if "s_slots" in fib :
+             
+       handle_slot( optical_link.optical_details.s_slots,fib["s_slots"])
+    if "l_slots" in fib :
+           
+       handle_slot( optical_link.optical_details.l_slots,fib["l_slots"])
+
+    
+    optical_link.name=link['name']
+  
+    optical_link.link_id.CopyFrom(linkId)
+    
+    ctx_client = ContextClient()
+    ctx_client.connect()
+    try:
+        ctx_client.SetOpticalLink(optical_link)
+    except Exception as err:
+        print (f"setOpticalLink {err}")    
diff --git a/src/opticalcontroller/variables.py b/src/opticalcontroller/variables.py
index ca436736b20a525c866ea9745be14bc4db37dfcf..83d073e92009c8796a396d19af0bc737865c77e9 100644
--- a/src/opticalcontroller/variables.py
+++ b/src/opticalcontroller/variables.py
@@ -23,10 +23,4 @@ Nc = 320
 #Nc = 10
 Ns = 720
 
-nodes_json = 'json_files/nodes.json'
-topology_json = 'json_files/tfs.json' #LAST
-#topology_json = 'json_files/optical_TFSworking.json' #LAST
-#topology_json = 'json_files/optical_topoTFS.json'
-#topology_json = 'json_files/topo_2_links.json'
-
-testing = 1
+full_links = 0
diff --git a/src/pathcomp/frontend/service/algorithms/_Algorithm.py b/src/pathcomp/frontend/service/algorithms/_Algorithm.py
index 3ed2b13fb33ae06faeacc4286959a8016ca995d1..3394d8df99933d8acc83a8cc8cebb1488ff6752c 100644
--- a/src/pathcomp/frontend/service/algorithms/_Algorithm.py
+++ b/src/pathcomp/frontend/service/algorithms/_Algorithm.py
@@ -14,6 +14,7 @@
 
 import json, logging, requests, uuid
 from typing import Dict, List, Optional, Tuple, Union
+from common.DeviceTypes import DeviceTypeEnum
 from common.proto.context_pb2 import (
     ConfigRule, Connection, Device, DeviceList, EndPointId, Link, LinkList, Service, ServiceStatusEnum, ServiceTypeEnum
 )
@@ -251,21 +252,37 @@ class _Algorithm:
                 ]
 
                 self.logger.debug('path_hops = {:s}'.format(str(path_hops)))
-                try:
-                    _device_dict = {k:v[0] for k,v in self.device_dict.items()}
-                    self.logger.debug('self.device_dict = {:s}'.format(str(_device_dict)))
-                    connections = convert_explicit_path_hops_to_connections(
-                        path_hops, self.device_dict, main_service_uuid, main_service_type)
-                    self.logger.debug('EXTRAPOLATED connections = {:s}'.format(str(connections)))
-                except: # pylint: disable=bare-except
-                    MSG = ' '.join([
-                        'Unable to Extrapolate sub-services and sub-connections.',
-                        'Assuming single-service and single-connection.',
-                    ])
-                    self.logger.exception(MSG)
+                device_types = {v[0]['device_type'] for k,v in self.device_dict.items()}
+                DEVICES_BASIC_CONNECTION = {
+                    DeviceTypeEnum.DATACENTER.value,    DeviceTypeEnum.EMULATED_DATACENTER.value,
+                    DeviceTypeEnum.CLIENT.value,        DeviceTypeEnum.EMULATED_CLIENT.value,
+                    DeviceTypeEnum.PACKET_ROUTER.value, DeviceTypeEnum.EMULATED_PACKET_ROUTER.value,
+                }
+                self.logger.debug('device_types = {:s}'.format(str(device_types)))
+                self.logger.debug('DEVICES_BASIC_CONNECTION = {:s}'.format(str(DEVICES_BASIC_CONNECTION)))
+                is_basic_connection = device_types.issubset(DEVICES_BASIC_CONNECTION)
+                self.logger.debug('is_basic_connection = {:s}'.format(str(is_basic_connection)))
+                if is_basic_connection:
+                    self.logger.info('Assuming basic connections...')
                     connections = convert_explicit_path_hops_to_plain_connection(
                         path_hops, main_service_uuid, main_service_type)
                     self.logger.debug('BASIC connections = {:s}'.format(str(connections)))
+                else:
+                    try:
+                        _device_dict = {k:v[0] for k,v in self.device_dict.items()}
+                        self.logger.debug('self.device_dict = {:s}'.format(str(_device_dict)))
+                        connections = convert_explicit_path_hops_to_connections(
+                            path_hops, self.device_dict, main_service_uuid, main_service_type)
+                        self.logger.debug('EXTRAPOLATED connections = {:s}'.format(str(connections)))
+                    except: # pylint: disable=bare-except
+                        MSG = ' '.join([
+                            'Unable to Extrapolate sub-services and sub-connections.',
+                            'Assuming single-service and single-connection.',
+                        ])
+                        self.logger.exception(MSG)
+                        connections = convert_explicit_path_hops_to_plain_connection(
+                            path_hops, main_service_uuid, main_service_type)
+                        self.logger.debug('BASIC connections = {:s}'.format(str(connections)))
 
                 for connection in connections:
                     service_uuid,service_type,path_hops,_ = connection
diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py
index 45a8e0b6c0fd9a26b45fc47d55074d8863c0caed..992b11cf3edaaed8211cd70a08452cd091cdf19a 100644
--- a/src/service/service/ServiceServiceServicerImpl.py
+++ b/src/service/service/ServiceServiceServicerImpl.py
@@ -17,7 +17,8 @@ from typing import Optional
 from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method
 from common.method_wrappers.ServiceExceptions import (
     AlreadyExistsException, InvalidArgumentException, NotFoundException, NotImplementedException,
-    OperationFailedException)
+    OperationFailedException
+)
 from common.proto.context_pb2 import (
     Connection, ConstraintActionEnum, Empty, Service, ServiceId, ServiceStatusEnum,
     ServiceTypeEnum, TopologyId
@@ -42,7 +43,8 @@ from .service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory
 from .task_scheduler.TaskScheduler import TasksScheduler
 from .tools.GeodesicDistance import gps_distance
 from .tools.OpticalTools import (
-    add_lightpath, delete_lightpath, adapt_reply, get_device_name_from_uuid, get_optical_band
+    add_lightpath, delete_lightpath, adapt_reply, get_device_name_from_uuid,
+    get_optical_band, refresh_opticalcontroller, DelFlexLightpath
 )
 
 
@@ -257,6 +259,8 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
                 DEFAULT_TOPOLOGY_NAME, context_id_x)
             topology_details = context_client.GetTopologyDetails(
                 TopologyId(**topology_id_x))
+        
+            refresh_opticalcontroller(topology_id_x)
             # devices = get_devices_in_topology(context_client, TopologyId(**topology_id_x), ContextId(**context_id_x))
             devices = topology_details.devices
             context_uuid_x = topology_details.topology_id.context_id.context_uuid.uuid
@@ -292,7 +296,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
                             parent_ob = reply_json["parent_opt_band"]
                             LOGGER.debug('Parent optical-band={}'.format(parent_ob))
                             optical_band_txt = get_optical_band(parent_ob)
-                            LOGGER.info('optical-band details={}'.format(optical_band_txt))
+
                         else:
                             LOGGER.debug('expected optical band not found')
                     else:
@@ -301,12 +305,11 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
                     LOGGER.debug('Using existing optical band')
             else:
                 LOGGER.debug('Using existing optical band')
+
             if reply_txt is not None:
                 optical_reply = adapt_reply(
                     devices, _service, reply_json, context_uuid_x, topology_uuid_x, optical_band_txt
                 )
-                LOGGER.info('optical_reply={:s}'.format(
-                    grpc_message_to_json_string(optical_reply)))
 
                 tasks_scheduler.compose_from_pathcompreply(
                     optical_reply, is_delete=False)
@@ -342,6 +345,10 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
         if service is None: raise Exception('Service({:s}) not found'.format(grpc_message_to_json_string(request)))
         # pylint: disable=no-member
         service.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL
+
+        if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+             service.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_ACTIVE
+
         context_client.SetService(service)
 
         if is_deployed_te() and service.service_type == ServiceTypeEnum.SERVICETYPE_TE:
@@ -351,7 +358,14 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
             context_client.RemoveService(request)
             return Empty()
 
-        if is_deployed_optical() and service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+        if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+            params = {
+                "src"     : None,
+                "dst"     : None,
+                "bitrate" : None,
+                'ob_id'   : None,
+                'flow_id' : None
+            }
             devs = []
 
             context_id_x = json_context_id(DEFAULT_CONTEXT_NAME)
@@ -364,15 +378,38 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
                 devs.append(endpoint_id.device_id.device_uuid.uuid)
             src = get_device_name_from_uuid(devices, devs[0])
             dst = get_device_name_from_uuid(devices, devs[1])
-
-            bitrate = int(
-                float(service.service_constraints[0].custom.constraint_value))
+            bitrate = 100
+            for constraint in service.service_constraints:
+                if "bandwidth" in constraint.custom.constraint_type:
+                    bitrate = int(float(constraint.custom.constraint_value))
+                    break
+            
+            bitrate = int(float(
+                service.service_constraints[0].custom.constraint_value
+            ))
             if len(service.service_config.config_rules) > 0:
                 c_rules_dict = json.loads(
                 service.service_config.config_rules[0].custom.resource_value)
+                ob_id = None
+                flow_id = None
+             
+                if "ob_id" in c_rules_dict:
+                    ob_id = c_rules_dict["ob_id"]
                 if ("flow_id" in c_rules_dict):
                     flow_id = c_rules_dict["flow_id"]
-                    reply = delete_lightpath(flow_id, src, dst, bitrate)
+                    #if ("ob_id" in c_rules_dict):
+                    #    ob_id = c_rules_dict["ob_id"]
+            
+                params['bitrate'] = bitrate
+                params['dst'    ] = dst
+                params['src'    ] = src
+                params['ob_id'  ] = ob_id
+                params['flow_id'] = flow_id
+
+            tasks_scheduler = TasksScheduler(self.service_handler_factory)
+            tasks_scheduler.compose_from_optical_service(service, params=params, is_delete=True)
+            tasks_scheduler.execute_all()
+            return Empty()
 
         # Normal service
         # Feed TaskScheduler with this service and the sub-services and sub-connections related to this service.
diff --git a/src/service/service/__main__.py b/src/service/service/__main__.py
index ae8a9e960cf6a0d720b508fe3ea5592632420c18..d4bbccea4fdb03fa8e8f93d8b9987b8436bb434a 100644
--- a/src/service/service/__main__.py
+++ b/src/service/service/__main__.py
@@ -16,7 +16,8 @@ import logging, signal, sys, threading
 from prometheus_client import start_http_server
 from common.Constants import ServiceNameEnum
 from common.Settings import (
-    ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, get_env_var_name, get_log_level, get_metrics_port,
+    ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC,
+    get_env_var_name, get_log_level, get_metrics_port,
     wait_for_environment_variables
 )
 from .ServiceService import ServiceService
diff --git a/src/service/service/service_handler_api/SettingsHandler.py b/src/service/service/service_handler_api/SettingsHandler.py
index 293de54aa84be11f3c31bc1b47fce852df19a16a..24c5b638a35859b144969425d36ddad63a39d611 100644
--- a/src/service/service/service_handler_api/SettingsHandler.py
+++ b/src/service/service/service_handler_api/SettingsHandler.py
@@ -57,6 +57,11 @@ class SettingsHandler:
     def get(self, key_or_path : Union[str, List[str]], default : Optional[Any] = None) -> Optional[TreeNode]:
         return get_subnode(self.__resolver, self.__config, key_or_path, default=default)
 
+    def get_service_settings(self) -> Optional[TreeNode]:
+        service_settings_uri = '/settings'
+        service_settings = self.get(service_settings_uri)
+        return service_settings
+
     def get_device_settings(self, device : Device) -> Optional[TreeNode]:
         device_keys = device.device_id.device_uuid.uuid, device.name
 
diff --git a/src/service/service/service_handlers/l3nm_gnmi_openconfig/ConfigRuleComposer.py b/src/service/service/service_handlers/l3nm_gnmi_openconfig/ConfigRuleComposer.py
index be314a8c1ee5112dd9d321dd2c1ee1dc6173aca4..777cc4588a6d3a1a3664f736faf03665efa50c79 100644
--- a/src/service/service/service_handlers/l3nm_gnmi_openconfig/ConfigRuleComposer.py
+++ b/src/service/service/service_handlers/l3nm_gnmi_openconfig/ConfigRuleComposer.py
@@ -12,33 +12,65 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from typing import Dict, List, Optional, Tuple
-from common.proto.context_pb2 import Device, EndPoint
+import json, logging, netaddr, re
+from typing import Dict, List, Optional, Set, Tuple
+from common.DeviceTypes import DeviceTypeEnum
+from common.proto.context_pb2 import ConfigActionEnum, Device, EndPoint, Service
 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 _interface(if_name, sif_index, ipv4_address, ipv4_prefix, enabled) -> Tuple[str, Dict]:
-    str_path = '/interface[{:s}]'.format(if_name)
-    str_data = {'name': if_name, 'enabled': enabled, 'sub_if_index': sif_index,
-                'sub_if_enabled': enabled, 'sub_if_ipv4_enabled': enabled,
-                'sub_if_ipv4_address': ipv4_address, 'sub_if_ipv4_prefix': ipv4_prefix}
-    return str_path, str_data
+LOGGER = logging.getLogger(__name__)
+
+NETWORK_INSTANCE = 'teraflowsdn'
+
+RE_IF    = re.compile(r'^\/interface\[([^\]]+)\]$')
+RE_SUBIF = re.compile(r'^\/interface\[([^\]]+)\]\/subinterface\[([^\]]+)\]$')
+RE_SR    = re.compile(r'^\/network_instance\[([^\]]+)\]\/protocols\[STATIC\]/route\[([^\:]+)\:([^\]]+)\]$')
+
+def _interface(
+    interface : str, if_type : Optional[str] = 'l3ipvlan', index : int = 0, vlan_id : Optional[int] = None,
+    address_ip : Optional[str] = None, address_prefix : Optional[int] = None, mtu : Optional[int] = None,
+    enabled : bool = True
+) -> Tuple[str, Dict]:
+    path = '/interface[{:s}]/subinterface[{:d}]'.format(interface, index)
+    data = {'name': interface, 'type': if_type, 'index': index, 'enabled': enabled}
+    if if_type is not None: data['type'] = if_type
+    if vlan_id is not None: data['vlan_id'] = vlan_id
+    if address_ip is not None: data['address_ip'] = address_ip
+    if address_prefix is not None: data['address_prefix'] = address_prefix
+    if mtu is not None: data['mtu'] = mtu
+    return path, data
 
-def _network_instance(ni_name, ni_type) -> Tuple[str, Dict]:
-    str_path = '/network_instance[{:s}]'.format(ni_name)
-    str_data = {'name': ni_name, 'type': ni_type}
-    return str_path, str_data
+def _network_instance(ni_name : str, ni_type : str) -> Tuple[str, Dict]:
+    path = '/network_instance[{:s}]'.format(ni_name)
+    data = {'name': ni_name, 'type': ni_type}
+    return path, data
 
-def _network_instance_static_route(ni_name, prefix, next_hop, next_hop_index=0) -> Tuple[str, Dict]:
-    str_path = '/network_instance[{:s}]/static_route[{:s}]'.format(ni_name, prefix)
-    str_data = {'name': ni_name, 'prefix': prefix, 'next_hop': next_hop, 'next_hop_index': next_hop_index}
-    return str_path, str_data
+def _network_instance_protocol(ni_name : str, protocol : str) -> Tuple[str, Dict]:
+    path = '/network_instance[{:s}]/protocols[{:s}]'.format(ni_name, protocol)
+    data = {'name': ni_name, 'identifier': protocol, 'protocol_name': protocol}
+    return path, data
 
-def _network_instance_interface(ni_name, if_name, sif_index) -> Tuple[str, Dict]:
-    str_path = '/network_instance[{:s}]/interface[{:s}.{:d}]'.format(ni_name, if_name, sif_index)
-    str_data = {'name': ni_name, 'if_name': if_name, 'sif_index': sif_index}
-    return str_path, str_data
+def _network_instance_protocol_static(ni_name : str) -> Tuple[str, Dict]:
+    return _network_instance_protocol(ni_name, 'STATIC')
+
+def _network_instance_protocol_static_route(
+    ni_name : str, prefix : str, next_hop : str, metric : int
+) -> Tuple[str, Dict]:
+    protocol = 'STATIC'
+    path = '/network_instance[{:s}]/protocols[{:s}]/static_route[{:s}:{:d}]'.format(ni_name, protocol, prefix, metric)
+    index = 'AUTO_{:d}_{:s}'.format(metric, next_hop.replace('.', '-'))
+    data = {
+        'name': ni_name, 'identifier': protocol, 'protocol_name': protocol,
+        'prefix': prefix, 'index': index, 'next_hop': next_hop, 'metric': metric
+    }
+    return path, data
+
+def _network_instance_interface(ni_name : str, interface : str, sub_interface_index : int) -> Tuple[str, Dict]:
+    sub_interface_name = '{:s}.{:d}'.format(interface, sub_interface_index)
+    path = '/network_instance[{:s}]/interface[{:s}]'.format(ni_name, sub_interface_name)
+    data = {'name': ni_name, 'id': sub_interface_name, 'interface': interface, 'subinterface': sub_interface_index}
+    return path, data
 
 class EndpointComposer:
     def __init__(self, endpoint_uuid : str) -> None:
@@ -46,74 +78,201 @@ class EndpointComposer:
         self.objekt : Optional[EndPoint] = None
         self.sub_interface_index = 0
         self.ipv4_address = None
-        self.ipv4_prefix = None
+        self.ipv4_prefix_len = None
 
-    def configure(self, endpoint_obj : EndPoint, settings : Optional[TreeNode]) -> None:
-        self.objekt = endpoint_obj
+    def configure(self, endpoint_obj : Optional[EndPoint], settings : Optional[TreeNode]) -> None:
+        if endpoint_obj is not None:
+            self.objekt = endpoint_obj
         if settings is None: return
         json_settings : Dict = settings.value
-        self.ipv4_address = json_settings['ipv4_address']
-        self.ipv4_prefix = json_settings['ipv4_prefix']
-        self.sub_interface_index = json_settings['sub_interface_index']
+
+        if 'address_ip' in json_settings:
+            self.ipv4_address = json_settings['address_ip']
+        elif 'ip_address' in json_settings:
+            self.ipv4_address = json_settings['ip_address']
+        else:
+            MSG = 'IP Address not found. Tried: address_ip and ip_address. endpoint_obj={:s} settings={:s}'
+            LOGGER.warning(MSG.format(str(endpoint_obj), str(settings)))
+
+        if 'address_prefix' in json_settings:
+            self.ipv4_prefix_len = json_settings['address_prefix']
+        elif 'prefix_length' in json_settings:
+            self.ipv4_prefix_len = json_settings['prefix_length']
+        else:
+            MSG = 'IP Address Prefix not found. Tried: address_prefix and prefix_length. endpoint_obj={:s} settings={:s}'
+            LOGGER.warning(MSG.format(str(endpoint_obj), str(settings)))
+
+        self.sub_interface_index = json_settings.get('index', 0)
 
     def get_config_rules(self, network_instance_name : str, delete : bool = False) -> List[Dict]:
+        if self.ipv4_address is None: return []
+        if self.ipv4_prefix_len is None: return []
         json_config_rule = json_config_rule_delete if delete else json_config_rule_set
-        return [
-            json_config_rule(*_interface(
-                self.objekt.name, self.sub_interface_index, self.ipv4_address, self.ipv4_prefix, True
-            )),
+        config_rules = [
             json_config_rule(*_network_instance_interface(
                 network_instance_name, self.objekt.name, self.sub_interface_index
             )),
         ]
+        if not delete:
+            config_rules.extend([
+                json_config_rule(*_interface(
+                    self.objekt.name, index=self.sub_interface_index, address_ip=self.ipv4_address,
+                    address_prefix=self.ipv4_prefix_len, enabled=True
+                )),
+            ])
+        return config_rules
+
+    def dump(self) -> Dict:
+        return {
+            'index'         : self.sub_interface_index,
+            'address_ip'    : self.ipv4_address,
+            'address_prefix': self.ipv4_prefix_len,
+        }
 
 class DeviceComposer:
     def __init__(self, device_uuid : str) -> None:
         self.uuid = device_uuid
         self.objekt : Optional[Device] = None
-        self.endpoints : Dict[str, EndpointComposer] = dict()
-        self.static_routes : Dict[str, str] = dict()
-    
+        self.aliases : Dict[str, str] = dict() # endpoint_name => endpoint_uuid
+        self.endpoints : Dict[str, EndpointComposer] = dict() # endpoint_uuid => EndpointComposer
+        self.connected : Set[str] = set()
+        self.static_routes : Dict[str, Dict[int, str]] = dict() # {prefix => {metric => next_hop}}
+
+    def set_endpoint_alias(self, endpoint_name : str, endpoint_uuid : str) -> None:
+        self.aliases[endpoint_name] = endpoint_uuid
+
     def get_endpoint(self, endpoint_uuid : str) -> EndpointComposer:
+        endpoint_uuid = self.aliases.get(endpoint_uuid, endpoint_uuid)
         if endpoint_uuid not in self.endpoints:
             self.endpoints[endpoint_uuid] = EndpointComposer(endpoint_uuid)
         return self.endpoints[endpoint_uuid]
 
     def configure(self, device_obj : Device, settings : Optional[TreeNode]) -> None:
         self.objekt = device_obj
+        for endpoint_obj in device_obj.device_endpoints:
+            endpoint_uuid = endpoint_obj.endpoint_id.endpoint_uuid.uuid
+            self.set_endpoint_alias(endpoint_obj.name, endpoint_uuid)
+            self.get_endpoint(endpoint_obj.name).configure(endpoint_obj, None)
+
+        # Find management interfaces
+        mgmt_ifaces = set()
+        for config_rule in device_obj.device_config.config_rules:
+            if config_rule.action != ConfigActionEnum.CONFIGACTION_SET: continue
+            if config_rule.WhichOneof('config_rule') != 'custom': continue
+            config_rule_custom = config_rule.custom
+            match = RE_IF.match(config_rule_custom.resource_key)
+            if match is None: continue
+            if_name = match.groups()[0]
+            resource_value = json.loads(config_rule_custom.resource_value)
+            management = resource_value.get('management', False)
+            if management: mgmt_ifaces.add(if_name)
+
+        # Find data plane interfaces
+        for config_rule in device_obj.device_config.config_rules:
+            if config_rule.action != ConfigActionEnum.CONFIGACTION_SET: continue
+            if config_rule.WhichOneof('config_rule') != 'custom': continue
+            config_rule_custom = config_rule.custom
+
+            match = RE_SUBIF.match(config_rule_custom.resource_key)
+            if match is not None:
+                if_name, subif_index = match.groups()
+                if if_name in mgmt_ifaces: continue
+                resource_value = json.loads(config_rule_custom.resource_value)
+                if 'address_ip' not in resource_value: continue
+                if 'address_prefix' not in resource_value: continue
+                ipv4_network    = str(resource_value['address_ip'])
+                ipv4_prefix_len = int(resource_value['address_prefix'])
+                endpoint = self.get_endpoint(if_name)
+                endpoint.ipv4_address = ipv4_network
+                endpoint.ipv4_prefix_len = ipv4_prefix_len
+                endpoint.sub_interface_index = int(subif_index)
+                endpoint_ip_network = netaddr.IPNetwork('{:s}/{:d}'.format(ipv4_network, ipv4_prefix_len))
+                self.connected.add(str(endpoint_ip_network.cidr))
+
+            match = RE_SR.match(config_rule_custom.resource_key)
+            if match is not None:
+                ni_name, prefix, metric = match.groups()
+                if ni_name != NETWORK_INSTANCE: continue
+                resource_value : Dict = json.loads(config_rule_custom.resource_value)
+                next_hop = resource_value['next_hop']
+                self.static_routes.setdefault(prefix, dict())[metric] = next_hop
+
         if settings is None: return
         json_settings : Dict = settings.value
-        static_routes = json_settings.get('static_routes', [])
+        static_routes : List[Dict] = json_settings.get('static_routes', [])
         for static_route in static_routes:
             prefix   = static_route['prefix']
             next_hop = static_route['next_hop']
-            self.static_routes[prefix] = next_hop
+            metric   = static_route.get('metric', 0)
+            self.static_routes.setdefault(prefix, dict())[metric] = next_hop
 
     def get_config_rules(self, network_instance_name : str, delete : bool = False) -> List[Dict]:
+        SELECTED_DEVICES = {DeviceTypeEnum.PACKET_ROUTER.value, DeviceTypeEnum.EMULATED_PACKET_ROUTER.value}
+        if self.objekt.device_type not in SELECTED_DEVICES: return []
+
         json_config_rule = json_config_rule_delete if delete else json_config_rule_set
         config_rules = [
             json_config_rule(*_network_instance(network_instance_name, 'L3VRF'))
         ]
         for endpoint in self.endpoints.values():
             config_rules.extend(endpoint.get_config_rules(network_instance_name, delete=delete))
-        for prefix, next_hop in self.static_routes.items():
+        if len(self.static_routes) > 0:
             config_rules.append(
-                json_config_rule(*_network_instance_static_route(network_instance_name, prefix, next_hop))
+                json_config_rule(*_network_instance_protocol_static(network_instance_name))
             )
+        for prefix, metric_next_hop in self.static_routes.items():
+            for metric, next_hop in metric_next_hop.items():
+                config_rules.append(
+                    json_config_rule(*_network_instance_protocol_static_route(
+                        network_instance_name, prefix, next_hop, metric
+                    ))
+                )
         if delete: config_rules = list(reversed(config_rules))
         return config_rules
 
+    def dump(self) -> Dict:
+        return {
+            'endpoints' : {
+                endpoint_uuid : endpoint.dump()
+                for endpoint_uuid, endpoint in self.endpoints.items()
+            },
+            'connected' : list(self.connected),
+            'static_routes' : self.static_routes,
+        }
+
 class ConfigRuleComposer:
     def __init__(self) -> None:
-        self.devices : Dict[str, DeviceComposer] = dict()
+        self.objekt : Optional[Service] = None
+        self.aliases : Dict[str, str] = dict() # device_name => device_uuid
+        self.devices : Dict[str, DeviceComposer] = dict() # device_uuid => DeviceComposer
+
+    def set_device_alias(self, device_name : str, device_uuid : str) -> None:
+        self.aliases[device_name] = device_uuid
 
     def get_device(self, device_uuid : str) -> DeviceComposer:
+        device_uuid = self.aliases.get(device_uuid, device_uuid)
         if device_uuid not in self.devices:
             self.devices[device_uuid] = DeviceComposer(device_uuid)
         return self.devices[device_uuid]
 
-    def get_config_rules(self, network_instance_name : str, delete : bool = False) -> Dict[str, List[Dict]]:
+    def configure(self, service_obj : Service, settings : Optional[TreeNode]) -> None:
+        self.objekt = service_obj
+        if settings is None: return
+        #json_settings : Dict = settings.value
+        # For future use
+
+    def get_config_rules(
+        self, network_instance_name : str = NETWORK_INSTANCE, delete : bool = False
+    ) -> Dict[str, List[Dict]]:
         return {
             device_uuid : device.get_config_rules(network_instance_name, delete=delete)
             for device_uuid, device in self.devices.items()
         }
+
+    def dump(self) -> Dict:
+        return {
+            'devices' : {
+                device_uuid : device.dump()
+                for device_uuid, device in self.devices.items()
+            }
+        }
diff --git a/src/service/service/service_handlers/l3nm_gnmi_openconfig/L3NMGnmiOpenConfigServiceHandler.py b/src/service/service/service_handlers/l3nm_gnmi_openconfig/L3NMGnmiOpenConfigServiceHandler.py
index 5856b5f61893174a92ce02a303ae9ad30be16005..88bb5655b872dfce90988686e7d8bc242d866bf0 100644
--- a/src/service/service/service_handlers/l3nm_gnmi_openconfig/L3NMGnmiOpenConfigServiceHandler.py
+++ b/src/service/service/service_handlers/l3nm_gnmi_openconfig/L3NMGnmiOpenConfigServiceHandler.py
@@ -15,14 +15,17 @@
 import json, logging
 from typing import Any, Dict, 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.proto.context_pb2 import ConfigRule, ConnectionId, DeviceId, Service
+from common.tools.object_factory.Connection import json_connection_id
 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.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching
 from service.service.task_scheduler.TaskExecutor import TaskExecutor
+from service.service.tools.EndpointIdFormatters import endpointids_to_raw
 from .ConfigRuleComposer import ConfigRuleComposer
+from .StaticRouteGenerator import StaticRouteGenerator
 
 LOGGER = logging.getLogger(__name__)
 
@@ -35,24 +38,35 @@ class L3NMGnmiOpenConfigServiceHandler(_ServiceHandler):
         self.__service = service
         self.__task_executor = task_executor
         self.__settings_handler = SettingsHandler(service.service_config, **settings)
-        self.__composer = ConfigRuleComposer()
-        self.__endpoint_map : Dict[Tuple[str, str], str] = dict()
+        self.__config_rule_composer = ConfigRuleComposer()
+        self.__static_route_generator = StaticRouteGenerator(self.__config_rule_composer)
+        self.__endpoint_map : Dict[Tuple[str, str], Tuple[str, str]] = dict()
 
     def _compose_config_rules(self, endpoints : List[Tuple[str, str, Optional[str]]]) -> None:
+        if len(endpoints) % 2 != 0: raise Exception('Number of endpoints should be even')
+
+        service_settings = self.__settings_handler.get_service_settings()
+        self.__config_rule_composer.configure(self.__service, service_settings)
+
         for endpoint in endpoints:
             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)
-            _device = self.__composer.get_device(device_obj.name)
+            self.__config_rule_composer.set_device_alias(device_obj.name, device_uuid)
+            _device = self.__config_rule_composer.get_device(device_obj.name)
             _device.configure(device_obj, device_settings)
 
             endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid)
             endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj)
+            _device.set_endpoint_alias(endpoint_obj.name, endpoint_uuid)
             _endpoint = _device.get_endpoint(endpoint_obj.name)
             _endpoint.configure(endpoint_obj, endpoint_settings)
 
-            self.__endpoint_map[(device_uuid, endpoint_uuid)] = device_obj.name
+            self.__endpoint_map[(device_uuid, endpoint_uuid)] = (device_obj.name, endpoint_obj.name)
+
+        self.__static_route_generator.compose(endpoints)
+        LOGGER.debug('config_rule_composer = {:s}'.format(json.dumps(self.__config_rule_composer.dump())))
 
     def _do_configurations(
         self, config_rules_per_device : Dict[str, List[Dict]], endpoints : List[Tuple[str, str, Optional[str]]],
@@ -62,7 +76,7 @@ class L3NMGnmiOpenConfigServiceHandler(_ServiceHandler):
         results_per_device = dict()
         for device_name,json_config_rules in config_rules_per_device.items():
             try:
-                device_obj = self.__composer.get_device(device_name).objekt
+                device_obj = self.__config_rule_composer.get_device(device_name).objekt
                 if len(json_config_rules) == 0: continue
                 del device_obj.device_config.config_rules[:]
                 for json_config_rule in json_config_rules:
@@ -78,7 +92,8 @@ class L3NMGnmiOpenConfigServiceHandler(_ServiceHandler):
         results = []
         for endpoint in endpoints:
             device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint)
-            device_name = self.__endpoint_map[(device_uuid, endpoint_uuid)]
+            device_name, _ = self.__endpoint_map[(device_uuid, endpoint_uuid)]
+            if device_name not in results_per_device: continue
             results.append(results_per_device[device_name])
         return results
 
@@ -88,12 +103,16 @@ class L3NMGnmiOpenConfigServiceHandler(_ServiceHandler):
     ) -> 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')
-        self._compose_config_rules(endpoints)
-        network_instance_name = service_uuid.split('-')[0]
-        config_rules_per_device = self.__composer.get_config_rules(network_instance_name, delete=False)
+        #service_uuid = self.__service.service_id.service_uuid.uuid
+        connection = self.__task_executor.get_connection(ConnectionId(**json_connection_id(connection_uuid)))
+        connection_endpoint_ids = endpointids_to_raw(connection.path_hops_endpoint_ids)
+        self._compose_config_rules(connection_endpoint_ids)
+        #network_instance_name = service_uuid.split('-')[0]
+        #config_rules_per_device = self.__config_rule_composer.get_config_rules(network_instance_name, delete=False)
+        config_rules_per_device = self.__config_rule_composer.get_config_rules(delete=False)
+        LOGGER.debug('config_rules_per_device={:s}'.format(str(config_rules_per_device)))
         results = self._do_configurations(config_rules_per_device, endpoints)
+        LOGGER.debug('results={:s}'.format(str(results)))
         return results
 
     @metered_subclass_method(METRICS_POOL)
@@ -102,12 +121,16 @@ class L3NMGnmiOpenConfigServiceHandler(_ServiceHandler):
     ) -> 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')
-        self._compose_config_rules(endpoints)
-        network_instance_name = service_uuid.split('-')[0]
-        config_rules_per_device = self.__composer.get_config_rules(network_instance_name, delete=True)
+        #service_uuid = self.__service.service_id.service_uuid.uuid
+        connection = self.__task_executor.get_connection(ConnectionId(**json_connection_id(connection_uuid)))
+        connection_endpoint_ids = endpointids_to_raw(connection.path_hops_endpoint_ids)
+        self._compose_config_rules(connection_endpoint_ids)
+        #network_instance_name = service_uuid.split('-')[0]
+        #config_rules_per_device = self.__config_rule_composer.get_config_rules(network_instance_name, delete=True)
+        config_rules_per_device = self.__config_rule_composer.get_config_rules(delete=True)
+        LOGGER.debug('config_rules_per_device={:s}'.format(str(config_rules_per_device)))
         results = self._do_configurations(config_rules_per_device, endpoints, delete=True)
+        LOGGER.debug('results={:s}'.format(str(results)))
         return results
 
     @metered_subclass_method(METRICS_POOL)
diff --git a/src/service/service/service_handlers/l3nm_gnmi_openconfig/StaticRouteGenerator.py b/src/service/service/service_handlers/l3nm_gnmi_openconfig/StaticRouteGenerator.py
new file mode 100644
index 0000000000000000000000000000000000000000..a16e4d5b1c46da600b9dc078ca9f6a74c7eaa187
--- /dev/null
+++ b/src/service/service/service_handlers/l3nm_gnmi_openconfig/StaticRouteGenerator.py
@@ -0,0 +1,197 @@
+# 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, netaddr, sys
+from typing import List, Optional, Tuple
+from .ConfigRuleComposer import ConfigRuleComposer
+
+LOGGER = logging.getLogger(__name__)
+
+# Used to infer routing networks for adjacent ports when there is no hint in device/endpoint settings
+ROOT_NEIGHBOR_ROUTING_NETWORK = netaddr.IPNetwork('10.254.254.0/16')
+NEIGHBOR_ROUTING_NETWORKS_PREFIX_LEN = 30
+NEIGHBOR_ROUTING_NETWORKS = set(ROOT_NEIGHBOR_ROUTING_NETWORK.subnet(NEIGHBOR_ROUTING_NETWORKS_PREFIX_LEN))
+
+def _generate_neighbor_addresses() -> Tuple[netaddr.IPAddress, netaddr.IPAddress, int]:
+    ip_network = NEIGHBOR_ROUTING_NETWORKS.pop()
+    ip_addresses = list(ip_network.iter_hosts())
+    ip_addresses.append(NEIGHBOR_ROUTING_NETWORKS_PREFIX_LEN)
+    return ip_addresses
+
+def _compute_gateway(ip_network : netaddr.IPNetwork, gateway_host=1) -> netaddr.IPAddress:
+    return netaddr.IPAddress(ip_network.cidr.first + gateway_host)
+
+def _compose_ipv4_network(ipv4_network, ipv4_prefix_len) -> netaddr.IPNetwork:
+    return netaddr.IPNetwork('{:s}/{:d}'.format(str(ipv4_network), int(ipv4_prefix_len)))
+
+class StaticRouteGenerator:
+    def __init__(self, config_rule_composer : ConfigRuleComposer) -> None:
+        self._config_rule_composer = config_rule_composer
+
+    def compose(self, connection_hop_list : List[Tuple[str, str, Optional[str]]]) -> None:
+        link_endpoints = self._compute_link_endpoints(connection_hop_list)
+        LOGGER.debug('link_endpoints = {:s}'.format(str(link_endpoints)))
+
+        self._compute_link_addresses(link_endpoints)
+        LOGGER.debug('config_rule_composer = {:s}'.format(json.dumps(self._config_rule_composer.dump())))
+
+        self._discover_connected_networks(connection_hop_list)
+        LOGGER.debug('config_rule_composer = {:s}'.format(json.dumps(self._config_rule_composer.dump())))
+
+        # Compute and propagate static routes forward (service_endpoint_a => service_endpoint_b)
+        self._compute_static_routes(link_endpoints)
+
+        # Compute and propagate static routes backward (service_endpoint_b => service_endpoint_a)
+        reversed_endpoints = list(reversed(connection_hop_list))
+        reversed_link_endpoints = self._compute_link_endpoints(reversed_endpoints)
+        LOGGER.debug('reversed_link_endpoints = {:s}'.format(str(reversed_link_endpoints)))
+        self._compute_static_routes(reversed_link_endpoints)
+
+        LOGGER.debug('config_rule_composer = {:s}'.format(json.dumps(self._config_rule_composer.dump())))
+
+    def _compute_link_endpoints(
+        self, connection_hop_list : List[Tuple[str, str, Optional[str]]]
+    ) -> List[Tuple[Tuple[str, str, Optional[str]], Tuple[str, str, Optional[str]]]]:
+        num_connection_hops = len(connection_hop_list)
+        if num_connection_hops % 2 != 0: raise Exception('Number of connection hops must be even')
+        if num_connection_hops < 4: raise Exception('Number of connection hops must be >= 4')
+
+        # Skip service endpoints (first and last)
+        it_connection_hops = iter(connection_hop_list[1:-1])
+        return list(zip(it_connection_hops, it_connection_hops))
+
+    def _compute_link_addresses(
+        self, link_endpoints_list : List[Tuple[Tuple[str, str, Optional[str]], Tuple[str, str, Optional[str]]]]
+    ) -> None:
+        for link_endpoints in link_endpoints_list:
+            device_endpoint_a, device_endpoint_b = link_endpoints
+
+            device_uuid_a, endpoint_uuid_a = device_endpoint_a[0:2]
+            endpoint_a = self._config_rule_composer.get_device(device_uuid_a).get_endpoint(endpoint_uuid_a)
+
+            device_uuid_b, endpoint_uuid_b = device_endpoint_b[0:2]
+            endpoint_b = self._config_rule_composer.get_device(device_uuid_b).get_endpoint(endpoint_uuid_b)
+
+            if endpoint_a.ipv4_address is None and endpoint_b.ipv4_address is None:
+                ip_endpoint_a, ip_endpoint_b, prefix_len = _generate_neighbor_addresses()
+                endpoint_a.ipv4_address    = str(ip_endpoint_a)
+                endpoint_a.ipv4_prefix_len = prefix_len
+                endpoint_b.ipv4_address    = str(ip_endpoint_b)
+                endpoint_b.ipv4_prefix_len = prefix_len
+            elif endpoint_a.ipv4_address is not None and endpoint_b.ipv4_address is None:
+                prefix_len = endpoint_a.ipv4_prefix_len
+                ip_network_a = _compose_ipv4_network(endpoint_a.ipv4_address, prefix_len)
+                if prefix_len > 30:
+                    MSG = 'Unsupported prefix_len for {:s}: {:s}'
+                    raise Exception(MSG.format(str(endpoint_a), str(prefix_len)))
+                ip_endpoint_b = _compute_gateway(ip_network_a, gateway_host=1)
+                if ip_endpoint_b == ip_network_a.ip:
+                    ip_endpoint_b = _compute_gateway(ip_network_a, gateway_host=2)
+                endpoint_b.ipv4_address    = str(ip_endpoint_b)
+                endpoint_b.ipv4_prefix_len = prefix_len
+            elif endpoint_a.ipv4_address is None and endpoint_b.ipv4_address is not None:
+                prefix_len = endpoint_b.ipv4_prefix_len
+                ip_network_b = _compose_ipv4_network(endpoint_b.ipv4_address, prefix_len)
+                if prefix_len > 30:
+                    MSG = 'Unsupported prefix_len for {:s}: {:s}'
+                    raise Exception(MSG.format(str(endpoint_b), str(prefix_len)))
+                ip_endpoint_a = _compute_gateway(ip_network_b, gateway_host=1)
+                if ip_endpoint_a == ip_network_b.ip:
+                    ip_endpoint_a = _compute_gateway(ip_network_b, gateway_host=2)
+                endpoint_a.ipv4_address    = str(ip_endpoint_a)
+                endpoint_a.ipv4_prefix_len = prefix_len
+            elif endpoint_a.ipv4_address is not None and endpoint_b.ipv4_address is not None:
+                ip_network_a = _compose_ipv4_network(endpoint_a.ipv4_address, endpoint_a.ipv4_prefix_len)
+                ip_network_b = _compose_ipv4_network(endpoint_b.ipv4_address, endpoint_b.ipv4_prefix_len)
+                if ip_network_a.cidr != ip_network_b.cidr:
+                    MSG = 'Incompatible CIDRs: endpoint_a({:s})=>{:s} endpoint_b({:s})=>{:s}'
+                    raise Exception(MSG.format(str(endpoint_a), str(ip_network_a), str(endpoint_b), str(ip_network_b)))
+                if ip_network_a.ip == ip_network_b.ip:
+                    MSG = 'Duplicated IP: endpoint_a({:s})=>{:s} endpoint_b({:s})=>{:s}'
+                    raise Exception(MSG.format(str(endpoint_a), str(ip_network_a), str(endpoint_b), str(ip_network_b)))
+
+    def _discover_connected_networks(self, connection_hop_list : List[Tuple[str, str, Optional[str]]]) -> None:
+        for connection_hop in connection_hop_list:
+            device_uuid, endpoint_uuid = connection_hop[0:2]
+            device = self._config_rule_composer.get_device(device_uuid)
+            endpoint = device.get_endpoint(endpoint_uuid)
+
+            if endpoint.ipv4_address is None: continue
+            ip_network = _compose_ipv4_network(endpoint.ipv4_address, endpoint.ipv4_prefix_len)
+
+            device.connected.add(str(ip_network.cidr))
+
+    def _compute_static_routes(
+        self, link_endpoints_list : List[Tuple[Tuple[str, str, Optional[str]], Tuple[str, str, Optional[str]]]]
+    ) -> None:
+        for link_endpoints in link_endpoints_list:
+            device_endpoint_a, device_endpoint_b = link_endpoints
+
+            device_uuid_a, endpoint_uuid_a = device_endpoint_a[0:2]
+            device_a   = self._config_rule_composer.get_device(device_uuid_a)
+            endpoint_a = device_a.get_endpoint(endpoint_uuid_a)
+
+            device_uuid_b, endpoint_uuid_b = device_endpoint_b[0:2]
+            device_b   = self._config_rule_composer.get_device(device_uuid_b)
+            endpoint_b = device_b.get_endpoint(endpoint_uuid_b)
+
+            # Compute static routes from networks connected in device_a
+            for ip_network_a in device_a.connected:
+                if ip_network_a in device_b.connected: continue
+                if ip_network_a in device_b.static_routes: continue
+                if ip_network_a in ROOT_NEIGHBOR_ROUTING_NETWORK: continue
+                endpoint_a_ip_network = _compose_ipv4_network(endpoint_a.ipv4_address, endpoint_a.ipv4_prefix_len)
+                next_hop = str(endpoint_a_ip_network.ip)
+                metric = 1
+                device_b.static_routes.setdefault(ip_network_a, dict())[metric] = next_hop
+
+            # Compute static routes from networks connected in device_b
+            for ip_network_b in device_b.connected:
+                if ip_network_b in device_a.connected: continue
+                if ip_network_b in device_a.static_routes: continue
+                if ip_network_b in ROOT_NEIGHBOR_ROUTING_NETWORK: continue
+                endpoint_b_ip_network = _compose_ipv4_network(endpoint_b.ipv4_address, endpoint_b.ipv4_prefix_len)
+                next_hop = str(endpoint_b_ip_network.ip)
+                metric = 1
+                device_a.static_routes.setdefault(ip_network_b, dict())[metric] = next_hop
+
+            # Propagate static routes from networks connected in device_a
+            for ip_network_a, metric_next_hop in device_a.static_routes.items():
+                if ip_network_a in device_b.connected: continue
+                if ip_network_a in ROOT_NEIGHBOR_ROUTING_NETWORK: continue
+                endpoint_a_ip_network = _compose_ipv4_network(endpoint_a.ipv4_address, endpoint_a.ipv4_prefix_len)
+                if ip_network_a in device_b.static_routes:
+                    current_metric = min(device_b.static_routes[ip_network_a].keys())
+                else:
+                    current_metric = int(sys.float_info.max)
+                for metric, next_hop in metric_next_hop.items():
+                    new_metric = metric + 1
+                    if new_metric >= current_metric: continue
+                    next_hop_a = str(endpoint_a_ip_network.ip)
+                    device_b.static_routes.setdefault(ip_network_a, dict())[metric] = next_hop_a
+
+            # Propagate static routes from networks connected in device_b
+            for ip_network_b in device_b.static_routes.keys():
+                if ip_network_b in device_a.connected: continue
+                if ip_network_b in ROOT_NEIGHBOR_ROUTING_NETWORK: continue
+                endpoint_b_ip_network = _compose_ipv4_network(endpoint_b.ipv4_address, endpoint_b.ipv4_prefix_len)
+                if ip_network_b in device_a.static_routes:
+                    current_metric = min(device_a.static_routes[ip_network_b].keys())
+                else:
+                    current_metric = int(sys.float_info.max)
+                for metric, next_hop in metric_next_hop.items():
+                    new_metric = metric + 1
+                    if new_metric >= current_metric: continue
+                    next_hop_b = str(endpoint_b_ip_network.ip)
+                    device_a.static_routes.setdefault(ip_network_b, dict())[metric] = next_hop_b
diff --git a/src/service/service/service_handlers/oc/ConfigRules.py b/src/service/service/service_handlers/oc/ConfigRules.py
deleted file mode 100644
index 44245705ecdb48d33c9152328a352d736cc3dd27..0000000000000000000000000000000000000000
--- a/src/service/service/service_handlers/oc/ConfigRules.py
+++ /dev/null
@@ -1,255 +0,0 @@
-# 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 Dict, List
-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 setup_config_rules(
-    service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str, endpoint_name : str,
-    service_settings : TreeNode, endpoint_settings : TreeNode
-) -> List[Dict]:
-
-    if service_settings  is None: return []
-    if endpoint_settings is None: return []
-
-    json_settings          : Dict = service_settings.value
-    json_endpoint_settings : Dict = endpoint_settings.value
-
-    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                 = json_settings.get('mtu',                 1450 )    # 1512
-    #address_families    = json_settings.get('address_families',    []   )    # ['IPV4']
-    bgp_as              = json_settings.get('bgp_as',              0    )    # 65000
-    bgp_route_target    = json_settings.get('bgp_route_target',    '0:0')    # 65000:333
-
-    #router_id           = json_endpoint_settings.get('router_id',           '0.0.0.0')  # '10.95.0.10'
-    route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0'    )  # '60001:801'
-    sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0        )  # 1
-    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
-    if_subif_name       = '{:s}.{:d}'.format(endpoint_name, vlan_id)
-
-    json_config_rules = [
-        json_config_rule_set(
-            '/network_instance[{:s}]'.format(network_instance_name), {
-                'name': network_instance_name, 'description': network_interface_desc, 'type': 'L3VRF',
-                'route_distinguisher': route_distinguisher,
-                #'router_id': router_id, 'address_families': address_families,
-        }),
-        json_config_rule_set(
-            '/interface[{:s}]'.format(endpoint_name), {
-                'name': endpoint_name, 'description': network_interface_desc, 'mtu': mtu,
-        }),
-        json_config_rule_set(
-            '/interface[{:s}]/subinterface[{:d}]'.format(endpoint_name, sub_interface_index), {
-                'name': endpoint_name, 'index': sub_interface_index,
-                'description': network_subinterface_desc, 'vlan_id': vlan_id,
-                'address_ip': address_ip, 'address_prefix': address_prefix,
-        }),
-        json_config_rule_set(
-            '/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), {
-                'name': network_instance_name, 'id': if_subif_name, 'interface': endpoint_name,
-                'subinterface': sub_interface_index,
-        }),
-        json_config_rule_set(
-            '/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), {
-                'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP', 'as': bgp_as,
-        }),
-        json_config_rule_set(
-            '/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), {
-                'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP',
-                'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
-        }),
-        json_config_rule_set(
-            '/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format(
-                network_instance_name), {
-                'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP',
-                'address_family': 'IPV4', #'default_import_policy': 'REJECT_ROUTE',
-        }),
-        json_config_rule_set(
-            '/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), {
-                'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
-        }),
-        json_config_rule_set(
-            '/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format(
-                network_instance_name, bgp_route_target), {
-                'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
-                'ext_community_member'  : 'route-target:{:s}'.format(bgp_route_target),
-        }),
-        json_config_rule_set(
-            '/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), {
-                'policy_name': '{:s}_import'.format(network_instance_name),
-        }),
-        json_config_rule_set(
-            '/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format(
-                network_instance_name, '3'), {
-                'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3',
-                'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
-                'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
-        }),
-        json_config_rule_set(
-            # pylint: disable=duplicate-string-formatting-argument
-            '/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format(
-                network_instance_name, network_instance_name), {
-                'name': network_instance_name, 'import_policy': '{:s}_import'.format(network_instance_name),
-        }),
-        json_config_rule_set(
-            '/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), {
-                'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
-        }),
-        json_config_rule_set(
-            '/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format(
-                network_instance_name, bgp_route_target), {
-                'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
-                'ext_community_member'  : 'route-target:{:s}'.format(bgp_route_target),
-        }),
-        json_config_rule_set(
-            '/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), {
-                'policy_name': '{:s}_export'.format(network_instance_name),
-        }),
-        json_config_rule_set(
-            '/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format(
-                network_instance_name, '3'), {
-                'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3',
-                'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
-                'match_set_options': 'ANY', 'policy_result': 'ACCEPT_ROUTE',
-        }),
-        json_config_rule_set(
-            # pylint: disable=duplicate-string-formatting-argument
-            '/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format(
-                network_instance_name, network_instance_name), {
-                'name': network_instance_name, 'export_policy': '{:s}_export'.format(network_instance_name),
-        }),
-    ]
-
-    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, endpoint_settings : TreeNode
-) -> List[Dict]:
-
-    if service_settings  is None: return []
-    if endpoint_settings is None: return []
-
-    json_settings          : Dict = service_settings.value
-    json_endpoint_settings : Dict = endpoint_settings.value
-
-    #mtu                 = json_settings.get('mtu',                 1450 )    # 1512
-    #address_families    = json_settings.get('address_families',    []   )    # ['IPV4']
-    #bgp_as              = json_settings.get('bgp_as',              0    )    # 65000
-    bgp_route_target    = json_settings.get('bgp_route_target',    '0:0')    # 65000:333
-
-    #router_id           = json_endpoint_settings.get('router_id',           '0.0.0.0')  # '10.95.0.10'
-    #route_distinguisher = json_endpoint_settings.get('route_distinguisher', '0:0'    )  # '60001:801'
-    sub_interface_index = json_endpoint_settings.get('sub_interface_index', 0        )  # 1
-    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
-
-    if_subif_name             = '{:s}.{:d}'.format(endpoint_name, vlan_id)
-    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)
-
-    json_config_rules = [
-        json_config_rule_delete(
-            '/network_instance[{:s}]/interface[{:s}]'.format(network_instance_name, if_subif_name), {
-                'name': network_instance_name, 'id': if_subif_name,
-        }),
-        json_config_rule_delete(
-            '/interface[{:s}]/subinterface[{:d}]'.format(endpoint_name, sub_interface_index), {
-                'name': endpoint_name, 'index': sub_interface_index,
-        }),
-        json_config_rule_delete(
-            '/interface[{:s}]'.format(endpoint_name), {
-                'name': endpoint_name,
-        }),
-        json_config_rule_delete(
-            '/network_instance[{:s}]/table_connections[DIRECTLY_CONNECTED][BGP][IPV4]'.format(
-                network_instance_name), {
-                'name': network_instance_name, 'src_protocol': 'DIRECTLY_CONNECTED', 'dst_protocol': 'BGP',
-                'address_family': 'IPV4',
-        }),
-        json_config_rule_delete(
-            '/network_instance[{:s}]/table_connections[STATIC][BGP][IPV4]'.format(network_instance_name), {
-                'name': network_instance_name, 'src_protocol': 'STATIC', 'dst_protocol': 'BGP',
-                'address_family': 'IPV4',
-        }),
-        json_config_rule_delete(
-            '/network_instance[{:s}]/protocols[BGP]'.format(network_instance_name), {
-                'name': network_instance_name, 'identifier': 'BGP', 'protocol_name': 'BGP',
-        }),
-        json_config_rule_delete(
-            # pylint: disable=duplicate-string-formatting-argument
-            '/network_instance[{:s}]/inter_instance_policies[{:s}_import]'.format(
-                network_instance_name, network_instance_name), {
-            'name': network_instance_name,
-        }),
-        json_config_rule_delete(
-            '/routing_policy/policy_definition[{:s}_import]/statement[{:s}]'.format(
-                network_instance_name, '3'), {
-                'policy_name': '{:s}_import'.format(network_instance_name), 'statement_name': '3',
-        }),
-        json_config_rule_delete(
-            '/routing_policy/policy_definition[{:s}_import]'.format(network_instance_name), {
-                'policy_name': '{:s}_import'.format(network_instance_name),
-        }),
-        json_config_rule_delete(
-            '/routing_policy/bgp_defined_set[{:s}_rt_import][route-target:{:s}]'.format(
-                network_instance_name, bgp_route_target), {
-                'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
-                'ext_community_member'  : 'route-target:{:s}'.format(bgp_route_target),
-        }),
-        json_config_rule_delete(
-            '/routing_policy/bgp_defined_set[{:s}_rt_import]'.format(network_instance_name), {
-                'ext_community_set_name': '{:s}_rt_import'.format(network_instance_name),
-        }),
-        json_config_rule_delete(
-            # pylint: disable=duplicate-string-formatting-argument
-            '/network_instance[{:s}]/inter_instance_policies[{:s}_export]'.format(
-                network_instance_name, network_instance_name), {
-                'name': network_instance_name,
-        }),
-        json_config_rule_delete(
-            '/routing_policy/policy_definition[{:s}_export]/statement[{:s}]'.format(
-                network_instance_name, '3'), {
-                'policy_name': '{:s}_export'.format(network_instance_name), 'statement_name': '3',
-        }),
-        json_config_rule_delete(
-            '/routing_policy/policy_definition[{:s}_export]'.format(network_instance_name), {
-                'policy_name': '{:s}_export'.format(network_instance_name),
-        }),
-        json_config_rule_delete(
-            '/routing_policy/bgp_defined_set[{:s}_rt_export][route-target:{:s}]'.format(
-                network_instance_name, bgp_route_target), {
-                'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
-                'ext_community_member'  : 'route-target:{:s}'.format(bgp_route_target),
-        }),
-        json_config_rule_delete(
-            '/routing_policy/bgp_defined_set[{:s}_rt_export]'.format(network_instance_name), {
-                'ext_community_set_name': '{:s}_rt_export'.format(network_instance_name),
-        }),
-        json_config_rule_delete(
-            '/network_instance[{:s}]'.format(network_instance_name), {
-                'name': network_instance_name
-        }),
-    ]
-    return json_config_rules
diff --git a/src/service/service/service_handlers/oc/OCServiceHandler.py b/src/service/service/service_handlers/oc/OCServiceHandler.py
index 73ff3b89dea808d7a857cd52d5b4d4e581d218cc..277080d6589d08e9765b16962b2cc5737c2c50af 100644
--- a/src/service/service/service_handlers/oc/OCServiceHandler.py
+++ b/src/service/service/service_handlers/oc/OCServiceHandler.py
@@ -15,15 +15,18 @@
 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.proto.context_pb2 import 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 common.DeviceTypes import DeviceTypeEnum
+from service.service.service_handler_api.Tools import 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
-from .OCTools import convert_endpoints_to_flows, handle_flows_names
+from .OCTools import (
+    convert_endpoints_to_flows, endpoints_to_flows,
+    #handle_flows_names, check_media_channel_existance
+)
 
 LOGGER = logging.getLogger(__name__)
 
@@ -47,70 +50,88 @@ class OCServiceHandler(_ServiceHandler):
         is_opticalband =False
         #service_uuid = self.__service.service_id.service_uuid.uuid
         settings=None
+       
         if self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)):
             is_opticalband=True
             settings = self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid))
         else:
             settings = self.__settings_handler.get('/settings')
        
-       
+        bidir = settings.value.get("bidir")
+        LOGGER.debug(f"Bidir bvalue is: {bidir}")
         # settings = self.__settings_handler.get('/settings')
 
         #flow is the new variable that stores input-output relationship
-        
-        flows = convert_endpoints_to_flows(endpoints)
+        #flows = convert_endpoints_to_flows(endpoints)
+        flows = endpoints_to_flows(endpoints, bidir, is_opticalband)
         #handled_flows=handle_flows_names(flows=flows,task_executor=self.__task_executor)
-       
-        #LOGGER.info("Handled Flows %s",handled_flows)
-        
+
         results = []
+
         #new cycle for setting optical devices
-        for device_uuid in flows.keys():
+        for device_uuid, dev_flows in flows.items():
             try:
-                dev_flows = flows[device_uuid]
                 device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
-               
-              
-                if (settings): 
-                   
+                if settings:
                     self.__task_executor.configure_optical_device(device_obj, settings, dev_flows, is_opticalband)
                 results.append(True)
             except Exception as e: # pylint: disable=broad-except
                 LOGGER.exception('Unable to configure Device({:s})'.format(str(device_uuid)))
                 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]]:
+        is_opticalband =False
+        flows = convert_endpoints_to_flows(endpoints)
+
         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')
+        if self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)):
+            is_opticalband =True
+            settings = self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid))
+        else:
+            settings = self.__settings_handler.get('/settings')  
 
         results = []
-        for endpoint in endpoints:
+        for device_uuid, dev_flows in flows.items():
             try:
-                device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint)
-
+                channel_indexes= []
                 device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
-                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, 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)
 
+                if (device_obj.device_type == DeviceTypeEnum.OPTICAL_TRANSPONDER._value_):
+                    for endpoint in dev_flows:
+                        src , dst = endpoint
+                        src_enpoint_name='0'
+                        dist_enpoint_name='0'
+                        if src !="0":
+                           src_endponit_obj =get_endpoint_matching(device_obj, src)
+                           src_enpoint_name=src_endponit_obj.name
+                        if dst !="0":
+                           dst_endpoint_obj = get_endpoint_matching(device_obj, dst) 
+                           dist_enpoint_name=dst_endpoint_obj.name
+                        channel_indexes.append((src_enpoint_name,dist_enpoint_name))   
+                else:
+                    if not is_opticalband:
+                        if 'flow_id' in settings.value:
+                            channel_indexes.append(settings.value["flow_id"])
+                    elif is_opticalband:
+                        if "ob_id" in settings.value:
+                            channel_indexes.append(settings.value["ob_id"])
+
+                if len(channel_indexes) > 0:
+                    errors = self.__task_executor.deconfigure_optical_device(
+                        device=device_obj, channel_indexes=channel_indexes,
+                        is_opticalband=is_opticalband, dev_flow=dev_flows
+                    )
+                    # if (len(errors)==0):
+                    #     service_id =self.__service.service_id
+                    #     if   not is_opticalband :
+                    #         self.__task_executor.delete_setting(service_id,"/settings","value")
                 results.append(True)
             except Exception as e: # pylint: disable=broad-except
                 LOGGER.exception('Unable to DeleteEndpoint({:s})'.format(str(endpoint)))
@@ -157,13 +178,21 @@ class OCServiceHandler(_ServiceHandler):
     def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
         chk_type('resources', resources, list)
         if len(resources) == 0: return []
+        service_id = self.__service.service_id
 
         results = []
         for resource in resources:
             try:
                 self.__settings_handler.delete(resource[0])
+                # self.__task_executor.delete_setting(service_id,"/settings","value")
             except Exception as e: # pylint: disable=broad-except
                 LOGGER.exception('Unable to DeleteConfig({:s})'.format(str(resource)))
                 results.append(e)
 
         return results
+
+    def check_media_channel(self,connection_uuid):
+        if self.__settings_handler.get('/settings-ob_{}'.format(connection_uuid)):
+            return False
+        else:
+            return True
diff --git a/src/service/service/service_handlers/oc/OCTools.py b/src/service/service/service_handlers/oc/OCTools.py
index 7b6c344ede5512f32098fd019076ae57fe87028e..e9097c7e7136303586edc1d7c1dc56d89ad0b3dc 100644
--- a/src/service/service/service_handlers/oc/OCTools.py
+++ b/src/service/service/service_handlers/oc/OCTools.py
@@ -12,11 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching
-from typing import Dict, Any, List, Optional, Tuple
-import logging
-from common.proto.context_pb2 import ConfigRule, DeviceId, Service
+import logging, json
+from typing import Dict, List, Optional, Tuple
+from common.proto.context_pb2 import DeviceId, Service
 from common.tools.object_factory.Device import json_device_id
+from service.service.service_handler_api.Tools import get_endpoint_matching
 
 log = logging.getLogger(__name__)
 
@@ -116,27 +116,227 @@ def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]])
     return entries
 
 
-def get_device_endpint_name (endpoint_uuid:str,device_uuid:str,task_executor)->Tuple:
+def ob_flows(endpoints : List[Tuple[str, str, Optional[str]]], bidir : int):
+    entries = {}
+    end = len(endpoints)
+    i = 0
+    if bidir:
+        endpoint = endpoints[i]
+        device_uuid, endpoint_uuid = endpoint[0:2]
+
+        if device_uuid not in entries.keys():
+            entries[device_uuid] = []
+        entry_tuple = "0", endpoint_uuid
+        entries[device_uuid].append(entry_tuple)
+        next_endpoint = endpoints[i+1]
+        next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+        if next_device_uuid == device_uuid:
+            if next_device_uuid not in entries.keys():
+                entries[next_device_uuid] = []
+            entry_tuple = next_endpoint_uuid, "0"
+            entries[next_device_uuid].append(entry_tuple)
+        else:
+            log.info("error expected device_id {}, found {}".format(device_uuid, next_device_uuid))
+            return {} 
+        i = i + 2
+        if end > 4:
+        
+            while(i < end-2):
+                #i
+                endpoint = endpoints[i]
+                device_uuid, endpoint_uuid = endpoint[0:2]
+                log.debug("current OCTools step {}, {}, {}".format(i, device_uuid, endpoint_uuid))
+                if device_uuid not in entries.keys():
+                    entries[device_uuid] = []
+                #i+1
+                next_endpoint = endpoints[i+1]
+                next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+                if next_device_uuid == device_uuid:
+                    entry_tuple = endpoint_uuid, next_endpoint_uuid
+                    entries[device_uuid].append(entry_tuple)
+                else:
+                    log.debug("ERROR in bidirectional ob")
+                    log.debug("{}, {}, {}".format(i, next_device_uuid, device_uuid))
+                    return {} 
+                #i+2
+                next_2_endpoint = endpoints[i+2]
+                next_2_device_uuid, next_2_endpoint_uuid = next_2_endpoint[0:2]                    
+                #i+3
+                next_3_endpoint = endpoints[i+3]
+                next_3_device_uuid, next_3_endpoint_uuid = next_3_endpoint[0:2]
+                if next_2_device_uuid == next_3_device_uuid and next_3_device_uuid == device_uuid:
+                    entry_tuple = next_2_endpoint_uuid, next_3_endpoint_uuid
+                    entries[device_uuid].append(entry_tuple)
+                    i = i + 4
+                else:
+                    log.debug("ERROR in bidirection ob")
+                    return {}            
+        endpoint = endpoints[i]
+        device_uuid, endpoint_uuid = endpoint[0:2]
+        if device_uuid not in entries.keys():
+            entries[device_uuid] = []
+        entry_tuple = endpoint_uuid, "0", 
+        entries[device_uuid].append(entry_tuple)
+        next_endpoint = endpoints[i+1]
+        next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+        if next_device_uuid == device_uuid:
+            if next_device_uuid not in entries.keys():
+                entries[next_device_uuid] = []
+            entry_tuple = "0", next_endpoint_uuid
+            entries[next_device_uuid].append(entry_tuple)
+        else:
+            log.debug("error expected device_id {}, found {}".format(device_uuid, next_device_uuid))
+    else:
+        endpoint = endpoints[i]
+        device_uuid, endpoint_uuid = endpoint[0:2]
+
+        if device_uuid not in entries.keys():
+            entries[device_uuid] = []
+        entry_tuple = "0", endpoint_uuid
+        entries[device_uuid].append(entry_tuple)
+        i = i + 1
+        if end > 2:
+
+            while(i < end-1):
+                #i
+                endpoint = endpoints[i]
+                device_uuid, endpoint_uuid = endpoint[0:2]
+
+                if device_uuid not in entries.keys():
+                    entries[device_uuid] = []
+                #i+1
+                next_endpoint = endpoints[i+1]
+                next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+                if next_device_uuid == device_uuid:
+                    entry_tuple = endpoint_uuid, next_endpoint_uuid
+                    entries[device_uuid].append(entry_tuple)
+                else:
+                    log.debug("ERROR in bidirectional ob")
+                    log.debug("{}, {}, {}".format(i, next_device_uuid, device_uuid))
+                    return {}
+                i = i + 2 
+        next_endpoint = endpoints[i]
+        next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+        if next_device_uuid not in entries.keys():
+            entries[next_device_uuid] = []
+        entry_tuple = next_endpoint_uuid, "0"
+        entries[next_device_uuid].append(entry_tuple)
+    return entries
+    
+             
+def conn_flows(endpoints : List[Tuple[str, str, Optional[str]]], bidir : int):
+    entries = {}
+    end = len(endpoints)
+    i = 0
+    #tx tp
+    endpoint = endpoints[i]
+    device_uuid, endpoint_uuid = endpoint[0:2]
+
+    if device_uuid not in entries.keys():
+        entries[device_uuid] = []
+    entry_tuple = "0", endpoint_uuid
+    entries[device_uuid].append(entry_tuple)
+    i = i + 1
+    #if bidir reading 4 endpoints per node
+    if bidir:
+        i = i + 1
+        while(i < end-2):
+            #i
+            endpoint = endpoints[i]
+            device_uuid, endpoint_uuid = endpoint[0:2]
+
+            if device_uuid not in entries.keys():
+                entries[device_uuid] = []
+            #i+1
+            next_endpoint = endpoints[i+1]
+            next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+            if next_device_uuid == device_uuid:
+                entry_tuple = endpoint_uuid, next_endpoint_uuid
+                entries[device_uuid].append(entry_tuple)
+            else:
+
+                return {} 
+            #i+2
+            
+            next_2_endpoint = endpoints[i+2]
+            next_2_device_uuid, next_2_endpoint_uuid = next_2_endpoint[0:2]                    
+            #i+3
+            next_3_endpoint = endpoints[i+3]
+            next_3_device_uuid, next_3_endpoint_uuid = next_3_endpoint[0:2]
+            if next_2_device_uuid == next_3_device_uuid and next_3_device_uuid == device_uuid:
+                entry_tuple = next_2_endpoint_uuid, next_3_endpoint_uuid
+                entries[device_uuid].append(entry_tuple)
+                i = i + 4
+            else:
+
+                return {}
+    else:
+        while(i < end-1):
+            #i
+            endpoint = endpoints[i]
+            device_uuid, endpoint_uuid = endpoint[0:2]
+
+            if device_uuid not in entries.keys():
+                entries[device_uuid] = []
+            #i+1
+            next_endpoint = endpoints[i+1]
+            next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+            if next_device_uuid == device_uuid:
+                entry_tuple = endpoint_uuid, next_endpoint_uuid
+                entries[device_uuid].append(entry_tuple)
+                i = i + 2
+            else:
+                return {}
+    #rx tp            
+    endpoint = endpoints[i]
+    device_uuid, endpoint_uuid = endpoint[0:2]
+    if device_uuid not in entries.keys():
+        entries[device_uuid] = []
+    entry_tuple = endpoint_uuid, "0", 
+    entries[device_uuid].append(entry_tuple)
+    return entries
+
+def endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]], bidir : int, is_ob: bool)->Dict:
+    if is_ob:
+        entries = ob_flows(endpoints, bidir)
+    else:
+        entries = conn_flows(endpoints, bidir)
+    return entries
+
+def get_device_endpint_name(endpoint_uuid : str, device_uuid : str, task_executor) -> Tuple:
     device_obj = task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
     endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid)
     endpoint_name = endpoint_obj.name
     return (device_obj.name, endpoint_name)
 
-def handle_flows_names (task_executor,flows:dict)->Dict :
-    new_flows={}
-    for index,( device_uuid_key , device_endpoints_list) in enumerate(flows.items()):
+def handle_flows_names(task_executor, flows : dict) -> Dict:
+    new_flows = {}
+    for index, (device_uuid_key, device_endpoints_list) in enumerate(flows.items()):
         for endpoint_tupple in device_endpoints_list:
-            source_port=None 
-            destination_port=None
-            device_name=""
-            source_endpoint,destination_endpoint =endpoint_tupple
-            if (source_endpoint !='0'):
-                if get_device_endpint_name(source_endpoint,device_uuid_key,task_executor) is not None:
-                   device_name,source_port=get_device_endpint_name(source_endpoint,device_uuid_key,task_executor) 
-            if (destination_endpoint !='0'):
-                if get_device_endpint_name(destination_endpoint,device_uuid_key,task_executor) is not None:   
-                    device_name,destination_port=get_device_endpint_name(destination_endpoint,device_uuid_key,task_executor) 
-            if (device_name  not in new_flows):
-                new_flows[device_name]=[]    
-            new_flows[device_name].append((source_port,destination_port))    
+            source_port = None 
+            destination_port = None
+            device_name = ""
+            source_endpoint, destination_endpoint = endpoint_tupple
+            if source_endpoint != '0':
+                if get_device_endpint_name(source_endpoint, device_uuid_key, task_executor) is not None:
+                    device_name, source_port = get_device_endpint_name(
+                        source_endpoint, device_uuid_key, task_executor
+                    )
+            if destination_endpoint != '0':
+                if get_device_endpint_name(destination_endpoint, device_uuid_key, task_executor) is not None:
+                    device_name, destination_port = get_device_endpint_name(
+                        destination_endpoint, device_uuid_key, task_executor
+                    )
+            if device_name not in new_flows:
+                new_flows[device_name] = []
+            new_flows[device_name].append((source_port, destination_port))
     return new_flows
+
+def check_media_channel_existance(service : Service):
+    has_media_channel = False
+    for config_rule in service.service_config.config_rules:
+        if isinstance(config_rule.custom.resource_value, str):
+           settings = json.dumps(config_rule.custom.resource_value)
+           if "flow_id" in settings:
+               has_media_channel = True
+    return has_media_channel
diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py
index 67f6a516c9bc3031b5cdd2aed80cd6fdd7e1c9c2..ac06e321d342fc7cddb9f54958a38ed87067c922 100644
--- a/src/service/service/task_scheduler/TaskExecutor.py
+++ b/src/service/service/task_scheduler/TaskExecutor.py
@@ -14,13 +14,14 @@
 
 import json, logging
 from enum import Enum
-from typing import TYPE_CHECKING, Any, Dict, Optional, Union
+from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union
+from common.DeviceTypes import DeviceTypeEnum
 from common.method_wrappers.ServiceExceptions import NotFoundException
 from typing import List
 from common.proto.qkd_app_pb2 import QKDAppStatusEnum
 from common.proto.context_pb2 import (
     Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId,
-    OpticalConfig, OpticalConfigId
+    OpticalConfig, OpticalConfigId, ConnectionList, ServiceConfigRule
 )
 from common.proto.qkd_app_pb2 import App, AppId
 from common.proto.context_pb2 import ContextId
@@ -37,6 +38,7 @@ from service.service.service_handler_api.Exceptions import (
 )
 from service.service.service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory, get_service_handler_class
 from service.service.tools.ObjectKeys import get_connection_key, get_device_key, get_service_key, get_qkd_app_key
+from service.service.tools.object_uuid import opticalconfig_get_uuid
 
 if TYPE_CHECKING:
     from service.service.service_handler_api._ServiceHandler import _ServiceHandler
@@ -125,17 +127,27 @@ class TaskExecutor:
         self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device)
     
     # New function Andrea for Optical Devices
-    def configure_optical_device(self, device : Device, settings : str, flows : list, is_opticalband : bool):
+    def configure_optical_device(
+        self, device : Device, settings : str, flows : list, is_opticalband : bool
+    ):
         device_key = get_device_key(device.device_id)
         optical_config_id = OpticalConfigId()
-        optical_config_id.opticalconfig_uuid = device.device_id.device_uuid.uuid
+        optical_config_id.opticalconfig_uuid = opticalconfig_get_uuid(device.device_id)
+
         optical_config = OpticalConfig()
-        setting = settings.value if settings else ''
+
+        setting = settings.value if settings else ""
+        config_type = None
 
         try:
             result = self._context_client.SelectOpticalConfig(optical_config_id)
-            if result is not None:
-                new_config = json.loads(result.config)
+
+            new_config = json.loads(result.config)
+            if 'type' in new_config:
+                config_type=new_config['type']
+            if config_type == 'optical-transponder':
+                setting['status']='ENABLED'    
+            if result is not None :
                 new_config["new_config"] = setting
                 new_config["is_opticalband"] = is_opticalband
                 new_config["flow"] = flows
@@ -144,7 +156,86 @@ class TaskExecutor:
                 self._device_client.ConfigureOpticalDevice(optical_config)
             self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device)
         except Exception as e:
-            LOGGER.info("error in config my config %s",e)
+            LOGGER.info("error in configure_optical_device  %s",e)
+
+    # Deconfiguring Optical Devices ( CNIT )   
+    def deconfigure_optical_device(
+        self, device : Device, channel_indexes : list, is_opticalband : bool, dev_flow : list
+    ):
+        errors = []
+        flows = []
+        indexes = {}
+        new_config = {}
+        optical_config_id = OpticalConfigId()
+        optical_config_id.opticalconfig_uuid = opticalconfig_get_uuid(device.device_id)
+        # if transponder the channel index is same as its endpoint
+        if device.device_type == DeviceTypeEnum.OPTICAL_TRANSPONDER._value_:
+            for index in channel_indexes :
+                flows.append(index)
+        # if Roadm the channel index is the flow_id  ,or ob_id       
+        else:
+            for index in channel_indexes:
+                if not is_opticalband:
+                    indexes["flow_id"] = index  
+                else:
+                    indexes["ob_id"] = index
+
+        try:
+            result = self._context_client.SelectOpticalConfig(optical_config_id)
+            # for extractor in device service to extract the index , dummy data for freq and band required
+            indexes["frequency"] = None
+            indexes["band"] = None
+            if result is not None:
+                new_config = json.loads(result.config)
+                new_config["new_config"]=indexes
+                new_config["flow"] = flows if len(flows)>0 else dev_flow
+                new_config["is_opticalband"] = is_opticalband
+                result.config = json.dumps(new_config)
+                # new_optical_config.config= json.dumps(new_config)
+                # new_optical_config.opticalconfig_id.CopyFrom (optical_config_id)
+                # new_optical_config.device_id.CopyFrom(device.device_id)
+                self._device_client.DisableOpticalDevice(result)
+        except Exception as e:
+            errors.append(e)
+            LOGGER.info("error in deconfigure_optical_device  %s",e)   
+        return errors    
+
+    def delete_setting(
+        self, service_id : ServiceId, config_key : str, config_value : str
+    ):
+        service_configRule = ServiceConfigRule()
+        service_configRule.service_id.CopyFrom( service_id)
+        service_configRule.configrule_custom.resource_key = config_key
+        service_configRule.configrule_custom.resource_value = config_value
+        try:
+            ctxt = ContextClient()
+            ctxt.connect()
+            ctxt.DeleteServiceConfigRule(service_configRule)
+            ctxt.close()
+        except Exception as e :
+            LOGGER.info("error in delete service config rule  %s",e)   
+
+    def check_service_for_media_channel(self, connections : ConnectionList, item) -> bool:
+        service = item
+        if (isinstance(item, ServiceId)):
+            service = self.get_service(item)
+        class_service_handler = None
+        service_handler_settings = {}
+        for connection in connections.connections:
+            connection_uuid=connection.connection_id.connection_uuid
+            if class_service_handler is None:
+                class_service_handler = self.get_service_handler(connection, service,**service_handler_settings)
+            if class_service_handler.check_media_channel(connection_uuid):
+                return True
+        return False
+
+    def check_connection_for_media_channel(
+        self, connection : Connection, service : Service
+    ) -> bool:
+        service_handler_settings = {}
+        connection_uuid = connection.connection_id.connection_uuid
+        service_handler_class = self.get_service_handler(connection, service, **service_handler_settings)
+        return service_handler_class.check_media_channel(connection_uuid)
 
     def get_device_controller(self, device : Device) -> Optional[Device]:
         #json_controller = None
@@ -166,8 +257,8 @@ class TaskExecutor:
 
     def get_devices_from_connection(
         self, connection : Connection, exclude_managed_by_controller : bool = False
-    ) -> Dict[str, Device]:
-        devices = dict()
+    ) -> Dict[DeviceTypeEnum, Dict[str, Device]]:
+        devices : Dict[DeviceTypeEnum, Dict[str, Device]] = dict()
         for endpoint_id in connection.path_hops_endpoint_ids:
             device = self.get_device(endpoint_id.device_id)
             device_uuid = endpoint_id.device_id.device_uuid.uuid
@@ -175,11 +266,14 @@ class TaskExecutor:
 
             controller = self.get_device_controller(device)
             if controller is None:
-                devices[device_uuid] = device
+                device_type = DeviceTypeEnum._value2member_map_[device.device_type]
+                devices.setdefault(device_type, dict())[device_uuid] = device
             else:
                 if not exclude_managed_by_controller:
-                    devices[device_uuid] = device
-                devices[controller.device_id.device_uuid.uuid] = controller
+                    device_type = DeviceTypeEnum._value2member_map_[device.device_type]
+                    devices.setdefault(device_type, dict())[device_uuid] = device
+                device_type = DeviceTypeEnum._value2member_map_[controller.device_type]
+                devices.setdefault(device_type, dict())[controller.device_id.device_uuid.uuid] = controller
         return devices
 
     # ----- Service-related methods ------------------------------------------------------------------------------------
@@ -206,28 +300,36 @@ class TaskExecutor:
 
     # ----- Service Handler Factory ------------------------------------------------------------------------------------
 
-    def get_service_handler(
+    def get_service_handlers(
         self, connection : Connection, service : Service, **service_handler_settings
-    ) -> '_ServiceHandler':
-        connection_devices = self.get_devices_from_connection(connection, exclude_managed_by_controller=True)
-        try:
-            service_handler_class = get_service_handler_class(
-                self._service_handler_factory, service, connection_devices)
-            return service_handler_class(service, self, **service_handler_settings)
-        except (UnsatisfiedFilterException, UnsupportedFilterFieldException, UnsupportedFilterFieldValueException):
-            dict_connection_devices = {
-                cd_data.name : (cd_uuid, cd_data.name, {
-                    (device_driver, DeviceDriverEnum.Name(device_driver))
-                    for device_driver in cd_data.device_drivers
-                })
-                for cd_uuid,cd_data in connection_devices.items()
-            }
-            LOGGER.exception(
-                'Unable to select service handler. service={:s} connection={:s} connection_devices={:s}'.format(
+    ) -> Dict[DeviceTypeEnum, Tuple['_ServiceHandler', Dict[str, Device]]]:
+        connection_device_types : Dict[DeviceTypeEnum, Dict[str, Device]] = self.get_devices_from_connection(
+            connection, exclude_managed_by_controller=True
+        )
+        service_handlers : Dict[DeviceTypeEnum, Tuple['_ServiceHandler', Dict[str, Device]]] = dict()
+        for device_type, connection_devices in connection_device_types.items():
+            try:
+                service_handler_class = get_service_handler_class(
+                    self._service_handler_factory, service, connection_devices)
+                service_handler = service_handler_class(service, self, **service_handler_settings)
+                service_handlers[device_type] = (service_handler, connection_devices)
+            except (
+                UnsatisfiedFilterException, UnsupportedFilterFieldException,
+                UnsupportedFilterFieldValueException
+            ):
+                dict_connection_devices = {
+                    cd_data.name : (cd_uuid, cd_data.name, {
+                        (device_driver, DeviceDriverEnum.Name(device_driver))
+                        for device_driver in cd_data.device_drivers
+                    })
+                    for cd_uuid,cd_data in connection_devices.items()
+                }
+                MSG = 'Unable to select service handler. service={:s} connection={:s} connection_devices={:s}'
+                LOGGER.exception(MSG.format(
                     grpc_message_to_json_string(service), grpc_message_to_json_string(connection),
                     str(dict_connection_devices)
-                )
-            )
+                ))
+        return service_handlers
 
 
     # ----- QkdApp-related methods -------------------------------------------------------------------------------------
@@ -284,4 +386,3 @@ class TaskExecutor:
         except Exception as e:
             LOGGER.error(f"Failed to delete QKD app with AppId {app_id}: {str(e)}")
             raise e
-
diff --git a/src/service/service/task_scheduler/TaskScheduler.py b/src/service/service/task_scheduler/TaskScheduler.py
index b492b4581b05cb34bed624efd9be2d4f62da5856..c2d8423156fd145a262108701860aeb17df3e6f9 100644
--- a/src/service/service/task_scheduler/TaskScheduler.py
+++ b/src/service/service/task_scheduler/TaskScheduler.py
@@ -14,17 +14,23 @@
 
 import graphlib, logging, queue, time
 from typing import TYPE_CHECKING, Dict, Tuple
-from common.proto.context_pb2 import Connection, ConnectionId, Service, ServiceId, ServiceStatusEnum
+from common.proto.context_pb2 import (
+    Connection, ConnectionId, Service, ServiceId, ServiceStatusEnum, ConnectionList
+)
 from common.proto.pathcomp_pb2 import PathCompReply
 from common.tools.grpc.Tools import grpc_message_to_json_string
 from context.client.ContextClient import ContextClient
 from service.service.tools.ObjectKeys import get_connection_key, get_service_key
 from .tasks._Task import _Task
 from .tasks.Task_ConnectionConfigure import Task_ConnectionConfigure
+from .tasks.Task_OpticalConnectionDeconfigure import Task_OpticalConnectionDeconfigure
+from .tasks.Task_OpticalServiceDelete import Task_OpticalServiceDelete
 from .tasks.Task_ConnectionDeconfigure import Task_ConnectionDeconfigure
 from .tasks.Task_ServiceDelete import Task_ServiceDelete
 from .tasks.Task_ServiceSetStatus import Task_ServiceSetStatus
 from .TaskExecutor import CacheableObjectType, TaskExecutor
+from .tasks.Task_OpticalServiceConfigDelete import Task_OpticalServiceConfigDelete
+from service.service.tools.OpticalTools import delete_lightpath 
 
 if TYPE_CHECKING:
     from service.service.service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory
@@ -70,6 +76,7 @@ class TasksScheduler:
         return service_planned_key, service_active_key
 
     def _service_remove(self, service_id : ServiceId) -> Tuple[str, str]:
+
         service_removing_key = self._add_task_if_not_exists(Task_ServiceSetStatus(
             self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL))
 
@@ -79,6 +86,21 @@ class TasksScheduler:
         self._dag.add(service_delete_key, service_removing_key)
         return service_removing_key, service_delete_key
 
+    def _optical_service_remove(
+        self, service_id : ServiceId, has_media_channel : bool, has_optical_band = True
+    ) -> Tuple[str, str]:
+        service_removing_key = self._add_task_if_not_exists(Task_ServiceSetStatus(
+            self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_ACTIVE
+        ))
+
+        service_delete_key = self._add_task_if_not_exists(Task_OpticalServiceDelete(
+            self._executor, service_id, has_media_channel, has_optical_band
+        ))
+
+        # deleting a service requires the service is in removing state
+        self._dag.add(service_delete_key, service_removing_key)
+        return service_removing_key, service_delete_key
+
     def _connection_configure(self, connection_id : ConnectionId, service_id : ServiceId) -> str:
         connection_configure_key = self._add_task_if_not_exists(Task_ConnectionConfigure(
             self._executor, connection_id))
@@ -97,20 +119,56 @@ class TasksScheduler:
 
     def _connection_deconfigure(self, connection_id : ConnectionId, service_id : ServiceId) -> str:
         connection_deconfigure_key = self._add_task_if_not_exists(Task_ConnectionDeconfigure(
-            self._executor, connection_id))
+            self._executor, connection_id
+        ))
 
         # the connection deconfiguration depends on its connection's service being in removing state
         service_pending_removal_key = self._add_task_if_not_exists(Task_ServiceSetStatus(
-            self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL))
+            self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL
+        ))
         self._dag.add(connection_deconfigure_key, service_pending_removal_key)
 
         # the connection's service depends on the connection deconfiguration to transition to delete
         service_delete_key = self._add_task_if_not_exists(Task_ServiceDelete(
-            self._executor, service_id))
+            self._executor, service_id
+        ))
         self._dag.add(service_delete_key, connection_deconfigure_key)
 
         return connection_deconfigure_key
 
+    def _optical_connection_deconfigure(
+        self, connection_id : ConnectionId, service_id : ServiceId,
+        has_media_channel : bool, has_optical_band = True
+    ) -> str:
+        connection_deconfigure_key = self._add_task_if_not_exists(Task_OpticalConnectionDeconfigure(
+            self._executor, connection_id, has_media_channel=has_media_channel
+        ))
+
+        # the connection deconfiguration depends on its connection's service being in removing state
+        service_pending_removal_key = self._add_task_if_not_exists(Task_ServiceSetStatus(
+            self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_ACTIVE
+        ))
+        self._dag.add(connection_deconfigure_key, service_pending_removal_key)
+
+        service_delete_key = self._add_task_if_not_exists(Task_OpticalServiceDelete(
+            self._executor, service_id, has_media_channel, has_optical_band
+        ))
+        self._dag.add(service_delete_key, connection_deconfigure_key)
+
+        return connection_deconfigure_key
+    
+    def _optical_service_config_remove(
+        self, connection_id : ConnectionId, service_id : ServiceId
+    ) -> str:
+        service_config_key = self._add_task_if_not_exists(Task_OpticalServiceConfigDelete(
+            self._executor, connection_id, service_id
+        ))
+        service_pending_removal_key = self._add_task_if_not_exists(Task_ServiceSetStatus(
+            self._executor, service_id, ServiceStatusEnum.SERVICESTATUS_ACTIVE
+        ))
+        self._dag.add(service_config_key, service_pending_removal_key)
+        return service_config_key
+
     def compose_from_pathcompreply(self, pathcomp_reply : PathCompReply, is_delete : bool = False) -> None:
         t0 = time.time()
         include_service = self._service_remove if is_delete else self._service_create
@@ -132,6 +190,136 @@ class TasksScheduler:
         t1 = time.time()
         LOGGER.debug('[compose_from_pathcompreply] elapsed_time: {:f} sec'.format(t1-t0))
 
+    def check_service_for_media_channel(
+        self, connections : ConnectionList, item
+    )->Tuple[bool, bool]:
+        service = item
+        has_media_channel = False
+        has_optical_band = False
+        if isinstance(item, ServiceId):
+            service = self._executor.get_service(item)
+        class_service_handler = None
+        service_handler_settings = {}
+        for connection in connections.connections:
+            connection_uuid = connection.connection_id.connection_uuid.uuid
+            if class_service_handler is None:
+                class_service_handler = self._executor.get_service_handler(
+                    connection, service, **service_handler_settings
+                )
+            if class_service_handler.check_media_channel(connection_uuid):
+                has_media_channel = True
+            else :
+                has_optical_band = True
+        return (has_media_channel, has_optical_band)
+
+    def compose_from_optical_service(
+        self, service : Service, params : dict, is_delete : bool = False
+    ) -> None:
+        t0 = time.time()
+        include_service = self._optical_service_remove if is_delete else self._service_create
+        include_connection = self._optical_connection_deconfigure if is_delete else self._connection_configure
+        include_service_config = self._optical_service_config_remove if is_delete else None
+
+        explored_items = set()
+        pending_items_to_explore = queue.Queue()
+        pending_items_to_explore.put(service)
+        has_media_channel = None
+        has_optical_band = None
+        reply = None
+        code = 0
+        reply_not_allowed = "DELETE_NOT_ALLOWED"
+        while not pending_items_to_explore.empty():
+            try:
+                item = pending_items_to_explore.get(block=False)
+            except queue.Empty:
+                break
+
+            if isinstance(item, Service):
+                str_item_key = grpc_message_to_json_string(item.service_id)
+                if str_item_key in explored_items: continue
+                connections = self._context_client.ListConnections(item.service_id)
+                has_media_channel, has_optical_band = self.check_service_for_media_channel(
+                    connections=connections, item=item.service_id
+                )
+
+                if len(service.service_config.config_rules) > 0:
+                    reply, code = delete_lightpath(
+                        params['src'], params ['dst'], params['bitrate'], params['ob_id'],
+                        delete_band=not has_media_channel, flow_id= params['flow_id']
+                    )
+
+                if code == 400 and reply_not_allowed in reply:
+                   MSG = 'Deleteion for the service is not Allowed , Served Lightpaths is not empty'
+                   raise Exception(MSG)
+
+                include_service(
+                    item.service_id, has_media_channel=has_media_channel, has_optical_band=has_optical_band
+                )
+                self._add_service_to_executor_cache(item)
+
+                for connection in connections.connections:
+                    self._add_connection_to_executor_cache(connection)
+                    pending_items_to_explore.put(connection)
+                explored_items.add(str_item_key)
+
+            elif isinstance(item, ServiceId):
+                if code == 400 and reply_not_allowed in reply: break
+                str_item_key = grpc_message_to_json_string(item)
+                if str_item_key in explored_items: continue
+                connections = self._context_client.ListConnections(item)
+                has_media_channel, has_optical_band = self.check_service_for_media_channel(
+                    connections=connections, item=item
+                )
+                include_service(
+                    item, has_media_channel=has_media_channel, has_optical_band=has_optical_band
+                )
+                self._executor.get_service(item)
+
+                for connection in connections.connections:
+                    self._add_connection_to_executor_cache(connection)
+                    pending_items_to_explore.put(connection)
+                explored_items.add(str_item_key)
+
+            elif isinstance(item, Connection):
+                if code == 400 and reply_not_allowed in reply:break
+                str_item_key = grpc_message_to_json_string(item.connection_id)
+                if str_item_key in explored_items: continue
+                connection_key = include_connection(
+                    item.connection_id, item.service_id, has_media_channel=has_media_channel,
+                    has_optical_band=has_optical_band
+                ) 
+                self._add_connection_to_executor_cache(connection)
+
+                if include_service_config is not None : 
+                    connections_list = ConnectionList()  
+                    connections_list.connections.append(item)
+                    is_media_channel, _ = self.check_service_for_media_channel(
+                        connections=connections_list, item=service
+                    )
+                    if has_optical_band and is_media_channel:
+                        include_service_config(
+                            item.connection_id, item.service_id
+                        )
+                self._executor.get_service(item.service_id)
+                pending_items_to_explore.put(item.service_id)
+
+                for sub_service_id in item.sub_service_ids:
+                    _,service_key_done = include_service(
+                        sub_service_id, has_media_channel=has_media_channel,
+                        has_optical_band=has_optical_band
+                    )
+                    self._executor.get_service(sub_service_id)
+                    self._dag.add(service_key_done, connection_key)
+                    pending_items_to_explore.put(sub_service_id)
+
+                explored_items.add(str_item_key)
+            else:
+                MSG = 'Unsupported item {:s}({:s})'
+                raise Exception(MSG.format(type(item).__name__, grpc_message_to_json_string(item)))
+
+        t1 = time.time()
+        LOGGER.debug('[compose_from_service] elapsed_time: {:f} sec'.format(t1-t0))
+
     def compose_from_service(self, service : Service, is_delete : bool = False) -> None:
         t0 = time.time()
         include_service = self._service_remove if is_delete else self._service_create
@@ -157,7 +345,6 @@ class TasksScheduler:
                 for connection in connections.connections:
                     self._add_connection_to_executor_cache(connection)
                     pending_items_to_explore.put(connection)
-
                 explored_items.add(str_item_key)
 
             elif isinstance(item, ServiceId):
@@ -170,7 +357,6 @@ class TasksScheduler:
                 for connection in connections.connections:
                     self._add_connection_to_executor_cache(connection)
                     pending_items_to_explore.put(connection)
-
                 explored_items.add(str_item_key)
 
             elif isinstance(item, Connection):
@@ -179,7 +365,6 @@ class TasksScheduler:
 
                 connection_key = include_connection(item.connection_id, item.service_id)
                 self._add_connection_to_executor_cache(connection)
-
                 self._executor.get_service(item.service_id)
                 pending_items_to_explore.put(item.service_id)
 
@@ -208,16 +393,20 @@ class TasksScheduler:
         self._add_connection_to_executor_cache(new_connection)
 
         service_updating_key = self._add_task_if_not_exists(Task_ServiceSetStatus(
-            self._executor, service.service_id, ServiceStatusEnum.SERVICESTATUS_UPDATING))
+            self._executor, service.service_id, ServiceStatusEnum.SERVICESTATUS_UPDATING
+        ))
 
         old_connection_deconfigure_key = self._add_task_if_not_exists(Task_ConnectionDeconfigure(
-            self._executor, old_connection.connection_id))
+            self._executor, old_connection.connection_id
+        ))
 
         new_connection_configure_key = self._add_task_if_not_exists(Task_ConnectionConfigure(
-            self._executor, new_connection.connection_id))
+            self._executor, new_connection.connection_id
+        ))
 
         service_active_key = self._add_task_if_not_exists(Task_ServiceSetStatus(
-            self._executor, service.service_id, ServiceStatusEnum.SERVICESTATUS_ACTIVE))
+            self._executor, service.service_id, ServiceStatusEnum.SERVICESTATUS_ACTIVE
+        ))
 
         # the old connection deconfiguration depends on service being in updating state
         self._dag.add(old_connection_deconfigure_key, service_updating_key)
@@ -239,7 +428,7 @@ class TasksScheduler:
 
     def execute_all(self, dry_run : bool = False) -> None:
         ordered_task_keys = list(self._dag.static_order())
-        LOGGER.debug('[execute_all] ordered_task_keys={:s}'.format(str(ordered_task_keys)))
+        LOGGER.info('[execute_all] ordered_task_keys={:s}'.format(str(ordered_task_keys)))
 
         results = []
         for task_key in ordered_task_keys:
diff --git a/src/service/service/task_scheduler/tasks/Task_ConnectionConfigure.py b/src/service/service/task_scheduler/tasks/Task_ConnectionConfigure.py
index f6c543c1ccb947eb01c3d5f5fb93c0504a77ca95..3f52f337ae163a6e8c78d873a58a291ecff4bd1a 100644
--- a/src/service/service/task_scheduler/tasks/Task_ConnectionConfigure.py
+++ b/src/service/service/task_scheduler/tasks/Task_ConnectionConfigure.py
@@ -12,8 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from typing import TYPE_CHECKING, Dict, Tuple
+from common.DeviceTypes import DeviceTypeEnum
 from common.method_wrappers.ServiceExceptions import OperationFailedException
-from common.proto.context_pb2 import ConnectionId
+from common.proto.context_pb2 import ConnectionId, Device
 from common.tools.grpc.Tools import grpc_message_to_json_string
 from service.service.service_handler_api.Tools import check_errors_setendpoint
 from service.service.task_scheduler.TaskExecutor import TaskExecutor
@@ -21,6 +23,9 @@ from service.service.tools.EndpointIdFormatters import endpointids_to_raw
 from service.service.tools.ObjectKeys import get_connection_key
 from ._Task import _Task
 
+if TYPE_CHECKING:
+    from service.service.service_handler_api._ServiceHandler import _ServiceHandler
+
 KEY_TEMPLATE = 'connection({connection_id:s}):configure'
 
 class Task_ConnectionConfigure(_Task):
@@ -44,12 +49,24 @@ class Task_ConnectionConfigure(_Task):
         service = self._task_executor.get_service(connection.service_id)
 
         service_handler_settings = {}
-        service_handler = self._task_executor.get_service_handler(connection, service, **service_handler_settings)
+        service_handlers : Dict[DeviceTypeEnum, Tuple['_ServiceHandler', Dict[str, Device]]] = \
+            self._task_executor.get_service_handlers(connection, service, **service_handler_settings)
 
-        endpointids_to_set = endpointids_to_raw(connection.path_hops_endpoint_ids)
         connection_uuid = connection.connection_id.connection_uuid.uuid
-        results_setendpoint = service_handler.SetEndpoint(endpointids_to_set, connection_uuid=connection_uuid)
-        errors = check_errors_setendpoint(endpointids_to_set, results_setendpoint)
+        endpointids_to_set = endpointids_to_raw(connection.path_hops_endpoint_ids)
+
+        errors = list()
+        for _, (service_handler, connection_devices) in service_handlers.items():
+            _endpointids_to_set = [
+                (device_uuid, endpoint_uuid, topology_uuid)
+                for device_uuid, endpoint_uuid, topology_uuid in endpointids_to_set
+                if device_uuid in connection_devices
+            ]
+            results_setendpoint = service_handler.SetEndpoint(
+                _endpointids_to_set, connection_uuid=connection_uuid
+            )
+            errors.extend(check_errors_setendpoint(endpointids_to_set, results_setendpoint))
+
         if len(errors) > 0:
             MSG = 'SetEndpoint for Connection({:s}) from Service({:s})'
             str_connection = grpc_message_to_json_string(connection)
diff --git a/src/service/service/task_scheduler/tasks/Task_ConnectionDeconfigure.py b/src/service/service/task_scheduler/tasks/Task_ConnectionDeconfigure.py
index 7b6b7951befbd6abd4d052ce5eec39d3398aa6e7..4ce774d208d3ea71e55482ea0653521cb7f1083a 100644
--- a/src/service/service/task_scheduler/tasks/Task_ConnectionDeconfigure.py
+++ b/src/service/service/task_scheduler/tasks/Task_ConnectionDeconfigure.py
@@ -12,8 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from typing import TYPE_CHECKING, Dict, Tuple
+from common.DeviceTypes import DeviceTypeEnum
 from common.method_wrappers.ServiceExceptions import OperationFailedException
-from common.proto.context_pb2 import ConnectionId
+from common.proto.context_pb2 import ConnectionId, Device
 from common.tools.grpc.Tools import grpc_message_to_json_string
 from service.service.service_handler_api.Tools import check_errors_deleteendpoint
 from service.service.task_scheduler.TaskExecutor import TaskExecutor
@@ -21,6 +23,9 @@ from service.service.tools.EndpointIdFormatters import endpointids_to_raw
 from service.service.tools.ObjectKeys import get_connection_key
 from ._Task import _Task
 
+if TYPE_CHECKING:
+    from service.service.service_handler_api._ServiceHandler import _ServiceHandler
+
 KEY_TEMPLATE = 'connection({connection_id:s}):deconfigure'
 
 class Task_ConnectionDeconfigure(_Task):
@@ -44,12 +49,24 @@ class Task_ConnectionDeconfigure(_Task):
         service = self._task_executor.get_service(connection.service_id)
 
         service_handler_settings = {}
-        service_handler = self._task_executor.get_service_handler(connection, service, **service_handler_settings)
+        service_handlers : Dict[DeviceTypeEnum, Tuple['_ServiceHandler', Dict[str, Device]]] = \
+            self._task_executor.get_service_handlers(connection, service, **service_handler_settings)
 
-        endpointids_to_delete = endpointids_to_raw(connection.path_hops_endpoint_ids)
         connection_uuid = connection.connection_id.connection_uuid.uuid
-        results_deleteendpoint = service_handler.DeleteEndpoint(endpointids_to_delete, connection_uuid=connection_uuid)
-        errors = check_errors_deleteendpoint(endpointids_to_delete, results_deleteendpoint)
+        endpointids_to_delete = endpointids_to_raw(connection.path_hops_endpoint_ids)
+
+        errors = list()
+        for _, (service_handler, connection_devices) in service_handlers.items():
+            _endpointids_to_delete = [
+                (device_uuid, endpoint_uuid, topology_uuid)
+                for device_uuid, endpoint_uuid, topology_uuid in endpointids_to_delete
+                if device_uuid in connection_devices
+            ]
+            results_deleteendpoint = service_handler.DeleteEndpoint(
+                _endpointids_to_delete, connection_uuid=connection_uuid
+            )
+            errors.extend(check_errors_deleteendpoint(endpointids_to_delete, results_deleteendpoint))
+
         if len(errors) > 0:
             MSG = 'DeleteEndpoint for Connection({:s}) from Service({:s})'
             str_connection = grpc_message_to_json_string(connection)
diff --git a/src/service/service/task_scheduler/tasks/Task_OpticalConnectionDeconfigure.py b/src/service/service/task_scheduler/tasks/Task_OpticalConnectionDeconfigure.py
new file mode 100644
index 0000000000000000000000000000000000000000..b1afdeef19d6526d6f52b05924b5b77a8049da8f
--- /dev/null
+++ b/src/service/service/task_scheduler/tasks/Task_OpticalConnectionDeconfigure.py
@@ -0,0 +1,75 @@
+# 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 common.method_wrappers.ServiceExceptions import OperationFailedException
+from common.proto.context_pb2 import ConnectionId
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from service.service.service_handler_api.Tools import check_errors_deleteendpoint
+from service.service.task_scheduler.TaskExecutor import TaskExecutor
+from service.service.tools.EndpointIdFormatters import endpointids_to_raw
+from service.service.tools.ObjectKeys import get_connection_key
+from ._Task import _Task
+
+KEY_TEMPLATE = 'optical_connection({connection_id:s}):deconfigure'
+
+class Task_OpticalConnectionDeconfigure(_Task):
+    def __init__(
+        self, task_executor : TaskExecutor, connection_id : ConnectionId,
+        has_media_channel : bool
+    ) -> None:
+        super().__init__(task_executor)
+        self._connection_id = connection_id
+        self._has_media_channel = has_media_channel
+
+    @property
+    def connection_id(self) -> ConnectionId: return self._connection_id
+
+    @staticmethod
+    def build_key(connection_id : ConnectionId) -> str: # pylint: disable=arguments-differ
+        str_connection_id = get_connection_key(connection_id)
+        return KEY_TEMPLATE.format(connection_id=str_connection_id)
+
+    @property
+    def key(self) -> str: return self.build_key(self._connection_id)
+
+    def execute(self) -> None:
+        connection = self._task_executor.get_connection(self._connection_id)
+        service = self._task_executor.get_service(connection.service_id)
+        errors = []
+        service_handler_settings = {}
+        service_handler = self._task_executor.get_service_handler(connection, service, **service_handler_settings)
+
+        endpointids_to_delete = endpointids_to_raw(connection.path_hops_endpoint_ids)
+        connection_uuid = connection.connection_id.connection_uuid.uuid
+        if self._has_media_channel:
+            is_media_channel = service_handler.check_media_channel(connection_uuid)
+            if is_media_channel:
+                results_deleteendpoint = service_handler.DeleteEndpoint(endpointids_to_delete, connection_uuid=connection_uuid)
+                errors = check_errors_deleteendpoint(endpointids_to_delete, results_deleteendpoint)
+            if len(errors) > 0:
+                MSG = 'DeleteEndpoint for OpticalConnection({:s}) from Service({:s})'
+                str_connection = grpc_message_to_json_string(connection)
+                str_service = grpc_message_to_json_string(service)
+                raise OperationFailedException(MSG.format(str_connection, str_service), extra_details=errors)
+            if is_media_channel:
+                self._task_executor.delete_connection(self._connection_id)
+        else:
+            results_deleteendpoint = service_handler.DeleteEndpoint(endpointids_to_delete, connection_uuid=connection_uuid)
+            errors = check_errors_deleteendpoint(endpointids_to_delete, results_deleteendpoint)
+            if len(errors) > 0:
+                MSG = 'DeleteEndpoint for OpticalConnection({:s}) from Service({:s})'
+                str_connection = grpc_message_to_json_string(connection)
+                str_service = grpc_message_to_json_string(service)
+                raise OperationFailedException(MSG.format(str_connection, str_service), extra_details=errors)
+            self._task_executor.delete_connection(self._connection_id)
diff --git a/src/service/service/task_scheduler/tasks/Task_OpticalServiceConfigDelete.py b/src/service/service/task_scheduler/tasks/Task_OpticalServiceConfigDelete.py
new file mode 100644
index 0000000000000000000000000000000000000000..4a21d246e8dfcce4f828553df68169a2bbada160
--- /dev/null
+++ b/src/service/service/task_scheduler/tasks/Task_OpticalServiceConfigDelete.py
@@ -0,0 +1,43 @@
+# 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 common.proto.context_pb2 import ServiceId , ConnectionId
+from service.service.task_scheduler.TaskExecutor import TaskExecutor
+from service.service.tools.ObjectKeys import get_service_key
+from ._Task import _Task
+
+KEY_TEMPLATE = 'optical_service({service_id:s})_Config:delete'
+
+class Task_OpticalServiceConfigDelete(_Task):
+    def __init__(
+        self, task_executor : TaskExecutor, connection_id : ConnectionId,
+        service_id : ServiceId
+    ) -> None:
+        super().__init__(task_executor)
+        self._connection_id = connection_id
+        self._service_id = service_id
+
+    @property
+    def service_id(self) -> ServiceId: return self._service_id
+
+    @staticmethod
+    def build_key(service_id : ServiceId) -> str:   # pylint: disable=arguments-differ
+        str_service_id = get_service_key(service_id)
+        return KEY_TEMPLATE.format(service_id=str_service_id)
+
+    @property
+    def key(self) -> str: return self.build_key(self._service_id)
+
+    def execute(self) -> None:
+        self._task_executor.delete_setting(self._service_id, '/settings', 'value')
diff --git a/src/service/service/task_scheduler/tasks/Task_OpticalServiceDelete.py b/src/service/service/task_scheduler/tasks/Task_OpticalServiceDelete.py
new file mode 100644
index 0000000000000000000000000000000000000000..536d954957ebf1f2d294b9bc435cae7ded7c7531
--- /dev/null
+++ b/src/service/service/task_scheduler/tasks/Task_OpticalServiceDelete.py
@@ -0,0 +1,45 @@
+# 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 common.proto.context_pb2 import ServiceId
+from service.service.task_scheduler.TaskExecutor import TaskExecutor
+from service.service.tools.ObjectKeys import get_service_key
+from ._Task import _Task
+
+KEY_TEMPLATE = 'optical_service({service_id:s}):delete'
+
+class Task_OpticalServiceDelete(_Task):
+    def __init__(
+        self, task_executor : TaskExecutor, service_id : ServiceId,
+        has_media_channel : bool, has_optical_band : bool
+    ) -> None:
+        super().__init__(task_executor)
+        self._service_id = service_id
+        self._has_media_channel = has_media_channel
+        self._has_optical_band = has_optical_band
+
+    @property
+    def service_id(self) -> ServiceId: return self._service_id
+
+    @staticmethod
+    def build_key(service_id : ServiceId) -> str:   # pylint: disable=arguments-differ
+        str_service_id = get_service_key(service_id)
+        return KEY_TEMPLATE.format(service_id=str_service_id)
+
+    @property
+    def key(self) -> str: return self.build_key(self._service_id)
+
+    def execute(self) -> None:
+        if not self._has_media_channel or not self._has_optical_band:
+            self._task_executor.delete_service(self._service_id)
diff --git a/src/service/service/tools/OpticalTools.py b/src/service/service/tools/OpticalTools.py
index ca73dce480a46369b47ce4c6baed516168b24817..f62c60ac9d256e277478f1703ed75e992961a4da 100644
--- a/src/service/service/tools/OpticalTools.py
+++ b/src/service/service/tools/OpticalTools.py
@@ -91,6 +91,7 @@ def get_names_from_uuids(devices: List[Device], device_uuid: str, port_uuid: str
                     return device_name, port_name
     return "", ""
 
+
 def get_device_name_from_uuid(devices: List[Device], device_uuid: str):
     device_name = ""
     
@@ -101,6 +102,17 @@ def get_device_name_from_uuid(devices: List[Device], device_uuid: str):
     return ""
 
 
+def refresh_opticalcontroller(topology_id : dict):
+    topo_id_str = topology_id["topology_uuid"]["uuid"]
+    cxt_id_str = topology_id["context_id"]["context_uuid"]["uuid"]
+    headers = {"Content-Type": "application/json"}
+    base_url = get_optical_controller_base_url()
+    urlx = "{:s}/GetTopology/{:s}/{:s}".format(base_url, cxt_id_str, topo_id_str)
+    res = requests.get(urlx, headers=headers)
+    if res is not None:
+        log.debug(f"DELETELIGHTPATH Response {res}")
+
+
 def add_lightpath(src, dst, bitrate, bidir, ob_band) -> str:
     if not TESTING:
         urlx = ""
@@ -115,6 +127,7 @@ def add_lightpath(src, dst, bitrate, bidir, ob_band) -> str:
                 bidir = 1
             urlx = "{:s}/AddFlexLightpath/{:s}/{:s}/{:s}/{:s}/{:s}".format(base_url, src, dst, str(bitrate), str(bidir), str(ob_band))
         r = requests.put(urlx, headers=headers)
+        print(f"addpathlight {r}")
         reply = r.text 
         return reply
     else:
@@ -139,17 +152,30 @@ def get_optical_band(idx) -> str:
             return optical_band_uni_txt
 
     
-def delete_lightpath(flow_id, src, dst, bitrate) -> str:
+def delete_lightpath( src, dst, bitrate, ob_id, delete_band, flow_id=None) -> str:
     reply = "200"
+    delete_band = 1 if delete_band else 0
+    base_url = get_optical_controller_base_url()
     if not TESTING:
-        base_url = get_optical_controller_base_url()
-        urlx = "{:s}/DelLightpath/{:s}/{:s}/{:s}/{:s}".format(base_url, str(flow_id), src, dst, str(bitrate))
-
+        if flow_id is not None:
+            urlx = "{:s}/DelFlexLightpath/{}/{}/{}/{}/{}".format(base_url, src, dst, bitrate, ob_id, flow_id)
+        else :
+            urlx = "{:s}/DelOpticalBand/{}/{}/{}".format(base_url, src, dst, ob_id)
         headers = {"Content-Type": "application/json"}
         r = requests.delete(urlx, headers=headers)
         reply = r.text 
-    return reply
+        code = r.status_code
+    return (reply, code)
 
+def DelFlexLightpath (flow_id, src, dst, bitrate, o_band_id):
+    reply = "200"
+    base_url = get_optical_controller_base_url()
+    if not TESTING:
+        urlx = "{:s}/DelFlexLightpath/{}/{}/{}/{}/{}".format(base_url, flow_id, src, dst, bitrate, o_band_id)
+        headers = {"Content-Type": "application/json"}
+        r = requests.delete(urlx, headers=headers)
+        reply = r.text
+    return reply
 
 def get_lightpaths() -> str:
     base_url = get_optical_controller_base_url()
@@ -160,14 +186,24 @@ def get_lightpaths() -> str:
     reply = r.text 
     return reply
 
-        
 def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_band_txt) ->  PathCompReply:
     opt_reply = PathCompReply()
-    topo = TopologyId(context_id=ContextId(context_uuid=Uuid(uuid=context_id)),topology_uuid=Uuid(uuid=topology_id))
+    topo = TopologyId(
+        context_id=ContextId(context_uuid=Uuid(uuid=context_id)),
+        topology_uuid=Uuid(uuid=topology_id)
+    )
     #add optical band connection first
     rules_ob= []
     ob_id = 0
     connection_ob=None
+
+    r = reply_json
+    if "parent_opt_band" in r.keys():
+        ob_id = r["parent_opt_band"]
+    if "bidir" in r.keys():
+        bidir_f = r["bidir"]
+    else:
+        bidir_f = False
     if optical_band_txt != "":
         ob_json = json.loads(optical_band_txt)
         ob = ob_json
@@ -187,9 +223,18 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b
           
         freq = ob["freq"]
         bx = ob["band"]
-        lf = int(int(freq)-int(bx/2))
+        #+1 is added to avoid overlap in the WSS of MGONs
+        lf = int(int(freq)-int(bx/2))+1
         uf = int(int(freq)+int(bx/2))
-        val_ob = {"band_type": band_type, "low-freq": lf, "up-freq": uf, "frequency": freq, "band": bx, "ob_id": ob_id}
+        val_ob = {
+            "band_type" : band_type,
+            "low-freq"  : lf,
+            "up-freq"   : uf,
+            "frequency" : freq,
+            "band"      : bx,
+            "ob_id"     : ob_id,
+            "bidir"     : bidir_f
+        }
         rules_ob.append(ConfigRule_Custom(resource_key="/settings-ob_{}".format(uuuid_x), resource_value=json.dumps(val_ob)))
         bidir_ob = ob["bidir"]
         for devxb in ob["flows"].keys():
@@ -234,8 +279,7 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b
                 else:
                     log.info("no map device port for device {} port {}".format(devxb, out_end_point_b))
             log.debug("optical-band connection {}".format(connection_ob))
-    r = reply_json
-    bidir_f = r["bidir"]
+    
     connection_f = add_connection_to_reply(opt_reply)
     connection_f.connection_id.connection_uuid.uuid = str(uuid.uuid4())
     connection_f.service_id.CopyFrom(service.service_id)
@@ -278,12 +322,13 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b
                 end_point = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d)), endpoint_uuid=Uuid(uuid=p))
                 connection_f.path_hops_endpoint_ids.add().CopyFrom(end_point) 
             else:
-                log.info("no map device port for device {} port {}".format(devx, out_end_point_b))      
+                log.info("no map device port for device {} port {}".format(devx, out_end_point_b))
+
     #check that list of endpoints is not empty  
     if connection_ob is not None and  len(connection_ob.path_hops_endpoint_ids) == 0:
         log.debug("deleting empty optical-band connection")
         opt_reply.connections.remove(connection_ob)
-    
+
     #inizialize custom optical parameters
     band = r["band"] if "band" in r else None
     op_mode = r["op-mode"] if "op-mode" in r else None
@@ -298,27 +343,26 @@ def adapt_reply(devices, service, reply_json, context_id, topology_id, optical_b
         band_type = "C_BAND"
         
     if ob_id != 0:
-        val = {"frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "ob_id": ob_id, "band_type": band_type,}
+        val = {"target-output-power": "1.0", "frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "ob_id": ob_id, "band_type": band_type, "bidir": bidir_f}
     else:
-        val = {"frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "band_type": band_type,}
+        val = {"target-output-power": "1.0", "frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "band_type": band_type, "bidir": bidir_f}
     custom_rule = ConfigRule_Custom(resource_key="/settings", resource_value=json.dumps(val))
     rule = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=custom_rule)
     service.service_config.config_rules.add().CopyFrom(rule)
    
     if len(rules_ob) > 0:
-      for rulex in rules_ob:
-        rule_ob = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=rulex)
-        service.service_config.config_rules.add().CopyFrom(rule_ob)
-      
+        for rulex in rules_ob:
+            rule_ob = ConfigRule(action=ConfigActionEnum.CONFIGACTION_SET, custom=rulex)
+            service.service_config.config_rules.add().CopyFrom(rule_ob)
+
     opt_reply.services.add().CopyFrom(service)   
-    
-    return opt_reply         
+    return opt_reply
 
-def add_service_to_reply(reply : PathCompReply, service : Service)-> Service:
+def add_service_to_reply(reply : PathCompReply, service : Service) -> Service:
     service_x = reply.services.add()
     service_x.CopyFrom(service)
     return service_x
- 
-def add_connection_to_reply(reply : PathCompReply)-> Connection:
+
+def add_connection_to_reply(reply : PathCompReply) -> Connection:
     conn = reply.connections.add()
     return conn
diff --git a/src/service/service/tools/object_uuid.py b/src/service/service/tools/object_uuid.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbcbc71b9b9d4edeb31858e3c22cd0af508210b9
--- /dev/null
+++ b/src/service/service/tools/object_uuid.py
@@ -0,0 +1,53 @@
+# 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 common.method_wrappers.ServiceExceptions import InvalidArgumentsException
+from typing import Optional, Union
+from uuid import UUID, uuid5
+from common.proto.context_pb2 import DeviceId
+
+# Generate a UUIDv5-like from the SHA-1 of "TFS" and no namespace to be used as the NAMESPACE for all
+# the context UUIDs generated. For efficiency purposes, the UUID is hardcoded; however, it is produced
+# using the following code:
+#    from hashlib import sha1
+#    from uuid import UUID
+#    hash = sha1(bytes('TFS', 'utf-8')).digest()
+#    NAMESPACE_TFS = UUID(bytes=hash[:16], version=5)
+NAMESPACE_TFS = UUID('200e3a1f-2223-534f-a100-758e29c37f40')
+
+def get_uuid_from_string(str_uuid_or_name : Union[str, UUID], prefix_for_name : Optional[str] = None) -> str:
+    # if UUID given, assume it is already a valid UUID
+    if isinstance(str_uuid_or_name, UUID): return str_uuid_or_name
+    if not isinstance(str_uuid_or_name, str):
+        MSG = 'Parameter({:s}) cannot be used to produce a UUID'
+        raise Exception(MSG.format(str(repr(str_uuid_or_name))))
+    try:
+        # try to parse as UUID
+        return str(UUID(str_uuid_or_name))
+    except: # pylint: disable=bare-except
+        # produce a UUID within TFS namespace from parameter
+        if prefix_for_name is not None:
+            str_uuid_or_name = '{:s}/{:s}'.format(prefix_for_name, str_uuid_or_name)
+        return str(uuid5(NAMESPACE_TFS, str_uuid_or_name))
+
+def opticalconfig_get_uuid(device_id: DeviceId) -> str: 
+    device_uuid = device_id.device_uuid.uuid
+    if len(device_uuid) > 0:
+        return get_uuid_from_string(f"{device_uuid}_opticalconfig")
+
+    raise InvalidArgumentsException([
+        ('DeviceId ', device_id),
+       
+    ], extra_details=['device_id is required to produce a OpticalConfig UUID'])
diff --git a/src/service/tests/test_l3nm_gnmi_static_rule_gen/MockServiceHandler.py b/src/service/tests/test_l3nm_gnmi_static_rule_gen/MockServiceHandler.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b3f76566c9d8e5b2c8bdfb05f4b2448c29b7eae
--- /dev/null
+++ b/src/service/tests/test_l3nm_gnmi_static_rule_gen/MockServiceHandler.py
@@ -0,0 +1,160 @@
+# 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, Dict, List, Optional, Tuple, Union
+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._ServiceHandler import _ServiceHandler
+from service.service.service_handler_api.SettingsHandler import SettingsHandler
+from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching
+from .MockTaskExecutor import MockTaskExecutor
+from service.service.service_handlers.l3nm_gnmi_openconfig.ConfigRuleComposer import ConfigRuleComposer
+from service.service.service_handlers.l3nm_gnmi_openconfig.StaticRouteGenerator import StaticRouteGenerator
+
+LOGGER = logging.getLogger(__name__)
+
+class MockServiceHandler(_ServiceHandler):
+    def __init__(   # pylint: disable=super-init-not-called
+        self, service : Service, task_executor : MockTaskExecutor, **settings
+    ) -> None:
+        self.__service = service
+        self.__task_executor = task_executor
+        self.__settings_handler = SettingsHandler(service.service_config, **settings)
+        self.__config_rule_composer = ConfigRuleComposer()
+        self.__static_route_generator = StaticRouteGenerator(self.__config_rule_composer)
+        self.__endpoint_map : Dict[Tuple[str, str], Tuple[str, str]] = dict()
+
+    def _compose_config_rules(self, endpoints : List[Tuple[str, str, Optional[str]]]) -> None:
+        if len(endpoints) % 2 != 0: raise Exception('Number of endpoints should be even')
+
+        service_settings = self.__settings_handler.get_service_settings()
+        self.__config_rule_composer.configure(self.__service, service_settings)
+
+        for endpoint in endpoints:
+            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)
+            _device = self.__config_rule_composer.get_device(device_obj.name)
+            _device.configure(device_obj, device_settings)
+
+            endpoint_obj = get_endpoint_matching(device_obj, endpoint_uuid)
+            endpoint_settings = self.__settings_handler.get_endpoint_settings(device_obj, endpoint_obj)
+            _endpoint = _device.get_endpoint(endpoint_obj.name)
+            _endpoint.configure(endpoint_obj, endpoint_settings)
+
+            self.__endpoint_map[(device_uuid, endpoint_uuid)] = (device_obj.name, endpoint_obj.name)
+
+        self.__static_route_generator.compose(endpoints)
+
+    def _do_configurations(
+        self, config_rules_per_device : Dict[str, List[Dict]], endpoints : List[Tuple[str, str, Optional[str]]],
+        delete : bool = False
+    ) -> List[Union[bool, Exception]]:
+        # Configuration is done atomically on each device, all OK / all KO per device
+        results_per_device = dict()
+        for device_name,json_config_rules in config_rules_per_device.items():
+            try:
+                device_obj = self.__config_rule_composer.get_device(device_name).objekt
+                if len(json_config_rules) == 0: continue
+                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_per_device[device_name] = True
+            except Exception as e: # pylint: disable=broad-exception-caught
+                verb = 'deconfigure' if delete else 'configure'
+                MSG = 'Unable to {:s} Device({:s}) : ConfigRules({:s})'
+                LOGGER.exception(MSG.format(verb, str(device_name), str(json_config_rules)))
+                results_per_device[device_name] = e
+
+        results = []
+        for endpoint in endpoints:
+            device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint)
+            device_name, _ = self.__endpoint_map[(device_uuid, endpoint_uuid)]
+            if device_name not in results_per_device: continue
+            results.append(results_per_device[device_name])
+        return results
+
+    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 []
+        self._compose_config_rules(endpoints)
+        config_rules_per_device = self.__config_rule_composer.get_config_rules(delete=False)
+        LOGGER.debug('config_rules_per_device={:s}'.format(str(config_rules_per_device)))
+        results = self._do_configurations(config_rules_per_device, endpoints)
+        LOGGER.debug('results={:s}'.format(str(results)))
+        return results
+
+    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 []
+        self._compose_config_rules(endpoints)
+        config_rules_per_device = self.__config_rule_composer.get_config_rules(delete=True)
+        LOGGER.debug('config_rules_per_device={:s}'.format(str(config_rules_per_device)))
+        results = self._do_configurations(config_rules_per_device, endpoints, delete=True)
+        LOGGER.debug('results={:s}'.format(str(results)))
+        return results
+
+    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))]
+
+    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))]
+
+    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
+
+    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/tests/test_l3nm_gnmi_static_rule_gen/MockTaskExecutor.py b/src/service/tests/test_l3nm_gnmi_static_rule_gen/MockTaskExecutor.py
new file mode 100644
index 0000000000000000000000000000000000000000..765b04477efdf06bfef934e96329887e898aa1b4
--- /dev/null
+++ b/src/service/tests/test_l3nm_gnmi_static_rule_gen/MockTaskExecutor.py
@@ -0,0 +1,57 @@
+# 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 logging
+from enum import Enum
+from typing import Dict, Optional, Union
+from common.method_wrappers.ServiceExceptions import NotFoundException
+from common.proto.context_pb2 import Connection, Device, DeviceId, Service
+from service.service.tools.ObjectKeys import get_device_key
+
+LOGGER = logging.getLogger(__name__)
+
+CacheableObject = Union[Connection, Device, Service]
+
+class CacheableObjectType(Enum):
+    CONNECTION = 'connection'
+    DEVICE     = 'device'
+    SERVICE    = 'service'
+
+class MockTaskExecutor:
+    def __init__(self) -> None:
+        self._grpc_objects_cache : Dict[str, CacheableObject] = dict()
+
+    # ----- Common methods ---------------------------------------------------------------------------------------------
+
+    def _load_grpc_object(self, object_type : CacheableObjectType, object_key : str) -> Optional[CacheableObject]:
+        object_key = '{:s}:{:s}'.format(object_type.value, object_key)
+        return self._grpc_objects_cache.get(object_key)
+
+    def _store_grpc_object(self, object_type : CacheableObjectType, object_key : str, grpc_object) -> None:
+        object_key = '{:s}:{:s}'.format(object_type.value, object_key)
+        self._grpc_objects_cache[object_key] = grpc_object
+    
+    def _delete_grpc_object(self, object_type : CacheableObjectType, object_key : str) -> None:
+        object_key = '{:s}:{:s}'.format(object_type.value, object_key)
+        self._grpc_objects_cache.pop(object_key, None)
+
+    def get_device(self, device_id : DeviceId) -> Device:
+        device_key = get_device_key(device_id)
+        device = self._load_grpc_object(CacheableObjectType.DEVICE, device_key)
+        if device is None: raise NotFoundException('Device', device_key)
+        return device
+
+    def configure_device(self, device : Device) -> None:
+        device_key = get_device_key(device.device_id)
+        self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device)
diff --git a/src/service/tests/test_l3nm_gnmi_static_rule_gen/__init__.py b/src/service/tests/test_l3nm_gnmi_static_rule_gen/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ee6f7071f145e06c3aeaefc09a43ccd88e619e3
--- /dev/null
+++ b/src/service/tests/test_l3nm_gnmi_static_rule_gen/__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/service/tests/test_l3nm_gnmi_static_rule_gen/test_unitary.py b/src/service/tests/test_l3nm_gnmi_static_rule_gen/test_unitary.py
new file mode 100644
index 0000000000000000000000000000000000000000..43709b036b8158ddfc59453aa798fa2d303906e0
--- /dev/null
+++ b/src/service/tests/test_l3nm_gnmi_static_rule_gen/test_unitary.py
@@ -0,0 +1,147 @@
+# 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.
+
+# Run with:
+# $ PYTHONPATH=./src python -m service.tests.test_l3nm_gnmi_static_rule_gen.test_unitary
+
+import logging
+from typing import List, Optional, Tuple
+from common.DeviceTypes import DeviceTypeEnum
+from common.proto.context_pb2 import Device, DeviceOperationalStatusEnum, Service
+from common.tools.object_factory.ConfigRule import json_config_rule_set
+from common.tools.object_factory.Device import json_device, json_device_id
+from common.tools.object_factory.EndPoint import json_endpoint, json_endpoint_id
+from common.tools.object_factory.Service import json_service_l3nm_planned
+from .MockServiceHandler import MockServiceHandler
+from .MockTaskExecutor import CacheableObjectType, MockTaskExecutor
+
+logging.basicConfig(level=logging.DEBUG)
+LOGGER = logging.getLogger(__name__)
+
+SERVICE_DC1_DC2 = Service(**json_service_l3nm_planned(
+    'svc-dc1-dc2-uuid',
+    endpoint_ids=[
+        json_endpoint_id(json_device_id('DC1'), 'int'),
+        json_endpoint_id(json_device_id('DC2'), 'int'),
+    ],
+    config_rules=[
+        json_config_rule_set('/device[DC1]/endpoint[eth0]/settings', {
+            'ipv4_address': '192.168.10.10', 'ipv4_prefix_len': 24, 'sub_interface_index': 0
+        }),
+        json_config_rule_set('/device[R1]/endpoint[1/2]/settings', {
+            'ipv4_address': '10.0.1.1', 'ipv4_prefix_len': 24, 'sub_interface_index': 0
+        }),
+        #json_config_rule_set('/device[R2]/endpoint[1/2]/settings', {
+        #    'ipv4_address': '10.0.2.1', 'ipv4_prefix_len': 24, 'sub_interface_index': 0
+        #}),
+        json_config_rule_set('/device[DC2]/endpoint[eth0]/settings', {
+            'ipv4_address': '192.168.20.10', 'ipv4_prefix_len': 24, 'sub_interface_index': 0
+        }),
+    ]
+))
+
+SERVICE_DC1_DC3 = Service(**json_service_l3nm_planned(
+    'svc-dc1-dc3-uuid',
+    endpoint_ids=[
+        json_endpoint_id(json_device_id('DC1'), 'int'),
+        json_endpoint_id(json_device_id('DC3'), 'int'),
+    ],
+    config_rules=[
+        json_config_rule_set('/device[DC1]/endpoint[eth0]/settings', {
+            'ipv4_address': '192.168.10.10', 'ipv4_prefix_len': 24, 'sub_interface_index': 0
+        }),
+        #json_config_rule_set('/device[R1]/endpoint[1/2]/settings', {
+        #    'ipv4_address': '10.0.1.1', 'ipv4_prefix_len': 24, 'sub_interface_index': 0
+        #}),
+        json_config_rule_set('/device[R4]/endpoint[1/1]/settings', {
+            'ipv4_address': '10.0.4.1', 'ipv4_prefix_len': 24, 'sub_interface_index': 0
+        }),
+        json_config_rule_set('/device[DC3]/endpoint[eth0]/settings', {
+            'ipv4_address': '192.168.30.10', 'ipv4_prefix_len': 24, 'sub_interface_index': 0
+        }),
+    ]
+))
+
+CONNECTION_ENDPOINTS_DC1_DC2 : List[Tuple[str, str, Optional[str]]] = [
+    ('DC1', 'int',  None), ('DC1', 'eth0', None),
+    ('R1',  '1/1',  None), ('R1',  '1/2',  None),
+    ('R2',  '1/1',  None), ('R2',  '1/2',  None),
+    ('R3',  '1/1',  None), ('R3',  '1/2',  None),
+    ('DC2', 'eth0', None), ('DC2', 'int',  None),
+]
+
+CONNECTION_ENDPOINTS_DC1_DC3 : List[Tuple[str, str, Optional[str]]] = [
+    ('DC1', 'int',  None), ('DC1', 'eth0', None),
+    ('R1',  '1/1',  None), ('R1',  '1/2',  None),
+    ('R2',  '1/1',  None), ('R2',  '1/3',  None),
+    ('R4',  '1/1',  None), ('R4',  '1/2',  None),
+    ('DC3', 'eth0', None), ('DC3', 'int',  None),
+]
+
+def test_l3nm_gnmi_static_rule_gen() -> None:
+    dev_op_st_enabled = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
+
+    mock_task_executor = MockTaskExecutor()
+    mock_task_executor._store_grpc_object(CacheableObjectType.DEVICE, 'DC1', Device(**json_device(
+        'uuid-DC1', DeviceTypeEnum.EMULATED_DATACENTER.value, dev_op_st_enabled, name='DC1', endpoints=[
+            json_endpoint(json_device_id('uuid-DC1'), 'uuid-int',  'packet', name='int' ),
+            json_endpoint(json_device_id('uuid-DC1'), 'uuid-eth0', 'packet', name='eth0'),
+        ]
+    )))
+    mock_task_executor._store_grpc_object(CacheableObjectType.DEVICE, 'DC2', Device(**json_device(
+        'uuid-DC2', DeviceTypeEnum.EMULATED_DATACENTER.value, dev_op_st_enabled, name='DC2', endpoints=[
+            json_endpoint(json_device_id('uuid-DC2'), 'uuid-int',  'packet', name='int' ),
+            json_endpoint(json_device_id('uuid-DC2'), 'uuid-eth0', 'packet', name='eth0'),
+        ]
+    )))
+    mock_task_executor._store_grpc_object(CacheableObjectType.DEVICE, 'DC3', Device(**json_device(
+        'uuid-DC3', DeviceTypeEnum.EMULATED_DATACENTER.value, dev_op_st_enabled, name='DC3', endpoints=[
+            json_endpoint(json_device_id('uuid-DC3'), 'uuid-int',  'packet', name='int' ),
+            json_endpoint(json_device_id('uuid-DC3'), 'uuid-eth0', 'packet', name='eth0'),
+        ]
+    )))
+    mock_task_executor._store_grpc_object(CacheableObjectType.DEVICE, 'R1', Device(**json_device(
+        'uuid-R1', DeviceTypeEnum.EMULATED_PACKET_ROUTER.value, dev_op_st_enabled, name='R1', endpoints=[
+            json_endpoint(json_device_id('uuid-R1'), 'uuid-1/1', 'packet', name='1/1'),
+            json_endpoint(json_device_id('uuid-R1'), 'uuid-1/2', 'packet', name='1/2'),
+        ]
+    )))
+    mock_task_executor._store_grpc_object(CacheableObjectType.DEVICE, 'R2', Device(**json_device(
+        'uuid-R2', DeviceTypeEnum.EMULATED_PACKET_ROUTER.value, dev_op_st_enabled, name='R2', endpoints=[
+            json_endpoint(json_device_id('uuid-R2'), 'uuid-1/1', 'packet', name='1/1'),
+            json_endpoint(json_device_id('uuid-R2'), 'uuid-1/2', 'packet', name='1/2'),
+            json_endpoint(json_device_id('uuid-R2'), 'uuid-1/3', 'packet', name='1/3'),
+        ]
+    )))
+    mock_task_executor._store_grpc_object(CacheableObjectType.DEVICE, 'R3', Device(**json_device(
+        'uuid-R3', DeviceTypeEnum.EMULATED_PACKET_ROUTER.value, dev_op_st_enabled, name='R3', endpoints=[
+            json_endpoint(json_device_id('uuid-R3'), 'uuid-1/1', 'packet', name='1/1'),
+            json_endpoint(json_device_id('uuid-R3'), 'uuid-1/2', 'packet', name='1/2'),
+        ]
+    )))
+    mock_task_executor._store_grpc_object(CacheableObjectType.DEVICE, 'R4', Device(**json_device(
+        'uuid-R4', DeviceTypeEnum.EMULATED_PACKET_ROUTER.value, dev_op_st_enabled, name='R4', endpoints=[
+            json_endpoint(json_device_id('uuid-R4'), 'uuid-1/1', 'packet', name='1/1'),
+            json_endpoint(json_device_id('uuid-R4'), 'uuid-1/2', 'packet', name='1/2'),
+        ]
+    )))
+
+    mock_service_handler = MockServiceHandler(SERVICE_DC1_DC2, mock_task_executor)
+    mock_service_handler.SetEndpoint(CONNECTION_ENDPOINTS_DC1_DC2)
+
+    mock_service_handler = MockServiceHandler(SERVICE_DC1_DC3, mock_task_executor)
+    mock_service_handler.SetEndpoint(CONNECTION_ENDPOINTS_DC1_DC3)
+
+if __name__ == '__main__':
+    test_l3nm_gnmi_static_rule_gen()
diff --git a/src/tests/.gitlab-ci.yml b/src/tests/.gitlab-ci.yml
index 808aebf2173361e05fee5ed2806b9c7aa6362753..b7da988bf33175e149906243f28b0df0d78d9d8b 100644
--- a/src/tests/.gitlab-ci.yml
+++ b/src/tests/.gitlab-ci.yml
@@ -20,4 +20,5 @@ include:
   #- local: '/src/tests/nfvsdn22/.gitlab-ci.yml'
   #- local: '/src/tests/ofc23/.gitlab-ci.yml'
   - local: '/src/tests/ofc24/.gitlab-ci.yml'
+  - local: '/src/tests/eucnc24/.gitlab-ci.yml'
   #- local: '/src/tests/ecoc24/.gitlab-ci.yml'
diff --git a/src/tests/eucnc24/.gitignore b/src/tests/eucnc24/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..24a4b233365e23a9462f4b64e8b60fef6a62bee4
--- /dev/null
+++ b/src/tests/eucnc24/.gitignore
@@ -0,0 +1,5 @@
+clab-*/
+images/
+*.clab.yml.bak
+*.tar
+*.tar.gz
diff --git a/src/tests/eucnc24/.gitlab-ci.yml b/src/tests/eucnc24/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5dec5e36cf2a2984fcbb073190fb386e16a4e8c3
--- /dev/null
+++ b/src/tests/eucnc24/.gitlab-ci.yml
@@ -0,0 +1,201 @@
+# 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.
+
+# Build, tag, and push the Docker image to the GitLab Docker registry
+build eucnc24:
+  variables:
+    TEST_NAME: 'eucnc24'
+  stage: build
+  before_script:
+    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
+  script:
+    - docker buildx build -t "${TEST_NAME}:latest" -f ./src/tests/${TEST_NAME}/Dockerfile .
+    - docker tag "${TEST_NAME}:latest" "$CI_REGISTRY_IMAGE/${TEST_NAME}:latest"
+    - docker push "$CI_REGISTRY_IMAGE/${TEST_NAME}:latest"
+  after_script:
+    - docker images --filter="dangling=true" --quiet | xargs -r docker rmi
+  rules:
+    - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)'
+    - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"'
+    - changes:
+      - src/common/**/*.py
+      - proto/*.proto
+      - src/tests/${TEST_NAME}/**/*.{py,in,sh,yml}
+      - src/tests/${TEST_NAME}/Dockerfile
+      - .gitlab-ci.yml
+
+# Deploy TeraFlowSDN and Execute end-2-end test
+end2end_test eucnc24:
+  variables:
+    TEST_NAME: 'eucnc24'
+  stage: end2end_test
+  # Disable to force running it after all other tasks
+  #needs:
+  #  - build eucnc24
+  before_script:
+    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
+    - docker rm -f ${TEST_NAME} || true
+    - sudo containerlab destroy --all --cleanup || true
+
+  script:
+    # Download Docker image to run the test
+    - docker pull "${CI_REGISTRY_IMAGE}/${TEST_NAME}:latest"
+
+    # Check MicroK8s is ready
+    - microk8s status --wait-ready
+    - kubectl get pods --all-namespaces
+
+    # Deploy ContainerLab Scenario
+    - RUNNER_PATH=`pwd`
+    #- cd $PWD/src/tests/${TEST_NAME}
+    - mkdir -p /tmp/clab/${TEST_NAME}
+    - cp -R src/tests/${TEST_NAME}/clab/* /tmp/clab/${TEST_NAME}
+    - tree -la /tmp/clab/${TEST_NAME}
+    - cd /tmp/clab/${TEST_NAME}
+    - sudo containerlab deploy --reconfigure --topo eucnc24.clab.yml
+    - cd $RUNNER_PATH
+
+    # Wait for initialization of Device NOSes
+    - sleep 3
+    - docker ps -a
+
+    # Configure TeraFlowSDN deployment
+    # Uncomment if DEBUG log level is needed for the components
+    #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="server").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/contextservice.yaml
+    #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="server").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/deviceservice.yaml
+    #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="frontend").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/pathcompservice.yaml
+    #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="server").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/serviceservice.yaml
+    #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="server").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/nbiservice.yaml
+    #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="server").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/monitoringservice.yaml
+
+    - source src/tests/${TEST_NAME}/deploy_specs.sh
+    #- export TFS_REGISTRY_IMAGES="${CI_REGISTRY_IMAGE}"
+    #- export TFS_SKIP_BUILD="YES"
+    #- export TFS_IMAGE_TAG="latest"
+    #- echo "TFS_REGISTRY_IMAGES=${CI_REGISTRY_IMAGE}"
+
+    # Deploy TeraFlowSDN
+    - ./deploy/crdb.sh
+    - ./deploy/nats.sh
+    - ./deploy/qdb.sh
+    - ./deploy/kafka.sh
+    - ./deploy/tfs.sh
+    - ./deploy/show.sh
+
+    ## Wait for Context to be subscribed to NATS
+    ## WARNING: this loop is infinite if there is no subscriber (such as monitoring).
+    ##          Investigate if we can use a counter to limit the number of iterations.
+    ##          For now, keep it commented out.
+    #- LOOP_MAX_ATTEMPTS=180
+    #- LOOP_COUNTER=0
+    #- >
+    #  while ! kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/contextservice -c server 2>&1 | grep -q 'Subscriber is Ready? True'; do
+    #    echo "Attempt: $LOOP_COUNTER"
+    #    kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/contextservice -c server 2>&1;
+    #    sleep 1;
+    #    LOOP_COUNTER=$((LOOP_COUNTER + 1))
+    #    if [ "$LOOP_COUNTER" -ge "$LOOP_MAX_ATTEMPTS" ]; then
+    #      echo "Max attempts reached, exiting the loop."
+    #      break
+    #    fi
+    #  done
+    - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/contextservice -c server
+
+    # Run end-to-end test: onboard scenario
+    - >
+      docker run -t --rm --name ${TEST_NAME} --network=host 
+      --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh"
+      --volume "$PWD/src/tests/${TEST_NAME}:/opt/results"
+      $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-onboarding.sh
+
+    # Run end-to-end test: configure service TFS
+    - >
+      docker run -t --rm --name ${TEST_NAME} --network=host 
+      --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh"
+      --volume "$PWD/src/tests/${TEST_NAME}:/opt/results"
+      $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-tfs-create.sh
+
+    # Run end-to-end test: test connectivity with ping
+    - sudo containerlab exec --name eucnc24 --label clab-node-name=dc1 --cmd 'ping -n -c3 192.168.1.10'
+    - sudo containerlab exec --name eucnc24 --label clab-node-name=dc1 --cmd 'ping -n -c3 192.168.1.1'
+    - sudo containerlab exec --name eucnc24 --label clab-node-name=dc1 --cmd 'ping -n -c3 192.168.2.1'
+    - sudo containerlab exec --name eucnc24 --label clab-node-name=dc1 --cmd 'ping -n -c3 192.168.2.10'
+    - sudo containerlab exec --name eucnc24 --label clab-node-name=dc1 --cmd 'ping -n -c3 192.168.3.10'
+
+    # Run end-to-end test: deconfigure service TFS
+    - >
+      docker run -t --rm --name ${TEST_NAME} --network=host 
+      --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh"
+      --volume "$PWD/src/tests/${TEST_NAME}:/opt/results"
+      $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-tfs-remove.sh
+
+    # Run end-to-end test: configure service IETF
+    - >
+      docker run -t --rm --name ${TEST_NAME} --network=host 
+      --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh"
+      --volume "$PWD/src/tests/${TEST_NAME}:/opt/results"
+      $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-ietf-create.sh
+
+    # Run end-to-end test: test connectivity with ping
+    - sudo containerlab exec --name eucnc24 --label clab-node-name=dc1 --cmd 'ping -n -c3 192.168.1.10'
+    - sudo containerlab exec --name eucnc24 --label clab-node-name=dc1 --cmd 'ping -n -c3 192.168.1.1'
+    - sudo containerlab exec --name eucnc24 --label clab-node-name=dc1 --cmd 'ping -n -c3 192.168.2.1'
+    - sudo containerlab exec --name eucnc24 --label clab-node-name=dc1 --cmd 'ping -n -c3 192.168.2.10'
+    - sudo containerlab exec --name eucnc24 --label clab-node-name=dc1 --cmd 'ping -n -c3 192.168.3.10'
+
+    # Run end-to-end test: deconfigure service IETF
+    - >
+      docker run -t --rm --name ${TEST_NAME} --network=host 
+      --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh"
+      --volume "$PWD/src/tests/${TEST_NAME}:/opt/results"
+      $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-ietf-remove.sh
+
+    # Run end-to-end test: cleanup scenario
+    - >
+      docker run -t --rm --name ${TEST_NAME} --network=host 
+      --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh"
+      --volume "$PWD/src/tests/${TEST_NAME}:/opt/results"
+      $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-cleanup.sh
+
+  after_script:
+    # Dump TeraFlowSDN component logs
+    - source src/tests/${TEST_NAME}/deploy_specs.sh
+    - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/contextservice -c server
+    - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/deviceservice -c server
+    - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/pathcompservice -c frontend
+    - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/serviceservice -c server
+    - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/nbiservice -c server
+    #- kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/monitoringservice -c server
+
+    # Destroy Scenario
+    - docker rm -f ${TEST_NAME} || true
+    - RUNNER_PATH=`pwd`
+    #- cd $PWD/src/tests/${TEST_NAME}
+    - cd /tmp/clab/${TEST_NAME}
+    - sudo containerlab destroy --topo eucnc24.clab.yml --cleanup || true
+    - sudo rm -rf clab-eucnc24/ .eucnc24.clab.yml.bak || true
+    - cd $RUNNER_PATH
+    - kubectl delete namespaces tfs || true
+
+    # Clean old docker images
+    - docker images --filter="dangling=true" --quiet | xargs -r docker rmi
+
+  #coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'
+  rules:
+    - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)'
+    - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"'
+  artifacts:
+      when: always
+      reports:
+        junit: ./src/tests/${TEST_NAME}/report_*.xml
diff --git a/src/tests/eucnc24/Dockerfile b/src/tests/eucnc24/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..23a38bace79880f37fe7957566f7d84030fa7fd8
--- /dev/null
+++ b/src/tests/eucnc24/Dockerfile
@@ -0,0 +1,84 @@
+# 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 python:3.9-slim
+
+# Install dependencies
+RUN apt-get --yes --quiet --quiet update && \
+    apt-get --yes --quiet --quiet install wget g++ git && \
+    rm -rf /var/lib/apt/lists/*
+
+# Set Python to show logs as they occur
+ENV PYTHONUNBUFFERED=0
+
+# Get generic Python packages
+RUN python3 -m pip install --upgrade pip
+RUN python3 -m pip install --upgrade setuptools wheel
+RUN python3 -m pip install --upgrade pip-tools
+
+# Get common Python packages
+# Note: this step enables sharing the previous Docker build steps among all the Python components
+WORKDIR /var/teraflow
+COPY common_requirements.in common_requirements.in
+RUN pip-compile --quiet --output-file=common_requirements.txt common_requirements.in
+RUN python3 -m pip install -r common_requirements.txt
+
+# Add common files into working directory
+WORKDIR /var/teraflow/common
+COPY src/common/. ./
+RUN rm -rf proto
+
+# Create proto sub-folder, copy .proto files, and generate Python code
+RUN mkdir -p /var/teraflow/common/proto
+WORKDIR /var/teraflow/common/proto
+RUN touch __init__.py
+COPY proto/*.proto ./
+RUN python3 -m grpc_tools.protoc -I=. --python_out=. --grpc_python_out=. *.proto
+RUN rm *.proto
+RUN find . -type f -exec sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' {} \;
+
+# Create component sub-folders, get specific Python packages
+RUN mkdir -p /var/teraflow/tests/eucnc24
+WORKDIR /var/teraflow/tests/eucnc24
+COPY src/tests/eucnc24/requirements.in requirements.in
+RUN pip-compile --quiet --output-file=requirements.txt requirements.in
+RUN python3 -m pip install -r requirements.txt
+
+# Add component files into working directory
+WORKDIR /var/teraflow
+COPY src/__init__.py ./__init__.py
+COPY src/common/*.py ./common/
+COPY src/common/tests/. ./common/tests/
+COPY src/common/tools/. ./common/tools/
+COPY src/context/__init__.py context/__init__.py
+COPY src/context/client/. context/client/
+COPY src/device/__init__.py device/__init__.py
+COPY src/device/client/. device/client/
+COPY src/monitoring/__init__.py monitoring/__init__.py
+COPY src/monitoring/client/. monitoring/client/
+COPY src/service/__init__.py service/__init__.py
+COPY src/service/client/. service/client/
+COPY src/slice/__init__.py slice/__init__.py
+COPY src/slice/client/. slice/client/
+COPY src/tests/*.py ./tests/
+COPY src/tests/eucnc24/__init__.py ./tests/eucnc24/__init__.py
+COPY src/tests/eucnc24/data/. ./tests/eucnc24/data/
+COPY src/tests/eucnc24/tests/. ./tests/eucnc24/tests/
+COPY src/tests/eucnc24/scripts/. ./
+
+RUN apt-get --yes --quiet --quiet update && \
+    apt-get --yes --quiet --quiet install tree && \
+    rm -rf /var/lib/apt/lists/*
+
+RUN tree -la /var/teraflow
diff --git a/src/tests/eucnc24/README.md b/src/tests/eucnc24/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f8c2f9d49793b8e0751ea4ea09bf893e7ceae0b6
--- /dev/null
+++ b/src/tests/eucnc24/README.md
@@ -0,0 +1,123 @@
+# DataPlane-in-a-Box - Control an Emulated DataPlane through TeraFlowSDN
+
+## Emulated DataPlane Deployment
+- ContainerLab
+- Scenario
+- Descriptor
+
+## TeraFlowSDN Deployment
+```bash
+cd ~/tfs-ctrl
+source dataplane-in-a-box/deploy_specs.sh
+./deploy/all.sh
+```
+
+# ContainerLab - Arista cEOS - Commands
+
+## Download and install ContainerLab
+```bash
+sudo bash -c "$(curl -sL https://get.containerlab.dev)" -- -v 0.48.6
+```
+
+## Download Arista cEOS image and create Docker image
+```bash
+cd ~/tfs-ctrl/dataplane-in-a-box
+docker import arista/cEOS64-lab-4.31.2F.tar ceos:4.31.2F
+```
+
+## Deploy scenario
+```bash
+cd ~/tfs-ctrl/dataplane-in-a-box
+sudo containerlab deploy --topo arista.clab.yml
+```
+
+## Inspect scenario
+```bash
+cd ~/tfs-ctrl/dataplane-in-a-box
+sudo containerlab inspect --topo arista.clab.yml
+```
+
+## Destroy scenario
+```bash
+cd ~/tfs-ctrl/dataplane-in-a-box
+sudo containerlab destroy --topo arista.clab.yml
+sudo rm -rf clab-arista/ .arista.clab.yml.bak
+```
+
+## Access cEOS Bash
+```bash
+docker exec -it clab-arista-r1 bash
+```
+
+## Access cEOS CLI
+```bash
+docker exec -it clab-arista-r1 Cli
+docker exec -it clab-arista-r2 Cli
+```
+
+## Configure ContainerLab clients
+```bash
+docker exec -it clab-arista-client1 bash
+    ip address add 192.168.1.10/24 dev eth1
+    ip route add 192.168.2.0/24 via 192.168.1.1
+    ip route add 192.168.3.0/24 via 192.168.1.1
+    ping 192.168.2.10
+    ping 192.168.3.10
+
+docker exec -it clab-arista-client2 bash
+    ip address add 192.168.2.10/24 dev eth1
+    ip route add 192.168.1.0/24 via 192.168.2.1
+    ip route add 192.168.3.0/24 via 192.168.2.1
+    ping 192.168.1.10
+    ping 192.168.3.10
+
+docker exec -it clab-arista-client3 bash
+    ip address add 192.168.3.10/24 dev eth1
+    ip route add 192.168.2.0/24 via 192.168.3.1
+    ip route add 192.168.3.0/24 via 192.168.3.1
+    ping 192.168.2.10
+    ping 192.168.3.10
+```
+
+## Install gNMIc
+```bash
+sudo bash -c "$(curl -sL https://get-gnmic.kmrd.dev)"
+```
+
+## gNMI Capabilities request
+```bash
+gnmic --address clab-arista-wan1 --port 6030 --username admin --password admin --insecure capabilities
+```
+
+## gNMI Get request
+```bash
+gnmic --address clab-arista-wan1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path / > wan1.json
+gnmic --address clab-arista-wan1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path /interfaces/interface > wan1-ifaces.json
+```
+
+## gNMI Set request
+```bash
+#gnmic --address clab-arista-wan1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --update-path /system/config/hostname --update-value srl11
+#gnmic --address clab-arista-wan1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path /system/config/hostname
+```
+
+## Subscribe request
+```bash
+gnmic --address clab-arista-wan1 --port 6030 --username admin --password admin --insecure --encoding json_ietf subscribe --path /interfaces/interface[name=Management0]/state/
+
+# In another terminal, you can generate traffic opening SSH connection
+ssh admin@clab-arista-wan1
+```
+
+# Check configurations done:
+```bash
+gnmic --address clab-arista-wan1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path '/network-instances' > wan1-nis.json
+gnmic --address clab-arista-wan1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path '/interfaces' > wan1-ifs.json
+```
+
+# Delete elements:
+```bash
+--address clab-arista-wan1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/network-instances/network-instance[name=b19229e8]'
+--address clab-arista-wan1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/interfaces/interface[name=ethernet-1/1]/subinterfaces/subinterface[index=0]'
+--address clab-arista-wan1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/interfaces/interface[name=ethernet-1/2]/subinterfaces/subinterface[index=0]'
+```
diff --git a/src/tests/eucnc24/__init__.py b/src/tests/eucnc24/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ee6f7071f145e06c3aeaefc09a43ccd88e619e3
--- /dev/null
+++ b/src/tests/eucnc24/__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/tests/eucnc24/clab/eucnc24.clab.yml b/src/tests/eucnc24/clab/eucnc24.clab.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c9182ba1d405cce514d54494da37d27586fd83ac
--- /dev/null
+++ b/src/tests/eucnc24/clab/eucnc24.clab.yml
@@ -0,0 +1,70 @@
+# 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.
+
+# TFS - Arista devices + Linux clients
+
+name: eucnc24
+
+mgmt:
+  network: mgmt-net
+  ipv4-subnet: 172.20.20.0/24
+
+topology:
+  kinds:
+    arista_ceos:
+      kind: arista_ceos
+      #image: ceos:4.30.4M
+      #image: ceos:4.31.2F
+      #image: ceos:4.31.5M
+      #image: ceos:4.32.0F
+      image: ceos:4.32.2F
+      #image: ceos:4.32.2.1F
+    linux:
+      kind: linux
+      image: ghcr.io/hellt/network-multitool:latest
+
+  nodes:
+    r1:
+      kind: arista_ceos
+      mgmt-ipv4: 172.20.20.101
+
+    r2:
+      kind: arista_ceos
+      mgmt-ipv4: 172.20.20.102
+
+    r3:
+      kind: arista_ceos
+      mgmt-ipv4: 172.20.20.103
+
+    dc1:
+      kind: linux
+      mgmt-ipv4: 172.20.20.211
+      exec:
+        - ip link set address 00:c1:ab:00:01:01 dev eth1
+        - ip address add 192.168.1.10/24 dev eth1
+        - ip route add 192.168.2.0/24 via 192.168.1.1
+
+    dc2:
+      kind: linux
+      mgmt-ipv4: 172.20.20.221
+      exec:
+        - ip link set address 00:c1:ab:00:02:01 dev eth1
+        - ip address add 192.168.2.10/24 dev eth1
+        - ip route add 192.168.1.0/24 via 192.168.2.1
+
+  links:
+    - endpoints: ["r1:eth2", "r2:eth1"]
+    - endpoints: ["r2:eth3", "r3:eth2"]
+    - endpoints: ["r1:eth10", "dc1:eth1"]
+    - endpoints: ["r3:eth10", "dc2:eth1"]
diff --git a/src/tests/eucnc24/data/ietf-l3vpn-service.json b/src/tests/eucnc24/data/ietf-l3vpn-service.json
new file mode 100644
index 0000000000000000000000000000000000000000..a6297b28f0fea94dcc8a457ad2b45d38e77aa4ea
--- /dev/null
+++ b/src/tests/eucnc24/data/ietf-l3vpn-service.json
@@ -0,0 +1,83 @@
+{
+    "ietf-l3vpn-svc:l3vpn-svc": {
+        "vpn-services": {"vpn-service": [{"vpn-id": "ietf-l3vpn-svc"}]},
+        "sites": {
+            "site": [
+                {
+                    "site-id": "site_DC1",
+                    "management": {"type": "ietf-l3vpn-svc:provider-managed"},
+                    "locations": {"location": [{"location-id": "DC1"}]},
+                    "devices": {"device": [{"device-id": "dc1", "location": "DC1"}]},
+                    "site-network-accesses": {
+                        "site-network-access": [
+                            {
+                                "site-network-access-id": "int",
+                                "site-network-access-type": "ietf-l3vpn-svc:multipoint",
+                                "device-reference": "dc1",
+                                "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:spoke-role"},
+                                "ip-connection": {
+                                    "ipv4": {
+                                        "address-allocation-type": "ietf-l3vpn-svc:static-address",
+                                        "addresses": {
+                                            "provider-address": "192.168.1.1",
+                                            "customer-address": "192.168.1.10",
+                                            "prefix-length": 24
+                                        }
+                                    }
+                                },
+                                "service": {
+                                    "svc-mtu": 1500,
+                                    "svc-input-bandwidth": 1000000000,
+                                    "svc-output-bandwidth": 1000000000,
+                                    "qos": {"qos-profile": {"classes": {"class": [{
+                                        "class-id": "qos-realtime",
+                                        "direction": "ietf-l3vpn-svc:both",
+                                        "latency": {"latency-boundary": 10},
+                                        "bandwidth": {"guaranteed-bw-percent": 100}
+                                    }]}}}
+                                }
+                            }
+                        ]
+                    }
+                },
+                {
+                    "site-id": "site_DC2",
+                    "management": {"type": "ietf-l3vpn-svc:provider-managed"},
+                    "locations": {"location": [{"location-id": "DC2"}]},
+                    "devices": {"device": [{"device-id": "dc2", "location": "DC2"}]},
+                    "site-network-accesses": {
+                        "site-network-access": [
+                            {
+                                "site-network-access-id": "int",
+                                "site-network-access-type": "ietf-l3vpn-svc:multipoint",
+                                "device-reference": "dc2",
+                                "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:hub-role"},
+                                "ip-connection": {
+                                    "ipv4": {
+                                        "address-allocation-type": "ietf-l3vpn-svc:static-address",
+                                        "addresses": {
+                                            "provider-address": "192.168.2.1",
+                                            "customer-address": "192.168.2.10",
+                                            "prefix-length": 24
+                                        }
+                                    }
+                                },
+                                "service": {
+                                    "svc-mtu": 1500,
+                                    "svc-input-bandwidth": 1000000000,
+                                    "svc-output-bandwidth": 1000000000,
+                                    "qos": {"qos-profile": {"classes": {"class": [{
+                                        "class-id": "qos-realtime",
+                                        "direction": "ietf-l3vpn-svc:both",
+                                        "latency": {"latency-boundary": 10},
+                                        "bandwidth": {"guaranteed-bw-percent": 100}
+                                    }]}}}
+                                }
+                            }
+                        ]
+                    }
+                }
+            ]
+        }
+    }
+}
diff --git a/src/tests/eucnc24/data/tfs-service.json b/src/tests/eucnc24/data/tfs-service.json
new file mode 100644
index 0000000000000000000000000000000000000000..397fc84789111932da047acd22c7bc787888657f
--- /dev/null
+++ b/src/tests/eucnc24/data/tfs-service.json
@@ -0,0 +1,26 @@
+{
+    "services": [
+        {
+            "service_id": {
+                "context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "tfs-l3vpn-svc"}
+            },
+            "service_type": "SERVICETYPE_L3NM",
+            "service_status": {"service_status": "SERVICESTATUS_PLANNED"},
+            "service_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "dc1"}}, "endpoint_uuid": {"uuid": "int"}},
+                {"device_id": {"device_uuid": {"uuid": "dc2"}}, "endpoint_uuid": {"uuid": "int"}}
+            ],
+            "service_constraints": [],
+            "service_config": {"config_rules": [
+                {"action": "CONFIGACTION_SET", "custom": {
+                    "resource_key": "/device[dc1]/endpoint[eth1]/settings",
+                    "resource_value": {"address_ip": "192.168.1.10", "address_prefix": 24, "index": 0}
+                }},
+                {"action": "CONFIGACTION_SET", "custom": {
+                    "resource_key": "/device[dc2]/endpoint[eth1]/settings",
+                    "resource_value": {"address_ip": "192.168.2.10", "address_prefix": 24, "index": 0}
+                }}
+            ]}
+        }
+    ]
+}
diff --git a/src/tests/eucnc24/data/tfs-topology.json b/src/tests/eucnc24/data/tfs-topology.json
new file mode 100644
index 0000000000000000000000000000000000000000..ac87af62d31e4728c12687c525233d8e840d7441
--- /dev/null
+++ b/src/tests/eucnc24/data/tfs-topology.json
@@ -0,0 +1,126 @@
+{
+    "contexts": [
+        {"context_id": {"context_uuid": {"uuid": "admin"}}}
+    ],
+    "topologies": [
+        {"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}}
+    ],
+    "devices": [
+        {
+            "device_id": {"device_uuid": {"uuid": "dc1"}}, "device_type": "emu-datacenter",
+            "device_drivers": ["DEVICEDRIVER_UNDEFINED"],
+            "device_config": {"config_rules": [
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"uuid": "eth1", "type": "copper"}, {"uuid": "int", "type": "copper"}
+                ]}}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "dc2"}}, "device_type": "emu-datacenter",
+            "device_drivers": ["DEVICEDRIVER_UNDEFINED"],
+            "device_config": {"config_rules": [
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"uuid": "eth1", "type": "copper"}, {"uuid": "int", "type": "copper"}
+                ]}}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "r1"}}, "device_type": "packet-router",
+            "device_drivers": ["DEVICEDRIVER_GNMI_OPENCONFIG"],
+            "device_config": {"config_rules": [
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "172.20.20.101"}},
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "6030"}},
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": {
+                    "username": "admin", "password": "admin", "use_tls": false
+                }}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "r2"}}, "device_type": "packet-router",
+            "device_drivers": ["DEVICEDRIVER_GNMI_OPENCONFIG"],
+            "device_config": {"config_rules": [
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "172.20.20.102"}},
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "6030"}},
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": {
+                    "username": "admin", "password": "admin", "use_tls": false
+                }}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "r3"}}, "device_type": "packet-router",
+            "device_drivers": ["DEVICEDRIVER_GNMI_OPENCONFIG"],
+            "device_config": {"config_rules": [
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "172.20.20.103"}},
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "6030"}},
+                {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": {
+                    "username": "admin", "password": "admin", "use_tls": false
+                }}}
+            ]}
+        }
+    ],
+    "links": [
+        {
+            "link_id": {"link_uuid": {"uuid": "r1/Ethernet2==r2/Ethernet1"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet2"}},
+                {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet1"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "r2/Ethernet1==r1/Ethernet2"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet1"}},
+                {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet2"}}
+            ]
+        },
+
+        {
+            "link_id": {"link_uuid": {"uuid": "r2/Ethernet3==r3/Ethernet2"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet3"}},
+                {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet2"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "r3/Ethernet2==r2/Ethernet3"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet2"}},
+                {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet3"}}
+            ]
+        },
+
+        {
+            "link_id": {"link_uuid": {"uuid": "r1/Ethernet10==dc1/eth1"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet10"}},
+                {"device_id": {"device_uuid": {"uuid": "dc1"}}, "endpoint_uuid": {"uuid": "eth1"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "dc1/eth1==r1/Ethernet10"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "dc1"}}, "endpoint_uuid": {"uuid": "eth1"}},
+                {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet10"}}
+            ]
+        },
+
+        {
+            "link_id": {"link_uuid": {"uuid": "r3/Ethernet10==dc2/eth1"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet10"}},
+                {"device_id": {"device_uuid": {"uuid": "dc2"}}, "endpoint_uuid": {"uuid": "eth1"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "dc2/eth1==r3/Ethernet10"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "dc2"}}, "endpoint_uuid": {"uuid": "eth1"}},
+                {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet10"}}
+            ]
+        }
+    ]
+}
diff --git a/src/tests/eucnc24/deploy-scripts/clab-cli-dc1.sh b/src/tests/eucnc24/deploy-scripts/clab-cli-dc1.sh
new file mode 100755
index 0000000000000000000000000000000000000000..d0ee18dcfd7eac03b108e163200d14b532d8db8f
--- /dev/null
+++ b/src/tests/eucnc24/deploy-scripts/clab-cli-dc1.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# 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.
+
+docker exec -it clab-eucnc24-dc1 bash
diff --git a/src/tests/eucnc24/deploy-scripts/clab-cli-dc2.sh b/src/tests/eucnc24/deploy-scripts/clab-cli-dc2.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2867fedcb9051f6d73b78d571b33ed7ae25efd80
--- /dev/null
+++ b/src/tests/eucnc24/deploy-scripts/clab-cli-dc2.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# 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.
+
+docker exec -it clab-eucnc24-dc2 bash
diff --git a/src/tests/eucnc24/deploy-scripts/clab-cli-r1.sh b/src/tests/eucnc24/deploy-scripts/clab-cli-r1.sh
new file mode 100755
index 0000000000000000000000000000000000000000..69141a0ae73ee23274b823242b0f864e1527d505
--- /dev/null
+++ b/src/tests/eucnc24/deploy-scripts/clab-cli-r1.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# 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.
+
+docker exec -it clab-eucnc24-r1 Cli
diff --git a/src/tests/eucnc24/deploy-scripts/clab-cli-r2.sh b/src/tests/eucnc24/deploy-scripts/clab-cli-r2.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7860d1d21f07a293f3bcbc65575625568a49a41c
--- /dev/null
+++ b/src/tests/eucnc24/deploy-scripts/clab-cli-r2.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# 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.
+
+docker exec -it clab-eucnc24-r2 Cli
diff --git a/src/tests/eucnc24/deploy-scripts/clab-cli-r3.sh b/src/tests/eucnc24/deploy-scripts/clab-cli-r3.sh
new file mode 100755
index 0000000000000000000000000000000000000000..801c3223d7c59e767bcc64b0cc331553a34bb4b4
--- /dev/null
+++ b/src/tests/eucnc24/deploy-scripts/clab-cli-r3.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# 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.
+
+docker exec -it clab-eucnc24-r3 Cli
diff --git a/src/tests/eucnc24/deploy-scripts/clab-deploy.sh b/src/tests/eucnc24/deploy-scripts/clab-deploy.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ae1676ada75ab6a5ce671fae187c0a94ffc62331
--- /dev/null
+++ b/src/tests/eucnc24/deploy-scripts/clab-deploy.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# 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.
+
+cd ~/tfs-ctrl/src/tests/eucnc24
+sudo containerlab deploy --topo eucnc24.clab.yml
diff --git a/src/tests/eucnc24/deploy-scripts/clab-destroy.sh b/src/tests/eucnc24/deploy-scripts/clab-destroy.sh
new file mode 100755
index 0000000000000000000000000000000000000000..6e58a3c490c196073f4cb259e11d45dd4ff2a1f8
--- /dev/null
+++ b/src/tests/eucnc24/deploy-scripts/clab-destroy.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+# 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.
+
+cd ~/tfs-ctrl/src/tests/eucnc24
+sudo containerlab destroy --topo eucnc24.clab.yml
+sudo rm -rf clab-eucnc24/ .eucnc24.clab.yml.bak
diff --git a/src/tests/eucnc24/deploy-scripts/clab-inspect.sh b/src/tests/eucnc24/deploy-scripts/clab-inspect.sh
new file mode 100755
index 0000000000000000000000000000000000000000..0dd6dce12dc60e775edc6ab449d1d448f37bd686
--- /dev/null
+++ b/src/tests/eucnc24/deploy-scripts/clab-inspect.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# 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.
+
+cd ~/tfs-ctrl/src/tests/eucnc24
+sudo containerlab inspect --topo eucnc24.clab.yml
diff --git a/src/tests/eucnc24/deploy_specs.sh b/src/tests/eucnc24/deploy_specs.sh
new file mode 100755
index 0000000000000000000000000000000000000000..aa72575a97f7b73ce916448307c3e1773fac57c4
--- /dev/null
+++ b/src/tests/eucnc24/deploy_specs.sh
@@ -0,0 +1,211 @@
+#!/bin/bash
+# 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.
+
+
+# ----- TeraFlowSDN ------------------------------------------------------------
+
+# Set the URL of the internal MicroK8s Docker registry where the images will be uploaded to.
+export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/"
+
+# Set the list of components, separated by spaces, you want to build images for, and deploy.
+#export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_generator"
+export TFS_COMPONENTS="context device pathcomp service nbi"
+
+# Uncomment to activate Monitoring (old)
+#export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring"
+
+# Uncomment to activate Monitoring Framework (new)
+#export TFS_COMPONENTS="${TFS_COMPONENTS} kpi_manager kpi_value_writer kpi_value_api telemetry analytics automation"
+
+# Uncomment to activate QoS Profiles
+#export TFS_COMPONENTS="${TFS_COMPONENTS} qos_profile"
+
+# Uncomment to activate BGP-LS Speaker
+#export TFS_COMPONENTS="${TFS_COMPONENTS} bgpls_speaker"
+
+# Uncomment to activate Optical Controller
+#   To manage optical connections, "service" requires "opticalcontroller" to be deployed
+#   before "service", thus we "hack" the TFS_COMPONENTS environment variable prepending the
+#   "opticalcontroller" only if "service" is already in TFS_COMPONENTS, and re-export it.
+#if [[ "$TFS_COMPONENTS" == *"service"* ]]; then
+#    BEFORE="${TFS_COMPONENTS% service*}"
+#    AFTER="${TFS_COMPONENTS#* service}"
+#    export TFS_COMPONENTS="${BEFORE} opticalcontroller service ${AFTER}"
+#fi
+
+# Uncomment to activate ZTP
+#export TFS_COMPONENTS="${TFS_COMPONENTS} ztp"
+
+# Uncomment to activate Policy Manager
+#export TFS_COMPONENTS="${TFS_COMPONENTS} policy"
+
+# Uncomment to activate Optical CyberSecurity
+#export TFS_COMPONENTS="${TFS_COMPONENTS} dbscanserving opticalattackmitigator opticalattackdetector opticalattackmanager"
+
+# Uncomment to activate L3 CyberSecurity
+#export TFS_COMPONENTS="${TFS_COMPONENTS} l3_attackmitigator l3_centralizedattackdetector"
+
+# Uncomment to activate TE
+#export TFS_COMPONENTS="${TFS_COMPONENTS} te"
+
+# Uncomment to activate Forecaster
+#export TFS_COMPONENTS="${TFS_COMPONENTS} forecaster"
+
+# Uncomment to activate E2E Orchestrator
+#export TFS_COMPONENTS="${TFS_COMPONENTS} e2e_orchestrator"
+
+# Uncomment to activate DLT and Interdomain
+#export TFS_COMPONENTS="${TFS_COMPONENTS} interdomain dlt"
+#if [[ "$TFS_COMPONENTS" == *"dlt"* ]]; then
+#    export KEY_DIRECTORY_PATH="src/dlt/gateway/keys/priv_sk"
+#    export CERT_DIRECTORY_PATH="src/dlt/gateway/keys/cert.pem"
+#    export TLS_CERT_PATH="src/dlt/gateway/keys/ca.crt"
+#fi
+
+# Uncomment to activate QKD App
+#   To manage QKD Apps, "service" requires "qkd_app" to be deployed
+#   before "service", thus we "hack" the TFS_COMPONENTS environment variable prepending the
+#   "qkd_app" only if "service" is already in TFS_COMPONENTS, and re-export it.
+#if [[ "$TFS_COMPONENTS" == *"service"* ]]; then
+#    BEFORE="${TFS_COMPONENTS% service*}"
+#    AFTER="${TFS_COMPONENTS#* service}"
+#    export TFS_COMPONENTS="${BEFORE} qkd_app service ${AFTER}"
+#fi
+
+
+# Set the tag you want to use for your images.
+export TFS_IMAGE_TAG="dev"
+
+# Set the name of the Kubernetes namespace to deploy TFS to.
+export TFS_K8S_NAMESPACE="tfs"
+
+# Set additional manifest files to be applied after the deployment
+export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml"
+
+# Uncomment to monitor performance of components
+#export TFS_EXTRA_MANIFESTS="${TFS_EXTRA_MANIFESTS} manifests/servicemonitors.yaml"
+
+# Uncomment when deploying Optical CyberSecurity
+#export TFS_EXTRA_MANIFESTS="${TFS_EXTRA_MANIFESTS} manifests/cachingservice.yaml"
+
+# Set the new Grafana admin password
+export TFS_GRAFANA_PASSWORD="admin123+"
+
+# Disable skip-build flag to rebuild the Docker images.
+export TFS_SKIP_BUILD=""
+
+
+# ----- CockroachDB ------------------------------------------------------------
+
+# Set the namespace where CockroackDB will be deployed.
+export CRDB_NAMESPACE="crdb"
+
+# Set the external port CockroackDB Postgre SQL interface will be exposed to.
+export CRDB_EXT_PORT_SQL="26257"
+
+# Set the external port CockroackDB HTTP Mgmt GUI interface will be exposed to.
+export CRDB_EXT_PORT_HTTP="8081"
+
+# Set the database username to be used by Context.
+export CRDB_USERNAME="tfs"
+
+# Set the database user's password to be used by Context.
+export CRDB_PASSWORD="tfs123"
+
+# Set the database name to be used by Context.
+export CRDB_DATABASE="tfs"
+
+# Set CockroachDB installation mode to 'single'. This option is convenient for development and testing.
+# See ./deploy/all.sh or ./deploy/crdb.sh for additional details
+export CRDB_DEPLOY_MODE="single"
+
+# Disable flag for dropping database, if it exists.
+export CRDB_DROP_DATABASE_IF_EXISTS="YES"
+
+# Disable flag for re-deploying CockroachDB from scratch.
+export CRDB_REDEPLOY=""
+
+
+# ----- NATS -------------------------------------------------------------------
+
+# Set the namespace where NATS will be deployed.
+export NATS_NAMESPACE="nats"
+
+# Set the external port NATS Client interface will be exposed to.
+export NATS_EXT_PORT_CLIENT="4222"
+
+# Set the external port NATS HTTP Mgmt GUI interface will be exposed to.
+export NATS_EXT_PORT_HTTP="8222"
+
+# Set NATS installation mode to 'single'. This option is convenient for development and testing.
+# See ./deploy/all.sh or ./deploy/nats.sh for additional details
+export NATS_DEPLOY_MODE="single"
+
+# Disable flag for re-deploying NATS from scratch.
+export NATS_REDEPLOY=""
+
+
+# ----- QuestDB ----------------------------------------------------------------
+
+# Set the namespace where QuestDB will be deployed.
+export QDB_NAMESPACE="qdb"
+
+# Set the external port QuestDB Postgre SQL interface will be exposed to.
+export QDB_EXT_PORT_SQL="8812"
+
+# Set the external port QuestDB Influx Line Protocol interface will be exposed to.
+export QDB_EXT_PORT_ILP="9009"
+
+# Set the external port QuestDB HTTP Mgmt GUI interface will be exposed to.
+export QDB_EXT_PORT_HTTP="9000"
+
+# Set the database username to be used for QuestDB.
+export QDB_USERNAME="admin"
+
+# Set the database user's password to be used for QuestDB.
+export QDB_PASSWORD="quest"
+
+# Set the table name to be used by Monitoring for KPIs.
+export QDB_TABLE_MONITORING_KPIS="tfs_monitoring_kpis"
+
+# Set the table name to be used by Slice for plotting groups.
+export QDB_TABLE_SLICE_GROUPS="tfs_slice_groups"
+
+# Disable flag for dropping tables if they exist.
+export QDB_DROP_TABLES_IF_EXIST="YES"
+
+# Disable flag for re-deploying QuestDB from scratch.
+export QDB_REDEPLOY=""
+
+
+# ----- K8s Observability ------------------------------------------------------
+
+# Set the external port Prometheus Mgmt HTTP GUI interface will be exposed to.
+export PROM_EXT_PORT_HTTP="9090"
+
+# Set the external port Grafana HTTP Dashboards will be exposed to.
+export GRAF_EXT_PORT_HTTP="3000"
+
+
+# ----- Apache Kafka -----------------------------------------------------------
+
+# Set the namespace where Apache Kafka will be deployed.
+export KFK_NAMESPACE="kafka"
+
+# Set the port Apache Kafka server will be exposed to.
+export KFK_SERVER_PORT="9092"
+
+# Set the flag to YES for redeploying of Apache Kafka
+export KFK_REDEPLOY=""
diff --git a/src/tests/eucnc24/redeploy-tfs.sh b/src/tests/eucnc24/redeploy-tfs.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b5ced0d12e026be4b9cb7eefcf343445b776f042
--- /dev/null
+++ b/src/tests/eucnc24/redeploy-tfs.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# 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.
+
+source ~/tfs-ctrl/src/tests/eucnc24/deploy_specs.sh
+./deploy/all.sh
diff --git a/src/tests/eucnc24/requirements.in b/src/tests/eucnc24/requirements.in
new file mode 100644
index 0000000000000000000000000000000000000000..468af1a17931d6e545647e3e7a057433d74826b3
--- /dev/null
+++ b/src/tests/eucnc24/requirements.in
@@ -0,0 +1,15 @@
+# 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.
+
+requests==2.27.*
diff --git a/src/tests/eucnc24/scripts/run-cleanup.sh b/src/tests/eucnc24/scripts/run-cleanup.sh
new file mode 100755
index 0000000000000000000000000000000000000000..3f697711a48f8d7fdf9fbd84d8100013ca349272
--- /dev/null
+++ b/src/tests/eucnc24/scripts/run-cleanup.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# 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.
+
+source /var/teraflow/tfs_runtime_env_vars.sh
+export PYTHONPATH=/var/teraflow
+pytest --verbose --log-level=INFO \
+    --junitxml=/opt/results/report_cleanup.xml \
+    /var/teraflow/tests/eucnc24/tests/test_cleanup.py
diff --git a/src/tests/eucnc24/scripts/run-onboarding.sh b/src/tests/eucnc24/scripts/run-onboarding.sh
new file mode 100755
index 0000000000000000000000000000000000000000..57fc435e417e02edca08ff92d5db03bf9332c0e0
--- /dev/null
+++ b/src/tests/eucnc24/scripts/run-onboarding.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# 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.
+
+source /var/teraflow/tfs_runtime_env_vars.sh
+export PYTHONPATH=/var/teraflow
+pytest --verbose --log-level=INFO \
+    --junitxml=/opt/results/report_onboarding.xml \
+    /var/teraflow/tests/eucnc24/tests/test_onboarding.py
diff --git a/src/tests/eucnc24/scripts/run-service-ietf-create.sh b/src/tests/eucnc24/scripts/run-service-ietf-create.sh
new file mode 100755
index 0000000000000000000000000000000000000000..d2ec9eef51a1dbe311ddbc052d305ef0d8c92085
--- /dev/null
+++ b/src/tests/eucnc24/scripts/run-service-ietf-create.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# 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.
+
+source /var/teraflow/tfs_runtime_env_vars.sh
+export PYTHONPATH=/var/teraflow
+pytest --verbose --log-level=INFO \
+    --junitxml=/opt/results/report_service_ietf_create.xml \
+    /var/teraflow/tests/eucnc24/tests/test_service_ietf_create.py
diff --git a/src/tests/eucnc24/scripts/run-service-ietf-remove.sh b/src/tests/eucnc24/scripts/run-service-ietf-remove.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8c52636001fb8163b3a94fa0b229c7ab1264ab13
--- /dev/null
+++ b/src/tests/eucnc24/scripts/run-service-ietf-remove.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# 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.
+
+source /var/teraflow/tfs_runtime_env_vars.sh
+export PYTHONPATH=/var/teraflow
+pytest --verbose --log-level=INFO \
+    --junitxml=/opt/results/report_service_ietf_remove.xml \
+    /var/teraflow/tests/eucnc24/tests/test_service_ietf_remove.py
diff --git a/src/tests/eucnc24/scripts/run-service-tfs-create.sh b/src/tests/eucnc24/scripts/run-service-tfs-create.sh
new file mode 100755
index 0000000000000000000000000000000000000000..5395f38b3ab82a11361a066f2d80b750e636b010
--- /dev/null
+++ b/src/tests/eucnc24/scripts/run-service-tfs-create.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# 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.
+
+source /var/teraflow/tfs_runtime_env_vars.sh
+export PYTHONPATH=/var/teraflow
+pytest --verbose --log-level=INFO \
+    --junitxml=/opt/results/report_service_tfs_create.xml \
+    /var/teraflow/tests/eucnc24/tests/test_service_tfs_create.py
diff --git a/src/tests/eucnc24/scripts/run-service-tfs-remove.sh b/src/tests/eucnc24/scripts/run-service-tfs-remove.sh
new file mode 100755
index 0000000000000000000000000000000000000000..d82d6d7738c24039fc4b8e878f48bb3c0c90f3fe
--- /dev/null
+++ b/src/tests/eucnc24/scripts/run-service-tfs-remove.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# 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.
+
+source /var/teraflow/tfs_runtime_env_vars.sh
+export PYTHONPATH=/var/teraflow
+pytest --verbose --log-level=INFO \
+    --junitxml=/opt/results/report_service_tfs_remove.xml \
+    /var/teraflow/tests/eucnc24/tests/test_service_tfs_remove.py
diff --git a/src/tests/eucnc24/tests/Fixtures.py b/src/tests/eucnc24/tests/Fixtures.py
new file mode 100644
index 0000000000000000000000000000000000000000..a9d2ceb24488dbd5b3775c958358df419dec4172
--- /dev/null
+++ b/src/tests/eucnc24/tests/Fixtures.py
@@ -0,0 +1,43 @@
+# 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 pytest
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+from monitoring.client.MonitoringClient import MonitoringClient
+from service.client.ServiceClient import ServiceClient
+
+@pytest.fixture(scope='session')
+def context_client():
+    _client = ContextClient()
+    yield _client
+    _client.close()
+
+@pytest.fixture(scope='session')
+def device_client():
+    _client = DeviceClient()
+    yield _client
+    _client.close()
+
+@pytest.fixture(scope='session')
+def monitoring_client():
+    _client = MonitoringClient()
+    yield _client
+    _client.close()
+
+@pytest.fixture(scope='session')
+def service_client():
+    _client = ServiceClient()
+    yield _client
+    _client.close()
diff --git a/src/tests/eucnc24/tests/Tools.py b/src/tests/eucnc24/tests/Tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..e983ffefff3d5aea6b078efa9bb586202957a5e1
--- /dev/null
+++ b/src/tests/eucnc24/tests/Tools.py
@@ -0,0 +1,109 @@
+# 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 enum, logging, requests
+from typing import Any, Dict, List, Optional, Set, Union
+from common.Constants import ServiceNameEnum
+from common.Settings import get_service_host, get_service_port_http
+
+NBI_ADDRESS  = get_service_host(ServiceNameEnum.NBI)
+NBI_PORT     = get_service_port_http(ServiceNameEnum.NBI)
+NBI_USERNAME = 'admin'
+NBI_PASSWORD = 'admin'
+NBI_BASE_URL = ''
+
+class RestRequestMethod(enum.Enum):
+    GET    = 'get'
+    POST   = 'post'
+    PUT    = 'put'
+    PATCH  = 'patch'
+    DELETE = 'delete'
+
+EXPECTED_STATUS_CODES : Set[int] = {
+    requests.codes['OK'        ],
+    requests.codes['CREATED'   ],
+    requests.codes['ACCEPTED'  ],
+    requests.codes['NO_CONTENT'],
+}
+
+def do_rest_request(
+    method : RestRequestMethod, url : str, body : Optional[Any] = None, timeout : int = 10,
+    allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
+    logger : Optional[logging.Logger] = None
+) -> Optional[Union[Dict, List]]:
+    request_url = 'http://{:s}:{:s}@{:s}:{:d}{:s}{:s}'.format(
+        NBI_USERNAME, NBI_PASSWORD, NBI_ADDRESS, NBI_PORT, str(NBI_BASE_URL), url
+    )
+
+    if logger is not None:
+        msg = 'Request: {:s} {:s}'.format(str(method.value).upper(), str(request_url))
+        if body is not None: msg += ' body={:s}'.format(str(body))
+        logger.warning(msg)
+    reply = requests.request(method.value, request_url, timeout=timeout, json=body, allow_redirects=allow_redirects)
+    if logger is not None:
+        logger.warning('Reply: {:s}'.format(str(reply.text)))
+    assert reply.status_code in expected_status_codes, 'Reply failed with status code {:d}'.format(reply.status_code)
+
+    if reply.content and len(reply.content) > 0: return reply.json()
+    return None
+
+def do_rest_get_request(
+    url : str, body : Optional[Any] = None, timeout : int = 10,
+    allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
+    logger : Optional[logging.Logger] = None
+) -> Optional[Union[Dict, List]]:
+    return do_rest_request(
+        RestRequestMethod.GET, url, body=body, timeout=timeout, allow_redirects=allow_redirects,
+        expected_status_codes=expected_status_codes, logger=logger
+    )
+
+def do_rest_post_request(
+    url : str, body : Optional[Any] = None, timeout : int = 10,
+    allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
+    logger : Optional[logging.Logger] = None
+) -> Optional[Union[Dict, List]]:
+    return do_rest_request(
+        RestRequestMethod.POST, url, body=body, timeout=timeout, allow_redirects=allow_redirects,
+        expected_status_codes=expected_status_codes, logger=logger
+    )
+
+def do_rest_put_request(
+    url : str, body : Optional[Any] = None, timeout : int = 10,
+    allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
+    logger : Optional[logging.Logger] = None
+) -> Optional[Union[Dict, List]]:
+    return do_rest_request(
+        RestRequestMethod.PUT, url, body=body, timeout=timeout, allow_redirects=allow_redirects,
+        expected_status_codes=expected_status_codes, logger=logger
+    )
+
+def do_rest_patch_request(
+    url : str, body : Optional[Any] = None, timeout : int = 10,
+    allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
+    logger : Optional[logging.Logger] = None
+) -> Optional[Union[Dict, List]]:
+    return do_rest_request(
+        RestRequestMethod.PATCH, url, body=body, timeout=timeout, allow_redirects=allow_redirects,
+        expected_status_codes=expected_status_codes, logger=logger
+    )
+
+def do_rest_delete_request(
+    url : str, body : Optional[Any] = None, timeout : int = 10,
+    allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
+    logger : Optional[logging.Logger] = None
+) -> Optional[Union[Dict, List]]:
+    return do_rest_request(
+        RestRequestMethod.DELETE, url, body=body, timeout=timeout, allow_redirects=allow_redirects,
+        expected_status_codes=expected_status_codes, logger=logger
+    )
diff --git a/src/tests/eucnc24/tests/__init__.py b/src/tests/eucnc24/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ee6f7071f145e06c3aeaefc09a43ccd88e619e3
--- /dev/null
+++ b/src/tests/eucnc24/tests/__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/tests/eucnc24/tests/test_cleanup.py b/src/tests/eucnc24/tests/test_cleanup.py
new file mode 100644
index 0000000000000000000000000000000000000000..7cfed0caf295af9dd5f66fd263339e37a7c887a0
--- /dev/null
+++ b/src/tests/eucnc24/tests/test_cleanup.py
@@ -0,0 +1,44 @@
+# 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 logging, os
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId
+from common.tools.descriptor.Loader import DescriptorLoader, validate_empty_scenario
+from common.tools.object_factory.Context import json_context_id
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+from .Fixtures import context_client, device_client    # pylint: disable=unused-import
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'tfs-topology.json')
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+def test_scenario_cleanup(
+    context_client : ContextClient, # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,   # pylint: disable=redefined-outer-name
+) -> None:
+    # Verify the scenario has no services/slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 0
+    assert len(response.slice_ids) == 0
+
+    # Load descriptors and validate the base scenario
+    descriptor_loader = DescriptorLoader(
+        descriptors_file=DESCRIPTOR_FILE, context_client=context_client, device_client=device_client)
+    descriptor_loader.validate()
+    descriptor_loader.unload()
+    validate_empty_scenario(context_client)
diff --git a/src/tests/eucnc24/tests/test_onboarding.py b/src/tests/eucnc24/tests/test_onboarding.py
new file mode 100644
index 0000000000000000000000000000000000000000..93f040877a4d0c40e2a9d832872e78c75688cffb
--- /dev/null
+++ b/src/tests/eucnc24/tests/test_onboarding.py
@@ -0,0 +1,67 @@
+# 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 logging, os, time
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId, DeviceOperationalStatusEnum, Empty
+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 device.client.DeviceClient import DeviceClient
+from .Fixtures import context_client, device_client # pylint: disable=unused-import
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'tfs-topology.json')
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+def test_scenario_onboarding(
+    context_client : ContextClient, # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,   # pylint: disable=redefined-outer-name
+) -> None:
+    validate_empty_scenario(context_client)
+
+    descriptor_loader = DescriptorLoader(
+        descriptors_file=DESCRIPTOR_FILE, context_client=context_client, device_client=device_client)
+    results = descriptor_loader.process()
+    check_descriptor_load_results(results, descriptor_loader)
+    descriptor_loader.validate()
+
+    # Verify the scenario has no services/slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 0
+    assert len(response.slice_ids) == 0
+
+def test_scenario_devices_enabled(
+    context_client : ContextClient,         # pylint: disable=redefined-outer-name
+) -> None:
+    """
+    This test validates that the devices are enabled.
+    """
+    DEVICE_OP_STATUS_ENABLED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
+
+    num_devices = -1
+    num_devices_enabled, num_retry = 0, 0
+    while (num_devices != num_devices_enabled) and (num_retry < 10):
+        time.sleep(1.0)
+        response = context_client.ListDevices(Empty())
+        num_devices = len(response.devices)
+        num_devices_enabled = 0
+        for device in response.devices:
+            if device.device_operational_status != DEVICE_OP_STATUS_ENABLED: continue
+            num_devices_enabled += 1
+        LOGGER.info('Num Devices enabled: {:d}/{:d}'.format(num_devices_enabled, num_devices))
+        num_retry += 1
+    assert num_devices_enabled == num_devices
diff --git a/src/tests/eucnc24/tests/test_service_ietf_create.py b/src/tests/eucnc24/tests/test_service_ietf_create.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0785c21a332ddf03021644bc4b415ba86027412
--- /dev/null
+++ b/src/tests/eucnc24/tests/test_service_ietf_create.py
@@ -0,0 +1,71 @@
+# 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, os
+from typing import Dict
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId, ServiceStatusEnum, ServiceTypeEnum
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from common.tools.object_factory.Context import json_context_id
+from context.client.ContextClient import ContextClient
+from .Fixtures import context_client        # pylint: disable=unused-import
+from .Tools import do_rest_get_request, do_rest_post_request
+
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+REQUEST_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'ietf-l3vpn-service.json')
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+
+# pylint: disable=redefined-outer-name, unused-argument
+def test_service_ietf_creation(
+    context_client : ContextClient,
+):
+    # Issue service creation request
+    with open(REQUEST_FILE, 'r', encoding='UTF-8') as f:
+        svc1_data = json.load(f)
+    URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services'
+    do_rest_post_request(URL, body=svc1_data, logger=LOGGER, expected_status_codes={201})
+    vpn_id = svc1_data['ietf-l3vpn-svc:l3vpn-svc']['vpn-services']['vpn-service'][0]['vpn-id']
+
+    URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services/vpn-service={:s}/'.format(vpn_id)
+    service_data = do_rest_get_request(URL, logger=LOGGER, expected_status_codes={200})
+    service_uuid = service_data['service-id']
+
+    # Verify service was created
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 1
+    assert len(response.slice_ids) == 0
+
+    # Check there is 1 service
+    response = context_client.ListServices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Services[{:d}] = {:s}'.format(
+        len(response.services), grpc_message_to_json_string(response)
+    ))
+    assert len(response.services) == 1
+
+    for service in response.services:
+        service_id = service.service_id
+        assert service_id.service_uuid.uuid == service_uuid
+        assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE
+        assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM
+
+        response = context_client.ListConnections(service_id)
+        LOGGER.warning('  ServiceId[{:s}] => Connections[{:d}] = {:s}'.format(
+            grpc_message_to_json_string(service_id), len(response.connections),
+            grpc_message_to_json_string(response)
+        ))
+        assert len(response.connections) == 1
diff --git a/src/tests/eucnc24/tests/test_service_ietf_remove.py b/src/tests/eucnc24/tests/test_service_ietf_remove.py
new file mode 100644
index 0000000000000000000000000000000000000000..f64fc07bfd82c4bd2e50f6a3184f83635cc89cc5
--- /dev/null
+++ b/src/tests/eucnc24/tests/test_service_ietf_remove.py
@@ -0,0 +1,77 @@
+# 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 logging, os
+from typing import Dict, Set, Tuple
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId, ServiceStatusEnum, ServiceTypeEnum
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from common.tools.object_factory.Context import json_context_id
+from context.client.ContextClient import ContextClient
+from .Fixtures import context_client        # pylint: disable=unused-import
+from .Tools import do_rest_delete_request
+
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+REQUEST_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'ietf-l3vpn-service.json')
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+
+# pylint: disable=redefined-outer-name, unused-argument
+def test_service_ietf_removal(
+    context_client : ContextClient, # pylint: disable=redefined-outer-name
+):
+    # Verify the scenario has 1 service and 0 slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 1
+    assert len(response.slice_ids) == 0
+
+    # Check there are no slices
+    response = context_client.ListSlices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Slices[{:d}] = {:s}'.format(len(response.slices), grpc_message_to_json_string(response)))
+    assert len(response.slices) == 0
+
+    # Check there is 1 service
+    response = context_client.ListServices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response)))
+    assert len(response.services) == 1
+
+    service_uuids : Set[str] = set()
+    for service in response.services:
+        service_id = service.service_id
+        assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE
+        assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM
+
+        response = context_client.ListConnections(service_id)
+        LOGGER.warning('  ServiceId[{:s}] => Connections[{:d}] = {:s}'.format(
+            grpc_message_to_json_string(service_id), len(response.connections),
+            grpc_message_to_json_string(response)
+        ))
+        assert len(response.connections) == 1
+
+        service_uuids.add(service_id.service_uuid.uuid)
+
+    # Identify service to delete
+    assert len(service_uuids) == 1
+    service_uuid = set(service_uuids).pop()
+
+    URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services/vpn-service={:s}/'.format(service_uuid)
+    do_rest_delete_request(URL, logger=LOGGER, expected_status_codes={204})
+
+    # Verify the scenario has no services/slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 0
+    assert len(response.slice_ids) == 0
diff --git a/src/tests/eucnc24/tests/test_service_tfs_create.py b/src/tests/eucnc24/tests/test_service_tfs_create.py
new file mode 100644
index 0000000000000000000000000000000000000000..6e0492f86f21b02c7f047d84c2db49d342710ac7
--- /dev/null
+++ b/src/tests/eucnc24/tests/test_service_tfs_create.py
@@ -0,0 +1,76 @@
+# 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 logging, os
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId, ServiceStatusEnum, ServiceTypeEnum
+from common.tools.descriptor.Loader import DescriptorLoader, check_descriptor_load_results
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from common.tools.object_factory.Context import json_context_id
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+from service.client.ServiceClient import ServiceClient
+from .Fixtures import context_client, device_client, service_client        # pylint: disable=unused-import
+
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'tfs-service.json')
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+
+def test_service_tfs_creation(
+    context_client : ContextClient, # pylint: disable=redefined-outer-name
+    device_client  : DeviceClient,  # pylint: disable=redefined-outer-name
+    service_client : ServiceClient, # pylint: disable=redefined-outer-name
+):
+    # Load descriptors and validate the base scenario
+    descriptor_loader = DescriptorLoader(
+        descriptors_file=DESCRIPTOR_FILE, context_client=context_client,
+        device_client=device_client, service_client=service_client
+    )
+    results = descriptor_loader.process()
+    check_descriptor_load_results(results, descriptor_loader)
+
+    # Verify the scenario has 1 service and 0 slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 1
+    assert len(response.slice_ids) == 0
+
+    # Check there are no slices
+    response = context_client.ListSlices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Slices[{:d}] = {:s}'.format(
+        len(response.slices), grpc_message_to_json_string(response)
+    ))
+    assert len(response.slices) == 0
+
+    # Check there is 1 service
+    response = context_client.ListServices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Services[{:d}] = {:s}'.format(
+        len(response.services), grpc_message_to_json_string(response)
+    ))
+    assert len(response.services) == 1
+
+    for service in response.services:
+        service_id = service.service_id
+        assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE
+        assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM
+
+        response = context_client.ListConnections(service_id)
+        LOGGER.warning('  ServiceId[{:s}] => Connections[{:d}] = {:s}'.format(
+            grpc_message_to_json_string(service_id), len(response.connections),
+            grpc_message_to_json_string(response)
+        ))
+        assert len(response.connections) == 1
diff --git a/src/tests/eucnc24/tests/test_service_tfs_remove.py b/src/tests/eucnc24/tests/test_service_tfs_remove.py
new file mode 100644
index 0000000000000000000000000000000000000000..76fdf0fc7407ce86bbd87806932eb1a4a45c40d1
--- /dev/null
+++ b/src/tests/eucnc24/tests/test_service_tfs_remove.py
@@ -0,0 +1,80 @@
+# 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 logging, os
+from typing import Set, Tuple
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId, ServiceId, ServiceStatusEnum, ServiceTypeEnum
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from common.tools.object_factory.Context import json_context_id
+from common.tools.object_factory.Service import json_service_id
+from context.client.ContextClient import ContextClient
+from service.client.ServiceClient import ServiceClient
+from .Fixtures import context_client, service_client        # pylint: disable=unused-import
+
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'tfs-service.json')
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+
+def test_service_tfs_removal(
+    context_client : ContextClient, # pylint: disable=redefined-outer-name
+    service_client : ServiceClient, # pylint: disable=redefined-outer-name
+):
+    # Verify the scenario has 1 service and 0 slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 1
+    assert len(response.slice_ids) == 0
+
+    # Check there are no slices
+    response = context_client.ListSlices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Slices[{:d}] = {:s}'.format(len(response.slices), grpc_message_to_json_string(response)))
+    assert len(response.slices) == 0
+
+    # Check there is 1 service
+    response = context_client.ListServices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response)))
+    assert len(response.services) == 1
+
+    context_service_uuids : Set[Tuple[str, str]] = set()
+    for service in response.services:
+        service_id = service.service_id
+        assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE
+        assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM
+
+        response = context_client.ListConnections(service_id)
+        LOGGER.warning('  ServiceId[{:s}] => Connections[{:d}] = {:s}'.format(
+            grpc_message_to_json_string(service_id), len(response.connections),
+            grpc_message_to_json_string(response)
+        ))
+        assert len(response.connections) == 1
+
+        context_uuid = service_id.context_id.context_uuid.uuid
+        service_uuid = service_id.service_uuid.uuid
+        context_service_uuids.add((context_uuid, service_uuid))
+
+    # Identify service to delete
+    assert len(context_service_uuids) == 1
+    context_uuid, service_uuid = set(context_service_uuids).pop()
+
+    # Delete Service
+    service_client.DeleteService(ServiceId(**json_service_id(service_uuid, json_context_id(context_uuid))))
+
+    # Verify the scenario has no services/slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 0
+    assert len(response.slice_ids) == 0
diff --git a/src/tests/ofc24/.gitlab-ci.yml b/src/tests/ofc24/.gitlab-ci.yml
index d7bda488689abe88b8abba9a054307fcf377af46..af4e1aaa6b98beb21a85a4746f61cf9d4916dba7 100644
--- a/src/tests/ofc24/.gitlab-ci.yml
+++ b/src/tests/ofc24/.gitlab-ci.yml
@@ -138,6 +138,7 @@ end2end_test ofc24:
     - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/serviceservice -c server
     - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/sliceservice -c server
     - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/nbiservice -c server
+    - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/webuiservice -c server
     - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/opticalcontrollerservice -c server
     - if docker ps -a | grep ${TEST_NAME}; then docker rm -f ${TEST_NAME}; fi
 
diff --git a/src/tests/ofc24/_old/startExtraNetConfigAgent.sh b/src/tests/ofc24/_old/startExtraNetConfigAgent.sh
index 197171d2f5e2653e9c38d51c60502984c4d0b345..706010bd11b940af276b74a8366795c6448df8b7 100755
--- a/src/tests/ofc24/_old/startExtraNetConfigAgent.sh
+++ b/src/tests/ofc24/_old/startExtraNetConfigAgent.sh
@@ -15,10 +15,14 @@
 
          
 
+docker stop na1 
+docker rm na1
+docker stop na2 
+docker rm na2
 
 
-screen -dmS t1 -T xterm sh -c "docker run -p 10.0.2.4:2023:2022 -v ~/tfs-ctrl/src/tests/ofc24/tempOC/files:/files --name na1 -it asgamb1/oc23bgp.img:latest bash"
-screen -dmS t2 -T xterm sh -c "docker run -p 10.0.2.4:2024:2022 -v ~/tfs-ctrl/src/tests/ofc24/tempOC/files:/files --name na2 -it asgamb1/oc23bgp.img:latest bash"
+screen -dmS t1 -T xterm sh -c "docker run -p 10.0.2.4:2023:2022 -v ~/tfs-ctrl/src/tests/ofc24/tempOC/files:/files --name na1 -it asgamb1/oc23bgp.img:latest sh"
+screen -dmS t2 -T xterm sh -c "docker run -p 10.0.2.4:2024:2022 -v ~/tfs-ctrl/src/tests/ofc24/tempOC/files:/files --name na2 -it asgamb1/oc23bgp.img:latest sh"
 
 
 
@@ -26,7 +30,7 @@ sleep 4
 echo "starting transponder1 "
 
 if [ "$( docker container  inspect -f '{{.State.Running}}' na1)" = "true" ]; then 
-        docker exec  na1 sh -c  " cp /files/platform_t1.xml demoECOC21.xml ; 
+        docker exec  na1 bash -c  " cp /files/platform_t1.xml demoECOC21.xml ; 
                                  /confd/examples.confd/OC23/startNetconfAgent.sh;"
        
 else 
@@ -36,7 +40,7 @@ fi
 echo "starting transponder2 "
 
 if [ "$( docker container  inspect -f '{{.State.Running}}' na2)" = "true" ]; then 
-        docker exec  na2 sh -c " cp /files/platform_t2.xml demoECOC21.xml;
+        docker exec  na2 bash -c " cp /files/platform_t2.xml demoECOC21.xml;
                                   /confd/examples.confd/OC23/startNetconfAgent.sh  "
 
 else 
diff --git a/src/tests/ofc24/descriptors/topology.json b/src/tests/ofc24/descriptors/topology.json
index 85bbad55eb8608d2d2a7abad7fffab8fffdae682..f358bf94cebc5ebe51cef25dd3816622dcdb7b64 100644
--- a/src/tests/ofc24/descriptors/topology.json
+++ b/src/tests/ofc24/descriptors/topology.json
@@ -7,144 +7,1564 @@
     ],
     "devices": [
         {
-            "device_id": {"device_uuid": {"uuid": "T1"}}, "device_type": "optical-transponder", "device_drivers": [11],
+            "device_id": {"device_uuid": {"uuid": "T1.1"}}, "device_type": "optical-transponder", "device_drivers": [11],
             "device_operational_status": 1,
-            "device_endpoints": [
-                {"endpoint_id": {
-                    "device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"},
-                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
-                }}
-            ],
             "device_config": {"config_rules": [
                 {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.101"}},
                 {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
                 {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
                     "username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
                     "look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
-                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120},
-                    "endpoints": [{"uuid": "1", "type": "optical", "sample_types": [101, 102, 201, 202]}]
+                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120}
                 }}}
             ]}
         },
         {
-            "device_id": {"device_uuid": {"uuid": "T2"}}, "device_type": "optical-transponder", "device_drivers": [11],
+            "device_id": {"device_uuid": {"uuid": "T1.2"}}, "device_type": "optical-transponder", "device_drivers": [11],
+            "device_operational_status": 1,
+            "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.101"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
+                    "username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
+                    "look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
+                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120}
+                }}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "T1.3"}}, "device_type": "optical-transponder", "device_drivers": [11],
+            "device_operational_status": 1,
+            "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.101"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
+                    "username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
+                    "look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
+                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120}
+                }}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "T2.1"}}, "device_type": "optical-transponder", "device_drivers": [11],
+            "device_operational_status": 1,
+            "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.102"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
+                    "username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
+                    "look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
+                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120}
+                }}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "T2.2"}}, "device_type": "optical-transponder", "device_drivers": [11],
+            "device_operational_status": 1,
+            "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.102"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
+                    "username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
+                    "look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
+                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120}
+                }}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "T2.3"}}, "device_type": "optical-transponder", "device_drivers": [11],
             "device_operational_status": 1,
-            "device_endpoints": [
-                {"endpoint_id": {
-                    "device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"},
-                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
-                }}
-            ],
             "device_config": {"config_rules": [
                 {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.102"}},
                 {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
                 {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
                     "username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
                     "look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
-                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120},
-                    "endpoints": [{"uuid": "6", "type": "optical", "sample_types": [101, 102, 201, 202]}]
+                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120}
                 }}}
             ]}
         },
         {
             "device_id": {"device_uuid": {"uuid": "R1"}}, "device_type": "optical-roadm", "device_drivers": [11],
             "device_operational_status": 1,
-            "device_endpoints": [
-                {"endpoint_id": {
-                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2"},
-                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
-                }},
-                {"endpoint_id": {
-                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "3"},
-                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
-                }},
-                {"endpoint_id": {
-                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "12"},
-                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
-                }},
-                {"endpoint_id": {
-                    "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "13"},
-                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
-                }}
-            ],
             "device_config": {"config_rules": [
                 {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.201"}},
                 {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
                 {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
                     "username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
-                    "look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
-                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120},
-                    "endpoints": [
-                        {"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "2"},
-                        {"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "3"},
-                        {"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "12"},
-                        {"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "13"}
-                    ]}
-                }}]
-            }
+                    "look_for_keys": false, "allow_agent": false, "commit_per_rule": false, "type": "optical-roadm",
+                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120}
+                }}}
+            ]}
         },
         {
             "device_id": {"device_uuid": {"uuid": "R2"}}, "device_type": "optical-roadm", "device_drivers": [11],
             "device_operational_status": 1,
-            "device_endpoints": [
-                {"endpoint_id": {
-                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "4"},
-                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
-                }},
-                {"endpoint_id": {
-                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "5"},
-                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
-                }},
-                {"endpoint_id": {
-                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "14"},
-                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
-                }},
-                {"endpoint_id": {
-                    "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "15"},
-                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}
-                }}
-            ],
             "device_config": {"config_rules": [
                 {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "172.254.253.202"}},
                 {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "2022"}},
                 {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {
                     "username": "admin", "password": "admin", "force_running": false, "hostkey_verify": false,
-                    "look_for_keys": false, "allow_agent": false, "commit_per_rule": false,
-                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120},
-                    "endpoints": [
-                        {"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "4"},
-                        {"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "5"},
-                        {"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "14"},
-                        {"sample_types": [101, 102, 201, 202], "type": "optical", "uuid": "15"}
-                    ]
+                    "look_for_keys": false, "allow_agent": false, "commit_per_rule": false, "type": "optical-roadm",
+                    "device_params": {"name": "default"}, "manager_params": {"timeout": 120}
                 }}}
             ]}
         }
     ],
-    "links": [
-        {"link_id": {"link_uuid": {"uuid": "T1->R1"}}, "link_endpoint_ids": [
-            {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"}},
-            {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "12"}}
-        ]},
-        {"link_id": {"link_uuid": {"uuid": "R1->T1"}}, "link_endpoint_ids": [
-            {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2"}},
-            {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"}}
-        ]},
-        {"link_id": {"link_uuid": {"uuid": "R1->R2"}}, "link_endpoint_ids": [
-            {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "3"}},
-            {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "14"}}
-        ]},
-        {"link_id": {"link_uuid": {"uuid": "R2->R1"}}, "link_endpoint_ids": [
-            {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "4"}},
-            {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "13"}}
-        ]},
-        {"link_id": {"link_uuid": {"uuid": "T2->R2"}}, "link_endpoint_ids": [
-            {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"}},
-            {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "15"}}
-        ]},
-        {"link_id": {"link_uuid": {"uuid": "R2->T2"}}, "link_endpoint_ids": [
-            {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "5"}},
-            {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"}}
-        ]}
-    ]
+    "optical_links": [
+		{
+			"name": "T1.1-R1",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "T1.1->R1"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T1.1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "1"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "12"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "1",
+				"dst_port": "12",
+				"local_peer_port": "1",
+				"remote_peer_port": "2",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "T1.2-R1",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "T1.2->R1"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T1.2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "1"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "13"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "1",
+				"dst_port": "13",
+				"local_peer_port": "1",
+				"remote_peer_port": "3",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "T1.3-R1",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "T1.3->R1"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T1.3"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "1"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "14"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "1",
+				"dst_port": "14",
+				"local_peer_port": "1",
+				"remote_peer_port": "4",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "R1-T1.1",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "R1->T1.1"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "2"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T1.1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "1"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "2",
+				"dst_port": "1",
+				"local_peer_port": "12",
+				"remote_peer_port": "1",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "R1-T1.2",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "R1->T1.2"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "3"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T1.2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "1"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "3",
+				"dst_port": "1",
+				"local_peer_port": "13",
+				"remote_peer_port": "1",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "R1-T1.3",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "R1->T1.3"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "4"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T1.3"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "1"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "4",
+				"dst_port": "1",
+				"local_peer_port": "14",
+				"remote_peer_port": "1",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "R1-R2",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "R1->R2"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "101"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "111"
+					}
+				}
+			],
+            "optical_details": {
+				"length": 0,
+				"src_port": "101",
+				"dst_port": "111",
+				"local_peer_port": "111",
+				"remote_peer_port": "101",
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "R2-R1",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "R2->R1"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "101"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "111"
+					}
+				}
+			],
+            "optical_details": {
+				"length": 0,
+				"src_port": "101",
+				"dst_port": "111",
+				"local_peer_port": "111",
+				"remote_peer_port": "101",
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "T2.1-R2",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "T2.1->R2"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T2.1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "6"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "12"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "6",
+				"dst_port": "12",
+				"local_peer_port": "6",
+				"remote_peer_port": "2",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "T2.2-R2",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "T2.2->R2"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T2.2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "6"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "13"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "6",
+				"dst_port": "13",
+				"local_peer_port": "6",
+				"remote_peer_port": "3",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "T2.3-R2",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "T2.3->R2"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T2.3"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "6"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "14"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "6",
+				"dst_port": "14",
+				"local_peer_port": "6",
+				"remote_peer_port": "4",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "R2-T2.1",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "R2->T2.1"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "2"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T2.1"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "6"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "2",
+				"dst_port": "6",
+				"local_peer_port": "12",
+				"remote_peer_port": "6",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "R2-T2.2",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "R1->T2.2"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "3"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T2.2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "6"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "3",
+				"dst_port": "6",
+				"local_peer_port": "13",
+				"remote_peer_port": "6",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		},
+		{
+			"name": "R2-T2.3",
+			"link_id": {
+				"link_uuid": {
+					"uuid": "R2->T2.3"
+				}
+			},
+			"link_endpoint_ids": [
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "R2"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "4"
+					}
+				},
+				{
+					"device_id": {
+						"device_uuid": {
+							"uuid": "T2.3"
+						}
+					},
+					"endpoint_uuid": {
+						"uuid": "6"
+					}
+				}
+			],
+			"optical_details": {
+				"length": 0,
+				"src_port": "4",
+				"dst_port": "6",
+				"local_peer_port": "14",
+				"remote_peer_port": "6",
+				"used": false,
+				"c_slots": {
+					"1": 1,
+					"2": 1,
+					"3": 1,
+					"4": 1,
+					"5": 1,
+					"6": 1,
+					"7": 1,
+					"8": 1,
+					"9": 1,
+					"10": 1,
+					"11": 1,
+					"12": 1,
+					"13": 1,
+					"14": 1,
+					"15": 1,
+					"16": 1,
+					"17": 1,
+					"18": 1,
+					"19": 1,
+					"20": 1
+				},
+				"l_slots": {
+					"101": 1,
+					"102": 1,
+					"103": 1,
+					"104": 1,
+					"105": 1,
+					"106": 1,
+					"107": 1,
+					"108": 1,
+					"109": 1,
+					"110": 1,
+					"111": 1,
+					"112": 1,
+					"113": 1,
+					"114": 1,
+					"115": 1,
+					"116": 1,
+					"117": 1,
+					"118": 1,
+					"119": 1,
+					"120": 1
+				},
+				"s_slots": {
+					"501": 1,
+					"502": 1,
+					"503": 1,
+					"504": 1,
+					"505": 1,
+					"506": 1,
+					"507": 1,
+					"508": 1,
+					"509": 1,
+					"510": 1,
+					"511": 1,
+					"512": 1,
+					"513": 1,
+					"514": 1,
+					"515": 1,
+					"516": 1,
+					"517": 1,
+					"518": 1,
+					"519": 1,
+					"520": 1
+				}
+			}
+		}
+	]
 }
diff --git a/src/tests/ofc24/get_all.sh b/src/tests/ofc24/get_all.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ceb96a34c98823e122a65b38ccef57e9ed2f1ec0
--- /dev/null
+++ b/src/tests/ofc24/get_all.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+# 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
+
+~/tfs-ctrl/src/tests/ofc24/get_bands.sh > bands.json
+~/tfs-ctrl/src/tests/ofc24/get_links.sh > links.json
+~/tfs-ctrl/src/tests/ofc24/get_lightpath.sh > lightpath.json 
diff --git a/src/tests/ofc24/get_bands.sh b/src/tests/ofc24/get_bands.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c63461e44d8363f768fa1770b88b916e4d5689f7
--- /dev/null
+++ b/src/tests/ofc24/get_bands.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+# 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
+
+ip=$(sudo kubectl get all --all-namespaces | grep service/opticalcontrollerservice | awk '{print $4}')
+echo $ip
+
+#push=$(curl -X GET "http://$ip:10060/OpticalTFS/GetTopology/admin/admin")
+
+links=$(curl -X GET "http://$ip:10060/OpticalTFS/GetOpticalBands")
+echo $links
diff --git a/src/tests/ofc24/get_lightpath.sh b/src/tests/ofc24/get_lightpath.sh
new file mode 100755
index 0000000000000000000000000000000000000000..eefd46c0ed5ee1435e3b0dc5fa601d7d4a8f9243
--- /dev/null
+++ b/src/tests/ofc24/get_lightpath.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+# 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
+
+ip=$(sudo kubectl get all --all-namespaces | grep service/opticalcontrollerservice | awk '{print $4}')
+echo $ip
+
+#push=$(curl -X GET "http://$ip:10060/OpticalTFS/GetTopology/admin/admin")
+
+links=$(curl -X GET "http://$ip:10060/OpticalTFS/GetLightpaths")
+echo $links
diff --git a/src/tests/ofc24/get_links.sh b/src/tests/ofc24/get_links.sh
new file mode 100755
index 0000000000000000000000000000000000000000..f1146b4eac873114282a58445c3aad1b33002dd9
--- /dev/null
+++ b/src/tests/ofc24/get_links.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+# 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
+
+ip=$(sudo kubectl get all --all-namespaces | grep service/opticalcontrollerservice | awk '{print $4}')
+echo $ip
+
+#push=$(curl -X GET "http://$ip:10060/OpticalTFS/GetTopology/admin/admin")
+
+links=$(curl -X GET "http://$ip:10060/OpticalTFS/GetLinks")
+echo $links
diff --git a/src/tests/ofc24/node-agents-config/platform_r1.xml b/src/tests/ofc24/node-agents-config/platform_r1.xml
index b9412d1bda3e5eafc17fc6d3233d2bcc1dffec04..c8569cfec736b6d17e76030bd13d2161c588a726 100644
--- a/src/tests/ofc24/node-agents-config/platform_r1.xml
+++ b/src/tests/ofc24/node-agents-config/platform_r1.xml
@@ -132,5 +132,122 @@
                 </property>
             </properties>
         </component>
-    </components>
-</config>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>4</name>
+            <config>
+                <name>4</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>14</name>
+            <config>
+                <name>14</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+   
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>101</name>
+            <config>
+                <name>101</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>111</name>
+            <config>
+                <name>111</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        </components>
+</config>
\ No newline at end of file
diff --git a/src/tests/ofc24/node-agents-config/platform_r2.xml b/src/tests/ofc24/node-agents-config/platform_r2.xml
index 317203483a89348c51e354a6c7973239b494f42d..608941ff47123da942df20fa8bebc42769c780e0 100644
--- a/src/tests/ofc24/node-agents-config/platform_r2.xml
+++ b/src/tests/ofc24/node-agents-config/platform_r2.xml
@@ -16,6 +16,122 @@
 
 <config xmlns="http://tail-f.com/ns/config/1.0">
     <components xmlns="http://openconfig.net/yang/platform">
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>2</name>
+            <config>
+                <name>2</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D1</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>12</name>
+            <config>
+                <name>12</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D1</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>3</name>
+            <config>
+                <name>3</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>13</name>
+            <config>
+                <name>13</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
         <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
             <name>4</name>
             <config>
@@ -40,7 +156,7 @@
                     <name>MG_ON_PORT_DEGREE</name>
                     <config>
                         <name>MG_ON_PORT_DEGREE</name>
-                        <value>D1</value>
+                        <value>D2</value>
                     </config>
                 </property>
             </properties>
@@ -69,15 +185,16 @@
                     <name>MG_ON_PORT_DEGREE</name>
                     <config>
                         <name>MG_ON_PORT_DEGREE</name>
-                        <value>D1</value>
+                        <value>D2</value>
                     </config>
                 </property>
             </properties>
         </component>
+ 
         <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
-            <name>5</name>
+            <name>101</name>
             <config>
-                <name>5</name>
+                <name>101</name>
             </config>
             <properties>
                 <property>
@@ -104,9 +221,9 @@
             </properties>
         </component>
         <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
-            <name>15</name>
+            <name>111</name>
             <config>
-                <name>15</name>
+                <name>111</name>
             </config>
             <properties>
                 <property>
@@ -132,5 +249,5 @@
                 </property>
             </properties>
         </component>
-    </components>
-</config>
+        </components>
+</config>
\ No newline at end of file
diff --git a/src/tests/ofc24/node-agents-config/transponders_x4.xml b/src/tests/ofc24/node-agents-config/transponders_x4.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fb55f02abefa6c5a444d3fecaa2ca049798f9483
--- /dev/null
+++ b/src/tests/ofc24/node-agents-config/transponders_x4.xml
@@ -0,0 +1,1039 @@
+<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <components xmlns="http://openconfig.net/yang/platform">
+        <component>
+            <name>device</name>
+            <config>
+                <name>device</name>
+            </config>
+            <state>
+				<name>MellanoxSwitch</name>
+				<mfg-name>SSSA-CNIT</mfg-name>
+				<hardware-version>1.0.0</hardware-version>
+				<firmware-version>1.0.0</firmware-version>
+				<software-version>1.0.0</software-version>
+				<serial-no>610610</serial-no>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:OPERATING_SYSTEM</type>
+			</state>
+		</component>
+		<component>
+			<name>channel-1</name>
+			<config>
+					<name>channel-1</name>
+			</config>
+			<state>
+				<name>channel-1</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-1</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-1</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-2</name>
+			<config>
+					<name>channel-2</name>
+			</config>
+			<state>
+				<name>channel-2</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-2</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-2</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-3</name>
+			<config>
+					<name>channel-3</name>
+			</config>
+			<state>
+				<name>channel-3</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-3</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-3</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-4</name>
+			<config>
+					<name>channel-4</name>
+			</config>
+			<state>
+				<name>channel-4</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-4</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-4</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+				<component>
+			<name>transceiver-1</name>
+			<config>
+				<name>transceiver-1</name>
+			</config>
+			<state>
+				<name>transceiver-1</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-1</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+			<name>transceiver-2</name>
+			<config>
+				<name>transceiver-2</name>
+			</config>
+			<state>
+				<name>transceiver-2</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-2</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+			<name>transceiver-3</name>
+			<config>
+				<name>transceiver-3</name>
+			</config>
+			<state>
+				<name>transceiver-3</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-3</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+
+		<component>
+			<name>transceiver-4</name>
+			<config>
+				<name>transceiver-4</name>
+			</config>
+			<state>
+				<name>transceiver-4</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-4</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+            <name>port-1</name>
+            <config>
+                <name>port-1</name>
+            </config>
+            <state>
+                <name>port-1</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-1</name>
+					<config>
+							<name>channel-1</name>
+					</config>
+					<state>
+							<name>channel-1</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>1</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>1</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>   
+				<component>
+            <name>port-2</name>
+            <config>
+                <name>port-2</name>
+            </config>
+            <state>
+                <name>port-2</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-2</name>
+					<config>
+							<name>channel-2</name>
+					</config>
+					<state>
+							<name>channel-2</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>2</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>2</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>
+				<component>
+            <name>port-3</name>
+            <config>
+                <name>port-3</name>
+            </config>
+            <state>
+                <name>port-3</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-3</name>
+					<config>
+							<name>channel-3</name>
+					</config>
+					<state>
+							<name>channel-3</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>3</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>3</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>   
+		<component>
+            <name>port-4</name>
+            <config>
+                <name>port-4</name>
+            </config>
+            <state>
+                <name>port-4</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-4</name>
+					<config>
+							<name>channel-4</name>
+					</config>
+					<state>
+							<name>channel-4</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>4</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>4</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>      
+	</components>
+	<terminal-device xmlns="http://openconfig.net/yang/terminal-device">
+        <logical-channels>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>1</index>
+			<config>
+				<index>1</index>
+				<description>Logical channel 1</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>1</index>
+				<description>Logical channel 1</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-1</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-1</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-1</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-1</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+		           <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>2</index>
+			<config>
+				<index>2</index>
+				<description>Logical channel 2</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>2</index>
+				<description>Logical channel 2</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-2</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-2</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-2</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-2</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>3</index>
+			<config>
+				<index>3</index>
+				<description>Logical channel 3</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>3</index>
+				<description>Logical channel 3</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-3</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-3</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-3</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-3</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>4</index>
+			<config>
+				<index>4</index>
+				<description>Logical channel 4</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>4</index>
+				<description>Logical channel 4</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-4</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-4</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-4</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-4</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+        </channel>
+	</logical-channels>
+	<operational-modes>
+       <mode>
+		<mode-id>1</mode-id>
+			<state>
+				<mode-id>1</mode-id>
+				<description>FEC1</description>
+				<vendor-id>Ericsson</vendor-id>
+			</state>
+		</mode>
+		<mode>
+		    <mode-id>2</mode-id>
+			<state>
+				<mode-id>2</mode-id>
+				<description>FEC2</description>
+				<vendor-id>Ericsson</vendor-id>
+			</state>
+		</mode>		
+    	   </operational-modes>
+	</terminal-device>
+</config>
+
diff --git a/src/tests/ofc24/node-agents-config/transponders_x4_2.xml b/src/tests/ofc24/node-agents-config/transponders_x4_2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8d10c593b3c2166b16e8ecea383dadd69c3ac067
--- /dev/null
+++ b/src/tests/ofc24/node-agents-config/transponders_x4_2.xml
@@ -0,0 +1,1039 @@
+<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <components xmlns="http://openconfig.net/yang/platform">
+        <component>
+            <name>device</name>
+            <config>
+                <name>device</name>
+            </config>
+            <state>
+				<name>MellanoxSwitch</name>
+				<mfg-name>SSSA-CNIT</mfg-name>
+				<hardware-version>1.0.0</hardware-version>
+				<firmware-version>1.0.0</firmware-version>
+				<software-version>1.0.0</software-version>
+				<serial-no>610610</serial-no>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:OPERATING_SYSTEM</type>
+			</state>
+		</component>
+		<component>
+			<name>channel-5</name>
+			<config>
+					<name>channel-5</name>
+			</config>
+			<state>
+				<name>channel-5</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-5</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-5</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-6</name>
+			<config>
+					<name>channel-6</name>
+			</config>
+			<state>
+				<name>channel-6</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-6</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-6</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-7</name>
+			<config>
+					<name>channel-7</name>
+			</config>
+			<state>
+				<name>channel-7</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-7</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-7</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-8</name>
+			<config>
+					<name>channel-8</name>
+			</config>
+			<state>
+				<name>channel-8</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-8</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-8</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+				<component>
+			<name>transceiver-5</name>
+			<config>
+				<name>transceiver-5</name>
+			</config>
+			<state>
+				<name>transceiver-5</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-5</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+			<name>transceiver-6</name>
+			<config>
+				<name>transceiver-6</name>
+			</config>
+			<state>
+				<name>transceiver-6</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-6</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+			<name>transceiver-7</name>
+			<config>
+				<name>transceiver-7</name>
+			</config>
+			<state>
+				<name>transceiver-7</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-7</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+
+		<component>
+			<name>transceiver-8</name>
+			<config>
+				<name>transceiver-8</name>
+			</config>
+			<state>
+				<name>transceiver-8</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-8</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+            <name>port-5</name>
+            <config>
+                <name>port-5</name>
+            </config>
+            <state>
+                <name>port-5</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-5</name>
+					<config>
+							<name>channel-5</name>
+					</config>
+					<state>
+							<name>channel-5</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>5</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>5</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>   
+				<component>
+            <name>port-6</name>
+            <config>
+                <name>port-6</name>
+            </config>
+            <state>
+                <name>port-6</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-6</name>
+					<config>
+							<name>channel-6</name>
+					</config>
+					<state>
+							<name>channel-6</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>6</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>6</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>
+				<component>
+            <name>port-7</name>
+            <config>
+                <name>port-7</name>
+            </config>
+            <state>
+                <name>port-7</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-7</name>
+					<config>
+							<name>channel-7</name>
+					</config>
+					<state>
+							<name>channel-7</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>7</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>7</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>   
+		<component>
+            <name>port-8</name>
+            <config>
+                <name>port-8</name>
+            </config>
+            <state>
+                <name>port-8</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-8</name>
+					<config>
+							<name>channel-8</name>
+					</config>
+					<state>
+							<name>channel-8</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>8</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>8</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>      
+	</components>
+	<terminal-device xmlns="http://openconfig.net/yang/terminal-device">
+        <logical-channels>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>5</index>
+			<config>
+				<index>5</index>
+				<description>Logical channel 5</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>5</index>
+				<description>Logical channel 5</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-5</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-5</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-5</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-5</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+		           <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>6</index>
+			<config>
+				<index>6</index>
+				<description>Logical channel 6</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>6</index>
+				<description>Logical channel 6</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-6</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-6</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-6</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-6</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>7</index>
+			<config>
+				<index>7</index>
+				<description>Logical channel 7</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>7</index>
+				<description>Logical channel 7</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-7</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-7</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-7</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-7</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>8</index>
+			<config>
+				<index>8</index>
+				<description>Logical channel 8</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>8</index>
+				<description>Logical channel 8</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-8</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-8</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-8</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-8</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+        </channel>
+	</logical-channels>
+	<operational-modes>
+       <mode>
+		<mode-id>1</mode-id>
+			<state>
+				<mode-id>1</mode-id>
+				<description>FEC1</description>
+				<vendor-id>Ericsson</vendor-id>
+			</state>
+		</mode>
+		<mode>
+		    <mode-id>2</mode-id>
+			<state>
+				<mode-id>2</mode-id>
+				<description>FEC2</description>
+				<vendor-id>Ericsson</vendor-id>
+			</state>
+		</mode>		
+    	   </operational-modes>
+	</terminal-device>
+</config>
+
diff --git a/src/tests/ofc24/r_t.sh b/src/tests/ofc24/r_t.sh
new file mode 100755
index 0000000000000000000000000000000000000000..eef73563fbec2aa60e1133d0790e2821867fe997
--- /dev/null
+++ b/src/tests/ofc24/r_t.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+# 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
+
+
+docker stop -t 1 t1
+docker stop -t 1 na3
+docker stop -t 1 t2
+docker stop -t 1 na2
+
+docker rm t1
+docker rm na3
+
+docker rm t2
+docker rm na2
+
+screen -dmS t1 -T xterm sh -c "docker run --name t1  -p  10.0.2.4:2023:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files  -it asgamb1/oc23bgp.img:latest bash -c 'cp /files/transponders_x4.xml demoECOC21.xml ; ./startNetconfAgent.sh'"
+screen -dmS t3 -T xterm sh -c "docker run --name na3  -p  10.0.2.4:2025:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files  -it asgamb1/flexscale-node.img:latest bash -c 'cp /files/platform_r1.xml init_openconfig-platform.xml ; ./startNetconfAgent.sh'"
+screen -dmS t2 -T xterm sh -c "docker run --name t2  -p  10.0.2.4:2024:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files  -it asgamb1/oc23bgp.img:latest bash -c 'cp /files/transponders_x4_2.xml demoECOC21.xml ; ./startNetconfAgent.sh'"
+screen -dmS t4 -T xterm sh -c "docker run --name na2  -p  10.0.2.4:2026:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files  -it asgamb1/flexscale-node.img:latest bash -c 'cp /files/platform_r2.xml init_openconfig-platform.xml ; ./startNetconfAgent.sh'"
diff --git a/src/tests/ofc24/roadms.sh b/src/tests/ofc24/roadms.sh
new file mode 100644
index 0000000000000000000000000000000000000000..032615d555fce47c94a83848a9b24f0ed7ce04ae
--- /dev/null
+++ b/src/tests/ofc24/roadms.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# 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.
+
+         
+docker stop -t 1 na3
+docker stop -t 1 na4
+
+docker rm na3
+docker rm na4
+
+
+
+screen -dmS t3 -T xterm sh -c "docker run --name na3  -p  10.0.2.4:2025:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files  -it asgamb1/flexscale-node.img:latest bash -c 'cp /files/platform_r1.xml demoECOC21.xml ; ./startNetconfAgent.sh'"
+screen -dmS t4 -T xterm sh -c "docker run --name na4  -p  10.0.2.4:2026:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files  -it asgamb1/flexscale-node.img:latest bash -c 'cp /files/platform_r2.xml demoECOC21.xml ; ./startNetconfAgent.sh'"
\ No newline at end of file
diff --git a/src/tests/ofc24/run_test.sh b/src/tests/ofc24/run_test.sh
new file mode 100644
index 0000000000000000000000000000000000000000..b1cbe33c9c9169375b2f88fe5590347d85dd5552
--- /dev/null
+++ b/src/tests/ofc24/run_test.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# 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
+
+docker stop na1 
+docker rm na1
+screen -dmS t1 -T xterm sh -c "docker run -p 10.0.2.10:2023:2022 -v ~/tfs-ctrl/src/tests/ofc24/tempOC/files:/files --name na1 -it asgamb1/oc23bgp.img:latest"              
+sleep  2
+if [ "$( docker container  inspect -f '{{.State.Running}}' na1)" = "true" ]; then
+      docker exec na1 sh -c " cp /files/platform_t1.xml demoECOC21.xml ; /confd/examples.confd/OC23/startNetconfAgent.sh; "
+else
+      echo "your container is not running yet"
+fi
diff --git a/src/tests/ofc24/tempOC/files/platform_r1.xml b/src/tests/ofc24/tempOC/files/platform_r1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..02ea8feb47d4da5a4fce657837eb6e3fa749c545
--- /dev/null
+++ b/src/tests/ofc24/tempOC/files/platform_r1.xml
@@ -0,0 +1,237 @@
+<config xmlns="http://tail-f.com/ns/config/1.0">
+    <components xmlns="http://openconfig.net/yang/platform">
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>2</name>
+            <config>
+                <name>2</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D1</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>12</name>
+            <config>
+                <name>12</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D1</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>3</name>
+            <config>
+                <name>3</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>13</name>
+            <config>
+                <name>13</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>4</name>
+            <config>
+                <name>4</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>14</name>
+            <config>
+                <name>14</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+   
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>101</name>
+            <config>
+                <name>101</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>111</name>
+            <config>
+                <name>111</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        </components>
+</config>
\ No newline at end of file
diff --git a/src/tests/ofc24/tempOC/files/platform_r2.xml b/src/tests/ofc24/tempOC/files/platform_r2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..04d1d8370ffb72d74d1730094a6591115f7c7d6f
--- /dev/null
+++ b/src/tests/ofc24/tempOC/files/platform_r2.xml
@@ -0,0 +1,237 @@
+<config xmlns="http://tail-f.com/ns/config/1.0">
+    <components xmlns="http://openconfig.net/yang/platform">
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>2</name>
+            <config>
+                <name>2</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D1</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>12</name>
+            <config>
+                <name>12</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D1</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>3</name>
+            <config>
+                <name>3</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>13</name>
+            <config>
+                <name>13</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>4</name>
+            <config>
+                <name>4</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>14</name>
+            <config>
+                <name>14</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+ 
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>101</name>
+            <config>
+                <name>101</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>OUTPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>111</name>
+            <config>
+                <name>111</name>
+            </config>
+            <properties>
+                <property>
+                    <name>MG_ON_PORT_TYPE</name>
+                    <config>
+                        <name>MG_ON_PORT_TYPE</name>
+                        <value>MG_ON_OPTICAL_PORT_WAVEBAND</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DIRECTION</name>
+                    <config>
+                        <name>MG_ON_PORT_DIRECTION</name>
+                        <value>INPUT</value>
+                    </config>
+                </property>
+                <property>
+                    <name>MG_ON_PORT_DEGREE</name>
+                    <config>
+                        <name>MG_ON_PORT_DEGREE</name>
+                        <value>D2</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        </components>
+</config>
\ No newline at end of file
diff --git a/src/tests/ofc24/tempOC/files/platform_t1.xml b/src/tests/ofc24/tempOC/files/platform_t1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..09f316211dcd5fce4a31de45065bddb276c5b268
--- /dev/null
+++ b/src/tests/ofc24/tempOC/files/platform_t1.xml
@@ -0,0 +1,295 @@
+<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
+	<components xmlns="http://openconfig.net/yang/platform">
+		<component>
+			<name>device</name>
+			<config>
+				<name>device</name>
+			</config>
+			<state>
+				<name>MellanoxSwitch</name>
+				<mfg-name>SSSA-CNIT</mfg-name>
+				<hardware-version>1.0.0</hardware-version>
+				<firmware-version>1.0.0</firmware-version>
+				<software-version>1.0.0</software-version>
+				<serial-no>610610</serial-no>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:OPERATING_SYSTEM</type>
+			</state>
+		</component>
+		<component>
+			<name>channel-1</name>
+			<config>
+				<name>channel-1</name>
+			</config>
+			<state>
+				<name>channel-1</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-1</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-1</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>transceiver-1</name>
+			<config>
+				<name>transceiver-1</name>
+			</config>
+			<state>
+				<name>transceiver-1</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-1</associated-optical-channel>
+						</config>
+						<!--state>
+							<index>1</index>
+							<associated-optical-channel>channel-4</associated-optical-channel>
+						</state-->
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+			<name>port-1</name>
+			<config>
+				<name>port-1</name>
+			</config>
+			<state>
+				<name>port-1</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+			</state>
+			<subcomponents>
+				<subcomponent>
+					<name>channel-1</name>
+					<config>
+						<name>channel-1</name>
+					</config>
+					<state>
+						<name>channel-1</name>
+					</state>
+				</subcomponent>
+			</subcomponents>
+			<properties>
+				<property>
+					<name>onos-index</name>
+					<config>
+						<name>onos-index</name>
+						<value>4</value>
+					</config>
+					<state>
+						<name>onos-index</name>
+						<value>4</value>
+					</state>
+				</property>
+				<property>
+					<name>odtn-port-type</name>
+					<config>
+						<name>odtn-port-type</name>
+						<value>line</value>
+					</config>
+					<state>
+						<name>odtn-port-type</name>
+						<value>line</value>
+					</state>
+				</property>
+			</properties>
+		</component>
+	</components>
+	<terminal-device xmlns="http://openconfig.net/yang/terminal-device">
+		<logical-channels>
+			<!--Description: Optical logical link-->
+			<channel>
+
+				<!--Description: Line (OTN) Port-->
+				<index>1</index>
+				<config>
+					<index>1</index>
+					<description>Logical channel 1</description>
+					<admin-state>DISABLED</admin-state>
+					<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+					<loopback-mode>NONE</loopback-mode>
+				</config>
+				<state>
+					<index>1</index>
+					<description>Logical channel 1</description>
+					<admin-state>DISABLED</admin-state>
+					<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+					<loopback-mode>NONE</loopback-mode>
+					<link-state>UP</link-state>
+				</state>
+				<ingress>
+					<config>
+						<transceiver>transceiver-1</transceiver>
+					</config>
+					<state>
+						<transceiver>transceiver-1</transceiver>
+					</state>
+				</ingress>
+				<otn>
+					<config>
+						<tti-msg-expected>test1</tti-msg-expected>
+						<tti-msg-transmit>test1</tti-msg-transmit>
+					</config>
+					<state>
+						<tti-msg-expected>test1</tti-msg-expected>
+						<tti-msg-transmit>test1</tti-msg-transmit>
+						<tti-msg-auto>0</tti-msg-auto>
+						<tti-msg-recv>0</tti-msg-recv>
+						<rdi-msg>0</rdi-msg>
+						<errored-seconds>0</errored-seconds>
+						<severely-errored-seconds>0</severely-errored-seconds>
+						<unavailable-seconds>0</unavailable-seconds>
+						<code-violations>0</code-violations>
+						<fec-uncorrectable-words>0</fec-uncorrectable-words>
+						<fec-corrected-bytes>0</fec-corrected-bytes>
+						<fec-corrected-bits>0</fec-corrected-bits>
+						<background-block-errors>0</background-block-errors>
+						<pre-fec-ber>
+							<instant>0.0</instant>
+							<avg>0.0</avg>
+							<min>0.0</min>
+							<max>0.0</max>
+						</pre-fec-ber>
+						<post-fec-ber>
+							<instant>0.0</instant>
+							<avg>0.0</avg>
+							<min>0.0</min>
+							<max>0.0</max>
+						</post-fec-ber>
+						<q-value>
+							<instant>0.0</instant>
+							<avg>0.0</avg>
+							<min>0.0</min>
+							<max>0.0</max>
+							<interval>0</interval>
+						</q-value>
+						<esnr>
+							<instant>0.0</instant>
+							<avg>0.0</avg>
+							<min>0.0</min>
+							<max>0.0</max>
+							<interval>0</interval>
+						</esnr>
+					</state>
+				</otn>
+				<logical-channel-assignments>
+					<assignment>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-1</optical-channel>
+						</config>
+						<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-1</optical-channel>
+						</state>
+					</assignment>
+				</logical-channel-assignments>
+			</channel>
+		</logical-channels>
+		<operational-modes>
+			<mode>
+				<mode-id>1</mode-id>
+				<state>
+					<mode-id>1</mode-id>
+					<description>FEC1</description>
+					<vendor-id>Ericsson</vendor-id>
+				</state>
+			</mode>
+			<mode>
+				<mode-id>2</mode-id>
+				<state>
+					<mode-id>2</mode-id>
+					<description>FEC2</description>
+					<vendor-id>Ericsson</vendor-id>
+				</state>
+			</mode>
+		</operational-modes>
+	</terminal-device>
+</config>
diff --git a/src/tests/ofc24/tempOC/files/platform_t2.xml b/src/tests/ofc24/tempOC/files/platform_t2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..03c643c91f176b531ec25bda6fbb36c8bdb1c099
--- /dev/null
+++ b/src/tests/ofc24/tempOC/files/platform_t2.xml
@@ -0,0 +1,295 @@
+<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
+	<components xmlns="http://openconfig.net/yang/platform">
+		<component>
+			<name>device</name>
+			<config>
+				<name>device</name>
+			</config>
+			<state>
+				<name>MellanoxSwitch</name>
+				<mfg-name>SSSA-CNIT</mfg-name>
+				<hardware-version>1.0.0</hardware-version>
+				<firmware-version>1.0.0</firmware-version>
+				<software-version>1.0.0</software-version>
+				<serial-no>610610</serial-no>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:OPERATING_SYSTEM</type>
+			</state>
+		</component>
+		<component>
+			<name>channel-6</name>
+			<config>
+				<name>channel-6</name>
+			</config>
+			<state>
+				<name>channel-6</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-6</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-6</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>transceiver-6</name>
+			<config>
+				<name>transceiver-6</name>
+			</config>
+			<state>
+				<name>transceiver-6</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-6</associated-optical-channel>
+						</config>
+						<!--state>
+							<index>1</index>
+							<associated-optical-channel>channel-4</associated-optical-channel>
+						</state-->
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+			<name>port-6</name>
+			<config>
+				<name>port-6</name>
+			</config>
+			<state>
+				<name>port-6</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+			</state>
+			<subcomponents>
+				<subcomponent>
+					<name>channel-6</name>
+					<config>
+						<name>channel-6</name>
+					</config>
+					<state>
+						<name>channel-6</name>
+					</state>
+				</subcomponent>
+			</subcomponents>
+			<properties>
+				<property>
+					<name>onos-index</name>
+					<config>
+						<name>onos-index</name>
+						<value>4</value>
+					</config>
+					<state>
+						<name>onos-index</name>
+						<value>4</value>
+					</state>
+				</property>
+				<property>
+					<name>odtn-port-type</name>
+					<config>
+						<name>odtn-port-type</name>
+						<value>line</value>
+					</config>
+					<state>
+						<name>odtn-port-type</name>
+						<value>line</value>
+					</state>
+				</property>
+			</properties>
+		</component>
+	</components>
+	<terminal-device xmlns="http://openconfig.net/yang/terminal-device">
+		<logical-channels>
+			<!--Description: Optical logical link-->
+			<channel>
+
+				<!--Description: Line (OTN) Port-->
+				<index>4</index>
+				<config>
+					<index>4</index>
+					<description>Logical channel 4</description>
+					<admin-state>DISABLED</admin-state>
+					<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+					<loopback-mode>NONE</loopback-mode>
+				</config>
+				<state>
+					<index>4</index>
+					<description>Logical channel 4</description>
+					<admin-state>DISABLED</admin-state>
+					<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+					<loopback-mode>NONE</loopback-mode>
+					<link-state>UP</link-state>
+				</state>
+				<ingress>
+					<config>
+						<transceiver>transceiver-6</transceiver>
+					</config>
+					<state>
+						<transceiver>transceiver-6</transceiver>
+					</state>
+				</ingress>
+				<otn>
+					<config>
+						<tti-msg-expected>test1</tti-msg-expected>
+						<tti-msg-transmit>test1</tti-msg-transmit>
+					</config>
+					<state>
+						<tti-msg-expected>test1</tti-msg-expected>
+						<tti-msg-transmit>test1</tti-msg-transmit>
+						<tti-msg-auto>0</tti-msg-auto>
+						<tti-msg-recv>0</tti-msg-recv>
+						<rdi-msg>0</rdi-msg>
+						<errored-seconds>0</errored-seconds>
+						<severely-errored-seconds>0</severely-errored-seconds>
+						<unavailable-seconds>0</unavailable-seconds>
+						<code-violations>0</code-violations>
+						<fec-uncorrectable-words>0</fec-uncorrectable-words>
+						<fec-corrected-bytes>0</fec-corrected-bytes>
+						<fec-corrected-bits>0</fec-corrected-bits>
+						<background-block-errors>0</background-block-errors>
+						<pre-fec-ber>
+							<instant>0.0</instant>
+							<avg>0.0</avg>
+							<min>0.0</min>
+							<max>0.0</max>
+						</pre-fec-ber>
+						<post-fec-ber>
+							<instant>0.0</instant>
+							<avg>0.0</avg>
+							<min>0.0</min>
+							<max>0.0</max>
+						</post-fec-ber>
+						<q-value>
+							<instant>0.0</instant>
+							<avg>0.0</avg>
+							<min>0.0</min>
+							<max>0.0</max>
+							<interval>0</interval>
+						</q-value>
+						<esnr>
+							<instant>0.0</instant>
+							<avg>0.0</avg>
+							<min>0.0</min>
+							<max>0.0</max>
+							<interval>0</interval>
+						</esnr>
+					</state>
+				</otn>
+				<logical-channel-assignments>
+					<assignment>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-6</optical-channel>
+						</config>
+						<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-6</optical-channel>
+						</state>
+					</assignment>
+				</logical-channel-assignments>
+			</channel>
+		</logical-channels>
+		<operational-modes>
+			<mode>
+				<mode-id>1</mode-id>
+				<state>
+					<mode-id>1</mode-id>
+					<description>FEC1</description>
+					<vendor-id>Ericsson</vendor-id>
+				</state>
+			</mode>
+			<mode>
+				<mode-id>2</mode-id>
+				<state>
+					<mode-id>2</mode-id>
+					<description>FEC2</description>
+					<vendor-id>Ericsson</vendor-id>
+				</state>
+			</mode>
+		</operational-modes>
+	</terminal-device>
+</config>
diff --git a/src/tests/ofc24/tempOC/files/startNetconfAgent.sh b/src/tests/ofc24/tempOC/files/startNetconfAgent.sh
new file mode 100644
index 0000000000000000000000000000000000000000..35c95b6574bca3e0b620c356ea0f393137ec1b90
--- /dev/null
+++ b/src/tests/ofc24/tempOC/files/startNetconfAgent.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# 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
+
+make clean
+make all
+#make init
+cp init_openconfig-platform.xml confd-cdb/
+#cp init_flex-scale-mg-on.xml confd-cdb/
+make start2
diff --git a/src/tests/ofc24/tempOC/files/transponders_x4.xml b/src/tests/ofc24/tempOC/files/transponders_x4.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fb55f02abefa6c5a444d3fecaa2ca049798f9483
--- /dev/null
+++ b/src/tests/ofc24/tempOC/files/transponders_x4.xml
@@ -0,0 +1,1039 @@
+<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <components xmlns="http://openconfig.net/yang/platform">
+        <component>
+            <name>device</name>
+            <config>
+                <name>device</name>
+            </config>
+            <state>
+				<name>MellanoxSwitch</name>
+				<mfg-name>SSSA-CNIT</mfg-name>
+				<hardware-version>1.0.0</hardware-version>
+				<firmware-version>1.0.0</firmware-version>
+				<software-version>1.0.0</software-version>
+				<serial-no>610610</serial-no>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:OPERATING_SYSTEM</type>
+			</state>
+		</component>
+		<component>
+			<name>channel-1</name>
+			<config>
+					<name>channel-1</name>
+			</config>
+			<state>
+				<name>channel-1</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-1</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-1</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-2</name>
+			<config>
+					<name>channel-2</name>
+			</config>
+			<state>
+				<name>channel-2</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-2</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-2</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-3</name>
+			<config>
+					<name>channel-3</name>
+			</config>
+			<state>
+				<name>channel-3</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-3</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-3</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-4</name>
+			<config>
+					<name>channel-4</name>
+			</config>
+			<state>
+				<name>channel-4</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-4</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-4</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+				<component>
+			<name>transceiver-1</name>
+			<config>
+				<name>transceiver-1</name>
+			</config>
+			<state>
+				<name>transceiver-1</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-1</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+			<name>transceiver-2</name>
+			<config>
+				<name>transceiver-2</name>
+			</config>
+			<state>
+				<name>transceiver-2</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-2</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+			<name>transceiver-3</name>
+			<config>
+				<name>transceiver-3</name>
+			</config>
+			<state>
+				<name>transceiver-3</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-3</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+
+		<component>
+			<name>transceiver-4</name>
+			<config>
+				<name>transceiver-4</name>
+			</config>
+			<state>
+				<name>transceiver-4</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-4</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+            <name>port-1</name>
+            <config>
+                <name>port-1</name>
+            </config>
+            <state>
+                <name>port-1</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-1</name>
+					<config>
+							<name>channel-1</name>
+					</config>
+					<state>
+							<name>channel-1</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>1</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>1</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>   
+				<component>
+            <name>port-2</name>
+            <config>
+                <name>port-2</name>
+            </config>
+            <state>
+                <name>port-2</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-2</name>
+					<config>
+							<name>channel-2</name>
+					</config>
+					<state>
+							<name>channel-2</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>2</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>2</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>
+				<component>
+            <name>port-3</name>
+            <config>
+                <name>port-3</name>
+            </config>
+            <state>
+                <name>port-3</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-3</name>
+					<config>
+							<name>channel-3</name>
+					</config>
+					<state>
+							<name>channel-3</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>3</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>3</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>   
+		<component>
+            <name>port-4</name>
+            <config>
+                <name>port-4</name>
+            </config>
+            <state>
+                <name>port-4</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-4</name>
+					<config>
+							<name>channel-4</name>
+					</config>
+					<state>
+							<name>channel-4</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>4</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>4</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>      
+	</components>
+	<terminal-device xmlns="http://openconfig.net/yang/terminal-device">
+        <logical-channels>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>1</index>
+			<config>
+				<index>1</index>
+				<description>Logical channel 1</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>1</index>
+				<description>Logical channel 1</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-1</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-1</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-1</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-1</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+		           <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>2</index>
+			<config>
+				<index>2</index>
+				<description>Logical channel 2</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>2</index>
+				<description>Logical channel 2</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-2</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-2</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-2</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-2</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>3</index>
+			<config>
+				<index>3</index>
+				<description>Logical channel 3</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>3</index>
+				<description>Logical channel 3</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-3</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-3</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-3</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-3</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>4</index>
+			<config>
+				<index>4</index>
+				<description>Logical channel 4</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>4</index>
+				<description>Logical channel 4</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-4</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-4</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-4</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-4</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+        </channel>
+	</logical-channels>
+	<operational-modes>
+       <mode>
+		<mode-id>1</mode-id>
+			<state>
+				<mode-id>1</mode-id>
+				<description>FEC1</description>
+				<vendor-id>Ericsson</vendor-id>
+			</state>
+		</mode>
+		<mode>
+		    <mode-id>2</mode-id>
+			<state>
+				<mode-id>2</mode-id>
+				<description>FEC2</description>
+				<vendor-id>Ericsson</vendor-id>
+			</state>
+		</mode>		
+    	   </operational-modes>
+	</terminal-device>
+</config>
+
diff --git a/src/tests/ofc24/tempOC/files/transponders_x4_2.xml b/src/tests/ofc24/tempOC/files/transponders_x4_2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8d10c593b3c2166b16e8ecea383dadd69c3ac067
--- /dev/null
+++ b/src/tests/ofc24/tempOC/files/transponders_x4_2.xml
@@ -0,0 +1,1039 @@
+<config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <components xmlns="http://openconfig.net/yang/platform">
+        <component>
+            <name>device</name>
+            <config>
+                <name>device</name>
+            </config>
+            <state>
+				<name>MellanoxSwitch</name>
+				<mfg-name>SSSA-CNIT</mfg-name>
+				<hardware-version>1.0.0</hardware-version>
+				<firmware-version>1.0.0</firmware-version>
+				<software-version>1.0.0</software-version>
+				<serial-no>610610</serial-no>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:OPERATING_SYSTEM</type>
+			</state>
+		</component>
+		<component>
+			<name>channel-5</name>
+			<config>
+					<name>channel-5</name>
+			</config>
+			<state>
+				<name>channel-5</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-5</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-5</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-6</name>
+			<config>
+					<name>channel-6</name>
+			</config>
+			<state>
+				<name>channel-6</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-6</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-6</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-7</name>
+			<config>
+					<name>channel-7</name>
+			</config>
+			<state>
+				<name>channel-7</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-7</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-7</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+		<component>
+			<name>channel-8</name>
+			<config>
+					<name>channel-8</name>
+			</config>
+			<state>
+				<name>channel-8</name>
+				<type xmlns:typex="http://openconfig.net/yang/transport-types">typex:OPTICAL_CHANNEL</type>
+			</state>
+			<optical-channel xmlns="http://openconfig.net/yang/terminal-device">
+				<config>
+					<frequency>191600000</frequency>
+					<target-output-power>100</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-8</line-port>
+				</config>
+				<state>
+					<frequency>191600000</frequency>
+					<target-output-power>0</target-output-power>
+					<operational-mode>0</operational-mode>
+					<line-port>transceiver-8</line-port>
+					<group-id>1</group-id>
+					<output-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</output-power>
+					<input-power>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</input-power>
+					<laser-bias-current>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</laser-bias-current>
+					<chromatic-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</chromatic-dispersion>
+					<polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</polarization-mode-dispersion>
+					<second-order-polarization-mode-dispersion>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+					</second-order-polarization-mode-dispersion>
+					<polarization-dependent-loss>
+						<instant>0</instant>
+						<avg>0</avg>
+						<min>0</min>
+						<max>0</max>
+						<interval>0</interval>
+					</polarization-dependent-loss>
+				</state>
+			</optical-channel>
+		</component>
+				<component>
+			<name>transceiver-5</name>
+			<config>
+				<name>transceiver-5</name>
+			</config>
+			<state>
+				<name>transceiver-5</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-5</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+			<name>transceiver-6</name>
+			<config>
+				<name>transceiver-6</name>
+			</config>
+			<state>
+				<name>transceiver-6</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-6</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+			<name>transceiver-7</name>
+			<config>
+				<name>transceiver-7</name>
+			</config>
+			<state>
+				<name>transceiver-7</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-7</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+
+		<component>
+			<name>transceiver-8</name>
+			<config>
+				<name>transceiver-8</name>
+			</config>
+			<state>
+				<name>transceiver-8</name>
+				<type xmlns:typex="http://openconfig.net/yang/platform-types">typex:TRANSCEIVER</type>
+			</state>
+			<transceiver xmlns="http://openconfig.net/yang/platform/transceiver">
+				<config>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+				</config>
+				<state>
+					<enabled>true</enabled>
+					<form-factor-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:QSFP56_DD_TYPE1</form-factor-preconf>
+					<ethernet-pmd-preconf xmlns:typex="http://openconfig.net/yang/transport-types">typex:ETH_400GBASE_ZR</ethernet-pmd-preconf>
+					<fec-mode xmlns:typex="http://openconfig.net/yang/platform-types">typex:FEC_AUTO</fec-mode>
+					<module-functional-type xmlns:typex="http://openconfig.net/yang/transport-types">typex:TYPE_DIGITAL_COHERENT_OPTIC</module-functional-type>
+					<vendor>Cisco</vendor>
+					<vendor-part>400zr-QSFP-DD</vendor-part>
+					<vendor-rev>01</vendor-rev>
+					<serial-no>1567321</serial-no>
+				</state>
+				<physical-channels>
+					<channel>
+						<index>1</index>
+						<config>
+							<index>1</index>
+							<associated-optical-channel>channel-8</associated-optical-channel>
+						</config>
+					</channel>
+				</physical-channels>
+			</transceiver>
+		</component>
+		<component>
+            <name>port-5</name>
+            <config>
+                <name>port-5</name>
+            </config>
+            <state>
+                <name>port-5</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-5</name>
+					<config>
+							<name>channel-5</name>
+					</config>
+					<state>
+							<name>channel-5</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>5</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>5</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>   
+				<component>
+            <name>port-6</name>
+            <config>
+                <name>port-6</name>
+            </config>
+            <state>
+                <name>port-6</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-6</name>
+					<config>
+							<name>channel-6</name>
+					</config>
+					<state>
+							<name>channel-6</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>6</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>6</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>
+				<component>
+            <name>port-7</name>
+            <config>
+                <name>port-7</name>
+            </config>
+            <state>
+                <name>port-7</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-7</name>
+					<config>
+							<name>channel-7</name>
+					</config>
+					<state>
+							<name>channel-7</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>7</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>7</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>   
+		<component>
+            <name>port-8</name>
+            <config>
+                <name>port-8</name>
+            </config>
+            <state>
+                <name>port-8</name>
+                <type xmlns:typex="http://openconfig.net/yang/platform-types">typex:PORT</type>
+            </state>
+            <subcomponents>
+				<subcomponent>
+					<name>channel-8</name>
+					<config>
+							<name>channel-8</name>
+					</config>
+					<state>
+							<name>channel-8</name>
+					</state>
+				</subcomponent>
+            </subcomponents>
+            <properties>
+				<property>
+						<name>onos-index</name>
+						<config>
+								<name>onos-index</name>
+								<value>8</value>
+						</config>
+						<state>
+								<name>onos-index</name>
+								<value>8</value>
+						</state>
+				</property>
+				<property>
+						<name>odtn-port-type</name>
+						<config>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</config>
+						<state>
+								<name>odtn-port-type</name>
+								<value>line</value>
+						</state>
+				</property>
+            </properties>
+        </component>      
+	</components>
+	<terminal-device xmlns="http://openconfig.net/yang/terminal-device">
+        <logical-channels>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>5</index>
+			<config>
+				<index>5</index>
+				<description>Logical channel 5</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>5</index>
+				<description>Logical channel 5</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-5</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-5</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-5</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-5</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+		           <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>6</index>
+			<config>
+				<index>6</index>
+				<description>Logical channel 6</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>6</index>
+				<description>Logical channel 6</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-6</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-6</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-6</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-6</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>7</index>
+			<config>
+				<index>7</index>
+				<description>Logical channel 7</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>7</index>
+				<description>Logical channel 7</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-7</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-7</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-7</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-7</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+                  </channel>
+            <!--Description: Optical logical link-->
+            <channel>
+			<!--Description: Line (OTN) Port-->
+			<index>8</index>
+			<config>
+				<index>8</index>
+				<description>Logical channel 8</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+			</config>
+			<state>
+				<index>8</index>
+				<description>Logical channel 8</description>
+				<admin-state>DISABLED</admin-state>
+				<logical-channel-type xmlns:type="http://openconfig.net/yang/transport-types">type:PROT_OTN</logical-channel-type>
+				<loopback-mode>NONE</loopback-mode>
+				<link-state>UP</link-state>
+			</state>
+		   	<ingress>
+				<config>
+					<transceiver>transceiver-8</transceiver>
+				</config>
+				<state>
+					<transceiver>transceiver-8</transceiver>
+				</state>
+			</ingress>
+			<otn>
+				<config>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+				</config>
+				<state>
+					<tti-msg-expected>test1</tti-msg-expected>
+					<tti-msg-transmit>test1</tti-msg-transmit>
+					<tti-msg-auto>0</tti-msg-auto>
+					<tti-msg-recv>0</tti-msg-recv>
+					<rdi-msg>0</rdi-msg>
+					<errored-seconds>0</errored-seconds>
+					<severely-errored-seconds>0</severely-errored-seconds>
+					<unavailable-seconds>0</unavailable-seconds>
+					<code-violations>0</code-violations>
+					<fec-uncorrectable-words>0</fec-uncorrectable-words>
+					<fec-corrected-bytes>0</fec-corrected-bytes>
+					<fec-corrected-bits>0</fec-corrected-bits>
+					<background-block-errors>0</background-block-errors>
+					<pre-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</pre-fec-ber>
+					<post-fec-ber>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+					</post-fec-ber>
+					<q-value>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</q-value>
+					<esnr>
+						<instant>0.0</instant>
+						<avg>0.0</avg>
+						<min>0.0</min>
+						<max>0.0</max>
+						<interval>0</interval>
+					</esnr>
+				</state>
+			</otn>
+			<logical-channel-assignments>
+				<assignment>
+					<index>1</index>
+					<config>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-8</optical-channel>
+					</config>
+					<state>
+							<index>1</index>
+							<description>Optical channel assigned 100</description>
+							<allocation>100</allocation>
+							<assignment-type>OPTICAL_CHANNEL</assignment-type>
+							<optical-channel>channel-8</optical-channel>
+					</state>
+				</assignment>
+			</logical-channel-assignments>
+        </channel>
+	</logical-channels>
+	<operational-modes>
+       <mode>
+		<mode-id>1</mode-id>
+			<state>
+				<mode-id>1</mode-id>
+				<description>FEC1</description>
+				<vendor-id>Ericsson</vendor-id>
+			</state>
+		</mode>
+		<mode>
+		    <mode-id>2</mode-id>
+			<state>
+				<mode-id>2</mode-id>
+				<description>FEC2</description>
+				<vendor-id>Ericsson</vendor-id>
+			</state>
+		</mode>		
+    	   </operational-modes>
+	</terminal-device>
+</config>
+
diff --git a/src/tests/ofc24/transponders.sh b/src/tests/ofc24/transponders.sh
new file mode 100644
index 0000000000000000000000000000000000000000..17fe4a5e7ebcbc653e1f43291addbc15670c03f6
--- /dev/null
+++ b/src/tests/ofc24/transponders.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# 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.
+
+         
+docker stop -t 1 tna1
+docker stop -t 1 tna2
+
+docker rm tna1
+docker rm tna2
+
+
+
+screen -dmS tt1 -T xterm sh -c "docker run --name tna1  -p  10.0.2.4:2023:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files  -it asgamb1/oc23bgp.img:latest bash -c 'cp /files/platform_t1.xml demoECOC21.xml ; ./startNetconfAgent.sh'"
+screen -dmS tt2 -T xterm sh -c "docker run --name tna2  -p  10.0.2.4:2024:2022 -v /home/tfs/tfs-ctrl/src/tests/ofc24/tempOC/files:/files  -it asgamb1/oc23bgp.img:latest bash -c 'cp /files/platform_t2.xml demoECOC21.xml ; ./startNetconfAgent.sh'"
diff --git a/src/tests/p4-fwd-l1/README.md b/src/tests/p4-fwd-l1/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..b7da0fd88c6b54e4210d5f0d6664ae1ce219fafb
--- /dev/null
+++ b/src/tests/p4-fwd-l1/README.md
@@ -0,0 +1,47 @@
+# Tests for P4 functionality of TeraFlowSDN
+
+This directory contains the necessary scripts and configurations to run tests for a simple port forwarding TFS program atop software-based P4 switches (using Mininet).
+
+## Prerequisites
+
+This test requires some custom monitoring services (latency monitoring and probe).
+These services are implemented in Rust and can be found in the `./probe` directory.
+To build these services on your target platform, follow the instructions in `./probe/probe-tfs/README.md`.
+
+## Basic scripts
+
+To run the experiments you should use the five scripts in the following order:
+
+```shell
+setup.sh
+run_test_01_bootstrap.sh
+run_test_02_create_service.sh
+run_test_03_delete_service.sh
+run_test_04_cleanup.sh
+```
+
+The `setup` script copies the necessary artefacts to the SBI service pod. It should be run just once, after a fresh install of TFS.
+The `bootstrap` script registers the context, topology, links, and devices to TFS.
+The `create` service script establishes a service between two endpoints.
+The `delete` service script deletes the aforementioned service.
+The `cleanup` script deletes all the objects (context, topology, links, and devices) from TFS.
+
+## Objects file
+
+The above bash scripts make use of the corresponding python scripts found under `./tests/` directory.
+More important is the `./tests/Objects.py` file, which contains the definition of the Context, Topology, Devices, Links, Services. **This is the file that needs changes in case of a new topology.**
+
+Check the `./tests/Objects.py` file before running the experiment to make sure that the switches' details are correct (ip address, port, etc.)
+
+## Mininet topologies
+
+In the `./mininet/` directory there are different mininet topology examples. The current `./tests/Objects.py` file corresponds to the `./mininet/8switch3path.py` topology. Additionally there is a backup file `./tests/topologies/6switchObjects.py` which corresponds to the `./mininet/6switch2path.py`.
+
+## P4 artefacts
+
+In the `./p4/` directory there are compiled p4 artefacts of the pipeline that will be pushed to the p4 switch, along with the p4-runtime definitions.
+The `./setup.sh` script copies from this directory. So if you need to change p4 program, make sure to put the compiled artefacts there.
+
+## Latency probe
+
+In the `./probe/` directory there is a little program which calculates latency between two hosts in mininet and sends these measurements to the Monitoring component. For specific instructions, refer to the corresponding `./probe/README.md` file.
diff --git a/src/tests/p4-fwd-l1/__init__.py b/src/tests/p4-fwd-l1/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ee6f7071f145e06c3aeaefc09a43ccd88e619e3
--- /dev/null
+++ b/src/tests/p4-fwd-l1/__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/tests/p4/deploy_specs.sh b/src/tests/p4-fwd-l1/deploy_specs.sh
similarity index 100%
rename from src/tests/p4/deploy_specs.sh
rename to src/tests/p4-fwd-l1/deploy_specs.sh
diff --git a/src/tests/p4/mininet/1switch1path.py b/src/tests/p4-fwd-l1/mininet/1switch1path.py
similarity index 100%
rename from src/tests/p4/mininet/1switch1path.py
rename to src/tests/p4-fwd-l1/mininet/1switch1path.py
diff --git a/src/tests/p4/mininet/2switch1path.py b/src/tests/p4-fwd-l1/mininet/2switch1path.py
similarity index 100%
rename from src/tests/p4/mininet/2switch1path.py
rename to src/tests/p4-fwd-l1/mininet/2switch1path.py
diff --git a/src/tests/p4/mininet/4switch2path.py b/src/tests/p4-fwd-l1/mininet/4switch2path.py
similarity index 100%
rename from src/tests/p4/mininet/4switch2path.py
rename to src/tests/p4-fwd-l1/mininet/4switch2path.py
diff --git a/src/tests/p4/mininet/6switch2path.py b/src/tests/p4-fwd-l1/mininet/6switch2path.py
similarity index 100%
rename from src/tests/p4/mininet/6switch2path.py
rename to src/tests/p4-fwd-l1/mininet/6switch2path.py
diff --git a/src/tests/p4/mininet/8switch3path.py b/src/tests/p4-fwd-l1/mininet/8switch3path.py
similarity index 100%
rename from src/tests/p4/mininet/8switch3path.py
rename to src/tests/p4-fwd-l1/mininet/8switch3path.py
diff --git a/src/tests/p4/p4/bmv2.json b/src/tests/p4-fwd-l1/p4/bmv2.json
similarity index 100%
rename from src/tests/p4/p4/bmv2.json
rename to src/tests/p4-fwd-l1/p4/bmv2.json
diff --git a/src/tests/p4/p4/main.p4 b/src/tests/p4-fwd-l1/p4/main.p4
similarity index 100%
rename from src/tests/p4/p4/main.p4
rename to src/tests/p4-fwd-l1/p4/main.p4
diff --git a/src/tests/p4/p4/p4info.txt b/src/tests/p4-fwd-l1/p4/p4info.txt
similarity index 100%
rename from src/tests/p4/p4/p4info.txt
rename to src/tests/p4-fwd-l1/p4/p4info.txt
diff --git a/src/tests/p4/probe/README.md b/src/tests/p4-fwd-l1/probe/README.md
similarity index 100%
rename from src/tests/p4/probe/README.md
rename to src/tests/p4-fwd-l1/probe/README.md
diff --git a/src/tests/p4/probe/monitoring_kpis.ipynb b/src/tests/p4-fwd-l1/probe/monitoring_kpis.ipynb
similarity index 100%
rename from src/tests/p4/probe/monitoring_kpis.ipynb
rename to src/tests/p4-fwd-l1/probe/monitoring_kpis.ipynb
diff --git a/src/tests/p4/probe/monitoring_kpis.py b/src/tests/p4-fwd-l1/probe/monitoring_kpis.py
similarity index 100%
rename from src/tests/p4/probe/monitoring_kpis.py
rename to src/tests/p4-fwd-l1/probe/monitoring_kpis.py
diff --git a/src/tests/p4/probe/probe-tfs/.gitignore b/src/tests/p4-fwd-l1/probe/probe-tfs/.gitignore
similarity index 100%
rename from src/tests/p4/probe/probe-tfs/.gitignore
rename to src/tests/p4-fwd-l1/probe/probe-tfs/.gitignore
diff --git a/src/tests/p4/probe/probe-tfs/Cargo.toml b/src/tests/p4-fwd-l1/probe/probe-tfs/Cargo.toml
similarity index 100%
rename from src/tests/p4/probe/probe-tfs/Cargo.toml
rename to src/tests/p4-fwd-l1/probe/probe-tfs/Cargo.toml
diff --git a/src/tests/p4/probe/probe-tfs/LICENSE b/src/tests/p4-fwd-l1/probe/probe-tfs/LICENSE
similarity index 100%
rename from src/tests/p4/probe/probe-tfs/LICENSE
rename to src/tests/p4-fwd-l1/probe/probe-tfs/LICENSE
diff --git a/src/tests/p4-fwd-l1/probe/probe-tfs/README.md b/src/tests/p4-fwd-l1/probe/probe-tfs/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..3cff11314ee92db79d7b56c03e38a8a7f2acadec
--- /dev/null
+++ b/src/tests/p4-fwd-l1/probe/probe-tfs/README.md
@@ -0,0 +1,21 @@
+# Rust-tfs
+
+Client for TFS functionalities written in Rust.
+
+## Dependencies
+
+This project requires the cargo Rust compiler:
+
+```sh
+sudo apt-get install protobuf-compiler cargo
+```
+
+## Build
+
+Build sources as follows:
+
+```sh
+cargo build
+```
+
+After a successfuly build, two new executables will be generated in `target/`.
diff --git a/src/tests/p4/probe/probe-tfs/build.rs b/src/tests/p4-fwd-l1/probe/probe-tfs/build.rs
similarity index 100%
rename from src/tests/p4/probe/probe-tfs/build.rs
rename to src/tests/p4-fwd-l1/probe/probe-tfs/build.rs
diff --git a/src/tests/p4/probe/probe-tfs/connect_to_mininet.sh b/src/tests/p4-fwd-l1/probe/probe-tfs/connect_to_mininet.sh
similarity index 100%
rename from src/tests/p4/probe/probe-tfs/connect_to_mininet.sh
rename to src/tests/p4-fwd-l1/probe/probe-tfs/connect_to_mininet.sh
diff --git a/src/tests/p4/probe/probe-tfs/deploy.sh b/src/tests/p4-fwd-l1/probe/probe-tfs/deploy.sh
similarity index 100%
rename from src/tests/p4/probe/probe-tfs/deploy.sh
rename to src/tests/p4-fwd-l1/probe/probe-tfs/deploy.sh
diff --git a/src/tests/p4/probe/probe-tfs/proto b/src/tests/p4-fwd-l1/probe/probe-tfs/proto
similarity index 100%
rename from src/tests/p4/probe/probe-tfs/proto
rename to src/tests/p4-fwd-l1/probe/probe-tfs/proto
diff --git a/src/tests/p4/probe/probe-tfs/src/agent.rs b/src/tests/p4-fwd-l1/probe/probe-tfs/src/agent.rs
similarity index 99%
rename from src/tests/p4/probe/probe-tfs/src/agent.rs
rename to src/tests/p4-fwd-l1/probe/probe-tfs/src/agent.rs
index 749e42a6c81ce0523ae2cf52a29e9c90c43f48e7..81bc1a2a0b40947fd8b77f99ef10be8032eb66f7 100644
--- a/src/tests/p4/probe/probe-tfs/src/agent.rs
+++ b/src/tests/p4-fwd-l1/probe/probe-tfs/src/agent.rs
@@ -195,6 +195,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
                     endpoint_id: None,
                     slice_id: None,
                     connection_id: None,
+                    link_id: None,
                     kpi_description: format!(
                         "Latency value for service {}",
                         event_service.service_uuid.unwrap().uuid
diff --git a/src/tests/p4/probe/probe-tfs/src/ping.rs b/src/tests/p4-fwd-l1/probe/probe-tfs/src/ping.rs
similarity index 100%
rename from src/tests/p4/probe/probe-tfs/src/ping.rs
rename to src/tests/p4-fwd-l1/probe/probe-tfs/src/ping.rs
diff --git a/src/tests/p4/run_test_01_bootstrap.sh b/src/tests/p4-fwd-l1/run_test_01_bootstrap.sh
similarity index 100%
rename from src/tests/p4/run_test_01_bootstrap.sh
rename to src/tests/p4-fwd-l1/run_test_01_bootstrap.sh
diff --git a/src/tests/p4/run_test_02_create_service.sh b/src/tests/p4-fwd-l1/run_test_02_create_service.sh
similarity index 100%
rename from src/tests/p4/run_test_02_create_service.sh
rename to src/tests/p4-fwd-l1/run_test_02_create_service.sh
diff --git a/src/tests/p4/run_test_03_delete_service.sh b/src/tests/p4-fwd-l1/run_test_03_delete_service.sh
similarity index 100%
rename from src/tests/p4/run_test_03_delete_service.sh
rename to src/tests/p4-fwd-l1/run_test_03_delete_service.sh
diff --git a/src/tests/p4/run_test_04_cleanup.sh b/src/tests/p4-fwd-l1/run_test_04_cleanup.sh
similarity index 100%
rename from src/tests/p4/run_test_04_cleanup.sh
rename to src/tests/p4-fwd-l1/run_test_04_cleanup.sh
diff --git a/src/tests/p4/setup.sh b/src/tests/p4-fwd-l1/setup.sh
similarity index 100%
rename from src/tests/p4/setup.sh
rename to src/tests/p4-fwd-l1/setup.sh
diff --git a/src/tests/p4/tests/.gitignore b/src/tests/p4-fwd-l1/tests/.gitignore
similarity index 100%
rename from src/tests/p4/tests/.gitignore
rename to src/tests/p4-fwd-l1/tests/.gitignore
diff --git a/src/tests/p4/tests/BuildDescriptors.py b/src/tests/p4-fwd-l1/tests/BuildDescriptors.py
similarity index 100%
rename from src/tests/p4/tests/BuildDescriptors.py
rename to src/tests/p4-fwd-l1/tests/BuildDescriptors.py
diff --git a/src/tests/p4/tests/LoadDescriptors.py b/src/tests/p4-fwd-l1/tests/LoadDescriptors.py
similarity index 100%
rename from src/tests/p4/tests/LoadDescriptors.py
rename to src/tests/p4-fwd-l1/tests/LoadDescriptors.py
diff --git a/src/tests/p4/tests/Objects.py b/src/tests/p4-fwd-l1/tests/Objects.py
similarity index 100%
rename from src/tests/p4/tests/Objects.py
rename to src/tests/p4-fwd-l1/tests/Objects.py
diff --git a/src/tests/p4-fwd-l1/tests/__init__.py b/src/tests/p4-fwd-l1/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ee6f7071f145e06c3aeaefc09a43ccd88e619e3
--- /dev/null
+++ b/src/tests/p4-fwd-l1/tests/__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/tests/p4/tests/test_functional_bootstrap.py b/src/tests/p4-fwd-l1/tests/test_functional_bootstrap.py
similarity index 100%
rename from src/tests/p4/tests/test_functional_bootstrap.py
rename to src/tests/p4-fwd-l1/tests/test_functional_bootstrap.py
diff --git a/src/tests/p4/tests/test_functional_cleanup.py b/src/tests/p4-fwd-l1/tests/test_functional_cleanup.py
similarity index 100%
rename from src/tests/p4/tests/test_functional_cleanup.py
rename to src/tests/p4-fwd-l1/tests/test_functional_cleanup.py
diff --git a/src/tests/p4/tests/test_functional_create_service.py b/src/tests/p4-fwd-l1/tests/test_functional_create_service.py
similarity index 100%
rename from src/tests/p4/tests/test_functional_create_service.py
rename to src/tests/p4-fwd-l1/tests/test_functional_create_service.py
diff --git a/src/tests/p4/tests/test_functional_delete_service.py b/src/tests/p4-fwd-l1/tests/test_functional_delete_service.py
similarity index 100%
rename from src/tests/p4/tests/test_functional_delete_service.py
rename to src/tests/p4-fwd-l1/tests/test_functional_delete_service.py
diff --git a/src/tests/p4/tests/topologies/6switchObjects.py b/src/tests/p4-fwd-l1/tests/topologies/6switchObjects.py
similarity index 100%
rename from src/tests/p4/tests/topologies/6switchObjects.py
rename to src/tests/p4-fwd-l1/tests/topologies/6switchObjects.py
diff --git a/src/tests/p4/README.md b/src/tests/p4/README.md
deleted file mode 100644
index 43920d14d5e99214bb2ad8418cc4babcae5be91c..0000000000000000000000000000000000000000
--- a/src/tests/p4/README.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Tests for P4 functionality of TeraFlowSDN
-
-This directory contains the necessary scripts and configurations to run tests for the P4 functionality of TFS.
-
-## Basic scripts
-
-To run the experiments you should use the five scripts in the following order:
-```
-setup.sh
-run_test_01_bootstrap.sh
-run_test_02_create_service.sh
-run_test_03_delete_service.sh
-run_test_04_cleanup.sh
-```
-
-The setup script copies the necessary artifacts to the SBI service pod. It should be run just once, after a fresh install of TFS.
-The bootstrap script registers the context, topology, links and, devices to TFS.
-The create service scripts establishes a service between two endpoints.
-The delete service script delete the aforementioned service.
-Cleanup script deletes all the objects (context, topology, links, devices) from TFS.
-
-## Objects file
-
-The above bash scripts make use of the corresponding python scripts found under `./tests/` directory.
-More important is the `./tests/Objects.py` file, which contains the definition of the Context, Topology, Devices, Links, Services. **This is the file that need changes in case of a new topology.**
-
-Check the `./tests/Objects.py` file before running the experiment to make sure that the switches details are correct (ip address, port, etc.)
-
-## Mininet topologies
-
-In the `./mininet/` directory there are different mininet topology examples. The current `./tests/Objects.py` file corresponds to the `./mininet/8switch3path.py` topology. Additionally there is a backup file `./tests/topologies/6switchObjects.py` which corresponds to the `./mininet/6switch2path.py`.
-
-## P4 artifacts
-
-In the `./p4/` directory there are the compiled p4 artifacts that contain the pipeline that will be pushed to the p4 switch, along with the p4-runtime definitions. 
-The `./setup.sh` script copies from this directory. So if you need to change p4 program, make sure to put the compiled artifacts here.
-
-## Latency probe
-
-In the `./probe/` directory there is a little program which calculates latency between two hosts in mininet and sends them to the Monitoring component. For specific instructions, refer to the corresponding `./probe/README.md` file.
-
diff --git a/src/tests/p4/probe/probe-tfs/README.md b/src/tests/p4/probe/probe-tfs/README.md
deleted file mode 100644
index f88d7c542dae22ad623797f43750e0589d2473cf..0000000000000000000000000000000000000000
--- a/src/tests/p4/probe/probe-tfs/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# rust-tfs
-Client for TFS functionalities written in Rust.
diff --git a/src/tests/p4/probe/probe-tfs/target/x86_64-unknown-linux-musl/release/tfsagent b/src/tests/p4/probe/probe-tfs/target/x86_64-unknown-linux-musl/release/tfsagent
deleted file mode 100755
index b7cef11a433c6bf2eeb94638fa90d93f25acd3c8..0000000000000000000000000000000000000000
Binary files a/src/tests/p4/probe/probe-tfs/target/x86_64-unknown-linux-musl/release/tfsagent and /dev/null differ
diff --git a/src/tests/p4/probe/probe-tfs/target/x86_64-unknown-linux-musl/release/tfsping b/src/tests/p4/probe/probe-tfs/target/x86_64-unknown-linux-musl/release/tfsping
deleted file mode 100755
index 6e943d292dd6653e857bf5eea3258d38ad246026..0000000000000000000000000000000000000000
Binary files a/src/tests/p4/probe/probe-tfs/target/x86_64-unknown-linux-musl/release/tfsping and /dev/null differ
diff --git a/src/webui/service/__init__.py b/src/webui/service/__init__.py
index f137c247e1c4d2f4be5707e72e4140ab75f8e886..4c39e3c033717d1e6e48120a5ebf27fd327ecac9 100644
--- a/src/webui/service/__init__.py
+++ b/src/webui/service/__init__.py
@@ -21,7 +21,8 @@ from context.client.ContextClient import ContextClient
 from device.client.DeviceClient import DeviceClient
 from qkd_app.client.QKDAppClient import QKDAppClient
 from common.Settings import (
-    is_deployed_bgpls, is_deployed_load_gen, is_deployed_policy, is_deployed_qkd_app, is_deployed_slice
+    is_deployed_bgpls, is_deployed_load_gen, is_deployed_optical,
+    is_deployed_policy, is_deployed_qkd_app, is_deployed_slice
 )
 
 def get_working_context() -> str:
@@ -86,34 +87,43 @@ def create_app(use_config=None, web_app_root=None):
     
     app.register_blueprint(healthz, url_prefix='/healthz')
 
-    from webui.service.js.routes import js                   # pylint: disable=import-outside-toplevel
+    from webui.service.js.routes import js                          # pylint: disable=import-outside-toplevel
     app.register_blueprint(js)
 
-    from webui.service.main.routes import main               # pylint: disable=import-outside-toplevel
+    from webui.service.main.routes import main                      # pylint: disable=import-outside-toplevel
     app.register_blueprint(main)
 
-    from webui.service.load_gen.routes import load_gen       # pylint: disable=import-outside-toplevel
+    from webui.service.load_gen.routes import load_gen              # pylint: disable=import-outside-toplevel
     app.register_blueprint(load_gen)
 
-    from webui.service.service.routes import service         # pylint: disable=import-outside-toplevel
+    from webui.service.base_optical.route import base_optical       # pylint: disable=import-outside-toplevel
+    app.register_blueprint(base_optical)
+
+    from webui.service.opticalconfig.routes import opticalconfig    # pylint: disable=import-outside-toplevel
+    app.register_blueprint(opticalconfig)
+
+    from webui.service.optical_link.routes import optical_link      # pylint: disable=import-outside-toplevel
+    app.register_blueprint(optical_link)
+
+    from webui.service.service.routes import service                # pylint: disable=import-outside-toplevel
     app.register_blueprint(service)
 
-    from webui.service.slice.routes import slice             # pylint: disable=import-outside-toplevel,redefined-builtin
+    from webui.service.slice.routes import slice                    # pylint: disable=import-outside-toplevel,redefined-builtin
     app.register_blueprint(slice)
 
-    from webui.service.device.routes import device           # pylint: disable=import-outside-toplevel
+    from webui.service.device.routes import device                  # pylint: disable=import-outside-toplevel
     app.register_blueprint(device)
     
-    from webui.service.bgpls.routes import bgpls             # pylint: disable=import-outside-toplevel
+    from webui.service.bgpls.routes import bgpls                    # pylint: disable=import-outside-toplevel
     app.register_blueprint(bgpls)
 
-    from webui.service.link.routes import link               # pylint: disable=import-outside-toplevel
+    from webui.service.link.routes import link                      # pylint: disable=import-outside-toplevel
     app.register_blueprint(link)
 
-    from webui.service.qkd_app.routes import qkd_app         # pylint: disable=import-outside-toplevel
+    from webui.service.qkd_app.routes import qkd_app                # pylint: disable=import-outside-toplevel
     app.register_blueprint(qkd_app)
 
-    from webui.service.policy_rule.routes import policy_rule # pylint: disable=import-outside-toplevel
+    from webui.service.policy_rule.routes import policy_rule        # pylint: disable=import-outside-toplevel
     app.register_blueprint(policy_rule)
 
     app.jinja_env.globals.update({              # pylint: disable=no-member
@@ -126,6 +136,7 @@ def create_app(use_config=None, web_app_root=None):
 
         'is_deployed_bgpls'   : is_deployed_bgpls,
         'is_deployed_load_gen': is_deployed_load_gen,
+        'is_deployed_optical' : is_deployed_optical,
         'is_deployed_policy'  : is_deployed_policy,
         'is_deployed_qkd_app' : is_deployed_qkd_app,
         'is_deployed_slice'   : is_deployed_slice,
diff --git a/src/webui/service/base_optical/__init__.py b/src/webui/service/base_optical/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ee6f7071f145e06c3aeaefc09a43ccd88e619e3
--- /dev/null
+++ b/src/webui/service/base_optical/__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/webui/service/base_optical/route.py b/src/webui/service/base_optical/route.py
new file mode 100644
index 0000000000000000000000000000000000000000..84fb8a97572e9e6f9f2056cae3ad9087a7390720
--- /dev/null
+++ b/src/webui/service/base_optical/route.py
@@ -0,0 +1,33 @@
+# 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 flask import render_template, Blueprint
+#from common.proto.context_pb2 import Empty, OpticalConfigList
+#from context.client.ContextClient import ContextClient
+#from device.client.DeviceClient import DeviceClient
+
+base_optical = Blueprint('base_optical', __name__, url_prefix='/base_optical')
+#device_client = DeviceClient()
+#context_client = ContextClient()
+
+@base_optical.get('/')
+def home():
+    # context_client.connect()
+    # opticalConfig_list:OpticalConfigList = context_client.GetOpticalConfig(Empty())
+    # context_client.close()
+    # device_client.connect()
+    # device_client.GetDeviceConfiguration(opticalConfig_list)
+    # device_client.close()
+    return render_template("base_optical/home.html")
diff --git a/src/webui/service/main/routes.py b/src/webui/service/main/routes.py
index 52944a31c439472055d65e9e75249465dcbca7f7..97c97331d415b8c2d059f5bb65236ba6563d48c3 100644
--- a/src/webui/service/main/routes.py
+++ b/src/webui/service/main/routes.py
@@ -153,11 +153,24 @@ def topology():
                 'source': link.link_endpoint_ids[0].device_id.device_uuid.uuid,
                 'target': link.link_endpoint_ids[1].device_id.device_uuid.uuid,
             })
-
-        return jsonify({'devices': devices, 'links': links})
+            
+        optical_links = []
+        for link in response.optical_links:
+            if len(link.link_endpoint_ids) != 2:
+                str_link = grpc_message_to_json_string(link)
+                LOGGER.warning('Unexpected link with len(endpoints) != 2: {:s}'.format(str_link))
+                continue
+            optical_links.append({
+                'id': link.link_id.link_uuid.uuid,
+                'name': link.name,
+                'source': link.link_endpoint_ids[0].device_id.device_uuid.uuid,
+                'target': link.link_endpoint_ids[1].device_id.device_uuid.uuid,
+            })    
+      
+        return jsonify({'devices': devices, 'links': links, 'optical_links': optical_links})
     except: # pylint: disable=bare-except
         LOGGER.exception('Error retrieving topology')
-        return jsonify({'devices': [], 'links': []})
+        return jsonify({'devices': [], 'links': [], 'optical_links': []})
     finally:
         context_client.close()
 
diff --git a/src/webui/service/optical_link/__init__.py b/src/webui/service/optical_link/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c7568fdb6e3b1446aa9412ad32a0a5948ba949b
--- /dev/null
+++ b/src/webui/service/optical_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/webui/service/optical_link/routes.py b/src/webui/service/optical_link/routes.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc4ed8c6a14d31512398341984029f07fc2bcc6c
--- /dev/null
+++ b/src/webui/service/optical_link/routes.py
@@ -0,0 +1,108 @@
+# 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 flask import current_app, render_template, Blueprint, flash, session, redirect, url_for
+from common.proto.context_pb2 import Empty, OpticalLink, LinkId, OpticalLinkList
+from common.tools.context_queries.EndPoint import get_endpoint_names
+from common.tools.context_queries.Topology import get_topology
+from context.client.ContextClient import ContextClient
+
+optical_link = Blueprint('optical_link', __name__, url_prefix='/optical_link')
+context_client = ContextClient()
+
+@optical_link.get('/')
+def home():
+    if 'context_uuid' not in session or 'topology_uuid' not in session:
+        flash("Please select a context!", "warning")
+        return redirect(url_for("main.home"))
+
+    context_uuid = session['context_uuid']
+    topology_uuid = session['topology_uuid']
+
+    links, endpoint_ids = list(), list()
+    device_names, endpoints_data = dict(), dict()
+
+    context_client.connect()
+    grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False)
+    if grpc_topology is None:
+        flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger')
+    else:
+        grpc_links : OpticalLinkList = context_client.GetOpticalLinkList(Empty())
+        for link_ in grpc_links.optical_links:
+            links.append(link_)
+            endpoint_ids.extend(link_.link_endpoint_ids)
+        device_names, endpoints_data = get_endpoint_names(context_client, endpoint_ids)
+    context_client.close()
+
+    return render_template(
+        'optical_link/home.html', links=links, device_names=device_names,
+        endpoints_data=endpoints_data
+    )
+
+
+@optical_link.route('detail/<path:link_uuid>', methods=('GET', 'POST'))
+def detail(link_uuid: str):
+    context_client.connect()
+    # pylint: disable=no-member
+    link_id = LinkId()
+    link_id.link_uuid.uuid = link_uuid
+    link_obj = context_client.GetOpticalLink(link_id)
+    c_slots=s_slots=l_slots=None
+    if link_obj is None:
+        flash('Optical Link({:s}) not found'.format(str(link_uuid)), 'danger')
+        link_obj = OpticalLink()
+        device_names, endpoints_data = dict(), dict()
+    else:
+        device_names, endpoints_data = get_endpoint_names(context_client, link_obj.link_endpoint_ids)
+        c_slots = link_obj.optical_details.c_slots
+        l_slots = link_obj.optical_details.l_slots
+        s_slots = link_obj.optical_details.s_slots
+
+    context_client.close()
+
+    return render_template(
+        'optical_link/detail.html', link=link_obj, device_names=device_names,
+        endpoints_data=endpoints_data, c_slots=c_slots, l_slots=l_slots, s_slots=s_slots
+    )
+
+
+@optical_link.get('<path:link_uuid>/delete')
+def delete(link_uuid):
+    try:
+        request = LinkId()
+        request.link_uuid.uuid = link_uuid # pylint: disable=no-member
+        context_client.connect()
+        context_client.DeleteOpticalLink(request)
+        context_client.close()
+
+        flash(f'Optical Link "{link_uuid}" deleted successfully!', 'success')
+    except Exception as e: # pylint: disable=broad-except
+        flash(f'Problem deleting link "{link_uuid}": {e.details()}', 'danger')
+        current_app.logger.exception(e)
+    return redirect(url_for('optical_link.home'))
+
+
+@optical_link.get("delete_all")
+def delete_all():
+    try:
+        context_client.connect()
+        optical_link_list : OpticalLinkList = context_client.GetOpticalLinkList(Empty())
+        for optical_link in optical_link_list.optical_links:
+            context_client.DeleteOpticalLink(optical_link.link_id)
+        context_client.close()
+        flash(f"All Optical Link Deleted Successfully",'success')
+    except Exception as e:
+        flash(f"Problem in delete all optical link  => {e}",'danger')
+    return redirect(url_for('optical_link.home'))
diff --git a/src/webui/service/opticalconfig/__init__.py b/src/webui/service/opticalconfig/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3ee6f7071f145e06c3aeaefc09a43ccd88e619e3
--- /dev/null
+++ b/src/webui/service/opticalconfig/__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/webui/service/opticalconfig/forms.py b/src/webui/service/opticalconfig/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..e9cb283eb00e07fa6ad10e78c377d921ac4c506d
--- /dev/null
+++ b/src/webui/service/opticalconfig/forms.py
@@ -0,0 +1,41 @@
+# 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 flask_wtf import FlaskForm
+from wtforms import StringField, SelectField, SubmitField
+
+class UpdateDeviceForm(FlaskForm):
+   power            = StringField('Power')
+   frequency        = StringField("Frequency")
+   operational_mode = StringField("Operational Mode")
+   line_port        = SelectField("Line Port")
+   submit           = SubmitField('Update')
+
+class AddTrancseiver(FlaskForm):
+   transceiver = StringField("Transceiver")
+   submit      = SubmitField('Add')
+
+class UpdateInterfaceForm(FlaskForm):
+   ip            = StringField("IP Address")
+   prefix_length = StringField("Prefix Length")
+
+DEVICE_STATUS = [
+   ('', 'Select...'),
+   ('DISABLED', 'DISABLED'),
+   ('ENABLED', 'ENABLED')
+]
+
+class UpdateStatusForm(FlaskForm):
+   status = SelectField("Device Status", choices=DEVICE_STATUS)
diff --git a/src/webui/service/opticalconfig/routes.py b/src/webui/service/opticalconfig/routes.py
new file mode 100644
index 0000000000000000000000000000000000000000..79a487a4e80d96d3f6a6bab1e813202e6679ee66
--- /dev/null
+++ b/src/webui/service/opticalconfig/routes.py
@@ -0,0 +1,329 @@
+# 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 flask import (
+    request, redirect, render_template, Blueprint, flash, session, url_for,
+    current_app, make_response
+)
+from common.proto.context_pb2 import (
+    Empty, OpticalConfig, OpticalConfigId, OpticalConfigList
+)
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+from service.client.ServiceClient import ServiceClient
+from slice.client.SliceClient import SliceClient
+from .forms import UpdateDeviceForm, AddTrancseiver, UpdateStatusForm
+from common.tools.context_queries.OpticalConfig import opticalconfig_get_uuid
+
+
+opticalconfig = Blueprint('opticalconfig', __name__,url_prefix="/opticalconfig")
+
+context_client = ContextClient()
+device_client = DeviceClient()
+service_client = ServiceClient()
+slice_client = SliceClient()
+
+LOGGER = logging.getLogger(__name__)
+
+DESCRIPTOR_LOADER_NUM_WORKERS = 10
+
+@opticalconfig.get("/")
+def home() :
+    list_config = []
+    channels_num = 0
+    if 'context_uuid' not in session or 'topology_uuid' not in session:
+        flash("Please select a context!", "warning")
+        return redirect(url_for("main.home"))
+    context_uuid = session['context_uuid']
+    topology_uuid = session['topology_uuid']
+   
+    context_client.connect()
+    opticalConfig_list : OpticalConfigList = context_client.GetOpticalConfig(Empty())
+    for configs in opticalConfig_list.opticalconfigs:
+        value = json.loads(configs.config) if type(configs.config)==str else configs.config
+        config_type = value["type"]
+        if 'channels' in value:
+            channels_num = len(value['channels']) 
+            value["channels_number"] = channels_num
+        # value['operationalMode']=value['operational-mode']
+        # value['targetOutputPower']=value['target-output-power']
+        value['opticalconfig_id']=configs.opticalconfig_id
+        # value['line_port']=value["line-port"]
+        list_config.append(value)
+
+    context_client.close()
+    return render_template('opticalconfig/home.html', config=list_config)
+
+@opticalconfig.route('<path:config_uuid>/detail',methods=['GET'])    
+def show_details(config_uuid):
+    opticalconfigId = OpticalConfigId()
+    opticalconfigId.opticalconfig_uuid = config_uuid
+    device_details = []
+    
+    context_client.connect()
+    response = context_client.SelectOpticalConfig(opticalconfigId)
+    context_client.close()
+    if (response and response.opticalconfig_id.opticalconfig_uuid !=''):
+        opticalConfig = OpticalConfig()
+        opticalConfig.CopyFrom(response)
+            
+        device_name = ""
+        config = json.loads(opticalConfig.config)
+        if "device_name" in config:
+            device_name = config["device_name"]
+
+        config_type = config["type"]
+        if config_type == 'optical-transponder':
+            if 'channels' in config:
+                for channel in config['channels'] :
+                    new_config = {
+                        "name"             : channel['name'],
+                        'operationalMode'  : channel['operational-mode'] if 'operational-mode' in channel else '',
+                        'targetOutputPower': channel['target-output-power'] if 'target-output-power' in channel else '',
+                        "frequency"        : channel['frequency'] if 'frequency' in channel else '',
+                        'line_port'        : channel["line-port"] if 'line-port' in channel else '',
+                        "status"           : channel['status'] if 'status' in channel else "",
+                    }
+                    device_details.append(new_config)
+
+        if config_type == 'optical-roadm':
+            if 'channels' in config:
+                for channel in config['channels'] :
+                    new_config = {
+                        "band_name"           : channel['band_name'] if 'band_name' in channel else None,
+                        'type'                : channel['type'] if 'type' in channel else '',
+                        'src_port'            : channel['src_port'] if 'src_port' in channel else '',
+                        'dest_port'           : channel['dest_port'] if 'dest_port' in channel else '',
+                        "lower_frequency"     : channel['lower_frequency'] if 'lower_frequency' in channel else '',
+                        "upper_frequency"     : channel['upper_frequency'] if 'upper_frequency' in channel else '',
+                        "status"              : channel['status'] if 'status' in channel else "",
+                        'optical_band_parent' : channel['optical_band_parent'] if 'optical_band_parent' in channel else '',
+                        'channel_index'       : channel['channel_index'] if 'channel_index' in channel else '',
+                    }
+                    device_details.append(new_config)
+
+    return render_template(
+        'opticalconfig/details.html', device=device_details, config_id=config_uuid,
+        device_name=device_name, type=config_type
+    )
+
+
+@opticalconfig.route('<path:opticalconfig_uuid>/delete', methods=['GET'])
+def delete_opitcalconfig (opticalconfig_uuid)  :
+    try : 
+        opticalconfigId = OpticalConfigId()
+        opticalconfigId.opticalconfig_uuid = opticalconfig_uuid
+        context_client.connect()
+        context_client.DeleteOpticalConfig(opticalconfigId)
+        context_client.close()
+        flash(f'OpticalConfig "{opticalconfig_uuid}" deleted successfully!', 'success')
+    except Exception as e: # pylint: disable=broad-except
+        flash(f'Problem deleting optical config {opticalconfig_uuid}', 'danger')
+        current_app.logger.exception(e)
+    return redirect(url_for('opticalconfig.home'))
+
+
+@opticalconfig.route('/update_opticalconfig', methods=['POST'])
+def update_externally():
+    if (request.method == 'POST'):
+        data = request.get_json()
+        devices = data.get('devices')
+
+        myResponse = []
+        status_code = ''
+        for device in devices :
+            port = device.get("port")
+            channel_name = f"channel-{port}"
+            device_name = device.get("device_name")
+        
+            if device_name:
+                opticalconfig_uuid = opticalconfig_get_uuid(device_name=device_name)
+                opticalconfigId=OpticalConfigId()
+                opticalconfigId.opticalconfig_uuid = opticalconfig_uuid
+                context_client.connect()
+                opticalconfig = context_client.SelectOpticalConfig(opticalconfigId)
+                context_client.close()
+            
+                if opticalconfig and opticalconfig.opticalconfig_id.opticalconfig_uuid != '' :
+                    new_opticalconfig = OpticalConfig()
+                    new_opticalconfig.CopyFrom(opticalconfig)
+                    config = json.loads(opticalconfig.config)
+                    channels = config['channels']
+                    target_channel = next((item for item in channels if item["name"]['index'] == channel_name) , None)
+                    target_power = device.get( "target-output-power")
+                    freq = device.get("frequency")
+                    mode = device.get("operational-mode")
+                    status = device.get("status","ENABLED")
+
+                    if target_channel:
+                        if target_power is not None :
+                            target_channel["target-output-power"] =str(target_power)
+                        if freq  is not None :
+                            target_channel["frequency"] = freq
+                        if mode is not None :
+                            target_channel["operational-mode"] = mode
+                        if status is not None :
+                            target_channel["status"] = "ENABLED"
+                        #del target_channel['name']
+                        config["new_config"]=target_channel
+                        config["new_config"]["channel_name"]=channel_name
+                        config["flow"]=[(port,'0')]
+                        opticalconfig.config =json.dumps(config)
+
+                        try:
+                            device_client.connect()
+                            device_client.ConfigureOpticalDevice(opticalconfig)
+                            device_client.close()
+
+                            myResponse.append(f"device {device_name} port {port} is updated successfully")
+                            status_code = 200
+                        except Exception as e: # pylint: disable=broad-except
+                            myResponse.append(f"Problem updating the device. {e}")
+                            status_code = 500 
+                            break   
+                    else :
+                        myResponse.append(f"requested channel {channel_name} is not existed")
+                        status_code = 400
+                        break         
+                else :
+                    myResponse.append(f"requested device {device_name} is not existed")
+                    status_code = 400
+                    break              
+
+        response=make_response(f'{myResponse}')
+        response.status_code=status_code
+        return response
+
+        #return redirect(url_for('opticalconfig.show_details',config_uuid=opticalconfig_uuid))
+        #return redirect(url_for('opticalconfig.home'))
+    
+@opticalconfig.route('<path:config_uuid>/<path:channel_name>/update', methods=['GET', 'POST'])
+def update(config_uuid, channel_name):
+    form = UpdateDeviceForm()
+
+    opticalconfigId = OpticalConfigId()
+    opticalconfigId.opticalconfig_uuid = config_uuid
+    context_client.connect()
+    response = context_client.SelectOpticalConfig(opticalconfigId)
+    context_client.close()
+
+    opticalconfig = OpticalConfig()
+    opticalconfig.CopyFrom(response)
+    config =json.loads(opticalconfig.config)
+    new_config={}
+    for channel in config['channels']:
+        if (channel["name"] == channel_name):
+            new_config=channel
+            form.frequency.default = channel["frequency"]
+            form.operational_mode.default=channel["operational-mode"]
+            form.power.default=channel["target-output-power"]
+            form.line_port.choices = [("","")]
+
+    for transceiver in config["transceivers"]['transceiver']:
+        form.line_port.choices.append((transceiver,transceiver))
+
+    # listing enum values
+    if form.validate_on_submit():
+        new_config["target-output-power"] =form.power.data if form.power.data != '' else  new_config['target-output-power']
+        new_config["frequency"]=form.frequency.data if form.frequency.data != '' else new_config['frequency']
+        new_config["operational-mode"]=form.operational_mode.data if form.operational_mode.data != '' else new_config['operational-mode']
+        new_config["line-port"]=form.line_port.data if form.line_port.data != '' else new_config['line-port']
+        opticalconfig.config =json.dumps(new_config)
+
+        try:
+            device_client.connect()
+            device_client.ConfigureOpticalDevice(opticalconfig)
+            device_client.close()
+            flash(f' device  was updated.', 'success')
+            return redirect(url_for('opticalconfig.show_details',config_uuid=config_uuid))
+        except Exception as e: # pylint: disable=broad-except
+             flash(f'Problem updating the device. {e}', 'danger')  
+    return render_template('device/update.html', device=response, form=form, submit_text='Update Device',channel_name=channel_name)
+
+
+@opticalconfig.route('refresh_all',methods=['POST','GET'])
+def refresh_all ():
+    context_client.connect()
+    opticalConfig_list:OpticalConfigList = context_client.GetOpticalConfig(Empty())
+    context_client.close()
+    device_client.connect()
+    device_client.GetDeviceConfiguration(opticalConfig_list)
+    device_client.close()
+    return home()
+
+
+@opticalconfig.route('<path:config_uuid>/add_transceiver', methods=['GET','POST'])
+def add_transceiver (config_uuid):
+    config={}
+    addtrancseiver=AddTrancseiver()
+    opticalconfigId=OpticalConfig()
+    opticalconfigId.opticalconfig_uuid=config_uuid
+    context_client.connect()
+    response = context_client.SelectOpticalConfig(opticalconfigId)
+    context_client.close()
+    opticlConfig=OpticalConfig()
+    opticlConfig.CopyFrom(response)
+   
+    if addtrancseiver.validate_on_submit():
+        config["add_transceiver"]=addtrancseiver.transceiver.data
+        opticlConfig.config=json.dumps(config)
+       
+        try:
+            device_client.connect()
+            device_client.ConfigureOpticalDevice(opticlConfig)
+            device_client.close()
+            flash(f' device  was updated.', 'success')
+            return redirect(url_for('opticalconfig.update',config_uuid=config_uuid))
+        except Exception as e: # pylint: disable=broad-except
+             flash(f'Problem updating the device. {e}', 'danger')  
+    return render_template('opticalconfig/add_transceiver.html',form=addtrancseiver, submit_text='Add Trancseiver')         
+
+
+@opticalconfig.route('<path:config_uuid>/<path:channel_name>/update_status', methods=['GET','POST'])
+def update_status (config_uuid,channel_name):
+    config = {}
+    form = UpdateStatusForm()
+
+    opticalconfigId=OpticalConfigId()
+    opticalconfigId.opticalconfig_uuid=config_uuid
+    context_client.connect()
+    response = context_client.SelectOpticalConfig(opticalconfigId)
+    context_client.close()
+    opticlConfig=OpticalConfig()
+    opticlConfig.CopyFrom(response)
+    config=json.loads(opticlConfig.config)
+    new_config={}
+    port=""
+    if form.validate_on_submit():
+        if channel_name:
+            port = channel_name.split('-')[1]
+        new_config["status"]=form.status.data
+        new_config["name"]=channel_name
+        config["flow"]=[(port,'0')]
+        config["new_config"]=new_config
+        opticlConfig.config=json.dumps(config)
+
+        try:
+            device_client.connect()
+            device_client.ConfigureOpticalDevice(opticlConfig)
+            device_client.close()
+            flash(f' device  was updated.', 'success')
+            return redirect(url_for('opticalconfig.show_details',config_uuid=config_uuid))
+        except Exception as e: # pylint: disable=broad-except
+             flash(f'Problem updating the device. {e}', 'danger')  
+    return render_template(
+        'opticalconfig/update_status.html', form=form, channel_name=channel_name,
+        submit_text='Update Device Status'
+    )
diff --git a/src/webui/service/templates/base.html b/src/webui/service/templates/base.html
index 432f1a095be1a682624a45decf2355310e58238b..1402f40c43f3066b0cb09017dfb81f0e4911333f 100644
--- a/src/webui/service/templates/base.html
+++ b/src/webui/service/templates/base.html
@@ -90,6 +90,16 @@
                   </li>
                 {% endif %}
 
+                {% if is_deployed_optical() %}
+                  <li class="nav-item">
+                    {% if '/base_optical/' in request.path %}
+                    <a class="nav-link active" aria-current="page" href="{{ url_for('base_optical.home') }}">Optical Config</a>
+                    {% else %}
+                    <a class="nav-link" href="{{ url_for('base_optical.home') }}">Optical Config</a>
+                    {% endif %}
+                  </li>
+                {% endif %}
+
                 {% if is_deployed_policy() %}
                   <li class="nav-item">
                     {% if '/policy_rule/' in request.path %}
diff --git a/src/webui/service/templates/base_optical/home.html b/src/webui/service/templates/base_optical/home.html
new file mode 100644
index 0000000000000000000000000000000000000000..6c1e55b140f28e8bfdc60162a77b8756f6cee7a3
--- /dev/null
+++ b/src/webui/service/templates/base_optical/home.html
@@ -0,0 +1,36 @@
+<!--
+    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.
+   -->
+
+   {% extends 'base.html' %}
+
+   {% block content %}
+       <h1>Optical Configurations</h1>
+   
+       <div class="row">
+          <div class="col">
+            <a href="{{ url_for('opticalconfig.home') }}" class="btn btn-primary" style="margin-bottom: 10px;">
+              
+                  Optical Devices
+            </a>
+          </div>
+          <div class="col">
+            <a href="{{ url_for('optical_link.home') }}" class="btn btn-primary" style="margin-bottom: 10px;">
+              
+                  Optical Links
+            </a>
+          </div>
+       </div>
+   {% endblock %}
diff --git a/src/webui/service/templates/js/topology.js b/src/webui/service/templates/js/topology.js
index caba65fe5359fb64499408886c36c30377cfbbeb..8f5a383c6e90467f8a00df22c8bfb223f3b1e841 100644
--- a/src/webui/service/templates/js/topology.js
+++ b/src/webui/service/templates/js/topology.js
@@ -51,7 +51,7 @@ const svg = d3.select('#topology')
         ;
 
 // svg objects
-var link, node;
+var link, node, optical_link;
 
 // values for all forces
 forceProperties = {
@@ -85,6 +85,23 @@ d3.json("{{ url_for('main.topology') }}", function(data) {
         .attr("stroke-dasharray", function(l) {
             return l.name.toLowerCase().includes('mgmt') ? "5,5" : "0";
         });
+
+     optical_link = svg.append("g").attr("class", "links").style('stroke', '#aaa')
+         .selectAll("line")
+         .data(data.optical_links)
+         .enter()
+         .append("line")
+         .attr("opacity", 1)
+         .attr("stroke", function(l) {
+             return l.name.toLowerCase().includes('mgmt') ? '#AAAAAA' : '#555555';
+         })
+         .attr("stroke-width", function(l) {
+             return l.name.toLowerCase().includes('mgmt') ? 1 : 2;
+         })
+         .attr("stroke-dasharray", function(l) {
+             return l.name.toLowerCase().includes('mgmt') ? "5,5" : "0";
+         });   
+
     node = svg.append("g").attr("class", "devices").attr('r', 20).style('fill', '#69b3a2')
         .selectAll("circle")
         .data(data.devices)
@@ -101,6 +118,8 @@ d3.json("{{ url_for('main.topology') }}", function(data) {
     node.append("title").text(function(n) { return n.name; });
     // link tooltip
     link.append("title").text(function(l) { return l.name; });
+    // optical link tooltip
+    optical_link.append("title").text(function(l) { return l.name; });
 
     // link style
     //link
@@ -116,7 +135,14 @@ d3.json("{{ url_for('main.topology') }}", function(data) {
             .id(function(d) {return d.id;})
             .distance(forceProperties.link.distance)
             .iterations(forceProperties.link.iterations)
-            .links(forceProperties.link.enabled ? data.links : []))
+            .links(forceProperties.link.enabled ? data.links.length>0? data.links :[]:[]))
+//  ------------------    Experimental : Optical link part 
+        .force("link", d3.forceLink()
+            .id(function(d) {return d.id;})
+            .distance(forceProperties.link.distance)
+            .iterations(forceProperties.link.iterations)
+            .links(forceProperties.link.enabled ?  data.optical_links.length>0?data.optical_links:[]:[])) 
+
         .force("charge", d3.forceManyBody()
             .strength(forceProperties.charge.strength * forceProperties.charge.enabled)
             .distanceMin(forceProperties.charge.distanceMin)
@@ -147,6 +173,12 @@ function ticked() {
         .attr('x2', function(d) { return d.target.x; })
         .attr('y2', function(d) { return d.target.y; });
 
+    optical_link
+        .attr('x1', function(d) { return d.source.x; })
+        .attr('y1', function(d) { return d.source.y; })
+        .attr('x2', function(d) { return d.target.x; })
+        .attr('y2', function(d) { return d.target.y; });
+
     node
         .attr('x', function(d) { return d.x-icon_width/2; })
         .attr('y', function(d) { return d.y-icon_height/2; });
diff --git a/src/webui/service/templates/optical_link/detail.html b/src/webui/service/templates/optical_link/detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..d8274e6dfde59b29801bb3d49010285c48eeee25
--- /dev/null
+++ b/src/webui/service/templates/optical_link/detail.html
@@ -0,0 +1,158 @@
+<!--
+    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.
+   -->
+
+{% extends 'base.html' %}
+
+{% block content %}
+<h1>Link {{ link.name }} ({{ link.link_id.link_uuid.uuid }})</h1>
+<div class="row mb-3">
+    <div class="col-sm-3">
+        <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('optical_link.home') }}'">
+            <i class="bi bi-box-arrow-in-left"></i>
+            Back to link list
+        </button>
+    </div>
+    <div class="col-sm-3">
+        <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete link</button> -->
+        <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
+            <i class="bi bi-x-square"></i>
+            Delete link
+        </button>
+    </div>
+</div>
+
+<br>
+<div class="row mb-3">
+    <div class="col-sm-4">
+        <b>UUID: </b>{{ link.link_id.link_uuid.uuid }}<br>
+        <b>Name: </b>{{ link.name }}<br>
+    </div>
+    <div class="col-sm-8">
+        <table class="table table-striped table-hover">
+            <thead>
+                <tr>
+                    <th scope="col">Endpoint UUID</th>
+                    <th scope="col">Name</th>
+                    <th scope="col">Device</th>
+                    <th scope="col">Endpoint Type</th>
+                </tr>
+            </thead>
+            <tbody>
+                {% for endpoint in link.link_endpoint_ids %}
+                <tr>
+                    <td>
+                        {{ endpoint.endpoint_uuid.uuid }}
+                    </td>
+                    <td>
+                        {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, (endpoint.endpoint_uuid.uuid, ''))[0] }}
+                    </td>
+                    <td>
+                        <a href="{{ url_for('device.detail', device_uuid=endpoint.device_id.device_uuid.uuid) }}">
+                            {{ device_names.get(endpoint.device_id.device_uuid.uuid, endpoint.device_id.device_uuid.uuid) }}
+                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16">
+                                    <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
+                                    <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
+                            </svg>
+                        </a>
+                    </td>
+                    <td>
+                        {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, ('', '-'))[1] }}
+                    </td>
+                </tr>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
+</div>
+
+
+
+<b>Optical Link Detail:</b>
+<table class="table table-striped table-hover">
+    <thead>
+        <tr>
+            <th scope="col">Key</th>
+            <th scope="col">Value</th>
+        </tr>
+    </thead>
+    <tbody>
+        {% for field_descriptor, field_value in link.optical_details.ListFields() %}
+            {% if  field_descriptor.name != "c_slots" and  field_descriptor.name != "s_slots" and  field_descriptor.name != "l_slots" %}
+            <tr>
+                <td>
+                    {{ field_descriptor.name }}
+                </td>
+                <td>
+                    {{ field_value }}
+                </td>
+            </tr>
+            {%endif%}
+        {% endfor %}
+        {%if c_slots %}
+        <tr>
+            <td>
+                c_slots
+            </td>
+            <td>
+                {{ c_slots }}
+            </td>
+        </tr>
+        {%endif%}
+        {%if l_slots %}
+        <tr>
+            <td>
+                l_slots
+            </td>
+            <td>
+                {{ l_slots }}
+            </td>
+        </tr>
+        {%endif%}
+        {%if s_slots %}
+        <tr>
+            <td>
+                s_slots
+            </td>
+            <td>
+                {{ s_slots }}
+            </td>
+        </tr>
+        {%endif%}
+    </tbody>
+</table>
+<!-- Modal -->
+<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
+    aria-labelledby="staticBackdropLabel" aria-hidden="true">
+    <div class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title" id="staticBackdropLabel">Delete link?</h5>
+                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+            </div>
+            <div class="modal-body">
+                Are you sure you want to delete the link "{{ link.link_id.link_uuid.uuid }}"?
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">No</button>
+                <a type="button" class="btn btn-danger"
+                    href="{{ url_for('optical_link.delete', link_uuid=link.link_id.link_uuid.uuid) }}"><i
+                        class="bi bi-exclamation-diamond"></i>Yes</a>
+            </div>
+        </div>
+    </div>
+</div>
+
+{% endblock %}
diff --git a/src/webui/service/templates/optical_link/home.html b/src/webui/service/templates/optical_link/home.html
new file mode 100644
index 0000000000000000000000000000000000000000..2f1b8e4af149bee70524943233800d2eb5a740d5
--- /dev/null
+++ b/src/webui/service/templates/optical_link/home.html
@@ -0,0 +1,122 @@
+<!--
+    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.
+-->
+
+{% extends 'base.html' %}
+   
+   {% block content %}
+       <h1>Optical Links</h1>
+   
+       <div class="row">
+
+           <div class="col">
+               {{ links | length }} links found in context <i>{{ session['context_uuid'] }}</i>
+           </div>
+           <div class="col-sm-3">
+            <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete link</button> -->
+            <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
+                <i class="bi bi-x-square"></i>
+                Delete All Optical Links
+            </button>
+        </div>
+           <!-- <div class="col">
+               <form>
+                   <div class="input-group">
+                       <input type="text" aria-label="Search" placeholder="Search..." class="form-control"/>
+                       <button type="submit" class="btn btn-primary">Search</button>
+                     </div>
+               </form>
+           </div> -->
+       </div>
+   
+       <table class="table table-striped table-hover">
+           <thead>
+             <tr>
+               <th scope="col">UUID</th>
+               <th scope="col">Name</th>
+               <th scope="col">Endpoints</th>
+               <th scope="col"></th>
+             </tr>
+           </thead>
+           <tbody>
+               {% if links %}
+                   {% for link in links %}
+                   <tr>
+                       <td>
+                            {{ link.link_id.link_uuid.uuid }}
+                       </td>
+                       <td>
+                            {{ link.name }}
+                        </td>
+
+                       <td>
+                           <ul>
+                               {% for endpoint in link.link_endpoint_ids %}
+                               <li>
+                                   {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, (endpoint.endpoint_uuid.uuid, ''))[0] }} / 
+                                   Device: 
+                                   <a href="{{ url_for('device.detail', device_uuid=endpoint.device_id.device_uuid.uuid) }}">
+                                       {{ device_names.get(endpoint.device_id.device_uuid.uuid, endpoint.device_id.device_uuid.uuid) }}
+                                       <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16">
+                                           <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
+                                           <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
+                                       </svg>
+                                   </a>
+                               </li>
+                               {% endfor %}
+                           </ul>
+                       </td>
+   
+                       <td> 
+                            <a href="{{ url_for('optical_link.detail', link_uuid=link.link_id.link_uuid.uuid) }}">
+                               <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16">
+                                   <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
+                                   <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
+                               </svg> 
+                           </a>
+                       </td>
+                   </tr>
+                   {% endfor %}
+               {% else %}
+                   <tr>
+                       <td colspan="7">No links found</td>
+                   </tr>
+               {% endif %}
+           </tbody>
+
+       </table>
+   
+<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
+    aria-labelledby="staticBackdropLabel" aria-hidden="true">
+    <div class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title" id="staticBackdropLabel">Delete All Optical links?</h5>
+                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+            </div>
+            <div class="modal-body">
+                Are you sure you want to delete all the links ?
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">No</button>
+                <a type="button" class="btn btn-danger"
+                    href="{{ url_for('optical_link.delete_all') }}"><i
+                        class="bi bi-exclamation-diamond"></i>Yes</a>
+            </div>
+        </div>
+    </div>
+</div>
+
+{% endblock %}
diff --git a/src/webui/service/templates/opticalconfig/add_transceiver.html b/src/webui/service/templates/opticalconfig/add_transceiver.html
new file mode 100644
index 0000000000000000000000000000000000000000..d10faa7f146fcef18c4f865fe969cf6620e13c15
--- /dev/null
+++ b/src/webui/service/templates/opticalconfig/add_transceiver.html
@@ -0,0 +1,56 @@
+<!--
+ 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.
+-->
+
+{% extends 'base.html' %}
+
+{% block content %}
+<h1>Add Transceiver </h1>
+<br />
+<form id="Add_transceiver" method="POST">
+    {{ form.hidden_tag() }}
+    <fieldset>
+        <div class="row mb-3 ">
+            <div class="col-12">
+            {{ form.transceiver.label(class="col-sm-2 col-form-label") }}
+            <div class="col-sm-10">
+                {% if form.transceiver.errors %}
+                {{ form.transceiver(class="form-control is-invalid") }}
+                <div class="invalid-feedback">
+                    {% for error in form.transceiver.errors %}
+                    <span>{{ error }}</span>
+                    {% endfor %}
+                </div>
+                {% else %}
+
+                {{ form.transceiver(class="col-sm-7 form-control") }}
+    
+                {% endif %}
+            </div>
+        
+        </div> 
+        <button type="submit" class="btn btn-primary">
+            <i class="bi bi-plus-circle-fill"></i>
+            {{ submit_text }}
+        </button>
+        <button type="button" class="btn btn-block btn-secondary" onclick="javascript: history.back()">
+            <i class="bi bi-box-arrow-in-left"></i>
+            Cancel
+        </button>
+    </div>
+    </fieldset>
+</form>
+
+{% endblock %}
diff --git a/src/webui/service/templates/opticalconfig/details.html b/src/webui/service/templates/opticalconfig/details.html
new file mode 100644
index 0000000000000000000000000000000000000000..70b17331097f24733729345d252ce1090e568018
--- /dev/null
+++ b/src/webui/service/templates/opticalconfig/details.html
@@ -0,0 +1,152 @@
+<!--
+ 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.
+-->
+
+
+
+{% extends 'base.html' %}
+
+{% block content %}
+
+
+<h1>Optical Configurations</h1>
+
+<div class="row">
+ 
+  {% if device %}
+  <div class="col-sm-12">
+    <span>Device ID:</span>
+    <h5>{{config_id}}</h5>
+  </div>
+  <div class="col-sm-12">
+  <div class="col-sm-12">
+    <div class="row mb-3 ">
+
+        <div class="col-sm-3">
+          <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('opticalconfig.home') }}'">
+              <i class="bi bi-box-arrow-in-left"></i>
+              Back to device list
+          </button>
+        </div>
+        <div class="col-sm-3">
+          <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete device</button> -->
+          <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
+              <i class="bi bi-x-square"></i>
+              Delete Optical Config
+          </button>
+      </div>
+    </div>
+  </div>
+  <div class="col-sm-12">
+    <span>Device Name:</span>
+    <span>{{device_name}}</span>
+    </div>
+  
+  </div>
+
+              {% if type == 'optical-transponder' %}
+                  <table class="table table-striped table-hover">
+                        <thead>
+                          <tr>
+                            <th scope="col">channel name</th>
+                            <th scope="col">Frequency</th>
+                            <th scope="col">Target Output Power</th>
+                            <th scope="col">Operational Mode</th>
+                            <th scope="col">Line Port</th>
+                            <th scope="col">Channel Status</th>
+                          </tr>
+                        </thead>
+                        <tbody>
+                    
+                            {% for channel in device %}
+                            <tr style="background-color:{%if channel.status == 'DISABLED' %} gray {% endif %};">
+                              <td>{{channel.name.index}}</td>
+                              <td>{{channel.frequency}}</td>
+                              <td> {{channel.targetOutputPower}}</td>
+                              <td>{{channel.operationalMode}}</td>
+                              <td>{{channel.line_port}}</td>
+                              <td> {{channel.status}}</td>
+                            </tr>
+                            {% endfor %}
+                        </tbody>
+                  </table>
+              {%else%}     
+                  <table class="table table-striped table-hover">
+                    <thead>
+                      <tr>
+                        <th scope="col">Channel Index</th>
+                        <th scope="col">Optical Band Parent</th>
+                        <th scope="col">Band Name</th>
+                        <th scope="col">Lower Frequency</th>
+                        <th scope="col">Upper Frequency</th>
+                        <th scope="col">type</th>
+                        <th scope="col"> Source Port</th>
+                        <th scope="col">Destination Port</th>
+                        <th scope="col">Channel Status </th>
+                      
+                      </tr>
+                    </thead>
+                    <tbody>
+                
+                      {% for channel in device %} 
+                            <tr>
+                                <td>{{channel.channel_index}}</td>
+                                <td>{{channel.optical_band_parent}}</td>
+                                <td> {{channel.band_name}}</td>
+                                <td>{{channel.lower_frequency}}</td>
+                                <td>{{channel.upper_frequency}}</td>
+                                <td> {{channel.type}}</td>
+                                <td>{{channel.src_port}}</td>
+                                <td>{{channel.dest_port}}</td>
+                                <td> {{channel.status}}</td> 
+                              
+                            </tr>
+                            {% endfor %}
+                    
+                    </tbody>
+                  </table>
+                  
+              {% endif%}
+
+</div>
+
+{% else %}
+<div class="col">
+  <h4 colspan="7">No devices found</h4>
+</div>
+{% endif %}
+<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
+    aria-labelledby="staticBackdropLabel" aria-hidden="true">
+    <div class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title" id="staticBackdropLabel">Delete Optical Config?</h5>
+                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+            </div>
+            <div class="modal-body">
+                Are you sure you want to delete the Optical Config "{{config_id}}"?
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">No</button>
+                <a type="button" class="btn btn-danger"
+                    href="{{ url_for('opticalconfig.delete_opitcalconfig', opticalconfig_uuid=config_id) }}"><i
+                        class="bi bi-exclamation-diamond"></i>Yes</a>
+            </div>
+        </div>
+    </div>
+</div>
+</div>
+
+{% endblock %}
diff --git a/src/webui/service/templates/opticalconfig/home.html b/src/webui/service/templates/opticalconfig/home.html
new file mode 100644
index 0000000000000000000000000000000000000000..a8127de5b3eec45d8e3e09d2561939814b65df46
--- /dev/null
+++ b/src/webui/service/templates/opticalconfig/home.html
@@ -0,0 +1,113 @@
+<!--
+    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.
+-->
+  
+{% extends 'base.html' %}
+
+{% block content %}
+    <h1>Optical Configurations</h1>
+    {% if config %}
+    <div class="row">
+        <div class="col-sm-12">
+            <div class="row mb-3 ">
+        
+                <div class="col-sm-3">
+                  <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('base_optical.home') }}'">
+                      <i class="bi bi-box-arrow-in-left"></i>
+                      Back to main
+                  </button>
+                </div>
+                <div class="col-sm-3">
+                  <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete device</button> -->
+                  <!-- <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
+                      <i class="bi bi-x-square"></i>
+                      Delete All
+                  </button> -->
+                    <button type="button" class="btn btn-info" 
+                    onclick="window.location.href='{{ url_for('opticalconfig.refresh_all') }}'">
+                    <i class="bi bi-arrow-clockwise"></i>
+                        Refresh
+                    </button>
+              </div>
+            </div>
+          </div>
+     
+        
+         <table class="table table-striped table-hover">
+            <thead>
+              <tr>
+                <th scope="col">UUID</th>
+                <th scope="col">Device Name</th>
+                <th scope="col">Device Type</th>
+                <th scope="col">Channels Number</th>
+               
+              </tr>
+            </thead>
+            <tbody>
+       
+                    {% for device in config %}
+                    <tr>
+                        <td>{{device.opticalconfig_id.opticalconfig_uuid}}</td>
+                        <td>{{device.device_name}}</td>
+                        <td> {{device.type}}</td>
+                        {% if device.channels_number %}
+                        <td>{{ device.channels_number }}</td>
+                        {%else%}
+                          <td>__ </td>
+                        {%endif%}
+                        {% if device.opticalconfig_id %}
+                        <td>
+                            <a href="{{ url_for('opticalconfig.show_details', config_uuid=device.opticalconfig_id.opticalconfig_uuid) }}">
+                                <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16">
+                                    <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
+                                    <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
+                                </svg>
+                            </a>
+                        </td>
+                        {%endif%}
+                    </tr>
+                    {% endfor %}
+             
+            </tbody>
+        </table>
+         
+        </div>
+     
+        {% else %}
+        <div class="col">
+            <h4 colspan="7">No devices found</h4>
+        </div>
+        {% endif %}
+        <!-- <div class="col">
+            <a href="{{ url_for('service.add') }}" class="btn btn-primary" style="margin-bottom: 10px;">
+                <i class="bi bi-plus"></i>
+                Add New Service
+            </a>
+        </div> -->
+
+        <!-- Only display XR service addition button if there are XR constellations. Otherwise it might confuse
+             user, as other service types do not have GUI to add service yet. -->
+      
+        <!-- <div class="col">
+            <form>
+                <div class="input-group">
+                    <input type="text" aria-label="Search" placeholder="Search..." class="form-control"/>
+                    <button type="submit" class="btn btn-primary">Search</button>
+                  </div>
+            </form>
+        </div> -->
+    </div>
+
+{% endblock %}
diff --git a/src/webui/service/templates/opticalconfig/update_interface.html b/src/webui/service/templates/opticalconfig/update_interface.html
new file mode 100644
index 0000000000000000000000000000000000000000..5c9b7b79c419861b287b0e4aae17e60cfbda18cc
--- /dev/null
+++ b/src/webui/service/templates/opticalconfig/update_interface.html
@@ -0,0 +1,90 @@
+<!--
+ 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.
+-->
+
+{% extends 'base.html' %}
+
+{% block content %}
+<div class="col-sm-12 d-flex flex-column">
+
+    <h1>Update Device {{ device.opticalconfig_id.opticalconfig_uuid }}</h1>
+    <h2> interface :{{interface_name}}</h2>
+</div>
+<br />
+<form id="update_device" method="POST">
+    {{ form.hidden_tag() }}
+    <fieldset>
+        <div class="row mb-3 ">
+            <div class="col-12">
+                {{ form.ip.label(class="col-sm-2 col-form-label") }}
+                <div class="col-sm-10">
+                    {% if form.ip.errors %}
+                    {{ form.ip(class="form-control is-invalid") }}
+                    <div class="invalid-feedback">
+                        {% for error in form.ip.errors %}
+                        <span>{{ error }}</span>
+                        {% endfor %}
+                    </div>
+                    {% else %}
+
+                    {{ form.ip(class="col-sm-7 form-control") }}
+
+                    {% endif %}
+                </div>
+            </div>
+            <div class="col-12 ">
+                {{ form.prefix_length.label(class="col-sm-2 col-form-label") }}
+                <div class="col-sm-10">
+                    {% if form.prefix_length.errors %}
+                    {{ form.prefix_length(class="form-control is-invalid") }}
+                    <div class="invalid-feedback">
+                        {% for error in form.prefix_length.errors %}
+                        <span>{{ error }}</span>
+                        {% endfor %}
+                    </div>
+                    {% else %}
+
+
+                    {{ form.prefix_length(class="col-sm-7 form-control") }}
+
+                    {% endif %}
+                </div>
+
+
+            </div>
+        </div>
+        <div class="col-sm-12">
+            <div class="row">
+                <div class="col-sm-3">
+
+                    <button type="submit" class="btn btn-primary">
+                        <i class="bi bi-plus-circle-fill"></i>
+                        update interface
+                    </button>
+                </div>
+                <div class="col-sm-3 mx-1">
+
+                    <button type="button" class="btn btn-block btn-secondary" onclick="javascript: history.back()">
+                        <i class="bi bi-box-arrow-in-left"></i>
+                        Cancel
+                    </button>
+                </div>
+            </div>
+        </div>
+        </div>
+    </fieldset>
+</form>
+
+{% endblock %}
diff --git a/src/webui/service/templates/opticalconfig/update_status.html b/src/webui/service/templates/opticalconfig/update_status.html
new file mode 100644
index 0000000000000000000000000000000000000000..e52bfbebbe29813a49841829c57f66862baf77f8
--- /dev/null
+++ b/src/webui/service/templates/opticalconfig/update_status.html
@@ -0,0 +1,67 @@
+<!--
+ 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.
+-->
+
+{% extends 'base.html' %}
+
+{% block content %}
+<h1>Update Channel Status </h1>
+<br />
+<div>
+    channel : <span class="font-weight-bold">{{channel_name}}</span>
+</div>
+<form id="update_status" method="POST">
+    {{ form.hidden_tag() }}
+    <fieldset>
+        <div class="row mb-3 ">
+            <div class="col-12">
+            {{ form.status.label(class="col-sm-2 col-form-label") }}
+            <div class="col-sm-10">
+                {% if form.status.errors %}
+                {{ form.status(class="form-control is-invalid") }}
+                <div class="invalid-feedback">
+                    {% for error in form.status.errors %}
+                    <span>{{ error }}</span>
+                    {% endfor %}
+                </div>
+                {% else %}
+
+                {{ form.status(class="col-sm-7 form-control") }}
+    
+                {% endif %}
+            </div>
+        
+        </div> 
+        <div class="row gx-2">
+            <div class="col-5">
+                <button type="submit" class="btn btn-primary" >
+                    <i class="bi bi-plus-circle-fill"></i>
+                    {{ submit_text }}
+                </button>
+                <div class="col-5">
+  
+                    <button type="button" class="btn btn-block btn-secondary" onclick="javascript: history.back()">
+                        <i class="bi bi-box-arrow-in-left"></i>
+                        Cancel
+                    </button>
+                </div>
+            </div>
+        </div>
+      
+    </div>
+    </fieldset>
+</form>
+
+{% endblock %}