@@ -594,11 +594,25 @@ static inline u32 fnhe_hashfun(__be32 daddr)
594
594
return hval & (FNHE_HASH_SIZE - 1 );
595
595
}
596
596
597
+ static 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
+
597
609
static void update_or_create_fnhe (struct fib_nh * nh , __be32 daddr , __be32 gw ,
598
610
u32 pmtu , unsigned long expires )
599
611
{
600
612
struct fnhe_hash_bucket * hash ;
601
613
struct fib_nh_exception * fnhe ;
614
+ struct rtable * rt ;
615
+ unsigned int i ;
602
616
int depth ;
603
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
641
fnhe -> fnhe_gw = gw ;
628
642
if (pmtu ) {
629
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
650
} else {
633
651
if (depth > FNHE_RECLAIM_DEPTH )
634
652
fnhe = fnhe_oldest (hash );
@@ -644,6 +662,18 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
644
662
fnhe -> fnhe_gw = gw ;
645
663
fnhe -> fnhe_pmtu = pmtu ;
646
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
679
fnhe -> fnhe_stamp = jiffies ;
@@ -917,13 +947,6 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
917
947
if (mtu < ip_rt_min_pmtu )
918
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
950
rcu_read_lock ();
928
951
if (fib_lookup (dev_net (dst -> dev ), fl4 , & res ) == 0 ) {
929
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
1086
* DST_OBSOLETE_FORCE_CHK which forces validation calls down
1064
1087
* into this function always.
1065
1088
*
1066
- * When a PMTU/redirect information update invalidates a
1067
- * route, this is indicated by setting obsolete to
1068
- * DST_OBSOLETE_KILL .
1089
+ * When a PMTU/redirect information update invalidates a route,
1090
+ * this is indicated by setting obsolete to DST_OBSOLETE_KILL or
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
1094
return NULL ;
1072
1095
return dst ;
1073
1096
}
@@ -1215,20 +1238,8 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
1215
1238
fnhe -> fnhe_pmtu = 0 ;
1216
1239
fnhe -> fnhe_expires = 0 ;
1217
1240
}
1218
- if (fnhe -> fnhe_pmtu ) {
1219
- unsigned long expires = fnhe -> fnhe_expires ;
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 )
1241
+ fill_route_from_fnhe (rt , fnhe );
1242
+ if (!rt -> rt_gateway )
1232
1243
rt -> rt_gateway = daddr ;
1233
1244
1234
1245
rcu_assign_pointer (fnhe -> fnhe_rth , rt );
0 commit comments