blob: 50aada149c91a87fe7680f40e2dee2a5ab00136f [file] [log] [blame]
#
# Copyright 2017 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.
#
"""
PMC Sierra ONU adapter
"""
import structlog
from twisted.internet import reactor
from twisted.internet.defer import DeferredQueue, inlineCallbacks
from zope.interface import implementer
from voltha.adapters.interface import IAdapterInterface
from voltha.adapters.microsemi_olt.DeviceManager import mac_str_to_tuple
from voltha.adapters.microsemi_olt.PAS5211 import PAS5211GetOnuAllocs, PAS5211GetOnuAllocsResponse, PAS5211GetSnInfo, \
PAS5211GetSnInfoResponse, PAS5211GetOnusRange, PAS5211GetOnusRangeResponse
from voltha.extensions.omci.omci_frame import OmciFrame
from voltha.protos import third_party
from voltha.protos.adapter_pb2 import Adapter
from voltha.protos.adapter_pb2 import AdapterConfig
from voltha.protos.common_pb2 import LogLevel, ConnectStatus, AdminState, OperStatus
from voltha.protos.device_pb2 import DeviceType, DeviceTypes, Port
from voltha.protos.health_pb2 import HealthStatus
from voltha.protos.logical_device_pb2 import LogicalPort
from voltha.protos.openflow_13_pb2 import OFPPF_1GB_FD, OFPPF_FIBER, ofp_port, OFPPS_LIVE
from voltha.extensions.omci.omci_messages import OmciGet, OmciGetResponse, OmciCreate, OmciMibResetResponse, OmciSet, \
OmciSetResponse, OmciCreateResponse, OmciMibReset
_ = third_party
log = structlog.get_logger()
def sequence_generator(init):
num = init
while True:
yield num
num += 1
@implementer(IAdapterInterface)
class PmcsOnu(object):
name = 'pmcs_onu'
supported_device_types = [
DeviceType(
id=name,
adapter=name,
accepts_bulk_flow_update=True
)
]
def __init__(self, adapter_agent, config):
self.adapter_agent = adapter_agent
self.config = config
self.descriptor = Adapter(
id=self.name,
vendor='PMCS',
version='0.1',
config=AdapterConfig(log_level=LogLevel.INFO)
)
self.incoming_messages = DeferredQueue()
self.trangen = sequence_generator(1)
def start(self):
log.debug('starting')
log.info('started')
def stop(self):
log.debug('stopping')
log.info('stopped')
def adapter_descriptor(self):
return self.descriptor
def device_types(self):
return DeviceTypes(items=self.supported_device_types)
def health(self):
return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
def change_master_state(self, master):
raise NotImplementedError()
def adopt_device(self, device):
log.info('adopt-device', device=device)
reactor.callLater(0.1, self._onu_device_activation, device)
return device
def abandon_device(self, device):
raise NotImplementedError()
def disable_device(self, device):
raise NotImplementedError()
def reenable_device(self, device):
raise NotImplementedError()
def reboot_device(self, device):
raise NotImplementedError()
def delete_device(self, device):
raise NotImplementedError()
def get_device_details(self, device):
raise NotImplementedError()
def deactivate_device(self, device):
raise NotImplementedError()
def update_pm_config(self, device, pm_configs):
raise NotImplementedError()
def update_flows_bulk(self, device, flows, groups):
log.info('bulk-flow-update', device_id=device.id,
flows=flows, groups=groups)
def update_flows_incrementally(self, device, flow_changes, group_changes):
raise NotImplementedError()
def send_proxied_message(self, proxy_address, msg):
log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)
def receive_proxied_message(self, proxy_address, msg):
log.info('receive-proxied-message', proxy_address=proxy_address,
device_id=proxy_address.device_id)
self.incoming_messages.put(msg)
def receive_packet_out(self, logical_device_id, egress_port_no, msg):
log.info('packet-out', logical_device_id=logical_device_id,
egress_port_no=egress_port_no, msg_len=len(msg))
def receive_inter_adapter_message(self, msg):
raise NotImplementedError()
@inlineCallbacks
def _onu_device_activation(self, device):
# first we verify that we got parent reference and proxy info
assert device.parent_id
assert device.proxy_address.device_id
assert device.proxy_address.channel_id == 0
device.model = 'GPON ONU'
device.hardware_version = 'tbd'
device.firmware_version = 'tbd'
device.software_version = 'tbd'
device.connect_status = ConnectStatus.REACHABLE
self.adapter_agent.update_device(device)
uni_port = Port(port_no=1000, # FIXME It becomes the alloc_id
label="{} ONU".format('PMCS'),
type=Port.ETHERNET_UNI,
admin_state=AdminState.ENABLED,
oper_status=OperStatus.ACTIVE
)
self.adapter_agent.add_port(device.id, uni_port)
pon_port = Port(
port_no=1,
label='PON port',
type=Port.PON_ONU,
admin_state=AdminState.ENABLED,
oper_status=OperStatus.ACTIVE,
peers=[
Port.PeerPort(
device_id=device.parent_id,
port_no=device.parent_port_no
)
]
)
self.adapter_agent.add_port(device.id, pon_port)
# obtain logical device id
parent_device = self.adapter_agent.get_device(device.parent_id)
logical_device_id = parent_device.parent_id
assert logical_device_id
# we are going to use the proxy_address.channel_id as unique number
# and name for the virtual ports, as this is guaranteed to be unique
# in the context of the OLT port, so it is also unique in the context
# of the logical device
port_no = device.proxy_address.channel_id # FIXME this may need to be fixed
cap = OFPPF_1GB_FD | OFPPF_FIBER
self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
id=str(port_no),
ofp_port=ofp_port(
port_no=port_no,
hw_addr=mac_str_to_tuple(device.serial_number)[2:8],
name='uni-{}'.format(port_no),
config=0,
state=OFPPS_LIVE,
curr=cap,
advertised=cap,
peer=cap,
curr_speed=OFPPF_1GB_FD,
max_speed=OFPPF_1GB_FD
),
device_id=device.id,
device_port_no=uni_port.port_no
))
yield self._initialize_onu(device)
# and finally update to "ACTIVE"
device = self.adapter_agent.get_device(device.id)
device.oper_status = OperStatus.ACTIVE
self.adapter_agent.update_device(device)
@inlineCallbacks
def _initialize_onu(self, device):
device = self.adapter_agent.get_device(device.id)
self.adapter_agent.register_for_proxied_messages(device.proxy_address)
log.debug("INIT", device=device)
# DO things to the ONU
# |###[ OmciFrame ]###
# | transaction_id= 1
# | message_type= 79
# | omci = 10
# | \omci_message\
# | |###[ OmciMibReset ]###
# | | entity_class= 2
# | | entity_id = 0
# | omci_trailer= 40
# OmciMibReset
msg = OmciMibReset(entity_class = 2, entity_id = 0)
frame = OmciFrame(transaction_id=self.trangen.next(),
message_type=OmciMibReset.message_id,
omci_message=msg)
self.adapter_agent.send_proxied_message(device.proxy_address, frame)
response = yield self.incoming_messages.get()
if OmciMibResetResponse not in response:
log.error("Failed to perform a MIB reset for {}".format(device.proxy_address))
return
# ###[ PAS5211Dot3 ]###
# dst = 00:0c:d5:00:01:00
# src = 90:e2:ba:82:f9:77
# len = 22
# ###[ PAS5211FrameHeader ]###
# part = 1
# total_parts= 1
# size = 16
# magic_number= 0x1234abcd
# ###[ PAS5211MsgHeader ]###
# sequence_number= 51
# opcode = 0x3009
# event_type= 0
# channel_id= 0
# onu_id = 0
# onu_session_id= 1
# ###[ PAS5211GetOnuAllocs ]###
# nothing = 0
# ###[ Raw ]###
# load = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
msg = PAS5211GetOnuAllocs()
self.adapter_agent.send_proxied_message(device.proxy_address, msg)
response = yield self.incoming_messages.get()
if PAS5211GetOnuAllocsResponse not in response:
log.error("Failed to get alloc ids for {}".format(device.proxy_address))
return
# ###[ PAS5211Dot3 ]###
# dst = 00:0c:d5:00:01:00
# src = 90:e2:ba:82:f9:77
# len = 30
# ###[ PAS5211FrameHeader ]###
# part = 1
# total_parts= 1
# size = 24
# magic_number= 0x1234abcd
# ###[ PAS5211MsgHeader ]###
# sequence_number= 52
# opcode = 0x3007
# event_type= 0
# channel_id= 0
# onu_id = -1
# onu_session_id= -1
# ###[ PAS5211GetSnInfo ]###
# serial_number= 'PMCS\xd5b\x84\xac'
# ###[ Raw ]###
# load = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
msg = PAS5211GetSnInfo(serial_number=device.serial_number)
self.adapter_agent.send_proxied_message(device.proxy_address, msg)
response = yield self.incoming_messages.get()
if PAS5211GetSnInfoResponse not in response:
log.error("Failed to get serial number info for {}".format(device.proxy_address))
return
# ###[ PAS5211Dot3 ]###
# dst = 00:0c:d5:00:01:00
# src = 90:e2:ba:82:f9:77
# len = 22
# ###[ PAS5211FrameHeader ]###
# part = 1
# total_parts= 1
# size = 16
# magic_number= 0x1234abcd
# ###[ PAS5211MsgHeader ]###
# sequence_number= 53
# opcode = 0x3074
# event_type= 0
# channel_id= 0
# onu_id = -1
# onu_session_id= -1
# ###[ PAS5211GetOnusRange ]###
# nothing = 0
# ###[ Raw ]###
# load = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
msg = PAS5211GetOnusRange()
self.adapter_agent.send_proxied_message(device.proxy_address, msg)
response = yield self.incoming_messages.get()
if PAS5211GetOnusRangeResponse not in response:
log.error("Failed to get ONU Range for {}".format(device.proxy_address))
return
# | ###[ OmciFrame ]###
# | transaction_id = 2
# | message_type = 72
# | omci = 10
# | \omci_message \
# | | ###[ OmciSet ]###
# | | entity_class = 262
# | | entity_id = 32769
# | | attributes_mask = 32768
# | | data = {'alloc_id': 1000}
# | omci_trailer = 40
# OmciSet
# TODO: maskdata
msg = OmciSet(entity_class = 262, entity_id = 32769, attributes_mask = 32768,
data=dict(
alloc_id = 1000
))
frame = OmciFrame(transaction_id=self.trangen.next(),
message_type=OmciSet.message_id,
omci_message=msg)
self.adapter_agent.send_proxied_message(device.proxy_address, frame)
response = yield self.incoming_messages.get()
if OmciSetResponse not in response:
log.error("Failed to set alloc id for {}".format(device.proxy_address))
return
# length = 44
# port_type = 0
# port_id = 0
# management_frame = 1
# \frame \
# | ###[ OmciFrame ]###
# | transaction_id = 3
# | message_type = 68
# | omci = 10
# | \omci_message \
# | | ###[ OmciCreate ]###
# | | entity_class = 45
# | | entity_id = 1
# | | data = {'max_age': 5120, 'hello_time': 512, 'priority': 32768, 'port_bridging_ind': 0,
# 'spanning_tree_ind': 0, 'unknown_mac_address_discard': 0, 'mac_learning_depth': 128,
# 'learning_ind': 0, 'forward_delay': 3840}
# | | ###[ Raw ]###
# | | load = '\x00\x00\x00\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
# | omci_trailer = 40
# Found in method: pmc_omci_mac_bridge_sp_me_create from: PMC_OFAL.c
# Params
# - priority: The bridge priority set on the LAN card
# - max_age: The maximum age for an entry in the spanning tree listing
# - hello_time: The time interval between hello packets
# - forward_delay: The time that the bridge on the Ethernet card in the ONT retains a packet before forwarding it
# - unknown_mac_address_discard: frames with unknown destination addresses will be forwarded to all allowed ports
msg = OmciCreate(entity_class=45, entity_id=1,
data=dict(
max_age=5120,
hello_time=512,
priority=32768,
port_bridging_ind=PON_FALSE,
spanning_tree_ind=PON_FALSE,
unknown_mac_address_discard=0,
mac_learning_depth=128,
learning_ind=PON_FALSE,
forward_delay=3840
))
frame = OmciFrame(transaction_id=self.trangen.next(),
message_type=OmciCreate.message_id,
omci_message=msg)
self.adapter_agent.send_proxied_message(device.proxy_address, frame)
response = yield self.incoming_messages.get()
if OmciCreateResponse not in response:
log.error("Failed to set parameter on {}".format(device.proxy_address))
return
# |###[ OmciFrame ]###
# | transaction_id= 4
# | message_type= 68
# | omci = 10
# | \omci_message\
# | |###[ OmciCreate ]###
# | | entity_class= 47
# | | entity_id = 0
# | | data = {'tp_pointer': 257, 'encapsulation_methods': 1, 'port_num': 0, 'port_priority': 10, 'tp_type': 1, 'port_path_cost': 100, 'port_spanning_tree_in': 0, 'lan_fcs_ind': 0, 'bridge_id_pointer': 1}
# | omci_trailer= 40
# Found in method: pmc_omci_mac_bridge_pcd_me_create from: PMC_OFAL.c
# Params
# - port_path_cost: The cost contribution of the port to the path cost towards the spanning tree root bridge
# - bridge_id_pointer: MAC bridge controlling the port
msg = OmciCreate(entity_class=47, entity_id=0,
data=dict(
tp_pointer=257,
encapsulation_methods=OMCI_MAC_BRIDGE_PCD_ENCAP_METHOD_LLC,
port_num=0,
port_priority=10,
tp_type=1,
port_path_cost=100,
port_spanning_tree_in=PON_FALSE,
lan_fcs_ind=OMCI_MAC_BRIDGE_PCD_LANFCS_FORWARDED,
bridge_id_pointer=1
))
frame = OmciFrame(transaction_id=self.trangen.next(),
message_type=OmciCreate.message_id,
omci_message=msg)
self.adapter_agent.send_proxied_message(device.proxy_address, frame)
response = yield self.incoming_messages.get()
if OmciCreateResponse not in response:
log.error("Failed to set info for {}".format(device.proxy_address))
return
# |###[ OmciFrame ]###
# | transaction_id= 5
# | message_type= 68
# | omci = 10
# | \omci_message\
# | |###[ OmciCreate ]###
# | | entity_class= 171
# | | entity_id = 0
# | | data = {'association_type': 2, 'associated_me_pointer': 257}
# | omci_trailer= 40
# Found in method: pmc_omci_evto_create from: PMC_OFAL.c
msg = OmciCreate(entity_class=171, entity_id=0,
data=dict(
association_type=OMCI_EX_VLAN_TAG_OCD_ASSOCIATION_TYPE_PPTP_ETH_UNI,
associated_me_pointer=257
))
frame = OmciFrame(transaction_id=self.trangen.next(),
message_type=OmciCreate.message_id,
omci_message=msg)
self.adapter_agent.send_proxied_message(device.proxy_address, frame)
response = yield self.incoming_messages.get()
if OmciCreateResponse not in response:
log.error("Failed to set association info for {}".format(device.proxy_address))
return
# |###[ OmciFrame ]###
# | transaction_id= 6
# | message_type= 72
# | omci = 10
# | \omci_message\
# | |###[ OmciSet ]###
# | | entity_class= 171
# | | entity_id = 0
# | | attributes_mask= 47616
# | | data = {'association_type': 2, 'input_tpid': 33024, 'associated_me_pointer': 257, 'downstream_mode': 0, 'output_tpid': 33024}
# | omci_trailer= 40
# Found in method: pmc_omci_evto_set from: PMC_OFAL.c
msg = OmciSet(entity_class=171, entity_id=0, attributes_mask=47616,
data=dict(
association_type=OMCI_EX_VLAN_TAG_OCD_ASSOCIATION_TYPE_PPTP_ETH_UNI,
input_tpid=33024,
associated_me_pointer=257,
downstream_mode=OMCI_EX_VLAN_TAG_OCD_DS_MODE_US_INVERSE,
output_tpid=33024
))
frame = OmciFrame(transaction_id=self.trangen.next(),
message_type=OmciSet.message_id,
omci_message=msg)
self.adapter_agent.send_proxied_message(device.proxy_address, frame)
response = yield self.incoming_messages.get()
if OmciSetResponse not in response:
log.error("Failed to set association tpid info for {}".format(device.proxy_address))
return
# |###[ OmciFrame ]###
# | transaction_id= 7
# | message_type= 68
# | omci = 10
# | \omci_message\
# | |###[ OmciCreate ]###
# | | entity_class= 130
# | | entity_id = 1
# | | data = {'tp_pointer': 65535, 'unmarked_frame_option': 1, 'interwork_tp_pointer_for_p_bit_priority_6': 65535,
# 'interwork_tp_pointer_for_p_bit_priority_7': 65535, 'interwork_tp_pointer_for_p_bit_priority_4': 65535,
# 'interwork_tp_pointer_for_p_bit_priority_5': 65535, 'interwork_tp_pointer_for_p_bit_priority_2': 65535,
# 'interwork_tp_pointer_for_p_bit_priority_3': 65535, 'interwork_tp_pointer_for_p_bit_priority_0': 65535,
# 'interwork_tp_pointer_for_p_bit_priority_1': 65535, 'tp_type': 0, 'default_p_bit_marking': 0}
# | omci_trailer= 40
# Found in method: pmc_omci_8021p_msp_me_create from: PMC_OFAL.c
msg = OmciCreate(entity_class=130, entity_id=1,
data=dict(
tp_pointer=65535,
unmarked_frame_option=OMCI_8021P_MSP_UNMARKED_FRAME_TAG_FRAME,
interwork_tp_pointer_for_p_bit_priority_6=65535,
interwork_tp_pointer_for_p_bit_priority_7=65535,
interwork_tp_pointer_for_p_bit_priority_4=65535,
interwork_tp_pointer_for_p_bit_priority_5=65535,
interwork_tp_pointer_for_p_bit_priority_2=65535,
interwork_tp_pointer_for_p_bit_priority_3=65535,
interwork_tp_pointer_for_p_bit_priority_0=65535,
interwork_tp_pointer_for_p_bit_priority_1=65535,
tp_type=OMCI_8021P_MSP_TP_TYPE_NULL,
default_p_bit_marking=0
))
frame = OmciFrame(transaction_id=self.trangen.next(),
message_type=OmciCreate.message_id,
omci_message=msg)
self.adapter_agent.send_proxied_message(device.proxy_address, frame)
response = yield self.incoming_messages.get()
if OmciCreateResponse not in response:
log.error("Failed to set interwork info for {}".format(device.proxy_address))
return
# |###[ OmciFrame ]###
# | transaction_id= 8
# | message_type= 68
# | omci = 10
# | \omci_message\
# | |###[ OmciCreate ]###
# | | entity_class= 130
# | | entity_id = 1
# | | data = {'tp_pointer': 1, 'encapsulation_methods': 1, 'port_num': 1, 'port_priority': 3, 'tp_type': 5, 'port_path_cost': 32, 'port_spanning_tree_in': 1, 'lan_fcs_ind': 0, 'bridge_id_pointer': 1}
# | omci_trailer= 40
# Found in method: pmc_omci_mac_bridge_pcd_me_create from: PMC_OFAL.c
# Params
# - port_path_cost: The cost contribution of the port to the path cost towards the spanning tree root bridge
# - bridge_id_pointer: MAC bridge controlling the port
msg = OmciCreate(entity_class=130, entity_id=1,
data=dict(
tp_pointer=1,
encapsulation_methods=OMCI_MAC_BRIDGE_PCD_ENCAP_METHOD_LLC,
port_num=1,
port_priority=3,
tp_type=5,
port_path_cost=32,
port_spanning_tree_in=PON_TRUE,
lan_fcs_ind=OMCI_MAC_BRIDGE_PCD_LANFCS_FORWARDED,
bridge_id_pointer=1
))
frame = OmciFrame(transaction_id=self.trangen.next(),
message_type=OmciCreate.message_id,
omci_message=msg)
self.adapter_agent.send_proxied_message(self, device.proxy_address, frame)
response = yield self.incoming_messages.get()
if OmciCreateResponse not in response:
log.error("Failed to set encap info for {}".format(device.proxy_address))
return
# |###[ OmciFrame ]###
# | transaction_id= 9
# | message_type= 68
# | omci = 10
# | \omci_message\
# | |###[ OmciCreate ]###
# | | entity_class= 268
# | | entity_id = 1
# | | data = {'priority_queue_pointer_downstream': 0, 'direction': 3, 'tcont_pointer': 32769, 'traffic_descriptor_profile_pointer': 0, 'traffic_management_pointer_upstream': 4, 'port_id': 1000}
# | omci_trailer= 40
# Found in method: pmc_omci_gem_nctp_create from: PMC_OFAL.c
msg = OmciCreate(entity_class=268, entity_id=1,
data=dict(
priority_queue_pointer_downstream=0,
direction=GEM_DIR_BIDIRECT,
tcont_pointer=32769,
traffic_descriptor_profile_pointer=0,
traffic_management_pointer_upstream=4,
port_id=1000
))
frame = OmciFrame(transaction_id=self.trangen.next(),
message_type=OmciCreate.message_id,
omci_message=msg)
self.adapter_agent.send_proxied_message(device.proxy_address, frame)
response = yield self.incoming_messages.get()
if OmciCreateResponse not in response:
log.error("Failed to priority queue for {}".format(device.proxy_address))
return
# |###[ OmciFrame ]###
# | transaction_id= 10
# | message_type= 68
# | omci = 10
# | \omci_message\
# | |###[ OmciCreate ]###
# | | entity_class= 266
# | | entity_id = 1
# | | data = {'gem_port_network_ctp_pointer': 1, 'gal_profile_pointer': 0, 'service_profile_pointer': 1, 'interworking_option': 5, 'interworking_tp_pointer': 0}
# | omci_trailer= 40
# Found in method: pmc_omci_gem_iwtp_me_create from: PMC_OFAL.c
# Params
# - gem_port_network_ctp_pointer: An instance identifier of the GEM Port Network CTP that is associated with this GEM Interworking Termination Point
# - service_profile_pointer: The service profile type and a pointer to the instance of a service profile
# - interworking_tp_pointer: Used for in the case of Circuit Emulation Services and 802.1p mapper service
# - gal_profile_pointer: A pointer to an instance of the GAL Profile
msg = OmciCreate(entity_class=266, entity_id=1,
data=dict(
gem_port_network_ctp_pointer=1,
gal_profile_pointer=0,
service_profile_pointer=1,
interworking_option=OMCI_GEM_IWTP_IW_OPT_8021P_MAPPER,
interworking_tp_pointer=0
))
frame = OmciFrame(transaction_id=self.trangen.next(),
message_type=OmciCreate.message_id,
omci_message=msg)
self.adapter_agent.send_proxied_message(device.proxy_address, frame)
response = yield self.incoming_messages.get()
if OmciCreateResponse not in response:
log.error("Failed to set gem info for {}".format(device.proxy_address))
return