blob: 76af28bc6346d4b12f85cfd7520bb707aa6e5662 [file] [log] [blame]
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001#
2# Copyright 2018 the original author or authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import structlog
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050017from twisted.internet import reactor
18from twisted.internet.defer import inlineCallbacks, returnValue, TimeoutError, failure
Matt Jeanneret72f96fc2019-02-11 10:53:05 -050019from pyvoltha.adapters.extensions.omci.omci_me import *
20from pyvoltha.adapters.extensions.omci.tasks.task import Task
21from pyvoltha.adapters.extensions.omci.omci_defs import *
22from adapters.brcm_openomci_onu.uni_port import *
23from adapters.brcm_openomci_onu.pon_port \
Matt Jeanneret810148b2019-09-29 12:44:01 -040024 import TASK_PRIORITY, DEFAULT_TPID, DEFAULT_GEM_PAYLOAD
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050025
26OP = EntityOperations
27RC = ReasonCodes
28
29
30class MibDownloadFailure(Exception):
31 """
32 This error is raised by default when the download fails
33 """
34
35
36class MibResourcesFailure(Exception):
37 """
38 This error is raised by when one or more resources required is not available
39 """
40
41
42class BrcmMibDownloadTask(Task):
43 """
Matt Jeanneret810148b2019-09-29 12:44:01 -040044 OpenOMCI MIB Download Bridge Setup Task
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050045
46 This task takes the legacy OMCI 'script' for provisioning the Broadcom ONU
47 and converts it to run as a Task on the OpenOMCI Task runner. This is
48 in order to begin to decompose service instantiation in preparation for
49 Technology Profile work.
50
51 Once technology profiles are ready, some of this task may hang around or
52 be moved into OpenOMCI if there are any very common settings/configs to do
53 for any profile that may be provided in the v2.0 release
54
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050055 """
56
Matt Jeanneret810148b2019-09-29 12:44:01 -040057 name = "Broadcom MIB Download Bridge Setup Task"
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050058
59 def __init__(self, omci_agent, handler):
60 """
61 Class initialization
62
63 :param omci_agent: (OmciAdapterAgent) OMCI Adapter agent
64 :param device_id: (str) ONU Device ID
65 """
66
67 self.log = structlog.get_logger(device_id=handler.device_id)
68 self.log.debug('function-entry')
69
70 super(BrcmMibDownloadTask, self).__init__(BrcmMibDownloadTask.name,
71 omci_agent,
72 handler.device_id,
73 priority=TASK_PRIORITY)
74 self._handler = handler
75 self._onu_device = omci_agent.get_device(handler.device_id)
76 self._local_deferred = None
77
78 # Frame size
79 self._max_gem_payload = DEFAULT_GEM_PAYLOAD
80
81 self._pon = handler.pon_port
82
83 # Defaults
84 self._input_tpid = DEFAULT_TPID
85 self._output_tpid = DEFAULT_TPID
86
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050087 # Entity IDs. IDs with values can probably be most anything for most ONUs,
88 # IDs set to None are discovered/set
89
90 self._mac_bridge_service_profile_entity_id = \
91 self._handler.mac_bridge_service_profile_entity_id
92 self._ieee_mapper_service_profile_entity_id = \
93 self._pon.ieee_mapper_service_profile_entity_id
94 self._mac_bridge_port_ani_entity_id = \
95 self._pon.mac_bridge_port_ani_entity_id
96 self._gal_enet_profile_entity_id = \
97 self._handler.gal_enet_profile_entity_id
98
99 self._free_ul_prior_q_entity_ids = set()
100 self._free_dl_prior_q_entity_ids = set()
101
102 def cancel_deferred(self):
103 self.log.debug('function-entry')
104 super(BrcmMibDownloadTask, self).cancel_deferred()
105
106 d, self._local_deferred = self._local_deferred, None
107 try:
108 if d is not None and not d.called:
109 d.cancel()
110 except:
111 pass
112
113 def start(self):
114 """
115 Start the MIB Download
116 """
117 self.log.debug('function-entry')
118 super(BrcmMibDownloadTask, self).start()
119 self._local_deferred = reactor.callLater(0, self.perform_mib_download)
120
121 def stop(self):
122 """
123 Shutdown MIB Synchronization tasks
124 """
125 self.log.debug('function-entry')
126 self.log.debug('stopping')
127
128 self.cancel_deferred()
129 super(BrcmMibDownloadTask, self).stop()
130
131 def check_status_and_state(self, results, operation=''):
132 """
133 Check the results of an OMCI response. An exception is thrown
134 if the task was cancelled or an error was detected.
135
136 :param results: (OmciFrame) OMCI Response frame
137 :param operation: (str) what operation was being performed
138 :return: True if successful, False if the entity existed (already created)
139 """
140 self.log.debug('function-entry')
141
142 omci_msg = results.fields['omci_message'].fields
143 status = omci_msg['success_code']
144 error_mask = omci_msg.get('parameter_error_attributes_mask', 'n/a')
145 failed_mask = omci_msg.get('failed_attributes_mask', 'n/a')
146 unsupported_mask = omci_msg.get('unsupported_attributes_mask', 'n/a')
147
Matt Jeannerete8fc53e2019-04-13 15:58:33 -0400148 self.log.debug("OMCI Result", operation=operation,
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500149 omci_msg=omci_msg, status=status,
150 error_mask=error_mask, failed_mask=failed_mask,
151 unsupported_mask=unsupported_mask)
152
153 if status == RC.Success:
154 self.strobe_watchdog()
155 return True
156
157 elif status == RC.InstanceExists:
158 return False
159
160 raise MibDownloadFailure('{} failed with a status of {}, error_mask: {}, failed_mask: {}, unsupported_mask: {}'
161 .format(operation, status, error_mask, failed_mask, unsupported_mask))
162
163 @inlineCallbacks
164 def perform_mib_download(self):
165 """
166 Send the commands to minimally configure the PON, Bridge, and
167 UNI ports for this device. The application of any service flows
168 and other characteristics are done as needed.
169 """
170 try:
171 self.log.debug('function-entry')
172 self.log.info('perform-download')
173
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500174 if self._handler.enabled and len(self._handler.uni_ports) > 0:
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700175 yield self._handler.core_proxy.device_reason_update(self.device_id, 'performing-initial-mib-download')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500176
177 try:
178 # Lock the UNI ports to prevent any alarms during initial configuration
179 # of the ONU
180 self.strobe_watchdog()
181
182 # Provision the initial bridge configuration
183 yield self.perform_initial_bridge_setup()
184
185 for uni_port in self._handler.uni_ports:
186 yield self.enable_uni(uni_port, True)
187
188 # Provision the initial bridge configuration
189 yield self.perform_uni_initial_bridge_setup(uni_port)
190
191 # And re-enable the UNIs if needed
192 yield self.enable_uni(uni_port, False)
193
194 self.deferred.callback('initial-download-success')
195
196 except TimeoutError as e:
197 self.log.error('initial-download-failure', e=e)
198 self.deferred.errback(failure.Failure(e))
199
200 except Exception as e:
201 self.log.exception('initial-download-failure', e=e)
202 self.deferred.errback(failure.Failure(e))
203
204 else:
205 e = MibResourcesFailure('Required resources are not available',
206 len(self._handler.uni_ports))
207 self.deferred.errback(failure.Failure(e))
208 except BaseException as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400209 self.log.debug('cannot-start-mib-download', exception=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500210
211 @inlineCallbacks
212 def perform_initial_bridge_setup(self):
213 self.log.debug('function-entry')
214
215 omci_cc = self._onu_device.omci_cc
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500216 try:
217 ########################################################################################
218 # Create GalEthernetProfile - Once per ONU/PON interface
219 #
220 # EntityID will be referenced by:
221 # - GemInterworkingTp
222 # References:
223 # - Nothing
224
225 msg = GalEthernetProfileFrame(
226 self._gal_enet_profile_entity_id,
227 max_gem_payload_size=self._max_gem_payload
228 )
229 frame = msg.create()
230 self.log.debug('openomci-msg', omci_msg=msg)
231 results = yield omci_cc.send(frame)
232 self.check_status_and_state(results, 'create-gal-ethernet-profile')
233
234 except TimeoutError as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400235 self.log.warn('rx-timeout-initial-gal-profile', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500236 raise
237
238 except Exception as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400239 self.log.exception('omci-setup-initial-gal-profile', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500240 raise
241
242 returnValue(None)
243
244 @inlineCallbacks
245 def perform_uni_initial_bridge_setup(self, uni_port):
246 self.log.debug('function-entry')
247 omci_cc = self._onu_device.omci_cc
248 frame = None
249 try:
250 ################################################################################
251 # Common - PON and/or UNI #
252 ################################################################################
253 # MAC Bridge Service Profile
254 #
255 # EntityID will be referenced by:
256 # - MAC Bridge Port Configuration Data (PON & UNI)
257 # References:
258 # - Nothing
259
260 # TODO: magic. event if static, assign to a meaningful variable name
261 attributes = {
262 'spanning_tree_ind': False,
263 'learning_ind': True,
264 'priority': 0x8000,
265 'max_age': 20 * 256,
266 'hello_time': 2 * 256,
267 'forward_delay': 15 * 256,
268 'unknown_mac_address_discard': True
269 }
270 msg = MacBridgeServiceProfileFrame(
271 self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num,
272 attributes
273 )
274 frame = msg.create()
275 self.log.debug('openomci-msg', omci_msg=msg)
276 results = yield omci_cc.send(frame)
277 self.check_status_and_state(results, 'create-mac-bridge-service-profile')
278
279 ################################################################################
280 # PON Specific #
281 ################################################################################
282 # IEEE 802.1 Mapper Service config - Once per PON
283 #
284 # EntityID will be referenced by:
285 # - MAC Bridge Port Configuration Data for the PON port
286 # References:
287 # - Nothing at this point. When a GEM port is created, this entity will
288 # be updated to reference the GEM Interworking TP
289
290 msg = Ieee8021pMapperServiceProfileFrame(self._ieee_mapper_service_profile_entity_id + uni_port.mac_bridge_port_num)
291 frame = msg.create()
292 self.log.debug('openomci-msg', omci_msg=msg)
293 results = yield omci_cc.send(frame)
294 self.check_status_and_state(results, 'create-8021p-mapper-service-profile')
295
296 ################################################################################
297 # Create MAC Bridge Port Configuration Data for the PON port via IEEE 802.1
298 # mapper service. Upon receipt by the ONU, the ONU will create an instance
299 # of the following before returning the response.
300 #
301 # - MAC bridge port designation data
302 # - MAC bridge port filter table data
303 # - MAC bridge port bridge table data
304 #
305 # EntityID will be referenced by:
306 # - Implicitly by the VLAN tagging filter data
307 # References:
308 # - MAC Bridge Service Profile (the bridge)
309 # - IEEE 802.1p mapper service profile for PON port
310
311 # TODO: magic. make a static variable for tp_type
312 msg = MacBridgePortConfigurationDataFrame(
313 self._mac_bridge_port_ani_entity_id + uni_port.mac_bridge_port_num,
314 bridge_id_pointer=self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
315 port_num= 0xff, # Port ID - unique number within the bridge
316 tp_type=3, # TP Type (IEEE 802.1p mapper service)
317 tp_pointer=self._ieee_mapper_service_profile_entity_id + uni_port.mac_bridge_port_num # TP ID, 8021p mapper ID
318 )
319 frame = msg.create()
320 self.log.debug('openomci-msg', omci_msg=msg)
321 results = yield omci_cc.send(frame)
Matt Jeanneret810148b2019-09-29 12:44:01 -0400322 self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-8021p-mapper')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500323
324 ################################################################################
325 # UNI Specific #
326 ################################################################################
327 # MAC Bridge Port config
328 # This configuration is for Ethernet UNI
329 #
330 # EntityID will be referenced by:
331 # - Nothing
332 # References:
333 # - MAC Bridge Service Profile (the bridge)
334 # - PPTP Ethernet or VEIP UNI
335
Matt Jeanneret810148b2019-09-29 12:44:01 -0400336 # TODO: magic. make a static variable for tp_type and association_type
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500337 # default to PPTP
338 tp_type = None
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400339 if uni_port.type.value == UniType.VEIP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500340 tp_type = 11
Matt Jeanneret810148b2019-09-29 12:44:01 -0400341 association_type = 10
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400342 elif uni_port.type.value == UniType.PPTP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500343 tp_type = 1
Matt Jeanneret810148b2019-09-29 12:44:01 -0400344 association_type = 2
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500345 else:
346 tp_type = 1
Matt Jeanneret810148b2019-09-29 12:44:01 -0400347 association_type = 2
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500348
349 msg = MacBridgePortConfigurationDataFrame(
350 uni_port.entity_id, # Entity ID - This is read-only/set-by-create !!!
351 bridge_id_pointer=self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
352 port_num=uni_port.mac_bridge_port_num, # Port ID
353 tp_type=tp_type, # PPTP Ethernet or VEIP UNI
354 tp_pointer=uni_port.entity_id # Ethernet UNI ID
355 )
356 frame = msg.create()
357 self.log.debug('openomci-msg', omci_msg=msg)
358 results = yield omci_cc.send(frame)
Matt Jeanneret810148b2019-09-29 12:44:01 -0400359 self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-uni-port')
360
361 ################################################################################
362 # Create Extended VLAN Tagging Operation config (UNI-side)
363 #
364 # EntityID relates to the VLAN TCIS later used int vlan filter task. This only
365 # sets up the inital MIB entry as it relates to port config, it does not set vlan
366 # that is saved for the vlan filter task
367 #
368 # References:
369 # - PPTP Ethernet or VEIP UNI
370 #
371
372 attributes = dict(
373 association_type=association_type, # Assoc Type, PPTP/VEIP Ethernet UNI
374 associated_me_pointer=uni_port.entity_id, # Assoc ME, PPTP/VEIP Entity Id
375
376 # See VOL-1311 - Need to set table during create to avoid exception
377 # trying to read back table during post-create-read-missing-attributes
378 # But, because this is a R/W attribute. Some ONU may not accept the
379 # value during create. It is repeated again in a set below.
380 input_tpid=self._input_tpid, # input TPID
381 output_tpid=self._output_tpid, # output TPID
382 )
383
384 msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
385 self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
386 attributes=attributes
387 )
388
389 frame = msg.create()
390 self.log.debug('openomci-msg', omci_msg=msg)
391 results = yield omci_cc.send(frame)
392 self.check_status_and_state(results, 'create-extended-vlan-tagging-operation-configuration-data')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500393
394 except TimeoutError as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400395 self.log.warn('rx-timeout-inital-per-uni-setup', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500396 raise
397
398 except Exception as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400399 self.log.exception('omci-setup-initial-per-uni-setup', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500400 raise
401
402 returnValue(None)
403
404 @inlineCallbacks
405 def enable_uni(self, uni_port, force_lock):
406 """
407 Lock or unlock a single uni port
408
409 :param uni_port: UniPort to admin up/down
410 :param force_lock: (boolean) If True, force lock regardless of enabled state
411 """
412 self.log.debug('function-entry')
413
414 omci_cc = self._onu_device.omci_cc
415 frame = None
416
417 ################################################################################
418 # Lock/Unlock UNI - 0 to Unlock, 1 to lock
419 #
420 # EntityID is referenced by:
421 # - MAC bridge port configuration data for the UNI side
422 # References:
423 # - Nothing
424 try:
425 state = 1 if force_lock or not uni_port.enabled else 0
426 msg = None
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400427 if uni_port.type.value == UniType.PPTP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500428 msg = PptpEthernetUniFrame(uni_port.entity_id,
429 attributes=dict(administrative_state=state))
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400430 elif uni_port.type.value == UniType.VEIP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500431 msg = VeipUniFrame(uni_port.entity_id,
432 attributes=dict(administrative_state=state))
433 else:
434 self.log.warn('unknown-uni-type', uni_port=uni_port)
435
436 if msg:
437 frame = msg.set()
438 self.log.debug('openomci-msg', omci_msg=msg)
439 results = yield omci_cc.send(frame)
440 self.check_status_and_state(results, 'set-pptp-ethernet-uni-lock-restore')
441
442 except TimeoutError as e:
443 self.log.warn('rx-timeout', e=e)
444 raise
445
446 except Exception as e:
447 self.log.exception('omci-failure', e=e)
448 raise
449
450 returnValue(None)