blob: 75f71d56835e6b35213cf48373cf0f59a9b37db4 [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 ################################################################################
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500282 # UNI Specific #
283 ################################################################################
284 # MAC Bridge Port config
285 # This configuration is for Ethernet UNI
286 #
287 # EntityID will be referenced by:
288 # - Nothing
289 # References:
290 # - MAC Bridge Service Profile (the bridge)
291 # - PPTP Ethernet or VEIP UNI
292
Matt Jeanneret810148b2019-09-29 12:44:01 -0400293 # TODO: magic. make a static variable for tp_type and association_type
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500294 # default to PPTP
295 tp_type = None
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400296 if uni_port.type.value == UniType.VEIP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500297 tp_type = 11
Matt Jeanneret810148b2019-09-29 12:44:01 -0400298 association_type = 10
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400299 elif uni_port.type.value == UniType.PPTP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500300 tp_type = 1
Matt Jeanneret810148b2019-09-29 12:44:01 -0400301 association_type = 2
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500302 else:
303 tp_type = 1
Matt Jeanneret810148b2019-09-29 12:44:01 -0400304 association_type = 2
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500305
306 msg = MacBridgePortConfigurationDataFrame(
Matt Jeanneret2e5c6f12019-12-13 07:06:06 -0500307 self._mac_bridge_port_ani_entity_id + uni_port.entity_id, # Entity ID
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500308 bridge_id_pointer=self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
309 port_num=uni_port.mac_bridge_port_num, # Port ID
310 tp_type=tp_type, # PPTP Ethernet or VEIP UNI
311 tp_pointer=uni_port.entity_id # Ethernet UNI ID
312 )
313 frame = msg.create()
314 self.log.debug('openomci-msg', omci_msg=msg)
315 results = yield omci_cc.send(frame)
Matt Jeanneret810148b2019-09-29 12:44:01 -0400316 self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-uni-port')
317
318 ################################################################################
319 # Create Extended VLAN Tagging Operation config (UNI-side)
320 #
321 # EntityID relates to the VLAN TCIS later used int vlan filter task. This only
322 # sets up the inital MIB entry as it relates to port config, it does not set vlan
323 # that is saved for the vlan filter task
324 #
325 # References:
326 # - PPTP Ethernet or VEIP UNI
327 #
328
329 attributes = dict(
330 association_type=association_type, # Assoc Type, PPTP/VEIP Ethernet UNI
331 associated_me_pointer=uni_port.entity_id, # Assoc ME, PPTP/VEIP Entity Id
332
333 # See VOL-1311 - Need to set table during create to avoid exception
334 # trying to read back table during post-create-read-missing-attributes
335 # But, because this is a R/W attribute. Some ONU may not accept the
336 # value during create. It is repeated again in a set below.
337 input_tpid=self._input_tpid, # input TPID
338 output_tpid=self._output_tpid, # output TPID
339 )
340
341 msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
342 self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
343 attributes=attributes
344 )
345
346 frame = msg.create()
347 self.log.debug('openomci-msg', omci_msg=msg)
348 results = yield omci_cc.send(frame)
349 self.check_status_and_state(results, 'create-extended-vlan-tagging-operation-configuration-data')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500350
351 except TimeoutError as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400352 self.log.warn('rx-timeout-inital-per-uni-setup', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500353 raise
354
355 except Exception as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400356 self.log.exception('omci-setup-initial-per-uni-setup', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500357 raise
358
359 returnValue(None)
360
361 @inlineCallbacks
362 def enable_uni(self, uni_port, force_lock):
363 """
364 Lock or unlock a single uni port
365
366 :param uni_port: UniPort to admin up/down
367 :param force_lock: (boolean) If True, force lock regardless of enabled state
368 """
369 self.log.debug('function-entry')
370
371 omci_cc = self._onu_device.omci_cc
372 frame = None
373
374 ################################################################################
375 # Lock/Unlock UNI - 0 to Unlock, 1 to lock
376 #
377 # EntityID is referenced by:
378 # - MAC bridge port configuration data for the UNI side
379 # References:
380 # - Nothing
381 try:
382 state = 1 if force_lock or not uni_port.enabled else 0
383 msg = None
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400384 if uni_port.type.value == UniType.PPTP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500385 msg = PptpEthernetUniFrame(uni_port.entity_id,
386 attributes=dict(administrative_state=state))
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400387 elif uni_port.type.value == UniType.VEIP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500388 msg = VeipUniFrame(uni_port.entity_id,
389 attributes=dict(administrative_state=state))
390 else:
391 self.log.warn('unknown-uni-type', uni_port=uni_port)
392
393 if msg:
394 frame = msg.set()
395 self.log.debug('openomci-msg', omci_msg=msg)
396 results = yield omci_cc.send(frame)
397 self.check_status_and_state(results, 'set-pptp-ethernet-uni-lock-restore')
398
399 except TimeoutError as e:
400 self.log.warn('rx-timeout', e=e)
401 raise
402
403 except Exception as e:
404 self.log.exception('omci-failure', e=e)
405 raise
406
407 returnValue(None)