blob: f0fbf776b68d5e7014964764a82f85346efeb76b [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, failure
18from voltha.extensions.omci.omci_me import *
19from voltha.extensions.omci.tasks.task import Task
20from voltha.extensions.omci.omci_defs import *
21from voltha.adapters.adtran_onu.flow.flow_entry import FlowEntry
22from voltha.adapters.adtran_onu.omci.omci import OMCI
23
24OP = EntityOperations
25RC = ReasonCodes
26
27
28class ServiceRemovalFailure(Exception):
29 """
30 This error is raised by default when the flow-install fails
31 """
32
33
34class AdtnRemoveFlowTask(Task):
35 """
36 OpenOMCI MIB Flow Remove Task
37
38 Currently, the only service tech profiles expected by v2.0 will be for AT&T
39 residential data service and DT residential data service.
40 """
41 task_priority = Task.DEFAULT_PRIORITY + 10
42 default_tpid = 0x8100 # TODO: Locate to a better location
43
44 name = "ADTRAN MIB Install Flow Task"
45
46 def __init__(self, omci_agent, handler, flow_entry):
47 """
48 Class initialization
49
50 :param omci_agent: (OpenOMCIAgent) OMCI Adapter agent
51 :param handler: (AdtranOnuHandler) ONU Handler
52 :param flow_entry: (FlowEntry) Flow to install
53 """
54 super(AdtnRemoveFlowTask, self).__init__(AdtnRemoveFlowTask.name,
55 omci_agent,
56 handler.device_id,
57 priority=AdtnRemoveFlowTask.task_priority,
58 exclusive=False)
59 self._handler = handler
60 self._onu_device = omci_agent.get_device(handler.device_id)
61 self._local_deferred = None
62 self._flow_entry = flow_entry
63
64 # TODO: Cleanup below that is not needed
65 # self._vlan_tcis_1 = 0x900
66 # self._input_tpid = AdtnRemoveFlowTask.default_tpid
67 # self._output_tpid = AdtnRemoveFlowTask.default_tpid
68
69 is_upstream = flow_entry.flow_direction in FlowEntry.upstream_flow_types
70 uni_port = flow_entry.in_port if is_upstream else flow_entry.out_port
71 pon_port = flow_entry.out_port if is_upstream else flow_entry.in_port
72
73 self._uni = handler.uni_port(uni_port)
74 self._pon = handler.pon_port(pon_port)
75
76 self._vid = OMCI.DEFAULT_UNTAGGED_VLAN
77
78 # Entity IDs. IDs with values can probably be most anything for most ONUs,
79 # IDs set to None are discovered/set
80 #
81 # TODO: Probably need to store many of these in the appropriate object (UNI, PON,...)
82 #
83 self._ieee_mapper_service_profile_entity_id = self._pon.ieee_mapper_service_profile_entity_id
84 self._mac_bridge_port_ani_entity_id = self._pon.mac_bridge_port_ani_entity_id
85
86 # Next to are specific
87 self._mac_bridge_service_profile_entity_id = handler.mac_bridge_service_profile_entity_id
88
89 def cancel_deferred(self):
90 super(AdtnRemoveFlowTask, self).cancel_deferred()
91
92 d, self._local_deferred = self._local_deferred, None
93 try:
94 if d is not None and not d.called:
95 d.cancel()
96 except:
97 pass
98
99 def start(self):
100 """
101 Start the flow installation
102 """
103 super(AdtnRemoveFlowTask, self).start()
104 self._local_deferred = reactor.callLater(0, self.perform_flow_removal)
105
106 def stop(self):
107 """
108 Shutdown flow install task
109 """
110 self.log.debug('stopping')
111
112 self.cancel_deferred()
113 super(AdtnRemoveFlowTask, self).stop()
114
115 def check_status_and_state(self, results, operation=''):
116 """
117 Check the results of an OMCI response. An exception is thrown
118 if the task was cancelled or an error was detected.
119
120 :param results: (OmciFrame) OMCI Response frame
121 :param operation: (str) what operation was being performed
122 :return: True if successful, False if the entity existed (already created)
123 """
124 omci_msg = results.fields['omci_message'].fields
125 status = omci_msg['success_code']
126 error_mask = omci_msg.get('parameter_error_attributes_mask', 'n/a')
127 failed_mask = omci_msg.get('failed_attributes_mask', 'n/a')
128 unsupported_mask = omci_msg.get('unsupported_attributes_mask', 'n/a')
129
130 self.log.debug(operation, status=status, error_mask=error_mask,
131 failed_mask=failed_mask, unsupported_mask=unsupported_mask)
132
133 if status == RC.Success:
134 self.strobe_watchdog()
135 return True
136
137 elif status == RC.InstanceExists:
138 return False
139
140 raise ServiceRemovalFailure(
141 '{} failed with a status of {}, error_mask: {}, failed_mask: {}, unsupported_mask: {}'
142 .format(operation, status, error_mask, failed_mask, unsupported_mask))
143
144 @inlineCallbacks
145 def perform_flow_removal(self):
146 """
147 Send the commands to configure the flow
148 """
149 self.log.info('perform-flow-removal')
150
151 # TODO: This has not been fully implemented
152
153 def resources_available():
154 return (len(self._handler.uni_ports) > 0 and
155 len(self._pon.tconts) and
156 len(self._pon.gem_ports))
157
158 if self._handler.enabled and resources_available():
159 omci = self._onu_device.omci_cc
160 try:
161 # TODO: make this a member of the onu gem port or the uni port
162 set_vlan_vid = self._flow_entry.set_vlan_vid
163
164 # # Delete bridge ani side vlan filter
165 # msg = VlanTaggingFilterDataFrame(self._mac_bridge_port_ani_entity_id)
166 # frame = msg.delete()
167 #
168 # results = yield omci.send(frame)
169 # self.check_status_and_state(results, 'flow-delete-vlan-tagging-filter-data')
170 #
171 # # Re-Create bridge ani side vlan filter
172 # msg = VlanTaggingFilterDataFrame(
173 # self._mac_bridge_port_ani_entity_id, # Entity ID
174 # vlan_tcis=[self._vlan_tcis_1], # VLAN IDs
175 # forward_operation=0x10
176 # )
177 # frame = msg.create()
178 # results = yield omci.send(frame)
179 # self.check_status_and_state(results, 'flow-create-vlan-tagging-filter-data')
180
181 # Update uni side extended vlan filter
182 attributes = dict(
183 received_frame_vlan_tagging_operation_table=
184 VlanTaggingOperation(
185 filter_outer_priority=15, # This entry is not a double-tag rule
186 filter_outer_vid=4096, # Do not filter on the outer VID value
187 filter_outer_tpid_de=0, # Do not filter on the outer TPID field
188
189 filter_inner_priority=15, # This is a no-tag rule, ignore all other VLAN tag filter fields
190 filter_inner_vid=0x1000, # Do not filter on the inner VID
191 filter_inner_tpid_de=0, # Do not filter on inner TPID field
192
193 filter_ether_type=0, # Do not filter on EtherType
194 treatment_tags_to_remove=0, # Remove 0 tags
195
196 treatment_outer_priority=15, # Do not add an outer tag
197 treatment_outer_vid=0, # n/a
198 treatment_outer_tpid_de=0, # n/a
199
200 treatment_inner_priority=0, # Add an inner tag and insert this value as the priority
201 treatment_inner_vid=self._vid, # use this value as the VID in the inner VLAN tag
202 treatment_inner_tpid_de=4, # set TPID
203 )
204 )
205 msg = ExtendedVlanTaggingOperationConfigurationDataFrame(
206 self._mac_bridge_service_profile_entity_id +
207 self._uni.mac_bridge_port_num, # Bridge Entity ID
208 attributes=attributes # See above
209 )
210 frame = msg.set()
211 results = yield omci.send(frame)
212 self.check_status_and_state(results,
213 'flow-set-ext-vlan-tagging-op-config-data-untagged')
214
215 self.deferred.callback('flow-remove-success')
216
217 except Exception as e:
218 # TODO: Better context info for this exception output...
219 self.log.exception('failed-to-remove-flow', e=e)
220 self.deferred.errback(failure.Failure(e))
221
222 else:
223 # TODO: Provide better error reason, what was missing...
224 e = ServiceRemovalFailure('Required resources are not available')
225 self.deferred.errback(failure.Failure(e))