blob: 9d7175a3e88ec72d4b49effa3aa3a6627da0fd82 [file] [log] [blame]
Zsolt Haraszti656ecc62016-12-28 15:08:23 -08001#
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08002# Copyright 2017 the original author or authors.
Zsolt Haraszti656ecc62016-12-28 15:08:23 -08003#
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"""
18Fully simulated OLT/ONU adapter.
19"""
20
21import structlog
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080022from twisted.internet.defer import DeferredQueue, inlineCallbacks
Khen Nursimulud068d812017-03-06 11:44:18 -050023from common.utils.asleep import asleep
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080024
Shad Ansarid1aa9e72017-06-23 21:34:25 -070025from voltha.adapters.iadapter import OnuAdapter
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080026from voltha.core.logical_device_agent import mac_str_to_tuple
27from voltha.protos import third_party
Shad Ansari14bcd992017-06-13 14:27:20 -070028from voltha.protos.common_pb2 import OperStatus, ConnectStatus, AdminState
29from voltha.protos.device_pb2 import Port
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080030from voltha.protos.logical_device_pb2 import LogicalPort
Khen Nursimulud068d812017-03-06 11:44:18 -050031from voltha.protos.openflow_13_pb2 import OFPPS_LIVE, OFPPF_FIBER, \
Shad Ansari14bcd992017-06-13 14:27:20 -070032 OFPPF_1GB_FD
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080033from voltha.protos.openflow_13_pb2 import ofp_port
34from voltha.protos.ponsim_pb2 import FlowTable
Nikolay Titov0da216c2017-07-27 00:47:44 -040035from voltha.protos.ponsim_pb2 import InterfaceConfig
36from voltha.protos.bbf_fiber_base_pb2 import OntaniConfig, VOntaniConfig, \
37 VEnetConfig
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080038
39_ = third_party
40log = structlog.get_logger()
41
42
Shad Ansarid1aa9e72017-06-23 21:34:25 -070043class PonSimOnuAdapter(OnuAdapter):
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080044 def __init__(self, adapter_agent, config):
Nikolay Titov89004ec2017-06-19 18:22:42 -040045 #DeviceType of ONU should be same as VENDOR ID of ONU Serial Number as specified by standard
46 #requires for identifying correct adapter or ranged ONU
Shad Ansari14bcd992017-06-13 14:27:20 -070047 super(PonSimOnuAdapter, self).__init__(adapter_agent=adapter_agent,
48 config=config,
Shad Ansari96f817b2017-06-18 23:17:44 -070049 device_handler_class = PonSimOnuHandler,
Shad Ansari14bcd992017-06-13 14:27:20 -070050 name='ponsim_onu',
51 vendor='Voltha project',
Nikolay Titov89004ec2017-06-19 18:22:42 -040052 version='0.4',
Niren R Chidrawarefcebcd2017-07-19 20:03:39 -040053 device_type='ponsim_onu',
54 vendor_id='PSMO')
Khen Nursimulud068d812017-03-06 11:44:18 -050055
Nikolay Titov0da216c2017-07-27 00:47:44 -040056 def create_interface(self, device, data):
57 log.info('create-interface', device_id=device.id)
Nikolay Titovfae5c912017-08-01 15:09:59 -040058 if device.id in self.devices_handlers:
59 handler = self.devices_handlers[device.id]
60 if handler is not None:
61 handler.create_interface(data)
62
Nikolay Titove44c3d22017-08-03 15:27:37 -040063 def update_interface(self, device, data):
64 log.info('update-interface', device_id=device.id)
65 if device.id in self.devices_handlers:
66 handler = self.devices_handlers[device.id]
67 if handler is not None:
68 handler.update_interface(data)
69
Nikolay Titovfae5c912017-08-01 15:09:59 -040070 def remove_interface(self, device, data):
71 log.info('remove-interface', device_id=device.id)
72 if device.id in self.devices_handlers:
73 handler = self.devices_handlers[device.id]
74 if handler is not None:
75 handler.remove_interface(data)
Nikolay Titov0da216c2017-07-27 00:47:44 -040076
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080077class PonSimOnuHandler(object):
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080078 def __init__(self, adapter, device_id):
79 self.adapter = adapter
80 self.adapter_agent = adapter.adapter_agent
81 self.device_id = device_id
82 self.log = structlog.get_logger(device_id=device_id)
83 self.incoming_messages = DeferredQueue()
84 self.proxy_address = None
Khen Nursimulud068d812017-03-06 11:44:18 -050085 # reference of uni_port is required when re-enabling the device if
86 # it was disabled previously
87 self.uni_port = None
88 self.pon_port = None
Zsolt Haraszti656ecc62016-12-28 15:08:23 -080089
90 def receive_message(self, msg):
91 self.incoming_messages.put(msg)
92
93 def activate(self, device):
94 self.log.info('activating')
95
96 # first we verify that we got parent reference and proxy info
97 assert device.parent_id
98 assert device.proxy_address.device_id
99 assert device.proxy_address.channel_id
100
101 # register for proxied messages right away
102 self.proxy_address = device.proxy_address
103 self.adapter_agent.register_for_proxied_messages(device.proxy_address)
104
105 # populate device info
106 device.root = True
107 device.vendor = 'ponsim'
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400108 device.model = 'n/a'
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800109 device.connect_status = ConnectStatus.REACHABLE
110 self.adapter_agent.update_device(device)
111
112 # register physical ports
Khen Nursimulud068d812017-03-06 11:44:18 -0500113 self.uni_port = Port(
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800114 port_no=2,
115 label='UNI facing Ethernet port',
116 type=Port.ETHERNET_UNI,
117 admin_state=AdminState.ENABLED,
118 oper_status=OperStatus.ACTIVE
119 )
Khen Nursimulud068d812017-03-06 11:44:18 -0500120 self.pon_port = Port(
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800121 port_no=1,
122 label='PON port',
123 type=Port.PON_ONU,
124 admin_state=AdminState.ENABLED,
125 oper_status=OperStatus.ACTIVE,
126 peers=[
127 Port.PeerPort(
128 device_id=device.parent_id,
129 port_no=device.parent_port_no
130 )
131 ]
Khen Nursimulud068d812017-03-06 11:44:18 -0500132 )
133 self.adapter_agent.add_port(device.id, self.uni_port)
134 self.adapter_agent.add_port(device.id, self.pon_port)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800135
136 # add uni port to logical device
137 parent_device = self.adapter_agent.get_device(device.parent_id)
138 logical_device_id = parent_device.parent_id
139 assert logical_device_id
140 port_no = device.proxy_address.channel_id
141 cap = OFPPF_1GB_FD | OFPPF_FIBER
142 self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
143 id='uni-{}'.format(port_no),
144 ofp_port=ofp_port(
145 port_no=port_no,
146 hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % port_no),
147 name='uni-{}'.format(port_no),
148 config=0,
149 state=OFPPS_LIVE,
150 curr=cap,
151 advertised=cap,
152 peer=cap,
153 curr_speed=OFPPF_1GB_FD,
154 max_speed=OFPPF_1GB_FD
155 ),
156 device_id=device.id,
Khen Nursimulud068d812017-03-06 11:44:18 -0500157 device_port_no=self.uni_port.port_no
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800158 ))
159
160 device = self.adapter_agent.get_device(device.id)
161 device.oper_status = OperStatus.ACTIVE
162 self.adapter_agent.update_device(device)
163
khenaidoo032d3302017-06-09 14:50:04 -0400164 def _get_uni_port(self):
165 ports = self.adapter_agent.get_ports(self.device_id, Port.ETHERNET_UNI)
166 if ports:
167 # For now, we use on one uni port
168 return ports[0]
169
170 def _get_pon_port(self):
171 ports = self.adapter_agent.get_ports(self.device_id, Port.PON_ONU)
172 if ports:
173 # For now, we use on one uni port
174 return ports[0]
175
176 def reconcile(self, device):
177 self.log.info('reconciling-ONU-device-starts')
178
179 # first we verify that we got parent reference and proxy info
180 assert device.parent_id
181 assert device.proxy_address.device_id
182 assert device.proxy_address.channel_id
183
184 # register for proxied messages right away
185 self.proxy_address = device.proxy_address
186 self.adapter_agent.register_for_proxied_messages(device.proxy_address)
187
188 # Set the connection status to REACHABLE
189 device.connect_status = ConnectStatus.REACHABLE
190 self.adapter_agent.update_device(device)
191
192 # TODO: Verify that the uni, pon and logical ports exists
193
194 # Mark the device as REACHABLE and ACTIVE
195 device = self.adapter_agent.get_device(device.id)
196 device.connect_status = ConnectStatus.REACHABLE
197 device.oper_status = OperStatus.ACTIVE
198 self.adapter_agent.update_device(device)
199
200 self.log.info('reconciling-ONU-device-ends')
201
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800202 @inlineCallbacks
203 def update_flow_table(self, flows):
204
205 # we need to proxy through the OLT to get to the ONU
206
207 # reset response queue
208 while self.incoming_messages.pending:
209 yield self.incoming_messages.get()
210
211 msg = FlowTable(
212 port=self.proxy_address.channel_id,
213 flows=flows
214 )
215 self.adapter_agent.send_proxied_message(self.proxy_address, msg)
216
217 yield self.incoming_messages.get()
Khen Nursimulud068d812017-03-06 11:44:18 -0500218
Khen Nursimulud068d812017-03-06 11:44:18 -0500219 @inlineCallbacks
220 def reboot(self):
221 self.log.info('rebooting', device_id=self.device_id)
222
223 # Update the operational status to ACTIVATING and connect status to
224 # UNREACHABLE
225 device = self.adapter_agent.get_device(self.device_id)
226 previous_oper_status = device.oper_status
227 previous_conn_status = device.connect_status
228 device.oper_status = OperStatus.ACTIVATING
229 device.connect_status = ConnectStatus.UNREACHABLE
230 self.adapter_agent.update_device(device)
231
232 # Sleep 10 secs, simulating a reboot
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400233 # TODO: send alert and clear alert after the reboot
Khen Nursimulud068d812017-03-06 11:44:18 -0500234 yield asleep(10)
235
236 # Change the operational status back to its previous state. With a
237 # real OLT the operational state should be the state the device is
238 # after a reboot.
239 # Get the latest device reference
240 device = self.adapter_agent.get_device(self.device_id)
241 device.oper_status = previous_oper_status
242 device.connect_status = previous_conn_status
243 self.adapter_agent.update_device(device)
244 self.log.info('rebooted', device_id=self.device_id)
245
sathishg5ae86222017-06-28 15:16:29 +0530246 def self_test_device(self, device):
247 """
248 This is called to Self a device based on a NBI call.
249 :param device: A Voltha.Device object.
250 :return: Will return result of self test
251 """
252 log.info('self-test-device', device=device.id)
253 raise NotImplementedError()
254
Khen Nursimulud068d812017-03-06 11:44:18 -0500255 def disable(self):
256 self.log.info('disabling', device_id=self.device_id)
257
258 # Get the latest device reference
259 device = self.adapter_agent.get_device(self.device_id)
260
261 # Disable all ports on that device
262 self.adapter_agent.disable_all_ports(self.device_id)
263
264 # Update the device operational status to UNKNOWN
265 device.oper_status = OperStatus.UNKNOWN
266 device.connect_status = ConnectStatus.UNREACHABLE
267 self.adapter_agent.update_device(device)
268
269 # Remove the uni logical port from the OLT, if still present
270 parent_device = self.adapter_agent.get_device(device.parent_id)
271 assert parent_device
272 logical_device_id = parent_device.parent_id
273 assert logical_device_id
274 port_no = device.proxy_address.channel_id
275 port_id = 'uni-{}'.format(port_no)
276 try:
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400277 port = self.adapter_agent.get_logical_port(logical_device_id,
278 port_id)
Khen Nursimulud068d812017-03-06 11:44:18 -0500279 self.adapter_agent.delete_logical_port(logical_device_id, port)
280 except KeyError:
281 self.log.info('logical-port-not-found', device_id=self.device_id,
282 portid=port_id)
283
284 # Remove pon port from parent
khenaidoo032d3302017-06-09 14:50:04 -0400285 self.pon_port = self._get_pon_port()
Khen Nursimulud068d812017-03-06 11:44:18 -0500286 self.adapter_agent.delete_port_reference_from_parent(self.device_id,
287 self.pon_port)
288
289 # Just updating the port status may be an option as well
290 # port.ofp_port.config = OFPPC_NO_RECV
291 # yield self.adapter_agent.update_logical_port(logical_device_id,
292 # port)
293 # Unregister for proxied message
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400294 self.adapter_agent.unregister_for_proxied_messages(
295 device.proxy_address)
Khen Nursimulud068d812017-03-06 11:44:18 -0500296
297 # TODO:
298 # 1) Remove all flows from the device
299 # 2) Remove the device from ponsim
300
301 self.log.info('disabled', device_id=device.id)
302
Khen Nursimulud068d812017-03-06 11:44:18 -0500303 def reenable(self):
304 self.log.info('re-enabling', device_id=self.device_id)
khenaidoo032d3302017-06-09 14:50:04 -0400305 try:
306 # Get the latest device reference
307 device = self.adapter_agent.get_device(self.device_id)
Khen Nursimulud068d812017-03-06 11:44:18 -0500308
khenaidoo032d3302017-06-09 14:50:04 -0400309 # First we verify that we got parent reference and proxy info
310 assert device.parent_id
311 assert device.proxy_address.device_id
312 assert device.proxy_address.channel_id
Khen Nursimulud068d812017-03-06 11:44:18 -0500313
khenaidoo032d3302017-06-09 14:50:04 -0400314 # Re-register for proxied messages right away
315 self.proxy_address = device.proxy_address
316 self.adapter_agent.register_for_proxied_messages(
317 device.proxy_address)
Khen Nursimulud068d812017-03-06 11:44:18 -0500318
khenaidoo032d3302017-06-09 14:50:04 -0400319 # Re-enable the ports on that device
320 self.adapter_agent.enable_all_ports(self.device_id)
Khen Nursimulud068d812017-03-06 11:44:18 -0500321
khenaidoo032d3302017-06-09 14:50:04 -0400322 # Refresh the port reference
323 self.uni_port = self._get_uni_port()
324 self.pon_port = self._get_pon_port()
Khen Nursimuluc60afa12017-03-13 14:33:50 -0400325
khenaidoo032d3302017-06-09 14:50:04 -0400326 # Add the pon port reference to the parent
327 self.adapter_agent.add_port_reference_to_parent(device.id,
328 self.pon_port)
Khen Nursimulud068d812017-03-06 11:44:18 -0500329
khenaidoo032d3302017-06-09 14:50:04 -0400330 # Update the connect status to REACHABLE
331 device.connect_status = ConnectStatus.REACHABLE
332 self.adapter_agent.update_device(device)
Khen Nursimulud068d812017-03-06 11:44:18 -0500333
khenaidoo032d3302017-06-09 14:50:04 -0400334 # re-add uni port to logical device
335 parent_device = self.adapter_agent.get_device(device.parent_id)
336 logical_device_id = parent_device.parent_id
337 assert logical_device_id
338 port_no = device.proxy_address.channel_id
339 cap = OFPPF_1GB_FD | OFPPF_FIBER
340 self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
341 id='uni-{}'.format(port_no),
342 ofp_port=ofp_port(
343 port_no=port_no,
344 hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % port_no),
345 name='uni-{}'.format(port_no),
346 config=0,
347 state=OFPPS_LIVE,
348 curr=cap,
349 advertised=cap,
350 peer=cap,
351 curr_speed=OFPPF_1GB_FD,
352 max_speed=OFPPF_1GB_FD
353 ),
354 device_id=device.id,
355 device_port_no=self.uni_port.port_no
356 ))
Khen Nursimulud068d812017-03-06 11:44:18 -0500357
khenaidoo032d3302017-06-09 14:50:04 -0400358 device = self.adapter_agent.get_device(device.id)
359 device.oper_status = OperStatus.ACTIVE
360 self.adapter_agent.update_device(device)
Khen Nursimulud068d812017-03-06 11:44:18 -0500361
khenaidoo032d3302017-06-09 14:50:04 -0400362 self.log.info('re-enabled', device_id=device.id)
363 except Exception, e:
364 self.log.exception('error-reenabling', e=e)
Khen Nursimulud068d812017-03-06 11:44:18 -0500365
Khen Nursimulud068d812017-03-06 11:44:18 -0500366 def delete(self):
367 self.log.info('deleting', device_id=self.device_id)
368
369 # A delete request may be received when an OLT is dsiabled
370
371 # TODO:
372 # 1) Remove all flows from the device
373 # 2) Remove the device from ponsim
374
375 self.log.info('deleted', device_id=self.device_id)
Nikolay Titov0da216c2017-07-27 00:47:44 -0400376
377 def get_interface_config(self, data):
378 interfaceConfig = InterfaceConfig()
379 if isinstance(data, OntaniConfig):
380 interfaceConfig.ont_ani_config.CopyFrom(data)
381 elif isinstance(data, VOntaniConfig):
382 interfaceConfig.vont_ani_config.CopyFrom(data)
383 elif isinstance(data, VEnetConfig):
384 interfaceConfig.venet_config.CopyFrom(data)
385 else:
386 return None
387 return interfaceConfig
388
389 def create_interface(self, data):
390 interfaceConfig = self.get_interface_config(data)
391 if interfaceConfig is not None:
392 self.log.info(
Nikolay Titovfae5c912017-08-01 15:09:59 -0400393 'forwarding-create-interface-request-to-onu-for-intfc-type',
394 interface_type=type(data))
395
Nikolay Titove44c3d22017-08-03 15:27:37 -0400396 def update_interface(self, data):
397 interfaceConfig = self.get_interface_config(data)
398 if interfaceConfig is not None:
399 self.log.info(
400 'forwarding-update-interface-request-to-onu-for-intfc-type',
401 interface_type=type(data))
402
Nikolay Titovfae5c912017-08-01 15:09:59 -0400403 def remove_interface(self, data):
404 interfaceConfig = self.get_interface_config(data)
405 if interfaceConfig is not None:
406 self.log.info(
407 'forwarding-remove-interface-request-to-onu-for-intfc-type',
Nikolay Titov0da216c2017-07-27 00:47:44 -0400408 interface_type=type(data))