Add 'struct bpf_devmap_val' to formalize the expected values that can be passed in for a DEVMAP. Update devmap code to use the struct.
Unified · Split
| @@ -60,12 +60,18 @@ struct xdp_dev_bulk_queue { · 59 unmodified lines | ||
| 60 | 60 | unsigned int count; |
| 61 | 61 | }; |
| 62 | 62 | |
| 63 | +/* DEVMAP values */ | |
| 64 | +struct bpf_devmap_val { | |
| 65 | + u32 ifindex; /* device index */ | |
| 66 | +}; | |
| 67 | + | |
| 63 | 68 | struct bpf_dtab_netdev { |
| 64 | 69 | struct net_device *dev; /* must be first member, due to tracepoint */ |
| 65 | 70 | struct hlist_node index_hlist; |
| 66 | 71 | struct bpf_dtab *dtab; |
| 67 | 72 | struct rcu_head rcu; |
| 68 | 73 | unsigned int idx; |
| 74 | + struct bpf_devmap_val val; | |
| 69 | 75 | }; |
| 70 | 76 | |
| 71 | 77 | struct bpf_dtab { |
| @@ -472,18 +478,15 @@ int dev_map_generic_redirect(struct bpf_dtab_netdev *dst, struct sk_buff *skb, · 400 unmodified lines | ||
| 472 | 478 | static void *dev_map_lookup_elem(struct bpf_map *map, void *key) |
| 473 | 479 | { |
| 474 | 480 | struct bpf_dtab_netdev *obj = __dev_map_lookup_elem(map, *(u32 *)key); |
| 475 | − struct net_device *dev = obj ? obj->dev : NULL; | |
| 476 | 481 | |
| 477 | − return dev ? &dev->ifindex : NULL; | |
| 482 | + return obj ? &obj->val : NULL; | |
| 478 | 483 | } |
| 479 | 484 | |
| 480 | 485 | static void *dev_map_hash_lookup_elem(struct bpf_map *map, void *key) |
| 481 | 486 | { |
| 482 | 487 | struct bpf_dtab_netdev *obj = __dev_map_hash_lookup_elem(map, |
| 483 | 488 | *(u32 *)key); |
| 484 | − struct net_device *dev = obj ? obj->dev : NULL; | |
| 485 | − | |
| 486 | − return dev ? &dev->ifindex : NULL; | |
| 489 | + return obj ? &obj->val : NULL; | |
| 487 | 490 | } |
| 488 | 491 | |
| 489 | 492 | static void __dev_map_entry_free(struct rcu_head *rcu) |
| @@ -541,7 +544,7 @@ static int dev_map_hash_delete_elem(struct bpf_map *map, void *key) · 51 unmodified lines | ||
| 541 | 544 | |
| 542 | 545 | static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net, |
| 543 | 546 | struct bpf_dtab *dtab, |
| 544 | − u32 ifindex, | |
| 547 | + struct bpf_devmap_val *val, | |
| 545 | 548 | unsigned int idx) |
| 546 | 549 | { |
| 547 | 550 | struct bpf_dtab_netdev *dev; |
| @@ -551,16 +554,18 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net, · 3 unmodified lines | ||
| 551 | 554 | if (!dev) |
| 552 | 555 | return ERR_PTR(-ENOMEM); |
| 553 | 556 | |
| 554 | − dev->dev = dev_get_by_index(net, ifindex); | |
| 555 | − if (!dev->dev) { | |
| 556 | − kfree(dev); | |
| 557 | − return ERR_PTR(-EINVAL); | |
| 558 | − } | |
| 557 | + dev->dev = dev_get_by_index(net, val->ifindex); | |
| 558 | + if (!dev->dev) | |
| 559 | + goto err_out; | |
| 559 | 560 | |
| 560 | 561 | dev->idx = idx; |
| 561 | 562 | dev->dtab = dtab; |
| 563 | + dev->val.ifindex = val->ifindex; | |
| 562 | 564 | |
| 563 | 565 | return dev; |
| 566 | +err_out: | |
| 567 | + kfree(dev); | |
| 568 | + return ERR_PTR(-EINVAL); | |
| 564 | 569 | } |
| 565 | 570 | |
| 566 | 571 | static int __dev_map_update_elem(struct net *net, struct bpf_map *map, |
| @@ -568,7 +573,7 @@ static int __dev_map_update_elem(struct net *net, struct bpf_map *map, · 1 unmodified line | ||
| 568 | 573 | { |
| 569 | 574 | struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map); |
| 570 | 575 | struct bpf_dtab_netdev *dev, *old_dev; |
| 571 | − u32 ifindex = *(u32 *)value; | |
| 576 | + struct bpf_devmap_val val = { }; | |
| 572 | 577 | u32 i = *(u32 *)key; |
| 573 | 578 | |
| 574 | 579 | if (unlikely(map_flags > BPF_EXIST)) |
| @@ -578,10 +583,13 @@ static int __dev_map_update_elem(struct net *net, struct bpf_map *map, · 3 unmodified lines | ||
| 578 | 583 | if (unlikely(map_flags == BPF_NOEXIST)) |
| 579 | 584 | return -EEXIST; |
| 580 | 585 | |
| 581 | − if (!ifindex) { | |
| 586 | + /* already verified value_size <= sizeof val */ | |
| 587 | + memcpy(&val, value, map->value_size); | |
| 588 | + | |
| 589 | + if (!val.ifindex) { | |
| 582 | 590 | dev = NULL; |
| 583 | 591 | } else { |
| 584 | − dev = __dev_map_alloc_node(net, dtab, ifindex, i); | |
| 592 | + dev = __dev_map_alloc_node(net, dtab, &val, i); | |
| 585 | 593 | if (IS_ERR(dev)) |
| 586 | 594 | return PTR_ERR(dev); |
| 587 | 595 | } |
| @@ -609,12 +617,15 @@ static int __dev_map_hash_update_elem(struct net *net, struct bpf_map *map, · 21 unmodified lines | ||
| 609 | 617 | { |
| 610 | 618 | struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map); |
| 611 | 619 | struct bpf_dtab_netdev *dev, *old_dev; |
| 612 | − u32 ifindex = *(u32 *)value; | |
| 620 | + struct bpf_devmap_val val = { }; | |
| 613 | 621 | u32 idx = *(u32 *)key; |
| 614 | 622 | unsigned long flags; |
| 615 | 623 | int err = -EEXIST; |
| 616 | 624 | |
| 617 | − if (unlikely(map_flags > BPF_EXIST || !ifindex)) | |
| 625 | + /* already verified value_size <= sizeof val */ | |
| 626 | + memcpy(&val, value, map->value_size); | |
| 627 | + | |
| 628 | + if (unlikely(map_flags > BPF_EXIST || !val.ifindex)) | |
| 618 | 629 | return -EINVAL; |
| 619 | 630 | |
| 620 | 631 | spin_lock_irqsave(&dtab->index_lock, flags); |
| @@ -623,7 +634,7 @@ static int __dev_map_hash_update_elem(struct net *net, struct bpf_map *map, · 2 unmodified lines | ||
| 623 | 634 | if (old_dev && (map_flags & BPF_NOEXIST)) |
| 624 | 635 | goto out_err; |
| 625 | 636 | |
| 626 | − dev = __dev_map_alloc_node(net, dtab, ifindex, idx); | |
| 637 | + dev = __dev_map_alloc_node(net, dtab, &val, idx); | |
| 627 | 638 | if (IS_ERR(dev)) { |
| 628 | 639 | err = PTR_ERR(dev); |
| 629 | 640 | goto out_err; |