Performance suite reorg, v4 tests
[csit.git] / resources / libraries / python / TrafficGenerator.py
1 # Copyright (c) 2016 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Performance testing traffic generator library."""
15
16 from robot.api import logger
17
18 from resources.libraries.python.ssh import SSH
19 from resources.libraries.python.topology import NodeType
20 from resources.libraries.python.topology import NodeSubTypeTG
21 from resources.libraries.python.topology import Topology
22
23 __all__ = ['TrafficGenerator']
24
25 class TrafficGenerator(object):
26     """Traffic Generator"""
27
28     ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
29
30     def __init__(self):
31         self._result = None
32         self._loss = None
33         self._sent = None
34         self._received = None
35         #T-REX interface order mapping
36         self._ifaces_reordered = 0
37
38     def initialize_traffic_generator(self, tg_node, tg_if1, tg_if2,
39                                      dut1_node, dut1_if1, dut1_if2,
40                                      dut2_node, dut2_if1, dut2_if2,
41                                      test_type):
42         """TG initialization
43         :param tg_node: Traffic generator node
44         :param tg_if1: TG - name of first interface
45         :param tg_if2: TG - name of second interface
46         :param dut1_node: DUT1 node
47         :param dut1_if1: DUT1 - name of first interface
48         :param dut1_if2: DUT1 - name of second interface
49         :param dut2_node: DUT2 node
50         :param dut2_if1: DUT2 - name of first interface
51         :param dut2_if2: DUT2 - name of second interface
52         :test_type: 'L2' or 'L3' - src/dst MAC address
53         :type tg_node: dict
54         :type tg_if1: str
55         :type tg_if2: str
56         :type dut1_node: dict
57         :type dut1_if1: str
58         :type dut1_if2: str
59         :type dut2_node: dict
60         :type dut2_if1: str
61         :type dut2_if2: str
62         :type test_type: str
63         :return: nothing
64         """
65
66         trex_path = "/opt/trex-core-1.91"
67
68         topo = Topology()
69
70         if tg_node['type'] != NodeType.TG:
71             raise Exception('Node type is not a TG')
72         if tg_node['subtype'] == NodeSubTypeTG.TREX:
73             ssh = SSH()
74             ssh.connect(tg_node)
75
76             if1_pci = topo.get_interface_pci_addr(tg_node, tg_if1)
77             if2_pci = topo.get_interface_pci_addr(tg_node, tg_if2)
78             if1_mac = topo.get_interface_mac(tg_node, tg_if1)
79             if2_mac = topo.get_interface_mac(tg_node, tg_if2)
80
81             if test_type == 'L2':
82                 if1_adj_mac = if2_mac
83                 if2_adj_mac = if1_mac
84             elif test_type == 'L3':
85                 if1_adj_mac = topo.get_interface_mac(dut1_node, dut1_if1)
86                 if2_adj_mac = topo.get_interface_mac(dut2_node, dut2_if2)
87             else:
88                 raise Exception("test_type unknown")
89
90             if min(if1_pci, if2_pci) != if1_pci:
91                 if1_mac, if2_mac = if2_mac, if1_mac
92                 if1_pci, if2_pci = if2_pci, if1_pci
93                 if1_adj_mac, if2_adj_mac = if2_adj_mac, if1_adj_mac
94                 self._ifaces_reordered = 1
95
96             if1_mac_hex = "0x"+if1_mac.replace(":", ",0x")
97             if2_mac_hex = "0x"+if2_mac.replace(":", ",0x")
98             if1_adj_mac_hex = "0x"+if1_adj_mac.replace(":", ",0x")
99             if2_adj_mac_hex = "0x"+if2_adj_mac.replace(":", ",0x")
100
101             (ret, stdout, stderr) = ssh.exec_command(
102                 "sudo sh -c 'cat << EOF > /etc/trex_cfg.yaml\n"
103                 "- port_limit      : 2\n"
104                 "  version         : 2\n"
105                 "  interfaces      : [\"{}\",\"{}\"]\n"
106                 "  port_info       :\n"
107                 "          - dest_mac        :   [{}]\n"
108                 "            src_mac         :   [{}]\n"
109                 "          - dest_mac        :   [{}]\n"
110                 "            src_mac         :   [{}]\n"
111                 "EOF'"\
112                 .format(if1_pci, if2_pci,
113                         if1_adj_mac_hex, if1_mac_hex,
114                         if2_adj_mac_hex, if2_mac_hex))
115             if int(ret) != 0:
116                 logger.error("failed to create t-rex config: {}"\
117                 .format(stdout + stderr))
118                 raise RuntimeError('trex config generation error')
119
120             (ret, stdout, stderr) = ssh.exec_command(
121                 "sh -c 'cd {0}/scripts/ && "
122                 "sudo ./trex-cfg'"\
123                 .format(trex_path))
124             if int(ret) != 0:
125                 logger.error('trex-cfg failed: {0}'.format(stdout + stderr))
126                 raise RuntimeError('trex-cfg failed')
127
128             (ret, _, _) = ssh.exec_command(
129                 "sh -c 'cd {0}/scripts/ && "
130                 "sudo nohup ./t-rex-64 -i -c 4 --iom 0 > /dev/null 2>&1 &'"
131                 "> /dev/null"\
132                 .format(trex_path))
133             if int(ret) != 0:
134                 raise RuntimeError('t-rex-64 startup failed')
135
136     @staticmethod
137     def teardown_traffic_generator(node):
138         """TG teardown
139         :param node: Traffic generator node
140         :type node: dict
141         :return: nothing
142         """
143
144         if node['type'] != NodeType.TG:
145             raise Exception('Node type is not a TG')
146         if node['subtype'] == NodeSubTypeTG.TREX:
147             ssh = SSH()
148             ssh.connect(node)
149             (ret, stdout, stderr) = ssh.exec_command(
150                 "sh -c 'sudo pkill t-rex'")
151             if int(ret) != 0:
152                 logger.error('pkill t-rex failed: {0}'.format(stdout + stderr))
153                 raise RuntimeError('pkill t-rex failed')
154
155     def send_traffic_on(self, nodes_info, duration, rate,
156                         framesize, traffic_type):
157         """Send traffic from all configured interfaces on TG
158         :param nodes_info: Dictionary containing information on all nodes
159         in topology.
160         :param duration: Duration of test traffic generation in seconds
161         :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...)
162         :param framesize: Frame size (L2) in Bytes
163         :param traffic_type: Traffic profile
164         :type nodes_info: dict
165         :type duration: str
166         :type rate: str
167         :type framesize: str
168         :type traffic_type: str
169         :return: TG output
170         :rtype: str
171         """
172
173         node = nodes_info["TG"]
174
175         if node['type'] != NodeType.TG:
176             raise Exception('Node type is not a TG')
177
178         if node['subtype'] is None:
179             raise Exception('TG subtype not defined')
180
181         ssh = SSH()
182         ssh.connect(node)
183
184         if node['subtype'] == NodeSubTypeTG.TREX:
185
186             _p0 = 1
187             _p1 = 2
188
189             if self._ifaces_reordered != 0:
190                 _p0, _p1 = _p1, _p0
191
192             if traffic_type in ["3-node-xconnect", "3-node-bridge"]:
193                 (ret, stdout, stderr) = ssh.exec_command(
194                     "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
195                     "t-rex-stateless.py "
196                     "-d {0} -r {1} -s {2} "
197                     "--p{3}_src_start_ip 10.10.10.1 "
198                     "--p{3}_src_end_ip 10.10.10.254 "
199                     "--p{3}_dst_start_ip 20.20.20.1 "
200                     "--p{4}_src_start_ip 20.20.20.1 "
201                     "--p{4}_src_end_ip 20.20.20.254 "
202                     "--p{4}_dst_start_ip 10.10.10.1'".\
203                     format(duration, rate, framesize, _p0, _p1),\
204                     timeout=int(duration)+60)
205             elif traffic_type in ["3-node-IPv4"]:
206                 (ret, stdout, stderr) = ssh.exec_command(
207                     "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
208                     "t-rex-stateless.py "
209                     "-d {0} -r {1} -s {2} "
210                     "--p{3}_src_start_ip 10.10.10.2 "
211                     "--p{3}_src_end_ip 10.10.10.254 "
212                     "--p{3}_dst_start_ip 20.20.20.2 "
213                     "--p{4}_src_start_ip 20.20.20.2 "
214                     "--p{4}_src_end_ip 20.20.20.254 "
215                     "--p{4}_dst_start_ip 10.10.10.2'".\
216                     format(duration, rate, framesize, _p0, _p1),\
217                     timeout=int(duration)+60)
218             else:
219                 raise NotImplementedError('Unsupported traffic type')
220
221         else:
222             raise NotImplementedError("TG subtype not supported")
223
224         logger.trace(ret)
225         logger.trace(stdout)
226         logger.trace(stderr)
227
228         for line in stdout.splitlines():
229             pass
230
231         self._result = line
232         logger.info('TrafficGen result: {0}'.format(self._result))
233
234         self._loss = self._result.split(', ')[3].split('=')[1]
235
236         return self._result
237
238     def no_traffic_loss_occured(self):
239         """Fail is loss occured in traffic run
240         :return: nothing
241         """
242
243         if self._loss is None:
244             raise Exception('The traffic generation has not been issued')
245         if self._loss != '0':
246             raise Exception('Traffic loss occured: {0}'.format(self._loss))