Skip to content

Commit 22e1b23

Browse files
committed
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 <[email protected]>
1 parent 573ce1c commit 22e1b23

File tree

1 file changed

+34
-15
lines changed

1 file changed

+34
-15
lines changed

net/ipv6/ip6_vti.c

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -380,30 +380,22 @@ vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
380380
* vti6_xmit - send a packet
381381
* @skb: the outgoing socket buffer
382382
* @dev: the outgoing tunnel device
383+
* @fl: the flow informations for the xfrm_lookup
383384
**/
384-
static int vti6_xmit(struct sk_buff *skb, struct net_device *dev)
385+
static int
386+
vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
385387
{
386388
struct ip6_tnl *t = netdev_priv(dev);
387389
struct net_device_stats *stats = &t->dev->stats;
388390
struct dst_entry *dst = skb_dst(skb);
389-
struct flowi fl;
390-
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
391391
struct net_device *tdev;
392392
int err = -1;
393393

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-
402394
if (!dst)
403395
goto tx_err_link_failure;
404396

405397
dst_hold(dst);
406-
dst = xfrm_lookup(t->net, dst, &fl, NULL, 0);
398+
dst = xfrm_lookup(t->net, dst, fl, NULL, 0);
407399
if (IS_ERR(dst)) {
408400
err = PTR_ERR(dst);
409401
dst = NULL;
@@ -422,12 +414,22 @@ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev)
422414
goto tx_err_dst_release;
423415
}
424416

425-
memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
426417
skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
427418
skb_dst_set(skb, dst);
428419
skb->dev = skb_dst(skb)->dev;
429420

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+
}
431433

432434
return 0;
433435
tx_err_link_failure:
@@ -443,16 +445,33 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
443445
{
444446
struct ip6_tnl *t = netdev_priv(dev);
445447
struct net_device_stats *stats = &t->dev->stats;
448+
struct ipv6hdr *ipv6h;
449+
struct flowi fl;
446450
int ret;
447451

452+
memset(&fl, 0, sizeof(fl));
453+
skb->mark = be32_to_cpu(t->parms.o_key);
454+
448455
switch (skb->protocol) {
449456
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)));
451469
break;
452470
default:
453471
goto tx_err;
454472
}
455473

474+
ret = vti6_xmit(skb, dev, &fl);
456475
if (ret < 0)
457476
goto tx_err;
458477

0 commit comments

Comments
 (0)