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