aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ah4.c7
-rw-r--r--net/ipv4/esp4.c7
-rw-r--r--net/ipv4/ipcomp.c7
-rw-r--r--net/ipv4/route.c63
4 files changed, 43 insertions, 41 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 2e7f1948216f..717902669d2f 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -419,12 +419,9 @@ static void ah4_err(struct sk_buff *skb, u32 info)
419 if (!x) 419 if (!x)
420 return; 420 return;
421 421
422 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) { 422 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
423 atomic_inc(&flow_cache_genid);
424 rt_genid_bump(net);
425
426 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0); 423 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
427 } else 424 else
428 ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0); 425 ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0);
429 xfrm_state_put(x); 426 xfrm_state_put(x);
430} 427}
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 4cfe34d4cc96..ab3d814bc80a 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -502,12 +502,9 @@ static void esp4_err(struct sk_buff *skb, u32 info)
502 if (!x) 502 if (!x)
503 return; 503 return;
504 504
505 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) { 505 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
506 atomic_inc(&flow_cache_genid);
507 rt_genid_bump(net);
508
509 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0); 506 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
510 } else 507 else
511 ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0); 508 ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0);
512 xfrm_state_put(x); 509 xfrm_state_put(x);
513} 510}
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 59cb8c769056..826be4cb482a 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -47,12 +47,9 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
47 if (!x) 47 if (!x)
48 return; 48 return;
49 49
50 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) { 50 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
51 atomic_inc(&flow_cache_genid);
52 rt_genid_bump(net);
53
54 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0); 51 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
55 } else 52 else
56 ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0); 53 ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0);
57 xfrm_state_put(x); 54 xfrm_state_put(x);
58} 55}
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);