diff mbox

[RESEND,3] IPv6: 6rd tunnel mode

Message ID 20090922220251.GA22874@lnxos.staff.proxad.net
State Superseded, archived
Delegated to: David Miller
Headers show

Commit Message

Alexandre Cassen Sept. 22, 2009, 10:02 p.m. UTC
This patch add support to 6rd tunnel mode as described into
draft-despres-6rd-03.

Patch history :
* http://patchwork.ozlabs.org/patch/26870/
* http://patchwork.ozlabs.org/patch/34026/
* http://patchwork.ozlabs.org/patch/34045/

IPv6 rapid deployment (draft-despres-6rd-03) 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.

Signed-off-by: Alexandre Cassen <acassen@freebox.fr>
---
 include/linux/if_tunnel.h |   10 +++++
 include/net/ipip.h        |    2 +
 net/ipv6/Kconfig          |   13 +++++++
 net/ipv6/sit.c            |   84 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 109 insertions(+), 0 deletions(-)

Comments

Eric Dumazet Sept. 22, 2009, 10:18 p.m. UTC | #1
Alexandre Cassen a écrit :
> This patch add support to 6rd tunnel mode as described into
> draft-despres-6rd-03.
> 
> Patch history :
> * http://patchwork.ozlabs.org/patch/26870/
> * http://patchwork.ozlabs.org/patch/34026/
> * http://patchwork.ozlabs.org/patch/34045/
> 
> IPv6 rapid deployment (draft-despres-6rd-03) 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.
> 
> Signed-off-by: Alexandre Cassen <acassen@freebox.fr>
> ---
>  include/linux/if_tunnel.h |   10 +++++
>  include/net/ipip.h        |    2 +
>  net/ipv6/Kconfig          |   13 +++++++
>  net/ipv6/sit.c            |   84 +++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 109 insertions(+), 0 deletions(-)
> 
> diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
> index 5eb9b0f..0d44376 100644
> --- a/include/linux/if_tunnel.h
> +++ b/include/linux/if_tunnel.h
> @@ -15,6 +15,10 @@
>  #define SIOCADDPRL      (SIOCDEVPRIVATE + 5)
>  #define SIOCDELPRL      (SIOCDEVPRIVATE + 6)
>  #define SIOCCHGPRL      (SIOCDEVPRIVATE + 7)
> +#define SIOCGET6RD      (SIOCDEVPRIVATE + 8)
> +#define SIOCADD6RD      (SIOCDEVPRIVATE + 9)
> +#define SIOCDEL6RD      (SIOCDEVPRIVATE + 10)
> +#define SIOCCHG6RD      (SIOCDEVPRIVATE + 11)
>  
>  #define GRE_CSUM	__cpu_to_be16(0x8000)
>  #define GRE_ROUTING	__cpu_to_be16(0x4000)
> @@ -51,6 +55,12 @@ struct ip_tunnel_prl {
>  /* PRL flags */
>  #define	PRL_DEFAULT		0x0001
>  
> +/* 6RD parms */
> +struct ip_tunnel_6rd {
> +	struct in6_addr		addr;
> +	__u8			prefixlen;
> +};
> +
>  enum
>  {
>  	IFLA_GRE_UNSPEC,
> diff --git a/include/net/ipip.h b/include/net/ipip.h
> index 5d3036f..fa92c41 100644
> --- a/include/net/ipip.h
> +++ b/include/net/ipip.h
> @@ -26,6 +26,8 @@ struct ip_tunnel
>  
>  	struct ip_tunnel_prl_entry	*prl;		/* potential router list */
>  	unsigned int			prl_count;	/* # of entries in PRL */
> +
> +	struct ip_tunnel_6rd	ip6rd_prefix;	/* 6RD SP prefix */
>  };
>  
>  /* ISATAP: default interval between RS in secondy */
> diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
> index ead6c7a..8b779f7 100644
> --- a/net/ipv6/Kconfig
> +++ b/net/ipv6/Kconfig
> @@ -170,6 +170,19 @@ config IPV6_SIT
>  
>  	  Saying M here will produce a module called sit. If unsure, say Y.
>  
> +config IPV6_SIT_6RD
> +	bool "IPv6: 6rd tunnel mode (EXPERIMENTAL)"
> +	depends on IPV6_SIT && EXPERIMENTAL
> +	default n
> +	---help---
> +	IPv6 rapid deployment (draft-despres-6rd-03) 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.
> +
>  config IPV6_NDISC_NODETYPE
>  	bool
>  
> diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
> index 0ae4f64..3587149 100644
> --- a/net/ipv6/sit.c
> +++ b/net/ipv6/sit.c
> @@ -604,6 +604,30 @@ static inline __be32 try_6to4(struct in6_addr *v6dst)
>  	return dst;
>  }
>  
> +#ifdef CONFIG_IPV6_SIT_6RD
> +/* Returns the embedded IPv4 address if the IPv6 address comes from
> +   6rd rule */
> +
> +static inline __be32 try_6rd(struct in6_addr *addr, u8 prefix_len, struct in6_addr *v6dst)
> +{
> +	__be32 dst = 0;
> +
> +	/* isolate addr according to mask */
> +	if (ipv6_prefix_equal(v6dst, addr, prefix_len)) {
> +		unsigned int d32_off, bits;
> +
> +		d32_off = prefix_len >> 5;
> +		bits = (prefix_len & 0x1f);
> +
> +		dst = (ntohl(v6dst->s6_addr32[d32_off]) << bits);
> +		if (bits)
> +			dst |= ntohl(v6dst->s6_addr32[d32_off + 1]) >> (32 - bits);
> +		dst = htonl(dst);
> +	}
> +	return dst;
> +}
> +#endif
> +
>  /*
>   *	This function assumes it is being called from dev_queue_xmit()
>   *	and that skb is filled properly by that function.
> @@ -657,6 +681,13 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
>  			goto tx_error;
>  	}
>  
> +#ifdef CONFIG_IPV6_SIT_6RD
> +	if (!dst && tunnel->ip6rd_prefix.prefixlen)
> +		dst = try_6rd(&tunnel->ip6rd_prefix.addr,
> +			      tunnel->ip6rd_prefix.prefixlen,
> +			      &iph6->daddr);
> +	else
> +#endif
>  	if (!dst)
>  		dst = try_6to4(&iph6->daddr);
>  
> @@ -848,6 +879,9 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
>  	int err = 0;
>  	struct ip_tunnel_parm p;
>  	struct ip_tunnel_prl prl;
> +#ifdef CONFIG_IPV6_SIT_6RD
> +	struct ip_tunnel_6rd ip6rd;
> +#endif
>  	struct ip_tunnel *t;
>  	struct net *net = dev_net(dev);
>  	struct sit_net *sitn = net_generic(net, sit_net_id);
> @@ -987,6 +1021,56 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
>  		netdev_state_change(dev);
>  		break;
>  
> +#ifdef CONFIG_IPV6_SIT_6RD
> +	case SIOCGET6RD:
> +		err = -EINVAL;
> +		if (dev == sitn->fb_tunnel_dev)
> +			goto done;
> +		err = -ENOENT;
> +		if (!(t = netdev_priv(dev)))
> +			goto done;

> +		memcpy(&ip6rd, &t->ip6rd_prefix, sizeof(ip6rd));

Just wondering why you need a temporary ip6rd here,
why dont you copy_to_user(ifr->ifr_ifru.ifru_data, &t->ip6rd_prefix, sizeof(ip6rd)); ?

> +		if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd, sizeof(ip6rd)))
> +			err = -EFAULT;
> +		else
> +			err = 0;
> +		break;
> +
> +	case SIOCADD6RD:
> +	case SIOCDEL6RD:
> +	case SIOCCHG6RD:
> +		err = -EPERM;
> +		if (!capable(CAP_NET_ADMIN))
> +			goto done;
> +		err = -EINVAL;
> +		if (dev == sitn->fb_tunnel_dev)
> +			goto done;
> +		err = -EFAULT;
> +		if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data, sizeof(ip6rd)))
> +			goto done;
> +		err = -ENOENT;
> +		if (!(t = netdev_priv(dev)))
> +			goto done;
> +
> +		err = 0;
> +		switch (cmd) {
> +		case SIOCDEL6RD:
> +			memset(&t->ip6rd_prefix, 0, sizeof(ip6rd));
> +			break;
> +		case SIOCADD6RD:
> +		case SIOCCHG6RD:
> +			if (ip6rd.prefixlen >= 95) {
> +				err = -EINVAL;
> +				goto done;
> +			}
> +			ipv6_addr_copy(&t->ip6rd_prefix.addr, &ip6rd.addr);
> +			t->ip6rd_prefix.prefixlen = ip6rd.prefixlen;
> +			break;
> +		}
> +		netdev_state_change(dev);
> +		break;
> +#endif
> +
>  	default:
>  		err = -EINVAL;
>  	}

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joe Perches Sept. 22, 2009, 11:06 p.m. UTC | #2
On Wed, 2009-09-23 at 00:02 +0200, Alexandre Cassen wrote:
> diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
> index 0ae4f64..3587149 100644
> --- a/net/ipv6/sit.c
> +++ b/net/ipv6/sit.c
[]
> +static inline __be32 try_6rd(struct in6_addr *addr, u8 prefix_len, struct in6_addr *v6dst)
> +{
> +	__be32 dst = 0;
> +
> +	/* isolate addr according to mask */
> +	if (ipv6_prefix_equal(v6dst, addr, prefix_len)) {
> +		unsigned int d32_off, bits;
> +
> +		d32_off = prefix_len >> 5;
> +		bits = (prefix_len & 0x1f);
> +
> +		dst = (ntohl(v6dst->s6_addr32[d32_off]) << bits);

unnecessary parens and a sparse warning?
Perhaps use a temporary u32 and an htonl or cpu_to_be32 at the end?

> +		if (bits)
> +			dst |= ntohl(v6dst->s6_addr32[d32_off + 1]) >> (32 - bits);
> +		dst = htonl(dst);
> +	}
> +	return dst;
> +}
> +#endif


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Brian Haley Sept. 23, 2009, 1:47 a.m. UTC | #3
Alexandre Cassen wrote:
>
> +/* 6RD parms */
> +struct ip_tunnel_6rd {
> +	struct in6_addr		addr;
> +	__u8			prefixlen;
> +};

Are you sure you're not going to want to add anything to this struct in
the future like ifindex or flags?  Since it's part of the API you'd want
to do that now.

-Brian
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Alexandre Cassen Sept. 23, 2009, 6:07 a.m. UTC | #4
On Wed, 23 Sep 2009, Eric Dumazet wrote:
>> +#ifdef CONFIG_IPV6_SIT_6RD
>> +	case SIOCGET6RD:
>> +		err = -EINVAL;
>> +		if (dev == sitn->fb_tunnel_dev)
>> +			goto done;
>> +		err = -ENOENT;
>> +		if (!(t = netdev_priv(dev)))
>> +			goto done;
>
>> +		memcpy(&ip6rd, &t->ip6rd_prefix, sizeof(ip6rd));
>
> Just wondering why you need a temporary ip6rd here,
> why dont you copy_to_user(ifr->ifr_ifru.ifru_data, &t->ip6rd_prefix, sizeof(ip6rd)); ?
>
>> +		if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd, sizeof(ip6rd)))
>> +			err = -EFAULT;
>> +		else
>> +			err = 0;
>> +		break;

agreed. will fix.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h
index 5eb9b0f..0d44376 100644
--- a/include/linux/if_tunnel.h
+++ b/include/linux/if_tunnel.h
@@ -15,6 +15,10 @@ 
 #define SIOCADDPRL      (SIOCDEVPRIVATE + 5)
 #define SIOCDELPRL      (SIOCDEVPRIVATE + 6)
 #define SIOCCHGPRL      (SIOCDEVPRIVATE + 7)
+#define SIOCGET6RD      (SIOCDEVPRIVATE + 8)
+#define SIOCADD6RD      (SIOCDEVPRIVATE + 9)
+#define SIOCDEL6RD      (SIOCDEVPRIVATE + 10)
+#define SIOCCHG6RD      (SIOCDEVPRIVATE + 11)
 
 #define GRE_CSUM	__cpu_to_be16(0x8000)
 #define GRE_ROUTING	__cpu_to_be16(0x4000)
@@ -51,6 +55,12 @@  struct ip_tunnel_prl {
 /* PRL flags */
 #define	PRL_DEFAULT		0x0001
 
+/* 6RD parms */
+struct ip_tunnel_6rd {
+	struct in6_addr		addr;
+	__u8			prefixlen;
+};
+
 enum
 {
 	IFLA_GRE_UNSPEC,
diff --git a/include/net/ipip.h b/include/net/ipip.h
index 5d3036f..fa92c41 100644
--- a/include/net/ipip.h
+++ b/include/net/ipip.h
@@ -26,6 +26,8 @@  struct ip_tunnel
 
 	struct ip_tunnel_prl_entry	*prl;		/* potential router list */
 	unsigned int			prl_count;	/* # of entries in PRL */
+
+	struct ip_tunnel_6rd	ip6rd_prefix;	/* 6RD SP prefix */
 };
 
 /* ISATAP: default interval between RS in secondy */
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index ead6c7a..8b779f7 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -170,6 +170,19 @@  config IPV6_SIT
 
 	  Saying M here will produce a module called sit. If unsure, say Y.
 
+config IPV6_SIT_6RD
+	bool "IPv6: 6rd tunnel mode (EXPERIMENTAL)"
+	depends on IPV6_SIT && EXPERIMENTAL
+	default n
+	---help---
+	IPv6 rapid deployment (draft-despres-6rd-03) 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.
+
 config IPV6_NDISC_NODETYPE
 	bool
 
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 0ae4f64..3587149 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -604,6 +604,30 @@  static inline __be32 try_6to4(struct in6_addr *v6dst)
 	return dst;
 }
 
+#ifdef CONFIG_IPV6_SIT_6RD
+/* Returns the embedded IPv4 address if the IPv6 address comes from
+   6rd rule */
+
+static inline __be32 try_6rd(struct in6_addr *addr, u8 prefix_len, struct in6_addr *v6dst)
+{
+	__be32 dst = 0;
+
+	/* isolate addr according to mask */
+	if (ipv6_prefix_equal(v6dst, addr, prefix_len)) {
+		unsigned int d32_off, bits;
+
+		d32_off = prefix_len >> 5;
+		bits = (prefix_len & 0x1f);
+
+		dst = (ntohl(v6dst->s6_addr32[d32_off]) << bits);
+		if (bits)
+			dst |= ntohl(v6dst->s6_addr32[d32_off + 1]) >> (32 - bits);
+		dst = htonl(dst);
+	}
+	return dst;
+}
+#endif
+
 /*
  *	This function assumes it is being called from dev_queue_xmit()
  *	and that skb is filled properly by that function.
@@ -657,6 +681,13 @@  static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
 			goto tx_error;
 	}
 
+#ifdef CONFIG_IPV6_SIT_6RD
+	if (!dst && tunnel->ip6rd_prefix.prefixlen)
+		dst = try_6rd(&tunnel->ip6rd_prefix.addr,
+			      tunnel->ip6rd_prefix.prefixlen,
+			      &iph6->daddr);
+	else
+#endif
 	if (!dst)
 		dst = try_6to4(&iph6->daddr);
 
@@ -848,6 +879,9 @@  ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 	int err = 0;
 	struct ip_tunnel_parm p;
 	struct ip_tunnel_prl prl;
+#ifdef CONFIG_IPV6_SIT_6RD
+	struct ip_tunnel_6rd ip6rd;
+#endif
 	struct ip_tunnel *t;
 	struct net *net = dev_net(dev);
 	struct sit_net *sitn = net_generic(net, sit_net_id);
@@ -987,6 +1021,56 @@  ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
 		netdev_state_change(dev);
 		break;
 
+#ifdef CONFIG_IPV6_SIT_6RD
+	case SIOCGET6RD:
+		err = -EINVAL;
+		if (dev == sitn->fb_tunnel_dev)
+			goto done;
+		err = -ENOENT;
+		if (!(t = netdev_priv(dev)))
+			goto done;
+		memcpy(&ip6rd, &t->ip6rd_prefix, sizeof(ip6rd));
+		if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd, sizeof(ip6rd)))
+			err = -EFAULT;
+		else
+			err = 0;
+		break;
+
+	case SIOCADD6RD:
+	case SIOCDEL6RD:
+	case SIOCCHG6RD:
+		err = -EPERM;
+		if (!capable(CAP_NET_ADMIN))
+			goto done;
+		err = -EINVAL;
+		if (dev == sitn->fb_tunnel_dev)
+			goto done;
+		err = -EFAULT;
+		if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data, sizeof(ip6rd)))
+			goto done;
+		err = -ENOENT;
+		if (!(t = netdev_priv(dev)))
+			goto done;
+
+		err = 0;
+		switch (cmd) {
+		case SIOCDEL6RD:
+			memset(&t->ip6rd_prefix, 0, sizeof(ip6rd));
+			break;
+		case SIOCADD6RD:
+		case SIOCCHG6RD:
+			if (ip6rd.prefixlen >= 95) {
+				err = -EINVAL;
+				goto done;
+			}
+			ipv6_addr_copy(&t->ip6rd_prefix.addr, &ip6rd.addr);
+			t->ip6rd_prefix.prefixlen = ip6rd.prefixlen;
+			break;
+		}
+		netdev_state_change(dev);
+		break;
+#endif
+
 	default:
 		err = -EINVAL;
 	}