aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r--net/ipv4/route.c63
1 files changed, 37 insertions, 26 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 550781a17b34..561a37833d86 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -594,11 +594,25 @@ static inline u32 fnhe_hashfun(__be32 daddr)
594 return hval & (FNHE_HASH_SIZE - 1); 594 return hval & (FNHE_HASH_SIZE - 1);
595} 595}
596 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, 609static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
598 u32 pmtu, unsigned long expires) 610 u32 pmtu, unsigned long expires)
599{ 611{
600 struct fnhe_hash_bucket *hash; 612 struct fnhe_hash_bucket *hash;
601 struct fib_nh_exception *fnhe; 613 struct fib_nh_exception *fnhe;
614 struct rtable *rt;
615 unsigned int i;
602 int depth; 616 int depth;
603 u32 hval = fnhe_hashfun(daddr); 617 u32 hval = fnhe_hashfun(daddr);
604 618
@@ -627,8 +641,12 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
627 fnhe->fnhe_gw = gw; 641 fnhe->fnhe_gw = gw;
628 if (pmtu) { 642 if (pmtu) {
629 fnhe->fnhe_pmtu = 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 { 650 } else {
633 if (depth > FNHE_RECLAIM_DEPTH) 651 if (depth > FNHE_RECLAIM_DEPTH)
634 fnhe = fnhe_oldest(hash); 652 fnhe = fnhe_oldest(hash);
@@ -644,6 +662,18 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
644 fnhe->fnhe_gw = gw; 662 fnhe->fnhe_gw = gw;
645 fnhe->fnhe_pmtu = pmtu; 663 fnhe->fnhe_pmtu = pmtu;
646 fnhe->fnhe_expires = expires; 664 fnhe->fnhe_expires = expires;
665
666 /* Exception created; mark the cached routes for the nexthop
667 * stale, so anyone caching it rechecks if this exception
668 * applies to them.
669 */
670 for_each_possible_cpu(i) {
671 struct rtable __rcu **prt;
672 prt = per_cpu_ptr(nh->nh_pcpu_rth_output, i);
673 rt = rcu_dereference(*prt);
674 if (rt)
675 rt->dst.obsolete = DST_OBSOLETE_KILL;
676 }
647 } 677 }
648 678
649 fnhe->fnhe_stamp = jiffies; 679 fnhe->fnhe_stamp = jiffies;
@@ -917,13 +947,6 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
917 if (mtu < ip_rt_min_pmtu) 947 if (mtu < ip_rt_min_pmtu)
918 mtu = ip_rt_min_pmtu; 948 mtu = ip_rt_min_pmtu;
919 949
920 if (!rt->rt_pmtu) {
921 dst->obsolete = DST_OBSOLETE_KILL;
922 } else {
923 rt->rt_pmtu = mtu;
924 dst->expires = max(1UL, jiffies + ip_rt_mtu_expires);
925 }
926
927 rcu_read_lock(); 950 rcu_read_lock();
928 if (fib_lookup(dev_net(dst->dev), fl4, &res) == 0) { 951 if (fib_lookup(dev_net(dst->dev), fl4, &res) == 0) {
929 struct fib_nh *nh = &FIB_RES_NH(res); 952 struct fib_nh *nh = &FIB_RES_NH(res);
@@ -1063,11 +1086,11 @@ static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie)
1063 * DST_OBSOLETE_FORCE_CHK which forces validation calls down 1086 * DST_OBSOLETE_FORCE_CHK which forces validation calls down
1064 * into this function always. 1087 * into this function always.
1065 * 1088 *
1066 * When a PMTU/redirect information update invalidates a 1089 * When a PMTU/redirect information update invalidates a route,
1067 * route, this is indicated by setting obsolete to 1090 * this is indicated by setting obsolete to DST_OBSOLETE_KILL or
1068 * DST_OBSOLETE_KILL. 1091 * DST_OBSOLETE_DEAD by dst_free().
1069 */ 1092 */
1070 if (dst->obsolete == DST_OBSOLETE_KILL || rt_is_expired(rt)) 1093 if (dst->obsolete != DST_OBSOLETE_FORCE_CHK || rt_is_expired(rt))
1071 return NULL; 1094 return NULL;
1072 return dst; 1095 return dst;
1073} 1096}
@@ -1215,20 +1238,8 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
1215 fnhe->fnhe_pmtu = 0; 1238 fnhe->fnhe_pmtu = 0;
1216 fnhe->fnhe_expires = 0; 1239 fnhe->fnhe_expires = 0;
1217 } 1240 }
1218 if (fnhe->fnhe_pmtu) { 1241 fill_route_from_fnhe(rt, fnhe);
1219 unsigned long expires = fnhe->fnhe_expires; 1242 if (!rt->rt_gateway)
1220 unsigned long diff = expires - jiffies;
1221
1222 if (time_before(jiffies, expires)) {
1223 rt->rt_pmtu = fnhe->fnhe_pmtu;
1224 dst_set_expires(&rt->dst, diff);
1225 }
1226 }
1227 if (fnhe->fnhe_gw) {
1228 rt->rt_flags |= RTCF_REDIRECTED;
1229 rt->rt_gateway = fnhe->fnhe_gw;
1230 rt->rt_uses_gateway = 1;
1231 } else if (!rt->rt_gateway)
1232 rt->rt_gateway = daddr; 1243 rt->rt_gateway = daddr;
1233 1244
1234 rcu_assign_pointer(fnhe->fnhe_rth, rt); 1245 rcu_assign_pointer(fnhe->fnhe_rth, rt);