Commit fb577316 authored by David S. Miller's avatar David S. Miller

Merge branch 'mpls-in-ipv4-and-udp'

Simon Horman says:

====================
net: support MPLS in IPv4 and UDP

This short series provides support for MPLS in IPv4 (RFC4023), and by
virtue of FOU, MPLS in UDP (RFC7510).

The changes are as follows:
1. Teach tunnel4.c about AF_MPLS, it already understands AF_INET and
   AF_INET6
2. Enhance IPIP and SIT to handle MPLS. Both already handle IPv4.
   SIT also already handles IPv6.
3. Trivially enhance MPLS to allow routes over SIT and IPIP tunnels.

A corresponding patch set for iproute2 has also been provided.

Changes since v1
* Correct inverted IPIP protocol logic in SIT patch
* Provide usage example below

Sample configuration follows:

* The following creates a tunnel and routes MPLS packets whose outermost
  label is 100 over it. The forwarded packets will have the outermost label
  stack entry, 100, removed and two label stack entries added, the
  outermost having label 200 and the next having label 300.

  The local end-point for the tunnel is 10.0.99.192 and the remote
  endpoint is 10.0.99.193.

  The local address for encapsulated packets is 10.0.98.192 and the
  remote address is 10.0.98.193.

  # Create an MPLS over IPv4 tunnel using the IPIP driver
  ip link add name tun1 type ipip remote 10.0.99.193 local 10.0.99.192 \
	ttl 225 mode mplsip

  # Bring the tunnel up and an add an IPv4 address and route
  ip link set up dev tun1
  ip addr add 10.0.98.192/24 dev tun1

  # Set MPLS route
  # Allow MPLS forwarding of packets recieved on eth0
  echo 1 > /proc/sys/net/mpls/conf/eth0/input
  # Larger than label to be routed (100)
  echo 101 > /proc/sys/net/mpls/platform_labels
  ip -f mpls route add 100 as 200/300 via inet 10.0.98.193

* For FOU (in this case MPLS over UDP) a tunnel may created using:

  # Packets recieved on UDP port 6635 are MPLS over UDP (IP proto 137)
  ip fou add port 6635 ipproto 137
  # Create the tunnel netdev
  ip link add name tun1 type ipip remote 10.0.99.193 local 10.0.99.192 \
	ttl 225 mode mplsip encap fou encap-sport auto encap-dport 6635

  IPv4 address, link and route, and MPLS routing commands are as per
  the MPLS over IPv4 example

* To use the SIT driver instead of the IPIP driver "ipip" may be substituted
  for "sit" in the above examples.

* To create a tunnel that forwards and receives all supported
  inner-protocols "mplsip" may be substituted for "any" in the above
  examples.

  For the IPIP driver this configures both IPv4 and MPLS over IPv4.
  For the SIT driver this configures IPv6, IPv4 and MPLS over IPv4.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a65056ec 407f31be
...@@ -148,14 +148,14 @@ static int ipip_err(struct sk_buff *skb, u32 info) ...@@ -148,14 +148,14 @@ static int ipip_err(struct sk_buff *skb, u32 info)
if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
ipv4_update_pmtu(skb, dev_net(skb->dev), info, ipv4_update_pmtu(skb, dev_net(skb->dev), info,
t->parms.link, 0, IPPROTO_IPIP, 0); t->parms.link, 0, iph->protocol, 0);
err = 0; err = 0;
goto out; goto out;
} }
if (type == ICMP_REDIRECT) { if (type == ICMP_REDIRECT) {
ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
IPPROTO_IPIP, 0); iph->protocol, 0);
err = 0; err = 0;
goto out; goto out;
} }
...@@ -177,12 +177,19 @@ static int ipip_err(struct sk_buff *skb, u32 info) ...@@ -177,12 +177,19 @@ static int ipip_err(struct sk_buff *skb, u32 info)
return err; return err;
} }
static const struct tnl_ptk_info tpi = { static const struct tnl_ptk_info ipip_tpi = {
/* no tunnel info required for ipip. */ /* no tunnel info required for ipip. */
.proto = htons(ETH_P_IP), .proto = htons(ETH_P_IP),
}; };
static int ipip_rcv(struct sk_buff *skb) #if IS_ENABLED(CONFIG_MPLS)
static const struct tnl_ptk_info mplsip_tpi = {
/* no tunnel info required for mplsip. */
.proto = htons(ETH_P_MPLS_UC),
};
#endif
static int ipip_tunnel_rcv(struct sk_buff *skb, u8 ipproto)
{ {
struct net *net = dev_net(skb->dev); struct net *net = dev_net(skb->dev);
struct ip_tunnel_net *itn = net_generic(net, ipip_net_id); struct ip_tunnel_net *itn = net_generic(net, ipip_net_id);
...@@ -193,11 +200,23 @@ static int ipip_rcv(struct sk_buff *skb) ...@@ -193,11 +200,23 @@ static int ipip_rcv(struct sk_buff *skb)
tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY, tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
iph->saddr, iph->daddr, 0); iph->saddr, iph->daddr, 0);
if (tunnel) { if (tunnel) {
const struct tnl_ptk_info *tpi;
if (tunnel->parms.iph.protocol != ipproto &&
tunnel->parms.iph.protocol != 0)
goto drop;
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto drop; goto drop;
if (iptunnel_pull_header(skb, 0, tpi.proto, false)) #if IS_ENABLED(CONFIG_MPLS)
if (ipproto == IPPROTO_MPLS)
tpi = &mplsip_tpi;
else
#endif
tpi = &ipip_tpi;
if (iptunnel_pull_header(skb, 0, tpi->proto, false))
goto drop; goto drop;
return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error); return ip_tunnel_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
} }
return -1; return -1;
...@@ -207,24 +226,51 @@ static int ipip_rcv(struct sk_buff *skb) ...@@ -207,24 +226,51 @@ static int ipip_rcv(struct sk_buff *skb)
return 0; return 0;
} }
static int ipip_rcv(struct sk_buff *skb)
{
return ipip_tunnel_rcv(skb, IPPROTO_IPIP);
}
#if IS_ENABLED(CONFIG_MPLS)
static int mplsip_rcv(struct sk_buff *skb)
{
return ipip_tunnel_rcv(skb, IPPROTO_MPLS);
}
#endif
/* /*
* This function assumes it is being called from dev_queue_xmit() * This function assumes it is being called from dev_queue_xmit()
* and that skb is filled properly by that function. * and that skb is filled properly by that function.
*/ */
static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb,
struct net_device *dev)
{ {
struct ip_tunnel *tunnel = netdev_priv(dev); struct ip_tunnel *tunnel = netdev_priv(dev);
const struct iphdr *tiph = &tunnel->parms.iph; const struct iphdr *tiph = &tunnel->parms.iph;
u8 ipproto;
switch (skb->protocol) {
case htons(ETH_P_IP):
ipproto = IPPROTO_IPIP;
break;
#if IS_ENABLED(CONFIG_MPLS)
case htons(ETH_P_MPLS_UC):
ipproto = IPPROTO_MPLS;
break;
#endif
default:
goto tx_error;
}
if (unlikely(skb->protocol != htons(ETH_P_IP))) if (tiph->protocol != ipproto && tiph->protocol != 0)
goto tx_error; goto tx_error;
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
goto tx_error; goto tx_error;
skb_set_inner_ipproto(skb, IPPROTO_IPIP); skb_set_inner_ipproto(skb, ipproto);
ip_tunnel_xmit(skb, dev, tiph, tiph->protocol); ip_tunnel_xmit(skb, dev, tiph, ipproto);
return NETDEV_TX_OK; return NETDEV_TX_OK;
tx_error: tx_error:
...@@ -234,6 +280,20 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -234,6 +280,20 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static bool ipip_tunnel_ioctl_verify_protocol(u8 ipproto)
{
switch (ipproto) {
case 0:
case IPPROTO_IPIP:
#if IS_ENABLED(CONFIG_MPLS)
case IPPROTO_MPLS:
#endif
return true;
}
return false;
}
static int static int
ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
...@@ -244,7 +304,8 @@ ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -244,7 +304,8 @@ ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EFAULT; return -EFAULT;
if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) { if (cmd == SIOCADDTUNNEL || cmd == SIOCCHGTUNNEL) {
if (p.iph.version != 4 || p.iph.protocol != IPPROTO_IPIP || if (p.iph.version != 4 ||
!ipip_tunnel_ioctl_verify_protocol(p.iph.protocol) ||
p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF))) p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
return -EINVAL; return -EINVAL;
} }
...@@ -301,10 +362,23 @@ static int ipip_tunnel_init(struct net_device *dev) ...@@ -301,10 +362,23 @@ static int ipip_tunnel_init(struct net_device *dev)
tunnel->tun_hlen = 0; tunnel->tun_hlen = 0;
tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
tunnel->parms.iph.protocol = IPPROTO_IPIP;
return ip_tunnel_init(dev); return ip_tunnel_init(dev);
} }
static int ipip_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
{
u8 proto;
if (!data || !data[IFLA_IPTUN_PROTO])
return 0;
proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
if (proto != IPPROTO_IPIP && proto != IPPROTO_MPLS && proto != 0)
return -EINVAL;
return 0;
}
static void ipip_netlink_parms(struct nlattr *data[], static void ipip_netlink_parms(struct nlattr *data[],
struct ip_tunnel_parm *parms) struct ip_tunnel_parm *parms)
{ {
...@@ -335,6 +409,9 @@ static void ipip_netlink_parms(struct nlattr *data[], ...@@ -335,6 +409,9 @@ static void ipip_netlink_parms(struct nlattr *data[],
if (data[IFLA_IPTUN_TOS]) if (data[IFLA_IPTUN_TOS])
parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]); parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]);
if (data[IFLA_IPTUN_PROTO])
parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]);
if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC])) if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC]))
parms->iph.frag_off = htons(IP_DF); parms->iph.frag_off = htons(IP_DF);
} }
...@@ -427,6 +504,8 @@ static size_t ipip_get_size(const struct net_device *dev) ...@@ -427,6 +504,8 @@ static size_t ipip_get_size(const struct net_device *dev)
nla_total_size(1) + nla_total_size(1) +
/* IFLA_IPTUN_TOS */ /* IFLA_IPTUN_TOS */
nla_total_size(1) + nla_total_size(1) +
/* IFLA_IPTUN_PROTO */
nla_total_size(1) +
/* IFLA_IPTUN_PMTUDISC */ /* IFLA_IPTUN_PMTUDISC */
nla_total_size(1) + nla_total_size(1) +
/* IFLA_IPTUN_ENCAP_TYPE */ /* IFLA_IPTUN_ENCAP_TYPE */
...@@ -450,6 +529,7 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev) ...@@ -450,6 +529,7 @@ static int ipip_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) || nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) ||
nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) || nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) ||
nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) ||
nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) ||
nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, nla_put_u8(skb, IFLA_IPTUN_PMTUDISC,
!!(parm->iph.frag_off & htons(IP_DF)))) !!(parm->iph.frag_off & htons(IP_DF))))
goto nla_put_failure; goto nla_put_failure;
...@@ -476,6 +556,7 @@ static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = { ...@@ -476,6 +556,7 @@ static const struct nla_policy ipip_policy[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 },
[IFLA_IPTUN_TTL] = { .type = NLA_U8 }, [IFLA_IPTUN_TTL] = { .type = NLA_U8 },
[IFLA_IPTUN_TOS] = { .type = NLA_U8 }, [IFLA_IPTUN_TOS] = { .type = NLA_U8 },
[IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
[IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
[IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 },
[IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 },
...@@ -489,6 +570,7 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly = { ...@@ -489,6 +570,7 @@ static struct rtnl_link_ops ipip_link_ops __read_mostly = {
.policy = ipip_policy, .policy = ipip_policy,
.priv_size = sizeof(struct ip_tunnel), .priv_size = sizeof(struct ip_tunnel),
.setup = ipip_tunnel_setup, .setup = ipip_tunnel_setup,
.validate = ipip_tunnel_validate,
.newlink = ipip_newlink, .newlink = ipip_newlink,
.changelink = ipip_changelink, .changelink = ipip_changelink,
.dellink = ip_tunnel_dellink, .dellink = ip_tunnel_dellink,
...@@ -503,6 +585,14 @@ static struct xfrm_tunnel ipip_handler __read_mostly = { ...@@ -503,6 +585,14 @@ static struct xfrm_tunnel ipip_handler __read_mostly = {
.priority = 1, .priority = 1,
}; };
#if IS_ENABLED(CONFIG_MPLS)
static struct xfrm_tunnel mplsip_handler __read_mostly = {
.handler = mplsip_rcv,
.err_handler = ipip_err,
.priority = 1,
};
#endif
static int __net_init ipip_init_net(struct net *net) static int __net_init ipip_init_net(struct net *net)
{ {
return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0"); return ip_tunnel_init_net(net, ipip_net_id, &ipip_link_ops, "tunl0");
...@@ -525,7 +615,7 @@ static int __init ipip_init(void) ...@@ -525,7 +615,7 @@ static int __init ipip_init(void)
{ {
int err; int err;
pr_info("ipip: IPv4 over IPv4 tunneling driver\n"); pr_info("ipip: IPv4 and MPLS over IPv4 tunneling driver\n");
err = register_pernet_device(&ipip_net_ops); err = register_pernet_device(&ipip_net_ops);
if (err < 0) if (err < 0)
...@@ -533,8 +623,15 @@ static int __init ipip_init(void) ...@@ -533,8 +623,15 @@ static int __init ipip_init(void)
err = xfrm4_tunnel_register(&ipip_handler, AF_INET); err = xfrm4_tunnel_register(&ipip_handler, AF_INET);
if (err < 0) { if (err < 0) {
pr_info("%s: can't register tunnel\n", __func__); pr_info("%s: can't register tunnel\n", __func__);
goto xfrm_tunnel_failed; goto xfrm_tunnel_ipip_failed;
}
#if IS_ENABLED(CONFIG_MPLS)
err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS);
if (err < 0) {
pr_info("%s: can't register tunnel\n", __func__);
goto xfrm_tunnel_mplsip_failed;
} }
#endif
err = rtnl_link_register(&ipip_link_ops); err = rtnl_link_register(&ipip_link_ops);
if (err < 0) if (err < 0)
goto rtnl_link_failed; goto rtnl_link_failed;
...@@ -543,8 +640,13 @@ static int __init ipip_init(void) ...@@ -543,8 +640,13 @@ static int __init ipip_init(void)
return err; return err;
rtnl_link_failed: rtnl_link_failed:
#if IS_ENABLED(CONFIG_MPLS)
xfrm4_tunnel_deregister(&mplsip_handler, AF_INET);
xfrm_tunnel_mplsip_failed:
#endif
xfrm4_tunnel_deregister(&ipip_handler, AF_INET); xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
xfrm_tunnel_failed: xfrm_tunnel_ipip_failed:
unregister_pernet_device(&ipip_net_ops); unregister_pernet_device(&ipip_net_ops);
goto out; goto out;
} }
...@@ -554,7 +656,10 @@ static void __exit ipip_fini(void) ...@@ -554,7 +656,10 @@ static void __exit ipip_fini(void)
rtnl_link_unregister(&ipip_link_ops); rtnl_link_unregister(&ipip_link_ops);
if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET))
pr_info("%s: can't deregister tunnel\n", __func__); pr_info("%s: can't deregister tunnel\n", __func__);
#if IS_ENABLED(CONFIG_MPLS)
if (xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS))
pr_info("%s: can't deregister tunnel\n", __func__);
#endif
unregister_pernet_device(&ipip_net_ops); unregister_pernet_device(&ipip_net_ops);
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/mpls.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -16,11 +17,14 @@ ...@@ -16,11 +17,14 @@
static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly;
static struct xfrm_tunnel __rcu *tunnel64_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 DEFINE_MUTEX(tunnel4_mutex);
static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family) 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) int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
...@@ -125,6 +129,26 @@ static int tunnel64_rcv(struct sk_buff *skb) ...@@ -125,6 +129,26 @@ static int tunnel64_rcv(struct sk_buff *skb)
} }
#endif #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) static void tunnel4_err(struct sk_buff *skb, u32 info)
{ {
struct xfrm_tunnel *handler; struct xfrm_tunnel *handler;
...@@ -145,6 +169,17 @@ static void tunnel64_err(struct sk_buff *skb, u32 info) ...@@ -145,6 +169,17 @@ static void tunnel64_err(struct sk_buff *skb, u32 info)
} }
#endif #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 = { static const struct net_protocol tunnel4_protocol = {
.handler = tunnel4_rcv, .handler = tunnel4_rcv,
.err_handler = tunnel4_err, .err_handler = tunnel4_err,
...@@ -161,24 +196,46 @@ static const struct net_protocol tunnel64_protocol = { ...@@ -161,24 +196,46 @@ static const struct net_protocol tunnel64_protocol = {
}; };
#endif #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) static int __init tunnel4_init(void)
{ {
if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP))
pr_err("%s: can't add protocol\n", __func__); goto err_ipip;
return -EAGAIN;
}
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6))
pr_err("tunnel64 init: can't add protocol\n"); goto err_ipv6;
inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); #endif
return -EAGAIN; #if IS_ENABLED(CONFIG_MPLS)
} if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS))
goto err_mpls;
#endif #endif
return 0; 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) 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 IS_ENABLED(CONFIG_IPV6)
if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6))
pr_err("tunnel64 close: can't remove protocol\n"); pr_err("tunnel64 close: can't remove protocol\n");
......
...@@ -688,12 +688,19 @@ static int ipip6_rcv(struct sk_buff *skb) ...@@ -688,12 +688,19 @@ static int ipip6_rcv(struct sk_buff *skb)
return 0; return 0;
} }
static const struct tnl_ptk_info tpi = { static const struct tnl_ptk_info ipip_tpi = {
/* no tunnel info required for ipip. */ /* no tunnel info required for ipip. */
.proto = htons(ETH_P_IP), .proto = htons(ETH_P_IP),
}; };
static int ipip_rcv(struct sk_buff *skb) #if IS_ENABLED(CONFIG_MPLS)
static const struct tnl_ptk_info mplsip_tpi = {
/* no tunnel info required for mplsip. */
.proto = htons(ETH_P_MPLS_UC),
};
#endif
static int sit_tunnel_rcv(struct sk_buff *skb, u8 ipproto)
{ {
const struct iphdr *iph; const struct iphdr *iph;
struct ip_tunnel *tunnel; struct ip_tunnel *tunnel;
...@@ -702,15 +709,23 @@ static int ipip_rcv(struct sk_buff *skb) ...@@ -702,15 +709,23 @@ static int ipip_rcv(struct sk_buff *skb)
tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
iph->saddr, iph->daddr); iph->saddr, iph->daddr);
if (tunnel) { if (tunnel) {
if (tunnel->parms.iph.protocol != IPPROTO_IPIP && const struct tnl_ptk_info *tpi;
if (tunnel->parms.iph.protocol != ipproto &&
tunnel->parms.iph.protocol != 0) tunnel->parms.iph.protocol != 0)
goto drop; goto drop;
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
goto drop; goto drop;
if (iptunnel_pull_header(skb, 0, tpi.proto, false)) #if IS_ENABLED(CONFIG_MPLS)
if (ipproto == IPPROTO_MPLS)
tpi = &mplsip_tpi;
else
#endif
tpi = &ipip_tpi;
if (iptunnel_pull_header(skb, 0, tpi->proto, false))
goto drop; goto drop;
return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error); return ip_tunnel_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
} }
return 1; return 1;
...@@ -720,6 +735,18 @@ static int ipip_rcv(struct sk_buff *skb) ...@@ -720,6 +735,18 @@ static int ipip_rcv(struct sk_buff *skb)
return 0; return 0;
} }
static int ipip_rcv(struct sk_buff *skb)
{
return sit_tunnel_rcv(skb, IPPROTO_IPIP);
}
#if IS_ENABLED(CONFIG_MPLS)
static int mplsip_rcv(struct sk_buff *skb)
{
return sit_tunnel_rcv(skb, IPPROTO_MPLS);
}
#endif
/* /*
* If the IPv6 address comes from 6rd / 6to4 (RFC 3056) addr space this function * If the IPv6 address comes from 6rd / 6to4 (RFC 3056) addr space this function
* stores the embedded IPv4 address in v4dst and returns true. * stores the embedded IPv4 address in v4dst and returns true.
...@@ -958,7 +985,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, ...@@ -958,7 +985,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) static netdev_tx_t sit_tunnel_xmit__(struct sk_buff *skb,
struct net_device *dev, u8 ipproto)
{ {
struct ip_tunnel *tunnel = netdev_priv(dev); struct ip_tunnel *tunnel = netdev_priv(dev);
const struct iphdr *tiph = &tunnel->parms.iph; const struct iphdr *tiph = &tunnel->parms.iph;
...@@ -966,9 +994,9 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -966,9 +994,9 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
goto tx_error; goto tx_error;
skb_set_inner_ipproto(skb, IPPROTO_IPIP); skb_set_inner_ipproto(skb, ipproto);
ip_tunnel_xmit(skb, dev, tiph, IPPROTO_IPIP); ip_tunnel_xmit(skb, dev, tiph, ipproto);
return NETDEV_TX_OK; return NETDEV_TX_OK;
tx_error: tx_error:
kfree_skb(skb); kfree_skb(skb);
...@@ -981,11 +1009,16 @@ static netdev_tx_t sit_tunnel_xmit(struct sk_buff *skb, ...@@ -981,11 +1009,16 @@ static netdev_tx_t sit_tunnel_xmit(struct sk_buff *skb,
{ {
switch (skb->protocol) { switch (skb->protocol) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
ipip_tunnel_xmit(skb, dev); sit_tunnel_xmit__(skb, dev, IPPROTO_IPIP);
break; break;
case htons(ETH_P_IPV6): case htons(ETH_P_IPV6):
ipip6_tunnel_xmit(skb, dev); ipip6_tunnel_xmit(skb, dev);
break; break;
#if IS_ENABLED(CONFIG_MPLS)
case htons(ETH_P_MPLS_UC):
sit_tunnel_xmit__(skb, dev, IPPROTO_MPLS);
break;
#endif
default: default:
goto tx_err; goto tx_err;
} }
...@@ -1093,6 +1126,16 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t, ...@@ -1093,6 +1126,16 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
} }
#endif #endif
bool ipip6_valid_ip_proto(u8 ipproto)
{
return ipproto == IPPROTO_IPV6 ||
ipproto == IPPROTO_IPIP ||
#if IS_ENABLED(CONFIG_MPLS)
ipproto == IPPROTO_MPLS ||
#endif
ipproto == 0;
}
static int static int
ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
...@@ -1152,9 +1195,7 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1152,9 +1195,7 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
goto done; goto done;
err = -EINVAL; err = -EINVAL;
if (p.iph.protocol != IPPROTO_IPV6 && if (!ipip6_valid_ip_proto(p.iph.protocol))
p.iph.protocol != IPPROTO_IPIP &&
p.iph.protocol != 0)
goto done; goto done;
if (p.iph.version != 4 || if (p.iph.version != 4 ||
p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF))) p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
...@@ -1379,9 +1420,7 @@ static int ipip6_validate(struct nlattr *tb[], struct nlattr *data[]) ...@@ -1379,9 +1420,7 @@ static int ipip6_validate(struct nlattr *tb[], struct nlattr *data[])
return 0; return 0;
proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
if (proto != IPPROTO_IPV6 && if (!ipip6_valid_ip_proto(proto))
proto != IPPROTO_IPIP &&
proto != 0)
return -EINVAL; return -EINVAL;
return 0; return 0;
...@@ -1723,6 +1762,14 @@ static struct xfrm_tunnel ipip_handler __read_mostly = { ...@@ -1723,6 +1762,14 @@ static struct xfrm_tunnel ipip_handler __read_mostly = {
.priority = 2, .priority = 2,
}; };
#if IS_ENABLED(CONFIG_MPLS)
static struct xfrm_tunnel mplsip_handler __read_mostly = {
.handler = mplsip_rcv,
.err_handler = ipip6_err,
.priority = 2,
};
#endif
static void __net_exit sit_destroy_tunnels(struct net *net, static void __net_exit sit_destroy_tunnels(struct net *net,
struct list_head *head) struct list_head *head)
{ {
...@@ -1818,6 +1865,9 @@ static void __exit sit_cleanup(void) ...@@ -1818,6 +1865,9 @@ static void __exit sit_cleanup(void)
rtnl_link_unregister(&sit_link_ops); rtnl_link_unregister(&sit_link_ops);
xfrm4_tunnel_deregister(&sit_handler, AF_INET6); xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
xfrm4_tunnel_deregister(&ipip_handler, AF_INET); xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
#if IS_ENABLED(CONFIG_MPLS)
xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS);
#endif
unregister_pernet_device(&sit_net_ops); unregister_pernet_device(&sit_net_ops);
rcu_barrier(); /* Wait for completion of call_rcu()'s */ rcu_barrier(); /* Wait for completion of call_rcu()'s */
...@@ -1827,7 +1877,7 @@ static int __init sit_init(void) ...@@ -1827,7 +1877,7 @@ static int __init sit_init(void)
{ {
int err; int err;
pr_info("IPv6 over IPv4 tunneling driver\n"); pr_info("IPv6, IPv4 and MPLS over IPv4 tunneling driver\n");
err = register_pernet_device(&sit_net_ops); err = register_pernet_device(&sit_net_ops);
if (err < 0) if (err < 0)
...@@ -1842,6 +1892,13 @@ static int __init sit_init(void) ...@@ -1842,6 +1892,13 @@ static int __init sit_init(void)
pr_info("%s: can't register ip4ip4\n", __func__); pr_info("%s: can't register ip4ip4\n", __func__);
goto xfrm_tunnel4_failed; goto xfrm_tunnel4_failed;
} }
#if IS_ENABLED(CONFIG_MPLS)
err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS);
if (err < 0) {
pr_info("%s: can't register mplsip\n", __func__);
goto xfrm_tunnel_mpls_failed;
}
#endif
err = rtnl_link_register(&sit_link_ops); err = rtnl_link_register(&sit_link_ops);
if (err < 0) if (err < 0)
goto rtnl_link_failed; goto rtnl_link_failed;
...@@ -1850,6 +1907,10 @@ static int __init sit_init(void) ...@@ -1850,6 +1907,10 @@ static int __init sit_init(void)
return err; return err;
rtnl_link_failed: rtnl_link_failed:
#if IS_ENABLED(CONFIG_MPLS)
xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS);
xfrm_tunnel_mpls_failed:
#endif
xfrm4_tunnel_deregister(&ipip_handler, AF_INET); xfrm4_tunnel_deregister(&ipip_handler, AF_INET);
xfrm_tunnel4_failed: xfrm_tunnel4_failed:
xfrm4_tunnel_deregister(&sit_handler, AF_INET6); xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
......
...@@ -1009,10 +1009,12 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event, ...@@ -1009,10 +1009,12 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
unsigned int flags; unsigned int flags;
if (event == NETDEV_REGISTER) { if (event == NETDEV_REGISTER) {
/* For now just support Ethernet and IPGRE devices */ /* For now just support Ethernet, IPGRE, SIT and IPIP devices */
if (dev->type == ARPHRD_ETHER || if (dev->type == ARPHRD_ETHER ||
dev->type == ARPHRD_LOOPBACK || dev->type == ARPHRD_LOOPBACK ||
dev->type == ARPHRD_IPGRE) { dev->type == ARPHRD_IPGRE ||
dev->type == ARPHRD_SIT ||
dev->type == ARPHRD_TUNNEL) {
mdev = mpls_add_dev(dev); mdev = mpls_add_dev(dev);
if (IS_ERR(mdev)) if (IS_ERR(mdev))
return notifier_from_errno(PTR_ERR(mdev)); return notifier_from_errno(PTR_ERR(mdev));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment