diff --git a/mininet/node.py b/mininet/node.py index c93fc1b8..03fbc66e 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -882,7 +882,7 @@ def defaultDpid( self, dpid=None ): def defaultIntf( self ): "Return control interface" - if self.controlIntf: + if hasattr(self, "controlIntf") and self.controlIntf: return self.controlIntf else: return Node.defaultIntf( self ) @@ -1043,6 +1043,7 @@ def __init__( self, name, failMode='secure', datapath='kernel', self._uuids = [] # controller UUIDs self.batch = batch self.commands = [] # saved commands for batch startup + self.children = [] @classmethod def setup( cls ): @@ -1081,6 +1082,9 @@ def vsctl( self, *args, **kwargs ): if self.batch: cmd = ' '.join( str( arg ).strip() for arg in args ) self.commands.append( cmd ) + elif self.inNamespace: + args = ('--db=unix:/tmp/%s/db.sock' % self.name, "--retry", "--timeout=2")+args + return self.cmd( 'ovs-vsctl', *args, **kwargs ) else: return self.cmd( 'ovs-vsctl', *args, **kwargs ) @@ -1106,7 +1110,7 @@ def controllerUUIDs( self, update=False ): """Return ovsdb UUIDs for our controllers update: update cached value""" if not self._uuids or update: - controllers = self.cmd( 'ovs-vsctl -- get Bridge', self, + controllers = self.vsctl( '--', 'get Bridge', self, 'Controller' ).strip() if controllers.startswith( '[' ) and controllers.endswith( ']' ): controllers = controllers[ 1 : -1 ] @@ -1153,21 +1157,63 @@ def bridgeOpts( self ): def start( self, controllers ): "Start up a new OVS OpenFlow switch using ovs-vsctl" if self.inNamespace: - raise Exception( - 'OVS kernel switch does not work in a namespace' ) + self.workdir = workdir = "/tmp/%s" % self.name + self.cmd("export OVS_RUNDIR=%s" % workdir) + self.cmd("mkdir %s || true" % workdir) + self.cmd("rm %s/* || true" % workdir) + self.cmd("ovsdb-tool create %s/conf.db" % workdir) + self.cmd("ovsdb-server", + "%s/conf.db" % workdir, + "--remote=punix:%s/db.sock" % workdir, + "-vconsole:emer", + "-vfile:info", + "--log-file=%s/ovsdb-server.log" % workdir, + "&") + self.cmd("ovs-vswitchd", + 'unix:%s/db.sock' % workdir, + "-vconsole:emer", + "-vfile:info", + '--log-file=%s/ovs-vswitchd.log' % workdir, + '&') + for c in controllers: + socat = None + if c.protocol == "tcp": + socat = "socat unix-listen:%s/%s.%d.ofp,reuseaddr,fork tcp-connect:%s:%s" % ( + self.workdir, c.IP(), c.port, c.IP(), c.port ) + elif c.protocol == "ssl": + socat = "socat unix-listen:%s/%s.%d.ofp,reuseaddr,fork openssl:%s:%s" % ( + self.workdir, c.IP(), c.port, c.IP(), c.port ) + elif c.protocol == "ptcp": + socat = "socat tcp-listen:%s,reuseaddr,fork unix-connect:%s/%s.mgmt" % ( + c.port, self.workdir, self.name ) + elif c.protocol == "pssl": + socat = "socat ssl-listen:%s,reuseaddr,fork unix-connect:%s/%s.mgmt" % ( + c.port, self.workdir, self.name ) + if socat: + self.children.append(Popen(socat.split())) + if self.listenPort: + socat = "socat tcp-listen:%s,reuseaddr,fork unix-connect:%s/%s.mgmt" % ( + self.listenPort, self.workdir, self.name ) + self.children.append(Popen(socat.split())) int( self.dpid, 16 ) # DPID must be a hex string # Command to add interfaces intfs = ''.join( ' -- add-port %s %s' % ( self, intf ) + self.intfOpts( intf ) for intf in self.intfList() if self.ports[ intf ] and not intf.IP() ) - # Command to create controller entries - clist = [ ( self.name + c.name, '%s:%s:%d' % - ( c.protocol, c.IP(), c.port ) ) - for c in controllers ] - if self.listenPort: - clist.append( ( self.name + '-listen', - 'ptcp:%s' % self.listenPort ) ) + if self.inNamespace: + # inNamespace, tcp, ssl controllers will be proxied through punix + clist = [ ( self.name + c.name, 'unix:%s/%s.%d.ofp' % + ( self.workdir, c.IP(), c.port ) ) + for c in controllers if c.protocol in ("ssl", "tcp") ] + else: + # Command to create controller entries + clist = [ ( self.name + c.name, '%s:%s:%d' % + ( c.protocol, c.IP(), c.port ) ) + for c in controllers ] + if self.listenPort: + clist.append( ( self.name + '-listen', + 'ptcp:%s' % self.listenPort ) ) ccmd = '-- --id=@%s create Controller target=\\"%s\\"' if self.reconnectms: ccmd += ' max_backoff=%d' % self.reconnectms @@ -1199,22 +1245,34 @@ def batchStartup( cls, switches, run=errRun ): switches: switches to start up run: function to run commands (errRun)""" info( '...' ) - cmds = 'ovs-vsctl' + cmds = '' for switch in switches: - if switch.isOldOVS(): - # Ideally we'd optimize this also - run( 'ovs-vsctl del-br %s' % switch ) - for cmd in switch.commands: - cmd = cmd.strip() - # Don't exceed ARG_MAX - if len( cmds ) + len( cmd ) >= cls.argmax: - run( cmds, shell=True ) - cmds = 'ovs-vsctl' - cmds += ' ' + cmd - switch.cmds = [] - switch.batch = False + if switch.inNamespace: + switch.batch = False # stop batch capture + nscmds = '' + for cmd in switch.commands: + cmd = cmd.strip() + if len( nscmds ) + len( cmd ) >= cls.argmax: + switch.vsctl( nscmds ) + nscmds = '' + nscmds += ' -- ' + cmd + if nscmds: + switch.vsctl( nscmds ) + else: + if switch.isOldOVS(): + # Ideally we'd optimize this also + run( 'ovs-vsctl del-br %s' % switch ) + for cmd in switch.commands: + cmd = cmd.strip() + # Don't exceed ARG_MAX + if len( cmds ) + len( cmd ) >= cls.argmax: + run( 'ovs-vsctl' + cmds, shell=True ) + cmds = '' + cmds += ' -- ' + cmd + switch.cmds = [] + switch.batch = False if cmds: - run( cmds, shell=True ) + run( 'ovs-vsctl' + cmds, shell=True ) # Reapply link config if necessary... for switch in switches: for intf in switch.intfs.itervalues(): @@ -1225,23 +1283,30 @@ def batchStartup( cls, switches, run=errRun ): def stop( self, deleteIntfs=True ): """Terminate OVS switch. deleteIntfs: delete interfaces? (True)""" - self.cmd( 'ovs-vsctl del-br', self ) + for c in self.children: + c.kill() + self.vsctl( 'del-br', str(self) ) if self.datapath == 'user': self.cmd( 'ip link del', self ) super( OVSSwitch, self ).stop( deleteIntfs ) @classmethod def batchShutdown( cls, switches, run=errRun ): + for s in switches: + for c in s.children: + c.kill() + switches = [s for s in switches if not s.inNamespace] "Shut down a list of OVS switches" delcmd = 'del-br %s' if switches and not switches[ 0 ].isOldOVS(): delcmd = '--if-exists ' + delcmd # First, delete them all from ovsdb - run( 'ovs-vsctl ' + + if switches: + run( 'ovs-vsctl ' + ' -- '.join( delcmd % s for s in switches ) ) # Next, shut down all of the processes - pids = ' '.join( str( switch.pid ) for switch in switches ) - run( 'kill -HUP ' + pids ) + pids = ' '.join( str( switch.pid ) for switch in switches ) + run( 'kill -HUP ' + pids ) for switch in switches: switch.shell = None return switches