diff --git a/configure.ac b/configure.ac
index e31a79e..1fad6b1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -45,6 +45,17 @@ AC_SUBST(EXEC_LDADD)
 # FIXME: Replace `main' with a function in `-links':
 #AC_CHECK_LIB([inks], [main])
 
+dnl GTP kernel dependencies
+AC_ARG_ENABLE([gtp-kernel],
+	AS_HELP_STRING([--enable-gtp-kernel], [Build GTP tunneling kernel]),
+	[enable_gtp_kernel="$enableval"], [enable_gtp_kernel="no"])
+
+if test "x$enable_gtp_kernel" = "xyes"; then
+	PKG_CHECK_MODULES([LIBGTPNL], [libgtpnl >= 1.0.0])
+fi
+
+AM_CONDITIONAL([ENABLE_GTP_KERNEL], [test "$enable_gtp_kernel" = "yes"])
+
 # Checks for header files.
 AC_HEADER_STDC
 AC_HEADER_SYS_WAIT
@@ -119,3 +130,7 @@ AC_CONFIG_FILES([Makefile
                  libgtp.pc
                  openggsn.spec])
 AC_OUTPUT
+
+echo "
+openggsn Configuration:
+  GTP kernel support:			${enable_gtp_kernel}"
diff --git a/ggsn/Makefile.am b/ggsn/Makefile.am
index 91df8f0..c8868c1 100644
--- a/ggsn/Makefile.am
+++ b/ggsn/Makefile.am
@@ -4,7 +4,16 @@ AM_LDFLAGS = @EXEC_LDFLAGS@
 
 AM_CFLAGS = -O2 -D_GNU_SOURCE -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
 
+if ENABLE_GTP_KERNEL
+AM_CFLAGS += -DGTP_KERNEL
+ggsn_LDADD = @EXEC_LDADD@ -lgtp -lgtpnl -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS)
+else
 ggsn_LDADD = @EXEC_LDADD@ -lgtp -L../gtp ../lib/libmisc.a $(LIBOSMOCORE_LIBS)
+endif
+
 ggsn_DEPENDENCIES = ../gtp/libgtp.la ../lib/libmisc.a
-ggsn_SOURCES = ggsn.c cmdline.c cmdline.h
+ggsn_SOURCES = ggsn.c cmdline.c cmdline.h gtp-kernel.h
 
+if ENABLE_GTP_KERNEL
+ggsn_SOURCES += gtp-kernel.c
+endif
diff --git a/ggsn/cmdline.c b/ggsn/cmdline.c
index 37ed992..a4c25d8 100644
--- a/ggsn/cmdline.c
+++ b/ggsn/cmdline.c
@@ -1,5 +1,5 @@
 /*
-  File autogenerated by gengetopt version 2.22.6
+  File autogenerated by gengetopt version 2.22.5
   generated with the following command:
   gengetopt --conf-parser 
 
@@ -29,8 +29,6 @@ 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[] = {
@@ -39,8 +37,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",
@@ -54,6 +52,7 @@ const char *gengetopt_args_info_help[] = {
   "  -q, --qos=INT          Requested quality of service  (default=`0x0b921f')",
   "      --logfile=STRING   Logfile for errors",
   "      --loglevel=STRING  Global log ldevel  (default=`error')",
+  "  -g, --gtpnl=STRING     GTP kernel support  (default=`eth0')",
     0
 };
 
@@ -123,6 +122,7 @@ void clear_given (struct gengetopt_args_info *args_info)
   args_info->qos_given = 0 ;
   args_info->logfile_given = 0 ;
   args_info->loglevel_given = 0 ;
+  args_info->gtpnl_given = 0 ;
 }
 
 static
@@ -163,6 +163,8 @@ void clear_args (struct gengetopt_args_info *args_info)
   args_info->logfile_orig = NULL;
   args_info->loglevel_arg = gengetopt_strdup ("error");
   args_info->loglevel_orig = NULL;
+  args_info->gtpnl_arg = gengetopt_strdup ("eth0");
+  args_info->gtpnl_orig = NULL;
   
 }
 
@@ -191,6 +193,7 @@ 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] ;
   
 }
 
@@ -200,9 +203,6 @@ 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) {
@@ -304,6 +304,8 @@ cmdline_parser_release (struct gengetopt_args_info *args_info)
   free_string_field (&(args_info->logfile_orig));
   free_string_field (&(args_info->loglevel_arg));
   free_string_field (&(args_info->loglevel_orig));
+  free_string_field (&(args_info->gtpnl_arg));
+  free_string_field (&(args_info->gtpnl_orig));
   
   
 
@@ -374,6 +376,8 @@ cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info)
     write_into_file(outfile, "logfile", args_info->logfile_orig, 0);
   if (args_info->loglevel_given)
     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);
   
 
   i = EXIT_SUCCESS;
@@ -598,7 +602,7 @@ cmdline_parser_internal (
 {
   int c;	/* Character of the parsed option.  */
 
-  int error_occurred = 0;
+  int error = 0;
   struct gengetopt_args_info local_args_info;
   
   int override;
@@ -648,10 +652,11 @@ cmdline_parser_internal (
         { "qos",	1, NULL, 'q' },
         { "logfile",	1, NULL, 0 },
         { "loglevel",	1, NULL, 0 },
+        { "gtpnl",	1, NULL, 'g' },
         { 0,  0, 0, 0 }
       };
 
-      c = getopt_long (argc, argv, "hVfdc:l:n:a:q:", long_options, &option_index);
+      c = getopt_long (argc, argv, "hVfdc:l:n:a:q:g:", long_options, &option_index);
 
       if (c == -1) break;	/* Exit from `while (1)' loop.  */
 
@@ -747,6 +752,18 @@ cmdline_parser_internal (
             goto failure;
         
           break;
+        case 'g':	/* GTP kernel support.  */
+        
+        
+          if (update_arg( (void *)&(args_info->gtpnl_arg), 
+               &(args_info->gtpnl_orig), &(args_info->gtpnl_given),
+              &(local_args_info.gtpnl_given), optarg, 0, "eth0", ARG_STRING,
+              check_ambiguity, override, 0, 0,
+              "gtpnl", 'g',
+              additional_error))
+            goto failure;
+        
+          break;
 
         case 0:	/* Long option with no short option */
           /* Filename of process id file.  */
@@ -920,7 +937,7 @@ cmdline_parser_internal (
 
   cmdline_parser_release (&local_args_info);
 
-  if ( error_occurred )
+  if ( error )
     return (EXIT_FAILURE);
 
   return 0;
diff --git a/ggsn/cmdline.ggo b/ggsn/cmdline.ggo
index 9c4c976..47ff102 100644
--- a/ggsn/cmdline.ggo
+++ b/ggsn/cmdline.ggo
@@ -33,3 +33,6 @@ option  "apn"         a "Access point name"             string default="internet
 option  "qos"         q "Requested quality of service"  int    default="0x0b921f" no
 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
+
diff --git a/ggsn/cmdline.h b/ggsn/cmdline.h
index a87fa4a..150fb4d 100644
--- a/ggsn/cmdline.h
+++ b/ggsn/cmdline.h
@@ -1,6 +1,6 @@
 /** @file cmdline.h
  *  @brief The header file for the command line option parser
- *  generated by GNU Gengetopt version 2.22.6
+ *  generated by GNU Gengetopt version 2.22.5
  *  http://www.gnu.org/software/gengetopt.
  *  DO NOT modify this file, since it can be overwritten
  *  @author GNU Gengetopt by Lorenzo Bettini */
@@ -95,6 +95,9 @@ struct gengetopt_args_info
   char * loglevel_arg;	/**< @brief Global log ldevel (default='error').  */
   char * loglevel_orig;	/**< @brief Global log ldevel original value given at command line.  */
   const char *loglevel_help; /**< @brief Global log ldevel help description.  */
+  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.  */
   
   unsigned int help_given ;	/**< @brief Whether help was given.  */
   unsigned int version_given ;	/**< @brief Whether version was given.  */
@@ -116,6 +119,7 @@ struct gengetopt_args_info
   unsigned int qos_given ;	/**< @brief Whether qos was given.  */
   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.  */
 
 } ;
 
@@ -133,8 +137,6 @@ 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[];
 
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 53c8c01..821c942 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -54,6 +54,7 @@
 #include "../gtp/pdp.h"
 #include "../gtp/gtp.h"
 #include "cmdline.h"
+#include "gtp-kernel.h"
 
 int end = 0;
 int maxfd = 0;			/* For select()            */
@@ -134,6 +135,13 @@ int delete_context(struct pdp_t *pdp)
 		ippool_freeip(ippool, (struct ippoolm_t *)pdp->peer);
 	else
 		SYS_ERR(DGGSN, LOGL_ERROR, 0, "Peer not defined!");
+
+	if (gtp_kernel_tunnel_del(pdp)) {
+		SYS_ERR(DGGSN, LOGL_ERROR, 0,
+			"Cannot delete tunnel from kernel: %s\n",
+			strerror(errno));
+	}
+
 	return 0;
 }
 
@@ -167,6 +175,11 @@ int create_context_ind(struct pdp_t *pdp)
 	pdp->ipif = tun;	/* TODO */
 	member->peer = pdp;
 
+	if (gtp_kernel_tunnel_add(pdp) < 0) {
+		sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+			"Cannot add tunnel to kernel: %s\n", strerror(errno));
+	}
+
 	gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ);
 	return 0;		/* Success */
 }
@@ -247,6 +260,8 @@ int main(int argc, char **argv)
 			printf("pidfile: %s\n", args_info.pidfile_arg);
 		if (args_info.statedir_arg)
 			printf("statedir: %s\n", args_info.statedir_arg);
+		if (args_info.gtpnl_arg)
+			printf("gtpnl: %s\n", args_info.gtpnl_arg);
 		printf("timelimit: %d\n", args_info.timelimit_arg);
 	}
 
@@ -307,6 +322,8 @@ int main(int argc, char **argv)
 			printf("pidfile: %s\n", args_info.pidfile_arg);
 		if (args_info.statedir_arg)
 			printf("statedir: %s\n", args_info.statedir_arg);
+		if (args_info.gtpnl_arg)
+			printf("gtpnl: %s\n", args_info.gtpnl_arg);
 		printf("timelimit: %d\n", args_info.timelimit_arg);
 	}
 
@@ -502,10 +519,18 @@ int main(int argc, char **argv)
 	if (gsn->fd1u > maxfd)
 		maxfd = gsn->fd1u;
 
+	/* use GTP kernel module for data packet encapsulation */
+	if (gtp_kernel_init(gsn, &net, &mask, &args_info) < 0)
+		goto err;
+
 	gtp_set_cb_data_ind(gsn, encaps_tun);
 	gtp_set_cb_delete_context(gsn, delete_context);
 	gtp_set_cb_create_context_ind(gsn, create_context_ind);
 
+	/* skip the configuration of the tun0 if we're using the gtp0 device */
+	if (gtp_kernel_enabled())
+		goto skip_tun;
+
 	/* Create a tunnel interface */
 	DEBUGP(DGGSN, "Creating tun interface\n");
 	if (tun_new((struct tun_t **)&tun)) {
@@ -526,6 +551,8 @@ int main(int argc, char **argv)
 	if (ipup)
 		tun_runscript(tun, ipup);
 
+skip_tun:
+
   /******************************************************************/
 	/* Main select loop                                               */
   /******************************************************************/
@@ -556,7 +583,7 @@ int main(int argc, char **argv)
 			break;
 		}
 
-		if (tun->fd != -1 && FD_ISSET(tun->fd, &fds) &&
+		if (tun && tun->fd != -1 && FD_ISSET(tun->fd, &fds) &&
 		    tun_decaps(tun) < 0) {
 			SYS_ERR(DGGSN, LOGL_ERROR, 0,
 				"TUN read failed (fd)=(%d)", tun->fd);
@@ -572,11 +599,13 @@ int main(int argc, char **argv)
 			gtp_decaps1u(gsn);
 
 	}
-
+err:
+	gtp_kernel_stop();
 	cmdline_parser_free(&args_info);
 	ippool_free(ippool);
 	gtp_free(gsn);
-	tun_free(tun);
+	if (tun)
+		tun_free(tun);
 
 	return 1;
 
diff --git a/ggsn/gtp-kernel.c b/ggsn/gtp-kernel.c
new file mode 100644
index 0000000..16e51ac
--- /dev/null
+++ b/ggsn/gtp-kernel.c
@@ -0,0 +1,240 @@
+#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 <syslog.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.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 "cmdline.h"
+
+#include <libgtpnl/gtp.h>
+#include <libgtpnl/gtpnl.h>
+#include <libmnl/libmnl.h>
+
+#include "gtp-kernel.h"
+
+static void pdp_debug(struct pdp_t *pdp)
+{
+	int i;
+	uint64_t teid;
+
+	if (!debug)
+		return;
+
+	printf("version %u\n", pdp->version);
+	if (pdp->version == 0) {
+		teid = pdp_gettid(pdp->imsi, pdp->nsapi);
+		printf("flowid %u\n", pdp->flru);
+	} else {
+		teid = pdp->teid_gn; /* GTPIE_TEI_DI */
+	}
+
+	printf("teid %llx\n", teid);
+	printf("address (%u)\n", pdp->eua.l);
+
+	/* Byte 0: 0xf1 == IETF */
+	/* Byte 1: 0x21 == IPv4 */
+	/* Byte 2-6: IPv4 address */
+
+	for (i = 0; i < 6; i++)
+		printf("%x ", pdp->eua.v[i] & 0xff); /* GTPIE_EUA */
+
+	printf("\n");
+	printf("sgsn-addr (%u)\n", pdp->gsnrc.l);
+
+	for (i = 0; i < 4; i++)
+		printf("%x ", pdp->gsnrc.v[i] & 0xff); /* GTPIE_GSN_ADDR */
+
+	printf("\n");
+}
+
+static int mask2prefix(struct in_addr *mask)
+{
+	uint32_t tmp = ntohl(mask->s_addr);
+	int k;
+
+	for (k=0; tmp > 0; k++)
+		tmp = (tmp << 1);
+
+	return k;
+}
+
+static struct {
+	int			genl_id;
+	struct mnl_socket	*nl;
+	bool			enabled;
+} gtp_nl;
+
+/* 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,
+		    struct in_addr *mask,
+		    struct gengetopt_args_info *args_info)
+{
+	if (!args_info->gtpnl_given)
+		return 0;
+
+	if (gtp_dev_create(GTP_DEVNAME, args_info->gtpnl_orig,
+			   gsn->fd0, gsn->fd1u) < 0) {
+		sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+			"cannot create GTP tunnel device: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	gtp_nl.enabled = true;
+
+	gtp_nl.nl = genl_socket_open();
+	if (gtp_nl.nl == NULL) {
+		sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+			"cannot create genetlink socket\n");
+		return -1;
+	}
+	gtp_nl.genl_id = genl_lookup_family(gtp_nl.nl, "gtp");
+	if (gtp_nl.genl_id < 0) {
+		sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+			"cannot lookup GTP genetlink ID\n");
+		return -1;
+	}
+	if (debug) {
+		sys_err(LOG_NOTICE, __FILE__, __LINE__, 0,
+			"Using the GTP kernel mode (genl ID is %d)\n",
+			gtp_nl.genl_id);
+	}
+
+	if (debug) {
+		printf("Setting route to reach %s via %s\n",
+		       args_info->net_arg, GTP_DEVNAME);
+	}
+
+	if (gtp_dev_config(GTP_DEVNAME, net, mask2prefix(mask)) < 0) {
+		sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+			"Cannot add route to reach network %s\n",
+			args_info->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, GTP_DEVNAME, args_info->net_arg);
+		cmd[sizeof(cmd)-1] = '\0';
+
+		err = system(cmd);
+		if (err < 0) {
+			sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+				"Failed to launch script `%s'", ipup);
+			return -1;
+		}
+	}
+	sys_err(LOG_NOTICE, __FILE__, __LINE__, 0, "GTP kernel configured\n");
+
+	return 0;
+}
+
+void gtp_kernel_stop(void)
+{
+	if (!gtp_nl.enabled)
+		return;
+
+	gtp_dev_destroy(GTP_DEVNAME);
+}
+
+int gtp_kernel_tunnel_add(struct pdp_t *pdp)
+{
+	struct in_addr ms, sgsn;
+	struct gtp_tunnel *t;
+	int ret;
+
+	if (!gtp_nl.enabled)
+		return 0;
+
+	pdp_debug(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(GTP_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_tid(t, pdp->teid_gn); /* GTPIE_TEI_DI */
+	}
+
+	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)
+{
+	struct gtp_tunnel *t;
+	int ret;
+
+	if (!gtp_nl.enabled)
+		return 0;
+
+	pdp_debug(pdp);
+
+	t = gtp_tunnel_alloc();
+	if (t == NULL)
+		return -1;
+
+	gtp_tunnel_set_ifidx(t, if_nametoindex(GTP_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_tid(t, pdp->teid_gn); /* GTPIE_TEI_DI */
+	}
+
+	ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
+	gtp_tunnel_free(t);
+
+	return ret;
+}
+
+int gtp_kernel_enabled(void)
+{
+	return gtp_nl.enabled;
+}
diff --git a/ggsn/gtp-kernel.h b/ggsn/gtp-kernel.h
new file mode 100644
index 0000000..7bf533d
--- /dev/null
+++ b/ggsn/gtp-kernel.h
@@ -0,0 +1,51 @@
+#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, struct in_addr *net,
+		    struct in_addr *mask,
+		    struct gengetopt_args_info *args_info);
+void gtp_kernel_stop(void);
+
+int gtp_kernel_tunnel_add(struct pdp_t *pdp);
+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,
+				  struct in_addr *mask,
+				  struct gengetopt_args_info *args_info)
+{
+	if (args_info->gtpnl_given) {
+		sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+			"ggsn compiled without GTP kernel support!\n");
+		return -1;
+	}
+	return 0;
+}
+
+static inline void gtp_kernel_stop(void) {}
+
+static inline int gtp_kernel_tunnel_add(struct pdp_t *pdp)
+{
+	return 0;
+}
+
+static inline int gtp_kernel_tunnel_del(struct pdp_t *pdp)
+{
+	return 0;
+}
+
+static inline int gtp_kernel_enabled(void)
+{
+	return 0;
+}
+
+#endif
+#endif /* _GTP_KERNEL_H_ */
