Skip to content

Commit

Permalink
tunnels: support MPLS over IPv4 tunnels
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Simon Horman authored and David S. Miller committed Jul 9, 2016
1 parent a65056e commit 8afe97e
Showing 1 changed file with 67 additions and 10 deletions.
77 changes: 67 additions & 10 deletions net/ipv4/tunnel4.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/mpls.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
Expand All @@ -16,11 +17,14 @@

static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly;
static struct xfrm_tunnel __rcu *tunnelmpls4_handlers __read_mostly;
static DEFINE_MUTEX(tunnel4_mutex);

static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
{
return (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers;
return (family == AF_INET) ? &tunnel4_handlers :
(family == AF_INET6) ? &tunnel64_handlers :
&tunnelmpls4_handlers;
}

int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
Expand Down Expand Up @@ -125,6 +129,26 @@ static int tunnel64_rcv(struct sk_buff *skb)
}
#endif

#if IS_ENABLED(CONFIG_MPLS)
static int tunnelmpls4_rcv(struct sk_buff *skb)
{
struct xfrm_tunnel *handler;

if (!pskb_may_pull(skb, sizeof(struct mpls_label)))
goto drop;

for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
if (!handler->handler(skb))
return 0;

icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);

drop:
kfree_skb(skb);
return 0;
}
#endif

static void tunnel4_err(struct sk_buff *skb, u32 info)
{
struct xfrm_tunnel *handler;
Expand All @@ -145,6 +169,17 @@ static void tunnel64_err(struct sk_buff *skb, u32 info)
}
#endif

#if IS_ENABLED(CONFIG_MPLS)
static void tunnelmpls4_err(struct sk_buff *skb, u32 info)
{
struct xfrm_tunnel *handler;

for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
if (!handler->err_handler(skb, info))
break;
}
#endif

static const struct net_protocol tunnel4_protocol = {
.handler = tunnel4_rcv,
.err_handler = tunnel4_err,
Expand All @@ -161,24 +196,46 @@ static const struct net_protocol tunnel64_protocol = {
};
#endif

#if IS_ENABLED(CONFIG_MPLS)
static const struct net_protocol tunnelmpls4_protocol = {
.handler = tunnelmpls4_rcv,
.err_handler = tunnelmpls4_err,
.no_policy = 1,
.netns_ok = 1,
};
#endif

static int __init tunnel4_init(void)
{
if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) {
pr_err("%s: can't add protocol\n", __func__);
return -EAGAIN;
}
if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP))
goto err_ipip;
#if IS_ENABLED(CONFIG_IPV6)
if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) {
pr_err("tunnel64 init: can't add protocol\n");
inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
return -EAGAIN;
}
if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6))
goto err_ipv6;
#endif
#if IS_ENABLED(CONFIG_MPLS)
if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS))
goto err_mpls;
#endif
return 0;

#if IS_ENABLED(CONFIG_IPV6)
err_mpls:
inet_del_protocol(&tunnel4_protocol, IPPROTO_IPV6);
#endif
err_ipv6:
inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP);
err_ipip:
pr_err("%s: can't add protocol\n", __func__);
return -EAGAIN;
}

static void __exit tunnel4_fini(void)
{
#if IS_ENABLED(CONFIG_MPLS)
if (inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS))
pr_err("tunnelmpls4 close: can't remove protocol\n");
#endif
#if IS_ENABLED(CONFIG_IPV6)
if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6))
pr_err("tunnel64 close: can't remove protocol\n");
Expand Down

0 comments on commit 8afe97e

Please sign in to comment.