예제 #1
0
def parseConfigFile(file):
    cc_algorithms = get_available_algorithms()

    unknown_alorithms = []
    number_of_hosts = 0
    output = []
    f = open(file)
    for line in f:
        line = line.replace('\n', '').strip()

        if len(line) > 1:
            if line[0] == '#':
                continue

        split = line.split(',')
        if split[0] == '':
            continue
        command = split[0].strip()

        if command == 'host':
            if len(split) != 5:
                print_warning(
                    'Too few arguments to add host in line\n{}'.format(line))
                continue
            algorithm = split[1].strip()
            rtt = split[2].strip()
            start = float(split[3].strip())
            stop = float(split[4].strip())
            if algorithm not in cc_algorithms:
                if algorithm not in unknown_alorithms:
                    unknown_alorithms.append(algorithm)
                continue

            if number_of_hosts >= MAX_HOST_NUMBER:
                print_warning(
                    'Max host number reached. Skipping further hosts.')
                continue

            number_of_hosts += 1
            output.append({
                'command': command,
                'algorithm': algorithm,
                'rtt': rtt,
                'start': start,
                'stop': stop
            })

        elif command == 'link':
            if len(split) != 4:
                print_warning(
                    'Too few arguments to change link in line\n{}'.format(
                        line))
                continue
            change = split[1].strip()
            if change != 'bw' and change != 'rtt':
                print_warning('Unknown link option "{} in line\n{}'.format(
                    change, line))
                continue
            value = split[2].strip()
            start = float(split[3].strip())
            output.append({
                'command': command,
                'change': change,
                'value': value,
                'start': start
            })
        else:
            print_warning('Skip unknown command "{}" in line\n{}'.format(
                command, line))
            continue

    if len(unknown_alorithms) > 0:
        print_warning(
            'Skipping uninstalled congestion control algorithm:\n  ' +
            ' '.join(unknown_alorithms))
        print_warning('Available algorithms:\n  ' + cc_algorithms.strip())
        print_warning('Start Test anyway in 10s. (Press ^C to interrupt)')
        try:
            time.sleep(10)
        except KeyboardInterrupt:
            sys.exit(1)

    return output
예제 #2
0
def run_test(commands, output_directory, name, bandwidth, initial_rtt, initial_loss,
             buffer_size, buffer_latency, poll_interval):

    duration = 0
    start_time = 0
    number_of_hosts = 0

    current_netem_delay = initial_rtt
    current_netem_loss = initial_loss

    if not os.path.exists(output_directory):
        os.makedirs(output_directory)

    config = [
        'Test Name: {}'.format(name),
        'Date: {}'.format(time.strftime('%c')),
        'Kernel: {}'.format(get_host_version()),
        'Git Commit: {}'.format(get_git_revision_hash()),
        'Initial Bandwidth: {}'.format(bandwidth),
        'Burst Buffer: {}'.format(buffer_size),
        'Buffer Latency: {}'.format(buffer_latency),
        'Initial Link RTT: {}'.format(initial_rtt),
        'Initial Link Loss: {}'.format(initial_loss),
        'Commands: '
    ]
    for cmd in commands:
        start_time += cmd['start']

        config_line = '{}, '.format(cmd['command'])
        if cmd['command'] == 'link':
            config_line += '{}, {}, {}'.format(cmd['change'], cmd['value'], cmd['start'])
        elif cmd['command'] == 'host':
            number_of_hosts += 1
            config_line += '{}, {}, {}, {}'.format(cmd['algorithm'], cmd['rtt'], cmd['start'], cmd['stop'])
            if start_time + cmd['stop'] > duration:
                duration = start_time + cmd['stop']
        config.append(config_line)

    with open(os.path.join('{}'.format(output_directory), 'parameters.txt'), 'w') as f:
        f.write('\n'.join(config))

    print('-' * TEXT_WIDTH)
    print('Starting test: {}'.format(name))
    print('Total duration: {}s'.format(duration))

    try:
        topo = DumbbellTopo(number_of_hosts)
        net = Mininet(topo=topo, link=TCLink)
        net.start()
    except Exception as e:
        print_error('Could not start Mininet:')
        print_error(e)
        sys.exit(1)

    # start tcp dump
    try:
        FNULL = open(os.devnull, 'w')
        subprocess.Popen(['tcpdump', '-i', 's1-eth1', '-n', 'tcp', '-s', '88',
                          '-w', os.path.join(output_directory, 's1.pcap')], stderr=FNULL)
        subprocess.Popen(['tcpdump', '-i', 's3-eth1', '-n', 'tcp', '-s', '88',
                          '-w', os.path.join(output_directory, 's3.pcap')], stderr=FNULL)
    except Exception as e:
        print_error('Error on starting tcpdump\n{}'.format(e))
        sys.exit(1)


    time.sleep(1)

    host_counter = 0
    for cmd in commands:
        if cmd['command'] != 'host':
            continue
        send = net.get('h{}'.format(host_counter))
        send.setIP('10.1.{}.{}/8'.format(host_counter // 256, host_counter % 256))
        recv = net.get('r{}'.format(host_counter))
        recv.setIP('10.2.{}.{}/8'.format(host_counter // 256, host_counter % 256))
        host_counter += 1

        # setup FQ, algorithm, netem, nc host
        send.cmd('tc qdisc add dev {}-eth0 root fq pacing'.format(send))
        send.cmd('ip route change 10.0.0.0/8 dev {}-eth0 congctl {}'.format(send, cmd['algorithm']))
        send.cmd('ethtool -K {}-eth0 tso off'.format(send))
        recv.cmd('tc qdisc add dev {}-eth0 root netem delay {}'.format(recv, cmd['rtt']))
        recv.cmd('timeout {} nc -klp 9000 > /dev/null &'.format(duration))

        # pull BBR values
        send.cmd('./ss_script.sh {} >> {}.{} &'.format(poll_interval, os.path.join(output_directory, send.IP()), FLOW_FILE_EXTENSION))

    s2, s3 = net.get('s2', 's3')
    s2.cmd(traffic_shaping('tbf', 's2-eth2', add=True, rate=bandwidth, buffer=buffer_size, latency=buffer_latency))

    netem_running = False
    if current_netem_delay != '0ms' or current_netem_loss != '0%':
        netem_running = True
        s2.cmd(traffic_shaping('netem', 's2-eth2', add=True, delay=current_netem_delay, loss=current_netem_loss))
    s2.cmd('./buffer_script.sh {0} {1} >> {2}.{3} &'.format(poll_interval, 's2-eth2',
                                                            os.path.join(output_directory, 's2-eth2-tbf'),
                                                            BUFFER_FILE_EXTENSION))

    complete = duration
    current_time = 0
    host_counter = 0


    try:
        for cmd in commands:
            start = cmd['start']
            current_time = sleep_progress_bar(start, current_time=current_time, complete=complete)

            if cmd['command'] == 'link':
                s2 = net.get('s2')

                if cmd['change'] == 'bw':
                    s2.cmd(traffic_shaping('tbf', 's2-eth2', add=False, rate=cmd['value'], buffer=buffer_size, latency=buffer_latency))
                    log_String = '  Change bandwidth to {}.'.format(cmd['value'])

                elif cmd['change'] == 'rtt' or cmd['change'] == 'loss':
                    current_netem_delay = cmd['value'] if cmd['change'] == 'rtt' else current_netem_delay
                    current_netem_loss = cmd['value'] if cmd['change'] == 'loss' else current_netem_loss

                    s2.cmd(traffic_shaping('netem', 's2-eth2', add=not netem_running, delay=current_netem_delay,
                                           loss=current_netem_loss))
                    netem_running = True
                    log_String = '  Change {} to {}.'.format(cmd['change'], cmd['value'])

            elif cmd['command'] == 'host':
                send = net.get('h{}'.format(host_counter))
                recv = net.get('r{}'.format(host_counter))
                timeout = cmd['stop']
                log_String = '  h{}: {} {}, {} -> {}'.format(host_counter, cmd['algorithm'], cmd['rtt'], send.IP(), recv.IP())
                send.cmd('timeout {} nc {} 9000 < /dev/urandom > /dev/null &'.format(timeout, recv.IP()))
                host_counter += 1
            print(log_String + ' ' * (TEXT_WIDTH - len(log_String)))

        current_time = sleep_progress_bar((complete - current_time) % 1, current_time=current_time, complete=complete)
        current_time = sleep_progress_bar(complete - current_time, current_time=current_time, complete=complete)
    except (KeyboardInterrupt, Exception) as e:
        if isinstance(e, KeyboardInterrupt):
            print_warning('\nReceived keyboard interrupt. Stop Mininet.')
        else:
            print_error(e)
    finally:
        net.stop()
        cleanup()

    print('-' * TEXT_WIDTH)
예제 #3
0
def run_test(commands, directory, name, bandwidth, initial_rtt, buffer_size,
             buffer_limit, poll_interval):
    duration = 0
    start_time = 0
    number_of_hosts = 0

    output_directory = os.path.join(
        directory, '{}_{}'.format(time.strftime('%m%d_%H%M%S'), name))

    if not os.path.exists(output_directory):
        os.makedirs(output_directory)

    write_config = [
        'Test Name: {}'.format(name), 'Date: {}'.format(time.strftime('%c')),
        'Kernel: {}'.format(get_host_version()),
        'Git Commit: {}'.format(get_git_revision_hash()),
        'Initial Bandwidth: {}'.format(bandwidth),
        'Burst Buffer: {}'.format(buffer_size),
        'Buffer Latency: {}'.format(buffer_limit), 'Commands: '
    ]
    for cmd in commands:
        start_time += cmd['start']

        config_line = '{}, '.format(cmd['command'])
        if cmd['command'] == 'link':
            config_line += '{}, {}, {}'.format(cmd['change'], cmd['value'],
                                               cmd['start'])
        elif cmd['command'] == 'host':
            number_of_hosts += 1
            config_line += '{}, {}, {}, {}'.format(cmd['algorithm'],
                                                   cmd['rtt'], cmd['start'],
                                                   cmd['stop'])
            if start_time + cmd['stop'] > duration:
                duration = start_time + cmd['stop']
        write_config.append(config_line)

    with open(os.path.join('{}'.format(output_directory), 'parameters.txt'),
              'w') as f:
        f.write('\n'.join(write_config))
        f.close()

    text_width = 60
    print('-' * text_width)
    print('Starting test: {}'.format(name))
    print('Total duration: {}s'.format(duration))

    try:
        topo = DumbbellTopo(number_of_hosts)
        net = Mininet(topo=topo, link=TCLink)
        net.start()
    except Exception as e:
        print_error('Could not start Mininet:')
        print_error(e)
        sys.exit(1)

    # start tcp dump
    try:
        FNULL = open(os.devnull, 'w')
        subprocess.Popen([
            'tcpdump', '-i', 's1-eth1', '-n', 'tcp', '-s', '88', '-w',
            os.path.join(output_directory, 's1.pcap')
        ],
                         stderr=FNULL)
        subprocess.Popen([
            'tcpdump', '-i', 's3-eth1', '-n', 'tcp', '-s', '88', '-w',
            os.path.join(output_directory, 's3.pcap')
        ],
                         stderr=FNULL)
    except Exception as e:
        print_error('Error on starting tcpdump\n{}'.format(e))
        sys.exit(1)

    # start tcpprobe
    os.system('modprobe -r tcp_probe')
    os.system('modprobe tcp_probe full=1 port=5000')
    os.system('chmod 444 /proc/net/tcpprobe')
    os.system('timeout {} cat /proc/net/tcpprobe > {} &'.format(
        duration, os.path.join(output_directory, 'tcpprobe.xls')))

    time.sleep(1)

    host_counter = 0
    for cmd in commands:
        if cmd['command'] != 'host':
            continue
        send = net.get('h{}'.format(host_counter))
        send.setIP('10.1.{}.{}/8'.format(host_counter / 256,
                                         host_counter % 256))
        recv = net.get('r{}'.format(host_counter))
        recv.setIP('10.2.{}.{}/8'.format(host_counter / 256,
                                         host_counter % 256))
        host_counter += 1

        # setup FQ, algorithm, netem, nc host
        if cmd['algorithm'] == 'bbr' or cmd['algorithm'] == 'nv' or cmd[
                'algorithm'] == 'mybbr':
            send.cmd('tc qdisc add dev {}-eth0 root fq pacing'.format(send))
        else:
            send.cmd('tc qdisc add dev {}-eth0 root pfifo_fast')
        send.cmd('ip route change 10.0.0.0/8 dev {}-eth0 congctl {}'.format(
            send, cmd['algorithm']))
        send.cmd('ethtool -K {}-eth0 tso off'.format(send))
        recv.cmd('tc qdisc add dev {}-eth0 root netem delay {}'.format(
            recv, cmd['rtt']))
        recv.cmd('tcpdump -i {}-eth0 -n tcp -s 88 > {} &'.format(
            recv, os.path.join(output_directory, '{}.txt'.format(recv))))
        #recv.cmd('timeout {} nc -klp 9000 > /dev/null &'.format(duration))
        #recv.cmd('iperf -s -p 5000 &')
        #recv.cmd('./goodput.sh .5 {} &'.format(output_directory,'goodput_{}.txt'.format(recv.IP())));
        #recv.cmd('./goodput.sh 100 {} &'.format(os.path.join(output_directory,'goodput_{}.txt'.format(recv.IP()))))
        recv.cmd('./server 5000 {} {} &'.format(
            os.path.join(output_directory, '{}.goodput'.format(recv)),
            GOODPUT_INTERVAL))

        #time.sleep(1)
        #recv.cmd('sudo python TCPserver.py > ./goodputResult.txt &')
        # pull BBR values
        send.cmd('./ss_script.sh {} >> {}.bbr &'.format(
            poll_interval, os.path.join(output_directory, send.IP())))

    s2, s3 = net.get('s2', 's3')
    s2.cmd(
        'tc qdisc add dev s2-eth2 root tbf rate {} buffer {} limit {}'.format(
            bandwidth, buffer_size, buffer_limit))
    netem_running = False
    if initial_rtt != '0ms':
        netem_running = True
        s2.cmd(
            'tc qdisc add dev s2-eth1 root netem delay {}'.format(initial_rtt))
    s2.cmd('./buffer_script.sh {0} {1} >> {2}.buffer &'.format(
        poll_interval, 's2-eth2', os.path.join(output_directory,
                                               's2-eth2-tbf')))

    complete = duration
    current_time = 0

    host_counter = 0

    try:
        for cmd in commands:
            start = cmd['start']
            current_time = sleep_progress_bar(start,
                                              current_time=current_time,
                                              complete=complete)

            if cmd['command'] == 'link':
                s2 = net.get('s2')
                if cmd['change'] == 'bw':
                    s2.cmd(
                        'tc qdisc change dev s2-eth2 root tbf rate {} buffer {} limit {}'
                        .format(cmd['value'], buffer_size, buffer_limit))
                    print("Bottleneck : " + str(cmd['value']))
                    log_String = '  Change bandwidth to {}.'.format(
                        cmd['value'])
                elif cmd['change'] == 'rtt':
                    if netem_running:
                        s2.cmd(
                            'tc qdisc change dev s2-eth1 root netem delay {}'.
                            format(cmd['value']))
                    else:
                        netem_running = True
                        s2.cmd('tc qdisc add dev s2-eth1 root netem delay {}'.
                               format(cmd['value']))
                    log_String = '  Change rtt to {}.'.format(cmd['value'])

            elif cmd['command'] == 'host':
                send = net.get('h{}'.format(host_counter))
                recv = net.get('r{}'.format(host_counter))
                timeout = cmd['stop']
                log_String = '  h{}: {} {}, {} -> {}'.format(
                    host_counter, cmd['algorithm'], cmd['rtt'], send.IP(),
                    recv.IP())
                #send.cmd('timeout {} nc {} 9000 < /dev/urandom > /dev/null &'.format(timeout, recv.IP()))
                send.cmd('iperf -c {} -p 5000 -t {} -i 0.5 &'.format(
                    recv.IP(), cmd['stop'],
                    os.path.join(output_directory,
                                 'sender_iperf.txt'.format(send.IP()))))
                host_counter += 1
            print(log_String + ' ' * (text_width - len(log_String)))

        current_time = sleep_progress_bar((complete - current_time) % 1,
                                          current_time=current_time,
                                          complete=complete)
        current_time = sleep_progress_bar(complete - current_time,
                                          current_time=current_time,
                                          complete=complete)
    except (KeyboardInterrupt, Exception) as e:
        if isinstance(e, KeyboardInterrupt):
            print_warning('\nReceived keyboard interrupt. Stop Mininet.')
        else:
            print_error(e)
    finally:
        time.sleep(3)
        net.stop()
        cleanup()

    print('-' * text_width)
예제 #4
0
    if len(commands) == 0:
        print_error('No valid commands found in config file.')
        sys.exit(128)

    if not verify_arguments(args, commands):
        print_error('Please fix malformed parameters.')
        sys.exit(128)

    output_directory = os.path.join(args.directory, '{}_{}'.format(time.strftime('%m%d_%H%M%S'), args.name))

    # setLogLevel('info')
    run_test(bandwidth=args.bandwidth,
             initial_rtt=args.rtt,
             initial_loss=args.loss,
             commands=commands,
             buffer_size=args.buffer_size,
             buffer_latency=args.latency,
             name=args.name,
             output_directory=output_directory,
             poll_interval=args.poll_interval)

    compression = args.compression

    if compression != COMPRESSION_METHODS[0]:
        if not check_tool(compression):
            print_warning('Compression with {} not possible. Continuing without compression.'.format(compression))
            compression = COMPRESSION_METHODS[0]

        compress_output(output_directory, compression)
        print('-' * TEXT_WIDTH)