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