infiniband-diags: initial port of linux ib diags
[mirror/winof/.git] / tools / infiniband_diags / src / ibping.c
1 /*\r
2  * Copyright (c) 2004-2008 Voltaire Inc.  All rights reserved.\r
3  *\r
4  * This software is available to you under a choice of one of two\r
5  * licenses.  You may choose to be licensed under the terms of the GNU\r
6  * General Public License (GPL) Version 2, available from the file\r
7  * COPYING in the main directory of this source tree, or the\r
8  * OpenIB.org BSD license below:\r
9  *\r
10  *     Redistribution and use in source and binary forms, with or\r
11  *     without modification, are permitted provided that the following\r
12  *     conditions are met:\r
13  *\r
14  *      - Redistributions of source code must retain the above\r
15  *        copyright notice, this list of conditions and the following\r
16  *        disclaimer.\r
17  *\r
18  *      - Redistributions in binary form must reproduce the above\r
19  *        copyright notice, this list of conditions and the following\r
20  *        disclaimer in the documentation and/or other materials\r
21  *        provided with the distribution.\r
22  *\r
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
30  * SOFTWARE.\r
31  *\r
32  */\r
33 \r
34 #if HAVE_CONFIG_H\r
35 #  include <config.h>\r
36 #endif /* HAVE_CONFIG_H */\r
37 \r
38 #include <stdio.h>\r
39 #include <stdlib.h>\r
40 \r
41 #if defined(_WIN32) \r
42 #include <windows.h>\r
43 #include <winsock2.h>\r
44 #include <ws2tcpip.h> \r
45 #include "..\..\..\..\etc\user\getopt.c"\r
46 #else\r
47 #include <unistd.h>\r
48 #include <stdarg.h>\r
49 #include <time.h>\r
50 #include <string.h>\r
51 #include <signal.h>\r
52 #include <getopt.h>\r
53 #endif\r
54 \r
55 #include <infiniband/umad.h>\r
56 #include <infiniband/mad.h>\r
57 \r
58 #include "ibdiag_common.h"\r
59 \r
60 #undef DEBUG\r
61 #define DEBUG   if (verbose) IBWARN\r
62 \r
63 static int dest_type = IB_DEST_LID;\r
64 static int verbose;\r
65 static char host_and_domain[IB_VENDOR_RANGE2_DATA_SIZE];\r
66 static char last_host[IB_VENDOR_RANGE2_DATA_SIZE];\r
67 \r
68 char *argv0 = "ibping";\r
69 \r
70 static void\r
71 get_host_and_domain(char *data, int sz)\r
72 {\r
73         char *s = data;\r
74         int n;\r
75 \r
76         if (gethostname(s, sz) < 0)\r
77                 snprintf(s, sz, "?hostname?");\r
78 \r
79         s[sz-1] = 0;\r
80         if ((n = strlen(s)) >= sz)\r
81                 return;\r
82         s[n] = '.';\r
83         s += n + 1;\r
84         sz -= n + 1;\r
85 \r
86         if (getdomainname(s, sz) < 0)\r
87                 snprintf(s, sz, "?domainname?");\r
88         if (strlen(s) == 0)\r
89                 s[-1] = 0;      /* no domain */\r
90 }\r
91 \r
92 static char *\r
93 ibping_serv(void)\r
94 {\r
95         void *umad;\r
96         void *mad;\r
97         char *data;\r
98 \r
99         DEBUG("starting to serve...");\r
100 \r
101         while ((umad = mad_receive(0, -1))) {\r
102 \r
103                 mad = umad_get_mad(umad);\r
104                 data = (char *)mad + IB_VENDOR_RANGE2_DATA_OFFS;\r
105 \r
106                 memcpy(data, host_and_domain, IB_VENDOR_RANGE2_DATA_SIZE);\r
107 \r
108                 DEBUG("Pong: %s", data);\r
109 \r
110                 if (mad_respond(umad, 0, 0) < 0)\r
111                         DEBUG("respond failed");\r
112 \r
113                 mad_free(umad);\r
114         }\r
115 \r
116         DEBUG("server out");\r
117         return 0;\r
118 }\r
119 \r
120 static uint64_t\r
121 ibping(ib_portid_t *portid, int quiet)\r
122 {\r
123         char data[IB_VENDOR_RANGE2_DATA_SIZE] = {0};\r
124         ib_vendor_call_t call;\r
125         uint64_t start, rtt;\r
126 \r
127         DEBUG("Ping..");\r
128 \r
129         start = getcurrenttime();\r
130 \r
131         call.method = IB_MAD_METHOD_GET;\r
132         call.mgmt_class = IB_VENDOR_OPENIB_PING_CLASS;\r
133         call.attrid = 0;\r
134         call.mod = 0;\r
135         call.oui = IB_OPENIB_OUI;\r
136         call.timeout = 0;\r
137         memset(&call.rmpp, 0, sizeof call.rmpp);\r
138 \r
139         if (!ib_vendor_call(data, portid, &call))\r
140                 return ~0llu;\r
141 \r
142         rtt = getcurrenttime() - start;\r
143 \r
144         if (!last_host[0])\r
145                 memcpy(last_host, data, sizeof last_host);\r
146 \r
147         if (!quiet)\r
148                 printf("Pong from %s (%s): time %" PRIu64 ".%03" PRIu64 " ms\n",\r
149                         data, portid2str(portid), rtt/1000, rtt%1000);\r
150 \r
151         return rtt;\r
152 }\r
153 \r
154 static void\r
155 usage(void)\r
156 {\r
157         char *basename;\r
158 \r
159         if (!(basename = strrchr(argv0, '/')))\r
160                 basename = argv0;\r
161         else\r
162                 basename++;\r
163 \r
164         fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port "\r
165                         "-t(imeout) timeout_ms -c ping_count -f(lood) -o oui -S(erver)] <dest lid|guid>\n",\r
166                         basename);\r
167         exit(-1);\r
168 }\r
169 \r
170 static uint64_t minrtt = ~0ull, maxrtt, total_rtt;\r
171 static uint64_t start, total_time, replied, lost, ntrans;\r
172 static ib_portid_t portid = {0};\r
173 \r
174 void\r
175 report(int sig)\r
176 {\r
177         total_time = getcurrenttime() - start;\r
178 \r
179         DEBUG("out due signal %d", sig);\r
180 \r
181         printf("\n--- %s (%s) ibping statistics ---\n", last_host, portid2str(&portid));\r
182         printf("%" PRIu64 " packets transmitted, %" PRIu64 " received, %" PRIu64 "%% packet loss, time %" PRIu64 " ms\n",\r
183                 ntrans, replied,\r
184                 (lost != 0) ?  lost * 100 / ntrans : 0, total_time / 1000);\r
185         printf("rtt min/avg/max = %" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" PRIu64 " ms\n",\r
186                 minrtt == ~0ull ? 0 : minrtt/1000,\r
187                 minrtt == ~0ull ? 0 : minrtt%1000,\r
188                 replied ? total_rtt/replied/1000 : 0,\r
189                 replied ? (total_rtt/replied)%1000 : 0,\r
190                 maxrtt/1000, maxrtt%1000);\r
191 \r
192         exit(0);\r
193 }\r
194 \r
195 int\r
196 main(int argc, char **argv)\r
197 {\r
198         int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS};\r
199         int ping_class = IB_VENDOR_OPENIB_PING_CLASS;\r
200         ib_portid_t *sm_id = 0, sm_portid = {0};\r
201         int timeout = 0, udebug = 0, server = 0, flood = 0;\r
202         int oui = IB_OPENIB_OUI;\r
203         uint64_t rtt;\r
204         uint count = ~0;\r
205         extern int ibdebug;\r
206         char *err;\r
207         char *ca = 0;\r
208         int ca_port = 0;\r
209 \r
210         static char str_opts[] = "C:P:t:s:c:o:devGfSVhu";\r
211         static struct option long_opts[] = {\r
212                 { "C", 1, 0, 'C'},\r
213                 { "P", 1, 0, 'P'},\r
214                 { "debug", 0, 0, 'd'},\r
215                 { "err_show", 0, 0, 'e'},\r
216                 { "verbose", 0, 0, 'v'},\r
217                 { "Guid", 0, 0, 'G'},\r
218                 { "s", 1, 0, 's'},\r
219                 { "timeout", 1, 0, 't'},\r
220                 { "c", 1, 0, 'c'},\r
221                 { "flood", 0, 0, 'f'},\r
222                 { "o", 1, 0, 'o'},\r
223                 { "Server", 0, 0, 'S'},\r
224                 { "Version", 0, 0, 'V'},\r
225                 { "help", 0, 0, 'h'},\r
226                 { "usage", 0, 0, 'u'},\r
227                 { 0 }\r
228         };\r
229 \r
230         argv0 = argv[0];\r
231 \r
232         while (1) {\r
233                 int ch = getopt_long(argc, argv, str_opts, long_opts, NULL);\r
234                 if ( ch == -1 )\r
235                         break;\r
236                 switch(ch) {\r
237                 case 'C':\r
238                         ca = optarg;\r
239                         break;\r
240                 case 'P':\r
241                         ca_port = strtoul(optarg, 0, 0);\r
242                         break;\r
243                 case 'c':\r
244                         count = strtoul(optarg, 0, 0);\r
245                         break;\r
246                 case 'd':\r
247                         ibdebug++;\r
248                         madrpc_show_errors(1);\r
249                         umad_debug(udebug);\r
250                         udebug++;\r
251                         break;\r
252                 case 'e':\r
253                         madrpc_show_errors(1);\r
254                         break;\r
255                 case 'f':\r
256                         flood++;\r
257                         break;\r
258                 case 'G':\r
259                         dest_type = IB_DEST_GUID;\r
260                         break;\r
261                 case 'o':\r
262                         oui = strtoul(optarg, 0, 0);\r
263                         break;\r
264                 case 's':\r
265                         if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0)\r
266                                 IBERROR("can't resolve SM destination port %s", optarg);\r
267                         sm_id = &sm_portid;\r
268                         break;\r
269                 case 'S':\r
270                         server++;\r
271                         break;\r
272                 case 't':\r
273                         timeout = strtoul(optarg, 0, 0);\r
274                         madrpc_set_timeout(timeout);\r
275                         break;\r
276                 case 'v':\r
277                         verbose++;\r
278                         break;\r
279                 case 'V':\r
280                         fprintf(stderr, "%s %s\n", argv0, get_build_version() );\r
281                         exit(-1);\r
282                 default:\r
283                         usage();\r
284                         break;\r
285                 }\r
286         }\r
287         argc -= optind;\r
288         argv += optind;\r
289 \r
290         if (!argc && !server)\r
291                 usage();\r
292 \r
293         madrpc_init(ca, ca_port, mgmt_classes, 3);\r
294 \r
295         if (server) {\r
296                 if (mad_register_server(ping_class, 0, 0, oui) < 0)\r
297                         IBERROR("can't serve class %d on this port", ping_class);\r
298 \r
299                 get_host_and_domain(host_and_domain, sizeof host_and_domain);\r
300 \r
301                 if ((err = ibping_serv()))\r
302                         IBERROR("ibping to %s: %s", portid2str(&portid), err);\r
303                 exit(0);\r
304         }\r
305 \r
306         if (mad_register_client(ping_class, 0) < 0)\r
307                 IBERROR("can't register ping class %d on this port", ping_class);\r
308 \r
309         if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0)\r
310                 IBERROR("can't resolve destination port %s", argv[0]);\r
311 \r
312         signal(SIGINT, report);\r
313         signal(SIGTERM, report);\r
314 \r
315         start = getcurrenttime();\r
316 \r
317         while (count-- > 0) {\r
318                 ntrans++;\r
319                 if ((rtt = ibping(&portid, flood)) == ~0ull) {\r
320                         DEBUG("ibping to %s failed", portid2str(&portid));\r
321                         lost++;\r
322                 } else {\r
323                         if (rtt < minrtt)\r
324                                 minrtt = rtt;\r
325                         if (rtt > maxrtt)\r
326                                 maxrtt = rtt;\r
327                         total_rtt += rtt;\r
328                         replied++;\r
329                 }\r
330 \r
331                 if (!flood)\r
332                         sleep(1);\r
333         }\r
334 \r
335         report(0);\r
336 \r
337         exit(-1);\r
338 }\r