blob: 36dfaa5021abb8636898af3523f0f266833aa82b [file] [log] [blame]
Chip Boling252c7772017-08-16 10:13:17 -05001# Copyright 2017-present Open Networking Foundation
Chip Boling3e3b1a92017-05-16 11:51:18 -05002#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
Chip Boling252c7772017-08-16 10:13:17 -05007# http://www.apache.org/licenses/LICENSE-2.0
Chip Boling3e3b1a92017-05-16 11:51:18 -05008#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
Chip Boling3e3b1a92017-05-16 11:51:18 -050014
15"""
16Adtran 1-U OLT adapter.
17"""
18import structlog
19from twisted.internet import reactor
20from zope.interface import implementer
21
22from adtran_olt_handler import AdtranOltHandler
23from voltha.adapters.interface import IAdapterInterface
24from voltha.protos import third_party
25from voltha.protos.adapter_pb2 import Adapter
26from voltha.protos.adapter_pb2 import AdapterConfig
27from voltha.protos.common_pb2 import LogLevel
28from voltha.protos.device_pb2 import DeviceType, DeviceTypes
29from voltha.protos.health_pb2 import HealthStatus
30from voltha.registry import registry
31
32_ = third_party
33log = structlog.get_logger()
34
35
36@implementer(IAdapterInterface)
37class AdtranOltAdapter(object):
38 name = 'adtran_olt'
39
40 supported_device_types = [
41 DeviceType(
42 id=name,
43 adapter=name,
44 accepts_bulk_flow_update=True
45 )
46 ]
47
48 def __init__(self, adapter_agent, config):
49 self.adapter_agent = adapter_agent
50 self.config = config
51 self.descriptor = Adapter(
52 id=self.name,
53 vendor='Adtran Inc.',
Chip Boling252c7772017-08-16 10:13:17 -050054 version='0.2',
Chip Boling3e3b1a92017-05-16 11:51:18 -050055 config=AdapterConfig(log_level=LogLevel.INFO)
56 )
57 log.debug('adtran_olt.__init__', adapter_agent=adapter_agent)
58 self.devices_handlers = dict() # device_id -> AdtranOltHandler()
59 self.interface = registry('main').get_args().interface
Chip Boling252c7772017-08-16 10:13:17 -050060 self.logical_device_id_to_root_device_id = dict()
Chip Boling3e3b1a92017-05-16 11:51:18 -050061
62 def start(self):
63 """
64 Called once after adapter instance is loaded. Can be used to async
65 initialization.
66
67 :return: (None or Deferred)
68 """
Chip Boling3e3b1a92017-05-16 11:51:18 -050069 log.info('started', interface=self.interface)
70
71 def stop(self):
72 """
73 Called once before adapter is unloaded. It can be used to perform
74 any cleanup after the adapter.
75
76 :return: (None or Deferred)
77 """
Chip Boling3e3b1a92017-05-16 11:51:18 -050078 log.info('stopped', interface=self.interface)
79
80 def adapter_descriptor(self):
81 """
82 Return the adapter descriptor object for this adapter.
83
84 :return: voltha.Adapter grpc object (see voltha/protos/adapter.proto),
85 with adapter-specific information and config extensions.
86 """
87 log.debug('get descriptor', interface=self.interface)
88 return self.descriptor
89
90 def device_types(self):
91 """
92 Return list of device types supported by the adapter.
93
94 :return: voltha.DeviceTypes protobuf object, with optional type
95 specific extensions.
96 """
97 log.debug('get device_types', interface=self.interface, items=self.supported_device_types)
98 return DeviceTypes(items=self.supported_device_types)
99
100 def health(self):
101 """
102 Return a 3-state health status using the voltha.HealthStatus message.
103
104 :return: Deferred or direct return with voltha.HealthStatus message
105 """
106 log.debug('get health', interface=self.interface)
107 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
108
109 def change_master_state(self, master):
110 """
111 Called to indicate if plugin shall assume or lose master role. The
112 master role can be used to perform functions that must be performed
113 from a single point in the cluster. In single-node deployments of
114 Voltha, the plugins are always in master role.
115
116 :param master: (bool) True to indicate the mastership needs to be
117 assumed; False to indicate that mastership needs to be abandoned.
118 :return: (Deferred) which is fired by the adapter when mastership is
119 assumed/dropped, respectively.
120 """
121 log.debug('change_master_state', interface=self.interface, master=master)
122 raise NotImplementedError()
123
124 def adopt_device(self, device):
125 """
126 Make sure the adapter looks after given device. Called when a device
127 is provisioned top-down and needs to be activated by the adapter.
128
129 :param device: A voltha.Device object, with possible device-type
130 specific extensions. Such extensions shall be described as part of
131 the device type specification returned by device_types().
132 :return: (Deferred) Shall be fired to acknowledge device ownership.
133 """
134 log.info('adopt-device', device=device)
135 self.devices_handlers[device.id] = AdtranOltHandler(self, device.id)
136 reactor.callLater(0, self.devices_handlers[device.id].activate, device)
137 return device
138
khenaidooce681042017-06-12 11:25:34 -0400139 def reconcile_device(self, device):
140 """
Chip Boling7294b252017-06-15 16:16:55 -0500141 Make sure the adapter looks after given device. Called when this device has
142 changed ownership from another Voltha instance to this one (typically, this
143 occurs when the previous voltha instance went down).
khenaidooce681042017-06-12 11:25:34 -0400144
Chip Boling7294b252017-06-15 16:16:55 -0500145 :param device: A voltha.Device object, with possible device-type specific
146 extensions. Such extensions shall be described as part of
147 the device type specification returned by device_types().
148 :return: (Deferred) Shall be fired to acknowledge device ownership.
149 """
150 log.info('reconcile-device', device=device)
151 self.devices_handlers[device.id] = AdtranOltHandler(self, device.id)
152 reactor.callLater(0, self.devices_handlers[device.id].activate, device, reconciling=True)
153 return device
khenaidooce681042017-06-12 11:25:34 -0400154
Chip Boling3e3b1a92017-05-16 11:51:18 -0500155 def abandon_device(self, device):
156 """
157 Make sure the adapter no longer looks after device. This is called
158 if device ownership is taken over by another Voltha instance.
159
160 :param device: A Voltha.Device object.
161 :return: (Deferred) Shall be fired to acknowledge abandonment.
162 """
163 log.info('abandon-device', device=device)
Chip Boling7294b252017-06-15 16:16:55 -0500164 raise NotImplementedError()
Chip Boling3e3b1a92017-05-16 11:51:18 -0500165
166 def disable_device(self, device):
167 """
168 This is called when a previously enabled device needs to be disabled
169 based on a NBI call.
170
171 :param device: A Voltha.Device object.
172 :return: (Deferred) Shall be fired to acknowledge disabling the device.
173 """
174 log.debug('disable_device', device=device)
Chip Boling7294b252017-06-15 16:16:55 -0500175 reactor.callLater(0, self.devices_handlers[device.id].disable)
176 return device
Chip Boling3e3b1a92017-05-16 11:51:18 -0500177
178 def reenable_device(self, device):
179 """
180 This is called when a previously disabled device needs to be enabled
181 based on a NBI call.
182
183 :param device: A Voltha.Device object.
184 :return: (Deferred) Shall be fired to acknowledge re-enabling the device.
185 """
186 log.debug('reenable_device', device=device)
Chip Boling7294b252017-06-15 16:16:55 -0500187 reactor.callLater(0, self.devices_handlers[device.id].reenable)
188 return device
Chip Boling3e3b1a92017-05-16 11:51:18 -0500189
190 def reboot_device(self, device):
191 """
192 This is called to reboot a device based on a NBI call. The admin
193 state of the device will not change after the reboot
194
195 :param device: A Voltha.Device object.
196 :return: (Deferred) Shall be fired to acknowledge the reboot.
197 """
198 log.info('reboot_device', device=device)
Chip Boling7294b252017-06-15 16:16:55 -0500199 reactor.callLater(0, self.devices_handlers[device.id].reboot)
200 return device
Chip Boling3e3b1a92017-05-16 11:51:18 -0500201
Lydia Fang01f2e852017-06-28 17:24:58 -0700202 def download_image(self, device, request):
203 log.info('image_download', device=device, request=request)
204 raise NotImplementedError()
205
206 def get_image_download_status(self, device, request):
207 log.info('get_image_download', device=device, request=request)
208 raise NotImplementedError()
209
210 def cancel_image_download(self, device, request):
211 log.info('cancel_image_download', device=device)
212 raise NotImplementedError()
213
214 def activate_image_update(self, device, request):
215 log.info('activate_image_update', device=device, \
216 request=request)
217 raise NotImplementedError()
218
219 def revert_image_update(self, device, request):
220 log.info('revert_image_update', device=device, \
221 request=request)
222 raise NotImplementedError()
223
sathishg5ae86222017-06-28 15:16:29 +0530224 def self_test_device(self, device):
225 """
226 This is called to Self a device based on a NBI call.
227 :param device: A Voltha.Device object.
228 :return: Will return result of self test
229 """
Chip Boling5561d552017-07-07 15:11:26 -0500230 from voltha.protos.voltha_pb2 import SelfTestResponse
sathishg5ae86222017-06-28 15:16:29 +0530231 log.info('self-test-device', device=device.id)
Chip Boling5561d552017-07-07 15:11:26 -0500232
233 # TODO: Support self test?
234 return SelfTestResponse(result=SelfTestResponse.NOT_SUPPORTED)
sathishg5ae86222017-06-28 15:16:29 +0530235
Chip Boling3e3b1a92017-05-16 11:51:18 -0500236 def delete_device(self, device):
237 """
238 This is called to delete a device from the PON based on a NBI call.
239 If the device is an OLT then the whole PON will be deleted.
240
241 :param device: A Voltha.Device object.
242 :return: (Deferred) Shall be fired to acknowledge the deletion.
243 """
244 log.info('delete_device', device=device)
Chip Boling7294b252017-06-15 16:16:55 -0500245 reactor.callLater(0, self.devices_handlers[device.id].delete)
246 return device
Chip Boling3e3b1a92017-05-16 11:51:18 -0500247
248 def get_device_details(self, device):
249 """
250 This is called to get additional device details based on a NBI call.
251
252 :param device: A Voltha.Device object.
253 :return: (Deferred) Shall be fired to acknowledge the retrieval of
254 additional details.
255 """
256 log.debug('get_device_details', device=device)
257 raise NotImplementedError()
258
259 def update_flows_bulk(self, device, flows, groups):
260 """
261 Called after any flow table change, but only if the device supports
262 bulk mode, which is expressed by the 'accepts_bulk_flow_update'
263 capability attribute of the device type.
264
265 :param device: A Voltha.Device object.
266 :param flows: An openflow_v13.Flows object
267 :param groups: An openflow_v13.Flows object
268 :return: (Deferred or None)
269 """
270 log.info('bulk-flow-update', device_id=device.id, flows=flows,
271 groups=groups)
272 assert len(groups.items) == 0, "Cannot yet deal with groups"
Chip Boling7294b252017-06-15 16:16:55 -0500273
Chip Boling3e3b1a92017-05-16 11:51:18 -0500274 handler = self.devices_handlers[device.id]
275 return handler.update_flow_table(flows.items, device)
276
277 def update_flows_incrementally(self, device, flow_changes, group_changes):
278 """
279 [This mode is not supported yet.]
280
281 :param device: A Voltha.Device object.
282 :param flow_changes:
283 :param group_changes:
284 :return:
285 """
286 log.debug('update_flows_incrementally', device=device, flow_changes=flow_changes,
287 group_changes=group_changes)
288 raise NotImplementedError()
289
290 def update_pm_config(self, device, pm_configs):
291 """
292 Called every time a request is made to change pm collection behavior
293 :param device: A Voltha.Device object
294 :param pm_configs: A Pms
295 """
296 log.debug('update_pm_config', device=device, pm_configs=pm_configs)
Chip Boling5561d552017-07-07 15:11:26 -0500297 handler = self.devices_handlers[device.id]
298 handler.update_pm_config(device, pm_configs)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500299
300 def send_proxied_message(self, proxy_address, msg):
301 """
302 Forward a msg to a child device of device, addressed by the given
303 proxy_address=Device.ProxyAddress().
304
305 :param proxy_address: Address info for the parent device
306 to route the message to the child device. This was given to the
307 child device by the parent device at the creation of the child
308 device.
309 :param msg: (str) The actual message to send.
310 :return: (Deferred(None) or None) The return of this method should
311 indicate that the message was successfully *sent*.
312 """
313 log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)
314 handler = self.devices_handlers[proxy_address.device_id]
315 handler.send_proxied_message(proxy_address, msg)
316
317 def receive_proxied_message(self, proxy_address, msg):
318 """
319 Pass an async message (arrived via a proxy) to this device.
320
321 :param proxy_address: Address info for the parent device
322 to route the message to the child device. This was given to the
323 child device by the parent device at the creation of the child
324 device. Note this is the proxy_address with which the adapter
325 had to register prior to receiving proxied messages.
326 :param msg: (str) The actual message received.
327 :return: None
328 """
329 log.debug('receive_proxied_message', proxy_address=proxy_address, msg=msg)
330 raise NotImplementedError()
331
332 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
333 """
334 Pass a packet_out message content to adapter so that it can forward it
335 out to the device. This is only called on root devices.
336
337 :param logical_device_id:
338 :param egress_port_no: egress logical port number
339 :param msg: actual message
340 :return: None
341 """
342 log.info('packet-out', logical_device_id=logical_device_id,
343 egress_port_no=egress_port_no, msg_len=len(msg))
Chip Boling5561d552017-07-07 15:11:26 -0500344
345 def ldi_to_di(ldi):
346 di = self.logical_device_id_to_root_device_id.get(ldi)
347 if di is None:
348 logical_device = self.adapter_agent.get_logical_device(ldi)
349 di = logical_device.root_device_id
350 self.logical_device_id_to_root_device_id[ldi] = di
351 return di
352
353 device_id = ldi_to_di(logical_device_id)
354 handler = self.devices_handlers[device_id]
355 handler.packet_out(egress_port_no, msg)
Chip Boling3e3b1a92017-05-16 11:51:18 -0500356
357 def receive_inter_adapter_message(self, msg):
358 """
Chip Boling252c7772017-08-16 10:13:17 -0500359 Called when the adapter receives a message that was sent to it directly
Chip Boling3e3b1a92017-05-16 11:51:18 -0500360 from another adapter. An adapter may register for these messages by calling
361 the register_for_inter_adapter_messages() method in the adapter agent.
362 Note that it is the responsibility of the sending and receiving
363 adapters to properly encode and decode the message.
364 :param msg: The message contents.
365 :return: None
366 """
367 log.info('rx_inter_adapter_msg')
368 raise NotImplementedError()
Chip Boling99004882017-05-19 15:36:19 -0500369
370 def suppress_alarm(self, filter):
Chip Boling5561d552017-07-07 15:11:26 -0500371 """
372 Inform an adapter that all incoming alarms should be suppressed
373 :param filter: A Voltha.AlarmFilter object.
374 :return: (Deferred) Shall be fired to acknowledge the suppression.
375 """
Chip Boling99004882017-05-19 15:36:19 -0500376 log.info('suppress_alarm', filter=filter)
377 raise NotImplementedError()
378
379 def unsuppress_alarm(self, filter):
Chip Boling5561d552017-07-07 15:11:26 -0500380 """
381 Inform an adapter that all incoming alarms should resume
382 :param filter: A Voltha.AlarmFilter object.
383 :return: (Deferred) Shall be fired to acknowledge the unsuppression.
384 """
Chip Boling99004882017-05-19 15:36:19 -0500385 log.info('unsuppress_alarm', filter=filter)
386 raise NotImplementedError()
Nikolay Titov89004ec2017-06-19 18:22:42 -0400387
Chip Boling5561d552017-07-07 15:11:26 -0500388 # PON Mgnt APIs #
Nikolay Titov89004ec2017-06-19 18:22:42 -0400389 def create_interface(self, device, data):
Chip Boling5561d552017-07-07 15:11:26 -0500390 """
391 API to create various interfaces (only some PON interfaces as of now)
392 in the devices
393 """
Chip Boling252c7772017-08-16 10:13:17 -0500394 log.info('create_interface', data=data)
395 handler = self.devices_handlers[device.id]
396 handler.create_interface(device, data)
Nikolay Titov89004ec2017-06-19 18:22:42 -0400397
398 def update_interface(self, device, data):
Chip Boling5561d552017-07-07 15:11:26 -0500399 """
400 API to update various interfaces (only some PON interfaces as of now)
401 in the devices
402 """
Nikolay Titov89004ec2017-06-19 18:22:42 -0400403 raise NotImplementedError()
404
405 def remove_interface(self, device, data):
Chip Boling5561d552017-07-07 15:11:26 -0500406 """
407 API to delete various interfaces (only some PON interfaces as of now)
408 in the devices
409 """
Nikolay Titov89004ec2017-06-19 18:22:42 -0400410 raise NotImplementedError()
411
412 def receive_onu_detect_state(self, device_id, state):
Chip Boling5561d552017-07-07 15:11:26 -0500413 """
414 Receive onu detect state in ONU adapter
415 :param proxy_address: ONU device address
416 :param state: ONU detect state (bool)
417 :return: None
418 """
Nikolay Titov89004ec2017-06-19 18:22:42 -0400419 raise NotImplementedError()
Nikolay Titov176f1db2017-08-10 12:38:43 -0400420
421 def create_tcont(self, device, tcont_data, traffic_descriptor_data):
422 raise NotImplementedError()
423
424 def update_tcont(self, device, tcont_data, traffic_descriptor_data):
425 raise NotImplementedError()
426
427 def remove_tcont(self, device, tcont_data, traffic_descriptor_data):
428 raise NotImplementedError()
429
430 def create_gemport(self, device, data):
431 raise NotImplementedError()
432
433 def update_gemport(self, device, data):
434 raise NotImplementedError()
435
436 def remove_gemport(self, device, data):
437 raise NotImplementedError()
438
439 def create_multicast_gemport(self, device, data):
440 raise NotImplementedError()
441
442 def update_multicast_gemport(self, device, data):
443 raise NotImplementedError()
444
445 def remove_multicast_gemport(self, device, data):
446 raise NotImplementedError()
447
448 def create_multicast_distribution_set(self, device, data):
449 raise NotImplementedError()
450
451 def update_multicast_distribution_set(self, device, data):
452 raise NotImplementedError()
453
454 def remove_multicast_distribution_set(self, device, data):
455 raise NotImplementedError()