blob: 1e81c679e067b03a2cb3c959b81602c8afe53460 [file] [log] [blame]
William Kurkian6f436d02019-02-06 16:25:01 -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#
16
17"""
18Openolt adapter.
19"""
William Kurkian6f436d02019-02-06 16:25:01 -050020import structlog
Matt Jeanneret7906d232019-02-14 14:57:38 -050021
22from zope.interface import implementer
William Kurkian6f436d02019-02-06 16:25:01 -050023from twisted.internet import reactor
Matt Jeanneret7906d232019-02-14 14:57:38 -050024from pyvoltha.adapters.iadapter import IAdapterInterface
William Kurkian44cd7bb2019-02-11 16:39:12 -050025from pyvoltha.common.utils.registry import registry
William Kurkian8b1690c2019-03-04 16:53:22 -050026from voltha_protos.common_pb2 import LogLevel
27from voltha_protos.common_pb2 import OperationResp
Matt Jeannerete33a7092019-03-12 21:54:14 -040028from voltha_protos.device_pb2 import DeviceType, DeviceTypes
William Kurkian8b1690c2019-03-04 16:53:22 -050029from voltha_protos.adapter_pb2 import Adapter
30from voltha_protos.adapter_pb2 import AdapterConfig
William Kurkian33508752019-02-12 14:56:06 -050031from openolt_flow_mgr import OpenOltFlowMgr
32from openolt_alarms import OpenOltAlarmMgr
33from openolt_statistics import OpenOltStatisticsMgr
34from openolt_bw import OpenOltBW
35from openolt_platform import OpenOltPlatform
36from openolt_resource_manager import OpenOltResourceMgr
37from openolt_device import OpenoltDevice
Matt Jeanneret9fd36df2019-02-14 19:14:36 -050038
William Kurkian6f436d02019-02-06 16:25:01 -050039log = structlog.get_logger()
William Kurkianfefd4642019-02-07 15:30:03 -050040OpenOltDefaults = {
41 'support_classes': {
42 'platform': OpenOltPlatform,
43 'resource_mgr': OpenOltResourceMgr,
44 'flow_mgr': OpenOltFlowMgr,
45 'alarm_mgr': OpenOltAlarmMgr,
46 'stats_mgr': OpenOltStatisticsMgr,
47 'bw_mgr': OpenOltBW
48 }
49}
William Kurkian6f436d02019-02-06 16:25:01 -050050
William Kurkian6f436d02019-02-06 16:25:01 -050051
Matt Jeanneret7906d232019-02-14 14:57:38 -050052@implementer(IAdapterInterface)
53class OpenoltAdapter(object):
William Kurkian6f436d02019-02-06 16:25:01 -050054 name = 'openolt'
55
56 supported_device_types = [
57 DeviceType(
58 id=name,
59 adapter=name,
Matt Jeanneret9dbce8c2019-03-23 14:35:00 -040060 accepts_bulk_flow_update=False,
William Kurkian6f436d02019-02-06 16:25:01 -050061 accepts_add_remove_flow_updates=True
62 )
63 ]
64
65 # System Init Methods #
66 def __init__(self, core_proxy, adapter_proxy, config):
Matt Jeanneretbad3d982019-03-11 16:06:10 -040067 self.core_proxy = core_proxy
William Kurkian6f436d02019-02-06 16:25:01 -050068 self.adapter_proxy = adapter_proxy
William Kurkian6f436d02019-02-06 16:25:01 -050069 self.config = config
70 self.descriptor = Adapter(
71 id=self.name,
72 vendor='OLT white box vendor',
73 version='0.1',
Matt Jeanneret7906d232019-02-14 14:57:38 -050074 config=AdapterConfig(log_level=LogLevel.INFO)
William Kurkian6f436d02019-02-06 16:25:01 -050075 )
Matt Jeanneretbad3d982019-03-11 16:06:10 -040076 log.debug('openolt.__init__', core_proxy=core_proxy, adapter_proxy=adapter_proxy)
William Kurkian6f436d02019-02-06 16:25:01 -050077 self.devices = dict() # device_id -> OpenoltDevice()
78 self.interface = registry('main').get_args().interface
79 self.logical_device_id_to_root_device_id = dict()
80 self.num_devices = 0
81
82 def start(self):
83 log.info('started', interface=self.interface)
84
85 def stop(self):
86 log.info('stopped', interface=self.interface)
87
Arun Arora75e6bb22019-03-07 13:57:31 +000088 def get_ofp_device_info(self, device):
Matt Jeannerete33a7092019-03-12 21:54:14 -040089 ofp_device_info = self.devices[device.id].get_ofp_device_info(device)
90 log.debug('get_ofp_device_info', ofp_device_info=ofp_device_info)
91 return ofp_device_info
Arun Arora75e6bb22019-03-07 13:57:31 +000092
93 def get_ofp_port_info(self, device, port_no):
Matt Jeannerete33a7092019-03-12 21:54:14 -040094 ofp_port_info = self.devices[device.id].get_ofp_port_info(device, port_no)
95 log.debug('get_ofp_port_info', device_id=device.id, ofp_port_no=ofp_port_info)
96 return ofp_port_info
Arun Arora75e6bb22019-03-07 13:57:31 +000097
William Kurkian6f436d02019-02-06 16:25:01 -050098 def adapter_descriptor(self):
99 log.debug('get descriptor', interface=self.interface)
100 return self.descriptor
101
102 def device_types(self):
103 log.debug('get device_types', interface=self.interface,
104 items=self.supported_device_types)
105 return DeviceTypes(items=self.supported_device_types)
106
107 def health(self):
108 log.debug('get health', interface=self.interface)
109 raise NotImplementedError()
110
William Kurkian6f436d02019-02-06 16:25:01 -0500111 def change_master_state(self, master):
112 log.debug('change_master_state', interface=self.interface,
113 master=master)
114 raise NotImplementedError()
115
Matt Jeanneret7906d232019-02-14 14:57:38 -0500116 def adopt_device(self, device):
117 log.info('adopt-device', device=device)
118
119 kwargs = {
120 'support_classes': OpenOltDefaults['support_classes'],
Matt Jeanneretbad3d982019-03-11 16:06:10 -0400121 'core_proxy': self.core_proxy,
Matt Jeanneret7906d232019-02-14 14:57:38 -0500122 'adapter_proxy': self.adapter_proxy,
Matt Jeanneret7906d232019-02-14 14:57:38 -0500123 'device': device,
124 'device_num': self.num_devices + 1
125 }
126 try:
127 self.devices[device.id] = OpenoltDevice(**kwargs)
128 except Exception as e:
129 log.error('Failed to adopt OpenOLT device', error=e)
130 # TODO set status to ERROR so that is clear something went wrong
131 del self.devices[device.id]
132 raise
133 else:
134 self.num_devices += 1
135
136 def reconcile_device(self, device):
137 log.info('reconcile-device', device=device)
138 kwargs = {
139 'support_classes': OpenOltDefaults['support_classes'],
Matt Jeanneretbad3d982019-03-11 16:06:10 -0400140 'core_proxy': self.core_proxy,
141 'adapter_proxy': self.adapter_proxy,
Matt Jeanneret7906d232019-02-14 14:57:38 -0500142 'device': device,
143 'device_num': self.num_devices + 1,
144 'reconciliation': True
145 }
146 try:
147 reconciled_device = OpenoltDevice(**kwargs)
148 log.debug('reconciled-device-recreated',
149 device_id=reconciled_device.device_id)
150 self.devices[device.id] = reconciled_device
151 except Exception as e:
152 log.error('Failed to reconcile OpenOLT device', error=e,
153 exception_type=type(e).__name__)
154 del self.devices[device.id]
155 raise
156 else:
157 self.num_devices += 1
158 # Invoke the children reconciliation which would setup the
159 # basic children data structures
160 self.adapter_agent.reconcile_child_devices(device.id)
161 return device
162
William Kurkian6f436d02019-02-06 16:25:01 -0500163 def abandon_device(self, device):
164 log.info('abandon-device', device=device)
165 raise NotImplementedError()
166
Matt Jeanneret7906d232019-02-14 14:57:38 -0500167 def disable_device(self, device):
168 log.info('disable-device', device=device)
169 handler = self.devices[device.id]
170 handler.disable()
William Kurkian6f436d02019-02-06 16:25:01 -0500171
Matt Jeanneret7906d232019-02-14 14:57:38 -0500172 def reenable_device(self, device):
173 log.info('reenable-device', device=device)
174 handler = self.devices[device.id]
175 handler.reenable()
William Kurkian6f436d02019-02-06 16:25:01 -0500176
Matt Jeanneret7906d232019-02-14 14:57:38 -0500177 def reboot_device(self, device):
178 log.info('reboot_device', device=device)
179 handler = self.devices[device.id]
180 handler.reboot()
William Kurkian6f436d02019-02-06 16:25:01 -0500181
William Kurkian6f436d02019-02-06 16:25:01 -0500182 def download_image(self, device, request):
183 log.info('image_download - Not implemented yet', device=device,
184 request=request)
185 raise NotImplementedError()
186
187 def get_image_download_status(self, device, request):
188 log.info('get_image_download - Not implemented yet', device=device,
189 request=request)
190 raise NotImplementedError()
191
192 def cancel_image_download(self, device, request):
193 log.info('cancel_image_download - Not implemented yet', device=device)
194 raise NotImplementedError()
195
196 def activate_image_update(self, device, request):
197 log.info('activate_image_update - Not implemented yet',
198 device=device, request=request)
199 raise NotImplementedError()
200
201 def revert_image_update(self, device, request):
202 log.info('revert_image_update - Not implemented yet',
203 device=device, request=request)
204 raise NotImplementedError()
205
206 def self_test_device(self, device):
William Kurkian6f436d02019-02-06 16:25:01 -0500207 log.info('Not implemented yet')
208 raise NotImplementedError()
209
Matt Jeanneret7906d232019-02-14 14:57:38 -0500210 def delete_device(self, device):
211 log.info('delete-device', device=device)
212 handler = self.devices[device.id]
213 handler.delete()
214 del self.devices[device.id]
William Kurkian29ecfdf2019-04-03 18:01:46 -0400215 if device.parent_id in self.logical_device_id_to_root_device_id.keys():
216 del self.logical_device_id_to_root_device_id[device.parent_id]
Matt Jeanneret7906d232019-02-14 14:57:38 -0500217 return device
William Kurkian6f436d02019-02-06 16:25:01 -0500218
Matt Jeanneret7906d232019-02-14 14:57:38 -0500219 def get_device_details(self, device):
220 log.debug('get_device_details', device=device)
221 raise NotImplementedError()
222
223 def update_flows_bulk(self, device, flows, groups):
224 log.info('bulk-flow-update', device_id=device.id,
Matt Jeanneret9fd36df2019-02-14 19:14:36 -0500225 number_of_flows=len(flows.items),
226 number_of_groups=len(groups.items))
Matt Jeanneret7906d232019-02-14 14:57:38 -0500227 log.debug('flows and grousp details', flows=flows, groups=groups)
228 assert len(groups.items) == 0, "Cannot yet deal with groups"
229 handler = self.devices[device.id]
Matt Jeanneret9dbce8c2019-03-23 14:35:00 -0400230 handler.update_flow_table(flows.items)
231
232 return device
Matt Jeanneret7906d232019-02-14 14:57:38 -0500233
234 def update_flows_incrementally(self, device, flow_changes, group_changes):
235 log.debug('update_flows_incrementally', device=device,
236 flow_changes=flow_changes, group_changes=group_changes)
Matt Jeanneret9dbce8c2019-03-23 14:35:00 -0400237 handler = self.devices[device.id]
238 handler.update_flow_table(flow_changes)
239
240 return device
Matt Jeanneret7906d232019-02-14 14:57:38 -0500241
242 def update_logical_flows(self, device_id, flows_to_add, flows_to_remove,
243 groups, device_rules_map):
244
245 log.info('logical-flows-update', flows_to_add=len(flows_to_add),
246 flows_to_remove=len(flows_to_remove))
247 log.debug('logical-flows-details', flows_to_add=flows_to_add,
248 flows_to_remove=flows_to_remove)
249 assert len(groups) == 0, "Cannot yet deal with groups"
250 handler = self.devices[device_id]
251 handler.update_logical_flows(flows_to_add, flows_to_remove,
252 device_rules_map)
253
254 def update_pm_config(self, device, pm_configs):
255 log.info('update_pm_config - Not implemented yet', device=device,
256 pm_configs=pm_configs)
257 raise NotImplementedError()
258
259 def send_proxied_message(self, proxy_address, msg):
260 log.debug('send-proxied-message',
261 proxy_address=proxy_address,
262 proxied_msg=msg)
263 handler = self.devices[proxy_address.device_id]
264 handler.send_proxied_message(proxy_address, msg)
265
266 def receive_proxied_message(self, proxy_address, msg):
267 log.debug('receive_proxied_message - Not implemented',
268 proxy_address=proxy_address,
269 proxied_msg=msg)
270 raise NotImplementedError()
271
Matt Jeannereta591ab82019-04-13 15:54:28 -0400272 def receive_packet_out(self, device_id, port_no, packet):
273 log.debug('packet-out', device_id=device_id,
274 port_no=port_no, msg_len=len(packet.data))
Matt Jeanneret7906d232019-02-14 14:57:38 -0500275 try:
Matt Jeanneret7906d232019-02-14 14:57:38 -0500276 handler = self.devices[device_id]
Matt Jeannereta591ab82019-04-13 15:54:28 -0400277 handler.packet_out(port_no, packet.data)
Matt Jeanneret7906d232019-02-14 14:57:38 -0500278 except Exception as e:
279 log.error('packet-out:exception', e=e.message)
280
Matt Jeanneretb428b952019-03-07 05:14:17 -0500281 def process_inter_adapter_message(self, msg):
282 log.debug('process-inter-adapter-message', msg=msg)
283 # Unpack the header to know which device needs to handle this message
284 handler = None
285 if msg.header.proxy_device_id:
286 # typical request
287 handler = self.devices[msg.header.proxy_device_id]
288 elif msg.header.to_device_id and \
289 msg.header.to_device_id in self.devices_handlers:
290 # typical response
291 handler = self.devices[msg.header.to_device_id]
292 if handler:
293 reactor.callLater(0, handler.process_inter_adapter_message, msg)
294
Matt Jeanneret7906d232019-02-14 14:57:38 -0500295 def receive_inter_adapter_message(self, msg):
296 log.info('rx_inter_adapter_msg - Not implemented')
297 raise NotImplementedError()
298
299 def suppress_alarm(self, filter):
300 log.info('suppress_alarm - Not implemented yet', filter=filter)
301 raise NotImplementedError()
302
303 def unsuppress_alarm(self, filter):
304 log.info('unsuppress_alarm - Not implemented yet', filter=filter)
305 raise NotImplementedError()
306
307 # PON Mgnt APIs #
William Kurkian6f436d02019-02-06 16:25:01 -0500308 def create_interface(self, device, data):
309 log.debug('create-interface - Not implemented - We do not use this',
310 data=data)
311 raise NotImplementedError()
312
313 def update_interface(self, device, data):
314 log.debug('update-interface - Not implemented - We do not use this',
315 data=data)
316 raise NotImplementedError()
317
318 def remove_interface(self, device, data):
319 log.debug('remove-interface - Not implemented - We do not use this',
320 data=data)
321 raise NotImplementedError()
322
323 def receive_onu_detect_state(self, proxy_address, state):
324 log.debug('receive-onu-detect-state - Not implemented - We do not '
325 'use this', proxy_address=proxy_address,
326 state=state)
327 raise NotImplementedError()
328
329 def create_tcont(self, device, tcont_data, traffic_descriptor_data):
330 log.info('create-tcont - Not implemented - We do not use this',
331 tcont_data=tcont_data,
332 traffic_descriptor_data=traffic_descriptor_data)
333 raise NotImplementedError()
334
335 def update_tcont(self, device, tcont_data, traffic_descriptor_data):
336 log.info('update-tcont - Not implemented - We do not use this',
337 tcont_data=tcont_data,
338 traffic_descriptor_data=traffic_descriptor_data)
339 raise NotImplementedError()
340
341 def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
342 log.info('remove-tcont - Not implemented - We do not use this',
343 tcont_data=tcont_data,
344 traffic_descriptor_data=traffic_descriptor_data)
345 raise NotImplementedError()
346
347 def create_gemport(self, device, data):
348 log.info('create-gemport - Not implemented - We do not use this',
349 data=data)
350 raise NotImplementedError()
351
352 def update_gemport(self, device, data):
353 log.info('update-gemport - Not implemented - We do not use this',
354 data=data)
355 raise NotImplementedError()
356
357 def remove_gemport(self, device, data):
358 log.info('remove-gemport - Not implemented - We do not use this',
359 data=data)
360 raise NotImplementedError()
361
362 def create_multicast_gemport(self, device, data):
363 log.info('create-mcast-gemport - Not implemented - We do not use '
364 'this', data=data)
365 raise NotImplementedError()
366
367 def update_multicast_gemport(self, device, data):
368 log.info('update-mcast-gemport - Not implemented - We do not use '
369 'this', data=data)
370 raise NotImplementedError()
371
372 def remove_multicast_gemport(self, device, data):
373 log.info('remove-mcast-gemport - Not implemented - We do not use '
374 'this', data=data)
375 raise NotImplementedError()
376
377 def create_multicast_distribution_set(self, device, data):
378 log.info('create-mcast-distribution-set - Not implemented - We do '
379 'not use this', data=data)
380 raise NotImplementedError()
381
382 def update_multicast_distribution_set(self, device, data):
383 log.info('update-mcast-distribution-set - Not implemented - We do '
384 'not use this', data=data)
385 raise NotImplementedError()
386
387 def remove_multicast_distribution_set(self, device, data):
388 log.info('remove-mcast-distribution-set - Not implemented - We do '
389 'not use this', data=data)
390 raise NotImplementedError()
391
Matt Jeanneret7906d232019-02-14 14:57:38 -0500392 def delete_child_device(self, parent_device_id, child_device):
393 log.info('delete-child_device', parent_device_id=parent_device_id,
394 child_device=child_device)
395 handler = self.devices[parent_device_id]
396 if handler is not None:
397 handler.delete_child_device(child_device)
William Kurkian6f436d02019-02-06 16:25:01 -0500398 else:
Matt Jeanneret7906d232019-02-14 14:57:38 -0500399 log.error('Could not find matching handler',
400 looking_for_device_id=parent_device_id,
401 available_handlers=self.devices.keys())
William Kurkian6f436d02019-02-06 16:25:01 -0500402
Matt Jeanneret7906d232019-02-14 14:57:38 -0500403 # This is currently not part of the Iadapter interface
404 def collect_stats(self, device_id):
405 log.info('collect_stats', device_id=device_id)
406 handler = self.devices[device_id]
407 if handler is not None:
408 handler.trigger_statistics_collection()
409 else:
410 log.error('Could not find matching handler',
411 looking_for_device_id=device_id,
412 available_handlers=self.devices.keys())
William Kurkian6f436d02019-02-06 16:25:01 -0500413
Matt Jeanneret7906d232019-02-14 14:57:38 -0500414 def simulate_alarm(self, device, request):
415 log.info('simulate_alarm', device=device, request=request)
William Kurkian6f436d02019-02-06 16:25:01 -0500416
Matt Jeanneret7906d232019-02-14 14:57:38 -0500417 if device.id not in self.devices:
418 log.error("Device does not exist", device_id=device.id)
419 return OperationResp(code=OperationResp.OPERATION_FAILURE,
420 additional_info="Device %s does not exist"
Matt Jeanneret9fd36df2019-02-14 19:14:36 -0500421 % device.id)
William Kurkian6f436d02019-02-06 16:25:01 -0500422
Matt Jeanneret7906d232019-02-14 14:57:38 -0500423 handler = self.devices[device.id]
William Kurkian6f436d02019-02-06 16:25:01 -0500424
Matt Jeanneret7906d232019-02-14 14:57:38 -0500425 handler.simulate_alarm(request)
William Kurkian6f436d02019-02-06 16:25:01 -0500426
Matt Jeanneret7906d232019-02-14 14:57:38 -0500427 return OperationResp(code=OperationResp.OPERATION_SUCCESS)