blob: 7aa36bd8aefd01d8ba1dbdfc90af19c40bef155f [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 Bolingbb15b512018-06-01 11:39:58 -050028from voltha.protos.common_pb2 import AdminState
Chip Boling3e3b1a92017-05-16 11:51:18 -050029from voltha.protos.device_pb2 import Port
Chip Bolingb4868192018-11-01 16:38:44 -050030from voltha.protos.bbf_fiber_tcont_body_pb2 import TcontsConfigData
31from voltha.protos.bbf_fiber_traffic_descriptor_profile_body_pb2 import TrafficDescriptorProfileData
32from voltha.protos.bbf_fiber_gemport_body_pb2 import GemportsConfigData
33from xpon.olt_traffic_descriptor import OltTrafficDescriptor
34import resources.adtranolt_platform as platform
35
Chip Boling3e3b1a92017-05-16 11:51:18 -050036
Chip Bolingbb15b512018-06-01 11:39:58 -050037try:
Chip Bolingbffef5e2018-08-07 14:53:12 -050038 from voltha.extensions.alarms.onu.onu_discovery_alarm import OnuDiscoveryAlarm
Chip Bolingbb15b512018-06-01 11:39:58 -050039except ImportError:
Chip Bolingbffef5e2018-08-07 14:53:12 -050040 from voltha.extensions.alarms.onu.onu_discovery_alarm import OnuDiscoveryAlarm
Chip Bolingbb15b512018-06-01 11:39:58 -050041
Chip Boling3e3b1a92017-05-16 11:51:18 -050042
Chip Bolingab8863d2018-03-22 14:50:31 -050043class PonPort(AdtnPort):
Chip Boling3e3b1a92017-05-16 11:51:18 -050044 """
Chip Bolingab8863d2018-03-22 14:50:31 -050045 GPON Port
Chip Boling3e3b1a92017-05-16 11:51:18 -050046 """
Chip Bolingb4868192018-11-01 16:38:44 -050047 MAX_ONUS_SUPPORTED = 128
Chip Bolingfd1fd372017-12-20 13:34:12 -060048 MAX_DEPLOYMENT_RANGE = 25000 # Meters (OLT-PB maximum)
Chip Boling27275992017-09-22 15:17:04 -050049
50 _MCAST_ONU_ID = 253
51 _MCAST_ALLOC_BASE = 0x500
Chip Boling3e3b1a92017-05-16 11:51:18 -050052
Chip Boling88354fb2018-09-21 12:17:19 -050053 # AutoActivate should be used if xPON configuration is not supported
54 _SUPPORTED_ACTIVATION_METHODS = ['autodiscovery', 'autoactivate']
Chip Boling252c7772017-08-16 10:13:17 -050055 _SUPPORTED_AUTHENTICATION_METHODS = ['serial-number']
56
Chip Bolingab8863d2018-03-22 14:50:31 -050057 def __init__(self, parent, **kwargs):
Chip Bolingab8863d2018-03-22 14:50:31 -050058 super(PonPort, self).__init__(parent, **kwargs)
Chip Bolingab8863d2018-03-22 14:50:31 -050059 assert 'pon-id' in kwargs, 'PON ID not found'
Chip Boling7294b252017-06-15 16:16:55 -050060
61 self._parent = parent
Chip Bolingab8863d2018-03-22 14:50:31 -050062 self._pon_id = kwargs['pon-id']
63 self.log = structlog.get_logger(device_id=parent.device_id, pon_id=self._pon_id)
64 self._port_no = kwargs['port_no']
Chip Boling3eedf462018-10-17 12:18:28 -050065 self._physical_port_name = 'xpon 0/{}'.format(self._pon_id+1)
Chip Bolingab8863d2018-03-22 14:50:31 -050066 self._label = 'pon-{}'.format(self._pon_id)
67
Chip Boling27275992017-09-22 15:17:04 -050068 self._in_sync = False
Chip Bolingdb61c6a2017-09-27 12:36:45 -050069 self._expedite_sync = False
70 self._expedite_count = 0
71
Chip Bolingab8863d2018-03-22 14:50:31 -050072 self._discovery_tick = 20.0
73 self._no_onu_discover_tick = self._discovery_tick / 2
74 self._discovered_onus = [] # List of serial numbers
Chip Bolingb4868192018-11-01 16:38:44 -050075 self._discovery_deferred = None # Specifically for ONU discovery
Chip Bolingab8863d2018-03-22 14:50:31 -050076
Chip Bolingb4868192018-11-01 16:38:44 -050077 self._onus = {} # serial_number-base64 -> ONU (allowed list)
78 self._onu_by_id = {} # onu-id -> ONU
79 self._mcast_gem_ports = {} # VLAN -> GemPort
Chip Boling7294b252017-06-15 16:16:55 -050080
Chip Bolingb4868192018-11-01 16:38:44 -050081 self._active_los_alarms = set() # ONU-ID
Chip Boling27275992017-09-22 15:17:04 -050082
Chip Bolingb4868192018-11-01 16:38:44 -050083 # xPON configuration
84 self._activation_method = 'autoactivate'
Chip Boling7294b252017-06-15 16:16:55 -050085
Chip Bolingb4868192018-11-01 16:38:44 -050086 self._downstream_fec_enable = True
87 self._upstream_fec_enable = True
Chip Boling27275992017-09-22 15:17:04 -050088 self._deployment_range = 25000
Chip Boling252c7772017-08-16 10:13:17 -050089 self._authentication_method = 'serial-number'
Chip Bolingfd1fd372017-12-20 13:34:12 -060090 self._mcast_aes = False
Chip Boling3e3b1a92017-05-16 11:51:18 -050091
Chip Bolingfd1fd372017-12-20 13:34:12 -060092 # Statistics
Chip Bolingfd1fd372017-12-20 13:34:12 -060093 self.tx_bip_errors = 0
94
Chip Bolingb4868192018-11-01 16:38:44 -050095 # xPON Configuration (TODO: Move Tcont/GEMPort to ONU eventually)
96 # TODO: TD may be system-wide, wait for Service Profiles
97 self._v_ont_anis = {} # Name -> dict
98 self._ont_anis = {} # Name -> dict
99 self._tconts = {} # Name -> dict
100 self._traffic_descriptors = {} # Name -> dict
101 self._gem_ports = {} # Name -> dict
102
Chip Boling3e3b1a92017-05-16 11:51:18 -0500103 def __str__(self):
Chip Boling252c7772017-08-16 10:13:17 -0500104 return "PonPort-{}: Admin: {}, Oper: {}, OLT: {}".format(self._label,
105 self._admin_state,
106 self._oper_status,
107 self.olt)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500108
109 def get_port(self):
110 """
111 Get the VOLTHA PORT object for this port
112 :return: VOLTHA Port object
113 """
Chip Boling7294b252017-06-15 16:16:55 -0500114 if self._port is None:
115 self._port = Port(port_no=self._port_no,
116 label=self._label,
117 type=Port.PON_OLT,
Chip Bolingc64c8dc2018-04-20 14:42:24 -0500118 admin_state=self._admin_state,
119 oper_status=self._oper_status)
120
Chip Boling7294b252017-06-15 16:16:55 -0500121 return self._port
Chip Boling3e3b1a92017-05-16 11:51:18 -0500122
123 @property
Chip Boling3e3b1a92017-05-16 11:51:18 -0500124 def pon_id(self):
Chip Boling7294b252017-06-15 16:16:55 -0500125 return self._pon_id
126
127 @property
Chip Bolingfd1fd372017-12-20 13:34:12 -0600128 def onus(self):
129 """
130 Get a set of all ONUs. While the set is immutable, do not use this method
131 to get a collection that you will iterate through that my yield the CPU
132 such as inline callback. ONUs may be deleted at any time and they will
133 set some references to other objects to NULL during the 'delete' call.
134 Instead, get a list of ONU-IDs and iterate on these and call the 'onu'
135 method below (which will return 'None' if the ONU has been deleted.
136
137 :return: (frozenset) collection of ONU objects on this PON
138 """
139 return frozenset(self._onus.values())
140
141 @property
142 def onu_ids(self):
143 return frozenset(self._onu_by_id.keys())
144
Chip Bolingef0e2fa2017-10-06 14:33:01 -0500145 def onu(self, onu_id):
146 return self._onu_by_id.get(onu_id)
147
Chip Boling7294b252017-06-15 16:16:55 -0500148 @property
Chip Bolingfd1fd372017-12-20 13:34:12 -0600149 def in_service_onus(self):
150 return len({onu.onu_id for onu in self.onus
151 if onu.onu_id not in self._active_los_alarms})
152
153 @property
154 def closest_onu_distance(self):
155 distance = -1
156 for onu in self.onus:
157 if onu.fiber_length < distance or distance == -1:
158 distance = onu.fiber_length
159 return distance
160
161 @property
Chip Boling27275992017-09-22 15:17:04 -0500162 def downstream_fec_enable(self):
163 return self._downstream_fec_enable
164
165 @downstream_fec_enable.setter
166 def downstream_fec_enable(self, value):
167 assert isinstance(value, bool), 'downstream FEC enabled is a boolean'
168
169 if self._downstream_fec_enable != value:
170 self._downstream_fec_enable = value
Chip Bolingab8863d2018-03-22 14:50:31 -0500171 if self.state == AdtnPort.State.RUNNING:
172 self.deferred = self._set_pon_config("downstream-fec-enable", value)
Chip Boling27275992017-09-22 15:17:04 -0500173
174 @property
175 def upstream_fec_enable(self):
176 return self._upstream_fec_enable
177
178 @upstream_fec_enable.setter
179 def upstream_fec_enable(self, value):
180 assert isinstance(value, bool), 'upstream FEC enabled is a boolean'
Chip Boling27275992017-09-22 15:17:04 -0500181 if self._upstream_fec_enable != value:
182 self._upstream_fec_enable = value
Chip Bolingab8863d2018-03-22 14:50:31 -0500183 if self.state == AdtnPort.State.RUNNING:
184 self.deferred = self._set_pon_config("upstream-fec-enable", value)
Chip Boling27275992017-09-22 15:17:04 -0500185
186 @property
Chip Bolingfd1fd372017-12-20 13:34:12 -0600187 def any_upstream_fec_enabled(self):
188 for onu in self.onus:
189 if onu.upstream_fec_enable and onu.enabled:
190 return True
191 return False
192
193 @property
194 def mcast_aes(self):
195 return self._mcast_aes
196
197 @mcast_aes.setter
198 def mcast_aes(self, value):
199 assert isinstance(value, bool), 'MCAST AES is a boolean'
200 if self._mcast_aes != value:
201 self._mcast_aes = value
Chip Bolingab8863d2018-03-22 14:50:31 -0500202 if self.state == AdtnPort.State.RUNNING:
Chip Bolingfd1fd372017-12-20 13:34:12 -0600203 pass # TODO
204
205 @property
Chip Boling27275992017-09-22 15:17:04 -0500206 def deployment_range(self):
207 """Maximum deployment range (in meters)"""
208 return self._deployment_range
209
210 @deployment_range.setter
211 def deployment_range(self, value):
212 """Maximum deployment range (in meters)"""
213 if not 0 <= value <= PonPort.MAX_DEPLOYMENT_RANGE:
214 raise ValueError('Deployment range should be 0..{} meters'.
215 format(PonPort.MAX_DEPLOYMENT_RANGE))
216 if self._deployment_range != value:
217 self._deployment_range = value
Chip Bolingab8863d2018-03-22 14:50:31 -0500218 if self.state == AdtnPort.State.RUNNING:
219 self.deferred = self._set_pon_config("deployment-range", value)
Chip Boling27275992017-09-22 15:17:04 -0500220
221 @property
Chip Boling252c7772017-08-16 10:13:17 -0500222 def discovery_tick(self):
223 return self._discovery_tick * 10
224
225 @discovery_tick.setter
226 def discovery_tick(self, value):
227 if value < 0:
228 raise ValueError("Polling interval must be >= 0")
229
230 if self.discovery_tick != value:
231 self._discovery_tick = value / 10
232
Chip Boling27275992017-09-22 15:17:04 -0500233 try:
234 if self._discovery_deferred is not None and \
235 not self._discovery_deferred.called:
236 self._discovery_deferred.cancel()
237 except:
238 pass
239 self._discovery_deferred = None
Chip Boling252c7772017-08-16 10:13:17 -0500240
241 if self._discovery_tick > 0:
242 self._discovery_deferred = reactor.callLater(self._discovery_tick,
243 self._discover_onus)
244
245 @property
246 def activation_method(self):
247 return self._activation_method
248
249 @activation_method.setter
250 def activation_method(self, value):
251 value = value.lower()
252 if value not in PonPort._SUPPORTED_ACTIVATION_METHODS:
253 raise ValueError('Invalid ONU activation method')
Chip Boling88354fb2018-09-21 12:17:19 -0500254
Chip Boling252c7772017-08-16 10:13:17 -0500255 self._activation_method = value
256
257 @property
258 def authentication_method(self):
259 return self._authentication_method
260
261 @authentication_method.setter
262 def authentication_method(self, value):
263 value = value.lower()
264 if value not in PonPort._SUPPORTED_AUTHENTICATION_METHODS:
265 raise ValueError('Invalid ONU authentication method')
266 self._authentication_method = value
267
Chip Bolingab8863d2018-03-22 14:50:31 -0500268 def cancel_deferred(self):
269 super(PonPort, self).cancel_deferred()
Chip Boling7294b252017-06-15 16:16:55 -0500270
Chip Bolingab8863d2018-03-22 14:50:31 -0500271 d, self._discovery_deferred = self._discovery_deferred, None
Chip Boling3e3b1a92017-05-16 11:51:18 -0500272
Chip Bolingab8863d2018-03-22 14:50:31 -0500273 try:
274 if d is not None and not d.called:
275 d.cancel()
276 except Exception as e:
277 pass
Chip Boling7294b252017-06-15 16:16:55 -0500278
279 def _update_adapter_agent(self):
Chip Bolingc64c8dc2018-04-20 14:42:24 -0500280 """
281 Update the port status and state in the core
282 """
283 self.log.debug('update-adapter-agent', admin_state=self._admin_state,
Chip Boling3971d242018-06-06 10:26:34 -0500284 oper_status=self._oper_status)
Chip Bolingc64c8dc2018-04-20 14:42:24 -0500285
286 # because the core does not provide methods for updating admin
287 # and oper status per port, we need to copy any existing port
288 # info so that we don't wipe out the peers
289 if self._port is not None:
290 agent_ports = self.adapter_agent.get_ports(self.olt.device_id, Port.PON_OLT)
291
292 agent_port = next((ap for ap in agent_ports if ap.port_no == self._port_no), None)
293
294 # copy current Port info
295 if agent_port is not None:
Chip Boling3971d242018-06-06 10:26:34 -0500296 self._port = agent_port
Chip Bolingc64c8dc2018-04-20 14:42:24 -0500297
298 # set new states
299 self._port.admin_state = self._admin_state
300 self._port.oper_status = self._oper_status
301
302 # adapter_agent add_port also does an update of existing port
303 self.adapter_agent.add_port(self.olt.device_id, self.get_port())
Chip Boling7294b252017-06-15 16:16:55 -0500304
Chip Boling7294b252017-06-15 16:16:55 -0500305 @inlineCallbacks
Chip Bolingab8863d2018-03-22 14:50:31 -0500306 def finish_startup(self):
Chip Boling3e3b1a92017-05-16 11:51:18 -0500307 """
Chip Boling7294b252017-06-15 16:16:55 -0500308 Do all startup offline since REST may fail
Chip Boling3e3b1a92017-05-16 11:51:18 -0500309 """
Chip Bolingab8863d2018-03-22 14:50:31 -0500310 if self.state != AdtnPort.State.INITIAL:
Chip Boling7294b252017-06-15 16:16:55 -0500311 returnValue('Done')
Chip Boling3e3b1a92017-05-16 11:51:18 -0500312
Chip Boling252c7772017-08-16 10:13:17 -0500313 self.log.debug('final-startup')
Chip Bolingab8863d2018-03-22 14:50:31 -0500314 results = None
Chip Boling5561d552017-07-07 15:11:26 -0500315
Chip Boling27275992017-09-22 15:17:04 -0500316 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500317 self.deferred = self._get_pon_config()
318 results = yield self.deferred
Chip Boling27275992017-09-22 15:17:04 -0500319
320 except Exception as e:
321 self.log.exception('initial-GET', e=e)
Chip Bolingab8863d2018-03-22 14:50:31 -0500322 self.deferred = reactor.callLater(5, self.finish_startup)
323 returnValue(self.deferred)
Chip Boling27275992017-09-22 15:17:04 -0500324
325 # Load config from hardware
326
327 enabled = results.get('enabled', False)
328 downstream_fec_enable = results.get('downstream-fec-enable', False)
329 upstream_fec_enable = results.get('upstream-fec-enable', False)
330 deployment_range = results.get('deployment-range', 25000)
331 self._in_sync = True
332
333 if enabled != self._enabled:
Chip Boling7294b252017-06-15 16:16:55 -0500334 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500335 self.deferred = self._set_pon_config("enabled", True)
336 yield self.deferred
Chip Boling3e3b1a92017-05-16 11:51:18 -0500337
Chip Boling7294b252017-06-15 16:16:55 -0500338 except Exception as e:
Chip Boling252c7772017-08-16 10:13:17 -0500339 self.log.exception('final-startup-enable', e=e)
Chip Bolingab8863d2018-03-22 14:50:31 -0500340 self.deferred = reactor.callLater(3, self.finish_startup)
341 returnValue(self.deferred)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500342
Chip Boling27275992017-09-22 15:17:04 -0500343 if downstream_fec_enable != self._downstream_fec_enable:
Chip Boling7294b252017-06-15 16:16:55 -0500344 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500345 self.deferred = self._set_pon_config("downstream-fec-enable",
346 self._downstream_fec_enable)
347 yield self.deferred
Chip Boling3e3b1a92017-05-16 11:51:18 -0500348
Chip Boling7294b252017-06-15 16:16:55 -0500349 except Exception as e:
Chip Boling27275992017-09-22 15:17:04 -0500350 self.log.warning('final-startup-downstream-FEC', e=e)
351 self._in_sync = False
352 # Non-fatal. May have failed due to no SFQ in slot
Chip Boling7294b252017-06-15 16:16:55 -0500353
Chip Boling27275992017-09-22 15:17:04 -0500354 if upstream_fec_enable != self._upstream_fec_enable:
Chip Boling7294b252017-06-15 16:16:55 -0500355 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500356 self.deferred = self._set_pon_config("upstream-fec-enable",
357 self._upstream_fec_enable)
358 yield self.deferred
Chip Boling7294b252017-06-15 16:16:55 -0500359
360 except Exception as e:
Chip Boling27275992017-09-22 15:17:04 -0500361 self.log.warning('final-startup-upstream-FEC', e=e)
362 self._in_sync = False
363 # Non-fatal. May have failed due to no SFQ in slot
Chip Boling7294b252017-06-15 16:16:55 -0500364
Chip Boling27275992017-09-22 15:17:04 -0500365 if deployment_range != self._deployment_range:
366 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500367 self.deferred = self._set_pon_config("deployment-range",
368 self._deployment_range)
369 yield self.deferred
Chip Boling7294b252017-06-15 16:16:55 -0500370
Chip Boling27275992017-09-22 15:17:04 -0500371 except Exception as e:
372 self.log.warning('final-startup-deployment-range', e=e)
373 self._in_sync = False
374 # Non-fatal. May have failed due to no SFQ in slot
Chip Boling7294b252017-06-15 16:16:55 -0500375
Chip Boling27275992017-09-22 15:17:04 -0500376 if len(self._onus) > 0:
377 dl = []
Chip Bolingfd1fd372017-12-20 13:34:12 -0600378 for onu_id in self.onu_ids:
379 onu = self.onu(onu_id)
380 if onu is not None:
381 dl.append(onu.restart())
Chip Boling27275992017-09-22 15:17:04 -0500382 yield defer.gatherResults(dl, consumeErrors=True)
Chip Boling7294b252017-06-15 16:16:55 -0500383
Chip Boling27275992017-09-22 15:17:04 -0500384 # Begin to ONU discovery and hardware sync
Chip Boling3e3b1a92017-05-16 11:51:18 -0500385
Chip Boling27275992017-09-22 15:17:04 -0500386 self._discovery_deferred = reactor.callLater(5, self._discover_onus)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500387
Chip Bolingab8863d2018-03-22 14:50:31 -0500388 # If here, initial settings were successfully written to hardware
389
390 super(PonPort, self).finish_startup()
Chip Boling27275992017-09-22 15:17:04 -0500391 returnValue('Enabled')
Chip Boling7294b252017-06-15 16:16:55 -0500392
Chip Bolingab8863d2018-03-22 14:50:31 -0500393 def finish_stop(self):
Chip Bolingfd1fd372017-12-20 13:34:12 -0600394 # Remove all existing ONUs. They will need to be re-discovered
Chip Bolingab8863d2018-03-22 14:50:31 -0500395 dl = []
Chip Bolingfd1fd372017-12-20 13:34:12 -0600396 onu_ids = frozenset(self._onu_by_id.keys())
397 for onu_id in onu_ids:
398 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500399 dl.append(self.delete_onu(onu_id))
400
Chip Bolingfd1fd372017-12-20 13:34:12 -0600401 except Exception as e:
402 self.log.exception('onu-cleanup', onu_id=onu_id, e=e)
403
Chip Bolingab8863d2018-03-22 14:50:31 -0500404 dl.append(self._set_pon_config("enabled", False))
Chip Bolingab8863d2018-03-22 14:50:31 -0500405 return defer.gatherResults(dl, consumeErrors=True)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500406
407 @inlineCallbacks
408 def reset(self):
Chip Boling7294b252017-06-15 16:16:55 -0500409 """
410 Set the PON Port to a known good state on initial port startup. Actual
411 PON 'Start' is done elsewhere
412 """
Chip Bolingb4868192018-11-01 16:38:44 -0500413 initial_port_state = AdminState.ENABLED
Chip Boling27275992017-09-22 15:17:04 -0500414 self.log.info('reset', initial_state=initial_port_state)
Chip Boling7294b252017-06-15 16:16:55 -0500415
Chip Boling252c7772017-08-16 10:13:17 -0500416 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500417 self.deferred = self._get_pon_config()
418 results = yield self.deferred
Chip Boling27275992017-09-22 15:17:04 -0500419 enabled = results.get('enabled', False)
Chip Boling252c7772017-08-16 10:13:17 -0500420
421 except Exception as e:
Chip Boling27275992017-09-22 15:17:04 -0500422 self.log.exception('get-config', e=e)
423 enabled = False
Chip Boling252c7772017-08-16 10:13:17 -0500424
Chip Boling27275992017-09-22 15:17:04 -0500425 enable = initial_port_state == AdminState.ENABLED
Chip Boling252c7772017-08-16 10:13:17 -0500426
Chip Boling27275992017-09-22 15:17:04 -0500427 if enable != enabled:
Chip Boling3e3b1a92017-05-16 11:51:18 -0500428 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500429 self.deferred = yield self._set_pon_config("enabled", enable)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500430 except Exception as e:
Chip Boling27275992017-09-22 15:17:04 -0500431 self.log.exception('reset-enabled', e=e, enabled=enabled)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500432
Chip Boling27275992017-09-22 15:17:04 -0500433 # TODO: Move to 'set_pon_config' method and also make sure GRPC/Port is ok
434 self._admin_state = AdminState.ENABLED if enable else AdminState.DISABLED
Chip Boling3e3b1a92017-05-16 11:51:18 -0500435
Chip Boling252c7772017-08-16 10:13:17 -0500436 try:
Chip Boling27275992017-09-22 15:17:04 -0500437 # Walk the provisioned ONU list and disable any exiting ONUs
438 results = yield self._get_onu_config()
Chip Boling3e3b1a92017-05-16 11:51:18 -0500439
Chip Boling252c7772017-08-16 10:13:17 -0500440 if isinstance(results, list) and len(results) > 0:
441 onu_configs = OltConfig.Pon.Onu.decode(results)
Chip Boling27275992017-09-22 15:17:04 -0500442 dl = []
Chip Boling252c7772017-08-16 10:13:17 -0500443 for onu_id in onu_configs.iterkeys():
Chip Boling27275992017-09-22 15:17:04 -0500444 dl.append(self.delete_onu(onu_id))
Chip Boling3e3b1a92017-05-16 11:51:18 -0500445
Chip Boling27275992017-09-22 15:17:04 -0500446 try:
447 if len(dl) > 0:
448 yield defer.gatherResults(dl, consumeErrors=True)
449
450 except Exception as e:
Chip Bolingab8863d2018-03-22 14:50:31 -0500451 self.log.exception('rest-ONU-delete', e=e)
Chip Boling27275992017-09-22 15:17:04 -0500452 pass # Non-fatal
Chip Boling252c7772017-08-16 10:13:17 -0500453
454 except Exception as e:
455 self.log.exception('onu-delete', e=e)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500456
Chip Boling5561d552017-07-07 15:11:26 -0500457 returnValue('Reset complete')
458
Chip Bolingb4868192018-11-01 16:38:44 -0500459 def gem_ids(self, logical_port, flow_vlan, multicast_gems=False):
Chip Boling252c7772017-08-16 10:13:17 -0500460 """
461 Get all GEM Port IDs used on a given PON
462
Chip Bolingb4868192018-11-01 16:38:44 -0500463 :param logical_port: (int) Logical port number of ONU. None if for all ONUs
Chip Bolingab8863d2018-03-22 14:50:31 -0500464 on PON, if Multicast, VID for Multicast, or None for all
Chip Boling27275992017-09-22 15:17:04 -0500465 Multicast GEMPorts
Chip Bolingb4868192018-11-01 16:38:44 -0500466 :param flow_vlan: (int) If not None, this is the ingress tag (c-tag)
Chip Boling27275992017-09-22 15:17:04 -0500467 :param multicast_gems: (boolean) Select from available Multicast GEM Ports
468 :return: (dict) data_gem -> key -> onu-id, value -> tuple(sorted list of GEM Port IDs, onu_vid)
469 mcast_gem-> key -> mcast-vid, value -> GEM Port IDs
Chip Boling252c7772017-08-16 10:13:17 -0500470 """
471 gem_ids = {}
Chip Boling27275992017-09-22 15:17:04 -0500472
473 if multicast_gems:
474 # Multicast GEMs belong to the PON, but we may need to register them on
Chip Bolingb4868192018-11-01 16:38:44 -0500475 # all ONUs. TODO: Rework when BBF MCAST is addressed in VOLTHA v2.O+
476 for vlan, gem_port in self._mcast_gem_ports.iteritems():
Chip Bolingab8863d2018-03-22 14:50:31 -0500477 if logical_port is None or (logical_port == vlan and logical_port in self.olt.multicast_vlans):
Chip Boling27275992017-09-22 15:17:04 -0500478 gem_ids[vlan] = ([gem_port.gem_id], None)
479 else:
480 for onu_id, onu in self._onu_by_id.iteritems():
Chip Bolingab8863d2018-03-22 14:50:31 -0500481 if logical_port is None or logical_port == onu.logical_port:
Chip Bolingb4868192018-11-01 16:38:44 -0500482 gem_ids[onu_id] = (onu.gem_ids(), flow_vlan)
Chip Boling252c7772017-08-16 10:13:17 -0500483 return gem_ids
484
Chip Boling27275992017-09-22 15:17:04 -0500485 def _get_pon_config(self):
Chip Boling7294b252017-06-15 16:16:55 -0500486 uri = AdtranOltHandler.GPON_PON_CONFIG_URI.format(self._pon_id)
487 name = 'pon-get-config-{}'.format(self._pon_id)
488 return self._parent.rest_client.request('GET', uri, name=name)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500489
Chip Boling27275992017-09-22 15:17:04 -0500490 def _get_onu_config(self, onu_id=None):
Chip Boling252c7772017-08-16 10:13:17 -0500491 if onu_id is None:
492 uri = AdtranOltHandler.GPON_ONU_CONFIG_LIST_URI.format(self._pon_id)
493 else:
494 uri = AdtranOltHandler.GPON_ONU_CONFIG_URI.format(self._pon_id, onu_id)
495
Chip Boling7294b252017-06-15 16:16:55 -0500496 name = 'pon-get-onu_config-{}-{}'.format(self._pon_id, onu_id)
497 return self._parent.rest_client.request('GET', uri, name=name)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500498
Chip Boling27275992017-09-22 15:17:04 -0500499 def _set_pon_config(self, leaf, value):
Chip Boling3e3b1a92017-05-16 11:51:18 -0500500 data = json.dumps({leaf: value})
Chip Boling7294b252017-06-15 16:16:55 -0500501 uri = AdtranOltHandler.GPON_PON_CONFIG_URI.format(self._pon_id)
502 name = 'pon-set-config-{}-{}-{}'.format(self._pon_id, leaf, str(value))
Chip Boling88354fb2018-09-21 12:17:19 -0500503 # If no optics on PON, then PON config fails with status 400, suppress this
504 suppress_error = len(self.onu_ids) == 0
505 return self._parent.rest_client.request('PATCH', uri, data=data, name=name,
506 suppress_error=suppress_error)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500507
Chip Boling252c7772017-08-16 10:13:17 -0500508 def _discover_onus(self):
Chip Boling27275992017-09-22 15:17:04 -0500509 self.log.debug('discovery', state=self._admin_state, in_sync=self._in_sync)
Chip Boling7294b252017-06-15 16:16:55 -0500510 if self._admin_state == AdminState.ENABLED:
Chip Boling27275992017-09-22 15:17:04 -0500511 if self._in_sync:
512 data = json.dumps({'pon-id': self._pon_id})
513 uri = AdtranOltHandler.GPON_PON_DISCOVER_ONU
514 name = 'pon-discover-onu-{}'.format(self._pon_id)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500515
Chip Boling27275992017-09-22 15:17:04 -0500516 self._discovery_deferred = self._parent.rest_client.request('POST', uri, data, name=name)
517 self._discovery_deferred.addBoth(self._onu_discovery_init_complete)
518 else:
519 self.discovery_deferred = reactor.callLater(0,
520 self._onu_discovery_init_complete,
521 None)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500522
Chip Bolingab8863d2018-03-22 14:50:31 -0500523 def _onu_discovery_init_complete(self, _result):
Chip Boling3e3b1a92017-05-16 11:51:18 -0500524 """
525 This method is called after the REST POST to request ONU discovery is
526 completed. The results (body) of the post is always empty / 204 NO CONTENT
527 """
Chip Boling7294b252017-06-15 16:16:55 -0500528 delay = self._no_onu_discover_tick if len(self._onus) == 0 else self._discovery_tick
Chip Boling3e3b1a92017-05-16 11:51:18 -0500529 delay += random.uniform(-delay / 10, delay / 10)
Chip Boling252c7772017-08-16 10:13:17 -0500530 self._discovery_deferred = reactor.callLater(delay, self._discover_onus)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500531
Chip Bolingab8863d2018-03-22 14:50:31 -0500532 def sync_hardware(self):
533 if self.state == AdtnPort.State.RUNNING or self.state == AdtnPort.State.STOPPED:
Chip Boling27275992017-09-22 15:17:04 -0500534 def read_config(results):
535 self.log.debug('read-config', results=results)
536 config = OltConfig.Pon.decode([results])
537 assert self.pon_id in config, 'sync-pon-not-found-{}'.format(self.pon_id)
538 config = config[self.pon_id]
539 self._in_sync = True
540
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500541 dl = []
Chip Boling27275992017-09-22 15:17:04 -0500542
543 if self.enabled != config.enabled:
544 self._in_sync = False
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500545 self._expedite_sync = True
Chip Boling27275992017-09-22 15:17:04 -0500546 dl.append(self._set_pon_config("enabled", self.enabled))
547
Chip Bolingab8863d2018-03-22 14:50:31 -0500548 elif self.state == AdtnPort.State.RUNNING:
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500549 if self.deployment_range != config.deployment_range:
550 self._in_sync = False
551 self._expedite_sync = True
552 dl.append(self._set_pon_config("deployment-range",
553 self.deployment_range))
554
Chip Boling88354fb2018-09-21 12:17:19 -0500555 # A little side note: FEC enable/disable cannot be changed and
556 # will remain in the previous status until an optical module
557 # is plugged in.
Chip Boling27275992017-09-22 15:17:04 -0500558 if self.downstream_fec_enable != config.downstream_fec_enable:
559 self._in_sync = False
560 dl.append(self._set_pon_config("downstream-fec-enable",
561 self.downstream_fec_enable))
562
563 if self.upstream_fec_enable != config.upstream_fec_enable:
564 self._in_sync = False
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500565 self._expedite_sync = True
Chip Boling27275992017-09-22 15:17:04 -0500566 dl.append(self._set_pon_config("upstream-fec-enable",
567 self.upstream_fec_enable))
Chip Bolingfd1fd372017-12-20 13:34:12 -0600568 defer.gatherResults(dl, consumeErrors=True)
569 return config.onus
Chip Boling27275992017-09-22 15:17:04 -0500570
Chip Bolingfd1fd372017-12-20 13:34:12 -0600571 def sync_onus(hw_onus):
Chip Bolingab8863d2018-03-22 14:50:31 -0500572 if self.state == AdtnPort.State.RUNNING:
Chip Bolingfd1fd372017-12-20 13:34:12 -0600573 self.log.debug('sync-pon-onu-results', config=hw_onus)
Chip Boling27275992017-09-22 15:17:04 -0500574
575 # ONU's have their own sync task, extra (should be deleted) are
Chip Boling88354fb2018-09-21 12:17:19 -0500576 # handled here.
Chip Boling27275992017-09-22 15:17:04 -0500577
Chip Bolingfd1fd372017-12-20 13:34:12 -0600578 hw_onu_ids = frozenset(hw_onus.keys())
Chip Boling27275992017-09-22 15:17:04 -0500579 my_onu_ids = frozenset(self._onu_by_id.keys())
580
581 extra_onus = hw_onu_ids - my_onu_ids
582 dl = [self.delete_onu(onu_id) for onu_id in extra_onus]
583
Chip Boling88354fb2018-09-21 12:17:19 -0500584 if self.activation_method == "autoactivate":
585 # Autoactivation of ONUs requires missing ONU detection. If
586 # not found, create them here but let TCont/GEM-Port restore be
587 # handle by ONU H/w sync logic.
588 for onu in [self._onu_by_id[onu_id] for onu_id in my_onu_ids - hw_onu_ids
589 if self._onu_by_id.get(onu_id) is not None]:
590 dl.append(onu.create(dict(), dict(), reflow=True))
591
Chip Boling27275992017-09-22 15:17:04 -0500592 return defer.gatherResults(dl, consumeErrors=True)
593
594 def failure(reason, what):
595 self.log.error('hardware-sync-{}-failed'.format(what), reason=reason)
596 self._in_sync = False
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500597 self._expedite_sync = False
Chip Boling27275992017-09-22 15:17:04 -0500598
599 def reschedule(_):
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500600 # Speed up sequential resync a limited number of times if out of sync.
601
Chip Bolingab8863d2018-03-22 14:50:31 -0500602 delay = self.sync_tick
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500603
604 if self._expedite_sync:
605 self._expedite_count += 1
606 if self._expedite_count < 5:
607 delay = 1
608 else:
609 self._expedite_count = 0
610
Chip Boling27275992017-09-22 15:17:04 -0500611 delay += random.uniform(-delay / 10, delay / 10)
Chip Bolingab8863d2018-03-22 14:50:31 -0500612 self.sync_deferred = reactor.callLater(delay, self.sync_hardware)
Chip Boling27275992017-09-22 15:17:04 -0500613
Chip Bolingab8863d2018-03-22 14:50:31 -0500614 self.sync_deferred = self._get_pon_config()
615 self.sync_deferred.addCallbacks(read_config, failure, errbackArgs=['get-config'])
616 self.sync_deferred.addCallbacks(sync_onus, failure, errbackArgs=['pon-sync'])
617 self.sync_deferred.addBoth(reschedule)
Chip Boling27275992017-09-22 15:17:04 -0500618
Chip Boling3e3b1a92017-05-16 11:51:18 -0500619 def process_status_poll(self, status):
620 """
621 Process PON status poll request
622
623 :param status: (OltState.Pon object) results from RESTCONF GET
624 """
Chip Boling252c7772017-08-16 10:13:17 -0500625 self.log.debug('process-status-poll', status=status)
Chip Boling7294b252017-06-15 16:16:55 -0500626
627 if self._admin_state != AdminState.ENABLED:
Chip Boling3e3b1a92017-05-16 11:51:18 -0500628 return
629
Chip Bolingfd1fd372017-12-20 13:34:12 -0600630 # Process LOS list
631 self._process_los_alarms(frozenset(status.ont_los))
632
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500633 # Get new/missing from the discovered ONU leaf. Stale ONUs from previous
634 # configs are now cleaned up during h/w re-sync/reflow.
Chip Boling3e3b1a92017-05-16 11:51:18 -0500635
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500636 new, rediscovered_onus = self._process_status_onu_discovered_list(status.discovered_onu)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500637
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500638 # Process newly discovered ONU list and rediscovered ONUs
Chip Bolingb4868192018-11-01 16:38:44 -0500639
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500640 for serial_number in new | rediscovered_onus:
Chip Boling3e3b1a92017-05-16 11:51:18 -0500641 reactor.callLater(0, self.add_onu, serial_number, status)
642
Chip Bolingfd1fd372017-12-20 13:34:12 -0600643 # PON Statistics
Chip Bolingc0451382018-08-24 14:21:53 -0500644 timestamp = arrow.utcnow().float_timestamp
645 self._process_statistics(status, timestamp)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500646
Chip Boling27275992017-09-22 15:17:04 -0500647 # Process ONU info. Note that newly added ONUs will not be processed
648 # until the next pass
Chip Bolingc0451382018-08-24 14:21:53 -0500649 self._update_onu_status(status.onus, timestamp)
Chip Boling27275992017-09-22 15:17:04 -0500650
Chip Bolingfd1fd372017-12-20 13:34:12 -0600651 # Process GEM Port information
Chip Bolingc0451382018-08-24 14:21:53 -0500652 self._update_gem_status(status.gems, timestamp)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600653
Chip Bolingc0451382018-08-24 14:21:53 -0500654 def _process_statistics(self, status, timestamp):
655 self.timestamp = timestamp
Chip Bolingfd1fd372017-12-20 13:34:12 -0600656 self.rx_packets = status.rx_packets
657 self.rx_bytes = status.rx_bytes
658 self.tx_packets = status.tx_packets
659 self.tx_bytes = status.tx_bytes
660 self.tx_bip_errors = status.tx_bip_errors
661
Chip Bolingc0451382018-08-24 14:21:53 -0500662 def _update_onu_status(self, onus, timestamp):
Chip Boling27275992017-09-22 15:17:04 -0500663 """
664 Process ONU status for this PON
665 :param onus: (dict) onu_id: ONU State
666 """
667 for onu_id, onu_status in onus.iteritems():
668 if onu_id in self._onu_by_id:
Chip Bolingfd1fd372017-12-20 13:34:12 -0600669 onu = self._onu_by_id[onu_id]
Chip Bolingc0451382018-08-24 14:21:53 -0500670 onu.timestamp = timestamp
Chip Bolingfd1fd372017-12-20 13:34:12 -0600671 onu.rssi = onu_status.rssi
672 onu.equalization_delay = onu_status.equalization_delay
673 onu.equalization_delay = onu_status.equalization_delay
674 onu.fiber_length = onu_status.fiber_length
Chip Bolingbb15b512018-06-01 11:39:58 -0500675 onu.password = onu_status.reported_password
Chip Bolingfd1fd372017-12-20 13:34:12 -0600676
Chip Bolingc0451382018-08-24 14:21:53 -0500677 def _update_gem_status(self, gems, timestamp):
Chip Bolingfd1fd372017-12-20 13:34:12 -0600678 for gem_id, gem_status in gems.iteritems():
679 onu = self._onu_by_id.get(gem_status.onu_id)
680 if onu is not None:
681 gem_port = onu.gem_port(gem_status.gem_id)
682 if gem_port is not None:
Chip Bolingc0451382018-08-24 14:21:53 -0500683 gem_port.timestamp = timestamp
Chip Bolingfd1fd372017-12-20 13:34:12 -0600684 gem_port.rx_packets = gem_status.rx_packets
685 gem_port.rx_bytes = gem_status.rx_bytes
686 gem_port.tx_packets = gem_status.tx_packets
687 gem_port.tx_bytes = gem_status.tx_bytes
Chip Boling27275992017-09-22 15:17:04 -0500688
689 def _process_los_alarms(self, ont_los):
690 """
691 Walk current LOS and set/clear LOS as appropriate
692 :param ont_los: (frozenset) ONU IDs of ONUs in LOS alarm state
693 """
694 cleared_alarms = self._active_los_alarms - ont_los
695 new_alarms = ont_los - self._active_los_alarms
696
Chip Boling27275992017-09-22 15:17:04 -0500697 if len(cleared_alarms) > 0 or len(new_alarms) > 0:
698 self.log.info('onu-los', cleared=cleared_alarms, new=new_alarms)
699
700 for onu_id in cleared_alarms:
Chip Boling27275992017-09-22 15:17:04 -0500701 self._active_los_alarms.remove(onu_id)
Chip Bolingbffef5e2018-08-07 14:53:12 -0500702 OnuLosAlarm(self.olt.alarms, onu_id).clear_alarm()
Chip Boling27275992017-09-22 15:17:04 -0500703
704 for onu_id in new_alarms:
705 self._active_los_alarms.add(onu_id)
Chip Bolingbffef5e2018-08-07 14:53:12 -0500706 OnuLosAlarm(self.olt.alarms, onu_id).raise_alarm()
Chip Bolingfd1fd372017-12-20 13:34:12 -0600707 self.delete_onu(onu_id)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500708
Chip Boling3e3b1a92017-05-16 11:51:18 -0500709 def _process_status_onu_discovered_list(self, discovered_onus):
710 """
Chip Bolingae298012017-08-28 08:55:17 -0500711 Look for new ONUs
Chip Boling3e3b1a92017-05-16 11:51:18 -0500712
713 :param discovered_onus: (frozenset) Set of ONUs currently discovered
714 """
Chip Boling252c7772017-08-16 10:13:17 -0500715 self.log.debug('discovered-ONUs', list=discovered_onus)
716
717 # Only request discovery if activation is auto-discovery or auto-activate
Chip Boling88354fb2018-09-21 12:17:19 -0500718 continue_discovery = ['autodiscovery', 'autoactivate']
Chip Boling252c7772017-08-16 10:13:17 -0500719
720 if self._activation_method not in continue_discovery:
721 return set(), set()
Chip Boling3e3b1a92017-05-16 11:51:18 -0500722
Chip Boling7294b252017-06-15 16:16:55 -0500723 my_onus = frozenset(self._onus.keys())
Chip Boling3e3b1a92017-05-16 11:51:18 -0500724
725 new_onus = discovered_onus - my_onus
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500726 rediscovered_onus = my_onus & discovered_onus
Chip Boling3e3b1a92017-05-16 11:51:18 -0500727
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500728 return new_onus, rediscovered_onus
Chip Boling3e3b1a92017-05-16 11:51:18 -0500729
Chip Boling252c7772017-08-16 10:13:17 -0500730 def _get_onu_info(self, serial_number):
731 """
732 Parse through available xPON information for ONU configuration settings
733 :param serial_number: (string) Decoded (not base64) serial number string
734 :return: (dict) onu config data or None on lookup failure
735 """
736 try:
Chip Bolingab8863d2018-03-22 14:50:31 -0500737 if self.activation_method == "autodiscovery":
Chip Bolingb4868192018-11-01 16:38:44 -0500738 # if self.authentication_method == 'serial-number':
739 raise NotImplemented('TODO: Not supported at this time')
Chip Boling252c7772017-08-16 10:13:17 -0500740
Chip Boling88354fb2018-09-21 12:17:19 -0500741 elif self.activation_method == "autoactivate":
742 # TODO: Currently a somewhat copy of the xPON way to do things
743 # update here with Technology profile info when it becomes available
Chip Bolingb4868192018-11-01 16:38:44 -0500744 activate_onu, tconts, gem_ports = self.get_device_profile_info(serial_number)
745
Chip Boling88354fb2018-09-21 12:17:19 -0500746 try:
747 # TODO: (SEBA) All of this can be greatly simplified once we fully
748 # deprecate xPON support
Chip Bolingb4868192018-11-01 16:38:44 -0500749 vont_ani = next(info for _, info in self._v_ont_anis.items()
Chip Boling88354fb2018-09-21 12:17:19 -0500750 if info.get('expected-serial-number') == serial_number)
751
Chip Boling88354fb2018-09-21 12:17:19 -0500752 onu_id = vont_ani['onu-id']
753 enabled = vont_ani['enabled']
754 channel_speed = vont_ani['upstream-channel-speed']
Chip Bolingb4868192018-11-01 16:38:44 -0500755 upstream_fec_enabled = self._ont_anis[vont_ani['name']]['upstream-fec']
Chip Boling88354fb2018-09-21 12:17:19 -0500756
757 except StopIteration:
758 # Can happen if vont-ani or ont-ani has not yet been configured
759 self.log.error('no-vont-or-ont-autoactivate')
760 return None, False
761
762 except Exception as e:
763 self.log.exception('autoactivate', e=e)
764 raise
Chip Boling252c7772017-08-16 10:13:17 -0500765 else:
Chip Boling88354fb2018-09-21 12:17:19 -0500766 self.log.debug('unsupported-activation-method', method=self.activation_method)
767 return None, False
Chip Boling252c7772017-08-16 10:13:17 -0500768
769 onu_info = {
Chip Boling27275992017-09-22 15:17:04 -0500770 'device-id': self.olt.device_id,
Chip Boling252c7772017-08-16 10:13:17 -0500771 'serial-number': serial_number,
Chip Boling252c7772017-08-16 10:13:17 -0500772 'pon': self,
773 'onu-id': onu_id,
774 'enabled': enabled,
775 'upstream-channel-speed': channel_speed,
Chip Bolingfd1fd372017-12-20 13:34:12 -0600776 'upstream-fec': upstream_fec_enabled,
Chip Boling252c7772017-08-16 10:13:17 -0500777 'password': Onu.DEFAULT_PASSWORD,
Chip Bolingae298012017-08-28 08:55:17 -0500778 't-conts': tconts,
779 'gem-ports': gem_ports,
Chip Boling252c7772017-08-16 10:13:17 -0500780 }
Chip Bolingb4868192018-11-01 16:38:44 -0500781 intf_id = platform.intf_id_to_port_no(self._pon_id, Port.PON_OLT)
782
783 # TODO: Currently only one ONU port and it is hardcoded to port 0
784 onu_info['uni-ports'] = [platform.mk_uni_port_num(intf_id, onu_id)]
Chip Boling88354fb2018-09-21 12:17:19 -0500785
Chip Bolingae298012017-08-28 08:55:17 -0500786 # Hold off ONU activation until at least one GEM Port is defined.
Chip Boling88354fb2018-09-21 12:17:19 -0500787 self.log.debug('onu-info-tech-profiles', gem_ports=gem_ports)
Chip Bolingae298012017-08-28 08:55:17 -0500788
Chip Boling3971d242018-06-06 10:26:34 -0500789 # return onu_info
Chip Boling88354fb2018-09-21 12:17:19 -0500790 return onu_info, activate_onu
Chip Boling252c7772017-08-16 10:13:17 -0500791
792 except Exception as e:
Chip Boling88354fb2018-09-21 12:17:19 -0500793 self.log.exception('get-onu-info-tech-profiles', e=e)
794 return None, False
Chip Boling252c7772017-08-16 10:13:17 -0500795
Chip Boling3e3b1a92017-05-16 11:51:18 -0500796 @inlineCallbacks
Chip Bolingfd1fd372017-12-20 13:34:12 -0600797 def add_onu(self, serial_number_64, status):
Chip Boling88354fb2018-09-21 12:17:19 -0500798 """
799 Add an ONU to the PON
800
801 TODO: This needs major refactoring after xPON is deprecated to be more maintainable
802 """
Chip Bolingfd1fd372017-12-20 13:34:12 -0600803 serial_number = Onu.serial_number_to_string(serial_number_64)
804 self.log.info('add-onu', serial_number=serial_number,
805 serial_number_64=serial_number_64, status=status)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500806
Chip Bolingb4868192018-11-01 16:38:44 -0500807 # It takes a little while for a new ONU to be removed from the discovery
808 # list. Return early here so extra ONU IDs are not allocated
809 if serial_number_64 in self._onus:
Chip Boling88354fb2018-09-21 12:17:19 -0500810 returnValue('wait-for-fpga')
811
812 onu_info, activate_onu = self._get_onu_info(serial_number)
813
814 if activate_onu:
Chip Boling88354fb2018-09-21 12:17:19 -0500815 alarm = OnuDiscoveryAlarm(self.olt.alarms, self.pon_id, serial_number)
816 reactor.callLater(0, alarm.raise_alarm)
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500817
Chip Bolingfd1fd372017-12-20 13:34:12 -0600818 if serial_number_64 not in status.onus or onu_info['onu-id'] in self._active_los_alarms:
Chip Bolingff3087f2017-10-12 09:26:29 -0500819 onu = None
Chip Bolingfd1fd372017-12-20 13:34:12 -0600820 onu_id = onu_info['onu-id']
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500821
Chip Bolingab8863d2018-03-22 14:50:31 -0500822 if serial_number_64 in self._onus and onu_id in self._onu_by_id:
823 # Handles fast entry into this task before FPGA can set/clear results
824 returnValue('sticky-onu')
825
826 elif (serial_number_64 in self._onus and onu_id not in self._onu_by_id) or \
827 (serial_number_64 not in self._onus and onu_id in self._onu_by_id):
Chip Bolingfd1fd372017-12-20 13:34:12 -0600828 # May be here due to unmanaged power-cycle on OLT or fiber bounced for a
Chip Boling88354fb2018-09-21 12:17:19 -0500829 # previously activated ONU.
Chip Bolingb4868192018-11-01 16:38:44 -0500830 #
831 # TODO: Track when the ONU was discovered, and if > some maximum amount
832 # place the ONU (with serial number & ONU ID) on a wait list and
833 # use that to recover the ONU ID should it show up within a
834 # reasonable amount of time. Periodically groom the wait list and
835 # delete state ONUs so we can reclaim the ONU ID.
836 #
837 returnValue('waiting-for-fpga') # non-XPON mode will not
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500838
839 elif len(self._onus) >= self.MAX_ONUS_SUPPORTED:
Chip Bolingff3087f2017-10-12 09:26:29 -0500840 self.log.warning('max-onus-provisioned', count=len(self._onus))
Chip Bolingab8863d2018-03-22 14:50:31 -0500841 returnValue('max-onus-reached')
Chip Bolingff3087f2017-10-12 09:26:29 -0500842
Chip Boling252c7772017-08-16 10:13:17 -0500843 else:
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500844 # TODO: Make use of upstream_channel_speed variable
845 onu = Onu(onu_info)
Chip Bolingfd1fd372017-12-20 13:34:12 -0600846 self._onus[serial_number_64] = onu
Chip Bolingdb61c6a2017-09-27 12:36:45 -0500847 self._onu_by_id[onu.onu_id] = onu
Chip Boling3e3b1a92017-05-16 11:51:18 -0500848
Chip Bolingff3087f2017-10-12 09:26:29 -0500849 if onu is not None:
Chip Bolingb4868192018-11-01 16:38:44 -0500850 tconts = onu_info.pop('t-conts')
851 gem_ports = onu_info.pop('gem-ports')
Chip Boling252c7772017-08-16 10:13:17 -0500852
Chip Boling88354fb2018-09-21 12:17:19 -0500853 if activate_onu:
Chip Bolingb4868192018-11-01 16:38:44 -0500854 _onu_device = self._parent.add_onu_device(self._port_no, # PON ID
855 onu.onu_id, # ONU ID
Chip Boling88354fb2018-09-21 12:17:19 -0500856 serial_number,
Chip Bolingb4868192018-11-01 16:38:44 -0500857 tconts,
858 gem_ports)
Chip Boling88354fb2018-09-21 12:17:19 -0500859 try:
Chip Bolingb4868192018-11-01 16:38:44 -0500860 # Add Multicast to PON on a per-ONU basis until xPON multicast support
861 # is ready
Chip Bolingff3087f2017-10-12 09:26:29 -0500862 # In xPON/BBF, mcast gems tie back to the channel-pair
863 # MCAST VLAN IDs stored as a negative value
Chip Boling252c7772017-08-16 10:13:17 -0500864
Chip Bolingb4868192018-11-01 16:38:44 -0500865 # for id_or_vid, gem_port in gem_ports.iteritems(): # TODO: Deprecate this when BBF ready
866 # try:
867 # if gem_port.multicast:
868 # self.log.debug('id-or-vid', id_or_vid=id_or_vid)
869 # vid = self.olt.multicast_vlans[0] if len(self.olt.multicast_vlans) else None
870 # if vid is not None:
871 # self.add_mcast_gem_port(gem_port, vid)
872 #
873 # except Exception as e:
874 # self.log.exception('id-or-vid', e=e)
Chip Boling252c7772017-08-16 10:13:17 -0500875
Chip Boling88354fb2018-09-21 12:17:19 -0500876 # TODO: Need to clean up TCont and GEM-Port on ONU delete in non-xPON mode
877 _results = yield onu.create(tconts, gem_ports)
Chip Bolingef0e2fa2017-10-06 14:33:01 -0500878
Chip Bolingff3087f2017-10-12 09:26:29 -0500879 except Exception as e:
Chip Bolingfd1fd372017-12-20 13:34:12 -0600880 self.log.exception('add-onu', serial_number=serial_number_64, e=e)
Chip Boling88354fb2018-09-21 12:17:19 -0500881 # allowable exception. H/w re-sync will recover any issues
Chip Boling3e3b1a92017-05-16 11:51:18 -0500882
Chip Boling88354fb2018-09-21 12:17:19 -0500883 @property
Chip Boling3e3b1a92017-05-16 11:51:18 -0500884 def get_next_onu_id(self):
Chip Bolingb4868192018-11-01 16:38:44 -0500885 return self._parent.resource_mgr.get_onu_id(self._pon_id)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500886
Chip Boling88354fb2018-09-21 12:17:19 -0500887 def release_onu_id(self, onu_id):
Chip Bolingb4868192018-11-01 16:38:44 -0500888 self._parent.resource_mgr.free_onu_id(self._pon_id, onu_id)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500889
Chip Bolingae298012017-08-28 08:55:17 -0500890 @inlineCallbacks
Chip Bolingff3087f2017-10-12 09:26:29 -0500891 def _remove_from_hardware(self, onu_id):
Chip Boling252c7772017-08-16 10:13:17 -0500892 uri = AdtranOltHandler.GPON_ONU_CONFIG_URI.format(self._pon_id, onu_id)
Chip Boling7294b252017-06-15 16:16:55 -0500893 name = 'pon-delete-onu-{}-{}'.format(self._pon_id, onu_id)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500894
Chip Bolingff3087f2017-10-12 09:26:29 -0500895 try:
896 yield self._parent.rest_client.request('DELETE', uri, name=name)
897
Chip Bolingfd1fd372017-12-20 13:34:12 -0600898 except RestInvalidResponseCode as e:
899 if e.code != 404:
900 self.log.exception('onu-delete', e=e)
901
Chip Bolingff3087f2017-10-12 09:26:29 -0500902 except Exception as e:
903 self.log.exception('onu-hw-delete', onu_id=onu_id, e=e)
904
905 @inlineCallbacks
906 def delete_onu(self, onu_id):
Chip Bolingae298012017-08-28 08:55:17 -0500907 onu = self._onu_by_id.get(onu_id)
908
Chip Boling252c7772017-08-16 10:13:17 -0500909 # Remove from any local dictionary
910 if onu_id in self._onu_by_id:
911 del self._onu_by_id[onu_id]
Chip Boling88354fb2018-09-21 12:17:19 -0500912 self.release_onu_id(onu.onu_id)
Chip Bolingff3087f2017-10-12 09:26:29 -0500913
Chip Bolingfd1fd372017-12-20 13:34:12 -0600914 for sn_64 in [onu.serial_number_64 for onu in self.onus if onu.onu_id == onu_id]:
915 del self._onus[sn_64]
Chip Bolingae298012017-08-28 08:55:17 -0500916
Chip Boling27275992017-09-22 15:17:04 -0500917 if onu is not None:
Chip Bolingef0e2fa2017-10-06 14:33:01 -0500918 proxy = onu.proxy_address
Chip Bolingfd1fd372017-12-20 13:34:12 -0600919 try:
920 onu.delete()
Chip Boling252c7772017-08-16 10:13:17 -0500921
Chip Bolingfd1fd372017-12-20 13:34:12 -0600922 except Exception as e:
923 self.log.exception('onu-delete', serial_number=onu.serial_number, e=e)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500924
Chip Bolingfd1fd372017-12-20 13:34:12 -0600925 else:
926 try:
927 yield self._remove_from_hardware(onu_id)
928
929 except Exception as e:
930 self.log.exception('onu-remove', serial_number=onu.serial_number, e=e)
Chip Bolingae298012017-08-28 08:55:17 -0500931
Chip Boling4912e782018-11-09 16:33:40 -0600932 # Remove from LOS list if needed
933 if onu.id in self._active_los_alarms:
934 self._active_los_alarms.remove(onu.id)
935
Chip Boling27275992017-09-22 15:17:04 -0500936 def add_mcast_gem_port(self, mcast_gem, vlan):
Chip Bolingae298012017-08-28 08:55:17 -0500937 """
Chip Boling27275992017-09-22 15:17:04 -0500938 Add any new Multicast GEM Ports to the PON
939 :param mcast_gem: (GemPort)
Chip Bolingae298012017-08-28 08:55:17 -0500940 """
Chip Boling27275992017-09-22 15:17:04 -0500941 if vlan in self._mcast_gem_ports:
942 return
943
944 assert len(self._mcast_gem_ports) == 0, 'Only 1 MCAST GEMPort until BBF Support'
945 assert 1 <= vlan <= 4095, 'Invalid Multicast VLAN ID'
946 assert len(self.olt.multicast_vlans) == 1, 'Only support 1 MCAST VLAN until BBF Support'
947
948 self._mcast_gem_ports[vlan] = mcast_gem
Chip Bolingb4868192018-11-01 16:38:44 -0500949
950 # ===========================================================================
951 #
952 # Some xPON methods that need refactoring
953
954 @property
955 def tconts(self):
956 return self._tconts
957
958 @property
959 def traffic_descriptors(self):
960 return self._traffic_descriptors
961
962 @property
963 def gem_ports(self):
964 return self._gem_ports
965
966 def get_device_profile_info(self, serial_number):
967 vont_ani_info = next((info for _, info in self._v_ont_anis.items()
968 if info.get('expected-serial-number') == serial_number), None)
969 # New ONU?
970 activate_onu = vont_ani_info is None
971
972 tconts = list()
973 gem_ports = list()
974
975 if activate_onu:
976 onu_id = self.get_next_onu_id
977 name = 'customer-{}-{}'.format(self.pon_id, onu_id)
978 vont_ani_info = {
979 'name' : name,
980 'enabled' : True,
981 'description' : '',
982 'pon-id' : self.pon_id,
983 'onu-id' : onu_id,
984 'expected-serial-number' : serial_number,
985 'expected-registration-id': '', # TODO: How about this?
986 'upstream-channel-speed' : 10000000000,
987 }
988 ont_ani_info = {
989 'name': name,
990 'description': '',
991 'enabled': True,
992 'upstream-fec': True,
993 'mgnt-gemport-aes': False
994 }
995 assert name not in self._v_ont_anis
996 assert name not in self._ont_anis
997 self._v_ont_anis[name] = vont_ani_info
998 self._ont_anis[name] = ont_ani_info
999
1000 tcont, tc, td = self.create_xpon_tcont(onu_id)
1001 from xpon.olt_tcont import OltTCont
1002 tc['object'] = OltTCont.create(tc,
1003 OltTrafficDescriptor.create(tc['td-ref']),
1004 self.pon_id, onu_id)
1005 self._tconts[tcont.name] = tc['object']
1006 tconts.append(tc)
1007
1008 # Now create the User-Data GEM-Ports
1009 num_priorities = 1 # TODO: Pull from tech-profile later
1010 for index in range(0, num_priorities):
1011 gem_port, gp = self.create_xpon_gem_port(onu_id, index, tcont)
1012
1013 from xpon.olt_gem_port import OltGemPort
1014 gp['object'] = OltGemPort.create(self, gp, self.pon_id, onu_id)
1015 self._gem_ports[gem_port.name] = gp['object']
1016 gem_ports.append(gp)
1017
1018 return activate_onu, tconts, gem_ports
1019
1020 def create_xpon_gem_port(self, onu_id, index, tcont):
1021 # gem port creation (this initial one is for untagged ONU data support / EAPOL)
1022 gem_port = GemportsConfigData()
1023 gem_port.gemport_id = platform.mk_gemport_id(self.pon_id, onu_id, idx=index)
1024 gem_port.name = 'gem-{}-{}-{}'.format(self.pon_id, onu_id, gem_port.gemport_id)
1025
1026 gem_port.tcont_ref = tcont.name
1027 gp = {
1028 'name': gem_port.name,
1029 'gemport-id': gem_port.gemport_id,
1030 'tcont-ref': gem_port.tcont_ref,
1031 'encryption': False,
1032 'traffic-class': 0,
1033 'data': gem_port
1034 }
1035 return gem_port, gp
1036
1037 def create_xpon_tcont(self, onu_id):
1038 """ Create the xPON TCONT Config data """
1039 tcont = TcontsConfigData()
1040 tcont.name = 'tcont-{}-{}-data'.format(self.pon_id, onu_id)
1041 pon_intf_onu_id = (self.pon_id, onu_id)
1042 tcont.alloc_id = self._parent.resource_mgr.get_alloc_id(pon_intf_onu_id)
1043 # TODO: Add release of alloc_id on ONU delete and/or TCONT delete
1044
1045 traffic_desc = TrafficDescriptorProfileData(name='BestEffort',
1046 fixed_bandwidth=0,
1047 assured_bandwidth=0,
1048 maximum_bandwidth=10000000000,
1049 priority=0,
1050 weight=0,
1051 additional_bw_eligibility_indicator=0)
1052 tc = {
1053 'name': tcont.name,
1054 'alloc-id': tcont.alloc_id,
1055 'pon-id': self.pon_id,
1056 'onu-id': onu_id,
1057 'td-ref': { # TODO: This should be the TD Name and the TD installed in xpon cache
1058 'name': traffic_desc.name,
1059 'fixed-bandwidth': traffic_desc.fixed_bandwidth,
1060 'assured-bandwidth': traffic_desc.assured_bandwidth,
1061 'maximum-bandwidth': traffic_desc.maximum_bandwidth,
1062 'priority': traffic_desc.priority,
1063 'weight': traffic_desc.weight,
1064 'additional-bw-eligibility-indicator': 0,
1065 'data': traffic_desc
1066 },
1067 'data': tcont
1068 }
1069 return tcont, tc, traffic_desc