diff --git a/examples/cluster.py b/examples/cluster.py index e16170d..b6128a6 100755 --- a/examples/cluster.py +++ b/examples/cluster.py @@ -87,7 +87,7 @@ from signal import signal, SIGINT, SIG_IGN from subprocess import Popen, PIPE, STDOUT import os from random import randrange -from sys import exit +import sys import re from distutils.version import StrictVersion @@ -282,7 +282,7 @@ class RemoteOVSSwitch( RemoteMixin, OVSSwitch ): cls = type( self ) if self.server not in cls.OVSVersions: vers = self.cmd( 'ovs-vsctl --version' ) - cls.OVSVersions[ self.server ] = re.findall( '\d+\.\d+', vers )[ 0 ] + cls.OVSVersions[ self.server ] = re.findall( r'\d+\.\d+', vers )[ 0 ] return ( StrictVersion( cls.OVSVersions[ self.server ] ) < StrictVersion( '1.10' ) ) @@ -387,7 +387,7 @@ class RemoteLink( Link ): tunnel.wait() error( ch + tunnel.stdout.read() ) error( tunnel.stderr.read() ) - exit( 1 ) + sys.exit( 1 ) # 3. Move interfaces if necessary for node in node1, node2: if node.inNamespace: @@ -643,7 +643,7 @@ class MininetCluster( Mininet ): for server in self.servers: ip = self.serverIP[ server ] if not server or server == 'localhost': - continue + continue info( server, '' ) dest = '%s@%s' % ( self.user, ip ) cmd = [ 'sudo', '-E', '-u', self.user ] @@ -660,7 +660,7 @@ class MininetCluster( Mininet ): '*** Make sure that the above ssh command works correctly.\n' '*** You may also need to run mn -c on all nodes, and/or\n' '*** use sudo -E.\n' ) - exit( 1 ) + sys.exit( 1 ) info( '\n' ) def modifiedaddHost( self, *args, **kwargs ): @@ -703,7 +703,7 @@ class MininetCluster( Mininet ): if ( isinstance( controller, Controller) and controller.IP() == '127.0.0.1' and ' eth0:' in controller.cmd( 'ip link show' ) ): - Intf( 'eth0', node=controller ).updateIP() + Intf( 'eth0', node=controller ).updateIP() return controller def buildFromTopo( self, *args, **kwargs ): diff --git a/mininet/clean.py b/mininet/clean.py index 28c4fca..8883fcc 100755 --- a/mininet/clean.py +++ b/mininet/clean.py @@ -10,7 +10,8 @@ It may also get rid of 'false positives', but hopefully nothing irreplaceable! """ -from subprocess import Popen, PIPE, check_output as co +from subprocess import ( Popen, PIPE, check_output as co, + CalledProcessError ) import time from mininet.log import info @@ -28,11 +29,11 @@ def killprocs( pattern ): # Make sure they are gone while True: try: - pids = co( 'pgrep -f %s' % pattern ) - except: + pids = co( [ 'pgrep', '-f', pattern ] ) + except CalledProcessError: pids = '' if pids: - sh( 'pkill -f 9 mininet:' ) + sh( 'pkill -9 -f %s' % pattern ) time.sleep( .5 ) else: break diff --git a/mininet/cli.py b/mininet/cli.py index c3537eb..42ad779 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -96,7 +96,7 @@ class CLI( Cmd ): # Disable pylint "Unused argument: 'arg's'" messages, as well as # "method could be a function" warning, since each CLI function # must have the same interface - # pylint: disable-msg=R0201 + # pylint: disable=R0201 helpStr = ( 'You may also send a command to a node using:\n' @@ -128,7 +128,7 @@ class CLI( Cmd ): nodes = ' '.join( sorted( self.mn ) ) output( 'available nodes are: \n%s\n' % nodes ) - def do_ports( self, line ): + def do_ports( self, _line ): "display ports and interfaces for each switch" dumpPorts( self.mn.switches ) @@ -142,7 +142,7 @@ class CLI( Cmd ): call( line, shell=True ) # do_py() and do_px() need to catch any exception during eval()/exec() - # pylint: disable-msg=W0703 + # pylint: disable=W0703 def do_py( self, line ): """Evaluate a Python expression. @@ -159,7 +159,7 @@ class CLI( Cmd ): output( str( e ) + '\n' ) # We are in fact using the exec() pseudo-function - # pylint: disable-msg=W0122 + # pylint: disable=W0122 def do_px( self, line ): """Execute a Python statement. @@ -169,7 +169,7 @@ class CLI( Cmd ): except Exception, e: output( str( e ) + '\n' ) - # pylint: enable-msg=W0703,W0122 + # pylint: enable=W0703,W0122 def do_pingall( self, line ): "Ping between all hosts." @@ -346,7 +346,7 @@ class CLI( Cmd ): elapsed = time.time() - start self.stdout.write("*** Elapsed time: %0.6f secs\n" % elapsed) - def do_links( self, line ): + def do_links( self, _line ): "Report on links" for link in self.mn.links: print link, link.status() @@ -355,7 +355,8 @@ class CLI( Cmd ): "Starts or stops a switch" args = line.split() if len(args) != 2: - error( 'invalid number of args: switch {start, stop}\n' ) + error( 'invalid number of args: switch ' + '{start, stop}\n' ) return sw = args[ 0 ] command = args[ 1 ] @@ -397,7 +398,7 @@ class CLI( Cmd ): else: error( '*** Unknown command: %s\n' % line ) - # pylint: enable-msg=R0201 + # pylint: enable=R0201 def waitForNode( self, node ): "Wait for a node to finish, and print its output." diff --git a/mininet/link.py b/mininet/link.py index f71abf2..4c70ca2 100644 --- a/mininet/link.py +++ b/mininet/link.py @@ -33,7 +33,7 @@ class Intf( object ): "Basic interface object that can configure itself." def __init__( self, name, node=None, port=None, link=None, - mac=None, srcNode=None, **params ): + mac=None, **params ): """name: interface name (e.g. h1-eth0) node: owning node (where this intf most likely lives) link: parent link if we're part of a link @@ -71,7 +71,8 @@ class Intf( object ): return self.ifconfig( ipstr, 'up' ) else: if prefixLen is None: - raise Exception( 'No prefix length set for IP address %s' % ( ipstr, ) ) + raise Exception( 'No prefix length set for IP address %s' + % ( ipstr, ) ) self.ip, self.prefixLen = ipstr, prefixLen return self.ifconfig( '%s/%s' % ( ipstr, prefixLen ) ) @@ -196,7 +197,7 @@ class Intf( object ): def status( self ): "Return intf status as a string" - links, err_, result_ = self.node.pexec( 'ip link show' ) + links, _err, _result = self.node.pexec( 'ip link show' ) if self.name in links: return "OK" else: @@ -419,15 +420,19 @@ class Link( object ): def intfName( self, node, n ): "Construct a canonical interface name node-ethN for interface n." + # Leave this as an instance method for now + assert self return node.name + '-eth' + repr( n ) @classmethod - def makeIntfPair( _cls, intfname1, intfname2, addr1=None, addr2=None ): + def makeIntfPair( cls, intfname1, intfname2, addr1=None, addr2=None ): """Create pair of interfaces intfname1: name of interface 1 intfname2: name of interface 2 (override this method [and possibly delete()] to change link type)""" + # Leave this as a class method for now + assert cls return makeIntfPair( intfname1, intfname2, addr1, addr2 ) def delete( self ): diff --git a/mininet/log.py b/mininet/log.py index 5f96569..b351eb8 100644 --- a/mininet/log.py +++ b/mininet/log.py @@ -124,7 +124,7 @@ class MininetLogger( Logger, object ): self.setLevel( level ) self.handlers[ 0 ].setLevel( level ) - # pylint: disable-msg=E0202 + # pylint: disable=E0202 # "An attribute inherited from mininet.log hide this method" # Not sure why this is occurring - this function definitely gets called. @@ -142,7 +142,7 @@ class MininetLogger( Logger, object ): if self.isEnabledFor( OUTPUT ): self._log( OUTPUT, msg, args, kwargs ) - # pylint: enable-msg=E0202 + # pylint: enable=E0202 lg = MininetLogger() diff --git a/mininet/net.py b/mininet/net.py index 8d0c3bb..6e17184 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -98,7 +98,8 @@ from math import ceil from mininet.cli import CLI from mininet.log import info, error, debug, output, warn -from mininet.node import Host, OVSKernelSwitch, DefaultController, Controller +from mininet.node import ( Node, Host, OVSKernelSwitch, DefaultController, + Controller ) from mininet.nodelib import NAT from mininet.link import Link, Intf from mininet.util import quietRun, fixLimits, numCores, ensureRoot @@ -264,14 +265,24 @@ class Mininet( object ): self.nameToNode[ name ] = controller_new return controller_new - def addNAT( self, name='nat0', connect=True, inNamespace=False, **params ): + def addNAT( self, name='nat0', connect=True, inNamespace=False, + **params): + """Add a NAT to the Mininet network + name: name of NAT node + connect: switch to connect to | True (s1) | None + inNamespace: create in a network namespace + params: other NAT node params, notably: + ip: used as default gateway address""" nat = self.addHost( name, cls=NAT, inNamespace=inNamespace, subnet=self.ipBase, **params ) # find first switch and create link if connect: - # connect the nat to the first switch + if not isinstance( connect, Node ): + # Use first switch if not specified + connect = self.switches[ 0 ] + # Connect the nat to the switch self.addLink( nat, self.switches[ 0 ] ) - # set the default route on hosts + # Set the default route on hosts natIP = nat.params[ 'ip' ].split('/')[ 0 ] for host in self.hosts: if host.inNamespace: @@ -486,7 +497,8 @@ class Mininet( object ): info( '*** Stopping %i terms\n' % len( self.terms ) ) self.stopXterms() info( '*** Stopping %i switches\n' % len( self.switches ) ) - for swclass, switches in groupby( sorted( self.switches, key=type ), type ): + for swclass, switches in groupby( + sorted( self.switches, key=type ), type ): if hasattr( swclass, 'batchShutdown' ): swclass.batchShutdown( switches ) for switch in self.switches: @@ -521,13 +533,13 @@ class Mininet( object ): if hosts is None: hosts = self.hosts poller = select.poll() - Node = hosts[ 0 ] # so we can call class method fdToNode + h1 = hosts[ 0 ] # so we can call class method fdToNode for host in hosts: poller.register( host.stdout ) while True: ready = poller.poll( timeoutms ) for fd, event in ready: - host = Node.fdToNode( fd ) + host = h1.fdToNode( fd ) if event & select.POLLIN: line = host.readline() if line is not None: @@ -574,7 +586,8 @@ class Mininet( object ): if timeout: opts = '-W %s' % timeout if dest.intfs: - result = node.cmd( 'ping -c1 %s %s' % (opts, dest.IP()) ) + result = node.cmd( 'ping -c1 %s %s' % + (opts, dest.IP()) ) sent, received = self._parsePing( result ) else: sent, received = 0, 0 @@ -699,13 +712,13 @@ class Mininet( object ): # XXX This should be cleaned up - def iperf( self, hosts=None, l4Type='TCP', udpBw='10M', format=None, + def iperf( self, hosts=None, l4Type='TCP', udpBw='10M', fmt=None, seconds=5): """Run iperf between two hosts. - hosts: list of hosts; if None, uses opposite hosts + hosts: list of hosts; if None, uses first and last hosts l4Type: string, one of [ TCP, UDP ] udpBw: bandwidth target for UDP test - format: iperf format argument if any + fmt: iperf format argument if any seconds: iperf time to transmit returns: two-element array of [ server, client ] speeds note: send() is buffered, so client rate can be much higher than @@ -729,8 +742,8 @@ class Mininet( object ): bwArgs = '-b ' + udpBw + ' ' elif l4Type != 'TCP': raise Exception( 'Unexpected l4 type: %s' % l4Type ) - if format: - iperfArgs += '-f %s ' %format + if fmt: + iperfArgs += '-f %s ' % fmt server.sendCmd( iperfArgs + '-s', printPid=True ) servout = '' while server.lastPid is None: @@ -755,7 +768,7 @@ class Mininet( object ): def runCpuLimitTest( self, cpu, duration=5 ): """run CPU limit test with 'while true' processes. cpu: desired CPU fraction of each host - duration: test duration in seconds + duration: test duration in seconds (integer) returns a single list of measured CPU fractions as floats. """ cores = int( quietRun( 'nproc' ) ) @@ -776,12 +789,14 @@ class Mininet( object ): # get the initial cpu time for each host for host in hosts: outputs[ host ] = [] - with open( '/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' % host, 'r' ) as f: + with open( '/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' % + host, 'r' ) as f: time[ host ] = float( f.read() ) - for _ in range( 5 ): + for _ in range( duration ): sleep( 1 ) for host in hosts: - with open( '/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' % host, 'r' ) as f: + with open( '/sys/fs/cgroup/cpuacct/%s/cpuacct.usage' % + host, 'r' ) as f: readTime = float( f.read() ) outputs[ host ].append( ( ( readTime - time[ host ] ) / 1000000000 ) / cores * 100 ) diff --git a/mininet/node.py b/mininet/node.py index 33eb052..2cf2a4c 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -189,6 +189,8 @@ class Node( object ): """Internal method: spawn and return a process cmd: command to run (list) params: parameters to Popen()""" + # Leave this is as an instance method for now + assert self return Popen( cmd, **params ) def cleanup( self ): @@ -240,8 +242,11 @@ class Node( object ): os.killpg( self.shell.pid, signal.SIGHUP ) self.cleanup() - def stop( self ): - "Stop node." + def stop( self, deleteIntfs=False ): + """Stop node. + deleteIntfs: delete interfaces? (False)""" + if deleteIntfs: + self.deleteIntfs() self.terminate() def waitReadable( self, timeoutms=None ): @@ -324,7 +329,7 @@ class Node( object ): log = info if verbose else debug output = '' while self.waiting: - data = self.monitor() + data = self.monitor( findPid=findPid ) output += data log( data ) return output @@ -421,7 +426,7 @@ class Node( object ): warn( '*** defaultIntf: warning:', self.name, 'has no interfaces\n' ) - def intf( self, intf='' ): + def intf( self, intf=None ): """Return our interface object with given string name, default intf if name is falsy (None, empty string, etc). or the input intf arg. @@ -682,8 +687,8 @@ class CPULimitedHost( Host ): if int( self.cgroupGet( 'rt_runtime_us', 'cpu' ) ) <= 0: mncmd += [ '-r', str( self.rtprio ) ] else: - debug( '*** error: not enough cpu time available for %s.' % self.name, - 'Using cfs scheduler for subprocess\n' ) + debug( '*** error: not enough cpu time available for %s.' % + self.name, 'Using cfs scheduler for subprocess\n' ) return Host.popen( self, *args, mncmd=mncmd, **kwargs ) def cleanup( self ): @@ -698,9 +703,11 @@ class CPULimitedHost( Host ): "Check (Ubuntu,Debian) kernel config for CONFIG_RT_GROUP_SCHED for RT" if not cls._rtGroupSched: release = quietRun( 'uname -r' ).strip('\r\n') - output = quietRun( 'grep CONFIG_RT_GROUP_SCHED /boot/config-%s' % release ) + output = quietRun( 'grep CONFIG_RT_GROUP_SCHED /boot/config-%s' % + release ) if output == '# CONFIG_RT_GROUP_SCHED is not set\n': - error( '\n*** error: please enable RT_GROUP_SCHED in your kernel\n' ) + error( '\n*** error: please enable RT_GROUP_SCHED' + 'in your kernel\n' ) exit( 1 ) cls._rtGroupSched = True @@ -755,8 +762,8 @@ class CPULimitedHost( Host ): sched = self.sched if sched == 'rt': if not f or f < 0: - raise Exception( 'Please set a positive CPU fraction for sched=rt\n' ) - return + raise Exception( 'Please set a positive CPU fraction' + ' for sched=rt\n' ) pstr, qstr, period, quota = self.rtInfo( f ) elif sched == 'cfs': pstr, qstr, period, quota = self.cfsInfo( f ) @@ -881,7 +888,8 @@ class Switch( Node ): def connected( self ): "Is the switch connected to a controller? (override this method)" - return False and self # satisfy pylint + raise NotImplementedError( "connected() needs to be implemented in" + " Switch subclass %s" % self.__class__ ) def __repr__( self ): "More informative string representation" @@ -890,6 +898,7 @@ class Switch( Node ): return '<%s %s: %s pid=%s> ' % ( self.__class__.__name__, self.name, intfs, self.pid ) + class UserSwitch( Switch ): "User-space switch." @@ -982,7 +991,8 @@ class UserSwitch( Switch ): self.TCReapply( intf ) def stop( self, deleteIntfs=True ): - "Stop OpenFlow reference user datapath." + """Stop OpenFlow reference user datapath. + deleteIntfs: delete interfaces? (True)""" self.cmd( 'kill %ofdatapath' ) self.cmd( 'kill %ofprotocol' ) if deleteIntfs: @@ -1033,7 +1043,8 @@ class OVSLegacyKernelSwitch( Switch ): self.execed = False def stop( self, deleteIntfs=True ): - "Terminate kernel datapath." + """Terminate kernel datapath." + deleteIntfs: delete interfaces? (True)""" quietRun( 'ovs-dpctl del-dp ' + self.dp ) self.cmd( 'kill %ovs-openflowd' ) if deleteIntfs: @@ -1075,11 +1086,12 @@ class OVSSwitch( Switch ): 'You may wish to try ' '"service openvswitch-switch start".\n' ) exit( 1 ) - info = quietRun( 'ovs-vsctl --version' ) - cls.OVSVersion = findall( '\d+\.\d+', info )[ 0 ] + version = quietRun( 'ovs-vsctl --version' ) + cls.OVSVersion = findall( r'\d+\.\d+', version )[ 0 ] @classmethod def isOldOVS( cls ): + "Is OVS ersion < 1.10?" return ( StrictVersion( cls.OVSVersion ) < StrictVersion( '1.10' ) ) @@ -1186,7 +1198,8 @@ class OVSSwitch( Switch ): def stop( self, deleteIntfs=True ): - "Terminate OVS switch." + """Terminate OVS switch. + deleteIntfs: delete interfaces? (True)""" self.cmd( 'ovs-vsctl del-br', self ) if self.datapath == 'user': self.cmd( 'ip link del', self ) @@ -1255,7 +1268,8 @@ class IVSSwitch( Switch ): self.cmd( ' '.join(args) + ' >' + logfile + ' 2>&1 ' + cout + ' 2>' + cout + ' &' ) self.execed = False - def stop( self ): + def stop( self, *args, **kwargs ): "Stop controller." self.cmd( 'kill %' + self.command ) self.cmd( 'wait %' + self.command ) - self.terminate() + super( Controller, self ).stop( *args, **kwargs ) def IP( self, intf=None ): "Return IP address of the Controller" @@ -1343,7 +1361,8 @@ class Controller( Node ): self.__class__.__name__, self.name, self.IP(), self.port, self.pid ) @classmethod - def isAvailable( self ): + def isAvailable( cls ): + "Is controller available?" return quietRun( 'which controller' ) class OVSController( Controller ): @@ -1353,8 +1372,9 @@ class OVSController( Controller ): command = 'test-controller' Controller.__init__( self, name, command=command, **kwargs ) @classmethod - def isAvailable( self ): - return quietRun( 'which ovs-controller' ) or quietRun( 'which test-controller' ) + def isAvailable( cls ): + return ( quietRun( 'which ovs-controller' ) or + quietRun( 'which test-controller' ) ) class NOX( Controller ): "Controller to run a NOX application." @@ -1432,7 +1452,7 @@ class RemoteController( Controller ): " at %s:%d\n" % ( self.ip, self.port ) ) -DefaultControllers = [ Controller, OVSController ] +DefaultControllers = ( Controller, OVSController ) def findController( controllers=DefaultControllers ): "Return first available controller from list, if any" @@ -1446,4 +1466,3 @@ def DefaultController( name, controllers=DefaultControllers, **kwargs ): if not controller: raise Exception( 'Could not find a default OpenFlow controller' ) return controller( name, **kwargs ) - diff --git a/mininet/nodelib.py b/mininet/nodelib.py index d8a3c4f..b629051 100644 --- a/mininet/nodelib.py +++ b/mininet/nodelib.py @@ -33,7 +33,7 @@ class LinuxBridge( Switch ): else: return True - def start( self, controllers ): + def start( self, _controllers ): "Start Linux bridge" self.cmd( 'ifconfig', self, 'down' ) self.cmd( 'brctl delbr', self ) @@ -62,21 +62,22 @@ class LinuxBridge( Switch ): class NAT( Node ): - """NAT: Provides connectivity to external network""" + "NAT: Provides connectivity to external network" - def __init__( self, name, inetIntf=None, subnet='10.0/8', localIntf=None, **params): + def __init__( self, name, inetIntf=None, subnet='10.0/8', + localIntf=None, **params): + """Start NAT/forwarding between Mininet and external network + inetIntf: interface for internet access + subnet: Mininet subnet (default 10.0/8)=""" super( NAT, self ).__init__( name, **params ) - """Start NAT/forwarding between Mininet and external network - inetIntf: interface for internet access - subnet: Mininet subnet (default 10.0/8)=""" self.inetIntf = inetIntf if inetIntf else self.getGatewayIntf() self.subnet = subnet self.localIntf = localIntf def config( self, **params ): - super( NAT, self).config( **params ) """Configure the NAT and iptables""" + super( NAT, self).config( **params ) if not self.localIntf: self.localIntf = self.defaultIntf() @@ -94,10 +95,14 @@ class NAT( Node ): self.cmd( 'iptables -P FORWARD DROP' ) # Configure NAT - self.cmd( 'iptables -I FORWARD -i', self.localIntf, '-d', self.subnet, '-j DROP' ) - self.cmd( 'iptables -A FORWARD -i', self.localIntf, '-s', self.subnet, '-j ACCEPT' ) - self.cmd( 'iptables -A FORWARD -i', self.inetIntf, '-d', self.subnet, '-j ACCEPT' ) - self.cmd( 'iptables -t nat -A POSTROUTING -o ', self.inetIntf, '-s', self.subnet, '-j MASQUERADE' ) + self.cmd( 'iptables -I FORWARD', + '-i', self.localIntf, '-d', self.subnet, '-j DROP' ) + self.cmd( 'iptables -A FORWARD', + '-i', self.localIntf, '-s', self.subnet, '-j ACCEPT' ) + self.cmd( 'iptables -A FORWARD', + '-i', self.inetIntf, '-d', self.subnet, '-j ACCEPT' ) + self.cmd( 'iptables -t nat -A POSTROUTING', + '-o', self.inetIntf, '-s', self.subnet, '-j MASQUERADE' ) # Instruct the kernel to perform forwarding self.cmd( 'sysctl net.ipv4.ip_forward=1' ) @@ -116,14 +121,17 @@ class NAT( Node ): # hopefully this won't disconnect you self.cmd( 'service network-manager restart' ) - def getGatewayIntf( self ): + def getGatewayIntf( self, fallback='eth0' ): + """Return gateway interface name + fallback: default device to fall back to""" routes = self.cmd( 'ip route show' ) - match = re.search('default via \S+ dev (\S+)', routes ) + match = re.search( r'default via \S+ dev (\S+)', routes ) if match: return match.group( 1 ) else: - warn( 'There is no default route set. Using eth0 as gateway interface...\n' ) - return 'eth0' + warn( 'There is no default route set.', + 'Using', fallback, 'as gateway interface...\n' ) + return fallback def terminate( self ): """Stop NAT/forwarding between Mininet and external network""" @@ -136,4 +144,3 @@ class NAT( Node ): self.cmd( 'sysctl net.ipv4.ip_forward=0' ) super( NAT, self ).terminate() - diff --git a/mininet/topo.py b/mininet/topo.py index 951770f..3856a49 100644 --- a/mininet/topo.py +++ b/mininet/topo.py @@ -111,7 +111,8 @@ class Topo( object ): self.hopts = params.pop( 'hopts', {} ) self.sopts = params.pop( 'sopts', {} ) self.lopts = params.pop( 'lopts', {} ) - self.ports = {} # ports[src][dst][sport] is port on dst that connects to src + # ports[src][dst][sport] is port on dst that connects to src + self.ports = {} self.build( *args, **params ) def build( self, *args, **params ): @@ -187,7 +188,7 @@ class Topo( object ): withKeys: return link keys withInfo: return link info returns: list of ( src, dst [,key, info ] )""" - for src, dst, key, info in self.g.edges_iter( data=True, keys=True ): + for _src, _dst, key, info in self.g.edges_iter( data=True, keys=True ): node1, node2 = info[ 'node1' ], info[ 'node2' ] if withKeys: if withInfo: @@ -207,7 +208,7 @@ class Topo( object ): withInfo: return link info returns: list of ( src, dst [,key, info ] )""" links = list( self.iterLinks( withKeys, withInfo ) ) - if not sorted: + if not sort: return links # Ignore info when sorting tupleSize = 3 if withKeys else 2 @@ -287,10 +288,13 @@ class Topo( object ): return sorted( items, key=natural ) +# Our idiom defines additional parameters in build(param...) +# pylint: disable=arguments-differ, attribute-defined-outside-init + class SingleSwitchTopo( Topo ): "Single switch connected to k hosts." - def build( self, k=2, **opts ): + def build( self, k=2, **_opts ): "k: number of hosts" self.k = k switch = self.addSwitch( 's1' ) @@ -317,7 +321,7 @@ class SingleSwitchReversedTopo( Topo ): class LinearTopo( Topo ): "Linear topology of k switches, with n hosts per switch." - def build( self, k=2, n=1, **opts): + def build( self, k=2, n=1, **_opts): """k: number of switches n: number of hosts per switch""" self.k = k @@ -340,3 +344,5 @@ class LinearTopo( Topo ): if lastSwitch: self.addLink( switch, lastSwitch ) lastSwitch = switch + +# pylint: enable=arguments-differ, attribute-defined-outside-init diff --git a/mininet/topolib.py b/mininet/topolib.py index 3a00ab4..f78acc8 100644 --- a/mininet/topolib.py +++ b/mininet/topolib.py @@ -3,6 +3,9 @@ from mininet.topo import Topo from mininet.net import Mininet +# The build() method is expected to do both of these things: +# pylint: disable=attribute-defined-outside-init, arguments-differ + class TreeTopo( Topo ): "Topology for a tree network with a given depth and fanout." @@ -53,7 +56,8 @@ class TorusTopo( Topo ): loc = '%dx%d' % ( i + 1, j + 1 ) # dpid cannot be zero for OVS dpid = ( i + 1 ) * 256 + ( j + 1 ) - switch = switches[ i, j ] = self.addSwitch( 's' + loc, dpid='%016x' % dpid ) + switch = switches[ i, j ] = self.addSwitch( + 's' + loc, dpid='%016x' % dpid ) host = hosts[ i, j ] = self.addHost( 'h' + loc ) self.addLink( host, switch ) # Connect switches @@ -65,5 +69,4 @@ class TorusTopo( Topo ): self.addLink( sw1, sw2 ) self.addLink( sw1, sw3 ) - - +# pylint: enable=attribute-defined-outside-init, arguments-differ diff --git a/mininet/util.py b/mininet/util.py index 74a2424..6334649 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -25,7 +25,7 @@ def checkRun( cmd ): return check_call( cmd.split( ' ' ) ) # pylint doesn't understand explicit type checking -# pylint: disable-msg=E1103 +# pylint: disable=E1103 def oldQuietRun( *cmd ): """Run a command, routing stderr to stdout, and return the output. @@ -119,8 +119,8 @@ def quietRun( cmd, **kwargs ): "Run a command and return merged stdout and stderr" return errRun( cmd, stderr=STDOUT, **kwargs )[ 0 ] -# pylint: enable-msg=E1103 -# pylint: disable-msg=E1101 +# pylint: enable=E1103 +# pylint: disable=E1101 def isShellBuiltin( cmd ): "Return True if cmd is a bash builtin." @@ -133,7 +133,7 @@ def isShellBuiltin( cmd ): isShellBuiltin.builtIns = None -# pylint: enable-msg=E1101 +# pylint: enable=E1101 # Interface management # @@ -148,22 +148,22 @@ isShellBuiltin.builtIns = None # live in the root namespace and thus do not have to be # explicitly moved. -def makeIntfPair( intf1, intf2, addr1=None, addr2=None, run=quietRun ): +def makeIntfPair( intf1, intf2, addr1=None, addr2=None, runCmd=quietRun ): """Make a veth pair connecting intf1 and intf2. intf1: string, interface intf2: string, interface - node: node to run on or None (default) + runCmd: function to run shell commands (quietRun) returns: ip link add result""" # Delete any old interfaces with the same names - run( 'ip link del ' + intf1 ) - run( 'ip link del ' + intf2 ) + runCmd( 'ip link del ' + intf1 ) + runCmd( 'ip link del ' + intf2 ) # Create new pair if addr1 is None and addr2 is None: cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2 else: cmd = ( 'ip link add name ' + intf1 + ' address ' + addr1 + ' type veth peer name ' + intf2 + ' address ' + addr2 ) - cmdOutput = run( cmd ) + cmdOutput = runCmd( cmd ) if cmdOutput == '': return True else: @@ -202,7 +202,7 @@ def moveIntfNoRetry( intf, dstNode, printError=False ): return False return True -def moveIntf( intf, dstNode, srcNode=None, printError=True, +def moveIntf( intf, dstNode, printError=True, retries=3, delaySecs=0.001 ): """Move interface to node, retrying on failure. intf: string, interface @@ -296,7 +296,7 @@ def ipAdd( i, prefixLen=8, ipBaseNum=0x0a000000 ): def ipParse( ip ): "Parse an IP address and return an unsigned int." args = [ int( arg ) for arg in ip.split( '.' ) ] - while ( len(args) < 4 ): + while len(args) < 4: args.append( 0 ) return ipNum( *args ) @@ -427,7 +427,7 @@ def fixLimits(): sysctlTestAndSet( 'net.ipv4.route.max_size', 32768 ) #Increase number of PTYs for nodes sysctlTestAndSet( 'kernel.pty.max', 20000 ) - except: + except Exception: warn( "*** Error setting resource limits. " "Mininet's performance may be affected.\n" ) @@ -545,9 +545,9 @@ def ensureRoot(): def waitListening( client=None, server='127.0.0.1', port=80, timeout=None ): """Wait until server is listening on port. returns True if server is listening""" - run = ( client.cmd if client else + runCmd = ( client.cmd if client else partial( quietRun, shell=True ) ) - if not run( 'which telnet' ): + if not runCmd( 'which telnet' ): raise Exception('Could not find telnet' ) serverIP = server if isinstance( server, basestring ) else server.IP() cmd = ( 'sh -c "echo A | telnet -e A %s %s"' %