Whamcloud - gitweb
* lctl set_route <nid> <up/down> enables or disables particular portals
[fs/lustre-release.git] / lustre / portals / utils / portals.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2001, 2002 Cluster File Systems, Inc.
5  *
6  *   This file is part of Portals, http://www.sf.net/projects/lustre/
7  *
8  *   Portals 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  *   Portals 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 Portals; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <netdb.h>
26 #include <sys/socket.h>
27 #include <netinet/tcp.h>
28 #include <netdb.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <sys/ioctl.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <time.h>
36 #include <stdarg.h>
37 #include <asm/byteorder.h>
38
39 #include <portals/api-support.h>
40 #include <portals/ptlctl.h>
41 #include <portals/list.h>
42 #include <portals/lib-types.h>
43 #include "parser.h"
44
45 unsigned int portal_debug;
46 unsigned int portal_printk;
47 unsigned int portal_stack;
48
49
50 static unsigned int g_nal = 0;
51
52 static int g_socket_txmem = 0;
53 static int g_socket_rxmem = 0;
54 static int g_socket_nonagle = 1;
55
56 typedef struct
57 {
58         char *name;
59         int   num;
60 } name2num_t;
61
62 static name2num_t nalnames[] = {
63         {"any",         0},
64         {"tcp",         SOCKNAL},
65         {"toe",         TOENAL},
66         {"elan",        QSWNAL},
67         {"gm",          GMNAL},
68         {"scimac",      SCIMACNAL},
69         {NULL,          -1}
70 };
71
72 static name2num_t *
73 name2num_lookup_name (name2num_t *table, char *str)
74 {
75         while (table->name != NULL)
76                 if (!strcmp (str, table->name))
77                         return (table);
78                 else
79                         table++;
80         return (NULL);
81 }
82
83 static name2num_t *
84 name2num_lookup_num (name2num_t *table, int num)
85 {
86         while (table->name != NULL)
87                 if (num == table->num)
88                         return (table);
89                 else
90                         table++;
91         return (NULL);
92 }
93
94 int
95 ptl_name2nal (char *str)
96 {
97         name2num_t *e = name2num_lookup_name (nalnames, str);
98
99         return ((e == NULL) ? -1 : e->num);
100 }
101
102 static char *
103 nal2name (int nal)
104 {
105         name2num_t *e = name2num_lookup_num (nalnames, nal);
106
107         return ((e == NULL) ? "???" : e->name);
108 }
109
110 static struct hostent *
111 ptl_gethostbyname(char * hname) {
112         struct hostent *he;
113         he = gethostbyname(hname);
114         if (!he) {
115                 switch(h_errno) {
116                 case HOST_NOT_FOUND:
117                 case NO_ADDRESS:
118                         fprintf(stderr, "Unable to resolve hostname: %s\n",
119                                 hname);
120                         break;
121                 default:
122                         fprintf(stderr, "gethostbyname error: %s\n",
123                                 strerror(errno));
124                         break;
125                 }
126                 return NULL;
127         }
128         return he;
129 }
130
131 int
132 ptl_parse_port (int *port, char *str)
133 {
134         char      *end;
135         
136         *port = strtol (str, &end, 0);
137
138         if (*end == 0 &&                        /* parsed whole string */
139             *port > 0 && *port < 65536)         /* minimal sanity check */
140                 return (0);
141         
142         return (-1);
143 }
144
145 int
146 ptl_parse_time (time_t *t, char *str) 
147 {
148         char          *end;
149         int            n;
150         struct tm      tm;
151         
152         *t = strtol (str, &end, 0);
153         if (*end == 0) /* parsed whole string */
154                 return (0);
155         
156         memset (&tm, 0, sizeof (tm));
157         n = sscanf (str, "%d-%d-%d %d:%d:%d",
158                     &tm.tm_year, &tm.tm_mon, &tm.tm_mday, 
159                     &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
160         if (n != 6)
161                 return (-1);
162         
163         tm.tm_mon--;                    /* convert to 0 == Jan */
164         tm.tm_year -= 1900;             /* y2k quirk */
165         tm.tm_isdst = -1;               /* dunno if it's daylight savings... */
166         
167         *t = mktime (&tm);
168         if (*t == (time_t)-1)
169                 return (-1);
170                         
171         return (0);
172 }
173
174 int
175 ptl_parse_ipaddr (__u32 *ipaddrp, char *str)
176 {
177         struct hostent *he;
178         int             a;
179         int             b;
180         int             c;
181         int             d;
182
183         if (!strcmp (str, "_all_")) 
184         {
185                 *ipaddrp = 0;
186                 return (0);
187         }
188
189         if (sscanf (str, "%d.%d.%d.%d", &a, &b, &c, &d) == 4 &&
190             (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
191             (c & ~0xff) == 0 && (d & ~0xff) == 0)
192         {
193                 *ipaddrp = (a<<24)|(b<<16)|(c<<8)|d;
194                 return (0);
195         }
196         
197         if ((('a' <= str[0] && str[0] <= 'z') ||
198              ('A' <= str[0] && str[0] <= 'Z')) &&
199              (he = ptl_gethostbyname (str)) != NULL)
200         {
201                 __u32 addr = *(__u32 *)he->h_addr;
202
203                 *ipaddrp = ntohl(addr);         /* HOST byte order */
204                 return (0);
205         }
206
207         return (-1);
208 }
209
210 char *
211 ptl_ipaddr_2_str (__u32 ipaddr, char *str)
212 {
213         __u32           net_ip;
214         struct hostent *he;
215         
216         net_ip = htonl (ipaddr);
217         he = gethostbyaddr (&net_ip, sizeof (net_ip), AF_INET);
218         if (he != NULL)
219                 return (he->h_name);
220         
221         sprintf (str, "%d.%d.%d.%d",
222                  (ipaddr >> 24) & 0xff, (ipaddr >> 16) & 0xff,
223                  (ipaddr >> 8) & 0xff, ipaddr & 0xff);
224         return (str);
225 }
226
227 int
228 ptl_parse_nid (ptl_nid_t *nidp, char *str)
229 {
230         __u32 ipaddr;
231         long  lval;
232         
233         if (!strcmp (str, "_all_")) {
234                 *nidp = PTL_NID_ANY;
235                 return (0);
236         }
237
238         if (ptl_parse_ipaddr (&ipaddr, str) == 0) {
239                 *nidp = (ptl_nid_t)ipaddr;
240                 return (0);
241         }
242
243         if (sscanf (str, "%li", &lval) == 1)
244         {
245                 *nidp = (ptl_nid_t)lval;
246                 return (0);
247         }
248
249         if (sscanf (str, "%lx", &lval) == 1)
250         {
251                 *nidp = (ptl_nid_t)lval;
252                 return (0);
253         }
254
255         return (-1);
256 }
257
258 char *
259 ptl_nid2str (char *buffer, ptl_nid_t nid)
260 {
261         __u32           addr = htonl((__u32)nid); /* back to NETWORK byte order */
262         struct hostent *he = gethostbyaddr ((const char *)&addr, sizeof (addr), AF_INET);
263
264         if (he != NULL)
265                 strcpy (buffer, he->h_name);
266         else
267                 sprintf (buffer, LPX64, nid);
268         
269         return (buffer);
270 }
271
272 int g_nal_is_set () 
273 {
274         if (g_nal == 0) {
275                 fprintf (stderr, "Error: you must run the 'network' command first.\n");
276                 return (0);
277         }
278
279         return (1);
280 }
281
282 int g_nal_is_compatible (char *cmd, ...)
283 {
284         va_list       ap;
285         int           nal;
286
287         if (!g_nal_is_set ())
288                 return (0);
289
290         va_start (ap, cmd);
291
292         do {
293                 nal = va_arg (ap, int);
294         } while (nal != 0 && nal != g_nal);
295         
296         va_end (ap);
297         
298         if (g_nal == nal)
299                 return (1);
300         
301         fprintf (stderr, "Command %s not compatible with nal %s\n",
302                  cmd, nal2name (g_nal));
303         return (0);
304 }
305
306 int
307 sock_write (int cfd, void *buffer, int nob)
308 {
309         while (nob > 0)
310         {
311                 int rc = write (cfd, buffer, nob);
312
313                 if (rc < 0)
314                 {
315                         if (errno == EINTR)
316                                 continue;
317                         
318                         return (rc);
319                 }
320
321                 if (rc == 0)
322                 {
323                         fprintf (stderr, "Unexpected zero sock_write\n");
324                         abort();
325                 }
326
327                 nob -= rc;
328                 buffer = (char *)buffer + nob;
329         }
330         
331         return (0);
332 }
333
334 int
335 sock_read (int cfd, void *buffer, int nob)
336 {
337         while (nob > 0)
338         {
339                 int rc = read (cfd, buffer, nob);
340                 
341                 if (rc < 0)
342                 {
343                         if (errno == EINTR)
344                                 continue;
345                         
346                         return (rc);
347                 }
348                 
349                 if (rc == 0)                    /* EOF */
350                 {
351                         errno = ECONNABORTED;
352                         return (-1);
353                 }
354                 
355                 nob -= rc;
356                 buffer = (char *)buffer + nob;
357         }
358         
359         return (0);
360 }
361
362 int ptl_initialize(int argc, char **argv) 
363 {
364         register_ioc_dev(PORTALS_DEV_ID, PORTALS_DEV_PATH);
365         return 0;
366 }
367
368
369 int jt_ptl_network(int argc, char **argv)
370 {
371         name2num_t *entry;
372         int         nal;
373         
374         if (argc == 2 &&
375             (nal = ptl_name2nal (argv[1])) >= 0) {
376                 g_nal = nal;
377                 return (0);
378         }
379                 
380         fprintf(stderr, "usage: %s \n", argv[0]);
381         for (entry = nalnames; entry->name != NULL; entry++)
382                 fprintf (stderr, "%s%s", entry == nalnames ? "<" : "|", entry->name);
383         fprintf(stderr, ">\n");
384         return (-1);
385 }
386
387 int 
388 jt_ptl_print_autoconnects (int argc, char **argv)
389 {
390         struct portal_ioctl_data data;
391         char                     buffer[64];
392         int                      index;
393         int                      rc;
394
395         if (!g_nal_is_compatible (argv[0], SOCKNAL, 0))
396                 return -1;
397
398         for (index = 0;;index++) {
399                 PORTAL_IOC_INIT (data);
400                 data.ioc_nal     = g_nal;
401                 data.ioc_nal_cmd = NAL_CMD_GET_AUTOCONN;
402                 data.ioc_count   = index;
403                 
404                 rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
405                 if (rc != 0)
406                         break;
407
408                 printf (LPX64"@%s:%d #%d buffer %d nonagle %s xchg %s "
409                         "affinity %s eager %s share %d\n",
410                         data.ioc_nid, ptl_ipaddr_2_str (data.ioc_id, buffer),
411                         data.ioc_misc, data.ioc_count, data.ioc_size, 
412                         (data.ioc_flags & 1) ? "on" : "off",
413                         (data.ioc_flags & 2) ? "on" : "off",
414                         (data.ioc_flags & 4) ? "on" : "off",
415                         (data.ioc_flags & 8) ? "on" : "off",
416                         data.ioc_wait);
417         }
418
419         if (index == 0)
420                 printf ("<no autoconnect routes>\n");
421         return 0;
422 }
423
424 int 
425 jt_ptl_add_autoconnect (int argc, char **argv)
426 {
427         struct portal_ioctl_data data;
428         ptl_nid_t                nid;
429         __u32                    ip;
430         int                      port;
431         int                      xchange_nids = 0;
432         int                      irq_affinity = 0;
433         int                      share = 0;
434         int                      eager = 0;
435         int                      rc;
436
437         if (argc < 4 || argc > 5) {
438                 fprintf (stderr, "usage: %s nid ipaddr port [ixse]\n", argv[0]);
439                 return 0;
440         }
441
442         if (!g_nal_is_compatible (argv[0], SOCKNAL, 0))
443                 return -1;
444
445         if (ptl_parse_nid (&nid, argv[1]) != 0 ||
446                 nid == PTL_NID_ANY) {
447                 fprintf (stderr, "Can't parse NID: %s\n", argv[1]);
448                 return -1;
449         }
450
451         if (ptl_parse_ipaddr (&ip, argv[2]) != 0) {
452                 fprintf (stderr, "Can't parse ip addr: %s\n", argv[2]);
453                 return -1;
454         }
455
456         if (ptl_parse_port (&port, argv[3]) != 0) {
457                 fprintf (stderr, "Can't parse port: %s\n", argv[3]);
458                 return -1;
459         }
460
461         if (argc > 4) {
462                 char *opts = argv[4];
463                 
464                 while (*opts != 0)
465                         switch (*opts++) {
466                         case 'x':
467                                 xchange_nids = 1;
468                                 break;
469                         case 'i':
470                                 irq_affinity = 1;
471                                 break;
472                         case 's':
473                                 share = 1;
474                                 break;
475                         case 'e':
476                                 eager = 1;
477                                 break;
478                         default:
479                                 fprintf (stderr, "Can't parse options: %s\n",
480                                          argv[4]);
481                                 return -1;
482                         }
483         }
484
485         PORTAL_IOC_INIT (data);
486         data.ioc_nal     = g_nal;
487         data.ioc_nal_cmd = NAL_CMD_ADD_AUTOCONN;
488         data.ioc_nid     = nid;
489         data.ioc_id      = ip;
490         data.ioc_misc    = port;
491         /* only passing one buffer size! */
492         data.ioc_size    = MAX (g_socket_rxmem, g_socket_txmem);
493         data.ioc_flags   = (g_socket_nonagle ? 0x01 : 0) |
494                            (xchange_nids     ? 0x02 : 0) |
495                            (irq_affinity     ? 0x04 : 0) |
496                            (share            ? 0x08 : 0) |
497                            (eager            ? 0x10 : 0);
498
499         rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
500         if (rc != 0) {
501                 fprintf (stderr, "failed to enable autoconnect: %s\n",
502                          strerror (errno));
503                 return -1;
504         }
505         
506         return 0;
507 }
508
509 int 
510 jt_ptl_del_autoconnect (int argc, char **argv)
511 {
512         struct portal_ioctl_data data;
513         ptl_nid_t                nid = PTL_NID_ANY;
514         __u32                    ip  = 0;
515         int                      share = 0;
516         int                      keep_conn = 0;
517         int                      rc;
518
519         if (argc > 4) {
520                 fprintf (stderr, "usage: %s [nid] [ipaddr] [sk]\n",
521                          argv[0]);
522                 return 0;
523         }
524
525         if (!g_nal_is_compatible (argv[0], SOCKNAL, 0))
526                 return -1;
527
528         if (argc > 1 &&
529             ptl_parse_nid (&nid, argv[1]) != 0) {
530                 fprintf (stderr, "Can't parse nid: %s\n", argv[1]);
531                 return -1;
532         }
533
534         if (argc > 2 &&
535             ptl_parse_ipaddr (&ip, argv[2]) != 0) {
536                 fprintf (stderr, "Can't parse ip addr: %s\n", argv[2]);
537                 return -1;
538         }
539
540         if (argc > 3) {
541                 char *opts = argv[3];
542                 
543                 while (*opts != 0)
544                         switch (*opts++) {
545                         case 's':
546                                 share = 1;
547                                 break;
548                         case 'k':
549                                 keep_conn = 1;
550                                 break;
551                         default:
552                                 fprintf (stderr, "Can't parse flags: %s\n", 
553                                          argv[3]);
554                                 return -1;
555                         }
556         }
557
558         PORTAL_IOC_INIT (data);
559         data.ioc_nal     = g_nal;
560         data.ioc_nal_cmd = NAL_CMD_DEL_AUTOCONN;
561         data.ioc_nid     = nid;
562         data.ioc_id      = ip;
563         data.ioc_flags   = (share     ? 1 : 0) |
564                            (keep_conn ? 2 : 0);
565         
566         rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
567         if (rc != 0) {
568                 fprintf (stderr, "failed to remove autoconnect route: %s\n",
569                          strerror (errno));
570                 return -1;
571         }
572         
573         return 0;
574 }
575
576 int 
577 jt_ptl_print_connections (int argc, char **argv)
578 {
579         struct portal_ioctl_data data;
580         char                     buffer[64];
581         int                      index;
582         int                      rc;
583
584         if (!g_nal_is_compatible (argv[0], SOCKNAL, 0))
585                 return -1;
586
587         for (index = 0;;index++) {
588                 PORTAL_IOC_INIT (data);
589                 data.ioc_nal     = g_nal;
590                 data.ioc_nal_cmd = NAL_CMD_GET_CONN;
591                 data.ioc_count   = index;
592                 
593                 rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
594                 if (rc != 0)
595                         break;
596
597                 printf (LPX64"@%s:%d\n",
598                         data.ioc_nid, 
599                         ptl_ipaddr_2_str (data.ioc_id, buffer),
600                         data.ioc_misc);
601         }
602
603         if (index == 0)
604                 printf ("<no connections>\n");
605         return 0;
606 }
607
608 int
609 exchange_nids (int cfd, ptl_nid_t my_nid, ptl_nid_t *peer_nid)
610 {
611         int                      rc;
612         ptl_hdr_t                hdr;
613         ptl_magicversion_t      *hmv = (ptl_magicversion_t *)&hdr.dest_nid;
614
615         LASSERT (sizeof (*hmv) == sizeof (hdr.dest_nid));
616
617         memset (&hdr, 0, sizeof (hdr));
618         
619         hmv->magic          = __cpu_to_le32 (PORTALS_PROTO_MAGIC);
620         hmv->version_major  = __cpu_to_le16 (PORTALS_PROTO_VERSION_MAJOR);
621         hmv->version_minor  = __cpu_to_le16 (PORTALS_PROTO_VERSION_MINOR);
622
623         hdr.src_nid = __cpu_to_le64 (my_nid);
624         hdr.type = __cpu_to_le32 (PTL_MSG_HELLO);
625         
626         /* Assume there's sufficient socket buffering for a portals HELLO header */
627         rc = sock_write (cfd, &hdr, sizeof (hdr));
628         if (rc != 0) {
629                 perror ("Can't send initial HELLO");
630                 return (-1);
631         }
632
633         /* First few bytes down the wire are the portals protocol magic and
634          * version, no matter what protocol version we're running. */
635
636         rc = sock_read (cfd, hmv, sizeof (*hmv));
637         if (rc != 0) {
638                 perror ("Can't read from peer");
639                 return (-1);
640         }
641
642         if (hmv->magic != __cpu_to_le32 (PORTALS_PROTO_MAGIC)) {
643                 fprintf (stderr, "Bad magic %#08x (%#08x expected)\n", 
644                          __le32_to_cpu (hmv->magic), PORTALS_PROTO_MAGIC);
645                 return (-1);
646         }
647
648         if (hmv->version_major != __cpu_to_le16 (PORTALS_PROTO_VERSION_MAJOR) ||
649             hmv->version_minor != __cpu_to_le16 (PORTALS_PROTO_VERSION_MINOR)) {
650                 fprintf (stderr, "Incompatible protocol version %d.%d (%d.%d expected)\n",
651                          __le16_to_cpu (hmv->version_major),
652                          __le16_to_cpu (hmv->version_minor),
653                          PORTALS_PROTO_VERSION_MAJOR,
654                          PORTALS_PROTO_VERSION_MINOR);
655         }
656
657         /* version 0 sends magic/version as the dest_nid of a 'hello' header,
658          * so read the rest of it in now... */
659         LASSERT (PORTALS_PROTO_VERSION_MAJOR == 0);
660         rc = sock_read (cfd, hmv + 1, sizeof (hdr) - sizeof (*hmv));
661         if (rc != 0) {
662                 perror ("Can't read rest of HELLO hdr");
663                 return (-1);
664         }
665
666         /* ...and check we got what we expected */
667         if (hdr.type != __cpu_to_le32 (PTL_MSG_HELLO) ||
668             PTL_HDR_LENGTH (&hdr) != __cpu_to_le32 (0)) {
669                 fprintf (stderr, "Expecting a HELLO hdr with 0 payload,"
670                          " but got type %d with %d payload\n",
671                          __le32_to_cpu (hdr.type),
672                          __le32_to_cpu (PTL_HDR_LENGTH (&hdr)));
673                 return (-1);
674         }
675         
676         *peer_nid = __le64_to_cpu (hdr.src_nid);
677         return (0);
678 }
679
680 int jt_ptl_connect(int argc, char **argv)
681 {
682         ptl_nid_t peer_nid;
683         struct portal_ioctl_data data;
684         struct sockaddr_in srvaddr;
685         __u32 ipaddr;
686         char *flag;
687         int fd, rc;
688         int nonagle = 0;
689         int rxmem = 0;
690         int txmem = 0;
691         int bind_irq = 0;
692         int xchange_nids = 0;
693         int port;
694         int o;
695         int olen;
696
697         if (argc < 3) {
698                 fprintf(stderr, "usage: %s ip port [xi]\n", argv[0]);
699                 return 0;
700         }
701
702         if (!g_nal_is_compatible (argv[0], SOCKNAL, TOENAL, 0))
703                 return -1;
704         
705         rc = ptl_parse_ipaddr (&ipaddr, argv[1]);
706         if (rc != 0) {
707                 fprintf(stderr, "Can't parse hostname: %s\n", argv[1]);
708                 return -1;
709         }
710
711         if (ptl_parse_port (&port, argv[2]) != 0) {
712                 fprintf (stderr, "Can't parse port: %s\n", argv[2]);
713                 return -1;
714         }
715
716         if (argc > 3)
717                 for (flag = argv[3]; *flag != 0; flag++)
718                         switch (*flag)
719                         {
720                         case 'i':
721                                 bind_irq = 1;
722                                 break;
723                                 
724                         case 'x':
725                                 xchange_nids = 1;
726                                 break;
727                                 
728                         default:
729                                 fprintf (stderr, "unrecognised flag '%c'\n",
730                                          *flag);
731                                 return (-1);
732                         }
733
734         memset(&srvaddr, 0, sizeof(srvaddr));
735         srvaddr.sin_family = AF_INET;
736         srvaddr.sin_port = htons(port);
737         srvaddr.sin_addr.s_addr = htonl(ipaddr);
738
739         fd = socket(PF_INET, SOCK_STREAM, 0);
740         if ( fd < 0 ) {
741                 fprintf(stderr, "socket() failed: %s\n", strerror(errno));
742                 return -1;
743         }
744
745         if (g_socket_nonagle)
746         {
747                 o = 1;
748                 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &o, sizeof (o)) != 0) { 
749                         fprintf(stderr, "cannot disable nagle: %s\n", strerror(errno));
750                         return (-1);
751                 }
752         }
753
754         if (g_socket_rxmem != 0) {
755                 o = g_socket_rxmem;
756                 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &o, sizeof (o)) != 0) { 
757                         fprintf(stderr, "cannot set receive buffer size: %s\n", strerror(errno));
758                         return (-1);
759                 }
760         }
761
762         if (g_socket_txmem != 0) {
763                 o = g_socket_txmem;
764                 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &o, sizeof (o)) != 0) { 
765                         fprintf(stderr, "cannot set send buffer size: %s\n", strerror(errno));
766                         return (-1);
767                 }
768         }
769
770         rc = connect(fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
771         if ( rc == -1 ) { 
772                 fprintf(stderr, "connect() failed: %s\n", strerror(errno));
773                 return -1;
774         }
775
776         olen = sizeof (txmem);
777         if (getsockopt (fd, SOL_SOCKET, SO_SNDBUF, &txmem, &olen) != 0)
778                 fprintf (stderr, "Can't get send buffer size: %s\n", strerror (errno));
779         olen = sizeof (rxmem);
780         if (getsockopt (fd, SOL_SOCKET, SO_RCVBUF, &rxmem, &olen) != 0)
781                 fprintf (stderr, "Can't get receive buffer size: %s\n", strerror (errno));
782         olen = sizeof (nonagle);
783         if (getsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &nonagle, &olen) != 0)
784                 fprintf (stderr, "Can't get nagle: %s\n", strerror (errno));
785
786         if (!xchange_nids) 
787                 peer_nid = ipaddr;
788         else {
789                 PORTAL_IOC_INIT (data);
790                 data.ioc_nal = g_nal;
791                 rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_GET_NID, &data);
792                 if (rc != 0) {
793                         fprintf (stderr, "failed to get my nid: %s\n",
794                                  strerror (errno));
795                         close (fd);
796                         return (-1);
797                 }
798
799                 rc = exchange_nids (fd, data.ioc_nid, &peer_nid);
800                 if (rc != 0) {
801                         close (fd);
802                         return (-1);
803                 }
804         } 
805         printf("Connected host: %s NID "LPX64" snd: %d rcv: %d nagle: %s\n", argv[1],
806                peer_nid, txmem, rxmem, nonagle ? "Disabled" : "Enabled");
807
808         PORTAL_IOC_INIT(data);
809         data.ioc_fd = fd;
810         data.ioc_nal = g_nal;
811         data.ioc_nal_cmd = NAL_CMD_REGISTER_PEER_FD;
812         data.ioc_nid = peer_nid;
813         data.ioc_flags = bind_irq;
814
815         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
816         if (rc) {
817                 fprintf(stderr, "failed to register fd with portals: %s\n", 
818                         strerror(errno));
819                 close (fd);
820                 return -1;
821         }
822
823         printf("Connection to "LPX64" registered with socknal\n", peer_nid);
824
825         rc = close(fd);
826         if (rc)
827                 fprintf(stderr, "close failed: %d\n", rc);
828
829         return 0;
830 }
831
832 int jt_ptl_disconnect(int argc, char **argv)
833 {
834         struct portal_ioctl_data data;
835         ptl_nid_t                nid = PTL_NID_ANY;
836         __u32                    ipaddr = 0;
837         int                      rc;
838
839         if (argc > 3) {
840                 fprintf(stderr, "usage: %s [nid] [ipaddr]\n", argv[0]);
841                 return 0;
842         }
843
844         if (!g_nal_is_compatible (argv[0], SOCKNAL, TOENAL, 0))
845                 return -1;
846
847         if (argc >= 2 &&
848             ptl_parse_nid (&nid, argv[1]) != 0) {
849                 fprintf (stderr, "Can't parse nid %s\n", argv[1]);
850                 return -1;
851         }
852
853         if (argc >= 3 &&
854             ptl_parse_ipaddr (&ipaddr, argv[2]) != 0) {
855                 fprintf (stderr, "Can't parse ip addr %s\n", argv[2]);
856                 return -1;
857         }
858
859         PORTAL_IOC_INIT(data);
860         data.ioc_nal     = g_nal;
861         data.ioc_nal_cmd = NAL_CMD_CLOSE_CONNECTION;
862         data.ioc_nid     = nid;
863         data.ioc_id      = ipaddr;
864         
865         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
866         if (rc) {
867                 fprintf(stderr, "failed to remove connection: %s\n",
868                         strerror(errno));
869                 return -1;
870         }
871
872         return 0;
873 }
874
875 int jt_ptl_push_connection (int argc, char **argv)
876 {
877         struct portal_ioctl_data data;
878         int                      rc;
879         ptl_nid_t                nid = PTL_NID_ANY;
880         __u32                    ipaddr = 0;
881
882         if (argc > 3) {
883                 fprintf(stderr, "usage: %s [nid] [ip]\n", argv[0]);
884                 return 0;
885         }
886
887         if (!g_nal_is_compatible (argv[0], SOCKNAL, TOENAL, 0))
888                 return -1;
889         
890         if (argc > 1 &&
891             ptl_parse_nid (&nid, argv[1]) != 0) {
892                 fprintf(stderr, "Can't parse nid: %s\n", argv[1]);
893                 return -1;
894         }
895                         
896         if (argc > 2 &&
897             ptl_parse_ipaddr (&ipaddr, argv[2]) != 0) {
898                 fprintf(stderr, "Can't parse ipaddr: %s\n", argv[2]);
899         }
900
901         PORTAL_IOC_INIT(data);
902         data.ioc_nal     = g_nal;
903         data.ioc_nal_cmd = NAL_CMD_PUSH_CONNECTION;
904         data.ioc_nid     = nid;
905         data.ioc_id      = ipaddr;
906
907         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
908         if (rc) {
909                 fprintf(stderr, "failed to push connection: %s\n",
910                         strerror(errno));
911                 return -1;
912         }
913
914         return 0;
915 }
916
917 int 
918 jt_ptl_print_active_txs (int argc, char **argv)
919 {
920         struct portal_ioctl_data data;
921         int                      index;
922         int                      rc;
923
924         if (!g_nal_is_compatible (argv[0], QSWNAL, 0))
925                 return -1;
926
927         for (index = 0;;index++) {
928                 PORTAL_IOC_INIT (data);
929                 data.ioc_nal     = g_nal;
930                 data.ioc_nal_cmd = NAL_CMD_GET_TXDESC;
931                 data.ioc_count   = index;
932                 
933                 rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
934                 if (rc != 0)
935                         break;
936
937                 printf ("%p: %5s payload %6d bytes to "LPX64" via "LPX64" by pid %6d: %s,%s,%s\n",
938                         data.ioc_pbuf1,
939                         data.ioc_count == PTL_MSG_ACK ? "ACK" :
940                         data.ioc_count == PTL_MSG_PUT ? "PUT" :
941                         data.ioc_count == PTL_MSG_GET ? "GET" :
942                         data.ioc_count == PTL_MSG_REPLY ? "REPLY" : "<wierd message>",
943                         data.ioc_size,
944                         data.ioc_nid,
945                         data.ioc_nid2,
946                         data.ioc_misc,
947                         (data.ioc_flags & 1) ? "delayed" : "active",
948                         (data.ioc_flags & 2) ? "forwarding" : "sending",
949                         (data.ioc_flags & 4) ? "nblk" : "normal");
950         }
951
952         if (index == 0)
953                 printf ("<no active descs>\n");
954         return 0;
955 }
956
957 int jt_ptl_ping(int argc, char **argv)
958 {
959         int       rc;
960         ptl_nid_t nid;
961         long      count   = 1;
962         long      size    = 4;
963         long      timeout = 1;
964         struct portal_ioctl_data data;
965
966         if (argc < 2) {
967                 fprintf(stderr, "usage: %s nid [count] [size] [timeout (secs)]\n", argv[0]);
968                 return 0;
969         }
970
971         if (!g_nal_is_set())
972                 return -1;
973
974         if (ptl_parse_nid (&nid, argv[1]) != 0)
975         {
976                 fprintf (stderr, "Can't parse nid \"%s\"\n", argv[1]);
977                 return (-1);
978         }
979         
980         if (argc > 2)
981         {
982                 count = atol(argv[2]);
983
984                 if (count < 0 || count > 20000) 
985                 {
986                         fprintf(stderr, "are you insane?  %ld is a crazy count.\n", count);
987                         return -1;
988                 }
989         }
990         
991         if (argc > 3)
992                 size= atol(argv[3]);
993
994         if (argc > 4)
995                 timeout = atol (argv[4]);
996         
997         PORTAL_IOC_INIT (data);
998         data.ioc_count   = count;
999         data.ioc_size    = size;
1000         data.ioc_nid     = nid;
1001         data.ioc_nal     = g_nal;
1002         data.ioc_timeout = timeout;
1003         
1004         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_PING, &data);
1005         if (rc) {
1006                 fprintf(stderr, "failed to start pinger: %s\n",
1007                         strerror(errno));
1008                 return -1;
1009         }
1010         return 0;
1011 }
1012
1013 int jt_ptl_shownid(int argc, char **argv)
1014 {
1015         struct portal_ioctl_data data;
1016         int                      rc;
1017         
1018         if (argc > 1) {
1019                 fprintf(stderr, "usage: %s\n", argv[0]);
1020                 return 0;
1021         }
1022         
1023         if (!g_nal_is_set())
1024                 return -1;
1025
1026         PORTAL_IOC_INIT (data);
1027         data.ioc_nal = g_nal;
1028         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_GET_NID, &data);
1029         if (rc < 0)
1030                 fprintf(stderr, "getting my NID failed: %s\n",
1031                         strerror (errno));
1032         else
1033                 printf(LPX64"\n", data.ioc_nid);
1034         return 0;
1035 }
1036
1037 int jt_ptl_mynid(int argc, char **argv)
1038 {
1039         int rc;
1040         char hostname[1024];
1041         char *nidstr;
1042         struct portal_ioctl_data data;
1043         ptl_nid_t mynid;
1044         
1045         if (argc > 2) {
1046                 fprintf(stderr, "usage: %s [NID]\n", argv[0]);
1047                 fprintf(stderr, "NID defaults to the primary IP address of the machine.\n");
1048                 return 0;
1049         }
1050
1051         if (!g_nal_is_set())
1052                 return -1;
1053
1054         if (argc >= 2)
1055                 nidstr = argv[1];
1056         else if (gethostname(hostname, sizeof(hostname)) != 0) {
1057                 fprintf(stderr, "gethostname failed: %s\n",
1058                         strerror(errno));
1059                 return -1;
1060         }
1061         else
1062                 nidstr = hostname;
1063
1064         rc = ptl_parse_nid (&mynid, nidstr);
1065         if (rc != 0) {
1066                 fprintf (stderr, "Can't convert '%s' into a NID\n", nidstr);
1067                 return -1;
1068         }
1069         
1070         PORTAL_IOC_INIT(data);
1071         data.ioc_nid = mynid;
1072         data.ioc_nal = g_nal;
1073         data.ioc_nal_cmd = NAL_CMD_REGISTER_MYNID;
1074
1075         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
1076         if (rc < 0)
1077                 fprintf(stderr, "setting my NID failed: %s\n",
1078                        strerror(errno));
1079         else
1080                 printf("registered my nid "LPX64" (%s)\n", mynid, hostname);
1081         return 0;
1082 }
1083
1084 int
1085 jt_ptl_fail_nid (int argc, char **argv)
1086 {
1087         int                      rc;
1088         ptl_nid_t                nid;
1089         unsigned int             threshold;
1090         struct portal_ioctl_data data;
1091
1092         if (argc < 2 || argc > 3)
1093         {
1094                 fprintf (stderr, "usage: %s nid|\"_all_\" [count (0 == mend)]\n", argv[0]);
1095                 return (0);
1096         }
1097         
1098         if (!g_nal_is_set())
1099                 return (-1);
1100
1101         if (!strcmp (argv[1], "_all_"))
1102                 nid = PTL_NID_ANY;
1103         else if (ptl_parse_nid (&nid, argv[1]) != 0)
1104         {
1105                 fprintf (stderr, "Can't parse nid \"%s\"\n", argv[1]);
1106                 return (-1);
1107         }
1108
1109         if (argc < 3)
1110                 threshold = PTL_MD_THRESH_INF;
1111         else if (sscanf (argv[2], "%i", &threshold) != 1) {
1112                 fprintf (stderr, "Can't parse count \"%s\"\n", argv[2]);
1113                 return (-1);
1114         }
1115         
1116         PORTAL_IOC_INIT (data);
1117         data.ioc_nal = g_nal;
1118         data.ioc_nid = nid;
1119         data.ioc_count = threshold;
1120         
1121         rc = l_ioctl (PORTALS_DEV_ID, IOC_PORTAL_FAIL_NID, &data);
1122         if (rc < 0)
1123                 fprintf (stderr, "IOC_PORTAL_FAIL_NID failed: %s\n",
1124                          strerror (errno));
1125         else
1126                 printf ("%s %s\n", threshold == 0 ? "Unfailing" : "Failing", argv[1]);
1127         
1128         return (0);
1129 }
1130
1131 int
1132 jt_ptl_rxmem (int argc, char **argv)
1133 {
1134         int   size;
1135         
1136         if (argc > 1)
1137         {
1138                 if (Parser_size (&size, argv[1]) != 0 || size < 0)
1139                 {
1140                         fprintf (stderr, "Can't parse size %s\n", argv[1]);
1141                         return (0);
1142                 }
1143
1144                 g_socket_rxmem = size;
1145         }
1146         printf ("Socket rmem = %d\n", g_socket_rxmem);        
1147         return (0);
1148 }
1149
1150 int
1151 jt_ptl_txmem (int argc, char **argv)
1152 {
1153         int   size;
1154         
1155         if (argc > 1)
1156         {
1157                 if (Parser_size (&size, argv[1]) != 0 || size < 0)
1158                 {
1159                         fprintf (stderr, "Can't parse size %s\n", argv[1]);
1160                         return (0);
1161                 }
1162                 g_socket_txmem = size;
1163         }
1164         printf ("Socket txmem = %d\n", g_socket_txmem);
1165         return (0);
1166 }
1167
1168 int
1169 jt_ptl_nagle (int argc, char **argv)
1170 {
1171         int enable;
1172
1173         if (argc > 1)
1174         {
1175                 if (Parser_bool (&enable, argv[1]) != 0)
1176                 {
1177                         fprintf (stderr, "Can't parse boolean %s\n", argv[1]);
1178                         return (-1);
1179                 }
1180                 g_socket_nonagle = !enable;
1181         }
1182         printf ("Nagle %s\n", g_socket_nonagle ? "disabled" : "enabled");
1183         return (0);
1184 }
1185
1186 int
1187 jt_ptl_add_route (int argc, char **argv)
1188 {
1189         struct portal_ioctl_data data;
1190         ptl_nid_t                nid1;
1191         ptl_nid_t                nid2;
1192         ptl_nid_t                gateway_nid;
1193         int                      rc;
1194         
1195         if (argc < 3)
1196         {
1197                 fprintf (stderr, "usage: %s gateway target [target]\n", argv[0]);
1198                 return (0);
1199         }
1200
1201         if (!g_nal_is_set())
1202                 return (-1);
1203
1204         if (ptl_parse_nid (&gateway_nid, argv[1]) != 0)
1205         {
1206                 fprintf (stderr, "Can't parse gateway NID \"%s\"\n", argv[1]);
1207                 return (-1);
1208         }
1209
1210         if (ptl_parse_nid (&nid1, argv[2]) != 0)
1211         {
1212                 fprintf (stderr, "Can't parse first target NID \"%s\"\n", argv[2]);
1213                 return (-1);
1214         }
1215
1216         if (argc < 4)
1217                 nid2 = nid1;
1218         else if (ptl_parse_nid (&nid2, argv[3]) != 0)
1219         {
1220                 fprintf (stderr, "Can't parse second target NID \"%s\"\n", argv[4]);
1221                 return (-1);
1222         }
1223
1224         PORTAL_IOC_INIT(data);
1225         data.ioc_nid = gateway_nid;
1226         data.ioc_nal = g_nal;
1227         data.ioc_nid2 = MIN (nid1, nid2);
1228         data.ioc_nid3 = MAX (nid1, nid2);
1229
1230         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_ADD_ROUTE, &data);
1231         if (rc != 0) 
1232         {
1233                 fprintf (stderr, "IOC_PORTAL_ADD_ROUTE failed: %s\n", strerror (errno));
1234                 return (-1);
1235         }
1236         
1237         return (0);
1238 }
1239
1240 int
1241 jt_ptl_del_route (int argc, char **argv)
1242 {
1243         struct portal_ioctl_data data;
1244         ptl_nid_t                nid;
1245         ptl_nid_t                nid1 = PTL_NID_ANY;
1246         ptl_nid_t                nid2 = PTL_NID_ANY;
1247         int                      rc;
1248         
1249         if (argc < 2)
1250         {
1251                 fprintf (stderr, "usage: %s targetNID\n", argv[0]);
1252                 return (0);
1253         }
1254
1255         if (!g_nal_is_set())
1256                 return (-1);
1257
1258         if (ptl_parse_nid (&nid, argv[1]) != 0)
1259         {
1260                 fprintf (stderr, "Can't parse gateway NID \"%s\"\n", argv[1]);
1261                 return (-1);
1262         }
1263
1264         if (argc >= 3 &&
1265             ptl_parse_nid (&nid1, argv[2]) != 0)
1266         {
1267                 fprintf (stderr, "Can't parse target NID \"%s\"\n", argv[2]);
1268                 return (-1);
1269         }
1270
1271         if (argc < 4) {
1272                 nid2 = nid1;
1273         } else {
1274                 if (ptl_parse_nid (&nid2, argv[3]) != 0) {
1275                         fprintf (stderr, "Can't parse target NID \"%s\"\n", argv[3]);
1276                         return (-1);
1277                 }
1278
1279                 if (nid1 > nid2) {
1280                         ptl_nid_t tmp = nid1;
1281                         
1282                         nid1 = nid2;
1283                         nid2 = tmp;
1284                 }
1285         }
1286         
1287         PORTAL_IOC_INIT(data);
1288         data.ioc_nal = g_nal;
1289         data.ioc_nid = nid;
1290         data.ioc_nid2 = nid1;
1291         data.ioc_nid3 = nid2;
1292
1293         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_DEL_ROUTE, &data);
1294         if (rc != 0) 
1295         {
1296                 fprintf (stderr, "IOC_PORTAL_DEL_ROUTE ("LPX64") failed: %s\n", nid, strerror (errno));
1297                 return (-1);
1298         }
1299         
1300         return (0);
1301 }
1302
1303 int
1304 jt_ptl_notify_router (int argc, char **argv)
1305 {
1306         struct portal_ioctl_data data;
1307         int                      enable;
1308         ptl_nid_t                nid;
1309         int                      rc;
1310         struct timeval           now;
1311         time_t                   when;
1312
1313         if (argc < 3)
1314         {
1315                 fprintf (stderr, "usage: %s targetNID <up/down> [<time>]\n", 
1316                          argv[0]);
1317                 return (0);
1318         }
1319
1320         if (ptl_parse_nid (&nid, argv[1]) != 0)
1321         {
1322                 fprintf (stderr, "Can't parse target NID \"%s\"\n", argv[1]);
1323                 return (-1);
1324         }
1325
1326         if (Parser_bool (&enable, argv[2]) != 0) {
1327                 fprintf (stderr, "Can't parse boolean %s\n", argv[2]);
1328                 return (-1);
1329         }
1330
1331         gettimeofday(&now, NULL);
1332         
1333         if (argc < 4) {
1334                 when = now.tv_sec;
1335         } else if (ptl_parse_time (&when, argv[3]) != 0) {
1336                 fprintf(stderr, "Can't parse time %s\n"
1337                         "Please specify either 'YYYY-MM-DD HH:MM:SS'\n"
1338                         "or an absolute unix time in seconds\n", argv[3]);
1339                 return (-1);
1340         } else if (when > now.tv_sec) {
1341                 fprintf (stderr, "%s specifies a time in the future\n",
1342                          argv[3]);
1343                 return (-1);
1344         }
1345
1346         PORTAL_IOC_INIT(data);
1347         data.ioc_nal = g_nal;
1348         data.ioc_nid = nid;
1349         data.ioc_flags = enable;
1350         /* Yeuch; 'cept I need a __u64 on 64 bit machines... */
1351         data.ioc_nid3 = (__u64)when;
1352         
1353         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NOTIFY_ROUTER, &data);
1354         if (rc != 0) 
1355         {
1356                 fprintf (stderr, "IOC_PORTAL_NOTIFY_ROUTER ("LPX64") failed: %s\n",
1357                          nid, strerror (errno));
1358                 return (-1);
1359         }
1360         
1361         return (0);
1362 }
1363
1364 int
1365 jt_ptl_print_routes (int argc, char **argv)
1366 {
1367         char                      buffer[3][128];
1368         struct portal_ioctl_data  data;
1369         int                       rc;
1370         int                       index;
1371         int                       gateway_nal;
1372         ptl_nid_t                 gateway_nid;
1373         ptl_nid_t                 nid1;
1374         ptl_nid_t                 nid2;
1375         int                       alive;
1376
1377         for (index = 0;;index++)
1378         {
1379                 PORTAL_IOC_INIT(data);
1380                 data.ioc_count = index;
1381                 
1382                 rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_GET_ROUTE, &data);
1383                 if (rc != 0)
1384                         break;
1385
1386                 gateway_nal = data.ioc_nal;
1387                 gateway_nid = data.ioc_nid;
1388                 nid1 = data.ioc_nid2;
1389                 nid2 = data.ioc_nid3;
1390                 alive = data.ioc_flags;
1391
1392                 printf ("%8s %18s : %s - %s, %s\n", 
1393                         nal2name (gateway_nal), 
1394                         ptl_nid2str (buffer[0], gateway_nid),
1395                         ptl_nid2str (buffer[1], nid1),
1396                         ptl_nid2str (buffer[2], nid2),
1397                         alive ? "up" : "down");
1398         }
1399         return (0);
1400 }
1401
1402 static int
1403 lwt_control(int enable, int clear)
1404 {
1405         struct portal_ioctl_data data;
1406         int                      rc;
1407
1408         PORTAL_IOC_INIT(data);
1409         data.ioc_flags = enable;
1410         data.ioc_misc = clear;
1411
1412         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_LWT_CONTROL, &data);
1413         if (rc == 0)
1414                 return (0);
1415
1416         fprintf(stderr, "IOC_PORTAL_LWT_CONTROL failed: %s\n",
1417                 strerror(errno));
1418         return (-1);
1419 }
1420
1421 static int
1422 lwt_snapshot(int *ncpu, int *totalsize, lwt_event_t *events, int size)
1423 {
1424         struct portal_ioctl_data data;
1425         int                      rc;
1426
1427         PORTAL_IOC_INIT(data);
1428         data.ioc_pbuf1 = (char *)events;
1429         data.ioc_plen1 = size;
1430
1431         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_LWT_SNAPSHOT, &data);
1432         if (rc != 0) {
1433                 fprintf(stderr, "IOC_PORTAL_LWT_SNAPSHOT failed: %s\n",
1434                         strerror(errno));
1435                 return (-1);
1436         }
1437
1438         LASSERT (data.ioc_count != 0);
1439         LASSERT (data.ioc_misc != 0);
1440         
1441         if (ncpu != NULL)
1442                 *ncpu = data.ioc_count;
1443
1444         if (totalsize != NULL)
1445                 *totalsize = data.ioc_misc;
1446
1447         return (0);
1448 }
1449
1450 static char *
1451 lwt_get_string(char *kstr)
1452 {
1453         char                     *ustr;
1454         struct portal_ioctl_data  data;
1455         int                       size;
1456         int                       rc;
1457
1458         /* FIXME: this could maintain a symbol table since we expect to be
1459          * looking up the same strings all the time... */
1460
1461         PORTAL_IOC_INIT(data);
1462         data.ioc_pbuf1 = kstr;
1463         data.ioc_plen1 = 1;        /* non-zero just to fool portal_ioctl_is_invalid() */
1464         data.ioc_pbuf2 = NULL;
1465         data.ioc_plen2 = 0;
1466
1467         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_LWT_LOOKUP_STRING, &data);
1468         if (rc != 0) {
1469                 fprintf(stderr, "IOC_PORTAL_LWT_LOOKUP_STRING failed: %s\n",
1470                         strerror(errno));
1471                 return (NULL);
1472         }
1473
1474         size = data.ioc_count;
1475         ustr = (char *)malloc(size);
1476         if (ustr == NULL) {
1477                 fprintf(stderr, "Can't allocate string storage of size %d\n",
1478                         size);
1479                 return (NULL);
1480         }
1481
1482         PORTAL_IOC_INIT(data);
1483         data.ioc_pbuf1 = kstr;
1484         data.ioc_plen1 = 1;        /* non-zero just to fool portal_ioctl_is_invalid() */
1485         data.ioc_pbuf2 = ustr;
1486         data.ioc_plen2 = size;
1487
1488         rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_LWT_LOOKUP_STRING, &data);
1489         if (rc != 0) {
1490                 fprintf(stderr, "IOC_PORTAL_LWT_LOOKUP_STRING failed: %s\n",
1491                         strerror(errno));
1492                 return (NULL);
1493         }
1494
1495         LASSERT(strlen(ustr) == size - 1);
1496         return (ustr);
1497 }
1498
1499 static void
1500 lwt_put_string(char *ustr)
1501 {
1502         free(ustr);
1503 }
1504
1505 static int
1506 lwt_print(FILE *f, cycles_t t0, cycles_t tlast, double mhz, int cpu, lwt_event_t *e)
1507 {
1508         char            whenstr[32];
1509         char           *where = lwt_get_string(e->lwte_where);
1510
1511         if (where == NULL)
1512                 return (-1);
1513
1514         sprintf(whenstr, LPD64, e->lwte_when - t0);
1515
1516         fprintf(f, "%#010lx %#010lx %#010lx %#010lx: %#010lx %1d %10.6f %10.2f %s\n",
1517                 e->lwte_p1, e->lwte_p2, e->lwte_p3, e->lwte_p4,
1518                 (long)e->lwte_task, cpu, (e->lwte_when - t0) / (mhz * 1000000.0),
1519                 (t0 == e->lwte_when) ? 0.0 : (e->lwte_when - tlast) / mhz,
1520                 where);
1521
1522         lwt_put_string(where);
1523
1524         return (0);
1525 }
1526
1527 double
1528 get_cycles_per_usec ()
1529 {
1530         FILE      *f = fopen ("/proc/cpuinfo", "r");
1531         double     mhz;
1532         char      line[64];
1533         
1534         if (f != NULL) {
1535                 while (fgets (line, sizeof (line), f) != NULL)
1536                         if (sscanf (line, "cpu MHz : %lf", &mhz) == 1) {
1537                                 fclose (f);
1538                                 return (mhz);
1539                         }
1540                 fclose (f);
1541         }
1542
1543         fprintf (stderr, "Can't read/parse /proc/cpuinfo\n");
1544         return (1000.0);
1545 }
1546
1547 int
1548 jt_ptl_lwt(int argc, char **argv)
1549 {
1550 #define MAX_CPUS 8
1551         int             ncpus;
1552         int             totalspace;
1553         int             nevents_per_cpu;
1554         lwt_event_t    *events;
1555         lwt_event_t    *cpu_event[MAX_CPUS + 1];
1556         lwt_event_t    *next_event[MAX_CPUS];
1557         lwt_event_t    *first_event[MAX_CPUS];
1558         int             cpu;
1559         lwt_event_t    *e;
1560         int             rc;
1561         int             i;
1562         double          mhz;
1563         cycles_t        t0;
1564         cycles_t        tlast;
1565         FILE           *f = stdout;
1566
1567         if (argc < 2 ||
1568             (strcmp(argv[1], "start") &&
1569              strcmp(argv[1], "stop"))) {
1570                 fprintf(stderr, 
1571                         "usage:  %s start\n"
1572                         "        %s stop [fname]\n", argv[0], argv[0]);
1573                 return (-1);
1574         }
1575         
1576         if (!strcmp(argv[1], "start")) {
1577                 /* disable */
1578                 if (lwt_control(0, 0) != 0)
1579                         return (-1);
1580
1581                 /* clear */
1582                 if (lwt_control(0, 1) != 0)
1583                         return (-1);
1584
1585                 /* enable */
1586                 if (lwt_control(1, 0) != 0)
1587                         return (-1);
1588
1589                 return (0);
1590         }
1591                 
1592         if (lwt_snapshot(&ncpus, &totalspace, NULL, 0) != 0)
1593                 return (-1);
1594
1595         if (ncpus > MAX_CPUS) {
1596                 fprintf(stderr, "Too many cpus: %d (%d)\n", ncpus, MAX_CPUS);
1597                 return (-1);
1598         }
1599
1600         events = (lwt_event_t *)malloc(totalspace);
1601         if (events == NULL) {
1602                 fprintf(stderr, "Can't allocate %d\n", totalspace);
1603                 return (-1);
1604         }
1605
1606         if (lwt_control(0, 0) != 0) {           /* disable */
1607                 free(events);
1608                 return (-1);
1609         }
1610
1611         if (lwt_snapshot(NULL, NULL, events, totalspace)) {
1612                 free(events);
1613                 return (-1);
1614         }
1615
1616         if (argc > 2) {
1617                 f = fopen (argv[2], "w");
1618                 if (f == NULL) {
1619                         fprintf(stderr, "Can't open %s for writing: %s\n", argv[2], strerror (errno));
1620                         free(events);
1621                         return (-1);
1622                 }
1623         }
1624
1625         mhz = get_cycles_per_usec();
1626         
1627         /* carve events into per-cpu slices */
1628         nevents_per_cpu = totalspace / (ncpus * sizeof(lwt_event_t));
1629         for (cpu = 0; cpu <= ncpus; cpu++)
1630                 cpu_event[cpu] = &events[cpu * nevents_per_cpu];
1631
1632         /* find the earliest event on each cpu */
1633         for (cpu = 0; cpu < ncpus; cpu++) {
1634                 first_event[cpu] = NULL;
1635
1636                 for (e = cpu_event[cpu]; e < cpu_event[cpu + 1]; e++) {
1637
1638                         if (e->lwte_where == NULL) /* not an event */
1639                                 continue;
1640
1641                         if (first_event[cpu] == NULL ||
1642                             first_event[cpu]->lwte_when > e->lwte_when)
1643                                 first_event[cpu] = e;
1644                 }
1645
1646                 next_event[cpu] = first_event[cpu];
1647         }
1648
1649         t0 = tlast = 0;
1650         for (cpu = 0; cpu < ncpus; cpu++) {
1651                 e = first_event[cpu];
1652                 if (e == NULL)                  /* no events this cpu */
1653                         continue;
1654                 
1655                 if (e == cpu_event[cpu])
1656                         e = cpu_event[cpu + 1] - 1;
1657                 else 
1658                         e = e - 1;
1659                 
1660                 /* If there's an event immediately before the first one, this
1661                  * cpu wrapped its event buffer */
1662                 if (e->lwte_where == NULL)
1663                         continue;
1664          
1665                 /* We should only start outputting events from the most recent
1666                  * first event in any wrapped cpu.  Events before this time on
1667                  * other cpus won't have any events from this CPU to interleave
1668                  * with. */
1669                 if (t0 < first_event[cpu]->lwte_when)
1670                         t0 = first_event[cpu]->lwte_when;
1671         }
1672
1673         for (;;) {
1674                 /* find which cpu has the next event */
1675                 cpu = -1;
1676                 for (i = 0; i < ncpus; i++) {
1677
1678                         if (next_event[i] == NULL) /* this cpu exhausted */
1679                                 continue;
1680
1681                         if (cpu < 0 ||
1682                             next_event[i]->lwte_when < next_event[cpu]->lwte_when)
1683                                 cpu = i;
1684                 }
1685
1686                 if (cpu < 0)                    /* all cpus exhausted */
1687                         break;
1688
1689                 if (t0 == 0) {
1690                         /* no wrapped cpus and this is he first ever event */
1691                         t0 = next_event[cpu]->lwte_when;
1692                 }
1693                 
1694                 if (t0 <= next_event[cpu]->lwte_when) {
1695                         /* on or after the first event */
1696                         rc = lwt_print(f, t0, tlast, mhz, cpu, next_event[cpu]);
1697                         if (rc != 0)
1698                                 break;
1699                 }
1700
1701                 tlast = next_event[cpu]->lwte_when;
1702                 
1703                 next_event[cpu]++;
1704                 if (next_event[cpu] == cpu_event[cpu + 1])
1705                         next_event[cpu] = cpu_event[cpu];
1706
1707                 if (next_event[cpu]->lwte_where == NULL ||
1708                     next_event[cpu] == first_event[cpu])
1709                         next_event[cpu] = NULL;
1710         }
1711
1712         if (f != stdout)
1713                 fclose(f);
1714
1715         free(events);
1716         return (0);
1717 #undef MAX_CPUS
1718 }