diff options
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/bpf/main.c | 23 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/bpf/main.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/bpf/offload.c | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_app.c | 17 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_app.h | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 2 | ||||
-rw-r--r-- | drivers/net/netdevsim/bpf.c | 50 | ||||
-rw-r--r-- | drivers/net/netdevsim/netdev.c | 103 | ||||
-rw-r--r-- | drivers/net/netdevsim/netdevsim.h | 23 | ||||
-rw-r--r-- | include/linux/bpf.h | 13 | ||||
-rw-r--r-- | kernel/bpf/cgroup.c | 7 | ||||
-rw-r--r-- | kernel/bpf/core.c | 2 | ||||
-rw-r--r-- | kernel/bpf/offload.c | 223 | ||||
-rw-r--r-- | kernel/bpf/sockmap.c | 3 | ||||
-rw-r--r-- | kernel/bpf/verifier.c | 2 | ||||
-rw-r--r-- | samples/bpf/bpf_load.c | 3 | ||||
-rw-r--r-- | samples/bpf/test_cgrp2_sock2.c | 2 | ||||
-rw-r--r-- | tools/bpf/bpftool/Makefile | 2 | ||||
-rw-r--r-- | tools/lib/bpf/Makefile | 6 | ||||
-rwxr-xr-x | tools/testing/selftests/bpf/test_offload.py | 151 |
21 files changed, 555 insertions, 101 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index b95b94d008cf..458f49235d06 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c | |||
@@ -404,6 +404,20 @@ err_release_free: | |||
404 | return -EINVAL; | 404 | return -EINVAL; |
405 | } | 405 | } |
406 | 406 | ||
407 | static int nfp_bpf_ndo_init(struct nfp_app *app, struct net_device *netdev) | ||
408 | { | ||
409 | struct nfp_app_bpf *bpf = app->priv; | ||
410 | |||
411 | return bpf_offload_dev_netdev_register(bpf->bpf_dev, netdev); | ||
412 | } | ||
413 | |||
414 | static void nfp_bpf_ndo_uninit(struct nfp_app *app, struct net_device *netdev) | ||
415 | { | ||
416 | struct nfp_app_bpf *bpf = app->priv; | ||
417 | |||
418 | bpf_offload_dev_netdev_unregister(bpf->bpf_dev, netdev); | ||
419 | } | ||
420 | |||
407 | static int nfp_bpf_init(struct nfp_app *app) | 421 | static int nfp_bpf_init(struct nfp_app *app) |
408 | { | 422 | { |
409 | struct nfp_app_bpf *bpf; | 423 | struct nfp_app_bpf *bpf; |
@@ -427,6 +441,11 @@ static int nfp_bpf_init(struct nfp_app *app) | |||
427 | if (err) | 441 | if (err) |
428 | goto err_free_neutral_maps; | 442 | goto err_free_neutral_maps; |
429 | 443 | ||
444 | bpf->bpf_dev = bpf_offload_dev_create(); | ||
445 | err = PTR_ERR_OR_ZERO(bpf->bpf_dev); | ||
446 | if (err) | ||
447 | goto err_free_neutral_maps; | ||
448 | |||
430 | return 0; | 449 | return 0; |
431 | 450 | ||
432 | err_free_neutral_maps: | 451 | err_free_neutral_maps: |
@@ -445,6 +464,7 @@ static void nfp_bpf_clean(struct nfp_app *app) | |||
445 | { | 464 | { |
446 | struct nfp_app_bpf *bpf = app->priv; | 465 | struct nfp_app_bpf *bpf = app->priv; |
447 | 466 | ||
467 | bpf_offload_dev_destroy(bpf->bpf_dev); | ||
448 | WARN_ON(!skb_queue_empty(&bpf->cmsg_replies)); | 468 | WARN_ON(!skb_queue_empty(&bpf->cmsg_replies)); |
449 | WARN_ON(!list_empty(&bpf->map_list)); | 469 | WARN_ON(!list_empty(&bpf->map_list)); |
450 | WARN_ON(bpf->maps_in_use || bpf->map_elems_in_use); | 470 | WARN_ON(bpf->maps_in_use || bpf->map_elems_in_use); |
@@ -466,6 +486,9 @@ const struct nfp_app_type app_bpf = { | |||
466 | 486 | ||
467 | .extra_cap = nfp_bpf_extra_cap, | 487 | .extra_cap = nfp_bpf_extra_cap, |
468 | 488 | ||
489 | .ndo_init = nfp_bpf_ndo_init, | ||
490 | .ndo_uninit = nfp_bpf_ndo_uninit, | ||
491 | |||
469 | .vnic_alloc = nfp_bpf_vnic_alloc, | 492 | .vnic_alloc = nfp_bpf_vnic_alloc, |
470 | .vnic_free = nfp_bpf_vnic_free, | 493 | .vnic_free = nfp_bpf_vnic_free, |
471 | 494 | ||
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 9845c1a2d4c2..bec935468f90 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h | |||
@@ -110,6 +110,8 @@ enum pkt_vec { | |||
110 | * struct nfp_app_bpf - bpf app priv structure | 110 | * struct nfp_app_bpf - bpf app priv structure |
111 | * @app: backpointer to the app | 111 | * @app: backpointer to the app |
112 | * | 112 | * |
113 | * @bpf_dev: BPF offload device handle | ||
114 | * | ||
113 | * @tag_allocator: bitmap of control message tags in use | 115 | * @tag_allocator: bitmap of control message tags in use |
114 | * @tag_alloc_next: next tag bit to allocate | 116 | * @tag_alloc_next: next tag bit to allocate |
115 | * @tag_alloc_last: next tag bit to be freed | 117 | * @tag_alloc_last: next tag bit to be freed |
@@ -150,6 +152,8 @@ enum pkt_vec { | |||
150 | struct nfp_app_bpf { | 152 | struct nfp_app_bpf { |
151 | struct nfp_app *app; | 153 | struct nfp_app *app; |
152 | 154 | ||
155 | struct bpf_offload_dev *bpf_dev; | ||
156 | |||
153 | DECLARE_BITMAP(tag_allocator, U16_MAX + 1); | 157 | DECLARE_BITMAP(tag_allocator, U16_MAX + 1); |
154 | u16 tag_alloc_next; | 158 | u16 tag_alloc_next; |
155 | u16 tag_alloc_last; | 159 | u16 tag_alloc_last; |
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index 78f44c4d95b4..49b03f7dbf46 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c | |||
@@ -566,14 +566,8 @@ int nfp_net_bpf_offload(struct nfp_net *nn, struct bpf_prog *prog, | |||
566 | { | 566 | { |
567 | int err; | 567 | int err; |
568 | 568 | ||
569 | if (prog) { | 569 | if (prog && !bpf_offload_dev_match(prog, nn->dp.netdev)) |
570 | struct bpf_prog_offload *offload = prog->aux->offload; | 570 | return -EINVAL; |
571 | |||
572 | if (!offload) | ||
573 | return -EINVAL; | ||
574 | if (offload->netdev != nn->dp.netdev) | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | 571 | ||
578 | if (prog && old_prog) { | 572 | if (prog && old_prog) { |
579 | u8 cap; | 573 | u8 cap; |
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c index f28b244f4ee7..69d4ae7a61f3 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c | |||
@@ -86,6 +86,23 @@ const char *nfp_app_mip_name(struct nfp_app *app) | |||
86 | return nfp_mip_name(app->pf->mip); | 86 | return nfp_mip_name(app->pf->mip); |
87 | } | 87 | } |
88 | 88 | ||
89 | int nfp_app_ndo_init(struct net_device *netdev) | ||
90 | { | ||
91 | struct nfp_app *app = nfp_app_from_netdev(netdev); | ||
92 | |||
93 | if (!app || !app->type->ndo_init) | ||
94 | return 0; | ||
95 | return app->type->ndo_init(app, netdev); | ||
96 | } | ||
97 | |||
98 | void nfp_app_ndo_uninit(struct net_device *netdev) | ||
99 | { | ||
100 | struct nfp_app *app = nfp_app_from_netdev(netdev); | ||
101 | |||
102 | if (app && app->type->ndo_uninit) | ||
103 | app->type->ndo_uninit(app, netdev); | ||
104 | } | ||
105 | |||
89 | u64 *nfp_app_port_get_stats(struct nfp_port *port, u64 *data) | 106 | u64 *nfp_app_port_get_stats(struct nfp_port *port, u64 *data) |
90 | { | 107 | { |
91 | if (!port || !port->app || !port->app->type->port_get_stats) | 108 | if (!port || !port->app || !port->app->type->port_get_stats) |
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h index ee74caacb015..afbc19aa66a8 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h | |||
@@ -78,6 +78,8 @@ extern const struct nfp_app_type app_abm; | |||
78 | * @init: perform basic app checks and init | 78 | * @init: perform basic app checks and init |
79 | * @clean: clean app state | 79 | * @clean: clean app state |
80 | * @extra_cap: extra capabilities string | 80 | * @extra_cap: extra capabilities string |
81 | * @ndo_init: vNIC and repr netdev .ndo_init | ||
82 | * @ndo_uninit: vNIC and repr netdev .ndo_unint | ||
81 | * @vnic_alloc: allocate vNICs (assign port types, etc.) | 83 | * @vnic_alloc: allocate vNICs (assign port types, etc.) |
82 | * @vnic_free: free up app's vNIC state | 84 | * @vnic_free: free up app's vNIC state |
83 | * @vnic_init: vNIC netdev was registered | 85 | * @vnic_init: vNIC netdev was registered |
@@ -117,6 +119,9 @@ struct nfp_app_type { | |||
117 | 119 | ||
118 | const char *(*extra_cap)(struct nfp_app *app, struct nfp_net *nn); | 120 | const char *(*extra_cap)(struct nfp_app *app, struct nfp_net *nn); |
119 | 121 | ||
122 | int (*ndo_init)(struct nfp_app *app, struct net_device *netdev); | ||
123 | void (*ndo_uninit)(struct nfp_app *app, struct net_device *netdev); | ||
124 | |||
120 | int (*vnic_alloc)(struct nfp_app *app, struct nfp_net *nn, | 125 | int (*vnic_alloc)(struct nfp_app *app, struct nfp_net *nn, |
121 | unsigned int id); | 126 | unsigned int id); |
122 | void (*vnic_free)(struct nfp_app *app, struct nfp_net *nn); | 127 | void (*vnic_free)(struct nfp_app *app, struct nfp_net *nn); |
@@ -200,6 +205,9 @@ static inline void nfp_app_clean(struct nfp_app *app) | |||
200 | app->type->clean(app); | 205 | app->type->clean(app); |
201 | } | 206 | } |
202 | 207 | ||
208 | int nfp_app_ndo_init(struct net_device *netdev); | ||
209 | void nfp_app_ndo_uninit(struct net_device *netdev); | ||
210 | |||
203 | static inline int nfp_app_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, | 211 | static inline int nfp_app_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, |
204 | unsigned int id) | 212 | unsigned int id) |
205 | { | 213 | { |
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index a712e83c3f0f..279b8ab8a17b 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c | |||
@@ -3480,6 +3480,8 @@ static int nfp_net_set_mac_address(struct net_device *netdev, void *addr) | |||
3480 | } | 3480 | } |
3481 | 3481 | ||
3482 | const struct net_device_ops nfp_net_netdev_ops = { | 3482 | const struct net_device_ops nfp_net_netdev_ops = { |
3483 | .ndo_init = nfp_app_ndo_init, | ||
3484 | .ndo_uninit = nfp_app_ndo_uninit, | ||
3483 | .ndo_open = nfp_net_netdev_open, | 3485 | .ndo_open = nfp_net_netdev_open, |
3484 | .ndo_stop = nfp_net_netdev_close, | 3486 | .ndo_stop = nfp_net_netdev_close, |
3485 | .ndo_start_xmit = nfp_net_tx, | 3487 | .ndo_start_xmit = nfp_net_tx, |
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c index d7b712f6362f..18a09cdcd9c6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | |||
@@ -262,6 +262,8 @@ err_port_disable: | |||
262 | } | 262 | } |
263 | 263 | ||
264 | const struct net_device_ops nfp_repr_netdev_ops = { | 264 | const struct net_device_ops nfp_repr_netdev_ops = { |
265 | .ndo_init = nfp_app_ndo_init, | ||
266 | .ndo_uninit = nfp_app_ndo_uninit, | ||
265 | .ndo_open = nfp_repr_open, | 267 | .ndo_open = nfp_repr_open, |
266 | .ndo_stop = nfp_repr_stop, | 268 | .ndo_stop = nfp_repr_stop, |
267 | .ndo_start_xmit = nfp_repr_xmit, | 269 | .ndo_start_xmit = nfp_repr_xmit, |
diff --git a/drivers/net/netdevsim/bpf.c b/drivers/net/netdevsim/bpf.c index c36d2a768202..81444208b216 100644 --- a/drivers/net/netdevsim/bpf.c +++ b/drivers/net/netdevsim/bpf.c | |||
@@ -238,8 +238,8 @@ static int nsim_bpf_create_prog(struct netdevsim *ns, struct bpf_prog *prog) | |||
238 | state->state = "verify"; | 238 | state->state = "verify"; |
239 | 239 | ||
240 | /* Program id is not populated yet when we create the state. */ | 240 | /* Program id is not populated yet when we create the state. */ |
241 | sprintf(name, "%u", ns->prog_id_gen++); | 241 | sprintf(name, "%u", ns->sdev->prog_id_gen++); |
242 | state->ddir = debugfs_create_dir(name, ns->ddir_bpf_bound_progs); | 242 | state->ddir = debugfs_create_dir(name, ns->sdev->ddir_bpf_bound_progs); |
243 | if (IS_ERR_OR_NULL(state->ddir)) { | 243 | if (IS_ERR_OR_NULL(state->ddir)) { |
244 | kfree(state); | 244 | kfree(state); |
245 | return -ENOMEM; | 245 | return -ENOMEM; |
@@ -250,7 +250,7 @@ static int nsim_bpf_create_prog(struct netdevsim *ns, struct bpf_prog *prog) | |||
250 | &state->state, &nsim_bpf_string_fops); | 250 | &state->state, &nsim_bpf_string_fops); |
251 | debugfs_create_bool("loaded", 0400, state->ddir, &state->is_loaded); | 251 | debugfs_create_bool("loaded", 0400, state->ddir, &state->is_loaded); |
252 | 252 | ||
253 | list_add_tail(&state->l, &ns->bpf_bound_progs); | 253 | list_add_tail(&state->l, &ns->sdev->bpf_bound_progs); |
254 | 254 | ||
255 | prog->aux->offload->dev_priv = state; | 255 | prog->aux->offload->dev_priv = state; |
256 | 256 | ||
@@ -294,7 +294,7 @@ nsim_setup_prog_hw_checks(struct netdevsim *ns, struct netdev_bpf *bpf) | |||
294 | NSIM_EA(bpf->extack, "xdpoffload of non-bound program"); | 294 | NSIM_EA(bpf->extack, "xdpoffload of non-bound program"); |
295 | return -EINVAL; | 295 | return -EINVAL; |
296 | } | 296 | } |
297 | if (bpf->prog->aux->offload->netdev != ns->netdev) { | 297 | if (!bpf_offload_dev_match(bpf->prog, ns->netdev)) { |
298 | NSIM_EA(bpf->extack, "program bound to different dev"); | 298 | NSIM_EA(bpf->extack, "program bound to different dev"); |
299 | return -EINVAL; | 299 | return -EINVAL; |
300 | } | 300 | } |
@@ -497,7 +497,7 @@ nsim_bpf_map_alloc(struct netdevsim *ns, struct bpf_offloaded_map *offmap) | |||
497 | } | 497 | } |
498 | 498 | ||
499 | offmap->dev_ops = &nsim_bpf_map_ops; | 499 | offmap->dev_ops = &nsim_bpf_map_ops; |
500 | list_add_tail(&nmap->l, &ns->bpf_bound_maps); | 500 | list_add_tail(&nmap->l, &ns->sdev->bpf_bound_maps); |
501 | 501 | ||
502 | return 0; | 502 | return 0; |
503 | 503 | ||
@@ -582,8 +582,26 @@ int nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf) | |||
582 | 582 | ||
583 | int nsim_bpf_init(struct netdevsim *ns) | 583 | int nsim_bpf_init(struct netdevsim *ns) |
584 | { | 584 | { |
585 | INIT_LIST_HEAD(&ns->bpf_bound_progs); | 585 | int err; |
586 | INIT_LIST_HEAD(&ns->bpf_bound_maps); | 586 | |
587 | if (ns->sdev->refcnt == 1) { | ||
588 | INIT_LIST_HEAD(&ns->sdev->bpf_bound_progs); | ||
589 | INIT_LIST_HEAD(&ns->sdev->bpf_bound_maps); | ||
590 | |||
591 | ns->sdev->ddir_bpf_bound_progs = | ||
592 | debugfs_create_dir("bpf_bound_progs", ns->sdev->ddir); | ||
593 | if (IS_ERR_OR_NULL(ns->sdev->ddir_bpf_bound_progs)) | ||
594 | return -ENOMEM; | ||
595 | |||
596 | ns->sdev->bpf_dev = bpf_offload_dev_create(); | ||
597 | err = PTR_ERR_OR_ZERO(ns->sdev->bpf_dev); | ||
598 | if (err) | ||
599 | return err; | ||
600 | } | ||
601 | |||
602 | err = bpf_offload_dev_netdev_register(ns->sdev->bpf_dev, ns->netdev); | ||
603 | if (err) | ||
604 | goto err_destroy_bdev; | ||
587 | 605 | ||
588 | debugfs_create_u32("bpf_offloaded_id", 0400, ns->ddir, | 606 | debugfs_create_u32("bpf_offloaded_id", 0400, ns->ddir, |
589 | &ns->bpf_offloaded_id); | 607 | &ns->bpf_offloaded_id); |
@@ -593,10 +611,6 @@ int nsim_bpf_init(struct netdevsim *ns) | |||
593 | &ns->bpf_bind_accept); | 611 | &ns->bpf_bind_accept); |
594 | debugfs_create_u32("bpf_bind_verifier_delay", 0600, ns->ddir, | 612 | debugfs_create_u32("bpf_bind_verifier_delay", 0600, ns->ddir, |
595 | &ns->bpf_bind_verifier_delay); | 613 | &ns->bpf_bind_verifier_delay); |
596 | ns->ddir_bpf_bound_progs = | ||
597 | debugfs_create_dir("bpf_bound_progs", ns->ddir); | ||
598 | if (IS_ERR_OR_NULL(ns->ddir_bpf_bound_progs)) | ||
599 | return -ENOMEM; | ||
600 | 614 | ||
601 | ns->bpf_tc_accept = true; | 615 | ns->bpf_tc_accept = true; |
602 | debugfs_create_bool("bpf_tc_accept", 0600, ns->ddir, | 616 | debugfs_create_bool("bpf_tc_accept", 0600, ns->ddir, |
@@ -615,13 +629,23 @@ int nsim_bpf_init(struct netdevsim *ns) | |||
615 | &ns->bpf_map_accept); | 629 | &ns->bpf_map_accept); |
616 | 630 | ||
617 | return 0; | 631 | return 0; |
632 | |||
633 | err_destroy_bdev: | ||
634 | if (ns->sdev->refcnt == 1) | ||
635 | bpf_offload_dev_destroy(ns->sdev->bpf_dev); | ||
636 | return err; | ||
618 | } | 637 | } |
619 | 638 | ||
620 | void nsim_bpf_uninit(struct netdevsim *ns) | 639 | void nsim_bpf_uninit(struct netdevsim *ns) |
621 | { | 640 | { |
622 | WARN_ON(!list_empty(&ns->bpf_bound_progs)); | ||
623 | WARN_ON(!list_empty(&ns->bpf_bound_maps)); | ||
624 | WARN_ON(ns->xdp.prog); | 641 | WARN_ON(ns->xdp.prog); |
625 | WARN_ON(ns->xdp_hw.prog); | 642 | WARN_ON(ns->xdp_hw.prog); |
626 | WARN_ON(ns->bpf_offloaded); | 643 | WARN_ON(ns->bpf_offloaded); |
644 | bpf_offload_dev_netdev_unregister(ns->sdev->bpf_dev, ns->netdev); | ||
645 | |||
646 | if (ns->sdev->refcnt == 1) { | ||
647 | WARN_ON(!list_empty(&ns->sdev->bpf_bound_progs)); | ||
648 | WARN_ON(!list_empty(&ns->sdev->bpf_bound_maps)); | ||
649 | bpf_offload_dev_destroy(ns->sdev->bpf_dev); | ||
650 | } | ||
627 | } | 651 | } |
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index a7b179f0d954..2d244551298b 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <net/netlink.h> | 22 | #include <net/netlink.h> |
23 | #include <net/pkt_cls.h> | 23 | #include <net/pkt_cls.h> |
24 | #include <net/rtnetlink.h> | 24 | #include <net/rtnetlink.h> |
25 | #include <net/switchdev.h> | ||
25 | 26 | ||
26 | #include "netdevsim.h" | 27 | #include "netdevsim.h" |
27 | 28 | ||
@@ -144,8 +145,29 @@ static struct device_type nsim_dev_type = { | |||
144 | .release = nsim_dev_release, | 145 | .release = nsim_dev_release, |
145 | }; | 146 | }; |
146 | 147 | ||
148 | static int | ||
149 | nsim_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) | ||
150 | { | ||
151 | struct netdevsim *ns = netdev_priv(dev); | ||
152 | |||
153 | switch (attr->id) { | ||
154 | case SWITCHDEV_ATTR_ID_PORT_PARENT_ID: | ||
155 | attr->u.ppid.id_len = sizeof(ns->sdev->switch_id); | ||
156 | memcpy(&attr->u.ppid.id, &ns->sdev->switch_id, | ||
157 | attr->u.ppid.id_len); | ||
158 | return 0; | ||
159 | default: | ||
160 | return -EOPNOTSUPP; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static const struct switchdev_ops nsim_switchdev_ops = { | ||
165 | .switchdev_port_attr_get = nsim_port_attr_get, | ||
166 | }; | ||
167 | |||
147 | static int nsim_init(struct net_device *dev) | 168 | static int nsim_init(struct net_device *dev) |
148 | { | 169 | { |
170 | char sdev_ddir_name[10], sdev_link_name[32]; | ||
149 | struct netdevsim *ns = netdev_priv(dev); | 171 | struct netdevsim *ns = netdev_priv(dev); |
150 | int err; | 172 | int err; |
151 | 173 | ||
@@ -154,9 +176,32 @@ static int nsim_init(struct net_device *dev) | |||
154 | if (IS_ERR_OR_NULL(ns->ddir)) | 176 | if (IS_ERR_OR_NULL(ns->ddir)) |
155 | return -ENOMEM; | 177 | return -ENOMEM; |
156 | 178 | ||
179 | if (!ns->sdev) { | ||
180 | ns->sdev = kzalloc(sizeof(*ns->sdev), GFP_KERNEL); | ||
181 | if (!ns->sdev) { | ||
182 | err = -ENOMEM; | ||
183 | goto err_debugfs_destroy; | ||
184 | } | ||
185 | ns->sdev->refcnt = 1; | ||
186 | ns->sdev->switch_id = nsim_dev_id; | ||
187 | sprintf(sdev_ddir_name, "%u", ns->sdev->switch_id); | ||
188 | ns->sdev->ddir = debugfs_create_dir(sdev_ddir_name, | ||
189 | nsim_sdev_ddir); | ||
190 | if (IS_ERR_OR_NULL(ns->sdev->ddir)) { | ||
191 | err = PTR_ERR_OR_ZERO(ns->sdev->ddir) ?: -EINVAL; | ||
192 | goto err_sdev_free; | ||
193 | } | ||
194 | } else { | ||
195 | sprintf(sdev_ddir_name, "%u", ns->sdev->switch_id); | ||
196 | ns->sdev->refcnt++; | ||
197 | } | ||
198 | |||
199 | sprintf(sdev_link_name, "../../" DRV_NAME "_sdev/%s", sdev_ddir_name); | ||
200 | debugfs_create_symlink("sdev", ns->ddir, sdev_link_name); | ||
201 | |||
157 | err = nsim_bpf_init(ns); | 202 | err = nsim_bpf_init(ns); |
158 | if (err) | 203 | if (err) |
159 | goto err_debugfs_destroy; | 204 | goto err_sdev_destroy; |
160 | 205 | ||
161 | ns->dev.id = nsim_dev_id++; | 206 | ns->dev.id = nsim_dev_id++; |
162 | ns->dev.bus = &nsim_bus; | 207 | ns->dev.bus = &nsim_bus; |
@@ -166,6 +211,7 @@ static int nsim_init(struct net_device *dev) | |||
166 | goto err_bpf_uninit; | 211 | goto err_bpf_uninit; |
167 | 212 | ||
168 | SET_NETDEV_DEV(dev, &ns->dev); | 213 | SET_NETDEV_DEV(dev, &ns->dev); |
214 | SWITCHDEV_SET_OPS(dev, &nsim_switchdev_ops); | ||
169 | 215 | ||
170 | err = nsim_devlink_setup(ns); | 216 | err = nsim_devlink_setup(ns); |
171 | if (err) | 217 | if (err) |
@@ -179,6 +225,12 @@ err_unreg_dev: | |||
179 | device_unregister(&ns->dev); | 225 | device_unregister(&ns->dev); |
180 | err_bpf_uninit: | 226 | err_bpf_uninit: |
181 | nsim_bpf_uninit(ns); | 227 | nsim_bpf_uninit(ns); |
228 | err_sdev_destroy: | ||
229 | if (!--ns->sdev->refcnt) { | ||
230 | debugfs_remove_recursive(ns->sdev->ddir); | ||
231 | err_sdev_free: | ||
232 | kfree(ns->sdev); | ||
233 | } | ||
182 | err_debugfs_destroy: | 234 | err_debugfs_destroy: |
183 | debugfs_remove_recursive(ns->ddir); | 235 | debugfs_remove_recursive(ns->ddir); |
184 | return err; | 236 | return err; |
@@ -192,6 +244,10 @@ static void nsim_uninit(struct net_device *dev) | |||
192 | nsim_devlink_teardown(ns); | 244 | nsim_devlink_teardown(ns); |
193 | debugfs_remove_recursive(ns->ddir); | 245 | debugfs_remove_recursive(ns->ddir); |
194 | nsim_bpf_uninit(ns); | 246 | nsim_bpf_uninit(ns); |
247 | if (!--ns->sdev->refcnt) { | ||
248 | debugfs_remove_recursive(ns->sdev->ddir); | ||
249 | kfree(ns->sdev); | ||
250 | } | ||
195 | } | 251 | } |
196 | 252 | ||
197 | static void nsim_free(struct net_device *dev) | 253 | static void nsim_free(struct net_device *dev) |
@@ -470,14 +526,48 @@ static int nsim_validate(struct nlattr *tb[], struct nlattr *data[], | |||
470 | return 0; | 526 | return 0; |
471 | } | 527 | } |
472 | 528 | ||
529 | static int nsim_newlink(struct net *src_net, struct net_device *dev, | ||
530 | struct nlattr *tb[], struct nlattr *data[], | ||
531 | struct netlink_ext_ack *extack) | ||
532 | { | ||
533 | struct netdevsim *ns = netdev_priv(dev); | ||
534 | |||
535 | if (tb[IFLA_LINK]) { | ||
536 | struct net_device *joindev; | ||
537 | struct netdevsim *joinns; | ||
538 | |||
539 | joindev = __dev_get_by_index(src_net, | ||
540 | nla_get_u32(tb[IFLA_LINK])); | ||
541 | if (!joindev) | ||
542 | return -ENODEV; | ||
543 | if (joindev->netdev_ops != &nsim_netdev_ops) | ||
544 | return -EINVAL; | ||
545 | |||
546 | joinns = netdev_priv(joindev); | ||
547 | if (!joinns->sdev || !joinns->sdev->refcnt) | ||
548 | return -EINVAL; | ||
549 | ns->sdev = joinns->sdev; | ||
550 | } | ||
551 | |||
552 | return register_netdevice(dev); | ||
553 | } | ||
554 | |||
555 | static void nsim_dellink(struct net_device *dev, struct list_head *head) | ||
556 | { | ||
557 | unregister_netdevice_queue(dev, head); | ||
558 | } | ||
559 | |||
473 | static struct rtnl_link_ops nsim_link_ops __read_mostly = { | 560 | static struct rtnl_link_ops nsim_link_ops __read_mostly = { |
474 | .kind = DRV_NAME, | 561 | .kind = DRV_NAME, |
475 | .priv_size = sizeof(struct netdevsim), | 562 | .priv_size = sizeof(struct netdevsim), |
476 | .setup = nsim_setup, | 563 | .setup = nsim_setup, |
477 | .validate = nsim_validate, | 564 | .validate = nsim_validate, |
565 | .newlink = nsim_newlink, | ||
566 | .dellink = nsim_dellink, | ||
478 | }; | 567 | }; |
479 | 568 | ||
480 | struct dentry *nsim_ddir; | 569 | struct dentry *nsim_ddir; |
570 | struct dentry *nsim_sdev_ddir; | ||
481 | 571 | ||
482 | static int __init nsim_module_init(void) | 572 | static int __init nsim_module_init(void) |
483 | { | 573 | { |
@@ -487,9 +577,15 @@ static int __init nsim_module_init(void) | |||
487 | if (IS_ERR_OR_NULL(nsim_ddir)) | 577 | if (IS_ERR_OR_NULL(nsim_ddir)) |
488 | return -ENOMEM; | 578 | return -ENOMEM; |
489 | 579 | ||
580 | nsim_sdev_ddir = debugfs_create_dir(DRV_NAME "_sdev", NULL); | ||
581 | if (IS_ERR_OR_NULL(nsim_sdev_ddir)) { | ||
582 | err = -ENOMEM; | ||
583 | goto err_debugfs_destroy; | ||
584 | } | ||
585 | |||
490 | err = bus_register(&nsim_bus); | 586 | err = bus_register(&nsim_bus); |
491 | if (err) | 587 | if (err) |
492 | goto err_debugfs_destroy; | 588 | goto err_sdir_destroy; |
493 | 589 | ||
494 | err = nsim_devlink_init(); | 590 | err = nsim_devlink_init(); |
495 | if (err) | 591 | if (err) |
@@ -505,6 +601,8 @@ err_dl_fini: | |||
505 | nsim_devlink_exit(); | 601 | nsim_devlink_exit(); |
506 | err_unreg_bus: | 602 | err_unreg_bus: |
507 | bus_unregister(&nsim_bus); | 603 | bus_unregister(&nsim_bus); |
604 | err_sdir_destroy: | ||
605 | debugfs_remove_recursive(nsim_sdev_ddir); | ||
508 | err_debugfs_destroy: | 606 | err_debugfs_destroy: |
509 | debugfs_remove_recursive(nsim_ddir); | 607 | debugfs_remove_recursive(nsim_ddir); |
510 | return err; | 608 | return err; |
@@ -515,6 +613,7 @@ static void __exit nsim_module_exit(void) | |||
515 | rtnl_link_unregister(&nsim_link_ops); | 613 | rtnl_link_unregister(&nsim_link_ops); |
516 | nsim_devlink_exit(); | 614 | nsim_devlink_exit(); |
517 | bus_unregister(&nsim_bus); | 615 | bus_unregister(&nsim_bus); |
616 | debugfs_remove_recursive(nsim_sdev_ddir); | ||
518 | debugfs_remove_recursive(nsim_ddir); | 617 | debugfs_remove_recursive(nsim_ddir); |
519 | } | 618 | } |
520 | 619 | ||
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 0aeabbe81cc6..02be199eb005 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h | |||
@@ -27,9 +27,25 @@ | |||
27 | #define NSIM_EA(extack, msg) NL_SET_ERR_MSG_MOD((extack), msg) | 27 | #define NSIM_EA(extack, msg) NL_SET_ERR_MSG_MOD((extack), msg) |
28 | 28 | ||
29 | struct bpf_prog; | 29 | struct bpf_prog; |
30 | struct bpf_offload_dev; | ||
30 | struct dentry; | 31 | struct dentry; |
31 | struct nsim_vf_config; | 32 | struct nsim_vf_config; |
32 | 33 | ||
34 | struct netdevsim_shared_dev { | ||
35 | unsigned int refcnt; | ||
36 | u32 switch_id; | ||
37 | |||
38 | struct dentry *ddir; | ||
39 | |||
40 | struct bpf_offload_dev *bpf_dev; | ||
41 | |||
42 | struct dentry *ddir_bpf_bound_progs; | ||
43 | u32 prog_id_gen; | ||
44 | |||
45 | struct list_head bpf_bound_progs; | ||
46 | struct list_head bpf_bound_maps; | ||
47 | }; | ||
48 | |||
33 | #define NSIM_IPSEC_MAX_SA_COUNT 33 | 49 | #define NSIM_IPSEC_MAX_SA_COUNT 33 |
34 | #define NSIM_IPSEC_VALID BIT(31) | 50 | #define NSIM_IPSEC_VALID BIT(31) |
35 | 51 | ||
@@ -59,6 +75,7 @@ struct netdevsim { | |||
59 | struct u64_stats_sync syncp; | 75 | struct u64_stats_sync syncp; |
60 | 76 | ||
61 | struct device dev; | 77 | struct device dev; |
78 | struct netdevsim_shared_dev *sdev; | ||
62 | 79 | ||
63 | struct dentry *ddir; | 80 | struct dentry *ddir; |
64 | 81 | ||
@@ -71,12 +88,8 @@ struct netdevsim { | |||
71 | struct xdp_attachment_info xdp; | 88 | struct xdp_attachment_info xdp; |
72 | struct xdp_attachment_info xdp_hw; | 89 | struct xdp_attachment_info xdp_hw; |
73 | 90 | ||
74 | u32 prog_id_gen; | ||
75 | |||
76 | bool bpf_bind_accept; | 91 | bool bpf_bind_accept; |
77 | u32 bpf_bind_verifier_delay; | 92 | u32 bpf_bind_verifier_delay; |
78 | struct dentry *ddir_bpf_bound_progs; | ||
79 | struct list_head bpf_bound_progs; | ||
80 | 93 | ||
81 | bool bpf_tc_accept; | 94 | bool bpf_tc_accept; |
82 | bool bpf_tc_non_bound_accept; | 95 | bool bpf_tc_non_bound_accept; |
@@ -84,7 +97,6 @@ struct netdevsim { | |||
84 | bool bpf_xdpoffload_accept; | 97 | bool bpf_xdpoffload_accept; |
85 | 98 | ||
86 | bool bpf_map_accept; | 99 | bool bpf_map_accept; |
87 | struct list_head bpf_bound_maps; | ||
88 | #if IS_ENABLED(CONFIG_NET_DEVLINK) | 100 | #if IS_ENABLED(CONFIG_NET_DEVLINK) |
89 | struct devlink *devlink; | 101 | struct devlink *devlink; |
90 | #endif | 102 | #endif |
@@ -92,6 +104,7 @@ struct netdevsim { | |||
92 | }; | 104 | }; |
93 | 105 | ||
94 | extern struct dentry *nsim_ddir; | 106 | extern struct dentry *nsim_ddir; |
107 | extern struct dentry *nsim_sdev_ddir; | ||
95 | 108 | ||
96 | #ifdef CONFIG_BPF_SYSCALL | 109 | #ifdef CONFIG_BPF_SYSCALL |
97 | int nsim_bpf_init(struct netdevsim *ns); | 110 | int nsim_bpf_init(struct netdevsim *ns); |
diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 8827e797ff97..5b5ad95cf339 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h | |||
@@ -85,6 +85,7 @@ struct bpf_map { | |||
85 | char name[BPF_OBJ_NAME_LEN]; | 85 | char name[BPF_OBJ_NAME_LEN]; |
86 | }; | 86 | }; |
87 | 87 | ||
88 | struct bpf_offload_dev; | ||
88 | struct bpf_offloaded_map; | 89 | struct bpf_offloaded_map; |
89 | 90 | ||
90 | struct bpf_map_dev_ops { | 91 | struct bpf_map_dev_ops { |
@@ -352,7 +353,7 @@ struct bpf_prog_array { | |||
352 | struct bpf_prog *progs[0]; | 353 | struct bpf_prog *progs[0]; |
353 | }; | 354 | }; |
354 | 355 | ||
355 | struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags); | 356 | struct bpf_prog_array *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags); |
356 | void bpf_prog_array_free(struct bpf_prog_array __rcu *progs); | 357 | void bpf_prog_array_free(struct bpf_prog_array __rcu *progs); |
357 | int bpf_prog_array_length(struct bpf_prog_array __rcu *progs); | 358 | int bpf_prog_array_length(struct bpf_prog_array __rcu *progs); |
358 | int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, | 359 | int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs, |
@@ -648,7 +649,15 @@ int bpf_map_offload_delete_elem(struct bpf_map *map, void *key); | |||
648 | int bpf_map_offload_get_next_key(struct bpf_map *map, | 649 | int bpf_map_offload_get_next_key(struct bpf_map *map, |
649 | void *key, void *next_key); | 650 | void *key, void *next_key); |
650 | 651 | ||
651 | bool bpf_offload_dev_match(struct bpf_prog *prog, struct bpf_map *map); | 652 | bool bpf_offload_prog_map_match(struct bpf_prog *prog, struct bpf_map *map); |
653 | |||
654 | struct bpf_offload_dev *bpf_offload_dev_create(void); | ||
655 | void bpf_offload_dev_destroy(struct bpf_offload_dev *offdev); | ||
656 | int bpf_offload_dev_netdev_register(struct bpf_offload_dev *offdev, | ||
657 | struct net_device *netdev); | ||
658 | void bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev, | ||
659 | struct net_device *netdev); | ||
660 | bool bpf_offload_dev_match(struct bpf_prog *prog, struct net_device *netdev); | ||
652 | 661 | ||
653 | #if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL) | 662 | #if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL) |
654 | int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr); | 663 | int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr); |
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 3d83ee7df381..badabb0b435c 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c | |||
@@ -95,7 +95,7 @@ static int compute_effective_progs(struct cgroup *cgrp, | |||
95 | enum bpf_attach_type type, | 95 | enum bpf_attach_type type, |
96 | struct bpf_prog_array __rcu **array) | 96 | struct bpf_prog_array __rcu **array) |
97 | { | 97 | { |
98 | struct bpf_prog_array __rcu *progs; | 98 | struct bpf_prog_array *progs; |
99 | struct bpf_prog_list *pl; | 99 | struct bpf_prog_list *pl; |
100 | struct cgroup *p = cgrp; | 100 | struct cgroup *p = cgrp; |
101 | int cnt = 0; | 101 | int cnt = 0; |
@@ -120,13 +120,12 @@ static int compute_effective_progs(struct cgroup *cgrp, | |||
120 | &p->bpf.progs[type], node) { | 120 | &p->bpf.progs[type], node) { |
121 | if (!pl->prog) | 121 | if (!pl->prog) |
122 | continue; | 122 | continue; |
123 | rcu_dereference_protected(progs, 1)-> | 123 | progs->progs[cnt++] = pl->prog; |
124 | progs[cnt++] = pl->prog; | ||
125 | } | 124 | } |
126 | p = cgroup_parent(p); | 125 | p = cgroup_parent(p); |
127 | } while (p); | 126 | } while (p); |
128 | 127 | ||
129 | *array = progs; | 128 | rcu_assign_pointer(*array, progs); |
130 | return 0; | 129 | return 0; |
131 | } | 130 | } |
132 | 131 | ||
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 1e5625d46414..253aa8e79c7b 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c | |||
@@ -1538,7 +1538,7 @@ static struct { | |||
1538 | .null_prog = NULL, | 1538 | .null_prog = NULL, |
1539 | }; | 1539 | }; |
1540 | 1540 | ||
1541 | struct bpf_prog_array __rcu *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags) | 1541 | struct bpf_prog_array *bpf_prog_array_alloc(u32 prog_cnt, gfp_t flags) |
1542 | { | 1542 | { |
1543 | if (prog_cnt) | 1543 | if (prog_cnt) |
1544 | return kzalloc(sizeof(struct bpf_prog_array) + | 1544 | return kzalloc(sizeof(struct bpf_prog_array) + |
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c index ac747d5cf7c6..177a52436394 100644 --- a/kernel/bpf/offload.c +++ b/kernel/bpf/offload.c | |||
@@ -18,19 +18,43 @@ | |||
18 | #include <linux/bug.h> | 18 | #include <linux/bug.h> |
19 | #include <linux/kdev_t.h> | 19 | #include <linux/kdev_t.h> |
20 | #include <linux/list.h> | 20 | #include <linux/list.h> |
21 | #include <linux/lockdep.h> | ||
21 | #include <linux/netdevice.h> | 22 | #include <linux/netdevice.h> |
22 | #include <linux/printk.h> | 23 | #include <linux/printk.h> |
23 | #include <linux/proc_ns.h> | 24 | #include <linux/proc_ns.h> |
25 | #include <linux/rhashtable.h> | ||
24 | #include <linux/rtnetlink.h> | 26 | #include <linux/rtnetlink.h> |
25 | #include <linux/rwsem.h> | 27 | #include <linux/rwsem.h> |
26 | 28 | ||
27 | /* Protects bpf_prog_offload_devs, bpf_map_offload_devs and offload members | 29 | /* Protects offdevs, members of bpf_offload_netdev and offload members |
28 | * of all progs. | 30 | * of all progs. |
29 | * RTNL lock cannot be taken when holding this lock. | 31 | * RTNL lock cannot be taken when holding this lock. |
30 | */ | 32 | */ |
31 | static DECLARE_RWSEM(bpf_devs_lock); | 33 | static DECLARE_RWSEM(bpf_devs_lock); |
32 | static LIST_HEAD(bpf_prog_offload_devs); | 34 | |
33 | static LIST_HEAD(bpf_map_offload_devs); | 35 | struct bpf_offload_dev { |
36 | struct list_head netdevs; | ||
37 | }; | ||
38 | |||
39 | struct bpf_offload_netdev { | ||
40 | struct rhash_head l; | ||
41 | struct net_device *netdev; | ||
42 | struct bpf_offload_dev *offdev; | ||
43 | struct list_head progs; | ||
44 | struct list_head maps; | ||
45 | struct list_head offdev_netdevs; | ||
46 | }; | ||
47 | |||
48 | static const struct rhashtable_params offdevs_params = { | ||
49 | .nelem_hint = 4, | ||
50 | .key_len = sizeof(struct net_device *), | ||
51 | .key_offset = offsetof(struct bpf_offload_netdev, netdev), | ||
52 | .head_offset = offsetof(struct bpf_offload_netdev, l), | ||
53 | .automatic_shrinking = true, | ||
54 | }; | ||
55 | |||
56 | static struct rhashtable offdevs; | ||
57 | static bool offdevs_inited; | ||
34 | 58 | ||
35 | static int bpf_dev_offload_check(struct net_device *netdev) | 59 | static int bpf_dev_offload_check(struct net_device *netdev) |
36 | { | 60 | { |
@@ -41,8 +65,19 @@ static int bpf_dev_offload_check(struct net_device *netdev) | |||
41 | return 0; | 65 | return 0; |
42 | } | 66 | } |
43 | 67 | ||
68 | static struct bpf_offload_netdev * | ||
69 | bpf_offload_find_netdev(struct net_device *netdev) | ||
70 | { | ||
71 | lockdep_assert_held(&bpf_devs_lock); | ||
72 | |||
73 | if (!offdevs_inited) | ||
74 | return NULL; | ||
75 | return rhashtable_lookup_fast(&offdevs, &netdev, offdevs_params); | ||
76 | } | ||
77 | |||
44 | int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr) | 78 | int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr) |
45 | { | 79 | { |
80 | struct bpf_offload_netdev *ondev; | ||
46 | struct bpf_prog_offload *offload; | 81 | struct bpf_prog_offload *offload; |
47 | int err; | 82 | int err; |
48 | 83 | ||
@@ -66,12 +101,13 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr) | |||
66 | goto err_maybe_put; | 101 | goto err_maybe_put; |
67 | 102 | ||
68 | down_write(&bpf_devs_lock); | 103 | down_write(&bpf_devs_lock); |
69 | if (offload->netdev->reg_state != NETREG_REGISTERED) { | 104 | ondev = bpf_offload_find_netdev(offload->netdev); |
105 | if (!ondev) { | ||
70 | err = -EINVAL; | 106 | err = -EINVAL; |
71 | goto err_unlock; | 107 | goto err_unlock; |
72 | } | 108 | } |
73 | prog->aux->offload = offload; | 109 | prog->aux->offload = offload; |
74 | list_add_tail(&offload->offloads, &bpf_prog_offload_devs); | 110 | list_add_tail(&offload->offloads, &ondev->progs); |
75 | dev_put(offload->netdev); | 111 | dev_put(offload->netdev); |
76 | up_write(&bpf_devs_lock); | 112 | up_write(&bpf_devs_lock); |
77 | 113 | ||
@@ -294,6 +330,7 @@ static int bpf_map_offload_ndo(struct bpf_offloaded_map *offmap, | |||
294 | struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr) | 330 | struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr) |
295 | { | 331 | { |
296 | struct net *net = current->nsproxy->net_ns; | 332 | struct net *net = current->nsproxy->net_ns; |
333 | struct bpf_offload_netdev *ondev; | ||
297 | struct bpf_offloaded_map *offmap; | 334 | struct bpf_offloaded_map *offmap; |
298 | int err; | 335 | int err; |
299 | 336 | ||
@@ -316,11 +353,17 @@ struct bpf_map *bpf_map_offload_map_alloc(union bpf_attr *attr) | |||
316 | if (err) | 353 | if (err) |
317 | goto err_unlock; | 354 | goto err_unlock; |
318 | 355 | ||
356 | ondev = bpf_offload_find_netdev(offmap->netdev); | ||
357 | if (!ondev) { | ||
358 | err = -EINVAL; | ||
359 | goto err_unlock; | ||
360 | } | ||
361 | |||
319 | err = bpf_map_offload_ndo(offmap, BPF_OFFLOAD_MAP_ALLOC); | 362 | err = bpf_map_offload_ndo(offmap, BPF_OFFLOAD_MAP_ALLOC); |
320 | if (err) | 363 | if (err) |
321 | goto err_unlock; | 364 | goto err_unlock; |
322 | 365 | ||
323 | list_add_tail(&offmap->offloads, &bpf_map_offload_devs); | 366 | list_add_tail(&offmap->offloads, &ondev->maps); |
324 | up_write(&bpf_devs_lock); | 367 | up_write(&bpf_devs_lock); |
325 | rtnl_unlock(); | 368 | rtnl_unlock(); |
326 | 369 | ||
@@ -468,77 +511,159 @@ int bpf_map_offload_info_fill(struct bpf_map_info *info, struct bpf_map *map) | |||
468 | return 0; | 511 | return 0; |
469 | } | 512 | } |
470 | 513 | ||
471 | bool bpf_offload_dev_match(struct bpf_prog *prog, struct bpf_map *map) | 514 | static bool __bpf_offload_dev_match(struct bpf_prog *prog, |
515 | struct net_device *netdev) | ||
472 | { | 516 | { |
473 | struct bpf_offloaded_map *offmap; | 517 | struct bpf_offload_netdev *ondev1, *ondev2; |
474 | struct bpf_prog_offload *offload; | 518 | struct bpf_prog_offload *offload; |
475 | bool ret; | ||
476 | 519 | ||
477 | if (!bpf_prog_is_dev_bound(prog->aux)) | 520 | if (!bpf_prog_is_dev_bound(prog->aux)) |
478 | return false; | 521 | return false; |
479 | if (!bpf_map_is_dev_bound(map)) | ||
480 | return bpf_map_offload_neutral(map); | ||
481 | 522 | ||
482 | down_read(&bpf_devs_lock); | ||
483 | offload = prog->aux->offload; | 523 | offload = prog->aux->offload; |
484 | offmap = map_to_offmap(map); | 524 | if (!offload) |
525 | return false; | ||
526 | if (offload->netdev == netdev) | ||
527 | return true; | ||
485 | 528 | ||
486 | ret = offload && offload->netdev == offmap->netdev; | 529 | ondev1 = bpf_offload_find_netdev(offload->netdev); |
530 | ondev2 = bpf_offload_find_netdev(netdev); | ||
531 | |||
532 | return ondev1 && ondev2 && ondev1->offdev == ondev2->offdev; | ||
533 | } | ||
534 | |||
535 | bool bpf_offload_dev_match(struct bpf_prog *prog, struct net_device *netdev) | ||
536 | { | ||
537 | bool ret; | ||
538 | |||
539 | down_read(&bpf_devs_lock); | ||
540 | ret = __bpf_offload_dev_match(prog, netdev); | ||
487 | up_read(&bpf_devs_lock); | 541 | up_read(&bpf_devs_lock); |
488 | 542 | ||
489 | return ret; | 543 | return ret; |
490 | } | 544 | } |
545 | EXPORT_SYMBOL_GPL(bpf_offload_dev_match); | ||
491 | 546 | ||
492 | static void bpf_offload_orphan_all_progs(struct net_device *netdev) | 547 | bool bpf_offload_prog_map_match(struct bpf_prog *prog, struct bpf_map *map) |
493 | { | 548 | { |
494 | struct bpf_prog_offload *offload, *tmp; | 549 | struct bpf_offloaded_map *offmap; |
550 | bool ret; | ||
495 | 551 | ||
496 | list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs, offloads) | 552 | if (!bpf_map_is_dev_bound(map)) |
497 | if (offload->netdev == netdev) | 553 | return bpf_map_offload_neutral(map); |
498 | __bpf_prog_offload_destroy(offload->prog); | 554 | offmap = map_to_offmap(map); |
555 | |||
556 | down_read(&bpf_devs_lock); | ||
557 | ret = __bpf_offload_dev_match(prog, offmap->netdev); | ||
558 | up_read(&bpf_devs_lock); | ||
559 | |||
560 | return ret; | ||
499 | } | 561 | } |
500 | 562 | ||
501 | static void bpf_offload_orphan_all_maps(struct net_device *netdev) | 563 | int bpf_offload_dev_netdev_register(struct bpf_offload_dev *offdev, |
564 | struct net_device *netdev) | ||
502 | { | 565 | { |
503 | struct bpf_offloaded_map *offmap, *tmp; | 566 | struct bpf_offload_netdev *ondev; |
567 | int err; | ||
504 | 568 | ||
505 | list_for_each_entry_safe(offmap, tmp, &bpf_map_offload_devs, offloads) | 569 | ondev = kzalloc(sizeof(*ondev), GFP_KERNEL); |
506 | if (offmap->netdev == netdev) | 570 | if (!ondev) |
507 | __bpf_map_offload_destroy(offmap); | 571 | return -ENOMEM; |
572 | |||
573 | ondev->netdev = netdev; | ||
574 | ondev->offdev = offdev; | ||
575 | INIT_LIST_HEAD(&ondev->progs); | ||
576 | INIT_LIST_HEAD(&ondev->maps); | ||
577 | |||
578 | down_write(&bpf_devs_lock); | ||
579 | err = rhashtable_insert_fast(&offdevs, &ondev->l, offdevs_params); | ||
580 | if (err) { | ||
581 | netdev_warn(netdev, "failed to register for BPF offload\n"); | ||
582 | goto err_unlock_free; | ||
583 | } | ||
584 | |||
585 | list_add(&ondev->offdev_netdevs, &offdev->netdevs); | ||
586 | up_write(&bpf_devs_lock); | ||
587 | return 0; | ||
588 | |||
589 | err_unlock_free: | ||
590 | up_write(&bpf_devs_lock); | ||
591 | kfree(ondev); | ||
592 | return err; | ||
508 | } | 593 | } |
594 | EXPORT_SYMBOL_GPL(bpf_offload_dev_netdev_register); | ||
509 | 595 | ||
510 | static int bpf_offload_notification(struct notifier_block *notifier, | 596 | void bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev, |
511 | ulong event, void *ptr) | 597 | struct net_device *netdev) |
512 | { | 598 | { |
513 | struct net_device *netdev = netdev_notifier_info_to_dev(ptr); | 599 | struct bpf_offload_netdev *ondev, *altdev; |
600 | struct bpf_offloaded_map *offmap, *mtmp; | ||
601 | struct bpf_prog_offload *offload, *ptmp; | ||
514 | 602 | ||
515 | ASSERT_RTNL(); | 603 | ASSERT_RTNL(); |
516 | 604 | ||
517 | switch (event) { | 605 | down_write(&bpf_devs_lock); |
518 | case NETDEV_UNREGISTER: | 606 | ondev = rhashtable_lookup_fast(&offdevs, &netdev, offdevs_params); |
519 | /* ignore namespace changes */ | 607 | if (WARN_ON(!ondev)) |
520 | if (netdev->reg_state != NETREG_UNREGISTERING) | 608 | goto unlock; |
521 | break; | 609 | |
522 | 610 | WARN_ON(rhashtable_remove_fast(&offdevs, &ondev->l, offdevs_params)); | |
523 | down_write(&bpf_devs_lock); | 611 | list_del(&ondev->offdev_netdevs); |
524 | bpf_offload_orphan_all_progs(netdev); | 612 | |
525 | bpf_offload_orphan_all_maps(netdev); | 613 | /* Try to move the objects to another netdev of the device */ |
526 | up_write(&bpf_devs_lock); | 614 | altdev = list_first_entry_or_null(&offdev->netdevs, |
527 | break; | 615 | struct bpf_offload_netdev, |
528 | default: | 616 | offdev_netdevs); |
529 | break; | 617 | if (altdev) { |
618 | list_for_each_entry(offload, &ondev->progs, offloads) | ||
619 | offload->netdev = altdev->netdev; | ||
620 | list_splice_init(&ondev->progs, &altdev->progs); | ||
621 | |||
622 | list_for_each_entry(offmap, &ondev->maps, offloads) | ||
623 | offmap->netdev = altdev->netdev; | ||
624 | list_splice_init(&ondev->maps, &altdev->maps); | ||
625 | } else { | ||
626 | list_for_each_entry_safe(offload, ptmp, &ondev->progs, offloads) | ||
627 | __bpf_prog_offload_destroy(offload->prog); | ||
628 | list_for_each_entry_safe(offmap, mtmp, &ondev->maps, offloads) | ||
629 | __bpf_map_offload_destroy(offmap); | ||
530 | } | 630 | } |
531 | return NOTIFY_OK; | ||
532 | } | ||
533 | 631 | ||
534 | static struct notifier_block bpf_offload_notifier = { | 632 | WARN_ON(!list_empty(&ondev->progs)); |
535 | .notifier_call = bpf_offload_notification, | 633 | WARN_ON(!list_empty(&ondev->maps)); |
536 | }; | 634 | kfree(ondev); |
635 | unlock: | ||
636 | up_write(&bpf_devs_lock); | ||
637 | } | ||
638 | EXPORT_SYMBOL_GPL(bpf_offload_dev_netdev_unregister); | ||
537 | 639 | ||
538 | static int __init bpf_offload_init(void) | 640 | struct bpf_offload_dev *bpf_offload_dev_create(void) |
539 | { | 641 | { |
540 | register_netdevice_notifier(&bpf_offload_notifier); | 642 | struct bpf_offload_dev *offdev; |
541 | return 0; | 643 | int err; |
644 | |||
645 | down_write(&bpf_devs_lock); | ||
646 | if (!offdevs_inited) { | ||
647 | err = rhashtable_init(&offdevs, &offdevs_params); | ||
648 | if (err) | ||
649 | return ERR_PTR(err); | ||
650 | offdevs_inited = true; | ||
651 | } | ||
652 | up_write(&bpf_devs_lock); | ||
653 | |||
654 | offdev = kzalloc(sizeof(*offdev), GFP_KERNEL); | ||
655 | if (!offdev) | ||
656 | return ERR_PTR(-ENOMEM); | ||
657 | |||
658 | INIT_LIST_HEAD(&offdev->netdevs); | ||
659 | |||
660 | return offdev; | ||
542 | } | 661 | } |
662 | EXPORT_SYMBOL_GPL(bpf_offload_dev_create); | ||
543 | 663 | ||
544 | subsys_initcall(bpf_offload_init); | 664 | void bpf_offload_dev_destroy(struct bpf_offload_dev *offdev) |
665 | { | ||
666 | WARN_ON(!list_empty(&offdev->netdevs)); | ||
667 | kfree(offdev); | ||
668 | } | ||
669 | EXPORT_SYMBOL_GPL(bpf_offload_dev_destroy); | ||
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 98fb7938beea..0b38be5a955c 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c | |||
@@ -725,11 +725,8 @@ static int bpf_tcp_sendmsg_do_redirect(struct sock *sk, int send, | |||
725 | { | 725 | { |
726 | bool ingress = !!(md->flags & BPF_F_INGRESS); | 726 | bool ingress = !!(md->flags & BPF_F_INGRESS); |
727 | struct smap_psock *psock; | 727 | struct smap_psock *psock; |
728 | struct scatterlist *sg; | ||
729 | int err = 0; | 728 | int err = 0; |
730 | 729 | ||
731 | sg = md->sg_data; | ||
732 | |||
733 | rcu_read_lock(); | 730 | rcu_read_lock(); |
734 | psock = smap_psock_sk(sk); | 731 | psock = smap_psock_sk(sk); |
735 | if (unlikely(!psock)) | 732 | if (unlikely(!psock)) |
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 63aaac52a265..25e47c195874 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -5054,7 +5054,7 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env, | |||
5054 | } | 5054 | } |
5055 | 5055 | ||
5056 | if ((bpf_prog_is_dev_bound(prog->aux) || bpf_map_is_dev_bound(map)) && | 5056 | if ((bpf_prog_is_dev_bound(prog->aux) || bpf_map_is_dev_bound(map)) && |
5057 | !bpf_offload_dev_match(prog, map)) { | 5057 | !bpf_offload_prog_map_match(prog, map)) { |
5058 | verbose(env, "offload device mismatch between prog and map\n"); | 5058 | verbose(env, "offload device mismatch between prog and map\n"); |
5059 | return -EINVAL; | 5059 | return -EINVAL; |
5060 | } | 5060 | } |
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c index 89161c9ed466..904e775d1a44 100644 --- a/samples/bpf/bpf_load.c +++ b/samples/bpf/bpf_load.c | |||
@@ -107,6 +107,9 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) | |||
107 | return -1; | 107 | return -1; |
108 | } | 108 | } |
109 | 109 | ||
110 | if (prog_cnt == MAX_PROGS) | ||
111 | return -1; | ||
112 | |||
110 | fd = bpf_load_program(prog_type, prog, insns_cnt, license, kern_version, | 113 | fd = bpf_load_program(prog_type, prog, insns_cnt, license, kern_version, |
111 | bpf_log_buf, BPF_LOG_BUF_SIZE); | 114 | bpf_log_buf, BPF_LOG_BUF_SIZE); |
112 | if (fd < 0) { | 115 | if (fd < 0) { |
diff --git a/samples/bpf/test_cgrp2_sock2.c b/samples/bpf/test_cgrp2_sock2.c index 3b5be2364975..a9277b118c33 100644 --- a/samples/bpf/test_cgrp2_sock2.c +++ b/samples/bpf/test_cgrp2_sock2.c | |||
@@ -51,7 +51,7 @@ int main(int argc, char **argv) | |||
51 | if (argc > 3) | 51 | if (argc > 3) |
52 | filter_id = atoi(argv[3]); | 52 | filter_id = atoi(argv[3]); |
53 | 53 | ||
54 | if (filter_id > prog_cnt) { | 54 | if (filter_id >= prog_cnt) { |
55 | printf("Invalid program id; program not found in file\n"); | 55 | printf("Invalid program id; program not found in file\n"); |
56 | return EXIT_FAILURE; | 56 | return EXIT_FAILURE; |
57 | } | 57 | } |
diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 6c4830e18879..74288a2197ab 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile | |||
@@ -26,7 +26,7 @@ LIBBPF = $(BPF_PATH)libbpf.a | |||
26 | BPFTOOL_VERSION := $(shell make --no-print-directory -sC ../../.. kernelversion) | 26 | BPFTOOL_VERSION := $(shell make --no-print-directory -sC ../../.. kernelversion) |
27 | 27 | ||
28 | $(LIBBPF): FORCE | 28 | $(LIBBPF): FORCE |
29 | $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT) | 29 | $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a |
30 | 30 | ||
31 | $(LIBBPF)-clean: | 31 | $(LIBBPF)-clean: |
32 | $(call QUIET_CLEAN, libbpf) | 32 | $(call QUIET_CLEAN, libbpf) |
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 7a8e4c98ef1a..d49902e818b5 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile | |||
@@ -66,7 +66,7 @@ ifndef VERBOSE | |||
66 | endif | 66 | endif |
67 | 67 | ||
68 | FEATURE_USER = .libbpf | 68 | FEATURE_USER = .libbpf |
69 | FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf reallocarray | 69 | FEATURE_TESTS = libelf libelf-mmap bpf reallocarray |
70 | FEATURE_DISPLAY = libelf bpf | 70 | FEATURE_DISPLAY = libelf bpf |
71 | 71 | ||
72 | INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf | 72 | INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf |
@@ -116,10 +116,6 @@ ifeq ($(feature-libelf-mmap), 1) | |||
116 | override CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT | 116 | override CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT |
117 | endif | 117 | endif |
118 | 118 | ||
119 | ifeq ($(feature-libelf-getphdrnum), 1) | ||
120 | override CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT | ||
121 | endif | ||
122 | |||
123 | ifeq ($(feature-reallocarray), 0) | 119 | ifeq ($(feature-reallocarray), 0) |
124 | override CFLAGS += -DCOMPAT_NEED_REALLOCARRAY | 120 | override CFLAGS += -DCOMPAT_NEED_REALLOCARRAY |
125 | endif | 121 | endif |
diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py index b746227eaff2..d59642e70f56 100755 --- a/tools/testing/selftests/bpf/test_offload.py +++ b/tools/testing/selftests/bpf/test_offload.py | |||
@@ -158,8 +158,9 @@ def tool(name, args, flags, JSON=True, ns="", fail=True, include_stderr=False): | |||
158 | else: | 158 | else: |
159 | return ret, out | 159 | return ret, out |
160 | 160 | ||
161 | def bpftool(args, JSON=True, ns="", fail=True): | 161 | def bpftool(args, JSON=True, ns="", fail=True, include_stderr=False): |
162 | return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail) | 162 | return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, |
163 | fail=fail, include_stderr=include_stderr) | ||
163 | 164 | ||
164 | def bpftool_prog_list(expected=None, ns=""): | 165 | def bpftool_prog_list(expected=None, ns=""): |
165 | _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True) | 166 | _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True) |
@@ -201,6 +202,21 @@ def bpftool_map_list_wait(expected=0, n_retry=20): | |||
201 | time.sleep(0.05) | 202 | time.sleep(0.05) |
202 | raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps)) | 203 | raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps)) |
203 | 204 | ||
205 | def bpftool_prog_load(sample, file_name, maps=[], prog_type="xdp", dev=None, | ||
206 | fail=True, include_stderr=False): | ||
207 | args = "prog load %s %s" % (os.path.join(bpf_test_dir, sample), file_name) | ||
208 | if prog_type is not None: | ||
209 | args += " type " + prog_type | ||
210 | if dev is not None: | ||
211 | args += " dev " + dev | ||
212 | if len(maps): | ||
213 | args += " map " + " map ".join(maps) | ||
214 | |||
215 | res = bpftool(args, fail=fail, include_stderr=include_stderr) | ||
216 | if res[0] == 0: | ||
217 | files.append(file_name) | ||
218 | return res | ||
219 | |||
204 | def ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False): | 220 | def ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False): |
205 | if force: | 221 | if force: |
206 | args = "-force " + args | 222 | args = "-force " + args |
@@ -307,21 +323,25 @@ class NetdevSim: | |||
307 | Class for netdevsim netdevice and its attributes. | 323 | Class for netdevsim netdevice and its attributes. |
308 | """ | 324 | """ |
309 | 325 | ||
310 | def __init__(self): | 326 | def __init__(self, link=None): |
327 | self.link = link | ||
328 | |||
311 | self.dev = self._netdevsim_create() | 329 | self.dev = self._netdevsim_create() |
312 | devs.append(self) | 330 | devs.append(self) |
313 | 331 | ||
314 | self.ns = "" | 332 | self.ns = "" |
315 | 333 | ||
316 | self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname']) | 334 | self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname']) |
335 | self.sdev_dir = self.dfs_dir + '/sdev/' | ||
317 | self.dfs_refresh() | 336 | self.dfs_refresh() |
318 | 337 | ||
319 | def __getitem__(self, key): | 338 | def __getitem__(self, key): |
320 | return self.dev[key] | 339 | return self.dev[key] |
321 | 340 | ||
322 | def _netdevsim_create(self): | 341 | def _netdevsim_create(self): |
342 | link = "" if self.link is None else "link " + self.link.dev['ifname'] | ||
323 | _, old = ip("link show") | 343 | _, old = ip("link show") |
324 | ip("link add sim%d type netdevsim") | 344 | ip("link add sim%d {link} type netdevsim".format(link=link)) |
325 | _, new = ip("link show") | 345 | _, new = ip("link show") |
326 | 346 | ||
327 | for dev in new: | 347 | for dev in new: |
@@ -345,12 +365,12 @@ class NetdevSim: | |||
345 | return data.strip() | 365 | return data.strip() |
346 | 366 | ||
347 | def dfs_num_bound_progs(self): | 367 | def dfs_num_bound_progs(self): |
348 | path = os.path.join(self.dfs_dir, "bpf_bound_progs") | 368 | path = os.path.join(self.sdev_dir, "bpf_bound_progs") |
349 | _, progs = cmd('ls %s' % (path)) | 369 | _, progs = cmd('ls %s' % (path)) |
350 | return len(progs.split()) | 370 | return len(progs.split()) |
351 | 371 | ||
352 | def dfs_get_bound_progs(self, expected): | 372 | def dfs_get_bound_progs(self, expected): |
353 | progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs")) | 373 | progs = DebugfsDir(os.path.join(self.sdev_dir, "bpf_bound_progs")) |
354 | if expected is not None: | 374 | if expected is not None: |
355 | if len(progs) != expected: | 375 | if len(progs) != expected: |
356 | fail(True, "%d BPF programs bound, expected %d" % | 376 | fail(True, "%d BPF programs bound, expected %d" % |
@@ -847,6 +867,25 @@ try: | |||
847 | sim.set_mtu(1500) | 867 | sim.set_mtu(1500) |
848 | 868 | ||
849 | sim.wait_for_flush() | 869 | sim.wait_for_flush() |
870 | start_test("Test non-offload XDP attaching to HW...") | ||
871 | bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/nooffload") | ||
872 | nooffload = bpf_pinned("/sys/fs/bpf/nooffload") | ||
873 | ret, _, err = sim.set_xdp(nooffload, "offload", | ||
874 | fail=False, include_stderr=True) | ||
875 | fail(ret == 0, "attached non-offloaded XDP program to HW") | ||
876 | check_extack_nsim(err, "xdpoffload of non-bound program.", args) | ||
877 | rm("/sys/fs/bpf/nooffload") | ||
878 | |||
879 | start_test("Test offload XDP attaching to drv...") | ||
880 | bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/offload", | ||
881 | dev=sim['ifname']) | ||
882 | offload = bpf_pinned("/sys/fs/bpf/offload") | ||
883 | ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True) | ||
884 | fail(ret == 0, "attached offloaded XDP program to drv") | ||
885 | check_extack(err, "using device-bound program without HW_MODE flag is not supported.", args) | ||
886 | rm("/sys/fs/bpf/offload") | ||
887 | sim.wait_for_flush() | ||
888 | |||
850 | start_test("Test XDP offload...") | 889 | start_test("Test XDP offload...") |
851 | _, _, err = sim.set_xdp(obj, "offload", verbose=True, include_stderr=True) | 890 | _, _, err = sim.set_xdp(obj, "offload", verbose=True, include_stderr=True) |
852 | ipl = sim.ip_link_show(xdp=True) | 891 | ipl = sim.ip_link_show(xdp=True) |
@@ -1140,6 +1179,106 @@ try: | |||
1140 | fail(ret == 0, | 1179 | fail(ret == 0, |
1141 | "netdevsim didn't refuse to create a map with offload disabled") | 1180 | "netdevsim didn't refuse to create a map with offload disabled") |
1142 | 1181 | ||
1182 | sim.remove() | ||
1183 | |||
1184 | start_test("Test multi-dev ASIC program reuse...") | ||
1185 | simA = NetdevSim() | ||
1186 | simB1 = NetdevSim() | ||
1187 | simB2 = NetdevSim(link=simB1) | ||
1188 | simB3 = NetdevSim(link=simB1) | ||
1189 | sims = (simA, simB1, simB2, simB3) | ||
1190 | simB = (simB1, simB2, simB3) | ||
1191 | |||
1192 | bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA", | ||
1193 | dev=simA['ifname']) | ||
1194 | progA = bpf_pinned("/sys/fs/bpf/nsimA") | ||
1195 | bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB", | ||
1196 | dev=simB1['ifname']) | ||
1197 | progB = bpf_pinned("/sys/fs/bpf/nsimB") | ||
1198 | |||
1199 | simA.set_xdp(progA, "offload", JSON=False) | ||
1200 | for d in simB: | ||
1201 | d.set_xdp(progB, "offload", JSON=False) | ||
1202 | |||
1203 | start_test("Test multi-dev ASIC cross-dev replace...") | ||
1204 | ret, _ = simA.set_xdp(progB, "offload", force=True, JSON=False, fail=False) | ||
1205 | fail(ret == 0, "cross-ASIC program allowed") | ||
1206 | for d in simB: | ||
1207 | ret, _ = d.set_xdp(progA, "offload", force=True, JSON=False, fail=False) | ||
1208 | fail(ret == 0, "cross-ASIC program allowed") | ||
1209 | |||
1210 | start_test("Test multi-dev ASIC cross-dev install...") | ||
1211 | for d in sims: | ||
1212 | d.unset_xdp("offload") | ||
1213 | |||
1214 | ret, _, err = simA.set_xdp(progB, "offload", force=True, JSON=False, | ||
1215 | fail=False, include_stderr=True) | ||
1216 | fail(ret == 0, "cross-ASIC program allowed") | ||
1217 | check_extack_nsim(err, "program bound to different dev.", args) | ||
1218 | for d in simB: | ||
1219 | ret, _, err = d.set_xdp(progA, "offload", force=True, JSON=False, | ||
1220 | fail=False, include_stderr=True) | ||
1221 | fail(ret == 0, "cross-ASIC program allowed") | ||
1222 | check_extack_nsim(err, "program bound to different dev.", args) | ||
1223 | |||
1224 | start_test("Test multi-dev ASIC cross-dev map reuse...") | ||
1225 | |||
1226 | mapA = bpftool("prog show %s" % (progA))[1]["map_ids"][0] | ||
1227 | mapB = bpftool("prog show %s" % (progB))[1]["map_ids"][0] | ||
1228 | |||
1229 | ret, _ = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_", | ||
1230 | dev=simB3['ifname'], | ||
1231 | maps=["idx 0 id %d" % (mapB)], | ||
1232 | fail=False) | ||
1233 | fail(ret != 0, "couldn't reuse a map on the same ASIC") | ||
1234 | rm("/sys/fs/bpf/nsimB_") | ||
1235 | |||
1236 | ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA_", | ||
1237 | dev=simA['ifname'], | ||
1238 | maps=["idx 0 id %d" % (mapB)], | ||
1239 | fail=False, include_stderr=True) | ||
1240 | fail(ret == 0, "could reuse a map on a different ASIC") | ||
1241 | fail(err.count("offload device mismatch between prog and map") == 0, | ||
1242 | "error message missing for cross-ASIC map") | ||
1243 | |||
1244 | ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_", | ||
1245 | dev=simB1['ifname'], | ||
1246 | maps=["idx 0 id %d" % (mapA)], | ||
1247 | fail=False, include_stderr=True) | ||
1248 | fail(ret == 0, "could reuse a map on a different ASIC") | ||
1249 | fail(err.count("offload device mismatch between prog and map") == 0, | ||
1250 | "error message missing for cross-ASIC map") | ||
1251 | |||
1252 | start_test("Test multi-dev ASIC cross-dev destruction...") | ||
1253 | bpftool_prog_list_wait(expected=2) | ||
1254 | |||
1255 | simA.remove() | ||
1256 | bpftool_prog_list_wait(expected=1) | ||
1257 | |||
1258 | ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] | ||
1259 | fail(ifnameB != simB1['ifname'], "program not bound to originial device") | ||
1260 | simB1.remove() | ||
1261 | bpftool_prog_list_wait(expected=1) | ||
1262 | |||
1263 | start_test("Test multi-dev ASIC cross-dev destruction - move...") | ||
1264 | ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] | ||
1265 | fail(ifnameB not in (simB2['ifname'], simB3['ifname']), | ||
1266 | "program not bound to remaining devices") | ||
1267 | |||
1268 | simB2.remove() | ||
1269 | ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] | ||
1270 | fail(ifnameB != simB3['ifname'], "program not bound to remaining device") | ||
1271 | |||
1272 | simB3.remove() | ||
1273 | bpftool_prog_list_wait(expected=0) | ||
1274 | |||
1275 | start_test("Test multi-dev ASIC cross-dev destruction - orphaned...") | ||
1276 | ret, out = bpftool("prog show %s" % (progB), fail=False) | ||
1277 | fail(ret == 0, "got information about orphaned program") | ||
1278 | fail("error" not in out, "no error reported for get info on orphaned") | ||
1279 | fail(out["error"] != "can't get prog info: No such device", | ||
1280 | "wrong error for get info on orphaned") | ||
1281 | |||
1143 | print("%s: OK" % (os.path.basename(__file__))) | 1282 | print("%s: OK" % (os.path.basename(__file__))) |
1144 | 1283 | ||
1145 | finally: | 1284 | finally: |