[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230926055913.9859-3-daniel@iogearbox.net>
Date: Tue, 26 Sep 2023 07:59:07 +0200
From: Daniel Borkmann <daniel@...earbox.net>
To: bpf@...r.kernel.org
Cc: netdev@...r.kernel.org,
martin.lau@...nel.org,
razor@...ckwall.org,
ast@...nel.org,
andrii@...nel.org,
john.fastabend@...il.com,
Daniel Borkmann <daniel@...earbox.net>
Subject: [PATCH bpf-next 2/8] meta, bpf: Add bpf link support for meta device
This adds BPF link support for meta device (BPF_LINK_TYPE_META). Similar
as with tcx or XDP, the BPF link for meta contains the device.
The bpf_mprog API has been reused for its implementation. For details, see
also commit e420bed0250 ("bpf: Add fd-based tcx multi-prog infra with link
support").
This is now the second user of bpf_mprog after tcx, and in meta case the
implementation is also a bit more straight forward since it does not need
to deal with miniq.
The UAPI extensions for the BPF_LINK_CREATE command are similar as for tcx,
that is, relative_{fd,id} and expected_revision.
Signed-off-by: Daniel Borkmann <daniel@...earbox.net>
---
drivers/net/meta.c | 211 ++++++++++++++++++++++++++++++++-
include/net/meta.h | 7 ++
include/uapi/linux/bpf.h | 11 ++
kernel/bpf/syscall.c | 2 +-
tools/include/uapi/linux/bpf.h | 11 ++
5 files changed, 240 insertions(+), 2 deletions(-)
diff --git a/drivers/net/meta.c b/drivers/net/meta.c
index e464f547b0a6..8cb39281c455 100644
--- a/drivers/net/meta.c
+++ b/drivers/net/meta.c
@@ -27,6 +27,11 @@ struct meta {
u32 headroom;
};
+struct meta_link {
+ struct bpf_link link;
+ struct net_device *dev;
+};
+
static void meta_scrub_minimum(struct sk_buff *skb)
{
skb->skb_iif = 0;
@@ -576,6 +581,207 @@ int meta_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
return ret;
}
+static struct meta_link *meta_link(struct bpf_link *link)
+{
+ return container_of(link, struct meta_link, link);
+}
+
+static const struct meta_link *meta_link_const(const struct bpf_link *link)
+{
+ return meta_link((struct bpf_link *)link);
+}
+
+static int meta_link_prog_attach(struct bpf_link *link, u32 flags,
+ u32 id_or_fd, u64 revision)
+{
+ struct meta_link *meta = meta_link(link);
+ struct bpf_mprog_entry *entry, *entry_new;
+ struct net_device *dev = meta->dev;
+ int ret;
+
+ ASSERT_RTNL();
+ entry = meta_entry_fetch(dev, true);
+ ret = bpf_mprog_attach(entry, &entry_new, link->prog, link, NULL, flags,
+ id_or_fd, revision);
+ if (!ret) {
+ if (entry != entry_new) {
+ meta_entry_update(dev, entry_new);
+ meta_entry_sync();
+ }
+ bpf_mprog_commit(entry);
+ }
+ return ret;
+}
+
+static void meta_link_release(struct bpf_link *link)
+{
+ struct meta_link *meta = meta_link(link);
+ struct bpf_mprog_entry *entry, *entry_new;
+ struct net_device *dev;
+ int ret = 0;
+
+ rtnl_lock();
+ dev = meta->dev;
+ if (!dev)
+ goto out;
+ entry = meta_entry_fetch(dev, false);
+ if (!entry) {
+ ret = -ENOENT;
+ goto out;
+ }
+ ret = bpf_mprog_detach(entry, &entry_new, link->prog, link, 0, 0, 0);
+ if (!ret) {
+ if (!bpf_mprog_total(entry_new))
+ entry_new = NULL;
+ meta_entry_update(dev, entry_new);
+ meta_entry_sync();
+ bpf_mprog_commit(entry);
+ meta->dev = NULL;
+ }
+out:
+ WARN_ON_ONCE(ret);
+ rtnl_unlock();
+}
+
+static int meta_link_update(struct bpf_link *link, struct bpf_prog *nprog,
+ struct bpf_prog *oprog)
+{
+ struct meta_link *meta = meta_link(link);
+ struct bpf_mprog_entry *entry, *entry_new;
+ struct net_device *dev;
+ int ret = 0;
+
+ rtnl_lock();
+ dev = meta->dev;
+ if (!dev) {
+ ret = -ENOLINK;
+ goto out;
+ }
+ if (oprog && link->prog != oprog) {
+ ret = -EPERM;
+ goto out;
+ }
+ oprog = link->prog;
+ if (oprog == nprog) {
+ bpf_prog_put(nprog);
+ goto out;
+ }
+ entry = meta_entry_fetch(dev, false);
+ if (!entry) {
+ ret = -ENOENT;
+ goto out;
+ }
+ ret = bpf_mprog_attach(entry, &entry_new, nprog, link, oprog,
+ BPF_F_REPLACE | BPF_F_ID,
+ link->prog->aux->id, 0);
+ if (!ret) {
+ WARN_ON_ONCE(entry != entry_new);
+ oprog = xchg(&link->prog, nprog);
+ bpf_prog_put(oprog);
+ bpf_mprog_commit(entry);
+ }
+out:
+ rtnl_unlock();
+ return ret;
+}
+
+static void meta_link_dealloc(struct bpf_link *link)
+{
+ kfree(meta_link(link));
+}
+
+static void meta_link_fdinfo(const struct bpf_link *link, struct seq_file *seq)
+{
+ const struct meta_link *meta = meta_link_const(link);
+ u32 ifindex = 0;
+
+ rtnl_lock();
+ if (meta->dev)
+ ifindex = meta->dev->ifindex;
+ rtnl_unlock();
+
+ seq_printf(seq, "ifindex:\t%u\n", ifindex);
+}
+
+static int meta_link_fill_info(const struct bpf_link *link,
+ struct bpf_link_info *info)
+{
+ const struct meta_link *meta = meta_link_const(link);
+ u32 ifindex = 0;
+
+ rtnl_lock();
+ if (meta->dev)
+ ifindex = meta->dev->ifindex;
+ rtnl_unlock();
+
+ info->meta.ifindex = ifindex;
+ return 0;
+}
+
+static int meta_link_detach(struct bpf_link *link)
+{
+ meta_link_release(link);
+ return 0;
+}
+
+static const struct bpf_link_ops meta_link_lops = {
+ .release = meta_link_release,
+ .detach = meta_link_detach,
+ .dealloc = meta_link_dealloc,
+ .update_prog = meta_link_update,
+ .show_fdinfo = meta_link_fdinfo,
+ .fill_link_info = meta_link_fill_info,
+};
+
+static int meta_link_init(struct meta_link *meta,
+ struct bpf_link_primer *link_primer,
+ struct net_device *dev, struct bpf_prog *prog)
+{
+ bpf_link_init(&meta->link, BPF_LINK_TYPE_META, &meta_link_lops, prog);
+ meta->dev = dev;
+ return bpf_link_prime(&meta->link, link_primer);
+}
+
+int meta_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
+{
+ struct bpf_link_primer link_primer;
+ struct net_device *dev;
+ struct meta_link *meta;
+ int ret;
+
+ rtnl_lock();
+ dev = meta_dev_fetch(current->nsproxy->net_ns,
+ attr->link_create.target_ifindex,
+ attr->link_create.attach_type);
+ if (IS_ERR(dev)) {
+ ret = PTR_ERR(dev);
+ goto out;
+ }
+ meta = kzalloc(sizeof(*meta), GFP_USER);
+ if (!meta) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = meta_link_init(meta, &link_primer, dev, prog);
+ if (ret) {
+ kfree(meta);
+ goto out;
+ }
+ ret = meta_link_prog_attach(&meta->link,
+ attr->link_create.flags,
+ attr->link_create.meta.relative_fd,
+ attr->link_create.meta.expected_revision);
+ if (ret) {
+ meta->dev = NULL;
+ bpf_link_cleanup(&link_primer);
+ goto out;
+ }
+ ret = bpf_link_settle(&link_primer);
+out:
+ rtnl_unlock();
+ return ret;
+}
+
static void meta_release_all(struct net_device *dev)
{
struct bpf_mprog_entry *entry;
@@ -589,7 +795,10 @@ static void meta_release_all(struct net_device *dev)
meta_entry_update(dev, NULL);
meta_entry_sync();
bpf_mprog_foreach_tuple(entry, fp, cp, tuple) {
- bpf_prog_put(tuple.prog);
+ if (tuple.link)
+ meta_link(tuple.link)->dev = NULL;
+ else
+ bpf_prog_put(tuple.prog);
}
}
diff --git a/include/net/meta.h b/include/net/meta.h
index 20fc61d05970..f1abe1d6d02d 100644
--- a/include/net/meta.h
+++ b/include/net/meta.h
@@ -7,6 +7,7 @@
#ifdef CONFIG_META
int meta_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog);
+int meta_link_attach(const union bpf_attr *attr, struct bpf_prog *prog);
int meta_prog_detach(const union bpf_attr *attr, struct bpf_prog *prog);
int meta_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr);
#else
@@ -16,6 +17,12 @@ static inline int meta_prog_attach(const union bpf_attr *attr,
return -EINVAL;
}
+static inline int meta_link_attach(const union bpf_attr *attr,
+ struct bpf_prog *prog)
+{
+ return -EINVAL;
+}
+
static inline int meta_prog_detach(const union bpf_attr *attr,
struct bpf_prog *prog)
{
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 00a875720e84..fd069f285fbc 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1068,6 +1068,7 @@ enum bpf_link_type {
BPF_LINK_TYPE_NETFILTER = 10,
BPF_LINK_TYPE_TCX = 11,
BPF_LINK_TYPE_UPROBE_MULTI = 12,
+ BPF_LINK_TYPE_META = 12,
MAX_BPF_LINK_TYPE,
};
@@ -1653,6 +1654,13 @@ union bpf_attr {
__u32 flags;
__u32 pid;
} uprobe_multi;
+ struct {
+ union {
+ __u32 relative_fd;
+ __u32 relative_id;
+ };
+ __u64 expected_revision;
+ } meta;
};
} link_create;
@@ -6564,6 +6572,9 @@ struct bpf_link_info {
__u32 ifindex;
__u32 attach_type;
} tcx;
+ struct {
+ __u32 ifindex;
+ } meta;
};
} __attribute__((aligned(8)));
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 51baf4355c39..b689da4de280 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -4969,7 +4969,7 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr)
attr->link_create.attach_type == BPF_TCX_EGRESS)
ret = tcx_link_attach(attr, prog);
else
- ret = -EINVAL;
+ ret = meta_link_attach(attr, prog);
break;
case BPF_PROG_TYPE_NETFILTER:
ret = bpf_nf_link_attach(attr, prog);
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 00a875720e84..fd069f285fbc 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -1068,6 +1068,7 @@ enum bpf_link_type {
BPF_LINK_TYPE_NETFILTER = 10,
BPF_LINK_TYPE_TCX = 11,
BPF_LINK_TYPE_UPROBE_MULTI = 12,
+ BPF_LINK_TYPE_META = 12,
MAX_BPF_LINK_TYPE,
};
@@ -1653,6 +1654,13 @@ union bpf_attr {
__u32 flags;
__u32 pid;
} uprobe_multi;
+ struct {
+ union {
+ __u32 relative_fd;
+ __u32 relative_id;
+ };
+ __u64 expected_revision;
+ } meta;
};
} link_create;
@@ -6564,6 +6572,9 @@ struct bpf_link_info {
__u32 ifindex;
__u32 attach_type;
} tcx;
+ struct {
+ __u32 ifindex;
+ } meta;
};
} __attribute__((aligned(8)));
--
2.34.1
Powered by blists - more mailing lists