Revision d44a5843 mininet/node.py

View differences:

mininet/node.py
49 49
from time import sleep
50 50

  
51 51
from mininet.log import info, error, debug
52
from mininet.util import quietRun, moveIntf
53

  
52
from mininet.util import quietRun, makeIntfPair, moveIntf
54 53

  
55 54
class Node( object ):
56 55
    """A virtual network node is simply a shell in a network namespace.
......
84 83
        self.outToNode[ self.stdout.fileno() ] = self
85 84
        self.inToNode[ self.stdin.fileno() ] = self
86 85
        self.pid = self.shell.pid
87
        self.intfCount = 0
88 86
        self.intfs = {} # dict of port numbers to interface names
89 87
        self.ports = {} # dict of interface names to port numbers
90 88
                        # replace with Port objects, eventually ?
......
206 204
        "Construct a canonical interface name node-ethN for interface n."
207 205
        return self.name + '-eth' + repr( n )
208 206

  
209
    def newIntf( self ):
210
        "Reserve and return a new interface name."
211
        intfName = self.intfName( self.intfCount )
212
        self.intfCount += 1
213
        return intfName
207
    def newPort( self ):
208
        "Return the next port number to allocate."
209
        if len( self.ports ) > 0:
210
            return max( self.ports.values() ) + 1
211
        return 0
214 212

  
215 213
    def addIntf( self, intf, port ):
216 214
        """Add an interface.
......
219 217
        self.intfs[ port ] = intf
220 218
        self.ports[ intf ] = port
221 219
        #info( '\n' )
222
        #info( 'added intf %s to node %x\n' % ( srcIntf, src ) )
220
        #info( 'added intf %s:%d to node %s\n' % ( intf,port, self.name ) )
223 221
        if self.inNamespace:
224 222
            #info( 'moving w/inNamespace set\n' )
225 223
            moveIntf( intf, self )
226 224

  
227
    def connect( self, intf, dstNode, dstIntf ):
225
    def registerIntf( self, intf, dstNode, dstIntf ):
228 226
        "Register connection of intf to dstIntf on dstNode."
229 227
        self.connection[ intf ] = ( dstNode, dstIntf )
230 228

  
229
    # This is a symmetric operation, but it makes sense to put
230
    # the code here since it is tightly coupled to routines in
231
    # this class. For a more symmetric API, you can use
232
    # mininet.util.createLink()
233

  
234
    def linkTo( self, node2, port1=None, port2=None ):
235
        """Create link to another node, making two new interfaces.
236
           node2: Node to link us to
237
           port1: our port number (optional)
238
           port2: node2 port number (optional)
239
           returns: intf1 name, intf2 name"""
240
        node1 = self
241
        if port1 is None:
242
            port1 = node1.newPort()
243
        if port2 is None:
244
            port2 = node2.newPort()
245
        intf1 = node1.intfName( port1 )
246
        intf2 = node2.intfName( port2 )
247
        makeIntfPair( intf1, intf2 )
248
        node1.addIntf( intf1, port1 )
249
        node2.addIntf( intf2, port2 )
250
        node1.registerIntf( intf1, node2, intf2 )
251
        node2.registerIntf( intf2, node1, intf1 )
252
        return intf1, intf2
253

  
231 254
    def deleteIntfs( self ):
232 255
        "Delete all of our interfaces."
233 256
        # In theory the interfaces should go away after we shut down.
234 257
        # However, this takes time, so we're better off removing them
235 258
        # explicitly so that we won't get errors if we run before they
236
        # have been removed by the kernel. Unfortunately this is very slow.
259
        # have been removed by the kernel. Unfortunately this is very slow,
260
        # at least with Linux kernels before 2.6.33
237 261
        for intf in self.intfs.values():
238 262
            quietRun( 'ip link del ' + intf )
239 263
            info( '.' )
......
255 279
        result = self.cmd( [ 'arp', '-s', ip, mac ] )
256 280
        return result
257 281

  
258
    def setIP( self, intf, ip, prefixLen ):
282
    def setIP( self, intf, ip, prefixLen=8 ):
259 283
        """Set the IP address for an interface.
260 284
           intf: interface name
261 285
           ip: IP address as a string
......
277 301
        self.cmd( 'ip route flush' )
278 302
        return self.cmd( 'route add default ' + intf )
279 303

  
280
    def IP( self ):
281
        "Return IP address of interface 0"
282
        return self.ips.get( self.intfs.get( 0 , None ), None )
283

  
284
    def MAC( self ):
285
        "Return MAC address of interface 0"
286
        ifconfig = self.cmd( 'ifconfig ' + self.intfs[ 0 ] )
304
    def IP( self, intf=None ):
305
        "Return IP address of a node or specific interface."
306
        if len( self.ips ) == 1:
307
            return self.ips.values()[ 0 ]
308
        if intf:
309
            return self.ips.get( intf, None )
310

  
311
    def MAC( self, intf=None ):
312
        "Return MAC address of a node or specific interface."
313
        if intf is None and len( self.intfs ) == 1:
314
            intf = self.intfs.values()[ 0 ]
315
        ifconfig = self.cmd( 'ifconfig ' + intf )
287 316
        macs = re.findall( '..:..:..:..:..:..', ifconfig )
288 317
        if len( macs ) > 0:
289 318
            return macs[ 0 ]
290
        else:
291
            return None
292 319

  
293
    def intfIsUp( self, port ):
294
        """Check if interface for a given port number is up.
295
           port: port number"""
296
        return 'UP' in self.cmd( 'ifconfig ' + self.intfs[ port ] )
320
    def intfIsUp( self, intf ):
321
        "Check if an interface is up."
322
        return 'UP' in self.cmd( 'ifconfig ' + intf )
297 323

  
298 324
    # Other methods
299 325
    def __str__( self ):
......
331 357

  
332 358

  
333 359
class UserSwitch( Switch ):
334
    """User-space switch.
335
       Currently only works in the root namespace."""
360
    "User-space switch."
336 361

  
337 362
    def __init__( self, name, *args, **kwargs ):
338 363
        """Init.
339 364
           name: name for the switch"""
340
        Switch.__init__( self, name, inNamespace=False, **kwargs )
365
        Switch.__init__( self, name, **kwargs )
341 366

  
342 367
    def start( self, controllers ):
343 368
        """Start OpenFlow reference user datapath.
......
348 373
        ofplog = '/tmp/' + self.name + '-ofp.log'
349 374
        self.cmd( 'ifconfig lo up' )
350 375
        intfs = sorted( self.intfs.values() )
351

  
376
        if self.inNamespace:
377
            intfs = intfs[ :-1 ]
352 378
        self.cmd( 'ofdatapath -i ' + ','.join( intfs ) +
353 379
            ' punix:/tmp/' + self.name +
354 380
            ' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' )
......
364 390

  
365 391
class KernelSwitch( Switch ):
366 392
    """Kernel-space switch.
367
       Currently only works in the root namespace."""
393
       Currently only works in root namespace."""
368 394

  
369 395
    def __init__( self, name, dp=None, **kwargs ):
370 396
        """Init.
371 397
           name:
372 398
           dp: netlink id (0, 1, 2, ...)
373 399
           defaultMAC: default MAC as string; random value if None"""
374
        Switch.__init__( self, name, inNamespace=False, **kwargs )
400
        Switch.__init__( self, name, **kwargs )
375 401
        self.dp = dp
402
        if self.inNamespace:
403
            error( "KernelSwitch currently only works"
404
                " in the root namespace." )
405
            exit( 1 )
376 406

  
377 407
    def start( self, controllers ):
378 408
        "Start up reference kernel datapath."
......
385 415
        if self.defaultMAC:
386 416
            intf = 'of%i' % self.dp
387 417
            self.cmd( [ 'ifconfig', intf, 'hw', 'ether', self.defaultMAC ] )
388

  
389 418
        if len( self.intfs ) != max( self.intfs ) + 1:
390 419
            raise Exception( 'only contiguous, zero-indexed port ranges'
391 420
                            'supported: %s' % self.intfs )
......
412 441

  
413 442
    def __init__( self, name, dp=None, **kwargs ):
414 443
        """Init.
415
           name:
444
           name: name of switch
416 445
           dp: netlink id (0, 1, 2, ...)
417
           dpid: datapath ID as unsigned int; random value if None"""
418
        Switch.__init__( self, name, inNamespace=False, **kwargs )
446
           defaultMAC: default MAC as unsigned int; random value if None"""
447
        Switch.__init__( self, name, **kwargs )
419 448
        self.dp = dp
449
        if self.inNamespace:
450
            error( "OVSKernelSwitch currently only works"
451
                " in the root namespace." )
452
            exit( 1 )
420 453

  
421 454
    def start( self, controllers ):
422 455
        "Start up kernel datapath."
......
480 513
        self.cmd( 'kill %' + self.controller )
481 514
        self.terminate()
482 515

  
483
    def IP( self ):
516
    def IP( self, intf=None ):
484 517
        "Return IP address of the Controller"
485
        return self.defaultIP
486

  
518
        ip = Node.IP( self, intf=intf )
519
        if ip is None:
520
            ip = self.defaultIP
521
        return ip
487 522

  
488 523
class ControllerParams( object ):
489 524
    "Container for controller IP parameters."

Also available in: Unified diff