blob: cb402028f1ce3adea66e567ad44567029c509faf [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
William Kurkian23047b92019-05-01 11:02:35 -040024from twisted.internet.defer import inlineCallbacks, returnValue
Matt Jeanneret7906d232019-02-14 14:57:38 -050025from pyvoltha.adapters.iadapter import IAdapterInterface
William Kurkian44cd7bb2019-02-11 16:39:12 -050026from pyvoltha.common.utils.registry import registry
William Kurkian8b1690c2019-03-04 16:53:22 -050027from voltha_protos.common_pb2 import LogLevel
28from voltha_protos.common_pb2 import OperationResp
Matt Jeannerete33a7092019-03-12 21:54:14 -040029from voltha_protos.device_pb2 import DeviceType, DeviceTypes
William Kurkian8b1690c2019-03-04 16:53:22 -050030from voltha_protos.adapter_pb2 import Adapter
31from voltha_protos.adapter_pb2 import AdapterConfig
William Kurkian33508752019-02-12 14:56:06 -050032from openolt_flow_mgr import OpenOltFlowMgr
33from openolt_alarms import OpenOltAlarmMgr
34from openolt_statistics import OpenOltStatisticsMgr
35from openolt_bw import OpenOltBW
36from openolt_platform import OpenOltPlatform
37from openolt_resource_manager import OpenOltResourceMgr
38from openolt_device import OpenoltDevice
Matt Jeanneret9fd36df2019-02-14 19:14:36 -050039
William Kurkian6f436d02019-02-06 16:25:01 -050040log = structlog.get_logger()
William Kurkianfefd4642019-02-07 15:30:03 -050041OpenOltDefaults = {
42 'support_classes': {
43 'platform': OpenOltPlatform,
44 'resource_mgr': OpenOltResourceMgr,
45 'flow_mgr': OpenOltFlowMgr,
46 'alarm_mgr': OpenOltAlarmMgr,
47 'stats_mgr': OpenOltStatisticsMgr,
48 'bw_mgr': OpenOltBW
49 }
50}
William Kurkian6f436d02019-02-06 16:25:01 -050051
William Kurkian6f436d02019-02-06 16:25:01 -050052
Matt Jeanneret7906d232019-02-14 14:57:38 -050053@implementer(IAdapterInterface)
54class OpenoltAdapter(object):
William Kurkian6f436d02019-02-06 16:25:01 -050055 name = 'openolt'
56
57 supported_device_types = [
58 DeviceType(
59 id=name,
60 adapter=name,
Matt Jeanneret9dbce8c2019-03-23 14:35:00 -040061 accepts_bulk_flow_update=False,
William Kurkian6f436d02019-02-06 16:25:01 -050062 accepts_add_remove_flow_updates=True
63 )
64 ]
65
66 # System Init Methods #
67 def __init__(self, core_proxy, adapter_proxy, config):
Matt Jeanneretbad3d982019-03-11 16:06:10 -040068 self.core_proxy = core_proxy
William Kurkian6f436d02019-02-06 16:25:01 -050069 self.adapter_proxy = adapter_proxy
William Kurkian6f436d02019-02-06 16:25:01 -050070 self.config = config
71 self.descriptor = Adapter(
72 id=self.name,
Matt Jeanneret8fa5c302019-08-09 11:28:58 -040073 vendor='VOLTHA OpenOLT Python',
74 version='2.0',
Matt Jeanneret7906d232019-02-14 14:57:38 -050075 config=AdapterConfig(log_level=LogLevel.INFO)
William Kurkian6f436d02019-02-06 16:25:01 -050076 )
Matt Jeanneretbad3d982019-03-11 16:06:10 -040077 log.debug('openolt.__init__', core_proxy=core_proxy, adapter_proxy=adapter_proxy)
William Kurkian6f436d02019-02-06 16:25:01 -050078 self.devices = dict() # device_id -> OpenoltDevice()
79 self.interface = registry('main').get_args().interface
80 self.logical_device_id_to_root_device_id = dict()
81 self.num_devices = 0
82
83 def start(self):
84 log.info('started', interface=self.interface)
85
86 def stop(self):
87 log.info('stopped', interface=self.interface)
88
Arun Arora75e6bb22019-03-07 13:57:31 +000089 def get_ofp_device_info(self, device):
Matt Jeannerete33a7092019-03-12 21:54:14 -040090 ofp_device_info = self.devices[device.id].get_ofp_device_info(device)
91 log.debug('get_ofp_device_info', ofp_device_info=ofp_device_info)
92 return ofp_device_info
Arun Arora75e6bb22019-03-07 13:57:31 +000093
94 def get_ofp_port_info(self, device, port_no):
Matt Jeannerete33a7092019-03-12 21:54:14 -040095 ofp_port_info = self.devices[device.id].get_ofp_port_info(device, port_no)
96 log.debug('get_ofp_port_info', device_id=device.id, ofp_port_no=ofp_port_info)
97 return ofp_port_info
Arun Arora75e6bb22019-03-07 13:57:31 +000098
William Kurkian6f436d02019-02-06 16:25:01 -050099 def adapter_descriptor(self):
100 log.debug('get descriptor', interface=self.interface)
101 return self.descriptor
102
103 def device_types(self):
104 log.debug('get device_types', interface=self.interface,
105 items=self.supported_device_types)
106 return DeviceTypes(items=self.supported_device_types)
107
108 def health(self):
109 log.debug('get health', interface=self.interface)
110 raise NotImplementedError()
111
William Kurkian6f436d02019-02-06 16:25:01 -0500112 def change_master_state(self, master):
113 log.debug('change_master_state', interface=self.interface,
114 master=master)
115 raise NotImplementedError()
116
Matt Jeanneret7906d232019-02-14 14:57:38 -0500117 def adopt_device(self, device):
118 log.info('adopt-device', device=device)
119
120 kwargs = {
121 'support_classes': OpenOltDefaults['support_classes'],
Matt Jeanneretbad3d982019-03-11 16:06:10 -0400122 'core_proxy': self.core_proxy,
Matt Jeanneret7906d232019-02-14 14:57:38 -0500123 'adapter_proxy': self.adapter_proxy,
Matt Jeanneret7906d232019-02-14 14:57:38 -0500124 'device': device,
125 'device_num': self.num_devices + 1
126 }
127 try:
128 self.devices[device.id] = OpenoltDevice(**kwargs)
129 except Exception as e:
130 log.error('Failed to adopt OpenOLT device', error=e)
131 # TODO set status to ERROR so that is clear something went wrong
132 del self.devices[device.id]
133 raise
134 else:
135 self.num_devices += 1
136
William Kurkian23047b92019-05-01 11:02:35 -0400137 # TODO This is currently not used in VOLTHA 2.0
138 # Reconcile needs to be rethought given the new architecture
139 @inlineCallbacks
Matt Jeanneret7906d232019-02-14 14:57:38 -0500140 def reconcile_device(self, device):
141 log.info('reconcile-device', device=device)
142 kwargs = {
143 'support_classes': OpenOltDefaults['support_classes'],
Matt Jeanneretbad3d982019-03-11 16:06:10 -0400144 'core_proxy': self.core_proxy,
145 'adapter_proxy': self.adapter_proxy,
Matt Jeanneret7906d232019-02-14 14:57:38 -0500146 'device': device,
147 'device_num': self.num_devices + 1,
148 'reconciliation': True
149 }
150 try:
151 reconciled_device = OpenoltDevice(**kwargs)
152 log.debug('reconciled-device-recreated',
153 device_id=reconciled_device.device_id)
154 self.devices[device.id] = reconciled_device
155 except Exception as e:
156 log.error('Failed to reconcile OpenOLT device', error=e,
157 exception_type=type(e).__name__)
158 del self.devices[device.id]
159 raise
160 else:
161 self.num_devices += 1
162 # Invoke the children reconciliation which would setup the
163 # basic children data structures
William Kurkian23047b92019-05-01 11:02:35 -0400164 yield self.core_proxy.reconcile_child_devices(device.id)
165 returnValue(device)
Matt Jeanneret7906d232019-02-14 14:57:38 -0500166
William Kurkian6f436d02019-02-06 16:25:01 -0500167 def abandon_device(self, device):
168 log.info('abandon-device', device=device)
169 raise NotImplementedError()
170
Matt Jeanneret7906d232019-02-14 14:57:38 -0500171 def disable_device(self, device):
172 log.info('disable-device', device=device)
173 handler = self.devices[device.id]
174 handler.disable()
William Kurkian6f436d02019-02-06 16:25:01 -0500175
Matt Jeanneret7906d232019-02-14 14:57:38 -0500176 def reenable_device(self, device):
177 log.info('reenable-device', device=device)
178 handler = self.devices[device.id]
179 handler.reenable()
William Kurkian6f436d02019-02-06 16:25:01 -0500180
Matt Jeanneret7906d232019-02-14 14:57:38 -0500181 def reboot_device(self, device):
182 log.info('reboot_device', device=device)
183 handler = self.devices[device.id]
184 handler.reboot()
William Kurkian6f436d02019-02-06 16:25:01 -0500185
William Kurkian6f436d02019-02-06 16:25:01 -0500186 def download_image(self, device, request):
187 log.info('image_download - Not implemented yet', device=device,
188 request=request)
189 raise NotImplementedError()
190
191 def get_image_download_status(self, device, request):
192 log.info('get_image_download - Not implemented yet', device=device,
193 request=request)
194 raise NotImplementedError()
195
196 def cancel_image_download(self, device, request):
197 log.info('cancel_image_download - Not implemented yet', device=device)
198 raise NotImplementedError()
199
200 def activate_image_update(self, device, request):
201 log.info('activate_image_update - Not implemented yet',
202 device=device, request=request)
203 raise NotImplementedError()
204
205 def revert_image_update(self, device, request):
206 log.info('revert_image_update - Not implemented yet',
207 device=device, request=request)
208 raise NotImplementedError()
209
210 def self_test_device(self, device):
William Kurkian6f436d02019-02-06 16:25:01 -0500211 log.info('Not implemented yet')
212 raise NotImplementedError()
213
Matt Jeanneret7906d232019-02-14 14:57:38 -0500214 def delete_device(self, device):
215 log.info('delete-device', device=device)
216 handler = self.devices[device.id]
217 handler.delete()
218 del self.devices[device.id]
William Kurkian29ecfdf2019-04-03 18:01:46 -0400219 if device.parent_id in self.logical_device_id_to_root_device_id.keys():
220 del self.logical_device_id_to_root_device_id[device.parent_id]
Matt Jeanneret7906d232019-02-14 14:57:38 -0500221 return device
William Kurkian6f436d02019-02-06 16:25:01 -0500222
Matt Jeanneret7906d232019-02-14 14:57:38 -0500223 def get_device_details(self, device):
224 log.debug('get_device_details', device=device)
225 raise NotImplementedError()
226
227 def update_flows_bulk(self, device, flows, groups):
228 log.info('bulk-flow-update', device_id=device.id,
Matt Jeanneret9fd36df2019-02-14 19:14:36 -0500229 number_of_flows=len(flows.items),
230 number_of_groups=len(groups.items))
Matt Jeanneret7906d232019-02-14 14:57:38 -0500231 log.debug('flows and grousp details', flows=flows, groups=groups)
232 assert len(groups.items) == 0, "Cannot yet deal with groups"
233 handler = self.devices[device.id]
Matt Jeanneret9dbce8c2019-03-23 14:35:00 -0400234 handler.update_flow_table(flows.items)
235
236 return device
Matt Jeanneret7906d232019-02-14 14:57:38 -0500237
238 def update_flows_incrementally(self, device, flow_changes, group_changes):
239 log.debug('update_flows_incrementally', device=device,
240 flow_changes=flow_changes, group_changes=group_changes)
Matt Jeanneret9dbce8c2019-03-23 14:35:00 -0400241 handler = self.devices[device.id]
242 handler.update_flow_table(flow_changes)
243
244 return device
Matt Jeanneret7906d232019-02-14 14:57:38 -0500245
246 def update_logical_flows(self, device_id, flows_to_add, flows_to_remove,
247 groups, device_rules_map):
248
249 log.info('logical-flows-update', flows_to_add=len(flows_to_add),
250 flows_to_remove=len(flows_to_remove))
251 log.debug('logical-flows-details', flows_to_add=flows_to_add,
252 flows_to_remove=flows_to_remove)
253 assert len(groups) == 0, "Cannot yet deal with groups"
254 handler = self.devices[device_id]
255 handler.update_logical_flows(flows_to_add, flows_to_remove,
256 device_rules_map)
257
258 def update_pm_config(self, device, pm_configs):
259 log.info('update_pm_config - Not implemented yet', device=device,
260 pm_configs=pm_configs)
261 raise NotImplementedError()
262
263 def send_proxied_message(self, proxy_address, msg):
264 log.debug('send-proxied-message',
265 proxy_address=proxy_address,
266 proxied_msg=msg)
267 handler = self.devices[proxy_address.device_id]
268 handler.send_proxied_message(proxy_address, msg)
269
270 def receive_proxied_message(self, proxy_address, msg):
271 log.debug('receive_proxied_message - Not implemented',
272 proxy_address=proxy_address,
273 proxied_msg=msg)
274 raise NotImplementedError()
275
Matt Jeannereta591ab82019-04-13 15:54:28 -0400276 def receive_packet_out(self, device_id, port_no, packet):
277 log.debug('packet-out', device_id=device_id,
278 port_no=port_no, msg_len=len(packet.data))
Matt Jeanneret7906d232019-02-14 14:57:38 -0500279 try:
Matt Jeanneret7906d232019-02-14 14:57:38 -0500280 handler = self.devices[device_id]
Matt Jeannereta591ab82019-04-13 15:54:28 -0400281 handler.packet_out(port_no, packet.data)
Matt Jeanneret7906d232019-02-14 14:57:38 -0500282 except Exception as e:
283 log.error('packet-out:exception', e=e.message)
284
Matt Jeanneretb428b952019-03-07 05:14:17 -0500285 def process_inter_adapter_message(self, msg):
286 log.debug('process-inter-adapter-message', msg=msg)
287 # Unpack the header to know which device needs to handle this message
288 handler = None
289 if msg.header.proxy_device_id:
290 # typical request
291 handler = self.devices[msg.header.proxy_device_id]
292 elif msg.header.to_device_id and \
293 msg.header.to_device_id in self.devices_handlers:
294 # typical response
295 handler = self.devices[msg.header.to_device_id]
296 if handler:
297 reactor.callLater(0, handler.process_inter_adapter_message, msg)
298
Matt Jeanneret7906d232019-02-14 14:57:38 -0500299 def receive_inter_adapter_message(self, msg):
300 log.info('rx_inter_adapter_msg - Not implemented')
301 raise NotImplementedError()
302
303 def suppress_alarm(self, filter):
304 log.info('suppress_alarm - Not implemented yet', filter=filter)
305 raise NotImplementedError()
306
307 def unsuppress_alarm(self, filter):
308 log.info('unsuppress_alarm - Not implemented yet', filter=filter)
309 raise NotImplementedError()
310
311 # PON Mgnt APIs #
William Kurkian6f436d02019-02-06 16:25:01 -0500312 def create_interface(self, device, data):
313 log.debug('create-interface - Not implemented - We do not use this',
314 data=data)
315 raise NotImplementedError()
316
317 def update_interface(self, device, data):
318 log.debug('update-interface - Not implemented - We do not use this',
319 data=data)
320 raise NotImplementedError()
321
322 def remove_interface(self, device, data):
323 log.debug('remove-interface - Not implemented - We do not use this',
324 data=data)
325 raise NotImplementedError()
326
327 def receive_onu_detect_state(self, proxy_address, state):
328 log.debug('receive-onu-detect-state - Not implemented - We do not '
329 'use this', proxy_address=proxy_address,
330 state=state)
331 raise NotImplementedError()
332
333 def create_tcont(self, device, tcont_data, traffic_descriptor_data):
334 log.info('create-tcont - Not implemented - We do not use this',
335 tcont_data=tcont_data,
336 traffic_descriptor_data=traffic_descriptor_data)
337 raise NotImplementedError()
338
339 def update_tcont(self, device, tcont_data, traffic_descriptor_data):
340 log.info('update-tcont - Not implemented - We do not use this',
341 tcont_data=tcont_data,
342 traffic_descriptor_data=traffic_descriptor_data)
343 raise NotImplementedError()
344
345 def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
346 log.info('remove-tcont - Not implemented - We do not use this',
347 tcont_data=tcont_data,
348 traffic_descriptor_data=traffic_descriptor_data)
349 raise NotImplementedError()
350
351 def create_gemport(self, device, data):
352 log.info('create-gemport - Not implemented - We do not use this',
353 data=data)
354 raise NotImplementedError()
355
356 def update_gemport(self, device, data):
357 log.info('update-gemport - Not implemented - We do not use this',
358 data=data)
359 raise NotImplementedError()
360
361 def remove_gemport(self, device, data):
362 log.info('remove-gemport - Not implemented - We do not use this',
363 data=data)
364 raise NotImplementedError()
365
366 def create_multicast_gemport(self, device, data):
367 log.info('create-mcast-gemport - Not implemented - We do not use '
368 'this', data=data)
369 raise NotImplementedError()
370
371 def update_multicast_gemport(self, device, data):
372 log.info('update-mcast-gemport - Not implemented - We do not use '
373 'this', data=data)
374 raise NotImplementedError()
375
376 def remove_multicast_gemport(self, device, data):
377 log.info('remove-mcast-gemport - Not implemented - We do not use '
378 'this', data=data)
379 raise NotImplementedError()
380
381 def create_multicast_distribution_set(self, device, data):
382 log.info('create-mcast-distribution-set - Not implemented - We do '
383 'not use this', data=data)
384 raise NotImplementedError()
385
386 def update_multicast_distribution_set(self, device, data):
387 log.info('update-mcast-distribution-set - Not implemented - We do '
388 'not use this', data=data)
389 raise NotImplementedError()
390
391 def remove_multicast_distribution_set(self, device, data):
392 log.info('remove-mcast-distribution-set - Not implemented - We do '
393 'not use this', data=data)
394 raise NotImplementedError()
395
Matt Jeanneret7906d232019-02-14 14:57:38 -0500396 def delete_child_device(self, parent_device_id, child_device):
397 log.info('delete-child_device', parent_device_id=parent_device_id,
398 child_device=child_device)
399 handler = self.devices[parent_device_id]
400 if handler is not None:
401 handler.delete_child_device(child_device)
William Kurkian6f436d02019-02-06 16:25:01 -0500402 else:
Matt Jeanneret7906d232019-02-14 14:57:38 -0500403 log.error('Could not find matching handler',
404 looking_for_device_id=parent_device_id,
405 available_handlers=self.devices.keys())
William Kurkian6f436d02019-02-06 16:25:01 -0500406
Matt Jeanneret7906d232019-02-14 14:57:38 -0500407 # This is currently not part of the Iadapter interface
408 def collect_stats(self, device_id):
409 log.info('collect_stats', device_id=device_id)
410 handler = self.devices[device_id]
411 if handler is not None:
412 handler.trigger_statistics_collection()
413 else:
414 log.error('Could not find matching handler',
415 looking_for_device_id=device_id,
416 available_handlers=self.devices.keys())
William Kurkian6f436d02019-02-06 16:25:01 -0500417
Matt Jeanneret7906d232019-02-14 14:57:38 -0500418 def simulate_alarm(self, device, request):
419 log.info('simulate_alarm', device=device, request=request)
William Kurkian6f436d02019-02-06 16:25:01 -0500420
Matt Jeanneret7906d232019-02-14 14:57:38 -0500421 if device.id not in self.devices:
422 log.error("Device does not exist", device_id=device.id)
423 return OperationResp(code=OperationResp.OPERATION_FAILURE,
424 additional_info="Device %s does not exist"
Matt Jeanneret9fd36df2019-02-14 19:14:36 -0500425 % device.id)
William Kurkian6f436d02019-02-06 16:25:01 -0500426
Matt Jeanneret7906d232019-02-14 14:57:38 -0500427 handler = self.devices[device.id]
William Kurkian6f436d02019-02-06 16:25:01 -0500428
Matt Jeanneret7906d232019-02-14 14:57:38 -0500429 handler.simulate_alarm(request)
William Kurkian6f436d02019-02-06 16:25:01 -0500430
Matt Jeanneret7906d232019-02-14 14:57:38 -0500431 return OperationResp(code=OperationResp.OPERATION_SUCCESS)