Adtran OLT: Work on ACL entries for initial flows and warning cleanup

Change-Id: I6bddec2c252ad8f0230371e818707d6e03ee9427
diff --git a/voltha/adapters/adtran_olt/adtran_device_handler.py b/voltha/adapters/adtran_olt/adtran_device_handler.py
index ad735b3..a4c84a2 100644
--- a/voltha/adapters/adtran_olt/adtran_device_handler.py
+++ b/voltha/adapters/adtran_olt/adtran_device_handler.py
@@ -396,7 +396,7 @@
                         device.images.image.extend(results.get('software-images', []))
 
                         device.root = True
-                        device.vendor = results.get('vendor', 'Adtran, Inc.')
+                        device.vendor = results.get('vendor', 'Adtran Inc.')
                         device.connect_status = ConnectStatus.REACHABLE
                         self.adapter_agent.update_device(device)
 
diff --git a/voltha/adapters/adtran_olt/adtran_olt.py b/voltha/adapters/adtran_olt/adtran_olt.py
index ee2ede8..fccee66 100644
--- a/voltha/adapters/adtran_olt/adtran_olt.py
+++ b/voltha/adapters/adtran_olt/adtran_olt.py
@@ -51,8 +51,8 @@
         self.config = config
         self.descriptor = Adapter(
             id=self.name,
-            vendor='Adtran Inc.',
-            version='1.29',
+            vendor='ADTRAN, Inc.',
+            version='1.30',
             config=AdapterConfig(log_level=LogLevel.INFO)
         )
         log.debug('adtran_olt.__init__', adapter_agent=adapter_agent)
diff --git a/voltha/adapters/adtran_olt/adtran_olt_handler.py b/voltha/adapters/adtran_olt/adtran_olt_handler.py
index 2df0387..2a36cb4 100644
--- a/voltha/adapters/adtran_olt/adtran_olt_handler.py
+++ b/voltha/adapters/adtran_olt/adtran_olt_handler.py
@@ -146,7 +146,7 @@
             'model': 'n/a',
             'hardware_version': 'unknown',
             'serial_number': 'unknown',
-            'vendor': 'Adtran, Inc.',
+            'vendor': 'ADTRAN, Inc.',
             'firmware_version': 'unknown',
             'running-revision': 'unknown',
             'candidate-revision': 'unknown',
@@ -214,7 +214,7 @@
 
     def initialize_resource_manager(self):
         # Initialize the resource manager
-        extra_args = '--olt_vendor {}'.format(self.resource_manager_key)
+        extra_args = '--olt_model {}'.format(self.resource_manager_key)
         self.resource_mgr = AdtranOltResourceMgr(self.device_id,
                                                  self.host_and_port,
                                                  extra_args,
diff --git a/voltha/adapters/adtran_olt/flow/acl.py b/voltha/adapters/adtran_olt/flow/acl.py
index 1845b0f..67f8c08 100644
--- a/voltha/adapters/adtran_olt/flow/acl.py
+++ b/voltha/adapters/adtran_olt/flow/acl.py
@@ -24,7 +24,7 @@
 
 ACL_NAME_FORMAT = 'VOLTHA-ACL-{}-{}'  # format(flow_entry.flow_id, flow-entry-hash)
 ACL_NAME_REGEX_ALL = 'VOLTHA-ACL-*'
-ACE_NAME_FORMAT = 'VOLTHA-ACE-{}-{}'  # format(flow_entry.flow_id, flow-entry-hash)
+ACE_NAME_FORMAT = 'VOLTHA-ACE-{}'  # format(flow_entry.flow_id)
 
 
 class ACL(object):
@@ -191,7 +191,16 @@
 
     @staticmethod
     def create(flow_entry):
-        return ACL(flow_entry)
+        acl = ACL(flow_entry)
+
+        # Already created and installed, return that one
+        acls_installed = _acl_list.get(flow_entry.handler.device_id)
+        if acls_installed is not None:
+            entry = acls_installed.get(acl._name)
+            if entry is not None:
+                return entry
+
+        return acl
 
     @staticmethod
     def flow_to_name(flow_entry):
@@ -199,7 +208,7 @@
 
     @staticmethod
     def flow_to_ace_name(flow_entry):
-        return ACE_NAME_FORMAT.format(flow_entry.flow_id, ACL.acl_hash(flow_entry))
+        return ACE_NAME_FORMAT.format(flow_entry.flow_id)
 
     @staticmethod
     def acl_hash(flow_entry):
diff --git a/voltha/adapters/adtran_olt/flow/evc.py b/voltha/adapters/adtran_olt/flow/evc.py
index 17cf005..ecc0593 100644
--- a/voltha/adapters/adtran_olt/flow/evc.py
+++ b/voltha/adapters/adtran_olt/flow/evc.py
@@ -395,7 +395,14 @@
         if self._flow.inner_vid is not None:
            self._switching_method = EVC.SwitchingMethod.DOUBLE_TAGGED
 
-        # Note: The following fields will get set when the first EVC-MAP
+        # For the Utility VLAN, multiple ingress ACLs (different GEMs) will need to
+        # be trapped on this EVC. Since these are usually untagged, we have to force
+        # the EVC to preserve CE VLAN tags.
+
+        if self._s_tag == self._flow.handler.utility_vlan:
+            self._ce_vlan_preservation = True
+
+        # Note: The following fields may get set when the first EVC-MAP
         #       is associated with this object. Once set, they cannot be changed to
         #       another value.
         #  self._stpid
diff --git a/voltha/adapters/adtran_olt/flow/evc_map.py b/voltha/adapters/adtran_olt/flow/evc_map.py
index d3e25dc..33c9360 100644
--- a/voltha/adapters/adtran_olt/flow/evc_map.py
+++ b/voltha/adapters/adtran_olt/flow/evc_map.py
@@ -19,6 +19,7 @@
 from acl import ACL
 from twisted.internet import defer
 from twisted.internet.defer import inlineCallbacks, returnValue, succeed
+from ncclient.operations.rpc import RPCError
 
 log = structlog.get_logger()
 
@@ -90,7 +91,6 @@
         self._c_tag = None
         self._men_ctag_priority = EVCMap.PriorityOption.DEFAULT
         self._men_ctag_pri = 0  # If Explicit Priority
-
         self._match_ce_vlan_id = None
         self._match_untagged = False
         self._match_destination_mac_address = None
@@ -322,8 +322,6 @@
             for acl in work_acls.itervalues():
                 try:
                     yield acl.install()
-                    # if not results.ok:
-                    #     pass                # TODO : do anything?
 
                 except Exception as e:
                     log.exception('acl-install-failed', name=self.name, e=e)
@@ -333,10 +331,12 @@
             # Now EVC-MAP
             if not self._installed or self._needs_update:
                 log.debug('needs-install-or-update', installed=self._installed, update=self._needs_update)
+                is_installed = self._installed
+                self._installed = True
                 try:
                     self._cancel_deferred()
                     map_xml = self._ingress_install_xml(self._gem_ids_and_vid, work_acls.values(),
-                                                        not self._installed) \
+                                                        not is_installed) \
                         if self._is_ingress_map else self._egress_install_xml()
 
                     log.debug('install', xml=map_xml, name=self.name)
@@ -347,12 +347,16 @@
 
                     if results.ok:
                         self._existing_acls.update(work_acls)
-
                     else:
                         self._new_acls.update(work_acls)
 
+                except RPCError as rpc_err:             # TODO: Try to catch this before attempting the install
+                    if rpc_err.tag == 'data-exists':    # Known race due to bulk-flow operation
+                        pass
+
                 except Exception as e:
                     log.exception('evc-map-install-failed', name=self.name, e=e)
+                    self._installed = is_installed
                     self._new_acls.update(work_acls)
                     raise
 
@@ -687,8 +691,9 @@
         is_uni = flow.handler.is_uni_port(flow.in_port)
 
         if is_pon or is_uni:
+            # Preserve CE VLAN tag only if utility VLAN/EVC
             self._uni_port = flow.handler.get_port_name(flow.in_port)
-            evc.ce_vlan_preservation = False
+            evc.ce_vlan_preservation = evc.ce_vlan_preservation or False
         else:
             self._status_message = 'EVC-MAPS without UNI or PON ports are not supported'
             return False    # UNI Ports handled in the EVC Maps
diff --git a/voltha/adapters/adtran_olt/pon_port.py b/voltha/adapters/adtran_olt/pon_port.py
index 0b18dc2..7aa36bd 100644
--- a/voltha/adapters/adtran_olt/pon_port.py
+++ b/voltha/adapters/adtran_olt/pon_port.py
@@ -883,11 +883,9 @@
     @property
     def get_next_onu_id(self):
         return self._parent.resource_mgr.get_onu_id(self._pon_id)
-        # return self._onu_id_pool.get_next()
 
     def release_onu_id(self, onu_id):
         self._parent.resource_mgr.free_onu_id(self._pon_id, onu_id)
-        # self._onu_id_pool.release(onu_id)
 
     @inlineCallbacks
     def _remove_from_hardware(self, onu_id):
@@ -931,6 +929,10 @@
             except Exception as e:
                 self.log.exception('onu-remove', serial_number=onu.serial_number, e=e)
 
+        # Remove from LOS list if needed
+        if onu.id in self._active_los_alarms:
+            self._active_los_alarms.remove(onu.id)
+
     def add_mcast_gem_port(self, mcast_gem, vlan):
         """
         Add any new Multicast GEM Ports to the PON