1 # Copyright (c) 2016-2017 Intel Corporation
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 from multiprocessing import Process, Queue
21 from yardstick.benchmark.contexts import base as ctx_base
22 from yardstick.network_services.nfvi.resource import ResourceProfile
23 from yardstick.network_services.vnf_generic.vnf import base as vnf_base
24 from yardstick.network_services.vnf_generic.vnf import sample_vnf
25 from yardstick.network_services.vnf_generic.vnf import vpe_vnf
26 from yardstick.tests.unit.network_services.vnf_generic.vnf import test_base
29 TEST_FILE_YAML = 'nsb_test_case.yaml'
33 PING_OUTPUT_1 = "Pkts in: 101\r\n\tPkts dropped by AH: 100\r\n\tPkts dropped by other: 100"
35 MODULE_PATH = test_base.FileAbsPath(__file__)
36 get_file_abspath = MODULE_PATH.get_path
39 class TestConfigCreate(unittest.TestCase):
42 'short-name': 'VpeVnf',
47 'network': '152.16.100.20',
48 'netmask': '255.255.255.0',
49 'gateway': '152.16.100.20',
53 'network': '152.16.40.20',
54 'netmask': '255.255.255.0',
55 'gateway': '152.16.40.20',
59 'description': 'VPE approximation using DPDK',
60 'name': 'vpevnf-baremetal',
63 'network': '0064:ff9b:0:0:0:0:9810:6414',
65 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
69 'network': '0064:ff9b:0:0:0:0:9810:2814',
71 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
75 'id': 'vpevnf-baremetal',
76 'external-interface': [
78 'virtual-interface': {
79 'dst_mac': '00:00:00:00:00:03',
80 'vpci': '0000:05:00.0',
81 'local_ip': '152.16.100.19',
82 'type': 'PCI-PASSTHROUGH',
83 'netmask': '255.255.255.0',
85 'bandwidth': '10 Gbps',
86 'dst_ip': '152.16.100.20',
87 'local_mac': '00:00:00:00:00:01',
91 'vnfd-connection-point-ref': 'xe0',
95 'virtual-interface': {
96 'dst_mac': '00:00:00:00:00:04',
97 'vpci': '0000:05:00.1',
98 'local_ip': '152.16.40.19',
99 'type': 'PCI-PASSTHROUGH',
100 'netmask': '255.255.255.0',
102 'bandwidth': '10 Gbps',
103 'dst_ip': '152.16.40.20',
104 'local_mac': '00:00:00:00:00:02',
105 'vld_id': 'downlink_0',
108 'vnfd-connection-point-ref': 'xe1',
114 'description': 'Vpe approximation using DPDK',
116 'vdu-id': 'vpevnf-baremetal',
129 'connection-point': [
139 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'
142 def test___init__(self):
143 vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0)
144 config_create = vpe_vnf.ConfigCreate(vnfd_helper, 2)
145 self.assertEqual(config_create.uplink_ports, ['xe0'])
146 self.assertEqual(config_create.downlink_ports, ['xe1'])
147 self.assertEqual(config_create.socket, 2)
149 def test_generate_vpe_script(self):
150 vnfd_helper = vnf_base.VnfdHelper(self.VNFD_0)
151 vpe_config_vnf = vpe_vnf.ConfigCreate(vnfd_helper, 2)
155 "virtual-interface": {
157 "dst_mac": "00:00:00:00:00:00:02",
162 "virtual-interface": {
164 "dst_mac": "00:00:00:00:00:00:02",
168 vpe_config_vnf.downlink_ports = ['xe1']
169 vpe_config_vnf.uplink_ports = ['xe2']
170 result = vpe_config_vnf.generate_vpe_script(intf)
171 self.assertIsInstance(result, str)
172 self.assertNotEqual(result, '')
175 class TestVpeApproxVnf(unittest.TestCase):
178 'short-name': 'VpeVnf',
183 'network': '152.16.100.20',
184 'netmask': '255.255.255.0',
185 'gateway': '152.16.100.20',
189 'network': '152.16.40.20',
190 'netmask': '255.255.255.0',
191 'gateway': '152.16.40.20',
195 'description': 'VPE approximation using DPDK',
196 'name': 'vpevnf-baremetal',
199 'network': '0064:ff9b:0:0:0:0:9810:6414',
201 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
205 'network': '0064:ff9b:0:0:0:0:9810:2814',
207 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
211 'id': 'vpevnf-baremetal',
212 'external-interface': [
214 'virtual-interface': {
215 'dst_mac': '00:00:00:00:00:04',
216 'vpci': '0000:05:00.0',
217 'local_ip': '152.16.100.19',
218 'type': 'PCI-PASSTHROUGH',
219 'netmask': '255.255.255.0',
221 'bandwidth': '10 Gbps',
223 'dst_ip': '152.16.100.20',
224 'local_iface_name': 'xe0',
225 'local_mac': '00:00:00:00:00:02',
226 'vld_id': 'uplink_0',
229 'vnfd-connection-point-ref': 'xe0',
233 'virtual-interface': {
234 'dst_mac': '00:00:00:00:00:03',
235 'vpci': '0000:05:00.1',
236 'local_ip': '152.16.40.19',
237 'type': 'PCI-PASSTHROUGH',
239 'netmask': '255.255.255.0',
241 'bandwidth': '10 Gbps',
242 'dst_ip': '152.16.40.20',
243 'local_iface_name': 'xe1',
244 'local_mac': '00:00:00:00:00:01',
245 'vld_id': 'downlink_0',
248 'vnfd-connection-point-ref': 'xe1',
254 'description': 'Vpe approximation using DPDK',
256 'vdu-id': 'vpevnf-baremetal',
269 'connection-point': [
279 'id': 'VpeApproxVnf',
284 'vnfd:vnfd-catalog': {
296 'allowed_drop_rate': '0.8 - 1',
299 'cfg': 'acl_1rule.yaml',
309 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
310 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
312 'object': 'NetworkServiceTestCase',
314 'output_filename': '/tmp/yardstick.out',
319 'traffic_profile': 'ipv4_throughput_vpe.yaml',
321 'flow': 'ipv4_Packets_vpe.yaml',
322 'imix': 'imix_voice.yaml',
326 'tg__2': 'trafficgen_2.yardstick',
327 'tg__1': 'trafficgen_1.yardstick',
328 'vnf__1': 'vnf.yardstick',
330 'topology': 'vpe-tg-topology-baremetal.yaml',
336 'member-vnf-index': '3',
337 'role': 'TrafficGen',
338 'name': 'trafficgen_2.yardstick',
339 'vnfd-id-ref': 'tg__2',
343 'local_iface_name': 'ens513f0',
344 'vld_id': vpe_vnf.VpeApproxVnf.DOWNLINK,
345 'netmask': '255.255.255.0',
346 'local_ip': '152.16.40.20',
347 'dst_mac': '00:00:00:00:00:01',
348 'local_mac': '00:00:00:00:00:03',
349 'dst_ip': '152.16.40.19',
351 'vpci': '0000:02:00.0',
355 'local_iface_name': 'ens513f1',
356 'netmask': '255.255.255.0',
357 'network': '202.16.100.0',
358 'local_ip': '202.16.100.20',
359 'local_mac': '00:1e:67:d0:60:5d',
361 'vpci': '0000:02:00.1',
366 'VNF model': 'l3fwd_vnf.yaml',
370 'member-vnf-index': '1',
371 'role': 'TrafficGen',
372 'name': 'trafficgen_1.yardstick',
373 'vnfd-id-ref': 'tg__1',
377 'local_iface_name': 'ens785f0',
378 'vld_id': vpe_vnf.VpeApproxVnf.UPLINK,
379 'netmask': '255.255.255.0',
380 'local_ip': '152.16.100.20',
381 'dst_mac': '00:00:00:00:00:02',
382 'local_mac': '00:00:00:00:00:04',
383 'dst_ip': '152.16.100.19',
385 'vpci': '0000:05:00.0',
389 'local_iface_name': 'ens785f1',
390 'netmask': '255.255.255.0',
391 'local_ip': '152.16.100.21',
392 'local_mac': '00:00:00:00:00:01',
394 'vpci': '0000:05:00.1',
399 'VNF model': 'tg_rfc2544_tpl.yaml',
403 'name': 'vnf.yardstick',
404 'vnfd-id-ref': 'vnf__1',
408 'local_iface_name': 'ens786f0',
409 'vld_id': vpe_vnf.VpeApproxVnf.UPLINK,
410 'netmask': '255.255.255.0',
411 'local_ip': '152.16.100.19',
412 'dst_mac': '00:00:00:00:00:04',
413 'local_mac': '00:00:00:00:00:02',
414 'dst_ip': '152.16.100.20',
416 'vpci': '0000:05:00.0',
420 'local_iface_name': 'ens786f1',
421 'vld_id': vpe_vnf.VpeApproxVnf.DOWNLINK,
422 'netmask': '255.255.255.0',
423 'local_ip': '152.16.40.19',
424 'dst_mac': '00:00:00:00:00:03',
425 'local_mac': '00:00:00:00:00:01',
426 'dst_ip': '152.16.40.20',
428 'vpci': '0000:05:00.1',
434 'netmask': '255.255.255.0',
435 'gateway': '152.16.100.20',
436 'network': '152.16.100.20',
440 'netmask': '255.255.255.0',
441 'gateway': '152.16.40.20',
442 'network': '152.16.40.20',
446 'member-vnf-index': '2',
453 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
454 'network': '0064:ff9b:0:0:0:0:9810:6414',
459 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
460 'network': '0064:ff9b:0:0:0:0:9810:2814',
465 'VNF model': 'vpe_vnf.yaml',
471 self._mock_time_sleep = mock.patch.object(time, 'sleep')
472 self.mock_time_sleep = self._mock_time_sleep.start()
473 self.addCleanup(self._stop_mocks)
475 def _stop_mocks(self):
476 self._mock_time_sleep.stop()
478 def test___init__(self):
479 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
480 self.assertIsNone(vpe_approx_vnf._vnf_process)
482 @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server',
483 return_value='mock_node')
484 @mock.patch.object(sample_vnf, 'VnfSshHelper')
485 def test_collect_kpi_sa_not_running(self, ssh, *args):
486 test_base.mock_ssh(ssh)
488 resource = mock.Mock(autospec=ResourceProfile)
489 resource.check_if_system_agent_running.return_value = 1, ''
490 resource.amqp_collect_nfvi_kpi.return_value = {'foo': 234}
491 resource.check_if_system_agent_running.return_value = (1, None)
493 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
494 vpe_approx_vnf.scenario_helper.scenario_cfg = {
495 'nodes': {vpe_approx_vnf.name: "mock"}
497 vpe_approx_vnf.q_in = mock.MagicMock()
498 vpe_approx_vnf.q_out = mock.MagicMock()
499 vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
500 vpe_approx_vnf.resource_helper.resource = resource
503 'physical_node': 'mock_node',
504 'pkt_in_down_stream': 0,
505 'pkt_in_up_stream': 0,
506 'pkt_drop_down_stream': 0,
507 'pkt_drop_up_stream': 0,
508 'collect_stats': {'core': {}},
510 self.assertEqual(vpe_approx_vnf.collect_kpi(), expected)
512 @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server',
513 return_value='mock_node')
514 @mock.patch.object(sample_vnf, 'VnfSshHelper')
515 def test_collect_kpi_sa_running(self, ssh, *args):
516 test_base.mock_ssh(ssh)
518 resource = mock.Mock(autospec=ResourceProfile)
519 resource.check_if_system_agent_running.return_value = 0, '1234'
520 resource.amqp_collect_nfvi_kpi.return_value = {'foo': 234}
522 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
523 vpe_approx_vnf.scenario_helper.scenario_cfg = {
524 'nodes': {vpe_approx_vnf.name: "mock"}
526 vpe_approx_vnf.q_in = mock.MagicMock()
527 vpe_approx_vnf.q_out = mock.MagicMock()
528 vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
529 vpe_approx_vnf.resource_helper.resource = resource
532 'physical_node': 'mock_node',
533 'pkt_in_down_stream': 0,
534 'pkt_in_up_stream': 0,
535 'pkt_drop_down_stream': 0,
536 'pkt_drop_up_stream': 0,
537 'collect_stats': {'core': {'foo': 234}},
539 self.assertEqual(vpe_approx_vnf.collect_kpi(), expected)
541 @mock.patch.object(sample_vnf, 'VnfSshHelper')
542 def test_vnf_execute(self, ssh):
543 test_base.mock_ssh(ssh)
544 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
545 vpe_approx_vnf.q_in = mock.MagicMock()
546 vpe_approx_vnf.q_out = mock.MagicMock()
547 vpe_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
548 self.assertEqual(vpe_approx_vnf.vnf_execute("quit", 0), '')
550 @mock.patch.object(sample_vnf, 'VnfSshHelper')
551 def test_run_vpe(self, ssh):
552 test_base.mock_ssh(ssh)
554 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
555 vpe_approx_vnf.tc_file_name = get_file_abspath(TEST_FILE_YAML)
556 vpe_approx_vnf.vnf_cfg = {
559 'worker_config': '1C/1T',
562 vpe_approx_vnf.scenario_helper.scenario_cfg = {
566 'topology': 'nsb_test_case.yaml',
567 'vnf_config': 'vpe_config',
571 vpe_approx_vnf.topology = "nsb_test_case.yaml"
572 vpe_approx_vnf.nfvi_type = "baremetal"
573 vpe_approx_vnf._provide_config_file = mock.Mock()
574 vpe_approx_vnf._build_config = mock.MagicMock()
576 self.assertIsInstance(vpe_approx_vnf.ssh_helper, mock.Mock)
577 self.assertIsInstance(vpe_approx_vnf.ssh_helper, mock.Mock)
578 self.assertIsNone(vpe_approx_vnf._run())
580 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig")
581 @mock.patch("yardstick.network_services.vnf_generic.vnf.vpe_vnf.ConfigCreate")
582 @mock.patch("six.moves.builtins.open")
583 @mock.patch.object(sample_vnf, 'VnfSshHelper')
584 def test_build_config(self, ssh, *args):
585 test_base.mock_ssh(ssh)
586 vpe_approx_vnf = vpe_vnf.VpeApproxSetupEnvHelper(
587 mock.MagicMock(), mock.MagicMock(), mock.MagicMock())
588 vpe_approx_vnf.tc_file_name = get_file_abspath(TEST_FILE_YAML)
589 vpe_approx_vnf.generate_port_pairs = mock.Mock()
590 vpe_approx_vnf.vnf_cfg = {
593 'worker_config': '1C/1T',
596 vpe_approx_vnf.scenario_helper.scenario_cfg = {
600 'topology': 'nsb_test_case.yaml',
601 'vnf_config': 'vpe_config',
605 vpe_approx_vnf.topology = "nsb_test_case.yaml"
606 vpe_approx_vnf.nfvi_type = "baremetal"
607 vpe_approx_vnf._provide_config_file = mock.Mock()
609 vpe_approx_vnf.ssh_helper = mock.MagicMock()
610 vpe_approx_vnf.scenario_helper = mock.MagicMock()
611 vpe_approx_vnf.ssh_helper.bin_path = mock.Mock()
612 vpe_approx_vnf.ssh_helper.upload_config_file = mock.MagicMock()
613 self.assertIsNone(vpe_approx_vnf._build_vnf_ports())
615 vpe_approx_vnf.ssh_helper.provision_tool = mock.Mock(return_value='tool_path')
616 vpe_approx_vnf.ssh_helper.all_ports = mock.Mock()
617 vpe_approx_vnf.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1])
618 vpe_approx_vnf.scenario_helper.vnf_cfg = {'lb_config': 'HW'}
620 expected = 'sudo tool_path -p 0x3 -f /tmp/vpe_config -s /tmp/vpe_script --hwlb 3'
621 self.assertEqual(vpe_approx_vnf.build_config(), expected)
623 @mock.patch.object(sample_vnf, 'VnfSshHelper')
624 def test_wait_for_instantiate(self, ssh):
625 test_base.mock_ssh(ssh)
627 mock_process = mock.Mock(autospec=Process)
628 mock_process.is_alive.return_value = True
629 mock_process.exitcode = 432
631 mock_q_out = mock.Mock(autospec=Queue)
632 mock_q_out.get.side_effect = iter(["pipeline>"])
633 mock_q_out.qsize.side_effect = range(1, -1, -1)
635 mock_resource = mock.MagicMock()
637 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
638 vpe_approx_vnf._vnf_process = mock_process
639 vpe_approx_vnf.q_out = mock_q_out
640 vpe_approx_vnf.queue_wrapper = mock.Mock(
641 autospec=vnf_base.QueueFileWrapper)
642 vpe_approx_vnf.resource_helper.resource = mock_resource
644 vpe_approx_vnf.q_out.put("pipeline>")
645 self.assertEqual(vpe_approx_vnf.wait_for_instantiate(), 432)
647 @mock.patch.object(sample_vnf, 'VnfSshHelper')
648 def test_wait_for_instantiate_fragmented(self, ssh):
649 test_base.mock_ssh(ssh)
651 mock_process = mock.Mock(autospec=Process)
652 mock_process.is_alive.return_value = True
653 mock_process.exitcode = 432
655 # test that fragmented pipeline prompt is recognized
656 mock_q_out = mock.Mock(autospec=Queue)
657 mock_q_out.get.side_effect = iter(["wow pipel", "ine>"])
658 mock_q_out.qsize.side_effect = range(2, -1, -1)
660 mock_resource = mock.MagicMock()
662 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
663 vpe_approx_vnf._vnf_process = mock_process
664 vpe_approx_vnf.q_out = mock_q_out
665 vpe_approx_vnf.queue_wrapper = mock.Mock(
666 autospec=vnf_base.QueueFileWrapper)
667 vpe_approx_vnf.resource_helper.resource = mock_resource
669 self.assertEqual(vpe_approx_vnf.wait_for_instantiate(), 432)
671 @mock.patch.object(sample_vnf, 'VnfSshHelper')
672 def test_wait_for_instantiate_crash(self, ssh):
673 test_base.mock_ssh(ssh, exec_result=(1, "", ""))
675 mock_process = mock.Mock(autospec=Process)
676 mock_process.is_alive.return_value = False
677 mock_process.exitcode = 432
679 mock_resource = mock.MagicMock()
681 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
682 vpe_approx_vnf._vnf_process = mock_process
683 vpe_approx_vnf.resource_helper.resource = mock_resource
685 with self.assertRaises(RuntimeError) as raised:
686 vpe_approx_vnf.wait_for_instantiate()
688 self.assertIn('VNF process died', str(raised.exception))
690 @mock.patch.object(sample_vnf, 'VnfSshHelper')
691 def test_wait_for_instantiate_panic(self, ssh):
692 test_base.mock_ssh(ssh, exec_result=(1, "", ""))
694 mock_process = mock.Mock(autospec=Process)
695 mock_process.is_alive.return_value = True
696 mock_process.exitcode = 432
698 mock_resource = mock.MagicMock()
700 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
701 vpe_approx_vnf._vnf_process = mock_process
702 vpe_approx_vnf.resource_helper.resource = mock_resource
704 vpe_approx_vnf.q_out.put("PANIC")
705 with self.assertRaises(RuntimeError) as raised:
706 vpe_approx_vnf.wait_for_instantiate()
708 self.assertIn('Error starting', str(raised.exception))
710 @mock.patch.object(sample_vnf, 'VnfSshHelper')
711 def test_wait_for_instantiate_panic_fragmented(self, ssh):
712 test_base.mock_ssh(ssh, exec_result=(1, "", ""))
714 mock_process = mock.Mock(autospec=Process)
715 mock_process.is_alive.return_value = True
716 mock_process.exitcode = 432
718 # test that fragmented PANIC is recognized
719 mock_q_out = mock.Mock(autospec=Queue)
720 mock_q_out.get.side_effect = iter(["omg PA", "NIC this is bad"])
721 mock_q_out.qsize.side_effect = range(2, -1, -1)
723 mock_resource = mock.MagicMock()
725 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
726 vpe_approx_vnf._vnf_process = mock_process
727 vpe_approx_vnf.q_out = mock_q_out
728 vpe_approx_vnf.resource_helper.resource = mock_resource
730 with self.assertRaises(RuntimeError) as raised:
731 vpe_approx_vnf.wait_for_instantiate()
733 self.assertIn('Error starting', str(raised.exception))
735 @mock.patch.object(sample_vnf, 'VnfSshHelper')
736 def test_terminate(self, ssh):
737 test_base.mock_ssh(ssh)
739 vpe_approx_vnf = vpe_vnf.VpeApproxVnf(NAME, self.VNFD_0, 'task_id')
740 vpe_approx_vnf._vnf_process = mock.MagicMock()
741 vpe_approx_vnf._resource_collect_stop = mock.Mock()
742 vpe_approx_vnf.resource_helper = mock.MagicMock()
744 self.assertIsNone(vpe_approx_vnf.terminate())