2 # Copyright 2016 Cisco Systems, Inc. All rights reserved.
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may
5 # not use this file except in compliance with the License. You may obtain
6 # a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations
17 from attrdict import AttrDict
18 from nfvbench.config import get_err_config
19 from nfvbench.connection import SSH
20 from nfvbench.credentials import Credentials
21 from nfvbench.network import Interface
22 from nfvbench.network import Network
23 from nfvbench.specs import Encaps
24 import nfvbench.traffic_gen.traffic_utils as traffic_utils
28 __location__ = os.path.realpath(os.path.join(os.getcwd(),
29 os.path.dirname(__file__)))
34 def mock_init(self, ssh_access, *args, **kwargs):
35 self.ssh_access = ssh_access
36 if ssh_access.private_key:
37 self.pkey = self._get_pkey(ssh_access.private_key)
41 self.connect_timeout = 2
42 self.connect_retry_count = 1
43 self.connect_retry_wait_sec = 1
44 super(SSH, self).__init__()
46 monkeypatch.setattr(SSH, '__init__', mock_init)
50 def openstack_vxlan_spec():
53 'openstack': AttrDict({
55 'encaps': Encaps.VxLAN}
57 'run_spec': AttrDict({
63 # =========================================================================
65 # =========================================================================
67 def test_chain_interface():
68 iface = Interface('testname', 'vpp', tx_packets=1234, rx_packets=4321)
69 assert iface.name == 'testname'
70 assert iface.device == 'vpp'
71 assert iface.get_packet_count('tx') == 1234
72 assert iface.get_packet_count('rx') == 4321
73 assert iface.get_packet_count('wrong_key') == 0
76 @pytest.fixture(scope='session')
78 return Interface('iface1', 'trex', tx_packets=10000, rx_packets=1234)
81 @pytest.fixture(scope='session')
83 return Interface('iface2', 'n9k', tx_packets=1234, rx_packets=9901)
86 @pytest.fixture(scope='session')
88 return Interface('iface3', 'n9k', tx_packets=9900, rx_packets=1234)
91 @pytest.fixture(scope='session')
93 return Interface('iface4', 'vpp', tx_packets=1234, rx_packets=9801)
96 @pytest.fixture(scope='session')
97 def net1(iface1, iface2, iface3, iface4):
98 return Network([iface1, iface2, iface3, iface4], reverse=False)
101 @pytest.fixture(scope='session')
102 def net2(iface1, iface2, iface3):
103 return Network([iface1, iface2, iface3], reverse=True)
106 def test_chain_network(net1, net2, iface1, iface2, iface3, iface4):
107 assert [iface1, iface2, iface3, iface4] == net1.get_interfaces()
108 assert [iface3, iface2, iface1] == net2.get_interfaces()
109 net2.add_interface(iface4)
110 assert [iface4, iface3, iface2, iface1] == net2.get_interfaces()
114 def test_chain_analysis(net1, monkeypatch, openstack_vxlan_spec):
115 def mock_empty(self, *args, **kwargs):
118 monkeypatch.setattr(ServiceChain, '_setup', mock_empty)
120 f = ServiceChain(AttrDict({'service_chain': 'DUMMY'}), [], {'tor': {}}, openstack_vxlan_spec,
121 lambda x, y, z: None)
122 result = f.get_analysis([net1])
123 assert result[1]['packet_drop_count'] == 99
124 assert result[1]['packet_drop_percentage'] == 0.99
125 assert result[2]['packet_drop_count'] == 1
126 assert result[2]['packet_drop_percentage'] == 0.01
127 assert result[3]['packet_drop_count'] == 99
128 assert result[3]['packet_drop_percentage'] == 0.99
131 result = f.get_analysis([net1])
132 assert result[1]['packet_drop_count'] == 0
133 assert result[1]['packet_drop_percentage'] == 0.0
134 assert result[2]['packet_drop_count'] == 0
135 assert result[2]['packet_drop_percentage'] == 0.0
136 assert result[3]['packet_drop_count'] == 0
137 assert result[3]['packet_drop_percentage'] == 0.0
141 def pvp_chain(monkeypatch, openstack_vxlan_spec):
142 tor_vni1 = Interface('vni-4097', 'n9k', 50, 77)
143 vsw_vni1 = Interface('vxlan_tunnel0', 'vpp', 77, 48)
144 vsw_vif1 = Interface('VirtualEthernet0/0/2', 'vpp', 48, 77)
145 vsw_vif2 = Interface('VirtualEthernet0/0/3', 'vpp', 77, 47)
146 vsw_vni2 = Interface('vxlan_tunnel1', 'vpp', 43, 77)
147 tor_vni2 = Interface('vni-4098', 'n9k', 77, 40)
149 def mock_init(self, *args, **kwargs):
150 self.vni_ports = [4097, 4098]
151 self.specs = openstack_vxlan_spec
154 'set_interface_counters': lambda: None,
157 self.worker = AttrDict({
161 def mock_empty(self, *args, **kwargs):
164 def mock_get_network(self, traffic_port, vni_id, reverse=False):
166 return Network([tor_vni1, vsw_vni1, vsw_vif1], reverse)
168 return Network([tor_vni2, vsw_vni2, vsw_vif2], reverse)
170 def mock_get_data(self):
173 monkeypatch.setattr(PVPChain, '_get_network', mock_get_network)
174 monkeypatch.setattr(PVPChain, '_get_data', mock_get_data)
175 monkeypatch.setattr(PVPChain, '_setup', mock_empty)
176 monkeypatch.setattr(VxLANWorker, '_clear_interfaces', mock_empty)
177 monkeypatch.setattr(PVPChain, '_generate_traffic', mock_empty)
178 monkeypatch.setattr(PVPChain, '__init__', mock_init)
179 return PVPChain(None, None, {'vm': None, 'vpp': None, 'tor': None, 'traffic': None}, None)
182 def test_pvp_chain_run(pvp_chain):
183 result = pvp_chain.run()
188 'direction-forward': [
190 ('interface', 'vni-4097'),
195 ('interface', 'vxlan_tunnel0'),
197 ('packet_count', 48),
198 ('packet_drop_count', 2),
199 ('packet_drop_percentage', 4.0)
202 ('interface', 'VirtualEthernet0/0/2'),
204 ('packet_count', 48),
205 ('packet_drop_count', 0),
206 ('packet_drop_percentage', 0.0)
209 ('interface', 'VirtualEthernet0/0/3'),
211 ('packet_count', 47),
212 ('packet_drop_count', 1),
213 ('packet_drop_percentage', 2.0)
216 ('interface', 'vxlan_tunnel1'),
218 ('packet_count', 43),
219 ('packet_drop_count', 4),
220 ('packet_drop_percentage', 8.0)
223 ('interface', 'vni-4098'),
225 ('packet_count', 40),
226 ('packet_drop_count', 3),
227 ('packet_drop_percentage', 6.0)
230 'direction-reverse': [
232 ('interface', 'vni-4098'),
237 ('interface', 'vxlan_tunnel1'),
239 ('packet_count', 77),
240 ('packet_drop_count', 0),
241 ('packet_drop_percentage', 0.0)
244 ('interface', 'VirtualEthernet0/0/3'),
246 ('packet_count', 77),
247 ('packet_drop_count', 0),
248 ('packet_drop_percentage', 0.0)
251 ('interface', 'VirtualEthernet0/0/2'),
253 ('packet_count', 77),
254 ('packet_drop_count', 0),
255 ('packet_drop_percentage', 0.0)
258 ('interface', 'vxlan_tunnel0'),
260 ('packet_count', 77),
261 ('packet_drop_count', 0),
262 ('packet_drop_percentage', 0.0)
265 ('interface', 'vni-4097'),
267 ('packet_count', 77),
268 ('packet_drop_count', 0),
269 ('packet_drop_percentage', 0.0)
274 assert result == expected_result
278 # =========================================================================
280 # =========================================================================
284 def pvvp_chain(monkeypatch, openstack_vxlan_spec):
285 tor_vni1 = Interface('vni-4097', 'n9k', 50, 77)
286 vsw_vni1 = Interface('vxlan_tunnel0', 'vpp', 77, 48)
287 vsw_vif1 = Interface('VirtualEthernet0/0/2', 'vpp', 48, 77)
288 vsw_vif3 = Interface('VirtualEthernet0/0/0', 'vpp', 77, 47)
289 vsw_vif4 = Interface('VirtualEthernet0/0/1', 'vpp', 45, 77)
290 vsw_vif2 = Interface('VirtualEthernet0/0/3', 'vpp', 77, 44)
291 vsw_vni2 = Interface('vxlan_tunnel1', 'vpp', 43, 77)
292 tor_vni2 = Interface('vni-4098', 'n9k', 77, 40)
294 def mock_init(self, *args, **kwargs):
295 self.vni_ports = [4099, 4100]
296 self.v2vnet = V2VNetwork()
297 self.specs = openstack_vxlan_spec
300 'get_v2v_network': lambda reverse=None: Network([vsw_vif3, vsw_vif4], reverse),
301 'set_interface_counters': lambda pvvp=None: None,
302 'set_v2v_counters': lambda: None,
305 self.worker = AttrDict({
309 def mock_empty(self, *args, **kwargs):
312 def mock_get_network(self, traffic_port, vni_id, reverse=False):
314 return Network([tor_vni1, vsw_vni1, vsw_vif1], reverse)
316 return Network([tor_vni2, vsw_vni2, vsw_vif2], reverse)
318 def mock_get_data(self):
321 monkeypatch.setattr(PVVPChain, '_get_network', mock_get_network)
322 monkeypatch.setattr(PVVPChain, '_get_data', mock_get_data)
323 monkeypatch.setattr(PVVPChain, '_setup', mock_empty)
324 monkeypatch.setattr(VxLANWorker, '_clear_interfaces', mock_empty)
325 monkeypatch.setattr(PVVPChain, '_generate_traffic', mock_empty)
326 monkeypatch.setattr(PVVPChain, '__init__', mock_init)
328 return PVVPChain(None, None, {'vm': None, 'vpp': None, 'tor': None, 'traffic': None}, None)
331 def test_pvvp_chain_run(pvvp_chain):
332 result = pvvp_chain.run()
338 {'direction-forward': [
340 ('interface', 'vni-4097'),
345 ('interface', 'vxlan_tunnel0'),
347 ('packet_count', 48),
348 ('packet_drop_count', 2),
349 ('packet_drop_percentage', 4.0)
352 ('interface', 'VirtualEthernet0/0/2'),
354 ('packet_count', 48),
355 ('packet_drop_count', 0),
356 ('packet_drop_percentage', 0.0)
359 ('interface', 'VirtualEthernet0/0/0'),
361 ('packet_count', 47),
362 ('packet_drop_count', 1),
363 ('packet_drop_percentage', 2.0)
366 ('interface', 'VirtualEthernet0/0/1'),
368 ('packet_count', 45),
369 ('packet_drop_count', 2),
370 ('packet_drop_percentage', 4.0)
373 ('interface', 'VirtualEthernet0/0/3'),
375 ('packet_count', 44),
376 ('packet_drop_count', 1),
377 ('packet_drop_percentage', 2.0)
380 ('interface', 'vxlan_tunnel1'),
382 ('packet_count', 43),
383 ('packet_drop_count', 1),
384 ('packet_drop_percentage', 2.0)
387 ('interface', 'vni-4098'),
389 ('packet_count', 40),
390 ('packet_drop_count', 3),
391 ('packet_drop_percentage', 6.0)
394 'direction-reverse': [
396 ('interface', 'vni-4098'),
401 ('interface', 'vxlan_tunnel1'),
403 ('packet_count', 77),
404 ('packet_drop_count', 0),
405 ('packet_drop_percentage', 0.0)
408 ('interface', 'VirtualEthernet0/0/3'),
410 ('packet_count', 77),
411 ('packet_drop_count', 0),
412 ('packet_drop_percentage', 0.0)
415 ('interface', 'VirtualEthernet0/0/1'),
417 ('packet_count', 77),
418 ('packet_drop_count', 0),
419 ('packet_drop_percentage', 0.0)
422 ('interface', 'VirtualEthernet0/0/0'),
424 ('packet_count', 77),
425 ('packet_drop_count', 0),
426 ('packet_drop_percentage', 0.0)
429 ('interface', 'VirtualEthernet0/0/2'),
431 ('packet_count', 77),
432 ('packet_drop_count', 0),
433 ('packet_drop_percentage', 0.0)
436 ('interface', 'vxlan_tunnel0'),
438 ('packet_count', 77),
439 ('packet_drop_count', 0),
440 ('packet_drop_percentage', 0.0)
443 ('interface', 'vni-4097'),
445 ('packet_count', 77),
446 ('packet_drop_count', 0),
447 ('packet_drop_percentage', 0.0)
451 assert result == expected_result
454 # =========================================================================
455 # Traffic client tests
456 # =========================================================================
458 def test_parse_rate_str():
459 parse_rate_str = traffic_utils.parse_rate_str
461 assert parse_rate_str('100%') == {'rate_percent': '100.0'}
462 assert parse_rate_str('37.5%') == {'rate_percent': '37.5'}
463 assert parse_rate_str('100%') == {'rate_percent': '100.0'}
464 assert parse_rate_str('60pps') == {'rate_pps': '60'}
465 assert parse_rate_str('60kpps') == {'rate_pps': '60000'}
466 assert parse_rate_str('6Mpps') == {'rate_pps': '6000000'}
467 assert parse_rate_str('6gpps') == {'rate_pps': '6000000000'}
468 assert parse_rate_str('80bps') == {'rate_bps': '80'}
469 assert parse_rate_str('80bps') == {'rate_bps': '80'}
470 assert parse_rate_str('80kbps') == {'rate_bps': '80000'}
471 assert parse_rate_str('80kBps') == {'rate_bps': '640000'}
472 assert parse_rate_str('80Mbps') == {'rate_bps': '80000000'}
473 assert parse_rate_str('80 MBps') == {'rate_bps': '640000000'}
474 assert parse_rate_str('80Gbps') == {'rate_bps': '80000000000'}
475 except Exception as exc:
476 assert False, exc.message
478 def should_raise_error(str):
486 assert should_raise_error('101')
487 assert should_raise_error('201%')
488 assert should_raise_error('10Kbps')
489 assert should_raise_error('0kbps')
490 assert should_raise_error('0pps')
491 assert should_raise_error('-1bps')
493 def test_rate_conversion():
494 assert traffic_utils.load_to_bps(50, 10000000000) == pytest.approx(5000000000.0)
495 assert traffic_utils.load_to_bps(37, 10000000000) == pytest.approx(3700000000.0)
496 assert traffic_utils.load_to_bps(100, 10000000000) == pytest.approx(10000000000.0)
498 assert traffic_utils.bps_to_load(5000000000.0, 10000000000) == pytest.approx(50.0)
499 assert traffic_utils.bps_to_load(3700000000.0, 10000000000) == pytest.approx(37.0)
500 assert traffic_utils.bps_to_load(10000000000.0, 10000000000) == pytest.approx(100.0)
502 assert traffic_utils.bps_to_pps(500000, 64) == pytest.approx(744.047619048)
503 assert traffic_utils.bps_to_pps(388888, 1518) == pytest.approx(31.6066319896)
504 assert traffic_utils.bps_to_pps(9298322222, 340.3) == pytest.approx(3225895.85831)
506 assert traffic_utils.pps_to_bps(744.047619048, 64) == pytest.approx(500000)
507 assert traffic_utils.pps_to_bps(31.6066319896, 1518) == pytest.approx(388888)
508 assert traffic_utils.pps_to_bps(3225895.85831, 340.3) == pytest.approx(9298322222)
513 def traffic_client(monkeypatch):
515 def mock_init(self, *args, **kwargs):
517 'bidirectional': False,
518 'l2frame_size': '64',
520 'rates': [{'rate_percent': '10'}, {'rate_pps': '1'}]
523 self.config = AttrDict({
524 'generator_config': {
525 'intf_speed': 10000000000
538 self.runner = AttrDict({
539 'time_elapsed': lambda: 30,
540 'stop': lambda: None,
541 'client': AttrDict({'get_stats': lambda: None})
544 self.current_load = None
551 14.0625: 2.47154392563,
552 13.28125: 0.000663797066801,
555 13.18359375: 0.00359387347122,
556 13.671875: 0.307939922531,
557 13.4765625: 0.0207718516156,
558 13.57421875: 0.0661795060969
561 def mock_modify_load(self, load):
562 self.run_config['rates'][0] = {'rate_percent': str(load)}
563 self.current_load = load
565 def mock_run_traffic(self):
568 'drop_rate_percent': self.dummy_stats[self.current_load],
571 'avg_delay_usec': 0.0,
572 'max_delay_usec': 0.0,
573 'min_delay_usec': 0.0
578 monkeypatch.setattr(TrafficClient, '__init__', mock_init)
579 monkeypatch.setattr(TrafficClient, 'modify_load', mock_modify_load)
580 monkeypatch.setattr(TrafficClient, 'run_traffic', mock_run_traffic)
582 return TrafficClient()
585 def test_ndr_pdr_search(traffic_client):
588 'l2frame_size': '64',
589 'initial_rate_type': 'rate_percent',
592 'drop_rate_percent': 0.0661795060969,
593 'min_delay_usec': 0.0,
594 'avg_delay_usec': 0.0,
595 'max_delay_usec': 0.0
598 'load_percent_per_direction': 13.57421875,
599 'rate_percent': 13.57422547,
600 'rate_bps': 1357422547.0,
601 'rate_pps': 2019974.0282738095,
605 'l2frame_size': '64',
606 'initial_rate_type': 'rate_percent',
609 'drop_rate_percent': 0.0,
610 'min_delay_usec': 0.0,
611 'avg_delay_usec': 0.0,
612 'max_delay_usec': 0.0
615 'load_percent_per_direction': 13.0859375,
616 'rate_percent': 13.08594422,
617 'rate_bps': 1308594422.0,
618 'rate_pps': 1947313.1279761905,
623 results = traffic_client.get_ndr_and_pdr()
624 assert len(results) == 2
625 for result in results.values():
626 result.pop('timestamp_sec')
627 result.pop('time_taken_sec')
628 assert results == expected_results
631 # =========================================================================
633 # =========================================================================
635 def test_no_credentials():
636 cred = Credentials('/completely/wrong/path/openrc', None, False)
638 # shouldn't get valid data unless user set environment variables
644 refcfg = {1: 100, 2: {21: 100, 22: 200}, 3: None}
645 assert(get_err_config({}, refcfg) is None)
646 assert(get_err_config({1: 10}, refcfg) is None)
647 assert(get_err_config({2: {21: 1000}}, refcfg) is None)
648 assert(get_err_config({3: "abc"}, refcfg) is None)
650 assert(get_err_config({4: 0}, refcfg) == {4: 0})
651 assert(get_err_config({2: {21: 100, 30: 50}}, refcfg) == {2: {30: 50}})
652 assert(get_err_config({2: {0: 1, 1: 2}}, refcfg) == {2: {0: 1, 1: 2}})
653 assert(get_err_config({2: {0: 1, 1: 2}, 5: 5}, refcfg) == {2: {0: 1, 1: 2}, 5: 5})
655 assert(get_err_config({1: 'abc', 2: {21: 0}}, refcfg) == {1: 'abc'})
656 assert(get_err_config({2: 100}, refcfg) == {2: 100})
657 # both correctly fail and invalid value type
658 assert(get_err_config({2: 100, 5: 10}, refcfg) == {2: 100, 5: 10})