Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /* Multipath TCP
3 : : *
4 : : * Copyright (c) 2020, Tessares SA.
5 : : * Copyright (c) 2022, SUSE.
6 : : *
7 : : * Author: Nicolas Rybowski <nicolas.rybowski@tessares.net>
8 : : */
9 : :
10 : : #define pr_fmt(fmt) "MPTCP: " fmt
11 : :
12 : : #include <linux/bpf.h>
13 : : #include <linux/bpf_verifier.h>
14 : : #include <linux/btf.h>
15 : : #include <linux/btf_ids.h>
16 : : #include <net/bpf_sk_storage.h>
17 : : #include "protocol.h"
18 : :
19 : : #ifdef CONFIG_BPF_JIT
20 : : static struct bpf_struct_ops bpf_mptcp_sched_ops;
21 : : static u32 mptcp_sock_id,
22 : : mptcp_subflow_id;
23 : :
24 : : /* MPTCP BPF packet scheduler */
25 : :
26 : : static const struct bpf_func_proto *
27 : 222 : bpf_mptcp_sched_get_func_proto(enum bpf_func_id func_id,
28 : : const struct bpf_prog *prog)
29 : : {
30 [ + - + + : 222 : switch (func_id) {
+ ]
31 : : case BPF_FUNC_sk_storage_get:
32 : : return &bpf_sk_storage_get_proto;
33 : 18 : case BPF_FUNC_sk_storage_delete:
34 : 18 : return &bpf_sk_storage_delete_proto;
35 : 0 : case BPF_FUNC_skc_to_tcp6_sock:
36 : 0 : return &bpf_skc_to_tcp6_sock_proto;
37 : 120 : case BPF_FUNC_skc_to_tcp_sock:
38 : 120 : return &bpf_skc_to_tcp_sock_proto;
39 : 48 : default:
40 : 48 : return bpf_base_func_proto(func_id, prog);
41 : : }
42 : : }
43 : :
44 : 154 : static int bpf_mptcp_sched_btf_struct_access(struct bpf_verifier_log *log,
45 : : const struct bpf_reg_state *reg,
46 : : int off, int size)
47 : : {
48 : 154 : u32 id = reg->btf_id;
49 : 154 : size_t end;
50 : :
51 [ + + ]: 154 : if (id == mptcp_sock_id) {
52 [ - + ]: 8 : switch (off) {
53 : : case offsetof(struct mptcp_sock, snd_burst):
54 : : end = offsetofend(struct mptcp_sock, snd_burst);
55 : : break;
56 : 0 : default:
57 : 0 : bpf_log(log, "no write support to mptcp_sock at off %d\n",
58 : : off);
59 : 0 : return -EACCES;
60 : : }
61 [ + - ]: 146 : } else if (id == mptcp_subflow_id) {
62 [ - + ]: 146 : switch (off) {
63 : : case offsetof(struct mptcp_subflow_context, avg_pacing_rate):
64 : : end = offsetofend(struct mptcp_subflow_context, avg_pacing_rate);
65 : : break;
66 : 0 : default:
67 : 0 : bpf_log(log, "no write support to mptcp_subflow_context at off %d\n",
68 : : off);
69 : 0 : return -EACCES;
70 : : }
71 : : } else {
72 : 0 : bpf_log(log, "only access to mptcp sock or subflow is supported\n");
73 : 0 : return -EACCES;
74 : : }
75 : :
76 [ - + ]: 154 : if (off + size > end) {
77 [ # # ]: 0 : bpf_log(log, "access beyond %s at off %u size %u ended at %zu",
78 : : id == mptcp_sock_id ? "mptcp_sock" : "mptcp_subflow_context",
79 : : off, size, end);
80 : 0 : return -EACCES;
81 : : }
82 : :
83 : : return NOT_INIT;
84 : : }
85 : :
86 : : static const struct bpf_verifier_ops bpf_mptcp_sched_verifier_ops = {
87 : : .get_func_proto = bpf_mptcp_sched_get_func_proto,
88 : : .is_valid_access = bpf_tracing_btf_ctx_access,
89 : : .btf_struct_access = bpf_mptcp_sched_btf_struct_access,
90 : : };
91 : :
92 : 30 : static int bpf_mptcp_sched_reg(void *kdata, struct bpf_link *link)
93 : : {
94 : 30 : return mptcp_register_scheduler(kdata);
95 : : }
96 : :
97 : 30 : static void bpf_mptcp_sched_unreg(void *kdata, struct bpf_link *link)
98 : : {
99 : 30 : mptcp_unregister_scheduler(kdata);
100 : 30 : }
101 : :
102 : 96 : static int bpf_mptcp_sched_check_member(const struct btf_type *t,
103 : : const struct btf_member *member,
104 : : const struct bpf_prog *prog)
105 : : {
106 : 96 : return 0;
107 : : }
108 : :
109 : 180 : static int bpf_mptcp_sched_init_member(const struct btf_type *t,
110 : : const struct btf_member *member,
111 : : void *kdata, const void *udata)
112 : : {
113 : 180 : const struct mptcp_sched_ops *usched;
114 : 180 : struct mptcp_sched_ops *sched;
115 : 180 : u32 moff;
116 : :
117 : 180 : usched = (const struct mptcp_sched_ops *)udata;
118 : 180 : sched = (struct mptcp_sched_ops *)kdata;
119 : :
120 [ - + ]: 180 : moff = __btf_member_bit_offset(t, member) / 8;
121 [ + + ]: 180 : switch (moff) {
122 : 30 : case offsetof(struct mptcp_sched_ops, name):
123 [ - + ]: 30 : if (bpf_obj_name_cpy(sched->name, usched->name,
124 : : sizeof(sched->name)) <= 0)
125 : 0 : return -EINVAL;
126 : : return 1;
127 : : }
128 : :
129 : : return 0;
130 : : }
131 : :
132 : 2 : static int bpf_mptcp_sched_init(struct btf *btf)
133 : : {
134 : 2 : s32 type_id;
135 : :
136 : 2 : type_id = btf_find_by_name_kind(btf, "mptcp_sock",
137 : : BTF_KIND_STRUCT);
138 [ - + ]: 2 : if (type_id < 0)
139 : : return -EINVAL;
140 : 2 : mptcp_sock_id = type_id;
141 : :
142 : 2 : type_id = btf_find_by_name_kind(btf, "mptcp_subflow_context",
143 : : BTF_KIND_STRUCT);
144 [ - + ]: 2 : if (type_id < 0)
145 : : return -EINVAL;
146 : 2 : mptcp_subflow_id = type_id;
147 : :
148 : 2 : return 0;
149 : : }
150 : :
151 : 30 : static int bpf_mptcp_sched_validate(void *kdata)
152 : : {
153 : 30 : return mptcp_validate_scheduler(kdata);
154 : : }
155 : :
156 : 0 : static int __bpf_mptcp_sched_get_send(struct mptcp_sock *msk)
157 : : {
158 : 0 : return 0;
159 : : }
160 : :
161 : 0 : static int __bpf_mptcp_sched_get_retrans(struct mptcp_sock *msk)
162 : : {
163 : 0 : return 0;
164 : : }
165 : :
166 : 0 : static void __bpf_mptcp_sched_init(struct mptcp_sock *msk)
167 : : {
168 : 0 : }
169 : :
170 : 0 : static void __bpf_mptcp_sched_release(struct mptcp_sock *msk)
171 : : {
172 : 0 : }
173 : :
174 : : static struct mptcp_sched_ops __bpf_mptcp_sched_ops = {
175 : : .get_send = __bpf_mptcp_sched_get_send,
176 : : .get_retrans = __bpf_mptcp_sched_get_retrans,
177 : : .init = __bpf_mptcp_sched_init,
178 : : .release = __bpf_mptcp_sched_release,
179 : : };
180 : :
181 : : static struct bpf_struct_ops bpf_mptcp_sched_ops = {
182 : : .verifier_ops = &bpf_mptcp_sched_verifier_ops,
183 : : .reg = bpf_mptcp_sched_reg,
184 : : .unreg = bpf_mptcp_sched_unreg,
185 : : .check_member = bpf_mptcp_sched_check_member,
186 : : .init_member = bpf_mptcp_sched_init_member,
187 : : .init = bpf_mptcp_sched_init,
188 : : .validate = bpf_mptcp_sched_validate,
189 : : .name = "mptcp_sched_ops",
190 : : .cfi_stubs = &__bpf_mptcp_sched_ops,
191 : : };
192 : : #endif /* CONFIG_BPF_JIT */
193 : :
194 : 18 : struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk)
195 : : {
196 [ + - + + : 27 : if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
+ + + + ]
197 [ - + ]: 18 : return mptcp_sk(mptcp_subflow_ctx(sk)->conn);
198 : :
199 : : return NULL;
200 : : }
201 : :
202 : : BTF_SET8_START(bpf_mptcp_fmodret_ids)
203 : : BTF_ID_FLAGS(func, update_socket_protocol)
204 : : BTF_SET8_END(bpf_mptcp_fmodret_ids)
205 : :
206 : : static const struct btf_kfunc_id_set bpf_mptcp_fmodret_set = {
207 : : .owner = THIS_MODULE,
208 : : .set = &bpf_mptcp_fmodret_ids,
209 : : };
210 : :
211 : : struct bpf_iter_mptcp_subflow {
212 : : __u64 __opaque[2];
213 : : } __aligned(8);
214 : :
215 : : struct bpf_iter_mptcp_subflow_kern {
216 : : struct mptcp_sock *msk;
217 : : struct list_head *pos;
218 : : } __aligned(8);
219 : :
220 : : __bpf_kfunc_start_defs();
221 : :
222 : : __bpf_kfunc static struct mptcp_subflow_context *
223 : 131307 : bpf_mptcp_subflow_ctx(const struct sock *sk__ign)
224 : : {
225 : 131307 : const struct sock *sk = sk__ign;
226 : :
227 [ + - + + ]: 131307 : if (sk && sk_fullsock(sk) &&
228 [ + + + + ]: 197802 : sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
229 : 131307 : return mptcp_subflow_ctx(sk);
230 : :
231 : : return NULL;
232 : : }
233 : :
234 : : __bpf_kfunc static struct sock *
235 : 14 : bpf_mptcp_subflow_tcp_sock(const struct mptcp_subflow_context *subflow)
236 : : {
237 [ + - ]: 14 : if (!subflow)
238 : : return NULL;
239 : :
240 : 14 : return mptcp_subflow_tcp_sock(subflow);
241 : : }
242 : :
243 : : __bpf_kfunc static int
244 : 173624 : bpf_iter_mptcp_subflow_new(struct bpf_iter_mptcp_subflow *it,
245 : : struct sock *sk)
246 : : {
247 : 173624 : struct bpf_iter_mptcp_subflow_kern *kit = (void *)it;
248 : 173624 : struct mptcp_sock *msk;
249 : :
250 : 173624 : BUILD_BUG_ON(sizeof(struct bpf_iter_mptcp_subflow_kern) >
251 : : sizeof(struct bpf_iter_mptcp_subflow));
252 : 173624 : BUILD_BUG_ON(__alignof__(struct bpf_iter_mptcp_subflow_kern) !=
253 : : __alignof__(struct bpf_iter_mptcp_subflow));
254 : :
255 [ + - + + ]: 173624 : if (unlikely(!sk || !sk_fullsock(sk)))
256 : 0 : return -EINVAL;
257 : :
258 [ + + ]: 173624 : if (sk->sk_protocol != IPPROTO_MPTCP)
259 : : return -EINVAL;
260 : :
261 : 173624 : msk = mptcp_sk(sk);
262 : :
263 : 173624 : msk_owned_by_me(msk);
264 : :
265 : 173624 : kit->msk = msk;
266 : 173624 : kit->pos = &msk->conn_list;
267 : 173624 : return 0;
268 : : }
269 : :
270 : : __bpf_kfunc static struct mptcp_subflow_context *
271 : 410520 : bpf_iter_mptcp_subflow_next(struct bpf_iter_mptcp_subflow *it)
272 : : {
273 : 410520 : struct bpf_iter_mptcp_subflow_kern *kit = (void *)it;
274 : :
275 [ + - + + ]: 410520 : if (!kit->msk || list_is_last(kit->pos, &kit->msk->conn_list))
276 : : return NULL;
277 : :
278 : 303139 : kit->pos = kit->pos->next;
279 : 303139 : return list_entry(kit->pos, struct mptcp_subflow_context, node);
280 : : }
281 : :
282 : : __bpf_kfunc static void
283 : 173624 : bpf_iter_mptcp_subflow_destroy(struct bpf_iter_mptcp_subflow *it)
284 : : {
285 : 173624 : }
286 : :
287 : 14 : __bpf_kfunc static bool bpf_mptcp_subflow_queues_empty(struct sock *sk)
288 : : {
289 : 14 : return tcp_rtx_queue_empty(sk);
290 : : }
291 : :
292 : 42435 : __bpf_kfunc static bool bpf_sk_stream_memory_free(const struct sock *sk__ign)
293 : : {
294 : 42435 : const struct sock *sk = sk__ign;
295 : :
296 [ + - + + ]: 42435 : if (sk && sk_fullsock(sk) &&
297 [ + + + + ]: 63688 : sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
298 : 42435 : return sk_stream_memory_free(sk);
299 : :
300 : : return NULL;
301 : : }
302 : :
303 : : __bpf_kfunc_end_defs();
304 : :
305 : : BTF_KFUNCS_START(bpf_mptcp_common_kfunc_ids)
306 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx, KF_RET_NULL)
307 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_tcp_sock, KF_RET_NULL)
308 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_new, KF_ITER_NEW | KF_TRUSTED_ARGS)
309 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_next, KF_ITER_NEXT | KF_RET_NULL)
310 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_destroy, KF_ITER_DESTROY)
311 : : BTF_ID_FLAGS(func, mptcp_subflow_set_scheduled)
312 : : BTF_ID_FLAGS(func, mptcp_subflow_active)
313 : : BTF_ID_FLAGS(func, mptcp_set_timeout)
314 : : BTF_ID_FLAGS(func, mptcp_wnd_end)
315 : : BTF_ID_FLAGS(func, bpf_sk_stream_memory_free, KF_RET_NULL)
316 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_queues_empty)
317 : : BTF_ID_FLAGS(func, mptcp_pm_subflow_chk_stale, KF_SLEEPABLE)
318 : : BTF_KFUNCS_END(bpf_mptcp_common_kfunc_ids)
319 : :
320 : : static const struct btf_kfunc_id_set bpf_mptcp_common_kfunc_set = {
321 : : .owner = THIS_MODULE,
322 : : .set = &bpf_mptcp_common_kfunc_ids,
323 : : };
324 : :
325 : 4 : static int __init bpf_mptcp_kfunc_init(void)
326 : : {
327 : 4 : int ret;
328 : :
329 : 4 : ret = register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
330 [ + - ]: 4 : ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SOCKOPT,
331 : : &bpf_mptcp_common_kfunc_set);
332 [ + - ]: 4 : ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS,
333 : : &bpf_mptcp_common_kfunc_set);
334 : : #ifdef CONFIG_BPF_JIT
335 [ + - ]: 4 : ret = ret ?: register_bpf_struct_ops(&bpf_mptcp_sched_ops, mptcp_sched_ops);
336 : : #endif
337 : :
338 : 4 : return ret;
339 : : }
340 : : late_initcall(bpf_mptcp_kfunc_init);
|