Message ID | 20220513224827.662254-4-mathew.j.martineau@linux.intel.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | BPF |
Headers | show |
Series | bpf: mptcp: Support for mptcp_sock | expand |
On Fri, May 13, 2022 at 3:48 PM Mat Martineau <mathew.j.martineau@linux.intel.com> wrote: > > From: Nicolas Rybowski <nicolas.rybowski@tessares.net> > > This patch adds a base for MPTCP specific tests. > > It is currently limited to the is_mptcp field in case of plain TCP > connection because there is no easy way to get the subflow sk from a msk > in userspace. This implies that we cannot lookup the sk_storage attached > to the subflow sk in the sockops program. > > v4: > - add copyright 2022 (Andrii) > - use ASSERT_* instead of CHECK_FAIL (Andrii) > - drop SEC("version") (Andrii) > - use is_mptcp in tcp_sock, instead of bpf_tcp_sock (Martin & Andrii) > > Acked-by: Matthieu Baerts <matthieu.baerts@tessares.net> > Co-developed-by: Geliang Tang <geliang.tang@suse.com> > Signed-off-by: Geliang Tang <geliang.tang@suse.com> > Signed-off-by: Nicolas Rybowski <nicolas.rybowski@tessares.net> > Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> > --- > MAINTAINERS | 1 + > tools/testing/selftests/bpf/bpf_tcp_helpers.h | 1 + > tools/testing/selftests/bpf/config | 1 + > tools/testing/selftests/bpf/network_helpers.c | 43 ++++-- > tools/testing/selftests/bpf/network_helpers.h | 4 + > .../testing/selftests/bpf/prog_tests/mptcp.c | 136 ++++++++++++++++++ > .../testing/selftests/bpf/progs/mptcp_sock.c | 53 +++++++ > 7 files changed, 231 insertions(+), 8 deletions(-) > create mode 100644 tools/testing/selftests/bpf/prog_tests/mptcp.c > create mode 100644 tools/testing/selftests/bpf/progs/mptcp_sock.c > Seems like bpf_core_field_exists() works fine for your use case and CI is green. See some selftest-specific issues below, though. [...] > +static int run_test(int cgroup_fd, int server_fd, bool is_mptcp) > +{ > + int client_fd, prog_fd, map_fd, err; > + struct bpf_program *prog; > + struct bpf_object *obj; > + struct bpf_map *map; > + > + obj = bpf_object__open("./mptcp_sock.o"); > + if (libbpf_get_error(obj)) > + return -EIO; > + > + err = bpf_object__load(obj); > + if (!ASSERT_OK(err, "bpf_object__load")) > + goto out; > + > + prog = bpf_object__find_program_by_name(obj, "_sockops"); can you please use BPF skeleton instead of doing these lookups by name? See other tests that are including .skel.h headers for example > + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) { > + err = -EIO; > + goto out; > + } > + [...] > +void test_base(void) > +{ > + int server_fd, cgroup_fd; > + > + cgroup_fd = test__join_cgroup("/mptcp"); > + if (CHECK_FAIL(cgroup_fd < 0)) > + return; > + > + /* without MPTCP */ > + server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0); > + if (CHECK_FAIL(server_fd < 0)) > + goto with_mptcp; > + > + CHECK_FAIL(run_test(cgroup_fd, server_fd, false)); please don't add new uses of CHECK_FAIL() > + > + close(server_fd); > + [...]
On Fri, May 13, 2022 at 03:48:23PM -0700, Mat Martineau wrote: [ ... ] > @@ -265,7 +282,7 @@ int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts) > } > > addr_in = (struct sockaddr_in *)&addr; > - fd = socket(addr_in->sin_family, type, 0); > + fd = socket(addr_in->sin_family, type, opts->protocol); ops->protocol is the same as the server_fd's protocol ? Can that be learned from getsockopt(server_fd, SOL_SOCKET, SO_PROTOCOL, ....) ? Then the ops->protocol additions and related changes are not needed. connect_to_fd_opts() has already obtained the SO_TYPE in similar way. > if (fd < 0) { > log_err("Failed to create client socket"); > return -1; > @@ -298,6 +315,16 @@ int connect_to_fd(int server_fd, int timeout_ms) > return connect_to_fd_opts(server_fd, &opts); > } > > +int connect_to_mptcp_fd(int server_fd, int timeout_ms) > +{ > + struct network_helper_opts opts = { > + .timeout_ms = timeout_ms, > + .protocol = IPPROTO_MPTCP, > + }; > + > + return connect_to_fd_opts(server_fd, &opts); > +} > + > int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms) > { > struct sockaddr_storage addr; > diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h > index a4b3b2f9877b..e0feb115b2ae 100644 > --- a/tools/testing/selftests/bpf/network_helpers.h > +++ b/tools/testing/selftests/bpf/network_helpers.h > @@ -21,6 +21,7 @@ struct network_helper_opts { > const char *cc; > int timeout_ms; > bool must_fail; > + int protocol; > }; > > /* ipv4 test vector */ > @@ -42,11 +43,14 @@ 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 start_mptcp_server(int family, const char *addr, __u16 port, > + int timeout_ms); > int *start_reuseport_server(int family, int type, const char *addr_str, > __u16 port, int timeout_ms, > unsigned int nr_listens); > void free_fds(int *fds, unsigned int nr_close_fds); > int connect_to_fd(int server_fd, int timeout_ms); > +int connect_to_mptcp_fd(int server_fd, int timeout_ms); > int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts); > int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms); > int fastopen_connect(int server_fd, const char *data, unsigned int data_len,
Martin KaFai Lau <kafai@fb.com> 于2022年5月17日周二 09:18写道: > > On Fri, May 13, 2022 at 03:48:23PM -0700, Mat Martineau wrote: > [ ... ] > > > @@ -265,7 +282,7 @@ int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts) > > } > > > > addr_in = (struct sockaddr_in *)&addr; > > - fd = socket(addr_in->sin_family, type, 0); > > + fd = socket(addr_in->sin_family, type, opts->protocol); > ops->protocol is the same as the server_fd's protocol ? > > Can that be learned from getsockopt(server_fd, SOL_SOCKET, SO_PROTOCOL, ....) ? > Then the ops->protocol additions and related changes are not needed. Yes, I will update this in v5. > > connect_to_fd_opts() has already obtained the SO_TYPE in similar way. > > > if (fd < 0) { > > log_err("Failed to create client socket"); > > return -1; > > @@ -298,6 +315,16 @@ int connect_to_fd(int server_fd, int timeout_ms) > > return connect_to_fd_opts(server_fd, &opts); > > } > > > > +int connect_to_mptcp_fd(int server_fd, int timeout_ms) > > +{ > > + struct network_helper_opts opts = { > > + .timeout_ms = timeout_ms, > > + .protocol = IPPROTO_MPTCP, > > + }; > > + > > + return connect_to_fd_opts(server_fd, &opts); > > +} > > + > > int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms) > > { > > struct sockaddr_storage addr; > > diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h > > index a4b3b2f9877b..e0feb115b2ae 100644 > > --- a/tools/testing/selftests/bpf/network_helpers.h > > +++ b/tools/testing/selftests/bpf/network_helpers.h > > @@ -21,6 +21,7 @@ struct network_helper_opts { > > const char *cc; > > int timeout_ms; > > bool must_fail; > > + int protocol; > > }; > > > > /* ipv4 test vector */ > > @@ -42,11 +43,14 @@ 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 start_mptcp_server(int family, const char *addr, __u16 port, > > + int timeout_ms); > > int *start_reuseport_server(int family, int type, const char *addr_str, > > __u16 port, int timeout_ms, > > unsigned int nr_listens); > > void free_fds(int *fds, unsigned int nr_close_fds); > > int connect_to_fd(int server_fd, int timeout_ms); > > +int connect_to_mptcp_fd(int server_fd, int timeout_ms); > > int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts); > > int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms); > > int fastopen_connect(int server_fd, const char *data, unsigned int data_len, >
Andrii Nakryiko <andrii.nakryiko@gmail.com> 于2022年5月17日周二 06:43写道: > > On Fri, May 13, 2022 at 3:48 PM Mat Martineau > <mathew.j.martineau@linux.intel.com> wrote: > > > > From: Nicolas Rybowski <nicolas.rybowski@tessares.net> > > > > This patch adds a base for MPTCP specific tests. > > > > It is currently limited to the is_mptcp field in case of plain TCP > > connection because there is no easy way to get the subflow sk from a msk > > in userspace. This implies that we cannot lookup the sk_storage attached > > to the subflow sk in the sockops program. > > > > v4: > > - add copyright 2022 (Andrii) > > - use ASSERT_* instead of CHECK_FAIL (Andrii) > > - drop SEC("version") (Andrii) > > - use is_mptcp in tcp_sock, instead of bpf_tcp_sock (Martin & Andrii) > > > > Acked-by: Matthieu Baerts <matthieu.baerts@tessares.net> > > Co-developed-by: Geliang Tang <geliang.tang@suse.com> > > Signed-off-by: Geliang Tang <geliang.tang@suse.com> > > Signed-off-by: Nicolas Rybowski <nicolas.rybowski@tessares.net> > > Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com> > > --- > > MAINTAINERS | 1 + > > tools/testing/selftests/bpf/bpf_tcp_helpers.h | 1 + > > tools/testing/selftests/bpf/config | 1 + > > tools/testing/selftests/bpf/network_helpers.c | 43 ++++-- > > tools/testing/selftests/bpf/network_helpers.h | 4 + > > .../testing/selftests/bpf/prog_tests/mptcp.c | 136 ++++++++++++++++++ > > .../testing/selftests/bpf/progs/mptcp_sock.c | 53 +++++++ > > 7 files changed, 231 insertions(+), 8 deletions(-) > > create mode 100644 tools/testing/selftests/bpf/prog_tests/mptcp.c > > create mode 100644 tools/testing/selftests/bpf/progs/mptcp_sock.c > > > > Seems like bpf_core_field_exists() works fine for your use case and CI > is green. See some selftest-specific issues below, though. > > [...] > > > +static int run_test(int cgroup_fd, int server_fd, bool is_mptcp) > > +{ > > + int client_fd, prog_fd, map_fd, err; > > + struct bpf_program *prog; > > + struct bpf_object *obj; > > + struct bpf_map *map; > > + > > + obj = bpf_object__open("./mptcp_sock.o"); > > + if (libbpf_get_error(obj)) > > + return -EIO; > > + > > + err = bpf_object__load(obj); > > + if (!ASSERT_OK(err, "bpf_object__load")) > > + goto out; > > + > > + prog = bpf_object__find_program_by_name(obj, "_sockops"); > > can you please use BPF skeleton instead of doing these lookups by > name? See other tests that are including .skel.h headers for example Sure, I will update this in v5. > > > + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) { > > + err = -EIO; > > + goto out; > > + } > > + > > [...] > > > +void test_base(void) > > +{ > > + int server_fd, cgroup_fd; > > + > > + cgroup_fd = test__join_cgroup("/mptcp"); > > + if (CHECK_FAIL(cgroup_fd < 0)) > > + return; > > + > > + /* without MPTCP */ > > + server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0); > > + if (CHECK_FAIL(server_fd < 0)) > > + goto with_mptcp; > > + > > + CHECK_FAIL(run_test(cgroup_fd, server_fd, false)); > > please don't add new uses of CHECK_FAIL() > > > + > > + close(server_fd); > > + > > [...] >
diff --git a/MAINTAINERS b/MAINTAINERS index cc5559a7fb5c..359afc617b92 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13780,6 +13780,7 @@ F: include/net/mptcp.h F: include/trace/events/mptcp.h F: include/uapi/linux/mptcp.h F: net/mptcp/ +F: tools/testing/selftests/bpf/*/*mptcp*.c F: tools/testing/selftests/net/mptcp/ NETWORKING [TCP] diff --git a/tools/testing/selftests/bpf/bpf_tcp_helpers.h b/tools/testing/selftests/bpf/bpf_tcp_helpers.h index b1ede6f0b821..22e0c8849a17 100644 --- a/tools/testing/selftests/bpf/bpf_tcp_helpers.h +++ b/tools/testing/selftests/bpf/bpf_tcp_helpers.h @@ -81,6 +81,7 @@ struct tcp_sock { __u32 lsndtime; __u32 prior_cwnd; __u64 tcp_mstamp; /* most recent packet received/sent */ + bool is_mptcp; } __attribute__((preserve_access_index)); static __always_inline struct inet_connection_sock *inet_csk(const struct sock *sk) diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 6840d4625e01..3b3edc0fc8a6 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -56,3 +56,4 @@ CONFIG_USERFAULTFD=y CONFIG_FPROBE=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_MPTCP=y diff --git a/tools/testing/selftests/bpf/network_helpers.c b/tools/testing/selftests/bpf/network_helpers.c index 2bb1f9b3841d..c9a2e39e34fc 100644 --- a/tools/testing/selftests/bpf/network_helpers.c +++ b/tools/testing/selftests/bpf/network_helpers.c @@ -21,6 +21,10 @@ #include "network_helpers.h" #include "test_progs.h" +#ifndef IPPROTO_MPTCP +#define IPPROTO_MPTCP 262 +#endif + #define clean_errno() (errno == 0 ? "None" : strerror(errno)) #define log_err(MSG, ...) ({ \ int __save = errno; \ @@ -73,13 +77,13 @@ int settimeo(int fd, int timeout_ms) #define save_errno_close(fd) ({ int __save = errno; close(fd); errno = __save; }) -static int __start_server(int type, const struct sockaddr *addr, +static int __start_server(int type, int protocol, const struct sockaddr *addr, socklen_t addrlen, int timeout_ms, bool reuseport) { int on = 1; int fd; - fd = socket(addr->sa_family, type, 0); + fd = socket(addr->sa_family, type, protocol); if (fd < 0) { log_err("Failed to create server socket"); return -1; @@ -113,8 +117,8 @@ static int __start_server(int type, const struct sockaddr *addr, return -1; } -int start_server(int family, int type, const char *addr_str, __u16 port, - int timeout_ms) +static int start_server_proto(int family, int type, int protocol, + const char *addr_str, __u16 port, int timeout_ms) { struct sockaddr_storage addr; socklen_t addrlen; @@ -122,10 +126,23 @@ int start_server(int family, int type, const char *addr_str, __u16 port, if (make_sockaddr(family, addr_str, port, &addr, &addrlen)) return -1; - return __start_server(type, (struct sockaddr *)&addr, + return __start_server(type, protocol, (struct sockaddr *)&addr, addrlen, timeout_ms, false); } +int start_server(int family, int type, const char *addr_str, __u16 port, + int timeout_ms) +{ + return start_server_proto(family, type, 0, addr_str, port, timeout_ms); +} + +int start_mptcp_server(int family, const char *addr_str, __u16 port, + int timeout_ms) +{ + return start_server_proto(family, SOCK_STREAM, IPPROTO_MPTCP, addr_str, + port, timeout_ms); +} + int *start_reuseport_server(int family, int type, const char *addr_str, __u16 port, int timeout_ms, unsigned int nr_listens) { @@ -144,7 +161,7 @@ int *start_reuseport_server(int family, int type, const char *addr_str, if (!fds) return NULL; - fds[0] = __start_server(type, (struct sockaddr *)&addr, addrlen, + fds[0] = __start_server(type, 0, (struct sockaddr *)&addr, addrlen, timeout_ms, true); if (fds[0] == -1) goto close_fds; @@ -154,7 +171,7 @@ int *start_reuseport_server(int family, int type, const char *addr_str, goto close_fds; for (; nr_fds < nr_listens; nr_fds++) { - fds[nr_fds] = __start_server(type, (struct sockaddr *)&addr, + fds[nr_fds] = __start_server(type, 0, (struct sockaddr *)&addr, addrlen, timeout_ms, true); if (fds[nr_fds] == -1) goto close_fds; @@ -265,7 +282,7 @@ int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts) } addr_in = (struct sockaddr_in *)&addr; - fd = socket(addr_in->sin_family, type, 0); + fd = socket(addr_in->sin_family, type, opts->protocol); if (fd < 0) { log_err("Failed to create client socket"); return -1; @@ -298,6 +315,16 @@ int connect_to_fd(int server_fd, int timeout_ms) return connect_to_fd_opts(server_fd, &opts); } +int connect_to_mptcp_fd(int server_fd, int timeout_ms) +{ + struct network_helper_opts opts = { + .timeout_ms = timeout_ms, + .protocol = IPPROTO_MPTCP, + }; + + return connect_to_fd_opts(server_fd, &opts); +} + int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms) { struct sockaddr_storage addr; diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h index a4b3b2f9877b..e0feb115b2ae 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -21,6 +21,7 @@ struct network_helper_opts { const char *cc; int timeout_ms; bool must_fail; + int protocol; }; /* ipv4 test vector */ @@ -42,11 +43,14 @@ 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 start_mptcp_server(int family, const char *addr, __u16 port, + int timeout_ms); int *start_reuseport_server(int family, int type, const char *addr_str, __u16 port, int timeout_ms, unsigned int nr_listens); void free_fds(int *fds, unsigned int nr_close_fds); int connect_to_fd(int server_fd, int timeout_ms); +int connect_to_mptcp_fd(int server_fd, int timeout_ms); int connect_to_fd_opts(int server_fd, const struct network_helper_opts *opts); int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms); int fastopen_connect(int server_fd, const char *data, unsigned int data_len, diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c new file mode 100644 index 000000000000..cb0389ca8690 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2020, Tessares SA. */ +/* Copyright (c) 2022, SUSE. */ + +#include <test_progs.h> +#include "cgroup_helpers.h" +#include "network_helpers.h" + +struct mptcp_storage { + __u32 invoked; + __u32 is_mptcp; +}; + +static int verify_sk(int map_fd, int client_fd, const char *msg, __u32 is_mptcp) +{ + int err, cfd = client_fd; + struct mptcp_storage val; + + if (is_mptcp == 1) + return 0; + + err = bpf_map_lookup_elem(map_fd, &cfd, &val); + if (!ASSERT_OK(err, "bpf_map_lookup_elem")) + return err; + + if (val.invoked != 1) { + log_err("%s: unexpected invoked count %d != 1", + msg, val.invoked); + err++; + } + + if (val.is_mptcp != 0) { + log_err("%s: unexpected bpf_tcp_sock.is_mptcp %d != 0", + msg, val.is_mptcp); + err++; + } + + return err; +} + +static int run_test(int cgroup_fd, int server_fd, bool is_mptcp) +{ + int client_fd, prog_fd, map_fd, err; + struct bpf_program *prog; + struct bpf_object *obj; + struct bpf_map *map; + + obj = bpf_object__open("./mptcp_sock.o"); + if (libbpf_get_error(obj)) + return -EIO; + + err = bpf_object__load(obj); + if (!ASSERT_OK(err, "bpf_object__load")) + goto out; + + prog = bpf_object__find_program_by_name(obj, "_sockops"); + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) { + err = -EIO; + goto out; + } + + prog_fd = bpf_program__fd(prog); + if (!ASSERT_GE(prog_fd, 0, "bpf_program__fd")) { + err = -EIO; + goto out; + } + + map = bpf_object__find_map_by_name(obj, "socket_storage_map"); + if (!ASSERT_OK_PTR(map, "bpf_object__find_map_by_name")) { + err = -EIO; + goto out; + } + + map_fd = bpf_map__fd(map); + if (!ASSERT_GE(map_fd, 0, "bpf_map__fd")) { + err = -EIO; + goto out; + } + + err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0); + if (!ASSERT_OK(err, "bpf_prog_attach")) + goto out; + + client_fd = is_mptcp ? connect_to_mptcp_fd(server_fd, 0) : + connect_to_fd(server_fd, 0); + if (!ASSERT_GE(client_fd, 0, "connect to fd")) { + err = -EIO; + goto out; + } + + err += is_mptcp ? verify_sk(map_fd, client_fd, "MPTCP subflow socket", 1) : + verify_sk(map_fd, client_fd, "plain TCP socket", 0); + + close(client_fd); + +out: + bpf_object__close(obj); + return err; +} + +void test_base(void) +{ + int server_fd, cgroup_fd; + + cgroup_fd = test__join_cgroup("/mptcp"); + if (CHECK_FAIL(cgroup_fd < 0)) + return; + + /* without MPTCP */ + server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0); + if (CHECK_FAIL(server_fd < 0)) + goto with_mptcp; + + CHECK_FAIL(run_test(cgroup_fd, server_fd, false)); + + close(server_fd); + +with_mptcp: + /* with MPTCP */ + server_fd = start_mptcp_server(AF_INET, NULL, 0, 0); + if (CHECK_FAIL(server_fd < 0)) + goto close_cgroup_fd; + + CHECK_FAIL(run_test(cgroup_fd, server_fd, true)); + + close(server_fd); + +close_cgroup_fd: + close(cgroup_fd); +} + +void test_mptcp(void) +{ + if (test__start_subtest("base")) + test_base(); +} diff --git a/tools/testing/selftests/bpf/progs/mptcp_sock.c b/tools/testing/selftests/bpf/progs/mptcp_sock.c new file mode 100644 index 000000000000..bc09dba0b078 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/mptcp_sock.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2020, Tessares SA. */ +/* Copyright (c) 2022, SUSE. */ + +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> +#include "bpf_tcp_helpers.h" + +char _license[] SEC("license") = "GPL"; + +struct mptcp_storage { + __u32 invoked; + __u32 is_mptcp; +}; + +struct { + __uint(type, BPF_MAP_TYPE_SK_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, int); + __type(value, struct mptcp_storage); +} socket_storage_map SEC(".maps"); + +SEC("sockops") +int _sockops(struct bpf_sock_ops *ctx) +{ + struct mptcp_storage *storage; + int op = (int)ctx->op; + struct tcp_sock *tsk; + struct bpf_sock *sk; + bool is_mptcp; + + if (op != BPF_SOCK_OPS_TCP_CONNECT_CB) + return 1; + + sk = ctx->sk; + if (!sk) + return 1; + + tsk = bpf_skc_to_tcp_sock(sk); + if (!tsk) + return 1; + + is_mptcp = bpf_core_field_exists(tsk->is_mptcp) ? tsk->is_mptcp : 0; + storage = bpf_sk_storage_get(&socket_storage_map, sk, 0, + BPF_SK_STORAGE_GET_F_CREATE); + if (!storage) + return 1; + + storage->invoked++; + storage->is_mptcp = is_mptcp; + + return 1; +}