diff options
author | Hiroaki SHIMODA <shimoda.hiroaki@gmail.com> | 2011-03-09 15:09:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-13 21:37:49 -0400 |
commit | 46af31800b6916c92fffa529dc3c357008da957d (patch) | |
tree | 2c66ee7b78527da504a294f1bd8a2a899623fead /net/ipv4/route.c | |
parent | bef55aebd560c5a6f8883c421abccee39978c58c (diff) |
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>
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 5655095a89e0..209989cf7d1b 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -1533,9 +1533,15 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, | |||
1533 | if (mtu < ip_rt_min_pmtu) | 1533 | if (mtu < ip_rt_min_pmtu) |
1534 | mtu = ip_rt_min_pmtu; | 1534 | mtu = ip_rt_min_pmtu; |
1535 | if (!peer->pmtu_expires || mtu < peer->pmtu_learned) { | 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 | est_mtu = mtu; | 1542 | est_mtu = mtu; |
1537 | peer->pmtu_learned = mtu; | 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 | inet_putpeer(peer); | 1547 | inet_putpeer(peer); |
@@ -1549,7 +1555,7 @@ static void check_peer_pmtu(struct dst_entry *dst, struct inet_peer *peer) | |||
1549 | { | 1555 | { |
1550 | unsigned long expires = peer->pmtu_expires; | 1556 | unsigned long expires = peer->pmtu_expires; |
1551 | 1557 | ||
1552 | if (time_before(expires, jiffies)) { | 1558 | if (time_before(jiffies, expires)) { |
1553 | u32 orig_dst_mtu = dst_mtu(dst); | 1559 | u32 orig_dst_mtu = dst_mtu(dst); |
1554 | if (peer->pmtu_learned < orig_dst_mtu) { | 1560 | if (peer->pmtu_learned < orig_dst_mtu) { |
1555 | if (!peer->pmtu_orig) | 1561 | if (!peer->pmtu_orig) |
@@ -1574,14 +1580,20 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
1574 | if (mtu < ip_rt_min_pmtu) | 1580 | if (mtu < ip_rt_min_pmtu) |
1575 | mtu = ip_rt_min_pmtu; | 1581 | mtu = ip_rt_min_pmtu; |
1576 | if (!peer->pmtu_expires || mtu < peer->pmtu_learned) { | 1582 | if (!peer->pmtu_expires || mtu < peer->pmtu_learned) { |
1583 | unsigned long pmtu_expires; | ||
1584 | |||
1585 | pmtu_expires = jiffies + ip_rt_mtu_expires; | ||
1586 | if (!pmtu_expires) | ||
1587 | pmtu_expires = 1UL; | ||
1588 | |||
1577 | peer->pmtu_learned = mtu; | 1589 | peer->pmtu_learned = mtu; |
1578 | peer->pmtu_expires = jiffies + ip_rt_mtu_expires; | 1590 | peer->pmtu_expires = pmtu_expires; |
1579 | 1591 | ||
1580 | atomic_inc(&__rt_peer_genid); | 1592 | atomic_inc(&__rt_peer_genid); |
1581 | rt->rt_peer_genid = rt_peer_genid(); | 1593 | rt->rt_peer_genid = rt_peer_genid(); |
1582 | |||
1583 | check_peer_pmtu(dst, peer); | ||
1584 | } | 1594 | } |
1595 | check_peer_pmtu(dst, peer); | ||
1596 | |||
1585 | inet_putpeer(peer); | 1597 | inet_putpeer(peer); |
1586 | } | 1598 | } |
1587 | } | 1599 | } |