blob: d68e72b38bf61b5a43f44369ccc89d33a5e25f33 [file] [log] [blame]
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -05001#
2# Copyright 2017 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"""
18Broadcom OpenOMCI OLT/ONU adapter.
19
20This adapter does NOT support XPON
21"""
22
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -050023from __future__ import absolute_import
24import structlog
25from twisted.internet import reactor
kesavand5a2f61d2020-11-23 21:49:50 -050026from twisted.internet.defer import inlineCallbacks, returnValue
William Kurkian3a206332019-04-29 11:05:47 -040027
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050028from zope.interface import implementer
29
Matt Jeanneret72f96fc2019-02-11 10:53:05 -050030from pyvoltha.adapters.interface import IAdapterInterface
William Kurkian8235c1e2019-03-05 12:58:28 -050031from voltha_protos.adapter_pb2 import Adapter
32from voltha_protos.adapter_pb2 import AdapterConfig
Matt Jeanneret2e3cb8d2019-11-16 09:22:41 -050033from voltha_protos.device_pb2 import DeviceType, DeviceTypes
William Kurkian8235c1e2019-03-05 12:58:28 -050034from voltha_protos.health_pb2 import HealthStatus
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050035
Matt Jeanneret72f96fc2019-02-11 10:53:05 -050036from pyvoltha.adapters.common.frameio.frameio import hexify
37from pyvoltha.adapters.extensions.omci.openomci_agent import OpenOMCIAgent, OpenOmciAgentDefaults
Matt Jeanneret98f99dc2019-09-25 11:05:25 -040038from pyvoltha.adapters.extensions.omci.database.mib_db_dict import MibDbVolatileDict
Matt Jeanneret5e331892019-12-07 21:31:45 -050039from pyvoltha.adapters.extensions.omci.database.mib_db_dict_lazy import MibDbLazyWriteDict
Matt Jeanneret72f96fc2019-02-11 10:53:05 -050040
41from brcm_openomci_onu_handler import BrcmOpenomciOnuHandler
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050042from omci.brcm_capabilities_task import BrcmCapabilitiesTask
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050043from copy import deepcopy
kesavand5a2f61d2020-11-23 21:49:50 -050044from voltha_protos.extensions_pb2 import SingleGetValueResponse, GetValueResponse
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050045
46@implementer(IAdapterInterface)
47class BrcmOpenomciOnuAdapter(object):
48
49 name = 'brcm_openomci_onu'
50
51 supported_device_types = [
52 DeviceType(
53 id=name,
Mahir Gunyeld680cb62020-02-18 10:28:12 -080054 vendor_ids=['OPEN', 'ALCL', 'BRCM', 'TWSH', 'ALPH', 'ISKT', 'SFAA', 'BBSM', 'SCOM', 'ARPX', 'DACM', 'ERSN', 'HWTC', 'CIGG'],
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050055 adapter=name,
Mahir Gunyel9dfab822020-02-20 15:52:15 -080056 accepts_bulk_flow_update=False,
57 accepts_add_remove_flow_updates=True
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050058 )
59 ]
60
Matteo Scandolobb3317d2020-03-31 10:49:42 -070061 def __init__(self, id, core_proxy, adapter_proxy, config, build_info, current_replica, total_replicas, endpoint):
Matt Jeanneret08a8e862019-12-20 14:02:32 -050062 self.log = structlog.get_logger()
63 self.log.debug('starting-adapter', config=config)
64
Matt Jeannereta32441c2019-03-07 05:16:37 -050065 self.core_proxy = core_proxy
Matt Jeanneret0bd63c82019-02-15 05:40:44 -050066 self.adapter_proxy = adapter_proxy
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050067 self.config = config
68 self.descriptor = Adapter(
Matteo Scandolobb3317d2020-03-31 10:49:42 -070069 id=id,
Matt Jeanneret08a8e862019-12-20 14:02:32 -050070 vendor='VOLTHA OpenONU',
71 version=build_info.version,
Matteo Scandolobb3317d2020-03-31 10:49:42 -070072 config=AdapterConfig(),
73 currentReplica=current_replica,
74 totalReplicas=total_replicas,
75 endpoint=endpoint,
76 type=self.name
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050077 )
78 self.devices_handlers = dict()
Matt Jeanneret21363202019-02-13 16:21:48 -050079 self.device_handler_class = BrcmOpenomciOnuHandler
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050080
81 # Customize OpenOMCI for Broadcom ONUs
82 self.broadcom_omci = deepcopy(OpenOmciAgentDefaults)
83
Matt Jeanneretde16ed52019-09-18 19:05:15 -040084 self.broadcom_omci['mib-synchronizer']['audit-delay'] = 0 # disable audits as brcm onu wont upload once provisioned
Matt Jeanneret5e331892019-12-07 21:31:45 -050085 self.broadcom_omci['mib-synchronizer']['database'] = MibDbLazyWriteDict
Matt Jeanneret98f99dc2019-09-25 11:05:25 -040086 self.broadcom_omci['alarm-synchronizer']['database'] = MibDbVolatileDict
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050087 self.broadcom_omci['omci-capabilities']['tasks']['get-capabilities'] = BrcmCapabilitiesTask
88
89 # Defer creation of omci agent to a lazy init that allows subclasses to override support classes
90
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -050091 def custom_me_entities(self):
92 return None
93
94 @property
95 def omci_agent(self):
96 if not hasattr(self, '_omci_agent') or self._omci_agent is None:
Matt Jeanneret08a8e862019-12-20 14:02:32 -050097 self.log.debug('creating-omci-agent')
Matt Jeannereta32441c2019-03-07 05:16:37 -050098 self._omci_agent = OpenOMCIAgent(self.core_proxy,
99 self.adapter_proxy,
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500100 support_classes=self.broadcom_omci)
101 return self._omci_agent
102
103 def start(self):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500104 self.log.debug('starting')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500105 self.omci_agent.start()
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500106 self.log.info('started')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500107
108 def stop(self):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500109 self.log.debug('stopping')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500110
111 omci, self._omci_agent = self._omci_agent, None
112 if omci is not None:
113 self._omci_agent.stop()
114
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500115 self.log.info('stopped')
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500116
117 def adapter_descriptor(self):
118 return self.descriptor
119
120 def device_types(self):
121 return DeviceTypes(items=self.supported_device_types)
122
123 def health(self):
124 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
125
126 def change_master_state(self, master):
127 raise NotImplementedError()
128
129 def adopt_device(self, device):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500130 self.log.info('adopt-device', device_id=device.id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500131 self.devices_handlers[device.id] = BrcmOpenomciOnuHandler(self, device.id)
132 reactor.callLater(0, self.devices_handlers[device.id].activate, device)
133 return device
134
135 def reconcile_device(self, device):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500136 self.log.info('reconcile-device', device_id=device.id)
Matt Jeanneret5e331892019-12-07 21:31:45 -0500137 if not device.id in self.devices_handlers:
138 self.devices_handlers[device.id] = BrcmOpenomciOnuHandler(self, device.id)
139 reactor.callLater(0, self.devices_handlers[device.id].reconcile, device)
140 else:
141 self.log.debug('already-called-reconcile-device', device_id=device.id)
142 return device
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500143
144 def abandon_device(self, device):
145 raise NotImplementedError()
146
147 def disable_device(self, device):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500148 self.log.info('disable-onu-device', device_id=device.id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500149 if device.id in self.devices_handlers:
150 handler = self.devices_handlers[device.id]
151 if handler is not None:
152 handler.disable(device)
153
154 def reenable_device(self, device):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500155 self.log.info('reenable-onu-device', device_id=device.id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500156 if device.id in self.devices_handlers:
157 handler = self.devices_handlers[device.id]
158 if handler is not None:
159 handler.reenable(device)
160
161 def reboot_device(self, device):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500162 self.log.info('reboot-device', device_id=device.id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500163 if device.id in self.devices_handlers:
164 handler = self.devices_handlers[device.id]
165 if handler is not None:
166 handler.reboot()
167
168 def download_image(self, device, request):
169 raise NotImplementedError()
170
171 def get_image_download_status(self, device, request):
172 raise NotImplementedError()
173
174 def cancel_image_download(self, device, request):
175 raise NotImplementedError()
176
177 def activate_image_update(self, device, request):
178 raise NotImplementedError()
179
180 def revert_image_update(self, device, request):
181 raise NotImplementedError()
182
kesavand54959a32020-01-20 18:52:42 +0530183 def enable_port(self, device_id, port):
184 raise NotImplementedError()
185
186 def disable_port(self, device_id, port):
187 raise NotImplementedError()
188
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500189 def self_test_device(self, device):
190 """
191 This is called to Self a device based on a NBI call.
192 :param device: A Voltha.Device object.
193 :return: Will return result of self test
194 """
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500195 self.log.info('self-test-device - Not implemented yet', device_id=device.id, serial_number=device.serial_number)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500196 raise NotImplementedError()
197
198 def delete_device(self, device):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500199 self.log.info('delete-device', device_id=device.id)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500200 if device.id in self.devices_handlers:
201 handler = self.devices_handlers[device.id]
202 if handler is not None:
203 handler.delete(device)
204 del self.devices_handlers[device.id]
205 return
206
207 def get_device_details(self, device):
208 raise NotImplementedError()
209
210 # TODO(smbaker): When BrcmOpenomciOnuAdapter is updated to inherit from OnuAdapter, this function can be deleted
Rohan Agrawalf0f8c292020-06-01 09:30:55 +0000211 def update_pm_config(self, device, pm_configs):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500212 self.log.info("adapter-update-pm-config", device_id=device.id, serial_number=device.serial_number,
Rohan Agrawalf0f8c292020-06-01 09:30:55 +0000213 pm_configs=pm_configs)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500214 handler = self.devices_handlers[device.id]
Rohan Agrawalf0f8c292020-06-01 09:30:55 +0000215 handler.update_pm_config(device, pm_configs)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500216
217 def update_flows_bulk(self, device, flows, groups):
218 '''
219 log.info('bulk-flow-update', device_id=device.id,
220 flows=flows, groups=groups)
221 '''
222 assert len(groups.items) == 0
223 handler = self.devices_handlers[device.id]
224 return handler.update_flow_table(device, flows.items)
225
226 def update_flows_incrementally(self, device, flow_changes, group_changes):
Mahir Gunyeld680cb62020-02-18 10:28:12 -0800227 self.log.info('incremental-flow-update', device_id=device.id,
228 flows=flow_changes, groups=group_changes)
229 # For now, there is no support for group changes
230 assert len(group_changes.to_add.items) == 0
231 assert len(group_changes.to_remove.items) == 0
232
233 handler = self.devices_handlers[device.id]
234 # Remove flows
235 if len(flow_changes.to_remove.items) != 0:
236 handler.remove_onu_flows(device, flow_changes.to_remove.items)
237
238 # Add flows
239 if len(flow_changes.to_add.items) != 0:
240 handler.add_onu_flows(device, flow_changes.to_add.items)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500241
242 def send_proxied_message(self, proxy_address, msg):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500243 self.log.debug('send-proxied-message', proxy_address=proxy_address, msg=msg)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500244
William Kurkian3a206332019-04-29 11:05:47 -0400245 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500246 def receive_proxied_message(self, proxy_address, msg):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500247 self.log.debug('receive-proxied-message', proxy_address=proxy_address,
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500248 device_id=proxy_address.device_id, msg=hexify(msg))
249 # Device_id from the proxy_address is the olt device id. We need to
250 # get the onu device id using the port number in the proxy_address
William Kurkian3a206332019-04-29 11:05:47 -0400251 device = self.core_proxy. \
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500252 get_child_device_with_proxy_address(proxy_address)
253 if device:
254 handler = self.devices_handlers[device.id]
255 handler.receive_message(msg)
256
257 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500258 self.log.debug('packet-out', logical_device_id=logical_device_id,
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500259 egress_port_no=egress_port_no, msg_len=len(msg))
260
William Kurkian3a206332019-04-29 11:05:47 -0400261 @inlineCallbacks
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500262 def receive_inter_adapter_message(self, msg):
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500263 self.log.debug('receive-inter-adapter-message', msg=msg)
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500264 proxy_address = msg['proxy_address']
265 assert proxy_address is not None
266 # Device_id from the proxy_address is the olt device id. We need to
267 # get the onu device id using the port number in the proxy_address
William Kurkian3a206332019-04-29 11:05:47 -0400268 device = self.core_proxy. \
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500269 get_child_device_with_proxy_address(proxy_address)
270 if device:
271 handler = self.devices_handlers[device.id]
272 handler.event_messages.put(msg)
273 else:
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500274 self.log.error("device-not-found")
Matt Jeanneretf1e9c5d2019-02-08 07:41:29 -0500275
Matt Jeanneretc083f462019-03-11 15:02:01 -0400276
Matteo Scandolob33166d2020-06-16 16:08:00 -0700277 def process_inter_adapter_message(self, msg, max_retry=0, current_retry=0):
Matt Jeannereta32441c2019-03-07 05:16:37 -0500278 # Unpack the header to know which device needs to handle this message
279 if msg.header:
Matt Jeanneret08a8e862019-12-20 14:02:32 -0500280 self.log.debug('process-inter-adapter-message', type=msg.header.type, from_topic=msg.header.from_topic,
Matteo Scandolod8d73172019-11-26 12:15:15 -0700281 to_topic=msg.header.to_topic, to_device_id=msg.header.to_device_id)
Matteo Scandolob33166d2020-06-16 16:08:00 -0700282
283 # NOTE this should only happen in the case of ONU_IND_REQUEST as described in VOL-3223
284 if not msg.header.to_device_id in self.devices_handlers:
285 self.log.warn('process-inter-adapter-message-handler-not-found-retry-in-one-sec', type=msg.header.type,
286 from_topic=msg.header.from_topic, to_topic=msg.header.to_topic, to_device_id=msg.header.to_device_id)
287 if current_retry == max_retry:
288 self.log.error('process-inter-adapter-message-handler-not-found-no-more-retry', type=msg.header.type,
289 from_topic=msg.header.from_topic, to_topic=msg.header.to_topic, to_device_id=msg.header.to_device_id)
290 return
291 else:
292 reactor.callLater(1, self.process_inter_adapter_message, msg, max_retry=10, current_retry=current_retry+1)
293 return
294
Matt Jeannereta32441c2019-03-07 05:16:37 -0500295 handler = self.devices_handlers[msg.header.to_device_id]
296 handler.process_inter_adapter_message(msg)
onkarkundargia1e2af22020-01-27 11:51:43 +0530297
298 def start_omci_test(self, device, uuid):
299 """
300
301 :param device:
302 :return:
303 """
304 self.log.info('Omci-test-action-request-On', request=device)
305 handler = self.devices_handlers[device.id]
306 result = handler.start_omci_test_action(device, uuid)
307 return result
kesavand5a2f61d2020-11-23 21:49:50 -0500308
309 @inlineCallbacks
310 def single_get_value_request(self, request):
311 """
312 :param request: A request to get a specific attribute of a device, of type SingleGetValueRequest
313 :return:
314 """
315 self.log.info('single-get-value-request', request=request)
316 handler = self.devices_handlers[request.targetId]
317 get_value_req = request.request
318 if get_value_req.HasField("uniInfo"):
319 result = yield handler.get_uni_status(get_value_req)
320 self.log.debug('single-get-value-result', res=result)
321 returnValue(result)
322 else:
323 self.log.debug('invalid-request')
324 errresult = SingleGetValueResponse()
325 errresult.response.status = GetValueResponse.ERROR
326 errresult.response.errReason = GetValueResponse.UNSUPPORTED
327 returnValue(errresult)