diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
| -rw-r--r-- | net/ipv6/ip6_output.c | 70 | 
1 files changed, 70 insertions, 0 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 087304427bbb..8a8c2d0cfcc8 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -54,6 +54,7 @@  #include <linux/mroute6.h>  #include <net/l3mdev.h>  #include <net/lwtunnel.h> +#include <net/ip_tunnels.h>  static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)  { @@ -1196,6 +1197,75 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,  }  EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); +/** + *      ip6_dst_lookup_tunnel - perform route lookup on tunnel + *      @skb: Packet for which lookup is done + *      @dev: Tunnel device + *      @net: Network namespace of tunnel device + *      @sk: Socket which provides route info + *      @saddr: Memory to store the src ip address + *      @info: Tunnel information + *      @protocol: IP protocol + *      @use_cahce: Flag to enable cache usage + *      This function performs a route lookup on a tunnel + * + *      It returns a valid dst pointer and stores src address to be used in + *      tunnel in param saddr on success, else a pointer encoded error code. + */ + +struct dst_entry *ip6_dst_lookup_tunnel(struct sk_buff *skb, +					struct net_device *dev, +					struct net *net, +					struct socket *sock, +					struct in6_addr *saddr, +					const struct ip_tunnel_info *info, +					u8 protocol, +					bool use_cache) +{ +	struct dst_entry *dst = NULL; +#ifdef CONFIG_DST_CACHE +	struct dst_cache *dst_cache; +#endif +	struct flowi6 fl6; +	__u8 prio; + +#ifdef CONFIG_DST_CACHE +	dst_cache = (struct dst_cache *)&info->dst_cache; +	if (use_cache) { +		dst = dst_cache_get_ip6(dst_cache, saddr); +		if (dst) +			return dst; +	} +#endif +	memset(&fl6, 0, sizeof(fl6)); +	fl6.flowi6_mark = skb->mark; +	fl6.flowi6_proto = protocol; +	fl6.daddr = info->key.u.ipv6.dst; +	fl6.saddr = info->key.u.ipv6.src; +	prio = info->key.tos; +	fl6.flowlabel = ip6_make_flowinfo(RT_TOS(prio), +					  info->key.label); + +	dst = ipv6_stub->ipv6_dst_lookup_flow(net, sock->sk, &fl6, +					      NULL); +	if (IS_ERR(dst)) { +		netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr); +		return ERR_PTR(-ENETUNREACH); +	} +	if (dst->dev == dev) { /* is this necessary? */ +		netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr); +		dst_release(dst); +		return ERR_PTR(-ELOOP); +	} +#ifdef CONFIG_DST_CACHE +	if (use_cache) +		dst_cache_set_ip6(dst_cache, dst, &fl6.saddr); +#endif +	*saddr = fl6.saddr; +	return dst; +} +EXPORT_SYMBOL_GPL(ip6_dst_lookup_tunnel); +  static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src,  					       gfp_t gfp)  {  |