route.c (ff299f1b1cb4e0c44a3f76d1f8ee4eb2f64f098f) route.c (fe2c6338fd2c6f383c4d4164262f35c8f3708e1f)
1/*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * ROUTE - implementation of the IP router.
7 *
8 * Authors: Ross Biro

--- 580 unchanged lines hidden (view full) ---

589 u32 hval;
590
591 hval = (__force u32) daddr;
592 hval ^= (hval >> 11) ^ (hval >> 22);
593
594 return hval & (FNHE_HASH_SIZE - 1);
595}
596
1/*
2 * INET An implementation of the TCP/IP protocol suite for the LINUX
3 * operating system. INET is implemented using the BSD Socket
4 * interface as the means of communication with the user level.
5 *
6 * ROUTE - implementation of the IP router.
7 *
8 * Authors: Ross Biro

--- 580 unchanged lines hidden (view full) ---

589 u32 hval;
590
591 hval = (__force u32) daddr;
592 hval ^= (hval >> 11) ^ (hval >> 22);
593
594 return hval & (FNHE_HASH_SIZE - 1);
595}
596
597static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe)
598{
599 rt->rt_pmtu = fnhe->fnhe_pmtu;
600 rt->dst.expires = fnhe->fnhe_expires;
601
602 if (fnhe->fnhe_gw) {
603 rt->rt_flags |= RTCF_REDIRECTED;
604 rt->rt_gateway = fnhe->fnhe_gw;
605 rt->rt_uses_gateway = 1;
606 }
607}
608
597static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
598 u32 pmtu, unsigned long expires)
599{
600 struct fnhe_hash_bucket *hash;
601 struct fib_nh_exception *fnhe;
609static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
610 u32 pmtu, unsigned long expires)
611{
612 struct fnhe_hash_bucket *hash;
613 struct fib_nh_exception *fnhe;
614 struct rtable *rt;
615 unsigned int i;
602 int depth;
603 u32 hval = fnhe_hashfun(daddr);
604
605 spin_lock_bh(&fnhe_lock);
606
607 hash = nh->nh_exceptions;
608 if (!hash) {
609 hash = kzalloc(FNHE_HASH_SIZE * sizeof(*hash), GFP_ATOMIC);

--- 12 unchanged lines hidden (view full) ---

622 depth++;
623 }
624
625 if (fnhe) {
626 if (gw)
627 fnhe->fnhe_gw = gw;
628 if (pmtu) {
629 fnhe->fnhe_pmtu = pmtu;
616 int depth;
617 u32 hval = fnhe_hashfun(daddr);
618
619 spin_lock_bh(&fnhe_lock);
620
621 hash = nh->nh_exceptions;
622 if (!hash) {
623 hash = kzalloc(FNHE_HASH_SIZE * sizeof(*hash), GFP_ATOMIC);

--- 12 unchanged lines hidden (view full) ---

636 depth++;
637 }
638
639 if (fnhe) {
640 if (gw)
641 fnhe->fnhe_gw = gw;
642 if (pmtu) {
643 fnhe->fnhe_pmtu = pmtu;
630 fnhe->fnhe_expires = expires;
644 fnhe->fnhe_expires = max(1UL, expires);
631 }
645 }
646 /* Update all cached dsts too */
647 rt = rcu_dereference(fnhe->fnhe_rth);
648 if (rt)
649 fill_route_from_fnhe(rt, fnhe);
632 } else {
633 if (depth > FNHE_RECLAIM_DEPTH)
634 fnhe = fnhe_oldest(hash);
635 else {
636 fnhe = kzalloc(sizeof(*fnhe), GFP_ATOMIC);
637 if (!fnhe)
638 goto out_unlock;
639
640 fnhe->fnhe_next = hash->chain;
641 rcu_assign_pointer(hash->chain, fnhe);
642 }
650 } else {
651 if (depth > FNHE_RECLAIM_DEPTH)
652 fnhe = fnhe_oldest(hash);
653 else {
654 fnhe = kzalloc(sizeof(*fnhe), GFP_ATOMIC);
655 if (!fnhe)
656 goto out_unlock;
657
658 fnhe->fnhe_next = hash->chain;
659 rcu_assign_pointer(hash->chain, fnhe);
660 }
661 fnhe->fnhe_genid = fnhe_genid(dev_net(nh->nh_dev));
643 fnhe->fnhe_daddr = daddr;
644 fnhe->fnhe_gw = gw;
645 fnhe->fnhe_pmtu = pmtu;
646 fnhe->fnhe_expires = expires;
662 fnhe->fnhe_daddr = daddr;
663 fnhe->fnhe_gw = gw;
664 fnhe->fnhe_pmtu = pmtu;
665 fnhe->fnhe_expires = expires;
666
667 /* Exception created; mark the cached routes for the nexthop
668 * stale, so anyone caching it rechecks if this exception
669 * applies to them.
670 */
671 for_each_possible_cpu(i) {
672 struct rtable __rcu **prt;
673 prt = per_cpu_ptr(nh->nh_pcpu_rth_output, i);
674 rt = rcu_dereference(*prt);
675 if (rt)
676 rt->dst.obsolete = DST_OBSOLETE_KILL;
677 }
647 }
648
649 fnhe->fnhe_stamp = jiffies;
650
651out_unlock:
652 spin_unlock_bh(&fnhe_lock);
653 return;
654}

--- 262 unchanged lines hidden (view full) ---

917 return;
918
919 if (dst->dev->mtu < mtu)
920 return;
921
922 if (mtu < ip_rt_min_pmtu)
923 mtu = ip_rt_min_pmtu;
924
678 }
679
680 fnhe->fnhe_stamp = jiffies;
681
682out_unlock:
683 spin_unlock_bh(&fnhe_lock);
684 return;
685}

--- 262 unchanged lines hidden (view full) ---

948 return;
949
950 if (dst->dev->mtu < mtu)
951 return;
952
953 if (mtu < ip_rt_min_pmtu)
954 mtu = ip_rt_min_pmtu;
955
925 if (!rt->rt_pmtu) {
926 dst->obsolete = DST_OBSOLETE_KILL;
927 } else {
928 rt->rt_pmtu = mtu;
929 dst->expires = max(1UL, jiffies + ip_rt_mtu_expires);
930 }
956 if (rt->rt_pmtu == mtu &&
957 time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2))
958 return;
931
932 rcu_read_lock();
933 if (fib_lookup(dev_net(dst->dev), fl4, &res) == 0) {
934 struct fib_nh *nh = &FIB_RES_NH(res);
935
936 update_or_create_fnhe(nh, fl4->daddr, 0, mtu,
937 jiffies + ip_rt_mtu_expires);
938 }

--- 124 unchanged lines hidden (view full) ---

1063static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
1064{
1065 struct rtable *rt = (struct rtable *) dst;
1066
1067 /* All IPV4 dsts are created with ->obsolete set to the value
1068 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1069 * into this function always.
1070 *
959
960 rcu_read_lock();
961 if (fib_lookup(dev_net(dst->dev), fl4, &res) == 0) {
962 struct fib_nh *nh = &FIB_RES_NH(res);
963
964 update_or_create_fnhe(nh, fl4->daddr, 0, mtu,
965 jiffies + ip_rt_mtu_expires);
966 }

--- 124 unchanged lines hidden (view full) ---

1091static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
1092{
1093 struct rtable *rt = (struct rtable *) dst;
1094
1095 /* All IPV4 dsts are created with ->obsolete set to the value
1096 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1097 * into this function always.
1098 *
1071 * When a PMTU/redirect information update invalidates a
1072 * route, this is indicated by setting obsolete to
1073 * DST_OBSOLETE_KILL.
1099 * When a PMTU/redirect information update invalidates a route,
1100 * this is indicated by setting obsolete to DST_OBSOLETE_KILL or
1101 * DST_OBSOLETE_DEAD by dst_free().
1074 */
1102 */
1075 if (dst->obsolete == DST_OBSOLETE_KILL || rt_is_expired(rt))
1103 if (dst->obsolete != DST_OBSOLETE_FORCE_CHK || rt_is_expired(rt))
1076 return NULL;
1077 return dst;
1078}
1079
1080static void ipv4_link_failure(struct sk_buff *skb)
1081{
1082 struct rtable *rt;
1083

--- 125 unchanged lines hidden (view full) ---

1209static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
1210 __be32 daddr)
1211{
1212 bool ret = false;
1213
1214 spin_lock_bh(&fnhe_lock);
1215
1216 if (daddr == fnhe->fnhe_daddr) {
1104 return NULL;
1105 return dst;
1106}
1107
1108static void ipv4_link_failure(struct sk_buff *skb)
1109{
1110 struct rtable *rt;
1111

--- 125 unchanged lines hidden (view full) ---

1237static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
1238 __be32 daddr)
1239{
1240 bool ret = false;
1241
1242 spin_lock_bh(&fnhe_lock);
1243
1244 if (daddr == fnhe->fnhe_daddr) {
1245 int genid = fnhe_genid(dev_net(rt->dst.dev));
1217 struct rtable *orig = rcu_dereference(fnhe->fnhe_rth);
1246 struct rtable *orig = rcu_dereference(fnhe->fnhe_rth);
1218 if (orig && rt_is_expired(orig)) {
1247
1248 if (fnhe->fnhe_genid != genid) {
1249 fnhe->fnhe_genid = genid;
1219 fnhe->fnhe_gw = 0;
1220 fnhe->fnhe_pmtu = 0;
1221 fnhe->fnhe_expires = 0;
1222 }
1250 fnhe->fnhe_gw = 0;
1251 fnhe->fnhe_pmtu = 0;
1252 fnhe->fnhe_expires = 0;
1253 }
1223 if (fnhe->fnhe_pmtu) {
1224 unsigned long expires = fnhe->fnhe_expires;
1225 unsigned long diff = expires - jiffies;
1226
1227 if (time_before(jiffies, expires)) {
1228 rt->rt_pmtu = fnhe->fnhe_pmtu;
1229 dst_set_expires(&rt->dst, diff);
1230 }
1231 }
1232 if (fnhe->fnhe_gw) {
1233 rt->rt_flags |= RTCF_REDIRECTED;
1234 rt->rt_gateway = fnhe->fnhe_gw;
1235 rt->rt_uses_gateway = 1;
1236 } else if (!rt->rt_gateway)
1254 fill_route_from_fnhe(rt, fnhe);
1255 if (!rt->rt_gateway)
1237 rt->rt_gateway = daddr;
1238
1239 rcu_assign_pointer(fnhe->fnhe_rth, rt);
1240 if (orig)
1241 rt_free(orig);
1242
1243 fnhe->fnhe_stamp = jiffies;
1244 ret = true;

--- 1179 unchanged lines hidden (view full) ---

2424}
2425
2426#ifdef CONFIG_SYSCTL
2427static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT;
2428static int ip_rt_gc_interval __read_mostly = 60 * HZ;
2429static int ip_rt_gc_min_interval __read_mostly = HZ / 2;
2430static int ip_rt_gc_elasticity __read_mostly = 8;
2431
1256 rt->rt_gateway = daddr;
1257
1258 rcu_assign_pointer(fnhe->fnhe_rth, rt);
1259 if (orig)
1260 rt_free(orig);
1261
1262 fnhe->fnhe_stamp = jiffies;
1263 ret = true;

--- 1179 unchanged lines hidden (view full) ---

2443}
2444
2445#ifdef CONFIG_SYSCTL
2446static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT;
2447static int ip_rt_gc_interval __read_mostly = 60 * HZ;
2448static int ip_rt_gc_min_interval __read_mostly = HZ / 2;
2449static int ip_rt_gc_elasticity __read_mostly = 8;
2450
2432static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write,
2451static int ipv4_sysctl_rtcache_flush(struct ctl_table *__ctl, int write,
2433 void __user *buffer,
2434 size_t *lenp, loff_t *ppos)
2435{
2452 void __user *buffer,
2453 size_t *lenp, loff_t *ppos)
2454{
2455 struct net *net = (struct net *)__ctl->extra1;
2456
2436 if (write) {
2457 if (write) {
2437 rt_cache_flush((struct net *)__ctl->extra1);
2458 rt_cache_flush(net);
2459 fnhe_genid_bump(net);
2438 return 0;
2439 }
2440
2441 return -EINVAL;
2442}
2443
2460 return 0;
2461 }
2462
2463 return -EINVAL;
2464}
2465
2444static ctl_table ipv4_route_table[] = {
2466static struct ctl_table ipv4_route_table[] = {
2445 {
2446 .procname = "gc_thresh",
2447 .data = &ipv4_dst_ops.gc_thresh,
2448 .maxlen = sizeof(int),
2449 .mode = 0644,
2450 .proc_handler = proc_dointvec,
2451 },
2452 {

--- 151 unchanged lines hidden (view full) ---

2604 .init = sysctl_route_net_init,
2605 .exit = sysctl_route_net_exit,
2606};
2607#endif
2608
2609static __net_init int rt_genid_init(struct net *net)
2610{
2611 atomic_set(&net->rt_genid, 0);
2467 {
2468 .procname = "gc_thresh",
2469 .data = &ipv4_dst_ops.gc_thresh,
2470 .maxlen = sizeof(int),
2471 .mode = 0644,
2472 .proc_handler = proc_dointvec,
2473 },
2474 {

--- 151 unchanged lines hidden (view full) ---

2626 .init = sysctl_route_net_init,
2627 .exit = sysctl_route_net_exit,
2628};
2629#endif
2630
2631static __net_init int rt_genid_init(struct net *net)
2632{
2633 atomic_set(&net->rt_genid, 0);
2634 atomic_set(&net->fnhe_genid, 0);
2612 get_random_bytes(&net->ipv4.dev_addr_genid,
2613 sizeof(net->ipv4.dev_addr_genid));
2614 return 0;
2615}
2616
2617static __net_initdata struct pernet_operations rt_genid_ops = {
2618 .init = rt_genid_init,
2619};

--- 84 unchanged lines hidden ---
2635 get_random_bytes(&net->ipv4.dev_addr_genid,
2636 sizeof(net->ipv4.dev_addr_genid));
2637 return 0;
2638}
2639
2640static __net_initdata struct pernet_operations rt_genid_ops = {
2641 .init = rt_genid_init,
2642};

--- 84 unchanged lines hidden ---