Message ID | 20241028110535.82999-15-kerneljasonxing@gmail.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | net-timestamp: bpf extension to equip applications transparently | expand |
Jason Xing wrote: > From: Jason Xing <kernelxing@tencent.com> > > Only check if we pass those three key points after we enable the > bpf extension for so_timestamping. During each point, we can choose > whether to print the current timestamp. > > Signed-off-by: Jason Xing <kernelxing@tencent.com> > --- > .../bpf/prog_tests/so_timestamping.c | 98 ++++++++++++++ > .../selftests/bpf/progs/so_timestamping.c | 123 ++++++++++++++++++ > 2 files changed, 221 insertions(+) > create mode 100644 tools/testing/selftests/bpf/prog_tests/so_timestamping.c > create mode 100644 tools/testing/selftests/bpf/progs/so_timestamping.c > > diff --git a/tools/testing/selftests/bpf/prog_tests/so_timestamping.c b/tools/testing/selftests/bpf/prog_tests/so_timestamping.c > new file mode 100644 > index 000000000000..dfb7588c246d > --- /dev/null > +++ b/tools/testing/selftests/bpf/prog_tests/so_timestamping.c > @@ -0,0 +1,98 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Copyright (c) 2024 Tencent */ > + > +#define _GNU_SOURCE > +#include <sched.h> > +#include <linux/socket.h> > +#include <linux/tls.h> > +#include <net/if.h> > + > +#include "test_progs.h" > +#include "cgroup_helpers.h" > +#include "network_helpers.h" > + > +#include "so_timestamping.skel.h" > + > +#define CG_NAME "/so-timestamping-test" > + > +static const char addr4_str[] = "127.0.0.1"; > +static const char addr6_str[] = "::1"; > +static struct so_timestamping *skel; > +static int cg_fd; > + > +static int create_netns(void) > +{ > + if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) > + return -1; > + > + if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up")) > + return -1; > + > + return 0; > +} > + > +static void test_tcp(int family) > +{ > + struct so_timestamping__bss *bss = skel->bss; > + char buf[] = "testing testing"; > + int sfd = -1, cfd = -1; > + int n; > + > + memset(bss, 0, sizeof(*bss)); > + > + sfd = start_server(family, SOCK_STREAM, > + family == AF_INET6 ? addr6_str : addr4_str, 0, 0); > + if (!ASSERT_GE(sfd, 0, "start_server")) > + goto out; > + > + cfd = connect_to_fd(sfd, 0); > + if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) { > + close(sfd); > + goto out; > + } > + > + n = write(cfd, buf, sizeof(buf)); > + if (!ASSERT_EQ(n, sizeof(buf), "send to server")) > + goto out; > + > + ASSERT_EQ(bss->nr_active, 1, "nr_active"); > + ASSERT_EQ(bss->nr_passive, 1, "nr_passive"); > + ASSERT_EQ(bss->nr_sched, 1, "nr_sched"); > + ASSERT_EQ(bss->nr_txsw, 1, "nr_txsw"); > + ASSERT_EQ(bss->nr_ack, 1, "nr_ack"); > + > +out: > + if (sfd >= 0) > + close(sfd); > + if (cfd >= 0) > + close(cfd); > +} > + > +void test_so_timestamping(void) > +{ > + cg_fd = test__join_cgroup(CG_NAME); > + if (cg_fd < 0) > + return; > + > + if (create_netns()) > + goto done; > + > + skel = so_timestamping__open(); > + if (!ASSERT_OK_PTR(skel, "open skel")) > + goto done; > + > + if (!ASSERT_OK(so_timestamping__load(skel), "load skel")) > + goto done; > + > + skel->links.skops_sockopt = > + bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd); > + if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup")) > + goto done; > + > + test_tcp(AF_INET6); > + test_tcp(AF_INET); > + > +done: > + so_timestamping__destroy(skel); > + close(cg_fd); > +} > diff --git a/tools/testing/selftests/bpf/progs/so_timestamping.c b/tools/testing/selftests/bpf/progs/so_timestamping.c > new file mode 100644 > index 000000000000..a15317951786 > --- /dev/null > +++ b/tools/testing/selftests/bpf/progs/so_timestamping.c > @@ -0,0 +1,123 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Copyright (c) 2024 Tencent */ > + > +#include "vmlinux.h" > +#include "bpf_tracing_net.h" > +#include <bpf/bpf_core_read.h> > +#include <bpf/bpf_helpers.h> > +#include <bpf/bpf_tracing.h> > +#include "bpf_misc.h" > + > +#define SO_TIMESTAMPING 37 > +#define SOF_TIMESTAMPING_BPF_SUPPPORTED_MASK (SOF_TIMESTAMPING_SOFTWARE | \ > + SOF_TIMESTAMPING_TX_SCHED | \ > + SOF_TIMESTAMPING_TX_SOFTWARE | \ > + SOF_TIMESTAMPING_TX_ACK | \ > + SOF_TIMESTAMPING_OPT_ID | \ > + SOF_TIMESTAMPING_OPT_ID_TCP) > + > +extern unsigned long CONFIG_HZ __kconfig; > + > +int nr_active; > +int nr_passive; > +int nr_sched; > +int nr_txsw; > +int nr_ack; > + > +struct sockopt_test { > + int opt; > + int new; > + int expected; > +}; > + > +static const struct sockopt_test sol_socket_tests[] = { > + { .opt = SO_TIMESTAMPING, .new = SOF_TIMESTAMPING_TX_SCHED, .expected = 256, }, > + { .opt = SO_TIMESTAMPING, .new = SOF_TIMESTAMPING_BPF_SUPPPORTED_MASK, .expected = 66450, }, > + { .opt = 0, }, > +}; > + > +struct loop_ctx { > + void *ctx; > + struct sock *sk; > +}; > + > +static int bpf_test_sockopt_int(void *ctx, struct sock *sk, > + const struct sockopt_test *t, > + int level) > +{ > + int tmp, new, expected, opt; > + > + opt = t->opt; > + new = t->new; > + expected = t->expected; > + > + if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new))) > + return 1; > + if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) || > + tmp != expected) > + return 1; > + > + return 0; > +} > + > +static int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc) > +{ > + const struct sockopt_test *t; > + > + if (i >= ARRAY_SIZE(sol_socket_tests)) > + return 1; > + > + t = &sol_socket_tests[i]; > + if (!t->opt) > + return 1; > + > + return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET); > +} > + > +static int bpf_test_sockopt(void *ctx, struct sock *sk) > +{ > + struct loop_ctx lc = { .ctx = ctx, .sk = sk, }; > + int n; > + > + n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0); > + if (n != ARRAY_SIZE(sol_socket_tests)) > + return -1; > + > + return 0; > +} > + > +SEC("sockops") > +int skops_sockopt(struct bpf_sock_ops *skops) > +{ > + struct bpf_sock *bpf_sk = skops->sk; > + struct sock *sk; > + > + if (!bpf_sk) > + return 1; > + > + sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk); > + if (!sk) > + return 1; > + > + switch (skops->op) { > + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: > + nr_active += !bpf_test_sockopt(skops, sk); > + break; > + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: > + nr_passive += !bpf_test_sockopt(skops, sk); > + break; > + case BPF_SOCK_OPS_TS_SCHED_OPT_CB: > + nr_sched += 1; > + break; > + case BPF_SOCK_OPS_TS_SW_OPT_CB: > + nr_txsw += 1; > + break; > + case BPF_SOCK_OPS_TS_ACK_OPT_CB: > + nr_ack += 1; > + break; Perhaps demonstrate what to do with the args on the new TS_*_OPT_CB. > + } > + > + return 1; > +} > + > +char _license[] SEC("license") = "GPL"; > -- > 2.37.3 >
On Tue, Oct 29, 2024 at 9:27 AM Willem de Bruijn <willemdebruijn.kernel@gmail.com> wrote: > > Jason Xing wrote: > > From: Jason Xing <kernelxing@tencent.com> > > > > Only check if we pass those three key points after we enable the > > bpf extension for so_timestamping. During each point, we can choose > > whether to print the current timestamp. > > > > Signed-off-by: Jason Xing <kernelxing@tencent.com> > > --- > > .../bpf/prog_tests/so_timestamping.c | 98 ++++++++++++++ > > .../selftests/bpf/progs/so_timestamping.c | 123 ++++++++++++++++++ > > 2 files changed, 221 insertions(+) > > create mode 100644 tools/testing/selftests/bpf/prog_tests/so_timestamping.c > > create mode 100644 tools/testing/selftests/bpf/progs/so_timestamping.c > > > > diff --git a/tools/testing/selftests/bpf/prog_tests/so_timestamping.c b/tools/testing/selftests/bpf/prog_tests/so_timestamping.c > > new file mode 100644 > > index 000000000000..dfb7588c246d > > --- /dev/null > > +++ b/tools/testing/selftests/bpf/prog_tests/so_timestamping.c > > @@ -0,0 +1,98 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* Copyright (c) 2024 Tencent */ > > + > > +#define _GNU_SOURCE > > +#include <sched.h> > > +#include <linux/socket.h> > > +#include <linux/tls.h> > > +#include <net/if.h> > > + > > +#include "test_progs.h" > > +#include "cgroup_helpers.h" > > +#include "network_helpers.h" > > + > > +#include "so_timestamping.skel.h" > > + > > +#define CG_NAME "/so-timestamping-test" > > + > > +static const char addr4_str[] = "127.0.0.1"; > > +static const char addr6_str[] = "::1"; > > +static struct so_timestamping *skel; > > +static int cg_fd; > > + > > +static int create_netns(void) > > +{ > > + if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) > > + return -1; > > + > > + if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up")) > > + return -1; > > + > > + return 0; > > +} > > + > > +static void test_tcp(int family) > > +{ > > + struct so_timestamping__bss *bss = skel->bss; > > + char buf[] = "testing testing"; > > + int sfd = -1, cfd = -1; > > + int n; > > + > > + memset(bss, 0, sizeof(*bss)); > > + > > + sfd = start_server(family, SOCK_STREAM, > > + family == AF_INET6 ? addr6_str : addr4_str, 0, 0); > > + if (!ASSERT_GE(sfd, 0, "start_server")) > > + goto out; > > + > > + cfd = connect_to_fd(sfd, 0); > > + if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) { > > + close(sfd); > > + goto out; > > + } > > + > > + n = write(cfd, buf, sizeof(buf)); > > + if (!ASSERT_EQ(n, sizeof(buf), "send to server")) > > + goto out; > > + > > + ASSERT_EQ(bss->nr_active, 1, "nr_active"); > > + ASSERT_EQ(bss->nr_passive, 1, "nr_passive"); > > + ASSERT_EQ(bss->nr_sched, 1, "nr_sched"); > > + ASSERT_EQ(bss->nr_txsw, 1, "nr_txsw"); > > + ASSERT_EQ(bss->nr_ack, 1, "nr_ack"); > > + > > +out: > > + if (sfd >= 0) > > + close(sfd); > > + if (cfd >= 0) > > + close(cfd); > > +} > > + > > +void test_so_timestamping(void) > > +{ > > + cg_fd = test__join_cgroup(CG_NAME); > > + if (cg_fd < 0) > > + return; > > + > > + if (create_netns()) > > + goto done; > > + > > + skel = so_timestamping__open(); > > + if (!ASSERT_OK_PTR(skel, "open skel")) > > + goto done; > > + > > + if (!ASSERT_OK(so_timestamping__load(skel), "load skel")) > > + goto done; > > + > > + skel->links.skops_sockopt = > > + bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd); > > + if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup")) > > + goto done; > > + > > + test_tcp(AF_INET6); > > + test_tcp(AF_INET); > > + > > +done: > > + so_timestamping__destroy(skel); > > + close(cg_fd); > > +} > > diff --git a/tools/testing/selftests/bpf/progs/so_timestamping.c b/tools/testing/selftests/bpf/progs/so_timestamping.c > > new file mode 100644 > > index 000000000000..a15317951786 > > --- /dev/null > > +++ b/tools/testing/selftests/bpf/progs/so_timestamping.c > > @@ -0,0 +1,123 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* Copyright (c) 2024 Tencent */ > > + > > +#include "vmlinux.h" > > +#include "bpf_tracing_net.h" > > +#include <bpf/bpf_core_read.h> > > +#include <bpf/bpf_helpers.h> > > +#include <bpf/bpf_tracing.h> > > +#include "bpf_misc.h" > > + > > +#define SO_TIMESTAMPING 37 > > +#define SOF_TIMESTAMPING_BPF_SUPPPORTED_MASK (SOF_TIMESTAMPING_SOFTWARE | \ > > + SOF_TIMESTAMPING_TX_SCHED | \ > > + SOF_TIMESTAMPING_TX_SOFTWARE | \ > > + SOF_TIMESTAMPING_TX_ACK | \ > > + SOF_TIMESTAMPING_OPT_ID | \ > > + SOF_TIMESTAMPING_OPT_ID_TCP) > > + > > +extern unsigned long CONFIG_HZ __kconfig; > > + > > +int nr_active; > > +int nr_passive; > > +int nr_sched; > > +int nr_txsw; > > +int nr_ack; > > + > > +struct sockopt_test { > > + int opt; > > + int new; > > + int expected; > > +}; > > + > > +static const struct sockopt_test sol_socket_tests[] = { > > + { .opt = SO_TIMESTAMPING, .new = SOF_TIMESTAMPING_TX_SCHED, .expected = 256, }, > > + { .opt = SO_TIMESTAMPING, .new = SOF_TIMESTAMPING_BPF_SUPPPORTED_MASK, .expected = 66450, }, > > + { .opt = 0, }, > > +}; > > + > > +struct loop_ctx { > > + void *ctx; > > + struct sock *sk; > > +}; > > + > > +static int bpf_test_sockopt_int(void *ctx, struct sock *sk, > > + const struct sockopt_test *t, > > + int level) > > +{ > > + int tmp, new, expected, opt; > > + > > + opt = t->opt; > > + new = t->new; > > + expected = t->expected; > > + > > + if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new))) > > + return 1; > > + if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) || > > + tmp != expected) > > + return 1; > > + > > + return 0; > > +} > > + > > +static int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc) > > +{ > > + const struct sockopt_test *t; > > + > > + if (i >= ARRAY_SIZE(sol_socket_tests)) > > + return 1; > > + > > + t = &sol_socket_tests[i]; > > + if (!t->opt) > > + return 1; > > + > > + return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET); > > +} > > + > > +static int bpf_test_sockopt(void *ctx, struct sock *sk) > > +{ > > + struct loop_ctx lc = { .ctx = ctx, .sk = sk, }; > > + int n; > > + > > + n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0); > > + if (n != ARRAY_SIZE(sol_socket_tests)) > > + return -1; > > + > > + return 0; > > +} > > + > > +SEC("sockops") > > +int skops_sockopt(struct bpf_sock_ops *skops) > > +{ > > + struct bpf_sock *bpf_sk = skops->sk; > > + struct sock *sk; > > + > > + if (!bpf_sk) > > + return 1; > > + > > + sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk); > > + if (!sk) > > + return 1; > > + > > + switch (skops->op) { > > + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: > > + nr_active += !bpf_test_sockopt(skops, sk); > > + break; > > + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: > > + nr_passive += !bpf_test_sockopt(skops, sk); > > + break; > > + case BPF_SOCK_OPS_TS_SCHED_OPT_CB: > > + nr_sched += 1; > > + break; > > + case BPF_SOCK_OPS_TS_SW_OPT_CB: > > + nr_txsw += 1; > > + break; > > + case BPF_SOCK_OPS_TS_ACK_OPT_CB: > > + nr_ack += 1; > > + break; > > Perhaps demonstrate what to do with the args on the new > TS_*_OPT_CB. Roger that. I would like to know if the current patch is too big to review? Should I split it into a few patches? But this series has 14 patches right now which could possibly exceed the maximum limit. Thanks, Jason
Jason Xing wrote: > On Tue, Oct 29, 2024 at 9:27 AM Willem de Bruijn > <willemdebruijn.kernel@gmail.com> wrote: > > > > Jason Xing wrote: > > > From: Jason Xing <kernelxing@tencent.com> > > > > > > Only check if we pass those three key points after we enable the > > > bpf extension for so_timestamping. During each point, we can choose > > > whether to print the current timestamp. > > > > > > Signed-off-by: Jason Xing <kernelxing@tencent.com> > > > --- > > > .../bpf/prog_tests/so_timestamping.c | 98 ++++++++++++++ > > > .../selftests/bpf/progs/so_timestamping.c | 123 ++++++++++++++++++ > > > 2 files changed, 221 insertions(+) > > > create mode 100644 tools/testing/selftests/bpf/prog_tests/so_timestamping.c > > > create mode 100644 tools/testing/selftests/bpf/progs/so_timestamping.c > > > > > > diff --git a/tools/testing/selftests/bpf/prog_tests/so_timestamping.c b/tools/testing/selftests/bpf/prog_tests/so_timestamping.c > > > new file mode 100644 > > > index 000000000000..dfb7588c246d > > > --- /dev/null > > > +++ b/tools/testing/selftests/bpf/prog_tests/so_timestamping.c > > > @@ -0,0 +1,98 @@ > > > +// SPDX-License-Identifier: GPL-2.0 > > > +/* Copyright (c) 2024 Tencent */ > > > + > > > +#define _GNU_SOURCE > > > +#include <sched.h> > > > +#include <linux/socket.h> > > > +#include <linux/tls.h> > > > +#include <net/if.h> > > > + > > > +#include "test_progs.h" > > > +#include "cgroup_helpers.h" > > > +#include "network_helpers.h" > > > + > > > +#include "so_timestamping.skel.h" > > > + > > > +#define CG_NAME "/so-timestamping-test" > > > + > > > +static const char addr4_str[] = "127.0.0.1"; > > > +static const char addr6_str[] = "::1"; > > > +static struct so_timestamping *skel; > > > +static int cg_fd; > > > + > > > +static int create_netns(void) > > > +{ > > > + if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) > > > + return -1; > > > + > > > + if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up")) > > > + return -1; > > > + > > > + return 0; > > > +} > > > + > > > +static void test_tcp(int family) > > > +{ > > > + struct so_timestamping__bss *bss = skel->bss; > > > + char buf[] = "testing testing"; > > > + int sfd = -1, cfd = -1; > > > + int n; > > > + > > > + memset(bss, 0, sizeof(*bss)); > > > + > > > + sfd = start_server(family, SOCK_STREAM, > > > + family == AF_INET6 ? addr6_str : addr4_str, 0, 0); > > > + if (!ASSERT_GE(sfd, 0, "start_server")) > > > + goto out; > > > + > > > + cfd = connect_to_fd(sfd, 0); > > > + if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) { > > > + close(sfd); > > > + goto out; > > > + } > > > + > > > + n = write(cfd, buf, sizeof(buf)); > > > + if (!ASSERT_EQ(n, sizeof(buf), "send to server")) > > > + goto out; > > > + > > > + ASSERT_EQ(bss->nr_active, 1, "nr_active"); > > > + ASSERT_EQ(bss->nr_passive, 1, "nr_passive"); > > > + ASSERT_EQ(bss->nr_sched, 1, "nr_sched"); > > > + ASSERT_EQ(bss->nr_txsw, 1, "nr_txsw"); > > > + ASSERT_EQ(bss->nr_ack, 1, "nr_ack"); > > > + > > > +out: > > > + if (sfd >= 0) > > > + close(sfd); > > > + if (cfd >= 0) > > > + close(cfd); > > > +} > > > + > > > +void test_so_timestamping(void) > > > +{ > > > + cg_fd = test__join_cgroup(CG_NAME); > > > + if (cg_fd < 0) > > > + return; > > > + > > > + if (create_netns()) > > > + goto done; > > > + > > > + skel = so_timestamping__open(); > > > + if (!ASSERT_OK_PTR(skel, "open skel")) > > > + goto done; > > > + > > > + if (!ASSERT_OK(so_timestamping__load(skel), "load skel")) > > > + goto done; > > > + > > > + skel->links.skops_sockopt = > > > + bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd); > > > + if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup")) > > > + goto done; > > > + > > > + test_tcp(AF_INET6); > > > + test_tcp(AF_INET); > > > + > > > +done: > > > + so_timestamping__destroy(skel); > > > + close(cg_fd); > > > +} > > > diff --git a/tools/testing/selftests/bpf/progs/so_timestamping.c b/tools/testing/selftests/bpf/progs/so_timestamping.c > > > new file mode 100644 > > > index 000000000000..a15317951786 > > > --- /dev/null > > > +++ b/tools/testing/selftests/bpf/progs/so_timestamping.c > > > @@ -0,0 +1,123 @@ > > > +// SPDX-License-Identifier: GPL-2.0 > > > +/* Copyright (c) 2024 Tencent */ > > > + > > > +#include "vmlinux.h" > > > +#include "bpf_tracing_net.h" > > > +#include <bpf/bpf_core_read.h> > > > +#include <bpf/bpf_helpers.h> > > > +#include <bpf/bpf_tracing.h> > > > +#include "bpf_misc.h" > > > + > > > +#define SO_TIMESTAMPING 37 > > > +#define SOF_TIMESTAMPING_BPF_SUPPPORTED_MASK (SOF_TIMESTAMPING_SOFTWARE | \ > > > + SOF_TIMESTAMPING_TX_SCHED | \ > > > + SOF_TIMESTAMPING_TX_SOFTWARE | \ > > > + SOF_TIMESTAMPING_TX_ACK | \ > > > + SOF_TIMESTAMPING_OPT_ID | \ > > > + SOF_TIMESTAMPING_OPT_ID_TCP) > > > + > > > +extern unsigned long CONFIG_HZ __kconfig; > > > + > > > +int nr_active; > > > +int nr_passive; > > > +int nr_sched; > > > +int nr_txsw; > > > +int nr_ack; > > > + > > > +struct sockopt_test { > > > + int opt; > > > + int new; > > > + int expected; > > > +}; > > > + > > > +static const struct sockopt_test sol_socket_tests[] = { > > > + { .opt = SO_TIMESTAMPING, .new = SOF_TIMESTAMPING_TX_SCHED, .expected = 256, }, > > > + { .opt = SO_TIMESTAMPING, .new = SOF_TIMESTAMPING_BPF_SUPPPORTED_MASK, .expected = 66450, }, > > > + { .opt = 0, }, > > > +}; > > > + > > > +struct loop_ctx { > > > + void *ctx; > > > + struct sock *sk; > > > +}; > > > + > > > +static int bpf_test_sockopt_int(void *ctx, struct sock *sk, > > > + const struct sockopt_test *t, > > > + int level) > > > +{ > > > + int tmp, new, expected, opt; > > > + > > > + opt = t->opt; > > > + new = t->new; > > > + expected = t->expected; > > > + > > > + if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new))) > > > + return 1; > > > + if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) || > > > + tmp != expected) > > > + return 1; > > > + > > > + return 0; > > > +} > > > + > > > +static int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc) > > > +{ > > > + const struct sockopt_test *t; > > > + > > > + if (i >= ARRAY_SIZE(sol_socket_tests)) > > > + return 1; > > > + > > > + t = &sol_socket_tests[i]; > > > + if (!t->opt) > > > + return 1; > > > + > > > + return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET); > > > +} > > > + > > > +static int bpf_test_sockopt(void *ctx, struct sock *sk) > > > +{ > > > + struct loop_ctx lc = { .ctx = ctx, .sk = sk, }; > > > + int n; > > > + > > > + n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0); > > > + if (n != ARRAY_SIZE(sol_socket_tests)) > > > + return -1; > > > + > > > + return 0; > > > +} > > > + > > > +SEC("sockops") > > > +int skops_sockopt(struct bpf_sock_ops *skops) > > > +{ > > > + struct bpf_sock *bpf_sk = skops->sk; > > > + struct sock *sk; > > > + > > > + if (!bpf_sk) > > > + return 1; > > > + > > > + sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk); > > > + if (!sk) > > > + return 1; > > > + > > > + switch (skops->op) { > > > + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: > > > + nr_active += !bpf_test_sockopt(skops, sk); > > > + break; > > > + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: > > > + nr_passive += !bpf_test_sockopt(skops, sk); > > > + break; > > > + case BPF_SOCK_OPS_TS_SCHED_OPT_CB: > > > + nr_sched += 1; > > > + break; > > > + case BPF_SOCK_OPS_TS_SW_OPT_CB: > > > + nr_txsw += 1; > > > + break; > > > + case BPF_SOCK_OPS_TS_ACK_OPT_CB: > > > + nr_ack += 1; > > > + break; > > > > Perhaps demonstrate what to do with the args on the new > > TS_*_OPT_CB. > > Roger that. > > I would like to know if the current patch is too big to review? Should > I split it into a few patches? But this series has 14 patches right > now which could possibly exceed the maximum limit. For a test patch, this looks fine to me. They often are a longer than feature patches. But much of it is easy to grasp.
On Tue, Oct 29, 2024 at 9:40 AM Willem de Bruijn <willemdebruijn.kernel@gmail.com> wrote: > > Jason Xing wrote: > > On Tue, Oct 29, 2024 at 9:27 AM Willem de Bruijn > > <willemdebruijn.kernel@gmail.com> wrote: > > > > > > Jason Xing wrote: > > > > From: Jason Xing <kernelxing@tencent.com> > > > > > > > > Only check if we pass those three key points after we enable the > > > > bpf extension for so_timestamping. During each point, we can choose > > > > whether to print the current timestamp. > > > > > > > > Signed-off-by: Jason Xing <kernelxing@tencent.com> > > > > --- > > > > .../bpf/prog_tests/so_timestamping.c | 98 ++++++++++++++ > > > > .../selftests/bpf/progs/so_timestamping.c | 123 ++++++++++++++++++ > > > > 2 files changed, 221 insertions(+) > > > > create mode 100644 tools/testing/selftests/bpf/prog_tests/so_timestamping.c > > > > create mode 100644 tools/testing/selftests/bpf/progs/so_timestamping.c > > > > > > > > diff --git a/tools/testing/selftests/bpf/prog_tests/so_timestamping.c b/tools/testing/selftests/bpf/prog_tests/so_timestamping.c > > > > new file mode 100644 > > > > index 000000000000..dfb7588c246d > > > > --- /dev/null > > > > +++ b/tools/testing/selftests/bpf/prog_tests/so_timestamping.c > > > > @@ -0,0 +1,98 @@ > > > > +// SPDX-License-Identifier: GPL-2.0 > > > > +/* Copyright (c) 2024 Tencent */ > > > > + > > > > +#define _GNU_SOURCE > > > > +#include <sched.h> > > > > +#include <linux/socket.h> > > > > +#include <linux/tls.h> > > > > +#include <net/if.h> > > > > + > > > > +#include "test_progs.h" > > > > +#include "cgroup_helpers.h" > > > > +#include "network_helpers.h" > > > > + > > > > +#include "so_timestamping.skel.h" > > > > + > > > > +#define CG_NAME "/so-timestamping-test" > > > > + > > > > +static const char addr4_str[] = "127.0.0.1"; > > > > +static const char addr6_str[] = "::1"; > > > > +static struct so_timestamping *skel; > > > > +static int cg_fd; > > > > + > > > > +static int create_netns(void) > > > > +{ > > > > + if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) > > > > + return -1; > > > > + > > > > + if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up")) > > > > + return -1; > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static void test_tcp(int family) > > > > +{ > > > > + struct so_timestamping__bss *bss = skel->bss; > > > > + char buf[] = "testing testing"; > > > > + int sfd = -1, cfd = -1; > > > > + int n; > > > > + > > > > + memset(bss, 0, sizeof(*bss)); > > > > + > > > > + sfd = start_server(family, SOCK_STREAM, > > > > + family == AF_INET6 ? addr6_str : addr4_str, 0, 0); > > > > + if (!ASSERT_GE(sfd, 0, "start_server")) > > > > + goto out; > > > > + > > > > + cfd = connect_to_fd(sfd, 0); > > > > + if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) { > > > > + close(sfd); > > > > + goto out; > > > > + } > > > > + > > > > + n = write(cfd, buf, sizeof(buf)); > > > > + if (!ASSERT_EQ(n, sizeof(buf), "send to server")) > > > > + goto out; > > > > + > > > > + ASSERT_EQ(bss->nr_active, 1, "nr_active"); > > > > + ASSERT_EQ(bss->nr_passive, 1, "nr_passive"); > > > > + ASSERT_EQ(bss->nr_sched, 1, "nr_sched"); > > > > + ASSERT_EQ(bss->nr_txsw, 1, "nr_txsw"); > > > > + ASSERT_EQ(bss->nr_ack, 1, "nr_ack"); > > > > + > > > > +out: > > > > + if (sfd >= 0) > > > > + close(sfd); > > > > + if (cfd >= 0) > > > > + close(cfd); > > > > +} > > > > + > > > > +void test_so_timestamping(void) > > > > +{ > > > > + cg_fd = test__join_cgroup(CG_NAME); > > > > + if (cg_fd < 0) > > > > + return; > > > > + > > > > + if (create_netns()) > > > > + goto done; > > > > + > > > > + skel = so_timestamping__open(); > > > > + if (!ASSERT_OK_PTR(skel, "open skel")) > > > > + goto done; > > > > + > > > > + if (!ASSERT_OK(so_timestamping__load(skel), "load skel")) > > > > + goto done; > > > > + > > > > + skel->links.skops_sockopt = > > > > + bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd); > > > > + if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup")) > > > > + goto done; > > > > + > > > > + test_tcp(AF_INET6); > > > > + test_tcp(AF_INET); > > > > + > > > > +done: > > > > + so_timestamping__destroy(skel); > > > > + close(cg_fd); > > > > +} > > > > diff --git a/tools/testing/selftests/bpf/progs/so_timestamping.c b/tools/testing/selftests/bpf/progs/so_timestamping.c > > > > new file mode 100644 > > > > index 000000000000..a15317951786 > > > > --- /dev/null > > > > +++ b/tools/testing/selftests/bpf/progs/so_timestamping.c > > > > @@ -0,0 +1,123 @@ > > > > +// SPDX-License-Identifier: GPL-2.0 > > > > +/* Copyright (c) 2024 Tencent */ > > > > + > > > > +#include "vmlinux.h" > > > > +#include "bpf_tracing_net.h" > > > > +#include <bpf/bpf_core_read.h> > > > > +#include <bpf/bpf_helpers.h> > > > > +#include <bpf/bpf_tracing.h> > > > > +#include "bpf_misc.h" > > > > + > > > > +#define SO_TIMESTAMPING 37 > > > > +#define SOF_TIMESTAMPING_BPF_SUPPPORTED_MASK (SOF_TIMESTAMPING_SOFTWARE | \ > > > > + SOF_TIMESTAMPING_TX_SCHED | \ > > > > + SOF_TIMESTAMPING_TX_SOFTWARE | \ > > > > + SOF_TIMESTAMPING_TX_ACK | \ > > > > + SOF_TIMESTAMPING_OPT_ID | \ > > > > + SOF_TIMESTAMPING_OPT_ID_TCP) > > > > + > > > > +extern unsigned long CONFIG_HZ __kconfig; > > > > + > > > > +int nr_active; > > > > +int nr_passive; > > > > +int nr_sched; > > > > +int nr_txsw; > > > > +int nr_ack; > > > > + > > > > +struct sockopt_test { > > > > + int opt; > > > > + int new; > > > > + int expected; > > > > +}; > > > > + > > > > +static const struct sockopt_test sol_socket_tests[] = { > > > > + { .opt = SO_TIMESTAMPING, .new = SOF_TIMESTAMPING_TX_SCHED, .expected = 256, }, > > > > + { .opt = SO_TIMESTAMPING, .new = SOF_TIMESTAMPING_BPF_SUPPPORTED_MASK, .expected = 66450, }, > > > > + { .opt = 0, }, > > > > +}; > > > > + > > > > +struct loop_ctx { > > > > + void *ctx; > > > > + struct sock *sk; > > > > +}; > > > > + > > > > +static int bpf_test_sockopt_int(void *ctx, struct sock *sk, > > > > + const struct sockopt_test *t, > > > > + int level) > > > > +{ > > > > + int tmp, new, expected, opt; > > > > + > > > > + opt = t->opt; > > > > + new = t->new; > > > > + expected = t->expected; > > > > + > > > > + if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new))) > > > > + return 1; > > > > + if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) || > > > > + tmp != expected) > > > > + return 1; > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc) > > > > +{ > > > > + const struct sockopt_test *t; > > > > + > > > > + if (i >= ARRAY_SIZE(sol_socket_tests)) > > > > + return 1; > > > > + > > > > + t = &sol_socket_tests[i]; > > > > + if (!t->opt) > > > > + return 1; > > > > + > > > > + return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET); > > > > +} > > > > + > > > > +static int bpf_test_sockopt(void *ctx, struct sock *sk) > > > > +{ > > > > + struct loop_ctx lc = { .ctx = ctx, .sk = sk, }; > > > > + int n; > > > > + > > > > + n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0); > > > > + if (n != ARRAY_SIZE(sol_socket_tests)) > > > > + return -1; > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +SEC("sockops") > > > > +int skops_sockopt(struct bpf_sock_ops *skops) > > > > +{ > > > > + struct bpf_sock *bpf_sk = skops->sk; > > > > + struct sock *sk; > > > > + > > > > + if (!bpf_sk) > > > > + return 1; > > > > + > > > > + sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk); > > > > + if (!sk) > > > > + return 1; > > > > + > > > > + switch (skops->op) { > > > > + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: > > > > + nr_active += !bpf_test_sockopt(skops, sk); > > > > + break; > > > > + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: > > > > + nr_passive += !bpf_test_sockopt(skops, sk); > > > > + break; > > > > + case BPF_SOCK_OPS_TS_SCHED_OPT_CB: > > > > + nr_sched += 1; > > > > + break; > > > > + case BPF_SOCK_OPS_TS_SW_OPT_CB: > > > > + nr_txsw += 1; > > > > + break; > > > > + case BPF_SOCK_OPS_TS_ACK_OPT_CB: > > > > + nr_ack += 1; > > > > + break; > > > > > > Perhaps demonstrate what to do with the args on the new > > > TS_*_OPT_CB. > > > > Roger that. > > > > I would like to know if the current patch is too big to review? Should > > I split it into a few patches? But this series has 14 patches right > > now which could possibly exceed the maximum limit. > > For a test patch, this looks fine to me. They often are a longer than > feature patches. But much of it is easy to grasp. Got it, I will do it as you said. Thanks, Jason
On 10/28/24 4:05 AM, Jason Xing wrote: > From: Jason Xing <kernelxing@tencent.com> > > Only check if we pass those three key points after we enable the > bpf extension for so_timestamping. During each point, we can choose > whether to print the current timestamp. The bpf prog usually does more than just print. The bpf prog aggregates data first before sending all raw data to the user space. The selftests will be more useful for the reviewer and the future user if it can at least show how it can calculate the tx delay between [sendmsg, SCHED], [SCHED, SND], [SND, ACK]. [ ... ] > +SEC("sockops") > +int skops_sockopt(struct bpf_sock_ops *skops) > +{ > + struct bpf_sock *bpf_sk = skops->sk; > + struct sock *sk; > + > + if (!bpf_sk) > + return 1; > + > + sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk); > + if (!sk) > + return 1; > + > + switch (skops->op) { > + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: > + nr_active += !bpf_test_sockopt(skops, sk); > + break; > + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: > + nr_passive += !bpf_test_sockopt(skops, sk); > + break; > + case BPF_SOCK_OPS_TS_SCHED_OPT_CB: > + nr_sched += 1; > + break; > + case BPF_SOCK_OPS_TS_SW_OPT_CB: > + nr_txsw += 1; > + break; > + case BPF_SOCK_OPS_TS_ACK_OPT_CB: > + nr_ack += 1; > + break; > + } > + > + return 1; > +} > + > +char _license[] SEC("license") = "GPL";
On Wed, Oct 30, 2024 at 1:58 PM Martin KaFai Lau <martin.lau@linux.dev> wrote: > > On 10/28/24 4:05 AM, Jason Xing wrote: > > From: Jason Xing <kernelxing@tencent.com> > > > > Only check if we pass those three key points after we enable the > > bpf extension for so_timestamping. During each point, we can choose > > whether to print the current timestamp. > > The bpf prog usually does more than just print. The bpf prog aggregates data > first before sending all raw data to the user space. > > The selftests will be more useful for the reviewer and the future user if it can > at least show how it can calculate the tx delay between [sendmsg, SCHED], > [SCHED, SND], [SND, ACK]. Got it, I will dig into how to implement it and then post a new version. Before this, I only used the bpf program to print timestamps to one file without using those advanced functions (like aggregating data) in bpf. Let me try :) If you know some good examples of this, please show me :) Thanks in advance. Thanks, Jason
diff --git a/tools/testing/selftests/bpf/prog_tests/so_timestamping.c b/tools/testing/selftests/bpf/prog_tests/so_timestamping.c new file mode 100644 index 000000000000..dfb7588c246d --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/so_timestamping.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Tencent */ + +#define _GNU_SOURCE +#include <sched.h> +#include <linux/socket.h> +#include <linux/tls.h> +#include <net/if.h> + +#include "test_progs.h" +#include "cgroup_helpers.h" +#include "network_helpers.h" + +#include "so_timestamping.skel.h" + +#define CG_NAME "/so-timestamping-test" + +static const char addr4_str[] = "127.0.0.1"; +static const char addr6_str[] = "::1"; +static struct so_timestamping *skel; +static int cg_fd; + +static int create_netns(void) +{ + if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) + return -1; + + if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up")) + return -1; + + return 0; +} + +static void test_tcp(int family) +{ + struct so_timestamping__bss *bss = skel->bss; + char buf[] = "testing testing"; + int sfd = -1, cfd = -1; + int n; + + memset(bss, 0, sizeof(*bss)); + + sfd = start_server(family, SOCK_STREAM, + family == AF_INET6 ? addr6_str : addr4_str, 0, 0); + if (!ASSERT_GE(sfd, 0, "start_server")) + goto out; + + cfd = connect_to_fd(sfd, 0); + if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) { + close(sfd); + goto out; + } + + n = write(cfd, buf, sizeof(buf)); + if (!ASSERT_EQ(n, sizeof(buf), "send to server")) + goto out; + + ASSERT_EQ(bss->nr_active, 1, "nr_active"); + ASSERT_EQ(bss->nr_passive, 1, "nr_passive"); + ASSERT_EQ(bss->nr_sched, 1, "nr_sched"); + ASSERT_EQ(bss->nr_txsw, 1, "nr_txsw"); + ASSERT_EQ(bss->nr_ack, 1, "nr_ack"); + +out: + if (sfd >= 0) + close(sfd); + if (cfd >= 0) + close(cfd); +} + +void test_so_timestamping(void) +{ + cg_fd = test__join_cgroup(CG_NAME); + if (cg_fd < 0) + return; + + if (create_netns()) + goto done; + + skel = so_timestamping__open(); + if (!ASSERT_OK_PTR(skel, "open skel")) + goto done; + + if (!ASSERT_OK(so_timestamping__load(skel), "load skel")) + goto done; + + skel->links.skops_sockopt = + bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd); + if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup")) + goto done; + + test_tcp(AF_INET6); + test_tcp(AF_INET); + +done: + so_timestamping__destroy(skel); + close(cg_fd); +} diff --git a/tools/testing/selftests/bpf/progs/so_timestamping.c b/tools/testing/selftests/bpf/progs/so_timestamping.c new file mode 100644 index 000000000000..a15317951786 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/so_timestamping.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2024 Tencent */ + +#include "vmlinux.h" +#include "bpf_tracing_net.h" +#include <bpf/bpf_core_read.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include "bpf_misc.h" + +#define SO_TIMESTAMPING 37 +#define SOF_TIMESTAMPING_BPF_SUPPPORTED_MASK (SOF_TIMESTAMPING_SOFTWARE | \ + SOF_TIMESTAMPING_TX_SCHED | \ + SOF_TIMESTAMPING_TX_SOFTWARE | \ + SOF_TIMESTAMPING_TX_ACK | \ + SOF_TIMESTAMPING_OPT_ID | \ + SOF_TIMESTAMPING_OPT_ID_TCP) + +extern unsigned long CONFIG_HZ __kconfig; + +int nr_active; +int nr_passive; +int nr_sched; +int nr_txsw; +int nr_ack; + +struct sockopt_test { + int opt; + int new; + int expected; +}; + +static const struct sockopt_test sol_socket_tests[] = { + { .opt = SO_TIMESTAMPING, .new = SOF_TIMESTAMPING_TX_SCHED, .expected = 256, }, + { .opt = SO_TIMESTAMPING, .new = SOF_TIMESTAMPING_BPF_SUPPPORTED_MASK, .expected = 66450, }, + { .opt = 0, }, +}; + +struct loop_ctx { + void *ctx; + struct sock *sk; +}; + +static int bpf_test_sockopt_int(void *ctx, struct sock *sk, + const struct sockopt_test *t, + int level) +{ + int tmp, new, expected, opt; + + opt = t->opt; + new = t->new; + expected = t->expected; + + if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new))) + return 1; + if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) || + tmp != expected) + return 1; + + return 0; +} + +static int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc) +{ + const struct sockopt_test *t; + + if (i >= ARRAY_SIZE(sol_socket_tests)) + return 1; + + t = &sol_socket_tests[i]; + if (!t->opt) + return 1; + + return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET); +} + +static int bpf_test_sockopt(void *ctx, struct sock *sk) +{ + struct loop_ctx lc = { .ctx = ctx, .sk = sk, }; + int n; + + n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0); + if (n != ARRAY_SIZE(sol_socket_tests)) + return -1; + + return 0; +} + +SEC("sockops") +int skops_sockopt(struct bpf_sock_ops *skops) +{ + struct bpf_sock *bpf_sk = skops->sk; + struct sock *sk; + + if (!bpf_sk) + return 1; + + sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk); + if (!sk) + return 1; + + switch (skops->op) { + case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: + nr_active += !bpf_test_sockopt(skops, sk); + break; + case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: + nr_passive += !bpf_test_sockopt(skops, sk); + break; + case BPF_SOCK_OPS_TS_SCHED_OPT_CB: + nr_sched += 1; + break; + case BPF_SOCK_OPS_TS_SW_OPT_CB: + nr_txsw += 1; + break; + case BPF_SOCK_OPS_TS_ACK_OPT_CB: + nr_ack += 1; + break; + } + + return 1; +} + +char _license[] SEC("license") = "GPL";