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