@@ -1,5 +1,5 @@
/*
- File autogenerated by gengetopt version 2.22.5
+ File autogenerated by gengetopt version 2.22.6
generated with the following command:
gengetopt --conf-parser
@@ -29,6 +29,8 @@ const char *gengetopt_args_info_purpose = "";
const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " [OPTIONS]...";
+const char *gengetopt_args_info_versiontext = "";
+
const char *gengetopt_args_info_description = "";
const char *gengetopt_args_info_help[] = {
@@ -37,8 +39,8 @@ const char *gengetopt_args_info_help[] = {
" -f, --fg Run in foreground (default=off)",
" -d, --debug Run in debug mode (default=off)",
" -c, --conf=STRING Read configuration file (default=`/etc/ggsn.conf')",
- " --pidfile=STRING Filename of process id file \n (default=`/var/run/ggsn.pid')",
- " --statedir=STRING Directory of nonvolatile data \n (default=`/var/lib/ggsn/')",
+ " --pidfile=STRING Filename of process id file\n (default=`/var/run/ggsn.pid')",
+ " --statedir=STRING Directory of nonvolatile data\n (default=`/var/lib/ggsn/')",
" -l, --listen=STRING Local interface",
" -n, --net=STRING Network (default=`192.168.0.0/24')",
" --ipup=STRING Script to run after link-up",
@@ -53,6 +55,7 @@ const char *gengetopt_args_info_help[] = {
" --logfile=STRING Logfile for errors",
" --loglevel=STRING Global log ldevel (default=`error')",
" -g, --gtpnl=STRING GTP kernel support (default=`eth0')",
+ " --gtpns=STRING Namespace for GTP interface",
0
};
@@ -123,6 +126,7 @@ void clear_given (struct gengetopt_args_info *args_info)
args_info->logfile_given = 0 ;
args_info->loglevel_given = 0 ;
args_info->gtpnl_given = 0 ;
+ args_info->gtpns_given = 0 ;
}
static
@@ -165,6 +169,8 @@ void clear_args (struct gengetopt_args_info *args_info)
args_info->loglevel_orig = NULL;
args_info->gtpnl_arg = gengetopt_strdup ("eth0");
args_info->gtpnl_orig = NULL;
+ args_info->gtpns_arg = NULL;
+ args_info->gtpns_orig = NULL;
}
@@ -193,7 +199,8 @@ void init_args_info(struct gengetopt_args_info *args_info)
args_info->qos_help = gengetopt_args_info_help[17] ;
args_info->logfile_help = gengetopt_args_info_help[18] ;
args_info->loglevel_help = gengetopt_args_info_help[19] ;
- args_info->gtpnl_help = gengetopt_args_info_help[19] ;
+ args_info->gtpnl_help = gengetopt_args_info_help[20] ;
+ args_info->gtpns_help = gengetopt_args_info_help[21] ;
}
@@ -203,6 +210,9 @@ cmdline_parser_print_version (void)
printf ("%s %s\n",
(strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE),
CMDLINE_PARSER_VERSION);
+
+ if (strlen(gengetopt_args_info_versiontext) > 0)
+ printf("\n%s\n", gengetopt_args_info_versiontext);
}
static void print_help_common(void) {
@@ -306,6 +316,8 @@ cmdline_parser_release (struct gengetopt_args_info *args_info)
free_string_field (&(args_info->loglevel_orig));
free_string_field (&(args_info->gtpnl_arg));
free_string_field (&(args_info->gtpnl_orig));
+ free_string_field (&(args_info->gtpns_arg));
+ free_string_field (&(args_info->gtpns_orig));
@@ -378,6 +390,8 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info)
write_into_file(outfile, "loglevel", args_info->loglevel_orig, 0);
if (args_info->gtpnl_given)
write_into_file(outfile, "gtpnl", args_info->gtpnl_orig, 0);
+ if (args_info->gtpns_given)
+ write_into_file(outfile, "gtpns", args_info->gtpns_orig, 0);
i = EXIT_SUCCESS;
@@ -602,7 +616,7 @@ cmdline_parser_internal (
{
int c; /* Character of the parsed option. */
- int error = 0;
+ int error_occurred = 0;
struct gengetopt_args_info local_args_info;
int override;
@@ -653,6 +667,7 @@ cmdline_parser_internal (
{ "logfile", 1, NULL, 0 },
{ "loglevel", 1, NULL, 0 },
{ "gtpnl", 1, NULL, 'g' },
+ { "gtpns", 1, NULL, 0 },
{ 0, 0, 0, 0 }
};
@@ -920,6 +935,20 @@ cmdline_parser_internal (
goto failure;
}
+ /* Namespace for GTP interface. */
+ else if (strcmp (long_options[option_index].name, "gtpns") == 0)
+ {
+
+
+ if (update_arg( (void *)&(args_info->gtpns_arg),
+ &(args_info->gtpns_orig), &(args_info->gtpns_given),
+ &(local_args_info.gtpns_given), optarg, 0, 0, ARG_STRING,
+ check_ambiguity, override, 0, 0,
+ "gtpns", '-',
+ additional_error))
+ goto failure;
+
+ }
break;
case '?': /* Invalid option. */
@@ -937,7 +966,7 @@ cmdline_parser_internal (
cmdline_parser_release (&local_args_info);
- if ( error )
+ if ( error_occurred )
return (EXIT_FAILURE);
return 0;
@@ -35,4 +35,5 @@ option "logfile" - "Logfile for errors" string no
option "loglevel" - "Global log ldevel" string default="error" no
option "gtpnl" g "GTP kernel support" string default="eth0" no
+option "gtpns" - "Namespace for GTP interface" string no
@@ -1,6 +1,6 @@
/** @file cmdline.h
* @brief The header file for the command line option parser
- * generated by GNU Gengetopt version 2.22.5
+ * generated by GNU Gengetopt version 2.22.6
* http://www.gnu.org/software/gengetopt.
* DO NOT modify this file, since it can be overwritten
* @author GNU Gengetopt by Lorenzo Bettini */
@@ -98,6 +98,9 @@ struct gengetopt_args_info
char * gtpnl_arg; /**< @brief GTP kernel support (default='eth0'). */
char * gtpnl_orig; /**< @brief GTP kernel support original value given at command line. */
const char *gtpnl_help; /**< @brief GTP kernel support help description. */
+ char * gtpns_arg; /**< @brief Namespace for GTP interface. */
+ char * gtpns_orig; /**< @brief Namespace for GTP interface original value given at command line. */
+ const char *gtpns_help; /**< @brief Namespace for GTP interface help description. */
unsigned int help_given ; /**< @brief Whether help was given. */
unsigned int version_given ; /**< @brief Whether version was given. */
@@ -120,6 +123,7 @@ struct gengetopt_args_info
unsigned int logfile_given ; /**< @brief Whether logfile was given. */
unsigned int loglevel_given ; /**< @brief Whether loglevel was given. */
unsigned int gtpnl_given ; /**< @brief Whether gtpnl was given. */
+ unsigned int gtpns_given ; /**< @brief Whether gtpns was given. */
} ;
@@ -137,6 +141,8 @@ struct cmdline_parser_params
extern const char *gengetopt_args_info_purpose;
/** @brief the usage string of the program */
extern const char *gengetopt_args_info_usage;
+/** @brief the description string of the program */
+extern const char *gengetopt_args_info_description;
/** @brief all the lines making the help output */
extern const char *gengetopt_args_info_help[];
@@ -48,6 +48,7 @@
#include <time.h>
+#include "../lib/netns.h"
#include "../lib/tun.h"
#include "../lib/ippool.h"
#include "../lib/syserr.h"
@@ -59,6 +60,8 @@
int end = 0;
int maxfd = 0; /* For select() */
+int gtp_ns = 0;
+
struct in_addr listen_;
struct in_addr netaddr, destaddr, net, mask; /* Network interface */
struct in_addr dns1, dns2; /* PCO DNS address */
@@ -262,6 +265,8 @@ int main(int argc, char **argv)
printf("statedir: %s\n", args_info.statedir_arg);
if (args_info.gtpnl_arg)
printf("gtpnl: %s\n", args_info.gtpnl_arg);
+ if (args_info.gtpns_arg)
+ printf("gtpns: %s\n", args_info.gtpns_arg);
printf("timelimit: %d\n", args_info.timelimit_arg);
}
@@ -324,6 +329,8 @@ int main(int argc, char **argv)
printf("statedir: %s\n", args_info.statedir_arg);
if (args_info.gtpnl_arg)
printf("gtpnl: %s\n", args_info.gtpnl_arg);
+ if (args_info.gtpns_arg)
+ printf("gtpns: %s\n", args_info.gtpns_arg);
printf("timelimit: %d\n", args_info.timelimit_arg);
}
@@ -506,6 +513,16 @@ int main(int argc, char **argv)
log_pid(args_info.pidfile_arg);
}
+ init_netns();
+ if (args_info.gtpns_arg) {
+ DEBUGP(DGGSN, "gtpclient: Initialising Network Namespace\n");
+
+ if ((gtp_ns = get_nsfd(args_info.gtpns_arg)) <= 0) {
+ SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to initialize network namespace");
+ exit(1);
+ }
+ }
+
DEBUGP(DGGSN, "gtpclient: Initialising GTP tunnel\n");
if (gtp_new(&gsn, args_info.statedir_arg, &listen_, GTP_MODE_GGSN)) {
@@ -520,7 +537,7 @@ int main(int argc, char **argv)
maxfd = gsn->fd1u;
/* use GTP kernel module for data packet encapsulation */
- if (gtp_kernel_init(gsn, &net, &mask, &args_info) < 0)
+ if (gtp_kernel_init(gtp_ns, gsn, &net, &mask, &args_info) < 0)
goto err;
gtp_set_cb_data_ind(gsn, encaps_tun);
@@ -23,6 +23,7 @@
#include <time.h>
+#include "../lib/netns.h"
#include "../lib/tun.h"
#include "../lib/syserr.h"
#include "../gtp/pdp.h"
@@ -82,6 +83,8 @@ static int mask2prefix(struct in_addr *mask)
}
static struct {
+ int ns;
+ int ifidx;
int genl_id;
struct mnl_socket *nl;
bool enabled;
@@ -90,21 +93,27 @@ static struct {
/* Always forces the kernel to allocate gtp0. If it exists it hits EEXIST */
#define GTP_DEVNAME "gtp0"
-int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
+int gtp_kernel_init(int ns,
+ struct gsn_t *gsn, struct in_addr *net,
struct in_addr *mask,
struct gengetopt_args_info *args_info)
{
+ unsigned int ret = 0;
+ sigset_t oldmask;
+
if (!args_info->gtpnl_given)
return 0;
- if (gtp_dev_create(GTP_DEVNAME, args_info->gtpnl_orig,
+ if (gtp_dev_create(ns, GTP_DEVNAME, args_info->gtpnl_orig,
gsn->fd0, gsn->fd1u) < 0) {
SYS_ERR(DGGSN, LOGL_ERROR, 0,
"cannot create GTP tunnel device: %s\n",
strerror(errno));
return -1;
}
+
gtp_nl.enabled = true;
+ gtp_nl.ns = ns;
gtp_nl.nl = genl_socket_open();
if (gtp_nl.nl == NULL) {
@@ -127,6 +136,12 @@ int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
DEBUGP(DGGSN, "Setting route to reach %s via %s\n",
args_info->net_arg, GTP_DEVNAME);
+ /* configure gtp dev in it's own namespace */
+ if (ns > 0)
+ switch_ns(ns, &oldmask);
+
+ gtp_nl.ifidx = if_nametoindex(GTP_DEVNAME);
+
if (gtp_dev_config(GTP_DEVNAME, net, mask2prefix(mask)) < 0) {
SYS_ERR(DGGSN, LOGL_ERROR, 0,
"Cannot add route to reach network %s\n",
@@ -151,12 +166,16 @@ int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
if (err < 0) {
SYS_ERR(DGGSN, LOGL_ERROR, 0,
"Failed to launch script `%s'", ipup);
- return -1;
+ ret = -1;
}
}
+
+ if (ns > 0)
+ restore_ns(&oldmask);
+
SYS_ERR(DGGSN, LOGL_NOTICE, 0, "GTP kernel configured\n");
- return 0;
+ return ret;
}
void gtp_kernel_stop(void)
@@ -185,7 +204,8 @@ int gtp_kernel_tunnel_add(struct pdp_t *pdp)
memcpy(&ms, &pdp->eua.v[2], sizeof(struct in_addr));
memcpy(&sgsn, &pdp->gsnrc.v[0], sizeof(struct in_addr));
- gtp_tunnel_set_ifidx(t, if_nametoindex(GTP_DEVNAME));
+ gtp_tunnel_set_ifns(t, gtp_nl.ns);
+ gtp_tunnel_set_ifidx(t, gtp_nl.ifidx);
gtp_tunnel_set_version(t, pdp->version);
gtp_tunnel_set_ms_ip4(t, &ms);
gtp_tunnel_set_sgsn_ip4(t, &sgsn);
@@ -216,7 +236,8 @@ int gtp_kernel_tunnel_del(struct pdp_t *pdp)
if (t == NULL)
return -1;
- gtp_tunnel_set_ifidx(t, if_nametoindex(GTP_DEVNAME));
+ gtp_tunnel_set_ifns(t, gtp_nl.ns);
+ gtp_tunnel_set_ifidx(t, gtp_nl.ifidx);
gtp_tunnel_set_version(t, pdp->version);
if (pdp->version == 0) {
gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
@@ -7,7 +7,8 @@ extern int debug;
extern char *ipup;
#ifdef GTP_KERNEL
-int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
+int gtp_kernel_init(int ns,
+ struct gsn_t *gsn, struct in_addr *net,
struct in_addr *mask,
struct gengetopt_args_info *args_info);
void gtp_kernel_stop(void);
@@ -18,7 +19,8 @@ int gtp_kernel_tunnel_del(struct pdp_t *pdp);
int gtp_kernel_enabled(void);
#else
-static inline int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
+static inline int gtp_kernel_init(int ns,
+ struct gsn_t *gsn, struct in_addr *net,
struct in_addr *mask,
struct gengetopt_args_info *args_info)
{
@@ -1,7 +1,7 @@
noinst_LIBRARIES = libmisc.a
-noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h
+noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h netns.h
AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
-libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c
+libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c netns.c
new file mode 100644
@@ -0,0 +1,135 @@
+/*
+ * NETNS functions.
+ * Copyright (C) 2014, 2015 Travelping GmbH
+ *
+ * The contents of this file may be used under the terms of the GNU
+ * General Public License Version 2, provided that the above copyright
+ * notice and this permission notice is included in all copies or
+ * substantial portions of the software.
+ *
+ */
+
+#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 <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 "netns.h"
+
+#define NETNS_PATH "/var/run/netns"
+
+int default_nsfd;
+
+int switch_ns(int nsfd, sigset_t *oldmask)
+{
+ sigset_t intmask;
+
+ sigfillset(&intmask);
+ sigprocmask(SIG_BLOCK, &intmask, oldmask);
+
+ return setns(nsfd, CLONE_NEWNET);
+}
+
+void restore_ns(sigset_t *oldmask)
+{
+ setns(default_nsfd, CLONE_NEWNET);
+
+ sigprocmask(SIG_SETMASK, oldmask, NULL);
+}
+
+int open_ns(int nsfd, const char *pathname, int flags)
+{
+ sigset_t intmask, oldmask;
+ int fd;
+ int errsv;
+
+ sigfillset(&intmask);
+ sigprocmask(SIG_BLOCK, &intmask, &oldmask);
+
+ setns(nsfd, CLONE_NEWNET);
+ fd = open(pathname, flags);
+ errsv = errno;
+ setns(default_nsfd, CLONE_NEWNET);
+
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+ errno = errsv;
+ return fd;
+}
+
+int socket_ns(int nsfd, int domain, int type, int protocol)
+{
+ sigset_t intmask, oldmask;
+ int sk;
+ int errsv;
+
+ sigfillset(&intmask);
+ sigprocmask(SIG_BLOCK, &intmask, &oldmask);
+
+ setns(nsfd, CLONE_NEWNET);
+ sk = socket(domain, type, protocol);
+ errsv = errno;
+ setns(default_nsfd, CLONE_NEWNET);
+
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+ errno = errsv;
+ return sk;
+}
+
+void init_netns()
+{
+ if ((default_nsfd = open("/proc/self/ns/net", O_RDONLY)) < 0) {
+ perror("init_netns");
+ exit(EXIT_FAILURE);
+ }
+}
+
+int get_nsfd(const char *name)
+{
+ int r;
+ 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;
+
+ 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;
+ }
+ close(r);
+
+ sigfillset(&intmask);
+ sigprocmask(SIG_BLOCK, &intmask, &oldmask);
+
+ unshare(CLONE_NEWNET);
+ mount("/proc/self/ns/net", path, "none", MS_BIND, NULL);
+
+ setns(default_nsfd, CLONE_NEWNET);
+
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+ return open(path, O_RDONLY);
+}
new file mode 100644
@@ -0,0 +1,26 @@
+/*
+ * NETNS functions.
+ * Copyright (C) 2014, 2015 Travelping GmbH
+ *
+ * The contents of this file may be used under the terms of the GNU
+ * General Public License Version 2, provided that the above copyright
+ * notice and this permission notice is included in all copies or
+ * substantial portions of the software.
+ *
+ */
+
+#ifndef __NETNS_H
+#define __NETNS_H
+
+extern int default_nsfd;
+
+void init_netns(void);
+
+int switch_ns(int nsfd, sigset_t *oldmask);
+void 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
The kernel gtp can now be create in an existing sub namespace. Signed-off-by: Andreas Schultz <aschultz@tpip.net> --- ggsn/cmdline.c | 41 ++++++++++++++--- ggsn/cmdline.ggo | 1 + ggsn/cmdline.h | 8 +++- ggsn/ggsn.c | 19 +++++++- ggsn/gtp-kernel.c | 33 ++++++++++--- ggsn/gtp-kernel.h | 6 ++- lib/Makefile.am | 4 +- lib/netns.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/netns.h | 26 +++++++++++ 9 files changed, 255 insertions(+), 18 deletions(-) create mode 100644 lib/netns.c create mode 100644 lib/netns.h