iproute2/lib/namespace.c
<<
>>
Prefs
   1/*
   2 * namespace.c
   3 *
   4 *              This program is free software; you can redistribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 */
   9
  10#include <sys/statvfs.h>
  11#include <fcntl.h>
  12#include <dirent.h>
  13#include <limits.h>
  14
  15#include "utils.h"
  16#include "namespace.h"
  17
  18static void bind_etc(const char *name)
  19{
  20        char etc_netns_path[sizeof(NETNS_ETC_DIR) + NAME_MAX];
  21        char netns_name[PATH_MAX];
  22        char etc_name[PATH_MAX];
  23        struct dirent *entry;
  24        DIR *dir;
  25
  26        if (strlen(name) >= NAME_MAX)
  27                return;
  28
  29        snprintf(etc_netns_path, sizeof(etc_netns_path), "%s/%s", NETNS_ETC_DIR, name);
  30        dir = opendir(etc_netns_path);
  31        if (!dir)
  32                return;
  33
  34        while ((entry = readdir(dir)) != NULL) {
  35                if (strcmp(entry->d_name, ".") == 0)
  36                        continue;
  37                if (strcmp(entry->d_name, "..") == 0)
  38                        continue;
  39                snprintf(netns_name, sizeof(netns_name), "%s/%s", etc_netns_path, entry->d_name);
  40                snprintf(etc_name, sizeof(etc_name), "/etc/%s", entry->d_name);
  41                if (mount(netns_name, etc_name, "none", MS_BIND, NULL) < 0) {
  42                        fprintf(stderr, "Bind %s -> %s failed: %s\n",
  43                                netns_name, etc_name, strerror(errno));
  44                }
  45        }
  46        closedir(dir);
  47}
  48
  49int netns_switch(char *name)
  50{
  51        char net_path[PATH_MAX];
  52        int netns;
  53        unsigned long mountflags = 0;
  54        struct statvfs fsstat;
  55
  56        snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
  57        netns = open(net_path, O_RDONLY | O_CLOEXEC);
  58        if (netns < 0) {
  59                fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
  60                        name, strerror(errno));
  61                return -1;
  62        }
  63
  64        if (setns(netns, CLONE_NEWNET) < 0) {
  65                fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
  66                        name, strerror(errno));
  67                close(netns);
  68                return -1;
  69        }
  70        close(netns);
  71
  72        if (unshare(CLONE_NEWNS) < 0) {
  73                fprintf(stderr, "unshare failed: %s\n", strerror(errno));
  74                return -1;
  75        }
  76        /* Don't let any mounts propagate back to the parent */
  77        if (mount("", "/", "none", MS_SLAVE | MS_REC, NULL)) {
  78                fprintf(stderr, "\"mount --make-rslave /\" failed: %s\n",
  79                        strerror(errno));
  80                return -1;
  81        }
  82
  83        /* Mount a version of /sys that describes the network namespace */
  84
  85        if (umount2("/sys", MNT_DETACH) < 0) {
  86                /* If this fails, perhaps there wasn't a sysfs instance mounted. Good. */
  87                if (statvfs("/sys", &fsstat) == 0) {
  88                        /* We couldn't umount the sysfs, we'll attempt to overlay it.
  89                         * A read-only instance can't be shadowed with a read-write one. */
  90                        if (fsstat.f_flag & ST_RDONLY)
  91                                mountflags = MS_RDONLY;
  92                }
  93        }
  94        if (mount(name, "/sys", "sysfs", mountflags, NULL) < 0) {
  95                fprintf(stderr, "mount of /sys failed: %s\n",strerror(errno));
  96                return -1;
  97        }
  98
  99        /* Setup bind mounts for config files in /etc */
 100        bind_etc(name);
 101        return 0;
 102}
 103
 104int netns_get_fd(const char *name)
 105{
 106        char pathbuf[PATH_MAX];
 107        const char *path, *ptr;
 108
 109        path = name;
 110        ptr = strchr(name, '/');
 111        if (!ptr) {
 112                snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
 113                        NETNS_RUN_DIR, name );
 114                path = pathbuf;
 115        }
 116        return open(path, O_RDONLY);
 117}
 118
 119int netns_foreach(int (*func)(char *nsname, void *arg), void *arg)
 120{
 121        DIR *dir;
 122        struct dirent *entry;
 123
 124        dir = opendir(NETNS_RUN_DIR);
 125        if (!dir) {
 126                if (errno == ENOENT)
 127                        return 0;
 128
 129                fprintf(stderr, "Failed to open directory %s: %s\n",
 130                        NETNS_RUN_DIR, strerror(errno));
 131                return -1;
 132        }
 133
 134        while ((entry = readdir(dir)) != NULL) {
 135                if (strcmp(entry->d_name, ".") == 0)
 136                        continue;
 137                if (strcmp(entry->d_name, "..") == 0)
 138                        continue;
 139                if (func(entry->d_name, arg))
 140                        break;
 141        }
 142
 143        closedir(dir);
 144        return 0;
 145}
 146