Update udp-socket-create to create ipv6 socket currectly.

Signed-off-by: Pravin B Shelar <pshe...@ovn.org>
---
 acinclude.m4                                   |   1 +
 datapath/linux/compat/include/net/udp.h        |   9 ++
 datapath/linux/compat/include/net/udp_tunnel.h |  30 +++++-
 datapath/linux/compat/udp_tunnel.c             | 123 +++++++++++++++----------
 4 files changed, 110 insertions(+), 53 deletions(-)

diff --git a/acinclude.m4 b/acinclude.m4
index 9404024..a8ea2b7 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -572,6 +572,7 @@ 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/utsrelease.h], [el6],
                   [OVS_DEFINE([HAVE_RHEL6_PER_CPU])])
 
diff --git a/datapath/linux/compat/include/net/udp.h 
b/datapath/linux/compat/include/net/udp.h
index 41254aa..fc46d89 100644
--- a/datapath/linux/compat/include/net/udp.h
+++ b/datapath/linux/compat/include/net/udp.h
@@ -60,4 +60,13 @@ void rpl_udp_set_csum(bool nocheck, struct sk_buff *skb,
                      __be32 saddr, __be32 daddr, int len);
 #endif
 
+#ifndef HAVE_SK_NO_CHECK_TX
+static inline void udp_set_no_check6_tx(struct sock *sk, bool val)
+{
+}
+
+static inline void udp_set_no_check6_rx(struct sock *sk, bool val)
+{
+}
+#endif
 #endif
diff --git a/datapath/linux/compat/include/net/udp_tunnel.h 
b/datapath/linux/compat/include/net/udp_tunnel.h
index 17f829d..0f38c26 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 af606a9..4e2c64d 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)
-- 
2.5.5

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to