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