blob: 16155879d07ce03767a0fd6c12744eb498ba3b8c [file] [log] [blame]
ozgecanetsiab7f73092020-02-16 23:36:25 +03001#
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#
16
17from __future__ import absolute_import
18import structlog
19from pyvoltha.adapters.extensions.omci.omci_entities import OntG, PriorityQueueG, Tcont
20from pyvoltha.adapters.extensions.omci.omci_me import MacBridgePortConfigurationDataFrame, AccessControlRow0, \
21 MulticastOperationsProfileFrame, MulticastSubscriberConfigInfoFrame, VlanTaggingFilterDataFrame, \
22 ExtendedVlanTaggingOperationConfigurationDataFrame, VlanTaggingOperation
23from twisted.internet import reactor
24from pyvoltha.adapters.extensions.omci.omci_defs import ReasonCodes, EntityOperations
25from pyvoltha.adapters.extensions.omci.tasks.task import Task
26from twisted.internet.defer import inlineCallbacks, failure
27
28
29RC = ReasonCodes
30OP = EntityOperations
31IGMP_VERSION = 2
32RESERVED_VLAN = 4095
33
34
35class BrcmMcastTask(Task):
36 task_priority = 150
37 name = "Broadcom Multicast Task"
38
39 def __init__(self, omci_agent, handler, device_id, uni_id, tp_id, vlan_id, dynamic_acl, static_acl, multicast_gem_id ):
40
41 self.log = structlog.get_logger ( device_id=device_id )
42 super ( BrcmMcastTask , self ).__init__ ( BrcmMcastTask.name ,
43 omci_agent ,
44 device_id,
45 self.task_priority)
46 self._device = omci_agent.get_device ( device_id )
47 self._results = None
48 self._local_deferred = None
49 #mcast entities IDs
50 self._mcast_operation_profile_id = handler.pon_port.mac_bridge_port_ani_entity_id + tp_id
51 self._mcast_sub_conf_info_id = self._mcast_operation_profile_id + tp_id
52 self._mac_bridge_service_profile_entity_id = handler.mac_bridge_service_profile_entity_id
53 self._mac_bridge_configuration_data_id =self._mac_bridge_service_profile_entity_id +\
54 self._uni_port.mac_bridge_port_num
55 self._ieee_mapper_service_profile_entity_id = \
56 handler.pon_port.ieee_mapper_service_profile_entity_id
57 self._gal_enet_profile_entity_id = \
58 handler.gal_enet_profile_entity_id
59 # using for multicast operations profile and multicast subscriber config info
60 self._set_igmp_function = 0
61 self._set_immediate_leave = False
62 self._set_vlan_id = vlan_id
63 # dynamic_access_control_list , static_access_control_list and multicast_gem_id
64 self._dynamic_acl= dynamic_acl
65 self._static_acl= static_acl
66 self._mcast_gem_id= multicast_gem_id
67 self._uni_port = handler.uni_ports[uni_id]
68 assert self._uni_port.uni_id == uni_id
69 # gem_port list
70 self._gem_ports = []
71 for gem_port in list(handler.pon_port.gem_ports.values()):
72 if gem_port.uni_id is not None and gem_port.uni_id != self._uni_port.uni_id: continue
73 self._gem_ports.append(gem_port)
74
75 self._tcont_list=[]
76 for gem_port in self._gem_ports:
77 self._tcont_list.append(gem_port.tcont)
78 self.tcont_me_to_queue_map = dict()
79 self.uni_port_to_queue_map = dict()
80
81 self._set_me_type = 0
82 self._set_interworking_option = 0
83 self._store_tcont_list()
84
85 def cancel_deferred(self):
86 super ( BrcmMcastTask , self ).cancel_deferred ()
87 d , self._local_deferred = self._local_deferred , None
88 try:
89 if d is not None and not d.called:
90 d.cancel ()
91 except:
92 pass
93
94 def start(self):
95 super ( BrcmMcastTask , self ).start ()
96 self._local_deferred = reactor.callLater ( 0 , self.perform_multicast )
97
98 @inlineCallbacks
99 def perform_multicast(self):
100 self.log.debug('performing-multicast', device_id=self._device._device_id, uni_id=self._uni_port.uni_id,
101 vlan_id=self._set_vlan_id, multicast_gem_id=self._mcast_gem_id)
102
103 try:
104 # create gem port and use tcont
105 yield self._create_gem_ports()
106
107 # create multicast operation profile
108 yield self._create_mcast_operation_profile()
109
110 # set multicast operation profile
111 yield self._set_mcast_operation_profile()
112
113 # create multicast subscriber config data
114 yield self._create_mcast_subscriber_conf_info()
115
116 # create mac bridge port configuration data
117 yield self._create_mac_bridge_configuration_data()
118
119 # create vlan filtering entity
120 yield self._create_vlan_tagging_filter_data()
121
122 # set vlan filtering entity
123 yield self._set_vlan_tagging_filter_data()
124
125 self.deferred.callback ( self )
126 except Exception as e:
127 self.log.exception ( 'multicast exception' , e=e )
128 self.deferred.errback ( failure.Failure ( e ) )
129
130 @inlineCallbacks
131 def _create_gem_ports(self):
132 omci_cc = self._device.omci_cc
133 try:
134 tcont = None
135 self.log.debug("tcont-list", _tcont_list=self._tcont_list)
136 for gem_tcont in self._tcont_list:
137 if gem_tcont.entity_id is not None:
138 tcont=gem_tcont
139 for gem_port in self._gem_ports:
140 gem_port_tcont= gem_port.tcont
141 if gem_port_tcont is not None and gem_port_tcont.entity_id is not None:
142 tcont = gem_port.tcont
143 ul_prior_q_entity_id = \
144 self.tcont_me_to_queue_map[tcont.entity_id][gem_port.priority_q]
145 self.log.debug("ul_prior_q_entity_id", ul_priority=ul_prior_q_entity_id)
146
147 dl_prior_q_entity_id = \
148 self.uni_port_to_queue_map[self._uni_port.entity_id][gem_port.priority_q]
149 if ul_prior_q_entity_id is not None and dl_prior_q_entity_id is not None:
150 if gem_port.direction == 'downstream' and gem_port.gem_id == self._mcast_gem_id:
151 results = yield gem_port.add_to_hardware ( omci=omci_cc ,
152 tcont_entity_id=tcont.entity_id ,
153 ieee_mapper_service_profile_entity_id=self._ieee_mapper_service_profile_entity_id +
154 self._uni_port.mac_bridge_port_num ,
155 gal_enet_profile_entity_id=self._gal_enet_profile_entity_id ,
156 ul_prior_q_entity_id=ul_prior_q_entity_id ,
157 dl_prior_q_entity_id=dl_prior_q_entity_id)
158 self.check_status_and_state ( results , 'assign-gem-port' )
159 pass
160 except Exception as e:
161 self.log.debug("failed-create-gem-ports-method", e=e)
162
163 def _store_tcont_list(self):
164 pq_to_related_port = dict()
165 onu_g = self._device.query_mib ( OntG.class_id )
166 traffic_mgmt_opt = \
167 onu_g.get ( 'attributes' , {} ).get ( 'traffic_management_options' , 0 )
168 self.log.debug ( "traffic-mgmt-option" , traffic_mgmt_opt=traffic_mgmt_opt )
169
170 prior_q = self._device.query_mib ( PriorityQueueG.class_id )
171 for k , v in prior_q.items():
172 self.log.debug("prior-q", k=k, v=v)
173 try:
174 _ = iter(v)
175 except TypeError:
176 continue
177
178 if 'instance_id' in v:
179 related_port = v['attributes']['related_port']
180 pq_to_related_port[k] = related_port
181
182 if v['instance_id'] & 0b1000000000000000:
183 tcont_me = (related_port & 0xffff0000) >> 16
184 if tcont_me not in self.tcont_me_to_queue_map:
185 self.log.debug ( "prior-q-related-port-and-tcont-me" ,
186 related_port=related_port ,
187 tcont_me=tcont_me )
188 self.tcont_me_to_queue_map[tcont_me] = list ()
189
190 self.tcont_me_to_queue_map[tcont_me].append ( k )
191 else:
192 uni_port = (related_port & 0xffff0000) >> 16
193 if uni_port == self._uni_port.entity_id:
194 if uni_port not in self.uni_port_to_queue_map:
195 self.log.debug ( "prior-q-related-port-and-uni-port-me" ,
196 related_port=related_port ,
197 uni_port_me=uni_port )
198 self.uni_port_to_queue_map[uni_port] = list ()
199
200 self.uni_port_to_queue_map[uni_port].append ( k )
201
202
203 @inlineCallbacks
204 def _create_mac_bridge_configuration_data(self):
205 self.log.debug ( 'starting-create-mac-bridge-conf-data' )
206 attributes = dict ( bridge_id_pointer=self._mac_bridge_configuration_data_id,
207 port_num=0xf0,
208 tp_type=6,
209 tp_pointer=self._mcast_gem_id)
210 msg = MacBridgePortConfigurationDataFrame ( entity_id=self._mac_bridge_configuration_data_id, attributes=attributes )
211 yield self._send_msg ( msg , 'create' , 'create-mac-bridge-port-conf-data' )
212
213
214 @inlineCallbacks
215 def _create_mcast_operation_profile(self):
216 self.log.debug ( 'starting-create-mcast-operation-profile' )
217 attributes = dict ( igmp_version=IGMP_VERSION , igmp_function=self._set_igmp_function,
218 immediate_leave=self._set_immediate_leave, robustness=0)
219 msg = MulticastOperationsProfileFrame ( entity_id=self._mcast_operation_profile_id,
220 querier_ip_address=0,
221 query_interval=125,
222 query_max_response=100,
223 last_member_query_interval=10,
224 unauthorized_join_request_behavior=False,
225 attributes=attributes)
226 yield self._send_msg ( msg , 'create' , 'create-multicast-operation-profile')
227
228 @inlineCallbacks
229 def _set_mcast_operation_profile(self):
230 self.log.debug('starting-set-mcast-operation-profile')
231 dynamic_access_control_list_table= AccessControlRow0 (
232 set_ctrl=1 ,
233 row_part_id=0 ,
234 test=0 ,
235 row_key=0 ,
236 gem_port_id=self._mcast_gem_id,
237 vlan_id=self._set_vlan_id,
238 src_ip="0.0.0.0",
239 dst_ip_start=self._dynamic_acl[0],
240 dst_ip_end=self._dynamic_acl[1],
241 ipm_group_bw=0
242
243 )
244 msg = MulticastOperationsProfileFrame(entity_id=self._mcast_operation_profile_id,
245 dynamic_access_control_list_table=dynamic_access_control_list_table
246 )
247 yield self._send_msg(msg, 'set', 'set-multicast-operations-profile')
248
249 @inlineCallbacks
250 def _create_mcast_subscriber_conf_info(self):
251 self.log.debug ( 'creating-multicast-subscriber-config-info' )
252 attributes = dict ( me_type=self._set_me_type,
253 multicast_operations_profile_pointer=self._mcast_operation_profile_id )
254 msg = MulticastSubscriberConfigInfoFrame ( entity_id=self._uni_port.entity_id, attributes=attributes )
255 yield self._send_msg ( msg , 'create' , 'create-multicast-subscriber-config-info' )
256
257
258 @inlineCallbacks
259 def _create_vlan_tagging_filter_data(self):
260 self.log.debug('creating-vlan-tagging-filter-data')
261 forward_operation = 0x10 # VID investigation
262 # When the PUSH VLAN is RESERVED_VLAN (4095), let ONU be transparent
263 if self._set_vlan_id == RESERVED_VLAN:
264 forward_operation = 0x00 # no investigation, ONU transparent
265
266 # Create bridge ani side vlan filter
267 msg = VlanTaggingFilterDataFrame(
268 self._mac_bridge_configuration_data_id, # Entity ID
269 vlan_tcis=[self._set_vlan_id], # VLAN IDs
270 forward_operation=forward_operation
271 )
272
273 yield self._send_msg(msg, 'create', 'flow-create-vlan-tagging-filter-data')
274
275 @inlineCallbacks
276 def _set_vlan_tagging_filter_data(self):
277 self.log.debug('setting-vlan-tagging-filter-data')
278 forward_operation = 0x10 # VID investigation
279 # When the PUSH VLAN is RESERVED_VLAN (4095), let ONU be transparent
280 if self._set_vlan_id == RESERVED_VLAN:
281 forward_operation = 0x00 # no investigation, ONU transparent
282
283 # Create bridge ani side vlan filter
284 msg = VlanTaggingFilterDataFrame(
285 self._mac_bridge_configuration_data_id, # Entity ID
286 vlan_tcis=[self._set_vlan_id], # VLAN IDs
287 forward_operation=forward_operation
288 )
289
290 yield self._send_msg(msg, 'set', 'flow-set-vlan-tagging-filter-data')
291
292
293 @inlineCallbacks
294 def _send_msg(self , msg , operation , log_comment):
295 if operation == 'create':
296 frame = msg.create ()
297 elif operation == 'set':
298 frame = msg.set ()
299 else:
300 frame = msg.delete ()
301 self.log.debug ( 'openomci-msg' , omci_msg=msg )
302 self.strobe_watchdog ()
303 results = yield self._device.omci_cc.send ( frame )
304 self.check_status_and_state ( results , log_comment )
305
306 def check_status_and_state(self , results , operation=''):
307 """
308 Check the results of an OMCI response. An exception is thrown
309 if the task was cancelled or an error was detected.
310
311 :param results: (OmciFrame) OMCI Response frame
312 :param operation: (str) what operation was being performed
313 :return: True if successful, False if the entity existed (already created)
314 """
315
316 omci_msg = results.fields['omci_message'].fields
317 status = omci_msg['success_code']
318 error_mask = omci_msg.get ( 'parameter_error_attributes_mask' , 'n/a' )
319 failed_mask = omci_msg.get ( 'failed_attributes_mask' , 'n/a' )
320 unsupported_mask = omci_msg.get ( 'unsupported_attributes_mask' , 'n/a' )
321
322 self.log.debug ( "OMCI Result: %s" , operation , omci_msg=omci_msg ,
323 status=status , error_mask=error_mask ,
324 failed_mask=failed_mask , unsupported_mask=unsupported_mask )
325
326 if status == RC.Success:
327 self.strobe_watchdog ()
328 return True
329
330 elif status == RC.InstanceExists:
331 return False