Compare commits
49 Commits
Author | SHA1 | Date |
---|---|---|
Oliver Smith | a2dda133e4 | |
Harald Welte | 39e085f03e | |
Harald Welte | 9f46e04a23 | |
Oliver Smith | 1f8b868649 | |
Oliver Smith | c95db93512 | |
Oliver Smith | 170337196b | |
Oliver Smith | 7928152581 | |
Pablo Neira Ayuso | d489488a70 | |
Oliver Smith | 72ddb01219 | |
Pablo Neira Ayuso | 791a620e4d | |
Pablo Neira Ayuso | 64b5757043 | |
Pablo Neira Ayuso | 43b88cadbf | |
Pablo Neira Ayuso | 67e1fef97d | |
Pablo Neira Ayuso | 9911f6bfeb | |
Pablo Neira Ayuso | 38b5e239d6 | |
Oliver Smith | f3253354e3 | |
Oliver Smith | 4374964187 | |
Oliver Smith | 9c14b5060c | |
Oliver Smith | a295615229 | |
Oliver Smith | 717db098c7 | |
Oliver Smith | 2db5d2baf7 | |
Oliver Smith | 2121b82a61 | |
Oliver Smith | 0bd1e0d6eb | |
Oliver Smith | dd335ef8fc | |
Oliver Smith | 6db529f2da | |
Oliver Smith | b4e23a4fed | |
Pablo Neira Ayuso | 99a5c32546 | |
Oliver Smith | 0b272f256d | |
Pau Espin | 6af24bb93c | |
Oliver Smith | b59bc14f17 | |
Neels Hofmeyr | b8503c6537 | |
Pau Espin | dd3696f173 | |
Neels Hofmeyr | 50ae7eafd2 | |
Oliver Smith | 6954da78fb | |
Oliver Smith | 25d92af06a | |
Oliver Smith | 0535f30a37 | |
Pau Espin | 6e7f2f2aa3 | |
Neels Hofmeyr | 9fa76ec4d6 | |
Pau Espin Pedrol | 314cc32fce | |
Gabriel Ganne | 465b76dfca | |
Pau Espin | 118dd3ab17 | |
Oliver Smith | 5314ea43ac | |
Pau Espin | 102c81cf1b | |
Oliver Smith | 01b2d940a0 | |
Oliver Smith | 2f276eb3c6 | |
Pau Espin | fd3e98d334 | |
Pau Espin | 8639be5549 | |
Oliver Smith | d160a73a41 | |
Pau Espin | bc71674c67 |
|
@ -0,0 +1 @@
|
|||
open_collective: osmocom
|
|
@ -6,6 +6,7 @@
|
|||
.deps
|
||||
.libs
|
||||
.dirstamp
|
||||
*~
|
||||
|
||||
# Generated by autoconf/configure
|
||||
Makefile
|
||||
|
@ -31,3 +32,10 @@ debian/tmp
|
|||
debian/libgtpnl-dev
|
||||
debian/libgtpnl-dbg
|
||||
debian/libgtpnl0
|
||||
|
||||
contrib/libgtpnl.spec
|
||||
|
||||
tools/gtp-link
|
||||
tools/gtp-tunnel
|
||||
|
||||
tests/qemu/_*
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[gerrit]
|
||||
host=gerrit.osmocom.org
|
||||
project=libgtpnl
|
|
@ -1,2 +1,2 @@
|
|||
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_srcdir}/include ${LIBMNL_CFLAGS}
|
||||
AM_CFLAGS = ${regular_CFLAGS} ${GCC_FVISIBILITY_HIDDEN}
|
||||
AM_CPPFLAGS = ${CPPFLAGS} -I${top_srcdir}/include ${LIBMNL_CFLAGS}
|
||||
AM_CFLAGS = ${CFLAGS} ${GCC_FVISIBILITY_HIDDEN}
|
||||
|
|
|
@ -4,8 +4,12 @@ include $(top_srcdir)/Make_global.am
|
|||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = src include tools
|
||||
DIST_SUBDIRS = src include tools
|
||||
SUBDIRS = \
|
||||
include \
|
||||
src \
|
||||
tests \
|
||||
tools \
|
||||
$(NULL)
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libgtpnl.pc
|
||||
|
|
15
README.md
15
README.md
|
@ -1,11 +1,11 @@
|
|||
# libgtpnl - netlink library for Linux kernel GTP
|
||||
|
||||
In order to control the kernel-side GTP-U plane, a netlink based control
|
||||
interface between GTP-C in userspace and GTP-U in kernelspace was
|
||||
invented.
|
||||
In order to control the kernel-side GTP-U plane (`gtp` driver), a
|
||||
netlink based control interface between GTP-C in userspace and GTP-U in
|
||||
kernelspace was invented.
|
||||
|
||||
The encoding and decoding of these control messages is implemented in
|
||||
the libgtpnl (library for GTP netlink).
|
||||
this *libgtpnl* (library for GTP netlink).
|
||||
|
||||
libgtpnl is part of the [Osmocom](https://osmocom.org/) Open Source
|
||||
Mobile Communications project.
|
||||
|
@ -13,16 +13,17 @@ Mobile Communications project.
|
|||
## Homepage
|
||||
|
||||
The official homepage of the project is
|
||||
<https://osmocom.org/projects/libgtpnl/wiki/>
|
||||
<https://osmocom.org/projects/linux-kernel-gtp-u/wiki/Libgtpnl>
|
||||
|
||||
GIT Repository
|
||||
--------------
|
||||
|
||||
You can clone from the official libgtpnl.git repository using
|
||||
|
||||
git clone git://git.osmocom.org/libgtpnl.git
|
||||
git clone https://gitea.osmocom.org/cellular-infrastructure/libgtpnl
|
||||
|
||||
There is a cgit interface at <http://git.osmocom.org/libgtpnl/>
|
||||
Visiting the URL in a browser shows a
|
||||
[web interface](https://gitea.osmocom.org/cellular-infrastructure/libgtpnl).
|
||||
|
||||
Mailing List
|
||||
------------
|
||||
|
|
60
configure.ac
60
configure.ac
|
@ -9,10 +9,17 @@ AC_CONFIG_MACRO_DIR([m4])
|
|||
AC_CONFIG_HEADERS([config.h])
|
||||
AM_INIT_AUTOMAKE([foreign tar-pax no-dist-gzip dist-bzip2 1.6 subdir-objects])
|
||||
|
||||
CPPFLAGS="$CPPFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT"
|
||||
CFLAGS="$CFLAGS -Wall -Waggregate-return -Wmissing-declarations \
|
||||
-Wmissing-prototypes -Wshadow -Wstrict-prototypes \
|
||||
-Wformat=2 -pipe"
|
||||
|
||||
dnl include release helper
|
||||
RELMAKE='-include osmo-release.mk'
|
||||
AC_SUBST([RELMAKE])
|
||||
|
||||
CFLAGS="$CFLAGS -std=gnu11"
|
||||
|
||||
dnl kernel style compile messages
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
|
@ -46,11 +53,48 @@ then
|
|||
CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
|
||||
fi
|
||||
|
||||
regular_CPPFLAGS="-D_FILE_OFFSET_BITS=64 -D_REENTRANT"
|
||||
regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
|
||||
-Wmissing-prototypes -Wshadow -Wstrict-prototypes \
|
||||
-Wformat=2 -pipe"
|
||||
AC_SUBST([regular_CPPFLAGS])
|
||||
AC_SUBST([regular_CFLAGS])
|
||||
AC_CONFIG_FILES([Makefile src/Makefile include/Makefile include/libgtpnl/Makefile include/linux/Makefile tools/Makefile libgtpnl.pc])
|
||||
AC_OUTPUT
|
||||
AC_ARG_ENABLE(werror,
|
||||
[AS_HELP_STRING(
|
||||
[--enable-werror],
|
||||
[Turn all compiler warnings into errors, with exceptions:
|
||||
a) deprecation (allow upstream to mark deprecation without breaking builds);
|
||||
b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds)
|
||||
]
|
||||
)],
|
||||
[werror=$enableval], [werror="no"])
|
||||
if test x"$werror" = x"yes"
|
||||
then
|
||||
WERROR_FLAGS="-Werror"
|
||||
WERROR_FLAGS+=" -Werror=implicit-int -Werror=int-conversion -Werror=old-style-definition"
|
||||
WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
|
||||
WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
|
||||
CFLAGS="$CFLAGS $WERROR_FLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(qemu_tests,
|
||||
[AS_HELP_STRING(
|
||||
[--enable-qemu-tests],
|
||||
[Run automated tests in QEMU]
|
||||
)],
|
||||
[qemu_tests=$enableval], [qemu_tests="no"])
|
||||
AC_MSG_CHECKING([whether to enable QEMU tests])
|
||||
AC_MSG_RESULT([$qemu_tests])
|
||||
AM_CONDITIONAL(ENABLE_QEMU_TESTS, test x"$qemu_tests" = x"yes")
|
||||
if test x"$qemu_tests" = x"yes" && ! $srcdir/tests/qemu/check-depends.sh; then
|
||||
AC_MSG_ERROR([missing programs for --enable-qemu-tests])
|
||||
fi
|
||||
|
||||
AC_SUBST([CPPFLAGS])
|
||||
AC_SUBST([CFLAGS])
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
include/Makefile
|
||||
include/libgtpnl/Makefile
|
||||
include/linux/Makefile
|
||||
libgtpnl.pc
|
||||
src/Makefile
|
||||
tests/Makefile
|
||||
tools/Makefile
|
||||
])
|
||||
AC_OUTPUT()
|
||||
|
|
|
@ -7,6 +7,7 @@ osmo-clean-workspace.sh
|
|||
autoreconf --install --force
|
||||
./configure --enable-sanitize CFLAGS="-Werror" CPPFLAGS="-Werror"
|
||||
$MAKE $PARALLEL_MAKE
|
||||
$MAKE distcheck
|
||||
$MAKE $PARALLEL_MAKE distcheck
|
||||
$MAKE $PARALLEL_MAKE maintainer-clean
|
||||
|
||||
osmo-clean-workspace.sh
|
||||
|
|
|
@ -1,3 +1,56 @@
|
|||
libgtpnl (1.2.5) unstable; urgency=medium
|
||||
|
||||
[ Neels Janosch Hofmeyr ]
|
||||
* fix memleak on del_tunnel() failure
|
||||
|
||||
[ Oliver Smith ]
|
||||
* debian: set compat level to 10
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 12 Sep 2023 14:18:53 +0200
|
||||
|
||||
libgtpnl (1.2.4) unstable; urgency=medium
|
||||
|
||||
[ Oliver Smith ]
|
||||
* README: fix link to homepage
|
||||
* tools/gtp-tunnel: fix del usage
|
||||
* tools/gtp-link: add --sgsn to usage
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 07 Feb 2023 14:07:11 +0100
|
||||
|
||||
libgtpnl (1.2.3) unstable; urgency=medium
|
||||
|
||||
[ Neels Hofmeyr ]
|
||||
* fix some cases of rc == 0 on error
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Tue, 28 Jun 2022 16:13:45 +0200
|
||||
|
||||
libgtpnl (1.2.2) unstable; urgency=medium
|
||||
|
||||
[ Oliver Smith ]
|
||||
* contrib: import RPM spec
|
||||
* contrib: integrate RPM spec
|
||||
* configure.ac: set -std=gnu11
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* Enable parallel make in make distcheck
|
||||
* .gitignore: Ignore new autofoo tmp files
|
||||
|
||||
[ Gabriel Ganne ]
|
||||
* install gtp-tunnel and gtp-link tools
|
||||
|
||||
-- Pau Espin Pedrol <pespin@espeweb.net> Tue, 23 Feb 2021 12:52:08 +0100
|
||||
|
||||
libgtpnl (1.2.1) unstable; urgency=medium
|
||||
|
||||
[ Pau Espin Pedrol ]
|
||||
* debian/rules: Don't overwrite .tarball-version
|
||||
* debian: Adapt package name to lib's current major version
|
||||
|
||||
[ Oliver Smith ]
|
||||
* contrib/jenkins.sh: run "make maintainer-clean"
|
||||
|
||||
-- Pau Espin Pedrol <pespin@sysmocom.de> Wed, 07 Aug 2019 12:29:04 +0200
|
||||
|
||||
libgtpnl (1.2.0) unstable; urgency=medium
|
||||
|
||||
* Fix CTRL_ATTR_FAMILY_ID attribute size
|
||||
|
|
|
@ -1 +1 @@
|
|||
9
|
||||
10
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
Source: libgtpnl
|
||||
Maintainer: Harald Welte <laforge@gnumonks.org>
|
||||
Maintainer: Osmocom team <openbsc@lists.osmocom.org>
|
||||
Section: libs
|
||||
Priority: optional
|
||||
Build-Depends: debhelper (>= 9),
|
||||
Build-Depends: debhelper (>= 10),
|
||||
autotools-dev,
|
||||
autoconf,
|
||||
automake,
|
||||
|
@ -12,11 +12,11 @@ Build-Depends: debhelper (>= 9),
|
|||
pkg-config,
|
||||
libmnl-dev
|
||||
Standards-Version: 3.9.8
|
||||
Vcs-Git: git://git.osmocom.org/libgtpnl.git
|
||||
Vcs-Browser: http://git.osmocom.org/gitweb?p=libgtpnl.git;a=summary
|
||||
Homepage: https://projects.osmocom.org/projects/openggsn
|
||||
Vcs-Git: https://gitea.osmocom.org/cellular-infrastructure/libgtpnl
|
||||
Vcs-Browser: https://gitea.osmocom.org/cellular-infrastructure/libgtpnl
|
||||
Homepage: https://osmocom.org/projects/linux-kernel-gtp-u/wiki/Libgtpnl
|
||||
|
||||
Package: libgtpnl1
|
||||
Package: libgtpnl0
|
||||
Section: libs
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
|
@ -29,7 +29,7 @@ Architecture: any
|
|||
Multi-Arch: same
|
||||
Section: libdevel
|
||||
Depends: libmnl-dev,
|
||||
libgtpnl1 (= ${binary:Version}),
|
||||
libgtpnl0 (= ${binary:Version}),
|
||||
${misc:Depends}
|
||||
Description: Development headers for Linux kernel GTP-U netlink library
|
||||
The header files provided by this package may be used to develop
|
||||
|
@ -40,6 +40,15 @@ Architecture: any
|
|||
Multi-Arch: same
|
||||
Section: debug
|
||||
Priority: extra
|
||||
Depends: libgtpnl1 (= ${binary:Version}),
|
||||
Depends: libgtpnl0 (= ${binary:Version}),
|
||||
${misc:Depends}
|
||||
Description: Debug symbols for Linux kernel GTP-U netlink library
|
||||
|
||||
Package: libgtpnl-tools
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Section: net
|
||||
Priority: extra
|
||||
Depends: libgtpnl0 (= ${binary:Version}),
|
||||
${misc:Depends}
|
||||
Description: Tools to manage gtp interfaces and tunnels.
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
/usr/bin/gtp-link
|
||||
/usr/bin/gtp-tunnel
|
|
@ -24,7 +24,3 @@ override_dh_install:
|
|||
# Print test results in case of a failure
|
||||
override_dh_auto_test:
|
||||
dh_auto_test || (find . -name testsuite.log -exec cat {} \; ; false)
|
||||
|
||||
override_dh_autoreconf:
|
||||
echo $(VERSION) > .tarball-version
|
||||
dh_autoreconf
|
||||
|
|
|
@ -11,8 +11,11 @@ void gtp_tunnel_free(struct gtp_tunnel *t);
|
|||
|
||||
void gtp_tunnel_set_ifns(struct gtp_tunnel *t, int ifns);
|
||||
void gtp_tunnel_set_ifidx(struct gtp_tunnel *t, uint32_t ifidx);
|
||||
void gtp_tunnel_set_family(struct gtp_tunnel *t, uint16_t family);
|
||||
void gtp_tunnel_set_ms_ip4(struct gtp_tunnel *t, struct in_addr *ms_addr);
|
||||
void gtp_tunnel_set_sgsn_ip4(struct gtp_tunnel *t, struct in_addr *sgsn_addr);
|
||||
void gtp_tunnel_set_ms_ip6(struct gtp_tunnel *t, const struct in6_addr *ms_addr);
|
||||
void gtp_tunnel_set_sgsn_ip6(struct gtp_tunnel *t, const struct in6_addr *sgsn_addr);
|
||||
void gtp_tunnel_set_version(struct gtp_tunnel *t, uint32_t version);
|
||||
void gtp_tunnel_set_tid(struct gtp_tunnel *t, uint64_t tid);
|
||||
void gtp_tunnel_set_i_tei(struct gtp_tunnel *t, uint32_t i_tei);
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
#ifndef _UAPI_LINUX_GTP_H_
|
||||
#define _UAPI_LINUX_GTP_H__
|
||||
#define _UAPI_LINUX_GTP_H_
|
||||
|
||||
#define GTP_GENL_MCGRP_NAME "gtp"
|
||||
|
||||
enum gtp_genl_cmds {
|
||||
GTP_CMD_NEWPDP,
|
||||
GTP_CMD_DELPDP,
|
||||
GTP_CMD_GETPDP,
|
||||
GTP_CMD_ECHOREQ,
|
||||
|
||||
GTP_CMD_MAX,
|
||||
};
|
||||
|
@ -19,15 +23,19 @@ enum gtp_attrs {
|
|||
GTPA_LINK,
|
||||
GTPA_VERSION,
|
||||
GTPA_TID, /* for GTPv0 only */
|
||||
GTPA_PEER_ADDRESS,
|
||||
GTPA_PEER_ADDRESS, /* Remote GSN peer, either SGSN or GGSN */
|
||||
#define GTPA_SGSN_ADDRESS GTPA_PEER_ADDRESS /* maintain legacy attr name */
|
||||
GTPA_MS_ADDRESS,
|
||||
GTPA_FLOW,
|
||||
GTPA_NET_NS_FD,
|
||||
GTPA_I_TEI, /* for GTPv1 only */
|
||||
GTPA_O_TEI, /* for GTPv1 only */
|
||||
GTPA_PAD,
|
||||
GTPA_PEER_ADDR6,
|
||||
GTPA_MS_ADDR6,
|
||||
GTPA_FAMILY,
|
||||
__GTPA_MAX,
|
||||
};
|
||||
#define GTPA_MAX (__GTPA_MAX + 1)
|
||||
#define GTPA_MAX (__GTPA_MAX - 1)
|
||||
|
||||
#endif /* _UAPI_LINUX_GTP_H_ */
|
||||
|
|
|
@ -2,7 +2,7 @@ include $(top_srcdir)/Make_global.am
|
|||
|
||||
# This is _NOT_ the library release version, it's an API version.
|
||||
# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
|
||||
LIBVERSION=1:1:1
|
||||
LIBVERSION=1:2:1
|
||||
|
||||
|
||||
lib_LTLIBRARIES = libgtpnl.la
|
||||
|
|
155
src/gtp-genl.c
155
src/gtp-genl.c
|
@ -44,20 +44,55 @@
|
|||
|
||||
static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t)
|
||||
{
|
||||
mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version);
|
||||
if (t->ifns >= 0)
|
||||
if (t->flags & GTP_TUN_FAMILY)
|
||||
mnl_attr_put_u8(nlh, GTPA_FAMILY, t->ms_addr.family);
|
||||
if (t->flags & GTP_TUN_VERSION)
|
||||
mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version);
|
||||
if (t->flags & GTP_TUN_IFNS)
|
||||
mnl_attr_put_u32(nlh, GTPA_NET_NS_FD, t->ifns);
|
||||
mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx);
|
||||
if (t->sgsn_addr.s_addr)
|
||||
mnl_attr_put_u32(nlh, GTPA_PEER_ADDRESS, t->sgsn_addr.s_addr);
|
||||
if (t->ms_addr.s_addr)
|
||||
mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.s_addr);
|
||||
if (t->gtp_version == GTP_V0) {
|
||||
mnl_attr_put_u64(nlh, GTPA_TID, t->u.v0.tid);
|
||||
mnl_attr_put_u16(nlh, GTPA_FLOW, t->u.v0.flowid);
|
||||
} else if (t->gtp_version == GTP_V1) {
|
||||
mnl_attr_put_u32(nlh, GTPA_I_TEI, t->u.v1.i_tei);
|
||||
mnl_attr_put_u32(nlh, GTPA_O_TEI, t->u.v1.o_tei);
|
||||
if (t->flags & GTP_TUN_IFIDX)
|
||||
mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx);
|
||||
|
||||
if (t->flags & GTP_TUN_MS_ADDR) {
|
||||
switch (t->ms_addr.family) {
|
||||
case AF_INET:
|
||||
mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.ip4.s_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
mnl_attr_put(nlh, GTPA_MS_ADDR6, sizeof(t->ms_addr.ip6), &t->ms_addr.ip6);
|
||||
break;
|
||||
default:
|
||||
/* No addr is set when deleting a tunnel */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (t->flags & GTP_TUN_SGSN_ADDR) {
|
||||
switch (t->sgsn_addr.family) {
|
||||
case AF_INET:
|
||||
mnl_attr_put_u32(nlh, GTPA_PEER_ADDRESS, t->sgsn_addr.ip4.s_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
mnl_attr_put(nlh, GTPA_PEER_ADDR6, sizeof(t->sgsn_addr.ip6), &t->sgsn_addr.ip6);
|
||||
break;
|
||||
default:
|
||||
/* No addr is set when deleting a tunnel */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (t->flags & GTP_TUN_VERSION) {
|
||||
if (t->gtp_version == GTP_V0) {
|
||||
if (t->flags & GTP_TUN_V0_TID)
|
||||
mnl_attr_put_u64(nlh, GTPA_TID, t->u.v0.tid);
|
||||
if (t->flags & GTP_TUN_V0_FLOWID)
|
||||
mnl_attr_put_u16(nlh, GTPA_FLOW, t->u.v0.flowid);
|
||||
} else if (t->gtp_version == GTP_V1) {
|
||||
if (t->flags & GTP_TUN_V1_I_TEI)
|
||||
mnl_attr_put_u32(nlh, GTPA_I_TEI, t->u.v1.i_tei);
|
||||
if (t->flags & GTP_TUN_V1_O_TEI)
|
||||
mnl_attr_put_u32(nlh, GTPA_O_TEI, t->u.v1.o_tei);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,8 +112,10 @@ int gtp_add_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t)
|
|||
GTP_CMD_NEWPDP);
|
||||
gtp_build_payload(nlh, t);
|
||||
|
||||
if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0)
|
||||
if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0) {
|
||||
perror("genl_socket_talk");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -94,14 +131,17 @@ int gtp_del_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t)
|
|||
GTP_CMD_DELPDP);
|
||||
gtp_build_payload(nlh, t);
|
||||
|
||||
if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0)
|
||||
if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0) {
|
||||
perror("genl_socket_talk");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_del_tunnel);
|
||||
|
||||
struct gtp_pdp {
|
||||
uint32_t ifidx;
|
||||
uint32_t version;
|
||||
union {
|
||||
struct {
|
||||
|
@ -112,8 +152,8 @@ struct gtp_pdp {
|
|||
uint32_t o_tei;
|
||||
} v1;
|
||||
} u;
|
||||
struct in_addr sgsn_addr;
|
||||
struct in_addr ms_addr;
|
||||
struct gtp_addr sgsn_addr;
|
||||
struct gtp_addr ms_addr;
|
||||
};
|
||||
|
||||
static int genl_gtp_validate_cb(const struct nlattr *attr, void *data)
|
||||
|
@ -125,6 +165,12 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data)
|
|||
return MNL_CB_OK;
|
||||
|
||||
switch(type) {
|
||||
case GTPA_FAMILY:
|
||||
if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
|
||||
perror("mnl_attr_validate");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
break;
|
||||
case GTPA_TID:
|
||||
if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
|
||||
perror("mnl_attr_validate");
|
||||
|
@ -136,11 +182,20 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data)
|
|||
case GTPA_PEER_ADDRESS:
|
||||
case GTPA_MS_ADDRESS:
|
||||
case GTPA_VERSION:
|
||||
case GTPA_LINK:
|
||||
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
|
||||
perror("mnl_attr_validate");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
break;
|
||||
case GTPA_PEER_ADDR6:
|
||||
case GTPA_MS_ADDR6:
|
||||
if (mnl_attr_validate2(attr, MNL_TYPE_BINARY,
|
||||
sizeof(struct in6_addr)) < 0) {
|
||||
perror("mnl_attr_validate");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -151,39 +206,65 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data)
|
|||
static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct nlattr *tb[GTPA_MAX + 1] = {};
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
struct gtp_pdp pdp = {};
|
||||
struct genlmsghdr *genl;
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*genl), genl_gtp_validate_cb, tb);
|
||||
|
||||
if (tb[GTPA_LINK])
|
||||
pdp.ifidx = mnl_attr_get_u32(tb[GTPA_LINK]);
|
||||
if (tb[GTPA_TID])
|
||||
pdp.u.v0.tid = mnl_attr_get_u64(tb[GTPA_TID]);
|
||||
if (tb[GTPA_I_TEI])
|
||||
pdp.u.v1.i_tei = mnl_attr_get_u32(tb[GTPA_I_TEI]);
|
||||
if (tb[GTPA_O_TEI])
|
||||
pdp.u.v1.o_tei = mnl_attr_get_u32(tb[GTPA_O_TEI]);
|
||||
|
||||
if (tb[GTPA_PEER_ADDRESS]) {
|
||||
pdp.sgsn_addr.s_addr =
|
||||
mnl_attr_get_u32(tb[GTPA_PEER_ADDRESS]);
|
||||
}
|
||||
if (tb[GTPA_MS_ADDRESS]) {
|
||||
pdp.ms_addr.s_addr = mnl_attr_get_u32(tb[GTPA_MS_ADDRESS]);
|
||||
}
|
||||
if (tb[GTPA_VERSION]) {
|
||||
pdp.version = mnl_attr_get_u32(tb[GTPA_VERSION]);
|
||||
pdp.sgsn_addr.family = AF_INET;
|
||||
pdp.sgsn_addr.ip4.s_addr = mnl_attr_get_u32(tb[GTPA_PEER_ADDRESS]);
|
||||
} else if (tb[GTPA_PEER_ADDR6]) {
|
||||
pdp.sgsn_addr.family = AF_INET6;
|
||||
memcpy(&pdp.sgsn_addr.ip6, mnl_attr_get_payload(tb[GTPA_PEER_ADDR6]),
|
||||
sizeof(struct in6_addr));
|
||||
} else {
|
||||
fprintf(stderr, "sgsn_addr: no IPv4 nor IPv6 set\n");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
printf("version %u ", pdp.version);
|
||||
if (pdp.version == GTP_V0) {
|
||||
inet_ntop(AF_INET, &pdp.ms_addr, buf, sizeof(buf));
|
||||
printf("tid %"PRIu64" ms_addr %s ",
|
||||
pdp.u.v0.tid, buf);
|
||||
} else if (pdp.version == GTP_V1) {
|
||||
inet_ntop(AF_INET, &pdp.ms_addr, buf, sizeof(buf));
|
||||
printf("tei %u/%u ms_addr %s ", pdp.u.v1.i_tei,
|
||||
pdp.u.v1.o_tei, buf);
|
||||
if (tb[GTPA_MS_ADDRESS]) {
|
||||
pdp.ms_addr.family = AF_INET;
|
||||
pdp.ms_addr.ip4.s_addr = mnl_attr_get_u32(tb[GTPA_MS_ADDRESS]);
|
||||
} else if (tb[GTPA_MS_ADDR6]) {
|
||||
pdp.ms_addr.family = AF_INET6;
|
||||
memcpy(&pdp.ms_addr.ip6, mnl_attr_get_payload(tb[GTPA_MS_ADDR6]), sizeof(struct in6_addr));
|
||||
} else {
|
||||
fprintf(stderr, "ms_addr: no IPv4 nor IPv6 set\n");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
inet_ntop(AF_INET, &pdp.sgsn_addr, buf, sizeof(buf));
|
||||
|
||||
if (tb[GTPA_FAMILY] && mnl_attr_get_u32(tb[GTPA_FAMILY]) != pdp.ms_addr.family) {
|
||||
fprintf(stderr, "ms_addr family does not match GTPA_FAMILY\n");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
printf("%s ", if_indextoname(pdp.ifidx, buf));
|
||||
|
||||
if (tb[GTPA_VERSION])
|
||||
pdp.version = mnl_attr_get_u32(tb[GTPA_VERSION]);
|
||||
|
||||
printf("version %u ", pdp.version);
|
||||
|
||||
if (pdp.version == GTP_V0)
|
||||
printf("tid %"PRIu64" ", pdp.u.v0.tid);
|
||||
else if (pdp.version == GTP_V1)
|
||||
printf("tei %u/%u ", pdp.u.v1.i_tei, pdp.u.v1.o_tei);
|
||||
|
||||
inet_ntop(pdp.ms_addr.family, &pdp.ms_addr.ip4, buf, sizeof(buf));
|
||||
printf("ms_addr %s ", buf);
|
||||
|
||||
inet_ntop(pdp.sgsn_addr.family, &pdp.sgsn_addr.ip4, buf, sizeof(buf));
|
||||
printf("sgsn_addr %s\n", buf);
|
||||
|
||||
return MNL_CB_OK;
|
||||
|
@ -200,7 +281,7 @@ int gtp_list_tunnel(int genl_id, struct mnl_socket *nl)
|
|||
|
||||
if (genl_socket_talk(nl, nlh, seq, genl_gtp_attr_cb, NULL) < 0) {
|
||||
perror("genl_socket_talk");
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
42
src/gtp.c
42
src/gtp.c
|
@ -49,54 +49,88 @@ EXPORT_SYMBOL(gtp_tunnel_free);
|
|||
void gtp_tunnel_set_ifns(struct gtp_tunnel *t, int ifns)
|
||||
{
|
||||
t->ifns = ifns;
|
||||
t->flags |= GTP_TUN_IFNS;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_ifns);
|
||||
|
||||
void gtp_tunnel_set_ifidx(struct gtp_tunnel *t, uint32_t ifidx)
|
||||
{
|
||||
t->ifidx = ifidx;
|
||||
t->flags |= GTP_TUN_IFIDX;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_ifidx);
|
||||
|
||||
void gtp_tunnel_set_family(struct gtp_tunnel *t, uint16_t family)
|
||||
{
|
||||
t->ms_addr.family = family;
|
||||
t->flags |= GTP_TUN_FAMILY;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_family);
|
||||
|
||||
void gtp_tunnel_set_ms_ip4(struct gtp_tunnel *t, struct in_addr *ms_addr)
|
||||
{
|
||||
t->ms_addr = *ms_addr;
|
||||
t->ms_addr.family = AF_INET;
|
||||
t->ms_addr.ip4 = *ms_addr;
|
||||
t->flags |= GTP_TUN_FAMILY | GTP_TUN_MS_ADDR;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_ms_ip4);
|
||||
|
||||
void gtp_tunnel_set_sgsn_ip4(struct gtp_tunnel *t, struct in_addr *sgsn_addr)
|
||||
{
|
||||
t->sgsn_addr = *sgsn_addr;
|
||||
t->sgsn_addr.family = AF_INET;
|
||||
t->sgsn_addr.ip4 = *sgsn_addr;
|
||||
t->flags |= GTP_TUN_SGSN_ADDR;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_sgsn_ip4);
|
||||
|
||||
void gtp_tunnel_set_ms_ip6(struct gtp_tunnel *t, const struct in6_addr *ms_addr)
|
||||
{
|
||||
t->ms_addr.family = AF_INET6;
|
||||
t->ms_addr.ip6 = *ms_addr;
|
||||
t->flags |= GTP_TUN_FAMILY | GTP_TUN_MS_ADDR;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_ms_ip6);
|
||||
|
||||
void gtp_tunnel_set_sgsn_ip6(struct gtp_tunnel *t, const struct in6_addr *sgsn_addr)
|
||||
{
|
||||
t->sgsn_addr.family = AF_INET6;
|
||||
t->sgsn_addr.ip6 = *sgsn_addr;
|
||||
t->flags |= GTP_TUN_SGSN_ADDR;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_sgsn_ip6);
|
||||
|
||||
void gtp_tunnel_set_version(struct gtp_tunnel *t, uint32_t version)
|
||||
{
|
||||
t->gtp_version = version;
|
||||
t->flags |= GTP_TUN_VERSION;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_version);
|
||||
|
||||
void gtp_tunnel_set_tid(struct gtp_tunnel *t, uint64_t tid)
|
||||
{
|
||||
t->u.v0.tid = tid;
|
||||
t->flags |= GTP_TUN_V0_TID;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_tid);
|
||||
|
||||
void gtp_tunnel_set_flowid(struct gtp_tunnel *t, uint16_t flowid)
|
||||
{
|
||||
t->u.v0.flowid = flowid;
|
||||
t->flags |= GTP_TUN_V0_FLOWID;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_flowid);
|
||||
|
||||
void gtp_tunnel_set_i_tei(struct gtp_tunnel *t, uint32_t i_tei)
|
||||
{
|
||||
t->u.v1.i_tei = i_tei;
|
||||
t->flags |= GTP_TUN_V1_I_TEI;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_i_tei);
|
||||
|
||||
void gtp_tunnel_set_o_tei(struct gtp_tunnel *t, uint32_t o_tei)
|
||||
{
|
||||
t->u.v1.o_tei = o_tei;
|
||||
t->flags |= GTP_TUN_V1_O_TEI;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_set_o_tei);
|
||||
|
||||
|
@ -114,13 +148,13 @@ EXPORT_SYMBOL(gtp_tunnel_get_ifidx);
|
|||
|
||||
const struct in_addr *gtp_tunnel_get_ms_ip4(struct gtp_tunnel *t)
|
||||
{
|
||||
return &t->ms_addr;
|
||||
return &t->ms_addr.ip4;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_get_ms_ip4);
|
||||
|
||||
const struct in_addr *gtp_tunnel_get_sgsn_ip4(struct gtp_tunnel *t)
|
||||
{
|
||||
return &t->sgsn_addr;
|
||||
return &t->sgsn_addr.ip4;
|
||||
}
|
||||
EXPORT_SYMBOL(gtp_tunnel_get_sgsn_ip4);
|
||||
|
||||
|
|
|
@ -12,11 +12,32 @@
|
|||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
struct gtp_addr {
|
||||
sa_family_t family;
|
||||
union {
|
||||
struct in_addr ip4;
|
||||
struct in6_addr ip6;
|
||||
};
|
||||
};
|
||||
|
||||
enum {
|
||||
GTP_TUN_IFNS = (1 << 0),
|
||||
GTP_TUN_IFIDX = (1 << 1),
|
||||
GTP_TUN_FAMILY = (1 << 2),
|
||||
GTP_TUN_MS_ADDR = (1 << 3),
|
||||
GTP_TUN_SGSN_ADDR = (1 << 4),
|
||||
GTP_TUN_VERSION = (1 << 5),
|
||||
GTP_TUN_V0_TID = (1 << 6),
|
||||
GTP_TUN_V0_FLOWID = (1 << 7),
|
||||
GTP_TUN_V1_I_TEI = (1 << 8),
|
||||
GTP_TUN_V1_O_TEI = (1 << 9),
|
||||
};
|
||||
|
||||
struct gtp_tunnel {
|
||||
int ifns;
|
||||
uint32_t ifidx;
|
||||
struct in_addr ms_addr;
|
||||
struct in_addr sgsn_addr;
|
||||
struct gtp_addr ms_addr;
|
||||
struct gtp_addr sgsn_addr;
|
||||
int gtp_version;
|
||||
union {
|
||||
struct {
|
||||
|
@ -28,6 +49,7 @@ struct gtp_tunnel {
|
|||
uint32_t o_tei;
|
||||
} v1;
|
||||
} u;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,3 +38,12 @@ global:
|
|||
|
||||
local: *;
|
||||
};
|
||||
|
||||
LIBGTPNL_1.1 {
|
||||
gtp_tunnel_set_ms_ip6;
|
||||
gtp_tunnel_set_sgsn_ip6;
|
||||
} LIBGTPNL_1.0;
|
||||
|
||||
LIBGTPNL_1.2 {
|
||||
gtp_tunnel_set_family;
|
||||
} LIBGTPNL_1.1;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
check-local:
|
||||
$(MAKE) qemu-tests
|
||||
|
||||
if ENABLE_QEMU_TESTS
|
||||
qemu-download-kernel:
|
||||
rm -f qemu/_linux
|
||||
wget -O qemu/_linux \
|
||||
https://jenkins.osmocom.org/jenkins/job/ttcn3-ggsn-test-kernel-latest-net-next/ws/_cache/kernel-test/linux
|
||||
qemu-tests:
|
||||
qemu/initrd-build.sh
|
||||
qemu/run-qemu.sh
|
||||
else
|
||||
qemu-tests:
|
||||
@echo "Not running QEMU tests (determined at configure-time)"
|
||||
endif
|
|
@ -0,0 +1,123 @@
|
|||
#!/bin/sh -ex
|
||||
|
||||
# Use ip from iproute2 instead of busybox ip, because iproute2's version has
|
||||
# "ip netns" implemented. Calling /bin/ip explicitly is needed here, otherwise
|
||||
# busybox sh will use busybox ip, regardless of PATH.
|
||||
alias ip="/bin/ip"
|
||||
alias ggsn_side="ip netns exec ggsn_side"
|
||||
|
||||
# MS - SGSN -gtp- GGSN - WEBSERVER
|
||||
tunnel_start() {
|
||||
test -n "$MS_PROTO"
|
||||
test -n "$MS"
|
||||
test -n "$MS_PREFLEN"
|
||||
test -n "$SGSN_GGSN_PROTO"
|
||||
test -n "$SGSN"
|
||||
test -n "$SGSN_PREFLEN"
|
||||
test -n "$GGSN"
|
||||
test -n "$WEBSERVER"
|
||||
|
||||
ip netns add ggsn_side
|
||||
|
||||
# SGSN side: prepare veth_sgsn (SGSN), lo (MS)
|
||||
ip link add veth_sgsn type veth peer name veth_ggsn
|
||||
ip addr add "$SGSN"/"$SGSN_PREFLEN" dev veth_sgsn
|
||||
ip link set veth_sgsn up
|
||||
ip addr add "$MS"/"$MS_PREFLEN" dev lo
|
||||
ip link set lo up
|
||||
|
||||
# SGSN side: prepare gtp-tunnel
|
||||
gtp-link add gtp_sgsn "$SGSN_GGSN_PROTO" --sgsn &
|
||||
sleep 1
|
||||
gtp-tunnel add gtp_sgsn v1 200 100 "$MS" "$GGSN"
|
||||
ip route add "$WEBSERVER"/"$MS_PREFLEN" dev gtp_sgsn
|
||||
|
||||
# GGSN side: prepare veth_ggsn (GGSN), lo (WEBSERVER)
|
||||
ip link set veth_ggsn netns ggsn_side
|
||||
ggsn_side ip addr add "$GGSN"/"$SGSN_PREFLEN" dev veth_ggsn
|
||||
ggsn_side ip link set veth_ggsn up
|
||||
ggsn_side ip addr add "$WEBSERVER"/"$MS_PREFLEN" dev lo
|
||||
ggsn_side ip link set lo up
|
||||
|
||||
# GGSN side: prepare gtp-tunnel
|
||||
ggsn_side gtp-link add gtp_ggsn "$SGSN_GGSN_PROTO" &
|
||||
sleep 1
|
||||
ggsn_side gtp-tunnel add gtp_ggsn v1 100 200 "$MS" "$SGSN"
|
||||
ggsn_side ip route add "$MS"/"$MS_PREFLEN" dev gtp_ggsn
|
||||
|
||||
# List tunnel from both sides
|
||||
gtp-tunnel list
|
||||
ggsn_side gtp-tunnel list
|
||||
}
|
||||
|
||||
# Add a second tunnel to test MS with IPv4v6
|
||||
tunnel_start_2() {
|
||||
test -n "$MS2_PROTO"
|
||||
test -n "$MS2"
|
||||
test -n "$MS2_PREFLEN"
|
||||
test -n "$WEBSERVER2"
|
||||
|
||||
# SGSN side: add second IP to lo (MS)
|
||||
ip addr add "$MS2"/"$MS2_PREFLEN" dev lo
|
||||
|
||||
# SGSN side: prepare second gtp-tunnel
|
||||
gtp-tunnel add gtp_sgsn v1 200 100 "$MS2" "$GGSN"
|
||||
ip route add "$WEBSERVER2"/"$MS2_PREFLEN" dev gtp_sgsn
|
||||
|
||||
# GGSN side: add second IP to lo (WEBSERVER)
|
||||
ggsn_side ip addr add "$WEBSERVER2"/"$MS2_PREFLEN" dev lo
|
||||
|
||||
# GGSN side: prepare second gtp-tunnel
|
||||
ggsn_side gtp-tunnel add gtp_ggsn v1 100 200 "$MS2" "$SGSN"
|
||||
ggsn_side ip route add "$MS2"/"$MS2_PREFLEN" dev gtp_ggsn
|
||||
|
||||
# List tunnels from both sides
|
||||
gtp-tunnel list
|
||||
ggsn_side gtp-tunnel list
|
||||
}
|
||||
|
||||
tunnel_ping() {
|
||||
ip addr show
|
||||
ping -c 1 "$WEBSERVER"
|
||||
ggsn_side ping -c 1 "$MS"
|
||||
|
||||
if [ -n "$MS2" ]; then
|
||||
ping -c 1 "$WEBSERVER2"
|
||||
ggsn_side ping -c 1 "$MS2"
|
||||
fi
|
||||
}
|
||||
|
||||
tunnel_stop() {
|
||||
killall gtp-link
|
||||
|
||||
ip addr del "$MS"/"$MS_PREFLEN" dev lo
|
||||
|
||||
if [ -n "$MS2" ]; then
|
||||
ip addr del "$MS2"/"$MS2_PREFLEN" dev lo
|
||||
fi
|
||||
|
||||
ip link set veth_sgsn down
|
||||
|
||||
if [ "$SGSN_GGSN_PROTO" == "ip" ]; then # FIXME: doesn't work with ip6
|
||||
ip addr del "$SGSN"/"$SGSN_PREFLEN" dev veth_sgsn
|
||||
fi
|
||||
|
||||
ip link del veth_sgsn
|
||||
ip route del "$WEBSERVER"/"$MS_PREFLEN" dev gtp_sgsn
|
||||
gtp-tunnel delete gtp_sgsn v1 200 "$MS_PROTO"
|
||||
|
||||
if [ -n "$MS2" ]; then
|
||||
ip route del "$WEBSERVER2"/"$MS2_PREFLEN" dev gtp_sgsn
|
||||
gtp-tunnel delete gtp_sgsn v1 200 "$MS2_PROTO"
|
||||
fi
|
||||
|
||||
gtp-link del gtp_sgsn
|
||||
ggsn_side gtp-tunnel delete gtp_ggsn v1 100 "$MS_PROTO"
|
||||
|
||||
if [ -n "$MS2" ]; then
|
||||
ggsn_side gtp-tunnel delete gtp_ggsn v1 100 "$MS2_PROTO"
|
||||
fi
|
||||
|
||||
ggsn_side gtp-link del gtp_ggsn
|
||||
ip netns del ggsn_side
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh -ex
|
||||
. /tests/00_test_functions.sh
|
||||
|
||||
MS_PROTO="ip"
|
||||
MS="172.99.0.1"
|
||||
MS_PREFLEN="32"
|
||||
SGSN_GGSN_PROTO="ip"
|
||||
SGSN="172.0.0.1"
|
||||
SGSN_PREFLEN="24"
|
||||
GGSN="172.0.0.2"
|
||||
WEBSERVER="172.99.0.2"
|
||||
|
||||
tunnel_start
|
||||
tunnel_ping
|
||||
tunnel_stop
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh -ex
|
||||
. /tests/00_test_functions.sh
|
||||
|
||||
MS_PROTO="ip"
|
||||
MS="172.99.0.1"
|
||||
MS_PREFLEN="32"
|
||||
SGSN_GGSN_PROTO="ip6"
|
||||
SGSN="fd00::1"
|
||||
SGSN_PREFLEN="7"
|
||||
GGSN="fd00::2"
|
||||
WEBSERVER="172.99.0.2"
|
||||
|
||||
tunnel_start
|
||||
tunnel_ping
|
||||
tunnel_stop
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh -ex
|
||||
. /tests/00_test_functions.sh
|
||||
|
||||
MS_PROTO="ip6"
|
||||
MS="fd00::"
|
||||
MS_PREFLEN="64"
|
||||
SGSN_GGSN_PROTO="ip"
|
||||
SGSN="172.0.0.1"
|
||||
SGSN_PREFLEN="24"
|
||||
GGSN="172.0.0.2"
|
||||
WEBSERVER="fe00::2"
|
||||
|
||||
tunnel_start
|
||||
tunnel_ping
|
||||
tunnel_stop
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh -ex
|
||||
. /tests/00_test_functions.sh
|
||||
|
||||
MS_PROTO="ip6"
|
||||
MS="fc00::"
|
||||
MS_PREFLEN="64"
|
||||
SGSN_GGSN_PROTO="ip6"
|
||||
SGSN="fd00::1"
|
||||
SGSN_PREFLEN="7"
|
||||
GGSN="fd00::2"
|
||||
WEBSERVER="fe00::2"
|
||||
|
||||
tunnel_start
|
||||
tunnel_ping
|
||||
tunnel_stop
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/sh -ex
|
||||
. /tests/00_test_functions.sh
|
||||
|
||||
MS_PROTO="ip"
|
||||
MS="172.99.0.1"
|
||||
MS_PREFLEN="32"
|
||||
SGSN_GGSN_PROTO="ip"
|
||||
SGSN="172.0.0.1"
|
||||
SGSN_PREFLEN="24"
|
||||
GGSN="172.0.0.2"
|
||||
WEBSERVER="172.99.0.2"
|
||||
|
||||
tunnel_start
|
||||
|
||||
MS2_PROTO="ip6"
|
||||
MS2="fd00::"
|
||||
MS2_PREFLEN="64"
|
||||
WEBSERVER2="fe00::2"
|
||||
|
||||
tunnel_start_2
|
||||
tunnel_ping
|
||||
tunnel_stop
|
|
@ -0,0 +1,36 @@
|
|||
# QEMU tests for libgtpnl
|
||||
|
||||
The tests simulate how a GGSN would use libgtpnl, to set up a GTP tunnel
|
||||
between SGSN and GGSN, so a MS on the SGSN side can talk to a webserver on the
|
||||
GGSN side.
|
||||
|
||||
## Running the tests
|
||||
|
||||
```
|
||||
$ autoreconf -fi
|
||||
$ ./configure --enable-qemu-tests
|
||||
$ make
|
||||
$ make -C tests qemu-download-kernel # or build your own, see below
|
||||
$ make check
|
||||
```
|
||||
|
||||
## Building your own kernel
|
||||
|
||||
Clone a kernel tree, then:
|
||||
```
|
||||
$ make defconfig
|
||||
$ make menuconfig
|
||||
```
|
||||
|
||||
Set the following options:
|
||||
```
|
||||
CONFIG_GTP=y
|
||||
CONFIG_NET_NS=y
|
||||
CONFIG_VETH=y
|
||||
```
|
||||
|
||||
Build the kernel and copy it to the tests dir:
|
||||
```
|
||||
$ make -j$(nproc)
|
||||
$ cp arch/x86/boot/bzImage /path/to/libgtpnl/tests/qemu/_linux
|
||||
```
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
RET=0
|
||||
|
||||
require_program() {
|
||||
if [ -z "$(command -v "$1")" ]; then
|
||||
RET=1
|
||||
echo "ERROR: missing program: $1"
|
||||
fi
|
||||
}
|
||||
|
||||
require_program busybox
|
||||
require_program cpio
|
||||
require_program find
|
||||
require_program gzip
|
||||
require_program ip
|
||||
require_program lddtree
|
||||
require_program qemu-system-x86_64
|
||||
|
||||
exit "$RET"
|
|
@ -0,0 +1,110 @@
|
|||
#!/bin/sh -e
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
DIR_INITRD="$DIR/_initrd"
|
||||
SRC_LIBS="$(realpath "$DIR/../../src/.libs/")"
|
||||
TOOLS_LIBS="$(realpath "$DIR/../../tools/.libs/")"
|
||||
|
||||
# Add one or more files to the initramfs, with parent directories.
|
||||
# usr-merge: resolve symlinks for /lib -> /usr/lib etc. so "cp --parents" does
|
||||
# not fail with "cp: cannot make directory '/tmp/initrd/lib': File exists"
|
||||
# $@: path to files
|
||||
initrd_add_file() {
|
||||
local i
|
||||
|
||||
for i in "$@"; do
|
||||
case "$i" in
|
||||
/bin/*|/sbin/*|/lib/*|/lib64/*)
|
||||
cp -a --parents "$i" "$DIR_INITRD"/usr
|
||||
;;
|
||||
*)
|
||||
cp -a --parents "$i" "$DIR_INITRD"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Add binaries with depending libraries
|
||||
# $@: paths to binaries
|
||||
initrd_add_bin() {
|
||||
local bin
|
||||
local bin_path
|
||||
local file
|
||||
|
||||
for bin in "$@"; do
|
||||
local bin_path="$(which "$bin")"
|
||||
if [ -z "$bin_path" ]; then
|
||||
echo "ERROR: file not found: $bin"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
lddtree_out="$(lddtree -l "$bin_path")"
|
||||
if [ -z "$lddtree_out" ]; then
|
||||
echo "ERROR: lddtree failed on '$bin_path'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for file in $lddtree_out; do
|
||||
initrd_add_file "$file"
|
||||
|
||||
# Copy resolved symlink
|
||||
if [ -L "$file" ]; then
|
||||
initrd_add_file "$(realpath "$file")"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# Add command to run inside the initramfs
|
||||
# $@: commands
|
||||
initrd_add_cmd() {
|
||||
local i
|
||||
|
||||
if ! [ -e "$DIR_INITRD"/cmd.sh ]; then
|
||||
echo "#!/bin/sh -ex" > "$DIR_INITRD"/cmd.sh
|
||||
chmod +x "$DIR_INITRD"/cmd.sh
|
||||
fi
|
||||
|
||||
for i in "$@"; do
|
||||
echo "$i" >> "$DIR_INITRD"/cmd.sh
|
||||
done
|
||||
}
|
||||
|
||||
rm -rf "$DIR_INITRD"
|
||||
mkdir -p "$DIR_INITRD"
|
||||
cd "$DIR_INITRD"
|
||||
|
||||
for dir in bin sbin lib lib64; do
|
||||
ln -s usr/"$dir" "$dir"
|
||||
done
|
||||
|
||||
mkdir -p \
|
||||
dev/net \
|
||||
proc \
|
||||
run \
|
||||
sys \
|
||||
tmp \
|
||||
usr/bin \
|
||||
usr/sbin
|
||||
|
||||
initrd_add_bin \
|
||||
busybox \
|
||||
ip
|
||||
|
||||
initrd_add_cmd \
|
||||
"export LD_LIBRARY_PATH=$SRC_LIBS:$LD_LIBRARY_PATH"
|
||||
|
||||
export LD_LIBRARY_PATH="$SRC_LIBS:$LD_LIBRARY_PATH"
|
||||
|
||||
for i in gtp-link gtp-tunnel; do
|
||||
initrd_add_bin "$TOOLS_LIBS"/"$i"
|
||||
ln -s "$TOOLS_LIBS"/"$i" usr/bin/"$i"
|
||||
done
|
||||
|
||||
mkdir tests
|
||||
cp "$DIR"/*.sh tests
|
||||
|
||||
cp "$DIR"/initrd-init.sh init
|
||||
|
||||
find . -print0 \
|
||||
| cpio --quiet -o -0 -H newc \
|
||||
| gzip -1 > "$DIR"/_initrd.gz
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/busybox sh
|
||||
echo "Running initrd-init.sh"
|
||||
set -x
|
||||
|
||||
run_test() {
|
||||
echo
|
||||
echo "QEMU test: $1"
|
||||
echo
|
||||
if ! sh -ex "/tests/$1"; then
|
||||
poweroff -f
|
||||
fi
|
||||
}
|
||||
|
||||
export HOME=/root
|
||||
export LD_LIBRARY_PATH=/usr/local/lib
|
||||
export PATH=/usr/local/bin:/usr/bin:/bin:/sbin:/usr/local/sbin:/usr/sbin
|
||||
export TERM=screen
|
||||
|
||||
/bin/busybox --install -s
|
||||
hostname qemu
|
||||
mount -t proc proc /proc
|
||||
mount -t sysfs sys /sys
|
||||
mknod /dev/null c 1 3
|
||||
. /cmd.sh
|
||||
set +x
|
||||
|
||||
# Run all tests
|
||||
run_test 01_ms_ip4_sgsn_ip4.sh
|
||||
run_test 02_ms_ip4_sgsn_ip6.sh
|
||||
run_test 03_ms_ip6_sgsn_ip4.sh
|
||||
run_test 04_ms_ip6_sgsn_ip6.sh
|
||||
run_test 05_ms_ip46_sgsn_ip4.sh
|
||||
|
||||
# Success (run-qemu.sh checks for this line)
|
||||
echo "QEMU_TEST_SUCCESSFUL"
|
||||
poweroff -f
|
|
@ -0,0 +1,51 @@
|
|||
#!/bin/sh -e
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
if [ -e /dev/kvm ]; then
|
||||
MACHINE_ARG="-machine pc,accel=kvm"
|
||||
else
|
||||
echo "WARNING: /dev/kvm not found, emulation will be slower"
|
||||
MACHINE_ARG="-machine pc"
|
||||
fi
|
||||
|
||||
if ! [ -e "$DIR"/_linux ]; then
|
||||
echo "ERROR: linux kernel not found: $DIR/_linux"
|
||||
echo "Put a kernel there, either download it from the Osmocom jenkins:"
|
||||
echo "$ make -C tests qemu-download-kernel"
|
||||
echo
|
||||
echo "Or build your own kernel. Make sure to set:"
|
||||
echo " CONFIG_GTP=y"
|
||||
echo " CONFIG_NET_NS=y"
|
||||
echo " CONFIG_VETH=y"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
KERNEL_CMDLINE="root=/dev/ram0 console=ttyS0 panic=-1 init=/init"
|
||||
|
||||
set -x
|
||||
qemu-system-x86_64 \
|
||||
$MACHINE_ARG \
|
||||
-smp 1 \
|
||||
-m 512M \
|
||||
-no-user-config -nodefaults -display none \
|
||||
-gdb unix:"$DIR"/_gdb.pipe,server=on,wait=off \
|
||||
-no-reboot \
|
||||
-kernel "$DIR"/_linux \
|
||||
-initrd "$DIR"/_initrd.gz \
|
||||
-append "${KERNEL_CMDLINE}" \
|
||||
-serial stdio \
|
||||
-chardev socket,id=charserial1,path="$DIR"/_gdb-serial.pipe,server=on,wait=off \
|
||||
-device isa-serial,chardev=charserial1,id=serial1 \
|
||||
2>&1 | tee "$DIR/_output"
|
||||
|
||||
set +x
|
||||
if grep -q "QEMU_TEST_SUCCESSFUL" "$DIR/_output"; then
|
||||
echo
|
||||
echo "QEMU tests: successful"
|
||||
echo
|
||||
else
|
||||
echo
|
||||
echo "QEMU tests: failed"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
|
@ -1,6 +1,6 @@
|
|||
include $(top_srcdir)/Make_global.am
|
||||
|
||||
noinst_PROGRAMS = gtp-link \
|
||||
bin_PROGRAMS = gtp-link \
|
||||
gtp-tunnel
|
||||
|
||||
gtp_link_SOURCES = gtp-link.c
|
||||
|
|
193
tools/gtp-link.c
193
tools/gtp-link.c
|
@ -39,14 +39,106 @@
|
|||
#include <linux/if_link.h>
|
||||
|
||||
#include <libgtpnl/gtpnl.h>
|
||||
#include <errno.h>
|
||||
|
||||
struct gtp_server_sock {
|
||||
int family;
|
||||
int fd1;
|
||||
int fd2;
|
||||
socklen_t len;
|
||||
struct {
|
||||
union {
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
} fd1;
|
||||
union {
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
} fd2;
|
||||
} sockaddr;
|
||||
union {
|
||||
struct in_addr v4;
|
||||
struct in6_addr v6;
|
||||
} addr;
|
||||
};
|
||||
|
||||
static void setup_sockaddr_in(struct sockaddr_in *sockaddr, struct in_addr *in,
|
||||
uint16_t port)
|
||||
{
|
||||
sockaddr->sin_family = AF_INET;
|
||||
sockaddr->sin_port = htons(port);
|
||||
sockaddr->sin_addr = *in;
|
||||
}
|
||||
|
||||
static void setup_sockaddr_in6(struct sockaddr_in6 *sockaddr, struct in6_addr *in6,
|
||||
uint16_t port)
|
||||
{
|
||||
sockaddr->sin6_family = AF_INET6;
|
||||
sockaddr->sin6_port = htons(port);
|
||||
sockaddr->sin6_addr = *in6;
|
||||
}
|
||||
|
||||
static int setup_socket(struct gtp_server_sock *gtp_sock, int family)
|
||||
{
|
||||
int one = 1;
|
||||
|
||||
gtp_sock->fd1 = socket(family, SOCK_DGRAM, 0);
|
||||
gtp_sock->fd2 = socket(family, SOCK_DGRAM, 0);
|
||||
|
||||
if (gtp_sock->fd1 < 0 || gtp_sock->fd2 < 0)
|
||||
return -1;
|
||||
|
||||
gtp_sock->family = family;
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
gtp_sock->len = sizeof(struct sockaddr_in);
|
||||
setup_sockaddr_in(>p_sock->sockaddr.fd1.in,
|
||||
>p_sock->addr.v4, 3386);
|
||||
setup_sockaddr_in(>p_sock->sockaddr.fd2.in,
|
||||
>p_sock->addr.v4, 2152);
|
||||
break;
|
||||
case AF_INET6:
|
||||
gtp_sock->len = sizeof(struct sockaddr_in6);
|
||||
setup_sockaddr_in6(>p_sock->sockaddr.fd1.in6,
|
||||
>p_sock->addr.v6, 3386);
|
||||
setup_sockaddr_in6(>p_sock->sockaddr.fd2.in6,
|
||||
>p_sock->addr.v6, 2152);
|
||||
if (setsockopt(gtp_sock->fd1, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
|
||||
perror("setsockopt IPV6_V6ONLY: ");
|
||||
if (setsockopt(gtp_sock->fd2, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
|
||||
perror("setsockopt IPV6_V6ONLY: ");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void close_socket(struct gtp_server_sock *gtp_sock)
|
||||
{
|
||||
if (gtp_sock->fd1 != -1) {
|
||||
close(gtp_sock->fd1);
|
||||
gtp_sock->fd1 = -1;
|
||||
}
|
||||
|
||||
if (gtp_sock->fd2 != -1) {
|
||||
close(gtp_sock->fd2);
|
||||
gtp_sock->fd2 = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
int ret, sgsn_mode = 0;
|
||||
struct gtp_server_sock gtp_sock;
|
||||
int ret, sgsn_mode = 0, family;
|
||||
const char *addr = NULL;
|
||||
|
||||
memset(>p_sock, 0, sizeof(gtp_sock));
|
||||
|
||||
if (argc < 3) {
|
||||
printf("Usage: %s <add|del> <device>\n", argv[0]);
|
||||
printf("Usage: %s add <device> <family> [--sgsn] [<address>]\n", argv[0]);
|
||||
printf(" %s del <device>\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
@ -56,45 +148,78 @@ int main(int argc, char *argv[])
|
|||
perror("gtp_dev_destroy");
|
||||
|
||||
return 0;
|
||||
} else if (!strcmp(argv[1], "add")) {
|
||||
if (argc < 4) {
|
||||
printf("Usage: %s add <device> <family> [--sgsn] [<address>]\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (argc == 5) {
|
||||
if (!strcmp(argv[4], "--sgsn"))
|
||||
sgsn_mode = 1;
|
||||
else
|
||||
addr = argv[4];
|
||||
}
|
||||
|
||||
if (argc == 6) {
|
||||
if (!strcmp(argv[4], "--sgsn"))
|
||||
sgsn_mode = 1;
|
||||
|
||||
addr = argv[5];
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > 3 && !strcmp(argv[3], "--sgsn"))
|
||||
sgsn_mode = 1;
|
||||
|
||||
int fd1 = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
int fd2 = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
struct sockaddr_in sockaddr_fd1 = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htons(3386),
|
||||
.sin_addr = {
|
||||
.s_addr = INADDR_ANY,
|
||||
},
|
||||
};
|
||||
struct sockaddr_in sockaddr_fd2 = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_port = htons(2152),
|
||||
.sin_addr = {
|
||||
.s_addr = INADDR_ANY,
|
||||
},
|
||||
};
|
||||
|
||||
if (bind(fd1, (struct sockaddr *) &sockaddr_fd1,
|
||||
sizeof(sockaddr_fd1)) < 0) {
|
||||
perror("bind");
|
||||
if (!strcmp(argv[3], "ip"))
|
||||
family = AF_INET;
|
||||
else if (!strcmp(argv[3], "ip6"))
|
||||
family = AF_INET6;
|
||||
else {
|
||||
fprintf(stderr, "unsupport family `%s', expecting `ip' or `ip6'\n",
|
||||
argv[3]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (bind(fd2, (struct sockaddr *) &sockaddr_fd2,
|
||||
sizeof(sockaddr_fd2)) < 0) {
|
||||
|
||||
if (addr) {
|
||||
if (!inet_pton(family, addr, >p_sock.addr)) {
|
||||
fprintf(stderr, "invalid listener address: %s\n",
|
||||
strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
gtp_sock.addr.v4.s_addr = INADDR_ANY;
|
||||
break;
|
||||
case AF_INET6:
|
||||
gtp_sock.addr.v6 = in6addr_any;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (setup_socket(>p_sock, family) < 0) {
|
||||
perror("socket");
|
||||
close_socket(>p_sock);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (bind(gtp_sock.fd1, (struct sockaddr *) >p_sock.sockaddr.fd1, gtp_sock.len) < 0) {
|
||||
perror("bind");
|
||||
close_socket(>p_sock);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (bind(gtp_sock.fd2, (struct sockaddr *) >p_sock.sockaddr.fd2, gtp_sock.len) < 0) {
|
||||
perror("bind");
|
||||
close_socket(>p_sock);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (sgsn_mode)
|
||||
ret = gtp_dev_create_sgsn(-1, argv[2], fd1, fd2);
|
||||
ret = gtp_dev_create_sgsn(-1, argv[2], gtp_sock.fd1, gtp_sock.fd2);
|
||||
else
|
||||
ret = gtp_dev_create(-1, argv[2], fd1, fd2);
|
||||
ret = gtp_dev_create(-1, argv[2], gtp_sock.fd1, gtp_sock.fd2);
|
||||
if (ret < 0) {
|
||||
perror("cannot create GTP device\n");
|
||||
close_socket(>p_sock);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
@ -102,11 +227,13 @@ int main(int argc, char *argv[])
|
|||
"this process running for testing purposes.\n");
|
||||
|
||||
while (1) {
|
||||
struct sockaddr_in addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
union {
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_in6 addr6;
|
||||
} sock;
|
||||
|
||||
ret = recvfrom(fd1, buf, sizeof(buf), 0,
|
||||
(struct sockaddr *)&addr, &len);
|
||||
ret = recvfrom(gtp_sock.fd1, buf, sizeof(buf), 0,
|
||||
(struct sockaddr *)&sock, >p_sock.len);
|
||||
printf("received %d bytes via UDP socket\n", ret);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,14 +49,35 @@ static void add_usage(const char *name)
|
|||
name);
|
||||
}
|
||||
|
||||
static void set_addr(const char *addr, bool is_ms, struct gtp_tunnel *t)
|
||||
{
|
||||
struct in_addr ip4;
|
||||
struct in6_addr ip6;
|
||||
|
||||
if (inet_pton(AF_INET, addr, &ip4) == 1) {
|
||||
if (is_ms)
|
||||
return gtp_tunnel_set_ms_ip4(t, &ip4);
|
||||
return gtp_tunnel_set_sgsn_ip4(t, &ip4);
|
||||
}
|
||||
|
||||
if (inet_pton(AF_INET6, addr, &ip6) == 1) {
|
||||
if (is_ms)
|
||||
return gtp_tunnel_set_ms_ip6(t, &ip6);
|
||||
return gtp_tunnel_set_sgsn_ip6(t, &ip6);
|
||||
}
|
||||
|
||||
fprintf(stderr, "bad address: %s\n", addr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static int
|
||||
add_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
|
||||
{
|
||||
struct gtp_tunnel *t;
|
||||
uint32_t gtp_ifidx;
|
||||
struct in_addr ms, sgsn;
|
||||
uint32_t gtp_version;
|
||||
int optidx;
|
||||
int ret;
|
||||
|
||||
if (argc < 7 || argc > 8) {
|
||||
add_usage(argv[0]);
|
||||
|
@ -88,29 +109,21 @@ add_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
|
|||
|
||||
optidx++;
|
||||
|
||||
if (gtp_version == GTP_V0)
|
||||
if (gtp_version == GTP_V0) {
|
||||
gtp_tunnel_set_tid(t, atoi(argv[optidx++]));
|
||||
else if (gtp_version == GTP_V1) {
|
||||
gtp_tunnel_set_flowid(t, 0);
|
||||
} else if (gtp_version == GTP_V1) {
|
||||
gtp_tunnel_set_i_tei(t, atoi(argv[optidx++]));
|
||||
gtp_tunnel_set_o_tei(t, atoi(argv[optidx++]));
|
||||
}
|
||||
|
||||
if (inet_aton(argv[optidx++], &ms) < 0) {
|
||||
perror("bad address for ms");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
gtp_tunnel_set_ms_ip4(t, &ms);
|
||||
set_addr(argv[optidx++], true, t);
|
||||
set_addr(argv[optidx++], false, t);
|
||||
|
||||
if (inet_aton(argv[optidx++], &sgsn) < 0) {
|
||||
perror("bad address for sgsn");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
gtp_tunnel_set_sgsn_ip4(t, &sgsn);
|
||||
|
||||
gtp_add_tunnel(genl_id, nl, t);
|
||||
ret = gtp_add_tunnel(genl_id, nl, t);
|
||||
|
||||
gtp_tunnel_free(t);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -118,9 +131,10 @@ del_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
|
|||
{
|
||||
struct gtp_tunnel *t;
|
||||
uint32_t gtp_ifidx;
|
||||
int ret;
|
||||
|
||||
if (argc != 5) {
|
||||
printf("%s add <gtp device> <version> <tid>\n",
|
||||
if (argc != 6) {
|
||||
printf("%s del <gtp device> <version> <tid|i_tei> <family>\n",
|
||||
argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -130,6 +144,7 @@ del_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
|
|||
gtp_ifidx = if_nametoindex(argv[2]);
|
||||
if (gtp_ifidx == 0) {
|
||||
fprintf(stderr, "wrong GTP interface %s\n", argv[2]);
|
||||
gtp_tunnel_free(t);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
gtp_tunnel_set_ifidx(t, gtp_ifidx);
|
||||
|
@ -143,13 +158,24 @@ del_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
|
|||
} else {
|
||||
fprintf(stderr, "wrong GTP version %s, use v0 or v1\n",
|
||||
argv[3]);
|
||||
gtp_tunnel_free(t);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
gtp_del_tunnel(genl_id, nl, t);
|
||||
if (strcmp(argv[5], "ip") == 0) {
|
||||
gtp_tunnel_set_family(t, AF_INET);
|
||||
} else if (strcmp(argv[5], "ip6") == 0) {
|
||||
gtp_tunnel_set_family(t, AF_INET6);
|
||||
} else {
|
||||
fprintf(stderr, "wrong family %s, use ip or ip6\n", argv[5]);
|
||||
gtp_tunnel_free(t);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ret = gtp_del_tunnel(genl_id, nl, t);
|
||||
|
||||
gtp_tunnel_free(t);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct gtp_pdp {
|
||||
|
|
Loading…
Reference in New Issue