Skip to content

Commit 2536862

Browse files
tomratbertdavem330
authored andcommitted
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 <tom@herbertland.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent f376d4a commit 2536862

File tree

4 files changed

+98
-3
lines changed

4 files changed

+98
-3
lines changed

include/net/lwtunnel.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@
1111
#define LWTUNNEL_HASH_SIZE (1 << LWTUNNEL_HASH_BITS)
1212

1313
/* lw tunnel state flags */
14-
#define LWTUNNEL_STATE_OUTPUT_REDIRECT 0x1
14+
#define LWTUNNEL_STATE_OUTPUT_REDIRECT BIT(0)
15+
#define LWTUNNEL_STATE_INPUT_REDIRECT BIT(1)
1516

1617
struct lwtunnel_state {
1718
__u16 type;
1819
__u16 flags;
1920
atomic_t refcnt;
21+
int (*orig_output)(struct sock *sk, struct sk_buff *skb);
22+
int (*orig_input)(struct sk_buff *);
2023
int len;
2124
__u8 data[0];
2225
};
@@ -25,6 +28,7 @@ struct lwtunnel_encap_ops {
2528
int (*build_state)(struct net_device *dev, struct nlattr *encap,
2629
struct lwtunnel_state **ts);
2730
int (*output)(struct sock *sk, struct sk_buff *skb);
31+
int (*input)(struct sk_buff *skb);
2832
int (*fill_encap)(struct sk_buff *skb,
2933
struct lwtunnel_state *lwtstate);
3034
int (*get_encap_size)(struct lwtunnel_state *lwtstate);
@@ -58,6 +62,13 @@ static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate)
5862
return false;
5963
}
6064

65+
static inline bool lwtunnel_input_redirect(struct lwtunnel_state *lwtstate)
66+
{
67+
if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_INPUT_REDIRECT))
68+
return true;
69+
70+
return false;
71+
}
6172
int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
6273
unsigned int num);
6374
int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
@@ -72,6 +83,8 @@ struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len);
7283
int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b);
7384
int lwtunnel_output(struct sock *sk, struct sk_buff *skb);
7485
int lwtunnel_output6(struct sock *sk, struct sk_buff *skb);
86+
int lwtunnel_input(struct sk_buff *skb);
87+
int lwtunnel_input6(struct sk_buff *skb);
7588

7689
#else
7790

@@ -90,6 +103,11 @@ static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate)
90103
return false;
91104
}
92105

106+
static inline bool lwtunnel_input_redirect(struct lwtunnel_state *lwtstate)
107+
{
108+
return false;
109+
}
110+
93111
static inline int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op,
94112
unsigned int num)
95113
{
@@ -142,6 +160,16 @@ static inline int lwtunnel_output6(struct sock *sk, struct sk_buff *skb)
142160
return -EOPNOTSUPP;
143161
}
144162

163+
static inline int lwtunnel_input(struct sk_buff *skb)
164+
{
165+
return -EOPNOTSUPP;
166+
}
167+
168+
static inline int lwtunnel_input6(struct sk_buff *skb)
169+
{
170+
return -EOPNOTSUPP;
171+
}
172+
145173
#endif
146174

147175
#endif /* __NET_LWTUNNEL_H */

net/core/lwtunnel.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,3 +241,58 @@ int lwtunnel_output(struct sock *sk, struct sk_buff *skb)
241241
return __lwtunnel_output(sk, skb, lwtstate);
242242
}
243243
EXPORT_SYMBOL(lwtunnel_output);
244+
245+
int __lwtunnel_input(struct sk_buff *skb,
246+
struct lwtunnel_state *lwtstate)
247+
{
248+
const struct lwtunnel_encap_ops *ops;
249+
int ret = -EINVAL;
250+
251+
if (!lwtstate)
252+
goto drop;
253+
254+
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
255+
lwtstate->type > LWTUNNEL_ENCAP_MAX)
256+
return 0;
257+
258+
ret = -EOPNOTSUPP;
259+
rcu_read_lock();
260+
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
261+
if (likely(ops && ops->input))
262+
ret = ops->input(skb);
263+
rcu_read_unlock();
264+
265+
if (ret == -EOPNOTSUPP)
266+
goto drop;
267+
268+
return ret;
269+
270+
drop:
271+
kfree_skb(skb);
272+
273+
return ret;
274+
}
275+
276+
int lwtunnel_input6(struct sk_buff *skb)
277+
{
278+
struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
279+
struct lwtunnel_state *lwtstate = NULL;
280+
281+
if (rt)
282+
lwtstate = rt->rt6i_lwtstate;
283+
284+
return __lwtunnel_input(skb, lwtstate);
285+
}
286+
EXPORT_SYMBOL(lwtunnel_input6);
287+
288+
int lwtunnel_input(struct sk_buff *skb)
289+
{
290+
struct rtable *rt = (struct rtable *)skb_dst(skb);
291+
struct lwtunnel_state *lwtstate = NULL;
292+
293+
if (rt)
294+
lwtstate = rt->rt_lwtstate;
295+
296+
return __lwtunnel_input(skb, lwtstate);
297+
}
298+
EXPORT_SYMBOL(lwtunnel_input);

net/ipv4/route.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1631,8 +1631,14 @@ static int __mkroute_input(struct sk_buff *skb,
16311631
rth->dst.output = ip_output;
16321632

16331633
rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag);
1634-
if (lwtunnel_output_redirect(rth->rt_lwtstate))
1634+
if (lwtunnel_output_redirect(rth->rt_lwtstate)) {
1635+
rth->rt_lwtstate->orig_output = rth->dst.output;
16351636
rth->dst.output = lwtunnel_output;
1637+
}
1638+
if (lwtunnel_input_redirect(rth->rt_lwtstate)) {
1639+
rth->rt_lwtstate->orig_input = rth->dst.input;
1640+
rth->dst.input = lwtunnel_input;
1641+
}
16361642
skb_dst_set(skb, &rth->dst);
16371643
out:
16381644
err = 0;

net/ipv6/route.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1785,8 +1785,14 @@ int ip6_route_add(struct fib6_config *cfg)
17851785
if (err)
17861786
goto out;
17871787
rt->rt6i_lwtstate = lwtstate_get(lwtstate);
1788-
if (lwtunnel_output_redirect(rt->rt6i_lwtstate))
1788+
if (lwtunnel_output_redirect(rt->rt6i_lwtstate)) {
1789+
rt->rt6i_lwtstate->orig_output = rt->dst.output;
17891790
rt->dst.output = lwtunnel_output6;
1791+
}
1792+
if (lwtunnel_input_redirect(rt->rt6i_lwtstate)) {
1793+
rt->rt6i_lwtstate->orig_input = rt->dst.input;
1794+
rt->dst.input = lwtunnel_input6;
1795+
}
17901796
}
17911797

17921798
ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);

0 commit comments

Comments
 (0)