Whamcloud - gitweb
LU-10391 socklnd: use interface index to track local addr
[fs/lustre-release.git] / lnet / lnet / lib-socket.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2015, 2017, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  */
32 #define DEBUG_SUBSYSTEM S_LNET
33
34 #include <linux/if.h>
35 #include <linux/in.h>
36 #include <linux/net.h>
37 #include <linux/file.h>
38 #include <linux/pagemap.h>
39 /* For sys_open & sys_close */
40 #include <linux/syscalls.h>
41 #include <net/sock.h>
42 #include <linux/inetdevice.h>
43
44 #include <libcfs/libcfs.h>
45 #include <lnet/lib-lnet.h>
46
47 /*
48  * kernel 5.1: commit 7f1bc6e95d7840d4305595b3e4025cddda88cee5
49  * Y2038 64-bit time.
50  *  SO_TIMESTAMP, SO_TIMESTAMPNS and SO_TIMESTAMPING options, the
51  *  way they are currently defined, are not y2038 safe.
52  *  Subsequent patches in the series add new y2038 safe versions
53  *  of these options which provide 64 bit timestamps on all
54  *  architectures uniformly.
55  *  Hence, rename existing options with OLD tag suffixes.
56  *
57  * NOTE: When updating to timespec64 change change these to '_NEW'.
58  *
59  */
60 #ifndef SO_SNDTIMEO
61 #define SO_SNDTIMEO SO_SNDTIMEO_OLD
62 #endif
63
64 #ifndef SO_RCVTIMEO
65 #define SO_RCVTIMEO SO_RCVTIMEO_OLD
66 #endif
67
68 int
69 lnet_sock_write(struct socket *sock, void *buffer, int nob, int timeout)
70 {
71         int             rc;
72         long            jiffies_left = cfs_time_seconds(timeout);
73         unsigned long   then;
74         struct timeval  tv;
75
76         LASSERT(nob > 0);
77         /* Caller may pass a zero timeout if she thinks the socket buffer is
78          * empty enough to take the whole message immediately */
79
80         for (;;) {
81                 struct kvec  iov = {
82                         .iov_base = buffer,
83                         .iov_len  = nob
84                 };
85                 struct msghdr msg = {
86                         .msg_flags      = (timeout == 0) ? MSG_DONTWAIT : 0
87                 };
88
89                 if (timeout != 0) {
90                         /* Set send timeout to remaining time */
91                         jiffies_to_timeval(jiffies_left, &tv);
92                         rc = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
93                                                (char *)&tv, sizeof(tv));
94                         if (rc != 0) {
95                                 CERROR("Can't set socket send timeout "
96                                        "%ld.%06d: %d\n",
97                                        (long)tv.tv_sec, (int)tv.tv_usec, rc);
98                                 return rc;
99                         }
100                 }
101
102                 then = jiffies;
103                 rc = kernel_sendmsg(sock, &msg, &iov, 1, nob);
104                 jiffies_left -= jiffies - then;
105
106                 if (rc == nob)
107                         return 0;
108
109                 if (rc < 0)
110                         return rc;
111
112                 if (rc == 0) {
113                         CERROR("Unexpected zero rc\n");
114                         return -ECONNABORTED;
115                 }
116
117                 if (jiffies_left <= 0)
118                         return -EAGAIN;
119
120                 buffer = ((char *)buffer) + rc;
121                 nob -= rc;
122         }
123         return 0;
124 }
125 EXPORT_SYMBOL(lnet_sock_write);
126
127 int
128 lnet_sock_read(struct socket *sock, void *buffer, int nob, int timeout)
129 {
130         int             rc;
131         long            jiffies_left = cfs_time_seconds(timeout);
132         unsigned long   then;
133         struct timeval  tv;
134
135         LASSERT(nob > 0);
136         LASSERT(jiffies_left > 0);
137
138         for (;;) {
139                 struct kvec  iov = {
140                         .iov_base = buffer,
141                         .iov_len  = nob
142                 };
143                 struct msghdr msg = {
144                         .msg_flags      = 0
145                 };
146
147                 /* Set receive timeout to remaining time */
148                 jiffies_to_timeval(jiffies_left, &tv);
149                 rc = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
150                                        (char *)&tv, sizeof(tv));
151                 if (rc != 0) {
152                         CERROR("Can't set socket recv timeout %ld.%06d: %d\n",
153                                (long)tv.tv_sec, (int)tv.tv_usec, rc);
154                         return rc;
155                 }
156
157                 then = jiffies;
158                 rc = kernel_recvmsg(sock, &msg, &iov, 1, nob, 0);
159                 jiffies_left -= jiffies - then;
160
161                 if (rc < 0)
162                         return rc;
163
164                 if (rc == 0)
165                         return -ECONNRESET;
166
167                 buffer = ((char *)buffer) + rc;
168                 nob -= rc;
169
170                 if (nob == 0)
171                         return 0;
172
173                 if (jiffies_left <= 0)
174                         return -ETIMEDOUT;
175         }
176 }
177 EXPORT_SYMBOL(lnet_sock_read);
178
179 int choose_ipv4_src(__u32 *ret, int interface, __u32 dst_ipaddr, struct net *ns)
180 {
181         struct net_device *dev;
182         struct in_device *in_dev;
183         int err;
184         DECLARE_CONST_IN_IFADDR(ifa);
185
186         rcu_read_lock();
187         dev = dev_get_by_index_rcu(ns, interface);
188         err = -EINVAL;
189         if (!dev || !(dev->flags & IFF_UP))
190                 goto out;
191         in_dev = __in_dev_get_rcu(dev);
192         if (!in_dev)
193                 goto out;
194         err = -ENOENT;
195         in_dev_for_each_ifa_rcu(ifa, in_dev) {
196                 if (*ret == 0 ||
197                     ((dst_ipaddr ^ ntohl(ifa->ifa_local))
198                      & ntohl(ifa->ifa_mask)) == 0) {
199                         /* This address at least as good as what we
200                          * already have
201                          */
202                         *ret = ntohl(ifa->ifa_local);
203                         err = 0;
204                 }
205         }
206         endfor_ifa(in_dev);
207 out:
208         rcu_read_unlock();
209         return err;
210 }
211 EXPORT_SYMBOL(choose_ipv4_src);
212
213 static struct socket *
214 lnet_sock_create(int interface, struct sockaddr *remaddr,
215                  int local_port, struct net *ns)
216 {
217         struct socket      *sock;
218         int                 rc;
219         int                 option;
220
221 #ifdef HAVE_SOCK_CREATE_KERN_USE_NET
222         rc = sock_create_kern(ns, PF_INET, SOCK_STREAM, 0, &sock);
223 #else
224         rc = sock_create_kern(PF_INET, SOCK_STREAM, 0, &sock);
225 #endif
226         if (rc) {
227                 CERROR("Can't create socket: %d\n", rc);
228                 return ERR_PTR(rc);
229         }
230
231         option = 1;
232         rc = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
233                                (char *)&option, sizeof(option));
234         if (rc) {
235                 CERROR("Can't set SO_REUSEADDR for socket: %d\n", rc);
236                 goto failed;
237         }
238
239         if (interface >= 0 || local_port != 0) {
240                 struct sockaddr_in locaddr = {};
241
242                 locaddr.sin_family = AF_INET;
243                 locaddr.sin_addr.s_addr = INADDR_ANY;
244                 if (interface >= 0) {
245                         struct sockaddr_in *sin = (void *)remaddr;
246                         __u32 ip;
247
248                         rc = choose_ipv4_src(&ip,
249                                              interface,
250                                              ntohl(sin->sin_addr.s_addr),
251                                              ns);
252                         if (rc)
253                                 goto failed;
254                         locaddr.sin_addr.s_addr = htonl(ip);
255                 }
256
257                 locaddr.sin_port = htons(local_port);
258
259                 rc = kernel_bind(sock, (struct sockaddr *)&locaddr,
260                                  sizeof(locaddr));
261                 if (rc == -EADDRINUSE) {
262                         CDEBUG(D_NET, "Port %d already in use\n", local_port);
263                         goto failed;
264                 }
265                 if (rc != 0) {
266                         CERROR("Error trying to bind to port %d: %d\n",
267                                local_port, rc);
268                         goto failed;
269                 }
270         }
271         return sock;
272
273 failed:
274         sock_release(sock);
275         return ERR_PTR(rc);
276 }
277
278 int
279 lnet_sock_setbuf(struct socket *sock, int txbufsize, int rxbufsize)
280 {
281         int                 option;
282         int                 rc;
283
284         if (txbufsize != 0) {
285                 option = txbufsize;
286                 rc = kernel_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
287                                        (char *)&option, sizeof(option));
288                 if (rc != 0) {
289                         CERROR("Can't set send buffer %d: %d\n",
290                                 option, rc);
291                         return rc;
292                 }
293         }
294
295         if (rxbufsize != 0) {
296                 option = rxbufsize;
297                 rc = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
298                                        (char *)&option, sizeof(option));
299                 if (rc != 0) {
300                         CERROR("Can't set receive buffer %d: %d\n",
301                                 option, rc);
302                         return rc;
303                 }
304         }
305         return 0;
306 }
307 EXPORT_SYMBOL(lnet_sock_setbuf);
308
309 int
310 lnet_sock_getaddr(struct socket *sock, bool remote, __u32 *ip, int *port)
311 {
312         struct sockaddr_in sin;
313         int rc;
314 #ifndef HAVE_KERN_SOCK_GETNAME_2ARGS
315         int len = sizeof(sin);
316 #endif
317
318         if (remote)
319                 rc = lnet_kernel_getpeername(sock,
320                                              (struct sockaddr *)&sin, &len);
321         else
322                 rc = lnet_kernel_getsockname(sock,
323                                              (struct sockaddr *)&sin, &len);
324         if (rc < 0) {
325                 CERROR("Error %d getting sock %s IP/port\n",
326                         rc, remote ? "peer" : "local");
327                 return rc;
328         }
329
330         if (ip != NULL)
331                 *ip = ntohl(sin.sin_addr.s_addr);
332
333         if (port != NULL)
334                 *port = ntohs(sin.sin_port);
335
336         return 0;
337 }
338 EXPORT_SYMBOL(lnet_sock_getaddr);
339
340 int
341 lnet_sock_getbuf(struct socket *sock, int *txbufsize, int *rxbufsize)
342 {
343         if (txbufsize != NULL)
344                 *txbufsize = sock->sk->sk_sndbuf;
345
346         if (rxbufsize != NULL)
347                 *rxbufsize = sock->sk->sk_rcvbuf;
348
349         return 0;
350 }
351 EXPORT_SYMBOL(lnet_sock_getbuf);
352
353 struct socket *
354 lnet_sock_listen(int local_port, int backlog, struct net *ns)
355 {
356         struct socket *sock;
357         int rc;
358
359         sock = lnet_sock_create(-1, NULL, local_port, ns);
360         if (IS_ERR(sock)) {
361                 rc = PTR_ERR(sock);
362                 if (rc == -EADDRINUSE)
363                         CERROR("Can't create socket: port %d already in use\n",
364                                local_port);
365                 return ERR_PTR(rc);
366         }
367
368         rc = kernel_listen(sock, backlog);
369         if (rc == 0)
370                 return sock;
371
372         CERROR("Can't set listen backlog %d: %d\n", backlog, rc);
373         sock_release(sock);
374         return ERR_PTR(rc);
375 }
376
377 struct socket *
378 lnet_sock_connect(int interface, int local_port,
379                   __u32 peer_ip, int peer_port,
380                   struct net *ns)
381 {
382         struct socket *sock;
383         struct sockaddr_in srvaddr;
384         int rc;
385
386         memset(&srvaddr, 0, sizeof(srvaddr));
387         srvaddr.sin_family = AF_INET;
388         srvaddr.sin_port = htons(peer_port);
389         srvaddr.sin_addr.s_addr = htonl(peer_ip);
390
391         sock = lnet_sock_create(interface, (struct sockaddr *)&srvaddr,
392                                 local_port, ns);
393         if (IS_ERR(sock))
394                 return sock;
395
396         rc = kernel_connect(sock, (struct sockaddr *)&srvaddr,
397                             sizeof(srvaddr), 0);
398         if (rc == 0)
399                 return sock;
400
401         /* EADDRNOTAVAIL probably means we're already connected to the same
402          * peer/port on the same local port on a differently typed
403          * connection.  Let our caller retry with a different local
404          * port... */
405
406         CDEBUG_LIMIT(rc == -EADDRNOTAVAIL ? D_NET : D_NETERROR,
407                      "Error %d connecting %d -> %pI4h/%d\n", rc,
408                      local_port, &peer_ip, peer_port);
409
410         sock_release(sock);
411         return ERR_PTR(rc);
412 }