Openolt data model changes (3rd batch)

Remove adapter_agent from openolt_flow_mgr.

Change-Id: I6d29180528a80c96df45ec441fdefda8c815c29b
diff --git a/voltha/adapters/openolt/openolt_data_model.py b/voltha/adapters/openolt/openolt_data_model.py
index f48e0d6..dca219d 100644
--- a/voltha/adapters/openolt/openolt_data_model.py
+++ b/voltha/adapters/openolt/openolt_data_model.py
@@ -15,6 +15,7 @@
 #
 import structlog
 import socket
+import voltha.core.flow_decomposer as fd
 from voltha.adapters.openolt.openolt_utils import OpenoltUtils
 from voltha.protos.device_pb2 import Port, Device
 from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
@@ -44,8 +45,7 @@
 
         self.adapter_agent.update_device(device)
 
-    def __del__(self):
-        pass
+        self.nni_intf_id = None
 
     def reconcile(self):
         assert self.logical_device_id is not None
@@ -115,12 +115,42 @@
         self.adapter_agent.update_device(self.device)
 
     def olt_oper_down(self):
-        self._disable_logical_device()
+        self.__disable_logical_device()
 
     def olt_delete(self):
         ld = self.adapter_agent.get_logical_device(self.logical_device_id)
         self.adapter_agent.delete_logical_device(ld)
 
+    def olt_port_add_update(self, intf_id, intf_type, oper):
+        if oper == "up":
+            oper_status = OperStatus.ACTIVE
+        else:
+            oper_status = OperStatus.DISCOVERED
+
+        if intf_type == "nni":
+            port_type = Port.ETHERNET_NNI
+        elif intf_type == "pon":
+            port_type = Port.PON_OLT
+
+        port_no, label = self.__add_port(intf_id, port_type, oper_status)
+
+        if intf_type == "nni":
+            self.__add_logical_port(port_no, intf_id, oper_status)
+            self.nni_intf_id = intf_id
+
+    def olt_nni_intf_id(self):
+        if self.nni_intf_id is not None:
+            return self.nni_intf_id
+
+        port_list = self.adapter_agent.get_ports(self.device.id,
+                                                 Port.ETHERNET_NNI)
+        logical_port = self.adapter_agent.get_logical_port(
+            self.logical_device_id, port_list[0].label)
+        self.nni_intf_id = self.platform.intf_id_from_nni_port_num(
+            logical_port.ofp_port.port_no)
+        self.log.debug("nni-intf-d ", nni_intf_id=self.nni_intf_id)
+        return self.nni_intf_id
+
     def onu_create(self, intf_id, onu_id, serial_number):
         onu_device = self.adapter_agent.get_child_device(
             self.device.id,
@@ -156,18 +186,18 @@
             self.device.id,
             serial_number=serial_number)
         try:
-            self.adapter_agent.delete_child_device(self.device_id,
+            self.adapter_agent.delete_child_device(self.device.id,
                                                    onu_device.id, onu_device)
         except Exception as e:
             self.log.error('adapter_agent error', error=e)
 
-        ofp_port_name = self._get_uni_ofp_port_name(onu_device)
+        ofp_port_name = self.__get_uni_ofp_port_name(onu_device)
         if ofp_port_name is None:
             self.log.exception("uni-ofp-port-not-found")
             return
 
         try:
-            self._delete_logical_port(onu_device)
+            self.__delete_logical_port(onu_device)
         except Exception as e:
             self.log.error('logical_port delete error', error=e)
         try:
@@ -215,7 +245,7 @@
             onu_device.oper_status = OperStatus.DISCOVERED
             self.adapter_agent.update_device(onu_device)
         # Set port oper state to Discovered
-        self.data_model._onu_ports_down(onu_device)
+        self.data_model.__onu_ports_down(onu_device)
 
         onu_adapter_agent.update_interface(onu_device,
                                            {'oper_state': 'down'})
@@ -258,27 +288,89 @@
         onu_adapter_agent.create_interface(onu_device,
                                            _OnuIndication(intf_id, onu_id))
 
-    def olt_port_add_update(self, intf_id, intf_type, oper):
-        if oper == "up":
-            oper_status = OperStatus.ACTIVE
+    def onu_download_tech_profile(self, intf_id, onu_id, uni_id, tp_path):
+        onu_device = self.adapter_agent.get_child_device(
+            self.device.id,
+            parent_port_no=self.platform.intf_id_to_port_no(intf_id,
+                                                            Port.PON_OLT),
+            onu_id=onu_id)
+        msg = {'proxy_address': onu_device.proxy_address,
+               'uni_id': uni_id, 'event': 'download_tech_profile',
+               'event_data': tp_path}
+
+        # Send the event message to the ONU adapter
+        self.adapter_agent.publish_inter_adapter_message(
+            onu_device.id, msg)
+
+    # #######################################################################
+    # Flow decomposer utility functions
+    #
+    # Flow related functions that are used by the OpenOLT flow decomposer.
+    # These are all prefixed with _ to denote that they will likely be removed
+    # once OpenOLT adapter transitions back to using core's flow decomposer.
+    # #######################################################################
+
+    def _flow_extract_info(self, flow, flow_direction):
+        uni_port_no = None
+        child_device_id = None
+        if flow_direction == "upstream":
+            for field in fd.get_ofb_fields(flow):
+                if field.type == fd.IN_PORT:
+                    is_uni, child_device_id = self.__is_uni_port(field.port)
+                    if is_uni:
+                        uni_port_no = field.port
+        elif flow_direction == "downstream":
+            for field in fd.get_ofb_fields(flow):
+                if field.type == fd.METADATA:
+                    uni_port = field.table_metadata & 0xFFFFFFFF
+                    is_uni, child_device_id = self.__is_uni_port(uni_port)
+                    if is_uni:
+                        uni_port_no = field.port
+
+            if uni_port_no is None:
+                for action in fd.get_actions(flow):
+                    if action.type == fd.OUTPUT:
+                        is_uni, child_device_id = \
+                            self.__is_uni_port(action.output.port)
+                        if is_uni:
+                            uni_port_no = action.output.port
+
+        if child_device_id:
+            child_device = self.adapter_agent.get_device(child_device_id)
+            pon_intf = child_device.proxy_address.channel_id
+            onu_id = child_device.proxy_address.onu_id
+            uni_id = self.platform.uni_id_from_port_num(uni_port_no) \
+                if uni_port_no is not None else None
         else:
-            oper_status = OperStatus.DISCOVERED
+            raise ValueError
 
-        if intf_type == "nni":
-            port_type = Port.ETHERNET_NNI
-        elif intf_type == "pon":
-            port_type = Port.PON_OLT
+        return pon_intf, onu_id, uni_id
 
-        port_no, label = self._add_port(intf_id, port_type, oper_status)
+    def _get_ofp_port_name(self, intf_id, onu_id, uni_id):
+        parent_port_no = self.platform.intf_id_to_port_no(intf_id,
+                                                          Port.PON_OLT)
+        child_device = self.adapter_agent.get_child_device(
+            self.device.id, parent_port_no=parent_port_no, onu_id=onu_id)
+        if child_device is None:
+            self.log.error("could-not-find-child-device",
+                           parent_port_no=intf_id, onu_id=onu_id)
+            return (None, None)
+        ports = self.adapter_agent.get_ports(child_device.id,
+                                             Port.ETHERNET_UNI)
+        logical_port = self.adapter_agent.get_logical_port(
+            self.logical_device_id, ports[uni_id].label)
+        ofp_port_name = (logical_port.ofp_port.name,
+                         logical_port.ofp_port.port_no)
+        return ofp_port_name
 
-        if intf_type == "nni":
-            self._add_logical_port(port_no, intf_id, oper_status)
-
-    # #################
+    # #######################################################################
     # Private functions
-    # #################
+    #
+    # These functions are prefixed with __ to denote that they are private
+    # to openolt_data_model and should not be called directly from the adapter.
+    # #######################################################################
 
-    def _disable_logical_device(self):
+    def __disable_logical_device(self):
         oper_state = OperStatus.UNKNOWN
         connect_state = ConnectStatus.UNREACHABLE
 
@@ -316,7 +408,7 @@
         self.device.connect_status = connect_state
         self.adapter_agent.update_device(self.device)
 
-    def _add_logical_port(self, port_no, intf_id, oper_state):
+    def __add_logical_port(self, port_no, intf_id, oper_state):
         self.log.info('adding-logical-port', port_no=port_no)
 
         label = OpenoltUtils.port_name(port_no, Port.ETHERNET_NNI)
@@ -348,7 +440,7 @@
         self.adapter_agent.add_logical_port(self.logical_device_id,
                                             logical_port)
 
-    def _delete_logical_port(self, child_device):
+    def __delete_logical_port(self, child_device):
         logical_ports = self.proxy.get('/logical_devices/{}/ports'.format(
             self.data_model.logical_device_id))
         for logical_port in logical_ports:
@@ -362,7 +454,7 @@
                     self.data_model.logical_device_id, logical_port)
                 return
 
-    def _onu_ports_down(self, onu_device):
+    def __onu_ports_down(self, onu_device):
         onu_ports = self.proxy.get('devices/{}/ports'.format(onu_device.id))
         for onu_port in onu_ports:
             self.log.debug('onu-ports-down', onu_port=onu_port)
@@ -382,7 +474,7 @@
                                onu_ports=onu_ports, onu_port_id=onu_port_id,
                                error=e)
 
-    def _add_port(self, intf_id, port_type, oper_status):
+    def __add_port(self, intf_id, port_type, oper_status):
         port_no = self.platform.intf_id_to_port_no(intf_id, port_type)
 
         label = OpenoltUtils.port_name(port_no, port_type, intf_id)
@@ -397,10 +489,22 @@
 
         return port_no, label
 
-    def _get_uni_ofp_port_name(self, child_device):
+    def __get_uni_ofp_port_name(self, child_device):
         logical_ports = self.proxy.get('/logical_devices/{}/ports'.format(
             self.data_model.logical_device_id))
         for logical_port in logical_ports:
             if logical_port.device_id == child_device.id:
                 return logical_port.ofp_port.name
         return None
+
+    def __is_uni_port(self, port_no):
+        try:
+            port = self.adapter_agent.get_logical_port(
+                self.logical_device_id, 'uni-{}'.format(port_no))
+            if port is not None:
+                return (not port.root_port), port.device_id
+            else:
+                return False, None
+        except Exception as e:
+            self.log.error("error-retrieving-port", e=e)
+            return False, None
diff --git a/voltha/adapters/openolt/openolt_device.py b/voltha/adapters/openolt/openolt_device.py
index 105db1d..da08170 100644
--- a/voltha/adapters/openolt/openolt_device.py
+++ b/voltha/adapters/openolt/openolt_device.py
@@ -158,10 +158,11 @@
                                                     self.host_and_port,
                                                     self.extra_args,
                                                     self.device_info)
-        self.flow_mgr = self.flow_mgr_class(self.adapter_agent, self.log,
-                                            self.stub, self.device_id,
+        self.flow_mgr = self.flow_mgr_class(self.log, self.stub,
+                                            self.device_id,
                                             self.data_model.logical_device_id,
-                                            self.platform, self.resource_mgr)
+                                            self.platform, self.resource_mgr,
+                                            self.data_model)
 
         self.alarm_mgr = self.alarm_mgr_class(
             self.log, self.adapter_agent, self.device_id,
@@ -548,7 +549,6 @@
             # Rebooting to reset the state
             self.reboot()
             self.data_model.olt_delete()
-            del self.data_model
         except Exception as e:
             self.log.error('Failure to delete openolt device', error=e)
             raise e
diff --git a/voltha/adapters/openolt/openolt_flow_mgr.py b/voltha/adapters/openolt/openolt_flow_mgr.py
index b15d70c..edac82a 100644
--- a/voltha/adapters/openolt/openolt_flow_mgr.py
+++ b/voltha/adapters/openolt/openolt_flow_mgr.py
@@ -71,14 +71,13 @@
 
 class OpenOltFlowMgr(object):
 
-    def __init__(self, adapter_agent, log, stub, device_id, logical_device_id,
-                 platform, resource_mgr):
-        self.adapter_agent = adapter_agent
+    def __init__(self, log, stub, device_id, logical_device_id,
+                 platform, resource_mgr, data_model):
+        self.data_model = data_model
         self.log = log
         self.stub = stub
         self.device_id = device_id
         self.logical_device_id = logical_device_id
-        self.nni_intf_id = None
         self.platform = platform
         self.logical_flows_proxy = registry('core').get_proxy(
             '/logical_devices/{}/flows'.format(self.logical_device_id))
@@ -206,51 +205,14 @@
         self.divide_and_add_flow(intf_id, onu_id, uni_id, port_no,
                                  classifier_info, action_info, flow)
 
-    def _is_uni_port(self, port_no):
-        try:
-            port = self.adapter_agent.get_logical_port(
-                self.logical_device_id, 'uni-{}'.format(port_no))
-            if port is not None:
-                return (not port.root_port), port.device_id
-            else:
-                return False, None
-        except Exception as e:
-            self.log.error("error-retrieving-port", e=e)
-            return False, None
-
     def _clear_flow_id_from_rm(self, flow, flow_id, flow_direction):
-        uni_port_no = None
-        child_device_id = None
-        if flow_direction == UPSTREAM:
-            for field in fd.get_ofb_fields(flow):
-                if field.type == fd.IN_PORT:
-                    is_uni, child_device_id = self._is_uni_port(field.port)
-                    if is_uni:
-                        uni_port_no = field.port
-        elif flow_direction == DOWNSTREAM:
-            for field in fd.get_ofb_fields(flow):
-                if field.type == fd.METADATA:
-                    uni_port = field.table_metadata & 0xFFFFFFFF
-                    is_uni, child_device_id = self._is_uni_port(uni_port)
-                    if is_uni:
-                        uni_port_no = field.port
-
-            if uni_port_no is None:
-                for action in fd.get_actions(flow):
-                    if action.type == fd.OUTPUT:
-                        is_uni, child_device_id = \
-                            self._is_uni_port(action.output.port)
-                        if is_uni:
-                            uni_port_no = action.output.port
-
-        if child_device_id:
-            child_device = self.adapter_agent.get_device(child_device_id)
-            pon_intf = child_device.proxy_address.channel_id
-            onu_id = child_device.proxy_address.onu_id
-            uni_id = self.platform.uni_id_from_port_num(uni_port_no) \
-                if uni_port_no is not None else None
-            uni_id = self.platform.uni_id_from_port_num(uni_port_no) \
-                if uni_port_no is not None else None
+        try:
+            pon_intf, onu_id, uni_id \
+                = self.data_model._flow_extract_info(flow, flow_direction)
+        except ValueError:
+            self.log.error("failure extracting pon_intf, onu_id, uni_id info \
+                           from flow")
+        else:
             flows = self.resource_mgr.get_flow_id_info(pon_intf, onu_id,
                                                        uni_id, flow_id)
             assert (isinstance(flows, list))
@@ -268,9 +230,6 @@
                         return
 
             self.resource_mgr.free_flow_id(pon_intf, onu_id, uni_id, flow_id)
-        else:
-            self.log.error("invalid-info", uni_port_no=uni_port_no,
-                           child_device_id=child_device_id)
 
     def retry_add_flow(self, flow):
         self.log.debug("retry-add-flow")
@@ -324,23 +283,6 @@
             self.log.debug('no device flow to remove for this flow (normal '
                            'for multi table flows)', flow=flow)
 
-    def _get_ofp_port_name(self, intf_id, onu_id, uni_id):
-        parent_port_no = self.platform.intf_id_to_port_no(intf_id,
-                                                          Port.PON_OLT)
-        child_device = self.adapter_agent.get_child_device(
-            self.device_id, parent_port_no=parent_port_no, onu_id=onu_id)
-        if child_device is None:
-            self.log.error("could-not-find-child-device",
-                           parent_port_no=intf_id, onu_id=onu_id)
-            return (None, None)
-        ports = self.adapter_agent.get_ports(child_device.id,
-                                             Port.ETHERNET_UNI)
-        logical_port = self.adapter_agent.get_logical_port(
-            self.logical_device_id, ports[uni_id].label)
-        ofp_port_name = (logical_port.ofp_port.name,
-                         logical_port.ofp_port.port_no)
-        return ofp_port_name
-
     def get_tp_path(self, intf_id, ofp_port_name, techprofile_id):
         return self.tech_profile[intf_id]. \
             get_tp_path(techprofile_id,
@@ -350,9 +292,8 @@
                                      ofp_port_name):
         # Remove the TP instance associated with the ONU
         if ofp_port_name is None:
-            ofp_port_name, ofp_port_no = self._get_ofp_port_name(intf_id,
-                                                                 onu_id,
-                                                                 uni_id)
+            ofp_port_name, ofp_port_no \
+                = self.data_model._get_ofp_port_name(intf_id, onu_id, uni_id)
         tp_id = self.resource_mgr.get_tech_profile_id_for_onu(intf_id, onu_id,
                                                               uni_id)
         tp_path = self.get_tp_path(intf_id, ofp_port_name, tp_id)
@@ -401,13 +342,9 @@
                         self.add_eapol_flow(intf_id, onu_id, uni_id, port_no,
                                             flow, alloc_id, gemport_id,
                                             vlan_id=vlan_id)
-                    parent_port_no = self.platform.intf_id_to_port_no(
-                        intf_id, Port.PON_OLT)
-                    onu_device = self.adapter_agent.get_child_device(
-                        self.device_id, onu_id=onu_id,
-                        parent_port_no=parent_port_no)
-                    (ofp_port_name, ofp_port_no) = self._get_ofp_port_name(
-                        intf_id, onu_id, uni_id)
+                    (ofp_port_name, ofp_port_no) \
+                        = self.data_model._get_ofp_port_name(intf_id, onu_id,
+                                                             uni_id)
                     if ofp_port_name is None:
                         self.log.error("port-name-not-found")
                         return
@@ -417,17 +354,12 @@
 
                     self.log.debug('Load-tech-profile-request-to-brcm-handler',
                                    tp_path=tp_path)
-                    msg = {'proxy_address': onu_device.proxy_address,
-                           'uni_id': uni_id, 'event': 'download_tech_profile',
-                           'event_data': tp_path}
-
-                    # Send the event message to the ONU adapter
-                    self.adapter_agent.publish_inter_adapter_message(
-                        onu_device.id, msg)
+                    self.data_model.onu_download_tech_profile(
+                        intf_id, onu_id, uni_id, tp_path)
 
                 if classifier[ETH_TYPE] == LLDP_ETH_TYPE:
                     self.log.debug('lldp flow add')
-                    nni_intf_id = self.get_nni_intf_id()
+                    nni_intf_id = self.data_model.olt_nni_intf_id()
                     self.add_lldp_flow(flow, port_no, nni_intf_id)
 
             elif PUSH_VLAN in action:
@@ -457,9 +389,8 @@
             return alloc_id, gem_port_ids
 
         try:
-            (ofp_port_name, ofp_port_no) = self._get_ofp_port_name(intf_id,
-                                                                   onu_id,
-                                                                   uni_id)
+            (ofp_port_name, ofp_port_no) \
+                = self.data_model._get_ofp_port_name(intf_id, onu_id, uni_id)
             if ofp_port_name is None:
                 self.log.error("port-name-not-found")
                 return alloc_id, gem_port_ids
@@ -588,7 +519,8 @@
             flow = openolt_pb2.Flow(
                 access_intf_id=intf_id, onu_id=onu_id, uni_id=uni_id,
                 flow_id=flow_id, flow_type=direction, alloc_id=alloc_id,
-                network_intf_id=self.get_nni_intf_id(), gemport_id=gemport_id,
+                network_intf_id=self.data_model.olt_nni_intf_id(),
+                gemport_id=gemport_id,
                 classifier=self.mk_classifier(classifier),
                 action=self.mk_action(action), priority=logical_flow.priority,
                 port_no=port_no, cookie=logical_flow.cookie)
@@ -630,7 +562,7 @@
                 onu_id=onu_id, uni_id=uni_id, flow_id=flow_id,
                 flow_type=UPSTREAM, access_intf_id=intf_id,
                 gemport_id=gemport_id, alloc_id=alloc_id,
-                network_intf_id=self.get_nni_intf_id(),
+                network_intf_id=self.data_model.olt_nni_intf_id(),
                 priority=logical_flow.priority,
                 classifier=self.mk_classifier(classifier),
                 action=self.mk_action(action),
@@ -673,7 +605,8 @@
             upstream_flow = openolt_pb2.Flow(
                 access_intf_id=intf_id, onu_id=onu_id, uni_id=uni_id,
                 flow_id=uplink_flow_id, flow_type=UPSTREAM, alloc_id=alloc_id,
-                network_intf_id=self.get_nni_intf_id(), gemport_id=gemport_id,
+                network_intf_id=self.data_model.olt_nni_intf_id(),
+                gemport_id=gemport_id,
                 classifier=self.mk_classifier(uplink_classifier),
                 action=self.mk_action(uplink_action),
                 priority=logical_flow.priority,
@@ -729,7 +662,8 @@
                 downstream_flow = openolt_pb2.Flow(
                     access_intf_id=intf_id, onu_id=onu_id, uni_id=uni_id,
                     flow_id=downlink_flow_id, flow_type=DOWNSTREAM,
-                    alloc_id=alloc_id, network_intf_id=self.get_nni_intf_id(),
+                    alloc_id=alloc_id,
+                    network_intf_id=self.data_model.olt_nni_intf_id(),
                     gemport_id=gemport_id,
                     classifier=self.mk_classifier(downlink_classifier),
                     action=self.mk_action(downlink_action),
@@ -1138,16 +1072,3 @@
         else:
             to_hash = dumps(classifier, sort_keys=True)
         return hashlib.md5(to_hash).hexdigest()[:12]
-
-    def get_nni_intf_id(self):
-        if self.nni_intf_id is not None:
-            return self.nni_intf_id
-
-        port_list = self.adapter_agent.get_ports(self.device_id,
-                                                 Port.ETHERNET_NNI)
-        logical_port = self.adapter_agent.get_logical_port(
-            self.logical_device_id, port_list[0].label)
-        self.nni_intf_id = self.platform.intf_id_from_nni_port_num(
-            logical_port.ofp_port.port_no)
-        self.log.debug("nni-intf-d ", nni_intf_id=self.nni_intf_id)
-        return self.nni_intf_id