diff --git a/src/device/Dockerfile b/src/device/Dockerfile
index 7ddf719a389b4a059a03c4ab845b94a349955b43..6566625527f8ceaa8de4639d558c92572c4835cb 100644
--- a/src/device/Dockerfile
+++ b/src/device/Dockerfile
@@ -16,7 +16,7 @@ FROM python:3.9-slim
 
 # Install dependencies
 RUN apt-get --yes --quiet --quiet update && \
-    apt-get --yes --quiet --quiet install wget g++ && \
+    apt-get --yes --quiet --quiet install wget g++ git && \
     rm -rf /var/lib/apt/lists/*
 
 # Set Python to show logs as they occur
diff --git a/src/device/requirements.in b/src/device/requirements.in
index ec29fc7a30278625e950f3eed608281f8c7c5cb8..4e927d65cdb0c3ec6da07db461d52ec03a7bed83 100644
--- a/src/device/requirements.in
+++ b/src/device/requirements.in
@@ -29,7 +29,8 @@ xmltodict==0.12.0
 tabulate
 ipaddress
 macaddress
-
+pyang
+git+https://github.com/robshakir/pyangbind.git
 # pip's dependency resolver does not take into account installed packages.
 # p4runtime does not specify the version of grpcio/protobuf it needs, so it tries to install latest one
 # adding here again grpcio==1.47.* and protobuf==3.20.* with explicit versions to prevent collisions
diff --git a/src/device/service/Tools.py b/src/device/service/Tools.py
index 571e8acdab7fc243c22923a69202c89db88c8ce3..b63bac9659521f47117ef97b3ae6d97be653adcf 100644
--- a/src/device/service/Tools.py
+++ b/src/device/service/Tools.py
@@ -16,7 +16,7 @@ import json, logging
 from typing import Any, Dict, List, 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, Device, DeviceConfig
+from common.proto.context_pb2 import ConfigActionEnum, ConfigRule_ACL, Device, DeviceConfig
 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
@@ -143,6 +143,7 @@ def _raw_config_rules_to_grpc(
 
         if resource_value is None: continue
         resource_value = json.loads(resource_value) if isinstance(resource_value, str) else resource_value
+        if isinstance(resource_value, ConfigRule_ACL): resource_value = grpc_message_to_json(resource_value)
         resource_value = {field_name : (field_value, False) for field_name,field_value in resource_value.items()}
         update_config_rule_custom(device_config.config_rules, resource_key, resource_value, new_action=config_action)
 
@@ -162,21 +163,36 @@ def populate_initial_config_rules(device_uuid : str, device_config : DeviceConfi
 def compute_rules_to_add_delete(
     device : Device, request : Device
 ) -> Tuple[List[Tuple[str, Any]], List[Tuple[str, Any]]]:
-    # convert config rules from context into a dictionary
-    # TODO: add support for non-custom config rules
-    context_config_rules = {
-        config_rule.custom.resource_key: config_rule.custom.resource_value
-        for config_rule in device.device_config.config_rules
-        if config_rule.WhichOneof('config_rule') == 'custom'
-    }
-
-    # convert config rules from request into a list
-    # TODO: add support for non-custom config rules
-    request_config_rules = [
-        (config_rule.action, config_rule.custom.resource_key, config_rule.custom.resource_value)
-        for config_rule in request.device_config.config_rules
-        if config_rule.WhichOneof('config_rule') == 'custom'
-    ]
+    # convert config rules from context into a dictionary  
+    context_config_rules = {}
+    for config_rule in device.device_config.config_rules: 
+        config_rule_kind = config_rule.WhichOneof('config_rule')
+        if config_rule_kind == 'custom':    # process "custom" rules
+            context_config_rules[config_rule.custom.resource_key] = config_rule.custom.resource_value # get the resource value of the rule resource
+        elif config_rule_kind == 'acl':     # process "custom" rules
+            device_uuid = config_rule.acl.endpoint_id.device_id.device_uuid.uuid # get the device name
+            endpoint_uuid = config_rule.acl.endpoint_id.endpoint_uuid.uuid       # get the endpoint name
+            acl_ruleset_name = config_rule.acl.rule_set.name                     # get the acl name
+            ACL_KEY_TEMPLATE = '/device[{:s}]/endpoint[{:s}]/acl_ruleset[{:s}]'
+            key_or_path = ACL_KEY_TEMPLATE.format(device_uuid, endpoint_uuid, acl_ruleset_name)            
+            context_config_rules[key_or_path] = config_rule.acl                  # get the resource value of the acl
+ 
+    request_config_rules = []
+    for config_rule in request.device_config.config_rules:
+        config_rule_kind = config_rule.WhichOneof('config_rule')
+        if config_rule_kind == 'custom': # resource management of "custom" rule  
+            request_config_rules.append((
+                config_rule.action, config_rule.custom.resource_key, config_rule.custom.resource_value
+            ))
+        elif config_rule_kind == 'acl':  # resource management of "acl" rule  
+            device_uuid = config_rule.acl.endpoint_id.device_id.device_uuid.uuid
+            endpoint_uuid = config_rule.acl.endpoint_id.endpoint_uuid.uuid
+            acl_ruleset_name = config_rule.acl.rule_set.name
+            ACL_KEY_TEMPLATE = '/device[{:s}]/endpoint[{:s}]/acl_ruleset[{:s}]'
+            key_or_path = ACL_KEY_TEMPLATE.format(device_uuid, endpoint_uuid, acl_ruleset_name) 
+            request_config_rules.append((
+                config_rule.action, key_or_path, config_rule.acl
+            ))
 
     resources_to_set    : List[Tuple[str, Any]] = [] # key, value
     resources_to_delete : List[Tuple[str, Any]] = [] # key, value
diff --git a/src/device/service/drivers/openconfig/OpenConfigDriver.py b/src/device/service/drivers/openconfig/OpenConfigDriver.py
index ac03527529b603089c4f8233cb185f6427e0c360..0c8ef2d685edda826bad0513704dabeb61365945 100644
--- a/src/device/service/drivers/openconfig/OpenConfigDriver.py
+++ b/src/device/service/drivers/openconfig/OpenConfigDriver.py
@@ -190,7 +190,7 @@ def do_sampling(
     except: # pylint: disable=bare-except
         logger.exception('Error retrieving samples')
 
-def edit_config(
+def edit_config(                                                                                                            # edit the configuration of openconfig devices
     netconf_handler : NetconfSessionHandler, logger : logging.Logger, resources : List[Tuple[str, Any]], delete=False,
     commit_per_rule=False, target='running', default_operation='merge', test_option=None, error_option=None,
     format='xml' # pylint: disable=redefined-builtin
@@ -201,21 +201,22 @@ def edit_config(
     for i,resource in enumerate(resources):
         str_resource_name = 'resources[#{:d}]'.format(i)
         try:
-            logger.debug('[{:s}] resource = {:s}'.format(str_method, str(resource)))
+            # logger.debug('[{: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(
+            str_config_messages = compose_config(                                                                          # get template for configuration
                 resource_key, resource_value, delete=delete, vendor=netconf_handler.vendor)
-            if str_config_message is None: raise UnsupportedResourceKeyException(resource_key)
-            logger.debug('[{: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)
-            if commit_per_rule:
-                netconf_handler.commit()
+            for str_config_message in str_config_messages:                                                                 # configuration of the received templates 
+                if str_config_message is None: raise UnsupportedResourceKeyException(resource_key)
+                # logger.debug('[{:s}] str_config_message[{:d}] = {:s}'.format(
+                #    str_method, len(str_config_message), str(str_config_message)))
+                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
         except Exception as e: # pylint: disable=broad-except
             str_operation = 'preparing' if target == 'candidate' else ('deleting' if delete else 'setting')
diff --git a/src/device/service/drivers/openconfig/templates/ACL/ACL_multivendor.py b/src/device/service/drivers/openconfig/templates/ACL/ACL_multivendor.py
index c8151d67586fef62cdc38e94594ae9a59d748334..4d332e5d0a10fb10a4c68912287eda962fc581c9 100755
--- a/src/device/service/drivers/openconfig/templates/ACL/ACL_multivendor.py
+++ b/src/device/service/drivers/openconfig/templates/ACL/ACL_multivendor.py
@@ -1,77 +1,92 @@
-from openconfig_acl import openconfig_acl
+from .openconfig_acl import openconfig_acl
 from pyangbind.lib.serialise import pybindIETFXMLEncoder
-
-def acl_set_mgmt(parameters):
-    Acl_name = parameters['name']
-    Acl_type = parameters['type']
-    ID       = parameters['sequence_id']
-    DEL      = parameters['DEL']
+from common.tools.grpc.Tools import grpc_message_to_json
+import logging
+def acl_mgmt(parameters,vendor):                                                                                       # acl templates management
+    acl   = []    
+    data = grpc_message_to_json(parameters,use_integers_for_enums=True)                                         # acl rule parameters management
+    acl.append(acl_set_mgmt(data,vendor))                                                                              # acl_set template
+    acl.append(acl_interface(data,vendor))                                                                             # acl interface template
+    return acl
+    
+def acl_set_mgmt(parameters,vendor):
+    type     = ["ACL_UNDEFINED", "ACL_IPV4","ACL_IPV6","ACL_L2","ACL_MPLS","ACL_MIXED"]
+    f_action = ["UNDEFINED", "DROP","ACCEPT","REJECT"]
+    l_action = ["UNDEFINED", "LOG_NONE","LOG_SYSLOG"]
+    
+    Acl_data    = parameters["rule_set"]
+    Acl_name    = Acl_data['name']
+    Acl_type    = type[Acl_data['type']]
+    Acl_desc    = Acl_data['description']
+    Acl_entries = Acl_data['entries']
 
     # Create an instance of the YANG model
     acl_instance = openconfig_acl()
 
     # Access the entry container
-    acl_set = acl_instance.acl.acl_sets.acl_set.add(name = Acl_name, type=Acl_type)
-    acl_entrie = acl_set.acl_entries.acl_entry.add(ID)
+    acl_set                    = acl_instance.acl.acl_sets.acl_set.add(name = Acl_name, type=Acl_type)
+    acl_set.config.name        = Acl_name
+    acl_set.config.type        = Acl_type
+    acl_set.config.description = Acl_desc
+    LOGGER = logging.getLogger(__name__)
 
-    if DEL: 
-        # Dump the entire instance as RFC 7950 XML
-        acl_set = pybindIETFXMLEncoder.serialise(acl_instance)
-        #Delete replace
-        acl_set = acl_set.replace('<acl-entry>','<acl-entry xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete">')
-        #Generic replaces
-        acl_set = acl_set.replace('<openconfig-acl xmlns="http://openconfig.net/yang/acl">',"")
-        acl_set = acl_set.replace('<acl>','<acl xmlns="http://openconfig.net/yang/acl">')
-        acl_set = acl_set.replace('</openconfig-acl>','')
-        
-    else:
-        acl_set.config.name = Acl_name
-        acl_set.config.type = Acl_type
+    LOGGER.warning("VALORES DE ENTRIES",Acl_entries)
+
+    for entry in Acl_entries:
+        ID     = entry['sequence_id']
+        desc   = entry['description']
+        match  = entry['match']
+        action = entry['action']
+
+        acl_entrie = acl_set.acl_entries.acl_entry.add(ID)
         acl_entrie.config.sequence_id = ID
+        acl_entrie.config.description= desc
         
         # Configuration per type
         if "L2" in Acl_type:
-            for variable, valor in parameters.items():
-                if   "source_mac"          in variable and len(valor) != 0: acl_entrie.l2.config.source_mac = valor
-                elif "destination_mac"     in variable and len(valor) != 0: acl_entrie.l2.config.destination_mac = valor
+            for key, value in match.items():
+                if   "src_address"     in key and len(value) != 0: acl_entrie.l2.config.source_mac = value
+                elif "dst_address"     in key and len(value) != 0: acl_entrie.l2.config.destination_mac = value
                 
         elif "IPV4" in Acl_type:
-            for variable, valor in parameters.items():
-                if   "source_address"       in variable and len(valor) != 0: acl_entrie.ipv4.config.source_address = valor
-                elif "destination_address"  in variable and len(valor) != 0: acl_entrie.ipv4.config.destination_address = valor
-                elif "protocol"             in variable and len(valor) != 0: acl_entrie.ipv4.config.protocol = valor
-                elif "hop_limit"            in variable and len(valor) != 0: acl_entrie.ipv4.config.hop_limit = valor
-                elif "dscp"                 in variable and len(valor) != 0: acl_entrie.ipv4.config.dscp = valor
-                  
-            for variable, valor in parameters.items():
-                if   "source_port"          in variable and len(valor) != 0: acl_entrie.transport.config.source_port = valor
-                elif "destination_port"     in variable and len(valor) != 0: acl_entrie.transport.config.destination_port = valor
-                elif "tcp_flags"            in variable and len(valor) != 0: acl_entrie.transport.config.tcp_flags = valor
+            for key, value in match.items():
+                if   "src_address"       in key and len(value) != 0: acl_entrie.ipv4.config.source_address = value
+                elif "dst_address"       in key and len(value) != 0: acl_entrie.ipv4.config.destination_address = value
+                elif "protocol"          in key                    : acl_entrie.ipv4.config.protocol = value
+                elif "hop_limit"         in key                    : acl_entrie.ipv4.config.hop_limit = value
+                elif "dscp"              in key                    : acl_entrie.ipv4.config.dscp = value
+                    
+            for key, value in match.items():
+                if   "src_port"     in key : acl_entrie.transport.config.source_port = value
+                elif "dst_port"     in key : acl_entrie.transport.config.destination_port = value
+                elif "tcp_flags"    in key : acl_entrie.transport.config.tcp_flags = value
                 
         elif "IPV6" in Acl_type:
-            for variable, valor in parameters.items():
-                if   "source_address"       in variable and len(valor) != 0: acl_entrie.ipv6.config.source_address = valor
-                elif "destination_address"  in variable and len(valor) != 0: acl_entrie.ipv6.config.destination_address = valor
-                elif "protocol"             in variable and len(valor) != 0: acl_entrie.ipv6.config.protocol = valor
-                elif "hop_limit"            in variable and len(valor) != 0: acl_entrie.ipv6.config.hop_limit = valor
-                elif "dscp"                 in variable and len(valor) != 0: acl_entrie.ipv6.config.dscp = valor
+            for key, value in match.items():
+                if   "src_address"       in key and len(value) != 0: acl_entrie.ipv6.config.source_address = value
+                elif "dst_address"       in key and len(value) != 0: acl_entrie.ipv6.config.destination_address = value
+                elif "protocol"          in key                    : acl_entrie.ipv6.config.protocol = value
+                elif "hop_limit"         in key                    : acl_entrie.ipv6.config.hop_limit = value
+                elif "dscp"              in key                    : acl_entrie.ipv6.config.dscp = value
         
-        for variable, valor in parameters.items():
-            if   "forwarding_action"        in variable and len(valor) != 0: acl_entrie.actions.config.forwarding_action = valor
-            elif "log_action"               in variable and len(valor) != 0: acl_entrie.actions.config.log_action = valor
+        for key, value in action.items():
+            if   "forward_action"        in key : acl_entrie.actions.config.forwarding_action = f_action[value]
+            elif "log_action"            in key : acl_entrie.actions.config.log_action = l_action[value]
             
-        # Dump the entire instance as RFC 7950 XML
-        acl_set = pybindIETFXMLEncoder.serialise(acl_instance)
-        acl_set = acl_set.replace('<openconfig-acl xmlns="http://openconfig.net/yang/acl">',"")
-        acl_set = acl_set.replace('<acl>','<acl xmlns="http://openconfig.net/yang/acl">')
-        acl_set = acl_set.replace('</openconfig-acl>','')
+    # Dump the entire instance as RFC 7950 XML
+    acl_set = pybindIETFXMLEncoder.serialise(acl_instance)
+    acl_set = acl_set.replace('<openconfig-acl xmlns="http://openconfig.net/yang/acl">',"")
+    acl_set = acl_set.replace('<acl>','<acl xmlns="http://openconfig.net/yang/acl">')
+    acl_set = acl_set.replace('</openconfig-acl>','')
 
     return(acl_set)
 
-def acl_interface(parameters):
-    ID           = parameters['id']
-    DEL          = parameters['DEL']
-    verify       = str(parameters)                                    #Verify transforms the received parameters into a string format for later making verifications and modifications
+def acl_interface(parameters,vendor):
+    type      = ["ACL_UNDEFINED", "ACL_IPV4","ACL_IPV6","ACL_L2","ACL_MPLS","ACL_MIXED"]
+    ID        = parameters['endpoint_id']['endpoint_uuid']['uuid']
+    Acl_data  = parameters["rule_set"]
+    Acl_name  = Acl_data['name']
+    Acl_type  = type[Acl_data['type']]
 
     # Create an instance of the YANG model
     acl_instance = openconfig_acl()
@@ -79,48 +94,24 @@ def acl_interface(parameters):
     # Access the entry container
     interface = acl_instance.acl.interfaces.interface.add(id = ID)
 
-    if DEL: 
-        acl_set = pybindIETFXMLEncoder.serialise(acl_instance)                                      
-        acl_set = acl_set.replace('<interface>','<interface xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="delete">')     
+    #Config - Interface
+    interface.config.id = ID
+    
+    #If the Interface parameter is defined [OPTIONAL-PARAMETER]
+    interface.interface_ref.config.interface = ID        # Interface parameter 
+    
+    #TODO: add subinterface management
+    if   vendor == "ADVA"   : interface.interface_ref.config.subinterface = '0'    # Subinterface parameter
+    elif vendor == "Juniper": interface.interface_ref.config.subinterface = '0'
+    else:                     interface.interface_ref.config.subinterface = Acl_data['subinterface']
+    # Configuration ingress type
+    ingress= interface.ingress_acl_sets.ingress_acl_set.add(set_name = Acl_name, type = Acl_type)
+    ingress.config.set_name = Acl_name
+    ingress.config.type     = Acl_type
 
-        # Dump the entire instance as RFC 7950 XML
-        acl_set = acl_set.replace('<openconfig-acl xmlns="http://openconfig.net/yang/acl">'," ")     
-        acl_set = acl_set.replace('<acl>','<acl xmlns="http://openconfig.net/yang/acl">')            
-        acl_set = acl_set.replace('</openconfig-acl>','')                                           
-    else:
-        #Config - Interface
-        interface.config.id = ID
-        #If the Interface parameter is defined [OPTIONAL-PARAMETER]
-        if verify.find('interface')>0:
-            Interface = parameters['interface']        
-            if  len(Interface) != 0: interface.interface_ref.config.interface = Interface        #If interface parameter has a value
-        
-        #If the Subinterface parameter is defined [OPTIONAL-PARAMETER]
-        if verify.find('subinterface')>0:
-            Subinterface = parameters['subinterface']        
-            if  len(Interface) != 0: interface.interface_ref.config.subinterface = Subinterface   #If subinterface parameter has a value
-        
-         # Configuration per type
-        if verify.find('set_name_ingress')>0:                           #If set_name_ingress is defined
-            Ingress_name = parameters['set_name_ingress']        
-            if  len(Ingress_name) != 0: 
-                Ingress_type         = parameters['type_ingress']
-                ingress= interface.ingress_acl_sets.ingress_acl_set.add(set_name = Ingress_name, type = Ingress_type)
-                ingress.config.set_name = Ingress_name
-                ingress.config.type     = Ingress_type
-        
-        if verify.find('set_name_egress')>0:                            #If set_name_egress is defined
-            Egress_name = parameters['set_name_egress']        
-            if  len(Egress_name) != 0: 
-                Egress_name         = parameters['set_name_egress']
-                Egress_type         = parameters['type_egress']
-                egress= interface.egress_acl_sets.egress_acl_set.add(set_name = Egress_name, type = Egress_type)
-                egress.config.set_name = Egress_name
-                egress.config.type     = Egress_type
-  
-        # Dump the entire instance as RFC 7950 XML
-        acl_set = pybindIETFXMLEncoder.serialise(acl_instance)                                      
-        acl_set = acl_set.replace('<openconfig-acl xmlns="http://openconfig.net/yang/acl">',"")     
-        acl_set = acl_set.replace('<acl>','<acl xmlns="http://openconfig.net/yang/acl">')           
-        acl_set = acl_set.replace('</openconfig-acl>','')                                           
+    # Dump the entire instance as RFC 7950 XML
+    acl_set = pybindIETFXMLEncoder.serialise(acl_instance)                                      
+    acl_set = acl_set.replace('<openconfig-acl xmlns="http://openconfig.net/yang/acl">',"")     
+    acl_set = acl_set.replace('<acl>','<acl xmlns="http://openconfig.net/yang/acl">')           
+    acl_set = acl_set.replace('</openconfig-acl>','')                                           
     return(acl_set)
diff --git a/src/device/service/drivers/openconfig/templates/Tools.py b/src/device/service/drivers/openconfig/templates/Tools.py
index d71c00742ebb8f224ad8308f657cef87000b88c5..a56fe3ea5e936d78a85fcd36d5a49094e112a37b 100644
--- a/src/device/service/drivers/openconfig/templates/Tools.py
+++ b/src/device/service/drivers/openconfig/templates/Tools.py
@@ -15,10 +15,10 @@
 import json
 import lxml.etree as ET
 from typing import Collection, Dict, Any
-from  ACL.ACL_multivendor  import      acl_set_mgmt, acl_interface        
-from VPN.Network_instance_multivendor import create_network_instance, associate_virtual_circuit, associate_RP_to_NI, add_protocol_NI, create_table_conns, associate_If_to_NI
-from VPN.Interfaces_multivendor       import create_If_SubIf  
-from VPN.Routing_policy               import create_rp_def, create_rp_statement
+from .ACL.ACL_multivendor              import acl_mgmt        
+from .VPN.Network_instance_multivendor import create_network_instance, associate_virtual_circuit, associate_RP_to_NI, add_protocol_NI, create_table_conns, associate_If_to_NI
+from .VPN.Interfaces_multivendor       import create_If_SubIf  
+from .VPN.Routing_policy               import create_rp_def, create_rp_statement
 
 def add_value_from_tag(target : Dict, field_name: str, field_value : ET.Element, cast=None) -> None:
     if field_value is None or field_value.text is None: return
@@ -30,43 +30,41 @@ def add_value_from_collection(target : Dict, field_name: str, field_value : Coll
     if field_value is None or len(field_value) == 0: return
     target[field_name] = field_value
 
-def generate_template(resource_key: str, resource_value: str, delete: bool) -> str:
-    data: Dict[str, Any] = json.loads(resource_value)
-    data['DEL'] = delete
+def generate_templates(resource_key: str, resource_value: str, delete: bool,vendor:str) -> str:    # template management to be configured
 
-    list_resource_key = resource_key.split("/")
-
-    if "network_instance" in list_resource_key[1]:
-        if "connection_point" in list_resource_key:
-            result_template = associate_virtual_circuit(data)
-        elif "inter_instance_policies" in list_resource_key:
-            result_template = associate_RP_to_NI(data)
-        elif "protocolos" in list_resource_key:
-            result_template = add_protocol_NI(data)
-        elif "table_connections" in list_resource_key:
-            result_template = create_table_conns(data)
-        elif "interface" in list_resource_key:
-            result_template = associate_If_to_NI(data)
+    result_templates = []
+    list_resource_key = resource_key.split("/")                                         # the rule resource key management
+    if "network_instance" in list_resource_key[1]:                                      # network instance rules management
+        data: Dict[str, Any] = json.loads(resource_value)
+        data['DEL'] = delete
+        if "connection_point" in resource_key:
+            result_templates.append(associate_virtual_circuit(data))
+        elif "inter_instance_policies" in resource_key:
+            result_templates.append(associate_RP_to_NI(data))
+        elif "protocols" in resource_key:
+            result_templates.append(add_protocol_NI(data))
+        elif "table_connections" in resource_key:
+            result_templates.append(create_table_conns(data))
+        elif "interface" in resource_key:
+            result_templates.append(associate_If_to_NI(data))
         else:
-            result_template = create_network_instance(data)
-
-    elif "interface" in list_resource_key[1]:
-        if "subinterface" in list_resource_key:
-            result_template = create_If_SubIf(data)
+            result_templates.append(create_network_instance(data))
 
-    elif "acl" in list_resource_key[1]:
-        if "acl_set" in list_resource_key:
-            result_template = acl_set_mgmt(data)
-        else:
-            result_template = acl_interface(data)
+    elif "interface" in list_resource_key[1]:                                           # interface rules management
+        data: Dict[str, Any] = json.loads(resource_value)
+        data['DEL'] = delete
+        if "subinterface" in resource_key:
+            result_templates.append(create_If_SubIf(data))
 
-    elif "routing_policy" in list_resource_key[1]:
-        if "bgp_defined_set" in list_resource_key:
-            result_template = create_rp_def(data)
+    elif "routing_policy" in list_resource_key[1]:                                      # routing policy rules management
+        data: Dict[str, Any] = json.loads(resource_value)
+        data['DEL'] = delete
+        if "bgp_defined_set" in resource_key:
+            result_templates.append(create_rp_def(data))
         else:
-            result_template = create_rp_statement(data)
-    
+            result_templates.append(create_rp_statement(data))
     else:
-        result_template = ""
+        if "acl_ruleset" in resource_key:                                               # acl rules management
+            result_templates.extend(acl_mgmt(resource_value,vendor))
 
-    return result_template
\ No newline at end of file
+    return result_templates
\ No newline at end of file
diff --git a/src/device/service/drivers/openconfig/templates/VPN/Interfaces_multivendor.py b/src/device/service/drivers/openconfig/templates/VPN/Interfaces_multivendor.py
index 201c691249712e831a96c27da3062b549d676ed8..6cfe525d77ec28a5714248ef5cf481a60f460d9b 100644
--- a/src/device/service/drivers/openconfig/templates/VPN/Interfaces_multivendor.py
+++ b/src/device/service/drivers/openconfig/templates/VPN/Interfaces_multivendor.py
@@ -1,4 +1,4 @@
-from openconfig_interfaces import openconfig_interfaces
+from .openconfig_interfaces import openconfig_interfaces
 from pyangbind.lib.serialise import pybindIETFXMLEncoder
 
 def set_vlan(OptionalParams):                                   #[L2/L3] Sets a VLANID and a VENDOR that will be requested for executing the following methods
@@ -11,32 +11,28 @@ def set_vlan(OptionalParams):                                   #[L2/L3] Sets a
     #If the VlanID parameter is defined [OPTIONAL-PARAMETER]
     if verify.find('vlan_id')>0:
         VlanID = OptionalParams['vlan_id'] 
-        if VlanID == 0 and "ADVA" in Vendor:
-            vlan = '</description>\n \t    <untagged-allowed xmlns="http://www.advaoptical.com/cim/adva-dnos-oc-interfaces">true</untagged-allowed></config>'
-        elif VlanID != 0:
-            vlan = '</description>\n          </config>\n\t  <vlan xmlns="http://openconfig.net/yang/vlan"> \n\t    <match> \n\t      <single-tagged> \n \t\t<config>\n \t\t  <vlan-id>'+str(VlanID)+'</vlan-id> \n \t\t</config> \n \t      </single-tagged> \n \t    </match> \n \t  </vlan>'
-        else:
-            vlan = '</description>\n          </config>'
-    else:
-        vlan = '</description>\n          </config>'   
+        if VlanID == 0 and "ADVA" in Vendor: vlan = '  <untagged-allowed xmlns="http://www.advaoptical.com/cim/adva-dnos-oc-interfaces">true</untagged-allowed></config> \n          </config>\n        </subinterface>'
+        elif VlanID != 0:                    vlan = '</config>\n          <vlan xmlns="http://openconfig.net/yang/vlan"> \n\t    <match> \n\t      <single-tagged> \n \t\t<config>\n \t\t  <vlan-id>'+str(VlanID)+'</vlan-id> \n \t\t</config> \n \t      </single-tagged> \n \t    </match> \n \t  </vlan> \n         </subinterface>'
+        else:                                vlan = '</subinterface>\n          </config>'
+    else:                                    vlan = '</subinterface>\n          </config>'   
     return vlan
 
 def set_ip(OptionalParams):                                     #[L3]    Sets a IPAddress that will be requested for executing the following L3VPN methods
-    verify = str(OptionalParams)                                    #Verify transforms the received parameters into a string format for later making verifications and modifications
+    verify = str(OptionalParams)                                 # Verify transforms the received parameters into a string format for later making verifications and modifications
     
     #If the Address_ip parameter is defined [OPTIONAL-PARAMETER]
     if verify.find('address_ip')>0:
-        IP     = OptionalParams['address_ip']  
-        Prefix = OptionalParams['address_prefix']
+        IP      = OptionalParams['address_ip']  
+        Prefix  = OptionalParams['address_prefix']
         address = '  <ipv4 xmlns="http://openconfig.net/yang/interfaces/ip"> \n\t    <addresses> \n\t      <address> \n \t\t<ip>'+IP+'</ip> \n \t\t<config>\n \t\t  <ip>'+IP+'</ip> \n \t\t  <prefix-length>'+str(Prefix)+'</prefix-length> \n \t\t</config> \n \t      </address> \n \t    </addresses> \n \t  </ipv4>  \n \t</subinterface>'
     else:
         address ='</subinterface>'
     return address
 
-def create_If_SubIf(parameters):                                #[L2/L3] Creates a Interface with a Subinterface as described in /interface[{:s}]/subinterface[{:d}]
+def create_If_SubIf(parameters):                                # [L2/L3] Creates a Interface with a Subinterface as described in /interface[{:s}]/subinterface[{:d}]
     Interface_name     = parameters['name']
-    DEL                = parameters['DEL']                      #If the parameters DEL is set to "TRUE" that will mean that is for making a DELETE, ELSE is for creating
-    verify = str(parameters)                                    #Verify transforms the received parameters into a string format for later making verifications and modifications
+    DEL                = parameters['DEL']                      # If the parameters DEL is set to "TRUE" that will mean that is for making a DELETE, ELSE is for creating
+    verify             = str(parameters)                        # Verify transforms the received parameters into a string format for later making verifications and modifications
 
     #Create an instance of the YANG model
     InterfaceInstance = openconfig_interfaces()
@@ -66,7 +62,7 @@ def create_If_SubIf(parameters):                                #[L2/L3] Creates
         InterfaceInstance_set.config.enabled = True
 
         #SubIntefaces-Config
-        SubInterfaceInstance = InterfaceInstance_set.subinterfaces.subinterface.add(index = SubInterface_Index)
+        SubInterfaceInstance              = InterfaceInstance_set.subinterfaces.subinterface.add(index = SubInterface_Index)
         SubInterfaceInstance.config.index = SubInterface_Index
 
         #If the description parameter is defined [OPTIONAL-PARAMETER]
@@ -85,7 +81,7 @@ def create_If_SubIf(parameters):                                #[L2/L3] Creates
         #Replaces for adding the Interface Type
         InterfaceInstance_set = InterfaceInstance_set.replace('</config>\n      <subinterfaces>','  <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:'+Interface_type+'</type>\n      </config>\n      <subinterfaces>')
         vlan = set_vlan(parameters)
-        InterfaceInstance_set = InterfaceInstance_set.replace('</description>\n          </config>',vlan)
+        InterfaceInstance_set = InterfaceInstance_set.replace('</config>\n        </subinterface>',vlan)
         
         if "l3ipvlan" in Interface_type: 
             ip = set_ip(parameters)
@@ -97,4 +93,3 @@ def create_If_SubIf(parameters):                                #[L2/L3] Creates
         InterfaceInstance_set = InterfaceInstance_set.replace('</openconfig-interfaces>','')
 
     return (InterfaceInstance_set) 
-
diff --git a/src/device/service/drivers/openconfig/templates/VPN/Network_instance_multivendor.py b/src/device/service/drivers/openconfig/templates/VPN/Network_instance_multivendor.py
index 22c365f7c0b468c7f0e44b2c57e3e04587d9eac4..2b85ba60c3d27bb351c462dff1b30ad41d5cdf05 100644
--- a/src/device/service/drivers/openconfig/templates/VPN/Network_instance_multivendor.py
+++ b/src/device/service/drivers/openconfig/templates/VPN/Network_instance_multivendor.py
@@ -1,4 +1,4 @@
-from openconfig_network_instance import openconfig_network_instance
+from .openconfig_network_instance import openconfig_network_instance
 from pyangbind.lib.serialise     import pybindIETFXMLEncoder
 
 def create_network_instance(parameters):                   #[L2/L3] Creates a Network Instance as described in: /network_instance[{:s}] 
@@ -51,7 +51,7 @@ def create_network_instance(parameters):                   #[L2/L3] Creates a Ne
             #Dump the entire instance as RFC 750 XML
             NetInstance_set = pybindIETFXMLEncoder.serialise(Network_Instance)
             #Specific Replace [Addition of the enabled and MTU variables]
-            NetInstance_set = NetInstance_set.replace('</name>','</name>\n        <mtu>'+str(NetInstance_MTU)+'</mtu>\n        <enabled>true</enabled>')   
+            NetInstance_set = NetInstance_set.replace('</type>','</type>\n        <mtu>'+str(NetInstance_MTU)+'</mtu>\n        <enabled>true</enabled>')   
 
         #Configuration for L3VRF
         elif   "L3VRF" in NetInstance_type:
diff --git a/src/device/service/drivers/openconfig/templates/VPN/Routing_policy.py b/src/device/service/drivers/openconfig/templates/VPN/Routing_policy.py
index 21d6f1560c5365464409124e4c17a11811cff178..895385a65a3f71cd1e3daa42b56d32fbd7ceec0b 100644
--- a/src/device/service/drivers/openconfig/templates/VPN/Routing_policy.py
+++ b/src/device/service/drivers/openconfig/templates/VPN/Routing_policy.py
@@ -1,4 +1,4 @@
-from openconfig_routing_policy import openconfig_routing_policy
+from .openconfig_routing_policy import openconfig_routing_policy
 from pyangbind.lib.serialise import pybindIETFXMLEncoder
 
 def create_rp_statement(parameters):                     #[L3] Creates a Routing Policy Statement
diff --git a/src/device/service/drivers/openconfig/templates/__init__.py b/src/device/service/drivers/openconfig/templates/__init__.py
index fc3b8db150f8b2ac26a1b040af48d15e440bb578..039cf5b5549061a8c6a8e785e47001ac0e639363 100644
--- a/src/device/service/drivers/openconfig/templates/__init__.py
+++ b/src/device/service/drivers/openconfig/templates/__init__.py
@@ -15,7 +15,7 @@
 import json, logging, lxml.etree as ET, re
 from typing import Any, Dict, Optional
 from jinja2 import Environment, PackageLoader, select_autoescape
-from Tools import generate_template
+from .Tools import generate_templates
 from device.service.driver_api._Driver import (
     RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_ACL)
 from .EndPoints import parse as parse_endpoints
@@ -78,9 +78,11 @@ def parse(resource_key : str, xml_data : ET.Element):
     if parser is None: return [(resource_key, xml_data)]
     return parser(xml_data)
 
-def compose_config(
+def compose_config( # template generation
     resource_key : str, resource_value : str, delete : bool = False, vendor : Optional[str] = None
 ) -> str:
-    template = (generate_template(resource_key, resource_value, delete))
-
-    return '<config>{:s}</config>'.format(template)
+    templates = (generate_templates(resource_key, resource_value, delete,vendor))
+    return [
+        '<config>{:s}</config>'.format(template) # format correction
+        for template in templates
+        ]
diff --git a/src/service/service/service_handler_api/SettingsHandler.py b/src/service/service/service_handler_api/SettingsHandler.py
index 85dd3a12851bf8c5ba697180fe00d0467e7a76b5..255e60b061373e4fedd42f90eadb2e64a67f7d55 100644
--- a/src/service/service/service_handler_api/SettingsHandler.py
+++ b/src/service/service/service_handler_api/SettingsHandler.py
@@ -16,8 +16,8 @@ import anytree, json, logging
 from typing import Any, List, Optional, Tuple, Union
 from common.proto.context_pb2 import ConfigActionEnum, ConfigRule, Device, EndPoint, ServiceConfig
 from common.tools.grpc.Tools import grpc_message_to_json, grpc_message_to_json_string
-from service.service.service_handler_api.AnyTreeTools import TreeNode, delete_subnode, get_subnode, set_subnode_value
-
+from service.service.service_handler_api.Tools import extract_endpoint_index, extract_index
+from service.service.service_handler_api.AnyTreeTools import TreeNode, delete_subnode, get_subnode, set_subnode_value, dump_subtree
 LOGGER = logging.getLogger(__name__)
 
 class SettingsHandler:
@@ -41,9 +41,10 @@ class SettingsHandler:
         elif kind == 'acl':
             device_uuid = config_rule.acl.endpoint_id.device_id.device_uuid.uuid
             endpoint_uuid = config_rule.acl.endpoint_id.endpoint_uuid.uuid
+            endpoint_name, endpoint_index = extract_endpoint_index(endpoint_uuid)
             acl_ruleset_name = config_rule.acl.rule_set.name
-            ACL_KEY_TEMPLATE = '/device[{:s}]/endpoint[{:s}]/acl_ruleset[{:s}]'
-            key_or_path = ACL_KEY_TEMPLATE.format(device_uuid, endpoint_uuid, acl_ruleset_name)
+            ACL_KEY_TEMPLATE = '/device[{:s}]/endpoint[{:s}]/index[{:d}]/acl_ruleset[{:s}]'
+            key_or_path = ACL_KEY_TEMPLATE.format(device_uuid, endpoint_name,endpoint_index, acl_ruleset_name)
             value = grpc_message_to_json(config_rule.acl)
         else:
             MSG = 'Unsupported Kind({:s}) in ConfigRule({:s})'
@@ -66,6 +67,28 @@ class SettingsHandler:
                 if endpoint_settings is not None: return endpoint_settings
 
         return None
+    
+    def get_endpoint_acls(self, device : Device, endpoint : EndPoint) -> List [Tuple]:
+        endpoint_name = endpoint.name
+        device_keys   = device.device_id.device_uuid.uuid,       device.name
+        endpoint_keys = endpoint.endpoint_id.endpoint_uuid.uuid, endpoint.name
+        acl_rules = []
+        for device_key in device_keys:
+            for endpoint_key in endpoint_keys:
+                endpoint_settings_uri = '/device[{:s}]/endpoint[{:s}]'.format(device_key, endpoint_key)
+                endpoint_settings = self.get(endpoint_settings_uri)
+                if endpoint_settings is None: continue  
+                endpoint_name, endpoint_index = extract_endpoint_index(endpoint_name)
+                ACL_RULE_PREFIX = '/device[{:s}]/endpoint[{:s}]/'.format(device_key, endpoint_name)
+
+                results = dump_subtree(endpoint_settings)
+                for res_key, res_value in results: 
+                    if not res_key.startswith(ACL_RULE_PREFIX): continue
+                    if not "acl_ruleset" in res_key: continue
+                    acl_index = extract_index(res_value)
+                    if not 'index[{:d}]'.format(acl_index) in res_key: continue
+                    acl_rules.append((res_key, res_value))
+        return acl_rules
 
     def set(self, key_or_path : Union[str, List[str]], value : Any) -> None:
         set_subnode_value(self.__resolver, self.__config, key_or_path, value)
diff --git a/src/service/service/service_handler_api/Tools.py b/src/service/service/service_handler_api/Tools.py
index 222cd8968cd490d488dbbfc0082b6c3d4f5c1035..787b0f499a2d4b3ad76bfe4b7d41f072bbe6c50c 100644
--- a/src/service/service/service_handler_api/Tools.py
+++ b/src/service/service/service_handler_api/Tools.py
@@ -11,12 +11,12 @@
 # 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 functools
+import functools, re
 from typing import Any, List, Optional, Tuple, Union
 from common.method_wrappers.ServiceExceptions import NotFoundException
 from common.proto.context_pb2 import Device, EndPoint
 from common.type_checkers.Checkers import chk_length, chk_type
+from common.tools.grpc.Tools import grpc_message_to_json
 
 ACTION_MSG_SET_ENDPOINT      = 'Set EndPoint(device_uuid={:s}, endpoint_uuid={:s}, topology_uuid={:s})'
 ACTION_MSG_DELETE_ENDPOINT   = 'Delete EndPoint(device_uuid={:s}, endpoint_uuid={:s}, topology_uuid={:s})'
@@ -58,3 +58,18 @@ def get_device_endpoint_uuids(endpoint : Tuple[str, str, Optional[str]]) -> Tupl
     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 extract_endpoint_index(endpoint_name : str, default_index=0) -> Tuple[str, int]:
+    RE_PATTERN = '^(eth\-[0-9]+(?:\/[0-9]+)*)(?:\.([0-9]+))?$'
+    m = re.match(RE_PATTERN, endpoint_name)
+    if m is None: return endpoint_name, default_index
+    endpoint_name, index = m.groups()
+    if index is not None: index = int(index)
+    return endpoint_name, index
+
+def extract_index(res_value : str) ->  int:
+    acl_value = grpc_message_to_json(res_value,use_integers_for_enums=True) 
+    endpoint  = acl_value.split("'endpoint_uuid': {'uuid': '")
+    endpoint  = endpoint[1].split("'}")
+    _ , index = extract_endpoint_index(endpoint[0])
+    return index
diff --git a/src/service/service/service_handlers/l2nm_openconfig/ConfigRules.py b/src/service/service/service_handlers/l2nm_openconfig/ConfigRules.py
index 07e78d73631342d101d77697098e83961c7dcf26..70ee430f0d82fe520b4f6b8e77a519c990d71e76 100644
--- a/src/service/service/service_handlers/l2nm_openconfig/ConfigRules.py
+++ b/src/service/service/service_handlers/l2nm_openconfig/ConfigRules.py
@@ -12,13 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from typing import Dict, List
+from typing import Dict, List, Tuple
 from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set
 from service.service.service_handler_api.AnyTreeTools import TreeNode
 
 def setup_config_rules(
     service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str, endpoint_name : str,
-    service_settings : TreeNode, endpoint_settings : TreeNode
+    service_settings : TreeNode, endpoint_settings : TreeNode, endpoint_acls : List [Tuple]
 ) -> List[Dict]:
     
     if service_settings  is None: return []
@@ -30,7 +30,7 @@ def setup_config_rules(
     json_settings          : Dict = {} if service_settings  is None else service_settings.value
     json_endpoint_settings : Dict = {} if endpoint_settings is None else endpoint_settings.value
 
-    #mtu                 = json_settings.get('mtu',                 1450 )    # 1512
+    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
@@ -79,6 +79,10 @@ def setup_config_rules(
              'remote_system': remote_router
             }),
     ]
+    for res_key, res_value in endpoint_acls:
+        json_config_rules.append(
+               {'action': 1, 'acl': res_value}
+            )
     return json_config_rules
 
 def teardown_config_rules(
diff --git a/src/service/service/service_handlers/l2nm_openconfig/L2NMOpenConfigServiceHandler.py b/src/service/service/service_handlers/l2nm_openconfig/L2NMOpenConfigServiceHandler.py
index d511c8947ecb43052fd154ab3ce3293a468b4263..467f4e4c842ecdfb5f9e3410c47d4334ee1cb9bb 100644
--- a/src/service/service/service_handlers/l2nm_openconfig/L2NMOpenConfigServiceHandler.py
+++ b/src/service/service/service_handlers/l2nm_openconfig/L2NMOpenConfigServiceHandler.py
@@ -69,11 +69,12 @@ class L2NMOpenConfigServiceHandler(_ServiceHandler):
                 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_acls = self.__settings_handler.get_endpoint_acls(device_obj, endpoint_obj)
                 endpoint_name = endpoint_obj.name
 
                 json_config_rules = setup_config_rules(
                     service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name,
-                    settings, endpoint_settings)
+                    settings, endpoint_settings, endpoint_acls)
 
                 if len(json_config_rules) > 0:
                     del device_obj.device_config.config_rules[:]
diff --git a/src/service/service/service_handlers/l3nm_openconfig/ConfigRules.py b/src/service/service/service_handlers/l3nm_openconfig/ConfigRules.py
index ef93dcdda8145cab15ff21c24b6318e9eb00e098..dd48fe7351e03328ddad8fdb29abf0fae09bc7b7 100644
--- a/src/service/service/service_handlers/l3nm_openconfig/ConfigRules.py
+++ b/src/service/service/service_handlers/l3nm_openconfig/ConfigRules.py
@@ -12,13 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from typing import Dict, List
+from typing import Dict, List, Tuple
 from common.tools.object_factory.ConfigRule import json_config_rule_delete, json_config_rule_set
 from service.service.service_handler_api.AnyTreeTools import TreeNode
 
 def setup_config_rules(
     service_uuid : str, connection_uuid : str, device_uuid : str, endpoint_uuid : str, endpoint_name : str,
-    service_settings : TreeNode, endpoint_settings : TreeNode
+    service_settings : TreeNode, endpoint_settings : TreeNode, endpoint_acls : List [Tuple]
 ) -> List[Dict]:
 
     if service_settings  is None: return []
@@ -177,6 +177,10 @@ def setup_config_rules(
         }),
 
     ]
+    for res_key, res_value in endpoint_acls:
+        json_config_rules.append(
+               {'action': 1, 'acl': res_value}
+            )
     return json_config_rules
 
 def teardown_config_rules(
diff --git a/src/service/service/service_handlers/l3nm_openconfig/L3NMOpenConfigServiceHandler.py b/src/service/service/service_handlers/l3nm_openconfig/L3NMOpenConfigServiceHandler.py
index b2639ddad58e4c453f1b1e2dc87fce8861ad79a2..eae2f3cbec0cad805c44b338bfbac3fb06cb84b3 100644
--- a/src/service/service/service_handlers/l3nm_openconfig/L3NMOpenConfigServiceHandler.py
+++ b/src/service/service/service_handlers/l3nm_openconfig/L3NMOpenConfigServiceHandler.py
@@ -69,11 +69,12 @@ class L3NMOpenConfigServiceHandler(_ServiceHandler):
                 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_acls = self.__settings_handler.get_endpoint_acls(device_obj, endpoint_obj)
                 endpoint_name = endpoint_obj.name
 
                 json_config_rules = setup_config_rules(
                     service_uuid, connection_uuid, device_uuid, endpoint_uuid, endpoint_name,
-                    settings, endpoint_settings)
+                    settings, endpoint_settings, endpoint_acls)
 
                 if len(json_config_rules) > 0:
                     del device_obj.device_config.config_rules[:]
diff --git a/src/webui/requirements.in b/src/webui/requirements.in
index b4a158d394bc2de67af1e0e99e922df08104f736..d9de647f1225f0f2a58bf4322ae5ca4b19f5329c 100644
--- a/src/webui/requirements.in
+++ b/src/webui/requirements.in
@@ -17,3 +17,4 @@ Flask-WTF==1.0.0
 flask-healthz==0.0.3
 flask-unittest==0.1.2
 lorem-text==2.1
+APScheduler==3.8.1
diff --git a/src/webui/service/service/routes.py b/src/webui/service/service/routes.py
index defbe2cb003cc97830d6ec24db01bf8734a7f530..a58d08c46cfc805caf6d270bbea92ddbc67ee235 100644
--- a/src/webui/service/service/routes.py
+++ b/src/webui/service/service/routes.py
@@ -13,30 +13,51 @@
 # limitations under the License.
 
 import grpc
-from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for
+import base64, json, logging #, re
+from flask import current_app, redirect, render_template, Blueprint, flash, session, url_for, request
 from common.proto.context_pb2 import (
-    IsolationLevelEnum, Service, ServiceId, ServiceTypeEnum, ServiceStatusEnum, Connection)
+    IsolationLevelEnum, Device, Service, ServiceId, ServiceTypeEnum, ServiceStatusEnum, Connection, DeviceList, Empty)
 from common.tools.context_queries.Context import get_context
 from common.tools.context_queries.EndPoint import get_endpoint_names
 from common.tools.context_queries.Service import get_service
+from common.tools.context_queries.Topology import get_topology
+from wtforms.validators import ValidationError
 from context.client.ContextClient import ContextClient
 from service.client.ServiceClient import ServiceClient
+from common.tools.object_factory.Service import (
+    json_service_l2nm_planned, json_service_l3nm_planned)
+from webui.service import json_to_list
+from common.tools.object_factory.Constraint import (
+    json_constraint_sla_availability, json_constraint_sla_capacity, json_constraint_sla_isolation,
+    json_constraint_sla_latency)
+from common.tools.descriptor.Loader import DescriptorLoader, compose_notifications
+from common.tools.object_factory.ConfigRule import json_config_rule_set
+from common.tools.object_factory.Device import json_device_id
+from common.tools.object_factory.EndPoint import json_endpoint_id
+from webui.service.service.forms import AddServiceForm_1, AddServiceForm_ACL_L2, AddServiceForm_ACL_IPV4, AddServiceForm_ACL_IPV6, AddServiceForm_L2VPN, AddServiceForm_L3VPN
+from common.tools.grpc.Tools import grpc_message_to_json
 
-service = Blueprint('service', __name__, url_prefix='/service')
+LOGGER = logging.getLogger(__name__)
+service = Blueprint('service', __name__, url_prefix='/service')                     #Define a flask Blueprint called "service" behind the url "/service"
 
-context_client = ContextClient()
-service_client = ServiceClient()
+context_client = ContextClient()                                                    #Create an instance of ContextClient class as defined in /src/service/client/ContextClient.py
+service_client = ServiceClient()                                                    #Create an instance of ServiceClient class as defined in /src/service/client/ServiceClient.py
 
-@service.get('/')
+type     = ["ACL_UNDEFINED", "ACL_IPV4","ACL_IPV6","ACL_L2","ACL_MPLS","ACL_MIXED"]
+f_action = ["UNDEFINED", "DROP","ACCEPT","REJECT"]
+l_action = ["UNDEFINED", "LOG_NONE","LOG_SYSLOG"]
+
+@service.get('/')                                                                   #Route for the homepage of the created "service" blueprint 
 def home():
-    if 'context_uuid' not in session or 'topology_uuid' not in session:
-        flash("Please select a context!", "warning")
+    if 'context_uuid' not in session or 'topology_uuid' not in session:             #Check if context_uuid and topology_uuid are defined in the current seession
+        flash("Please select a context!", "warning")                                #If they are not defined in the current session [Return to main page - STOP]                           
         return redirect(url_for("main.home"))
-    context_uuid = session['context_uuid']
+    context_uuid = session['context_uuid']                                          #If both are they are present in the current session, the value of the "context_uuid" 
+                                                                                    #is retrieved from the session and stored in the local variable "context_uuid"
 
-    context_client.connect()
+    context_client.connect()                                                        #Creates a connection, as specified in the connect method of the ContextClient() class
 
-    context_obj = get_context(context_client, context_uuid, rw_copy=False)
+    context_obj = get_context(context_client, context_uuid, rw_copy=False)          #Using the get_context function, defined in /src/common/ 
     if context_obj is None:
         flash('Context({:s}) not found'.format(str(context_uuid)), 'danger')
         services, device_names, endpoints_data = list(), list(), list()
@@ -59,15 +80,7 @@ def home():
         'service/home.html', services=services, device_names=device_names, endpoints_data=endpoints_data,
         ste=ServiceTypeEnum, sse=ServiceStatusEnum)
 
-
-@service.route('add', methods=['GET', 'POST'])
-def add():
-    flash('Add service route called', 'danger')
-    raise NotImplementedError()
-    #return render_template('service/home.html')
-
-
-@service.get('<path:service_uuid>/detail')
+@service.get('<path:service_uuid>/detail')                                          #Route for display all the details about a specific service 
 def detail(service_uuid: str):
     if 'context_uuid' not in session or 'topology_uuid' not in session:
         flash("Please select a context!", "warning")
@@ -76,9 +89,9 @@ def detail(service_uuid: str):
 
     try:
         context_client.connect()
-
         endpoint_ids = list()
         service_obj = get_service(context_client, service_uuid, rw_copy=False)
+
         if service_obj is None:
             flash('Context({:s})/Service({:s}) not found'.format(str(context_uuid), str(service_uuid)), 'danger')
             service_obj = Service()
@@ -94,17 +107,15 @@ def detail(service_uuid: str):
             device_names, endpoints_data = dict(), dict()
 
         context_client.close()
-
         return render_template(
             'service/detail.html', service=service_obj, connections=connections, device_names=device_names,
-            endpoints_data=endpoints_data, ste=ServiceTypeEnum, sse=ServiceStatusEnum, ile=IsolationLevelEnum)
+            endpoints_data=endpoints_data, ste=ServiceTypeEnum, sse=ServiceStatusEnum, ile=IsolationLevelEnum, type = type, f_action = f_action, l_action = l_action)
     except Exception as e:
         flash('The system encountered an error and cannot show the details of this service.', 'warning')
         current_app.logger.exception(e)
         return redirect(url_for('service.home'))
 
-
-@service.get('<path:service_uuid>/delete')
+@service.get('<path:service_uuid>/delete')                                          #Route for deleting a specific service     
 def delete(service_uuid: str):
     if 'context_uuid' not in session or 'topology_uuid' not in session:
         flash("Please select a context!", "warning")
@@ -124,3 +135,167 @@ def delete(service_uuid: str):
         flash('Problem deleting service "{:s}": {:s}'.format(service_uuid, str(e.details())), 'danger')
         current_app.logger.exception(e)
     return redirect(url_for('service.home'))
+
+#Added routes for creating a new Service
+@service.route('add', methods=['GET', 'POST'])                                      #Route for adding a new service          [Selecting the type of operation to be performed - First Form]
+def add():
+    form_1 = AddServiceForm_1()
+    if form_1.validate_on_submit():
+        #store the selected service type in session
+        #session['service_type'] = form_1.service_type.data
+        #redirect to the same page to display the second form
+        if form_1.service_type.data == 'ACL_L2':
+            return redirect(url_for('service.add_configure_ACL_L2'))
+        elif form_1.service_type.data == 'ACL_IPV4':
+            return redirect(url_for('service.add_configure_ACL_IPV4'))      
+        elif form_1.service_type.data == 'ACL_IPV6':
+            return redirect(url_for('service.add_configure_ACL_IPV6'))      
+        elif form_1.service_type.data == 'L2VPN':
+            return redirect(url_for('service.add_configure_L2VPN'))      
+        elif form_1.service_type.data == 'L3VPN':
+            return redirect(url_for('service.add_configure_L3VPN'))
+    # display the first form
+    return render_template('service/add.html', form_1=form_1, submit_text='Continue to configuraton')
+
+@service.route('add/configure/ACL_L2', methods=['GET', 'POST'])                     #Route for adding a new ACL_L2 service   [Setting the parameters for defining the service]
+def add_configure_ACL_L2():
+    form_acl = AddServiceForm_ACL_L2()
+    if form_acl.validate_on_submit():
+        flash(f'New configuration was created', 'success')
+        return redirect(url_for('service.home'))
+    print(form_acl.errors)
+    return render_template('service/configure_ACL_L2.html', form_acl=form_acl, submit_text='Add New Service')
+
+@service.route('add/configure/ACL_IPV4', methods=['GET', 'POST'])                   #Route for adding a new ACL_IPV4 service [Setting the parameters for defining the service]
+def add_configure_ACL_IPV4():
+    form_acl = AddServiceForm_ACL_IPV4()
+    if form_acl.validate_on_submit():
+        flash(f'New configuration was created', 'success')
+        return redirect(url_for('service.home'))
+    print(form_acl.errors)
+    return render_template('service/configure_ACL_IPV4.html', form_acl=form_acl, submit_text='Add New Service')
+
+@service.route('add/configure/ACL_IPV6', methods=['GET', 'POST'])                   #Route for adding a new ACL_IPV6 service [Setting the parameters for defining the service]
+def add_configure_ACL_IPV6():
+    form_acl = AddServiceForm_ACL_IPV6()
+    if form_acl.validate_on_submit():
+        flash(f'New configuration was created', 'success')
+        return redirect(url_for('service.home'))
+    print(form_acl.errors)
+    return render_template('service/configure_ACL_IPV6.html', form_acl=form_acl, submit_text='Add New Service')
+ 
+@service.route('add/configure/L2VPN', methods=['GET', 'POST'])                      #Route for adding a new L2VPN service    [Setting the parameters for defining the service]
+def add_configure_L2VPN():
+    form_l2vpn = AddServiceForm_L2VPN()                                                                     #Load the AddServiceForm_L2VPN form defined in forms.py
+    service_obj = Service()                                                                                 #Create a new instance of the Service class
+    context_uuid = session['context_uuid']                                                                  #Retrieves the context UUID from the session
+    topology_uuid = session['topology_uuid']                                                                #Retrieves the topology UUID from the session
+    context_client.connect()                                                                                #Connects to the context service using the context_client object
+    grpc_topology = get_topology(context_client, topology_uuid, context_uuid=context_uuid, rw_copy=False)   #Call the get_topology() function to retrieve the topology information for the given context and topology UUIDs
+    if grpc_topology is None:                                                                               #If the topology is not found, display an error message and set the devices list to an empty list
+        flash('Context({:s})/Topology({:s}) not found'.format(str(context_uuid), str(topology_uuid)), 'danger')
+        devices = []
+    else:                                                                                                   #If the topology is found
+        topo_device_uuids = {device_id.device_uuid.uuid for device_id in grpc_topology.device_ids}          #Retrieve the device UUIDs from the topology information
+        grpc_devices: DeviceList = context_client.ListDevices(Empty())                                      #Call the ListDevices() method on the context_client to retrieve a list of all devices
+        devices = [                                                                                         #Filter the list of devices to only include those with UUIDs that appear in the topology
+            device for device in grpc_devices.devices
+            if device.device_id.device_uuid.uuid in topo_device_uuids
+        ]
+
+    for i, device in enumerate(devices):                                                                    #Iterate over a range of numbers from 0 to the length of the devices list (The number of devices in the topology)
+        new_choice = (i, str(device.name))                                                                  #Create a new tuple consisting of the index and the name of the device at the current index.
+        form_l2vpn.service_device_1.choices.append(new_choice)                                              #Add the device to a select option in the form_l2vpn service_device_1 part.
+            
+    if form_l2vpn.validate_on_submit():                                                                     #Check if the form has been submitted and is valid
+        selected_device = devices[int(form_l2vpn.service_device_1.data)]                                    #Selected_Device will be the one selected by the user in the previously defined form field
+        try:
+            if form_l2vpn.service_endpoint_1.data not in [endpoint.name for endpoint in selected_device.device_endpoints]:    # Check if the endpoint submitted by the user is a valid endpoint of the selected device
+                raise ValidationError('The selected endpoint: ' + form_l2vpn.service_endpoint_1.data + ' is not a valid endpoint for: '+ selected_device.name + '. Please select an endpoint that is available for this device') # If it is not a valid endpoint -> Raise a Validation Error
+            else:
+                selected_endpoint = form_l2vpn.service_endpoint_1.data                                        #If the selected endpoint is valid, save it in a variable
+        except Exception as e:                                                                              # Catch any exception raised during the validation process 
+            flash('{:s}'.format(str(e.args[0])), 'danger')
+            current_app.logger.exception(e)
+            return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service')    #Render the L2VPN configuration form with the previously entered data and an error message
+
+        #SET THE MANDATORY PARAMETERS FOR WHEN DEFINING A SERVICE [APART FROM THE ONES DEFINING THE TYPE OF SERVICE]
+        #Service UUID:
+        service_obj.service_id.service_uuid.uuid = str(form_l2vpn.service_name.data)                        #Create the Service UUID (Unique Identifier of the service) from the service name
+
+        #Service type [OPTIONS Defined in Context.proto]: 0(Unknown), 1(L3NM), 2(L2NM), 3(TAPI_CONNECTIVITY_SERVICE), 4(ACL) :
+        service_obj.service_type = int(form_l2vpn.service_type.data)                                        #Set the Service type as selected by the user in the form [Fixed value: L2NM]
+                
+        #Validate the Context
+        try:
+            if 'context_uuid' not in session or 'topology_uuid' not in session:                             #Check if the context_uuid and topology_uuid are in session              
+                flash("Please select a context!", "warning")                                        
+                return redirect(url_for("main.home"))                                                       #If not -> Warning message & redirect to home page
+            context_uuid = session['context_uuid']                                                          #Retrieves the context UUID from the session       
+            
+            service_uuid = service_obj.service_id.service_uuid.uuid                                         #Set the service UUID
+            endpoint_ids = [
+                json_endpoint_id(json_device_id(selected_device.name), str(selected_endpoint))              #Create a list containing a element that represents the Selected Device ID and the Selected Endpoint
+            ]
+            
+            constraints = []                                                                                #Constraints -> Creates a list in which the constraints for the service will be added
+            if form_l2vpn.service_capacity.data:
+                constraints.append(json_constraint_sla_capacity(float(form_l2vpn.service_capacity.data)))   #Capacity [Gbps]
+            if form_l2vpn.service_latency.data:
+                constraints.append(json_constraint_sla_latency(float(form_l2vpn.service_latency.data)))     #Latency [ms]
+            if form_l2vpn.service_availability.data:
+                constraints.append(json_constraint_sla_availability(1, True, float(form_l2vpn.service_availability.data)))                  #Availability [%]
+            if form_l2vpn.service_isolation.data is not None and form_l2vpn.service_isolation.data != '':
+                constraints.append(json_constraint_sla_isolation([getattr(IsolationLevelEnum, str(form_l2vpn.service_isolation.data))]))    #Isolation (Predefined values)
+
+            params = {                                                                                      #Parameters for defining the L2VPN [Value given in the webui form] -> /service/service_handlers/l2nm_emulated/ConfigRules.py
+                'sub_interface_index': str(form_l2vpn.IF_index.data),                                       #sub_interface_index -> IF_index
+                'vlan_id': str(form_l2vpn.IF_vlan_id.data),                                                 #vlan_id             -> IF_vlan_id
+                'remote_router': str(form_l2vpn.NI_remote_system.data),                                     #remote_router       -> NI_remote_system
+                'circuit_id': str(form_l2vpn.NI_VC_ID.data),                                                #circuit_id          -> NI_VC_ID
+                'mtu':str(form_l2vpn.IF_mtu.data),                                                          #mtu                 -> NI_mtu                               
+            }
+            params_with_data = {k: v for k, v in params.items() if v is not None and str(v) != 'None' and v != ''}      #The parameters that have no value are removed and the rest are stored in params_with_data
+            config_rules = [                                                                                            #Create the configuration rules from the params_with_data 
+                json_config_rule_set(
+                    '/device[{:s}]/endpoint[{:s}]/settings'.format(str(selected_device.name), str(selected_endpoint)), params_with_data
+                )
+            ]
+            service_client.connect()
+            context_client.connect()
+
+            descriptor_json = json_service_l2nm_planned(service_uuid = service_uuid, endpoint_ids = endpoint_ids, constraints = constraints, config_rules = config_rules, context_uuid= context_uuid)
+            descriptor_json = {"services": [descriptor_json]}                                               #Wrap the descriptor between the tag: "services": []"
+            process_descriptors(descriptor_json)                                                            #Call the process_descriptors function to add the new service defined in the descriptor_json variable
+            
+            service_client.close()
+            context_client.close()
+
+            flash('Service "{:s}" added successfully!'.format(service_obj.service_id.service_uuid.uuid), 'success')     #If the service was added succesfully -> Flash success message with newly added service UUID.
+            return redirect(url_for('service.home', service_uuid=service_obj.service_id.service_uuid.uuid))             #If the service was added succesfully -> Redirect to the service.home URL
+        
+        except Exception as e:                                                                                          #If the service was NOT added succesfully -> Catch any exceptions that occur when adding a new service
+            flash('Problem adding service: {:s}'.format((str(e.args[0]))), 'danger')                                    #If the service was NOT added succesfully -> Include the exception message in a flashed message 
+            current_app.logger.exception(e)                                                                             #If the service was NOT added succesfully -> Log the exception using Flask's logger
+        return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service')    #If the service was NOT added succesfully -> Redirect to service/configure_L2VPN.html 
+    print(form_l2vpn.errors)
+    return render_template('service/configure_L2VPN.html', form_l2vpn=form_l2vpn, submit_text='Add New Service')
+
+@service.route('add/configure/L3VPN', methods=['GET', 'POST'])                      #Route for adding a new L3VPN service    [Setting the parameters for defining the service]
+def add_configure_L3VPN():
+    form_l3vpn = AddServiceForm_L3VPN()
+    #form_l3vpn.l3vpn_params = SERVICE_PARAMETERS['L3VPN']
+    if form_l3vpn.validate_on_submit():
+        flash(f'New configuration was created', 'success')
+        return redirect(url_for('service.home'))
+    print(form_l3vpn.errors)
+    return render_template('service/configure_L3VPN.html', form_l3vpn=form_l3vpn, submit_text='Add New Service')
+
+def process_descriptors(descriptors):                                                                       #The function receives a "descriptors" parameter which has to be a JSON descriptor object 
+    descriptor_loader = DescriptorLoader(descriptors)                                                       #Creates a descriptor_loader object 
+    results = descriptor_loader.process()                                                                   #
+    for message,level in compose_notifications(results):                                                    #
+        if level == 'error':                                                                                #
+            LOGGER.warning('ERROR message={:s}'.format(str(message)))                                       #
+        flash(message, level)                                                                               #
+
diff --git a/src/webui/service/templates/service/detail.html b/src/webui/service/templates/service/detail.html
index bee2e93c53896a8eeac826703a60afe02a5aa825..1c5335db36deb5f5aef0077106243b61e7935666 100644
--- a/src/webui/service/templates/service/detail.html
+++ b/src/webui/service/templates/service/detail.html
@@ -211,6 +211,69 @@
             </td>
         </tr>
         {% endif %}
+        {% if config.WhichOneof('config_rule') == 'acl' %}
+        <tr>
+            <td>
+                {% if config.acl %}
+                    {% set endpoint_id = config.acl.endpoint_id %}
+                    {% set rule_set_name = config.acl.rule_set.name %}
+                    /device[{{ endpoint_id.device_id.device_uuid.uuid }}]/endpoint[{{ endpoint_id.endpoint_uuid.uuid }}]/acl_ruleset[{{ rule_set_name }}]
+                {% endif %}
+            </td>
+            <td>
+                <ul>
+                    {% if config.acl.rule_set.name %}
+                        <li><b>name: </b>{{ config.acl.rule_set.name }}</li>
+                    {% endif %}
+                    {% if config.acl.rule_set.type %}
+                        <li><b>type: </b>{{ type[config.acl.rule_set.type] }}</li>
+                    {% endif %}
+                    {% if config.acl.rule_set.description %}
+                        <li><b>description: </b>{{ config.acl.rule_set.description }}</li>
+                    {% endif %}
+                    {% if config.acl.rule_set.user_id %}
+                        <li><b>user_id: </b>{{ config.acl.rule_set.user_id }}</li>
+                    {% endif %}  
+                    {% for entry in config.acl.rule_set.entries %}
+                    {% if entry.description %}
+                        <li><b>entry {{ entry.sequence_id }} description: </b>{{ entry.description }}</li>
+                    {% endif %}
+                    {% if entry.match.protocol %}
+                        <li><b>entry {{ entry.sequence_id }} protocol: </b>{{ entry.match.protocol }}</li>
+                    {% endif %}
+                    {% if entry.match.dscp %}
+                        <li><b>entry {{ entry.sequence_id }} dscp:</b>{{ entry.match.dscp }}</li>
+                    {% endif %}
+                    {% if entry.match.src_address %}
+                        <li><b>entry {{ entry.sequence_id }} src_address: </b>{{ entry.match.src_address }}</li>
+                    {% endif %}
+                    {% if entry.match.dst_address %}
+                        <li><b>entry {{ entry.sequence_id }} dst_address: </b>{{ entry.match.dst_address }}</li>
+                    {% endif %}
+                    {% if entry.match.src_port %}
+                        <li><b>entry {{ entry.sequence_id }} src_port: </b>{{ entry.match.src_port }}</li>
+                    {% endif %}
+                    {% if entry.match.dst_port %}
+                        <li><b>entry {{ entry.sequence_id }} dst_port: </b>{{ entry.match.dst_port }}</li>
+                    {% endif %}
+                    {% if entry.match.start_mpls_label %}
+                        <li><b>entry {{ entry.sequence_id }} start mpls label: </b>{{ entry.match.start_mpls_label }}</li>
+                    {% endif %}
+                    {% if entry.match.end_mpls_label %}
+                        <li><b>entry {{ entry.sequence_id }} end mpls label: </b> {{ entry.match.end_mpls_label }}</li>
+                    {% endif %}
+                    {% if entry.action.forward_action %}
+                        <li><b>entry {{ entry.sequence_id }} forward_action: </b>{{ f_action[entry.action.forward_action] }}</li>
+                    {% endif %}
+                    {% if entry.action.log_action %}
+                        <li><b>entry {{ entry.sequence_id }} log_action: </b>{{l_action[entry.action.log_action] }}</li>
+                    {% endif %}
+                {% endfor %}
+
+                </ul>
+            </td>
+        </tr>
+        {% endif %}
         {% endfor %}
     </tbody>
 </table>