| @@ -63,12 +63,17 @@ struct xdp_dev_bulk_queue { · 62 unmodified lines |
| 63 | 63 | /* DEVMAP values */ |
| 64 | 64 | struct bpf_devmap_val { |
| 65 | 65 | u32 ifindex; /* device index */ |
| 66 | + union { |
| 67 | + int fd; /* prog fd on map write */ |
| 68 | + u32 id; /* prog id on map read */ |
| 69 | + } bpf_prog; |
| 66 | 70 | }; |
| 67 | 71 | |
| 68 | 72 | struct bpf_dtab_netdev { |
| 69 | 73 | struct net_device *dev; /* must be first member, due to tracepoint */ |
| 70 | 74 | struct hlist_node index_hlist; |
| 71 | 75 | struct bpf_dtab *dtab; |
| 76 | + struct bpf_prog *xdp_prog; |
| 72 | 77 | struct rcu_head rcu; |
| 73 | 78 | unsigned int idx; |
| 74 | 79 | struct bpf_devmap_val val; |
| @@ -111,12 +116,18 @@ static inline struct hlist_head *dev_map_index_hash(struct bpf_dtab *dtab, · 36 unmodified lines |
| 111 | 116 | |
| 112 | 117 | static int dev_map_init_map(struct bpf_dtab *dtab, union bpf_attr *attr) |
| 113 | 118 | { |
| 119 | + u32 valsize = attr->value_size; |
| 114 | 120 | u64 cost = 0; |
| 115 | 121 | int err; |
| 116 | 122 | |
| 117 | | − /* check sanity of attributes */ |
| 123 | + /* check sanity of attributes. 2 value sizes supported: |
| 124 | + * 4 bytes: ifindex |
| 125 | + * 8 bytes: ifindex + prog fd |
| 126 | + */ |
| 118 | 127 | if (attr->max_entries == 0 || attr->key_size != 4 || |
| 119 | | − attr->value_size != 4 || attr->map_flags & ~DEV_CREATE_FLAG_MASK) |
| 128 | + (valsize != offsetofend(struct bpf_devmap_val, ifindex) && |
| 129 | + valsize != offsetofend(struct bpf_devmap_val, bpf_prog.fd)) || |
| 130 | + attr->map_flags & ~DEV_CREATE_FLAG_MASK) |
| 120 | 131 | return -EINVAL; |
| 121 | 132 | |
| 122 | 133 | /* Lookup returns a pointer straight to dev->ifindex, so make sure the |
| @@ -223,6 +234,8 @@ static void dev_map_free(struct bpf_map *map) · 100 unmodified lines |
| 223 | 234 | |
| 224 | 235 | hlist_for_each_entry_safe(dev, next, head, index_hlist) { |
| 225 | 236 | hlist_del_rcu(&dev->index_hlist); |
| 237 | + if (dev->xdp_prog) |
| 238 | + bpf_prog_put(dev->xdp_prog); |
| 226 | 239 | dev_put(dev->dev); |
| 227 | 240 | kfree(dev); |
| 228 | 241 | } |
| @@ -237,6 +250,8 @@ static void dev_map_free(struct bpf_map *map) · 8 unmodified lines |
| 237 | 250 | if (!dev) |
| 238 | 251 | continue; |
| 239 | 252 | |
| 253 | + if (dev->xdp_prog) |
| 254 | + bpf_prog_put(dev->xdp_prog); |
| 240 | 255 | dev_put(dev->dev); |
| 241 | 256 | kfree(dev); |
| 242 | 257 | } |
| @@ -323,6 +338,16 @@ static int dev_map_hash_get_next_key(struct bpf_map *map, void *key, · 80 unmodified lines |
| 323 | 338 | return -ENOENT; |
| 324 | 339 | } |
| 325 | 340 | |
| 341 | +bool dev_map_can_have_prog(struct bpf_map *map) |
| 342 | +{ |
| 343 | + if ((map->map_type == BPF_MAP_TYPE_DEVMAP || |
| 344 | + map->map_type == BPF_MAP_TYPE_DEVMAP_HASH) && |
| 345 | + map->value_size != offsetofend(struct bpf_devmap_val, ifindex)) |
| 346 | + return true; |
| 347 | + |
| 348 | + return false; |
| 349 | +} |
| 350 | + |
| 326 | 351 | static int bq_xmit_all(struct xdp_dev_bulk_queue *bq, u32 flags) |
| 327 | 352 | { |
| 328 | 353 | struct net_device *dev = bq->dev; |
| @@ -447,6 +472,30 @@ static inline int __xdp_enqueue(struct net_device *dev, struct xdp_buff *xdp, · 118 unmodified lines |
| 447 | 472 | return bq_enqueue(dev, xdpf, dev_rx); |
| 448 | 473 | } |
| 449 | 474 | |
| 475 | +static struct xdp_buff *dev_map_run_prog(struct net_device *dev, |
| 476 | + struct xdp_buff *xdp, |
| 477 | + struct bpf_prog *xdp_prog) |
| 478 | +{ |
| 479 | + u32 act; |
| 480 | + |
| 481 | + act = bpf_prog_run_xdp(xdp_prog, xdp); |
| 482 | + switch (act) { |
| 483 | + case XDP_PASS: |
| 484 | + return xdp; |
| 485 | + case XDP_DROP: |
| 486 | + break; |
| 487 | + default: |
| 488 | + bpf_warn_invalid_xdp_action(act); |
| 489 | + fallthrough; |
| 490 | + case XDP_ABORTED: |
| 491 | + trace_xdp_exception(dev, xdp_prog, act); |
| 492 | + break; |
| 493 | + } |
| 494 | + |
| 495 | + xdp_return_buff(xdp); |
| 496 | + return NULL; |
| 497 | +} |
| 498 | + |
| 450 | 499 | int dev_xdp_enqueue(struct net_device *dev, struct xdp_buff *xdp, |
| 451 | 500 | struct net_device *dev_rx) |
| 452 | 501 | { |
| @@ -458,6 +507,11 @@ int dev_map_enqueue(struct bpf_dtab_netdev *dst, struct xdp_buff *xdp, · 5 unmodified lines |
| 458 | 507 | { |
| 459 | 508 | struct net_device *dev = dst->dev; |
| 460 | 509 | |
| 510 | + if (dst->xdp_prog) { |
| 511 | + xdp = dev_map_run_prog(dev, xdp, dst->xdp_prog); |
| 512 | + if (!xdp) |
| 513 | + return 0; |
| 514 | + } |
| 461 | 515 | return __xdp_enqueue(dev, xdp, dev_rx); |
| 462 | 516 | } |
| 463 | 517 | |
| @@ -494,6 +548,8 @@ static void __dev_map_entry_free(struct rcu_head *rcu) · 30 unmodified lines |
| 494 | 548 | struct bpf_dtab_netdev *dev; |
| 495 | 549 | |
| 496 | 550 | dev = container_of(rcu, struct bpf_dtab_netdev, rcu); |
| 551 | + if (dev->xdp_prog) |
| 552 | + bpf_prog_put(dev->xdp_prog); |
| 497 | 553 | dev_put(dev->dev); |
| 498 | 554 | kfree(dev); |
| 499 | 555 | } |
| @@ -547,6 +603,7 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net, · 47 unmodified lines |
| 547 | 603 | struct bpf_devmap_val *val, |
| 548 | 604 | unsigned int idx) |
| 549 | 605 | { |
| 606 | + struct bpf_prog *prog = NULL; |
| 550 | 607 | struct bpf_dtab_netdev *dev; |
| 551 | 608 | |
| 552 | 609 | dev = kmalloc_node(sizeof(*dev), GFP_ATOMIC | __GFP_NOWARN, |
| @@ -558,11 +615,31 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net, · 5 unmodified lines |
| 558 | 615 | if (!dev->dev) |
| 559 | 616 | goto err_out; |
| 560 | 617 | |
| 618 | + if (val->bpf_prog.fd >= 0) { |
| 619 | + prog = bpf_prog_get_type_dev(val->bpf_prog.fd, |
| 620 | + BPF_PROG_TYPE_XDP, false); |
| 621 | + if (IS_ERR(prog)) |
| 622 | + goto err_put_dev; |
| 623 | + if (prog->expected_attach_type != BPF_XDP_DEVMAP) |
| 624 | + goto err_put_prog; |
| 625 | + } |
| 626 | + |
| 561 | 627 | dev->idx = idx; |
| 562 | 628 | dev->dtab = dtab; |
| 629 | + if (prog) { |
| 630 | + dev->xdp_prog = prog; |
| 631 | + dev->val.bpf_prog.id = prog->aux->id; |
| 632 | + } else { |
| 633 | + dev->xdp_prog = NULL; |
| 634 | + dev->val.bpf_prog.id = 0; |
| 635 | + } |
| 563 | 636 | dev->val.ifindex = val->ifindex; |
| 564 | 637 | |
| 565 | 638 | return dev; |
| 639 | +err_put_prog: |
| 640 | + bpf_prog_put(prog); |
| 641 | +err_put_dev: |
| 642 | + dev_put(dev->dev); |
| 566 | 643 | err_out: |
| 567 | 644 | kfree(dev); |
| 568 | 645 | return ERR_PTR(-EINVAL); |
| @@ -572,8 +649,8 @@ static int __dev_map_update_elem(struct net *net, struct bpf_map *map, · 3 unmodified lines |
| 572 | 649 | void *key, void *value, u64 map_flags) |
| 573 | 650 | { |
| 574 | 651 | struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map); |
| 652 | + struct bpf_devmap_val val = { .bpf_prog.fd = -1 }; |
| 575 | 653 | struct bpf_dtab_netdev *dev, *old_dev; |
| 576 | | − struct bpf_devmap_val val = { }; |
| 577 | 654 | u32 i = *(u32 *)key; |
| 578 | 655 | |
| 579 | 656 | if (unlikely(map_flags > BPF_EXIST)) |
| @@ -588,6 +665,9 @@ static int __dev_map_update_elem(struct net *net, struct bpf_map *map, · 8 unmodified lines |
| 588 | 665 | |
| 589 | 666 | if (!val.ifindex) { |
| 590 | 667 | dev = NULL; |
| 668 | + /* can not specify fd if ifindex is 0 */ |
| 669 | + if (val.bpf_prog.fd != -1) |
| 670 | + return -EINVAL; |
| 591 | 671 | } else { |
| 592 | 672 | dev = __dev_map_alloc_node(net, dtab, &val, i); |
| 593 | 673 | if (IS_ERR(dev)) |
| @@ -616,8 +696,8 @@ static int __dev_map_hash_update_elem(struct net *net, struct bpf_map *map, · 22 unmodified lines |
| 616 | 696 | void *key, void *value, u64 map_flags) |
| 617 | 697 | { |
| 618 | 698 | struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map); |
| 699 | + struct bpf_devmap_val val = { .bpf_prog.fd = -1 }; |
| 619 | 700 | struct bpf_dtab_netdev *dev, *old_dev; |
| 620 | | − struct bpf_devmap_val val = { }; |
| 621 | 701 | u32 idx = *(u32 *)key; |
| 622 | 702 | unsigned long flags; |
| 623 | 703 | int err = -EEXIST; |