diff mbox series

[bpf-next,v5,07/17] bpf: XDP metadata RX kfuncs

Message ID 20221220222043.3348718-8-sdf@google.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series xdp: hints via kfuncs | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ${{ matrix.test }} on ${{ matrix.arch }} with ${{ matrix.toolchain }}
bpf/vmtest-bpf-next-VM_Test-2 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 fail Logs for build for aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-7 fail Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-8 success Logs for llvm-toolchain
bpf/vmtest-bpf-next-VM_Test-9 success Logs for set-matrix
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count fail Series longer than 15 patches (and no cover letter)
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 4422 this patch: 4426
netdev/cc_maintainers warning 4 maintainers not CCed: edumazet@google.com davem@davemloft.net pabeni@redhat.com hawk@kernel.org
netdev/build_clang fail Errors and warnings before: 1040 this patch: 1042
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 4614 this patch: 4618
netdev/checkpatch fail ERROR: Macros with complex values should be enclosed in parentheses WARNING: line length of 82 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns
netdev/kdoc fail Errors and warnings before: 0 this patch: 1
netdev/source_inline success Was 0 now: 0

Commit Message

Stanislav Fomichev Dec. 20, 2022, 10:20 p.m. UTC
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>
---
 include/linux/bpf.h       |  9 ++++++-
 include/linux/netdevice.h |  7 ++++++
 include/net/xdp.h         | 21 ++++++++++++++++
 kernel/bpf/core.c         |  8 +++++++
 kernel/bpf/offload.c      | 28 ++++++++++++++++++++++
 kernel/bpf/verifier.c     | 41 +++++++++++++++++++++++++++++++-
 net/bpf/test_run.c        |  3 +++
 net/core/xdp.c            | 50 +++++++++++++++++++++++++++++++++++++++
 8 files changed, 165 insertions(+), 2 deletions(-)

Comments

kernel test robot Dec. 21, 2022, 5:43 a.m. UTC | #1
Hi Stanislav,

I love your patch! Perhaps something to improve:

[auto build test WARNING on bpf-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Stanislav-Fomichev/xdp-hints-via-kfuncs/20221221-110542
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20221220222043.3348718-8-sdf%40google.com
patch subject: [PATCH bpf-next v5 07/17] bpf: XDP metadata RX kfuncs
config: ia64-allyesconfig
compiler: ia64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/f0946bf20669262734baef03ae12ef189c9c9292
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Stanislav-Fomichev/xdp-hints-via-kfuncs/20221221-110542
        git checkout f0946bf20669262734baef03ae12ef189c9c9292
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=ia64 olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=ia64 SHELL=/bin/bash kernel/bpf/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> kernel/bpf/verifier.c:2084:5: warning: no previous prototype for 'bpf_dev_bound_kfunc_check' [-Wmissing-prototypes]
    2084 | int bpf_dev_bound_kfunc_check(struct bpf_verifier_env *env,
         |     ^~~~~~~~~~~~~~~~~~~~~~~~~


vim +/bpf_dev_bound_kfunc_check +2084 kernel/bpf/verifier.c

  2083	
> 2084	int bpf_dev_bound_kfunc_check(struct bpf_verifier_env *env,
  2085				      struct bpf_prog_aux *prog_aux)
  2086	{
  2087		if (!bpf_prog_is_dev_bound(prog_aux)) {
  2088			verbose(env, "metadata kfuncs require device-bound program\n");
  2089			return -EINVAL;
  2090		}
  2091	
  2092		if (bpf_prog_is_offloaded(prog_aux)) {
  2093			verbose(env, "metadata kfuncs can't be offloaded\n");
  2094			return -EINVAL;
  2095		}
  2096	
  2097		return 0;
  2098	}
  2099
Stanislav Fomichev Dec. 21, 2022, 5:49 p.m. UTC | #2
On Tue, Dec 20, 2022 at 9:44 PM kernel test robot <lkp@intel.com> wrote:
>
> Hi Stanislav,
>
> I love your patch! Perhaps something to improve:
>
> [auto build test WARNING on bpf-next/master]
>
> url:    https://github.com/intel-lab-lkp/linux/commits/Stanislav-Fomichev/xdp-hints-via-kfuncs/20221221-110542
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
> patch link:    https://lore.kernel.org/r/20221220222043.3348718-8-sdf%40google.com
> patch subject: [PATCH bpf-next v5 07/17] bpf: XDP metadata RX kfuncs
> config: ia64-allyesconfig
> compiler: ia64-linux-gcc (GCC) 12.1.0
> reproduce (this is a W=1 build):
>         wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>         chmod +x ~/bin/make.cross
>         # https://github.com/intel-lab-lkp/linux/commit/f0946bf20669262734baef03ae12ef189c9c9292
>         git remote add linux-review https://github.com/intel-lab-lkp/linux
>         git fetch --no-tags linux-review Stanislav-Fomichev/xdp-hints-via-kfuncs/20221221-110542
>         git checkout f0946bf20669262734baef03ae12ef189c9c9292
>         # save the config file
>         mkdir build_dir && cp config build_dir/.config
>         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=ia64 olddefconfig
>         COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=ia64 SHELL=/bin/bash kernel/bpf/
>
> If you fix the issue, kindly add following tag where applicable
> | Reported-by: kernel test robot <lkp@intel.com>
>
> All warnings (new ones prefixed by >>):
>
> >> kernel/bpf/verifier.c:2084:5: warning: no previous prototype for 'bpf_dev_bound_kfunc_check' [-Wmissing-prototypes]
>     2084 | int bpf_dev_bound_kfunc_check(struct bpf_verifier_env *env,
>          |     ^~~~~~~~~~~~~~~~~~~~~~~~~

Oops, this should be "static int bpf_dev_bound_kfunc_check" :-(



> vim +/bpf_dev_bound_kfunc_check +2084 kernel/bpf/verifier.c
>
>   2083
> > 2084  int bpf_dev_bound_kfunc_check(struct bpf_verifier_env *env,
>   2085                                struct bpf_prog_aux *prog_aux)
>   2086  {
>   2087          if (!bpf_prog_is_dev_bound(prog_aux)) {
>   2088                  verbose(env, "metadata kfuncs require device-bound program\n");
>   2089                  return -EINVAL;
>   2090          }
>   2091
>   2092          if (bpf_prog_is_offloaded(prog_aux)) {
>   2093                  verbose(env, "metadata kfuncs can't be offloaded\n");
>   2094                  return -EINVAL;
>   2095          }
>   2096
>   2097          return 0;
>   2098  }
>   2099
>
> --
> 0-DAY CI Kernel Test Service
> https://01.org/lkp
Martin KaFai Lau Dec. 23, 2022, 12:31 a.m. UTC | #3
On 12/20/22 2:20 PM, Stanislav Fomichev wrote:
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index bafcb7a3ae6f..6d81b14361e3 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -2097,6 +2097,14 @@ bool bpf_prog_map_compatible(struct bpf_map *map,
>   	if (fp->kprobe_override)
>   		return false;
>   
> +	/* XDP programs inserted into maps are not guaranteed to run on
> +	 * a particular netdev (and can run outside driver context entirely
> +	 * in the case of devmap and cpumap). Until device checks
> +	 * are implemented, prohibit adding dev-bound programs to program maps.
> +	 */
> +	if (bpf_prog_is_dev_bound(fp->aux))
> +		return false;
> +

There is a recent change in the same function in the bpf tree, commit 
1c123c567fb1. fyi.

[ ... ]

> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index fdfdcab4a59d..320451a0be3e 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -2081,6 +2081,22 @@ static struct btf *find_kfunc_desc_btf(struct bpf_verifier_env *env, s16 offset)
>   	return btf_vmlinux ?: ERR_PTR(-ENOENT);
>   }
>   
> +int bpf_dev_bound_kfunc_check(struct bpf_verifier_env *env,
> +			      struct bpf_prog_aux *prog_aux)

nit. Move the dev bound related function to offload.c. &env->log can be passed 
instead of env and then use bpf_log().


Others lgtm.
Stanislav Fomichev Dec. 23, 2022, 4:06 a.m. UTC | #4
On Thu, Dec 22, 2022 at 4:31 PM Martin KaFai Lau <martin.lau@linux.dev> wrote:
>
> On 12/20/22 2:20 PM, Stanislav Fomichev wrote:
> > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> > index bafcb7a3ae6f..6d81b14361e3 100644
> > --- a/kernel/bpf/core.c
> > +++ b/kernel/bpf/core.c
> > @@ -2097,6 +2097,14 @@ bool bpf_prog_map_compatible(struct bpf_map *map,
> >       if (fp->kprobe_override)
> >               return false;
> >
> > +     /* XDP programs inserted into maps are not guaranteed to run on
> > +      * a particular netdev (and can run outside driver context entirely
> > +      * in the case of devmap and cpumap). Until device checks
> > +      * are implemented, prohibit adding dev-bound programs to program maps.
> > +      */
> > +     if (bpf_prog_is_dev_bound(fp->aux))
> > +             return false;
> > +
>
> There is a recent change in the same function in the bpf tree, commit
> 1c123c567fb1. fyi.

Thanks for the heads up; looks like it won't conflict, right?

> [ ... ]
>
> > diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> > index fdfdcab4a59d..320451a0be3e 100644
> > --- a/kernel/bpf/verifier.c
> > +++ b/kernel/bpf/verifier.c
> > @@ -2081,6 +2081,22 @@ static struct btf *find_kfunc_desc_btf(struct bpf_verifier_env *env, s16 offset)
> >       return btf_vmlinux ?: ERR_PTR(-ENOENT);
> >   }
> >
> > +int bpf_dev_bound_kfunc_check(struct bpf_verifier_env *env,
> > +                           struct bpf_prog_aux *prog_aux)
>
> nit. Move the dev bound related function to offload.c. &env->log can be passed
> instead of env and then use bpf_log().

Sure, SG!

> Others lgtm.
>
David Vernet Dec. 27, 2022, 8:33 p.m. UTC | #5
On Tue, Dec 20, 2022 at 02:20:33PM -0800, Stanislav Fomichev wrote:

Hey Stanislav,

[...]

> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index aad12a179e54..b41d18490595 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -74,6 +74,7 @@ struct udp_tunnel_nic_info;
>  struct udp_tunnel_nic;
>  struct bpf_prog;
>  struct xdp_buff;
> +struct xdp_md;
>  
>  void synchronize_net(void);
>  void netdev_set_default_ethtool_ops(struct net_device *dev,
> @@ -1618,6 +1619,11 @@ struct net_device_ops {
>  						  bool cycles);
>  };
>  
> +struct xdp_metadata_ops {
> +	int	(*xmo_rx_timestamp)(const struct xdp_md *ctx, u64 *timestamp);
> +	int	(*xmo_rx_hash)(const struct xdp_md *ctx, u32 *hash);
> +};
> +
>  /**
>   * enum netdev_priv_flags - &struct net_device priv_flags
>   *
> @@ -2050,6 +2056,7 @@ struct net_device {
>  	unsigned int		flags;
>  	unsigned long long	priv_flags;
>  	const struct net_device_ops *netdev_ops;
> +	const struct xdp_metadata_ops *xdp_metadata_ops;

You need to document this field above the struct, or the docs build will
complain:

  SPHINX  htmldocs -->
  <redacted>
  make[2]: Nothing to be done for 'html'.
  Using sphinx_rtd_theme theme
  source directory: networking
  ./include/linux/netdevice.h:2371: warning: Function parameter or
  member 'xdp_metadata_ops' not described in 'net_device'

>  	int			ifindex;
>  	unsigned short		gflags;
>  	unsigned short		hard_header_len;

Thanks,
David
Stanislav Fomichev Jan. 3, 2023, 10:23 p.m. UTC | #6
On Tue, Dec 27, 2022 at 12:33 PM David Vernet <void@manifault.com> wrote:
>
> On Tue, Dec 20, 2022 at 02:20:33PM -0800, Stanislav Fomichev wrote:
>
> Hey Stanislav,
>
> [...]
>
> > diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> > index aad12a179e54..b41d18490595 100644
> > --- a/include/linux/netdevice.h
> > +++ b/include/linux/netdevice.h
> > @@ -74,6 +74,7 @@ struct udp_tunnel_nic_info;
> >  struct udp_tunnel_nic;
> >  struct bpf_prog;
> >  struct xdp_buff;
> > +struct xdp_md;
> >
> >  void synchronize_net(void);
> >  void netdev_set_default_ethtool_ops(struct net_device *dev,
> > @@ -1618,6 +1619,11 @@ struct net_device_ops {
> >                                                 bool cycles);
> >  };
> >
> > +struct xdp_metadata_ops {
> > +     int     (*xmo_rx_timestamp)(const struct xdp_md *ctx, u64 *timestamp);
> > +     int     (*xmo_rx_hash)(const struct xdp_md *ctx, u32 *hash);
> > +};
> > +
> >  /**
> >   * enum netdev_priv_flags - &struct net_device priv_flags
> >   *
> > @@ -2050,6 +2056,7 @@ struct net_device {
> >       unsigned int            flags;
> >       unsigned long long      priv_flags;
> >       const struct net_device_ops *netdev_ops;
> > +     const struct xdp_metadata_ops *xdp_metadata_ops;
>
> You need to document this field above the struct, or the docs build will
> complain:
>
>   SPHINX  htmldocs -->
>   <redacted>
>   make[2]: Nothing to be done for 'html'.
>   Using sphinx_rtd_theme theme
>   source directory: networking
>   ./include/linux/netdevice.h:2371: warning: Function parameter or
>   member 'xdp_metadata_ops' not described in 'net_device'
>
> >       int                     ifindex;
> >       unsigned short          gflags;
> >       unsigned short          hard_header_len;

Thanks, I will try to actually build the doc. Last time I tried it
took too long and I gave up :-)

> Thanks,
> David
David Vernet Jan. 3, 2023, 10:35 p.m. UTC | #7
On Tue, Jan 03, 2023 at 02:23:59PM -0800, Stanislav Fomichev wrote:
> On Tue, Dec 27, 2022 at 12:33 PM David Vernet <void@manifault.com> wrote:
> >
> > On Tue, Dec 20, 2022 at 02:20:33PM -0800, Stanislav Fomichev wrote:
> >
> > Hey Stanislav,
> >
> > [...]
> >
> > > diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> > > index aad12a179e54..b41d18490595 100644
> > > --- a/include/linux/netdevice.h
> > > +++ b/include/linux/netdevice.h
> > > @@ -74,6 +74,7 @@ struct udp_tunnel_nic_info;
> > >  struct udp_tunnel_nic;
> > >  struct bpf_prog;
> > >  struct xdp_buff;
> > > +struct xdp_md;
> > >
> > >  void synchronize_net(void);
> > >  void netdev_set_default_ethtool_ops(struct net_device *dev,
> > > @@ -1618,6 +1619,11 @@ struct net_device_ops {
> > >                                                 bool cycles);
> > >  };
> > >
> > > +struct xdp_metadata_ops {
> > > +     int     (*xmo_rx_timestamp)(const struct xdp_md *ctx, u64 *timestamp);
> > > +     int     (*xmo_rx_hash)(const struct xdp_md *ctx, u32 *hash);
> > > +};
> > > +
> > >  /**
> > >   * enum netdev_priv_flags - &struct net_device priv_flags
> > >   *
> > > @@ -2050,6 +2056,7 @@ struct net_device {
> > >       unsigned int            flags;
> > >       unsigned long long      priv_flags;
> > >       const struct net_device_ops *netdev_ops;
> > > +     const struct xdp_metadata_ops *xdp_metadata_ops;
> >
> > You need to document this field above the struct, or the docs build will
> > complain:
> >
> >   SPHINX  htmldocs -->
> >   <redacted>
> >   make[2]: Nothing to be done for 'html'.
> >   Using sphinx_rtd_theme theme
> >   source directory: networking
> >   ./include/linux/netdevice.h:2371: warning: Function parameter or
> >   member 'xdp_metadata_ops' not described in 'net_device'
> >
> > >       int                     ifindex;
> > >       unsigned short          gflags;
> > >       unsigned short          hard_header_len;
> 
> Thanks, I will try to actually build the doc. Last time I tried it
> took too long and I gave up :-)

FYI the docs build system supports building specific subdirectories,
e.g.:

make -j SPHINXDIRS="networking" htmldocs

That should take O(seconds) instead of O(timeout) :-)

- David
diff mbox series

Patch

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 4c9649e69993..969f53691dd4 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2480,6 +2480,7 @@  bool bpf_offload_dev_match(struct bpf_prog *prog, struct net_device *netdev);
 void unpriv_ebpf_notify(int new_state);
 
 #if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL)
+void *bpf_dev_bound_resolve_kfunc(struct bpf_prog *prog, u32 func_id);
 int bpf_prog_dev_bound_init(struct bpf_prog *prog, union bpf_attr *attr);
 void bpf_dev_bound_netdev_unregister(struct net_device *dev);
 
@@ -2514,8 +2515,14 @@  void sock_map_unhash(struct sock *sk);
 void sock_map_destroy(struct sock *sk);
 void sock_map_close(struct sock *sk, long timeout);
 #else
+static inline void *bpf_dev_bound_resolve_kfunc(struct bpf_prog *prog,
+						u32 func_id)
+{
+	return NULL;
+}
+
 static inline int bpf_prog_dev_bound_init(struct bpf_prog *prog,
-					union bpf_attr *attr)
+					  union bpf_attr *attr)
 {
 	return -EOPNOTSUPP;
 }
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index aad12a179e54..b41d18490595 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -74,6 +74,7 @@  struct udp_tunnel_nic_info;
 struct udp_tunnel_nic;
 struct bpf_prog;
 struct xdp_buff;
+struct xdp_md;
 
 void synchronize_net(void);
 void netdev_set_default_ethtool_ops(struct net_device *dev,
@@ -1618,6 +1619,11 @@  struct net_device_ops {
 						  bool cycles);
 };
 
+struct xdp_metadata_ops {
+	int	(*xmo_rx_timestamp)(const struct xdp_md *ctx, u64 *timestamp);
+	int	(*xmo_rx_hash)(const struct xdp_md *ctx, u32 *hash);
+};
+
 /**
  * enum netdev_priv_flags - &struct net_device priv_flags
  *
@@ -2050,6 +2056,7 @@  struct net_device {
 	unsigned int		flags;
 	unsigned long long	priv_flags;
 	const struct net_device_ops *netdev_ops;
+	const struct xdp_metadata_ops *xdp_metadata_ops;
 	int			ifindex;
 	unsigned short		gflags;
 	unsigned short		hard_header_len;
diff --git a/include/net/xdp.h b/include/net/xdp.h
index 55dbc68bfffc..91292aa13bc0 100644
--- a/include/net/xdp.h
+++ b/include/net/xdp.h
@@ -409,4 +409,25 @@  void xdp_attachment_setup(struct xdp_attachment_info *info,
 
 #define DEV_MAP_BULK_SIZE XDP_BULK_QUEUE_SIZE
 
+#define XDP_METADATA_KFUNC_xxx	\
+	XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_TIMESTAMP, \
+			   bpf_xdp_metadata_rx_timestamp) \
+	XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_HASH, \
+			   bpf_xdp_metadata_rx_hash) \
+
+enum {
+#define XDP_METADATA_KFUNC(name, _) name,
+XDP_METADATA_KFUNC_xxx
+#undef XDP_METADATA_KFUNC
+MAX_XDP_METADATA_KFUNC,
+};
+
+#ifdef CONFIG_NET
+u32 bpf_xdp_metadata_kfunc_id(int id);
+bool bpf_dev_bound_kfunc_id(u32 btf_id);
+#else
+static inline u32 bpf_xdp_metadata_kfunc_id(int id) { return 0; }
+static inline bool bpf_dev_bound_kfunc_id(u32 btf_id) { return false; }
+#endif
+
 #endif /* __LINUX_NET_XDP_H__ */
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index bafcb7a3ae6f..6d81b14361e3 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2097,6 +2097,14 @@  bool bpf_prog_map_compatible(struct bpf_map *map,
 	if (fp->kprobe_override)
 		return false;
 
+	/* XDP programs inserted into maps are not guaranteed to run on
+	 * a particular netdev (and can run outside driver context entirely
+	 * in the case of devmap and cpumap). Until device checks
+	 * are implemented, prohibit adding dev-bound programs to program maps.
+	 */
+	if (bpf_prog_is_dev_bound(fp->aux))
+		return false;
+
 	spin_lock(&map->owner.lock);
 	if (!map->owner.type) {
 		/* There's no owner yet where we could check for
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c
index e803824c1ddd..0e3fc743e0a8 100644
--- a/kernel/bpf/offload.c
+++ b/kernel/bpf/offload.c
@@ -767,6 +767,34 @@  void bpf_dev_bound_netdev_unregister(struct net_device *dev)
 	up_write(&bpf_devs_lock);
 }
 
+void *bpf_dev_bound_resolve_kfunc(struct bpf_prog *prog, u32 func_id)
+{
+	const struct xdp_metadata_ops *ops;
+	void *p = NULL;
+
+	/* We don't hold bpf_devs_lock while resolving several
+	 * kfuncs and can race with the unregister_netdevice().
+	 * We rely on bpf_dev_bound_match() check at attach
+	 * to render this program unusable.
+	 */
+	down_read(&bpf_devs_lock);
+	if (!prog->aux->offload || !prog->aux->offload->netdev)
+		goto out;
+
+	ops = prog->aux->offload->netdev->xdp_metadata_ops;
+	if (!ops)
+		goto out;
+
+	if (func_id == bpf_xdp_metadata_kfunc_id(XDP_METADATA_KFUNC_RX_TIMESTAMP))
+		p = ops->xmo_rx_timestamp;
+	else if (func_id == bpf_xdp_metadata_kfunc_id(XDP_METADATA_KFUNC_RX_HASH))
+		p = ops->xmo_rx_hash;
+out:
+	up_read(&bpf_devs_lock);
+
+	return p;
+}
+
 static int __init bpf_offload_init(void)
 {
 	return rhashtable_init(&offdevs, &offdevs_params);
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index fdfdcab4a59d..320451a0be3e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2081,6 +2081,22 @@  static struct btf *find_kfunc_desc_btf(struct bpf_verifier_env *env, s16 offset)
 	return btf_vmlinux ?: ERR_PTR(-ENOENT);
 }
 
+int bpf_dev_bound_kfunc_check(struct bpf_verifier_env *env,
+			      struct bpf_prog_aux *prog_aux)
+{
+	if (!bpf_prog_is_dev_bound(prog_aux)) {
+		verbose(env, "metadata kfuncs require device-bound program\n");
+		return -EINVAL;
+	}
+
+	if (bpf_prog_is_offloaded(prog_aux)) {
+		verbose(env, "metadata kfuncs can't be offloaded\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
 {
 	const struct btf_type *func, *func_proto;
@@ -2183,6 +2199,12 @@  static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
 		return -EINVAL;
 	}
 
+	if (bpf_dev_bound_kfunc_id(func_id)) {
+		err = bpf_dev_bound_kfunc_check(env, prog_aux);
+		if (err)
+			return err;
+	}
+
 	desc = &tab->descs[tab->nr_descs++];
 	desc->func_id = func_id;
 	desc->imm = call_imm;
@@ -15480,12 +15502,25 @@  static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 			    struct bpf_insn *insn_buf, int insn_idx, int *cnt)
 {
 	const struct bpf_kfunc_desc *desc;
+	void *xdp_kfunc;
 
 	if (!insn->imm) {
 		verbose(env, "invalid kernel function call not eliminated in verifier pass\n");
 		return -EINVAL;
 	}
 
+	*cnt = 0;
+
+	if (bpf_dev_bound_kfunc_id(insn->imm)) {
+		xdp_kfunc = bpf_dev_bound_resolve_kfunc(env->prog, insn->imm);
+		if (xdp_kfunc) {
+			insn->imm = BPF_CALL_IMM(xdp_kfunc);
+			return 0;
+		}
+
+		/* fallback to default kfunc when not supported by netdev */
+	}
+
 	/* insn->imm has the btf func_id. Replace it with
 	 * an address (relative to __bpf_call_base).
 	 */
@@ -15496,7 +15531,6 @@  static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
 		return -EFAULT;
 	}
 
-	*cnt = 0;
 	insn->imm = desc->imm;
 	if (insn->off)
 		return 0;
@@ -16503,6 +16537,11 @@  int bpf_check_attach_target(struct bpf_verifier_log *log,
 	if (tgt_prog) {
 		struct bpf_prog_aux *aux = tgt_prog->aux;
 
+		if (bpf_prog_is_dev_bound(tgt_prog->aux)) {
+			bpf_log(log, "Replacing device-bound programs not supported\n");
+			return -EINVAL;
+		}
+
 		for (i = 0; i < aux->func_info_cnt; i++)
 			if (aux->func_info[i].type_id == btf_id) {
 				subprog = i;
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index 2723623429ac..8da0d73b368e 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -1300,6 +1300,9 @@  int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
 	if (kattr->test.flags & ~BPF_F_TEST_XDP_LIVE_FRAMES)
 		return -EINVAL;
 
+	if (bpf_prog_is_dev_bound(prog->aux))
+		return -EINVAL;
+
 	if (do_live) {
 		if (!batch_size)
 			batch_size = NAPI_POLL_WEIGHT;
diff --git a/net/core/xdp.c b/net/core/xdp.c
index 844c9d99dc0e..ec016ee5c046 100644
--- a/net/core/xdp.c
+++ b/net/core/xdp.c
@@ -4,6 +4,7 @@ 
  * Copyright (c) 2017 Jesper Dangaard Brouer, Red Hat Inc.
  */
 #include <linux/bpf.h>
+#include <linux/btf_ids.h>
 #include <linux/filter.h>
 #include <linux/types.h>
 #include <linux/mm.h>
@@ -709,3 +710,52 @@  struct xdp_frame *xdpf_clone(struct xdp_frame *xdpf)
 
 	return nxdpf;
 }
+
+__diag_push();
+__diag_ignore_all("-Wmissing-prototypes",
+		  "Global functions as their definitions will be in vmlinux BTF");
+
+int bpf_xdp_metadata_rx_timestamp(const struct xdp_md *ctx, u64 *timestamp)
+{
+	return -EOPNOTSUPP;
+}
+
+int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, u32 *hash)
+{
+	return -EOPNOTSUPP;
+}
+
+__diag_pop();
+
+BTF_SET8_START(xdp_metadata_kfunc_ids)
+#define XDP_METADATA_KFUNC(_, name) BTF_ID_FLAGS(func, name, 0)
+XDP_METADATA_KFUNC_xxx
+#undef XDP_METADATA_KFUNC
+BTF_SET8_END(xdp_metadata_kfunc_ids)
+
+static const struct btf_kfunc_id_set xdp_metadata_kfunc_set = {
+	.owner = THIS_MODULE,
+	.set   = &xdp_metadata_kfunc_ids,
+};
+
+BTF_ID_LIST(xdp_metadata_kfunc_ids_unsorted)
+#define XDP_METADATA_KFUNC(name, str) BTF_ID(func, str)
+XDP_METADATA_KFUNC_xxx
+#undef XDP_METADATA_KFUNC
+
+u32 bpf_xdp_metadata_kfunc_id(int id)
+{
+	/* xdp_metadata_kfunc_ids is sorted and can't be used */
+	return xdp_metadata_kfunc_ids_unsorted[id];
+}
+
+bool bpf_dev_bound_kfunc_id(u32 btf_id)
+{
+	return btf_id_set8_contains(&xdp_metadata_kfunc_ids, btf_id);
+}
+
+static int __init xdp_metadata_init(void)
+{
+	return register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &xdp_metadata_kfunc_set);
+}
+late_initcall(xdp_metadata_init);