aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>2009-09-22 19:43:14 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-07 04:07:37 -0400
commitfa857afcf77da669eb6b7031ec07ad14b912c307 (patch)
tree3dcc3899a968e2e21f912442ebfb4cac46f93a0c
parentee5e81f00051b5c373c8de16e3604fd6d3be699e (diff)
ipv6 sit: 6rd (IPv6 Rapid Deployment) Support.
IPv6 Rapid Deployment (6rd; draft-ietf-softwire-ipv6-6rd) builds upon mechanisms of 6to4 (RFC3056) to enable a service provider to rapidly deploy IPv6 unicast service to IPv4 sites to which it provides customer premise equipment. Like 6to4, it utilizes stateless IPv6 in IPv4 encapsulation in order to transit IPv4-only network infrastructure. Unlike 6to4, a 6rd service provider uses an IPv6 prefix of its own in place of the fixed 6to4 prefix. With this option enabled, the SIT driver offers 6rd functionality by providing additional ioctl API to configure the IPv6 Prefix for in stead of static 2002::/16 for 6to4. Original patch was done by Alexandre Cassen <acassen@freebox.fr> based on old Internet-Draft. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/if_tunnel.h11
-rw-r--r--include/net/ipip.h13
-rw-r--r--net/ipv6/Kconfig19
-rw-r--r--net/ipv6/sit.c124
4 files changed, 159 insertions, 8 deletions
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 5a9aae4adb44..c53c8e016940 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -15,6 +15,10 @@
15#define SIOCADDPRL (SIOCDEVPRIVATE + 5) 15#define SIOCADDPRL (SIOCDEVPRIVATE + 5)
16#define SIOCDELPRL (SIOCDEVPRIVATE + 6) 16#define SIOCDELPRL (SIOCDEVPRIVATE + 6)
17#define SIOCCHGPRL (SIOCDEVPRIVATE + 7) 17#define SIOCCHGPRL (SIOCDEVPRIVATE + 7)
18#define SIOCGET6RD (SIOCDEVPRIVATE + 8)
19#define SIOCADD6RD (SIOCDEVPRIVATE + 9)
20#define SIOCDEL6RD (SIOCDEVPRIVATE + 10)
21#define SIOCCHG6RD (SIOCDEVPRIVATE + 11)
18 22
19#define GRE_CSUM __cpu_to_be16(0x8000) 23#define GRE_CSUM __cpu_to_be16(0x8000)
20#define GRE_ROUTING __cpu_to_be16(0x4000) 24#define GRE_ROUTING __cpu_to_be16(0x4000)
@@ -51,6 +55,13 @@ struct ip_tunnel_prl {
51/* PRL flags */ 55/* PRL flags */
52#define PRL_DEFAULT 0x0001 56#define PRL_DEFAULT 0x0001
53 57
58struct ip_tunnel_6rd {
59 struct in6_addr prefix;
60 __be32 relay_prefix;
61 __u16 prefixlen;
62 __u16 relay_prefixlen;
63};
64
54enum 65enum
55{ 66{
56 IFLA_GRE_UNSPEC, 67 IFLA_GRE_UNSPEC,
diff --git a/include/net/ipip.h b/include/net/ipip.h
index 0159221a8509..86f1c8bd040c 100644
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -7,6 +7,15 @@
7/* Keep error state on tunnel for 30 sec */ 7/* Keep error state on tunnel for 30 sec */
8#define IPTUNNEL_ERR_TIMEO (30*HZ) 8#define IPTUNNEL_ERR_TIMEO (30*HZ)
9 9
10/* 6rd prefix/relay information */
11struct ip_tunnel_6rd_parm
12{
13 struct in6_addr prefix;
14 __be32 relay_prefix;
15 u16 prefixlen;
16 u16 relay_prefixlen;
17};
18
10struct ip_tunnel 19struct ip_tunnel
11{ 20{
12 struct ip_tunnel *next; 21 struct ip_tunnel *next;
@@ -23,6 +32,10 @@ struct ip_tunnel
23 32
24 struct ip_tunnel_parm parms; 33 struct ip_tunnel_parm parms;
25 34
35 /* for SIT */
36#ifdef CONFIG_IPV6_SIT_6RD
37 struct ip_tunnel_6rd_parm ip6rd;
38#endif
26 struct ip_tunnel_prl_entry *prl; /* potential router list */ 39 struct ip_tunnel_prl_entry *prl; /* potential router list */
27 unsigned int prl_count; /* # of entries in PRL */ 40 unsigned int prl_count; /* # of entries in PRL */
28}; 41};
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index ead6c7a42f44..f56199827452 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -170,6 +170,25 @@ config IPV6_SIT
170 170
171 Saying M here will produce a module called sit. If unsure, say Y. 171 Saying M here will produce a module called sit. If unsure, say Y.
172 172
173config IPV6_SIT_6RD
174 bool "IPv6: IPv6 Rapid Development (6RD) (EXPERIMENTAL)"
175 depends on IPV6_SIT && EXPERIMENTAL
176 default n
177 ---help---
178 IPv6 Rapid Deployment (6rd; draft-ietf-softwire-ipv6-6rd) builds upon
179 mechanisms of 6to4 (RFC3056) to enable a service provider to rapidly
180 deploy IPv6 unicast service to IPv4 sites to which it provides
181 customer premise equipment. Like 6to4, it utilizes stateless IPv6 in
182 IPv4 encapsulation in order to transit IPv4-only network
183 infrastructure. Unlike 6to4, a 6rd service provider uses an IPv6
184 prefix of its own in place of the fixed 6to4 prefix.
185
186 With this option enabled, the SIT driver offers 6rd functionality by
187 providing additional ioctl API to configure the IPv6 Prefix for in
188 stead of static 2002::/16 for 6to4.
189
190 If unsure, say N.
191
173config IPV6_NDISC_NODETYPE 192config IPV6_NDISC_NODETYPE
174 bool 193 bool
175 194
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 99da272951dc..6955654262a5 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -161,6 +161,21 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
161 write_unlock_bh(&ipip6_lock); 161 write_unlock_bh(&ipip6_lock);
162} 162}
163 163
164static void ipip6_tunnel_clone_6rd(struct ip_tunnel *t, struct sit_net *sitn)
165{
166#ifdef CONFIG_IPV6_SIT_6RD
167 if (t->dev == sitn->fb_tunnel_dev) {
168 ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0);
169 t->ip6rd.relay_prefix = 0;
170 t->ip6rd.prefixlen = 16;
171 t->ip6rd.relay_prefixlen = 0;
172 } else {
173 struct ip_tunnel *t0 = netdev_priv(sitn->fb_tunnel_dev);
174 memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd));
175 }
176#endif
177}
178
164static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, 179static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
165 struct ip_tunnel_parm *parms, int create) 180 struct ip_tunnel_parm *parms, int create)
166{ 181{
@@ -213,6 +228,8 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
213 228
214 dev_hold(dev); 229 dev_hold(dev);
215 230
231 ipip6_tunnel_clone_6rd(t, sitn);
232
216 ipip6_tunnel_link(sitn, nt); 233 ipip6_tunnel_link(sitn, nt);
217 return nt; 234 return nt;
218 235
@@ -532,17 +549,41 @@ out:
532 return 0; 549 return 0;
533} 550}
534 551
535/* Returns the embedded IPv4 address if the IPv6 address 552/*
536 comes from 6to4 (RFC 3056) addr space */ 553 * Returns the embedded IPv4 address if the IPv6 address
537 554 * comes from 6rd / 6to4 (RFC 3056) addr space.
538static inline __be32 try_6to4(struct in6_addr *v6dst) 555 */
556static inline
557__be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel)
539{ 558{
540 __be32 dst = 0; 559 __be32 dst = 0;
541 560
561#ifdef CONFIG_IPV6_SIT_6RD
562 if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix,
563 tunnel->ip6rd.prefixlen)) {
564 unsigned pbw0, pbi0;
565 int pbi1;
566 u32 d;
567
568 pbw0 = tunnel->ip6rd.prefixlen >> 5;
569 pbi0 = tunnel->ip6rd.prefixlen & 0x1f;
570
571 d = (ntohl(tunnel->ip6rd.prefix.s6_addr32[pbw0]) << pbi0) >>
572 tunnel->ip6rd.relay_prefixlen;
573
574 pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen;
575 if (pbi1 > 0)
576 d |= ntohl(tunnel->ip6rd.prefix.s6_addr32[pbw0 + 1]) >>
577 (32 - pbi1);
578
579 dst = tunnel->ip6rd.relay_prefix | htonl(d);
580 }
581#else
542 if (v6dst->s6_addr16[0] == htons(0x2002)) { 582 if (v6dst->s6_addr16[0] == htons(0x2002)) {
543 /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ 583 /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */
544 memcpy(&dst, &v6dst->s6_addr16[1], 4); 584 memcpy(&dst, &v6dst->s6_addr16[1], 4);
545 } 585 }
586#endif
546 return dst; 587 return dst;
547} 588}
548 589
@@ -596,7 +637,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
596 } 637 }
597 638
598 if (!dst) 639 if (!dst)
599 dst = try_6to4(&iph6->daddr); 640 dst = try_6rd(&iph6->daddr, tunnel);
600 641
601 if (!dst) { 642 if (!dst) {
602 struct neighbour *neigh = NULL; 643 struct neighbour *neigh = NULL;
@@ -786,9 +827,15 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
786 struct ip_tunnel *t; 827 struct ip_tunnel *t;
787 struct net *net = dev_net(dev); 828 struct net *net = dev_net(dev);
788 struct sit_net *sitn = net_generic(net, sit_net_id); 829 struct sit_net *sitn = net_generic(net, sit_net_id);
830#ifdef CONFIG_IPV6_SIT_6RD
831 struct ip_tunnel_6rd ip6rd;
832#endif
789 833
790 switch (cmd) { 834 switch (cmd) {
791 case SIOCGETTUNNEL: 835 case SIOCGETTUNNEL:
836#ifdef CONFIG_IPV6_SIT_6RD
837 case SIOCGET6RD:
838#endif
792 t = NULL; 839 t = NULL;
793 if (dev == sitn->fb_tunnel_dev) { 840 if (dev == sitn->fb_tunnel_dev) {
794 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { 841 if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
@@ -799,9 +846,25 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
799 } 846 }
800 if (t == NULL) 847 if (t == NULL)
801 t = netdev_priv(dev); 848 t = netdev_priv(dev);
802 memcpy(&p, &t->parms, sizeof(p)); 849
803 if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) 850 err = -EFAULT;
804 err = -EFAULT; 851 if (cmd == SIOCGETTUNNEL) {
852 memcpy(&p, &t->parms, sizeof(p));
853 if (copy_to_user(ifr->ifr_ifru.ifru_data, &p,
854 sizeof(p)))
855 goto done;
856#ifdef CONFIG_IPV6_SIT_6RD
857 } else {
858 ipv6_addr_copy(&ip6rd.prefix, &t->ip6rd.prefix);
859 ip6rd.relay_prefix = t->ip6rd.relay_prefix;
860 ip6rd.prefixlen = t->ip6rd.prefixlen;
861 ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen;
862 if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd,
863 sizeof(ip6rd)))
864 goto done;
865#endif
866 }
867 err = 0;
805 break; 868 break;
806 869
807 case SIOCADDTUNNEL: 870 case SIOCADDTUNNEL:
@@ -922,6 +985,51 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
922 netdev_state_change(dev); 985 netdev_state_change(dev);
923 break; 986 break;
924 987
988#ifdef CONFIG_IPV6_SIT_6RD
989 case SIOCADD6RD:
990 case SIOCCHG6RD:
991 case SIOCDEL6RD:
992 err = -EPERM;
993 if (!capable(CAP_NET_ADMIN))
994 goto done;
995
996 err = -EFAULT;
997 if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data,
998 sizeof(ip6rd)))
999 goto done;
1000
1001 t = netdev_priv(dev);
1002
1003 if (cmd != SIOCDEL6RD) {
1004 struct in6_addr prefix;
1005 __be32 relay_prefix;
1006
1007 err = -EINVAL;
1008 if (ip6rd.relay_prefixlen > 32 ||
1009 ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64)
1010 goto done;
1011
1012 ipv6_addr_prefix(&prefix, &ip6rd.prefix,
1013 ip6rd.prefixlen);
1014 if (!ipv6_addr_equal(&prefix, &ip6rd.prefix))
1015 goto done;
1016 relay_prefix = ip6rd.relay_prefix &
1017 htonl(0xffffffffUL <<
1018 (32 - ip6rd.relay_prefixlen));
1019 if (relay_prefix != ip6rd.relay_prefix)
1020 goto done;
1021
1022 ipv6_addr_copy(&t->ip6rd.prefix, &prefix);
1023 t->ip6rd.relay_prefix = relay_prefix;
1024 t->ip6rd.prefixlen = ip6rd.prefixlen;
1025 t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen;
1026 } else
1027 ipip6_tunnel_clone_6rd(t, sitn);
1028
1029 err = 0;
1030 break;
1031#endif
1032
925 default: 1033 default:
926 err = -EINVAL; 1034 err = -EINVAL;
927 } 1035 }