[v5,7/8] net/tap: use libbpf to load new BPF program

Message ID 20240402171751.138324-8-stephen@networkplumber.org (mailing list archive)
State Superseded
Delegated to: Thomas Monjalon
Headers
Series net/tap: cleanups and fix BPF flow |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Stephen Hemminger April 2, 2024, 5:12 p.m. UTC
  There were multiple issues in the RSS queue support in the TAP
driver. This required extensive rework of the BPF support.

Change the BPF loading to use bpftool to
create a skeleton header file, and load with libbpf.
The BPF is always compiled from source so less chance that
source and instructions diverge. Also resolves issue where
libbpf and source get out of sync. The program
is only loaded once, so if multiple rules are created
only one BPF program is loaded in kernel.

The new BPF program only needs a single action.
No need for action and re-classification step.

It alsow fixes the missing bits from the original.
    - supports setting RSS key per flow
    - level of hash can be L3 or L3/L4.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 drivers/net/tap/bpf/meson.build |  14 +-
 drivers/net/tap/meson.build     |  29 +--
 drivers/net/tap/rte_eth_tap.c   |   2 +
 drivers/net/tap/rte_eth_tap.h   |   9 +-
 drivers/net/tap/tap_flow.c      | 410 +++++++-------------------------
 drivers/net/tap/tap_flow.h      |  16 +-
 drivers/net/tap/tap_rss.h       |  10 +-
 drivers/net/tap/tap_tcmsgs.h    |   4 +-
 8 files changed, 127 insertions(+), 367 deletions(-)
  

Comments

Luca Boccassi April 3, 2024, 11:50 a.m. UTC | #1
On Tue, 2024-04-02 at 10:12 -0700, Stephen Hemminger wrote:
> There were multiple issues in the RSS queue support in the TAP
> driver. This required extensive rework of the BPF support.
> 
> Change the BPF loading to use bpftool to
> create a skeleton header file, and load with libbpf.
> The BPF is always compiled from source so less chance that
> source and instructions diverge. Also resolves issue where
> libbpf and source get out of sync. The program
> is only loaded once, so if multiple rules are created
> only one BPF program is loaded in kernel.
> 
> The new BPF program only needs a single action.
> No need for action and re-classification step.
> 
> It alsow fixes the missing bits from the original.
>     - supports setting RSS key per flow
>     - level of hash can be L3 or L3/L4.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
>  drivers/net/tap/bpf/meson.build |  14 +-
>  drivers/net/tap/meson.build     |  29 +--
>  drivers/net/tap/rte_eth_tap.c   |   2 +
>  drivers/net/tap/rte_eth_tap.h   |   9 +-
>  drivers/net/tap/tap_flow.c      | 410 +++++++-------------------------
>  drivers/net/tap/tap_flow.h      |  16 +-
>  drivers/net/tap/tap_rss.h       |  10 +-
>  drivers/net/tap/tap_tcmsgs.h    |   4 +-
>  8 files changed, 127 insertions(+), 367 deletions(-)
> 
> diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
> index f2c03a19fd..3f3c4e6602 100644
> --- a/drivers/net/tap/bpf/meson.build
> +++ b/drivers/net/tap/bpf/meson.build
> @@ -3,15 +3,24 @@
>  
>  enable_tap_rss = false
>  
> +# Loading BPF requires libbpf
>  libbpf = dependency('libbpf', required: false, method: 'pkg-config')
>  if not libbpf.found()
>      message('net/tap: no RSS support missing libbpf')
>      subdir_done()
>  endif
>  
> +# Making skeleton needs bpftool
>  # Debian install this in /usr/sbin which is not in $PATH
> -bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
> -if not bpftool.found()
> +bpftool_supports_skel = false
> +bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
> +if bpftool.found()
> +    # Some Ubuntu has non-functional bpftool
> +    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
> +                                        check:false).returncode() == 0
> +endif

Using bpftool to generate the header at build time is a bit icky,
because it will look at sysfs on the build system, which is from the
running kernel. But a build system's kernel might be some ancient LTS,
and even be a completely different kconfig/build/distro from the actual
runtime one.

We have ran in the same problem in systemd recently, and the solution
is to have distros publish the vmlinux.h together with the kernel
image/headers, that way we can rely on the fact that by build-depending
on the right kernel package we get exactly the generated vmlinux.h that
we want. This has already happened in Centos, Debian, Fedora and Arch,
and I am trying to get Ubuntu onboard too.

The annoying thing is that every distro packages differently, so the
path needs to be configurable with a meson option.

Feel free to pilfer the systemd meson glue:

https://github.com/systemd/systemd/pull/26826/commits/d917079e7e320aa281fc4ad6f8073b0814b9cb13

It's of course file to go to the runtime kernel if no vmlinux.h is
specified, as a fallback, which is going to be useful for developers
machines.
  
Stephen Hemminger April 3, 2024, 2:53 p.m. UTC | #2
On Wed, 03 Apr 2024 12:50:35 +0100
Luca Boccassi <bluca@debian.org> wrote:

> On Tue, 2024-04-02 at 10:12 -0700, Stephen Hemminger wrote:
> > There were multiple issues in the RSS queue support in the TAP
> > driver. This required extensive rework of the BPF support.
> > 
> > Change the BPF loading to use bpftool to
> > create a skeleton header file, and load with libbpf.
> > The BPF is always compiled from source so less chance that
> > source and instructions diverge. Also resolves issue where
> > libbpf and source get out of sync. The program
> > is only loaded once, so if multiple rules are created
> > only one BPF program is loaded in kernel.
> > 
> > The new BPF program only needs a single action.
> > No need for action and re-classification step.
> > 
> > It alsow fixes the missing bits from the original.
> >     - supports setting RSS key per flow
> >     - level of hash can be L3 or L3/L4.
> > 
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> > ---
> >  drivers/net/tap/bpf/meson.build |  14 +-
> >  drivers/net/tap/meson.build     |  29 +--
> >  drivers/net/tap/rte_eth_tap.c   |   2 +
> >  drivers/net/tap/rte_eth_tap.h   |   9 +-
> >  drivers/net/tap/tap_flow.c      | 410 +++++++-------------------------
> >  drivers/net/tap/tap_flow.h      |  16 +-
> >  drivers/net/tap/tap_rss.h       |  10 +-
> >  drivers/net/tap/tap_tcmsgs.h    |   4 +-
> >  8 files changed, 127 insertions(+), 367 deletions(-)
> > 
> > diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
> > index f2c03a19fd..3f3c4e6602 100644
> > --- a/drivers/net/tap/bpf/meson.build
> > +++ b/drivers/net/tap/bpf/meson.build
> > @@ -3,15 +3,24 @@
> >  
> >  enable_tap_rss = false
> >  
> > +# Loading BPF requires libbpf
> >  libbpf = dependency('libbpf', required: false, method: 'pkg-config')
> >  if not libbpf.found()
> >      message('net/tap: no RSS support missing libbpf')
> >      subdir_done()
> >  endif
> >  
> > +# Making skeleton needs bpftool
> >  # Debian install this in /usr/sbin which is not in $PATH
> > -bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
> > -if not bpftool.found()
> > +bpftool_supports_skel = false
> > +bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
> > +if bpftool.found()
> > +    # Some Ubuntu has non-functional bpftool
> > +    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
> > +                                        check:false).returncode() == 0
> > +endif  
> 
> Using bpftool to generate the header at build time is a bit icky,
> because it will look at sysfs on the build system, which is from the
> running kernel. But a build system's kernel might be some ancient LTS,
> and even be a completely different kconfig/build/distro from the actual
> runtime one.

I wish there was a better way to get bpf compiled to an array to load.
The other alternative is to embed the object but then the ickiness of decoding
ELF headers ends up in the driver.

This method seems to be the BPF way now.

> 
> We have ran in the same problem in systemd recently, and the solution
> is to have distros publish the vmlinux.h together with the kernel
> image/headers, that way we can rely on the fact that by build-depending
> on the right kernel package we get exactly the generated vmlinux.h that
> we want. This has already happened in Centos, Debian, Fedora and Arch,
> and I am trying to get Ubuntu onboard too.

Not sure how much it matters for the TAP BPF bits. Unlike other kernel BPF
this program only really depends on layout of skb, and is not using system
call hooks. So vmlinux.h is not referenced directly.  But if layout of skb
changes, then things would break.


> The annoying thing is that every distro packages differently, so the
> path needs to be configurable with a meson option.
> 
> Feel free to pilfer the systemd meson glue:
> 
> https://github.com/systemd/systemd/pull/26826/commits/d917079e7e320aa281fc4ad6f8073b0814b9cb13
> 
> It's of course file to go to the runtime kernel if no vmlinux.h is
> specified, as a fallback, which is going to be useful for developers
> machines.
>
  
Stephen Hemminger April 3, 2024, 3:55 p.m. UTC | #3
On Wed, 03 Apr 2024 12:50:35 +0100
Luca Boccassi <bluca@debian.org> wrote:

> Using bpftool to generate the header at build time is a bit icky,
> because it will look at sysfs on the build system, which is from the
> running kernel. But a build system's kernel might be some ancient LTS,
> and even be a completely different kconfig/build/distro from the actual
> runtime one.

One other option would be to ship a pre-built skeleton file.
Which is what the method the old code did.
But that creates an implied dependency on the developers machine build environment.
  
Luca Boccassi April 3, 2024, 9:19 p.m. UTC | #4
On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Wed, 03 Apr 2024 12:50:35 +0100
> Luca Boccassi <bluca@debian.org> wrote:
>
> > Using bpftool to generate the header at build time is a bit icky,
> > because it will look at sysfs on the build system, which is from the
> > running kernel. But a build system's kernel might be some ancient LTS,
> > and even be a completely different kconfig/build/distro from the actual
> > runtime one.
>
> One other option would be to ship a pre-built skeleton file.
> Which is what the method the old code did.
> But that creates an implied dependency on the developers machine build environment.

That's what the distro-provided vmlinux.h should help with - by
#include'ing that, it should be possible to build a co-re bpf program,
no other artifacts needed. You can try it out locally by generating it
from the local running kernel on your dev machine:

bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
  
Stephen Hemminger April 3, 2024, 11:41 p.m. UTC | #5
On Wed, 3 Apr 2024 22:19:20 +0100
Luca Boccassi <bluca@debian.org> wrote:

> On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > On Wed, 03 Apr 2024 12:50:35 +0100
> > Luca Boccassi <bluca@debian.org> wrote:
> >  
> > > Using bpftool to generate the header at build time is a bit icky,
> > > because it will look at sysfs on the build system, which is from the
> > > running kernel. But a build system's kernel might be some ancient LTS,
> > > and even be a completely different kconfig/build/distro from the actual
> > > runtime one.  
> >
> > One other option would be to ship a pre-built skeleton file.
> > Which is what the method the old code did.
> > But that creates an implied dependency on the developers machine build environment.  
> 
> That's what the distro-provided vmlinux.h should help with - by
> #include'ing that, it should be possible to build a co-re bpf program,
> no other artifacts needed. You can try it out locally by generating it
> from the local running kernel on your dev machine:
> 
> bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

Not all distros are providing vmlinux.h.
And some like Ubuntu haven't figured out how to package bpftool and libbpf correctly.
  
Luca Boccassi April 4, 2024, 12:49 a.m. UTC | #6
On Thu, 4 Apr 2024 at 00:41, Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Wed, 3 Apr 2024 22:19:20 +0100
> Luca Boccassi <bluca@debian.org> wrote:
>
> > On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> > <stephen@networkplumber.org> wrote:
> > >
> > > On Wed, 03 Apr 2024 12:50:35 +0100
> > > Luca Boccassi <bluca@debian.org> wrote:
> > >
> > > > Using bpftool to generate the header at build time is a bit icky,
> > > > because it will look at sysfs on the build system, which is from the
> > > > running kernel. But a build system's kernel might be some ancient LTS,
> > > > and even be a completely different kconfig/build/distro from the actual
> > > > runtime one.
> > >
> > > One other option would be to ship a pre-built skeleton file.
> > > Which is what the method the old code did.
> > > But that creates an implied dependency on the developers machine build environment.
> >
> > That's what the distro-provided vmlinux.h should help with - by
> > #include'ing that, it should be possible to build a co-re bpf program,
> > no other artifacts needed. You can try it out locally by generating it
> > from the local running kernel on your dev machine:
> >
> > bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
>
> Not all distros are providing vmlinux.h.
> And some like Ubuntu haven't figured out how to package bpftool and libbpf correctly.

Yes and for those the usual pattern is a fallback to generate at build
time, if no pre-prepared vmlinux.h is configured
  
Stephen Hemminger April 4, 2024, 3:30 p.m. UTC | #7
On Wed, 3 Apr 2024 22:19:20 +0100
Luca Boccassi <bluca@debian.org> wrote:

> On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > On Wed, 03 Apr 2024 12:50:35 +0100
> > Luca Boccassi <bluca@debian.org> wrote:
> >  
> > > Using bpftool to generate the header at build time is a bit icky,
> > > because it will look at sysfs on the build system, which is from the
> > > running kernel. But a build system's kernel might be some ancient LTS,
> > > and even be a completely different kconfig/build/distro from the actual
> > > runtime one.  
> >
> > One other option would be to ship a pre-built skeleton file.
> > Which is what the method the old code did.
> > But that creates an implied dependency on the developers machine build environment.  
> 
> That's what the distro-provided vmlinux.h should help with - by
> #include'ing that, it should be possible to build a co-re bpf program,
> no other artifacts needed. You can try it out locally by generating it
> from the local running kernel on your dev machine:
> 
> bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

What about Ubuntu with borked installation of bpftool?
  
Stephen Hemminger April 4, 2024, 3:51 p.m. UTC | #8
On Thu, 4 Apr 2024 01:49:56 +0100
Luca Boccassi <bluca@debian.org> wrote:

> On Thu, 4 Apr 2024 at 00:41, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > On Wed, 3 Apr 2024 22:19:20 +0100
> > Luca Boccassi <bluca@debian.org> wrote:
> >  
> > > On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> > > <stephen@networkplumber.org> wrote:  
> > > >
> > > > On Wed, 03 Apr 2024 12:50:35 +0100
> > > > Luca Boccassi <bluca@debian.org> wrote:
> > > >  
> > > > > Using bpftool to generate the header at build time is a bit icky,
> > > > > because it will look at sysfs on the build system, which is from the
> > > > > running kernel. But a build system's kernel might be some ancient LTS,
> > > > > and even be a completely different kconfig/build/distro from the actual
> > > > > runtime one.  
> > > >
> > > > One other option would be to ship a pre-built skeleton file.
> > > > Which is what the method the old code did.
> > > > But that creates an implied dependency on the developers machine build environment.  
> > >
> > > That's what the distro-provided vmlinux.h should help with - by
> > > #include'ing that, it should be possible to build a co-re bpf program,
> > > no other artifacts needed. You can try it out locally by generating it
> > > from the local running kernel on your dev machine:
> > >
> > > bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h  
> >
> > Not all distros are providing vmlinux.h.
> > And some like Ubuntu haven't figured out how to package bpftool and libbpf correctly.  
> 
> Yes and for those the usual pattern is a fallback to generate at build
> time, if no pre-prepared vmlinux.h is configured

Looks like vmlinux.h is not setup to handle tc programs.

If vmlinux.h is included, it supersedes other kernel headers (ok).
But is missing some other things like IPv6 options, ether types, and
TC actions. To use it requires copy  pasting from other headers
to fill in the missing pieces. Thats a mess.

This little program only refers to skb and the fields that are problematic
are protocol, mark, and queue_mapping.
  
Luca Boccassi April 4, 2024, 4:11 p.m. UTC | #9
On Thu, 4 Apr 2024 at 16:31, Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Wed, 3 Apr 2024 22:19:20 +0100
> Luca Boccassi <bluca@debian.org> wrote:
>
> > On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> > <stephen@networkplumber.org> wrote:
> > >
> > > On Wed, 03 Apr 2024 12:50:35 +0100
> > > Luca Boccassi <bluca@debian.org> wrote:
> > >
> > > > Using bpftool to generate the header at build time is a bit icky,
> > > > because it will look at sysfs on the build system, which is from the
> > > > running kernel. But a build system's kernel might be some ancient LTS,
> > > > and even be a completely different kconfig/build/distro from the actual
> > > > runtime one.
> > >
> > > One other option would be to ship a pre-built skeleton file.
> > > Which is what the method the old code did.
> > > But that creates an implied dependency on the developers machine build environment.
> >
> > That's what the distro-provided vmlinux.h should help with - by
> > #include'ing that, it should be possible to build a co-re bpf program,
> > no other artifacts needed. You can try it out locally by generating it
> > from the local running kernel on your dev machine:
> >
> > bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
>
> What about Ubuntu with borked installation of bpftool?

Yeah that's a bit confusing, the way to do it is to install
linux-tools-generic and then here's logic to find the right one:

https://git.launchpad.net/ubuntu/+source/xdp-tools/tree/debian/rules#n34

But I wouldn't bother with it in upstream projects, let the
integrators deal with it
  
Luca Boccassi April 4, 2024, 4:12 p.m. UTC | #10
On Thu, 4 Apr 2024 at 16:51, Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Thu, 4 Apr 2024 01:49:56 +0100
> Luca Boccassi <bluca@debian.org> wrote:
>
> > On Thu, 4 Apr 2024 at 00:41, Stephen Hemminger
> > <stephen@networkplumber.org> wrote:
> > >
> > > On Wed, 3 Apr 2024 22:19:20 +0100
> > > Luca Boccassi <bluca@debian.org> wrote:
> > >
> > > > On Wed, 3 Apr 2024 at 16:55, Stephen Hemminger
> > > > <stephen@networkplumber.org> wrote:
> > > > >
> > > > > On Wed, 03 Apr 2024 12:50:35 +0100
> > > > > Luca Boccassi <bluca@debian.org> wrote:
> > > > >
> > > > > > Using bpftool to generate the header at build time is a bit icky,
> > > > > > because it will look at sysfs on the build system, which is from the
> > > > > > running kernel. But a build system's kernel might be some ancient LTS,
> > > > > > and even be a completely different kconfig/build/distro from the actual
> > > > > > runtime one.
> > > > >
> > > > > One other option would be to ship a pre-built skeleton file.
> > > > > Which is what the method the old code did.
> > > > > But that creates an implied dependency on the developers machine build environment.
> > > >
> > > > That's what the distro-provided vmlinux.h should help with - by
> > > > #include'ing that, it should be possible to build a co-re bpf program,
> > > > no other artifacts needed. You can try it out locally by generating it
> > > > from the local running kernel on your dev machine:
> > > >
> > > > bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
> > >
> > > Not all distros are providing vmlinux.h.
> > > And some like Ubuntu haven't figured out how to package bpftool and libbpf correctly.
> >
> > Yes and for those the usual pattern is a fallback to generate at build
> > time, if no pre-prepared vmlinux.h is configured
>
> Looks like vmlinux.h is not setup to handle tc programs.
>
> If vmlinux.h is included, it supersedes other kernel headers (ok).
> But is missing some other things like IPv6 options, ether types, and
> TC actions. To use it requires copy  pasting from other headers
> to fill in the missing pieces. Thats a mess.
>
> This little program only refers to skb and the fields that are problematic
> are protocol, mark, and queue_mapping.

That's not good, could you please report that to the BPF folks? Pretty
sure it should get fixed in bpftool?
  

Patch

diff --git a/drivers/net/tap/bpf/meson.build b/drivers/net/tap/bpf/meson.build
index f2c03a19fd..3f3c4e6602 100644
--- a/drivers/net/tap/bpf/meson.build
+++ b/drivers/net/tap/bpf/meson.build
@@ -3,15 +3,24 @@ 
 
 enable_tap_rss = false
 
+# Loading BPF requires libbpf
 libbpf = dependency('libbpf', required: false, method: 'pkg-config')
 if not libbpf.found()
     message('net/tap: no RSS support missing libbpf')
     subdir_done()
 endif
 
+# Making skeleton needs bpftool
 # Debian install this in /usr/sbin which is not in $PATH
-bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false, version: '>= 5.6.0')
-if not bpftool.found()
+bpftool_supports_skel = false
+bpftool = find_program('bpftool', '/usr/sbin/bpftool', required: false)
+if bpftool.found()
+    # Some Ubuntu has non-functional bpftool
+    bpftool_supports_skel = run_command(bpftool, 'gen', 'help',
+                                        check:false).returncode() == 0
+endif
+
+if not bpftool_supports_skel
     message('net/tap: no RSS support missing bpftool')
     subdir_done()
 endif
@@ -42,6 +51,7 @@  clang_flags = [
     '-O2',
     '-Wall',
     '-Wextra',
+    max_queues,
     '-target',
     'bpf',
     '-g',
diff --git a/drivers/net/tap/meson.build b/drivers/net/tap/meson.build
index 9cd124d53e..46ffd35beb 100644
--- a/drivers/net/tap/meson.build
+++ b/drivers/net/tap/meson.build
@@ -7,33 +7,22 @@  if not is_linux
 endif
 sources = files(
         'rte_eth_tap.c',
-        'tap_bpf_api.c',
         'tap_flow.c',
         'tap_intr.c',
         'tap_netlink.c',
         'tap_tcmsgs.c',
 )
 
-deps = ['bus_vdev', 'gso', 'hash']
+max_queues = '-DTAP_MAX_QUEUES=16'
+cflags += max_queues
 
-cflags += '-DTAP_MAX_QUEUES=8'
+subdir('bpf')
+if enable_tap_rss
+    cflags += '-DHAVE_BPF_RSS'
+    ext_deps += libbpf
+    sources += tap_rss_skel_h
+endif
 
-# input array for meson symbol search:
-# [ "MACRO to define if found", "header for the search",
-#   "enum/define", "symbol to search" ]
-#
-args = [
-        [ 'HAVE_TC_FLOWER', 'linux/pkt_cls.h', 'TCA_FLOWER_UNSPEC' ],
-        [ 'HAVE_TC_VLAN_ID', 'linux/pkt_cls.h', 'TCA_FLOWER_KEY_VLAN_PRIO' ],
-        [ 'HAVE_TC_BPF', 'linux/pkt_cls.h', 'TCA_BPF_UNSPEC' ],
-        [ 'HAVE_TC_BPF_FD', 'linux/pkt_cls.h', 'TCA_BPF_FD' ],
-        [ 'HAVE_TC_ACT_BPF', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_UNSPEC' ],
-        [ 'HAVE_TC_ACT_BPF_FD', 'linux/tc_act/tc_bpf.h', 'TCA_ACT_BPF_FD' ],
-]
-config = configuration_data()
-foreach arg:args
-    config.set(arg[0], cc.has_header_symbol(arg[1], arg[2]))
-endforeach
-configure_file(output : 'tap_autoconf.h', configuration : config)
+deps = ['bus_vdev', 'gso', 'hash']
 
 require_iova_in_mbuf = false
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 38a1b2d825..b76c5bf527 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -1129,6 +1129,7 @@  tap_dev_close(struct rte_eth_dev *dev)
 		tap_flow_implicit_flush(internals, NULL);
 		tap_nl_final(internals->nlsk_fd);
 		internals->nlsk_fd = -1;
+		tap_flow_bpf_destroy(internals);
 	}
 
 	for (i = 0; i < RTE_PMD_TAP_MAX_QUEUES; i++) {
@@ -1941,6 +1942,7 @@  eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	strlcpy(pmd->name, tap_name, sizeof(pmd->name));
 	pmd->type = type;
 	pmd->ka_fd = -1;
+	pmd->rss = NULL;
 	pmd->nlsk_fd = -1;
 	pmd->gso_ctx_mp = NULL;
 
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index dc8201020b..4e9ca6d826 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -79,12 +79,11 @@  struct pmd_internals {
 	int flow_isolate;                 /* 1 if flow isolation is enabled */
 	int flower_support;               /* 1 if kernel supports, else 0 */
 	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
-	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
 	int persist;			  /* 1 if keep link up, else 0 */
-	/* implicit rules set when RSS is enabled */
-	int map_fd;                       /* BPF RSS map fd */
-	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */
-	LIST_HEAD(tap_rss_flows, rte_flow) rss_flows;
+
+	struct tap_rss *rss;		  /* BPF program */
+	uint16_t bpf_flowid;		  /* next BPF class id */
+
 	LIST_HEAD(tap_flows, rte_flow) flows;        /* rte_flow rules */
 	/* implicit rte_flow rules set when a remote device is active */
 	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index e154ea0ae0..77dc8e9741 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -15,26 +15,19 @@ 
 #include <rte_random.h>
 #include <rte_malloc.h>
 #include <rte_eth_tap.h>
+#include <rte_uuid.h>
 
 #include <tap_flow.h>
-#include <tap_autoconf.h>
 #include <tap_tcmsgs.h>
 #include <tap_rss.h>
 
-
-/* RSS key management */
-enum bpf_rss_key_e {
-	KEY_CMD_GET = 1,
-	KEY_CMD_RELEASE,
-	KEY_CMD_INIT,
-	KEY_CMD_DEINIT,
-};
-
-enum key_status_e {
-	KEY_STAT_UNSPEC,
-	KEY_STAT_USED,
-	KEY_STAT_AVAILABLE,
-};
+#ifdef HAVE_BPF_RSS
+/* Workaround for warning in bpftool generated skeleton code */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#include "tap_rss.skel.h"
+#pragma GCC diagnostic pop
+#endif
 
 #define ISOLATE_HANDLE 1
 #define REMOTE_PROMISCUOUS_HANDLE 2
@@ -42,8 +35,6 @@  enum key_status_e {
 struct rte_flow {
 	LIST_ENTRY(rte_flow) next; /* Pointer to the next rte_flow structure */
 	struct rte_flow *remote_flow; /* associated remote flow */
-	int bpf_fd[SEC_MAX]; /* list of bfs fds per ELF section */
-	uint32_t key_idx; /* RSS rule key index into BPF map */
 	struct nlmsg msg;
 };
 
@@ -70,9 +61,11 @@  struct action_data {
 		struct skbedit {
 			struct tc_skbedit skbedit;
 			uint16_t queue;
+			uint32_t mark;
 		} skbedit;
 		struct bpf {
 			struct tc_act_bpf bpf;
+			uint32_t map_key;
 			int bpf_fd;
 			const char *annotation;
 		} bpf;
@@ -113,13 +106,12 @@  tap_flow_isolate(struct rte_eth_dev *dev,
 		 int set,
 		 struct rte_flow_error *error);
 
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx);
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error);
+#ifdef HAVE_BPF_RSS
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error);
 static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			const struct rte_flow_action_rss *rss,
 			struct rte_flow_error *error);
+#endif
 
 static const struct rte_flow_ops tap_flow_ops = {
 	.validate = tap_flow_validate,
@@ -854,10 +846,11 @@  add_action(struct rte_flow *flow, size_t *act_index, struct action_data *adata)
 			   &adata->mirred);
 	} else if (strcmp("skbedit", adata->id) == 0) {
 		tap_nlattr_add(&msg->nh, TCA_SKBEDIT_PARMS,
-			   sizeof(adata->skbedit.skbedit),
-			   &adata->skbedit.skbedit);
-		tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING,
-			     adata->skbedit.queue);
+			   sizeof(adata->skbedit.skbedit), &adata->skbedit.skbedit);
+		if (adata->skbedit.mark)
+			tap_nlattr_add32(&msg->nh, TCA_SKBEDIT_MARK, adata->skbedit.mark);
+		else
+			tap_nlattr_add16(&msg->nh, TCA_SKBEDIT_QUEUE_MAPPING, adata->skbedit.queue);
 	} else if (strcmp("bpf", adata->id) == 0) {
 		tap_nlattr_add32(&msg->nh, TCA_ACT_BPF_FD, adata->bpf.bpf_fd);
 		tap_nlattr_add(&msg->nh, TCA_ACT_BPF_NAME,
@@ -1105,8 +1098,7 @@  priv_flow_process(struct pmd_internals *pmd,
 					},
 				};
 
-				err = add_actions(flow, 1, &adata,
-						  TCA_FLOWER_ACT);
+				err = add_actions(flow, 1, &adata, TCA_FLOWER_ACT);
 			}
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
 			const struct rte_flow_action_queue *queue =
@@ -1136,6 +1128,7 @@  priv_flow_process(struct pmd_internals *pmd,
 				err = add_actions(flow, 1, &adata,
 					TCA_FLOWER_ACT);
 			}
+#ifdef HAVE_BPF_RSS
 		} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
 			const struct rte_flow_action_rss *rss =
 				(const struct rte_flow_action_rss *)
@@ -1144,13 +1137,14 @@  priv_flow_process(struct pmd_internals *pmd,
 			if (action++)
 				goto exit_action_not_supported;
 
-			if (!pmd->rss_enabled) {
-				err = rss_enable(pmd, attr, error);
+			if (pmd->rss == NULL) {
+				err = rss_enable(pmd, error);
 				if (err)
 					goto exit_return_error;
 			}
 			if (flow)
 				err = rss_add_actions(flow, pmd, rss, error);
+#endif
 		} else {
 			goto exit_action_not_supported;
 		}
@@ -1247,26 +1241,17 @@  tap_flow_set_handle(struct rte_flow *flow)
  *
  */
 static void
-tap_flow_free(struct pmd_internals *pmd, struct rte_flow *flow)
+tap_flow_free(struct pmd_internals *pmd __rte_unused, struct rte_flow *flow)
 {
-	int i;
-
 	if (!flow)
 		return;
 
-	if (pmd->rss_enabled) {
-		/* Close flow BPF file descriptors */
-		for (i = 0; i < SEC_MAX; i++)
-			if (flow->bpf_fd[i] != 0) {
-				close(flow->bpf_fd[i]);
-				flow->bpf_fd[i] = 0;
-			}
-
-		/* Release the map key for this RSS rule */
-		bpf_rss_key(KEY_CMD_RELEASE, &flow->key_idx);
-		flow->key_idx = 0;
-	}
-
+#ifdef HAVE_BPF_RSS
+	struct tap_rss *rss = pmd->rss;
+	if (rss)
+		bpf_map__delete_elem(rss->maps.rss_map,
+				     &flow->msg.t.tcm_handle, sizeof(uint32_t), 0);
+#endif
 	/* Free flow allocated memory */
 	rte_free(flow);
 }
@@ -1734,14 +1719,18 @@  tap_flow_implicit_flush(struct pmd_internals *pmd, struct rte_flow_error *error)
 	return 0;
 }
 
-#define MAX_RSS_KEYS 256
-#define KEY_IDX_OFFSET (3 * MAX_RSS_KEYS)
-#define SEC_NAME_CLS_Q "cls_q"
-
-static const char *sec_name[SEC_MAX] = {
-	[SEC_L3_L4] = "l3_l4",
-};
+/**
+ * Cleanup when device is closed
+ */
+void tap_flow_bpf_destroy(struct pmd_internals *pmd __rte_unused)
+{
+#ifdef HAVE_BPF_RSS
+	tap_rss__destroy(pmd->rss);
+	pmd->rss = NULL;
+#endif
+}
 
+#ifdef HAVE_BPF_RSS
 /**
  * Enable RSS on tap: create TC rules for queuing.
  *
@@ -1756,226 +1745,32 @@  static const char *sec_name[SEC_MAX] = {
  *
  * @return 0 on success, negative value on failure.
  */
-static int rss_enable(struct pmd_internals *pmd,
-			const struct rte_flow_attr *attr,
-			struct rte_flow_error *error)
+static int rss_enable(struct pmd_internals *pmd, struct rte_flow_error *error)
 {
-	struct rte_flow *rss_flow = NULL;
-	struct nlmsg *msg = NULL;
-	/* 4096 is the maximum number of instructions for a BPF program */
-	char annotation[64];
-	int i;
-	int err = 0;
-
-	/* unlimit locked memory */
-	struct rlimit memlock_limit = {
-		.rlim_cur = RLIM_INFINITY,
-		.rlim_max = RLIM_INFINITY,
-	};
-	setrlimit(RLIMIT_MEMLOCK, &memlock_limit);
-
-	 /* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_INIT, NULL);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to initialize BPF RSS keys");
-
-		return -1;
-	}
-
-	/*
-	 *  Create BPF RSS MAP
-	 */
-	pmd->map_fd = tap_flow_bpf_rss_map_create(sizeof(__u32), /* key size */
-				sizeof(struct rss_key),
-				MAX_RSS_KEYS);
-	if (pmd->map_fd < 0) {
-		TAP_LOG(ERR,
-			"Failed to create BPF map (%d): %s",
-				errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF maps");
+	int err;
 
-		return -ENOTSUP;
+	/* Load the BPF program (defined in tap_bpf.h from skeleton) */
+	pmd->rss = tap_rss__open_and_load();
+	if (pmd->rss == NULL) {
+		TAP_LOG(ERR, "Failed to load BPF object: %s", strerror(errno));
+		rte_flow_error_set(error, errno, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be loaded");
+		return -errno;
 	}
 
-	/*
-	 * Add a rule per queue to match reclassified packets and direct them to
-	 * the correct queue.
-	 */
-	for (i = 0; i < pmd->dev->data->nb_rx_queues; i++) {
-		pmd->bpf_fd[i] = tap_flow_bpf_cls_q(i);
-		if (pmd->bpf_fd[i] < 0) {
-			TAP_LOG(ERR,
-				"Failed to load BPF section %s for queue %d",
-				SEC_NAME_CLS_Q, i);
-			rte_flow_error_set(
-				error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
-				NULL,
-				"Kernel too old or not configured "
-				"to support BPF programs loading");
-
-			return -ENOTSUP;
-		}
-
-		rss_flow = rte_zmalloc(__func__, sizeof(struct rte_flow), 0);
-		if (!rss_flow) {
-			TAP_LOG(ERR,
-				"Cannot allocate memory for rte_flow");
-			return -1;
-		}
-		msg = &rss_flow->msg;
-		tc_init_msg(msg, pmd->if_index, RTM_NEWTFILTER, NLM_F_REQUEST |
-			    NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
-		msg->t.tcm_info = TC_H_MAKE(0, htons(ETH_P_ALL));
-		tap_flow_set_handle(rss_flow);
-		uint16_t group = attr->group << GROUP_SHIFT;
-		uint16_t prio = group | (i + PRIORITY_OFFSET);
-		msg->t.tcm_info = TC_H_MAKE(prio << 16, msg->t.tcm_info);
-		msg->t.tcm_parent = TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0);
-
-		tap_nlattr_add(&msg->nh, TCA_KIND, sizeof("bpf"), "bpf");
-		if (tap_nlattr_nested_start(msg, TCA_OPTIONS) < 0)
-			return -1;
-		tap_nlattr_add32(&msg->nh, TCA_BPF_FD, pmd->bpf_fd[i]);
-		snprintf(annotation, sizeof(annotation), "[%s%d]",
-			SEC_NAME_CLS_Q, i);
-		tap_nlattr_add(&msg->nh, TCA_BPF_NAME, strlen(annotation) + 1,
-			   annotation);
-		/* Actions */
-		{
-			struct action_data adata = {
-				.id = "skbedit",
-				.skbedit = {
-					.skbedit = {
-						.action = TC_ACT_PIPE,
-					},
-					.queue = i,
-				},
-			};
-			if (add_actions(rss_flow, 1, &adata, TCA_BPF_ACT) < 0)
-				return -1;
-		}
-		tap_nlattr_nested_finish(msg); /* nested TCA_OPTIONS */
-
-		/* Netlink message is now ready to be sent */
-		if (tap_nl_send(pmd->nlsk_fd, &msg->nh) < 0)
-			return -1;
-		err = tap_nl_recv_ack(pmd->nlsk_fd);
-		if (err < 0) {
-			TAP_LOG(ERR,
-				"Kernel refused TC filter rule creation (%d): %s",
-				errno, strerror(errno));
-			return err;
-		}
-		LIST_INSERT_HEAD(&pmd->rss_flows, rss_flow, next);
-	}
-
-	pmd->rss_enabled = 1;
-	return err;
-}
-
-/**
- * Manage bpf RSS keys repository with operations: init, get, release
- *
- * @param[in] cmd
- *   Command on RSS keys: init, get, release
- *
- * @param[in, out] key_idx
- *   Pointer to RSS Key index (out for get command, in for release command)
- *
- * @return -1 if couldn't get, release or init the RSS keys, 0 otherwise.
- */
-static int bpf_rss_key(enum bpf_rss_key_e cmd, __u32 *key_idx)
-{
-	__u32 i;
-	int err = 0;
-	static __u32 num_used_keys;
-	static __u32 rss_keys[MAX_RSS_KEYS] = {KEY_STAT_UNSPEC};
-	static __u32 rss_keys_initialized;
-	__u32 key;
-
-	switch (cmd) {
-	case KEY_CMD_GET:
-		if (!rss_keys_initialized) {
-			err = -1;
-			break;
-		}
-
-		if (num_used_keys == RTE_DIM(rss_keys)) {
-			err = -1;
-			break;
-		}
-
-		*key_idx = num_used_keys % RTE_DIM(rss_keys);
-		while (rss_keys[*key_idx] == KEY_STAT_USED)
-			*key_idx = (*key_idx + 1) % RTE_DIM(rss_keys);
-
-		rss_keys[*key_idx] = KEY_STAT_USED;
-
-		/*
-		 * Add an offset to key_idx in order to handle a case of
-		 * RSS and non RSS flows mixture.
-		 * If a non RSS flow is destroyed it has an eBPF map
-		 * index 0 (initialized on flow creation) and might
-		 * unintentionally remove RSS entry 0 from eBPF map.
-		 * To avoid this issue, add an offset to the real index
-		 * during a KEY_CMD_GET operation and subtract this offset
-		 * during a KEY_CMD_RELEASE operation in order to restore
-		 * the real index.
-		 */
-		*key_idx += KEY_IDX_OFFSET;
-		num_used_keys++;
-	break;
-
-	case KEY_CMD_RELEASE:
-		if (!rss_keys_initialized)
-			break;
-
-		/*
-		 * Subtract offset to restore real key index
-		 * If a non RSS flow is falsely trying to release map
-		 * entry 0 - the offset subtraction will calculate the real
-		 * map index as an out-of-range value and the release operation
-		 * will be silently ignored.
-		 */
-		key = *key_idx - KEY_IDX_OFFSET;
-		if (key >= RTE_DIM(rss_keys))
-			break;
-
-		if (rss_keys[key] == KEY_STAT_USED) {
-			rss_keys[key] = KEY_STAT_AVAILABLE;
-			num_used_keys--;
-		}
-	break;
-
-	case KEY_CMD_INIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_AVAILABLE;
-
-		rss_keys_initialized = 1;
-		num_used_keys = 0;
-	break;
-
-	case KEY_CMD_DEINIT:
-		for (i = 0; i < RTE_DIM(rss_keys); i++)
-			rss_keys[i] = KEY_STAT_UNSPEC;
-
-		rss_keys_initialized = 0;
-		num_used_keys = 0;
-	break;
-
-	default:
-		break;
+	/* Attach the maps defined in BPF program */
+	err = tap_rss__attach(pmd->rss);
+	if (err < 0) {
+		TAP_LOG(ERR, "Failed to attach BPF object: %d", err);
+		rte_flow_error_set(error, -err, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+			"BPF object could not be attached");
+		tap_flow_bpf_destroy(pmd);
+		return err;
 	}
 
-	return err;
+	return 0;
 }
 
-
 /* Default RSS hash key also used by mlx devices */
 static const uint8_t rss_hash_default_key[] = {
 	0x2c, 0xc6, 0x81, 0xd1,
@@ -2008,9 +1803,11 @@  static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 			   const struct rte_flow_action_rss *rss,
 			   struct rte_flow_error *error)
 {
+	const struct bpf_program *rss_prog = pmd->rss->progs.rss_flow_action;
 	struct rss_key rss_entry = { };
 	const uint8_t *key_in;
 	uint32_t hash_type = 0;
+	uint32_t handle = flow->msg.t.tcm_handle;
 	unsigned int i;
 	int err;
 
@@ -2059,34 +1856,24 @@  static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 	else if (rss->types & (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_IPV6_EX))
 		hash_type |= RTE_BIT32(HASH_FIELD_IPV6_L3);
 
-	/* Get a new map key for a new RSS rule */
-	err = bpf_rss_key(KEY_CMD_GET, &flow->key_idx);
-	if (err < 0) {
-		rte_flow_error_set(
-			error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Failed to get BPF RSS key");
-
-		return -1;
-	}
+	rss_entry.hash_fields = hash_type;
+	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
+			    TAP_RSS_HASH_KEY_SIZE);
 
 	/* Update RSS map entry with queues */
 	rss_entry.nb_queues = rss->queue_num;
 	for (i = 0; i < rss->queue_num; i++)
 		rss_entry.queues[i] = rss->queue[i];
 
-	rss_entry.hash_fields = hash_type;
-	rte_convert_rss_key((const uint32_t *)key_in, (uint32_t *)rss_entry.key,
-			    TAP_RSS_HASH_KEY_SIZE);
-
-
-	/* Add this RSS entry to map */
-	err = tap_flow_bpf_update_rss_elem(pmd->map_fd,
-				&flow->key_idx, &rss_entry);
 
+	/* Add this way for BPF to find  entry in map */
+	err = bpf_map__update_elem(pmd->rss->maps.rss_map,
+				   &handle, sizeof(handle),
+				   &rss_entry, sizeof(rss_entry), 0);
 	if (err) {
 		TAP_LOG(ERR,
-			"Failed to update BPF map entry #%u (%d): %s",
-			flow->key_idx, errno, strerror(errno));
+			"Failed to update BPF map entry %#x (%d): %s",
+			handle,  errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"Kernel too old or not configured "
@@ -2095,47 +1882,28 @@  static int rss_add_actions(struct rte_flow *flow, struct pmd_internals *pmd,
 		return -ENOTSUP;
 	}
 
-
-	/*
-	 * Load bpf rules to calculate hash for this key_idx
-	 */
-
-	flow->bpf_fd[SEC_L3_L4] =
-		tap_flow_bpf_calc_l3_l4_hash(flow->key_idx, pmd->map_fd);
-	if (flow->bpf_fd[SEC_L3_L4] < 0) {
-		TAP_LOG(ERR,
-			"Failed to load BPF section %s (%d): %s",
-				sec_name[SEC_L3_L4], errno, strerror(errno));
-		rte_flow_error_set(
-			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
-			"Kernel too old or not configured "
-			"to support BPF program loading");
-
-		return -ENOTSUP;
-	}
-
-	/* Actions */
-	{
-		struct action_data adata[] = {
-			{
-				.id = "bpf",
-				.bpf = {
-					.bpf_fd = flow->bpf_fd[SEC_L3_L4],
-					.annotation = sec_name[SEC_L3_L4],
-					.bpf = {
-						.action = TC_ACT_PIPE,
-					},
-				},
+	/* Add actions to mark packet then run the RSS BPF program */
+	struct action_data adata[] = {
+		{
+			.id = "skbedit",
+			.skbedit = {
+				.skbedit.action = TC_ACT_PIPE,
+				.mark = handle,
 			},
-		};
-
-		if (add_actions(flow, RTE_DIM(adata), adata,
-			TCA_FLOWER_ACT) < 0)
-			return -1;
-	}
+		},
+		{
+			.id = "bpf",
+			.bpf = {
+				.bpf.action = TC_ACT_PIPE,
+				.annotation = "tap_rss",
+				.bpf_fd = bpf_program__fd(rss_prog),
+			},
+		},
+	};
 
-	return 0;
+	return add_actions(flow, RTE_DIM(adata), adata, TCA_FLOWER_ACT);
 }
+#endif
 
 /**
  * Get rte_flow operations.
diff --git a/drivers/net/tap/tap_flow.h b/drivers/net/tap/tap_flow.h
index 240fbc3dfa..bc54af28ca 100644
--- a/drivers/net/tap/tap_flow.h
+++ b/drivers/net/tap/tap_flow.h
@@ -9,7 +9,11 @@ 
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_eth_tap.h>
-#include <tap_autoconf.h>
+
+/**
+ * Mask of unsupported RSS types
+ */
+#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -41,10 +45,6 @@  enum implicit_rule_index {
 	TAP_REMOTE_MAX_IDX,
 };
 
-enum bpf_fd_idx {
-	SEC_L3_L4,
-	SEC_MAX,
-};
 
 int tap_dev_flow_ops_get(struct rte_eth_dev *dev,
 			 const struct rte_flow_ops **ops);
@@ -57,10 +57,6 @@  int tap_flow_implicit_destroy(struct pmd_internals *pmd,
 int tap_flow_implicit_flush(struct pmd_internals *pmd,
 			    struct rte_flow_error *error);
 
-int tap_flow_bpf_cls_q(__u32 queue_idx);
-int tap_flow_bpf_calc_l3_l4_hash(__u32 key_idx, int map_fd);
-int tap_flow_bpf_rss_map_create(unsigned int key_size, unsigned int value_size,
-			unsigned int max_entries);
-int tap_flow_bpf_update_rss_elem(int fd, void *key, void *value);
+void tap_flow_bpf_destroy(struct pmd_internals *pmd);
 
 #endif /* _TAP_FLOW_H_ */
diff --git a/drivers/net/tap/tap_rss.h b/drivers/net/tap/tap_rss.h
index 6009be7031..65bd8991b1 100644
--- a/drivers/net/tap/tap_rss.h
+++ b/drivers/net/tap/tap_rss.h
@@ -5,16 +5,14 @@ 
 #ifndef _TAP_RSS_H_
 #define _TAP_RSS_H_
 
-#ifndef TAP_MAX_QUEUES
-#define TAP_MAX_QUEUES 16
+/* Size of the map from BPF classid to queue table */
+#ifndef TAP_RSS_MAX
+#define TAP_RSS_MAX	32
 #endif
 
-/* Fixed RSS hash key size in bytes. */
+/* Standard Toeplitz hash key size */
 #define TAP_RSS_HASH_KEY_SIZE 40
 
-/* Supported RSS */
-#define TAP_RSS_HF_MASK (~(RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP))
-
 /* hashed fields for RSS */
 enum hash_field {
 	HASH_FIELD_IPV4_L3,	/* IPv4 src/dst addr */
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a64cb29d6f..00a0f22e31 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -6,7 +6,6 @@ 
 #ifndef _TAP_TCMSGS_H_
 #define _TAP_TCMSGS_H_
 
-#include <tap_autoconf.h>
 #include <linux/if_ether.h>
 #include <linux/rtnetlink.h>
 #include <linux/pkt_sched.h>
@@ -14,9 +13,8 @@ 
 #include <linux/tc_act/tc_mirred.h>
 #include <linux/tc_act/tc_gact.h>
 #include <linux/tc_act/tc_skbedit.h>
-#ifdef HAVE_TC_ACT_BPF
 #include <linux/tc_act/tc_bpf.h>
-#endif
+
 #include <inttypes.h>
 
 #include <rte_ether.h>