[RFC PATCH bpf-next 1/2] net: bpf: Make xdp and cls_bpf use bpf_prog_put_dev()

From: Daniel Xu
Date: Tue Aug 22 2023 - 20:09:00 EST


This commit adds a stubbed bpf_prog_put_dev() that is symmetric to
bpf_prog_get_type_dev() such that all bpf device attachments are using a
*_dev() API.

This gives core bpf the ability to do special refcnt handling for device
attachments.

Signed-off-by: Daniel Xu <dxu@xxxxxxxxx>
---
include/linux/bpf.h | 1 +
kernel/bpf/devmap.c | 8 ++++----
kernel/bpf/syscall.c | 6 ++++++
net/core/dev.c | 16 ++++++++--------
net/sched/cls_bpf.c | 4 ++--
5 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index eced6400f778..08269ad8cc45 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2030,6 +2030,7 @@ void bpf_prog_sub(struct bpf_prog *prog, int i);
void bpf_prog_inc(struct bpf_prog *prog);
struct bpf_prog * __must_check bpf_prog_inc_not_zero(struct bpf_prog *prog);
void bpf_prog_put(struct bpf_prog *prog);
+void bpf_prog_put_dev(struct bpf_prog *prog);

void bpf_prog_free_id(struct bpf_prog *prog);
void bpf_map_free_id(struct bpf_map *map);
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index 4d42f6ed6c11..b5d33a87a560 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -212,7 +212,7 @@ static void dev_map_free(struct bpf_map *map)
hlist_for_each_entry_safe(dev, next, head, index_hlist) {
hlist_del_rcu(&dev->index_hlist);
if (dev->xdp_prog)
- bpf_prog_put(dev->xdp_prog);
+ bpf_prog_put_dev(dev->xdp_prog);
dev_put(dev->dev);
kfree(dev);
}
@@ -228,7 +228,7 @@ static void dev_map_free(struct bpf_map *map)
continue;

if (dev->xdp_prog)
- bpf_prog_put(dev->xdp_prog);
+ bpf_prog_put_dev(dev->xdp_prog);
dev_put(dev->dev);
kfree(dev);
}
@@ -800,7 +800,7 @@ static void __dev_map_entry_free(struct rcu_head *rcu)

dev = container_of(rcu, struct bpf_dtab_netdev, rcu);
if (dev->xdp_prog)
- bpf_prog_put(dev->xdp_prog);
+ bpf_prog_put_dev(dev->xdp_prog);
dev_put(dev->dev);
kfree(dev);
}
@@ -884,7 +884,7 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net,

return dev;
err_put_prog:
- bpf_prog_put(prog);
+ bpf_prog_put_dev(prog);
err_put_dev:
dev_put(dev->dev);
err_out:
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 10666d17b9e3..d8e5530598f3 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -2164,6 +2164,12 @@ void bpf_prog_put(struct bpf_prog *prog)
}
EXPORT_SYMBOL_GPL(bpf_prog_put);

+void bpf_prog_put_dev(struct bpf_prog *prog)
+{
+ bpf_prog_put(prog);
+}
+EXPORT_SYMBOL_GPL(bpf_prog_put_dev);
+
static int bpf_prog_release(struct inode *inode, struct file *filp)
{
struct bpf_prog *prog = filp->private_data;
diff --git a/net/core/dev.c b/net/core/dev.c
index 17e6281e408c..ed0ece344416 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5676,7 +5676,7 @@ static int generic_xdp_install(struct net_device *dev, struct netdev_bpf *xdp)
case XDP_SETUP_PROG:
rcu_assign_pointer(dev->xdp_prog, new);
if (old)
- bpf_prog_put(old);
+ bpf_prog_put_dev(old);

if (old && !new) {
static_branch_dec(&generic_xdp_needed_key);
@@ -9167,7 +9167,7 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode,
err = bpf_op(dev, &xdp);
if (err) {
if (prog)
- bpf_prog_put(prog);
+ bpf_prog_put_dev(prog);
return err;
}

@@ -9202,7 +9202,7 @@ static void dev_xdp_uninstall(struct net_device *dev)
if (link)
link->dev = NULL;
else
- bpf_prog_put(prog);
+ bpf_prog_put_dev(prog);

dev_xdp_set_link(dev, mode, NULL);
}
@@ -9326,7 +9326,7 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack
else
dev_xdp_set_prog(dev, mode, new_prog);
if (cur_prog)
- bpf_prog_put(cur_prog);
+ bpf_prog_put_dev(cur_prog);

return 0;
}
@@ -9445,7 +9445,7 @@ static int bpf_xdp_link_update(struct bpf_link *link, struct bpf_prog *new_prog,

if (old_prog == new_prog) {
/* no-op, don't disturb drivers */
- bpf_prog_put(new_prog);
+ bpf_prog_put_dev(new_prog);
goto out_unlock;
}

@@ -9457,7 +9457,7 @@ static int bpf_xdp_link_update(struct bpf_link *link, struct bpf_prog *new_prog,
goto out_unlock;

old_prog = xchg(&link->prog, new_prog);
- bpf_prog_put(old_prog);
+ bpf_prog_put_dev(old_prog);

out_unlock:
rtnl_unlock();
@@ -9568,9 +9568,9 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,

err_out:
if (err && new_prog)
- bpf_prog_put(new_prog);
+ bpf_prog_put_dev(new_prog);
if (old_prog)
- bpf_prog_put(old_prog);
+ bpf_prog_put_dev(old_prog);
return err;
}

diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index 382c7a71f81f..20129d73dab4 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -258,7 +258,7 @@ static int cls_bpf_init(struct tcf_proto *tp)
static void cls_bpf_free_parms(struct cls_bpf_prog *prog)
{
if (cls_bpf_is_ebpf(prog))
- bpf_prog_put(prog->filter);
+ bpf_prog_put_dev(prog->filter);
else
bpf_prog_destroy(prog->filter);

@@ -391,7 +391,7 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
if (tb[TCA_BPF_NAME]) {
name = nla_memdup(tb[TCA_BPF_NAME], GFP_KERNEL);
if (!name) {
- bpf_prog_put(fp);
+ bpf_prog_put_dev(fp);
return -ENOMEM;
}
}
--
2.41.0