1321936Shselasky/* 2321936Shselasky * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. 3321936Shselasky * 4321936Shselasky * This software is available to you under a choice of one of two 5321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 6321936Shselasky * General Public License (GPL) Version 2, available from the file 7321936Shselasky * COPYING in the main directory of this source tree, or the 8321936Shselasky * OpenIB.org BSD license below: 9321936Shselasky * 10321936Shselasky * Redistribution and use in source and binary forms, with or 11321936Shselasky * without modification, are permitted provided that the following 12321936Shselasky * conditions are met: 13321936Shselasky * 14321936Shselasky * - Redistributions of source code must retain the above 15321936Shselasky * copyright notice, this list of conditions and the following 16321936Shselasky * disclaimer. 17321936Shselasky * 18321936Shselasky * - Redistributions in binary form must reproduce the above 19321936Shselasky * copyright notice, this list of conditions and the following 20321936Shselasky * disclaimer in the documentation and/or other materials 21321936Shselasky * provided with the distribution. 22321936Shselasky * 23321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30321936Shselasky * SOFTWARE. 31321936Shselasky * 32321936Shselasky */ 33321936Shselasky 34321936Shselasky#if HAVE_CONFIG_H 35321936Shselasky# include <config.h> 36321936Shselasky#endif /* HAVE_CONFIG_H */ 37321936Shselasky 38321936Shselasky#include <stdio.h> 39321936Shselasky#include <stdlib.h> 40321936Shselasky#include <unistd.h> 41321936Shselasky#include <string.h> 42321936Shselasky#include <signal.h> 43321936Shselasky#include <getopt.h> 44321936Shselasky 45321936Shselasky#include <infiniband/umad.h> 46321936Shselasky#include <infiniband/mad.h> 47321936Shselasky#include <complib/cl_timer.h> 48321936Shselasky 49321936Shselasky#include "ibdiag_common.h" 50321936Shselasky 51321936Shselaskystruct ibmad_port *srcport; 52321936Shselasky 53321936Shselaskystatic char host_and_domain[IB_VENDOR_RANGE2_DATA_SIZE]; 54321936Shselaskystatic char last_host[IB_VENDOR_RANGE2_DATA_SIZE]; 55321936Shselaskystatic ibmad_gid_t dgid; 56321936Shselaskystatic int with_grh; 57321936Shselasky 58321936Shselaskystatic void get_host_and_domain(char *data, int sz) 59321936Shselasky{ 60321936Shselasky char *s = data; 61321936Shselasky int n; 62321936Shselasky 63321936Shselasky if (gethostname(s, sz) < 0) 64321936Shselasky snprintf(s, sz, "?hostname?"); 65321936Shselasky 66321936Shselasky s[sz - 1] = 0; 67321936Shselasky if ((n = strlen(s)) >= sz) 68321936Shselasky return; 69321936Shselasky s[n] = '.'; 70321936Shselasky s += n + 1; 71321936Shselasky sz -= n + 1; 72321936Shselasky 73321936Shselasky if (getdomainname(s, sz) < 0) 74321936Shselasky snprintf(s, sz, "?domainname?"); 75321936Shselasky if (strlen(s) == 0) 76321936Shselasky s[-1] = 0; /* no domain */ 77321936Shselasky} 78321936Shselasky 79321936Shselaskystatic char *ibping_serv(void) 80321936Shselasky{ 81321936Shselasky void *umad; 82321936Shselasky void *mad; 83321936Shselasky char *data; 84321936Shselasky 85321936Shselasky DEBUG("starting to serve..."); 86321936Shselasky 87321936Shselasky while ((umad = mad_receive_via(0, -1, srcport))) { 88321936Shselasky 89321936Shselasky if (umad_status(umad) == 0) { 90321936Shselasky mad = umad_get_mad(umad); 91321936Shselasky data = (char *)mad + IB_VENDOR_RANGE2_DATA_OFFS; 92321936Shselasky 93321936Shselasky memcpy(data, host_and_domain, IB_VENDOR_RANGE2_DATA_SIZE); 94321936Shselasky 95321936Shselasky DEBUG("Pong: %s", data); 96321936Shselasky 97321936Shselasky if (mad_respond_via(umad, 0, 0, srcport) < 0) 98321936Shselasky DEBUG("respond failed"); 99321936Shselasky 100321936Shselasky } 101321936Shselasky mad_free(umad); 102321936Shselasky } 103321936Shselasky 104321936Shselasky DEBUG("server out"); 105321936Shselasky return 0; 106321936Shselasky} 107321936Shselasky 108321936Shselaskystatic int oui = IB_OPENIB_OUI; 109321936Shselasky 110321936Shselaskystatic uint64_t ibping(ib_portid_t * portid, int quiet) 111321936Shselasky{ 112321936Shselasky char data[IB_VENDOR_RANGE2_DATA_SIZE] = { 0 }; 113321936Shselasky ib_vendor_call_t call; 114321936Shselasky uint64_t start, rtt; 115321936Shselasky 116321936Shselasky DEBUG("Ping.."); 117321936Shselasky 118321936Shselasky start = cl_get_time_stamp(); 119321936Shselasky 120321936Shselasky call.method = IB_MAD_METHOD_GET; 121321936Shselasky call.mgmt_class = IB_VENDOR_OPENIB_PING_CLASS; 122321936Shselasky call.attrid = 0; 123321936Shselasky call.mod = 0; 124321936Shselasky call.oui = oui; 125321936Shselasky call.timeout = 0; 126321936Shselasky memset(&call.rmpp, 0, sizeof call.rmpp); 127321936Shselasky 128321936Shselasky if (!ib_vendor_call_via(data, portid, &call, srcport)) 129321936Shselasky return ~0ull; 130321936Shselasky 131321936Shselasky rtt = cl_get_time_stamp() - start; 132321936Shselasky 133321936Shselasky if (!last_host[0]) 134321936Shselasky memcpy(last_host, data, sizeof last_host); 135321936Shselasky 136321936Shselasky if (!quiet) 137321936Shselasky printf("Pong from %s (%s): time %" PRIu64 ".%03" PRIu64 " ms\n", 138321936Shselasky data, portid2str(portid), rtt / 1000, rtt % 1000); 139321936Shselasky 140321936Shselasky return rtt; 141321936Shselasky} 142321936Shselasky 143321936Shselaskystatic uint64_t minrtt = ~0ull, maxrtt, total_rtt; 144321936Shselaskystatic uint64_t start, total_time, replied, lost, ntrans; 145321936Shselaskystatic ib_portid_t portid = { 0 }; 146321936Shselasky 147321936Shselaskyvoid report(int sig) 148321936Shselasky{ 149321936Shselasky total_time = cl_get_time_stamp() - start; 150321936Shselasky 151321936Shselasky DEBUG("out due signal %d", sig); 152321936Shselasky 153321936Shselasky printf("\n--- %s (%s) ibping statistics ---\n", last_host, 154321936Shselasky portid2str(&portid)); 155321936Shselasky printf("%" PRIu64 " packets transmitted, %" PRIu64 " received, %" PRIu64 156321936Shselasky "%% packet loss, time %" PRIu64 " ms\n", ntrans, replied, 157321936Shselasky (lost != 0) ? lost * 100 / ntrans : 0, total_time / 1000); 158321936Shselasky printf("rtt min/avg/max = %" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" 159321936Shselasky PRIu64 "/%" PRIu64 ".%03" PRIu64 " ms\n", 160321936Shselasky minrtt == ~0ull ? 0 : minrtt / 1000, 161321936Shselasky minrtt == ~0ull ? 0 : minrtt % 1000, 162321936Shselasky replied ? total_rtt / replied / 1000 : 0, 163321936Shselasky replied ? (total_rtt / replied) % 1000 : 0, maxrtt / 1000, 164321936Shselasky maxrtt % 1000); 165321936Shselasky 166321936Shselasky exit(0); 167321936Shselasky} 168321936Shselasky 169321936Shselaskystatic int server = 0, flood = 0; 170321936Shselaskystatic unsigned count = ~0; 171321936Shselasky 172321936Shselaskystatic int process_opt(void *context, int ch, char *optarg) 173321936Shselasky{ 174321936Shselasky switch (ch) { 175321936Shselasky case 'c': 176321936Shselasky count = strtoul(optarg, 0, 0); 177321936Shselasky break; 178321936Shselasky case 'f': 179321936Shselasky flood++; 180321936Shselasky break; 181321936Shselasky case 'o': 182321936Shselasky oui = strtoul(optarg, 0, 0); 183321936Shselasky break; 184321936Shselasky case 'S': 185321936Shselasky server++; 186321936Shselasky break; 187321936Shselasky case 25: 188321936Shselasky if (!inet_pton(AF_INET6, optarg, &dgid)) { 189321936Shselasky printf("dgid format is wrong!\n"); 190321936Shselasky ibdiag_show_usage(); 191321936Shselasky return 1; 192321936Shselasky } 193321936Shselasky with_grh = 1; 194321936Shselasky break; 195321936Shselasky default: 196321936Shselasky return -1; 197321936Shselasky } 198321936Shselasky return 0; 199321936Shselasky} 200321936Shselasky 201321936Shselaskyint main(int argc, char **argv) 202321936Shselasky{ 203321936Shselasky int mgmt_classes[1] = { IB_SA_CLASS }; 204321936Shselasky int ping_class = IB_VENDOR_OPENIB_PING_CLASS; 205321936Shselasky uint64_t rtt; 206321936Shselasky char *err; 207321936Shselasky 208321936Shselasky const struct ibdiag_opt opts[] = { 209321936Shselasky {"count", 'c', 1, "<num>", "stop after count packets"}, 210321936Shselasky {"flood", 'f', 0, NULL, "flood destination"}, 211321936Shselasky {"oui", 'o', 1, NULL, "use specified OUI number"}, 212321936Shselasky {"Server", 'S', 0, NULL, "start in server mode"}, 213321936Shselasky {"dgid", 25, 1, NULL, "remote gid (IPv6 format)"}, 214321936Shselasky {0} 215321936Shselasky }; 216321936Shselasky char usage_args[] = "<dest lid|guid>"; 217321936Shselasky 218321936Shselasky ibdiag_process_opts(argc, argv, NULL, "DKy", opts, process_opt, 219321936Shselasky usage_args, NULL); 220321936Shselasky 221321936Shselasky argc -= optind; 222321936Shselasky argv += optind; 223321936Shselasky 224321936Shselasky if (!argc && !server) 225321936Shselasky ibdiag_show_usage(); 226321936Shselasky 227321936Shselasky srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 1); 228321936Shselasky if (!srcport) 229321936Shselasky IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); 230321936Shselasky 231321936Shselasky if (server) { 232321936Shselasky if (mad_register_server_via(ping_class, 0, 0, oui, srcport) < 0) 233321936Shselasky IBEXIT("can't serve class %d on this port", 234321936Shselasky ping_class); 235321936Shselasky 236321936Shselasky get_host_and_domain(host_and_domain, sizeof host_and_domain); 237321936Shselasky 238321936Shselasky if ((err = ibping_serv())) 239321936Shselasky IBEXIT("ibping to %s: %s", portid2str(&portid), err); 240321936Shselasky exit(0); 241321936Shselasky } 242321936Shselasky 243321936Shselasky if (mad_register_client_via(ping_class, 0, srcport) < 0) 244321936Shselasky IBEXIT("can't register ping class %d on this port", 245321936Shselasky ping_class); 246321936Shselasky 247321936Shselasky if (with_grh && ibd_dest_type != IB_DEST_LID) 248321936Shselasky IBEXIT("When using GRH, LID should be provided"); 249321936Shselasky if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[0], 250321936Shselasky ibd_dest_type, ibd_sm_id, srcport) < 0) 251321936Shselasky IBEXIT("can't resolve destination port %s", argv[0]); 252321936Shselasky 253321936Shselasky if (with_grh) { 254321936Shselasky portid.grh_present = 1; 255321936Shselasky memcpy(&portid.gid, &dgid, sizeof(portid.gid)); 256321936Shselasky } 257321936Shselasky 258321936Shselasky signal(SIGINT, report); 259321936Shselasky signal(SIGTERM, report); 260321936Shselasky 261321936Shselasky start = cl_get_time_stamp(); 262321936Shselasky 263321936Shselasky while (count-- > 0) { 264321936Shselasky ntrans++; 265321936Shselasky if ((rtt = ibping(&portid, flood)) == ~0ull) { 266321936Shselasky DEBUG("ibping to %s failed", portid2str(&portid)); 267321936Shselasky lost++; 268321936Shselasky } else { 269321936Shselasky if (rtt < minrtt) 270321936Shselasky minrtt = rtt; 271321936Shselasky if (rtt > maxrtt) 272321936Shselasky maxrtt = rtt; 273321936Shselasky total_rtt += rtt; 274321936Shselasky replied++; 275321936Shselasky } 276321936Shselasky 277321936Shselasky if (!flood) 278321936Shselasky sleep(1); 279321936Shselasky } 280321936Shselasky 281321936Shselasky report(0); 282321936Shselasky 283321936Shselasky mad_rpc_close_port(srcport); 284321936Shselasky 285321936Shselasky exit(-1); 286321936Shselasky} 287