2 * lwtunnel Infrastructure for light weight tunnels like mpls
4 * Authors: Roopa Prabhu, <roopa@cumulusnetworks.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
13 #include <linux/capability.h>
14 #include <linux/module.h>
15 #include <linux/types.h>
16 #include <linux/kernel.h>
17 #include <linux/slab.h>
18 #include <linux/uaccess.h>
19 #include <linux/skbuff.h>
20 #include <linux/netdevice.h>
21 #include <linux/lwtunnel.h>
23 #include <linux/init.h>
24 #include <linux/err.h>
26 #include <net/lwtunnel.h>
27 #include <net/rtnetlink.h>
28 #include <net/ip6_fib.h>
30 struct lwtunnel_state
*lwtunnel_state_alloc(int encap_len
)
32 struct lwtunnel_state
*lws
;
34 lws
= kzalloc(sizeof(*lws
) + encap_len
, GFP_ATOMIC
);
38 EXPORT_SYMBOL(lwtunnel_state_alloc
);
40 static const struct lwtunnel_encap_ops __rcu
*
41 lwtun_encaps
[LWTUNNEL_ENCAP_MAX
+ 1] __read_mostly
;
43 int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops
*ops
,
46 if (num
> LWTUNNEL_ENCAP_MAX
)
49 return !cmpxchg((const struct lwtunnel_encap_ops
**)
53 EXPORT_SYMBOL(lwtunnel_encap_add_ops
);
55 int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops
*ops
,
56 unsigned int encap_type
)
60 if (encap_type
== LWTUNNEL_ENCAP_NONE
||
61 encap_type
> LWTUNNEL_ENCAP_MAX
)
64 ret
= (cmpxchg((const struct lwtunnel_encap_ops
**)
65 &lwtun_encaps
[encap_type
],
66 ops
, NULL
) == ops
) ? 0 : -1;
72 EXPORT_SYMBOL(lwtunnel_encap_del_ops
);
74 int lwtunnel_build_state(struct net_device
*dev
, u16 encap_type
,
75 struct nlattr
*encap
, unsigned int family
,
76 const void *cfg
, struct lwtunnel_state
**lws
)
78 const struct lwtunnel_encap_ops
*ops
;
81 if (encap_type
== LWTUNNEL_ENCAP_NONE
||
82 encap_type
> LWTUNNEL_ENCAP_MAX
)
87 ops
= rcu_dereference(lwtun_encaps
[encap_type
]);
88 if (likely(ops
&& ops
->build_state
))
89 ret
= ops
->build_state(dev
, encap
, family
, cfg
, lws
);
94 EXPORT_SYMBOL(lwtunnel_build_state
);
96 int lwtunnel_fill_encap(struct sk_buff
*skb
, struct lwtunnel_state
*lwtstate
)
98 const struct lwtunnel_encap_ops
*ops
;
105 if (lwtstate
->type
== LWTUNNEL_ENCAP_NONE
||
106 lwtstate
->type
> LWTUNNEL_ENCAP_MAX
)
110 nest
= nla_nest_start(skb
, RTA_ENCAP
);
112 ops
= rcu_dereference(lwtun_encaps
[lwtstate
->type
]);
113 if (likely(ops
&& ops
->fill_encap
))
114 ret
= ops
->fill_encap(skb
, lwtstate
);
118 goto nla_put_failure
;
119 nla_nest_end(skb
, nest
);
120 ret
= nla_put_u16(skb
, RTA_ENCAP_TYPE
, lwtstate
->type
);
122 goto nla_put_failure
;
127 nla_nest_cancel(skb
, nest
);
129 return (ret
== -EOPNOTSUPP
? 0 : ret
);
131 EXPORT_SYMBOL(lwtunnel_fill_encap
);
133 int lwtunnel_get_encap_size(struct lwtunnel_state
*lwtstate
)
135 const struct lwtunnel_encap_ops
*ops
;
141 if (lwtstate
->type
== LWTUNNEL_ENCAP_NONE
||
142 lwtstate
->type
> LWTUNNEL_ENCAP_MAX
)
146 ops
= rcu_dereference(lwtun_encaps
[lwtstate
->type
]);
147 if (likely(ops
&& ops
->get_encap_size
))
148 ret
= nla_total_size(ops
->get_encap_size(lwtstate
));
153 EXPORT_SYMBOL(lwtunnel_get_encap_size
);
155 int lwtunnel_cmp_encap(struct lwtunnel_state
*a
, struct lwtunnel_state
*b
)
157 const struct lwtunnel_encap_ops
*ops
;
166 if (a
->type
!= b
->type
)
169 if (a
->type
== LWTUNNEL_ENCAP_NONE
||
170 a
->type
> LWTUNNEL_ENCAP_MAX
)
174 ops
= rcu_dereference(lwtun_encaps
[a
->type
]);
175 if (likely(ops
&& ops
->cmp_encap
))
176 ret
= ops
->cmp_encap(a
, b
);
181 EXPORT_SYMBOL(lwtunnel_cmp_encap
);
183 int lwtunnel_output(struct net
*net
, struct sock
*sk
, struct sk_buff
*skb
)
185 struct dst_entry
*dst
= skb_dst(skb
);
186 const struct lwtunnel_encap_ops
*ops
;
187 struct lwtunnel_state
*lwtstate
;
192 lwtstate
= dst
->lwtstate
;
194 if (lwtstate
->type
== LWTUNNEL_ENCAP_NONE
||
195 lwtstate
->type
> LWTUNNEL_ENCAP_MAX
)
200 ops
= rcu_dereference(lwtun_encaps
[lwtstate
->type
]);
201 if (likely(ops
&& ops
->output
))
202 ret
= ops
->output(net
, sk
, skb
);
205 if (ret
== -EOPNOTSUPP
)
215 EXPORT_SYMBOL(lwtunnel_output
);
217 int lwtunnel_input(struct sk_buff
*skb
)
219 struct dst_entry
*dst
= skb_dst(skb
);
220 const struct lwtunnel_encap_ops
*ops
;
221 struct lwtunnel_state
*lwtstate
;
226 lwtstate
= dst
->lwtstate
;
228 if (lwtstate
->type
== LWTUNNEL_ENCAP_NONE
||
229 lwtstate
->type
> LWTUNNEL_ENCAP_MAX
)
234 ops
= rcu_dereference(lwtun_encaps
[lwtstate
->type
]);
235 if (likely(ops
&& ops
->input
))
236 ret
= ops
->input(skb
);
239 if (ret
== -EOPNOTSUPP
)
249 EXPORT_SYMBOL(lwtunnel_input
);