mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-04-03 12:05:13 +02:00
[ Upstream commita73ca0449b] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
125 lines
2.6 KiB
C
125 lines
2.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
static void set_addr(struct sockaddr_storage *ss, char *ip, char *port, int *len)
|
|
{
|
|
if (ss->ss_family == AF_INET) {
|
|
struct sockaddr_in *a = (struct sockaddr_in *)ss;
|
|
|
|
a->sin_addr.s_addr = inet_addr(ip);
|
|
a->sin_port = htons(atoi(port));
|
|
*len = sizeof(*a);
|
|
} else {
|
|
struct sockaddr_in6 *a = (struct sockaddr_in6 *)ss;
|
|
|
|
a->sin6_family = AF_INET6;
|
|
inet_pton(AF_INET6, ip, &a->sin6_addr);
|
|
a->sin6_port = htons(atoi(port));
|
|
*len = sizeof(*a);
|
|
}
|
|
}
|
|
|
|
static int do_client(int argc, char *argv[])
|
|
{
|
|
struct sockaddr_storage ss;
|
|
int csk, ret, len;
|
|
|
|
if (argc < 5) {
|
|
printf("%s client -4|6 IP PORT [IP PORT]\n", argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
bzero((void *)&ss, sizeof(ss));
|
|
ss.ss_family = !strcmp(argv[2], "-4") ? AF_INET : AF_INET6;
|
|
csk = socket(ss.ss_family, SOCK_STREAM, IPPROTO_SCTP);
|
|
if (csk < 0) {
|
|
printf("failed to create socket\n");
|
|
return -1;
|
|
}
|
|
|
|
if (argc >= 7) {
|
|
set_addr(&ss, argv[5], argv[6], &len);
|
|
ret = bind(csk, (struct sockaddr *)&ss, len);
|
|
if (ret < 0) {
|
|
printf("failed to bind to address\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
set_addr(&ss, argv[3], argv[4], &len);
|
|
ret = connect(csk, (struct sockaddr *)&ss, len);
|
|
if (ret < 0)
|
|
return -1;
|
|
|
|
recv(csk, NULL, 0, 0);
|
|
close(csk);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct sockaddr_storage ss;
|
|
int lsk, csk, ret, len;
|
|
|
|
if (argc < 2 || (strcmp(argv[1], "server") && strcmp(argv[1], "client"))) {
|
|
printf("%s server|client ...\n", argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
if (!strcmp(argv[1], "client"))
|
|
return do_client(argc, argv);
|
|
|
|
if (argc < 5) {
|
|
printf("%s server -4|6 IP PORT [IFACE]\n", argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
ss.ss_family = !strcmp(argv[2], "-4") ? AF_INET : AF_INET6;
|
|
lsk = socket(ss.ss_family, SOCK_STREAM, IPPROTO_SCTP);
|
|
if (lsk < 0) {
|
|
printf("failed to create lsk\n");
|
|
return -1;
|
|
}
|
|
|
|
if (argc >= 6) {
|
|
ret = setsockopt(lsk, SOL_SOCKET, SO_BINDTODEVICE,
|
|
argv[5], strlen(argv[5]) + 1);
|
|
if (ret < 0) {
|
|
printf("failed to bind to device\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
set_addr(&ss, argv[3], argv[4], &len);
|
|
ret = bind(lsk, (struct sockaddr *)&ss, len);
|
|
if (ret < 0) {
|
|
printf("failed to bind to address\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = listen(lsk, 5);
|
|
if (ret < 0) {
|
|
printf("failed to listen on port\n");
|
|
return -1;
|
|
}
|
|
|
|
csk = accept(lsk, (struct sockaddr *)NULL, (socklen_t *)NULL);
|
|
if (csk < 0) {
|
|
printf("failed to accept new client\n");
|
|
return -1;
|
|
}
|
|
|
|
close(csk);
|
|
close(lsk);
|
|
|
|
return 0;
|
|
}
|