Skip to content

Commit 387aa65

Browse files
fableddavem330
authored andcommitted
ipv4: properly refresh rtable entries on pmtu/redirect events
This reverts commit 05ab86c (xfrm4: Invalidate all ipv4 routes on IPsec pmtu events). Flushing all cached entries is not needed. Instead, invalidate only the related next hop dsts to recheck for the added next hop exception where needed. This also fixes a subtle race due to bumping generation id's before updating the pmtu. Cc: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Timo Teräs <timo.teras@iki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 829a507 commit 387aa65

File tree

4 files changed

+43
-41
lines changed

4 files changed

+43
-41
lines changed

net/ipv4/ah4.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -419,12 +419,9 @@ static void ah4_err(struct sk_buff *skb, u32 info)
419419
if (!x)
420420
return;
421421

422-
if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
423-
atomic_inc(&flow_cache_genid);
424-
rt_genid_bump(net);
425-
422+
if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
426423
ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
427-
} else
424+
else
428425
ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0);
429426
xfrm_state_put(x);
430427
}

net/ipv4/esp4.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -502,12 +502,9 @@ static void esp4_err(struct sk_buff *skb, u32 info)
502502
if (!x)
503503
return;
504504

505-
if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
506-
atomic_inc(&flow_cache_genid);
507-
rt_genid_bump(net);
508-
505+
if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
509506
ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
510-
} else
507+
else
511508
ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0);
512509
xfrm_state_put(x);
513510
}

net/ipv4/ipcomp.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,9 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
4747
if (!x)
4848
return;
4949

50-
if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
51-
atomic_inc(&flow_cache_genid);
52-
rt_genid_bump(net);
53-
50+
if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
5451
ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
55-
} else
52+
else
5653
ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0);
5754
xfrm_state_put(x);
5855
}

net/ipv4/route.c

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -594,11 +594,25 @@ static inline u32 fnhe_hashfun(__be32 daddr)
594594
return hval & (FNHE_HASH_SIZE - 1);
595595
}
596596

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+
597609
static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
598610
u32 pmtu, unsigned long expires)
599611
{
600612
struct fnhe_hash_bucket *hash;
601613
struct fib_nh_exception *fnhe;
614+
struct rtable *rt;
615+
unsigned int i;
602616
int depth;
603617
u32 hval = fnhe_hashfun(daddr);
604618

@@ -627,8 +641,12 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
627641
fnhe->fnhe_gw = gw;
628642
if (pmtu) {
629643
fnhe->fnhe_pmtu = pmtu;
630-
fnhe->fnhe_expires = expires;
644+
fnhe->fnhe_expires = max(1UL, expires);
631645
}
646+
/* Update all cached dsts too */
647+
rt = rcu_dereference(fnhe->fnhe_rth);
648+
if (rt)
649+
fill_route_from_fnhe(rt, fnhe);
632650
} else {
633651
if (depth > FNHE_RECLAIM_DEPTH)
634652
fnhe = fnhe_oldest(hash);
@@ -644,6 +662,18 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
644662
fnhe->fnhe_gw = gw;
645663
fnhe->fnhe_pmtu = pmtu;
646664
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+
}
647677
}
648678

649679
fnhe->fnhe_stamp = jiffies;
@@ -917,13 +947,6 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
917947
if (mtu < ip_rt_min_pmtu)
918948
mtu = ip_rt_min_pmtu;
919949

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-
927950
rcu_read_lock();
928951
if (fib_lookup(dev_net(dst->dev), fl4, &res) == 0) {
929952
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)
10631086
* DST_OBSOLETE_FORCE_CHK which forces validation calls down
10641087
* into this function always.
10651088
*
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().
10691092
*/
1070-
if (dst->obsolete == DST_OBSOLETE_KILL || rt_is_expired(rt))
1093+
if (dst->obsolete != DST_OBSOLETE_FORCE_CHK || rt_is_expired(rt))
10711094
return NULL;
10721095
return dst;
10731096
}
@@ -1215,20 +1238,8 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
12151238
fnhe->fnhe_pmtu = 0;
12161239
fnhe->fnhe_expires = 0;
12171240
}
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)
12321243
rt->rt_gateway = daddr;
12331244

12341245
rcu_assign_pointer(fnhe->fnhe_rth, rt);

0 commit comments

Comments
 (0)