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
18 from robot.api.deco import keyword
20 from resources.libraries.python.ssh import SSH
21 from resources.libraries.python.topology import NodeType
22 from resources.libraries.python.topology import NodeSubTypeTG
23 from resources.libraries.python.topology import Topology
24 from resources.libraries.python.DropRateSearch import DropRateSearch
26 __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('resources.libraries.python.TrafficGenerator')
41 if tg_instance._node['subtype'] is None:
42 raise Exception('TG subtype not defined')
43 elif tg_instance._node['subtype'] == NodeSubTypeTG.TREX:
44 unit_rate = str(rate) + self.get_rate_type_str()
45 tg_instance.trex_stateless_remote_exec(self.get_duration(), unit_rate,
46 frame_size, traffic_type)
48 #TODO:getters for tg_instance and loss_acceptance_type
49 logger.trace("comparing: {} < {} ".format(tg_instance._loss, loss_acceptance))
50 if float(tg_instance._loss) > float(loss_acceptance):
55 raise NotImplementedError("TG subtype not supported")
57 class TrafficGenerator(object):
58 """Traffic Generator"""
60 #use one instance of TrafficGenerator for all tests in test suite
61 ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
69 #T-REX interface order mapping
70 self._ifaces_reordered = 0
72 def initialize_traffic_generator(self, tg_node, tg_if1, tg_if2,
73 dut1_node, dut1_if1, dut1_if2,
74 dut2_node, dut2_if1, dut2_if2,
77 :param tg_node: Traffic generator node
78 :param tg_if1: TG - name of first interface
79 :param tg_if2: TG - name of second interface
80 :param dut1_node: DUT1 node
81 :param dut1_if1: DUT1 - name of first interface
82 :param dut1_if2: DUT1 - name of second interface
83 :param dut2_node: DUT2 node
84 :param dut2_if1: DUT2 - name of first interface
85 :param dut2_if2: DUT2 - name of second interface
86 :test_type: 'L2' or 'L3' - src/dst MAC address
100 trex_path = "/opt/trex-core-1.91"
104 if tg_node['type'] != NodeType.TG:
105 raise Exception('Node type is not a TG')
108 if tg_node['subtype'] == NodeSubTypeTG.TREX:
112 if1_pci = topo.get_interface_pci_addr(tg_node, tg_if1)
113 if2_pci = topo.get_interface_pci_addr(tg_node, tg_if2)
114 if1_mac = topo.get_interface_mac(tg_node, tg_if1)
115 if2_mac = topo.get_interface_mac(tg_node, tg_if2)
117 if test_type == 'L2':
118 if1_adj_mac = if2_mac
119 if2_adj_mac = if1_mac
120 elif test_type == 'L3':
121 if1_adj_mac = topo.get_interface_mac(dut1_node, dut1_if1)
122 if2_adj_mac = topo.get_interface_mac(dut2_node, dut2_if2)
124 raise Exception("test_type unknown")
126 if min(if1_pci, if2_pci) != if1_pci:
127 if1_mac, if2_mac = if2_mac, if1_mac
128 if1_pci, if2_pci = if2_pci, if1_pci
129 if1_adj_mac, if2_adj_mac = if2_adj_mac, if1_adj_mac
130 self._ifaces_reordered = 1
132 if1_mac_hex = "0x"+if1_mac.replace(":", ",0x")
133 if2_mac_hex = "0x"+if2_mac.replace(":", ",0x")
134 if1_adj_mac_hex = "0x"+if1_adj_mac.replace(":", ",0x")
135 if2_adj_mac_hex = "0x"+if2_adj_mac.replace(":", ",0x")
137 (ret, stdout, stderr) = ssh.exec_command(
138 "sudo sh -c 'cat << EOF > /etc/trex_cfg.yaml\n"
141 " interfaces : [\"{}\",\"{}\"]\n"
142 " port_bandwidth_gb : 10\n"
144 " - dest_mac : [{}]\n"
146 " - dest_mac : [{}]\n"
149 .format(if1_pci, if2_pci,
150 if1_adj_mac_hex, if1_mac_hex,
151 if2_adj_mac_hex, if2_mac_hex))
153 logger.error("failed to create t-rex config: {}"\
154 .format(stdout + stderr))
155 raise RuntimeError('trex config generation error')
157 (ret, stdout, stderr) = ssh.exec_command(
158 "sh -c 'cd {0}/scripts/ && "
162 logger.error('trex-cfg failed: {0}'.format(stdout + stderr))
163 raise RuntimeError('trex-cfg failed')
165 (ret, _, _) = ssh.exec_command(
166 "sh -c 'cd {0}/scripts/ && "
167 "sudo nohup ./t-rex-64 -i -c 4 --iom 0 > /dev/null 2>&1 &'"
171 raise RuntimeError('t-rex-64 startup failed')
174 def teardown_traffic_generator(node):
176 :param node: Traffic generator node
181 if node['type'] != NodeType.TG:
182 raise Exception('Node type is not a TG')
183 if node['subtype'] == NodeSubTypeTG.TREX:
186 (ret, stdout, stderr) = ssh.exec_command(
187 "sh -c 'sudo pkill t-rex'")
189 logger.error('pkill t-rex failed: {0}'.format(stdout + stderr))
190 raise RuntimeError('pkill t-rex failed')
192 def trex_stateless_remote_exec(self, duration, rate, framesize,
194 """Execute stateless script on remote node over ssh
196 :param node: remote node
197 :param traffic_type: Traffic profile
199 :type traffic_type: str
202 ssh.connect(self._node)
207 if self._ifaces_reordered != 0:
210 if traffic_type in ["3-node-xconnect", "3-node-bridge"]:
211 (ret, stdout, stderr) = ssh.exec_command(
212 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
213 "t-rex-stateless.py "
214 "-d {0} -r {1} -s {2} "
215 "--p{3}_src_start_ip 10.10.10.1 "
216 "--p{3}_src_end_ip 10.10.10.254 "
217 "--p{3}_dst_start_ip 20.20.20.1 "
218 "--p{4}_src_start_ip 20.20.20.1 "
219 "--p{4}_src_end_ip 20.20.20.254 "
220 "--p{4}_dst_start_ip 10.10.10.1'".\
221 format(duration, rate, framesize, _p0, _p1),\
222 timeout=int(duration)+60)
223 elif traffic_type in ["3-node-IPv4"]:
224 (ret, stdout, stderr) = ssh.exec_command(
225 "sh -c '/tmp/openvpp-testing/resources/tools/t-rex/"
226 "t-rex-stateless.py "
227 "-d {0} -r {1} -s {2} "
228 "--p{3}_src_start_ip 10.10.10.2 "
229 "--p{3}_src_end_ip 10.10.10.254 "
230 "--p{3}_dst_start_ip 20.20.20.2 "
231 "--p{4}_src_start_ip 20.20.20.2 "
232 "--p{4}_src_end_ip 20.20.20.254 "
233 "--p{4}_dst_start_ip 10.10.10.2'".\
234 format(duration, rate, framesize, _p0, _p1),\
235 timeout=int(duration)+60)
237 raise NotImplementedError('Unsupported traffic type')
243 #last line from console output
244 line = stdout.splitlines()[-1]
247 logger.info('TrafficGen result: {0}'.format(self._result))
249 self._received = self._result.split(', ')[1].split('=')[1]
250 self._sent = self._result.split(', ')[2].split('=')[1]
251 self._loss = self._result.split(', ')[3].split('=')[1]
253 def send_traffic_on(self, node, duration, rate,
254 framesize, traffic_type):
255 """Send traffic from all configured interfaces on TG
256 :param node: Dictionary containing TG information
257 :param duration: Duration of test traffic generation in seconds
258 :param rate: Offered load per interface (e.g. 1%, 3gbps, 4mpps, ...)
259 :param framesize: Frame size (L2) in Bytes
260 :param traffic_type: Traffic profile
265 :type traffic_type: str
270 if node['type'] != NodeType.TG:
271 raise Exception('Node type is not a TG')
273 if node['subtype'] is None:
274 raise Exception('TG subtype not defined')
275 elif node['subtype'] == NodeSubTypeTG.TREX:
276 self.trex_stateless_remote_exec(duration, rate, framesize,
279 raise NotImplementedError("TG subtype not supported")
283 def no_traffic_loss_occured(self):
284 """Fail is loss occured in traffic run
288 if self._loss is None:
289 raise Exception('The traffic generation has not been issued')
290 if self._loss != '0':
291 raise Exception('Traffic loss occured: {0}'.format(self._loss))