diff --git a/mininet/net.py b/mininet/net.py index 1c932f9..8edaee3 100755 --- a/mininet/net.py +++ b/mininet/net.py @@ -91,7 +91,7 @@ import re import select import signal from time import sleep -from itertools import chain +from itertools import chain, groupby from mininet.cli import CLI from mininet.log import info, error, debug, output @@ -408,10 +408,9 @@ class Mininet( object ): info( '*** Stopping %i terms\n' % len( self.terms ) ) self.stopXterms() info( '*** Stopping %i switches\n' % len( self.switches ) ) - if self.switches: - swclass = type( self.switches[ 0 ] ) + for swclass, switches in groupby( sorted( self.switches, key=type ), type ): if hasattr( swclass, 'batchShutdown' ): - swclass.batchShutdown( self.switches ) + swclass.batchShutdown( switches ) for switch in self.switches: info( switch.name + ' ' ) switch.stop() diff --git a/mininet/node.py b/mininet/node.py index 72c782a..568d986 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -856,6 +856,8 @@ class UserSwitch( Switch ): '(openflow.org)' ) if self.listenPort: self.opts += ' --listen=ptcp:%i ' % self.listenPort + else: + self.opts += ' --listen=punix:/tmp/%s.listen' % self.name self.dpopts = dpopts @classmethod @@ -868,7 +870,7 @@ class UserSwitch( Switch ): "Run dpctl command" listenAddr = None if not self.listenPort: - listenAddr = 'unix:/tmp/' + self.name + listenAddr = 'unix:/tmp/%s.listen' % self.name else: listenAddr = 'tcp:127.0.0.1:%i' % self.listenPort return self.cmd( 'dpctl ' + ' '.join( args ) + @@ -1034,7 +1036,7 @@ class OVSSwitch( Switch ): "Call ovs-vsctl del-br on all OVSSwitches in a list" quietRun( 'ovs-vsctl ' + ' -- '.join( '--if-exists del-br %s' % s - for s in switches if type(s) == cls ) ) + for s in switches ) ) def dpctl( self, *args ): "Run ovs-ofctl command" @@ -1108,16 +1110,16 @@ class OVSSwitch( Switch ): self.cmd( 'ovs-vsctl add-br', self ) for intf in self.intfList(): if not intf.IP(): - self.cmd('ovs-vsctl add-port', self, intf ) - cmd = ('ovs-vsctl set Bridge %s ' % self + - 'other_config:datapath-id=%s ' % self.dpid + - '-- set-fail-mode %s %s ' % ( self, self.failMode ) + - '-- set-controller %s %s ' % ( self, clist ) ) + self.cmd( 'ovs-vsctl add-port', self, intf ) + cmd = ( 'ovs-vsctl set Bridge %s ' % self + + 'other_config:datapath-id=%s ' % self.dpid + + '-- set-fail-mode %s %s ' % ( self, self.failMode ) + + '-- set-controller %s %s ' % ( self, clist ) ) if not self.inband: cmd += ( '-- set bridge %s ' 'other-config:disable-in-band=true ' % self ) if self.datapath == 'user': - cmd += '-- set bridge %s datapath_type=netdev ' % self + cmd += '-- set bridge %s datapath_type=netdev ' % self # Reconnect quickly to controllers (1s vs. 15s max_backoff) for uuid in self.controllerUUIDs(): if uuid.count( '-' ) != 4: @@ -1144,8 +1146,9 @@ OVSKernelSwitch = OVSSwitch class IVSSwitch(Switch): """IVS virtual switch""" - def __init__( self, name, **kwargs ): + def __init__( self, name, verbose=True, **kwargs ): Switch.__init__( self, name, **kwargs ) + self.verbose = verbose @classmethod def setup( cls ): @@ -1160,12 +1163,19 @@ class IVSSwitch(Switch): 'not be loaded. Try modprobe openvswitch.\n' ) exit( 1 ) + @classmethod + def batchShutdown( cls, switches ): + "Kill each IVS switch, to be waited on later in stop()" + for switch in switches: + switch.cmd( 'kill %ivs' ) + def start( self, controllers ): "Start up a new IVS switch" args = ['ivs'] args.extend( ['--name', self.name] ) args.extend( ['--dpid', self.dpid] ) - args.extend( ['--verbose'] ) + if self.verbose: + args.extend( ['--verbose'] ) for intf in self.intfs.values(): if not intf.IP(): args.extend( ['-i', intf.name] ) diff --git a/mininet/util.py b/mininet/util.py index b03e945..5cb27f4 100644 --- a/mininet/util.py +++ b/mininet/util.py @@ -273,7 +273,7 @@ def ipAdd( i, prefixLen=8, ipBaseNum=0x0a000000 ): ipBaseNum: option base IP address as int returns IP address as string""" imax = 0xffffffff >> prefixLen - assert i <= imax + assert i <= imax, 'Not enough IP addresses in the subnet' mask = 0xffffffff ^ imax ipnum = ( ipBaseNum & mask ) + i return ipStr( ipnum ) @@ -281,6 +281,8 @@ 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 ): + args.append( 0 ) return ipNum( *args ) def netParse( ipstr ): @@ -290,6 +292,10 @@ def netParse( ipstr ): if '/' in ipstr: ip, pf = ipstr.split( '/' ) prefixLen = int( pf ) + #if no prefix is specified, set the prefix to 24 + else: + ip = ipstr + prefixLen = 24 return ipParse( ip ), prefixLen def checkInt( s ): diff --git a/util/vm/build.py b/util/vm/build.py index 3e0daa7..be809ec 100755 --- a/util/vm/build.py +++ b/util/vm/build.py @@ -158,7 +158,7 @@ def depend(): run( 'sudo apt-get -y update' ) run( 'sudo apt-get install -y' ' kvm cloud-utils genisoimage qemu-kvm qemu-utils' - ' e2fsprogs dnsmasq' + ' e2fsprogs dnsmasq curl' ' python-setuptools mtools zip' ) run( 'sudo easy_install pexpect' ) @@ -457,16 +457,16 @@ def boot( cow, kernel, initrd, logfile, memory=1024 ): return vm -def login( vm ): +def login( vm, user='mininet', password='mininet' ): "Log in to vm (pexpect object)" log( '* Waiting for login prompt' ) vm.expect( 'login: ' ) log( '* Logging in' ) - vm.sendline( 'mininet' ) + vm.sendline( user ) log( '* Waiting for password prompt' ) vm.expect( 'Password: ' ) log( '* Sending password' ) - vm.sendline( 'mininet' ) + vm.sendline( password ) log( '* Waiting for login...' ) @@ -628,9 +628,9 @@ OVFTemplate = """ The nat network - -A Mininet Virtual Machine (%(name)s) -mininet-vm + +%(vminfo)s (%(name)s) +%(vmname)s The kind of installed guest operating system %(osname)s @@ -640,10 +640,10 @@ OVFTemplate = """ hertz * 10^6 Number of Virtual CPUs -1 virtual CPU(s) +%(cpus)s virtual CPU(s) 1 3 -1 +%(cpus)s byte * 2^20 @@ -694,19 +694,23 @@ OVFTemplate = """ """ -def generateOVF( name, osname, osid, diskname, disksize, mem=1024 ): +def generateOVF( name, osname, osid, diskname, disksize, mem=1024, cpus=1, + vmname='Mininet-VM', vminfo='A Mininet Virtual Machine' ): """Generate (and return) OVF file "name.ovf" name: root name of OVF file to generate osname: OS name for OVF (Ubuntu | Ubuntu 64-bit) osid: OS ID for OVF (93 | 94 ) diskname: name of disk file disksize: size of virtual disk in bytes - mem: VM memory size in MB""" + mem: VM memory size in MB + cpus: # of virtual CPUs + vmname: Name for VM (default name when importing) + vmimfo: Brief description of VM for OVF""" ovf = name + '.ovf' filesize = stat( diskname )[ ST_SIZE ] params = dict( osname=osname, osid=osid, diskname=diskname, filesize=filesize, disksize=disksize, name=name, - mem=mem ) + mem=mem, cpus=cpus, vmname=vmname, vminfo=vminfo ) xmltext = OVFTemplate % params with open( ovf, 'w+' ) as f: f.write( xmltext ) @@ -781,6 +785,9 @@ def build( flavor='raring32server', tests=None, pre='', post='', memory=1024 ): def runTests( vm, tests=None, pre='', post='', prompt=Prompt ): "Run tests (list) in vm (pexpect object)" + if Branch: + checkOutBranch( vm, branch=Branch ) + vm.expect( prompt ) if not tests: tests = [] if pre: @@ -811,8 +818,8 @@ def getMininetVersion( vm ): return version -def bootAndRunTests( image, tests=None, pre='', post='', prompt=Prompt, - memory=1024, outputFile=None ): +def bootAndRun( image, prompt=Prompt, memory=1024, outputFile=None, + runFunction=None, **runArgs ): """Boot and test VM tests: list of tests to run pre: command line to run in VM before tests @@ -840,11 +847,9 @@ def bootAndRunTests( image, tests=None, pre='', post='', prompt=Prompt, login( vm ) log( '* Waiting for prompt after login' ) vm.expect( prompt ) - if Branch: - checkOutBranch( vm, branch=Branch ) - vm.expect( prompt ) - runTests( vm, tests=tests, pre=pre, post=post ) - # runTests eats its last prompt, but maybe it shouldn't... + # runFunction should begin with sendline and should eat its last prompt + if runFunction: + runFunction( vm, **runArgs ) log( '* Shutting down' ) vm.sendline( 'sudo shutdown -h now ' ) log( '* Waiting for shutdown' ) @@ -950,9 +955,8 @@ def parseArgs(): log( '* BUILD FAILED with exception: ', e ) exit( 1 ) for image in args.image: - bootAndRunTests( image, tests=args.test, pre=args.run, - post=args.post, memory=args.memory, - outputFile=args.out ) + bootAndRun( image, runFunction=runTests, tests=args.test, pre=args.run, + post=args.post, memory=args.memory, outputFile=args.out ) if not ( args.depend or args.list or args.clean or args.flavor or args.image ): parser.print_help()