aboutsummaryrefslogtreecommitdiffstats
path: root/ggsn
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2018-04-25 19:02:31 +0200
committerHarald Welte <laforge@gnumonks.org>2018-04-25 20:46:05 +0200
commit0406bdde75fc200754021f356c481059bae42b33 (patch)
tree835ed5bdc688bd32799ea34556e9ce95fae81974 /ggsn
parent97e7a98e0a25557e9156fe2f7b0bf7de44fab250 (diff)
Move kernel GTP support from ggsn/ to lib/
This way, the IP address / route handling between TUN devices and kernel GTP can be shared, which will provide not only a unified codebase but also a more consistent behavior. This also paves the road for to use kernel GTP from sgsnemu in the future. Related: OS#3214 Change-Id: Ic53a971136edd0d8871fbd6746d7b0090ce3a188
Diffstat (limited to 'ggsn')
-rw-r--r--ggsn/Makefile.am6
-rw-r--r--ggsn/ggsn.c142
-rw-r--r--ggsn/gtp-kernel.c196
-rw-r--r--ggsn/gtp-kernel.h36
4 files changed, 74 insertions, 306 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..2b0581e 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, -1, -1, false)) {
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, gsn->fd0, gsn->fd1u, true)) {
+ 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/ggsn/gtp-kernel.c b/ggsn/gtp-kernel.c
deleted file mode 100644
index 4564d9a..0000000
--- a/ggsn/gtp-kernel.c
+++ /dev/null
@@ -1,196 +0,0 @@
-#ifdef __linux__
-#define _GNU_SOURCE 1 /* strdup() prototype, broken arpa/inet.h */
-#endif
-
-#include "../config.h"
-
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-
-#include <libgtpnl/gtp.h>
-#include <libgtpnl/gtpnl.h>
-#include <libmnl/libmnl.h>
-
-#include <errno.h>
-
-#include <time.h>
-
-#include "../lib/tun.h"
-#include "../lib/syserr.h"
-#include "../gtp/pdp.h"
-#include "../gtp/gtp.h"
-
-#include <libgtpnl/gtp.h>
-#include <libgtpnl/gtpnl.h>
-#include <libmnl/libmnl.h>
-
-#include "gtp-kernel.h"
-
-static void pdp_debug(const char *prefix, const char *devname, struct pdp_t *pdp)
-{
- struct in46_addr ia46;
- struct in_addr ia;
-
- in46a_from_eua(&pdp->eua, &ia46);
- gsna2in_addr(&ia, &pdp->gsnrc);
-
- LOGPDPX(DGGSN, LOGL_DEBUG, pdp, "%s %s v%u TEID %"PRIx64" EUA=%s SGSN=%s\n", prefix,
- devname, pdp->version,
- pdp->version == 0 ? pdp_gettid(pdp->imsi, pdp->nsapi) : pdp->teid_gn,
- in46a_ntoa(&ia46), inet_ntoa(ia));
-}
-
-static struct {
- int genl_id;
- struct mnl_socket *nl;
-} gtp_nl;
-
-static int gtp_kernel_init_once(void)
-{
- /* only initialize once */
- if (gtp_nl.nl)
- return 0;
-
- gtp_nl.nl = genl_socket_open();
- if (gtp_nl.nl == NULL) {
- LOGP(DGGSN, LOGL_ERROR, "cannot create genetlink socket\n");
- return -1;
- }
- gtp_nl.genl_id = genl_lookup_family(gtp_nl.nl, "gtp");
- if (gtp_nl.genl_id < 0) {
- LOGP(DGGSN, LOGL_ERROR, "cannot lookup GTP genetlink ID\n");
- genl_socket_close(gtp_nl.nl);
- gtp_nl.nl = NULL;
- return -1;
- }
- LOGP(DGGSN, LOGL_NOTICE, "Initialized GTP kernel mode (genl ID is %d)\n", gtp_nl.genl_id);
-
- return 0;
-}
-
-int gtp_kernel_init(struct gsn_t *gsn, const char *devname, struct in46_prefix *prefix, const char *ipup)
-{
- 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 :/");
- 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);
- }
-
- /* 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");
-
- return 0;
-}
-
-void gtp_kernel_stop(const char *devname)
-{
- gtp_dev_destroy(devname);
-}
-
-int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname)
-{
- struct in_addr ms, sgsn;
- struct gtp_tunnel *t;
- int ret;
-
- pdp_debug(__func__, devname, pdp);
-
- t = gtp_tunnel_alloc();
- if (t == NULL)
- return -1;
-
- 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(devname));
- gtp_tunnel_set_version(t, pdp->version);
- gtp_tunnel_set_ms_ip4(t, &ms);
- gtp_tunnel_set_sgsn_ip4(t, &sgsn);
- if (pdp->version == 0) {
- gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
- gtp_tunnel_set_flowid(t, pdp->flru);
- } else {
- gtp_tunnel_set_i_tei(t, pdp->teid_own);
- /* use the TEI advertised by SGSN when sending packets
- * towards the SGSN */
- gtp_tunnel_set_o_tei(t, pdp->teid_gn);
- }
-
- ret = gtp_add_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
- gtp_tunnel_free(t);
-
- return ret;
-}
-
-int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname)
-{
- struct gtp_tunnel *t;
- int ret;
-
- pdp_debug(__func__, devname, pdp);
-
- t = gtp_tunnel_alloc();
- if (t == NULL)
- return -1;
-
- gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
- gtp_tunnel_set_version(t, pdp->version);
- if (pdp->version == 0) {
- gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
- gtp_tunnel_set_flowid(t, pdp->flru);
- } else {
- gtp_tunnel_set_i_tei(t, pdp->teid_own);
- }
-
- ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
- gtp_tunnel_free(t);
-
- return ret;
-}
diff --git a/ggsn/gtp-kernel.h b/ggsn/gtp-kernel.h
deleted file mode 100644
index e2da55a..0000000
--- a/ggsn/gtp-kernel.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _GTP_KERNEL_H_
-#define _GTP_KERNEL_H_
-
-struct gengetopt_args_info;
-
-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);
-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)
-{
- SYS_ERR(DGGSN, LOGL_ERROR, 0, "ggsn compiled without GTP kernel support!\n");
- return -1;
-}
-
-static inline void gtp_kernel_stop(const char *devname) {}
-
-static inline int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname)
-{
- return 0;
-}
-
-static inline int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname)
-{
- return 0;
-}
-
-#endif
-#endif /* _GTP_KERNEL_H_ */