Revision 216a4b7c mininet/node.py

View differences:

mininet/node.py
127 127
        if self.shell:
128 128
            error( "%s: shell is already running" )
129 129
            return
130
        # mnexec: (c)lose descriptors, (d)etach from tty,
131
        # (p)rint pid, and run in (n)amespace 
130 132
        opts = '-cdp'
131 133
        if self.inNamespace:
132 134
            opts += 'n'
135
        # bash -m: enable job control
133 136
        cmd = [ 'mnexec', opts, 'bash', '-m' ]
134 137
        self.shell = Popen( cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
135 138
            close_fds=True )
......
405 408
    # annoying, but at least the information is there!
406 409

  
407 410
    def setParam( self, results, method, **param ):
408
        """Internal method: configure single parameter"""
411
        """Internal method: configure a *single* parameter
412
           results: dict of results to update
413
           method: config method name
414
           param: arg=value (ignore if value=None)
415
           value may also be list or dict"""
409 416
        name, value = param.items()[ 0 ]
410 417
        f = getattr( self, method, None )
411
        if not value or not f:
418
        if not f or value is None:
412 419
            return
413 420
        if type( value ) is list:
414 421
            result = f( *value )
......
417 424
        else:
418 425
            result = f( value )
419 426
        results[ name ] = result
427
        return result
420 428

  
421 429
    def config( self, mac=None, ip=None, ifconfig=None, 
422 430
                defaultRoute=None, **params):
......
462 470
            self.name, self.IP(), ','.join( self.intfNames() ), self.pid )
463 471

  
464 472

  
465
class CPULimitedHost( Node ):
473
class Host( Node ):
474
    "A host is simply a Node"
475
    pass
476

  
477

  
478
class CPULimitedHost( Host ):
466 479

  
467 480
    "CPU limited host"
468 481

  
......
472 485
        cgroup = 'cpu,cpuacct:/' + self.name
473 486
        errFail( 'cgcreate -g ' + cgroup )
474 487
        errFail( 'cgclassify -g %s %s' % ( cgroup, self.pid ) )
475
        self.sched = 'rt'
476
        self.period_us = 10000
477
        self.rtset = False
488
        self.period_us = kwargs.get( 'period_us', 10000 )
489
        self.sched = kwargs.get( 'sched', 'rt' )
478 490

  
479 491
    def cgroupSet( self, param, value, resource='cpu' ):
480 492
        "Set a cgroup parameter and return its value"
......
495 507
        lastword = firstline.split( ' ' )[ -1 ]
496 508
        return lastword
497 509

  
498
    def setCPUFrac( self, f=-1 ):
499
        "Set overall CPU fraction for this host"
500
        if ( f < 0 or f is None):
510
    # BL comment:
511
    # This may not be the right API, 
512
    # since it doesn't specify CPU bandwidth in "absolute"
513
    # units the way link bandwidth is specified.
514
    # We should use MIPS or SPECINT or something instead.
515
    # Alternatively, we should change from system fraction
516
    # to CPU seconds per second, essentially assuming that
517
    # all CPUs are the same.
518
    
519
    def setCPUFrac( self, f=-1, sched=None):
520
        """Set overall CPU fraction for this host
521
           f: CPU bandwidth limit (fraction)
522
           sched: 'rt' or 'cfs'
523
           Note 'cfs' requires CONFIG_CFS_BANDWIDTH"""
524
        if not f:
525
            return
526
        if not sched:
527
            sched = self.sched
528
        period = self.period_us
529
        if sched == 'rt':
530
            pstr, qstr = 'rt_period_us', 'rt_runtime_us'
531
            # RT uses system time for period and quota
532
            quota = int( period * f * numCores() )
533
        elif sched == 'cfs':
534
            pstr, qstr = 'cfs_period_us', 'cfs_quota_us'
535
            # CFS uses wall clock time for period and CPU time for quota.
536
            quota = int( self.period_us * f * numCores() )
537
            if f > 0 and quota < 1000:
538
                info( '*** setCPUFrac: quota too small - adjusting period\n' )
539
                quota = 1000
540
                period = int( quota / f / numCores() )
541
        else:
542
            return
543
        if quota < 0:
501 544
            # Reset to unlimited
502
            f = -1
503
        # Set new period and quota
504
        pstr, qstr = 'rt_period_us', 'rt_runtime_us'
505
        quota = int( self.period_us * f * numCores() )
506
        self.cgroupSet( pstr, self.period_us )
545
            quota = -1
546
        # Set cgroup's period and quota
547
        self.cgroupSet( pstr, period )
507 548
        nquota = int ( self.cgroupGet( qstr ) )
508 549
        self.cgroupSet( qstr, quota )
509 550
        nperiod = int( self.cgroupGet( pstr ) )
510
        # Set RT priority
511
        nchrt = self.chrt( prio=20 )
512
        # Check to make sure it worked
513
        if 'SCHED_RR' not in nchrt:
514
            error( '*** error: could not assign SCHED_RR to %s\n' % self.name )
551
        # Make sure it worked
515 552
        if nperiod != self.period_us:
516 553
            error( '*** error: period is %s rather than %s\n' % (
517 554
                    nperiod, self.period_us ) )
518 555
        if nquota != quota:
519 556
            error( '*** error: quota is %s rather than %s\n' % (
520 557
                    nquota, quota ) )
558
        if sched == 'rt':
559
            # Set RT priority if necessary
560
            nchrt = self.chrt( prio=20 )
561
            # Nake sure it worked
562
            if sched == 'SCHED_RR' not in nchrt:
563
                error( '*** error: could not assign SCHED_RR to %s\n' % self.name )
564
            info( '( period', nperiod, 'quota', nquota, nchrt, ') ' )
565
        else:
566
            info( '( period', nperiod, 'quota', nquota, ') ' )
521 567

  
522
    def config( self, cpu=None, **params ):
568
    def config( self, cpu=None, sched=None, **params ):
523 569
        """cpu: desired overall system CPU fraction
524 570
           params: parameters for Node.config()"""
525 571
        r = Node.config( self, **params )
572
        # Was considering cpu={'cpu': cpu , 'sched': sched}, but
573
        # that seems redundant
526 574
        self.setParam( r, 'setCPUFrac', cpu=cpu )
527 575
        return r
528 576

  
529
Host = CPULimitedHost
530

  
531

  
532 577
# Some important things to note:
533 578
#
534 579
# The "IP" address which we assign to the switch is not
......
805 850
class NOX( Controller ):
806 851
    "Controller to run a NOX application."
807 852

  
808
    def __init__( self, name, noxArgs=None, **kwargs ):
853
    def __init__( self, name, noxArgs=[], **kwargs ):
809 854
        """Init.
810 855
           name: name to give controller
811 856
           noxArgs: list of args, or single arg, to pass to NOX"""

Also available in: Unified diff