Skip to content

Commit b2739bf

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 fc0f0a0 commit b2739bf

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

tools/testing/selftests/bpf/prog_tests/mptcp.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,10 @@ static int endpoint_init(char *flags)
371371
static void run_subflow(void)
372372
{
373373
int server_fd, client_fd;
374+
char cc[TCP_CA_NAME_MAX];
375+
unsigned int mark;
376+
socklen_t len;
377+
int err;
374378

375379
server_fd = start_mptcp_server(AF_INET, ADDR_1, PORT_1, 0);
376380
if (!ASSERT_GE(server_fd, 0, "start_mptcp_server"))
@@ -382,6 +386,18 @@ static void run_subflow(void)
382386

383387
send_byte(client_fd);
384388

389+
sleep(0.1);
390+
391+
len = sizeof(mark);
392+
err = getsockopt(client_fd, SOL_SOCKET, SO_MARK, &mark, &len);
393+
if (!ASSERT_OK(err, "getsockopt(client_fd, SO_MARK)"))
394+
goto close_client;
395+
396+
len = sizeof(cc);
397+
err = getsockopt(client_fd, SOL_TCP, TCP_CONGESTION, cc, &len);
398+
ASSERT_OK(err, "getsockopt(client_fd, TCP_CONGESTION)");
399+
400+
close_client:
385401
close(client_fd);
386402
close_server:
387403
close(server_fd);
@@ -392,6 +408,7 @@ static void test_subflow(void)
392408
int cgroup_fd, prog_fd, err;
393409
struct mptcp_subflow *skel;
394410
struct nstoken *nstoken;
411+
struct bpf_link *link;
395412

396413
cgroup_fd = test__join_cgroup("/mptcp_subflow");
397414
if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup: mptcp_subflow"))
@@ -417,6 +434,11 @@ static void test_subflow(void)
417434
if (endpoint_init("subflow") < 0)
418435
goto close_netns;
419436

437+
link = bpf_program__attach_cgroup(skel->progs._getsockopt_subflow,
438+
cgroup_fd);
439+
if (!ASSERT_OK_PTR(link, "getsockopt prog"))
440+
goto close_netns;
441+
420442
run_subflow();
421443

422444
close_netns:
@@ -425,6 +447,7 @@ static void test_subflow(void)
425447
mptcp_subflow__destroy(skel);
426448
close_cgroup:
427449
close(cgroup_fd);
450+
bpf_link__destroy(link);
428451
}
429452

430453
static struct nstoken *sched_init(char *flags, char *sched)

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+
!list_entry_is_head(pos, head, member); \
32+
cond_break, 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+
!list_entry_is_head(pos, head, member); \
38+
cond_break, 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: 55 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,57 @@ 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 i = 0;
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 (ssk->sk_mark != ++i)
74+
ctx->retval = -1;
75+
}
76+
77+
return 1;
78+
}
79+
80+
static int _check_getsockopt_subflow_cc(struct mptcp_sock *msk, struct bpf_sockopt *ctx)
81+
{
82+
struct mptcp_subflow_context *subflow, *tmp;
83+
84+
mptcp_for_each_subflow_safe(msk, subflow, tmp) {
85+
struct inet_connection_sock *icsk;
86+
struct sock *ssk;
87+
88+
ssk = mptcp_subflow_tcp_sock(bpf_core_cast(subflow,
89+
struct mptcp_subflow_context));
90+
icsk = bpf_core_cast(ssk, struct inet_connection_sock);
91+
92+
if (ssk->sk_mark == 1 &&
93+
__builtin_memcmp(icsk->icsk_ca_ops->name, cc, TCP_CA_NAME_MAX))
94+
ctx->retval = -1;
95+
}
96+
97+
return 1;
98+
}
99+
100+
SEC("cgroup/getsockopt")
101+
int _getsockopt_subflow(struct bpf_sockopt *ctx)
102+
{
103+
struct mptcp_sock *msk = bpf_core_cast(ctx->sk, struct mptcp_sock);
104+
105+
if (!msk || !msk->token)
106+
return 1;
107+
108+
if (ctx->level == SOL_SOCKET && ctx->optname == SO_MARK)
109+
return _check_getsockopt_subflows_mark(msk, ctx);
110+
if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION)
111+
return _check_getsockopt_subflow_cc(msk, ctx);
112+
113+
return 1;
114+
}

0 commit comments

Comments
 (0)