Commit 49dbe7ae authored by Simon Horman's avatar Simon Horman Committed by David S. Miller

sit: support MPLS over IPv4

Extend the SIT driver to support MPLS over IPv4. This implementation
extends existing support for IPv6 over IPv4 and IPv4 over IPv4.
Signed-off-by: default avatarSimon Horman <simon.horman@netronome.com>
Reviewed-by: default avatarDinan Gunawardena <dinan.gunawardena@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8afe97e5
...@@ -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);
......
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