Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2017-2018 Netronome Systems, Inc.
3 : : *
4 : : * This software is licensed under the GNU General License Version 2,
5 : : * June 1991 as shown in the file COPYING in the top-level directory of this
6 : : * source tree.
7 : : *
8 : : * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
9 : : * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
10 : : * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11 : : * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
12 : : * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
13 : : * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
14 : : */
15 : :
16 : : #include <linux/bpf.h>
17 : : #include <linux/bpf_verifier.h>
18 : : #include <linux/bug.h>
19 : : #include <linux/kdev_t.h>
20 : : #include <linux/list.h>
21 : : #include <linux/lockdep.h>
22 : : #include <linux/netdevice.h>
23 : : #include <linux/printk.h>
24 : : #include <linux/proc_ns.h>
25 : : #include <linux/rhashtable.h>
26 : : #include <linux/rtnetlink.h>
27 : : #include <linux/rwsem.h>
28 : :
29 : : /* Protects offdevs, members of bpf_offload_netdev and offload members
30 : : * of all progs.
31 : : * RTNL lock cannot be taken when holding this lock.
32 : : */
33 : : static DECLARE_RWSEM(bpf_devs_lock);
34 : :
35 : : struct bpf_offload_dev {
36 : : const struct bpf_prog_offload_ops *ops;
37 : : struct list_head netdevs;
38 : : void *priv;
39 : : };
40 : :
41 : : struct bpf_offload_netdev {
42 : : struct rhash_head l;
43 : : struct net_device *netdev;
44 : : struct bpf_offload_dev *offdev;
45 : : struct list_head progs;
46 : : struct list_head maps;
47 : : struct list_head offdev_netdevs;
48 : : };
49 : :
50 : : static const struct rhashtable_params offdevs_params = {
51 : : .nelem_hint = 4,
52 : : .key_len = sizeof(struct net_device *),
53 : : .key_offset = offsetof(struct bpf_offload_netdev, netdev),
54 : : .head_offset = offsetof(struct bpf_offload_netdev, l),
55 : : .automatic_shrinking = true,
56 : : };
57 : :
58 : : static struct rhashtable offdevs;
59 : : static bool offdevs_inited;
60 : :
61 : : static int bpf_dev_offload_check(struct net_device *netdev)
62 : : {
63 : 0 : if (!netdev)
64 : : return -EINVAL;
65 : 0 : if (!netdev->netdev_ops->ndo_bpf)
66 : : return -EOPNOTSUPP;
67 : : return 0;
68 : : }
69 : :
70 : : static struct bpf_offload_netdev *
71 : 0 : bpf_offload_find_netdev(struct net_device *netdev)
72 : : {
73 : : lockdep_assert_held(&bpf_devs_lock);
74 : :
75 : 0 : if (!offdevs_inited)
76 : : return NULL;
77 : 0 : return rhashtable_lookup_fast(&offdevs, &netdev, offdevs_params);
78 : : }
79 : :
80 : 0 : int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
81 : : {
82 : : struct bpf_offload_netdev *ondev;
83 : : struct bpf_prog_offload *offload;
84 : : int err;
85 : :
86 : 0 : if (attr->prog_type != BPF_PROG_TYPE_SCHED_CLS &&
87 : : attr->prog_type != BPF_PROG_TYPE_XDP)
88 : : return -EINVAL;
89 : :
90 : 0 : if (attr->prog_flags)
91 : : return -EINVAL;
92 : :
93 : 0 : offload = kzalloc(sizeof(*offload), GFP_USER);
94 : 0 : if (!offload)
95 : : return -ENOMEM;
96 : :
97 : 0 : offload->prog = prog;
98 : :
99 : 0 : offload->netdev = dev_get_by_index(current->nsproxy->net_ns,
100 : 0 : attr->prog_ifindex);
101 : : err = bpf_dev_offload_check(offload->netdev);
102 : 0 : if (err)
103 : : goto err_maybe_put;
104 : :
105 : 0 : down_write(&bpf_devs_lock);
106 : 0 : ondev = bpf_offload_find_netdev(offload->netdev);
107 : 0 : if (!ondev) {
108 : : err = -EINVAL;
109 : : goto err_unlock;
110 : : }
111 : 0 : offload->offdev = ondev->offdev;
112 : 0 : prog->aux->offload = offload;
113 : 0 : list_add_tail(&offload->offloads, &ondev->progs);
114 : 0 : dev_put(offload->netdev);
115 : 0 : up_write(&bpf_devs_lock);
116 : :
117 : 0 : return 0;
118 : : err_unlock:
119 : 0 : up_write(&bpf_devs_lock);
120 : : err_maybe_put:
121 : 0 : if (offload->netdev)
122 : 0 : dev_put(offload->netdev);
123 : 0 : kfree(offload);
124 : 0 : return err;
125 : : }
126 : :
127 : 0 : int bpf_prog_offload_verifier_prep(struct bpf_prog *prog)
128 : : {
129 : : struct bpf_prog_offload *offload;
130 : : int ret = -ENODEV;
131 : :
132 : 0 : down_read(&bpf_devs_lock);
133 : 0 : offload = prog->aux->offload;
134 : 0 : if (offload) {
135 : 0 : ret = offload->offdev->ops->prepare(prog);
136 : 0 : offload->dev_state = !ret;
137 : : }
138 : 0 : up_read(&bpf_devs_lock);
139 : :
140 : 0 : return ret;
141 : : }
142 : :
143 : 0 : int bpf_prog_offload_verify_insn(struct bpf_verifier_env *env,
144 : : int insn_idx, int prev_insn_idx)
145 : : {
146 : : struct bpf_prog_offload *offload;
147 : : int ret = -ENODEV;
148 : :
149 : 0 : down_read(&bpf_devs_lock);
150 : 0 : offload = env->prog->aux->offload;
151 : 0 : if (offload)
152 : 0 : ret = offload->offdev->ops->insn_hook(env, insn_idx,
153 : : prev_insn_idx);
154 : 0 : up_read(&bpf_devs_lock);
155 : :
156 : 0 : return ret;
157 : : }
158 : :
159 : 0 : int bpf_prog_offload_finalize(struct bpf_verifier_env *env)
160 : : {
161 : : struct bpf_prog_offload *offload;
162 : : int ret = -ENODEV;
163 : :
164 : 0 : down_read(&bpf_devs_lock);
165 : 0 : offload = env->prog->aux->offload;
166 : 0 : if (offload) {
167 : 0 : if (offload->offdev->ops->finalize)
168 : 0 : ret = offload->offdev->ops->finalize(env);
169 : : else
170 : : ret = 0;
171 : : }
172 : 0 : up_read(&bpf_devs_lock);
173 : :
174 : 0 : return ret;
175 : : }
176 : :
177 : : void
178 : 0 : bpf_prog_offload_replace_insn(struct bpf_verifier_env *env, u32 off,
179 : : struct bpf_insn *insn)
180 : : {
181 : : const struct bpf_prog_offload_ops *ops;
182 : : struct bpf_prog_offload *offload;
183 : : int ret = -EOPNOTSUPP;
184 : :
185 : 0 : down_read(&bpf_devs_lock);
186 : 0 : offload = env->prog->aux->offload;
187 : 0 : if (offload) {
188 : 0 : ops = offload->offdev->ops;
189 : 0 : if (!offload->opt_failed && ops->replace_insn)
190 : 0 : ret = ops->replace_insn(env, off, insn);
191 : 0 : offload->opt_failed |= ret;
192 : : }
193 : 0 : up_read(&bpf_devs_lock);
194 : 0 : }
195 : :
196 : : void
197 : 0 : bpf_prog_offload_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt)
198 : : {
199 : : struct bpf_prog_offload *offload;
200 : : int ret = -EOPNOTSUPP;
201 : :
202 : 0 : down_read(&bpf_devs_lock);
203 : 0 : offload = env->prog->aux->offload;
204 : 0 : if (offload) {
205 : 0 : if (!offload->opt_failed && offload->offdev->ops->remove_insns)
206 : 0 : ret = offload->offdev->ops->remove_insns(env, off, cnt);
207 : 0 : offload->opt_failed |= ret;
208 : : }
209 : 0 : up_read(&bpf_devs_lock);
210 : 0 : }
211 : :
212 : 0 : static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
213 : : {
214 : 0 : struct bpf_prog_offload *offload = prog->aux->offload;
215 : :
216 : 0 : if (offload->dev_state)
217 : 0 : offload->offdev->ops->destroy(prog);
218 : :
219 : : /* Make sure BPF_PROG_GET_NEXT_ID can't find this dead program */
220 : 0 : bpf_prog_free_id(prog, true);
221 : :
222 : 0 : list_del_init(&offload->offloads);
223 : 0 : kfree(offload);
224 : 0 : prog->aux->offload = NULL;
225 : 0 : }
226 : :
227 : 0 : void bpf_prog_offload_destroy(struct bpf_prog *prog)
228 : : {
229 : 0 : down_write(&bpf_devs_lock);
230 : 0 : if (prog->aux->offload)
231 : 0 : __bpf_prog_offload_destroy(prog);
232 : 0 : up_write(&bpf_devs_lock);
233 : 0 : }
234 : :
235 : 0 : static int bpf_prog_offload_translate(struct bpf_prog *prog)
236 : : {
237 : : struct bpf_prog_offload *offload;
238 : : int ret = -ENODEV;
239 : :
240 : 0 : down_read(&bpf_devs_lock);
241 : 0 : offload = prog->aux->offload;
242 : 0 : if (offload)
243 : 0 : ret = offload->offdev->ops->translate(prog);
244 : 0 : up_read(&bpf_devs_lock);
245 : :
246 : 0 : return ret;
247 : : }
248 : :
249 : 0 : static unsigned int bpf_prog_warn_on_exec(const void *ctx,
250 : : const struct bpf_insn *insn)
251 : : {
252 : 0 : WARN(1, "attempt to execute device eBPF program on the host!");
253 : 0 : return 0;
254 : : }
255 : :
256 : 0 : int bpf_prog_offload_compile(struct bpf_prog *prog)
257 : : {
258 : 0 : prog->bpf_func = bpf_prog_warn_on_exec;
259 : :
260 : 0 : return bpf_prog_offload_translate(prog);
261 : : }
262 : :
263 : : struct ns_get_path_bpf_prog_args {
264 : : struct bpf_prog *prog;
265 : : struct bpf_prog_info *info;
266 : : };
267 : :
268 : 0 : static struct ns_common *bpf_prog_offload_info_fill_ns(void *private_data)
269 : : {
270 : : struct ns_get_path_bpf_prog_args *args = private_data;
271 : 0 : struct bpf_prog_aux *aux = args->prog->aux;
272 : : struct ns_common *ns;
273 : : struct net *net;
274 : :
275 : 0 : rtnl_lock();
276 : 0 : down_read(&bpf_devs_lock);
277 : :
278 : 0 : if (aux->offload) {
279 : 0 : args->info->ifindex = aux->offload->netdev->ifindex;
280 : 0 : net = dev_net(aux->offload->netdev);
281 : : get_net(net);
282 : 0 : ns = &net->ns;
283 : : } else {
284 : 0 : args->info->ifindex = 0;
285 : : ns = NULL;
286 : : }
287 : :
288 : 0 : up_read(&bpf_devs_lock);
289 : 0 : rtnl_unlock();
290 : :
291 : 0 : return ns;
292 : : }
293 : :
294 : 0 : int bpf_prog_offload_info_fill(struct bpf_prog_info *info,
295 : : struct bpf_prog *prog)
296 : : {
297 : 0 : struct ns_get_path_bpf_prog_args args = {
298 : : .prog = prog,
299 : : .info = info,
300 : : };
301 : 0 : struct bpf_prog_aux *aux = prog->aux;
302 : : struct inode *ns_inode;
303 : : struct path ns_path;
304 : : char __user *uinsns;
305 : : void *res;
306 : : u32 ulen;
307 : :
308 : 0 : res = ns_get_path_cb(&ns_path, bpf_prog_offload_info_fill_ns, &args);
309 : 0 : if (IS_ERR(res)) {
310 : 0 : if (!info->ifindex)
311 : : return -ENODEV;
312 : 0 : return PTR_ERR(res);
313 : : }
314 : :
315 : 0 : down_read(&bpf_devs_lock);
316 : :
317 : 0 : if (!aux->offload) {
318 : 0 : up_read(&bpf_devs_lock);
319 : 0 : return -ENODEV;
320 : : }
321 : :
322 : 0 : ulen = info->jited_prog_len;
323 : 0 : info->jited_prog_len = aux->offload->jited_len;
324 : 0 : if (info->jited_prog_len && ulen) {
325 : 0 : uinsns = u64_to_user_ptr(info->jited_prog_insns);
326 : 0 : ulen = min_t(u32, info->jited_prog_len, ulen);
327 : 0 : if (copy_to_user(uinsns, aux->offload->jited_image, ulen)) {
328 : 0 : up_read(&bpf_devs_lock);
329 : 0 : return -EFAULT;
330 : : }
331 : : }
332 : :
333 : 0 : up_read(&bpf_devs_lock);
334 : :
335 : 0 : ns_inode = ns_path.dentry->d_inode;
336 : 0 : info->netns_dev = new_encode_dev(ns_inode->i_sb->s_dev);
337 : 0 : info->netns_ino = ns_inode->i_ino;
338 : 0 : path_put(&ns_path);
339 : :
340 : 0 : return 0;
341 : : }
342 : :
343 : : const struct bpf_prog_ops bpf_offload_prog_ops = {
344 : : };
345 : :
346 : 0 : static int bpf_map_offload_ndo(struct bpf_offloaded_map *offmap,
347 : : enum bpf_netdev_command cmd)
348 : : {
349 : 0 : struct netdev_bpf data = {};
350 : : struct net_device *netdev;
351 : :
352 : 0 : ASSERT_RTNL();
353 : :
354 : 0 : data.command = cmd;
355 : 0 : data.offmap = offmap;
356 : : /* Caller must make sure netdev is valid */
357 : 0 : netdev = offmap->netdev;
358 : :
359 : 0 : return netdev->netdev_ops->ndo_bpf(netdev, &data);
360 : : }
361 : :
362 : 0 : struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr)
363 : : {
364 : 0 : struct net *net = current->nsproxy->net_ns;
365 : : struct bpf_offload_netdev *ondev;
366 : : struct bpf_offloaded_map *offmap;
367 : : int err;
368 : :
369 : 0 : if (!capable(CAP_SYS_ADMIN))
370 : : return ERR_PTR(-EPERM);
371 : 0 : if (attr->map_type != BPF_MAP_TYPE_ARRAY &&
372 : : attr->map_type != BPF_MAP_TYPE_HASH)
373 : : return ERR_PTR(-EINVAL);
374 : :
375 : 0 : offmap = kzalloc(sizeof(*offmap), GFP_USER);
376 : 0 : if (!offmap)
377 : : return ERR_PTR(-ENOMEM);
378 : :
379 : 0 : bpf_map_init_from_attr(&offmap->map, attr);
380 : :
381 : 0 : rtnl_lock();
382 : 0 : down_write(&bpf_devs_lock);
383 : 0 : offmap->netdev = __dev_get_by_index(net, attr->map_ifindex);
384 : : err = bpf_dev_offload_check(offmap->netdev);
385 : 0 : if (err)
386 : : goto err_unlock;
387 : :
388 : 0 : ondev = bpf_offload_find_netdev(offmap->netdev);
389 : 0 : if (!ondev) {
390 : : err = -EINVAL;
391 : : goto err_unlock;
392 : : }
393 : :
394 : 0 : err = bpf_map_offload_ndo(offmap, BPF_OFFLOAD_MAP_ALLOC);
395 : 0 : if (err)
396 : : goto err_unlock;
397 : :
398 : 0 : list_add_tail(&offmap->offloads, &ondev->maps);
399 : 0 : up_write(&bpf_devs_lock);
400 : 0 : rtnl_unlock();
401 : :
402 : 0 : return &offmap->map;
403 : :
404 : : err_unlock:
405 : 0 : up_write(&bpf_devs_lock);
406 : 0 : rtnl_unlock();
407 : 0 : kfree(offmap);
408 : 0 : return ERR_PTR(err);
409 : : }
410 : :
411 : 0 : static void __bpf_map_offload_destroy(struct bpf_offloaded_map *offmap)
412 : : {
413 : 0 : WARN_ON(bpf_map_offload_ndo(offmap, BPF_OFFLOAD_MAP_FREE));
414 : : /* Make sure BPF_MAP_GET_NEXT_ID can't find this dead map */
415 : 0 : bpf_map_free_id(&offmap->map, true);
416 : 0 : list_del_init(&offmap->offloads);
417 : 0 : offmap->netdev = NULL;
418 : 0 : }
419 : :
420 : 0 : void bpf_map_offload_map_free(struct bpf_map *map)
421 : : {
422 : : struct bpf_offloaded_map *offmap = map_to_offmap(map);
423 : :
424 : 0 : rtnl_lock();
425 : 0 : down_write(&bpf_devs_lock);
426 : 0 : if (offmap->netdev)
427 : 0 : __bpf_map_offload_destroy(offmap);
428 : 0 : up_write(&bpf_devs_lock);
429 : 0 : rtnl_unlock();
430 : :
431 : 0 : kfree(offmap);
432 : 0 : }
433 : :
434 : 0 : int bpf_map_offload_lookup_elem(struct bpf_map *map, void *key, void *value)
435 : : {
436 : : struct bpf_offloaded_map *offmap = map_to_offmap(map);
437 : : int ret = -ENODEV;
438 : :
439 : 0 : down_read(&bpf_devs_lock);
440 : 0 : if (offmap->netdev)
441 : 0 : ret = offmap->dev_ops->map_lookup_elem(offmap, key, value);
442 : 0 : up_read(&bpf_devs_lock);
443 : :
444 : 0 : return ret;
445 : : }
446 : :
447 : 0 : int bpf_map_offload_update_elem(struct bpf_map *map,
448 : : void *key, void *value, u64 flags)
449 : : {
450 : : struct bpf_offloaded_map *offmap = map_to_offmap(map);
451 : : int ret = -ENODEV;
452 : :
453 : 0 : if (unlikely(flags > BPF_EXIST))
454 : : return -EINVAL;
455 : :
456 : 0 : down_read(&bpf_devs_lock);
457 : 0 : if (offmap->netdev)
458 : 0 : ret = offmap->dev_ops->map_update_elem(offmap, key, value,
459 : : flags);
460 : 0 : up_read(&bpf_devs_lock);
461 : :
462 : 0 : return ret;
463 : : }
464 : :
465 : 0 : int bpf_map_offload_delete_elem(struct bpf_map *map, void *key)
466 : : {
467 : : struct bpf_offloaded_map *offmap = map_to_offmap(map);
468 : : int ret = -ENODEV;
469 : :
470 : 0 : down_read(&bpf_devs_lock);
471 : 0 : if (offmap->netdev)
472 : 0 : ret = offmap->dev_ops->map_delete_elem(offmap, key);
473 : 0 : up_read(&bpf_devs_lock);
474 : :
475 : 0 : return ret;
476 : : }
477 : :
478 : 0 : int bpf_map_offload_get_next_key(struct bpf_map *map, void *key, void *next_key)
479 : : {
480 : : struct bpf_offloaded_map *offmap = map_to_offmap(map);
481 : : int ret = -ENODEV;
482 : :
483 : 0 : down_read(&bpf_devs_lock);
484 : 0 : if (offmap->netdev)
485 : 0 : ret = offmap->dev_ops->map_get_next_key(offmap, key, next_key);
486 : 0 : up_read(&bpf_devs_lock);
487 : :
488 : 0 : return ret;
489 : : }
490 : :
491 : : struct ns_get_path_bpf_map_args {
492 : : struct bpf_offloaded_map *offmap;
493 : : struct bpf_map_info *info;
494 : : };
495 : :
496 : 0 : static struct ns_common *bpf_map_offload_info_fill_ns(void *private_data)
497 : : {
498 : : struct ns_get_path_bpf_map_args *args = private_data;
499 : : struct ns_common *ns;
500 : : struct net *net;
501 : :
502 : 0 : rtnl_lock();
503 : 0 : down_read(&bpf_devs_lock);
504 : :
505 : 0 : if (args->offmap->netdev) {
506 : 0 : args->info->ifindex = args->offmap->netdev->ifindex;
507 : 0 : net = dev_net(args->offmap->netdev);
508 : : get_net(net);
509 : 0 : ns = &net->ns;
510 : : } else {
511 : 0 : args->info->ifindex = 0;
512 : : ns = NULL;
513 : : }
514 : :
515 : 0 : up_read(&bpf_devs_lock);
516 : 0 : rtnl_unlock();
517 : :
518 : 0 : return ns;
519 : : }
520 : :
521 : 0 : int bpf_map_offload_info_fill(struct bpf_map_info *info, struct bpf_map *map)
522 : : {
523 : 0 : struct ns_get_path_bpf_map_args args = {
524 : : .offmap = map_to_offmap(map),
525 : : .info = info,
526 : : };
527 : : struct inode *ns_inode;
528 : : struct path ns_path;
529 : : void *res;
530 : :
531 : 0 : res = ns_get_path_cb(&ns_path, bpf_map_offload_info_fill_ns, &args);
532 : 0 : if (IS_ERR(res)) {
533 : 0 : if (!info->ifindex)
534 : : return -ENODEV;
535 : 0 : return PTR_ERR(res);
536 : : }
537 : :
538 : 0 : ns_inode = ns_path.dentry->d_inode;
539 : 0 : info->netns_dev = new_encode_dev(ns_inode->i_sb->s_dev);
540 : 0 : info->netns_ino = ns_inode->i_ino;
541 : 0 : path_put(&ns_path);
542 : :
543 : 0 : return 0;
544 : : }
545 : :
546 : 0 : static bool __bpf_offload_dev_match(struct bpf_prog *prog,
547 : : struct net_device *netdev)
548 : : {
549 : : struct bpf_offload_netdev *ondev1, *ondev2;
550 : : struct bpf_prog_offload *offload;
551 : :
552 : 0 : if (!bpf_prog_is_dev_bound(prog->aux))
553 : : return false;
554 : :
555 : 0 : offload = prog->aux->offload;
556 : 0 : if (!offload)
557 : : return false;
558 : 0 : if (offload->netdev == netdev)
559 : : return true;
560 : :
561 : 0 : ondev1 = bpf_offload_find_netdev(offload->netdev);
562 : 0 : ondev2 = bpf_offload_find_netdev(netdev);
563 : :
564 : 0 : return ondev1 && ondev2 && ondev1->offdev == ondev2->offdev;
565 : : }
566 : :
567 : 0 : bool bpf_offload_dev_match(struct bpf_prog *prog, struct net_device *netdev)
568 : : {
569 : : bool ret;
570 : :
571 : 0 : down_read(&bpf_devs_lock);
572 : 0 : ret = __bpf_offload_dev_match(prog, netdev);
573 : 0 : up_read(&bpf_devs_lock);
574 : :
575 : 0 : return ret;
576 : : }
577 : : EXPORT_SYMBOL_GPL(bpf_offload_dev_match);
578 : :
579 : 0 : bool bpf_offload_prog_map_match(struct bpf_prog *prog, struct bpf_map *map)
580 : : {
581 : : struct bpf_offloaded_map *offmap;
582 : : bool ret;
583 : :
584 : 0 : if (!bpf_map_is_dev_bound(map))
585 : 0 : return bpf_map_offload_neutral(map);
586 : : offmap = map_to_offmap(map);
587 : :
588 : 0 : down_read(&bpf_devs_lock);
589 : 0 : ret = __bpf_offload_dev_match(prog, offmap->netdev);
590 : 0 : up_read(&bpf_devs_lock);
591 : :
592 : 0 : return ret;
593 : : }
594 : :
595 : 0 : int bpf_offload_dev_netdev_register(struct bpf_offload_dev *offdev,
596 : : struct net_device *netdev)
597 : : {
598 : : struct bpf_offload_netdev *ondev;
599 : : int err;
600 : :
601 : 0 : ondev = kzalloc(sizeof(*ondev), GFP_KERNEL);
602 : 0 : if (!ondev)
603 : : return -ENOMEM;
604 : :
605 : 0 : ondev->netdev = netdev;
606 : 0 : ondev->offdev = offdev;
607 : 0 : INIT_LIST_HEAD(&ondev->progs);
608 : 0 : INIT_LIST_HEAD(&ondev->maps);
609 : :
610 : 0 : down_write(&bpf_devs_lock);
611 : 0 : err = rhashtable_insert_fast(&offdevs, &ondev->l, offdevs_params);
612 : 0 : if (err) {
613 : 0 : netdev_warn(netdev, "failed to register for BPF offload\n");
614 : : goto err_unlock_free;
615 : : }
616 : :
617 : 0 : list_add(&ondev->offdev_netdevs, &offdev->netdevs);
618 : 0 : up_write(&bpf_devs_lock);
619 : 0 : return 0;
620 : :
621 : : err_unlock_free:
622 : 0 : up_write(&bpf_devs_lock);
623 : 0 : kfree(ondev);
624 : 0 : return err;
625 : : }
626 : : EXPORT_SYMBOL_GPL(bpf_offload_dev_netdev_register);
627 : :
628 : 0 : void bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev,
629 : : struct net_device *netdev)
630 : : {
631 : : struct bpf_offload_netdev *ondev, *altdev;
632 : : struct bpf_offloaded_map *offmap, *mtmp;
633 : : struct bpf_prog_offload *offload, *ptmp;
634 : :
635 : 0 : ASSERT_RTNL();
636 : :
637 : 0 : down_write(&bpf_devs_lock);
638 : 0 : ondev = rhashtable_lookup_fast(&offdevs, &netdev, offdevs_params);
639 : 0 : if (WARN_ON(!ondev))
640 : : goto unlock;
641 : :
642 : 0 : WARN_ON(rhashtable_remove_fast(&offdevs, &ondev->l, offdevs_params));
643 : : list_del(&ondev->offdev_netdevs);
644 : :
645 : : /* Try to move the objects to another netdev of the device */
646 : 0 : altdev = list_first_entry_or_null(&offdev->netdevs,
647 : : struct bpf_offload_netdev,
648 : : offdev_netdevs);
649 : 0 : if (altdev) {
650 : 0 : list_for_each_entry(offload, &ondev->progs, offloads)
651 : 0 : offload->netdev = altdev->netdev;
652 : 0 : list_splice_init(&ondev->progs, &altdev->progs);
653 : :
654 : 0 : list_for_each_entry(offmap, &ondev->maps, offloads)
655 : 0 : offmap->netdev = altdev->netdev;
656 : 0 : list_splice_init(&ondev->maps, &altdev->maps);
657 : : } else {
658 : 0 : list_for_each_entry_safe(offload, ptmp, &ondev->progs, offloads)
659 : 0 : __bpf_prog_offload_destroy(offload->prog);
660 : 0 : list_for_each_entry_safe(offmap, mtmp, &ondev->maps, offloads)
661 : 0 : __bpf_map_offload_destroy(offmap);
662 : : }
663 : :
664 : 0 : WARN_ON(!list_empty(&ondev->progs));
665 : 0 : WARN_ON(!list_empty(&ondev->maps));
666 : 0 : kfree(ondev);
667 : : unlock:
668 : 0 : up_write(&bpf_devs_lock);
669 : 0 : }
670 : : EXPORT_SYMBOL_GPL(bpf_offload_dev_netdev_unregister);
671 : :
672 : : struct bpf_offload_dev *
673 : 0 : bpf_offload_dev_create(const struct bpf_prog_offload_ops *ops, void *priv)
674 : : {
675 : : struct bpf_offload_dev *offdev;
676 : : int err;
677 : :
678 : 0 : down_write(&bpf_devs_lock);
679 : 0 : if (!offdevs_inited) {
680 : 0 : err = rhashtable_init(&offdevs, &offdevs_params);
681 : 0 : if (err) {
682 : 0 : up_write(&bpf_devs_lock);
683 : 0 : return ERR_PTR(err);
684 : : }
685 : 0 : offdevs_inited = true;
686 : : }
687 : 0 : up_write(&bpf_devs_lock);
688 : :
689 : 0 : offdev = kzalloc(sizeof(*offdev), GFP_KERNEL);
690 : 0 : if (!offdev)
691 : : return ERR_PTR(-ENOMEM);
692 : :
693 : 0 : offdev->ops = ops;
694 : 0 : offdev->priv = priv;
695 : 0 : INIT_LIST_HEAD(&offdev->netdevs);
696 : :
697 : 0 : return offdev;
698 : : }
699 : : EXPORT_SYMBOL_GPL(bpf_offload_dev_create);
700 : :
701 : 0 : void bpf_offload_dev_destroy(struct bpf_offload_dev *offdev)
702 : : {
703 : 0 : WARN_ON(!list_empty(&offdev->netdevs));
704 : 0 : kfree(offdev);
705 : 0 : }
706 : : EXPORT_SYMBOL_GPL(bpf_offload_dev_destroy);
707 : :
708 : 0 : void *bpf_offload_dev_priv(struct bpf_offload_dev *offdev)
709 : : {
710 : 0 : return offdev->priv;
711 : : }
712 : : EXPORT_SYMBOL_GPL(bpf_offload_dev_priv);
|