blob: 406e21010978e62a6835ae3b1303e5d9fc9628f9 [file] [log] [blame]
Zsolt Haraszti66862032016-11-28 14:28:39 -08001#
Zsolt Haraszti3eb27a52017-01-03 21:56:48 -08002# Copyright 2017 the original author or authors.
Zsolt Haraszti66862032016-11-28 14:28:39 -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"""
18Mock device adapter for testing.
19"""
20from uuid import uuid4
21
Zsolt Haraszti749b0952017-01-18 09:02:35 -080022import arrow
Zsolt Haraszti66862032016-11-28 14:28:39 -080023import structlog
Zsolt Haraszti217a12e2016-12-19 16:37:55 -080024from klein import Klein
Zsolt Haraszti8925d1f2016-12-21 00:45:19 -080025from scapy.layers.l2 import Ether, EAPOL, Padding
Zsolt Haraszti217a12e2016-12-19 16:37:55 -080026from twisted.internet import endpoints
Zsolt Haraszti66862032016-11-28 14:28:39 -080027from twisted.internet import reactor
28from twisted.internet.defer import inlineCallbacks
Zsolt Haraszti749b0952017-01-18 09:02:35 -080029from twisted.internet.task import LoopingCall
Zsolt Haraszti217a12e2016-12-19 16:37:55 -080030from twisted.web.server import Site
Zsolt Haraszti66862032016-11-28 14:28:39 -080031from zope.interface import implementer
32
33from common.utils.asleep import asleep
34from voltha.adapters.interface import IAdapterInterface
Zsolt Haraszti85f12852016-12-24 08:30:58 -080035from voltha.core.flow_decomposer import *
Zsolt Haraszti66862032016-11-28 14:28:39 -080036from voltha.core.logical_device_agent import mac_str_to_tuple
37from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
38from voltha.protos.device_pb2 import DeviceType, DeviceTypes, Device, Port
Zsolt Haraszti749b0952017-01-18 09:02:35 -080039from voltha.protos.events_pb2 import KpiEvent, KpiEventType, MetricValuePairs
Zsolt Haraszti66862032016-11-28 14:28:39 -080040from voltha.protos.health_pb2 import HealthStatus
41from voltha.protos.common_pb2 import LogLevel, OperStatus, ConnectStatus, \
42 AdminState
43from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
44from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_port, OFPPF_1GB_FD, \
45 OFPPF_FIBER, OFPPS_LIVE, ofp_switch_features, OFPC_PORT_STATS, \
46 OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
47
48log = structlog.get_logger()
49
50
51@implementer(IAdapterInterface)
52class SimulatedOltAdapter(object):
53
54 name = 'simulated_olt'
55
Zsolt Harasztic5c5d102016-12-07 21:12:27 -080056 supported_device_types = [
57 DeviceType(
58 id='simulated_olt',
59 adapter=name,
60 accepts_bulk_flow_update=True
61 )
62 ]
63
Zsolt Haraszti217a12e2016-12-19 16:37:55 -080064 app = Klein()
65
Zsolt Haraszti66862032016-11-28 14:28:39 -080066 def __init__(self, adapter_agent, config):
67 self.adapter_agent = adapter_agent
68 self.config = config
69 self.descriptor = Adapter(
70 id=self.name,
71 vendor='Voltha project',
72 version='0.1',
73 config=AdapterConfig(log_level=LogLevel.INFO)
74 )
Zsolt Haraszti217a12e2016-12-19 16:37:55 -080075 self.control_endpoint = None
Sergio Slobodrianf39aaf82017-02-28 16:10:16 -050076 # Faked PM metrics for testing PM functionality
77 self.pon_tx_64 = 0
78 self.pon_tx_65_127 = 0
79 self.pon_tx_128_255 = 0
80 self.pon_tx_256_511 = 0
81 self.pon_tx_512_1023 = 0
82 self.pon_tx_1024_1518 = 0
83 self.pon_tx_1519_9k = 0
84
85 self.pon_rx_64 = 0
86 self.pon_rx_65_127 = 0
87 self.pon_rx_128_255 = 0
88 self.pon_rx_256_511 = 0
89 self.pon_rx_512_1023 = 0
90 self.pon_rx_1024_1518 = 0
91 self.pon_rx_1519_9k = 0
92
93 self.pon_tx_pkts = 0
94 self.pon_rx_pkts = 0
95 self.pon_tx_bytes = 0
96 self.pon_rx_bytes = 0
97
98 self.nni_tx_64 = 0
99 self.nni_tx_65_127 = 0
100 self.nni_tx_128_255 = 0
101 self.nni_tx_256_511 = 0
102 self.nni_tx_512_1023 = 0
103 self.nni_tx_1024_1518 = 0
104 self.nni_tx_1519_9k = 0
105
106 self.nni_rx_64 = 0
107 self.nni_rx_65_127 = 0
108 self.nni_rx_128_255 = 0
109 self.nni_rx_256_511 = 0
110 self.nni_rx_512_1023 = 0
111 self.nni_rx_1024_1518 = 0
112 self.nni_rx_1519_9k = 0
113
114 self.nni_tx_pkts = 0
115 self.nni_rx_pkts = 0
116 self.nni_tx_bytes = 0
117 self.nni_rx_bytes = 0
Zsolt Haraszti66862032016-11-28 14:28:39 -0800118
119 def start(self):
120 log.debug('starting')
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800121
122 # setup a basic web server for test control
123 self.control_endpoint = endpoints.TCP4ServerEndpoint(reactor, 18880)
124 self.control_endpoint.listen(self.get_test_control_site())
125
Zsolt Haraszti66862032016-11-28 14:28:39 -0800126 # TODO tmp: populate some devices and logical devices
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800127 # reactor.callLater(0, self._tmp_populate_stuff)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800128 log.info('started')
129
130 def stop(self):
131 log.debug('stopping')
132 log.info('stopped')
133
134 def adapter_descriptor(self):
135 return self.descriptor
136
137 def device_types(self):
Zsolt Harasztic5c5d102016-12-07 21:12:27 -0800138 return DeviceTypes(items=self.supported_device_types)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800139
140 def health(self):
141 return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
142
143 def change_master_state(self, master):
144 raise NotImplementedError()
145
146 def adopt_device(self, device):
147 # We kick of a simulated activation scenario
148 reactor.callLater(0.2, self._simulate_device_activation, device)
149 return device
150
151 def abandon_device(self, device):
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800152 raise NotImplementedError()
153
Zsolt Haraszti66862032016-11-28 14:28:39 -0800154 def deactivate_device(self, device):
155 raise NotImplementedError()
156
157 def _tmp_populate_stuff(self):
158 """
159 pretend that we discovered some devices and create:
160 - devices
161 - device ports for each
162 - logical device
163 - logical device ports
164 """
165
166 olt = Device(
167 id='simulated_olt_1',
168 type='simulated_olt',
169 root=True,
170 vendor='simulated',
171 model='n/a',
172 hardware_version='n/a',
173 firmware_version='n/a',
174 software_version='1.0',
175 serial_number=uuid4().hex,
176 adapter=self.name,
177 oper_status=OperStatus.DISCOVERED
178 )
179 self.adapter_agent.add_device(olt)
180 self.adapter_agent.add_port(
181 olt.id, Port(port_no=1, label='pon', type=Port.PON_OLT))
182 self.adapter_agent.add_port(
183 olt.id, Port(port_no=2, label='eth', type=Port.ETHERNET_NNI))
184
185 onu1 = Device(
186 id='simulated_onu_1',
187 type='simulated_onu',
188 root=False,
189 parent_id=olt.id,
190 parent_port_no=1,
191 vendor='simulated',
192 model='n/a',
193 hardware_version='n/a',
194 firmware_version='n/a',
195 software_version='1.0',
196 serial_number=uuid4().hex,
197 adapter='simulated_onu',
198 oper_status=OperStatus.DISCOVERED,
199 vlan=101
200 )
201 self.adapter_agent.add_device(onu1)
202 self.adapter_agent.add_port(onu1.id, Port(
203 port_no=2, label='eth', type=Port.ETHERNET_UNI))
204 self.adapter_agent.add_port(onu1.id, Port(
205 port_no=1,
206 label='pon',
207 type=Port.PON_ONU,
208 peers=[Port.PeerPort(device_id=olt.id, port_no=1)]))
209
210 onu2 = Device(
211 id='simulated_onu_2',
212 type='simulated_onu',
213 root=False,
214 parent_id=olt.id,
215 parent_port_no=1,
216 vendor='simulated',
217 model='n/a',
218 hardware_version='n/a',
219 firmware_version='n/a',
220 software_version='1.0',
221 serial_number=uuid4().hex,
222 adapter='simulated_onu',
223 oper_status=OperStatus.DISCOVERED,
224 vlan=102
225 )
226 self.adapter_agent.add_device(onu2)
227 self.adapter_agent.add_port(onu2.id, Port(
228 port_no=2, label='eth', type=Port.ETHERNET_UNI))
229 self.adapter_agent.add_port(onu2.id, Port(
230 port_no=1,
231 label='pon',
232 type=Port.PON_ONU,
233 peers=[Port.PeerPort(device_id=olt.id, port_no=1)]))
234
235 ld = LogicalDevice(
236 id='simulated1',
237 datapath_id=1,
238 desc=ofp_desc(
alshabib9fbb2232016-12-23 00:40:08 -0800239 mfr_desc='cord project',
Zsolt Haraszti66862032016-11-28 14:28:39 -0800240 hw_desc='simualted pon',
241 sw_desc='simualted pon',
242 serial_num=uuid4().hex,
243 dp_desc='n/a'
244 ),
245 switch_features=ofp_switch_features(
246 n_buffers=256, # TODO fake for now
247 n_tables=2, # TODO ditto
248 capabilities=( # TODO and ditto
249 OFPC_FLOW_STATS
250 | OFPC_TABLE_STATS
251 | OFPC_PORT_STATS
252 | OFPC_GROUP_STATS
253 )
254 ),
255 root_device_id=olt.id
256 )
257 self.adapter_agent.create_logical_device(ld)
258
259 cap = OFPPF_1GB_FD | OFPPF_FIBER
260 for port_no, name, device_id, device_port_no, root_port in [
261 (1, 'onu1', onu1.id, 2, False),
262 (2, 'onu2', onu2.id, 2, False),
263 (129, 'olt1', olt.id, 2, True)]:
264 port = LogicalPort(
265 id=name,
266 ofp_port=ofp_port(
267 port_no=port_no,
268 hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % port_no),
269 name=name,
270 config=0,
271 state=OFPPS_LIVE,
272 curr=cap,
273 advertised=cap,
274 peer=cap,
275 curr_speed=OFPPF_1GB_FD,
276 max_speed=OFPPF_1GB_FD
277 ),
278 device_id=device_id,
279 device_port_no=device_port_no,
280 root_port=root_port
281 )
282 self.adapter_agent.add_logical_port(ld.id, port)
283
Zsolt Haraszti8925d1f2016-12-21 00:45:19 -0800284 olt.parent_id = ld.id
285 self.adapter_agent.update_device(olt)
286
Zsolt Haraszti66862032016-11-28 14:28:39 -0800287 @inlineCallbacks
288 def _simulate_device_activation(self, device):
289
290 # first we pretend that we were able to contact the device and obtain
291 # additional information about it
292 device.root = True
293 device.vendor = 'simulated'
294 device.model = 'n/a'
295 device.hardware_version = 'n/a'
296 device.firmware_version = 'n/a'
297 device.software_version = '1.0'
298 device.serial_number = uuid4().hex
299 device.connect_status = ConnectStatus.REACHABLE
300 self.adapter_agent.update_device(device)
301
302 # then shortly after we create some ports for the device
303 yield asleep(0.05)
304 nni_port = Port(
305 port_no=2,
306 label='NNI facing Ethernet port',
307 type=Port.ETHERNET_NNI,
308 admin_state=AdminState.ENABLED,
309 oper_status=OperStatus.ACTIVE
310 )
311 self.adapter_agent.add_port(device.id, nni_port)
312 self.adapter_agent.add_port(device.id, Port(
313 port_no=1,
314 label='PON port',
315 type=Port.PON_OLT,
316 admin_state=AdminState.ENABLED,
317 oper_status=OperStatus.ACTIVE
318 ))
319
320 # then shortly after we create the logical device with one port
321 # that will correspond to the NNI port
322 yield asleep(0.05)
alshabib9fbb2232016-12-23 00:40:08 -0800323 logical_device_id = uuid4().hex[:12]
Zsolt Haraszti66862032016-11-28 14:28:39 -0800324 ld = LogicalDevice(
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800325 # not setting id and datapth_id will let the adapter agent pick id
Zsolt Haraszti66862032016-11-28 14:28:39 -0800326 desc=ofp_desc(
327 mfr_desc='cord porject',
328 hw_desc='simualted pon',
329 sw_desc='simualted pon',
330 serial_num=uuid4().hex,
331 dp_desc='n/a'
332 ),
333 switch_features=ofp_switch_features(
334 n_buffers=256, # TODO fake for now
335 n_tables=2, # TODO ditto
336 capabilities=( # TODO and ditto
337 OFPC_FLOW_STATS
338 | OFPC_TABLE_STATS
339 | OFPC_PORT_STATS
340 | OFPC_GROUP_STATS
341 )
342 ),
343 root_device_id=device.id
344 )
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800345 ld_initialized = self.adapter_agent.create_logical_device(ld)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800346 cap = OFPPF_1GB_FD | OFPPF_FIBER
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800347 self.adapter_agent.add_logical_port(ld_initialized.id, LogicalPort(
Zsolt Haraszti66862032016-11-28 14:28:39 -0800348 id='nni',
349 ofp_port=ofp_port(
350 port_no=129,
351 hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' % 129),
352 name='nni',
353 config=0,
354 state=OFPPS_LIVE,
355 curr=cap,
356 advertised=cap,
357 peer=cap,
358 curr_speed=OFPPF_1GB_FD,
359 max_speed=OFPPF_1GB_FD
360 ),
361 device_id=device.id,
362 device_port_no=nni_port.port_no,
363 root_port=True
364 ))
365
366 # and finally update to active
367 device = self.adapter_agent.get_device(device.id)
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800368 device.parent_id = ld_initialized.id
Zsolt Haraszti66862032016-11-28 14:28:39 -0800369 device.oper_status = OperStatus.ACTIVE
370 self.adapter_agent.update_device(device)
371
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800372 # reactor.callLater(0.1, self._simulate_detection_of_onus, device.id)
Zsolt Haraszti749b0952017-01-18 09:02:35 -0800373 self.start_kpi_collection(device.id)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800374
375 @inlineCallbacks
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800376 def _simulate_detection_of_onus(self, device_id):
Zsolt Haraszti66862032016-11-28 14:28:39 -0800377 for i in xrange(1, 5):
378 log.info('activate-olt-for-onu-{}'.format(i))
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800379 vlan_id = self._olt_side_onu_activation(i)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800380 yield asleep(0.05)
381 self.adapter_agent.child_device_detected(
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800382 parent_device_id=device_id,
Zsolt Haraszti66862032016-11-28 14:28:39 -0800383 parent_port_no=1,
384 child_device_type='simulated_onu',
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800385 proxy_address=Device.ProxyAddress(
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800386 device_id=device_id,
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800387 channel_id=vlan_id
388 ),
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800389 vlan=vlan_id
Zsolt Haraszti66862032016-11-28 14:28:39 -0800390 )
391
392 def _olt_side_onu_activation(self, seq):
393 """
394 This is where if this was a real OLT, the OLT-side activation for
395 the new ONU should be performed. By the time we return, the OLT shall
396 be able to provide tunneled (proxy) communication to the given ONU,
397 using the returned information.
398 """
Zsolt Haraszti66862032016-11-28 14:28:39 -0800399 vlan_id = seq + 100
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800400 return vlan_id
Zsolt Haraszti66862032016-11-28 14:28:39 -0800401
Zsolt Harasztic5c5d102016-12-07 21:12:27 -0800402 def update_flows_bulk(self, device, flows, groups):
403 log.debug('bulk-flow-update', device_id=device.id,
404 flows=flows, groups=groups)
405
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800406 # sample code that analyzes the incoming flow table
407 assert len(groups.items) == 0, "Cannot yet deal with groups"
408
409 for flow in flows.items:
410 in_port = get_in_port(flow)
411 assert in_port is not None
412
413 if in_port == 2:
414
415 # Downstream rule
416
417 for field in get_ofb_fields(flow):
418 if field.type == ETH_TYPE:
419 _type = field.eth_type
420 pass # construct ether type based condition here
421
422 elif field.type == IP_PROTO:
423 _proto = field.ip_proto
424 pass # construct ip_proto based condition here
425
426 elif field.type == IN_PORT:
427 _port = field.port
428 pass # construct in_port based condition here
429
430 elif field.type == VLAN_VID:
431 _vlan_vid = field.vlan_vid
432 pass # construct VLAN ID based filter condition here
433
434 elif field.type == VLAN_PCP:
435 _vlan_pcp = field.vlan_pcp
436 pass # construct VLAN PCP based filter condition here
437
Zsolt Haraszti6a5107c2017-01-09 23:42:41 -0800438 elif field.type == METADATA:
439 pass # safe to ignore
440
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800441 # TODO
442 else:
443 raise NotImplementedError('field.type={}'.format(
444 field.type))
445
446 for action in get_actions(flow):
447
448 if action.type == OUTPUT:
449 pass # construct packet emit rule here
450
451 elif action.type == PUSH_VLAN:
452 if action.push.ethertype != 0x8100:
453 log.error('unhandled-ether-type',
454 ethertype=action.push.ethertype)
455 pass # construct vlan push command here
456
457 elif action.type == POP_VLAN:
458 pass # construct vlan pop command here
459
460 elif action.type == SET_FIELD:
461 assert (action.set_field.field.oxm_class ==
462 ofp.OFPXMC_OPENFLOW_BASIC)
463 field = action.set_field.field.ofb_field
464 if field.type == VLAN_VID:
465 pass # construct vlan_id set command here
466 else:
467 log.error('unsupported-action-set-field-type',
468 field_type=field.type)
469
470 else:
471 log.error('unsupported-action-type',
472 action_type=action.type)
473
474 # final assembly of low level device flow rule and pushing it
475 # down to device
476 pass
477
478 elif in_port == 1:
479
480 # Upstream rule
481
482 for field in get_ofb_fields(flow):
483
484 if field.type == ETH_TYPE:
485 _type = field.eth_type
486 pass # construct ether type based condition here
487
488 elif field.type == IP_PROTO:
489 _proto = field.ip_proto
490 pass # construct ip_proto based condition here
491
492 elif field.type == IN_PORT:
493 _port = field.port
494 pass # construct in_port based condition here
495
496 elif field.type == VLAN_VID:
497 _vlan_vid = field.vlan_vid
498 pass # construct VLAN ID based filter condition here
499
500 elif field.type == VLAN_PCP:
501 _vlan_pcp = field.vlan_pcp
502 pass # construct VLAN PCP based filter condition here
503
Zsolt Haraszti3578a1c2017-01-10 15:29:02 -0800504 elif field.type == UDP_SRC:
505 _udp_src = field.udp_src
506 pass # construct UDP SRC based filter here
507
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800508 elif field.type == UDP_DST:
509 _udp_dst = field.udp_dst
Zsolt Haraszti3578a1c2017-01-10 15:29:02 -0800510 pass # construct UDP DST based filter here
Zsolt Haraszti85f12852016-12-24 08:30:58 -0800511
512 # TODO
513 else:
514 raise NotImplementedError('field.type={}'.format(
515 field.type))
516
517 for action in get_actions(flow):
518
519 if action.type == OUTPUT:
520 pass # construct packet emit rule here
521
522 elif action.type == PUSH_VLAN:
523 if action.push.ethertype != 0x8100:
524 log.error('unhandled-ether-type',
525 ethertype=action.push.ethertype)
526 pass # construct vlan push command here
527
528 elif action.type == SET_FIELD:
529 assert (action.set_field.field.oxm_class ==
530 ofp.OFPXMC_OPENFLOW_BASIC)
531 field = action.set_field.field.ofb_field
532 if field.type == VLAN_VID:
533 pass # construct vlan_id set command here
534 else:
535 log.error('unsupported-action-set-field-type',
536 field_type=field.type)
537
538 else:
539 log.error('unsupported-action-type',
540 action_type=action.type)
541
542 # final assembly of low level device flow rule and pushing it
543 # down to device
544 pass
545
546 else:
547 raise Exception('Port should be 1 or 2 by our convention')
548
549
Zsolt Harasztic5c5d102016-12-07 21:12:27 -0800550 def update_flows_incrementally(self, device, flow_changes, group_changes):
551 raise NotImplementedError()
552
553 def send_proxied_message(self, proxy_address, msg):
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800554 log.info('send-proxied-message', proxy_address=proxy_address, msg=msg)
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800555 # we mimic a response by sending the same message back in a short time
Zsolt Haraszti89a27302016-12-08 16:53:06 -0800556 reactor.callLater(
557 0.2,
558 self.adapter_agent.receive_proxied_message,
559 proxy_address,
560 msg
561 )
Zsolt Harasztic5c5d102016-12-07 21:12:27 -0800562
563 def receive_proxied_message(self, proxy_address, msg):
564 raise NotImplementedError()
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800565
Zsolt Haraszti656ecc62016-12-28 15:08:23 -0800566 def receive_packet_out(self, logical_device_id, egress_port_no, msg):
567 log.info('packet-out', logical_device_id=logical_device_id,
568 egress_port_no=egress_port_no, msg_len=len(msg))
569
Zsolt Haraszti749b0952017-01-18 09:02:35 -0800570 def start_kpi_collection(self, device_id):
Zsolt Harasztic5f740b2017-01-18 09:53:17 -0800571
Zsolt Haraszti749b0952017-01-18 09:02:35 -0800572 """Simulate periodic KPI metric collection from the device"""
573 import random
574
575 @inlineCallbacks # pretend that we need to do async calls
576 def _collect(device_id, prefix):
577
578 try:
579 # Step 1: gather metrics from device (pretend it here) - examples
Sergio Slobodrianf39aaf82017-02-28 16:10:16 -0500580 # upgraded the metrics to include packet statistics for
581 # testing.
Zsolt Haraszti749b0952017-01-18 09:02:35 -0800582 nni_port_metrics = yield dict(
Sergio Slobodrianf39aaf82017-02-28 16:10:16 -0500583 tx_pkts=self.nni_tx_pkts+random.randint(90, 100),
584 rx_pkts=self.nni_rx_pkts+random.randint(90, 100),
585 tx_bytes=self.nni_tx_bytes+random.randint(90000, 100000),
586 rx_bytes=self.nni_rx_bytes+random.randint(90000, 100000),
587 tx_64 = self.nni_tx_64 + random.randint(50,55),
588 tx_65_127 = self.nni_tx_65_127 + random.randint(55,60),
589 tx_128_255 = self.nni_tx_128_255 + random.randint(60,65),
590 tx_256_511 = self.nni_tx_256_511 + random.randint(85,90),
591 tx_512_1023 = self.nni_tx_512_1023 + random.randint(90,95),
592 tx_1024_1518 = self.nni_tx_1024_1518 + random.randint(60,65),
593 tx_1519_9k = self.nni_tx_1519_9k + random.randint(50,55),
594
595 rx_64 = self.nni_tx_64 + random.randint(50,55),
596 rx_65_127 = self.nni_tx_65_127 + random.randint(55,60),
597 rx_128_255 = self.nni_tx_128_255 + random.randint(60,65),
598 rx_256_511 = self.nni_tx_256_511 + random.randint(85,90),
599 rx_512_1023 = self.nni_tx_512_1023 + random.randint(90,95),
600 rx_1024_1518 = self.nni_tx_1024_1518 + random.randint(60,65),
601 rx_1519_9k = self.nni_tx_1519_9k + random.randint(50,55)
Zsolt Haraszti749b0952017-01-18 09:02:35 -0800602 )
603 pon_port_metrics = yield dict(
Sergio Slobodrianf39aaf82017-02-28 16:10:16 -0500604 tx_pkts=self.pon_tx_pkts+random.randint(90, 100),
605 rx_pkts=self.pon_rx_pkts+random.randint(90, 100),
606 tx_bytes=self.pon_tx_bytes+random.randint(90000, 100000),
607 rx_bytes=self.pon_rx_bytes+random.randint(90000, 100000),
608 tx_64 = self.pon_tx_64 + random.randint(50,55),
609 tx_65_127 = self.pon_tx_65_127 + random.randint(55,60),
610 tx_128_255 = self.pon_tx_128_255 + random.randint(60,65),
611 tx_256_511 = self.pon_tx_256_511 + random.randint(85,90),
612 tx_512_1023 = self.pon_tx_512_1023 + random.randint(90,95),
613 tx_1024_1518 = self.pon_tx_1024_1518 + random.randint(60,65),
614 tx_1519_9k = self.pon_tx_1519_9k + random.randint(50,55),
615
616 rx_64 = self.pon_tx_64 + random.randint(50,55),
617 rx_65_127 = self.pon_tx_65_127 + random.randint(55,60),
618 rx_128_255 = self.pon_tx_128_255 + random.randint(60,65),
619 rx_256_511 = self.pon_tx_256_511 + random.randint(85,90),
620 rx_512_1023 = self.pon_tx_512_1023 + random.randint(90,95),
621 rx_1024_1518 = self.pon_tx_1024_1518 + random.randint(60,65),
622 rx_1519_9k = self.pon_tx_1519_9k + random.randint(50,55)
Zsolt Haraszti749b0952017-01-18 09:02:35 -0800623 )
Sergio Slobodrianf39aaf82017-02-28 16:10:16 -0500624 self.pon_tx_pkts = pon_port_metrics['tx_pkts']
625 self.pon_rx_pkts = pon_port_metrics['rx_pkts']
626 self.pon_tx_bytes = pon_port_metrics['tx_bytes']
627 self.pon_rx_bytes = pon_port_metrics['rx_bytes']
628
629 self.pon_tx_64 = pon_port_metrics['tx_64']
630 self.pon_tx_65_127 = pon_port_metrics['tx_65_127']
631 self.pon_tx_128_255 = pon_port_metrics['tx_128_255']
632 self.pon_tx_256_511 = pon_port_metrics['tx_256_511']
633 self.pon_tx_512_1023 = pon_port_metrics['tx_512_1023']
634 self.pon_tx_1024_1518 = pon_port_metrics['tx_1024_1518']
635 self.pon_tx_1519_9k = pon_port_metrics['tx_1519_9k']
636
637 self.pon_rx_64 = pon_port_metrics['rx_64']
638 self.pon_rx_65_127 = pon_port_metrics['rx_65_127']
639 self.pon_rx_128_255 = pon_port_metrics['rx_128_255']
640 self.pon_rx_256_511 = pon_port_metrics['rx_256_511']
641 self.pon_rx_512_1023 = pon_port_metrics['rx_512_1023']
642 self.pon_rx_1024_1518 = pon_port_metrics['rx_1024_1518']
643 self.pon_rx_1519_9k = pon_port_metrics['rx_1519_9k']
644
645 self.nni_tx_pkts = nni_port_metrics['tx_pkts']
646 self.nni_rx_pkts = nni_port_metrics['rx_pkts']
647 self.nni_tx_bytes = nni_port_metrics['tx_bytes']
648 self.nni_rx_bytes = nni_port_metrics['rx_bytes']
649
650 self.nni_tx_64 = nni_port_metrics['tx_64']
651 self.nni_tx_65_127 = nni_port_metrics['tx_65_127']
652 self.nni_tx_128_255 = nni_port_metrics['tx_128_255']
653 self.nni_tx_256_511 = nni_port_metrics['tx_256_511']
654 self.nni_tx_512_1023 = nni_port_metrics['tx_512_1023']
655 self.nni_tx_1024_1518 = nni_port_metrics['tx_1024_1518']
656 self.nni_tx_1519_9k = nni_port_metrics['tx_1519_9k']
657
658 self.nni_rx_64 = nni_port_metrics['rx_64']
659 self.nni_rx_65_127 = nni_port_metrics['rx_65_127']
660 self.nni_rx_128_255 = nni_port_metrics['rx_128_255']
661 self.nni_rx_256_511 = nni_port_metrics['rx_256_511']
662 self.nni_rx_512_1023 = nni_port_metrics['rx_512_1023']
663 self.nni_rx_1024_1518 = nni_port_metrics['rx_1024_1518']
664 self.nni_rx_1519_9k = nni_port_metrics['rx_1519_9k']
665
Zsolt Haraszti749b0952017-01-18 09:02:35 -0800666 olt_metrics = yield dict(
667 cpu_util=20 + 5 * random.random(),
668 buffer_util=10 + 10 * random.random()
669 )
670
671 # Step 2: prepare the KpiEvent for submission
672 # we can time-stamp them here (or could use time derived from OLT
673 ts = arrow.utcnow().timestamp
674 kpi_event = KpiEvent(
675 type=KpiEventType.slice,
676 ts=ts,
677 prefixes={
678 # OLT-level
679 prefix: MetricValuePairs(metrics=olt_metrics),
680 # OLT NNI port
681 prefix + '.nni': MetricValuePairs(metrics=nni_port_metrics),
682 # OLT PON port
683 prefix + '.pon': MetricValuePairs(metrics=pon_port_metrics)
684 }
685 )
686
687 # Step 3: submit
688 self.adapter_agent.submit_kpis(kpi_event)
689
690 except Exception as e:
691 log.exception('failed-to-submit-kpis', e=e)
692
693 prefix = 'voltha.{}.{}'.format(self.name, device_id)
694 lc = LoopingCall(_collect, device_id, prefix)
695 lc.start(interval=15) # TODO make this configurable
696
697
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800698 # ~~~~~~~~~~~~~~~~~~~~ Embedded test Klein rest server ~~~~~~~~~~~~~~~~~~~~
699
Zsolt Haraszti8925d1f2016-12-21 00:45:19 -0800700 def get_test_control_site(self):
701 return Site(self.app.resource())
702
703 @app.route('/devices/<string:device_id>/detect_onus')
704 def detect_onus(self, request, device_id):
705 log.info('detect-onus', request=request, device_id=device_id)
Zsolt Haraszti217a12e2016-12-19 16:37:55 -0800706 self._simulate_detection_of_onus(device_id)
707 return '{"status": "OK"}'
708
Zsolt Haraszti8925d1f2016-12-21 00:45:19 -0800709 @app.route('/devices/<string:device_id>/test_eapol_in')
710 def test_eapol_in(self, request, device_id):
711 """Simulate a packet in message posted upstream"""
712 log.info('test_eapol_in', request=request, device_id=device_id)
713 eapol_start = str(
Zsolt Harasztid036b7e2016-12-23 15:36:01 -0800714 Ether(src='00:11:22:33:44:55') /
715 EAPOL(type=1, len=0) /
716 Padding(load=42*'\x00')
Zsolt Haraszti8925d1f2016-12-21 00:45:19 -0800717 )
Zsolt Haraszti8925d1f2016-12-21 00:45:19 -0800718 device = self.adapter_agent.get_device(device_id)
719 self.adapter_agent.send_packet_in(logical_device_id=device.parent_id,
720 logical_port_no=1,
721 packet=eapol_start)
722 return '{"status": "sent"}'