diff --git a/mininet/node.py b/mininet/node.py index 7539b63..a901b7a 100644 --- a/mininet/node.py +++ b/mininet/node.py @@ -287,7 +287,8 @@ class Node( object ): args: Popen() args, single list, or string kwargs: Popen() keyword args""" defaults = { 'stdout': PIPE, 'stderr': PIPE, - 'mncmd': [ 'mnexec', '-a' ] } + 'mncmd': + [ 'mnexec', '-a', str( self.pid ) ] } defaults.update( kwargs ) if len( args ) == 1: if type( args[ 0 ] ) is list: @@ -302,7 +303,7 @@ class Node( object ): # Attach to our namespace using mnexec -a mncmd = defaults[ 'mncmd' ] del defaults[ 'mncmd' ] - cmd = mncmd + [ str( self.pid ) ] + cmd + cmd = mncmd + cmd return Popen( cmd, **defaults ) def pexec( self, *args, **kwargs ): @@ -591,9 +592,9 @@ class CPULimitedHost( Host ): kwargs: Popen() keyword args""" # Tell mnexec to execute command in our cgroup mncmd = [ 'mnexec', '-a', str( self.pid ), - '-c', self.cgroup ] + '-g', self.name ] if self.sched == 'rt': - mncmd = [ 'chrt', self.rtprio ] + mncmd + mncmd += [ '-r', str( self.rtprio ) ] return Host.popen( self, *args, mncmd=mncmd, **kwargs ) def cleanup( self ): @@ -661,7 +662,7 @@ class CPULimitedHost( Host ): self.cgroupSet( qstr, quota ) if sched == 'rt': # Set RT priority if necessary - self.chrt( prio=20 ) + self.chrt() info( '(%s %d/%dus) ' % ( sched, quota, period ) ) def setCPUs( self, cores, mems=0 ): diff --git a/mnexec.c b/mnexec.c index acad6b4..ebd479c 100644 --- a/mnexec.c +++ b/mnexec.c @@ -7,6 +7,8 @@ * - detaching from a controlling tty using setsid * - running in a network namespace * - printing out the pid of a process so we can identify it later + * - attaching to a namespace and cgroup + * - setting RT scheduling * * Partially based on public domain setsid(1) */ @@ -17,16 +19,21 @@ #include #include #include +#include +#include +#include void usage(char *name) { printf("Execution utility for Mininet.\n" - "usage: %s [-cdnp]\n" + "usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\n" "-c: close all file descriptors except stdin/out/error\n" "-d: detach from tty by calling setsid()\n" "-n: run in new network namespace\n" "-p: print ^A + pid\n" - "-a pid: attach to pid's network namespace\n", + "-a pid: attach to pid's network namespace\n" + "-g group: add to cgroup\n" + "-r rtprio: run with SCHED_RR (usually requires -g)\n", name); } @@ -36,6 +43,47 @@ int setns(int fd, int nstype) return syscall(308, fd, nstype); } +/* Validate alphanumeric path foo1/bar2/baz */ +void validate(char *path) +{ + char *s; + for (s=path; *s; s++) { + if (!isalnum(*s) && *s != '/') { + fprintf(stderr, "invalid path: %s\n", path); + exit(1); + } + } +} + +/* Add our pid to cgroup */ +int cgroup(char *gname) +{ + static char path[PATH_MAX]; + static char *groups[] = { + "cpu", "cpuacct", "cpuset", NULL + }; + char **gptr; + pid_t pid = getpid(); + int count = 0; + validate(gname); + for (gptr = groups; *gptr; gptr++) { + FILE *f; + snprintf(path, PATH_MAX, "/sys/fs/cgroup/%s/%s/tasks", + *gptr, gname); + f = fopen(path, "w"); + if (f) { + count++; + fprintf(f, "%d\n", pid); + fclose(f); + } + } + if (!count) { + fprintf(stderr, "cgroup: could not add to cgroup %s\n", + gname); + exit(1); + } +} + int main(int argc, char *argv[]) { char c; @@ -43,8 +91,8 @@ int main(int argc, char *argv[]) char path[PATH_MAX]; int nsid; int pid; - - while ((c = getopt(argc, argv, "+cdnpa:")) != -1) + static struct sched_param sp; + while ((c = getopt(argc, argv, "+cdnpa:g:r:")) != -1) switch(c) { case 'c': /* close file descriptors except stdin/out/error */ @@ -92,16 +140,28 @@ int main(int argc, char *argv[]) return 1; } break; + case 'g': + /* Attach to cgroup */ + cgroup(optarg); + break; + case 'r': + /* Set RT scheduling priority */ + sp.sched_priority = atoi(optarg); + if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) { + perror("sched_setscheduler"); + return 1; + } + break; default: usage(argv[0]); break; } if (optind < argc) { - execvp(argv[optind], &argv[optind]); - perror(argv[optind]); - return 1; - } + execvp(argv[optind], &argv[optind]); + perror(argv[optind]); + return 1; + } usage(argv[0]); }