Skip to content

Commit e1c83dd

Browse files
Geliang Tangintel-lab-lkp
authored andcommitted
selftests/bpf: Add getsockopt to inspect mptcp subflow
This patch adds a "cgroup/getsockopt" way to inspect the subflows of a mptcp socket. mptcp_for_each_stubflow() and other helpers related to list_dentry are added into progs/mptcp_bpf.h. Add an extra "cgroup/getsockopt" prog to walk the msk->conn_list and use bpf_core_cast to cast a pointer to tcp_sock for readonly. It will allow to inspect all the fields in a tcp_sock. Suggested-by: Martin KaFai Lau <[email protected]> Signed-off-by: Geliang Tang <[email protected]>
1 parent 69d56e8 commit e1c83dd

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

tools/testing/selftests/bpf/progs/mptcp_bpf.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,44 @@
44

55
#include <vmlinux.h>
66
#include <bpf/bpf_core_read.h>
7+
#include "bpf_experimental.h"
78

89
#define MPTCP_SUBFLOWS_MAX 8
910

11+
static inline int list_is_head(const struct list_head *list,
12+
const struct list_head *head)
13+
{
14+
return list == head;
15+
}
16+
17+
#define list_entry(ptr, type, member) \
18+
container_of(ptr, type, member)
19+
20+
#define list_first_entry(ptr, type, member) \
21+
list_entry((ptr)->next, type, member)
22+
23+
#define list_next_entry(pos, member) \
24+
list_entry((pos)->member.next, typeof(*(pos)), member)
25+
26+
#define list_entry_is_head(pos, head, member) \
27+
list_is_head(&pos->member, (head))
28+
29+
#define list_for_each_entry(pos, head, member) \
30+
for (pos = list_first_entry(head, typeof(*pos), member); \
31+
cond_break, !list_entry_is_head(pos, head, member); \
32+
pos = list_next_entry(pos, member))
33+
34+
#define list_for_each_entry_safe(pos, n, head, member) \
35+
for (pos = list_first_entry(head, typeof(*pos), member), \
36+
n = list_next_entry(pos, member); \
37+
cond_break, !list_entry_is_head(pos, head, member); \
38+
pos = n, n = list_next_entry(n, member))
39+
40+
#define mptcp_for_each_subflow(__msk, __subflow) \
41+
list_for_each_entry(__subflow, &((__msk)->conn_list), node)
42+
#define mptcp_for_each_subflow_safe(__msk, __subflow, __tmp) \
43+
list_for_each_entry_safe(__subflow, __tmp, &((__msk)->conn_list), node)
44+
1045
extern void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow,
1146
bool scheduled) __ksym;
1247

tools/testing/selftests/bpf/progs/mptcp_subflow.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
/* vmlinux.h, bpf_helpers.h and other 'define' */
66
#include "bpf_tracing_net.h"
7+
#include "mptcp_bpf.h"
78

89
char _license[] SEC("license") = "GPL";
910

@@ -57,3 +58,66 @@ int mptcp_subflow(struct bpf_sock_ops *skops)
5758

5859
return 1;
5960
}
61+
62+
static int _check_getsockopt_subflows_mark(struct mptcp_sock *msk, struct bpf_sockopt *ctx)
63+
{
64+
struct mptcp_subflow_context *subflow;
65+
int *optval = ctx->optval;
66+
67+
mptcp_for_each_subflow(msk, subflow) {
68+
struct sock *ssk;
69+
70+
ssk = mptcp_subflow_tcp_sock(bpf_core_cast(subflow,
71+
struct mptcp_subflow_context));
72+
73+
if (ctx->optval + sizeof(int) <= ctx->optval_end) {
74+
*optval = ssk->sk_mark;
75+
ctx->retval = 0;
76+
}
77+
}
78+
79+
return 1;
80+
}
81+
82+
static int _check_getsockopt_subflow_cc(struct mptcp_sock *msk, struct bpf_sockopt *ctx)
83+
{
84+
struct mptcp_subflow_context *subflow, *tmp;
85+
char *optval = ctx->optval;
86+
87+
mptcp_for_each_subflow_safe(msk, subflow, tmp) {
88+
struct inet_connection_sock *icsk;
89+
struct sock *ssk;
90+
91+
ssk = mptcp_subflow_tcp_sock(bpf_core_cast(subflow,
92+
struct mptcp_subflow_context));
93+
icsk = bpf_core_cast(ssk, struct inet_connection_sock);
94+
95+
if (ctx->optval + TCP_CA_NAME_MAX <= ctx->optval_end) {
96+
__builtin_memcpy(optval, icsk->icsk_ca_ops->name, TCP_CA_NAME_MAX);
97+
ctx->retval = 0;
98+
}
99+
}
100+
101+
return 1;
102+
}
103+
104+
SEC("cgroup/getsockopt")
105+
int _getsockopt_subflow(struct bpf_sockopt *ctx)
106+
{
107+
struct bpf_sock *sk = ctx->sk;
108+
struct mptcp_sock *msk;
109+
110+
if (!sk || sk->protocol != IPPROTO_MPTCP)
111+
return 1;
112+
113+
msk = bpf_core_cast(sk, struct mptcp_sock);
114+
if (msk->pm.subflows != 1)
115+
return 1;
116+
117+
if (ctx->level == SOL_SOCKET && ctx->optname == SO_MARK)
118+
return _check_getsockopt_subflows_mark(msk, ctx);
119+
if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION)
120+
return _check_getsockopt_subflow_cc(msk, ctx);
121+
122+
return 1;
123+
}

0 commit comments

Comments
 (0)