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 const struct btf_type *mptcp_sock_type, *mptcp_subflow_type __read_mostly;
22 : : static u32 mptcp_sock_id, mptcp_subflow_id;
23 : :
24 : : static const struct bpf_func_proto *
25 : 2670 : bpf_mptcp_sched_get_func_proto(enum bpf_func_id func_id,
26 : : const struct bpf_prog *prog)
27 : : {
28 [ + - + + : 2670 : switch (func_id) {
+ ]
29 : : case BPF_FUNC_sk_storage_get:
30 : : return &bpf_sk_storage_get_proto;
31 : 18 : case BPF_FUNC_sk_storage_delete:
32 : 18 : return &bpf_sk_storage_delete_proto;
33 : 0 : case BPF_FUNC_skc_to_tcp6_sock:
34 : 0 : return &bpf_skc_to_tcp6_sock_proto;
35 : 2496 : case BPF_FUNC_skc_to_tcp_sock:
36 : 2496 : return &bpf_skc_to_tcp_sock_proto;
37 : 120 : default:
38 : 120 : return bpf_base_func_proto(func_id, prog);
39 : : }
40 : : }
41 : :
42 : 188 : static int bpf_mptcp_sched_btf_struct_access(struct bpf_verifier_log *log,
43 : : const struct bpf_reg_state *reg,
44 : : int off, int size)
45 : : {
46 : 188 : const struct btf_type *t;
47 : 188 : size_t end;
48 : :
49 : 188 : t = btf_type_by_id(reg->btf, reg->btf_id);
50 : :
51 [ + + ]: 188 : if (t == mptcp_sock_type) {
52 [ - + ]: 10 : 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 [ + - ]: 178 : } else if (t == mptcp_subflow_type) {
62 [ - + ]: 178 : 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 [ - + ]: 188 : if (off + size > end) {
77 [ # # ]: 0 : bpf_log(log, "access beyond %s at off %u size %u ended at %zu",
78 : : t == mptcp_sock_type ? "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 : 90 : 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 : 90 : return 0;
107 : : }
108 : :
109 : 150 : 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 : 150 : const struct mptcp_sched_ops *usched;
114 : 150 : struct mptcp_sched_ops *sched;
115 : 150 : u32 moff;
116 : 150 : int ret;
117 : :
118 : 150 : usched = (const struct mptcp_sched_ops *)udata;
119 : 150 : sched = (struct mptcp_sched_ops *)kdata;
120 : :
121 [ - + ]: 150 : moff = __btf_member_bit_offset(t, member) / 8;
122 [ + + ]: 150 : switch (moff) {
123 : 30 : case offsetof(struct mptcp_sched_ops, name):
124 [ + - ]: 30 : if (bpf_obj_name_cpy(sched->name, usched->name,
125 : : sizeof(sched->name)) <= 0)
126 : : return -EINVAL;
127 : :
128 : 30 : rcu_read_lock();
129 [ + - ]: 30 : ret = mptcp_sched_find(usched->name) ? -EEXIST : 1;
130 : 30 : rcu_read_unlock();
131 : :
132 : 30 : return ret;
133 : : }
134 : :
135 : : return 0;
136 : : }
137 : :
138 : 2 : static int bpf_mptcp_sched_init(struct btf *btf)
139 : : {
140 : 2 : s32 type_id;
141 : :
142 : 2 : type_id = btf_find_by_name_kind(btf, "mptcp_sock",
143 : : BTF_KIND_STRUCT);
144 [ - + ]: 2 : if (type_id < 0)
145 : : return -EINVAL;
146 : 2 : mptcp_sock_id = type_id;
147 : 2 : mptcp_sock_type = btf_type_by_id(btf, mptcp_sock_id);
148 : :
149 : 2 : type_id = btf_find_by_name_kind(btf, "mptcp_subflow_context",
150 : : BTF_KIND_STRUCT);
151 [ - + ]: 2 : if (type_id < 0)
152 : : return -EINVAL;
153 : 2 : mptcp_subflow_id = type_id;
154 : 2 : mptcp_subflow_type = btf_type_by_id(btf, mptcp_subflow_id);
155 : :
156 : 2 : return 0;
157 : : }
158 : :
159 : 0 : static int __bpf_mptcp_sched_get_subflow(struct mptcp_sock *msk,
160 : : struct mptcp_sched_data *data)
161 : : {
162 : 0 : return 0;
163 : : }
164 : :
165 : 0 : static void __bpf_mptcp_sched_init(struct mptcp_sock *msk)
166 : : {
167 : 0 : }
168 : :
169 : 0 : static void __bpf_mptcp_sched_release(struct mptcp_sock *msk)
170 : : {
171 : 0 : }
172 : :
173 : : static struct mptcp_sched_ops __bpf_mptcp_sched_ops = {
174 : : .get_subflow = __bpf_mptcp_sched_get_subflow,
175 : : .init = __bpf_mptcp_sched_init,
176 : : .release = __bpf_mptcp_sched_release,
177 : : };
178 : :
179 : : static struct bpf_struct_ops bpf_mptcp_sched_ops = {
180 : : .verifier_ops = &bpf_mptcp_sched_verifier_ops,
181 : : .reg = bpf_mptcp_sched_reg,
182 : : .unreg = bpf_mptcp_sched_unreg,
183 : : .check_member = bpf_mptcp_sched_check_member,
184 : : .init_member = bpf_mptcp_sched_init_member,
185 : : .init = bpf_mptcp_sched_init,
186 : : .name = "mptcp_sched_ops",
187 : : .cfi_stubs = &__bpf_mptcp_sched_ops,
188 : : };
189 : : #endif /* CONFIG_BPF_JIT */
190 : :
191 : 24 : struct mptcp_sock *bpf_mptcp_sock_from_sock(struct sock *sk)
192 : : {
193 [ + - + + ]: 24 : if (unlikely(!sk || !sk_fullsock(sk)))
194 : 0 : return NULL;
195 : :
196 [ + + ]: 24 : if (sk->sk_protocol == IPPROTO_MPTCP)
197 : : return mptcp_sk(sk);
198 : :
199 [ + + + + ]: 27 : if (sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
200 [ - + ]: 18 : return mptcp_sk(mptcp_subflow_ctx(sk)->conn);
201 : :
202 : : return NULL;
203 : : }
204 : :
205 : : BTF_SET8_START(bpf_mptcp_fmodret_ids)
206 : : BTF_ID_FLAGS(func, update_socket_protocol)
207 : : BTF_SET8_END(bpf_mptcp_fmodret_ids)
208 : :
209 : : static const struct btf_kfunc_id_set bpf_mptcp_fmodret_set = {
210 : : .owner = THIS_MODULE,
211 : : .set = &bpf_mptcp_fmodret_ids,
212 : : };
213 : :
214 : : struct bpf_iter_mptcp_subflow {
215 : : __u64 __opaque[2];
216 : : } __aligned(8);
217 : :
218 : : struct bpf_iter_mptcp_subflow_kern {
219 : : struct mptcp_sock *msk;
220 : : struct list_head *pos;
221 : : } __aligned(8);
222 : :
223 : : __bpf_kfunc_start_defs();
224 : :
225 : : __bpf_kfunc static struct mptcp_subflow_context *
226 : 6 : bpf_mptcp_subflow_ctx(const struct sock *sk)
227 : : {
228 [ + - + + ]: 6 : if (sk && sk_fullsock(sk) &&
229 [ + + + + ]: 9 : sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
230 : 6 : return mptcp_subflow_ctx(sk);
231 : :
232 : : return NULL;
233 : : }
234 : :
235 : : __bpf_kfunc static int
236 : 6 : bpf_iter_mptcp_subflow_new(struct bpf_iter_mptcp_subflow *it,
237 : : struct mptcp_sock *msk)
238 : : {
239 : 6 : struct bpf_iter_mptcp_subflow_kern *kit = (void *)it;
240 : 6 : struct sock *sk = (struct sock *)msk;
241 : :
242 : 6 : BUILD_BUG_ON(sizeof(struct bpf_iter_mptcp_subflow_kern) >
243 : : sizeof(struct bpf_iter_mptcp_subflow));
244 : 6 : BUILD_BUG_ON(__alignof__(struct bpf_iter_mptcp_subflow_kern) !=
245 : : __alignof__(struct bpf_iter_mptcp_subflow));
246 : :
247 : 6 : kit->msk = msk;
248 [ + + ]: 6 : if (!msk)
249 : : return -EINVAL;
250 : :
251 [ - + - - ]: 6 : if (!sock_owned_by_user_nocheck(sk) &&
252 [ # # ]: 0 : !spin_is_locked(&sk->sk_lock.slock))
253 : : return -EINVAL;
254 : :
255 : 6 : kit->pos = &msk->conn_list;
256 : 6 : return 0;
257 : : }
258 : :
259 : : __bpf_kfunc static struct mptcp_subflow_context *
260 : 30 : bpf_iter_mptcp_subflow_next(struct bpf_iter_mptcp_subflow *it)
261 : : {
262 : 30 : struct bpf_iter_mptcp_subflow_kern *kit = (void *)it;
263 : :
264 [ + - + + ]: 30 : if (!kit->msk || list_is_last(kit->pos, &kit->msk->conn_list))
265 : : return NULL;
266 : :
267 : 24 : kit->pos = kit->pos->next;
268 : 24 : return list_entry(kit->pos, struct mptcp_subflow_context, node);
269 : : }
270 : :
271 : : __bpf_kfunc static void
272 : 6 : bpf_iter_mptcp_subflow_destroy(struct bpf_iter_mptcp_subflow *it)
273 : : {
274 : 6 : }
275 : :
276 : : __bpf_kfunc static struct
277 : 6 : mptcp_sock *bpf_mptcp_sock_acquire(struct mptcp_sock *msk)
278 : : {
279 : 6 : struct sock *sk = (struct sock *)msk;
280 : :
281 [ + - - + ]: 6 : if (sk && refcount_inc_not_zero(&sk->sk_refcnt))
282 : : return msk;
283 : : return NULL;
284 : : }
285 : :
286 : 6 : __bpf_kfunc static void bpf_mptcp_sock_release(struct mptcp_sock *msk)
287 : : {
288 : 6 : struct sock *sk = (struct sock *)msk;
289 : :
290 [ + - - + ]: 6 : WARN_ON_ONCE(!sk || !refcount_dec_not_one(&sk->sk_refcnt));
291 : 6 : }
292 : :
293 : : __bpf_kfunc struct mptcp_subflow_context *
294 : 542681 : bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos)
295 : : {
296 [ + - ]: 542681 : if (pos >= MPTCP_SUBFLOWS_MAX)
297 : : return NULL;
298 : 542681 : return data->contexts[pos];
299 : : }
300 : :
301 : 6 : __bpf_kfunc static bool bpf_mptcp_subflow_queues_empty(struct sock *sk)
302 : : {
303 : 6 : return tcp_rtx_queue_empty(sk);
304 : : }
305 : :
306 : : __bpf_kfunc_end_defs();
307 : :
308 : : BTF_KFUNCS_START(bpf_mptcp_common_kfunc_ids)
309 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx, KF_RET_NULL)
310 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_new, KF_ITER_NEW | KF_TRUSTED_ARGS)
311 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_next, KF_ITER_NEXT | KF_RET_NULL)
312 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_destroy, KF_ITER_DESTROY)
313 : : BTF_ID_FLAGS(func, bpf_mptcp_sock_acquire, KF_ACQUIRE | KF_RET_NULL)
314 : : BTF_ID_FLAGS(func, bpf_mptcp_sock_release, KF_RELEASE)
315 : : BTF_KFUNCS_END(bpf_mptcp_common_kfunc_ids)
316 : :
317 : : static const struct btf_kfunc_id_set bpf_mptcp_common_kfunc_set = {
318 : : .owner = THIS_MODULE,
319 : : .set = &bpf_mptcp_common_kfunc_ids,
320 : : };
321 : :
322 : : BTF_KFUNCS_START(bpf_mptcp_sched_kfunc_ids)
323 : : BTF_ID_FLAGS(func, mptcp_subflow_set_scheduled)
324 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx_by_pos)
325 : : BTF_ID_FLAGS(func, mptcp_subflow_active)
326 : : BTF_ID_FLAGS(func, mptcp_set_timeout)
327 : : BTF_ID_FLAGS(func, mptcp_wnd_end)
328 : : BTF_ID_FLAGS(func, tcp_stream_memory_free)
329 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_queues_empty)
330 : : BTF_ID_FLAGS(func, mptcp_pm_subflow_chk_stale)
331 : : BTF_KFUNCS_END(bpf_mptcp_sched_kfunc_ids)
332 : :
333 : : static const struct btf_kfunc_id_set bpf_mptcp_sched_kfunc_set = {
334 : : .owner = THIS_MODULE,
335 : : .set = &bpf_mptcp_sched_kfunc_ids,
336 : : };
337 : :
338 : 4 : static int __init bpf_mptcp_kfunc_init(void)
339 : : {
340 : 4 : int ret;
341 : :
342 : 4 : ret = register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
343 [ + - ]: 4 : ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_CGROUP_SOCKOPT,
344 : : &bpf_mptcp_common_kfunc_set);
345 [ + - ]: 4 : ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS,
346 : : &bpf_mptcp_sched_kfunc_set);
347 : : #ifdef CONFIG_BPF_JIT
348 [ + - ]: 4 : ret = ret ?: register_bpf_struct_ops(&bpf_mptcp_sched_ops, mptcp_sched_ops);
349 : : #endif
350 : :
351 : 4 : return ret;
352 : : }
353 : : late_initcall(bpf_mptcp_kfunc_init);
|