diff --git a/include/net/dst_ops.h b/include/net/dst_ops.h index b8ee48ea07f15a1f3a09e6eeef4d9f12fdff134f..c73c6958e70eba907352e6ff752b45476197ab87 100644 --- a/include/net/dst_ops.h +++ b/include/net/dst_ops.h @@ -25,7 +25,8 @@ struct dst_ops { void (*destroy)(struct dst_entry *); void (*ifdown)(struct dst_entry *, struct net_device *dev, int how); - struct dst_entry * (*negative_advice)(struct dst_entry *); + // struct dst_entry * (*negative_advice)(struct dst_entry *); + void (*negative_advice)(struct sock *sk, struct dst_entry *); void (*link_failure)(struct sk_buff *); void (*update_pmtu)(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, u32 mtu, diff --git a/include/net/sock.h b/include/net/sock.h index a1bfb777a1afb31d8a0732f5c33c913a45209313..7618be37927ab2c9ded3165c931466d87e5e0ebe 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1955,19 +1955,21 @@ sk_dst_get(struct sock *sk) static inline void dst_negative_advice(struct sock *sk) { - struct dst_entry *ndst, *dst = __sk_dst_get(sk); - + // struct dst_entry *ndst, *dst = __sk_dst_get(sk); + struct dst_entry *dst = __sk_dst_get(sk); sk_rethink_txhash(sk); - if (dst && dst->ops->negative_advice) { - ndst = dst->ops->negative_advice(dst); - - if (ndst != dst) { - rcu_assign_pointer(sk->sk_dst_cache, ndst); - sk_tx_queue_clear(sk); - WRITE_ONCE(sk->sk_dst_pending_confirm, 0); - } - } + // if (dst && dst->ops->negative_advice) { + // ndst = dst->ops->negative_advice(dst); + + // if (ndst != dst) { + // rcu_assign_pointer(sk->sk_dst_cache, ndst); + // sk_tx_queue_clear(sk); + // WRITE_ONCE(sk->sk_dst_pending_confirm, 0); + // } + // } + if (dst && dst->ops->negative_advice) + dst->ops->negative_advice(sk, dst); } static inline void diff --git a/net/ipv4/route.c b/net/ipv4/route.c index dcb16e6747da2b811ced7bfa6eb7c2c8a8d82f2e..b96fbd7833c0cf06e649d5015ee104e2296f3e15 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -140,7 +140,8 @@ static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); static unsigned int ipv4_default_advmss(const struct dst_entry *dst); static unsigned int ipv4_mtu(const struct dst_entry *dst); -static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); +// static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); +void ipv4_negative_advice(struct sock *sk,struct dst_entry *dst); static void ipv4_link_failure(struct sk_buff *skb); static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, u32 mtu, @@ -846,22 +847,24 @@ static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buf __ip_do_redirect(rt, skb, &fl4, true); } -static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) +static void ipv4_negative_advice(struct sock *sk, struct dst_entry *dst) { struct rtable *rt = (struct rtable *)dst; - struct dst_entry *ret = dst; - - if (rt) { - if (dst->obsolete > 0) { - ip_rt_put(rt); - ret = NULL; - } else if ((rt->rt_flags & RTCF_REDIRECTED) || - rt->dst.expires) { - ip_rt_put(rt); - ret = NULL; - } - } - return ret; + // struct dst_entry *ret = dst; + + // if (rt) { + // if (dst->obsolete > 0) { + // ip_rt_put(rt); + // ret = NULL; + // } else if ((rt->rt_flags & RTCF_REDIRECTED) || + // rt->dst.expires) { + // ip_rt_put(rt); + // ret = NULL; + // } + // } + if ((dst->obsolete > 0) || (rt->rt_flags & RTCF_REDIRECTED) || rt->dst.expires) + sk_dst_reset(sk); + // return ret; } /* diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b0aaac94d7f859898ff989f9934f8ae90e4bc1bc..2c1b8df8429c7be2a6d896d1004bdf350474d542 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2284,24 +2284,37 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) return dst_ret; } -static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) +static void ip6_negative_advice(struct sock *sk,struct dst_entry *dst) { struct rt6_info *rt = (struct rt6_info *) dst; - if (rt) { - if (rt->rt6i_flags & RTF_CACHE) { - rcu_read_lock(); - if (rt6_check_expired(rt)) { - rt6_remove_exception_rt(rt); - dst = NULL; - } - rcu_read_unlock(); - } else { - dst_release(dst); - dst = NULL; + // if (rt) { + // if (rt->rt6i_flags & RTF_CACHE) { + // rcu_read_lock(); + // if (rt6_check_expired(rt)) { + // rt6_remove_exception_rt(rt); + // dst = NULL; + // } + // rcu_read_unlock(); + // } else { + // dst_release(dst); + // dst = NULL; + // } + // } + // return dst; + if (rt->rt6i_flags & RTF_CACHE) { + rcu_read_lock(); + if (rt6_check_expired(rt)) { + /* counteract the dst_release() in sk_dst_reset() */ + dst_hold(dst); + sk_dst_reset(sk); + + rt6_remove_exception_rt(rt); } + rcu_read_unlock(); + return; } - return dst; + sk_dst_reset(sk); } static void ip6_link_failure(struct sk_buff *skb) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 74ce9aee28ba06447ea6cdeb06b4fee700014430..fc9cdccc679fcc47ffadd030f9084f3c12118593 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2562,15 +2562,17 @@ static void xfrm_link_failure(struct sk_buff *skb) /* Impossible. Such dst must be popped before reaches point of failure. */ } -static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) -{ - if (dst) { - if (dst->obsolete) { - dst_release(dst); - dst = NULL; - } - } - return dst; +static void xfrm_negative_advice(struct sock *sk, struct dst_entry *dst) +{ + // if (dst) { + // if (dst->obsolete) { + // dst_release(dst); + // dst = NULL; + // } + // } + // return dst; + if (dst->obsolete) + sk_dst_reset(sk); } static void xfrm_init_pmtu(struct xfrm_dst **bundle, int nr)