Example #1
0
def stop_batmanadv_instances_all(remotes):
    rmap = get_remote_mapping(remotes)
    for id, remote in rmap.items():
        exec(
            remote,
            f'ip netns exec "ns-{id}" batctl meshif "bat0" interface del "uplink" || true'
        )
Example #2
0
def main():
    parser = argparse.ArgumentParser(description='Measure mean traffic.')
    parser.add_argument(
        '--remotes',
        help='Distribute nodes and links on remotes described in the JSON file.'
    )
    parser.add_argument('--interface', help='Interface to measure traffic on.')
    parser.add_argument('--duration',
                        type=int,
                        help='Measurement duration in seconds.')

    args = parser.parse_args()

    if args.remotes:
        if not os.path.isfile(args.remotes):
            eprint(f'File not found: {args.remotes}')
            stop_all_terminals()
            exit(1)

        with open(args.remotes) as file:
            args.remotes = [Remote.from_json(obj) for obj in json.load(file)]
    else:
        args.remotes = default_remotes

    # need root for local setup
    for remote in args.remotes:
        if remote.address is None:
            if os.geteuid() != 0:
                eprint('Need to run as root.')
                exit(1)

    rmap = get_remote_mapping(args.remotes)
    if args.duration:
        ds = args.duration
        ts_beg = traffic(args.remotes, interface=args.interface, rmap=rmap)
        time.sleep(ds)
        ts_end = traffic(args.remotes, interface=args.interface, rmap=rmap)
        ts = ts_end - ts_beg
        n = ds * len(rmap)
        print(
            f'rx: {format_size(ts.rx_bytes / n)}/s, {ts.rx_packets / n:.2f} packets/s, {ts.rx_dropped / n:.2f} dropped/s (avg. per node)'
        )
        print(
            f'tx: {format_size(ts.tx_bytes / n)}/s, {ts.tx_packets / n:.2f} packets/s, {ts.tx_dropped / n:.2f} dropped/s (avg. per node)'
        )
    else:
        ts = traffic(args.remotes, interface=args.interface, rmap=rmap)
        print(
            f'rx: {format_size(ts.rx_bytes)} / {ts.rx_packets} packets / {ts.rx_dropped} dropped'
        )
        print(
            f'tx: {format_size(ts.tx_bytes)} / {ts.tx_packets} packets / {ts.tx_dropped} dropped'
        )

    stop_all_terminals()
Example #3
0
def traffic(remotes=default_remotes, ids=None, interface=None, rmap=None):
    if rmap is None:
        rmap = get_remote_mapping(remotes)

    if ids is None:
        ids = list(rmap.keys())

    if interface is None:
        interface = 'uplink'

    ts = _Traffic()

    for id in ids:
        remote = rmap[id]
        stdout = exec(
            remote,
            f'ip netns exec ns-{id} ip -statistics link show dev {interface}',
            get_output=True)[0]
        lines = stdout.split('\n')
        link_toks = lines[1].split()
        rx_toks = lines[3].split()
        tx_toks = lines[5].split()
        ts.rx_bytes += int(rx_toks[0])
        ts.rx_packets += int(rx_toks[1])
        ts.rx_errors += int(rx_toks[2])
        ts.rx_dropped += int(rx_toks[3])
        ts.rx_overrun += int(rx_toks[4])
        ts.rx_mcast += int(rx_toks[5])
        ts.tx_bytes += int(tx_toks[0])
        ts.tx_packets += int(tx_toks[1])
        ts.tx_errors += int(tx_toks[2])
        ts.tx_dropped += int(tx_toks[3])
        ts.tx_carrier += int(tx_toks[4])
        ts.tx_collsns += int(tx_toks[5])

    return ts
Example #4
0
def main():
    parser = argparse.ArgumentParser(description="Ping various nodes.")
    parser.add_argument(
        "--remotes",
        help=
        "Distribute nodes and links on remotes described in the JSON file.",
    )
    parser.add_argument("--input", help="JSON state of the network.")
    parser.add_argument("--interface",
                        help="Interface to send data over (autodetected).")
    parser.add_argument("--min-hops",
                        type=int,
                        help="Minimum hops to ping. Needs --input.")
    parser.add_argument("--max-hops",
                        type=int,
                        help="Maximum hops to ping. Needs --input.")
    parser.add_argument(
        "--pings",
        type=int,
        default=10,
        help="Number of pings (unique, no self, no reverse paths).",
    )
    parser.add_argument("--duration",
                        type=int,
                        default=1000,
                        help="Spread pings over duration in ms.")
    parser.add_argument(
        "--deadline",
        type=int,
        default=1,
        help=
        "Specify a timeout, in seconds, before ping exits regardless of how many packets have been sent or received. In this case ping does not stop after count packet are sent, it waits either for deadline expire or until count probes are answered or for some error notification from network.",
    )
    parser.add_argument(
        "--timeout",
        type=int,
        default=None,
        help=
        "Time to wait for a response, in seconds. The option affects only timeout in absence of any responses, otherwise ping waits for two RTTs.",
    )
    parser.add_argument("--path",
                        nargs=2,
                        help="Send pings from a node to another.")
    parser.add_argument("-4",
                        action="store_true",
                        help="Force use of IPv4 addresses.")
    parser.add_argument("-6",
                        action="store_true",
                        help="Force use of IPv6 addresses.")

    args = parser.parse_args()

    if args.remotes:
        if not os.path.isfile(args.remotes):
            eprint(f"File not found: {args.remotes}")
            stop_all_terminals()
            exit(1)

        with open(args.remotes) as file:
            args.remotes = [Remote.from_json(obj) for obj in json.load(file)]
    else:
        args.remotes = default_remotes

    # need root for local setup
    for remote in args.remotes:
        if remote.address is None:
            if os.geteuid() != 0:
                eprint("Need to run as root.")
                exit(1)

    paths = None

    if args.path:
        for ns in args.path:
            if not namespace_exists(args.remotes, ns):
                eprint(f"Namespace ns-{ns} does not exist")
                stop_all_terminals()
                exit(1)
        paths = [args.path]
    elif args.input:
        state = json.load(args.input)
        paths = get_random_paths(network=state, count=args.pings)
        paths = filter_paths(state,
                             paths,
                             min_hops=args.min_hops,
                             max_hops=args.max_hops)
    else:
        if args.min_hops is not None or args.max_hops is not None:
            eprint(
                "No min/max hops available without topology information (--input)"
            )
            stop_all_terminals()
            exit(1)

        rmap = get_remote_mapping(args.remotes)
        all = list(rmap.keys())
        paths = _get_random_paths(nodes=all, count=args.pings)

    address_type = None
    if getattr(args, "4"):
        address_type = "4"
    if getattr(args, "6"):
        address_type = "6"

    ping(
        paths=paths,
        remotes=args.remotes,
        duration_ms=args.duration,
        interface=args.interface,
        verbosity="verbose",
        address_type=address_type,
        ping_deadline=args.deadline,
        ping_timeout=args.timeout,
    )

    stop_all_terminals()
Example #5
0
def ping(
    paths,
    duration_ms=1000,
    remotes=default_remotes,
    interface=None,
    verbosity="normal",
    address_type=None,
    ping_deadline=1,
    ping_timeout=None,
):
    ping_count = 1
    rmap = get_remote_mapping(remotes)
    path_count = len(paths)

    # prepare ping tasks
    tasks = []
    for (source, target) in paths:
        source_remote = rmap[source]
        target_remote = rmap[target]

        if interface is None:
            interface = _get_interface(source_remote, source)

        target_addr = _get_ip_address(target_remote, target, interface,
                                      address_type)

        if target_addr is None:
            eprint(f"Cannot get address of {interface} in ns-{target}")
        else:
            debug = f"ping {source:>4} => {target:>4} ({target_addr:<18} / {interface})"
            command = (
                f"ip netns exec ns-{source} ping -c {ping_count} " +
                (f"-w {ping_deadline} " if ping_deadline is not None else "") +
                (f"-W {ping_timeout} " if ping_timeout is not None else "") +
                f"-D -I {interface} {target_addr}")
            tasks.append((source_remote, command, debug))

    processes = []
    started = 0

    def process_results():
        for (process, started_ms, debug, result) in processes:
            if not result.processed and process.poll() is not None:
                process.wait()
                (output, err) = process.communicate()
                _parse_ping(result, output.decode())
                result.processed = True

    # keep track of status ouput lines to delete them for updates
    lines_printed = 0

    def print_processes():
        nonlocal lines_printed

        # delete previous printed lines
        for _ in range(lines_printed):
            sys.stdout.write("\x1b[1A\x1b[2K")

        lines_printed = 0
        process_counter = 0
        for (process, started_ms, debug, result) in processes:
            process_counter += 1
            status = "???"
            if result.processed:
                if result.packet_loss == 0.0:
                    status = "success"
                elif result.packet_loss == 100.0:
                    status = "failed"
                else:
                    status = f"mixed ({result.packet_loss:0.2f}% loss)"
            else:
                status = "running"

            print(
                f"[{process_counter:03}:{started_ms:06}] {debug} => {status}")
            lines_printed += 1

    # start tasks in the given time frame
    start_ms = millis()
    last_processed = millis()
    tasks_count = len(tasks)
    while started < tasks_count:
        started_expected = math.ceil(tasks_count *
                                     ((millis() - start_ms) / duration_ms))
        if started_expected > started:
            for _ in range(0, started_expected - started):
                if len(tasks) == 0:
                    break

                (remote, command, debug) = tasks.pop()
                process = create_process(remote, command)
                started_ms = millis() - start_ms
                processes.append(
                    (process, started_ms, debug, _PingResult(ping_count)))

                # process results and print updates once per second
                if (last_processed + 1000) < millis():
                    last_processed = millis()
                    process_results()
                    if verbosity != "quiet":
                        print_processes()

                started += 1
        else:
            # sleep a small amount
            time.sleep(duration_ms / tasks_count / 1000.0 / 10.0)

    stop1_ms = millis()

    # wait until rest fraction of duration_ms is over
    if (stop1_ms - start_ms) < duration_ms:
        time.sleep((duration_ms - (stop1_ms - start_ms)) / 1000.0)

    stop2_ms = millis()

    process_results()
    if verbosity != "quiet":
        print_processes()

    # collect results
    rtt_avg_ms_count = 0
    ret = _PingStats()
    for (process, started_ms, debug, result) in processes:
        ret.send += result.send
        if result.processed:
            ret.received += int(result.send * (1.0 -
                                               (result.packet_loss / 100.0)))
            # failing ping outputs do not have rtt values
            if not math.isnan(result.rtt_avg):
                ret.rtt_avg_ms += result.rtt_avg
                rtt_avg_ms_count += 1

    if rtt_avg_ms_count > 0:
        ret.rtt_avg_ms /= float(rtt_avg_ms_count)

    result_duration_ms = stop1_ms - start_ms
    result_filler_ms = stop2_ms - stop1_ms

    if verbosity != "quiet":
        print(
            "pings send: {}, received: {} ({}), measurement span: {}ms".format(
                ret.send,
                ret.received,
                "-" if (ret.send == 0) else
                f"{100.0 * (ret.received / ret.send):0.2f}%",
                result_duration_ms + result_filler_ms,
            ))

    return ret
Example #6
0
def stop(protocol, remotes=default_remotes):
    rmap = get_remote_mapping(remotes)
    ids = list(rmap.keys())
    stop_routing_protocol(protocol, rmap, ids)
Example #7
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--remotes',
        help='Distribute nodes and links on remotes described in the JSON file.'
    )
    subparsers = parser.add_subparsers(dest='action', required=True)

    parser_traffic = subparsers.add_parser('traffic',
                                           help='Measure mean traffic.')
    parser_traffic.add_argument('--interface',
                                help='Interface to measure traffic on.')
    parser_traffic.add_argument('--duration',
                                type=int,
                                help='Measurement duration in seconds.')

    parser_ping = subparsers.add_parser('ping', help='Ping various nodes.')
    parser_ping.add_argument('--input', help='JSON state of the network.')
    parser_ping.add_argument(
        '--interface', help='Interface to send data over (autodetected).')
    parser_ping.add_argument('--min-hops',
                             type=int,
                             help='Minimum hops to ping. Needs --input.')
    parser_ping.add_argument('--max-hops',
                             type=int,
                             help='Maximum hops to ping. Needs --input.')
    parser_ping.add_argument(
        '--pings',
        type=int,
        default=10,
        help='Number of pings (unique, no self, no reverse paths).')
    parser_ping.add_argument('--duration',
                             type=int,
                             default=1000,
                             help='Spread pings over duration in ms.')

    args = parser.parse_args()

    if args.remotes:
        with open(args.remotes) as file:
            args.remotes = json.load(file)
    else:
        args.remotes = default_remotes

    # need root for local setup
    for remote in args.remotes:
        if remote.get('address') is None:
            if os.geteuid() != 0:
                eprint('Need to run as root.')
                exit(1)

    if args.action == 'traffic':
        rmap = get_remote_mapping(args.remotes)
        if args.duration:
            ds = args.duration
            ts_beg = traffic(args.remotes, interface=args.interface, rmap=rmap)
            time.sleep(ds)
            ts_end = traffic(args.remotes, interface=args.interface, rmap=rmap)
            ts = ts_end - ts_beg
            n = ds * len(rmap)
            print(
                f'rx: {format_size(ts.rx_bytes / n)}/s, {ts.rx_packets / n:.2f} packets/s, {ts.rx_dropped / n:.2f} dropped/s (avg. per node)'
            )
            print(
                f'tx: {format_size(ts.tx_bytes / n)}/s, {ts.tx_packets / n:.2f} packets/s, {ts.tx_dropped / n:.2f} dropped/s (avg. per node)'
            )
        else:
            ts = traffic(args.remotes, interface=args.interface, rmap=rmap)
            print(
                f'rx: {format_size(ts.rx_bytes)} / {ts.rx_packets} packets / {ts.rx_dropped} dropped'
            )
            print(
                f'tx: {format_size(ts.tx_bytes)} / {ts.tx_packets} packets / {ts.tx_dropped} dropped'
            )
    elif args.action == 'ping':
        paths = None

        if args.input:
            state = json.load(args.input)
            paths = get_random_paths(network=state, count=args.pings)
            paths = filter_paths(state,
                                 paths,
                                 min_hops=args.min_hops,
                                 max_hops=args.max_hops)
        else:
            if args.min_hops is not None or args.max_hops is not None:
                eprint(
                    'No min/max hops available without topology information (--input)'
                )
                stop_all_terminals()
                exit(1)

            rmap = get_remote_mapping(args.remotes)
            all = list(rmap.keys())
            paths = _get_random_paths(nodes=all, count=args.pings)

        ping_paths(paths=paths,
                   remotes=args.remotes,
                   duration_ms=args.duration,
                   interface=args.interface,
                   verbosity='verbose')
    else:
        eprint(f'Unknown action: {args.action}')
        exit(1)

    stop_all_terminals()
Example #8
0
def ping_paths(paths,
               duration_ms=1000,
               remotes=default_remotes,
               interface=None,
               verbosity='normal'):
    ping_deadline = 1
    ping_count = 1
    processes = []
    start_ms = millis()
    started = 0
    rmap = get_remote_mapping(remotes)
    path_count = len(paths)
    while started < path_count:
        # number of expected tests to have been run
        started_expected = math.ceil(path_count *
                                     ((millis() - start_ms) / duration_ms))
        if started_expected > started:
            for _ in range(0, started_expected - started):
                if len(paths) == 0:
                    break
                (source, target) = paths.pop()

                source_remote = rmap[source]
                target_remote = rmap[target]

                if interface is None:
                    interface = _get_interface(source_remote, source)

                target_addr = _get_ip_address(target_remote, target, interface)

                if target_addr is None:
                    eprint(f'Cannot get address of {interface} in ns-{target}')
                    # count as started
                    started += 1
                else:
                    debug = '[{:06}] Ping {} => {} ({} / {})'.format(
                        millis() - start_ms, source, target, target_addr,
                        interface)
                    process = create_process(
                        source_remote,
                        f'ip netns exec ns-{source} ping -c {ping_count} -w {ping_deadline} -D {target_addr}'
                    )
                    processes.append((process, debug))
                    started += 1
        else:
            # sleep a small amount
            time.sleep(duration_ms / path_count / 1000.0 / 10.0)

    stop1_ms = millis()

    # wait until duration_ms is over
    if (stop1_ms - start_ms) < duration_ms:
        time.sleep((duration_ms - (stop1_ms - start_ms)) / 1000.0)

    stop2_ms = millis()

    ret = _PingResult()

    # wait/collect for results from pings (prolongs testing up to 1 second!)
    for (process, debug) in processes:
        process.wait()
        (output, err) = process.communicate()
        result = _parse_ping(output.decode())
        result.send = ping_count  # TODO: nicer

        ret.send += result.send
        ret.transmitted += result.transmitted
        ret.received += result.received
        ret.rtt_avg += result.rtt_avg

        if verbosity != 'quiet':
            if result.send != result.received:
                print(f'{debug} => failed')
            else:
                # success
                print(f'{debug}')

    ret.rtt_avg = 0 if ret.received == 0 else int(ret.rtt_avg / ret.received)
    result_duration_ms = stop1_ms - start_ms
    result_filler_ms = stop2_ms - stop1_ms

    if verbosity != 'quiet':
        print('send: {}, received: {}, arrived: {}%, measurement span: {}ms'.
              format(
                  ret.send, ret.received, '-' if (ret.send == 0) else
                  '{:0.2f}'.format(100.0 * (ret.received / ret.send)),
                  result_duration_ms + result_filler_ms))

    return ret
Example #9
0
def main():
    parser = argparse.ArgumentParser(description='Ping various nodes.')
    parser.add_argument(
        '--remotes',
        help='Distribute nodes and links on remotes described in the JSON file.'
    )
    parser.add_argument('--input', help='JSON state of the network.')
    parser.add_argument('--interface',
                        help='Interface to send data over (autodetected).')
    parser.add_argument('--min-hops',
                        type=int,
                        help='Minimum hops to ping. Needs --input.')
    parser.add_argument('--max-hops',
                        type=int,
                        help='Maximum hops to ping. Needs --input.')
    parser.add_argument(
        '--pings',
        type=int,
        default=10,
        help='Number of pings (unique, no self, no reverse paths).')
    parser.add_argument('--duration',
                        type=int,
                        default=1000,
                        help='Spread pings over duration in ms.')
    parser.add_argument('-4',
                        action='store_true',
                        help='Force use of IPv4 addresses.')
    parser.add_argument('-6',
                        action='store_true',
                        help='Force use of IPv6 addresses.')

    args = parser.parse_args()

    if args.remotes:
        if not os.path.isfile(args.remotes):
            eprint(f'File not found: {args.remotes}')
            stop_all_terminals()
            exit(1)

        with open(args.remotes) as file:
            args.remotes = [Remote.from_json(obj) for obj in json.load(file)]
    else:
        args.remotes = default_remotes

    # need root for local setup
    for remote in args.remotes:
        if remote.address is None:
            if os.geteuid() != 0:
                eprint('Need to run as root.')
                exit(1)

    paths = None

    if args.input:
        state = json.load(args.input)
        paths = get_random_paths(network=state, count=args.pings)
        paths = filter_paths(state,
                             paths,
                             min_hops=args.min_hops,
                             max_hops=args.max_hops)
    else:
        if args.min_hops is not None or args.max_hops is not None:
            eprint(
                'No min/max hops available without topology information (--input)'
            )
            stop_all_terminals()
            exit(1)

        rmap = get_remote_mapping(args.remotes)
        all = list(rmap.keys())
        paths = _get_random_paths(nodes=all, count=args.pings)

    address_type = None
    if getattr(args, '4'):
        address_type = '4'
    if getattr(args, '6'):
        address_type = '6'

    ping(paths=paths,
         remotes=args.remotes,
         duration_ms=args.duration,
         interface=args.interface,
         verbosity='verbose',
         address_type=address_type)

    stop_all_terminals()
Example #10
0
def start(protocol, remotes=default_remotes):
    rmap = get_remote_mapping(remotes)
    ids = list(rmap.keys())
    _start_protocol(protocol, rmap, ids)