diff options
-rw-r--r-- | ggsn/Makefile.am | 6 | ||||
-rw-r--r-- | ggsn/ggsn.c | 142 | ||||
-rw-r--r-- | lib/Makefile.am | 7 | ||||
-rw-r--r-- | lib/gtp-kernel.c (renamed from ggsn/gtp-kernel.c) | 54 | ||||
-rw-r--r-- | lib/gtp-kernel.h (renamed from ggsn/gtp-kernel.h) | 6 | ||||
-rw-r--r-- | lib/tun.c | 73 | ||||
-rw-r--r-- | lib/tun.h | 3 | ||||
-rw-r--r-- | sgsnemu/Makefile.am | 6 | ||||
-rw-r--r-- | sgsnemu/sgsnemu.c | 2 |
9 files changed, 151 insertions, 148 deletions
diff --git a/ggsn/Makefile.am b/ggsn/Makefile.am index 6b2232f..eca385f 100644 --- a/ggsn/Makefile.am +++ b/ggsn/Makefile.am @@ -12,8 +12,4 @@ osmo_ggsn_LDADD += $(LIBGTPNL_LIBS) endif osmo_ggsn_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a -osmo_ggsn_SOURCES = ggsn_vty.c ggsn.c ggsn.h gtp-kernel.h icmpv6.c icmpv6.h checksum.c checksum.h - -if ENABLE_GTP_KERNEL -osmo_ggsn_SOURCES += gtp-kernel.c -endif +osmo_ggsn_SOURCES = ggsn_vty.c ggsn.c ggsn.h icmpv6.c icmpv6.h checksum.c checksum.h diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 85a2211..4636c04 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -63,9 +63,9 @@ #include "../lib/ippool.h" #include "../lib/syserr.h" #include "../lib/in46_addr.h" +#include "../lib/gtp-kernel.h" #include "../gtp/pdp.h" #include "../gtp/gtp.h" -#include "gtp-kernel.h" #include "icmpv6.h" #include "ggsn.h" @@ -125,13 +125,14 @@ int apn_stop(struct apn_ctx *apn, bool force) LOGPAPN( LOGL_INFO, apn, "Running %s\n", apn->tun.cfg.ipdown_script); tun_runscript(apn->tun.tun, apn->tun.cfg.ipdown_script); } - /* release tun device */ - LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n", apn->tun.tun->devname); - osmo_fd_unregister(&apn->tun.fd); + if (apn->cfg.gtpu_mode == APN_GTPU_MODE_TUN) { + /* release tun device */ + LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n", apn->tun.tun->devname); + osmo_fd_unregister(&apn->tun.fd); + } tun_free(apn->tun.tun); apn->tun.tun = NULL; } - gtp_kernel_stop(apn->tun.cfg.dev_name); if (apn->v4.pool) { LOGPAPN(LOGL_INFO, apn, "Releasing IPv4 pool\n"); @@ -195,6 +196,7 @@ int apn_start(struct apn_ctx *apn) struct in46_prefix ipv6_tun_linklocal_ip; struct in46_prefix *blacklist; int blacklist_size; + struct gsn_t *gsn = apn->ggsn->gsn; int rc; if (apn->started) @@ -204,7 +206,7 @@ int apn_start(struct apn_ctx *apn) switch (apn->cfg.gtpu_mode) { case APN_GTPU_MODE_TUN: LOGPAPN(LOGL_INFO, apn, "Opening TUN device %s\n", apn->tun.cfg.dev_name); - if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name)) { + if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, false, -1, -1)) { LOGPAPN(LOGL_ERROR, apn, "Failed to configure tun device\n"); return -1; } @@ -216,66 +218,6 @@ int apn_start(struct apn_ctx *apn) /* Set TUN library callback */ tun_set_cb_ind(apn->tun.tun, cb_tun_ind); - - if (apn->v4.cfg.ifconfig_prefix.addr.len) { - LOGPAPN(LOGL_INFO, apn, "Setting tun IP address %s\n", - in46p_ntoa(&apn->v4.cfg.ifconfig_prefix)); - if (tun_addaddr(apn->tun.tun, &apn->v4.cfg.ifconfig_prefix.addr, NULL, - apn->v4.cfg.ifconfig_prefix.prefixlen)) { - LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv4 address %s: %s\n", - in46p_ntoa(&apn->v4.cfg.ifconfig_prefix), strerror(errno)); - apn_stop(apn, false); - return -1; - } - } - - if (apn->v6.cfg.ifconfig_prefix.addr.len) { - LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 address %s\n", - in46p_ntoa(&apn->v6.cfg.ifconfig_prefix)); - if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ifconfig_prefix.addr, NULL, - apn->v6.cfg.ifconfig_prefix.prefixlen)) { - LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 address %s: %s. " - "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n", - in46p_ntoa(&apn->v6.cfg.ifconfig_prefix), strerror(errno)); - apn_stop(apn, false); - return -1; - } - } - - if (apn->v6.cfg.ll_prefix.addr.len) { - LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 link-local address %s\n", - in46p_ntoa(&apn->v6.cfg.ll_prefix)); - if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ll_prefix.addr, NULL, - apn->v6.cfg.ll_prefix.prefixlen)) { - LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 link-local address %s: %s. " - "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n", - in46p_ntoa(&apn->v6.cfg.ll_prefix), strerror(errno)); - apn_stop(apn, false); - return -1; - } - apn->v6_lladdr = apn->v6.cfg.ll_prefix.addr.v6; - } - - if (apn->tun.cfg.ipup_script) { - LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n", - apn->tun.cfg.ipup_script); - tun_runscript(apn->tun.tun, apn->tun.cfg.ipup_script); - } - - if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6) && - apn->v6.cfg.ll_prefix.addr.len == 0) { - rc = tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK); - if (rc < 1) { - LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of interface: %s\n", - rc ? strerror(errno) : "tun interface has no link-local IP assigned"); - apn_stop(apn, false); - return -1; - } - apn->v6_lladdr = ipv6_tun_linklocal_ip.addr.v6; - } - - /* set back-pointer from TUN device to APN */ - apn->tun.tun->priv = apn; break; case APN_GTPU_MODE_KERNEL_GTP: LOGPAPN(LOGL_INFO, apn, "Opening Kernel GTP device %s\n", apn->tun.cfg.dev_name); @@ -284,7 +226,7 @@ int apn_start(struct apn_ctx *apn) apn_stop(apn, false); return -1; } - if (apn->ggsn->gsn == NULL) { + if (gsn == NULL) { /* skip bringing up the APN now if the GSN is not initialized yet. * This happens during initial load of the config file, as the * "no shutdown" in the ggsn node only happens after the "apn" nodes @@ -293,8 +235,8 @@ int apn_start(struct apn_ctx *apn) return 0; } /* use GTP kernel module for data packet encapsulation */ - if (gtp_kernel_init(apn->ggsn->gsn, apn->tun.cfg.dev_name, - &apn->v4.cfg.ifconfig_prefix, apn->tun.cfg.ipup_script) < 0) { + if (tun_new(&apn->tun.tun, apn->tun.cfg.dev_name, true, gsn->fd0, gsn->fd1u)) { + LOGPAPN(LOGL_ERROR, apn, "Failed to configure Kernel GTP device\n"); return -1; } break; @@ -303,6 +245,68 @@ int apn_start(struct apn_ctx *apn) return -1; } + /* common initialization below */ + + /* set back-pointer from TUN device to APN */ + apn->tun.tun->priv = apn; + + if (apn->v4.cfg.ifconfig_prefix.addr.len) { + LOGPAPN(LOGL_INFO, apn, "Setting tun IP address %s\n", + in46p_ntoa(&apn->v4.cfg.ifconfig_prefix)); + if (tun_addaddr(apn->tun.tun, &apn->v4.cfg.ifconfig_prefix.addr, NULL, + apn->v4.cfg.ifconfig_prefix.prefixlen)) { + LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv4 address %s: %s\n", + in46p_ntoa(&apn->v4.cfg.ifconfig_prefix), strerror(errno)); + apn_stop(apn, false); + return -1; + } + } + + if (apn->v6.cfg.ifconfig_prefix.addr.len) { + LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 address %s\n", + in46p_ntoa(&apn->v6.cfg.ifconfig_prefix)); + if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ifconfig_prefix.addr, NULL, + apn->v6.cfg.ifconfig_prefix.prefixlen)) { + LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 address %s: %s. " + "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n", + in46p_ntoa(&apn->v6.cfg.ifconfig_prefix), strerror(errno)); + apn_stop(apn, false); + return -1; + } + } + + if (apn->v6.cfg.ll_prefix.addr.len) { + LOGPAPN(LOGL_INFO, apn, "Setting tun IPv6 link-local address %s\n", + in46p_ntoa(&apn->v6.cfg.ll_prefix)); + if (tun_addaddr(apn->tun.tun, &apn->v6.cfg.ll_prefix.addr, NULL, + apn->v6.cfg.ll_prefix.prefixlen)) { + LOGPAPN(LOGL_ERROR, apn, "Failed to set tun IPv6 link-local address %s: %s. " + "Ensure you have ipv6 support and not used the disable_ipv6 sysctl?\n", + in46p_ntoa(&apn->v6.cfg.ll_prefix), strerror(errno)); + apn_stop(apn, false); + return -1; + } + apn->v6_lladdr = apn->v6.cfg.ll_prefix.addr.v6; + } + + if (apn->tun.cfg.ipup_script) { + LOGPAPN(LOGL_INFO, apn, "Running ip-up script %s\n", + apn->tun.cfg.ipup_script); + tun_runscript(apn->tun.tun, apn->tun.cfg.ipup_script); + } + + if (apn->cfg.apn_type_mask & (APN_TYPE_IPv6|APN_TYPE_IPv4v6) && + apn->v6.cfg.ll_prefix.addr.len == 0) { + rc = tun_ip_local_get(apn->tun.tun, &ipv6_tun_linklocal_ip, 1, IP_TYPE_IPv6_LINK); + if (rc < 1) { + LOGPAPN(LOGL_ERROR, apn, "Cannot obtain IPv6 link-local address of interface: %s\n", + rc ? strerror(errno) : "tun interface has no link-local IP assigned"); + apn_stop(apn, false); + return -1; + } + apn->v6_lladdr = ipv6_tun_linklocal_ip.addr.v6; + } + /* Create IPv4 pool */ if (apn->v4.cfg.dynamic_prefix.addr.len) { LOGPAPN(LOGL_INFO, apn, "Creating IPv4 pool %s\n", diff --git a/lib/Makefile.am b/lib/Makefile.am index 55348ad..b6e7aba 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,7 +1,12 @@ noinst_LIBRARIES = libmisc.a -noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h in46_addr.h netdev.h +noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h in46_addr.h netdev.h gtp-kernel.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 in46_addr.c netdev.c + +if ENABLE_GTP_KERNEL +AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS) +libmisc_a_SOURCES += gtp-kernel.c +endif diff --git a/ggsn/gtp-kernel.c b/lib/gtp-kernel.c index 4564d9a..48811bc 100644 --- a/ggsn/gtp-kernel.c +++ b/lib/gtp-kernel.c @@ -77,56 +77,20 @@ static int gtp_kernel_init_once(void) return 0; } -int gtp_kernel_init(struct gsn_t *gsn, const char *devname, struct in46_prefix *prefix, const char *ipup) +int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u) { - struct in_addr net; - const char *net_arg; - - if (!gtp_nl.nl) - gtp_kernel_init_once(); - - if (prefix->addr.len != 4) { - LOGP(DGGSN, LOGL_ERROR, "we only support IPv4 in this path :/"); + if (gtp_kernel_init_once() < 0) return -1; - } - net = prefix->addr.v4; - - if (gtp_dev_create(-1, devname, gsn->fd0, gsn->fd1u) < 0) { - LOGP(DGGSN, LOGL_ERROR, "cannot create GTP tunnel device: %s\n", - strerror(errno)); - return -1; - } - - net_arg = in46p_ntoa(prefix); - DEBUGP(DGGSN, "Setting route to reach %s via %s\n", net_arg, devname); - - if (gtp_dev_config(devname, &net, prefix->prefixlen) < 0) { - LOGP(DGGSN, LOGL_ERROR, "Cannot add route to reach network %s\n", net_arg); - } + return gtp_dev_create(dest_ns, devname, fd0, fd1u); +} - /* launch script if it is set to bring up the route to reach - * the MS, eg. ip ro add 10.0.0.0/8 dev gtp0. Better add this - * using native rtnetlink interface given that we know the - * MS network mask, later. - */ - if (ipup) { - char cmd[1024]; - int err; - - /* eg. /home/ggsn/ipup gtp0 10.0.0.0/8 */ - snprintf(cmd, sizeof(cmd), "%s %s %s", ipup, devname, net_arg); - cmd[sizeof(cmd)-1] = '\0'; - - err = system(cmd); - if (err < 0) { - LOGP(DGGSN, LOGL_ERROR, "Failed to launch script `%s'\n", ipup); - return -1; - } - } - LOGP(DGGSN, LOGL_NOTICE, "GTP kernel configured\n"); +int gtp_kernel_create_sgsn(int dest_ns, const char *devname, int fd0, int fd1u) +{ + if (gtp_kernel_init_once() < 0) + return -1; - return 0; + return gtp_dev_create_sgsn(dest_ns, devname, fd0, fd1u); } void gtp_kernel_stop(const char *devname) diff --git a/ggsn/gtp-kernel.h b/lib/gtp-kernel.h index e2da55a..464352c 100644 --- a/ggsn/gtp-kernel.h +++ b/lib/gtp-kernel.h @@ -7,18 +7,20 @@ extern int debug; extern char *ipup; #ifdef GTP_KERNEL -int gtp_kernel_init(struct gsn_t *gsn, const char *devname, struct in46_prefix *prefix, const char *ipup); +int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u); +int gtp_kernel_create_sgsn(int dest_ns, const char *devname, int fd0, int fd1u); void gtp_kernel_stop(const char *devname); int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname); int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname); #else -static inline int gtp_kernel_init(struct gsn_t *gsn, const char *devname, struct in46_prefix *prefix, const char *ipup) +static inline int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u) { SYS_ERR(DGGSN, LOGL_ERROR, 0, "ggsn compiled without GTP kernel support!\n"); return -1; } +#define gtp_kernel_create_sgsn gtp_kernel_create static inline void gtp_kernel_stop(const char *devname) {} @@ -19,6 +19,7 @@ #include <stdio.h> #include <stdlib.h> +#include <stdbool.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> @@ -57,6 +58,7 @@ #include "tun.h" #include "syserr.h" +#include "gtp-kernel.h" static int tun_setaddr4(struct tun_t *this, struct in_addr *addr, struct in_addr *dstaddr, struct in_addr *netmask) @@ -147,7 +149,7 @@ int tun_addaddr(struct tun_t *this, struct in46_addr *addr, struct in46_addr *ds } } -int tun_new(struct tun_t **tun, const char *dev_name) +int tun_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int fd0, int fd1u) { #if defined(__linux__) @@ -170,31 +172,50 @@ int tun_new(struct tun_t **tun, const char *dev_name) (*tun)->routes = 0; #if defined(__linux__) - /* Open the actual tun device */ - if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) { - SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed"); - goto err_free; - } - - /* Set device flags. For some weird reason this is also the method - used to obtain the network interface name */ - memset(&ifr, 0, sizeof(ifr)); - if (dev_name) - strcpy(ifr.ifr_name, dev_name); - ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */ - if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) { - SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed"); - goto err_close; + if (!use_kernel) { + /* Open the actual tun device */ + if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) { + SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed"); + goto err_free; + } + + /* Set device flags. For some weird reason this is also the method + used to obtain the network interface name */ + memset(&ifr, 0, sizeof(ifr)); + if (dev_name) + strcpy(ifr.ifr_name, dev_name); + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */ + if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) { + SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed"); + goto err_close; + } + + strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ); + (*tun)->devname[IFNAMSIZ - 1] = 0; + + ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */ + return 0; + } else { + strncpy((*tun)->devname, dev_name, IFNAMSIZ); + (*tun)->devname[IFNAMSIZ - 1] = 0; + (*tun)->fd = -1; + + if (gtp_kernel_create(-1, dev_name, fd0, fd1u) < 0) { + LOGP(DTUN, LOGL_ERROR, "cannot create GTP tunnel device: %s\n", + strerror(errno)); + return -1; + } + LOGP(DTUN, LOGL_NOTICE, "GTP kernel configured\n"); + return 0; } - strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ); - (*tun)->devname[IFNAMSIZ - 1] = 0; - - ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */ - return 0; - #elif defined(__FreeBSD__) || defined (__APPLE__) + if (use_kernel) { + LOGP(DTUN, LOGL_ERROR, "No kernel GTP-U support in FreeBSD!\n"); + return -1; + } + /* Find suitable device */ for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */ snprintf(devname, sizeof(devname), "/dev/tun%d", devnum); @@ -249,10 +270,14 @@ int tun_free(struct tun_t *tun) netdev_delroute(&tun->dstaddr, &tun->addr, &tun->netmask); } - if (close(tun->fd)) { - SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed"); + if (tun->fd >= 0) { + if (close(tun->fd)) { + SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed"); + } } + gtp_kernel_stop(tun->devname); + /* TODO: For solaris we need to unlink streams */ free(tun); @@ -13,6 +13,7 @@ #ifndef _TUN_H #define _TUN_H +#include <stdbool.h> #include <net/if.h> #include "../lib/in46_addr.h" @@ -41,7 +42,7 @@ struct tun_t { void *priv; }; -extern int tun_new(struct tun_t **tun, const char *dev_name); +extern int tun_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int fd0, int fd1u); extern int tun_free(struct tun_t *tun); extern int tun_decaps(struct tun_t *this); extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len); diff --git a/sgsnemu/Makefile.am b/sgsnemu/Makefile.am index 4d02eca..9f10cd2 100644 --- a/sgsnemu/Makefile.am +++ b/sgsnemu/Makefile.am @@ -5,5 +5,11 @@ AM_LDFLAGS = @EXEC_LDFLAGS@ AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS) sgsnemu_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS) + +if ENABLE_GTP_KERNEL +AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS) +sgsnemu_LDADD += $(LIBGTPNL_LIBS) +endif + sgsnemu_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a sgsnemu_SOURCES = sgsnemu.c cmdline.c cmdline.h diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c index 92abc70..1e61a09 100644 --- a/sgsnemu/sgsnemu.c +++ b/sgsnemu/sgsnemu.c @@ -1571,7 +1571,7 @@ int main(int argc, char **argv) if (options.createif) { printf("Setting up interface\n"); /* Create a tunnel interface */ - if (tun_new((struct tun_t **)&tun, options.tun_dev_name)) { + if (tun_new((struct tun_t **)&tun, options.tun_dev_name, false, -1, -1)) { SYS_ERR(DSGSN, LOGL_ERROR, 0, "Failed to create tun"); exit(1); |