Skip to content

Commit

Permalink
sit: support MPLS over IPv4
Browse files Browse the repository at this point in the history
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: 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 8afe97e commit 49dbe7a
Showing 1 changed file with 77 additions and 16 deletions.
93 changes: 77 additions & 16 deletions net/ipv6/sit.c
Original file line number Diff line number Diff line change
Expand Up @@ -688,12 +688,19 @@ static int ipip6_rcv(struct sk_buff *skb)
return 0;
}

static const struct tnl_ptk_info tpi = {
static const struct tnl_ptk_info ipip_tpi = {
/* no tunnel info required for ipip. */
.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;
struct ip_tunnel *tunnel;
Expand All @@ -702,15 +709,23 @@ static int ipip_rcv(struct sk_buff *skb)
tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
iph->saddr, iph->daddr);
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)
goto drop;

if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
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;
return ip_tunnel_rcv(tunnel, skb, &tpi, NULL, log_ecn_error);
return ip_tunnel_rcv(tunnel, skb, tpi, NULL, log_ecn_error);
}

return 1;
Expand All @@ -720,6 +735,18 @@ static int ipip_rcv(struct sk_buff *skb)
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
* stores the embedded IPv4 address in v4dst and returns true.
Expand Down Expand Up @@ -958,17 +985,18 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
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);
const struct iphdr *tiph = &tunnel->parms.iph;

if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4))
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;
tx_error:
kfree_skb(skb);
Expand All @@ -981,11 +1009,16 @@ static netdev_tx_t sit_tunnel_xmit(struct sk_buff *skb,
{
switch (skb->protocol) {
case htons(ETH_P_IP):
ipip_tunnel_xmit(skb, dev);
sit_tunnel_xmit__(skb, dev, IPPROTO_IPIP);
break;
case htons(ETH_P_IPV6):
ipip6_tunnel_xmit(skb, dev);
break;
#if IS_ENABLED(CONFIG_MPLS)
case htons(ETH_P_MPLS_UC):
sit_tunnel_xmit__(skb, dev, IPPROTO_MPLS);
break;
#endif
default:
goto tx_err;
}
Expand Down Expand Up @@ -1093,6 +1126,16 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
}
#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
ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
Expand Down Expand Up @@ -1152,9 +1195,7 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
goto done;

err = -EINVAL;
if (p.iph.protocol != IPPROTO_IPV6 &&
p.iph.protocol != IPPROTO_IPIP &&
p.iph.protocol != 0)
if (!ipip6_valid_ip_proto(p.iph.protocol))
goto done;
if (p.iph.version != 4 ||
p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF)))
Expand Down Expand Up @@ -1379,9 +1420,7 @@ static int ipip6_validate(struct nlattr *tb[], struct nlattr *data[])
return 0;

proto = nla_get_u8(data[IFLA_IPTUN_PROTO]);
if (proto != IPPROTO_IPV6 &&
proto != IPPROTO_IPIP &&
proto != 0)
if (!ipip6_valid_ip_proto(proto))
return -EINVAL;

return 0;
Expand Down Expand Up @@ -1723,6 +1762,14 @@ static struct xfrm_tunnel ipip_handler __read_mostly = {
.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,
struct list_head *head)
{
Expand Down Expand Up @@ -1818,6 +1865,9 @@ static void __exit sit_cleanup(void)
rtnl_link_unregister(&sit_link_ops);
xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
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);
rcu_barrier(); /* Wait for completion of call_rcu()'s */
Expand All @@ -1827,7 +1877,7 @@ static int __init sit_init(void)
{
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);
if (err < 0)
Expand All @@ -1842,6 +1892,13 @@ static int __init sit_init(void)
pr_info("%s: can't register ip4ip4\n", __func__);
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);
if (err < 0)
goto rtnl_link_failed;
Expand All @@ -1850,6 +1907,10 @@ static int __init sit_init(void)
return err;

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);
xfrm_tunnel4_failed:
xfrm4_tunnel_deregister(&sit_handler, AF_INET6);
Expand Down

0 comments on commit 49dbe7a

Please sign in to comment.