Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lnet / utils / lst.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  * 
4  * Author: Liang Zhen <liangzhen@clusterfs.com>
5  *
6  * This file is part of Lustre, http://www.lustre.org
7  */
8
9 #define _GNU_SOURCE
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <getopt.h>
15 #include <errno.h>
16 #include <pwd.h>
17 #include <lnet/lnetctl.h>
18 #include <lnet/lnetst.h>
19 #include "parser.h"
20
21 static command_t           lst_cmdlist[];
22 static lst_sid_t           session_id;
23 static int                 session_key; 
24 static lstcon_trans_stat_t trans_stat;
25
26 typedef struct list_string {
27         struct list_string *lstr_next;
28         int                 lstr_sz;
29         char                lstr_str[0];
30 } lstr_t;
31
32 #define offsetof(typ,memb)     ((unsigned long)((char *)&(((typ *)0)->memb)))
33
34 static int alloc_count = 0;
35 static int alloc_nob   = 0;
36
37 lstr_t *
38 alloc_lstr(int sz)
39 {
40         lstr_t  *lstr = malloc(offsetof(lstr_t, lstr_str[sz]));
41
42         if (lstr == NULL) {
43                 fprintf(stderr, "Can't allocate lstr\n");
44                 abort();
45         }
46
47         alloc_nob += sz;
48         alloc_count++;
49
50         lstr->lstr_str[0] = 0;
51         lstr->lstr_sz = sz;
52         return lstr;
53 }
54
55 void
56 free_lstr(lstr_t *lstr)
57 {
58         alloc_count--;
59         alloc_nob -= lstr->lstr_sz;
60         free(lstr);
61 }
62
63 void
64 free_lstrs(lstr_t **list)
65 {
66         lstr_t   *lstr;
67
68         while ((lstr = *list) != NULL) {
69                 *list = lstr->lstr_next;
70                 free_lstr(lstr);
71         }
72 }
73
74 void
75 new_lstrs(lstr_t **list, char *prefix, char *postfix,
76           int lo, int hi, int stride)
77 {
78         int    n1 = strlen(prefix);
79         int    n2 = strlen(postfix);
80         int    sz = n1 + 20 + n2 + 1;
81
82         do { 
83                 lstr_t *n = alloc_lstr(sz);
84
85                 snprintf(n->lstr_str, sz - 1, "%s%u%s",
86                          prefix, lo, postfix);
87
88                 n->lstr_next = *list;
89                 *list = n;
90
91                 lo += stride;
92         } while (lo <= hi);
93 }
94
95 int
96 expand_lstr(lstr_t **list, lstr_t *l)
97 {
98         int          nob = strlen(l->lstr_str);
99         char        *b1;
100         char        *b2;
101         char        *expr;
102         char        *sep;
103         int          x;
104         int          y;
105         int          z;
106         int          n; 
107
108         b1 = strchr(l->lstr_str, '[');  
109         if (b1 == NULL) {
110                 l->lstr_next = *list;
111                 *list = l;
112                 return 0;
113         }
114
115         b2 = strchr(b1, ']');
116         if (b2 == NULL || b2 == b1 + 1)
117                 return -1;
118
119         *b1++ = 0;
120         *b2++ = 0;
121         expr = b1;
122         do {
123
124                 sep = strchr(expr, ',');
125                 if (sep != NULL)
126                         *sep++ = 0;
127
128                 nob = strlen(expr);
129                 n = nob;
130                 if (sscanf(expr, "%u%n", &x, &n) >= 1 && n == nob) {
131                         /* simple number */
132                         new_lstrs(list, l->lstr_str, b2, x, x, 1);
133                         continue;
134                 }
135
136                 n = nob;
137                 if (sscanf(expr, "%u-%u%n", &x, &y, &n) >= 2 && n == nob &&
138                     x < y) {
139                         /* simple range */
140                         new_lstrs(list, l->lstr_str, b2, x, y, 1);
141                         continue;
142                 }
143
144                 n = nob;
145                 if (sscanf(expr, "%u-%u/%u%n", &x, &y, &z, &n) >= 3 && n == nob &&
146                     x < y) {
147                         /* strided range */
148                         new_lstrs(list, l->lstr_str, b2, x, y, z);
149                         continue;
150                 }
151
152                 /* syntax error */
153                 return -1;
154         } while ((expr = sep) != NULL);
155
156         free_lstr(l);
157
158         return 1;
159 }
160
161 int
162 expand_strs(char *str, lstr_t **head)
163 {
164         lstr_t  *list = NULL;
165         lstr_t  *nlist;
166         lstr_t  *l;
167         int      rc = 0;
168         int      expanded;
169
170         l = alloc_lstr(strlen(str) + 1);
171         memcpy(l->lstr_str, str, strlen(str) + 1);
172         l->lstr_next = NULL;
173         list = l;
174
175         do {
176                 expanded = 0;
177                 nlist = NULL;
178
179                 while ((l = list) != NULL) {
180                         list = l->lstr_next;
181
182                         rc = expand_lstr(&nlist, l);
183                         if (rc < 0) {
184                                 fprintf(stderr, "Syntax error in \"%s\"\n", str);
185                                 free_lstr(l);
186                                 break;
187                         }
188
189                         expanded |= rc > 0;
190                 }
191
192                 /* re-order onto 'list' */
193                 while ((l = nlist) != NULL) {
194                         nlist = l->lstr_next;
195                         l->lstr_next = list;
196                         list = l;
197                 }
198
199         } while (expanded && rc > 0);
200
201         if (rc >= 0) {
202                 *head = list;
203                 return 0;
204         }
205
206         while ((l = list) != NULL) {
207                 list = l->lstr_next;
208
209                 free_lstr(l);
210         }
211         return rc;
212 }
213
214 int
215 lst_parse_nids(char *str, int *countp, lnet_process_id_t **idspp)
216 {
217         lstr_t  *head = NULL;
218         lstr_t  *l;
219         int      c = 0;
220         int      i;
221         int      rc;
222
223         rc = expand_strs(str, &head);
224         if (rc != 0)
225                 goto out;
226
227         l = head;
228         while (l != NULL) {
229                 l = l->lstr_next;
230                 c++;
231         }
232
233         *idspp = malloc(c * sizeof(lnet_process_id_t));
234         if (*idspp == NULL) {
235                 fprintf(stderr, "Out of memory\n");
236                 rc = -1;
237         }
238
239         *countp = c;
240 out:
241         i = 0;
242         while ((l = head) != NULL) {
243                 head = l->lstr_next;
244
245                 if (rc == 0) {
246                         (*idspp)[i].nid = libcfs_str2nid(l->lstr_str);
247                         if ((*idspp)[i].nid == LNET_NID_ANY) {
248                                 fprintf(stderr, "Invalid nid: %s\n",
249                                         l->lstr_str);
250                                 rc = -1;
251                         }
252
253                         (*idspp)[i].pid = LUSTRE_LNET_PID;
254                         i++;
255                 }
256
257                 free_lstr(l);
258         }
259
260         if (rc == 0)
261                 return 0;
262
263         free(*idspp);
264         *idspp = NULL;
265
266         return rc;
267 }
268
269 char *
270 lst_node_state2str(int state)
271 {
272         if (state == LST_NODE_ACTIVE)
273                 return "Active";
274         if (state == LST_NODE_BUSY)
275                 return "Busy";
276         if (state == LST_NODE_DOWN)
277                 return "Down";
278
279         return "Unknown";
280 }
281
282 int
283 lst_node_str2state(char *str)
284 {
285         if (strcasecmp(str, "active") == 0)
286                 return LST_NODE_ACTIVE;
287         if (strcasecmp(str, "busy") == 0)
288                 return LST_NODE_BUSY;
289         if (strcasecmp(str, "down") == 0)
290                 return LST_NODE_DOWN;
291         if (strcasecmp(str, "unknown") == 0)
292                 return LST_NODE_UNKNOWN;
293         if (strcasecmp(str, "invalid") == 0)
294                 return (LST_NODE_UNKNOWN | LST_NODE_DOWN | LST_NODE_BUSY);
295
296         return -1;
297 }
298
299 char *
300 lst_test_type2name(int type)
301 {
302         if (type == LST_TEST_PING)
303                 return "ping";
304         if (type == LST_TEST_BULK)
305                 return "brw";
306
307         return "unknown";
308 }
309
310 int
311 lst_test_name2type(char *name)
312 {
313         if (strcasecmp(name, "ping") == 0)
314                 return LST_TEST_PING;
315         if (strcasecmp(name, "brw") == 0)
316                 return LST_TEST_BULK;
317
318         return -1;
319 }
320
321 void
322 lst_print_usage(char *cmd)
323 {
324         Parser_printhelp(cmd);
325 }
326
327 void
328 lst_print_error(char *sub, const char *def_format, ...)
329 {
330         va_list ap;
331
332         /* local error returned from kernel */
333         switch (errno) {
334         case ESRCH:
335                 fprintf(stderr, "No session exists\n");
336                 return;
337         case ESHUTDOWN:
338                 fprintf(stderr, "Session is shutting down\n");
339                 return;
340         case EACCES:
341                 fprintf(stderr, "Unmatched session key or not root\n");
342                 return;
343         case ENOENT:
344                 fprintf(stderr, "Can't find %s in current session\n", sub);
345                 return;
346         case EINVAL:
347                 fprintf(stderr, "Invalid parameters list in command line\n");
348                 return;
349         case EFAULT:
350                 fprintf(stderr, "Bad parameter address\n");
351                 return;
352         case EEXIST:
353                 fprintf(stderr, "%s already exists\n", sub);
354                 return;
355         default:
356                 va_start(ap, def_format);
357                 vfprintf(stderr, def_format, ap);
358                 va_end(ap);
359
360                 return;
361         }
362 }
363
364 void
365 lst_free_rpcent(struct list_head *head)
366 {
367         lstcon_rpc_ent_t *ent;
368
369         while (!list_empty(head)) {
370                 ent = list_entry(head->next, lstcon_rpc_ent_t, rpe_link);
371
372                 list_del(&ent->rpe_link);
373                 free(ent);
374         }
375 }
376
377 void
378 lst_reset_rpcent(struct list_head *head)
379 {
380         lstcon_rpc_ent_t *ent;
381
382         list_for_each_entry(ent, head, rpe_link) {
383                 ent->rpe_sid      = LST_INVALID_SID;
384                 ent->rpe_peer.nid = LNET_NID_ANY; 
385                 ent->rpe_peer.pid = LNET_PID_ANY;
386                 ent->rpe_rpc_errno = ent->rpe_fwk_errno = 0;
387         }
388 }
389
390 int
391 lst_alloc_rpcent(struct list_head *head, int count, int offset)
392 {
393         lstcon_rpc_ent_t *ent;
394         int               i;
395
396         for (i = 0; i < count; i++) {
397                 ent = malloc(offsetof(lstcon_rpc_ent_t, rpe_payload[offset]));
398                 if (ent == NULL) {
399                         lst_free_rpcent(head);
400                         return -1;
401                 }
402
403                 memset(ent, 0, offsetof(lstcon_rpc_ent_t, rpe_payload[offset]));
404
405                 ent->rpe_sid      = LST_INVALID_SID;
406                 ent->rpe_peer.nid = LNET_NID_ANY; 
407                 ent->rpe_peer.pid = LNET_PID_ANY;
408                 list_add(&ent->rpe_link, head);
409         }
410
411         return 0;
412 }
413
414 void
415 lst_print_transerr(struct list_head *head, char *optstr)
416 {
417         lstcon_rpc_ent_t  *ent;
418
419         list_for_each_entry(ent, head, rpe_link) {
420                 if (ent->rpe_rpc_errno == 0 && ent->rpe_fwk_errno == 0)
421                         continue;
422
423                 if (ent->rpe_rpc_errno != 0) {
424                         fprintf(stderr, "%s RPC failed on %s: %s\n",
425                                 optstr, libcfs_id2str(ent->rpe_peer),
426                                 strerror(ent->rpe_rpc_errno));
427                         continue;
428                 }
429
430                 fprintf(stderr, "%s failed on %s: %s\n", 
431                         optstr, libcfs_id2str(ent->rpe_peer),
432                         strerror(ent->rpe_fwk_errno));
433         }
434 }
435
436 int lst_info_batch_ioctl(char *batch, int test, int server,
437                         lstcon_test_batch_ent_t *entp, int *idxp,
438                         int *ndentp, lstcon_node_ent_t *dentsp);
439
440 int lst_info_group_ioctl(char *name, lstcon_ndlist_ent_t *gent,
441                          int *idx, int *count, lstcon_node_ent_t *dents);
442
443 int lst_query_batch_ioctl(char *batch, int test, int server,
444                           int timeout, struct list_head *head);
445
446 int
447 lst_ioctl(unsigned int opc, void *buf, int len)
448 {
449         struct libcfs_ioctl_data data;
450         int    rc;
451
452         LIBCFS_IOC_INIT (data);
453         data.ioc_u32[0]  = opc;
454         data.ioc_plen1   = len;
455         data.ioc_pbuf1   = (char *)buf;
456         data.ioc_plen2   = sizeof(trans_stat);
457         data.ioc_pbuf2   = (char *)&trans_stat;
458
459         memset(&trans_stat, 0, sizeof(trans_stat));
460
461         rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_LNETST, &data);
462
463         /* local error, no valid RPC result */
464         if (rc != 0)
465                 return -1;
466
467         /* RPC error */
468         if (trans_stat.trs_rpc_errno != 0)
469                 return -2;
470
471         /* Framework error */
472         if (trans_stat.trs_fwk_errno != 0)
473                 return -3;
474
475         return 0;
476 }
477
478 int
479 lst_new_session_ioctl (char *name, int timeout, int force, lst_sid_t *sid)
480 {
481         lstio_session_new_args_t        args = {
482                 .lstio_ses_key          = session_key,
483                 .lstio_ses_timeout      = timeout,
484                 .lstio_ses_force        = force,
485                 .lstio_ses_idp          = sid,
486                 .lstio_ses_namep        = name,
487                 .lstio_ses_nmlen        = strlen(name),
488         };
489
490         return lst_ioctl (LSTIO_SESSION_NEW, &args, sizeof(args));
491 }
492
493 int
494 jt_lst_new_session(int argc,  char **argv)
495 {
496         char  buf[LST_NAME_SIZE];
497         char *name;
498         int   optidx  = 0;
499         int   timeout = 300;
500         int   force   = 0;
501         int   c;
502         int   rc;
503
504         static struct option session_opts[] =
505         {
506                 {"timeout", required_argument,  0, 't' },
507                 {"force",   no_argument,        0, 'f' },
508                 {0,         0,                  0,  0  }
509         };
510
511         if (session_key == 0) {
512                 fprintf(stderr,
513                         "Can't find env LST_SESSION or value is not valid\n");
514                 return -1;
515         }
516
517         while (1) {
518
519                 c = getopt_long(argc, argv, "ft:",
520                                 session_opts, &optidx);
521
522                 if (c == -1)
523                         break;
524         
525                 switch (c) {
526                 case 'f':
527                         force = 1;
528                         break;
529                 case 't':
530                         timeout = atoi(optarg);
531                         break;
532                 default:
533                         lst_print_usage(argv[0]);
534                         return -1;
535                 }
536         }
537
538         if (timeout <= 0) {
539                 fprintf(stderr, "Invalid timeout value\n");
540                 return -1;
541         }
542
543         if (optind == argc - 1) {
544                 name = argv[optind ++];
545                 if (strlen(name) >= LST_NAME_SIZE) {
546                         fprintf(stderr, "Name size is limited to %d\n",
547                                 LST_NAME_SIZE - 1);
548                         return -1;
549                 }
550
551         } else if (optind == argc) {
552                 char           user[LST_NAME_SIZE];
553                 char           host[LST_NAME_SIZE];
554                 struct passwd *pw = getpwuid(getuid());
555
556                 if (pw == NULL)
557                         snprintf(user, sizeof(user), "%d", (int)getuid());
558                 else
559                         snprintf(user, sizeof(user), "%s", pw->pw_name);
560
561                 rc = gethostname(host, sizeof(host));
562                 if (rc != 0)
563                         snprintf(host, sizeof(host), "unknown_host");
564
565                 snprintf(buf, LST_NAME_SIZE, "%s@%s", user, host);
566                 name = buf;
567
568         } else { 
569                 lst_print_usage(argv[0]);
570                 return -1;
571         }
572
573         rc = lst_new_session_ioctl(name, timeout, force, &session_id);
574
575         if (rc != 0) {
576                 lst_print_error("session", "Failed to create session: %s\n",
577                                 strerror(errno));
578                 return rc;
579         }
580
581         fprintf(stdout, "SESSION: %s TIMEOUT: %d FORCE: %s\n",
582                 name, timeout, force ? "Yes": "No");
583
584         return rc;
585 }
586
587 int
588 lst_session_info_ioctl(char *name, int len, int *key,
589                        lst_sid_t *sid, lstcon_ndlist_ent_t *ndinfo)
590 {
591         lstio_session_info_args_t args = {
592                 .lstio_ses_keyp         = key,
593                 .lstio_ses_idp          = sid,
594                 .lstio_ses_ndinfo       = ndinfo,
595                 .lstio_ses_nmlen        = len,
596                 .lstio_ses_namep        = name,
597         };
598
599         return lst_ioctl(LSTIO_SESSION_INFO, &args, sizeof(args));
600 }
601
602 int
603 jt_lst_show_session(int argc, char **argv)
604 {
605         lstcon_ndlist_ent_t ndinfo;
606         lst_sid_t           sid;
607         char                name[LST_NAME_SIZE];
608         int                 key;
609         int                 rc;
610
611         rc = lst_session_info_ioctl(name, LST_NAME_SIZE, &key, &sid, &ndinfo);
612
613         if (rc != 0) {
614                 lst_print_error("session", "Failed to show session: %s\n",
615                                 strerror(errno));
616                 return -1;
617         }
618
619         fprintf(stdout, "%s ID: %Lu@%s, KEY: %d NODES: %d\n",
620                 name, sid.ses_stamp, libcfs_nid2str(sid.ses_nid),
621                 key, ndinfo.nle_nnode);
622
623         return 0;
624 }
625
626 int
627 lst_end_session_ioctl(void)
628 {
629         lstio_session_end_args_t args = {
630                 .lstio_ses_key           = session_key,
631         };
632
633         return lst_ioctl (LSTIO_SESSION_END, &args, sizeof(args));
634 }
635
636 int
637 jt_lst_end_session(int argc, char **argv)
638 {
639         int             rc;
640
641         if (session_key == 0) {
642                 fprintf(stderr,
643                         "Can't find env LST_SESSION or value is not valid\n");
644                 return -1;
645         }
646
647         rc = lst_end_session_ioctl();
648
649         if (rc == 0) {
650                 fprintf(stdout, "session is ended\n");
651                 return 0;
652         }
653
654         if (rc == -1) {
655                 lst_print_error("session", "Failed to end session: %s\n",
656                                 strerror(errno));
657                 return rc;
658         }
659
660         if (trans_stat.trs_rpc_errno != 0) {
661                 fprintf(stderr,
662                         "[RPC] Failed to send %d session RPCs: %s\n",
663                         lstcon_rpc_stat_failure(&trans_stat, 0),
664                         strerror(trans_stat.trs_rpc_errno));
665         }
666
667         if (trans_stat.trs_fwk_errno != 0) {
668                 fprintf(stderr,
669                         "[FWK] Failed to end session on %d nodes: %s\n",
670                         lstcon_sesop_stat_failure(&trans_stat, 0),
671                         strerror(trans_stat.trs_fwk_errno));
672         }
673
674         return rc;
675 }
676
677 int
678 lst_ping_ioctl(char *str, int type, int timeout, 
679                int count, lnet_process_id_t *ids, struct list_head *head)
680 {
681         lstio_debug_args_t args = {
682                 .lstio_dbg_key          = session_key,
683                 .lstio_dbg_type         = type,
684                 .lstio_dbg_flags        = 0,
685                 .lstio_dbg_timeout      = timeout,
686                 .lstio_dbg_nmlen        = (str == NULL) ? 0: strlen(str),
687                 .lstio_dbg_namep        = str,
688                 .lstio_dbg_count        = count,
689                 .lstio_dbg_idsp         = ids,
690                 .lstio_dbg_resultp      = head,
691         };
692
693         return lst_ioctl (LSTIO_DEBUG, &args, sizeof(args));
694 }
695
696 int
697 lst_get_node_count(int type, char *str, int *countp, lnet_process_id_t **idspp)
698 {
699         char                    buf[LST_NAME_SIZE];
700         lstcon_test_batch_ent_t ent;
701         lstcon_ndlist_ent_t    *entp = &ent.tbe_cli_nle;
702         lst_sid_t               sid;
703         int                     key;
704         int                     rc;
705
706         switch (type) {
707         case LST_OPC_SESSION:
708                 rc = lst_session_info_ioctl(buf, LST_NAME_SIZE,
709                                             &key, &sid, entp);
710                 break;
711
712         case LST_OPC_BATCHSRV:
713                 entp = &ent.tbe_srv_nle;
714         case LST_OPC_BATCHCLI:
715                 rc = lst_info_batch_ioctl(str, 0, 0, &ent, NULL, NULL, NULL);
716                 break;
717                 
718         case LST_OPC_GROUP:
719                 rc = lst_info_group_ioctl(str, entp, NULL, NULL, NULL);
720                 break;
721
722         case LST_OPC_NODES:
723                 rc = lst_parse_nids(str, &entp->nle_nnode, idspp) < 0 ? -1 : 0;
724                 break;
725
726         default:
727                 rc = -1;
728                 break;
729         }
730
731         if (rc == 0) 
732                 *countp = entp->nle_nnode;
733
734         return rc;
735 }
736
737 int
738 jt_lst_ping(int argc,  char **argv)
739 {
740         struct list_head   head;
741         lnet_process_id_t *ids = NULL;
742         lstcon_rpc_ent_t  *ent = NULL;
743         char              *str = NULL;
744         int                optidx  = 0;
745         int                server  = 0;
746         int                timeout = 5;
747         int                count   = 0;
748         int                type    = 0;
749         int                rc      = 0;
750         int                c;
751
752         static struct option ping_opts[] =
753         {
754                 {"session", no_argument,       0, 's' },
755                 {"server",  no_argument,       0, 'v' },
756                 {"batch",   required_argument, 0, 'b' },
757                 {"group",   required_argument, 0, 'g' },
758                 {"nodes",   required_argument, 0, 'n' },
759                 {"timeout", required_argument, 0, 't' },
760                 {0,         0,                 0,  0  }
761         };
762
763         if (session_key == 0) {
764                 fprintf(stderr,
765                         "Can't find env LST_SESSION or value is not valid\n");
766                 return -1;
767         }
768
769         while (1) {
770
771                 c = getopt_long(argc, argv, "g:b:n:t:sv",
772                                 ping_opts, &optidx);
773
774                 if (c == -1)
775                         break;
776         
777                 switch (c) {
778                 case 's':
779                         type = LST_OPC_SESSION;
780                         break;
781
782                 case 'g':
783                         type = LST_OPC_GROUP;
784                         str = optarg;
785                         break;
786
787                 case 'b':
788                         type = LST_OPC_BATCHCLI;
789                         str = optarg;
790                         break;
791
792                 case 'n':
793                         type = LST_OPC_NODES;
794                         str = optarg;
795                         break;
796
797                 case 't':
798                         timeout = atoi(optarg);
799                         break;
800
801                 case 'v':
802                         server = 1;
803                         break;
804
805                 default:
806                         lst_print_usage(argv[0]);
807                         return -1;
808                 }
809         }
810
811         if (type == 0 || timeout <= 0 || optind != argc) {
812                 lst_print_usage(argv[0]);
813                 return -1;
814         }
815
816         if (type == LST_OPC_BATCHCLI && server)
817                 type = LST_OPC_BATCHSRV;
818
819         rc = lst_get_node_count(type, str, &count, &ids);
820         if (rc < 0) {
821                 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
822                         (str == NULL) ? "session" : str, strerror(errno));
823                 return -1;
824         }
825
826         CFS_INIT_LIST_HEAD(&head);
827
828         rc = lst_alloc_rpcent(&head, count, LST_NAME_SIZE);
829         if (rc != 0) {
830                 fprintf(stderr, "Out of memory\n");
831                 goto out;
832         }
833
834         if (count == 0) {
835                 fprintf(stdout, "Target %s is empty\n",
836                         (str == NULL) ? "session" : str);
837                 goto out;
838         }
839
840         rc = lst_ping_ioctl(str, type, timeout, count, ids, &head);
841         if (rc == -1) { /* local failure */
842                 lst_print_error("debug", "Failed to ping %s: %s\n",
843                                 (str == NULL) ? "session" : str,
844                                 strerror(errno));
845                 rc = -1;
846                 goto out;
847         }
848
849         /* ignore RPC errors and framwork errors */
850         list_for_each_entry(ent, &head, rpe_link) {
851                 fprintf(stdout, "\t%s: %s [session: %s id: %s]\n",
852                         libcfs_id2str(ent->rpe_peer),
853                         lst_node_state2str(ent->rpe_state),
854                         (ent->rpe_state == LST_NODE_ACTIVE ||
855                          ent->rpe_state == LST_NODE_BUSY)?
856                                  (ent->rpe_rpc_errno == 0 ?
857                                          &ent->rpe_payload[0] : "Unknown") :
858                                  "<NULL>", libcfs_nid2str(ent->rpe_sid.ses_nid));
859         }
860
861 out:
862         lst_free_rpcent(&head);
863
864         if (ids != NULL)
865                 free(ids);
866
867         return rc;
868                 
869 }
870
871 int
872 lst_add_nodes_ioctl (char *name, int count, lnet_process_id_t *ids,
873                      struct list_head *resultp)
874 {       
875         lstio_group_nodes_args_t        args = {
876                 .lstio_grp_key          = session_key,
877                 .lstio_grp_nmlen        = strlen(name),
878                 .lstio_grp_namep        = name,
879                 .lstio_grp_count        = count,
880                 .lstio_grp_idsp         = ids,
881                 .lstio_grp_resultp      = resultp,
882         };
883
884         return lst_ioctl(LSTIO_NODES_ADD, &args, sizeof(args));
885 }
886
887 int
888 lst_add_group_ioctl (char *name)
889 {
890         lstio_group_add_args_t  args = {
891                 .lstio_grp_key          = session_key,
892                 .lstio_grp_nmlen        = strlen(name),
893                 .lstio_grp_namep        = name,
894         };
895
896         return lst_ioctl(LSTIO_GROUP_ADD, &args, sizeof(args));
897 }
898
899 int
900 jt_lst_add_group(int argc, char **argv)
901 {
902         struct list_head   head;
903         lnet_process_id_t *ids;
904         char              *name;
905         int                count;
906         int                rc;
907         int                i;
908
909         if (session_key == 0) {
910                 fprintf(stderr,
911                         "Can't find env LST_SESSION or value is not valid\n");
912                 return -1;
913         }
914
915         if (argc < 3) {
916                 lst_print_usage(argv[0]);
917                 return -1;
918         }
919
920         name = argv[1];
921         if (strlen(name) >= LST_NAME_SIZE) {
922                 fprintf(stderr, "Name length is limited to %d\n",
923                         LST_NAME_SIZE - 1);
924                 return -1;
925         }
926
927         rc = lst_add_group_ioctl(name);
928         if (rc != 0) {
929                 lst_print_error("group", "Failed to add group %s: %s\n",
930                                 name, strerror(errno));
931                 return -1;
932         }
933
934         CFS_INIT_LIST_HEAD(&head);
935
936         for (i = 2; i < argc; i++) {
937                 /* parse address list */
938                 rc = lst_parse_nids(argv[i], &count, &ids);
939                 if (rc < 0) {
940                         fprintf(stderr, "Ignore invalid id list %s\n",
941                                 argv[i]);
942                         continue;
943                 }
944
945                 if (count == 0)
946                         continue;
947
948                 rc = lst_alloc_rpcent(&head, count, 0);
949                 if (rc != 0) {
950                         fprintf(stderr, "Out of memory\n");
951                         break;
952                 }
953
954                 rc = lst_add_nodes_ioctl(name, count, ids, &head);
955
956                 free(ids);
957
958                 if (rc == 0) {
959                         lst_free_rpcent(&head);
960                         fprintf(stderr, "%s are added to session\n", argv[i]);
961                         continue;
962                 }
963
964                 if (rc == -1) {
965                         lst_free_rpcent(&head);
966                         lst_print_error("group", "Failed to add nodes %s: %s\n",
967                                         argv[i], strerror(errno));
968                         break;
969                 }
970
971                 lst_print_transerr(&head, "create session");
972                 lst_free_rpcent(&head);
973         }
974
975         return rc;
976 }
977
978 int
979 lst_del_group_ioctl (char *name)
980 {
981         lstio_group_del_args_t  args = {
982                 .lstio_grp_key          = session_key,
983                 .lstio_grp_nmlen        = strlen(name),
984                 .lstio_grp_namep        = name,
985         };
986
987         return lst_ioctl(LSTIO_GROUP_DEL, &args, sizeof(args));
988 }
989
990 int
991 jt_lst_del_group(int argc, char **argv)
992 {
993         int     rc;
994
995         if (session_key == 0) {
996                 fprintf(stderr,
997                         "Can't find env LST_SESSION or value is not valid\n");
998                 return -1;
999         }
1000
1001         if (argc != 2) {
1002                 lst_print_usage(argv[0]);
1003                 return -1;
1004         }
1005
1006         rc = lst_del_group_ioctl(argv[1]);
1007         if (rc == 0) {
1008                 fprintf(stdout, "Group is deleted\n");
1009                 return 0;
1010         }
1011
1012         if (rc == -1) {
1013                 lst_print_error("group", "Failed to delete group: %s\n",
1014                                 strerror(errno));
1015                 return rc;
1016         }
1017
1018         fprintf(stderr, "Group is deleted with some errors\n");
1019
1020         if (trans_stat.trs_rpc_errno != 0) {
1021                 fprintf(stderr, "[RPC] Failed to send %d end session RPCs: %s\n",
1022                         lstcon_rpc_stat_failure(&trans_stat, 0), 
1023                         strerror(trans_stat.trs_rpc_errno));
1024         }
1025
1026         if (trans_stat.trs_fwk_errno != 0) {
1027                 fprintf(stderr,
1028                         "[FWK] Failed to end session on %d nodes: %s\n",
1029                         lstcon_sesop_stat_failure(&trans_stat, 0),
1030                         strerror(trans_stat.trs_fwk_errno));
1031         }
1032
1033         return -1;
1034 }
1035
1036 int
1037 lst_update_group_ioctl(int opc, char *name, int clean, int count,
1038                        lnet_process_id_t *ids, struct list_head *resultp)
1039 {
1040         lstio_group_update_args_t  args = {
1041                 .lstio_grp_key          = session_key,
1042                 .lstio_grp_opc          = opc,
1043                 .lstio_grp_args         = clean,
1044                 .lstio_grp_nmlen        = strlen(name),
1045                 .lstio_grp_namep        = name,
1046                 .lstio_grp_count        = count,
1047                 .lstio_grp_idsp         = ids,
1048                 .lstio_grp_resultp      = resultp,
1049         };
1050
1051         return lst_ioctl(LSTIO_GROUP_UPDATE, &args, sizeof(args));
1052 }
1053
1054 int
1055 jt_lst_update_group(int argc, char **argv)
1056 {
1057         struct list_head   head;
1058         lnet_process_id_t *ids = NULL;
1059         char              *str = NULL;
1060         char              *grp = NULL;
1061         int                optidx = 0;
1062         int                count = 0;
1063         int                clean = 0;
1064         int                opc = 0;
1065         int                rc;
1066         int                c;
1067
1068         static struct option update_group_opts[] =
1069         {
1070                 {"refresh", no_argument,       0, 'f' },
1071                 {"clean",   required_argument, 0, 'c' },
1072                 {"remove",  required_argument, 0, 'r' },
1073                 {0,         0,                 0,  0  }
1074         };
1075
1076         if (session_key == 0) {
1077                 fprintf(stderr,
1078                         "Can't find env LST_SESSION or value is not valid\n");
1079                 return -1;
1080         }
1081
1082         while (1) {
1083                 c = getopt_long(argc, argv, "fc:r:",
1084                                 update_group_opts, &optidx);
1085
1086                 /* Detect the end of the options. */
1087                 if (c == -1)
1088                         break;
1089         
1090                 switch (c) {
1091                 case 'f':
1092                         if (opc != 0) {
1093                                 lst_print_usage(argv[0]);
1094                                 return -1;
1095                         }
1096                         opc = LST_GROUP_REFRESH;
1097                         break;
1098
1099                 case 'r':
1100                         if (opc != 0) {
1101                                 lst_print_usage(argv[0]);
1102                                 return -1;
1103                         }
1104                         opc = LST_GROUP_RMND;
1105                         str = optarg;
1106                         break;
1107
1108                 case 'c':
1109                         clean = lst_node_str2state(optarg);
1110                         if (opc != 0 || clean <= 0) {
1111                                 lst_print_usage(argv[0]);
1112                                 return -1;
1113                         }
1114                         opc = LST_GROUP_CLEAN;
1115                         break;
1116
1117                 default:
1118                         lst_print_usage(argv[0]);
1119                         return -1;
1120                 }
1121         }
1122
1123         /* no OPC or group is specified */
1124         if (opc == 0 || optind != argc - 1) {
1125                 lst_print_usage(argv[0]);
1126                 return -1;
1127         }
1128
1129         grp = argv[optind];
1130
1131         CFS_INIT_LIST_HEAD(&head);
1132
1133         if (opc == LST_GROUP_RMND || opc == LST_GROUP_REFRESH) {
1134                 rc = lst_get_node_count(opc == LST_GROUP_RMND ? LST_OPC_NODES :
1135                                                                 LST_OPC_GROUP,
1136                                         opc == LST_GROUP_RMND ? str : grp,
1137                                         &count, &ids);
1138
1139                 if (rc != 0) {
1140                         fprintf(stderr, "Can't get count of nodes from %s: %s\n",
1141                                 opc == LST_GROUP_RMND ? str : grp,
1142                                 strerror(errno));
1143                         return -1;
1144                 }
1145
1146                 rc = lst_alloc_rpcent(&head, count, 0);
1147                 if (rc != 0) {
1148                         fprintf(stderr, "Out of memory\n");
1149                         free(ids);
1150                         return -1;
1151                 }
1152
1153         } 
1154
1155         rc = lst_update_group_ioctl(opc, grp, clean, count, ids, &head);
1156
1157         if (ids != NULL)
1158                 free(ids);
1159
1160         if (rc == 0) {
1161                 lst_free_rpcent(&head);
1162                 return 0;
1163         }
1164
1165         if (rc == -1) {
1166                 lst_free_rpcent(&head);
1167                 lst_print_error("group", "Failed to update group: %s\n",
1168                                 strerror(errno));
1169                 return rc;
1170         }
1171
1172         lst_print_transerr(&head, "Updating group");
1173
1174         lst_free_rpcent(&head);
1175
1176         return rc;
1177 }
1178
1179 int
1180 lst_list_group_ioctl(int len, char *name, int idx)
1181 {
1182         lstio_group_list_args_t         args = {
1183                 .lstio_grp_key          = session_key,
1184                 .lstio_grp_idx          = idx,
1185                 .lstio_grp_nmlen        = len,
1186                 .lstio_grp_namep        = name,
1187         };
1188
1189         return lst_ioctl(LSTIO_GROUP_LIST, &args, sizeof(args));
1190 }
1191
1192 int
1193 lst_info_group_ioctl(char *name, lstcon_ndlist_ent_t *gent,
1194                      int *idx, int *count, lstcon_node_ent_t *dents)
1195 {
1196         lstio_group_info_args_t         args = {
1197                 .lstio_grp_key          = session_key,
1198                 .lstio_grp_nmlen        = strlen(name),
1199                 .lstio_grp_namep        = name,
1200                 .lstio_grp_entp         = gent,
1201                 .lstio_grp_idxp         = idx,
1202                 .lstio_grp_ndentp       = count,
1203                 .lstio_grp_dentsp       = dents,
1204         };
1205
1206         return lst_ioctl(LSTIO_GROUP_INFO, &args, sizeof(args));
1207 }
1208
1209 int
1210 lst_list_group_all(void)
1211 {
1212         char  name[LST_NAME_SIZE];
1213         int   rc;
1214         int   i;
1215
1216         /* no group is specified, list name of all groups */
1217         for (i = 0; ; i++) {
1218                 rc = lst_list_group_ioctl(LST_NAME_SIZE, name, i);
1219                 if (rc == 0) {
1220                         fprintf(stdout, "%d) %s\n", i + 1, name);
1221                         continue;
1222                 }
1223
1224                 if (errno == ENOENT) 
1225                         break;
1226
1227                 lst_print_error("group", "Failed to list group: %s\n",
1228                                 strerror(errno));
1229                 return -1;
1230         }
1231
1232         fprintf(stdout, "Total %d groups\n", i);
1233
1234         return 0;
1235 }
1236
1237 #define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
1238
1239 int
1240 jt_lst_list_group(int argc, char **argv)
1241 {
1242         lstcon_ndlist_ent_t  gent;
1243         lstcon_node_ent_t   *dents;
1244         int               optidx  = 0;
1245         int               verbose = 0;
1246         int               active  = 0;
1247         int               busy    = 0;
1248         int               down    = 0;
1249         int               unknown = 0;
1250         int               all     = 0;
1251         int               count;
1252         int               index;
1253         int               i;
1254         int               j;
1255         int               c;
1256         int               rc = 0;
1257
1258         static struct option list_group_opts[] =
1259         {
1260                 {"active",  no_argument, 0, 'a' },
1261                 {"busy",    no_argument, 0, 'b' },
1262                 {"down",    no_argument, 0, 'd' },
1263                 {"unknown", no_argument, 0, 'u' },
1264                 {"all",     no_argument, 0, 'l' },
1265                 {0,         0,           0,  0  }
1266         };
1267
1268         if (session_key == 0) {
1269                 fprintf(stderr,
1270                         "Can't find env LST_SESSION or value is not valid\n");
1271                 return -1;
1272         }
1273
1274         while (1) {
1275                 c = getopt_long(argc, argv, "abdul",
1276                                 list_group_opts, &optidx);
1277
1278                 if (c == -1)
1279                         break;
1280         
1281                 switch (c) {
1282                 case 'a':
1283                         verbose = active = 1;
1284                         all = 0;
1285                         break;
1286                 case 'b':
1287                         verbose = busy = 1;
1288                         all = 0;
1289                         break;
1290                 case 'd':
1291                         verbose = down = 1;
1292                         all = 0;
1293                         break;
1294                 case 'u':
1295                         verbose = unknown = 1;
1296                         all = 0;
1297                         break;
1298                 case 'l':
1299                         verbose = all = 1;
1300                         break;
1301                 default:
1302                         lst_print_usage(argv[0]);
1303                         return -1;
1304                 }
1305         }
1306
1307         if (optind == argc) {
1308                 /* no group is specified, list name of all groups */
1309                 rc = lst_list_group_all();
1310
1311                 return rc;
1312         }
1313
1314         if (!verbose)
1315                 fprintf(stdout, LST_NODES_TITLE);
1316
1317         /* list nodes in specified groups */
1318         for (i = optind; i < argc; i++) {
1319                 rc = lst_info_group_ioctl(argv[i], &gent, NULL, NULL, NULL);
1320                 if (rc != 0) {
1321                         if (errno == ENOENT) {
1322                                 rc = 0;
1323                                 break;
1324                         }
1325
1326                         lst_print_error("group", "Failed to list group\n",
1327                                         strerror(errno));
1328                         break;
1329                 }
1330
1331                 if (!verbose) {
1332                         fprintf(stdout, "\t%d\t%d\t%d\t%d\t%d\t%s\n",
1333                                 gent.nle_nactive, gent.nle_nbusy,
1334                                 gent.nle_ndown, gent.nle_nunknown,
1335                                 gent.nle_nnode, argv[i]);
1336                         continue;
1337                 }
1338
1339                 fprintf(stdout, "Group [ %s ]\n", argv[i]);
1340
1341                 if (gent.nle_nnode == 0) {
1342                         fprintf(stdout, "No nodes found [ %s ]\n", argv[i]);
1343                         continue;
1344                 }
1345
1346                 count = gent.nle_nnode;
1347
1348                 dents = malloc(count * sizeof(lstcon_node_ent_t));
1349                 if (dents == NULL) {
1350                         fprintf(stderr, "Failed to malloc: %s\n",
1351                                 strerror(errno));
1352                         return -1;
1353                 }
1354
1355                 index = 0;
1356                 rc = lst_info_group_ioctl(argv[i], &gent, &index, &count, dents);
1357                 if (rc != 0) {
1358                         lst_print_error("group", "Failed to list group: %s\n",
1359                                         strerror(errno));
1360                         free(dents);
1361                         return -1;
1362                 }
1363
1364                 for (j = 0, c = 0; j < count; j++) {
1365                         if (all ||
1366                             ((active  &&  dents[j].nde_state == LST_NODE_ACTIVE) ||
1367                              (busy    &&  dents[j].nde_state == LST_NODE_BUSY)   ||
1368                              (down    &&  dents[j].nde_state == LST_NODE_DOWN)   ||
1369                              (unknown &&  dents[j].nde_state == LST_NODE_UNKNOWN))) {
1370
1371                                 fprintf(stdout, "\t%s: %s\n",
1372                                         libcfs_id2str(dents[j].nde_id),
1373                                         lst_node_state2str(dents[j].nde_state));
1374                                 c++;
1375                         }
1376                 }
1377
1378                 fprintf(stdout, "Total %d nodes [ %s ]\n", c, argv[i]);
1379
1380                 free(dents);
1381         }
1382
1383         return rc;
1384 }
1385
1386 int
1387 lst_stat_ioctl (char *name, int count, lnet_process_id_t *idsp,
1388                 int timeout, struct list_head *resultp)
1389 {
1390         lstio_stat_args_t  args = {
1391                 .lstio_sta_key           = session_key,
1392                 .lstio_sta_timeout       = timeout,
1393                 .lstio_sta_nmlen         = strlen(name),
1394                 .lstio_sta_namep         = name,
1395                 .lstio_sta_count         = count,
1396                 .lstio_sta_idsp          = idsp,
1397                 .lstio_sta_resultp       = resultp,
1398         };
1399
1400         return lst_ioctl (LSTIO_STAT_QUERY, &args, sizeof(args));
1401 }
1402
1403 typedef struct {
1404         struct list_head        srp_link;
1405         int                     srp_count;
1406         char                   *srp_name;
1407         lnet_process_id_t      *srp_ids;
1408         struct list_head        srp_result[2];
1409 } lst_stat_req_param_t;
1410
1411 static void
1412 lst_stat_req_param_free(lst_stat_req_param_t *srp)
1413 {
1414         int     i;
1415
1416         for (i = 0; i < 2; i++) 
1417                 lst_free_rpcent(&srp->srp_result[i]);
1418
1419         if (srp->srp_ids != NULL)
1420                 free(srp->srp_ids);
1421
1422         free(srp);
1423 }
1424
1425 static int
1426 lst_stat_req_param_alloc(char *name, lst_stat_req_param_t **srpp, int save_old)
1427 {
1428         lst_stat_req_param_t *srp = NULL;
1429         int                   count = save_old ? 2 : 1;
1430         int                   rc;
1431         int                   i;
1432
1433         srp = malloc(sizeof(*srp));
1434         if (srp == NULL)
1435                 return -ENOMEM;
1436
1437         memset(srp, 0, sizeof(*srp));
1438         CFS_INIT_LIST_HEAD(&srp->srp_result[0]);
1439         CFS_INIT_LIST_HEAD(&srp->srp_result[1]);
1440
1441         rc = lst_get_node_count(LST_OPC_GROUP, name,
1442                                 &srp->srp_count, NULL);
1443         if (rc != 0 && errno == ENOENT) {
1444                 rc = lst_get_node_count(LST_OPC_NODES, name,
1445                                         &srp->srp_count, &srp->srp_ids);
1446         }
1447
1448         if (rc != 0) {
1449                 fprintf(stderr,
1450                         "Failed to get count of nodes from %s: %s\n",
1451                         name, strerror(errno));
1452                 lst_stat_req_param_free(srp);
1453
1454                 return rc;
1455         }
1456
1457         srp->srp_name = name;
1458
1459         for (i = 0; i < count; i++) {
1460                 rc = lst_alloc_rpcent(&srp->srp_result[i], srp->srp_count,
1461                                       sizeof(sfw_counters_t)  +
1462                                       sizeof(srpc_counters_t) +
1463                                       sizeof(lnet_counters_t));
1464                 if (rc != 0) {
1465                         fprintf(stderr, "Out of memory\n");
1466                         break;
1467                 }
1468         }
1469
1470         if (rc == 0) {
1471                 *srpp = srp;
1472                 return 0;
1473         }
1474
1475         lst_stat_req_param_free(srp);
1476
1477         return rc;
1478 }
1479
1480 typedef struct {
1481         /* TODO */
1482 } lst_srpc_stat_result;
1483
1484 #define LST_LNET_AVG    0
1485 #define LST_LNET_MIN    1
1486 #define LST_LNET_MAX    2
1487
1488 typedef struct {
1489         float           lnet_avg_sndrate;
1490         float           lnet_min_sndrate;
1491         float           lnet_max_sndrate;
1492         float           lnet_total_sndrate;
1493
1494         float           lnet_avg_rcvrate;
1495         float           lnet_min_rcvrate;
1496         float           lnet_max_rcvrate;
1497         float           lnet_total_rcvrate;
1498
1499         float           lnet_avg_sndperf;
1500         float           lnet_min_sndperf;
1501         float           lnet_max_sndperf;
1502         float           lnet_total_sndperf;
1503
1504         float           lnet_avg_rcvperf;
1505         float           lnet_min_rcvperf;
1506         float           lnet_max_rcvperf;
1507         float           lnet_total_rcvperf;
1508
1509         int             lnet_stat_count;
1510 } lst_lnet_stat_result_t;
1511
1512 lst_lnet_stat_result_t lnet_stat_result;
1513
1514 static float
1515 lst_lnet_stat_value(int bw, int send, int off)
1516 {
1517         float  *p;
1518
1519         p = bw ? &lnet_stat_result.lnet_avg_sndperf :
1520                  &lnet_stat_result.lnet_avg_sndrate;
1521
1522         if (!send)
1523                 p += 4; 
1524
1525         p += off;
1526
1527         return *p;
1528 }
1529
1530 static void
1531 lst_timeval_diff(struct timeval *tv1,
1532                  struct timeval *tv2, struct timeval *df)
1533 {
1534         if (tv1->tv_usec >= tv2->tv_usec) {
1535                 df->tv_sec  = tv1->tv_sec - tv2->tv_sec;
1536                 df->tv_usec = tv1->tv_usec - tv2->tv_usec;
1537                 return;
1538         }
1539
1540         df->tv_sec  = tv1->tv_sec - 1 - tv2->tv_sec;
1541         df->tv_usec = tv1->tv_sec + 1000000 - tv2->tv_usec;
1542
1543         return;
1544 }
1545
1546 void
1547 lst_cal_lnet_stat(float delta, lnet_counters_t *lnet_new,
1548                   lnet_counters_t *lnet_old)
1549 {
1550         float perf;
1551         float rate;
1552
1553         perf = (float)(lnet_new->send_length -
1554                        lnet_old->send_length) / (1024 * 1024) / delta;
1555         lnet_stat_result.lnet_total_sndperf += perf;
1556
1557         if (lnet_stat_result.lnet_min_sndperf > perf ||
1558             lnet_stat_result.lnet_min_sndperf == 0)
1559                 lnet_stat_result.lnet_min_sndperf = perf;
1560
1561         if (lnet_stat_result.lnet_max_sndperf < perf)
1562                 lnet_stat_result.lnet_max_sndperf = perf;
1563
1564         perf = (float)(lnet_new->recv_length -
1565                        lnet_old->recv_length) / (1024 * 1024) / delta;
1566         lnet_stat_result.lnet_total_rcvperf += perf;
1567
1568         if (lnet_stat_result.lnet_min_rcvperf > perf ||
1569             lnet_stat_result.lnet_min_rcvperf == 0)
1570                 lnet_stat_result.lnet_min_rcvperf = perf;
1571
1572         if (lnet_stat_result.lnet_max_rcvperf < perf)
1573                 lnet_stat_result.lnet_max_rcvperf = perf;
1574
1575         rate = (lnet_new->send_count - lnet_old->send_count) / delta;
1576         lnet_stat_result.lnet_total_sndrate += rate;
1577
1578         if (lnet_stat_result.lnet_min_sndrate > rate ||
1579             lnet_stat_result.lnet_min_sndrate == 0)
1580                 lnet_stat_result.lnet_min_sndrate = rate;
1581
1582         if (lnet_stat_result.lnet_max_sndrate < rate)
1583                 lnet_stat_result.lnet_max_sndrate = rate;
1584
1585         rate = (lnet_new->recv_count - lnet_old->recv_count) / delta;
1586         lnet_stat_result.lnet_total_rcvrate += rate;
1587
1588         if (lnet_stat_result.lnet_min_rcvrate > rate ||
1589             lnet_stat_result.lnet_min_rcvrate == 0)
1590                 lnet_stat_result.lnet_min_rcvrate = rate;
1591
1592         if (lnet_stat_result.lnet_max_rcvrate < rate)
1593                 lnet_stat_result.lnet_max_rcvrate = rate;
1594
1595         lnet_stat_result.lnet_stat_count ++;
1596
1597         lnet_stat_result.lnet_avg_sndrate = lnet_stat_result.lnet_total_sndrate /
1598                                             lnet_stat_result.lnet_stat_count;
1599         lnet_stat_result.lnet_avg_rcvrate = lnet_stat_result.lnet_total_rcvrate /
1600                                             lnet_stat_result.lnet_stat_count;
1601
1602         lnet_stat_result.lnet_avg_sndperf = lnet_stat_result.lnet_total_sndperf /
1603                                             lnet_stat_result.lnet_stat_count;
1604         lnet_stat_result.lnet_avg_rcvperf = lnet_stat_result.lnet_total_rcvperf /
1605                                             lnet_stat_result.lnet_stat_count;
1606
1607 }
1608
1609 void
1610 lst_print_lnet_stat(char *name, int bwrt, int rdwr, int type)
1611 {
1612         int     start1 = 0;
1613         int     end1   = 1;
1614         int     start2 = 0;
1615         int     end2   = 1;
1616         int     i;
1617         int     j;
1618
1619         if (lnet_stat_result.lnet_stat_count == 0)
1620                 return;
1621
1622         if (bwrt == 1) /* bw only */
1623                 start1 = 1;
1624
1625         if (bwrt == 2) /* rates only */
1626                 end1 = 0;
1627
1628         if (rdwr == 1) /* recv only */
1629                 start2 = 1;
1630
1631         if (rdwr == 2) /* send only */
1632                 end2 = 0;
1633
1634         for (i = start1; i <= end1; i++) {
1635                 fprintf(stdout, "[LNet %s of %s]\n",
1636                         i == 0 ? "Rates" : "Bandwidth", name);
1637
1638                 for (j = start2; j <= end2; j++) {
1639                         fprintf(stdout, "[%c] ", j == 0 ? 'W' : 'R');
1640
1641                         if ((type & 1) != 0) {
1642                                 fprintf(stdout, i == 0 ? "Avg: %-8.0f RPC/s " :
1643                                                          "Avg: %-8.2f MB/s  ",
1644                                         lst_lnet_stat_value(i, j, 0));
1645                         }
1646
1647                         if ((type & 2) != 0) {
1648                                 fprintf(stdout, i == 0 ? "Min: %-8.0f RPC/s " :
1649                                                          "Min: %-8.2f MB/s  ",
1650                                         lst_lnet_stat_value(i, j, 1));
1651                         }
1652
1653                         if ((type & 4) != 0) {
1654                                 fprintf(stdout, i == 0 ? "Max: %-8.0f RPC/s" :
1655                                                          "Max: %-8.2f MB/s",
1656                                         lst_lnet_stat_value(i, j, 2));
1657                         }
1658
1659                         fprintf(stdout, "\n");
1660                 }
1661         }
1662 }
1663
1664 void
1665 lst_print_stat(char *name, struct list_head *resultp,
1666                int idx, int lnet, int bwrt, int rdwr, int type)
1667 {
1668         struct list_head  tmp[2];
1669         lstcon_rpc_ent_t *new;
1670         lstcon_rpc_ent_t *old;
1671         sfw_counters_t   *sfwk_new;
1672         sfw_counters_t   *sfwk_old;
1673         srpc_counters_t  *srpc_new;
1674         srpc_counters_t  *srpc_old;
1675         lnet_counters_t  *lnet_new;
1676         lnet_counters_t  *lnet_old;
1677         struct timeval    tv;
1678         float             delta;
1679         int               errcount = 0;
1680
1681         CFS_INIT_LIST_HEAD(&tmp[0]);
1682         CFS_INIT_LIST_HEAD(&tmp[1]);
1683
1684         memset(&lnet_stat_result, 0, sizeof(lnet_stat_result));
1685
1686         while (!list_empty(&resultp[idx])) {
1687                 if (list_empty(&resultp[1 - idx])) {
1688                         fprintf(stderr, "Group is changed, re-run stat\n");
1689                         break;
1690                 }
1691
1692                 new = list_entry(resultp[idx].next, lstcon_rpc_ent_t, rpe_link);
1693                 old = list_entry(resultp[1 - idx].next, lstcon_rpc_ent_t, rpe_link);
1694
1695                 /* first time get stats result, can't calculate diff */
1696                 if (new->rpe_peer.nid == LNET_NID_ANY)
1697                         break;
1698
1699                 if (new->rpe_peer.nid != old->rpe_peer.nid ||
1700                     new->rpe_peer.pid != old->rpe_peer.pid) {
1701                         /* Something wrong. i.e, somebody change the group */
1702                         break;
1703                 }
1704
1705                 list_del(&new->rpe_link);
1706                 list_add_tail(&new->rpe_link, &tmp[idx]);
1707
1708                 list_del(&old->rpe_link);
1709                 list_add_tail(&old->rpe_link, &tmp[1 - idx]);
1710
1711                 if (new->rpe_rpc_errno != 0 || new->rpe_fwk_errno != 0 ||
1712                     old->rpe_rpc_errno != 0 || old->rpe_fwk_errno != 0) {
1713                         errcount ++;
1714                         continue;
1715                 }
1716
1717                 sfwk_new = (sfw_counters_t *)&new->rpe_payload[0];
1718                 sfwk_old = (sfw_counters_t *)&old->rpe_payload[0];
1719
1720                 srpc_new = (srpc_counters_t *)((char *)sfwk_new + sizeof(*sfwk_new));
1721                 srpc_old = (srpc_counters_t *)((char *)sfwk_old + sizeof(*sfwk_old));
1722
1723                 lnet_new = (lnet_counters_t *)((char *)srpc_new + sizeof(*srpc_new));
1724                 lnet_old = (lnet_counters_t *)((char *)srpc_old + sizeof(*srpc_old));
1725
1726                 lst_timeval_diff(&new->rpe_stamp, &old->rpe_stamp, &tv);
1727
1728                 delta = tv.tv_sec + (float)tv.tv_usec/1000000;
1729
1730                 if (!lnet) /* TODO */
1731                         continue;
1732                 
1733                 lst_cal_lnet_stat(delta, lnet_new, lnet_old);
1734         }
1735
1736         list_splice(&tmp[idx], &resultp[idx]);
1737         list_splice(&tmp[1 - idx], &resultp[1 - idx]);
1738
1739         if (errcount > 0)
1740                 fprintf(stdout, "Failed to stat on %d nodes\n", errcount);
1741
1742         if (!lnet)  /* TODO */
1743                 return;
1744
1745         lst_print_lnet_stat(name, bwrt, rdwr, type);
1746 }
1747
1748 int
1749 jt_lst_stat(int argc, char **argv)
1750 {
1751         struct list_head      head;
1752         lst_stat_req_param_t *srp;
1753         time_t                last    = 0;
1754         int                   optidx  = 0;
1755         int                   timeout = 5; /* default timeout, 5 sec */
1756         int                   delay   = 5; /* default delay, 5 sec */
1757         int                   lnet    = 1; /* lnet stat by default */
1758         int                   bwrt    = 0;
1759         int                   rdwr    = 0;
1760         int                   type    = -1;
1761         int                   idx     = 0;
1762         int                   rc;
1763         int                   c;
1764
1765         static struct option stat_opts[] =
1766         {
1767                 {"timeout", required_argument, 0, 't' },
1768                 {"delay"  , required_argument, 0, 'd' },
1769                 {"lnet"   , no_argument,       0, 'l' },
1770                 {"rpc"    , no_argument,       0, 'c' },
1771                 {"bw"     , no_argument,       0, 'b' },
1772                 {"rate"   , no_argument,       0, 'a' },
1773                 {"read"   , no_argument,       0, 'r' },
1774                 {"write"  , no_argument,       0, 'w' },
1775                 {"avg"    , no_argument,       0, 'g' },
1776                 {"min"    , no_argument,       0, 'n' },
1777                 {"max"    , no_argument,       0, 'x' },
1778                 {0,         0,                 0,  0  }
1779         };
1780
1781         if (session_key == 0) {
1782                 fprintf(stderr,
1783                         "Can't find env LST_SESSION or value is not valid\n");
1784                 return -1;
1785         }
1786
1787         while (1) {
1788                 c = getopt_long(argc, argv, "t:d:lcbarwgnx", stat_opts, &optidx);
1789
1790                 if (c == -1)
1791                         break;
1792         
1793                 switch (c) {
1794                 case 't':
1795                         timeout = atoi(optarg);
1796                         break;
1797                 case 'd':
1798                         delay = atoi(optarg);
1799                         break;
1800                 case 'l':
1801                         lnet = 1;
1802                         break;
1803                 case 'c':
1804                         lnet = 0;
1805                         break;
1806                 case 'b':
1807                         bwrt |= 1;
1808                         break;
1809                 case 'a':
1810                         bwrt |= 2;
1811                         break;
1812                 case 'r':
1813                         rdwr |= 1;
1814                         break;
1815                 case 'w':
1816                         rdwr |= 2;
1817                         break;
1818                 case 'g':
1819                         if (type == -1) {
1820                                 type = 1;
1821                                 break;
1822                         }
1823                         type |= 1;
1824                         break;
1825                 case 'n':
1826                         if (type == -1) {
1827                                 type = 2;
1828                                 break;
1829                         }
1830                         type |= 2;
1831                         break;
1832                 case 'x':
1833                         if (type == -1) {
1834                                 type = 4;
1835                                 break;
1836                         }
1837                         type |= 4;
1838                         break;
1839                 default:
1840                         lst_print_usage(argv[0]);
1841                         return -1;
1842                 }
1843         }
1844
1845         if (optind == argc) {
1846                 lst_print_usage(argv[0]);
1847                 return -1;
1848         }
1849
1850         if (timeout <= 0 || delay <= 0) {
1851                 fprintf(stderr, "Invalid timeout or delay value\n");
1852                 return -1;
1853         }
1854
1855         CFS_INIT_LIST_HEAD(&head);
1856
1857         while (optind < argc) {
1858                 rc = lst_stat_req_param_alloc(argv[optind++], &srp, 1);
1859                 if (rc != 0) 
1860                         goto out;
1861
1862                 list_add_tail(&srp->srp_link, &head);
1863         }
1864
1865         while (1) {
1866                 time_t  now = time(NULL);
1867         
1868                 if (now - last < delay) {
1869                         sleep(delay - now + last);
1870                         time(&now);
1871                 }
1872
1873                 last = now;
1874
1875                 list_for_each_entry(srp, &head, srp_link) {
1876                         rc = lst_stat_ioctl(srp->srp_name,
1877                                             srp->srp_count, srp->srp_ids,
1878                                             timeout, &srp->srp_result[idx]);
1879                         if (rc == -1) {
1880                                 lst_print_error("stat", "Failed to stat %s: %s\n",
1881                                                 srp->srp_name, strerror(errno));
1882                                 goto out;
1883                         }
1884
1885                         lst_print_stat(srp->srp_name, srp->srp_result,
1886                                        idx, lnet, bwrt, rdwr, type);
1887
1888                         lst_reset_rpcent(&srp->srp_result[1 - idx]);
1889                 }
1890
1891                 idx = 1 - idx;
1892         }
1893
1894 out:
1895         while (!list_empty(&head)) {
1896                 srp = list_entry(head.next, lst_stat_req_param_t, srp_link);
1897
1898                 list_del(&srp->srp_link);
1899                 lst_stat_req_param_free(srp);
1900         }
1901
1902         return rc;
1903 }
1904
1905 int
1906 jt_lst_show_error(int argc, char **argv)
1907 {
1908         struct list_head      head;
1909         lst_stat_req_param_t *srp;
1910         lstcon_rpc_ent_t     *ent;
1911         sfw_counters_t       *sfwk;
1912         srpc_counters_t      *srpc;
1913         lnet_counters_t      *lnet;
1914         int                   show_rpc = 1;
1915         int                   optidx   = 0;
1916         int                   rc       = 0;
1917         int                   ecount;
1918         int                   c;
1919
1920         static struct option  show_error_opts[] =
1921         {
1922                 {"session", no_argument,       0, 's' },
1923                 {0,         0,                 0,  0  }
1924         };
1925  
1926         if (session_key == 0) {
1927                 fprintf(stderr,
1928                         "Can't find env LST_SESSION or value is not valid\n");
1929                 return -1;
1930         }
1931
1932         while (1) {
1933                 c = getopt_long(argc, argv, "s", show_error_opts, &optidx);
1934
1935                 if (c == -1)
1936                         break;
1937         
1938                 switch (c) {
1939                 case 's':
1940                         show_rpc  = 0;
1941                         break;
1942
1943                 default:
1944                         lst_print_usage(argv[0]);
1945                         return -1;
1946                 }
1947         }
1948  
1949         if (optind == argc) {
1950                 lst_print_usage(argv[0]);
1951                 return -1;
1952         }
1953
1954         CFS_INIT_LIST_HEAD(&head);
1955
1956         while (optind < argc) {
1957                 rc = lst_stat_req_param_alloc(argv[optind++], &srp, 0);
1958                 if (rc != 0) 
1959                         goto out;
1960
1961                 list_add_tail(&srp->srp_link, &head);
1962         }
1963
1964         list_for_each_entry(srp, &head, srp_link) {
1965                 rc = lst_stat_ioctl(srp->srp_name, srp->srp_count,
1966                                     srp->srp_ids, 5, &srp->srp_result[0]);
1967
1968                 if (rc == -1) {
1969                         lst_print_error(srp->srp_name, "Failed to show errors of %s: %s\n",
1970                                         srp->srp_name, strerror(errno));
1971                         goto out;
1972                 }
1973
1974                 fprintf(stdout, "%s:\n", srp->srp_name);
1975
1976                 ecount = 0;
1977
1978                 list_for_each_entry(ent, &srp->srp_result[0], rpe_link) {
1979                         if (ent->rpe_rpc_errno != 0) {
1980                                 ecount ++;
1981                                 fprintf(stderr, "RPC failure, can't show error on %s\n",
1982                                         libcfs_id2str(ent->rpe_peer));
1983                                 continue;
1984                         }
1985
1986                         if (ent->rpe_fwk_errno != 0) {
1987                                 ecount ++;
1988                                 fprintf(stderr, "Framework failure, can't show error on %s\n",
1989                                         libcfs_id2str(ent->rpe_peer));
1990                                 continue;
1991                         }
1992
1993                         sfwk = (sfw_counters_t *)&ent->rpe_payload[0];
1994                         srpc = (srpc_counters_t *)((char *)sfwk + sizeof(*sfwk));
1995                         lnet = (lnet_counters_t *)((char *)srpc + sizeof(*srpc));
1996
1997                         if (srpc->errors == 0 &&
1998                             sfwk->brw_errors == 0 && sfwk->ping_errors == 0)
1999                                 continue;
2000
2001                         if (!show_rpc  && 
2002                             sfwk->brw_errors == 0 && sfwk->ping_errors == 0)
2003                                 continue;
2004         
2005                         ecount ++;
2006
2007                         fprintf(stderr, "%s: [Session %d brw errors, %d ping errors]%c",
2008                                 libcfs_id2str(ent->rpe_peer), 
2009                                 sfwk->brw_errors, sfwk->ping_errors,
2010                                 show_rpc  ? ' ' : '\n');
2011
2012                         if (!show_rpc)
2013                                 continue;
2014
2015                         fprintf(stderr, "[RPC: %d errors, %d dropped, %d expired]\n",
2016                                 srpc->errors, srpc->rpcs_dropped, srpc->rpcs_expired);
2017                 }
2018         
2019                 fprintf(stdout, "Total %d error nodes in %s\n", ecount, srp->srp_name);
2020         }
2021 out:
2022         while (!list_empty(&head)) {
2023                 srp = list_entry(head.next, lst_stat_req_param_t, srp_link);
2024
2025                 list_del(&srp->srp_link);
2026                 lst_stat_req_param_free(srp);
2027         }
2028
2029         return rc;
2030 }
2031
2032 int
2033 lst_add_batch_ioctl (char *name)
2034 {
2035         lstio_batch_add_args_t  args = {
2036                 .lstio_bat_key           = session_key,
2037                 .lstio_bat_nmlen         = strlen(name),
2038                 .lstio_bat_namep         = name,
2039         };
2040
2041         return lst_ioctl (LSTIO_BATCH_ADD, &args, sizeof(args));
2042 }
2043
2044 int
2045 jt_lst_add_batch(int argc, char **argv)
2046 {
2047         char   *name;
2048         int     rc;
2049
2050         if (session_key == 0) {
2051                 fprintf(stderr,
2052                         "Can't find env LST_SESSION or value is not valid\n");
2053                 return -1;
2054         }
2055
2056         if (argc != 2) {
2057                 lst_print_usage(argv[0]);
2058                 return -1;
2059         }
2060
2061         name = argv[1];        
2062         if (strlen(name) >= LST_NAME_SIZE) {
2063                 fprintf(stderr, "Name length is limited to %d\n",
2064                         LST_NAME_SIZE - 1);
2065                 return -1;
2066         }
2067
2068         rc = lst_add_batch_ioctl(name);
2069         if (rc == 0)
2070                 return 0;
2071
2072         lst_print_error("batch", "Failed to create batch: %s\n",
2073                         strerror(errno));
2074
2075         return -1;
2076 }
2077
2078 int
2079 lst_start_batch_ioctl (char *name, int timeout, struct list_head *resultp)
2080 {
2081         lstio_batch_run_args_t   args = {
2082                 .lstio_bat_key          = session_key,
2083                 .lstio_bat_timeout      = timeout,
2084                 .lstio_bat_nmlen        = strlen(name),
2085                 .lstio_bat_namep        = name,
2086                 .lstio_bat_resultp      = resultp,
2087         };
2088
2089         return lst_ioctl(LSTIO_BATCH_START, &args, sizeof(args));
2090 }
2091
2092 int
2093 jt_lst_start_batch(int argc, char **argv)
2094 {
2095         struct list_head  head;
2096         char             *batch;
2097         int               optidx  = 0;
2098         int               timeout = 0;
2099         int               count = 0;
2100         int               rc;
2101         int               c;
2102
2103         static struct option start_batch_opts[] =
2104         {
2105                 {"timeout", required_argument, 0, 't' },
2106                 {0,         0,                 0,  0  }
2107         };
2108
2109         if (session_key == 0) {
2110                 fprintf(stderr,
2111                         "Can't find env LST_SESSION or value is not valid\n");
2112                 return -1;
2113         }
2114
2115         while (1) {
2116                 c = getopt_long(argc, argv, "t:",
2117                                 start_batch_opts, &optidx);
2118
2119                 /* Detect the end of the options. */
2120                 if (c == -1)
2121                         break;
2122         
2123                 switch (c) {
2124                 case 't':
2125                         timeout = atoi(optarg);
2126                         break;
2127                 default:
2128                         lst_print_usage(argv[0]);
2129                         return -1;
2130                 }
2131         }
2132        
2133         if (optind == argc) {
2134                 batch = LST_DEFAULT_BATCH;
2135
2136         } else if (optind == argc - 1) {
2137                 batch = argv[optind];
2138
2139         } else {
2140                 lst_print_usage(argv[0]);
2141                 return -1;
2142         }
2143
2144         rc = lst_get_node_count(LST_OPC_BATCHCLI, batch, &count, NULL);
2145         if (rc != 0) {
2146                 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
2147                         batch, strerror(errno));
2148                 return -1;
2149         }
2150
2151         CFS_INIT_LIST_HEAD(&head);
2152
2153         rc = lst_alloc_rpcent(&head, count, 0);
2154         if (rc != 0) {
2155                 fprintf(stderr, "Out of memory\n");
2156                 return -1;
2157         }
2158
2159         rc = lst_start_batch_ioctl(batch, timeout, &head);
2160
2161         if (rc == 0) {
2162                 fprintf(stdout, "%s is running now\n", batch);
2163                 lst_free_rpcent(&head);
2164                 return 0;
2165         }
2166
2167         if (rc == -1) {
2168                 lst_print_error("batch", "Failed to start batch: %s\n",
2169                                 strerror(errno));
2170                 lst_free_rpcent(&head);
2171                 return rc;
2172         }
2173
2174         lst_print_transerr(&head, "Run batch");
2175
2176         lst_free_rpcent(&head);
2177
2178         return rc;
2179 }
2180
2181 int
2182 lst_stop_batch_ioctl(char *name, int force, struct list_head *resultp)
2183 {       
2184         lstio_batch_stop_args_t   args = {
2185                 .lstio_bat_key          = session_key,
2186                 .lstio_bat_force        = force,
2187                 .lstio_bat_nmlen        = strlen(name),
2188                 .lstio_bat_namep        = name,
2189                 .lstio_bat_resultp      = resultp,
2190         };
2191
2192         return lst_ioctl(LSTIO_BATCH_STOP, &args, sizeof(args));
2193 }
2194
2195 int
2196 jt_lst_stop_batch(int argc, char **argv)
2197 {
2198         struct list_head  head;
2199         char             *batch;
2200         int               force = 0;
2201         int               optidx;
2202         int               count;
2203         int               rc;
2204         int               c;
2205
2206         static struct option stop_batch_opts[] =
2207         {
2208                 {"force",   no_argument,   0, 'f' },
2209                 {0,         0,             0,  0  }
2210         };
2211
2212         if (session_key == 0) {
2213                 fprintf(stderr,
2214                         "Can't find env LST_SESSION or value is not valid\n");
2215                 return -1;
2216         }
2217
2218         while (1) {
2219                 c = getopt_long(argc, argv, "f",
2220                                 stop_batch_opts, &optidx);
2221
2222                 /* Detect the end of the options. */
2223                 if (c == -1)
2224                         break;
2225         
2226                 switch (c) {
2227                 case 'f':
2228                         force = 1;
2229                         break;
2230                 default:
2231                         lst_print_usage(argv[0]);
2232                         return -1;
2233                 }
2234         }
2235
2236         if (optind == argc) {
2237                 batch = LST_DEFAULT_BATCH;
2238
2239         } else if (optind == argc - 1) {
2240                 batch = argv[optind];
2241
2242         } else {
2243                 lst_print_usage(argv[0]);
2244                 return -1;
2245         }
2246
2247         rc = lst_get_node_count(LST_OPC_BATCHCLI, batch, &count, NULL);
2248         if (rc != 0) {
2249                 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
2250                         batch, strerror(errno));
2251                 return -1;
2252         }
2253
2254         CFS_INIT_LIST_HEAD(&head);
2255
2256         rc = lst_alloc_rpcent(&head, count, 0);
2257         if (rc != 0) {
2258                 fprintf(stderr, "Out of memory\n");
2259                 return -1;
2260         }
2261
2262         rc = lst_stop_batch_ioctl(batch, force, &head);
2263         if (rc != 0)
2264                 goto out;
2265
2266         while (1) {
2267                 lst_reset_rpcent(&head);
2268
2269                 rc = lst_query_batch_ioctl(batch, 0, 0, 30, &head);
2270                 if (rc != 0)
2271                         goto out;
2272
2273                 if (lstcon_tsbqry_stat_run(&trans_stat, 0)  == 0 &&
2274                     lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0)
2275                         break;
2276
2277                 fprintf(stdout, "%d batch in stopping\n",
2278                         lstcon_tsbqry_stat_run(&trans_stat, 0));
2279                 sleep(1);
2280         }
2281
2282         fprintf(stdout, "Batch is stopped\n");
2283         lst_free_rpcent(&head);
2284
2285         return 0;
2286 out:
2287         if (rc == -1) {
2288                 lst_print_error("batch", "Failed to stop batch: %s\n",
2289                                 strerror(errno));
2290                 lst_free_rpcent(&head);
2291                 return -1;
2292         }
2293
2294         lst_print_transerr(&head, "stop batch");
2295
2296         lst_free_rpcent(&head);
2297
2298         return rc;
2299 }
2300
2301 int
2302 lst_list_batch_ioctl(int len, char *name, int index)
2303 {
2304         lstio_batch_list_args_t         args = {
2305                 .lstio_bat_key          = session_key,
2306                 .lstio_bat_idx          = index,
2307                 .lstio_bat_nmlen        = len,
2308                 .lstio_bat_namep        = name,
2309         };
2310
2311         return lst_ioctl(LSTIO_BATCH_LIST, &args, sizeof(args));
2312 }
2313
2314 int
2315 lst_info_batch_ioctl(char *batch, int test, int server,
2316                      lstcon_test_batch_ent_t *entp, int *idxp,
2317                      int *ndentp, lstcon_node_ent_t *dentsp)
2318 {
2319         lstio_batch_info_args_t         args = {
2320                 .lstio_bat_key          = session_key,
2321                 .lstio_bat_nmlen        = strlen(batch),
2322                 .lstio_bat_namep        = batch,
2323                 .lstio_bat_server       = server,
2324                 .lstio_bat_testidx      = test,
2325                 .lstio_bat_entp         = entp,
2326                 .lstio_bat_idxp         = idxp,
2327                 .lstio_bat_ndentp       = ndentp,
2328                 .lstio_bat_dentsp       = dentsp,
2329         };
2330
2331         return lst_ioctl(LSTIO_BATCH_INFO, &args, sizeof(args));
2332 }
2333
2334 int
2335 lst_list_batch_all(void)
2336 {
2337         char name[LST_NAME_SIZE];
2338         int  rc;
2339         int  i;
2340
2341         for (i = 0; ; i++) {
2342                 rc = lst_list_batch_ioctl(LST_NAME_SIZE, name, i);
2343                 if (rc == 0) {
2344                         fprintf(stdout, "%d) %s\n", i + 1, name);
2345                         continue;
2346                 }
2347
2348                 if (errno == ENOENT) 
2349                         break;
2350
2351                 lst_print_error("batch", "Failed to list batch: %s\n",
2352                                 strerror(errno));
2353                 return rc;
2354         }
2355
2356         fprintf(stdout, "Total %d batches\n", i);
2357
2358         return 0;
2359 }
2360
2361 int
2362 lst_list_tsb_nodes(char *batch, int test, int server,
2363                    int count, int active, int invalid)
2364 {
2365         lstcon_node_ent_t *dents;
2366         int                index = 0;
2367         int                rc;
2368         int                c;
2369         int                i;
2370
2371         if (count == 0) 
2372                 return 0;
2373
2374         /* verbose list, show nodes in batch or test */
2375         dents = malloc(count * sizeof(lstcon_node_ent_t));
2376         if (dents == NULL) {
2377                 fprintf(stdout, "Can't allocate memory\n");
2378                 return -1;
2379         }
2380
2381         rc = lst_info_batch_ioctl(batch, test, server,
2382                                   NULL, &index, &count, dents);
2383         if (rc != 0) {
2384                 free(dents);
2385                 lst_print_error((test > 0) ? "test" : "batch",
2386                                 (test > 0) ? "Failed to query test: %s\n" :
2387                                              "Failed to query batch: %s\n",
2388                                 strerror(errno));
2389                 return -1;
2390         }
2391
2392         for (i = 0, c = 0; i < count; i++) {
2393                 if ((!active  && dents[i].nde_state == LST_NODE_ACTIVE) ||
2394                     (!invalid && (dents[i].nde_state == LST_NODE_BUSY  ||
2395                                   dents[i].nde_state == LST_NODE_DOWN  ||
2396                                   dents[i].nde_state == LST_NODE_UNKNOWN))) 
2397                         continue;
2398
2399                 fprintf(stdout, "\t%s: %s\n",
2400                         libcfs_id2str(dents[i].nde_id),
2401                         lst_node_state2str(dents[i].nde_state));
2402                 c++;
2403         }
2404       
2405         fprintf(stdout, "Total %d nodes\n", c);
2406         free(dents);
2407
2408         return 0;
2409 }
2410
2411 int
2412 jt_lst_list_batch(int argc, char **argv)
2413 {
2414         lstcon_test_batch_ent_t ent;
2415         char                *batch   = NULL;
2416         int                  optidx  = 0;
2417         int                  verbose = 0; /* list nodes in batch or test */
2418         int                  invalid = 0;
2419         int                  active  = 0;
2420         int                  server  = 0;
2421         int                  ntest   = 0;
2422         int                  test    = 0;
2423         int                  c       = 0;
2424         int                  rc;
2425
2426         static struct option list_batch_opts[] =
2427         {
2428                 {"test",    required_argument, 0, 't' },
2429                 {"invalid", no_argument,       0, 'i' },
2430                 {"active",  no_argument,       0, 'a' },
2431                 {"all",     no_argument,       0, 'l' },
2432                 {"server",  no_argument,       0, 's' },
2433                 {0,         0,                 0,  0  }
2434         };
2435
2436         if (session_key == 0) {
2437                 fprintf(stderr,
2438                         "Can't find env LST_SESSION or value is not valid\n");
2439                 return -1;
2440         }
2441
2442         while (1) {
2443                 c = getopt_long(argc, argv, "ailst:",
2444                                 list_batch_opts, &optidx);
2445
2446                 if (c == -1)
2447                         break;
2448         
2449                 switch (c) {
2450                 case 'a':
2451                         verbose = active = 1;
2452                         break;
2453                 case 'i':
2454                         verbose = invalid = 1;
2455                         break;
2456                 case 'l':
2457                         verbose = active = invalid = 1;
2458                         break;
2459                 case 's':
2460                         server = 1;
2461                         break;
2462                 case 't':
2463                         test = atoi(optarg);
2464                         ntest = 1;
2465                         break;
2466                 default:
2467                         lst_print_usage(argv[0]);
2468                         return -1;
2469                 }
2470         }
2471
2472         if (optind == argc) {
2473                 /* list all batches */
2474                 rc = lst_list_batch_all();
2475                 return rc;
2476         }
2477
2478         if (ntest == 1 && test <= 0) {
2479                 fprintf(stderr, "Invalid test id, test id starts from 1\n");
2480                 return -1;
2481         }
2482
2483         if (optind != argc - 1) {
2484                 lst_print_usage(argv[0]);
2485                 return -1;
2486         }
2487                 
2488         batch = argv[optind];
2489
2490 loop:
2491         /* show detail of specified batch or test */
2492         rc = lst_info_batch_ioctl(batch, test, server,
2493                                   &ent, NULL, NULL, NULL);
2494         if (rc != 0) {
2495                 lst_print_error((test > 0) ? "test" : "batch",
2496                                 (test > 0) ? "Failed to query test: %s\n" :
2497                                              "Failed to query batch: %s\n",
2498                                 strerror(errno));
2499                 return -1;
2500         }
2501
2502         if (verbose) {
2503                 /* list nodes in test or batch */
2504                 rc = lst_list_tsb_nodes(batch, test, server,
2505                                         server ? ent.tbe_srv_nle.nle_nnode :
2506                                                  ent.tbe_cli_nle.nle_nnode,
2507                                         active, invalid);
2508                 return rc;
2509         }
2510
2511         /* only show number of hosts in batch or test */
2512         if (test == 0) {
2513                 fprintf(stdout, "Batch: %s Tests: %d State: %d\n",
2514                         batch, ent.u.tbe_batch.bae_ntest,
2515                         ent.u.tbe_batch.bae_state);
2516                 ntest = ent.u.tbe_batch.bae_ntest;
2517                 test = 1; /* starting from test 1 */
2518
2519         } else {
2520                 fprintf(stdout,
2521                         "\tTest %d(%s) (loop: %d, concurrency: %d)\n",
2522                         test, lst_test_type2name(ent.u.tbe_test.tse_type),
2523                         ent.u.tbe_test.tse_loop,
2524                         ent.u.tbe_test.tse_concur);
2525                 ntest --;
2526                 test ++;
2527         }
2528
2529         fprintf(stdout, LST_NODES_TITLE);
2530         fprintf(stdout, "client\t%d\t%d\t%d\t%d\t%d\n"
2531                         "server\t%d\t%d\t%d\t%d\t%d\n",
2532                 ent.tbe_cli_nle.nle_nactive, 
2533                 ent.tbe_cli_nle.nle_nbusy,
2534                 ent.tbe_cli_nle.nle_ndown,
2535                 ent.tbe_cli_nle.nle_nunknown,
2536                 ent.tbe_cli_nle.nle_nnode,
2537                 ent.tbe_srv_nle.nle_nactive,
2538                 ent.tbe_srv_nle.nle_nbusy,
2539                 ent.tbe_srv_nle.nle_ndown,
2540                 ent.tbe_srv_nle.nle_nunknown,
2541                 ent.tbe_srv_nle.nle_nnode);
2542
2543         if (ntest != 0)
2544                 goto loop;
2545
2546         return 0;
2547 }
2548
2549 int
2550 lst_query_batch_ioctl(char *batch, int test, int server,
2551                       int timeout, struct list_head *head)
2552 {
2553         lstio_batch_query_args_t args = {
2554                 .lstio_bat_key     = session_key,
2555                 .lstio_bat_testidx = test,
2556                 .lstio_bat_client  = !(server),
2557                 .lstio_bat_timeout = timeout,
2558                 .lstio_bat_nmlen   = strlen(batch),
2559                 .lstio_bat_namep   = batch,
2560                 .lstio_bat_resultp = head,
2561         };
2562
2563         return lst_ioctl(LSTIO_BATCH_QUERY, &args, sizeof(args));
2564 }
2565
2566 void
2567 lst_print_tsb_verbose(struct list_head *head,
2568                       int active, int idle, int error)
2569 {
2570         lstcon_rpc_ent_t *ent;
2571
2572         list_for_each_entry(ent, head, rpe_link) {
2573                 if (ent->rpe_priv[0] == 0 && active)
2574                         continue;
2575
2576                 if (ent->rpe_priv[0] != 0 && idle)
2577                         continue;
2578
2579                 if (ent->rpe_fwk_errno == 0 && error)
2580                         continue;
2581
2582                 fprintf(stdout, "%s [%s]: %s\n",
2583                         libcfs_id2str(ent->rpe_peer),
2584                         lst_node_state2str(ent->rpe_state),
2585                         ent->rpe_rpc_errno != 0 ?
2586                                 strerror(ent->rpe_rpc_errno) :
2587                                 (ent->rpe_priv[0] > 0 ? "Running" : "Idle"));
2588         }
2589 }
2590
2591 int
2592 jt_lst_query_batch(int argc, char **argv)
2593 {
2594         lstcon_test_batch_ent_t ent;
2595         struct list_head     head;
2596         char                *batch   = NULL;
2597         time_t               last    = 0;
2598         int                  optidx  = 0;
2599         int                  verbose = 0;
2600         int                  server  = 0;
2601         int                  timeout = 5; /* default 5 seconds */
2602         int                  delay   = 5; /* default 5 seconds */
2603         int                  loop    = 1; /* default 1 loop */
2604         int                  active  = 0;
2605         int                  error   = 0;
2606         int                  idle    = 0;
2607         int                  count   = 0;
2608         int                  test    = 0;
2609         int                  rc      = 0;
2610         int                  c       = 0;
2611         int                  i;
2612
2613         static struct option query_batch_opts[] =
2614         {
2615                 {"timeout", required_argument, 0, 'o' },
2616                 {"delay",   required_argument, 0, 'd' },
2617                 {"loop",    required_argument, 0, 'c' },
2618                 {"test",    required_argument, 0, 't' },
2619                 {"server",  no_argument,       0, 's' },
2620                 {"active",  no_argument,       0, 'a' },
2621                 {"idle",    no_argument,       0, 'i' },
2622                 {"error",   no_argument,       0, 'e' },
2623                 {"all",     no_argument,       0, 'l' },
2624                 {0,         0,                 0,  0  }
2625         };
2626
2627         if (session_key == 0) {
2628                 fprintf(stderr,
2629                         "Can't find env LST_SESSION or value is not valid\n");
2630                 return -1;
2631         }
2632
2633         while (1) {
2634                 c = getopt_long(argc, argv, "o:d:c:t:saiel",
2635                                 query_batch_opts, &optidx);
2636
2637                 /* Detect the end of the options. */
2638                 if (c == -1)
2639                         break;
2640         
2641                 switch (c) {
2642                 case 'o':
2643                         timeout = atoi(optarg);
2644                         break;
2645                 case 'd':
2646                         delay = atoi(optarg);
2647                         break;
2648                 case 'c':
2649                         loop = atoi(optarg);
2650                         break;
2651                 case 't':
2652                         test = atoi(optarg);
2653                         break;
2654                 case 's':
2655                         server = 1;
2656                         break;
2657                 case 'a':
2658                         active = verbose = 1;
2659                         break;
2660                 case 'i':
2661                         idle = verbose = 1;
2662                         break;
2663                 case 'e':
2664                         error = verbose = 1;
2665                         break;
2666                 case 'l':
2667                         verbose = 1;
2668                         break;
2669                 default:
2670                         lst_print_usage(argv[0]);
2671                         return -1;
2672                 }
2673         }
2674
2675         if (test < 0 || timeout <= 0 || delay <= 0 || loop <= 0) {
2676                 lst_print_usage(argv[0]);
2677                 return -1;
2678         }
2679
2680         if (optind == argc) {
2681                 batch = LST_DEFAULT_BATCH;
2682
2683         } else if (optind == argc - 1) {
2684                 batch = argv[optind];
2685
2686         } else {
2687                 lst_print_usage(argv[0]);
2688                 return -1;
2689         }
2690
2691
2692         CFS_INIT_LIST_HEAD(&head);
2693
2694         if (verbose) {
2695                 rc = lst_info_batch_ioctl(batch, test, server,
2696                                           &ent, NULL, NULL, NULL);
2697                 if (rc != 0) {
2698                         fprintf(stderr, "Failed to query %s [%d]: %s\n",
2699                                 batch, test, strerror(errno));
2700                         return -1;
2701                 }
2702
2703                 count = server ? ent.tbe_srv_nle.nle_nnode :
2704                                  ent.tbe_cli_nle.nle_nnode;
2705                 if (count == 0) {
2706                         fprintf(stdout, "Batch or test is empty\n");
2707                         return 0;
2708                 }
2709         }
2710
2711         rc = lst_alloc_rpcent(&head, count, 0);
2712         if (rc != 0) {
2713                 fprintf(stderr, "Out of memory\n");
2714                 return rc;
2715         }
2716
2717         for (i = 0; i < loop; i++) {
2718                 time_t  now = time(NULL);
2719         
2720                 if (now - last < delay) {
2721                         sleep(delay - now + last);
2722                         time(&now);
2723                 }
2724
2725                 last = now;
2726
2727                 rc = lst_query_batch_ioctl(batch, test,
2728                                            server, timeout, &head);
2729                 if (rc == -1) {
2730                         fprintf(stderr, "Failed to query batch: %s\n",
2731                                 strerror(errno));
2732                         break;
2733                 }
2734
2735                 if (verbose) {
2736                         /* Verbose mode */
2737                         lst_print_tsb_verbose(&head, active, idle, error);
2738                         continue;
2739                 }
2740
2741                 fprintf(stdout, "%s [%d] ", batch, test);
2742
2743                 if (lstcon_rpc_stat_failure(&trans_stat, 0) != 0) {
2744                         fprintf(stdout, "%d of %d nodes are unknown, ",
2745                                 lstcon_rpc_stat_failure(&trans_stat, 0),
2746                                 lstcon_rpc_stat_total(&trans_stat, 0));
2747                 }
2748
2749                 if (lstcon_rpc_stat_failure(&trans_stat, 0) == 0 &&
2750                     lstcon_tsbqry_stat_run(&trans_stat, 0)  == 0  &&
2751                     lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0) {
2752                         fprintf(stdout, "is stopped\n");
2753                         continue;
2754                 }
2755
2756                 if (lstcon_rpc_stat_failure(&trans_stat, 0) == 0 &&
2757                     lstcon_tsbqry_stat_idle(&trans_stat, 0) == 0 &&
2758                     lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0) {
2759                         fprintf(stdout, "is running\n");
2760                         continue;
2761                 }
2762
2763                 fprintf(stdout, "stopped: %d , running: %d, failed: %d\n",
2764                                 lstcon_tsbqry_stat_idle(&trans_stat, 0),
2765                                 lstcon_tsbqry_stat_run(&trans_stat, 0),
2766                                 lstcon_tsbqry_stat_failure(&trans_stat, 0));
2767         }
2768
2769         lst_free_rpcent(&head);
2770
2771         return rc;
2772 }
2773          
2774 int
2775 lst_parse_distribute(char *dstr, int *dist, int *span)
2776 {
2777         *dist = atoi(dstr);
2778         if (*dist <= 0)
2779                 return -1;
2780
2781         dstr = strchr(dstr, ':');
2782         if (dstr == NULL) 
2783                 return -1;
2784
2785         *span = atoi(dstr + 1);
2786         if (*span <= 0)
2787                 return -1;
2788
2789         return 0;
2790 }
2791
2792 int
2793 lst_get_bulk_param(int argc, char **argv, lst_test_bulk_param_t *bulk)
2794 {
2795         char   *tok = NULL;
2796         char   *end = NULL;
2797         int     rc  = 0;
2798         int     i   = 0;
2799
2800         bulk->blk_size  = 4096;
2801         bulk->blk_opc   = LST_BRW_READ;
2802         bulk->blk_flags = LST_BRW_CHECK_NONE;
2803
2804         while (i < argc) {
2805                 if (strcasestr(argv[i], "check=") == argv[i] ||
2806                     strcasestr(argv[i], "c=") == argv[i]) {
2807                         tok = strchr(argv[i], '=') + 1;
2808
2809                         if (strcasecmp(tok, "full") == 0) {
2810                                 bulk->blk_flags = LST_BRW_CHECK_FULL;
2811                         } else if (strcasecmp(tok, "simple") == 0) {
2812                                 bulk->blk_flags = LST_BRW_CHECK_SIMPLE;
2813                         } else {
2814                                 fprintf(stderr, "Unknow flag %s\n", tok);
2815                                 return -1;
2816                         }
2817                                 
2818                 } else if (strcasestr(argv[i], "size=") == argv[i] ||
2819                          strcasestr(argv[i], "s=") == argv[i]) {
2820                         tok = strchr(argv[i], '=') + 1;
2821
2822                         bulk->blk_size = strtol(tok, &end, 0);
2823                         if (bulk->blk_size <= 0) {
2824                                 fprintf(stderr, "Invalid size %s\n", tok);
2825                                 return -1;
2826                         }
2827
2828                         if (end == NULL)
2829                                 return 0;
2830
2831                         if (*end == 'k' || *end == 'K')
2832                                 bulk->blk_size *= 1024;
2833                         else if (*end == 'm' || *end == 'M')
2834                                 bulk->blk_size *= 1024 * 1024;
2835
2836                         if (bulk->blk_size > CFS_PAGE_SIZE * LNET_MAX_IOV) {
2837                                 fprintf(stderr, "Size exceed limitation: %d bytes\n",
2838                                         bulk->blk_size);
2839                                 return -1;
2840                         }
2841                         
2842                 } else if (strcasecmp(argv[i], "read") == 0 ||
2843                            strcasecmp(argv[i], "r") == 0) {
2844                         bulk->blk_opc = LST_BRW_READ;
2845                 
2846                 } else if (strcasecmp(argv[i], "write") == 0 ||
2847                            strcasecmp(argv[i], "w") == 0) {
2848                         bulk->blk_opc = LST_BRW_WRITE;
2849
2850                 } else {
2851                         fprintf(stderr, "Unknow parameter: %s\n", argv[i]);
2852                         return -1;
2853                 }
2854
2855                 i++;
2856         }
2857
2858         return rc;
2859 }
2860
2861 int
2862 lst_get_test_param(char *test, int argc, char **argv, void **param, int *plen)
2863 {
2864         lst_test_bulk_param_t *bulk = NULL;
2865         int                    type;
2866
2867         type = lst_test_name2type(test);
2868         if (type < 0) {
2869                 fprintf(stderr, "Unknow test name %s\n", test);
2870                 return -1;
2871         }
2872
2873         switch (type) {
2874         case LST_TEST_PING:
2875                 break;
2876
2877         case LST_TEST_BULK:
2878                 bulk = malloc(sizeof(*bulk));
2879                 if (bulk == NULL) {
2880                         fprintf(stderr, "Out of memory\n");
2881                         return -1;
2882                 }
2883
2884                 memset(bulk, 0, sizeof(*bulk));
2885
2886                 if (lst_get_bulk_param(argc, argv, bulk) != 0) {
2887                         free(bulk);
2888                         return -1;
2889                 }
2890
2891                 *param = bulk;
2892                 *plen  = sizeof(*bulk);
2893
2894                 break;
2895
2896         default:
2897                 break;
2898         }
2899         
2900         /* TODO: parse more parameter */
2901         return type;
2902 }
2903
2904 int
2905 lst_add_test_ioctl(char *batch, int type, int loop, int concur,
2906                    int dist, int span, char *sgrp, char *dgrp,
2907                    void *param, int plen, int *retp, struct list_head *resultp)
2908 {
2909         lstio_test_args_t args = {
2910                 .lstio_tes_key          = session_key,
2911                 .lstio_tes_bat_nmlen    = strlen(batch),
2912                 .lstio_tes_bat_name     = batch,
2913                 .lstio_tes_type         = type,
2914                 .lstio_tes_loop         = loop,
2915                 .lstio_tes_concur       = concur,
2916                 .lstio_tes_dist         = dist,
2917                 .lstio_tes_span         = span,
2918                 .lstio_tes_sgrp_nmlen   = strlen(sgrp),
2919                 .lstio_tes_sgrp_name    = sgrp,
2920                 .lstio_tes_dgrp_nmlen   = strlen(dgrp),
2921                 .lstio_tes_dgrp_name    = dgrp,
2922                 .lstio_tes_param_len    = plen,
2923                 .lstio_tes_param        = param,
2924                 .lstio_tes_retp         = retp,
2925                 .lstio_tes_resultp      = resultp,
2926         };
2927
2928         return lst_ioctl(LSTIO_TEST_ADD, &args, sizeof(args));
2929 }
2930
2931 int
2932 jt_lst_add_test(int argc, char **argv)
2933 {
2934         struct list_head  head;
2935         char             *batch  = NULL;
2936         char             *test   = NULL;
2937         char             *dstr   = NULL;
2938         char             *from   = NULL;
2939         char             *to     = NULL;
2940         void             *param  = NULL;
2941         int               optidx = 0;
2942         int               concur = 1;
2943         int               loop   = -1;
2944         int               dist   = 1;
2945         int               span   = 1;
2946         int               plen   = 0;
2947         int               fcount = 0;
2948         int               tcount = 0;
2949         int               ret    = 0;
2950         int               type;
2951         int               rc;
2952         int               c;
2953
2954         static struct option add_test_opts[] =
2955         {
2956                 {"batch",       required_argument, 0, 'b' },
2957                 {"concurrency", required_argument, 0, 'c' },
2958                 {"distribute",  required_argument, 0, 'd' },
2959                 {"from",        required_argument, 0, 'f' },
2960                 {"to",          required_argument, 0, 't' },
2961                 {"loop",        required_argument, 0, 'l' },
2962                 {0,             0,                 0,  0  }
2963         };
2964
2965         if (session_key == 0) {
2966                 fprintf(stderr,
2967                         "Can't find env LST_SESSION or value is not valid\n");
2968                 return -1;
2969         }
2970
2971         while (1) {
2972                 c = getopt_long(argc, argv, "b:c:d:f:l:t:",
2973                                 add_test_opts, &optidx);
2974
2975                 /* Detect the end of the options. */
2976                 if (c == -1)
2977                         break;
2978         
2979                 switch (c) {
2980                 case 'b':
2981                         batch = optarg;
2982                         break;
2983                 case 'c':
2984                         concur = atoi(optarg);
2985                         break;
2986                 case 'd':
2987                         dstr = optarg;
2988                         break;
2989                 case 'f':
2990                         from = optarg;
2991                         break;
2992                 case 'l':
2993                         loop = atoi(optarg);
2994                         break;
2995                 case 't':
2996                         to = optarg;
2997                         break;
2998                 default:
2999                         lst_print_usage(argv[0]);
3000                         return -1;
3001                 }
3002         }
3003
3004         if (optind == argc || from == NULL || to == NULL) {
3005                 lst_print_usage(argv[0]);
3006                 return -1;
3007         }
3008
3009         if (concur <= 0 || concur > LST_MAX_CONCUR) {
3010                 fprintf(stderr, "Invalid concurrency of test: %d\n", concur);
3011                 return -1;
3012         }
3013
3014         if (batch == NULL)
3015                 batch = LST_DEFAULT_BATCH;
3016
3017         if (dstr != NULL) {
3018                 rc = lst_parse_distribute(dstr, &dist, &span);
3019                 if (rc != 0) {
3020                         fprintf(stderr, "Invalid distribution: %s\n", dstr);
3021                         return -1;
3022                 }
3023         }
3024
3025         test = argv[optind++];
3026
3027         argc -= optind;
3028         argv += optind;
3029
3030         type = lst_get_test_param(test, argc, argv, &param, &plen);
3031         if (type < 0) {
3032                 fprintf(stderr, "Failed to add test (%s)\n", test);
3033                 return -1;
3034         }
3035
3036         CFS_INIT_LIST_HEAD(&head);
3037
3038         rc = lst_get_node_count(LST_OPC_GROUP, from, &fcount, NULL);
3039         if (rc != 0) {
3040                 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
3041                         from, strerror(errno));
3042                 goto out;
3043         }
3044
3045         rc = lst_get_node_count(LST_OPC_GROUP, to, &tcount, NULL);
3046         if (rc != 0) {
3047                 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
3048                         to, strerror(errno));
3049                 goto out;
3050         }
3051
3052         rc = lst_alloc_rpcent(&head, fcount > tcount ? fcount : tcount, 0);
3053         if (rc != 0) {
3054                 fprintf(stderr, "Out of memory\n");
3055                 goto out;
3056         }
3057
3058         rc = lst_add_test_ioctl(batch, type, loop, concur,
3059                                 dist, span, from, to, param, plen, &ret, &head);
3060
3061         if (rc == 0) {
3062                 fprintf(stdout, "Test was added successfully\n");
3063                 if (ret != 0) {
3064                         fprintf(stdout, "Server group contains userland test "
3065                                 "nodes, old version of tcplnd can't accept "
3066                                 "connection request\n");
3067                 }
3068
3069                 goto out;
3070         }
3071
3072         if (rc == -1) {
3073                 lst_print_error("test", "Failed to add test: %s\n",
3074                                 strerror(errno));
3075                 goto out;
3076         }
3077
3078         lst_print_transerr(&head, "add test");
3079 out:
3080         lst_free_rpcent(&head);
3081
3082         if (param != NULL)
3083                 free(param);
3084
3085         return rc;
3086 }
3087
3088 static command_t lst_cmdlist[] = {
3089         {"new_session",         jt_lst_new_session,     NULL,
3090          "Usage: lst new_session [--timeout TIME] [--force] [NAME]"                     },
3091         {"end_session",         jt_lst_end_session,     NULL,
3092          "Usage: lst end_session"                                                       },
3093         {"show_session",        jt_lst_show_session,    NULL,
3094          "Usage: lst show_session"                                                      },
3095         {"ping",                jt_lst_ping ,           NULL,
3096          "Usage: lst ping  [--group NAME] [--batch NAME] [--session] [--nodes IDS]"     },
3097         {"add_group",           jt_lst_add_group,       NULL,
3098          "Usage: lst group NAME IDs [IDs]..."                                           },
3099         {"del_group",           jt_lst_del_group,       NULL,
3100          "Usage: lst del_group NAME"                                                    },
3101         {"update_group",        jt_lst_update_group,    NULL,
3102          "Usage: lst update_group NAME [--clean] [--refresh] [--remove IDs]"            },
3103         {"list_group",          jt_lst_list_group,      NULL,
3104           "Usage: lst list_group [--active] [--busy] [--down] [--unknown] GROUP ..."    },
3105         {"stat",                jt_lst_stat,            NULL,
3106          "Usage: lst stat [--bw] [--rate] [--read] [--write] [--max] [--min] [--avg] "
3107          " [--timeout #] [--delay #] GROUP [GROUP]"                                     },
3108         {"show_error",          jt_lst_show_error,      NULL,
3109          "Usage: lst show_error [--group NAME] | [--nodes IDS]"                         },
3110         {"add_batch",           jt_lst_add_batch,       NULL,
3111          "Usage: lst add_batch NAME"                                                    },
3112         {"run",                 jt_lst_start_batch,     NULL,
3113          "Usage: lst run [--timeout TIME] [NAME]"                                       },
3114         {"stop",                jt_lst_stop_batch,      NULL,
3115          "Usage: lst stop [--force] BATCH_NAME"                                         },
3116         {"list_batch",          jt_lst_list_batch,      NULL,
3117          "Usage: lst list_batch NAME [--test ID] [--server]"                            },
3118         {"query",               jt_lst_query_batch,     NULL,
3119          "Usage: lst query [--test ID] [--server] [--timeout TIME] NAME"                },
3120         {"add_test",            jt_lst_add_test,        NULL,
3121          "Usage: lst add_test [--batch BATCH] [--loop #] [--concurrency #] "
3122          " [--distribute #:#] [--from GROUP] [--to GROUP] TEST..."                      },
3123         {"help",                Parser_help,            0,     "help"                   },
3124         {0,                     0,                      0,      NULL                    }
3125 };
3126
3127 int
3128 lst_initialize(void)
3129 {
3130         char   *key;
3131
3132         key = getenv("LST_SESSION");
3133
3134         if (key == NULL) {
3135                 session_key = 0;
3136                 return 0;
3137         }
3138
3139         session_key = atoi(key);
3140
3141         return 0;
3142 }
3143
3144 int
3145 main(int argc, char **argv)
3146 {
3147         setlinebuf(stdout);
3148
3149         if (lst_initialize() < 0)
3150                 exit(0);
3151
3152         if (ptl_initialize(argc, argv) < 0)
3153                 exit(0);
3154         
3155         Parser_init("lst > ", lst_cmdlist);
3156
3157         if (argc != 1) 
3158                 return Parser_execarg(argc - 1, argv + 1, lst_cmdlist);
3159
3160         Parser_commands();
3161
3162         return 0;
3163 }