mirror of https://github.com/torvalds/linux.git
ipv6: adopt skb_dst_dev() and skb_dst_dev_net[_rcu]() helpers
Use the new helpers as a step to deal with potential dst->dev races. v2: fix typo in ipv6_rthdr_rcv() (kernel test robot <lkp@intel.com>) Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20250630121934.3399505-10-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
1caf272972
commit
93d1cff35a
|
|
@ -150,7 +150,7 @@ static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
|
|||
int iif, int sdif,
|
||||
bool *refcounted)
|
||||
{
|
||||
struct net *net = dev_net_rcu(skb_dst(skb)->dev);
|
||||
struct net *net = skb_dst_dev_net_rcu(skb);
|
||||
const struct ipv6hdr *ip6h = ipv6_hdr(skb);
|
||||
struct sock *sk;
|
||||
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
|
|||
memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
|
||||
IP6CB(skb)->flags = ip6cb_flags;
|
||||
pkt_len = skb->len - skb_inner_network_offset(skb);
|
||||
err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb);
|
||||
err = ip6_local_out(skb_dst_dev_net(skb), sk, skb);
|
||||
|
||||
if (dev) {
|
||||
if (unlikely(net_xmit_eval(err)))
|
||||
|
|
|
|||
|
|
@ -460,7 +460,7 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
|
||||
if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) {
|
||||
if (ipv6_hdr(skb)->hop_limit <= 1) {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_send(skb, ICMPV6_TIME_EXCEED,
|
||||
|
|
@ -621,7 +621,7 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
|
||||
if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) {
|
||||
if (ipv6_hdr(skb)->hop_limit <= 1) {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_send(skb, ICMPV6_TIME_EXCEED,
|
||||
|
|
@ -783,7 +783,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
|
|||
kfree_skb(skb);
|
||||
return -1;
|
||||
}
|
||||
if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) {
|
||||
if (!ipv6_chk_home_addr(skb_dst_dev_net(skb), addr)) {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
|
||||
kfree_skb(skb);
|
||||
return -1;
|
||||
|
|
@ -809,7 +809,7 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) {
|
||||
if (skb_dst_dev(skb)->flags & IFF_LOOPBACK) {
|
||||
if (ipv6_hdr(skb)->hop_limit <= 1) {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
|
||||
|
|
|
|||
|
|
@ -696,6 +696,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
|
|||
struct ioam6_schema *sc,
|
||||
u8 sclen, bool is_input)
|
||||
{
|
||||
struct net_device *dev = skb_dst_dev(skb);
|
||||
struct timespec64 ts;
|
||||
ktime_t tstamp;
|
||||
u64 raw64;
|
||||
|
|
@ -712,7 +713,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
|
|||
if (is_input)
|
||||
byte--;
|
||||
|
||||
raw32 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id;
|
||||
raw32 = dev_net(dev)->ipv6.sysctl.ioam6_id;
|
||||
|
||||
*(__be32 *)data = cpu_to_be32((byte << 24) | raw32);
|
||||
data += sizeof(__be32);
|
||||
|
|
@ -728,10 +729,10 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
|
|||
*(__be16 *)data = cpu_to_be16(raw16);
|
||||
data += sizeof(__be16);
|
||||
|
||||
if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
|
||||
if (dev->flags & IFF_LOOPBACK)
|
||||
raw16 = IOAM6_U16_UNAVAILABLE;
|
||||
else
|
||||
raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id);
|
||||
raw16 = (__force u16)READ_ONCE(__in6_dev_get(dev)->cnf.ioam6_id);
|
||||
|
||||
*(__be16 *)data = cpu_to_be16(raw16);
|
||||
data += sizeof(__be16);
|
||||
|
|
@ -783,10 +784,10 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
|
|||
struct Qdisc *qdisc;
|
||||
__u32 qlen, backlog;
|
||||
|
||||
if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
|
||||
if (dev->flags & IFF_LOOPBACK) {
|
||||
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
|
||||
} else {
|
||||
queue = skb_get_tx_queue(skb_dst(skb)->dev, skb);
|
||||
queue = skb_get_tx_queue(dev, skb);
|
||||
qdisc = rcu_dereference(queue->qdisc);
|
||||
qdisc_qstats_qlen_backlog(qdisc, &qlen, &backlog);
|
||||
|
||||
|
|
@ -807,7 +808,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
|
|||
if (is_input)
|
||||
byte--;
|
||||
|
||||
raw64 = dev_net(skb_dst(skb)->dev)->ipv6.sysctl.ioam6_id_wide;
|
||||
raw64 = dev_net(dev)->ipv6.sysctl.ioam6_id_wide;
|
||||
|
||||
*(__be64 *)data = cpu_to_be64(((u64)byte << 56) | raw64);
|
||||
data += sizeof(__be64);
|
||||
|
|
@ -823,10 +824,10 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
|
|||
*(__be32 *)data = cpu_to_be32(raw32);
|
||||
data += sizeof(__be32);
|
||||
|
||||
if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
|
||||
if (dev->flags & IFF_LOOPBACK)
|
||||
raw32 = IOAM6_U32_UNAVAILABLE;
|
||||
else
|
||||
raw32 = READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide);
|
||||
raw32 = READ_ONCE(__in6_dev_get(dev)->cnf.ioam6_id_wide);
|
||||
|
||||
*(__be32 *)data = cpu_to_be32(raw32);
|
||||
data += sizeof(__be32);
|
||||
|
|
|
|||
|
|
@ -187,7 +187,9 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
|
|||
* arrived via the sending interface (ethX), because of the
|
||||
* nature of scoping architecture. --yoshfuji
|
||||
*/
|
||||
IP6CB(skb)->iif = skb_valid_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex;
|
||||
IP6CB(skb)->iif = skb_valid_dst(skb) ?
|
||||
ip6_dst_idev(skb_dst(skb))->dev->ifindex :
|
||||
dev->ifindex;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, sizeof(*hdr))))
|
||||
goto err;
|
||||
|
|
@ -504,7 +506,7 @@ int ip6_mc_input(struct sk_buff *skb)
|
|||
struct net_device *dev;
|
||||
bool deliver;
|
||||
|
||||
__IP6_UPD_PO_STATS(dev_net(skb_dst(skb)->dev),
|
||||
__IP6_UPD_PO_STATS(skb_dst_dev_net(skb),
|
||||
__in6_dev_get_safely(skb->dev), IPSTATS_MIB_INMCAST,
|
||||
skb->len);
|
||||
|
||||
|
|
|
|||
|
|
@ -232,8 +232,9 @@ static int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *s
|
|||
|
||||
int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = skb_dst(skb)->dev, *indev = skb->dev;
|
||||
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct net_device *dev = dst_dev(dst), *indev = skb->dev;
|
||||
struct inet6_dev *idev = ip6_dst_idev(dst);
|
||||
|
||||
skb->protocol = htons(ETH_P_IPV6);
|
||||
skb->dev = dev;
|
||||
|
|
|
|||
|
|
@ -632,7 +632,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
|||
} else {
|
||||
if (ip_route_input(skb2, eiph->daddr, eiph->saddr,
|
||||
ip4h_dscp(eiph), skb2->dev) ||
|
||||
skb_dst(skb2)->dev->type != ARPHRD_TUNNEL6)
|
||||
skb_dst_dev(skb2)->type != ARPHRD_TUNNEL6)
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
|
|||
xmit:
|
||||
skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
|
||||
skb_dst_set(skb, dst);
|
||||
skb->dev = skb_dst(skb)->dev;
|
||||
skb->dev = dst_dev(dst);
|
||||
|
||||
err = dst_output(t->net, skb->sk, skb);
|
||||
if (net_xmit_eval(err) == 0)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff
|
|||
{
|
||||
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
||||
struct sock *sk = sk_to_full_sk(sk_partial);
|
||||
struct net_device *dev = skb_dst(skb)->dev;
|
||||
struct net_device *dev = skb_dst_dev(skb);
|
||||
struct flow_keys flkeys;
|
||||
unsigned int hh_len;
|
||||
struct dst_entry *dst;
|
||||
|
|
@ -72,7 +72,7 @@ int ip6_route_me_harder(struct net *net, struct sock *sk_partial, struct sk_buff
|
|||
#endif
|
||||
|
||||
/* Change in oif may mean change in hh_len. */
|
||||
hh_len = skb_dst(skb)->dev->hard_header_len;
|
||||
hh_len = skb_dst_dev(skb)->hard_header_len;
|
||||
if (skb_headroom(skb) < hh_len &&
|
||||
pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)),
|
||||
0, GFP_ATOMIC))
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
|
|||
skb_dst_set(oldskb, dst);
|
||||
}
|
||||
|
||||
fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev);
|
||||
fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst_dev(oldskb));
|
||||
fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark);
|
||||
security_skb_classify_flow(oldskb, flowi6_to_flowi_common(&fl6));
|
||||
dst = ip6_route_output(net, NULL, &fl6);
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|||
skb->protocol = htons(ETH_P_IPV6);
|
||||
|
||||
return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
|
||||
net, sk, skb, NULL, skb_dst(skb)->dev,
|
||||
net, sk, skb, NULL, skb_dst_dev(skb),
|
||||
dst_output);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__ip6_local_out);
|
||||
|
|
|
|||
|
|
@ -104,11 +104,11 @@ fq_find(struct net *net, __be32 id, const struct ipv6hdr *hdr, int iif)
|
|||
return container_of(q, struct frag_queue, q);
|
||||
}
|
||||
|
||||
static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
|
||||
static int ip6_frag_queue(struct net *net,
|
||||
struct frag_queue *fq, struct sk_buff *skb,
|
||||
struct frag_hdr *fhdr, int nhoff,
|
||||
u32 *prob_offset, int *refs)
|
||||
{
|
||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||
int offset, end, fragsize;
|
||||
struct sk_buff *prev_tail;
|
||||
struct net_device *dev;
|
||||
|
|
@ -324,10 +324,10 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
|
|||
|
||||
static int ipv6_frag_rcv(struct sk_buff *skb)
|
||||
{
|
||||
const struct ipv6hdr *hdr = ipv6_hdr(skb);
|
||||
struct net *net = skb_dst_dev_net(skb);
|
||||
struct frag_hdr *fhdr;
|
||||
struct frag_queue *fq;
|
||||
const struct ipv6hdr *hdr = ipv6_hdr(skb);
|
||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||
u8 nexthdr;
|
||||
int iif;
|
||||
|
||||
|
|
@ -384,7 +384,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
|
|||
spin_lock(&fq->q.lock);
|
||||
|
||||
fq->iif = iif;
|
||||
ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff,
|
||||
ret = ip6_frag_queue(net, fq, skb, fhdr, IP6CB(skb)->nhoff,
|
||||
&prob_offset, &refs);
|
||||
|
||||
spin_unlock(&fq->q.lock);
|
||||
|
|
|
|||
|
|
@ -4631,7 +4631,7 @@ static int ip6_pkt_discard(struct sk_buff *skb)
|
|||
|
||||
static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
skb->dev = skb_dst(skb)->dev;
|
||||
skb->dev = skb_dst_dev(skb);
|
||||
return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES);
|
||||
}
|
||||
|
||||
|
|
@ -4642,7 +4642,7 @@ static int ip6_pkt_prohibit(struct sk_buff *skb)
|
|||
|
||||
static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
skb->dev = skb_dst(skb)->dev;
|
||||
skb->dev = skb_dst_dev(skb);
|
||||
return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ static int __seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,
|
|||
|
||||
#ifdef CONFIG_IPV6_SEG6_HMAC
|
||||
if (sr_has_hmac(isrh)) {
|
||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||
struct net *net = skb_dst_dev_net(skb);
|
||||
|
||||
err = seg6_push_hmac(net, &hdr->saddr, isrh);
|
||||
if (unlikely(err))
|
||||
|
|
@ -530,7 +530,7 @@ static int seg6_input_core(struct net *net, struct sock *sk,
|
|||
|
||||
static int seg6_input_nf(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = skb_dst(skb)->dev;
|
||||
struct net_device *dev = skb_dst_dev(skb);
|
||||
struct net *net = dev_net(skb->dev);
|
||||
|
||||
switch (skb->protocol) {
|
||||
|
|
@ -616,7 +616,7 @@ static int seg6_output_core(struct net *net, struct sock *sk,
|
|||
|
||||
static int seg6_output_nf(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = skb_dst(skb)->dev;
|
||||
struct net_device *dev = skb_dst_dev(skb);
|
||||
|
||||
switch (skb->protocol) {
|
||||
case htons(ETH_P_IP):
|
||||
|
|
|
|||
|
|
@ -868,7 +868,7 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
|
|||
int oif, int rst, u8 tclass, __be32 label,
|
||||
u32 priority, u32 txhash, struct tcp_key *key)
|
||||
{
|
||||
struct net *net = sk ? sock_net(sk) : dev_net_rcu(skb_dst(skb)->dev);
|
||||
struct net *net = sk ? sock_net(sk) : skb_dst_dev_net_rcu(skb);
|
||||
unsigned int tot_len = sizeof(struct tcphdr);
|
||||
struct sock *ctl_sk = net->ipv6.tcp_sk;
|
||||
const struct tcphdr *th = tcp_hdr(skb);
|
||||
|
|
@ -1043,7 +1043,7 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb,
|
|||
if (!sk && !ipv6_unicast_destination(skb))
|
||||
return;
|
||||
|
||||
net = sk ? sock_net(sk) : dev_net_rcu(skb_dst(skb)->dev);
|
||||
net = sk ? sock_net(sk) : skb_dst_dev_net_rcu(skb);
|
||||
/* Invalid TCP option size or twice included auth */
|
||||
if (tcp_parse_auth_options(th, &md5_hash_location, &aoh))
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|||
int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING,
|
||||
net, sk, skb, skb->dev, skb_dst(skb)->dev,
|
||||
net, sk, skb, skb->dev, skb_dst_dev(skb),
|
||||
__xfrm6_output,
|
||||
!(IP6CB(skb)->flags & IP6SKB_REROUTED));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue