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;