Stub Implementation of the Microsemi Adaptor.
Change-Id: Ida503793c263cedd3b1eed8a68d32b0ce99de992
diff --git a/voltha/adapters/microsemi/PAS5211.py b/voltha/adapters/microsemi/PAS5211.py
new file mode 100644
index 0000000..01a3b66
--- /dev/null
+++ b/voltha/adapters/microsemi/PAS5211.py
@@ -0,0 +1,113 @@
+#
+# Copyright 2016 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.
+#
+
+
+"""
+PAS5211 scapy structs used for interaction with Ruby
+"""
+from scapy.fields import LEShortField, Field, LEIntField, LESignedIntField, FieldLenField, FieldListField
+from scapy.layers.l2 import Dot3, LLC
+from scapy.packet import Packet, bind_layers, split_layers
+from scapy.utils import lhex
+from scapy.volatile import RandSInt
+from scapy.layers.ntp import XLEShortField
+
+"""
+Extra field structs
+"""
+
+class LESignedShortField(Field):
+ def __init__(self, name, default):
+ Field.__init__(self, name, default, "<h")
+
+class XLESignedIntField(Field):
+ def __init__(self, name, default):
+ Field.__init__(self, name, default, "<i")
+ def randval(self):
+ return RandSInt()
+ def i2repr(self, pkt, x):
+ return lhex(self.i2h(pkt, x))
+
+"""
+PAS5211 Message structs
+"""
+
+class PAS5211Msg(Packet):
+ opcode = "Must be filled by subclass"
+ pass
+
+class PAS5211FrameHeader(Packet):
+ name = "PAS5211FrameHeader"
+ fields_desc = [
+ LEShortField("part", 1),
+ LEShortField("total_parts", 1),
+ LEShortField("size", 0),
+ XLESignedIntField("magic_number", 0x1234ABCD)
+ ]
+
+class PAS5211MsgHeader(Packet):
+ name = "PAS5211MsgHeader"
+ fields_desc = [
+ LEIntField("sequence_number", 0),
+ XLEShortField("opcode", 0),
+ LEShortField("event_type", 0),
+ LESignedShortField("channel_id", -1),
+ LESignedShortField("onu_id", -1),
+ LESignedIntField("onu_session_id", -1)
+ ]
+
+class PAS5211MsgGetOltVersion(PAS5211Msg):
+ opcode = 3
+ name = "PAS5211MsgGetOltVersion"
+ fields_desc = [ ]
+
+ def answers(self, other):
+ return other.name == "PAS5211MsgGetOltVersionResponse"
+
+class PAS5211MsgGetOltVersionResponse(PAS5211Msg):
+ name = "PAS5211MsgGetOltVersionResponse"
+ fields_desc = [
+ LEShortField("major_firmware_version", 0),
+ LEShortField("minor_firmware_version", 0),
+ LEShortField("build_firmware_version", 0),
+ LEShortField("maintenance_firmware_version", 0),
+ LEShortField("major_hardware_version", 0),
+ LEShortField("minor_hardware_version", 0),
+ LEIntField("system_port_mac_type", 0),
+ FieldLenField("channels_supported", 0, fmt="<H"),
+ LEShortField("onus_supported_per_channel", 0),
+ LEShortField("ports_supported_per_channel", 0),
+ LEShortField("alloc_ids_supported_per_channel", 0),
+ FieldListField("critical_events_counter", [0, 0, 0, 0],
+ LEIntField("entry", 0),
+ count_from=lambda pkt: pkt.channels_supported),
+ FieldListField("non_critical_events_counter", [0, 0, 0, 0],
+ LEIntField("entry", 0),
+ count_from=lambda pkt: pkt.channels_supported)
+ ]
+
+ # FIXME: find a better way to pair messages together.
+ def answers(self, other):
+ return other.name == "PAS5211MsgGetOltVersion"
+
+"""
+Bindings used for message processing
+"""
+
+split_layers(Dot3, LLC)
+bind_layers(Dot3,PAS5211FrameHeader)
+bind_layers(PAS5211FrameHeader, PAS5211MsgHeader)
+bind_layers(PAS5211MsgHeader, PAS5211MsgGetOltVersionResponse, opcode=0x3800 | 3)
\ No newline at end of file
diff --git a/voltha/adapters/microsemi/PAS5211_comm.py b/voltha/adapters/microsemi/PAS5211_comm.py
new file mode 100644
index 0000000..a9fec63
--- /dev/null
+++ b/voltha/adapters/microsemi/PAS5211_comm.py
@@ -0,0 +1,72 @@
+#
+# Copyright 2016 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 netifaces
+from scapy.layers.l2 import Dot3
+from scapy.sendrecv import srp1
+import structlog
+from voltha.adapters.microsemi.PAS5211 import PAS5211Msg, PAS5211MsgHeader, PAS5211FrameHeader
+
+log = structlog.get_logger()
+
+
+def constructPAS5211Frames(msg, seq, src_mac, dst_mac, channel_id=-1,
+ onu_id=-1, onu_session_id=-1):
+
+ assert isinstance(msg, PAS5211Msg)
+ opcode = 0x3000 | msg.opcode
+
+ inner_msg = PAS5211MsgHeader(
+ sequence_number=seq,
+ opcode=opcode,
+ channel_id=channel_id,
+ onu_id=onu_id,
+ onu_session_id=onu_session_id
+ ) / msg
+
+ size = len(inner_msg)
+ frame_body = PAS5211FrameHeader(size=size) / inner_msg
+ frame = Dot3(src=src_mac, dst=dst_mac) / frame_body
+
+ return frame
+
+
+def sequence_generator(init):
+ num = init
+ while True:
+ yield num
+ num += 1
+
+
+def determine_src_mac(iface):
+ if iface in netifaces.interfaces():
+ return netifaces.ifaddresses(iface)[netifaces.AF_LINK][0]['addr']
+ return None
+
+
+class PAS5211Communication(object):
+ def __init__(self, dst_mac, init = 0, iface = None):
+ self.iface = iface
+ self.dst_mac = dst_mac
+ self.seqgen = sequence_generator(init)
+ self.src_mac = determine_src_mac(self.iface)
+
+ def communicate(self, msg, **kwargs):
+ if self.src_mac is not None:
+ frame = constructPAS5211Frames(msg, self.seqgen.next(), self.src_mac,
+ self.dst_mac, **kwargs)
+ return srp1(frame, timeout=2, iface=self.iface)
+ else:
+ log.info('Unknown src mac for {}'.format(self.iface))
diff --git a/voltha/adapters/microsemi/PAS5211_constants.py b/voltha/adapters/microsemi/PAS5211_constants.py
new file mode 100644
index 0000000..d1d6846
--- /dev/null
+++ b/voltha/adapters/microsemi/PAS5211_constants.py
@@ -0,0 +1,180 @@
+#
+# Copyright 2016 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.
+#
+
+"""
+PAS5211 Constants
+"""
+
+# from enum PON_true_false_t
+PON_FALSE = 0
+PON_TRUE = 1
+
+# from enum PON_enable_disable_t
+PON_DISABLE = 0
+PON_ENABLE = 1
+
+# from enym PON_mac_t
+PON_MII = 0
+PON_GMII = 1
+PON_TBI = 2
+
+PON_POLARITY_ACTIVE_LOW = 0
+PON_POLARITY_ACTIVE_HIGH = 1
+
+PON_OPTICS_VOLTAGE_IF_UNDEFINED = 0
+PON_OPTICS_VOLTAGE_IF_CML = 1
+PON_OPTICS_VOLTAGE_IF_LVPECL = 2
+
+PON_SD_SOURCE_LASER_SD = 0
+PON_SD_SOURCE_BCDR_LOCK = 1
+PON_SD_SOURCE_BCDR_SD = 2
+
+PON_RESET_TYPE_DELAY_BASED = 0
+PON_RESET_TYPE_SINGLE_RESET = 1
+PON_RESET_TYPE_DOUBLE_RESET = 2
+
+PON_RESET_TYPE_NORMAL_START_BURST_BASED = 0
+PON_RESET_TYPE_NORMAL_END_BURST_BASED = 1
+
+PON_GPIO_LINE_0 = 0
+PON_GPIO_LINE_1 = 1
+PON_GPIO_LINE_2 = 2
+PON_GPIO_LINE_3 = 3
+PON_GPIO_LINE_4 = 4
+PON_GPIO_LINE_5 = 5
+PON_GPIO_LINE_6 = 6
+PON_GPIO_LINE_7 = 7
+def PON_EXT_GPIO_LINE(line):
+ return line + 8
+
+# from enum PON_alarm_t
+PON_ALARM_SOFTWARE_ERROR = 0
+PON_ALARM_LOS = 1
+PON_ALARM_LOSI = 2
+PON_ALARM_DOWI = 3
+PON_ALARM_LOFI = 4
+PON_ALARM_RDII = 5
+PON_ALARM_LOAMI = 6
+PON_ALARM_LCDGI = 7
+PON_ALARM_LOAI = 8
+PON_ALARM_SDI = 9
+PON_ALARM_SFI = 10
+PON_ALARM_PEE = 11
+PON_ALARM_DGI = 12
+PON_ALARM_LOKI = 13
+PON_ALARM_TIWI = 14
+PON_ALARM_TIA = 15
+PON_ALARM_VIRTUAL_SCOPE_ONU_LASER_ALWAYS_ON = 16
+PON_ALARM_VIRTUAL_SCOPE_ONU_SIGNAL_DEGRADATION = 17
+PON_ALARM_VIRTUAL_SCOPE_ONU_EOL = 18
+PON_ALARM_VIRTUAL_SCOPE_ONU_EOL_DATABASE_IS_FULL = 19
+PON_ALARM_AUTH_FAILED_IN_REGISTRATION_ID_MODE = 20
+PON_ALARM_SUFI = 21
+PON_ALARM_LAST_ALARM = 22
+
+# from enum PON_general_parameters_type_t
+PON_COMBINED_LOSI_LOFI = 1000
+PON_TX_ENABLE_DEFAULT = 1001
+
+# Enable or disable False queue full event from DBA
+PON_FALSE_Q_FULL_EVENT_MODE = 1002
+
+# Set PID_AID_MISMATCH min silence period. 0 - disable, Else - period in secs
+PON_PID_AID_MISMATCH_MIN_SILENCE_PERIOD = 1003
+
+# Set if FW generate clear alarm. 0 - generate clear alarm, Else - don't
+# generate clear alarm
+PON_ENABLE_CLEAR_ALARM = 1004
+
+# Enable or disabl send assign alloc id ploam. 0 - disable, 1 - enable
+PON_ASSIGN_ALLOC_ID_PLOAM = 1005
+
+# BIP error polling period, 200 - 65000, 0 - Disabled, Recommended: 5000
+# (default)
+PON_BIP_ERR_POLLING_PERIOD_MS = 1006
+
+# Ignore SN when decatived 0 - consider SN (deactivate the onu if received
+# same SN when activated (default) 1 - Ignore
+PON_IGNORE_SN_WHEN_ACTIVE = 1007
+
+# 0xffffffff - Disabled (default). Any other value (0 - 0xfffe) indicates
+# that PA delay is enabled, with the specified delay value and included in
+# the US_OVERHEAD PLOAM
+PON_ONU_PRE_ASSIGNED_DELAY = 1008
+
+# Enable or disable DS fragmentation, 0 disable, 1 enable
+PON_DS_FRAGMENTATION = 1009
+
+# Set if fw report rei alarm when errors is 0, 0 disable (default), 1 enable
+PON_REI_ERRORS_REPORT_ALL = 1010
+
+# Set if igonre sfi deactivation, 0 disable (default), 1 enable
+PON_IGNORE_SFI_DEACTIVATION = 1011
+
+# Allows to override the allocation overhead set by optic-params
+# configuration. This configuration is only allowed when the the pon channel
+# is disabled
+PON_OVERRIDE_ALLOCATION_OVERHEAD = 1012
+
+# Optics timeline offset, -128-127, : this parameter is very sensitive and
+# requires coordination with PMC
+PON_OPTICS_TIMELINE_OFFSET = 1013
+
+# Last general meter
+PON_LAST_GENERAL_PARAMETER = PON_OPTICS_TIMELINE_OFFSET
+
+# from enum PON_dba_mode_t
+PON_DBA_MODE_NOT_LOADED = 0
+PON_DBA_MODE_LOADED_NOT_RUNNING = 1
+PON_DBA_MODE_RUNNING = 2
+PON_DBA_MODE_LAST = 3
+
+# from enum type typedef enum PON_port_frame_destination_t
+PON_PORT_PON = 0
+PON_PORT_SYSTEM = 1
+
+# from enum PON_olt_hw_classification_t
+
+PON_OLT_HW_CLASSIFICATION_PAUSE = 0
+PON_OLT_HW_CLASSIFICATION_LINK_CONSTRAINT = 1
+PON_OLT_HW_CLASSIFICATION_IGMP = 2
+PON_OLT_HW_CLASSIFICATION_MPCP = 3
+PON_OLT_HW_CLASSIFICATION_OAM = 4
+PON_OLT_HW_CLASSIFICATION_802_1X = 5
+PON_OLT_HW_CLASSIFICATION_PPPOE_DISCOVERY = 6
+PON_OLT_HW_CLASSIFICATION_PPPOE_SESSION = 7
+PON_OLT_HW_CLASSIFICATION_DHCP_V4 = 8
+PON_OLT_HW_CLASSIFICATION_PIM = 9
+PON_OLT_HW_CLASSIFICATION_DHCP_V6 = 10
+PON_OLT_HW_CLASSIFICATION_ICMP_V4 = 11
+PON_OLT_HW_CLASSIFICATION_MLD = 12
+PON_OLT_HW_CLASSIFICATION_ARP = 13
+PON_OLT_HW_CLASSIFICATION_CONF_DA = 14
+PON_OLT_HW_CLASSIFICATION_CONF_RULE = 15
+PON_OLT_HW_CLASSIFICATION_DA_EQ_SA = 16
+PON_OLT_HW_CLASSIFICATION_DA_EQ_MAC = 17
+PON_OLT_HW_CLASSIFICATION_DA_EQ_SEC_MAC = 18
+PON_OLT_HW_CLASSIFICATION_SA_EQ_MAC = 19
+PON_OLT_HW_CLASSIFICATION_SA_EQ_SEC_MAC = 20
+PON_OLT_HW_CLASSIFICATION_ETHERNET_MANAGEMENT = 100
+PON_OLT_HW_CLASSIFICATION_IPV4_LOCAL_MULTICAST = 101
+PON_OLT_HW_CLASSIFICATION_IPV4_MANAGEMENT = 102
+PON_OLT_HW_CLASSIFICATION_ALL_IPV4_MULTICAST = 103
+PON_OLT_HW_CLASSIFICATION_IPV6_LOCAL_MULTICAST = 104
+PON_OLT_HW_CLASSIFICATION_IPV6_MANAGEMENT = 105
+PON_OLT_HW_CLASSIFICATION_ALL_IPV6_MULTICAST = 106
+PON_OLT_HW_CLASSIFICATION_OTHER = 107
+PON_OLT_HW_CLASSIFICATION_LAST_RULE = 108
\ No newline at end of file
diff --git a/voltha/adapters/microsemi/RubyAdapter.py b/voltha/adapters/microsemi/RubyAdapter.py
new file mode 100644
index 0000000..93c5b07
--- /dev/null
+++ b/voltha/adapters/microsemi/RubyAdapter.py
@@ -0,0 +1,83 @@
+#
+# Copyright 2016 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.
+#
+
+"""
+Microsemi/Celestica Ruby vOLTHA adapter.
+"""
+import structlog
+from voltha.adapters.interface import IAdapterInterface
+from voltha.adapters.microsemi.PAS5211 import PAS5211MsgGetOltVersion
+from voltha.adapters.microsemi.PAS5211_comm import PAS5211Communication
+#from voltha.protos.adapter_pb2 import Adapter, AdapterConfig, DeviceTypes
+#from voltha.protos.health_pb2 import HealthStatus
+from zope.interface import implementer
+
+log = structlog.get_logger()
+
+olt_conf = { 'olts' : { 'id' : 0, 'mac' : '00:0c:d5:00:01:00'}, 'iface' : 'eth3'}
+
+@implementer(IAdapterInterface)
+class RubyAdapter(object):
+ def __init__(self, config):
+ self.config = config
+# self.descriptor = Adapter(
+# id='ruby',
+# config=AdapterConfig()
+# # TODO
+# )
+
+ def start(self):
+ log.debug('starting')
+ self.init_olt()
+ log.info('started')
+
+ def stop(self):
+ log.debug('stopping')
+ log.info('stopped')
+
+ def adapter_descriptor(self):
+ return self.descriptor
+
+ def device_types(self):
+ pass
+# return DeviceTypes(
+# items=[] # TODO
+# )
+
+ def health(self):
+ pass
+# return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
+
+ def change_master_state(self, master):
+ raise NotImplementedError()
+
+ def adopt_device(self, device):
+ raise NotImplementedError()
+
+ def abandon_device(self, device):
+ raise NotImplementedError(0)
+
+ def deactivate_device(self, device):
+ raise NotImplementedError()
+
+ def init_olt(self):
+ comm = PAS5211Communication(dst_mac=olt_conf['olts']['mac'], iface=olt_conf['iface'])
+ packet = comm.communicate(PAS5211MsgGetOltVersion())
+ log.info('{}'.format(packet.show()))
+
+
+if __name__ == '__main__':
+ RubyAdapter(None).start()
\ No newline at end of file
diff --git a/voltha/adapters/microsemi/chat.py b/voltha/adapters/microsemi/chat.py
index 80b026b..945533b 100755
--- a/voltha/adapters/microsemi/chat.py
+++ b/voltha/adapters/microsemi/chat.py
@@ -8,7 +8,7 @@
from scapy.fields import Field, lhex, MACField, LenField, LEShortField, \
LEIntField, LESignedIntField, FieldLenField, FieldListField, PacketField, \
ByteField, StrField, ConditionalField, StrFixedLenField
-from scapy.layers.l2 import DestMACField, ETHER_ANY, ETH_P_ALL, sniff, sendp
+from scapy.layers.l2 import DestMACField, ETHER_ANY, ETH_P_ALL, sniff, sendp, LLC, SNAP, Dot3
from scapy.layers.ntp import XLEShortField
from scapy.packet import Packet, bind_layers
from scapy.volatile import RandSInt
@@ -580,7 +580,7 @@
# bindings for messages received
-bind_layers(PAS5211Dot3, PAS5211FrameHeader)
+bind_layers(Dot3,PAS5211FrameHeader)
bind_layers(PAS5211FrameHeader, PAS5211MsgHeader)
bind_layers(PAS5211MsgHeader, PAS5211MsgGetProtocolVersionResponse, opcode=0x2800 | 2)
bind_layers(PAS5211MsgHeader, PAS5211MsgGetOltVersionResponse, opcode=0x3800 | 3)
diff --git a/voltha/adapters/microsemi/send.py b/voltha/adapters/microsemi/send.py
index 8697ae7..a639aaa 100644
--- a/voltha/adapters/microsemi/send.py
+++ b/voltha/adapters/microsemi/send.py
@@ -1,4 +1,5 @@
from scapy.all import *
+from scapy.layers.l2 import Dot3
MIN_FRAME_SIZE = 60