diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 68 |
1 files changed, 45 insertions, 23 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 28205e5bfa9b..65b3a8b11a6c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -131,8 +131,8 @@ static int ip_rt_min_advmss __read_mostly = 256; | |||
131 | static int ip_rt_secret_interval __read_mostly = 10 * 60 * HZ; | 131 | static int ip_rt_secret_interval __read_mostly = 10 * 60 * HZ; |
132 | static int rt_chain_length_max __read_mostly = 20; | 132 | static int rt_chain_length_max __read_mostly = 20; |
133 | 133 | ||
134 | static void rt_worker_func(struct work_struct *work); | 134 | static struct delayed_work expires_work; |
135 | static DECLARE_DELAYED_WORK(expires_work, rt_worker_func); | 135 | static unsigned long expires_ljiffies; |
136 | 136 | ||
137 | /* | 137 | /* |
138 | * Interface to generic destination cache. | 138 | * Interface to generic destination cache. |
@@ -787,9 +787,12 @@ static void rt_check_expire(void) | |||
787 | struct rtable *rth, *aux, **rthp; | 787 | struct rtable *rth, *aux, **rthp; |
788 | unsigned long samples = 0; | 788 | unsigned long samples = 0; |
789 | unsigned long sum = 0, sum2 = 0; | 789 | unsigned long sum = 0, sum2 = 0; |
790 | unsigned long delta; | ||
790 | u64 mult; | 791 | u64 mult; |
791 | 792 | ||
792 | mult = ((u64)ip_rt_gc_interval) << rt_hash_log; | 793 | delta = jiffies - expires_ljiffies; |
794 | expires_ljiffies = jiffies; | ||
795 | mult = ((u64)delta) << rt_hash_log; | ||
793 | if (ip_rt_gc_timeout > 1) | 796 | if (ip_rt_gc_timeout > 1) |
794 | do_div(mult, ip_rt_gc_timeout); | 797 | do_div(mult, ip_rt_gc_timeout); |
795 | goal = (unsigned int)mult; | 798 | goal = (unsigned int)mult; |
@@ -1064,7 +1067,8 @@ work_done: | |||
1064 | out: return 0; | 1067 | out: return 0; |
1065 | } | 1068 | } |
1066 | 1069 | ||
1067 | static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp) | 1070 | static int rt_intern_hash(unsigned hash, struct rtable *rt, |
1071 | struct rtable **rp, struct sk_buff *skb) | ||
1068 | { | 1072 | { |
1069 | struct rtable *rth, **rthp; | 1073 | struct rtable *rth, **rthp; |
1070 | unsigned long now; | 1074 | unsigned long now; |
@@ -1081,8 +1085,16 @@ restart: | |||
1081 | now = jiffies; | 1085 | now = jiffies; |
1082 | 1086 | ||
1083 | if (!rt_caching(dev_net(rt->u.dst.dev))) { | 1087 | if (!rt_caching(dev_net(rt->u.dst.dev))) { |
1084 | rt_drop(rt); | 1088 | /* |
1085 | return 0; | 1089 | * If we're not caching, just tell the caller we |
1090 | * were successful and don't touch the route. The | ||
1091 | * caller hold the sole reference to the cache entry, and | ||
1092 | * it will be released when the caller is done with it. | ||
1093 | * If we drop it here, the callers have no way to resolve routes | ||
1094 | * when we're not caching. Instead, just point *rp at rt, so | ||
1095 | * the caller gets a single use out of the route | ||
1096 | */ | ||
1097 | goto report_and_exit; | ||
1086 | } | 1098 | } |
1087 | 1099 | ||
1088 | rthp = &rt_hash_table[hash].chain; | 1100 | rthp = &rt_hash_table[hash].chain; |
@@ -1114,7 +1126,10 @@ restart: | |||
1114 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1126 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1115 | 1127 | ||
1116 | rt_drop(rt); | 1128 | rt_drop(rt); |
1117 | *rp = rth; | 1129 | if (rp) |
1130 | *rp = rth; | ||
1131 | else | ||
1132 | skb_dst_set(skb, &rth->u.dst); | ||
1118 | return 0; | 1133 | return 0; |
1119 | } | 1134 | } |
1120 | 1135 | ||
@@ -1210,7 +1225,12 @@ restart: | |||
1210 | rcu_assign_pointer(rt_hash_table[hash].chain, rt); | 1225 | rcu_assign_pointer(rt_hash_table[hash].chain, rt); |
1211 | 1226 | ||
1212 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1227 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1213 | *rp = rt; | 1228 | |
1229 | report_and_exit: | ||
1230 | if (rp) | ||
1231 | *rp = rt; | ||
1232 | else | ||
1233 | skb_dst_set(skb, &rt->u.dst); | ||
1214 | return 0; | 1234 | return 0; |
1215 | } | 1235 | } |
1216 | 1236 | ||
@@ -1407,7 +1427,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1407 | &netevent); | 1427 | &netevent); |
1408 | 1428 | ||
1409 | rt_del(hash, rth); | 1429 | rt_del(hash, rth); |
1410 | if (!rt_intern_hash(hash, rt, &rt)) | 1430 | if (!rt_intern_hash(hash, rt, &rt, NULL)) |
1411 | ip_rt_put(rt); | 1431 | ip_rt_put(rt); |
1412 | goto do_next; | 1432 | goto do_next; |
1413 | } | 1433 | } |
@@ -1473,7 +1493,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) | |||
1473 | 1493 | ||
1474 | void ip_rt_send_redirect(struct sk_buff *skb) | 1494 | void ip_rt_send_redirect(struct sk_buff *skb) |
1475 | { | 1495 | { |
1476 | struct rtable *rt = skb->rtable; | 1496 | struct rtable *rt = skb_rtable(skb); |
1477 | struct in_device *in_dev = in_dev_get(rt->u.dst.dev); | 1497 | struct in_device *in_dev = in_dev_get(rt->u.dst.dev); |
1478 | 1498 | ||
1479 | if (!in_dev) | 1499 | if (!in_dev) |
@@ -1521,7 +1541,7 @@ out: | |||
1521 | 1541 | ||
1522 | static int ip_error(struct sk_buff *skb) | 1542 | static int ip_error(struct sk_buff *skb) |
1523 | { | 1543 | { |
1524 | struct rtable *rt = skb->rtable; | 1544 | struct rtable *rt = skb_rtable(skb); |
1525 | unsigned long now; | 1545 | unsigned long now; |
1526 | int code; | 1546 | int code; |
1527 | 1547 | ||
@@ -1698,7 +1718,7 @@ static void ipv4_link_failure(struct sk_buff *skb) | |||
1698 | 1718 | ||
1699 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); | 1719 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); |
1700 | 1720 | ||
1701 | rt = skb->rtable; | 1721 | rt = skb_rtable(skb); |
1702 | if (rt) | 1722 | if (rt) |
1703 | dst_set_expires(&rt->u.dst, 0); | 1723 | dst_set_expires(&rt->u.dst, 0); |
1704 | } | 1724 | } |
@@ -1858,7 +1878,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
1858 | 1878 | ||
1859 | in_dev_put(in_dev); | 1879 | in_dev_put(in_dev); |
1860 | hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); | 1880 | hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); |
1861 | return rt_intern_hash(hash, rth, &skb->rtable); | 1881 | return rt_intern_hash(hash, rth, NULL, skb); |
1862 | 1882 | ||
1863 | e_nobufs: | 1883 | e_nobufs: |
1864 | in_dev_put(in_dev); | 1884 | in_dev_put(in_dev); |
@@ -2019,7 +2039,7 @@ static int ip_mkroute_input(struct sk_buff *skb, | |||
2019 | /* put it into the cache */ | 2039 | /* put it into the cache */ |
2020 | hash = rt_hash(daddr, saddr, fl->iif, | 2040 | hash = rt_hash(daddr, saddr, fl->iif, |
2021 | rt_genid(dev_net(rth->u.dst.dev))); | 2041 | rt_genid(dev_net(rth->u.dst.dev))); |
2022 | return rt_intern_hash(hash, rth, &skb->rtable); | 2042 | return rt_intern_hash(hash, rth, NULL, skb); |
2023 | } | 2043 | } |
2024 | 2044 | ||
2025 | /* | 2045 | /* |
@@ -2175,7 +2195,7 @@ local_input: | |||
2175 | } | 2195 | } |
2176 | rth->rt_type = res.type; | 2196 | rth->rt_type = res.type; |
2177 | hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); | 2197 | hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); |
2178 | err = rt_intern_hash(hash, rth, &skb->rtable); | 2198 | err = rt_intern_hash(hash, rth, NULL, skb); |
2179 | goto done; | 2199 | goto done; |
2180 | 2200 | ||
2181 | no_route: | 2201 | no_route: |
@@ -2244,7 +2264,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
2244 | dst_use(&rth->u.dst, jiffies); | 2264 | dst_use(&rth->u.dst, jiffies); |
2245 | RT_CACHE_STAT_INC(in_hit); | 2265 | RT_CACHE_STAT_INC(in_hit); |
2246 | rcu_read_unlock(); | 2266 | rcu_read_unlock(); |
2247 | skb->rtable = rth; | 2267 | skb_dst_set(skb, &rth->u.dst); |
2248 | return 0; | 2268 | return 0; |
2249 | } | 2269 | } |
2250 | RT_CACHE_STAT_INC(in_hlist_search); | 2270 | RT_CACHE_STAT_INC(in_hlist_search); |
@@ -2420,7 +2440,7 @@ static int ip_mkroute_output(struct rtable **rp, | |||
2420 | if (err == 0) { | 2440 | if (err == 0) { |
2421 | hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, | 2441 | hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, |
2422 | rt_genid(dev_net(dev_out))); | 2442 | rt_genid(dev_net(dev_out))); |
2423 | err = rt_intern_hash(hash, rth, rp); | 2443 | err = rt_intern_hash(hash, rth, rp, NULL); |
2424 | } | 2444 | } |
2425 | 2445 | ||
2426 | return err; | 2446 | return err; |
@@ -2763,7 +2783,7 @@ static int rt_fill_info(struct net *net, | |||
2763 | struct sk_buff *skb, u32 pid, u32 seq, int event, | 2783 | struct sk_buff *skb, u32 pid, u32 seq, int event, |
2764 | int nowait, unsigned int flags) | 2784 | int nowait, unsigned int flags) |
2765 | { | 2785 | { |
2766 | struct rtable *rt = skb->rtable; | 2786 | struct rtable *rt = skb_rtable(skb); |
2767 | struct rtmsg *r; | 2787 | struct rtmsg *r; |
2768 | struct nlmsghdr *nlh; | 2788 | struct nlmsghdr *nlh; |
2769 | long expires; | 2789 | long expires; |
@@ -2907,7 +2927,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2907 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); | 2927 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); |
2908 | local_bh_enable(); | 2928 | local_bh_enable(); |
2909 | 2929 | ||
2910 | rt = skb->rtable; | 2930 | rt = skb_rtable(skb); |
2911 | if (err == 0 && rt->u.dst.error) | 2931 | if (err == 0 && rt->u.dst.error) |
2912 | err = -rt->u.dst.error; | 2932 | err = -rt->u.dst.error; |
2913 | } else { | 2933 | } else { |
@@ -2927,7 +2947,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2927 | if (err) | 2947 | if (err) |
2928 | goto errout_free; | 2948 | goto errout_free; |
2929 | 2949 | ||
2930 | skb->rtable = rt; | 2950 | skb_dst_set(skb, &rt->u.dst); |
2931 | if (rtm->rtm_flags & RTM_F_NOTIFY) | 2951 | if (rtm->rtm_flags & RTM_F_NOTIFY) |
2932 | rt->rt_flags |= RTCF_NOTIFY; | 2952 | rt->rt_flags |= RTCF_NOTIFY; |
2933 | 2953 | ||
@@ -2968,15 +2988,15 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
2968 | continue; | 2988 | continue; |
2969 | if (rt_is_expired(rt)) | 2989 | if (rt_is_expired(rt)) |
2970 | continue; | 2990 | continue; |
2971 | skb->dst = dst_clone(&rt->u.dst); | 2991 | skb_dst_set(skb, dst_clone(&rt->u.dst)); |
2972 | if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid, | 2992 | if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid, |
2973 | cb->nlh->nlmsg_seq, RTM_NEWROUTE, | 2993 | cb->nlh->nlmsg_seq, RTM_NEWROUTE, |
2974 | 1, NLM_F_MULTI) <= 0) { | 2994 | 1, NLM_F_MULTI) <= 0) { |
2975 | dst_release(xchg(&skb->dst, NULL)); | 2995 | skb_dst_drop(skb); |
2976 | rcu_read_unlock_bh(); | 2996 | rcu_read_unlock_bh(); |
2977 | goto done; | 2997 | goto done; |
2978 | } | 2998 | } |
2979 | dst_release(xchg(&skb->dst, NULL)); | 2999 | skb_dst_drop(skb); |
2980 | } | 3000 | } |
2981 | rcu_read_unlock_bh(); | 3001 | rcu_read_unlock_bh(); |
2982 | } | 3002 | } |
@@ -3390,6 +3410,8 @@ int __init ip_rt_init(void) | |||
3390 | /* All the timers, started at system startup tend | 3410 | /* All the timers, started at system startup tend |
3391 | to synchronize. Perturb it a bit. | 3411 | to synchronize. Perturb it a bit. |
3392 | */ | 3412 | */ |
3413 | INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func); | ||
3414 | expires_ljiffies = jiffies; | ||
3393 | schedule_delayed_work(&expires_work, | 3415 | schedule_delayed_work(&expires_work, |
3394 | net_random() % ip_rt_gc_interval + ip_rt_gc_interval); | 3416 | net_random() % ip_rt_gc_interval + ip_rt_gc_interval); |
3395 | 3417 | ||