This is a followup of the review of the teql arp-queue fix as reported by Sashiko. The issue: __bpf_redirect_neigh_v4() and __bpf_redirect_neigh_v6() install a dst for the redirect target only when the program lets the helper do the FIB lookup. With BPF_F_NEXTHOP the program supplies the nexthop, the lookup is skipped, and whatever dst the packet arrived with stays attached while bpf_out_neigh_v{4,6}() switch skb->dev to the target device. If that device's neighbour is incomplete the packet is parked on its arp_queue with the original route's dst; draining the queue re-looks the neighbour up from that dst and builds the frame with the original device's link-layer header, then transmits it on the target device. The Fix: drop the dst when the nexthop is supplied. That branch never consults the route dst, so nothing is lost, and the queue drain keeps the target device's parking neighbour. Conditions to recreate the bug: two network namespaces, A (10.10.0.1/24) and B (10.1.0.1/24) in one, their veth peers in the other with only A's peer addressed (10.10.0.2/24) so B's nexthop cannot be resolved by ARP. Resolve A's neighbour for 10.10.0.2 as permanent and attach a cls_bpf egress program to A, with vb the index of B: struct bpf_redir_neigh nh = { .nh_family = AF_INET, .ipv4_nh = htonl(0x0a010002) }; return bpf_redirect_neigh(vb, &nh, sizeof(nh), 0); Send one packet to 10.10.0.2. It is parked on B's incomplete neighbour for 10.1.0.2; once that neighbour becomes valid the frame leaves B carrying A's source address and A's neighbour as the destination. Reported-by: Sashiko (nipa) Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/QDISC-6HS9.v3.r0.20261103062649-2@mojatatu.com Link: https://lore.kernel.org/netdev/QDISC-6HS9.v3.r0.20261103062649-2@mojatatu.com/ Reviewed-by: Victor Nogueira Signed-off-by: Jamal Hadi Salim --- net/core/filter.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/core/filter.c b/net/core/filter.c index aca8160b26a1..2af24f371648 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -2318,6 +2318,8 @@ static int __bpf_redirect_neigh_v6(struct sk_buff *skb, struct net_device *dev, skb_dst_set(skb, dst); } else if (nh->nh_family != AF_INET6) { goto out_drop; + } else { + skb_dst_drop(skb); } err = bpf_out_neigh_v6(net, skb, dev, nh); @@ -2433,6 +2435,8 @@ static int __bpf_redirect_neigh_v4(struct sk_buff *skb, struct net_device *dev, skb_dst_drop(skb); skb_dst_set(skb, &rt->dst); + } else { + skb_dst_drop(skb); } err = bpf_out_neigh_v4(net, skb, dev, nh); -- 2.43.0