blob: b3b906f86fcb0f56bc487a7fdafecbcac0c32262 [file] [log] [blame]
Chip Boling67b674a2019-02-08 11:42:18 -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#
16
17"""
18Adapter abstract base class
19"""
20
Zack Williams84a71e92019-11-15 09:00:19 -070021from __future__ import absolute_import
Chip Boling67b674a2019-02-08 11:42:18 -060022import structlog
23from twisted.internet import reactor
24from zope.interface import implementer
25
Zack Williams84a71e92019-11-15 09:00:19 -070026from .interface import IAdapterInterface
William Kurkianede82e92019-03-05 13:02:57 -050027from voltha_protos.adapter_pb2 import Adapter
28from voltha_protos.adapter_pb2 import AdapterConfig
29from voltha_protos.common_pb2 import AdminState
30from voltha_protos.common_pb2 import LogLevel
31from voltha_protos.device_pb2 import DeviceType, DeviceTypes
32from voltha_protos.health_pb2 import HealthStatus
Chip Boling67b674a2019-02-08 11:42:18 -060033
34
35log = structlog.get_logger()
36
37
38@implementer(IAdapterInterface)
39class IAdapter(object):
40 def __init__(self,
41 core_proxy,
42 adapter_proxy,
43 config,
44 device_handler_class,
45 name,
46 vendor,
47 version,
48 device_type, vendor_id,
49 accepts_bulk_flow_update=True,
50 accepts_add_remove_flow_updates=False):
51 log.debug(
52 'Initializing adapter: {} {} {}'.format(vendor, name, version))
53 self.core_proxy = core_proxy
54 self.adapter_proxy = adapter_proxy
55 self.config = config
56 self.name = name
57 self.supported_device_types = [
58 DeviceType(
59 id=device_type,
60 vendor_id=vendor_id,
61 adapter=name,
62 accepts_bulk_flow_update=accepts_bulk_flow_update,
63 accepts_add_remove_flow_updates=accepts_add_remove_flow_updates
64 )
65 ]
66 self.descriptor = Adapter(
67 id=self.name,
68 vendor=vendor,
69 version=version,
70 config=AdapterConfig(log_level=LogLevel.INFO)
71 )
72 self.devices_handlers = dict() # device_id -> Olt/OnuHandler()
73 self.device_handler_class = device_handler_class
74
75 def start(self):
76 log.info('Starting adapter: {}'.format(self.name))
77
78 def stop(self):
79 log.info('Stopping adapter: {}'.format(self.name))
80
81 def adapter_descriptor(self):
82 return self.descriptor
83
84 def device_types(self):
85 return DeviceTypes(items=self.supported_device_types)
86
87 def health(self):
88 # return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
89 return HealthStatus(state=HealthStatus.HEALTHY)
90
91 def change_master_state(self, master):
92 raise NotImplementedError()
93
94 def get_ofp_device_info(self, device):
95 log.debug('get_ofp_device_info_start', device_id=device.id)
96 ofp_device_info = self.devices_handlers[device.id].get_ofp_device_info(
97 device)
98 log.debug('get_ofp_device_info_ends', device_id=device.id)
99 return ofp_device_info
100
Chip Boling67b674a2019-02-08 11:42:18 -0600101 def adopt_device(self, device):
102 log.debug('adopt_device', device_id=device.id)
103 self.devices_handlers[device.id] = self.device_handler_class(self,
104 device.id)
105 reactor.callLater(0, self.devices_handlers[device.id].activate, device)
106 log.debug('adopt_device_done', device_id=device.id)
107 return device
108
109 def reconcile_device(self, device):
110 raise NotImplementedError()
111
112 def abandon_device(self, device):
113 raise NotImplementedError()
114
115 def disable_device(self, device):
116 log.info('disable-device', device_id=device.id)
117 reactor.callLater(0, self.devices_handlers[device.id].disable)
118 log.debug('disable-device-done', device_id=device.id)
119 return device
120
121 def reenable_device(self, device):
122 log.info('reenable-device', device_id=device.id)
123 reactor.callLater(0, self.devices_handlers[device.id].reenable)
124 log.info('reenable-device-done', device_id=device.id)
125 return device
126
127 def reboot_device(self, device):
128 log.info('reboot-device', device_id=device.id)
129 reactor.callLater(0, self.devices_handlers[device.id].reboot)
130 log.info('reboot-device-done', device_id=device.id)
131 return device
132
133 def download_image(self, device, request):
134 raise NotImplementedError()
135
136 def get_image_download_status(self, device, request):
137 raise NotImplementedError()
138
139 def cancel_image_download(self, device, request):
140 raise NotImplementedError()
141
142 def activate_image_update(self, device, request):
143 raise NotImplementedError()
144
145 def revert_image_update(self, device, request):
146 raise NotImplementedError()
147
148 def self_test_device(self, device):
149 log.info('self-test', device_id=device.id)
150 result = reactor.callLater(0, self.devices_handlers[
151 device.id].self_test_device)
152 log.info('self-test-done', device_id=device.id)
153 return result
154
155 def delete_device(self, device):
156 log.info('delete-device', device_id=device.id)
157 reactor.callLater(0, self.devices_handlers[device.id].delete)
158 log.info('delete-device-done', device_id=device.id)
159 return device
160
161 def get_device_details(self, device):
162 raise NotImplementedError()
163
164 def update_flows_bulk(self, device, flows, groups):
Matteo Scandolo63efb062019-11-26 12:14:48 -0700165 log.debug('bulk-flow-update', device_id=device.id,
Chip Boling67b674a2019-02-08 11:42:18 -0600166 flows=flows, groups=groups)
167 assert len(groups.items) == 0
168 reactor.callLater(0, self.devices_handlers[device.id].update_flow_table,
169 flows.items)
170 return device
171
172 def update_flows_incrementally(self, device, flow_changes, group_changes):
173 log.info('incremental-flow-update', device_id=device.id,
174 flows=flow_changes, groups=group_changes)
175 # For now, there is no support for group changes
176 assert len(group_changes.to_add.items) == 0
177 assert len(group_changes.to_remove.items) == 0
178
179 handler = self.devices_handlers[device.id]
180 # Remove flows
181 if len(flow_changes.to_remove.items) != 0:
182 reactor.callLater(0, handler.remove_from_flow_table,
183 flow_changes.to_remove.items)
184
185 # Add flows
186 if len(flow_changes.to_add.items) != 0:
187 reactor.callLater(0, handler.add_to_flow_table,
188 flow_changes.to_add.items)
189 return device
190
191 def update_pm_config(self, device, pm_config):
192 log.info("adapter-update-pm-config", device=device,
193 pm_config=pm_config)
194 handler = self.devices_handlers[device.id]
195 if handler:
196 reactor.callLater(0, handler.update_pm_config, device, pm_config)
197
198 def process_inter_adapter_message(self, msg):
199 raise NotImplementedError()
200
201 def receive_packet_out(self, device_id, egress_port_no, msg):
202 raise NotImplementedError()
203
204 def suppress_alarm(self, filter):
205 raise NotImplementedError()
206
207 def unsuppress_alarm(self, filter):
208 raise NotImplementedError()
209
210 def _get_handler(self, device):
211 if device.id in self.devices_handlers:
212 handler = self.devices_handlers[device.id]
213 if handler is not None:
214 return handler
215 return None
216
217
218"""
219OLT Adapter base class
220"""
221
222
223class OltAdapter(IAdapter):
224 def __init__(self,
225 core_proxy,
226 adapter_proxy,
227 config,
228 device_handler_class,
229 name,
230 vendor,
231 version, device_type,
232 accepts_bulk_flow_update=True,
233 accepts_add_remove_flow_updates=False):
234 super(OltAdapter, self).__init__(core_proxy=core_proxy,
235 adapter_proxy=adapter_proxy,
236 config=config,
237 device_handler_class=device_handler_class,
238 name=name,
239 vendor=vendor,
240 version=version,
241 device_type=device_type,
242 vendor_id=None,
243 accepts_bulk_flow_update=accepts_bulk_flow_update,
244 accepts_add_remove_flow_updates=accepts_add_remove_flow_updates)
245 self.logical_device_id_to_root_device_id = dict()
246
247 def reconcile_device(self, device):
248 try:
249 self.devices_handlers[device.id] = self.device_handler_class(self,
250 device.id)
251 # Work only required for devices that are in ENABLED state
252 if device.admin_state == AdminState.ENABLED:
253 reactor.callLater(0,
254 self.devices_handlers[device.id].reconcile,
255 device)
256 else:
257 # Invoke the children reconciliation which would setup the
258 # basic children data structures
259 self.core_proxy.reconcile_child_devices(device.id)
260 return device
Zack Williams84a71e92019-11-15 09:00:19 -0700261 except Exception as e:
Chip Boling67b674a2019-02-08 11:42:18 -0600262 log.exception('Exception', e=e)
263
264 def send_proxied_message(self, proxy_address, msg):
265 log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)
266 handler = self.devices_handlers[proxy_address.device_id]
267 handler.send_proxied_message(proxy_address, msg)
268
269 def process_inter_adapter_message(self, msg):
270 log.debug('process-inter-adapter-message', msg=msg)
271 # Unpack the header to know which device needs to handle this message
272 handler = None
273 if msg.header.proxy_device_id:
274 # typical request
275 handler = self.devices_handlers[msg.header.proxy_device_id]
276 elif msg.header.to_device_id and \
277 msg.header.to_device_id in self.devices_handlers:
278 # typical response
279 handler = self.devices_handlers[msg.header.to_device_id]
280 if handler:
281 reactor.callLater(0, handler.process_inter_adapter_message, msg)
282
283 def receive_packet_out(self, device_id, egress_port_no, msg):
284 try:
285 log.info('receive_packet_out', device_id=device_id,
286 egress_port=egress_port_no, msg=msg)
287 handler = self.devices_handlers[device_id]
288 if handler:
289 reactor.callLater(0, handler.packet_out, egress_port_no, msg.data)
Zack Williams84a71e92019-11-15 09:00:19 -0700290 except Exception as e:
Chip Boling67b674a2019-02-08 11:42:18 -0600291 log.exception('packet-out-failure', e=e)
292
293
294"""
295ONU Adapter base class
296"""
297
298
299class OnuAdapter(IAdapter):
300 def __init__(self,
301 core_proxy,
302 adapter_proxy,
303 config,
304 device_handler_class,
305 name,
306 vendor,
307 version,
308 device_type,
309 vendor_id,
310 accepts_bulk_flow_update=True,
311 accepts_add_remove_flow_updates=False):
312 super(OnuAdapter, self).__init__(core_proxy=core_proxy,
313 adapter_proxy=adapter_proxy,
314 config=config,
315 device_handler_class=device_handler_class,
316 name=name,
317 vendor=vendor,
318 version=version,
319 device_type=device_type,
320 vendor_id=vendor_id,
321 accepts_bulk_flow_update=accepts_bulk_flow_update,
322 accepts_add_remove_flow_updates=accepts_add_remove_flow_updates)
323
324 def reconcile_device(self, device):
325 self.devices_handlers[device.id] = self.device_handler_class(self,
326 device.id)
327 # Reconcile only if state was ENABLED
328 if device.admin_state == AdminState.ENABLED:
329 reactor.callLater(0,
330 self.devices_handlers[device.id].reconcile,
331 device)
332 return device
333
334 def receive_proxied_message(self, proxy_address, msg):
335 log.info('receive-proxied-message', proxy_address=proxy_address,
336 device_id=proxy_address.device_id, msg=msg)
337 # Device_id from the proxy_address is the olt device id. We need to
338 # get the onu device id using the port number in the proxy_address
339 device = self.core_proxy. \
340 get_child_device_with_proxy_address(proxy_address)
341 if device:
342 handler = self.devices_handlers[device.id]
343 handler.receive_message(msg)
344
345 def process_inter_adapter_message(self, msg):
346 log.info('process-inter-adapter-message', msg=msg)
347 # Unpack the header to know which device needs to handle this message
348 if msg.header:
349 handler = self.devices_handlers[msg.header.to_device_id]
350 handler.process_inter_adapter_message(msg)