blob: 81824948f4f3f199ff580804f6cb145d2be5371a [file] [log] [blame]
Zsolt Harasztied091602016-12-08 13:36:38 -08001#
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08002# Copyright 2017 the original author or authors.
Zsolt Harasztied091602016-12-08 13:36:38 -08003#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17"""
18Tibit ONU device adapter
19"""
20
Zsolt Haraszti348d1932016-12-10 01:10:07 -080021import json
Paul Grayeee44382017-03-31 09:00:25 -070022import time
23import struct
Paul Gray934d2882017-05-25 04:44:49 -070024import re
Zsolt Haraszti348d1932016-12-10 01:10:07 -080025
26from uuid import uuid4
27
Zsolt Harasztic5f740b2017-01-18 09:53:17 -080028import arrow
Zsolt Harasztied091602016-12-08 13:36:38 -080029import structlog
Zsolt Harasztic5f740b2017-01-18 09:53:17 -080030from twisted.internet.task import LoopingCall
Zsolt Harasztied091602016-12-08 13:36:38 -080031from zope.interface import implementer
32
Zsolt Haraszti348d1932016-12-10 01:10:07 -080033from scapy.layers.inet import ICMP, IP
34from scapy.layers.l2 import Ether
35from twisted.internet.defer import DeferredQueue, inlineCallbacks
36from twisted.internet import reactor
37
Zsolt Haraszti85f12852016-12-24 08:30:58 -080038from voltha.core.flow_decomposer import *
Zsolt Haraszti348d1932016-12-10 01:10:07 -080039from voltha.core.logical_device_agent import mac_str_to_tuple
Nathan Knutha1a11932017-01-12 16:59:58 -080040from common.frameio.frameio import BpfProgramFilter, hexify
Zsolt Harasztied091602016-12-08 13:36:38 -080041from voltha.adapters.interface import IAdapterInterface
42from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
ggowdru236bd952017-06-20 20:32:55 -070043from voltha.protos.device_pb2 import Port, Image
Zsolt Harasztied091602016-12-08 13:36:38 -080044from voltha.protos.device_pb2 import DeviceType, DeviceTypes
Zsolt Harasztic5f740b2017-01-18 09:53:17 -080045from voltha.protos.events_pb2 import KpiEventType
46from voltha.protos.events_pb2 import MetricValuePairs, KpiEvent
Zsolt Harasztied091602016-12-08 13:36:38 -080047from voltha.protos.health_pb2 import HealthStatus
Zsolt Haraszti348d1932016-12-10 01:10:07 -080048from voltha.protos.common_pb2 import LogLevel, ConnectStatus
Zsolt Haraszti348d1932016-12-10 01:10:07 -080049from voltha.protos.common_pb2 import OperStatus, AdminState
50
51from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
52from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_port, OFPPF_10GB_FD, \
53 OFPPF_FIBER, OFPPS_LIVE, ofp_switch_features, OFPC_PORT_STATS, \
54 OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
55
56from scapy.packet import Packet, bind_layers
57from scapy.fields import StrField
Zsolt Harasztied091602016-12-08 13:36:38 -080058
59log = structlog.get_logger()
60
Paul Graycfc2dc32017-05-31 12:58:43 -070061from voltha.extensions.eoam.EOAM_TLV import UserPortObject
Nathan Knuth31c36962016-12-27 10:04:49 -080062from voltha.extensions.eoam.EOAM_TLV import AddStaticMacAddress, DeleteStaticMacAddress
63from voltha.extensions.eoam.EOAM_TLV import ClearStaticMacTable
64from voltha.extensions.eoam.EOAM_TLV import DeviceId
Nathan Knuthd8285e62017-01-11 14:18:43 -060065from voltha.extensions.eoam.EOAM_TLV import ClauseSubtypeEnum
66from voltha.extensions.eoam.EOAM_TLV import RuleOperatorEnum
Paul Gray934d2882017-05-25 04:44:49 -070067from voltha.extensions.eoam.EOAM_TLV import DPoEOpcodeEnum, DPoEVariableResponseCodes
Paul Grayef008892017-05-17 12:28:45 -070068from voltha.extensions.eoam.EOAM_TLV import DPoEOpcode_MulticastRegister, MulticastRegisterSet
Paul Gray934d2882017-05-25 04:44:49 -070069from voltha.extensions.eoam.EOAM_TLV import VendorName, OnuMode, HardwareVersion, ManufacturerInfo
Paul Gray7a312e42017-05-25 15:08:00 -070070from voltha.extensions.eoam.EOAM_TLV import SlowProtocolsSubtypeEnum, DeviceReset
Paul Graycfc2dc32017-05-31 12:58:43 -070071from voltha.extensions.eoam.EOAM_TLV import DONUObject, \
72 UserPortObject, PonPortObject, \
73 PortIngressRuleClauseMatchLength00, PortIngressRuleClauseMatchLength01, \
74 PortIngressRuleClauseMatchLength02, PortIngressRuleResultForward, \
75 PortIngressRuleResultSet, PortIngressRuleResultInsert, \
76 PortIngressRuleResultCopy, PortIngressRuleResultReplace, \
77 PortIngressRuleResultDelete, PortIngressRuleResultOLTQueue, \
78 PortIngressRuleTerminator, AddPortIngressRule
79from voltha.extensions.eoam.EOAM_TLV import PortIngressRuleHeader
80from voltha.extensions.eoam.EOAM_TLV import ClauseSubtypeEnum
81from voltha.extensions.eoam.EOAM_TLV import RuleOperatorEnum
Paul Gray934d2882017-05-25 04:44:49 -070082from voltha.extensions.eoam.EOAM_TLV import EndOfPDU
Nathan Knuthd8285e62017-01-11 14:18:43 -060083
Paul Grayef008892017-05-17 12:28:45 -070084from voltha.extensions.eoam.EOAM import EOAMPayload, EOAMEvent, EOAM_VendSpecificMsg
85from voltha.extensions.eoam.EOAM import EOAM_OmciMsg, EOAM_TibitMsg, EOAM_DpoeMsg
86from voltha.extensions.eoam.EOAM import EOAMPayload, CableLabs_OUI, Tibit_OUI
Nathan Knuth31c36962016-12-27 10:04:49 -080087from voltha.extensions.eoam.EOAM import DPoEOpcode_GetRequest, DPoEOpcode_SetRequest
Nathan Knuth5f4163e2017-01-11 18:21:10 -060088from voltha.extensions.eoam.EOAM import mcastIp2McastMac
Paul Graycfc2dc32017-05-31 12:58:43 -070089from voltha.extensions.eoam.EOAM import RxedOamMsgTypeEnum, Dpoe_Opcodes, get_oam_msg_type, \
90 handle_get_value, get_value_from_msg, check_set_resp, check_resp
Zsolt Harasztied091602016-12-08 13:36:38 -080091
Paul Grayeee44382017-03-31 09:00:25 -070092TIBIT_MSG_WAIT_TIME = 3
93
Paul Gray934d2882017-05-25 04:44:49 -070094
Zsolt Harasztied091602016-12-08 13:36:38 -080095@implementer(IAdapterInterface)
96class TibitOnuAdapter(object):
97
98 name = 'tibit_onu'
99
100 supported_device_types = [
101 DeviceType(
102 id='tibit_onu',
103 adapter=name,
104 accepts_bulk_flow_update=True
105 )
106 ]
107
108 def __init__(self, adapter_agent, config):
109 self.adapter_agent = adapter_agent
110 self.config = config
111 self.descriptor = Adapter(
112 id=self.name,
113 vendor='Tibit Communications Inc.',
114 version='0.1',
115 config=AdapterConfig(log_level=LogLevel.INFO)
116 )
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800117 self.incoming_messages = DeferredQueue()
Paul Gray934d2882017-05-25 04:44:49 -0700118 self.mode = "GPON"
Zsolt Harasztied091602016-12-08 13:36:38 -0800119
120 def start(self):
121 log.debug('starting')
122 log.info('started')
123
124 def stop(self):
125 log.debug('stopping')
126 log.info('stopped')
127
128 def adapter_descriptor(self):
129 return self.descriptor
130
131 def device_types(self):
132 return DeviceTypes(items=self.supported_device_types)
133
134 def health(self):
135 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
136
137 def change_master_state(self, master):
138 raise NotImplementedError()
139
Sergio Slobodrianec864c62017-03-09 11:41:43 -0500140 def update_pm_config(self, device, pm_configs):
141 raise NotImplementedError()
142
Zsolt Harasztied091602016-12-08 13:36:38 -0800143 def adopt_device(self, device):
144 log.info('adopt-device', device=device)
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800145 reactor.callLater(0.1, self._onu_device_activation, device)
Zsolt Harasztied091602016-12-08 13:36:38 -0800146 return device
147
khenaidoo032d3302017-06-09 14:50:04 -0400148 def reconcile_device(self, device):
149 raise NotImplementedError()
150
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800151 @inlineCallbacks
152 def _onu_device_activation(self, device):
153 # first we verify that we got parent reference and proxy info
154 assert device.parent_id
155 assert device.proxy_address.device_id
156 assert device.proxy_address.channel_id
157
Paul Gray934d2882017-05-25 04:44:49 -0700158 # Device information will be updated later on
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800159 device.vendor = 'Tibit Communications, Inc.'
160 device.model = '10G GPON ONU'
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800161 device.connect_status = ConnectStatus.REACHABLE
162 self.adapter_agent.update_device(device)
163
164 # then shortly after we create some ports for the device
165 uni_port = Port(
166 port_no=2,
167 label='UNI facing Ethernet port',
168 type=Port.ETHERNET_UNI,
169 admin_state=AdminState.ENABLED,
170 oper_status=OperStatus.ACTIVE
171 )
172 self.adapter_agent.add_port(device.id, uni_port)
173 self.adapter_agent.add_port(device.id, Port(
174 port_no=1,
175 label='PON port',
176 type=Port.PON_ONU,
177 admin_state=AdminState.ENABLED,
178 oper_status=OperStatus.ACTIVE,
179 peers=[
180 Port.PeerPort(
181 device_id=device.parent_id,
182 port_no=device.parent_port_no
183 )
184 ]
185 ))
186
187 # TODO adding vports to the logical device shall be done by agent?
188 # then we create the logical device port that corresponds to the UNI
189 # port of the device
190
191 # obtain logical device id
192 parent_device = self.adapter_agent.get_device(device.parent_id)
193 logical_device_id = parent_device.parent_id
194 assert logical_device_id
195
196 # we are going to use the proxy_address.channel_id as unique number
197 # and name for the virtual ports, as this is guaranteed to be unique
198 # in the context of the OLT port, so it is also unique in the context
199 # of the logical device
200 port_no = device.proxy_address.channel_id
201 cap = OFPPF_10GB_FD | OFPPF_FIBER
202 self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
203 id=str(port_no),
204 ofp_port=ofp_port(
205 port_no=port_no,
206 hw_addr=mac_str_to_tuple(device.mac_address),
207 name='uni-{}'.format(port_no),
208 config=0,
209 state=OFPPS_LIVE,
210 curr=cap,
211 advertised=cap,
212 peer=cap,
213 curr_speed=OFPPF_10GB_FD,
214 max_speed=OFPPF_10GB_FD
215 ),
216 device_id=device.id,
217 device_port_no=uni_port.port_no
218 ))
219
220 # simulate a proxied message sending and receving a reply
221 reply = yield self._message_exchange(device)
222
Paul Grayef008892017-05-17 12:28:45 -0700223 # TODO - Need to add validation of reply and decide what to do upon failure
224
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800225 # and finally update to "ACTIVE"
226 device = self.adapter_agent.get_device(device.id)
227 device.oper_status = OperStatus.ACTIVE
228 self.adapter_agent.update_device(device)
229
Paul Grayef008892017-05-17 12:28:45 -0700230 # TODO - Disable Stats Reporting for the moment
231 #self.start_kpi_collection(device.id)
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800232
Zsolt Harasztied091602016-12-08 13:36:38 -0800233 def abandon_device(self, device):
234 raise NotImplementedError(0
235 )
Khen Nursimulud068d812017-03-06 11:44:18 -0500236 def disable_device(self, device):
Paul Gray7a312e42017-05-25 15:08:00 -0700237 log.info('disable-device', device_id=device.id)
238 return device
Khen Nursimulud068d812017-03-06 11:44:18 -0500239
240 def reenable_device(self, device):
Paul Gray7a312e42017-05-25 15:08:00 -0700241 log.info('reenable-device', device_id=device.id)
242 return device
Khen Nursimulud068d812017-03-06 11:44:18 -0500243
Paul Gray7a312e42017-05-25 15:08:00 -0700244 @inlineCallbacks
Khen Nursimulud068d812017-03-06 11:44:18 -0500245 def reboot_device(self, device):
Paul Gray7a312e42017-05-25 15:08:00 -0700246 log.info('Rebooting ONU: {}'.format(device.mac_address))
247
248 # Update the operational status to ACTIVATING and connect status to
249 # UNREACHABLE
250 previous_oper_status = device.oper_status
251 previous_conn_status = device.connect_status
252 device.oper_status = OperStatus.ACTIVATING
253 device.connect_status = ConnectStatus.UNREACHABLE
254 self.adapter_agent.update_device(device)
255
256 msg = (
257 EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
258 EOAM_DpoeMsg(dpoe_opcode = Dpoe_Opcodes["Set Request"],
259 body=DeviceReset())/
260 EndOfPDU()
261 )
262
263 action = "Device Reset"
264
265 # send message
266 log.info('ONU-send-proxied-message to {} for ONU: {}'.format(action, device.mac_address))
267 self.adapter_agent.send_proxied_message(device.proxy_address, msg)
268
269 rc = []
270 yield self._handle_set_resp(device, action, rc)
271
272 # Change the operational status back to its previous state.
273 device.oper_status = previous_oper_status
274 device.connect_status = previous_conn_status
275 self.adapter_agent.update_device(device)
276
277 log.info('ONU Rebooted: {}'.format(device.mac_address))
Khen Nursimulud068d812017-03-06 11:44:18 -0500278
sathishg5ae86222017-06-28 15:16:29 +0530279 def self_test_device(self, device):
280 """
281 This is called to Self a device based on a NBI call.
282 :param device: A Voltha.Device object.
283 :return: Will return result of self test
284 """
285 log.info('self-test-device', device=device.id)
286 raise NotImplementedError()
287
Khen Nursimulud068d812017-03-06 11:44:18 -0500288 def delete_device(self, device):
289 raise NotImplementedError()
290
291 def get_device_details(self, device):
Zsolt Harasztied091602016-12-08 13:36:38 -0800292 raise NotImplementedError()
293
Paul Grayeee44382017-03-31 09:00:25 -0700294 @inlineCallbacks
Zsolt Harasztied091602016-12-08 13:36:38 -0800295 def update_flows_bulk(self, device, flows, groups):
Nathan Knuthd8285e62017-01-11 14:18:43 -0600296 log.info('########################################')
297 log.info('bulk-flow-update', device_id=device.id,
298 flows=flows, groups=groups)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800299 assert len(groups.items) == 0, "Cannot yet deal with groups"
300
Paul Gray934d2882017-05-25 04:44:49 -0700301 # Clear the existing entries in the Static MAC Address Table
302 yield self._send_clear_static_mac_table(device)
303
304 # Re-add the IGMP Multicast Address
305 yield self._send_igmp_mcast_addr(device)
306
307
Nathan Knuthd8285e62017-01-11 14:18:43 -0600308 Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
309 Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
310
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800311 for flow in flows.items:
312 in_port = get_in_port(flow)
313 assert in_port is not None
314
Nathan Knuthd8285e62017-01-11 14:18:43 -0600315 precedence = 255 - min(flow.priority / 256, 255)
316
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800317 if in_port == 2:
Nathan Knuth5f4163e2017-01-11 18:21:10 -0600318 log.info('#### Upstream Rule ####')
Paul Grayef008892017-05-17 12:28:45 -0700319
Paul Grayef008892017-05-17 12:28:45 -0700320
Paul Graycfc2dc32017-05-31 12:58:43 -0700321 up_req = UserPortObject()
322 up_req /= PortIngressRuleHeader(precedence=precedence)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800323
324 for field in get_ofb_fields(flow):
Nathan Knuthd8285e62017-01-11 14:18:43 -0600325
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800326 if field.type == ETH_TYPE:
327 _type = field.eth_type
Nathan Knuthd8285e62017-01-11 14:18:43 -0600328 log.info('#### field.type == ETH_TYPE ####',field_type=_type)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800329
330 elif field.type == IP_PROTO:
331 _proto = field.ip_proto
Nathan Knuthd8285e62017-01-11 14:18:43 -0600332 log.info('#### field.type == IP_PROTO ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800333
334 elif field.type == IN_PORT:
335 _port = field.port
Nathan Knuthd8285e62017-01-11 14:18:43 -0600336 log.info('#### field.type == IN_PORT ####', port=_port)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800337
338 elif field.type == VLAN_VID:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600339 _vlan_vid = field.vlan_vid & 0xfff
340 log.info('#### field.type == VLAN_VID ####', vlan=_vlan_vid)
Paul Graycfc2dc32017-05-31 12:58:43 -0700341 up_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
342 operator=Operator['=='], match=_vlan_vid)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800343
344 elif field.type == VLAN_PCP:
345 _vlan_pcp = field.vlan_pcp
Nathan Knuthd8285e62017-01-11 14:18:43 -0600346 log.info('#### field.type == VLAN_PCP ####', pcp=_vlan_pcp)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800347
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800348 elif field.type == UDP_DST:
349 _udp_dst = field.udp_dst
Paul Graycfc2dc32017-05-31 12:58:43 -0700350 log.info('#### field.type == UDP_DST ####', udp_dst=_udp_dst)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800351
Nathan Knuthd8285e62017-01-11 14:18:43 -0600352 elif field.type == IPV4_DST:
353 _ipv4_dst = field.ipv4_dst
Paul Graycfc2dc32017-05-31 12:58:43 -0700354 log.info('#### field.type == IPV4_DST ####', ipv4_dst=_ipv4_dst)
355
356 elif field.type == METADATA:
357 _metadata = field.table_metadata
358 log.info('#### field.type == METADATA ####', metadata=_metadata)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600359
360 else:
361 log.info('#### field.type == NOT IMPLEMENTED!! ####')
362 raise NotImplementedError('field.type={}'.format(
363 field.type))
364
365 for action in get_actions(flow):
366
367 if action.type == OUTPUT:
368 log.info('#### action.type == OUTPUT ####')
Paul Graycfc2dc32017-05-31 12:58:43 -0700369 up_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])
Nathan Knuthd8285e62017-01-11 14:18:43 -0600370
371 elif action.type == POP_VLAN:
372 log.info('#### action.type == POP_VLAN ####')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600373
374 elif action.type == PUSH_VLAN:
375 log.info('#### action.type == PUSH_VLAN ####')
Paul Graycfc2dc32017-05-31 12:58:43 -0700376 up_req /= PortIngressRuleResultInsert(fieldcode=Clause['C-VLAN Tag'])
377# if action.push.ethertype != 0x8100:
378# log.error('unhandled-tpid',
379# ethertype=action.push.ethertype)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600380
381 elif action.type == SET_FIELD:
382 log.info('#### action.type == SET_FIELD ####')
383 assert (action.set_field.field.oxm_class ==
384 ofp.OFPXMC_OPENFLOW_BASIC)
385 field = action.set_field.field.ofb_field
386 if field.type == VLAN_VID:
Paul Graycfc2dc32017-05-31 12:58:43 -0700387 log.info("#### action.field.vlan {} ####".format(field.vlan_vid & 0xfff))
388 up_req /= PortIngressRuleResultSet(
389 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600390 else:
391 log.error('unsupported-action-set-field-type',
392 field_type=field.type)
393 else:
394 log.error('UNSUPPORTED-ACTION-TYPE',
395 action_type=action.type)
396
Paul Graycfc2dc32017-05-31 12:58:43 -0700397 up_req /= PortIngressRuleTerminator()
398 up_req /= AddPortIngressRule()
399
400 msg = (
401 EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
402 EOAM_DpoeMsg(dpoe_opcode = Dpoe_Opcodes["Set Request"], body=up_req)/
403 EndOfPDU()
404 )
405
406 # send message
407 action = "Set ONU US Rule"
408 log.info('ONU-send-proxied-message to {} for ONU: {}'.format(action, device.mac_address))
409 self.adapter_agent.send_proxied_message(device.proxy_address, msg)
410
411 # Get and process the Set Response
412 rc = []
413 yield self._handle_set_resp(device, action, rc)
414
415
Nathan Knuthd8285e62017-01-11 14:18:43 -0600416 elif in_port == 1:
Nathan Knuth5f4163e2017-01-11 18:21:10 -0600417 log.info('#### Downstream Rule ####')
Paul Graycfc2dc32017-05-31 12:58:43 -0700418 Is_MCast = False
419
420 dn_req = PonPortObject()
421 dn_req /= PortIngressRuleHeader(precedence=precedence)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600422
423 #### Loop through fields again...
424
425 for field in get_ofb_fields(flow):
426
427 if field.type == ETH_TYPE:
428 _type = field.eth_type
429 log.info('#### field.type == ETH_TYPE ####', in_port=in_port,
430 match=_type)
431
432 elif field.type == IP_PROTO:
433 _proto = field.ip_proto
434 log.info('#### field.type == IP_PROTO ####', in_port=in_port,
Paul Graycfc2dc32017-05-31 12:58:43 -0700435 ip_proto=_proto)
Nathan Knuthd8285e62017-01-11 14:18:43 -0600436
437 elif field.type == IN_PORT:
438 _port = field.port
439 log.info('#### field.type == IN_PORT ####')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600440
441 elif field.type == VLAN_VID:
442 _vlan_vid = field.vlan_vid & 0xfff
443 log.info('#### field.type == VLAN_VID ####')
444
445 elif field.type == VLAN_PCP:
446 _vlan_pcp = field.vlan_pcp
447 log.info('#### field.type == VLAN_PCP ####')
Nathan Knuthd8285e62017-01-11 14:18:43 -0600448
449 elif field.type == UDP_DST:
450 _udp_dst = field.udp_dst
451 log.info('#### field.type == UDP_DST ####')
452
Nathan Knuth5f4163e2017-01-11 18:21:10 -0600453 elif field.type == IPV4_DST:
454 _ipv4_dst = field.ipv4_dst
455 log.info('#### field.type == IPV4_DST ####')
456 a = int(hex(_ipv4_dst)[2:4], 16)
457 b = int(hex(_ipv4_dst)[4:6], 16)
458 c = int(hex(_ipv4_dst)[6:8], 16)
459 d = int(hex(_ipv4_dst)[8:], 16)
Paul Graycfc2dc32017-05-31 12:58:43 -0700460 dn_req = AddStaticMacAddress(mac=mcastIp2McastMac('%d.%d.%d.%d' % (a,b,c,d)))
461 Is_MCast = True
Nathan Knuth5f4163e2017-01-11 18:21:10 -0600462
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800463 else:
464 raise NotImplementedError('field.type={}'.format(
465 field.type))
466
467 for action in get_actions(flow):
468
469 if action.type == OUTPUT:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600470 log.info('#### action.type == OUTPUT ####')
471
472 elif action.type == POP_VLAN:
473 log.info('#### action.type == POP_VLAN ####')
Paul Graycfc2dc32017-05-31 12:58:43 -0700474 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
475 operator=Operator['=='], match=_vlan_vid)
476 dn_req /= PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag'])
477 dn_req /= PortIngressRuleResultSet(
478 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800479
480 elif action.type == PUSH_VLAN:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600481 log.info('#### action.type == PUSH_VLAN ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800482 if action.push.ethertype != 0x8100:
483 log.error('unhandled-ether-type',
484 ethertype=action.push.ethertype)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800485
486 elif action.type == SET_FIELD:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600487 log.info('#### action.type == SET_FIELD ####')
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800488 assert (action.set_field.field.oxm_class ==
489 ofp.OFPXMC_OPENFLOW_BASIC)
490 field = action.set_field.field.ofb_field
491 if field.type == VLAN_VID:
Paul Graycfc2dc32017-05-31 12:58:43 -0700492 dn_req /= PortIngressRuleClauseMatchLength02(fieldcode=Clause['C-VLAN Tag'], fieldinstance=0,
493 operator=Operator['=='], match=_vlan_vid)
494 dn_req /= PortIngressRuleResultReplace(fieldcode=Clause['C-VLAN Tag'])
495 dn_req /= PortIngressRuleResultSet(
496 fieldcode=Clause['C-VLAN Tag'], value=field.vlan_vid & 0xfff)
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800497 else:
498 log.error('unsupported-action-set-field-type',
499 field_type=field.type)
500
501 else:
Nathan Knuthd8285e62017-01-11 14:18:43 -0600502 log.error('UNSUPPORTED-ACTION-TYPE',
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800503 action_type=action.type)
504
Paul Graycfc2dc32017-05-31 12:58:43 -0700505 if Is_MCast is True:
506 action = "Set Static IP MCAST address"
507 else:
508 dn_req /= PortIngressRuleTerminator()
509 dn_req /= AddPortIngressRule()
510 action = "Set ONU DS Rule"
511
512 msg = (
513 EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
514 EOAM_DpoeMsg(dpoe_opcode = Dpoe_Opcodes["Set Request"], body=dn_req)/
515 EndOfPDU()
516 )
517
518 # send message
519 log.info('ONU-send-proxied-message to {} for ONU: {}'.format(action, device.mac_address))
520 self.adapter_agent.send_proxied_message(device.proxy_address, msg)
521
522 # Get and process the Set Response
523 rc = []
524 yield self._handle_set_resp(device, action, rc)
525
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800526 else:
527 raise Exception('Port should be 1 or 2 by our convention')
528
Zsolt Harasztied091602016-12-08 13:36:38 -0800529 def update_flows_incrementally(self, device, flow_changes, group_changes):
530 raise NotImplementedError()
531
532 def send_proxied_message(self, proxy_address, msg):
533 raise NotImplementedError()
534
535 def receive_proxied_message(self, proxy_address, msg):
Nathan Knutha1a11932017-01-12 16:59:58 -0800536 log.info('receive-proxied-message',
537 proxy_address=proxy_address, msg=msg.show(dump=True))
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800538 self.incoming_messages.put(msg)
539
Nikolay Titov89004ec2017-06-19 18:22:42 -0400540 def create_interface(self, device, data):
541 raise NotImplementedError()
542
543 def update_interface(self, device, data):
544 raise NotImplementedError()
545
546 def remove_interface(self, device, data):
547 raise NotImplementedError()
548
549 def receive_onu_detect_state(self, device_id, state):
550 raise NotImplementedError()
551
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800552 @inlineCallbacks
553 def _message_exchange(self, device):
554
555 # register for receiving async messages
556 self.adapter_agent.register_for_proxied_messages(device.proxy_address)
557
558 # reset incoming message queue
559 while self.incoming_messages.pending:
560 _ = yield self.incoming_messages.get()
561
Paul Gray934d2882017-05-25 04:44:49 -0700562 # send out ping frame to ONU device get device information
563 ping_frame = (
Paul Grayef008892017-05-17 12:28:45 -0700564 EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
Paul Gray934d2882017-05-25 04:44:49 -0700565 EOAM_DpoeMsg(dpoe_opcode=Dpoe_Opcodes["Get Request"],
566 body=VendorName() /
567 OnuMode() /
568 HardwareVersion() /
569 ManufacturerInfo()
570 ) /
571 EndOfPDU()
Paul Grayef008892017-05-17 12:28:45 -0700572 )
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800573
Paul Gray934d2882017-05-25 04:44:49 -0700574 log.info('ONU-send-proxied-message to Get Version Info for ONU: {}'.format(device.mac_address))
575 self.adapter_agent.send_proxied_message(device.proxy_address, ping_frame)
Paul Grayeee44382017-03-31 09:00:25 -0700576
Paul Gray934d2882017-05-25 04:44:49 -0700577 # Loop until we have a Get Response
Paul Grayeee44382017-03-31 09:00:25 -0700578 ack = False
Paul Grayeee44382017-03-31 09:00:25 -0700579 while not ack:
580 frame = yield self.incoming_messages.get()
Paul Grayeee44382017-03-31 09:00:25 -0700581
Paul Graycfc2dc32017-05-31 12:58:43 -0700582 respType = get_oam_msg_type(log, frame)
Paul Gray934d2882017-05-25 04:44:49 -0700583
584 if (respType == RxedOamMsgTypeEnum["DPoE Get Response"]):
Paul Grayeee44382017-03-31 09:00:25 -0700585 ack = True
586 else:
587 # Handle unexpected events/OMCI messages
Paul Graycfc2dc32017-05-31 12:58:43 -0700588 check_resp(log, frame)
Paul Grayeee44382017-03-31 09:00:25 -0700589
Paul Grayeee44382017-03-31 09:00:25 -0700590 if ack:
Paul Gray934d2882017-05-25 04:44:49 -0700591 log.info('ONU-response received for Get Version Info for ONU: {}'.format(device.mac_address))
Paul Grayef008892017-05-17 12:28:45 -0700592
Paul Gray934d2882017-05-25 04:44:49 -0700593 self._process_ping_frame_response(device, frame)
Paul Grayef008892017-05-17 12:28:45 -0700594
Paul Grayef008892017-05-17 12:28:45 -0700595
Paul Gray934d2882017-05-25 04:44:49 -0700596 if self.mode.upper()[0] == "G": # GPON
Paul Grayac4850d2017-06-02 14:53:40 -0700597
Andrew Chagnonb4d604f2017-06-09 15:45:39 -0400598 hw_vers = int(device.hardware_version, 16)
Paul Grayac4850d2017-06-02 14:53:40 -0700599
Andrew Chagnonfe0eb732017-07-10 19:29:29 -0400600 if hw_vers >= 0x170618:
601 mcastLidx = 0x04bc
602 elif hw_vers >= 0x170517:
Paul Grayac4850d2017-06-02 14:53:40 -0700603 mcastLidx = 0x14bc
604 else:
605 mcastLidx = 0x10bc
606
607 log.info("Using Multicast LIDX {:04X}".format(mcastLidx))
608
Paul Gray934d2882017-05-25 04:44:49 -0700609 # construct multicast LLID set
610 msg = (
611 EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
Paul Grayac4850d2017-06-02 14:53:40 -0700612 EOAM_DpoeMsg(dpoe_opcode=Dpoe_Opcodes["Multicast Register"],body=MulticastRegisterSet(MulticastLink=mcastLidx, UnicastLink=0)
Paul Gray934d2882017-05-25 04:44:49 -0700613 ))
614
615 # send message
616 log.info('ONU-send-proxied-message to Multicast Register Set for ONU: {}'.format(device.mac_address))
617 self.adapter_agent.send_proxied_message(device.proxy_address, msg)
618
619 # The MulticastRegisterSet does not currently return a response. Just hope it worked.
Zsolt Haraszti348d1932016-12-10 01:10:07 -0800620
621 # by returning we allow the device to be shown as active, which
622 # indirectly verified that message passing works
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800623
624 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
625 log.info('packet-out', logical_device_id=logical_device_id,
626 egress_port_no=egress_port_no, msg_len=len(msg))
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800627
Peter Shafik9107f2e2017-05-02 15:54:39 -0400628 def receive_inter_adapter_message(self, msg):
629 raise NotImplementedError()
630
Stephane Barbarie980a0912017-05-11 11:27:06 -0400631 def suppress_alarm(self, filter):
632 raise NotImplementedError()
633
634 def unsuppress_alarm(self, filter):
635 raise NotImplementedError()
636
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800637 def start_kpi_collection(self, device_id):
638
639 """TMP Simulate periodic KPI metric collection from the device"""
640 import random
641
642 @inlineCallbacks # pretend that we need to do async calls
643 def _collect(device_id, prefix):
644
645 try:
646 # Step 1: gather metrics from device (pretend it here) - examples
647 uni_port_metrics = yield dict(
648 tx_pkts=random.randint(0, 100),
649 rx_pkts=random.randint(0, 100),
650 tx_bytes=random.randint(0, 100000),
651 rx_bytes=random.randint(0, 100000),
652 )
653 pon_port_metrics = yield dict(
654 tx_pkts=uni_port_metrics['rx_pkts'],
655 rx_pkts=uni_port_metrics['tx_pkts'],
656 tx_bytes=uni_port_metrics['rx_bytes'],
657 rx_bytes=uni_port_metrics['tx_bytes'],
658 )
659 onu_metrics = yield dict(
660 cpu_util=20 + 5 * random.random(),
661 buffer_util=10 + 10 * random.random()
662 )
663
664 # Step 2: prepare the KpiEvent for submission
665 # we can time-stamp them here (or could use time derived from OLT
666 ts = arrow.utcnow().timestamp
667 kpi_event = KpiEvent(
668 type=KpiEventType.slice,
669 ts=ts,
670 prefixes={
671 # OLT-level
672 prefix: MetricValuePairs(metrics=onu_metrics),
673 # OLT NNI port
674 prefix + '.nni': MetricValuePairs(metrics=uni_port_metrics),
675 # OLT PON port
676 prefix + '.pon': MetricValuePairs(metrics=pon_port_metrics)
677 }
678 )
679
680 # Step 3: submit
681 self.adapter_agent.submit_kpis(kpi_event)
682
683 except Exception as e:
684 log.exception('failed-to-submit-kpis', e=e)
685
686 prefix = 'voltha.{}.{}'.format(self.name, device_id)
687 lc = LoopingCall(_collect, device_id, prefix)
688 lc.start(interval=15) # TODO make this configurable
689
Paul Grayef008892017-05-17 12:28:45 -0700690
691# Methods for Get / Set Response Processing from eoam_messages
692
Paul Gray934d2882017-05-25 04:44:49 -0700693 @inlineCallbacks
694 def _send_igmp_mcast_addr(self, device):
695 # construct install of igmp query address
696 msg = (
697 EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
698 EOAM_DpoeMsg(dpoe_opcode=Dpoe_Opcodes["Set Request"],body=AddStaticMacAddress(mac='01:00:5e:00:00:01')
699 ))
700
701 action = "Set Static IGMP MAC address"
702
703 # send message
704 log.info('ONU-send-proxied-message to {} for ONU: {}'.format(action, device.mac_address))
705 self.adapter_agent.send_proxied_message(device.proxy_address, msg)
706
707 rc = []
708 yield self._handle_set_resp(device, action, rc)
709
710
711 @inlineCallbacks
712 def _send_clear_static_mac_table(self, device):
713 # construct install of igmp query address
714 msg = (
715 EOAMPayload() / EOAM_VendSpecificMsg(oui=CableLabs_OUI) /
716 EOAM_DpoeMsg(dpoe_opcode=Dpoe_Opcodes["Set Request"],body=ClearStaticMacTable()
717 ))
718
719 action = "Clear Static MAC Table"
720
721 # send message
722 log.info('ONU-send-proxied-message to {} for ONU: {}'.format(action, device.mac_address))
723 self.adapter_agent.send_proxied_message(device.proxy_address, msg)
724
725 rc = []
726 yield self._handle_set_resp(device, action, rc)
727
728
729 @inlineCallbacks
730 def _handle_set_resp(self, device, action, retcode):
731 # Get and process the Set Response
732 ack = False
733 start_time = time.time()
734
735 # Loop until we have a set response or timeout
736 while not ack:
737 frame = yield self.incoming_messages.get()
738 #TODO - Need to add propoer timeout functionality
739 #if (time.time() - start_time) > TIBIT_MSG_WAIT_TIME or (frame is None):
740 # break # don't wait forever
741
Paul Graycfc2dc32017-05-31 12:58:43 -0700742 respType = get_oam_msg_type(log, frame)
Paul Gray934d2882017-05-25 04:44:49 -0700743 log.info('Received OAM Message 0x %s' % str(respType))
744
745 #Check that the message received is a Set Response
746 if (respType == RxedOamMsgTypeEnum["DPoE Set Response"]):
747 ack = True
748 else:
749 # Handle unexpected events/OMCI messages
Paul Graycfc2dc32017-05-31 12:58:43 -0700750 check_resp(log, frame)
Paul Gray934d2882017-05-25 04:44:49 -0700751
752 # Verify Set Response
753 rc = False
754 if ack:
Paul Graycfc2dc32017-05-31 12:58:43 -0700755 (rc,branch,leaf,status) = check_set_resp(log, frame)
Paul Gray934d2882017-05-25 04:44:49 -0700756 if (rc is False):
757 log.info('Set Response had errors - Branch 0x{:X} Leaf 0x{:0>4X} {}'.format(branch, leaf, DPoEVariableResponseCodes[status]))
758
759 if (rc is True):
760 log.info('ONU-response received for {} for ONU: {}'.format(action, device.mac_address))
761 else:
762 log.info('BAD ONU-response received for {} for ONU: {}'.format(action, device.mac_address))
763
764 retcode.append(rc)
765
766 def _process_ping_frame_response(self, device, frame):
767
768 vendor = [0xD7, 0x0011]
769 ponMode = [0xB7, 0x0105]
770 hw_version = [0xD7, 0x0013]
771 manufacturer = [0xD7, 0x0006]
772 branch_leaf_pairs = [vendor, ponMode, hw_version, manufacturer]
773
774 for pair in branch_leaf_pairs:
775 temp_pair = pair
Paul Graycfc2dc32017-05-31 12:58:43 -0700776 (rc, value) = (get_value_from_msg(log, frame, pair[0], pair[1]))
Paul Gray934d2882017-05-25 04:44:49 -0700777 temp_pair.append(rc)
778 temp_pair.append(value)
779 if rc:
780 overall_rc = True
781 else:
782 log.info('Failed to get valid response for Branch 0x{:X} Leaf 0x{:0>4X} '.format(temp_pair[0], temp_pair[1]))
783 ack = True
784
785 if vendor[rc]:
786 device.vendor = vendor.pop()
787 if device.vendor.endswith(''):
788 device.vendor = device.vendor[:-1]
789 else:
790 device.vendor = "UNKNOWN"
791
792 # mode: 3 = EPON OLT, 7 = GPON OLT
793 # mode: 2 = EPON ONU, 6 = GPON ONU
794 if ponMode[rc]:
795 value = ponMode.pop()
796 mode = "UNKNOWN"
797 self.mode = "UNKNOWN"
798
799 if value == 6:
800 mode = "10G GPON ONU"
801 self.mode = "GPON"
802 if value == 2:
803 mode = "10G EPON ONU"
804 self.mode = "EPON"
805 if value == 1:
806 mode = "10G Point to Point"
807 self.mode = "Unsupported"
808
809 device.model = mode
810
811 else:
812 device.model = "UNKNOWN"
813 self.mode = "UNKNOWN"
814
815 log.info("PON Mode is {}".format(self.mode))
816
817 if hw_version[rc]:
818 device.hardware_version = hw_version.pop()
Andrew Chagnonb4d604f2017-06-09 15:45:39 -0400819 device.hardware_version = device.hardware_version.replace("FA","")
Paul Gray934d2882017-05-25 04:44:49 -0700820 if device.hardware_version.endswith(''):
821 device.hardware_version = device.hardware_version[:-1]
822 else:
823 device.hardware_version = "UNKNOWN"
824
825 if manufacturer[rc]:
826 manu_value = manufacturer.pop()
827 device.firmware_version = re.search('\Firmware: (.+?) ', manu_value).group(1)
ggowdru236bd952017-06-20 20:32:55 -0700828 image_1 = Image(version = \
829 re.search('\Build: (.+?) ', manu_value).group(1))
830 device.images.image.extend([ image_1 ])
Paul Gray934d2882017-05-25 04:44:49 -0700831 device.serial_number = re.search('\Serial #: (.+?) ', manu_value).group(1)
832 else:
833 device.firmware_version = "UNKNOWN"
ggowdru236bd952017-06-20 20:32:55 -0700834 image_1 = Image(version="UNKNOWN")
835 device.images.image.extend([ image_1 ])
Paul Gray934d2882017-05-25 04:44:49 -0700836 device.serial_number = "UNKNOWN"
837
838 device.connect_status = ConnectStatus.REACHABLE