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