Merge "Add scale out TCs with availability zone support"
[yardstick.git] / yardstick / tests / unit / network_services / vnf_generic / vnf / test_tg_trex.py
1 # Copyright (c) 2016-2017 Intel Corporation
2 #
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
6 #
7 #      http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 import copy
16
17 import mock
18 import unittest
19
20 from yardstick.network_services.traffic_profile import base as tp_base
21 from yardstick.network_services.traffic_profile import rfc2544
22 from yardstick.network_services.vnf_generic.vnf import sample_vnf
23 from yardstick.network_services.vnf_generic.vnf import tg_trex
24
25
26 NAME = 'vnf_1'
27
28
29 class TestTrexTrafficGen(unittest.TestCase):
30
31     VNFD = {'vnfd:vnfd-catalog':
32             {'vnfd':
33              [{'short-name': 'VpeVnf',
34                'vdu':
35                [{'routing_table':
36                              [{'network': '152.16.100.20',
37                                'netmask': '255.255.255.0',
38                                'gateway': '152.16.100.20',
39                                'if': 'xe0'},
40                               {'network': '152.16.40.20',
41                                'netmask': '255.255.255.0',
42                                'gateway': '152.16.40.20',
43                                'if': 'xe1'}],
44                              'description': 'VPE approximation using DPDK',
45                              'name': 'vpevnf-baremetal',
46                              'nd_route_tbl':
47                                  [{'network': '0064:ff9b:0:0:0:0:9810:6414',
48                                    'netmask': '112',
49                                    'gateway': '0064:ff9b:0:0:0:0:9810:6414',
50                                    'if': 'xe0'},
51                                   {'network': '0064:ff9b:0:0:0:0:9810:2814',
52                                    'netmask': '112',
53                                    'gateway': '0064:ff9b:0:0:0:0:9810:2814',
54                                    'if': 'xe1'}],
55                              'id': 'vpevnf-baremetal',
56                              'external-interface':
57                                  [{'virtual-interface':
58                                    {'dst_mac': '00:00:00:00:00:04',
59                                     'vpci': '0000:05:00.0',
60                                     'local_ip': '152.16.100.19',
61                                     'type': 'PCI-PASSTHROUGH',
62                                     'netmask': '255.255.255.0',
63                                     'dpdk_port_num': 0,
64                                     'bandwidth': '10 Gbps',
65                                     'driver': "i40e",
66                                     'dst_ip': '152.16.100.20',
67                                     'local_iface_name': 'xe0',
68                                     'vld_id': 'downlink_0',
69                                     'ifname': 'xe0',
70                                     'local_mac': '00:00:00:00:00:02'},
71                                    'vnfd-connection-point-ref': 'xe0',
72                                    'name': 'xe0'},
73                                   {'virtual-interface':
74                                    {'dst_mac': '00:00:00:00:00:03',
75                                     'vpci': '0000:05:00.1',
76                                     'local_ip': '152.16.40.19',
77                                     'type': 'PCI-PASSTHROUGH',
78                                     'driver': "i40e",
79                                     'netmask': '255.255.255.0',
80                                     'dpdk_port_num': 1,
81                                     'bandwidth': '10 Gbps',
82                                     'dst_ip': '152.16.40.20',
83                                     'local_iface_name': 'xe1',
84                                     'vld_id': 'uplink_0',
85                                     'ifname': 'xe1',
86                                     'local_mac': '00:00:00:00:00:01'},
87                                    'vnfd-connection-point-ref': 'xe1',
88                                    'name': 'xe1'}]}],
89                'description': 'Vpe approximation using DPDK',
90                'mgmt-interface':
91                {'vdu-id': 'vpevnf-baremetal',
92                 'host': '1.1.1.1',
93                 'password': 'r00t',
94                             'user': 'root',
95                             'ip': '1.1.1.1'},
96                'benchmark':
97                {'kpi': ['packets_in', 'packets_fwd',
98                         'packets_dropped']},
99                'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
100                                     {'type': 'VPORT', 'name': 'xe1'}],
101                'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}}
102
103     TRAFFIC_PROFILE = {
104         "schema": "isb:traffic_profile:0.1",
105         "name": "fixed",
106         "description": "Fixed traffic profile to run UDP traffic",
107         "traffic_profile": {
108             "traffic_type": "FixedTraffic",
109             "frame_rate": 100,  # pps
110             "flow_number": 10,
111             "frame_size": 64
112         },
113     }
114
115     SCENARIO_CFG = {
116         "options": {
117             "packetsize": 64,
118             "traffic_type": 4,
119             "rfc2544": {
120                 "allowed_drop_rate": "0.8 - 1",
121             },
122             "vnf__1": {
123                 "rules": "acl_1rule.yaml",
124                 "vnf_config": {
125                     "lb_config": "SW",
126                     "lb_count": 1,
127                     "worker_config": "1C/1T",
128                     "worker_threads": 1,
129                 }
130             }
131         },
132         "task_id": "a70bdf4a-8e67-47a3-9dc1-273c14506eb7",
133         "tc": "tc_ipv4_1Mflow_64B_packetsize",
134         "runner": {
135             "object": "NetworkServiceTestCase",
136             "interval": 35,
137             "output_filename": "/tmp/yardstick.out",
138             "runner_id": 74476, "duration": 400,
139             "type": "Duration"
140         },
141         "traffic_profile": "ipv4_throughput_acl.yaml",
142         "traffic_options": {
143             "flow": "ipv4_Packets_acl.yaml",
144             "imix": "imix_voice.yaml"
145         },
146         "type": "ISB",
147         "nodes": {
148             "tg__2": "trafficgen_2.yardstick",
149             "tg__1": "trafficgen_1.yardstick",
150             "vnf__1": "vnf.yardstick"
151         },
152         "topology": "udpreplay-tg-topology-baremetal.yaml"
153     }
154
155     CONTEXT_CFG = {
156         "nodes": {
157             "vnf__1": {
158                 "vnfd-id-ref": "vnf__1",
159                 "ip": "1.2.1.1",
160                 "interfaces": {
161                     "xe0": {
162                         "local_iface_name": "ens786f0",
163                         "vld_id": tp_base.TrafficProfile.UPLINK,
164                         "netmask": "255.255.255.0",
165                         "vpci": "0000:05:00.0",
166                         "local_ip": "152.16.100.19",
167                         "driver": "i40e",
168                         "dst_ip": "152.16.100.20",
169                         "local_mac": "00:00:00:00:00:02",
170                         "dst_mac": "00:00:00:00:00:04",
171                         "dpdk_port_num": 0
172                     },
173                     "xe1": {
174                         "local_iface_name": "ens786f1",
175                         "vld_id": tp_base.TrafficProfile.DOWNLINK,
176                         "netmask": "255.255.255.0",
177                         "vpci": "0000:05:00.1",
178                         "local_ip": "152.16.40.19",
179                         "driver": "i40e",
180                         "dst_ip": "152.16.40.20",
181                         "local_mac": "00:00:00:00:00:01",
182                         "dst_mac": "00:00:00:00:00:03",
183                         "dpdk_port_num": 1
184                     }
185                 },
186                 "host": "1.2.1.1",
187                 "user": "root",
188                 "nd_route_tbl": [
189                     {
190                         "netmask": "112",
191                         "if": "xe0",
192                         "gateway": "0064:ff9b:0:0:0:0:9810:6414",
193                         "network": "0064:ff9b:0:0:0:0:9810:6414"
194                     },
195                     {
196                         "netmask": "112",
197                         "if": "xe1",
198                         "gateway": "0064:ff9b:0:0:0:0:9810:2814",
199                         "network": "0064:ff9b:0:0:0:0:9810:2814"
200                     }
201                 ],
202                 "password": "r00t",
203                 "VNF model": "udp_replay.yaml",
204                 "name": "vnf.yardstick",
205                 "member-vnf-index": "2",
206                 "routing_table": [
207                     {
208                         "netmask": "255.255.255.0",
209                         "if": "xe0",
210                         "gateway": "152.16.100.20",
211                         "network": "152.16.100.20"
212                     },
213                     {
214                         "netmask": "255.255.255.0",
215                         "if": "xe1",
216                         "gateway": "152.16.40.20",
217                         "network": "152.16.40.20"
218                     }
219                 ],
220                 "role": "vnf"
221             },
222             "trafficgen_2.yardstick": {
223                 "member-vnf-index": "3",
224                 "role": "TrafficGen",
225                 "name": "trafficgen_2.yardstick",
226                 "vnfd-id-ref": "tg__2",
227                 "ip": "1.2.1.1",
228                 "interfaces": {
229                     "xe0": {
230                         "local_iface_name": "ens513f0",
231                         "vld_id": tp_base.TrafficProfile.DOWNLINK,
232                         "netmask": "255.255.255.0",
233                         "vpci": "0000:02:00.0",
234                         "local_ip": "152.16.40.20",
235                         "driver": "ixgbe",
236                         "dst_ip": "152.16.40.19",
237                         "local_mac": "00:00:00:00:00:03",
238                         "dst_mac": "00:00:00:00:00:01",
239                         "dpdk_port_num": 0
240                     },
241                     "xe1": {
242                         "local_iface_name": "ens513f1",
243                         "netmask": "255.255.255.0",
244                         "network": "202.16.100.0",
245                         "local_ip": "202.16.100.20",
246                         "driver": "ixgbe",
247                         "local_mac": "00:1e:67:d0:60:5d",
248                         "vpci": "0000:02:00.1",
249                         "dpdk_port_num": 1
250                     }
251                 },
252                 "password": "r00t",
253                 "VNF model": "l3fwd_vnf.yaml",
254                 "user": "root"
255             },
256             "trafficgen_1.yardstick": {
257                 "member-vnf-index": "1",
258                 "role": "TrafficGen",
259                 "name": "trafficgen_1.yardstick",
260                 "vnfd-id-ref": "tg__1",
261                 "ip": "1.2.1.1",
262                 "interfaces": {
263                     "xe0": {
264                         "local_iface_name": "ens785f0",
265                         "vld_id": tp_base.TrafficProfile.UPLINK,
266                         "netmask": "255.255.255.0",
267                         "vpci": "0000:05:00.0",
268                         "local_ip": "152.16.100.20",
269                         "driver": "i40e",
270                         "dst_ip": "152.16.100.19",
271                         "local_mac": "00:00:00:00:00:04",
272                         "dst_mac": "00:00:00:00:00:02",
273                         "dpdk_port_num": 0
274                     },
275                     "xe1": {
276                         "local_ip": "152.16.100.21",
277                         "driver": "i40e",
278                         "vpci": "0000:05:00.1",
279                         "dpdk_port_num": 1,
280                         "local_iface_name": "ens785f1",
281                         "netmask": "255.255.255.0",
282                         "local_mac": "00:00:00:00:00:01"
283                     }
284                 },
285                 "password": "r00t",
286                 "VNF model": "tg_rfc2544_tpl.yaml",
287                 "user": "root"
288             }
289         }
290     }
291
292     def setUp(self):
293         self._mock_ssh_helper = mock.patch.object(sample_vnf, 'VnfSshHelper')
294         self.mock_ssh_helper = self._mock_ssh_helper.start()
295         self.addCleanup(self._stop_mocks)
296
297     def _stop_mocks(self):
298         self._mock_ssh_helper.stop()
299
300     def test___init__(self):
301         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
302         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
303         self.assertIsInstance(trex_traffic_gen.resource_helper,
304                               tg_trex.TrexResourceHelper)
305
306     def test_collect_kpi(self):
307         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
308         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
309         trex_traffic_gen.resource_helper._queue.put({})
310         result = trex_traffic_gen.collect_kpi()
311         self.assertEqual({}, result)
312
313     def test_listen_traffic(self):
314         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
315         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
316         self.assertIsNone(trex_traffic_gen.listen_traffic({}))
317
318     def test_instantiate(self):
319         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
320         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
321         trex_traffic_gen._start_server = mock.Mock(return_value=0)
322         trex_traffic_gen._tg_process = mock.MagicMock()
323         trex_traffic_gen._tg_process.start = mock.Mock()
324         trex_traffic_gen._tg_process.exitcode = 0
325         trex_traffic_gen._tg_process._is_alive = mock.Mock(return_value=1)
326         trex_traffic_gen.ssh_helper = mock.MagicMock()
327         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
328         trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock()
329         self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG,
330                                                        self.CONTEXT_CFG))
331
332     def test_instantiate_error(self):
333         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
334         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
335         trex_traffic_gen._start_server = mock.Mock(return_value=0)
336         trex_traffic_gen._tg_process = mock.MagicMock()
337         trex_traffic_gen._tg_process.start = mock.Mock()
338         trex_traffic_gen._tg_process._is_alive = mock.Mock(return_value=0)
339         trex_traffic_gen.ssh_helper = mock.MagicMock()
340         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
341         trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock()
342         self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG,
343                                                        self.CONTEXT_CFG))
344
345     def test__start_server(self):
346         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
347         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
348         trex_traffic_gen.ssh_helper = mock.MagicMock()
349         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
350         trex_traffic_gen.scenario_helper.scenario_cfg = {}
351         self.assertIsNone(trex_traffic_gen._start_server())
352
353     def test__start_server_multiple_queues(self):
354         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
355         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
356         trex_traffic_gen.ssh_helper = mock.MagicMock()
357         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
358         trex_traffic_gen.scenario_helper.scenario_cfg = {
359             "options": {NAME: {"queues_per_port": 2}}}
360         self.assertIsNone(trex_traffic_gen._start_server())
361
362     def test__traffic_runner(self):
363         mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
364         mock_traffic_profile.get_traffic_definition.return_value = "64"
365         mock_traffic_profile.execute_traffic.return_value = "64"
366         mock_traffic_profile.params = self.TRAFFIC_PROFILE
367
368         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
369         self.sut = tg_trex.TrexTrafficGen(NAME, vnfd)
370         self.sut.ssh_helper = mock.Mock()
371         self.sut.ssh_helper.run = mock.Mock()
372         self.sut._connect_client = mock.Mock()
373         self.sut._connect_client.get_stats = mock.Mock(return_value="0")
374         self.sut.resource_helper.RUN_DURATION = 0
375         self.sut.resource_helper.QUEUE_WAIT_TIME = 0
376         # must generate cfg before we can run traffic so Trex port mapping is
377         # created
378         self.sut.resource_helper.generate_cfg()
379         with mock.patch.object(self.sut.resource_helper, 'run_traffic'):
380             self.sut._traffic_runner(mock_traffic_profile)
381
382     def test__generate_trex_cfg(self):
383         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
384         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
385         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
386         self.assertIsNone(trex_traffic_gen.resource_helper.generate_cfg())
387
388     def test_build_ports_reversed_pci_ordering(self):
389         vnfd = copy.deepcopy(self.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
390         vnfd['vdu'][0]['external-interface'] = [
391             {'virtual-interface':
392              {'dst_mac': '00:00:00:00:00:04',
393               'vpci': '0000:05:00.0',
394               'local_ip': '152.16.100.19',
395               'type': 'PCI-PASSTHROUGH',
396               'netmask': '255.255.255.0',
397               'dpdk_port_num': 2,
398               'bandwidth': '10 Gbps',
399               'driver': "i40e",
400               'dst_ip': '152.16.100.20',
401               'local_iface_name': 'xe0',
402               'vld_id': 'downlink_0',
403               'ifname': 'xe0',
404               'local_mac': '00:00:00:00:00:02'},
405              'vnfd-connection-point-ref': 'xe0',
406              'name': 'xe0'},
407             {'virtual-interface':
408              {'dst_mac': '00:00:00:00:00:03',
409               'vpci': '0000:04:00.0',
410               'local_ip': '152.16.40.19',
411               'type': 'PCI-PASSTHROUGH',
412               'driver': "i40e",
413               'netmask': '255.255.255.0',
414               'dpdk_port_num': 0,
415               'bandwidth': '10 Gbps',
416               'dst_ip': '152.16.40.20',
417               'local_iface_name': 'xe1',
418               'vld_id': 'uplink_0',
419               'ifname': 'xe1',
420               'local_mac': '00:00:00:00:00:01'},
421              'vnfd-connection-point-ref': 'xe1',
422              'name': 'xe1'}]
423         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
424         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
425         trex_traffic_gen.resource_helper.generate_cfg()
426         trex_traffic_gen.resource_helper._build_ports()
427         self.assertEqual(sorted(trex_traffic_gen.resource_helper.all_ports),
428                          [0, 1])
429         # there is a gap in ordering
430         self.assertEqual(
431             {0: 0, 2: 1},
432             dict(trex_traffic_gen.resource_helper.dpdk_to_trex_port_map))
433
434     def test_run_traffic(self):
435         mock_traffic_profile = mock.Mock(autospec=tp_base.TrafficProfile)
436         mock_traffic_profile.get_traffic_definition.return_value = "64"
437         mock_traffic_profile.params = self.TRAFFIC_PROFILE
438
439         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
440         self.sut = tg_trex.TrexTrafficGen(NAME, vnfd)
441         self.sut.ssh_helper = mock.Mock()
442         self.sut.ssh_helper.run = mock.Mock()
443         self.sut._traffic_runner = mock.Mock(return_value=0)
444         self.sut.resource_helper.client_started.value = 1
445         result = self.sut.run_traffic(mock_traffic_profile)
446         self.sut._traffic_process.terminate()
447         self.assertIsNotNone(result)
448
449     def test_terminate(self):
450         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
451         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
452         trex_traffic_gen.ssh_helper = mock.MagicMock()
453         trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock()
454         self.assertIsNone(trex_traffic_gen.terminate())
455
456     def test__connect_client(self):
457         vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
458         trex_traffic_gen = tg_trex.TrexTrafficGen(NAME, vnfd)
459         client = mock.Mock()
460         client.connect = mock.Mock(return_value=0)
461         self.assertIsNotNone(trex_traffic_gen.resource_helper._connect(client))
462
463
464 class TrexResourceHelperTestCase(unittest.TestCase):
465
466     def test__get_samples(self):
467         mock_setup_helper = mock.Mock()
468         trex_rh = tg_trex.TrexResourceHelper(mock_setup_helper)
469         trex_rh.vnfd_helper.interfaces = [
470             {'name': 'interface1'},
471             {'name': 'interface2'}]
472         stats = {
473             10: {'rx_pps': 5, 'ipackets': 200},
474             20: {'rx_pps': 10, 'ipackets': 300},
475             'latency': {1: {'latency': 'latency_port_10_pg_id_1'},
476                         2: {'latency': 'latency_port_10_pg_id_2'},
477                         3: {'latency': 'latency_port_20_pg_id_3'},
478                         4: {'latency': 'latency_port_20_pg_id_4'}}
479         }
480         port_pg_id = rfc2544.PortPgIDMap()
481         port_pg_id.add_port(10)
482         port_pg_id.increase_pg_id()
483         port_pg_id.increase_pg_id()
484         port_pg_id.add_port(20)
485         port_pg_id.increase_pg_id()
486         port_pg_id.increase_pg_id()
487
488         with mock.patch.object(trex_rh, 'get_stats') as mock_get_stats, \
489                 mock.patch.object(trex_rh.vnfd_helper, 'port_num') as \
490                 mock_port_num:
491             mock_get_stats.return_value = stats
492             mock_port_num.side_effect = [10, 20]
493             output = trex_rh._get_samples([10, 20], port_pg_id=port_pg_id)
494
495         interface = output['interface1']
496         self.assertEqual(5.0, interface['rx_throughput_fps'])
497         self.assertEqual(200, interface['in_packets'])
498         self.assertEqual('latency_port_10_pg_id_1', interface['latency'][1])
499         self.assertEqual('latency_port_10_pg_id_2', interface['latency'][2])
500
501         interface = output['interface2']
502         self.assertEqual(10.0, interface['rx_throughput_fps'])
503         self.assertEqual(300, interface['in_packets'])
504         self.assertEqual('latency_port_20_pg_id_3', interface['latency'][3])
505         self.assertEqual('latency_port_20_pg_id_4', interface['latency'][4])