Commit 78a010cc authored by Steffen Klassert's avatar Steffen Klassert

vti4: Support inter address family tunneling.

With this patch we can tunnel ipv6 traffic via a vti4
interface. A vti4 interface can now have an ipv6 address
and ipv6 traffic can be routed via a vti4 interface.
The resulting traffic is xfrm transformed and tunneled
throuhg ipv4 if matching IPsec policies and states are
present.
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent a34cd4f3
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/icmpv6.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/ip.h> #include <net/ip.h>
...@@ -122,31 +123,21 @@ static int vti_rcv_cb(struct sk_buff *skb, int err) ...@@ -122,31 +123,21 @@ static int vti_rcv_cb(struct sk_buff *skb, int err)
return 0; return 0;
} }
/* This function assumes it is being called from dev_queue_xmit() static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
* and that skb is filled properly by that function. struct flowi *fl)
*/
static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct ip_tunnel *tunnel = netdev_priv(dev); struct ip_tunnel *tunnel = netdev_priv(dev);
struct dst_entry *dst = skb_dst(skb); struct dst_entry *dst = skb_dst(skb);
struct net_device *tdev; /* Device to other host */ struct net_device *tdev; /* Device to other host */
struct flowi fl;
int err; int err;
if (skb->protocol != htons(ETH_P_IP))
goto tx_error;
memset(&fl, 0, sizeof(fl));
skb->mark = be32_to_cpu(tunnel->parms.o_key);
xfrm_decode_session(skb, &fl, AF_INET);
if (!dst) { if (!dst) {
dev->stats.tx_carrier_errors++; dev->stats.tx_carrier_errors++;
goto tx_error_icmp; goto tx_error_icmp;
} }
dst_hold(dst); dst_hold(dst);
dst = xfrm_lookup(tunnel->net, dst, &fl, NULL, 0); dst = xfrm_lookup(tunnel->net, dst, fl, NULL, 0);
if (IS_ERR(dst)) { if (IS_ERR(dst)) {
dev->stats.tx_carrier_errors++; dev->stats.tx_carrier_errors++;
goto tx_error_icmp; goto tx_error_icmp;
...@@ -178,7 +169,6 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -178,7 +169,6 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
tunnel->err_count = 0; tunnel->err_count = 0;
} }
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev))); skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
skb_dst_set(skb, dst); skb_dst_set(skb, dst);
skb->dev = skb_dst(skb)->dev; skb->dev = skb_dst(skb)->dev;
...@@ -197,6 +187,36 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -197,6 +187,36 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
/* This function assumes it is being called from dev_queue_xmit()
* and that skb is filled properly by that function.
*/
static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
struct flowi fl;
memset(&fl, 0, sizeof(fl));
skb->mark = be32_to_cpu(tunnel->parms.o_key);
switch (skb->protocol) {
case htons(ETH_P_IP):
xfrm_decode_session(skb, &fl, AF_INET);
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
break;
case htons(ETH_P_IPV6):
xfrm_decode_session(skb, &fl, AF_INET6);
memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
break;
default:
dev->stats.tx_errors++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
return vti_xmit(skb, dev, &fl);
}
static int vti4_err(struct sk_buff *skb, u32 info) static int vti4_err(struct sk_buff *skb, u32 info)
{ {
__be32 spi; __be32 spi;
......
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