Skip to content

Commit 7f8e5ce

Browse files
nrybowskikernel-patches-bot
authored andcommitted
In order to precisely identify the parent MPTCP connection of a subflow,
it is required to access the mptcp_sock's token which uniquely identify a MPTCP connection. This patch adds a new structure 'bpf_mptcp_sock' exposing the 'token' field of the 'mptcp_sock' extracted from a subflow's 'tcp_sock'. It also adds the declaration of a new BPF helper of the same name to expose the newly defined structure in the userspace BPF API. This is the foundation to expose more MPTCP-specific fields through BPF. Currently, it is limited to the field 'token' of the msk but it is easily extensible. Acked-by: Matthieu Baerts <matthieu.baerts@tessares.net> Acked-by: Mat Martineau <mathew.j.martineau@linux.intel.com> Acked-by: Song Liu <songliubraving@fb.com> Signed-off-by: Nicolas Rybowski <nicolas.rybowski@tessares.net> --- include/linux/bpf.h | 33 ++++++++++++++++ include/uapi/linux/bpf.h | 14 +++++++ kernel/bpf/verifier.c | 30 ++++++++++++++ net/core/filter.c | 4 ++ net/mptcp/Makefile | 2 + net/mptcp/bpf.c | 72 ++++++++++++++++++++++++++++++++++ scripts/bpf_helpers_doc.py | 2 + tools/include/uapi/linux/bpf.h | 14 +++++++ 8 files changed, 171 insertions(+) create mode 100644 net/mptcp/bpf.c
1 parent c19f6df commit 7f8e5ce

File tree

8 files changed

+171
-0
lines changed

8 files changed

+171
-0
lines changed

include/linux/bpf.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ enum bpf_return_type {
305305
RET_PTR_TO_SOCK_COMMON_OR_NULL, /* returns a pointer to a sock_common or NULL */
306306
RET_PTR_TO_ALLOC_MEM_OR_NULL, /* returns a pointer to dynamically allocated memory or NULL */
307307
RET_PTR_TO_BTF_ID_OR_NULL, /* returns a pointer to a btf_id or NULL */
308+
RET_PTR_TO_MPTCP_SOCK_OR_NULL, /* returns a pointer to mptcp_sock or NULL */
308309
};
309310

310311
/* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs
@@ -385,6 +386,8 @@ enum bpf_reg_type {
385386
PTR_TO_RDONLY_BUF_OR_NULL, /* reg points to a readonly buffer or NULL */
386387
PTR_TO_RDWR_BUF, /* reg points to a read/write buffer */
387388
PTR_TO_RDWR_BUF_OR_NULL, /* reg points to a read/write buffer or NULL */
389+
PTR_TO_MPTCP_SOCK, /* reg points to struct mptcp_sock */
390+
PTR_TO_MPTCP_SOCK_OR_NULL, /* reg points to struct mptcp_sock or NULL */
388391
};
389392

390393
/* The information passed from prog-specific *_is_valid_access
@@ -1790,6 +1793,7 @@ extern const struct bpf_func_proto bpf_skc_to_tcp_timewait_sock_proto;
17901793
extern const struct bpf_func_proto bpf_skc_to_tcp_request_sock_proto;
17911794
extern const struct bpf_func_proto bpf_skc_to_udp6_sock_proto;
17921795
extern const struct bpf_func_proto bpf_copy_from_user_proto;
1796+
extern const struct bpf_func_proto bpf_mptcp_sock_proto;
17931797

17941798
const struct bpf_func_proto *bpf_tracing_func_proto(
17951799
enum bpf_func_id func_id, const struct bpf_prog *prog);
@@ -1846,6 +1850,35 @@ struct sk_reuseport_kern {
18461850
u32 reuseport_id;
18471851
bool bind_inany;
18481852
};
1853+
1854+
#ifdef CONFIG_MPTCP
1855+
bool bpf_mptcp_sock_is_valid_access(int off, int size,
1856+
enum bpf_access_type type,
1857+
struct bpf_insn_access_aux *info);
1858+
1859+
u32 bpf_mptcp_sock_convert_ctx_access(enum bpf_access_type type,
1860+
const struct bpf_insn *si,
1861+
struct bpf_insn *insn_buf,
1862+
struct bpf_prog *prog,
1863+
u32 *target_size);
1864+
#else /* CONFIG_MPTCP */
1865+
static inline bool bpf_mptcp_sock_is_valid_access(int off, int size,
1866+
enum bpf_access_type type,
1867+
struct bpf_insn_access_aux *info)
1868+
{
1869+
return false;
1870+
}
1871+
1872+
static inline u32 bpf_mptcp_sock_convert_ctx_access(enum bpf_access_type type,
1873+
const struct bpf_insn *si,
1874+
struct bpf_insn *insn_buf,
1875+
struct bpf_prog *prog,
1876+
u32 *target_size)
1877+
{
1878+
return 0;
1879+
}
1880+
#endif /* CONFIG_MPTCP */
1881+
18491882
bool bpf_tcp_sock_is_valid_access(int off, int size, enum bpf_access_type type,
18501883
struct bpf_insn_access_aux *info);
18511884

include/uapi/linux/bpf.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3586,6 +3586,15 @@ union bpf_attr {
35863586
* the data in *dst*. This is a wrapper of **copy_from_user**\ ().
35873587
* Return
35883588
* 0 on success, or a negative error in case of failure.
3589+
*
3590+
* struct bpf_mptcp_sock *bpf_mptcp_sock(struct bpf_sock *sk)
3591+
* Description
3592+
* This helper gets a **struct bpf_mptcp_sock** pointer from a
3593+
* **struct bpf_sock** pointer.
3594+
* Return
3595+
* A **struct bpf_mptcp_sock** pointer on success, or **NULL** in
3596+
* case of failure.
3597+
*
35893598
*/
35903599
#define __BPF_FUNC_MAPPER(FN) \
35913600
FN(unspec), \
@@ -3737,6 +3746,7 @@ union bpf_attr {
37373746
FN(inode_storage_delete), \
37383747
FN(d_path), \
37393748
FN(copy_from_user), \
3749+
FN(mptcp_sock), \
37403750
/* */
37413751

37423752
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -4070,6 +4080,10 @@ struct bpf_tcp_sock {
40704080
__u32 is_mptcp; /* Is MPTCP subflow? */
40714081
};
40724082

4083+
struct bpf_mptcp_sock {
4084+
__u32 token; /* msk token */
4085+
};
4086+
40734087
struct bpf_sock_tuple {
40744088
union {
40754089
struct {

kernel/bpf/verifier.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,13 +392,15 @@ static bool type_is_sk_pointer(enum bpf_reg_type type)
392392
return type == PTR_TO_SOCKET ||
393393
type == PTR_TO_SOCK_COMMON ||
394394
type == PTR_TO_TCP_SOCK ||
395+
type == PTR_TO_MPTCP_SOCK ||
395396
type == PTR_TO_XDP_SOCK;
396397
}
397398

398399
static bool reg_type_not_null(enum bpf_reg_type type)
399400
{
400401
return type == PTR_TO_SOCKET ||
401402
type == PTR_TO_TCP_SOCK ||
403+
type == PTR_TO_MPTCP_SOCK ||
402404
type == PTR_TO_MAP_VALUE ||
403405
type == PTR_TO_SOCK_COMMON;
404406
}
@@ -409,6 +411,7 @@ static bool reg_type_may_be_null(enum bpf_reg_type type)
409411
type == PTR_TO_SOCKET_OR_NULL ||
410412
type == PTR_TO_SOCK_COMMON_OR_NULL ||
411413
type == PTR_TO_TCP_SOCK_OR_NULL ||
414+
type == PTR_TO_MPTCP_SOCK_OR_NULL ||
412415
type == PTR_TO_BTF_ID_OR_NULL ||
413416
type == PTR_TO_MEM_OR_NULL ||
414417
type == PTR_TO_RDONLY_BUF_OR_NULL ||
@@ -427,6 +430,8 @@ static bool reg_type_may_be_refcounted_or_null(enum bpf_reg_type type)
427430
type == PTR_TO_SOCKET_OR_NULL ||
428431
type == PTR_TO_TCP_SOCK ||
429432
type == PTR_TO_TCP_SOCK_OR_NULL ||
433+
type == PTR_TO_MPTCP_SOCK ||
434+
type == PTR_TO_MPTCP_SOCK_OR_NULL ||
430435
type == PTR_TO_MEM ||
431436
type == PTR_TO_MEM_OR_NULL;
432437
}
@@ -500,6 +505,8 @@ static const char * const reg_type_str[] = {
500505
[PTR_TO_SOCK_COMMON_OR_NULL] = "sock_common_or_null",
501506
[PTR_TO_TCP_SOCK] = "tcp_sock",
502507
[PTR_TO_TCP_SOCK_OR_NULL] = "tcp_sock_or_null",
508+
[PTR_TO_MPTCP_SOCK] = "mptcp_sock",
509+
[PTR_TO_MPTCP_SOCK_OR_NULL] = "mptcp_sock_or_null",
503510
[PTR_TO_TP_BUFFER] = "tp_buffer",
504511
[PTR_TO_XDP_SOCK] = "xdp_sock",
505512
[PTR_TO_BTF_ID] = "ptr_",
@@ -2184,6 +2191,8 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
21842191
case PTR_TO_SOCK_COMMON_OR_NULL:
21852192
case PTR_TO_TCP_SOCK:
21862193
case PTR_TO_TCP_SOCK_OR_NULL:
2194+
case PTR_TO_MPTCP_SOCK:
2195+
case PTR_TO_MPTCP_SOCK_OR_NULL:
21872196
case PTR_TO_XDP_SOCK:
21882197
case PTR_TO_BTF_ID:
21892198
case PTR_TO_BTF_ID_OR_NULL:
@@ -2793,6 +2802,9 @@ static int check_sock_access(struct bpf_verifier_env *env, int insn_idx,
27932802
case PTR_TO_TCP_SOCK:
27942803
valid = bpf_tcp_sock_is_valid_access(off, size, t, &info);
27952804
break;
2805+
case PTR_TO_MPTCP_SOCK:
2806+
valid = bpf_mptcp_sock_is_valid_access(off, size, t, &info);
2807+
break;
27962808
case PTR_TO_XDP_SOCK:
27972809
valid = bpf_xdp_sock_is_valid_access(off, size, t, &info);
27982810
break;
@@ -2951,6 +2963,9 @@ static int check_ptr_alignment(struct bpf_verifier_env *env,
29512963
case PTR_TO_TCP_SOCK:
29522964
pointer_desc = "tcp_sock ";
29532965
break;
2966+
case PTR_TO_MPTCP_SOCK:
2967+
pointer_desc = "mptcp_sock ";
2968+
break;
29542969
case PTR_TO_XDP_SOCK:
29552970
pointer_desc = "xdp_sock ";
29562971
break;
@@ -5049,6 +5064,10 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
50495064
mark_reg_known_zero(env, regs, BPF_REG_0);
50505065
regs[BPF_REG_0].type = PTR_TO_TCP_SOCK_OR_NULL;
50515066
regs[BPF_REG_0].id = ++env->id_gen;
5067+
} else if (fn->ret_type == RET_PTR_TO_MPTCP_SOCK_OR_NULL) {
5068+
mark_reg_known_zero(env, regs, BPF_REG_0);
5069+
regs[BPF_REG_0].type = PTR_TO_MPTCP_SOCK_OR_NULL;
5070+
regs[BPF_REG_0].id = ++env->id_gen;
50525071
} else if (fn->ret_type == RET_PTR_TO_ALLOC_MEM_OR_NULL) {
50535072
mark_reg_known_zero(env, regs, BPF_REG_0);
50545073
regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL;
@@ -5380,6 +5399,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
53805399
case PTR_TO_SOCK_COMMON_OR_NULL:
53815400
case PTR_TO_TCP_SOCK:
53825401
case PTR_TO_TCP_SOCK_OR_NULL:
5402+
case PTR_TO_MPTCP_SOCK:
5403+
case PTR_TO_MPTCP_SOCK_OR_NULL:
53835404
case PTR_TO_XDP_SOCK:
53845405
verbose(env, "R%d pointer arithmetic on %s prohibited\n",
53855406
dst, reg_type_str[ptr_reg->type]);
@@ -7100,6 +7121,8 @@ static void mark_ptr_or_null_reg(struct bpf_func_state *state,
71007121
reg->type = PTR_TO_SOCK_COMMON;
71017122
} else if (reg->type == PTR_TO_TCP_SOCK_OR_NULL) {
71027123
reg->type = PTR_TO_TCP_SOCK;
7124+
} else if (reg->type == PTR_TO_MPTCP_SOCK_OR_NULL) {
7125+
reg->type = PTR_TO_MPTCP_SOCK;
71037126
} else if (reg->type == PTR_TO_BTF_ID_OR_NULL) {
71047127
reg->type = PTR_TO_BTF_ID;
71057128
} else if (reg->type == PTR_TO_MEM_OR_NULL) {
@@ -8489,6 +8512,8 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
84898512
case PTR_TO_SOCK_COMMON_OR_NULL:
84908513
case PTR_TO_TCP_SOCK:
84918514
case PTR_TO_TCP_SOCK_OR_NULL:
8515+
case PTR_TO_MPTCP_SOCK:
8516+
case PTR_TO_MPTCP_SOCK_OR_NULL:
84928517
case PTR_TO_XDP_SOCK:
84938518
/* Only valid matches are exact, which memcmp() above
84948519
* would have accepted
@@ -9016,6 +9041,8 @@ static bool reg_type_mismatch_ok(enum bpf_reg_type type)
90169041
case PTR_TO_SOCK_COMMON_OR_NULL:
90179042
case PTR_TO_TCP_SOCK:
90189043
case PTR_TO_TCP_SOCK_OR_NULL:
9044+
case PTR_TO_MPTCP_SOCK:
9045+
case PTR_TO_MPTCP_SOCK_OR_NULL:
90199046
case PTR_TO_XDP_SOCK:
90209047
case PTR_TO_BTF_ID:
90219048
case PTR_TO_BTF_ID_OR_NULL:
@@ -10167,6 +10194,9 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
1016710194
case PTR_TO_TCP_SOCK:
1016810195
convert_ctx_access = bpf_tcp_sock_convert_ctx_access;
1016910196
break;
10197+
case PTR_TO_MPTCP_SOCK:
10198+
convert_ctx_access = bpf_mptcp_sock_convert_ctx_access;
10199+
break;
1017010200
case PTR_TO_XDP_SOCK:
1017110201
convert_ctx_access = bpf_xdp_sock_convert_ctx_access;
1017210202
break;

net/core/filter.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6890,6 +6890,10 @@ sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
68906890
case BPF_FUNC_tcp_sock:
68916891
return &bpf_tcp_sock_proto;
68926892
#endif /* CONFIG_INET */
6893+
#ifdef CONFIG_MPTCP
6894+
case BPF_FUNC_mptcp_sock:
6895+
return &bpf_mptcp_sock_proto;
6896+
#endif /* CONFIG_MPTCP */
68936897
default:
68946898
return bpf_base_func_proto(func_id);
68956899
}

net/mptcp/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ obj-$(CONFIG_INET_MPTCP_DIAG) += mptcp_diag.o
1010
mptcp_crypto_test-objs := crypto_test.o
1111
mptcp_token_test-objs := token_test.o
1212
obj-$(CONFIG_MPTCP_KUNIT_TESTS) += mptcp_crypto_test.o mptcp_token_test.o
13+
14+
obj-$(CONFIG_BPF) += bpf.o

net/mptcp/bpf.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Multipath TCP
3+
*
4+
* Copyright (c) 2020, Tessares SA.
5+
*
6+
* Author: Nicolas Rybowski <nicolas.rybowski@tessares.net>
7+
*
8+
*/
9+
10+
#include <linux/bpf.h>
11+
12+
#include "protocol.h"
13+
14+
bool bpf_mptcp_sock_is_valid_access(int off, int size, enum bpf_access_type type,
15+
struct bpf_insn_access_aux *info)
16+
{
17+
if (off < 0 || off >= offsetofend(struct bpf_mptcp_sock, token))
18+
return false;
19+
20+
if (off % size != 0)
21+
return false;
22+
23+
switch (off) {
24+
default:
25+
return size == sizeof(__u32);
26+
}
27+
}
28+
29+
u32 bpf_mptcp_sock_convert_ctx_access(enum bpf_access_type type,
30+
const struct bpf_insn *si,
31+
struct bpf_insn *insn_buf,
32+
struct bpf_prog *prog, u32 *target_size)
33+
{
34+
struct bpf_insn *insn = insn_buf;
35+
36+
#define BPF_MPTCP_SOCK_GET_COMMON(FIELD) \
37+
do { \
38+
BUILD_BUG_ON(sizeof_field(struct mptcp_sock, FIELD) > \
39+
sizeof_field(struct bpf_mptcp_sock, FIELD)); \
40+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct mptcp_sock, FIELD), \
41+
si->dst_reg, si->src_reg, \
42+
offsetof(struct mptcp_sock, FIELD)); \
43+
} while (0)
44+
45+
if (insn > insn_buf)
46+
return insn - insn_buf;
47+
48+
switch (si->off) {
49+
case offsetof(struct bpf_mptcp_sock, token):
50+
BPF_MPTCP_SOCK_GET_COMMON(token);
51+
break;
52+
}
53+
54+
return insn - insn_buf;
55+
}
56+
57+
BPF_CALL_1(bpf_mptcp_sock, struct sock *, sk)
58+
{
59+
if (sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk)) {
60+
struct mptcp_subflow_context *mptcp_sfc = mptcp_subflow_ctx(sk);
61+
62+
return (unsigned long)mptcp_sfc->conn;
63+
}
64+
return (unsigned long)NULL;
65+
}
66+
67+
const struct bpf_func_proto bpf_mptcp_sock_proto = {
68+
.func = bpf_mptcp_sock,
69+
.gpl_only = false,
70+
.ret_type = RET_PTR_TO_MPTCP_SOCK_OR_NULL,
71+
.arg1_type = ARG_PTR_TO_SOCK_COMMON,
72+
};

scripts/bpf_helpers_doc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ class PrinterHelpers(Printer):
428428
'struct tcp_request_sock',
429429
'struct udp6_sock',
430430
'struct task_struct',
431+
'struct bpf_mptcp_sock',
431432

432433
'struct __sk_buff',
433434
'struct sk_msg_md',
@@ -474,6 +475,7 @@ class PrinterHelpers(Printer):
474475
'struct udp6_sock',
475476
'struct task_struct',
476477
'struct path',
478+
'struct bpf_mptcp_sock',
477479
}
478480
mapped_types = {
479481
'u8': '__u8',

tools/include/uapi/linux/bpf.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3586,6 +3586,15 @@ union bpf_attr {
35863586
* the data in *dst*. This is a wrapper of **copy_from_user**\ ().
35873587
* Return
35883588
* 0 on success, or a negative error in case of failure.
3589+
*
3590+
* struct bpf_mptcp_sock *bpf_mptcp_sock(struct bpf_sock *sk)
3591+
* Description
3592+
* This helper gets a **struct bpf_mptcp_sock** pointer from a
3593+
* **struct bpf_sock** pointer.
3594+
* Return
3595+
* A **struct bpf_mptcp_sock** pointer on success, or **NULL** in
3596+
* case of failure.
3597+
*
35893598
*/
35903599
#define __BPF_FUNC_MAPPER(FN) \
35913600
FN(unspec), \
@@ -3737,6 +3746,7 @@ union bpf_attr {
37373746
FN(inode_storage_delete), \
37383747
FN(d_path), \
37393748
FN(copy_from_user), \
3749+
FN(mptcp_sock), \
37403750
/* */
37413751

37423752
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
@@ -4070,6 +4080,10 @@ struct bpf_tcp_sock {
40704080
__u32 is_mptcp; /* Is MPTCP subflow? */
40714081
};
40724082

4083+
struct bpf_mptcp_sock {
4084+
__u32 token; /* msk token */
4085+
};
4086+
40734087
struct bpf_sock_tuple {
40744088
union {
40754089
struct {

0 commit comments

Comments
 (0)