blob: bf7541b0b118d3b41a6bf0c5371ac9dc7725f3ba [file] [log] [blame]
Chip Boling27275992017-09-22 15:17:04 -05001# Copyright 2017-present Adtran, Inc.
Chip Boling3e3b1a92017-05-16 11:51:18 -05002#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
Chip Boling252c7772017-08-16 10:13:17 -05007# http://www.apache.org/licenses/LICENSE-2.0
Chip Boling3e3b1a92017-05-16 11:51:18 -05008#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
Chip Boling252c7772017-08-16 10:13:17 -050014
Chip Boling3e3b1a92017-05-16 11:51:18 -050015import json
Chip Boling3e3b1a92017-05-16 11:51:18 -050016import random
Chip Bolingc0451382018-08-24 14:21:53 -050017import arrow
Chip Boling3e3b1a92017-05-16 11:51:18 -050018
Chip Boling3e3b1a92017-05-16 11:51:18 -050019import structlog
Chip Bolingab8863d2018-03-22 14:50:31 -050020from port import AdtnPort
Chip Boling48646962017-08-20 09:41:18 -050021from twisted.internet import reactor, defer
Chip Bolingbffef5e2018-08-07 14:53:12 -050022from twisted.internet.defer import inlineCallbacks, returnValue
Chip Boling3e3b1a92017-05-16 11:51:18 -050023from adtran_olt_handler import AdtranOltHandler
Chip Bolingfd1fd372017-12-20 13:34:12 -060024from net.adtran_rest import RestInvalidResponseCode
Chip Boling3e3b1a92017-05-16 11:51:18 -050025from codec.olt_config import OltConfig
26from onu import Onu
Chip Bolingbffef5e2018-08-07 14:53:12 -050027from voltha.extensions.alarms.onu.onu_los_alarm import OnuLosAlarm
Chip Boling99c388e2018-11-20 09:33:57 -060028from voltha.extensions.alarms.onu.onu_discovery_alarm import OnuDiscoveryAlarm
Chip Bolingbb15b512018-06-01 11:39:58 -050029from voltha.protos.common_pb2 import AdminState
Chip Boling3e3b1a92017-05-16 11:51:18 -050030from voltha.protos.device_pb2 import Port
Chip Bolingb4868192018-11-01 16:38:44 -050031from voltha.protos.bbf_fiber_tcont_body_pb2 import TcontsConfigData
32from voltha.protos.bbf_fiber_traffic_descriptor_profile_body_pb2 import TrafficDescriptorProfileData
33from voltha.protos.bbf_fiber_gemport_body_pb2 import GemportsConfigData
34from xpon.olt_traffic_descriptor import OltTrafficDescriptor
35import resources.adtranolt_platform as platform
36
Chip Boling3e3b1a92017-05-16 11:51:18 -050037
Chip Bolingab8863d2018-03-22 14:50:31 -050038class PonPort(AdtnPort):
Chip Boling3e3b1a92017-05-16 11:51:18 -050039 """
Chip Bolingab8863d2018-03-22 14:50:31 -050040 GPON Port
Chip Boling3e3b1a92017-05-16 11:51:18 -050041 """
Chip Bolingb4868192018-11-01 16:38:44 -050042 MAX_ONUS_SUPPORTED = 128
Chip Bolingfd1fd372017-12-20 13:34:12 -060043 MAX_DEPLOYMENT_RANGE = 25000 # Meters (OLT-PB maximum)
Chip Boling27275992017-09-22 15:17:04 -050044
45 _MCAST_ONU_ID = 253
46 _MCAST_ALLOC_BASE = 0x500
Chip Boling3e3b1a92017-05-16 11:51:18 -050047
Chip Boling88354fb2018-09-21 12:17:19 -050048 # AutoActivate should be used if xPON configuration is not supported
49 _SUPPORTED_ACTIVATION_METHODS = ['autodiscovery', 'autoactivate']
Chip Boling252c7772017-08-16 10:13:17 -050050 _SUPPORTED_AUTHENTICATION_METHODS = ['serial-number']
51
Chip Bolingab8863d2018-03-22 14:50:31 -050052 def __init__(self, parent, **kwargs):
Chip Bolingab8863d2018-03-22 14:50:31 -050053 super(PonPort, self).__init__(parent, **kwargs)
Chip Bolingab8863d2018-03-22 14:50:31 -050054 assert 'pon-id' in kwargs, 'PON ID not found'
Chip Boling7294b252017-06-15 16:16:55 -050055
56 self._parent = parent
Chip Bolingab8863d2018-03-22 14:50:31 -050057 self._pon_id = kwargs['pon-id']
58 self.log = structlog.get_logger(device_id=parent.device_id, pon_id=self._pon_id)
59 self._port_no = kwargs['port_no']
Chip Boling3eedf462018-10-17 12:18:28 -050060 self._physical_port_name = 'xpon 0/{}'.format(self._pon_id+1)
Chip Bolingab8863d2018-03-22 14:50:31 -050061 self._label = 'pon-{}'.format(self._pon_id)
62
Chip Boling27275992017-09-22 15:17:04 -050063 self._in_sync = False
Chip Bolingdb61c6a2017-09-27 12:36:45 -050064 self._expedite_sync = False
65 self._expedite_count = 0
66
Chip Bolingab8863d2018-03-22 14:50:31 -050067 self._discovery_tick = 20.0
68 self._no_onu_discover_tick = self._discovery_tick / 2
69 self._discovered_onus = [] # List of serial numbers
Chip Bolingb4868192018-11-01 16:38:44 -050070 self._discovery_deferred = None # Specifically for ONU discovery
Chip Bolingab8863d2018-03-22 14:50:31 -050071
Chip Boling521735d2018-12-20 09:58:01 -060072 self._onus = {} # serial_number-base64 -> ONU
Chip Bolingb4868192018-11-01 16:38:44 -050073 self._onu_by_id = {} # onu-id -> ONU
74 self._mcast_gem_ports = {} # VLAN -> GemPort
Chip Boling7294b252017-06-15 16:16:55 -050075
Chip Bolingb4868192018-11-01 16:38:44 -050076 self._active_los_alarms = set() # ONU-ID
Chip Boling27275992017-09-22 15:17:04 -050077
Chip Bolingb4868192018-11-01 16:38:44 -050078 # xPON configuration
79 self._activation_method = 'autoactivate'
Chip Boling7294b252017-06-15 16:16:55 -050080
Chip Bolingb4868192018-11-01 16:38:44 -050081 self._downstream_fec_enable = True
82 self._upstream_fec_enable = True
Chip Boling27275992017-09-22 15:17:04 -050083 self._deployment_range = 25000
Chip Boling252c7772017-08-16 10:13:17 -050084 self._authentication_method = 'serial-number'
Chip Bolingfd1fd372017-12-20 13:34:12 -060085 self._mcast_aes = False
Chip Boling3e3b1a92017-05-16 11:51:18 -050086
Chip Bolingfd1fd372017-12-20 13:34:12 -060087 # Statistics
Chip Bolingfd1fd372017-12-20 13:34:12 -060088 self.tx_bip_errors = 0
89
Chip Boling3e3b1a92017-05-16 11:51:18 -050090 def __str__(self):
Chip Boling252c7772017-08-16 10:13:17 -050091 return "PonPort-{}: Admin: {}, Oper: {}, OLT: {}".format(self._label,
92 self._admin_state,
93 self._oper_status,
94 self.olt)
Chip Boling3e3b1a92017-05-16 11:51:18 -050095
96 def get_port(self):
97 """
98 Get the VOLTHA PORT object for this port
99 :return: VOLTHA Port object
100 """
Chip Boling7294b252017-06-15 16:16:55 -0500101 if self._port is None:
102 self._port = Port(port_no=self._port_no,
103 label=self._label,
104 type=Port.PON_OLT,
Chip Bolingc64c8dc2018-04-20 14:42:24 -0500105 admin_state=self._admin_state,
106 oper_status=self._oper_status)
107
Chip Boling7294b252017-06-15 16:16:55 -0500108 return self._port
Chip Boling3e3b1a92017-05-16 11:51:18 -0500109
110 @property
Chip Boling3e3b1a92017-05-16 11:51:18 -0500111 def pon_id(self):
Chip Boling7294b252017-06-15 16:16:55 -0500112 return self._pon_id
113
114 @property
Chip Bolingfd1fd372017-12-20 13:34:12 -0600115 def onus(self):
116 """
117 Get a set of all ONUs. While the set is immutable, do not use this method
118 to get a collection that you will iterate through that my yield the CPU
119 such as inline callback. ONUs may be deleted at any time and they will
120 set some references to other objects to NULL during the 'delete' call.
121 Instead, get a list of ONU-IDs and iterate on these and call the 'onu'
122 method below (which will return 'None' if the ONU has been deleted.
123
124 :return: (frozenset) collection of ONU objects on this PON
125 """
126 return frozenset(self._onus.values())
127
128 @property
129 def onu_ids(self):
130 return frozenset(self._onu_by_id.keys())
131
Chip Bolingef0e2fa2017-10-06 14:33:01 -0500132 def onu(self, onu_id):
133 return self._onu_by_id.get(onu_id)
134
Chip Boling7294b252017-06-15 16:16:55 -0500135 @property
Chip Bolingfd1fd372017-12-20 13:34:12 -0600136 def in_service_onus(self):
137 return len({onu.onu_id for onu in self.onus
138 if onu.onu_id not in self._active_los_alarms})
139
140 @property
141 def closest_onu_distance(self):
142 distance = -1
143 for onu in self.onus:
144 if onu.fiber_length < distance or distance == -1:
145 distance = onu.fiber_length
146 return distance
147
148 @property
Chip Boling27275992017-09-22 15:17:04 -0500149 def downstream_fec_enable(self):
150 return self._downstream_fec_enable
151
152 @downstream_fec_enable.setter
153 def downstream_fec_enable(self, value):
154 assert isinstance(value, bool), 'downstream FEC enabled is a boolean'
155
156 if self._downstream_fec_enable != value:
157 self._downstream_fec_enable = value
Chip Bolingab8863d2018-03-22 14:50:31 -0500158 if self.state == AdtnPort.State.RUNNING:
159 self.deferred = self._set_pon_config("downstream-fec-enable", value)
Chip Boling27275992017-09-22 15:17:04 -0500160
161 @property
162 def upstream_fec_enable(self):
163 return self._upstream_fec_enable
164
165 @upstream_fec_enable.setter
166 def upstream_fec_enable(self, value):
167 assert isinstance(value, bool), 'upstream FEC enabled is a boolean'
Chip Boling27275992017-09-22 15:17:04 -0500168 if self._upstream_fec_enable != value:
169 self._upstream_fec_enable = value
Chip Bolingab8863d2018-03-22 14:50:31 -0500170 if self.state == AdtnPort.State.RUNNING:
171 self.deferred = self._set_pon_config("upstream-fec-enable", value)
Chip Boling27275992017-09-22 15:17:04 -0500172
173 @property
Chip Bolingfd1fd372017-12-20 13:34:12 -0600174 def any_upstream_fec_enabled(self):
175 for onu in self.onus:
176 if onu.upstream_fec_enable and onu.enabled:
177 return True
178 return False
179
180 @property
181 def mcast_aes(self):
182 return self._mcast_aes
183
184 @mcast_aes.setter
185 def mcast_aes(self, value):
186 assert isinstance(value, bool), 'MCAST AES is a boolean'
187 if self._mcast_aes != value:
188 self._mcast_aes = value
Chip Bolingab8863d2018-03-22 14:50:31 -0500189 if self.state == AdtnPort.State.RUNNING:
Chip Bolingfd1fd372017-12-20 13:34:12 -0600190 pass # TODO
191
192 @property
Chip Boling27275992017-09-22 15:17:04 -0500193 def deployment_range(self):
194 """Maximum deployment range (in meters)"""
195 return self._deployment_range
196
197 @deployment_range.setter
198 def deployment_range(self, value):
199 """Maximum deployment range (in meters)"""
200 if not 0 <= value <= PonPort.MAX_DEPLOYMENT_RANGE:
201 raise ValueError('Deployment range should be 0..{} meters'.
202 format(PonPort.MAX_DEPLOYMENT_RANGE))
203 if self._deployment_range != value:
204 self._deployment_range = value
Chip Bolingab8863d2018-03-22 14:50:31 -0500205 if self.state == AdtnPort.State.RUNNING:
206 self.deferred = self._set_pon_config("deployment-range", value)
Chip Boling27275992017-09-22 15:17:04 -0500207
208 @property
Chip Boling252c7772017-08-16 10:13:17 -0500209 def discovery_tick(self):
210 return self._discovery_tick * 10
211
212 @discovery_tick.setter
213 def discovery_tick(self, value):
214 if value < 0:
215 raise ValueError("Polling interval must be >= 0")
216
217 if self.discovery_tick != value:
218 self._discovery_tick = value / 10
219
Chip Boling27275992017-09-22 15:17:04 -0500220 try:
221 if self._discovery_deferred is not None and \
222 not self._discovery_deferred.called:
223 self._discovery_deferred.cancel()
224 except:
225 pass
226 self._discovery_deferred = None
Chip Boling252c7772017-08-16 10:13:17 -0500227
228 if self._discovery_tick > 0:
229 self._discovery_deferred = reactor.callLater(self._discovery_tick,
230 self._discover_onus)
231
232 @property
233 def activation_method(self):
234 return self._activation_method
235
236 @activation_method.setter
237 def activation_method(self, value):
238 value = value.lower()
239 if value not in PonPort._SUPPORTED_ACTIVATION_METHODS:
240 raise ValueError('Invalid ONU activation method')
Chip Boling88354fb2018-09-21 12:17:19 -0500241
Chip Boling252c7772017-08-16 10:13:17 -0500242 self._activation_method = value
243
244 @property
245 def authentication_method(self):
246 return self._authentication_method
247
248 @authentication_method.setter
249 def authentication_method(self, value):
250 value = value.lower()
251 if value not in PonPort._SUPPORTED_AUTHENTICATION_METHODS:
252 raise ValueError('Invalid ONU authentication method')
253 self._authentication_method = value
254
Chip Bolingab8863d2018-03-22 14:50:31 -0500255 def cancel_deferred(self):
256 super(PonPort, self).cancel_deferred()
Chip Boling7294b252017-06-15 16:16:55 -0500257
Chip Bolingab8863d2018-03-22 14:50:31 -0500258 d, self._discovery_deferred = self._discovery_deferred, None
Chip Boling3e3b1a92017-05-16 11:51:18 -0500259
Chip Bolingab8863d2018-03-22 14:50:31 -0500260 try:
261 if d is not None and not d.called:
262 d.cancel()
263 except Exception as e:
264 pass
Chip Boling7294b252017-06-15 16:16:55 -0500265
266 def _update_adapter_agent(self):
Chip Bolingc64c8dc2018-04-20 14:42:24 -0500267 """
268 Update the port status and state in the core
269 """
270 self.log.debug('update-adapter-agent', admin_state=self._admin_state,
Chip Boling3971d242018-06-06 10:26:34 -0500271 oper_status=self._oper_status)
Chip Bolingc64c8dc2018-04-20 14:42:24 -0500272
273 # because the core does not provide methods for updating admin
274 # and oper status per port, we need to copy any existing port
275 # info so that we don't wipe out the peers
276 if self._port is not None:
277 agent_ports = self.adapter_agent.get_ports(self.olt.device_id, Port.PON_OLT)
278
279 agent_port = next((ap for ap in agent_ports if ap.port_no == self._port_no), None)
280
281 # copy current Port info
282 if agent_port is not None:
Chip Boling3971d242018-06-06 10:26:34 -0500283 self._port = agent_port
Chip Bolingc64c8dc2018-04-20 14:42:24 -0500284
285 # set new states
286 self._port.admin_state = self._admin_state
287 self._port.oper_status = self._oper_status
288
289 # adapter_agent add_port also does an update of existing port
290 self.adapter_agent.add_port(self.olt.device_id, self.get_port())
Chip Boling7294b252017-06-15 16:16:55 -0500291
Chip Boling7294b252017-06-15 16:16:55 -0500292 @inlineCallbacks
Chip Bolingab8863d2018-03-22 14:50:31 -0500293 def finish_startup(self):
Chip Boling3e3b1a92017-05-16 11:51:18 -0500294 """
Chip Boling7294b252017-06-15 16:16:55 -0500295 Do all startup offline since REST may fail
Chip Boling3e3b1a92017-05-16 11:51:18 -0500296 """
Chip Bolingab8863d2018-03-22 14:50:31 -0500297 if self.state != AdtnPort.State.INITIAL:
Chip Boling7294b252017-06-15 16:16:55 -0500298 returnValue('Done')
Chip Boling3e3b1a92017-05-16 11:51:18 -0500299
Chip Boling252c7772017-08-16 10:13:17 -0500300 self.log.debug('final-startup')
Chip Bolingab8863d2018-03-22 14:50:31 -0500301 results = None
Chip Boling5561d552017-07-07 15:11:26 -0500302
Chip Boling27275992017-09-22 15:17:04 -0500303 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500304 self.deferred = self._get_pon_config()
305 results = yield self.deferred
Chip Boling27275992017-09-22 15:17:04 -0500306
307 except Exception as e:
308 self.log.exception('initial-GET', e=e)
Chip Bolingab8863d2018-03-22 14:50:31 -0500309 self.deferred = reactor.callLater(5, self.finish_startup)
310 returnValue(self.deferred)
Chip Boling27275992017-09-22 15:17:04 -0500311
312 # Load config from hardware
313
314 enabled = results.get('enabled', False)
315 downstream_fec_enable = results.get('downstream-fec-enable', False)
316 upstream_fec_enable = results.get('upstream-fec-enable', False)
317 deployment_range = results.get('deployment-range', 25000)
318 self._in_sync = True
319
320 if enabled != self._enabled:
Chip Boling7294b252017-06-15 16:16:55 -0500321 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500322 self.deferred = self._set_pon_config("enabled", True)
323 yield self.deferred
Chip Boling3e3b1a92017-05-16 11:51:18 -0500324
Chip Boling7294b252017-06-15 16:16:55 -0500325 except Exception as e:
Chip Boling252c7772017-08-16 10:13:17 -0500326 self.log.exception('final-startup-enable', e=e)
Chip Bolingab8863d2018-03-22 14:50:31 -0500327 self.deferred = reactor.callLater(3, self.finish_startup)
328 returnValue(self.deferred)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500329
Chip Boling27275992017-09-22 15:17:04 -0500330 if downstream_fec_enable != self._downstream_fec_enable:
Chip Boling7294b252017-06-15 16:16:55 -0500331 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500332 self.deferred = self._set_pon_config("downstream-fec-enable",
333 self._downstream_fec_enable)
334 yield self.deferred
Chip Boling3e3b1a92017-05-16 11:51:18 -0500335
Chip Boling7294b252017-06-15 16:16:55 -0500336 except Exception as e:
Chip Boling27275992017-09-22 15:17:04 -0500337 self.log.warning('final-startup-downstream-FEC', e=e)
338 self._in_sync = False
339 # Non-fatal. May have failed due to no SFQ in slot
Chip Boling7294b252017-06-15 16:16:55 -0500340
Chip Boling27275992017-09-22 15:17:04 -0500341 if upstream_fec_enable != self._upstream_fec_enable:
Chip Boling7294b252017-06-15 16:16:55 -0500342 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500343 self.deferred = self._set_pon_config("upstream-fec-enable",
344 self._upstream_fec_enable)
345 yield self.deferred
Chip Boling7294b252017-06-15 16:16:55 -0500346
347 except Exception as e:
Chip Boling27275992017-09-22 15:17:04 -0500348 self.log.warning('final-startup-upstream-FEC', e=e)
349 self._in_sync = False
350 # Non-fatal. May have failed due to no SFQ in slot
Chip Boling7294b252017-06-15 16:16:55 -0500351
Chip Boling27275992017-09-22 15:17:04 -0500352 if deployment_range != self._deployment_range:
353 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500354 self.deferred = self._set_pon_config("deployment-range",
355 self._deployment_range)
356 yield self.deferred
Chip Boling7294b252017-06-15 16:16:55 -0500357
Chip Boling27275992017-09-22 15:17:04 -0500358 except Exception as e:
359 self.log.warning('final-startup-deployment-range', e=e)
360 self._in_sync = False
361 # Non-fatal. May have failed due to no SFQ in slot
Chip Boling7294b252017-06-15 16:16:55 -0500362
Chip Boling27275992017-09-22 15:17:04 -0500363 if len(self._onus) > 0:
364 dl = []
Chip Bolingfd1fd372017-12-20 13:34:12 -0600365 for onu_id in self.onu_ids:
366 onu = self.onu(onu_id)
367 if onu is not None:
368 dl.append(onu.restart())
Chip Boling27275992017-09-22 15:17:04 -0500369 yield defer.gatherResults(dl, consumeErrors=True)
Chip Boling7294b252017-06-15 16:16:55 -0500370
Chip Boling27275992017-09-22 15:17:04 -0500371 # Begin to ONU discovery and hardware sync
Chip Boling3e3b1a92017-05-16 11:51:18 -0500372
Chip Boling27275992017-09-22 15:17:04 -0500373 self._discovery_deferred = reactor.callLater(5, self._discover_onus)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500374
Chip Bolingab8863d2018-03-22 14:50:31 -0500375 # If here, initial settings were successfully written to hardware
376
377 super(PonPort, self).finish_startup()
Chip Boling27275992017-09-22 15:17:04 -0500378 returnValue('Enabled')
Chip Boling7294b252017-06-15 16:16:55 -0500379
Chip Boling9fef0fd2018-12-11 09:43:59 -0600380 @inlineCallbacks
Chip Bolingab8863d2018-03-22 14:50:31 -0500381 def finish_stop(self):
Chip Bolingfd1fd372017-12-20 13:34:12 -0600382 # Remove all existing ONUs. They will need to be re-discovered
Chip Bolingab8863d2018-03-22 14:50:31 -0500383 dl = []
Chip Bolingfd1fd372017-12-20 13:34:12 -0600384 onu_ids = frozenset(self._onu_by_id.keys())
385 for onu_id in onu_ids:
386 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500387 dl.append(self.delete_onu(onu_id))
388
Chip Bolingfd1fd372017-12-20 13:34:12 -0600389 except Exception as e:
390 self.log.exception('onu-cleanup', onu_id=onu_id, e=e)
391
Chip Bolingab8863d2018-03-22 14:50:31 -0500392 dl.append(self._set_pon_config("enabled", False))
Chip Boling9fef0fd2018-12-11 09:43:59 -0600393 results = yield defer.gatherResults(dl, consumeErrors=True)
394 returnValue(results)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500395
396 @inlineCallbacks
397 def reset(self):
Chip Boling7294b252017-06-15 16:16:55 -0500398 """
399 Set the PON Port to a known good state on initial port startup. Actual
400 PON 'Start' is done elsewhere
401 """
Chip Bolingb4868192018-11-01 16:38:44 -0500402 initial_port_state = AdminState.ENABLED
Chip Boling27275992017-09-22 15:17:04 -0500403 self.log.info('reset', initial_state=initial_port_state)
Chip Boling7294b252017-06-15 16:16:55 -0500404
Chip Boling252c7772017-08-16 10:13:17 -0500405 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500406 self.deferred = self._get_pon_config()
407 results = yield self.deferred
Chip Boling27275992017-09-22 15:17:04 -0500408 enabled = results.get('enabled', False)
Chip Boling252c7772017-08-16 10:13:17 -0500409
410 except Exception as e:
Chip Boling27275992017-09-22 15:17:04 -0500411 self.log.exception('get-config', e=e)
412 enabled = False
Chip Boling252c7772017-08-16 10:13:17 -0500413
Chip Boling27275992017-09-22 15:17:04 -0500414 enable = initial_port_state == AdminState.ENABLED
Chip Boling252c7772017-08-16 10:13:17 -0500415
Chip Boling27275992017-09-22 15:17:04 -0500416 if enable != enabled:
Chip Boling3e3b1a92017-05-16 11:51:18 -0500417 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500418 self.deferred = yield self._set_pon_config("enabled", enable)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500419 except Exception as e:
Chip Boling27275992017-09-22 15:17:04 -0500420 self.log.exception('reset-enabled', e=e, enabled=enabled)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500421
Chip Boling27275992017-09-22 15:17:04 -0500422 # TODO: Move to 'set_pon_config' method and also make sure GRPC/Port is ok
423 self._admin_state = AdminState.ENABLED if enable else AdminState.DISABLED
Chip Boling3e3b1a92017-05-16 11:51:18 -0500424
Chip Boling252c7772017-08-16 10:13:17 -0500425 try:
Chip Boling99c388e2018-11-20 09:33:57 -0600426 # Walk the provisioned ONU list and disable any existing ONUs
Chip Boling27275992017-09-22 15:17:04 -0500427 results = yield self._get_onu_config()
Chip Boling3e3b1a92017-05-16 11:51:18 -0500428
Chip Boling252c7772017-08-16 10:13:17 -0500429 if isinstance(results, list) and len(results) > 0:
430 onu_configs = OltConfig.Pon.Onu.decode(results)
Chip Boling27275992017-09-22 15:17:04 -0500431 dl = []
Chip Boling252c7772017-08-16 10:13:17 -0500432 for onu_id in onu_configs.iterkeys():
Chip Boling27275992017-09-22 15:17:04 -0500433 dl.append(self.delete_onu(onu_id))
Chip Boling3e3b1a92017-05-16 11:51:18 -0500434
Chip Boling27275992017-09-22 15:17:04 -0500435 try:
436 if len(dl) > 0:
437 yield defer.gatherResults(dl, consumeErrors=True)
438
439 except Exception as e:
Chip Bolingab8863d2018-03-22 14:50:31 -0500440 self.log.exception('rest-ONU-delete', e=e)
Chip Boling27275992017-09-22 15:17:04 -0500441 pass # Non-fatal
Chip Boling252c7772017-08-16 10:13:17 -0500442
443 except Exception as e:
444 self.log.exception('onu-delete', e=e)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500445
Chip Boling5561d552017-07-07 15:11:26 -0500446 returnValue('Reset complete')
447
Chip Bolingb4868192018-11-01 16:38:44 -0500448 def gem_ids(self, logical_port, flow_vlan, multicast_gems=False):
Chip Boling252c7772017-08-16 10:13:17 -0500449 """
450 Get all GEM Port IDs used on a given PON
451
Chip Bolingb4868192018-11-01 16:38:44 -0500452 :param logical_port: (int) Logical port number of ONU. None if for all ONUs
Chip Bolingab8863d2018-03-22 14:50:31 -0500453 on PON, if Multicast, VID for Multicast, or None for all
Chip Boling27275992017-09-22 15:17:04 -0500454 Multicast GEMPorts
Chip Bolingb4868192018-11-01 16:38:44 -0500455 :param flow_vlan: (int) If not None, this is the ingress tag (c-tag)
Chip Boling27275992017-09-22 15:17:04 -0500456 :param multicast_gems: (boolean) Select from available Multicast GEM Ports
457 :return: (dict) data_gem -> key -> onu-id, value -> tuple(sorted list of GEM Port IDs, onu_vid)
458 mcast_gem-> key -> mcast-vid, value -> GEM Port IDs
Chip Boling252c7772017-08-16 10:13:17 -0500459 """
460 gem_ids = {}
Chip Boling27275992017-09-22 15:17:04 -0500461
462 if multicast_gems:
463 # Multicast GEMs belong to the PON, but we may need to register them on
Chip Bolingb4868192018-11-01 16:38:44 -0500464 # all ONUs. TODO: Rework when BBF MCAST is addressed in VOLTHA v2.O+
465 for vlan, gem_port in self._mcast_gem_ports.iteritems():
Chip Bolingab8863d2018-03-22 14:50:31 -0500466 if logical_port is None or (logical_port == vlan and logical_port in self.olt.multicast_vlans):
Chip Boling27275992017-09-22 15:17:04 -0500467 gem_ids[vlan] = ([gem_port.gem_id], None)
468 else:
Chip Boling521735d2018-12-20 09:58:01 -0600469 raise NotImplemented('TODO: This is deprecated')
470 # for onu_id, onu in self._onu_by_id.iteritems():
471 # if logical_port is None or logical_port == onu.logical_port:
472 # gem_ids[onu_id] = (onu.gem_ids(), flow_vlan)
Chip Boling252c7772017-08-16 10:13:17 -0500473 return gem_ids
474
Chip Boling27275992017-09-22 15:17:04 -0500475 def _get_pon_config(self):
Chip Boling7294b252017-06-15 16:16:55 -0500476 uri = AdtranOltHandler.GPON_PON_CONFIG_URI.format(self._pon_id)
477 name = 'pon-get-config-{}'.format(self._pon_id)
478 return self._parent.rest_client.request('GET', uri, name=name)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500479
Chip Boling27275992017-09-22 15:17:04 -0500480 def _get_onu_config(self, onu_id=None):
Chip Boling252c7772017-08-16 10:13:17 -0500481 if onu_id is None:
482 uri = AdtranOltHandler.GPON_ONU_CONFIG_LIST_URI.format(self._pon_id)
483 else:
484 uri = AdtranOltHandler.GPON_ONU_CONFIG_URI.format(self._pon_id, onu_id)
485
Chip Boling7294b252017-06-15 16:16:55 -0500486 name = 'pon-get-onu_config-{}-{}'.format(self._pon_id, onu_id)
487 return self._parent.rest_client.request('GET', uri, name=name)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500488
Chip Boling27275992017-09-22 15:17:04 -0500489 def _set_pon_config(self, leaf, value):
Chip Boling3e3b1a92017-05-16 11:51:18 -0500490 data = json.dumps({leaf: value})
Chip Boling7294b252017-06-15 16:16:55 -0500491 uri = AdtranOltHandler.GPON_PON_CONFIG_URI.format(self._pon_id)
492 name = 'pon-set-config-{}-{}-{}'.format(self._pon_id, leaf, str(value))
Chip Boling88354fb2018-09-21 12:17:19 -0500493 # If no optics on PON, then PON config fails with status 400, suppress this
494 suppress_error = len(self.onu_ids) == 0
495 return self._parent.rest_client.request('PATCH', uri, data=data, name=name,
496 suppress_error=suppress_error)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500497
Chip Boling252c7772017-08-16 10:13:17 -0500498 def _discover_onus(self):
Chip Boling27275992017-09-22 15:17:04 -0500499 self.log.debug('discovery', state=self._admin_state, in_sync=self._in_sync)
Chip Boling7294b252017-06-15 16:16:55 -0500500 if self._admin_state == AdminState.ENABLED:
Chip Boling27275992017-09-22 15:17:04 -0500501 if self._in_sync:
502 data = json.dumps({'pon-id': self._pon_id})
503 uri = AdtranOltHandler.GPON_PON_DISCOVER_ONU
504 name = 'pon-discover-onu-{}'.format(self._pon_id)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500505
Chip Boling27275992017-09-22 15:17:04 -0500506 self._discovery_deferred = self._parent.rest_client.request('POST', uri, data, name=name)
507 self._discovery_deferred.addBoth(self._onu_discovery_init_complete)
508 else:
509 self.discovery_deferred = reactor.callLater(0,
510 self._onu_discovery_init_complete,
511 None)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500512
Chip Bolingab8863d2018-03-22 14:50:31 -0500513 def _onu_discovery_init_complete(self, _result):
Chip Boling3e3b1a92017-05-16 11:51:18 -0500514 """
515 This method is called after the REST POST to request ONU discovery is
516 completed. The results (body) of the post is always empty / 204 NO CONTENT
517 """
Chip Boling7294b252017-06-15 16:16:55 -0500518 delay = self._no_onu_discover_tick if len(self._onus) == 0 else self._discovery_tick
Chip Boling3e3b1a92017-05-16 11:51:18 -0500519 delay += random.uniform(-delay / 10, delay / 10)
Chip Boling252c7772017-08-16 10:13:17 -0500520 self._discovery_deferred = reactor.callLater(delay, self._discover_onus)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500521
Chip Bolingab8863d2018-03-22 14:50:31 -0500522 def sync_hardware(self):
523 if self.state == AdtnPort.State.RUNNING or self.state == AdtnPort.State.STOPPED:
Chip Boling27275992017-09-22 15:17:04 -0500524 def read_config(results):
525 self.log.debug('read-config', results=results)
526 config = OltConfig.Pon.decode([results])
527 assert self.pon_id in config, 'sync-pon-not-found-{}'.format(self.pon_id)
528 config = config[self.pon_id]
529 self._in_sync = True
530
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500531 dl = []
Chip Boling27275992017-09-22 15:17:04 -0500532
533 if self.enabled != config.enabled:
534 self._in_sync = False
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500535 self._expedite_sync = True
Chip Boling27275992017-09-22 15:17:04 -0500536 dl.append(self._set_pon_config("enabled", self.enabled))
537
Chip Bolingab8863d2018-03-22 14:50:31 -0500538 elif self.state == AdtnPort.State.RUNNING:
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500539 if self.deployment_range != config.deployment_range:
540 self._in_sync = False
541 self._expedite_sync = True
542 dl.append(self._set_pon_config("deployment-range",
543 self.deployment_range))
544
Chip Boling88354fb2018-09-21 12:17:19 -0500545 # A little side note: FEC enable/disable cannot be changed and
546 # will remain in the previous status until an optical module
547 # is plugged in.
Chip Boling27275992017-09-22 15:17:04 -0500548 if self.downstream_fec_enable != config.downstream_fec_enable:
549 self._in_sync = False
550 dl.append(self._set_pon_config("downstream-fec-enable",
551 self.downstream_fec_enable))
552
553 if self.upstream_fec_enable != config.upstream_fec_enable:
554 self._in_sync = False
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500555 self._expedite_sync = True
Chip Boling27275992017-09-22 15:17:04 -0500556 dl.append(self._set_pon_config("upstream-fec-enable",
557 self.upstream_fec_enable))
Chip Bolingfd1fd372017-12-20 13:34:12 -0600558 defer.gatherResults(dl, consumeErrors=True)
559 return config.onus
Chip Boling27275992017-09-22 15:17:04 -0500560
Chip Bolingfd1fd372017-12-20 13:34:12 -0600561 def sync_onus(hw_onus):
Chip Bolingab8863d2018-03-22 14:50:31 -0500562 if self.state == AdtnPort.State.RUNNING:
Chip Bolingfd1fd372017-12-20 13:34:12 -0600563 self.log.debug('sync-pon-onu-results', config=hw_onus)
Chip Boling27275992017-09-22 15:17:04 -0500564
565 # ONU's have their own sync task, extra (should be deleted) are
Chip Boling88354fb2018-09-21 12:17:19 -0500566 # handled here.
Chip Bolingfd1fd372017-12-20 13:34:12 -0600567 hw_onu_ids = frozenset(hw_onus.keys())
Chip Boling27275992017-09-22 15:17:04 -0500568 my_onu_ids = frozenset(self._onu_by_id.keys())
569
570 extra_onus = hw_onu_ids - my_onu_ids
Chip Boling99c388e2018-11-20 09:33:57 -0600571 dl = [self.delete_onu(onu_id, hw_only=True) for onu_id in extra_onus]
Chip Boling27275992017-09-22 15:17:04 -0500572
Chip Boling88354fb2018-09-21 12:17:19 -0500573 if self.activation_method == "autoactivate":
574 # Autoactivation of ONUs requires missing ONU detection. If
Chip Boling99c388e2018-11-20 09:33:57 -0600575 # not found, create them here but let the TCont/GEM-Port restore
576 # be handle by ONU H/w sync logic.
Chip Boling88354fb2018-09-21 12:17:19 -0500577 for onu in [self._onu_by_id[onu_id] for onu_id in my_onu_ids - hw_onu_ids
578 if self._onu_by_id.get(onu_id) is not None]:
Chip Bolingcadafd92018-12-20 14:42:22 -0600579 dl.append(onu.create(reflow=True))
Chip Boling88354fb2018-09-21 12:17:19 -0500580
Chip Boling27275992017-09-22 15:17:04 -0500581 return defer.gatherResults(dl, consumeErrors=True)
582
583 def failure(reason, what):
584 self.log.error('hardware-sync-{}-failed'.format(what), reason=reason)
585 self._in_sync = False
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500586 self._expedite_sync = False
Chip Boling27275992017-09-22 15:17:04 -0500587
588 def reschedule(_):
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500589 # Speed up sequential resync a limited number of times if out of sync.
590
Chip Bolingab8863d2018-03-22 14:50:31 -0500591 delay = self.sync_tick
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500592
593 if self._expedite_sync:
594 self._expedite_count += 1
595 if self._expedite_count < 5:
596 delay = 1
597 else:
598 self._expedite_count = 0
599
Chip Boling27275992017-09-22 15:17:04 -0500600 delay += random.uniform(-delay / 10, delay / 10)
Chip Bolingab8863d2018-03-22 14:50:31 -0500601 self.sync_deferred = reactor.callLater(delay, self.sync_hardware)
Chip Boling27275992017-09-22 15:17:04 -0500602
Chip Bolingab8863d2018-03-22 14:50:31 -0500603 self.sync_deferred = self._get_pon_config()
604 self.sync_deferred.addCallbacks(read_config, failure, errbackArgs=['get-config'])
605 self.sync_deferred.addCallbacks(sync_onus, failure, errbackArgs=['pon-sync'])
606 self.sync_deferred.addBoth(reschedule)
Chip Boling27275992017-09-22 15:17:04 -0500607
Chip Boling3e3b1a92017-05-16 11:51:18 -0500608 def process_status_poll(self, status):
609 """
610 Process PON status poll request
611
612 :param status: (OltState.Pon object) results from RESTCONF GET
613 """
Chip Boling252c7772017-08-16 10:13:17 -0500614 self.log.debug('process-status-poll', status=status)
Chip Boling7294b252017-06-15 16:16:55 -0500615
616 if self._admin_state != AdminState.ENABLED:
Chip Boling3e3b1a92017-05-16 11:51:18 -0500617 return
618
Chip Bolingfd1fd372017-12-20 13:34:12 -0600619 # Process LOS list
620 self._process_los_alarms(frozenset(status.ont_los))
621
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500622 # Get new/missing from the discovered ONU leaf. Stale ONUs from previous
623 # configs are now cleaned up during h/w re-sync/reflow.
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500624 new, rediscovered_onus = self._process_status_onu_discovered_list(status.discovered_onu)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500625
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500626 # Process newly discovered ONU list and rediscovered ONUs
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500627 for serial_number in new | rediscovered_onus:
Chip Boling3e3b1a92017-05-16 11:51:18 -0500628 reactor.callLater(0, self.add_onu, serial_number, status)
629
Chip Bolingfd1fd372017-12-20 13:34:12 -0600630 # PON Statistics
Chip Bolingc0451382018-08-24 14:21:53 -0500631 timestamp = arrow.utcnow().float_timestamp
632 self._process_statistics(status, timestamp)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500633
Chip Boling27275992017-09-22 15:17:04 -0500634 # Process ONU info. Note that newly added ONUs will not be processed
635 # until the next pass
Chip Bolingc0451382018-08-24 14:21:53 -0500636 self._update_onu_status(status.onus, timestamp)
Chip Boling27275992017-09-22 15:17:04 -0500637
Chip Bolingfd1fd372017-12-20 13:34:12 -0600638 # Process GEM Port information
Chip Bolingc0451382018-08-24 14:21:53 -0500639 self._update_gem_status(status.gems, timestamp)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600640
Chip Bolingc0451382018-08-24 14:21:53 -0500641 def _process_statistics(self, status, timestamp):
642 self.timestamp = timestamp
Chip Bolingfd1fd372017-12-20 13:34:12 -0600643 self.rx_packets = status.rx_packets
644 self.rx_bytes = status.rx_bytes
645 self.tx_packets = status.tx_packets
646 self.tx_bytes = status.tx_bytes
647 self.tx_bip_errors = status.tx_bip_errors
648
Chip Bolingc0451382018-08-24 14:21:53 -0500649 def _update_onu_status(self, onus, timestamp):
Chip Boling27275992017-09-22 15:17:04 -0500650 """
651 Process ONU status for this PON
652 :param onus: (dict) onu_id: ONU State
653 """
654 for onu_id, onu_status in onus.iteritems():
655 if onu_id in self._onu_by_id:
Chip Bolingfd1fd372017-12-20 13:34:12 -0600656 onu = self._onu_by_id[onu_id]
Chip Bolingc0451382018-08-24 14:21:53 -0500657 onu.timestamp = timestamp
Chip Bolingfd1fd372017-12-20 13:34:12 -0600658 onu.rssi = onu_status.rssi
659 onu.equalization_delay = onu_status.equalization_delay
660 onu.equalization_delay = onu_status.equalization_delay
661 onu.fiber_length = onu_status.fiber_length
Chip Bolingbb15b512018-06-01 11:39:58 -0500662 onu.password = onu_status.reported_password
Chip Bolingfd1fd372017-12-20 13:34:12 -0600663
Chip Bolingc0451382018-08-24 14:21:53 -0500664 def _update_gem_status(self, gems, timestamp):
Chip Bolingfd1fd372017-12-20 13:34:12 -0600665 for gem_id, gem_status in gems.iteritems():
666 onu = self._onu_by_id.get(gem_status.onu_id)
667 if onu is not None:
668 gem_port = onu.gem_port(gem_status.gem_id)
669 if gem_port is not None:
Chip Bolingc0451382018-08-24 14:21:53 -0500670 gem_port.timestamp = timestamp
Chip Bolingfd1fd372017-12-20 13:34:12 -0600671 gem_port.rx_packets = gem_status.rx_packets
672 gem_port.rx_bytes = gem_status.rx_bytes
673 gem_port.tx_packets = gem_status.tx_packets
674 gem_port.tx_bytes = gem_status.tx_bytes
Chip Boling27275992017-09-22 15:17:04 -0500675
676 def _process_los_alarms(self, ont_los):
677 """
678 Walk current LOS and set/clear LOS as appropriate
679 :param ont_los: (frozenset) ONU IDs of ONUs in LOS alarm state
680 """
681 cleared_alarms = self._active_los_alarms - ont_los
682 new_alarms = ont_los - self._active_los_alarms
683
Chip Boling27275992017-09-22 15:17:04 -0500684 if len(cleared_alarms) > 0 or len(new_alarms) > 0:
685 self.log.info('onu-los', cleared=cleared_alarms, new=new_alarms)
686
687 for onu_id in cleared_alarms:
Chip Boling27275992017-09-22 15:17:04 -0500688 self._active_los_alarms.remove(onu_id)
Chip Boling99c388e2018-11-20 09:33:57 -0600689 OnuLosAlarm(self.olt.alarms, onu_id, self.port_no).clear_alarm()
Chip Boling27275992017-09-22 15:17:04 -0500690
691 for onu_id in new_alarms:
692 self._active_los_alarms.add(onu_id)
Chip Boling99c388e2018-11-20 09:33:57 -0600693 OnuLosAlarm(self.olt.alarms, onu_id, self.port_no).raise_alarm()
694 reactor.callLater(0, self.delete_onu, onu_id)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500695
Chip Boling3e3b1a92017-05-16 11:51:18 -0500696 def _process_status_onu_discovered_list(self, discovered_onus):
697 """
Chip Bolingae298012017-08-28 08:55:17 -0500698 Look for new ONUs
Chip Boling3e3b1a92017-05-16 11:51:18 -0500699
700 :param discovered_onus: (frozenset) Set of ONUs currently discovered
701 """
Chip Boling252c7772017-08-16 10:13:17 -0500702 self.log.debug('discovered-ONUs', list=discovered_onus)
703
704 # Only request discovery if activation is auto-discovery or auto-activate
Chip Boling88354fb2018-09-21 12:17:19 -0500705 continue_discovery = ['autodiscovery', 'autoactivate']
Chip Boling252c7772017-08-16 10:13:17 -0500706
707 if self._activation_method not in continue_discovery:
708 return set(), set()
Chip Boling3e3b1a92017-05-16 11:51:18 -0500709
Chip Boling7294b252017-06-15 16:16:55 -0500710 my_onus = frozenset(self._onus.keys())
Chip Boling3e3b1a92017-05-16 11:51:18 -0500711
712 new_onus = discovered_onus - my_onus
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500713 rediscovered_onus = my_onus & discovered_onus
Chip Boling3e3b1a92017-05-16 11:51:18 -0500714
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500715 return new_onus, rediscovered_onus
Chip Boling3e3b1a92017-05-16 11:51:18 -0500716
Chip Boling252c7772017-08-16 10:13:17 -0500717 def _get_onu_info(self, serial_number):
718 """
719 Parse through available xPON information for ONU configuration settings
Chip Boling521735d2018-12-20 09:58:01 -0600720
Chip Boling252c7772017-08-16 10:13:17 -0500721 :param serial_number: (string) Decoded (not base64) serial number string
722 :return: (dict) onu config data or None on lookup failure
723 """
724 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500725 if self.activation_method == "autodiscovery":
Chip Bolingb4868192018-11-01 16:38:44 -0500726 # if self.authentication_method == 'serial-number':
Chip Boling521735d2018-12-20 09:58:01 -0600727 raise NotImplemented('autodiscovery: Not supported at this time')
Chip Boling252c7772017-08-16 10:13:17 -0500728
Chip Boling88354fb2018-09-21 12:17:19 -0500729 elif self.activation_method == "autoactivate":
Chip Boling521735d2018-12-20 09:58:01 -0600730 onu_id = self.get_next_onu_id
731 enabled = True
Chip Boling521735d2018-12-20 09:58:01 -0600732 upstream_fec_enabled = True
Chip Bolingb4868192018-11-01 16:38:44 -0500733
Chip Boling252c7772017-08-16 10:13:17 -0500734 else:
Chip Boling521735d2018-12-20 09:58:01 -0600735 self.log.error('unsupported-activation-method', method=self.activation_method)
736 return None
Chip Boling252c7772017-08-16 10:13:17 -0500737
738 onu_info = {
Chip Boling27275992017-09-22 15:17:04 -0500739 'device-id': self.olt.device_id,
Chip Boling252c7772017-08-16 10:13:17 -0500740 'serial-number': serial_number,
Chip Boling252c7772017-08-16 10:13:17 -0500741 'pon': self,
742 'onu-id': onu_id,
743 'enabled': enabled,
Chip Bolingfd1fd372017-12-20 13:34:12 -0600744 'upstream-fec': upstream_fec_enabled,
Chip Boling252c7772017-08-16 10:13:17 -0500745 'password': Onu.DEFAULT_PASSWORD,
Chip Boling252c7772017-08-16 10:13:17 -0500746 }
Chip Boling521735d2018-12-20 09:58:01 -0600747 pon_id = self.olt.pon_id_to_port_number(self._pon_id)
Chip Bolingb4868192018-11-01 16:38:44 -0500748
Chip Boling521735d2018-12-20 09:58:01 -0600749 # TODO: Currently only one UNI port and it is hardcoded to port 0
750 onu_info['uni-ports'] = [platform.mk_uni_port_num(pon_id, onu_id)]
Chip Bolingae298012017-08-28 08:55:17 -0500751
Chip Boling3971d242018-06-06 10:26:34 -0500752 # return onu_info
Chip Boling521735d2018-12-20 09:58:01 -0600753 return onu_info
Chip Boling252c7772017-08-16 10:13:17 -0500754
755 except Exception as e:
Chip Boling88354fb2018-09-21 12:17:19 -0500756 self.log.exception('get-onu-info-tech-profiles', e=e)
Chip Boling521735d2018-12-20 09:58:01 -0600757 return None
Chip Boling252c7772017-08-16 10:13:17 -0500758
Chip Boling3e3b1a92017-05-16 11:51:18 -0500759 @inlineCallbacks
Chip Bolingfd1fd372017-12-20 13:34:12 -0600760 def add_onu(self, serial_number_64, status):
Chip Boling88354fb2018-09-21 12:17:19 -0500761 """
762 Add an ONU to the PON
763
Chip Boling521735d2018-12-20 09:58:01 -0600764 :param serial_number_64: (str) base-64 encoded serial number
765 :param status: (dict) OLT PON status. Used to detect if ONU is already provisioned
Chip Boling88354fb2018-09-21 12:17:19 -0500766 """
Chip Bolingfd1fd372017-12-20 13:34:12 -0600767 serial_number = Onu.serial_number_to_string(serial_number_64)
768 self.log.info('add-onu', serial_number=serial_number,
769 serial_number_64=serial_number_64, status=status)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500770
Chip Bolingb4868192018-11-01 16:38:44 -0500771 # It takes a little while for a new ONU to be removed from the discovery
772 # list. Return early here so extra ONU IDs are not allocated
773 if serial_number_64 in self._onus:
Chip Boling88354fb2018-09-21 12:17:19 -0500774 returnValue('wait-for-fpga')
775
Chip Boling521735d2018-12-20 09:58:01 -0600776 if serial_number_64 in status.onus:
777 # Handles fast entry into this task before FPGA can clear results of ONU delete
778 returnValue('sticky-onu')
Chip Boling88354fb2018-09-21 12:17:19 -0500779
Chip Boling521735d2018-12-20 09:58:01 -0600780 # At our limit? TODO: Retrieve from device resource manager if available
781 if len(self._onus) >= self.MAX_ONUS_SUPPORTED:
782 self.log.warning('max-onus-provisioned', count=len(self._onus))
783 returnValue('max-onus-reached')
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500784
Chip Boling521735d2018-12-20 09:58:01 -0600785 onu_info = self._get_onu_info(serial_number)
786 onu_id = onu_info['onu-id']
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500787
Chip Boling521735d2018-12-20 09:58:01 -0600788 if onu_id is None:
789 self.log.warning('no-onu-ids-available', serial_number=serial_number,
790 serial_number_64=serial_number_64)
791 returnValue('no-ids-available')
Chip Bolingab8863d2018-03-22 14:50:31 -0500792
Chip Boling521735d2018-12-20 09:58:01 -0600793 # TODO: Is the best before or after creation in parent device?
794 alarm = OnuDiscoveryAlarm(self.olt.alarms, self.pon_id, serial_number)
795 reactor.callLater(0, alarm.raise_alarm)
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500796
Chip Boling521735d2018-12-20 09:58:01 -0600797 # Have the core create the ONU device
Chip Bolingcadafd92018-12-20 14:42:22 -0600798 self._parent.add_onu_device(self.pon_id, onu_id, serial_number)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500799
Chip Boling521735d2018-12-20 09:58:01 -0600800 try:
Chip Bolingcadafd92018-12-20 14:42:22 -0600801 onu = Onu(onu_info)
802 self._onus[serial_number_64] = onu
803 self._onu_by_id[onu.onu_id] = onu
804
Chip Boling521735d2018-12-20 09:58:01 -0600805 # Add Multicast to PON on a per-ONU basis
806 #
807 # for id_or_vid, gem_port in gem_ports.iteritems():
808 # try:
809 # if gem_port.multicast:
810 # self.log.debug('id-or-vid', id_or_vid=id_or_vid)
811 # vid = self.olt.multicast_vlans[0] if len(self.olt.multicast_vlans) else None
812 # if vid is not None:
813 # self.add_mcast_gem_port(gem_port, vid)
814 #
815 # except Exception as e:
816 # self.log.exception('id-or-vid', e=e)
Chip Boling252c7772017-08-16 10:13:17 -0500817
Chip Boling521735d2018-12-20 09:58:01 -0600818 _results = yield onu.create()
Chip Boling252c7772017-08-16 10:13:17 -0500819
Chip Boling521735d2018-12-20 09:58:01 -0600820 except Exception as e:
821 self.log.warning('add-onu', serial_number=serial_number_64, e=e)
822 # allowable exception. H/w re-sync will recover/fix any issues
Chip Boling3e3b1a92017-05-16 11:51:18 -0500823
Chip Boling88354fb2018-09-21 12:17:19 -0500824 @property
Chip Boling3e3b1a92017-05-16 11:51:18 -0500825 def get_next_onu_id(self):
Chip Bolingb4868192018-11-01 16:38:44 -0500826 return self._parent.resource_mgr.get_onu_id(self._pon_id)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500827
Chip Boling88354fb2018-09-21 12:17:19 -0500828 def release_onu_id(self, onu_id):
Chip Bolingb4868192018-11-01 16:38:44 -0500829 self._parent.resource_mgr.free_onu_id(self._pon_id, onu_id)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500830
Chip Bolingae298012017-08-28 08:55:17 -0500831 @inlineCallbacks
Chip Bolingff3087f2017-10-12 09:26:29 -0500832 def _remove_from_hardware(self, onu_id):
Chip Boling252c7772017-08-16 10:13:17 -0500833 uri = AdtranOltHandler.GPON_ONU_CONFIG_URI.format(self._pon_id, onu_id)
Chip Boling7294b252017-06-15 16:16:55 -0500834 name = 'pon-delete-onu-{}-{}'.format(self._pon_id, onu_id)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500835
Chip Bolingff3087f2017-10-12 09:26:29 -0500836 try:
837 yield self._parent.rest_client.request('DELETE', uri, name=name)
838
Chip Bolingfd1fd372017-12-20 13:34:12 -0600839 except RestInvalidResponseCode as e:
840 if e.code != 404:
841 self.log.exception('onu-delete', e=e)
842
Chip Bolingff3087f2017-10-12 09:26:29 -0500843 except Exception as e:
844 self.log.exception('onu-hw-delete', onu_id=onu_id, e=e)
845
846 @inlineCallbacks
Chip Boling99c388e2018-11-20 09:33:57 -0600847 def delete_onu(self, onu_id, hw_only=False):
Chip Bolingae298012017-08-28 08:55:17 -0500848 onu = self._onu_by_id.get(onu_id)
849
Chip Boling252c7772017-08-16 10:13:17 -0500850 # Remove from any local dictionary
851 if onu_id in self._onu_by_id:
852 del self._onu_by_id[onu_id]
Chip Bolingff3087f2017-10-12 09:26:29 -0500853
Chip Boling27275992017-09-22 15:17:04 -0500854 if onu is not None:
Chip Bolingcadafd92018-12-20 14:42:22 -0600855 if onu.serial_number_64 in self._onus:
856 del self._onus[onu.serial_number_64]
Chip Bolingfd1fd372017-12-20 13:34:12 -0600857 try:
Chip Boling521735d2018-12-20 09:58:01 -0600858 proxy_address = onu.proxy_address
859 onu.delete() # Remove from hardware
Chip Boling9fef0fd2018-12-11 09:43:59 -0600860
Chip Boling99c388e2018-11-20 09:33:57 -0600861 # And removal from VOLTHA adapter agent
862 if not hw_only:
Chip Boling521735d2018-12-20 09:58:01 -0600863 self._parent.delete_child_device(proxy_address)
Chip Boling99c388e2018-11-20 09:33:57 -0600864
Chip Bolingfd1fd372017-12-20 13:34:12 -0600865 except Exception as e:
866 self.log.exception('onu-delete', serial_number=onu.serial_number, e=e)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600867 else:
868 try:
869 yield self._remove_from_hardware(onu_id)
870
871 except Exception as e:
Chip Boling99c388e2018-11-20 09:33:57 -0600872 self.log.debug('onu-remove', serial_number=onu.serial_number, e=e)
Chip Bolingae298012017-08-28 08:55:17 -0500873
Chip Bolingcadafd92018-12-20 14:42:22 -0600874 # Remove from LOS list if needed TODO: Should a 'clear' alarm be sent as well ?
Chip Boling9fef0fd2018-12-11 09:43:59 -0600875 if onu is not None and onu.id in self._active_los_alarms:
Chip Boling4912e782018-11-09 16:33:40 -0600876 self._active_los_alarms.remove(onu.id)
877
Chip Boling27275992017-09-22 15:17:04 -0500878 def add_mcast_gem_port(self, mcast_gem, vlan):
Chip Bolingae298012017-08-28 08:55:17 -0500879 """
Chip Boling27275992017-09-22 15:17:04 -0500880 Add any new Multicast GEM Ports to the PON
881 :param mcast_gem: (GemPort)
Chip Bolingae298012017-08-28 08:55:17 -0500882 """
Chip Boling27275992017-09-22 15:17:04 -0500883 if vlan in self._mcast_gem_ports:
884 return
885
886 assert len(self._mcast_gem_ports) == 0, 'Only 1 MCAST GEMPort until BBF Support'
887 assert 1 <= vlan <= 4095, 'Invalid Multicast VLAN ID'
888 assert len(self.olt.multicast_vlans) == 1, 'Only support 1 MCAST VLAN until BBF Support'
889
890 self._mcast_gem_ports[vlan] = mcast_gem