Network interface card installed in server motherboard with visible ports and components
Performance
William  

XDP Offload vs Native: Which Mode Runs on Your Hardware

XDP offload means the driver hands your eBPF program to the network card itself, so packets get dropped, redirected, or passed on the NIC before they ever touch host memory or the kernel's own XDP hook. The other two modes people call "xdp offload," native and generic, run XDP on your CPU. Confusing the two is why most offload debugging goes nowhere. Run ethtool -i for the driver and bpftool net for the real attach mode before you assume you have offload at all.

Last updated: 2026-07-21

What does XDP offload actually mean?

There are three XDP modes and only one is offload. The word gets thrown at all three, and that is the root of the confusion.

Generic mode, also called skb mode, attaches after the driver, up in the stack. Native mode runs inside the driver's receive path, on your CPU. The speed comes from where it sits, because XDP runs before allocation of the socket buffer for every packet. Offload mode is different in kind: your program runs on the NIC's own processor, and your CPU never sees the packet.

Here is the split, plainly:

ModeWhere the program runsUses your CPU?
Generic / skbAfter the driver, in the stackYes
Native / driverDriver RX pathYes
Offload / hwOn the NIC hardwareNo

To tell which one you have, run bpftool net. It prints the attach mode per interface as xdp, xdpgeneric, or xdpoffload. If it does not say offload, you do not have offload, whatever mode flag you passed.

Which NICs and drivers really support offload

Almost none of the cards you own. That is the honest answer nobody leads with.

True XDP offload has been a Netronome NFP thing for years. Those SmartNICs run your eBPF on the card's flow processor. It is the reference implementation everyone quotes, and it is not gear most people have in a rack.

Intel Ethernet drivers are what people mean when they search for this, and here is the catch: the common Intel drivers do native mode. Hardware offload is a separate capability they lack. Native XDP runs fast, but it runs on your CPU. So when a page promises "XDP offload on Intel Ethernet," check what it actually did with bpftool net. Nine times out of ten it attached in native mode and called that offload.

Why an offloaded program falls back or fails to load

Load an offloaded program and two things kill it: the verifier and the driver. Read dmesg right after the load fails and the kernel usually names which one.

The offload verifier is stricter than the normal one. Most BPF helpers are missing on the card, map types are limited, and program size is tighter. So a program that loads fine in native mode gets rejected for offload with a helper-not-supported message. That is not a bug. The hardware is telling you it cannot run that code.

The second failure is the driver capability check. If the driver has no offload callback, requesting hw mode fails outright. XDP will not silently downgrade offload to native unless you asked for an unspecified mode and let the loader pick. So if you left the mode open and ended up on the CPU, that is why. Pin the mode and the fallback stops hiding.

How xdp-loader attaches and multiplexes programs

xdp-loader is a utility for loading XDP programs, and it lives in the xdp-tools and libxdp project. Use it instead of raw ip link once you need more than one program on an interface.

The mode flag is -m, and it takes skb, native, hw, or unspecified. That is where you demand offload:

sudo xdp-loader load -m hw eth0 prog.o
sudo xdp-loader status

status tells you the truth. It lists every attached program and its real mode. If you asked for hw and status shows native, stop and read dmesg.

The reason to prefer libxdp is multiplexing. Raw XDP allows one program per interface. libxdp installs a dispatcher so several programs share the same hook in a defined order. Run a firewall and a monitor on one link and that is how they coexist without clobbering each other.

Can AF_XDP sockets talk across a veth pair?

Yes, AF_XDP works across a veth pair for intra-host communication, and it is a great way to test. Just understand there is no offload happening anywhere in that setup, because a veth device has no hardware to offload to.

A veth pair is two virtual interfaces wired back to back inside the kernel. Attach XDP to one end and open an AF_XDP socket, and packets sent into the peer come out the other side and hit your program. Intra-host traffic between two namespaces or containers moves this way fine.

What you exercise is the software path, with no NIC in the loop. So use veth to prove your loader, your maps, and your redirect logic. Do not benchmark offload on it, because there is nothing to offload. I keep experiments on veth exactly so a stray XDP_DROP never takes out my management link.

Why AF_XDP on veth behaves differently than a physical NIC

The veth driver runs XDP in generic mode, and that changes everything downstream. On a physical NIC, native XDP owns the RX ring and AF_XDP can go zero-copy. veth has no ring and no zero-copy fast path, so packets get copied and the acceleration you expect on hardware never shows up.

If AF_XDP on veth acts slower or odder than expected, that is why, and no config change will fix it. strace your loader and you will see the socket setup succeed while the XDP attach lands on the generic hook. Read the veth driver source and its XDP handling confirms the same generic-mode path.

Intra-host AF_XDP over veth is correct and useful for development. It is a functional test bed, good for correctness rather than throughput. Treat veth numbers as production numbers and you talk yourself into offload that was never running. For the real per-packet path, you want lower kernel overhead with eBPF on actual hardware.

Does hardware offload actually beat native mode?

Not the way the marketing implies. Native XDP already hits 10 to 40 million packets per second per core, and that number is why most people never need offload at all.

Offload's real win is freeing the CPU, not raw speed. When the NIC drops or redirects a packet, your cores do zero work for it. That matters when you absorb a flood and want your CPU for the application. But the card's processor is often slower per packet than a modern CPU core, and the program you can run on it is far more restricted.

So the trade is honest but narrow: offload buys CPU headroom for simple, high-volume drop and redirect. For anything with real logic, parsing, or big maps, native mode wins on speed and flexibility. Most workloads that think they want offload actually want native XDP with a couple more cores. If you are building DDoS protection with eBPF, native handles it long before offload becomes the bottleneck.

Is offload worth it for industrial edge or Intel ECI?

It is oversold for that use case, and the reason is technical. Determinism on an industrial edge box comes from the real-time kernel and the native XDP path, and offload has nothing to do with it.

Intel's Edge Controls for Industrial stack pairs a real-time kernel with native XDP. That combination gives you low, predictable per-packet latency because the packet decision happens in the driver before the stack, on a CPU tuned for real-time. The Intel NICs in that setup do native mode, so any pitch crediting determinism to offload has the mechanism wrong.

If your platform needs bounded latency, spend your effort on the real-time kernel, core isolation, and a tight native XDP program. Chasing hardware offload on cards that do not implement it just burns a week and leaves you back on native anyway.

How to debug an offload problem instead of guessing

Administrator viewing terminal output with kernel debugging information on multiple screens

Reproduce it, then read three things in order: the loader, the verifier, and the driver. Skip the top Stack Overflow answer, because it almost always assumes hardware you do not have.

strace -f the loader first. You will see the bpf() syscall that loads the program and the setsockopt or netlink call that attaches it. The exact syscall that fails, and its error, tells you whether the problem is load or attach. That one split saves an hour.

Next, read the full verifier log, not just the last line. If offload rejected a helper, the log names it, and now you know the program cannot run on the card as written. Finally, check the driver source for its ndo_bpf handler and the XDP_SETUP_PROG_HW case. If that case is missing, the driver has no offload, and no flag will conjure one. That is the answer from the source, and it beats guessing.

FAQ

How do I force native mode and refuse the silent fallback?

Attach with an explicit mode instead of leaving it open. With ip link use xdpdrv for native and xdpgeneric for skb mode; with xdp-loader pass -m native. If the driver cannot do native, the load fails loudly, which is exactly what you want. Leave the mode open and the kernel quietly picks generic while you sit there wondering where your speed went.

Does AF_XDP require XDP offload to be fast?

No. AF_XDP gets its zero-copy path from native driver support, not from hardware offload. A card with native XDP and AF_XDP zero-copy delivers user-space packets at high rates with your CPU still in the loop. Offload is a separate feature aimed at keeping the CPU out of the path entirely.

Can I run offload and native programs on the same interface?

Not usefully in the same hook. Offload runs on the card and native runs on the CPU, so they target different execution engines. libxdp multiplexes several programs within one software hook, but it will not span hardware and CPU for you. Pick one target per interface and design around it.

What kernel and tools do I need to inspect all this?

Any recent kernel with bpftool, ethtool, and the xdp-tools package covers it. Use ethtool -i for the driver name, bpftool net for the live attach mode, bpftool prog for loaded programs, and dmesg for the kernel's own explanation when a load fails. Those four answer most offload questions before you write a single line of C.

Related on this blog