blob: 973af86c0450bcabb889c27bd1d5fd75bb7c52c9 [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 Jeanneretf1e9c5d2019-02-08 07:41:29 -050024 import BRDCM_DEFAULT_VLAN, TASK_PRIORITY, DEFAULT_TPID, DEFAULT_GEM_PAYLOAD
25
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 """
44 OpenOMCI MIB Download Example
45
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
55 Currently, the only service tech profiles expected by v2.0 will be for AT&T
56 residential data service and DT residential data service.
57 """
58
59 name = "Broadcom MIB Download Example Task"
60
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
89 self._vlan_tcis_1 = BRDCM_DEFAULT_VLAN
90 self._cvid = BRDCM_DEFAULT_VLAN
91 self._vlan_config_entity_id = self._vlan_tcis_1
92
93 # Entity IDs. IDs with values can probably be most anything for most ONUs,
94 # IDs set to None are discovered/set
95
96 self._mac_bridge_service_profile_entity_id = \
97 self._handler.mac_bridge_service_profile_entity_id
98 self._ieee_mapper_service_profile_entity_id = \
99 self._pon.ieee_mapper_service_profile_entity_id
100 self._mac_bridge_port_ani_entity_id = \
101 self._pon.mac_bridge_port_ani_entity_id
102 self._gal_enet_profile_entity_id = \
103 self._handler.gal_enet_profile_entity_id
104
105 self._free_ul_prior_q_entity_ids = set()
106 self._free_dl_prior_q_entity_ids = set()
107
108 def cancel_deferred(self):
109 self.log.debug('function-entry')
110 super(BrcmMibDownloadTask, self).cancel_deferred()
111
112 d, self._local_deferred = self._local_deferred, None
113 try:
114 if d is not None and not d.called:
115 d.cancel()
116 except:
117 pass
118
119 def start(self):
120 """
121 Start the MIB Download
122 """
123 self.log.debug('function-entry')
124 super(BrcmMibDownloadTask, self).start()
125 self._local_deferred = reactor.callLater(0, self.perform_mib_download)
126
127 def stop(self):
128 """
129 Shutdown MIB Synchronization tasks
130 """
131 self.log.debug('function-entry')
132 self.log.debug('stopping')
133
134 self.cancel_deferred()
135 super(BrcmMibDownloadTask, self).stop()
136
137 def check_status_and_state(self, results, operation=''):
138 """
139 Check the results of an OMCI response. An exception is thrown
140 if the task was cancelled or an error was detected.
141
142 :param results: (OmciFrame) OMCI Response frame
143 :param operation: (str) what operation was being performed
144 :return: True if successful, False if the entity existed (already created)
145 """
146 self.log.debug('function-entry')
147
148 omci_msg = results.fields['omci_message'].fields
149 status = omci_msg['success_code']
150 error_mask = omci_msg.get('parameter_error_attributes_mask', 'n/a')
151 failed_mask = omci_msg.get('failed_attributes_mask', 'n/a')
152 unsupported_mask = omci_msg.get('unsupported_attributes_mask', 'n/a')
153
Matt Jeannerete8fc53e2019-04-13 15:58:33 -0400154 self.log.debug("OMCI Result", operation=operation,
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500155 omci_msg=omci_msg, status=status,
156 error_mask=error_mask, failed_mask=failed_mask,
157 unsupported_mask=unsupported_mask)
158
159 if status == RC.Success:
160 self.strobe_watchdog()
161 return True
162
163 elif status == RC.InstanceExists:
164 return False
165
166 raise MibDownloadFailure('{} failed with a status of {}, error_mask: {}, failed_mask: {}, unsupported_mask: {}'
167 .format(operation, status, error_mask, failed_mask, unsupported_mask))
168
169 @inlineCallbacks
170 def perform_mib_download(self):
171 """
172 Send the commands to minimally configure the PON, Bridge, and
173 UNI ports for this device. The application of any service flows
174 and other characteristics are done as needed.
175 """
176 try:
177 self.log.debug('function-entry')
178 self.log.info('perform-download')
179
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500180 if self._handler.enabled and len(self._handler.uni_ports) > 0:
Mahir Gunyel0e6882a2019-10-16 17:02:39 -0700181 yield self._handler.core_proxy.device_reason_update(self.device_id, 'performing-initial-mib-download')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500182
183 try:
184 # Lock the UNI ports to prevent any alarms during initial configuration
185 # of the ONU
186 self.strobe_watchdog()
187
188 # Provision the initial bridge configuration
189 yield self.perform_initial_bridge_setup()
190
191 for uni_port in self._handler.uni_ports:
192 yield self.enable_uni(uni_port, True)
193
194 # Provision the initial bridge configuration
195 yield self.perform_uni_initial_bridge_setup(uni_port)
196
197 # And re-enable the UNIs if needed
198 yield self.enable_uni(uni_port, False)
199
200 self.deferred.callback('initial-download-success')
201
202 except TimeoutError as e:
203 self.log.error('initial-download-failure', e=e)
204 self.deferred.errback(failure.Failure(e))
205
206 except Exception as e:
207 self.log.exception('initial-download-failure', e=e)
208 self.deferred.errback(failure.Failure(e))
209
210 else:
211 e = MibResourcesFailure('Required resources are not available',
212 len(self._handler.uni_ports))
213 self.deferred.errback(failure.Failure(e))
214 except BaseException as e:
215 self.log.debug('@thyy_mib_check:', exception=e)
216
217 @inlineCallbacks
218 def perform_initial_bridge_setup(self):
219 self.log.debug('function-entry')
220
221 omci_cc = self._onu_device.omci_cc
222 # TODO: too many magic numbers
223
224 try:
225 ########################################################################################
226 # Create GalEthernetProfile - Once per ONU/PON interface
227 #
228 # EntityID will be referenced by:
229 # - GemInterworkingTp
230 # References:
231 # - Nothing
232
233 msg = GalEthernetProfileFrame(
234 self._gal_enet_profile_entity_id,
235 max_gem_payload_size=self._max_gem_payload
236 )
237 frame = msg.create()
238 self.log.debug('openomci-msg', omci_msg=msg)
239 results = yield omci_cc.send(frame)
240 self.check_status_and_state(results, 'create-gal-ethernet-profile')
241
242 except TimeoutError as e:
243 self.log.warn('rx-timeout-0', e=e)
244 raise
245
246 except Exception as e:
247 self.log.exception('omci-setup-0', e=e)
248 raise
249
250 returnValue(None)
251
252 @inlineCallbacks
253 def perform_uni_initial_bridge_setup(self, uni_port):
254 self.log.debug('function-entry')
255 omci_cc = self._onu_device.omci_cc
256 frame = None
257 try:
258 ################################################################################
259 # Common - PON and/or UNI #
260 ################################################################################
261 # MAC Bridge Service Profile
262 #
263 # EntityID will be referenced by:
264 # - MAC Bridge Port Configuration Data (PON & UNI)
265 # References:
266 # - Nothing
267
268 # TODO: magic. event if static, assign to a meaningful variable name
269 attributes = {
270 'spanning_tree_ind': False,
271 'learning_ind': True,
272 'priority': 0x8000,
273 'max_age': 20 * 256,
274 'hello_time': 2 * 256,
275 'forward_delay': 15 * 256,
276 'unknown_mac_address_discard': True
277 }
278 msg = MacBridgeServiceProfileFrame(
279 self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num,
280 attributes
281 )
282 frame = msg.create()
283 self.log.debug('openomci-msg', omci_msg=msg)
284 results = yield omci_cc.send(frame)
285 self.check_status_and_state(results, 'create-mac-bridge-service-profile')
286
287 ################################################################################
288 # PON Specific #
289 ################################################################################
290 # IEEE 802.1 Mapper Service config - Once per PON
291 #
292 # EntityID will be referenced by:
293 # - MAC Bridge Port Configuration Data for the PON port
294 # References:
295 # - Nothing at this point. When a GEM port is created, this entity will
296 # be updated to reference the GEM Interworking TP
297
298 msg = Ieee8021pMapperServiceProfileFrame(self._ieee_mapper_service_profile_entity_id + uni_port.mac_bridge_port_num)
299 frame = msg.create()
300 self.log.debug('openomci-msg', omci_msg=msg)
301 results = yield omci_cc.send(frame)
302 self.check_status_and_state(results, 'create-8021p-mapper-service-profile')
303
304 ################################################################################
305 # Create MAC Bridge Port Configuration Data for the PON port via IEEE 802.1
306 # mapper service. Upon receipt by the ONU, the ONU will create an instance
307 # of the following before returning the response.
308 #
309 # - MAC bridge port designation data
310 # - MAC bridge port filter table data
311 # - MAC bridge port bridge table data
312 #
313 # EntityID will be referenced by:
314 # - Implicitly by the VLAN tagging filter data
315 # References:
316 # - MAC Bridge Service Profile (the bridge)
317 # - IEEE 802.1p mapper service profile for PON port
318
319 # TODO: magic. make a static variable for tp_type
320 msg = MacBridgePortConfigurationDataFrame(
321 self._mac_bridge_port_ani_entity_id + uni_port.mac_bridge_port_num,
322 bridge_id_pointer=self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
323 port_num= 0xff, # Port ID - unique number within the bridge
324 tp_type=3, # TP Type (IEEE 802.1p mapper service)
325 tp_pointer=self._ieee_mapper_service_profile_entity_id + uni_port.mac_bridge_port_num # TP ID, 8021p mapper ID
326 )
327 frame = msg.create()
328 self.log.debug('openomci-msg', omci_msg=msg)
329 results = yield omci_cc.send(frame)
330 self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-part-1')
331
332 ################################################################################
333 # VLAN Tagging Filter config
334 #
335 # EntityID will be referenced by:
336 # - Nothing
337 # References:
338 # - MacBridgePortConfigurationData for the ANI/PON side
339 #
340 # Set anything, this request will not be used when using Extended Vlan
341
342 # TODO: magic. make a static variable for forward_op
343 msg = VlanTaggingFilterDataFrame(
344 self._mac_bridge_port_ani_entity_id + uni_port.mac_bridge_port_num, # Entity ID
345 vlan_tcis=[self._vlan_tcis_1], # VLAN IDs
346 forward_operation=0x10
347 )
348 frame = msg.create()
349 self.log.debug('openomci-msg', omci_msg=msg)
350 results = yield omci_cc.send(frame)
351 self.check_status_and_state(results, 'create-vlan-tagging-filter-data')
352
353 ################################################################################
354 # UNI Specific #
355 ################################################################################
356 # MAC Bridge Port config
357 # This configuration is for Ethernet UNI
358 #
359 # EntityID will be referenced by:
360 # - Nothing
361 # References:
362 # - MAC Bridge Service Profile (the bridge)
363 # - PPTP Ethernet or VEIP UNI
364
365 # TODO: do this for all uni/ports...
366 # TODO: magic. make a static variable for tp_type
367
368 # default to PPTP
369 tp_type = None
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400370 if uni_port.type.value == UniType.VEIP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500371 tp_type = 11
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400372 elif uni_port.type.value == UniType.PPTP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500373 tp_type = 1
374 else:
375 tp_type = 1
376
377 msg = MacBridgePortConfigurationDataFrame(
378 uni_port.entity_id, # Entity ID - This is read-only/set-by-create !!!
379 bridge_id_pointer=self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
380 port_num=uni_port.mac_bridge_port_num, # Port ID
381 tp_type=tp_type, # PPTP Ethernet or VEIP UNI
382 tp_pointer=uni_port.entity_id # Ethernet UNI ID
383 )
384 frame = msg.create()
385 self.log.debug('openomci-msg', omci_msg=msg)
386 results = yield omci_cc.send(frame)
387 self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-part-2')
388
389 except TimeoutError as e:
390 self.log.warn('rx-timeout-1', e=e)
391 raise
392
393 except Exception as e:
394 self.log.exception('omci-setup-1', e=e)
395 raise
396
397 returnValue(None)
398
399 @inlineCallbacks
400 def enable_uni(self, uni_port, force_lock):
401 """
402 Lock or unlock a single uni port
403
404 :param uni_port: UniPort to admin up/down
405 :param force_lock: (boolean) If True, force lock regardless of enabled state
406 """
407 self.log.debug('function-entry')
408
409 omci_cc = self._onu_device.omci_cc
410 frame = None
411
412 ################################################################################
413 # Lock/Unlock UNI - 0 to Unlock, 1 to lock
414 #
415 # EntityID is referenced by:
416 # - MAC bridge port configuration data for the UNI side
417 # References:
418 # - Nothing
419 try:
420 state = 1 if force_lock or not uni_port.enabled else 0
421 msg = None
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400422 if uni_port.type.value == UniType.PPTP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500423 msg = PptpEthernetUniFrame(uni_port.entity_id,
424 attributes=dict(administrative_state=state))
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400425 elif uni_port.type.value == UniType.VEIP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500426 msg = VeipUniFrame(uni_port.entity_id,
427 attributes=dict(administrative_state=state))
428 else:
429 self.log.warn('unknown-uni-type', uni_port=uni_port)
430
431 if msg:
432 frame = msg.set()
433 self.log.debug('openomci-msg', omci_msg=msg)
434 results = yield omci_cc.send(frame)
435 self.check_status_and_state(results, 'set-pptp-ethernet-uni-lock-restore')
436
437 except TimeoutError as e:
438 self.log.warn('rx-timeout', e=e)
439 raise
440
441 except Exception as e:
442 self.log.exception('omci-failure', e=e)
443 raise
444
445 returnValue(None)