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

net: Switch to skb_dstref_steal/skb_dstref_restore for ip_route_input callers

Going forward skb_dst_set will assert that skb dst_entry
is empty during skb_dst_set. skb_dstref_steal is added to reset
existing entry without doing refcnt. skb_dstref_restore should
be used to restore the previous entry. Convert icmp_route_lookup
and ip_options_rcv_srr to these helpers. Add extra call to
skb_dstref_reset to icmp_route_lookup to clear the ip_route_input
entry.

Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20250818154032.3173645-5-sdf@fomichev.me
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Stanislav Fomichev and committed by
Jakub Kicinski
e97e6a18 15488d4d

+6 -6
+4 -3
net/ipv4/icmp.c
··· 544 544 goto relookup_failed; 545 545 } 546 546 /* Ugh! */ 547 - orefdst = skb_in->_skb_refdst; /* save old refdst */ 548 - skb_dst_set(skb_in, NULL); 547 + orefdst = skb_dstref_steal(skb_in); 549 548 err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, 550 549 dscp, rt2->dst.dev) ? -EINVAL : 0; 551 550 552 551 dst_release(&rt2->dst); 553 552 rt2 = skb_rtable(skb_in); 554 - skb_in->_skb_refdst = orefdst; /* restore old refdst */ 553 + /* steal dst entry from skb_in, don't drop refcnt */ 554 + skb_dstref_steal(skb_in); 555 + skb_dstref_restore(skb_in, orefdst); 555 556 } 556 557 557 558 if (err)
+2 -3
net/ipv4/ip_options.c
··· 615 615 } 616 616 memcpy(&nexthop, &optptr[srrptr-1], 4); 617 617 618 - orefdst = skb->_skb_refdst; 619 - skb_dst_set(skb, NULL); 618 + orefdst = skb_dstref_steal(skb); 620 619 err = ip_route_input(skb, nexthop, iph->saddr, ip4h_dscp(iph), 621 620 dev) ? -EINVAL : 0; 622 621 rt2 = skb_rtable(skb); 623 622 if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { 624 623 skb_dst_drop(skb); 625 - skb->_skb_refdst = orefdst; 624 + skb_dstref_restore(skb, orefdst); 626 625 return -EINVAL; 627 626 } 628 627 refdst_drop(orefdst);