diff mbox

[ovs-dev,v4,10/28] datapath: compat: Update udp_sock_create

Message ID 1467937435-73122-1-git-send-email-pshelar@ovn.org
State Superseded
Headers show

Commit Message

Pravin Shelar July 8, 2016, 12:23 a.m. UTC
Update udp-socket-create to create ipv6 socket currectly.

Partially backports commit fd384412e199b ("udp_tunnel: Seperate ipv6
functions into its own file.")

Signed-off-by: Pravin B Shelar <pshelar@ovn.org>
---
 acinclude.m4                                   |   2 +
 datapath/linux/Modules.mk                      |   1 +
 datapath/linux/compat/include/linux/udp.h      |  33 +++++++
 datapath/linux/compat/include/net/udp.h        |   1 -
 datapath/linux/compat/include/net/udp_tunnel.h |  30 +++++-
 datapath/linux/compat/udp.c                    |  12 +++
 datapath/linux/compat/udp_tunnel.c             | 123 +++++++++++++++----------
 datapath/linux/compat/vxlan.c                  |   7 ++
 8 files changed, 155 insertions(+), 54 deletions(-)
 create mode 100644 datapath/linux/compat/include/linux/udp.h

Comments

Jesse Gross July 8, 2016, 2:13 a.m. UTC | #1
On Thu, Jul 7, 2016 at 5:23 PM, Pravin B Shelar <pshelar@ovn.org> wrote:
> diff --git a/datapath/linux/compat/include/linux/udp.h b/datapath/linux/compat/include/linux/udp.h
> new file mode 100644
> index 0000000..31ae022
> --- /dev/null
> +++ b/datapath/linux/compat/include/linux/udp.h
> @@ -0,0 +1,33 @@
> +#ifndef __LINUX_UDP_WRAPPER_H
> +#define __LINUX_UDP_WRAPPER_H  1
> +
> +#include_next <linux/udp.h>
> +#include <linux/ipv6.h>
> +
> +#ifndef HAVE_NO_CHECK6_TX
> +static inline void udp_set_no_check6_tx(struct sock *sk, bool val)
> +{
> +#ifdef HAVE_SK_NO_CHECK_TX
> +       sk->sk_no_check_tx = val;
> +#else
> +       /* since netwroking stack is not checking for zero UDP checksum
> +        * check it in OVS module. */
> +       #define OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
> +#endif
> +}
> +
> +static inline void udp_set_no_check6_rx(struct sock *sk, bool val)
> +{
> +#ifdef HAVE_SK_NO_CHECK_TX
> +       sk->sk_no_check_rx = val;
> +#endif
> +}
> +#endif

I guess it probably makes more sense to #define
OVS_CHECK_UDP_TUNNEL_ZERO_CSUM in udp_set_no_check6_rx() since it is
receive side issue, though functionally it doesn't make a difference.

> diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
> index d45125d..3776990 100644
> --- a/datapath/linux/compat/vxlan.c
> +++ b/datapath/linux/compat/vxlan.c
> @@ -850,6 +850,13 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
>                 oip6 = ipv6_hdr(skb);
>                 saddr.sin6.sin6_addr = oip6->saddr;
>                 saddr.sa.sa_family = AF_INET6;
> +#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
> +               if (!udp_hdr(skb)->check &&
> +                   !(vs->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) {
> +                       udp6_csum_zero_error(skb);
> +                       goto drop;
> +               }
> +#endif
>  #endif

Do we need a version of this for Geneve as well?
Jesse Gross July 8, 2016, 2:16 a.m. UTC | #2
On Thu, Jul 7, 2016 at 7:13 PM, Jesse Gross <jesse@kernel.org> wrote:
> On Thu, Jul 7, 2016 at 5:23 PM, Pravin B Shelar <pshelar@ovn.org> wrote:
>> diff --git a/datapath/linux/compat/include/linux/udp.h b/datapath/linux/compat/include/linux/udp.h
>> new file mode 100644
>> index 0000000..31ae022
>> --- /dev/null
>> +++ b/datapath/linux/compat/include/linux/udp.h
>> @@ -0,0 +1,33 @@
>> +#ifndef __LINUX_UDP_WRAPPER_H
>> +#define __LINUX_UDP_WRAPPER_H  1
>> +
>> +#include_next <linux/udp.h>
>> +#include <linux/ipv6.h>
>> +
>> +#ifndef HAVE_NO_CHECK6_TX
>> +static inline void udp_set_no_check6_tx(struct sock *sk, bool val)
>> +{
>> +#ifdef HAVE_SK_NO_CHECK_TX
>> +       sk->sk_no_check_tx = val;
>> +#else
>> +       /* since netwroking stack is not checking for zero UDP checksum
>> +        * check it in OVS module. */
>> +       #define OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
>> +#endif
>> +}
>> +
>> +static inline void udp_set_no_check6_rx(struct sock *sk, bool val)
>> +{
>> +#ifdef HAVE_SK_NO_CHECK_TX
>> +       sk->sk_no_check_rx = val;
>> +#endif
>> +}
>> +#endif
>
> I guess it probably makes more sense to #define
> OVS_CHECK_UDP_TUNNEL_ZERO_CSUM in udp_set_no_check6_rx() since it is
> receive side issue, though functionally it doesn't make a difference.
>
>> diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
>> index d45125d..3776990 100644
>> --- a/datapath/linux/compat/vxlan.c
>> +++ b/datapath/linux/compat/vxlan.c
>> @@ -850,6 +850,13 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
>>                 oip6 = ipv6_hdr(skb);
>>                 saddr.sin6.sin6_addr = oip6->saddr;
>>                 saddr.sa.sa_family = AF_INET6;
>> +#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
>> +               if (!udp_hdr(skb)->check &&
>> +                   !(vs->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) {
>> +                       udp6_csum_zero_error(skb);
>> +                       goto drop;
>> +               }
>> +#endif
>>  #endif
>
> Do we need a version of this for Geneve as well?

OK - I see that it actually came in later in the big resync patch.
Pravin Shelar July 8, 2016, 2:17 a.m. UTC | #3
On Thu, Jul 7, 2016 at 7:16 PM, Jesse Gross <jesse@kernel.org> wrote:
> On Thu, Jul 7, 2016 at 7:13 PM, Jesse Gross <jesse@kernel.org> wrote:
>> On Thu, Jul 7, 2016 at 5:23 PM, Pravin B Shelar <pshelar@ovn.org> wrote:
>>> diff --git a/datapath/linux/compat/include/linux/udp.h b/datapath/linux/compat/include/linux/udp.h
>>> new file mode 100644
>>> index 0000000..31ae022
>>> --- /dev/null
>>> +++ b/datapath/linux/compat/include/linux/udp.h
>>> @@ -0,0 +1,33 @@
>>> +#ifndef __LINUX_UDP_WRAPPER_H
>>> +#define __LINUX_UDP_WRAPPER_H  1
>>> +
>>> +#include_next <linux/udp.h>
>>> +#include <linux/ipv6.h>
>>> +
>>> +#ifndef HAVE_NO_CHECK6_TX
>>> +static inline void udp_set_no_check6_tx(struct sock *sk, bool val)
>>> +{
>>> +#ifdef HAVE_SK_NO_CHECK_TX
>>> +       sk->sk_no_check_tx = val;
>>> +#else
>>> +       /* since netwroking stack is not checking for zero UDP checksum
>>> +        * check it in OVS module. */
>>> +       #define OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
>>> +#endif
>>> +}
>>> +
>>> +static inline void udp_set_no_check6_rx(struct sock *sk, bool val)
>>> +{
>>> +#ifdef HAVE_SK_NO_CHECK_TX
>>> +       sk->sk_no_check_rx = val;
>>> +#endif
>>> +}
>>> +#endif
>>
>> I guess it probably makes more sense to #define
>> OVS_CHECK_UDP_TUNNEL_ZERO_CSUM in udp_set_no_check6_rx() since it is
>> receive side issue, though functionally it doesn't make a difference.
>>
>>> diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
>>> index d45125d..3776990 100644
>>> --- a/datapath/linux/compat/vxlan.c
>>> +++ b/datapath/linux/compat/vxlan.c
>>> @@ -850,6 +850,13 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
>>>                 oip6 = ipv6_hdr(skb);
>>>                 saddr.sin6.sin6_addr = oip6->saddr;
>>>                 saddr.sa.sa_family = AF_INET6;
>>> +#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
>>> +               if (!udp_hdr(skb)->check &&
>>> +                   !(vs->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) {
>>> +                       udp6_csum_zero_error(skb);
>>> +                       goto drop;
>>> +               }
>>> +#endif
>>>  #endif
>>
>> Do we need a version of this for Geneve as well?
>
> OK - I see that it actually came in later in the big resync patch.

Yes, Geneve does not support ipv6 tunnels at this point.
Jesse Gross July 8, 2016, 2:20 a.m. UTC | #4
On Thu, Jul 7, 2016 at 7:17 PM, pravin shelar <pshelar@ovn.org> wrote:
> On Thu, Jul 7, 2016 at 7:16 PM, Jesse Gross <jesse@kernel.org> wrote:
>> On Thu, Jul 7, 2016 at 7:13 PM, Jesse Gross <jesse@kernel.org> wrote:
>>> On Thu, Jul 7, 2016 at 5:23 PM, Pravin B Shelar <pshelar@ovn.org> wrote:
>>>> diff --git a/datapath/linux/compat/include/linux/udp.h b/datapath/linux/compat/include/linux/udp.h
>>>> new file mode 100644
>>>> index 0000000..31ae022
>>>> --- /dev/null
>>>> +++ b/datapath/linux/compat/include/linux/udp.h
>>>> @@ -0,0 +1,33 @@
>>>> +#ifndef __LINUX_UDP_WRAPPER_H
>>>> +#define __LINUX_UDP_WRAPPER_H  1
>>>> +
>>>> +#include_next <linux/udp.h>
>>>> +#include <linux/ipv6.h>
>>>> +
>>>> +#ifndef HAVE_NO_CHECK6_TX
>>>> +static inline void udp_set_no_check6_tx(struct sock *sk, bool val)
>>>> +{
>>>> +#ifdef HAVE_SK_NO_CHECK_TX
>>>> +       sk->sk_no_check_tx = val;
>>>> +#else
>>>> +       /* since netwroking stack is not checking for zero UDP checksum
>>>> +        * check it in OVS module. */
>>>> +       #define OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
>>>> +#endif
>>>> +}
>>>> +
>>>> +static inline void udp_set_no_check6_rx(struct sock *sk, bool val)
>>>> +{
>>>> +#ifdef HAVE_SK_NO_CHECK_TX
>>>> +       sk->sk_no_check_rx = val;
>>>> +#endif
>>>> +}
>>>> +#endif
>>>
>>> I guess it probably makes more sense to #define
>>> OVS_CHECK_UDP_TUNNEL_ZERO_CSUM in udp_set_no_check6_rx() since it is
>>> receive side issue, though functionally it doesn't make a difference.
>>>
>>>> diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
>>>> index d45125d..3776990 100644
>>>> --- a/datapath/linux/compat/vxlan.c
>>>> +++ b/datapath/linux/compat/vxlan.c
>>>> @@ -850,6 +850,13 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
>>>>                 oip6 = ipv6_hdr(skb);
>>>>                 saddr.sin6.sin6_addr = oip6->saddr;
>>>>                 saddr.sa.sa_family = AF_INET6;
>>>> +#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
>>>> +               if (!udp_hdr(skb)->check &&
>>>> +                   !(vs->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) {
>>>> +                       udp6_csum_zero_error(skb);
>>>> +                       goto drop;
>>>> +               }
>>>> +#endif
>>>>  #endif
>>>
>>> Do we need a version of this for Geneve as well?
>>
>> OK - I see that it actually came in later in the big resync patch.
>
> Yes, Geneve does not support ipv6 tunnels at this point.

In that case (with the minor adjustment noted above):
Acked-by: Jesse Gross <jesse@kernel.org>
diff mbox

Patch

diff --git a/acinclude.m4 b/acinclude.m4
index 4bb65c7..003ba72 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -619,6 +619,8 @@  AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
   OVS_GREP_IFELSE([$KSRC/include/uapi/linux/netdevice.h], [NET_NAME_UNKNOWN],
                   [OVS_DEFINE([HAVE_NET_NAME_UNKNOWN])])
 
+  OVS_GREP_IFELSE([$KSRC/include/net/sock.h], [sk_no_check_tx])
+  OVS_GREP_IFELSE([$KSRC/include/linux/udp.h], [no_check6_tx])
   OVS_GREP_IFELSE([$KSRC/include/linux/utsrelease.h], [el6],
                   [OVS_DEFINE([HAVE_RHEL6_PER_CPU])])
 
diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk
index ae7c753..ef08083 100644
--- a/datapath/linux/Modules.mk
+++ b/datapath/linux/Modules.mk
@@ -67,6 +67,7 @@  openvswitch_headers += \
 	linux/compat/include/linux/stddef.h \
 	linux/compat/include/linux/types.h \
 	linux/compat/include/linux/u64_stats_sync.h \
+	linux/compat/include/linux/udp.h \
 	linux/compat/include/linux/workqueue.h \
 	linux/compat/include/net/checksum.h \
 	linux/compat/include/net/dst.h \
diff --git a/datapath/linux/compat/include/linux/udp.h b/datapath/linux/compat/include/linux/udp.h
new file mode 100644
index 0000000..31ae022
--- /dev/null
+++ b/datapath/linux/compat/include/linux/udp.h
@@ -0,0 +1,33 @@ 
+#ifndef __LINUX_UDP_WRAPPER_H
+#define __LINUX_UDP_WRAPPER_H  1
+
+#include_next <linux/udp.h>
+#include <linux/ipv6.h>
+
+#ifndef HAVE_NO_CHECK6_TX
+static inline void udp_set_no_check6_tx(struct sock *sk, bool val)
+{
+#ifdef HAVE_SK_NO_CHECK_TX
+	sk->sk_no_check_tx = val;
+#else
+	/* since netwroking stack is not checking for zero UDP checksum
+	 * check it in OVS module. */
+	#define OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
+#endif
+}
+
+static inline void udp_set_no_check6_rx(struct sock *sk, bool val)
+{
+#ifdef HAVE_SK_NO_CHECK_TX
+	sk->sk_no_check_rx = val;
+#endif
+}
+#endif
+
+#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
+#define udp6_csum_zero_error rpl_udp6_csum_zero_error
+
+void rpl_udp6_csum_zero_error(struct sk_buff *skb);
+#endif
+
+#endif
diff --git a/datapath/linux/compat/include/net/udp.h b/datapath/linux/compat/include/net/udp.h
index 41254aa..fa49fa5 100644
--- a/datapath/linux/compat/include/net/udp.h
+++ b/datapath/linux/compat/include/net/udp.h
@@ -59,5 +59,4 @@  static inline __sum16 udp_v4_check(int len, __be32 saddr,
 void rpl_udp_set_csum(bool nocheck, struct sk_buff *skb,
 		      __be32 saddr, __be32 daddr, int len);
 #endif
-
 #endif
diff --git a/datapath/linux/compat/include/net/udp_tunnel.h b/datapath/linux/compat/include/net/udp_tunnel.h
index 605fe63..d953e09 100644
--- a/datapath/linux/compat/include/net/udp_tunnel.h
+++ b/datapath/linux/compat/include/net/udp_tunnel.h
@@ -41,9 +41,35 @@  struct udp_port_cfg {
 				ipv6_v6only:1;
 };
 
+#define udp_sock_create4 rpl_udp_sock_create4
+int rpl_udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
+		     struct socket **sockp);
+
+#define udp_sock_create6 rpl_udp_sock_create6
+#if IS_ENABLED(CONFIG_IPV6)
+int rpl_udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
+		struct socket **sockp);
+#else
+static inline int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
+				   struct socket **sockp)
+{
+	return -EPFNOSUPPORT;
+}
+#endif
+
 #define udp_sock_create rpl_udp_sock_create
-int rpl_udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
-		        struct socket **sockp);
+static inline int udp_sock_create(struct net *net,
+                                  struct udp_port_cfg *cfg,
+                                  struct socket **sockp)
+{
+        if (cfg->family == AF_INET)
+                return udp_sock_create4(net, cfg, sockp);
+
+        if (cfg->family == AF_INET6)
+                return udp_sock_create6(net, cfg, sockp);
+
+        return -EPFNOSUPPORT;
+}
 
 typedef int (*udp_tunnel_encap_rcv_t)(struct sock *sk, struct sk_buff *skb);
 typedef void (*udp_tunnel_encap_destroy_t)(struct sock *sk);
diff --git a/datapath/linux/compat/udp.c b/datapath/linux/compat/udp.c
index 487d317..f0362b6 100644
--- a/datapath/linux/compat/udp.c
+++ b/datapath/linux/compat/udp.c
@@ -42,3 +42,15 @@  void rpl_udp_set_csum(bool nocheck, struct sk_buff *skb,
 EXPORT_SYMBOL_GPL(rpl_udp_set_csum);
 
 #endif /* Linux version < 3.16 */
+
+#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
+void rpl_udp6_csum_zero_error(struct sk_buff *skb)
+{
+	/* RFC 2460 section 8.1 says that we SHOULD log
+	 * this error. Well, it is reasonable.
+	 */
+	net_dbg_ratelimited("IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n",
+			&ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source),
+			&ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest));
+}
+#endif
diff --git a/datapath/linux/compat/udp_tunnel.c b/datapath/linux/compat/udp_tunnel.c
index b4d345b..daa3fa1 100644
--- a/datapath/linux/compat/udp_tunnel.c
+++ b/datapath/linux/compat/udp_tunnel.c
@@ -16,74 +16,95 @@ 
 #include <net/ip6_tunnel.h>
 
 
-int rpl_udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
-		        struct socket **sockp)
+int rpl_udp_sock_create4(struct net *net, struct udp_port_cfg *cfg,
+			 struct socket **sockp)
 {
 	int err;
 	struct socket *sock = NULL;
+	struct sockaddr_in udp_addr;
 
-#if IS_ENABLED(CONFIG_IPV6)
-	if (cfg->family == AF_INET6) {
-		struct sockaddr_in6 udp6_addr;
+	err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 0, &sock);
+	if (err < 0)
+		goto error;
 
-		err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 0, &sock);
-		if (err < 0)
-			goto error;
+	udp_addr.sin_family = AF_INET;
+	udp_addr.sin_addr = cfg->local_ip;
+	udp_addr.sin_port = cfg->local_udp_port;
+	err = kernel_bind(sock, (struct sockaddr *)&udp_addr,
+			sizeof(udp_addr));
+	if (err < 0)
+		goto error;
 
-		udp6_addr.sin6_family = AF_INET6;
-		memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6,
-		       sizeof(udp6_addr.sin6_addr));
-		udp6_addr.sin6_port = cfg->local_udp_port;
-		err = kernel_bind(sock, (struct sockaddr *)&udp6_addr,
-				  sizeof(udp6_addr));
-		if (err < 0)
-			goto error;
-
-		if (cfg->peer_udp_port) {
-			udp6_addr.sin6_family = AF_INET6;
-			memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6,
-			       sizeof(udp6_addr.sin6_addr));
-			udp6_addr.sin6_port = cfg->peer_udp_port;
-			err = kernel_connect(sock,
-					     (struct sockaddr *)&udp6_addr,
-					     sizeof(udp6_addr), 0);
-		}
+	if (cfg->peer_udp_port) {
+		udp_addr.sin_family = AF_INET;
+		udp_addr.sin_addr = cfg->peer_ip;
+		udp_addr.sin_port = cfg->peer_udp_port;
+		err = kernel_connect(sock, (struct sockaddr *)&udp_addr,
+				sizeof(udp_addr), 0);
 		if (err < 0)
 			goto error;
-	} else
+	}
+#ifdef HAVE_SK_NO_CHECK_TX
+	sock->sk->sk_no_check_tx = !cfg->use_udp_checksums;
 #endif
-	if (cfg->family == AF_INET) {
-		struct sockaddr_in udp_addr;
+	*sockp = sock;
+	return 0;
 
-		err = sock_create_kern(net, AF_INET, SOCK_DGRAM, 0, &sock);
-		if (err < 0)
-			goto error;
+error:
+	if (sock) {
+		kernel_sock_shutdown(sock, SHUT_RDWR);
+		sock_release(sock);
+	}
+	*sockp = NULL;
+	return err;
+}
+EXPORT_SYMBOL(rpl_udp_sock_create4);
 
-		udp_addr.sin_family = AF_INET;
-		udp_addr.sin_addr = cfg->local_ip;
-		udp_addr.sin_port = cfg->local_udp_port;
-		err = kernel_bind(sock, (struct sockaddr *)&udp_addr,
-				  sizeof(udp_addr));
+int rpl_udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
+			 struct socket **sockp)
+{
+	struct sockaddr_in6 udp6_addr;
+	int err;
+	struct socket *sock = NULL;
+
+	err = sock_create_kern(net, AF_INET6, SOCK_DGRAM, 0, &sock);
+	if (err < 0)
+		goto error;
+
+	if (cfg->ipv6_v6only) {
+		int val = 1;
+
+		err = kernel_setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+				(char *) &val, sizeof(val));
 		if (err < 0)
 			goto error;
+	}
 
-		if (cfg->peer_udp_port) {
-			udp_addr.sin_family = AF_INET;
-			udp_addr.sin_addr = cfg->peer_ip;
-			udp_addr.sin_port = cfg->peer_udp_port;
-			err = kernel_connect(sock,
-					     (struct sockaddr *)&udp_addr,
-					     sizeof(udp_addr), 0);
-			if (err < 0)
-				goto error;
-		}
-	} else {
-		return -EPFNOSUPPORT;
+	udp6_addr.sin6_family = AF_INET6;
+	memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6,
+			sizeof(udp6_addr.sin6_addr));
+	udp6_addr.sin6_port = cfg->local_udp_port;
+	err = kernel_bind(sock, (struct sockaddr *)&udp6_addr,
+			sizeof(udp6_addr));
+	if (err < 0)
+		goto error;
+
+	if (cfg->peer_udp_port) {
+		udp6_addr.sin6_family = AF_INET6;
+		memcpy(&udp6_addr.sin6_addr, &cfg->peer_ip6,
+				sizeof(udp6_addr.sin6_addr));
+		udp6_addr.sin6_port = cfg->peer_udp_port;
+		err = kernel_connect(sock,
+				(struct sockaddr *)&udp6_addr,
+				sizeof(udp6_addr), 0);
 	}
+	if (err < 0)
+		goto error;
 
+	udp_set_no_check6_tx(sock->sk, !cfg->use_udp6_tx_checksums);
+	udp_set_no_check6_rx(sock->sk, !cfg->use_udp6_rx_checksums);
 
 	*sockp = sock;
-
 	return 0;
 
 error:
@@ -94,7 +115,7 @@  error:
 	*sockp = NULL;
 	return err;
 }
-EXPORT_SYMBOL_GPL(rpl_udp_sock_create);
+EXPORT_SYMBOL_GPL(rpl_udp_sock_create6);
 
 void rpl_setup_udp_tunnel_sock(struct net *net, struct socket *sock,
 			       struct udp_tunnel_sock_cfg *cfg)
diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
index d45125d..3776990 100644
--- a/datapath/linux/compat/vxlan.c
+++ b/datapath/linux/compat/vxlan.c
@@ -850,6 +850,13 @@  static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
 		oip6 = ipv6_hdr(skb);
 		saddr.sin6.sin6_addr = oip6->saddr;
 		saddr.sa.sa_family = AF_INET6;
+#ifdef OVS_CHECK_UDP_TUNNEL_ZERO_CSUM
+		if (!udp_hdr(skb)->check &&
+		    !(vs->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) {
+			udp6_csum_zero_error(skb);
+			goto drop;
+		}
+#endif
 #endif
 	}