diff --git a/deploy/tfs.sh b/deploy/tfs.sh
index 3a01606ce32369d0f0968282569eaf4ed59d778c..19c0d75a095bc5dc239d1d95237378bcf2fbb8da 100755
--- a/deploy/tfs.sh
+++ b/deploy/tfs.sh
@@ -364,7 +364,7 @@ for COMPONENT in $TFS_COMPONENTS; do
     echo "Waiting for '$COMPONENT' component..."
     COMPONENT_OBJNAME=$(echo "${COMPONENT}" | sed "s/\_/-/")
     kubectl wait --namespace $TFS_K8S_NAMESPACE \
-        --for='condition=available' --timeout=300s deployment/${COMPONENT_OBJNAME}service
+        --for='condition=available' --timeout=90s deployment/${COMPONENT_OBJNAME}service
     printf "\n"
 done
 
diff --git a/manifests/opticalcontrollerservice.yaml b/manifests/opticalcontrollerservice.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4b677ee4f7287b0790aaa0b19f034db03978fac0
--- /dev/null
+++ b/manifests/opticalcontrollerservice.yaml
@@ -0,0 +1,72 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: opticalcontrollerservice
+spec:
+  selector:
+    matchLabels:
+      app: opticalcontrollerservice
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: opticalcontrollerservice
+    spec:
+      terminationGracePeriodSeconds: 5
+      containers:
+      - name: server
+        image:  localhost:32000/tfs/opticalcontroller:dev
+        imagePullPolicy: Never
+        ports:
+        - containerPort: 10060
+        - containerPort: 9192
+        env:
+        - name: LOG_LEVEL
+          value: "INFO"
+        #readinessProbe:
+        #  exec:
+        #    command: ["/bin/grpc_health_probe", "-addr=:10060"]
+        #livenessProbe:
+        #  exec:
+        #    command: ["/bin/grpc_health_probe", "-addr=:10060"]
+        resources:
+          requests:
+            cpu: 500m
+            memory: 128Mi
+          limits:
+            cpu: 1000m
+            memory: 1024Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: opticalcontrollerservice
+  labels:
+    app: opticalcontrollerservice
+spec:
+  type: ClusterIP
+  selector:
+    app: opticalcontrollerservice
+  ports:
+  - name: grpc
+    protocol: TCP
+    port: 10060
+    targetPort: 10060
+  - name: metrics
+    protocol: TCP
+    port: 9192
+    targetPort: 9192
diff --git a/my_deploy.sh b/my_deploy.sh
index 0c5ba03c5b9f63038a622f44ab2dfaaf1e7e6ada..7dd5e5c3ee13cbce2b701b5b4e703823dfb2c28f 100755
--- a/my_deploy.sh
+++ b/my_deploy.sh
@@ -25,9 +25,12 @@ export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_gene
 # Uncomment to activate Monitoring
 #export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring"
 
-# Uncomment to activate bgpls_speaker
+# Uncomment to activate BGP-LS Speaker
 #export TFS_COMPONENTS="${TFS_COMPONENTS} bgpls_speaker"
 
+# Uncomment to activate Optical Controller
+#export TFS_COMPONENTS="${TFS_COMPONENTS} opticalcontroller"
+
 # Uncomment to activate ZTP
 #export TFS_COMPONENTS="${TFS_COMPONENTS} ztp"
 
diff --git a/ofc24 b/ofc24
new file mode 120000
index 0000000000000000000000000000000000000000..baae92c8e249f4abfbbcf9739c9162087fefbacd
--- /dev/null
+++ b/ofc24
@@ -0,0 +1 @@
+src/tests/ofc24/
\ No newline at end of file
diff --git a/proto/context.proto b/proto/context.proto
index d5022ac292f04cd2e9b80f690be3077e7aedd868..8a6b019dc99863da32631425d954afbaf167f1b7 100644
--- a/proto/context.proto
+++ b/proto/context.proto
@@ -74,6 +74,16 @@ service ContextService {
   rpc SetConnection      (Connection    ) returns (       ConnectionId    ) {}
   rpc RemoveConnection   (ConnectionId  ) returns (       Empty           ) {}
   rpc GetConnectionEvents(Empty         ) returns (stream ConnectionEvent ) {}
+
+ 
+  // ------------------------------ Experimental -----------------------------
+  rpc GetOpticalConfig   (Empty          ) returns (OpticalConfigList     ) {}
+  rpc SetOpticalConfig   (OpticalConfig  ) returns (OpticalConfigId       ) {}
+  rpc SelectOpticalConfig(OpticalConfigId) returns (OpticalConfig         ) {}
+
+  rpc SetOpticalLink     (OpticalLink    ) returns (Empty                 ) {}
+  rpc GetOpticalLink     (OpticalLinkId  ) returns (OpticalLink           ) {}
+  rpc GetFiber           (FiberId        ) returns (Fiber                 ) {}
 }
 
 // ----- Generic -------------------------------------------------------------------------------------------------------
@@ -203,6 +213,7 @@ enum DeviceDriverEnum {
   DEVICEDRIVER_GNMI_OPENCONFIG = 8;
   DEVICEDRIVER_FLEXSCALE = 9;
   DEVICEDRIVER_IETF_ACTN = 10;
+  DEVICEDRIVER_OC = 11;
 }
 
 enum DeviceOperationalStatusEnum {
@@ -288,6 +299,7 @@ enum ServiceTypeEnum {
   SERVICETYPE_TAPI_CONNECTIVITY_SERVICE = 3;
   SERVICETYPE_TE = 4;
   SERVICETYPE_E2E = 5;
+  SERVICETYPE_OPTICAL_CONNECTIVITY = 6;
 }
 
 enum ServiceStatusEnum {
@@ -612,3 +624,53 @@ message AuthenticationResult {
   ContextId context_id = 1;
   bool authenticated = 2;
 }
+
+// ---------------- Experimental ------------------------
+message OpticalConfigId {
+  string opticalconfig_uuid = 1;
+}
+message OpticalConfig {
+  OpticalConfigId opticalconfig_id = 1;
+  string config = 2;
+}
+
+message OpticalConfigList {
+  repeated OpticalConfig opticalconfigs = 1;
+}
+
+// ---- Optical Link ----
+
+message OpticalLinkId {
+  Uuid optical_link_uuid = 1;
+}
+
+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 OpticalLinkDetails {
+  float length = 1;
+  string source = 2;
+  string target = 3;
+  repeated Fiber fibers = 4;
+}
+
+message OpticalLink {
+  string name = 1;
+  OpticalLinkDetails details = 2;
+  OpticalLinkId optical_link_uuid = 3;
+}
diff --git a/proto/openconfig_device.proto b/proto/openconfig_device.proto
new file mode 100644
index 0000000000000000000000000000000000000000..913ac247eaab89efb7d6de9f64b2730378937738
--- /dev/null
+++ b/proto/openconfig_device.proto
@@ -0,0 +1,23 @@
+// Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto3";
+package openconfig_device;
+
+import "context.proto";
+
+service OpenConfigService {
+  rpc AddOpenConfigDevice   (context.OpticalConfig) returns (context.OpticalConfigId) {}
+  rpc ConfigureOpticalDevice(context.OpticalConfig) returns (context.Empty          ) {}
+}
diff --git a/scripts/show_logs_opticalcontroller.sh b/scripts/show_logs_opticalcontroller.sh
new file mode 100755
index 0000000000000000000000000000000000000000..17af5483c59e4d97a5534b388d006f5be00030e5
--- /dev/null
+++ b/scripts/show_logs_opticalcontroller.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+########################################################################################################################
+# Define your deployment settings here
+########################################################################################################################
+
+# If not already set, set the name of the Kubernetes namespace to deploy to.
+export TFS_K8S_NAMESPACE=${TFS_K8S_NAMESPACE:-"tfs"}
+
+########################################################################################################################
+# Automated steps start here
+########################################################################################################################
+
+kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/opticalcontrollerservice -c server
diff --git a/src/common/Constants.py b/src/common/Constants.py
index c7ba01f69978fd3c601dcfe30180015d524b1100..a1913a951aeaa968a594fc3bafcb49581459a0e0 100644
--- a/src/common/Constants.py
+++ b/src/common/Constants.py
@@ -59,6 +59,7 @@ class ServiceNameEnum(Enum):
     TE                     = 'te'
     FORECASTER             = 'forecaster'
     E2EORCHESTRATOR        = 'e2eorchestrator'
+    OPTICALCONTROLLER      = 'opticalcontroller'
     BGPLS                  = 'bgpls-speaker'
 
     # Used for test and debugging only
@@ -87,6 +88,7 @@ DEFAULT_SERVICE_GRPC_PORTS = {
     ServiceNameEnum.TE                     .value : 10030,
     ServiceNameEnum.FORECASTER             .value : 10040,
     ServiceNameEnum.E2EORCHESTRATOR        .value : 10050,
+    ServiceNameEnum.OPTICALCONTROLLER      .value : 10060,
     ServiceNameEnum.BGPLS                  .value : 20030,
 
     # Used for test and debugging only
diff --git a/src/common/tools/descriptor/Tools.py b/src/common/tools/descriptor/Tools.py
index b4a76ff4f00d0f6886895cca0ab6f27f7aa8aa43..e95fc756052bf792f0009518b19991b8e87bac68 100644
--- a/src/common/tools/descriptor/Tools.py
+++ b/src/common/tools/descriptor/Tools.py
@@ -15,6 +15,7 @@
 import copy, json
 from typing import Dict, List, Optional, Tuple, Union
 from common.DeviceTypes import DeviceTypeEnum
+from common.proto.context_pb2 import DeviceDriverEnum
 
 def get_descriptors_add_contexts(contexts : List[Dict]) -> List[Dict]:
     contexts_add = copy.deepcopy(contexts)
@@ -95,7 +96,8 @@ def split_devices_by_rules(devices : List[Dict]) -> Tuple[List[Dict], List[Dict]
 
         if len(connect_rules) > 0:
             device_add = copy.deepcopy(device)
-            device_add['device_endpoints'] = []
+            if (device['device_drivers'][0] != DeviceDriverEnum.DEVICEDRIVER_OC):
+                device_add['device_endpoints'] = []
             device_add['device_config'] = {'config_rules': connect_rules}
             devices_add.append(device_add)
 
diff --git a/src/context/client/ContextClient.py b/src/context/client/ContextClient.py
index 13d9dc0035b45845bf11367e02c8830b5151c1d6..48a635cccd19f5985721a6a737fb8a2e5bd260b2 100644
--- a/src/context/client/ContextClient.py
+++ b/src/context/client/ContextClient.py
@@ -26,7 +26,9 @@ from common.proto.context_pb2 import (
     Link, LinkEvent, LinkId, LinkIdList, LinkList,
     Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList,
     Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList,
-    Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList)
+    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
 from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule
@@ -436,3 +438,26 @@ class ContextClient:
         response = self.policy_stub.RemovePolicyRule(request)
         LOGGER.debug('RemovePolicyRule result: {:s}'.format(grpc_message_to_json_string(response)))
         return response
+
+    #//////////////// Experimental //////////////////
+
+    @RETRY_DECORATOR
+    def SetOpticalConfig(self, request : OpticalConfig) -> OpticalConfigId:
+        LOGGER.debug('SetOpticalConfig request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.stub.SetOpticalConfig(request)
+        LOGGER.debug('SetOpticalConfig result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
+
+    @RETRY_DECORATOR
+    def GetOpticalConfig(self, request : Empty) -> OpticalConfigList:
+        LOGGER.debug('GetOpticalConfig request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.stub.GetOpticalConfig(request)
+        LOGGER.debug('GetOpticalConfig result: {:s}'.format(grpc_message_to_json_string(response)))
+        return response
+
+    @RETRY_DECORATOR
+    def SelectOpticalConfig(self,request : OpticalConfigId) -> OpticalConfigList:
+        LOGGER.debug('SelectOpticalConfig request: {:s}'.format(grpc_message_to_json_string(request)))
+        response = self.stub.SelectOpticalConfig(request)
+        LOGGER.debug('SelectOpticalConfig 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 5aad7f9c9ff3a6fd063b1f364256e760f47e1c33..a102fa17629bd866d96883230a542a6e7a4d92ff 100644
--- a/src/context/service/ContextServiceServicerImpl.py
+++ b/src/context/service/ContextServiceServicerImpl.py
@@ -23,7 +23,9 @@ from common.proto.context_pb2 import (
     Link, LinkEvent, LinkId, LinkIdList, LinkList,
     Service, ServiceEvent, ServiceFilter, ServiceId, ServiceIdList, ServiceList,
     Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList,
-    Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList)
+    Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList,
+    OpticalConfigList, OpticalConfigId, OpticalConfig
+)
 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
@@ -43,6 +45,7 @@ from .database.Slice import (
     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
 
 LOGGER = logging.getLogger(__name__)
 
@@ -296,3 +299,22 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer
     @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
     def RemovePolicyRule(self, request : PolicyRuleId, context: grpc.ServicerContext) -> Empty:
         return policyrule_delete(self.db_engine, self.messagebroker, request)
+
+    # ---------------------------- Experimental -------------------
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def GetOpticalConfig(self, request : Empty, context : grpc.ServicerContext) -> OpticalConfigList:
+        result = get_opticalconfig(self.db_engine)
+        return OpticalConfigList(OpticalConfigs=result)
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def SetOpticalConfig(self, request : OpticalConfig, context : grpc.ServicerContext) -> OpticalConfigId:
+        result = set_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)
+        optical_config_id = OpticalConfigId()
+        optical_config_id.CopyFrom(result.OpticalConfig_id)
+        return OpticalConfig(config=result.config, OpticalConfig_id=optical_config_id)
diff --git a/src/context/service/database/Device.py b/src/context/service/database/Device.py
index 3aff20ade14532dcb7fbf8ec1033c084aaeead3c..737ad7add7a27580503e7f812e3064b879c191b5 100644
--- a/src/context/service/database/Device.py
+++ b/src/context/service/database/Device.py
@@ -21,7 +21,9 @@ from typing import Dict, List, Optional, Set, Tuple
 from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException
 from common.message_broker.MessageBroker import MessageBroker
 from common.proto.context_pb2 import (
-    Device, DeviceFilter, DeviceId, DeviceIdList, DeviceList, Empty, EventTypeEnum, TopologyId)
+    Device, DeviceDriverEnum, DeviceFilter, DeviceId, DeviceIdList, DeviceList,
+    Empty, EventTypeEnum, TopologyId
+)
 from common.tools.grpc.Tools import grpc_message_to_json_string
 from common.tools.object_factory.Device import json_device_id
 from context.service.database.uuids.Topology import topology_get_uuid
@@ -103,10 +105,12 @@ 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)
+
     endpoints_data : List[Dict] = list()
     for i, endpoint in enumerate(request.device_endpoints):
         endpoint_device_uuid = endpoint.endpoint_id.device_id.device_uuid.uuid
-        if len(endpoint_device_uuid) == 0: endpoint_device_uuid = device_uuid
+        if len(endpoint_device_uuid) == 0 or is_oc_driver : endpoint_device_uuid = device_uuid
         if endpoint_device_uuid not in {raw_device_uuid, device_uuid}:
             raise InvalidArgumentException(
                 'request.device_endpoints[{:d}].device_id.device_uuid.uuid'.format(i), endpoint_device_uuid,
diff --git a/src/context/service/database/OpticalConfig.py b/src/context/service/database/OpticalConfig.py
new file mode 100644
index 0000000000000000000000000000000000000000..9e7552bc111e40245bb649d2eb1ffa910c6f8588
--- /dev/null
+++ b/src/context/service/database/OpticalConfig.py
@@ -0,0 +1,88 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 sqlalchemy.dialects.postgresql import insert
+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
+
+LOGGER = logging.getLogger(__name__)
+
+def get_opticalconfig(db_engine : Engine):
+    def callback(session:Session):
+        optical_configs = list()
+        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_configs.append(optical_config)
+        return optical_configs
+    obj = run_transaction(sessionmaker(bind=db_engine), callback)
+    return obj
+
+def set_opticalconfig(db_engine : Engine, request : OpticalConfig):
+    opticalconfig_id = OpticalConfigId()
+    opticalconfig_id.opticalconfig_uuid = request.opticalconfig_id.opticalconfig_uuid
+    my_config_data = []
+    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 '',
+            }
+        ]
+
+    def callback(session:Session)->bool:
+        stmt = insert(OpticalConfigModel).values(my_config_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)
+        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 callback(session : Session) -> OpticalConfig:
+        result = OpticalConfig()
+        stmt = session.query(OpticalConfigModel)
+        stmt = stmt.filter_by(opticalconfig_uuid=request.opticalconfig_uuid)
+        obj = stmt.first()
+        if obj is not None:
+            result.config = json.dumps(obj.dump())
+            result.opticalconfig_id.opticalconfig_uuid = obj.opticalconfig_uuid
+        return result
+    return run_transaction(sessionmaker(bind=db_engine, expire_on_commit=False), callback)
diff --git a/src/context/service/database/Service.py b/src/context/service/database/Service.py
index fc196ddded291aa82c8f9df932c15611d13121e4..337bf592f785db97d5924aa7da17772c35eac1b2 100644
--- a/src/context/service/database/Service.py
+++ b/src/context/service/database/Service.py
@@ -20,7 +20,9 @@ from sqlalchemy.orm import Session, selectinload, sessionmaker
 from sqlalchemy_cockroachdb import run_transaction
 from typing import Dict, List, Optional, Set
 from common.proto.context_pb2 import (
-    ContextId, Empty, EventTypeEnum, Service, ServiceFilter, ServiceId, ServiceIdList, ServiceList)
+    ContextId, Empty, EventTypeEnum, Service, ServiceFilter, ServiceId, ServiceIdList,
+    ServiceList, ServiceTypeEnum
+)
 from common.message_broker.MessageBroker import MessageBroker
 from common.method_wrappers.ServiceExceptions import InvalidArgumentException, NotFoundException
 from common.tools.object_factory.Context import json_context_id
@@ -84,6 +86,9 @@ def service_set(db_engine : Engine, messagebroker : MessageBroker, request : Ser
     context_uuid,service_uuid = service_get_uuid(request.service_id, service_name=service_name, allow_random=True)
 
     service_type = grpc_to_enum__service_type(request.service_type)
+    if service_type is None and request.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+        service_type = "OPTICAL_CONNECTIVITY"
+
     service_status = grpc_to_enum__service_status(request.service_status.service_status)
 
     now = datetime.datetime.utcnow()
diff --git a/src/context/service/database/models/OpticalConfigModel.py b/src/context/service/database/models/OpticalConfigModel.py
new file mode 100644
index 0000000000000000000000000000000000000000..10cf197f9a8a728b8fd02bdcdaf255677551bf17
--- /dev/null
+++ b/src/context/service/database/models/OpticalConfigModel.py
@@ -0,0 +1,42 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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/enums/DeviceDriver.py b/src/context/service/database/models/enums/DeviceDriver.py
index 8e15bf058599eeed0629fc1249af0d052183db28..2ccdda2725a7f7bb13ba296d4eca25f88b1e73d1 100644
--- a/src/context/service/database/models/enums/DeviceDriver.py
+++ b/src/context/service/database/models/enums/DeviceDriver.py
@@ -33,6 +33,7 @@ class ORM_DeviceDriverEnum(enum.Enum):
     GNMI_OPENCONFIG       = DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG
     FLEXSCALE             = DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE
     IETF_ACTN             = DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN
+    OC                    = DeviceDriverEnum.DEVICEDRIVER_OC
 
 grpc_to_enum__device_driver = functools.partial(
     grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum)
diff --git a/src/context/service/database/models/enums/ServiceType.py b/src/context/service/database/models/enums/ServiceType.py
index ce198f8c1f795f25da547e2d5974059062489709..01ed68c1708dc617a46edc31e94fc07d79e278e1 100644
--- a/src/context/service/database/models/enums/ServiceType.py
+++ b/src/context/service/database/models/enums/ServiceType.py
@@ -28,6 +28,7 @@ class ORM_ServiceTypeEnum(enum.Enum):
     TAPI_CONNECTIVITY_SERVICE = ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE
     TE                        = ServiceTypeEnum.SERVICETYPE_TE
     E2E                       = ServiceTypeEnum.SERVICETYPE_E2E
+    OPTICAL_CONNECTIVITY      = ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY
 
 grpc_to_enum__service_type = functools.partial(
     grpc_to_enum, ServiceTypeEnum, ORM_ServiceTypeEnum)
diff --git a/src/device/client/DeviceClient.py b/src/device/client/DeviceClient.py
index b88727983474f1f815caa959b8ee8ccfb5b3623b..3fde3df778e32df20c863ff110a1eb572f38d177 100644
--- a/src/device/client/DeviceClient.py
+++ b/src/device/client/DeviceClient.py
@@ -15,12 +15,12 @@
 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
+from common.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty,OpticalConfig,OpticalConfigId
 from common.proto.device_pb2 import MonitoringSettings
 from common.proto.device_pb2_grpc import DeviceServiceStub
 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)
@@ -34,12 +34,14 @@ class DeviceClient:
         LOGGER.debug('Creating channel to {:s}...'.format(str(self.endpoint)))
         self.channel = None
         self.stub = None
+        self.openconfig_stub=None
         self.connect()
         LOGGER.debug('Channel created')
 
     def connect(self):
         self.channel = grpc.insecure_channel(self.endpoint)
         self.stub = DeviceServiceStub(self.channel)
+        self.openconfig_stub=OpenConfigServiceStub(self.channel)
 
     def close(self):
         if self.channel is not None: self.channel.close()
@@ -80,3 +82,8 @@ 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
diff --git a/src/device/service/DeviceService.py b/src/device/service/DeviceService.py
index 6d27ef96eef4b93fa7d6ca294d1fd645e815af03..c7868e44579fb27b6eecc6806f64e3bb531d7cd4 100644
--- a/src/device/service/DeviceService.py
+++ b/src/device/service/DeviceService.py
@@ -19,6 +19,8 @@ from common.tools.service.GenericGrpcService import GenericGrpcService
 from .driver_api.DriverInstanceCache import DriverInstanceCache
 from .DeviceServiceServicerImpl import DeviceServiceServicerImpl
 from .monitoring.MonitoringLoops import MonitoringLoops
+from .OpenConfigServicer import OpenConfigServicer
+from common.proto.openconfig_device_pb2_grpc import add_OpenConfigServiceServicer_to_server
 
 # Custom gRPC settings
 # Multiple clients might keep connections alive waiting for RPC methods to be executed.
@@ -31,10 +33,12 @@ class DeviceService(GenericGrpcService):
         super().__init__(port, max_workers=GRPC_MAX_WORKERS, cls_name=cls_name)
         self.monitoring_loops = MonitoringLoops()
         self.device_servicer = DeviceServiceServicerImpl(driver_instance_cache, self.monitoring_loops)
+        self.openconfig_device_servicer=OpenConfigServicer(driver_instance_cache,self.monitoring_loops)
 
     def install_servicers(self):
         self.monitoring_loops.start()
         add_DeviceServiceServicer_to_server(self.device_servicer, self.server)
+        add_OpenConfigServiceServicer_to_server(self.openconfig_device_servicer,self.server)
 
     def stop(self):
         super().stop()
diff --git a/src/device/service/DeviceServiceServicerImpl.py b/src/device/service/DeviceServiceServicerImpl.py
index 3df7c482272804eb2589ed1e7569f0a2e822ad21..76fb6545430f4802d7d37c0c35a35a0539aa200e 100644
--- a/src/device/service/DeviceServiceServicerImpl.py
+++ b/src/device/service/DeviceServiceServicerImpl.py
@@ -20,7 +20,9 @@ from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, get_env_var_name
 from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, safe_and_metered_rpc_method
 from common.method_wrappers.ServiceExceptions import NotFoundException, OperationFailedException
 from common.proto.context_pb2 import (
-    Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link)
+    Device, DeviceConfig, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Link,
+    OpticalConfig, OpticalConfigId
+)
 from common.proto.device_pb2 import MonitoringSettings
 from common.proto.device_pb2_grpc import DeviceServiceServicer
 from common.tools.context_queries.Device import get_device
@@ -29,6 +31,7 @@ from context.client.ContextClient import ContextClient
 from .driver_api._Driver import _Driver
 from .driver_api.DriverInstanceCache import DriverInstanceCache, get_driver
 from .monitoring.MonitoringLoops import MonitoringLoops
+from .drivers.oc_driver.OCDriver import OCDriver
 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,
@@ -58,7 +61,8 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
         device_uuid = request.device_id.device_uuid.uuid
 
         connection_config_rules = check_connect_rules(request.device_config)
-        check_no_endpoints(request.device_endpoints)
+        if request.device_drivers[0] != DeviceDriverEnum.DEVICEDRIVER_OC:
+            check_no_endpoints(request.device_endpoints)
 
         t1 = time.time()
 
@@ -138,6 +142,13 @@ 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:
+                #for endpoint in request.device_endpoints:
+                #    #endpoint.endpoint_id.device_id.CopyFrom(device.device_id)
+                #    pass
+                device.device_endpoints.extend(request.device_endpoints)
 
             device_id = context_client.SetDevice(device)
 
diff --git a/src/device/service/OpenConfigServicer.py b/src/device/service/OpenConfigServicer.py
new file mode 100644
index 0000000000000000000000000000000000000000..1060449f185330faa0a71ff062ad2bbd0086b2e4
--- /dev/null
+++ b/src/device/service/OpenConfigServicer.py
@@ -0,0 +1,95 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 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
+)
+from common.proto.device_pb2_grpc import DeviceServiceServicer
+from common.tools.context_queries.Device import get_device
+from common.tools.mutex_queues.MutexQueues import MutexQueues
+from context.client.ContextClient import ContextClient
+from .driver_api._Driver import _Driver
+from .driver_api.DriverInstanceCache import DriverInstanceCache, get_driver
+from .monitoring.MonitoringLoops import MonitoringLoops
+from .Tools import extract_resources
+from .Tools import check_no_endpoints
+
+LOGGER = logging.getLogger(__name__)
+
+METRICS_POOL = MetricsPool('Device', 'RPC')
+
+METRICS_POOL_DETAILS = MetricsPool('Device', 'execution', labels={
+    'driver': '', 'operation': '', 'step': '',
+})
+
+class OpenConfigServicer(DeviceServiceServicer):
+    def __init__(self, driver_instance_cache : DriverInstanceCache, monitoring_loops : MonitoringLoops) -> None:
+        LOGGER.debug('Creating Servicer...')
+        self.driver_instance_cache = driver_instance_cache
+        self.monitoring_loops = monitoring_loops
+        self.mutex_queues = MutexQueues()
+        LOGGER.debug('Servicer Created')
+
+    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
+    def AddOpenConfigDevice(self, request : OpticalConfig, context : grpc.ServicerContext) -> DeviceId:
+            device_uuid = request.device_id.device_uuid.uuid
+            check_no_endpoints(request.device_endpoints)
+
+            context_client = ContextClient()
+            device = get_device(context_client, device_uuid, rw_copy=True)
+            if device is None:
+                # not in context, create blank one to get UUID, and populate it below
+                device = Device()
+                device.device_id.CopyFrom(request.device_id)            # pylint: disable=no-member
+                device.name = request.name
+                device.device_type = request.device_type
+                device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED
+                device.device_drivers.extend(request.device_drivers)    # pylint: disable=no-member
+                device.device_config.CopyFrom(request.device_config)
+                device.device_endpoints.extend(request.device_endpoints)
+                # pylint: disable=no-member
+                device_id = context_client.SetDevice(device)
+                device = get_device(context_client, device_id.device_uuid.uuid, rw_copy=True)
+
+            # update device_uuid to honor UUID provided by Context
+            device_uuid = device.device_id.device_uuid.uuid
+            self.mutex_queues.wait_my_turn(device_uuid)
+            try:
+                device_id = context_client.SetDevice(device)
+            except Exception as error :
+                LOGGER.debug("error %s",error)    
+
+    @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)
+        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)
+            result = driver.SetConfig(resources=resources,conditions=conditions)
+            #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)    
+        return Empty()
diff --git a/src/device/service/Tools.py b/src/device/service/Tools.py
index b2b206471e07b654e5339f81db632699ae8b95df..f3700e10488228387145a2c4c8574a899675aade 100644
--- a/src/device/service/Tools.py
+++ b/src/device/service/Tools.py
@@ -15,12 +15,14 @@
 import json, logging
 from typing import Any, Dict, List, Optional, Tuple, Union
 from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME
-from common.method_wrappers.ServiceExceptions import InvalidArgumentException
-from common.proto.context_pb2 import ConfigActionEnum, ConfigRule_ACL, Device, DeviceConfig, Link, Location
+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.device_pb2 import MonitoringSettings
 from common.proto.kpi_sample_types_pb2 import KpiSampleType
 from common.tools.grpc.ConfigRules import update_config_rule_custom
 from common.tools.grpc.Tools import grpc_message_to_json
+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 (
@@ -30,6 +32,21 @@ from .ErrorMessages import (
 
 LOGGER = logging.getLogger(__name__)
 
+def get_endpoint_matching(device : Device, endpoint_uuid_or_name : str) -> EndPoint:
+    for endpoint in device.device_endpoints:
+        choices = {endpoint.endpoint_id.endpoint_uuid.uuid, endpoint.name}
+        if endpoint_uuid_or_name in choices: return endpoint
+
+    device_uuid = device.device_id.device_uuid.uuid
+    extra_details = 'Device({:s})'.format(str(device_uuid))
+    raise NotFoundException('Endpoint', endpoint_uuid_or_name, extra_details=extra_details)
+
+def get_device_endpoint_uuids(endpoint : Tuple[str, str, Optional[str]]) -> Tuple[str, str]:
+    chk_type('endpoint', endpoint, (tuple, list))
+    chk_length('endpoint', endpoint, min_length=2, max_length=3)
+    device_uuid, endpoint_uuid = endpoint[0:2] # ignore topology_uuid by now
+    return device_uuid, endpoint_uuid
+
 def check_connect_rules(device_config : DeviceConfig) -> Dict[str, Any]:
     connection_config_rules = dict()
     unexpected_config_rules = list()
@@ -434,3 +451,74 @@ def update_endpoints(src_device : Device, dst_device : Device) -> None:
             dst_topology_id = dst_endpoint_id.topology_id
             if len(src_topology_uuid) > 0: dst_topology_id.topology_uuid.uuid = src_topology_uuid
             if len(src_context_uuid) > 0: dst_topology_id.context_id.context_uuid.uuid = src_context_uuid
+
+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'
+    return 'optical-channel'
+
+def is_key_existed(key : str, keys_dic = dict, key_name_to_use = None) -> dict:
+    dic = {}
+    dic['resource_key'] = key
+    if key_name_to_use is not None:
+        dic['resource_key'] = key_name_to_use
+    if key in keys_dic:
+        dic['value'] = keys_dic[key]
+    else:
+        dic['value'] = None
+    return dic
+
+def extract_resources(config : dict, device : Device) -> list:
+    conditions = {}
+    resources = []
+    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 = []
+        for tuple_value in config['flow']:
+            source_port = None 
+            destination_port = None
+            source_port_uuid, destination_port_uuid = tuple_value
+            if source_port_uuid != '0':
+                src_endpoint_obj = get_endpoint_matching(device, source_port_uuid)
+                source_port = src_endpoint_obj.name
+            source_vals.append(source_port)
+            if destination_port_uuid != '0':
+                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  })
+
+    if 'new_config' in config:
+        lower_frequency = None
+        upper_frequency = None
+        resources.append(is_key_existed('target-output-power', keys_dic=config['new_config']))
+        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('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'))
+        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
+                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:
+            lower_frequency = config['new_config']['low-freq'] if 'low-freq' in config['new_config'] else None
+            upper_frequency = config['new_config']['up-freq' ] if 'up-freq'  in config['new_config'] else None
+            resources.append(is_key_existed('ob_id', keys_dic=config['new_config'], key_name_to_use='index'))
+            #resources.append({'resource_key':'index','value':config['new_config']['ob_id'] if 'ob_id' in config['new_config'] else None})
+        resources.append({'resource_key': 'lower-frequency', 'value': lower_frequency})
+        resources.append({'resource_key': 'upper-frequency', 'value': upper_frequency})
+
+    return [resources, conditions]
diff --git a/src/device/service/driver_api/DriverInstanceCache.py b/src/device/service/driver_api/DriverInstanceCache.py
index 1f92059a63889c002eb28ca7eaecc43199f66794..26735bc16a4f0d70c9299e206bda07c2b10e8c49 100644
--- a/src/device/service/driver_api/DriverInstanceCache.py
+++ b/src/device/service/driver_api/DriverInstanceCache.py
@@ -52,7 +52,12 @@ class DriverInstanceCache:
             driver_class = self._driver_factory.get_driver_class(**filter_fields)
             MSG = 'Driver({:s}) selected for device({:s}) with filter_fields({:s})...'
             LOGGER.info(MSG.format(str(driver_class.__name__), str(device_uuid), str(filter_fields)))
-            driver_instance : _Driver = driver_class(address, port, **settings)
+
+            if driver_class.__name__ == "OCDriver":
+                driver_instance : _Driver = driver_class(address, port, device_uuid=device_uuid, **settings)
+            else:
+                driver_instance : _Driver = driver_class(address, port, **settings)
+
             self._device_uuid__to__driver_instance[device_uuid] = driver_instance
             return driver_instance
 
diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py
index 27c61f89f15c735b44ad2724df01e08a51dda6ba..1e8cff6052d840af2aa57ff22793380f06f16356 100644
--- a/src/device/service/drivers/__init__.py
+++ b/src/device/service/drivers/__init__.py
@@ -167,3 +167,17 @@ if LOAD_ALL_DEVICE_DRIVERS:
                 FilterFieldEnum.DRIVER: DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE,
             }
         ]))
+
+if LOAD_ALL_DEVICE_DRIVERS:
+    from .oc_driver.OCDriver import OCDriver # pylint: disable=wrong-import-position
+    DRIVERS.append(
+        (OCDriver, [
+            {
+                # Real Packet Router, specifying OpenConfig Driver => use OpenConfigDriver
+                FilterFieldEnum.DEVICE_TYPE: [
+                    DeviceTypeEnum.OPTICAL_ROADM,
+                    DeviceTypeEnum.OPTICAL_TRANSPONDER
+                ],
+                FilterFieldEnum.DRIVER     : DeviceDriverEnum.DEVICEDRIVER_OC,
+            }
+        ]))
diff --git a/src/device/service/drivers/oc_driver/OCDriver.py b/src/device/service/drivers/oc_driver/OCDriver.py
new file mode 100644
index 0000000000000000000000000000000000000000..16f00cfb4c7b80d807882ab5b4c95b36b28db8f6
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/OCDriver.py
@@ -0,0 +1,315 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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
+import anytree, copy, 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 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 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 .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 .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
+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)
+logging.getLogger('apscheduler.executors.default').setLevel(logging.INFO if DEBUG_MODE else logging.ERROR)
+logging.getLogger('apscheduler.scheduler').setLevel(logging.INFO if DEBUG_MODE else logging.ERROR)
+logging.getLogger('monitoring-client').setLevel(logging.INFO if DEBUG_MODE else logging.ERROR)
+
+RE_GET_ENDPOINT_FROM_INTERFACE_KEY = re.compile(r'.*interface\[([^\]]+)\].*')
+RE_GET_ENDPOINT_FROM_INTERFACE_XPATH = re.compile(r".*interface\[oci\:name\='([^\]]+)'\].*")
+
+# Collection of samples through NetConf is very slow and each request collects all the data.
+# Populate a cache periodically (when first interface is interrogated).
+# Evict data after some seconds, when data is considered as outdated
+
+SAMPLE_EVICTION_SECONDS = 30.0 # seconds
+SAMPLE_RESOURCE_KEY = 'interfaces/interface/state/counters'
+filter_fields= ["frequency","target-output-power","interface","operational-mode","line-port"]
+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()
+        self.__connected = threading.Event()
+        self.__address = address
+        self.__port = int(port)
+        self.__username         = settings.get('username')
+        self.__password         = settings.get('password')
+        self.__vendor           = settings.get('vendor')
+        self.__version          = settings.get('version', "1")
+        self.__key_filename     = settings.get('key_filename')
+        self.__hostkey_verify   = settings.get('hostkey_verify', True)
+        self.__look_for_keys    = settings.get('look_for_keys', True)
+        self.__allow_agent      = settings.get('allow_agent', True)
+        self.__force_running    = settings.get('force_running', False)
+        self.__commit_per_rule  = settings.get('commit_per_rule', False)
+        self.__device_params    = settings.get('device_params', {})
+        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
+       
+    def connect(self):
+        with self.__lock:
+            self.__manager = connect_ssh(
+                host=self.__address, port=self.__port, username=self.__username, password=self.__password,
+                device_params=self.__device_params, manager_params=self.__manager_params, nc_params=self.__nc_params,
+                key_filename=self.__key_filename, hostkey_verify=self.__hostkey_verify, allow_agent=self.__allow_agent,
+                look_for_keys=self.__look_for_keys)
+            self.__candidate_supported = ':candidate' in self.__manager.server_capabilities
+            self.__connected.set()
+
+    def disconnect(self):
+        if not self.__connected.is_set(): return
+        with self.__lock:
+            self.__manager.close_session()
+
+    @property
+    def use_candidate(self): return self.__candidate_supported and not self.__force_running
+
+    @property
+    def commit_per_rule(self): return self.__commit_per_rule 
+
+    @property
+    def vendor(self): return self.__vendor
+    
+    @property
+    def version(self): return self.__version
+    
+    @property
+    def message_renderer(self): return self.__message_renderer
+
+    @RETRY_DECORATOR
+    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
+    def edit_config(
+        self, config, target='running', default_operation=None, test_option=None,
+        error_option=None, format='xml'                                             # pylint: disable=redefined-builtin
+    ):
+        
+
+        
+        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)
+           
+
+    @RETRY_DECORATOR
+    def locked(self, target):
+        return self.__manager.locked(target=target)
+
+    @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
+    netconf_handler : NetconfSessionHandler, logger : logging.Logger, resources : List[Tuple[str, Any]]
+    ,conditions, delete=False,
+    commit_per_rule=False, target='running', default_operation='merge', test_option=None, error_option=None,
+    format='xml' 
+):
+    #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)
+    
+    
+        
+    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
+        
+        #results[i] = True
+    results.append(True)
+   
+
+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.configure(
+            jobstores = {'default': MemoryJobStore()},
+            executors = {'default': ThreadPoolExecutor(max_workers=1)}, # important! 1 = avoid concurrent requests
+            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.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
+
+    @metered_subclass_method(METRICS_POOL)
+    def GetInitialConfig(self) -> List[Tuple[str, Any]]:
+        with self.__lock:
+            return []
+
+    @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={}
+          
+            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)     
+                            
+         
+            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()   
+                
+        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=[]
+        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
+                                    )
+        return results
+
+    @metered_subclass_method(METRICS_POOL)
+    def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        chk_type('resources', resources, list)
+        if len(resources) == 0: return []
+        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)
+            else:
+                results = edit_config(self.__netconf_handler, self.__logger, resources, delete=True)
+        return results
+
+  
diff --git a/src/device/service/drivers/oc_driver/RetryDecorator.py b/src/device/service/drivers/oc_driver/RetryDecorator.py
new file mode 100644
index 0000000000000000000000000000000000000000..deb1b4ed89346a99e9821f049375a1977914832b
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/RetryDecorator.py
@@ -0,0 +1,46 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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, time
+from common.tools.client.RetryDecorator import delay_linear
+
+LOGGER = logging.getLogger(__name__)
+
+def retry(max_retries=0, delay_function=delay_linear(initial=0, increment=0),
+          prepare_method_name=None, prepare_method_args=[], prepare_method_kwargs={}):
+    def _reconnect(func):
+        def wrapper(self, *args, **kwargs):
+            if prepare_method_name is not None:
+                prepare_method = getattr(self, prepare_method_name, None)
+                if prepare_method is None: raise Exception('Prepare Method ({}) not found'.format(prepare_method_name))
+            num_try, given_up = 0, False
+            while not given_up:
+                try:
+                    return func(self, *args, **kwargs)
+                except OSError as e:
+                    if str(e) != 'Socket is closed': raise
+
+                    num_try += 1
+                    given_up = num_try > max_retries
+                    if given_up: raise Exception('Giving up... {:d} tries failed'.format(max_retries)) from e
+                    if delay_function is not None:
+                        delay = delay_function(num_try)
+                        time.sleep(delay)
+                        LOGGER.info('Retry {:d}/{:d} after {:f} seconds...'.format(num_try, max_retries, delay))
+                    else:
+                        LOGGER.info('Retry {:d}/{:d} immediate...'.format(num_try, max_retries))
+
+                    if prepare_method_name is not None: prepare_method(*prepare_method_args, **prepare_method_kwargs)
+        return wrapper
+    return _reconnect
diff --git a/src/device/service/drivers/oc_driver/Tools.py b/src/device/service/drivers/oc_driver/Tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..d350fd877efcff04ec23f90341fca727b6177ba5
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/Tools.py
@@ -0,0 +1,38 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 hashlib
+import uuid
+import xml.dom.minidom, xmltodict
+
+def xml_pretty_print(data : str):
+    return xml.dom.minidom.parseString(data).toprettyxml()
+
+def xml_to_file(data : str, file_path : str) -> None:
+    with open(file_path, mode='w', encoding='UTF-8') as f:
+        f.write(xml_pretty_print(data))
+
+def xml_to_dict(data : str):
+    return xmltodict.parse(data)
+
+def generate_uuid_from_numbers(code:str) ->str:
+    # Concatenate the numbers into a single string
+
+
+    # Generate a hash value using MD5 algorithm
+    hash_value = hashlib.md5(code.encode()).hexdigest()
+
+    # Convert the hash value into a UUID
+    generated_uuid = uuid.UUID(hash_value)
+
+    return str(generated_uuid)
diff --git a/src/device/service/drivers/oc_driver/__init__.py b/src/device/service/drivers/oc_driver/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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/service/drivers/oc_driver/templates/Interfaces/__init__.py b/src/device/service/drivers/oc_driver/templates/Interfaces/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..355dcdb04bdddd352966a9567a7a63117666e619
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/Interfaces/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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/service/drivers/oc_driver/templates/Interfaces/interfaces.py b/src/device/service/drivers/oc_driver/templates/Interfaces/interfaces.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4df7c2bff7b050e665de9afa5b44a7c6d85db18
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/Interfaces/interfaces.py
@@ -0,0 +1,43 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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
+def interface_template (interface_data:dict) :
+    data={"name":"eth0","ip":"192.168.1.1","prefix-length":'24'}
+    doc, tag, text = Doc().tagtext()
+    with tag('config',xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"):
+        with tag('interfaces', xmlns="http://openconfig.net/yang/interfaces"):
+            with tag('interface'):
+                with tag('name'):text(interface_data['name'])
+                with tag('config'):
+                    with tag('name'):text(interface_data['name'])
+                    with tag("enabled"):text(interface_data["enabled"])
+                with tag('ipv4',xmlns="http://openconfig.net/yang/interfaces/ip") :
+                    with tag("addresses"):
+                        with tag("address"):
+                            with tag('ip'):text(interface_data["ip"])
+                            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
diff --git a/src/device/service/drivers/oc_driver/templates/Tools.py b/src/device/service/drivers/oc_driver/templates/Tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..909bdd83bf4c189da0a778268ce40119cca7c452
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/Tools.py
@@ -0,0 +1,257 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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
+
+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
+    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
+
+"""
+# Method Name: generate_templates
+  
+# Parameters:
+  - resource_key:   [str]  Variable to identify the rule to be executed.
+  - resource_value: [str]  Variable with the configuration parameters of the rule to be executed.
+  - delete:         [bool] Variable to identify whether to create or delete the rule.
+  - vendor:         [str]  Variable to identify the vendor of the equipment to be configured.
+  
+# Functionality:
+  This method generates the template to configure the equipment using pyangbind. 
+  To generate the template the following steps are performed:
+  1) Get the first parameter of the variable "resource_key" to identify the main path of the rule.
+  2) Search for the specific configuration path
+  3) Call the method with the configuration parameters (resource_data variable). 
+  
+# Return:
+  [dict] Set of templates generated according to the configuration rule
+"""
+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_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)
+
+    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:
+       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 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=[]
+    if (is_opticalband):
+        endpoints=channel_names
+    else:
+            
+        for channel_name in channel_names:
+            dic={}
+            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)  
+            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={})
+   
+    return [transceivers_dic,interfaces_dic,lst_dic,channel_namespace,endpoints]
\ No newline at end of file
diff --git a/src/device/service/drivers/oc_driver/templates/VPN/__init__.py b/src/device/service/drivers/oc_driver/templates/VPN/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/VPN/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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/service/drivers/oc_driver/templates/VPN/physical.py b/src/device/service/drivers/oc_driver/templates/VPN/physical.py
new file mode 100644
index 0000000000000000000000000000000000000000..355858d2da891d96777d111f481c070fe3036d44
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/VPN/physical.py
@@ -0,0 +1,210 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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
+
+def seperate_port_config(resources:list,unwanted_keys:list[str])->list[list,dict,str]:
+    config=[]
+    ports={}
+    index=None
+    for item in resources :
+      
+        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 create_optical_channel(resources):
+  
+    unwanted_keys=['destination_port','source_port','channel_namespace','optical-band-parent','index', 'name']
+    results =[]
+    data={"name":i["value"] for i in resources if i["resource_key"]=="channel_name"}
+    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'])
+    result = indent(
+        doc.getvalue(),
+        indentation = ' '*2,
+        newline = ''
+    )
+    results.append(result)
+
+
+    return results
+
+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_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"):
+      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_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'):
+                    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))
+                                    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
+             
+                
+     
\ No newline at end of file
diff --git a/src/device/service/drivers/oc_driver/templates/__init__.py b/src/device/service/drivers/oc_driver/templates/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612
--- /dev/null
+++ b/src/device/service/drivers/oc_driver/templates/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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/opticalcontroller/Dockerfile b/src/opticalcontroller/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..c3d886ab56ecf42cd2ffb96b32ef59b89f2c1207
--- /dev/null
+++ b/src/opticalcontroller/Dockerfile
@@ -0,0 +1,79 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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++ && \
+    rm -rf /var/lib/apt/lists/*
+
+# Set Python to show logs as they occur
+ENV PYTHONUNBUFFERED=0
+
+# Download the gRPC health probe
+# RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \
+#     wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \
+#     chmod +x /bin/grpc_health_probe
+
+
+
+
+# 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
+
+
+
+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
+
+RUN mkdir -p /var/teraflow/opticalcontroller
+
+WORKDIR /var/teraflow/opticalcontroller/common
+COPY src/common/. ./
+RUN rm -rf proto
+
+
+# Create proto sub-folder, copy .proto files, and generate Python code
+RUN mkdir -p /var/teraflow/opticalcontroller/common/proto
+WORKDIR /var/teraflow/opticalcontroller/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-folder, get specific Python packages
+
+
+
+WORKDIR /var/teraflow/opticalcontroller
+COPY src/opticalcontroller/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/context/. context/
+
+COPY src/opticalcontroller/. opticalcontroller/
+COPY src/context/. opticalcontroller/context/
+
+# Start the service
+WORKDIR /var/teraflow/opticalcontroller
+ENTRYPOINT ["python", "OpticalController.py"]
diff --git a/src/opticalcontroller/OpticalController.py b/src/opticalcontroller/OpticalController.py
new file mode 100644
index 0000000000000000000000000000000000000000..c2805695a75933c73d4ad367176bee8b504d4460
--- /dev/null
+++ b/src/opticalcontroller/OpticalController.py
@@ -0,0 +1,245 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 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
+
+
+rsa = None
+LOGGER = logging.getLogger(__name__)
+
+app = Flask(__name__)
+api = Api(app, version='1.0', title='Optical controller API',
+          description='Rest API to configure OC Optical devices in TFS')
+# app.config.from_object('config')
+# appbuilder = AppBuilder(app, indexview=MyIndexView)
+optical = api.namespace('OpticalTFS', description='TFS Optical APIs')
+
+
+@app.route('/index')
+def index():
+    return render_template('index.html')
+
+
+#@optical.route('/AddLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:bidir>')
+@optical.route('/AddLightpath/<string:src>/<string:dst>/<int:bitrate>')
+@optical.response(200, 'Success')
+@optical.response(404, 'Error, not found')
+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))
+        t0 = time.time()*1000.0
+        if debug:
+            rsa.g.printGraph()
+
+        if rsa is not None:
+            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
+            elapsed = t1 - t0
+            LOGGER.info("INFO: time elapsed = {} ms".format(elapsed))
+            return rsa.db_flows[flow_id], 200
+        else:
+            return "Error", 404
+
+
+#@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>')
+@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>',
+               defaults={"bidir": 1, "band": None})
+@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:bidir>',
+               defaults={"band": None})
+@optical.route('/AddFlexLightpath/<string:src>/<string:dst>/<int:bitrate>/<int:bidir>/<int:band>',)
+@optical.response(200, 'Success')
+@optical.response(404, 'Error, not found')
+class AddFlexLightpath(Resource):
+    @staticmethod
+    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} ")
+            if flow_id is not None:
+                if rsa.db_flows[flow_id]["op-mode"] == 0:
+                    return 'No path found', 404
+                t1 = time.time() * 1000.0
+                elapsed = t1 - t0
+                print("INFO: time elapsed = {} ms".format(elapsed))
+
+                return rsa.db_flows[flow_id], 200
+            else:
+                if len(rsa.optical_bands[optical_band_id]["flows"]) == 0:
+                    return 'No path found', 404
+                else:
+                    t1 = time.time() * 1000.0
+                    elapsed = t1 - t0
+                    LOGGER.info("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.response(200, 'Success')
+@optical.response(404, 'Error, not found')
+class DelLightpath(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
+                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
+
+
+
+@optical.route('/DelLightpath/<int:flow_id>/<string:src>/<string:dst>/<int:bitrate>')
+@optical.response(200, 'Success')
+@optical.response(404, 'Error, not found')
+class DelLightpath(Resource):
+    @staticmethod
+    def delete(flow_id, src, dst, bitrate):
+        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
+            match2 = flow["src"] == dst and flow["dst"] == src and flow["bitrate"] == bitrate
+            if match1 or match2:
+                rsa.del_flow(flow)
+                rsa.db_flows[flow_id]["is_active"] = False
+                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
+
+
+@optical.route('/GetLightpaths')
+@optical.response(200, 'Success')
+@optical.response(404, 'Error, not found')
+class GetFlows(Resource):
+    @staticmethod
+    def get():
+        try:
+            if debug:
+               LOGGER.info(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)
+            return rsa.optical_bands, 200
+        except:
+            return "Error", 404
+
+
+@optical.route('/GetOpticalBand/<int:ob_id>')
+@optical.response(200, 'Success')
+@optical.response(404, 'Error, not found')
+class GetBand(Resource):
+    @staticmethod
+    def get(ob_id):
+        for ob_idx in rsa.optical_bands.keys():
+            if str(ob_idx) == str(ob_id):
+                if debug:
+                   LOGGER.info(rsa.optical_bands[ob_id])
+                return rsa.optical_bands[ob_idx], 200
+        return {}, 404
+
+
+@optical.route('/GetLinks')
+@optical.response(200, 'Success')
+@optical.response(404, 'Error, not found')
+class GetFlows(Resource):
+    @staticmethod
+    def get():
+        global links_dict
+        try:
+            if debug:
+               LOGGER.info(links_dict)
+            return links_dict, 200
+        except:
+            return "Error", 404
+
+
+if __name__ == '__main__':
+    
+
+    # 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)
diff --git a/src/opticalcontroller/README.md b/src/opticalcontroller/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..5fd94c59e51cbd78dd76a7db0f24aaaec4ebd9db
--- /dev/null
+++ b/src/opticalcontroller/README.md
@@ -0,0 +1,17 @@
+# optical-controller
+This a framework to implement the optical controller for the RMSA algorithm.
+#create a venv
+python -m venv venv
+
+in linux
+source venv/Scripts/activate
+
+in windows
+venv\Scripts\activate
+
+pip install -r requirements_opt.txt
+
+python OpticalController.py
+![Reference Architecture](images/topo.png)
+
+
diff --git a/src/opticalcontroller/RSA.py b/src/opticalcontroller/RSA.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b12b1ac8d9302c2bb622b2d4b81924b5453036c
--- /dev/null
+++ b/src/opticalcontroller/RSA.py
@@ -0,0 +1,931 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 dijsktra
+from tools import *
+from variables import *
+
+
+class RSA():
+    def __init__(self, nodes, links):
+        self.nodes_dict = nodes
+        self.links_dict = links
+        self.g = None
+
+        self.flow_id = 0
+        self.opt_band_id = 0
+        self.db_flows = {}
+        self.initGraph()
+        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"]:
+                for fib in l["optical_link"]["details"]["fibers"]:
+                    #fib = self.links_dict[l]["fibers"][f]
+                    if len(fib["c_slots"]) > 0:
+                        fib["c_slots"] = list(range(0, Nc))
+                    if len(fib["l_slots"]) > 0:
+                        fib["l_slots"] = list(range(0, Nl))
+                    if len(fib["s_slots"]) > 0:
+                        fib["s_slots"] = list(range(0, Ns))
+                    if debug:
+                        print(fib)
+        for l1 in self.links_dict["links"]:
+
+            for fib1 in l1["optical_link"]["details"]["fibers"]:
+                #fib1 = self.links_dict[l1]["details"]["fibers"][f1]
+
+                self.c_slot_number = len(fib1["c_slots"])
+                self.l_slot_number = len(fib1["l_slots"])
+                self.s_slot_number = len(fib1["s_slots"])
+
+                break
+            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"]:
+            if debug:
+                print(l)
+            [s, d] = l["optical_link"]["name"].split('-')
+            ps = l["optical_link"]["details"]["source"]
+            pd = l["optical_link"]["details"]["target"]
+            self.g.add_edge(s, d, ps, pd, 1)
+
+        print("INFO: Graph initiated.")
+        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()))
+        if debug:
+            print(path)
+        links = []
+        for i in range(0, len(path) - 1):
+            s = path[i]
+            if debug:
+                print(s)
+            if i < len(path) - 1:
+                d = path[i + 1]
+                link_id = "{}-{}".format(s, d)
+                if debug:
+                    #print(link_id, self.links_dict[link_id])
+                    print(link_id, self.get_link_by_name(link_id))
+
+                links.append(link_id)
+        self.g.reset_graph()
+        return links, path
+
+    def get_slots(self, links, slots, optical_band_id = None):
+
+        if isinstance(slots, int):
+            val_c = slots
+            val_s = slots
+            val_l = slots
+        else:
+            val_c = self.c_slot_number
+            val_l = self.l_slot_number
+            val_s = self.s_slot_number
+
+        c_sts = []
+        l_sts = []
+        s_sts = []
+        c_slots = {}
+        l_slots = {}
+        s_slots = {}
+        add = ""
+        drop = ""
+        src_1, dst_1 = links[0].split('-')
+        src_2, dst_2 = links[-1].split('-')
+        if self.nodes_dict[src_1]["type"] == "OC-TP":
+            add = links[0]
+        if self.nodes_dict[dst_2]["type"] == "OC-TP":
+            drop = links[-1]
+
+        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:
+                return [], [], []
+
+        keys = list(c_slots.keys())
+        if debug:
+            print(len(keys))
+        if debug:
+            print(keys[0])
+        # intersection among the slots over all links
+        if len(keys) == 1:
+            c_sts = c_slots[keys[0]]
+            l_sts = l_slots[keys[0]]
+            s_sts = s_slots[keys[0]]
+        else:
+            for i in range(1, len(keys)):
+                if debug:
+                    print(keys[i])
+                # set a for the intersection
+                if i == 1:
+                    a_c = c_slots[keys[i - 1]]
+                    a_l = l_slots[keys[i - 1]]
+                    a_s = s_slots[keys[i - 1]]
+                else:
+                    a_c = c_sts
+                    a_l = l_sts
+                    a_s = s_sts
+                # set b for the intersection
+                b_c = c_slots[keys[i]]
+                b_l = l_slots[keys[i]]
+                b_s = s_slots[keys[i]]
+
+                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 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"]
+                    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"]
+                    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"]
+                    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):
+        for i in slots:
+            fib[band].remove(i)
+        if 'used' in fib:
+            fib['used'] = True
+
+    def update_optical_band(self, optical_band_id, slots, band):
+        for i in slots:
+            self.optical_bands[optical_band_id][band].remove(i)
+
+    def restore_link(self, fib, slots, band):
+        for i in slots:
+            fib[band].append(int(i))
+        if 'used' in fib:
+            fib['used'] = False
+        fib[band].sort()
+
+    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):
+        flows = flow["flows"]
+        band = flow["band_type"]
+        slots = flow["slots"]
+        fiber_f = flow["fiber_forward"]
+        fiber_b = flow["fiber_backward"]
+        op = flow["op-mode"]
+        n_slots = flow["n_slots"]
+        path = flow["path"]
+        links = flow["links"]
+        bidir = flow["bidir"]
+
+        for l in fiber_f.keys():
+            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)
+                if debug:
+                    print(fib[band])
+        if o_b_id is not None:
+            self.restore_optical_band(o_b_id, slots, band)
+        if bidir:
+            for rl in fiber_b.keys():
+                if debug:
+                    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 get_fibers_forward(self, links, slots, band):
+        fiber_list = {}
+        add = links[0]
+        drop = links[-1]
+        print(links)
+        '''
+        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"]:
+
+        '''
+        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
+        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:
+                if debug:
+                    print(link)
+                result = link
+                break
+        return result
+
+    def get_fiber_details(self, link_key, fiber_id):
+        for link in self.links_dict["links"]:
+            if link["optical_link"]["name"] == link_key:
+                if debug:
+                    print(link)
+                for fib in link["optical_link"]["details"]["fibers"]:
+                    if fib["ID"] == fiber_id:
+                        return fib
+        return None
+
+
+    def get_fibers_backward(self, links, fibers, 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])
+            '''
+            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"]
+            r_l = reverse_link(l)
+            r_link = self.get_link_by_name(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)
+        print("INFO: Path backward computation completed")
+        return fiber_list
+
+    def select_slots_and_ports(self, links, n_slots, c, l, s, bidir):
+        if debug:
+            print(self.links_dict)
+        band, slots = slot_selection(c, l, s, n_slots, self.c_slot_number, self.l_slot_number, self.s_slot_number)
+        if band is None:
+            print("No slots available in the three bands")
+            return None, None, None
+        if debug:
+            print(band, slots)
+        fibers_f = self.get_fibers_forward(links, slots, band)
+
+        fibers_b = []
+        if bidir:
+            fibers_b = self.get_fibers_backward(links, fibers_f, slots, band)
+        if debug:
+            print("forward")
+            print(fibers_f)
+            print("backward")
+            print(fibers_b)
+        add = links[0]
+        drop = links[-1]
+        inport = "0"
+        outport = "0"
+        r_inport = "0"
+        r_outport = "0"
+        t_flows = {}
+        #if len(links) == 1:
+
+        for lx in fibers_f:
+            if lx == add:
+                inport = "0"
+                r_outport = "0"
+            if lx == drop:
+                outport = "0"
+                r_inport = "0"
+            f = fibers_f[lx]
+            src, dst = lx.split("-")
+            fibx = self.get_fiber_details(lx, f)
+            #outport = self.links_dict[lx]['fibers'][f]["src_port"]
+            outport = fibx["src_port"]
+
+            t_flows[src] = {}
+            t_flows[src]["f"] = {}
+            t_flows[src]["b"] = {}
+            t_flows[src]["f"] = {"in": inport, "out": outport}
+
+            if bidir:
+                #r_inport = self.links_dict[lx]['fibers'][f]["local_peer_port"]
+                r_inport = fibx["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"]
+            if bidir:
+                #r_outport = self.links_dict[lx]['fibers'][f]["remote_peer_port"]
+                r_outport = fibx["remote_peer_port"]
+            t_flows[dst] = {}
+            t_flows[dst]["f"] = {}
+            t_flows[dst]["b"] = {}
+            t_flows[dst]["f"] = {"in": inport, "out": "0"}
+            if bidir:
+                t_flows[dst]["b"] = {"in": "0", "out": r_outport}
+
+        if debug:
+            print(self.links_dict)
+
+        if debug:
+            print(t_flows)
+        print("INFO: Flow matrix computed")
+
+        return t_flows, band, slots, fibers_f, fibers_b
+
+    def select_slots_and_ports_fs(self, links, n_slots, c, l, s, bidir, o_band_id):
+        if debug:
+            print(self.links_dict)
+        band, slots = slot_selection(c, l, s, n_slots, self.c_slot_number, self.l_slot_number, self.s_slot_number)
+        if band is None:
+            print("No slots available in the three bands")
+            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 = []
+        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"
+
+        t_flows = {}
+
+        #flows_add_side
+        f = fibers_f[add]
+        src, dst = add.split("-")
+        fibx = self.get_fiber_details(add, f)
+        #outport = self.links_dict[add]['fibers'][f]["src_port"]
+        outport = fibx["src_port"]
+        #T1 rules
+        t_flows[src] = {}
+        t_flows[src]["f"] = {}
+        t_flows[src]["b"] = {}
+        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"]
+            t_flows[src]["b"] = {"in": r_inport, "out": port_0}
+
+        #R1 rules
+        t_flows[dst] = {}
+        t_flows[dst]["f"] = {}
+        t_flows[dst]["b"] = {}
+        #inport = self.links_dict[add]['fibers'][f]["dst_port"]
+        inport = fibx["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"]
+            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"]
+            t_flows[dst]["b"] = {"in": rev_opt_band_dst_port, "out": r_outport}
+
+        #flows_drop_side
+        # R2 rules
+        f = fibers_f[drop]
+        src, dst = drop.split("-")
+        fiby = self.get_fiber_details(drop, f)
+        #outport = self.links_dict[drop]['fibers'][f]["src_port"]
+        outport = fiby["src_port"]
+
+        t_flows[src] = {}
+        t_flows[src]["f"] = {}
+        t_flows[src]["b"] = {}
+        opt_band_dst_port = self.optical_bands[o_band_id]["dst_port"]
+        t_flows[src]["f"] = {"in": opt_band_dst_port, "out": outport}
+        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"]
+            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"]
+        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"]
+            t_flows[dst]["b"] = {"in": port_0, "out": r_inport}
+
+        if debug:
+            print(self.links_dict)
+
+        if debug:
+            print(t_flows)
+        print("INFO: Flow matrix computed for Flex Lightpath")
+
+        return t_flows, band, slots, fibers_f, fibers_b
+
+    def rsa_computation(self, src, dst, rate, bidir):
+        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
+
+        links, path = self.compute_path(src, dst)
+
+        if len(path) < 1:
+            self.null_values(self.flow_id)
+            return self.flow_id
+        op, num_slots = map_rate_to_slot(rate)
+        c_slots, l_slots, s_slots = self.get_slots(links, num_slots)
+        if debug:
+            print(c_slots)
+            print(l_slots)
+            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)
+            if debug:
+                print(f0, band)
+            print("INFO: RSA completed for normal wavelenght connection")
+            if flow_list is None:
+                self.null_values(self.flow_id)
+                return self.flow_id
+            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"] = links
+            self.db_flows[self.flow_id]["path"] = 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
+        return self.flow_id
+
+    def null_values(self, flow_id):
+        self.db_flows[flow_id]["flows"] = {}
+        self.db_flows[flow_id]["band_type"] = ""
+        self.db_flows[flow_id]["slots"] = []
+        self.db_flows[flow_id]["fiber_forward"] = []
+        self.db_flows[flow_id]["fiber_backward"] = []
+        self.db_flows[flow_id]["op-mode"] = 0
+        self.db_flows[flow_id]["n_slots"] = 0
+        self.db_flows[flow_id]["links"] = {}
+        self.db_flows[flow_id]["path"] = []
+        self.db_flows[flow_id]["band"] = 0
+        self.db_flows[flow_id]["freq"] = 0
+        self.db_flows[flow_id]["is_active"] = False
+
+    def null_values_ob(self, ob_id):
+        self.optical_bands[ob_id]["flows"] = {}
+        self.optical_bands[ob_id]["band_type"] = ""
+        #self.optical_bands[ob_id]["slots"] = []
+        self.optical_bands[ob_id]["fiber_forward"] = []
+        self.optical_bands[ob_id]["n_slots"] = 0
+        self.optical_bands[ob_id]["links"] = {}
+        self.optical_bands[ob_id]["path"] = []
+        self.optical_bands[ob_id]["band"] = 0
+        self.optical_bands[ob_id]["freq"] = 0
+        self.optical_bands[ob_id]["is_active"] = False
+        self.optical_bands[ob_id]["c_slots"] = []
+        self.optical_bands[ob_id]["l_slots"] = []
+        self.optical_bands[ob_id]["s_slots"] = []
+        self.optical_bands[ob_id]["served_lightpaths"] = []
+        self.optical_bands[ob_id]["reverse_optical_band_id"] = 0
+        self.db_flows[self.flow_id]["parent_opt_band"] = 0
+        self.db_flows[self.flow_id]["new_optical_band"] = 0
+
+    def create_optical_band(self, links, path, bidir, num_slots):
+        print("INFO: Creating optical-band of {} slots".format(num_slots))
+        self.opt_band_id += 1
+        forw_opt_band_id = self.opt_band_id
+        self.optical_bands[forw_opt_band_id] = {}
+        self.optical_bands[forw_opt_band_id]["optical_band_id"] = forw_opt_band_id
+        self.optical_bands[forw_opt_band_id]["bidir"] = bidir
+        '''
+        back_opt_band_id = 0
+        if bidir:
+            self.opt_band_id += 1
+            back_opt_band_id = self.opt_band_id
+            self.optical_bands[back_opt_band_id] = {}
+            self.optical_bands[back_opt_band_id]["optical_band_id"] = back_opt_band_id
+            self.optical_bands[back_opt_band_id]["bidir"] = bidir
+            self.optical_bands[back_opt_band_id]["reverse_optical_band_id"] = forw_opt_band_id
+            self.optical_bands[forw_opt_band_id]["reverse_optical_band_id"] = back_opt_band_id
+        else:
+            self.optical_bands[forw_opt_band_id]["reverse_optical_band_id"] = 0
+        '''
+        op = 0
+        temp_links = []
+        #num_slots = "all"
+        if self.nodes_dict[path[0]]["type"] == "OC-TP":
+            add_link = links[0]
+            temp_links.append(add_link)
+            links.remove(add_link)
+            path.remove(path[0])
+        self.optical_bands[forw_opt_band_id]["src"] = path[0]
+        '''
+        if bidir:
+            self.optical_bands[back_opt_band_id]["dst"] = path[0]
+        '''
+        if self.nodes_dict[path[-1]]["type"] == "OC-TP":
+            drop_link = links[-1]
+            temp_links.append(drop_link)
+            links.remove(drop_link)
+            path.remove(path[-1])
+        self.optical_bands[forw_opt_band_id]["dst"] = path[-1]
+        '''
+        if bidir:
+            self.optical_bands[back_opt_band_id]["src"] = path[-1]
+        '''
+
+        c_slots, l_slots, s_slots = self.get_slots(links, num_slots)
+        if debug:
+            print(c_slots)
+            print(l_slots)
+            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(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 = []
+            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
+            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]
+                #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])
+                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])
+                rev_dst_port = fib_inx["local_peer_port"]
+                rev_src_port = fib_outx["remote_peer_port"]
+
+                #fib_in = fiber_f[link_in]
+                #fib_out = fiber_f[link_out]
+                #rev_dst_port = self.links_dict[link_in]['fibers'][fib_in]["local_peer_port"]
+                #rev_src_port = self.links_dict[link_out]['fibers'][fib_out]["remote_peer_port"]
+
+            self.optical_bands[forw_opt_band_id]["flows"] = flow_list
+            self.optical_bands[forw_opt_band_id]["band_type"] = band_range
+            self.optical_bands[forw_opt_band_id]["fiber_forward"] = fiber_f
+            self.optical_bands[forw_opt_band_id]["fiber_backward"] = fiber_b
+            self.optical_bands[forw_opt_band_id]["op-mode"] = op
+            self.optical_bands[forw_opt_band_id]["n_slots"] = num_slots
+            self.optical_bands[forw_opt_band_id]["links"] = links
+            self.optical_bands[forw_opt_band_id]["path"] = path
+            self.optical_bands[forw_opt_band_id]["band"] = band
+            self.optical_bands[forw_opt_band_id]["freq"] = f0
+            self.optical_bands[forw_opt_band_id]["is_active"] = True
+            self.optical_bands[forw_opt_band_id]["src_port"] = src_port
+            self.optical_bands[forw_opt_band_id]["dst_port"] = dst_port
+            self.optical_bands[forw_opt_band_id]["rev_dst_port"] = rev_dst_port
+            self.optical_bands[forw_opt_band_id]["rev_src_port"] = rev_src_port
+            self.optical_bands[forw_opt_band_id][band_range] = slots_i
+            self.optical_bands[forw_opt_band_id]["served_lightpaths"] = []
+            '''
+            if bidir:
+                self.optical_bands[back_opt_band_id]["flows"] = flow_list_b
+                self.optical_bands[back_opt_band_id]["band_type"] = band_range
+                self.optical_bands[back_opt_band_id]["fiber_forward"] = fiber_b
+                # self.optical_bands[back_opt_band_id]["fiber_backward"] = fiber_b
+                self.optical_bands[back_opt_band_id]["op-mode"] = op
+                self.optical_bands[back_opt_band_id]["n_slots"] = num_slots
+                self.optical_bands[back_opt_band_id]["links"] = rev_links
+                self.optical_bands[back_opt_band_id]["path"] = rev_path
+                self.optical_bands[back_opt_band_id]["band"] = band
+                self.optical_bands[back_opt_band_id]["freq"] = f0
+                self.optical_bands[back_opt_band_id]["is_active"] = True
+                self.optical_bands[back_opt_band_id]["src_port"] = rev_src_port
+                self.optical_bands[back_opt_band_id]["dst_port"] = rev_dst_port
+                self.optical_bands[back_opt_band_id][band_range] = slots_i.copy()
+                self.optical_bands[back_opt_band_id]["served_lightpaths"] = []
+            '''
+
+        return forw_opt_band_id, temp_links
+
+    def get_optical_bands(self, r_src, r_dst):
+        result = []
+        for ob_id in self.optical_bands:
+            ob = self.optical_bands[ob_id]
+            if debug:
+                print(r_src, ob["src"])
+                print(r_dst, ob["dst"])
+                print(ob)
+            if ob["src"] == r_src and ob["dst"] == r_dst:
+                result.append(ob_id)
+        return result
+
+    def rsa_fs_computation(self, src, dst, rate, bidir, band):
+        num_slots_ob = "full_band"
+        if band is not None:
+            num_slots_ob = map_band_to_slot(band)
+            print(band, num_slots_ob)
+        if self.nodes_dict[src]["type"] == "OC-ROADM" and self.nodes_dict[dst]["type"] == "OC-ROADM":
+            print("INFO: ROADM to ROADM connection")
+            links, path = self.compute_path(src, dst)
+            if len(path) < 1:
+                self.null_values_ob(self.opt_band_id)
+                return self.flow_id, []
+            optical_band_id, temp_links = self.create_optical_band(links, path, bidir, num_slots_ob)
+            return None, optical_band_id
+        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
+        print("INFO: TP to TP connection")
+        if band is None:
+            temp_links2 = []
+            temp_path = []
+            src_links = get_links_from_node(self.links_dict, src)
+            dst_links = get_links_to_node(self.links_dict, dst)
+            if len(src_links.keys()) >= 1:
+                temp_links2.append(list(src_links.keys())[0])
+            if len(dst_links.keys()) >= 1:
+                temp_links2.append(list(dst_links.keys())[0])
+
+            if len(temp_links2) == 2:
+                [t_src, roadm_src] = temp_links2[0].split('-')
+                [roadm_dst, t_dst] = temp_links2[1].split('-')
+                temp_path.append(t_src)
+                temp_path.append(roadm_src)
+                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:
+                        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)
+                        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 = freqency_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"] = 0
+                            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("not enough slots")
+        if band is None:
+            print("INFO: Not existing optical-band meeting the requirements")
+        else:
+            print("INFO: optical-band width specified")
+        #if no OB I create a new one
+        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)
+        if debug:
+            print(c_slots)
+            print(l_slots)
+            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_fs(temp_links, num_slots, c_slots,
+                                                                                            l_slots, s_slots, bidir, optical_band_id)
+            f0, band = freqency_converter(band_range, slots)
+            if debug:
+                print(f0, band)
+            print("INFO: RSA completed for FLex Lightpath with new OB")
+            if flow_list is None:
+                self.null_values(self.flow_id)
+                return self.flow_id, optical_band_id
+            slots_i = []
+            for i in slots:
+                slots_i.append(int(i))
+
+            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_links
+            self.db_flows[self.flow_id]["path"] = 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"] = optical_band_id
+            self.db_flows[self.flow_id]["new_optical_band"] = 1
+            self.optical_bands[optical_band_id]["served_lightpaths"].append(self.flow_id)
+            '''
+            if bidir:
+                rev_ob_id = self.optical_bands[optical_band_id]["reverse_optical_band_id"]
+                self.optical_bands[rev_ob_id]["served_lightpaths"].append(self.flow_id)
+            '''
+        return self.flow_id, optical_band_id
diff --git a/src/opticalcontroller/__init__.py b/src/opticalcontroller/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..38d04994fb0fa1951fb465bc127eb72659dc2eaf
--- /dev/null
+++ b/src/opticalcontroller/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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/opticalcontroller/dijsktra.py b/src/opticalcontroller/dijsktra.py
new file mode 100644
index 0000000000000000000000000000000000000000..a86d1d93dcbc30b9e4e3b95a34a0922439871bf6
--- /dev/null
+++ b/src/opticalcontroller/dijsktra.py
@@ -0,0 +1,240 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+# TODO: migrate to NetworkX:
+# https://networkx.org/documentation/stable/index.html
+# https://networkx.org/documentation/stable/reference/algorithms/shortest_paths.html
+
+import sys
+
+class Vertex:
+    def __init__(self, node):
+        self.id = node
+        self.adjacent = {}
+        # Set distance to infinity for all nodes
+        self.distance = float("inf")
+        # Mark all nodes unvisited        
+        self.visited = False  
+        # Predecessor
+        self.previous = None
+
+    # heapq compara gli item nella coda usando <= per vedere ci sono duplciati: 
+    # se ho una coda di tuple, 
+    # compara il primo elemento della prima tupla nella coda con il primo elemento della seconda tupla nella coda
+    # se sono diversi si ferma, se sono uguali continua
+    # la tupla nel caso in esame è: (v.get_distance(),v)
+    # se due nodi hanno stessa distanza, heapq procede a comparare v: Vertex().
+    # Va quindi definita una politica per confrontare i Vertex
+    def __lt__(self, other):
+        if self.id < other.id:
+            return True
+        else:
+            return False
+        
+    def __le__(self, other):
+        if self.id <= other.id:
+            return True
+        else:
+            return False
+
+    def add_neighbor(self, neighbor, port):
+        self.adjacent[neighbor] = port
+
+    def del_neighbor(self, neighbor):
+        self.adjacent.pop(neighbor)
+
+    def get_connections(self):
+        return self.adjacent.keys()  
+
+    def get_id(self):
+        return self.id
+
+    def get_port(self, neighbor):
+        return self.adjacent[neighbor][0]
+    
+    def get_weight(self, neighbor):
+        return self.adjacent[neighbor][1]
+
+    def set_distance(self, dist):
+        self.distance = dist
+
+    def get_distance(self):
+        return self.distance
+
+    def set_previous(self, prev):
+        self.previous = prev
+
+    def set_visited(self):
+        self.visited = True
+
+    def reset_vertex(self):
+        self.visited = False
+        self.previous = None
+        self.distance = float("inf")
+
+    def __str__(self):
+        return str(self.id) + ' adjacent: ' + str([x.id for x in self.adjacent])
+
+class Graph:
+    def __init__(self):
+        self.vert_dict = {}
+        self.num_vertices = 0
+
+    def __iter__(self):
+        return iter(self.vert_dict.values())
+    
+    def reset_graph(self):
+        for n in self.vert_dict:
+            self.get_vertex(n).reset_vertex()
+
+    def printGraph(self):
+        for v in self:
+            for w in v.get_connections():
+                vid = v.get_id()
+                wid = w.get_id()
+                print ('( %s , %s, %s, %s, %s, %s)'  % ( vid, wid, v.get_port(w), w.get_port(v), v.get_weight(w), w.get_weight(v)))
+
+    def add_vertex(self, node):
+        self.num_vertices = self.num_vertices + 1
+        new_vertex = Vertex(node)
+        self.vert_dict[node] = new_vertex
+        return new_vertex
+    
+    def del_Vertex(self, node):
+        self.vert_dict.pop(node)
+
+    def get_vertex(self, n):
+        if n in self.vert_dict:
+            return self.vert_dict[n]
+        else:
+            return None
+
+    def add_edge(self, frm, to, port_frm, port_to,w):
+        if frm not in self.vert_dict:
+            self.add_vertex(frm)
+        if to not in self.vert_dict:
+            self.add_vertex(to)
+
+        self.vert_dict[frm].add_neighbor(self.vert_dict[to], [port_frm, w])
+        self.vert_dict[to].add_neighbor(self.vert_dict[frm], [port_to, w])
+
+    def del_edge(self, frm, to, cost = 0):
+        self.vert_dict[frm].del_neighbor(self.vert_dict[to])
+        self.vert_dict[to].del_neighbor(self.vert_dict[frm])
+
+    def get_vertices(self):
+        return self.vert_dict.keys()
+
+    def set_previous(self, current):
+        self.previous = current
+
+    def get_previous(self, current):
+        return self.previous
+
+def shortest(v, path):
+    if v.previous:
+        path.append(v.previous.get_id())
+        shortest(v.previous, path)
+    return
+
+import heapq
+
+def dijkstra(aGraph, start):
+    """print ('''Dijkstra's shortest path''')"""
+    # Set the distance for the start node to zero 
+    start.set_distance(0)
+
+    # Put tuple pair into the priority queue
+    unvisited_queue = [(v.get_distance(),v) for v in aGraph]
+    #priority queue->costruisce un albero in cui ogni nodo parent ha  ha un valore <= di ogni child
+    #heappop prende il valore più piccolo, nel caso di dikstra, il nodo più vicino
+    heapq.heapify(unvisited_queue)
+
+    while len(unvisited_queue):
+        # Pops a vertex with the smallest distance 
+        uv = heapq.heappop(unvisited_queue)
+        current = uv[1]
+        current.set_visited()
+
+        #for next in v.adjacent:
+        for next in current.adjacent:
+            # if visited, skip
+            if next.visited:
+                continue
+            new_dist = current.get_distance() + current.get_weight(next)
+            
+            if new_dist < next.get_distance():
+                next.set_distance(new_dist)
+                next.set_previous(current)
+                """print ('updated : current = %s next = %s new_dist = %s' \
+                        %(current.get_id(), next.get_id(), next.get_distance()))"""
+            else:
+                """print ('not updated : current = %s next = %s new_dist = %s' \
+                        %(current.get_id(), next.get_id(), next.get_distance()))"""
+
+        # Rebuild heap
+        # 1. Pop every item
+        while len(unvisited_queue):
+            heapq.heappop(unvisited_queue)
+        # 2. Put all vertices not visited into the queue
+        unvisited_queue = [(v.get_distance(),v) for v in aGraph if not v.visited]
+        heapq.heapify(unvisited_queue)
+        
+def shortest_path(graph, src, dst):
+    dijkstra(graph, src)
+    target = dst
+    path = [target.get_id()]
+    shortest(target, path)
+    return path[::-1]
+
+if __name__ == '__main__':
+
+    print("Testing Algo")
+    g = Graph()
+
+    g.add_vertex('a')
+    g.add_vertex('b')
+    g.add_vertex('c')
+    g.add_vertex('d')
+    g.add_vertex('e')
+    g.add_vertex('f')
+
+    g.add_edge('a', 'b', 7)  
+    g.add_edge('a', 'c', 9)
+    g.add_edge('a', 'f', 14)
+    g.add_edge('b', 'c', 10)
+    g.add_edge('b', 'd', 15)
+    g.add_edge('c', 'd', 11)
+    g.add_edge('c', 'f', 2)
+    g.add_edge('d', 'e', 6)
+    g.add_edge('e', 'f', 9)
+
+
+    """print ('Graph data:')
+    for v in g:
+        for w in v.get_connections():
+            vid = v.get_id()
+            wid = w.get_id()
+            print ('( %s , %s, %3d)'  % ( vid, wid, v.get_weight(w)))
+
+            
+    dijkstra(g, g.get_vertex('a')) 
+
+    target = g.get_vertex('e')
+    path = [target.get_id()]
+    shortest(target, path)
+    print ('The shortest path : %s' %(path[::-1]))"""
+
+    p = shortest_path(g, g.get_vertex('a'), g.get_vertex('e'))
+    print(p)
diff --git a/src/opticalcontroller/images/topo.png b/src/opticalcontroller/images/topo.png
new file mode 100644
index 0000000000000000000000000000000000000000..216e1360b3caecd68285ca8b69fd498049dcbf79
Binary files /dev/null and b/src/opticalcontroller/images/topo.png differ
diff --git a/src/opticalcontroller/json_files/nodes.json b/src/opticalcontroller/json_files/nodes.json
new file mode 100644
index 0000000000000000000000000000000000000000..60f017c19d7c7a578c0ddfc2225cab742deb0026
--- /dev/null
+++ b/src/opticalcontroller/json_files/nodes.json
@@ -0,0 +1,39 @@
+{
+    "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
new file mode 100644
index 0000000000000000000000000000000000000000..ff1841eeea9df1e73bcfb25d07f19d64554f11e1
--- /dev/null
+++ b/src/opticalcontroller/json_files/optical_TFSworking.json
@@ -0,0 +1,486 @@
+{
+  "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
new file mode 100644
index 0000000000000000000000000000000000000000..7dea474cd676b7c699cffc1c180e14598b987473
--- /dev/null
+++ b/src/opticalcontroller/json_files/optical_topoTFS.json
@@ -0,0 +1,1836 @@
+{
+  "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
new file mode 100644
index 0000000000000000000000000000000000000000..31803b893b5639e957be33465599573baa475ca2
--- /dev/null
+++ b/src/opticalcontroller/json_files/tfs.json
@@ -0,0 +1,686 @@
+{
+	"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
new file mode 100644
index 0000000000000000000000000000000000000000..02165938ce675071a4ff4c3424e3b53244d40810
--- /dev/null
+++ b/src/opticalcontroller/json_files/topo_2_links.json
@@ -0,0 +1,1530 @@
+{
+  "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
new file mode 100644
index 0000000000000000000000000000000000000000..e2453b654d53fc3200570ce9c2b17effc964bd25
--- /dev/null
+++ b/src/opticalcontroller/json_files/topology-optical.json
@@ -0,0 +1,252 @@
+{
+    "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
new file mode 100644
index 0000000000000000000000000000000000000000..fe8e9866bcc64d52b2f49089ce03af47d72df9d0
--- /dev/null
+++ b/src/opticalcontroller/json_files/topology-optical2.json
@@ -0,0 +1,324 @@
+{
+    "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
new file mode 100644
index 0000000000000000000000000000000000000000..fefe604bc6f0d8d84c56817e7e85bb41015240ad
--- /dev/null
+++ b/src/opticalcontroller/requirements.in
@@ -0,0 +1,21 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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
new file mode 100644
index 0000000000000000000000000000000000000000..3b3223d81b2fe4e80956c02afae1a71c429493cf
--- /dev/null
+++ b/src/opticalcontroller/tools.py
@@ -0,0 +1,189 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 numpy as np
+from variables import  *
+import json
+
+
+def common_slots(a, b):
+    return list(np.intersect1d(a, b))
+
+
+def map_modulation_to_op(mod):
+    if mod == "DP-QPSK":
+        return 1
+    if mod == "DP-16QAM":
+        return 7
+    if mod == "DP-64QAM":
+        return 10
+
+
+def map_band_to_slot(band):
+    return int(band/12.5)
+
+
+def map_rate_to_slot(rate):
+    if rate == 100:
+        mod = "DP-QPSK"
+        slots = 4
+        op = map_modulation_to_op(mod)
+        return op, slots
+    if rate == 400:
+        mod = "DP-16QAM"
+        slots = 8
+        op = map_modulation_to_op(mod)
+        return op, slots
+    if rate == 1000:
+        mod = "DP-64QAM"
+        slots = 18
+        op = map_modulation_to_op(mod)
+        return op, slots
+    else:
+        return 2, 5
+
+
+def consecutives(x, val):
+    res = []
+    temp = []
+    x.sort()
+    temp.append(x[0])
+    y = 1
+    for i in range(1, len(x)):
+        if x[i] == x[i - 1] + 1:
+            y += 1
+            temp.append(x[i])
+        else:
+            if y >= val:
+                res.extend(temp)
+            temp = [x[i]]
+            y = 1
+        if i == len(x) - 1 and y >= val:
+            res.extend(temp)
+    return res
+
+
+def combine(ls1, ls2):
+    temp = ls1
+    for i in ls2:
+        if i not in ls1:
+            temp.append(i)
+    temp.sort()
+    return temp
+
+
+def list_in_list(a, b):
+    # convert list A to numpy array
+    a_arr = np.array(a)
+    # convert list B to numpy array
+    b_arr = np.array(b)
+
+    for i in range(len(b_arr)):
+        if np.array_equal(a_arr, b_arr[i:i + len(a_arr)]):
+            return True
+    return False
+
+
+def reverse_link(link):
+    s, d = link.split('-')
+    r_link = "{}-{}".format(d, s)
+    return r_link
+
+
+def get_slot_frequency(b, n):
+    if debug:
+        print(n)
+    if b == "c_slots":
+        return Fc + n * 12.5
+    if b == "s_slots":
+        return Fs + n * 12.5
+    if b == "l_slots":
+        return Fl + n * 12.5
+
+
+def freqency_converter(b, slots):
+    l = len(slots)
+    if debug:
+        print(slots)
+    if l % 2 == 0:
+        if debug:
+            print("pari {}".format(l))
+        fx = get_slot_frequency(b, slots[int(l / 2)-1])
+        if debug:
+            print(fx)
+        #GHz
+        # #f0 = fx + 6.25
+        #MHz
+        f0 = int((fx + 6.25) * 1000)
+    else:
+        f0 = get_slot_frequency(b, slots[int((l + 1) / 2) - 1])
+    #GHz
+    # #return f0, 12.5 * l
+    # MHz
+    return f0, int((12.5 * l) * 1000)
+
+
+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
+
+
+def reverse_links(links):
+    temp_links = links.copy()
+    temp_links.reverse()
+    result = []
+    for link in temp_links:
+        [a, b] = link.split("-")
+        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
+    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
+    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
+        slot_s = n_slots
+    else:
+        slot_c = Nc
+        slot_l = Nl
+        slot_s = Ns
+    if len(c) >= slot_c:
+        return "c_slots", c[0: slot_c]
+    elif len(l) >= slot_l:
+        return "l_slots", l[0: slot_l]
+    elif len(l) >= slot_s:
+        return "s_slots", s[0: slot_s]
+    else:
+        return None, None
diff --git a/src/opticalcontroller/variables.py b/src/opticalcontroller/variables.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbb65200f2f0c5ef9cd490c1435fb7a9120e5d63
--- /dev/null
+++ b/src/opticalcontroller/variables.py
@@ -0,0 +1,32 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+debug = 1
+
+Fl = 184800
+Fc = 192000
+Fs = 196200
+
+Nl = 550
+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
diff --git a/src/service/requirements.in b/src/service/requirements.in
index a10f7da7aba3027a89bdd8e9b62bc4ab90fb5e02..86720da190136c84d14e343b45cc0c97fa68ec06 100644
--- a/src/service/requirements.in
+++ b/src/service/requirements.in
@@ -19,3 +19,4 @@ netaddr==0.9.0
 networkx==2.6.3
 pydot==1.4.2
 redis==4.1.2
+requests==2.27.1
diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py
index d7a983dc97cefd9a796ab97629ba2dbe58a71b22..f65d5b59a0d9a81c44f4d04683eb87e7773efa4a 100644
--- a/src/service/service/ServiceServiceServicerImpl.py
+++ b/src/service/service/ServiceServiceServicerImpl.py
@@ -34,6 +34,13 @@ from .service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory
 from .task_scheduler.TaskScheduler import TasksScheduler
 from .tools.GeodesicDistance import gps_distance
 
+from common.tools.object_factory.Context import json_context_id
+from common.tools.object_factory.Topology import json_topology_id
+from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME
+from common.proto.context_pb2 import Empty, TopologyId
+from service.service.tools.OpticalTools import add_lightpath, delete_lightpath, adapt_reply, get_device_name_from_uuid, get_optical_band
+
+
 LOGGER = logging.getLogger(__name__)
 
 METRICS_POOL = MetricsPool('Service', 'RPC')
@@ -242,16 +249,74 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
             pathcomp_request = PathCompRequest()
             pathcomp_request.services.append(service_with_uuids)    # pylint: disable=no-member
 
-            if num_disjoint_paths is None or num_disjoint_paths in {0, 1}:
+        if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+            context_id_x = json_context_id(DEFAULT_CONTEXT_NAME)
+            topology_id_x = json_topology_id(
+                DEFAULT_TOPOLOGY_NAME, context_id_x)
+            topology_details = context_client.GetTopologyDetails(
+                TopologyId(**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
+            topology_uuid_x = topology_details.topology_id.topology_uuid.uuid
+            devs = []
+            ports = []
+            for endpoint_id in service.service_endpoint_ids:
+                devs.append(endpoint_id.device_id.device_uuid.uuid)
+                ports.append(endpoint_id.endpoint_uuid.uuid)
+            src = devs[0]
+            dst = devs[1]
+            bidir = None
+            ob_band = None
+            bitrate = 100
+            for constraint in service.service_constraints:
+                if "bandwidth" in constraint.custom.constraint_type:
+                    bitrate = int(float(constraint.custom.constraint_value))
+                elif "bidirectionality" in constraint.custom.constraint_type:
+                    bidir = int(constraint.custom.constraint_value)
+                elif "optical-band-width" in constraint.custom.constraint_type:
+                    ob_band = int(constraint.custom.constraint_value)
+
+            # to get the reply form the optical module
+            reply_txt = add_lightpath(src, dst, bitrate, bidir, ob_band)
+
+            # reply with 2 transponders and 2 roadms
+            reply_json = json.loads(reply_txt)
+            optical_band_txt = ""
+            if "new_optical_band" in reply_json.keys():
+                if reply_json["new_optical_band"] == 1:
+                    if reply_json["parent_opt_band"]:
+                        if "parent_opt_band" in reply_json.keys():
+                            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:
+                        LOGGER.debug('expected optical band not found')
+                else:
+                    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)
+        else:
+            if num_disjoint_paths is None or num_disjoint_paths in {0, 1} :
                 pathcomp_request.shortest_path.Clear()              # pylint: disable=no-member
             else:
                 pathcomp_request.k_disjoint_path.num_disjoint = num_disjoint_paths  # pylint: disable=no-member
 
-            LOGGER.debug('pathcomp_request={:s}'.format(grpc_message_to_json_string(pathcomp_request)))
             pathcomp = PathCompClient()
             pathcomp_reply = pathcomp.Compute(pathcomp_request)
             pathcomp.close()
-            LOGGER.debug('pathcomp_reply={:s}'.format(grpc_message_to_json_string(pathcomp_reply)))
 
             # Feed TaskScheduler with this path computation reply. TaskScheduler identifies inter-dependencies among
             # the services and connections retrieved and produces a schedule of tasks (an ordered list of tasks to be
@@ -280,6 +345,29 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
             context_client.RemoveService(request)
             return Empty()
 
+        if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+            devs = []
+
+            context_id_x = json_context_id(DEFAULT_CONTEXT_NAME)
+            topology_id_x = json_topology_id(
+                DEFAULT_TOPOLOGY_NAME, context_id_x)
+            topology_details = context_client.GetTopologyDetails(
+                TopologyId(**topology_id_x))
+            devices = topology_details.devices
+            for endpoint_id in service.service_endpoint_ids:
+                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))
+            if len(service.service_config.config_rules) > 0:
+                c_rules_dict = json.loads(
+                service.service_config.config_rules[0].custom.resource_value)
+                if ("flow_id" in c_rules_dict):
+                    flow_id = c_rules_dict["flow_id"]
+                    reply = delete_lightpath(flow_id, src, dst, bitrate)
+
         # Normal service
         # Feed TaskScheduler with this service and the sub-services and sub-connections related to this service.
         # TaskScheduler identifies inter-dependencies among them and produces a schedule of tasks (an ordered list of
diff --git a/src/service/service/__main__.py b/src/service/service/__main__.py
index f2b6e38d6181a0c56b4f1dfca3116717d1400ced..edd4d8f9973e20d0df6e2d99ba8164d5d68f068d 100644
--- a/src/service/service/__main__.py
+++ b/src/service/service/__main__.py
@@ -17,7 +17,8 @@ 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,
-    wait_for_environment_variables)
+    wait_for_environment_variables
+)
 from .ServiceService import ServiceService
 from .service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory
 from .service_handlers import SERVICE_HANDLERS
diff --git a/src/service/service/service_handler_api/FilterFields.py b/src/service/service/service_handler_api/FilterFields.py
index e771e24f17b2ea97c61158b65cb62c87ee9f37c5..633f41b63c71727d9ead0ee57b79002dc3a6cd97 100644
--- a/src/service/service/service_handler_api/FilterFields.py
+++ b/src/service/service/service_handler_api/FilterFields.py
@@ -26,6 +26,7 @@ SERVICE_TYPE_VALUES = {
     ServiceTypeEnum.SERVICETYPE_TAPI_CONNECTIVITY_SERVICE,
     ServiceTypeEnum.SERVICETYPE_TE,
     ServiceTypeEnum.SERVICETYPE_E2E,
+    ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY
 }
 
 DEVICE_DRIVER_VALUES = {
@@ -40,6 +41,7 @@ DEVICE_DRIVER_VALUES = {
     DeviceDriverEnum.DEVICEDRIVER_GNMI_OPENCONFIG,
     DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE,
     DeviceDriverEnum.DEVICEDRIVER_IETF_ACTN,
+    DeviceDriverEnum.DEVICEDRIVER_OC
 }
 
 # Map allowed filter fields to allowed values per Filter field. If no restriction (free text) None is specified
diff --git a/src/service/service/service_handlers/__init__.py b/src/service/service/service_handlers/__init__.py
index eaf8f715aeff435b67bce77928e726daeb4729e2..f0628110fbd5f2b15308f05c9061c699a09dbcff 100644
--- a/src/service/service/service_handlers/__init__.py
+++ b/src/service/service/service_handlers/__init__.py
@@ -26,6 +26,7 @@ from .p4.p4_service_handler import P4ServiceHandler
 from .tapi_tapi.TapiServiceHandler import TapiServiceHandler
 from .tapi_xr.TapiXrServiceHandler import TapiXrServiceHandler
 from .e2e_orch.E2EOrchestratorServiceHandler import E2EOrchestratorServiceHandler
+from .oc.OCServiceHandler import OCServiceHandler
 
 SERVICE_HANDLERS = [
     (L2NMEmulatedServiceHandler, [
@@ -100,4 +101,10 @@ SERVICE_HANDLERS = [
             FilterFieldEnum.DEVICE_DRIVER : [DeviceDriverEnum.DEVICEDRIVER_FLEXSCALE],
         }
     ]),
+    (OCServiceHandler, [
+        {
+            FilterFieldEnum.SERVICE_TYPE  : ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY,
+            FilterFieldEnum.DEVICE_DRIVER : DeviceDriverEnum.DEVICEDRIVER_OC,
+        }
+    ])
 ]
diff --git a/src/service/service/service_handlers/oc/ConfigRules.py b/src/service/service/service_handlers/oc/ConfigRules.py
new file mode 100644
index 0000000000000000000000000000000000000000..f4a46112e778bd01aa76322384d8adee942aaa5b
--- /dev/null
+++ b/src/service/service/service_handlers/oc/ConfigRules.py
@@ -0,0 +1,255 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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
new file mode 100644
index 0000000000000000000000000000000000000000..6359f2a09e53cab1002acd55d477aeb2d9b393b0
--- /dev/null
+++ b/src/service/service/service_handlers/oc/OCServiceHandler.py
@@ -0,0 +1,169 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json, logging
+from typing import Any, List, Optional, Tuple, Union
+from common.method_wrappers.Decorator import MetricsPool, metered_subclass_method
+from common.proto.context_pb2 import ConfigRule, DeviceId, Service
+from common.tools.object_factory.Device import json_device_id
+from common.type_checkers.Checkers import chk_type
+from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching
+from service.service.service_handler_api._ServiceHandler import _ServiceHandler
+from service.service.service_handler_api.SettingsHandler import SettingsHandler
+from service.service.task_scheduler.TaskExecutor import TaskExecutor
+from .ConfigRules import setup_config_rules, teardown_config_rules
+from .OCTools import convert_endpoints_to_flows, handle_flows_names
+
+LOGGER = logging.getLogger(__name__)
+
+METRICS_POOL = MetricsPool('Service', 'Handler', labels={'handler': 'oc'})
+
+class OCServiceHandler(_ServiceHandler):
+    def __init__(   # pylint: disable=super-init-not-called
+        self, service : Service, task_executor : TaskExecutor, **settings
+    ) -> None:
+        self.__service = service
+        self.__task_executor = task_executor
+        self.__settings_handler = SettingsHandler(service.service_config, **settings)
+
+    @metered_subclass_method(METRICS_POOL)
+    def SetEndpoint(
+        self, endpoints : List[Tuple[str, str, Optional[str]]], connection_uuid : Optional[str] = None
+    ) -> List[Union[bool, Exception]]:
+   
+        chk_type('endpoints', endpoints, list)
+        if len(endpoints) == 0: return []
+        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')
+       
+       
+        # settings = self.__settings_handler.get('/settings')
+
+        #flow is the new variable that stores input-output relationship
+        
+        flows = convert_endpoints_to_flows(endpoints)
+        #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():
+            try:
+                dev_flows = flows[device_uuid]
+                device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
+               
+              
+                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]]:
+        chk_type('endpoints', endpoints, list)
+        if len(endpoints) == 0: return []
+
+        service_uuid = self.__service.service_id.service_uuid.uuid
+        settings = self.__settings_handler.get('/settings')
+
+        results = []
+        for endpoint in endpoints:
+            try:
+                device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint)
+
+                device_obj = self.__task_executor.get_device(DeviceId(**json_device_id(device_uuid)))
+                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)
+
+                results.append(True)
+            except Exception as e: # pylint: disable=broad-except
+                LOGGER.exception('Unable to DeleteEndpoint({:s})'.format(str(endpoint)))
+                results.append(e)
+
+        return results
+
+    @metered_subclass_method(METRICS_POOL)
+    def SetConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        chk_type('constraints', constraints, list)
+        if len(constraints) == 0: return []
+
+        msg = '[SetConstraint] Method not implemented. Constraints({:s}) are being ignored.'
+        LOGGER.warning(msg.format(str(constraints)))
+        return [True for _ in range(len(constraints))]
+
+    @metered_subclass_method(METRICS_POOL)
+    def DeleteConstraint(self, constraints : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        chk_type('constraints', constraints, list)
+        if len(constraints) == 0: return []
+
+        msg = '[DeleteConstraint] Method not implemented. Constraints({:s}) are being ignored.'
+        LOGGER.warning(msg.format(str(constraints)))
+        return [True for _ in range(len(constraints))]
+
+    @metered_subclass_method(METRICS_POOL)
+    def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        chk_type('resources', resources, list)
+        if len(resources) == 0: return []
+
+        results = []
+        for resource in resources:
+            try:
+                resource_value = json.loads(resource[1])
+                self.__settings_handler.set(resource[0], resource_value)
+                results.append(True)
+            except Exception as e: # pylint: disable=broad-except
+                LOGGER.exception('Unable to SetConfig({:s})'.format(str(resource)))
+                results.append(e)
+
+        return results
+
+    @metered_subclass_method(METRICS_POOL)
+    def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        chk_type('resources', resources, list)
+        if len(resources) == 0: return []
+
+        results = []
+        for resource in resources:
+            try:
+                self.__settings_handler.delete(resource[0])
+            except Exception as e: # pylint: disable=broad-except
+                LOGGER.exception('Unable to DeleteConfig({:s})'.format(str(resource)))
+                results.append(e)
+
+        return results
diff --git a/src/service/service/service_handlers/oc/OCTools.py b/src/service/service/service_handlers/oc/OCTools.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b202a8a9ce2183342fc23f3563cc16d81abcd5d
--- /dev/null
+++ b/src/service/service/service_handlers/oc/OCTools.py
@@ -0,0 +1,142 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 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
+from common.tools.object_factory.Device import json_device_id
+
+log = logging.getLogger(__name__)
+
+#def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]])->Dict[str: List[Tuple[str, str]]]:
+
+def convert_endpoints_to_flows(endpoints : List[Tuple[str, str, Optional[str]]])->Dict:
+    #entries = List[Tuple[str, str, str, Optional[str]]]
+    #entries = Dict[str: List[Tuple[str, str]]]
+    entries = {}
+    #tuple is in, out
+    #end = len(endpoints) if isinstance(endpoints,list) else 0
+    end = len(endpoints)
+    i = 0
+    bidir = 0
+    log.debug("end={}".format(end))
+    while(i < end):
+        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] = []
+        if i == 0:
+            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:
+                bidir = 1
+                log.debug("connection is bidirectional")
+                entry_tuple = next_endpoint_uuid, "0"
+                entries[device_uuid].append(entry_tuple)
+                i = i + 1
+            else:
+                log.debug("connection is unidirectional")
+        else:
+            if not bidir:
+                if i == end-1:
+                    #is the last node
+                    entry_tuple = endpoint_uuid, "0"
+                    entries[device_uuid].append(entry_tuple)
+                else:
+                    #it is a transit node
+                    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 + 1
+                        log.debug("current OCTools step {}, {}, {}".format(i, next_device_uuid, device_uuid))
+                    else:
+                        log.debug("ERROR in unidirectional connection 4")
+                        return {}
+            if bidir:
+                log.debug("Ocheck i {}, {}, {}".format(i, i+1, end-1))
+                if i + 1 == end-1:
+                    log.debug("current OCTools step {}, {}, {}".format(i, device_uuid, endpoint_uuid))
+                    #is the last node
+                    entry_tuple = endpoint_uuid, "0"
+                    entries[device_uuid].append(entry_tuple)
+                    next_endpoint = endpoints[i+1]
+                    log.debug("OCTools i+1 step {}, {}, {}".format(i+1, next_device_uuid, device_uuid))
+
+                    next_device_uuid, next_endpoint_uuid = next_endpoint[0:2]
+                    if next_device_uuid == device_uuid:
+                        entry_tuple = "0", next_endpoint_uuid
+                        entries[device_uuid].append(entry_tuple)
+                        i = i + 1
+                    else:
+                        log.debug("ERROR in bidirectional connection 2")
+                        return entries
+                else:
+                    log.debug("OCTools i+1+2+3 step {}, {}, {}".format(i+1, next_device_uuid, 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 connection 3")
+                        log.debug("{}, {}, {}".format(i, next_device_uuid, device_uuid))
+                        return entries
+                    #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 + 3
+                    else:
+                        log.debug("ERROR in bidirection connection 4")
+                        return {}
+        i = i + 1
+    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()):
+        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))    
+    return new_flows
diff --git a/src/service/service/service_handlers/oc/__init__.py b/src/service/service/service_handlers/oc/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612
--- /dev/null
+++ b/src/service/service/service_handlers/oc/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py
index ae0f1be7da291a5dc025641cb606f7a7706059ca..b9715aae637bb8845077bfc2b8b9b9d1bb030645 100644
--- a/src/service/service/task_scheduler/TaskExecutor.py
+++ b/src/service/service/task_scheduler/TaskExecutor.py
@@ -12,11 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import logging #, json
+import json, logging
 from enum import Enum
 from typing import TYPE_CHECKING, Any, Dict, Optional, Union
 from common.method_wrappers.ServiceExceptions import NotFoundException
-from common.proto.context_pb2 import Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId
+from common.proto.context_pb2 import (
+    Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId,
+    OpticalConfig, OpticalConfigId
+)
 from common.tools.context_queries.Connection import get_connection_by_id
 from common.tools.context_queries.Device import get_device
 from common.tools.context_queries.Service import get_service_by_id
@@ -25,7 +28,8 @@ from common.tools.object_factory.Device import json_device_id
 from context.client.ContextClient import ContextClient
 from device.client.DeviceClient import DeviceClient
 from service.service.service_handler_api.Exceptions import (
-    UnsatisfiedFilterException, UnsupportedFilterFieldException, UnsupportedFilterFieldValueException)
+    UnsatisfiedFilterException, UnsupportedFilterFieldException, UnsupportedFilterFieldValueException
+)
 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
 
@@ -108,9 +112,33 @@ class TaskExecutor:
         return device
 
     def configure_device(self, device : Device) -> None:
+        self._context_client.SelectOpticalConfig()
         device_key = get_device_key(device.device_id)
         self._device_client.ConfigureDevice(device)
         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):
+        device_key = get_device_key(device.device_id)
+        myid = OpticalConfigId()
+        myid.opticalconfig_uuid = device.device_id.device_uuid.uuid
+        opticalconfig = OpticalConfig()
+        setting = settings.value if settings else ""
+
+        new_config = {}
+        try:
+            result = self._context_client.SelectOpticalConfig(myid)
+            new_config = json.loads(result.config)
+            if result is not None :
+                new_config["new_config"] = setting
+                new_config["is_opticalband"] = is_opticalband
+                new_config["flow"] = flows
+                result.config = str(new_config)
+                opticalconfig.CopyFrom(result)
+                self._device_client.ConfigureOpticalDevice(opticalconfig)
+            self._store_grpc_object(CacheableObjectType.DEVICE, device_key, device)
+        except Exception as e:
+            LOGGER.info("error in config my config %s",e)
 
     def get_device_controller(self, device : Device) -> Optional[Device]:
         #json_controller = None
diff --git a/src/service/service/tools/OpticalTools.py b/src/service/service/tools/OpticalTools.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b3e3153beb53063b17ae7998e8a7d49f8abd64e
--- /dev/null
+++ b/src/service/service/tools/OpticalTools.py
@@ -0,0 +1,300 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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
+import requests
+import uuid
+from common.Constants import *
+from typing import Dict, List
+from common.proto.context_pb2 import(
+    Device, DeviceId, Service, Connection, EndPointId, TopologyId, ContextId, Uuid,
+    ConfigRule, ConfigActionEnum, ConfigRule_Custom
+)
+from common.proto.pathcomp_pb2 import PathCompReply
+from typing import Dict, List, Optional, Tuple
+from common.Constants import ServiceNameEnum
+from common.Settings import (
+    ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, find_environment_variables, get_env_var_name
+)
+from context.service.database.uuids.EndPoint import endpoint_get_uuid
+from service.service.tools.replies import reply_uni_txt, optical_band_uni_txt, reply_bid_txt, optical_band_bid_txt
+
+log = logging.getLogger(__name__)
+
+testing = False
+
+VAR_NAME_OPTICAL_CONTROLLER_HOST = get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER, ENVVAR_SUFIX_SERVICE_HOST)
+VAR_NAME_OPTICAL_CONTROLLER_PORT = get_env_var_name(ServiceNameEnum.OPTICALCONTROLLER, ENVVAR_SUFIX_SERVICE_PORT_GRPC)
+
+opticalcontrollers_url = find_environment_variables([
+    VAR_NAME_OPTICAL_CONTROLLER_HOST,
+    VAR_NAME_OPTICAL_CONTROLLER_PORT,
+])
+OPTICAL_IP   = opticalcontrollers_url.get(VAR_NAME_OPTICAL_CONTROLLER_HOST)
+OPTICAL_PORT = opticalcontrollers_url.get(VAR_NAME_OPTICAL_CONTROLLER_PORT)
+log.info(str(OPTICAL_IP), str(OPTICAL_PORT))
+
+def get_uuids_from_names(devices: List[Device], device_name: str, port_name: str):
+    device_uuid = ""
+    port_uuid = ""
+    for device in devices:
+        if device.name == device_name:
+            device_uuid  = device.device_id.device_uuid.uuid
+            for ep in device.device_endpoints:
+                if ep.name == port_name:
+                    port_uuid = ep.endpoint_id.endpoint_uuid.uuid
+                    return device_uuid, port_uuid
+    return "", ""
+
+
+def get_names_from_uuids(devices: List[Device], device_uuid: str, port_uuid: str):
+    device_name = ""
+    port_name = ""
+    for device in devices:
+        if device.device_id.device_uuid.uuid == device_uuid:
+            device_name  = device.name
+            for ep in device.device_endpoints:
+                if ep.endpoint_id.endpoint_uuid.uuid == port_uuid:
+                    port_name = ep.name
+                    return device_name, port_name
+    return "", ""
+
+def get_device_name_from_uuid(devices: List[Device], device_uuid: str):
+    device_name = ""
+    
+    for device in devices:
+        if device.device_id.device_uuid.uuid == device_uuid:
+            device_name  = device.name
+            return device_name
+    return ""
+
+
+def add_lightpath(src, dst, bitrate, bidir, ob_band) -> str:
+    if not testing:
+        urlx = ""
+        headers = {"Content-Type": "application/json"}
+        if ob_band is None:
+            if bidir is None:
+                bidir = 1
+            urlx = "http://{}:{}/OpticalTFS/AddFlexLightpath/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, src, dst, bitrate, bidir)
+        else:
+            if bidir is None:
+                bidir = 1
+            urlx = "http://{}:{}/OpticalTFS/AddFlexLightpath/{}/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, src, dst, bitrate, bidir, ob_band)
+        r = requests.put(urlx, headers=headers)
+        reply = r.text 
+        return reply
+    else:
+        if bidir is not None:
+            if bidir == 0:        
+                return reply_uni_txt
+        return reply_bid_txt
+                
+
+def get_optical_band(idx) -> str:
+    if not testing:
+        urlx = "http://{}:{}/OpticalTFS/GetOpticalBand/{}".format(OPTICAL_IP, OPTICAL_PORT, idx)
+        headers = {"Content-Type": "application/json"}
+        r = requests.get(urlx, headers=headers)
+        reply = r.text 
+        return reply
+    else:
+        if str(idx) == "1":
+            return optical_band_bid_txt
+        else:
+            return optical_band_uni_txt
+
+    
+def delete_lightpath(flow_id, src, dst, bitrate) -> str:
+    reply = "200"
+    if not testing:
+        urlx = "http://{}:{}/OpticalTFS/DelLightpath/{}/{}/{}/{}".format(OPTICAL_IP, OPTICAL_PORT, flow_id, src, dst, bitrate)
+
+        headers = {"Content-Type": "application/json"}
+        r = requests.delete(urlx, headers=headers)
+        reply = r.text 
+    return reply
+
+
+def get_lightpaths() -> str:
+    urlx = "http://{}:{}/OpticalTFS/GetLightpaths".format(OPTICAL_IP, OPTICAL_PORT)
+
+    headers = {"Content-Type": "application/json"}
+    r = requests.get(urlx, headers=headers)
+    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))
+    #add optical band connection first
+    rules_ob= []
+    ob_id = 0
+    connection_ob=None
+    if optical_band_txt != "":
+        ob_json = json.loads(optical_band_txt)
+        ob = ob_json
+        connection_ob = add_connection_to_reply(opt_reply)
+        uuuid_x = str(uuid.uuid4())
+        connection_ob.connection_id.connection_uuid.uuid = uuuid_x
+        connection_ob.service_id.CopyFrom(service.service_id)
+       
+        ob_id = ob["optical_band_id"]        
+        obt = ob["band_type"]
+        if obt == "l_slots":
+          band_type = "L_BAND"
+        elif obt == "s_slots":
+          band_type = "S_BAND"
+        else:
+          band_type = "C_BAND"
+          
+        freq = ob["freq"]
+        bx = ob["band"]
+        lf = int(int(freq)-int(bx/2))
+        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}
+        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():
+            log.debug("optical-band device {}".format(devxb))
+            in_end_point_b = "0"
+            out_end_point_b = "0"
+            in_end_point_f = ob["flows"][devxb]["f"]["in"]
+            out_end_point_f = ob["flows"][devxb]["f"]["out"]
+            log.debug("optical-band ports {}, {}".format(in_end_point_f, out_end_point_f))
+            if bidir_ob:
+                in_end_point_b = ob["flows"][devxb]["b"]["in"]
+                out_end_point_b = ob["flows"][devxb]["b"]["out"]
+                log.debug("optical-band ports {}, {}".format(in_end_point_b, out_end_point_b))
+            #if (in_end_point_f == "0" or out_end_point_f == "0") and (in_end_point_b == "0" or out_end_point_b == "0"):
+            if in_end_point_f != "0":
+                d_ob, p_ob = get_uuids_from_names(devices, devxb, in_end_point_f)
+                if d_ob != "" and p_ob != "":
+                    end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob))
+                    connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b)
+                else:
+                    log.info("no map device port for device {} port {}".format(devxb, in_end_point_f))
+
+            if out_end_point_f != "0":
+                d_ob, p_ob = get_uuids_from_names(devices, devxb, out_end_point_f)
+                if d_ob != "" and p_ob != "":
+                    end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob))
+                    connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) 
+                else:
+                    log.info("no map device port for device {} port {}".format(devxb, out_end_point_f))
+            if in_end_point_b != "0":
+                d_ob, p_ob = get_uuids_from_names(devices, devxb, in_end_point_b)
+                if d_ob != "" and p_ob != "":
+                    end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob))
+                    connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_b) 
+                else:
+                    log.info("no map device port for device {} port {}".format(devxb, in_end_point_b))
+            if out_end_point_b != "0":
+                d_ob, p_ob = get_uuids_from_names(devices, devxb, out_end_point_b)
+                if d_ob != "" and p_ob != "":
+                    end_point_b = EndPointId(topology_id=topo, device_id=DeviceId(device_uuid=Uuid(uuid=d_ob)), endpoint_uuid=Uuid(uuid=p_ob))
+                    connection_ob.path_hops_endpoint_ids.add().CopyFrom(end_point_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)
+    for devx in r["flows"].keys():
+        log.debug("lightpath device {}".format(devx))
+        in_end_point_b = "0"
+        out_end_point_b = "0"
+        
+        in_end_point_f = r["flows"][devx]["f"]["in"]
+        out_end_point_f = r["flows"][devx]["f"]["out"]
+        log.debug("lightpath ports {}, {}".format(in_end_point_f, out_end_point_f))
+        if bidir_f:
+            in_end_point_b = r["flows"][devx]["b"]["in"]
+            out_end_point_b = r["flows"][devx]["b"]["out"]
+            log.debug("lightpath ports {}, {}".format(in_end_point_b, out_end_point_b))
+        if in_end_point_f != "0":
+            d, p = get_uuids_from_names(devices, devx, in_end_point_f)
+            if d != "" and p != "":
+                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, in_end_point_f))
+        if out_end_point_f != "0":
+            d, p = get_uuids_from_names(devices, devx, out_end_point_f)
+            if d != "" and p != "":
+                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_f))
+        if in_end_point_b != "0":
+            d, p = get_uuids_from_names(devices, devx, in_end_point_b)
+            if d != "" and p != "":
+                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, in_end_point_b))
+        if out_end_point_b != "0":
+            d, p = get_uuids_from_names(devices, devx, out_end_point_b)
+            if d != "" and p != "":
+                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))      
+    #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
+    frequency = r["freq"] if "freq" in r else None
+    flow_id = r["flow_id"] if "flow_id" in r else None
+    r_type = r["band_type"] if "band_type" in r else None
+    if r_type == "l_slots":
+        band_type = "L_BAND"
+    elif r_type == "s_slots":
+        band_type = "S_BAND"
+    else:
+        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,}
+    else:
+        val = {"frequency": frequency, "operational-mode": op_mode, "band": band, "flow_id": flow_id, "band_type": band_type,}
+    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)
+      
+    opt_reply.services.add().CopyFrom(service)   
+    
+    return opt_reply         
+
+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:
+    conn = reply.connections.add()
+    return conn
diff --git a/src/service/service/tools/replies.py b/src/service/service/tools/replies.py
new file mode 100644
index 0000000000000000000000000000000000000000..5fcb393e9d8a5eaaeccc11a8c1dc8e4485b8cbc9
--- /dev/null
+++ b/src/service/service/tools/replies.py
@@ -0,0 +1,321 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+# 
+
+reply_bid_txt = """
+{
+  "flow_id": 1,
+  "src": "T1",
+  "dst": "T2",
+  "bitrate": 100,
+  "bidir": 1,
+  "flows": {
+    "T1": {
+      "f": {
+        "in": "0",
+        "out": "1"
+      },
+      "b": {
+        "in": "1",
+        "out": "0"
+      }
+    },
+    "R1": {
+      "f": {
+        "in": "12",
+        "out": "3"
+      },
+      "b": {
+        "in": "13",
+        "out": "2"
+      }
+    },
+    "R2": {
+      "f": {
+        "in": "14",
+        "out": "5"
+      },
+      "b": {
+        "in": "15",
+        "out": "4"
+      }
+    },
+    "T2": {
+      "f": {
+        "in": "6",
+        "out": "0"
+      },
+      "b": {
+        "in": "0",
+        "out": "6"
+      }
+    }
+  },
+  "band_type": "c_slots",
+  "slots": [
+    1,
+    2,
+    3,
+    4
+  ],
+  "fiber_forward": {
+    "T1-R1": "M1",
+    "R2-T2": "S1"
+  },
+  "fiber_backward": {
+    "R1-T1": "S1",
+    "T2-R2": "M1"
+  },
+  "op-mode": 1,
+  "n_slots": 4,
+  "links": [
+    "T1-R1",
+    "R2-T2"
+  ],
+  "path": [
+    "R1",
+    "R2"
+  ],
+  "band": 50000,
+  "freq": 192031250,
+  "is_active": true,
+  "parent_opt_band": 1,
+  "new_optical_band": 1
+}
+  """
+  
+optical_band_bid_txt = """
+{
+  "optical_band_id": 1,
+  "bidir": 1,
+  "src": "R1",
+  "dst": "R2",
+  "flows": {
+    "R1": {
+      "f": {
+        "in": "0", 
+        "out": "3" 
+      },
+      "b": {
+        "in": "13",
+        "out": "0"
+      }
+    },
+    "R2": {
+      "f": {
+        "in": "14",
+        "out": "0"
+      },
+      "b": {
+        "in": "0",
+        "out": "4"
+      }
+    }
+  },
+  "band_type": "c_slots",
+  "fiber_forward": {
+    "R1-R2": "d1-1"
+  },
+  "fiber_backward": {
+    "R2-R1": "d1-1"
+  },
+  "op-mode": 0,
+  "n_slots": 16,
+  "links": [
+    "R1-R2"
+  ],
+  "path": [
+    "R1",
+    "R2"
+  ],
+  "band": 200000,
+  "freq": 192106250,
+  "is_active": true,
+  "src_port": "101",
+  "dst_port": "201",
+  "rev_dst_port": "201",
+  "rev_src_port": "101",
+  "c_slots": [
+    5,
+    6,
+    7,
+    8,
+    9,
+    10,
+    11,
+    12,
+    13,
+    14,
+    15,
+    16
+  ],
+  "served_lightpaths": [
+    1
+  ]
+}
+  """
+
+reply_uni_txt = """
+{
+  "flow_id": 2,
+  "src": "T1",
+  "dst": "T2",
+  "bitrate": 100,
+  "bidir": 0,
+  "flows": {
+    "T1": {
+      "f": {
+        "in": "0",
+        "out": "1"
+      },
+      "b": {
+        "in": "1",
+        "out": "0"
+      }
+    },
+    "R1": {
+      "f": {
+        "in": "12",
+        "out": "3"
+      },
+      "b": {
+        "in": "13",
+        "out": "2"
+      }
+    },
+    "R2": {
+      "f": {
+        "in": "14",
+        "out": "5"
+      },
+      "b": {
+        "in": "15",
+        "out": "4"
+      }
+    },
+    "T2": {
+      "f": {
+        "in": "6",
+        "out": "0"
+      },
+      "b": {
+        "in": "0",
+        "out": "6"
+      }
+    }
+  },
+  "band_type": "c_slots",
+  "slots": [
+    1,
+    2,
+    3,
+    4
+  ],
+  "fiber_forward": {
+    "T1-R1": "M1",
+    "R2-T2": "S1"
+  },
+  "fiber_backward": {
+    "R1-T1": "S1",
+    "T2-R2": "M1"
+  },
+  "op-mode": 1,
+  "n_slots": 4,
+  "links": [
+    "T1-R1",
+    "R2-T2"
+  ],
+  "path": [
+    "R1",
+    "R2"
+  ],
+  "band": 50000,
+  "freq": 192031250,
+  "is_active": true,
+  "parent_opt_band": 2,
+  "new_optical_band": 1
+}
+  """
+  
+optical_band_uni_txt = """
+{
+  "optical_band_id": 2,
+  "bidir": 0,
+  "src": "R1",
+  "dst": "R2",
+  "flows": {
+    "R1": {
+      "f": {
+        "in": "0", 
+        "out": "3" 
+      },
+      "b": {
+        "in": "13",
+        "out": "0"
+      }
+    },
+    "R2": {
+      "f": {
+        "in": "14",
+        "out": "0"
+      },
+      "b": {
+        "in": "0",
+        "out": "4"
+      }
+    }
+  },
+  "band_type": "c_slots",
+  "fiber_forward": {
+    "R1-R2": "d1-1"
+  },
+  "fiber_backward": {
+    "R2-R1": "d1-1"
+  },
+  "op-mode": 0,
+  "n_slots": 16,
+  "links": [
+    "R1-R2"
+  ],
+  "path": [
+    "R1",
+    "R2"
+  ],
+  "band": 200000,
+  "freq": 192106250,
+  "is_active": true,
+  "src_port": "101",
+  "dst_port": "201",
+  "rev_dst_port": "201",
+  "rev_src_port": "101",
+  "c_slots": [
+    5,
+    6,
+    7,
+    8,
+    9,
+    10,
+    11,
+    12,
+    13,
+    14,
+    15,
+    16
+  ],
+  "served_lightpaths": [
+    2
+  ]
+}
+  """
+
diff --git a/src/tests/ofc24/1.context.json b/src/tests/ofc24/1.context.json
new file mode 100755
index 0000000000000000000000000000000000000000..36b3c44fd61fdec9d208a82a11d5a16c3671d004
--- /dev/null
+++ b/src/tests/ofc24/1.context.json
@@ -0,0 +1,19 @@
+{
+    "contexts": [
+        {
+            "context_id": {"context_uuid": {"uuid": "admin"}},
+            "topology_ids": [],
+            "service_ids": []
+        }
+    ],
+    "topologies": [
+        {
+            "topology_id": {
+                "context_id": {"context_uuid": {"uuid": "admin"}},
+                "topology_uuid": {"uuid": "admin"}
+            },
+            "device_ids": [],
+            "link_ids": []
+        }
+    ]
+}
diff --git a/src/tests/ofc24/2.device1.json b/src/tests/ofc24/2.device1.json
new file mode 100755
index 0000000000000000000000000000000000000000..3e31f31eb84630415f96b6af1e6ae5d34bdb1c89
--- /dev/null
+++ b/src/tests/ofc24/2.device1.json
@@ -0,0 +1,91 @@
+{
+    "devices": [
+        {
+            "device_id": {
+                "device_uuid": {
+                    "uuid": "T1"
+                }
+            },
+            "device_type": "optical-transponder",
+            "device_drivers": [
+				11
+            ],
+            "device_endpoints": [
+                {
+                    "endpoint_id": {
+                        "device_id": {
+                            "device_uuid": {
+                                "uuid": "T1"
+                            }
+                        },
+                        "topology_id": {
+                            "context_id": {
+                                "context_uuid": {
+                                    "uuid": "admin"
+                                }
+                            },
+                            "topology_uuid": {
+                                "uuid": "admin"
+                            }
+                        },
+                        "endpoint_uuid": {
+                            "uuid": "1"
+                        }
+                    }
+                }
+            ],
+            "device_operational_status": 1,
+            "device_config": {
+                "config_rules": [
+                    {
+                        "action": 1,
+                        "custom": {
+                            "resource_key": "_connect/address",
+                            "resource_value": "10.0.2.15"
+                        }
+                    },
+                    {
+                        "action": 1,
+                        "custom": {
+                            "resource_key": "_connect/port",
+                            "resource_value": "2023"
+                        }
+                    },
+                    {
+                        "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": "1"
+                                    }
+                                ]
+                            }
+                        }
+                    }
+                ]
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/src/tests/ofc24/3.device2.json b/src/tests/ofc24/3.device2.json
new file mode 100755
index 0000000000000000000000000000000000000000..812affa7b8540b67f83d6f3c9bb9b5442c44fd0d
--- /dev/null
+++ b/src/tests/ofc24/3.device2.json
@@ -0,0 +1,91 @@
+{
+    "devices": [
+		{
+            "device_id": {
+                "device_uuid": {
+                    "uuid": "T2"
+                }
+            },
+            "device_type": "optical-transponder",
+            "device_drivers": [
+                11
+            ],
+            "device_endpoints": [
+                {
+                    "endpoint_id": {
+                        "device_id": {
+                            "device_uuid": {
+                                "uuid": "T2"
+                            }
+                        },
+                        "topology_id": {
+                            "context_id": {
+                                "context_uuid": {
+                                    "uuid": "admin"
+                                }
+                            },
+                            "topology_uuid": {
+                                "uuid": "admin"
+                            }
+                        },
+                        "endpoint_uuid": {
+                            "uuid": "6"
+                        }
+                    }
+                }
+            ],
+            "device_operational_status": 1,
+            "device_config": {
+                "config_rules": [
+                    {
+                        "action": 1,
+                        "custom": {
+                            "resource_key": "_connect/address",
+                            "resource_value": "10.0.2.15"
+                        }
+                    },
+                    {
+                        "action": 1,
+                        "custom": {
+                            "resource_key": "_connect/port",
+                            "resource_value": "2024"
+                        }
+                    },
+                    {
+                        "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": "6"
+                                    }
+                                ]
+                            }
+                        }
+                    }
+                ]
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/src/tests/ofc24/4.device3_R1.json b/src/tests/ofc24/4.device3_R1.json
new file mode 100755
index 0000000000000000000000000000000000000000..3a57ba79cd2ff8aa6d4b666ac382932ade2f20e0
--- /dev/null
+++ b/src/tests/ofc24/4.device3_R1.json
@@ -0,0 +1,188 @@
+{
+    "devices": [
+        {
+            "device_id": {
+                "device_uuid": {
+                    "uuid": "R1"
+                }
+            },
+            "device_type": "optical-roadm",
+            "device_drivers": [
+                11
+            ],
+            "device_endpoints": [
+                {
+                    "endpoint_id": {
+                        "device_id": {
+                            "device_uuid": {
+                                "uuid": "R1"
+                            }
+                        },
+                        "topology_id": {
+                            "context_id": {
+                                "context_uuid": {
+                                    "uuid": "admin"
+                                }
+                            },
+                            "topology_uuid": {
+                                "uuid": "admin"
+                            }
+                        },
+                        "endpoint_uuid": {
+                            "uuid": "2"
+                        }
+                    }
+                },
+				{
+                    "endpoint_id": {
+                        "device_id": {
+                            "device_uuid": {
+                                "uuid": "R1"
+                            }
+                        },
+                        "topology_id": {
+                            "context_id": {
+                                "context_uuid": {
+                                    "uuid": "admin"
+                                }
+                            },
+                            "topology_uuid": {
+                                "uuid": "admin"
+                            }
+                        },
+                        "endpoint_uuid": {
+                            "uuid": "3"
+                        }
+                    }
+                },
+				{
+                    "endpoint_id": {
+                        "device_id": {
+                            "device_uuid": {
+                                "uuid": "R1"
+                            }
+                        },
+                        "topology_id": {
+                            "context_id": {
+                                "context_uuid": {
+                                    "uuid": "admin"
+                                }
+                            },
+                            "topology_uuid": {
+                                "uuid": "admin"
+                            }
+                        },
+                        "endpoint_uuid": {
+                            "uuid": "12"
+                        }
+                    }
+                },
+				{
+                    "endpoint_id": {
+                        "device_id": {
+                            "device_uuid": {
+                                "uuid": "R1"
+                            }
+                        },
+                        "topology_id": {
+                            "context_id": {
+                                "context_uuid": {
+                                    "uuid": "admin"
+                                }
+                            },
+                            "topology_uuid": {
+                                "uuid": "admin"
+                            }
+                        },
+                        "endpoint_uuid": {
+                            "uuid": "13"
+                        }
+                    }
+                }			
+            ],
+            "device_operational_status": 1,
+            "device_config": {
+                "config_rules": [
+                    {
+                        "action": 1,
+                        "custom": {
+                            "resource_key": "_connect/address",
+                            "resource_value": "10.0.2.15"
+                        }
+                    },
+                    {
+                        "action": 1,
+                        "custom": {
+                            "resource_key": "_connect/port",
+                            "resource_value": "2025"
+                        }
+                    },
+                    {
+                        "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"
+                                    }
+
+                                ]
+                            }
+                        }
+                    }
+                ]
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/src/tests/ofc24/5.device4_R2.json b/src/tests/ofc24/5.device4_R2.json
new file mode 100755
index 0000000000000000000000000000000000000000..9b1968d095c3e2c28c058b22f7295d7d1cbda380
--- /dev/null
+++ b/src/tests/ofc24/5.device4_R2.json
@@ -0,0 +1,189 @@
+{
+    "devices": [
+        {
+            "device_id": {
+                "device_uuid": {
+                    "uuid": "R2"
+                }
+            },
+            "device_type": "optical-roadm",
+            "device_drivers": [
+                11
+            ],
+            "device_endpoints": [
+                {
+                    "endpoint_id": {
+                        "device_id": {
+                            "device_uuid": {
+                                "uuid": "R2"
+                            }
+                        },
+                        "topology_id": {
+                            "context_id": {
+                                "context_uuid": {
+                                    "uuid": "admin"
+                                }
+                            },
+                            "topology_uuid": {
+                                "uuid": "admin"
+                            }
+                        },
+                        "endpoint_uuid": {
+                            "uuid": "4"
+                        }
+                    }
+                },
+				{
+                    "endpoint_id": {
+                        "device_id": {
+                            "device_uuid": {
+                                "uuid": "R2"
+                            }
+                        },
+                        "topology_id": {
+                            "context_id": {
+                                "context_uuid": {
+                                    "uuid": "admin"
+                                }
+                            },
+                            "topology_uuid": {
+                                "uuid": "admin"
+                            }
+                        },
+                        "endpoint_uuid": {
+                            "uuid": "5"
+                        }
+                    }
+                },
+				{
+                    "endpoint_id": {
+                        "device_id": {
+                            "device_uuid": {
+                                "uuid": "R2"
+                            }
+                        },
+                        "topology_id": {
+                            "context_id": {
+                                "context_uuid": {
+                                    "uuid": "admin"
+                                }
+                            },
+                            "topology_uuid": {
+                                "uuid": "admin"
+                            }
+                        },
+                        "endpoint_uuid": {
+                            "uuid": "14"
+                        }
+                    }
+                },
+				{
+                    "endpoint_id": {
+                        "device_id": {
+                            "device_uuid": {
+                                "uuid": "R2"
+                            }
+                        },
+                        "topology_id": {
+                            "context_id": {
+                                "context_uuid": {
+                                    "uuid": "admin"
+                                }
+                            },
+                            "topology_uuid": {
+                                "uuid": "admin"
+                            }
+                        },
+                        "endpoint_uuid": {
+                            "uuid": "15"
+                        }
+                    }
+                }
+				
+            ],
+            "device_operational_status": 1,
+            "device_config": {
+                "config_rules": [
+                    {
+                        "action": 1,
+                        "custom": {
+                            "resource_key": "_connect/address",
+                            "resource_value": "10.0.2.15"
+                        }
+                    },
+                    {
+                        "action": 1,
+                        "custom": {
+                            "resource_key": "_connect/port",
+                            "resource_value": "2026"
+                        }
+                    },
+                    {
+                        "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"
+                                    }
+
+                                ]
+                            }
+                        }
+                    }
+                ]
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/src/tests/ofc24/6.links.json b/src/tests/ofc24/6.links.json
new file mode 100755
index 0000000000000000000000000000000000000000..eb2d004fc8e5484c5ae9eaafa6ec86efb49eb729
--- /dev/null
+++ b/src/tests/ofc24/6.links.json
@@ -0,0 +1,28 @@
+{ "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"}}
+    ]}	
+]
+
+}
diff --git a/src/tests/ofc24/7.service-bidir.json b/src/tests/ofc24/7.service-bidir.json
new file mode 100755
index 0000000000000000000000000000000000000000..05547a19d2d375d2a8202266b1a1a5ffcfe46eb6
--- /dev/null
+++ b/src/tests/ofc24/7.service-bidir.json
@@ -0,0 +1,22 @@
+{
+    "services": [
+        {
+            "service_id": {
+                "context_id": {"context_uuid": {"uuid": "admin"}},
+                "service_uuid": {"uuid": "optical-connection"}
+            },
+            "service_type": 6,
+            "service_status": {"service_status": 1},
+            "service_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"}},
+                {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"}}
+            ],
+            "service_constraints": [
+                {"custom": {"constraint_type": "bandwidth[gbps]", "constraint_value": "100.0"}},
+                {"custom": {"constraint_type": "bidirectionality", "constraint_value": "1"}},
+                {"custom": {"constraint_type": "optical-band-width[GHz]", "constraint_value": "200"}}
+            ],
+            "service_config": {"config_rules": []}
+        }
+    ]
+}
diff --git a/src/tests/ofc24/7.service-unidir.json b/src/tests/ofc24/7.service-unidir.json
new file mode 100755
index 0000000000000000000000000000000000000000..d9b4e88479c17aaf03f65d08b8d4b0ca22121e74
--- /dev/null
+++ b/src/tests/ofc24/7.service-unidir.json
@@ -0,0 +1,22 @@
+{
+    "services": [
+        {
+            "service_id": {
+                "context_id": {"context_uuid": {"uuid": "admin"}},
+                "service_uuid": {"uuid": "optical-connection"}
+            },
+            "service_type": 6,
+            "service_status": {"service_status": 1},
+            "service_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1"}},
+                {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "6"}}
+            ],
+            "service_constraints": [
+                {"custom": {"constraint_type": "bandwidth[gbps]", "constraint_value": "100.0"}},
+                {"custom": {"constraint_type": "bidirectionality", "constraint_value": "0"}},
+                {"custom": {"constraint_type": "optical-band-width[GHz]", "constraint_value": "200"}}
+            ],
+            "service_config": {"config_rules": []}
+        }
+    ]
+}
diff --git a/src/tests/ofc24/README.md b/src/tests/ofc24/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..93e95fc642273bf852c829d6fae14cddf8ccba96
--- /dev/null
+++ b/src/tests/ofc24/README.md
@@ -0,0 +1,21 @@
+# OFC'24 - Test scenario
+
+## Start Topology
+Topology is composed of 2 transponders managed through OpenConfig and 2 Multi-granular ROAMDS
+Strat the topology executing the following command:
+```bash
+sudo ./start_topo.sh
+```
+
+## Populate the TFS context and topology
+Pushing the JSON files following the file indexes, i.e, 1, 2, 3, ...
+The last JSON file with ID 7 is the service.
+To check the service is onboarded successfully go into the TFS WebUI and check the `Service` tab.
+
+## Check configuration in devices
+Check if the devices are configured properly.
+To check that, run, for each device (X={1, 2, 3, 4}):
+```bash
+screen -r tX
+```
+To release the terminal, press `Ctrl + A + D`
diff --git a/src/tests/ofc24/plat_r1.xml b/src/tests/ofc24/plat_r1.xml
new file mode 100755
index 0000000000000000000000000000000000000000..47e135c2e3752de21dbe2f17550026e9622f4de1
--- /dev/null
+++ b/src/tests/ofc24/plat_r1.xml
@@ -0,0 +1,120 @@
+<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>
+    </components>
+</config>
\ No newline at end of file
diff --git a/src/tests/ofc24/plat_r2.xml b/src/tests/ofc24/plat_r2.xml
new file mode 100755
index 0000000000000000000000000000000000000000..dfaaf05ad7134a950ec11f411037b9a058b7d719
--- /dev/null
+++ b/src/tests/ofc24/plat_r2.xml
@@ -0,0 +1,120 @@
+<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>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>D1</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>D1</value>
+                    </config>
+                </property>
+            </properties>
+        </component>
+        <component xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:operation="create">
+            <name>5</name>
+            <config>
+                <name>5</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>15</name>
+            <config>
+                <name>15</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/startExtraNetConfigAgent.sh b/src/tests/ofc24/startExtraNetConfigAgent.sh
new file mode 100755
index 0000000000000000000000000000000000000000..d9428585ef1040bb0440bf6db100b7f2bc71c970
--- /dev/null
+++ b/src/tests/ofc24/startExtraNetConfigAgent.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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_CONTAINER=$1
+DOCKER_PORT=$2
+
+if [ -n "$DOCKER_CONTAINER" ] && [ -n "$DOCKER_PORT" ];then
+      sudo docker stop "$DOCKER_CONTAINER" -t 1
+      sudo docker rm "$DOCKER_CONTAINER"
+
+      echo "Creating TPs"
+      screen -dmS t1 -T xterm sh -c "docker run -p 10.0.2.15:"$DOCKER_PORT":2022 -v ~/tfs-ctrl/tempOC/files:/files --name $DOCKER_CONTAINER -it asgamb1/oc23bgp.img:latest"
+      sleep  2 
+      if [ "$( docker container  inspect -f '{{.State.Running}}' "$DOCKER_CONTAINER")" = "true" ]; then 
+            docker exec  "$DOCKER_CONTAINER"  cp /files/demoECOC21_4.xml demoECOC21.xml
+            docker exec "$DOCKER_CONTAINER" /confd/examples.confd/OC23/startNetconfAgent.sh 
+      else 
+            echo "your container is not running yet"
+      fi
+else 
+   echo "Please define the docker container name and port"
+fi         
diff --git a/src/tests/ofc24/start_topo.sh b/src/tests/ofc24/start_topo.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c924064763c14e4da45344cd21f4d9c81c9640a9
--- /dev/null
+++ b/src/tests/ofc24/start_topo.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+IMAGE_NAME="asgamb1/oc23bgp.img:latest"
+DOCKER_CONTAINER=$1
+DOCKER_PORT="2022"
+
+sudo docker stop na1 -t 1
+sudo docker stop na2 -t 1
+sudo docker stop na3 -t 1
+sudo docker stop na4 -t 1
+
+sudo docker rm na2
+sudo docker rm na1
+sudo docker rm na3
+sudo docker rm na4
+
+echo "Creating Transponder Agents"
+
+# if ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1 ; then
+#    echo "asgamb1/oc23bgp.img:latest not existed ! "
+#    screen -dmS t3 -T xterm sh -c "docker run -p 10.0.2.15:2025:2022 -v ~/tempOC/files:/files --name na -it  $IMAGE_NAME bash"
+#    echo 'start downloading  asgamb1/oc23bgp.img:latest , it may take few minutes ! .... ' 
+#    while [ "$(docker image inspect asgamb1/oc23bgp.img:latest 2>/dev/null)" == "[]" ]; do
+#         sleep 1
+# done
+
+#fi
+
+
+
+screen -dmS t1 -T xterm sh -c "docker run  -p 127.0.0.1:2023:2022 -v ~/tempOC/files:/files --name $DOCKER_CONTAINER -it asgamb1/oc23bgp.img:latest bash"
+sleep  2 
+if [ "$( docker container  inspect -f '{{.State.Running}}' "$DOCKER_CONTAINER")" = "true" ]; then 
+        docker exec  "$DOCKER_CONTAINER"  cp /files/demoECOC21_4.xml demoECOC21.xml
+        docker exec "$DOCKER_CONTAINER" /confd/examples.confd/OC23/startNetconfAgent.sh 
+else 
+        echo "your container is not running yet"
+fi
+
+echo " It may take a while , Hang on ..."
+source "./startExtraNetConfigAgent.sh"  "na1" "2023"
+sleep 3
+
+source "./startExtraNetConfigAgent.sh"  "na2" "2024"
+sleep 3
+
+bash -c "cp /tempOC/files/plat_r1.xml /confd/examples.confd/OC23/init_openconfig-platform.xml; ./startNetconfAgent.sh"
+bash -c "cp /tempOC/files/plat_r2.xml /confd/examples.confd/OC23/init_openconfig-platform.xml; ./startNetconfAgent.sh"
+screen -dmS t3 -T xterm sh -c 'docker run -p 10.0.2.15:2025:2022 -v ~/tfs-ctrl/tempOC/files:/files --name na3 -it asgamb1/flexscale-node.img:latest ./startNetconfAgent.sh'
+screen -dmS t4 -T xterm sh -c 'docker run -p 10.0.2.15:2026:2022 -v ~/tfs-ctrl/tempOC/files:/files --name na4 -it asgamb1/flexscale-node.img:latest ./startNetconfAgent.sh'
diff --git a/src/tests/ofc24/t1.xml b/src/tests/ofc24/t1.xml
new file mode 100755
index 0000000000000000000000000000000000000000..712615df8dd821ff8e79df9785d6d29324a25b7d
--- /dev/null
+++ b/src/tests/ofc24/t1.xml
@@ -0,0 +1,298 @@
+<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/t2.xml b/src/tests/ofc24/t2.xml
new file mode 100755
index 0000000000000000000000000000000000000000..3a35e7e87eac7b14cd2bfa693560cc653f3719b9
--- /dev/null
+++ b/src/tests/ofc24/t2.xml
@@ -0,0 +1,298 @@
+<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>
+