mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 02:53:36 +02:00
Merge branch 'selftests/bpf: Various sockmap-related fixes'
Michal Luczaj says: ==================== Series takes care of few bugs and missing features with the aim to improve the test coverage of sockmap/sockhash. Last patch is a create_pair() rewrite making use of __attribute__((cleanup)) to handle socket fd lifetime. --- Changes in v2: - Rebase on bpf-next (Jakub) - Use cleanup helpers from kernel's cleanup.h (Jakub) - Fix subject of patch 3, rephrase patch 4, use correct prefix - Link to v1: https://lore.kernel.org/r/20240724-sockmap-selftest-fixes-v1-0-46165d224712@rbox.co Changes in v1: - No declarations in function body (Jakub) - Don't touch output arguments until function succeeds (Jakub) - Link to v0: https://lore.kernel.org/netdev/027fdb41-ee11-4be0-a493-22f28a1abd7c@rbox.co/ ==================== Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
This commit is contained in:
commit
db16377801
|
|
@ -451,11 +451,11 @@ static void test_sockmap_progs_query(enum bpf_attach_type attach_type)
|
|||
#define MAX_EVENTS 10
|
||||
static void test_sockmap_skb_verdict_shutdown(void)
|
||||
{
|
||||
int n, err, map, verdict, c1 = -1, p1 = -1;
|
||||
struct epoll_event ev, events[MAX_EVENTS];
|
||||
int n, err, map, verdict, s, c1 = -1, p1 = -1;
|
||||
struct test_sockmap_pass_prog *skel;
|
||||
int epollfd;
|
||||
int zero = 0;
|
||||
int epollfd;
|
||||
char b;
|
||||
|
||||
skel = test_sockmap_pass_prog__open_and_load();
|
||||
|
|
@ -469,10 +469,7 @@ static void test_sockmap_skb_verdict_shutdown(void)
|
|||
if (!ASSERT_OK(err, "bpf_prog_attach"))
|
||||
goto out;
|
||||
|
||||
s = socket_loopback(AF_INET, SOCK_STREAM);
|
||||
if (s < 0)
|
||||
goto out;
|
||||
err = create_pair(s, AF_INET, SOCK_STREAM, &c1, &p1);
|
||||
err = create_pair(AF_INET, SOCK_STREAM, &c1, &p1);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
|
|
@ -506,8 +503,8 @@ static void test_sockmap_skb_verdict_shutdown(void)
|
|||
|
||||
static void test_sockmap_skb_verdict_fionread(bool pass_prog)
|
||||
{
|
||||
int err, map, verdict, c0 = -1, c1 = -1, p0 = -1, p1 = -1;
|
||||
int expected, zero = 0, sent, recvd, avail;
|
||||
int err, map, verdict, s, c0 = -1, c1 = -1, p0 = -1, p1 = -1;
|
||||
struct test_sockmap_pass_prog *pass = NULL;
|
||||
struct test_sockmap_drop_prog *drop = NULL;
|
||||
char buf[256] = "0123456789";
|
||||
|
|
@ -534,11 +531,8 @@ static void test_sockmap_skb_verdict_fionread(bool pass_prog)
|
|||
if (!ASSERT_OK(err, "bpf_prog_attach"))
|
||||
goto out;
|
||||
|
||||
s = socket_loopback(AF_INET, SOCK_STREAM);
|
||||
if (!ASSERT_GT(s, -1, "socket_loopback(s)"))
|
||||
goto out;
|
||||
err = create_socket_pairs(s, AF_INET, SOCK_STREAM, &c0, &c1, &p0, &p1);
|
||||
if (!ASSERT_OK(err, "create_socket_pairs(s)"))
|
||||
err = create_socket_pairs(AF_INET, SOCK_STREAM, &c0, &c1, &p0, &p1);
|
||||
if (!ASSERT_OK(err, "create_socket_pairs()"))
|
||||
goto out;
|
||||
|
||||
err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
|
||||
|
|
@ -570,16 +564,12 @@ static void test_sockmap_skb_verdict_fionread(bool pass_prog)
|
|||
|
||||
static void test_sockmap_skb_verdict_peek_helper(int map)
|
||||
{
|
||||
int err, s, c1, p1, zero = 0, sent, recvd, avail;
|
||||
int err, c1, p1, zero = 0, sent, recvd, avail;
|
||||
char snd[256] = "0123456789";
|
||||
char rcv[256] = "0";
|
||||
|
||||
s = socket_loopback(AF_INET, SOCK_STREAM);
|
||||
if (!ASSERT_GT(s, -1, "socket_loopback(s)"))
|
||||
return;
|
||||
|
||||
err = create_pair(s, AF_INET, SOCK_STREAM, &c1, &p1);
|
||||
if (!ASSERT_OK(err, "create_pairs(s)"))
|
||||
err = create_pair(AF_INET, SOCK_STREAM, &c1, &p1);
|
||||
if (!ASSERT_OK(err, "create_pair()"))
|
||||
return;
|
||||
|
||||
err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include <linux/vm_sockets.h>
|
||||
|
||||
/* include/linux/net.h */
|
||||
#define SOCK_TYPE_MASK 0xf
|
||||
|
||||
#define IO_TIMEOUT_SEC 30
|
||||
#define MAX_STRERR_LEN 256
|
||||
#define MAX_TEST_NAME 80
|
||||
|
|
@ -14,6 +17,17 @@
|
|||
|
||||
#define __always_unused __attribute__((__unused__))
|
||||
|
||||
/* include/linux/cleanup.h */
|
||||
#define __get_and_null(p, nullvalue) \
|
||||
({ \
|
||||
__auto_type __ptr = &(p); \
|
||||
__auto_type __val = *__ptr; \
|
||||
*__ptr = nullvalue; \
|
||||
__val; \
|
||||
})
|
||||
|
||||
#define take_fd(fd) __get_and_null(fd, -EBADF)
|
||||
|
||||
#define _FAIL(errnum, fmt...) \
|
||||
({ \
|
||||
error_at_line(0, (errnum), __func__, __LINE__, fmt); \
|
||||
|
|
@ -179,6 +193,14 @@
|
|||
__ret; \
|
||||
})
|
||||
|
||||
static inline void close_fd(int *fd)
|
||||
{
|
||||
if (*fd >= 0)
|
||||
xclose(*fd);
|
||||
}
|
||||
|
||||
#define __close_fd __attribute__((cleanup(close_fd)))
|
||||
|
||||
static inline int poll_connect(int fd, unsigned int timeout_sec)
|
||||
{
|
||||
struct timeval timeout = { .tv_sec = timeout_sec };
|
||||
|
|
@ -312,54 +334,6 @@ static inline int add_to_sockmap(int sock_mapfd, int fd1, int fd2)
|
|||
return xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST);
|
||||
}
|
||||
|
||||
static inline int create_pair(int s, int family, int sotype, int *c, int *p)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len;
|
||||
int err = 0;
|
||||
|
||||
len = sizeof(addr);
|
||||
err = xgetsockname(s, sockaddr(&addr), &len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*c = xsocket(family, sotype, 0);
|
||||
if (*c < 0)
|
||||
return errno;
|
||||
err = xconnect(*c, sockaddr(&addr), len);
|
||||
if (err) {
|
||||
err = errno;
|
||||
goto close_cli0;
|
||||
}
|
||||
|
||||
*p = xaccept_nonblock(s, NULL, NULL);
|
||||
if (*p < 0) {
|
||||
err = errno;
|
||||
goto close_cli0;
|
||||
}
|
||||
return err;
|
||||
close_cli0:
|
||||
close(*c);
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int create_socket_pairs(int s, int family, int sotype,
|
||||
int *c0, int *c1, int *p0, int *p1)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = create_pair(s, family, sotype, c0, p0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = create_pair(s, family, sotype, c1, p1);
|
||||
if (err) {
|
||||
close(*c0);
|
||||
close(*p0);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int enable_reuseport(int s, int progfd)
|
||||
{
|
||||
int err, one = 1;
|
||||
|
|
@ -412,5 +386,84 @@ static inline int socket_loopback(int family, int sotype)
|
|||
return socket_loopback_reuseport(family, sotype, -1);
|
||||
}
|
||||
|
||||
static inline int create_pair(int family, int sotype, int *p0, int *p1)
|
||||
{
|
||||
__close_fd int s, c = -1, p = -1;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
int err;
|
||||
|
||||
s = socket_loopback(family, sotype);
|
||||
if (s < 0)
|
||||
return s;
|
||||
|
||||
err = xgetsockname(s, sockaddr(&addr), &len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
c = xsocket(family, sotype, 0);
|
||||
if (c < 0)
|
||||
return c;
|
||||
|
||||
err = connect(c, sockaddr(&addr), len);
|
||||
if (err) {
|
||||
if (errno != EINPROGRESS) {
|
||||
FAIL_ERRNO("connect");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = poll_connect(c, IO_TIMEOUT_SEC);
|
||||
if (err) {
|
||||
FAIL_ERRNO("poll_connect");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
switch (sotype & SOCK_TYPE_MASK) {
|
||||
case SOCK_DGRAM:
|
||||
err = xgetsockname(c, sockaddr(&addr), &len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = xconnect(s, sockaddr(&addr), len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*p0 = take_fd(s);
|
||||
break;
|
||||
case SOCK_STREAM:
|
||||
case SOCK_SEQPACKET:
|
||||
p = xaccept_nonblock(s, NULL, NULL);
|
||||
if (p < 0)
|
||||
return p;
|
||||
|
||||
*p0 = take_fd(p);
|
||||
break;
|
||||
default:
|
||||
FAIL("Unsupported socket type %#x", sotype);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
*p1 = take_fd(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int create_socket_pairs(int family, int sotype, int *c0, int *c1,
|
||||
int *p0, int *p1)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = create_pair(family, sotype, c0, p0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = create_pair(family, sotype, c1, p1);
|
||||
if (err) {
|
||||
close(*c0);
|
||||
close(*p0);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif // __SOCKMAP_HELPERS__
|
||||
|
|
|
|||
|
|
@ -677,7 +677,7 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd,
|
|||
int verd_mapfd, enum redir_mode mode)
|
||||
{
|
||||
const char *log_prefix = redir_mode_str(mode);
|
||||
int s, c0, c1, p0, p1;
|
||||
int c0, c1, p0, p1;
|
||||
unsigned int pass;
|
||||
int err, n;
|
||||
u32 key;
|
||||
|
|
@ -685,13 +685,10 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd,
|
|||
|
||||
zero_verdict_count(verd_mapfd);
|
||||
|
||||
s = socket_loopback(family, sotype | SOCK_NONBLOCK);
|
||||
if (s < 0)
|
||||
return;
|
||||
|
||||
err = create_socket_pairs(s, family, sotype, &c0, &c1, &p0, &p1);
|
||||
err = create_socket_pairs(family, sotype | SOCK_NONBLOCK, &c0, &c1,
|
||||
&p0, &p1);
|
||||
if (err)
|
||||
goto close_srv;
|
||||
return;
|
||||
|
||||
err = add_to_sockmap(sock_mapfd, p0, p1);
|
||||
if (err)
|
||||
|
|
@ -722,8 +719,6 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd,
|
|||
xclose(c1);
|
||||
xclose(p0);
|
||||
xclose(c0);
|
||||
close_srv:
|
||||
xclose(s);
|
||||
}
|
||||
|
||||
static void test_skb_redir_to_connected(struct test_sockmap_listen *skel,
|
||||
|
|
@ -909,7 +904,7 @@ static void test_msg_redir_to_listening_with_link(struct test_sockmap_listen *sk
|
|||
|
||||
static void redir_partial(int family, int sotype, int sock_map, int parser_map)
|
||||
{
|
||||
int s, c0 = -1, c1 = -1, p0 = -1, p1 = -1;
|
||||
int c0 = -1, c1 = -1, p0 = -1, p1 = -1;
|
||||
int err, n, key, value;
|
||||
char buf[] = "abc";
|
||||
|
||||
|
|
@ -919,13 +914,10 @@ static void redir_partial(int family, int sotype, int sock_map, int parser_map)
|
|||
if (err)
|
||||
return;
|
||||
|
||||
s = socket_loopback(family, sotype | SOCK_NONBLOCK);
|
||||
if (s < 0)
|
||||
goto clean_parser_map;
|
||||
|
||||
err = create_socket_pairs(s, family, sotype, &c0, &c1, &p0, &p1);
|
||||
err = create_socket_pairs(family, sotype | SOCK_NONBLOCK, &c0, &c1,
|
||||
&p0, &p1);
|
||||
if (err)
|
||||
goto close_srv;
|
||||
goto clean_parser_map;
|
||||
|
||||
err = add_to_sockmap(sock_map, p0, p1);
|
||||
if (err)
|
||||
|
|
@ -944,8 +936,6 @@ static void redir_partial(int family, int sotype, int sock_map, int parser_map)
|
|||
xclose(p0);
|
||||
xclose(c1);
|
||||
xclose(p1);
|
||||
close_srv:
|
||||
xclose(s);
|
||||
|
||||
clean_parser_map:
|
||||
key = 0;
|
||||
|
|
@ -1500,49 +1490,7 @@ static void test_unix_redir(struct test_sockmap_listen *skel, struct bpf_map *ma
|
|||
/* Returns two connected loopback vsock sockets */
|
||||
static int vsock_socketpair_connectible(int sotype, int *v0, int *v1)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len = sizeof(addr);
|
||||
int s, p, c;
|
||||
|
||||
s = socket_loopback(AF_VSOCK, sotype);
|
||||
if (s < 0)
|
||||
return -1;
|
||||
|
||||
c = xsocket(AF_VSOCK, sotype | SOCK_NONBLOCK, 0);
|
||||
if (c == -1)
|
||||
goto close_srv;
|
||||
|
||||
if (getsockname(s, sockaddr(&addr), &len) < 0)
|
||||
goto close_cli;
|
||||
|
||||
if (connect(c, sockaddr(&addr), len) < 0 && errno != EINPROGRESS) {
|
||||
FAIL_ERRNO("connect");
|
||||
goto close_cli;
|
||||
}
|
||||
|
||||
len = sizeof(addr);
|
||||
p = accept_timeout(s, sockaddr(&addr), &len, IO_TIMEOUT_SEC);
|
||||
if (p < 0)
|
||||
goto close_cli;
|
||||
|
||||
if (poll_connect(c, IO_TIMEOUT_SEC) < 0) {
|
||||
FAIL_ERRNO("poll_connect");
|
||||
goto close_acc;
|
||||
}
|
||||
|
||||
*v0 = p;
|
||||
*v1 = c;
|
||||
|
||||
return 0;
|
||||
|
||||
close_acc:
|
||||
close(p);
|
||||
close_cli:
|
||||
close(c);
|
||||
close_srv:
|
||||
close(s);
|
||||
|
||||
return -1;
|
||||
return create_pair(AF_VSOCK, sotype | SOCK_NONBLOCK, v0, v1);
|
||||
}
|
||||
|
||||
static void vsock_unix_redir_connectible(int sock_mapfd, int verd_mapfd,
|
||||
|
|
@ -1691,44 +1639,7 @@ static void test_reuseport(struct test_sockmap_listen *skel,
|
|||
|
||||
static int inet_socketpair(int family, int type, int *s, int *c)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len;
|
||||
int p0, c0;
|
||||
int err;
|
||||
|
||||
p0 = socket_loopback(family, type | SOCK_NONBLOCK);
|
||||
if (p0 < 0)
|
||||
return p0;
|
||||
|
||||
len = sizeof(addr);
|
||||
err = xgetsockname(p0, sockaddr(&addr), &len);
|
||||
if (err)
|
||||
goto close_peer0;
|
||||
|
||||
c0 = xsocket(family, type | SOCK_NONBLOCK, 0);
|
||||
if (c0 < 0) {
|
||||
err = c0;
|
||||
goto close_peer0;
|
||||
}
|
||||
err = xconnect(c0, sockaddr(&addr), len);
|
||||
if (err)
|
||||
goto close_cli0;
|
||||
err = xgetsockname(c0, sockaddr(&addr), &len);
|
||||
if (err)
|
||||
goto close_cli0;
|
||||
err = xconnect(p0, sockaddr(&addr), len);
|
||||
if (err)
|
||||
goto close_cli0;
|
||||
|
||||
*s = p0;
|
||||
*c = c0;
|
||||
return 0;
|
||||
|
||||
close_cli0:
|
||||
xclose(c0);
|
||||
close_peer0:
|
||||
xclose(p0);
|
||||
return err;
|
||||
return create_pair(family, type | SOCK_NONBLOCK, s, c);
|
||||
}
|
||||
|
||||
static void udp_redir_to_connected(int family, int sock_mapfd, int verd_mapfd,
|
||||
|
|
@ -1795,11 +1706,11 @@ static void inet_unix_redir_to_connected(int family, int type, int sock_mapfd,
|
|||
int sfd[2];
|
||||
int err;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, sfd))
|
||||
if (socketpair(AF_UNIX, type | SOCK_NONBLOCK, 0, sfd))
|
||||
return;
|
||||
c0 = sfd[0], p0 = sfd[1];
|
||||
|
||||
err = inet_socketpair(family, SOCK_DGRAM, &p1, &c1);
|
||||
err = inet_socketpair(family, type, &p1, &c1);
|
||||
if (err)
|
||||
goto close;
|
||||
|
||||
|
|
@ -1847,7 +1758,7 @@ static void unix_inet_redir_to_connected(int family, int type, int sock_mapfd,
|
|||
int sfd[2];
|
||||
int err;
|
||||
|
||||
err = inet_socketpair(family, SOCK_DGRAM, &p0, &c0);
|
||||
err = inet_socketpair(family, type, &p0, &c0);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
|
|
@ -1882,7 +1793,7 @@ static void unix_inet_skb_redir_to_connected(struct test_sockmap_listen *skel,
|
|||
unix_inet_redir_to_connected(family, SOCK_DGRAM,
|
||||
sock_map, -1, verdict_map,
|
||||
REDIR_EGRESS, NO_FLAGS);
|
||||
unix_inet_redir_to_connected(family, SOCK_DGRAM,
|
||||
unix_inet_redir_to_connected(family, SOCK_STREAM,
|
||||
sock_map, -1, verdict_map,
|
||||
REDIR_EGRESS, NO_FLAGS);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user