|
@@ -1206,11 +1206,15 @@ static inline void rt_free(struct rtable *rt)
|
|
|
|
|
|
static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
|
|
|
{
|
|
|
- struct rtable *orig, *prev, **p = (struct rtable **)&nh->nh_rth_output;
|
|
|
+ struct rtable *orig, *prev, **p;
|
|
|
|
|
|
- if (rt_is_input_route(rt))
|
|
|
+ if (rt_is_input_route(rt)) {
|
|
|
p = (struct rtable **)&nh->nh_rth_input;
|
|
|
-
|
|
|
+ } else {
|
|
|
+ if (!nh->nh_pcpu_rth_output)
|
|
|
+ goto nocache;
|
|
|
+ p = (struct rtable **)__this_cpu_ptr(nh->nh_pcpu_rth_output);
|
|
|
+ }
|
|
|
orig = *p;
|
|
|
|
|
|
prev = cmpxchg(p, orig, rt);
|
|
@@ -1223,6 +1227,7 @@ static void rt_cache_route(struct fib_nh *nh, struct rtable *rt)
|
|
|
* unsuccessful at storing this route into the cache
|
|
|
* we really need to set it.
|
|
|
*/
|
|
|
+nocache:
|
|
|
rt->dst.flags |= DST_NOCACHE;
|
|
|
}
|
|
|
}
|
|
@@ -1749,8 +1754,11 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
|
|
|
fnhe = NULL;
|
|
|
if (fi) {
|
|
|
fnhe = find_exception(&FIB_RES_NH(*res), fl4->daddr);
|
|
|
- if (!fnhe) {
|
|
|
- rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_output);
|
|
|
+ if (!fnhe && FIB_RES_NH(*res).nh_pcpu_rth_output) {
|
|
|
+ struct rtable __rcu **prth;
|
|
|
+
|
|
|
+ prth = __this_cpu_ptr(FIB_RES_NH(*res).nh_pcpu_rth_output);
|
|
|
+ rth = rcu_dereference(*prth);
|
|
|
if (rt_cache_valid(rth)) {
|
|
|
dst_hold(&rth->dst);
|
|
|
return rth;
|