Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: net: fix server bind failure in sctp_vrf.sh

sctp_vrf.sh could fail:

TEST 12: bind vrf-2 & 1 in server, connect from client 1 & 2, N [FAIL]
not ok 1 selftests: net: sctp_vrf.sh # exit=3

The failure happens when the server bind in a new run conflicts with an
existing association from the previous run:

[1] ip netns exec $SERVER_NS ./sctp_hello server ...
[2] ip netns exec $CLIENT_NS ./sctp_hello client ...
[3] ip netns exec $SERVER_NS pkill sctp_hello ...
[4] ip netns exec $SERVER_NS ./sctp_hello server ...

It occurs if the client in [2] sends a message and closes immediately.
With the message unacked, no SHUTDOWN is sent. Killing the server in [3]
triggers a SHUTDOWN the client also ignores due to the unacked message,
leaving the old association alive. This causes the bind at [4] to fail
until the message is acked and the client responds to a second SHUTDOWN
after the server’s T2 timer expires (3s).

This patch fixes the issue by preventing the client from sending data.
Instead, the client blocks on recv() and waits for the server to close.
It also waits until both the server and the client sockets are fully
released in stop_server and wait_client before restarting.

Additionally, replace 2>&1 >/dev/null with -q in sysctl and grep, and
drop other redundant 2>&1 >/dev/null redirections, and fix a typo from
N to Y (connect successfully) in the description of the last test.

Fixes: a61bd7b9fef3 ("selftests: add a selftest for sctp vrf")
Reported-by: Hangbin Liu <liuhangbin@gmail.com>
Tested-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/be2dacf52d0917c4ba5e2e8c5a9cb640740ad2b6.1760731574.git.lucien.xin@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Xin Long and committed by
Jakub Kicinski
a73ca044 ffff5c8f

+47 -43
+2 -15
tools/testing/selftests/net/sctp_hello.c
··· 29 29 static int do_client(int argc, char *argv[]) 30 30 { 31 31 struct sockaddr_storage ss; 32 - char buf[] = "hello"; 33 32 int csk, ret, len; 34 33 35 34 if (argc < 5) { ··· 55 56 56 57 set_addr(&ss, argv[3], argv[4], &len); 57 58 ret = connect(csk, (struct sockaddr *)&ss, len); 58 - if (ret < 0) { 59 - printf("failed to connect to peer\n"); 59 + if (ret < 0) 60 60 return -1; 61 - } 62 61 63 - ret = send(csk, buf, strlen(buf) + 1, 0); 64 - if (ret < 0) { 65 - printf("failed to send msg %d\n", ret); 66 - return -1; 67 - } 62 + recv(csk, NULL, 0, 0); 68 63 close(csk); 69 64 70 65 return 0; ··· 68 75 { 69 76 struct sockaddr_storage ss; 70 77 int lsk, csk, ret, len; 71 - char buf[20]; 72 78 73 79 if (argc < 2 || (strcmp(argv[1], "server") && strcmp(argv[1], "client"))) { 74 80 printf("%s server|client ...\n", argv[0]); ··· 117 125 return -1; 118 126 } 119 127 120 - ret = recv(csk, buf, sizeof(buf), 0); 121 - if (ret <= 0) { 122 - printf("failed to recv msg %d\n", ret); 123 - return -1; 124 - } 125 128 close(csk); 126 129 close(lsk); 127 130
+45 -28
tools/testing/selftests/net/sctp_vrf.sh
··· 20 20 modprobe sctp_diag 21 21 setup_ns CLIENT_NS1 CLIENT_NS2 SERVER_NS 22 22 23 - ip net exec $CLIENT_NS1 sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null 24 - ip net exec $CLIENT_NS2 sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null 25 - ip net exec $SERVER_NS sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null 23 + ip net exec $CLIENT_NS1 sysctl -wq net.ipv6.conf.default.accept_dad=0 24 + ip net exec $CLIENT_NS2 sysctl -wq net.ipv6.conf.default.accept_dad=0 25 + ip net exec $SERVER_NS sysctl -wq net.ipv6.conf.default.accept_dad=0 26 26 27 27 ip -n $SERVER_NS link add veth1 type veth peer name veth1 netns $CLIENT_NS1 28 28 ip -n $SERVER_NS link add veth2 type veth peer name veth1 netns $CLIENT_NS2 ··· 62 62 } 63 63 64 64 cleanup() { 65 - ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null 65 + wait_client $CLIENT_NS1 66 + wait_client $CLIENT_NS2 67 + stop_server 66 68 cleanup_ns $CLIENT_NS1 $CLIENT_NS2 $SERVER_NS 67 69 } 68 70 69 - wait_server() { 71 + start_server() { 70 72 local IFACE=$1 71 73 local CNT=0 72 74 73 - until ip netns exec $SERVER_NS ss -lS src $SERVER_IP:$SERVER_PORT | \ 74 - grep LISTEN | grep "$IFACE" 2>&1 >/dev/null; do 75 - [ $((CNT++)) = "20" ] && { RET=3; return $RET; } 75 + ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP $SERVER_PORT $IFACE & 76 + disown 77 + until ip netns exec $SERVER_NS ss -SlH | grep -q "$IFACE"; do 78 + [ $((CNT++)) -eq 30 ] && { RET=3; return $RET; } 79 + sleep 0.1 80 + done 81 + } 82 + 83 + stop_server() { 84 + local CNT=0 85 + 86 + ip netns exec $SERVER_NS pkill sctp_hello 87 + while ip netns exec $SERVER_NS ss -SaH | grep -q .; do 88 + [ $((CNT++)) -eq 30 ] && break 89 + sleep 0.1 90 + done 91 + } 92 + 93 + wait_client() { 94 + local CLIENT_NS=$1 95 + local CNT=0 96 + 97 + while ip netns exec $CLIENT_NS ss -SaH | grep -q .; do 98 + [ $((CNT++)) -eq 30 ] && break 76 99 sleep 0.1 77 100 done 78 101 } ··· 104 81 local CLIENT_NS=$1 105 82 local IFACE=$2 106 83 107 - ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null 108 - ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP \ 109 - $SERVER_PORT $IFACE 2>&1 >/dev/null & 110 - disown 111 - wait_server $IFACE || return $RET 84 + start_server $IFACE || return $RET 112 85 timeout 3 ip netns exec $CLIENT_NS ./sctp_hello client $AF \ 113 - $SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 2>&1 >/dev/null 86 + $SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 114 87 RET=$? 88 + wait_client $CLIENT_NS 89 + stop_server 115 90 return $RET 116 91 } 117 92 ··· 117 96 local IFACE1=$1 118 97 local IFACE2=$2 119 98 120 - ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null 121 - ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP \ 122 - $SERVER_PORT $IFACE1 2>&1 >/dev/null & 123 - disown 124 - wait_server $IFACE1 || return $RET 125 - ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP \ 126 - $SERVER_PORT $IFACE2 2>&1 >/dev/null & 127 - disown 128 - wait_server $IFACE2 || return $RET 99 + start_server $IFACE1 || return $RET 100 + start_server $IFACE2 || return $RET 129 101 timeout 3 ip netns exec $CLIENT_NS1 ./sctp_hello client $AF \ 130 - $SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 2>&1 >/dev/null && \ 102 + $SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT && \ 131 103 timeout 3 ip netns exec $CLIENT_NS2 ./sctp_hello client $AF \ 132 - $SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 2>&1 >/dev/null 104 + $SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 133 105 RET=$? 106 + wait_client $CLIENT_NS1 107 + wait_client $CLIENT_NS2 108 + stop_server 134 109 return $RET 135 110 } 136 111 137 112 testup() { 138 - ip netns exec $SERVER_NS sysctl -w net.sctp.l3mdev_accept=1 2>&1 >/dev/null 113 + ip netns exec $SERVER_NS sysctl -wq net.sctp.l3mdev_accept=1 139 114 echo -n "TEST 01: nobind, connect from client 1, l3mdev_accept=1, Y " 140 115 do_test $CLIENT_NS1 || { echo "[FAIL]"; return $RET; } 141 116 echo "[PASS]" ··· 140 123 do_test $CLIENT_NS2 && { echo "[FAIL]"; return $RET; } 141 124 echo "[PASS]" 142 125 143 - ip netns exec $SERVER_NS sysctl -w net.sctp.l3mdev_accept=0 2>&1 >/dev/null 126 + ip netns exec $SERVER_NS sysctl -wq net.sctp.l3mdev_accept=0 144 127 echo -n "TEST 03: nobind, connect from client 1, l3mdev_accept=0, N " 145 128 do_test $CLIENT_NS1 && { echo "[FAIL]"; return $RET; } 146 129 echo "[PASS]" ··· 177 160 do_testx vrf-1 vrf-2 || { echo "[FAIL]"; return $RET; } 178 161 echo "[PASS]" 179 162 180 - echo -n "TEST 12: bind vrf-2 & 1 in server, connect from client 1 & 2, N " 163 + echo -n "TEST 12: bind vrf-2 & 1 in server, connect from client 1 & 2, Y " 181 164 do_testx vrf-2 vrf-1 || { echo "[FAIL]"; return $RET; } 182 165 echo "[PASS]" 183 166 }