summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/net/netfilter/nft_queue.sh
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/net/netfilter/nft_queue.sh')
-rwxr-xr-xtools/testing/selftests/net/netfilter/nft_queue.sh272
1 files changed, 120 insertions, 152 deletions
diff --git a/tools/testing/selftests/net/netfilter/nft_queue.sh b/tools/testing/selftests/net/netfilter/nft_queue.sh
index 2eb65887e570..8538f08c64c2 100755
--- a/tools/testing/selftests/net/netfilter/nft_queue.sh
+++ b/tools/testing/selftests/net/netfilter/nft_queue.sh
@@ -4,94 +4,72 @@
# 1. can process packets from all hooks
# 2. support running nfqueue from more than one base chain
#
-# Kselftest framework requirement - SKIP code is 4.
-ksft_skip=4
-ret=0
+# shellcheck disable=SC2162,SC2317
-sfx=$(mktemp -u "XXXXXXXX")
-ns1="ns1-$sfx"
-ns2="ns2-$sfx"
-nsrouter="nsrouter-$sfx"
-timeout=4
+source lib.sh
+ret=0
+timeout=2
cleanup()
{
- ip netns pids ${ns1} | xargs kill 2>/dev/null
- ip netns pids ${ns2} | xargs kill 2>/dev/null
- ip netns pids ${nsrouter} | xargs kill 2>/dev/null
+ ip netns pids "$ns1" | xargs kill 2>/dev/null
+ ip netns pids "$ns2" | xargs kill 2>/dev/null
+ ip netns pids "$nsrouter" | xargs kill 2>/dev/null
- ip netns del ${ns1}
- ip netns del ${ns2}
- ip netns del ${nsrouter}
+ cleanup_all_ns
+
+ rm -f "$TMPINPUT"
rm -f "$TMPFILE0"
rm -f "$TMPFILE1"
rm -f "$TMPFILE2" "$TMPFILE3"
}
-nft --version > /dev/null 2>&1
-if [ $? -ne 0 ];then
- echo "SKIP: Could not run test without nft tool"
- exit $ksft_skip
-fi
+checktool "nft --version" "test without nft tool"
-ip -Version > /dev/null 2>&1
-if [ $? -ne 0 ];then
- echo "SKIP: Could not run test without ip tool"
- exit $ksft_skip
-fi
+trap cleanup EXIT
-ip netns add ${nsrouter}
-if [ $? -ne 0 ];then
- echo "SKIP: Could not create net namespace"
- exit $ksft_skip
-fi
+setup_ns ns1 ns2 nsrouter
TMPFILE0=$(mktemp)
TMPFILE1=$(mktemp)
TMPFILE2=$(mktemp)
TMPFILE3=$(mktemp)
-trap cleanup EXIT
-ip netns add ${ns1}
-ip netns add ${ns2}
+TMPINPUT=$(mktemp)
+dd conv=sparse status=none if=/dev/zero bs=1M count=200 of="$TMPINPUT"
-ip link add veth0 netns ${nsrouter} type veth peer name eth0 netns ${ns1} > /dev/null 2>&1
-if [ $? -ne 0 ];then
+if ! ip link add veth0 netns "$nsrouter" type veth peer name eth0 netns "$ns1" > /dev/null 2>&1; then
echo "SKIP: No virtual ethernet pair device support in kernel"
exit $ksft_skip
fi
-ip link add veth1 netns ${nsrouter} type veth peer name eth0 netns ${ns2}
+ip link add veth1 netns "$nsrouter" type veth peer name eth0 netns "$ns2"
-ip -net ${nsrouter} link set lo up
-ip -net ${nsrouter} link set veth0 up
-ip -net ${nsrouter} addr add 10.0.1.1/24 dev veth0
-ip -net ${nsrouter} addr add dead:1::1/64 dev veth0
+ip -net "$nsrouter" link set veth0 up
+ip -net "$nsrouter" addr add 10.0.1.1/24 dev veth0
+ip -net "$nsrouter" addr add dead:1::1/64 dev veth0 nodad
-ip -net ${nsrouter} link set veth1 up
-ip -net ${nsrouter} addr add 10.0.2.1/24 dev veth1
-ip -net ${nsrouter} addr add dead:2::1/64 dev veth1
+ip -net "$nsrouter" link set veth1 up
+ip -net "$nsrouter" addr add 10.0.2.1/24 dev veth1
+ip -net "$nsrouter" addr add dead:2::1/64 dev veth1 nodad
-ip -net ${ns1} link set lo up
-ip -net ${ns1} link set eth0 up
+ip -net "$ns1" link set eth0 up
+ip -net "$ns2" link set eth0 up
-ip -net ${ns2} link set lo up
-ip -net ${ns2} link set eth0 up
+ip -net "$ns1" addr add 10.0.1.99/24 dev eth0
+ip -net "$ns1" addr add dead:1::99/64 dev eth0 nodad
+ip -net "$ns1" route add default via 10.0.1.1
+ip -net "$ns1" route add default via dead:1::1
-ip -net ${ns1} addr add 10.0.1.99/24 dev eth0
-ip -net ${ns1} addr add dead:1::99/64 dev eth0
-ip -net ${ns1} route add default via 10.0.1.1
-ip -net ${ns1} route add default via dead:1::1
-
-ip -net ${ns2} addr add 10.0.2.99/24 dev eth0
-ip -net ${ns2} addr add dead:2::99/64 dev eth0
-ip -net ${ns2} route add default via 10.0.2.1
-ip -net ${ns2} route add default via dead:2::1
+ip -net "$ns2" addr add 10.0.2.99/24 dev eth0
+ip -net "$ns2" addr add dead:2::99/64 dev eth0 nodad
+ip -net "$ns2" route add default via 10.0.2.1
+ip -net "$ns2" route add default via dead:2::1
load_ruleset() {
local name=$1
local prio=$2
-ip netns exec ${nsrouter} nft -f /dev/stdin <<EOF
+ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF
table inet $name {
chain nfq {
ip protocol icmp queue bypass
@@ -127,7 +105,7 @@ EOF
load_counter_ruleset() {
local prio=$1
-ip netns exec ${nsrouter} nft -f /dev/stdin <<EOF
+ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF
table inet countrules {
chain pre {
type filter hook prerouting priority $prio; policy accept;
@@ -154,28 +132,24 @@ EOF
}
test_ping() {
- ip netns exec ${ns1} ping -c 1 -q 10.0.2.99 > /dev/null
- if [ $? -ne 0 ];then
+ if ! ip netns exec "$ns1" ping -c 1 -q 10.0.2.99 > /dev/null; then
return 1
fi
- ip netns exec ${ns1} ping -c 1 -q dead:2::99 > /dev/null
- if [ $? -ne 0 ];then
- return 1
+ if ! ip netns exec "$ns1" ping -c 1 -q dead:2::99 > /dev/null; then
+ return 2
fi
return 0
}
test_ping_router() {
- ip netns exec ${ns1} ping -c 1 -q 10.0.2.1 > /dev/null
- if [ $? -ne 0 ];then
- return 1
+ if ! ip netns exec "$ns1" ping -c 1 -q 10.0.2.1 > /dev/null; then
+ return 3
fi
- ip netns exec ${ns1} ping -c 1 -q dead:2::1 > /dev/null
- if [ $? -ne 0 ];then
- return 1
+ if ! ip netns exec "$ns1" ping -c 1 -q dead:2::1 > /dev/null; then
+ return 4
fi
return 0
@@ -184,7 +158,7 @@ test_ping_router() {
test_queue_blackhole() {
local proto=$1
-ip netns exec ${nsrouter} nft -f /dev/stdin <<EOF
+ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF
table $proto blackh {
chain forward {
type filter hook forward priority 0; policy accept;
@@ -192,24 +166,23 @@ table $proto blackh {
}
}
EOF
- if [ $proto = "ip" ] ;then
- ip netns exec ${ns1} ping -W 2 -c 1 -q 10.0.2.99 > /dev/null
+ if [ "$proto" = "ip" ] ;then
+ ip netns exec "$ns1" ping -W 2 -c 1 -q 10.0.2.99 > /dev/null
lret=$?
- elif [ $proto = "ip6" ]; then
- ip netns exec ${ns1} ping -W 2 -c 1 -q dead:2::99 > /dev/null
+ elif [ "$proto" = "ip6" ]; then
+ ip netns exec "$ns1" ping -W 2 -c 1 -q dead:2::99 > /dev/null
lret=$?
else
lret=111
fi
# queue without bypass keyword should drop traffic if no listener exists.
- if [ $lret -eq 0 ];then
+ if [ "$lret" -eq 0 ];then
echo "FAIL: $proto expected failure, got $lret" 1>&2
exit 1
fi
- ip netns exec ${nsrouter} nft delete table $proto blackh
- if [ $? -ne 0 ] ;then
+ if ! ip netns exec "$nsrouter" nft delete table "$proto" blackh; then
echo "FAIL: $proto: Could not delete blackh table"
exit 1
fi
@@ -217,26 +190,41 @@ EOF
echo "PASS: $proto: statement with no listener results in packet drop"
}
+nf_queue_wait()
+{
+ local procfile="/proc/self/net/netfilter/nfnetlink_queue"
+ local netns id
+
+ netns="$1"
+ id="$2"
+
+ # if this file doesn't exist, nfnetlink_module isn't loaded.
+ # rather than loading it ourselves, wait for kernel module autoload
+ # completion, nfnetlink should do so automatically because nf_queue
+ # helper program, spawned in the background, asked for this functionality.
+ test -f "$procfile" &&
+ ip netns exec "$netns" cat "$procfile" | grep -q "^ *$id "
+}
+
test_queue()
{
- local expected=$1
+ local expected="$1"
local last=""
# spawn nf_queue listeners
- ip netns exec ${nsrouter} ./nf_queue -c -q 0 -t $timeout > "$TMPFILE0" &
- ip netns exec ${nsrouter} ./nf_queue -c -q 1 -t $timeout > "$TMPFILE1" &
- sleep 1
- test_ping
- ret=$?
- if [ $ret -ne 0 ];then
- echo "FAIL: netns routing/connectivity with active listener on queue $queue: $ret" 1>&2
+ ip netns exec "$nsrouter" ./nf_queue -c -q 0 -t $timeout > "$TMPFILE0" &
+ ip netns exec "$nsrouter" ./nf_queue -c -q 1 -t $timeout > "$TMPFILE1" &
+
+ busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 0
+ busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 1
+
+ if ! test_ping;then
+ echo "FAIL: netns routing/connectivity with active listener on queues 0 and 1: $ret" 1>&2
exit $ret
fi
- test_ping_router
- ret=$?
- if [ $ret -ne 0 ];then
- echo "FAIL: netns router unreachable listener on queue $queue: $ret" 1>&2
+ if ! test_ping_router;then
+ echo "FAIL: netns router unreachable listener on queue 0 and 1: $ret" 1>&2
exit $ret
fi
@@ -247,9 +235,7 @@ test_queue()
last=$(tail -n1 "$file")
if [ x"$last" != x"$expected packets total" ]; then
echo "FAIL: Expected $expected packets total, but got $last" 1>&2
- cat "$file" 1>&2
-
- ip netns exec ${nsrouter} nft list ruleset
+ ip netns exec "$nsrouter" nft list ruleset
exit 1
fi
done
@@ -257,66 +243,57 @@ test_queue()
echo "PASS: Expected and received $last"
}
+listener_ready()
+{
+ ss -N "$1" -lnt -o "sport = :12345" | grep -q 12345
+}
+
test_tcp_forward()
{
- ip netns exec ${nsrouter} ./nf_queue -q 2 -t $timeout &
+ ip netns exec "$nsrouter" ./nf_queue -q 2 -t "$timeout" &
local nfqpid=$!
- tmpfile=$(mktemp) || exit 1
- dd conv=sparse status=none if=/dev/zero bs=1M count=200 of=$tmpfile
- ip netns exec ${ns2} nc -w 5 -l -p 12345 <"$tmpfile" >/dev/null &
+ timeout 5 ip netns exec "$ns2" socat -u TCP-LISTEN:12345 STDOUT >/dev/null &
local rpid=$!
- sleep 1
- ip netns exec ${ns1} nc -w 5 10.0.2.99 12345 <"$tmpfile" >/dev/null &
+ busywait "$BUSYWAIT_TIMEOUT" listener_ready "$ns2"
- rm -f "$tmpfile"
+ ip netns exec "$ns1" socat -u STDIN TCP:10.0.2.99:12345 <"$TMPINPUT" >/dev/null
- wait $rpid
- wait $lpid
- [ $? -eq 0 ] && echo "PASS: tcp and nfqueue in forward chain"
+ wait "$rpid" && echo "PASS: tcp and nfqueue in forward chain"
}
test_tcp_localhost()
{
- tmpfile=$(mktemp) || exit 1
-
- dd conv=sparse status=none if=/dev/zero bs=1M count=200 of=$tmpfile
- ip netns exec ${nsrouter} nc -w 5 -l -p 12345 <"$tmpfile" >/dev/null &
+ dd conv=sparse status=none if=/dev/zero bs=1M count=200 of="$TMPINPUT"
+ timeout 5 ip netns exec "$nsrouter" socat -u TCP-LISTEN:12345 STDOUT >/dev/null &
local rpid=$!
- ip netns exec ${nsrouter} ./nf_queue -q 3 -t $timeout &
+ ip netns exec "$nsrouter" ./nf_queue -q 3 -t "$timeout" &
local nfqpid=$!
- sleep 1
- ip netns exec ${nsrouter} nc -w 5 127.0.0.1 12345 <"$tmpfile" > /dev/null
- rm -f "$tmpfile"
+ busywait "$BUSYWAIT_TIMEOUT" listener_ready "$nsrouter"
+
+ ip netns exec "$nsrouter" socat -u STDIN TCP:127.0.0.1:12345 <"$TMPINPUT" >/dev/null
- wait $rpid
- [ $? -eq 0 ] && echo "PASS: tcp via loopback"
+ wait "$rpid" && echo "PASS: tcp via loopback"
wait 2>/dev/null
}
test_tcp_localhost_connectclose()
{
- tmpfile=$(mktemp) || exit 1
+ ip netns exec "$nsrouter" ./connect_close -p 23456 -t "$timeout" &
+ ip netns exec "$nsrouter" ./nf_queue -q 3 -t "$timeout" &
- ip netns exec ${nsrouter} ./connect_close -p 23456 -t $timeout &
-
- ip netns exec ${nsrouter} ./nf_queue -q 3 -t $timeout &
- local nfqpid=$!
+ busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$nsrouter" 3
- sleep 1
- rm -f "$tmpfile"
-
- wait $rpid
- [ $? -eq 0 ] && echo "PASS: tcp via loopback with connect/close"
+ wait && echo "PASS: tcp via loopback with connect/close"
wait 2>/dev/null
}
test_tcp_localhost_requeue()
{
-ip netns exec ${nsrouter} nft -f /dev/stdin <<EOF
+ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF
flush ruleset
table inet filter {
chain output {
@@ -329,20 +306,17 @@ table inet filter {
}
}
EOF
- tmpfile=$(mktemp) || exit 1
- dd conv=sparse status=none if=/dev/zero bs=1M count=200 of=$tmpfile
- ip netns exec ${nsrouter} nc -w 5 -l -p 12345 <"$tmpfile" >/dev/null &
+ timeout 5 ip netns exec "$nsrouter" socat -u TCP-LISTEN:12345 STDOUT >/dev/null &
local rpid=$!
- ip netns exec ${nsrouter} ./nf_queue -c -q 1 -t $timeout > "$TMPFILE2" &
+ ip netns exec "$nsrouter" ./nf_queue -c -q 1 -t "$timeout" > "$TMPFILE2" &
# nfqueue 1 will be called via output hook. But this time,
# re-queue the packet to nfqueue program on queue 2.
- ip netns exec ${nsrouter} ./nf_queue -G -d 150 -c -q 0 -Q 1 -t $timeout > "$TMPFILE3" &
+ ip netns exec "$nsrouter" ./nf_queue -G -d 150 -c -q 0 -Q 1 -t "$timeout" > "$TMPFILE3" &
- sleep 1
- ip netns exec ${nsrouter} nc -w 5 127.0.0.1 12345 <"$tmpfile" > /dev/null
- rm -f "$tmpfile"
+ busywait "$BUSYWAIT_TIMEOUT" listener_ready "$nsrouter"
+ ip netns exec "$nsrouter" socat -u STDIN TCP:127.0.0.1:12345 <"$TMPINPUT" > /dev/null
wait
@@ -355,17 +329,16 @@ EOF
}
test_icmp_vrf() {
- ip -net $ns1 link add tvrf type vrf table 9876
- if [ $? -ne 0 ];then
+ if ! ip -net "$ns1" link add tvrf type vrf table 9876;then
echo "SKIP: Could not add vrf device"
return
fi
- ip -net $ns1 li set eth0 master tvrf
- ip -net $ns1 li set tvrf up
+ ip -net "$ns1" li set eth0 master tvrf
+ ip -net "$ns1" li set tvrf up
- ip -net $ns1 route add 10.0.2.0/24 via 10.0.1.1 dev eth0 table 9876
-ip netns exec ${ns1} nft -f /dev/stdin <<EOF
+ ip -net "$ns1" route add 10.0.2.0/24 via 10.0.1.1 dev eth0 table 9876
+ip netns exec "$ns1" nft -f /dev/stdin <<EOF
flush ruleset
table inet filter {
chain output {
@@ -380,40 +353,35 @@ table inet filter {
}
}
EOF
- ip netns exec ${ns1} ./nf_queue -q 1 -t $timeout &
+ ip netns exec "$ns1" ./nf_queue -q 1 -t "$timeout" &
local nfqpid=$!
- sleep 1
- ip netns exec ${ns1} ip vrf exec tvrf ping -c 1 10.0.2.99 > /dev/null
+ busywait "$BUSYWAIT_TIMEOUT" nf_queue_wait "$ns1" 1
+
+ ip netns exec "$ns1" ip vrf exec tvrf ping -c 1 10.0.2.99 > /dev/null
for n in output post; do
for d in tvrf eth0; do
- ip netns exec ${ns1} nft list chain inet filter $n | grep -q "oifname \"$d\" icmp type echo-request counter packets 1"
- if [ $? -ne 0 ] ; then
+ if ! ip netns exec "$ns1" nft list chain inet filter "$n" | grep -q "oifname \"$d\" icmp type echo-request counter packets 1"; then
echo "FAIL: chain $n: icmp packet counter mismatch for device $d" 1>&2
- ip netns exec ${ns1} nft list ruleset
+ ip netns exec "$ns1" nft list ruleset
ret=1
return
fi
done
done
- wait $nfqpid
- [ $? -eq 0 ] && echo "PASS: icmp+nfqueue via vrf"
+ wait "$nfqpid" && echo "PASS: icmp+nfqueue via vrf"
wait 2>/dev/null
}
-ip netns exec ${nsrouter} sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
-ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
-ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
+ip netns exec "$nsrouter" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
+ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
+ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
load_ruleset "filter" 0
-sleep 3
-
-test_ping
-ret=$?
-if [ $ret -eq 0 ];then
+if test_ping; then
# queue bypass works (rules were skipped, no listener)
echo "PASS: ${ns1} can reach ${ns2}"
else