diff mbox series

[net-next] netfilter: nf_flow_table_bpf: populate VLAN encap in XDP flowtable lookup

Message ID 20260924202543.1090535-1-adrianox@gmail.com
State New
Headers show
Series [net-next] netfilter: nf_flow_table_bpf: populate VLAN encap in XDP flowtable lookup | expand

Commit Message

Adriano Cordova Sept. 24, 2026, 8:25 p.m. UTC
encap[] is part of the flow_offload_tuple rhashtable key
(flow_offload_hash() hashes up to __hash), so a lookup has to fill it like
the skb path does.  bpf_xdp_flow_lookup() builds its key from struct
bpf_fib_lookup only, which has no encap fields, so it leaves encap[]
zeroed and can never match a flow whose tuple carries a VLAN encap.

Fill encap[0] from an in-band 802.1Q tag, mirroring the ETH_P_8021Q case
of nf_flow_tuple_encap().

Link: https://github.com/xdp-project/xdp-tools/issues/488
Signed-off-by: Adriano Cordova <adrianox@gmail.com>
---
 net/netfilter/nf_flow_table_bpf.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
diff mbox series

Patch

diff --git a/net/netfilter/nf_flow_table_bpf.c b/net/netfilter/nf_flow_table_bpf.c
index cbd5b97a6329..479f8242da2b 100644
--- a/net/netfilter/nf_flow_table_bpf.c
+++ b/net/netfilter/nf_flow_table_bpf.c
@@ -10,6 +10,7 @@ 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/if_vlan.h>
 #include <net/netfilter/nf_flow_table.h>
 #include <linux/bpf.h>
 #include <linux/btf.h>
@@ -60,6 +61,8 @@  bpf_xdp_flow_lookup(struct xdp_md *ctx, struct bpf_fib_lookup *fib_tuple,
 		    struct bpf_flowtable_opts *opts, u32 opts_len)
 {
 	struct xdp_buff *xdp = (struct xdp_buff *)ctx;
+	const struct ethhdr *eth = xdp->data;
+	const struct vlan_hdr *vh;
 	struct flow_offload_tuple tuple = {
 		.iifidx = fib_tuple->ifindex,
 		.l3proto = fib_tuple->family,
@@ -91,6 +94,18 @@  bpf_xdp_flow_lookup(struct xdp_md *ctx, struct bpf_fib_lookup *fib_tuple,
 		return NULL;
 	}
 
+	/* encap[] is part of the lookup key, fill it from the 802.1Q tag. */
+	if (eth + 1 <= (const struct ethhdr *)xdp->data_end &&
+	    eth->h_proto == htons(ETH_P_8021Q)) {
+		vh = (const struct vlan_hdr *)(eth + 1);
+		if (unlikely(vh + 1 > (const struct vlan_hdr *)xdp->data_end)) {
+			opts->error = -EINVAL;
+			return NULL;
+		}
+		tuple.encap[0].id = ntohs(vh->h_vlan_TCI);
+		tuple.encap[0].proto = htons(ETH_P_8021Q);
+	}
+
 	tuplehash = bpf_xdp_flow_tuple_lookup(xdp->rxq->dev, &tuple, proto);
 	if (IS_ERR(tuplehash)) {
 		opts->error = PTR_ERR(tuplehash);