From 0c78af6a9d91dd5733092e55878d7036dce0d3b7 Mon Sep 17 00:00:00 2001 From: Nicolas Hurman Date: Thu, 31 Mar 2016 21:50:29 +0200 Subject: [PATCH 1/9] Change the hostname of hosts --- mininet/node.py | 3 ++- mininet/term.py | 2 +- mnexec.c | 18 +++++++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index ea7851b8..9234291a 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -130,11 +130,12 @@ def startShell( self, mnopts=None ): # (p)rint pid, and run in (n)amespace opts = '-cd' if mnopts is None else mnopts if self.inNamespace: + opts = '-H %s %s' % (self.name, opts) opts += 'n' # bash -i: force interactive # -s: pass $* to shell, and make process easy to find in ps # prompt is set to sentinel chr( 127 ) - cmd = [ 'mnexec', opts, 'env', 'PS1=' + chr( 127 ), + cmd = [ 'mnexec' ] + opts.split() + [ 'env', 'PS1=' + chr( 127 ), 'bash', '--norc', '-is', 'mininet:' + self.name ] # Spawn a shell subprocess in a pseudo-tty, to disable buffering # in the subprocess and insulate it from signals (e.g. SIGINT) diff --git a/mininet/term.py b/mininet/term.py index 04d9871c..8bdaa9e4 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -54,7 +54,7 @@ def makeTerm( node, title='Node', term='xterm', display=None, cmd='bash'): display, tunnel = tunnelX11( node, display ) if display is None: return [] - term = node.popen( cmds[ term ] + + term = node.popen( [ '-H', node.name ] + cmds[ term ] + [ display, '-e', 'env TERM=ansi %s' % cmd ] ) return [ tunnel, term ] if tunnel else [ term ] diff --git a/mnexec.c b/mnexec.c index d3f173d7..4458f624 100644 --- a/mnexec.c +++ b/mnexec.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #if !defined(VERSION) #define VERSION "(devel)" @@ -102,8 +104,22 @@ int main(int argc, char *argv[]) char *cwd = get_current_dir_name(); static struct sched_param sp; - while ((c = getopt(argc, argv, "+cdnpa:g:r:vh")) != -1) + while ((c = getopt(argc, argv, "+H:cdnpa:g:r:vh")) != -1) switch(c) { + case 'H': + /* rename if we have a hostname */ + if (*optarg) { + if (unshare(CLONE_NEWUTS) == -1) { + perror("unshare"); + return 1; + } + + if (sethostname(optarg, MIN(strlen(optarg), HOST_NAME_MAX)) == -1) { + perror("sethostname"); + return 1; + } + } + break; case 'c': /* close file descriptors except stdin/out/error */ for (fd = getdtablesize(); fd > 2; fd--) From 2de6e89213879cfe65958e82f15a034f2b24656c Mon Sep 17 00:00:00 2001 From: Nicolas Hurman Date: Thu, 31 Mar 2016 23:06:18 +0200 Subject: [PATCH 2/9] Added support for overlayfs --- mininet/node.py | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/mininet/node.py b/mininet/node.py index 9234291a..2c56c2d5 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -13,7 +13,7 @@ monitor(). Examples of how to run experiments using this functionality are provided in the examples/ directory. By default, hosts share the root file system, but they may also specify private - directories. + directories or overlayed directories. CPULimitedHost: a virtual host whose CPU bandwidth is limited by RT or CFS bandwidth limiting. @@ -78,6 +78,7 @@ def __init__( self, name, inNamespace=True, **params ): """name: name of node inNamespace: in network namespace? privateDirs: list of private directory strings or tuples + overlayDirs: list of overlay directory strings or tuples params: Node parameters (see config() for details)""" # Make sure class actually works @@ -85,6 +86,7 @@ def __init__( self, name, inNamespace=True, **params ): self.name = params.get( 'name', name ) self.privateDirs = params.get( 'privateDirs', [] ) + self.overlayDirs = params.get( 'overlayDirs', [] ) self.inNamespace = params.get( 'inNamespace', inNamespace ) # Stash configuration parameters for future reference @@ -104,6 +106,7 @@ def __init__( self, name, inNamespace=True, **params ): # Start command interpreter shell self.startShell() + self.mountOverlayDirs() self.mountPrivateDirs() # File descriptor to node mapping support @@ -167,6 +170,42 @@ def startShell( self, mnopts=None ): # +m: disable job control notification self.cmd( 'unset HISTFILE; stty -echo; set +m' ) + def mountOverlayDirs( self ): + "mount overlay directories" + # Avoid expanding a string into a list of chars + assert not isinstance( self.overlayDirs, basestring ) + for directory in self.overlayDirs: + if isinstance( directory, tuple ): + # mount given overlay directory + overlayDir = directory[ 1 ] % self.__dict__ + mountPoint = directory[ 0 ] + else: + # mount temporary filesystem on directory + tmpDir = '/tmp/mininet/%s%s' % (self, directory) + overlayDir = tmpDir + '/overlay' + + mountPoint = directory + self.cmd( 'mkdir -p %s' % tmpDir ) + self.cmd( 'mount -n -t tmpfs tmpfs %s' % tmpDir ) + self.cmd( 'mkdir -p %s', overlayDir ) + + workDir = overlayDir + '.work' + self.cmd( 'mkdir -p %s %s' % (mountPoint, workDir) ) + self.cmd( 'mount -t overlay overlay -o lowerdir=%s,upperdir=%s,workdir=%s %s' % + ( mountPoint, overlayDir, workDir, mountPoint ) ) + + def unmountOverlayDirs( self ): + "mount overlay directories" + for directory in self.overlayDirs: + if isinstance( directory, tuple ): + mountPoint = directory[ 0 ] + self.cmd( 'umount ', mountPoint ) + else: + mountPoint = directory + self.cmd( 'umount ', mountPoint ) + tmpDir = '/tmp/mininet/%s/%s' % (self, directory) + self.cmd( 'umount ', tmpDir ) + def mountPrivateDirs( self ): "mount private directories" # Avoid expanding a string into a list of chars @@ -246,6 +285,7 @@ def write( self, data ): def terminate( self ): "Send kill signal to Node and clean up after it." self.unmountPrivateDirs() + self.unmountOverlayDirs() if self.shell: if self.shell.poll() is None: os.killpg( self.shell.pid, signal.SIGHUP ) From b8732523d42e9c5ba6b4b8b0f2f130f2e8186728 Mon Sep 17 00:00:00 2001 From: Nicolas Hurman Date: Thu, 31 Mar 2016 23:25:01 +0200 Subject: [PATCH 3/9] Cleanup created directories when exiting --- mininet/node.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mininet/node.py b/mininet/node.py index 2c56c2d5..0a5a8e14 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -199,12 +199,15 @@ def unmountOverlayDirs( self ): for directory in self.overlayDirs: if isinstance( directory, tuple ): mountPoint = directory[ 0 ] + overlayDir = directory[ 1 ] % self.__dict__ + workDir = overlayDir + '.work' self.cmd( 'umount ', mountPoint ) + self.cmd( 'rmdir %s/work %s' % (workDir, workDir) ) else: mountPoint = directory self.cmd( 'umount ', mountPoint ) - tmpDir = '/tmp/mininet/%s/%s' % (self, directory) - self.cmd( 'umount ', tmpDir ) + self.cmd( 'umount ', '/tmp/mininet/%s/%s' % (self, directory) ) + self.cmd( 'rmdir /tmp/mininet/%s%s /tmp/mininet/%s /tmp/mininet' % (self, directory, self) ) def mountPrivateDirs( self ): "mount private directories" From bd2b46a3bd85e539fb6fab934cb9419e919a5322 Mon Sep 17 00:00:00 2001 From: Nicolas Hurman Date: Fri, 1 Apr 2016 10:00:51 +0200 Subject: [PATCH 4/9] Copy X credentials with new hostname --- mininet/term.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mininet/term.py b/mininet/term.py index 8bdaa9e4..add02030 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -7,6 +7,7 @@ """ from os import environ +import subprocess from mininet.log import error from mininet.util import quietRun, errRun @@ -28,6 +29,11 @@ def tunnelX11( node, display=None): quietRun( 'xhost +si:localuser:root' ) return display, None else: + # Add credentials with new hostname + creds = subprocess.check_output( 'xauth list $DISPLAY', shell=True ) + newCred = node.name + '/' + creds.split('/', 1)[ 1 ] + node.cmd( 'xauth add ' + newCred ) + # Create a tunnel for the TCP connection port = 6000 + int( float( screen ) ) connection = r'TCP\:%s\:%s' % ( host, port ) From 4310c39393e45c4d60cb92ef1285c2ab398de2a3 Mon Sep 17 00:00:00 2001 From: Nicolas Hurman Date: Fri, 1 Apr 2016 10:13:33 +0200 Subject: [PATCH 5/9] Throw an error if overlayfs is not supported but needed by a node --- mininet/node.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mininet/node.py b/mininet/node.py index 0a5a8e14..6e482f9e 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -174,6 +174,12 @@ def mountOverlayDirs( self ): "mount overlay directories" # Avoid expanding a string into a list of chars assert not isinstance( self.overlayDirs, basestring ) + if self.overlayDirs: + with open('/proc/filesystems', 'r') as f: + if 'overlay' not in f.read(): + raise OSError('OverlayFS is not supported by your kernel but is required by node %s' % + self.name) + for directory in self.overlayDirs: if isinstance( directory, tuple ): # mount given overlay directory From bd59d1a02e84694ded1a795790eddc399801e525 Mon Sep 17 00:00:00 2001 From: Nicolas Hurman Date: Fri, 1 Apr 2016 10:17:13 +0200 Subject: [PATCH 6/9] Create overlay dir if it doesn't exist --- mininet/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/node.py b/mininet/node.py index 6e482f9e..e5ab3612 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -196,7 +196,7 @@ def mountOverlayDirs( self ): self.cmd( 'mkdir -p %s', overlayDir ) workDir = overlayDir + '.work' - self.cmd( 'mkdir -p %s %s' % (mountPoint, workDir) ) + self.cmd( 'mkdir -p %s %s %s' % (mountPoint, workDir, overlayDir) ) self.cmd( 'mount -t overlay overlay -o lowerdir=%s,upperdir=%s,workdir=%s %s' % ( mountPoint, overlayDir, workDir, mountPoint ) ) From 6449885f6206f98984fc69b611820c659cae78be Mon Sep 17 00:00:00 2001 From: Nicolas Hurman Date: Fri, 1 Apr 2016 10:31:49 +0200 Subject: [PATCH 7/9] Make sure we actually find a cookie + Contributors --- CONTRIBUTORS | 5 +++-- mininet/term.py | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 9bdbb519..abaccbb4 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -19,17 +19,18 @@ Cody Burkard Additional Mininet Contributors Tomasz Buchert -Gustavo Pantuza Coelho Pinto Fernando Cappi +Gustavo Pantuza Coelho Pinto Ryan Cox Shaun Crampton David Erickson -Glen Gibb Andrew Ferguson Eder Leao Fernandes Gregory Gee +Glen Gibb Jon Hall Roan Huang +Nicolas Hurman Vitaly Ivanov Babis Kaidos Rich Lane diff --git a/mininet/term.py b/mininet/term.py index add02030..159a9fbb 100644 --- a/mininet/term.py +++ b/mininet/term.py @@ -30,9 +30,10 @@ def tunnelX11( node, display=None): return display, None else: # Add credentials with new hostname - creds = subprocess.check_output( 'xauth list $DISPLAY', shell=True ) - newCred = node.name + '/' + creds.split('/', 1)[ 1 ] - node.cmd( 'xauth add ' + newCred ) + creds = subprocess.check_output( 'xauth list $DISPLAY', shell=True ).split('/', 1) + if len( creds ) == 2: + newCred = node.name + '/' + creds[ 1 ] + node.cmd( 'xauth add ' + newCred ) # Create a tunnel for the TCP connection port = 6000 + int( float( screen ) ) From 2c0c9cbc001e0ebebbd0e4ee946ac344f9bbba67 Mon Sep 17 00:00:00 2001 From: Nicolas Hurman Date: Fri, 1 Apr 2016 10:41:08 +0200 Subject: [PATCH 8/9] Fixed typo --- mininet/node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mininet/node.py b/mininet/node.py index e5ab3612..0c59fd9a 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -193,7 +193,7 @@ def mountOverlayDirs( self ): mountPoint = directory self.cmd( 'mkdir -p %s' % tmpDir ) self.cmd( 'mount -n -t tmpfs tmpfs %s' % tmpDir ) - self.cmd( 'mkdir -p %s', overlayDir ) + self.cmd( 'mkdir -p %s' % overlayDir ) workDir = overlayDir + '.work' self.cmd( 'mkdir -p %s %s %s' % (mountPoint, workDir, overlayDir) ) From 46c9792c1d22341e7c85964e0ff54457682c0056 Mon Sep 17 00:00:00 2001 From: Nicolas Hurman Date: Fri, 1 Apr 2016 12:28:32 +0200 Subject: [PATCH 9/9] Try to modprobe overlay if it isn't loaded --- mininet/moduledeps.py | 1 + mininet/node.py | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/mininet/moduledeps.py b/mininet/moduledeps.py index 860c21c9..64f0a5d0 100644 --- a/mininet/moduledeps.py +++ b/mininet/moduledeps.py @@ -21,6 +21,7 @@ def modprobe( mod ): OF_KMOD = 'ofdatapath' OVS_KMOD = 'openvswitch_mod' # Renamed 'openvswitch' in OVS 1.7+/Linux 3.5+ TUN = 'tun' +OVERLAY = 'overlay' def moduleDeps( subtract=None, add=None ): """Handle module dependencies. diff --git a/mininet/node.py b/mininet/node.py index 0c59fd9a..c5a8e906 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -63,7 +63,7 @@ from mininet.log import info, error, warn, debug from mininet.util import ( quietRun, errRun, errFail, moveIntf, isShellBuiltin, numCores, retry, mountCgroups ) -from mininet.moduledeps import moduleDeps, pathCheck, TUN +from mininet.moduledeps import moduleDeps, pathCheck, TUN, OVERLAY from mininet.link import Link, Intf, TCIntf, OVSIntf from re import findall from distutils.version import StrictVersion @@ -175,10 +175,7 @@ def mountOverlayDirs( self ): # Avoid expanding a string into a list of chars assert not isinstance( self.overlayDirs, basestring ) if self.overlayDirs: - with open('/proc/filesystems', 'r') as f: - if 'overlay' not in f.read(): - raise OSError('OverlayFS is not supported by your kernel but is required by node %s' % - self.name) + moduleDeps( add=OVERLAY ) for directory in self.overlayDirs: if isinstance( directory, tuple ):