提交 8afe97e5 编写于 作者: S Simon Horman 提交者: David S. Miller

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: NSimon Horman <simon.horman@netronome.com>
Reviewed-by: NDinan Gunawardena <dinan.gunawardena@netronome.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 a65056ec
......@@ -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>
......@@ -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)
......@@ -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;
......@@ -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,
......@@ -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");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册