Beispiel #1
0
 def makeTunnel( self, node1, node2, intfname1, intfname2,
                 addr1=None, addr2=None ):
     "Make a tunnel across switches on different servers"
     # We should never try to create a tunnel to ourselves!
     assert node1.server != node2.server
     # And we can't ssh into this server remotely as 'localhost',
     # so try again swappping node1 and node2
     if node2.server == 'localhost':
         return self.makeTunnel( node1=node2, node2=node1,
                                 intfname1=intfname2, intfname2=intfname1,
                                 addr1=addr2, addr2=addr1 )
     debug( '\n*** Make SSH tunnel ' + node1.server + ':' + intfname1 +
            ' == ' + node2.server + ':' + intfname2 )
     # 1. Create tap interfaces
     for node in node1, node2:
         # For now we are hard-wiring tap9, which we will rename
         cmd = 'ip tuntap add dev tap9 mode tap user ' + node.user
         result = node.rcmd( cmd )
         if result:
             raise Exception( 'error creating tap9 on %s: %s' %
                              ( node, result ) )
     # 2. Create ssh tunnel between tap interfaces
     # -n: close stdin
     dest = '%s@%s' % ( node2.user, node2.serverIP )
     cmd = [ 'ssh', '-n', '-o', 'Tunnel=Ethernet', '-w', '9:9',
             dest, 'echo @' ]
     self.cmd = cmd
     tunnel = node1.rpopen( cmd, sudo=False )
     # When we receive the character '@', it means that our
     # tunnel should be set up
     debug( 'Waiting for tunnel to come up...\n' )
     ch = decode( tunnel.stdout.read( 1 ) )
     if ch != '@':
         ch += decode( tunnel.stdout.read() )
         cmd = ' '.join( cmd )
         raise Exception( 'makeTunnel:\n'
                          'Tunnel setup failed for '
                          '%s:%s' % ( node1, node1.dest ) + ' to '
                          '%s:%s\n' % ( node2, node2.dest ) +
                          'command was: %s' % cmd + '\n' +
                          'result was: ' + ch )
     # 3. Move interfaces if necessary
     for node in node1, node2:
         if not self.moveIntf( 'tap9', node ):
             raise Exception( 'interface move failed on node %s' % node )
     # 4. Rename tap interfaces to desired names
     for node, intf, addr in ( ( node1, intfname1, addr1 ),
                               ( node2, intfname2, addr2 ) ):
         if not addr:
             result = node.cmd( 'ip link set tap9 name', intf )
         else:
             result = node.cmd( 'ip link set tap9 name', intf,
                                'address', addr )
         if result:
             raise Exception( 'error renaming %s: %s' % ( intf, result ) )
     return tunnel
Beispiel #2
0
def monitorFiles(outfiles, seconds, timeoutms):
    "Monitor set of files and return [(host, line)...]"
    devnull = open('/dev/null', 'w')
    tails, fdToFile, fdToHost = {}, {}, {}
    for h, outfile in outfiles.items():
        tail = Popen(['tail', '-f', outfile], stdout=PIPE, stderr=devnull)
        fd = tail.stdout.fileno()
        tails[h] = tail
        fdToFile[fd] = tail.stdout
        fdToHost[fd] = h
    # Prepare to poll output files
    readable = poll()
    for t in tails.values():
        readable.register(t.stdout.fileno(), POLLIN)
    # Run until a set number of seconds have elapsed
    endTime = time() + seconds
    while time() < endTime:
        fdlist = readable.poll(timeoutms)
        if fdlist:
            for fd, _flags in fdlist:
                f = fdToFile[fd]
                host = fdToHost[fd]
                # Wait for a line of output
                line = f.readline().strip()
                yield host, decode(line)
        else:
            # If we timed out, return nothing
            yield None, ''
    for t in tails.values():
        t.terminate()
    devnull.close()  # Not really necessary
Beispiel #3
0
def monitorFiles( outfiles, seconds, timeoutms ):
    "Monitor set of files and return [(host, line)...]"
    devnull = open( '/dev/null', 'w' )
    tails, fdToFile, fdToHost = {}, {}, {}
    for h, outfile in outfiles.items():
        tail = Popen( [ 'tail', '-f', outfile ],
                      stdout=PIPE, stderr=devnull )
        fd = tail.stdout.fileno()
        tails[ h ] = tail
        fdToFile[ fd ] = tail.stdout
        fdToHost[ fd ] = h
    # Prepare to poll output files
    readable = poll()
    for t in tails.values():
        readable.register( t.stdout.fileno(), POLLIN )
    # Run until a set number of seconds have elapsed
    endTime = time() + seconds
    while time() < endTime:
        fdlist = readable.poll(timeoutms)
        if fdlist:
            for fd, _flags in fdlist:
                f = fdToFile[ fd ]
                host = fdToHost[ fd ]
                # Wait for a line of output
                line = f.readline().strip()
                yield host, decode( line )
        else:
            # If we timed out, return nothing
            yield None, ''
    for t in tails.values():
        t.terminate()
    devnull.close()  # Not really necessary
Beispiel #4
0
 def rcmd(self, *cmd, **opts):
     """rcmd: run a command on underlying server
        in root namespace
        args: string or list of strings
        returns: stdout and stderr"""
     popen = self.rpopen(*cmd, **opts)
     # info( 'RCMD: POPEN:', popen, '\n' )
     # These loops are tricky to get right.
     # Once the process exits, we can read
     # EOF twice if necessary.
     result = ''
     while True:
         poll = popen.poll()
         result += decode(popen.stdout.read())
         if poll is not None:
             break
     return result
Beispiel #5
0
def bwtest(cpuLimits, period_us=100000, seconds=10):
    """Example/test of link and CPU bandwidth limits
       cpu: cpu limit as fraction of overall CPU time"""

    topo = TreeTopo(depth=1, fanout=2)

    results = {}

    for sched in 'rt', 'cfs':
        info('*** Testing with', sched, 'bandwidth limiting\n')
        for cpu in cpuLimits:
            # cpu is the cpu fraction for all hosts, so we divide
            # it across two hosts
            host = custom(CPULimitedHost,
                          sched=sched,
                          period_us=period_us,
                          cpu=.5 * cpu)
            try:
                net = Mininet(topo=topo, host=host, waitConnected=True)
            # pylint: disable=bare-except
            except:
                info('*** Skipping scheduler %s and cleaning up\n' % sched)
                cleanup()
                break
            net.start()
            net.pingAll()
            hosts = [net.getNodeByName(h) for h in topo.hosts()]
            client, server = hosts[0], hosts[-1]
            info('*** Starting iperf with %d%% of CPU allocated to hosts\n' %
                 (100.0 * cpu))
            # We measure at the server because it doesn't include
            # the client's buffer fill rate
            popen = server.popen('iperf -yc -s -p 5001')
            waitListening(client, server, 5001)
            # ignore empty result from waitListening/telnet
            popen.stdout.readline()
            client.cmd('iperf -yc -t %s -c %s' % (seconds, server.IP()))
            result = decode(popen.stdout.readline()).split(',')
            bps = float(result[-1])
            popen.terminate()
            net.stop()
            updated = results.get(sched, [])
            updated += [(cpu, bps)]
            results[sched] = updated

    return results
Beispiel #6
0
def bwtest( cpuLimits, period_us=100000, seconds=10 ):
    """Example/test of link and CPU bandwidth limits
       cpu: cpu limit as fraction of overall CPU time"""

    topo = TreeTopo( depth=1, fanout=2 )

    results = {}

    for sched in 'rt', 'cfs':
        info( '*** Testing with', sched, 'bandwidth limiting\n' )
        for cpu in cpuLimits:
            # cpu is the cpu fraction for all hosts, so we divide
            # it across two hosts
            host = custom( CPULimitedHost, sched=sched,
                           period_us=period_us,
                           cpu=.5*cpu )
            try:
                net = Mininet( topo=topo, host=host )
            # pylint: disable=bare-except
            except:
                info( '*** Skipping scheduler %s and cleaning up\n' % sched )
                cleanup()
                break
            net.start()
            net.pingAll()
            hosts = [ net.getNodeByName( h ) for h in topo.hosts() ]
            client, server = hosts[ 0 ], hosts[ -1 ]
            info( '*** Starting iperf with %d%% of CPU allocated to hosts\n' %
                  ( 100.0 * cpu ) )
            # We measure at the server because it doesn't include
            # the client's buffer fill rate
            popen = server.popen( 'iperf -yc -s -p 5001' )
            waitListening( client, server, 5001 )
            # ignore empty result from waitListening/telnet
            popen.stdout.readline()
            client.cmd( 'iperf -yc -t %s -c %s' % ( seconds, server.IP() ) )
            result = decode( popen.stdout.readline() ).split( ',' )
            bps = float( result[ -1 ] )
            popen.terminate()
            net.stop()
            updated = results.get( sched, [] )
            updated += [ ( cpu, bps ) ]
            results[ sched ] = updated

    return results
Beispiel #7
0
def check(hosts, groups):
    """Check VLAN connectivity groups, returning error count"""

    vlan = {host: group for group in groups for host in group}

    # Start pings
    pings = [(src, dst, src.popen('ping -w1 -c1 %s' % dst.IP()))
             for src in hosts for dst in hosts]

    errors = 0

    # Collect and verify ping results
    for src, dst, ping in pings:

        out, err = ping.communicate()
        result = decode(out + err)
        ping.wait()

        # The space before '0%' is very important
        dropped = '100% packet loss' in result
        sent = ' 0% packet loss' in result

        # Sanity check
        if sent == dropped:
            raise RuntimeError('ping failed with output: %s' % result)

        info(src, '->', dst, 'sent' if sent else 'dropped', '\n')

        # Ping should only succeed when src and dst are in the same VLAN
        connected = (vlan[src] == vlan[dst])
        if sent != connected:
            error('ERROR:', src, 'should' if connected else 'should not',
                  'be able to ping', dst, '\n')
            errors += 1

    # Return error count
    return errors
Beispiel #8
0
def sh(cmd):
    "Print a command and send it to the shell"
    info(cmd + '\n')
    result = Popen(['/bin/sh', '-c', cmd], stdout=PIPE).communicate()[0]
    return decode(result)
Beispiel #9
0
def sh( cmd ):
    "Print a command and send it to the shell"
    info( cmd + '\n' )
    result = Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ]
    return decode( result )