From 92de1e0e3523317c5749f3c87173dc90b1e8011b Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Wed, 21 Jul 2021 19:43:05 -0400 Subject: [PATCH] libbpf: search for metadata casting in create link This is third approach to implement informing driver about metadata used in XDP program. The same as in first one, searching for casting looks silly and probably decision about using metadata should be move to user application (second approach). Instead of searching for cast in program loading path do it in link creating path. From this context new field can be sent via ndo_bpf call to driver. Intorduce new metadata field in attributes structure. Instead of that we probably can reuse XDP flags, but as header with definition of flags isn't included in libbpf I decided to create new field. We also can include this header in libbpf (I think). This code assume that user uses bpf_program__attach_xdp to attach XDP program. It is used only in selftest code, so I haven't tested it yet. This is only idea, and also I think it will be better to move decision about using metadata to user. Because of that I will write sample used this function and test it when we decide that this approach is correct. Signed-off-by: Michal Swiatkowski --- include/linux/netdevice.h | 1 + include/uapi/linux/bpf.h | 1 + net/core/dev.c | 13 ++++++++----- tools/lib/bpf/bpf.h | 1 + tools/lib/bpf/libbpf.c | 25 +++++++++++++++++++++++++ 5 files changed, 36 insertions(+), 5 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 5cbc950b34dfd3..6aa92dc0f8db60 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -968,6 +968,7 @@ struct netdev_bpf { /* XDP_SETUP_PROG */ struct { u32 flags; + bool metadata; struct bpf_prog *prog; struct netlink_ext_ack *extack; }; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index ec6d85a817449e..d65a6e3d768398 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1420,6 +1420,7 @@ union bpf_attr { }; __u32 attach_type; /* attach type */ __u32 flags; /* extra flags */ + __u32 metadata; union { __u32 target_btf_id; /* btf_id of target to attach to */ struct { diff --git a/net/core/dev.c b/net/core/dev.c index 222b1d322c9693..6bd7a24ae64264 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -9239,6 +9239,7 @@ struct bpf_xdp_link { struct bpf_link link; struct net_device *dev; /* protected by rtnl_lock, no refcnt held */ int flags; + bool metadata; }; static enum bpf_xdp_mode dev_xdp_mode(struct net_device *dev, u32 flags) @@ -9315,7 +9316,7 @@ static void dev_xdp_set_prog(struct net_device *dev, enum bpf_xdp_mode mode, static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode, bpf_op_t bpf_op, struct netlink_ext_ack *extack, - u32 flags, struct bpf_prog *prog) + u32 flags, bool metadata, struct bpf_prog *prog) { struct netdev_bpf xdp; int err; @@ -9325,6 +9326,7 @@ static int dev_xdp_install(struct net_device *dev, enum bpf_xdp_mode mode, xdp.extack = extack; xdp.flags = flags; xdp.prog = prog; + xdp.metadata = metadata; /* Drivers assume refcnt is already incremented (i.e, prog pointer is * "moved" into driver), so they don't increment it on their own, but @@ -9365,7 +9367,7 @@ static void dev_xdp_uninstall(struct net_device *dev) if (!bpf_op) continue; - WARN_ON(dev_xdp_install(dev, mode, bpf_op, NULL, 0, NULL)); + WARN_ON(dev_xdp_install(dev, mode, bpf_op, NULL, 0, false, NULL)); /* auto-detach link from net device */ link = dev_xdp_link(dev, mode); @@ -9472,7 +9474,7 @@ static int dev_xdp_attach(struct net_device *dev, struct netlink_ext_ack *extack return -EOPNOTSUPP; } - err = dev_xdp_install(dev, mode, bpf_op, extack, flags, new_prog); + err = dev_xdp_install(dev, mode, bpf_op, extack, flags, link->metadata, new_prog); if (err) return err; } @@ -9508,7 +9510,7 @@ static int dev_xdp_detach_link(struct net_device *dev, return -EINVAL; bpf_op = dev_xdp_bpf_op(dev, mode); - WARN_ON(dev_xdp_install(dev, mode, bpf_op, NULL, 0, NULL)); + WARN_ON(dev_xdp_install(dev, mode, bpf_op, NULL, 0, false, NULL)); dev_xdp_set_link(dev, mode, NULL); return 0; } @@ -9602,7 +9604,7 @@ static int bpf_xdp_link_update(struct bpf_link *link, struct bpf_prog *new_prog, mode = dev_xdp_mode(xdp_link->dev, xdp_link->flags); bpf_op = dev_xdp_bpf_op(xdp_link->dev, mode); err = dev_xdp_install(xdp_link->dev, mode, bpf_op, NULL, - xdp_link->flags, new_prog); + xdp_link->flags, xdp_link->metadata, new_prog); if (err) goto out_unlock; @@ -9644,6 +9646,7 @@ int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog) bpf_link_init(&link->link, BPF_LINK_TYPE_XDP, &bpf_xdp_link_lops, prog); link->dev = dev; link->flags = attr->link_create.flags; + link->metadata = attr->link_create.metadata; err = bpf_link_prime(&link->link, &link_primer); if (err) { diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 875dde20d56e32..49b9c753f0594c 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -175,6 +175,7 @@ struct bpf_link_create_opts { union bpf_iter_link_info *iter_info; __u32 iter_info_len; __u32 target_btf_id; + bool metadata; }; #define bpf_link_create_opts__last_field target_btf_id diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index e2a3cf4378140f..452c051f70ef51 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -10265,6 +10265,28 @@ static struct bpf_link *attach_iter(const struct bpf_sec_def *sec, return bpf_program__attach_iter(prog, NULL); } +/* Assume that if line have (struct xdp_meta_generic *) program for + * sure uses hints. This automatic search doesn't look good, maybe better + * solution is to allow user to decide if hints offload should be use. + * This can be done by exposing attr load bpf program flag. + * */ +static bool +libbpf_is_metadata_used(struct bpf_program *prog, int btf_fd) +{ + struct bpf_line_info *linfo = (struct bpf_line_info *)prog->line_info; + struct btf *btf = btf_get_from_fd(btf_fd, NULL); + const char meta_marker[] = "(struct xdp_meta_generic *)"; + int i; + + for (i = 0; i < prog->line_info_cnt; i++) { + if (strstr(btf__name_by_offset(btf, linfo[i].line_off), + meta_marker)) + return true; + } + + return false; +} + static struct bpf_link * bpf_program__attach_fd(struct bpf_program *prog, int target_fd, int btf_id, const char *target_name) @@ -10288,6 +10310,9 @@ bpf_program__attach_fd(struct bpf_program *prog, int target_fd, int btf_id, link->detach = &bpf_link__detach_fd; attach_type = bpf_program__get_expected_attach_type(prog); + opts.metadata = attach_type == BPF_XDP && + libbpf_is_metadata_used(prog, bpf_object__btf_fd(prog->obj)); + link_fd = bpf_link_create(prog_fd, target_fd, attach_type, &opts); if (link_fd < 0) { link_fd = -errno;