From 07aad110819778fdf65a43a6d11e9ca46c9881db Mon Sep 17 00:00:00 2001 From: Brandon Heller Date: Sat, 13 Mar 2010 21:33:42 -0800 Subject: [PATCH] Add ability to pause and resume any node --- mininet/cli.py | 20 +++++++++++++++++ mininet/node.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/mininet/cli.py b/mininet/cli.py index c045a6d..31b1ee4 100644 --- a/mininet/cli.py +++ b/mininet/cli.py @@ -157,6 +157,26 @@ class CLI( Cmd ): else: self.mn.link( *args ) + def do_pause( self, args ): + "Temporarily bring a node down." + args = args.split() + if len(args) != 1: + error( 'invalid number of args: pause [node]\n' ) + elif args[0] not in self.nodemap: + error( 'invalid node: %s\n' % args[0] ) + else: + self.nodemap[ args[ 0 ] ].pause() + + def do_resume( self, args ): + "Temporarily bring a node up." + args = args.split() + if len(args) != 1: + error( 'invalid number of args: resume [node]\n' ) + elif args[0] not in self.nodemap: + error( 'invalid node: %s\n' % args[0] ) + else: + self.nodemap[ args[ 0 ] ].resume() + def do_exit( self, args ): "Exit" return 'exited by user command' diff --git a/mininet/node.py b/mininet/node.py index d1f593f..06dd07d 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -337,6 +337,12 @@ class Node( object ): "Check if an interface is up." return 'UP' in self.cmd( 'ifconfig ' + intf ) + def modIntfs( self, action ): + """Bring all interfaces up or down. + action: string to pass to ifconfig""" + for intf in self.intfs.values(): + result = self.cmd( [ 'ifconfig', intf, action ] ) + # Other methods def __str__( self ): result = self.name + ':' @@ -351,6 +357,16 @@ class Host( Node ): "A host is simply a Node." pass + # Ideally, pausing a host would pause the process. However, when one + # tries to run a command on a paused host, it leads to an exception later. + # For now, disable interfaces to "pause" the host. + def pause( self ): + "Disable interfaces." + self.modIntfs('down') + + def resume( self ): + "Re-enable interfaces" + self.modIntfs('up') class Switch( Node ): """A Switch is a Node that is running (or has execed?) @@ -405,6 +421,17 @@ class UserSwitch( Switch ): self.cmd( 'kill %ofprotocol' ) self.deleteIntfs() + def pause( self ): + "Pause ofprotocol and ofdatapath." + self.cmd( 'kill -STOP %ofdatapath' ) + self.cmd( 'kill -STOP %ofprotocol' ) + + def resume( self ): + "Resume ofprotocol and datapath." + self.cmd( 'kill -CONT %ofdatapath' ) + self.cmd( 'kill -CONT %ofprotocol' ) + + class KernelSwitch( Switch ): """Kernel-space switch. Currently only works in root namespace.""" @@ -452,6 +479,18 @@ class KernelSwitch( Switch ): self.cmd( 'kill %ofprotocol' ) self.deleteIntfs() + # Since kernel threads cannot receive signals like user-space processes, + # disabling the interfaces and ofdatapath is our workaround. + def pause( self ): + "Disable interfaces and pause ofprotocol." + self.cmd( 'kill -STOP %ofprotocol' ) + self.modIntfs('down') + + def resume( self ): + "Re-enable interfaces and resume ofprotocol." + self.cmd( 'kill -CONT %ofprotocol' ) + self.modIntfs('up') + class OVSKernelSwitch( Switch ): """Open VSwitch kernel-space switch. Currently only works in the root namespace.""" @@ -500,6 +539,18 @@ class OVSKernelSwitch( Switch ): self.cmd( 'kill %ovs-openflowd' ) self.deleteIntfs() + # Since kernel threads cannot receive signals like user-space processes, + # disabling the interfaces and ofdatapath is our workaround. + def pause( self ): + "Disable interfaces and pause ovs-openflowd." + self.cmd( 'kill -STOP %ovs-openflowd' ) + self.modIntfs('down') + + def resume( self ): + "Re-enable interfaces and resume ovs-openflowd." + self.cmd( 'kill -CONT %ovs-openflowd' ) + self.modIntfs('up') + class Controller( Node ): """A Controller is a Node that is running (or has execed?) an @@ -530,6 +581,14 @@ class Controller( Node ): self.cmd( 'kill %' + self.controller ) self.terminate() + def pause( self ): + "Pause controller." + self.cmd( 'kill -STOP %' + self.controller ) + + def resume( self ): + "Resume controller." + self.cmd( 'kill -CONT %' + self.controller ) + def IP( self, intf=None ): "Return IP address of the Controller" ip = Node.IP( self, intf=intf ) @@ -537,6 +596,7 @@ class Controller( Node ): ip = self.defaultIP return ip + class ControllerParams( object ): "Container for controller IP parameters."