* [PATCH] tests: shell: Add a test case to verify the limit statement.
@ 2025-06-17 10:41 Yi Chen
2025-06-18 22:46 ` Florian Westphal
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Yi Chen @ 2025-06-17 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
Signed-off-by: Yi Chen <yiche@redhat.com>
---
tests/shell/features/ncat.sh | 4 +
tests/shell/testcases/packetpath/rate_limit | 154 ++++++++++++++++++++
2 files changed, 158 insertions(+)
create mode 100755 tests/shell/features/ncat.sh
create mode 100755 tests/shell/testcases/packetpath/rate_limit
diff --git a/tests/shell/features/ncat.sh b/tests/shell/features/ncat.sh
new file mode 100755
index 00000000..eb1581ce
--- /dev/null
+++ b/tests/shell/features/ncat.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# check whether ncat is installed
+ncat -h >/dev/null 2>&1
diff --git a/tests/shell/testcases/packetpath/rate_limit b/tests/shell/testcases/packetpath/rate_limit
new file mode 100755
index 00000000..d7556edc
--- /dev/null
+++ b/tests/shell/testcases/packetpath/rate_limit
@@ -0,0 +1,154 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_ncat)
+
+cleanup()
+{
+ for i in $C $S;do
+ kill $(ip netns pid $i) 2>/dev/null
+ ip netns del $i
+ done
+ rm -rf $WORKDIR
+}
+trap cleanup EXIT
+
+assert_pass()
+{
+ local ret=$?
+ if [ $ret != 0 ]; then
+ echo "FAIL: ${@}"
+ exit 1
+ else
+ echo "PASS: ${@}"
+ fi
+}
+assert_fail()
+{
+ local ret=$?
+ if [ $ret == 0 ]; then
+ echo "FAIL: ${@}"
+ exit 1
+ else
+ echo "PASS: ${@}"
+ fi
+}
+
+rnd=$(mktemp -u XXXXXXXX)
+C="ratelimit-client-$rnd"
+S="ratelimit-server-$rnd"
+
+ip_sc=10.167.1.1
+ip_cs=10.167.1.2
+ip1_cs=10.167.1.3
+
+ip netns add $S
+ip netns add $C
+
+ip link add s_c netns $S type veth peer name c_s netns $C
+ip -net $S link set s_c up
+ip -net $C link set c_s up
+ip -net $S link set lo up
+ip -net $C link set lo up
+ip -net $S addr add ${ip_sc}/24 dev s_c
+ip -net $C addr add ${ip_cs}/24 dev c_s
+ip -net $C addr add ${ip1_cs}/24 dev c_s
+ip netns exec $C ping ${ip_sc} -c1
+assert_pass "topo initialization"
+
+ip netns exec $S nft -f - <<EOF
+table ip filter {
+ set icmp1 {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ }
+
+ set http1 {
+ type inet_service . ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ip protocol icmp counter jump in_icmp
+ ip protocol tcp counter jump in_tcp
+ }
+ chain in_tcp {
+ iifname "s_c" tcp dport 80 ct state new add @http1 { tcp dport . ip saddr limit rate over 1/minute burst 5 packets } counter reject
+ iifname "s_c" tcp dport 80 counter accept
+ }
+
+ chain in_icmp {
+ iifname "s_c" ip protocol icmp counter update @icmp1 { ip saddr timeout 3s limit rate 1/second burst 5 packets } counter accept
+ iifname "s_c" ip protocol icmp counter reject
+ }
+
+}
+EOF
+assert_pass "Apply ruleset"
+
+# icmp test
+ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip_cs} | grep -q '5 received'
+assert_pass "saddr1, burst 5 accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip1_cs} | grep -q '5 received'
+assert_pass "saddr2, burst 5 accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip_cs} | grep -q '1 received'
+assert_fail "saddr1, burst 5 up to limit, reject"
+
+sleep 3
+ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip_cs} | grep -q '5 received'
+assert_pass "saddr1, element timeout,burst 5 pass again"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip_cs} | grep -q '1 received'
+assert_fail "saddr1, burst 5 up to limit"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 6 -i 1 -I ${ip1_cs} | grep -q '6 received'
+assert_pass "saddr2, 6s test, limit rate 1/second accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 4 -f -I ${ip1_cs} | grep -q '4 received'
+assert_pass "saddr2, burst 4 accept"
+
+sleep 2
+ip netns exec $C ping -W 1 ${ip_sc} -c 2 -f -I ${ip1_cs} | grep -q '2 received'
+assert_pass "saddr2, burst 2 sleep 2, accept"
+
+sleep 2
+ip netns exec $C ping -W 1 ${ip_sc} -c 2 -f -I ${ip1_cs} | grep -q '2 received'
+assert_pass "saddr2, burst 2 sleep 2, accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip1_cs} | grep -q '1 received'
+assert_fail "saddr2, limit rate 1/second up to limit, reject"
+
+
+# tcp test
+ip netns exec $S ncat -lk 80 > /dev/null & sleep 1
+for port in `seq 10000 10004`;do
+ ip netns exec $C ncat ${ip_sc} 80 -p $port -w 1 <<< 'AAA'
+ assert_pass "tcp connection burst 5 accept"
+done
+ip netns exec $C ncat ${ip_sc} 80 -p $port -w 1 <<< 'AAA'
+assert_fail "tcp connection burst 5 up to limit reject"
+
+ip netns exec $S nft flush chain filter in_tcp
+assert_pass result "flush chain"
+
+ip netns exec $S nft flush set filter http1
+assert_pass result "flush set"
+
+ip netns exec $S nft add rule filter in_tcp iifname s_c tcp dport 80 ct state new add @http1 { tcp dport . ip saddr limit rate over 1/second burst 1 packets} counter reject
+assert_pass result "add rule limit rate over 1/second burst 1"
+ip netns exec $S nft add rule filter in_tcp iifname s_c tcp dport 80 counter accept
+
+sleep 1
+ip netns exec $C ncat ${ip_sc} 80 -p 10000 -w 1 <<< 'AAA'
+assert_pass result "tcp connection limit rate 1/sec burst 1 accept"
+
+ip netns exec $C ncat ${ip_sc} 80 -p 10001 -w 1 <<< 'AAA'
+assert_fail result "tcp connection limit rate 1/sec burst 1 reject"
+
+sleep 1
+ip netns exec $C ncat ${ip_sc} 80 -p 10002 -w 1 <<< 'AAA'
+assert_pass result "tcp connection limit rate 1/sec burst 1 accept"
--
2.49.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] tests: shell: Add a test case to verify the limit statement.
2025-06-17 10:41 [PATCH] tests: shell: Add a test case to verify the limit statement Yi Chen
@ 2025-06-18 22:46 ` Florian Westphal
[not found] ` <CAJsUoE0etJbdwHsHFHDnY1CkdmAXLJy7PunwQg9Me4n-AMPWmQ@mail.gmail.com>
2025-06-20 16:40 ` [PATCH] tests: shell: Verify limit statement with new test case Yi Chen
2025-06-20 16:47 ` [PATCH v2] " Yi Chen
2 siblings, 1 reply; 7+ messages in thread
From: Florian Westphal @ 2025-06-18 22:46 UTC (permalink / raw)
To: Yi Chen; +Cc: netfilter-devel
Yi Chen <yiche@redhat.com> wrote:
> Signed-off-by: Yi Chen <yiche@redhat.com>
> ---
> tests/shell/features/ncat.sh | 4 +
> tests/shell/testcases/packetpath/rate_limit | 154 ++++++++++++++++++++
> 2 files changed, 158 insertions(+)
> create mode 100755 tests/shell/features/ncat.sh
> create mode 100755 tests/shell/testcases/packetpath/rate_limit
>
> diff --git a/tests/shell/features/ncat.sh b/tests/shell/features/ncat.sh
> new file mode 100755
> index 00000000..eb1581ce
> --- /dev/null
> +++ b/tests/shell/features/ncat.sh
> @@ -0,0 +1,4 @@
> +#!/bin/sh
> +
> +# check whether ncat is installed
> +ncat -h >/dev/null 2>&1
Could you convert the test to use socat, which is already
used by many other tests?
> +assert_pass()
> +{
> + local ret=$?
> + if [ $ret != 0 ]; then
> + echo "FAIL: ${@}"
> + exit 1
> + else
> + echo "PASS: ${@}"
> + fi
> +}
This is now the 3rd copy of this helper.
Maybe its time to add a library/utility file that has these
functions?
test-wrapper.sh could export an environment variable pointing to it, e.g.
export NFT_TEST_LIBRARY_FILE="$NFT_TEST_BASEDIR/helpers/lib.sh"
or whatever. Then tests can do
. $NFT_TEST_LIBRARY_FILE
and gain these helpers in case they need them.
> +# tcp test
> +ip netns exec $S ncat -lk 80 > /dev/null & sleep 1
I guess sleep 1 is fine. But maybe its time to add a central
helper for this wait.
You could submit a patch that adds the helpers/lib.sh file and
then lifts the "wait_local_port_listen" helper function from
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/diff/tools/testing/selftests/net/lib.sh?id=d9d836bfa5e6e255c411733b4b1ce7a1f8346c54
Other than that I think the test looks good, thanks Yi!
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] tests: shell: Add a test case to verify the limit statement.
[not found] ` <CAJsUoE0etJbdwHsHFHDnY1CkdmAXLJy7PunwQg9Me4n-AMPWmQ@mail.gmail.com>
@ 2025-06-20 9:31 ` Florian Westphal
[not found] ` <CAJsUoE1ZChx7VcbZLnBpwbbkhGmfVVzomHUu7GP8xQCs00gZrw@mail.gmail.com>
0 siblings, 1 reply; 7+ messages in thread
From: Florian Westphal @ 2025-06-20 9:31 UTC (permalink / raw)
To: Yi Chen; +Cc: netfilter-devel
Yi Chen <yiche@redhat.com> wrote:
> > export NFT_TEST_LIBRARY_FILE="$NFT_TEST_BASEDIR/helpers/lib.sh"
> > or whatever. Then tests can do
> > . $NFT_TEST_LIBRARY_FILE
>
> I prefer a single test script that can be executed independently.
Why? Its possible to execute only one test via
tests/shell/run-tests.sh $filename
There is one exeception in the tree:
tests/shell/testcases/transactions/30s-stress
... because that script can be passed a run-time, when
executed as part of the tests it runs for 30s but one
can do "tests/shell/testcases/transactions/30s-stress 600" etc.
Thats also why it does this:
if [ x = x"$NFT" ] ; then
NFT=nft
fi
I missed this earlier when reviewing nft_nat test:
+ ip netns exec $R nft -f - <<-EOF
*ALL* "nft" should be replaced by "$NFT", so when the tests are executed
the locally built nft version, i.e. src/nft, is used, not the system binary.
Also:
tools/check-tree.sh |grep ftp
ERR: "tests/shell/testcases/packetpath/nat_ftp" has no "tests/shell/testcases/packetpath/dumps/nat_ftp.{nft,nodump}" file
In this case it makes sense to add
tests/shell/testcases/packetpath/dumps/nat_ftp.nodump
Can you send a followup patch?
Thanks, and sorry for missing this earlier.
> So, Would you accept something like:
> . $NFT_TEST_LIBRARY_FILE || . ${PWD%%/testcases*}/helpers/lib.sh?
Yes, but only if there is a compelling reason for the stand-alone
requirement.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] tests: shell: Add a test case to verify the limit statement.
[not found] ` <CAJsUoE1ZChx7VcbZLnBpwbbkhGmfVVzomHUu7GP8xQCs00gZrw@mail.gmail.com>
@ 2025-06-20 12:30 ` Yi Chen
0 siblings, 0 replies; 7+ messages in thread
From: Yi Chen @ 2025-06-20 12:30 UTC (permalink / raw)
To: Florian Westphal; +Cc: netfilter-devel
Using tests/shell/run-tests.sh $filename has a small drawback:
when run manually, all output is buffered and only displayed at once
after the script finishes.
I guess it's not a compelling reason, but maybe we can improve the
single test output with unbuffered mode.
nft -> $NFT:
I also noticed it.
Will send out a fix later, thanks!
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] tests: shell: Verify limit statement with new test case.
2025-06-17 10:41 [PATCH] tests: shell: Add a test case to verify the limit statement Yi Chen
2025-06-18 22:46 ` Florian Westphal
@ 2025-06-20 16:40 ` Yi Chen
2025-06-20 16:47 ` [PATCH v2] " Yi Chen
2 siblings, 0 replies; 7+ messages in thread
From: Yi Chen @ 2025-06-20 16:40 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
1. Add rate_limit test case.
2. Consolidate frequently used functions in helper/lib.sh
3. Introduce NFT_TEST_LIBRARY_FILE variable to source helper/lib.sh in
tests.
4. Replace sleep with wait_local_port_listen().
5. Other fixes: nft->$NFT; add dumps/*.nodump files
Signed-off-by: Yi Chen <yiche@redhat.com>
---
tests/shell/helpers/lib.sh | 51 +++++++
tests/shell/helpers/test-wrapper.sh | 1 +
.../testcases/packetpath/dumps/nat_ftp.nodump | 0
.../packetpath/dumps/rate_limit.nodump | 0
tests/shell/testcases/packetpath/flowtables | 32 +---
tests/shell/testcases/packetpath/nat_ftp | 32 ++--
tests/shell/testcases/packetpath/rate_limit | 137 ++++++++++++++++++
7 files changed, 211 insertions(+), 42 deletions(-)
create mode 100755 tests/shell/helpers/lib.sh
create mode 100644 tests/shell/testcases/packetpath/dumps/nat_ftp.nodump
create mode 100644 tests/shell/testcases/packetpath/dumps/rate_limit.nodump
create mode 100755 tests/shell/testcases/packetpath/rate_limit
diff --git a/tests/shell/helpers/lib.sh b/tests/shell/helpers/lib.sh
new file mode 100755
index 00000000..4e01c957
--- /dev/null
+++ b/tests/shell/helpers/lib.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+# Frequently used functions.
+
+wait_local_port_listen()
+{
+ local listener_ns="${1}"
+ local port="${2}"
+ local protocol="${3}"
+ local pattern
+ local i
+
+ pattern=":$(printf "%04X" "${port}") "
+
+ # for tcp protocol additionally check the socket state
+ [ ${protocol} = "tcp" ] && pattern="${pattern}0A"
+ for i in $(seq 10); do
+ if ip netns exec "${listener_ns}" awk '{print $2" "$4}' \
+ /proc/net/"${protocol}"* | grep -q "${pattern}"; then
+ break
+ fi
+ sleep 0.1
+ done
+}
+
+assert_pass()
+{
+ local ret=$?
+ if [ $ret != 0 ]; then
+ echo "FAIL: ${@}"
+ if type -t failout; then
+ failout
+ fi
+ exit 1
+ else
+ echo "PASS: ${@}"
+ fi
+}
+assert_fail()
+{
+ local ret=$?
+ if [ $ret == 0 ]; then
+ echo "FAIL: ${@}"
+ if type -t failout; then
+ failout
+ fi
+ exit 1
+ else
+ echo "PASS: ${@}"
+ fi
+}
diff --git a/tests/shell/helpers/test-wrapper.sh b/tests/shell/helpers/test-wrapper.sh
index 4a7e8b7b..6ec4e030 100755
--- a/tests/shell/helpers/test-wrapper.sh
+++ b/tests/shell/helpers/test-wrapper.sh
@@ -36,6 +36,7 @@ TESTDIR="$(dirname "$TEST")"
START_TIME="$(cut -d ' ' -f1 /proc/uptime)"
export TMPDIR="$NFT_TEST_TESTTMPDIR"
+export NFT_TEST_LIBRARY_FILE="$NFT_TEST_BASEDIR/helpers/lib.sh"
CLEANUP_UMOUNT_VAR_RUN=n
diff --git a/tests/shell/testcases/packetpath/dumps/nat_ftp.nodump b/tests/shell/testcases/packetpath/dumps/nat_ftp.nodump
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/shell/testcases/packetpath/dumps/rate_limit.nodump b/tests/shell/testcases/packetpath/dumps/rate_limit.nodump
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/shell/testcases/packetpath/flowtables b/tests/shell/testcases/packetpath/flowtables
index b68c5dd4..01a775a1 100755
--- a/tests/shell/testcases/packetpath/flowtables
+++ b/tests/shell/testcases/packetpath/flowtables
@@ -3,6 +3,8 @@
# NFT_TEST_REQUIRES(NFT_TEST_HAVE_socat)
# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+. $NFT_TEST_LIBRARY_FILE
+
rnd=$(mktemp -u XXXXXXXX)
R="flowtable-router-$rnd"
C="flowtable-client-$rnd"
@@ -17,29 +19,10 @@ cleanup()
}
trap cleanup EXIT
-assert_pass()
-{
- local ret=$?
- if [ $ret != 0 ]
- then
- echo "FAIL: ${@}"
- ip netns exec $R cat /proc/net/nf_conntrack
- exit 1
- else
- echo "PASS: ${@}"
- fi
-}
-assert_fail()
+# call back when assert failed
+failout()
{
- local ret=$?
- if [ $ret == 0 ]
- then
- echo "FAIL: ${@}"
- ip netns exec $R cat /proc/net/nf_conntrack
- exit 1
- else
- echo "PASS: ${@}"
- fi
+ ip netns exec $R cat /proc/net/nf_conntrack
}
ip netns add $R
@@ -67,7 +50,7 @@ sleep 3
ip netns exec $C ping -q -6 2001:db8:ffff:22::1 -c1
assert_pass "topo initialization"
-ip netns exec $R nft -f - <<EOF
+ip netns exec $R $NFT -f - <<EOF
table ip6 filter {
flowtable f1 {
hook ingress priority -100
@@ -100,7 +83,8 @@ assert_pass "set net.netfilter.nf_conntrack_tcp_timeout_established=86400"
# A trick to control the timing to send a packet
ip netns exec $S socat TCP6-LISTEN:10001 GOPEN:/tmp/socat-$rnd,ignoreeof &
-sleep 1
+wait_local_port_listen $S 10001 tcp
+
ip netns exec $C socat -b 2048 PIPE:/tmp/pipefile-$rnd 'TCP:[2001:db8:ffff:22::1]:10001' &
sleep 1
ip netns exec $C echo "send sth" >> /tmp/pipefile-$rnd ; assert_pass "send a packet"
diff --git a/tests/shell/testcases/packetpath/nat_ftp b/tests/shell/testcases/packetpath/nat_ftp
index 327047b8..4b9f6eb0 100755
--- a/tests/shell/testcases/packetpath/nat_ftp
+++ b/tests/shell/testcases/packetpath/nat_ftp
@@ -4,6 +4,7 @@
# NFT_TEST_REQUIRES(NFT_TEST_HAVE_curl)
# NFT_TEST_REQUIRES(NFT_TEST_HAVE_vsftpd)
+. $NFT_TEST_LIBRARY_FILE
cleanup()
{
for i in $R $C $S;do
@@ -14,22 +15,15 @@ cleanup()
}
trap cleanup EXIT
-assert_pass()
+# call back when assert failed
+failout()
{
- local ret=$?
- if [ $ret != 0 ]
- then
- echo "FAIL: ${@}"
- ip netns exec $R nft list ruleset
- tcpdump -nnr ${PCAP}
- test -r /proc/net/nf_conntrack && ip netns exec $R cat /proc/net/nf_conntrack
- ip netns exec $R conntrack -S
- ip netns exec $R conntrack -L
- ip netns exec $S ss -nitepal
- exit 1
- else
- echo "PASS: ${@}"
- fi
+ ip netns exec $R $NFT list ruleset
+ tcpdump -nnr ${PCAP}
+ test -r /proc/net/nf_conntrack && ip netns exec $R cat /proc/net/nf_conntrack
+ ip netns exec $R conntrack -S
+ ip netns exec $R conntrack -L
+ ip netns exec $S ss -nitepal
}
rnd=$(mktemp -u XXXXXXXX)
@@ -82,7 +76,7 @@ assert_pass "topo initialization"
reload_ruleset()
{
ip netns exec $R conntrack -F 2> /dev/null
- ip netns exec $R nft -f - <<-EOF
+ ip netns exec $R $NFT -f - <<-EOF
flush ruleset
table ip6 ftp_helper_nat_test {
ct helper ftp-standard {
@@ -138,7 +132,8 @@ pam_service_name=vsftpd
background=YES
EOF
ip netns exec $S vsftpd ${FTPCONF}
-sleep 1
+wait_local_port_listen $S 21 tcp
+
ip netns exec $S ss -6ltnp | grep -q '*:21'
assert_pass "start vsftpd server"
@@ -147,7 +142,7 @@ assert_pass "start vsftpd server"
reload_ruleset
ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null &
pid=$!
-sleep 1
+sleep 0.5
ip netns exec $C curl --no-progress-meter --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE
assert_pass "curl ftp passive mode "
@@ -164,6 +159,7 @@ reload_ruleset
ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null &
pid=$!
+sleep 0.5
ip netns exec $C curl --no-progress-meter -P - --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE
assert_pass "curl ftp active mode "
diff --git a/tests/shell/testcases/packetpath/rate_limit b/tests/shell/testcases/packetpath/rate_limit
new file mode 100755
index 00000000..84ee5621
--- /dev/null
+++ b/tests/shell/testcases/packetpath/rate_limit
@@ -0,0 +1,137 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_socat)
+#
+
+. $NFT_TEST_LIBRARY_FILE
+
+cleanup()
+{
+ for i in $C $S;do
+ kill $(ip netns pid $i) 2>/dev/null
+ ip netns del $i
+ done
+}
+trap cleanup EXIT
+
+rnd=$(mktemp -u XXXXXXXX)
+C="ratelimit-client-$rnd"
+S="ratelimit-server-$rnd"
+
+ip_sc=10.167.1.1
+ip_cs=10.167.1.2
+ip1_cs=10.167.1.3
+
+ip netns add $S
+ip netns add $C
+
+ip link add s_c netns $S type veth peer name c_s netns $C
+ip -net $S link set s_c up
+ip -net $C link set c_s up
+ip -net $S link set lo up
+ip -net $C link set lo up
+ip -net $S addr add ${ip_sc}/24 dev s_c
+ip -net $C addr add ${ip_cs}/24 dev c_s
+ip -net $C addr add ${ip1_cs}/24 dev c_s
+ip netns exec $C ping ${ip_sc} -c1
+assert_pass "topo initialization"
+
+ip netns exec $S $NFT -f - <<EOF
+table ip filter {
+ set icmp1 {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ }
+
+ set http1 {
+ type inet_service . ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ip protocol icmp counter jump in_icmp
+ ip protocol tcp counter jump in_tcp
+ }
+ chain in_tcp {
+ iifname "s_c" tcp dport 80 ct state new add @http1 { tcp dport . ip saddr limit rate over 1/minute burst 5 packets } counter reject
+ iifname "s_c" tcp dport 80 counter accept
+ }
+
+ chain in_icmp {
+ iifname "s_c" ip protocol icmp counter update @icmp1 { ip saddr timeout 3s limit rate 1/second burst 5 packets } counter accept
+ iifname "s_c" ip protocol icmp counter reject
+ }
+
+}
+EOF
+assert_pass "Apply ruleset"
+
+# icmp test
+ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip_cs} | grep -q '5 received'
+assert_pass "saddr1, burst 5 accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip1_cs} | grep -q '5 received'
+assert_pass "saddr2, burst 5 accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip_cs} | grep -q '1 received'
+assert_fail "saddr1, burst 5 up to limit, reject"
+
+sleep 3
+ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip_cs} | grep -q '5 received'
+assert_pass "saddr1, element timeout,burst 5 pass again"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip_cs} | grep -q '1 received'
+assert_fail "saddr1, burst 5 up to limit"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 6 -i 1 -I ${ip1_cs} | grep -q '6 received'
+assert_pass "saddr2, 6s test, limit rate 1/second accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 4 -f -I ${ip1_cs} | grep -q '4 received'
+assert_pass "saddr2, burst 4 accept"
+
+sleep 2
+ip netns exec $C ping -W 1 ${ip_sc} -c 2 -f -I ${ip1_cs} | grep -q '2 received'
+assert_pass "saddr2, burst 2 sleep 2, accept"
+
+sleep 2
+ip netns exec $C ping -W 1 ${ip_sc} -c 2 -f -I ${ip1_cs} | grep -q '2 received'
+assert_pass "saddr2, burst 2 sleep 2, accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip1_cs} | grep -q '1 received'
+assert_fail "saddr2, limit rate 1/second up to limit, reject"
+
+
+# tcp test
+ip netns exec $S socat TCP-LISTEN:80,reuseaddr,fork - > /dev/null &
+wait_local_port_listen $S 80 tcp
+
+for port in {1..5};do
+ ip netns exec $C socat -u - TCP:${ip_sc}:80,connect-timeout=1 <<< 'AAA'
+ assert_pass "tcp connection burst 5 accept"
+done
+ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA'
+assert_fail "tcp connection burst 5 up to limit reject"
+
+ip netns exec $S $NFT flush chain filter in_tcp
+assert_pass result "flush chain"
+
+ip netns exec $S $NFT flush set filter http1
+assert_pass result "flush set"
+
+ip netns exec $S $NFT add rule filter in_tcp iifname s_c tcp dport 80 ct state new add @http1 { tcp dport . ip saddr limit rate over 1/second burst 1 packets} counter reject
+assert_pass result "add rule limit rate over 1/second burst 1"
+ip netns exec $S $NFT add rule filter in_tcp iifname s_c tcp dport 80 counter accept
+
+sleep 1
+ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA'
+assert_pass result "tcp connection limit rate 1/sec burst 1 accept"
+
+ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA'
+assert_fail result "tcp connection limit rate 1/sec burst 1 reject"
+
+sleep 1
+ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA'
+assert_pass result "tcp connection limit rate 1/sec burst 1 accept"
--
2.49.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2] tests: shell: Verify limit statement with new test case.
2025-06-17 10:41 [PATCH] tests: shell: Add a test case to verify the limit statement Yi Chen
2025-06-18 22:46 ` Florian Westphal
2025-06-20 16:40 ` [PATCH] tests: shell: Verify limit statement with new test case Yi Chen
@ 2025-06-20 16:47 ` Yi Chen
2025-06-21 11:37 ` Florian Westphal
2 siblings, 1 reply; 7+ messages in thread
From: Yi Chen @ 2025-06-20 16:47 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
1. Add rate_limit test case.
2. Consolidate frequently used functions in helper/lib.sh
3. Introduce NFT_TEST_LIBRARY_FILE variable to source helper/lib.sh in
tests.
4. Replace sleep with wait_local_port_listen().
5. Other fixes: nft->$NFT; add dumps/*.nodump files
Signed-off-by: Yi Chen <yiche@redhat.com>
---
tests/shell/helpers/lib.sh | 51 +++++++
tests/shell/helpers/test-wrapper.sh | 1 +
.../testcases/packetpath/dumps/nat_ftp.nodump | 0
.../packetpath/dumps/rate_limit.nodump | 0
tests/shell/testcases/packetpath/flowtables | 32 +---
tests/shell/testcases/packetpath/nat_ftp | 32 ++--
tests/shell/testcases/packetpath/rate_limit | 137 ++++++++++++++++++
7 files changed, 211 insertions(+), 42 deletions(-)
create mode 100755 tests/shell/helpers/lib.sh
create mode 100644 tests/shell/testcases/packetpath/dumps/nat_ftp.nodump
create mode 100644 tests/shell/testcases/packetpath/dumps/rate_limit.nodump
create mode 100755 tests/shell/testcases/packetpath/rate_limit
diff --git a/tests/shell/helpers/lib.sh b/tests/shell/helpers/lib.sh
new file mode 100755
index 00000000..4e01c957
--- /dev/null
+++ b/tests/shell/helpers/lib.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+# Frequently used functions.
+
+wait_local_port_listen()
+{
+ local listener_ns="${1}"
+ local port="${2}"
+ local protocol="${3}"
+ local pattern
+ local i
+
+ pattern=":$(printf "%04X" "${port}") "
+
+ # for tcp protocol additionally check the socket state
+ [ ${protocol} = "tcp" ] && pattern="${pattern}0A"
+ for i in $(seq 10); do
+ if ip netns exec "${listener_ns}" awk '{print $2" "$4}' \
+ /proc/net/"${protocol}"* | grep -q "${pattern}"; then
+ break
+ fi
+ sleep 0.1
+ done
+}
+
+assert_pass()
+{
+ local ret=$?
+ if [ $ret != 0 ]; then
+ echo "FAIL: ${@}"
+ if type -t failout; then
+ failout
+ fi
+ exit 1
+ else
+ echo "PASS: ${@}"
+ fi
+}
+assert_fail()
+{
+ local ret=$?
+ if [ $ret == 0 ]; then
+ echo "FAIL: ${@}"
+ if type -t failout; then
+ failout
+ fi
+ exit 1
+ else
+ echo "PASS: ${@}"
+ fi
+}
diff --git a/tests/shell/helpers/test-wrapper.sh b/tests/shell/helpers/test-wrapper.sh
index 4a7e8b7b..6ec4e030 100755
--- a/tests/shell/helpers/test-wrapper.sh
+++ b/tests/shell/helpers/test-wrapper.sh
@@ -36,6 +36,7 @@ TESTDIR="$(dirname "$TEST")"
START_TIME="$(cut -d ' ' -f1 /proc/uptime)"
export TMPDIR="$NFT_TEST_TESTTMPDIR"
+export NFT_TEST_LIBRARY_FILE="$NFT_TEST_BASEDIR/helpers/lib.sh"
CLEANUP_UMOUNT_VAR_RUN=n
diff --git a/tests/shell/testcases/packetpath/dumps/nat_ftp.nodump b/tests/shell/testcases/packetpath/dumps/nat_ftp.nodump
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/shell/testcases/packetpath/dumps/rate_limit.nodump b/tests/shell/testcases/packetpath/dumps/rate_limit.nodump
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/shell/testcases/packetpath/flowtables b/tests/shell/testcases/packetpath/flowtables
index b68c5dd4..01a775a1 100755
--- a/tests/shell/testcases/packetpath/flowtables
+++ b/tests/shell/testcases/packetpath/flowtables
@@ -3,6 +3,8 @@
# NFT_TEST_REQUIRES(NFT_TEST_HAVE_socat)
# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+. $NFT_TEST_LIBRARY_FILE
+
rnd=$(mktemp -u XXXXXXXX)
R="flowtable-router-$rnd"
C="flowtable-client-$rnd"
@@ -17,29 +19,10 @@ cleanup()
}
trap cleanup EXIT
-assert_pass()
-{
- local ret=$?
- if [ $ret != 0 ]
- then
- echo "FAIL: ${@}"
- ip netns exec $R cat /proc/net/nf_conntrack
- exit 1
- else
- echo "PASS: ${@}"
- fi
-}
-assert_fail()
+# call back when assert failed
+failout()
{
- local ret=$?
- if [ $ret == 0 ]
- then
- echo "FAIL: ${@}"
- ip netns exec $R cat /proc/net/nf_conntrack
- exit 1
- else
- echo "PASS: ${@}"
- fi
+ ip netns exec $R cat /proc/net/nf_conntrack
}
ip netns add $R
@@ -67,7 +50,7 @@ sleep 3
ip netns exec $C ping -q -6 2001:db8:ffff:22::1 -c1
assert_pass "topo initialization"
-ip netns exec $R nft -f - <<EOF
+ip netns exec $R $NFT -f - <<EOF
table ip6 filter {
flowtable f1 {
hook ingress priority -100
@@ -100,7 +83,8 @@ assert_pass "set net.netfilter.nf_conntrack_tcp_timeout_established=86400"
# A trick to control the timing to send a packet
ip netns exec $S socat TCP6-LISTEN:10001 GOPEN:/tmp/socat-$rnd,ignoreeof &
-sleep 1
+wait_local_port_listen $S 10001 tcp
+
ip netns exec $C socat -b 2048 PIPE:/tmp/pipefile-$rnd 'TCP:[2001:db8:ffff:22::1]:10001' &
sleep 1
ip netns exec $C echo "send sth" >> /tmp/pipefile-$rnd ; assert_pass "send a packet"
diff --git a/tests/shell/testcases/packetpath/nat_ftp b/tests/shell/testcases/packetpath/nat_ftp
index 327047b8..4b9f6eb0 100755
--- a/tests/shell/testcases/packetpath/nat_ftp
+++ b/tests/shell/testcases/packetpath/nat_ftp
@@ -4,6 +4,7 @@
# NFT_TEST_REQUIRES(NFT_TEST_HAVE_curl)
# NFT_TEST_REQUIRES(NFT_TEST_HAVE_vsftpd)
+. $NFT_TEST_LIBRARY_FILE
cleanup()
{
for i in $R $C $S;do
@@ -14,22 +15,15 @@ cleanup()
}
trap cleanup EXIT
-assert_pass()
+# call back when assert failed
+failout()
{
- local ret=$?
- if [ $ret != 0 ]
- then
- echo "FAIL: ${@}"
- ip netns exec $R nft list ruleset
- tcpdump -nnr ${PCAP}
- test -r /proc/net/nf_conntrack && ip netns exec $R cat /proc/net/nf_conntrack
- ip netns exec $R conntrack -S
- ip netns exec $R conntrack -L
- ip netns exec $S ss -nitepal
- exit 1
- else
- echo "PASS: ${@}"
- fi
+ ip netns exec $R $NFT list ruleset
+ tcpdump -nnr ${PCAP}
+ test -r /proc/net/nf_conntrack && ip netns exec $R cat /proc/net/nf_conntrack
+ ip netns exec $R conntrack -S
+ ip netns exec $R conntrack -L
+ ip netns exec $S ss -nitepal
}
rnd=$(mktemp -u XXXXXXXX)
@@ -82,7 +76,7 @@ assert_pass "topo initialization"
reload_ruleset()
{
ip netns exec $R conntrack -F 2> /dev/null
- ip netns exec $R nft -f - <<-EOF
+ ip netns exec $R $NFT -f - <<-EOF
flush ruleset
table ip6 ftp_helper_nat_test {
ct helper ftp-standard {
@@ -138,7 +132,8 @@ pam_service_name=vsftpd
background=YES
EOF
ip netns exec $S vsftpd ${FTPCONF}
-sleep 1
+wait_local_port_listen $S 21 tcp
+
ip netns exec $S ss -6ltnp | grep -q '*:21'
assert_pass "start vsftpd server"
@@ -147,7 +142,7 @@ assert_pass "start vsftpd server"
reload_ruleset
ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null &
pid=$!
-sleep 1
+sleep 0.5
ip netns exec $C curl --no-progress-meter --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE
assert_pass "curl ftp passive mode "
@@ -164,6 +159,7 @@ reload_ruleset
ip netns exec $S tcpdump -q --immediate-mode -Ui s_r -w ${PCAP} 2> /dev/null &
pid=$!
+sleep 0.5
ip netns exec $C curl --no-progress-meter -P - --connect-timeout 5 ftp://[${ip_rc}]:2121/$(basename $INFILE) -o $OUTFILE
assert_pass "curl ftp active mode "
diff --git a/tests/shell/testcases/packetpath/rate_limit b/tests/shell/testcases/packetpath/rate_limit
new file mode 100755
index 00000000..84ee5621
--- /dev/null
+++ b/tests/shell/testcases/packetpath/rate_limit
@@ -0,0 +1,137 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_socat)
+#
+
+. $NFT_TEST_LIBRARY_FILE
+
+cleanup()
+{
+ for i in $C $S;do
+ kill $(ip netns pid $i) 2>/dev/null
+ ip netns del $i
+ done
+}
+trap cleanup EXIT
+
+rnd=$(mktemp -u XXXXXXXX)
+C="ratelimit-client-$rnd"
+S="ratelimit-server-$rnd"
+
+ip_sc=10.167.1.1
+ip_cs=10.167.1.2
+ip1_cs=10.167.1.3
+
+ip netns add $S
+ip netns add $C
+
+ip link add s_c netns $S type veth peer name c_s netns $C
+ip -net $S link set s_c up
+ip -net $C link set c_s up
+ip -net $S link set lo up
+ip -net $C link set lo up
+ip -net $S addr add ${ip_sc}/24 dev s_c
+ip -net $C addr add ${ip_cs}/24 dev c_s
+ip -net $C addr add ${ip1_cs}/24 dev c_s
+ip netns exec $C ping ${ip_sc} -c1
+assert_pass "topo initialization"
+
+ip netns exec $S $NFT -f - <<EOF
+table ip filter {
+ set icmp1 {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ }
+
+ set http1 {
+ type inet_service . ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ip protocol icmp counter jump in_icmp
+ ip protocol tcp counter jump in_tcp
+ }
+ chain in_tcp {
+ iifname "s_c" tcp dport 80 ct state new add @http1 { tcp dport . ip saddr limit rate over 1/minute burst 5 packets } counter reject
+ iifname "s_c" tcp dport 80 counter accept
+ }
+
+ chain in_icmp {
+ iifname "s_c" ip protocol icmp counter update @icmp1 { ip saddr timeout 3s limit rate 1/second burst 5 packets } counter accept
+ iifname "s_c" ip protocol icmp counter reject
+ }
+
+}
+EOF
+assert_pass "Apply ruleset"
+
+# icmp test
+ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip_cs} | grep -q '5 received'
+assert_pass "saddr1, burst 5 accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip1_cs} | grep -q '5 received'
+assert_pass "saddr2, burst 5 accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip_cs} | grep -q '1 received'
+assert_fail "saddr1, burst 5 up to limit, reject"
+
+sleep 3
+ip netns exec $C ping -W 1 ${ip_sc} -c 5 -f -I ${ip_cs} | grep -q '5 received'
+assert_pass "saddr1, element timeout,burst 5 pass again"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip_cs} | grep -q '1 received'
+assert_fail "saddr1, burst 5 up to limit"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 6 -i 1 -I ${ip1_cs} | grep -q '6 received'
+assert_pass "saddr2, 6s test, limit rate 1/second accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 4 -f -I ${ip1_cs} | grep -q '4 received'
+assert_pass "saddr2, burst 4 accept"
+
+sleep 2
+ip netns exec $C ping -W 1 ${ip_sc} -c 2 -f -I ${ip1_cs} | grep -q '2 received'
+assert_pass "saddr2, burst 2 sleep 2, accept"
+
+sleep 2
+ip netns exec $C ping -W 1 ${ip_sc} -c 2 -f -I ${ip1_cs} | grep -q '2 received'
+assert_pass "saddr2, burst 2 sleep 2, accept"
+
+ip netns exec $C ping -W 1 ${ip_sc} -c 1 -f -I ${ip1_cs} | grep -q '1 received'
+assert_fail "saddr2, limit rate 1/second up to limit, reject"
+
+
+# tcp test
+ip netns exec $S socat TCP-LISTEN:80,reuseaddr,fork - > /dev/null &
+wait_local_port_listen $S 80 tcp
+
+for port in {1..5};do
+ ip netns exec $C socat -u - TCP:${ip_sc}:80,connect-timeout=1 <<< 'AAA'
+ assert_pass "tcp connection burst 5 accept"
+done
+ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA'
+assert_fail "tcp connection burst 5 up to limit reject"
+
+ip netns exec $S $NFT flush chain filter in_tcp
+assert_pass result "flush chain"
+
+ip netns exec $S $NFT flush set filter http1
+assert_pass result "flush set"
+
+ip netns exec $S $NFT add rule filter in_tcp iifname s_c tcp dport 80 ct state new add @http1 { tcp dport . ip saddr limit rate over 1/second burst 1 packets} counter reject
+assert_pass result "add rule limit rate over 1/second burst 1"
+ip netns exec $S $NFT add rule filter in_tcp iifname s_c tcp dport 80 counter accept
+
+sleep 1
+ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA'
+assert_pass result "tcp connection limit rate 1/sec burst 1 accept"
+
+ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA'
+assert_fail result "tcp connection limit rate 1/sec burst 1 reject"
+
+sleep 1
+ip netns exec $C socat -u - TCP:${ip_sc}:80,reuseport,connect-timeout=1 <<< 'AAA'
+assert_pass result "tcp connection limit rate 1/sec burst 1 accept"
--
2.49.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v2] tests: shell: Verify limit statement with new test case.
2025-06-20 16:47 ` [PATCH v2] " Yi Chen
@ 2025-06-21 11:37 ` Florian Westphal
0 siblings, 0 replies; 7+ messages in thread
From: Florian Westphal @ 2025-06-21 11:37 UTC (permalink / raw)
To: Yi Chen; +Cc: netfilter-devel
Yi Chen <yiche@redhat.com> wrote:
> 1. Add rate_limit test case.
> 2. Consolidate frequently used functions in helper/lib.sh
> 3. Introduce NFT_TEST_LIBRARY_FILE variable to source helper/lib.sh in
> tests.
> 4. Replace sleep with wait_local_port_listen().
> 5. Other fixes: nft->$NFT; add dumps/*.nodump files
This is hard to review, can you split this in multiple patches
to make it easier? We prefer to have one logical patch per change.
For example:
Patch1: don't use system nft binary
You can also add the .nodump file in this patch.
Patch 2:
Consolidate frequently used functions in helper/lib.sh
This also adds the NFT_TEST_LIBRARY_FILE environment variable
and would switch nat_ftp and flowtables to use it.
Patch 3: add and use wait_local_port_listen
This would add the helper and convert sleeps after listener to use
the new helper.
Patch 4:
Adds the new rate_limit test case and a nodump file.
I mean, the changes look good to me but I think its too big
for one single change.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-06-21 11:37 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-17 10:41 [PATCH] tests: shell: Add a test case to verify the limit statement Yi Chen
2025-06-18 22:46 ` Florian Westphal
[not found] ` <CAJsUoE0etJbdwHsHFHDnY1CkdmAXLJy7PunwQg9Me4n-AMPWmQ@mail.gmail.com>
2025-06-20 9:31 ` Florian Westphal
[not found] ` <CAJsUoE1ZChx7VcbZLnBpwbbkhGmfVVzomHUu7GP8xQCs00gZrw@mail.gmail.com>
2025-06-20 12:30 ` Yi Chen
2025-06-20 16:40 ` [PATCH] tests: shell: Verify limit statement with new test case Yi Chen
2025-06-20 16:47 ` [PATCH v2] " Yi Chen
2025-06-21 11:37 ` Florian Westphal
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.