Skip to content

Commit c4d3efa

Browse files
yasuyuki5David S. Miller
authored and
David S. Miller
committed
[IPV6] IP6TUNNEL: Add support to IPv4 over IPv6 tunnel.
Some notes - Protocol number IPPROTO_IPIP is used for IPv4 over IPv6 packets. - If IP6_TNL_F_USE_ORIG_TCLASS is set, TOS in IPv4 header is copied to Traffic Class in outer IPv6 header on xmit. - IP6_TNL_F_USE_ORIG_FLOWLABEL is ignored on xmit of IPv4 packets, because IPv4 header does not have flow label. - Kernel sends ICMP error if IPv4 packet is too big on xmit, even if DF flag is not set. Signed-off-by: Yasuyuki Kozakai <[email protected]> Signed-off-by: YOSHIFUJI Hideaki <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 61ec2ae commit c4d3efa

File tree

1 file changed

+185
-5
lines changed

1 file changed

+185
-5
lines changed

net/ipv6/ip6_tunnel.c

Lines changed: 185 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
/*
2-
* IPv6 over IPv6 tunnel device
2+
* IPv6 tunneling device
33
* Linux INET6 implementation
44
*
55
* Authors:
66
* Ville Nuorvala <[email protected]>
7+
* Yasuyuki Kozakai <[email protected]>
78
*
89
* $Id$
910
*
1011
* Based on:
11-
* linux/net/ipv6/sit.c
12+
* linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
1213
*
1314
* RFC 2473
1415
*
@@ -24,6 +25,7 @@
2425
#include <linux/errno.h>
2526
#include <linux/types.h>
2627
#include <linux/sockios.h>
28+
#include <linux/icmp.h>
2729
#include <linux/if.h>
2830
#include <linux/in.h>
2931
#include <linux/ip.h>
@@ -41,6 +43,7 @@
4143
#include <asm/uaccess.h>
4244
#include <asm/atomic.h>
4345

46+
#include <net/icmp.h>
4447
#include <net/ip.h>
4548
#include <net/ipv6.h>
4649
#include <net/ip6_route.h>
@@ -51,7 +54,7 @@
5154
#include <net/inet_ecn.h>
5255

5356
MODULE_AUTHOR("Ville Nuorvala");
54-
MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel");
57+
MODULE_DESCRIPTION("IPv6 tunneling device");
5558
MODULE_LICENSE("GPL");
5659

5760
#define IPV6_TLV_TEL_DST_SIZE 8
@@ -63,6 +66,7 @@ MODULE_LICENSE("GPL");
6366
#endif
6467

6568
#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
69+
#define IPV6_TCLASS_SHIFT 20
6670

6771
#define HASH_SIZE 32
6872

@@ -469,6 +473,104 @@ ip6_tnl_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
469473
return err;
470474
}
471475

476+
static int
477+
ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
478+
int type, int code, int offset, __u32 info)
479+
{
480+
int rel_msg = 0;
481+
int rel_type = type;
482+
int rel_code = code;
483+
__u32 rel_info = info;
484+
int err;
485+
struct sk_buff *skb2;
486+
struct iphdr *eiph;
487+
struct flowi fl;
488+
struct rtable *rt;
489+
490+
err = ip6_tnl_err(skb, opt, &rel_type, &rel_code, &rel_msg, &rel_info,
491+
offset);
492+
if (err < 0)
493+
return err;
494+
495+
if (rel_msg == 0)
496+
return 0;
497+
498+
switch (rel_type) {
499+
case ICMPV6_DEST_UNREACH:
500+
if (rel_code != ICMPV6_ADDR_UNREACH)
501+
return 0;
502+
rel_type = ICMP_DEST_UNREACH;
503+
rel_code = ICMP_HOST_UNREACH;
504+
break;
505+
case ICMPV6_PKT_TOOBIG:
506+
if (rel_code != 0)
507+
return 0;
508+
rel_type = ICMP_DEST_UNREACH;
509+
rel_code = ICMP_FRAG_NEEDED;
510+
break;
511+
default:
512+
return 0;
513+
}
514+
515+
if (!pskb_may_pull(skb, offset + sizeof(struct iphdr)))
516+
return 0;
517+
518+
skb2 = skb_clone(skb, GFP_ATOMIC);
519+
if (!skb2)
520+
return 0;
521+
522+
dst_release(skb2->dst);
523+
skb2->dst = NULL;
524+
skb_pull(skb2, offset);
525+
skb2->nh.raw = skb2->data;
526+
eiph = skb2->nh.iph;
527+
528+
/* Try to guess incoming interface */
529+
memset(&fl, 0, sizeof(fl));
530+
fl.fl4_dst = eiph->saddr;
531+
fl.fl4_tos = RT_TOS(eiph->tos);
532+
fl.proto = IPPROTO_IPIP;
533+
if (ip_route_output_key(&rt, &fl))
534+
goto out;
535+
536+
skb2->dev = rt->u.dst.dev;
537+
538+
/* route "incoming" packet */
539+
if (rt->rt_flags & RTCF_LOCAL) {
540+
ip_rt_put(rt);
541+
rt = NULL;
542+
fl.fl4_dst = eiph->daddr;
543+
fl.fl4_src = eiph->saddr;
544+
fl.fl4_tos = eiph->tos;
545+
if (ip_route_output_key(&rt, &fl) ||
546+
rt->u.dst.dev->type != ARPHRD_TUNNEL) {
547+
ip_rt_put(rt);
548+
goto out;
549+
}
550+
} else {
551+
ip_rt_put(rt);
552+
if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos,
553+
skb2->dev) ||
554+
skb2->dst->dev->type != ARPHRD_TUNNEL)
555+
goto out;
556+
}
557+
558+
/* change mtu on this route */
559+
if (rel_type == ICMP_DEST_UNREACH && rel_code == ICMP_FRAG_NEEDED) {
560+
if (rel_info > dst_mtu(skb2->dst))
561+
goto out;
562+
563+
skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
564+
rel_info = htonl(rel_info);
565+
}
566+
567+
icmp_send(skb2, rel_type, rel_code, rel_info);
568+
569+
out:
570+
kfree_skb(skb2);
571+
return 0;
572+
}
573+
472574
static int
473575
ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
474576
int type, int code, int offset, __u32 info)
@@ -513,6 +615,19 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
513615
return 0;
514616
}
515617

618+
static void ip4ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
619+
struct ipv6hdr *ipv6h,
620+
struct sk_buff *skb)
621+
{
622+
__u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK;
623+
624+
if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
625+
ipv4_change_dsfield(skb->nh.iph, INET_ECN_MASK, dsfield);
626+
627+
if (INET_ECN_is_ce(dsfield))
628+
IP_ECN_set_ce(skb->nh.iph);
629+
}
630+
516631
static void ip6ip6_dscp_ecn_decapsulate(struct ip6_tnl *t,
517632
struct ipv6hdr *ipv6h,
518633
struct sk_buff *skb)
@@ -605,6 +720,11 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol,
605720
return 0;
606721
}
607722

723+
static int ip4ip6_rcv(struct sk_buff *skb)
724+
{
725+
return ip6_tnl_rcv(skb, ETH_P_IP, ip4ip6_dscp_ecn_decapsulate);
726+
}
727+
608728
static int ip6ip6_rcv(struct sk_buff *skb)
609729
{
610730
return ip6_tnl_rcv(skb, ETH_P_IPV6, ip6ip6_dscp_ecn_decapsulate);
@@ -691,7 +811,7 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
691811
* it.
692812
*
693813
* Return:
694-
* 0
814+
* 0 on success
695815
* -1 fail
696816
* %-EMSGSIZE message too big. return mtu in this case.
697817
**/
@@ -808,6 +928,44 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
808928
return err;
809929
}
810930

931+
static inline int
932+
ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
933+
{
934+
struct ip6_tnl *t = netdev_priv(dev);
935+
struct iphdr *iph = skb->nh.iph;
936+
int encap_limit = -1;
937+
struct flowi fl;
938+
__u8 dsfield;
939+
__u32 mtu;
940+
int err;
941+
942+
if (!ip6_tnl_xmit_ctl(t))
943+
return -1;
944+
945+
if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
946+
encap_limit = t->parms.encap_limit;
947+
948+
memcpy(&fl, &t->fl, sizeof (fl));
949+
fl.proto = IPPROTO_IPIP;
950+
951+
dsfield = ipv4_get_dsfield(iph);
952+
953+
if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
954+
fl.fl6_flowlabel |= ntohl(((__u32)iph->tos << IPV6_TCLASS_SHIFT)
955+
& IPV6_TCLASS_MASK);
956+
957+
err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu);
958+
if (err != 0) {
959+
/* XXX: send ICMP error even if DF is not set. */
960+
if (err == -EMSGSIZE)
961+
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
962+
htonl(mtu));
963+
return -1;
964+
}
965+
966+
return 0;
967+
}
968+
811969
static inline int
812970
ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
813971
{
@@ -867,6 +1025,9 @@ ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
8671025
}
8681026

8691027
switch (skb->protocol) {
1028+
case __constant_htons(ETH_P_IP):
1029+
ret = ip4ip6_tnl_xmit(skb, dev);
1030+
break;
8701031
case __constant_htons(ETH_P_IPV6):
8711032
ret = ip6ip6_tnl_xmit(skb, dev);
8721033
break;
@@ -1199,6 +1360,12 @@ ip6ip6_fb_tnl_dev_init(struct net_device *dev)
11991360
return 0;
12001361
}
12011362

1363+
static struct xfrm6_tunnel ip4ip6_handler = {
1364+
.handler = ip4ip6_rcv,
1365+
.err_handler = ip4ip6_err,
1366+
.priority = 1,
1367+
};
1368+
12021369
static struct xfrm6_tunnel ip6ip6_handler = {
12031370
.handler = ip6ip6_rcv,
12041371
.err_handler = ip6ip6_err,
@@ -1215,9 +1382,16 @@ static int __init ip6_tunnel_init(void)
12151382
{
12161383
int err;
12171384

1385+
if (xfrm6_tunnel_register(&ip4ip6_handler, AF_INET)) {
1386+
printk(KERN_ERR "ip4ip6 init: can't register tunnel\n");
1387+
err = -EAGAIN;
1388+
goto out;
1389+
}
1390+
12181391
if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) {
12191392
printk(KERN_ERR "ip6ip6 init: can't register tunnel\n");
1220-
return -EAGAIN;
1393+
err = -EAGAIN;
1394+
goto unreg_ip4ip6;
12211395
}
12221396
ip6ip6_fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0",
12231397
ip6ip6_tnl_dev_setup);
@@ -1235,6 +1409,9 @@ static int __init ip6_tunnel_init(void)
12351409
return 0;
12361410
fail:
12371411
xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6);
1412+
unreg_ip4ip6:
1413+
xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET);
1414+
out:
12381415
return err;
12391416
}
12401417

@@ -1258,6 +1435,9 @@ static void __exit ip6ip6_destroy_tunnels(void)
12581435

12591436
static void __exit ip6_tunnel_cleanup(void)
12601437
{
1438+
if (xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET))
1439+
printk(KERN_INFO "ip4ip6 close: can't deregister tunnel\n");
1440+
12611441
if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6))
12621442
printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n");
12631443

0 commit comments

Comments
 (0)