diff options
author | Harald Welte <laforge@gnumonks.org> | 2018-04-25 19:02:31 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2018-04-25 21:44:46 +0200 |
commit | f2286395e9dd5c1a9d2c57bafbe68c1e3a1b273f (patch) | |
tree | 409f91f428ca9a17d89208f37f7c8b730c227393 /ggsn | |
parent | 9eebe15cd1309011d43a3490de7fbc973966f120 (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.am | 6 | ||||
-rw-r--r-- | ggsn/ggsn.c | 142 | ||||
-rw-r--r-- | ggsn/gtp-kernel.c | 196 | ||||
-rw-r--r-- | ggsn/gtp-kernel.h | 36 |
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..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/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_ */ |