def find_binary(cls, ip_version, interval, length, host, marking=None, local_bind=None): """Find a suitable ping executable, looking first for a compatible `fping`, then falling back to the `ping` binary. Binaries are checked for the required capabilities.""" if ip_version == 6: suffix = "6" else: suffix = "" fping = util.which('fping'+suffix) ping = util.which('ping'+suffix) if fping is not None: proc = subprocess.Popen([fping, '-h'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out,err = proc.communicate() # check for presence of timestamp option if "print timestamp before each output line" in str(out): return "{binary} -D -p {interval:.0f} -c {count:.0f} {marking} {local_bind} {host}".format( binary=fping, interval=interval * 1000, # fping expects interval in milliseconds # since there's no timeout parameter for fping, calculate a total number # of pings to send count=length // interval + 1, marking="-O {0}".format(marking) if marking else "", local_bind="-I {0}".format(local_bind) if local_bind else "", host=host) elif "must run as root?" in str(err): sys.stderr.write("Found fping but it seems to be missing permissions (no SUID?). Not using.\n") if ping is not None: # Ping can't handle hostnames for the -I parameter, so do a lookup first. if local_bind: local_bind=util.lookup_host(local_bind, ip_version)[4][0] # Try parsing the output of 'ping' and complain if no data is # returned from the parser. This should pick up e.g. the ping on OSX # not having a -D option and allow us to supply a better error message. proc = subprocess.Popen([ping, '-D', '-n', '-c', '1', 'localhost'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out,err = proc.communicate() if hasattr(out, 'decode'): out = out.decode(ENCODING) if not cls._parse(out)[0]: raise RuntimeError("Cannot parse output of the system ping binary ({ping}). " "Please install fping v3.5+.".format(ping=ping)) return "{binary} -n -D -i {interval:.2f} -w {length:d} {marking} {local_bind} {host}".format( binary=ping, interval=max(0.2, interval), length=length, marking="-Q {0}".format(marking) if marking else "", local_bind="-I {0}".format(local_bind) if local_bind else "", host=host) raise RuntimeError("No suitable ping tool found.")
def find_binary(cls, host, interval, length, ip_version, local_bind=None, no_delay=False, udp=False, bw=None): iperf = util.which('iperf') if iperf is not None: proc = subprocess.Popen([iperf, '-h'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out,err = proc.communicate() if "--enhancedreports" in str(err): if udp: udp_args = "--udp --bandwidth {}".format(bw if bw else "100M") else: udp_args = "" return "{binary} --enhancedreports --reportstyle C --format m --client {host} --time {length} --interval {interval} " \ "{local_bind} {no_delay} {udp} {ip6}".format( host=host, binary=iperf, length=length, interval=interval, ip6="--ipv6_domain" if ip_version == 6 else "", # --help output is wrong local_bind="--bind {0}".format(local_bind) if local_bind else "", no_delay="--nodelay" if no_delay else "", udp=udp_args) else: sys.stderr.write("Found iperf binary, but it does not have an --enhancedreport option. Not using.\n") raise RuntimeError("No suitable Iperf binary found.")
def find_binary(cls, host, interval, length, ip_version, local_bind=None, no_delay=False, udp=False): iperf = util.which('iperf') if iperf is not None: proc = subprocess.Popen([iperf, '-h'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() if "--enhancedreports" in str(err): return "{binary} --enhancedreports --reportstyle C --format m --client {host} --time {length} --interval {interval} " \ "{local_bind} {no_delay} {udp} {ip6}".format( host=host, binary=iperf, length=length, interval=interval, ip6="--ipv6_domain" if ip_version == 6 else "", # --help output is wrong local_bind="--bind {0}".format(local_bind) if local_bind else "", no_delay="--nodelay" if no_delay else "", udp="--udp" if udp else "") else: sys.stderr.write( "Found iperf binary, but it does not have an --enhancedreport option. Not using.\n" ) raise RuntimeError("No suitable Iperf binary found.")
def find_itgsend(self, test_args, length, host): if self.itgsend is None: self.itgsend = util.which("ITGSend", fail=True) # We put placeholders in the command string to be filled out by string # format expansion by the runner once it has communicated with the control # server and obtained the port values. return "{binary} -Sdp {{signal_port}} -t {length} -a {dest_host} -rp {{dest_port}} {args}".format( binary=self.itgsend, length=int(length * 1000), dest_host=host, args=test_args )
def find_itgsend(self, test_args, length, host): if self.itgsend is None: self.itgsend = util.which("ITGSend", fail=True) # We put placeholders in the command string to be filled out by string # format expansion by the runner once it has communicated with the control # server and obtained the port values. return "{binary} -Sdp {{signal_port}} -t {length} -a {dest_host} -rp {{dest_port}} {args}".format( binary=self.itgsend, length=int(length * 1000), dest_host=host, args=test_args)
def find_http_getter(self, interval, length, workers=None, ip_version=None, dns_servers=None, url_file=None, timeout=None): args = "-i %d -l %d" % (int(interval * 1000.0), length) if url_file is None: url_file = self.env['HTTP_GETTER_URLLIST'] if dns_servers is None: dns_servers = self.env['HTTP_GETTER_DNS'] if timeout is None: timeout = self.env['HTTP_GETTER_TIMEOUT'] if workers is None: workers = self.env['HTTP_GETTER_WORKERS'] if ip_version is None: ip_version = self.env['IP_VERSION'] if ip_version == 4: args += " -4" elif ip_version == 6: args += " -6" if timeout is None: args += " -t %d" % int(length * 1000) else: args += " -t %d" % timeout if workers is not None: args += " -n %d" % workers if dns_servers is not None: args += " -d '%s'" % dns_servers if url_file is None: args += " http://%s/filelist.txt" % self.env['HOST'] else: args += " %s" % url_file if self.http_getter is None: self.http_getter = util.which('http-getter', fail=True) return "%s %s" % (self.http_getter, args)
def find_binary(cls, interval, length, host='localhost'): script = os.path.join(DATA_DIR, 'scripts', 'stat_iterate.sh') if not os.path.exists(script): raise RuntimeError("Cannot find stat_iterate.sh.") bash = util.which('bash') if not bash: raise RuntimeError("TC stats requires a Bash shell.") return "{bash} {script} -I {interval:.2f} -c {count:.0f} -H {host}".format( bash=bash, script=script, interval=interval, count=length // interval + 1, host=host)
def find_binary(cls, interval, length, host='localhost'): script = os.path.join(DATA_DIR, 'scripts', 'stat_iterate.sh') if not os.path.exists(script): raise RuntimeError("Cannot find stat_iterate.sh.") bash = util.which('bash') if not bash: raise RuntimeError("CPU stats requires a Bash shell.") return "{bash} {script} -I {interval:.2f} -c {count:.0f} -H {host}".format( bash=bash, script=script, interval=interval, count=length // interval + 1, host=host)
def find_http_getter( self, interval, length, workers=None, ip_version=None, dns_servers=None, url_file=None, timeout=None ): args = "-i %d -l %d" % (int(interval * 1000.0), length) if url_file is None: url_file = self.env["HTTP_GETTER_URLLIST"] if dns_servers is None: dns_servers = self.env["HTTP_GETTER_DNS"] if timeout is None: timeout = self.env["HTTP_GETTER_TIMEOUT"] if workers is None: workers = self.env["HTTP_GETTER_WORKERS"] if ip_version is None: ip_version = self.env["IP_VERSION"] if ip_version == 4: args += " -4" elif ip_version == 6: args += " -6" if timeout is None: args += " -t %d" % int(length * 1000) else: args += " -t %d" % timeout if workers is not None: args += " -n %d" % workers if dns_servers is not None: args += " -d '%s'" % dns_servers if url_file is None: args += " http://%s/filelist.txt" % self.env["HOST"] else: args += " %s" % url_file if self.http_getter is None: self.http_getter = util.which("http-getter", fail=True) return "%s %s" % (self.http_getter, args)
def find_binary(cls, interface, interval, length): script = os.path.join(DATA_DIR, 'scripts', 'tc_iterate.sh') if not os.path.exists(script): raise RuntimeError("Cannot find tc_iterate.sh.") bash = util.which('bash') if not bash: raise RuntimeError("TC stats requires a Bash shell.") if interface is None: sys.stderr.write("Warning: No interface given for tc runner. Defaulting to 'eth0'.\n") interface='eth0' return "{bash} {script} -i {interface} -I {interval:.2f} -c {count:.0f}".format( bash=bash, script=script, interface=interface, interval=interval, count=length // interval + 1)
def find_binary(cls, interface, interval, length, host='localhost'): script = os.path.join(DATA_DIR, 'scripts', 'tc_iterate.sh') if not os.path.exists(script): raise RuntimeError("Cannot find tc_iterate.sh.") bash = util.which('bash') if not bash: raise RuntimeError("TC stats requires a Bash shell.") if interface is None: sys.stderr.write("Warning: No interface given for tc runner. Defaulting to 'eth0'.\n") interface='eth0' return "{bash} {script} -i {interface} -I {interval:.2f} -c {count:.0f} -H {host}".format( bash=bash, script=script, interface=interface, interval=interval, count=length // interval + 1, host=host)
def find_itgsend(self, test_args, length, host, local_bind=None): if local_bind is None: local_bind = self.env['LOCAL_BIND'][ 0] if self.env['LOCAL_BIND'] else None if self.itgsend is None: self.itgsend = util.which("ITGSend", fail=True) # We put placeholders in the command string to be filled out by string # format expansion by the runner once it has communicated with the control # server and obtained the port values. return "{binary} -Sdp {{signal_port}} -t {length} {local_bind} " \ "-a {dest_host} -rp {{dest_port}} {args}".format( binary=self.itgsend, length=int(length * 1000), dest_host=host, local_bind="-sa {0} -Ssa {0}".format( local_bind) if local_bind else "", args=test_args)
def find_itgsend(self, test_args, length, host, local_bind=None): if local_bind is None: local_bind = self.env['LOCAL_BIND'][0] if self.env[ 'LOCAL_BIND'] else None if self.itgsend is None: self.itgsend = util.which("ITGSend", fail=True) # We put placeholders in the command string to be filled out by string # format expansion by the runner once it has communicated with the control # server and obtained the port values. return "{binary} -Sdp {{signal_port}} -t {length} {local_bind} " \ "-a {dest_host} -rp {{dest_port}} {args}".format( binary=self.itgsend, length=int(length * 1000), dest_host=host, local_bind="-sa {0} -Ssa {0}".format( local_bind) if local_bind else "", args=test_args)
def find_netperf(self, test, length, host, **args): """Find a suitable netperf executable, and test for the required capabilities.""" if self.netperf is None: netperf = util.which('netperf', fail=True) # Try to figure out whether this version of netperf supports the -e # option for socket timeout on UDP_RR tests, and whether it has been # compiled with --enable-demo. Unfortunately, the --help message is # not very helpful for this, so the only way to find out is try to # invoke it and check for an error message. This has the side-effect # of having netperf attempt a connection to localhost, which can # stall, so we kill the process almost immediately. proc = subprocess.Popen( [netperf, '-l', '1', '-D', '-0.2', '--', '-e', '1'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) time.sleep( 0.1 ) # should be enough time for netperf to output any error messages proc.kill() out, err = proc.communicate() if "Demo Mode not configured" in str(out): raise RuntimeError("%s does not support demo mode." % netperf) if "invalid option -- '0'" in str(err): raise RuntimeError( "%s does not support accurate intermediate time reporting. You need netperf v2.6.0 or newer." % netperf) self.netperf = {'executable': netperf, "-e": False} if not "netperf: invalid option -- 'e'" in str(err): self.netperf['-e'] = True args.setdefault('ip_version', self.env['IP_VERSION']) args.setdefault('interval', self.env['STEP_SIZE']) args.setdefault('control_host', self.env['CONTROL_HOST'] or host) args.setdefault('local_bind', self.env['LOCAL_BIND'] or "") args.setdefault('control_local_bind', self.env['CONTROL_LOCAL_BIND'] or args['local_bind']) args.setdefault('extra_args', "") args.setdefault('extra_test_args', "") args.setdefault('format', "") args.setdefault('marking', "") args.setdefault('socket_timeout', "") if self.env['SWAP_UPDOWN']: if test == 'TCP_STREAM': test = 'TCP_MAERTS' elif test == 'TCP_MAERTS': test = 'TCP_STREAM' args.update({ 'binary': self.netperf['executable'], 'host': host, 'test': test, 'length': length }) if args['marking']: args['marking'] = "-Y {0}".format(args['marking']) for c in 'local_bind', 'control_local_bind': if args[c]: args[c] = "-L {0}".format(args[c]) if test == "UDP_RR" and self.netperf["-e"]: args['socket_timeout'] = "-e {0:d}".format( self.env['SOCKET_TIMEOUT']) elif test in ("TCP_STREAM", "TCP_MAERTS", "omni"): args['format'] = "-f m" return "{binary} -P 0 -v 0 -D -{interval:.2f} -{ip_version} {marking} -H {control_host} -t {test} " \ "-l {length:d} {format} {control_local_bind} {extra_args} -- {socket_timeout} {local_bind} -H {host} " \ "{extra_test_args}".format(**args)
def find_netperf(self, test, length, host, **args): """Find a suitable netperf executable, and test for the required capabilities.""" if self.netperf is None: netperf = util.which("netperf", fail=True) # Try to figure out whether this version of netperf supports the -e # option for socket timeout on UDP_RR tests, and whether it has been # compiled with --enable-demo. Unfortunately, the --help message is # not very helpful for this, so the only way to find out is try to # invoke it and check for an error message. This has the side-effect # of having netperf attempt a connection to localhost, which can # stall, so we kill the process almost immediately. proc = subprocess.Popen( [netperf, "-l", "1", "-D", "-0.2", "--", "-e", "1"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) time.sleep(0.1) # should be enough time for netperf to output any error messages proc.kill() out, err = proc.communicate() if "Demo Mode not configured" in str(out): raise RuntimeError("%s does not support demo mode." % netperf) if "invalid option -- '0'" in str(err): raise RuntimeError( "%s does not support accurate intermediate time reporting. You need netperf v2.6.0 or newer." % netperf ) self.netperf = {"executable": netperf, "-e": False} if not "netperf: invalid option -- 'e'" in str(err): self.netperf["-e"] = True args.setdefault("ip_version", self.env["IP_VERSION"]) args.setdefault("interval", self.env["STEP_SIZE"]) args.setdefault("control_host", self.env["CONTROL_HOST"] or host) args.setdefault("local_bind", self.env["LOCAL_BIND"] or "") args.setdefault("control_local_bind", self.env["CONTROL_LOCAL_BIND"] or args["local_bind"]) args.setdefault("extra_args", "") args.setdefault("extra_test_args", "") args.setdefault("format", "") args.setdefault("marking", "") args.setdefault("socket_timeout", "") if self.env["SWAP_UPDOWN"]: if test == "TCP_STREAM": test = "TCP_MAERTS" elif test == "TCP_MAERTS": test = "TCP_STREAM" args.update({"binary": self.netperf["executable"], "host": host, "test": test, "length": length}) if args["marking"]: args["marking"] = "-Y {0}".format(args["marking"]) for c in "local_bind", "control_local_bind": if args[c]: args[c] = "-L {0}".format(args[c]) if test == "UDP_RR" and self.netperf["-e"]: args["socket_timeout"] = "-e {0:d}".format(self.env["SOCKET_TIMEOUT"]) elif test in ("TCP_STREAM", "TCP_MAERTS", "omni"): args["format"] = "-f m" return ( "{binary} -P 0 -v 0 -D -{interval:.2f} -{ip_version} {marking} -H {control_host} -t {test} " "-l {length:d} {format} {control_local_bind} {extra_args} -- {socket_timeout} {local_bind} -H {host} " "{extra_test_args}".format(**args) )
def setUp(self): sysctl = util.which("sysctl") if sysctl is None: self.skipTest("Could not find sysctl utility")
def find_netperf(self, test, length, host, **args): """Find a suitable netperf executable, and test for the required capabilities.""" if self.netperf is None: netperf = util.which('netperf', fail=True) # Try to figure out whether this version of netperf supports the -e # option for socket timeout on UDP_RR tests, and whether it has been # compiled with --enable-demo. Unfortunately, the --help message is # not very helpful for this, so the only way to find out is try to # invoke it and check for an error message. This has the side-effect # of having netperf attempt a connection to localhost, which can # stall, so we kill the process almost immediately. proc = subprocess.Popen([netperf, '-l', '1', '-D', '-0.2', '--', '-e', '1'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) time.sleep(0.1) # should be enough time for netperf to output any error messages proc.kill() out,err = proc.communicate() if "Demo Mode not configured" in str(out): raise RuntimeError("%s does not support demo mode." % netperf) if "invalid option -- '0'" in str(err): raise RuntimeError("%s does not support accurate intermediate time reporting. You need netperf v2.6.0 or newer." % netperf) self.netperf = {'executable': netperf, "-e": False} if not "netperf: invalid option -- 'e'" in str(err): self.netperf['-e'] = True args.setdefault('ip_version', self.env['IP_VERSION']) args.setdefault('interval', self.env['STEP_SIZE']) args.setdefault('control_host', self.env['CONTROL_HOST'] or host) args.setdefault('local_bind', self.env['LOCAL_BIND'] or "") args.setdefault('control_local_bind', self.env['CONTROL_LOCAL_BIND'] or args['local_bind']) args.setdefault('extra_args', "") args.setdefault('extra_test_args', "") args.setdefault('format', "") args.setdefault('marking', "") args.setdefault('socket_timeout', "") if self.env['SWAP_UPDOWN']: if test == 'TCP_STREAM': test = 'TCP_MAERTS' elif test == 'TCP_MAERTS': test = 'TCP_STREAM' args.update({'binary': self.netperf['executable'], 'host': host, 'test': test, 'length': length}) if args['marking']: args['marking'] = "-Y {0}".format(args['marking']) for c in 'local_bind', 'control_local_bind': if args[c]: args[c] = "-L {0}".format(args[c]) if test == "UDP_RR" and self.netperf["-e"]: args['socket_timeout'] = "-e {0:d}".format(self.env['SOCKET_TIMEOUT']) elif test in ("TCP_STREAM", "TCP_MAERTS", "omni"): args['format'] = "-f m" return "{binary} -P 0 -v 0 -D -{interval:.2f} -{ip_version} {marking} -H {control_host} -t {test} " \ "-l {length:d} {format} {control_local_bind} {extra_args} -- {socket_timeout} {local_bind} -H {host} " \ "{extra_test_args}".format(**args)