VOL-693: Support for enable, disable, and delete

Change-Id: I87e159379747bc1ec5c9269ddfb2254e87677895
diff --git a/voltha/adapters/adtran_onu/adtran_onu_handler.py b/voltha/adapters/adtran_onu/adtran_onu_handler.py
index e3290f8..0801796 100644
--- a/voltha/adapters/adtran_onu/adtran_onu_handler.py
+++ b/voltha/adapters/adtran_onu/adtran_onu_handler.py
@@ -35,6 +35,7 @@
 from voltha.protos.device_pb2 import Image
 from common.utils.indexpool import IndexPool
 from voltha.extensions.omci.openomci_agent import OpenOMCIAgent
+from voltha.extensions.omci.omci_me import *
 
 _ = third_party
 _MAXIMUM_PORT = 128          # PON and UNI ports
@@ -650,13 +651,16 @@
         # Remove the uni logical port from the OLT, if still present
         parent_device = self.adapter_agent.get_device(device.parent_id)
         assert parent_device
-        logical_device_id = parent_device.parent_id
-        assert logical_device_id
+
 
         for uni in self.uni_ports:
-            port_id = 'uni-{}'.format(uni.port_number)
+            #port_id = 'uni-{}'.format(uni.port_number)
+            port_id = uni.port_id_name()
 
             try:
+                #TODO: there is no logical device if olt disables first
+                logical_device_id = parent_device.parent_id
+                assert logical_device_id
                 port = self.adapter_agent.get_logical_port(logical_device_id,
                                                            port_id)
                 self.adapter_agent.delete_logical_port(logical_device_id, port)
@@ -664,10 +668,32 @@
                 self.log.info('logical-port-not-found', device_id=self.device_id,
                               portid=port_id)
 
-        # Remove pon port from parent
+        # Remove pon port from parent and disable
         if self._pon is not None:
             self.adapter_agent.delete_port_reference_from_parent(self.device_id,
                                                                  self._pon.get_port())
+            self._pon.enabled = False
+
+        # Send Uni Admin State Down
+
+        # ethernet_uni_entity_id = 0x101
+        # omci = self._handler.omci
+        # attributes = dict(
+        #     administrative_state=1  # - lock
+        # )
+        # frame = PptpEthernetUniFrame(
+        #     ethernet_uni_entity_id,  # Entity ID
+        #     attributes=attributes  # See above
+        # ).set()
+        # results = yield omci.send(frame)
+        #
+        # status = results.fields['omci_message'].fields['success_code']
+        # failed_attributes_mask = results.fields['omci_message'].fields['failed_attributes_mask']
+        # unsupported_attributes_mask = results.fields['omci_message'].fields['unsupported_attributes_mask']
+        # self.log.debug('set-pptp-ethernet-uni', status=status,
+        #                failed_attributes_mask=failed_attributes_mask,
+        #                unsupported_attributes_mask=unsupported_attributes_mask)
+
 
         # Just updating the port status may be an option as well
         # port.ofp_port.config = OFPPC_NO_RECV
@@ -708,7 +734,7 @@
 
             # Add the pon port reference to the parent
             if self._pon is not None:
-                # TODO: Send 'enable' to PonPort?
+                self._pon.enabled = True
                 self.adapter_agent.add_port_reference_to_parent(device.id,
                                                                 self._pon.get_port())
 
@@ -725,15 +751,23 @@
                 # vlan non-zero if created via legacy method (not xPON)
                 self.uni_port('deprecated').add_logical_port(device.vlan, device.vlan,
                                                              subscriber_vlan=device.vlan)
+            else:
+                # reestablish logical ports for each UNI
+                for uni in self.uni_ports:
+                    self.adapter_agent.add_port(device.id, uni.get_port())
+                    uni.add_logical_port(uni.logical_port_number, subscriber_vlan=uni.subscriber_vlan)
 
             device = self.adapter_agent.get_device(device.id)
             device.oper_status = OperStatus.ACTIVE
+            device.connect_status = ConnectStatus.REACHABLE
             device.reason = ''
 
             self.enabled = True
             self.adapter_agent.update_device(device)
 
             self.log.info('re-enabled', device_id=device.id)
+            self._pon._dev_info_loaded = False
+            self._bridge_initialized = False
         except Exception, e:
             self.log.exception('error-reenabling', e=e)
 
@@ -751,7 +785,6 @@
         if self._omci_agent is not None:
             self._omci_agent.remove_device(self.device_id, cleanup=True)
             self._omci_agent = None
-
         #
         # handling needed here
         # self.enabled = False
diff --git a/voltha/adapters/adtran_onu/onu_pm_metrics.py b/voltha/adapters/adtran_onu/onu_pm_metrics.py
index ac0b02e..52e1fc7 100644
--- a/voltha/adapters/adtran_onu/onu_pm_metrics.py
+++ b/voltha/adapters/adtran_onu/onu_pm_metrics.py
@@ -28,7 +28,7 @@
             ('tx_errors', PmConfig.COUNTER),
             ('rx_frames', PmConfig.COUNTER),
             ('rx_unknown_tid', PmConfig.COUNTER),
-            ('rx_onu_frames', PmConfig.COUNTER),        # Rx ONU autonomouse messages
+            ('rx_onu_frames', PmConfig.COUNTER),        # Rx ONU autonomous messages
             ('rx_alarm_overflow', PmConfig.COUNTER),    # Autonomous ONU generated alarm message overflows
             ('rx_avc_overflow', PmConfig.COUNTER),      # Autonomous ONU generated AVC message overflows
             ('rx_onu_discards', PmConfig.COUNTER),      # Autonomous ONU message unknown type discards
diff --git a/voltha/adapters/adtran_onu/pon_port.py b/voltha/adapters/adtran_onu/pon_port.py
index 0b14ee1..2edb6f7 100644
--- a/voltha/adapters/adtran_onu/pon_port.py
+++ b/voltha/adapters/adtran_onu/pon_port.py
@@ -175,9 +175,19 @@
         return self._port
 
     def _update_adapter_agent(self):
-        # TODO: Currently does the adapter_agent allow 'update' of port status
-        # self.adapter_agent.update_port(self.olt.device_id, self.get_port())
-        pass
+        """
+        Update the port status and state in the core
+        """
+        self.log.debug('update-adapter-agent', admin_state=self._admin_state,
+            oper_status=self._oper_status)
+
+        if self._port is not None:
+            self._port.admin_state = self._admin_state
+            self._port.oper_status = self._oper_status
+
+        # adapter_agent add_port also does an update of port status
+        self._handler.adapter_agent.add_port(self._handler.device_id, self.get_port())
+
 
     @property
     def onu_omci_device(self):
@@ -206,6 +216,9 @@
                 for uni in self._handler.uni_ports:
                     uni.add_logical_port(None, None)
 
+                #BKP
+                device = self._handler.adapter_agent.get_device(self._handler.device_id)
+
                 vendor = omci.query_mib_single_attribute(OntG.class_id, 0, 'vendor_id') or 'ADTN'
                 assert vendor == 'ADTN', \
                     "Invalid Device/Wrong device adapter assigned: '{}'".format(vendor)
@@ -263,6 +276,7 @@
                 # Save our device information
                 self._handler.adapter_agent.update_device(device)
                 self._dev_info_loaded = True
+                self._bridge_initialized = False
 
             except Exception as e:
                 self.log.exception('device-info-load', e=e)
@@ -274,9 +288,11 @@
     def resync_omci_settings(self):
         self._cancel_resync_deferred()
 
-        if not self._bridge_initialized:
+        device = self._handler.adapter_agent.get_device(self._handler.device_id)
+
+        if not self._bridge_initialized and device.vlan > 0 :
             self.log.info('resync-omci-settings', initialized=self._bridge_initialized)
-            device = self._handler.adapter_agent.get_device(self._handler.device_id)
+            #device = self._handler.adapter_agent.get_device(self._handler.device_id)
 
             if not self.enabled or device is None:
                 returnValue('not-enabled')
@@ -664,6 +680,9 @@
                 # Try again later
                 self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
                                                    self.resync_omci_settings)
+        else:
+                self._deferred = reactor.callLater(_STARTUP_RETRY_WAIT,
+                                                   self.resync_omci_settings)
 
     def add_tcont(self, tcont, reflow=False):
         """
diff --git a/voltha/adapters/adtran_onu/uni_port.py b/voltha/adapters/adtran_onu/uni_port.py
index 6fc7b04..d965144 100644
--- a/voltha/adapters/adtran_onu/uni_port.py
+++ b/voltha/adapters/adtran_onu/uni_port.py
@@ -107,6 +107,14 @@
         return self._port_number
 
     @property
+    def subscriber_vlan(self):
+        """
+        Subscriber vlan assigned to this UNI
+        :return: (int) subscriber vlan
+        """
+        return self._subscriber_vlan
+
+    @property
     def logical_port_number(self):
         """
         Logical device port number (used as OpenFlow port for UNI)
@@ -115,9 +123,19 @@
         return self._logical_port_number
 
     def _update_adapter_agent(self):
-        # TODO: Currently does the adapter_agent allow 'update' of port status
-        # self.adapter_agent.update_port(self.olt.device_id, self.get_port())
-        pass
+        """
+        Update the port status and state in the core
+        """
+        self.log.debug('update-adapter-agent', admin_state=self._admin_state,
+            oper_status=self._oper_status)
+
+        if self._port is not None:
+            self._port.admin_state = self._admin_state
+            self._port.oper_status = self._oper_status
+
+        # adapter_agent add_port also does an update of existing port
+        self._handler.adapter_agent.add_port(self._handler.logical_device_id,
+                                             self.get_port())
 
     @staticmethod
     def decode_venet(venet_info):
@@ -165,10 +183,26 @@
                               oper_status=self._oper_status)
         return self._port
 
+    def port_id_name(self):
+        return 'uni-{}'.format(self._logical_port_number)
+
     def add_logical_port(self, openflow_port_no, subscriber_vlan=None,
                          capabilities=OFPPF_10GB_FD | OFPPF_FIBER,
                          speed=OFPPF_10GB_FD):
 
+        if self._logical_port_number is not None:
+            # delete old logical port if it exists
+            try:
+                port = self.adapter_agent.get_logical_port(self._handler.logical_device_id,
+                                                           self.port_id_name())
+                self.adapter_agent.delete_logical_port(self._handler.logical_device_id, port)
+
+            except Exception as e:
+                # assume this exception was because logical port does not already exist
+                pass
+
+            self._logical_port_number = None
+
         # Use vENET provisioned values if none supplied
         port_no = openflow_port_no or self._ofp_port_no
         vlan = subscriber_vlan or self._subscriber_vlan
@@ -190,7 +224,7 @@
                                           device.parent_port_no & 0xff,
                                           (port_no >> 8) & 0xff,
                                           port_no & 0xff)),
-                name='uni-{}'.format(port_no),
+                name=self.port_id_name(),
                 config=0,
                 state=OFPPS_LIVE,
                 curr=capabilities,
@@ -201,7 +235,7 @@
             )
             self._handler.adapter_agent.add_logical_port(self._handler.logical_device_id,
                                                          LogicalPort(
-                                                             id='uni-{}'.format(port_no),
+                                                             id=self.port_id_name(),
                                                              ofp_port=openflow_port,
                                                              device_id=device.id,
                                                              device_port_no=self._port_number))