diff --git a/proto/context.proto b/proto/context.proto
index 49d16229cdac5de84f25cfaa7d196d25184f46f0..bfbe8ab2f1f1ed7ccc9055405778affa5393fb29 100644
--- a/proto/context.proto
+++ b/proto/context.proto
@@ -191,6 +191,7 @@ enum DeviceDriverEnum {
   DEVICEDRIVER_IETF_NETWORK_TOPOLOGY = 4;
   DEVICEDRIVER_ONF_TR_352 = 5;
   DEVICEDRIVER_XR = 6;
+  DEVICEDRIVER_BGPLS = 7;
 }
 
 enum DeviceOperationalStatusEnum {
diff --git a/src/common/DeviceTypes.py b/src/common/DeviceTypes.py
index 99255defdb6b5ee155607536a2e13d23b97b2d3a..a47b6be3c6acac5be0ebbe262ba0988f536bf083 100644
--- a/src/common/DeviceTypes.py
+++ b/src/common/DeviceTypes.py
@@ -28,6 +28,7 @@ class DeviceTypeEnum(Enum):
     EMULATED_P4_SWITCH              = 'emu-p4-switch'
     EMULATED_PACKET_ROUTER          = 'emu-packet-router'
     EMULATED_PACKET_SWITCH          = 'emu-packet-switch'
+    EMULATED_BGPLS_ASNUMBER         = 'emu-bgpls-asnumber'
 
     # Real device types
     DATACENTER                      = 'datacenter'
@@ -38,4 +39,5 @@ class DeviceTypeEnum(Enum):
     P4_SWITCH                       = 'p4-switch'
     PACKET_ROUTER                   = 'packet-router'
     PACKET_SWITCH                   = 'packet-switch'
-    XR_CONSTELLATION                = 'xr-constellation'
\ No newline at end of file
+    XR_CONSTELLATION                = 'xr-constellation'
+    BGPLS_ASNUMBER                  = 'bgpls-asnumber'
\ No newline at end of file
diff --git a/src/common/tools/object_factory/Device.py b/src/common/tools/object_factory/Device.py
index 0cc4555d455bf28ac2143a5d58b87e084a8360c7..d35cb684cb55181b7bc6d665e00f45ebf351c758 100644
--- a/src/common/tools/object_factory/Device.py
+++ b/src/common/tools/object_factory/Device.py
@@ -43,6 +43,9 @@ DEVICE_MICROWAVE_DRIVERS = [DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY]
 DEVICE_P4_TYPE      = DeviceTypeEnum.P4_SWITCH.value
 DEVICE_P4_DRIVERS   = [DeviceDriverEnum.DEVICEDRIVER_P4]
 
+DEVICE_BGPLS_TYPE      = DeviceTypeEnum.BGPLS_ASNUMBER.value
+DEVICE_BGPLS_DRIVERS   = [DeviceDriverEnum.DEVICEDRIVER_BGPLS]
+
 def json_device_id(device_uuid : str):
     return {'device_uuid': {'uuid': device_uuid}}
 
diff --git a/src/common/type_checkers/Assertions.py b/src/common/type_checkers/Assertions.py
index c0442d8770c682ac1eea032980b58e7028be90c4..e20b2d1f870be0327d1528180e39422d7eea06e0 100644
--- a/src/common/type_checkers/Assertions.py
+++ b/src/common/type_checkers/Assertions.py
@@ -33,6 +33,7 @@ def validate_device_driver_enum(message):
         'DEVICEDRIVER_IETF_NETWORK_TOPOLOGY',
         'DEVICEDRIVER_ONF_TR_352',
         'DEVICEDRIVER_XR',
+        'DEVICEDRIVER_BGPLS',
     ]
 
 def validate_device_operational_status_enum(message):
diff --git a/src/context/service/database/models/enums/DeviceDriver.py b/src/context/service/database/models/enums/DeviceDriver.py
index 6997e7dfbff6bc1d4b6452a28f11cdac9aae412f..9893add28e828eba93a67dffa0f599065f9c5cbf 100644
--- a/src/context/service/database/models/enums/DeviceDriver.py
+++ b/src/context/service/database/models/enums/DeviceDriver.py
@@ -24,6 +24,7 @@ class ORM_DeviceDriverEnum(enum.Enum):
     IETF_NETWORK_TOPOLOGY = DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY
     ONF_TR_352            = DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352
     XR                    = DeviceDriverEnum.DEVICEDRIVER_XR
+    BGPLS                 = DeviceDriverEnum.DEVICEDRIVER_BGPLS
 
 grpc_to_enum__device_driver = functools.partial(
     grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum)
diff --git a/src/device/service/DeviceServiceServicerImpl.py b/src/device/service/DeviceServiceServicerImpl.py
index be40e64ecd25a5c46c23d5ec0a73a2484b65691d..76acd203e4a63e0e7e8ad925a8af1a9edd0d56df 100644
--- a/src/device/service/DeviceServiceServicerImpl.py
+++ b/src/device/service/DeviceServiceServicerImpl.py
@@ -30,6 +30,7 @@ from .Tools import (
     check_connect_rules, check_no_endpoints, compute_rules_to_add_delete, configure_rules, deconfigure_rules,
     populate_config_rules, populate_endpoint_monitoring_resources, populate_endpoints, populate_initial_config_rules,
     subscribe_kpi, unsubscribe_kpi, update_endpoints)
+from .drivers.bgpls.Tools import config_BGPLSDriver
 
 LOGGER = logging.getLogger(__name__)
 
@@ -70,7 +71,7 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
         self.mutex_queues.wait_my_turn(device_uuid)
         try:
             driver : _Driver = get_driver(self.driver_instance_cache, device)
-
+            LOGGER.info("_DRIVER get_driver: %s",driver)
             errors = []
 
             if len(device.device_endpoints) == 0:
@@ -106,6 +107,7 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
         try:
             context_client = ContextClient()
             device = get_device(context_client, device_uuid, rw_copy=True)
+            # LOGGER.info("device get_device: %s", device )
             if device is None:
                 raise NotFoundException('Device', device_uuid, extra_details='loading in ConfigureDevice')
 
@@ -123,6 +125,13 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
                 device_id = context_client.SetDevice(device)
                 device = context_client.GetDevice(device_id)
 
+            # Checkear aqui si son dos driver y si uno es bgpls Connect ****tid-bgp-speaker****
+            if DeviceDriverEnum.DEVICEDRIVER_BGPLS in device.device_drivers:
+                LOGGER.info("Es BGPLS (ConfigureDevice)")
+                # config_BGPLSDriver.driverSettings(context_client)
+                # config_BGPLSDriver.driverConnect(self.driver_instance_cache,device,device_uuid)
+
+
             if request.device_operational_status != DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED:
                 device.device_operational_status = request.device_operational_status
 
diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py
index 469abcad387dc055ba17770e4f405db1d1ceaa3b..17fb8c8f12e7988a89bec8aede92d38b3c31944a 100644
--- a/src/device/service/drivers/__init__.py
+++ b/src/device/service/drivers/__init__.py
@@ -37,6 +37,7 @@ DRIVERS.append(
                 DeviceTypeEnum.EMULATED_P4_SWITCH,
                 DeviceTypeEnum.EMULATED_PACKET_ROUTER,
                 DeviceTypeEnum.EMULATED_PACKET_SWITCH,
+                DeviceTypeEnum.EMULATED_BGPLS_ASNUMBER,
 
                 #DeviceTypeEnum.DATACENTER,
                 #DeviceTypeEnum.MICROWAVE_RADIO_SYSTEM,
@@ -127,3 +128,13 @@ if LOAD_ALL_DEVICE_DRIVERS:
                 FilterFieldEnum.DRIVER     : DeviceDriverEnum.DEVICEDRIVER_XR,
             }
         ]))
+if LOAD_ALL_DEVICE_DRIVERS:
+    from .bgpls.BGPLSDriver import BGPLSDriver # pylint: disable=wrong-import-position
+    DRIVERS.append(
+        (BGPLSDriver, [
+            {
+                # Values :TODO ¿
+                FilterFieldEnum.DEVICE_TYPE: DeviceTypeEnum.BGPLS_ASNUMBER,
+                FilterFieldEnum.DRIVER     : DeviceDriverEnum.DEVICEDRIVER_BGPLS,
+            }
+        ]))
\ No newline at end of file
diff --git a/src/device/service/drivers/bgpls/BGPLSDriver.py b/src/device/service/drivers/bgpls/BGPLSDriver.py
new file mode 100644
index 0000000000000000000000000000000000000000..be7b4656e4f2e274c182b0ed9686e4127e81ae97
--- /dev/null
+++ b/src/device/service/drivers/bgpls/BGPLSDriver.py
@@ -0,0 +1,233 @@
+# 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,threading, queue,time,signal
+from datetime import datetime, timedelta
+from typing import Any, Iterator, List, Optional, Tuple, Union
+# from apscheduler.executors.pool import ThreadPoolExecutor
+# from apscheduler.job import Job
+# from apscheduler.jobstores.memory import MemoryJobStore
+# from apscheduler.schedulers.background import BackgroundScheduler
+# from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, metered_subclass_method, INF
+# from common.type_checkers.Checkers import chk_float, chk_length, chk_string, chk_type
+
+
+import logging,anytree, json, pytz, queue, re, threading
+import grpc
+from .Tools import grpcComms,Link,Node,UpdateInfo
+from .protos import grpcService_pb2_grpc
+from .protos import grpcService_pb2
+
+
+from concurrent import futures
+from lxml import etree
+import os
+import subprocess
+from multiprocessing import Pool
+
+from device.service.driver_api._Driver import _Driver
+from apscheduler.executors.pool import ThreadPoolExecutor
+from apscheduler.job import Job
+from apscheduler.jobstores.memory import MemoryJobStore
+from apscheduler.schedulers.background import BackgroundScheduler
+from common.method_wrappers.Decorator import MetricTypeEnum, MetricsPool, metered_subclass_method, INF
+from common.type_checkers.Checkers import chk_float, chk_length, chk_string, chk_type
+from device.service.driver_api._Driver import _Driver
+from device.service.driver_api.AnyTreeTools import TreeNode, dump_subtree, get_subnode, set_subnode_value
+
+SERVER_ADDRESS = 'localhost:2021'
+SERVER_ID = 1
+_ONE_DAY_IN_SECONDS = 60 * 60 * 24
+
+XML_FILE="BGP4Parameters_3.xml"
+XML_CONFIG_FILE="TMConfiguration_guillermo.xml"
+
+LOGGER = logging.getLogger(__name__)
+
+
+# Esto tiene que heredar de _Driver¿
+class BGPLSDriver(_Driver):
+    """
+    This class gets the current topology from a bgps speaker module in java 
+    and updates the posible new devices to add in the context topology.
+    Needs the address, port and as_number from the device giving de information via bgpls
+    to the java module.
+    """
+    def __init__(self, address : str, port : int, asNumber : int,**settings) -> None: # pylint: disable=super-init-not-called
+        self.__lock = threading.Lock()
+        self.__started = threading.Event()
+        self.__terminate = threading.Event()
+        self.__out_samples = queue.Queue()
+        # self.__scheduler = BackgroundScheduler(daemon=True) # scheduler used to emulate sampling events
+        # self.__scheduler.configure(
+        #     jobstores = {'default': MemoryJobStore()},
+        #     executors = {'default': ThreadPoolExecutor(max_workers=1)},
+        #     job_defaults = {'coalesce': False, 'max_instances': 3},
+        #     timezone=pytz.utc)
+        # TODO: atributos necesarios
+        # self.__server=asyncio.run(grpc.aio.server())
+
+        self.__address=address
+        self.__port=port
+        self.__asNumber=asNumber
+        self.__configFile=XML_CONFIG_FILE
+        self.__process=0
+        self.__comms=grpcComms
+
+     
+
+    async def Connect(self) -> bool:
+            # TODO: Metodos necesarios para conectarte al speaker
+            LOGGER.info("CONNECT BGPLSDriver")
+            # If started, assume it is already connected
+            if self.__started.is_set(): return True
+            # self.__scheduler.start()
+            self.__started.set() #notifyAll -->event.is_set()
+            # 10 workers ?
+            with self.__lock:
+                self.__server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+                grpcService_pb2_grpc.add_updateServiceServicer_to_server(self, self.__server)
+                self.__server.add_insecure_port(SERVER_ADDRESS)
+                # server.add_secure_port(SERVER_ADDRESS)
+                LOGGER.info("Starting server on %s", SERVER_ADDRESS)
+                await self.__server.start()
+                try:
+                    while True:
+                        time.sleep(_ONE_DAY_IN_SECONDS)
+                except KeyboardInterrupt:
+                    LOGGER.info("DISCONNECT")
+                    self.Disconnect()
+                return True
+
+
+    def Disconnect(self) -> bool:
+        # TODO: channel grpc close
+        self.__terminate.set()
+        # If not started, assume it is already disconnected
+        if not self.__started.is_set(): return True
+
+        LOGGER.info("Keyboard interrupt, stop server")
+        self.__server.stop(0)
+        # Disconnect triggers deactivation of sampling events
+        # self.__scheduler.shutdown()
+        exit(0)
+        return True
+
+    # @metered_subclass_method(METRICS_POOL)
+    def update(self,request, context) -> bool:
+        """
+        Processes the messages recived by de grpc server
+        """
+        with self.__lock:
+            #TODO: Get update
+            LOGGER.info("(server)SimpleMethod called by client the message: %s" % (request))
+            response = grpcService_pb2.updateResponse(greeting="OK")
+            link=None
+            node=None # inicializar en otro lado¿
+            for linkIn in request.link:
+                link=Link(linkIn.remoteID,linkIn.localID,linkIn.remoteIP,linkIn.localIP)
+            for nodeIn in request.node:
+                node=Node(nodeIn.nodeName,nodeIn.nodeID)
+            up=UpdateInfo(link,node)
+            return response
+
+    def GetState(self, blocking=False, terminate : Optional[threading.Event] = None) -> Iterator[Tuple[str, Any]]:
+        while True:
+            if self.__terminate.is_set(): break
+            if terminate is not None and terminate.is_set(): break
+            try:
+                sample = self.__out_samples.get(block=blocking, timeout=0.1)
+            except queue.Empty:
+                if blocking: continue
+                return
+            if sample is None: continue
+            yield sample
+
+    def setPeer(self) -> bool:
+        """
+        Sets XML existing config file with peer address and port. TODO: as_number
+        """
+
+        XMLParser = etree.XMLParser(remove_blank_text=False)
+        tree = etree.parse(XML_FILE, parser=XMLParser)
+        root = tree.getroot()
+        peerAddress = root.find(".//peer")
+        peerAddress.text=self.__address
+        peerPort = root.find(".//peerPort")
+        peerPort.text=str(self.__port)
+        tree.write(XML_FILE) #with ... as ..
+        return True
+
+    def execBGPSpeaker(self) -> bool:
+        """
+        Executes java BGPLS speaker
+        """
+        # CHECKEAR muchas cosas
+        LOGGER.debug("Before exec")
+        with subprocess.Popen(['java -jar bgp_ls.jar '+ XML_CONFIG_FILE],
+            shell=True,start_new_session=True) as self.__process:
+        #     # logging.debug(self.__process.stdout.read())
+            return True
+
+    def endBGPSpeaker(self) -> bool:
+        """
+        Starts timer to kill java BGPLS Speaker
+        """
+        LOGGER.debug("end to sleep")
+        time.sleep(15)
+        LOGGER.debug("PID: %d",self.__process.pid)
+        LOGGER.debug("Group PID: %d",os.getpgid(self.__process.pid))
+        os.killpg(os.getpgid(self.__process.pid), signal.SIGKILL)
+        self.__process.kill()
+        return True
+
+    def runThreads(self):
+        # with futures.ThreadPoolExecutor(max_workers=4) as executor:
+        #     executor.submit(bgpDriver.ConnectNotWait)
+        #     executor.submit(bgpDriver.execBGPSpeaker)
+        #     executor.submit(bgpDriver.endBGPSpeaker)
+        t1=threading.Thread(name="t1",target=bgpDriver.Connect)
+        t2=threading.Thread(name="t2",target=bgpDriver.execBGPSpeaker)
+        t3=threading.Thread(name="t3",target=bgpDriver.endBGPSpeaker)
+        t1.start()
+        t2.start()
+        t3.start()
+        return True
+
+    def getCurrentTopo():
+        # import common.tools.Device
+        # get_devices_in_topology(
+            # context_client : ContextClient, context_id : ContextId, topology_uuid : str)
+
+        return True
+
+def quit(signal, _frame):
+    LOGGER.info("Interrupted by %d, shutting down" % signal)
+    bgpDriver.Disconnect()
+
+if __name__ == "__main__":
+
+    logging.basicConfig(level=logging.DEBUG)
+    for sig in ('TERM', 'HUP', 'INT'):
+        signal.signal(getattr(signal, 'SIG'+sig), quit)
+    # TODO: add port connection speaker
+    bgpDriver=BGPLSDriver("10.95.90.76",179,65006)
+    bgpDriver.setPeer()
+    bgpDriver.runThreads()
+
+    
+    
+        
+
+
diff --git a/src/device/service/drivers/bgpls/Tools.py b/src/device/service/drivers/bgpls/Tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..61f52ad51c8b6dd0639a63dd2b297e508f642b5e
--- /dev/null
+++ b/src/device/service/drivers/bgpls/Tools.py
@@ -0,0 +1,111 @@
+
+from .protos import grpcService_pb2_grpc
+from .protos import grpcService_pb2
+
+import logging
+LOGGER = logging.getLogger(__name__)
+import os
+
+class UpdateInfo:
+    def __init__(self,link,node):
+        self.link=link
+        self.node=node
+class Link:
+    def __init__(self,rID,lID,rIP,lIP):
+        self.rID=rID
+        self.lID=lID
+        self.rIP=rIP
+        self.lIP=lIP
+class Node:
+    def __init__(self,name,nid):
+        self.Name=name
+        self.ID=nid
+
+class grpcComms(grpcService_pb2_grpc.updateServiceServicer):
+
+    def update(self,request, context) -> bool:
+        """
+        Processes the messages recived by de grpc server
+        """
+        with self.__lock:
+            #TODO: Get update
+            print("(server)SimpleMethod called by client the message: %s" % (request))
+            response = grpcService_pb2.updateResponse(greeting="OK")
+            link=None
+            node=None # inicializar en otro lado¿
+            for linkIn in request.link:
+                link=Link(linkIn.remoteID,linkIn.localID,linkIn.remoteIP,linkIn.localIP)
+            for nodeIn in request.node:
+                node=Node(nodeIn.nodeName,nodeIn.nodeID)
+            up=UpdateInfo(link,node)
+            return response
+
+from common.proto.context_pb2 import Device ,DeviceDriverEnum,ContextId,Empty
+from device.service.driver_api.DriverInstanceCache import DriverInstanceCache
+from device.service.driver_api.FilterFields import FilterFieldEnum, get_device_driver_filter_fields
+from device.service.Tools import get_connect_rules
+from . import BGPLSDriver as bgpls
+from context.client.ContextClient import ContextClient
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.tools.object_factory.Context import json_context_id
+
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+class config_BGPLSDriver():
+
+    
+    def driverSettings( context_client : ContextClient):
+
+        list_topo=[]
+        LOGGER.info("Context (driverSettings) **************%s",context_client)
+        # context_uuid = context_id['context_uuid']['uuid']
+        # response = context.GetContext(ADMIN_CONTEXT_ID)
+        contexts : ContextList = context_client.ListContexts(Empty())
+        for context_ in contexts.contexts:
+            context_uuid : str = context_.context_id.context_uuid.uuid
+            context_name : str = context_.name
+            topologies : TopologyList = context_client.ListTopologies(context_.context_id)
+        # topologies : TopologyList=context_client.ListTopologies(context_client)
+            for topology_ in topologies.topologies:
+                #topology_uuid : str = topology_.topology_id.topology_uuid.uuid
+                topology_name : str = topology_.name
+                context_topology_name  = 'Context({:s}):Topology({:s})'.format(context_name, topology_name)
+                # Topos=context.GetTopology(list_topo.topology_id)
+                LOGGER.info("topo (driverSettings) %s",topology_)
+                details=context_client.GetTopologyDetails(topology_.topology_id)
+                LOGGER.info("details (driverSettings) %s",details)
+                devices=context_client.ListDevices(Empty())
+                # LOGGER.info("devices (driverSettings) %s",devices)
+                for device_ in devices.devices:
+                    LOGGER.info("device_ (driverSettings) %s",device_.name)
+                    for config_rule_ in device_.device_config.config_rules:
+                        if config_rule_.custom.resource_key == "_connect/address":
+                            LOGGER.info("device_.resource_value-addr (driverSettings) %s",
+                            config_rule_.custom.resource_value)
+                
+        # LOGGER.info("response getContext (driverSettings) %s",response)
+        # list_topo=context.ListTopologies(response.context_id)
+        # LOGGER.info("list_topo (driverSettings) %s",list_topo)
+        # Topos=context.GetTopology(list_topo.topology_id)
+        # LOGGER.info("topo (driverSettings) %s",Topos)
+        return
+
+    def driverConnect(driver_instance_cache : DriverInstanceCache,device : Device,
+    device_uuid):
+        bgpls_instance=[driver for driver in device.device_drivers if DeviceDriverEnum.DEVICEDRIVER_BGPLS]
+        LOGGER.info(" (driverConnect) class bgpls: %s",bgpls_instance)
+        driver_filter_fields = get_device_driver_filter_fields(device)
+        connect_rules = get_connect_rules(device.device_config)
+        address  = connect_rules.get('address',  '127.0.0.1')
+        port     = connect_rules.get('port',     '0')
+        settings = connect_rules.get('settings', '{}')
+        driver : _Driver = driver_instance_cache.get(
+        device_uuid, filter_fields=driver_filter_fields, address=address, port=port, settings=settings)
+        LOGGER.info(" (driverConnect) driver: %s",driver)
+        bgpDriver=bgpls.BGPLSDriver("10.95.90.76",179,65006)
+        cwd = os.getcwd()
+        LOGGER.info("Current working directory:", cwd)
+        bgpDriver.setPeer()
+        bgpDriver.runThreads()
+        driver.Connect()
+        return
diff --git a/src/device/service/drivers/bgpls/__init__.py b/src/device/service/drivers/bgpls/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612
--- /dev/null
+++ b/src/device/service/drivers/bgpls/__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/bgpls/protos/grpcService.proto b/src/device/service/drivers/bgpls/protos/grpcService.proto
new file mode 100644
index 0000000000000000000000000000000000000000..ef3642c30a301087189db9d1e1a2abba09ba209c
--- /dev/null
+++ b/src/device/service/drivers/bgpls/protos/grpcService.proto
@@ -0,0 +1,40 @@
+syntax = "proto3";
+package src.main.proto;
+
+//el modulo java abre la comunicacion
+//cliente(java) manda la info al servidor(python)
+//el modulo en python responde con ok
+
+message updateRequest {
+
+  repeated nodeInfo node = 1;
+  // repeated : se da la posibilidad de mandar 0 o varios
+  repeated linkInfo link = 2;
+
+  // There are many more basics types, like Enum, Map
+  // See https://developers.google.com/protocol-buffers/docs/proto3
+  // for more information.
+}
+
+message nodeInfo{
+	string nodeName=1;
+	string nodeID=2;
+}
+
+message linkInfo{
+	string remoteID=1;
+	string localID=2;
+
+	string remoteIP=3;
+	string localIP=4;
+}
+
+message updateResponse {
+  string greeting = 1;
+}
+
+// Defining a Service, a Service can have multiple RPC operations
+service updateService {
+  // MODIFY HERE: Update the return to streaming return.
+  rpc update(updateRequest) returns (updateResponse);
+}
\ No newline at end of file
diff --git a/src/device/service/drivers/bgpls/protos/grpcService_pb2.py b/src/device/service/drivers/bgpls/protos/grpcService_pb2.py
new file mode 100644
index 0000000000000000000000000000000000000000..47f75875c38186d9e578a96b103a3697a1cfeadf
--- /dev/null
+++ b/src/device/service/drivers/bgpls/protos/grpcService_pb2.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: grpcService.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11grpcService.proto\x12\x0esrc.main.proto\"_\n\rupdateRequest\x12&\n\x04node\x18\x01 \x03(\x0b\x32\x18.src.main.proto.nodeInfo\x12&\n\x04link\x18\x02 \x03(\x0b\x32\x18.src.main.proto.linkInfo\",\n\x08nodeInfo\x12\x10\n\x08nodeName\x18\x01 \x01(\t\x12\x0e\n\x06nodeID\x18\x02 \x01(\t\"P\n\x08linkInfo\x12\x10\n\x08remoteID\x18\x01 \x01(\t\x12\x0f\n\x07localID\x18\x02 \x01(\t\x12\x10\n\x08remoteIP\x18\x03 \x01(\t\x12\x0f\n\x07localIP\x18\x04 \x01(\t\"\"\n\x0eupdateResponse\x12\x10\n\x08greeting\x18\x01 \x01(\t2X\n\rupdateService\x12G\n\x06update\x12\x1d.src.main.proto.updateRequest\x1a\x1e.src.main.proto.updateResponseb\x06proto3')
+
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'grpcService_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+  DESCRIPTOR._options = None
+  _UPDATEREQUEST._serialized_start=37
+  _UPDATEREQUEST._serialized_end=132
+  _NODEINFO._serialized_start=134
+  _NODEINFO._serialized_end=178
+  _LINKINFO._serialized_start=180
+  _LINKINFO._serialized_end=260
+  _UPDATERESPONSE._serialized_start=262
+  _UPDATERESPONSE._serialized_end=296
+  _UPDATESERVICE._serialized_start=298
+  _UPDATESERVICE._serialized_end=386
+# @@protoc_insertion_point(module_scope)
diff --git a/src/device/service/drivers/bgpls/protos/grpcService_pb2_grpc.py b/src/device/service/drivers/bgpls/protos/grpcService_pb2_grpc.py
new file mode 100644
index 0000000000000000000000000000000000000000..c8bbda558d60b1108bfcb1ff60fbe755bb2d75c3
--- /dev/null
+++ b/src/device/service/drivers/bgpls/protos/grpcService_pb2_grpc.py
@@ -0,0 +1,70 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+from . import grpcService_pb2 as grpcService__pb2
+
+
+class updateServiceStub(object):
+    """Defining a Service, a Service can have multiple RPC operations
+    """
+
+    def __init__(self, channel):
+        """Constructor.
+
+        Args:
+            channel: A grpc.Channel.
+        """
+        self.update = channel.unary_unary(
+                '/src.main.proto.updateService/update',
+                request_serializer=grpcService__pb2.updateRequest.SerializeToString,
+                response_deserializer=grpcService__pb2.updateResponse.FromString,
+                )
+
+
+class updateServiceServicer(object):
+    """Defining a Service, a Service can have multiple RPC operations
+    """
+
+    def update(self, request, context):
+        """MODIFY HERE: Update the return to streaming return.
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+
+def add_updateServiceServicer_to_server(servicer, server):
+    rpc_method_handlers = {
+            'update': grpc.unary_unary_rpc_method_handler(
+                    servicer.update,
+                    request_deserializer=grpcService__pb2.updateRequest.FromString,
+                    response_serializer=grpcService__pb2.updateResponse.SerializeToString,
+            ),
+    }
+    generic_handler = grpc.method_handlers_generic_handler(
+            'src.main.proto.updateService', rpc_method_handlers)
+    server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class updateService(object):
+    """Defining a Service, a Service can have multiple RPC operations
+    """
+
+    @staticmethod
+    def update(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/src.main.proto.updateService/update',
+            grpcService__pb2.updateRequest.SerializeToString,
+            grpcService__pb2.updateResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/src/pathcomp/frontend/service/algorithms/tools/ConstantsMappings.py b/src/pathcomp/frontend/service/algorithms/tools/ConstantsMappings.py
index cd1956a873dd2170c7a75db0c677db34162449ee..b38907668fd2faec199b5e2821efb1b8919e55da 100644
--- a/src/pathcomp/frontend/service/algorithms/tools/ConstantsMappings.py
+++ b/src/pathcomp/frontend/service/algorithms/tools/ConstantsMappings.py
@@ -101,6 +101,9 @@ DEVICE_TYPE_TO_LAYER = {
     DeviceTypeEnum.OPTICAL_ROADM.value                   : DeviceLayerEnum.OPTICAL_DEVICE,
     DeviceTypeEnum.EMULATED_OPTICAL_TRANSPONDER.value    : DeviceLayerEnum.OPTICAL_DEVICE,
     DeviceTypeEnum.OPTICAL_TRANSPONDER.value             : DeviceLayerEnum.OPTICAL_DEVICE,
+
+    DeviceTypeEnum.BGPLS_ASNUMBER.value                  : DeviceLayerEnum.APPLICATION_CONTROLLER, #TODO: value
+    DeviceTypeEnum.EMULATED_BGPLS_ASNUMBER.value         : DeviceLayerEnum.APPLICATION_CONTROLLER, #TODO:
 }
 
 DEVICE_LAYER_TO_SERVICE_TYPE = {
diff --git a/src/service/service/service_handler_api/FilterFields.py b/src/service/service/service_handler_api/FilterFields.py
index a73ec53f37d68e0414eeb1df146373c6906273c5..6f3e226cfe162e1165aa10dd82c9d39df27fcf78 100644
--- a/src/service/service/service_handler_api/FilterFields.py
+++ b/src/service/service/service_handler_api/FilterFields.py
@@ -33,7 +33,8 @@ DEVICE_DRIVER_VALUES = {
     DeviceDriverEnum.DEVICEDRIVER_P4,
     DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY,
     DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352,
-    DeviceDriverEnum.DEVICEDRIVER_XR
+    DeviceDriverEnum.DEVICEDRIVER_XR,
+    DeviceDriverEnum.DEVICEDRIVER_BGPLS
 }
 
 # Map allowed filter fields to allowed values per Filter field. If no restriction (free text) None is specified
diff --git a/src/webui/service/__init__.py b/src/webui/service/__init__.py
index fca1071419b3b2b61739c2a0d1d8bfa45aba5119..5ba5a35e52d45f578656610636d5897e996d8f65 100644
--- a/src/webui/service/__init__.py
+++ b/src/webui/service/__init__.py
@@ -91,6 +91,9 @@ def create_app(use_config=None, web_app_root=None):
 
     from webui.service.device.routes import device          # pylint: disable=import-outside-toplevel
     app.register_blueprint(device)
+    
+    from webui.service.topology.routes import topology          # pylint: disable=import-outside-toplevel
+    app.register_blueprint(topology)
 
     from webui.service.link.routes import link              # pylint: disable=import-outside-toplevel
     app.register_blueprint(link)
diff --git a/src/webui/service/device/routes.py b/src/webui/service/device/routes.py
index ebf77a35ffdf9c2546ddbdd1bac0c8c1f54a2b56..32fc6babc8990bbb5dfd2868f60b11e35c369119 100644
--- a/src/webui/service/device/routes.py
+++ b/src/webui/service/device/routes.py
@@ -120,6 +120,8 @@ def add():
             device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352)
         if form.device_drivers_xr.data:
             device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_XR)
+        if form.device_drivers_bgpls.data:
+            device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_BGPLS)
         device_obj.device_drivers.extend(device_drivers) # pylint: disable=no-member
 
         try:
diff --git a/src/webui/service/templates/base.html b/src/webui/service/templates/base.html
index 1dfa3687198d8a33db346ba2bbcd2989f6f109bb..daed737a493f1266288eca920075c0642aaafd8c 100644
--- a/src/webui/service/templates/base.html
+++ b/src/webui/service/templates/base.html
@@ -96,6 +96,13 @@
                   <a class="nav-link" href="{{ url_for('load_gen.home') }}">Load Generator</a>
                   {% endif %}
                 </li>
+                <li class="nav-item">
+                  {% if '/topology/' in request.path %}
+                  <a class="nav-link active" aria-current="page" href="{{ url_for('topology.home') }}">Topology</a>
+                  {% else %}
+                  <a class="nav-link" href="{{ url_for('topology.home') }}">Topology</a>
+                  {% endif %}
+                </li>
   
                 <!-- <li class="nav-item">
                   <a class="nav-link" href="#">Context</a>
diff --git a/src/webui/service/templates/topology/detail.html b/src/webui/service/templates/topology/detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..aad221c85e73b98869b90f59117228b77c02fa43
--- /dev/null
+++ b/src/webui/service/templates/topology/detail.html
@@ -0,0 +1,37 @@
+<!--
+    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.
+   -->
+
+{% extends 'base.html' %}
+
+{% block content %}
+     <h1>Device {{ device.name }} ({{ device.device_id.device_uuid.uuid }})</h1>
+     <!-- TEST -->
+     <h5>Type: {{ device.device_type }}</h5>
+     <div>
+          <label for="nombre">Device IP:</label>
+          <input type="text" id="ip" name="ip">
+          <label for="nombre">Device User:</label>
+          <input type="text" id="user" name="user">
+          <label for="nombre">Device Password:</label>
+          <input type="text" id="pass" name="pass">
+     </div>
+
+     <script src="https://d3js.org/d3.v4.min.js"></script>
+     <div id="topology"></div>
+     <script src="{{ url_for('js.topology_js') }}"></script>
+
+{% endblock %}
+   
\ No newline at end of file
diff --git a/src/webui/service/templates/topology/home.html b/src/webui/service/templates/topology/home.html
new file mode 100644
index 0000000000000000000000000000000000000000..27b864d3bb6aefb9d1586838a2466238cbe83299
--- /dev/null
+++ b/src/webui/service/templates/topology/home.html
@@ -0,0 +1,68 @@
+<!--
+ 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.
+-->
+
+{% extends 'base.html' %}
+
+{% block content %}
+    <h1>Topology</h1>
+
+    <div class="row">
+       
+        <div class="col">
+            {{ devices | length }} devices found in context <i>{{ session['context_uuid'] }}</i>
+        </div>
+    </div>
+    
+    
+    <table class="table table-striped table-hover">
+        <thead>
+          <tr>
+            <th scope="col">Name</th>
+            <th scope="col">Config Rules</th>
+            <th scope="col"></th>
+          </tr>
+        </thead>
+        <tbody>
+            {% if devices %}
+                {% for device in devices %}
+                <tr>
+                    <td>{{ device.name }}</td>
+                    <td>{{ device.device_config.config_rules | length }}</td>
+                    <td>
+                        <div class="col">
+                            <a href="{{ url_for('topology.detail', device_uuid=device.device_id.device_uuid.uuid) }}">
+                                <i class="bi bi-plus"></i>
+                                Add Device
+                            </a>
+                        </div>
+                            
+                    
+                    </td>
+                </tr>
+                {% endfor %}
+            {% else %}
+                <tr>
+                    <td colspan="3">No devices found</td>
+                </tr>
+            {% endif %}
+        </tbody>
+    </table>
+        
+    <script src="https://d3js.org/d3.v4.min.js"></script>
+    <div id="topology"></div>
+    <script src="{{ url_for('js.topology_js') }}"></script>
+
+{% endblock %}
\ No newline at end of file
diff --git a/src/webui/service/topology/__init__.py b/src/webui/service/topology/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612
--- /dev/null
+++ b/src/webui/service/topology/__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/webui/service/topology/forms.py b/src/webui/service/topology/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..ca039a9e2edbbd0176f513c150db6b120e3432ae
--- /dev/null
+++ b/src/webui/service/topology/forms.py
@@ -0,0 +1,80 @@
+# 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.
+
+# external imports
+from flask_wtf import FlaskForm
+from flask_wtf.file import FileAllowed
+from wtforms import SelectField, FileField, SubmitField
+
+from wtforms import StringField, SelectField, TextAreaField, SubmitField, BooleanField, Form
+from wtforms.validators import DataRequired, Length, NumberRange, Regexp, ValidationError
+from common.proto.context_pb2 import DeviceOperationalStatusEnum
+from webui.utils.form_validators import key_value_validator
+
+class AddDeviceForm(FlaskForm):
+    device_id = StringField('ID', 
+                           validators=[DataRequired(), Length(min=5)])
+    device_type = SelectField('Type', choices = [])                                                     
+    operational_status = SelectField('Operational Status',
+                        #    choices=[(-1, 'Select...'), (0, 'Undefined'), (1, 'Disabled'), (2, 'Enabled')],
+                           coerce=int,
+                           validators=[NumberRange(min=0)])
+    device_drivers_undefined = BooleanField('UNDEFINED / EMULATED')
+    device_drivers_openconfig = BooleanField('OPENCONFIG')
+    device_drivers_transport_api = BooleanField('TRANSPORT_API')
+    device_drivers_p4 = BooleanField('P4')
+    device_drivers_ietf_network_topology = BooleanField('IETF_NETWORK_TOPOLOGY')
+    device_drivers_onf_tr_352 = BooleanField('ONF_TR_352')
+    device_drivers_xr = BooleanField('XR')
+    device_drivers_bgpls = BooleanField('BGPLS')
+    device_config_address = StringField('connect/address',default='127.0.0.1',validators=[DataRequired(), Length(min=5)])
+    device_config_port = StringField('connect/port',default='0',validators=[DataRequired(), Length(min=1)])
+    device_config_settings = TextAreaField('connect/settings',default='{}',validators=[DataRequired(), Length(min=2)])
+    submit = SubmitField('Add')
+
+    def validate_operational_status(form, field):
+        if field.data not in DeviceOperationalStatusEnum.DESCRIPTOR.values_by_number:
+            raise ValidationError('The operational status value selected is incorrect!')
+
+class ConfigForm(FlaskForm):
+    device_key_config = StringField('Key configuration')
+    device_value_config = StringField('Value configuration')    
+    submit = SubmitField('Add')
+
+
+class UpdateDeviceForm(FlaskForm):
+    update_operational_status = SelectField('Operational Status',
+                           choices=[(-1, 'Select...'), (0, 'Undefined'), (1, 'Disabled'), (2, 'Enabled')],
+                           coerce=int,
+                           validators=[NumberRange(min=0)])
+                        
+    submit = SubmitField('Update')
+
+class ContextTopologyForm(FlaskForm):
+    context_topology = SelectField(
+        'Ctx/Topo',
+        choices=[],
+        validators=[
+            DataRequired(),
+            Length(min=1)
+        ])
+    submit = SubmitField('Submit')
+    
+class DescriptorForm(FlaskForm):
+    descriptors = FileField(
+        'Descriptors',
+        validators=[
+            FileAllowed(['json'], 'JSON Descriptors only!')
+        ])
+    submit = SubmitField('Submit')
\ No newline at end of file
diff --git a/src/webui/service/topology/routes.py b/src/webui/service/topology/routes.py
new file mode 100644
index 0000000000000000000000000000000000000000..710461b47b5dd500995beacf5f6244be41b04886
--- /dev/null
+++ b/src/webui/service/topology/routes.py
@@ -0,0 +1,232 @@
+# 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 flask import current_app, render_template, Blueprint, flash, session, redirect, url_for
+from common.proto.context_pb2 import (
+    ConfigActionEnum, Device, DeviceDriverEnum, DeviceId, DeviceList, DeviceOperationalStatusEnum, Empty, TopologyId)
+from common.tools.object_factory.Context import json_context_id
+from common.tools.object_factory.Topology import json_topology_id
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+from webui.service.device.forms import AddDeviceForm
+from common.DeviceTypes import DeviceTypeEnum
+from webui.service.topology.forms import ConfigForm
+from webui.service.topology.forms import UpdateDeviceForm
+
+topology = Blueprint('topology', __name__, url_prefix='/topoloy')
+context_client = ContextClient()
+device_client = DeviceClient()
+
+@topology.get('/')
+def home():
+    if 'context_uuid' not in session or 'topology_uuid' not in session:
+        flash("Please select a context!", "warning")
+        return redirect(url_for("main.home"))
+
+    context_uuid = session['context_uuid']
+    topology_uuid = session['topology_uuid']
+
+    context_client.connect()
+    json_topo_id = json_topology_id(topology_uuid, context_id=json_context_id(context_uuid))
+    grpc_topology = context_client.GetTopology(TopologyId(**json_topo_id))
+    topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids}
+    grpc_devices: DeviceList = context_client.ListDevices(Empty())
+    context_client.close()
+
+    devices = [
+        device for device in grpc_devices.devices
+        if device.device_id.device_uuid.uuid in topo_device_uuids
+    ]
+
+    return render_template(
+        'topology/home.html', devices=devices, dde=DeviceDriverEnum,
+        dose=DeviceOperationalStatusEnum)
+
+@topology.route('add', methods=['GET', 'POST'])
+def add():
+    form = AddDeviceForm()
+
+    # listing enum values
+    form.operational_status.choices = []
+    for key, _ in DeviceOperationalStatusEnum.DESCRIPTOR.values_by_name.items():
+        form.operational_status.choices.append(
+            (DeviceOperationalStatusEnum.Value(key), key.replace('DEVICEOPERATIONALSTATUS_', '')))
+
+    # items for Device Type field
+    for device_type in DeviceTypeEnum:
+        form.device_type.choices.append((device_type.value,device_type.value))    
+
+    if form.validate_on_submit():
+        device_obj = Device()
+        # Device UUID: 
+        device_obj.device_id.device_uuid.uuid = form.device_id.data
+
+        # Device type: 
+        device_obj.device_type = str(form.device_type.data)
+
+        # Device configurations: 
+        config_rule = device_obj.device_config.config_rules.add()
+        config_rule.action = ConfigActionEnum.CONFIGACTION_SET
+        config_rule.custom.resource_key = '_connect/address'
+        config_rule.custom.resource_value = form.device_config_address.data
+
+        config_rule = device_obj.device_config.config_rules.add()
+        config_rule.action = ConfigActionEnum.CONFIGACTION_SET
+        config_rule.custom.resource_key = '_connect/port'
+        config_rule.custom.resource_value = form.device_config_port.data
+
+        config_rule = device_obj.device_config.config_rules.add()
+        config_rule.action = ConfigActionEnum.CONFIGACTION_SET
+        config_rule.custom.resource_key = '_connect/settings'
+
+        try:
+            device_config_settings = json.loads(form.device_config_settings.data)
+        except: # pylint: disable=bare-except
+            device_config_settings = form.device_config_settings.data
+
+        if isinstance(device_config_settings, dict):
+            config_rule.custom.resource_value = json.dumps(device_config_settings)
+        else:
+            config_rule.custom.resource_value = str(device_config_settings)
+
+        # Device status: 
+        device_obj.device_operational_status = form.operational_status.data
+
+        # Device drivers: 
+        if form.device_drivers_undefined.data:
+            device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_UNDEFINED)
+        if form.device_drivers_openconfig.data:
+            device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG)
+        if form.device_drivers_transport_api.data:
+            device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API)
+        if form.device_drivers_p4.data:
+            device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_P4)
+        if form.device_drivers_ietf_network_topology.data:
+            device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY)
+        if form.device_drivers_onf_tr_352.data:
+            device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352)
+        if form.device_drivers_xr.data:
+            device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_XR)
+        if form.device_drivers_bgpls.data:
+            device_obj.device_drivers.append(DeviceDriverEnum.DEVICEDRIVER_BGPLS)
+
+        try:
+            device_client.connect()
+            response: DeviceId = device_client.AddDevice(device_obj)
+            device_client.close()
+            flash(f'New device was created with ID "{response.device_uuid.uuid}".', 'success')
+            return redirect(url_for('device.home'))
+        except Exception as e:
+            flash(f'Problem adding the device. {e.details()}', 'danger')
+        
+    return render_template('device/add.html', form=form,
+                        submit_text='Add New Device')
+
+@topology.route('detail/<path:device_uuid>', methods=['GET', 'POST'])
+def detail(device_uuid: str):
+    request = DeviceId()
+    request.device_uuid.uuid = device_uuid
+    context_client.connect()
+    response = context_client.GetDevice(request)
+    context_client.close()
+    return render_template('topology/detail.html', device=response,
+                                                 dde=DeviceDriverEnum,
+                                                 dose=DeviceOperationalStatusEnum)
+
+@topology.get('<path:device_uuid>/delete')
+def delete(device_uuid):
+    try:
+
+        # first, check if device exists!
+        # request: DeviceId = DeviceId()
+        # request.device_uuid.uuid = device_uuid
+        # response: Device = client.GetDevice(request)
+        # TODO: finalize implementation
+
+        request = DeviceId()
+        request.device_uuid.uuid = device_uuid
+        device_client.connect()
+        response = device_client.DeleteDevice(request)
+        device_client.close()
+
+        flash(f'Device "{device_uuid}" deleted successfully!', 'success')
+    except Exception as e:
+        flash(f'Problem deleting device "{device_uuid}": {e.details()}', 'danger')
+        current_app.logger.exception(e)
+    return redirect(url_for('device.home'))
+
+@topology.route('<path:device_uuid>/addconfig', methods=['GET', 'POST'])
+def addconfig(device_uuid):
+    form = ConfigForm()
+    request = DeviceId()
+    request.device_uuid.uuid = device_uuid
+    context_client.connect()
+    response = context_client.GetDevice(request)
+    context_client.close()
+
+    if form.validate_on_submit():
+        device = Device()
+        device.CopyFrom(response)
+        config_rule = device.device_config.config_rules.add()
+        config_rule.action = ConfigActionEnum.CONFIGACTION_SET
+        config_rule.custom.resource_key = form.device_key_config.data
+        config_rule.custom.resource_value = form.device_value_config.data
+        try:
+            device_client.connect()
+            response: DeviceId = device_client.ConfigureDevice(device)
+            device_client.close()
+            flash(f'New configuration was created with ID "{response.device_uuid.uuid}".', 'success')
+            return redirect(url_for('device.home'))
+        except Exception as e:
+             flash(f'Problem adding the device. {e.details()}', 'danger')
+
+    return render_template('topology/addconfig.html', form=form,  submit_text='Add New Configuration')
+
+@topology.route('updateconfig', methods=['GET', 'POST'])
+def updateconfig():
+
+        
+    return render_template('topology/updateconfig.html')
+
+
+@topology.route('<path:device_uuid>/update', methods=['GET', 'POST'])
+def update(device_uuid):
+    form = UpdateDeviceForm()
+    request = DeviceId()
+    request.device_uuid.uuid = device_uuid
+    context_client.connect()
+    response = context_client.GetDevice(request)
+    context_client.close()
+
+    # listing enum values
+    form.update_operational_status.choices = []
+    for key, value in DeviceOperationalStatusEnum.DESCRIPTOR.values_by_name.items():
+        form.update_operational_status.choices.append((DeviceOperationalStatusEnum.Value(key), key.replace('DEVICEOPERATIONALSTATUS_', '')))
+
+    form.update_operational_status.default = response.device_operational_status
+
+    if form.validate_on_submit():
+        device = Device()
+        device.CopyFrom(response)
+        device.device_operational_status = form.update_operational_status.data
+        try:
+            device_client.connect()
+            response: DeviceId = device_client.ConfigureDevice(device)
+            device_client.close()
+            flash(f'Status of device with ID "{response.device_uuid.uuid}" was updated.', 'success')
+            return redirect(url_for('device.home'))
+        except Exception as e:
+             flash(f'Problem updating the device. {e.details()}', 'danger')  
+    return render_template('topology/update.html', device=response, form=form, submit_text='Update Device')