selftests: bpf: Add tests for UDP sockets in sockmap
Expand the TCP sockmap test suite to also check UDP sockets. Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com> Signed-off-by: Lorenz Bauer <lmb@cloudflare.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: John Fastabend <john.fastabend@gmail.com> Link: https://lore.kernel.org/bpf/20200309111243.6982-11-lmb@cloudflare.com
This commit is contained in:
parent
b05fbb9f03
commit
84be2113e6
@ -108,6 +108,22 @@
|
|||||||
__ret; \
|
__ret; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#define xsend(fd, buf, len, flags) \
|
||||||
|
({ \
|
||||||
|
ssize_t __ret = send((fd), (buf), (len), (flags)); \
|
||||||
|
if (__ret == -1) \
|
||||||
|
FAIL_ERRNO("send"); \
|
||||||
|
__ret; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define xrecv(fd, buf, len, flags) \
|
||||||
|
({ \
|
||||||
|
ssize_t __ret = recv((fd), (buf), (len), (flags)); \
|
||||||
|
if (__ret == -1) \
|
||||||
|
FAIL_ERRNO("recv"); \
|
||||||
|
__ret; \
|
||||||
|
})
|
||||||
|
|
||||||
#define xsocket(family, sotype, flags) \
|
#define xsocket(family, sotype, flags) \
|
||||||
({ \
|
({ \
|
||||||
int __ret = socket(family, sotype, flags); \
|
int __ret = socket(family, sotype, flags); \
|
||||||
@ -330,7 +346,7 @@ close:
|
|||||||
xclose(s);
|
xclose(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_insert_listening(int family, int sotype, int mapfd)
|
static void test_insert(int family, int sotype, int mapfd)
|
||||||
{
|
{
|
||||||
u64 value;
|
u64 value;
|
||||||
u32 key;
|
u32 key;
|
||||||
@ -467,7 +483,7 @@ close:
|
|||||||
xclose(s);
|
xclose(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_update_listening(int family, int sotype, int mapfd)
|
static void test_update_existing(int family, int sotype, int mapfd)
|
||||||
{
|
{
|
||||||
int s1, s2;
|
int s1, s2;
|
||||||
u64 value;
|
u64 value;
|
||||||
@ -1116,7 +1132,7 @@ static void test_reuseport_select_listening(int family, int sotype,
|
|||||||
{
|
{
|
||||||
struct sockaddr_storage addr;
|
struct sockaddr_storage addr;
|
||||||
unsigned int pass;
|
unsigned int pass;
|
||||||
int s, c, p, err;
|
int s, c, err;
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
u64 value;
|
u64 value;
|
||||||
u32 key;
|
u32 key;
|
||||||
@ -1145,19 +1161,33 @@ static void test_reuseport_select_listening(int family, int sotype,
|
|||||||
if (err)
|
if (err)
|
||||||
goto close_cli;
|
goto close_cli;
|
||||||
|
|
||||||
p = xaccept(s, NULL, NULL);
|
if (sotype == SOCK_STREAM) {
|
||||||
if (p < 0)
|
int p;
|
||||||
goto close_cli;
|
|
||||||
|
p = xaccept(s, NULL, NULL);
|
||||||
|
if (p < 0)
|
||||||
|
goto close_cli;
|
||||||
|
xclose(p);
|
||||||
|
} else {
|
||||||
|
char b = 'a';
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
n = xsend(c, &b, sizeof(b), 0);
|
||||||
|
if (n == -1)
|
||||||
|
goto close_cli;
|
||||||
|
|
||||||
|
n = xrecv(s, &b, sizeof(b), 0);
|
||||||
|
if (n == -1)
|
||||||
|
goto close_cli;
|
||||||
|
}
|
||||||
|
|
||||||
key = SK_PASS;
|
key = SK_PASS;
|
||||||
err = xbpf_map_lookup_elem(verd_map, &key, &pass);
|
err = xbpf_map_lookup_elem(verd_map, &key, &pass);
|
||||||
if (err)
|
if (err)
|
||||||
goto close_peer;
|
goto close_cli;
|
||||||
if (pass != 1)
|
if (pass != 1)
|
||||||
FAIL("want pass count 1, have %d", pass);
|
FAIL("want pass count 1, have %d", pass);
|
||||||
|
|
||||||
close_peer:
|
|
||||||
xclose(p);
|
|
||||||
close_cli:
|
close_cli:
|
||||||
xclose(c);
|
xclose(c);
|
||||||
close_srv:
|
close_srv:
|
||||||
@ -1201,9 +1231,24 @@ static void test_reuseport_select_connected(int family, int sotype,
|
|||||||
if (err)
|
if (err)
|
||||||
goto close_cli0;
|
goto close_cli0;
|
||||||
|
|
||||||
p0 = xaccept(s, NULL, NULL);
|
if (sotype == SOCK_STREAM) {
|
||||||
if (err)
|
p0 = xaccept(s, NULL, NULL);
|
||||||
goto close_cli0;
|
if (p0 < 0)
|
||||||
|
goto close_cli0;
|
||||||
|
} else {
|
||||||
|
p0 = xsocket(family, sotype, 0);
|
||||||
|
if (p0 < 0)
|
||||||
|
goto close_cli0;
|
||||||
|
|
||||||
|
len = sizeof(addr);
|
||||||
|
err = xgetsockname(c0, sockaddr(&addr), &len);
|
||||||
|
if (err)
|
||||||
|
goto close_cli0;
|
||||||
|
|
||||||
|
err = xconnect(p0, sockaddr(&addr), len);
|
||||||
|
if (err)
|
||||||
|
goto close_cli0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Update sock_map[0] to redirect to a connected socket */
|
/* Update sock_map[0] to redirect to a connected socket */
|
||||||
key = 0;
|
key = 0;
|
||||||
@ -1216,8 +1261,24 @@ static void test_reuseport_select_connected(int family, int sotype,
|
|||||||
if (c1 < 0)
|
if (c1 < 0)
|
||||||
goto close_peer0;
|
goto close_peer0;
|
||||||
|
|
||||||
|
len = sizeof(addr);
|
||||||
|
err = xgetsockname(s, sockaddr(&addr), &len);
|
||||||
|
if (err)
|
||||||
|
goto close_srv;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
err = connect(c1, sockaddr(&addr), len);
|
err = connect(c1, sockaddr(&addr), len);
|
||||||
|
if (sotype == SOCK_DGRAM) {
|
||||||
|
char b = 'a';
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
n = xsend(c1, &b, sizeof(b), 0);
|
||||||
|
if (n == -1)
|
||||||
|
goto close_cli1;
|
||||||
|
|
||||||
|
n = recv(c1, &b, sizeof(b), 0);
|
||||||
|
err = n == -1;
|
||||||
|
}
|
||||||
if (!err || errno != ECONNREFUSED)
|
if (!err || errno != ECONNREFUSED)
|
||||||
FAIL_ERRNO("connect: expected ECONNREFUSED");
|
FAIL_ERRNO("connect: expected ECONNREFUSED");
|
||||||
|
|
||||||
@ -1281,7 +1342,18 @@ static void test_reuseport_mixed_groups(int family, int sotype, int sock_map,
|
|||||||
goto close_srv2;
|
goto close_srv2;
|
||||||
|
|
||||||
err = connect(c, sockaddr(&addr), len);
|
err = connect(c, sockaddr(&addr), len);
|
||||||
if (err && errno != ECONNREFUSED) {
|
if (sotype == SOCK_DGRAM) {
|
||||||
|
char b = 'a';
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
n = xsend(c, &b, sizeof(b), 0);
|
||||||
|
if (n == -1)
|
||||||
|
goto close_cli;
|
||||||
|
|
||||||
|
n = recv(c, &b, sizeof(b), 0);
|
||||||
|
err = n == -1;
|
||||||
|
}
|
||||||
|
if (!err || errno != ECONNREFUSED) {
|
||||||
FAIL_ERRNO("connect: expected ECONNREFUSED");
|
FAIL_ERRNO("connect: expected ECONNREFUSED");
|
||||||
goto close_cli;
|
goto close_cli;
|
||||||
}
|
}
|
||||||
@ -1302,9 +1374,9 @@ close_srv1:
|
|||||||
xclose(s1);
|
xclose(s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TEST(fn) \
|
#define TEST(fn, ...) \
|
||||||
{ \
|
{ \
|
||||||
fn, #fn \
|
fn, #fn, __VA_ARGS__ \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_ops_cleanup(const struct bpf_map *map)
|
static void test_ops_cleanup(const struct bpf_map *map)
|
||||||
@ -1353,18 +1425,31 @@ static const char *map_type_str(const struct bpf_map *map)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *sotype_str(int sotype)
|
||||||
|
{
|
||||||
|
switch (sotype) {
|
||||||
|
case SOCK_DGRAM:
|
||||||
|
return "UDP";
|
||||||
|
case SOCK_STREAM:
|
||||||
|
return "TCP";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
|
static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
|
||||||
int family, int sotype)
|
int family, int sotype)
|
||||||
{
|
{
|
||||||
const struct op_test {
|
const struct op_test {
|
||||||
void (*fn)(int family, int sotype, int mapfd);
|
void (*fn)(int family, int sotype, int mapfd);
|
||||||
const char *name;
|
const char *name;
|
||||||
|
int sotype;
|
||||||
} tests[] = {
|
} tests[] = {
|
||||||
/* insert */
|
/* insert */
|
||||||
TEST(test_insert_invalid),
|
TEST(test_insert_invalid),
|
||||||
TEST(test_insert_opened),
|
TEST(test_insert_opened),
|
||||||
TEST(test_insert_bound),
|
TEST(test_insert_bound, SOCK_STREAM),
|
||||||
TEST(test_insert_listening),
|
TEST(test_insert),
|
||||||
/* delete */
|
/* delete */
|
||||||
TEST(test_delete_after_insert),
|
TEST(test_delete_after_insert),
|
||||||
TEST(test_delete_after_close),
|
TEST(test_delete_after_close),
|
||||||
@ -1373,28 +1458,32 @@ static void test_ops(struct test_sockmap_listen *skel, struct bpf_map *map,
|
|||||||
TEST(test_lookup_after_delete),
|
TEST(test_lookup_after_delete),
|
||||||
TEST(test_lookup_32_bit_value),
|
TEST(test_lookup_32_bit_value),
|
||||||
/* update */
|
/* update */
|
||||||
TEST(test_update_listening),
|
TEST(test_update_existing),
|
||||||
/* races with insert/delete */
|
/* races with insert/delete */
|
||||||
TEST(test_destroy_orphan_child),
|
TEST(test_destroy_orphan_child, SOCK_STREAM),
|
||||||
TEST(test_syn_recv_insert_delete),
|
TEST(test_syn_recv_insert_delete, SOCK_STREAM),
|
||||||
TEST(test_race_insert_listen),
|
TEST(test_race_insert_listen, SOCK_STREAM),
|
||||||
/* child clone */
|
/* child clone */
|
||||||
TEST(test_clone_after_delete),
|
TEST(test_clone_after_delete, SOCK_STREAM),
|
||||||
TEST(test_accept_after_delete),
|
TEST(test_accept_after_delete, SOCK_STREAM),
|
||||||
TEST(test_accept_before_delete),
|
TEST(test_accept_before_delete, SOCK_STREAM),
|
||||||
};
|
};
|
||||||
const char *family_name, *map_name;
|
const char *family_name, *map_name, *sotype_name;
|
||||||
const struct op_test *t;
|
const struct op_test *t;
|
||||||
char s[MAX_TEST_NAME];
|
char s[MAX_TEST_NAME];
|
||||||
int map_fd;
|
int map_fd;
|
||||||
|
|
||||||
family_name = family_str(family);
|
family_name = family_str(family);
|
||||||
map_name = map_type_str(map);
|
map_name = map_type_str(map);
|
||||||
|
sotype_name = sotype_str(sotype);
|
||||||
map_fd = bpf_map__fd(map);
|
map_fd = bpf_map__fd(map);
|
||||||
|
|
||||||
for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
|
for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
|
||||||
snprintf(s, sizeof(s), "%s %s %s", map_name, family_name,
|
snprintf(s, sizeof(s), "%s %s %s %s", map_name, family_name,
|
||||||
t->name);
|
sotype_name, t->name);
|
||||||
|
|
||||||
|
if (t->sotype != 0 && t->sotype != sotype)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!test__start_subtest(s))
|
if (!test__start_subtest(s))
|
||||||
continue;
|
continue;
|
||||||
@ -1427,6 +1516,7 @@ static void test_redir(struct test_sockmap_listen *skel, struct bpf_map *map,
|
|||||||
for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
|
for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
|
||||||
snprintf(s, sizeof(s), "%s %s %s", map_name, family_name,
|
snprintf(s, sizeof(s), "%s %s %s", map_name, family_name,
|
||||||
t->name);
|
t->name);
|
||||||
|
|
||||||
if (!test__start_subtest(s))
|
if (!test__start_subtest(s))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1441,26 +1531,31 @@ static void test_reuseport(struct test_sockmap_listen *skel,
|
|||||||
void (*fn)(int family, int sotype, int socket_map,
|
void (*fn)(int family, int sotype, int socket_map,
|
||||||
int verdict_map, int reuseport_prog);
|
int verdict_map, int reuseport_prog);
|
||||||
const char *name;
|
const char *name;
|
||||||
|
int sotype;
|
||||||
} tests[] = {
|
} tests[] = {
|
||||||
TEST(test_reuseport_select_listening),
|
TEST(test_reuseport_select_listening),
|
||||||
TEST(test_reuseport_select_connected),
|
TEST(test_reuseport_select_connected),
|
||||||
TEST(test_reuseport_mixed_groups),
|
TEST(test_reuseport_mixed_groups),
|
||||||
};
|
};
|
||||||
int socket_map, verdict_map, reuseport_prog;
|
int socket_map, verdict_map, reuseport_prog;
|
||||||
const char *family_name, *map_name;
|
const char *family_name, *map_name, *sotype_name;
|
||||||
const struct reuseport_test *t;
|
const struct reuseport_test *t;
|
||||||
char s[MAX_TEST_NAME];
|
char s[MAX_TEST_NAME];
|
||||||
|
|
||||||
family_name = family_str(family);
|
family_name = family_str(family);
|
||||||
map_name = map_type_str(map);
|
map_name = map_type_str(map);
|
||||||
|
sotype_name = sotype_str(sotype);
|
||||||
|
|
||||||
socket_map = bpf_map__fd(map);
|
socket_map = bpf_map__fd(map);
|
||||||
verdict_map = bpf_map__fd(skel->maps.verdict_map);
|
verdict_map = bpf_map__fd(skel->maps.verdict_map);
|
||||||
reuseport_prog = bpf_program__fd(skel->progs.prog_reuseport);
|
reuseport_prog = bpf_program__fd(skel->progs.prog_reuseport);
|
||||||
|
|
||||||
for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
|
for (t = tests; t < tests + ARRAY_SIZE(tests); t++) {
|
||||||
snprintf(s, sizeof(s), "%s %s %s", map_name, family_name,
|
snprintf(s, sizeof(s), "%s %s %s %s", map_name, family_name,
|
||||||
t->name);
|
sotype_name, t->name);
|
||||||
|
|
||||||
|
if (t->sotype != 0 && t->sotype != sotype)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!test__start_subtest(s))
|
if (!test__start_subtest(s))
|
||||||
continue;
|
continue;
|
||||||
@ -1473,8 +1568,10 @@ static void run_tests(struct test_sockmap_listen *skel, struct bpf_map *map,
|
|||||||
int family)
|
int family)
|
||||||
{
|
{
|
||||||
test_ops(skel, map, family, SOCK_STREAM);
|
test_ops(skel, map, family, SOCK_STREAM);
|
||||||
|
test_ops(skel, map, family, SOCK_DGRAM);
|
||||||
test_redir(skel, map, family, SOCK_STREAM);
|
test_redir(skel, map, family, SOCK_STREAM);
|
||||||
test_reuseport(skel, map, family, SOCK_STREAM);
|
test_reuseport(skel, map, family, SOCK_STREAM);
|
||||||
|
test_reuseport(skel, map, family, SOCK_DGRAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_sockmap_listen(void)
|
void test_sockmap_listen(void)
|
||||||
|
Loading…
Reference in New Issue
Block a user