diff options
author | Roopa Prabhu <roopa@cumulusnetworks.com> | 2015-07-21 11:43:49 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-07-21 20:39:04 +0300 |
commit | ffce41962ef64b8e685e5b621caf24bf381addd9 (patch) | |
tree | a731e4ae211389d6ab5f722177379975a918b54f /net/core | |
parent | 19e42e45150672124b6a4341e2bc7982d247f0ac (diff) | |
download | linux-ffce41962ef64b8e685e5b621caf24bf381addd9.tar.xz |
lwtunnel: support dst output redirect function
This patch introduces lwtunnel_output function to call corresponding
lwtunnels output function to xmit the packet.
It adds two variants lwtunnel_output and lwtunnel_output6 for ipv4 and
ipv6 respectively today. But this is subject to change when lwtstate will
reside in dst or dst_metadata (as per upstream discussions).
Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/lwtunnel.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c index d7ae3a235b4b..bb58826c708d 100644 --- a/net/core/lwtunnel.c +++ b/net/core/lwtunnel.c @@ -25,6 +25,7 @@ #include <net/lwtunnel.h> #include <net/rtnetlink.h> +#include <net/ip6_fib.h> struct lwtunnel_state *lwtunnel_state_alloc(int encap_len) { @@ -177,3 +178,58 @@ int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b) return ret; } EXPORT_SYMBOL(lwtunnel_cmp_encap); + +int __lwtunnel_output(struct sock *sk, struct sk_buff *skb, + struct lwtunnel_state *lwtstate) +{ + const struct lwtunnel_encap_ops *ops; + int ret = -EINVAL; + + if (!lwtstate) + goto drop; + + if (lwtstate->type == LWTUNNEL_ENCAP_NONE || + lwtstate->type > LWTUNNEL_ENCAP_MAX) + return 0; + + ret = -EOPNOTSUPP; + rcu_read_lock(); + ops = rcu_dereference(lwtun_encaps[lwtstate->type]); + if (likely(ops && ops->output)) + ret = ops->output(sk, skb); + rcu_read_unlock(); + + if (ret == -EOPNOTSUPP) + goto drop; + + return ret; + +drop: + kfree(skb); + + return ret; +} + +int lwtunnel_output6(struct sock *sk, struct sk_buff *skb) +{ + struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); + struct lwtunnel_state *lwtstate = NULL; + + if (rt) + lwtstate = rt->rt6i_lwtstate; + + return __lwtunnel_output(sk, skb, lwtstate); +} +EXPORT_SYMBOL(lwtunnel_output6); + +int lwtunnel_output(struct sock *sk, struct sk_buff *skb) +{ + struct rtable *rt = (struct rtable *)skb_dst(skb); + struct lwtunnel_state *lwtstate = NULL; + + if (rt) + lwtstate = rt->rt_lwtstate; + + return __lwtunnel_output(sk, skb, lwtstate); +} +EXPORT_SYMBOL(lwtunnel_output); |