1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5 * Use is subject to license terms.
7 * Copyright (c) 2012, 2017, Intel Corporation.
11 * This file is part of Lustre, http://www.lustre.org/
13 * Author: Liang Zhen <liangzhen@clusterfs.com>
25 #include <sys/ioctl.h>
27 #include <linux/types.h>
29 #include <libcfs/util/list.h>
30 #include <libcfs/util/ioctl.h>
31 #include <libcfs/util/parser.h>
32 #include <linux/lnet/lnetctl.h>
33 #include <linux/lnet/lnetst.h>
34 #include <linux/lnet/nidstr.h>
35 #include "lnetconfig/liblnetconfig.h"
37 static int lst_info_batch_ioctl(char *batch, int test, int server,
38 struct lstcon_test_batch_ent *entp, int *idxp,
39 int *ndentp, struct lstcon_node_ent *dentsp);
40 static int lst_info_group_ioctl(char *name, struct lstcon_ndlist_ent *gent,
41 int *idx, int *count, struct lstcon_node_ent *dents);
42 static int lst_query_batch_ioctl(char *batch, int test, int server,
43 int timeout, struct list_head *head);
45 struct lst_sid LST_INVALID_SID = { .ses_nid = LNET_NID_ANY, .ses_stamp = -1 };
46 static unsigned int session_key;
48 /* All nodes running 2.6.50 or later understand feature LST_FEAT_BULK_LEN */
49 static unsigned int session_features = LST_FEATS_MASK;
50 static struct lstcon_trans_stat trans_stat;
52 typedef struct list_string {
53 struct list_string *lstr_next;
59 # define offsetof(typ,memb) ((unsigned long)((char *)&(((typ *)0)->memb)))
62 static int alloc_count = 0;
63 static int alloc_nob = 0;
68 lstr_t *lstr = malloc(offsetof(lstr_t, lstr_str[sz]));
71 fprintf(stderr, "Can't allocate lstr\n");
78 lstr->lstr_str[0] = 0;
84 free_lstr(lstr_t *lstr)
87 alloc_nob -= lstr->lstr_sz;
92 new_lstrs(lstr_t **list, char *prefix, char *postfix,
93 int lo, int hi, int stride)
95 int n1 = strlen(prefix);
96 int n2 = strlen(postfix);
97 int sz = n1 + 20 + n2 + 1;
100 lstr_t *n = alloc_lstr(sz);
102 snprintf(n->lstr_str, sz - 1, "%s%u%s",
103 prefix, lo, postfix);
105 n->lstr_next = *list;
113 expand_lstr(lstr_t **list, lstr_t *l)
115 int nob = strlen(l->lstr_str);
125 b1 = strchr(l->lstr_str, '[');
127 l->lstr_next = *list;
132 b2 = strchr(b1, ']');
133 if (b2 == NULL || b2 == b1 + 1)
141 sep = strchr(expr, ',');
147 if (sscanf(expr, "%u%n", &x, &n) >= 1 && n == nob) {
149 new_lstrs(list, l->lstr_str, b2, x, x, 1);
154 if (sscanf(expr, "%u-%u%n", &x, &y, &n) >= 2 && n == nob &&
157 new_lstrs(list, l->lstr_str, b2, x, y, 1);
162 if (sscanf(expr, "%u-%u/%u%n", &x, &y, &z, &n) >= 3 && n == nob &&
165 new_lstrs(list, l->lstr_str, b2, x, y, z);
171 } while ((expr = sep) != NULL);
179 expand_strs(char *str, lstr_t **head)
187 l = alloc_lstr(strlen(str) + 1);
188 memcpy(l->lstr_str, str, strlen(str) + 1);
196 while ((l = list) != NULL) {
199 rc = expand_lstr(&nlist, l);
201 fprintf(stderr, "Syntax error in \"%s\"\n", str);
209 /* re-order onto 'list' */
210 while ((l = nlist) != NULL) {
211 nlist = l->lstr_next;
216 } while (expanded && rc > 0);
223 while ((l = list) != NULL) {
232 lst_parse_nids(char *str, int *countp, struct lnet_process_id **idspp)
240 rc = expand_strs(str, &head);
250 *idspp = malloc(c * sizeof(struct lnet_process_id));
251 if (*idspp == NULL) {
252 fprintf(stderr, "Out of memory\n");
259 while ((l = head) != NULL) {
263 (*idspp)[i].nid = libcfs_str2nid(l->lstr_str);
264 if ((*idspp)[i].nid == LNET_NID_ANY) {
265 fprintf(stderr, "Invalid nid: %s\n",
270 (*idspp)[i].pid = LNET_PID_LUSTRE;
287 lst_node_state2str(int state)
289 if (state == LST_NODE_ACTIVE)
291 if (state == LST_NODE_BUSY)
293 if (state == LST_NODE_DOWN)
300 lst_node_str2state(char *str)
302 if (strcasecmp(str, "active") == 0)
303 return LST_NODE_ACTIVE;
304 if (strcasecmp(str, "busy") == 0)
305 return LST_NODE_BUSY;
306 if (strcasecmp(str, "down") == 0)
307 return LST_NODE_DOWN;
308 if (strcasecmp(str, "unknown") == 0)
309 return LST_NODE_UNKNOWN;
310 if (strcasecmp(str, "invalid") == 0)
311 return (LST_NODE_UNKNOWN | LST_NODE_DOWN | LST_NODE_BUSY);
317 lst_test_type2name(int type)
319 if (type == LST_TEST_PING)
321 if (type == LST_TEST_BULK)
328 lst_test_name2type(char *name)
330 if (strcasecmp(name, "ping") == 0)
331 return LST_TEST_PING;
332 if (strcasecmp(name, "brw") == 0)
333 return LST_TEST_BULK;
339 lst_print_usage(char *cmd)
341 char *argv[] = { "help", cmd };
343 cfs_parser(2, argv, NULL);
347 lst_print_error(char *sub, const char *def_format, ...)
351 /* local error returned from kernel */
354 fprintf(stderr, "No session exists\n");
357 fprintf(stderr, "Session is shutting down\n");
360 fprintf(stderr, "Unmatched session key or not root\n");
363 fprintf(stderr, "Can't find %s in current session\n", sub);
366 fprintf(stderr, "Invalid parameters list in command line\n");
369 fprintf(stderr, "Bad parameter address\n");
372 fprintf(stderr, "%s already exists\n", sub);
375 va_start(ap, def_format);
376 vfprintf(stderr, def_format, ap);
384 lst_free_rpcent(struct list_head *head)
386 struct lstcon_rpc_ent *ent;
388 while (!list_empty(head)) {
389 ent = list_first_entry(head, struct lstcon_rpc_ent, rpe_link);
391 list_del(&ent->rpe_link);
397 lst_reset_rpcent(struct list_head *head)
399 struct lstcon_rpc_ent *ent;
401 list_for_each_entry(ent, head, rpe_link) {
402 ent->rpe_sid = LST_INVALID_SID;
403 ent->rpe_peer.nid = LNET_NID_ANY;
404 ent->rpe_peer.pid = LNET_PID_ANY;
405 ent->rpe_rpc_errno = ent->rpe_fwk_errno = 0;
410 lst_alloc_rpcent(struct list_head *head, int count, int offset)
412 struct lstcon_rpc_ent *ent;
415 for (i = 0; i < count; i++) {
416 ent = malloc(offsetof(struct lstcon_rpc_ent, rpe_payload[offset]));
418 lst_free_rpcent(head);
422 memset(ent, 0, offsetof(struct lstcon_rpc_ent, rpe_payload[offset]));
424 ent->rpe_sid = LST_INVALID_SID;
425 ent->rpe_peer.nid = LNET_NID_ANY;
426 ent->rpe_peer.pid = LNET_PID_ANY;
427 list_add(&ent->rpe_link, head);
434 lst_print_transerr(struct list_head *head, char *optstr)
436 struct lstcon_rpc_ent *ent;
438 list_for_each_entry(ent, head, rpe_link) {
439 if (ent->rpe_rpc_errno == 0 && ent->rpe_fwk_errno == 0)
442 if (ent->rpe_rpc_errno != 0) {
443 fprintf(stderr, "%s RPC failed on %s: %s\n",
444 optstr, libcfs_id2str(ent->rpe_peer),
445 strerror(ent->rpe_rpc_errno));
449 fprintf(stderr, "operation %s failed on %s: %s\n",
450 optstr, libcfs_id2str(ent->rpe_peer),
451 strerror(ent->rpe_fwk_errno));
456 lst_ioctl(unsigned int opc, void *buf, int len)
458 struct libcfs_ioctl_data data;
461 LIBCFS_IOC_INIT (data);
462 data.ioc_u32[0] = opc;
463 data.ioc_plen1 = len;
464 data.ioc_pbuf1 = (char *)buf;
465 data.ioc_plen2 = sizeof(trans_stat);
466 data.ioc_pbuf2 = (char *)&trans_stat;
468 memset(&trans_stat, 0, sizeof(trans_stat));
470 rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_LNETST, &data);
472 /* local error, no valid RPC result */
477 if (trans_stat.trs_rpc_errno != 0)
480 /* Framework error */
481 if (trans_stat.trs_fwk_errno != 0)
487 static int lst_yaml_session(const char *label, const char *timeout, int nlflags,
490 struct lstcon_ndlist_ent ndinfo = { };
491 struct lst_sid sid = LST_INVALID_SID;
492 /* nlflags being zero means we are destroying the session.
493 * No parsing of reply needed.
495 bool done = nlflags ? false : true;
496 char nid[LNET_NIDSTR_SIZE];
497 char name[LST_NAME_SIZE];
498 unsigned int key = 0;
499 yaml_emitter_t request;
505 sk = nl_socket_alloc();
509 /* Note: NL_AUTO_PID == zero which we use by default for the
510 * session_key when creating a new session. This is considered
511 * an invalid key so we need to get the real session key from
512 * the yaml parser yet to be created. If the user did request
513 * a specific session key then set the socket's port id to this
517 nl_socket_set_local_port(sk, session_key);
519 /* Setup reply parser to recieve Netlink packets */
520 rc = yaml_parser_initialize(&reply);
526 rc = yaml_parser_set_input_netlink(&reply, sk, false);
530 /* Create Netlink emitter to send request to kernel */
531 yaml_emitter_initialize(&request);
532 rc = yaml_emitter_set_output_netlink(&request, sk,
533 LNET_SELFTEST_GENL_NAME,
534 LNET_SELFTEST_GENL_VERSION,
535 LNET_SELFTEST_CMD_SESSIONS,
540 yaml_emitter_open(&request);
541 yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
542 rc = yaml_emitter_emit(&request, &event);
546 yaml_mapping_start_event_initialize(&event, NULL,
547 (yaml_char_t *)YAML_MAP_TAG,
548 1, YAML_BLOCK_MAPPING_STYLE);
549 rc = yaml_emitter_emit(&request, &event);
553 yaml_scalar_event_initialize(&event, NULL,
554 (yaml_char_t *)YAML_STR_TAG,
555 (yaml_char_t *)"sessions",
556 strlen("sessions"), 1, 0,
557 YAML_PLAIN_SCALAR_STYLE);
558 rc = yaml_emitter_emit(&request, &event);
563 yaml_scalar_event_initialize(&event, NULL,
564 (yaml_char_t *)YAML_STR_TAG,
567 YAML_PLAIN_SCALAR_STYLE);
568 rc = yaml_emitter_emit(&request, &event);
574 /* sessions: { name: 'name', timeout: 300 }
580 yaml_mapping_start_event_initialize(&event, NULL,
581 (yaml_char_t *)YAML_MAP_TAG,
582 1, YAML_FLOW_MAPPING_STYLE);
583 rc = yaml_emitter_emit(&request, &event);
587 yaml_scalar_event_initialize(&event, NULL,
588 (yaml_char_t *)YAML_STR_TAG,
589 (yaml_char_t *)"name",
590 strlen("name"), 1, 0,
591 YAML_PLAIN_SCALAR_STYLE);
592 rc = yaml_emitter_emit(&request, &event);
596 yaml_scalar_event_initialize(&event, NULL,
597 (yaml_char_t *)YAML_STR_TAG,
598 (yaml_char_t *)label,
600 YAML_PLAIN_SCALAR_STYLE);
601 rc = yaml_emitter_emit(&request, &event);
606 yaml_scalar_event_initialize(&event, NULL,
607 (yaml_char_t *)YAML_STR_TAG,
608 (yaml_char_t *)"timeout",
609 strlen("timeout"), 1, 0,
610 YAML_PLAIN_SCALAR_STYLE);
611 rc = yaml_emitter_emit(&request, &event);
615 yaml_scalar_event_initialize(&event, NULL,
616 (yaml_char_t *)YAML_STR_TAG,
617 (yaml_char_t *)timeout,
618 strlen(timeout), 1, 0,
619 YAML_PLAIN_SCALAR_STYLE);
620 rc = yaml_emitter_emit(&request, &event);
625 yaml_mapping_end_event_initialize(&event);
626 rc = yaml_emitter_emit(&request, &event);
631 yaml_mapping_end_event_initialize(&event);
632 rc = yaml_emitter_emit(&request, &event);
636 yaml_document_end_event_initialize(&event, 0);
637 rc = yaml_emitter_emit(&request, &event);
641 rc = yaml_emitter_close(&request);
644 yaml_emitter_log_error(&request, stderr);
645 yaml_emitter_delete(&request);
649 yaml_emitter_delete(&request);
652 rc = yaml_parser_parse(&reply, &event);
656 if (event.type == YAML_SCALAR_EVENT) {
657 char *tmp, *endp = NULL;
659 if (strcmp((char *)event.data.scalar.value,
661 yaml_event_delete(&event);
662 rc = yaml_parser_parse(&reply, &event);
666 strncpy(name, (char *)event.data.scalar.value,
670 if (strcmp((char *)event.data.scalar.value,
672 yaml_event_delete(&event);
673 rc = yaml_parser_parse(&reply, &event);
677 tmp = (char *)event.data.scalar.value;
678 key = strtoul(tmp, &endp, 10);
683 if (strcmp((char *)event.data.scalar.value,
685 yaml_event_delete(&event);
686 rc = yaml_parser_parse(&reply, &event);
690 tmp = (char *)event.data.scalar.value;
691 sid.ses_stamp = strtoll(tmp, &endp, 10);
696 if (strcmp((char *)event.data.scalar.value,
698 yaml_event_delete(&event);
699 rc = yaml_parser_parse(&reply, &event);
703 strncpy(nid, (char *)event.data.scalar.value,
707 if (strcmp((char *)event.data.scalar.value,
709 yaml_event_delete(&event);
710 rc = yaml_parser_parse(&reply, &event);
714 tmp = (char *)event.data.scalar.value;
715 ndinfo.nle_nnode = strtoul(tmp, &endp, 10);
721 done = (event.type == YAML_STREAM_END_EVENT);
723 yaml_event_delete(&event);
726 if (nlflags & NLM_F_CREATE) {
727 session_features = yaml_parser_get_reader_proto_version(&reply);
731 if (rc == 0 && errmsg)
732 yaml_parser_log_error(&reply, stderr, errmsg);
733 yaml_parser_delete(&reply);
736 if (((nlflags & NLM_F_DUMP) == NLM_F_DUMP) && rc != 0) {
738 "%s ID: %ju@%s, KEY: %u FEATURES: %x NODES: %d\n",
739 name, (uintmax_t)sid.ses_stamp, nid,
740 key, session_features, ndinfo.nle_nnode);
743 return rc == 0 ? -1 : 0;
747 lst_new_session_ioctl(char *name, int timeout, int force, struct lst_sid *sid)
749 struct lstio_session_new_args args = { 0 };
751 args.lstio_ses_key = session_key;
752 args.lstio_ses_timeout = timeout;
753 args.lstio_ses_force = force;
754 args.lstio_ses_idp = sid;
755 args.lstio_ses_feats = session_features;
756 args.lstio_ses_nmlen = strlen(name);
757 args.lstio_ses_namep = name;
759 return lst_ioctl (LSTIO_SESSION_NEW, &args, sizeof(args));
763 jt_lst_new_session(int argc, char **argv)
765 char buf[LST_NAME_SIZE * 2 + 1];
766 char *name, *timeout_s = NULL;
767 int nlflags = NLM_F_CREATE;
768 struct lst_sid session_id;
775 static const struct option session_opts[] = {
776 { .name = "timeout", .has_arg = required_argument, .val = 't' },
777 { .name = "force", .has_arg = no_argument, .val = 'f' },
781 c = getopt_long(argc, argv, "ft:",
782 session_opts, &optidx);
788 nlflags |= NLM_F_REPLACE;
795 lst_print_usage(argv[0]);
801 timeout = atoi(timeout_s);
803 fprintf(stderr, "Invalid timeout value\n");
808 if (optind == argc - 1) {
809 name = argv[optind ++];
810 if (strlen(name) >= LST_NAME_SIZE) {
811 fprintf(stderr, "Name size is limited to %d\n",
815 } else if (optind == argc) {
816 char user[LST_NAME_SIZE];
817 char host[LST_NAME_SIZE];
818 struct passwd *pw = getpwuid(getuid());
821 snprintf(user, sizeof(user), "%d", (int)getuid());
823 snprintf(user, sizeof(user), "%s", pw->pw_name);
825 rc = gethostname(host, sizeof(host));
827 snprintf(host, sizeof(host), "unknown_host");
829 snprintf(buf, sizeof(buf), "%s@%s", user, host);
832 lst_print_usage(argv[0]);
836 rc = lst_yaml_session(name, timeout_s, nlflags, "new session");
840 if (session_key == 0) {
842 "Can't find env LST_SESSION or value is not valid\n");
846 rc = lst_new_session_ioctl(name, timeout, force, &session_id);
848 lst_print_error("session", "Failed to create session: %s\n",
853 fprintf(stdout, "SESSION: %s FEATURES: %x TIMEOUT: %d FORCE: %s\n",
854 name, session_features, timeout, force ? "Yes" : "No");
859 lst_session_info_ioctl(char *name, int len, int *key, unsigned *featp,
860 struct lst_sid *sid, struct lstcon_ndlist_ent *ndinfo)
862 struct lstio_session_info_args args = { 0 };
864 args.lstio_ses_idp = sid;
865 args.lstio_ses_keyp = key;
866 args.lstio_ses_featp = featp;
867 args.lstio_ses_ndinfo = ndinfo;
868 args.lstio_ses_nmlen = len;
869 args.lstio_ses_namep = name;
871 return lst_ioctl(LSTIO_SESSION_INFO, &args, sizeof(args));
875 jt_lst_show_session(int argc, char **argv)
877 struct lstcon_ndlist_ent ndinfo;
879 char name[LST_NAME_SIZE];
884 rc = lst_yaml_session(NULL, NULL, NLM_F_DUMP, "show session");
888 rc = lst_session_info_ioctl(name, sizeof(name), &key,
889 &feats, &sid, &ndinfo);
892 lst_print_error("session", "Failed to show session: %s\n",
897 fprintf(stdout, "%s ID: %ju@%s, KEY: %d FEATURES: %x NODES: %d\n",
898 name, (uintmax_t)sid.ses_stamp, libcfs_nid2str(sid.ses_nid),
899 key, feats, ndinfo.nle_nnode);
905 lst_end_session_ioctl(void)
907 struct lstio_session_end_args args = { 0 };
909 args.lstio_ses_key = session_key;
910 return lst_ioctl(LSTIO_SESSION_END, &args, sizeof(args));
914 jt_lst_end_session(int argc, char **argv)
918 if (session_key == 0) {
920 "Can't find env LST_SESSION or value is not valid\n");
924 rc = lst_yaml_session(NULL, NULL, 0, "end session");
928 rc = lst_end_session_ioctl();
931 fprintf(stdout, "session is ended\n");
936 lst_print_error("session", "Failed to end session: %s\n",
941 if (trans_stat.trs_rpc_errno != 0) {
943 "[RPC] Failed to send %d session RPCs: %s\n",
944 lstcon_rpc_stat_failure(&trans_stat, 0),
945 strerror(trans_stat.trs_rpc_errno));
948 if (trans_stat.trs_fwk_errno != 0) {
950 "[FWK] Failed to end session on %d nodes: %s\n",
951 lstcon_sesop_stat_failure(&trans_stat, 0),
952 strerror(trans_stat.trs_fwk_errno));
958 #define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
960 static int lst_yaml_display_groups(yaml_parser_t *reply, char *group,
961 int states, bool print)
967 char name[LST_NAME_SIZE] = {};
972 fprintf(stdout, LST_NODES_TITLE);
975 rc = yaml_parser_parse(reply, &event);
979 if (event.type == YAML_MAPPING_START_EVENT) {
983 rc = yaml_parser_parse(reply, &next);
987 if (next.type != YAML_SCALAR_EVENT) {
988 yaml_event_delete(&next);
992 value = (char *)next.data.scalar.value;
993 if (strcmp(value, "groups") == 0) {
994 yaml_event_delete(&next);
995 } else if (strcmp(value, "nid") == 0) {
999 rc = yaml_parser_parse(reply, &next);
1003 fprintf(stdout, "\t%s: ",
1004 (char *)next.data.scalar.value);
1006 rc = yaml_parser_parse(reply, &next);
1010 tmp = (char *)next.data.scalar.value;
1011 if (strcmp(tmp, "status") == 0) {
1014 rc = yaml_parser_parse(reply, &state);
1018 fprintf(stdout, "%s\n",
1019 (char *)state.data.scalar.value);
1025 rc = yaml_parser_parse(reply, &next);
1029 strncpy(name, value, sizeof(name) - 1);
1030 fprintf(stdout, "Group [ %s ]\n", name);
1033 if (next.type != YAML_SEQUENCE_START_EVENT) {
1035 "No nodes found [ %s ]\n",
1039 } else if (event.type == YAML_SEQUENCE_END_EVENT &&
1041 fprintf(stdout, "Total %d nodes [ %s ]\n",
1046 done = (event.type == YAML_STREAM_END_EVENT);
1047 yaml_event_delete(&event);
1050 int active = 0, busy = 0, down = 0, unknown = 0;
1051 char group[LST_NAME_SIZE];
1055 rc = yaml_parser_parse(reply, &event);
1059 if (event.type == YAML_SCALAR_EVENT) {
1060 char *value = (char *)event.data.scalar.value;
1063 value = (char *)event.data.scalar.value;
1064 if (strcmp(value, "groups") == 0) {
1065 yaml_event_delete(&event);
1069 rc = yaml_parser_parse(reply, &next);
1073 if (next.type == YAML_SCALAR_EVENT) {
1076 status = lst_node_str2state((char *)next.data.scalar.value);
1078 case LST_NODE_ACTIVE:
1087 case LST_NODE_UNKNOWN:
1092 } else if (next.type == YAML_SEQUENCE_START_EVENT) {
1093 strncpy(group, value, sizeof(group) - 1);
1099 yaml_event_delete(&next);
1100 } else if (event.type == YAML_SEQUENCE_END_EVENT) {
1101 if (strlen(group)) {
1102 fprintf(stdout, "\t%d\t%d\t%d\t%d\t%d\t%s\n",
1103 active, busy, down, unknown,
1104 active + busy + down + unknown, group);
1106 memset(group, 0, sizeof(group));
1108 done = (event.type == YAML_STREAM_END_EVENT);
1109 yaml_event_delete(&event);
1116 rc = yaml_parser_parse(reply, &event);
1120 if (event.type == YAML_SCALAR_EVENT) {
1123 value = (char *)event.data.scalar.value;
1124 if (strlen(value) &&
1125 strcmp(value, "groups") != 0) {
1127 fprintf(stdout, "%d) %s\n",
1132 done = (event.type == YAML_STREAM_END_EVENT);
1134 yaml_event_delete(&event);
1137 fprintf(stdout, "Total %d groups\n", i - 1);
1145 #define LST_NODES_TITLE "\tACTIVE\tBUSY\tDOWN\tUNKNOWN\tTOTAL\n"
1147 static int lst_yaml_groups(int nlflags, char *name, int states, bool print)
1149 yaml_emitter_t request;
1150 yaml_parser_t reply;
1155 sk = nl_socket_alloc();
1159 /* Setup reply parser to recieve Netlink packets */
1160 rc = yaml_parser_initialize(&reply);
1166 rc = yaml_parser_set_input_netlink(&reply, sk, false);
1170 /* Create Netlink emitter to send request to kernel */
1171 yaml_emitter_initialize(&request);
1172 rc = yaml_emitter_set_output_netlink(&request, sk,
1173 LNET_SELFTEST_GENL_NAME,
1174 LNET_SELFTEST_GENL_VERSION,
1175 LNET_SELFTEST_CMD_GROUPS,
1180 yaml_emitter_open(&request);
1181 yaml_document_start_event_initialize(&event, NULL, NULL, NULL, 0);
1182 rc = yaml_emitter_emit(&request, &event);
1186 yaml_mapping_start_event_initialize(&event, NULL,
1187 (yaml_char_t *)YAML_MAP_TAG,
1188 1, YAML_BLOCK_MAPPING_STYLE);
1189 rc = yaml_emitter_emit(&request, &event);
1193 yaml_scalar_event_initialize(&event, NULL,
1194 (yaml_char_t *)YAML_STR_TAG,
1195 (yaml_char_t *)"groups",
1196 strlen("groups"), 1, 0,
1197 YAML_PLAIN_SCALAR_STYLE);
1198 rc = yaml_emitter_emit(&request, &event);
1203 yaml_sequence_start_event_initialize(&event, NULL,
1204 (yaml_char_t *)YAML_SEQ_TAG,
1205 1, YAML_BLOCK_SEQUENCE_STYLE);
1206 rc = yaml_emitter_emit(&request, &event);
1210 yaml_mapping_start_event_initialize(&event, NULL,
1211 (yaml_char_t *)YAML_MAP_TAG,
1212 1, YAML_BLOCK_MAPPING_STYLE);
1213 rc = yaml_emitter_emit(&request, &event);
1217 yaml_scalar_event_initialize(&event, NULL,
1218 (yaml_char_t *)YAML_STR_TAG,
1219 (yaml_char_t *)name,
1221 YAML_PLAIN_SCALAR_STYLE);
1222 rc = yaml_emitter_emit(&request, &event);
1227 int max = ffs(LST_NODE_UNKNOWN) + 1, i;
1230 yaml_sequence_start_event_initialize(&event, NULL,
1231 (yaml_char_t *)YAML_SEQ_TAG,
1232 1, YAML_BLOCK_SEQUENCE_STYLE);
1233 rc = yaml_emitter_emit(&request, &event);
1238 for (i = 0; i < max; i++) {
1239 int mask = states & (1 << i);
1241 state = lst_node_state2str(mask);
1242 if (mask != LST_NODE_UNKNOWN && strcmp(state, "Unknown") == 0)
1245 yaml_mapping_start_event_initialize(&event, NULL,
1246 (yaml_char_t *)YAML_MAP_TAG,
1247 1, YAML_BLOCK_MAPPING_STYLE);
1248 rc = yaml_emitter_emit(&request, &event);
1252 yaml_scalar_event_initialize(&event, NULL,
1253 (yaml_char_t *)YAML_STR_TAG,
1254 (yaml_char_t *)"status",
1255 strlen("status"), 1, 0,
1256 YAML_PLAIN_SCALAR_STYLE);
1257 rc = yaml_emitter_emit(&request, &event);
1261 yaml_scalar_event_initialize(&event, NULL,
1262 (yaml_char_t *)YAML_STR_TAG,
1263 (yaml_char_t *)state,
1264 strlen(state), 1, 0,
1265 YAML_PLAIN_SCALAR_STYLE);
1266 rc = yaml_emitter_emit(&request, &event);
1270 yaml_mapping_end_event_initialize(&event);
1271 rc = yaml_emitter_emit(&request, &event);
1276 yaml_sequence_end_event_initialize(&event);
1277 rc = yaml_emitter_emit(&request, &event);
1281 yaml_scalar_event_initialize(&event, NULL,
1282 (yaml_char_t *)YAML_STR_TAG,
1285 YAML_PLAIN_SCALAR_STYLE);
1286 rc = yaml_emitter_emit(&request, &event);
1291 yaml_mapping_end_event_initialize(&event);
1292 rc = yaml_emitter_emit(&request, &event);
1296 yaml_sequence_end_event_initialize(&event);
1297 rc = yaml_emitter_emit(&request, &event);
1301 yaml_scalar_event_initialize(&event, NULL,
1302 (yaml_char_t *)YAML_STR_TAG,
1305 YAML_PLAIN_SCALAR_STYLE);
1306 rc = yaml_emitter_emit(&request, &event);
1310 yaml_mapping_end_event_initialize(&event);
1311 rc = yaml_emitter_emit(&request, &event);
1315 yaml_document_end_event_initialize(&event, 0);
1316 rc = yaml_emitter_emit(&request, &event);
1320 rc = yaml_emitter_close(&request);
1323 yaml_emitter_log_error(&request, stderr);
1324 yaml_emitter_delete(&request);
1328 yaml_emitter_delete(&request);
1330 /* display output */
1331 if (nlflags == NLM_F_DUMP)
1332 rc = lst_yaml_display_groups(&reply, name, states, print);
1335 yaml_parser_log_error(&reply, stderr, NULL);
1336 yaml_parser_delete(&reply);
1340 rc = rc == 1 ? 0 : -EINVAL;
1346 lst_ping_ioctl(char *str, int type, int timeout,
1347 int count, struct lnet_process_id *ids, struct list_head *head)
1349 struct lstio_debug_args args = { 0 };
1351 args.lstio_dbg_key = session_key;
1352 args.lstio_dbg_type = type;
1353 args.lstio_dbg_flags = 0;
1354 args.lstio_dbg_timeout = timeout;
1355 args.lstio_dbg_nmlen = (str == NULL) ? 0: strlen(str);
1356 args.lstio_dbg_namep = str;
1357 args.lstio_dbg_count = count;
1358 args.lstio_dbg_idsp = ids;
1359 args.lstio_dbg_resultp = head;
1361 return lst_ioctl (LSTIO_DEBUG, &args, sizeof(args));
1365 lst_get_node_count(int type, char *str, int *countp,
1366 struct lnet_process_id **idspp)
1368 char buf[LST_NAME_SIZE];
1369 struct lstcon_test_batch_ent ent;
1370 struct lstcon_ndlist_ent *entp = &ent.tbe_cli_nle;
1377 case LST_OPC_SESSION:
1378 rc = lst_session_info_ioctl(buf, LST_NAME_SIZE,
1379 &key, &feats, &sid, entp);
1382 case LST_OPC_BATCHSRV:
1383 entp = &ent.tbe_srv_nle;
1384 case LST_OPC_BATCHCLI:
1385 rc = lst_info_batch_ioctl(str, 0, 0, &ent, NULL, NULL, NULL);
1389 rc = lst_yaml_groups(NLM_F_DUMP, NULL, 0, false);
1390 if (rc == -EOPNOTSUPP) {
1391 rc = lst_info_group_ioctl(str, entp, NULL, NULL, NULL);
1392 } else if (rc > 0) {
1393 entp->nle_nnode = rc;
1399 rc = lst_parse_nids(str, &entp->nle_nnode, idspp) < 0 ? -1 : 0;
1408 *countp = entp->nle_nnode;
1414 jt_lst_ping(int argc, char **argv)
1416 struct list_head head;
1417 struct lnet_process_id *ids = NULL;
1418 struct lstcon_rpc_ent *ent = NULL;
1428 static const struct option ping_opts[] = {
1429 { .name = "session", .has_arg = no_argument, .val = 's' },
1430 { .name = "server", .has_arg = no_argument, .val = 'v' },
1431 { .name = "batch", .has_arg = required_argument, .val = 'b' },
1432 { .name = "group", .has_arg = required_argument, .val = 'g' },
1433 { .name = "nodes", .has_arg = required_argument, .val = 'n' },
1434 { .name = "timeout", .has_arg = required_argument, .val = 't' },
1435 { .name = NULL, } };
1437 if (session_key == 0) {
1439 "Can't find env LST_SESSION or value is not valid\n");
1445 c = getopt_long(argc, argv, "g:b:n:t:sv",
1446 ping_opts, &optidx);
1453 type = LST_OPC_SESSION;
1457 type = LST_OPC_GROUP;
1462 type = LST_OPC_BATCHCLI;
1467 type = LST_OPC_NODES;
1472 timeout = atoi(optarg);
1480 lst_print_usage(argv[0]);
1485 if (type == 0 || timeout <= 0 || optind != argc) {
1486 lst_print_usage(argv[0]);
1490 if (type == LST_OPC_BATCHCLI && server)
1491 type = LST_OPC_BATCHSRV;
1493 rc = lst_get_node_count(type, str, &count, &ids);
1495 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
1496 (str == NULL) ? "session" : str, strerror(errno));
1500 INIT_LIST_HEAD(&head);
1502 rc = lst_alloc_rpcent(&head, count, LST_NAME_SIZE);
1504 fprintf(stderr, "Out of memory\n");
1509 fprintf(stdout, "Target %s is empty\n",
1510 (str == NULL) ? "session" : str);
1514 rc = lst_ping_ioctl(str, type, timeout, count, ids, &head);
1515 if (rc == -1) { /* local failure */
1516 lst_print_error("debug", "Failed to ping %s: %s\n",
1517 (str == NULL) ? "session" : str,
1523 /* ignore RPC errors and framwork errors */
1524 list_for_each_entry(ent, &head, rpe_link) {
1525 fprintf(stdout, "\t%s: %s [session: %s id: %s]\n",
1526 libcfs_id2str(ent->rpe_peer),
1527 lst_node_state2str(ent->rpe_state),
1528 (ent->rpe_state == LST_NODE_ACTIVE ||
1529 ent->rpe_state == LST_NODE_BUSY) ?
1530 (ent->rpe_rpc_errno == 0 ?
1531 &ent->rpe_payload[0] : "Unknown") :
1532 "<NULL>", libcfs_nid2str(ent->rpe_sid.ses_nid));
1536 lst_free_rpcent(&head);
1546 lst_add_nodes_ioctl(char *name, int count, struct lnet_process_id *ids,
1547 unsigned *featp, struct list_head *resultp)
1549 struct lstio_group_nodes_args args = { 0 };
1551 args.lstio_grp_key = session_key;
1552 args.lstio_grp_nmlen = strlen(name);
1553 args.lstio_grp_namep = name;
1554 args.lstio_grp_count = count;
1555 args.lstio_grp_featp = featp;
1556 args.lstio_grp_idsp = ids;
1557 args.lstio_grp_resultp = resultp;
1559 return lst_ioctl(LSTIO_NODES_ADD, &args, sizeof(args));
1563 lst_del_group_ioctl(char *name)
1565 struct lstio_group_del_args args = { 0 };
1567 args.lstio_grp_key = session_key;
1568 args.lstio_grp_nmlen = strlen(name);
1569 args.lstio_grp_namep = name;
1571 return lst_ioctl(LSTIO_GROUP_DEL, &args, sizeof(args));
1575 lst_del_group(char *grp_name)
1579 rc = lst_del_group_ioctl(grp_name);
1581 fprintf(stdout, "Group is deleted\n");
1586 lst_print_error("group", "Failed to delete group: %s\n",
1591 fprintf(stderr, "Group is deleted with some errors\n");
1593 if (trans_stat.trs_rpc_errno != 0) {
1595 "[RPC] Failed to send %d end session RPCs: %s\n",
1596 lstcon_rpc_stat_failure(&trans_stat, 0),
1597 strerror(trans_stat.trs_rpc_errno));
1600 if (trans_stat.trs_fwk_errno != 0) {
1602 "[FWK] Failed to end session on %d nodes: %s\n",
1603 lstcon_sesop_stat_failure(&trans_stat, 0),
1604 strerror(trans_stat.trs_fwk_errno));
1611 lst_add_group_ioctl(char *name)
1613 struct lstio_group_add_args args = { 0 };
1615 args.lstio_grp_key = session_key;
1616 args.lstio_grp_nmlen = strlen(name);
1617 args.lstio_grp_namep = name;
1619 return lst_ioctl(LSTIO_GROUP_ADD, &args, sizeof(args));
1623 jt_lst_add_group(int argc, char **argv)
1625 struct list_head head;
1626 struct lnet_process_id *ids;
1628 unsigned feats = session_features;
1632 bool nodes_added = false;
1634 if (session_key == 0) {
1636 "Can't find env LST_SESSION or value is not valid\n");
1641 lst_print_usage(argv[0]);
1646 if (strlen(name) >= LST_NAME_SIZE) {
1647 fprintf(stderr, "Name length is limited to %d\n",
1652 rc = lst_add_group_ioctl(name);
1654 lst_print_error("group", "Failed to add group %s: %s\n",
1655 name, strerror(errno));
1659 INIT_LIST_HEAD(&head);
1661 for (i = 2; i < argc; i++) {
1662 /* parse address list */
1663 rc = lst_parse_nids(argv[i], &count, &ids);
1665 fprintf(stderr, "Ignore invalid id list %s\n",
1673 rc = lst_alloc_rpcent(&head, count, 0);
1675 fprintf(stderr, "Out of memory\n");
1681 rc = lst_add_nodes_ioctl(name, count, ids, &feats, &head);
1688 fprintf(stdout, "%s are added to session\n", argv[i]);
1692 if ((feats & session_features) != session_features) {
1694 "Warning, this session will run with "
1695 "compatible mode because some test nodes "
1696 "might not understand these features: %x\n",
1697 (~feats & session_features));
1700 lst_free_rpcent(&head);
1705 * The selftest kernel module expects that a group should
1706 * have at least one node, since it doesn't make sense for
1707 * an empty group to be added to a test.
1710 "No nodes added successfully, deleting group %s\n",
1712 rc = lst_del_group(name);
1715 "Failed to delete group %s."
1716 " Group is empty.\n", name);
1724 lst_print_error("group", "Failed to add nodes %s: %s\n",
1725 argv[i], strerror(errno));
1728 if (trans_stat.trs_fwk_errno == EPROTO) {
1730 "test nodes might have different LST "
1731 "features, please disable some features by "
1732 "setting LST_FEATURES\n");
1735 lst_print_transerr(&head, "create session");
1738 lst_free_rpcent(&head);
1742 "No nodes added successfully, deleting group %s\n",
1744 if (lst_del_group(name) != 0) {
1746 "Failed to delete group %s."
1747 " Group is empty.\n", name);
1755 jt_lst_del_group(int argc, char **argv)
1759 if (session_key == 0) {
1761 "Can't find env LST_SESSION or value is not valid\n");
1766 lst_print_usage(argv[0]);
1770 rc = lst_del_group(argv[1]);
1776 lst_update_group_ioctl(int opc, char *name, int clean, int count,
1777 struct lnet_process_id *ids, struct list_head *resultp)
1779 struct lstio_group_update_args args = { 0 };
1781 args.lstio_grp_key = session_key;
1782 args.lstio_grp_opc = opc;
1783 args.lstio_grp_args = clean;
1784 args.lstio_grp_nmlen = strlen(name);
1785 args.lstio_grp_namep = name;
1786 args.lstio_grp_count = count;
1787 args.lstio_grp_idsp = ids;
1788 args.lstio_grp_resultp = resultp;
1790 return lst_ioctl(LSTIO_GROUP_UPDATE, &args, sizeof(args));
1794 jt_lst_update_group(int argc, char **argv)
1796 struct list_head head;
1797 struct lnet_process_id *ids = NULL;
1807 static const struct option update_group_opts[] = {
1808 { .name = "refresh", .has_arg = no_argument, .val = 'f' },
1809 { .name = "clean", .has_arg = required_argument, .val = 'c' },
1810 { .name = "remove", .has_arg = required_argument, .val = 'r' },
1813 if (session_key == 0) {
1815 "Can't find env LST_SESSION or value is not valid\n");
1820 c = getopt_long(argc, argv, "fc:r:",
1821 update_group_opts, &optidx);
1823 /* Detect the end of the options. */
1830 lst_print_usage(argv[0]);
1833 opc = LST_GROUP_REFRESH;
1838 lst_print_usage(argv[0]);
1841 opc = LST_GROUP_RMND;
1846 clean = lst_node_str2state(optarg);
1847 if (opc != 0 || clean <= 0) {
1848 lst_print_usage(argv[0]);
1851 opc = LST_GROUP_CLEAN;
1855 lst_print_usage(argv[0]);
1860 /* no OPC or group is specified */
1861 if (opc == 0 || optind != argc - 1) {
1862 lst_print_usage(argv[0]);
1868 INIT_LIST_HEAD(&head);
1870 if (opc == LST_GROUP_RMND || opc == LST_GROUP_REFRESH) {
1871 rc = lst_get_node_count(opc == LST_GROUP_RMND ? LST_OPC_NODES :
1873 opc == LST_GROUP_RMND ? str : grp,
1877 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
1878 opc == LST_GROUP_RMND ? str : grp,
1883 rc = lst_alloc_rpcent(&head, count, 0);
1885 fprintf(stderr, "Out of memory\n");
1892 rc = lst_update_group_ioctl(opc, grp, clean, count, ids, &head);
1898 lst_free_rpcent(&head);
1903 lst_free_rpcent(&head);
1904 lst_print_error("group", "Failed to update group: %s\n",
1909 lst_print_transerr(&head, "Updating group");
1911 lst_free_rpcent(&head);
1917 lst_list_group_ioctl(int len, char *name, int idx)
1919 struct lstio_group_list_args args = { 0 };
1921 args.lstio_grp_key = session_key;
1922 args.lstio_grp_idx = idx;
1923 args.lstio_grp_nmlen = len;
1924 args.lstio_grp_namep = name;
1926 return lst_ioctl(LSTIO_GROUP_LIST, &args, sizeof(args));
1930 lst_info_group_ioctl(char *name, struct lstcon_ndlist_ent *gent,
1931 int *idx, int *count, struct lstcon_node_ent *dents)
1933 struct lstio_group_info_args args = { 0 };
1935 args.lstio_grp_key = session_key;
1936 args.lstio_grp_nmlen = strlen(name);
1937 args.lstio_grp_namep = name;
1938 args.lstio_grp_entp = gent;
1939 args.lstio_grp_idxp = idx;
1940 args.lstio_grp_ndentp = count;
1941 args.lstio_grp_dentsp = dents;
1943 return lst_ioctl(LSTIO_GROUP_INFO, &args, sizeof(args));
1947 lst_list_group_all(void)
1949 char name[LST_NAME_SIZE];
1953 /* no group is specified, list name of all groups */
1954 for (i = 0; ; i++) {
1955 rc = lst_list_group_ioctl(LST_NAME_SIZE, name, i);
1957 fprintf(stdout, "%d) %s\n", i + 1, name);
1961 if (errno == ENOENT)
1964 lst_print_error("group", "Failed to list group: %s\n",
1969 fprintf(stdout, "Total %d groups\n", i);
1975 jt_lst_list_group(int argc, char **argv)
1977 struct lstcon_ndlist_ent gent;
1978 struct lstcon_node_ent *dents;
1993 static const struct option list_group_opts[] = {
1994 { .name = "active", .has_arg = no_argument, .val = 'a' },
1995 { .name = "busy", .has_arg = no_argument, .val = 'b' },
1996 { .name = "down", .has_arg = no_argument, .val = 'd' },
1997 { .name = "unknown", .has_arg = no_argument, .val = 'u' },
1998 { .name = "all", .has_arg = no_argument, .val = 'l' },
1999 { .name = NULL, } };
2001 if (session_key == 0) {
2003 "Can't find env LST_SESSION or value is not valid\n");
2008 c = getopt_long(argc, argv, "abdul",
2009 list_group_opts, &optidx);
2016 verbose = active = 1;
2017 states |= LST_NODE_ACTIVE;
2022 states |= LST_NODE_BUSY;
2027 states |= LST_NODE_DOWN;
2031 verbose = unknown = 1;
2032 states |= LST_NODE_UNKNOWN;
2036 states |= LST_NODE_ACTIVE | LST_NODE_BUSY |
2037 LST_NODE_DOWN | LST_NODE_UNKNOWN;
2041 lst_print_usage(argv[0]);
2046 if (optind == argc) {
2047 rc = lst_yaml_groups(NLM_F_DUMP, NULL, 0, true);
2049 if (rc == -EOPNOTSUPP)
2054 for (i = optind; i < argc; i++) {
2055 rc = lst_yaml_groups(NLM_F_DUMP, argv[i], states,
2056 i == optind ? true : false);
2058 if (rc == -EOPNOTSUPP)
2066 if (optind == argc) {
2067 /* no group is specified, list name of all groups */
2068 rc = lst_list_group_all();
2074 fprintf(stdout, LST_NODES_TITLE);
2076 /* list nodes in specified groups */
2077 for (i = optind; i < argc; i++) {
2078 rc = lst_info_group_ioctl(argv[i], &gent, NULL, NULL, NULL);
2080 if (errno == ENOENT) {
2085 lst_print_error("group", "Failed to list group: %s\n",
2091 fprintf(stdout, "\t%d\t%d\t%d\t%d\t%d\t%s\n",
2092 gent.nle_nactive, gent.nle_nbusy,
2093 gent.nle_ndown, gent.nle_nunknown,
2094 gent.nle_nnode, argv[i]);
2098 fprintf(stdout, "Group [ %s ]\n", argv[i]);
2100 if (gent.nle_nnode == 0) {
2101 fprintf(stdout, "No nodes found [ %s ]\n", argv[i]);
2105 count = gent.nle_nnode;
2107 dents = malloc(count * sizeof(struct lstcon_node_ent));
2108 if (dents == NULL) {
2109 fprintf(stderr, "Failed to malloc: %s\n",
2115 rc = lst_info_group_ioctl(argv[i], &gent, &index, &count, dents);
2117 lst_print_error("group", "Failed to list group: %s\n",
2123 for (j = 0, c = 0; j < count; j++) {
2125 ((active && dents[j].nde_state == LST_NODE_ACTIVE) ||
2126 (busy && dents[j].nde_state == LST_NODE_BUSY) ||
2127 (down && dents[j].nde_state == LST_NODE_DOWN) ||
2128 (unknown && dents[j].nde_state == LST_NODE_UNKNOWN))) {
2130 fprintf(stdout, "\t%s: %s\n",
2131 libcfs_id2str(dents[j].nde_id),
2132 lst_node_state2str(dents[j].nde_state));
2137 fprintf(stdout, "Total %d nodes [ %s ]\n", c, argv[i]);
2146 lst_stat_ioctl(char *name, int count, struct lnet_process_id *idsp,
2147 int timeout, struct list_head *resultp)
2149 struct lstio_stat_args args = { 0 };
2151 args.lstio_sta_key = session_key;
2152 args.lstio_sta_timeout = timeout;
2153 args.lstio_sta_nmlen = strlen(name);
2154 args.lstio_sta_namep = name;
2155 args.lstio_sta_count = count;
2156 args.lstio_sta_idsp = idsp;
2157 args.lstio_sta_resultp = resultp;
2159 return lst_ioctl(LSTIO_STAT_QUERY, &args, sizeof(args));
2163 struct list_head srp_link;
2166 struct lnet_process_id *srp_ids;
2167 struct list_head srp_result[2];
2168 } lst_stat_req_param_t;
2171 lst_stat_req_param_free(lst_stat_req_param_t *srp)
2175 for (i = 0; i < 2; i++)
2176 lst_free_rpcent(&srp->srp_result[i]);
2178 if (srp->srp_ids != NULL)
2185 lst_stat_req_param_alloc(char *name, lst_stat_req_param_t **srpp, int save_old)
2187 lst_stat_req_param_t *srp = NULL;
2188 int count = save_old ? 2 : 1;
2192 srp = malloc(sizeof(*srp));
2196 memset(srp, 0, sizeof(*srp));
2197 INIT_LIST_HEAD(&srp->srp_result[0]);
2198 INIT_LIST_HEAD(&srp->srp_result[1]);
2200 rc = lst_get_node_count(LST_OPC_GROUP, name,
2201 &srp->srp_count, NULL);
2202 if (rc != 0 && errno == ENOENT) {
2203 rc = lst_get_node_count(LST_OPC_NODES, name,
2204 &srp->srp_count, &srp->srp_ids);
2209 "Failed to get count of nodes from %s: %s\n",
2210 name, strerror(errno));
2211 lst_stat_req_param_free(srp);
2216 srp->srp_name = name;
2218 for (i = 0; i < count; i++) {
2219 rc = lst_alloc_rpcent(&srp->srp_result[i], srp->srp_count,
2220 sizeof(struct sfw_counters) +
2221 sizeof(struct srpc_counters) +
2222 sizeof(struct lnet_counters_common));
2224 fprintf(stderr, "Out of memory\n");
2234 lst_stat_req_param_free(srp);
2242 } lst_srpc_stat_result;
2244 #define LST_LNET_AVG 0
2245 #define LST_LNET_MIN 1
2246 #define LST_LNET_MAX 2
2249 float lnet_avg_sndrate;
2250 float lnet_min_sndrate;
2251 float lnet_max_sndrate;
2252 float lnet_total_sndrate;
2254 float lnet_avg_rcvrate;
2255 float lnet_min_rcvrate;
2256 float lnet_max_rcvrate;
2257 float lnet_total_rcvrate;
2259 float lnet_avg_sndperf;
2260 float lnet_min_sndperf;
2261 float lnet_max_sndperf;
2262 float lnet_total_sndperf;
2264 float lnet_avg_rcvperf;
2265 float lnet_min_rcvperf;
2266 float lnet_max_rcvperf;
2267 float lnet_total_rcvperf;
2269 int lnet_stat_count;
2270 } lst_lnet_stat_result_t;
2272 lst_lnet_stat_result_t lnet_stat_result;
2275 lst_lnet_stat_value(int bw, int send, int off)
2279 p = bw ? &lnet_stat_result.lnet_avg_sndperf :
2280 &lnet_stat_result.lnet_avg_sndrate;
2291 lst_cal_lnet_stat(float delta, struct lnet_counters_common *lnet_new,
2292 struct lnet_counters_common *lnet_old, int mbs)
2296 unsigned int unit_divisor;
2298 unit_divisor = (mbs) ? (1000 * 1000) : (1024 * 1024);
2299 perf = (float)(lnet_new->lcc_send_length -
2300 lnet_old->lcc_send_length) / unit_divisor / delta;
2301 lnet_stat_result.lnet_total_sndperf += perf;
2303 if (lnet_stat_result.lnet_min_sndperf > perf ||
2304 lnet_stat_result.lnet_min_sndperf == 0)
2305 lnet_stat_result.lnet_min_sndperf = perf;
2307 if (lnet_stat_result.lnet_max_sndperf < perf)
2308 lnet_stat_result.lnet_max_sndperf = perf;
2310 perf = (float)(lnet_new->lcc_recv_length -
2311 lnet_old->lcc_recv_length) / unit_divisor / delta;
2312 lnet_stat_result.lnet_total_rcvperf += perf;
2314 if (lnet_stat_result.lnet_min_rcvperf > perf ||
2315 lnet_stat_result.lnet_min_rcvperf == 0)
2316 lnet_stat_result.lnet_min_rcvperf = perf;
2318 if (lnet_stat_result.lnet_max_rcvperf < perf)
2319 lnet_stat_result.lnet_max_rcvperf = perf;
2321 rate = (lnet_new->lcc_send_count - lnet_old->lcc_send_count) / delta;
2322 lnet_stat_result.lnet_total_sndrate += rate;
2324 if (lnet_stat_result.lnet_min_sndrate > rate ||
2325 lnet_stat_result.lnet_min_sndrate == 0)
2326 lnet_stat_result.lnet_min_sndrate = rate;
2328 if (lnet_stat_result.lnet_max_sndrate < rate)
2329 lnet_stat_result.lnet_max_sndrate = rate;
2331 rate = (lnet_new->lcc_recv_count - lnet_old->lcc_recv_count) / delta;
2332 lnet_stat_result.lnet_total_rcvrate += rate;
2334 if (lnet_stat_result.lnet_min_rcvrate > rate ||
2335 lnet_stat_result.lnet_min_rcvrate == 0)
2336 lnet_stat_result.lnet_min_rcvrate = rate;
2338 if (lnet_stat_result.lnet_max_rcvrate < rate)
2339 lnet_stat_result.lnet_max_rcvrate = rate;
2341 lnet_stat_result.lnet_stat_count++;
2343 lnet_stat_result.lnet_avg_sndrate = lnet_stat_result.lnet_total_sndrate /
2344 lnet_stat_result.lnet_stat_count;
2345 lnet_stat_result.lnet_avg_rcvrate = lnet_stat_result.lnet_total_rcvrate /
2346 lnet_stat_result.lnet_stat_count;
2348 lnet_stat_result.lnet_avg_sndperf = lnet_stat_result.lnet_total_sndperf /
2349 lnet_stat_result.lnet_stat_count;
2350 lnet_stat_result.lnet_avg_rcvperf = lnet_stat_result.lnet_total_rcvperf /
2351 lnet_stat_result.lnet_stat_count;
2355 lst_print_lnet_stat(char *name, int bwrt, int rdwr, int type, int mbs)
2365 if (lnet_stat_result.lnet_stat_count == 0)
2368 units = (mbs) ? "MB/s " : "MiB/s ";
2370 if (bwrt == 1) /* bw only */
2373 if (bwrt == 2) /* rates only */
2376 if (rdwr == 1) /* recv only */
2379 if (rdwr == 2) /* send only */
2382 for (i = start1; i <= end1; i++) {
2383 fprintf(stdout, "[LNet %s of %s]\n",
2384 i == 0 ? "Rates" : "Bandwidth", name);
2386 for (j = start2; j <= end2; j++) {
2387 fprintf(stdout, "[%c] ", j == 0 ? 'R' : 'W');
2389 if ((type & 1) != 0) {
2390 fprintf(stdout, i == 0 ? "Avg: %-8.0f RPC/s " :
2392 lst_lnet_stat_value(i, j, 0), units);
2395 if ((type & 2) != 0) {
2396 fprintf(stdout, i == 0 ? "Min: %-8.0f RPC/s " :
2398 lst_lnet_stat_value(i, j, 1), units);
2401 if ((type & 4) != 0) {
2402 fprintf(stdout, i == 0 ? "Max: %-8.0f RPC/s" :
2404 lst_lnet_stat_value(i, j, 2), units);
2407 fprintf(stdout, "\n");
2413 lst_print_stat(char *name, struct list_head *resultp,
2414 int idx, int lnet, int bwrt, int rdwr, int type,
2417 struct list_head tmp[2];
2418 struct lstcon_rpc_ent *new;
2419 struct lstcon_rpc_ent *old;
2420 struct sfw_counters *sfwk_new;
2421 struct sfw_counters *sfwk_old;
2422 struct srpc_counters *srpc_new;
2423 struct srpc_counters *srpc_old;
2424 struct lnet_counters_common *lnet_new;
2425 struct lnet_counters_common *lnet_old;
2429 INIT_LIST_HEAD(&tmp[0]);
2430 INIT_LIST_HEAD(&tmp[1]);
2432 memset(&lnet_stat_result, 0, sizeof(lnet_stat_result));
2434 while (!list_empty(&resultp[idx])) {
2435 if (list_empty(&resultp[1 - idx])) {
2436 fprintf(stderr, "Group is changed, re-run stat\n");
2440 new = list_first_entry(&resultp[idx], struct lstcon_rpc_ent,
2442 old = list_first_entry(&resultp[1 - idx], struct lstcon_rpc_ent,
2445 /* first time get stats result, can't calculate diff */
2446 if (new->rpe_peer.nid == LNET_NID_ANY)
2449 if (new->rpe_peer.nid != old->rpe_peer.nid ||
2450 new->rpe_peer.pid != old->rpe_peer.pid) {
2451 /* Something wrong. i.e, somebody change the group */
2455 list_move_tail(&new->rpe_link, &tmp[idx]);
2457 list_move_tail(&old->rpe_link, &tmp[1 - idx]);
2459 if (new->rpe_rpc_errno != 0 || new->rpe_fwk_errno != 0 ||
2460 old->rpe_rpc_errno != 0 || old->rpe_fwk_errno != 0) {
2465 sfwk_new = (struct sfw_counters *)&new->rpe_payload[0];
2466 sfwk_old = (struct sfw_counters *)&old->rpe_payload[0];
2468 srpc_new = (struct srpc_counters *)((char *)sfwk_new +
2470 srpc_old = (struct srpc_counters *)((char *)sfwk_old +
2473 lnet_new = (struct lnet_counters_common *)((char *)srpc_new +
2475 lnet_old = (struct lnet_counters_common *)((char *)srpc_old +
2478 /* Prior to version 2.3, the running_ms was a counter for
2479 * the number of running tests. Since 2.3, running_ms is
2480 * changed to hold the millisecond since the start of
2481 * the work item. The rpe_stamp field was formerly used,
2482 * but is no longer. In 2.12 rpe_stamp was changed to
2483 * struct timespec64 and has nanosecond resolution, in
2484 * case it is needed in the future.
2486 delta = (float)(sfwk_new->running_ms -
2487 sfwk_old->running_ms) / 1000;
2489 if (!lnet) /* TODO */
2492 lst_cal_lnet_stat(delta, lnet_new, lnet_old, mbs);
2495 list_splice(&tmp[idx], &resultp[idx]);
2496 list_splice(&tmp[1 - idx], &resultp[1 - idx]);
2499 fprintf(stdout, "Failed to stat on %d nodes\n", errcount);
2501 if (!lnet) /* TODO */
2504 lst_print_lnet_stat(name, bwrt, rdwr, type, mbs);
2508 jt_lst_stat(int argc, char **argv)
2510 struct list_head head;
2511 lst_stat_req_param_t *srp;
2514 int timeout = 5; /* default timeout, 5 sec */
2515 int delay = 5; /* default delay, 5 sec */
2516 int count = -1; /* run forever */
2517 int lnet = 1; /* lnet stat by default */
2524 int mbs = 0; /* report as MB/s */
2526 static const struct option stat_opts[] = {
2527 { .name = "timeout", .has_arg = required_argument, .val = 't' },
2528 { .name = "delay", .has_arg = required_argument, .val = 'd' },
2529 { .name = "count", .has_arg = required_argument, .val = 'o' },
2530 { .name = "lnet", .has_arg = no_argument, .val = 'l' },
2531 { .name = "rpc", .has_arg = no_argument, .val = 'c' },
2532 { .name = "bw", .has_arg = no_argument, .val = 'b' },
2533 { .name = "rate", .has_arg = no_argument, .val = 'a' },
2534 { .name = "read", .has_arg = no_argument, .val = 'r' },
2535 { .name = "write", .has_arg = no_argument, .val = 'w' },
2536 { .name = "avg", .has_arg = no_argument, .val = 'g' },
2537 { .name = "min", .has_arg = no_argument, .val = 'n' },
2538 { .name = "max", .has_arg = no_argument, .val = 'x' },
2539 { .name = "mbs", .has_arg = no_argument, .val = 'm' },
2542 if (session_key == 0) {
2544 "Can't find env LST_SESSION or value is not valid\n");
2549 c = getopt_long(argc, argv, "t:d:lcbarwgnxm", stat_opts,
2557 timeout = atoi(optarg);
2560 delay = atoi(optarg);
2563 count = atoi(optarg);
2609 lst_print_usage(argv[0]);
2614 if (optind == argc) {
2615 lst_print_usage(argv[0]);
2619 if (timeout <= 0 || delay <= 0) {
2620 fprintf(stderr, "Invalid timeout or delay value\n");
2625 fprintf(stderr, "Invalid count value\n");
2629 /* extra count to get first data point */
2633 INIT_LIST_HEAD(&head);
2635 while (optind < argc) {
2636 rc = lst_stat_req_param_alloc(argv[optind++], &srp, 1);
2640 list_add_tail(&srp->srp_link, &head);
2644 time_t now = time(NULL);
2646 if (now - last < delay) {
2647 sleep(delay - now + last);
2652 list_for_each_entry(srp, &head, srp_link) {
2653 rc = lst_stat_ioctl(srp->srp_name,
2654 srp->srp_count, srp->srp_ids,
2655 timeout, &srp->srp_result[idx]);
2657 lst_print_error("stat", "Failed to stat %s: %s\n",
2658 srp->srp_name, strerror(errno));
2662 lst_print_stat(srp->srp_name, srp->srp_result,
2663 idx, lnet, bwrt, rdwr, type, mbs);
2665 lst_reset_rpcent(&srp->srp_result[1 - idx]);
2672 } while (count == -1 || count > 0);
2675 while (!list_empty(&head)) {
2676 srp = list_first_entry(&head, lst_stat_req_param_t, srp_link);
2678 list_del(&srp->srp_link);
2679 lst_stat_req_param_free(srp);
2686 jt_lst_show_error(int argc, char **argv)
2688 struct list_head head;
2689 lst_stat_req_param_t *srp;
2690 struct lstcon_rpc_ent *ent;
2691 struct sfw_counters *sfwk;
2692 struct srpc_counters *srpc;
2699 static const struct option show_error_opts[] = {
2700 { .name = "session", .has_arg = no_argument, .val = 's' },
2701 { .name = NULL, } };
2703 if (session_key == 0) {
2705 "Can't find env LST_SESSION or value is not valid\n");
2710 c = getopt_long(argc, argv, "s", show_error_opts, &optidx);
2721 lst_print_usage(argv[0]);
2726 if (optind == argc) {
2727 lst_print_usage(argv[0]);
2731 INIT_LIST_HEAD(&head);
2733 while (optind < argc) {
2734 rc = lst_stat_req_param_alloc(argv[optind++], &srp, 0);
2738 list_add_tail(&srp->srp_link, &head);
2741 list_for_each_entry(srp, &head, srp_link) {
2742 rc = lst_stat_ioctl(srp->srp_name, srp->srp_count,
2743 srp->srp_ids, 10, &srp->srp_result[0]);
2746 lst_print_error(srp->srp_name, "Failed to show errors of %s: %s\n",
2747 srp->srp_name, strerror(errno));
2751 fprintf(stdout, "%s:\n", srp->srp_name);
2755 list_for_each_entry(ent, &srp->srp_result[0], rpe_link) {
2756 if (ent->rpe_rpc_errno != 0) {
2758 fprintf(stderr, "RPC failure, can't show error on %s\n",
2759 libcfs_id2str(ent->rpe_peer));
2763 if (ent->rpe_fwk_errno != 0) {
2765 fprintf(stderr, "Framework failure, can't show error on %s\n",
2766 libcfs_id2str(ent->rpe_peer));
2770 sfwk = (struct sfw_counters *)&ent->rpe_payload[0];
2771 srpc = (struct srpc_counters *)((char *)sfwk + sizeof(*sfwk));
2773 if (srpc->errors == 0 &&
2774 sfwk->brw_errors == 0 && sfwk->ping_errors == 0)
2778 sfwk->brw_errors == 0 && sfwk->ping_errors == 0)
2783 fprintf(stderr, "%s: [Session %d brw errors, %d ping errors]%c",
2784 libcfs_id2str(ent->rpe_peer),
2785 sfwk->brw_errors, sfwk->ping_errors,
2786 show_rpc ? ' ' : '\n');
2791 fprintf(stderr, "[RPC: %d errors, %d dropped, %d expired]\n",
2792 srpc->errors, srpc->rpcs_dropped, srpc->rpcs_expired);
2795 fprintf(stdout, "Total %d error nodes in %s\n", ecount, srp->srp_name);
2798 while (!list_empty(&head)) {
2799 srp = list_first_entry(&head, lst_stat_req_param_t, srp_link);
2801 list_del(&srp->srp_link);
2802 lst_stat_req_param_free(srp);
2809 lst_add_batch_ioctl(char *name)
2811 struct lstio_batch_add_args args = { 0 };
2813 args.lstio_bat_key = session_key;
2814 args.lstio_bat_nmlen = strlen(name);
2815 args.lstio_bat_namep = name;
2817 return lst_ioctl (LSTIO_BATCH_ADD, &args, sizeof(args));
2821 jt_lst_add_batch(int argc, char **argv)
2826 if (session_key == 0) {
2828 "Can't find env LST_SESSION or value is not valid\n");
2833 lst_print_usage(argv[0]);
2838 if (strlen(name) >= LST_NAME_SIZE) {
2839 fprintf(stderr, "Name length is limited to %d\n",
2844 rc = lst_add_batch_ioctl(name);
2848 lst_print_error("batch", "Failed to create batch: %s\n",
2855 lst_start_batch_ioctl(char *name, int timeout, struct list_head *resultp)
2857 struct lstio_batch_run_args args = { 0 };
2859 args.lstio_bat_key = session_key;
2860 args.lstio_bat_timeout = timeout;
2861 args.lstio_bat_nmlen = strlen(name);
2862 args.lstio_bat_namep = name;
2863 args.lstio_bat_resultp = resultp;
2865 return lst_ioctl(LSTIO_BATCH_START, &args, sizeof(args));
2869 jt_lst_start_batch(int argc, char **argv)
2871 struct list_head head;
2879 static const struct option start_batch_opts[] = {
2880 { .name = "timeout", .has_arg = required_argument, .val = 't' },
2883 if (session_key == 0) {
2885 "Can't find env LST_SESSION or value is not valid\n");
2890 c = getopt_long(argc, argv, "t:",
2891 start_batch_opts, &optidx);
2893 /* Detect the end of the options. */
2899 timeout = atoi(optarg);
2902 lst_print_usage(argv[0]);
2907 if (optind == argc) {
2908 batch = LST_DEFAULT_BATCH;
2910 } else if (optind == argc - 1) {
2911 batch = argv[optind];
2914 lst_print_usage(argv[0]);
2918 rc = lst_get_node_count(LST_OPC_BATCHCLI, batch, &count, NULL);
2920 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
2921 batch, strerror(errno));
2925 INIT_LIST_HEAD(&head);
2927 rc = lst_alloc_rpcent(&head, count, 0);
2929 fprintf(stderr, "Out of memory\n");
2933 rc = lst_start_batch_ioctl(batch, timeout, &head);
2936 fprintf(stdout, "%s is running now\n", batch);
2937 lst_free_rpcent(&head);
2942 lst_print_error("batch", "Failed to start batch: %s\n",
2944 lst_free_rpcent(&head);
2948 lst_print_transerr(&head, "Run batch");
2950 lst_free_rpcent(&head);
2956 lst_stop_batch_ioctl(char *name, int force, struct list_head *resultp)
2958 struct lstio_batch_stop_args args = { 0 };
2960 args.lstio_bat_key = session_key;
2961 args.lstio_bat_force = force;
2962 args.lstio_bat_nmlen = strlen(name);
2963 args.lstio_bat_namep = name;
2964 args.lstio_bat_resultp = resultp;
2966 return lst_ioctl(LSTIO_BATCH_STOP, &args, sizeof(args));
2970 jt_lst_stop_batch(int argc, char **argv)
2972 struct list_head head;
2980 static const struct option stop_batch_opts[] = {
2981 { .name = "force", .has_arg = no_argument, .val = 'f' },
2984 if (session_key == 0) {
2986 "Can't find env LST_SESSION or value is not valid\n");
2991 c = getopt_long(argc, argv, "f",
2992 stop_batch_opts, &optidx);
2994 /* Detect the end of the options. */
3003 lst_print_usage(argv[0]);
3008 if (optind == argc) {
3009 batch = LST_DEFAULT_BATCH;
3011 } else if (optind == argc - 1) {
3012 batch = argv[optind];
3015 lst_print_usage(argv[0]);
3019 rc = lst_get_node_count(LST_OPC_BATCHCLI, batch, &count, NULL);
3021 fprintf(stderr, "Failed to get count of nodes from %s: %s\n",
3022 batch, strerror(errno));
3026 INIT_LIST_HEAD(&head);
3028 rc = lst_alloc_rpcent(&head, count, 0);
3030 fprintf(stderr, "Out of memory\n");
3034 rc = lst_stop_batch_ioctl(batch, force, &head);
3039 lst_reset_rpcent(&head);
3041 rc = lst_query_batch_ioctl(batch, 0, 0, 30, &head);
3045 if (lstcon_tsbqry_stat_run(&trans_stat, 0) == 0 &&
3046 lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0)
3049 fprintf(stdout, "%d batch in stopping\n",
3050 lstcon_tsbqry_stat_run(&trans_stat, 0));
3054 fprintf(stdout, "Batch is stopped\n");
3055 lst_free_rpcent(&head);
3060 lst_print_error("batch", "Failed to stop batch: %s\n",
3062 lst_free_rpcent(&head);
3066 lst_print_transerr(&head, "stop batch");
3068 lst_free_rpcent(&head);
3074 lst_list_batch_ioctl(int len, char *name, int index)
3076 struct lstio_batch_list_args args = { 0 };
3078 args.lstio_bat_key = session_key;
3079 args.lstio_bat_idx = index;
3080 args.lstio_bat_nmlen = len;
3081 args.lstio_bat_namep = name;
3083 return lst_ioctl(LSTIO_BATCH_LIST, &args, sizeof(args));
3087 lst_info_batch_ioctl(char *batch, int test, int server,
3088 struct lstcon_test_batch_ent *entp, int *idxp,
3089 int *ndentp, struct lstcon_node_ent *dentsp)
3091 struct lstio_batch_info_args args = { 0 };
3093 args.lstio_bat_key = session_key;
3094 args.lstio_bat_nmlen = strlen(batch);
3095 args.lstio_bat_namep = batch;
3096 args.lstio_bat_server = server;
3097 args.lstio_bat_testidx = test;
3098 args.lstio_bat_entp = entp;
3099 args.lstio_bat_idxp = idxp;
3100 args.lstio_bat_ndentp = ndentp;
3101 args.lstio_bat_dentsp = dentsp;
3103 return lst_ioctl(LSTIO_BATCH_INFO, &args, sizeof(args));
3107 lst_list_batch_all(void)
3109 char name[LST_NAME_SIZE];
3113 for (i = 0; ; i++) {
3114 rc = lst_list_batch_ioctl(LST_NAME_SIZE, name, i);
3116 fprintf(stdout, "%d) %s\n", i + 1, name);
3120 if (errno == ENOENT)
3123 lst_print_error("batch", "Failed to list batch: %s\n",
3128 fprintf(stdout, "Total %d batches\n", i);
3134 lst_list_tsb_nodes(char *batch, int test, int server,
3135 int count, int active, int invalid)
3137 struct lstcon_node_ent *dents;
3146 /* verbose list, show nodes in batch or test */
3147 dents = malloc(count * sizeof(struct lstcon_node_ent));
3148 if (dents == NULL) {
3149 fprintf(stdout, "Can't allocate memory\n");
3153 rc = lst_info_batch_ioctl(batch, test, server,
3154 NULL, &index, &count, dents);
3157 lst_print_error((test > 0) ? "test" : "batch",
3158 (test > 0) ? "Failed to query test: %s\n" :
3159 "Failed to query batch: %s\n",
3164 for (i = 0, c = 0; i < count; i++) {
3165 if ((!active && dents[i].nde_state == LST_NODE_ACTIVE) ||
3166 (!invalid && (dents[i].nde_state == LST_NODE_BUSY ||
3167 dents[i].nde_state == LST_NODE_DOWN ||
3168 dents[i].nde_state == LST_NODE_UNKNOWN)))
3171 fprintf(stdout, "\t%s: %s\n",
3172 libcfs_id2str(dents[i].nde_id),
3173 lst_node_state2str(dents[i].nde_state));
3177 fprintf(stdout, "Total %d nodes\n", c);
3184 jt_lst_list_batch(int argc, char **argv)
3186 struct lstcon_test_batch_ent ent;
3189 int verbose = 0; /* list nodes in batch or test */
3198 static const struct option list_batch_opts[] = {
3199 { .name = "test", .has_arg = required_argument, .val = 't' },
3200 { .name = "invalid", .has_arg = no_argument, .val = 'i' },
3201 { .name = "active", .has_arg = no_argument, .val = 'a' },
3202 { .name = "all", .has_arg = no_argument, .val = 'l' },
3203 { .name = "server", .has_arg = no_argument, .val = 's' },
3204 { .name = NULL, } };
3206 if (session_key == 0) {
3208 "Can't find env LST_SESSION or value is not valid\n");
3213 c = getopt_long(argc, argv, "ailst:",
3214 list_batch_opts, &optidx);
3221 verbose = active = 1;
3224 verbose = invalid = 1;
3227 verbose = active = invalid = 1;
3233 test = atoi(optarg);
3237 lst_print_usage(argv[0]);
3242 if (optind == argc) {
3243 /* list all batches */
3244 rc = lst_list_batch_all();
3248 if (ntest == 1 && test <= 0) {
3249 fprintf(stderr, "Invalid test id, test id starts from 1\n");
3253 if (optind != argc - 1) {
3254 lst_print_usage(argv[0]);
3258 batch = argv[optind];
3261 /* show detail of specified batch or test */
3262 rc = lst_info_batch_ioctl(batch, test, server,
3263 &ent, NULL, NULL, NULL);
3265 lst_print_error((test > 0) ? "test" : "batch",
3266 (test > 0) ? "Failed to query test: %s\n" :
3267 "Failed to query batch: %s\n",
3273 /* list nodes in test or batch */
3274 rc = lst_list_tsb_nodes(batch, test, server,
3275 server ? ent.tbe_srv_nle.nle_nnode :
3276 ent.tbe_cli_nle.nle_nnode,
3281 /* only show number of hosts in batch or test */
3283 fprintf(stdout, "Batch: %s Tests: %d State: %d\n",
3284 batch, ent.u.tbe_batch.bae_ntest,
3285 ent.u.tbe_batch.bae_state);
3286 ntest = ent.u.tbe_batch.bae_ntest;
3287 test = 1; /* starting from test 1 */
3291 "\tTest %d(%s) (loop: %d, concurrency: %d)\n",
3292 test, lst_test_type2name(ent.u.tbe_test.tse_type),
3293 ent.u.tbe_test.tse_loop,
3294 ent.u.tbe_test.tse_concur);
3299 fprintf(stdout, LST_NODES_TITLE);
3300 fprintf(stdout, "client\t%d\t%d\t%d\t%d\t%d\n"
3301 "server\t%d\t%d\t%d\t%d\t%d\n",
3302 ent.tbe_cli_nle.nle_nactive,
3303 ent.tbe_cli_nle.nle_nbusy,
3304 ent.tbe_cli_nle.nle_ndown,
3305 ent.tbe_cli_nle.nle_nunknown,
3306 ent.tbe_cli_nle.nle_nnode,
3307 ent.tbe_srv_nle.nle_nactive,
3308 ent.tbe_srv_nle.nle_nbusy,
3309 ent.tbe_srv_nle.nle_ndown,
3310 ent.tbe_srv_nle.nle_nunknown,
3311 ent.tbe_srv_nle.nle_nnode);
3320 lst_query_batch_ioctl(char *batch, int test, int server,
3321 int timeout, struct list_head *head)
3323 struct lstio_batch_query_args args = { 0 };
3325 args.lstio_bat_key = session_key;
3326 args.lstio_bat_testidx = test;
3327 args.lstio_bat_client = !(server);
3328 args.lstio_bat_timeout = timeout;
3329 args.lstio_bat_nmlen = strlen(batch);
3330 args.lstio_bat_namep = batch;
3331 args.lstio_bat_resultp = head;
3333 return lst_ioctl(LSTIO_BATCH_QUERY, &args, sizeof(args));
3337 lst_print_tsb_verbose(struct list_head *head,
3338 int active, int idle, int error)
3340 struct lstcon_rpc_ent *ent;
3342 list_for_each_entry(ent, head, rpe_link) {
3343 if (ent->rpe_priv[0] == 0 && active)
3346 if (ent->rpe_priv[0] != 0 && idle)
3349 if (ent->rpe_fwk_errno == 0 && error)
3352 fprintf(stdout, "%s [%s]: %s\n",
3353 libcfs_id2str(ent->rpe_peer),
3354 lst_node_state2str(ent->rpe_state),
3355 ent->rpe_rpc_errno != 0 ?
3356 strerror(ent->rpe_rpc_errno) :
3357 (ent->rpe_priv[0] > 0 ? "Running" : "Idle"));
3362 jt_lst_query_batch(int argc, char **argv)
3364 struct lstcon_test_batch_ent ent;
3365 struct list_head head;
3371 int timeout = 5; /* default 5 seconds */
3372 int delay = 5; /* default 5 seconds */
3373 int loop = 1; /* default 1 loop */
3383 static const struct option query_batch_opts[] = {
3384 { .name = "timeout", .has_arg = required_argument, .val = 'o' },
3385 { .name = "delay", .has_arg = required_argument, .val = 'd' },
3386 { .name = "loop", .has_arg = required_argument, .val = 'c' },
3387 { .name = "test", .has_arg = required_argument, .val = 't' },
3388 { .name = "server", .has_arg = no_argument, .val = 's' },
3389 { .name = "active", .has_arg = no_argument, .val = 'a' },
3390 { .name = "idle", .has_arg = no_argument, .val = 'i' },
3391 { .name = "error", .has_arg = no_argument, .val = 'e' },
3392 { .name = "all", .has_arg = no_argument, .val = 'l' },
3393 { .name = NULL, } };
3395 if (session_key == 0) {
3397 "Can't find env LST_SESSION or value is not valid\n");
3402 c = getopt_long(argc, argv, "o:d:c:t:saiel",
3403 query_batch_opts, &optidx);
3405 /* Detect the end of the options. */
3411 timeout = atoi(optarg);
3414 delay = atoi(optarg);
3417 loop = atoi(optarg);
3420 test = atoi(optarg);
3426 active = verbose = 1;
3432 error = verbose = 1;
3438 lst_print_usage(argv[0]);
3443 if (test < 0 || timeout <= 0 || delay <= 0 || loop <= 0) {
3444 lst_print_usage(argv[0]);
3448 if (optind == argc) {
3449 batch = LST_DEFAULT_BATCH;
3451 } else if (optind == argc - 1) {
3452 batch = argv[optind];
3455 lst_print_usage(argv[0]);
3460 INIT_LIST_HEAD(&head);
3463 rc = lst_info_batch_ioctl(batch, test, server,
3464 &ent, NULL, NULL, NULL);
3466 fprintf(stderr, "Failed to query %s [%d]: %s\n",
3467 batch, test, strerror(errno));
3471 count = server ? ent.tbe_srv_nle.nle_nnode :
3472 ent.tbe_cli_nle.nle_nnode;
3474 fprintf(stdout, "Batch or test is empty\n");
3479 rc = lst_alloc_rpcent(&head, count, 0);
3481 fprintf(stderr, "Out of memory\n");
3485 for (i = 0; i < loop; i++) {
3486 time_t now = time(NULL);
3488 if (now - last < delay) {
3489 sleep(delay - now + last);
3495 rc = lst_query_batch_ioctl(batch, test,
3496 server, timeout, &head);
3498 fprintf(stderr, "Failed to query batch: %s\n",
3505 lst_print_tsb_verbose(&head, active, idle, error);
3509 fprintf(stdout, "%s [%d] ", batch, test);
3511 if (lstcon_rpc_stat_failure(&trans_stat, 0) != 0) {
3512 fprintf(stdout, "%d of %d nodes are unknown, ",
3513 lstcon_rpc_stat_failure(&trans_stat, 0),
3514 lstcon_rpc_stat_total(&trans_stat, 0));
3517 if (lstcon_rpc_stat_failure(&trans_stat, 0) == 0 &&
3518 lstcon_tsbqry_stat_run(&trans_stat, 0) == 0 &&
3519 lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0) {
3520 fprintf(stdout, "is stopped\n");
3524 if (lstcon_rpc_stat_failure(&trans_stat, 0) == 0 &&
3525 lstcon_tsbqry_stat_idle(&trans_stat, 0) == 0 &&
3526 lstcon_tsbqry_stat_failure(&trans_stat, 0) == 0) {
3527 fprintf(stdout, "is running\n");
3531 fprintf(stdout, "stopped: %d , running: %d, failed: %d\n",
3532 lstcon_tsbqry_stat_idle(&trans_stat, 0),
3533 lstcon_tsbqry_stat_run(&trans_stat, 0),
3534 lstcon_tsbqry_stat_failure(&trans_stat, 0));
3537 lst_free_rpcent(&head);
3543 lst_parse_distribute(char *dstr, int *dist, int *span)
3549 dstr = strchr(dstr, ':');
3553 *span = atoi(dstr + 1);
3561 lst_get_bulk_param(int argc, char **argv, struct lst_test_bulk_param *bulk)
3568 bulk->blk_size = 4096;
3569 bulk->blk_opc = LST_BRW_READ;
3570 bulk->blk_flags = LST_BRW_CHECK_NONE;
3571 bulk->blk_srv_off = bulk->blk_cli_off = 0;
3574 if (strcasestr(argv[i], "check=") == argv[i] ||
3575 strcasestr(argv[i], "c=") == argv[i]) {
3576 tok = strchr(argv[i], '=') + 1;
3578 if (strcasecmp(tok, "full") == 0) {
3579 bulk->blk_flags = LST_BRW_CHECK_FULL;
3580 } else if (strcasecmp(tok, "simple") == 0) {
3581 bulk->blk_flags = LST_BRW_CHECK_SIMPLE;
3583 fprintf(stderr, "Unknow flag %s\n", tok);
3587 } else if (strcasestr(argv[i], "size=") == argv[i] ||
3588 strcasestr(argv[i], "s=") == argv[i]) {
3589 tok = strchr(argv[i], '=') + 1;
3591 bulk->blk_size = strtol(tok, &end, 0);
3592 if (bulk->blk_size <= 0) {
3593 fprintf(stderr, "Invalid size %s\n", tok);
3600 if (*end == 'k' || *end == 'K')
3601 bulk->blk_size *= 1024;
3602 else if (*end == 'm' || *end == 'M')
3603 bulk->blk_size *= 1024 * 1024;
3605 if (bulk->blk_size > LNET_MTU) {
3606 fprintf(stderr, "Size exceed limitation: %d bytes\n",
3611 } else if (strcasestr(argv[i], "off=") == argv[i]) {
3614 tok = strchr(argv[i], '=') + 1;
3616 off = strtol(tok, &end, 0);
3617 /* NB: align with sizeof(__u64) to simplify page
3618 * checking implementation */
3619 if (off < 0 || off % sizeof(__u64) != 0) {
3621 "Invalid offset %s/%d, it should be "
3622 "postive value and multiple of %d\n",
3623 tok, off, (int)sizeof(__u64));
3627 /* NB: blk_srv_off is reserved so far */
3628 bulk->blk_cli_off = bulk->blk_srv_off = off;
3632 } else if (strcasecmp(argv[i], "read") == 0 ||
3633 strcasecmp(argv[i], "r") == 0) {
3634 bulk->blk_opc = LST_BRW_READ;
3636 } else if (strcasecmp(argv[i], "write") == 0 ||
3637 strcasecmp(argv[i], "w") == 0) {
3638 bulk->blk_opc = LST_BRW_WRITE;
3641 fprintf(stderr, "Unknow parameter: %s\n", argv[i]);
3652 lst_get_test_param(char *test, int argc, char **argv, void **param, int *plen)
3654 struct lst_test_bulk_param *bulk = NULL;
3655 struct lst_test_ping_param *ping = NULL;
3658 type = lst_test_name2type(test);
3660 fprintf(stderr, "Unknow test name %s\n", test);
3666 /* unused but needs for kernel part */
3667 ping = malloc(sizeof(*ping));
3669 fprintf(stderr, "Out of memory\n");
3672 memset(ping, 0, sizeof(*ping));
3675 *plen = sizeof(*ping);
3680 bulk = malloc(sizeof(*bulk));
3682 fprintf(stderr, "Out of memory\n");
3686 memset(bulk, 0, sizeof(*bulk));
3688 if (lst_get_bulk_param(argc, argv, bulk) != 0) {
3694 *plen = sizeof(*bulk);
3702 /* TODO: parse more parameter */
3707 lst_add_test_ioctl(char *batch, int type, int loop, int concur,
3708 int dist, int span, char *sgrp, char *dgrp,
3709 void *param, int plen, int *retp, struct list_head *resultp)
3711 struct lstio_test_args args = { 0 };
3713 args.lstio_tes_key = session_key;
3714 args.lstio_tes_bat_nmlen = strlen(batch);
3715 args.lstio_tes_bat_name = batch;
3716 args.lstio_tes_type = type;
3717 args.lstio_tes_oneside = 0;
3718 args.lstio_tes_loop = loop;
3719 args.lstio_tes_concur = concur;
3720 args.lstio_tes_dist = dist;
3721 args.lstio_tes_span = span;
3722 args.lstio_tes_sgrp_nmlen = strlen(sgrp);
3723 args.lstio_tes_sgrp_name = sgrp;
3724 args.lstio_tes_dgrp_nmlen = strlen(dgrp);
3725 args.lstio_tes_dgrp_name = dgrp;
3726 args.lstio_tes_param_len = plen;
3727 args.lstio_tes_param = param;
3728 args.lstio_tes_retp = retp;
3729 args.lstio_tes_resultp = resultp;
3731 return lst_ioctl(LSTIO_TEST_ADD, &args, sizeof(args));
3735 jt_lst_add_test(int argc, char **argv)
3737 struct list_head head;
3757 static const struct option add_test_opts[] = {
3758 { .name = "batch", .has_arg = required_argument, .val = 'b' },
3759 { .name = "concurrency", .has_arg = required_argument, .val = 'c' },
3760 { .name = "distribute", .has_arg = required_argument, .val = 'd' },
3761 { .name = "from", .has_arg = required_argument, .val = 'f' },
3762 { .name = "to", .has_arg = required_argument, .val = 't' },
3763 { .name = "loop", .has_arg = required_argument, .val = 'l' },
3766 if (session_key == 0) {
3768 "Can't find env LST_SESSION or value is not valid\n");
3773 c = getopt_long(argc, argv, "b:c:d:f:l:t:",
3774 add_test_opts, &optidx);
3776 /* Detect the end of the options. */
3785 concur = atoi(optarg);
3794 loop = atoi(optarg);
3800 lst_print_usage(argv[0]);
3805 if (optind == argc || from == NULL || to == NULL) {
3806 lst_print_usage(argv[0]);
3810 if (concur <= 0 || concur > LST_MAX_CONCUR) {
3811 fprintf(stderr, "Invalid concurrency of test: %d\n", concur);
3816 batch = LST_DEFAULT_BATCH;
3819 rc = lst_parse_distribute(dstr, &dist, &span);
3821 fprintf(stderr, "Invalid distribution: %s\n", dstr);
3826 test = argv[optind++];
3831 type = lst_get_test_param(test, argc, argv, ¶m, &plen);
3833 fprintf(stderr, "Failed to add test (%s)\n", test);
3837 INIT_LIST_HEAD(&head);
3839 rc = lst_get_node_count(LST_OPC_GROUP, from, &fcount, NULL);
3841 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
3842 from, strerror(errno));
3846 rc = lst_get_node_count(LST_OPC_GROUP, to, &tcount, NULL);
3848 fprintf(stderr, "Can't get count of nodes from %s: %s\n",
3849 to, strerror(errno));
3853 rc = lst_alloc_rpcent(&head, fcount > tcount ? fcount : tcount, 0);
3855 fprintf(stderr, "Out of memory\n");
3859 rc = lst_add_test_ioctl(batch, type, loop, concur,
3860 dist, span, from, to, param, plen, &ret, &head);
3863 fprintf(stdout, "Test was added successfully\n");
3865 fprintf(stdout, "Server group contains userland test "
3866 "nodes, old version of tcplnd can't accept "
3867 "connection request\n");
3874 lst_print_error("test", "Failed to add test: %s\n",
3879 lst_print_transerr(&head, "add test");
3881 lst_free_rpcent(&head);
3889 static command_t lst_cmdlist[] = {
3890 {"new_session", jt_lst_new_session, NULL,
3891 "Usage: lst new_session [--timeout TIME] [--force] [NAME]" },
3892 {"end_session", jt_lst_end_session, NULL,
3893 "Usage: lst end_session" },
3894 {"show_session", jt_lst_show_session, NULL,
3895 "Usage: lst show_session" },
3896 {"ping", jt_lst_ping , NULL,
3897 "Usage: lst ping [--group NAME] [--batch NAME] [--session] [--nodes IDS]" },
3898 {"add_group", jt_lst_add_group, NULL,
3899 "Usage: lst group NAME IDs [IDs]..." },
3900 {"del_group", jt_lst_del_group, NULL,
3901 "Usage: lst del_group NAME" },
3902 {"update_group", jt_lst_update_group, NULL,
3903 "Usage: lst update_group NAME [--clean] [--refresh] [--remove IDs]" },
3904 {"list_group", jt_lst_list_group, NULL,
3905 "Usage: lst list_group [--active] [--busy] [--down] [--unknown] GROUP ..." },
3906 {"stat", jt_lst_stat, NULL,
3907 "Usage: lst stat [--bw] [--rate] [--read] [--write] [--max] [--min] [--avg] "
3908 " [--mbs] [--timeout #] [--delay #] [--count #] GROUP [GROUP]" },
3909 {"show_error", jt_lst_show_error, NULL,
3910 "Usage: lst show_error NAME | IDS ..." },
3911 {"add_batch", jt_lst_add_batch, NULL,
3912 "Usage: lst add_batch NAME" },
3913 {"run", jt_lst_start_batch, NULL,
3914 "Usage: lst run [--timeout TIME] [NAME]" },
3915 {"stop", jt_lst_stop_batch, NULL,
3916 "Usage: lst stop [--force] BATCH_NAME" },
3917 {"list_batch", jt_lst_list_batch, NULL,
3918 "Usage: lst list_batch NAME [--test ID] [--server]" },
3919 {"query", jt_lst_query_batch, NULL,
3920 "Usage: lst query [--test ID] [--server] [--timeout TIME] NAME" },
3921 {"add_test", jt_lst_add_test, NULL,
3922 "Usage: lst add_test [--batch BATCH] [--loop #] [--concurrency #] "
3923 " [--distribute #:#] [--from GROUP] [--to GROUP] TEST..." },
3928 lst_initialize(void)
3933 feats = getenv("LST_FEATURES");
3935 session_features = strtol(feats, NULL, 16);
3937 if ((session_features & ~LST_FEATS_MASK) != 0) {
3939 "Unsupported session features %x, "
3940 "only support these features so far: %x\n",
3941 (session_features & ~LST_FEATS_MASK), LST_FEATS_MASK);
3945 key = getenv("LST_SESSION");
3952 session_key = atoi(key);
3957 int main(int argc, char **argv)
3963 rc = lst_initialize();
3967 rc = lustre_lnet_config_lib_init();
3971 rc = cfs_parser(argc, argv, lst_cmdlist);