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
26 from yardstick.benchmark.contexts import base as ctx_base
29 STLClient = mock.MagicMock()
30 stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
34 from yardstick.network_services.vnf_generic.vnf import acl_vnf
35 from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
36 from yardstick.network_services.nfvi.resource import ResourceProfile
37 from yardstick.network_services.vnf_generic.vnf.acl_vnf import AclApproxSetupEnvSetupEnvHelper
40 TEST_FILE_YAML = 'nsb_test_case.yaml'
41 SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper'
47 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Process")
48 class TestAclApproxVnf(unittest.TestCase):
49 VNFD = {'vnfd:vnfd-catalog':
51 [{'short-name': 'VpeVnf',
54 [{'network': '152.16.100.20',
55 'netmask': '255.255.255.0',
56 'gateway': '152.16.100.20',
58 {'network': '152.16.40.20',
59 'netmask': '255.255.255.0',
60 'gateway': '152.16.40.20',
62 'description': 'VPE approximation using DPDK',
63 'name': 'vpevnf-baremetal',
65 [{'network': '0064:ff9b:0:0:0:0:9810:6414',
67 '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',
73 'id': 'vpevnf-baremetal',
75 [{'virtual-interface':
76 {'dst_mac': '00:00:00:00:00:04',
77 'vpci': '0000:05:00.0',
78 'local_ip': '152.16.100.19',
79 'type': 'PCI-PASSTHROUGH',
80 'netmask': '255.255.255.0',
82 'bandwidth': '10 Gbps',
84 'dst_ip': '152.16.100.20',
85 'local_iface_name': 'xe0',
86 'local_mac': '00:00:00:00:00:02'},
87 'vnfd-connection-point-ref': 'xe0',
90 {'dst_mac': '00:00:00:00:00:03',
91 'vpci': '0000:05:00.1',
92 'local_ip': '152.16.40.19',
93 'type': 'PCI-PASSTHROUGH',
95 'netmask': '255.255.255.0',
97 'bandwidth': '10 Gbps',
98 'dst_ip': '152.16.40.20',
99 'local_iface_name': 'xe1',
100 'local_mac': '00:00:00:00:00:01'},
101 'vnfd-connection-point-ref': 'xe1',
103 'description': 'Vpe approximation using DPDK',
105 {'vdu-id': 'vpevnf-baremetal',
111 {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']},
112 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
113 {'type': 'VPORT', 'name': 'xe1'}],
114 'id': 'AclApproxVnf', 'name': 'VPEVnfSsh'}]}}
116 scenario_cfg = {'options': {'packetsize': 64, 'traffic_type': 4,
117 'rfc2544': {'allowed_drop_rate': '0.8 - 1'},
118 'vnf__1': {'rules': 'acl_1rule.yaml',
119 'vnf_config': {'lb_config': 'SW',
123 'worker_threads': 1}}
125 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7',
127 'tc': 'tc_ipv4_1Mflow_64B_packetsize',
128 'runner': {'object': 'NetworkServiceTestCase',
130 'output_filename': '/tmp/yardstick.out',
131 'runner_id': 74476, 'duration': 400,
133 'traffic_profile': 'ipv4_throughput_acl.yaml',
134 'traffic_options': {'flow': 'ipv4_Packets_acl.yaml',
135 'imix': 'imix_voice.yaml'},
137 'nodes': {'tg__2': 'trafficgen_2.yardstick',
138 'tg__1': 'trafficgen_1.yardstick',
139 'vnf__1': 'vnf.yardstick'},
140 'topology': 'vpe-tg-topology-baremetal.yaml'}
142 context_cfg = {'nodes': {'tg__2':
143 {'member-vnf-index': '3',
144 'role': 'TrafficGen',
145 'name': 'trafficgen_2.yardstick',
146 'vnfd-id-ref': 'tg__2',
149 {'xe0': {'local_iface_name': 'ens513f0',
150 'vld_id': acl_vnf.AclApproxVnf.DOWNLINK,
151 'netmask': '255.255.255.0',
152 'local_ip': '152.16.40.20',
153 'dst_mac': '00:00:00:00:00:01',
154 'local_mac': '00:00:00:00:00:03',
155 'dst_ip': '152.16.40.19',
157 'vpci': '0000:02:00.0',
159 'xe1': {'local_iface_name': 'ens513f1',
160 'netmask': '255.255.255.0',
161 'network': '202.16.100.0',
162 'local_ip': '202.16.100.20',
163 'local_mac': '00:1e:67:d0:60:5d',
165 'vpci': '0000:02:00.1',
166 'dpdk_port_num': 1}},
168 'VNF model': 'l3fwd_vnf.yaml',
171 {'member-vnf-index': '1',
172 'role': 'TrafficGen',
173 'name': 'trafficgen_1.yardstick',
174 'vnfd-id-ref': 'tg__1',
177 {'xe0': {'local_iface_name': 'ens785f0',
178 'vld_id': acl_vnf.AclApproxVnf.UPLINK,
179 'netmask': '255.255.255.0',
180 'local_ip': '152.16.100.20',
181 'dst_mac': '00:00:00:00:00:02',
182 'local_mac': '00:00:00:00:00:04',
183 'dst_ip': '152.16.100.19',
185 'vpci': '0000:05:00.0',
187 'xe1': {'local_iface_name': 'ens785f1',
188 'netmask': '255.255.255.0',
189 'local_ip': '152.16.100.21',
190 'local_mac': '00:00:00:00:00:01',
192 'vpci': '0000:05:00.1',
193 'dpdk_port_num': 1}},
195 'VNF model': 'tg_rfc2544_tpl.yaml',
198 {'name': 'vnf.yardstick',
199 'vnfd-id-ref': 'vnf__1',
202 {'xe0': {'local_iface_name': 'ens786f0',
203 'vld_id': acl_vnf.AclApproxVnf.UPLINK,
204 'netmask': '255.255.255.0',
205 'local_ip': '152.16.100.19',
206 'dst_mac': '00:00:00:00:00:04',
207 'local_mac': '00:00:00:00:00:02',
208 'dst_ip': '152.16.100.20',
210 'vpci': '0000:05:00.0',
212 'xe1': {'local_iface_name': 'ens786f1',
213 'vld_id': acl_vnf.AclApproxVnf.DOWNLINK,
214 'netmask': '255.255.255.0',
215 'local_ip': '152.16.40.19',
216 'dst_mac': '00:00:00:00:00:03',
217 'local_mac': '00:00:00:00:00:01',
218 'dst_ip': '152.16.40.20',
220 'vpci': '0000:05:00.1',
221 'dpdk_port_num': 1}},
223 [{'netmask': '255.255.255.0',
224 'gateway': '152.16.100.20',
225 'network': '152.16.100.20',
227 {'netmask': '255.255.255.0',
228 'gateway': '152.16.40.20',
229 'network': '152.16.40.20',
231 'member-vnf-index': '2',
237 'gateway': '0064:ff9b:0:0:0:0:9810:6414',
238 'network': '0064:ff9b:0:0:0:0:9810:6414',
241 'gateway': '0064:ff9b:0:0:0:0:9810:2814',
242 'network': '0064:ff9b:0:0:0:0:9810:2814',
245 'VNF model': 'acl_vnf.yaml'}}}
247 def test___init__(self, *args):
248 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
249 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
250 self.assertIsNone(acl_approx_vnf._vnf_process)
252 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
253 @mock.patch.object(ctx_base.Context, 'get_physical_node_from_server', return_value='mock_node')
254 @mock.patch(SSH_HELPER)
255 def test_collect_kpi(self, ssh, *args):
258 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
259 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
260 acl_approx_vnf.scenario_helper.scenario_cfg = {
261 'nodes': {acl_approx_vnf.name: "mock"}
263 acl_approx_vnf.q_in = mock.MagicMock()
264 acl_approx_vnf.q_out = mock.MagicMock()
265 acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
266 acl_approx_vnf.resource = mock.Mock(autospec=ResourceProfile)
267 acl_approx_vnf.vnf_execute = mock.Mock(return_value="")
269 'physical_node': 'mock_node',
270 'packets_dropped': 0,
274 self.assertEqual(result, acl_approx_vnf.collect_kpi())
276 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
277 @mock.patch(SSH_HELPER)
278 def test_vnf_execute_command(self, ssh, *args):
281 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
282 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
283 acl_approx_vnf.q_in = mock.MagicMock()
284 acl_approx_vnf.q_out = mock.MagicMock()
285 acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
287 self.assertEqual("", acl_approx_vnf.vnf_execute(cmd))
289 @mock.patch(SSH_HELPER)
290 def test_get_stats(self, ssh, *args):
293 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
294 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
295 acl_approx_vnf.q_in = mock.MagicMock()
296 acl_approx_vnf.q_out = mock.MagicMock()
297 acl_approx_vnf.q_out.qsize = mock.Mock(return_value=0)
298 result = "ACL TOTAL: pkts_processed: 100, pkts_drop: 0, spkts_received: 100"
299 acl_approx_vnf.vnf_execute = mock.Mock(return_value=result)
300 self.assertEqual(result, acl_approx_vnf.get_stats())
302 def _get_file_abspath(self, filename):
303 curr_path = os.path.dirname(os.path.abspath(__file__))
304 file_path = os.path.join(curr_path, filename)
307 @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.hex")
308 @mock.patch("yardstick.network_services.vnf_generic.vnf.acl_vnf.eval")
309 @mock.patch('yardstick.network_services.vnf_generic.vnf.acl_vnf.open')
310 @mock.patch(SSH_HELPER)
311 def test_run_acl(self, ssh, *args):
314 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
315 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
316 acl_approx_vnf._build_config = mock.MagicMock()
317 acl_approx_vnf.queue_wrapper = mock.MagicMock()
318 acl_approx_vnf.scenario_helper.scenario_cfg = self.scenario_cfg
319 acl_approx_vnf.vnf_cfg = {'lb_config': 'SW',
321 'worker_config': '1C/1T',
323 acl_approx_vnf.all_options = {'traffic_type': '4',
324 'topology': 'nsb_test_case.yaml'}
325 acl_approx_vnf._run()
326 acl_approx_vnf.ssh_helper.run.assert_called_once()
328 @mock.patch.object(utils, 'find_relative_file')
329 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context")
330 @mock.patch(SSH_HELPER)
331 def test_instantiate(self, ssh, *args):
334 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
335 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
336 acl_approx_vnf.deploy_helper = mock.MagicMock()
337 acl_approx_vnf.resource_helper = mock.MagicMock()
338 acl_approx_vnf._build_config = mock.MagicMock()
339 self.scenario_cfg['vnf_options'] = {'acl': {'cfg': "",
341 acl_approx_vnf.q_out.put("pipeline>")
342 acl_approx_vnf.WAIT_TIME = 0
343 self.scenario_cfg.update({"nodes": {"vnf__1": ""}})
344 self.assertIsNone(acl_approx_vnf.instantiate(self.scenario_cfg,
347 @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time")
348 @mock.patch(SSH_HELPER)
349 def test_terminate(self, ssh, *args):
352 vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
353 acl_approx_vnf = acl_vnf.AclApproxVnf(name, vnfd)
354 acl_approx_vnf._vnf_process = mock.MagicMock()
355 acl_approx_vnf._vnf_process.terminate = mock.Mock()
356 acl_approx_vnf.used_drivers = {"01:01.0": "i40e",
358 acl_approx_vnf.vnf_execute = mock.MagicMock()
359 acl_approx_vnf.dpdk_devbind = "dpdk-devbind.py"
360 acl_approx_vnf._resource_collect_stop = mock.Mock()
361 self.assertIsNone(acl_approx_vnf.terminate())
364 class TestAclApproxSetupEnvSetupEnvHelper(unittest.TestCase):
366 ACL_CONFIG = {"access-list-entries": [{
375 "destination-ipv4-network": "152.16.0.0/24",
376 "destination-port-range": {
380 "source-ipv4-network": "0.0.0.0/0",
381 "source-port-range": {
385 "protocol-mask": 255,
389 "rule-name": "rule1588"
393 def test_get_default_flows(self):
394 """Check if default ACL SampleVNF CLI commands are
395 generated correctly"""
396 ssh_helper = mock.Mock()
397 vnfd_helper = VnfdHelper({'vdu': [
398 {'external-interface': [
400 'virtual-interface': {
401 'local_ip': '152.16.100.19',
402 'netmask': '255.255.255.0',
404 'dst_ip': '152.16.100.20',
405 'vld_id': 'uplink_0',
408 'vnfd-connection-point-ref': 'xe0',
412 'virtual-interface': {
413 'local_ip': '152.16.40.19',
414 'netmask': '255.255.255.0',
416 'dst_ip': '152.16.40.20',
417 'vld_id': 'downlink_0',
420 'vnfd-connection-point-ref': 'xe1',
425 setup_helper = AclApproxSetupEnvSetupEnvHelper(vnfd_helper, ssh_helper, None)
426 self.check_acl_commands(setup_helper.get_flows_config(), [
427 # format: (<cli pattern>, <number of expected matches>)
428 ("^p action add [0-9]+ accept$", 2),
429 ("^p action add [0-9]+ count$", 2),
430 ("^p action add [0-9]+ fwd 1$", 1),
431 ("^p action add [0-9]+ fwd 0$", 1),
432 ("^p acl add 1 152.16.100.0 24 152.16.40.0 24 0 65535 0 65535 0 0 [0-9]+$", 1),
433 ("^p acl add 1 152.16.40.0 24 152.16.100.0 24 0 65535 0 65535 0 0 [0-9]+$", 1),
434 ("^p acl applyruleset$", 1)
437 @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
438 def test_get_flows_config(self, get_default_flows):
439 """Check if provided ACL config can be converted to
440 ACL SampleVNF CLI commands correctly"""
441 ssh_helper = mock.Mock()
442 setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
443 get_default_flows.return_value = ({}, [])
444 self.check_acl_commands(setup_helper.get_flows_config(self.ACL_CONFIG), [
445 # format: (<cli pattern>, <number of expected matches>)
446 ("^p action add [0-9]+ count$", 1),
447 ("^p action add [0-9]+ fwd 0$", 1),
448 ("^p acl add 1 0.0.0.0 0 152.16.0.0 24 0 65535 0 65535 127 0 [0-9]+$", 1),
449 ("^p acl applyruleset$", 1)
452 @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
453 def test_get_flows_config_invalid_action(self, get_default_flows):
454 """Check if incorrect ACL config fails to convert
455 to ACL SampleVNF CLI commands"""
456 ssh_helper = mock.Mock()
457 setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
458 get_default_flows.return_value = ({}, [])
459 # duplicate config and add invald action
460 acl_config = copy.deepcopy(self.ACL_CONFIG)
461 acl_config['access-list-entries'][0]["actions"].append({"xnat": {}})
462 self.assertRaises(exceptions.AclUknownActionTemplate,
463 setup_helper.get_flows_config, acl_config)
465 @mock.patch.object(AclApproxSetupEnvSetupEnvHelper, 'get_default_flows')
466 def test_get_flows_config_invalid_action_param(self, get_default_flows):
467 """Check if ACL config with invalid action parameter fails to convert
468 to ACL SampleVNF CLI commands"""
469 ssh_helper = mock.Mock()
470 setup_helper = AclApproxSetupEnvSetupEnvHelper(None, ssh_helper, None)
471 get_default_flows.return_value = ({}, [])
472 # duplicate config and add action with invalid parameter
473 acl_config = copy.deepcopy(self.ACL_CONFIG)
474 acl_config['access-list-entries'][0]["actions"].append(
475 {"nat": {"xport": 0}})
476 self.assertRaises(exceptions.AclMissingActionArguments,
477 setup_helper.get_flows_config, acl_config)
479 def check_acl_commands(self, config, expected_cli_patterns):
480 """Check if expected ACL CLI commands (given as a list of patterns,
481 `expected_cli_patterns` parameter) present in SampleVNF ACL
482 configuration (given as a multiline string, `config` parameter)"""
483 # Example of expected config:
484 # ---------------------------
485 # p action add 1 accept
486 # p action add 1 fwd 1
487 # p action add 2 accept
488 # p action add 2 count
489 # p action add 2 fwd 0
490 # p acl add 1 152.16.100.0 24 152.16.40.0 24 0 65535 0 65535 0 0 1
491 # p acl add 1 152.16.40.0 24 152.16.100.0 24 0 65535 0 65535 0 0 2
493 # ---------------------------
494 # NOTE: The config above consists of actions ids, which are actually
495 # unknown (generated at runtime), thus it's incorrect just to compare
496 # the example ACL config above with the configuration returned by
497 # get_flows_config() function. It's more correct to use CLI patterns
498 # (RE) to find the required SampleVNF CLI commands in the multiline
499 # string (SampleVNF ACL configuration).
500 for pattern, num_of_match in expected_cli_patterns:
501 # format: (<cli pattern>, <number of expected matches>)
502 result = re.findall(pattern, config, re.MULTILINE)
503 self.assertEqual(len(result), num_of_match)
505 @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.open')
506 @mock.patch.object(utils, 'find_relative_file')
507 @mock.patch('yardstick.network_services.vnf_generic.vnf.sample_vnf.MultiPortConfig')
508 @mock.patch.object(utils, 'open_relative_file')
509 def test_build_config(self, *args):
510 vnfd_helper = mock.Mock()
511 ssh_helper = mock.Mock()
512 scenario_helper = mock.Mock()
513 scenario_helper.vnf_cfg = {'lb_config': 'HW'}
514 scenario_helper.options = {}
515 scenario_helper.all_options = {}
517 acl_approx_setup_helper = AclApproxSetupEnvSetupEnvHelper(vnfd_helper,
521 acl_approx_setup_helper.get_flows_config = mock.Mock()
522 acl_approx_setup_helper.ssh_helper.provision_tool = mock.Mock(return_value='tool_path')
523 acl_approx_setup_helper.ssh_helper.all_ports = mock.Mock()
524 acl_approx_setup_helper.vnfd_helper.port_nums = mock.Mock(return_value=[0, 1])
525 expected = 'sudo tool_path -p 0x3 -f /tmp/acl_config -s /tmp/acl_script --hwlb 3'
526 self.assertEqual(acl_approx_setup_helper.build_config(), expected)
527 acl_approx_setup_helper.get_flows_config.assert_called_once()