Commit db163778 authored by Martin KaFai Lau's avatar Martin KaFai Lau

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: default avatarMartin KaFai Lau <martin.lau@kernel.org>
parents 92ec8b93 86149b4f
...@@ -451,11 +451,11 @@ static void test_sockmap_progs_query(enum bpf_attach_type attach_type) ...@@ -451,11 +451,11 @@ static void test_sockmap_progs_query(enum bpf_attach_type attach_type)
#define MAX_EVENTS 10 #define MAX_EVENTS 10
static void test_sockmap_skb_verdict_shutdown(void) static void test_sockmap_skb_verdict_shutdown(void)
{ {
int n, err, map, verdict, c1 = -1, p1 = -1;
struct epoll_event ev, events[MAX_EVENTS]; struct epoll_event ev, events[MAX_EVENTS];
int n, err, map, verdict, s, c1 = -1, p1 = -1;
struct test_sockmap_pass_prog *skel; struct test_sockmap_pass_prog *skel;
int epollfd;
int zero = 0; int zero = 0;
int epollfd;
char b; char b;
skel = test_sockmap_pass_prog__open_and_load(); skel = test_sockmap_pass_prog__open_and_load();
...@@ -469,10 +469,7 @@ static void test_sockmap_skb_verdict_shutdown(void) ...@@ -469,10 +469,7 @@ static void test_sockmap_skb_verdict_shutdown(void)
if (!ASSERT_OK(err, "bpf_prog_attach")) if (!ASSERT_OK(err, "bpf_prog_attach"))
goto out; goto out;
s = socket_loopback(AF_INET, SOCK_STREAM); err = create_pair(AF_INET, SOCK_STREAM, &c1, &p1);
if (s < 0)
goto out;
err = create_pair(s, AF_INET, SOCK_STREAM, &c1, &p1);
if (err < 0) if (err < 0)
goto out; goto out;
...@@ -506,8 +503,8 @@ static void test_sockmap_skb_verdict_shutdown(void) ...@@ -506,8 +503,8 @@ static void test_sockmap_skb_verdict_shutdown(void)
static void test_sockmap_skb_verdict_fionread(bool pass_prog) 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 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_pass_prog *pass = NULL;
struct test_sockmap_drop_prog *drop = NULL; struct test_sockmap_drop_prog *drop = NULL;
char buf[256] = "0123456789"; char buf[256] = "0123456789";
...@@ -534,11 +531,8 @@ static void test_sockmap_skb_verdict_fionread(bool pass_prog) ...@@ -534,11 +531,8 @@ static void test_sockmap_skb_verdict_fionread(bool pass_prog)
if (!ASSERT_OK(err, "bpf_prog_attach")) if (!ASSERT_OK(err, "bpf_prog_attach"))
goto out; goto out;
s = socket_loopback(AF_INET, SOCK_STREAM); err = create_socket_pairs(AF_INET, SOCK_STREAM, &c0, &c1, &p0, &p1);
if (!ASSERT_GT(s, -1, "socket_loopback(s)")) if (!ASSERT_OK(err, "create_socket_pairs()"))
goto out;
err = create_socket_pairs(s, AF_INET, SOCK_STREAM, &c0, &c1, &p0, &p1);
if (!ASSERT_OK(err, "create_socket_pairs(s)"))
goto out; goto out;
err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST); err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
...@@ -570,16 +564,12 @@ static void test_sockmap_skb_verdict_fionread(bool pass_prog) ...@@ -570,16 +564,12 @@ static void test_sockmap_skb_verdict_fionread(bool pass_prog)
static void test_sockmap_skb_verdict_peek_helper(int map) 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 snd[256] = "0123456789";
char rcv[256] = "0"; char rcv[256] = "0";
s = socket_loopback(AF_INET, SOCK_STREAM); err = create_pair(AF_INET, SOCK_STREAM, &c1, &p1);
if (!ASSERT_GT(s, -1, "socket_loopback(s)")) if (!ASSERT_OK(err, "create_pair()"))
return;
err = create_pair(s, AF_INET, SOCK_STREAM, &c1, &p1);
if (!ASSERT_OK(err, "create_pairs(s)"))
return; return;
err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST); err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST);
......
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
#include <linux/vm_sockets.h> #include <linux/vm_sockets.h>
/* include/linux/net.h */
#define SOCK_TYPE_MASK 0xf
#define IO_TIMEOUT_SEC 30 #define IO_TIMEOUT_SEC 30
#define MAX_STRERR_LEN 256 #define MAX_STRERR_LEN 256
#define MAX_TEST_NAME 80 #define MAX_TEST_NAME 80
...@@ -14,6 +17,17 @@ ...@@ -14,6 +17,17 @@
#define __always_unused __attribute__((__unused__)) #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...) \ #define _FAIL(errnum, fmt...) \
({ \ ({ \
error_at_line(0, (errnum), __func__, __LINE__, fmt); \ error_at_line(0, (errnum), __func__, __LINE__, fmt); \
...@@ -179,6 +193,14 @@ ...@@ -179,6 +193,14 @@
__ret; \ __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) static inline int poll_connect(int fd, unsigned int timeout_sec)
{ {
struct timeval timeout = { .tv_sec = 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) ...@@ -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); 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) static inline int enable_reuseport(int s, int progfd)
{ {
int err, one = 1; int err, one = 1;
...@@ -412,5 +386,84 @@ static inline int socket_loopback(int family, int sotype) ...@@ -412,5 +386,84 @@ static inline int socket_loopback(int family, int sotype)
return socket_loopback_reuseport(family, sotype, -1); 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__ #endif // __SOCKMAP_HELPERS__
...@@ -677,7 +677,7 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd, ...@@ -677,7 +677,7 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd,
int verd_mapfd, enum redir_mode mode) int verd_mapfd, enum redir_mode mode)
{ {
const char *log_prefix = redir_mode_str(mode); const char *log_prefix = redir_mode_str(mode);
int s, c0, c1, p0, p1; int c0, c1, p0, p1;
unsigned int pass; unsigned int pass;
int err, n; int err, n;
u32 key; u32 key;
...@@ -685,13 +685,10 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd, ...@@ -685,13 +685,10 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd,
zero_verdict_count(verd_mapfd); zero_verdict_count(verd_mapfd);
s = socket_loopback(family, sotype | SOCK_NONBLOCK); err = create_socket_pairs(family, sotype | SOCK_NONBLOCK, &c0, &c1,
if (s < 0) &p0, &p1);
return;
err = create_socket_pairs(s, family, sotype, &c0, &c1, &p0, &p1);
if (err) if (err)
goto close_srv; return;
err = add_to_sockmap(sock_mapfd, p0, p1); err = add_to_sockmap(sock_mapfd, p0, p1);
if (err) if (err)
...@@ -722,8 +719,6 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd, ...@@ -722,8 +719,6 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd,
xclose(c1); xclose(c1);
xclose(p0); xclose(p0);
xclose(c0); xclose(c0);
close_srv:
xclose(s);
} }
static void test_skb_redir_to_connected(struct test_sockmap_listen *skel, 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 ...@@ -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) 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; int err, n, key, value;
char buf[] = "abc"; char buf[] = "abc";
...@@ -919,13 +914,10 @@ static void redir_partial(int family, int sotype, int sock_map, int parser_map) ...@@ -919,13 +914,10 @@ static void redir_partial(int family, int sotype, int sock_map, int parser_map)
if (err) if (err)
return; return;
s = socket_loopback(family, sotype | SOCK_NONBLOCK); err = create_socket_pairs(family, sotype | SOCK_NONBLOCK, &c0, &c1,
if (s < 0) &p0, &p1);
goto clean_parser_map;
err = create_socket_pairs(s, family, sotype, &c0, &c1, &p0, &p1);
if (err) if (err)
goto close_srv; goto clean_parser_map;
err = add_to_sockmap(sock_map, p0, p1); err = add_to_sockmap(sock_map, p0, p1);
if (err) if (err)
...@@ -944,8 +936,6 @@ static void redir_partial(int family, int sotype, int sock_map, int parser_map) ...@@ -944,8 +936,6 @@ static void redir_partial(int family, int sotype, int sock_map, int parser_map)
xclose(p0); xclose(p0);
xclose(c1); xclose(c1);
xclose(p1); xclose(p1);
close_srv:
xclose(s);
clean_parser_map: clean_parser_map:
key = 0; key = 0;
...@@ -1500,49 +1490,7 @@ static void test_unix_redir(struct test_sockmap_listen *skel, struct bpf_map *ma ...@@ -1500,49 +1490,7 @@ static void test_unix_redir(struct test_sockmap_listen *skel, struct bpf_map *ma
/* Returns two connected loopback vsock sockets */ /* Returns two connected loopback vsock sockets */
static int vsock_socketpair_connectible(int sotype, int *v0, int *v1) static int vsock_socketpair_connectible(int sotype, int *v0, int *v1)
{ {
struct sockaddr_storage addr; return create_pair(AF_VSOCK, sotype | SOCK_NONBLOCK, v0, v1);
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;
} }
static void vsock_unix_redir_connectible(int sock_mapfd, int verd_mapfd, 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, ...@@ -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) static int inet_socketpair(int family, int type, int *s, int *c)
{ {
struct sockaddr_storage addr; return create_pair(family, type | SOCK_NONBLOCK, s, c);
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;
} }
static void udp_redir_to_connected(int family, int sock_mapfd, int verd_mapfd, 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, ...@@ -1795,11 +1706,11 @@ static void inet_unix_redir_to_connected(int family, int type, int sock_mapfd,
int sfd[2]; int sfd[2];
int err; int err;
if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, sfd)) if (socketpair(AF_UNIX, type | SOCK_NONBLOCK, 0, sfd))
return; return;
c0 = sfd[0], p0 = sfd[1]; c0 = sfd[0], p0 = sfd[1];
err = inet_socketpair(family, SOCK_DGRAM, &p1, &c1); err = inet_socketpair(family, type, &p1, &c1);
if (err) if (err)
goto close; goto close;
...@@ -1847,7 +1758,7 @@ static void unix_inet_redir_to_connected(int family, int type, int sock_mapfd, ...@@ -1847,7 +1758,7 @@ static void unix_inet_redir_to_connected(int family, int type, int sock_mapfd,
int sfd[2]; int sfd[2];
int err; int err;
err = inet_socketpair(family, SOCK_DGRAM, &p0, &c0); err = inet_socketpair(family, type, &p0, &c0);
if (err) if (err)
return; return;
...@@ -1882,7 +1793,7 @@ static void unix_inet_skb_redir_to_connected(struct test_sockmap_listen *skel, ...@@ -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, unix_inet_redir_to_connected(family, SOCK_DGRAM,
sock_map, -1, verdict_map, sock_map, -1, verdict_map,
REDIR_EGRESS, NO_FLAGS); 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, sock_map, -1, verdict_map,
REDIR_EGRESS, NO_FLAGS); REDIR_EGRESS, NO_FLAGS);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment