lwt: Add support to redirect dst.input

This patch adds the capability to redirect dst input in the same way
that dst output is redirected by LWT.

Also, save the original dst.input and and dst.out when setting up
lwtunnel redirection. These can be called by the client as a pass-
through.

Signed-off-by: Tom Herbert <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
Tom Herbert 2015-08-17 13:42:24 -07:00 • committed by David S. Miller
commit 2536862311
4 changed files with 98 additions and 3 deletions

View file

@ -241,3 +241,58 @@ int lwtunnel_output(struct sock *sk, struct sk_buff *skb)
return __lwtunnel_output(sk, skb, lwtstate);
}
EXPORT_SYMBOL(lwtunnel_output);
int __lwtunnel_input(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->input))
ret = ops->input(skb);
rcu_read_unlock();
if (ret == -EOPNOTSUPP)
goto drop;
return ret;
drop:
kfree_skb(skb);
return ret;
}
int lwtunnel_input6(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_input(skb, lwtstate);
}
EXPORT_SYMBOL(lwtunnel_input6);
int lwtunnel_input(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_input(skb, lwtstate);
}
EXPORT_SYMBOL(lwtunnel_input);

View file

@ -1631,8 +1631,14 @@ static int __mkroute_input(struct sk_buff *skb,
rth->dst.output = ip_output;
rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag);
if (lwtunnel_output_redirect(rth->rt_lwtstate))
if (lwtunnel_output_redirect(rth->rt_lwtstate)) {
rth->rt_lwtstate->orig_output = rth->dst.output;
rth->dst.output = lwtunnel_output;
}
if (lwtunnel_input_redirect(rth->rt_lwtstate)) {
rth->rt_lwtstate->orig_input = rth->dst.input;
rth->dst.input = lwtunnel_input;
}
skb_dst_set(skb, &rth->dst);
out:
err = 0;

View file

@ -1785,8 +1785,14 @@ int ip6_route_add(struct fib6_config *cfg)
if (err)
goto out;
rt->rt6i_lwtstate = lwtstate_get(lwtstate);
if (lwtunnel_output_redirect(rt->rt6i_lwtstate))
if (lwtunnel_output_redirect(rt->rt6i_lwtstate)) {
rt->rt6i_lwtstate->orig_output = rt->dst.output;
rt->dst.output = lwtunnel_output6;
}
if (lwtunnel_input_redirect(rt->rt6i_lwtstate)) {
rt->rt6i_lwtstate->orig_input = rt->dst.input;
rt->dst.input = lwtunnel_input6;
}
}
ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);