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
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
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
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
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
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
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
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)
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 )