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:
6 # http://www.apache.org/licenses/LICENSE-2.0
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.
14 """Performance testing traffic generator library."""
16 from robot.api import logger
17 from robot.libraries.BuiltIn import BuiltIn
19 from resources.libraries.python.ssh import SSH
20 from resources.libraries.python.topology import NodeType
21 from resources.libraries.python.topology import NodeSubTypeTG
22 from resources.libraries.python.topology import Topology
23 from resources.libraries.python.DropRateSearch import DropRateSearch
25 __all__ = ['TrafficGenerator', 'TGDropRateSearchImpl']
28 class TGDropRateSearchImpl(DropRateSearch):
29 """Drop Rate Search implementation."""
32 super(TGDropRateSearchImpl, self).__init__()
34 def measure_loss(self, rate, frame_size, loss_acceptance,
35 loss_acceptance_type, traffic_type):
37 # we need instance of TrafficGenerator instantiated by Robot Framework
38 # to be able to use trex_stateless_remote_exec method
39 tg_instance = BuiltIn().get_library_instance(
40 'resources.libraries.python.TrafficGenerator')
42 if tg_instance._node['subtype'] is None:
43 raise Exception('TG subtype not defined')
44 elif tg_instance._node['subtype'] == NodeSubTypeTG.TREX:
45 unit_rate = str(rate) + self.get_rate_type_str()
46 tg_instance.trex_stateless_remote_exec(self.get_duration(),
47 unit_rate, frame_size,
50 # TODO: getters for tg_instance and loss_acceptance_type
51 logger.trace("comparing: {} < {} ".format(tg_instance._loss,
53 if float(tg_instance._loss) > float(loss_acceptance):
58 raise NotImplementedError("TG subtype not supported")
61 class TrafficGenerator(object):
62 """Traffic Generator."""
64 # use one instance of TrafficGenerator for all tests in test suite
65 ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
73 # T-REX interface order mapping
74 self._ifaces_reordered = 0
76 def initialize_traffic_generator(self, tg_node, tg_if1, tg_if2,
77 dut1_node, dut1_if1, dut1_if2,
78 dut2_node, dut2_if1, dut2_if2,
82 :param tg_node: Traffic generator node.
83 :param tg_if1: TG - name of first interface.
84 :param tg_if2: TG - name of second interface.
85 :param dut1_node: DUT1 node.
86 :param dut1_if1: DUT1 - name of first interface.
87 :param dut1_if2: DUT1 - name of second interface.
88 :param dut2_node: DUT2 node.
89 :param dut2_if1: DUT2 - name of first interface.
90 :param dut2_if2: DUT2 - name of second interface.
91 :test_type: 'L2' or 'L3' - src/dst MAC address.
105 trex_path = "/opt/trex-core-2.00"
109 if tg_node['type'] != NodeType.TG:
110 raise Exception('Node type is not a TG')
113 if tg_node['subtype'] == NodeSubTypeTG.TREX:
117 if1_pci = topo.get_interface_pci_addr(tg_node, tg_if1)
118 if2_pci = topo.get_interface_pci_addr(tg_node, tg_if2)
119 if1_mac = topo.get_interface_mac(tg_node, tg_if1)
120 if2_mac = topo.get_interface_mac(tg_node, tg_if2)
122 if test_type == 'L2':
123 if1_adj_mac = if2_mac
124 if2_adj_mac = if1_mac
125 elif test_type == 'L3':
126 if1_adj_mac = topo.get_interface_mac(dut1_node, dut1_if1)
127 if2_adj_mac = topo.get_interface_mac(dut2_node, dut2_if2)
129 raise Exception("test_type unknown")
131 if min(if1_pci, if2_pci) != if1_pci:
132 if1_mac, if2_mac = if2_mac, if1_mac
133 if1_pci, if2_pci = if2_pci, if1_pci
134 if1_adj_mac, if2_adj_mac = if2_adj_mac, if1_adj_mac
135 self._ifaces_reordered = 1
137 if1_mac_hex = "0x"+if1_mac.replace(":", ",0x")
138 if2_mac_hex = "0x"+if2_mac.replace(":", ",0x")
139 if1_adj_mac_hex = "0x"+if1_adj_mac.replace(":", ",0x")
140 if2_adj_mac_hex = "0x"+if2_adj_mac.replace(":", ",0x")
142 (ret, stdout, stderr) = ssh.exec_command(
143 "sudo sh -c 'cat << EOF > /etc/trex_cfg.yaml\n"
146 " interfaces : [\"{}\",\"{}\"]\n"
147 " port_bandwidth_gb : 10\n"
149 " - dest_mac : [{}]\n"
151 " - dest_mac : [{}]\n"
154 .format(if1_pci, if2_pci,
155 if1_adj_mac_hex, if1_mac_hex,
156 if2_adj_mac_hex, if2_mac_hex))
158 logger.error("failed to create t-rex config: {}"\
159 .format(stdout + stderr))
160 raise RuntimeError('trex config generation error')
162 (ret, stdout, stderr) = ssh.exec_command(
163 "sh -c 'cd {0}/scripts/ && "
167 logger.error('trex-cfg failed: {0}'.format(stdout + stderr))
168 raise RuntimeError('trex-cfg failed')
170 (ret, _, _) = ssh.exec_command(
171 "sh -c 'cd {0}/scripts/ && "
172 "sudo nohup ./t-rex-64 -i -c 7 --iom 0 > /dev/null 2>&1 &'"
176 raise RuntimeError('t-rex-64 startup failed')
179 def teardown_traffic_generator(node):
182 :param node: Traffic generator node.
186 if node['type'] != NodeType.TG:
187 raise Exception('Node type is not a TG')
188 if node['subtype'] == NodeSubTypeTG.TREX:
191 (ret, stdout, stderr) = ssh.exec_command(
192 "sh -c 'sudo pkill t-rex'")
194 logger.error('pkill t-rex failed: {0}'.format(stdout + stderr))
195 raise RuntimeError('pkill t-rex failed')
197 def trex_stateless_remote_exec(self, duration, rate, framesize,
199 """Execute stateless script on remote node over ssh.
201 :param traffic_type: Traffic profile.
202 :type traffic_type: str
205 ssh.connect(self._node)
210 if self._ifaces_reordered != 0:
213 if traffic_type in ["3-node-xconnect", "3-node-bridge"]:
214 (ret, stdout, stderr) = ssh.exec_command(
215 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
216 "t-rex-stateless.py "
217 "-d {0} -r {1} -s {2} "
218 "--p{3}_src_start_ip 10.10.10.1 "
219 "--p{3}_src_end_ip 10.10.10.254 "
220 "--p{3}_dst_start_ip 20.20.20.1 "
221 "--p{4}_src_start_ip 20.20.20.1 "
222 "--p{4}_src_end_ip 20.20.20.254 "
223 "--p{4}_dst_start_ip 10.10.10.1'".\
224 format(duration, rate, framesize, _p0, _p1),\
225 timeout=int(duration)+60)
226 elif traffic_type in ["3-node-IPv4"]:
227 (ret, stdout, stderr) = ssh.exec_command(
228 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
229 "t-rex-stateless.py "
230 "-d {0} -r {1} -s {2} "
231 "--p{3}_src_start_ip 10.10.10.2 "
232 "--p{3}_src_end_ip 10.10.10.254 "
233 "--p{3}_dst_start_ip 20.20.20.2 "
234 "--p{4}_src_start_ip 20.20.20.2 "
235 "--p{4}_src_end_ip 20.20.20.254 "
236 "--p{4}_dst_start_ip 10.10.10.2'".\
237 format(duration, rate, framesize, _p0, _p1),\
238 timeout=int(duration)+60)
239 elif traffic_type in ["3-node-IPv6"]:
240 (ret, stdout, stderr) = ssh.exec_command(
241 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
242 "t-rex-stateless.py "
243 "-d {0} -r {1} -s {2} -6 "
244 "--p{3}_src_start_ip 2001:1::2 "
245 "--p{3}_src_end_ip 2001:1::FE "
246 "--p{3}_dst_start_ip 2001:2::2 "
247 "--p{4}_src_start_ip 2001:2::2 "
248 "--p{4}_src_end_ip 2001:2::FE "
249 "--p{4}_dst_start_ip 2001:1::2'".\
250 format(duration, rate, framesize, _p0, _p1),\
251 timeout=int(duration)+60)
253 raise NotImplementedError('Unsupported traffic type')
260 raise RuntimeError('T-rex stateless runtime error')
262 # last line from console output
263 line = stdout.splitlines()[-1]
266 logger.info('TrafficGen result: {0}'.format(self._result))
268 self._received = self._result.split(', ')[1].split('=')[1]
269 self._sent = self._result.split(', ')[2].split('=')[1]
270 self._loss = self._result.split(', ')[3].split('=')[1]
272 def send_traffic_on(self, node, duration, rate,
273 framesize, traffic_type):
274 """Send traffic from all configured interfaces on TG.
276 :param node: Dictionary containing TG information.
277 :param duration: Duration of test traffic generation in seconds.
278 :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...).
279 :param framesize: Frame size (L2) in Bytes.
280 :param traffic_type: Traffic profile.
285 :type traffic_type: str
289 if node['type'] != NodeType.TG:
290 raise Exception('Node type is not a TG')
292 if node['subtype'] is None:
293 raise Exception('TG subtype not defined')
294 elif node['subtype'] == NodeSubTypeTG.TREX:
295 self.trex_stateless_remote_exec(duration, rate, framesize,
298 raise NotImplementedError("TG subtype not supported")
302 def no_traffic_loss_occurred(self):
303 """Fail is loss occurred in traffic run.
307 if self._loss is None:
308 raise Exception('The traffic generation has not been issued')
309 if self._loss != '0':
310 raise Exception('Traffic loss occurred: {0}'.format(self._loss))