mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-21 18:11:35 +00:00
tests: Add a package for network namespace stress tests
Signed-off-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
This commit is contained in:
parent
03b78d5153
commit
9fad2e8b31
16
test/pkg/netns/Dockerfile
Normal file
16
test/pkg/netns/Dockerfile
Normal file
@ -0,0 +1,16 @@
|
||||
FROM linuxkit/alpine:3d57ded3edd54e616210cf0c17e3bc15eed9d03a AS mirror
|
||||
RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/
|
||||
RUN apk add --no-cache --initdb -p /out \
|
||||
alpine-baselayout \
|
||||
busybox \
|
||||
iperf3 \
|
||||
iproute2 \
|
||||
musl
|
||||
RUN rm -rf /out/etc/apk /out/lib/apk /out/var/cache
|
||||
|
||||
FROM scratch
|
||||
COPY --from=mirror /out/ /
|
||||
COPY netns.sh runp.sh /
|
||||
|
||||
LABEL org.mobyproject.config='{"pid": "host", "net":"host", "binds": ["/dev:/dev","/sys:/sys"], "capabilities": ["all"]}'
|
||||
|
15
test/pkg/netns/Makefile
Normal file
15
test/pkg/netns/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
.PHONY: tag push
|
||||
default: push
|
||||
|
||||
ORG?=linuxkit
|
||||
IMAGE=test-netns
|
||||
DEPS=Dockerfile Makefile
|
||||
|
||||
HASH?=$(shell git ls-tree HEAD -- ../$(notdir $(CURDIR)) | awk '{print $$3}')
|
||||
|
||||
tag: $(DEPS)
|
||||
docker build --squash --no-cache -t $(ORG)/$(IMAGE):$(HASH) .
|
||||
|
||||
push: tag
|
||||
DOCKER_CONTENT_TRUST=1 docker pull $(ORG)/$(IMAGE):$(HASH) || \
|
||||
DOCKER_CONTENT_TRUST=1 docker push $(ORG)/$(IMAGE):$(HASH)
|
199
test/pkg/netns/netns.sh
Executable file
199
test/pkg/netns/netns.sh
Executable file
@ -0,0 +1,199 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Initialise the Random Number Seed with the PID
|
||||
RANDOM=$$
|
||||
|
||||
# defaults
|
||||
ARG_TYPE=veth
|
||||
ARG_PROTO=tcp
|
||||
ARG_IP=4
|
||||
ARG_CONN=1
|
||||
ARG_ITER=10
|
||||
ARG_LEN=20
|
||||
ARG_REUSE=0
|
||||
|
||||
usage() {
|
||||
echo "Stress test for network namespace using iperf"
|
||||
echo " -t loopback|veth Type of test [$ARG_TYPE]"
|
||||
echo " -p tcp|udp Protocol to use [$ARG_PROTO]"
|
||||
echo " -ip 4|6 IP version to use [$ARG_IP]"
|
||||
echo " -c <n> Number of concurrent connections in ns [$ARG_CONN]"
|
||||
echo " -i <n> Number of iterations [$ARG_ITER]"
|
||||
echo " -l <n> Maximum length of test before killing [$ARG_LEN]"
|
||||
echo " -r Re-use network namespace name"
|
||||
}
|
||||
|
||||
# parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
key="$1"
|
||||
|
||||
case $key in
|
||||
-t)
|
||||
ARG_TYPE="$2"
|
||||
shift
|
||||
;;
|
||||
-p)
|
||||
ARG_PROTO="$2"
|
||||
shift
|
||||
;;
|
||||
-ip)
|
||||
ARG_IP="$2"
|
||||
shift
|
||||
;;
|
||||
-c)
|
||||
ARG_CONN="$2"
|
||||
shift
|
||||
;;
|
||||
-i)
|
||||
ARG_ITER="$2"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
ARG_LEN="$2"
|
||||
shift
|
||||
;;
|
||||
-r)
|
||||
ARG_REUSE=1
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
echo "PID=$$"
|
||||
|
||||
# Kill a random bit (client, server, network namespace, device) first
|
||||
# before cleaning up
|
||||
kill_all() {
|
||||
ns=$1
|
||||
pid_client=$2
|
||||
pid_server=$3
|
||||
host_dev=$4
|
||||
ns_dev=$5
|
||||
|
||||
R=$(($RANDOM%$#))
|
||||
case $R in
|
||||
0)
|
||||
echo "$ns: Remove namespace first"
|
||||
ip netns del "$ns" > /dev/nukk 2>&1 || true
|
||||
;;
|
||||
1)
|
||||
echo "$ns: Kill client processes first"
|
||||
kill "$pid_client" > /dev/null 2>&1 || true
|
||||
;;
|
||||
2)
|
||||
echo "$ns: Kill server process first"
|
||||
kill "$pid_server" > /dev/null 2>&1 || true
|
||||
;;
|
||||
3)
|
||||
echo "$ns: Remove host netdev first"
|
||||
ip link del "$host_dev"
|
||||
;;
|
||||
4)
|
||||
echo "$ns: Remove netns netdev first"
|
||||
ip netns exec "$ns" ip link del "$ns_dev"
|
||||
;;
|
||||
esac
|
||||
kill "$pid_client" > /dev/null 2>&1 || true
|
||||
kill "$pid_server" > /dev/null 2>&1 || true
|
||||
ip netns del "$ns" > /dev/null 2>&1 || true
|
||||
[ "$host_dev"x != x ] && (ip link del "$host_dev" > /dev/null 2>&1 || true) || true
|
||||
[ "$ns_dev"x != x ] && (ip netns exec "$ns" ip link del "$ns_dev" > /dev/null 2>&1 || true) || true
|
||||
}
|
||||
|
||||
# Run sock_stress in loopback mode in a network namespace
|
||||
loopback_run() {
|
||||
id=$1 # unique ID for this run, used to create namespace
|
||||
ip=$2 # 4 or 6 to select IP version to use
|
||||
pr=$3 # protocol tcp or udp
|
||||
|
||||
# Use our PID as the ID to get unique namespaces
|
||||
if [ "$ARG_REUSE" = "1" ]; then
|
||||
ns="ns_$$"
|
||||
else
|
||||
ns="ns_$$_$id"
|
||||
fi
|
||||
ip netns add "$ns"
|
||||
ip netns exec "$ns" ip link set lo up
|
||||
|
||||
ip netns exec "$ns" iperf3 -s --logfile /dev/null &
|
||||
pid_server=$!
|
||||
sleep 1
|
||||
[ "$pr" = "udp" ] && o="-u"
|
||||
ip netns exec "$ns" iperf3 -"$ip" "$o" -P "$ARG_CONN" -c localhost -t 10000 -i 20 &
|
||||
pid_client=$!
|
||||
|
||||
# wait for a while before killing processes
|
||||
sleep $(((RANDOM % $ARG_LEN )+1))
|
||||
|
||||
kill_all "$ns" "$pid_client" "$pid_server"
|
||||
}
|
||||
|
||||
# Run sock_stress in with the client in a namespace
|
||||
veth_run() {
|
||||
id=$1 # unique ID for this run, used to create namespace
|
||||
ip=$2 # 4 or 6 to select IP version to use
|
||||
pr=$3 # tcp or udp
|
||||
|
||||
# Use our PID as the ID to get unique namespaces
|
||||
if [ "$ARG_REUSE" = "1" ]; then
|
||||
ns="ns_$$"
|
||||
else
|
||||
ns="ns_$$_$id"
|
||||
fi
|
||||
dev_host="h-$$-$id"
|
||||
dev_ns="n-$$-$id"
|
||||
ip netns add "$ns"
|
||||
ip netns exec "$ns" ip link set lo up
|
||||
|
||||
ip link add "$dev_host" type veth peer name "$dev_ns"
|
||||
ip link set "$dev_ns" netns "$ns"
|
||||
|
||||
# derive IP addresses based on PID and $id
|
||||
if [ "$ip" = "4" ]; then
|
||||
sub0=$(($$%255))
|
||||
sub1=$(($id%255))
|
||||
mask=24
|
||||
ip_host="10.$sub0.$sub1.1"
|
||||
ip_ns="10.$sub0.$sub1.2"
|
||||
else
|
||||
# Make sure IPv6 is enabled on the interface
|
||||
echo 0 > /proc/sys/net/ipv6/conf/"$dev_host"/disable_ipv6
|
||||
sub0=$(printf "%x" $(($$%65535)))
|
||||
sub1=$(printf "%x" $(($id%65535)))
|
||||
mask=64
|
||||
ip_host="2001:$sub0:$sub1::1"
|
||||
ip_ns="2001:$sub0:$sub1::2"
|
||||
fi
|
||||
ip -"$ip" addr add "$ip_host"/"$mask" dev "$dev_host"
|
||||
ip link set "$dev_host" up
|
||||
|
||||
ip netns exec "$ns" ip -"$ip" addr add "$ip_ns"/"$mask" dev "$dev_ns"
|
||||
ip netns exec "$ns" ip link set "$dev_ns" up
|
||||
sleep 2 # for IPv6 it takes a little while for the link to come up
|
||||
|
||||
ip netns exec "$ns" iperf3 -s --logfile /dev/null &
|
||||
pid_server=$!
|
||||
sleep 1
|
||||
[ "$pr" = "udp" ] && o="-u"
|
||||
iperf3 -"$ip" "$o" -P "$ARG_CONN" -c "$ip_ns" -t 10000 -i 20 &
|
||||
pid_client=$!
|
||||
|
||||
# wait for a while before killing processes
|
||||
sleep $(((RANDOM % $ARG_LEN )+1))
|
||||
|
||||
kill_all "$ns" "$pid_client" "$pid_server" "$dev_host" "$dev_ns"
|
||||
}
|
||||
|
||||
for i in $(seq 1 "$ARG_ITER"); do
|
||||
case $ARG_TYPE in
|
||||
veth)
|
||||
veth_run "$i" "$ARG_IP" "$ARG_PROTO"
|
||||
;;
|
||||
loopback)
|
||||
loopback_run "$i" "$ARG_IP" "$ARG_PROTO"
|
||||
esac
|
||||
done
|
48
test/pkg/netns/runp.sh
Executable file
48
test/pkg/netns/runp.sh
Executable file
@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
|
||||
ITER=$1
|
||||
shift
|
||||
|
||||
rm -rf ./logs
|
||||
mkdir -p ./logs
|
||||
|
||||
fail() {
|
||||
for f in ./logs/*; do
|
||||
echo
|
||||
echo "=== $f ==="
|
||||
cat $f
|
||||
done
|
||||
echo
|
||||
dmesg
|
||||
echo "Test FAILED with $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
ns_before=$(ip netns list | wc -l)
|
||||
|
||||
pids=""
|
||||
for i in $(seq 1 "$ITER"); do
|
||||
"$@" > "./logs/$1-$i.log" 2>&1 &
|
||||
pid=$!
|
||||
pids="$pids $pid"
|
||||
echo "Test $i started with PID=$pid"
|
||||
done
|
||||
|
||||
for pid in $pids; do
|
||||
wait "$pid"
|
||||
[ $? -eq 0 ] || fail "$pid return non-zero"
|
||||
done
|
||||
|
||||
dmesg | grep -q 'Call Trace:' && fail "Kernel backtrace"
|
||||
|
||||
# A message like:
|
||||
# unregister_netdevice: waiting for lo to become free. Usage count = 1
|
||||
# is somewhat benign as it just waits for the ref count to go to 0. However
|
||||
# it may become a problem if we have to many of them
|
||||
nd=$(dmesg | grep -q 'unregister_netdevice' | wc -l)
|
||||
[ "$nd" -gt 10 ] && fail "unregister_netdevice more than 10 times"
|
||||
|
||||
ns_after=$(ip netns list | wc -l)
|
||||
[ "$ns_before" != "$ns_after" ] && fail "NS leak: $ns_before != $ns_after"
|
||||
|
||||
echo "netns test suite PASSED"
|
Loading…
Reference in New Issue
Block a user