Whamcloud - gitweb
LU-15150 tests: sanity-lnet removes testsuite log on failure
[fs/lustre-release.git] / lnet / lnet / lib-socket.c
index 9fa349f..90cdc3e 100644 (file)
@@ -27,7 +27,6 @@
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
  */
 #define DEBUG_SUBSYSTEM S_LNET
 
@@ -44,6 +43,7 @@
 #include <linux/inetdevice.h>
 
 #include <libcfs/linux/linux-time.h>
+#include <libcfs/linux/linux-net.h>
 #include <libcfs/libcfs.h>
 #include <lnet/lib-lnet.h>
 
@@ -188,37 +188,36 @@ lnet_sock_create(int interface, struct sockaddr *remaddr,
 {
        struct socket *sock;
        int rc;
-       int option;
        int family;
 
        family = AF_INET6;
        if (remaddr)
                family = remaddr->sa_family;
+retry:
 #ifdef HAVE_SOCK_CREATE_KERN_USE_NET
        rc = sock_create_kern(ns, family, SOCK_STREAM, 0, &sock);
 #else
        rc = sock_create_kern(family, SOCK_STREAM, 0, &sock);
 #endif
+       if (rc == -EAFNOSUPPORT && family == AF_INET6 && !remaddr) {
+               family = AF_INET;
+               goto retry;
+       }
+
        if (rc) {
                CERROR("Can't create socket: %d\n", rc);
                return ERR_PTR(rc);
        }
 
-       option = 1;
-       rc = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
-                              (char *)&option, sizeof(option));
-       if (rc) {
-               CERROR("Can't set SO_REUSEADDR for socket: %d\n", rc);
-               goto failed;
-       }
+       sock->sk->sk_reuseport = 1;
 
        if (interface >= 0 || local_port != 0) {
                struct sockaddr_storage locaddr = {};
-               struct sockaddr_in *sin = (void *)&locaddr;
-               struct sockaddr_in6 *sin6 = (void *)&locaddr;
 
                switch (family) {
-               case AF_INET:
+               case AF_INET: {
+                       struct sockaddr_in *sin = (void *)&locaddr;
+
                        sin->sin_family = AF_INET;
                        sin->sin_addr.s_addr = INADDR_ANY;
                        if (interface >= 0 && remaddr) {
@@ -235,9 +234,54 @@ lnet_sock_create(int interface, struct sockaddr *remaddr,
                        }
                        sin->sin_port = htons(local_port);
                        break;
-               case AF_INET6:
+               }
+#if IS_ENABLED(CONFIG_IPV6)
+               case AF_INET6: {
+                       struct sockaddr_in6 *sin6 = (void *)&locaddr;
+                       int val = 0;
+
                        sin6->sin6_family = AF_INET6;
                        sin6->sin6_addr = in6addr_any;
+
+                       /* Make sure we get both IPv4 and IPv6 connections.
+                        * This is the default, but it can be overridden so we
+                        * force it back.
+                        */
+#ifdef HAVE_KERNEL_SETSOCKOPT
+                       kernel_setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+                                         (char *) &val, sizeof(val));
+#elif defined(_LINUX_SOCKPTR_H)
+                       /* sockptr_t was introduced around
+                        * v5.8-rc4-1952-ga7b75c5a8c41 and allows a
+                        * kernel address to be passed to ->setsockopt
+                        */
+                       if (ipv6_only_sock(sock->sk)) {
+                               sockptr_t optval = KERNEL_SOCKPTR(&val);
+
+                               sock->ops->setsockopt(sock,
+                                                     IPPROTO_IPV6, IPV6_V6ONLY,
+                                                     optval, sizeof(val));
+                       }
+#else
+                       /* From v5.7-rc6-2614-g5a892ff2facb when
+                        * kernel_setsockopt() was removed until
+                        * sockptr_t (above) there is no clean way to
+                        * pass kernel address to setsockopt.  We could
+                        * use get_fs()/set_fs(), but in this particular
+                        * situation there is an easier way.  It depends
+                        * on the fact that at least for these few
+                        * kernels a NULL address to ipv6_setsockopt()
+                        * is treated like the address of a zero.
+                        */
+                       if (ipv6_only_sock(sock->sk) && !val) {
+                               void *optval = NULL;
+
+                               sock->ops->setsockopt(sock,
+                                                     IPPROTO_IPV6, IPV6_V6ONLY,
+                                                     optval, sizeof(val));
+                       }
+#endif /* HAVE_KERNEL_SETSOCKOPT */
+
                        if (interface >= 0 && remaddr) {
                                struct sockaddr_in6 *rem = (void *)remaddr;
 
@@ -250,6 +294,8 @@ lnet_sock_create(int interface, struct sockaddr *remaddr,
                        sin6->sin6_port = htons(local_port);
                        break;
                }
+#endif /* IS_ENABLED(CONFIG_IPV6) */
+               }
                rc = kernel_bind(sock, (struct sockaddr *)&locaddr,
                                 sizeof(locaddr));
                if (rc == -EADDRINUSE) {
@@ -269,34 +315,21 @@ failed:
        return ERR_PTR(rc);
 }
 
-int
+void
 lnet_sock_setbuf(struct socket *sock, int txbufsize, int rxbufsize)
 {
-       int                 option;
-       int                 rc;
+       struct sock *sk = sock->sk;
 
        if (txbufsize != 0) {
-               option = txbufsize;
-               rc = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
-                                      (char *)&option, sizeof(option));
-               if (rc != 0) {
-                       CERROR("Can't set send buffer %d: %d\n",
-                               option, rc);
-                       return rc;
-               }
+               sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
+               sk->sk_sndbuf = txbufsize;
+               sk->sk_write_space(sk);
        }
 
        if (rxbufsize != 0) {
-               option = rxbufsize;
-               rc = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
-                                      (char *)&option, sizeof(option));
-               if (rc != 0) {
-                       CERROR("Can't set receive buffer %d: %d\n",
-                               option, rc);
-                       return rc;
-               }
+               sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
+               sk->sk_sndbuf = rxbufsize;
        }
-       return 0;
 }
 EXPORT_SYMBOL(lnet_sock_setbuf);
 
@@ -337,16 +370,13 @@ lnet_sock_getaddr(struct socket *sock, bool remote,
 }
 EXPORT_SYMBOL(lnet_sock_getaddr);
 
-int
-lnet_sock_getbuf(struct socket *sock, int *txbufsize, int *rxbufsize)
+void lnet_sock_getbuf(struct socket *sock, int *txbufsize, int *rxbufsize)
 {
        if (txbufsize != NULL)
                *txbufsize = sock->sk->sk_sndbuf;
 
        if (rxbufsize != NULL)
                *rxbufsize = sock->sk->sk_rcvbuf;
-
-       return 0;
 }
 EXPORT_SYMBOL(lnet_sock_getbuf);
 
@@ -354,7 +384,6 @@ struct socket *
 lnet_sock_listen(int local_port, int backlog, struct net *ns)
 {
        struct socket *sock;
-       int val = 0;
        int rc;
 
        sock = lnet_sock_create(-1, NULL, local_port, ns);
@@ -366,13 +395,6 @@ lnet_sock_listen(int local_port, int backlog, struct net *ns)
                return ERR_PTR(rc);
        }
 
-       /* Make sure we get both IPv4 and IPv6 connections.
-        * This is the default, but it can be overridden so
-        * we force it back.
-        */
-       kernel_setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
-                         (char *) &val, sizeof(val));
-
        rc = kernel_listen(sock, backlog);
        if (rc == 0)
                return sock;