aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorSimon Horman <simon.horman@netronome.com>2016-07-07 01:56:12 -0400
committerDavid S. Miller <davem@davemloft.net>2016-07-09 17:45:56 -0400
commit8afe97e5d4165c9d181d42504af3f96c8427659a (patch)
tree5a38e2b771aa9f07d77ed523b16c4e59243deb72 /net/ipv4
parenta65056ecf4b48be0d0284a7b6a57b6dace10b843 (diff)
tunnels: support MPLS over IPv4 tunnels
Extend tunnel support to MPLS over IPv4. The implementation extends the existing differentiation between IPIP and IPv6 over IPv4 to also cover MPLS over IPv4. Signed-off-by: Simon Horman <simon.horman@netronome.com> Reviewed-by: Dinan Gunawardena <dinan.gunawardena@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/tunnel4.c77
1 files changed, 67 insertions, 10 deletions
diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c
index 0d0171830620..45cd4253583a 100644
--- a/net/ipv4/tunnel4.c
+++ b/net/ipv4/tunnel4.c
@@ -6,6 +6,7 @@
6#include <linux/init.h> 6#include <linux/init.h>
7#include <linux/module.h> 7#include <linux/module.h>
8#include <linux/mutex.h> 8#include <linux/mutex.h>
9#include <linux/mpls.h>
9#include <linux/netdevice.h> 10#include <linux/netdevice.h>
10#include <linux/skbuff.h> 11#include <linux/skbuff.h>
11#include <linux/slab.h> 12#include <linux/slab.h>
@@ -16,11 +17,14 @@
16 17
17static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; 18static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
18static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly; 19static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly;
20static struct xfrm_tunnel __rcu *tunnelmpls4_handlers __read_mostly;
19static DEFINE_MUTEX(tunnel4_mutex); 21static DEFINE_MUTEX(tunnel4_mutex);
20 22
21static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family) 23static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
22{ 24{
23 return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; 25 return (family == AF_INET) ? &tunnel4_handlers :
26 (family == AF_INET6) ? &tunnel64_handlers :
27 &tunnelmpls4_handlers;
24} 28}
25 29
26int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) 30int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
@@ -125,6 +129,26 @@ drop:
125} 129}
126#endif 130#endif
127 131
132#if IS_ENABLED(CONFIG_MPLS)
133static int tunnelmpls4_rcv(struct sk_buff *skb)
134{
135 struct xfrm_tunnel *handler;
136
137 if (!pskb_may_pull(skb, sizeof(struct mpls_label)))
138 goto drop;
139
140 for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
141 if (!handler->handler(skb))
142 return 0;
143
144 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
145
146drop:
147 kfree_skb(skb);
148 return 0;
149}
150#endif
151
128static void tunnel4_err(struct sk_buff *skb, u32 info) 152static void tunnel4_err(struct sk_buff *skb, u32 info)
129{ 153{
130 struct xfrm_tunnel *handler; 154 struct xfrm_tunnel *handler;
@@ -145,6 +169,17 @@ static void tunnel64_err(struct sk_buff *skb, u32 info)
145} 169}
146#endif 170#endif
147 171
172#if IS_ENABLED(CONFIG_MPLS)
173static void tunnelmpls4_err(struct sk_buff *skb, u32 info)
174{
175 struct xfrm_tunnel *handler;
176
177 for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
178 if (!handler->err_handler(skb, info))
179 break;
180}
181#endif
182
148static const struct net_protocol tunnel4_protocol = { 183static const struct net_protocol tunnel4_protocol = {
149 .handler = tunnel4_rcv, 184 .handler = tunnel4_rcv,
150 .err_handler = tunnel4_err, 185 .err_handler = tunnel4_err,
@@ -161,24 +196,46 @@ static const struct net_protocol tunnel64_protocol = {
161}; 196};
162#endif 197#endif
163 198
199#if IS_ENABLED(CONFIG_MPLS)
200static const struct net_protocol tunnelmpls4_protocol = {
201 .handler = tunnelmpls4_rcv,
202 .err_handler = tunnelmpls4_err,
203 .no_policy = 1,
204 .netns_ok = 1,
205};
206#endif
207
164static int __init tunnel4_init(void) 208static int __init tunnel4_init(void)
165{ 209{
166 if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { 210 if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP))
167 pr_err("%s: can't add protocol\n", __func__); 211 goto err_ipip;
168 return -EAGAIN;
169 }
170#if IS_ENABLED(CONFIG_IPV6) 212#if IS_ENABLED(CONFIG_IPV6)
171 if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { 213 if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6))
172 pr_err("tunnel64 init: can't add protocol\n"); 214 goto err_ipv6;
173 inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); 215#endif
174 return -EAGAIN; 216#if IS_ENABLED(CONFIG_MPLS)
175 } 217 if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS))
218 goto err_mpls;
176#endif 219#endif
177 return 0; 220 return 0;
221
222#if IS_ENABLED(CONFIG_IPV6)
223err_mpls:
224 inet_del_protocol(&tunnel4_protocol, IPPROTO_IPV6);
225#endif
226err_ipv6:
227 inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
228err_ipip:
229 pr_err("%s: can't add protocol\n", __func__);
230 return -EAGAIN;
178} 231}
179 232
180static void __exit tunnel4_fini(void) 233static void __exit tunnel4_fini(void)
181{ 234{
235#if IS_ENABLED(CONFIG_MPLS)
236 if (inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS))
237 pr_err("tunnelmpls4 close: can't remove protocol\n");
238#endif
182#if IS_ENABLED(CONFIG_IPV6) 239#if IS_ENABLED(CONFIG_IPV6)
183 if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) 240 if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6))
184 pr_err("tunnel64 close: can't remove protocol\n"); 241 pr_err("tunnel64 close: can't remove protocol\n");