diff --git a/src/device/requirements.in b/src/device/requirements.in
index dde08cf195ecb503c7a10f75a2df9ca9f1a0c651..3bac91e712575d62a6a3809f56a663427a36e5c3 100644
--- a/src/device/requirements.in
+++ b/src/device/requirements.in
@@ -4,7 +4,7 @@ fastcache==1.1.0
 grpcio==1.43.0
 grpcio-health-checking==1.43.0
 Jinja2==3.0.3
-netconf-client==2.0.0 #1.7.3
+ncclient==0.6.13
 p4runtime==1.3.0
 paramiko==2.9.2
 prometheus-client==0.13.0
diff --git a/src/device/service/driver_api/_Driver.py b/src/device/service/driver_api/_Driver.py
index f30165a178a5946c414157da5d09df07bf060a39..7dbb9eddb238dcaae9d00b579a1851aacf53225d 100644
--- a/src/device/service/driver_api/_Driver.py
+++ b/src/device/service/driver_api/_Driver.py
@@ -21,6 +21,7 @@ RESOURCE_ENDPOINTS         = '__endpoints__'
 RESOURCE_INTERFACES        = '__interfaces__'
 RESOURCE_NETWORK_INSTANCES = '__network_instances__'
 RESOURCE_ROUTING_POLICIES  = '__routing_policies__'
+RESOURCE_ACL               = '__acl__'
 
 class _Driver:
     def __init__(self, address : str, port : int, **settings) -> None:
diff --git a/src/device/service/drivers/openconfig/OpenConfigDriver.py b/src/device/service/drivers/openconfig/OpenConfigDriver.py
index 7f582c4880bafd08aee0204c7498ea3a3e7ad279..b282178989fa3f357a77fd6a1aa8fb6900fd430d 100644
--- a/src/device/service/drivers/openconfig/OpenConfigDriver.py
+++ b/src/device/service/drivers/openconfig/OpenConfigDriver.py
@@ -20,8 +20,7 @@ from apscheduler.executors.pool import ThreadPoolExecutor
 from apscheduler.job import Job
 from apscheduler.jobstores.memory import MemoryJobStore
 from apscheduler.schedulers.background import BackgroundScheduler
-from netconf_client.connect import connect_ssh, Session
-from netconf_client.ncclient import Manager
+from ncclient.manager import Manager, connect_ssh
 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
@@ -31,8 +30,10 @@ from device.service.driver_api.AnyTreeTools import TreeNode, get_subnode, set_su
 from .templates import ALL_RESOURCE_KEYS, EMPTY_CONFIG, compose_config, get_filter, parse
 from .RetryDecorator import retry
 
+
 DEBUG_MODE = False
-#logging.getLogger('ncclient.transport.ssh').setLevel(logging.DEBUG if DEBUG_MODE else logging.WARNING)
+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)
@@ -59,29 +60,41 @@ class NetconfSessionHandler:
         self.__connected = threading.Event()
         self.__address = address
         self.__port = int(port)
-        self.__username = settings.get('username')
-        self.__password = settings.get('password')
-        self.__timeout = int(settings.get('timeout', 120))
-        self.__netconf_session : Session = None
-        self.__netconf_manager : Manager = None
+        self.__username       = settings.get('username')
+        self.__password       = settings.get('password')
+        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.__device_params  = settings.get('device_params', {})
+        self.__manager_params = settings.get('manager_params', {})
+        self.__nc_params      = settings.get('nc_params', {})
+        self.__manager : Manager   = None
+        self.__candidate_supported = False
 
     def connect(self):
         with self.__lock:
-            self.__netconf_session = connect_ssh(
-                host=self.__address, port=self.__port, username=self.__username, password=self.__password)
-            self.__netconf_manager = Manager(self.__netconf_session, timeout=self.__timeout)
-            self.__netconf_manager.set_logger_level(logging.DEBUG if DEBUG_MODE else logging.WARNING)
+            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.__netconf_manager.close_session()
+            self.__manager.close_session()
+
+    @property
+    def use_candidate(self): return self.__candidate_supported and not self.__force_running
 
     @RETRY_DECORATOR
     def get(self, filter=None, with_defaults=None): # pylint: disable=redefined-builtin
         with self.__lock:
-            return self.__netconf_manager.get(filter=filter, with_defaults=with_defaults)
+            return self.__manager.get(filter=filter, with_defaults=with_defaults)
 
     @RETRY_DECORATOR
     def edit_config(
@@ -90,10 +103,16 @@ class NetconfSessionHandler:
     ):
         if config == EMPTY_CONFIG: return
         with self.__lock:
-            self.__netconf_manager.edit_config(
+            self.__manager.edit_config(
                 config, target=target, default_operation=default_operation, test_option=test_option,
                 error_option=error_option, format=format)
 
+    def locked(self, target):
+        return self.__manager.locked(target=target)
+
+    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)
+
 def compute_delta_sample(previous_sample, previous_timestamp, current_sample, current_timestamp):
     if previous_sample is None: return None
     if previous_timestamp is None: return None
@@ -162,6 +181,36 @@ def do_sampling(samples_cache : SamplesCache, resource_key : str, out_samples :
     except: # pylint: disable=bare-except
         LOGGER.exception('Error retrieving samples')
 
+def edit_config(
+    netconf_handler : NetconfSessionHandler, resources : List[Tuple[str, Any]], delete=False, target='running',
+    default_operation='merge', test_option=None, error_option=None, format='xml' # pylint: disable=redefined-builtin
+):
+    str_method = 'DeleteConfig' if delete else 'SetConfig'
+    LOGGER.info('[{:s}] resources = {:s}'.format(str_method, str(resources)))
+    results = [None for _ in resources]
+    for i,resource in enumerate(resources):
+        str_resource_name = 'resources[#{:d}]'.format(i)
+        try:
+            LOGGER.info('[{:s}] resource = {:s}'.format(str_method, str(resource)))
+            chk_type(str_resource_name, resource, (list, tuple))
+            chk_length(str_resource_name, resource, min_length=2, max_length=2)
+            resource_key,resource_value = resource
+            chk_string(str_resource_name + '.key', resource_key, allow_empty=False)
+            str_config_message = compose_config(resource_key, resource_value, delete=delete)
+            if str_config_message is None: raise UnsupportedResourceKeyException(resource_key)
+            LOGGER.info('[{:s}] str_config_message[{:d}] = {:s}'.format(
+                str_method, len(str_config_message), str(str_config_message)))
+            netconf_handler.edit_config(
+                config=str_config_message, target=target, default_operation=default_operation,
+                test_option=test_option, error_option=error_option, format=format)
+            results[i] = True
+        except Exception as e: # pylint: disable=broad-except
+            str_operation = 'preparing' if target == 'candidate' else ('deleting' if delete else 'setting')
+            msg = '[{:s}] Exception {:s} {:s}: {:s}'
+            LOGGER.exception(msg.format(str_method, str_operation, str_resource_name, str(resource)))
+            results[i] = e # if validation fails, store the exception
+    return results
+
 class OpenConfigDriver(_Driver):
     def __init__(self, address : str, port : int, **settings) -> None: # pylint: disable=super-init-not-called
         self.__lock = threading.Lock()
@@ -227,51 +276,33 @@ class OpenConfigDriver(_Driver):
     def SetConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
         chk_type('resources', resources, list)
         if len(resources) == 0: return []
-        results = []
-        LOGGER.info('[SetConfig] resources = {:s}'.format(str(resources)))
         with self.__lock:
-            for i,resource in enumerate(resources):
-                str_resource_name = 'resources[#{:d}]'.format(i)
-                try:
-                    LOGGER.info('[SetConfig] resource = {:s}'.format(str(resource)))
-                    chk_type(str_resource_name, resource, (list, tuple))
-                    chk_length(str_resource_name, resource, min_length=2, max_length=2)
-                    resource_key,resource_value = resource
-                    chk_string(str_resource_name + '.key', resource_key, allow_empty=False)
-                    str_config_message = compose_config(resource_key, resource_value)
-                    if str_config_message is None: raise UnsupportedResourceKeyException(resource_key)
-                    LOGGER.info('[SetConfig] str_config_message[{:d}] = {:s}'.format(
-                        len(str_config_message), str(str_config_message)))
-                    self.__netconf_handler.edit_config(str_config_message, target='running')
-                    results.append(True)
-                except Exception as e: # pylint: disable=broad-except
-                    LOGGER.exception('Exception setting {:s}: {:s}'.format(str_resource_name, str(resource)))
-                    results.append(e) # if validation fails, store the exception
+            if self.__netconf_handler.use_candidate:
+                with self.__netconf_handler.locked(target='candidate'):
+                    results = edit_config(self.__netconf_handler, resources, target='candidate')
+                    try:
+                        self.__netconf_handler.commit()
+                    except Exception as e: # pylint: disable=broad-except
+                        LOGGER.exception('[SetConfig] Exception commiting resources: {:s}'.format(str(resources)))
+                        results = [e for _ in resources] # if commit fails, set exception in each resource
+            else:
+                results = edit_config(self.__netconf_handler, resources)
         return results
 
     def DeleteConfig(self, resources : List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
         chk_type('resources', resources, list)
         if len(resources) == 0: return []
-        results = []
-        LOGGER.info('[DeleteConfig] resources = {:s}'.format(str(resources)))
         with self.__lock:
-            for i,resource in enumerate(resources):
-                str_resource_name = 'resources[#{:d}]'.format(i)
-                try:
-                    LOGGER.info('[DeleteConfig] resource = {:s}'.format(str(resource)))
-                    chk_type(str_resource_name, resource, (list, tuple))
-                    chk_length(str_resource_name, resource, min_length=2, max_length=2)
-                    resource_key,resource_value = resource
-                    chk_string(str_resource_name + '.key', resource_key, allow_empty=False)
-                    str_config_message = compose_config(resource_key, resource_value, delete=True)
-                    if str_config_message is None: raise UnsupportedResourceKeyException(resource_key)
-                    LOGGER.info('[DeleteConfig] str_config_message[{:d}] = {:s}'.format(
-                        len(str_config_message), str(str_config_message)))
-                    self.__netconf_handler.edit_config(str_config_message, target='running')
-                    results.append(True)
-                except Exception as e: # pylint: disable=broad-except
-                    LOGGER.exception('Exception deleting {:s}: {:s}'.format(str_resource_name, str(resource_key)))
-                    results.append(e) # if validation fails, store the exception
+            if self.__netconf_handler.use_candidate:
+                with self.__netconf_handler.locked(target='candidate'):
+                    results = edit_config(self.__netconf_handler, resources, target='candidate', delete=True)
+                    try:
+                        self.__netconf_handler.commit()
+                    except Exception as e: # pylint: disable=broad-except
+                        LOGGER.exception('[DeleteConfig] Exception commiting resources: {:s}'.format(str(resources)))
+                        results = [e for _ in resources] # if commit fails, set exception in each resource
+            else:
+                results = edit_config(self.__netconf_handler, resources, delete=True)
         return results
 
     def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
diff --git a/src/device/service/drivers/openconfig/templates/Acl.py b/src/device/service/drivers/openconfig/templates/Acl.py
new file mode 100644
index 0000000000000000000000000000000000000000..6cd90f373427e2ab55550985929c4cfcd8798702
--- /dev/null
+++ b/src/device/service/drivers/openconfig/templates/Acl.py
@@ -0,0 +1,123 @@
+# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+#
+# 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, lxml.etree as ET
+from typing import Any, Dict, List, Tuple
+from .Namespace import NAMESPACES
+from .Tools import add_value_from_tag
+
+LOGGER = logging.getLogger(__name__)
+
+XPATH_ACL_SET     = "//ocacl:acl/ocacl:acl-sets/ocacl:acl-set"
+XPATH_A_ACL_ENTRY = ".//ocacl:acl-entries/ocacl:ecl-entry"
+XPATH_A_IPv4      = ".//ocacl:ipv4/ocacl:config"
+XPATH_A_TRANSPORT = ".//ocacl:transport/ocacl:config"
+XPATH_A_ACTIONS   = ".//ocacl:actions/ocacl:config"
+
+XPATH_INTERFACE   = "//ocacl:acl/ocacl:interfaces/ocacl:interface"
+XPATH_I_INGRESS   = ".//ocacl:ingress-acl-sets/ocacl:ingress-acl-set"
+XPATH_I_EGRESS    = ".//ocacl:egress-acl-sets/ocacl:egress-acl-set"
+
+def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]:
+    #LOGGER.info('[ACL] xml_data = {:s}'.format(str(ET.tostring(xml_data))))
+
+    response = []
+    acl = {}
+
+    for xml_acl in xml_data.xpath(XPATH_ACL_SET, namespaces=NAMESPACES):
+        #LOGGER.info('xml_acl = {:s}'.format(str(ET.tostring(xml_acl))))
+
+        acl_name = xml_acl.find('ocacl:name', namespaces=NAMESPACES)
+        if acl_name is None or acl_name.text is None: continue
+        add_value_from_tag(acl, 'name', acl_name)
+
+        acl_type = xml_acl.find('ocacl:type', namespaces=NAMESPACES)
+        add_value_from_tag(acl, 'type', acl_type)
+
+        for xml_acl_entries in xml_acl.xpath(XPATH_A_ACL_ENTRY, namespaces=NAMESPACES):
+
+            acl_id = xml_acl_entries.find('ocacl:sequence_id', namespaces=NAMESPACES)
+            add_value_from_tag(acl, 'sequence_id', acl_id)
+
+            for xml_ipv4 in xml_acl_entries.xpath(XPATH_A_IPv4, namespaces=NAMESPACES):
+
+                ipv4_source = xml_ipv4.find('ocacl:source_address', namespaces=NAMESPACES)
+                add_value_from_tag(acl, 'source_address' , ipv4_source)
+
+                ipv4_destination = xml_ipv4.find('ocacl:destination_address', namespaces=NAMESPACES)
+                add_value_from_tag(acl, 'destination_address' , ipv4_destination)
+
+                ipv4_protocol = xml_ipv4.find('ocacl:protocol', namespaces=NAMESPACES)
+                add_value_from_tag(acl, 'protocol' , ipv4_protocol)
+
+                ipv4_dscp = xml_ipv4.find('ocacl:dscp', namespaces=NAMESPACES)
+                add_value_from_tag(acl, 'dscp' , ipv4_dscp)
+
+                ipv4_hop_limit = xml_ipv4.find('ocacl:hop_limit', namespaces=NAMESPACES)
+                add_value_from_tag(acl, 'hop_limit' , ipv4_hop_limit)
+
+            for xml_transport in xml_acl_entries.xpath(XPATH_A_TRANSPORT, namespaces=NAMESPACES):
+
+                transport_source = xml_transport.find('ocacl:source_port', namespaces=NAMESPACES)
+                add_value_from_tag(acl, 'source_port' ,transport_source)
+
+                transport_destination = xml_transport.find('ocacl:destination_port', namespaces=NAMESPACES)
+                add_value_from_tag(acl, 'destination_port' ,transport_destination)
+
+                transport_tcp_flags = xml_transport.find('ocacl:tcp_flags', namespaces=NAMESPACES)
+                add_value_from_tag(acl, 'tcp_flags' ,transport_tcp_flags)
+
+            for xml_action in xml_acl_entries.xpath(XPATH_A_ACTIONS, namespaces=NAMESPACES):
+
+                action = xml_action.find('ocacl:forwarding_action', namespaces=NAMESPACES)
+                add_value_from_tag(acl, 'forwarding_action' ,action)
+
+                log_action = xml_action.find('ocacl:log_action', namespaces=NAMESPACES)
+                add_value_from_tag(acl, 'log_action' ,log_action)
+
+            resource_key =  '/acl/acl-set[{:s}][{:s}]/acl-entry[{:s}]'.format(
+                acl['name'], acl['type'], acl['sequence-id'])
+            response.append((resource_key,acl))
+
+    for xml_interface in xml_data.xpath(XPATH_INTERFACE, namespaces=NAMESPACES):
+
+        interface = {}
+
+        interface_id = xml_interface.find('ocacl:id', namespaces=NAMESPACES)
+        add_value_from_tag(interface, 'id' , interface_id)
+
+        for xml_ingress in xml_interface.xpath(XPATH_I_INGRESS, namespaces=NAMESPACES):
+
+            i_name = xml_ingress.find('ocacl:set_name_ingress', namespaces=NAMESPACES)
+            add_value_from_tag(interface, 'ingress_set_name' , i_name)
+
+            i_type = xml_ingress.find('ocacl:type_ingress', namespaces=NAMESPACES)
+            add_value_from_tag(interface, 'ingress_type' , i_type)
+
+            resource_key =  '/acl/interfaces/ingress[{:s}][{:s}]'.format(
+                acl['name'], acl['type'])
+            response.append((resource_key,interface))
+
+        for xml_egress in xml_interface.xpath(XPATH_I_EGRESS, namespaces=NAMESPACES):
+
+            e_name = xml_egress.find('ocacl:set_name_egress', namespaces=NAMESPACES)
+            add_value_from_tag(interface, 'egress_set_name' , e_name)
+
+            e_type = xml_egress.find('ocacl:type_egress', namespaces=NAMESPACES)
+            add_value_from_tag(interface, 'egress_type' , e_type)
+
+            resource_key =  '/acl/interfaces/egress[{:s}][{:s}]'.format(
+                acl['name'], acl['type'])
+            response.append((resource_key,interface))
+    return response
diff --git a/src/device/service/drivers/openconfig/templates/Namespace.py b/src/device/service/drivers/openconfig/templates/Namespace.py
index 35be5827db892541847a3c02af42e2fd08ee0e1d..94af95566f33751a25fb1cb1c817cbffa910eec4 100644
--- a/src/device/service/drivers/openconfig/templates/Namespace.py
+++ b/src/device/service/drivers/openconfig/templates/Namespace.py
@@ -13,8 +13,9 @@
 # limitations under the License.
 
 
-NAMESPACE_NETCONF       = 'urn:ietf:params:xml:ns:netconf:base:1.0'
+NAMESPACE_NETCONF                = 'urn:ietf:params:xml:ns:netconf:base:1.0'
 
+NAMESPACE_ACL                    = 'http://openconfig.net/yang/acl'
 NAMESPACE_BGP_POLICY             = 'http://openconfig.net/yang/bgp-policy'
 NAMESPACE_INTERFACES             = 'http://openconfig.net/yang/interfaces'
 NAMESPACE_INTERFACES_IP          = 'http://openconfig.net/yang/interfaces/ip'
@@ -30,6 +31,7 @@ NAMESPACE_VLAN                   = 'http://openconfig.net/yang/vlan'
 
 NAMESPACES = {
     'nc'   : NAMESPACE_NETCONF,
+    'ocacl': NAMESPACE_ACL,
     'ocbp' : NAMESPACE_BGP_POLICY,
     'oci'  : NAMESPACE_INTERFACES,
     'ociip': NAMESPACE_INTERFACES_IP,
diff --git a/src/device/service/drivers/openconfig/templates/RoutingPolicy.py b/src/device/service/drivers/openconfig/templates/RoutingPolicy.py
index aae8483706646801dccf6d3018eb9860209bf52b..369732de3fe58c52a2e9ab2227899160d091ff68 100644
--- a/src/device/service/drivers/openconfig/templates/RoutingPolicy.py
+++ b/src/device/service/drivers/openconfig/templates/RoutingPolicy.py
@@ -15,7 +15,7 @@
 import copy, logging, lxml.etree as ET
 from typing import Any, Dict, List, Tuple
 from .Namespace import NAMESPACES
-from .Tools import add_value_from_collection, add_value_from_tag
+from .Tools import add_value_from_tag
 
 LOGGER = logging.getLogger(__name__)
 
diff --git a/src/device/service/drivers/openconfig/templates/__init__.py b/src/device/service/drivers/openconfig/templates/__init__.py
index eb7842ea8d5b62798f08429776700a792f69dc91..901f5cf0291dca1bda155e20abd16db5989df7dc 100644
--- a/src/device/service/drivers/openconfig/templates/__init__.py
+++ b/src/device/service/drivers/openconfig/templates/__init__.py
@@ -16,17 +16,19 @@ import json, logging, lxml.etree as ET, re
 from typing import Any, Dict
 from jinja2 import Environment, PackageLoader, select_autoescape
 from device.service.driver_api._Driver import (
-    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES)
+    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_ACL)
 from .EndPoints import parse as parse_endpoints
 from .Interfaces import parse as parse_interfaces, parse_counters
 from .NetworkInstances import parse as parse_network_instances
 from .RoutingPolicy import parse as parse_routing_policy
+from .Acl import parse as parse_acl
 
 ALL_RESOURCE_KEYS = [
     RESOURCE_ENDPOINTS,
     RESOURCE_INTERFACES,
     RESOURCE_ROUTING_POLICIES,      # routing policies should come before network instances
     RESOURCE_NETWORK_INSTANCES,
+    RESOURCE_ACL,
 ]
 
 RESOURCE_KEY_MAPPINGS = {
@@ -34,6 +36,7 @@ RESOURCE_KEY_MAPPINGS = {
     RESOURCE_INTERFACES       : 'interface',
     RESOURCE_NETWORK_INSTANCES: 'network_instance',
     RESOURCE_ROUTING_POLICIES : 'routing_policy',
+    RESOURCE_ACL              : 'acl',
 }
 
 RESOURCE_PARSERS = {
@@ -42,6 +45,7 @@ RESOURCE_PARSERS = {
     'network_instance': parse_network_instances,
     'routing_policy'  : parse_routing_policy,
     'interfaces/interface/state/counters': parse_counters,
+    'acl'             : parse_acl,
 }
 
 LOGGER = logging.getLogger(__name__)
diff --git a/src/device/service/drivers/openconfig/templates/acl/acl-set/acl-entry/edit_config.xml b/src/device/service/drivers/openconfig/templates/acl/acl-set/acl-entry/edit_config.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fac259b6fdcd3cbded93088ddc6335ea2bfe5f69
--- /dev/null
+++ b/src/device/service/drivers/openconfig/templates/acl/acl-set/acl-entry/edit_config.xml
@@ -0,0 +1,42 @@
+<acl xmlns="http://openconfig.net/yang/acl">
+  <acl-sets>
+    <acl-set{% if operation is defined %} xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="{{operation}}"{% endif %}>
+      <name>{{name}}</name>
+      <type>{{type}}</type>
+      <config>
+        <name>{{name}}</name>
+        <type>{{type}}</type>
+      </config>
+      <acl-entries>
+        <acl-entry>
+          <sequence-id>{{sequence_id}}</sequence-id>
+          <config>
+            <sequence-id>{{sequence_id}}</sequence-id>
+          </config>
+          <ipv4>
+            <config>
+              {% if source_address is defined %}<source-address>{{source_address}}</source-address>{% endif%}
+              {% if destination_address is defined %}<destination-address>{{destination_address}}</destination-address>{% endif%}
+              {% if protocol is defined %}<protocol>{{protocol}}</protocol>{% endif%}
+              {% if dscp is defined %}<dscp>{{dscp}}</dscp>{% endif%}
+              {% if hop_limit is defined %}<hop-limit>{{hop_limit}}</hop-limit>{% endif%}
+            </config>
+          </ipv4>
+          <transport>
+            <config>
+              {% if source_port is defined %}<source-port>{{source_port}}</source-port>{% endif%}
+              {% if destination_port is defined %}<destination-port>{{destination_port}}</destination-port>{% endif%}
+              {% if tcp_flags is defined %}<tcp-flags>{{tcp_flags}}</tcp-flags>{% endif%}
+            </config>
+          </transport>
+          <actions>
+            <config>
+              {% if forwarding_action is defined %}<forwarding-action>{{forwarding_action}}</forwarding-action>{% endif%}
+              {% if log_action is defined %}<log-action>{{log_action}}</log-action>{% endif%}
+            </config>
+          </actions>
+        </acl-entry>
+      </acl-entries>
+    </acl-set>
+  </acl-sets>
+</acl>
diff --git a/src/device/service/drivers/openconfig/templates/acl/get.xml b/src/device/service/drivers/openconfig/templates/acl/get.xml
new file mode 100644
index 0000000000000000000000000000000000000000..dfed162427d03953890ecf1f90352cc26a76cbc9
--- /dev/null
+++ b/src/device/service/drivers/openconfig/templates/acl/get.xml
@@ -0,0 +1,7 @@
+<acl xmlns="http://openconfig.net/yang/acl">
+    <acl-sets>
+    </acl-sets>
+    <interfaces>
+    </interfaces>
+</acl>
+    
\ No newline at end of file
diff --git a/src/device/service/drivers/openconfig/templates/acl/interfaces/egress/edit_config.xml b/src/device/service/drivers/openconfig/templates/acl/interfaces/egress/edit_config.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d987b0cc4b40298533f140f71af83c6fad884020
--- /dev/null
+++ b/src/device/service/drivers/openconfig/templates/acl/interfaces/egress/edit_config.xml
@@ -0,0 +1,26 @@
+<acl xmlns="http://openconfig.net/yang/acl">
+  <interfaces>
+    <interface{% if operation is defined %} xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="{{operation}}"{% endif %}>
+      <id>{{id}}</id>
+      <config>
+        <id>{{id}}</id>
+      </config>
+      <interface-ref>
+        <config>
+          <interface>{{interface}}</interface>
+          {% if subinterface is defined %}<subinterface>{{subinterface}}</subinterface>{% endif%}
+        </config>
+      </interface-ref>
+      <egress-acl-sets>
+        <egress-acl-set>
+          <set-name>{{set_name_egress}}</set-name>
+          <type>{{type_egress}}</type>
+          <config>
+            <set-name>{{set_name_egress}}</set-name>
+            <type>{{type_egress}}</type>
+          </config>
+        </egress-acl-set>
+      </egress-acl-sets>
+    </interface>
+  </interfaces>
+</acl>
diff --git a/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config.xml b/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config.xml
new file mode 100644
index 0000000000000000000000000000000000000000..144a03c55477e532379541be5443063fe3aa2f10
--- /dev/null
+++ b/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config.xml
@@ -0,0 +1,26 @@
+<acl xmlns="http://openconfig.net/yang/acl">
+  <interfaces>
+    <interface{% if operation is defined %} xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="{{operation}}"{% endif %}>
+      <id>{{id}}</id>
+      <config>
+        <id>{{id}}</id>
+      </config>
+      <interface-ref>
+        <config>
+          <interface>{{interface}}</interface>
+          {% if subinterface is defined %}<subinterface>{{subinterface}}</subinterface>{% endif%}
+        </config>
+      </interface-ref>
+      <ingress-acl-sets>
+        <ingress-acl-set>
+          <set-name>{{set_name_ingress}}</set-name>
+          <type>{{type_ingress}}</type>
+          <config>
+            <set-name>{{set_name_ingress}}</set-name>
+            <type>{{type_ingress}}</type>
+          </config>
+        </ingress-acl-set>
+      </ingress-acl-sets>
+    </interface>
+  </interfaces>
+</acl>
diff --git a/src/device/tests/.gitignore b/src/device/tests/.gitignore
index b5f6bc13b7b17daa79d9e67c5fc0c50338d089a1..4cbf5059c2f905c16aac6234e2b9ca0ac7584c09 100644
--- a/src/device/tests/.gitignore
+++ b/src/device/tests/.gitignore
@@ -1,3 +1,5 @@
 # Add here your files containing confidential testbed details such as IP addresses, ports, usernames, passwords, etc.
+Device_OpenConfig_Adva*
+Device_OpenConfig_Cisco*
 Device_OpenConfig_Infinera*
 Device_Transport_Api*
diff --git a/src/device/tests/Device_OpenConfig_Template.py b/src/device/tests/Device_OpenConfig_Template.py
index df588b3d8a65883e0ebbfeacb222648bda0455ed..6afa2721ff920c39de243b308b9b9a4749cb013b 100644
--- a/src/device/tests/Device_OpenConfig_Template.py
+++ b/src/device/tests/Device_OpenConfig_Template.py
@@ -20,15 +20,20 @@ DEVICE_OC_ADDRESS  = '127.0.0.1'  # populate the Netconf Server IP address of th
 DEVICE_OC_PORT     = 830          # populate the Netconf Server port of the device to test
 DEVICE_OC_USERNAME = 'username'   # populate the Netconf Server username of the device to test
 DEVICE_OC_PASSWORD = 'password'   # populate the Netconf Server password of the device to test
-DEVICE_OC_TIMEOUT  = 120
+DEVICE_OC_TIMEOUT  = 15
 
 DEVICE_OC_ID = json_device_id(DEVICE_OC_UUID)
 DEVICE_OC    = json_device_packetrouter_disabled(DEVICE_OC_UUID)
 
 DEVICE_OC_CONNECT_RULES = json_device_connect_rules(DEVICE_OC_ADDRESS, DEVICE_OC_PORT, {
-    'username': DEVICE_OC_USERNAME,
-    'password': DEVICE_OC_PASSWORD,
-    'timeout' : DEVICE_OC_TIMEOUT,
+    'username'       : DEVICE_OC_USERNAME,
+    'password'       : DEVICE_OC_PASSWORD,
+    'force_running'  : False,
+    'hostkey_verify' : True,
+    'look_for_keys'  : True,
+    'allow_agent'    : True,
+    'device_params'  : {'name': 'default'},
+    'manager_params' : {'timeout' : DEVICE_OC_TIMEOUT},
 })
 
 DEVICE_OC_CONFIG_RULES   = []           # populate your configuration rules to test
diff --git a/src/device/tests/test_unitary.py b/src/device/tests/test_unitary.py
index 411cbba05957425687b0b03e3e868febe82a944d..0853da9a5e3572b15e5581413d1a5c765e02444e 100644
--- a/src/device/tests/test_unitary.py
+++ b/src/device/tests/test_unitary.py
@@ -55,6 +55,9 @@ ENABLE_EMULATED = True
 try:
     from .Device_OpenConfig_Infinera1 import(
     #from .Device_OpenConfig_Infinera2 import(
+    #from .Device_OpenConfig_Cisco import(
+    #from .Device_OpenConfig_Adva import(
+
         DEVICE_OC, DEVICE_OC_CONFIG_RULES, DEVICE_OC_DECONFIG_RULES, DEVICE_OC_CONNECT_RULES, DEVICE_OC_ID,
         DEVICE_OC_UUID)
     ENABLE_OPENCONFIG = True