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.
22 from yardstick.tests import STL_MOCKS
23 from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
24 from yardstick.common import utils
25 from yardstick.common import exceptions
28 STLClient = mock.MagicMock()
29 stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
33 from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxVnf
34 from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
35 from yardstick.network_services.nfvi.resource import ResourceProfile
36 from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxSetupEnvSetupEnvHelper
39 TEST_FILE_YAML = 'nsb_test_case.yaml'
40 SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
46 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Process")
47 class TestAclApproxVnf(unittest.TestCase):
48 VNFD = {'vnfd:vnfd-catalog':
50 [{'short-name': 'VpeVnf',
53 [{'network': '152.16.100.20',
54 'netmask': '255.255.255.0',
55 'gateway': '152.16.100.20',
57 {'network': '152.16.40.20',
58 'netmask': '255.255.255.0',
59 'gateway': '152.16.40.20',
61 'description': 'VPE approximation using DPDK',
62 'name': 'vpevnf-baremetal',
64 [{'network': '0064:ff9b:0:0:0:0:9810:6414',
66 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
68 {'network': '0064:ff9b:0:0:0:0:9810:2814',
70 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
72 'id': 'vpevnf-baremetal',
74 [{'virtual-interface':
75 {'dst_mac': '00:00:00:00:00:04',
76 'vpci': '0000:05:00.0',
77 'local_ip': '152.16.100.19',
78 'type': 'PCI-PASSTHROUGH',
79 'netmask': '255.255.255.0',
81 'bandwidth': '10 Gbps',
83 'dst_ip': '152.16.100.20',
84 'local_iface_name': 'xe0',
85 'local_mac': '00:00:00:00:00:02'},
86 'vnfd-connection-point-ref': 'xe0',
89 {'dst_mac': '00:00:00:00:00:03',
90 'vpci': '0000:05:00.1',
91 'local_ip': '152.16.40.19',
92 'type': 'PCI-PASSTHROUGH',
94 'netmask': '255.255.255.0',
96 'bandwidth': '10 Gbps',
97 'dst_ip': '152.16.40.20',
98 'local_iface_name': 'xe1',
99 'local_mac': '00:00:00:00:00:01'},
100 'vnfd-connection-point-ref': 'xe1',
102 'description': 'Vpe approximation using DPDK',
104 {'vdu-id': 'vpevnf-baremetal',
110 {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']},
111 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
112 {'type': 'VPORT', 'name': 'xe1'}],
113 'id': 'AclApproxVnf', 'name': 'VPEVnfSsh'}]}}
115 scenario_cfg = {'options': {'packetsize': 64, 'traffic_type': 4,
116 'rfc2544': {'allowed_drop_rate': '0.8 - 1'},
117 'vnf__1': {'rules': 'acl_1rule.yaml',
118 'vnf_config': {'lb_config': 'SW',
122 'worker_threads': 1}}
124 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
126 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
127 'runner': {'object': 'NetworkServiceTestCase',
129 'output_filename': '/tmp/yardstick.out',
130 'runner_id': 74476, 'duration': 400,
132 'traffic_profile': 'ipv4_throughput_acl.yaml',
133 'traffic_options': {'flow': 'ipv4_Packets_acl.yaml',
134 'imix': 'imix_voice.yaml'},
136 'nodes': {'tg__2': 'trafficgen_2.yardstick',
137 'tg__1': 'trafficgen_1.yardstick',
138 'vnf__1': 'vnf.yardstick'},
139 'topology': 'vpe-tg-topology-baremetal.yaml'}
141 context_cfg = {'nodes': {'tg__2':
142 {'member-vnf-index': '3',
143 'role': 'TrafficGen',
144 'name': 'trafficgen_2.yardstick',
145 'vnfd-id-ref': 'tg__2',
148 {'xe0': {'local_iface_name': 'ens513f0',
149 'vld_id': AclApproxVnf.DOWNLINK,
150 'netmask': '255.255.255.0',
151 'local_ip': '152.16.40.20',
152 'dst_mac': '00:00:00:00:00:01',
153 'local_mac': '00:00:00:00:00:03',
154 'dst_ip': '152.16.40.19',
156 'vpci': '0000:02:00.0',
158 'xe1': {'local_iface_name': 'ens513f1',
159 'netmask': '255.255.255.0',
160 'network': '202.16.100.0',
161 'local_ip': '202.16.100.20',
162 'local_mac': '00:1e:67:d0:60:5d',
164 'vpci': '0000:02:00.1',
165 'dpdk_port_num': 1}},
167 'VNF model': 'l3fwd_vnf.yaml',
170 {'member-vnf-index': '1',
171 'role': 'TrafficGen',
172 'name': 'trafficgen_1.yardstick',
173 'vnfd-id-ref': 'tg__1',
176 {'xe0': {'local_iface_name': 'ens785f0',
177 'vld_id': AclApproxVnf.UPLINK,
178 'netmask': '255.255.255.0',
179 'local_ip': '152.16.100.20',
180 'dst_mac': '00:00:00:00:00:02',
181 'local_mac': '00:00:00:00:00:04',
182 'dst_ip': '152.16.100.19',
184 'vpci': '0000:05:00.0',
186 'xe1': {'local_iface_name': 'ens785f1',
187 'netmask': '255.255.255.0',
188 'local_ip': '152.16.100.21',
189 'local_mac': '00:00:00:00:00:01',
191 'vpci': '0000:05:00.1',
192 'dpdk_port_num': 1}},
194 'VNF model': 'tg_rfc2544_tpl.yaml',
197 {'name': 'vnf.yardstick',
198 'vnfd-id-ref': 'vnf__1',
201 {'xe0': {'local_iface_name': 'ens786f0',
202 'vld_id': AclApproxVnf.UPLINK,
203 'netmask': '255.255.255.0',
204 'local_ip': '152.16.100.19',
205 'dst_mac': '00:00:00:00:00:04',
206 'local_mac': '00:00:00:00:00:02',
207 'dst_ip': '152.16.100.20',
209 'vpci': '0000:05:00.0',
211 'xe1': {'local_iface_name': 'ens786f1',
212 'vld_id': AclApproxVnf.DOWNLINK,
213 'netmask': '255.255.255.0',
214 'local_ip': '152.16.40.19',
215 'dst_mac': '00:00:00:00:00:03',
216 'local_mac': '00:00:00:00:00:01',
217 'dst_ip': '152.16.40.20',
219 'vpci': '0000:05:00.1',
220 'dpdk_port_num': 1}},
222 [{'netmask': '255.255.255.0',
223 'gateway': '152.16.100.20',
224 'network': '152.16.100.20',
226 {'netmask': '255.255.255.0',
227 'gateway': '152.16.40.20',
228 'network': '152.16.40.20',
230 'member-vnf-index': '2',
236 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
237 'network': '0064:ff9b:0:0:0:0:9810:6414',
240 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
241 'network': '0064:ff9b:0:0:0:0:9810:2814',
244 'VNF model': 'acl_vnf.yaml'}}}
246 def test___init__(self, *args):
247 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
248 acl_approx_vnf = AclApproxVnf(name, vnfd)
249 self.assertIsNone(acl_approx_vnf._vnf_process)
251 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
252 @mock.patch(SSH_HELPER)
253 def test_collect_kpi(self, ssh, *args):
256 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
257 acl_approx_vnf = AclApproxVnf(name, vnfd)
258 acl_approx_vnf.q_in = mock.MagicMock()
259 acl_approx_vnf.q_out = mock.MagicMock()
260 acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
261 acl_approx_vnf.resource = mock.Mock(autospec=ResourceProfile)
262 acl_approx_vnf.vnf_execute = mock.Mock(return_value="")
263 result = {'packets_dropped': 0, 'packets_fwd': 0, 'packets_in': 0}
264 self.assertEqual(result, acl_approx_vnf.collect_kpi())
266 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
267 @mock.patch(SSH_HELPER)
268 def test_vnf_execute_command(self, ssh, *args):
271 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
272 acl_approx_vnf = AclApproxVnf(name, vnfd)
273 acl_approx_vnf.q_in = mock.MagicMock()
274 acl_approx_vnf.q_out = mock.MagicMock()
275 acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
277 self.assertEqual("", acl_approx_vnf.vnf_execute(cmd))
279 @mock.patch(SSH_HELPER)
280 def test_get_stats(self, ssh, *args):
283 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
284 acl_approx_vnf = AclApproxVnf(name, vnfd)
285 acl_approx_vnf.q_in = mock.MagicMock()
286 acl_approx_vnf.q_out = mock.MagicMock()
287 acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
288 result = "ACL TOTAL: pkts_processed: 100, pkts_drop: 0, spkts_received: 100"
289 acl_approx_vnf.vnf_execute = mock.Mock(return_value=result)
290 self.assertEqual(result, acl_approx_vnf.get_stats())
292 def _get_file_abspath(self, filename):
293 curr_path = os.path.dirname(os.path.abspath(__file__))
294 file_path = os.path.join(curr_path, filename)
297 @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.hex")
298 @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.eval")
299 @mock.patch('yardstick.network_services.vnf_generic.vnf.acl_vnf.open')
300 @mock.patch(SSH_HELPER)
301 def test_run_acl(self, ssh, *args):
304 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
305 acl_approx_vnf = AclApproxVnf(name, vnfd)
306 acl_approx_vnf._build_config = mock.MagicMock()
307 acl_approx_vnf.queue_wrapper = mock.MagicMock()
308 acl_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
309 acl_approx_vnf.vnf_cfg = {'lb_config': 'SW',
311 'worker_config': '1C/1T',
313 acl_approx_vnf.all_options = {'traffic_type': '4',
314 'topology': 'nsb_test_case.yaml'}
315 acl_approx_vnf._run()
316 acl_approx_vnf.ssh_helper.run.assert_called_once()
318 @mock.patch.object(utils, 'find_relative_file')
319 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context")
320 @mock.patch(SSH_HELPER)
321 def test_instantiate(self, ssh, *args):
324 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
325 acl_approx_vnf = AclApproxVnf(name, vnfd)
326 acl_approx_vnf.deploy_helper = mock.MagicMock()
327 acl_approx_vnf.resource_helper = mock.MagicMock()
328 acl_approx_vnf._build_config = mock.MagicMock()
329 self.scenario_cfg['vnf_options'] = {'acl': {'cfg': "",
331 acl_approx_vnf.q_out.put("pipeline>")
332 acl_approx_vnf.WAIT_TIME = 0
333 self.scenario_cfg.update({"nodes": {"vnf__1": ""}})
334 self.assertIsNone(acl_approx_vnf.instantiate(self.scenario_cfg,
337 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
338 @mock.patch(SSH_HELPER)
339 def test_terminate(self, ssh, *args):
342 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
343 acl_approx_vnf = AclApproxVnf(name, vnfd)
344 acl_approx_vnf._vnf_process = mock.MagicMock()
345 acl_approx_vnf._vnf_process.terminate = mock.Mock()
346 acl_approx_vnf.used_drivers = {"01:01.0": "i40e",
348 acl_approx_vnf.vnf_execute = mock.MagicMock()
349 acl_approx_vnf.dpdk_devbind = "dpdk-devbind.py"
350 acl_approx_vnf._resource_collect_stop = mock.Mock()
351 self.assertIsNone(acl_approx_vnf.terminate())
354 class TestAclApproxSetupEnvSetupEnvHelper(unittest.TestCase):
356 ACL_CONFIG = {"access-list-entries": [{
365 "destination-ipv4-network": "152.16.0.0/24",
366 "destination-port-range": {
370 "source-ipv4-network": "0.0.0.0/0",
371 "source-port-range": {
375 "protocol-mask": 255,
379 "rule-name": "rule1588"
383 def test_get_default_flows(self):
384 """Check if default ACL SampleVNF CLI commands are
385 generated correctly"""
386 ssh_helper = mock.Mock()
387 vnfd_helper = VnfdHelper({'vdu': [
388 {'external-interface': [
390 'virtual-interface': {
391 'local_ip': '152.16.100.19',
392 'netmask': '255.255.255.0',
394 'dst_ip': '152.16.100.20',
395 'vld_id': 'uplink_0',
398 'vnfd-connection-point-ref': 'xe0',
402 'virtual-interface': {
403 'local_ip': '152.16.40.19',
404 'netmask': '255.255.255.0',
406 'dst_ip': '152.16.40.20',
407 'vld_id': 'downlink_0',
410 'vnfd-connection-point-ref': 'xe1',
415 setup_helper = AclApproxSetupEnvSetupEnvHelper(vnfd_helper, ssh_helper, None)
416 self.check_acl_commands(setup_helper.get_flows_config(), [
417 # format: (<cli pattern>, <number of expected matches>)
418 ("^p action add [0-9]+ accept$", 2),
419 ("^p action add [0-9]+ count$", 2),
420 ("^p action add [0-9]+ fwd 1$", 1),
421 ("^p action add [0-9]+ fwd 0$", 1),
422 ("^p acl add 1 152.16.100.0 24 152.16.40.0 24 0 65535 0 65535 0 0 [0-9]+$", 1),
423 ("^p acl add 1 152.16.40.0 24 152.16.100.0 24 0 65535 0 65535 0 0 [0-9]+$", 1),
424 ("^p acl applyruleset$", 1)
427 @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
428 def test_get_flows_config(self, get_default_flows):
429 """Check if provided ACL config can be converted to
430 ACL SampleVNF CLI commands correctly"""
431 ssh_helper = mock.Mock()
432 setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
433 get_default_flows.return_value = ({}, [])
434 self.check_acl_commands(setup_helper.get_flows_config(self.ACL_CONFIG), [
435 # format: (<cli pattern>, <number of expected matches>)
436 ("^p action add [0-9]+ count$", 1),
437 ("^p action add [0-9]+ fwd 0$", 1),
438 ("^p acl add 1 0.0.0.0 0 152.16.0.0 24 0 65535 0 65535 127 0 [0-9]+$", 1),
439 ("^p acl applyruleset$", 1)
442 @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
443 def test_get_flows_config_invalid_action(self, get_default_flows):
444 """Check if incorrect ACL config fails to convert
445 to ACL SampleVNF CLI commands"""
446 ssh_helper = mock.Mock()
447 setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
448 get_default_flows.return_value = ({}, [])
449 # duplicate config and add invald action
450 acl_config = copy.deepcopy(self.ACL_CONFIG)
451 acl_config['access-list-entries'][0]["actions"].append({"xnat": {}})
452 self.assertRaises(exceptions.AclUknownActionTemplate,
453 setup_helper.get_flows_config, acl_config)
455 @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
456 def test_get_flows_config_invalid_action_param(self, get_default_flows):
457 """Check if ACL config with invalid action parameter fails to convert
458 to ACL SampleVNF CLI commands"""
459 ssh_helper = mock.Mock()
460 setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
461 get_default_flows.return_value = ({}, [])
462 # duplicate config and add action with invalid parameter
463 acl_config = copy.deepcopy(self.ACL_CONFIG)
464 acl_config['access-list-entries'][0]["actions"].append(
465 {"nat": {"xport": 0}})
466 self.assertRaises(exceptions.AclMissingActionArguments,
467 setup_helper.get_flows_config, acl_config)
469 def check_acl_commands(self, config, expected_cli_patterns):
470 """Check if expected ACL CLI commands (given as a list of patterns,
471 `expected_cli_patterns` parameter) present in SampleVNF ACL
472 configuration (given as a multiline string, `config` parameter)"""
473 # Example of expected config:
474 # ---------------------------
475 # p action add 1 accept
476 # p action add 1 fwd 1
477 # p action add 2 accept
478 # p action add 2 count
479 # p action add 2 fwd 0
480 # p acl add 1 152.16.100.0 24 152.16.40.0 24 0 65535 0 65535 0 0 1
481 # p acl add 1 152.16.40.0 24 152.16.100.0 24 0 65535 0 65535 0 0 2
483 # ---------------------------
484 # NOTE: The config above consists of actions ids, which are actually
485 # unknown (generated at runtime), thus it's incorrect just to compare
486 # the example ACL config above with the configuration returned by
487 # get_flows_config() function. It's more correct to use CLI patterns
488 # (RE) to find the required SampleVNF CLI commands in the multiline
489 # string (SampleVNF ACL configuration).
490 for pattern, num_of_match in expected_cli_patterns:
491 # format: (<cli pattern>, <number of expected matches>)
492 result = re.findall(pattern, config, re.MULTILINE)
493 self.assertEqual(len(result), num_of_match)
495 @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open')
496 @mock.patch.object(utils, 'find_relative_file')
497 @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig')
498 @mock.patch.object(utils, 'open_relative_file')
499 def test_build_config(self, *args):
500 vnfd_helper = mock.Mock()
501 ssh_helper = mock.Mock()
502 scenario_helper = mock.Mock()
503 scenario_helper.vnf_cfg = {'lb_config': 'HW'}
504 scenario_helper.options = {}
505 scenario_helper.all_options = {}
507 acl_approx_setup_helper = AclApproxSetupEnvSetupEnvHelper(vnfd_helper,
511 acl_approx_setup_helper.get_flows_config = mock.Mock()
512 acl_approx_setup_helper.ssh_helper.provision_tool = mock.Mock(return_value='tool_path')
513 acl_approx_setup_helper.ssh_helper.all_ports = mock.Mock()
514 acl_approx_setup_helper.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1])
515 expected = 'sudo tool_path -p 0x3 -f /tmp/acl_config -s /tmp/acl_script --hwlb 3'
516 self.assertEqual(acl_approx_setup_helper.build_config(), expected)
517 acl_approx_setup_helper.get_flows_config.assert_called_once()