blob: f09379b503bb781a5501d14d7b5f90da5402bcc7 [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 Jeanneret2e3cb8d2019-11-16 09:22:41 -050019from pyvoltha.adapters.extensions.omci.omci_me import PptpEthernetUniFrame, GalEthernetProfileFrame, \
20 MacBridgePortConfigurationDataFrame, MacBridgeServiceProfileFrame, Ieee8021pMapperServiceProfileFrame, \
21 VeipUniFrame, ExtendedVlanTaggingOperationConfigurationDataFrame
Matt Jeanneret72f96fc2019-02-11 10:53:05 -050022from pyvoltha.adapters.extensions.omci.tasks.task import Task
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -050023from pyvoltha.adapters.extensions.omci.omci_defs import EntityOperations, ReasonCodes
24from uni_port import UniType
25from pon_port \
Matt Jeanneret810148b2019-09-29 12:44:01 -040026 import TASK_PRIORITY, DEFAULT_TPID, DEFAULT_GEM_PAYLOAD
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050027
28OP = EntityOperations
29RC = ReasonCodes
30
31
32class MibDownloadFailure(Exception):
33 """
34 This error is raised by default when the download fails
35 """
36
37
38class MibResourcesFailure(Exception):
39 """
40 This error is raised by when one or more resources required is not available
41 """
42
43
44class BrcmMibDownloadTask(Task):
45 """
Matt Jeanneret810148b2019-09-29 12:44:01 -040046 OpenOMCI MIB Download Bridge Setup Task
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050047
48 This task takes the legacy OMCI 'script' for provisioning the Broadcom ONU
49 and converts it to run as a Task on the OpenOMCI Task runner. This is
50 in order to begin to decompose service instantiation in preparation for
51 Technology Profile work.
52
53 Once technology profiles are ready, some of this task may hang around or
54 be moved into OpenOMCI if there are any very common settings/configs to do
55 for any profile that may be provided in the v2.0 release
56
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050057 """
58
Matt Jeanneret810148b2019-09-29 12:44:01 -040059 name = "Broadcom MIB Download Bridge Setup Task"
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050060
61 def __init__(self, omci_agent, handler):
62 """
63 Class initialization
64
65 :param omci_agent: (OmciAdapterAgent) OMCI Adapter agent
66 :param device_id: (str) ONU Device ID
67 """
68
69 self.log = structlog.get_logger(device_id=handler.device_id)
70 self.log.debug('function-entry')
71
72 super(BrcmMibDownloadTask, self).__init__(BrcmMibDownloadTask.name,
73 omci_agent,
74 handler.device_id,
75 priority=TASK_PRIORITY)
76 self._handler = handler
77 self._onu_device = omci_agent.get_device(handler.device_id)
78 self._local_deferred = None
79
80 # Frame size
81 self._max_gem_payload = DEFAULT_GEM_PAYLOAD
82
83 self._pon = handler.pon_port
84
85 # Defaults
86 self._input_tpid = DEFAULT_TPID
87 self._output_tpid = DEFAULT_TPID
88
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050089 # Entity IDs. IDs with values can probably be most anything for most ONUs,
90 # IDs set to None are discovered/set
91
92 self._mac_bridge_service_profile_entity_id = \
93 self._handler.mac_bridge_service_profile_entity_id
94 self._ieee_mapper_service_profile_entity_id = \
95 self._pon.ieee_mapper_service_profile_entity_id
96 self._mac_bridge_port_ani_entity_id = \
97 self._pon.mac_bridge_port_ani_entity_id
98 self._gal_enet_profile_entity_id = \
99 self._handler.gal_enet_profile_entity_id
100
101 self._free_ul_prior_q_entity_ids = set()
102 self._free_dl_prior_q_entity_ids = set()
103
104 def cancel_deferred(self):
105 self.log.debug('function-entry')
106 super(BrcmMibDownloadTask, self).cancel_deferred()
107
108 d, self._local_deferred = self._local_deferred, None
109 try:
110 if d is not None and not d.called:
111 d.cancel()
112 except:
113 pass
114
115 def start(self):
116 """
117 Start the MIB Download
118 """
119 self.log.debug('function-entry')
120 super(BrcmMibDownloadTask, self).start()
121 self._local_deferred = reactor.callLater(0, self.perform_mib_download)
122
123 def stop(self):
124 """
125 Shutdown MIB Synchronization tasks
126 """
127 self.log.debug('function-entry')
128 self.log.debug('stopping')
129
130 self.cancel_deferred()
131 super(BrcmMibDownloadTask, self).stop()
132
133 def check_status_and_state(self, results, operation=''):
134 """
135 Check the results of an OMCI response. An exception is thrown
136 if the task was cancelled or an error was detected.
137
138 :param results: (OmciFrame) OMCI Response frame
139 :param operation: (str) what operation was being performed
140 :return: True if successful, False if the entity existed (already created)
141 """
142 self.log.debug('function-entry')
143
144 omci_msg = results.fields['omci_message'].fields
145 status = omci_msg['success_code']
146 error_mask = omci_msg.get('parameter_error_attributes_mask', 'n/a')
147 failed_mask = omci_msg.get('failed_attributes_mask', 'n/a')
148 unsupported_mask = omci_msg.get('unsupported_attributes_mask', 'n/a')
149
Matt Jeannerete8fc53e2019-04-13 15:58:33 -0400150 self.log.debug("OMCI Result", operation=operation,
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500151 omci_msg=omci_msg, status=status,
152 error_mask=error_mask, failed_mask=failed_mask,
153 unsupported_mask=unsupported_mask)
154
155 if status == RC.Success:
156 self.strobe_watchdog()
157 return True
158
159 elif status == RC.InstanceExists:
160 return False
161
162 raise MibDownloadFailure('{} failed with a status of {}, error_mask: {}, failed_mask: {}, unsupported_mask: {}'
163 .format(operation, status, error_mask, failed_mask, unsupported_mask))
164
165 @inlineCallbacks
166 def perform_mib_download(self):
167 """
168 Send the commands to minimally configure the PON, Bridge, and
169 UNI ports for this device. The application of any service flows
170 and other characteristics are done as needed.
171 """
172 try:
173 self.log.debug('function-entry')
174 self.log.info('perform-download')
175
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500176 if self._handler.enabled and len(self._handler.uni_ports) > 0:
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700177 yield self._handler.core_proxy.device_reason_update(self.device_id, 'performing-initial-mib-download')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500178
179 try:
180 # Lock the UNI ports to prevent any alarms during initial configuration
181 # of the ONU
182 self.strobe_watchdog()
183
184 # Provision the initial bridge configuration
185 yield self.perform_initial_bridge_setup()
186
187 for uni_port in self._handler.uni_ports:
188 yield self.enable_uni(uni_port, True)
189
190 # Provision the initial bridge configuration
191 yield self.perform_uni_initial_bridge_setup(uni_port)
192
193 # And re-enable the UNIs if needed
194 yield self.enable_uni(uni_port, False)
195
196 self.deferred.callback('initial-download-success')
197
198 except TimeoutError as e:
199 self.log.error('initial-download-failure', e=e)
200 self.deferred.errback(failure.Failure(e))
201
202 except Exception as e:
203 self.log.exception('initial-download-failure', e=e)
204 self.deferred.errback(failure.Failure(e))
205
206 else:
207 e = MibResourcesFailure('Required resources are not available',
208 len(self._handler.uni_ports))
209 self.deferred.errback(failure.Failure(e))
210 except BaseException as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400211 self.log.debug('cannot-start-mib-download', exception=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500212
213 @inlineCallbacks
214 def perform_initial_bridge_setup(self):
215 self.log.debug('function-entry')
216
217 omci_cc = self._onu_device.omci_cc
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500218 try:
219 ########################################################################################
220 # Create GalEthernetProfile - Once per ONU/PON interface
221 #
222 # EntityID will be referenced by:
223 # - GemInterworkingTp
224 # References:
225 # - Nothing
226
227 msg = GalEthernetProfileFrame(
228 self._gal_enet_profile_entity_id,
229 max_gem_payload_size=self._max_gem_payload
230 )
231 frame = msg.create()
232 self.log.debug('openomci-msg', omci_msg=msg)
233 results = yield omci_cc.send(frame)
234 self.check_status_and_state(results, 'create-gal-ethernet-profile')
235
236 except TimeoutError as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400237 self.log.warn('rx-timeout-initial-gal-profile', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500238 raise
239
240 except Exception as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400241 self.log.exception('omci-setup-initial-gal-profile', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500242 raise
243
244 returnValue(None)
245
246 @inlineCallbacks
247 def perform_uni_initial_bridge_setup(self, uni_port):
248 self.log.debug('function-entry')
249 omci_cc = self._onu_device.omci_cc
250 frame = None
251 try:
252 ################################################################################
253 # Common - PON and/or UNI #
254 ################################################################################
255 # MAC Bridge Service Profile
256 #
257 # EntityID will be referenced by:
258 # - MAC Bridge Port Configuration Data (PON & UNI)
259 # References:
260 # - Nothing
261
262 # TODO: magic. event if static, assign to a meaningful variable name
263 attributes = {
264 'spanning_tree_ind': False,
265 'learning_ind': True,
266 'priority': 0x8000,
267 'max_age': 20 * 256,
268 'hello_time': 2 * 256,
269 'forward_delay': 15 * 256,
270 'unknown_mac_address_discard': True
271 }
272 msg = MacBridgeServiceProfileFrame(
273 self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num,
274 attributes
275 )
276 frame = msg.create()
277 self.log.debug('openomci-msg', omci_msg=msg)
278 results = yield omci_cc.send(frame)
279 self.check_status_and_state(results, 'create-mac-bridge-service-profile')
280
281 ################################################################################
282 # PON Specific #
283 ################################################################################
284 # IEEE 802.1 Mapper Service config - Once per PON
285 #
286 # EntityID will be referenced by:
287 # - MAC Bridge Port Configuration Data for the PON port
288 # References:
289 # - Nothing at this point. When a GEM port is created, this entity will
290 # be updated to reference the GEM Interworking TP
291
292 msg = Ieee8021pMapperServiceProfileFrame(self._ieee_mapper_service_profile_entity_id + uni_port.mac_bridge_port_num)
293 frame = msg.create()
294 self.log.debug('openomci-msg', omci_msg=msg)
295 results = yield omci_cc.send(frame)
296 self.check_status_and_state(results, 'create-8021p-mapper-service-profile')
297
298 ################################################################################
299 # Create MAC Bridge Port Configuration Data for the PON port via IEEE 802.1
300 # mapper service. Upon receipt by the ONU, the ONU will create an instance
301 # of the following before returning the response.
302 #
303 # - MAC bridge port designation data
304 # - MAC bridge port filter table data
305 # - MAC bridge port bridge table data
306 #
307 # EntityID will be referenced by:
308 # - Implicitly by the VLAN tagging filter data
309 # References:
310 # - MAC Bridge Service Profile (the bridge)
311 # - IEEE 802.1p mapper service profile for PON port
312
313 # TODO: magic. make a static variable for tp_type
314 msg = MacBridgePortConfigurationDataFrame(
315 self._mac_bridge_port_ani_entity_id + uni_port.mac_bridge_port_num,
316 bridge_id_pointer=self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
317 port_num= 0xff, # Port ID - unique number within the bridge
318 tp_type=3, # TP Type (IEEE 802.1p mapper service)
319 tp_pointer=self._ieee_mapper_service_profile_entity_id + uni_port.mac_bridge_port_num # TP ID, 8021p mapper ID
320 )
321 frame = msg.create()
322 self.log.debug('openomci-msg', omci_msg=msg)
323 results = yield omci_cc.send(frame)
Matt Jeanneret810148b2019-09-29 12:44:01 -0400324 self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-8021p-mapper')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500325
326 ################################################################################
327 # UNI Specific #
328 ################################################################################
329 # MAC Bridge Port config
330 # This configuration is for Ethernet UNI
331 #
332 # EntityID will be referenced by:
333 # - Nothing
334 # References:
335 # - MAC Bridge Service Profile (the bridge)
336 # - PPTP Ethernet or VEIP UNI
337
Matt Jeanneret810148b2019-09-29 12:44:01 -0400338 # TODO: magic. make a static variable for tp_type and association_type
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500339 # default to PPTP
340 tp_type = None
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400341 if uni_port.type.value == UniType.VEIP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500342 tp_type = 11
Matt Jeanneret810148b2019-09-29 12:44:01 -0400343 association_type = 10
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400344 elif uni_port.type.value == UniType.PPTP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500345 tp_type = 1
Matt Jeanneret810148b2019-09-29 12:44:01 -0400346 association_type = 2
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500347 else:
348 tp_type = 1
Matt Jeanneret810148b2019-09-29 12:44:01 -0400349 association_type = 2
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500350
351 msg = MacBridgePortConfigurationDataFrame(
352 uni_port.entity_id, # Entity ID - This is read-only/set-by-create !!!
353 bridge_id_pointer=self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
354 port_num=uni_port.mac_bridge_port_num, # Port ID
355 tp_type=tp_type, # PPTP Ethernet or VEIP UNI
356 tp_pointer=uni_port.entity_id # Ethernet UNI ID
357 )
358 frame = msg.create()
359 self.log.debug('openomci-msg', omci_msg=msg)
360 results = yield omci_cc.send(frame)
Matt Jeanneret810148b2019-09-29 12:44:01 -0400361 self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-uni-port')
362
363 ################################################################################
364 # Create Extended VLAN Tagging Operation config (UNI-side)
365 #
366 # EntityID relates to the VLAN TCIS later used int vlan filter task. This only
367 # sets up the inital MIB entry as it relates to port config, it does not set vlan
368 # that is saved for the vlan filter task
369 #
370 # References:
371 # - PPTP Ethernet or VEIP UNI
372 #
373
374 attributes = dict(
375 association_type=association_type, # Assoc Type, PPTP/VEIP Ethernet UNI
376 associated_me_pointer=uni_port.entity_id, # Assoc ME, PPTP/VEIP Entity Id
377
378 # See VOL-1311 - Need to set table during create to avoid exception
379 # trying to read back table during post-create-read-missing-attributes
380 # But, because this is a R/W attribute. Some ONU may not accept the
381 # value during create. It is repeated again in a set below.
382 input_tpid=self._input_tpid, # input TPID
383 output_tpid=self._output_tpid, # output TPID
384 )
385
386 msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
387 self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
388 attributes=attributes
389 )
390
391 frame = msg.create()
392 self.log.debug('openomci-msg', omci_msg=msg)
393 results = yield omci_cc.send(frame)
394 self.check_status_and_state(results, 'create-extended-vlan-tagging-operation-configuration-data')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500395
396 except TimeoutError as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400397 self.log.warn('rx-timeout-inital-per-uni-setup', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500398 raise
399
400 except Exception as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400401 self.log.exception('omci-setup-initial-per-uni-setup', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500402 raise
403
404 returnValue(None)
405
406 @inlineCallbacks
407 def enable_uni(self, uni_port, force_lock):
408 """
409 Lock or unlock a single uni port
410
411 :param uni_port: UniPort to admin up/down
412 :param force_lock: (boolean) If True, force lock regardless of enabled state
413 """
414 self.log.debug('function-entry')
415
416 omci_cc = self._onu_device.omci_cc
417 frame = None
418
419 ################################################################################
420 # Lock/Unlock UNI - 0 to Unlock, 1 to lock
421 #
422 # EntityID is referenced by:
423 # - MAC bridge port configuration data for the UNI side
424 # References:
425 # - Nothing
426 try:
427 state = 1 if force_lock or not uni_port.enabled else 0
428 msg = None
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400429 if uni_port.type.value == UniType.PPTP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500430 msg = PptpEthernetUniFrame(uni_port.entity_id,
431 attributes=dict(administrative_state=state))
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400432 elif uni_port.type.value == UniType.VEIP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500433 msg = VeipUniFrame(uni_port.entity_id,
434 attributes=dict(administrative_state=state))
435 else:
436 self.log.warn('unknown-uni-type', uni_port=uni_port)
437
438 if msg:
439 frame = msg.set()
440 self.log.debug('openomci-msg', omci_msg=msg)
441 results = yield omci_cc.send(frame)
442 self.check_status_and_state(results, 'set-pptp-ethernet-uni-lock-restore')
443
444 except TimeoutError as e:
445 self.log.warn('rx-timeout', e=e)
446 raise
447
448 except Exception as e:
449 self.log.exception('omci-failure', e=e)
450 raise
451
452 returnValue(None)