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

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: Hiroaki SHIMODA <shimoda.hiroaki@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Hiroaki SHIMODA and committed by
David S. Miller
46af3180 bef55aeb

+18 -5
+1
net/ipv4/inetpeer.c
··· 511 511 p->rate_tokens = 0; 512 512 p->rate_last = 0; 513 513 p->pmtu_expires = 0; 514 + p->pmtu_orig = 0; 514 515 memset(&p->redirect_learned, 0, sizeof(p->redirect_learned)); 515 516 INIT_LIST_HEAD(&p->unused); 516 517
+17 -5
net/ipv4/route.c
··· 1533 1533 if (mtu < ip_rt_min_pmtu) 1534 1534 mtu = ip_rt_min_pmtu; 1535 1535 if (!peer->pmtu_expires || mtu < peer->pmtu_learned) { 1536 + unsigned long pmtu_expires; 1537 + 1538 + pmtu_expires = jiffies + ip_rt_mtu_expires; 1539 + if (!pmtu_expires) 1540 + pmtu_expires = 1UL; 1541 + 1536 1542 est_mtu = mtu; 1537 1543 peer->pmtu_learned = mtu; 1538 - peer->pmtu_expires = jiffies + ip_rt_mtu_expires; 1544 + peer->pmtu_expires = pmtu_expires; 1539 1545 } 1540 1546 1541 1547 inet_putpeer(peer); ··· 1555 1549 { 1556 1550 unsigned long expires = peer->pmtu_expires; 1557 1551 1558 - if (time_before(expires, jiffies)) { 1552 + if (time_before(jiffies, expires)) { 1559 1553 u32 orig_dst_mtu = dst_mtu(dst); 1560 1554 if (peer->pmtu_learned < orig_dst_mtu) { 1561 1555 if (!peer->pmtu_orig) ··· 1580 1574 if (mtu < ip_rt_min_pmtu) 1581 1575 mtu = ip_rt_min_pmtu; 1582 1576 if (!peer->pmtu_expires || mtu < peer->pmtu_learned) { 1577 + unsigned long pmtu_expires; 1578 + 1579 + pmtu_expires = jiffies + ip_rt_mtu_expires; 1580 + if (!pmtu_expires) 1581 + pmtu_expires = 1UL; 1582 + 1583 1583 peer->pmtu_learned = mtu; 1584 - peer->pmtu_expires = jiffies + ip_rt_mtu_expires; 1584 + peer->pmtu_expires = pmtu_expires; 1585 1585 1586 1586 atomic_inc(&__rt_peer_genid); 1587 1587 rt->rt_peer_genid = rt_peer_genid(); 1588 - 1589 - check_peer_pmtu(dst, peer); 1590 1588 } 1589 + check_peer_pmtu(dst, peer); 1590 + 1591 1591 inet_putpeer(peer); 1592 1592 } 1593 1593 }