blob: e3290f87034556ca484e999eb90ce918378f470c [file] [log] [blame]
Chip Bolingfd1fd372017-12-20 13:34:12 -06001#
2# Copyright 2017 the original author or authors.
3#
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
17import arrow
Chip Bolinge84aca92018-03-27 11:45:56 -070018import structlog
Chip Bolingfd1fd372017-12-20 13:34:12 -060019
20from voltha.adapters.adtran_olt.xpon.adtran_xpon import AdtranXPON
Chip Bolingfd1fd372017-12-20 13:34:12 -060021from pon_port import PonPort
22from uni_port import UniPort
23from heartbeat import HeartBeat
24
25from voltha.adapters.adtran_olt.alarms.adapter_alarms import AdapterAlarms
26from onu_pm_metrics import OnuPmMetrics
27
28from uuid import uuid4
29from twisted.internet import reactor
30from twisted.internet.defer import DeferredQueue, inlineCallbacks
31from twisted.internet.defer import returnValue
32
33from voltha.protos import third_party
34from voltha.protos.common_pb2 import OperStatus, ConnectStatus
35from voltha.protos.device_pb2 import Image
Chip Bolingfd1fd372017-12-20 13:34:12 -060036from common.utils.indexpool import IndexPool
Chip Bolinge84aca92018-03-27 11:45:56 -070037from voltha.extensions.omci.openomci_agent import OpenOMCIAgent
Chip Bolingfd1fd372017-12-20 13:34:12 -060038
39_ = third_party
40_MAXIMUM_PORT = 128 # PON and UNI ports
Chip Boling0f19f4e2018-02-13 09:27:30 -060041_ONU_REBOOT_MIN = 60
42_ONU_REBOOT_RETRY = 10
Chip Bolingfd1fd372017-12-20 13:34:12 -060043
Chip Bolinge84aca92018-03-27 11:45:56 -070044
Chip Bolingfd1fd372017-12-20 13:34:12 -060045class AdtranOnuHandler(AdtranXPON):
46 def __init__(self, adapter, device_id):
47 kwargs = dict()
48 super(AdtranOnuHandler, self).__init__(**kwargs)
49 self.adapter = adapter
50 self.adapter_agent = adapter.adapter_agent
51 self.device_id = device_id
52 self.log = structlog.get_logger(device_id=device_id)
53 self.logical_device_id = None
54 self.proxy_address = None
55 self._event_messages = None
56 self._enabled = False
57 self.pm_metrics = None
58 self.alarms = None
59 self._mgmt_gemport_aes = False
60 self._upstream_channel_speed = 0
61
62 self._unis = dict() # Port # -> UniPort
Chip Bolinge84aca92018-03-27 11:45:56 -070063 self._pon = None
Chip Bolingfd1fd372017-12-20 13:34:12 -060064 self._heartbeat = HeartBeat.create(self, device_id)
65
66 self._deferred = None
67 self._event_deferred = None
Chip Bolinge84aca92018-03-27 11:45:56 -070068
69 # TODO: Remove next two lines if/when OpenOMCI is in the core or a container
70 # in order to support multiple ONUs per instance
71 self._omci_agent = OpenOMCIAgent(self.adapter_agent.core)
72 self._omci_agent.start()
73
Chip Bolingfd1fd372017-12-20 13:34:12 -060074 self._port_number_pool = IndexPool(_MAXIMUM_PORT, 1)
75
76 self._olt_created = False # True if deprecated method of OLT creating DA is used
77 self._is_mock = False
78
79 def __str__(self):
80 return "AdtranOnuHandler: {}".format(self.device_id)
81
82 def _cancel_deferred(self):
83 d1, self._deferred = self._deferred, None
84 d2, self._event_deferred = self._event_deferred, None
85
86 for d in [d1, d2]:
87 try:
88 if d is not None and not d.called:
89 d.cancel()
90 except:
91 pass
92
93 @property
94 def enabled(self):
95 return self._enabled
96
97 @enabled.setter
98 def enabled(self, value):
99 assert isinstance(value, bool), 'enabled is a boolean'
100 if self._enabled != value:
101 self._enabled = value
102 if self._enabled:
103 self.start()
104 else:
105 self.stop()
106
107 @property
108 def mgmt_gemport_aes(self):
109 return self._mgmt_gemport_aes
110
111 @mgmt_gemport_aes.setter
112 def mgmt_gemport_aes(self, value):
113 if self._mgmt_gemport_aes != value:
114 self._mgmt_gemport_aes = value
115 # TODO: Anything else
116
117 @property
118 def upstream_channel_speed(self):
119 return self._upstream_channel_speed
120
121 @upstream_channel_speed.setter
122 def upstream_channel_speed(self, value):
123 if self._upstream_channel_speed != value:
124 self._upstream_channel_speed = value
125 # TODO: Anything else
126
127 @property
128 def is_mock(self):
Chip Boling8536d1b2018-01-19 12:44:54 -0600129 return self._is_mock # Not pointing to real hardware
Chip Bolingfd1fd372017-12-20 13:34:12 -0600130
131 @property
132 def olt_created(self):
133 return self._olt_created # ONU was created with deprecated 'child_device_detected' call
134
135 @property
Chip Bolinge84aca92018-03-27 11:45:56 -0700136 def omci_agent(self):
137 return self._omci_agent
138
139 @property
Chip Bolingfd1fd372017-12-20 13:34:12 -0600140 def omci(self):
Chip Bolinge84aca92018-03-27 11:45:56 -0700141 # TODO: Decrement access to Communications channel at this point? What about current PM stuff?
142 _onu_omci_device = self._pon.onu_omci_device
143 return _onu_omci_device.omci_cc if _onu_omci_device is not None else None
Chip Bolingfd1fd372017-12-20 13:34:12 -0600144
145 @property
146 def heartbeat(self):
147 return self._heartbeat
148
149 @property
150 def uni_ports(self):
151 return self._unis.values()
152
153 def uni_port(self, port_no_or_name):
154 if isinstance(port_no_or_name, (str, unicode)):
155 return next((uni for uni in self.uni_ports
156 if uni.name == port_no_or_name), None)
157
158 assert isinstance(port_no_or_name, int), 'Invalid parameter type'
159 return self._unis.get(port_no_or_name)
160
161 @property
Chip Bolinge84aca92018-03-27 11:45:56 -0700162 def pon_port(self):
163 return self._pon
Chip Bolingfd1fd372017-12-20 13:34:12 -0600164
165 @property
166 def _next_port_number(self):
167 return self._port_number_pool.get_next()
168
169 def _release_port_number(self, number):
170 self._port_number_pool.release(number)
171
172 def start(self):
173 assert self._enabled, 'Start should only be called if enabled'
Chip Bolinge84aca92018-03-27 11:45:56 -0700174
Chip Bolingfd1fd372017-12-20 13:34:12 -0600175 self._cancel_deferred()
176
Chip Bolinge84aca92018-03-27 11:45:56 -0700177 # Handle received ONU event messages TODO: Deprecate this....
Chip Bolingfd1fd372017-12-20 13:34:12 -0600178 self._event_messages = DeferredQueue()
179 self._event_deferred = reactor.callLater(0, self._handle_onu_events)
180
181 # Register for adapter messages
182 self.adapter_agent.register_for_inter_adapter_messages()
183
184 # Port startup
Chip Bolinge84aca92018-03-27 11:45:56 -0700185 if self._pon is not None:
186 self._pon.enabled = True
Chip Bolingfd1fd372017-12-20 13:34:12 -0600187
Chip Bolinge84aca92018-03-27 11:45:56 -0700188 for port in self.uni_ports:
Chip Bolingfd1fd372017-12-20 13:34:12 -0600189 port.enabled = True
190
191 # Heartbeat
192 self._heartbeat.enabled = True
193
194 def stop(self):
195 assert not self._enabled, 'Stop should only be called if disabled'
196 #
197 # TODO: Perform common shutdown tasks here
198 #
199 self._cancel_deferred()
200
201 # Drop registration for adapter messages
202 self.adapter_agent.unregister_for_inter_adapter_messages()
203
204 # Heartbeat
205 self._heartbeat.stop()
206
Chip Bolinge84aca92018-03-27 11:45:56 -0700207 # OMCI Communications
208 # if self._onu_omci_device is not None:
209 # self._onu_omci_device.stop()
210
Chip Bolingfd1fd372017-12-20 13:34:12 -0600211 # Port shutdown
212 for port in self.uni_ports:
213 port.enabled = False
214
Chip Bolinge84aca92018-03-27 11:45:56 -0700215 if self._pon is not None:
216 self._pon.enabled = False
Chip Bolingfd1fd372017-12-20 13:34:12 -0600217
218 queue, self._event_deferred = self._event_deferred, None
219 if queue is not None:
220 while queue.pending:
221 _ = yield queue.get()
222
223 def receive_message(self, msg):
Chip Bolinge84aca92018-03-27 11:45:56 -0700224 if self.omci is not None and self.enabled:
225 self.omci.receive_message(msg)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600226
227 def activate(self, device):
228 self.log.info('activating')
229
230 # first we verify that we got parent reference and proxy info
231 assert device.parent_id, 'Invalid Parent ID'
232 assert device.proxy_address.device_id, 'Invalid Device ID'
233
234 if device.vlan:
235 # vlan non-zero if created via legacy method (not xPON). Also
236 # Set a random serial number since not xPON based
237 self._olt_created = True
238
239 # register for proxied messages right away
240 self.proxy_address = device.proxy_address
241 self.adapter_agent.register_for_proxied_messages(device.proxy_address)
242
243 # initialize device info
244 device.root = True
245 device.vendor = 'Adtran Inc.'
246 device.model = 'n/a'
247 device.hardware_version = 'n/a'
248 device.firmware_version = 'n/a'
Chip Boling8536d1b2018-01-19 12:44:54 -0600249 device.reason = ''
Chip Bolingfd1fd372017-12-20 13:34:12 -0600250 device.connect_status = ConnectStatus.UNKNOWN
251
252 ############################################################################
253 # Setup PM configuration for this device
254
255 self.pm_metrics = OnuPmMetrics(self, device, grouped=True, freq_override=False)
256 pm_config = self.pm_metrics.make_proto()
257 self.log.info("initial-pm-config", pm_config=pm_config)
258 self.adapter_agent.update_device_pm_config(pm_config, init=True)
259
260 ############################################################################
261 # Setup Alarm handler
262
263 self.alarms = AdapterAlarms(self.adapter, device.id)
264
265 # reference of uni_port is required when re-enabling the device if
266 # it was disabled previously
267 # Need to query ONU for number of supported uni ports
268 # For now, temporarily set number of ports to 1 - port #2
269
Chip Bolingfd1fd372017-12-20 13:34:12 -0600270 parent_device = self.adapter_agent.get_device(device.parent_id)
271 self.logical_device_id = parent_device.parent_id
272 assert self.logical_device_id, 'Invalid logical device ID'
273
Chip Bolinge84aca92018-03-27 11:45:56 -0700274 # Register physical ports. Should have at least one of each
275
276 self._pon = PonPort.create(self, self._next_port_number)
277 self.adapter_agent.add_port(device.id, self._pon.get_port())
278
Chip Bolingfd1fd372017-12-20 13:34:12 -0600279 if self._olt_created:
280 # vlan non-zero if created via legacy method (not xPON). Also
281 # Set a random serial number since not xPON based
282
Chip Bolinge84aca92018-03-27 11:45:56 -0700283 uni_port = UniPort.create(self, self._next_port_number, device.vlan,
284 'deprecated', device.vlan, None)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600285 self._unis[uni_port.port_number] = uni_port
286 self.adapter_agent.add_port(device.id, uni_port.get_port())
287
288 device.serial_number = uuid4().hex
Chip Bolinge84aca92018-03-27 11:45:56 -0700289 uni_port.add_logical_port(device.vlan, subscriber_vlan=device.vlan)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600290
291 # Start things up for this ONU Handler.
292 self.enabled = True
293
294 # Start collecting stats from the device after a brief pause
Chip Boling8536d1b2018-01-19 12:44:54 -0600295 reactor.callLater(30, self.start_kpi_collection, device.id)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600296
297 self.adapter_agent.update_device(device)
298
299 def reconcile(self, device):
300 self.log.info('reconciling-ONU-device-starts')
301
302 # first we verify that we got parent reference and proxy info
303 assert device.parent_id
304 assert device.proxy_address.device_id
305 # assert device.proxy_address.channel_id
306 self._cancel_deferred()
307
308 # register for proxied messages right away
309 self.proxy_address = device.proxy_address
310 self.adapter_agent.register_for_proxied_messages(device.proxy_address)
311
312 # Register for adapter messages
313 self.adapter_agent.register_for_inter_adapter_messages()
314
315 # Set the connection status to REACHABLE
316 device.connect_status = ConnectStatus.REACHABLE
317 self.adapter_agent.update_device(device)
318 self.enabled = True
319
320 # TODO: Verify that the uni, pon and logical ports exists
321
322 # Mark the device as REACHABLE and ACTIVE
323 device = self.adapter_agent.get_device(device.id)
324 device.connect_status = ConnectStatus.REACHABLE
325 device.oper_status = OperStatus.ACTIVE
Chip Boling8536d1b2018-01-19 12:44:54 -0600326 device.reason = ''
Chip Bolingfd1fd372017-12-20 13:34:12 -0600327 self.adapter_agent.update_device(device)
328
329 self.log.info('reconciling-ONU-device-ends')
330
331 def update_pm_config(self, device, pm_config):
332 # TODO: This has not been tested
333 self.log.info('update_pm_config', pm_config=pm_config)
334 self.pm_metrics.update(pm_config)
335
336 def start_kpi_collection(self, device_id):
337 # TODO: This has not been tested
338 def _collect(device_id, prefix):
339 from voltha.protos.events_pb2 import KpiEvent, KpiEventType, MetricValuePairs
340
341 if self.enabled:
342 try:
343 # Step 1: gather metrics from device
344 port_metrics = self.pm_metrics.collect_port_metrics()
345
346 # Step 2: prepare the KpiEvent for submission
347 # we can time-stamp them here or could use time derived from OLT
348 ts = arrow.utcnow().timestamp
349 kpi_event = KpiEvent(
350 type=KpiEventType.slice,
351 ts=ts,
352 prefixes={
353 prefix + '.{}'.format(k): MetricValuePairs(metrics=port_metrics[k])
354 for k in port_metrics.keys()}
355 )
356 # Step 3: submit
357 self.adapter_agent.submit_kpis(kpi_event)
358
359 except Exception as e:
360 self.log.exception('failed-to-submit-kpis', e=e)
361
362 self.pm_metrics.start_collector(_collect)
363
364 @inlineCallbacks
365 def update_flow_table(self, device, flows):
366 #
367 # We need to proxy through the OLT to get to the ONU
368 # Configuration from here should be using OMCI
369 #
370 # self.log.info('bulk-flow-update', device_id=device.id, flows=flows)
371
372 import voltha.core.flow_decomposer as fd
Chip Bolinge84aca92018-03-27 11:45:56 -0700373 from voltha.protos.openflow_13_pb2 import OFPXMC_OPENFLOW_BASIC
Chip Bolingfd1fd372017-12-20 13:34:12 -0600374
375 def is_downstream(port):
376 return port == 100 # Need a better way
377
378 def is_upstream(port):
379 return not is_downstream(port)
380
Chip Bolinge84aca92018-03-27 11:45:56 -0700381 omci = self.omci
Chip Bolingfd1fd372017-12-20 13:34:12 -0600382
383 for flow in flows:
384 _type = None
385 _port = None
386 _vlan_vid = None
387 _udp_dst = None
388 _udp_src = None
389 _ipv4_dst = None
390 _ipv4_src = None
391 _metadata = None
392 _output = None
393 _push_tpid = None
394 _field = None
395 _set_vlan_vid = None
396 self.log.info('bulk-flow-update', device_id=device.id, flow=flow)
397 try:
398 _in_port = fd.get_in_port(flow)
399 assert _in_port is not None
400
401 if is_downstream(_in_port):
402 self.log.info('downstream-flow')
403 elif is_upstream(_in_port):
404 self.log.info('upstream-flow')
405 else:
406 raise Exception('port should be 1 or 2 by our convention')
407
408 _out_port = fd.get_out_port(flow) # may be None
409 self.log.info('out-port', out_port=_out_port)
410
411 for field in fd.get_ofb_fields(flow):
412 if field.type == fd.ETH_TYPE:
413 _type = field.eth_type
414 self.log.info('field-type-eth-type',
415 eth_type=_type)
416
417 elif field.type == fd.IP_PROTO:
418 _proto = field.ip_proto
419 self.log.info('field-type-ip-proto',
420 ip_proto=_proto)
421
422 elif field.type == fd.IN_PORT:
423 _port = field.port
424 self.log.info('field-type-in-port',
425 in_port=_port)
426
427 elif field.type == fd.VLAN_VID:
428 _vlan_vid = field.vlan_vid & 0xfff
429 self.log.info('field-type-vlan-vid',
430 vlan=_vlan_vid)
431
432 elif field.type == fd.VLAN_PCP:
433 _vlan_pcp = field.vlan_pcp
434 self.log.info('field-type-vlan-pcp',
435 pcp=_vlan_pcp)
436
437 elif field.type == fd.UDP_DST:
438 _udp_dst = field.udp_dst
439 self.log.info('field-type-udp-dst',
440 udp_dst=_udp_dst)
441
442 elif field.type == fd.UDP_SRC:
443 _udp_src = field.udp_src
444 self.log.info('field-type-udp-src',
445 udp_src=_udp_src)
446
447 elif field.type == fd.IPV4_DST:
448 _ipv4_dst = field.ipv4_dst
449 self.log.info('field-type-ipv4-dst',
450 ipv4_dst=_ipv4_dst)
451
452 elif field.type == fd.IPV4_SRC:
453 _ipv4_src = field.ipv4_src
454 self.log.info('field-type-ipv4-src',
455 ipv4_dst=_ipv4_src)
456
457 elif field.type == fd.METADATA:
458 _metadata = field.table_metadata
459 self.log.info('field-type-metadata',
460 metadata=_metadata)
461
462 else:
463 raise NotImplementedError('field.type={}'.format(
464 field.type))
465
466 for action in fd.get_actions(flow):
467
468 if action.type == fd.OUTPUT:
469 _output = action.output.port
470 self.log.info('action-type-output',
471 output=_output, in_port=_in_port)
472
473 elif action.type == fd.POP_VLAN:
474 self.log.info('action-type-pop-vlan',
475 in_port=_in_port)
476
477 elif action.type == fd.PUSH_VLAN:
478 _push_tpid = action.push.ethertype
Chip Bolinge84aca92018-03-27 11:45:56 -0700479 self.log.info('action-type-push-vlan',
Chip Bolingfd1fd372017-12-20 13:34:12 -0600480 push_tpid=_push_tpid, in_port=_in_port)
481 if action.push.ethertype != 0x8100:
482 self.log.error('unhandled-tpid',
483 ethertype=action.push.ethertype)
484
485 elif action.type == fd.SET_FIELD:
486 _field = action.set_field.field.ofb_field
487 assert (action.set_field.field.oxm_class ==
488 OFPXMC_OPENFLOW_BASIC)
489 self.log.info('action-type-set-field',
490 field=_field, in_port=_in_port)
491 if _field.type == fd.VLAN_VID:
492 _set_vlan_vid = _field.vlan_vid & 0xfff
493 self.log.info('set-field-type-valn-vid', _set_vlan_vid)
494 else:
495 self.log.error('unsupported-action-set-field-type',
496 field_type=_field.type)
497 else:
Chip Bolinge84aca92018-03-27 11:45:56 -0700498 self.log.error('unsupported-action-type',
499 action_type=action.type, in_port=_in_port)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600500 #
501 # All flows created from ONU adapter should be OMCI based
502 #
503 if _vlan_vid == 0 and _set_vlan_vid != None and _set_vlan_vid != 0:
504 # allow priority tagged packets
505 # Set AR - ExtendedVlanTaggingOperationConfigData
506 # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
507
508 results = yield omci.send_delete_vlan_tagging_filter_data(0x2102)
509
510 # self.send_set_vlan_tagging_filter_data(0x2102, _set_vlan_vid)
511 results = yield omci.send_create_vlan_tagging_filter_data(
512 0x2102,
513 _set_vlan_vid)
514
515 results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_untagged(
516 0x202,
517 0x1000,
518 _set_vlan_vid)
519
520 results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(
521 0x202,
522 8,
523 0,
524 0,
525 1,
526 8,
527 _set_vlan_vid)
528
529 # Set AR - ExtendedVlanTaggingOperationConfigData
530 # 514 - RxVlanTaggingOperationTable - add VLAN <cvid> to priority tagged pkts - c-vid
531 '''
532 results = yield omci.send_set_extended_vlan_tagging_operation_vlan_configuration_data_single_tag(0x205, 8, 0, 0,
533
534 '''
535
536 except Exception as e:
Chip Bolinge84aca92018-03-27 11:45:56 -0700537 self.log.exception('failed-to-install-flow', e=e, flow=flow)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600538
539 @inlineCallbacks
540 def reboot(self):
Chip Bolingfd1fd372017-12-20 13:34:12 -0600541 self.log.info('rebooting', device_id=self.device_id)
542 self._cancel_deferred()
543
Chip Boling0f19f4e2018-02-13 09:27:30 -0600544 reregister = True
545 try:
546 # Drop registration for adapter messages
547 self.adapter_agent.unregister_for_inter_adapter_messages()
548
549 except KeyError:
550 reregister = False
Chip Bolingfd1fd372017-12-20 13:34:12 -0600551
552 # Update the operational status to ACTIVATING and connect status to
553 # UNREACHABLE
554 device = self.adapter_agent.get_device(self.device_id)
Chip Boling0f19f4e2018-02-13 09:27:30 -0600555
Chip Bolingfd1fd372017-12-20 13:34:12 -0600556 previous_oper_status = device.oper_status
557 previous_conn_status = device.connect_status
Chip Boling0f19f4e2018-02-13 09:27:30 -0600558
Chip Bolingfd1fd372017-12-20 13:34:12 -0600559 device.oper_status = OperStatus.ACTIVATING
560 device.connect_status = ConnectStatus.UNREACHABLE
Chip Boling0f19f4e2018-02-13 09:27:30 -0600561 device.reason = 'Attempting reboot'
Chip Bolingfd1fd372017-12-20 13:34:12 -0600562 self.adapter_agent.update_device(device)
563
Chip Bolingfd1fd372017-12-20 13:34:12 -0600564 # TODO: send alert and clear alert after the reboot
Chip Bolingfd1fd372017-12-20 13:34:12 -0600565
Chip Boling0f19f4e2018-02-13 09:27:30 -0600566 if not self.is_mock:
567 from twisted.internet.defer import TimeoutError
568
569 try:
570 ######################################################
571 # MIB Reset - For ADTRAN ONU, we do not get a response
572 # back (because we are rebooting)
573 pass
574 yield self.omci.send_reboot(timeout=0.1)
575
576 except TimeoutError:
577 # This is expected
578 returnValue('reboot-in-progress')
579
580 except Exception as e:
581 self.log.exception('send-reboot', e=e)
582 raise
583
584 # Reboot in progress. A reboot may take up to 3 min 30 seconds
585 # Go ahead and pause less than that and start to look
586 # for it being alive
587
588 device.reason = 'reboot in progress'
589 self.adapter_agent.update_device(device)
590
591 self._deferred = reactor.callLater(_ONU_REBOOT_MIN,
592 self._finish_reboot,
593 previous_oper_status,
594 previous_conn_status,
595 reregister)
596
597 @inlineCallbacks
598 def _finish_reboot(self, previous_oper_status, previous_conn_status,
599 reregister):
600 from common.utils.asleep import asleep
601
602 if not self.is_mock:
603 # TODO: Do a simple poll and call this again if we timeout
604 # _ONU_REBOOT_RETRY
605 yield asleep(180) # 3 minutes ...
Chip Bolingfd1fd372017-12-20 13:34:12 -0600606
607 # Change the operational status back to its previous state. With a
608 # real OLT the operational state should be the state the device is
609 # after a reboot.
610 # Get the latest device reference
611 device = self.adapter_agent.get_device(self.device_id)
Chip Boling0f19f4e2018-02-13 09:27:30 -0600612
Chip Bolingfd1fd372017-12-20 13:34:12 -0600613 device.oper_status = previous_oper_status
614 device.connect_status = previous_conn_status
Chip Boling8536d1b2018-01-19 12:44:54 -0600615 device.reason = ''
Chip Bolingfd1fd372017-12-20 13:34:12 -0600616 self.adapter_agent.update_device(device)
Chip Boling0f19f4e2018-02-13 09:27:30 -0600617
618 if reregister:
619 self.adapter_agent.register_for_inter_adapter_messages()
620
621 self.log.info('reboot-complete', device_id=self.device_id)
622
Chip Bolingfd1fd372017-12-20 13:34:12 -0600623 def self_test_device(self, device):
624 """
625 This is called to Self a device based on a NBI call.
626 :param device: A Voltha.Device object.
627 :return: Will return result of self test
628 """
629 from voltha.protos.voltha_pb2 import SelfTestResponse
630 self.log.info('self-test-device', device=device.id)
631 # TODO: Support self test?
632 return SelfTestResponse(result=SelfTestResponse.NOT_SUPPORTED)
633
634 def disable(self):
635 self.log.info('disabling', device_id=self.device_id)
636 self.enabled = False
637
638 # Get the latest device reference
639 device = self.adapter_agent.get_device(self.device_id)
640
641 # Disable all ports on that device
642 self.adapter_agent.disable_all_ports(self.device_id)
643
644 # Update the device operational status to UNKNOWN
645 device.oper_status = OperStatus.UNKNOWN
646 device.connect_status = ConnectStatus.UNREACHABLE
Chip Boling8536d1b2018-01-19 12:44:54 -0600647 device.reason = 'Disabled'
Chip Bolingfd1fd372017-12-20 13:34:12 -0600648 self.adapter_agent.update_device(device)
649
650 # Remove the uni logical port from the OLT, if still present
651 parent_device = self.adapter_agent.get_device(device.parent_id)
652 assert parent_device
653 logical_device_id = parent_device.parent_id
654 assert logical_device_id
655
656 for uni in self.uni_ports:
657 port_id = 'uni-{}'.format(uni.port_number)
658
659 try:
660 port = self.adapter_agent.get_logical_port(logical_device_id,
661 port_id)
662 self.adapter_agent.delete_logical_port(logical_device_id, port)
663 except KeyError:
664 self.log.info('logical-port-not-found', device_id=self.device_id,
665 portid=port_id)
666
667 # Remove pon port from parent
Chip Bolinge84aca92018-03-27 11:45:56 -0700668 if self._pon is not None:
Chip Bolingfd1fd372017-12-20 13:34:12 -0600669 self.adapter_agent.delete_port_reference_from_parent(self.device_id,
Chip Bolinge84aca92018-03-27 11:45:56 -0700670 self._pon.get_port())
Chip Bolingfd1fd372017-12-20 13:34:12 -0600671
672 # Just updating the port status may be an option as well
673 # port.ofp_port.config = OFPPC_NO_RECV
674 # yield self.adapter_agent.update_logical_port(logical_device_id,
675 # port)
676 # Unregister for proxied message
677 self.adapter_agent.unregister_for_proxied_messages(
678 device.proxy_address)
679
680 # TODO:
681 # 1) Remove all flows from the device
682 # 2) Remove the device from ponsim
683
684 self.log.info('disabled', device_id=device.id)
685
686 def reenable(self):
687 self.log.info('re-enabling', device_id=self.device_id)
688 try:
689 # Get the latest device reference
690 device = self.adapter_agent.get_device(self.device_id)
691 self._cancel_deferred()
692
693 # First we verify that we got parent reference and proxy info
694 assert device.parent_id
695 assert device.proxy_address.device_id
696 # assert device.proxy_address.channel_id
697
698 # Re-register for proxied messages right away
699 self.proxy_address = device.proxy_address
700 self.adapter_agent.register_for_proxied_messages(
701 device.proxy_address)
702
703 # Re-enable the ports on that device
704 self.adapter_agent.enable_all_ports(self.device_id)
705
706 # Refresh the port reference
707 # self.uni_port = self._get_uni_port() deprecated
708
709 # Add the pon port reference to the parent
Chip Bolinge84aca92018-03-27 11:45:56 -0700710 if self._pon is not None:
Chip Bolingfd1fd372017-12-20 13:34:12 -0600711 # TODO: Send 'enable' to PonPort?
712 self.adapter_agent.add_port_reference_to_parent(device.id,
Chip Bolinge84aca92018-03-27 11:45:56 -0700713 self._pon.get_port())
Chip Bolingfd1fd372017-12-20 13:34:12 -0600714
715 # Update the connect status to REACHABLE
716 device.connect_status = ConnectStatus.REACHABLE
717 self.adapter_agent.update_device(device)
718
719 # re-add uni port to logical device
720 parent_device = self.adapter_agent.get_device(device.parent_id)
721 self.logical_device_id = parent_device.parent_id
722 assert self.logical_device_id, 'Invalid logical device ID'
723
724 if self.olt_created:
725 # vlan non-zero if created via legacy method (not xPON)
726 self.uni_port('deprecated').add_logical_port(device.vlan, device.vlan,
Chip Bolinge84aca92018-03-27 11:45:56 -0700727 subscriber_vlan=device.vlan)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600728
729 device = self.adapter_agent.get_device(device.id)
730 device.oper_status = OperStatus.ACTIVE
Chip Boling8536d1b2018-01-19 12:44:54 -0600731 device.reason = ''
Chip Bolingfd1fd372017-12-20 13:34:12 -0600732
733 self.enabled = True
734 self.adapter_agent.update_device(device)
735
736 self.log.info('re-enabled', device_id=device.id)
737 except Exception, e:
738 self.log.exception('error-reenabling', e=e)
739
740 def delete(self):
741 self.log.info('deleting', device_id=self.device_id)
Chip Bolinge84aca92018-03-27 11:45:56 -0700742
Chip Bolingf6954aa2018-04-18 10:30:51 -0500743 for uni in self._unis.itervalues():
744 uni.stop()
745 uni.delete()
746
747 self._pon.stop()
748 self._pon.delete()
749
Chip Bolinge84aca92018-03-27 11:45:56 -0700750 # OpenOMCI cleanup
751 if self._omci_agent is not None:
752 self._omci_agent.remove_device(self.device_id, cleanup=True)
Chip Bolinge84aca92018-03-27 11:45:56 -0700753 self._omci_agent = None
Chip Bolingf6954aa2018-04-18 10:30:51 -0500754
Chip Boling0f19f4e2018-02-13 09:27:30 -0600755 #
756 # handling needed here
757 # self.enabled = False
758 #
759 # # TODO: Need to implement this
760 # # 1) Remove all flows from the device
761 #
762 # self.log.info('deleted', device_id=self.device_id)
763 #
764 # # Drop device ID
765 # self.device_id = None @inlineCallbacks
766 # def delete_v_ont_ani(self, data):
767 # self.log.info('deleting-v_ont_ani')
768 #
769 # device = self.adapter_agent.get_device(self.device_id)
770 # # construct message
771 # # MIB Reset - OntData - 0
772 # if device.connect_status != ConnectStatus.REACHABLE:
773 # self.log.error('device-unreachable')
774 # returnValue(None)
775 #
776 # self.send_mib_reset()
777 # yield self.wait_for_response()
778 # self.proxy_address = device.proxy_address
779 # self.adapter_agent.unregister_for_proxied_messages(device.proxy_address)
780 #
781 # ports = self.adapter_agent.get_ports(self.device_id, Port.PON_ONU)
782 # if ports is not None:
783 # for port in ports:
784 # if port.label == 'PON port':
785 # self.adapter_agent.delete_port(self.device_id, port)
786 # break
Chip Bolingfd1fd372017-12-20 13:34:12 -0600787
788 def _check_for_mock_config(self, data):
789 # Check for MOCK configuration
790 description = data.get('description')
Chip Bolinge84aca92018-03-27 11:45:56 -0700791 if description is not None and 'mock' in description.lower():
Chip Bolingfd1fd372017-12-20 13:34:12 -0600792 self._is_mock = True
793
794 def on_ont_ani_create(self, ont_ani):
795 """
796 A new ONT-ani is being created. You can override this method to
797 perform custom operations as needed. If you override this method, you can add
798 additional items to the item dictionary to track additional implementation
799 key/value pairs.
800
801 :param ont_ani: (dict) new ONT-ani
802 :return: (dict) Updated ONT-ani dictionary, None if item should be deleted
803 """
804 self.log.info('ont-ani-create', ont_ani=ont_ani)
805
806 self._check_for_mock_config(ont_ani)
807 self.enabled = ont_ani['enabled']
808
809 return ont_ani # Implement in your OLT, if needed
810
811 def on_ont_ani_modify(self, ont_ani, update, diffs):
812 """
813 A existing ONT-ani is being updated. You can override this method to
814 perform custom operations as needed. If you override this method, you can add
815 additional items to the item dictionary to track additional implementation
816 key/value pairs.
817
818 :param ont_ani: (dict) existing ONT-ani item dictionary
819 :param update: (dict) updated (changed) ONT-ani
820 :param diffs: (dict) collection of items different in the update
821 :return: (dict) Updated ONT-ani dictionary, None if item should be deleted
822 """
823 valid_keys = ['enabled', 'mgnt-gemport-aes'] # Modify of these keys supported
824
825 invalid_key = next((key for key in diffs.keys() if key not in valid_keys), None)
826 if invalid_key is not None:
827 raise KeyError("ont_ani leaf '{}' is read-only or write-once".format(invalid_key))
828
829 keys = [k for k in diffs.keys() if k in valid_keys]
830
831 for k in keys:
832 if k == 'enabled':
833 self.enabled = update[k]
834
835 elif k == 'mgnt-gemport-aes':
836 self.mgmt_gemport_aes = update[k]
837
838 return update
839
840 def on_ont_ani_delete(self, ont_ani):
841 """
842 A existing ONT-ani is being deleted. You can override this method to
843 perform custom operations as needed. If you override this method, you can add
844 additional items to the item dictionary to track additional implementation
845 key/value pairs.
846
847 :param ont_ani: (dict) ONT-ani to delete
848 :return: (dict) None if item should be deleted
849 """
850 # TODO: Is this ever called or is the iAdapter 'delete' called first?
851 return None # Implement in your OLT, if needed
852
853 def on_vont_ani_create(self, vont_ani):
854 self.log.info('vont-ani-create', vont_ani=vont_ani)
855
856 self._check_for_mock_config(vont_ani)
857 # TODO: look up PON port and update 'upstream-channel-speed'
858 return vont_ani # Implement in your OLT, if needed
859
860 def on_vont_ani_modify(self, vont_ani, update, diffs):
861 valid_keys = ['upstream-channel-speed'] # Modify of these keys supported
862
863 invalid_key = next((key for key in diffs.keys() if key not in valid_keys), None)
864 if invalid_key is not None:
865 raise KeyError("vont_ani leaf '{}' is read-only or write-once".format(invalid_key))
866
867 keys = [k for k in diffs.keys() if k in valid_keys]
868
869 for k in keys:
870 if k == 'upstream-channel-speed':
871 self.upstream_channel_speed = update[k]
872
873 return update
874
875 def on_vont_ani_delete(self, vont_ani):
Chip Boling0f19f4e2018-02-13 09:27:30 -0600876 return self.delete()
Chip Bolingfd1fd372017-12-20 13:34:12 -0600877
878 def on_venet_create(self, venet):
879 self.log.info('venet-create', venet=venet)
880
881 self._check_for_mock_config(venet)
882
883 # TODO: This first set is copied over from BroadCOM ONU. For testing, actual work
884 # is the last 7 lines. The 'test' code below assumes we have not registered
885 # any UNI ports during 'activate' but we want to create them as the vEnet
886 # information comes in.
887 # onu_device = self.adapter_agent.get_device(self.device_id)
888 # existing_uni_ports = self.adapter_agent.get_ports(onu_device.parent_id, Port.ETHERNET_UNI)
889 #
890 # parent_port_num = None
891 # for uni in existing_uni_ports:
892 # if uni.label == venet['name']: # TODO: was -> data.interface.name:
893 # parent_port_num = uni.port_no
894 # break
895 #
896 # # Create both the physical and logical ports for the UNI now
897 # parent_device = self.adapter_agent.get_device(onu_device.parent_id)
898 # logical_device_id = parent_device.parent_id
899 # assert logical_device_id, 'Invalid logical device ID'
900 # # self.add_uni_port(onu_device, logical_device_id, venet['name'], parent_port_num)
901 #
902 # pon_ports = self.adapter_agent.get_ports(self.device_id, Port.PON_ONU)
903 # if pon_ports:
904 # # TODO: Assumed only one PON port and UNI port per ONU.
905 # pon_port = pon_ports[0]
906 # else:
907 # self.log.error("No-Pon-port-configured-yet")
908 # return
909 #
910 # self.adapter_agent.delete_port_reference_from_parent(self.device_id, pon_port)
911 # pon_port.peers[0].device_id = onu_device.parent_id
912 # pon_port.peers[0].port_no = parent_port_num
913 # self.adapter_agent.add_port_reference_to_parent(self.device_id, pon_port)
914
915 #################################################################################
916 # Start of actual work (what actually does something)
917 # TODO: Clean this up. Use looked up UNI
918
919 if self._olt_created:
920 uni_port = self.uni_port('deprecated')
921
922 else:
923 # vlan non-zero if created via legacy method (not xPON). Also
924 # Set a random serial number since not xPON based
925
926 device = self.adapter_agent.get_device(self.device_id)
Chip Bolinge84aca92018-03-27 11:45:56 -0700927 ofp_port_no, subscriber_vlan, untagged_vlan = UniPort.decode_venet(venet)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600928
929 uni_port = UniPort.create(self, venet['name'],
930 self._next_port_number,
Chip Bolinge84aca92018-03-27 11:45:56 -0700931 ofp_port_no,
932 subscriber_vlan,
933 untagged_vlan)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600934
935 self._unis[uni_port.port_number] = uni_port
936 self.adapter_agent.add_port(device.id, uni_port.get_port())
937
Chip Bolinge84aca92018-03-27 11:45:56 -0700938 # If the PON has already synchronized, add the logical port now
939 # since we know we have been activated
940
941 if self._pon is not None and self._pon.connected:
942 uni_port.add_logical_port(ofp_port_no, subscriber_vlan=subscriber_vlan)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600943
944 # TODO: Next is just for debugging to see what this call returns after
945 # we add a UNI
946 # existing_uni_ports = self.adapter_agent.get_ports(onu_device.parent_id, Port.ETHERNET_UNI)
947
948 uni_port.enabled = venet['enabled']
949
950 return venet
951
952 def on_venet_modify(self, venet, update, diffs):
953 # Look up the associated UNI port
954
955 if self._olt_created:
956 uni_port = self.uni_port('deprecated')
957 else:
958 uni_port = self.uni_port(venet['name'])
959
960 if uni_port is not None:
961 valid_keys = ['enabled'] # Modify of these keys supported
962
963 invalid_key = next((key for key in diffs.keys() if key not in valid_keys), None)
964 if invalid_key is not None:
965 raise KeyError("venet leaf '{}' is read-only or write-once".format(invalid_key))
966
967 keys = [k for k in diffs.keys() if k in valid_keys]
968
969 for k in keys:
970 if k == 'enabled':
971 uni_port.enabled = update[k]
972
973 return update
974
975 def on_venet_delete(self, venet):
976 # Look up the associated UNI port
977
978 if self._olt_created:
979 uni_port = self.uni_port('deprecated')
980 else:
981 uni_port = self.uni_port(venet['name'])
982
983 if uni_port is not None:
984 port_no = uni_port.port_number
985 del self._unis[port_no]
986 uni_port.delete()
987 self._release_port_number(port_no)
988
989 return None
990
991 def on_tcont_create(self, tcont):
992 from onu_tcont import OnuTCont
993
994 self.log.info('create-tcont')
995
996 td = self.traffic_descriptors.get(tcont.get('td-ref'))
997 traffic_descriptor = td['object'] if td is not None else None
Chip Boling8536d1b2018-01-19 12:44:54 -0600998 tcont['object'] = OnuTCont.create(self, tcont, traffic_descriptor,
999 is_mock=self.is_mock)
Chip Bolingfd1fd372017-12-20 13:34:12 -06001000
Chip Bolinge84aca92018-03-27 11:45:56 -07001001 if self._pon is not None:
1002 self._pon.add_tcont(tcont['object'])
Chip Bolingfd1fd372017-12-20 13:34:12 -06001003
1004 return tcont
1005
1006 def on_tcont_modify(self, tcont, update, diffs):
1007 valid_keys = ['td-ref'] # Modify of these keys supported
1008
1009 invalid_key = next((key for key in diffs.keys() if key not in valid_keys), None)
1010 if invalid_key is not None:
1011 raise KeyError("TCONT leaf '{}' is read-only or write-once".format(invalid_key))
1012
1013 tc = tcont.get('object')
1014 assert tc is not None, 'TCONT not found'
1015
1016 update['object'] = tc
1017
Chip Bolinge84aca92018-03-27 11:45:56 -07001018 if self._pon is not None:
Chip Bolingfd1fd372017-12-20 13:34:12 -06001019 keys = [k for k in diffs.keys() if k in valid_keys]
1020
1021 for k in keys:
1022 if k == 'td-ref':
1023 td = self.traffic_descriptors.get(update['td-ref'])
1024 if td is not None:
Chip Bolinge84aca92018-03-27 11:45:56 -07001025 self._pon.update_tcont_td(tcont['alloc-id'], td)
Chip Bolingfd1fd372017-12-20 13:34:12 -06001026
1027 return update
1028
1029 def on_tcont_delete(self, tcont):
Chip Bolinge84aca92018-03-27 11:45:56 -07001030 if self._pon is not None:
1031 self._pon.remove_tcont(tcont['alloc-id'])
Chip Bolingfd1fd372017-12-20 13:34:12 -06001032
1033 return None
1034
1035 def on_td_create(self, traffic_disc):
1036 from onu_traffic_descriptor import OnuTrafficDescriptor
1037
1038 traffic_disc['object'] = OnuTrafficDescriptor.create(traffic_disc)
1039 return traffic_disc
1040
1041 def on_td_modify(self, traffic_disc, update, diffs):
1042 from onu_traffic_descriptor import OnuTrafficDescriptor
1043
1044 valid_keys = ['fixed-bandwidth',
1045 'assured-bandwidth',
1046 'maximum-bandwidth',
1047 'priority',
1048 'weight',
1049 'additional-bw-eligibility-indicator']
1050 invalid_key = next((key for key in diffs.keys() if key not in valid_keys), None)
1051 if invalid_key is not None:
1052 raise KeyError("traffic-descriptor leaf '{}' is read-only or write-once".format(invalid_key))
1053
1054 # New traffic descriptor
1055 update['object'] = OnuTrafficDescriptor.create(update)
1056
1057 td_name = traffic_disc['name']
1058 tconts = {key: val for key, val in self.tconts.iteritems()
1059 if val['td-ref'] == td_name and td_name is not None}
1060
1061 for tcont in tconts.itervalues():
Chip Bolinge84aca92018-03-27 11:45:56 -07001062 if self._pon is not None:
1063 self._pon.update_tcont_td(tcont['alloc-id'], update['object'])
Chip Bolingfd1fd372017-12-20 13:34:12 -06001064
1065 return update
1066
1067 def on_td_delete(self, traffic_desc):
1068 # TD may be used by more than one TCONT. Only delete if the last one
1069
1070 td_name = traffic_desc['name']
1071 num_tconts = len([val for val in self.tconts.itervalues()
1072 if val['td-ref'] == td_name and td_name is not None])
1073
1074 return None if num_tconts <= 1 else traffic_desc
1075
1076 def on_gemport_create(self, gem_port):
1077 from onu_gem_port import OnuGemPort
Chip Bolinge84aca92018-03-27 11:45:56 -07001078 assert self._pon is not None, 'No PON port'
Chip Bolingfd1fd372017-12-20 13:34:12 -06001079
Chip Bolinge84aca92018-03-27 11:45:56 -07001080 gem_port['object'] = OnuGemPort.create(self, gem_port,
1081 self._pon.next_gem_entity_id,
1082 is_mock=self.is_mock)
1083 self._pon.add_gem_port(gem_port['object'])
Chip Bolingfd1fd372017-12-20 13:34:12 -06001084 return gem_port
1085
1086 def on_gemport_modify(self, gem_port, update, diffs):
1087 valid_keys = ['encryption',
1088 'traffic-class'] # Modify of these keys supported
1089
1090 invalid_key = next((key for key in diffs.keys() if key not in valid_keys), None)
1091 if invalid_key is not None:
1092 raise KeyError("GEM Port leaf '{}' is read-only or write-once".format(invalid_key))
1093
1094 port = gem_port.get('object')
1095 assert port is not None, 'GemPort not found'
1096
1097 keys = [k for k in diffs.keys() if k in valid_keys]
1098 update['object'] = port
1099
1100 for k in keys:
1101 if k == 'encryption':
1102 port.encryption = update[k]
1103 elif k == 'traffic-class':
1104 pass # TODO: Implement
1105
1106 return update
1107
1108 def on_gemport_delete(self, gem_port):
Chip Bolinge84aca92018-03-27 11:45:56 -07001109 if self._pon is not None:
1110 self._pon.remove_gem_id(gem_port['gemport-id'])
Chip Bolingfd1fd372017-12-20 13:34:12 -06001111
1112 return None
1113
1114 def on_mcast_gemport_create(self, mcast_gem_port):
1115 return mcast_gem_port # Implement in your OLT, if needed
1116
1117 def on_mcast_gemport_modify(self, mcast_gem_port, update, diffs):
1118 return mcast_gem_port # Implement in your OLT, if needed
1119
1120 def on_mcast_gemport_delete(self, mcast_gem_port):
1121 return None # Implement in your OLT, if needed
1122
1123 def on_mcast_dist_set_create(self, dist_set):
1124 return dist_set # Implement in your OLT, if needed
1125
1126 def on_mcast_dist_set_modify(self, dist_set, update, diffs):
1127 return update # Implement in your OLT, if needed
1128
1129 def on_mcast_dist_set_delete(self, dist_set):
1130 return None # Implement in your OLT, if needed
1131
1132 def rx_inter_adapter_message(self, msg):
1133 if self.enabled and self._event_messages is not None:
1134 self._event_messages.put(msg)
1135
1136 @inlineCallbacks
1137 def _handle_onu_events(self):
1138 #
1139 # TODO: From broadcom ONU. This is from the 'receive_inter_adapter_message()'
1140 # method.
1141 #
1142 event_msg = yield self._event_messages.get()
1143
1144 if self._event_deferred is None:
1145 returnValue('cancelled')
1146
1147 if event_msg['event'] == 'activation-completed':
1148 # if event_msg['event_data']['activation_successful']:
1149 # for uni in self.uni_ports:
1150 # port_no = self.proxy_address.channel_id + uni
1151 # reactor.callLater(1,
1152 # self.message_exchange,
1153 # self.proxy_address.onu_id,
1154 # self.proxy_address.onu_session_id,
1155 # port_no)
1156 #
1157 # device = self.adapter_agent.get_device(self.device_id)
1158 # device.oper_status = OperStatus.ACTIVE
1159 # self.adapter_agent.update_device(device)
1160 #
1161 # else:
1162 # device = self.adapter_agent.get_device(self.device_id)
1163 # device.oper_status = OperStatus.FAILED
1164 # self.adapter_agent.update_device(device)
1165 pass
1166
1167 elif event_msg['event'] == 'deactivation-completed':
1168 # device = self.adapter_agent.get_device(self.device_id)
1169 # device.oper_status = OperStatus.DISCOVERED
1170 # self.adapter_agent.update_device(device)
1171 pass
1172
1173 elif event_msg['event'] == 'ranging-completed':
1174 # if event_msg['event_data']['ranging_successful']:
1175 # device = self.adapter_agent.get_device(self.device_id)
1176 # device.oper_status = OperStatus.ACTIVATING
1177 # self.adapter_agent.update_device(device)
1178 #
1179 # else:
1180 # device = self.adapter_agent.get_device(self.device_id)
1181 # device.oper_status = OperStatus.FAILED
1182 # self.adapter_agent.update_device(device)
1183 pass
1184
1185 # Handle next event (self._event_deferred is None if we got stopped)
1186
1187 self._event_deferred = reactor.callLater(0, self.handle_onu_events)