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 'pgrep t-rex && sudo pkill t-rex'")
173 (ret, _, _) = ssh.exec_command(
174 "sh -c 'cd {0}/scripts/ && "
175 "sudo nohup ./t-rex-64 -i -c 7 --iom 0 > /dev/null 2>&1 &'"
179 raise RuntimeError('t-rex-64 startup failed')
182 def teardown_traffic_generator(node):
185 :param node: Traffic generator node.
189 if node['type'] != NodeType.TG:
190 raise Exception('Node type is not a TG')
191 if node['subtype'] == NodeSubTypeTG.TREX:
194 (ret, stdout, stderr) = ssh.exec_command(
195 "sh -c 'sudo pkill t-rex'")
197 logger.error('pkill t-rex failed: {0}'.format(stdout + stderr))
198 raise RuntimeError('pkill t-rex failed')
200 def trex_stateless_remote_exec(self, duration, rate, framesize,
202 """Execute stateless script on remote node over ssh.
204 :param traffic_type: Traffic profile.
205 :type traffic_type: str
208 ssh.connect(self._node)
213 if self._ifaces_reordered != 0:
216 if traffic_type in ["3-node-xconnect", "3-node-bridge"]:
217 (ret, stdout, stderr) = ssh.exec_command(
218 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
219 "t-rex-stateless.py "
220 "-d {0} -r {1} -s {2} "
221 "--p{3}_src_start_ip 10.10.10.1 "
222 "--p{3}_src_end_ip 10.10.10.254 "
223 "--p{3}_dst_start_ip 20.20.20.1 "
224 "--p{4}_src_start_ip 20.20.20.1 "
225 "--p{4}_src_end_ip 20.20.20.254 "
226 "--p{4}_dst_start_ip 10.10.10.1'".\
227 format(duration, rate, framesize, _p0, _p1),\
228 timeout=int(duration)+60)
229 elif traffic_type in ["3-node-IPv4"]:
230 (ret, stdout, stderr) = ssh.exec_command(
231 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
232 "t-rex-stateless.py "
233 "-d {0} -r {1} -s {2} "
234 "--p{3}_src_start_ip 10.10.10.2 "
235 "--p{3}_src_end_ip 10.10.10.254 "
236 "--p{3}_dst_start_ip 20.20.20.2 "
237 "--p{4}_src_start_ip 20.20.20.2 "
238 "--p{4}_src_end_ip 20.20.20.254 "
239 "--p{4}_dst_start_ip 10.10.10.2'".\
240 format(duration, rate, framesize, _p0, _p1),\
241 timeout=int(duration)+60)
242 elif traffic_type in ["3-node-IPv6"]:
243 (ret, stdout, stderr) = ssh.exec_command(
244 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
245 "t-rex-stateless.py "
246 "-d {0} -r {1} -s {2} -6 "
247 "--p{3}_src_start_ip 2001:1::2 "
248 "--p{3}_src_end_ip 2001:1::FE "
249 "--p{3}_dst_start_ip 2001:2::2 "
250 "--p{4}_src_start_ip 2001:2::2 "
251 "--p{4}_src_end_ip 2001:2::FE "
252 "--p{4}_dst_start_ip 2001:1::2'".\
253 format(duration, rate, framesize, _p0, _p1),\
254 timeout=int(duration)+60)
256 raise NotImplementedError('Unsupported traffic type')
263 raise RuntimeError('T-rex stateless runtime error')
265 # last line from console output
266 line = stdout.splitlines()[-1]
269 logger.info('TrafficGen result: {0}'.format(self._result))
271 self._received = self._result.split(', ')[1].split('=')[1]
272 self._sent = self._result.split(', ')[2].split('=')[1]
273 self._loss = self._result.split(', ')[3].split('=')[1]
275 def send_traffic_on(self, node, duration, rate,
276 framesize, traffic_type):
277 """Send traffic from all configured interfaces on TG.
279 :param node: Dictionary containing TG information.
280 :param duration: Duration of test traffic generation in seconds.
281 :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...).
282 :param framesize: Frame size (L2) in Bytes.
283 :param traffic_type: Traffic profile.
288 :type traffic_type: str
292 if node['type'] != NodeType.TG:
293 raise Exception('Node type is not a TG')
295 if node['subtype'] is None:
296 raise Exception('TG subtype not defined')
297 elif node['subtype'] == NodeSubTypeTG.TREX:
298 self.trex_stateless_remote_exec(duration, rate, framesize,
301 raise NotImplementedError("TG subtype not supported")
305 def no_traffic_loss_occurred(self):
306 """Fail is loss occurred in traffic run.
310 if self._loss is None:
311 raise Exception('The traffic generation has not been issued')
312 if self._loss != '0':
313 raise Exception('Traffic loss occurred: {0}'.format(self._loss))