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