aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2014-03-14 02:28:08 -0400
committerSteffen Klassert <steffen.klassert@secunet.com>2014-03-14 02:28:08 -0400
commit22e1b23dafa8554ef722454e8b84645820cbbc17 (patch)
tree6fe157ae571ee70930f199a96ff1f723966d9923 /net/ipv6
parent573ce1c11b0d93a08b988d2713ef02214404aad1 (diff)
vti6: Support inter address family tunneling.
With this patch we can tunnel ipv4 traffic via a vti6 interface. A vti6 interface can now have an ipv4 address and ipv4 traffic can be routed via a vti6 interface. The resulting traffic is xfrm transformed and tunneled through ipv6 if matching IPsec policies and states are present. Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_vti.c49
1 files changed, 34 insertions, 15 deletions
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index 226854a3c392..8d189aae7c96 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -380,30 +380,22 @@ vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
380 * vti6_xmit - send a packet 380 * vti6_xmit - send a packet
381 * @skb: the outgoing socket buffer 381 * @skb: the outgoing socket buffer
382 * @dev: the outgoing tunnel device 382 * @dev: the outgoing tunnel device
383 * @fl: the flow informations for the xfrm_lookup
383 **/ 384 **/
384static int vti6_xmit(struct sk_buff *skb, struct net_device *dev) 385static int
386vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
385{ 387{
386 struct ip6_tnl *t = netdev_priv(dev); 388 struct ip6_tnl *t = netdev_priv(dev);
387 struct net_device_stats *stats = &t->dev->stats; 389 struct net_device_stats *stats = &t->dev->stats;
388 struct dst_entry *dst = skb_dst(skb); 390 struct dst_entry *dst = skb_dst(skb);
389 struct flowi fl;
390 struct ipv6hdr *ipv6h = ipv6_hdr(skb);
391 struct net_device *tdev; 391 struct net_device *tdev;
392 int err = -1; 392 int err = -1;
393 393
394 if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
395 !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
396 return err;
397
398 memset(&fl, 0, sizeof(fl));
399 skb->mark = be32_to_cpu(t->parms.o_key);
400 xfrm_decode_session(skb, &fl, AF_INET6);
401
402 if (!dst) 394 if (!dst)
403 goto tx_err_link_failure; 395 goto tx_err_link_failure;
404 396
405 dst_hold(dst); 397 dst_hold(dst);
406 dst = xfrm_lookup(t->net, dst, &fl, NULL, 0); 398 dst = xfrm_lookup(t->net, dst, fl, NULL, 0);
407 if (IS_ERR(dst)) { 399 if (IS_ERR(dst)) {
408 err = PTR_ERR(dst); 400 err = PTR_ERR(dst);
409 dst = NULL; 401 dst = NULL;
@@ -422,12 +414,22 @@ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev)
422 goto tx_err_dst_release; 414 goto tx_err_dst_release;
423 } 415 }
424 416
425 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
426 skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev))); 417 skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
427 skb_dst_set(skb, dst); 418 skb_dst_set(skb, dst);
428 skb->dev = skb_dst(skb)->dev; 419 skb->dev = skb_dst(skb)->dev;
429 420
430 ip6tunnel_xmit(skb, dev); 421 err = dst_output(skb);
422 if (net_xmit_eval(err) == 0) {
423 struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
424
425 u64_stats_update_begin(&tstats->syncp);
426 tstats->tx_bytes += skb->len;
427 tstats->tx_packets++;
428 u64_stats_update_end(&tstats->syncp);
429 } else {
430 stats->tx_errors++;
431 stats->tx_aborted_errors++;
432 }
431 433
432 return 0; 434 return 0;
433tx_err_link_failure: 435tx_err_link_failure:
@@ -443,16 +445,33 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
443{ 445{
444 struct ip6_tnl *t = netdev_priv(dev); 446 struct ip6_tnl *t = netdev_priv(dev);
445 struct net_device_stats *stats = &t->dev->stats; 447 struct net_device_stats *stats = &t->dev->stats;
448 struct ipv6hdr *ipv6h;
449 struct flowi fl;
446 int ret; 450 int ret;
447 451
452 memset(&fl, 0, sizeof(fl));
453 skb->mark = be32_to_cpu(t->parms.o_key);
454
448 switch (skb->protocol) { 455 switch (skb->protocol) {
449 case htons(ETH_P_IPV6): 456 case htons(ETH_P_IPV6):
450 ret = vti6_xmit(skb, dev); 457 ipv6h = ipv6_hdr(skb);
458
459 if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
460 !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
461 goto tx_err;
462
463 xfrm_decode_session(skb, &fl, AF_INET6);
464 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
465 break;
466 case htons(ETH_P_IP):
467 xfrm_decode_session(skb, &fl, AF_INET);
468 memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
451 break; 469 break;
452 default: 470 default:
453 goto tx_err; 471 goto tx_err;
454 } 472 }
455 473
474 ret = vti6_xmit(skb, dev, &fl);
456 if (ret < 0) 475 if (ret < 0)
457 goto tx_err; 476 goto tx_err;
458 477