VOL-1398: Adtran-ONU - Initial containerization commit
Change-Id: I7afcc1ad65b9ef80da994b0b0ddf74860911bb46
diff --git a/adapters/adtran_onu/uni_port.py b/adapters/adtran_onu/uni_port.py
new file mode 100644
index 0000000..96cd353
--- /dev/null
+++ b/adapters/adtran_onu/uni_port.py
@@ -0,0 +1,227 @@
+# Copyright 2017-present Adtran, Inc.
+#
+# 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 pyvoltha.protos.common_pb2 import OperStatus, AdminState
+from pyvoltha.protos.device_pb2 import Port
+from pyvoltha.protos.openflow_13_pb2 import OFPPF_10GB_FD
+from pyvoltha.protos.logical_device_pb2 import LogicalPort
+from pyvoltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER
+from pyvoltha.protos.openflow_13_pb2 import ofp_port
+import adtran_olt.resources.adtranolt_platform as platform
+
+
+class UniPort(object):
+ """Wraps southbound-port(s) support for ONU"""
+ def __init__(self, handler, name, port_no, ofp_port_no):
+ self.log = structlog.get_logger(device_id=handler.device_id, port_no=port_no)
+ self._enabled = False
+ self._handler = handler
+ self._name = name
+ self.uni_id = platform.uni_id_from_uni_port(port_no)
+ self._port = None
+ self._port_number = port_no
+ self._ofp_port_no = ofp_port_no # Set at by creator (vENET create)
+ self._logical_port_number = None # Set at time of logical port creation
+ self._entity_id = None # TODO: Use port number from UNI-G entity ID
+ self._mac_bridge_port_num = 0
+
+ self._admin_state = AdminState.ENABLED
+ self._oper_status = OperStatus.ACTIVE
+ # TODO Add state, stats, alarm reference, ...
+ pass
+
+ def __str__(self):
+ return "UniPort: {}:{}".format(self.name, self.port_number)
+
+ @staticmethod
+ def create(handler, name, port_no, ofp_port_no):
+ port = UniPort(handler, name, port_no, ofp_port_no)
+ return port
+
+ def _start(self):
+ self._cancel_deferred()
+
+ self._admin_state = AdminState.ENABLED
+ self._oper_status = OperStatus.ACTIVE
+ self._update_adapter_agent()
+ # TODO: start h/w sync
+ # TODO: Enable the actual physical port?
+ pass
+
+ def _stop(self):
+ self._cancel_deferred()
+
+ self._admin_state = AdminState.DISABLED
+ self._oper_status = OperStatus.UNKNOWN
+ self._update_adapter_agent()
+ # TODO: Disable/power-down the actual physical port?
+ pass
+
+ 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 port_number(self):
+ """
+ Physical device port number
+ :return: (int) port number
+ """
+ return self._port_number
+
+ @property
+ def mac_bridge_port_num(self):
+ """
+ Port number used when creating MacBridgePortConfigurationDataFrame port number
+ :return: (int) port number
+ """
+ self.log.debug('function-entry')
+ return self._mac_bridge_port_num
+
+ @mac_bridge_port_num.setter
+ def mac_bridge_port_num(self, value):
+ self.log.debug('function-entry')
+ self._mac_bridge_port_num = value
+
+ @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
+
+ 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 KeyError: # Expected exception during ONU disabling
+ pass
+ except Exception as e: # Expected exception during ONU disabling
+ self.log.exception('update-port', e=e)
+
+ def get_port(self):
+ """
+ Get the VOLTHA PORT object for this port
+ :return: VOLTHA Port object
+ """
+ if self._port is None:
+ 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):
+
+ 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
+
+ # Use vENET provisioned values if none supplied
+ 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)
+
+ def mac_str_to_tuple(mac):
+ """
+ Convert 'xx:xx:xx:xx:xx:xx' MAC address string to a tuple of integers.
+ Example: mac_str_to_tuple('00:01:02:03:04:05') == (0, 1, 2, 3, 4, 5)
+ """
+ return tuple(int(d, 16) for d in mac.split(':'))
+
+ openflow_port = ofp_port(
+ port_no=port_no,
+ hw_addr=mac_str_to_tuple('08:00:%02x:%02x:%02x:%02x' %
+ ((device.parent_port_no >> 8 & 0xff),
+ device.parent_port_no & 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_LIVE,
+ 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))