Statistics
| Branch: | Tag: | Revision:

mininet / mnexec.c @ 9c6620d8

History | View | Annotate | Download (4.31 KB)

1 c4ae4232 Bob Lantz
/* mnexec: execution utility for mininet
2
 *
3
 * Starts up programs and does things that are slow or
4
 * difficult in Python, including:
5
 *
6
 *  - closing all file descriptors except stdin/out/error
7
 *  - detaching from a controlling tty using setsid
8
 *  - running in a network namespace
9
 *  - printing out the pid of a process so we can identify it later
10 df600200 Bob Lantz
 *  - attaching to a namespace and cgroup
11
 *  - setting RT scheduling
12 c4ae4232 Bob Lantz
 *
13
 * Partially based on public domain setsid(1)
14
*/
15
16
#include <stdio.h>
17
#include <linux/sched.h>
18
#include <unistd.h>
19 e78e8fb5 Bob Lantz
#include <limits.h>
20
#include <syscall.h>
21
#include <fcntl.h>
22 df600200 Bob Lantz
#include <stdlib.h>
23
#include <limits.h>
24
#include <sched.h>
25 c4ae4232 Bob Lantz
26
void usage(char *name) 
27
{
28
    printf("Execution utility for Mininet.\n"
29 df600200 Bob Lantz
           "usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\n"
30 c4ae4232 Bob Lantz
           "-c: close all file descriptors except stdin/out/error\n"
31
           "-d: detach from tty by calling setsid()\n"
32
           "-n: run in new network namespace\n"
33 e78e8fb5 Bob Lantz
           "-p: print ^A + pid\n"
34 df600200 Bob Lantz
           "-a pid: attach to pid's network namespace\n"
35
           "-g group: add to cgroup\n"
36
           "-r rtprio: run with SCHED_RR (usually requires -g)\n",
37 e78e8fb5 Bob Lantz
           name);
38
}
39
40
41
int setns(int fd, int nstype)
42
{
43
        return syscall(308, fd, nstype);
44 c4ae4232 Bob Lantz
}
45
46 df600200 Bob Lantz
/* Validate alphanumeric path foo1/bar2/baz */
47
void validate(char *path)
48
{
49
    char *s;
50
    for (s=path; *s; s++) {
51
        if (!isalnum(*s) && *s != '/') {
52
            fprintf(stderr, "invalid path: %s\n", path);
53
            exit(1);
54
        }
55
    }
56
}
57
58
/* Add our pid to cgroup */
59
int cgroup(char *gname)
60
{
61
    static char path[PATH_MAX];
62
    static char *groups[] = {
63
        "cpu", "cpuacct", "cpuset", NULL
64
    };
65
    char **gptr;
66
    pid_t pid = getpid();
67
    int count = 0;
68
    validate(gname);
69
    for (gptr = groups; *gptr; gptr++) {
70
        FILE *f;
71
        snprintf(path, PATH_MAX, "/sys/fs/cgroup/%s/%s/tasks",
72
                 *gptr, gname);
73
        f = fopen(path, "w");
74
        if (f) {
75
            count++;
76
            fprintf(f, "%d\n", pid);
77
            fclose(f);
78
        }
79
    }
80
    if (!count) {
81
        fprintf(stderr, "cgroup: could not add to cgroup %s\n",
82
            gname);
83
        exit(1);
84
    }
85
}
86
87 c4ae4232 Bob Lantz
int main(int argc, char *argv[])
88
{
89
    char c;
90
    int fd;
91 e78e8fb5 Bob Lantz
    char path[PATH_MAX];
92
    int nsid;
93
    int pid;
94 df600200 Bob Lantz
    static struct sched_param sp;
95
    while ((c = getopt(argc, argv, "+cdnpa:g:r:")) != -1)
96 c4ae4232 Bob Lantz
        switch(c) {
97
        case 'c':
98
            /* close file descriptors except stdin/out/error */
99
            for (fd = getdtablesize(); fd > 2; fd--)
100
                close(fd);
101
            break;
102
        case 'd':
103
            /* detach from tty */
104
            if (getpgrp() == getpid()) {
105
                switch(fork()) {
106
                    case -1:
107
                        perror("fork");
108
                        return 1;
109
                    case 0:                /* child */
110
                        break;
111
                    default:        /* parent */
112
                        return 0;
113
                }
114
            }
115
            setsid();
116
            break;
117
        case 'n':
118
            /* run in network namespace */
119
            if (unshare(CLONE_NEWNET) == -1) {
120
                perror("unshare");
121
                return 1;
122
            }
123
            break;
124
        case 'p':
125
            /* print pid */
126
            printf("\001%d\n", getpid());
127
            fflush(stdout);
128
            break;
129 e78e8fb5 Bob Lantz
        case 'a':
130
            /* Attach to pid's network namespace */
131
            pid = atoi(optarg);
132
            sprintf(path, "/proc/%d/ns/net", pid );
133
            nsid = open(path, O_RDONLY);
134
            if (nsid < 0) {
135
                perror(path);
136
                return 1;
137
            }
138
            if (setns(nsid, 0) != 0) {
139
                perror("setns");
140
                return 1;
141
            }
142
            break;
143 df600200 Bob Lantz
        case 'g':
144
            /* Attach to cgroup */
145
            cgroup(optarg);
146
            break;
147
        case 'r':
148
            /* Set RT scheduling priority */
149
            sp.sched_priority = atoi(optarg);
150
            if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) {
151
                perror("sched_setscheduler");
152
                return 1;
153
            }
154
            break;
155 c4ae4232 Bob Lantz
        default:
156
            usage(argv[0]);
157
            break;
158
        }
159
160
    if (optind < argc) {
161 df600200 Bob Lantz
        execvp(argv[optind], &argv[optind]);
162
        perror(argv[optind]);
163
        return 1;
164
    }
165 c4ae4232 Bob Lantz
    
166
    usage(argv[0]);
167
}