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 --- |