1/*
2 * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses.  You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 *     Redistribution and use in source and binary forms, with or
12 *     without modification, are permitted provided that the following
13 *     conditions are met:
14 *
15 *      - Redistributions of source code must retain the above
16 *        copyright notice, this list of conditions and the following
17 *        disclaimer.
18 *
19 *      - Redistributions in binary form must reproduce the above
20 *        copyright notice, this list of conditions and the following
21 *        disclaimer in the documentation and/or other materials
22 *        provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 *
33 */
34
35/*
36 * Abstract:
37 * 	Command line interface for osmtest.
38 *
39 */
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <getopt.h>
44#include <complib/cl_debug.h>
45#include "osmtest.h"
46
47/********************************************************************
48       D E F I N E    G L O B A L    V A R I A B L E S
49*********************************************************************/
50
51/*
52	This is the global osmtest object.
53	One osmtest object is required per subnet.
54	Future versions could support multiple subents by
55	instantiating more than one osmtest object.
56*/
57#define GUID_ARRAY_SIZE 64
58#define OSMT_DEFAULT_RETRY_COUNT 3
59#define OSMT_DEFAULT_TRANS_TIMEOUT_MILLISEC 1000
60#define OSMT_DEFAULT_TRAP_WAIT_TIMEOUT_SEC 10
61#define INVALID_GUID (0xFFFFFFFFFFFFFFFFULL)
62
63/**********************************************************************
64 **********************************************************************/
65boolean_t osmt_is_debug(void)
66{
67#if defined( _DEBUG_ )
68	return TRUE;
69#else
70	return FALSE;
71#endif				/* defined( _DEBUG_ ) */
72}
73
74/**********************************************************************
75 **********************************************************************/
76void show_usage(void);
77
78void show_usage()
79{
80	printf
81	    ("\n------- osmtest - Usage and options ----------------------\n");
82	printf("Usage:	  osmtest [options]\n");
83	printf("Options:\n");
84	printf("-f <c|a|v|s|e|f|m|q|t>\n"
85	       "--flow <c|a|v|s|e|f|m|q|t>\n"
86	       "          This option directs osmtest to run a specific flow:\n"
87	       "          FLOW  DESCRIPTION\n"
88	       "          c = create an inventory file with all nodes, ports and paths\n"
89	       "          a = run all validation tests (expecting an input inventory)\n"
90	       "          v = only validate the given inventory file\n"
91	       "          s = run service registration, deregistration, and lease test\n"
92	       "          e = run event forwarding test\n"
93	       "          f = flood the SA with queries according to the stress mode\n"
94	       "          m = multicast flow\n"
95	       "          q = QoS info: dump VLArb and SLtoVL tables\n"
96	       "          t = run trap 64/65 flow (this flow requires running of external tool)\n"
97	       "          (default is all flows except QoS)\n\n");
98
99	printf("-w <trap_wait_time>\n"
100	       "--wait <trap_wait_time>\n"
101	       "          This option specifies the wait time for trap 64/65 in seconds\n"
102	       "          It is used only when running -f t - the trap 64/65 flow\n"
103	       "          (default to 10 sec)\n\n");
104	printf("-d <number>\n"
105	       "--debug <number>\n"
106	       "          This option specifies a debug option\n"
107	       "          These options are not normally needed\n"
108	       "          The number following -d selects the debug\n"
109	       "          option to enable as follows:\n"
110	       "          OPT   Description\n"
111	       "          ---    -----------------\n"
112	       "          -d0  - Unused.\n"
113	       "          -d1  - Do not scan/compare path records.\n"
114	       "          -d2  - Force log flushing after each log message.\n"
115	       "          Without -d, no debug options are enabled\n\n");
116	printf("-m <LID in hex>\n"
117	       "--max_lid <LID in hex>\n"
118	       "          This option specifies the maximal LID number to be searched\n"
119	       "          for during inventory file build (default to 100)\n\n");
120	printf("-g <GUID in hex>\n"
121	       "--guid <GUID in hex>\n"
122	       "          This option specifies the local port GUID value\n"
123	       "          with which osmtest should bind.  osmtest may be\n"
124	       "          bound to 1 port at a time\n\n");
125	printf("-p \n"
126	       "--port\n"
127	       "          This option displays a menu of possible local port GUID values\n"
128	       "          with which osmtest could bind\n\n");
129	printf("-h\n"
130	       "--help\n" "          Display this usage info then exit\n\n");
131	printf("-i <filename>\n"
132	       "--inventory <filename>\n"
133	       "          This option specifies the name of the inventory file\n"
134	       "          Normally, osmtest expects to find an inventory file,\n"
135	       "          which osmtest uses to validate real-time information\n"
136	       "          received from the SA during testing\n"
137	       "          If -i is not specified, osmtest defaults to the file\n"
138	       "          'osmtest.dat'\n"
139	       "          See -c option for related information\n\n");
140	printf("-s\n"
141	       "--stress\n"
142	       "          This option runs the specified stress test instead\n"
143	       "          of the normal test suite\n"
144	       "          Stress test options are as follows:\n"
145	       "          OPT    Description\n"
146	       "          ---    -----------------\n"
147	       "          -s1  - Single-MAD response SA queries\n"
148	       "          -s2  - Multi-MAD (RMPP) response SA queries\n"
149	       "          -s3  - Multi-MAD (RMPP) Path Record SA queries\n"
150	       "          Without -s, stress testing is not performed\n\n");
151	printf("-M\n"
152	       "--Multicast_Mode\n"
153	       "          This option specify length of Multicast test:\n"
154	       "          OPT    Description\n"
155	       "          ---    -----------------\n"
156	       "          -M1  - Short Multicast Flow (default) - single mode\n"
157	       "          -M2  - Short Multicast Flow - multiple mode\n"
158	       "          -M3  - Long Multicast Flow - single mode\n"
159	       "          -M4  - Long Multicast Flow - multiple mode\n"
160	       " Single mode - Osmtest is tested alone, with no other\n"
161	       "   apps that interact with OpenSM MC\n"
162	       " Multiple mode - Could be run with other apps using MC with\n"
163	       "   OpenSM."
164	       " Without -M, default flow testing is performed\n\n");
165
166	printf("-t <milliseconds>\n"
167	       "          This option specifies the time in milliseconds\n"
168	       "          used for transaction timeouts\n"
169	       "          Specifying -t 0 disables timeouts\n"
170	       "          Without -t, osmtest defaults to a timeout value of\n"
171	       "          1 second\n\n");
172	printf("-l\n"
173	       "--log_file\n"
174	       "          This option defines the log to be the given file\n"
175	       "          By default the log goes to stdout\n\n");
176	printf("-v\n"
177	       "          This option increases the log verbosity level\n"
178	       "          The -v option may be specified multiple times\n"
179	       "          to further increase the verbosity level\n"
180	       "          See the -vf option for more information about.\n"
181	       "          log verbosity\n\n");
182	printf("-V\n"
183	       "          This option sets the maximum verbosity level and\n"
184	       "          forces log flushing\n"
185	       "          The -V is equivalent to '-vf 0xFF -d 2'\n"
186	       "          See the -vf option for more information about.\n"
187	       "          log verbosity\n\n");
188	printf("-vf <flags>\n"
189	       "          This option sets the log verbosity level\n"
190	       "          A flags field must follow the -vf option\n"
191	       "          A bit set/clear in the flags enables/disables a\n"
192	       "          specific log level as follows:\n"
193	       "          BIT    LOG LEVEL ENABLED\n"
194	       "          ----   -----------------\n"
195	       "          0x01 - ERROR (error messages)\n"
196	       "          0x02 - INFO (basic messages, low volume)\n"
197	       "          0x04 - VERBOSE (interesting stuff, moderate volume)\n"
198	       "          0x08 - DEBUG (diagnostic, high volume)\n"
199	       "          0x10 - FUNCS (function entry/exit, very high volume)\n"
200	       "          0x20 - FRAMES (dumps all SMP and GMP frames)\n"
201	       "          0x40 - currently unused\n"
202	       "          0x80 - currently unused\n"
203	       "          Without -vf, osmtest defaults to ERROR + INFO (0x3)\n"
204	       "          Specifying -vf 0 disables all messages\n"
205	       "          Specifying -vf 0xFF enables all messages (see -V)\n"
206	       "          High verbosity levels may require increasing\n"
207	       "          the transaction timeout with the -t option\n\n");
208}
209
210/**********************************************************************
211 **********************************************************************/
212static void print_all_guids(IN osmtest_t * p_osmt);
213static void print_all_guids(IN osmtest_t * p_osmt)
214{
215	ib_api_status_t status;
216	uint32_t num_ports = GUID_ARRAY_SIZE;
217	ib_port_attr_t attr_array[GUID_ARRAY_SIZE];
218	int i;
219
220	/*
221	   Call the transport layer for a list of local port
222	   GUID values.
223	 */
224	status =
225	    osm_vendor_get_all_port_attr(p_osmt->p_vendor, attr_array,
226					 &num_ports);
227	if (status != IB_SUCCESS) {
228		printf("\nError from osm_vendor_get_all_port_attr (%x)\n",
229		       status);
230		return;
231	}
232
233	printf("\nListing GUIDs:\n");
234	for (i = 0; i < num_ports; i++)
235		printf("Port %i: 0x%" PRIx64 "\n", i,
236		       cl_hton64(attr_array[i].port_guid));
237}
238
239/**********************************************************************
240 **********************************************************************/
241ib_net64_t get_port_guid(IN osmtest_t * p_osmt, uint64_t port_guid)
242{
243	ib_api_status_t status;
244	uint32_t num_ports = GUID_ARRAY_SIZE;
245	ib_port_attr_t attr_array[GUID_ARRAY_SIZE];
246	int i;
247
248	/*
249	   Call the transport layer for a list of local port
250	   GUID values.
251	 */
252/* "local ports" is(?) phys, shouldn't this exclude port 0 then ? */
253	status =
254	    osm_vendor_get_all_port_attr(p_osmt->p_vendor, attr_array,
255					 &num_ports);
256	if (status != IB_SUCCESS) {
257		printf("\nError from osm_vendor_get_all_port_attr (%x)\n",
258		       status);
259		return (0);
260	}
261
262	if (num_ports == 1) {
263		printf("using default guid 0x%" PRIx64 "\n",
264		       cl_hton64(attr_array[0].port_guid));
265		return (attr_array[0].port_guid);
266	}
267
268	for (i = 0; i < num_ports; i++) {
269		if (attr_array[i].port_guid == port_guid ||
270		    (!port_guid && attr_array[i].link_state > IB_LINK_DOWN))
271			return attr_array[i].port_guid;
272	}
273
274	return 0;
275}
276
277/**********************************************************************
278 **********************************************************************/
279int main(int argc, char *argv[])
280{
281	static osmtest_t osm_test;
282	osmtest_opt_t opt = { 0 };
283	ib_net64_t guid = 0;
284	uint16_t max_lid = 100;
285	ib_api_status_t status;
286	uint32_t log_flags = OSM_LOG_ERROR | OSM_LOG_INFO;
287	int32_t vendor_debug = 0;
288	char flow_name[64];
289	uint32_t next_option;
290	const char *const short_option = "f:l:m:M:d:g:s:t:i:pcvVh";
291
292	/*
293	 * In the array below, the 2nd parameter specified the number
294	 * of arguments as follows:
295	 * 0: no arguments
296	 * 1: argument
297	 * 2: optional
298	 */
299	const struct option long_option[] = {
300		{"create", 0, NULL, 'c'},
301		{"debug", 1, NULL, 'd'},
302		{"flow", 1, NULL, 'f'},
303		{"wait", 1, NULL, 'w'},
304		{"inventory", 1, NULL, 'i'},
305		{"max_lid", 1, NULL, 'm'},
306		{"guid", 2, NULL, 'g'},
307		{"port", 0, NULL, 'p'},
308		{"help", 0, NULL, 'h'},
309		{"stress", 1, NULL, 's'},
310		{"Multicast_Mode", 1, NULL, 'M'},
311		{"timeout", 1, NULL, 't'},
312		{"verbose", 0, NULL, 'v'},
313		{"log_file", 1, NULL, 'l'},
314		{"vf", 1, NULL, 'x'},
315		{"V", 0, NULL, 'V'},
316
317		{NULL, 0, NULL, 0}	/* Required at end of array */
318	};
319
320	/* Make sure that the opensm, complib and osmtest were compiled using
321	   same modes (debug/free) */
322	if (osm_is_debug() != cl_is_debug() || osm_is_debug() != osmt_is_debug()
323	    || osmt_is_debug() != cl_is_debug()) {
324		fprintf(stderr,
325			"-E- OpenSM, Complib and OsmTest were compiled using different modes\n");
326		fprintf(stderr,
327			"-E- OpenSM debug:%d Complib debug:%d OsmTest debug:%d \n",
328			osm_is_debug(), cl_is_debug(), osmt_is_debug());
329		exit(1);
330	}
331
332	opt.transaction_timeout = OSMT_DEFAULT_TRANS_TIMEOUT_MILLISEC;
333	opt.wait_time = OSMT_DEFAULT_TRAP_WAIT_TIMEOUT_SEC;
334	opt.retry_count = OSMT_DEFAULT_RETRY_COUNT;
335	opt.force_log_flush = FALSE;
336	opt.stress = 0;
337	opt.log_file = NULL;
338	opt.create = FALSE;
339	opt.mmode = 1;
340	opt.ignore_path_records = FALSE;	/*  Do path Records too */
341	opt.flow = OSMT_FLOW_ALL;	/*  run all validation tests */
342	strcpy(flow_name, "All Validations");
343	strcpy(opt.file_name, "osmtest.dat");
344
345	printf("\nCommand Line Arguments\n");
346	do {
347		next_option = getopt_long_only(argc, argv, short_option,
348					       long_option, NULL);
349		switch (next_option) {
350		case 'c':
351			/*
352			 * Create the inventory file.
353			 */
354			opt.create = TRUE;
355			printf("\tCreating inventory file\n");
356			break;
357
358		case 'i':
359			/*
360			 * Specifies inventory file name.
361			 */
362			if (strlen(optarg) > OSMTEST_FILE_PATH_MAX)
363				printf
364				    ("\nError: path name too long (ignored)\n");
365			else
366				strcpy(opt.file_name, optarg);
367
368			printf("\tFile = %s\n", opt.file_name);
369			break;
370
371		case 'f':
372			/*
373			 * Specifies Flow .
374			 */
375			if (strlen(optarg) > OSMTEST_FILE_PATH_MAX)
376				printf
377				    ("\nError: path name too long (ignored)\n");
378			else
379				strcpy(flow_name, optarg);
380
381			if (!strcmp("c", optarg)) {
382				strcpy(flow_name, "Create Inventory");
383				opt.flow = OSMT_FLOW_CREATE_INVENTORY;
384			} else if (!strcmp("v", optarg)) {
385				strcpy(flow_name, "Validate Inventory");
386				opt.flow = OSMT_FLOW_VALIDATE_INVENTORY;
387			} else if (!strcmp("s", optarg)) {
388				strcpy(flow_name, "Services Registration");
389				opt.flow = OSMT_FLOW_SERVICE_REGISTRATION;
390			} else if (!strcmp("e", optarg)) {
391				strcpy(flow_name, "Event Forwarding");
392				opt.flow = OSMT_FLOW_EVENT_FORWARDING;
393			} else if (!strcmp("f", optarg)) {
394				strcpy(flow_name, "Stress SA");
395				opt.flow = OSMT_FLOW_STRESS_SA;
396			} else if (!strcmp("m", optarg)) {
397				strcpy(flow_name, "Multicast");
398				opt.flow = OSMT_FLOW_MULTICAST;
399			} else if (!strcmp("q", optarg)) {
400				strcpy(flow_name, "QoS: VLArb and SLtoVL");
401				opt.flow = OSMT_FLOW_QOS;
402			} else if (!strcmp("t", optarg)) {
403				strcpy(flow_name, "Trap 64/65");
404				opt.flow = OSMT_FLOW_TRAP;
405			} else if (!strcmp("a", optarg)) {
406				strcpy(flow_name, "All Validations");
407				opt.flow = OSMT_FLOW_ALL;
408			} else {
409				printf("\nError: unknown flow %s\n", flow_name);
410				exit(2);
411			}
412			break;
413
414		case 'w':
415			/*
416			 * Specifies trap 64/65 wait time
417			 */
418			CL_ASSERT(strtol(optarg, NULL, 0) < 0x100);
419			opt.wait_time = (uint8_t) strtol(optarg, NULL, 0);
420			printf("\tTrap 64/65 wait time = %d\n", opt.wait_time);
421			break;
422
423		case 'm':
424			/*
425			 * Specifies the max LID to search for during exploration.
426			 */
427			max_lid = atoi(optarg);
428			printf("\tMAX-LID %u\n", max_lid);
429			break;
430
431		case 'g':
432			/*
433			 * Specifies port guid with which to bind.
434			 */
435			guid = cl_hton64(strtoull(optarg, NULL, 16));
436			printf(" Guid <0x%" PRIx64 ">\n", cl_hton64(guid));
437			break;
438
439		case 'p':
440			/*
441			 * Display current port guids
442			 */
443			guid = INVALID_GUID;
444			break;
445
446		case 't':
447			/*
448			 * Specifies transaction timeout.
449			 */
450			opt.transaction_timeout = strtol(optarg, NULL, 0);
451			printf("\tTransaction timeout = %d\n",
452			       opt.transaction_timeout);
453			break;
454
455		case 'l':
456			opt.log_file = optarg;
457			printf("\tLog File:%s\n", opt.log_file);
458			break;
459
460		case 'v':
461			/*
462			 * Increases log verbosity.
463			 */
464			log_flags = (log_flags << 1) | 1;
465			printf("\tVerbose option -v (log flags = 0x%X)\n",
466			       log_flags);
467			break;
468
469		case 'V':
470			/*
471			 * Specifies maximum log verbosity.
472			 */
473			log_flags = 0xFFFFFFFF;
474			opt.force_log_flush = TRUE;
475			printf("\tEnabling maximum log verbosity\n");
476			break;
477
478		case 's':
479			/*
480			 * Perform stress test.
481			 */
482			opt.stress = strtol(optarg, NULL, 0);
483			printf("\tStress test enabled: ");
484			switch (opt.stress) {
485			case 1:
486				printf("Small SA queries\n");
487				break;
488			case 2:
489				printf("Large SA queries\n");
490				break;
491			case 3:
492				printf("Large Path Record SA queries\n");
493				break;
494			default:
495				printf("Unknown value %u (ignored)\n",
496				       opt.stress);
497				opt.stress = 0;
498				break;
499			}
500			break;
501
502		case 'M':
503			/*
504			 * Perform multicast test.
505			 */
506			opt.mmode = strtol(optarg, NULL, 0);
507			printf("\tMulticast test enabled: ");
508			switch (opt.mmode) {
509			case 1:
510				printf
511				    ("Short MC Flow - single mode (default)\n");
512				break;
513			case 2:
514				printf("Short MC Flow - multiple mode\n");
515				break;
516			case 3:
517				printf("Long MC Flow - single mode\n");
518				break;
519			case 4:
520				printf("Long MC Flow - multiple mode\n");
521				break;
522			default:
523				printf("Unknown value %u (ignored)\n",
524				       opt.stress);
525				opt.mmode = 0;
526				break;
527			}
528			break;
529
530		case 'd':
531			/*
532			 * Debug Options
533			 */
534			printf("\tDebug Option: ");
535			switch (strtol(optarg, NULL, 0)) {
536			case 1:
537				printf("Ignore Path Records\n");
538				opt.ignore_path_records = TRUE;
539				break;
540			case 2:
541				printf("Force Log Flush\n");
542				opt.force_log_flush = TRUE;
543				break;
544			case 3:
545				/* Used to be memory tracking */
546			default:
547				printf("Unknown value %ld (ignored)\n",
548				       strtol(optarg, NULL, 0));
549				break;
550			}
551			break;
552
553		case 'h':
554			show_usage();
555			return 0;
556
557		case 'x':
558			log_flags = strtol(optarg, NULL, 0);
559			printf
560			    ("\t\t\t\tVerbose option -vf (log flags = 0x%X)\n",
561			     log_flags);
562			break;
563
564		case -1:
565			printf("Done with args\n");
566			break;
567
568		default:	/* something wrong */
569			abort();
570		}
571
572	}
573	while (next_option != -1);
574
575	printf("\tFlow = %s\n", flow_name);
576
577	if (vendor_debug)
578		osm_vendor_set_debug(osm_test.p_vendor, vendor_debug);
579
580	complib_init();
581
582	status = osmtest_init(&osm_test, &opt, (osm_log_level_t) log_flags);
583	if (status != IB_SUCCESS) {
584		printf("\nError from osmtest_init: %s\n",
585		       ib_get_err_str(status));
586		goto Exit;
587	}
588	if (cl_hton64(guid) == cl_hton64(INVALID_GUID)) {
589		print_all_guids(&osm_test);
590		complib_exit();
591		return (status);
592	}
593
594	/*
595	   If the user didn't specify a GUID on the command line,
596	   then get a port GUID value with which to bind.
597	 */
598	if (guid == 0 && !(guid = get_port_guid(&osm_test, guid))) {
599		printf("\nError: port guid 0x%" PRIx64 " not found\n", guid);
600		goto Exit;
601	}
602
603	/*
604	 * Guid may be zero going into this function if the user
605	 * hasn't specified a binding port on the command line.
606	 */
607	status = osmtest_bind(&osm_test, max_lid, guid);
608	if (status != IB_SUCCESS)
609		exit(status);
610
611	status = osmtest_run(&osm_test);
612	if (status != IB_SUCCESS) {
613		printf("OSMTEST: TEST \"%s\" FAIL\n", flow_name);
614	} else {
615		printf("OSMTEST: TEST \"%s\" PASS\n", flow_name);
616	}
617	osmtest_destroy(&osm_test);
618
619	complib_exit();
620
621Exit:
622	return (status);
623}
624