Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next

Martin KaFai Lau says:

====================
pull-request: bpf-next 2026-04-01

We've added 2 non-merge commits during the last 2 day(s) which contain
a total of 3 files changed, 139 insertions(+), 23 deletions(-).

The main changes are:

1) skb_dst_drop(skb) when bpf prog does a encap or decap,
from Jakub Kicinski

* tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next:
selftests/bpf: Test that dst is cleared on same-protocol encap
net: Clear the dst when performing encap / decap
====================

Link: https://patch.msgid.link/20260401233956.4133413-1-martin.lau@linux.dev
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+139 -23
+27 -23
net/core/filter.c
··· 3256 3256 .arg1_type = ARG_PTR_TO_CTX, 3257 3257 }; 3258 3258 3259 - static void bpf_skb_change_protocol(struct sk_buff *skb, u16 proto) 3260 - { 3261 - skb->protocol = htons(proto); 3262 - if (skb_valid_dst(skb)) 3263 - skb_dst_drop(skb); 3264 - } 3265 - 3266 3259 static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len) 3267 3260 { 3268 3261 /* Caller already did skb_cow() with meta_len+len as headroom, ··· 3354 3361 shinfo->gso_type |= SKB_GSO_DODGY; 3355 3362 } 3356 3363 3357 - bpf_skb_change_protocol(skb, ETH_P_IPV6); 3364 + skb->protocol = htons(ETH_P_IPV6); 3358 3365 skb_clear_hash(skb); 3359 3366 3360 3367 return 0; ··· 3385 3392 shinfo->gso_type |= SKB_GSO_DODGY; 3386 3393 } 3387 3394 3388 - bpf_skb_change_protocol(skb, ETH_P_IP); 3395 + skb->protocol = htons(ETH_P_IP); 3389 3396 skb_clear_hash(skb); 3390 3397 3391 3398 return 0; ··· 3433 3440 */ 3434 3441 ret = bpf_skb_proto_xlat(skb, proto); 3435 3442 bpf_compute_data_pointers(skb); 3436 - return ret; 3443 + if (ret) 3444 + return ret; 3445 + 3446 + if (skb_valid_dst(skb)) 3447 + skb_dst_drop(skb); 3448 + 3449 + return 0; 3437 3450 } 3438 3451 3439 3452 static const struct bpf_func_proto bpf_skb_change_proto_proto = { ··· 3581 3582 } 3582 3583 3583 3584 /* Match skb->protocol to new outer l3 protocol */ 3584 - if (skb->protocol == htons(ETH_P_IP) && 3585 - flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV6) 3586 - bpf_skb_change_protocol(skb, ETH_P_IPV6); 3587 - else if (skb->protocol == htons(ETH_P_IPV6) && 3588 - flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV4) 3589 - bpf_skb_change_protocol(skb, ETH_P_IP); 3585 + if (flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV6) 3586 + skb->protocol = htons(ETH_P_IPV6); 3587 + else if (flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV4) 3588 + skb->protocol = htons(ETH_P_IP); 3589 + 3590 + if (skb_valid_dst(skb)) 3591 + skb_dst_drop(skb); 3590 3592 } 3591 3593 3592 3594 if (skb_is_gso(skb)) { ··· 3615 3615 static int bpf_skb_net_shrink(struct sk_buff *skb, u32 off, u32 len_diff, 3616 3616 u64 flags) 3617 3617 { 3618 + bool decap = flags & BPF_F_ADJ_ROOM_DECAP_L3_MASK; 3618 3619 int ret; 3619 3620 3620 3621 if (unlikely(flags & ~(BPF_F_ADJ_ROOM_FIXED_GSO | ··· 3638 3637 if (unlikely(ret < 0)) 3639 3638 return ret; 3640 3639 3641 - /* Match skb->protocol to new outer l3 protocol */ 3642 - if (skb->protocol == htons(ETH_P_IP) && 3643 - flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV6) 3644 - bpf_skb_change_protocol(skb, ETH_P_IPV6); 3645 - else if (skb->protocol == htons(ETH_P_IPV6) && 3646 - flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV4) 3647 - bpf_skb_change_protocol(skb, ETH_P_IP); 3640 + if (decap) { 3641 + /* Match skb->protocol to new outer l3 protocol */ 3642 + if (flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV6) 3643 + skb->protocol = htons(ETH_P_IPV6); 3644 + else if (flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV4) 3645 + skb->protocol = htons(ETH_P_IP); 3646 + 3647 + if (skb_valid_dst(skb)) 3648 + skb_dst_drop(skb); 3649 + } 3648 3650 3649 3651 if (skb_is_gso(skb)) { 3650 3652 struct skb_shared_info *shinfo = skb_shinfo(skb);
+55
tools/testing/selftests/bpf/prog_tests/test_dst_clear.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <sys/types.h> 5 + #include <sys/socket.h> 6 + #include <net/if.h> 7 + 8 + #include "test_progs.h" 9 + #include "network_helpers.h" 10 + #include "test_dst_clear.skel.h" 11 + 12 + #define IPV4_IFACE_ADDR "1.0.0.1" 13 + #define UDP_TEST_PORT 7777 14 + 15 + void test_ns_dst_clear(void) 16 + { 17 + LIBBPF_OPTS(bpf_tcx_opts, tcx_opts); 18 + struct test_dst_clear *skel; 19 + struct sockaddr_in addr; 20 + struct bpf_link *link; 21 + socklen_t addrlen; 22 + char buf[128] = {}; 23 + int sockfd, err; 24 + 25 + skel = test_dst_clear__open_and_load(); 26 + if (!ASSERT_OK_PTR(skel, "skel open_and_load")) 27 + return; 28 + 29 + SYS(fail, "ip addr add %s/8 dev lo", IPV4_IFACE_ADDR); 30 + 31 + link = bpf_program__attach_tcx(skel->progs.dst_clear, 32 + if_nametoindex("lo"), &tcx_opts); 33 + if (!ASSERT_OK_PTR(link, "attach_tcx")) 34 + goto fail; 35 + skel->links.dst_clear = link; 36 + 37 + addrlen = sizeof(addr); 38 + err = make_sockaddr(AF_INET, IPV4_IFACE_ADDR, UDP_TEST_PORT, 39 + (void *)&addr, &addrlen); 40 + if (!ASSERT_OK(err, "make_sockaddr")) 41 + goto fail; 42 + sockfd = socket(AF_INET, SOCK_DGRAM, 0); 43 + if (!ASSERT_NEQ(sockfd, -1, "socket")) 44 + goto fail; 45 + err = sendto(sockfd, buf, sizeof(buf), 0, (void *)&addr, addrlen); 46 + close(sockfd); 47 + if (!ASSERT_EQ(err, sizeof(buf), "send")) 48 + goto fail; 49 + 50 + ASSERT_TRUE(skel->bss->had_dst, "had_dst"); 51 + ASSERT_TRUE(skel->bss->dst_cleared, "dst_cleared"); 52 + 53 + fail: 54 + test_dst_clear__destroy(skel); 55 + }
+57
tools/testing/selftests/bpf/progs/test_dst_clear.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include "vmlinux.h" 5 + #include "bpf_tracing_net.h" 6 + #include <bpf/bpf_helpers.h> 7 + #include <bpf/bpf_endian.h> 8 + 9 + #define UDP_TEST_PORT 7777 10 + 11 + void *bpf_cast_to_kern_ctx(void *) __ksym; 12 + 13 + bool had_dst = false; 14 + bool dst_cleared = false; 15 + 16 + SEC("tc/egress") 17 + int dst_clear(struct __sk_buff *skb) 18 + { 19 + struct sk_buff *kskb; 20 + struct iphdr iph; 21 + struct udphdr udph; 22 + int err; 23 + 24 + if (skb->protocol != __bpf_constant_htons(ETH_P_IP)) 25 + return TC_ACT_OK; 26 + 27 + if (bpf_skb_load_bytes(skb, ETH_HLEN, &iph, sizeof(iph))) 28 + return TC_ACT_OK; 29 + 30 + if (iph.protocol != IPPROTO_UDP) 31 + return TC_ACT_OK; 32 + 33 + if (bpf_skb_load_bytes(skb, ETH_HLEN + sizeof(iph), &udph, sizeof(udph))) 34 + return TC_ACT_OK; 35 + 36 + if (udph.dest != __bpf_constant_htons(UDP_TEST_PORT)) 37 + return TC_ACT_OK; 38 + 39 + kskb = bpf_cast_to_kern_ctx(skb); 40 + had_dst = (kskb->_skb_refdst != 0); 41 + 42 + /* Same-protocol encap (IPIP): protocol stays IPv4, but the dst 43 + * from the original routing is no longer valid for the outer hdr. 44 + */ 45 + err = bpf_skb_adjust_room(skb, (s32)sizeof(struct iphdr), 46 + BPF_ADJ_ROOM_MAC, 47 + BPF_F_ADJ_ROOM_FIXED_GSO | 48 + BPF_F_ADJ_ROOM_ENCAP_L3_IPV4); 49 + if (err) 50 + return TC_ACT_SHOT; 51 + 52 + dst_cleared = (kskb->_skb_refdst == 0); 53 + 54 + return TC_ACT_SHOT; 55 + } 56 + 57 + char __license[] SEC("license") = "GPL";