Revision 723d068c

View differences:

Makefile
1
all: codecheck test
2

  
1 3
clean:
2 4
	rm -rf build dist build *.egg-info *.pyc
3 5

  
6
codecheck: mininet/*.py mininet/test/*.py
7
	pyflakes mininet/*.py mininet/test/*.py bin/*.py
8
	pylint --rcfile=.pylint mininet/*.py mininet/test/*.py bin/*.py
9
	pep8 --ignore=E251 mininet/*.py mininet/test/*.py bin/*.py
10

  
4 11
test: mininet/*.py mininet/test/*.py
5
	mininet/test/test_nets.py
12
	mininet/test/test_nets.py
bin/mn_clean.py
12 12
"""
13 13

  
14 14
from subprocess import Popen, PIPE
15
import re
16 15

  
17
from mininet.util import quietRun
18 16
from mininet.xterm import cleanUpScreens
19 17

  
20
def sh( cmd ): 
21
   "Print a command and send it to the shell"
22
   print cmd
23
   return Popen( [ '/bin/sh', '-c', cmd ], 
24
      stdout=PIPE ).communicate()[ 0 ]
25 18

  
26
 
19
def sh(cmd):
20
    "Print a command and send it to the shell"
21
    print cmd
22
    return Popen(['/bin/sh', '-c', cmd], stdout=PIPE).communicate()[0]
23

  
24

  
27 25
def cleanup():
28
   """Clean up junk which might be left over from old runs;
29
      do fast stuff before slow dp and link removal!"""
30
      
31
   print "*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes"
32
   zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core '
33
   zombies += 'udpbwtest'
34
   # Note: real zombie processes can't actually be killed, since they 
35
   # are already (un)dead. Then again,
36
   # you can't connect to them either, so they're mostly harmless.
37
   sh( 'killall -9 ' + zombies + ' 2> /dev/null' )
38

  
39
   print "*** Removing junk from /tmp"
40
   sh( 'rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log' )
41

  
42
   print "*** Removing old screen sessions"
43
   cleanUpScreens()
44

  
45
   print "*** Removing excess kernel datapaths"
46
   dps = sh( "ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'" ).split( '\n')
47
   for dp in dps: 
48
      if dp != '': sh( 'dpctl deldp ' + dp )
49
      
50
   print "*** Removing all links of the pattern foo-ethX"
51
   links = sh( "ip link show | egrep -o '(\w+-eth\w+)'" ).split( '\n' )
52
   for link in links: 
53
      if link != '': sh( "ip link del " + link )
54

  
55
   print "*** Cleanup complete."
26
    """Clean up junk which might be left over from old runs;
27
       do fast stuff before slow dp and link removal!"""
28

  
29
    print "*** Removing excess controllers/ofprotocols/ofdatapaths/pings/noxes"
30
    zombies = 'controller ofprotocol ofdatapath ping nox_core lt-nox_core '
31
    zombies += 'udpbwtest'
32
    # Note: real zombie processes can't actually be killed, since they
33
    # are already (un)dead. Then again,
34
    # you can't connect to them either, so they're mostly harmless.
35
    sh('killall -9 ' + zombies + ' 2> /dev/null')
36

  
37
    print "*** Removing junk from /tmp"
38
    sh('rm -f /tmp/vconn* /tmp/vlogs* /tmp/*.out /tmp/*.log')
39

  
40
    print "*** Removing old screen sessions"
41
    cleanUpScreens()
42

  
43
    print "*** Removing excess kernel datapaths"
44
    dps = sh("ps ax | egrep -o 'dp[0-9]+' | sed 's/dp/nl:/'").split('\n')
45
    for dp in dps:
46
        if dp != '':
47
            sh('dpctl deldp ' + dp)
48

  
49
    print "*** Removing all links of the pattern foo-ethX"
50
    links = sh("ip link show | egrep -o '(\w+-eth\w+)'").split('\n')
51
    for link in links:
52
        if link != '':
53
            sh("ip link del " + link)
54

  
55
    print "*** Cleanup complete."
56 56

  
57 57
if __name__ == "__main__":
58
   cleanup()
58
    cleanup()
bin/mn_run.py
13 13
except ImportError:
14 14
    USE_RIPCORD = False
15 15

  
16
from mininet.logging_mod import lg, set_loglevel, LEVELS
16
from mininet.logging_mod import lg, LEVELS
17 17
from mininet.net import Mininet, init
18 18
from mininet.node import KernelSwitch, Host, Controller, ControllerParams, NOX
19 19
from mininet.node import RemoteController, UserSwitch
......
21 21

  
22 22
# built in topologies, created only when run
23 23
TOPO_DEF = 'minimal'
24
TOPOS = {'minimal' :   (lambda: SingleSwitchTopo(k = 2)),
25
         'reversed' :  (lambda: SingleSwitchReversedTopo(k = 2)),
26
         'single4' :   (lambda: SingleSwitchTopo(k = 4)),
27
         'single100' : (lambda: SingleSwitchTopo(k = 100)),
28
         'linear2' :   (lambda: LinearTopo(k = 2)),
29
         'linear100' : (lambda: LinearTopo(k = 100))}
24
TOPOS = {'minimal': (lambda: SingleSwitchTopo(k = 2)),
25
         'reversed': (lambda: SingleSwitchReversedTopo(k = 2)),
26
         'single4': (lambda: SingleSwitchTopo(k = 4)),
27
         'single100': (lambda: SingleSwitchTopo(k = 100)),
28
         'linear2': (lambda: LinearTopo(k = 2)),
29
         'linear100': (lambda: LinearTopo(k = 100))}
30 30
if USE_RIPCORD:
31 31
    TOPOS_RIPCORD = {
32
         'tree16' :   (lambda: TreeTopo(depth = 3, fanout = 4)),
33
         'tree64' :   (lambda: TreeTopo(depth = 4, fanout = 4)),
34
         'tree1024' : (lambda: TreeTopo(depth = 3, fanout = 32)),
35
         'fattree4' : (lambda: FatTreeTopo(k = 4)),
36
         'fattree6' : (lambda: FatTreeTopo(k = 6)),
37
         'vl2'      : (lambda: VL2Topo(da = 4, di = 4))}
32
         'tree16': (lambda: TreeTopo(depth = 3, fanout = 4)),
33
         'tree64': (lambda: TreeTopo(depth = 4, fanout = 4)),
34
         'tree1024': (lambda: TreeTopo(depth = 3, fanout = 32)),
35
         'fattree4': (lambda: FatTreeTopo(k = 4)),
36
         'fattree6': (lambda: FatTreeTopo(k = 6)),
37
         'vl2': (lambda: VL2Topo(da = 4, di = 4))}
38 38
    TOPOS.update(TOPOS_RIPCORD)
39 39

  
40 40
SWITCH_DEF = 'kernel'
41
SWITCHES = {'kernel' : KernelSwitch,
42
            'user' : UserSwitch}
41
SWITCHES = {'kernel': KernelSwitch,
42
            'user': UserSwitch}
43 43

  
44 44
HOST_DEF = 'process'
45
HOSTS = {'process' : Host}
45
HOSTS = {'process': Host}
46 46

  
47 47
CONTROLLER_DEF = 'ref'
48 48
# a and b are the name and inNamespace params.
49
CONTROLLERS = {'ref' : Controller,
50
               'nox_dump' : lambda a, b: NOX(a, b, 'packetdump'),
51
               'nox_pysw' : lambda a, b: NOX(a, b, 'pyswitch'),
52
               'remote' : lambda a, b: None,
53
               'none' :     lambda a, b: None}
49
CONTROLLERS = {'ref': Controller,
50
               'nox_dump': lambda a, b: NOX(a, b, 'packetdump'),
51
               'nox_pysw': lambda a, b: NOX(a, b, 'pyswitch'),
52
               'remote': lambda a, b: None,
53
               'none': lambda a, b: None}
54 54

  
55 55
# optional tests to run
56 56
TESTS = ['cli', 'build', 'ping_all', 'ping_pair', 'iperf', 'all', 'iperf_udp']
57 57

  
58

  
58 59
def add_dict_option(opts, choices_dict, default, name, help_str = None):
59 60
    '''Convenience function to add choices dicts to OptionParser.
60
    
61

  
61 62
    @param opts OptionParser instance
62 63
    @param choices_dict dictionary of valid choices, must include default
63 64
    @param default default choice key
......
82 83
    def __init__(self):
83 84
        '''Init.'''
84 85
        self.options = None
85
        
86

  
86 87
        self.parse_args()
87 88
        self.setup()
88 89
        self.begin()
89 90

  
90 91
    def parse_args(self):
91 92
        '''Parse command-line args and return options object.
92
        
93

  
93 94
        @return opts parse options dict
94 95
        '''
95 96
        opts = OptionParser()
......
124 125
        '''Setup and validate environment.'''
125 126

  
126 127
        # set logging verbosity
127
        set_loglevel(self.options.verbosity)
128
        lg.set_loglevel(self.options.verbosity)
128 129

  
129 130
        # validate environment setup
130 131
        init()
mininet/__init__.py
1
'''Docstring to silence pylint; ignores --ignore option for __init__.py'''
mininet/logging_mod.py
1 1
'''Logging functions for Mininet.'''
2 2

  
3 3
import logging
4
from logging import Logger
4 5
import types
5 6

  
6 7
LEVELS = {'debug': logging.DEBUG,
......
16 17
LOG_MSG_FORMAT = '%(message)s'
17 18

  
18 19

  
19

  
20 20
# Modified from python2.5/__init__.py
21 21
class StreamHandlerNoNewline(logging.StreamHandler):
22 22
    '''StreamHandler that doesn't print newlines by default.
......
53 53
            self.handleError(record)
54 54

  
55 55

  
56
def set_loglevel(level_name = None):
57
    '''Setup loglevel.
56
class Singleton(type):
57
    '''Singleton pattern from Wikipedia
58

  
59
    See http://en.wikipedia.org/wiki/Singleton_pattern#Python
60

  
61
    Intended to be used as a __metaclass_ param, as shown for the class below.
62

  
63
    Changed cls first args to mcs to satsify pylint.
64
    '''
65

  
66
    def __init__(mcs, name, bases, dict_):
67
        super(Singleton, mcs).__init__(name, bases, dict_)
68
        mcs.instance = None
69

  
70
    def __call__(mcs, *args, **kw):
71
        if mcs.instance is None:
72
            mcs.instance = super(Singleton, mcs).__call__(*args, **kw)
73
            return mcs.instance
74

  
75

  
76
class MininetLogger(Logger, object):
77
    '''Mininet-specific logger
78

  
79
    Enable each mininet .py file to with one import:
80

  
81
       from mininet.logging_mod import lg
82

  
83
    ...get a default logger that doesn't require one newline per logging call.
58 84

  
59
    @param level_name level name from LEVELS
85
    Inherit from object to ensure that we have at least one new-style base
86
    class, and can then use the __metaclass__ directive, to prevent this error:
87

  
88
      TypeError: Error when calling the metaclass bases
89
       a new-style class can't have only classic bases
90

  
91
    If Python2.5/logging/__init__.py defined Filterer as a new-style class,
92
    via Filterer(object): rather than Filterer, we wouldn't need this.
93

  
94
    Use singleton pattern to ensure only one logger is ever created.
60 95
    '''
61
    level = LOG_LEVEL_DEFAULT
62
    if level_name != None:
63
        if level_name not in LEVELS:
64
            raise Exception('unknown loglevel seen in set_loglevel')
65
        else:
66
            level = LEVELS.get(level_name, level)
67

  
68
    lg.setLevel(level)
69
    if len(lg.handlers) != 1:
70
        raise Exception('lg.handlers length not zero in logging_mod')
71
    lg.handlers[0].setLevel(level)
72

  
73

  
74
def _setup_logging():
75
    '''Setup logging for Mininet.'''
76
    global lg
77

  
78
    # create logger if first time
79
    if 'lg' not in globals():
80
        lg = logging.getLogger('mininet')
96
    __metaclass__ = Singleton
97

  
98
    def __init__(self):
99

  
100
        Logger.__init__(self, "mininet")
101

  
81 102
        # create console handler
82 103
        ch = StreamHandlerNoNewline()
83 104
        # create formatter
......
85 106
        # add formatter to ch
86 107
        ch.setFormatter(formatter)
87 108
        # add ch to lg
88
        lg.addHandler(ch)
89
    else:
90
        raise Exception('setup_logging called twice')
109
        self.addHandler(ch)
110

  
111
        self.set_loglevel()
112

  
113
    def set_loglevel(self, levelname = None):
114
        '''Setup loglevel.
115

  
116
        Convenience function to support lowercase names.
117

  
118
        @param level_name level name from LEVELS
119
        '''
120
        level = LOG_LEVEL_DEFAULT
121
        if levelname != None:
122
            if levelname not in LEVELS:
123
                raise Exception('unknown loglevel seen in set_loglevel')
124
            else:
125
                level = LEVELS.get(levelname, level)
91 126

  
92
    set_loglevel()
127
        self.setLevel(level)
128
        self.handlers[0].setLevel(level)
93 129

  
94 130

  
95
# There has to be some better way to ensure we only ever have one logging
96
# variable.  If this check isn't in, the order in which imports occur can
97
# affect whether a program runs, because the variable lg may get rebound.
98
if 'lg' not in globals():
99
    _setup_logging()
131
lg = MininetLogger()
mininet/net.py
5 5
@author Brandon Heller (brandonh@stanford.edu)
6 6

  
7 7
Mininet creates scalable OpenFlow test networks by using
8
process-based virtualization and network namespaces. 
8
process-based virtualization and network namespaces.
9 9

  
10 10
Simulated hosts are created as processes in separate network
11 11
namespaces. This allows a complete OpenFlow network to be simulated on
......
15 15
   A virtual console (pipes to a shell)
16 16
   A virtual interfaces (half of a veth pair)
17 17
   A parent shell (and possibly some child processes) in a namespace
18
   
18

  
19 19
Hosts have a network interface which is configured via ifconfig/ip
20 20
link/etc.
21 21

  
......
210 210

  
211 211
        For use with the user datapath only right now.
212 212

  
213
        @todo(brandonh) Test this code and verify that user-space works!
213
        @todo(brandonh) Test this code!
214 214
        '''
215 215
        # params were: controller, switches, ips
216 216

  
......
242 242
            while not switch.intfIsUp(switch.intfs[0]):
243 243
                lg.info('*** Waiting for %s to come up\n' % switch.intfs[0])
244 244
                sleep(1)
245
            if self.ping_test(hosts=[switch, controller]) != 0:
245
            if self.ping(hosts = [switch, controller]) != 0:
246 246
                lg.error('*** Error: control network test failed\n')
247 247
                exit(1)
248 248
        lg.info('\n')
249 249

  
250
    def _config_hosts( self ):
250
    def _config_hosts(self):
251 251
        '''Configure a set of hosts.'''
252 252
        # params were: hosts, ips
253 253
        for host_dpid in self.topo.hosts():
......
343 343
    def start(self):
344 344
        '''Start controller and switches\n'''
345 345
        lg.info('*** Starting controller\n')
346
        for cname, cnode in self.controllers.iteritems():
346
        for cnode in self.controllers.values():
347 347
            cnode.start()
348 348
        lg.info('*** Starting %s switches\n' % len(self.topo.switches()))
349 349
        for switch_dpid in self.topo.switches():
......
371 371
            switch.stop()
372 372
        lg.info('\n')
373 373
        lg.info('*** Stopping controller\n')
374
        for cname, cnode in self.controllers.iteritems():
374
        for cnode in self.controllers.values():
375 375
            cnode.stop()
376 376
        lg.info('*** Test complete\n')
377 377

  
......
387 387
    def _parse_ping(pingOutput):
388 388
        '''Parse ping output and return packets sent, received.'''
389 389
        r = r'(\d+) packets transmitted, (\d+) received'
390
        m = re.search( r, pingOutput )
390
        m = re.search(r, pingOutput)
391 391
        if m == None:
392 392
            lg.error('*** Error: could not parse ping output: %s\n' %
393 393
                     pingOutput)
......
422 422
                        lg.error('*** Error: received too many packets')
423 423
                        lg.error('%s' % result)
424 424
                        node.cmdPrint('route')
425
                        exit( 1 )
425
                        exit(1)
426 426
                    lost += sent - received
427 427
                    lg.info(('%s ' % dest.name) if received else 'X ')
428 428
            lg.info('\n')
......
490 490
        server = host0.cmd(iperf_args + '-s &')
491 491
        if verbose:
492 492
            lg.info('%s\n' % server)
493
        client = host1.cmd(iperf_args + '-t 5 -c ' + host0.IP() + ' ' + bw_args)
493
        client = host1.cmd(iperf_args + '-t 5 -c ' + host0.IP() + ' ' +
494
                           bw_args)
494 495
        if verbose:
495 496
            lg.info('%s\n' % client)
496 497
        server = host0.cmd('killall -9 iperf')
......
529 530
        self.nodelist = self.nodemap.values()
530 531
        self.run()
531 532

  
533
    # Disable pylint "Unused argument: 'arg's'" messages.
534
    # Each CLI function needs the same interface.
535
    # pylint: disable-msg=W0613
536

  
532 537
    # Commands
533 538
    def help(self, args):
534 539
        '''Semi-useful help for CLI.'''
......
561 566
            switch = self.mn.nodes[switch_dpid]
562 567
            lg.info('%s <->', switch.name)
563 568
            for intf in switch.intfs:
564
                node, remoteIntf = switch.connection[intf]
569
                node = switch.connection[intf]
565 570
                lg.info(' %s' % node.name)
566 571
            lg.info('\n')
567 572

  
......
588 593

  
589 594
    def intfs(self, args):
590 595
        '''List interfaces.'''
591
        for dpid, node in self.mn.nodes.iteritems():
596
        for node in self.mn.nodes.values():
592 597
            lg.info('%s: %s\n' % (node.name, ' '.join(node.intfs)))
593 598

  
594 599
    def dump(self, args):
595 600
        '''Dump node info.'''
596
        for dpid, node in self.mn.nodes.iteritems():
601
        for node in self.mn.nodes.values():
597 602
            lg.info('%s\n' % node)
598 603

  
604
    # Re-enable pylint "Unused argument: 'arg's'" messages.
605
    # pylint: enable-msg=W0613
606

  
599 607
    def run(self):
600 608
        '''Read and execute commands.'''
601 609
        lg.warn('*** Starting CLI:\n')
602 610
        while True:
603 611
            lg.warn('mininet> ')
604
            input = sys.stdin.readline()
605
            if input == '':
612
            input_line = sys.stdin.readline()
613
            if input_line == '':
606 614
                break
607
            if input[-1] == '\n':
608
                input = input[:-1]
609
            cmd = input.split(' ')
615
            if input_line[-1] == '\n':
616
                input_line = input_line[:-1]
617
            cmd = input_line.split(' ')
610 618
            first = cmd[0]
611 619
            rest = cmd[1:]
612 620
            if first in self.cmds and hasattr(self, first):
......
634 642
            elif first in ['exit', 'quit']:
635 643
                break
636 644
            elif first == '?':
637
                self.help( rest )
645
                self.help(rest)
638 646
            else:
639 647
                lg.error('CLI: unknown node or command: < %s >\n' % first)
640 648
            #lg.info('*** CLI: command complete\n')
641
        return 'exited by user command'
649
        return 'exited by user command'
mininet/node.py
2 2
'''Node objects for Mininet.'''
3 3

  
4 4
from subprocess import Popen, PIPE, STDOUT
5
import os, signal, sys, select
5
import os
6
import signal
7
import sys
8
import select
6 9

  
7 10
flush = sys.stdout.flush
8 11

  
9 12
from mininet.logging_mod import lg
10 13
from mininet.util import quietRun, macColonHex, ipStr
11 14

  
15

  
12 16
class Node(object):
13 17
    '''A virtual network node is simply a shell in a network namespace.
14 18
       We communicate with it using pipes.'''
......
116 120

  
117 121
    def waitOutput(self):
118 122
        '''Wait for a command to complete.
119
        
123

  
120 124
        Completion is signaled by a sentinel character, ASCII(127) appearing in
121 125
        the output stream.  Wait for the sentinel and return the output,
122 126
        including trailing newline.
......
129 133
            if len(data) > 0  and data[-1] == chr(0177):
130 134
                output += data[:-1]
131 135
                break
132
            else: output += data
136
            else:
137
                output += data
133 138
        self.waiting = False
134 139
        return output
135 140

  
......
143 148

  
144 149
    def cmdPrint(self, cmd):
145 150
        '''Call cmd and printing its output
146
        
151

  
147 152
        @param cmd string
148 153
        '''
149 154
        #lg.info('*** %s : %s', self.name, cmd)
......
215 220
    def IP(self):
216 221
        '''Return IP address of first interface'''
217 222
        if len(self.intfs) > 0:
218
            return self.ips.get(self.intfs[ 0 ], None)
223
            return self.ips.get(self.intfs[0], None)
219 224

  
220 225
    def intfIsUp(self):
221 226
        '''Check if one of our interfaces is up.'''
......
258 263
        else:
259 264
            return True, ''
260 265

  
266

  
261 267
class UserSwitch(Switch):
262 268
    '''User-space switch.
263 269

  
......
269 275

  
270 276
        @param name
271 277
        '''
272
        Node.__init__(self, name, inNamespace = False)
278
        Switch.__init__(self, name, inNamespace = False)
273 279

  
274 280
    def start(self, controllers):
275 281
        '''Start OpenFlow reference user datapath.
......
298 304

  
299 305

  
300 306
class KernelSwitch(Switch):
307
    '''Kernel-space switch.
308

  
309
    Much faster than user-space!
310

  
311
    Currently only works in the root namespace.
312
    '''
301 313

  
302 314
    def __init__(self, name, dp = None, dpid = None):
303 315
        '''Init.
......
306 318
        @param dp netlink id (0, 1, 2, ...)
307 319
        @param dpid datapath ID as unsigned int; random value if None
308 320
        '''
309
        Node.__init__(self, name, inNamespace = False)
321
        Switch.__init__(self, name, inNamespace = False)
310 322
        self.dp = dp
311 323
        self.dpid = dpid
312 324

  
......
333 345
                      controllers['c0'].IP() + ':' +
334 346
                      str(controllers['c0'].port) +
335 347
                      ' --fail=closed 1> ' + ofplog + ' 2>' + ofplog + ' &')
336
        self.execed = False # XXX until I fix it
348
        self.execed = False
337 349

  
338 350
    def stop(self):
339 351
        '''Terminate reference kernel datapath.'''
......
372 384
            self.cmdPrint('cd ' + self.cdir)
373 385
        self.cmdPrint(self.controller + ' ' + self.cargs +
374 386
            ' 1> ' + cout + ' 2> ' + cout + ' &')
375
        self.execed = False # XXX Until I fix it
387
        self.execed = False
376 388

  
377 389
    def stop(self):
378 390
        '''Stop controller.'''
......
386 398

  
387 399
class ControllerParams(object):
388 400
    '''Container for controller IP parameters.'''
401

  
389 402
    def __init__(self, ip, subnet_size):
390 403
        '''Init.
391 404

  
......
398 411

  
399 412
class NOX(Controller):
400 413
    '''Controller to run a NOX application.'''
414

  
401 415
    def __init__(self, name, inNamespace = False, nox_args = None, **kwargs):
402 416
        '''Init.
403 417

  
......
420 434

  
421 435
class RemoteController(Controller):
422 436
    '''Controller running outside of Mininet's control.'''
437

  
423 438
    def __init__(self, name, inNamespace = False, ip_address = '127.0.0.1',
424 439
                 port = 6633):
425 440
        '''Init.
mininet/test/test_nets.py
4 4
Test creation and all-pairs ping for each included mininet topo type.
5 5
'''
6 6

  
7
from time import sleep
8 7
import unittest
9 8

  
10 9
from mininet.net import init, Mininet
......
12 11
from mininet.topo import SingleSwitchTopo, LinearTopo
13 12

  
14 13
# temporary, until user-space side is tested
15
SWITCHES = {'kernel' : KernelSwitch}
14
SWITCHES = {'kernel': KernelSwitch}
16 15

  
17 16

  
18 17
class testSingleSwitch(unittest.TestCase):
......
54 53

  
55 54

  
56 55
if __name__ == '__main__':
57
    unittest.main()
56
    unittest.main()
mininet/topo.py
11 11
setup for testing, and can even be emulated with the Mininet package.
12 12
'''
13 13

  
14
from networkx import Graph
14
from networkx.classes.graph import Graph
15 15

  
16 16

  
17 17
class NodeID(object):
......
87 87

  
88 88
class Topo(object):
89 89
    '''Data center network representation for structured multi-trees.'''
90

  
90 91
    def __init__(self):
91 92
        '''Create Topo object.
92 93

  
......
182 183

  
183 184
        @return dpids list of dpids
184 185
        '''
186

  
185 187
        def is_switch(n):
186 188
            '''Returns true if node is a switch.'''
187 189
            return self.node_info[n].is_switch
......
196 198

  
197 199
        @return dpids list of dpids
198 200
        '''
201

  
199 202
        def is_host(n):
200 203
            '''Returns true if node is a host.'''
201 204
            return not self.node_info[n].is_switch
......
391 394
                self._add_edge(s, s + 1, Edge())
392 395

  
393 396
        if enable_all:
394
            self.enable_all()
397
            self.enable_all()
mininet/util.py
99 99
# live in the root namespace and thus do not have to be
100 100
# explicitly moved.
101 101

  
102

  
102 103
def makeIntfPair(intf1, intf2):
103 104
    '''Make a veth pair.
104 105

  
......
111 112
    quietRun('ip link del ' + intf2)
112 113
    # Create new pair
113 114
    cmd = 'ip link add name ' + intf1 + ' type veth peer name ' + intf2
114
    return checkRun( cmd )
115
    return checkRun(cmd)
115 116

  
116 117

  
117 118
def moveIntf(intf, node, print_error = False):
......
132 133
    return True
133 134

  
134 135

  
135
def retry(n, retry_delay, fn, *args):
136
def retry(n, retry_delay, fn, *args, **keywords):
136 137
    '''Try something N times before giving up.
137 138

  
138 139
    @param n number of times to retry
......
141 142
    @param args args to apply to function call
142 143
    '''
143 144
    tries = 0
144
    while not apply(fn, args) and tries < n:
145
    while not fn(*args, **keywords) and tries < n:
145 146
        sleep(retry_delay)
146 147
        tries += 1
147 148
    if tries >= n:
148 149
        lg.error("*** gave up after %i retries\n" % tries)
149
        exit( 1 )
150
        exit(1)
150 151

  
151 152

  
152 153
# delay between interface move checks in seconds
......
154 155

  
155 156
CREATE_LINK_RETRIES = 10
156 157

  
158

  
157 159
def createLink(node1, node2):
158 160
    '''Create a link between nodes, making an interface for each.
159 161

  
......
174 176

  
175 177
def fixLimits():
176 178
    '''Fix ridiculously small resource limits.'''
177
    setrlimit( RLIMIT_NPROC, (4096, 8192))
178
    setrlimit( RLIMIT_NOFILE, (16384, 32768))
179
    setrlimit(RLIMIT_NPROC, (4096, 8192))
180
    setrlimit(RLIMIT_NOFILE, (16384, 32768))
179 181

  
180 182

  
181 183
def _colonHex(val, bytes):
......
186 188
    @return ch_str colon-hex string
187 189
    '''
188 190
    pieces = []
189
    for i in range (bytes - 1, -1, -1):
191
    for i in range(bytes - 1, -1, -1):
190 192
        pieces.append('%02x' % (((0xff << (i * 8)) & val) >> (i * 8)))
191 193
    ch_str = ':'.join(pieces)
192 194
    return ch_str
......
209 211
    hi = (ip & 0xff0000) >> 16
210 212
    mid = (ip & 0xff00) >> 8
211 213
    lo = ip & 0xff
212
    return "10.%i.%i.%i" % (hi, mid, lo)
214
    return "10.%i.%i.%i" % (hi, mid, lo)
mininet/xterm.py
6 6
Requires xterm(1) and GNU screen(1).
7 7
"""
8 8

  
9
import os
10 9
import re
11 10
from subprocess import Popen
12 11

  
13 12
from mininet.util import quietRun
14 13

  
14

  
15 15
def makeXterm(node, title):
16 16
    '''Run screen on a node, and hook up an xterm.
17 17

  
......
48 48
    @param title base title for each
49 49
    @return list of created xterm processes
50 50
    '''
51
    return [makeXterm(node, title) for node in nodes]
51
    return [makeXterm(node, title) for node in nodes]

Also available in: Unified diff