[PATCH net v3 4/6] vsock/test: Introduce vsock_connect_fd()
Distill timeout-guarded vsock_connect_fd(). Adapt callers. Suggested-by: Stefano Garzarella Reviewed-by: Stefano Garzarella Signed-off-by: Michal Luczaj --- tools/testing/vsock/util.c | 45 + tools/testing/vsock/util.h | 1 + 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c index 6e36f9371532cfc75dd14131b84bf8393ca0952b..de25892f865f07672da0886be8bd1a429ade8b05 100644 --- a/tools/testing/vsock/util.c +++ b/tools/testing/vsock/util.c @@ -120,27 +120,33 @@ int vsock_bind(unsigned int cid, unsigned int port, int type) return fd; } -/* Bind to , connect to and return the file descriptor. */ -int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type) +int vsock_connect_fd(int fd, unsigned int cid, unsigned int port) { - struct sockaddr_vm sa_server = { + struct sockaddr_vm sa = { .svm_family = AF_VSOCK, .svm_cid = cid, .svm_port = port, }; - - int client_fd, ret; - - client_fd = vsock_bind(VMADDR_CID_ANY, bind_port, type); + int ret; timeout_begin(TIMEOUT); do { - ret = connect(client_fd, (struct sockaddr *)&sa_server, sizeof(sa_server)); + ret = connect(fd, (struct sockaddr *)&sa, sizeof(sa)); timeout_check("connect"); } while (ret < 0 && errno == EINTR); timeout_end(); - if (ret < 0) { + return ret; +} + +/* Bind to , connect to and return the file descriptor. */ +int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type) +{ + int client_fd; + + client_fd = vsock_bind(VMADDR_CID_ANY, bind_port, type); + + if (vsock_connect_fd(client_fd, cid, port)) { perror("connect"); exit(EXIT_FAILURE); } @@ -151,17 +157,6 @@ int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_po /* Connect to and return the file descriptor. */ int vsock_connect(unsigned int cid, unsigned int port, int type) { - union { - struct sockaddr sa; - struct sockaddr_vm svm; - } addr = { - .svm = { - .svm_family = AF_VSOCK, - .svm_port = port, - .svm_cid = cid, - }, - }; - int ret; int fd; control_expectln("LISTENING"); @@ -172,20 +167,14 @@ int vsock_connect(unsigned int cid, unsigned int port, int type) exit(EXIT_FAILURE); } - timeout_begin(TIMEOUT); - do { - ret = connect(fd, &addr.sa, sizeof(addr.svm)); - timeout_check("connect"); - } while (ret < 0 && errno == EINTR); - timeout_end(); - - if (ret < 0) { + if (vsock_connect_fd(fd, cid, port)) { int old_errno = errno; close(fd); fd = -1; errno = old_errno; } + return fd; } diff --git a/tools/testing/vsock/util.h b/tools/testing/vsock/util.h index 077842905bc3e7a4bbd22caba4b7bde976de2718..d1f765ce3d8f738630846bb47c4f3f6f946f 100644 --- a/tools/testing/vsock/util.h +++ b/tools/testing/vsock/util.h @@ -39,6 +39,7 @@ struct test_case { void init_signals(void); unsigned int parse_cid(const char *str); unsigned int parse_port(const char *str); +int vsock_connect_fd(int fd, unsigned int cid, unsigned int port); int vsock_connect(unsigned int cid, unsigned int port, int type); int vsock_accept(unsigned int cid, unsigned int port, struct sockaddr_vm *clientaddrp, int type); -- 2.48.1
[PATCH net v3 6/6] vsock/test: Add test for connect() retries
Deliberately fail a connect() attempt; expect error. Then verify that subsequent attempt (using the same socket) can still succeed, rather than fail outright. Reviewed-by: Stefano Garzarella Reviewed-by: Luigi Leonardi Signed-off-by: Michal Luczaj --- tools/testing/vsock/vsock_test.c | 47 1 file changed, 47 insertions(+) diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index 92cfd92bbfdc2cca75dc1149bee7f354262ad2b1..dfff8b288265f96b602cb1bfa0e6dce02f114222 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -1746,6 +1746,48 @@ static void test_stream_transport_uaf_server(const struct test_opts *opts) control_expectln("DONE"); } +static void test_stream_connect_retry_client(const struct test_opts *opts) +{ + int fd; + + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + exit(EXIT_FAILURE); + } + + if (!vsock_connect_fd(fd, opts->peer_cid, opts->peer_port)) { + fprintf(stderr, "Unexpected connect() #1 success\n"); + exit(EXIT_FAILURE); + } + + control_writeln("LISTEN"); + control_expectln("LISTENING"); + + if (vsock_connect_fd(fd, opts->peer_cid, opts->peer_port)) { + perror("connect() #2"); + exit(EXIT_FAILURE); + } + + close(fd); +} + +static void test_stream_connect_retry_server(const struct test_opts *opts) +{ + int fd; + + control_expectln("LISTEN"); + + fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL); + if (fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + vsock_wait_remote_close(fd); + close(fd); +} + static struct test_case test_cases[] = { { .name = "SOCK_STREAM connection reset", @@ -1896,6 +1938,11 @@ static struct test_case test_cases[] = { .run_client = test_stream_transport_uaf_client, .run_server = test_stream_transport_uaf_server, }, + { + .name = "SOCK_STREAM retry failed connect()", + .run_client = test_stream_connect_retry_client, + .run_server = test_stream_connect_retry_server, + }, {}, }; -- 2.48.1
[PATCH net v3 5/6] vsock/test: Add test for UAF due to socket unbinding
Fail the autobind, then trigger a transport reassign. Socket might get unbound from unbound_sockets, which then leads to a reference count underflow. Reviewed-by: Stefano Garzarella Signed-off-by: Michal Luczaj --- tools/testing/vsock/vsock_test.c | 58 1 file changed, 58 insertions(+) diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index daa4f3ca9b6e7267d1bb14a7d43499da3bafb108..92cfd92bbfdc2cca75dc1149bee7f354262ad2b1 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -1693,6 +1693,59 @@ static void test_stream_msgzcopy_leak_zcskb_server(const struct test_opts *opts) close(fd); } +#define MAX_PORT_RETRIES 24 /* net/vmw_vsock/af_vsock.c */ + +/* Test attempts to trigger a transport release for an unbound socket. This can + * lead to a reference count mishandling. + */ +static void test_stream_transport_uaf_client(const struct test_opts *opts) +{ + int sockets[MAX_PORT_RETRIES]; + struct sockaddr_vm addr; + int fd, i, alen; + + fd = vsock_bind(VMADDR_CID_ANY, VMADDR_PORT_ANY, SOCK_STREAM); + + alen = sizeof(addr); + if (getsockname(fd, (struct sockaddr *)&addr, &alen)) { + perror("getsockname"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < MAX_PORT_RETRIES; ++i) + sockets[i] = vsock_bind(VMADDR_CID_ANY, ++addr.svm_port, + SOCK_STREAM); + + close(fd); + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + if (fd < 0) { + perror("socket"); + exit(EXIT_FAILURE); + } + + if (!vsock_connect_fd(fd, addr.svm_cid, addr.svm_port)) { + perror("Unexpected connect() #1 success"); + exit(EXIT_FAILURE); + } + + /* Vulnerable system may crash now. */ + if (!vsock_connect_fd(fd, VMADDR_CID_HOST, VMADDR_PORT_ANY)) { + perror("Unexpected connect() #2 success"); + exit(EXIT_FAILURE); + } + + close(fd); + while (i--) + close(sockets[i]); + + control_writeln("DONE"); +} + +static void test_stream_transport_uaf_server(const struct test_opts *opts) +{ + control_expectln("DONE"); +} + static struct test_case test_cases[] = { { .name = "SOCK_STREAM connection reset", @@ -1838,6 +1891,11 @@ static struct test_case test_cases[] = { .run_client = test_stream_msgzcopy_leak_zcskb_client, .run_server = test_stream_msgzcopy_leak_zcskb_server, }, + { + .name = "SOCK_STREAM transport release use-after-free", + .run_client = test_stream_transport_uaf_client, + .run_server = test_stream_transport_uaf_server, + }, {}, }; -- 2.48.1
[PATCH net v3 3/6] vsock/test: Introduce vsock_bind()
Add a helper for socket()+bind(). Adapt callers. Reviewed-by: Stefano Garzarella Reviewed-by: Luigi Leonardi Signed-off-by: Michal Luczaj --- tools/testing/vsock/util.c | 57 +--- tools/testing/vsock/util.h | 1 + tools/testing/vsock/vsock_test.c | 17 +--- 3 files changed, 26 insertions(+), 49 deletions(-) diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c index 7058dc614c25f546fc3219d6b9ade2dcef21a9bd..6e36f9371532cfc75dd14131b84bf8393ca0952b 100644 --- a/tools/testing/vsock/util.c +++ b/tools/testing/vsock/util.c @@ -96,33 +96,43 @@ void vsock_wait_remote_close(int fd) close(epollfd); } -/* Bind to , connect to and return the file descriptor. */ -int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type) +/* Create socket , bind to and return the file descriptor. */ +int vsock_bind(unsigned int cid, unsigned int port, int type) { - struct sockaddr_vm sa_client = { - .svm_family = AF_VSOCK, - .svm_cid = VMADDR_CID_ANY, - .svm_port = bind_port, - }; - struct sockaddr_vm sa_server = { + struct sockaddr_vm sa = { .svm_family = AF_VSOCK, .svm_cid = cid, .svm_port = port, }; + int fd; - int client_fd, ret; - - client_fd = socket(AF_VSOCK, type, 0); - if (client_fd < 0) { + fd = socket(AF_VSOCK, type, 0); + if (fd < 0) { perror("socket"); exit(EXIT_FAILURE); } - if (bind(client_fd, (struct sockaddr *)&sa_client, sizeof(sa_client))) { + if (bind(fd, (struct sockaddr *)&sa, sizeof(sa))) { perror("bind"); exit(EXIT_FAILURE); } + return fd; +} + +/* Bind to , connect to and return the file descriptor. */ +int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type) +{ + struct sockaddr_vm sa_server = { + .svm_family = AF_VSOCK, + .svm_cid = cid, + .svm_port = port, + }; + + int client_fd, ret; + + client_fd = vsock_bind(VMADDR_CID_ANY, bind_port, type); + timeout_begin(TIMEOUT); do { ret = connect(client_fd, (struct sockaddr *)&sa_server, sizeof(sa_server)); @@ -192,28 +202,9 @@ int vsock_seqpacket_connect(unsigned int cid, unsigned int port) /* Listen on and return the file descriptor. */ static int vsock_listen(unsigned int cid, unsigned int port, int type) { - union { - struct sockaddr sa; - struct sockaddr_vm svm; - } addr = { - .svm = { - .svm_family = AF_VSOCK, - .svm_port = port, - .svm_cid = cid, - }, - }; int fd; - fd = socket(AF_VSOCK, type, 0); - if (fd < 0) { - perror("socket"); - exit(EXIT_FAILURE); - } - - if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { - perror("bind"); - exit(EXIT_FAILURE); - } + fd = vsock_bind(cid, port, type); if (listen(fd, 1) < 0) { perror("listen"); diff --git a/tools/testing/vsock/util.h b/tools/testing/vsock/util.h index e62f46b2b92a7916e83e1e623b43c811b077db3e..077842905bc3e7a4bbd22caba4b7bde976de2718 100644 --- a/tools/testing/vsock/util.h +++ b/tools/testing/vsock/util.h @@ -43,6 +43,7 @@ int vsock_connect(unsigned int cid, unsigned int port, int type); int vsock_accept(unsigned int cid, unsigned int port, struct sockaddr_vm *clientaddrp, int type); int vsock_stream_connect(unsigned int cid, unsigned int port); +int vsock_bind(unsigned int cid, unsigned int port, int type); int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type); int vsock_seqpacket_connect(unsigned int cid, unsigned int port); diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index 1eebbc0d5f616bb1afab3ec3f9e59cb609f9f6e8..daa4f3ca9b6e7267d1bb14a7d43499da3bafb108 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -113,24 +113,9 @@ static void test_stream_bind_only_client(const struct test_opts *opts) static void test_stream_bind_only_server(const struct test_opts *opts) { - union { - struct sockaddr sa; - struct sockaddr_vm svm; - } addr = { - .svm = { - .svm_family = AF_VSOCK, - .svm_port = opts->peer_port, - .svm_cid = VMADDR_CID_ANY, - }, - }; int fd; - fd = socket(AF_VSOCK, SOCK_STREAM, 0); - - if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { - perror("bind"); - exit(E
Re: [PATCH net-next v2 3/3] test/vsock: add ioctl unsent bytes test
On Mon, Apr 08, 2024 at 03:37:49PM GMT, Luigi Leonardi wrote: This test that after a packet is delivered the number of unsent bytes is zero. Signed-off-by: Luigi Leonardi --- tools/testing/vsock/util.c | 6 +-- tools/testing/vsock/util.h | 3 ++ tools/testing/vsock/vsock_test.c | 85 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c index 554b290fefdc..a3d448a075e3 100644 --- a/tools/testing/vsock/util.c +++ b/tools/testing/vsock/util.c @@ -139,7 +139,7 @@ int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_po } /* Connect to and return the file descriptor. */ -static int vsock_connect(unsigned int cid, unsigned int port, int type) +int vsock_connect(unsigned int cid, unsigned int port, int type) { union { struct sockaddr sa; @@ -226,8 +226,8 @@ static int vsock_listen(unsigned int cid, unsigned int port, int type) /* Listen on and return the first incoming connection. The remote * address is stored to clientaddrp. clientaddrp may be NULL. */ -static int vsock_accept(unsigned int cid, unsigned int port, - struct sockaddr_vm *clientaddrp, int type) +int vsock_accept(unsigned int cid, unsigned int port, +struct sockaddr_vm *clientaddrp, int type) { union { struct sockaddr sa; diff --git a/tools/testing/vsock/util.h b/tools/testing/vsock/util.h index e95e62485959..fff22d4a14c0 100644 --- a/tools/testing/vsock/util.h +++ b/tools/testing/vsock/util.h @@ -39,6 +39,9 @@ struct test_case { void init_signals(void); unsigned int parse_cid(const char *str); unsigned int parse_port(const char *str); +int vsock_connect(unsigned int cid, unsigned int port, int type); +int vsock_accept(unsigned int cid, unsigned int port, +struct sockaddr_vm *clientaddrp, int type); int vsock_stream_connect(unsigned int cid, unsigned int port); int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type); diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index f851f8961247..c19ffbcca9dd 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "vsock_test_zerocopy.h" #include "timeout.h" @@ -1238,6 +1240,79 @@ static void test_double_bind_connect_client(const struct test_opts *opts) } } +#define MSG_BUF_IOCTL_LEN 64 +static void test_unsent_bytes_server(const struct test_opts *opts, int type) +{ + unsigned char buf[MSG_BUF_IOCTL_LEN]; + int client_fd; + + client_fd = vsock_accept(VMADDR_CID_ANY, 1234, NULL, type); + if (client_fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + recv_buf(client_fd, buf, sizeof(buf), 0, sizeof(buf)); + control_writeln("RECEIVED"); + + close(client_fd); +} + +static void test_unsent_bytes_client(const struct test_opts *opts, int type) +{ + unsigned char buf[MSG_BUF_IOCTL_LEN]; + int ret, fd, sock_bytes_unsent; + + fd = vsock_connect(opts->peer_cid, 1234, type); + if (fd < 0) { + perror("connect"); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < sizeof(buf); i++) + buf[i] = rand() & 0xFF; + + send_buf(fd, buf, sizeof(buf), 0, sizeof(buf)); + control_expectln("RECEIVED"); + + ret = ioctl(fd, SIOCOUTQ, &sock_bytes_unsent); + if (ret < 0) { + perror("ioctl"); + + if (errno != EOPNOTSUPP) I'm not sure `errno` is preserved after calling perror(). I'd suggest something like this: if (ret < 0) { if (errno == EOPNOTSUPP) { fprintf(stderr, "Test skipped\n"); } else { perror("ioctl"); exit(EXIT_FAILURE); } } else if ... Or if you prefer, we can avoid the “Test skipped” message and still fail as we do for other tests. Users already have ways of skipping tests and maybe in this way they are sure of what they are doing whether or not they expect this test to pass or not. The rest LGTM! Stefano + exit(EXIT_FAILURE); + + fprintf(stderr, "Test skipped\n"); + } else if (ret == 0 && sock_bytes_unsent != 0) { + fprintf(stderr, + "Unexpected 'SIOCOUTQ' value, expected 0, got %i\n", + sock_bytes_unsent); + exit(EXIT_FAILURE); + } + + close(fd); +} + +static void test_stream_unsent_bytes_client(const struct test_opts *opts) +{ +
[PATCH net-next v2 3/3] test/vsock: add ioctl unsent bytes test
This test that after a packet is delivered the number of unsent bytes is zero. Signed-off-by: Luigi Leonardi --- tools/testing/vsock/util.c | 6 +-- tools/testing/vsock/util.h | 3 ++ tools/testing/vsock/vsock_test.c | 85 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c index 554b290fefdc..a3d448a075e3 100644 --- a/tools/testing/vsock/util.c +++ b/tools/testing/vsock/util.c @@ -139,7 +139,7 @@ int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_po } /* Connect to and return the file descriptor. */ -static int vsock_connect(unsigned int cid, unsigned int port, int type) +int vsock_connect(unsigned int cid, unsigned int port, int type) { union { struct sockaddr sa; @@ -226,8 +226,8 @@ static int vsock_listen(unsigned int cid, unsigned int port, int type) /* Listen on and return the first incoming connection. The remote * address is stored to clientaddrp. clientaddrp may be NULL. */ -static int vsock_accept(unsigned int cid, unsigned int port, - struct sockaddr_vm *clientaddrp, int type) +int vsock_accept(unsigned int cid, unsigned int port, +struct sockaddr_vm *clientaddrp, int type) { union { struct sockaddr sa; diff --git a/tools/testing/vsock/util.h b/tools/testing/vsock/util.h index e95e62485959..fff22d4a14c0 100644 --- a/tools/testing/vsock/util.h +++ b/tools/testing/vsock/util.h @@ -39,6 +39,9 @@ struct test_case { void init_signals(void); unsigned int parse_cid(const char *str); unsigned int parse_port(const char *str); +int vsock_connect(unsigned int cid, unsigned int port, int type); +int vsock_accept(unsigned int cid, unsigned int port, +struct sockaddr_vm *clientaddrp, int type); int vsock_stream_connect(unsigned int cid, unsigned int port); int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type); diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index f851f8961247..c19ffbcca9dd 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "vsock_test_zerocopy.h" #include "timeout.h" @@ -1238,6 +1240,79 @@ static void test_double_bind_connect_client(const struct test_opts *opts) } } +#define MSG_BUF_IOCTL_LEN 64 +static void test_unsent_bytes_server(const struct test_opts *opts, int type) +{ + unsigned char buf[MSG_BUF_IOCTL_LEN]; + int client_fd; + + client_fd = vsock_accept(VMADDR_CID_ANY, 1234, NULL, type); + if (client_fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + recv_buf(client_fd, buf, sizeof(buf), 0, sizeof(buf)); + control_writeln("RECEIVED"); + + close(client_fd); +} + +static void test_unsent_bytes_client(const struct test_opts *opts, int type) +{ + unsigned char buf[MSG_BUF_IOCTL_LEN]; + int ret, fd, sock_bytes_unsent; + + fd = vsock_connect(opts->peer_cid, 1234, type); + if (fd < 0) { + perror("connect"); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < sizeof(buf); i++) + buf[i] = rand() & 0xFF; + + send_buf(fd, buf, sizeof(buf), 0, sizeof(buf)); + control_expectln("RECEIVED"); + + ret = ioctl(fd, SIOCOUTQ, &sock_bytes_unsent); + if (ret < 0) { + perror("ioctl"); + + if (errno != EOPNOTSUPP) + exit(EXIT_FAILURE); + + fprintf(stderr, "Test skipped\n"); + } else if (ret == 0 && sock_bytes_unsent != 0) { + fprintf(stderr, + "Unexpected 'SIOCOUTQ' value, expected 0, got %i\n", + sock_bytes_unsent); + exit(EXIT_FAILURE); + } + + close(fd); +} + +static void test_stream_unsent_bytes_client(const struct test_opts *opts) +{ + test_unsent_bytes_client(opts, SOCK_STREAM); +} + +static void test_stream_unsent_bytes_server(const struct test_opts *opts) +{ + test_unsent_bytes_server(opts, SOCK_STREAM); +} + +static void test_seqpacket_unsent_bytes_client(const struct test_opts *opts) +{ + test_unsent_bytes_client(opts, SOCK_SEQPACKET); +} + +static void test_seqpacket_unsent_bytes_server(const struct test_opts *opts) +{ + test_unsent_bytes_server(opts, SOCK_SEQPACKET); +} + #define RCVLOWAT_CREDIT_UPD_BUF_SIZE (1024 * 128) /* This define is the same as in 'include/linux/virtio_vsock.h': * it is used to decide when to send credit update message during @@ -1523,6 +1598,16 @@ static struct test_case test_cases[] =
Re: [PATCH net-next 3/3] test/vsock: add ioctl unsent bytes test
On Tue, Apr 02, 2024 at 05:05:39PM +0200, Luigi Leonardi wrote: This test that after a packet is delivered the number of unsent bytes is zero. Signed-off-by: Luigi Leonardi --- tools/testing/vsock/util.c | 6 +-- tools/testing/vsock/util.h | 3 ++ tools/testing/vsock/vsock_test.c | 83 3 files changed, 89 insertions(+), 3 deletions(-) diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c index 554b290fefdc..a3d448a075e3 100644 --- a/tools/testing/vsock/util.c +++ b/tools/testing/vsock/util.c @@ -139,7 +139,7 @@ int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_po } /* Connect to and return the file descriptor. */ -static int vsock_connect(unsigned int cid, unsigned int port, int type) +int vsock_connect(unsigned int cid, unsigned int port, int type) { union { struct sockaddr sa; @@ -226,8 +226,8 @@ static int vsock_listen(unsigned int cid, unsigned int port, int type) /* Listen on and return the first incoming connection. The remote * address is stored to clientaddrp. clientaddrp may be NULL. */ -static int vsock_accept(unsigned int cid, unsigned int port, - struct sockaddr_vm *clientaddrp, int type) +int vsock_accept(unsigned int cid, unsigned int port, +struct sockaddr_vm *clientaddrp, int type) { union { struct sockaddr sa; diff --git a/tools/testing/vsock/util.h b/tools/testing/vsock/util.h index e95e62485959..fff22d4a14c0 100644 --- a/tools/testing/vsock/util.h +++ b/tools/testing/vsock/util.h @@ -39,6 +39,9 @@ struct test_case { void init_signals(void); unsigned int parse_cid(const char *str); unsigned int parse_port(const char *str); +int vsock_connect(unsigned int cid, unsigned int port, int type); +int vsock_accept(unsigned int cid, unsigned int port, +struct sockaddr_vm *clientaddrp, int type); int vsock_stream_connect(unsigned int cid, unsigned int port); int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type); diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index f851f8961247..58c94e04e3af 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "vsock_test_zerocopy.h" #include "timeout.h" @@ -1238,6 +1240,77 @@ static void test_double_bind_connect_client(const struct test_opts *opts) } } +#define MSG_BUF_IOCTL_LEN 64 +static void test_unsent_bytes_server(const struct test_opts *opts, int type) +{ + unsigned char buf[MSG_BUF_IOCTL_LEN]; + int client_fd; + + client_fd = vsock_accept(VMADDR_CID_ANY, 1234, NULL, type); + if (client_fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + recv_buf(client_fd, buf, sizeof(buf), 0, sizeof(buf)); + control_writeln("RECEIVED"); + + close(client_fd); +} + +static void test_unsent_bytes_client(const struct test_opts *opts, int type) +{ + unsigned char buf[MSG_BUF_IOCTL_LEN]; + int ret, fd, sock_bytes_unsent; + + fd = vsock_connect(opts->peer_cid, 1234, type); + if (fd < 0) { + perror("connect"); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < sizeof(buf); i++) + buf[i] = rand() & 0xFF; + + send_buf(fd, buf, sizeof(buf), 0, sizeof(buf)); + control_expectln("RECEIVED"); + + ret = ioctl(fd, SIOCOUTQ, &sock_bytes_unsent); + if (ret < 0 && errno != EOPNOTSUPP) { What about adding a warning when it is not supported? Something like this (untested): if (ret < 0) { perror("ioctl"); if (errno != EOPNOTSUPP) { exit(EXIT_FAILURE); } fprintf(stderr, "Test skipped\n"); } The rest LGTM. Thanks, Stefano + perror("ioctl"); + exit(EXIT_FAILURE); + } + + if (ret == 0 && sock_bytes_unsent != 0) { + fprintf(stderr, + "Unexpected 'SIOCOUTQ' value, expected 0, got %i\n", + sock_bytes_unsent); + exit(EXIT_FAILURE); + } + + close(fd); +} + +static void test_stream_unsent_bytes_client(const struct test_opts *opts) +{ + test_unsent_bytes_client(opts, SOCK_STREAM); +} + +static void test_stream_unsent_bytes_server(const struct test_opts *opts) +{ + test_unsent_bytes_server(opts, SOCK_STREAM); +} + +static void test_seqpacket_unsent_bytes_client(const struct test_opts *opts) +{ + test_unsent_bytes_client(opts, SOCK_SEQPACKET); +} + +static void test_seqpacket_unsent_bytes_server(const struct tes
[PATCH net-next 3/3] test/vsock: add ioctl unsent bytes test
This test that after a packet is delivered the number of unsent bytes is zero. Signed-off-by: Luigi Leonardi --- tools/testing/vsock/util.c | 6 +-- tools/testing/vsock/util.h | 3 ++ tools/testing/vsock/vsock_test.c | 83 3 files changed, 89 insertions(+), 3 deletions(-) diff --git a/tools/testing/vsock/util.c b/tools/testing/vsock/util.c index 554b290fefdc..a3d448a075e3 100644 --- a/tools/testing/vsock/util.c +++ b/tools/testing/vsock/util.c @@ -139,7 +139,7 @@ int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_po } /* Connect to and return the file descriptor. */ -static int vsock_connect(unsigned int cid, unsigned int port, int type) +int vsock_connect(unsigned int cid, unsigned int port, int type) { union { struct sockaddr sa; @@ -226,8 +226,8 @@ static int vsock_listen(unsigned int cid, unsigned int port, int type) /* Listen on and return the first incoming connection. The remote * address is stored to clientaddrp. clientaddrp may be NULL. */ -static int vsock_accept(unsigned int cid, unsigned int port, - struct sockaddr_vm *clientaddrp, int type) +int vsock_accept(unsigned int cid, unsigned int port, +struct sockaddr_vm *clientaddrp, int type) { union { struct sockaddr sa; diff --git a/tools/testing/vsock/util.h b/tools/testing/vsock/util.h index e95e62485959..fff22d4a14c0 100644 --- a/tools/testing/vsock/util.h +++ b/tools/testing/vsock/util.h @@ -39,6 +39,9 @@ struct test_case { void init_signals(void); unsigned int parse_cid(const char *str); unsigned int parse_port(const char *str); +int vsock_connect(unsigned int cid, unsigned int port, int type); +int vsock_accept(unsigned int cid, unsigned int port, +struct sockaddr_vm *clientaddrp, int type); int vsock_stream_connect(unsigned int cid, unsigned int port); int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type); diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index f851f8961247..58c94e04e3af 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "vsock_test_zerocopy.h" #include "timeout.h" @@ -1238,6 +1240,77 @@ static void test_double_bind_connect_client(const struct test_opts *opts) } } +#define MSG_BUF_IOCTL_LEN 64 +static void test_unsent_bytes_server(const struct test_opts *opts, int type) +{ + unsigned char buf[MSG_BUF_IOCTL_LEN]; + int client_fd; + + client_fd = vsock_accept(VMADDR_CID_ANY, 1234, NULL, type); + if (client_fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + recv_buf(client_fd, buf, sizeof(buf), 0, sizeof(buf)); + control_writeln("RECEIVED"); + + close(client_fd); +} + +static void test_unsent_bytes_client(const struct test_opts *opts, int type) +{ + unsigned char buf[MSG_BUF_IOCTL_LEN]; + int ret, fd, sock_bytes_unsent; + + fd = vsock_connect(opts->peer_cid, 1234, type); + if (fd < 0) { + perror("connect"); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < sizeof(buf); i++) + buf[i] = rand() & 0xFF; + + send_buf(fd, buf, sizeof(buf), 0, sizeof(buf)); + control_expectln("RECEIVED"); + + ret = ioctl(fd, SIOCOUTQ, &sock_bytes_unsent); + if (ret < 0 && errno != EOPNOTSUPP) { + perror("ioctl"); + exit(EXIT_FAILURE); + } + + if (ret == 0 && sock_bytes_unsent != 0) { + fprintf(stderr, + "Unexpected 'SIOCOUTQ' value, expected 0, got %i\n", + sock_bytes_unsent); + exit(EXIT_FAILURE); + } + + close(fd); +} + +static void test_stream_unsent_bytes_client(const struct test_opts *opts) +{ + test_unsent_bytes_client(opts, SOCK_STREAM); +} + +static void test_stream_unsent_bytes_server(const struct test_opts *opts) +{ + test_unsent_bytes_server(opts, SOCK_STREAM); +} + +static void test_seqpacket_unsent_bytes_client(const struct test_opts *opts) +{ + test_unsent_bytes_client(opts, SOCK_SEQPACKET); +} + +static void test_seqpacket_unsent_bytes_server(const struct test_opts *opts) +{ + test_unsent_bytes_server(opts, SOCK_SEQPACKET); +} + #define RCVLOWAT_CREDIT_UPD_BUF_SIZE (1024 * 128) /* This define is the same as in 'include/linux/virtio_vsock.h': * it is used to decide when to send credit update message during @@ -1523,6 +1596,16 @@ static struct test_case test_cases[] = { .run_client = test_stream_rcvlowat_def_cred_upd_client,
Re: [PATCH v3 bpf-next 11/11] bpf: Test BPF_SK_REUSEPORT_SELECT_OR_MIGRATE.
On Tue, Apr 20, 2021 at 8:45 AM Kuniyuki Iwashima wrote: > > This patch adds a test for BPF_SK_REUSEPORT_SELECT_OR_MIGRATE and > removes 'static' from settimeo() in network_helpers.c. > > Signed-off-by: Kuniyuki Iwashima > --- Almost everything in prog_tests/migrate_reuseport.c should be static, functions and variables. Except the test_migrate_reuseport, of course. But thank you for using ASSERT_xxx()! :) > tools/testing/selftests/bpf/network_helpers.c | 2 +- > tools/testing/selftests/bpf/network_helpers.h | 1 + > .../bpf/prog_tests/migrate_reuseport.c| 483 ++ > .../bpf/progs/test_migrate_reuseport.c| 51 ++ > 4 files changed, 536 insertions(+), 1 deletion(-) > create mode 100644 tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c > create mode 100644 tools/testing/selftests/bpf/progs/test_migrate_reuseport.c > [...]
[PATCH v3 bpf-next 11/11] bpf: Test BPF_SK_REUSEPORT_SELECT_OR_MIGRATE.
This patch adds a test for BPF_SK_REUSEPORT_SELECT_OR_MIGRATE and removes 'static' from settimeo() in network_helpers.c. Signed-off-by: Kuniyuki Iwashima --- tools/testing/selftests/bpf/network_helpers.c | 2 +- tools/testing/selftests/bpf/network_helpers.h | 1 + .../bpf/prog_tests/migrate_reuseport.c| 483 ++ .../bpf/progs/test_migrate_reuseport.c| 51 ++ 4 files changed, 536 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c create mode 100644 tools/testing/selftests/bpf/progs/test_migrate_reuseport.c diff --git a/tools/testing/selftests/bpf/network_helpers.c b/tools/testing/selftests/bpf/network_helpers.c index 12ee40284da0..2060bc122c53 100644 --- a/tools/testing/selftests/bpf/network_helpers.c +++ b/tools/testing/selftests/bpf/network_helpers.c @@ -40,7 +40,7 @@ struct ipv6_packet pkt_v6 = { .tcp.doff = 5, }; -static int settimeo(int fd, int timeout_ms) +int settimeo(int fd, int timeout_ms) { struct timeval timeout = { .tv_sec = 3 }; diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h index 7205f8afdba1..5e0d51c07b63 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -33,6 +33,7 @@ struct ipv6_packet { } __packed; extern struct ipv6_packet pkt_v6; +int settimeo(int fd, int timeout_ms); int start_server(int family, int type, const char *addr, __u16 port, int timeout_ms); int connect_to_fd(int server_fd, int timeout_ms); diff --git a/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c new file mode 100644 index ..726f6380390a --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/migrate_reuseport.c @@ -0,0 +1,483 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Check if we can migrate child sockets. + * + * 1. call listen() for 5 server sockets. + * 2. update a map to migrate all child sockets + *to the last server socket (migrate_map[cookie] = 4) + * 3. call connect() for 25 client sockets. + * 4. call shutdown() for first 4 server sockets + *and migrate the requests in the accept queue + *to the last server socket. + * 5. call listen() for the second server socket. + * 6. call shutdown() for the last server + *and migrate the requests in the accept queue + *to the second server socket. + * 7. call listen() for the last server. + * 8. call shutdown() for the second server + *and migrate the requests in the accept queue + *to the last server socket. + * 9. call accept() for the last server socket. + * + * Author: Kuniyuki Iwashima + */ + +#include +#include + +#include "test_progs.h" +#include "test_migrate_reuseport.skel.h" +#include "network_helpers.h" + +#define NR_SERVERS 5 +#define NR_CLIENTS (NR_SERVERS * 5) +#define MIGRATED_TO (NR_SERVERS - 1) + +/* fastopenq->max_qlen and sk->sk_max_ack_backlog */ +#define QLEN (NR_CLIENTS * 5) + +#define MSG "Hello World" +#define MSGLEN 12 + +struct migrate_reuseport_test_case { + const char *name; + __s64 servers[NR_SERVERS]; + __s64 clients[NR_CLIENTS]; + struct sockaddr_storage addr; + socklen_t addrlen; + int family; + bool drop_ack; + bool expire_synack_timer; + bool fastopen; +} test_cases[] = { + { + .name = "IPv4 - TCP_ESTABLISHED - inet_csk_listen_stop", + .family = AF_INET, + .drop_ack = false, + .expire_synack_timer = false, + .fastopen = false, + }, + { + .name = "IPv4 - TCP_SYN_RECV - inet_csk_listen_stop", + .family = AF_INET, + .drop_ack = true, + .expire_synack_timer = false, + .fastopen = true, + }, + { + .name = "IPv4 - TCP_NEW_SYN_RECV - inet_csk_complete_hashdance", + .family = AF_INET, + .drop_ack = true, + .expire_synack_timer = false, + .fastopen = false, + }, + { + .name = "IPv4 - TCP_NEW_SYN_RECV - reqsk_timer_handler", + .family = AF_INET, + .drop_ack = true, + .expire_synack_timer = true, + .fastopen = false, + }, + { + .name = "IPv6 - TCP_ESTABLISHED - inet_csk_listen_stop", + .family = AF_INET6, + .drop_ack = false, + .expire_synack_timer = false, + .fastopen = false, + }, + { + .name = "IPv6 - TCP_SYN_RECV - inet_csk_listen_stop", + .family = AF_INET6, + .drop_ack = true, +
[PATCH net-next 10/10] selftests: mlxsw: sch_red_ets: Test proper counter cleaning in ETS
There was a bug introduced during the rework which cause non-zero backlog being stuck at ETS. Introduce a selftest that would have caught the issue earlier. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel --- tools/testing/selftests/drivers/net/mlxsw/sch_red_ets.sh | 7 +++ 1 file changed, 7 insertions(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/sch_red_ets.sh b/tools/testing/selftests/drivers/net/mlxsw/sch_red_ets.sh index 3f007c5f8361..f3ef3274f9b3 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/sch_red_ets.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/sch_red_ets.sh @@ -67,6 +67,13 @@ red_test() { install_qdisc + # Make sure that we get the non-zero value if there is any. + local cur=$(busywait 1100 until_counter_is "> 0" \ + qdisc_stats_get $swp3 10: .backlog) + (( cur == 0 )) + check_err $? "backlog of $cur observed on non-busy qdisc" + log_test "$QDISC backlog properly cleaned" + do_red_test 10 $BACKLOG1 do_red_test 11 $BACKLOG2 -- 2.26.2
[Patch bpf-next v2 9/9] selftests/bpf: add test cases for redirection between udp and unix
From: Cong Wang Add two test cases to ensure redirection between udp and unix work bidirectionally. Cc: John Fastabend Cc: Daniel Borkmann Cc: Jakub Sitnicki Cc: Lorenz Bauer Signed-off-by: Cong Wang --- .../selftests/bpf/prog_tests/sockmap_listen.c | 165 ++ 1 file changed, 165 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c index 2b1bdb8fa48d..01c052e15a83 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c @@ -1813,6 +1813,170 @@ static void test_udp_redir(struct test_sockmap_listen *skel, struct bpf_map *map udp_skb_redir_to_connected(skel, map, family); } +static void udp_unix_redir_to_connected(int family, int sock_mapfd, + int verd_mapfd, enum redir_mode mode) +{ + const char *log_prefix = redir_mode_str(mode); + int c0, c1, p0, p1; + unsigned int pass; + int err, n; + int sfd[2]; + u32 key; + char b; + + zero_verdict_count(verd_mapfd); + + if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, sfd)) + return; + c0 = sfd[0], p0 = sfd[1]; + + err = udp_socketpair(family, &p1, &c1); + if (err) + goto close; + + err = add_to_sockmap(sock_mapfd, p0, p1); + if (err) + goto close_cli1; + + n = write(c1, "a", 1); + if (n < 0) + FAIL_ERRNO("%s: write", log_prefix); + if (n == 0) + FAIL("%s: incomplete write", log_prefix); + if (n < 1) + goto close_cli1; + + key = SK_PASS; + err = xbpf_map_lookup_elem(verd_mapfd, &key, &pass); + if (err) + goto close_cli1; + if (pass != 1) + FAIL("%s: want pass count 1, have %d", log_prefix, pass); + + n = read(mode == REDIR_INGRESS ? p0 : c0, &b, 1); + if (n < 0) + FAIL_ERRNO("%s: read", log_prefix); + if (n == 0) + FAIL("%s: incomplete read", log_prefix); + +close_cli1: + xclose(c1); + xclose(p1); +close: + xclose(c0); + xclose(p0); +} + +static void udp_unix_skb_redir_to_connected(struct test_sockmap_listen *skel, + struct bpf_map *inner_map, int family) +{ + int verdict = bpf_program__fd(skel->progs.prog_skb_verdict); + int verdict_map = bpf_map__fd(skel->maps.verdict_map); + int sock_map = bpf_map__fd(inner_map); + int err; + + err = xbpf_prog_attach(verdict, sock_map, BPF_SK_SKB_VERDICT, 0); + if (err) + return; + + skel->bss->test_ingress = false; + udp_unix_redir_to_connected(family, sock_map, verdict_map, REDIR_EGRESS); + skel->bss->test_ingress = true; + udp_unix_redir_to_connected(family, sock_map, verdict_map, REDIR_INGRESS); + + xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT); +} + +static void unix_udp_redir_to_connected(int family, int sock_mapfd, + int verd_mapfd, enum redir_mode mode) +{ + const char *log_prefix = redir_mode_str(mode); + int c0, c1, p0, p1; + unsigned int pass; + int err, n; + int sfd[2]; + u32 key; + char b; + + zero_verdict_count(verd_mapfd); + + err = udp_socketpair(family, &p0, &c0); + if (err) + return; + + if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, sfd)) + goto close_cli0; + c1 = sfd[0], p1 = sfd[1]; + + err = add_to_sockmap(sock_mapfd, p0, p1); + if (err) + goto close; + + n = write(c1, "a", 1); + if (n < 0) + FAIL_ERRNO("%s: write", log_prefix); + if (n == 0) + FAIL("%s: incomplete write", log_prefix); + if (n < 1) + goto close; + + key = SK_PASS; + err = xbpf_map_lookup_elem(verd_mapfd, &key, &pass); + if (err) + goto close; + if (pass != 1) + FAIL("%s: want pass count 1, have %d", log_prefix, pass); + + n = read(mode == REDIR_INGRESS ? p0 : c0, &b, 1); + if (n < 0) + FAIL_ERRNO("%s: read", log_prefix); + if (n == 0) + FAIL("%s: incomplete read", log_prefix); + +close: + xclose(c1); + xclose(p1); +close_cli0: + xclose(c0); + xclose(p0); + +} + +static void unix_udp_skb_redir_to_connected(struct test_sockmap_listen *skel, + struct bpf_map *inner_map, int family) +{ + int verdict = bpf_program__fd(skel->progs.prog_skb_verdict); + int verdict
[Patch bpf-next v2 8/9] selftests/bpf: add a test case for unix sockmap
From: Cong Wang Add a test case to ensure redirection between two AF_UNIX datagram sockets work. Cc: John Fastabend Cc: Daniel Borkmann Cc: Jakub Sitnicki Cc: Lorenz Bauer Signed-off-by: Cong Wang --- .../selftests/bpf/prog_tests/sockmap_listen.c | 92 +++ 1 file changed, 92 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c index ee017278fae4..2b1bdb8fa48d 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c @@ -1433,6 +1433,8 @@ static const char *family_str(sa_family_t family) return "IPv4"; case AF_INET6: return "IPv6"; + case AF_UNIX: + return "Unix"; default: return "unknown"; } @@ -1555,6 +1557,94 @@ static void test_redir(struct test_sockmap_listen *skel, struct bpf_map *map, } } +static void unix_redir_to_connected(int sotype, int sock_mapfd, + int verd_mapfd, enum redir_mode mode) +{ + const char *log_prefix = redir_mode_str(mode); + int c0, c1, p0, p1; + unsigned int pass; + int err, n; + int sfd[2]; + u32 key; + char b; + + zero_verdict_count(verd_mapfd); + + if (socketpair(AF_UNIX, sotype | SOCK_NONBLOCK, 0, sfd)) + return; + c0 = sfd[0], p0 = sfd[1]; + + if (socketpair(AF_UNIX, sotype | SOCK_NONBLOCK, 0, sfd)) + goto close0; + c1 = sfd[0], p1 = sfd[1]; + + err = add_to_sockmap(sock_mapfd, p0, p1); + if (err) + goto close; + + n = write(c1, "a", 1); + if (n < 0) + FAIL_ERRNO("%s: write", log_prefix); + if (n == 0) + FAIL("%s: incomplete write", log_prefix); + if (n < 1) + goto close; + + key = SK_PASS; + err = xbpf_map_lookup_elem(verd_mapfd, &key, &pass); + if (err) + goto close; + if (pass != 1) + FAIL("%s: want pass count 1, have %d", log_prefix, pass); + + n = read(mode == REDIR_INGRESS ? p0 : c0, &b, 1); + if (n < 0) + FAIL_ERRNO("%s: read", log_prefix); + if (n == 0) + FAIL("%s: incomplete read", log_prefix); + +close: + xclose(c1); + xclose(p1); +close0: + xclose(c0); + xclose(p0); +} + +static void unix_skb_redir_to_connected(struct test_sockmap_listen *skel, + struct bpf_map *inner_map, int sotype) +{ + int verdict = bpf_program__fd(skel->progs.prog_skb_verdict); + int verdict_map = bpf_map__fd(skel->maps.verdict_map); + int sock_map = bpf_map__fd(inner_map); + int err; + + err = xbpf_prog_attach(verdict, sock_map, BPF_SK_SKB_VERDICT, 0); + if (err) + return; + + skel->bss->test_ingress = false; + unix_redir_to_connected(sotype, sock_map, verdict_map, REDIR_EGRESS); + skel->bss->test_ingress = true; + unix_redir_to_connected(sotype, sock_map, verdict_map, REDIR_INGRESS); + + xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT); +} + +static void test_unix_redir(struct test_sockmap_listen *skel, struct bpf_map *map, + int sotype) +{ + const char *family_name, *map_name; + char s[MAX_TEST_NAME]; + + family_name = family_str(AF_UNIX); + map_name = map_type_str(map); + snprintf(s, sizeof(s), "%s %s %s", map_name, family_name, __func__); + if (!test__start_subtest(s)) + return; + unix_skb_redir_to_connected(skel, map, sotype); +} + static void test_reuseport(struct test_sockmap_listen *skel, struct bpf_map *map, int family, int sotype) { @@ -1747,10 +1837,12 @@ void test_sockmap_listen(void) skel->bss->test_sockmap = true; run_tests(skel, skel->maps.sock_map, AF_INET); run_tests(skel, skel->maps.sock_map, AF_INET6); + test_unix_redir(skel, skel->maps.sock_map, SOCK_DGRAM); skel->bss->test_sockmap = false; run_tests(skel, skel->maps.sock_hash, AF_INET); run_tests(skel, skel->maps.sock_hash, AF_INET6); + test_unix_redir(skel, skel->maps.sock_hash, SOCK_DGRAM); test_sockmap_listen__destroy(skel); } -- 2.25.1
[PATCH net-next 13/14] selftests: fib_tests: Add test cases for interaction with mangling
From: Ido Schimmel Test that packets are correctly routed when netfilter mangling rules are present. Without previous patch: # ./fib_tests.sh -t ipv4_mangle IPv4 mangling tests TEST: Connection with correct parameters[ OK ] TEST: Connection with incorrect parameters [ OK ] TEST: Connection with correct parameters - mangling [FAIL] TEST: Connection with correct parameters - no mangling [ OK ] TEST: Connection check - server side[FAIL] Tests passed: 3 Tests failed: 2 # ./fib_tests.sh -t ipv6_mangle IPv6 mangling tests TEST: Connection with correct parameters[ OK ] TEST: Connection with incorrect parameters [ OK ] TEST: Connection with correct parameters - mangling [FAIL] TEST: Connection with correct parameters - no mangling [ OK ] TEST: Connection check - server side[FAIL] Tests passed: 3 Tests failed: 2 With previous patch: # ./fib_tests.sh -t ipv4_mangle IPv4 mangling tests TEST: Connection with correct parameters[ OK ] TEST: Connection with incorrect parameters [ OK ] TEST: Connection with correct parameters - mangling [ OK ] TEST: Connection with correct parameters - no mangling [ OK ] TEST: Connection check - server side[ OK ] Tests passed: 5 Tests failed: 0 # ./fib_tests.sh -t ipv6_mangle IPv6 mangling tests TEST: Connection with correct parameters[ OK ] TEST: Connection with incorrect parameters [ OK ] TEST: Connection with correct parameters - mangling [ OK ] TEST: Connection with correct parameters - no mangling [ OK ] TEST: Connection check - server side[ OK ] Tests passed: 5 Tests failed: 0 Signed-off-by: Ido Schimmel Reviewed-by: David Ahern Signed-off-by: Pablo Neira Ayuso --- tools/testing/selftests/net/fib_tests.sh | 152 ++- 1 file changed, 151 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index 2b5707738609..76d9487fb03c 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -9,7 +9,7 @@ ret=0 ksft_skip=4 # all tests in this script. Can be overridden with -t option -TESTS="unregister down carrier nexthop suppress ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr" +TESTS="unregister down carrier nexthop suppress ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr ipv4_mangle ipv6_mangle" VERBOSE=0 PAUSE_ON_FAIL=no @@ -1653,6 +1653,154 @@ ipv4_route_v6_gw_test() route_cleanup } +socat_check() +{ + if [ ! -x "$(command -v socat)" ]; then + echo "socat command not found. Skipping test" + return 1 + fi + + return 0 +} + +iptables_check() +{ + iptables -t mangle -L OUTPUT &> /dev/null + if [ $? -ne 0 ]; then + echo "iptables configuration not supported. Skipping test" + return 1 + fi + + return 0 +} + +ip6tables_check() +{ + ip6tables -t mangle -L OUTPUT &> /dev/null + if [ $? -ne 0 ]; then + echo "ip6tables configuration not supported. Skipping test" + return 1 + fi + + return 0 +} + +ipv4_mangle_test() +{ + local rc + + echo + echo "IPv4 mangling tests" + + socat_check || return 1 + iptables_check || return 1 + + route_setup + sleep 2 + + local tmp_file=$(mktemp) + ip netns exec ns2 socat UDP4-LISTEN:54321,fork $tmp_file & + + # Add a FIB rule and a route that will direct our connection to the + # listening server. + $IP rule add pref 100 ipproto udp sport 12345 dport 54321 table 123 + $IP route add table 123 172.16.101.0/24 dev veth1 + + # Add an unreachable route to the main table that will block our + # connection in case the FIB rule is not hit. + $IP route add unreachable 172.16.101.2/32 + + run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345" + log_test $? 0 "Connection with correct parameters" + + run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=1" + log_test $? 1 "Connection with incorrect parameters" + +
Re: [PATCH net-next 2/2] selftests: fib_nexthops: Test large scale nexthop flushing
On 4/16/21 8:55 AM, Ido Schimmel wrote: > From: Ido Schimmel > > Test that all the nexthops are flushed when a multi-part nexthop dump is > required for the flushing. > > Without previous patch: > > # ./fib_nexthops.sh > TEST: Large scale nexthop flushing [FAIL] > > With previous patch: > > # ./fib_nexthops.sh > TEST: Large scale nexthop flushing [ OK ] > > Signed-off-by: Ido Schimmel > Reviewed-by: Petr Machata > --- > tools/testing/selftests/net/fib_nexthops.sh | 15 +++ > 1 file changed, 15 insertions(+) > Reviewed-by: David Ahern
[PATCH bpf-next 07/15] selftests/bpf: Test for btf_load command.
From: Alexei Starovoitov Improve selftest to check that btf_load is working from bpf program. Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/progs/syscall.c | 48 + 1 file changed, 48 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/syscall.c b/tools/testing/selftests/bpf/progs/syscall.c index 01476f88e45f..b6ac10f75c37 100644 --- a/tools/testing/selftests/bpf/progs/syscall.c +++ b/tools/testing/selftests/bpf/progs/syscall.c @@ -4,6 +4,7 @@ #include #include #include +#include #include <../../tools/include/linux/filter.h> volatile const int workaround = 1; @@ -18,6 +19,45 @@ struct args { int prog_fd; }; +#define BTF_INFO_ENC(kind, kind_flag, vlen) \ + ((!!(kind_flag) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN)) +#define BTF_TYPE_ENC(name, info, size_or_type) (name), (info), (size_or_type) +#define BTF_INT_ENC(encoding, bits_offset, nr_bits) \ + ((encoding) << 24 | (bits_offset) << 16 | (nr_bits)) +#define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \ + BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \ + BTF_INT_ENC(encoding, bits_offset, bits) + +static int btf_load(void) +{ + struct btf_blob { + struct btf_header btf_hdr; + __u32 types[8]; + __u32 str; + } raw_btf = { + .btf_hdr = { + .magic = BTF_MAGIC, + .version = BTF_VERSION, + .hdr_len = sizeof(struct btf_header), + .type_len = sizeof(__u32) * 8, + .str_off = sizeof(__u32) * 8, + .str_len = sizeof(__u32), + }, + .types = { + /* long */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 64, 8), /* [1] */ + /* unsigned long */ + BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */ + }, + }; + static union bpf_attr btf_load_attr = { + .btf_size = sizeof(raw_btf), + }; + + btf_load_attr.btf = (long)&raw_btf; + return bpf_sys_bpf(BPF_BTF_LOAD, &btf_load_attr, sizeof(btf_load_attr)); +} + SEC("syscall") int bpf_prog(struct args *ctx) { @@ -35,6 +75,8 @@ int bpf_prog(struct args *ctx) .map_type = BPF_MAP_TYPE_HASH, .key_size = 8, .value_size = 8, + .btf_key_type_id = 1, + .btf_value_type_id = 2, }; static union bpf_attr map_update_attr = { .map_fd = 1, }; static __u64 key = 12; @@ -45,7 +87,13 @@ int bpf_prog(struct args *ctx) }; int ret; + ret = btf_load(); + if (ret < 0) + return ret; + map_create_attr.max_entries = ctx->max_entries; + map_create_attr.btf_fd = ret; + prog_load_attr.license = (long) license; prog_load_attr.insns = (long) insns; prog_load_attr.log_buf = ctx->log_buf; -- 2.30.2
[PATCH bpf-next 05/15] selftests/bpf: Test for syscall program type
From: Alexei Starovoitov bpf_prog_type_syscall is a program that creates a bpf map, updates it, and loads another bpf program using bpf_sys_bpf() helper. Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/Makefile | 1 + .../selftests/bpf/prog_tests/syscall.c| 53 ++ tools/testing/selftests/bpf/progs/syscall.c | 73 +++ 3 files changed, 127 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/syscall.c create mode 100644 tools/testing/selftests/bpf/progs/syscall.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index c45ae13b88a0..5e618ff1e8fd 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -277,6 +277,7 @@ MENDIAN=$(if $(IS_LITTLE_ENDIAN),-mlittle-endian,-mbig-endian) CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG)) BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \ -I$(INCLUDE_DIR) -I$(CURDIR) -I$(APIDIR) \ +-I$(TOOLSINCDIR) \ -I$(abspath $(OUTPUT)/../usr/include) CLANG_CFLAGS = $(CLANG_SYS_INCLUDES) \ diff --git a/tools/testing/selftests/bpf/prog_tests/syscall.c b/tools/testing/selftests/bpf/prog_tests/syscall.c new file mode 100644 index ..e550e36bb5da --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/syscall.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2021 Facebook */ +#include +#include "syscall.skel.h" + +struct args { + __u64 log_buf; + __u32 log_size; + int max_entries; + int map_fd; + int prog_fd; +}; + +void test_syscall(void) +{ + static char verifier_log[8192]; + struct args ctx = { + .max_entries = 1024, + .log_buf = (uintptr_t) verifier_log, + .log_size = sizeof(verifier_log), + }; + struct bpf_prog_test_run_attr tattr = { + .ctx_in = &ctx, + .ctx_size_in = sizeof(ctx), + }; + struct syscall *skel = NULL; + __u64 key = 12, value = 0; + __u32 duration = 0; + int err; + + skel = syscall__open_and_load(); + if (CHECK(!skel, "skel_load", "syscall skeleton failed\n")) + goto cleanup; + + tattr.prog_fd = bpf_program__fd(skel->progs.bpf_prog); + err = bpf_prog_test_run_xattr(&tattr); + if (CHECK(err || tattr.retval != 1, "test_run sys_bpf", + "err %d errno %d retval %d duration %d\n", + err, errno, tattr.retval, tattr.duration)) + goto cleanup; + + CHECK(ctx.map_fd <= 0, "map_fd", "fd = %d\n", ctx.map_fd); + CHECK(ctx.prog_fd <= 0, "prog_fd", "fd = %d\n", ctx.prog_fd); + CHECK(memcmp(verifier_log, "processed", sizeof("processed") - 1) != 0, + "verifier_log", "%s\n", verifier_log); + + err = bpf_map_lookup_elem(ctx.map_fd, &key, &value); + CHECK(err, "map_lookup", "map_lookup failed\n"); + CHECK(value != 34, "invalid_value", + "got value %llu expected %u\n", value, 34); +cleanup: + syscall__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/syscall.c b/tools/testing/selftests/bpf/progs/syscall.c new file mode 100644 index ..01476f88e45f --- /dev/null +++ b/tools/testing/selftests/bpf/progs/syscall.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2021 Facebook */ +#include +#include +#include +#include +#include <../../tools/include/linux/filter.h> + +volatile const int workaround = 1; + +char _license[] SEC("license") = "GPL"; + +struct args { + __u64 log_buf; + __u32 log_size; + int max_entries; + int map_fd; + int prog_fd; +}; + +SEC("syscall") +int bpf_prog(struct args *ctx) +{ + static char license[] = "GPL"; + static struct bpf_insn insns[] = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + static union bpf_attr map_create_attr = { + .map_type = BPF_MAP_TYPE_HASH, + .key_size = 8, + .value_size = 8, + }; + static union bpf_attr map_update_attr = { .map_fd = 1, }; + static __u64 key = 12; + static __u64 value = 34; + static union bpf_attr prog_load_attr = { + .prog_type = BPF_PROG_TYPE_XDP, + .insn_cnt = sizeof(insns) / sizeof(insns[0]), + }; + int ret; + + map_create_attr.max_entries = ctx->max_entries; + prog_load_attr.license = (long) license; + prog_load_attr.insns = (long) insns; + prog_load_attr.log_b
[PATCH net-next 2/2] selftests: fib_nexthops: Test large scale nexthop flushing
From: Ido Schimmel Test that all the nexthops are flushed when a multi-part nexthop dump is required for the flushing. Without previous patch: # ./fib_nexthops.sh TEST: Large scale nexthop flushing [FAIL] With previous patch: # ./fib_nexthops.sh TEST: Large scale nexthop flushing [ OK ] Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata --- tools/testing/selftests/net/fib_nexthops.sh | 15 +++ 1 file changed, 15 insertions(+) diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh index 56dd0c6f2e96..49774a8a7736 100755 --- a/tools/testing/selftests/net/fib_nexthops.sh +++ b/tools/testing/selftests/net/fib_nexthops.sh @@ -1933,6 +1933,21 @@ basic() log_test $? 2 "Nexthop group and blackhole" $IP nexthop flush >/dev/null 2>&1 + + # Test to ensure that flushing with a multi-part nexthop dump works as + # expected. + local batch_file=$(mktemp) + + for i in $(seq 1 $((64 * 1024))); do + echo "nexthop add id $i blackhole" >> $batch_file + done + + $IP -b $batch_file + $IP nexthop flush >/dev/null 2>&1 + [[ $($IP nexthop | wc -l) -eq 0 ]] + log_test $? 0 "Large scale nexthop flushing" + + rm $batch_file } check_nexthop_buckets_balance() -- 2.30.2
[PATCH net-next 13/13] selftests: mptcp: add packet mark test case
From: Florian Westphal Extend mptcp_connect tool with SO_MARK support (-M ) and add a test case that checks that the packet mark gets copied to all subflows. This is done by only allowing packets with either skb->mark 1 or 2 via iptables. DROP rule packet counter is checked; if its not zero, print an error message and fail the test case. Acked-by: Paolo Abeni Signed-off-by: Florian Westphal Signed-off-by: Mat Martineau --- tools/testing/selftests/net/mptcp/Makefile| 2 +- .../selftests/net/mptcp/mptcp_connect.c | 23 +- .../selftests/net/mptcp/mptcp_sockopt.sh | 276 ++ 3 files changed, 299 insertions(+), 2 deletions(-) create mode 100755 tools/testing/selftests/net/mptcp/mptcp_sockopt.sh diff --git a/tools/testing/selftests/net/mptcp/Makefile b/tools/testing/selftests/net/mptcp/Makefile index 00bb158b4a5d..f1464f09b080 100644 --- a/tools/testing/selftests/net/mptcp/Makefile +++ b/tools/testing/selftests/net/mptcp/Makefile @@ -6,7 +6,7 @@ KSFT_KHDR_INSTALL := 1 CFLAGS = -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include TEST_PROGS := mptcp_connect.sh pm_netlink.sh mptcp_join.sh diag.sh \ - simult_flows.sh + simult_flows.sh mptcp_sockopt.sh TEST_GEN_FILES = mptcp_connect pm_nl_ctl diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c index 69d89b5d666f..2f207cf33661 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_connect.c +++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c @@ -57,6 +57,7 @@ static bool cfg_join; static bool cfg_remove; static unsigned int cfg_do_w; static int cfg_wait; +static uint32_t cfg_mark; static void die_usage(void) { @@ -69,6 +70,7 @@ static void die_usage(void) fprintf(stderr, "\t-p num -- use port num\n"); fprintf(stderr, "\t-s [MPTCP|TCP] -- use mptcp(default) or tcp sockets\n"); fprintf(stderr, "\t-m [poll|mmap|sendfile] -- use poll(default)/mmap+write/sendfile\n"); + fprintf(stderr, "\t-M mark -- set socket packet mark\n"); fprintf(stderr, "\t-u -- check mptcp ulp\n"); fprintf(stderr, "\t-w num -- wait num sec before closing the socket\n"); exit(1); @@ -140,6 +142,17 @@ static void set_sndbuf(int fd, unsigned int size) } } +static void set_mark(int fd, uint32_t mark) +{ + int err; + + err = setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)); + if (err) { + perror("set SO_MARK"); + exit(1); + } +} + static int sock_listen_mptcp(const char * const listenaddr, const char * const port) { @@ -248,6 +261,9 @@ static int sock_connect_mptcp(const char * const remoteaddr, continue; } + if (cfg_mark) + set_mark(sock, cfg_mark); + if (connect(sock, a->ai_addr, a->ai_addrlen) == 0) break; /* success */ @@ -830,7 +846,7 @@ static void parse_opts(int argc, char **argv) { int c; - while ((c = getopt(argc, argv, "6jr:lp:s:hut:m:S:R:w:")) != -1) { + while ((c = getopt(argc, argv, "6jr:lp:s:hut:m:S:R:w:M:")) != -1) { switch (c) { case 'j': cfg_join = true; @@ -880,6 +896,9 @@ static void parse_opts(int argc, char **argv) case 'w': cfg_wait = atoi(optarg)*100; break; + case 'M': + cfg_mark = strtol(optarg, NULL, 0); + break; } } @@ -911,6 +930,8 @@ int main(int argc, char *argv[]) set_rcvbuf(fd, cfg_rcvbuf); if (cfg_sndbuf) set_sndbuf(fd, cfg_sndbuf); + if (cfg_mark) + set_mark(fd, cfg_mark); return main_loop_s(fd); } diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh new file mode 100755 index ..2fa13946ac04 --- /dev/null +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh @@ -0,0 +1,276 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +ret=0 +sin="" +sout="" +cin="" +cout="" +ksft_skip=4 +timeout_poll=30 +timeout_test=$((timeout_poll * 2 + 1)) +mptcp_connect="" +do_all_tests=1 + +add_mark_rules() +{ + local ns=$1 + local m=$2 + + for t in iptables ip6tables; do + # just to debug: check we have multiple subflows connection requests + ip netns exec $ns $t -A OUTPUT -p tcp --syn -m mark --mark $m -j ACCEPT + + # RST packets might be handled by a internal dummy socket +
Re: [PATCHv5 bpf-next 7/7] selftests/bpf: Use ASSERT macros in lsm test
On Wed, Apr 14, 2021 at 12:52 PM Jiri Olsa wrote: > > Replacing CHECK with ASSERT macros. > > Suggested-by: Andrii Nakryiko > Signed-off-by: Jiri Olsa > --- thanks! Acked-by: Andrii Nakryiko > .../selftests/bpf/prog_tests/test_lsm.c | 27 +++ > 1 file changed, 10 insertions(+), 17 deletions(-) > > diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c > b/tools/testing/selftests/bpf/prog_tests/test_lsm.c > index d492e76e01cf..244c01125126 100644 > --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c > +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c > @@ -18,8 +18,6 @@ char *CMD_ARGS[] = {"true", NULL}; > #define GET_PAGE_ADDR(ADDR, PAGE_SIZE) \ > (char *)(((unsigned long) (ADDR + PAGE_SIZE)) & ~(PAGE_SIZE-1)) > [...]
[PATCHv8 bpf-next 4/4] selftests/bpf: add xdp_redirect_multi test
Add a bpf selftest for new helper xdp_redirect_map_multi(). In this test there are 3 forward groups and 1 exclude group. The test will redirect each interface's packets to all the interfaces in the forward group, and exclude the interface in exclude map. Two maps (DEVMAP, DEVMAP_HASH) and two xdp modes (generic, drive) will be tested. XDP egress program will also be tested by setting pkt src MAC to egress interface's MAC address. For more test details, you can find it in the test script. Here is the test result. ]# ./test_xdp_redirect_multi.sh Pass: xdpgeneric arp ns1-2 Pass: xdpgeneric arp ns1-3 Pass: xdpgeneric arp ns1-4 Pass: xdpgeneric ping ns1-2 Pass: xdpgeneric ping ns1-3 Pass: xdpgeneric ping ns1-4 Pass: xdpgeneric ping6 ns1-2 Pass: xdpgeneric ping6 ns1-1 number Pass: xdpgeneric ping6 ns1-2 number Pass: xdpdrv arp ns1-2 Pass: xdpdrv arp ns1-3 Pass: xdpdrv arp ns1-4 Pass: xdpdrv ping ns1-2 Pass: xdpdrv ping ns1-3 Pass: xdpdrv ping ns1-4 Pass: xdpdrv ping6 ns1-2 Pass: xdpdrv ping6 ns1-1 number Pass: xdpdrv ping6 ns1-2 number Pass: xdpegress mac ns1-2 Pass: xdpegress mac ns1-3 Pass: xdpegress mac ns1-4 Summary: PASS 21, FAIL 0 Acked-by: Toke Høiland-Jørgensen Signed-off-by: Hangbin Liu --- v2: add a IPv6 test to validates that single redirect still works after multicast redirect. --- tools/testing/selftests/bpf/Makefile | 3 +- .../bpf/progs/xdp_redirect_multi_kern.c | 99 .../selftests/bpf/test_xdp_redirect_multi.sh | 205 +++ .../selftests/bpf/xdp_redirect_multi.c| 236 ++ 4 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c create mode 100755 tools/testing/selftests/bpf/test_xdp_redirect_multi.sh create mode 100644 tools/testing/selftests/bpf/xdp_redirect_multi.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 6448c626498f..0c08b662a64e 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -49,6 +49,7 @@ TEST_FILES = xsk_prereqs.sh \ # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ test_xdp_redirect.sh \ + test_xdp_redirect_multi.sh \ test_xdp_meta.sh \ test_xdp_veth.sh \ test_offload.py \ @@ -79,7 +80,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \ test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \ - xdpxceiver + xdpxceiver xdp_redirect_multi TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read diff --git a/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c b/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c new file mode 100644 index ..099bf444acab --- /dev/null +++ b/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* It would be easier to use a key:if_index, value:if_index map, but it + * will need a very large entries as the if_index number may get very large, + * this would affect the performace. So the DEVMAP here is just for testing. + */ +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 1024); +} map_v4 SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 128); +} map_all SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 128); +} map_egress SEC(".maps"); + +/* map to store egress interfaces mac addresses */ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u32); + __type(value, __be64); + __uint(max_entries, 128); +} mac_map SEC(".maps"); + +SEC("xdp_redirect_map_multi") +int xdp_redirect_map_multi_prog(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + int if_index = ctx->ingress_ifindex; + struct ethhdr *eth = data; + __u16 h_proto; + __u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + h_proto = eth->h_proto; + + if (h_proto == bpf_htons(ETH_P_IP)) + return bpf_redirect_map(&map_v4, 0, BPF_F_REDIR_MASK); + else if (h_proto == bpf_htons(ETH_P_IPV6)) + return bpf
[PATCHv8 bpf-next 3/4] sample/bpf: add xdp_redirect_map_multi for redirect_map broadcast test
This is a sample for xdp redirect broadcast. In the sample we could forward all packets between given interfaces. There is also an option -X that could enable 2nd xdp_prog on egress interface. Acked-by: Toke Høiland-Jørgensen Signed-off-by: Hangbin Liu --- samples/bpf/Makefile | 3 + samples/bpf/xdp_redirect_map_multi_kern.c | 87 +++ samples/bpf/xdp_redirect_map_multi_user.c | 302 ++ 3 files changed, 392 insertions(+) create mode 100644 samples/bpf/xdp_redirect_map_multi_kern.c create mode 100644 samples/bpf/xdp_redirect_map_multi_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 45ceca4e2c70..520434ea966f 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -41,6 +41,7 @@ tprogs-y += test_map_in_map tprogs-y += per_socket_stats_example tprogs-y += xdp_redirect tprogs-y += xdp_redirect_map +tprogs-y += xdp_redirect_map_multi tprogs-y += xdp_redirect_cpu tprogs-y += xdp_monitor tprogs-y += xdp_rxq_info @@ -99,6 +100,7 @@ test_map_in_map-objs := test_map_in_map_user.o per_socket_stats_example-objs := cookie_uid_helper_example.o xdp_redirect-objs := xdp_redirect_user.o xdp_redirect_map-objs := xdp_redirect_map_user.o +xdp_redirect_map_multi-objs := xdp_redirect_map_multi_user.o xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o xdp_monitor-objs := xdp_monitor_user.o xdp_rxq_info-objs := xdp_rxq_info_user.o @@ -160,6 +162,7 @@ always-y += tcp_tos_reflect_kern.o always-y += tcp_dumpstats_kern.o always-y += xdp_redirect_kern.o always-y += xdp_redirect_map_kern.o +always-y += xdp_redirect_map_multi_kern.o always-y += xdp_redirect_cpu_kern.o always-y += xdp_monitor_kern.o always-y += xdp_rxq_info_kern.o diff --git a/samples/bpf/xdp_redirect_map_multi_kern.c b/samples/bpf/xdp_redirect_map_multi_kern.c new file mode 100644 index ..e6be70225ee1 --- /dev/null +++ b/samples/bpf/xdp_redirect_map_multi_kern.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 32); +} forward_map_general SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 32); +} forward_map_native SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __type(key, u32); + __type(value, long); + __uint(max_entries, 1); +} rxcnt SEC(".maps"); + +/* map to store egress interfaces mac addresses, set the + * max_entries to 1 and extend it in user sapce prog. + */ +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, u32); + __type(value, __be64); + __uint(max_entries, 1); +} mac_map SEC(".maps"); + +static int xdp_redirect_map(struct xdp_md *ctx, void *forward_map) +{ + long *value; + u32 key = 0; + + /* count packet in global counter */ + value = bpf_map_lookup_elem(&rxcnt, &key); + if (value) + *value += 1; + + return bpf_redirect_map(forward_map, key, BPF_F_REDIR_MASK); +} + +SEC("xdp_redirect_general") +int xdp_redirect_map_general(struct xdp_md *ctx) +{ + return xdp_redirect_map(ctx, &forward_map_general); +} + +SEC("xdp_redirect_native") +int xdp_redirect_map_native(struct xdp_md *ctx) +{ + return xdp_redirect_map(ctx, &forward_map_native); +} + +SEC("xdp_devmap/map_prog") +int xdp_devmap_prog(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + u32 key = ctx->egress_ifindex; + struct ethhdr *eth = data; + __be64 *mac; + u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + mac = bpf_map_lookup_elem(&mac_map, &key); + if (mac) + __builtin_memcpy(eth->h_source, mac, ETH_ALEN); + + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/xdp_redirect_map_multi_user.c b/samples/bpf/xdp_redirect_map_multi_user.c new file mode 100644 index ..84cdbbed20b7 --- /dev/null +++ b/samples/bpf/xdp_redirect_map_multi_user.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_util.h" +#include +#include + +#define MAX_IFACE_NUM 32 + +static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; +static int ifaces[MAX_IFACE_NUM] = {}; +static int rxcnt_map_fd; + +static void int_exit(int sig) +{ + __u32 prog_id = 0; + int i; + + for (i = 0; ifaces[i] > 0; i++) { + if
Re: [PATCHv4 bpf-next 2/5] selftests/bpf: Add re-attach test to fentry_test
On Wed, Apr 14, 2021 at 3:57 AM Jiri Olsa wrote: > > On Tue, Apr 13, 2021 at 02:54:10PM -0700, Andrii Nakryiko wrote: > > SNIP > > > > __u32 duration = 0, retval; > > > + struct bpf_link *link; > > > __u64 *result; > > > > > > - fentry_skel = fentry_test__open_and_load(); > > > - if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton > > > failed\n")) > > > - goto cleanup; > > > - > > > err = fentry_test__attach(fentry_skel); > > > - if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", > > > err)) > > > - goto cleanup; > > > + if (!ASSERT_OK(err, "fentry_attach")) > > > + return err; > > > + > > > + /* Check that already linked program can't be attached again. */ > > > + link = bpf_program__attach(fentry_skel->progs.test1); > > > + if (!ASSERT_ERR_PTR(link, "fentry_attach_link")) > > > + return -1; > > > > > > prog_fd = bpf_program__fd(fentry_skel->progs.test1); > > > err = bpf_prog_test_run(prog_fd, 1, NULL, 0, > > > NULL, NULL, &retval, &duration); > > > - CHECK(err || retval, "test_run", > > > - "err %d errno %d retval %d duration %d\n", > > > - err, errno, retval, duration); > > > + ASSERT_OK(err || retval, "test_run"); > > > > this is quite misleading, even if will result in a correct check. Toke > > did this in his patch set: > > > > ASSERT_OK(err, ...); > > ASSERT_EQ(retval, 0, ...); > > > > It is a better and more straightforward way to validate the checks > > instead of relying on (err || retval) -> bool (true) -> int (1) -> != > > 0 chain. > > ok, makes sense > > SNIP > > > > +void test_fentry_test(void) > > > +{ > > > + struct fentry_test *fentry_skel = NULL; > > > + int err; > > > + > > > + fentry_skel = fentry_test__open_and_load(); > > > + if (!ASSERT_OK_PTR(fentry_skel, "fentry_skel_load")) > > > + goto cleanup; > > > + > > > + err = fentry_test(fentry_skel); > > > + if (!ASSERT_OK(err, "fentry_first_attach")) > > > + goto cleanup; > > > + > > > + err = fentry_test(fentry_skel); > > > + ASSERT_OK(err, "fentry_second_attach"); > > > + > > > cleanup: > > > fentry_test__destroy(fentry_skel); > > > } > > > diff --git a/tools/testing/selftests/bpf/test_progs.h > > > b/tools/testing/selftests/bpf/test_progs.h > > > index e87c8546230e..ee7e3b45182a 100644 > > > --- a/tools/testing/selftests/bpf/test_progs.h > > > +++ b/tools/testing/selftests/bpf/test_progs.h > > > @@ -210,7 +210,7 @@ extern int test__join_cgroup(const char *path); > > > #define ASSERT_ERR_PTR(ptr, name) ({ \ > > > static int duration = 0;\ > > > const void *___res = (ptr); \ > > > - bool ___ok = IS_ERR(___res) \ > > > + bool ___ok = IS_ERR(___res);\ > > > > heh, it probably deserves a separate patch with Fixes tag... > > va bene Where would I learn some Italian if not on bpf@vger :) > > jirka >
[PATCHv5 bpf-next 7/7] selftests/bpf: Use ASSERT macros in lsm test
Replacing CHECK with ASSERT macros. Suggested-by: Andrii Nakryiko Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/test_lsm.c | 27 +++ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c index d492e76e01cf..244c01125126 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c @@ -18,8 +18,6 @@ char *CMD_ARGS[] = {"true", NULL}; #define GET_PAGE_ADDR(ADDR, PAGE_SIZE) \ (char *)(((unsigned long) (ADDR + PAGE_SIZE)) & ~(PAGE_SIZE-1)) -static int duration = 0; - int stack_mprotect(void) { void *buf; @@ -60,38 +58,33 @@ static int test_lsm(struct lsm *skel) int err; err = lsm__attach(skel); - if (CHECK(err, "attach", "lsm attach failed: %d\n", err)) + if (!ASSERT_OK(err, "attach")) return err; /* Check that already linked program can't be attached again. */ link = bpf_program__attach(skel->progs.test_int_hook); - if (CHECK(!IS_ERR(link), "attach_link", - "re-attach without detach should not succeed")) + if (!ASSERT_ERR_PTR(link, "attach_link")) return -1; err = exec_cmd(&skel->bss->monitored_pid); - if (CHECK(err < 0, "exec_cmd", "err %d errno %d\n", err, errno)) + if (!ASSERT_OK(err, "exec_cmd")) return err; - CHECK(skel->bss->bprm_count != 1, "bprm_count", "bprm_count = %d\n", - skel->bss->bprm_count); + ASSERT_EQ(skel->bss->bprm_count, 1, "bprm_count"); skel->bss->monitored_pid = getpid(); err = stack_mprotect(); - if (CHECK(errno != EPERM, "stack_mprotect", "want err=EPERM, got %d\n", - errno)) + if (!ASSERT_EQ(errno, EPERM, "stack_mprotect")) return err; - CHECK(skel->bss->mprotect_count != 1, "mprotect_count", - "mprotect_count = %d\n", skel->bss->mprotect_count); + ASSERT_EQ(skel->bss->mprotect_count, 1, "mprotect_count"); syscall(__NR_setdomainname, &buf, -2L); syscall(__NR_setdomainname, 0, -3L); syscall(__NR_setdomainname, ~0L, -4L); - CHECK(skel->bss->copy_test != 3, "copy_test", - "copy_test = %d\n", skel->bss->copy_test); + ASSERT_EQ(skel->bss->copy_test, 3, "copy_test"); lsm__detach(skel); @@ -107,15 +100,15 @@ void test_test_lsm(void) int err; skel = lsm__open_and_load(); - if (CHECK(!skel, "lsm_skel_load", "lsm skeleton failed\n")) + if (!ASSERT_OK_PTR(skel, "lsm_skel_load")) goto close_prog; err = test_lsm(skel); - if (CHECK(err, "test_lsm", "first attach failed\n")) + if (!ASSERT_OK(err, "test_lsm_first_attach")) goto close_prog; err = test_lsm(skel); - CHECK(err, "test_lsm", "second attach failed\n"); + ASSERT_OK(err, "test_lsm_second_attach"); close_prog: lsm__destroy(skel); -- 2.30.2
[PATCHv5 bpf-next 6/7] selftests/bpf: Test that module can't be unloaded with attached trampoline
Adding test to verify that once we attach module's trampoline, the module can't be unloaded. Acked-by: Andrii Nakryiko Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/module_attach.c | 23 +++ 1 file changed, 23 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/module_attach.c b/tools/testing/selftests/bpf/prog_tests/module_attach.c index 5bc53d53d86e..d85a69b7ce44 100644 --- a/tools/testing/selftests/bpf/prog_tests/module_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/module_attach.c @@ -45,12 +45,18 @@ static int trigger_module_test_write(int write_sz) return 0; } +static int delete_module(const char *name, int flags) +{ + return syscall(__NR_delete_module, name, flags); +} + void test_module_attach(void) { const int READ_SZ = 456; const int WRITE_SZ = 457; struct test_module_attach* skel; struct test_module_attach__bss *bss; + struct bpf_link *link; int err; skel = test_module_attach__open(); @@ -84,6 +90,23 @@ void test_module_attach(void) ASSERT_EQ(bss->fexit_ret, -EIO, "fexit_tet"); ASSERT_EQ(bss->fmod_ret_read_sz, READ_SZ, "fmod_ret"); + test_module_attach__detach(skel); + + /* attach fentry/fexit and make sure it get's module reference */ + link = bpf_program__attach(skel->progs.handle_fentry); + if (!ASSERT_OK_PTR(link, "attach_fentry")) + goto cleanup; + + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + bpf_link__destroy(link); + + link = bpf_program__attach(skel->progs.handle_fexit); + if (!ASSERT_OK_PTR(link, "attach_fexit")) + goto cleanup; + + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + bpf_link__destroy(link); + cleanup: test_module_attach__destroy(skel); } -- 2.30.2
[PATCHv5 bpf-next 5/7] selftests/bpf: Add re-attach test to lsm test
Adding the test to re-attach (detach/attach again) lsm programs, plus check that already linked program can't be attached again. Acked-by: Andrii Nakryiko Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/test_lsm.c | 48 +++ 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c index 2755e4f81499..d492e76e01cf 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c @@ -18,6 +18,8 @@ char *CMD_ARGS[] = {"true", NULL}; #define GET_PAGE_ADDR(ADDR, PAGE_SIZE) \ (char *)(((unsigned long) (ADDR + PAGE_SIZE)) & ~(PAGE_SIZE-1)) +static int duration = 0; + int stack_mprotect(void) { void *buf; @@ -51,23 +53,25 @@ int exec_cmd(int *monitored_pid) return -EINVAL; } -void test_test_lsm(void) +static int test_lsm(struct lsm *skel) { - struct lsm *skel = NULL; - int err, duration = 0; + struct bpf_link *link; int buf = 1234; - - skel = lsm__open_and_load(); - if (CHECK(!skel, "skel_load", "lsm skeleton failed\n")) - goto close_prog; + int err; err = lsm__attach(skel); if (CHECK(err, "attach", "lsm attach failed: %d\n", err)) - goto close_prog; + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(skel->progs.test_int_hook); + if (CHECK(!IS_ERR(link), "attach_link", + "re-attach without detach should not succeed")) + return -1; err = exec_cmd(&skel->bss->monitored_pid); if (CHECK(err < 0, "exec_cmd", "err %d errno %d\n", err, errno)) - goto close_prog; + return err; CHECK(skel->bss->bprm_count != 1, "bprm_count", "bprm_count = %d\n", skel->bss->bprm_count); @@ -77,7 +81,7 @@ void test_test_lsm(void) err = stack_mprotect(); if (CHECK(errno != EPERM, "stack_mprotect", "want err=EPERM, got %d\n", errno)) - goto close_prog; + return err; CHECK(skel->bss->mprotect_count != 1, "mprotect_count", "mprotect_count = %d\n", skel->bss->mprotect_count); @@ -89,6 +93,30 @@ void test_test_lsm(void) CHECK(skel->bss->copy_test != 3, "copy_test", "copy_test = %d\n", skel->bss->copy_test); + lsm__detach(skel); + + skel->bss->copy_test = 0; + skel->bss->bprm_count = 0; + skel->bss->mprotect_count = 0; + return 0; +} + +void test_test_lsm(void) +{ + struct lsm *skel = NULL; + int err; + + skel = lsm__open_and_load(); + if (CHECK(!skel, "lsm_skel_load", "lsm skeleton failed\n")) + goto close_prog; + + err = test_lsm(skel); + if (CHECK(err, "test_lsm", "first attach failed\n")) + goto close_prog; + + err = test_lsm(skel); + CHECK(err, "test_lsm", "second attach failed\n"); + close_prog: lsm__destroy(skel); } -- 2.30.2
[PATCHv5 bpf-next 4/7] selftests/bpf: Add re-attach test to fexit_test
Adding the test to re-attach (detach/attach again) tracing fexit programs, plus check that already linked program can't be attached again. Also switching to ASSERT* macros. Acked-by: Andrii Nakryiko Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fexit_test.c | 52 +-- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_test.c b/tools/testing/selftests/bpf/prog_tests/fexit_test.c index 78d7a2765c27..6792e41f7f69 100644 --- a/tools/testing/selftests/bpf/prog_tests/fexit_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fexit_test.c @@ -3,35 +3,57 @@ #include #include "fexit_test.skel.h" -void test_fexit_test(void) +static int fexit_test(struct fexit_test *fexit_skel) { - struct fexit_test *fexit_skel = NULL; int err, prog_fd, i; __u32 duration = 0, retval; + struct bpf_link *link; __u64 *result; - fexit_skel = fexit_test__open_and_load(); - if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) - goto cleanup; - err = fexit_test__attach(fexit_skel); - if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) - goto cleanup; + if (!ASSERT_OK(err, "fexit_attach")) + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(fexit_skel->progs.test1); + if (!ASSERT_ERR_PTR(link, "fexit_attach_link")) + return -1; prog_fd = bpf_program__fd(fexit_skel->progs.test1); err = bpf_prog_test_run(prog_fd, 1, NULL, 0, NULL, NULL, &retval, &duration); - CHECK(err || retval, "test_run", - "err %d errno %d retval %d duration %d\n", - err, errno, retval, duration); + ASSERT_OK(err, "test_run"); + ASSERT_EQ(retval, 0, "test_run"); result = (__u64 *)fexit_skel->bss; - for (i = 0; i < 6; i++) { - if (CHECK(result[i] != 1, "result", - "fexit_test%d failed err %lld\n", i + 1, result[i])) - goto cleanup; + for (i = 0; i < sizeof(*fexit_skel->bss) / sizeof(__u64); i++) { + if (!ASSERT_EQ(result[i], 1, "fexit_result")) + return -1; } + fexit_test__detach(fexit_skel); + + /* zero results for re-attach test */ + memset(fexit_skel->bss, 0, sizeof(*fexit_skel->bss)); + return 0; +} + +void test_fexit_test(void) +{ + struct fexit_test *fexit_skel = NULL; + int err; + + fexit_skel = fexit_test__open_and_load(); + if (!ASSERT_OK_PTR(fexit_skel, "fexit_skel_load")) + goto cleanup; + + err = fexit_test(fexit_skel); + if (!ASSERT_OK(err, "fexit_first_attach")) + goto cleanup; + + err = fexit_test(fexit_skel); + ASSERT_OK(err, "fexit_second_attach"); + cleanup: fexit_test__destroy(fexit_skel); } -- 2.30.2
[PATCHv5 bpf-next 3/7] selftests/bpf: Add re-attach test to fentry_test
Adding the test to re-attach (detach/attach again) tracing fentry programs, plus check that already linked program can't be attached again. Acked-by: Andrii Nakryiko Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fentry_test.c| 52 +-- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fentry_test.c b/tools/testing/selftests/bpf/prog_tests/fentry_test.c index 04ebbf1cb390..7cb111b11995 100644 --- a/tools/testing/selftests/bpf/prog_tests/fentry_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fentry_test.c @@ -3,35 +3,57 @@ #include #include "fentry_test.skel.h" -void test_fentry_test(void) +static int fentry_test(struct fentry_test *fentry_skel) { - struct fentry_test *fentry_skel = NULL; int err, prog_fd, i; __u32 duration = 0, retval; + struct bpf_link *link; __u64 *result; - fentry_skel = fentry_test__open_and_load(); - if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n")) - goto cleanup; - err = fentry_test__attach(fentry_skel); - if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) - goto cleanup; + if (!ASSERT_OK(err, "fentry_attach")) + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(fentry_skel->progs.test1); + if (!ASSERT_ERR_PTR(link, "fentry_attach_link")) + return -1; prog_fd = bpf_program__fd(fentry_skel->progs.test1); err = bpf_prog_test_run(prog_fd, 1, NULL, 0, NULL, NULL, &retval, &duration); - CHECK(err || retval, "test_run", - "err %d errno %d retval %d duration %d\n", - err, errno, retval, duration); + ASSERT_OK(err, "test_run"); + ASSERT_EQ(retval, 0, "test_run"); result = (__u64 *)fentry_skel->bss; - for (i = 0; i < 6; i++) { - if (CHECK(result[i] != 1, "result", - "fentry_test%d failed err %lld\n", i + 1, result[i])) - goto cleanup; + for (i = 0; i < sizeof(*fentry_skel->bss) / sizeof(__u64); i++) { + if (!ASSERT_EQ(result[i], 1, "fentry_result")) + return -1; } + fentry_test__detach(fentry_skel); + + /* zero results for re-attach test */ + memset(fentry_skel->bss, 0, sizeof(*fentry_skel->bss)); + return 0; +} + +void test_fentry_test(void) +{ + struct fentry_test *fentry_skel = NULL; + int err; + + fentry_skel = fentry_test__open_and_load(); + if (!ASSERT_OK_PTR(fentry_skel, "fentry_skel_load")) + goto cleanup; + + err = fentry_test(fentry_skel); + if (!ASSERT_OK(err, "fentry_first_attach")) + goto cleanup; + + err = fentry_test(fentry_skel); + ASSERT_OK(err, "fentry_second_attach"); + cleanup: fentry_test__destroy(fentry_skel); } -- 2.30.2
[PATCH net 1/3] ixgbe: Fix NULL pointer dereference in ethtool loopback test
From: Alexander Duyck The ixgbe driver currently generates a NULL pointer dereference when performing the ethtool loopback test. This is due to the fact that there isn't a q_vector associated with the test ring when it is setup as interrupts are not normally added to the test rings. To address this I have added code that will check for a q_vector before returning a napi_id value. If a q_vector is not present it will return a value of 0. Fixes: b02e5a0ebb17 ("xsk: Propagate napi_id to XDP socket Rx path") Signed-off-by: Alexander Duyck Acked-by: Björn Töpel Tested-by: Dave Switzer Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 03d9aad516d4..45d2c8f37c01 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6536,6 +6536,13 @@ static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter) return err; } +static int ixgbe_rx_napi_id(struct ixgbe_ring *rx_ring) +{ + struct ixgbe_q_vector *q_vector = rx_ring->q_vector; + + return q_vector ? q_vector->napi.napi_id : 0; +} + /** * ixgbe_setup_rx_resources - allocate Rx resources (Descriptors) * @adapter: pointer to ixgbe_adapter @@ -6583,7 +6590,7 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, /* XDP RX-queue info */ if (xdp_rxq_info_reg(&rx_ring->xdp_rxq, adapter->netdev, -rx_ring->queue_index, rx_ring->q_vector->napi.napi_id) < 0) +rx_ring->queue_index, ixgbe_rx_napi_id(rx_ring)) < 0) goto err; rx_ring->xdp_prog = adapter->xdp_prog; -- 2.26.2
[PATCHv7 bpf-next 4/4] selftests/bpf: add xdp_redirect_multi test
Add a bpf selftest for new helper xdp_redirect_map_multi(). In this test there are 3 forward groups and 1 exclude group. The test will redirect each interface's packets to all the interfaces in the forward group, and exclude the interface in exclude map. Two maps (DEVMAP, DEVMAP_HASH) and two xdp modes (generic, drive) will be tested. XDP egress program will also be tested by setting pkt src MAC to egress interface's MAC address. For more test details, you can find it in the test script. Here is the test result. ]# ./test_xdp_redirect_multi.sh Pass: xdpgeneric arp ns1-2 Pass: xdpgeneric arp ns1-3 Pass: xdpgeneric arp ns1-4 Pass: xdpgeneric ping ns1-2 Pass: xdpgeneric ping ns1-3 Pass: xdpgeneric ping ns1-4 Pass: xdpgeneric ping6 ns1-2 Pass: xdpgeneric ping6 ns1-1 number Pass: xdpgeneric ping6 ns1-2 number Pass: xdpdrv arp ns1-2 Pass: xdpdrv arp ns1-3 Pass: xdpdrv arp ns1-4 Pass: xdpdrv ping ns1-2 Pass: xdpdrv ping ns1-3 Pass: xdpdrv ping ns1-4 Pass: xdpdrv ping6 ns1-2 Pass: xdpdrv ping6 ns1-1 number Pass: xdpdrv ping6 ns1-2 number Pass: xdpegress mac ns1-2 Pass: xdpegress mac ns1-3 Pass: xdpegress mac ns1-4 Summary: PASS 21, FAIL 0 Signed-off-by: Hangbin Liu --- v2: add a IPv6 test to validates that single redirect still works after multicast redirect. --- tools/testing/selftests/bpf/Makefile | 3 +- .../bpf/progs/xdp_redirect_multi_kern.c | 99 .../selftests/bpf/test_xdp_redirect_multi.sh | 205 +++ .../selftests/bpf/xdp_redirect_multi.c| 236 ++ 4 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c create mode 100755 tools/testing/selftests/bpf/test_xdp_redirect_multi.sh create mode 100644 tools/testing/selftests/bpf/xdp_redirect_multi.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 6448c626498f..0c08b662a64e 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -49,6 +49,7 @@ TEST_FILES = xsk_prereqs.sh \ # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ test_xdp_redirect.sh \ + test_xdp_redirect_multi.sh \ test_xdp_meta.sh \ test_xdp_veth.sh \ test_offload.py \ @@ -79,7 +80,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \ test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \ - xdpxceiver + xdpxceiver xdp_redirect_multi TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read diff --git a/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c b/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c new file mode 100644 index ..099bf444acab --- /dev/null +++ b/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* It would be easier to use a key:if_index, value:if_index map, but it + * will need a very large entries as the if_index number may get very large, + * this would affect the performace. So the DEVMAP here is just for testing. + */ +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 1024); +} map_v4 SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 128); +} map_all SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 128); +} map_egress SEC(".maps"); + +/* map to store egress interfaces mac addresses */ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u32); + __type(value, __be64); + __uint(max_entries, 128); +} mac_map SEC(".maps"); + +SEC("xdp_redirect_map_multi") +int xdp_redirect_map_multi_prog(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + int if_index = ctx->ingress_ifindex; + struct ethhdr *eth = data; + __u16 h_proto; + __u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + h_proto = eth->h_proto; + + if (h_proto == bpf_htons(ETH_P_IP)) + return bpf_redirect_map(&map_v4, 0, BPF_F_REDIR_MASK); + else if (h_proto == bpf_htons(ETH_P_IPV6)) + return bpf_redirect_map(&map_all, if_index
[PATCHv7 bpf-next 3/4] sample/bpf: add xdp_redirect_map_multi for redirect_map broadcast test
This is a sample for xdp redirect broadcast. In the sample we could forward all packets between given interfaces. There is also an option -X that could enable 2nd xdp_prog on egress interface. Signed-off-by: Hangbin Liu --- samples/bpf/Makefile | 3 + samples/bpf/xdp_redirect_map_multi_kern.c | 87 +++ samples/bpf/xdp_redirect_map_multi_user.c | 302 ++ 3 files changed, 392 insertions(+) create mode 100644 samples/bpf/xdp_redirect_map_multi_kern.c create mode 100644 samples/bpf/xdp_redirect_map_multi_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 45ceca4e2c70..520434ea966f 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -41,6 +41,7 @@ tprogs-y += test_map_in_map tprogs-y += per_socket_stats_example tprogs-y += xdp_redirect tprogs-y += xdp_redirect_map +tprogs-y += xdp_redirect_map_multi tprogs-y += xdp_redirect_cpu tprogs-y += xdp_monitor tprogs-y += xdp_rxq_info @@ -99,6 +100,7 @@ test_map_in_map-objs := test_map_in_map_user.o per_socket_stats_example-objs := cookie_uid_helper_example.o xdp_redirect-objs := xdp_redirect_user.o xdp_redirect_map-objs := xdp_redirect_map_user.o +xdp_redirect_map_multi-objs := xdp_redirect_map_multi_user.o xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o xdp_monitor-objs := xdp_monitor_user.o xdp_rxq_info-objs := xdp_rxq_info_user.o @@ -160,6 +162,7 @@ always-y += tcp_tos_reflect_kern.o always-y += tcp_dumpstats_kern.o always-y += xdp_redirect_kern.o always-y += xdp_redirect_map_kern.o +always-y += xdp_redirect_map_multi_kern.o always-y += xdp_redirect_cpu_kern.o always-y += xdp_monitor_kern.o always-y += xdp_rxq_info_kern.o diff --git a/samples/bpf/xdp_redirect_map_multi_kern.c b/samples/bpf/xdp_redirect_map_multi_kern.c new file mode 100644 index ..e6be70225ee1 --- /dev/null +++ b/samples/bpf/xdp_redirect_map_multi_kern.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 32); +} forward_map_general SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 32); +} forward_map_native SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __type(key, u32); + __type(value, long); + __uint(max_entries, 1); +} rxcnt SEC(".maps"); + +/* map to store egress interfaces mac addresses, set the + * max_entries to 1 and extend it in user sapce prog. + */ +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, u32); + __type(value, __be64); + __uint(max_entries, 1); +} mac_map SEC(".maps"); + +static int xdp_redirect_map(struct xdp_md *ctx, void *forward_map) +{ + long *value; + u32 key = 0; + + /* count packet in global counter */ + value = bpf_map_lookup_elem(&rxcnt, &key); + if (value) + *value += 1; + + return bpf_redirect_map(forward_map, key, BPF_F_REDIR_MASK); +} + +SEC("xdp_redirect_general") +int xdp_redirect_map_general(struct xdp_md *ctx) +{ + return xdp_redirect_map(ctx, &forward_map_general); +} + +SEC("xdp_redirect_native") +int xdp_redirect_map_native(struct xdp_md *ctx) +{ + return xdp_redirect_map(ctx, &forward_map_native); +} + +SEC("xdp_devmap/map_prog") +int xdp_devmap_prog(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + u32 key = ctx->egress_ifindex; + struct ethhdr *eth = data; + __be64 *mac; + u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + mac = bpf_map_lookup_elem(&mac_map, &key); + if (mac) + __builtin_memcpy(eth->h_source, mac, ETH_ALEN); + + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/xdp_redirect_map_multi_user.c b/samples/bpf/xdp_redirect_map_multi_user.c new file mode 100644 index ..84cdbbed20b7 --- /dev/null +++ b/samples/bpf/xdp_redirect_map_multi_user.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_util.h" +#include +#include + +#define MAX_IFACE_NUM 32 + +static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; +static int ifaces[MAX_IFACE_NUM] = {}; +static int rxcnt_map_fd; + +static void int_exit(int sig) +{ + __u32 prog_id = 0; + int i; + + for (i = 0; ifaces[i] > 0; i++) { + if (bpf_get_link_xdp_id(ifaces[i], &p
Re: [PATCHv4 bpf-next 3/5] selftests/bpf: Add re-attach test to fexit_test
On Tue, Apr 13, 2021 at 02:55:32PM -0700, Andrii Nakryiko wrote: > On Mon, Apr 12, 2021 at 9:30 AM Jiri Olsa wrote: > > > > Adding the test to re-attach (detach/attach again) tracing > > fexit programs, plus check that already linked program can't > > be attached again. > > > > Also switching to ASSERT* macros. > > > > Signed-off-by: Jiri Olsa > > --- > > .../selftests/bpf/prog_tests/fexit_test.c | 51 +-- > > 1 file changed, 36 insertions(+), 15 deletions(-) > > > > diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_test.c > > b/tools/testing/selftests/bpf/prog_tests/fexit_test.c > > index 78d7a2765c27..c48e10c138bc 100644 > > --- a/tools/testing/selftests/bpf/prog_tests/fexit_test.c > > +++ b/tools/testing/selftests/bpf/prog_tests/fexit_test.c > > @@ -3,35 +3,56 @@ > > #include > > #include "fexit_test.skel.h" > > > > -void test_fexit_test(void) > > +static int fexit_test(struct fexit_test *fexit_skel) > > { > > - struct fexit_test *fexit_skel = NULL; > > int err, prog_fd, i; > > __u32 duration = 0, retval; > > + struct bpf_link *link; > > __u64 *result; > > > > - fexit_skel = fexit_test__open_and_load(); > > - if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton > > failed\n")) > > - goto cleanup; > > - > > err = fexit_test__attach(fexit_skel); > > - if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) > > - goto cleanup; > > + if (!ASSERT_OK(err, "fexit_attach")) > > + return err; > > + > > + /* Check that already linked program can't be attached again. */ > > + link = bpf_program__attach(fexit_skel->progs.test1); > > + if (!ASSERT_ERR_PTR(link, "fexit_attach_link")) > > + return -1; > > > > prog_fd = bpf_program__fd(fexit_skel->progs.test1); > > err = bpf_prog_test_run(prog_fd, 1, NULL, 0, > > NULL, NULL, &retval, &duration); > > - CHECK(err || retval, "test_run", > > - "err %d errno %d retval %d duration %d\n", > > - err, errno, retval, duration); > > + ASSERT_OK(err || retval, "test_run"); > > same as in previous patch > > With this fixed, feel free to add my ack to this and previous patch. Thanks! ok, thanks, jirka
Re: [PATCHv4 bpf-next 2/5] selftests/bpf: Add re-attach test to fentry_test
On Tue, Apr 13, 2021 at 02:54:10PM -0700, Andrii Nakryiko wrote: SNIP > > __u32 duration = 0, retval; > > + struct bpf_link *link; > > __u64 *result; > > > > - fentry_skel = fentry_test__open_and_load(); > > - if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton > > failed\n")) > > - goto cleanup; > > - > > err = fentry_test__attach(fentry_skel); > > - if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) > > - goto cleanup; > > + if (!ASSERT_OK(err, "fentry_attach")) > > + return err; > > + > > + /* Check that already linked program can't be attached again. */ > > + link = bpf_program__attach(fentry_skel->progs.test1); > > + if (!ASSERT_ERR_PTR(link, "fentry_attach_link")) > > + return -1; > > > > prog_fd = bpf_program__fd(fentry_skel->progs.test1); > > err = bpf_prog_test_run(prog_fd, 1, NULL, 0, > > NULL, NULL, &retval, &duration); > > - CHECK(err || retval, "test_run", > > - "err %d errno %d retval %d duration %d\n", > > - err, errno, retval, duration); > > + ASSERT_OK(err || retval, "test_run"); > > this is quite misleading, even if will result in a correct check. Toke > did this in his patch set: > > ASSERT_OK(err, ...); > ASSERT_EQ(retval, 0, ...); > > It is a better and more straightforward way to validate the checks > instead of relying on (err || retval) -> bool (true) -> int (1) -> != > 0 chain. ok, makes sense SNIP > > +void test_fentry_test(void) > > +{ > > + struct fentry_test *fentry_skel = NULL; > > + int err; > > + > > + fentry_skel = fentry_test__open_and_load(); > > + if (!ASSERT_OK_PTR(fentry_skel, "fentry_skel_load")) > > + goto cleanup; > > + > > + err = fentry_test(fentry_skel); > > + if (!ASSERT_OK(err, "fentry_first_attach")) > > + goto cleanup; > > + > > + err = fentry_test(fentry_skel); > > + ASSERT_OK(err, "fentry_second_attach"); > > + > > cleanup: > > fentry_test__destroy(fentry_skel); > > } > > diff --git a/tools/testing/selftests/bpf/test_progs.h > > b/tools/testing/selftests/bpf/test_progs.h > > index e87c8546230e..ee7e3b45182a 100644 > > --- a/tools/testing/selftests/bpf/test_progs.h > > +++ b/tools/testing/selftests/bpf/test_progs.h > > @@ -210,7 +210,7 @@ extern int test__join_cgroup(const char *path); > > #define ASSERT_ERR_PTR(ptr, name) ({ \ > > static int duration = 0;\ > > const void *___res = (ptr); \ > > - bool ___ok = IS_ERR(___res) \ > > + bool ___ok = IS_ERR(___res);\ > > heh, it probably deserves a separate patch with Fixes tag... va bene jirka
Re: [PATCHv4 bpf-next 4/5] selftests/bpf: Add re-attach test to lsm test
On Tue, Apr 13, 2021 at 02:57:26PM -0700, Andrii Nakryiko wrote: > On Mon, Apr 12, 2021 at 9:31 AM Jiri Olsa wrote: > > > > Adding the test to re-attach (detach/attach again) lsm programs, > > plus check that already linked program can't be attached again. > > > > Signed-off-by: Jiri Olsa > > --- > > .../selftests/bpf/prog_tests/test_lsm.c | 48 +++ > > 1 file changed, 38 insertions(+), 10 deletions(-) > > > > Surprised you didn't switch this one to ASSERT, but ok, we can do it > some other time ;) yep, I commented on that in the previous version ;-) - used ASSERT* macros apart from lsm test, which is using CHECKs all over the place [Andrii] I think it should go to separate patch, so it won't shade the actual change jirka > > Acked-by: Andrii Nakryiko > > > > diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c > > b/tools/testing/selftests/bpf/prog_tests/test_lsm.c > > index 2755e4f81499..d492e76e01cf 100644 > > --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c > > +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c > > @@ -18,6 +18,8 @@ char *CMD_ARGS[] = {"true", NULL}; > > #define GET_PAGE_ADDR(ADDR, PAGE_SIZE) \ > > (char *)(((unsigned long) (ADDR + PAGE_SIZE)) & ~(PAGE_SIZE-1)) > > > > [...] >
[PATCHv6 bpf-next 3/4] sample/bpf: add xdp_redirect_map_multi for redirect_map broadcast test
This is a sample for xdp redirect broadcast. In the sample we could forward all packets between given interfaces. There is also an option -X that could enable 2nd xdp_prog on egress interface. Signed-off-by: Hangbin Liu --- samples/bpf/Makefile | 3 + samples/bpf/xdp_redirect_map_multi_kern.c | 87 +++ samples/bpf/xdp_redirect_map_multi_user.c | 302 ++ 3 files changed, 392 insertions(+) create mode 100644 samples/bpf/xdp_redirect_map_multi_kern.c create mode 100644 samples/bpf/xdp_redirect_map_multi_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 45ceca4e2c70..520434ea966f 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -41,6 +41,7 @@ tprogs-y += test_map_in_map tprogs-y += per_socket_stats_example tprogs-y += xdp_redirect tprogs-y += xdp_redirect_map +tprogs-y += xdp_redirect_map_multi tprogs-y += xdp_redirect_cpu tprogs-y += xdp_monitor tprogs-y += xdp_rxq_info @@ -99,6 +100,7 @@ test_map_in_map-objs := test_map_in_map_user.o per_socket_stats_example-objs := cookie_uid_helper_example.o xdp_redirect-objs := xdp_redirect_user.o xdp_redirect_map-objs := xdp_redirect_map_user.o +xdp_redirect_map_multi-objs := xdp_redirect_map_multi_user.o xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o xdp_monitor-objs := xdp_monitor_user.o xdp_rxq_info-objs := xdp_rxq_info_user.o @@ -160,6 +162,7 @@ always-y += tcp_tos_reflect_kern.o always-y += tcp_dumpstats_kern.o always-y += xdp_redirect_kern.o always-y += xdp_redirect_map_kern.o +always-y += xdp_redirect_map_multi_kern.o always-y += xdp_redirect_cpu_kern.o always-y += xdp_monitor_kern.o always-y += xdp_rxq_info_kern.o diff --git a/samples/bpf/xdp_redirect_map_multi_kern.c b/samples/bpf/xdp_redirect_map_multi_kern.c new file mode 100644 index ..e6be70225ee1 --- /dev/null +++ b/samples/bpf/xdp_redirect_map_multi_kern.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 32); +} forward_map_general SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 32); +} forward_map_native SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __type(key, u32); + __type(value, long); + __uint(max_entries, 1); +} rxcnt SEC(".maps"); + +/* map to store egress interfaces mac addresses, set the + * max_entries to 1 and extend it in user sapce prog. + */ +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, u32); + __type(value, __be64); + __uint(max_entries, 1); +} mac_map SEC(".maps"); + +static int xdp_redirect_map(struct xdp_md *ctx, void *forward_map) +{ + long *value; + u32 key = 0; + + /* count packet in global counter */ + value = bpf_map_lookup_elem(&rxcnt, &key); + if (value) + *value += 1; + + return bpf_redirect_map(forward_map, key, BPF_F_REDIR_MASK); +} + +SEC("xdp_redirect_general") +int xdp_redirect_map_general(struct xdp_md *ctx) +{ + return xdp_redirect_map(ctx, &forward_map_general); +} + +SEC("xdp_redirect_native") +int xdp_redirect_map_native(struct xdp_md *ctx) +{ + return xdp_redirect_map(ctx, &forward_map_native); +} + +SEC("xdp_devmap/map_prog") +int xdp_devmap_prog(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + u32 key = ctx->egress_ifindex; + struct ethhdr *eth = data; + __be64 *mac; + u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + mac = bpf_map_lookup_elem(&mac_map, &key); + if (mac) + __builtin_memcpy(eth->h_source, mac, ETH_ALEN); + + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/xdp_redirect_map_multi_user.c b/samples/bpf/xdp_redirect_map_multi_user.c new file mode 100644 index ..84cdbbed20b7 --- /dev/null +++ b/samples/bpf/xdp_redirect_map_multi_user.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_util.h" +#include +#include + +#define MAX_IFACE_NUM 32 + +static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; +static int ifaces[MAX_IFACE_NUM] = {}; +static int rxcnt_map_fd; + +static void int_exit(int sig) +{ + __u32 prog_id = 0; + int i; + + for (i = 0; ifaces[i] > 0; i++) { + if (bpf_get_link_xdp_id(ifaces[i], &p
[PATCHv6 bpf-next 4/4] selftests/bpf: add xdp_redirect_multi test
Add a bpf selftest for new helper xdp_redirect_map_multi(). In this test there are 3 forward groups and 1 exclude group. The test will redirect each interface's packets to all the interfaces in the forward group, and exclude the interface in exclude map. Two maps (DEVMAP, DEVMAP_HASH) and two xdp modes (generic, drive) will be tested. XDP egress program will also be tested by setting pkt src MAC to egress interface's MAC address. For more test details, you can find it in the test script. Here is the test result. ]# ./test_xdp_redirect_multi.sh Pass: xdpgeneric arp ns1-2 Pass: xdpgeneric arp ns1-3 Pass: xdpgeneric arp ns1-4 Pass: xdpgeneric ping ns1-2 Pass: xdpgeneric ping ns1-3 Pass: xdpgeneric ping ns1-4 Pass: xdpgeneric ping6 ns1-2 Pass: xdpgeneric ping6 ns1-1 number Pass: xdpgeneric ping6 ns1-2 number Pass: xdpdrv arp ns1-2 Pass: xdpdrv arp ns1-3 Pass: xdpdrv arp ns1-4 Pass: xdpdrv ping ns1-2 Pass: xdpdrv ping ns1-3 Pass: xdpdrv ping ns1-4 Pass: xdpdrv ping6 ns1-2 Pass: xdpdrv ping6 ns1-1 number Pass: xdpdrv ping6 ns1-2 number Pass: xdpegress mac ns1-2 Pass: xdpegress mac ns1-3 Pass: xdpegress mac ns1-4 Summary: PASS 21, FAIL 0 Signed-off-by: Hangbin Liu --- v2: add a IPv6 test to validates that single redirect still works after multicast redirect. --- tools/testing/selftests/bpf/Makefile | 3 +- .../bpf/progs/xdp_redirect_multi_kern.c | 99 .../selftests/bpf/test_xdp_redirect_multi.sh | 205 +++ .../selftests/bpf/xdp_redirect_multi.c| 236 ++ 4 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c create mode 100755 tools/testing/selftests/bpf/test_xdp_redirect_multi.sh create mode 100644 tools/testing/selftests/bpf/xdp_redirect_multi.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 6448c626498f..0c08b662a64e 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -49,6 +49,7 @@ TEST_FILES = xsk_prereqs.sh \ # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ test_xdp_redirect.sh \ + test_xdp_redirect_multi.sh \ test_xdp_meta.sh \ test_xdp_veth.sh \ test_offload.py \ @@ -79,7 +80,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \ test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \ - xdpxceiver + xdpxceiver xdp_redirect_multi TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read diff --git a/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c b/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c new file mode 100644 index ..099bf444acab --- /dev/null +++ b/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* It would be easier to use a key:if_index, value:if_index map, but it + * will need a very large entries as the if_index number may get very large, + * this would affect the performace. So the DEVMAP here is just for testing. + */ +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 1024); +} map_v4 SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 128); +} map_all SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 128); +} map_egress SEC(".maps"); + +/* map to store egress interfaces mac addresses */ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u32); + __type(value, __be64); + __uint(max_entries, 128); +} mac_map SEC(".maps"); + +SEC("xdp_redirect_map_multi") +int xdp_redirect_map_multi_prog(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + int if_index = ctx->ingress_ifindex; + struct ethhdr *eth = data; + __u16 h_proto; + __u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + h_proto = eth->h_proto; + + if (h_proto == bpf_htons(ETH_P_IP)) + return bpf_redirect_map(&map_v4, 0, BPF_F_REDIR_MASK); + else if (h_proto == bpf_htons(ETH_P_IPV6)) + return bpf_redirect_map(&map_all, if_index
Re: [PATCHv4 bpf-next 4/5] selftests/bpf: Add re-attach test to lsm test
On Mon, Apr 12, 2021 at 9:31 AM Jiri Olsa wrote: > > Adding the test to re-attach (detach/attach again) lsm programs, > plus check that already linked program can't be attached again. > > Signed-off-by: Jiri Olsa > --- > .../selftests/bpf/prog_tests/test_lsm.c | 48 +++ > 1 file changed, 38 insertions(+), 10 deletions(-) > Surprised you didn't switch this one to ASSERT, but ok, we can do it some other time ;) Acked-by: Andrii Nakryiko > diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c > b/tools/testing/selftests/bpf/prog_tests/test_lsm.c > index 2755e4f81499..d492e76e01cf 100644 > --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c > +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c > @@ -18,6 +18,8 @@ char *CMD_ARGS[] = {"true", NULL}; > #define GET_PAGE_ADDR(ADDR, PAGE_SIZE) \ > (char *)(((unsigned long) (ADDR + PAGE_SIZE)) & ~(PAGE_SIZE-1)) > [...]
Re: [PATCHv4 bpf-next 3/5] selftests/bpf: Add re-attach test to fexit_test
On Mon, Apr 12, 2021 at 9:30 AM Jiri Olsa wrote: > > Adding the test to re-attach (detach/attach again) tracing > fexit programs, plus check that already linked program can't > be attached again. > > Also switching to ASSERT* macros. > > Signed-off-by: Jiri Olsa > --- > .../selftests/bpf/prog_tests/fexit_test.c | 51 +-- > 1 file changed, 36 insertions(+), 15 deletions(-) > > diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_test.c > b/tools/testing/selftests/bpf/prog_tests/fexit_test.c > index 78d7a2765c27..c48e10c138bc 100644 > --- a/tools/testing/selftests/bpf/prog_tests/fexit_test.c > +++ b/tools/testing/selftests/bpf/prog_tests/fexit_test.c > @@ -3,35 +3,56 @@ > #include > #include "fexit_test.skel.h" > > -void test_fexit_test(void) > +static int fexit_test(struct fexit_test *fexit_skel) > { > - struct fexit_test *fexit_skel = NULL; > int err, prog_fd, i; > __u32 duration = 0, retval; > + struct bpf_link *link; > __u64 *result; > > - fexit_skel = fexit_test__open_and_load(); > - if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) > - goto cleanup; > - > err = fexit_test__attach(fexit_skel); > - if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) > - goto cleanup; > + if (!ASSERT_OK(err, "fexit_attach")) > + return err; > + > + /* Check that already linked program can't be attached again. */ > + link = bpf_program__attach(fexit_skel->progs.test1); > + if (!ASSERT_ERR_PTR(link, "fexit_attach_link")) > + return -1; > > prog_fd = bpf_program__fd(fexit_skel->progs.test1); > err = bpf_prog_test_run(prog_fd, 1, NULL, 0, > NULL, NULL, &retval, &duration); > - CHECK(err || retval, "test_run", > - "err %d errno %d retval %d duration %d\n", > - err, errno, retval, duration); > + ASSERT_OK(err || retval, "test_run"); same as in previous patch With this fixed, feel free to add my ack to this and previous patch. Thanks! > > result = (__u64 *)fexit_skel->bss; > - for (i = 0; i < 6; i++) { > - if (CHECK(result[i] != 1, "result", > - "fexit_test%d failed err %lld\n", i + 1, result[i])) > - goto cleanup; > + for (i = 0; i < sizeof(*fexit_skel->bss) / sizeof(__u64); i++) { > + if (!ASSERT_EQ(result[i], 1, "fexit_result")) > + return -1; > } > > + fexit_test__detach(fexit_skel); > + > + /* zero results for re-attach test */ > + memset(fexit_skel->bss, 0, sizeof(*fexit_skel->bss)); > + return 0; > +} > + > +void test_fexit_test(void) > +{ > + struct fexit_test *fexit_skel = NULL; > + int err; > + > + fexit_skel = fexit_test__open_and_load(); > + if (!ASSERT_OK_PTR(fexit_skel, "fexit_skel_load")) > + goto cleanup; > + > + err = fexit_test(fexit_skel); > + if (!ASSERT_OK(err, "fexit_first_attach")) > + goto cleanup; > + > + err = fexit_test(fexit_skel); > + ASSERT_OK(err, "fexit_second_attach"); > + > cleanup: > fexit_test__destroy(fexit_skel); > } > -- > 2.30.2 >
Re: [PATCHv4 bpf-next 2/5] selftests/bpf: Add re-attach test to fentry_test
On Mon, Apr 12, 2021 at 9:29 AM Jiri Olsa wrote: > > Adding the test to re-attach (detach/attach again) tracing > fentry programs, plus check that already linked program can't > be attached again. > > Also switching to ASSERT* macros and adding missing ';' in > ASSERT_ERR_PTR macro. > > Signed-off-by: Jiri Olsa > --- > .../selftests/bpf/prog_tests/fentry_test.c| 51 +-- > tools/testing/selftests/bpf/test_progs.h | 2 +- > 2 files changed, 37 insertions(+), 16 deletions(-) > > diff --git a/tools/testing/selftests/bpf/prog_tests/fentry_test.c > b/tools/testing/selftests/bpf/prog_tests/fentry_test.c > index 04ebbf1cb390..f440c74f5367 100644 > --- a/tools/testing/selftests/bpf/prog_tests/fentry_test.c > +++ b/tools/testing/selftests/bpf/prog_tests/fentry_test.c > @@ -3,35 +3,56 @@ > #include > #include "fentry_test.skel.h" > > -void test_fentry_test(void) > +static int fentry_test(struct fentry_test *fentry_skel) > { > - struct fentry_test *fentry_skel = NULL; > int err, prog_fd, i; > __u32 duration = 0, retval; > + struct bpf_link *link; > __u64 *result; > > - fentry_skel = fentry_test__open_and_load(); > - if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton > failed\n")) > - goto cleanup; > - > err = fentry_test__attach(fentry_skel); > - if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) > - goto cleanup; > + if (!ASSERT_OK(err, "fentry_attach")) > + return err; > + > + /* Check that already linked program can't be attached again. */ > + link = bpf_program__attach(fentry_skel->progs.test1); > + if (!ASSERT_ERR_PTR(link, "fentry_attach_link")) > + return -1; > > prog_fd = bpf_program__fd(fentry_skel->progs.test1); > err = bpf_prog_test_run(prog_fd, 1, NULL, 0, > NULL, NULL, &retval, &duration); > - CHECK(err || retval, "test_run", > - "err %d errno %d retval %d duration %d\n", > - err, errno, retval, duration); > + ASSERT_OK(err || retval, "test_run"); this is quite misleading, even if will result in a correct check. Toke did this in his patch set: ASSERT_OK(err, ...); ASSERT_EQ(retval, 0, ...); It is a better and more straightforward way to validate the checks instead of relying on (err || retval) -> bool (true) -> int (1) -> != 0 chain. > > result = (__u64 *)fentry_skel->bss; > - for (i = 0; i < 6; i++) { > - if (CHECK(result[i] != 1, "result", > - "fentry_test%d failed err %lld\n", i + 1, > result[i])) > - goto cleanup; > + for (i = 0; i < sizeof(*fentry_skel->bss) / sizeof(__u64); i++) { > + if (!ASSERT_EQ(result[i], 1, "fentry_result")) > + return -1; > } > > + fentry_test__detach(fentry_skel); > + > + /* zero results for re-attach test */ > + memset(fentry_skel->bss, 0, sizeof(*fentry_skel->bss)); > + return 0; > +} > + > +void test_fentry_test(void) > +{ > + struct fentry_test *fentry_skel = NULL; > + int err; > + > + fentry_skel = fentry_test__open_and_load(); > + if (!ASSERT_OK_PTR(fentry_skel, "fentry_skel_load")) > + goto cleanup; > + > + err = fentry_test(fentry_skel); > + if (!ASSERT_OK(err, "fentry_first_attach")) > + goto cleanup; > + > + err = fentry_test(fentry_skel); > + ASSERT_OK(err, "fentry_second_attach"); > + > cleanup: > fentry_test__destroy(fentry_skel); > } > diff --git a/tools/testing/selftests/bpf/test_progs.h > b/tools/testing/selftests/bpf/test_progs.h > index e87c8546230e..ee7e3b45182a 100644 > --- a/tools/testing/selftests/bpf/test_progs.h > +++ b/tools/testing/selftests/bpf/test_progs.h > @@ -210,7 +210,7 @@ extern int test__join_cgroup(const char *path); > #define ASSERT_ERR_PTR(ptr, name) ({ \ > static int duration = 0;\ > const void *___res = (ptr); \ > - bool ___ok = IS_ERR(___res) \ > + bool ___ok = IS_ERR(___res);\ heh, it probably deserves a separate patch with Fixes tag... > CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \ > ___ok; \ > }) > -- > 2.30.2 >
[PATCHv2 RFC bpf-next 6/7] selftests/bpf: Add ftrace probe to fentry test
Adding 2 more tests for fentry probe test, to show/test ftrace probe. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fentry_test.c | 5 - tools/testing/selftests/bpf/progs/fentry_test.c | 16 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fentry_test.c b/tools/testing/selftests/bpf/prog_tests/fentry_test.c index 04ebbf1cb390..70f414cb3bfd 100644 --- a/tools/testing/selftests/bpf/prog_tests/fentry_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fentry_test.c @@ -26,12 +26,15 @@ void test_fentry_test(void) err, errno, retval, duration); result = (__u64 *)fentry_skel->bss; - for (i = 0; i < 6; i++) { + for (i = 0; i < 8; i++) { if (CHECK(result[i] != 1, "result", "fentry_test%d failed err %lld\n", i + 1, result[i])) goto cleanup; } + ASSERT_EQ(result[8], 8, "result"); + ASSERT_EQ(result[9], 2, "result"); + cleanup: fentry_test__destroy(fentry_skel); } diff --git a/tools/testing/selftests/bpf/progs/fentry_test.c b/tools/testing/selftests/bpf/progs/fentry_test.c index 52a550d281d9..b32b589923a4 100644 --- a/tools/testing/selftests/bpf/progs/fentry_test.c +++ b/tools/testing/selftests/bpf/progs/fentry_test.c @@ -77,3 +77,19 @@ int BPF_PROG(test8, struct bpf_fentry_test_t *arg) test8_result = 1; return 0; } + +__u64 test9_result = 0; +SEC("fentry.ftrace/bpf_fentry_test*") +int BPF_PROG(test9) +{ + test9_result++; + return 0; +} + +__u64 test10_result = 0; +SEC("fentry.ftrace/bpf_fentry_test1|bpf_fentry_test2") +int BPF_PROG(test10) +{ + test10_result++; + return 0; +} -- 2.30.2
[PATCHv2 RFC bpf-next 7/7] selftests/bpf: Add ftrace probe test
Adding simple ftrace probe test that configures ftrace probe and verifies the 'ip' argument matches the probed functions addresses. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/ftrace_test.c| 48 +++ .../testing/selftests/bpf/progs/ftrace_test.c | 17 +++ 2 files changed, 65 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/ftrace_test.c create mode 100644 tools/testing/selftests/bpf/progs/ftrace_test.c diff --git a/tools/testing/selftests/bpf/prog_tests/ftrace_test.c b/tools/testing/selftests/bpf/prog_tests/ftrace_test.c new file mode 100644 index ..34d6dbe88251 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/ftrace_test.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include "ftrace_test.skel.h" + +void test_ftrace_test(void) +{ + struct ftrace_test *ftrace_skel = NULL; + __u32 duration = 0, retval; + int err, prog_fd; + __u64 *ips; + int idx, i; + + ftrace_skel = ftrace_test__open_and_load(); + if (!ASSERT_OK_PTR(ftrace_skel, "ftrace_skel_load")) + goto cleanup; + + err = ftrace_test__attach(ftrace_skel); + if (!ASSERT_OK(err, "ftrace_attach")) + goto cleanup; + + prog_fd = bpf_program__fd(ftrace_skel->progs.test); + err = bpf_prog_test_run(prog_fd, 1, NULL, 0, + NULL, NULL, &retval, &duration); + ASSERT_OK(err || retval, "test_run"); + + ips = ftrace_skel->bss->ips; + idx = ftrace_skel->bss->idx; + + if (!ASSERT_EQ(idx, 8, "idx")) + goto cleanup; + + for (i = 0; i < 8; i++) { + unsigned long long addr; + char func[50]; + + snprintf(func, sizeof(func), "bpf_fentry_test%d", i + 1); + + err = kallsyms_find(func, &addr); + if (!ASSERT_OK(err, "kallsyms_find")) + goto cleanup; + + if (!ASSERT_EQ(ips[i], addr, "ips_addr")) + goto cleanup; + } + +cleanup: + ftrace_test__destroy(ftrace_skel); +} diff --git a/tools/testing/selftests/bpf/progs/ftrace_test.c b/tools/testing/selftests/bpf/progs/ftrace_test.c new file mode 100644 index ..b2a55aa10318 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/ftrace_test.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +char _license[] SEC("license") = "GPL"; + +__u64 ips[9] = { }; +unsigned int idx = 0; + +SEC("fentry.ftrace/bpf_fentry_test*") +int BPF_PROG(test, __u64 ip, __u64 parent_ip) +{ + if (idx >= 0 && idx < 8) + ips[idx++] = ip; + return 0; +} -- 2.30.2
[PATCHv5 bpf-next 4/4] selftests/bpf: add xdp_redirect_multi test
Add a bpf selftest for new helper xdp_redirect_map_multi(). In this test there are 3 forward groups and 1 exclude group. The test will redirect each interface's packets to all the interfaces in the forward group, and exclude the interface in exclude map. Two maps (DEVMAP, DEVMAP_HASH) and two xdp modes (generic, drive) will be tested. XDP egress program will also be tested by setting pkt src MAC to egress interface's MAC address. For more test details, you can find it in the test script. Here is the test result. ]# ./test_xdp_redirect_multi.sh Pass: xdpgeneric arp ns1-2 Pass: xdpgeneric arp ns1-3 Pass: xdpgeneric arp ns1-4 Pass: xdpgeneric ping ns1-2 Pass: xdpgeneric ping ns1-3 Pass: xdpgeneric ping ns1-4 Pass: xdpgeneric ping6 ns1-2 Pass: xdpgeneric ping6 ns1-1 number Pass: xdpgeneric ping6 ns1-2 number Pass: xdpdrv arp ns1-2 Pass: xdpdrv arp ns1-3 Pass: xdpdrv arp ns1-4 Pass: xdpdrv ping ns1-2 Pass: xdpdrv ping ns1-3 Pass: xdpdrv ping ns1-4 Pass: xdpdrv ping6 ns1-2 Pass: xdpdrv ping6 ns1-1 number Pass: xdpdrv ping6 ns1-2 number Pass: xdpegress mac ns1-2 Pass: xdpegress mac ns1-3 Pass: xdpegress mac ns1-4 Summary: PASS 21, FAIL 0 Signed-off-by: Hangbin Liu --- v2: add a IPv6 test to validates that single redirect still works after multicast redirect. --- tools/testing/selftests/bpf/Makefile | 3 +- .../bpf/progs/xdp_redirect_multi_kern.c | 99 .../selftests/bpf/test_xdp_redirect_multi.sh | 205 +++ .../selftests/bpf/xdp_redirect_multi.c| 236 ++ 4 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c create mode 100755 tools/testing/selftests/bpf/test_xdp_redirect_multi.sh create mode 100644 tools/testing/selftests/bpf/xdp_redirect_multi.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 6448c626498f..0c08b662a64e 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -49,6 +49,7 @@ TEST_FILES = xsk_prereqs.sh \ # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ test_xdp_redirect.sh \ + test_xdp_redirect_multi.sh \ test_xdp_meta.sh \ test_xdp_veth.sh \ test_offload.py \ @@ -79,7 +80,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \ test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \ - xdpxceiver + xdpxceiver xdp_redirect_multi TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read diff --git a/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c b/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c new file mode 100644 index ..099bf444acab --- /dev/null +++ b/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* It would be easier to use a key:if_index, value:if_index map, but it + * will need a very large entries as the if_index number may get very large, + * this would affect the performace. So the DEVMAP here is just for testing. + */ +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 1024); +} map_v4 SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 128); +} map_all SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 128); +} map_egress SEC(".maps"); + +/* map to store egress interfaces mac addresses */ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u32); + __type(value, __be64); + __uint(max_entries, 128); +} mac_map SEC(".maps"); + +SEC("xdp_redirect_map_multi") +int xdp_redirect_map_multi_prog(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + int if_index = ctx->ingress_ifindex; + struct ethhdr *eth = data; + __u16 h_proto; + __u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + h_proto = eth->h_proto; + + if (h_proto == bpf_htons(ETH_P_IP)) + return bpf_redirect_map(&map_v4, 0, BPF_F_REDIR_MASK); + else if (h_proto == bpf_htons(ETH_P_IPV6)) + return bpf_redirect_map(&map_all, if_index
[PATCHv5 bpf-next 3/4] sample/bpf: add xdp_redirect_map_multi for redirect_map broadcast test
This is a sample for xdp redirect broadcast. In the sample we could forward all packets between given interfaces. There is also an option -X that could enable 2nd xdp_prog on egress interface. Signed-off-by: Hangbin Liu --- samples/bpf/Makefile | 3 + samples/bpf/xdp_redirect_map_multi_kern.c | 87 +++ samples/bpf/xdp_redirect_map_multi_user.c | 302 ++ 3 files changed, 392 insertions(+) create mode 100644 samples/bpf/xdp_redirect_map_multi_kern.c create mode 100644 samples/bpf/xdp_redirect_map_multi_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 45ceca4e2c70..520434ea966f 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -41,6 +41,7 @@ tprogs-y += test_map_in_map tprogs-y += per_socket_stats_example tprogs-y += xdp_redirect tprogs-y += xdp_redirect_map +tprogs-y += xdp_redirect_map_multi tprogs-y += xdp_redirect_cpu tprogs-y += xdp_monitor tprogs-y += xdp_rxq_info @@ -99,6 +100,7 @@ test_map_in_map-objs := test_map_in_map_user.o per_socket_stats_example-objs := cookie_uid_helper_example.o xdp_redirect-objs := xdp_redirect_user.o xdp_redirect_map-objs := xdp_redirect_map_user.o +xdp_redirect_map_multi-objs := xdp_redirect_map_multi_user.o xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o xdp_monitor-objs := xdp_monitor_user.o xdp_rxq_info-objs := xdp_rxq_info_user.o @@ -160,6 +162,7 @@ always-y += tcp_tos_reflect_kern.o always-y += tcp_dumpstats_kern.o always-y += xdp_redirect_kern.o always-y += xdp_redirect_map_kern.o +always-y += xdp_redirect_map_multi_kern.o always-y += xdp_redirect_cpu_kern.o always-y += xdp_monitor_kern.o always-y += xdp_rxq_info_kern.o diff --git a/samples/bpf/xdp_redirect_map_multi_kern.c b/samples/bpf/xdp_redirect_map_multi_kern.c new file mode 100644 index ..e6be70225ee1 --- /dev/null +++ b/samples/bpf/xdp_redirect_map_multi_kern.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 32); +} forward_map_general SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 32); +} forward_map_native SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __type(key, u32); + __type(value, long); + __uint(max_entries, 1); +} rxcnt SEC(".maps"); + +/* map to store egress interfaces mac addresses, set the + * max_entries to 1 and extend it in user sapce prog. + */ +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, u32); + __type(value, __be64); + __uint(max_entries, 1); +} mac_map SEC(".maps"); + +static int xdp_redirect_map(struct xdp_md *ctx, void *forward_map) +{ + long *value; + u32 key = 0; + + /* count packet in global counter */ + value = bpf_map_lookup_elem(&rxcnt, &key); + if (value) + *value += 1; + + return bpf_redirect_map(forward_map, key, BPF_F_REDIR_MASK); +} + +SEC("xdp_redirect_general") +int xdp_redirect_map_general(struct xdp_md *ctx) +{ + return xdp_redirect_map(ctx, &forward_map_general); +} + +SEC("xdp_redirect_native") +int xdp_redirect_map_native(struct xdp_md *ctx) +{ + return xdp_redirect_map(ctx, &forward_map_native); +} + +SEC("xdp_devmap/map_prog") +int xdp_devmap_prog(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + u32 key = ctx->egress_ifindex; + struct ethhdr *eth = data; + __be64 *mac; + u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + mac = bpf_map_lookup_elem(&mac_map, &key); + if (mac) + __builtin_memcpy(eth->h_source, mac, ETH_ALEN); + + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/xdp_redirect_map_multi_user.c b/samples/bpf/xdp_redirect_map_multi_user.c new file mode 100644 index ..84cdbbed20b7 --- /dev/null +++ b/samples/bpf/xdp_redirect_map_multi_user.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_util.h" +#include +#include + +#define MAX_IFACE_NUM 32 + +static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; +static int ifaces[MAX_IFACE_NUM] = {}; +static int rxcnt_map_fd; + +static void int_exit(int sig) +{ + __u32 prog_id = 0; + int i; + + for (i = 0; ifaces[i] > 0; i++) { + if (bpf_get_link_xdp_id(ifaces[i], &p
[PATCHv4 bpf-next 3/5] selftests/bpf: Add re-attach test to fexit_test
Adding the test to re-attach (detach/attach again) tracing fexit programs, plus check that already linked program can't be attached again. Also switching to ASSERT* macros. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fexit_test.c | 51 +-- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_test.c b/tools/testing/selftests/bpf/prog_tests/fexit_test.c index 78d7a2765c27..c48e10c138bc 100644 --- a/tools/testing/selftests/bpf/prog_tests/fexit_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fexit_test.c @@ -3,35 +3,56 @@ #include #include "fexit_test.skel.h" -void test_fexit_test(void) +static int fexit_test(struct fexit_test *fexit_skel) { - struct fexit_test *fexit_skel = NULL; int err, prog_fd, i; __u32 duration = 0, retval; + struct bpf_link *link; __u64 *result; - fexit_skel = fexit_test__open_and_load(); - if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) - goto cleanup; - err = fexit_test__attach(fexit_skel); - if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) - goto cleanup; + if (!ASSERT_OK(err, "fexit_attach")) + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(fexit_skel->progs.test1); + if (!ASSERT_ERR_PTR(link, "fexit_attach_link")) + return -1; prog_fd = bpf_program__fd(fexit_skel->progs.test1); err = bpf_prog_test_run(prog_fd, 1, NULL, 0, NULL, NULL, &retval, &duration); - CHECK(err || retval, "test_run", - "err %d errno %d retval %d duration %d\n", - err, errno, retval, duration); + ASSERT_OK(err || retval, "test_run"); result = (__u64 *)fexit_skel->bss; - for (i = 0; i < 6; i++) { - if (CHECK(result[i] != 1, "result", - "fexit_test%d failed err %lld\n", i + 1, result[i])) - goto cleanup; + for (i = 0; i < sizeof(*fexit_skel->bss) / sizeof(__u64); i++) { + if (!ASSERT_EQ(result[i], 1, "fexit_result")) + return -1; } + fexit_test__detach(fexit_skel); + + /* zero results for re-attach test */ + memset(fexit_skel->bss, 0, sizeof(*fexit_skel->bss)); + return 0; +} + +void test_fexit_test(void) +{ + struct fexit_test *fexit_skel = NULL; + int err; + + fexit_skel = fexit_test__open_and_load(); + if (!ASSERT_OK_PTR(fexit_skel, "fexit_skel_load")) + goto cleanup; + + err = fexit_test(fexit_skel); + if (!ASSERT_OK(err, "fexit_first_attach")) + goto cleanup; + + err = fexit_test(fexit_skel); + ASSERT_OK(err, "fexit_second_attach"); + cleanup: fexit_test__destroy(fexit_skel); } -- 2.30.2
[PATCHv4 bpf-next 4/5] selftests/bpf: Add re-attach test to lsm test
Adding the test to re-attach (detach/attach again) lsm programs, plus check that already linked program can't be attached again. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/test_lsm.c | 48 +++ 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c index 2755e4f81499..d492e76e01cf 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c @@ -18,6 +18,8 @@ char *CMD_ARGS[] = {"true", NULL}; #define GET_PAGE_ADDR(ADDR, PAGE_SIZE) \ (char *)(((unsigned long) (ADDR + PAGE_SIZE)) & ~(PAGE_SIZE-1)) +static int duration = 0; + int stack_mprotect(void) { void *buf; @@ -51,23 +53,25 @@ int exec_cmd(int *monitored_pid) return -EINVAL; } -void test_test_lsm(void) +static int test_lsm(struct lsm *skel) { - struct lsm *skel = NULL; - int err, duration = 0; + struct bpf_link *link; int buf = 1234; - - skel = lsm__open_and_load(); - if (CHECK(!skel, "skel_load", "lsm skeleton failed\n")) - goto close_prog; + int err; err = lsm__attach(skel); if (CHECK(err, "attach", "lsm attach failed: %d\n", err)) - goto close_prog; + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(skel->progs.test_int_hook); + if (CHECK(!IS_ERR(link), "attach_link", + "re-attach without detach should not succeed")) + return -1; err = exec_cmd(&skel->bss->monitored_pid); if (CHECK(err < 0, "exec_cmd", "err %d errno %d\n", err, errno)) - goto close_prog; + return err; CHECK(skel->bss->bprm_count != 1, "bprm_count", "bprm_count = %d\n", skel->bss->bprm_count); @@ -77,7 +81,7 @@ void test_test_lsm(void) err = stack_mprotect(); if (CHECK(errno != EPERM, "stack_mprotect", "want err=EPERM, got %d\n", errno)) - goto close_prog; + return err; CHECK(skel->bss->mprotect_count != 1, "mprotect_count", "mprotect_count = %d\n", skel->bss->mprotect_count); @@ -89,6 +93,30 @@ void test_test_lsm(void) CHECK(skel->bss->copy_test != 3, "copy_test", "copy_test = %d\n", skel->bss->copy_test); + lsm__detach(skel); + + skel->bss->copy_test = 0; + skel->bss->bprm_count = 0; + skel->bss->mprotect_count = 0; + return 0; +} + +void test_test_lsm(void) +{ + struct lsm *skel = NULL; + int err; + + skel = lsm__open_and_load(); + if (CHECK(!skel, "lsm_skel_load", "lsm skeleton failed\n")) + goto close_prog; + + err = test_lsm(skel); + if (CHECK(err, "test_lsm", "first attach failed\n")) + goto close_prog; + + err = test_lsm(skel); + CHECK(err, "test_lsm", "second attach failed\n"); + close_prog: lsm__destroy(skel); } -- 2.30.2
[PATCHv4 bpf-next 5/5] selftests/bpf: Test that module can't be unloaded with attached trampoline
Adding test to verify that once we attach module's trampoline, the module can't be unloaded. Acked-by: Andrii Nakryiko Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/module_attach.c | 23 +++ 1 file changed, 23 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/module_attach.c b/tools/testing/selftests/bpf/prog_tests/module_attach.c index 5bc53d53d86e..d85a69b7ce44 100644 --- a/tools/testing/selftests/bpf/prog_tests/module_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/module_attach.c @@ -45,12 +45,18 @@ static int trigger_module_test_write(int write_sz) return 0; } +static int delete_module(const char *name, int flags) +{ + return syscall(__NR_delete_module, name, flags); +} + void test_module_attach(void) { const int READ_SZ = 456; const int WRITE_SZ = 457; struct test_module_attach* skel; struct test_module_attach__bss *bss; + struct bpf_link *link; int err; skel = test_module_attach__open(); @@ -84,6 +90,23 @@ void test_module_attach(void) ASSERT_EQ(bss->fexit_ret, -EIO, "fexit_tet"); ASSERT_EQ(bss->fmod_ret_read_sz, READ_SZ, "fmod_ret"); + test_module_attach__detach(skel); + + /* attach fentry/fexit and make sure it get's module reference */ + link = bpf_program__attach(skel->progs.handle_fentry); + if (!ASSERT_OK_PTR(link, "attach_fentry")) + goto cleanup; + + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + bpf_link__destroy(link); + + link = bpf_program__attach(skel->progs.handle_fexit); + if (!ASSERT_OK_PTR(link, "attach_fexit")) + goto cleanup; + + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + bpf_link__destroy(link); + cleanup: test_module_attach__destroy(skel); } -- 2.30.2
[PATCHv4 bpf-next 2/5] selftests/bpf: Add re-attach test to fentry_test
Adding the test to re-attach (detach/attach again) tracing fentry programs, plus check that already linked program can't be attached again. Also switching to ASSERT* macros and adding missing ';' in ASSERT_ERR_PTR macro. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fentry_test.c| 51 +-- tools/testing/selftests/bpf/test_progs.h | 2 +- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fentry_test.c b/tools/testing/selftests/bpf/prog_tests/fentry_test.c index 04ebbf1cb390..f440c74f5367 100644 --- a/tools/testing/selftests/bpf/prog_tests/fentry_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fentry_test.c @@ -3,35 +3,56 @@ #include #include "fentry_test.skel.h" -void test_fentry_test(void) +static int fentry_test(struct fentry_test *fentry_skel) { - struct fentry_test *fentry_skel = NULL; int err, prog_fd, i; __u32 duration = 0, retval; + struct bpf_link *link; __u64 *result; - fentry_skel = fentry_test__open_and_load(); - if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n")) - goto cleanup; - err = fentry_test__attach(fentry_skel); - if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) - goto cleanup; + if (!ASSERT_OK(err, "fentry_attach")) + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(fentry_skel->progs.test1); + if (!ASSERT_ERR_PTR(link, "fentry_attach_link")) + return -1; prog_fd = bpf_program__fd(fentry_skel->progs.test1); err = bpf_prog_test_run(prog_fd, 1, NULL, 0, NULL, NULL, &retval, &duration); - CHECK(err || retval, "test_run", - "err %d errno %d retval %d duration %d\n", - err, errno, retval, duration); + ASSERT_OK(err || retval, "test_run"); result = (__u64 *)fentry_skel->bss; - for (i = 0; i < 6; i++) { - if (CHECK(result[i] != 1, "result", - "fentry_test%d failed err %lld\n", i + 1, result[i])) - goto cleanup; + for (i = 0; i < sizeof(*fentry_skel->bss) / sizeof(__u64); i++) { + if (!ASSERT_EQ(result[i], 1, "fentry_result")) + return -1; } + fentry_test__detach(fentry_skel); + + /* zero results for re-attach test */ + memset(fentry_skel->bss, 0, sizeof(*fentry_skel->bss)); + return 0; +} + +void test_fentry_test(void) +{ + struct fentry_test *fentry_skel = NULL; + int err; + + fentry_skel = fentry_test__open_and_load(); + if (!ASSERT_OK_PTR(fentry_skel, "fentry_skel_load")) + goto cleanup; + + err = fentry_test(fentry_skel); + if (!ASSERT_OK(err, "fentry_first_attach")) + goto cleanup; + + err = fentry_test(fentry_skel); + ASSERT_OK(err, "fentry_second_attach"); + cleanup: fentry_test__destroy(fentry_skel); } diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h index e87c8546230e..ee7e3b45182a 100644 --- a/tools/testing/selftests/bpf/test_progs.h +++ b/tools/testing/selftests/bpf/test_progs.h @@ -210,7 +210,7 @@ extern int test__join_cgroup(const char *path); #define ASSERT_ERR_PTR(ptr, name) ({ \ static int duration = 0;\ const void *___res = (ptr); \ - bool ___ok = IS_ERR(___res) \ + bool ___ok = IS_ERR(___res);\ CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \ ___ok; \ }) -- 2.30.2
[PATCHv3 bpf-next 4/5] selftests/bpf: Add re-attach test to lsm test
Adding the test to re-attach (detach/attach again) lsm programs, plus check that already linked program can't be attached again. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/test_lsm.c | 48 +++ 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c index 2755e4f81499..d492e76e01cf 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c @@ -18,6 +18,8 @@ char *CMD_ARGS[] = {"true", NULL}; #define GET_PAGE_ADDR(ADDR, PAGE_SIZE) \ (char *)(((unsigned long) (ADDR + PAGE_SIZE)) & ~(PAGE_SIZE-1)) +static int duration = 0; + int stack_mprotect(void) { void *buf; @@ -51,23 +53,25 @@ int exec_cmd(int *monitored_pid) return -EINVAL; } -void test_test_lsm(void) +static int test_lsm(struct lsm *skel) { - struct lsm *skel = NULL; - int err, duration = 0; + struct bpf_link *link; int buf = 1234; - - skel = lsm__open_and_load(); - if (CHECK(!skel, "skel_load", "lsm skeleton failed\n")) - goto close_prog; + int err; err = lsm__attach(skel); if (CHECK(err, "attach", "lsm attach failed: %d\n", err)) - goto close_prog; + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(skel->progs.test_int_hook); + if (CHECK(!IS_ERR(link), "attach_link", + "re-attach without detach should not succeed")) + return -1; err = exec_cmd(&skel->bss->monitored_pid); if (CHECK(err < 0, "exec_cmd", "err %d errno %d\n", err, errno)) - goto close_prog; + return err; CHECK(skel->bss->bprm_count != 1, "bprm_count", "bprm_count = %d\n", skel->bss->bprm_count); @@ -77,7 +81,7 @@ void test_test_lsm(void) err = stack_mprotect(); if (CHECK(errno != EPERM, "stack_mprotect", "want err=EPERM, got %d\n", errno)) - goto close_prog; + return err; CHECK(skel->bss->mprotect_count != 1, "mprotect_count", "mprotect_count = %d\n", skel->bss->mprotect_count); @@ -89,6 +93,30 @@ void test_test_lsm(void) CHECK(skel->bss->copy_test != 3, "copy_test", "copy_test = %d\n", skel->bss->copy_test); + lsm__detach(skel); + + skel->bss->copy_test = 0; + skel->bss->bprm_count = 0; + skel->bss->mprotect_count = 0; + return 0; +} + +void test_test_lsm(void) +{ + struct lsm *skel = NULL; + int err; + + skel = lsm__open_and_load(); + if (CHECK(!skel, "lsm_skel_load", "lsm skeleton failed\n")) + goto close_prog; + + err = test_lsm(skel); + if (CHECK(err, "test_lsm", "first attach failed\n")) + goto close_prog; + + err = test_lsm(skel); + CHECK(err, "test_lsm", "second attach failed\n"); + close_prog: lsm__destroy(skel); } -- 2.30.2
[PATCHv3 bpf-next 5/5] selftests/bpf: Test that module can't be unloaded with attached trampoline
Adding test to verify that once we attach module's trampoline, the module can't be unloaded. Acked-by: Andrii Nakryiko Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/module_attach.c | 23 +++ 1 file changed, 23 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/module_attach.c b/tools/testing/selftests/bpf/prog_tests/module_attach.c index 5bc53d53d86e..d85a69b7ce44 100644 --- a/tools/testing/selftests/bpf/prog_tests/module_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/module_attach.c @@ -45,12 +45,18 @@ static int trigger_module_test_write(int write_sz) return 0; } +static int delete_module(const char *name, int flags) +{ + return syscall(__NR_delete_module, name, flags); +} + void test_module_attach(void) { const int READ_SZ = 456; const int WRITE_SZ = 457; struct test_module_attach* skel; struct test_module_attach__bss *bss; + struct bpf_link *link; int err; skel = test_module_attach__open(); @@ -84,6 +90,23 @@ void test_module_attach(void) ASSERT_EQ(bss->fexit_ret, -EIO, "fexit_tet"); ASSERT_EQ(bss->fmod_ret_read_sz, READ_SZ, "fmod_ret"); + test_module_attach__detach(skel); + + /* attach fentry/fexit and make sure it get's module reference */ + link = bpf_program__attach(skel->progs.handle_fentry); + if (!ASSERT_OK_PTR(link, "attach_fentry")) + goto cleanup; + + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + bpf_link__destroy(link); + + link = bpf_program__attach(skel->progs.handle_fexit); + if (!ASSERT_OK_PTR(link, "attach_fexit")) + goto cleanup; + + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + bpf_link__destroy(link); + cleanup: test_module_attach__destroy(skel); } -- 2.30.2
[PATCHv3 bpf-next 2/5] selftests/bpf: Add re-attach test to fentry_test
Adding the test to re-attach (detach/attach again) tracing fentry programs, plus check that already linked program can't be attached again. Also switching to ASSERT* macros and adding missing ';' in ASSERT_ERR_PTR macro. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fentry_test.c| 51 +-- tools/testing/selftests/bpf/test_progs.h | 2 +- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fentry_test.c b/tools/testing/selftests/bpf/prog_tests/fentry_test.c index 04ebbf1cb390..f440c74f5367 100644 --- a/tools/testing/selftests/bpf/prog_tests/fentry_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fentry_test.c @@ -3,35 +3,56 @@ #include #include "fentry_test.skel.h" -void test_fentry_test(void) +static int fentry_test(struct fentry_test *fentry_skel) { - struct fentry_test *fentry_skel = NULL; int err, prog_fd, i; __u32 duration = 0, retval; + struct bpf_link *link; __u64 *result; - fentry_skel = fentry_test__open_and_load(); - if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n")) - goto cleanup; - err = fentry_test__attach(fentry_skel); - if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) - goto cleanup; + if (!ASSERT_OK(err, "fentry_attach")) + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(fentry_skel->progs.test1); + if (!ASSERT_ERR_PTR(link, "fentry_attach_link")) + return -1; prog_fd = bpf_program__fd(fentry_skel->progs.test1); err = bpf_prog_test_run(prog_fd, 1, NULL, 0, NULL, NULL, &retval, &duration); - CHECK(err || retval, "test_run", - "err %d errno %d retval %d duration %d\n", - err, errno, retval, duration); + ASSERT_OK(err || retval, "test_run"); result = (__u64 *)fentry_skel->bss; - for (i = 0; i < 6; i++) { - if (CHECK(result[i] != 1, "result", - "fentry_test%d failed err %lld\n", i + 1, result[i])) - goto cleanup; + for (i = 0; i < sizeof(*fentry_skel->bss) / sizeof(__u64); i++) { + if (!ASSERT_EQ(result[i], 1, "fentry_result")) + return -1; } + fentry_test__detach(fentry_skel); + + /* zero results for re-attach test */ + memset(fentry_skel->bss, 0, sizeof(*fentry_skel->bss)); + return 0; +} + +void test_fentry_test(void) +{ + struct fentry_test *fentry_skel = NULL; + int err; + + fentry_skel = fentry_test__open_and_load(); + if (!ASSERT_OK_PTR(fentry_skel, "fentry_skel_load")) + goto cleanup; + + err = fentry_test(fentry_skel); + if (!ASSERT_OK(err, "fentry_first_attach")) + goto cleanup; + + err = fentry_test(fentry_skel); + ASSERT_OK(err, "fentry_second_attach"); + cleanup: fentry_test__destroy(fentry_skel); } diff --git a/tools/testing/selftests/bpf/test_progs.h b/tools/testing/selftests/bpf/test_progs.h index e87c8546230e..ee7e3b45182a 100644 --- a/tools/testing/selftests/bpf/test_progs.h +++ b/tools/testing/selftests/bpf/test_progs.h @@ -210,7 +210,7 @@ extern int test__join_cgroup(const char *path); #define ASSERT_ERR_PTR(ptr, name) ({ \ static int duration = 0;\ const void *___res = (ptr); \ - bool ___ok = IS_ERR(___res) \ + bool ___ok = IS_ERR(___res);\ CHECK(!___ok, (name), "unexpected pointer: %p\n", ___res); \ ___ok; \ }) -- 2.30.2
[PATCHv3 bpf-next 3/5] selftests/bpf: Add re-attach test to fexit_test
Adding the test to re-attach (detach/attach again) tracing fexit programs, plus check that already linked program can't be attached again. Also switching to ASSERT* macros. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fexit_test.c | 51 +-- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_test.c b/tools/testing/selftests/bpf/prog_tests/fexit_test.c index 78d7a2765c27..c48e10c138bc 100644 --- a/tools/testing/selftests/bpf/prog_tests/fexit_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fexit_test.c @@ -3,35 +3,56 @@ #include #include "fexit_test.skel.h" -void test_fexit_test(void) +static int fexit_test(struct fexit_test *fexit_skel) { - struct fexit_test *fexit_skel = NULL; int err, prog_fd, i; __u32 duration = 0, retval; + struct bpf_link *link; __u64 *result; - fexit_skel = fexit_test__open_and_load(); - if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) - goto cleanup; - err = fexit_test__attach(fexit_skel); - if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) - goto cleanup; + if (!ASSERT_OK(err, "fexit_attach")) + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(fexit_skel->progs.test1); + if (!ASSERT_ERR_PTR(link, "fexit_attach_link")) + return -1; prog_fd = bpf_program__fd(fexit_skel->progs.test1); err = bpf_prog_test_run(prog_fd, 1, NULL, 0, NULL, NULL, &retval, &duration); - CHECK(err || retval, "test_run", - "err %d errno %d retval %d duration %d\n", - err, errno, retval, duration); + ASSERT_OK(err || retval, "test_run"); result = (__u64 *)fexit_skel->bss; - for (i = 0; i < 6; i++) { - if (CHECK(result[i] != 1, "result", - "fexit_test%d failed err %lld\n", i + 1, result[i])) - goto cleanup; + for (i = 0; i < sizeof(*fexit_skel->bss) / sizeof(__u64); i++) { + if (!ASSERT_EQ(result[i], 1, "fexit_result")) + return -1; } + fexit_test__detach(fexit_skel); + + /* zero results for re-attach test */ + memset(fexit_skel->bss, 0, sizeof(*fexit_skel->bss)); + return 0; +} + +void test_fexit_test(void) +{ + struct fexit_test *fexit_skel = NULL; + int err; + + fexit_skel = fexit_test__open_and_load(); + if (!ASSERT_OK_PTR(fexit_skel, "fexit_skel_load")) + goto cleanup; + + err = fexit_test(fexit_skel); + if (!ASSERT_OK(err, "fexit_first_attach")) + goto cleanup; + + err = fexit_test(fexit_skel); + ASSERT_OK(err, "fexit_second_attach"); + cleanup: fexit_test__destroy(fexit_skel); } -- 2.30.2
RE: [net PATCH] ixgbe: Fix NULL pointer dereference in ethtool loopback test
>-Original Message- >From: Alexander Duyck >Sent: Monday, March 8, 2021 12:42 PM >To: intel-wired-...@lists.osuosl.org >Cc: Brandeburg, Jesse ; Nguyen, Anthony L >; netdev@vger.kernel.org >Subject: [net PATCH] ixgbe: Fix NULL pointer dereference in ethtool loopback >test > >From: Alexander Duyck > >The ixgbe driver currently generates a NULL pointer dereference when >performing the ethtool loopback test. This is due to the fact that there isn't >a >q_vector associated with the test ring when it is setup as interrupts are not >normally added to the test rings. > >To address this I have added code that will check for a q_vector before >returning >a napi_id value. If a q_vector is not present it will return a value of 0. > >Fixes: b02e5a0ebb17 ("xsk: Propagate napi_id to XDP socket Rx path") >Signed-off-by: Alexander Duyck >--- > drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |9 - > 1 file changed, 8 insertions(+), 1 deletion(-) > Tested-by: Dave Switzer
[PATCH net-next 7/7] selftests: mlxsw: Add a trap_fwd test to devlink_trap_control
Test that trap_fwd'd packets show up under the correct trap. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel --- .../drivers/net/mlxsw/devlink_trap_control.sh | 23 --- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_control.sh b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_control.sh index a37273473c1b..8bca4c58819b 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_control.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/devlink_trap_control.sh @@ -83,6 +83,7 @@ ALL_TESTS=" ptp_general_test flow_action_sample_test flow_action_trap_test + flow_action_trap_fwd_test " NUM_NETIFS=4 source $lib_dir/lib.sh @@ -663,14 +664,18 @@ flow_action_sample_test() tc qdisc del dev $rp1 clsact } -flow_action_trap_test() +__flow_action_trap_test() { + local action=$1; shift + local trap=$1; shift + local description=$1; shift + # Install a filter that traps a specific flow. tc qdisc add dev $rp1 clsact tc filter add dev $rp1 ingress proto ip pref 1 handle 101 flower \ - skip_sw ip_proto udp src_port 12345 dst_port 54321 action trap + skip_sw ip_proto udp src_port 12345 dst_port 54321 action $action - devlink_trap_stats_test "Flow Trapping (Logging)" "flow_action_trap" \ + devlink_trap_stats_test "$description" $trap \ $MZ $h1 -c 1 -a own -b $(mac_get $rp1) \ -A 192.0.2.1 -B 198.51.100.1 -t udp sp=12345,dp=54321 -p 100 -q @@ -678,6 +683,18 @@ flow_action_trap_test() tc qdisc del dev $rp1 clsact } +flow_action_trap_test() +{ + __flow_action_trap_test trap flow_action_trap \ + "Flow Trapping (Logging)" +} + +flow_action_trap_fwd_test() +{ + __flow_action_trap_test trap_fwd flow_action_trap_fwd \ + "Flow Trap-and-forwarding (Logging)" +} + trap cleanup EXIT setup_prepare -- 2.26.2
[PATCH net-next 6/7] selftests: forwarding: Add a test for TC trapping behavior
Test that trapped packets are forwarded through the SW datapath, whereas trap_fwd'd ones are not (but are forwarded through HW datapath). For completeness' sake, also test that "pass" (i.e. lack of trapping) simply forwards the packets in the HW datapath. Signed-off-by: Petr Machata Reviewed-by: Ido Schimmel --- .../selftests/net/forwarding/tc_trap.sh | 170 ++ 1 file changed, 170 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_trap.sh diff --git a/tools/testing/selftests/net/forwarding/tc_trap.sh b/tools/testing/selftests/net/forwarding/tc_trap.sh new file mode 100755 index ..56336cea45a2 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_trap.sh @@ -0,0 +1,170 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# In the following simple routing scenario, put SW datapath packet probes on +# $swp1, $swp2 and $h2. Always expect packets to arrive at $h2. Depending on +# whether, in the HW datapath, $swp1 lets packets pass, traps them, or +# traps_forwards them, $swp1 and $swp2 probes are expected to give different +# results. +# +# +--+ +--+ +# | H1 | | H2 | +# |+ $h1 | |$h2 + | +# || 192.0.2.1/28| | 192.0.2.18/28 | | +# +|-+ +|-+ +# || +# +||-+ +# | SW || | +# |+ $swp1$swp2 + | +# | 192.0.2.2/28 192.0.2.17/28 | +# +---+ + + +ALL_TESTS=" + no_trap_test + trap_fwd_test + trap_test +" + +NUM_NETIFS=4 +source lib.sh +source tc_common.sh + +h1_create() +{ + simple_if_init $h1 192.0.2.1/28 + ip route add vrf v$h1 192.0.2.16/28 via 192.0.2.2 +} + +h1_destroy() +{ + ip route del vrf v$h1 192.0.2.16/28 via 192.0.2.2 + simple_if_fini $h1 192.0.2.1/28 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.18/28 + ip route add vrf v$h2 192.0.2.0/28 via 192.0.2.17 + tc qdisc add dev $h2 clsact +} + +h2_destroy() +{ + tc qdisc del dev $h2 clsact + ip route del vrf v$h2 192.0.2.0/28 via 192.0.2.17 + simple_if_fini $h2 192.0.2.18/28 +} + +switch_create() +{ + simple_if_init $swp1 192.0.2.2/28 + __simple_if_init $swp2 v$swp1 192.0.2.17/28 + + tc qdisc add dev $swp1 clsact + tc qdisc add dev $swp2 clsact +} + +switch_destroy() +{ + tc qdisc del dev $swp2 clsact + tc qdisc del dev $swp1 clsact + + __simple_if_fini $swp2 192.0.2.17/28 + simple_if_fini $swp1 192.0.2.2/28 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + forwarding_enable + + h1_create + h2_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h2_destroy + h1_destroy + + forwarding_restore + vrf_cleanup +} + +__test() +{ + local action=$1; shift + local ingress_should_fail=$1; shift + local egress_should_fail=$1; shift + + tc filter add dev $swp1 ingress protocol ip pref 2 handle 101 \ + flower skip_sw dst_ip 192.0.2.18 action $action + tc filter add dev $swp1 ingress protocol ip pref 1 handle 102 \ + flower skip_hw dst_ip 192.0.2.18 action pass + tc filter add dev $swp2 egress protocol ip pref 1 handle 103 \ + flower skip_hw dst_ip 192.0.2.18 action pass + tc filter add dev $h2 ingress protocol ip pref 1 handle 104 \ + flower dst_ip 192.0.2.18 action drop + + RET=0 + + $MZ $h1 -c 1 -p 64 -a $(mac_get $h1) -b $(mac_get $swp1) \ + -A 192.0.2.1 -B 192.0.2.18 -q -t ip + + tc_check_packets "dev $swp1 ingress" 102 1 + check_err_fail $ingress_should_fail $? "ingress should_fail $ingress_should_fail" + + tc_check_packets "dev $swp2 egress" 103 1 + check_err_fail $egress_should_fail $? "egress should_fail $egress_should_fail" + + tc_check_packets "dev $h2 ingress" 104 1 + check_err $? "Did not see the packet on host" + + log_test "$action test" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 104 flower + tc filter del dev $swp2 egress protocol ip pref 1 handle 103 flower + tc filter del dev $swp1 ingress protocol ip p
Re: [PATCHv2 bpf-next 5/5] selftests/bpf: Test that module can't be unloaded with attached trampoline
On Wed, Apr 07, 2021 at 04:04:48PM -0700, Andrii Nakryiko wrote: > On Wed, Apr 7, 2021 at 4:22 AM Jiri Olsa wrote: > > > > Adding test to verify that once we attach module's trampoline, > > the module can't be unloaded. > > > > Signed-off-by: Jiri Olsa > > --- > > To be fair, to test that you are actually testing what you think you > are testing, you'd have to prove that you *can* detach when no program > is attached to bpf_testmod ;) You'd also need kern_sync_rcu() to wait > for all the async clean up to complete inside the kernel. But that > doesn't interact with other tests well, so I think it's fine. well without the kernel change the module gets unloaded and the test below fails.. we could add module unload test, but as you described it could probably interfere with other tests > > grumpily due to CHECK() usage (please do consider updating to ASSERT): ok, will check thanks, jirka > > Acked-by: Andrii Nakryiko > > > .../selftests/bpf/prog_tests/module_attach.c | 23 +++ > > 1 file changed, 23 insertions(+) > > > > diff --git a/tools/testing/selftests/bpf/prog_tests/module_attach.c > > b/tools/testing/selftests/bpf/prog_tests/module_attach.c > > index 5bc53d53d86e..d180b8c28287 100644 > > --- a/tools/testing/selftests/bpf/prog_tests/module_attach.c > > +++ b/tools/testing/selftests/bpf/prog_tests/module_attach.c > > @@ -45,12 +45,18 @@ static int trigger_module_test_write(int write_sz) > > return 0; > > } > > > > +static int delete_module(const char *name, int flags) > > +{ > > + return syscall(__NR_delete_module, name, flags); > > +} > > + > > void test_module_attach(void) > > { > > const int READ_SZ = 456; > > const int WRITE_SZ = 457; > > struct test_module_attach* skel; > > struct test_module_attach__bss *bss; > > + struct bpf_link *link; > > int err; > > > > skel = test_module_attach__open(); > > @@ -84,6 +90,23 @@ void test_module_attach(void) > > ASSERT_EQ(bss->fexit_ret, -EIO, "fexit_tet"); > > ASSERT_EQ(bss->fmod_ret_read_sz, READ_SZ, "fmod_ret"); > > > > + test_module_attach__detach(skel); > > + > > + /* attach fentry/fexit and make sure it get's module reference */ > > + link = bpf_program__attach(skel->progs.handle_fentry); > > + if (CHECK(IS_ERR(link), "attach_fentry", "err: %ld\n", > > PTR_ERR(link))) > > + goto cleanup; > > + > > + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); > > + bpf_link__destroy(link); > > + > > + link = bpf_program__attach(skel->progs.handle_fexit); > > + if (CHECK(IS_ERR(link), "attach_fexit", "err: %ld\n", > > PTR_ERR(link))) > > + goto cleanup; > > + > > + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); > > + bpf_link__destroy(link); > > + > > cleanup: > > test_module_attach__destroy(skel); > > } > > -- > > 2.30.2 > > >
Re: [PATCHv2 bpf-next 2/5] selftests/bpf: Add re-attach test to fentry_test
On Wed, Apr 07, 2021 at 03:47:30PM -0700, Andrii Nakryiko wrote: > On Wed, Apr 7, 2021 at 4:21 AM Jiri Olsa wrote: > > > > Adding the test to re-attach (detach/attach again) tracing > > fentry programs, plus check that already linked program can't > > be attached again. > > > > Fixing the number of check-ed results, which should be 8. > > > > Signed-off-by: Jiri Olsa > > --- > > .../selftests/bpf/prog_tests/fentry_test.c| 48 +++ > > 1 file changed, 38 insertions(+), 10 deletions(-) > > > > diff --git a/tools/testing/selftests/bpf/prog_tests/fentry_test.c > > b/tools/testing/selftests/bpf/prog_tests/fentry_test.c > > index 04ebbf1cb390..1f7566e772e9 100644 > > --- a/tools/testing/selftests/bpf/prog_tests/fentry_test.c > > +++ b/tools/testing/selftests/bpf/prog_tests/fentry_test.c > > @@ -3,20 +3,24 @@ > > #include > > #include "fentry_test.skel.h" > > > > -void test_fentry_test(void) > > +static __u32 duration; > > + > > +static int fentry_test(struct fentry_test *fentry_skel) > > { > > - struct fentry_test *fentry_skel = NULL; > > + struct bpf_link *link; > > int err, prog_fd, i; > > - __u32 duration = 0, retval; > > __u64 *result; > > - > > - fentry_skel = fentry_test__open_and_load(); > > - if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton > > failed\n")) > > - goto cleanup; > > + __u32 retval; > > > > err = fentry_test__attach(fentry_skel); > > if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) > > - goto cleanup; > > + return err; > > + > > + /* Check that already linked program can't be attached again. */ > > + link = bpf_program__attach(fentry_skel->progs.test1); > > + if (CHECK(!IS_ERR(link), "fentry_attach_link", > > if (!ASSERT_ERR_PTR(link, "fentry_attach_link")) ? ok > > > + "re-attach without detach should not succeed")) > > + return -1; > > > > prog_fd = bpf_program__fd(fentry_skel->progs.test1); > > err = bpf_prog_test_run(prog_fd, 1, NULL, 0, > > @@ -26,12 +30,36 @@ void test_fentry_test(void) > > err, errno, retval, duration); > > > > result = (__u64 *)fentry_skel->bss; > > - for (i = 0; i < 6; i++) { > > + for (i = 0; i < 8; i++) { > > how about using sizeof(*fentry_skel->bss) / sizeof(__u64) ? ok > > > if (CHECK(result[i] != 1, "result", > > "fentry_test%d failed err %lld\n", i + 1, > > result[i])) > > - goto cleanup; > > + return -1; > > } > > > > + fentry_test__detach(fentry_skel); > > + > > + /* zero results for re-attach test */ > > + for (i = 0; i < 8; i++) > > + result[i] = 0; > > + return 0; > > +} > > + > > +void test_fentry_test(void) > > +{ > > + struct fentry_test *fentry_skel = NULL; > > + int err; > > + > > + fentry_skel = fentry_test__open_and_load(); > > + if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton > > failed\n")) > > + goto cleanup; > > + > > + err = fentry_test(fentry_skel); > > + if (CHECK(err, "fentry_test", "first attach failed\n")) > > + goto cleanup; > > + > > + err = fentry_test(fentry_skel); > > + CHECK(err, "fentry_test", "second attach failed\n"); > > overall: please try to use ASSERT_xxx macros, they are easier to > follow and require less typing ok, will check thanks, jirka
Re: [PATCHv2 bpf-next 3/5] selftests/bpf: Add re-attach test to fexit_test
On Wed, Apr 07, 2021 at 03:51:46PM -0700, Andrii Nakryiko wrote: > On Wed, Apr 7, 2021 at 4:21 AM Jiri Olsa wrote: > > > > Adding the test to re-attach (detach/attach again) tracing > > fexit programs, plus check that already linked program can't > > be attached again. > > > > Fixing the number of check-ed results, which should be 8. > > > > Signed-off-by: Jiri Olsa > > --- > > .../selftests/bpf/prog_tests/fexit_test.c | 48 +++ > > 1 file changed, 38 insertions(+), 10 deletions(-) > > > > diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_test.c > > b/tools/testing/selftests/bpf/prog_tests/fexit_test.c > > index 78d7a2765c27..579e620e6612 100644 > > --- a/tools/testing/selftests/bpf/prog_tests/fexit_test.c > > +++ b/tools/testing/selftests/bpf/prog_tests/fexit_test.c > > @@ -3,20 +3,24 @@ > > #include > > #include "fexit_test.skel.h" > > > > -void test_fexit_test(void) > > +static __u32 duration; > > + > > +static int fexit_test(struct fexit_test *fexit_skel) > > { > > - struct fexit_test *fexit_skel = NULL; > > + struct bpf_link *link; > > int err, prog_fd, i; > > - __u32 duration = 0, retval; > > __u64 *result; > > - > > - fexit_skel = fexit_test__open_and_load(); > > - if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton > > failed\n")) > > - goto cleanup; > > + __u32 retval; > > > > err = fexit_test__attach(fexit_skel); > > if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) > > - goto cleanup; > > + return err; > > + > > + /* Check that already linked program can't be attached again. */ > > + link = bpf_program__attach(fexit_skel->progs.test1); > > + if (CHECK(!IS_ERR(link), "fexit_attach_link", > > + "re-attach without detach should not succeed")) > > + return -1; > > > > prog_fd = bpf_program__fd(fexit_skel->progs.test1); > > err = bpf_prog_test_run(prog_fd, 1, NULL, 0, > > @@ -26,12 +30,36 @@ void test_fexit_test(void) > > err, errno, retval, duration); > > > > result = (__u64 *)fexit_skel->bss; > > - for (i = 0; i < 6; i++) { > > + for (i = 0; i < 8; i++) { > > if (CHECK(result[i] != 1, "result", > > "fexit_test%d failed err %lld\n", i + 1, > > result[i])) > > - goto cleanup; > > + return -1; > > } > > > > + fexit_test__detach(fexit_skel); > > + > > + /* zero results for re-attach test */ > > + for (i = 0; i < 8; i++) > > + result[i] = 0; > > memset(fexit_skel->bss, 0, sizeof(*fexit_skel->bss)) ? ;) > > and see my nits in previous patch about ASSERT over CHECK sure ;-) thanks jirka
Re: [PATCHv2 bpf-next 5/5] selftests/bpf: Test that module can't be unloaded with attached trampoline
On Wed, Apr 7, 2021 at 4:22 AM Jiri Olsa wrote: > > Adding test to verify that once we attach module's trampoline, > the module can't be unloaded. > > Signed-off-by: Jiri Olsa > --- To be fair, to test that you are actually testing what you think you are testing, you'd have to prove that you *can* detach when no program is attached to bpf_testmod ;) You'd also need kern_sync_rcu() to wait for all the async clean up to complete inside the kernel. But that doesn't interact with other tests well, so I think it's fine. grumpily due to CHECK() usage (please do consider updating to ASSERT): Acked-by: Andrii Nakryiko > .../selftests/bpf/prog_tests/module_attach.c | 23 +++ > 1 file changed, 23 insertions(+) > > diff --git a/tools/testing/selftests/bpf/prog_tests/module_attach.c > b/tools/testing/selftests/bpf/prog_tests/module_attach.c > index 5bc53d53d86e..d180b8c28287 100644 > --- a/tools/testing/selftests/bpf/prog_tests/module_attach.c > +++ b/tools/testing/selftests/bpf/prog_tests/module_attach.c > @@ -45,12 +45,18 @@ static int trigger_module_test_write(int write_sz) > return 0; > } > > +static int delete_module(const char *name, int flags) > +{ > + return syscall(__NR_delete_module, name, flags); > +} > + > void test_module_attach(void) > { > const int READ_SZ = 456; > const int WRITE_SZ = 457; > struct test_module_attach* skel; > struct test_module_attach__bss *bss; > + struct bpf_link *link; > int err; > > skel = test_module_attach__open(); > @@ -84,6 +90,23 @@ void test_module_attach(void) > ASSERT_EQ(bss->fexit_ret, -EIO, "fexit_tet"); > ASSERT_EQ(bss->fmod_ret_read_sz, READ_SZ, "fmod_ret"); > > + test_module_attach__detach(skel); > + > + /* attach fentry/fexit and make sure it get's module reference */ > + link = bpf_program__attach(skel->progs.handle_fentry); > + if (CHECK(IS_ERR(link), "attach_fentry", "err: %ld\n", PTR_ERR(link))) > + goto cleanup; > + > + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); > + bpf_link__destroy(link); > + > + link = bpf_program__attach(skel->progs.handle_fexit); > + if (CHECK(IS_ERR(link), "attach_fexit", "err: %ld\n", PTR_ERR(link))) > + goto cleanup; > + > + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); > + bpf_link__destroy(link); > + > cleanup: > test_module_attach__destroy(skel); > } > -- > 2.30.2 >
Re: [PATCHv2 bpf-next 3/5] selftests/bpf: Add re-attach test to fexit_test
On Wed, Apr 7, 2021 at 4:21 AM Jiri Olsa wrote: > > Adding the test to re-attach (detach/attach again) tracing > fexit programs, plus check that already linked program can't > be attached again. > > Fixing the number of check-ed results, which should be 8. > > Signed-off-by: Jiri Olsa > --- > .../selftests/bpf/prog_tests/fexit_test.c | 48 +++ > 1 file changed, 38 insertions(+), 10 deletions(-) > > diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_test.c > b/tools/testing/selftests/bpf/prog_tests/fexit_test.c > index 78d7a2765c27..579e620e6612 100644 > --- a/tools/testing/selftests/bpf/prog_tests/fexit_test.c > +++ b/tools/testing/selftests/bpf/prog_tests/fexit_test.c > @@ -3,20 +3,24 @@ > #include > #include "fexit_test.skel.h" > > -void test_fexit_test(void) > +static __u32 duration; > + > +static int fexit_test(struct fexit_test *fexit_skel) > { > - struct fexit_test *fexit_skel = NULL; > + struct bpf_link *link; > int err, prog_fd, i; > - __u32 duration = 0, retval; > __u64 *result; > - > - fexit_skel = fexit_test__open_and_load(); > - if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) > - goto cleanup; > + __u32 retval; > > err = fexit_test__attach(fexit_skel); > if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) > - goto cleanup; > + return err; > + > + /* Check that already linked program can't be attached again. */ > + link = bpf_program__attach(fexit_skel->progs.test1); > + if (CHECK(!IS_ERR(link), "fexit_attach_link", > + "re-attach without detach should not succeed")) > + return -1; > > prog_fd = bpf_program__fd(fexit_skel->progs.test1); > err = bpf_prog_test_run(prog_fd, 1, NULL, 0, > @@ -26,12 +30,36 @@ void test_fexit_test(void) > err, errno, retval, duration); > > result = (__u64 *)fexit_skel->bss; > - for (i = 0; i < 6; i++) { > + for (i = 0; i < 8; i++) { > if (CHECK(result[i] != 1, "result", > "fexit_test%d failed err %lld\n", i + 1, result[i])) > - goto cleanup; > + return -1; > } > > + fexit_test__detach(fexit_skel); > + > + /* zero results for re-attach test */ > + for (i = 0; i < 8; i++) > + result[i] = 0; memset(fexit_skel->bss, 0, sizeof(*fexit_skel->bss)) ? ;) and see my nits in previous patch about ASSERT over CHECK > + return 0; > +} > + > +void test_fexit_test(void) > +{ > + struct fexit_test *fexit_skel = NULL; > + int err; > + > + fexit_skel = fexit_test__open_and_load(); > + if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) > + goto cleanup; > + > + err = fexit_test(fexit_skel); > + if (CHECK(err, "fexit_test", "first attach failed\n")) > + goto cleanup; > + > + err = fexit_test(fexit_skel); > + CHECK(err, "fexit_test", "second attach failed\n"); > + > cleanup: > fexit_test__destroy(fexit_skel); > } > -- > 2.30.2 >
Re: [PATCHv2 bpf-next 2/5] selftests/bpf: Add re-attach test to fentry_test
On Wed, Apr 7, 2021 at 4:21 AM Jiri Olsa wrote: > > Adding the test to re-attach (detach/attach again) tracing > fentry programs, plus check that already linked program can't > be attached again. > > Fixing the number of check-ed results, which should be 8. > > Signed-off-by: Jiri Olsa > --- > .../selftests/bpf/prog_tests/fentry_test.c| 48 +++ > 1 file changed, 38 insertions(+), 10 deletions(-) > > diff --git a/tools/testing/selftests/bpf/prog_tests/fentry_test.c > b/tools/testing/selftests/bpf/prog_tests/fentry_test.c > index 04ebbf1cb390..1f7566e772e9 100644 > --- a/tools/testing/selftests/bpf/prog_tests/fentry_test.c > +++ b/tools/testing/selftests/bpf/prog_tests/fentry_test.c > @@ -3,20 +3,24 @@ > #include > #include "fentry_test.skel.h" > > -void test_fentry_test(void) > +static __u32 duration; > + > +static int fentry_test(struct fentry_test *fentry_skel) > { > - struct fentry_test *fentry_skel = NULL; > + struct bpf_link *link; > int err, prog_fd, i; > - __u32 duration = 0, retval; > __u64 *result; > - > - fentry_skel = fentry_test__open_and_load(); > - if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton > failed\n")) > - goto cleanup; > + __u32 retval; > > err = fentry_test__attach(fentry_skel); > if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) > - goto cleanup; > + return err; > + > + /* Check that already linked program can't be attached again. */ > + link = bpf_program__attach(fentry_skel->progs.test1); > + if (CHECK(!IS_ERR(link), "fentry_attach_link", if (!ASSERT_ERR_PTR(link, "fentry_attach_link")) ? > + "re-attach without detach should not succeed")) > + return -1; > > prog_fd = bpf_program__fd(fentry_skel->progs.test1); > err = bpf_prog_test_run(prog_fd, 1, NULL, 0, > @@ -26,12 +30,36 @@ void test_fentry_test(void) > err, errno, retval, duration); > > result = (__u64 *)fentry_skel->bss; > - for (i = 0; i < 6; i++) { > + for (i = 0; i < 8; i++) { how about using sizeof(*fentry_skel->bss) / sizeof(__u64) ? > if (CHECK(result[i] != 1, "result", > "fentry_test%d failed err %lld\n", i + 1, > result[i])) > - goto cleanup; > + return -1; > } > > + fentry_test__detach(fentry_skel); > + > + /* zero results for re-attach test */ > + for (i = 0; i < 8; i++) > + result[i] = 0; > + return 0; > +} > + > +void test_fentry_test(void) > +{ > + struct fentry_test *fentry_skel = NULL; > + int err; > + > + fentry_skel = fentry_test__open_and_load(); > + if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton > failed\n")) > + goto cleanup; > + > + err = fentry_test(fentry_skel); > + if (CHECK(err, "fentry_test", "first attach failed\n")) > + goto cleanup; > + > + err = fentry_test(fentry_skel); > + CHECK(err, "fentry_test", "second attach failed\n"); overall: please try to use ASSERT_xxx macros, they are easier to follow and require less typing > + > cleanup: > fentry_test__destroy(fentry_skel); > } > -- > 2.30.2 >
Re: [PATCH net-next 0/8] mptcp: Cleanup, a new test case, and header trimming
Hello: This series was applied to netdev/net-next.git (refs/heads/master): On Tue, 6 Apr 2021 17:15:56 -0700 you wrote: > Some more patches to include from the MPTCP tree: > > Patches 1-6 refactor an address-related data structure and reduce some > duplicate code that handles IPv4 and IPv6 addresses. > > Patch 7 adds a test case for the MPTCP netlink interface, passing a > specific ifindex to the kernel. > > [...] Here is the summary with links: - [net-next,1/8] mptcp: move flags and ifindex out of mptcp_addr_info https://git.kernel.org/netdev/net-next/c/daa83ab03954 - [net-next,2/8] mptcp: use mptcp_addr_info in mptcp_out_options https://git.kernel.org/netdev/net-next/c/30f60bae8092 - [net-next,3/8] mptcp: drop OPTION_MPTCP_ADD_ADDR6 https://git.kernel.org/netdev/net-next/c/fef6b7ecfbd4 - [net-next,4/8] mptcp: use mptcp_addr_info in mptcp_options_received https://git.kernel.org/netdev/net-next/c/f7dafee18538 - [net-next,5/8] mptcp: drop MPTCP_ADDR_IPVERSION_4/6 https://git.kernel.org/netdev/net-next/c/1b1a6ef597c7 - [net-next,6/8] mptcp: unify add_addr(6)_generate_hmac https://git.kernel.org/netdev/net-next/c/761c124ed969 - [net-next,7/8] selftests: mptcp: add the net device name testcase https://git.kernel.org/netdev/net-next/c/c3eaa5f667cb - [net-next,8/8] mptcp: drop all sub-options except ADD_ADDR when the echo bit is set https://git.kernel.org/netdev/net-next/c/07f8252fe0e3 You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html
[PATCH net-next 2/2] tc-testing: add simple action test to verify batch change cleanup
Verify cleanup of failed actions batch change where second action in batch fails after successful init of first action. Signed-off-by: Vlad Buslov --- .../tc-testing/tc-tests/actions/simple.json | 29 +++ 1 file changed, 29 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json index d5bcbb919dcc..e0c5f060ccb9 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json @@ -205,5 +205,34 @@ "teardown": [ "$TC actions flush action simple" ] +}, +{ +"id": "a68a", +"name": "Verify cleanup of failed actions batch change", +"category": [ +"actions", +"simple" +], +"setup": [ +[ +"$TC actions flush action simple", +0, +1, +255 +], +[ +"$TC actions change action simple sdata \"1\" index 1 action simple sdata \"2\" goto chain 42 index 2", +255 +], +"$TC actions flush action simple" +], +"cmdUnderTest": "$TC actions add action simple sdata \"1\" index 1", +"expExitCode": "0", +"verifyCmd": "$TC actions list action simple", +"matchPattern": "action order [0-9]*: Simple <1>.*index 1 ref", +"matchCount": "1", +"teardown": [ +"$TC actions flush action simple" +] } ] -- 2.29.2
[PATCH net-next 1/2] tc-testing: add simple action test to verify batch add cleanup
Verify cleanup of failed actions batch add where second action in batch fails after successful init of first action. Signed-off-by: Vlad Buslov --- .../tc-testing/tc-tests/actions/simple.json | 30 +++ 1 file changed, 30 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json index e15f708b0fa4..d5bcbb919dcc 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json @@ -175,5 +175,35 @@ "teardown": [ "$TC actions flush action simple" ] +}, +{ +"id": "8d07", +"name": "Verify cleanup of failed actions batch add", +"category": [ +"actions", +"simple" +], +"setup": [ +[ +"$TC actions flush action simple", +0, +1, +255 +], +"$TC actions add action simple sdata \"2\" index 2", +[ +"$TC actions add action simple sdata \"1\" index 1 action simple sdata \"2\" index 2", +255 +], +"$TC actions flush action simple" +], +"cmdUnderTest": "$TC actions add action simple sdata \"2\" index 2", +"expExitCode": "0", +"verifyCmd": "$TC actions list action simple", +"matchPattern": "action order [0-9]*: Simple <2>.*index 2 ref", +"matchCount": "1", +"teardown": [ +"$TC actions flush action simple" +] } ] -- 2.29.2
[PATCH net-next 0/8] mptcp: Cleanup, a new test case, and header trimming
Some more patches to include from the MPTCP tree: Patches 1-6 refactor an address-related data structure and reduce some duplicate code that handles IPv4 and IPv6 addresses. Patch 7 adds a test case for the MPTCP netlink interface, passing a specific ifindex to the kernel. Patch 8 drops extra header options from IPv4 address echo packets, improving consistency and testability between IPv4 and IPv6. Davide Caratti (1): mptcp: drop all sub-options except ADD_ADDR when the echo bit is set Geliang Tang (7): mptcp: move flags and ifindex out of mptcp_addr_info mptcp: use mptcp_addr_info in mptcp_out_options mptcp: drop OPTION_MPTCP_ADD_ADDR6 mptcp: use mptcp_addr_info in mptcp_options_received mptcp: drop MPTCP_ADDR_IPVERSION_4/6 mptcp: unify add_addr(6)_generate_hmac selftests: mptcp: add the net device name testcase include/net/mptcp.h | 21 ++- net/mptcp/options.c | 175 ++ net/mptcp/pm_netlink.c| 41 ++-- net/mptcp/protocol.h | 38 +--- net/mptcp/subflow.c | 7 +- .../testing/selftests/net/mptcp/mptcp_join.sh | 8 + 6 files changed, 115 insertions(+), 175 deletions(-) base-commit: be107538c5296fb888938ec3a32da21bb1733655 -- 2.31.1
[PATCHv2 bpf-next 5/5] selftests/bpf: Test that module can't be unloaded with attached trampoline
Adding test to verify that once we attach module's trampoline, the module can't be unloaded. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/module_attach.c | 23 +++ 1 file changed, 23 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/module_attach.c b/tools/testing/selftests/bpf/prog_tests/module_attach.c index 5bc53d53d86e..d180b8c28287 100644 --- a/tools/testing/selftests/bpf/prog_tests/module_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/module_attach.c @@ -45,12 +45,18 @@ static int trigger_module_test_write(int write_sz) return 0; } +static int delete_module(const char *name, int flags) +{ + return syscall(__NR_delete_module, name, flags); +} + void test_module_attach(void) { const int READ_SZ = 456; const int WRITE_SZ = 457; struct test_module_attach* skel; struct test_module_attach__bss *bss; + struct bpf_link *link; int err; skel = test_module_attach__open(); @@ -84,6 +90,23 @@ void test_module_attach(void) ASSERT_EQ(bss->fexit_ret, -EIO, "fexit_tet"); ASSERT_EQ(bss->fmod_ret_read_sz, READ_SZ, "fmod_ret"); + test_module_attach__detach(skel); + + /* attach fentry/fexit and make sure it get's module reference */ + link = bpf_program__attach(skel->progs.handle_fentry); + if (CHECK(IS_ERR(link), "attach_fentry", "err: %ld\n", PTR_ERR(link))) + goto cleanup; + + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + bpf_link__destroy(link); + + link = bpf_program__attach(skel->progs.handle_fexit); + if (CHECK(IS_ERR(link), "attach_fexit", "err: %ld\n", PTR_ERR(link))) + goto cleanup; + + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + bpf_link__destroy(link); + cleanup: test_module_attach__destroy(skel); } -- 2.30.2
[PATCHv2 bpf-next 4/5] selftests/bpf: Add re-attach test to lsm test
Adding the test to re-attach (detach/attach again) lsm programs, plus check that already linked program can't be attached again. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/test_lsm.c | 48 +++ 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c index 2755e4f81499..d492e76e01cf 100644 --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c @@ -18,6 +18,8 @@ char *CMD_ARGS[] = {"true", NULL}; #define GET_PAGE_ADDR(ADDR, PAGE_SIZE) \ (char *)(((unsigned long) (ADDR + PAGE_SIZE)) & ~(PAGE_SIZE-1)) +static int duration = 0; + int stack_mprotect(void) { void *buf; @@ -51,23 +53,25 @@ int exec_cmd(int *monitored_pid) return -EINVAL; } -void test_test_lsm(void) +static int test_lsm(struct lsm *skel) { - struct lsm *skel = NULL; - int err, duration = 0; + struct bpf_link *link; int buf = 1234; - - skel = lsm__open_and_load(); - if (CHECK(!skel, "skel_load", "lsm skeleton failed\n")) - goto close_prog; + int err; err = lsm__attach(skel); if (CHECK(err, "attach", "lsm attach failed: %d\n", err)) - goto close_prog; + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(skel->progs.test_int_hook); + if (CHECK(!IS_ERR(link), "attach_link", + "re-attach without detach should not succeed")) + return -1; err = exec_cmd(&skel->bss->monitored_pid); if (CHECK(err < 0, "exec_cmd", "err %d errno %d\n", err, errno)) - goto close_prog; + return err; CHECK(skel->bss->bprm_count != 1, "bprm_count", "bprm_count = %d\n", skel->bss->bprm_count); @@ -77,7 +81,7 @@ void test_test_lsm(void) err = stack_mprotect(); if (CHECK(errno != EPERM, "stack_mprotect", "want err=EPERM, got %d\n", errno)) - goto close_prog; + return err; CHECK(skel->bss->mprotect_count != 1, "mprotect_count", "mprotect_count = %d\n", skel->bss->mprotect_count); @@ -89,6 +93,30 @@ void test_test_lsm(void) CHECK(skel->bss->copy_test != 3, "copy_test", "copy_test = %d\n", skel->bss->copy_test); + lsm__detach(skel); + + skel->bss->copy_test = 0; + skel->bss->bprm_count = 0; + skel->bss->mprotect_count = 0; + return 0; +} + +void test_test_lsm(void) +{ + struct lsm *skel = NULL; + int err; + + skel = lsm__open_and_load(); + if (CHECK(!skel, "lsm_skel_load", "lsm skeleton failed\n")) + goto close_prog; + + err = test_lsm(skel); + if (CHECK(err, "test_lsm", "first attach failed\n")) + goto close_prog; + + err = test_lsm(skel); + CHECK(err, "test_lsm", "second attach failed\n"); + close_prog: lsm__destroy(skel); } -- 2.30.2
[PATCHv2 bpf-next 3/5] selftests/bpf: Add re-attach test to fexit_test
Adding the test to re-attach (detach/attach again) tracing fexit programs, plus check that already linked program can't be attached again. Fixing the number of check-ed results, which should be 8. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fexit_test.c | 48 +++ 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_test.c b/tools/testing/selftests/bpf/prog_tests/fexit_test.c index 78d7a2765c27..579e620e6612 100644 --- a/tools/testing/selftests/bpf/prog_tests/fexit_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fexit_test.c @@ -3,20 +3,24 @@ #include #include "fexit_test.skel.h" -void test_fexit_test(void) +static __u32 duration; + +static int fexit_test(struct fexit_test *fexit_skel) { - struct fexit_test *fexit_skel = NULL; + struct bpf_link *link; int err, prog_fd, i; - __u32 duration = 0, retval; __u64 *result; - - fexit_skel = fexit_test__open_and_load(); - if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) - goto cleanup; + __u32 retval; err = fexit_test__attach(fexit_skel); if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) - goto cleanup; + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(fexit_skel->progs.test1); + if (CHECK(!IS_ERR(link), "fexit_attach_link", + "re-attach without detach should not succeed")) + return -1; prog_fd = bpf_program__fd(fexit_skel->progs.test1); err = bpf_prog_test_run(prog_fd, 1, NULL, 0, @@ -26,12 +30,36 @@ void test_fexit_test(void) err, errno, retval, duration); result = (__u64 *)fexit_skel->bss; - for (i = 0; i < 6; i++) { + for (i = 0; i < 8; i++) { if (CHECK(result[i] != 1, "result", "fexit_test%d failed err %lld\n", i + 1, result[i])) - goto cleanup; + return -1; } + fexit_test__detach(fexit_skel); + + /* zero results for re-attach test */ + for (i = 0; i < 8; i++) + result[i] = 0; + return 0; +} + +void test_fexit_test(void) +{ + struct fexit_test *fexit_skel = NULL; + int err; + + fexit_skel = fexit_test__open_and_load(); + if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) + goto cleanup; + + err = fexit_test(fexit_skel); + if (CHECK(err, "fexit_test", "first attach failed\n")) + goto cleanup; + + err = fexit_test(fexit_skel); + CHECK(err, "fexit_test", "second attach failed\n"); + cleanup: fexit_test__destroy(fexit_skel); } -- 2.30.2
[PATCHv2 bpf-next 2/5] selftests/bpf: Add re-attach test to fentry_test
Adding the test to re-attach (detach/attach again) tracing fentry programs, plus check that already linked program can't be attached again. Fixing the number of check-ed results, which should be 8. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fentry_test.c| 48 +++ 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fentry_test.c b/tools/testing/selftests/bpf/prog_tests/fentry_test.c index 04ebbf1cb390..1f7566e772e9 100644 --- a/tools/testing/selftests/bpf/prog_tests/fentry_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fentry_test.c @@ -3,20 +3,24 @@ #include #include "fentry_test.skel.h" -void test_fentry_test(void) +static __u32 duration; + +static int fentry_test(struct fentry_test *fentry_skel) { - struct fentry_test *fentry_skel = NULL; + struct bpf_link *link; int err, prog_fd, i; - __u32 duration = 0, retval; __u64 *result; - - fentry_skel = fentry_test__open_and_load(); - if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n")) - goto cleanup; + __u32 retval; err = fentry_test__attach(fentry_skel); if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) - goto cleanup; + return err; + + /* Check that already linked program can't be attached again. */ + link = bpf_program__attach(fentry_skel->progs.test1); + if (CHECK(!IS_ERR(link), "fentry_attach_link", + "re-attach without detach should not succeed")) + return -1; prog_fd = bpf_program__fd(fentry_skel->progs.test1); err = bpf_prog_test_run(prog_fd, 1, NULL, 0, @@ -26,12 +30,36 @@ void test_fentry_test(void) err, errno, retval, duration); result = (__u64 *)fentry_skel->bss; - for (i = 0; i < 6; i++) { + for (i = 0; i < 8; i++) { if (CHECK(result[i] != 1, "result", "fentry_test%d failed err %lld\n", i + 1, result[i])) - goto cleanup; + return -1; } + fentry_test__detach(fentry_skel); + + /* zero results for re-attach test */ + for (i = 0; i < 8; i++) + result[i] = 0; + return 0; +} + +void test_fentry_test(void) +{ + struct fentry_test *fentry_skel = NULL; + int err; + + fentry_skel = fentry_test__open_and_load(); + if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n")) + goto cleanup; + + err = fentry_test(fentry_skel); + if (CHECK(err, "fentry_test", "first attach failed\n")) + goto cleanup; + + err = fentry_test(fentry_skel); + CHECK(err, "fentry_test", "second attach failed\n"); + cleanup: fentry_test__destroy(fentry_skel); } -- 2.30.2
[PATCHv4 bpf-next 4/4] selftests/bpf: add xdp_redirect_multi test
Add a bpf selftest for new helper xdp_redirect_map_multi(). In this test there are 3 forward groups and 1 exclude group. The test will redirect each interface's packets to all the interfaces in the forward group, and exclude the interface in exclude map. Two maps (DEVMAP, DEVMAP_HASH) and two xdp modes (generic, drive) will be tested. XDP egress program will also be tested by setting pkt src MAC to egress interface's MAC address. For more test details, you can find it in the test script. Here is the test result. ]# ./test_xdp_redirect_multi.sh Pass: xdpgeneric arp ns1-2 Pass: xdpgeneric arp ns1-3 Pass: xdpgeneric arp ns1-4 Pass: xdpgeneric ping ns1-2 Pass: xdpgeneric ping ns1-3 Pass: xdpgeneric ping ns1-4 Pass: xdpgeneric ping6 ns1-2 Pass: xdpgeneric ping6 ns1-1 number Pass: xdpgeneric ping6 ns1-2 number Pass: xdpdrv arp ns1-2 Pass: xdpdrv arp ns1-3 Pass: xdpdrv arp ns1-4 Pass: xdpdrv ping ns1-2 Pass: xdpdrv ping ns1-3 Pass: xdpdrv ping ns1-4 Pass: xdpdrv ping6 ns1-2 Pass: xdpdrv ping6 ns1-1 number Pass: xdpdrv ping6 ns1-2 number Pass: xdpegress mac ns1-2 Pass: xdpegress mac ns1-3 Pass: xdpegress mac ns1-4 Summary: PASS 21, FAIL 0 Signed-off-by: Hangbin Liu --- v4: add a IPv6 test to validates that single redirect still works after multicast redirect. v2-v3: no update --- tools/testing/selftests/bpf/Makefile | 3 +- .../bpf/progs/xdp_redirect_multi_kern.c | 99 .../selftests/bpf/test_xdp_redirect_multi.sh | 205 +++ .../selftests/bpf/xdp_redirect_multi.c| 236 ++ 4 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c create mode 100755 tools/testing/selftests/bpf/test_xdp_redirect_multi.sh create mode 100644 tools/testing/selftests/bpf/xdp_redirect_multi.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 6448c626498f..0c08b662a64e 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -49,6 +49,7 @@ TEST_FILES = xsk_prereqs.sh \ # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ test_xdp_redirect.sh \ + test_xdp_redirect_multi.sh \ test_xdp_meta.sh \ test_xdp_veth.sh \ test_offload.py \ @@ -79,7 +80,7 @@ TEST_PROGS_EXTENDED := with_addr.sh \ TEST_GEN_PROGS_EXTENDED = test_sock_addr test_skb_cgroup_id_user \ flow_dissector_load test_flow_dissector test_tcp_check_syncookie_user \ test_lirc_mode2_user xdping test_cpp runqslower bench bpf_testmod.ko \ - xdpxceiver + xdpxceiver xdp_redirect_multi TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read diff --git a/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c b/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c new file mode 100644 index ..099bf444acab --- /dev/null +++ b/tools/testing/selftests/bpf/progs/xdp_redirect_multi_kern.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* It would be easier to use a key:if_index, value:if_index map, but it + * will need a very large entries as the if_index number may get very large, + * this would affect the performace. So the DEVMAP here is just for testing. + */ +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 1024); +} map_v4 SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 128); +} map_all SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 128); +} map_egress SEC(".maps"); + +/* map to store egress interfaces mac addresses */ +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u32); + __type(value, __be64); + __uint(max_entries, 128); +} mac_map SEC(".maps"); + +SEC("xdp_redirect_map_multi") +int xdp_redirect_map_multi_prog(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + int if_index = ctx->ingress_ifindex; + struct ethhdr *eth = data; + __u16 h_proto; + __u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + h_proto = eth->h_proto; + + if (h_proto == bpf_htons(ETH_P_IP)) + return bpf_redirect_map(&map_v4, 0, BPF_F_REDIR_MASK); + else if (h_proto == bpf_htons(ETH_P_IPV6)) + return bpf_re
[PATCHv4 bpf-next 3/4] sample/bpf: add xdp_redirect_map_multi for redirect_map broadcast test
This is a sample for xdp redirect broadcast. In the sample we could forward all packets between given interfaces. There is also an option -X that could enable 2nd xdp_prog on egress interface. Signed-off-by: Hangbin Liu --- samples/bpf/Makefile | 3 + samples/bpf/xdp_redirect_map_multi_kern.c | 87 +++ samples/bpf/xdp_redirect_map_multi_user.c | 302 ++ 3 files changed, 392 insertions(+) create mode 100644 samples/bpf/xdp_redirect_map_multi_kern.c create mode 100644 samples/bpf/xdp_redirect_map_multi_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 45ceca4e2c70..520434ea966f 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -41,6 +41,7 @@ tprogs-y += test_map_in_map tprogs-y += per_socket_stats_example tprogs-y += xdp_redirect tprogs-y += xdp_redirect_map +tprogs-y += xdp_redirect_map_multi tprogs-y += xdp_redirect_cpu tprogs-y += xdp_monitor tprogs-y += xdp_rxq_info @@ -99,6 +100,7 @@ test_map_in_map-objs := test_map_in_map_user.o per_socket_stats_example-objs := cookie_uid_helper_example.o xdp_redirect-objs := xdp_redirect_user.o xdp_redirect_map-objs := xdp_redirect_map_user.o +xdp_redirect_map_multi-objs := xdp_redirect_map_multi_user.o xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o xdp_monitor-objs := xdp_monitor_user.o xdp_rxq_info-objs := xdp_rxq_info_user.o @@ -160,6 +162,7 @@ always-y += tcp_tos_reflect_kern.o always-y += tcp_dumpstats_kern.o always-y += xdp_redirect_kern.o always-y += xdp_redirect_map_kern.o +always-y += xdp_redirect_map_multi_kern.o always-y += xdp_redirect_cpu_kern.o always-y += xdp_monitor_kern.o always-y += xdp_rxq_info_kern.o diff --git a/samples/bpf/xdp_redirect_map_multi_kern.c b/samples/bpf/xdp_redirect_map_multi_kern.c new file mode 100644 index ..e6be70225ee1 --- /dev/null +++ b/samples/bpf/xdp_redirect_map_multi_kern.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 +#define KBUILD_MODNAME "foo" +#include +#include +#include +#include +#include +#include + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); + __uint(max_entries, 32); +} forward_map_general SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_DEVMAP_HASH); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(struct bpf_devmap_val)); + __uint(max_entries, 32); +} forward_map_native SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __type(key, u32); + __type(value, long); + __uint(max_entries, 1); +} rxcnt SEC(".maps"); + +/* map to store egress interfaces mac addresses, set the + * max_entries to 1 and extend it in user sapce prog. + */ +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, u32); + __type(value, __be64); + __uint(max_entries, 1); +} mac_map SEC(".maps"); + +static int xdp_redirect_map(struct xdp_md *ctx, void *forward_map) +{ + long *value; + u32 key = 0; + + /* count packet in global counter */ + value = bpf_map_lookup_elem(&rxcnt, &key); + if (value) + *value += 1; + + return bpf_redirect_map(forward_map, key, BPF_F_REDIR_MASK); +} + +SEC("xdp_redirect_general") +int xdp_redirect_map_general(struct xdp_md *ctx) +{ + return xdp_redirect_map(ctx, &forward_map_general); +} + +SEC("xdp_redirect_native") +int xdp_redirect_map_native(struct xdp_md *ctx) +{ + return xdp_redirect_map(ctx, &forward_map_native); +} + +SEC("xdp_devmap/map_prog") +int xdp_devmap_prog(struct xdp_md *ctx) +{ + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + u32 key = ctx->egress_ifindex; + struct ethhdr *eth = data; + __be64 *mac; + u64 nh_off; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + mac = bpf_map_lookup_elem(&mac_map, &key); + if (mac) + __builtin_memcpy(eth->h_source, mac, ETH_ALEN); + + return XDP_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/samples/bpf/xdp_redirect_map_multi_user.c b/samples/bpf/xdp_redirect_map_multi_user.c new file mode 100644 index ..84cdbbed20b7 --- /dev/null +++ b/samples/bpf/xdp_redirect_map_multi_user.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bpf_util.h" +#include +#include + +#define MAX_IFACE_NUM 32 + +static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; +static int ifaces[MAX_IFACE_NUM] = {}; +static int rxcnt_map_fd; + +static void int_exit(int sig) +{ + __u32 prog_id = 0; + int i; + + for (i = 0; ifaces[i] > 0; i++) { + if (bpf_get_link_xdp_id(ifaces[i], &p
[PATCH RFC 3/4] tc-testing: add simple action test to verify batch add cleanup
Verify cleanup of failed actions batch add where second action in batch fails after successful init of first action. Signed-off-by: Vlad Buslov --- .../tc-testing/tc-tests/actions/simple.json | 30 +++ 1 file changed, 30 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json index e15f708b0fa4..d5bcbb919dcc 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json @@ -175,5 +175,35 @@ "teardown": [ "$TC actions flush action simple" ] +}, +{ +"id": "8d07", +"name": "Verify cleanup of failed actions batch add", +"category": [ +"actions", +"simple" +], +"setup": [ +[ +"$TC actions flush action simple", +0, +1, +255 +], +"$TC actions add action simple sdata \"2\" index 2", +[ +"$TC actions add action simple sdata \"1\" index 1 action simple sdata \"2\" index 2", +255 +], +"$TC actions flush action simple" +], +"cmdUnderTest": "$TC actions add action simple sdata \"2\" index 2", +"expExitCode": "0", +"verifyCmd": "$TC actions list action simple", +"matchPattern": "action order [0-9]*: Simple <2>.*index 2 ref", +"matchCount": "1", +"teardown": [ +"$TC actions flush action simple" +] } ] -- 2.29.2
[PATCH RFC 4/4] tc-testing: add simple action test to verify batch change cleanup
Verify cleanup of failed actions batch change where second action in batch fails after successful init of first action. Signed-off-by: Vlad Buslov --- .../tc-testing/tc-tests/actions/simple.json | 29 +++ 1 file changed, 29 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json index d5bcbb919dcc..e0c5f060ccb9 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json @@ -205,5 +205,34 @@ "teardown": [ "$TC actions flush action simple" ] +}, +{ +"id": "a68a", +"name": "Verify cleanup of failed actions batch change", +"category": [ +"actions", +"simple" +], +"setup": [ +[ +"$TC actions flush action simple", +0, +1, +255 +], +[ +"$TC actions change action simple sdata \"1\" index 1 action simple sdata \"2\" goto chain 42 index 2", +255 +], +"$TC actions flush action simple" +], +"cmdUnderTest": "$TC actions add action simple sdata \"1\" index 1", +"expExitCode": "0", +"verifyCmd": "$TC actions list action simple", +"matchPattern": "action order [0-9]*: Simple <1>.*index 1 ref", +"matchCount": "1", +"teardown": [ +"$TC actions flush action simple" +] } ] -- 2.29.2
[Patch bpf-next v8 16/16] selftests/bpf: add a test case for loading BPF_SK_SKB_VERDICT
From: Cong Wang This adds a test case to ensure BPF_SK_SKB_VERDICT and BPF_SK_STREAM_VERDICT will never be attached at the same time. Cc: John Fastabend Cc: Daniel Borkmann Cc: Jakub Sitnicki Cc: Lorenz Bauer Signed-off-by: Cong Wang --- .../selftests/bpf/prog_tests/sockmap_basic.c | 40 +++ .../progs/test_sockmap_skb_verdict_attach.c | 18 + 2 files changed, 58 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/test_sockmap_skb_verdict_attach.c diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c index b8b48cac2ac3..ab77596b64e3 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c @@ -7,6 +7,7 @@ #include "test_skmsg_load_helpers.skel.h" #include "test_sockmap_update.skel.h" #include "test_sockmap_invalid_update.skel.h" +#include "test_sockmap_skb_verdict_attach.skel.h" #include "bpf_iter_sockmap.skel.h" #define TCP_REPAIR 19 /* TCP sock is under repair right now */ @@ -281,6 +282,39 @@ static void test_sockmap_copy(enum bpf_map_type map_type) bpf_iter_sockmap__destroy(skel); } +static void test_sockmap_skb_verdict_attach(enum bpf_attach_type first, + enum bpf_attach_type second) +{ + struct test_sockmap_skb_verdict_attach *skel; + int err, map, verdict; + + skel = test_sockmap_skb_verdict_attach__open_and_load(); + if (CHECK_FAIL(!skel)) { + perror("test_sockmap_skb_verdict_attach__open_and_load"); + return; + } + + verdict = bpf_program__fd(skel->progs.prog_skb_verdict); + map = bpf_map__fd(skel->maps.sock_map); + + err = bpf_prog_attach(verdict, map, first, 0); + if (CHECK_FAIL(err)) { + perror("bpf_prog_attach"); + goto out; + } + + err = bpf_prog_attach(verdict, map, second, 0); + assert(err == -1 && errno == EBUSY); + + err = bpf_prog_detach2(verdict, map, first); + if (CHECK_FAIL(err)) { + perror("bpf_prog_detach2"); + goto out; + } +out: + test_sockmap_skb_verdict_attach__destroy(skel); +} + void test_sockmap_basic(void) { if (test__start_subtest("sockmap create_update_free")) @@ -301,4 +335,10 @@ void test_sockmap_basic(void) test_sockmap_copy(BPF_MAP_TYPE_SOCKMAP); if (test__start_subtest("sockhash copy")) test_sockmap_copy(BPF_MAP_TYPE_SOCKHASH); + if (test__start_subtest("sockmap skb_verdict attach")) { + test_sockmap_skb_verdict_attach(BPF_SK_SKB_VERDICT, + BPF_SK_SKB_STREAM_VERDICT); + test_sockmap_skb_verdict_attach(BPF_SK_SKB_STREAM_VERDICT, + BPF_SK_SKB_VERDICT); + } } diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_skb_verdict_attach.c b/tools/testing/selftests/bpf/progs/test_sockmap_skb_verdict_attach.c new file mode 100644 index ..2d31f66e4f23 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_sockmap_skb_verdict_attach.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "vmlinux.h" +#include + +struct { + __uint(type, BPF_MAP_TYPE_SOCKMAP); + __uint(max_entries, 2); + __type(key, __u32); + __type(value, __u64); +} sock_map SEC(".maps"); + +SEC("sk_skb/skb_verdict") +int prog_skb_verdict(struct __sk_buff *skb) +{ + return SK_DROP; +} + +char _license[] SEC("license") = "GPL"; -- 2.25.1
[Patch bpf-next v8 15/16] selftests/bpf: add a test case for udp sockmap
From: Cong Wang Add a test case to ensure redirection between two UDP sockets work. Cc: John Fastabend Cc: Daniel Borkmann Cc: Jakub Sitnicki Cc: Lorenz Bauer Signed-off-by: Cong Wang --- .../selftests/bpf/prog_tests/sockmap_listen.c | 136 ++ .../selftests/bpf/progs/test_sockmap_listen.c | 22 +++ 2 files changed, 158 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c index c26e6bf05e49..648d9ae898d2 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c @@ -1603,6 +1603,141 @@ static void test_reuseport(struct test_sockmap_listen *skel, } } +static void udp_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); + struct sockaddr_storage addr; + int c0, c1, p0, p1; + unsigned int pass; + socklen_t len; + int err, n; + u64 value; + u32 key; + char b; + + zero_verdict_count(verd_mapfd); + + p0 = socket_loopback(family, sotype | SOCK_NONBLOCK); + if (p0 < 0) + return; + len = sizeof(addr); + err = xgetsockname(p0, sockaddr(&addr), &len); + if (err) + goto close_peer0; + + c0 = xsocket(family, sotype | SOCK_NONBLOCK, 0); + if (c0 < 0) + 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; + + p1 = socket_loopback(family, sotype | SOCK_NONBLOCK); + if (p1 < 0) + goto close_cli0; + err = xgetsockname(p1, sockaddr(&addr), &len); + if (err) + goto close_cli0; + + c1 = xsocket(family, sotype | SOCK_NONBLOCK, 0); + if (c1 < 0) + goto close_peer1; + err = xconnect(c1, sockaddr(&addr), len); + if (err) + goto close_cli1; + err = xgetsockname(c1, sockaddr(&addr), &len); + if (err) + goto close_cli1; + err = xconnect(p1, sockaddr(&addr), len); + if (err) + goto close_cli1; + + key = 0; + value = p0; + err = xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST); + if (err) + goto close_cli1; + + key = 1; + value = p1; + err = xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST); + if (err) + goto close_cli1; + + n = write(c1, "a", 1); + if (n < 0) + FAIL_ERRNO("%s: write", log_prefix); + if (n == 0) + FAIL("%s: incomplete write", log_prefix); + if (n < 1) + goto close_cli1; + + key = SK_PASS; + err = xbpf_map_lookup_elem(verd_mapfd, &key, &pass); + if (err) + goto close_cli1; + if (pass != 1) + FAIL("%s: want pass count 1, have %d", log_prefix, pass); + + n = read(mode == REDIR_INGRESS ? p0 : c0, &b, 1); + if (n < 0) + FAIL_ERRNO("%s: read", log_prefix); + if (n == 0) + FAIL("%s: incomplete read", log_prefix); + +close_cli1: + xclose(c1); +close_peer1: + xclose(p1); +close_cli0: + xclose(c0); +close_peer0: + xclose(p0); +} + +static void udp_skb_redir_to_connected(struct test_sockmap_listen *skel, + struct bpf_map *inner_map, int family) +{ + int verdict = bpf_program__fd(skel->progs.prog_skb_verdict); + int verdict_map = bpf_map__fd(skel->maps.verdict_map); + int sock_map = bpf_map__fd(inner_map); + int err; + + err = xbpf_prog_attach(verdict, sock_map, BPF_SK_SKB_VERDICT, 0); + if (err) + return; + + skel->bss->test_ingress = false; + udp_redir_to_connected(family, SOCK_DGRAM, sock_map, verdict_map, + REDIR_EGRESS); + skel->bss->test_ingress = true; + udp_redir_to_connected(family, SOCK_DGRAM, sock_map, verdict_map, + REDIR_INGRESS); + + xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT); +} + +static void test_udp_redir(struct test_sockmap_listen *skel, struct bpf_map *map, + int family) +{ + const char *family_name, *map_name; + char s[MAX_TEST_NAME]; + + family_name = family_str(family); + map_name = map_type_str(map); + snprintf(s, sizeof(s), &quo
Re: [PATCH net-next] tc-testing: add simple action change test
Hello: This patch was applied to netdev/net-next.git (refs/heads/master): On Tue, 30 Mar 2021 13:41:10 +0300 you wrote: > Use act_simple to verify that action created with 'tc actions change' > command exists after command returns. The goal is to verify internal action > API reference counting to ensure that the case when netlink message has > NLM_F_REPLACE flag set but action with specified index doesn't exist is > handled correctly. > > Signed-off-by: Vlad Buslov > > [...] Here is the summary with links: - [net-next] tc-testing: add simple action change test https://git.kernel.org/netdev/net-next/c/e48792a9ec78 You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html
Re: [RFC PATCH bpf-next 2/4] selftests/bpf: Add re-attach test to fentry_test
On Tue, Mar 30, 2021 at 01:23:15AM +, Song Liu wrote: > > > > On Mar 28, 2021, at 4:26 AM, Jiri Olsa wrote: > > > > Adding the test to re-attach (detach/attach again) tracing > > fentry programs, plus check that already linked program can't > > be attached again. > > > > Fixing the number of check-ed results, which should be 8. > > > > Signed-off-by: Jiri Olsa > > > [...] > > + > > +void test_fentry_test(void) > > +{ > > + struct fentry_test *fentry_skel = NULL; > > + struct bpf_link *link; > > + int err; > > + > > + fentry_skel = fentry_test__open_and_load(); > > + if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n")) > > + goto cleanup; > > + > > + err = fentry_test__attach(fentry_skel); > > + if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) > > + goto cleanup; > > + > > + err = fentry_test(fentry_skel); > > + if (CHECK(err, "fentry_test", "fentry test failed: %d\n", err)) > > + goto cleanup; > > + > > + fentry_test__detach(fentry_skel); > > + > > + /* Re-attach and test again */ > > + err = fentry_test__attach(fentry_skel); > > + if (CHECK(err, "fentry_attach", "fentry re-attach failed: %d\n", err)) > > + goto cleanup; > > + > > + link = bpf_program__attach(fentry_skel->progs.test1); > > + if (CHECK(!IS_ERR(link), "attach_fentry re-attach without detach", > > + "err: %ld\n", PTR_ERR(link))) > > nit: I guess we shouldn't print PTR_ERR(link) when link is not an error code? > This shouldn't break though. true, makes no sense.. I'll remove it thanks, jirka
Re: ❌ FAIL: Test report for kernel 5.10.0-rc6 (mainline.kernel.org)
On 12/10/20 9:35 AM, Vlad Buslov wrote: > On Thu 10 Dec 2020 at 00:22, Jakub Kicinski wrote: >> On Wed, 9 Dec 2020 22:54:40 +0200 Vlad Buslov wrote: Yes, I think the patch I sent should fix this, ETH_P_ARP should not be dropped ;) I am testing this before offical patch submission. >>> >>> Your patch fixed TC geneve tests for me, but some of more complex OVS >>> tests are still failing. I'll try to provide details tomorrow. >> >> Does a revert of Eric's patch fix it? For OvS is could also well be: >> 9c2e14b48119 ("ip_tunnels: Set tunnel option flag when tunnel metadata is >> present") > > The tests pass with Eric's commit reverted. > I will release today the syzbot report, I am lacking time to fix the issue.
[PATCH net-next] tc-testing: add simple action change test
Use act_simple to verify that action created with 'tc actions change' command exists after command returns. The goal is to verify internal action API reference counting to ensure that the case when netlink message has NLM_F_REPLACE flag set but action with specified index doesn't exist is handled correctly. Signed-off-by: Vlad Buslov --- .../tc-testing/tc-tests/actions/simple.json | 24 +++ 1 file changed, 24 insertions(+) diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json index 8e8c1ae12260..e15f708b0fa4 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/simple.json @@ -23,6 +23,30 @@ "$TC actions flush action simple" ] }, +{ +"id": "4297", +"name": "Add simple action with change command", +"category": [ +"actions", +"simple" +], +"setup": [ +[ +"$TC actions flush action simple", +0, +1, +255 +] +], +"cmdUnderTest": "$TC actions change action simple sdata \"Not changed\" index 60", +"expExitCode": "0", +"verifyCmd": "$TC actions list action simple", +"matchPattern": "action order [0-9]*: Simple .*index 60 ref", +"matchCount": "1", +"teardown": [ +"$TC actions flush action simple" +] +}, { "id": "6d4c", "name": "Add simple action with duplicate index", -- 2.29.2
Re: [RFC PATCH bpf-next 4/4] selftests/bpf: Test that module can't be unloaded with attached trampoline
> On Mar 28, 2021, at 4:26 AM, Jiri Olsa wrote: > > Adding test to verify that once we attach module's trampoline, > the module can't be unloaded. > > Signed-off-by: Jiri Olsa Acked-by: Song Liu [...]
[PATCH net-next 3/3] selftests: ethtool: add a netdevsim FEC test
Test FEC settings, iterate over configs. Signed-off-by: Jakub Kicinski --- .../drivers/net/netdevsim/ethtool-common.sh | 5 +- .../drivers/net/netdevsim/ethtool-fec.sh | 110 ++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100755 tools/testing/selftests/drivers/net/netdevsim/ethtool-fec.sh diff --git a/tools/testing/selftests/drivers/net/netdevsim/ethtool-common.sh b/tools/testing/selftests/drivers/net/netdevsim/ethtool-common.sh index 9f64d5c7107b..7ca1f030d209 100644 --- a/tools/testing/selftests/drivers/net/netdevsim/ethtool-common.sh +++ b/tools/testing/selftests/drivers/net/netdevsim/ethtool-common.sh @@ -24,8 +24,11 @@ function check { local code=$1 local str=$2 local exp_str=$3 +local exp_fail=$4 -if [ $code -ne 0 ]; then +[ -z "$exp_fail" ] && cop="-ne" || cop="-eq" + +if [ $code $cop 0 ]; then ((num_errors++)) return fi diff --git a/tools/testing/selftests/drivers/net/netdevsim/ethtool-fec.sh b/tools/testing/selftests/drivers/net/netdevsim/ethtool-fec.sh new file mode 100755 index ..0c56746e9ce0 --- /dev/null +++ b/tools/testing/selftests/drivers/net/netdevsim/ethtool-fec.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-only + +source ethtool-common.sh + +NSIM_NETDEV=$(make_netdev) +[ a$ETHTOOL == a ] && ETHTOOL=ethtool + +set -o pipefail + +# netdevsim starts out with None/None +s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2) +check $? "$s" "Configured FEC encodings: None +Active FEC encoding: None" + +# Test Auto +$ETHTOOL --set-fec $NSIM_NETDEV encoding auto +check $? +s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2) +check $? "$s" "Configured FEC encodings: Auto +Active FEC encoding: Off" + +# Test case in-sensitivity +for o in off Off OFF; do +$ETHTOOL --set-fec $NSIM_NETDEV encoding $o +check $? +s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2) +check $? "$s" "Configured FEC encodings: Off +Active FEC encoding: Off" +done + +for o in BaseR baser BAser; do +$ETHTOOL --set-fec $NSIM_NETDEV encoding $o +check $? +s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2) +check $? "$s" "Configured FEC encodings: BaseR +Active FEC encoding: BaseR" +done + +for o in llrs rs; do +$ETHTOOL --set-fec $NSIM_NETDEV encoding $o +check $? +s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2) +check $? "$s" "Configured FEC encodings: ${o^^} +Active FEC encoding: ${o^^}" +done + +# Test mutliple bits +$ETHTOOL --set-fec $NSIM_NETDEV encoding rs llrs +check $? +s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2) +check $? "$s" "Configured FEC encodings: RS LLRS +Active FEC encoding: LLRS" + +$ETHTOOL --set-fec $NSIM_NETDEV encoding rs off auto +check $? +s=$($ETHTOOL --show-fec $NSIM_NETDEV | tail -2) +check $? "$s" "Configured FEC encodings: Auto Off RS +Active FEC encoding: RS" + +# Make sure other link modes are rejected +$ETHTOOL --set-fec $NSIM_NETDEV encoding FIBRE 2>/dev/null +check $? '' '' 1 + +$ETHTOOL --set-fec $NSIM_NETDEV encoding bla-bla-bla 2>/dev/null +check $? '' '' 1 + +# Try JSON +$ETHTOOL --json --show-fec $NSIM_NETDEV | jq empty >>/dev/null 2>&1 +if [ $? -eq 0 ]; then +$ETHTOOL --set-fec $NSIM_NETDEV encoding auto +check $? + +s=$($ETHTOOL --json --show-fec $NSIM_NETDEV | jq '.[].config[]') +check $? "$s" '"Auto"' +s=$($ETHTOOL --json --show-fec $NSIM_NETDEV | jq '.[].active[]') +check $? "$s" '"Off"' + +$ETHTOOL --set-fec $NSIM_NETDEV encoding auto RS +check $? + +s=$($ETHTOOL --json --show-fec $NSIM_NETDEV | jq '.[].config[]') +check $? "$s" '"Auto" +"RS"' +s=$($ETHTOOL --json --show-fec $NSIM_NETDEV | jq '.[].active[]') +check $? "$s" '"RS"' +fi + +# Test error injection +echo 11 > $NSIM_DEV_DFS/ethtool/get_err + +$ETHTOOL --show-fec $NSIM_NETDEV >>/dev/null 2>&1 +check $? '' '' 1 + +echo 0 > $NSIM_DEV_DFS/ethtool/get_err +echo 11 > $NSIM_DEV_DFS/ethtool/set_err + +$ETHTOOL --show-fec $NSIM_NETDEV >>/dev/null 2>&1 +check $? + +$ETHTOOL --set-fec $NSIM_NETDEV encoding RS 2>/dev/null +check $? '' '' 1 + +if [ $num_errors -eq 0 ]; then +echo "PASSED all $((num_passes)) checks" +exit 0 +else +echo "FAILED $num_errors/$((num_errors+num_passes)) checks" +exit 1 +fi -- 2.30.2
Re: [RFC PATCH bpf-next 2/4] selftests/bpf: Add re-attach test to fentry_test
> On Mar 28, 2021, at 4:26 AM, Jiri Olsa wrote: > > Adding the test to re-attach (detach/attach again) tracing > fentry programs, plus check that already linked program can't > be attached again. > > Fixing the number of check-ed results, which should be 8. > > Signed-off-by: Jiri Olsa > [...] > + > +void test_fentry_test(void) > +{ > + struct fentry_test *fentry_skel = NULL; > + struct bpf_link *link; > + int err; > + > + fentry_skel = fentry_test__open_and_load(); > + if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n")) > + goto cleanup; > + > + err = fentry_test__attach(fentry_skel); > + if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) > + goto cleanup; > + > + err = fentry_test(fentry_skel); > + if (CHECK(err, "fentry_test", "fentry test failed: %d\n", err)) > + goto cleanup; > + > + fentry_test__detach(fentry_skel); > + > + /* Re-attach and test again */ > + err = fentry_test__attach(fentry_skel); > + if (CHECK(err, "fentry_attach", "fentry re-attach failed: %d\n", err)) > + goto cleanup; > + > + link = bpf_program__attach(fentry_skel->progs.test1); > + if (CHECK(!IS_ERR(link), "attach_fentry re-attach without detach", > + "err: %ld\n", PTR_ERR(link))) nit: I guess we shouldn't print PTR_ERR(link) when link is not an error code? This shouldn't break though. Thanks, Song > + goto cleanup; > + > + err = fentry_test(fentry_skel); > + CHECK(err, "fentry_test", "fentry test failed: %d\n", err); > + > cleanup: > fentry_test__destroy(fentry_skel); > } > -- > 2.30.2 >
[PATCH v5 bpf-next 14/17] selftests: xsk: implement bpf_link test
Introduce a test that is supposed to verify the persistence of BPF resources based on underlying bpf_link usage. Test will: 1) create and bind two sockets on queue ids 0 and 1 2) run a traffic on queue ids 0 3) remove xsk sockets from queue 0 on both veth interfaces 4) run a traffic on queues ids 1 Running traffic successfully on qids 1 means that BPF resources were not removed on step 3). In order to make it work, change the command that creates veth pair to have the 4 queue pairs by default. Introduce the arrays of xsks and umems to ifobject struct but keep a pointers to single entities, so rest of the logic around Rx/Tx can be kept as-is. For umem handling, double the size of mmapped space and split that between the two sockets. Rename also bidi_pass to a variable 'second_step' of a boolean type as it's now used also for the test that is introduced here and it doesn't have anything in common with bi-directional testing. Drop opt_queue command line argument as it wasn't working before anyway. Signed-off-by: Maciej Fijalkowski --- tools/testing/selftests/bpf/test_xsk.sh | 3 +- tools/testing/selftests/bpf/xdpxceiver.c | 179 +-- tools/testing/selftests/bpf/xdpxceiver.h | 7 +- 3 files changed, 139 insertions(+), 50 deletions(-) diff --git a/tools/testing/selftests/bpf/test_xsk.sh b/tools/testing/selftests/bpf/test_xsk.sh index 56d4474e2c83..46633a3bfb0b 100755 --- a/tools/testing/selftests/bpf/test_xsk.sh +++ b/tools/testing/selftests/bpf/test_xsk.sh @@ -107,7 +107,7 @@ setup_vethPairs() { echo "setting up ${VETH0}: namespace: ${NS0}" fi ip netns add ${NS1} - ip link add ${VETH0} type veth peer name ${VETH1} + ip link add ${VETH0} numtxqueues 4 numrxqueues 4 type veth peer name ${VETH1} numtxqueues 4 numrxqueues 4 if [ -f /proc/net/if_inet6 ]; then echo 1 > /proc/sys/net/ipv6/conf/${VETH0}/disable_ipv6 fi @@ -118,6 +118,7 @@ setup_vethPairs() { ip netns exec ${NS1} ip link set ${VETH1} mtu ${MTU} ip link set ${VETH0} mtu ${MTU} ip netns exec ${NS1} ip link set ${VETH1} up + ip netns exec ${NS1} ip link set dev lo up ip link set ${VETH0} up } diff --git a/tools/testing/selftests/bpf/xdpxceiver.c b/tools/testing/selftests/bpf/xdpxceiver.c index be7f4930dee9..b57c75d6904b 100644 --- a/tools/testing/selftests/bpf/xdpxceiver.c +++ b/tools/testing/selftests/bpf/xdpxceiver.c @@ -41,8 +41,12 @@ *Reduce the size of the RX ring to a fraction of the fill ring size. * iv. fill queue empty *Do not populate the fill queue and then try to receive pkts. + *f. bpf_link resource persistence + * Configure sockets at indexes 0 and 1, run a traffic on queue ids 0, + * then remove xsk sockets from queue 0 on both veth interfaces and + * finally run a traffic on queues ids 1 * - * Total tests: 10 + * Total tests: 12 * * Flow: * - @@ -115,11 +119,12 @@ static void __exit_with_error(int error, const char *file, const char *func, int #define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__) #define print_ksft_result(void)\ - (ksft_test_result_pass("PASS: %s %s %s%s%s\n", configured_mode ? "DRV" : "SKB",\ + (ksft_test_result_pass("PASS: %s %s %s%s%s%s\n", configured_mode ? "DRV" : "SKB",\ test_type == TEST_TYPE_POLL ? "POLL" : "NOPOLL",\ test_type == TEST_TYPE_TEARDOWN ? "Socket Teardown" : "",\ test_type == TEST_TYPE_BIDI ? "Bi-directional Sockets" : "",\ - test_type == TEST_TYPE_STATS ? "Stats" : "")) + test_type == TEST_TYPE_STATS ? "Stats" : "",\ + test_type == TEST_TYPE_BPF_RES ? "BPF RES" : "")) static void init_sync_resources(void) { @@ -258,9 +263,8 @@ static void gen_eth_frame(struct xsk_umem_info *umem, u64 addr) memcpy(xsk_umem__get_data(umem->buffer, addr), pkt_data, PKT_SIZE); } -static void xsk_configure_umem(struct ifobject *data, void *buffer, u64 size) +static void xsk_configure_umem(struct ifobject *data, void *buffer, int idx) { - int ret; struct xsk_umem_config cfg = { .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, @@ -268,17 +272,22 @@ static void xsk_configure_umem(struct ifobject *data, void *buffer, u64 size) .frame_headroom = frame_headroom, .flags = XSK_UMEM__DEFAULT_FLAGS }; + int size = num_frames * XSK_UMEM__DEFAULT_FRAME_SIZE; + struct xsk_umem_info *umem; + int r
[PATCH v5 bpf-next 11/17] selftests: xsk: refactor teardown/bidi test cases and testapp_validate
Currently, there is a testapp_sockets() that acts like a wrapper around testapp_validate() and it is called for bidi and teardown test types. Other test types call testapp_validate() directly. Split testapp_sockets() onto two separate functions so a bunch of bidi specific logic can be moved there and out of testapp_validate() itself. Introduce function pointer to ifobject struct which will be used for assigning the Rx/Tx function that is assigned to worker thread. Let's also have a global ifobject Rx/Tx pointers so it's easier to swap the vectors on a second run of a bi-directional test. Thread creation now is easey to follow. switching_notify variable is useless, info about vector switch can be printed based on bidi_pass state. Last but not least, init/destroy synchronization variables only once, not per each test. Signed-off-by: Maciej Fijalkowski --- tools/testing/selftests/bpf/xdpxceiver.c | 117 ++- tools/testing/selftests/bpf/xdpxceiver.h | 14 +-- 2 files changed, 78 insertions(+), 53 deletions(-) diff --git a/tools/testing/selftests/bpf/xdpxceiver.c b/tools/testing/selftests/bpf/xdpxceiver.c index 3db221e548cc..aeff5340be49 100644 --- a/tools/testing/selftests/bpf/xdpxceiver.c +++ b/tools/testing/selftests/bpf/xdpxceiver.c @@ -896,26 +896,10 @@ static void testapp_validate(void) pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, THREAD_STACK); - if ((test_type == TEST_TYPE_BIDI) && bidi_pass) { - pthread_init_mutex(); - if (!switching_notify) { - print_verbose("Switching Tx/Rx vectors\n"); - switching_notify++; - } - } - pthread_mutex_lock(&sync_mutex); /*Spawn RX thread */ - if (!bidi || !bidi_pass) { - if (pthread_create(&t0, &attr, worker_testapp_validate_rx, ifdict[1])) - exit_with_error(errno); - } else if (bidi && bidi_pass) { - /*switch Tx/Rx vectors */ - ifdict[0]->fv.vector = rx; - if (pthread_create(&t0, &attr, worker_testapp_validate_rx, ifdict[0])) - exit_with_error(errno); - } + pthread_create(&t0, &attr, ifdict_rx->func_ptr, ifdict_rx); if (clock_gettime(CLOCK_REALTIME, &max_wait)) exit_with_error(errno); @@ -927,15 +911,7 @@ static void testapp_validate(void) pthread_mutex_unlock(&sync_mutex); /*Spawn TX thread */ - if (!bidi || !bidi_pass) { - if (pthread_create(&t1, &attr, worker_testapp_validate_tx, ifdict[0])) - exit_with_error(errno); - } else if (bidi && bidi_pass) { - /*switch Tx/Rx vectors */ - ifdict[1]->fv.vector = tx; - if (pthread_create(&t1, &attr, worker_testapp_validate_tx, ifdict[1])) - exit_with_error(errno); - } + pthread_create(&t1, &attr, ifdict_tx->func_ptr, ifdict_tx); pthread_join(t1, NULL); pthread_join(t0, NULL); @@ -953,18 +929,53 @@ static void testapp_validate(void) print_ksft_result(); } -static void testapp_sockets(void) +static void testapp_teardown(void) +{ + int i; + + for (i = 0; i < MAX_TEARDOWN_ITER; i++) { + pkt_counter = 0; + prev_pkt = -1; + sigvar = 0; + print_verbose("Creating socket\n"); + testapp_validate(); + } + + print_ksft_result(); +} + +static void swap_vectors(struct ifobject *ifobj1, struct ifobject *ifobj2) +{ + void *(*tmp_func_ptr)(void *) = ifobj1->func_ptr; + enum fvector tmp_vector = ifobj1->fv.vector; + + ifobj1->func_ptr = ifobj2->func_ptr; + ifobj1->fv.vector = ifobj2->fv.vector; + + ifobj2->func_ptr = tmp_func_ptr; + ifobj2->fv.vector = tmp_vector; + + ifdict_tx = ifobj1; + ifdict_rx = ifobj2; +} + +static void testapp_bidi(void) { - for (int i = 0; i < ((test_type == TEST_TYPE_TEARDOWN) ? MAX_TEARDOWN_ITER : MAX_BIDI_ITER); -i++) { + for (int i = 0; i < MAX_BIDI_ITER; i++) { pkt_counter = 0; prev_pkt = -1; sigvar = 0; print_verbose("Creating socket\n"); testapp_validate(); - test_type == TEST_TYPE_BIDI ? bidi_pass++ : bidi_pass; + if (!bidi_pass) { + print_verbose("Switching Tx/Rx vectors\n"); + swap_vectors(ifdict[1], ifdict[0]); + } + bidi_pass++; } + swap_vectors(ifdict[0], ifdict[1]); + print_ksft_result(); } @@ -997,7 +1008,7 @@ static void testapp_stats(void) static
[PATCH v5 bpf-next 01/17] selftests: xsk: don't call worker_pkt_dump() for stats test
For TEST_TYPE_STATS, worker_pkt_validate() that places frames onto pkt_buf is not called. Therefore, when dump mode is set, don't call worker_pkt_dump() for mentioned test type, so that it won't crash on pkt_buf() access. Signed-off-by: Maciej Fijalkowski --- tools/testing/selftests/bpf/xdpxceiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/xdpxceiver.c b/tools/testing/selftests/bpf/xdpxceiver.c index 8b0f7fdd9003..04574c2b4f41 100644 --- a/tools/testing/selftests/bpf/xdpxceiver.c +++ b/tools/testing/selftests/bpf/xdpxceiver.c @@ -999,7 +999,7 @@ static void testapp_validate(void) pthread_join(t1, NULL); pthread_join(t0, NULL); - if (debug_pkt_dump) { + if (debug_pkt_dump && test_type != TEST_TYPE_STATS) { worker_pkt_dump(); for (int iter = 0; iter < num_frames - 1; iter++) { free(pkt_buf[iter]->payload); -- 2.20.1
[PATCH net-next 4/6] selftests: mlxsw: Test matchall failure with protocol match
From: Ido Schimmel The driver can only offload matchall rules that do not match on a protocol. Test that matchall rules that match on a protocol are vetoed. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko --- .../drivers/net/mlxsw/tc_restrictions.sh| 17 + 1 file changed, 17 insertions(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh index b4dbda706c4d..5ec3beb637c8 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh @@ -11,6 +11,7 @@ ALL_TESTS=" matchall_mirror_behind_flower_ingress_test matchall_sample_behind_flower_ingress_test matchall_mirror_behind_flower_egress_test + matchall_proto_match_test police_limits_test multi_police_test " @@ -291,6 +292,22 @@ matchall_mirror_behind_flower_egress_test() matchall_behind_flower_egress_test "mirror" "mirred egress mirror dev $swp2" } +matchall_proto_match_test() +{ + RET=0 + + tc qdisc add dev $swp1 clsact + + tc filter add dev $swp1 ingress pref 1 proto ip handle 101 \ + matchall skip_sw \ + action sample group 1 rate 100 + check_fail $? "Incorrect success to add matchall rule with protocol match" + + tc qdisc del dev $swp1 clsact + + log_test "matchall protocol match" +} + police_limits_test() { RET=0 -- 2.30.2
[PATCH net-next 6/6] selftests: mlxsw: Test vetoing of double sampling
From: Ido Schimmel Test that two sampling rules cannot be configured on the same port with the same trigger. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko --- .../selftests/drivers/net/mlxsw/tc_sample.sh | 30 +++ 1 file changed, 30 insertions(+) diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh index 57b05f042787..093bed088ad0 100755 --- a/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh +++ b/tools/testing/selftests/drivers/net/mlxsw/tc_sample.sh @@ -34,6 +34,7 @@ lib_dir=$(dirname $0)/../../../net/forwarding ALL_TESTS=" tc_sample_rate_test tc_sample_max_rate_test + tc_sample_conflict_test tc_sample_group_conflict_test tc_sample_md_iif_test tc_sample_md_lag_iif_test @@ -272,6 +273,35 @@ tc_sample_max_rate_test() log_test "tc sample maximum rate" } +tc_sample_conflict_test() +{ + RET=0 + + # Test that two sampling rules cannot be configured on the same port, + # even when they share the same parameters. + + tc filter add dev $rp1 ingress protocol all pref 1 handle 101 matchall \ + skip_sw action sample rate 1024 group 1 + check_err $? "Failed to configure sampling rule" + + tc filter add dev $rp1 ingress protocol all pref 2 handle 102 matchall \ + skip_sw action sample rate 1024 group 1 &> /dev/null + check_fail $? "Managed to configure second sampling rule" + + # Delete the first rule and make sure the second rule can now be + # configured. + + tc filter del dev $rp1 ingress protocol all pref 1 handle 101 matchall + + tc filter add dev $rp1 ingress protocol all pref 2 handle 102 matchall \ + skip_sw action sample rate 1024 group 1 + check_err $? "Failed to configure sampling rule after deletion" + + log_test "tc sample conflict test" + + tc filter del dev $rp1 ingress protocol all pref 2 handle 102 matchall +} + tc_sample_group_conflict_test() { RET=0 -- 2.30.2
Re: [PATCH net 2/2] selftests: forwarding: vxlan_bridge_1d: Add more ECN decap test cases
Ido Schimmel writes: > From: Ido Schimmel > > Test that all possible combinations of inner and outer ECN bits result > in the correct inner ECN marking according to RFC 6040 4.2. > > Signed-off-by: Ido Schimmel > Reviewed-by: Petr Machata Acked-by: Toke Høiland-Jørgensen
[PATCH net mlxsw v2 2/2] selftests: forwarding: vxlan_bridge_1d: Add more ECN decap test cases
From: Ido Schimmel Test that all possible combinations of inner and outer ECN bits result in the correct inner ECN marking according to RFC 6040 4.2. Signed-off-by: Ido Schimmel --- .../selftests/net/forwarding/vxlan_bridge_1d.sh | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh index 0ccb1dda099a..eb307ca37bfa 100755 --- a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh +++ b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh @@ -657,10 +657,21 @@ test_ecn_decap() { # In accordance with INET_ECN_decapsulate() __test_ecn_decap 00 00 0x00 + __test_ecn_decap 00 01 0x00 + __test_ecn_decap 00 02 0x00 + # 00 03 is tested in test_ecn_decap_error() + __test_ecn_decap 01 00 0x01 __test_ecn_decap 01 01 0x01 - __test_ecn_decap 02 01 0x01 + __test_ecn_decap 01 02 0x01 __test_ecn_decap 01 03 0x03 + __test_ecn_decap 02 00 0x02 + __test_ecn_decap 02 01 0x01 + __test_ecn_decap 02 02 0x02 __test_ecn_decap 02 03 0x03 + __test_ecn_decap 03 00 0x03 + __test_ecn_decap 03 01 0x03 + __test_ecn_decap 03 02 0x03 + __test_ecn_decap 03 03 0x03 test_ecn_decap_error } -- 2.30.2
[PATCH net 2/2] selftests: forwarding: vxlan_bridge_1d: Add more ECN decap test cases
From: Ido Schimmel Test that all possible combinations of inner and outer ECN bits result in the correct inner ECN marking according to RFC 6040 4.2. Signed-off-by: Ido Schimmel Reviewed-by: Petr Machata --- .../selftests/net/forwarding/vxlan_bridge_1d.sh | 13 - 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh index 0ccb1dda099a..eb307ca37bfa 100755 --- a/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh +++ b/tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh @@ -657,10 +657,21 @@ test_ecn_decap() { # In accordance with INET_ECN_decapsulate() __test_ecn_decap 00 00 0x00 + __test_ecn_decap 00 01 0x00 + __test_ecn_decap 00 02 0x00 + # 00 03 is tested in test_ecn_decap_error() + __test_ecn_decap 01 00 0x01 __test_ecn_decap 01 01 0x01 - __test_ecn_decap 02 01 0x01 + __test_ecn_decap 01 02 0x01 __test_ecn_decap 01 03 0x03 + __test_ecn_decap 02 00 0x02 + __test_ecn_decap 02 01 0x01 + __test_ecn_decap 02 02 0x02 __test_ecn_decap 02 03 0x03 + __test_ecn_decap 03 00 0x03 + __test_ecn_decap 03 01 0x03 + __test_ecn_decap 03 02 0x03 + __test_ecn_decap 03 03 0x03 test_ecn_decap_error } -- 2.30.2
[Patch bpf-next v7 13/13] selftests/bpf: add a test case for udp sockmap
From: Cong Wang Add a test case to ensure redirection between two UDP sockets work. Cc: John Fastabend Cc: Daniel Borkmann Cc: Jakub Sitnicki Cc: Lorenz Bauer Signed-off-by: Cong Wang --- .../selftests/bpf/prog_tests/sockmap_listen.c | 136 ++ .../selftests/bpf/progs/test_sockmap_listen.c | 22 +++ 2 files changed, 158 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c index c26e6bf05e49..648d9ae898d2 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_listen.c @@ -1603,6 +1603,141 @@ static void test_reuseport(struct test_sockmap_listen *skel, } } +static void udp_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); + struct sockaddr_storage addr; + int c0, c1, p0, p1; + unsigned int pass; + socklen_t len; + int err, n; + u64 value; + u32 key; + char b; + + zero_verdict_count(verd_mapfd); + + p0 = socket_loopback(family, sotype | SOCK_NONBLOCK); + if (p0 < 0) + return; + len = sizeof(addr); + err = xgetsockname(p0, sockaddr(&addr), &len); + if (err) + goto close_peer0; + + c0 = xsocket(family, sotype | SOCK_NONBLOCK, 0); + if (c0 < 0) + 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; + + p1 = socket_loopback(family, sotype | SOCK_NONBLOCK); + if (p1 < 0) + goto close_cli0; + err = xgetsockname(p1, sockaddr(&addr), &len); + if (err) + goto close_cli0; + + c1 = xsocket(family, sotype | SOCK_NONBLOCK, 0); + if (c1 < 0) + goto close_peer1; + err = xconnect(c1, sockaddr(&addr), len); + if (err) + goto close_cli1; + err = xgetsockname(c1, sockaddr(&addr), &len); + if (err) + goto close_cli1; + err = xconnect(p1, sockaddr(&addr), len); + if (err) + goto close_cli1; + + key = 0; + value = p0; + err = xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST); + if (err) + goto close_cli1; + + key = 1; + value = p1; + err = xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST); + if (err) + goto close_cli1; + + n = write(c1, "a", 1); + if (n < 0) + FAIL_ERRNO("%s: write", log_prefix); + if (n == 0) + FAIL("%s: incomplete write", log_prefix); + if (n < 1) + goto close_cli1; + + key = SK_PASS; + err = xbpf_map_lookup_elem(verd_mapfd, &key, &pass); + if (err) + goto close_cli1; + if (pass != 1) + FAIL("%s: want pass count 1, have %d", log_prefix, pass); + + n = read(mode == REDIR_INGRESS ? p0 : c0, &b, 1); + if (n < 0) + FAIL_ERRNO("%s: read", log_prefix); + if (n == 0) + FAIL("%s: incomplete read", log_prefix); + +close_cli1: + xclose(c1); +close_peer1: + xclose(p1); +close_cli0: + xclose(c0); +close_peer0: + xclose(p0); +} + +static void udp_skb_redir_to_connected(struct test_sockmap_listen *skel, + struct bpf_map *inner_map, int family) +{ + int verdict = bpf_program__fd(skel->progs.prog_skb_verdict); + int verdict_map = bpf_map__fd(skel->maps.verdict_map); + int sock_map = bpf_map__fd(inner_map); + int err; + + err = xbpf_prog_attach(verdict, sock_map, BPF_SK_SKB_VERDICT, 0); + if (err) + return; + + skel->bss->test_ingress = false; + udp_redir_to_connected(family, SOCK_DGRAM, sock_map, verdict_map, + REDIR_EGRESS); + skel->bss->test_ingress = true; + udp_redir_to_connected(family, SOCK_DGRAM, sock_map, verdict_map, + REDIR_INGRESS); + + xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_VERDICT); +} + +static void test_udp_redir(struct test_sockmap_listen *skel, struct bpf_map *map, + int family) +{ + const char *family_name, *map_name; + char s[MAX_TEST_NAME]; + + family_name = family_str(family); + map_name = map_type_str(map); + snprintf(s, sizeof(s), &quo
[RFC PATCH bpf-next 2/4] selftests/bpf: Add re-attach test to fentry_test
Adding the test to re-attach (detach/attach again) tracing fentry programs, plus check that already linked program can't be attached again. Fixing the number of check-ed results, which should be 8. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fentry_test.c| 58 ++- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fentry_test.c b/tools/testing/selftests/bpf/prog_tests/fentry_test.c index 04ebbf1cb390..fa7a9c719659 100644 --- a/tools/testing/selftests/bpf/prog_tests/fentry_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fentry_test.c @@ -3,20 +3,13 @@ #include #include "fentry_test.skel.h" -void test_fentry_test(void) +static __u32 duration; + +static int fentry_test(struct fentry_test *fentry_skel) { - struct fentry_test *fentry_skel = NULL; int err, prog_fd, i; - __u32 duration = 0, retval; __u64 *result; - - fentry_skel = fentry_test__open_and_load(); - if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n")) - goto cleanup; - - err = fentry_test__attach(fentry_skel); - if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) - goto cleanup; + __u32 retval; prog_fd = bpf_program__fd(fentry_skel->progs.test1); err = bpf_prog_test_run(prog_fd, 1, NULL, 0, @@ -26,12 +19,51 @@ void test_fentry_test(void) err, errno, retval, duration); result = (__u64 *)fentry_skel->bss; - for (i = 0; i < 6; i++) { + for (i = 0; i < 8; i++) { if (CHECK(result[i] != 1, "result", "fentry_test%d failed err %lld\n", i + 1, result[i])) - goto cleanup; + return -1; } + /* zero results for re-attach test */ + for (i = 0; i < 8; i++) + result[i] = 0; + return 0; +} + +void test_fentry_test(void) +{ + struct fentry_test *fentry_skel = NULL; + struct bpf_link *link; + int err; + + fentry_skel = fentry_test__open_and_load(); + if (CHECK(!fentry_skel, "fentry_skel_load", "fentry skeleton failed\n")) + goto cleanup; + + err = fentry_test__attach(fentry_skel); + if (CHECK(err, "fentry_attach", "fentry attach failed: %d\n", err)) + goto cleanup; + + err = fentry_test(fentry_skel); + if (CHECK(err, "fentry_test", "fentry test failed: %d\n", err)) + goto cleanup; + + fentry_test__detach(fentry_skel); + + /* Re-attach and test again */ + err = fentry_test__attach(fentry_skel); + if (CHECK(err, "fentry_attach", "fentry re-attach failed: %d\n", err)) + goto cleanup; + + link = bpf_program__attach(fentry_skel->progs.test1); + if (CHECK(!IS_ERR(link), "attach_fentry re-attach without detach", + "err: %ld\n", PTR_ERR(link))) + goto cleanup; + + err = fentry_test(fentry_skel); + CHECK(err, "fentry_test", "fentry test failed: %d\n", err); + cleanup: fentry_test__destroy(fentry_skel); } -- 2.30.2
[RFC PATCH bpf-next 4/4] selftests/bpf: Test that module can't be unloaded with attached trampoline
Adding test to verify that once we attach module's trampoline, the module can't be unloaded. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/module_attach.c | 23 +++ 1 file changed, 23 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/module_attach.c b/tools/testing/selftests/bpf/prog_tests/module_attach.c index 5bc53d53d86e..d180b8c28287 100644 --- a/tools/testing/selftests/bpf/prog_tests/module_attach.c +++ b/tools/testing/selftests/bpf/prog_tests/module_attach.c @@ -45,12 +45,18 @@ static int trigger_module_test_write(int write_sz) return 0; } +static int delete_module(const char *name, int flags) +{ + return syscall(__NR_delete_module, name, flags); +} + void test_module_attach(void) { const int READ_SZ = 456; const int WRITE_SZ = 457; struct test_module_attach* skel; struct test_module_attach__bss *bss; + struct bpf_link *link; int err; skel = test_module_attach__open(); @@ -84,6 +90,23 @@ void test_module_attach(void) ASSERT_EQ(bss->fexit_ret, -EIO, "fexit_tet"); ASSERT_EQ(bss->fmod_ret_read_sz, READ_SZ, "fmod_ret"); + test_module_attach__detach(skel); + + /* attach fentry/fexit and make sure it get's module reference */ + link = bpf_program__attach(skel->progs.handle_fentry); + if (CHECK(IS_ERR(link), "attach_fentry", "err: %ld\n", PTR_ERR(link))) + goto cleanup; + + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + bpf_link__destroy(link); + + link = bpf_program__attach(skel->progs.handle_fexit); + if (CHECK(IS_ERR(link), "attach_fexit", "err: %ld\n", PTR_ERR(link))) + goto cleanup; + + ASSERT_ERR(delete_module("bpf_testmod", 0), "delete_module"); + bpf_link__destroy(link); + cleanup: test_module_attach__destroy(skel); } -- 2.30.2
[RFC PATCH bpf-next 3/4] selftests/bpf: Add re-attach test to fexit_test
Adding the test to re-attach (detach/attach again) tracing fexit programs, plus check that already linked program can't be attached again. Fixing the number of check-ed results, which should be 8. Signed-off-by: Jiri Olsa --- .../selftests/bpf/prog_tests/fexit_test.c | 58 ++- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/fexit_test.c b/tools/testing/selftests/bpf/prog_tests/fexit_test.c index 78d7a2765c27..c5105f1e 100644 --- a/tools/testing/selftests/bpf/prog_tests/fexit_test.c +++ b/tools/testing/selftests/bpf/prog_tests/fexit_test.c @@ -3,20 +3,13 @@ #include #include "fexit_test.skel.h" -void test_fexit_test(void) +static __u32 duration; + +static int fexit_test(struct fexit_test *fexit_skel) { - struct fexit_test *fexit_skel = NULL; int err, prog_fd, i; - __u32 duration = 0, retval; __u64 *result; - - fexit_skel = fexit_test__open_and_load(); - if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) - goto cleanup; - - err = fexit_test__attach(fexit_skel); - if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) - goto cleanup; + __u32 retval; prog_fd = bpf_program__fd(fexit_skel->progs.test1); err = bpf_prog_test_run(prog_fd, 1, NULL, 0, @@ -26,12 +19,51 @@ void test_fexit_test(void) err, errno, retval, duration); result = (__u64 *)fexit_skel->bss; - for (i = 0; i < 6; i++) { + for (i = 0; i < 8; i++) { if (CHECK(result[i] != 1, "result", "fexit_test%d failed err %lld\n", i + 1, result[i])) - goto cleanup; + return -1; } + /* zero results for re-attach test */ + for (i = 0; i < 8; i++) + result[i] = 0; + return 0; +} + +void test_fexit_test(void) +{ + struct fexit_test *fexit_skel = NULL; + struct bpf_link *link; + int err; + + fexit_skel = fexit_test__open_and_load(); + if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) + goto cleanup; + + err = fexit_test__attach(fexit_skel); + if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) + goto cleanup; + + err = fexit_test(fexit_skel); + if (CHECK(err, "fexit_test", "exit test failed: %d\n", err)) + goto cleanup; + + fexit_test__detach(fexit_skel); + + /* Re-attach and test again */ + err = fexit_test__attach(fexit_skel); + if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) + goto cleanup; + + link = bpf_program__attach(fexit_skel->progs.test1); + if (CHECK(!IS_ERR(link), "attach_fexit re-attach without detach", + "err: %ld\n", PTR_ERR(link))) + goto cleanup; + + err = fexit_test(fexit_skel); + CHECK(err, "fexit_test", "fexit test failed: %d\n", err); + cleanup: fexit_test__destroy(fexit_skel); } -- 2.30.2
[PATCH v4 bpf-next 11/17] selftests: xsk: refactor teardown/bidi test cases and testapp_validate
Currently, there is a testapp_sockets() that acts like a wrapper around testapp_validate() and it is called for bidi and teardown test types. Other test types call testapp_validate() directly. Split testapp_sockets() onto two separate functions so a bunch of bidi specific logic can be moved there and out of testapp_validate() itself. Introduce function pointer to ifobject struct which will be used for assigning the Rx/Tx function that is assigned to worker thread. Let's also have a global ifobject Rx/Tx pointers so it's easier to swap the vectors on a second run of a bi-directional test. Thread creation now is easey to follow. switching_notify variable is useless, info about vector switch can be printed based on bidi_pass state. Last but not least, init/destroy synchronization variables only once, not per each test. Signed-off-by: Maciej Fijalkowski --- tools/testing/selftests/bpf/xdpxceiver.c | 117 ++- tools/testing/selftests/bpf/xdpxceiver.h | 14 +-- 2 files changed, 78 insertions(+), 53 deletions(-) diff --git a/tools/testing/selftests/bpf/xdpxceiver.c b/tools/testing/selftests/bpf/xdpxceiver.c index 3db221e548cc..aeff5340be49 100644 --- a/tools/testing/selftests/bpf/xdpxceiver.c +++ b/tools/testing/selftests/bpf/xdpxceiver.c @@ -896,26 +896,10 @@ static void testapp_validate(void) pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, THREAD_STACK); - if ((test_type == TEST_TYPE_BIDI) && bidi_pass) { - pthread_init_mutex(); - if (!switching_notify) { - print_verbose("Switching Tx/Rx vectors\n"); - switching_notify++; - } - } - pthread_mutex_lock(&sync_mutex); /*Spawn RX thread */ - if (!bidi || !bidi_pass) { - if (pthread_create(&t0, &attr, worker_testapp_validate_rx, ifdict[1])) - exit_with_error(errno); - } else if (bidi && bidi_pass) { - /*switch Tx/Rx vectors */ - ifdict[0]->fv.vector = rx; - if (pthread_create(&t0, &attr, worker_testapp_validate_rx, ifdict[0])) - exit_with_error(errno); - } + pthread_create(&t0, &attr, ifdict_rx->func_ptr, ifdict_rx); if (clock_gettime(CLOCK_REALTIME, &max_wait)) exit_with_error(errno); @@ -927,15 +911,7 @@ static void testapp_validate(void) pthread_mutex_unlock(&sync_mutex); /*Spawn TX thread */ - if (!bidi || !bidi_pass) { - if (pthread_create(&t1, &attr, worker_testapp_validate_tx, ifdict[0])) - exit_with_error(errno); - } else if (bidi && bidi_pass) { - /*switch Tx/Rx vectors */ - ifdict[1]->fv.vector = tx; - if (pthread_create(&t1, &attr, worker_testapp_validate_tx, ifdict[1])) - exit_with_error(errno); - } + pthread_create(&t1, &attr, ifdict_tx->func_ptr, ifdict_tx); pthread_join(t1, NULL); pthread_join(t0, NULL); @@ -953,18 +929,53 @@ static void testapp_validate(void) print_ksft_result(); } -static void testapp_sockets(void) +static void testapp_teardown(void) +{ + int i; + + for (i = 0; i < MAX_TEARDOWN_ITER; i++) { + pkt_counter = 0; + prev_pkt = -1; + sigvar = 0; + print_verbose("Creating socket\n"); + testapp_validate(); + } + + print_ksft_result(); +} + +static void swap_vectors(struct ifobject *ifobj1, struct ifobject *ifobj2) +{ + void *(*tmp_func_ptr)(void *) = ifobj1->func_ptr; + enum fvector tmp_vector = ifobj1->fv.vector; + + ifobj1->func_ptr = ifobj2->func_ptr; + ifobj1->fv.vector = ifobj2->fv.vector; + + ifobj2->func_ptr = tmp_func_ptr; + ifobj2->fv.vector = tmp_vector; + + ifdict_tx = ifobj1; + ifdict_rx = ifobj2; +} + +static void testapp_bidi(void) { - for (int i = 0; i < ((test_type == TEST_TYPE_TEARDOWN) ? MAX_TEARDOWN_ITER : MAX_BIDI_ITER); -i++) { + for (int i = 0; i < MAX_BIDI_ITER; i++) { pkt_counter = 0; prev_pkt = -1; sigvar = 0; print_verbose("Creating socket\n"); testapp_validate(); - test_type == TEST_TYPE_BIDI ? bidi_pass++ : bidi_pass; + if (!bidi_pass) { + print_verbose("Switching Tx/Rx vectors\n"); + swap_vectors(ifdict[1], ifdict[0]); + } + bidi_pass++; } + swap_vectors(ifdict[0], ifdict[1]); + print_ksft_result(); } @@ -997,7 +1008,7 @@ static void testapp_stats(void) static
[PATCH v4 bpf-next 14/17] selftests: xsk: implement bpf_link test
Introduce a test that is supposed to verify the persistence of BPF resources based on underlying bpf_link usage. Test will: 1) create and bind two sockets on queue ids 0 and 1 2) run a traffic on queue ids 0 3) remove xsk sockets from queue 0 on both veth interfaces 4) run a traffic on queues ids 1 Running traffic successfully on qids 1 means that BPF resources were not removed on step 3). In order to make it work, change the command that creates veth pair to have the 4 queue pairs by default. Introduce the arrays of xsks and umems to ifobject struct but keep a pointers to single entities, so rest of the logic around Rx/Tx can be kept as-is. For umem handling, double the size of mmapped space and split that between the two sockets. Rename also bidi_pass to a variable 'second_step' of a boolean type as it's now used also for the test that is introduced here and it doesn't have anything in common with bi-directional testing. Drop opt_queue command line argument as it wasn't working before anyway. Signed-off-by: Maciej Fijalkowski --- tools/testing/selftests/bpf/test_xsk.sh | 3 +- tools/testing/selftests/bpf/xdpxceiver.c | 179 +-- tools/testing/selftests/bpf/xdpxceiver.h | 7 +- 3 files changed, 139 insertions(+), 50 deletions(-) diff --git a/tools/testing/selftests/bpf/test_xsk.sh b/tools/testing/selftests/bpf/test_xsk.sh index 56d4474e2c83..46633a3bfb0b 100755 --- a/tools/testing/selftests/bpf/test_xsk.sh +++ b/tools/testing/selftests/bpf/test_xsk.sh @@ -107,7 +107,7 @@ setup_vethPairs() { echo "setting up ${VETH0}: namespace: ${NS0}" fi ip netns add ${NS1} - ip link add ${VETH0} type veth peer name ${VETH1} + ip link add ${VETH0} numtxqueues 4 numrxqueues 4 type veth peer name ${VETH1} numtxqueues 4 numrxqueues 4 if [ -f /proc/net/if_inet6 ]; then echo 1 > /proc/sys/net/ipv6/conf/${VETH0}/disable_ipv6 fi @@ -118,6 +118,7 @@ setup_vethPairs() { ip netns exec ${NS1} ip link set ${VETH1} mtu ${MTU} ip link set ${VETH0} mtu ${MTU} ip netns exec ${NS1} ip link set ${VETH1} up + ip netns exec ${NS1} ip link set dev lo up ip link set ${VETH0} up } diff --git a/tools/testing/selftests/bpf/xdpxceiver.c b/tools/testing/selftests/bpf/xdpxceiver.c index be7f4930dee9..b57c75d6904b 100644 --- a/tools/testing/selftests/bpf/xdpxceiver.c +++ b/tools/testing/selftests/bpf/xdpxceiver.c @@ -41,8 +41,12 @@ *Reduce the size of the RX ring to a fraction of the fill ring size. * iv. fill queue empty *Do not populate the fill queue and then try to receive pkts. + *f. bpf_link resource persistence + * Configure sockets at indexes 0 and 1, run a traffic on queue ids 0, + * then remove xsk sockets from queue 0 on both veth interfaces and + * finally run a traffic on queues ids 1 * - * Total tests: 10 + * Total tests: 12 * * Flow: * - @@ -115,11 +119,12 @@ static void __exit_with_error(int error, const char *file, const char *func, int #define exit_with_error(error) __exit_with_error(error, __FILE__, __func__, __LINE__) #define print_ksft_result(void)\ - (ksft_test_result_pass("PASS: %s %s %s%s%s\n", configured_mode ? "DRV" : "SKB",\ + (ksft_test_result_pass("PASS: %s %s %s%s%s%s\n", configured_mode ? "DRV" : "SKB",\ test_type == TEST_TYPE_POLL ? "POLL" : "NOPOLL",\ test_type == TEST_TYPE_TEARDOWN ? "Socket Teardown" : "",\ test_type == TEST_TYPE_BIDI ? "Bi-directional Sockets" : "",\ - test_type == TEST_TYPE_STATS ? "Stats" : "")) + test_type == TEST_TYPE_STATS ? "Stats" : "",\ + test_type == TEST_TYPE_BPF_RES ? "BPF RES" : "")) static void init_sync_resources(void) { @@ -258,9 +263,8 @@ static void gen_eth_frame(struct xsk_umem_info *umem, u64 addr) memcpy(xsk_umem__get_data(umem->buffer, addr), pkt_data, PKT_SIZE); } -static void xsk_configure_umem(struct ifobject *data, void *buffer, u64 size) +static void xsk_configure_umem(struct ifobject *data, void *buffer, int idx) { - int ret; struct xsk_umem_config cfg = { .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS, .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS, @@ -268,17 +272,22 @@ static void xsk_configure_umem(struct ifobject *data, void *buffer, u64 size) .frame_headroom = frame_headroom, .flags = XSK_UMEM__DEFAULT_FLAGS }; + int size = num_frames * XSK_UMEM__DEFAULT_FRAME_SIZE; + struct xsk_umem_info *umem; + int r
[PATCH v4 bpf-next 01/17] selftests: xsk: don't call worker_pkt_dump() for stats test
For TEST_TYPE_STATS, worker_pkt_validate() that places frames onto pkt_buf is not called. Therefore, when dump mode is set, don't call worker_pkt_dump() for mentioned test type, so that it won't crash on pkt_buf() access. Signed-off-by: Maciej Fijalkowski --- tools/testing/selftests/bpf/xdpxceiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/xdpxceiver.c b/tools/testing/selftests/bpf/xdpxceiver.c index 8b0f7fdd9003..04574c2b4f41 100644 --- a/tools/testing/selftests/bpf/xdpxceiver.c +++ b/tools/testing/selftests/bpf/xdpxceiver.c @@ -999,7 +999,7 @@ static void testapp_validate(void) pthread_join(t1, NULL); pthread_join(t0, NULL); - if (debug_pkt_dump) { + if (debug_pkt_dump && test_type != TEST_TYPE_STATS) { worker_pkt_dump(); for (int iter = 0; iter < num_frames - 1; iter++) { free(pkt_buf[iter]->payload); -- 2.20.1
Re: [PATCH bpf v2 2/2] bpf/selftests: test that kernel rejects a TCP CC with an invalid license
Andrii Nakryiko writes: >> Ah, thanks! I always get confused about CHECK() as well! Maybe it should >> be renamed to ASSERT()? But that would require flipping all the if() >> statements around them as well :/ > > Exactly, it's the opposite of assert (ASSERT_NOT %-), that > CHECK(!found) is "assert not not found", right?) and it throws me off > every. single. time. Yup, me too, I have to basically infer the right meaning from the surrounding if statements (i.e., whether it triggers an error path or not). > Ideally we complete the set of ASSERT_XXX() macros and convert as much > as possible to that. We can also have just generic ASSERT() for all > other complicated cases. Totally on board with that! I'll try to remember to fix any selftests I fiddle with (and not introduce any new uses of CHECK() of course). -Toke
Re: [PATCH bpf v2 2/2] bpf/selftests: test that kernel rejects a TCP CC with an invalid license
-- Andrii On Fri, Mar 26, 2021 at 2:43 AM Toke Høiland-Jørgensen wrote: > > Andrii Nakryiko writes: > > > On Thu, Mar 25, 2021 at 2:11 PM Toke Høiland-Jørgensen > > wrote: > >> > >> This adds a selftest to check that the verifier rejects a TCP CC struct_ops > >> with a non-GPL license. > >> > >> v2: > >> - Use a minimal struct_ops BPF program instead of rewriting bpf_dctcp's > >> license in memory. > >> - Check for the verifier reject message instead of just the return code. > >> > >> Signed-off-by: Toke Høiland-Jørgensen > >> --- > >> .../selftests/bpf/prog_tests/bpf_tcp_ca.c | 44 +++ > >> .../selftests/bpf/progs/bpf_nogpltcp.c| 19 > >> 2 files changed, 63 insertions(+) > >> create mode 100644 tools/testing/selftests/bpf/progs/bpf_nogpltcp.c > >> > >> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c > >> b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c > >> index 37c5494a0381..a09c716528e1 100644 > >> --- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c > >> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c > >> @@ -6,6 +6,7 @@ > >> #include > >> #include "bpf_dctcp.skel.h" > >> #include "bpf_cubic.skel.h" > >> +#include "bpf_nogpltcp.skel.h" > > > > total nit, but my eyes can't read "nogpltcp"... wouldn't > > "bpf_tcp_nogpl" be a bit easier? > > Haha, yeah, good point - my eyes also just lump it into a blob... thanks > > >> > >> #define min(a, b) ((a) < (b) ? (a) : (b)) > >> > >> @@ -227,10 +228,53 @@ static void test_dctcp(void) > >> bpf_dctcp__destroy(dctcp_skel); > >> } > >> > >> +static char *err_str = NULL; > >> +static bool found = false; > >> + > >> +static int libbpf_debug_print(enum libbpf_print_level level, > >> + const char *format, va_list args) > >> +{ > >> + char *log_buf; > >> + > >> + if (level != LIBBPF_WARN || > >> + strcmp(format, "libbpf: \n%s\n")) { > >> + vprintf(format, args); > >> + return 0; > >> + } > >> + > >> + log_buf = va_arg(args, char *); > >> + if (!log_buf) > >> + goto out; > >> + if (err_str && strstr(log_buf, err_str) != NULL) > >> + found = true; > >> +out: > >> + printf(format, log_buf); > >> + return 0; > >> +} > >> + > >> +static void test_invalid_license(void) > >> +{ > >> + libbpf_print_fn_t old_print_fn = NULL; > >> + struct bpf_nogpltcp *skel; > >> + > >> + err_str = "struct ops programs must have a GPL compatible license"; > >> + old_print_fn = libbpf_set_print(libbpf_debug_print); > >> + > >> + skel = bpf_nogpltcp__open_and_load(); > >> + if (CHECK(skel, "bpf_nogplgtcp__open_and_load()", "didn't fail\n")) > > > > ASSERT_OK_PTR() > > > >> + bpf_nogpltcp__destroy(skel); > > > > you should destroy unconditionally > > > >> + > >> + CHECK(!found, "errmsg check", "expected string '%s'", err_str); > > > > ASSERT_EQ(found, true, "expected_err_msg"); > > > > I can never be sure which way CHECK() is checking > > Ah, thanks! I always get confused about CHECK() as well! Maybe it should > be renamed to ASSERT()? But that would require flipping all the if() > statements around them as well :/ Exactly, it's the opposite of assert (ASSERT_NOT %-), that CHECK(!found) is "assert not not found", right?) and it throws me off every. single. time. Ideally we complete the set of ASSERT_XXX() macros and convert as much as possible to that. We can also have just generic ASSERT() for all other complicated cases. > > -Toke >
[PATCH bpf v3 2/2] bpf/selftests: test that kernel rejects a TCP CC with an invalid license
This adds a selftest to check that the verifier rejects a TCP CC struct_ops with a non-GPL license. v3: - Rename prog to bpf_tcp_nogpl - Use ASSERT macros instead of CHECK - Skip unneeded initialisation, unconditionally close skeleton v2: - Use a minimal struct_ops BPF program instead of rewriting bpf_dctcp's license in memory. - Check for the verifier reject message instead of just the return code. Acked-by: Martin KaFai Lau Signed-off-by: Toke Høiland-Jørgensen --- .../selftests/bpf/prog_tests/bpf_tcp_ca.c | 44 +++ .../selftests/bpf/progs/bpf_tcp_nogpl.c | 19 2 files changed, 63 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/bpf_tcp_nogpl.c diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c index 37c5494a0381..e25917f04602 100644 --- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c +++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c @@ -6,6 +6,7 @@ #include #include "bpf_dctcp.skel.h" #include "bpf_cubic.skel.h" +#include "bpf_tcp_nogpl.skel.h" #define min(a, b) ((a) < (b) ? (a) : (b)) @@ -227,10 +228,53 @@ static void test_dctcp(void) bpf_dctcp__destroy(dctcp_skel); } +static char *err_str; +static bool found; + +static int libbpf_debug_print(enum libbpf_print_level level, + const char *format, va_list args) +{ + char *log_buf; + + if (level != LIBBPF_WARN || + strcmp(format, "libbpf: \n%s\n")) { + vprintf(format, args); + return 0; + } + + log_buf = va_arg(args, char *); + if (!log_buf) + goto out; + if (err_str && strstr(log_buf, err_str) != NULL) + found = true; +out: + printf(format, log_buf); + return 0; +} + +static void test_invalid_license(void) +{ + libbpf_print_fn_t old_print_fn; + struct bpf_tcp_nogpl *skel; + + err_str = "struct ops programs must have a GPL compatible license"; + found = false; + old_print_fn = libbpf_set_print(libbpf_debug_print); + + skel = bpf_tcp_nogpl__open_and_load(); + ASSERT_NULL(skel, "bpf_tcp_nogpl"); + ASSERT_EQ(found, true, "expected_err_msg"); + + bpf_tcp_nogpl__destroy(skel); + libbpf_set_print(old_print_fn); +} + void test_bpf_tcp_ca(void) { if (test__start_subtest("dctcp")) test_dctcp(); if (test__start_subtest("cubic")) test_cubic(); + if (test__start_subtest("invalid_license")) + test_invalid_license(); } diff --git a/tools/testing/selftests/bpf/progs/bpf_tcp_nogpl.c b/tools/testing/selftests/bpf/progs/bpf_tcp_nogpl.c new file mode 100644 index ..2ecd833dcd41 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/bpf_tcp_nogpl.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include "bpf_tcp_helpers.h" + +char _license[] SEC("license") = "X"; + +void BPF_STRUCT_OPS(nogpltcp_init, struct sock *sk) +{ +} + +SEC(".struct_ops") +struct tcp_congestion_ops bpf_nogpltcp = { + .init = (void *)nogpltcp_init, + .name = "bpf_nogpltcp", +}; -- 2.31.0
Re: [PATCH bpf v2 2/2] bpf/selftests: test that kernel rejects a TCP CC with an invalid license
Andrii Nakryiko writes: > On Thu, Mar 25, 2021 at 2:11 PM Toke Høiland-Jørgensen > wrote: >> >> This adds a selftest to check that the verifier rejects a TCP CC struct_ops >> with a non-GPL license. >> >> v2: >> - Use a minimal struct_ops BPF program instead of rewriting bpf_dctcp's >> license in memory. >> - Check for the verifier reject message instead of just the return code. >> >> Signed-off-by: Toke Høiland-Jørgensen >> --- >> .../selftests/bpf/prog_tests/bpf_tcp_ca.c | 44 +++ >> .../selftests/bpf/progs/bpf_nogpltcp.c| 19 >> 2 files changed, 63 insertions(+) >> create mode 100644 tools/testing/selftests/bpf/progs/bpf_nogpltcp.c >> >> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c >> b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c >> index 37c5494a0381..a09c716528e1 100644 >> --- a/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c >> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_tcp_ca.c >> @@ -6,6 +6,7 @@ >> #include >> #include "bpf_dctcp.skel.h" >> #include "bpf_cubic.skel.h" >> +#include "bpf_nogpltcp.skel.h" > > total nit, but my eyes can't read "nogpltcp"... wouldn't > "bpf_tcp_nogpl" be a bit easier? Haha, yeah, good point - my eyes also just lump it into a blob... >> >> #define min(a, b) ((a) < (b) ? (a) : (b)) >> >> @@ -227,10 +228,53 @@ static void test_dctcp(void) >> bpf_dctcp__destroy(dctcp_skel); >> } >> >> +static char *err_str = NULL; >> +static bool found = false; >> + >> +static int libbpf_debug_print(enum libbpf_print_level level, >> + const char *format, va_list args) >> +{ >> + char *log_buf; >> + >> + if (level != LIBBPF_WARN || >> + strcmp(format, "libbpf: \n%s\n")) { >> + vprintf(format, args); >> + return 0; >> + } >> + >> + log_buf = va_arg(args, char *); >> + if (!log_buf) >> + goto out; >> + if (err_str && strstr(log_buf, err_str) != NULL) >> + found = true; >> +out: >> + printf(format, log_buf); >> + return 0; >> +} >> + >> +static void test_invalid_license(void) >> +{ >> + libbpf_print_fn_t old_print_fn = NULL; >> + struct bpf_nogpltcp *skel; >> + >> + err_str = "struct ops programs must have a GPL compatible license"; >> + old_print_fn = libbpf_set_print(libbpf_debug_print); >> + >> + skel = bpf_nogpltcp__open_and_load(); >> + if (CHECK(skel, "bpf_nogplgtcp__open_and_load()", "didn't fail\n")) > > ASSERT_OK_PTR() > >> + bpf_nogpltcp__destroy(skel); > > you should destroy unconditionally > >> + >> + CHECK(!found, "errmsg check", "expected string '%s'", err_str); > > ASSERT_EQ(found, true, "expected_err_msg"); > > I can never be sure which way CHECK() is checking Ah, thanks! I always get confused about CHECK() as well! Maybe it should be renamed to ASSERT()? But that would require flipping all the if() statements around them as well :/ -Toke