From 90c6b2550ae578cc570041ab239117d16f7f6683 Mon Sep 17 00:00:00 2001 From: Hiroaki KAWAI Date: Fri, 18 Dec 2015 14:05:57 +0900 Subject: [PATCH 1/5] add OVSSwitch inNamespace support To run ovs in namespace, ovs-vswitchd have to run in that namespace. Dedicated ovsdb and ovs-vswitchd will run using working directory. Ref: http://openvswitch.org/pipermail/discuss/2015-September/018693.html Signed-off-by: Hiroaki KAWAI --- mininet/node.py | 74 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 22 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index c93fc1b8..d2e02795 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 ) @@ -1081,6 +1081,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 +1109,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,8 +1156,21 @@ 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("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, + "-vfile:info", + "--log-file=%s/ovsdb-server.log" % workdir, + "&") + self.cmd("ovs-vswitchd", + 'unix:%s/db.sock' % workdir, + "-vfile:info", + '--log-file=%s/ovs-vswitchd.log' % workdir, + '&') int( self.dpid, 16 ) # DPID must be a hex string # Command to add interfaces intfs = ''.join( ' -- add-port %s %s' % ( self, intf ) + @@ -1199,22 +1215,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 +1253,25 @@ 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 ) + 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 ): + 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 From 61b6c9f572044d76365a8423b817873a5fd9f434 Mon Sep 17 00:00:00 2001 From: Hiroaki KAWAI Date: Fri, 18 Dec 2015 15:15:17 +0900 Subject: [PATCH 2/5] fixups for console Signed-off-by: Hiroaki KAWAI --- mininet/node.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mininet/node.py b/mininet/node.py index d2e02795..772f2f20 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1157,17 +1157,20 @@ def start( self, controllers ): "Start up a new OVS OpenFlow switch using ovs-vsctl" if self.inNamespace: 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, '&') From c284eeb373311fe6e42df334e1dac1e90c946a31 Mon Sep 17 00:00:00 2001 From: Hiroaki KAWAI Date: Fri, 18 Dec 2015 17:09:52 +0900 Subject: [PATCH 3/5] ovs-vsctl command delimiter is -- Signed-off-by: Hiroaki KAWAI --- mininet/node.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 772f2f20..27755d5d 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1228,7 +1228,7 @@ def batchStartup( cls, switches, run=errRun ): if len( nscmds ) + len( cmd ) >= cls.argmax: switch.vsctl( nscmds ) nscmds = '' - nscmds += ' ' + cmd + nscmds += ' -- ' + cmd if nscmds: switch.vsctl( nscmds ) else: @@ -1241,7 +1241,7 @@ def batchStartup( cls, switches, run=errRun ): if len( cmds ) + len( cmd ) >= cls.argmax: run( 'ovs-vsctl' + cmds, shell=True ) cmds = '' - cmds += ' ' + cmd + cmds += ' -- ' + cmd switch.cmds = [] switch.batch = False if cmds: From b32665766a6d20bb823eca40ec89e58152e9bced Mon Sep 17 00:00:00 2001 From: Hiroaki KAWAI Date: Mon, 21 Dec 2015 17:55:11 +0900 Subject: [PATCH 4/5] relay controller connections via socat inNamespace --- mininet/node.py | 46 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 27755d5d..0b60205a 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -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 ): @@ -1174,19 +1175,45 @@ def start( self, controllers ): "-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 not 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 @@ -1256,6 +1283,8 @@ def batchStartup( cls, switches, run=errRun ): def stop( self, deleteIntfs=True ): """Terminate OVS switch. deleteIntfs: delete interfaces? (True)""" + for c in self.children: + c.kill() self.vsctl( 'del-br', str(self) ) if self.datapath == 'user': self.cmd( 'ip link del', self ) @@ -1263,6 +1292,9 @@ def stop( self, deleteIntfs=True ): @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' From 125f8d41b90b9f703eeae265c1e3714dadbd5079 Mon Sep 17 00:00:00 2001 From: Hiroaki KAWAI Date: Mon, 21 Dec 2015 19:01:52 +0900 Subject: [PATCH 5/5] fix typo --- mininet/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/node.py b/mininet/node.py index 0b60205a..03fbc66e 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -1205,7 +1205,7 @@ def start( self, controllers ): # 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 not in ("ssl", "tcp") ] + for c in controllers if c.protocol in ("ssl", "tcp") ] else: # Command to create controller entries clist = [ ( self.name + c.name, '%s:%s:%d' %