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 : 178 : 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 : 178 : const struct btf_type *t;
47 : 178 : size_t end;
48 : :
49 : 178 : t = btf_type_by_id(reg->btf, reg->btf_id);
50 : :
51 [ + + ]: 178 : 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 [ + - ]: 168 : } else if (t == mptcp_subflow_type) {
62 [ - + ]: 168 : 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 [ - + ]: 178 : 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 : 18 : struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk)
192 : : {
193 [ + - + + : 27 : if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
+ + + + ]
194 [ - + ]: 18 : return mptcp_sk(mptcp_subflow_ctx(sk)->conn);
195 : :
196 : : return NULL;
197 : : }
198 : :
199 : : BTF_SET8_START(bpf_mptcp_fmodret_ids)
200 : : BTF_ID_FLAGS(func, update_socket_protocol)
201 : : BTF_SET8_END(bpf_mptcp_fmodret_ids)
202 : :
203 : : static const struct btf_kfunc_id_set bpf_mptcp_fmodret_set = {
204 : : .owner = THIS_MODULE,
205 : : .set = &bpf_mptcp_fmodret_ids,
206 : : };
207 : :
208 : : struct bpf_iter_mptcp_subflow {
209 : : __u64 __opaque[2];
210 : : } __aligned(8);
211 : :
212 : : struct bpf_iter_mptcp_subflow_kern {
213 : : struct mptcp_sock *msk;
214 : : struct list_head *pos;
215 : : } __aligned(8);
216 : :
217 : : __bpf_kfunc_start_defs();
218 : :
219 : 6 : __bpf_kfunc static struct mptcp_sock *bpf_mptcp_sk(struct sock *sk)
220 : : {
221 [ - + ]: 6 : return mptcp_sk(sk);
222 : : }
223 : :
224 : : __bpf_kfunc static struct mptcp_subflow_context *
225 : 6 : bpf_mptcp_subflow_ctx(const struct sock *sk)
226 : : {
227 : 6 : return mptcp_subflow_ctx(sk);
228 : : }
229 : :
230 : : __bpf_kfunc static struct sock *
231 : 24 : bpf_mptcp_subflow_tcp_sock(const struct mptcp_subflow_context *subflow)
232 : : {
233 : 24 : return mptcp_subflow_tcp_sock(subflow);
234 : : }
235 : :
236 : : __bpf_kfunc static int
237 : 6 : bpf_iter_mptcp_subflow_new(struct bpf_iter_mptcp_subflow *it,
238 : : struct mptcp_sock *msk)
239 : : {
240 : 6 : struct bpf_iter_mptcp_subflow_kern *kit = (void *)it;
241 : :
242 : 6 : kit->msk = msk;
243 [ + - ]: 6 : if (!msk)
244 : : return -EINVAL;
245 : :
246 : 6 : msk_owned_by_me(msk);
247 : :
248 : 6 : kit->pos = &msk->conn_list;
249 : 6 : return 0;
250 : : }
251 : :
252 : : __bpf_kfunc static struct mptcp_subflow_context *
253 : 30 : bpf_iter_mptcp_subflow_next(struct bpf_iter_mptcp_subflow *it)
254 : : {
255 : 30 : struct bpf_iter_mptcp_subflow_kern *kit = (void *)it;
256 : :
257 [ + - + + ]: 30 : if (!kit->msk || list_is_last(kit->pos, &kit->msk->conn_list))
258 : : return NULL;
259 : :
260 : 24 : kit->pos = kit->pos->next;
261 : 24 : return list_entry(kit->pos, struct mptcp_subflow_context, node);
262 : : }
263 : :
264 : : __bpf_kfunc static void
265 : 6 : bpf_iter_mptcp_subflow_destroy(struct bpf_iter_mptcp_subflow *it)
266 : : {
267 : 6 : }
268 : :
269 : : __bpf_kfunc static struct
270 : 6 : mptcp_sock *bpf_mptcp_sock_acquire(struct mptcp_sock *msk)
271 : : {
272 : 6 : struct sock *sk = (struct sock *)msk;
273 : :
274 [ + - - + ]: 6 : if (sk && refcount_inc_not_zero(&sk->sk_refcnt))
275 : : return msk;
276 : : return NULL;
277 : : }
278 : :
279 : 6 : __bpf_kfunc static void bpf_mptcp_sock_release(struct mptcp_sock *msk)
280 : : {
281 : 6 : struct sock *sk = (struct sock *)msk;
282 : :
283 [ + - - + : 6 : WARN_ON_ONCE(!sk || !refcount_dec_not_one(&sk->sk_refcnt));
- + ]
284 : 6 : }
285 : :
286 : : __bpf_kfunc struct mptcp_subflow_context *
287 : 543178 : bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos)
288 : : {
289 [ + + ]: 543178 : if (pos >= MPTCP_SUBFLOWS_MAX)
290 : : return NULL;
291 : 543177 : return data->contexts[pos];
292 : : }
293 : :
294 : 10 : __bpf_kfunc static bool bpf_mptcp_subflow_queues_empty(struct sock *sk)
295 : : {
296 : 10 : return tcp_rtx_queue_empty(sk);
297 : : }
298 : :
299 : : __bpf_kfunc_end_defs();
300 : :
301 : : BTF_KFUNCS_START(bpf_mptcp_common_kfunc_ids)
302 : : BTF_ID_FLAGS(func, bpf_mptcp_sk)
303 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx)
304 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_tcp_sock)
305 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_new, KF_ITER_NEW | KF_TRUSTED_ARGS)
306 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_next, KF_ITER_NEXT | KF_RET_NULL)
307 : : BTF_ID_FLAGS(func, bpf_iter_mptcp_subflow_destroy, KF_ITER_DESTROY)
308 : : BTF_ID_FLAGS(func, bpf_mptcp_sock_acquire, KF_ACQUIRE | KF_RET_NULL)
309 : : BTF_ID_FLAGS(func, bpf_mptcp_sock_release, KF_RELEASE)
310 : : BTF_KFUNCS_END(bpf_mptcp_common_kfunc_ids)
311 : :
312 : : static const struct btf_kfunc_id_set bpf_mptcp_common_kfunc_set = {
313 : : .owner = THIS_MODULE,
314 : : .set = &bpf_mptcp_common_kfunc_ids,
315 : : };
316 : :
317 : : BTF_KFUNCS_START(bpf_mptcp_sched_kfunc_ids)
318 : : BTF_ID_FLAGS(func, mptcp_subflow_set_scheduled)
319 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx_by_pos)
320 : : BTF_ID_FLAGS(func, mptcp_subflow_active)
321 : : BTF_ID_FLAGS(func, mptcp_set_timeout)
322 : : BTF_ID_FLAGS(func, mptcp_wnd_end)
323 : : BTF_ID_FLAGS(func, tcp_stream_memory_free)
324 : : BTF_ID_FLAGS(func, bpf_mptcp_subflow_queues_empty)
325 : : BTF_ID_FLAGS(func, mptcp_pm_subflow_chk_stale)
326 : : BTF_KFUNCS_END(bpf_mptcp_sched_kfunc_ids)
327 : :
328 : : static const struct btf_kfunc_id_set bpf_mptcp_sched_kfunc_set = {
329 : : .owner = THIS_MODULE,
330 : : .set = &bpf_mptcp_sched_kfunc_ids,
331 : : };
332 : :
333 : 4 : static int __init bpf_mptcp_kfunc_init(void)
334 : : {
335 : 4 : int ret;
336 : :
337 : 4 : ret = register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
338 [ + - ]: 4 : ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC,
339 : : &bpf_mptcp_common_kfunc_set);
340 [ + - ]: 4 : ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS,
341 : : &bpf_mptcp_sched_kfunc_set);
342 : : #ifdef CONFIG_BPF_JIT
343 [ + - ]: 4 : ret = ret ?: register_bpf_struct_ops(&bpf_mptcp_sched_ops, mptcp_sched_ops);
344 : : #endif
345 : :
346 : 4 : return ret;
347 : : }
348 : : late_initcall(bpf_mptcp_kfunc_init);
|