Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node: support setHostname to run a node in its own UTS namespace #643

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions mininet/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ class Node( object ):

portBase = 0 # Nodes always start with eth0/port0, even in OF 1.0

def __init__( self, name, inNamespace=True, **params ):
def __init__( self, name, inNamespace=True, setHostname=False, **params ):
"""name: name of node
inNamespace: in network namespace?
setHostname: in uts namespace?
privateDirs: list of private directory strings or tuples
params: Node parameters (see config() for details)"""

Expand All @@ -86,6 +87,7 @@ def __init__( self, name, inNamespace=True, **params ):
self.name = params.get( 'name', name )
self.privateDirs = params.get( 'privateDirs', [] )
self.inNamespace = params.get( 'inNamespace', inNamespace )
self.setHostname = params.get( 'setHostname', setHostname )

# Stash configuration parameters for future reference
self.params = params
Expand Down Expand Up @@ -127,15 +129,19 @@ def startShell( self, mnopts=None ):
error( "%s: shell is already running\n" % self.name )
return
# mnexec: (c)lose descriptors, (d)etach from tty,
# (p)rint pid, and run in (n)amespace
opts = '-cd' if mnopts is None else mnopts
# (p)rint pid, run in (n)amespace, unshare (u)ts with a hostname
mnexec = ['mnexec']
mnexec.append('-cd' if not mnopts else mnopts)
if self.inNamespace:
opts += 'n'
mnexec.append('-n')
if self.setHostname:
mnexec.extend(['-u', self.name])
# 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 ),
'bash', '--norc', '-is', 'mininet:' + self.name ]
bash = [ 'env', 'PS1=' + chr( 127 ),
'bash', '--norc', '-is', 'mininet:' + self.name ]
cmd = mnexec + bash
# Spawn a shell subprocess in a pseudo-tty, to disable buffering
# in the subprocess and insulate it from signals (e.g. SIGINT)
# received by the parent
Expand Down
1 change: 1 addition & 0 deletions mininet/topolib.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def addTree( self, depth, fanout ):

def TreeNet( depth=1, fanout=2, **kwargs ):
"Convenience function for creating tree networks."
# topo = TreeTopo( depth, fanout, hopts={'setHostname':True})
topo = TreeTopo( depth, fanout )
return Mininet( topo, **kwargs )

Expand Down
35 changes: 29 additions & 6 deletions mnexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <linux/sched.h>
#include <unistd.h>
#include <limits.h>
Expand All @@ -32,15 +33,16 @@
void usage(char *name)
{
printf("Execution utility for Mininet\n\n"
"Usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\n\n"
"Usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] [-u hostname] cmd args...\n\n"
"Options:\n"
" -c: close all file descriptors except stdin/out/error\n"
" -d: detach from tty by calling setsid()\n"
" -n: run in new network and mount namespaces\n"
" -p: print ^A + pid\n"
" -a pid: attach to pid's network and mount namespaces\n"
" -a pid: attach to pid's network, mount and UTS namespaces\n"
" -g group: add to cgroup\n"
" -r rtprio: run with SCHED_RR (usually requires -g)\n"
" -u hostname: run in new uts namespace\n"
" -v: print version\n",
name);
}
Expand Down Expand Up @@ -102,7 +104,7 @@ 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, "+cdnpa:g:r:u:vh")) != -1)
switch(c) {
case 'c':
/* close file descriptors except stdin/out/error */
Expand Down Expand Up @@ -154,7 +156,7 @@ int main(int argc, char *argv[])
case 'a':
/* Attach to pid's network namespace and mount namespace */
pid = atoi(optarg);
sprintf(path, "/proc/%d/ns/net", pid);
snprintf(path, PATH_MAX, "/proc/%d/ns/net", pid);
nsid = open(path, O_RDONLY);
if (nsid < 0) {
perror(path);
Expand All @@ -165,11 +167,11 @@ int main(int argc, char *argv[])
return 1;
}
/* Plan A: call setns() to attach to mount namespace */
sprintf(path, "/proc/%d/ns/mnt", pid);
snprintf(path, PATH_MAX, "/proc/%d/ns/mnt", pid);
nsid = open(path, O_RDONLY);
if (nsid < 0 || setns(nsid, 0) != 0) {
/* Plan B: chroot/chdir into pid's root file system */
sprintf(path, "/proc/%d/root", pid);
snprintf(path, PATH_MAX, "/proc/%d/root", pid);
if (chroot(path) < 0) {
perror(path);
return 1;
Expand All @@ -180,6 +182,17 @@ int main(int argc, char *argv[])
perror(cwd);
return 1;
}
/* Attach to pid's UTS namespace */
snprintf(path, PATH_MAX, "/proc/%d/ns/uts", pid);
nsid = open(path, O_RDONLY);
if (nsid < 0) {
perror(path);
return 1;
}
if (setns(nsid, 0) != 0) {
perror("setns");
return 1;
}
break;
case 'g':
/* Attach to cgroup */
Expand All @@ -193,6 +206,16 @@ int main(int argc, char *argv[])
return 1;
}
break;
case 'u':
if (unshare(CLONE_NEWUTS) == -1) {
perror("unshare NEWUTS");
return 1;
}
if (sethostname(optarg, strlen(optarg)) == -1) {
perror("sethostname");
return 1;
}
break;
case 'v':
printf("%s\n", VERSION);
exit(0);
Expand Down