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: a61bd7b9fe ("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>
This commit is contained in:
Xin Long
2025-10-17 16:06:14 -04:00
committed by Jakub Kicinski
parent ffff5c8fc2
commit a73ca0449b
2 changed files with 47 additions and 43 deletions

View File

@@ -29,7 +29,6 @@ static void set_addr(struct sockaddr_storage *ss, char *ip, char *port, int *len
static int do_client(int argc, char *argv[])
{
struct sockaddr_storage ss;
char buf[] = "hello";
int csk, ret, len;
if (argc < 5) {
@@ -56,16 +55,10 @@ static int do_client(int argc, char *argv[])
set_addr(&ss, argv[3], argv[4], &len);
ret = connect(csk, (struct sockaddr *)&ss, len);
if (ret < 0) {
printf("failed to connect to peer\n");
if (ret < 0)
return -1;
}
ret = send(csk, buf, strlen(buf) + 1, 0);
if (ret < 0) {
printf("failed to send msg %d\n", ret);
return -1;
}
recv(csk, NULL, 0, 0);
close(csk);
return 0;
@@ -75,7 +68,6 @@ int main(int argc, char *argv[])
{
struct sockaddr_storage ss;
int lsk, csk, ret, len;
char buf[20];
if (argc < 2 || (strcmp(argv[1], "server") && strcmp(argv[1], "client"))) {
printf("%s server|client ...\n", argv[0]);
@@ -125,11 +117,6 @@ int main(int argc, char *argv[])
return -1;
}
ret = recv(csk, buf, sizeof(buf), 0);
if (ret <= 0) {
printf("failed to recv msg %d\n", ret);
return -1;
}
close(csk);
close(lsk);

View File

@@ -20,9 +20,9 @@ setup() {
modprobe sctp_diag
setup_ns CLIENT_NS1 CLIENT_NS2 SERVER_NS
ip net exec $CLIENT_NS1 sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null
ip net exec $CLIENT_NS2 sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null
ip net exec $SERVER_NS sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null
ip net exec $CLIENT_NS1 sysctl -wq net.ipv6.conf.default.accept_dad=0
ip net exec $CLIENT_NS2 sysctl -wq net.ipv6.conf.default.accept_dad=0
ip net exec $SERVER_NS sysctl -wq net.ipv6.conf.default.accept_dad=0
ip -n $SERVER_NS link add veth1 type veth peer name veth1 netns $CLIENT_NS1
ip -n $SERVER_NS link add veth2 type veth peer name veth1 netns $CLIENT_NS2
@@ -62,17 +62,40 @@ setup() {
}
cleanup() {
ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null
wait_client $CLIENT_NS1
wait_client $CLIENT_NS2
stop_server
cleanup_ns $CLIENT_NS1 $CLIENT_NS2 $SERVER_NS
}
wait_server() {
start_server() {
local IFACE=$1
local CNT=0
until ip netns exec $SERVER_NS ss -lS src $SERVER_IP:$SERVER_PORT | \
grep LISTEN | grep "$IFACE" 2>&1 >/dev/null; do
[ $((CNT++)) = "20" ] && { RET=3; return $RET; }
ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP $SERVER_PORT $IFACE &
disown
until ip netns exec $SERVER_NS ss -SlH | grep -q "$IFACE"; do
[ $((CNT++)) -eq 30 ] && { RET=3; return $RET; }
sleep 0.1
done
}
stop_server() {
local CNT=0
ip netns exec $SERVER_NS pkill sctp_hello
while ip netns exec $SERVER_NS ss -SaH | grep -q .; do
[ $((CNT++)) -eq 30 ] && break
sleep 0.1
done
}
wait_client() {
local CLIENT_NS=$1
local CNT=0
while ip netns exec $CLIENT_NS ss -SaH | grep -q .; do
[ $((CNT++)) -eq 30 ] && break
sleep 0.1
done
}
@@ -81,14 +104,12 @@ do_test() {
local CLIENT_NS=$1
local IFACE=$2
ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null
ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP \
$SERVER_PORT $IFACE 2>&1 >/dev/null &
disown
wait_server $IFACE || return $RET
start_server $IFACE || return $RET
timeout 3 ip netns exec $CLIENT_NS ./sctp_hello client $AF \
$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 2>&1 >/dev/null
$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT
RET=$?
wait_client $CLIENT_NS
stop_server
return $RET
}
@@ -96,25 +117,21 @@ do_testx() {
local IFACE1=$1
local IFACE2=$2
ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null
ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP \
$SERVER_PORT $IFACE1 2>&1 >/dev/null &
disown
wait_server $IFACE1 || return $RET
ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP \
$SERVER_PORT $IFACE2 2>&1 >/dev/null &
disown
wait_server $IFACE2 || return $RET
start_server $IFACE1 || return $RET
start_server $IFACE2 || return $RET
timeout 3 ip netns exec $CLIENT_NS1 ./sctp_hello client $AF \
$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 2>&1 >/dev/null && \
$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT && \
timeout 3 ip netns exec $CLIENT_NS2 ./sctp_hello client $AF \
$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 2>&1 >/dev/null
$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT
RET=$?
wait_client $CLIENT_NS1
wait_client $CLIENT_NS2
stop_server
return $RET
}
testup() {
ip netns exec $SERVER_NS sysctl -w net.sctp.l3mdev_accept=1 2>&1 >/dev/null
ip netns exec $SERVER_NS sysctl -wq net.sctp.l3mdev_accept=1
echo -n "TEST 01: nobind, connect from client 1, l3mdev_accept=1, Y "
do_test $CLIENT_NS1 || { echo "[FAIL]"; return $RET; }
echo "[PASS]"
@@ -123,7 +140,7 @@ testup() {
do_test $CLIENT_NS2 && { echo "[FAIL]"; return $RET; }
echo "[PASS]"
ip netns exec $SERVER_NS sysctl -w net.sctp.l3mdev_accept=0 2>&1 >/dev/null
ip netns exec $SERVER_NS sysctl -wq net.sctp.l3mdev_accept=0
echo -n "TEST 03: nobind, connect from client 1, l3mdev_accept=0, N "
do_test $CLIENT_NS1 && { echo "[FAIL]"; return $RET; }
echo "[PASS]"
@@ -160,7 +177,7 @@ testup() {
do_testx vrf-1 vrf-2 || { echo "[FAIL]"; return $RET; }
echo "[PASS]"
echo -n "TEST 12: bind vrf-2 & 1 in server, connect from client 1 & 2, N "
echo -n "TEST 12: bind vrf-2 & 1 in server, connect from client 1 & 2, Y "
do_testx vrf-2 vrf-1 || { echo "[FAIL]"; return $RET; }
echo "[PASS]"
}