diff options
Diffstat (limited to 'net/ipv4/route.c')
| -rw-r--r-- | net/ipv4/route.c | 54 | 
1 files changed, 52 insertions, 2 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 844a9ef60db..a0fcc47fee7 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -912,6 +912,9 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)  	struct dst_entry *dst = &rt->dst;  	struct fib_result res; +	if (dst_metric_locked(dst, RTAX_MTU)) +		return; +  	if (dst->dev->mtu < mtu)  		return; @@ -962,7 +965,7 @@ void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu,  }  EXPORT_SYMBOL_GPL(ipv4_update_pmtu); -void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) +static void __ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)  {  	const struct iphdr *iph = (const struct iphdr *) skb->data;  	struct flowi4 fl4; @@ -975,6 +978,53 @@ void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu)  		ip_rt_put(rt);  	}  } + +void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) +{ +	const struct iphdr *iph = (const struct iphdr *) skb->data; +	struct flowi4 fl4; +	struct rtable *rt; +	struct dst_entry *dst; +	bool new = false; + +	bh_lock_sock(sk); +	rt = (struct rtable *) __sk_dst_get(sk); + +	if (sock_owned_by_user(sk) || !rt) { +		__ipv4_sk_update_pmtu(skb, sk, mtu); +		goto out; +	} + +	__build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); + +	if (!__sk_dst_check(sk, 0)) { +		rt = ip_route_output_flow(sock_net(sk), &fl4, sk); +		if (IS_ERR(rt)) +			goto out; + +		new = true; +	} + +	__ip_rt_update_pmtu((struct rtable *) rt->dst.path, &fl4, mtu); + +	dst = dst_check(&rt->dst, 0); +	if (!dst) { +		if (new) +			dst_release(&rt->dst); + +		rt = ip_route_output_flow(sock_net(sk), &fl4, sk); +		if (IS_ERR(rt)) +			goto out; + +		new = true; +	} + +	if (new) +		__sk_dst_set(sk, &rt->dst); + +out: +	bh_unlock_sock(sk); +}  EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu);  void ipv4_redirect(struct sk_buff *skb, struct net *net, @@ -1120,7 +1170,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)  	if (!mtu || time_after_eq(jiffies, rt->dst.expires))  		mtu = dst_metric_raw(dst, RTAX_MTU); -	if (mtu && rt_is_output_route(rt)) +	if (mtu)  		return mtu;  	mtu = dst->dev->mtu;  |