netns: Improve error checking
Change-Id: I9b9c8fd6eeaaa7d190b8e2a34ca82088904c7708changes/54/17254/3
parent
b629240a35
commit
ad6eaa2881
134
lib/netns.c
134
lib/netns.c
|
@ -49,99 +49,133 @@ static int default_nsfd;
|
|||
int switch_ns(int nsfd, sigset_t *oldmask)
|
||||
{
|
||||
sigset_t intmask;
|
||||
int rc;
|
||||
|
||||
sigfillset(&intmask);
|
||||
sigprocmask(SIG_BLOCK, &intmask, oldmask);
|
||||
if (sigfillset(&intmask) < 0)
|
||||
return -errno;
|
||||
if ((rc = sigprocmask(SIG_BLOCK, &intmask, oldmask)) != 0)
|
||||
return -rc;
|
||||
|
||||
return setns(nsfd, CLONE_NEWNET);
|
||||
if (setns(nsfd, CLONE_NEWNET) < 0)
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void restore_ns(sigset_t *oldmask)
|
||||
int restore_ns(sigset_t *oldmask)
|
||||
{
|
||||
setns(default_nsfd, CLONE_NEWNET);
|
||||
int rc;
|
||||
if (setns(default_nsfd, CLONE_NEWNET) < 0)
|
||||
return -errno;
|
||||
|
||||
sigprocmask(SIG_SETMASK, oldmask, NULL);
|
||||
if ((rc = sigprocmask(SIG_SETMASK, oldmask, NULL)) != 0)
|
||||
return -rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_ns(int nsfd, const char *pathname, int flags)
|
||||
{
|
||||
sigset_t intmask, oldmask;
|
||||
int fd;
|
||||
int errsv;
|
||||
int rc;
|
||||
|
||||
sigfillset(&intmask);
|
||||
sigprocmask(SIG_BLOCK, &intmask, &oldmask);
|
||||
if (sigfillset(&intmask) < 0)
|
||||
return -errno;
|
||||
if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0)
|
||||
return -rc;
|
||||
|
||||
setns(nsfd, CLONE_NEWNET);
|
||||
fd = open(pathname, flags);
|
||||
errsv = errno;
|
||||
setns(default_nsfd, CLONE_NEWNET);
|
||||
if (setns(nsfd, CLONE_NEWNET) < 0)
|
||||
return -errno;
|
||||
if ((fd = open(pathname, flags)) < 0)
|
||||
return -errno;
|
||||
if (setns(default_nsfd, CLONE_NEWNET) < 0) {
|
||||
close(fd);
|
||||
return -errno;
|
||||
}
|
||||
if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) {
|
||||
close(fd);
|
||||
return -rc;
|
||||
}
|
||||
|
||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||
|
||||
errno = errsv;
|
||||
return fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int socket_ns(int nsfd, int domain, int type, int protocol)
|
||||
{
|
||||
sigset_t intmask, oldmask;
|
||||
int sk;
|
||||
int errsv;
|
||||
int rc;
|
||||
|
||||
sigfillset(&intmask);
|
||||
sigprocmask(SIG_BLOCK, &intmask, &oldmask);
|
||||
if (sigfillset(&intmask) < 0)
|
||||
return -errno;
|
||||
if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0)
|
||||
return -rc;
|
||||
|
||||
setns(nsfd, CLONE_NEWNET);
|
||||
sk = socket(domain, type, protocol);
|
||||
errsv = errno;
|
||||
setns(default_nsfd, CLONE_NEWNET);
|
||||
if (setns(nsfd, CLONE_NEWNET) < 0)
|
||||
return -errno;
|
||||
if ((sk = socket(domain, type, protocol)) < 0)
|
||||
return -errno;
|
||||
if (setns(default_nsfd, CLONE_NEWNET) < 0) {
|
||||
close(sk);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||
|
||||
errno = errsv;
|
||||
if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) {
|
||||
close(sk);
|
||||
return -rc;
|
||||
}
|
||||
return sk;
|
||||
}
|
||||
|
||||
void init_netns()
|
||||
int init_netns()
|
||||
{
|
||||
if ((default_nsfd = open("/proc/self/ns/net", O_RDONLY)) < 0) {
|
||||
perror("init_netns");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if ((default_nsfd = open("/proc/self/ns/net", O_RDONLY)) < 0)
|
||||
return -errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_nsfd(const char *name)
|
||||
{
|
||||
int r;
|
||||
int rc;
|
||||
int fd;
|
||||
sigset_t intmask, oldmask;
|
||||
char path[MAXPATHLEN] = NETNS_PATH;
|
||||
|
||||
r = mkdir(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
|
||||
if (r < 0 && errno != EEXIST)
|
||||
return r;
|
||||
rc = mkdir(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
|
||||
if (rc < 0 && errno != EEXIST)
|
||||
return rc;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", NETNS_PATH, name);
|
||||
r = open(path, O_RDONLY|O_CREAT|O_EXCL, 0);
|
||||
if (r < 0) {
|
||||
if (errno == EEXIST)
|
||||
return open(path, O_RDONLY);
|
||||
|
||||
return r;
|
||||
fd = open(path, O_RDONLY|O_CREAT|O_EXCL, 0);
|
||||
if (fd < 0) {
|
||||
if (errno == EEXIST) {
|
||||
if ((fd = open(path, O_RDONLY)) < 0)
|
||||
return -errno;
|
||||
return fd;
|
||||
}
|
||||
return -errno;
|
||||
}
|
||||
close(r);
|
||||
if (close(fd) < 0)
|
||||
return -errno;
|
||||
|
||||
sigfillset(&intmask);
|
||||
sigprocmask(SIG_BLOCK, &intmask, &oldmask);
|
||||
if (sigfillset(&intmask) < 0)
|
||||
return -errno;
|
||||
if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0)
|
||||
return -rc;
|
||||
|
||||
unshare(CLONE_NEWNET);
|
||||
mount("/proc/self/ns/net", path, "none", MS_BIND, NULL);
|
||||
if (unshare(CLONE_NEWNET) < 0)
|
||||
return -errno;
|
||||
if (mount("/proc/self/ns/net", path, "none", MS_BIND, NULL) < 0)
|
||||
return -errno;
|
||||
|
||||
setns(default_nsfd, CLONE_NEWNET);
|
||||
if (setns(default_nsfd, CLONE_NEWNET) < 0)
|
||||
return -errno;
|
||||
|
||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||
if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0)
|
||||
return -rc;
|
||||
|
||||
return open(path, O_RDONLY);
|
||||
if ((fd = open(path, O_RDONLY)) < 0)
|
||||
return -errno;
|
||||
return fd;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
|
||||
#if defined(__linux__)
|
||||
|
||||
void init_netns(void);
|
||||
int init_netns(void);
|
||||
|
||||
int switch_ns(int nsfd, sigset_t *oldmask);
|
||||
void restore_ns(sigset_t *oldmask);
|
||||
int restore_ns(sigset_t *oldmask);
|
||||
|
||||
int open_ns(int nsfd, const char *pathname, int flags);
|
||||
int socket_ns(int nsfd, int domain, int type, int protocol);
|
||||
|
|
|
@ -1323,19 +1323,29 @@ static int create_ping(void *gsn, struct pdp_t *pdp,
|
|||
|
||||
static int delete_context(struct pdp_t *pdp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (tun && options.ipdown) {
|
||||
#if defined(__linux__)
|
||||
sigset_t oldmask;
|
||||
|
||||
if ((options.netns)) {
|
||||
switch_ns(netns, &oldmask);
|
||||
if ((rc = switch_ns(netns, &oldmask)) < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
"Failed to switch to netns %s: %s\n",
|
||||
options.netns, strerror(-rc));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
tun_runscript(tun, options.ipdown);
|
||||
|
||||
#if defined(__linux__)
|
||||
if ((options.netns)) {
|
||||
restore_ns(&oldmask);
|
||||
if ((rc = restore_ns(&oldmask)) < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
"Failed to switch to original netns: %s\n",
|
||||
strerror(-rc));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1399,6 +1409,7 @@ static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
|
|||
|
||||
static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
||||
{
|
||||
int rc;
|
||||
struct in46_addr addr;
|
||||
#if defined(__linux__)
|
||||
sigset_t oldmask;
|
||||
|
@ -1458,7 +1469,11 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
|||
|
||||
#if defined(__linux__)
|
||||
if ((options.createif) && (options.netns)) {
|
||||
switch_ns(netns, &oldmask);
|
||||
if ((rc = switch_ns(netns, &oldmask)) < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0,
|
||||
"Failed to switch to netns %s: %s\n",
|
||||
options.netns, strerror(-rc));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1504,7 +1519,10 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
|||
|
||||
#if defined(__linux__)
|
||||
if ((options.createif) && (options.netns)) {
|
||||
restore_ns(&oldmask);
|
||||
if ((rc = restore_ns(&oldmask)) < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
|
||||
strerror(-rc));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1572,7 +1590,7 @@ int main(int argc, char **argv)
|
|||
fd_set fds; /* For select() */
|
||||
struct timeval idleTime; /* How long to select() */
|
||||
struct pdp_t *pdp;
|
||||
int n;
|
||||
int n, rc;
|
||||
int starttime = time(NULL); /* Time program was started */
|
||||
int stoptime = 0; /* Time to exit */
|
||||
int pingtimeout = 0; /* Time to print ping statistics */
|
||||
|
@ -1594,7 +1612,10 @@ int main(int argc, char **argv)
|
|||
osmo_init_logging2(tall_sgsnemu_ctx, &log_info);
|
||||
|
||||
#if defined(__linux__)
|
||||
init_netns();
|
||||
if ((rc = init_netns()) < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to initialize netns: %s", strerror(-rc));
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Process options given in configuration file and command line */
|
||||
|
@ -1622,8 +1643,16 @@ int main(int argc, char **argv)
|
|||
|
||||
#if defined(__linux__)
|
||||
if ((options.createif) && (options.netns)) {
|
||||
netns = get_nsfd(options.netns);
|
||||
switch_ns(netns, &oldmask);
|
||||
if ((netns = get_nsfd(options.netns)) < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to obtain fd for netns %s: %s\n",
|
||||
options.netns, strerror(-netns));
|
||||
exit(1);
|
||||
}
|
||||
if ((rc = switch_ns(netns, &oldmask)) < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to netns %s: %s\n",
|
||||
options.netns, strerror(-rc));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1654,7 +1683,11 @@ int main(int argc, char **argv)
|
|||
|
||||
#if defined(__linux__)
|
||||
if ((options.createif) && (options.netns)) {
|
||||
restore_ns(&oldmask);
|
||||
if ((rc = restore_ns(&oldmask)) < 0) {
|
||||
SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to switch to original netns: %s\n",
|
||||
strerror(-rc));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue