Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 46af3180 authored by Hiroaki SHIMODA's avatar Hiroaki SHIMODA Committed by David S. Miller
Browse files

ipv4: Fix PMTU update.



On current net-next-2.6, when Linux receives ICMP Type: 3, Code: 4
(Destination unreachable (Fragmentation needed)),

  icmp_unreach
    -> ip_rt_frag_needed
         (peer->pmtu_expires is set here)
    -> tcp_v4_err
         -> do_pmtu_discovery
              -> ip_rt_update_pmtu
                   (peer->pmtu_expires is already set,
                    so check_peer_pmtu is skipped.)
                   -> check_peer_pmtu

check_peer_pmtu is skipped and MTU is not updated.

To fix this, let check_peer_pmtu execute unconditionally.
And some minor fixes
1) Avoid potential peer->pmtu_expires set to be zero.
2) In check_peer_pmtu, argument of time_before is reversed.
3) check_peer_pmtu expects peer->pmtu_orig is initialized as zero,
   but not initialized.

Signed-off-by: default avatarHiroaki SHIMODA <shimoda.hiroaki@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bef55aeb
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -511,6 +511,7 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
		p->rate_tokens = 0;
		p->rate_tokens = 0;
		p->rate_last = 0;
		p->rate_last = 0;
		p->pmtu_expires = 0;
		p->pmtu_expires = 0;
		p->pmtu_orig = 0;
		memset(&p->redirect_learned, 0, sizeof(p->redirect_learned));
		memset(&p->redirect_learned, 0, sizeof(p->redirect_learned));
		INIT_LIST_HEAD(&p->unused);
		INIT_LIST_HEAD(&p->unused);


+17 −5
Original line number Original line Diff line number Diff line
@@ -1533,9 +1533,15 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
		if (mtu < ip_rt_min_pmtu)
		if (mtu < ip_rt_min_pmtu)
			mtu = ip_rt_min_pmtu;
			mtu = ip_rt_min_pmtu;
		if (!peer->pmtu_expires || mtu < peer->pmtu_learned) {
		if (!peer->pmtu_expires || mtu < peer->pmtu_learned) {
			unsigned long pmtu_expires;

			pmtu_expires = jiffies + ip_rt_mtu_expires;
			if (!pmtu_expires)
				pmtu_expires = 1UL;

			est_mtu = mtu;
			est_mtu = mtu;
			peer->pmtu_learned = mtu;
			peer->pmtu_learned = mtu;
			peer->pmtu_expires = jiffies + ip_rt_mtu_expires;
			peer->pmtu_expires = pmtu_expires;
		}
		}


		inet_putpeer(peer);
		inet_putpeer(peer);
@@ -1549,7 +1555,7 @@ static void check_peer_pmtu(struct dst_entry *dst, struct inet_peer *peer)
{
{
	unsigned long expires = peer->pmtu_expires;
	unsigned long expires = peer->pmtu_expires;


	if (time_before(expires, jiffies)) {
	if (time_before(jiffies, expires)) {
		u32 orig_dst_mtu = dst_mtu(dst);
		u32 orig_dst_mtu = dst_mtu(dst);
		if (peer->pmtu_learned < orig_dst_mtu) {
		if (peer->pmtu_learned < orig_dst_mtu) {
			if (!peer->pmtu_orig)
			if (!peer->pmtu_orig)
@@ -1574,14 +1580,20 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
		if (mtu < ip_rt_min_pmtu)
		if (mtu < ip_rt_min_pmtu)
			mtu = ip_rt_min_pmtu;
			mtu = ip_rt_min_pmtu;
		if (!peer->pmtu_expires || mtu < peer->pmtu_learned) {
		if (!peer->pmtu_expires || mtu < peer->pmtu_learned) {
			unsigned long pmtu_expires;

			pmtu_expires = jiffies + ip_rt_mtu_expires;
			if (!pmtu_expires)
				pmtu_expires = 1UL;

			peer->pmtu_learned = mtu;
			peer->pmtu_learned = mtu;
			peer->pmtu_expires = jiffies + ip_rt_mtu_expires;
			peer->pmtu_expires = pmtu_expires;


			atomic_inc(&__rt_peer_genid);
			atomic_inc(&__rt_peer_genid);
			rt->rt_peer_genid = rt_peer_genid();
			rt->rt_peer_genid = rt_peer_genid();

			check_peer_pmtu(dst, peer);
		}
		}
		check_peer_pmtu(dst, peer);

		inet_putpeer(peer);
		inet_putpeer(peer);
	}
	}
}
}