spin_unlock_bh(&fnhe_lock);
 }
 
+static void set_lwt_redirect(struct rtable *rth)
+{
+       if (lwtunnel_output_redirect(rth->dst.lwtstate)) {
+               rth->dst.lwtstate->orig_output = rth->dst.output;
+               rth->dst.output = lwtunnel_output;
+       }
+
+       if (lwtunnel_input_redirect(rth->dst.lwtstate)) {
+               rth->dst.lwtstate->orig_input = rth->dst.input;
+               rth->dst.input = lwtunnel_input;
+       }
+}
+
 /* called in rcu_read_lock() section */
 static int __mkroute_input(struct sk_buff *skb,
                           const struct fib_result *res,
        rth->dst.input = ip_forward;
 
        rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag);
-       if (lwtunnel_output_redirect(rth->dst.lwtstate)) {
-               rth->dst.lwtstate->orig_output = rth->dst.output;
-               rth->dst.output = lwtunnel_output;
-       }
-       if (lwtunnel_input_redirect(rth->dst.lwtstate)) {
-               rth->dst.lwtstate->orig_input = rth->dst.input;
-               rth->dst.input = lwtunnel_input;
-       }
+       set_lwt_redirect(rth);
        skb_dst_set(skb, &rth->dst);
 out:
        err = 0;
                rth->dst.error= -err;
                rth->rt_flags   &= ~RTCF_LOCAL;
        }
+
        if (do_cache) {
-               if (unlikely(!rt_cache_route(&FIB_RES_NH(res), rth))) {
+               struct fib_nh *nh = &FIB_RES_NH(res);
+
+               rth->dst.lwtstate = lwtstate_get(nh->nh_lwtstate);
+               if (lwtunnel_input_redirect(rth->dst.lwtstate)) {
+                       WARN_ON(rth->dst.input == lwtunnel_input);
+                       rth->dst.lwtstate->orig_input = rth->dst.input;
+                       rth->dst.input = lwtunnel_input;
+               }
+
+               if (unlikely(!rt_cache_route(nh, rth))) {
                        rth->dst.flags |= DST_NOCACHE;
                        rt_add_uncached_list(rth);
                }
        }
 
        rt_set_nexthop(rth, fl4->daddr, res, fnhe, fi, type, 0);
-       if (lwtunnel_output_redirect(rth->dst.lwtstate)) {
-               rth->dst.lwtstate->orig_output = rth->dst.output;
-               rth->dst.output = lwtunnel_output;
-       }
+       set_lwt_redirect(rth);
 
        return rth;
 }