+ struct libcfs_ioctl_data data = {{0}};
+ struct lnet_fault_attr attr;
+ char *optstr;
+ int rc;
+
+ static struct option opts[] = {
+ {"source", required_argument, 0, 's'},
+ {"dest", required_argument, 0, 'd'},
+ {"rate", required_argument, 0, 'r'},
+ {"interval", required_argument, 0, 'i'},
+ {"latency", required_argument, 0, 'l'},
+ {"portal", required_argument, 0, 'p'},
+ {"message", required_argument, 0, 'm'},
+ {0, 0, 0, 0}
+ };
+
+ if (argc == 1) {
+ fprintf(stderr, "Failed, please provide source, destination "
+ "and rate of rule\n");
+ return -1;
+ }
+
+ optstr = opc == LNET_CTL_DROP_ADD ? "s:d:r:i:p:m:" : "s:d:r:l:p:m:";
+ memset(&attr, 0, sizeof(attr));
+ while (1) {
+ char c = getopt_long(argc, argv, optstr, opts, NULL);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 's': /* source NID/NET */
+ rc = fault_attr_nid_parse(optarg, &attr.fa_src);
+ if (rc != 0)
+ goto getopt_failed;
+ break;
+
+ case 'd': /* dest NID/NET */
+ rc = fault_attr_nid_parse(optarg, &attr.fa_dst);
+ if (rc != 0)
+ goto getopt_failed;
+ break;
+
+ case 'r': /* drop rate */
+ if (opc == LNET_CTL_DROP_ADD)
+ attr.u.drop.da_rate = strtoul(optarg, NULL, 0);
+ else
+ attr.u.delay.la_rate = strtoul(optarg, NULL, 0);
+ break;
+
+ case 'i': /* time interval (# seconds) for message drop */
+ if (opc == LNET_CTL_DROP_ADD)
+ attr.u.drop.da_interval = strtoul(optarg,
+ NULL, 0);
+ else
+ attr.u.delay.la_interval = strtoul(optarg,
+ NULL, 0);
+ break;
+
+ case 'l': /* seconds to wait before activating rule */
+ attr.u.delay.la_latency = strtoul(optarg, NULL, 0);
+ break;
+
+ case 'p': /* portal to filter */
+ rc = fault_attr_ptl_parse(optarg, &attr.fa_ptl_mask);
+ if (rc != 0)
+ goto getopt_failed;
+ break;
+
+ case 'm': /* message types to filter */
+ rc = fault_attr_msg_parse(optarg, &attr.fa_msg_mask);
+ if (rc != 0)
+ goto getopt_failed;
+ break;
+
+ default:
+ fprintf(stderr, "error: %s: option '%s' "
+ "unrecognized\n", argv[0], argv[optind - 1]);
+ goto getopt_failed;
+ }
+ }
+ optind = 1;
+
+ if (opc == LNET_CTL_DROP_ADD) {
+ /* NB: drop rate and interval are exclusive to each other */
+ if (!((attr.u.drop.da_rate == 0) ^
+ (attr.u.drop.da_interval == 0))) {
+ fprintf(stderr,
+ "please provide either drop rate or interval "
+ "but not both at the same time.\n");
+ return -1;
+ }
+ } else if (opc == LNET_CTL_DELAY_ADD) {
+ if (!((attr.u.delay.la_rate == 0) ^
+ (attr.u.delay.la_interval == 0))) {
+ fprintf(stderr,
+ "please provide either delay rate or interval "
+ "but not both at the same time.\n");
+ return -1;
+ }
+
+ if (attr.u.delay.la_latency == 0) {
+ fprintf(stderr, "latency cannot be zero\n");
+ return -1;
+ }
+ }
+
+ if (attr.fa_src == 0 || attr.fa_dst == 0) {
+ fprintf(stderr, "Please provide both source and destination "
+ "of %s rule\n", name);
+ return -1;
+ }
+
+ data.ioc_flags = opc;
+ data.ioc_inllen1 = sizeof(attr);
+ data.ioc_inlbuf1 = (char *)&attr;
+ if (libcfs_ioctl_pack(&data, &ioc_buf, IOC_BUF_SIZE) != 0) {
+ fprintf(stderr, "libcfs_ioctl_pack failed\n");
+ return -1;
+ }
+
+ rc = l_ioctl(LNET_DEV_ID, IOC_LIBCFS_LNET_FAULT, ioc_buf);
+ if (rc != 0) {
+ fprintf(stderr, "add %s rule %s->%s failed: %s\n",
+ name, libcfs_nid2str(attr.fa_src),
+ libcfs_nid2str(attr.fa_dst), strerror(errno));
+ return -1;
+ }
+
+ printf("Added %s rule %s->%s (1/%d)\n",
+ name, libcfs_nid2str(attr.fa_src), libcfs_nid2str(attr.fa_dst),
+ opc == LNET_CTL_DROP_ADD ?
+ attr.u.drop.da_rate : attr.u.delay.la_rate);
+ return 0;
+
+getopt_failed:
+ optind = 1;
+ return -1;
+}