blob: 2d58fe013a39398c05a795154a4d533da989e283 [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
154 self.log.debug("OMCI Result: %s", operation,
155 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
180 device = self._handler.adapter_agent.get_device(self.device_id)
181
182 if self._handler.enabled and len(self._handler.uni_ports) > 0:
183 device.reason = 'performing-initial-mib-download'
184 self._handler.adapter_agent.update_device(device)
185
186 try:
187 # Lock the UNI ports to prevent any alarms during initial configuration
188 # of the ONU
189 self.strobe_watchdog()
190
191 # Provision the initial bridge configuration
192 yield self.perform_initial_bridge_setup()
193
194 for uni_port in self._handler.uni_ports:
195 yield self.enable_uni(uni_port, True)
196
197 # Provision the initial bridge configuration
198 yield self.perform_uni_initial_bridge_setup(uni_port)
199
200 # And re-enable the UNIs if needed
201 yield self.enable_uni(uni_port, False)
202
203 self.deferred.callback('initial-download-success')
204
205 except TimeoutError as e:
206 self.log.error('initial-download-failure', e=e)
207 self.deferred.errback(failure.Failure(e))
208
209 except Exception as e:
210 self.log.exception('initial-download-failure', e=e)
211 self.deferred.errback(failure.Failure(e))
212
213 else:
214 e = MibResourcesFailure('Required resources are not available',
215 len(self._handler.uni_ports))
216 self.deferred.errback(failure.Failure(e))
217 except BaseException as e:
218 self.log.debug('@thyy_mib_check:', exception=e)
219
220 @inlineCallbacks
221 def perform_initial_bridge_setup(self):
222 self.log.debug('function-entry')
223
224 omci_cc = self._onu_device.omci_cc
225 # TODO: too many magic numbers
226
227 try:
228 ########################################################################################
229 # Create GalEthernetProfile - Once per ONU/PON interface
230 #
231 # EntityID will be referenced by:
232 # - GemInterworkingTp
233 # References:
234 # - Nothing
235
236 msg = GalEthernetProfileFrame(
237 self._gal_enet_profile_entity_id,
238 max_gem_payload_size=self._max_gem_payload
239 )
240 frame = msg.create()
241 self.log.debug('openomci-msg', omci_msg=msg)
242 results = yield omci_cc.send(frame)
243 self.check_status_and_state(results, 'create-gal-ethernet-profile')
244
245 except TimeoutError as e:
246 self.log.warn('rx-timeout-0', e=e)
247 raise
248
249 except Exception as e:
250 self.log.exception('omci-setup-0', e=e)
251 raise
252
253 returnValue(None)
254
255 @inlineCallbacks
256 def perform_uni_initial_bridge_setup(self, uni_port):
257 self.log.debug('function-entry')
258 omci_cc = self._onu_device.omci_cc
259 frame = None
260 try:
261 ################################################################################
262 # Common - PON and/or UNI #
263 ################################################################################
264 # MAC Bridge Service Profile
265 #
266 # EntityID will be referenced by:
267 # - MAC Bridge Port Configuration Data (PON & UNI)
268 # References:
269 # - Nothing
270
271 # TODO: magic. event if static, assign to a meaningful variable name
272 attributes = {
273 'spanning_tree_ind': False,
274 'learning_ind': True,
275 'priority': 0x8000,
276 'max_age': 20 * 256,
277 'hello_time': 2 * 256,
278 'forward_delay': 15 * 256,
279 'unknown_mac_address_discard': True
280 }
281 msg = MacBridgeServiceProfileFrame(
282 self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num,
283 attributes
284 )
285 frame = msg.create()
286 self.log.debug('openomci-msg', omci_msg=msg)
287 results = yield omci_cc.send(frame)
288 self.check_status_and_state(results, 'create-mac-bridge-service-profile')
289
290 ################################################################################
291 # PON Specific #
292 ################################################################################
293 # IEEE 802.1 Mapper Service config - Once per PON
294 #
295 # EntityID will be referenced by:
296 # - MAC Bridge Port Configuration Data for the PON port
297 # References:
298 # - Nothing at this point. When a GEM port is created, this entity will
299 # be updated to reference the GEM Interworking TP
300
301 msg = Ieee8021pMapperServiceProfileFrame(self._ieee_mapper_service_profile_entity_id + uni_port.mac_bridge_port_num)
302 frame = msg.create()
303 self.log.debug('openomci-msg', omci_msg=msg)
304 results = yield omci_cc.send(frame)
305 self.check_status_and_state(results, 'create-8021p-mapper-service-profile')
306
307 ################################################################################
308 # Create MAC Bridge Port Configuration Data for the PON port via IEEE 802.1
309 # mapper service. Upon receipt by the ONU, the ONU will create an instance
310 # of the following before returning the response.
311 #
312 # - MAC bridge port designation data
313 # - MAC bridge port filter table data
314 # - MAC bridge port bridge table data
315 #
316 # EntityID will be referenced by:
317 # - Implicitly by the VLAN tagging filter data
318 # References:
319 # - MAC Bridge Service Profile (the bridge)
320 # - IEEE 802.1p mapper service profile for PON port
321
322 # TODO: magic. make a static variable for tp_type
323 msg = MacBridgePortConfigurationDataFrame(
324 self._mac_bridge_port_ani_entity_id + uni_port.mac_bridge_port_num,
325 bridge_id_pointer=self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
326 port_num= 0xff, # Port ID - unique number within the bridge
327 tp_type=3, # TP Type (IEEE 802.1p mapper service)
328 tp_pointer=self._ieee_mapper_service_profile_entity_id + uni_port.mac_bridge_port_num # TP ID, 8021p mapper ID
329 )
330 frame = msg.create()
331 self.log.debug('openomci-msg', omci_msg=msg)
332 results = yield omci_cc.send(frame)
333 self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-part-1')
334
335 ################################################################################
336 # VLAN Tagging Filter config
337 #
338 # EntityID will be referenced by:
339 # - Nothing
340 # References:
341 # - MacBridgePortConfigurationData for the ANI/PON side
342 #
343 # Set anything, this request will not be used when using Extended Vlan
344
345 # TODO: magic. make a static variable for forward_op
346 msg = VlanTaggingFilterDataFrame(
347 self._mac_bridge_port_ani_entity_id + uni_port.mac_bridge_port_num, # Entity ID
348 vlan_tcis=[self._vlan_tcis_1], # VLAN IDs
349 forward_operation=0x10
350 )
351 frame = msg.create()
352 self.log.debug('openomci-msg', omci_msg=msg)
353 results = yield omci_cc.send(frame)
354 self.check_status_and_state(results, 'create-vlan-tagging-filter-data')
355
356 ################################################################################
357 # UNI Specific #
358 ################################################################################
359 # MAC Bridge Port config
360 # This configuration is for Ethernet UNI
361 #
362 # EntityID will be referenced by:
363 # - Nothing
364 # References:
365 # - MAC Bridge Service Profile (the bridge)
366 # - PPTP Ethernet or VEIP UNI
367
368 # TODO: do this for all uni/ports...
369 # TODO: magic. make a static variable for tp_type
370
371 # default to PPTP
372 tp_type = None
373 if uni_port.type is UniType.VEIP:
374 tp_type = 11
375 elif uni_port.type is UniType.PPTP:
376 tp_type = 1
377 else:
378 tp_type = 1
379
380 msg = MacBridgePortConfigurationDataFrame(
381 uni_port.entity_id, # Entity ID - This is read-only/set-by-create !!!
382 bridge_id_pointer=self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
383 port_num=uni_port.mac_bridge_port_num, # Port ID
384 tp_type=tp_type, # PPTP Ethernet or VEIP UNI
385 tp_pointer=uni_port.entity_id # Ethernet UNI ID
386 )
387 frame = msg.create()
388 self.log.debug('openomci-msg', omci_msg=msg)
389 results = yield omci_cc.send(frame)
390 self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-part-2')
391
392 except TimeoutError as e:
393 self.log.warn('rx-timeout-1', e=e)
394 raise
395
396 except Exception as e:
397 self.log.exception('omci-setup-1', e=e)
398 raise
399
400 returnValue(None)
401
402 @inlineCallbacks
403 def enable_uni(self, uni_port, force_lock):
404 """
405 Lock or unlock a single uni port
406
407 :param uni_port: UniPort to admin up/down
408 :param force_lock: (boolean) If True, force lock regardless of enabled state
409 """
410 self.log.debug('function-entry')
411
412 omci_cc = self._onu_device.omci_cc
413 frame = None
414
415 ################################################################################
416 # Lock/Unlock UNI - 0 to Unlock, 1 to lock
417 #
418 # EntityID is referenced by:
419 # - MAC bridge port configuration data for the UNI side
420 # References:
421 # - Nothing
422 try:
423 state = 1 if force_lock or not uni_port.enabled else 0
424 msg = None
425 if uni_port.type is UniType.PPTP:
426 msg = PptpEthernetUniFrame(uni_port.entity_id,
427 attributes=dict(administrative_state=state))
428 elif uni_port.type is UniType.VEIP:
429 msg = VeipUniFrame(uni_port.entity_id,
430 attributes=dict(administrative_state=state))
431 else:
432 self.log.warn('unknown-uni-type', uni_port=uni_port)
433
434 if msg:
435 frame = msg.set()
436 self.log.debug('openomci-msg', omci_msg=msg)
437 results = yield omci_cc.send(frame)
438 self.check_status_and_state(results, 'set-pptp-ethernet-uni-lock-restore')
439
440 except TimeoutError as e:
441 self.log.warn('rx-timeout', e=e)
442 raise
443
444 except Exception as e:
445 self.log.exception('omci-failure', e=e)
446 raise
447
448 returnValue(None)