blob: 18f7fbf6df3fa18901f8c8655b2e61f494a7b6d6 [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 Jeanneretf1e9c5d2019-02-08 07:41:29 -0500293 # default to PPTP
Matt Jeanneret31509ec2019-12-20 14:57:53 -0500294 tp_type = 1
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400295 if uni_port.type.value == UniType.VEIP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500296 tp_type = 11
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400297 elif uni_port.type.value == UniType.PPTP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500298 tp_type = 1
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500299
300 msg = MacBridgePortConfigurationDataFrame(
Matt Jeanneret2e5c6f12019-12-13 07:06:06 -0500301 self._mac_bridge_port_ani_entity_id + uni_port.entity_id, # Entity ID
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500302 bridge_id_pointer=self._mac_bridge_service_profile_entity_id + uni_port.mac_bridge_port_num, # Bridge Entity ID
303 port_num=uni_port.mac_bridge_port_num, # Port ID
304 tp_type=tp_type, # PPTP Ethernet or VEIP UNI
305 tp_pointer=uni_port.entity_id # Ethernet UNI ID
306 )
307 frame = msg.create()
308 self.log.debug('openomci-msg', omci_msg=msg)
309 results = yield omci_cc.send(frame)
Matt Jeanneret810148b2019-09-29 12:44:01 -0400310 self.check_status_and_state(results, 'create-mac-bridge-port-configuration-data-uni-port')
311
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500312 except TimeoutError as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400313 self.log.warn('rx-timeout-inital-per-uni-setup', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500314 raise
315
316 except Exception as e:
Matt Jeanneret810148b2019-09-29 12:44:01 -0400317 self.log.exception('omci-setup-initial-per-uni-setup', e=e)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500318 raise
319
320 returnValue(None)
321
322 @inlineCallbacks
323 def enable_uni(self, uni_port, force_lock):
324 """
325 Lock or unlock a single uni port
326
327 :param uni_port: UniPort to admin up/down
328 :param force_lock: (boolean) If True, force lock regardless of enabled state
329 """
330 self.log.debug('function-entry')
331
332 omci_cc = self._onu_device.omci_cc
333 frame = None
334
335 ################################################################################
336 # Lock/Unlock UNI - 0 to Unlock, 1 to lock
337 #
338 # EntityID is referenced by:
339 # - MAC bridge port configuration data for the UNI side
340 # References:
341 # - Nothing
342 try:
343 state = 1 if force_lock or not uni_port.enabled else 0
344 msg = None
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400345 if uni_port.type.value == UniType.PPTP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500346 msg = PptpEthernetUniFrame(uni_port.entity_id,
347 attributes=dict(administrative_state=state))
Matt Jeanneretaf7cd6b2019-04-05 15:37:34 -0400348 elif uni_port.type.value == UniType.VEIP.value:
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500349 msg = VeipUniFrame(uni_port.entity_id,
350 attributes=dict(administrative_state=state))
351 else:
352 self.log.warn('unknown-uni-type', uni_port=uni_port)
353
354 if msg:
355 frame = msg.set()
356 self.log.debug('openomci-msg', omci_msg=msg)
357 results = yield omci_cc.send(frame)
358 self.check_status_and_state(results, 'set-pptp-ethernet-uni-lock-restore')
359
360 except TimeoutError as e:
361 self.log.warn('rx-timeout', e=e)
362 raise
363
364 except Exception as e:
365 self.log.exception('omci-failure', e=e)
366 raise
367
368 returnValue(None)