VOL-1451 Initial checkin of openonu build

Produced docker container capable of building and running
openonu/brcm_openonci_onu.  Copied over current onu code
and resolved all imports by copying into the local source tree.

Change-Id: Ib9785d37afc65b7d32ecf74aee2456352626e2b6
diff --git a/python/adapters/brcm_openomci_onu/uni_port.py b/python/adapters/brcm_openomci_onu/uni_port.py
new file mode 100644
index 0000000..2ee307b
--- /dev/null
+++ b/python/adapters/brcm_openomci_onu/uni_port.py
@@ -0,0 +1,248 @@
+#
+# Copyright 2018 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import structlog
+from enum import Enum
+from voltha.protos.common_pb2 import OperStatus, AdminState
+from voltha.protos.device_pb2 import Port
+from voltha.protos.openflow_13_pb2 import OFPPF_10GB_FD
+from voltha.core.logical_device_agent import mac_str_to_tuple
+from voltha.protos.logical_device_pb2 import LogicalPort
+from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, OFPPS_LINK_DOWN
+from voltha.protos.openflow_13_pb2 import ofp_port
+
+class UniType(Enum):
+    """
+    UNI Types Defined in G.988
+    """
+    PPTP = 'PhysicalPathTerminationPointEthernet'
+    VEIP = 'VirtualEthernetInterfacePoint'
+    # TODO: Add others as they become supported
+
+
+class UniPort(object):
+    """Wraps southbound-port(s) support for ONU"""
+
+    def __init__(self, handler, name, uni_id, port_no, ofp_port_no,
+                 type=UniType.PPTP):
+        self.log = structlog.get_logger(device_id=handler.device_id,
+                                        port_no=port_no)
+        self._enabled = False
+        self._handler = handler
+        self._name = name
+        self._port = None
+        self._port_number = port_no
+        self._ofp_port_no = ofp_port_no
+        self._logical_port_number = None
+        self._entity_id = None
+        self._mac_bridge_port_num = 0
+        self._type = type
+        self._uni_id = uni_id
+
+        self._admin_state = AdminState.ENABLED
+        self._oper_status = OperStatus.ACTIVE
+
+    def __str__(self):
+        return "UniPort - name: {}, port_number: {}, entity_id: {}, mac_bridge_port_num: {}, type: {}, ofp_port: {}"\
+            .format(self.name, self.port_number, self.entity_id, self._mac_bridge_port_num, self.type, self._ofp_port_no)
+
+    def __repr__(self):
+        return str(self)
+
+    @staticmethod
+    def create(handler, name, uni_id, port_no, ofp_port_no, type):
+        port = UniPort(handler, name, uni_id, port_no, ofp_port_no, type)
+        return port
+
+    def _start(self):
+        self._cancel_deferred()
+        self._admin_state = AdminState.ENABLED
+        self._oper_status = OperStatus.ACTIVE
+        self._update_adapter_agent()
+
+    def _stop(self):
+        self._cancel_deferred()
+        self._admin_state = AdminState.DISABLED
+        self._oper_status = OperStatus.UNKNOWN
+        self._update_adapter_agent()
+
+    def delete(self):
+        self.enabled = False
+        self._handler = None
+
+    def _cancel_deferred(self):
+        pass
+
+    @property
+    def name(self):
+        return self._name
+
+    @property
+    def enabled(self):
+        return self._enabled
+
+    @enabled.setter
+    def enabled(self, value):
+        if self._enabled != value:
+            self._enabled = value
+
+            if value:
+                self._start()
+            else:
+                self._stop()
+
+    @property
+    def uni_id(self):
+        """
+        Physical prt index on ONU 0 - N
+        :return: (int) uni id
+        """
+        return self._uni_id
+
+
+    @property
+    def mac_bridge_port_num(self):
+        """
+        Port number used when creating MacBridgePortConfigurationDataFrame port number
+        :return: (int) port number
+        """
+        return self._mac_bridge_port_num
+
+    @mac_bridge_port_num.setter
+    def mac_bridge_port_num(self, value):
+        self._mac_bridge_port_num = value
+
+    @property
+    def port_number(self):
+        """
+        Physical device port number
+        :return: (int) port number
+        """
+        return self._port_number
+
+    @property
+    def entity_id(self):
+        """
+        OMCI UNI_G entity ID for port
+        """
+        return self._entity_id
+
+    @entity_id.setter
+    def entity_id(self, value):
+        assert self._entity_id is None, 'Cannot reset the Entity ID'
+        self._entity_id = value
+
+    @property
+    def logical_port_number(self):
+        """
+        Logical device port number (used as OpenFlow port for UNI)
+        :return: (int) port number
+        """
+        return self._logical_port_number
+
+    @property
+    def type(self):
+        """
+        UNI Type used in OMCI messaging
+        :return: (UniType) One of the enumerated types
+        """
+        return self._type
+
+    def _update_adapter_agent(self):
+        """
+        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
+
+        try:
+            # adapter_agent add_port also does an update of existing port
+            self._handler.adapter_agent.add_port(self._handler.device_id,
+                                                 self.get_port())
+
+        except Exception as e:
+            self.log.exception('update-port', e=e)
+
+    def get_port(self):
+        """
+        Get the VOLTHA PORT object for this port
+        :return: VOLTHA Port object
+        """
+        self._port = Port(port_no=self.port_number,
+                          label=self.port_id_name(),
+                          type=Port.ETHERNET_UNI,
+                          admin_state=self._admin_state,
+                          oper_status=self._oper_status)
+        return self._port
+
+    def port_id_name(self):
+        return 'uni-{}'.format(self._port_number)
+
+    def add_logical_port(self, openflow_port_no, multi_uni_naming,
+                         capabilities=OFPPF_10GB_FD | OFPPF_FIBER,
+                         speed=OFPPF_10GB_FD):
+
+        self.log.debug('function-entry')
+
+        if self._logical_port_number is not None:
+            # delete old logical port if it exists
+            try:
+                port = self._handler.adapter_agent.get_logical_port(self._handler.logical_device_id,
+                                                           self.port_id_name())
+                self._handler.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
+
+        port_no = openflow_port_no or self._ofp_port_no
+
+        if self._logical_port_number is None and port_no is not None:
+            self._logical_port_number = port_no
+
+            device = self._handler.adapter_agent.get_device(self._handler.device_id)
+
+            # leave the ports down until omci mib download has finished.  otherwise flows push before time
+            openflow_port = ofp_port(
+                port_no=port_no,
+                hw_addr=mac_str_to_tuple('08:%02x:%02x:%02x:%02x:%02x' %
+                                         ((device.parent_port_no >> 8 & 0xff),
+                                          device.parent_port_no & 0xff,
+                                          (port_no >> 16) & 0xff,
+                                          (port_no >> 8) & 0xff,
+                                          port_no & 0xff)),
+                name=device.serial_number + ['', '-' + str(self._mac_bridge_port_num)][multi_uni_naming],
+                config=0,
+                state=OFPPS_LINK_DOWN,
+                curr=capabilities,
+                advertised=capabilities,
+                peer=capabilities,
+                curr_speed=speed,
+                max_speed=speed
+            )
+            self._handler.adapter_agent.add_logical_port(self._handler.logical_device_id,
+                                                         LogicalPort(
+                                                             id=self.port_id_name(),
+                                                             ofp_port=openflow_port,
+                                                             device_id=device.id,
+                                                             device_port_no=self._port_number))
+
+            self.log.debug('logical-port', id=self.port_id_name(), device_port_no=self._port_number, openflow_port=openflow_port)