diff mbox

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

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

Commit Message

Pravin Shelar July 2, 2016, 12:59 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      |  22 +++++
 datapath/linux/compat/include/net/udp.h        |   1 -
 datapath/linux/compat/include/net/udp_tunnel.h |  30 +++++-
 datapath/linux/compat/udp_tunnel.c             | 123 +++++++++++++++----------
 6 files changed, 125 insertions(+), 54 deletions(-)
 create mode 100644 datapath/linux/compat/include/linux/udp.h

Comments

Jesse Gross July 5, 2016, 11:54 p.m. UTC | #1
On Fri, Jul 1, 2016 at 5:59 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..65cb77c
> --- /dev/null
> +++ b/datapath/linux/compat/include/linux/udp.h
[...]
> +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 don't know that this is sufficient to have consistent behavior
across old kernels. I think the only real way to solve the problem is
to have a check in the receive path for the UDP checksum not zero.
Pravin Shelar July 6, 2016, 9:48 p.m. UTC | #2
On Tue, Jul 5, 2016 at 4:54 PM, Jesse Gross <jesse@kernel.org> wrote:
> On Fri, Jul 1, 2016 at 5:59 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..65cb77c
>> --- /dev/null
>> +++ b/datapath/linux/compat/include/linux/udp.h
> [...]
>> +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 don't know that this is sufficient to have consistent behavior
> across old kernels. I think the only real way to solve the problem is
> to have a check in the receive path for the UDP checksum not zero.

OK, I added check in geneva and vxlan recv handler.
diff mbox

Patch

diff --git a/acinclude.m4 b/acinclude.m4
index 4d4341c..5d3e8b5 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -620,6 +620,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..65cb77c
--- /dev/null
+++ b/datapath/linux/compat/include/linux/udp.h
@@ -0,0 +1,22 @@ 
+#ifndef __LINUX_UDP_WRAPPER_H
+#define __LINUX_UDP_WRAPPER_H  1
+
+#include_next <linux/udp.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;
+#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
+
+#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 3132a53..7befd2d 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 0;
+}
+#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_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)