[PATCH bpf-next v4 0/3] bpf: bidirectional VLAN support for bpf_fib_lookup()
From: Avinash Duduskar
Date: Mon Jun 22 2026 - 22:52:19 EST
This series adds VLAN awareness to bpf_fib_lookup() in both directions.
BPF_FIB_LOOKUP_VLAN resolves a VLAN egress to its underlying real device
plus the VLAN tag (XDP programs need this because VLAN devices have no XDP
xmit), and BPF_FIB_LOOKUP_VLAN_INPUT runs the lookup as if a tagged frame
had arrived on the matching VLAN subinterface, for iif policy routing and
VRF table selection.
The independent l3mdev/VRF flow-init fix, patch 1 in v1 and v2, was split
out and merged to bpf separately.
v4 changes what bpf_fib_lookup() returns in one case. v3 left a VLAN
egress that cannot be reduced to a physical device plus one tag (a QinQ
egress, or a parent in another namespace) as best-effort SUCCESS with
the VLAN device's ifindex. In his v3 review Toke asked for a distinct
error code there instead, so an XDP program cannot mistake an unresolved
VLAN egress for a physical one, and suggested the name
BPF_FIB_LKUP_RET_VLAN_FAILURE; v4 implements that. The
code is appended after BPF_FIB_LKUP_RET_NO_SRC_ADDR (nothing renumbered,
tools/ mirror updated) and is returned only when BPF_FIB_LOOKUP_VLAN is
set, so no existing caller can observe it. On that failure params->ifindex
is left at the input, like the input-side failures; a tc or XDP program
that wants the VLAN device's own ifindex re-issues the lookup without the
flag, the recovery path he described.
The reason for a distinct code rather than best-effort SUCCESS: SUCCESS
on an unreducible egress silently blackholed XDP. A redirect to the VLAN
device drops at xdp_do_flush() with no in-band signal to the program;
VLAN_FAILURE makes the unreducible case explicit, and a live-frames
selftest exercises both the redirected and the passed paths. Only the
immediate parent is resolved, so QinQ and foreign-netns are the
unreducible cases; bond, team, TBID and VRF egress resolve, as the
selftest table pins.
Changes v3 -> v4:
- Patch 1: return BPF_FIB_LKUP_RET_VLAN_FAILURE for an unreducible VLAN
egress, leaving params->ifindex at the input.
- Patch 3: the QinQ-egress and cross-namespace-egress arms expect
VLAN_FAILURE; an escape-hatch arm re-issues without the flag for the
inner VLAN device's ifindex; and test_fib_lookup_vlan_redirect drives
live frames (BPF_F_TEST_XDP_LIVE_FRAMES) through the native redirect
path, asserting a reducible egress is delivered and a QinQ egress is
passed to the stack. The selftest's VLAN_FAILURE arms are IPv4 only,
since bpf_ipv6_fib_lookup() restores params->ifindex with the same code
as the IPv4 path that the arms exercise.
The three other v3 questions Toke marked fine as-is, and v4 keeps them: an
unmatched, down, or cross-namespace tag on input returns NOT_FWDED;
OUTPUT | VLAN_INPUT is rejected with -EINVAL; the BPF_FIB_LOOKUP_VLAN_INPUT
name is kept.
Taking the tag as lookup input follows the approach David Ahern suggested
in the 2021 fwmark discussion:
https://lore.kernel.org/bpf/6248c547-ad64-04d6-fcec-374893cc1ef2@xxxxxxxxx/
v3: https://lore.kernel.org/all/20260617224729.1428662-1-avinash.duduskar@xxxxxxxxx/
v2: https://lore.kernel.org/all/20260616223426.3568080-1-avinash.duduskar@xxxxxxxxx/
v1: https://lore.kernel.org/all/20260609172052.81613-1-avinash.duduskar@xxxxxxxxx/
Avinash Duduskar (3):
bpf: Add BPF_FIB_LOOKUP_VLAN flag to bpf_fib_lookup() helper
bpf: Add BPF_FIB_LOOKUP_VLAN_INPUT flag to bpf_fib_lookup() helper
selftests/bpf: Add bpf_fib_lookup() VLAN flag tests
include/uapi/linux/bpf.h | 47 +-
net/core/filter.c | 133 +++-
tools/include/uapi/linux/bpf.h | 47 +-
.../selftests/bpf/prog_tests/fib_lookup.c | 696 +++++++++++++++++-
.../testing/selftests/bpf/progs/fib_lookup.c | 36 +
5 files changed, 930 insertions(+), 29 deletions(-)
base-commit: a975094bf98ca97be9146f9d3b5681a6f9cf5ce3
--
2.54.0