1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#if HAVE_CONFIG_H 35219820Sjeff# include <config.h> 36219820Sjeff#endif /* HAVE_CONFIG_H */ 37219820Sjeff 38219820Sjeff#include <stdio.h> 39219820Sjeff#include <stdlib.h> 40219820Sjeff#include <unistd.h> 41219820Sjeff#include <stdarg.h> 42219820Sjeff#include <time.h> 43219820Sjeff#include <string.h> 44219820Sjeff#include <signal.h> 45219820Sjeff#include <getopt.h> 46219820Sjeff 47219820Sjeff#include <infiniband/common.h> 48219820Sjeff#include <infiniband/umad.h> 49219820Sjeff#include <infiniband/mad.h> 50219820Sjeff 51219820Sjeff#include "ibdiag_common.h" 52219820Sjeff 53219820Sjeff#undef DEBUG 54219820Sjeff#define DEBUG if (verbose) IBWARN 55219820Sjeff 56219820Sjeffstatic int dest_type = IB_DEST_LID; 57219820Sjeffstatic int verbose; 58219820Sjeffstatic char host_and_domain[IB_VENDOR_RANGE2_DATA_SIZE]; 59219820Sjeffstatic char last_host[IB_VENDOR_RANGE2_DATA_SIZE]; 60219820Sjeff 61219820Sjeffchar *argv0 = "ibping"; 62219820Sjeff 63219820Sjeffstatic void 64219820Sjeffget_host_and_domain(char *data, int sz) 65219820Sjeff{ 66219820Sjeff char *s = data; 67219820Sjeff int n; 68219820Sjeff 69219820Sjeff if (gethostname(s, sz) < 0) 70219820Sjeff snprintf(s, sz, "?hostname?"); 71219820Sjeff 72219820Sjeff s[sz-1] = 0; 73219820Sjeff if ((n = strlen(s)) >= sz) 74219820Sjeff return; 75219820Sjeff s[n] = '.'; 76219820Sjeff s += n + 1; 77219820Sjeff sz -= n + 1; 78219820Sjeff 79219820Sjeff if (getdomainname(s, sz) < 0) 80219820Sjeff snprintf(s, sz, "?domainname?"); 81219820Sjeff if (strlen(s) == 0) 82219820Sjeff s[-1] = 0; /* no domain */ 83219820Sjeff} 84219820Sjeff 85219820Sjeffstatic char * 86219820Sjeffibping_serv(void) 87219820Sjeff{ 88219820Sjeff void *umad; 89219820Sjeff void *mad; 90219820Sjeff char *data; 91219820Sjeff 92219820Sjeff DEBUG("starting to serve..."); 93219820Sjeff 94219820Sjeff while ((umad = mad_receive(0, -1))) { 95219820Sjeff 96219820Sjeff mad = umad_get_mad(umad); 97219820Sjeff data = (char *)mad + IB_VENDOR_RANGE2_DATA_OFFS; 98219820Sjeff 99219820Sjeff memcpy(data, host_and_domain, IB_VENDOR_RANGE2_DATA_SIZE); 100219820Sjeff 101219820Sjeff DEBUG("Pong: %s", data); 102219820Sjeff 103219820Sjeff if (mad_respond(umad, 0, 0) < 0) 104219820Sjeff DEBUG("respond failed"); 105219820Sjeff 106219820Sjeff mad_free(umad); 107219820Sjeff } 108219820Sjeff 109219820Sjeff DEBUG("server out"); 110219820Sjeff return 0; 111219820Sjeff} 112219820Sjeff 113219820Sjeffstatic uint64_t 114219820Sjeffibping(ib_portid_t *portid, int quiet) 115219820Sjeff{ 116219820Sjeff char data[IB_VENDOR_RANGE2_DATA_SIZE] = {0}; 117219820Sjeff ib_vendor_call_t call; 118219820Sjeff uint64_t start, rtt; 119219820Sjeff 120219820Sjeff DEBUG("Ping.."); 121219820Sjeff 122219820Sjeff start = getcurrenttime(); 123219820Sjeff 124219820Sjeff call.method = IB_MAD_METHOD_GET; 125219820Sjeff call.mgmt_class = IB_VENDOR_OPENIB_PING_CLASS; 126219820Sjeff call.attrid = 0; 127219820Sjeff call.mod = 0; 128219820Sjeff call.oui = IB_OPENIB_OUI; 129219820Sjeff call.timeout = 0; 130219820Sjeff memset(&call.rmpp, 0, sizeof call.rmpp); 131219820Sjeff 132219820Sjeff if (!ib_vendor_call(data, portid, &call)) 133219820Sjeff return ~0llu; 134219820Sjeff 135219820Sjeff rtt = getcurrenttime() - start; 136219820Sjeff 137219820Sjeff if (!last_host[0]) 138219820Sjeff memcpy(last_host, data, sizeof last_host); 139219820Sjeff 140219820Sjeff if (!quiet) 141219820Sjeff printf("Pong from %s (%s): time %" PRIu64 ".%03" PRIu64 " ms\n", 142219820Sjeff data, portid2str(portid), rtt/1000, rtt%1000); 143219820Sjeff 144219820Sjeff return rtt; 145219820Sjeff} 146219820Sjeff 147219820Sjeffstatic void 148219820Sjeffusage(void) 149219820Sjeff{ 150219820Sjeff char *basename; 151219820Sjeff 152219820Sjeff if (!(basename = strrchr(argv0, '/'))) 153219820Sjeff basename = argv0; 154219820Sjeff else 155219820Sjeff basename++; 156219820Sjeff 157219820Sjeff fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " 158219820Sjeff "-t(imeout) timeout_ms -c ping_count -f(lood) -o oui -S(erver)] <dest lid|guid>\n", 159219820Sjeff basename); 160219820Sjeff exit(-1); 161219820Sjeff} 162219820Sjeff 163219820Sjeffstatic uint64_t minrtt = ~0ull, maxrtt, total_rtt; 164219820Sjeffstatic uint64_t start, total_time, replied, lost, ntrans; 165219820Sjeffstatic ib_portid_t portid = {0}; 166219820Sjeff 167219820Sjeffvoid 168219820Sjeffreport(int sig) 169219820Sjeff{ 170219820Sjeff total_time = getcurrenttime() - start; 171219820Sjeff 172219820Sjeff DEBUG("out due signal %d", sig); 173219820Sjeff 174219820Sjeff printf("\n--- %s (%s) ibping statistics ---\n", last_host, portid2str(&portid)); 175219820Sjeff printf("%" PRIu64 " packets transmitted, %" PRIu64 " received, %" PRIu64 "%% packet loss, time %" PRIu64 " ms\n", 176219820Sjeff ntrans, replied, 177219820Sjeff (lost != 0) ? lost * 100 / ntrans : 0, total_time / 1000); 178219820Sjeff printf("rtt min/avg/max = %" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" PRIu64 " ms\n", 179219820Sjeff minrtt == ~0ull ? 0 : minrtt/1000, 180219820Sjeff minrtt == ~0ull ? 0 : minrtt%1000, 181219820Sjeff replied ? total_rtt/replied/1000 : 0, 182219820Sjeff replied ? (total_rtt/replied)%1000 : 0, 183219820Sjeff maxrtt/1000, maxrtt%1000); 184219820Sjeff 185219820Sjeff exit(0); 186219820Sjeff} 187219820Sjeff 188219820Sjeffint 189219820Sjeffmain(int argc, char **argv) 190219820Sjeff{ 191219820Sjeff int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; 192219820Sjeff int ping_class = IB_VENDOR_OPENIB_PING_CLASS; 193219820Sjeff ib_portid_t *sm_id = 0, sm_portid = {0}; 194219820Sjeff int timeout = 0, udebug = 0, server = 0, flood = 0; 195219820Sjeff int oui = IB_OPENIB_OUI; 196219820Sjeff uint64_t rtt; 197219820Sjeff unsigned count = ~0; 198219820Sjeff extern int ibdebug; 199219820Sjeff char *err; 200219820Sjeff char *ca = 0; 201219820Sjeff int ca_port = 0; 202219820Sjeff 203219820Sjeff static char const str_opts[] = "C:P:t:s:c:o:devGfSVhu"; 204219820Sjeff static const struct option long_opts[] = { 205219820Sjeff { "C", 1, 0, 'C'}, 206219820Sjeff { "P", 1, 0, 'P'}, 207219820Sjeff { "debug", 0, 0, 'd'}, 208219820Sjeff { "err_show", 0, 0, 'e'}, 209219820Sjeff { "verbose", 0, 0, 'v'}, 210219820Sjeff { "Guid", 0, 0, 'G'}, 211219820Sjeff { "s", 1, 0, 's'}, 212219820Sjeff { "timeout", 1, 0, 't'}, 213219820Sjeff { "c", 1, 0, 'c'}, 214219820Sjeff { "flood", 0, 0, 'f'}, 215219820Sjeff { "o", 1, 0, 'o'}, 216219820Sjeff { "Server", 0, 0, 'S'}, 217219820Sjeff { "Version", 0, 0, 'V'}, 218219820Sjeff { "help", 0, 0, 'h'}, 219219820Sjeff { "usage", 0, 0, 'u'}, 220219820Sjeff { } 221219820Sjeff }; 222219820Sjeff 223219820Sjeff argv0 = argv[0]; 224219820Sjeff 225219820Sjeff while (1) { 226219820Sjeff int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); 227219820Sjeff if ( ch == -1 ) 228219820Sjeff break; 229219820Sjeff switch(ch) { 230219820Sjeff case 'C': 231219820Sjeff ca = optarg; 232219820Sjeff break; 233219820Sjeff case 'P': 234219820Sjeff ca_port = strtoul(optarg, 0, 0); 235219820Sjeff break; 236219820Sjeff case 'c': 237219820Sjeff count = strtoul(optarg, 0, 0); 238219820Sjeff break; 239219820Sjeff case 'd': 240219820Sjeff ibdebug++; 241219820Sjeff madrpc_show_errors(1); 242219820Sjeff umad_debug(udebug); 243219820Sjeff udebug++; 244219820Sjeff break; 245219820Sjeff case 'e': 246219820Sjeff madrpc_show_errors(1); 247219820Sjeff break; 248219820Sjeff case 'f': 249219820Sjeff flood++; 250219820Sjeff break; 251219820Sjeff case 'G': 252219820Sjeff dest_type = IB_DEST_GUID; 253219820Sjeff break; 254219820Sjeff case 'o': 255219820Sjeff oui = strtoul(optarg, 0, 0); 256219820Sjeff break; 257219820Sjeff case 's': 258219820Sjeff if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) 259219820Sjeff IBERROR("can't resolve SM destination port %s", optarg); 260219820Sjeff sm_id = &sm_portid; 261219820Sjeff break; 262219820Sjeff case 'S': 263219820Sjeff server++; 264219820Sjeff break; 265219820Sjeff case 't': 266219820Sjeff timeout = strtoul(optarg, 0, 0); 267219820Sjeff madrpc_set_timeout(timeout); 268219820Sjeff break; 269219820Sjeff case 'v': 270219820Sjeff verbose++; 271219820Sjeff break; 272219820Sjeff case 'V': 273219820Sjeff fprintf(stderr, "%s %s\n", argv0, get_build_version() ); 274219820Sjeff exit(-1); 275219820Sjeff default: 276219820Sjeff usage(); 277219820Sjeff break; 278219820Sjeff } 279219820Sjeff } 280219820Sjeff argc -= optind; 281219820Sjeff argv += optind; 282219820Sjeff 283219820Sjeff if (!argc && !server) 284219820Sjeff usage(); 285219820Sjeff 286219820Sjeff madrpc_init(ca, ca_port, mgmt_classes, 3); 287219820Sjeff 288219820Sjeff if (server) { 289219820Sjeff if (mad_register_server(ping_class, 0, 0, oui) < 0) 290219820Sjeff IBERROR("can't serve class %d on this port", ping_class); 291219820Sjeff 292219820Sjeff get_host_and_domain(host_and_domain, sizeof host_and_domain); 293219820Sjeff 294219820Sjeff if ((err = ibping_serv())) 295219820Sjeff IBERROR("ibping to %s: %s", portid2str(&portid), err); 296219820Sjeff exit(0); 297219820Sjeff } 298219820Sjeff 299219820Sjeff if (mad_register_client(ping_class, 0) < 0) 300219820Sjeff IBERROR("can't register ping class %d on this port", ping_class); 301219820Sjeff 302219820Sjeff if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) 303219820Sjeff IBERROR("can't resolve destination port %s", argv[0]); 304219820Sjeff 305219820Sjeff signal(SIGINT, report); 306219820Sjeff signal(SIGTERM, report); 307219820Sjeff 308219820Sjeff start = getcurrenttime(); 309219820Sjeff 310219820Sjeff while (count-- > 0) { 311219820Sjeff ntrans++; 312219820Sjeff if ((rtt = ibping(&portid, flood)) == ~0ull) { 313219820Sjeff DEBUG("ibping to %s failed", portid2str(&portid)); 314219820Sjeff lost++; 315219820Sjeff } else { 316219820Sjeff if (rtt < minrtt) 317219820Sjeff minrtt = rtt; 318219820Sjeff if (rtt > maxrtt) 319219820Sjeff maxrtt = rtt; 320219820Sjeff total_rtt += rtt; 321219820Sjeff replied++; 322219820Sjeff } 323219820Sjeff 324219820Sjeff if (!flood) 325219820Sjeff sleep(1); 326219820Sjeff } 327219820Sjeff 328219820Sjeff report(0); 329219820Sjeff 330219820Sjeff exit(-1); 331219820Sjeff} 332