diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 80 |
1 files changed, 24 insertions, 56 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index e4ba974f143..ff622069fce 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -202,11 +202,6 @@ EXPORT_SYMBOL(ip_tos2prio); | |||
202 | static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat); | 202 | static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat); |
203 | #define RT_CACHE_STAT_INC(field) __this_cpu_inc(rt_cache_stat.field) | 203 | #define RT_CACHE_STAT_INC(field) __this_cpu_inc(rt_cache_stat.field) |
204 | 204 | ||
205 | static inline int rt_genid(struct net *net) | ||
206 | { | ||
207 | return atomic_read(&net->ipv4.rt_genid); | ||
208 | } | ||
209 | |||
210 | #ifdef CONFIG_PROC_FS | 205 | #ifdef CONFIG_PROC_FS |
211 | static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos) | 206 | static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos) |
212 | { | 207 | { |
@@ -447,27 +442,9 @@ static inline bool rt_is_expired(const struct rtable *rth) | |||
447 | return rth->rt_genid != rt_genid(dev_net(rth->dst.dev)); | 442 | return rth->rt_genid != rt_genid(dev_net(rth->dst.dev)); |
448 | } | 443 | } |
449 | 444 | ||
450 | /* | 445 | void rt_cache_flush(struct net *net) |
451 | * Perturbation of rt_genid by a small quantity [1..256] | ||
452 | * Using 8 bits of shuffling ensure we can call rt_cache_invalidate() | ||
453 | * many times (2^24) without giving recent rt_genid. | ||
454 | * Jenkins hash is strong enough that litle changes of rt_genid are OK. | ||
455 | */ | ||
456 | static void rt_cache_invalidate(struct net *net) | ||
457 | { | ||
458 | unsigned char shuffle; | ||
459 | |||
460 | get_random_bytes(&shuffle, sizeof(shuffle)); | ||
461 | atomic_add(shuffle + 1U, &net->ipv4.rt_genid); | ||
462 | } | ||
463 | |||
464 | /* | ||
465 | * delay < 0 : invalidate cache (fast : entries will be deleted later) | ||
466 | * delay >= 0 : invalidate & flush cache (can be long) | ||
467 | */ | ||
468 | void rt_cache_flush(struct net *net, int delay) | ||
469 | { | 446 | { |
470 | rt_cache_invalidate(net); | 447 | rt_genid_bump(net); |
471 | } | 448 | } |
472 | 449 | ||
473 | static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, | 450 | static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, |
@@ -934,12 +911,14 @@ static u32 __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) | |||
934 | if (mtu < ip_rt_min_pmtu) | 911 | if (mtu < ip_rt_min_pmtu) |
935 | mtu = ip_rt_min_pmtu; | 912 | mtu = ip_rt_min_pmtu; |
936 | 913 | ||
914 | rcu_read_lock(); | ||
937 | if (fib_lookup(dev_net(rt->dst.dev), fl4, &res) == 0) { | 915 | if (fib_lookup(dev_net(rt->dst.dev), fl4, &res) == 0) { |
938 | struct fib_nh *nh = &FIB_RES_NH(res); | 916 | struct fib_nh *nh = &FIB_RES_NH(res); |
939 | 917 | ||
940 | update_or_create_fnhe(nh, fl4->daddr, 0, mtu, | 918 | update_or_create_fnhe(nh, fl4->daddr, 0, mtu, |
941 | jiffies + ip_rt_mtu_expires); | 919 | jiffies + ip_rt_mtu_expires); |
942 | } | 920 | } |
921 | rcu_read_unlock(); | ||
943 | return mtu; | 922 | return mtu; |
944 | } | 923 | } |
945 | 924 | ||
@@ -956,7 +935,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, | |||
956 | dst->obsolete = DST_OBSOLETE_KILL; | 935 | dst->obsolete = DST_OBSOLETE_KILL; |
957 | } else { | 936 | } else { |
958 | rt->rt_pmtu = mtu; | 937 | rt->rt_pmtu = mtu; |
959 | dst_set_expires(&rt->dst, ip_rt_mtu_expires); | 938 | rt->dst.expires = max(1UL, jiffies + ip_rt_mtu_expires); |
960 | } | 939 | } |
961 | } | 940 | } |
962 | 941 | ||
@@ -1132,10 +1111,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst) | |||
1132 | const struct rtable *rt = (const struct rtable *) dst; | 1111 | const struct rtable *rt = (const struct rtable *) dst; |
1133 | unsigned int mtu = rt->rt_pmtu; | 1112 | unsigned int mtu = rt->rt_pmtu; |
1134 | 1113 | ||
1135 | if (mtu && time_after_eq(jiffies, rt->dst.expires)) | 1114 | if (!mtu || time_after_eq(jiffies, rt->dst.expires)) |
1136 | mtu = 0; | ||
1137 | |||
1138 | if (!mtu) | ||
1139 | mtu = dst_metric_raw(dst, RTAX_MTU); | 1115 | mtu = dst_metric_raw(dst, RTAX_MTU); |
1140 | 1116 | ||
1141 | if (mtu && rt_is_output_route(rt)) | 1117 | if (mtu && rt_is_output_route(rt)) |
@@ -1263,7 +1239,7 @@ static void ipv4_dst_destroy(struct dst_entry *dst) | |||
1263 | { | 1239 | { |
1264 | struct rtable *rt = (struct rtable *) dst; | 1240 | struct rtable *rt = (struct rtable *) dst; |
1265 | 1241 | ||
1266 | if (dst->flags & DST_NOCACHE) { | 1242 | if (!list_empty(&rt->rt_uncached)) { |
1267 | spin_lock_bh(&rt_uncached_lock); | 1243 | spin_lock_bh(&rt_uncached_lock); |
1268 | list_del(&rt->rt_uncached); | 1244 | list_del(&rt->rt_uncached); |
1269 | spin_unlock_bh(&rt_uncached_lock); | 1245 | spin_unlock_bh(&rt_uncached_lock); |
@@ -1587,11 +1563,14 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
1587 | if (ipv4_is_zeronet(daddr)) | 1563 | if (ipv4_is_zeronet(daddr)) |
1588 | goto martian_destination; | 1564 | goto martian_destination; |
1589 | 1565 | ||
1590 | if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev))) { | 1566 | /* Following code try to avoid calling IN_DEV_NET_ROUTE_LOCALNET(), |
1591 | if (ipv4_is_loopback(daddr)) | 1567 | * and call it once if daddr or/and saddr are loopback addresses |
1568 | */ | ||
1569 | if (ipv4_is_loopback(daddr)) { | ||
1570 | if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) | ||
1592 | goto martian_destination; | 1571 | goto martian_destination; |
1593 | 1572 | } else if (ipv4_is_loopback(saddr)) { | |
1594 | if (ipv4_is_loopback(saddr)) | 1573 | if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) |
1595 | goto martian_source; | 1574 | goto martian_source; |
1596 | } | 1575 | } |
1597 | 1576 | ||
@@ -1616,7 +1595,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
1616 | 1595 | ||
1617 | if (res.type == RTN_LOCAL) { | 1596 | if (res.type == RTN_LOCAL) { |
1618 | err = fib_validate_source(skb, saddr, daddr, tos, | 1597 | err = fib_validate_source(skb, saddr, daddr, tos, |
1619 | net->loopback_dev->ifindex, | 1598 | LOOPBACK_IFINDEX, |
1620 | dev, in_dev, &itag); | 1599 | dev, in_dev, &itag); |
1621 | if (err < 0) | 1600 | if (err < 0) |
1622 | goto martian_source_keep_err; | 1601 | goto martian_source_keep_err; |
@@ -1892,7 +1871,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4) | |||
1892 | 1871 | ||
1893 | orig_oif = fl4->flowi4_oif; | 1872 | orig_oif = fl4->flowi4_oif; |
1894 | 1873 | ||
1895 | fl4->flowi4_iif = net->loopback_dev->ifindex; | 1874 | fl4->flowi4_iif = LOOPBACK_IFINDEX; |
1896 | fl4->flowi4_tos = tos & IPTOS_RT_MASK; | 1875 | fl4->flowi4_tos = tos & IPTOS_RT_MASK; |
1897 | fl4->flowi4_scope = ((tos & RTO_ONLINK) ? | 1876 | fl4->flowi4_scope = ((tos & RTO_ONLINK) ? |
1898 | RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); | 1877 | RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); |
@@ -1981,7 +1960,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4) | |||
1981 | if (!fl4->daddr) | 1960 | if (!fl4->daddr) |
1982 | fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK); | 1961 | fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK); |
1983 | dev_out = net->loopback_dev; | 1962 | dev_out = net->loopback_dev; |
1984 | fl4->flowi4_oif = net->loopback_dev->ifindex; | 1963 | fl4->flowi4_oif = LOOPBACK_IFINDEX; |
1985 | res.type = RTN_LOCAL; | 1964 | res.type = RTN_LOCAL; |
1986 | flags |= RTCF_LOCAL; | 1965 | flags |= RTCF_LOCAL; |
1987 | goto make_route; | 1966 | goto make_route; |
@@ -2028,7 +2007,6 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4) | |||
2028 | } | 2007 | } |
2029 | dev_out = net->loopback_dev; | 2008 | dev_out = net->loopback_dev; |
2030 | fl4->flowi4_oif = dev_out->ifindex; | 2009 | fl4->flowi4_oif = dev_out->ifindex; |
2031 | res.fi = NULL; | ||
2032 | flags |= RTCF_LOCAL; | 2010 | flags |= RTCF_LOCAL; |
2033 | goto make_route; | 2011 | goto make_route; |
2034 | } | 2012 | } |
@@ -2153,7 +2131,7 @@ struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4, | |||
2153 | EXPORT_SYMBOL_GPL(ip_route_output_flow); | 2131 | EXPORT_SYMBOL_GPL(ip_route_output_flow); |
2154 | 2132 | ||
2155 | static int rt_fill_info(struct net *net, __be32 dst, __be32 src, | 2133 | static int rt_fill_info(struct net *net, __be32 dst, __be32 src, |
2156 | struct flowi4 *fl4, struct sk_buff *skb, u32 pid, | 2134 | struct flowi4 *fl4, struct sk_buff *skb, u32 portid, |
2157 | u32 seq, int event, int nowait, unsigned int flags) | 2135 | u32 seq, int event, int nowait, unsigned int flags) |
2158 | { | 2136 | { |
2159 | struct rtable *rt = skb_rtable(skb); | 2137 | struct rtable *rt = skb_rtable(skb); |
@@ -2163,7 +2141,7 @@ static int rt_fill_info(struct net *net, __be32 dst, __be32 src, | |||
2163 | u32 error; | 2141 | u32 error; |
2164 | u32 metrics[RTAX_MAX]; | 2142 | u32 metrics[RTAX_MAX]; |
2165 | 2143 | ||
2166 | nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags); | 2144 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*r), flags); |
2167 | if (nlh == NULL) | 2145 | if (nlh == NULL) |
2168 | return -EMSGSIZE; | 2146 | return -EMSGSIZE; |
2169 | 2147 | ||
@@ -2323,12 +2301,12 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void | |||
2323 | rt->rt_flags |= RTCF_NOTIFY; | 2301 | rt->rt_flags |= RTCF_NOTIFY; |
2324 | 2302 | ||
2325 | err = rt_fill_info(net, dst, src, &fl4, skb, | 2303 | err = rt_fill_info(net, dst, src, &fl4, skb, |
2326 | NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, | 2304 | NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, |
2327 | RTM_NEWROUTE, 0, 0); | 2305 | RTM_NEWROUTE, 0, 0); |
2328 | if (err <= 0) | 2306 | if (err <= 0) |
2329 | goto errout_free; | 2307 | goto errout_free; |
2330 | 2308 | ||
2331 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); | 2309 | err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); |
2332 | errout: | 2310 | errout: |
2333 | return err; | 2311 | return err; |
2334 | 2312 | ||
@@ -2344,7 +2322,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
2344 | 2322 | ||
2345 | void ip_rt_multicast_event(struct in_device *in_dev) | 2323 | void ip_rt_multicast_event(struct in_device *in_dev) |
2346 | { | 2324 | { |
2347 | rt_cache_flush(dev_net(in_dev->dev), 0); | 2325 | rt_cache_flush(dev_net(in_dev->dev)); |
2348 | } | 2326 | } |
2349 | 2327 | ||
2350 | #ifdef CONFIG_SYSCTL | 2328 | #ifdef CONFIG_SYSCTL |
@@ -2353,16 +2331,7 @@ static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write, | |||
2353 | size_t *lenp, loff_t *ppos) | 2331 | size_t *lenp, loff_t *ppos) |
2354 | { | 2332 | { |
2355 | if (write) { | 2333 | if (write) { |
2356 | int flush_delay; | 2334 | rt_cache_flush((struct net *)__ctl->extra1); |
2357 | ctl_table ctl; | ||
2358 | struct net *net; | ||
2359 | |||
2360 | memcpy(&ctl, __ctl, sizeof(ctl)); | ||
2361 | ctl.data = &flush_delay; | ||
2362 | proc_dointvec(&ctl, write, buffer, lenp, ppos); | ||
2363 | |||
2364 | net = (struct net *)__ctl->extra1; | ||
2365 | rt_cache_flush(net, flush_delay); | ||
2366 | return 0; | 2335 | return 0; |
2367 | } | 2336 | } |
2368 | 2337 | ||
@@ -2532,8 +2501,7 @@ static __net_initdata struct pernet_operations sysctl_route_ops = { | |||
2532 | 2501 | ||
2533 | static __net_init int rt_genid_init(struct net *net) | 2502 | static __net_init int rt_genid_init(struct net *net) |
2534 | { | 2503 | { |
2535 | get_random_bytes(&net->ipv4.rt_genid, | 2504 | atomic_set(&net->rt_genid, 0); |
2536 | sizeof(net->ipv4.rt_genid)); | ||
2537 | get_random_bytes(&net->ipv4.dev_addr_genid, | 2505 | get_random_bytes(&net->ipv4.dev_addr_genid, |
2538 | sizeof(net->ipv4.dev_addr_genid)); | 2506 | sizeof(net->ipv4.dev_addr_genid)); |
2539 | return 0; | 2507 | return 0; |