diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 94 |
1 files changed, 58 insertions, 36 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 0c74da8a0473..46af62363b8c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -112,7 +112,7 @@ | |||
112 | #include <net/secure_seq.h> | 112 | #include <net/secure_seq.h> |
113 | 113 | ||
114 | #define RT_FL_TOS(oldflp4) \ | 114 | #define RT_FL_TOS(oldflp4) \ |
115 | ((u32)(oldflp4->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))) | 115 | ((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK)) |
116 | 116 | ||
117 | #define IP_MAX_MTU 0xFFF0 | 117 | #define IP_MAX_MTU 0xFFF0 |
118 | 118 | ||
@@ -131,6 +131,7 @@ static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; | |||
131 | static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; | 131 | static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; |
132 | static int ip_rt_min_advmss __read_mostly = 256; | 132 | static int ip_rt_min_advmss __read_mostly = 256; |
133 | static int rt_chain_length_max __read_mostly = 20; | 133 | static int rt_chain_length_max __read_mostly = 20; |
134 | static int redirect_genid; | ||
134 | 135 | ||
135 | /* | 136 | /* |
136 | * Interface to generic destination cache. | 137 | * Interface to generic destination cache. |
@@ -138,7 +139,7 @@ static int rt_chain_length_max __read_mostly = 20; | |||
138 | 139 | ||
139 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); | 140 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); |
140 | static unsigned int ipv4_default_advmss(const struct dst_entry *dst); | 141 | static unsigned int ipv4_default_advmss(const struct dst_entry *dst); |
141 | static unsigned int ipv4_default_mtu(const struct dst_entry *dst); | 142 | static unsigned int ipv4_mtu(const struct dst_entry *dst); |
142 | static void ipv4_dst_destroy(struct dst_entry *dst); | 143 | static void ipv4_dst_destroy(struct dst_entry *dst); |
143 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); | 144 | static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); |
144 | static void ipv4_link_failure(struct sk_buff *skb); | 145 | static void ipv4_link_failure(struct sk_buff *skb); |
@@ -193,7 +194,7 @@ static struct dst_ops ipv4_dst_ops = { | |||
193 | .gc = rt_garbage_collect, | 194 | .gc = rt_garbage_collect, |
194 | .check = ipv4_dst_check, | 195 | .check = ipv4_dst_check, |
195 | .default_advmss = ipv4_default_advmss, | 196 | .default_advmss = ipv4_default_advmss, |
196 | .default_mtu = ipv4_default_mtu, | 197 | .mtu = ipv4_mtu, |
197 | .cow_metrics = ipv4_cow_metrics, | 198 | .cow_metrics = ipv4_cow_metrics, |
198 | .destroy = ipv4_dst_destroy, | 199 | .destroy = ipv4_dst_destroy, |
199 | .ifdown = ipv4_dst_ifdown, | 200 | .ifdown = ipv4_dst_ifdown, |
@@ -416,9 +417,13 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) | |||
416 | else { | 417 | else { |
417 | struct rtable *r = v; | 418 | struct rtable *r = v; |
418 | struct neighbour *n; | 419 | struct neighbour *n; |
419 | int len; | 420 | int len, HHUptod; |
420 | 421 | ||
422 | rcu_read_lock(); | ||
421 | n = dst_get_neighbour(&r->dst); | 423 | n = dst_get_neighbour(&r->dst); |
424 | HHUptod = (n && (n->nud_state & NUD_CONNECTED)) ? 1 : 0; | ||
425 | rcu_read_unlock(); | ||
426 | |||
422 | seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t" | 427 | seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t" |
423 | "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n", | 428 | "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n", |
424 | r->dst.dev ? r->dst.dev->name : "*", | 429 | r->dst.dev ? r->dst.dev->name : "*", |
@@ -432,7 +437,7 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) | |||
432 | dst_metric(&r->dst, RTAX_RTTVAR)), | 437 | dst_metric(&r->dst, RTAX_RTTVAR)), |
433 | r->rt_key_tos, | 438 | r->rt_key_tos, |
434 | -1, | 439 | -1, |
435 | (n && (n->nud_state & NUD_CONNECTED)) ? 1 : 0, | 440 | HHUptod, |
436 | r->rt_spec_dst, &len); | 441 | r->rt_spec_dst, &len); |
437 | 442 | ||
438 | seq_printf(seq, "%*s\n", 127 - len, ""); | 443 | seq_printf(seq, "%*s\n", 127 - len, ""); |
@@ -837,6 +842,7 @@ static void rt_cache_invalidate(struct net *net) | |||
837 | 842 | ||
838 | get_random_bytes(&shuffle, sizeof(shuffle)); | 843 | get_random_bytes(&shuffle, sizeof(shuffle)); |
839 | atomic_add(shuffle + 1U, &net->ipv4.rt_genid); | 844 | atomic_add(shuffle + 1U, &net->ipv4.rt_genid); |
845 | redirect_genid++; | ||
840 | } | 846 | } |
841 | 847 | ||
842 | /* | 848 | /* |
@@ -1304,7 +1310,7 @@ static void rt_del(unsigned hash, struct rtable *rt) | |||
1304 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1310 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1305 | } | 1311 | } |
1306 | 1312 | ||
1307 | static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) | 1313 | static void check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) |
1308 | { | 1314 | { |
1309 | struct rtable *rt = (struct rtable *) dst; | 1315 | struct rtable *rt = (struct rtable *) dst; |
1310 | __be32 orig_gw = rt->rt_gateway; | 1316 | __be32 orig_gw = rt->rt_gateway; |
@@ -1315,21 +1321,19 @@ static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) | |||
1315 | rt->rt_gateway = peer->redirect_learned.a4; | 1321 | rt->rt_gateway = peer->redirect_learned.a4; |
1316 | 1322 | ||
1317 | n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway); | 1323 | n = ipv4_neigh_lookup(&rt->dst, &rt->rt_gateway); |
1318 | if (IS_ERR(n)) | 1324 | if (IS_ERR(n)) { |
1319 | return PTR_ERR(n); | 1325 | rt->rt_gateway = orig_gw; |
1326 | return; | ||
1327 | } | ||
1320 | old_n = xchg(&rt->dst._neighbour, n); | 1328 | old_n = xchg(&rt->dst._neighbour, n); |
1321 | if (old_n) | 1329 | if (old_n) |
1322 | neigh_release(old_n); | 1330 | neigh_release(old_n); |
1323 | if (!n || !(n->nud_state & NUD_VALID)) { | 1331 | if (!(n->nud_state & NUD_VALID)) { |
1324 | if (n) | 1332 | neigh_event_send(n, NULL); |
1325 | neigh_event_send(n, NULL); | ||
1326 | rt->rt_gateway = orig_gw; | ||
1327 | return -EAGAIN; | ||
1328 | } else { | 1333 | } else { |
1329 | rt->rt_flags |= RTCF_REDIRECTED; | 1334 | rt->rt_flags |= RTCF_REDIRECTED; |
1330 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); | 1335 | call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); |
1331 | } | 1336 | } |
1332 | return 0; | ||
1333 | } | 1337 | } |
1334 | 1338 | ||
1335 | /* called in rcu_read_lock() section */ | 1339 | /* called in rcu_read_lock() section */ |
@@ -1391,8 +1395,10 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1391 | 1395 | ||
1392 | peer = rt->peer; | 1396 | peer = rt->peer; |
1393 | if (peer) { | 1397 | if (peer) { |
1394 | if (peer->redirect_learned.a4 != new_gw) { | 1398 | if (peer->redirect_learned.a4 != new_gw || |
1399 | peer->redirect_genid != redirect_genid) { | ||
1395 | peer->redirect_learned.a4 = new_gw; | 1400 | peer->redirect_learned.a4 = new_gw; |
1401 | peer->redirect_genid = redirect_genid; | ||
1396 | atomic_inc(&__rt_peer_genid); | 1402 | atomic_inc(&__rt_peer_genid); |
1397 | } | 1403 | } |
1398 | check_peer_redir(&rt->dst, peer); | 1404 | check_peer_redir(&rt->dst, peer); |
@@ -1685,12 +1691,8 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
1685 | } | 1691 | } |
1686 | 1692 | ||
1687 | 1693 | ||
1688 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) | 1694 | static void ipv4_validate_peer(struct rtable *rt) |
1689 | { | 1695 | { |
1690 | struct rtable *rt = (struct rtable *) dst; | ||
1691 | |||
1692 | if (rt_is_expired(rt)) | ||
1693 | return NULL; | ||
1694 | if (rt->rt_peer_genid != rt_peer_genid()) { | 1696 | if (rt->rt_peer_genid != rt_peer_genid()) { |
1695 | struct inet_peer *peer; | 1697 | struct inet_peer *peer; |
1696 | 1698 | ||
@@ -1699,17 +1701,26 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) | |||
1699 | 1701 | ||
1700 | peer = rt->peer; | 1702 | peer = rt->peer; |
1701 | if (peer) { | 1703 | if (peer) { |
1702 | check_peer_pmtu(dst, peer); | 1704 | check_peer_pmtu(&rt->dst, peer); |
1703 | 1705 | ||
1706 | if (peer->redirect_genid != redirect_genid) | ||
1707 | peer->redirect_learned.a4 = 0; | ||
1704 | if (peer->redirect_learned.a4 && | 1708 | if (peer->redirect_learned.a4 && |
1705 | peer->redirect_learned.a4 != rt->rt_gateway) { | 1709 | peer->redirect_learned.a4 != rt->rt_gateway) |
1706 | if (check_peer_redir(dst, peer)) | 1710 | check_peer_redir(&rt->dst, peer); |
1707 | return NULL; | ||
1708 | } | ||
1709 | } | 1711 | } |
1710 | 1712 | ||
1711 | rt->rt_peer_genid = rt_peer_genid(); | 1713 | rt->rt_peer_genid = rt_peer_genid(); |
1712 | } | 1714 | } |
1715 | } | ||
1716 | |||
1717 | static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) | ||
1718 | { | ||
1719 | struct rtable *rt = (struct rtable *) dst; | ||
1720 | |||
1721 | if (rt_is_expired(rt)) | ||
1722 | return NULL; | ||
1723 | ipv4_validate_peer(rt); | ||
1713 | return dst; | 1724 | return dst; |
1714 | } | 1725 | } |
1715 | 1726 | ||
@@ -1814,12 +1825,17 @@ static unsigned int ipv4_default_advmss(const struct dst_entry *dst) | |||
1814 | return advmss; | 1825 | return advmss; |
1815 | } | 1826 | } |
1816 | 1827 | ||
1817 | static unsigned int ipv4_default_mtu(const struct dst_entry *dst) | 1828 | static unsigned int ipv4_mtu(const struct dst_entry *dst) |
1818 | { | 1829 | { |
1819 | unsigned int mtu = dst->dev->mtu; | 1830 | const struct rtable *rt = (const struct rtable *) dst; |
1831 | unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); | ||
1832 | |||
1833 | if (mtu && rt_is_output_route(rt)) | ||
1834 | return mtu; | ||
1835 | |||
1836 | mtu = dst->dev->mtu; | ||
1820 | 1837 | ||
1821 | if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { | 1838 | if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { |
1822 | const struct rtable *rt = (const struct rtable *) dst; | ||
1823 | 1839 | ||
1824 | if (rt->rt_gateway != rt->rt_dst && mtu > 576) | 1840 | if (rt->rt_gateway != rt->rt_dst && mtu > 576) |
1825 | mtu = 576; | 1841 | mtu = 576; |
@@ -1852,6 +1868,8 @@ static void rt_init_metrics(struct rtable *rt, const struct flowi4 *fl4, | |||
1852 | dst_init_metrics(&rt->dst, peer->metrics, false); | 1868 | dst_init_metrics(&rt->dst, peer->metrics, false); |
1853 | 1869 | ||
1854 | check_peer_pmtu(&rt->dst, peer); | 1870 | check_peer_pmtu(&rt->dst, peer); |
1871 | if (peer->redirect_genid != redirect_genid) | ||
1872 | peer->redirect_learned.a4 = 0; | ||
1855 | if (peer->redirect_learned.a4 && | 1873 | if (peer->redirect_learned.a4 && |
1856 | peer->redirect_learned.a4 != rt->rt_gateway) { | 1874 | peer->redirect_learned.a4 != rt->rt_gateway) { |
1857 | rt->rt_gateway = peer->redirect_learned.a4; | 1875 | rt->rt_gateway = peer->redirect_learned.a4; |
@@ -2357,6 +2375,7 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
2357 | rth->rt_mark == skb->mark && | 2375 | rth->rt_mark == skb->mark && |
2358 | net_eq(dev_net(rth->dst.dev), net) && | 2376 | net_eq(dev_net(rth->dst.dev), net) && |
2359 | !rt_is_expired(rth)) { | 2377 | !rt_is_expired(rth)) { |
2378 | ipv4_validate_peer(rth); | ||
2360 | if (noref) { | 2379 | if (noref) { |
2361 | dst_use_noref(&rth->dst, jiffies); | 2380 | dst_use_noref(&rth->dst, jiffies); |
2362 | skb_dst_set_noref(skb, &rth->dst); | 2381 | skb_dst_set_noref(skb, &rth->dst); |
@@ -2415,11 +2434,11 @@ EXPORT_SYMBOL(ip_route_input_common); | |||
2415 | static struct rtable *__mkroute_output(const struct fib_result *res, | 2434 | static struct rtable *__mkroute_output(const struct fib_result *res, |
2416 | const struct flowi4 *fl4, | 2435 | const struct flowi4 *fl4, |
2417 | __be32 orig_daddr, __be32 orig_saddr, | 2436 | __be32 orig_daddr, __be32 orig_saddr, |
2418 | int orig_oif, struct net_device *dev_out, | 2437 | int orig_oif, __u8 orig_rtos, |
2438 | struct net_device *dev_out, | ||
2419 | unsigned int flags) | 2439 | unsigned int flags) |
2420 | { | 2440 | { |
2421 | struct fib_info *fi = res->fi; | 2441 | struct fib_info *fi = res->fi; |
2422 | u32 tos = RT_FL_TOS(fl4); | ||
2423 | struct in_device *in_dev; | 2442 | struct in_device *in_dev; |
2424 | u16 type = res->type; | 2443 | u16 type = res->type; |
2425 | struct rtable *rth; | 2444 | struct rtable *rth; |
@@ -2470,7 +2489,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | |||
2470 | rth->rt_genid = rt_genid(dev_net(dev_out)); | 2489 | rth->rt_genid = rt_genid(dev_net(dev_out)); |
2471 | rth->rt_flags = flags; | 2490 | rth->rt_flags = flags; |
2472 | rth->rt_type = type; | 2491 | rth->rt_type = type; |
2473 | rth->rt_key_tos = tos; | 2492 | rth->rt_key_tos = orig_rtos; |
2474 | rth->rt_dst = fl4->daddr; | 2493 | rth->rt_dst = fl4->daddr; |
2475 | rth->rt_src = fl4->saddr; | 2494 | rth->rt_src = fl4->saddr; |
2476 | rth->rt_route_iif = 0; | 2495 | rth->rt_route_iif = 0; |
@@ -2520,7 +2539,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res, | |||
2520 | static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4) | 2539 | static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4) |
2521 | { | 2540 | { |
2522 | struct net_device *dev_out = NULL; | 2541 | struct net_device *dev_out = NULL; |
2523 | u32 tos = RT_FL_TOS(fl4); | 2542 | __u8 tos = RT_FL_TOS(fl4); |
2524 | unsigned int flags = 0; | 2543 | unsigned int flags = 0; |
2525 | struct fib_result res; | 2544 | struct fib_result res; |
2526 | struct rtable *rth; | 2545 | struct rtable *rth; |
@@ -2696,7 +2715,7 @@ static struct rtable *ip_route_output_slow(struct net *net, struct flowi4 *fl4) | |||
2696 | 2715 | ||
2697 | make_route: | 2716 | make_route: |
2698 | rth = __mkroute_output(&res, fl4, orig_daddr, orig_saddr, orig_oif, | 2717 | rth = __mkroute_output(&res, fl4, orig_daddr, orig_saddr, orig_oif, |
2699 | dev_out, flags); | 2718 | tos, dev_out, flags); |
2700 | if (!IS_ERR(rth)) { | 2719 | if (!IS_ERR(rth)) { |
2701 | unsigned int hash; | 2720 | unsigned int hash; |
2702 | 2721 | ||
@@ -2732,6 +2751,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *flp4) | |||
2732 | (IPTOS_RT_MASK | RTO_ONLINK)) && | 2751 | (IPTOS_RT_MASK | RTO_ONLINK)) && |
2733 | net_eq(dev_net(rth->dst.dev), net) && | 2752 | net_eq(dev_net(rth->dst.dev), net) && |
2734 | !rt_is_expired(rth)) { | 2753 | !rt_is_expired(rth)) { |
2754 | ipv4_validate_peer(rth); | ||
2735 | dst_use(&rth->dst, jiffies); | 2755 | dst_use(&rth->dst, jiffies); |
2736 | RT_CACHE_STAT_INC(out_hit); | 2756 | RT_CACHE_STAT_INC(out_hit); |
2737 | rcu_read_unlock_bh(); | 2757 | rcu_read_unlock_bh(); |
@@ -2755,9 +2775,11 @@ static struct dst_entry *ipv4_blackhole_dst_check(struct dst_entry *dst, u32 coo | |||
2755 | return NULL; | 2775 | return NULL; |
2756 | } | 2776 | } |
2757 | 2777 | ||
2758 | static unsigned int ipv4_blackhole_default_mtu(const struct dst_entry *dst) | 2778 | static unsigned int ipv4_blackhole_mtu(const struct dst_entry *dst) |
2759 | { | 2779 | { |
2760 | return 0; | 2780 | unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); |
2781 | |||
2782 | return mtu ? : dst->dev->mtu; | ||
2761 | } | 2783 | } |
2762 | 2784 | ||
2763 | static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) | 2785 | static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) |
@@ -2775,7 +2797,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { | |||
2775 | .protocol = cpu_to_be16(ETH_P_IP), | 2797 | .protocol = cpu_to_be16(ETH_P_IP), |
2776 | .destroy = ipv4_dst_destroy, | 2798 | .destroy = ipv4_dst_destroy, |
2777 | .check = ipv4_blackhole_dst_check, | 2799 | .check = ipv4_blackhole_dst_check, |
2778 | .default_mtu = ipv4_blackhole_default_mtu, | 2800 | .mtu = ipv4_blackhole_mtu, |
2779 | .default_advmss = ipv4_default_advmss, | 2801 | .default_advmss = ipv4_default_advmss, |
2780 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, | 2802 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, |
2781 | .cow_metrics = ipv4_rt_blackhole_cow_metrics, | 2803 | .cow_metrics = ipv4_rt_blackhole_cow_metrics, |