diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index c48ea87..85d6d9f 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -105,6 +105,8 @@ #define rt6i_expires u.dst.expires struct rt6key rt6i_src; u8 rt6i_protocol; + + u32 rt6i_flow_cache_genid; }; static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 116f94a..f389322 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -139,6 +139,36 @@ void inet6_csk_addr2sockaddr(struct sock EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr); +static inline +void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst, + struct in6_addr *daddr, struct in6_addr *saddr) +{ + struct rt6_info *rt = (struct rt6_info *)dst; + + __ip6_dst_store(sk, dst, daddr, saddr); + rt->rt6i_flow_cache_genid = atomic_read(&flow_cache_genid); +} + +static inline +struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie) +{ + struct dst_entry *dst; + struct rt6_info *rt; + + dst = __sk_dst_check(sk, cookie); + if (!dst) + goto end; + + rt = (struct rt6_info *)dst; + if (rt->rt6i_flow_cache_genid != atomic_read(&flow_cache_genid)) { + sk->sk_dst_cache = NULL; + dst_release(dst); + dst = NULL; + } + end: + return dst; +} + int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) { struct sock *sk = skb->sk; @@ -166,7 +196,7 @@ int inet6_csk_xmit(struct sk_buff *skb, final_p = &final; } - dst = __sk_dst_check(sk, np->dst_cookie); + dst = __inet6_csk_dst_check(sk, np->dst_cookie); if (dst == NULL) { int err = ip6_dst_lookup(sk, &dst, &fl); @@ -186,7 +216,7 @@ int inet6_csk_xmit(struct sk_buff *skb, return err; } - __ip6_dst_store(sk, dst, NULL, NULL); + __inet6_csk_dst_store(sk, dst, NULL, NULL); } skb->dst = dst_clone(dst); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 50d86e9..1fcfc00 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -441,8 +441,11 @@ int ip6_forward(struct sk_buff *skb) /* IPv6 specs say nothing about it, but it is clear that we cannot send redirects to source routed frames. + We don't send it to transformed ones either, since they should + be decapsulated from IPsec tunnel. */ - if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0) { + if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0 && + !skb->sp) { struct in6_addr *target = NULL; struct rt6_info *rt; struct neighbour *n = dst->neighbour;