Skip to content

Commit 3d76a4d

Browse files
fomichevMartin KaFai Lau
authored andcommitted
bpf: XDP metadata RX kfuncs
Define a new kfunc set (xdp_metadata_kfunc_ids) which implements all possible XDP metatada kfuncs. Not all devices have to implement them. If kfunc is not supported by the target device, the default implementation is called instead. The verifier, at load time, replaces a call to the generic kfunc with a call to the per-device one. Per-device kfunc pointers are stored in separate struct xdp_metadata_ops. Cc: John Fastabend <john.fastabend@gmail.com> Cc: David Ahern <dsahern@gmail.com> Cc: Martin KaFai Lau <martin.lau@linux.dev> Cc: Jakub Kicinski <kuba@kernel.org> Cc: Willem de Bruijn <willemb@google.com> Cc: Jesper Dangaard Brouer <brouer@redhat.com> Cc: Anatoly Burakov <anatoly.burakov@intel.com> Cc: Alexander Lobakin <alexandr.lobakin@intel.com> Cc: Magnus Karlsson <magnus.karlsson@gmail.com> Cc: Maryam Tahhan <mtahhan@redhat.com> Cc: xdp-hints@xdp-project.net Cc: netdev@vger.kernel.org Signed-off-by: Stanislav Fomichev <sdf@google.com> Link: https://lore.kernel.org/r/20230119221536.3349901-8-sdf@google.com Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
1 parent 4053570 commit 3d76a4d

File tree

8 files changed

+188
-2
lines changed

8 files changed

+188
-2
lines changed

include/linux/bpf.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2480,6 +2480,9 @@ bool bpf_offload_dev_match(struct bpf_prog *prog, struct net_device *netdev);
24802480
void unpriv_ebpf_notify(int new_state);
24812481

24822482
#if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL)
2483+
int bpf_dev_bound_kfunc_check(struct bpf_verifier_log *log,
2484+
struct bpf_prog_aux *prog_aux);
2485+
void *bpf_dev_bound_resolve_kfunc(struct bpf_prog *prog, u32 func_id);
24832486
int bpf_prog_dev_bound_init(struct bpf_prog *prog, union bpf_attr *attr);
24842487
void bpf_dev_bound_netdev_unregister(struct net_device *dev);
24852488

@@ -2514,8 +2517,20 @@ void sock_map_unhash(struct sock *sk);
25142517
void sock_map_destroy(struct sock *sk);
25152518
void sock_map_close(struct sock *sk, long timeout);
25162519
#else
2520+
static inline int bpf_dev_bound_kfunc_check(struct bpf_verifier_log *log,
2521+
struct bpf_prog_aux *prog_aux)
2522+
{
2523+
return -EOPNOTSUPP;
2524+
}
2525+
2526+
static inline void *bpf_dev_bound_resolve_kfunc(struct bpf_prog *prog,
2527+
u32 func_id)
2528+
{
2529+
return NULL;
2530+
}
2531+
25172532
static inline int bpf_prog_dev_bound_init(struct bpf_prog *prog,
2518-
union bpf_attr *attr)
2533+
union bpf_attr *attr)
25192534
{
25202535
return -EOPNOTSUPP;
25212536
}

include/linux/netdevice.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct udp_tunnel_nic_info;
7474
struct udp_tunnel_nic;
7575
struct bpf_prog;
7676
struct xdp_buff;
77+
struct xdp_md;
7778

7879
void synchronize_net(void);
7980
void netdev_set_default_ethtool_ops(struct net_device *dev,
@@ -1618,6 +1619,11 @@ struct net_device_ops {
16181619
bool cycles);
16191620
};
16201621

1622+
struct xdp_metadata_ops {
1623+
int (*xmo_rx_timestamp)(const struct xdp_md *ctx, u64 *timestamp);
1624+
int (*xmo_rx_hash)(const struct xdp_md *ctx, u32 *hash);
1625+
};
1626+
16211627
/**
16221628
* enum netdev_priv_flags - &struct net_device priv_flags
16231629
*
@@ -1801,6 +1807,7 @@ enum netdev_ml_priv_type {
18011807
*
18021808
* @netdev_ops: Includes several pointers to callbacks,
18031809
* if one wants to override the ndo_*() functions
1810+
* @xdp_metadata_ops: Includes pointers to XDP metadata callbacks.
18041811
* @ethtool_ops: Management operations
18051812
* @l3mdev_ops: Layer 3 master device operations
18061813
* @ndisc_ops: Includes callbacks for different IPv6 neighbour
@@ -2050,6 +2057,7 @@ struct net_device {
20502057
unsigned int flags;
20512058
unsigned long long priv_flags;
20522059
const struct net_device_ops *netdev_ops;
2060+
const struct xdp_metadata_ops *xdp_metadata_ops;
20532061
int ifindex;
20542062
unsigned short gflags;
20552063
unsigned short hard_header_len;

include/net/xdp.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,4 +409,25 @@ void xdp_attachment_setup(struct xdp_attachment_info *info,
409409

410410
#define DEV_MAP_BULK_SIZE XDP_BULK_QUEUE_SIZE
411411

412+
#define XDP_METADATA_KFUNC_xxx \
413+
XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_TIMESTAMP, \
414+
bpf_xdp_metadata_rx_timestamp) \
415+
XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_HASH, \
416+
bpf_xdp_metadata_rx_hash) \
417+
418+
enum {
419+
#define XDP_METADATA_KFUNC(name, _) name,
420+
XDP_METADATA_KFUNC_xxx
421+
#undef XDP_METADATA_KFUNC
422+
MAX_XDP_METADATA_KFUNC,
423+
};
424+
425+
#ifdef CONFIG_NET
426+
u32 bpf_xdp_metadata_kfunc_id(int id);
427+
bool bpf_dev_bound_kfunc_id(u32 btf_id);
428+
#else
429+
static inline u32 bpf_xdp_metadata_kfunc_id(int id) { return 0; }
430+
static inline bool bpf_dev_bound_kfunc_id(u32 btf_id) { return false; }
431+
#endif
432+
412433
#endif /* __LINUX_NET_XDP_H__ */

kernel/bpf/core.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,6 +2096,14 @@ bool bpf_prog_map_compatible(struct bpf_map *map,
20962096
if (fp->kprobe_override)
20972097
return false;
20982098

2099+
/* XDP programs inserted into maps are not guaranteed to run on
2100+
* a particular netdev (and can run outside driver context entirely
2101+
* in the case of devmap and cpumap). Until device checks
2102+
* are implemented, prohibit adding dev-bound programs to program maps.
2103+
*/
2104+
if (bpf_prog_is_dev_bound(fp->aux))
2105+
return false;
2106+
20992107
spin_lock(&map->owner.lock);
21002108
if (!map->owner.type) {
21012109
/* There's no owner yet where we could check for

kernel/bpf/offload.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,50 @@ void bpf_dev_bound_netdev_unregister(struct net_device *dev)
755755
up_write(&bpf_devs_lock);
756756
}
757757

758+
int bpf_dev_bound_kfunc_check(struct bpf_verifier_log *log,
759+
struct bpf_prog_aux *prog_aux)
760+
{
761+
if (!bpf_prog_is_dev_bound(prog_aux)) {
762+
bpf_log(log, "metadata kfuncs require device-bound program\n");
763+
return -EINVAL;
764+
}
765+
766+
if (bpf_prog_is_offloaded(prog_aux)) {
767+
bpf_log(log, "metadata kfuncs can't be offloaded\n");
768+
return -EINVAL;
769+
}
770+
771+
return 0;
772+
}
773+
774+
void *bpf_dev_bound_resolve_kfunc(struct bpf_prog *prog, u32 func_id)
775+
{
776+
const struct xdp_metadata_ops *ops;
777+
void *p = NULL;
778+
779+
/* We don't hold bpf_devs_lock while resolving several
780+
* kfuncs and can race with the unregister_netdevice().
781+
* We rely on bpf_dev_bound_match() check at attach
782+
* to render this program unusable.
783+
*/
784+
down_read(&bpf_devs_lock);
785+
if (!prog->aux->offload)
786+
goto out;
787+
788+
ops = prog->aux->offload->netdev->xdp_metadata_ops;
789+
if (!ops)
790+
goto out;
791+
792+
if (func_id == bpf_xdp_metadata_kfunc_id(XDP_METADATA_KFUNC_RX_TIMESTAMP))
793+
p = ops->xmo_rx_timestamp;
794+
else if (func_id == bpf_xdp_metadata_kfunc_id(XDP_METADATA_KFUNC_RX_HASH))
795+
p = ops->xmo_rx_hash;
796+
out:
797+
up_read(&bpf_devs_lock);
798+
799+
return p;
800+
}
801+
758802
static int __init bpf_offload_init(void)
759803
{
760804
return rhashtable_init(&offdevs, &offdevs_params);

kernel/bpf/verifier.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2333,6 +2333,12 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
23332333
return -EINVAL;
23342334
}
23352335

2336+
if (bpf_dev_bound_kfunc_id(func_id)) {
2337+
err = bpf_dev_bound_kfunc_check(&env->log, prog_aux);
2338+
if (err)
2339+
return err;
2340+
}
2341+
23362342
desc = &tab->descs[tab->nr_descs++];
23372343
desc->func_id = func_id;
23382344
desc->imm = call_imm;
@@ -15772,12 +15778,25 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1577215778
struct bpf_insn *insn_buf, int insn_idx, int *cnt)
1577315779
{
1577415780
const struct bpf_kfunc_desc *desc;
15781+
void *xdp_kfunc;
1577515782

1577615783
if (!insn->imm) {
1577715784
verbose(env, "invalid kernel function call not eliminated in verifier pass\n");
1577815785
return -EINVAL;
1577915786
}
1578015787

15788+
*cnt = 0;
15789+
15790+
if (bpf_dev_bound_kfunc_id(insn->imm)) {
15791+
xdp_kfunc = bpf_dev_bound_resolve_kfunc(env->prog, insn->imm);
15792+
if (xdp_kfunc) {
15793+
insn->imm = BPF_CALL_IMM(xdp_kfunc);
15794+
return 0;
15795+
}
15796+
15797+
/* fallback to default kfunc when not supported by netdev */
15798+
}
15799+
1578115800
/* insn->imm has the btf func_id. Replace it with
1578215801
* an address (relative to __bpf_call_base).
1578315802
*/
@@ -15788,7 +15807,6 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1578815807
return -EFAULT;
1578915808
}
1579015809

15791-
*cnt = 0;
1579215810
insn->imm = desc->imm;
1579315811
if (insn->off)
1579415812
return 0;
@@ -16795,6 +16813,11 @@ int bpf_check_attach_target(struct bpf_verifier_log *log,
1679516813
if (tgt_prog) {
1679616814
struct bpf_prog_aux *aux = tgt_prog->aux;
1679716815

16816+
if (bpf_prog_is_dev_bound(tgt_prog->aux)) {
16817+
bpf_log(log, "Replacing device-bound programs not supported\n");
16818+
return -EINVAL;
16819+
}
16820+
1679816821
for (i = 0; i < aux->func_info_cnt; i++)
1679916822
if (aux->func_info[i].type_id == btf_id) {
1680016823
subprog = i;

net/bpf/test_run.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,9 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
13001300
if (kattr->test.flags & ~BPF_F_TEST_XDP_LIVE_FRAMES)
13011301
return -EINVAL;
13021302

1303+
if (bpf_prog_is_dev_bound(prog->aux))
1304+
return -EINVAL;
1305+
13031306
if (do_live) {
13041307
if (!batch_size)
13051308
batch_size = NAPI_POLL_WEIGHT;

net/core/xdp.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Copyright (c) 2017 Jesper Dangaard Brouer, Red Hat Inc.
55
*/
66
#include <linux/bpf.h>
7+
#include <linux/btf_ids.h>
78
#include <linux/filter.h>
89
#include <linux/types.h>
910
#include <linux/mm.h>
@@ -709,3 +710,66 @@ struct xdp_frame *xdpf_clone(struct xdp_frame *xdpf)
709710

710711
return nxdpf;
711712
}
713+
714+
__diag_push();
715+
__diag_ignore_all("-Wmissing-prototypes",
716+
"Global functions as their definitions will be in vmlinux BTF");
717+
718+
/**
719+
* bpf_xdp_metadata_rx_timestamp - Read XDP frame RX timestamp.
720+
* @ctx: XDP context pointer.
721+
* @timestamp: Return value pointer.
722+
*
723+
* Returns 0 on success or ``-errno`` on error.
724+
*/
725+
int bpf_xdp_metadata_rx_timestamp(const struct xdp_md *ctx, u64 *timestamp)
726+
{
727+
return -EOPNOTSUPP;
728+
}
729+
730+
/**
731+
* bpf_xdp_metadata_rx_hash - Read XDP frame RX hash.
732+
* @ctx: XDP context pointer.
733+
* @hash: Return value pointer.
734+
*
735+
* Returns 0 on success or ``-errno`` on error.
736+
*/
737+
int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, u32 *hash)
738+
{
739+
return -EOPNOTSUPP;
740+
}
741+
742+
__diag_pop();
743+
744+
BTF_SET8_START(xdp_metadata_kfunc_ids)
745+
#define XDP_METADATA_KFUNC(_, name) BTF_ID_FLAGS(func, name, 0)
746+
XDP_METADATA_KFUNC_xxx
747+
#undef XDP_METADATA_KFUNC
748+
BTF_SET8_END(xdp_metadata_kfunc_ids)
749+
750+
static const struct btf_kfunc_id_set xdp_metadata_kfunc_set = {
751+
.owner = THIS_MODULE,
752+
.set = &xdp_metadata_kfunc_ids,
753+
};
754+
755+
BTF_ID_LIST(xdp_metadata_kfunc_ids_unsorted)
756+
#define XDP_METADATA_KFUNC(name, str) BTF_ID(func, str)
757+
XDP_METADATA_KFUNC_xxx
758+
#undef XDP_METADATA_KFUNC
759+
760+
u32 bpf_xdp_metadata_kfunc_id(int id)
761+
{
762+
/* xdp_metadata_kfunc_ids is sorted and can't be used */
763+
return xdp_metadata_kfunc_ids_unsorted[id];
764+
}
765+
766+
bool bpf_dev_bound_kfunc_id(u32 btf_id)
767+
{
768+
return btf_id_set8_contains(&xdp_metadata_kfunc_ids, btf_id);
769+
}
770+
771+
static int __init xdp_metadata_init(void)
772+
{
773+
return register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &xdp_metadata_kfunc_set);
774+
}
775+
late_initcall(xdp_metadata_init);

0 commit comments

Comments
 (0)