1 # Copyright (c) 2016-2019 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.
21 from yardstick.common import utils
22 from yardstick.common import exceptions
23 from yardstick.benchmark.contexts import base as ctx_base
24 from yardstick.network_services.vnf_generic.vnf import acl_vnf
25 from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
26 from yardstick.network_services.nfvi.resource import ResourceProfile
27 from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxSetupEnvSetupEnvHelper
28 from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
31 TEST_FILE_YAML = 'nsb_test_case.yaml'
32 SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
38 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Process")
39 class TestAclApproxVnf(unittest.TestCase):
40 VNFD = {'vnfd:vnfd-catalog':
42 [{'short-name': 'VpeVnf',
45 [{'network': '152.16.100.20',
46 'netmask': '255.255.255.0',
47 'gateway': '152.16.100.20',
49 {'network': '152.16.40.20',
50 'netmask': '255.255.255.0',
51 'gateway': '152.16.40.20',
53 'description': 'VPE approximation using DPDK',
54 'name': 'vpevnf-baremetal',
56 [{'network': '0064:ff9b:0:0:0:0:9810:6414',
58 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
60 {'network': '0064:ff9b:0:0:0:0:9810:2814',
62 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
64 'id': 'vpevnf-baremetal',
66 [{'virtual-interface':
67 {'dst_mac': '00:00:00:00:00:04',
68 'vpci': '0000:05:00.0',
69 'local_ip': '152.16.100.19',
70 'type': 'PCI-PASSTHROUGH',
71 'netmask': '255.255.255.0',
73 'bandwidth': '10 Gbps',
75 'dst_ip': '152.16.100.20',
76 'local_iface_name': 'xe0',
77 'local_mac': '00:00:00:00:00:02'},
78 'vnfd-connection-point-ref': 'xe0',
81 {'dst_mac': '00:00:00:00:00:03',
82 'vpci': '0000:05:00.1',
83 'local_ip': '152.16.40.19',
84 'type': 'PCI-PASSTHROUGH',
86 'netmask': '255.255.255.0',
88 'bandwidth': '10 Gbps',
89 'dst_ip': '152.16.40.20',
90 'local_iface_name': 'xe1',
91 'local_mac': '00:00:00:00:00:01'},
92 'vnfd-connection-point-ref': 'xe1',
94 'description': 'Vpe approximation using DPDK',
96 {'vdu-id': 'vpevnf-baremetal',
102 {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']},
103 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
104 {'type': 'VPORT', 'name': 'xe1'}],
105 'id': 'AclApproxVnf', 'name': 'VPEVnfSsh'}]}}
107 scenario_cfg = {'options': {'packetsize': 64, 'traffic_type': 4,
108 'rfc2544': {'allowed_drop_rate': '0.8 - 1'},
109 'vnf__1': {'rules': 'acl_1rule.yaml',
110 'vnf_config': {'lb_config': 'SW',
114 'worker_threads': 1}}
116 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
118 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
119 'runner': {'object': 'NetworkServiceTestCase',
121 'output_filename': '/tmp/yardstick.out',
122 'runner_id': 74476, 'duration': 400,
124 'traffic_profile': 'ipv4_throughput_acl.yaml',
125 'traffic_options': {'flow': 'ipv4_Packets_acl.yaml',
126 'imix': 'imix_voice.yaml'},
128 'nodes': {'tg__2': 'trafficgen_2.yardstick',
129 'tg__1': 'trafficgen_1.yardstick',
130 'vnf__1': 'vnf.yardstick'},
131 'topology': 'vpe-tg-topology-baremetal.yaml'}
133 context_cfg = {'nodes': {'tg__2':
134 {'member-vnf-index': '3',
135 'role': 'TrafficGen',
136 'name': 'trafficgen_2.yardstick',
137 'vnfd-id-ref': 'tg__2',
140 {'xe0': {'local_iface_name': 'ens513f0',
141 'vld_id': acl_vnf.AclApproxVnf.DOWNLINK,
142 'netmask': '255.255.255.0',
143 'local_ip': '152.16.40.20',
144 'dst_mac': '00:00:00:00:00:01',
145 'local_mac': '00:00:00:00:00:03',
146 'dst_ip': '152.16.40.19',
148 'vpci': '0000:02:00.0',
150 'xe1': {'local_iface_name': 'ens513f1',
151 'netmask': '255.255.255.0',
152 'network': '202.16.100.0',
153 'local_ip': '202.16.100.20',
154 'local_mac': '00:1e:67:d0:60:5d',
156 'vpci': '0000:02:00.1',
157 'dpdk_port_num': 1}},
159 'VNF model': 'l3fwd_vnf.yaml',
162 {'member-vnf-index': '1',
163 'role': 'TrafficGen',
164 'name': 'trafficgen_1.yardstick',
165 'vnfd-id-ref': 'tg__1',
168 {'xe0': {'local_iface_name': 'ens785f0',
169 'vld_id': acl_vnf.AclApproxVnf.UPLINK,
170 'netmask': '255.255.255.0',
171 'local_ip': '152.16.100.20',
172 'dst_mac': '00:00:00:00:00:02',
173 'local_mac': '00:00:00:00:00:04',
174 'dst_ip': '152.16.100.19',
176 'vpci': '0000:05:00.0',
178 'xe1': {'local_iface_name': 'ens785f1',
179 'netmask': '255.255.255.0',
180 'local_ip': '152.16.100.21',
181 'local_mac': '00:00:00:00:00:01',
183 'vpci': '0000:05:00.1',
184 'dpdk_port_num': 1}},
186 'VNF model': 'tg_rfc2544_tpl.yaml',
189 {'name': 'vnf.yardstick',
190 'vnfd-id-ref': 'vnf__1',
193 {'xe0': {'local_iface_name': 'ens786f0',
194 'vld_id': acl_vnf.AclApproxVnf.UPLINK,
195 'netmask': '255.255.255.0',
196 'local_ip': '152.16.100.19',
197 'dst_mac': '00:00:00:00:00:04',
198 'local_mac': '00:00:00:00:00:02',
199 'dst_ip': '152.16.100.20',
201 'vpci': '0000:05:00.0',
203 'xe1': {'local_iface_name': 'ens786f1',
204 'vld_id': acl_vnf.AclApproxVnf.DOWNLINK,
205 'netmask': '255.255.255.0',
206 'local_ip': '152.16.40.19',
207 'dst_mac': '00:00:00:00:00:03',
208 'local_mac': '00:00:00:00:00:01',
209 'dst_ip': '152.16.40.20',
211 'vpci': '0000:05:00.1',
212 'dpdk_port_num': 1}},
214 [{'netmask': '255.255.255.0',
215 'gateway': '152.16.100.20',
216 'network': '152.16.100.20',
218 {'netmask': '255.255.255.0',
219 'gateway': '152.16.40.20',
220 'network': '152.16.40.20',
222 'member-vnf-index': '2',
228 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
229 'network': '0064:ff9b:0:0:0:0:9810:6414',
232 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
233 'network': '0064:ff9b:0:0:0:0:9810:2814',
236 'VNF model': 'acl_vnf.yaml'}}}
238 def test___init__(self, *args):
239 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
240 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
241 self.assertIsNone(acl_approx_vnf._vnf_process)
243 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
244 @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
245 @mock.patch(SSH_HELPER)
246 def test_collect_kpi(self, ssh, *args):
249 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
250 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
251 acl_approx_vnf.scenario_helper.scenario_cfg = {
252 'nodes': {acl_approx_vnf.name: "mock"}
254 acl_approx_vnf.q_in = mock.MagicMock()
255 acl_approx_vnf.q_out = mock.MagicMock()
256 acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
257 acl_approx_vnf.resource = mock.Mock(autospec=ResourceProfile)
258 acl_approx_vnf.vnf_execute = mock.Mock(return_value="")
260 'physical_node': 'mock_node',
261 'packets_dropped': 0,
265 self.assertEqual(result, acl_approx_vnf.collect_kpi())
267 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
268 @mock.patch(SSH_HELPER)
269 def test_vnf_execute_command(self, ssh, *args):
272 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
273 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
274 acl_approx_vnf.q_in = mock.MagicMock()
275 acl_approx_vnf.q_out = mock.MagicMock()
276 acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
278 self.assertEqual("", acl_approx_vnf.vnf_execute(cmd))
280 @mock.patch(SSH_HELPER)
281 def test_get_stats(self, ssh, *args):
284 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
285 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
286 acl_approx_vnf.q_in = mock.MagicMock()
287 acl_approx_vnf.q_out = mock.MagicMock()
288 acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
289 result = "ACL TOTAL: pkts_processed: 100, pkts_drop: 0, spkts_received: 100"
290 acl_approx_vnf.vnf_execute = mock.Mock(return_value=result)
291 self.assertEqual(result, acl_approx_vnf.get_stats())
293 def _get_file_abspath(self, filename):
294 curr_path = os.path.dirname(os.path.abspath(__file__))
295 file_path = os.path.join(curr_path, filename)
298 @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.hex")
299 @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.eval")
300 @mock.patch('yardstick.network_services.vnf_generic.vnf.acl_vnf.open')
301 @mock.patch(SSH_HELPER)
302 def test_run_acl(self, ssh, *args):
305 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
306 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
307 acl_approx_vnf._build_config = mock.MagicMock()
308 acl_approx_vnf.queue_wrapper = mock.MagicMock()
309 acl_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
310 acl_approx_vnf.vnf_cfg = {'lb_config': 'SW',
312 'worker_config': '1C/1T',
314 acl_approx_vnf.all_options = {'traffic_type': '4',
315 'topology': 'nsb_test_case.yaml'}
316 acl_approx_vnf._run()
317 acl_approx_vnf.ssh_helper.run.assert_called_once()
319 @mock.patch.object(utils, 'find_relative_file')
320 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context")
321 @mock.patch(SSH_HELPER)
322 def test_instantiate(self, ssh, *args):
325 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
326 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
327 acl_approx_vnf.deploy_helper = mock.MagicMock()
328 acl_approx_vnf.resource_helper = mock.MagicMock()
329 acl_approx_vnf._build_config = mock.MagicMock()
330 self.scenario_cfg['vnf_options'] = {'acl': {'cfg': "",
332 acl_approx_vnf.q_out.put("pipeline>")
333 acl_approx_vnf.WAIT_TIME = 0
334 self.scenario_cfg.update({"nodes": {"vnf__1": ""}})
335 self.assertIsNone(acl_approx_vnf.instantiate(self.scenario_cfg,
338 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
339 @mock.patch(SSH_HELPER)
340 def test_terminate(self, ssh, *args):
343 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
344 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
345 acl_approx_vnf._vnf_process = mock.MagicMock()
346 acl_approx_vnf._vnf_process.terminate = mock.Mock()
347 acl_approx_vnf.used_drivers = {"01:01.0": "i40e",
349 acl_approx_vnf.vnf_execute = mock.MagicMock()
350 acl_approx_vnf.dpdk_devbind = "dpdk-devbind.py"
351 acl_approx_vnf._resource_collect_stop = mock.Mock()
352 self.assertIsNone(acl_approx_vnf.terminate())
355 class TestAclApproxSetupEnvSetupEnvHelper(unittest.TestCase):
357 ACL_CONFIG = {"access-list-entries": [{
366 "destination-ipv4-network": "152.16.0.0/24",
367 "destination-port-range": {
371 "source-ipv4-network": "0.0.0.0/0",
372 "source-port-range": {
376 "protocol-mask": 255,
380 "rule-name": "rule1588"
384 def test_get_default_flows(self):
385 """Check if default ACL SampleVNF CLI commands are
386 generated correctly"""
387 ssh_helper = mock.Mock()
388 vnfd_helper = VnfdHelper({'vdu': [
389 {'external-interface': [
391 'virtual-interface': {
392 'local_ip': '152.16.100.19',
393 'netmask': '255.255.255.0',
395 'dst_ip': '152.16.100.20',
396 'vld_id': 'uplink_0',
399 'vnfd-connection-point-ref': 'xe0',
403 'virtual-interface': {
404 'local_ip': '152.16.40.19',
405 'netmask': '255.255.255.0',
407 'dst_ip': '152.16.40.20',
408 'vld_id': 'downlink_0',
411 'vnfd-connection-point-ref': 'xe1',
416 setup_helper = AclApproxSetupEnvSetupEnvHelper(vnfd_helper, ssh_helper, None)
417 self.check_acl_commands(setup_helper.get_flows_config(), [
418 # format: (<cli pattern>, <number of expected matches>)
419 ("^p action add [0-9]+ accept$", 2),
420 ("^p action add [0-9]+ count$", 2),
421 ("^p action add [0-9]+ fwd 1$", 1),
422 ("^p action add [0-9]+ fwd 0$", 1),
423 ("^p acl add 1 152.16.100.0 24 152.16.40.0 24 0 65535 0 65535 0 0 [0-9]+$", 1),
424 ("^p acl add 1 152.16.40.0 24 152.16.100.0 24 0 65535 0 65535 0 0 [0-9]+$", 1),
425 ("^p acl applyruleset$", 1)
428 @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
429 def test_get_flows_config(self, get_default_flows):
430 """Check if provided ACL config can be converted to
431 ACL SampleVNF CLI commands correctly"""
432 ssh_helper = mock.Mock()
433 setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
434 get_default_flows.return_value = ({}, [])
435 self.check_acl_commands(setup_helper.get_flows_config(self.ACL_CONFIG), [
436 # format: (<cli pattern>, <number of expected matches>)
437 ("^p action add [0-9]+ count$", 1),
438 ("^p action add [0-9]+ fwd 0$", 1),
439 ("^p acl add 1 0.0.0.0 0 152.16.0.0 24 0 65535 0 65535 127 0 [0-9]+$", 1),
440 ("^p acl applyruleset$", 1)
443 @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
444 def test_get_flows_config_invalid_action(self, get_default_flows):
445 """Check if incorrect ACL config fails to convert
446 to ACL SampleVNF CLI commands"""
447 ssh_helper = mock.Mock()
448 setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
449 get_default_flows.return_value = ({}, [])
450 # duplicate config and add invald action
451 acl_config = copy.deepcopy(self.ACL_CONFIG)
452 acl_config['access-list-entries'][0]["actions"].append({"xnat": {}})
453 self.assertRaises(exceptions.AclUnknownActionTemplate,
454 setup_helper.get_flows_config, acl_config)
456 @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
457 def test_get_flows_config_invalid_action_param(self, get_default_flows):
458 """Check if ACL config with invalid action parameter fails to convert
459 to ACL SampleVNF CLI commands"""
460 ssh_helper = mock.Mock()
461 setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
462 get_default_flows.return_value = ({}, [])
463 # duplicate config and add action with invalid parameter
464 acl_config = copy.deepcopy(self.ACL_CONFIG)
465 acl_config['access-list-entries'][0]["actions"].append(
466 {"nat": {"xport": 0}})
467 self.assertRaises(exceptions.AclMissingActionArguments,
468 setup_helper.get_flows_config, acl_config)
470 def check_acl_commands(self, config, expected_cli_patterns):
471 """Check if expected ACL CLI commands (given as a list of patterns,
472 `expected_cli_patterns` parameter) present in SampleVNF ACL
473 configuration (given as a multiline string, `config` parameter)"""
474 # Example of expected config:
475 # ---------------------------
476 # p action add 1 accept
477 # p action add 1 fwd 1
478 # p action add 2 accept
479 # p action add 2 count
480 # p action add 2 fwd 0
481 # p acl add 1 152.16.100.0 24 152.16.40.0 24 0 65535 0 65535 0 0 1
482 # p acl add 1 152.16.40.0 24 152.16.100.0 24 0 65535 0 65535 0 0 2
484 # ---------------------------
485 # NOTE: The config above consists of actions ids, which are actually
486 # unknown (generated at runtime), thus it's incorrect just to compare
487 # the example ACL config above with the configuration returned by
488 # get_flows_config() function. It's more correct to use CLI patterns
489 # (RE) to find the required SampleVNF CLI commands in the multiline
490 # string (SampleVNF ACL configuration).
491 for pattern, num_of_match in expected_cli_patterns:
492 # format: (<cli pattern>, <number of expected matches>)
493 result = re.findall(pattern, config, re.MULTILINE)
494 self.assertEqual(len(result), num_of_match)
496 @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open')
497 @mock.patch.object(utils, 'find_relative_file')
498 @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig')
499 @mock.patch.object(utils, 'open_relative_file')
500 def test_build_config(self, *args):
501 vnfd_helper = mock.Mock()
502 ssh_helper = mock.Mock()
503 scenario_helper = mock.Mock()
504 scenario_helper.vnf_cfg = {'lb_config': 'HW'}
505 scenario_helper.options = {}
506 scenario_helper.all_options = {}
508 acl_approx_setup_helper = AclApproxSetupEnvSetupEnvHelper(vnfd_helper,
512 acl_approx_setup_helper.get_flows_config = mock.Mock()
513 acl_approx_setup_helper.ssh_helper.provision_tool = mock.Mock(return_value='tool_path')
514 acl_approx_setup_helper.ssh_helper.all_ports = mock.Mock()
515 acl_approx_setup_helper.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1])
516 expected = 'sudo tool_path -p 0x3 -f /tmp/acl_config -s /tmp/acl_script --hwlb 3'
517 self.assertEqual(acl_approx_setup_helper.build_config(), expected)
518 acl_approx_setup_helper.get_flows_config.assert_called_once()