def run(self, dckr_net_name='', rm=True):

        if rm and ctn_exists(self.name):
            print('remove container:', self.name)
            dckr.remove_container(self.name, force=True)

        host_config = dckr.create_host_config(binds=[
            '{0}:{1}'.format(os.path.abspath(self.host_dir), self.guest_dir)
        ],
                                              privileged=True,
                                              network_mode='bridge',
                                              cap_add=['NET_ADMIN'])

        ctn = dckr.create_container(image=self.image,
                                    entrypoint='bash',
                                    detach=True,
                                    name=self.name,
                                    stdin_open=True,
                                    volumes=[self.guest_dir],
                                    host_config=host_config)
        self.ctn_id = ctn['Id']

        ipv4_addresses = self.get_ipv4_addresses()

        net_id = None
        for network in dckr.networks(names=[dckr_net_name]):
            if network['Name'] != dckr_net_name:
                continue

            net_id = network['Id']
            if not 'IPAM' in network:
                print('can\'t verify if container\'s IP addresses '
                      'are valid for Docker network {}: missing IPAM'.format(
                          dckr_net_name))
                break
            ipam = network['IPAM']

            if not 'Config' in ipam:
                print('can\'t verify if container\'s IP addresses '
                      'are valid for Docker network {}: missing IPAM.Config'.
                      format(dckr_net_name))
                break

            ip_ok = False
            network_subnets = [
                item['Subnet'] for item in ipam['Config'] if 'Subnet' in item
            ]
            for ip in ipv4_addresses:
                for subnet in network_subnets:
                    ip_ok = netaddr.IPAddress(ip) in netaddr.IPNetwork(subnet)

                if not ip_ok:
                    print(
                        'the container\'s IP address {} is not valid for Docker network {} '
                        'since it\'s not part of any of its subnets ({})'.
                        format(ip, dckr_net_name, ', '.join(network_subnets)))
                    print(
                        'Please consider removing the Docket network {net} '
                        'to allow bgperf to create it again using the '
                        'expected subnet:\n'
                        '  docker network rm {net}'.format(net=dckr_net_name))
                    sys.exit(1)
            break

        if net_id is None:
            print('Docker network "{}" not found!'.format(dckr_net_name))
            return

        dckr.connect_container_to_network(self.ctn_id,
                                          net_id,
                                          ipv4_address=ipv4_addresses[0])
        dckr.start(container=self.name)

        if len(ipv4_addresses) > 1:

            # get the interface used by the first IP address already added by Docker
            dev = None
            res = self.local('ip addr')
            for line in res.split(b'\n'):
                if ipv4_addresses[0].encode('utf-8') in line:
                    dev = line.split(b' ')[-1].strip()
            if not dev:
                dev = "eth0"

            for ip in ipv4_addresses[1:]:
                self.local('ip addr add {} dev {}'.format(ip, dev))

        return ctn
Exemplo n.º 2
0
    def run_relay(name, ip, listen, talk, dckr_net_name='', rm=True):
        if rm and ctn_exists(name):
            print 'remove relay containers:', name
            dckr.remove_container(name, force=True)

        ctn = dckr.create_container(
            image='sproxy',
            detach=True,
            name=name,
            environment=['LISTEN={0}'.format(listen), 'TALK={0}'.format(talk)])
        ctn_id = ctn['Id']

        ipv4_addresses = [ip]

        net_id = None
        for network in dckr.networks(names=[dckr_net_name]):
            if network['Name'] != dckr_net_name:
                continue

            net_id = network['Id']
            if not 'IPAM' in network:
                print(
                    'can\'t verify if container\'s IP addresses '
                    'are valid for Docker network {}: missing IPAM'.format(
                        dckr_net_name))
                break
            ipam = network['IPAM']

            if not 'Config' in ipam:
                print(
                    'can\'t verify if container\'s IP addresses '
                    'are valid for Docker network {}: missing IPAM.Config'.
                    format(dckr_net_name))
                break

            ip_ok = False
            network_subnets = [
                item['Subnet'] for item in ipam['Config'] if 'Subnet' in item
            ]

            for ip in ipv4_addresses:
                for subnet in network_subnets:
                    ip_ok = netaddr.IPAddress(ip) in netaddr.IPNetwork(subnet)

                if not ip_ok:
                    print(
                        'the container\'s IP address {} is not valid for Docker network {} '
                        'since it\'s not part of any of its subnets ({})'.
                        format(ip, dckr_net_name, ', '.join(network_subnets)))
                    print(
                        'Please consider removing the Docket network {net} '
                        'to allow bgperf to create it again using the '
                        'expected subnet:\n'
                        '  docker network rm {net}'.format(net=dckr_net_name))
                    sys.exit(1)
            break

        if net_id is None:
            print 'Docker network "{}" not found!'.format(dckr_net_name)
            return

        dckr.connect_container_to_network(ctn_id,
                                          net_id,
                                          ipv4_address=ipv4_addresses[0])
        dckr.start(container=name)

        return ctn
Exemplo n.º 3
0
def bench(args):
    config_dir = '{0}/{1}'.format(args.dir, args.bench_name)
    dckr_net_name = args.docker_network_name or args.bench_name + '-br'

    for target_class in [BIRDTarget, GoBGPTarget, QuaggaTarget]:
        if ctn_exists(target_class.CONTAINER_NAME):
            print 'removing target container', target_class.CONTAINER_NAME
            dckr.remove_container(target_class.CONTAINER_NAME, force=True)

    if not args.repeat:
        if ctn_exists(Monitor.CONTAINER_NAME):
            print 'removing monitor container', Monitor.CONTAINER_NAME
            dckr.remove_container(Monitor.CONTAINER_NAME, force=True)

        for ctn_name in get_ctn_names():
            if ctn_name.startswith(ExaBGPTester.CONTAINER_NAME_PREFIX) or \
                ctn_name.startswith(ExaBGPMrtTester.CONTAINER_NAME_PREFIX) or \
                ctn_name.startswith(GoBGPMRTTester.CONTAINER_NAME_PREFIX):
                print 'removing tester container', ctn_name
                dckr.remove_container(ctn_name, force=True)

        if os.path.exists(config_dir):
            shutil.rmtree(config_dir)

    if args.file:
        with open(args.file) as f:
            conf = yaml.load(Template(f.read()).render())
    else:
        conf = gen_conf(args)
        if not os.path.exists(config_dir):
            os.makedirs(config_dir)
        with open('{0}/scenario.yaml'.format(config_dir), 'w') as f:
            f.write(conf)
        conf = yaml.load(Template(conf).render())

    bridge_found = False
    for network in dckr.networks(names=[dckr_net_name]):
        if network['Name'] == dckr_net_name:
            print 'Docker network "{}" already exists'.format(dckr_net_name)
            bridge_found = True
            break
    if not bridge_found:
        subnet = conf['local_prefix']
        print 'creating Docker network "{}" with subnet {}'.format(
            dckr_net_name, subnet)
        ipam = IPAMConfig(pool_configs=[IPAMPool(subnet=subnet)])
        network = dckr.create_network(dckr_net_name,
                                      driver='bridge',
                                      ipam=ipam)

    num_tester = sum(
        len(t.get('neighbors', [])) for t in conf.get('testers', []))
    if num_tester > gc_thresh3():
        print 'gc_thresh3({0}) is lower than the number of peer({1})'.format(
            gc_thresh3(), num_tester)
        print 'type next to increase the value'
        print '$ echo 16384 | sudo tee /proc/sys/net/ipv4/neigh/default/gc_thresh3'

    print 'run monitor'
    m = Monitor(config_dir + '/monitor', conf['monitor'])
    m.run(conf, dckr_net_name)

    is_remote = True if 'remote' in conf['target'] and conf['target'][
        'remote'] else False

    if is_remote:
        print 'target is remote ({})'.format(conf['target']['local-address'])

        ip = IPRoute()

        # r: route to the target
        r = ip.get_routes(dst=conf['target']['local-address'], family=AF_INET)
        if len(r) == 0:
            print 'no route to remote target {0}'.format(
                conf['target']['local-address'])
            sys.exit(1)

        # intf: interface used to reach the target
        idx = [t[1] for t in r[0]['attrs'] if t[0] == 'RTA_OIF'][0]
        intf = ip.get_links(idx)[0]
        intf_name = intf.get_attr('IFLA_IFNAME')

        # raw_bridge_name: Linux bridge name of the Docker bridge
        # TODO: not sure if the linux bridge name is always given by
        #       "br-<first 12 characters of Docker network ID>".
        raw_bridge_name = args.bridge_name or 'br-{}'.format(
            network['Id'][0:12])

        # raw_bridges: list of Linux bridges that match raw_bridge_name
        raw_bridges = ip.link_lookup(ifname=raw_bridge_name)
        if len(raw_bridges) == 0:
            if not args.bridge_name:
                print(
                    'can\'t determine the Linux bridge interface name starting '
                    'from the Docker network {}'.format(dckr_net_name))
            else:
                print('the Linux bridge name provided ({}) seems nonexistent'.
                      format(raw_bridge_name))
            print(
                'Since the target is remote, the host interface used to '
                'reach the target ({}) must be part of the Linux bridge '
                'used by the Docker network {}, but without the correct Linux '
                'bridge name it\'s impossible to verify if that\'s true'.
                format(intf_name, dckr_net_name))
            if not args.bridge_name:
                print(
                    'Please supply the Linux bridge name corresponding to the '
                    'Docker network {} using the --bridge-name argument.'.
                    format(dckr_net_name))
            sys.exit(1)

        # intf_bridge: bridge interface that intf is already member of
        intf_bridge = intf.get_attr('IFLA_MASTER')

        # if intf is not member of the bridge, add it
        if intf_bridge not in raw_bridges:
            if intf_bridge is None:
                print(
                    'Since the target is remote, the host interface used to '
                    'reach the target ({}) must be part of the Linux bridge '
                    'used by the Docker network {}'.format(
                        intf_name, dckr_net_name))
                sys.stdout.write('Do you confirm to add the interface {} '
                                 'to the bridge {}? [yes/NO] '.format(
                                     intf_name, raw_bridge_name))
                try:
                    answer = raw_input()
                except:
                    print 'aborting'
                    sys.exit(1)
                answer = answer.strip()
                if answer.lower() != 'yes':
                    print 'aborting'
                    sys.exit(1)

                print 'adding interface {} to the bridge {}'.format(
                    intf_name, raw_bridge_name)
                br = raw_bridges[0]

                try:
                    ip.link('set', index=idx, master=br)
                except Exception as e:
                    print('Something went wrong: {}'.format(str(e)))
                    print(
                        'Please consider running the following command to '
                        'add the {iface} interface to the {br} bridge:\n'
                        '   sudo brctl addif {br} {iface}'.format(
                            iface=intf_name, br=raw_bridge_name))
                    print('\n\n\n')
                    raise
            else:
                curr_bridge_name = ip.get_links(intf_bridge)[0].get_attr(
                    'IFLA_IFNAME')
                print(
                    'the interface used to reach the target ({}) '
                    'is already member of the bridge {}, which is not '
                    'the one used in this configuration'.format(
                        intf_name, curr_bridge_name))
                print(
                    'Please consider running the following command to '
                    'remove the {iface} interface from the {br} bridge:\n'
                    '   sudo brctl addif {br} {iface}'.format(
                        iface=intf_name, br=curr_bridge_name))
                sys.exit(1)
    else:
        if args.target == 'gobgp':
            target_class = GoBGPTarget
        elif args.target == 'bird':
            target_class = BIRDTarget
        elif args.target == 'quagga':
            target_class = QuaggaTarget

        print 'run', args.target
        if args.image:
            target = target_class('{0}/{1}'.format(config_dir, args.target),
                                  conf['target'],
                                  image=args.image)
        else:
            target = target_class('{0}/{1}'.format(config_dir, args.target),
                                  conf['target'])
        target.run(conf, dckr_net_name)

    time.sleep(1)

    print 'waiting bgp connection between {0} and monitor'.format(args.target)
    m.wait_established(conf['target']['local-address'])

    if not args.repeat:
        for idx, tester in enumerate(conf['testers']):
            if 'name' not in tester:
                name = 'tester{0}'.format(idx)
            else:
                name = tester['name']
            if 'type' not in tester:
                tester_type = 'normal'
            else:
                tester_type = tester['type']
            if tester_type == 'normal':
                tester_class = ExaBGPTester
            elif tester_type == 'mrt':
                if 'mrt_injector' not in tester:
                    mrt_injector = 'gobgp'
                else:
                    mrt_injector = tester['mrt_injector']
                if mrt_injector == 'gobgp':
                    tester_class = GoBGPMRTTester
                elif mrt_injector == 'exabgp':
                    tester_class = ExaBGPMrtTester
                else:
                    print 'invalid mrt_injector:', mrt_injector
                    sys.exit(1)
            else:
                print 'invalid tester type:', tester_type
                sys.exit(1)
            t = tester_class(name, config_dir + '/' + name, tester)
            print 'run tester', name, 'type', tester_type
            t.run(conf['target'], dckr_net_name)

    start = datetime.datetime.now()

    q = Queue()

    m.stats(q)
    if not is_remote:
        target.stats(q)

    def mem_human(v):
        if v > 1000 * 1000 * 1000:
            return '{0:.2f}GB'.format(float(v) / (1000 * 1000 * 1000))
        elif v > 1000 * 1000:
            return '{0:.2f}MB'.format(float(v) / (1000 * 1000))
        elif v > 1000:
            return '{0:.2f}KB'.format(float(v) / 1000)
        else:
            return '{0:.2f}B'.format(float(v))

    f = open(args.output, 'w') if args.output else None
    cpu = 0
    mem = 0
    cooling = -1
    while True:
        info = q.get()

        if not is_remote and info['who'] == target.name:
            cpu = info['cpu']
            mem = info['mem']

        if info['who'] == m.name:
            now = datetime.datetime.now()
            elapsed = now - start
            recved = info['state']['adj-table'][
                'accepted'] if 'accepted' in info['state']['adj-table'] else 0
            if elapsed.seconds > 0:
                rm_line()
            print 'elapsed: {0}sec, cpu: {1:>4.2f}%, mem: {2}, recved: {3}'.format(
                elapsed.seconds, cpu, mem_human(mem), recved)
            f.write('{0}, {1}, {2}, {3}\n'.format(elapsed.seconds, cpu, mem,
                                                  recved)) if f else None
            f.flush() if f else None

            if cooling == args.cooling:
                f.close() if f else None
                return

            if cooling >= 0:
                cooling += 1

            if info['checked']:
                cooling = 0
Exemplo n.º 4
0
def two_peer_test(args):
    args.neighbor_num = 2

    RELAY_PREFIX = 'bgperf_relay_'

    config_dir = '{0}/{1}'.format(args.dir, args.bench_name)
    dckr_net_name = args.docker_network_name or args.bench_name + '-br'

    for target_class in [
            BIRDTarget, GoBGPTarget, QuaggaTarget, FRRoutingTarget,
            MIRAGETarget, MIRAGESTTarget
    ]:
        if ctn_exists(target_class.CONTAINER_NAME):
            print 'removing target container', target_class.CONTAINER_NAME
            dckr.remove_container(target_class.CONTAINER_NAME, force=True)

    if not args.repeat:
        if ctn_exists(Monitor.CONTAINER_NAME):
            print 'removing monitor container', Monitor.CONTAINER_NAME
            dckr.remove_container(Monitor.CONTAINER_NAME, force=True)

        for ctn_name in get_ctn_names():
            if ctn_name.startswith("bgperf_"):
                print 'removing container', ctn_name
                dckr.remove_container(ctn_name, force=True)

        for ctn_name in get_ctn_names():
            if ctn_name.startswith(RELAY_PREFIX):
                print 'removing relay container', ctn_name
                dckr.remove_container(ctn_name, force=True)

        for ctn_name in get_ctn_names():
            if ctn_name.startswith("bgperf_throughput_tester"):
                print 'removing throughput tester container', ctn_name
                dckr.remove_container(ctn_name, force=True)

        if os.path.exists(config_dir):
            shutil.rmtree(config_dir)

    if args.file:
        with open(args.file) as f:
            conf = yaml.load(Template(f.read()).render())
    else:
        conf = gen_conf(args)
        if not os.path.exists(config_dir):
            os.makedirs(config_dir)
        with open('{0}/scenario.yaml'.format(config_dir), 'w') as f:
            f.write(conf)
        conf = yaml.load(Template(conf).render())

    bridge_found = False
    for network in dckr.networks(names=[dckr_net_name]):
        if network['Name'] == dckr_net_name:
            print 'Docker network "{}" already exists'.format(dckr_net_name)
            bridge_found = True
            break
    if not bridge_found:
        print "subnet does not exist"
        exit(1)

    if args.target == 'gobgp':
        target_class = GoBGPTarget
    elif args.target == 'bird':
        target_class = BIRDTarget
    elif args.target == 'quagga':
        target_class = QuaggaTarget
    elif args.target == 'frr':
        target_class = FRRoutingTarget
    elif args.target == 'mirage':
        target_class = MIRAGETarget
    elif args.target == 'mirage_st':
        target_class = MIRAGESTTarget

    print 'run', args.target
    target = target_class('{0}/{1}'.format(config_dir, args.target),
                          conf['target'])
    target.run(conf, dckr_net_name)

    time.sleep(3)

    print 'run relays'

    def run_relay(name, ip, listen, talk, dckr_net_name='', rm=True):
        if rm and ctn_exists(name):
            print 'remove relay containers:', name
            dckr.remove_container(name, force=True)

        ctn = dckr.create_container(
            image='sproxy',
            detach=True,
            name=name,
            environment=['LISTEN={0}'.format(listen), 'TALK={0}'.format(talk)])
        ctn_id = ctn['Id']

        ipv4_addresses = [ip]

        net_id = None
        for network in dckr.networks(names=[dckr_net_name]):
            if network['Name'] != dckr_net_name:
                continue

            net_id = network['Id']
            if not 'IPAM' in network:
                print(
                    'can\'t verify if container\'s IP addresses '
                    'are valid for Docker network {}: missing IPAM'.format(
                        dckr_net_name))
                break
            ipam = network['IPAM']

            if not 'Config' in ipam:
                print(
                    'can\'t verify if container\'s IP addresses '
                    'are valid for Docker network {}: missing IPAM.Config'.
                    format(dckr_net_name))
                break

            ip_ok = False
            network_subnets = [
                item['Subnet'] for item in ipam['Config'] if 'Subnet' in item
            ]

            for ip in ipv4_addresses:
                for subnet in network_subnets:
                    ip_ok = netaddr.IPAddress(ip) in netaddr.IPNetwork(subnet)

                if not ip_ok:
                    print(
                        'the container\'s IP address {} is not valid for Docker network {} '
                        'since it\'s not part of any of its subnets ({})'.
                        format(ip, dckr_net_name, ', '.join(network_subnets)))
                    print(
                        'Please consider removing the Docket network {net} '
                        'to allow bgperf to create it again using the '
                        'expected subnet:\n'
                        '  docker network rm {net}'.format(net=dckr_net_name))
                    sys.exit(1)
            break

        if net_id is None:
            print 'Docker network "{}" not found!'.format(dckr_net_name)
            return

        dckr.connect_container_to_network(ctn_id,
                                          net_id,
                                          ipv4_address=ipv4_addresses[0])
        dckr.start(container=name)

        return ctn

    run_relay(RELAY_PREFIX + '1', '10.10.0.3', ':50001',
              '{}:179'.format(conf['target']['local-address']), 'bgperf-br')

    run_relay(RELAY_PREFIX + '2', '10.10.0.4', ':50002',
              '{}:179'.format(conf['target']['local-address']), 'bgperf-br')

    q = Queue()
    target.stats(q)

    print 'run throughput tester'

    throughput = ThroughputTarget('{0}/{1}'.format(config_dir, 'throughput'),
                                  {})
    throughput.run(conf, dckr_net_name)

    def mem_human(v):
        if v > 1000 * 1000 * 1000:
            return '{0:.2f}GB'.format(float(v) / (1000 * 1000 * 1000))
        elif v > 1000 * 1000:
            return '{0:.2f}MB'.format(float(v) / (1000 * 1000))
        elif v > 1000:
            return '{0:.2f}KB'.format(float(v) / 1000)
        else:
            return '{0:.2f}B'.format(float(v))

    cpu = 0.0
    max_mem = 0.0
    mem = 0.0

    prev_cpu = 0.0
    while True:
        if q.empty() and prev_cpu < 0.01:
            break

        info = q.get()
        prev_cpu = info['cpu']
        cpu += info['cpu']
        mem += info['mem']
        max_mem = max(info['mem'], max_mem)

        if args.verbose:
            print 'cpu: {0:>4.2f}%, mem: {1}'.format(info['cpu'],
                                                     mem_human(info['mem']))

    print 'total CPU: {0:>4.2f}, max MEM: {1}, total mem {2}'.format(
        cpu, mem_human(max_mem), mem_human(mem))

    return