1 # Copyright 2016 Intel Corporation.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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 """ Vsperf specific scenario definition """
16 from __future__ import absolute_import
22 import yardstick.ssh as ssh
23 from yardstick.benchmark.scenarios import base
25 LOG = logging.getLogger(__name__)
28 class Vsperf(base.Scenario):
29 """Execute vsperf with defined parameters
32 traffic_type - to specify the type of traffic executed by traffic generator
33 the valid values are "rfc2544", "continuous", "back2back"
36 frame_size - a frame size for which test should be executed;
37 Multiple frame sizes can be tested by modification of sequence runner
38 section inside TC YAML definition.
41 bidirectional - speficies if traffic will be uni (False) or bi-directional
45 iload - specifies frame rate
48 multistream - the number of simulated streams
51 stream_type - specifies network layer used for multistream simulation
52 the valid values are "L4", "L3" and "L2"
55 test_params - specifies a string with a list of vsperf configuration
56 parameters, which will be passed to the '--test-params' CLI argument;
57 Parameters should be stated in the form of 'param=value' and separated
58 by a semicolon. Please check VSPERF documentation for details about
59 available configuration parameters and their data types.
60 In case that both 'test_params' and 'conf_file' are specified,
61 then values from 'test_params' will override values defined
62 in the configuration file.
65 conf_file - path to the vsperf configuration file, which will be uploaded
67 In case that both 'test_params' and 'conf_file' are specified,
68 then values from 'test_params' will override values defined
69 in configuration file.
72 setup_script - path to the setup script, which will be executed during
73 setup and teardown phases
76 trafficgen_port1 - specifies device name of 1st interface connected to
80 trafficgen_port2 - specifies device name of 2nd interface connected to
84 external_bridge - specifies name of external bridge configured in OVS
89 __scenario_type__ = "Vsperf"
91 def __init__(self, scenario_cfg, context_cfg):
92 self.scenario_cfg = scenario_cfg
93 self.context_cfg = context_cfg
94 self.setup_done = False
96 self.tg_port1 = self.scenario_cfg['options'].get('trafficgen_port1',
98 self.tg_port2 = self.scenario_cfg['options'].get('trafficgen_port2',
100 self.br_ex = self.scenario_cfg['options'].get('external_bridge',
102 self.vsperf_conf = self.scenario_cfg['options'].get('conf_file', None)
104 self.vsperf_conf = os.path.expanduser(self.vsperf_conf)
106 self.setup_script = self.scenario_cfg['options'].get('setup_script',
108 if self.setup_script:
109 self.setup_script = os.path.expanduser(self.setup_script)
111 self.test_params = self.scenario_cfg['options'].get('test-params',
116 vsperf = self.context_cfg['host']
117 vsperf_user = vsperf.get('user', 'ubuntu')
118 vsperf_ssh_port = vsperf.get('ssh_port', ssh.DEFAULT_PORT)
119 vsperf_password = vsperf.get('password', 'ubuntu')
120 vsperf_ip = vsperf.get('ip', None)
122 # add trafficgen interfaces to the external bridge
124 subprocess.call('sudo bash -c "ovs-vsctl add-port %s %s"' %
125 (self.br_ex, self.tg_port1), shell=True)
127 subprocess.call('sudo bash -c "ovs-vsctl add-port %s %s"' %
128 (self.br_ex, self.tg_port2), shell=True)
130 # copy vsperf conf to VM
131 LOG.info("user:%s, host:%s", vsperf_user, vsperf_ip)
132 self.client = ssh.SSH(vsperf_user, vsperf_ip,
133 password=vsperf_password, port=vsperf_ssh_port)
134 # traffic generation could last long
135 self.client.wait(timeout=1800)
137 # copy script to host
138 self.client._put_file_shell(self.vsperf_conf, '~/vsperf.conf')
140 # execute external setup script
141 if self.setup_script:
142 cmd = "%s setup" % (self.setup_script)
143 LOG.info("Execute setup script \"%s\"", cmd)
144 subprocess.call(cmd, shell=True)
146 self.setup_done = True
148 def run(self, result):
149 """ execute the vsperf benchmark and return test results
150 within result dictionary
152 def add_test_params(options, option, default_value):
153 """return parameter and its value as a string to be passed
154 to the VSPERF inside --test-params argument
157 options - dictionary with scenario options
158 option - a name of option to be added to the string
159 default_value - value to be used in case that option
160 is not defined inside scenario options
162 if option in options:
163 return "%s=%s" % (option, options[option])
164 elif default_value is not None:
165 return "%s=%s" % (option, default_value)
169 if not self.setup_done:
172 # remove results from previous tests
173 self.client.execute("rm -rf /tmp/results*")
176 options = self.scenario_cfg['options']
178 test_params.append(add_test_params(options, "traffic_type", "rfc2544"))
179 test_params.append(add_test_params(options, "bidirectional", "False"))
180 test_params.append(add_test_params(options, "iload", 100))
181 test_params.append(add_test_params(options, "multistream", None))
182 test_params.append(add_test_params(options, "stream_type", None))
183 if 'frame_size' in options:
184 test_params.append("%s=(%s,)" % ('TRAFFICGEN_PKT_SIZES',
185 options['frame_size']))
186 if 'test_params' in options:
187 test_params.append(options['test_params'])
189 # filter empty parameters and escape quotes and double quotes
190 test_params = [tp.replace('"', '\\"').replace("'", "\\'")
191 for tp in test_params if tp]
194 cmd = "source ~/vsperfenv/bin/activate ; cd vswitchperf ; "
195 cmd += "./vsperf --mode trafficgen "
197 cmd += "--conf-file ~/vsperf.conf "
198 cmd += "--test-params=\"%s\"" % (';'.join(test_params))
199 LOG.debug("Executing command: %s", cmd)
200 status, stdout, stderr = self.client.execute(cmd)
203 raise RuntimeError(stderr)
206 cmd = "cat /tmp/results*/result.csv"
207 LOG.debug("Executing command: %s", cmd)
208 status, stdout, stderr = self.client.execute(cmd)
211 raise RuntimeError(stderr)
213 # convert result.csv to JSON format
214 reader = csv.DictReader(stdout.split('\r\n'))
215 result.update(next(reader))
217 # sla check; go through all defined SLAs and check if values measured
218 # by VSPERF are higher then those defined by SLAs
219 if 'sla' in self.scenario_cfg and \
220 'metrics' in self.scenario_cfg['sla']:
221 for metric in self.scenario_cfg['sla']['metrics'].split(','):
222 assert metric in result, \
223 '%s is not collected by VSPERF' % (metric)
224 assert metric in self.scenario_cfg['sla'], \
225 '%s is not defined in SLA' % (metric)
226 vs_res = float(result[metric])
227 sla_res = float(self.scenario_cfg['sla'][metric])
228 assert vs_res >= sla_res, \
229 'VSPERF_%s(%f) < SLA_%s(%f)' % \
230 (metric, vs_res, metric, sla_res)
233 """cleanup after the test execution"""
234 # remove trafficgen interfaces from the external bridge
236 subprocess.call('sudo bash -c "ovs-vsctl del-port %s %s"' %
237 (self.br_ex, self.tg_port1), shell=True)
239 subprocess.call('sudo bash -c "ovs-vsctl del-port %s %s"' %
240 (self.br_ex, self.tg_port2), shell=True)
242 # execute external setup script
243 if self.setup_script:
244 cmd = "%s teardown" % (self.setup_script)
245 LOG.info("Execute setup script \"%s\"", cmd)
246 subprocess.call(cmd, shell=True)
248 self.setup_done = False