Skip to content

Instantly share code, notes, and snippets.

@bturrubiates
Created January 2, 2018 17:43
Show Gist options
  • Save bturrubiates/47ad688581ddef4c5801b8369025bed5 to your computer and use it in GitHub Desktop.
Save bturrubiates/47ad688581ddef4c5801b8369025bed5 to your computer and use it in GitHub Desktop.
Script to run UDP/TCP testing with iperf in IPv4 and IPv6 mode.
#!/usr/bin/env python3
import subprocess
import threading
import itertools
import argparse
import shlex
import time
import re
def find_neighbor(address, direction):
unmasked = address.split('/')[0]
delimiter = '.' if '.' in unmasked else ':'
value = int(unmasked.split(delimiter)[-1])
index = unmasked.rfind(delimiter)
rest = unmasked[:index + 1]
value = value + 1 if direction == 'up' else value - 1
return rest + str(value)
def find_address(iface, ipv):
ip_opt = '-6' if ipv == 'ipv6' else '-4'
cmd = 'ip -o {0} addr show dev {1} scope global'.format(
ip_opt, iface)
sh = shlex.split(cmd)
proc = subprocess.Popen(sh, stdout=subprocess.PIPE)
out, _ = proc.communicate()
address = re.search(r'.*inet(?:.?) (.*)/.*', out.decode()).groups(1)[0]
return address
def generate_log_name(address, port, proto, client=False):
safe_addr = address.replace('.', '_')
safe_addr = address.replace(':', '_')
composite = '{0}_{1}_{2}.log'.format(safe_addr, port, proto)
if client:
composite = 'client_' + composite
return composite
def find_offset(ipv, proto):
offsets = {
'ipv4': {
'udp': 100,
'tcp': 200
},
'ipv6': {
'udp': 300,
'tcp': 400
}
}
return offsets[ipv][proto]
def start_server(args, iface, port, ipv, proto):
address = find_address(iface, ipv)
cmd = 'iperf -s -i {0}'.format(args.interval)
cmd += ' -B {0}'.format(address)
if ipv == 'ipv6':
cmd += ' -V'
if proto == 'udp':
cmd += ' -u'
port += find_offset(ipv, proto)
cmd += ' -p {0}'.format(port)
sh = shlex.split(cmd)
filename = generate_log_name(address, port, proto)
print('Running {0} and redirecting to {1}'.format(cmd, filename))
with open(filename, 'w') as log:
proc = subprocess.Popen(sh, stdout=log, stderr=log)
proc.wait()
def start_client(args, iface, port, ipv, proto):
address = find_address(iface, ipv)
neighbor = find_neighbor(address, args.neighbor)
cmd = 'iperf -c {0} -t 86400 -P4 -i {1}'.format(neighbor, args.interval)
if ipv == 'ipv6':
cmd += ' -V'
if proto == 'udp':
cmd += ' -u -b 10G -l 32k'
else:
cmd += ' -l 128k'
port += find_offset(ipv, proto)
cmd += ' -p {0}'.format(port)
sh = shlex.split(cmd)
filename = generate_log_name(address, port, proto, client=True)
print('Running {0} and redirecting to {1}'.format(cmd, filename))
with open(filename, 'w') as log:
proc = subprocess.Popen(sh, stdout=log, stderr=log)
proc.wait()
def interfaces(iface, count):
# Expect interfaces to follow the naming convention of
# eno5, this should break into ('eno', '5')
# enp138s0f0, this should break into ('enp', '138', 's0f0')
iface_re = r'([a-z]+)([0-9]+)'
prefix, number_str = re.search(iface_re, iface).groups()
number = int(number_str)
for i in range(count):
yield '{0}{1}'.format(prefix, number + i)
def dispatch_tests(target, args, interface, port):
threads = []
# Temporarily disable ipv6 as there is some sort of issue
ipv = ['ipv4']
# Temporarily disable udp as there is some sort of issue with TSO.
proto = ['tcp']
for pair in itertools.product(ipv, proto):
v, p = pair
t = threading.Thread(target=target, args=(args, interface, port, v, p))
t.start()
threads.append(t)
time.sleep(1)
return threads
def dispatch(target, args):
threads = []
port = args.starting_port
for interface in interfaces(args.iface, args.count):
pending = dispatch_tests(target, args, interface, port)
threads.extend(pending)
port = port + 1000
print('Done dispatching...now we wait.')
for thread in threads:
thread.join()
def handle_args():
parser = argparse.ArgumentParser(description="Start iperf clients")
parser.add_argument('--servers', action='store_true',
help='Start iperf servers')
parser.add_argument('--starting-port', type=int, default=5000,
help='Port to start iperf range')
parser.add_argument('--neighbor', choices=['up', 'down'],
help='Direction to find neighbor address based on IP',
default='up')
parser.add_argument('--interval', type=int, default=5,
help='Print interval for iperf')
parser.add_argument('iface', help='Interface to start from')
parser.add_argument('count', type=int, help='Interfaces to start on')
return parser.parse_args()
def main():
args = handle_args()
if args.servers:
dispatch(start_server, args)
else:
dispatch(start_client, args)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment