blob: 36289bfa5d58c1674f846147017630d88c6972dc [file] [log] [blame]
Chip Boling8e042f62019-02-12 16:14:34 -06001#
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#
16from twisted.internet import reactor
17from twisted.internet.defer import inlineCallbacks, returnValue, TimeoutError, failure
18from voltha.extensions.omci.omci_me import *
19from voltha.extensions.omci.tasks.task import Task
20from voltha.extensions.omci.omci_defs import *
21
22OP = EntityOperations
23RC = ReasonCodes
24
25
26class MibDownloadFailure(Exception):
27 """
28 This error is raised by default when the download fails
29 """
30
31
32class MibResourcesFailure(Exception):
33 """
34 This error is raised by when one or more resources required is not available
35 """
36
37
38class AdtnMibDownloadTask(Task):
39 """
40 OpenOMCI MIB Download Example
41
42 This task takes the legacy OMCI 'script' for provisioning the Adtran ONU
43 and converts it to run as a Task on the OpenOMCI Task runner. This is
44 in order to begin to decompose service instantiation in preparation for
45 Technology Profile work.
46
47 Once technology profiles are ready, some of this task may hang around or
48 be moved into OpenOMCI if there are any very common settings/configs to do
49 for any profile that may be provided in the v2.0 release
50
51 Currently, the only service tech profiles expected by v2.0 will be for AT&T
52 residential data service and DT residential data service.
53 """
54 task_priority = Task.DEFAULT_PRIORITY + 10
55 default_tpid = 0x8100
56 default_gem_payload = 1518
57
58 name = "ADTRAN MIB Download Task"
59
60 def __init__(self, omci_agent, handler):
61 """
62 Class initialization
63
64 :param omci_agent: (OpenOMCIAgent) OMCI Adapter agent
65 :param handler: (OnuHandler) ONU Device Handler
66 """
67 super(AdtnMibDownloadTask, self).__init__(AdtnMibDownloadTask.name,
68 omci_agent,
69 handler.device_id,
70 priority=AdtnMibDownloadTask.task_priority,
71 exclusive=False)
72 self._handler = handler
73 self._onu_device = omci_agent.get_device(handler.device_id)
74 self._local_deferred = None
75
76 # Frame size
77 self._max_gem_payload = AdtnMibDownloadTask.default_gem_payload
78
79 # Port numbers
80 self._pon_port_num = 0
81 self._uni_port_num = 0 # TODO Both port numbers are the same, is this correct? See MacBridgePortConfigurationDataFrame
82
83 self._pon = handler.pon_port()
84 self._vlan_tcis_1 = self._handler.vlan_tcis_1
85
86 # Entity IDs. IDs with values can probably be most anything for most ONUs,
87 # IDs set to None are discovered/set
88 #
89 # TODO: Probably need to store many of these in the appropriate object (UNI, PON,...)
90 #
91 self._ieee_mapper_service_profile_entity_id = self._pon.ieee_mapper_service_profile_entity_id
92 self._mac_bridge_port_ani_entity_id = self._pon.mac_bridge_port_ani_entity_id
93 self._gal_enet_profile_entity_id = self._handler.gal_enet_profile_entity_id
94
95 # Next to are specific TODO: UNI lookups here or uni specific install !!!
96 self._ethernet_uni_entity_id = self._handler.uni_ports[0].entity_id
97 self._mac_bridge_service_profile_entity_id = \
98 self._handler.mac_bridge_service_profile_entity_id
99
100 def cancel_deferred(self):
101 super(AdtnMibDownloadTask, self).cancel_deferred()
102
103 d, self._local_deferred = self._local_deferred, None
104 try:
105 if d is not None and not d.called:
106 d.cancel()
107 except:
108 pass
109
110 def start(self):
111 """
112 Start the MIB Download
113 """
114 super(AdtnMibDownloadTask, self).start()
115 self._local_deferred = reactor.callLater(0, self.perform_mib_download)
116
117 def stop(self):
118 """
119 Shutdown MIB Synchronization tasks
120 """
121 self.log.debug('stopping')
122
123 self.cancel_deferred()
124 super(AdtnMibDownloadTask, self).stop()
125
126 def check_status_and_state(self, results, operation=''):
127 """
128 Check the results of an OMCI response. An exception is thrown
129 if the task was cancelled or an error was detected.
130
131 :param results: (OmciFrame) OMCI Response frame
132 :param operation: (str) what operation was being performed
133 :return: True if successful, False if the entity existed (already created)
134 """
135 omci_msg = results.fields['omci_message'].fields
136 status = omci_msg['success_code']
137 error_mask = omci_msg.get('parameter_error_attributes_mask', 'n/a')
138 failed_mask = omci_msg.get('failed_attributes_mask', 'n/a')
139 unsupported_mask = omci_msg.get('unsupported_attributes_mask', 'n/a')
140
141 self.log.debug(operation, status=status, error_mask=error_mask,
142 failed_mask=failed_mask, unsupported_mask=unsupported_mask)
143
144 if status == RC.Success:
145 self.strobe_watchdog()
146 return True
147
148 elif status == RC.InstanceExists:
149 return False
150
151 raise MibDownloadFailure('{} failed with a status of {}, error_mask: {}, failed_mask: {}, unsupported_mask: {}'
152 .format(operation, status, error_mask, failed_mask, unsupported_mask))
153
154 @inlineCallbacks
155 def perform_mib_download(self):
156 """
157 Send the commands to minimally configure the PON, Bridge, and
158 UNI ports for this device. The application of any service flows
159 and other characteristics are done once resources (gem-ports, tconts, ...)
160 have been defined.
161 """
162 self.log.info('perform-initial-download')
163
164 device = self._handler.adapter_agent.get_device(self.device_id)
165
166 def resources_available():
167 return len(self._handler.uni_ports) > 0
168
169 if self._handler.enabled and resources_available():
170 device.reason = 'Performing Initial OMCI Download'
171 self._handler.adapter_agent.update_device(device)
172
173 try:
174 # Lock the UNI ports to prevent any alarms during initial configuration
175 # of the ONU
176 for uni_port in self._handler.uni_ports:
177 self.strobe_watchdog()
178
179 yield self.enable_uni(uni_port, True)
180
181 # Provision the initial bridge configuration
182 yield self.perform_initial_bridge_setup(uni_port)
183
184 # And re-enable the UNIs if needed
185 yield self.enable_uni(uni_port, False)
186
187 # If here, we are done with the generic MIB download
188 device = self._handler.adapter_agent.get_device(self.device_id)
189
190 device.reason = 'Initial OMCI Download Complete'
191 self._handler.adapter_agent.update_device(device)
192 self.deferred.callback('MIB Download - success')
193
194 except TimeoutError as e:
195 self.deferred.errback(failure.Failure(e))
196
197 else:
198 # TODO: Provide better error reason, what was missing...
199 e = MibResourcesFailure('ONU is not enabled')
200 self.deferred.errback(failure.Failure(e))
201
202 @inlineCallbacks
203 def perform_initial_bridge_setup(self, uni_port):
204 omci_cc = self._onu_device.omci_cc
205 frame = None
206
207 try:
208 ################################################################################
209 # Common - PON and/or UNI #
210 ################################################################################
211 # MAC Bridge Service Profile
212 #
213 # EntityID will be referenced by:
214 # - MAC Bridge Port Configuration Data (PON & UNI)
215 # References:
216 # - Nothing
217 attributes = {
218 'spanning_tree_ind': False,
219 'learning_ind': True
220 }
221 frame = MacBridgeServiceProfileFrame(
222 self._mac_bridge_service_profile_entity_id,
223 attributes
224 ).create()
225 results = yield omci_cc.send(frame)
226 self.check_status_and_state(results, 'create-mac-bridge-service-profile')
227
228 ################################################################################
229 # PON Specific #
230 ################################################################################
231 # IEEE 802.1 Mapper Service config - Once per PON
232 #
233 # EntityID will be referenced by:
234 # - MAC Bridge Port Configuration Data for the PON port
235 # References:
236 # - Nothing at this point. When a GEM port is created, this entity will
237 # be updated to reference the GEM Interworking TP
238
239 frame = Ieee8021pMapperServiceProfileFrame(self._ieee_mapper_service_profile_entity_id +
240 uni_port.mac_bridge_port_num).create()
241 results = yield omci_cc.send(frame)
242 self.check_status_and_state(results, 'create-8021p-mapper-service-profile')
243
244 ################################################################################
245 # Create MAC Bridge Port Configuration Data for the PON port via IEEE 802.1
246 # mapper service. Upon receipt by the ONU, the ONU will create an instance
247 # of the following before returning the response.
248 #
249 # - MAC bridge port designation data
250 # - MAC bridge port filter table data
251 # - MAC bridge port bridge table data
252 #
253 # EntityID will be referenced by:
254 # - Implicitly by the VLAN tagging filter data
255 # References:
256 # - MAC Bridge Service Profile (the bridge)
257 # - IEEE 802.1p mapper service profile for PON port
258
259 frame = MacBridgePortConfigurationDataFrame(
260 self._mac_bridge_port_ani_entity_id, # Entity ID
261 bridge_id_pointer=self._mac_bridge_service_profile_entity_id, # Bridge Entity ID
262 # TODO: The PORT number for this port and the UNI port are the same. Correct?
263 port_num=self._pon_port_num, # Port ID
264 tp_type=3, # TP Type (IEEE 802.1p mapper service)
265 tp_pointer=self._ieee_mapper_service_profile_entity_id +
266 uni_port.mac_bridge_port_num # TP ID, 8021p mapper ID
267 ).create()
268 results = yield omci_cc.send(frame)
269 self.check_status_and_state(results, 'create-mac-bridge-port-config-data-part-1')
270
271 #############################################################
272 # VLAN Tagging Filter config
273 #
274 # EntityID will be referenced by:
275 # - Nothing
276 # References:
277 # - MacBridgePortConfigurationData for the ANI/PON side
278 #
279 # Set anything, this request will not be used when using Extended Vlan
280
281 frame = VlanTaggingFilterDataFrame(
282 self._mac_bridge_port_ani_entity_id, # Entity ID
283 vlan_tcis=[self._vlan_tcis_1], # VLAN IDs
284 forward_operation=0x00
285 ).create()
286 results = yield omci_cc.send(frame)
287 self.check_status_and_state(results, 'create-vlan-tagging-filter-data')
288
289 #############################################################
290 # Create GalEthernetProfile - Once per ONU/PON interface
291 #
292 # EntityID will be referenced by:
293 # - GemInterworkingTp
294 # References:
295 # - Nothing
296
297 frame = GalEthernetProfileFrame(
298 self._gal_enet_profile_entity_id,
299 max_gem_payload_size=self._max_gem_payload
300 ).create()
301 results = yield omci_cc.send(frame)
302 self.check_status_and_state(results, 'create-gal-ethernet-profile')
303
304 ##################################################
305 # UNI Specific #
306 ##################################################
307 # MAC Bridge Port config
308 # This configuration is for Ethernet UNI
309 #
310 # EntityID will be referenced by:
311 # - Nothing
312 # References:
313 # - MAC Bridge Service Profile (the bridge)
314 # - PPTP Ethernet UNI
315
316 frame = MacBridgePortConfigurationDataFrame(
317 0x000, # Entity ID - This is read-only/set-by-create !!!
318 bridge_id_pointer=self._mac_bridge_service_profile_entity_id, # Bridge Entity ID
319 port_num=self._uni_port_num, # Port ID
320 tp_type=1, # PPTP Ethernet UNI
321 tp_pointer=self._ethernet_uni_entity_id # TP ID, 8021p mapper Id
322 ).create()
323 results = yield omci_cc.send(frame)
324 self.check_status_and_state(results, 'create-mac-bridge-port-config-data-part-2')
325
326 except TimeoutError as _e:
327 self.log.warn('rx-timeout-download', frame=hexlify(frame))
328 raise
329
330 except Exception as e:
331 self.log.exception('omci-setup-1', e=e)
332 raise
333
334 returnValue(None)
335
336 @inlineCallbacks
337 def enable_uni(self, uni, force_lock):
338 """
339 Lock or unlock one or more UNI ports
340
341 :param unis: (list) of UNI objects
342 :param force_lock: (boolean) If True, force lock regardless of enabled state
343 """
344 omci_cc = self._onu_device.omci_cc
345
346 ##################################################################
347 # Lock/Unlock UNI - 0 to Unlock, 1 to lock
348 #
349 # EntityID is referenced by:
350 # - MAC bridge port configuration data for the UNI side
351 # References:
352 # - Nothing
353 try:
354 state = 1 if force_lock or not uni.enabled else 0
355
356 frame = PptpEthernetUniFrame(uni.entity_id,
357 attributes=dict(administrative_state=state)).set()
358
359 results = yield omci_cc.send(frame)
360 self.check_status_and_state(results, 'set-pptp-ethernet-uni-lock-restore')
361
362 except TimeoutError:
363 self.log.warn('rx-timeout-uni-enable', uni_port=uni)
364 raise
365
366 except Exception as e:
367 self.log.exception('omci-failure', e=e)
368 raise
369
370 returnValue(None)