Whamcloud - gitweb
Landing b_hd_newconfig on HEAD
[fs/lustre-release.git] / lnet / libcfs / linux / linux-tcpip.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2005 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 #define DEBUG_SUBSYSTEM S_LNET
22
23 #include <libcfs/kp30.h>
24 #include <libcfs/libcfs.h>
25
26 #include <linux/if.h>
27 #include <linux/in.h>
28 #include <linux/file.h>
29 /* For sys_open & sys_close */
30 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
31 #include <linux/syscalls.h>
32 #else
33 #include <linux/fs.h>
34 #endif
35
36 int
37 libcfs_sock_ioctl(int cmd, unsigned long arg)
38 {
39         mm_segment_t   oldmm = get_fs();
40         struct socket  *sock;
41         int             fd;
42         int             rc;
43         struct file     *sock_filp;
44
45         rc = sock_create (PF_INET, SOCK_STREAM, 0, &sock);
46         if (rc != 0) {
47                 CERROR ("Can't create socket: %d\n", rc);
48                 return rc;
49         }
50
51         fd = sock_map_fd(sock);
52         if (fd < 0) {
53                 rc = fd;
54                 sock_release(sock);
55                 goto out;
56         }
57
58         sock_filp = fget(fd);
59         if (!sock_filp) {
60                 rc = -ENOMEM;
61                 goto out_fd;
62         }
63
64         set_fs(KERNEL_DS);
65 #ifdef HAVE_UNLOCKED_IOCTL
66         if (sock_filp->f_op->unlocked_ioctl)
67                 rc = sock_filp->f_op->unlocked_ioctl(sock_filp, cmd, arg);
68         else
69 #endif
70              {
71                 lock_kernel();
72                 rc =sock_filp->f_op->ioctl(sock_filp->f_dentry->d_inode,
73                                            sock_filp, cmd, arg);
74                 unlock_kernel();
75              }
76         set_fs(oldmm);
77
78         fput(sock_filp);
79
80  out_fd:
81         sys_close(fd);
82  out:
83         return rc;
84 }
85
86 int
87 libcfs_ipif_query (char *name, int *up, __u32 *ip, __u32 *mask)
88 {
89         struct ifreq   ifr;
90         int            nob;
91         int            rc;
92         __u32          val;
93
94         nob = strnlen(name, IFNAMSIZ);
95         if (nob == IFNAMSIZ) {
96                 CERROR("Interface name %s too long\n", name);
97                 rc = -EINVAL;
98                 goto out;
99         }
100
101         CLASSERT (sizeof(ifr.ifr_name) >= IFNAMSIZ);
102
103         strcpy(ifr.ifr_name, name);
104         rc = libcfs_sock_ioctl(SIOCGIFFLAGS, (unsigned long)&ifr);
105
106         if (rc != 0) {
107                 CERROR("Can't get flags for interface %s\n", name);
108                 goto out;
109         }
110
111         if ((ifr.ifr_flags & IFF_UP) == 0) {
112                 CDEBUG(D_NET, "Interface %s down\n", name);
113                 *up = 0;
114                 *ip = *mask = 0;
115                 goto out;
116         }
117
118         *up = 1;
119
120         strcpy(ifr.ifr_name, name);
121         ifr.ifr_addr.sa_family = AF_INET;
122         rc = libcfs_sock_ioctl(SIOCGIFADDR, (unsigned long)&ifr);
123
124         if (rc != 0) {
125                 CERROR("Can't get IP address for interface %s\n", name);
126                 goto out;
127         }
128
129         val = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
130         *ip = ntohl(val);
131
132         strcpy(ifr.ifr_name, name);
133         ifr.ifr_addr.sa_family = AF_INET;
134         rc = libcfs_sock_ioctl(SIOCGIFNETMASK, (unsigned long)&ifr);
135
136         if (rc != 0) {
137                 CERROR("Can't get netmask for interface %s\n", name);
138                 goto out;
139         }
140
141         val = ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr;
142         *mask = ntohl(val);
143
144  out:
145         return rc;
146 }
147
148 EXPORT_SYMBOL(libcfs_ipif_query);
149
150 int
151 libcfs_ipif_enumerate (char ***namesp)
152 {
153         /* Allocate and fill in 'names', returning # interfaces/error */
154         char           **names;
155         int             toobig;
156         int             nalloc;
157         int             nfound;
158         struct ifreq   *ifr;
159         struct ifconf   ifc;
160         int             rc;
161         int             nob;
162         int             i;
163
164
165         nalloc = 16;        /* first guess at max interfaces */
166         toobig = 0;
167         for (;;) {
168                 if (nalloc * sizeof(*ifr) > CFS_PAGE_SIZE) {
169                         toobig = 1;
170                         nalloc = CFS_PAGE_SIZE/sizeof(*ifr);
171                         CWARN("Too many interfaces: only enumerating first %d\n",
172                               nalloc);
173                 }
174
175                 LIBCFS_ALLOC(ifr, nalloc * sizeof(*ifr));
176                 if (ifr == NULL) {
177                         CERROR ("ENOMEM enumerating up to %d interfaces\n", nalloc);
178                         rc = -ENOMEM;
179                         goto out0;
180                 }
181
182                 ifc.ifc_buf = (char *)ifr;
183                 ifc.ifc_len = nalloc * sizeof(*ifr);
184
185                 rc = libcfs_sock_ioctl(SIOCGIFCONF, (unsigned long)&ifc);
186
187                 if (rc < 0) {
188                         CERROR ("Error %d enumerating interfaces\n", rc);
189                         goto out1;
190                 }
191
192                 LASSERT (rc == 0);
193
194                 nfound = ifc.ifc_len/sizeof(*ifr);
195                 LASSERT (nfound <= nalloc);
196
197                 if (nfound < nalloc || toobig)
198                         break;
199
200                 LIBCFS_FREE(ifr, nalloc * sizeof(*ifr));
201                 nalloc *= 2;
202         }
203
204         if (nfound == 0)
205                 goto out1;
206
207         LIBCFS_ALLOC(names, nfound * sizeof(*names));
208         if (names == NULL) {
209                 rc = -ENOMEM;
210                 goto out1;
211         }
212         /* NULL out all names[i] */
213         memset (names, 0, nfound * sizeof(*names));
214
215         for (i = 0; i < nfound; i++) {
216
217                 nob = strnlen (ifr[i].ifr_name, IFNAMSIZ);
218                 if (nob == IFNAMSIZ) {
219                         /* no space for terminating NULL */
220                         CERROR("interface name %.*s too long (%d max)\n",
221                                nob, ifr[i].ifr_name, IFNAMSIZ);
222                         rc = -ENAMETOOLONG;
223                         goto out2;
224                 }
225
226                 LIBCFS_ALLOC(names[i], IFNAMSIZ);
227                 if (names[i] == NULL) {
228                         rc = -ENOMEM;
229                         goto out2;
230                 }
231
232                 memcpy(names[i], ifr[i].ifr_name, nob);
233                 names[i][nob] = 0;
234         }
235
236         *namesp = names;
237         rc = nfound;
238
239  out2:
240         if (rc < 0)
241                 libcfs_ipif_free_enumeration(names, nfound);
242  out1:
243         LIBCFS_FREE(ifr, nalloc * sizeof(*ifr));
244  out0:
245         return rc;
246 }
247
248 EXPORT_SYMBOL(libcfs_ipif_enumerate);
249
250 void
251 libcfs_ipif_free_enumeration (char **names, int n)
252 {
253         int      i;
254
255         LASSERT (n > 0);
256
257         for (i = 0; i < n && names[i] != NULL; i++)
258                 LIBCFS_FREE(names[i], IFNAMSIZ);
259
260         LIBCFS_FREE(names, n * sizeof(*names));
261 }
262
263 EXPORT_SYMBOL(libcfs_ipif_free_enumeration);
264
265 int
266 libcfs_sock_write (struct socket *sock, void *buffer, int nob, int timeout)
267 {
268         int            rc;
269         mm_segment_t   oldmm = get_fs();
270         long           ticks = timeout * HZ;
271         unsigned long  then;
272         struct timeval tv;
273
274         LASSERT (nob > 0);
275         /* Caller may pass a zero timeout if she thinks the socket buffer is
276          * empty enough to take the whole message immediately */
277
278         for (;;) {
279                 struct iovec  iov = {
280                         .iov_base = buffer,
281                         .iov_len  = nob
282                 };
283                 struct msghdr msg = {
284                         .msg_name       = NULL,
285                         .msg_namelen    = 0,
286                         .msg_iov        = &iov,
287                         .msg_iovlen     = 1,
288                         .msg_control    = NULL,
289                         .msg_controllen = 0,
290                         .msg_flags      = (timeout == 0) ? MSG_DONTWAIT : 0
291                 };
292
293                 if (timeout != 0) {
294                         /* Set send timeout to remaining time */
295                         tv = (struct timeval) {
296                                 .tv_sec = ticks / HZ,
297                                 .tv_usec = ((ticks % HZ) * 1000000) / HZ
298                         };
299                         set_fs(KERNEL_DS);
300                         rc = sock_setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
301                                              (char *)&tv, sizeof(tv));
302                         set_fs(oldmm);
303                         if (rc != 0) {
304                                 CERROR("Can't set socket send timeout "
305                                        "%ld.%06d: %d\n",
306                                        (long)tv.tv_sec, (int)tv.tv_usec, rc);
307                                 return rc;
308                         }
309                 }
310
311                 set_fs (KERNEL_DS);
312                 then = jiffies;
313                 rc = sock_sendmsg (sock, &msg, iov.iov_len);
314                 ticks -= jiffies - then;
315                 set_fs (oldmm);
316
317                 if (rc == nob)
318                         return 0;
319
320                 if (rc < 0)
321                         return rc;
322
323                 if (rc == 0) {
324                         CERROR ("Unexpected zero rc\n");
325                         return (-ECONNABORTED);
326                 }
327
328                 if (ticks <= 0)
329                         return -EAGAIN;
330
331                 buffer = ((char *)buffer) + rc;
332                 nob -= rc;
333         }
334
335         return (0);
336 }
337 EXPORT_SYMBOL(libcfs_sock_write);
338
339 int
340 libcfs_sock_read (struct socket *sock, void *buffer, int nob, int timeout)
341 {
342         int            rc;
343         mm_segment_t   oldmm = get_fs();
344         long           ticks = timeout * HZ;
345         unsigned long  then;
346         struct timeval tv;
347
348         LASSERT (nob > 0);
349         LASSERT (ticks > 0);
350
351         for (;;) {
352                 struct iovec  iov = {
353                         .iov_base = buffer,
354                         .iov_len  = nob
355                 };
356                 struct msghdr msg = {
357                         .msg_name       = NULL,
358                         .msg_namelen    = 0,
359                         .msg_iov        = &iov,
360                         .msg_iovlen     = 1,
361                         .msg_control    = NULL,
362                         .msg_controllen = 0,
363                         .msg_flags      = 0
364                 };
365
366                 /* Set receive timeout to remaining time */
367                 tv = (struct timeval) {
368                         .tv_sec = ticks / HZ,
369                         .tv_usec = ((ticks % HZ) * 1000000) / HZ
370                 };
371                 set_fs(KERNEL_DS);
372                 rc = sock_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
373                                      (char *)&tv, sizeof(tv));
374                 set_fs(oldmm);
375                 if (rc != 0) {
376                         CERROR("Can't set socket recv timeout %ld.%06d: %d\n",
377                                (long)tv.tv_sec, (int)tv.tv_usec, rc);
378                         return rc;
379                 }
380
381                 set_fs(KERNEL_DS);
382                 then = jiffies;
383                 rc = sock_recvmsg(sock, &msg, iov.iov_len, 0);
384                 ticks -= jiffies - then;
385                 set_fs(oldmm);
386
387                 if (rc < 0)
388                         return rc;
389
390                 if (rc == 0)
391                         return -ECONNRESET;
392
393                 buffer = ((char *)buffer) + rc;
394                 nob -= rc;
395
396                 if (nob == 0)
397                         return 0;
398
399                 if (ticks <= 0)
400                         return -ETIMEDOUT;
401         }
402 }
403
404 EXPORT_SYMBOL(libcfs_sock_read);
405
406 static int
407 libcfs_sock_create (struct socket **sockp, int *fatal,
408                     __u32 local_ip, int local_port)
409 {
410         struct sockaddr_in  locaddr;
411         struct socket      *sock;
412         int                 rc;
413         int                 option;
414         mm_segment_t        oldmm = get_fs();
415
416         /* All errors are fatal except bind failure if the port is in use */
417         *fatal = 1;
418
419         rc = sock_create (PF_INET, SOCK_STREAM, 0, &sock);
420         *sockp = sock;
421         if (rc != 0) {
422                 CERROR ("Can't create socket: %d\n", rc);
423                 return (rc);
424         }
425
426         set_fs (KERNEL_DS);
427         option = 1;
428         rc = sock_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
429                              (char *)&option, sizeof (option));
430         set_fs (oldmm);
431         if (rc != 0) {
432                 CERROR("Can't set SO_REUSEADDR for socket: %d\n", rc);
433                 goto failed;
434         }
435
436         if (local_ip != 0 || local_port != 0) {
437                 memset(&locaddr, 0, sizeof(locaddr));
438                 locaddr.sin_family = AF_INET;
439                 locaddr.sin_port = htons(local_port);
440                 locaddr.sin_addr.s_addr = (local_ip == 0) ?
441                                           INADDR_ANY : htonl(local_ip);
442
443                 rc = sock->ops->bind(sock, (struct sockaddr *)&locaddr,
444                                      sizeof(locaddr));
445                 if (rc == -EADDRINUSE) {
446                         CDEBUG(D_NET, "Port %d already in use\n", local_port);
447                         *fatal = 0;
448                         goto failed;
449                 }
450                 if (rc != 0) {
451                         CERROR("Error trying to bind to port %d: %d\n",
452                                local_port, rc);
453                         goto failed;
454                 }
455         }
456
457         return 0;
458
459  failed:
460         sock_release(sock);
461         return rc;
462 }
463
464 int
465 libcfs_sock_setbuf (struct socket *sock, int txbufsize, int rxbufsize)
466 {
467         mm_segment_t        oldmm = get_fs();
468         int                 option;
469         int                 rc;
470
471         if (txbufsize != 0) {
472                 option = txbufsize;
473                 set_fs (KERNEL_DS);
474                 rc = sock_setsockopt(sock, SOL_SOCKET, SO_SNDBUF,
475                                      (char *)&option, sizeof (option));
476                 set_fs (oldmm);
477                 if (rc != 0) {
478                         CERROR ("Can't set send buffer %d: %d\n",
479                                 option, rc);
480                         return (rc);
481                 }
482         }
483
484         if (rxbufsize != 0) {
485                 option = rxbufsize;
486                 set_fs (KERNEL_DS);
487                 rc = sock_setsockopt (sock, SOL_SOCKET, SO_RCVBUF,
488                                       (char *)&option, sizeof (option));
489                 set_fs (oldmm);
490                 if (rc != 0) {
491                         CERROR ("Can't set receive buffer %d: %d\n",
492                                 option, rc);
493                         return (rc);
494                 }
495         }
496
497         return 0;
498 }
499
500 EXPORT_SYMBOL(libcfs_sock_setbuf);
501
502 int
503 libcfs_sock_getaddr (struct socket *sock, int remote, __u32 *ip, int *port)
504 {
505         struct sockaddr_in sin;
506         int                len = sizeof (sin);
507         int                rc;
508
509         rc = sock->ops->getname (sock, (struct sockaddr *)&sin, &len,
510                                  remote ? 2 : 0);
511         if (rc != 0) {
512                 CERROR ("Error %d getting sock %s IP/port\n",
513                         rc, remote ? "peer" : "local");
514                 return rc;
515         }
516
517         if (ip != NULL)
518                 *ip = ntohl (sin.sin_addr.s_addr);
519
520         if (port != NULL)
521                 *port = ntohs (sin.sin_port);
522
523         return 0;
524 }
525
526 EXPORT_SYMBOL(libcfs_sock_getaddr);
527
528 int
529 libcfs_sock_getbuf (struct socket *sock, int *txbufsize, int *rxbufsize)
530 {
531
532         if (txbufsize != NULL) {
533                 *txbufsize = sock->sk->sk_sndbuf;
534         }
535
536         if (rxbufsize != NULL) {
537                 *rxbufsize = sock->sk->sk_rcvbuf;
538         }
539
540         return 0;
541 }
542
543 EXPORT_SYMBOL(libcfs_sock_getbuf);
544
545 int
546 libcfs_sock_listen (struct socket **sockp,
547                     __u32 local_ip, int local_port, int backlog)
548 {
549         int      fatal;
550         int      rc;
551
552         rc = libcfs_sock_create(sockp, &fatal, local_ip, local_port);
553         if (rc != 0) {
554                 if (!fatal)
555                         CERROR("Can't create socket: port %d already in use\n",
556                                local_port);
557                 return rc;
558         }
559
560         rc = (*sockp)->ops->listen(*sockp, backlog);
561         if (rc == 0)
562                 return 0;
563
564         CERROR("Can't set listen backlog %d: %d\n", backlog, rc);
565         sock_release(*sockp);
566         return rc;
567 }
568
569 EXPORT_SYMBOL(libcfs_sock_listen);
570
571 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
572 int sock_create_lite(int family, int type, int protocol, struct socket **res)
573 {
574         int err = 0;
575         struct socket *sock;
576
577         sock = sock_alloc();
578         if (!sock) {
579                 err = -ENOMEM;
580                 goto out;
581         }
582         sock->type = type;
583 out:
584         *res = sock;
585         return err;
586 }
587 #endif
588
589 int
590 libcfs_sock_accept (struct socket **newsockp, struct socket *sock)
591 {
592         wait_queue_t   wait;
593         struct socket *newsock;
594         int            rc;
595
596         init_waitqueue_entry(&wait, current);
597
598         /* XXX this should add a ref to sock->ops->owner, if
599          * TCP could be a module */
600         rc = sock_create_lite(PF_PACKET, sock->type, IPPROTO_TCP, &newsock);
601         if (rc) {
602                 CERROR("Can't allocate socket\n");
603                 return rc;
604         }
605
606         newsock->ops = sock->ops;
607
608         set_current_state(TASK_INTERRUPTIBLE);
609         add_wait_queue(sock->sk->sk_sleep, &wait);
610
611         rc = sock->ops->accept(sock, newsock, O_NONBLOCK);
612         if (rc == -EAGAIN) {
613                 /* Nothing ready, so wait for activity */
614                 schedule();
615                 rc = sock->ops->accept(sock, newsock, O_NONBLOCK);
616         }
617
618         remove_wait_queue(sock->sk->sk_sleep, &wait);
619         set_current_state(TASK_RUNNING);
620
621         if (rc != 0)
622                 goto failed;
623
624         *newsockp = newsock;
625         return 0;
626
627  failed:
628         sock_release(newsock);
629         return rc;
630 }
631
632 EXPORT_SYMBOL(libcfs_sock_accept);
633
634 void
635 libcfs_sock_abort_accept (struct socket *sock)
636 {
637         wake_up_all(sock->sk->sk_sleep);
638 }
639
640 EXPORT_SYMBOL(libcfs_sock_abort_accept);
641
642 int
643 libcfs_sock_connect (struct socket **sockp, int *fatal,
644                      __u32 local_ip, int local_port,
645                      __u32 peer_ip, int peer_port)
646 {
647         struct sockaddr_in  srvaddr;
648         int                 rc;
649
650         rc = libcfs_sock_create(sockp, fatal, local_ip, local_port);
651         if (rc != 0)
652                 return rc;
653
654         memset (&srvaddr, 0, sizeof (srvaddr));
655         srvaddr.sin_family = AF_INET;
656         srvaddr.sin_port = htons(peer_port);
657         srvaddr.sin_addr.s_addr = htonl(peer_ip);
658
659         rc = (*sockp)->ops->connect(*sockp,
660                                     (struct sockaddr *)&srvaddr, sizeof(srvaddr),
661                                     0);
662         if (rc == 0)
663                 return 0;
664
665         /* EADDRNOTAVAIL probably means we're already connected to the same
666          * peer/port on the same local port on a differently typed
667          * connection.  Let our caller retry with a different local
668          * port... */
669         *fatal = !(rc == -EADDRNOTAVAIL);
670
671         CDEBUG(*fatal ? D_NETERROR : D_NET,
672                "Error %d connecting %u.%u.%u.%u/%d -> %u.%u.%u.%u/%d\n", rc,
673                HIPQUAD(local_ip), local_port, HIPQUAD(peer_ip), peer_port);
674
675         sock_release(*sockp);
676         return rc;
677 }
678
679 EXPORT_SYMBOL(libcfs_sock_connect);
680
681 void
682 libcfs_sock_release (struct socket *sock)
683 {
684         sock_release(sock);
685 }
686
687 EXPORT_SYMBOL(libcfs_sock_release);