pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-uecups/+/42442?usp=email )
Change subject: Use libosmocore netns API ......................................................................
Use libosmocore netns API
Change-Id: Ia8617765d4c14483e2ad0ea09a8f2276fd7aaebf --- M daemon/Makefile.am M daemon/cups_client.c M daemon/internal.h M daemon/main.c D daemon/netns.c D daemon/netns.h M daemon/tun_device.c 7 files changed, 10 insertions(+), 324 deletions(-)
Approvals: pespin: Looks good to me, approved fixeria: Looks good to me, but someone else must approve osmith: Looks good to me, but someone else must approve Jenkins Builder: Verified
diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 2d62f11..1c680a6 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -27,7 +27,6 @@
noinst_HEADERS = \ gtp.h \ - netns.h \ internal.h \ $(NULL)
@@ -39,7 +38,6 @@ cups_client.c \ utility.c \ netdev.c \ - netns.c \ tun_device.c \ gtp_daemon.c \ gtp_endpoint.c \ diff --git a/daemon/cups_client.c b/daemon/cups_client.c index e2bae46..578719b 100644 --- a/daemon/cups_client.c +++ b/daemon/cups_client.c @@ -13,6 +13,7 @@ #include <osmocom/core/talloc.h> #include <osmocom/core/logging.h> #include <osmocom/core/exec.h> +#include <osmocom/core/netns.h>
#include "internal.h" #include "gtp.h" @@ -405,7 +406,7 @@ struct gtp_daemon *d = cc->d; const char *cmd, *user; char **addl_env = NULL; - sigset_t oldmask; + struct osmo_netns_switch_state switch_state; int nsfd = -1, rc;
juser = json_object_get(sprog, "run_as_user"); @@ -447,7 +448,7 @@ }
if (jnetns) { - rc = switch_ns(nsfd, &oldmask); + rc = osmo_netns_switch_enter(nsfd, &switch_state); if (rc < 0) { talloc_free(addl_env); return -EIO; @@ -457,7 +458,7 @@ rc = osmo_system_nowait2(cmd, osmo_environment_whitelist, addl_env, user);
if (jnetns) { - OSMO_ASSERT(restore_ns(&oldmask) == 0); + OSMO_ASSERT(osmo_netns_switch_exit(&switch_state) == 0); }
talloc_free(addl_env); diff --git a/daemon/internal.h b/daemon/internal.h index d431add..7a016fa 100644 --- a/daemon/internal.h +++ b/daemon/internal.h @@ -1,8 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ #pragma once
-#include "netns.h" - #include <stdint.h> #include <stdbool.h> #include <pthread.h> diff --git a/daemon/main.c b/daemon/main.c index c023351..b00e5d3 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -36,7 +36,6 @@ #include <jansson.h>
#include "internal.h" -#include "netns.h" #include "gtp.h"
static void *g_tall_ctx; @@ -226,8 +225,6 @@
handle_options(argc, argv);
- init_netns(); - rc = vty_read_config_file(g_config_file, NULL); if (rc < 0) { fprintf(stderr, "Failed to open config file: '%s'\n", g_config_file); diff --git a/daemon/netns.c b/daemon/netns.c deleted file mode 100644 index b0ec254..0000000 --- a/daemon/netns.c +++ /dev/null @@ -1,273 +0,0 @@ -#warning "Merge netns.c from osmo-ggsn and osmo-gtpu-daemon" -/* - * Copyright (C) 2014-2017, Travelping GmbH info@travelping.com - * Copyright (C) 2020, Harald Welte laforge@gnumonks.org - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -#if defined(__linux__) - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <sched.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/mount.h> -#include <sys/param.h> -#include <fcntl.h> -#include <errno.h> - -#include <osmocom/core/utils.h> - -#include "netns.h" - -#define NETNS_PATH "/var/run/netns" - -/*! default namespace of the GGSN process */ -static int default_nsfd = -1; - -/*! switch to a (non-default) namespace, store existing signal mask in oldmask. - * \param[in] nsfd file descriptor representing the namespace to whch we shall switch - * \param[out] oldmaks caller-provided memory location to which old signal mask is stored - * \ returns 0 on success or negative (errno) in case of error */ -int switch_ns(int nsfd, sigset_t *oldmask) -{ - sigset_t intmask; - int rc; - - OSMO_ASSERT(default_nsfd >= 0); - - if (sigfillset(&intmask) < 0) - return -errno; - if ((rc = sigprocmask(SIG_BLOCK, &intmask, oldmask)) != 0) - return -rc; - - if (setns(nsfd, CLONE_NEWNET) < 0) { - /* restore old mask if we couldn't switch the netns */ - sigprocmask(SIG_SETMASK, oldmask, NULL); - return -errno; - } - return 0; -} - -/*! switch back to the default namespace, restoring signal mask. - * \param[in] oldmask signal mask to restore after returning to default namespace - * \returns 0 on successs; negative errno value in case of error */ -int restore_ns(sigset_t *oldmask) -{ - OSMO_ASSERT(default_nsfd >= 0); - - int rc; - if (setns(default_nsfd, CLONE_NEWNET) < 0) - return -errno; - - if ((rc = sigprocmask(SIG_SETMASK, oldmask, NULL)) != 0) - return -rc; - return 0; -} - -/*! open a file from within specified network namespace */ -int open_ns(int nsfd, const char *pathname, int flags) -{ - sigset_t intmask, oldmask; - int ret; - int fd = -1; - int rc; - - OSMO_ASSERT(default_nsfd >= 0); - - /* mask off all signals, store old signal mask */ - if (sigfillset(&intmask) < 0) - return -errno; - if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0) - return -rc; - - /* associate the calling thread with namespace file descriptor */ - if (setns(nsfd, CLONE_NEWNET) < 0) { - ret = -errno; - goto restore_sigmask; - } - /* open the requested file/path */ - if ((fd = open(pathname, flags)) < 0) { - ret = -errno; - goto restore_defaultns; - } - ret = fd; - -restore_defaultns: - /* return back to default namespace */ - if (setns(default_nsfd, CLONE_NEWNET) < 0) { - if (fd >= 0) - close(fd); - return -errno; - } - -restore_sigmask: - /* restore process mask */ - if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) { - if (fd >= 0) - close(fd); - return -rc; - } - - return ret; -} - -/*! create a socket in another namespace. - * Switches temporarily to namespace indicated by nsfd, creates a socket in - * that namespace and then returns to the default namespace. - * \param[in] nsfd File descriptor of the namspace in which to create socket - * \param[in] domain Domain of the socket (AF_INET, ...) - * \param[in] type Type of the socket (SOCK_STREAM, ...) - * \param[in] protocol Protocol of the socket (IPPROTO_TCP, ...) - * \returns 0 on success; negative errno in case of error */ -int socket_ns(int nsfd, int domain, int type, int protocol) -{ - sigset_t intmask, oldmask; - int ret; - int sk = -1; - int rc; - - OSMO_ASSERT(default_nsfd >= 0); - - /* mask off all signals, store old signal mask */ - if (sigfillset(&intmask) < 0) - return -errno; - if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0) - return -rc; - - /* associate the calling thread with namespace file descriptor */ - if (setns(nsfd, CLONE_NEWNET) < 0) { - ret = -errno; - goto restore_sigmask; - } - - /* create socket of requested domain/type/proto */ - if ((sk = socket(domain, type, protocol)) < 0) { - ret = -errno; - goto restore_defaultns; - } - ret = sk; - -restore_defaultns: - /* return back to default namespace */ - if (setns(default_nsfd, CLONE_NEWNET) < 0) { - if (sk >= 0) - close(sk); - return -errno; - } - -restore_sigmask: - /* restore process mask */ - if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) { - if (sk >= 0) - close(sk); - return -rc; - } - return ret; -} - -/*! initialize this network namespace helper module. - * Must be called before using any other functions of this file. - * \returns 0 on success; negative errno in case of error */ -int init_netns() -{ - /* store the default namespace for later reference */ - if ((default_nsfd = open("/proc/self/ns/net", O_RDONLY)) < 0) - return -errno; - return 0; -} - -/*! create obtain file descriptor for network namespace of give name. - * Creates /var/run/netns if it doesn't exist already. - * \param[in] name Name of the network namespace (in /var/run/netns/) - * \returns File descriptor of network namespace; negative errno in case of error */ -int get_nsfd(const char *name) -{ - int ret = 0; - int rc; - int fd; - sigset_t intmask, oldmask; - char path[MAXPATHLEN] = NETNS_PATH; - - OSMO_ASSERT(default_nsfd >= 0); - - /* create /var/run/netns, if it doesn't exist already */ - rc = mkdir(path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); - if (rc < 0 && errno != EEXIST) - return rc; - - /* create /var/run/netns/[name], if it doesn't exist already */ - snprintf(path, sizeof(path), "%s/%s", NETNS_PATH, name); - 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; - } - if (close(fd) < 0) - return -errno; - - /* mask off all signals, store old signal mask */ - if (sigfillset(&intmask) < 0) - return -errno; - if ((rc = sigprocmask(SIG_BLOCK, &intmask, &oldmask)) != 0) - return -rc; - - /* create a new network namespace */ - if (unshare(CLONE_NEWNET) < 0) { - ret = -errno; - goto restore_sigmask; - } - if (mount("/proc/self/ns/net", path, "none", MS_BIND, NULL) < 0) - ret = -errno; - - /* switch back to default namespace */ - if (setns(default_nsfd, CLONE_NEWNET) < 0) - return -errno; - -restore_sigmask: - /* restore process mask */ - if ((rc = sigprocmask(SIG_SETMASK, &oldmask, NULL)) != 0) - return -rc; - - /* might have been set above in case mount fails */ - if (ret < 0) - return ret; - - /* finally, open the created namespace file descriptor from default ns */ - if ((fd = open(path, O_RDONLY)) < 0) - return -errno; - - return fd; -} - -#endif diff --git a/daemon/netns.h b/daemon/netns.h deleted file mode 100644 index 3b91ba3..0000000 --- a/daemon/netns.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2014-2017, Travelping GmbH info@travelping.com - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - * - */ - -#ifndef __NETNS_H -#define __NETNS_H - -#if defined(__linux__) - -int init_netns(void); - -int switch_ns(int nsfd, 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); -int get_nsfd(const char *name); - -#endif - -#endif diff --git a/daemon/tun_device.c b/daemon/tun_device.c index bc41db9..837fd9d 100644 --- a/daemon/tun_device.c +++ b/daemon/tun_device.c @@ -33,11 +33,11 @@ #include <osmocom/core/linuxlist.h> #include <osmocom/core/talloc.h> #include <osmocom/core/logging.h> +#include <osmocom/core/netns.h> #include <osmocom/core/utils.h>
#include "gtp.h" #include "internal.h" -#include "netns.h"
/*********************************************************************** * TUN Device @@ -320,7 +320,7 @@ { struct rtnl_link *link; struct tun_device *tun; - sigset_t oldmask; + struct osmo_netns_switch_state switch_state; int rc;
tun = talloc_zero(d, struct tun_device); @@ -333,7 +333,7 @@
if (netns_name) { tun->netns_name = talloc_strdup(tun, netns_name); - tun->netns_fd = get_nsfd(tun->netns_name); + tun->netns_fd = osmo_netns_open_fd(tun->netns_name); if (tun->netns_fd < 0) { LOGTUN(tun, LOGL_ERROR, "Cannot obtain netns file descriptor: %s\n", strerror(errno)); @@ -343,7 +343,7 @@
/* temporarily switch to specified namespace to create tun device */ if (tun->netns_name) { - rc = switch_ns(tun->netns_fd, &oldmask); + rc = osmo_netns_switch_enter(tun->netns_fd, &switch_state); if (rc < 0) { LOGTUN(tun, LOGL_ERROR, "Cannot switch to netns '%s': %s\n", tun->netns_name, strerror(errno)); @@ -374,7 +374,7 @@
/* switch back to default namespace before creating new thread */ if (tun->netns_name) - OSMO_ASSERT(restore_ns(&oldmask) == 0); + OSMO_ASSERT(osmo_netns_switch_exit(&switch_state) == 0);
/* bring the network device up */ rc = netdev_set_link(tun->nl, tun->ifindex, true); @@ -413,7 +413,7 @@ close(tun->fd); err_restore_ns: if (tun->netns_name) - OSMO_ASSERT(restore_ns(&oldmask) == 0); + OSMO_ASSERT(osmo_netns_switch_exit(&switch_state) == 0); err_close_ns: if (tun->netns_name) close(tun->netns_fd);