diff --git a/bin/mn b/bin/mn index a7b1479..24dd6fb 100755 --- a/bin/mn +++ b/bin/mn @@ -256,7 +256,7 @@ class MininetRunner( object ): opts.add_option( '--arp', action='store_true', default=False, help='set all-pairs ARP entries' ) opts.add_option( '--verbosity', '-v', type='choice', - choices=LEVELS.keys(), default = 'info', + choices=list( LEVELS.keys() ), default = 'info', help = '|'.join( LEVELS.keys() ) ) opts.add_option( '--innamespace', action='store_true', default=False, help='sw and ctrl in namespace?' ) @@ -286,7 +286,7 @@ class MininetRunner( object ): metavar='server1,server2...', help=( 'run on multiple servers (experimental!)' ) ) opts.add_option( '--placement', type='choice', - choices=PLACEMENT.keys(), default='block', + choices=list( PLACEMENT.keys() ), default='block', metavar='block|random', help=( 'node placement for --cluster ' '(experimental!) ' ) ) diff --git a/mininet/clean.py b/mininet/clean.py index 248de8b..f66d633 100755 --- a/mininet/clean.py +++ b/mininet/clean.py @@ -16,12 +16,13 @@ import time from mininet.log import info from mininet.term import cleanUpScreens - +from mininet.util import decode def sh( cmd ): "Print a command and send it to the shell" info( cmd + '\n' ) - return Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ] + result = Popen( [ '/bin/sh', '-c', cmd ], stdout=PIPE ).communicate()[ 0 ] + return decode( result ) def killprocs( pattern ): "Reliably terminate processes matching a pattern (including args)" @@ -76,7 +77,6 @@ class Cleanup( object ): for dp in dps: if dp: sh( 'dpctl deldp ' + dp ) - info( "*** Removing OVS datapaths\n" ) dps = sh("ovs-vsctl --timeout=1 list-br").strip().splitlines() if dps: diff --git a/mininet/link.py b/mininet/link.py index d514de6..170d022 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -164,7 +164,7 @@ class Intf( object ): method: config method name param: arg=value (ignore if value=None) value may also be list or dict""" - name, value = param.items()[ 0 ] + name, value = list( param.items() )[ 0 ] f = getattr( self, method, None ) if not f or value is None: return diff --git a/mininet/moduledeps.py b/mininet/moduledeps.py index 860c21c..fda2d70 100644 --- a/mininet/moduledeps.py +++ b/mininet/moduledeps.py @@ -1,6 +1,6 @@ "Module dependency utility functions for Mininet." -from mininet.util import quietRun +from mininet.util import quietRun, BaseString from mininet.log import info, error, debug from os import environ @@ -28,9 +28,9 @@ def moduleDeps( subtract=None, add=None ): add: string or list of module names to add, if not already loaded""" subtract = subtract if subtract is not None else [] add = add if add is not None else [] - if isinstance( subtract, basestring ): + if isinstance( subtract, BaseString ): subtract = [ subtract ] - if isinstance( add, basestring ): + if isinstance( add, BaseString ): add = [ add ] for mod in subtract: if mod in lsmod(): diff --git a/mininet/net.py b/mininet/net.py index 2c7668d..d7bbf4f 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -104,7 +104,7 @@ from mininet.nodelib import NAT from mininet.link import Link, Intf from mininet.util import ( quietRun, fixLimits, numCores, ensureRoot, macColonHex, ipStr, ipParse, netParse, ipAdd, - waitListening ) + waitListening, BaseString ) from mininet.term import cleanUpScreens, makeTerms # Mininet version: should be consistent with README and LICENSE @@ -383,8 +383,8 @@ class Mininet( object ): params: additional link params (optional) returns: link object""" # Accept node objects or names - node1 = node1 if not isinstance( node1, basestring ) else self[ node1 ] - node2 = node2 if not isinstance( node2, basestring ) else self[ node2 ] + node1 = node1 if not isinstance( node1, BaseString ) else self[ node1 ] + node2 = node2 if not isinstance( node2, BaseString ) else self[ node2 ] options = dict( params ) # Port is optional if port1 is not None: diff --git a/mininet/node.py b/mininet/node.py index 42b3780..ba09f84 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -62,7 +62,8 @@ from time import sleep from mininet.log import info, error, warn, debug from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin, - numCores, retry, mountCgroups ) + numCores, retry, mountCgroups, BaseString, decode, + encode ) from mininet.moduledeps import moduleDeps, pathCheck, TUN from mininet.link import Link, Intf, TCIntf, OVSIntf from re import findall @@ -144,7 +145,9 @@ class Node( object ): master, slave = pty.openpty() self.shell = self._popen( cmd, stdin=slave, stdout=slave, stderr=slave, close_fds=False ) - self.stdin = os.fdopen( master, 'rw' ) + # XXX BL: This doesn't seem right, and we should also probably + # close our files when we exit... + self.stdin = os.fdopen( master, 'r' ) self.stdout = self.stdin self.pid = self.shell.pid self.pollOut = select.poll() @@ -171,7 +174,7 @@ class Node( object ): def mountPrivateDirs( self ): "mount private directories" # Avoid expanding a string into a list of chars - assert not isinstance( self.privateDirs, basestring ) + assert not isinstance( self.privateDirs, BaseString ) for directory in self.privateDirs: if isinstance( directory, tuple ): # mount given private directory @@ -218,7 +221,7 @@ class Node( object ): maxbytes: maximum number of bytes to return""" count = len( self.readbuf ) if count < maxbytes: - data = os.read( self.stdout.fileno(), maxbytes - count ) + data = decode( os.read( self.stdout.fileno(), maxbytes - count ) ) self.readbuf += data if maxbytes >= len( self.readbuf ): result = self.readbuf @@ -242,7 +245,7 @@ class Node( object ): def write( self, data ): """Write data to node. data: string""" - os.write( self.stdin.fileno(), data ) + os.write( self.stdin.fileno(), encode( data ) ) def terminate( self ): "Send kill signal to Node and clean up after it." @@ -376,7 +379,7 @@ class Node( object ): if isinstance( args[ 0 ], list ): # popen([cmd, arg1, arg2...]) cmd = args[ 0 ] - elif isinstance( args[ 0 ], basestring ): + elif isinstance( args[ 0 ], BaseString ): # popen("cmd arg1 arg2...") cmd = args[ 0 ].split() else: @@ -462,7 +465,7 @@ class Node( object ): """ if not intf: return self.defaultIntf() - elif isinstance( intf, basestring): + elif isinstance( intf, BaseString): return self.nameToIntf[ intf ] else: return intf @@ -514,7 +517,7 @@ class Node( object ): """Set the default route to go through intf. intf: Intf or {dev via ...}""" # Note setParam won't call us if intf is none - if isinstance( intf, basestring ) and ' ' in intf: + if isinstance( intf, BaseString ) and ' ' in intf: params = intf else: params = 'dev %s' % intf @@ -561,7 +564,7 @@ class Node( object ): method: config method name param: arg=value (ignore if value=None) value may also be list or dict""" - name, value = param.items()[ 0 ] + name, value = list( param.items() )[ 0 ] if value is None: return f = getattr( self, method, None ) @@ -610,7 +613,7 @@ class Node( object ): def intfList( self ): "List of our interfaces sorted by port number" - return [ self.intfs[ p ] for p in sorted( self.intfs.iterkeys() ) ] + return [ self.intfs[ p ] for p in sorted( self.intfs.keys() ) ] def intfNames( self ): "The names of our interfaces sorted by port number" @@ -1232,7 +1235,7 @@ class OVSSwitch( Switch ): run( cmds, shell=True ) # Reapply link config if necessary... for switch in switches: - for intf in switch.intfs.itervalues(): + for intf in switch.intfs.values(): if isinstance( intf, TCIntf ): intf.config( **intf.params ) return switches diff --git a/mininet/topo.py b/mininet/topo.py index 629632f..bc60c05 100644 --- a/mininet/topo.py +++ b/mininet/topo.py @@ -57,12 +57,12 @@ class MultiGraph( object ): def edges_iter( self, data=False, keys=False ): "Iterator: return graph edges, optionally with data and keys" - for src, entry in self.edge.iteritems(): - for dst, entrykeys in entry.iteritems(): + for src, entry in self.edge.items(): + for dst, entrykeys in entry.items(): if src > dst: # Skip duplicate edges continue - for k, attrs in entrykeys.iteritems(): + for k, attrs in entrykeys.items(): if data: if keys: yield( src, dst, k, attrs ) diff --git a/mininet/util.py b/mininet/util.py index 6cccddc..3b80f58 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -12,6 +12,18 @@ from fcntl import fcntl, F_GETFL, F_SETFL from os import O_NONBLOCK import os from functools import partial +import sys + +# Python 2/3 compatibility +Python3 = sys.version_info[0] == 3 +BaseString = str if Python3 else basestring +Encoding = 'utf-8' if Python3 else None +def decode( s ): + "Decode a byte string if needed for Python 3" + return s.decode( Encoding ) if Python3 else s +def encode( s ): + "Encode a byte string if needed for Python 3" + return s.encode( Encoding ) if Python3 else s # Command execution support @@ -98,6 +110,8 @@ def errRun( *cmd, **kwargs ): f = fdtofile[ fd ] if event & POLLIN: data = f.read( 1024 ) + if Python3: + data = data.decode( Encoding ) if echo: output( data ) if f == popen.stdout: @@ -374,7 +388,7 @@ def pmonitor(popens, timeoutms=500, readline=True, terminates: when all EOFs received""" poller = poll() fdToHost = {} - for host, popen in popens.iteritems(): + for host, popen in popens.items(): fd = popen.stdout.fileno() fdToHost[ fd ] = host poller.register( fd, POLLIN )