diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 54 |
1 files changed, 33 insertions, 21 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 28205e5bfa9b..cd76b3cb7092 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; |
@@ -1114,7 +1118,10 @@ restart: | |||
1114 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1118 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1115 | 1119 | ||
1116 | rt_drop(rt); | 1120 | rt_drop(rt); |
1117 | *rp = rth; | 1121 | if (rp) |
1122 | *rp = rth; | ||
1123 | else | ||
1124 | skb_dst_set(skb, &rth->u.dst); | ||
1118 | return 0; | 1125 | return 0; |
1119 | } | 1126 | } |
1120 | 1127 | ||
@@ -1210,7 +1217,10 @@ restart: | |||
1210 | rcu_assign_pointer(rt_hash_table[hash].chain, rt); | 1217 | rcu_assign_pointer(rt_hash_table[hash].chain, rt); |
1211 | 1218 | ||
1212 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1219 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1213 | *rp = rt; | 1220 | if (rp) |
1221 | *rp = rt; | ||
1222 | else | ||
1223 | skb_dst_set(skb, &rt->u.dst); | ||
1214 | return 0; | 1224 | return 0; |
1215 | } | 1225 | } |
1216 | 1226 | ||
@@ -1407,7 +1417,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, | |||
1407 | &netevent); | 1417 | &netevent); |
1408 | 1418 | ||
1409 | rt_del(hash, rth); | 1419 | rt_del(hash, rth); |
1410 | if (!rt_intern_hash(hash, rt, &rt)) | 1420 | if (!rt_intern_hash(hash, rt, &rt, NULL)) |
1411 | ip_rt_put(rt); | 1421 | ip_rt_put(rt); |
1412 | goto do_next; | 1422 | goto do_next; |
1413 | } | 1423 | } |
@@ -1473,7 +1483,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) | |||
1473 | 1483 | ||
1474 | void ip_rt_send_redirect(struct sk_buff *skb) | 1484 | void ip_rt_send_redirect(struct sk_buff *skb) |
1475 | { | 1485 | { |
1476 | struct rtable *rt = skb->rtable; | 1486 | struct rtable *rt = skb_rtable(skb); |
1477 | struct in_device *in_dev = in_dev_get(rt->u.dst.dev); | 1487 | struct in_device *in_dev = in_dev_get(rt->u.dst.dev); |
1478 | 1488 | ||
1479 | if (!in_dev) | 1489 | if (!in_dev) |
@@ -1521,7 +1531,7 @@ out: | |||
1521 | 1531 | ||
1522 | static int ip_error(struct sk_buff *skb) | 1532 | static int ip_error(struct sk_buff *skb) |
1523 | { | 1533 | { |
1524 | struct rtable *rt = skb->rtable; | 1534 | struct rtable *rt = skb_rtable(skb); |
1525 | unsigned long now; | 1535 | unsigned long now; |
1526 | int code; | 1536 | int code; |
1527 | 1537 | ||
@@ -1698,7 +1708,7 @@ static void ipv4_link_failure(struct sk_buff *skb) | |||
1698 | 1708 | ||
1699 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); | 1709 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); |
1700 | 1710 | ||
1701 | rt = skb->rtable; | 1711 | rt = skb_rtable(skb); |
1702 | if (rt) | 1712 | if (rt) |
1703 | dst_set_expires(&rt->u.dst, 0); | 1713 | dst_set_expires(&rt->u.dst, 0); |
1704 | } | 1714 | } |
@@ -1858,7 +1868,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
1858 | 1868 | ||
1859 | in_dev_put(in_dev); | 1869 | in_dev_put(in_dev); |
1860 | hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); | 1870 | hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev))); |
1861 | return rt_intern_hash(hash, rth, &skb->rtable); | 1871 | return rt_intern_hash(hash, rth, NULL, skb); |
1862 | 1872 | ||
1863 | e_nobufs: | 1873 | e_nobufs: |
1864 | in_dev_put(in_dev); | 1874 | in_dev_put(in_dev); |
@@ -2019,7 +2029,7 @@ static int ip_mkroute_input(struct sk_buff *skb, | |||
2019 | /* put it into the cache */ | 2029 | /* put it into the cache */ |
2020 | hash = rt_hash(daddr, saddr, fl->iif, | 2030 | hash = rt_hash(daddr, saddr, fl->iif, |
2021 | rt_genid(dev_net(rth->u.dst.dev))); | 2031 | rt_genid(dev_net(rth->u.dst.dev))); |
2022 | return rt_intern_hash(hash, rth, &skb->rtable); | 2032 | return rt_intern_hash(hash, rth, NULL, skb); |
2023 | } | 2033 | } |
2024 | 2034 | ||
2025 | /* | 2035 | /* |
@@ -2175,7 +2185,7 @@ local_input: | |||
2175 | } | 2185 | } |
2176 | rth->rt_type = res.type; | 2186 | rth->rt_type = res.type; |
2177 | hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); | 2187 | hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); |
2178 | err = rt_intern_hash(hash, rth, &skb->rtable); | 2188 | err = rt_intern_hash(hash, rth, NULL, skb); |
2179 | goto done; | 2189 | goto done; |
2180 | 2190 | ||
2181 | no_route: | 2191 | no_route: |
@@ -2244,7 +2254,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, | |||
2244 | dst_use(&rth->u.dst, jiffies); | 2254 | dst_use(&rth->u.dst, jiffies); |
2245 | RT_CACHE_STAT_INC(in_hit); | 2255 | RT_CACHE_STAT_INC(in_hit); |
2246 | rcu_read_unlock(); | 2256 | rcu_read_unlock(); |
2247 | skb->rtable = rth; | 2257 | skb_dst_set(skb, &rth->u.dst); |
2248 | return 0; | 2258 | return 0; |
2249 | } | 2259 | } |
2250 | RT_CACHE_STAT_INC(in_hlist_search); | 2260 | RT_CACHE_STAT_INC(in_hlist_search); |
@@ -2420,7 +2430,7 @@ static int ip_mkroute_output(struct rtable **rp, | |||
2420 | if (err == 0) { | 2430 | if (err == 0) { |
2421 | hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, | 2431 | hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif, |
2422 | rt_genid(dev_net(dev_out))); | 2432 | rt_genid(dev_net(dev_out))); |
2423 | err = rt_intern_hash(hash, rth, rp); | 2433 | err = rt_intern_hash(hash, rth, rp, NULL); |
2424 | } | 2434 | } |
2425 | 2435 | ||
2426 | return err; | 2436 | return err; |
@@ -2763,7 +2773,7 @@ static int rt_fill_info(struct net *net, | |||
2763 | struct sk_buff *skb, u32 pid, u32 seq, int event, | 2773 | struct sk_buff *skb, u32 pid, u32 seq, int event, |
2764 | int nowait, unsigned int flags) | 2774 | int nowait, unsigned int flags) |
2765 | { | 2775 | { |
2766 | struct rtable *rt = skb->rtable; | 2776 | struct rtable *rt = skb_rtable(skb); |
2767 | struct rtmsg *r; | 2777 | struct rtmsg *r; |
2768 | struct nlmsghdr *nlh; | 2778 | struct nlmsghdr *nlh; |
2769 | long expires; | 2779 | long expires; |
@@ -2907,7 +2917,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); | 2917 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); |
2908 | local_bh_enable(); | 2918 | local_bh_enable(); |
2909 | 2919 | ||
2910 | rt = skb->rtable; | 2920 | rt = skb_rtable(skb); |
2911 | if (err == 0 && rt->u.dst.error) | 2921 | if (err == 0 && rt->u.dst.error) |
2912 | err = -rt->u.dst.error; | 2922 | err = -rt->u.dst.error; |
2913 | } else { | 2923 | } else { |
@@ -2927,7 +2937,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void | |||
2927 | if (err) | 2937 | if (err) |
2928 | goto errout_free; | 2938 | goto errout_free; |
2929 | 2939 | ||
2930 | skb->rtable = rt; | 2940 | skb_dst_set(skb, &rt->u.dst); |
2931 | if (rtm->rtm_flags & RTM_F_NOTIFY) | 2941 | if (rtm->rtm_flags & RTM_F_NOTIFY) |
2932 | rt->rt_flags |= RTCF_NOTIFY; | 2942 | rt->rt_flags |= RTCF_NOTIFY; |
2933 | 2943 | ||
@@ -2968,15 +2978,15 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
2968 | continue; | 2978 | continue; |
2969 | if (rt_is_expired(rt)) | 2979 | if (rt_is_expired(rt)) |
2970 | continue; | 2980 | continue; |
2971 | skb->dst = dst_clone(&rt->u.dst); | 2981 | skb_dst_set(skb, dst_clone(&rt->u.dst)); |
2972 | if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid, | 2982 | if (rt_fill_info(net, skb, NETLINK_CB(cb->skb).pid, |
2973 | cb->nlh->nlmsg_seq, RTM_NEWROUTE, | 2983 | cb->nlh->nlmsg_seq, RTM_NEWROUTE, |
2974 | 1, NLM_F_MULTI) <= 0) { | 2984 | 1, NLM_F_MULTI) <= 0) { |
2975 | dst_release(xchg(&skb->dst, NULL)); | 2985 | skb_dst_drop(skb); |
2976 | rcu_read_unlock_bh(); | 2986 | rcu_read_unlock_bh(); |
2977 | goto done; | 2987 | goto done; |
2978 | } | 2988 | } |
2979 | dst_release(xchg(&skb->dst, NULL)); | 2989 | skb_dst_drop(skb); |
2980 | } | 2990 | } |
2981 | rcu_read_unlock_bh(); | 2991 | rcu_read_unlock_bh(); |
2982 | } | 2992 | } |
@@ -3390,6 +3400,8 @@ int __init ip_rt_init(void) | |||
3390 | /* All the timers, started at system startup tend | 3400 | /* All the timers, started at system startup tend |
3391 | to synchronize. Perturb it a bit. | 3401 | to synchronize. Perturb it a bit. |
3392 | */ | 3402 | */ |
3403 | INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func); | ||
3404 | expires_ljiffies = jiffies; | ||
3393 | schedule_delayed_work(&expires_work, | 3405 | schedule_delayed_work(&expires_work, |
3394 | net_random() % ip_rt_gc_interval + ip_rt_gc_interval); | 3406 | net_random() % ip_rt_gc_interval + ip_rt_gc_interval); |
3395 | 3407 | ||