Add QEMU tests
Add tests to ensure libgtpnl + kernel driver work as expected. Right now a kernel needs to be built from source, using Pablo's tree: https://git.kernel.org/pub/scm/linux/kernel/git/pablo/gtp.git/ Make sure to enable: CONFIG_GTP=y CONFIG_NET_NS=y CONFIG_VETH=y $ cp bzImage tests/qemu/_linux $ ./configure --enable-qemu-tests $ make $ make check Once patches are upstreamed, it will be possible to use a pre-built kernel from jenkins with: make -C tests qemu-download-kernel Related: OS#1952 Change-Id: Ibf75514b866fffb11e90529e4705f126b23d7415
This commit is contained in:
parent
791a620e4d
commit
72ddb01219
|
@ -37,3 +37,5 @@ contrib/libgtpnl.spec
|
|||
|
||||
tools/gtp-link
|
||||
tools/gtp-tunnel
|
||||
|
||||
tests/qemu/_*
|
||||
|
|
|
@ -4,7 +4,12 @@ include $(top_srcdir)/Make_global.am
|
|||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = src include tools
|
||||
SUBDIRS = \
|
||||
include \
|
||||
src \
|
||||
tests \
|
||||
tools \
|
||||
$(NULL)
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libgtpnl.pc
|
||||
|
|
14
configure.ac
14
configure.ac
|
@ -72,6 +72,19 @@ then
|
|||
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([
|
||||
|
@ -82,6 +95,7 @@ AC_CONFIG_FILES([
|
|||
include/linux/Makefile
|
||||
libgtpnl.pc
|
||||
src/Makefile
|
||||
tests/Makefile
|
||||
tools/Makefile
|
||||
])
|
||||
AC_OUTPUT()
|
||||
|
|
|
@ -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,75 @@
|
|||
#!/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"
|
||||
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
|
||||
}
|
||||
|
||||
tunnel_ping() {
|
||||
ip addr show
|
||||
ping -c 1 "$WEBSERVER"
|
||||
ggsn_side ping -c 1 "$MS"
|
||||
}
|
||||
|
||||
tunnel_stop() {
|
||||
killall gtp-link
|
||||
|
||||
ip addr del "$MS"/"$MS_PREFLEN" dev lo
|
||||
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 "$SGSN_GGSN_PROTO"
|
||||
gtp-link del gtp_sgsn
|
||||
ggsn_side gtp-tunnel delete gtp_ggsn v1 100 "$SGSN_GGSN_PROTO"
|
||||
ggsn_side gtp-link del gtp_ggsn
|
||||
ip netns del ggsn_side
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh -ex
|
||||
. /tests/00_test_functions.sh
|
||||
|
||||
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,14 @@
|
|||
#!/bin/sh -ex
|
||||
. /tests/00_test_functions.sh
|
||||
|
||||
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,14 @@
|
|||
#!/bin/sh -ex
|
||||
. /tests/00_test_functions.sh
|
||||
|
||||
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,14 @@
|
|||
#!/bin/sh -ex
|
||||
. /tests/00_test_functions.sh
|
||||
|
||||
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,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,35 @@
|
|||
#!/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
|
||||
|
||||
# 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
|
Loading…
Reference in New Issue