1 /* 2 * Copyright (c) 2004-2009 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 <string.h> 42 #include <signal.h> 43 #include <getopt.h> 44 45 #include <infiniband/umad.h> 46 #include <infiniband/mad.h> 47 #include <complib/cl_timer.h> 48 49 #include "ibdiag_common.h" 50 51 struct ibmad_port *srcport; 52 53 static char host_and_domain[IB_VENDOR_RANGE2_DATA_SIZE]; 54 static char last_host[IB_VENDOR_RANGE2_DATA_SIZE]; 55 static ibmad_gid_t dgid; 56 static int with_grh; 57 58 static void get_host_and_domain(char *data, int sz) 59 { 60 char *s = data; 61 int n; 62 63 if (gethostname(s, sz) < 0) 64 snprintf(s, sz, "?hostname?"); 65 66 s[sz - 1] = 0; 67 if ((n = strlen(s)) >= sz) 68 return; 69 s[n] = '.'; 70 s += n + 1; 71 sz -= n + 1; 72 73 if (getdomainname(s, sz) < 0) 74 snprintf(s, sz, "?domainname?"); 75 if (strlen(s) == 0) 76 s[-1] = 0; /* no domain */ 77 } 78 79 static char *ibping_serv(void) 80 { 81 void *umad; 82 void *mad; 83 char *data; 84 85 DEBUG("starting to serve..."); 86 87 while ((umad = mad_receive_via(0, -1, srcport))) { 88 89 if (umad_status(umad) == 0) { 90 mad = umad_get_mad(umad); 91 data = (char *)mad + IB_VENDOR_RANGE2_DATA_OFFS; 92 93 memcpy(data, host_and_domain, IB_VENDOR_RANGE2_DATA_SIZE); 94 95 DEBUG("Pong: %s", data); 96 97 if (mad_respond_via(umad, 0, 0, srcport) < 0) 98 DEBUG("respond failed"); 99 100 } 101 mad_free(umad); 102 } 103 104 DEBUG("server out"); 105 return 0; 106 } 107 108 static int oui = IB_OPENIB_OUI; 109 110 static uint64_t ibping(ib_portid_t * portid, int quiet) 111 { 112 char data[IB_VENDOR_RANGE2_DATA_SIZE] = { 0 }; 113 ib_vendor_call_t call; 114 uint64_t start, rtt; 115 116 DEBUG("Ping.."); 117 118 start = cl_get_time_stamp(); 119 120 call.method = IB_MAD_METHOD_GET; 121 call.mgmt_class = IB_VENDOR_OPENIB_PING_CLASS; 122 call.attrid = 0; 123 call.mod = 0; 124 call.oui = oui; 125 call.timeout = 0; 126 memset(&call.rmpp, 0, sizeof call.rmpp); 127 128 if (!ib_vendor_call_via(data, portid, &call, srcport)) 129 return ~0ull; 130 131 rtt = cl_get_time_stamp() - start; 132 133 if (!last_host[0]) 134 memcpy(last_host, data, sizeof last_host); 135 136 if (!quiet) 137 printf("Pong from %s (%s): time %" PRIu64 ".%03" PRIu64 " ms\n", 138 data, portid2str(portid), rtt / 1000, rtt % 1000); 139 140 return rtt; 141 } 142 143 static uint64_t minrtt = ~0ull, maxrtt, total_rtt; 144 static uint64_t start, total_time, replied, lost, ntrans; 145 static ib_portid_t portid = { 0 }; 146 147 void report(int sig) 148 { 149 total_time = cl_get_time_stamp() - start; 150 151 DEBUG("out due signal %d", sig); 152 153 printf("\n--- %s (%s) ibping statistics ---\n", last_host, 154 portid2str(&portid)); 155 printf("%" PRIu64 " packets transmitted, %" PRIu64 " received, %" PRIu64 156 "%% packet loss, time %" PRIu64 " ms\n", ntrans, replied, 157 (lost != 0) ? lost * 100 / ntrans : 0, total_time / 1000); 158 printf("rtt min/avg/max = %" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" 159 PRIu64 "/%" PRIu64 ".%03" PRIu64 " ms\n", 160 minrtt == ~0ull ? 0 : minrtt / 1000, 161 minrtt == ~0ull ? 0 : minrtt % 1000, 162 replied ? total_rtt / replied / 1000 : 0, 163 replied ? (total_rtt / replied) % 1000 : 0, maxrtt / 1000, 164 maxrtt % 1000); 165 166 exit(0); 167 } 168 169 static int server = 0, flood = 0; 170 static unsigned count = ~0; 171 172 static int process_opt(void *context, int ch, char *optarg) 173 { 174 switch (ch) { 175 case 'c': 176 count = strtoul(optarg, 0, 0); 177 break; 178 case 'f': 179 flood++; 180 break; 181 case 'o': 182 oui = strtoul(optarg, 0, 0); 183 break; 184 case 'S': 185 server++; 186 break; 187 case 25: 188 if (!inet_pton(AF_INET6, optarg, &dgid)) { 189 printf("dgid format is wrong!\n"); 190 ibdiag_show_usage(); 191 return 1; 192 } 193 with_grh = 1; 194 break; 195 default: 196 return -1; 197 } 198 return 0; 199 } 200 201 int main(int argc, char **argv) 202 { 203 int mgmt_classes[1] = { IB_SA_CLASS }; 204 int ping_class = IB_VENDOR_OPENIB_PING_CLASS; 205 uint64_t rtt; 206 char *err; 207 208 const struct ibdiag_opt opts[] = { 209 {"count", 'c', 1, "<num>", "stop after count packets"}, 210 {"flood", 'f', 0, NULL, "flood destination"}, 211 {"oui", 'o', 1, NULL, "use specified OUI number"}, 212 {"Server", 'S', 0, NULL, "start in server mode"}, 213 {"dgid", 25, 1, NULL, "remote gid (IPv6 format)"}, 214 {0} 215 }; 216 char usage_args[] = "<dest lid|guid>"; 217 218 ibdiag_process_opts(argc, argv, NULL, "DKy", opts, process_opt, 219 usage_args, NULL); 220 221 argc -= optind; 222 argv += optind; 223 224 if (!argc && !server) 225 ibdiag_show_usage(); 226 227 srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 1); 228 if (!srcport) 229 IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); 230 231 if (server) { 232 if (mad_register_server_via(ping_class, 0, 0, oui, srcport) < 0) 233 IBEXIT("can't serve class %d on this port", 234 ping_class); 235 236 get_host_and_domain(host_and_domain, sizeof host_and_domain); 237 238 if ((err = ibping_serv())) 239 IBEXIT("ibping to %s: %s", portid2str(&portid), err); 240 exit(0); 241 } 242 243 if (mad_register_client_via(ping_class, 0, srcport) < 0) 244 IBEXIT("can't register ping class %d on this port", 245 ping_class); 246 247 if (with_grh && ibd_dest_type != IB_DEST_LID) 248 IBEXIT("When using GRH, LID should be provided"); 249 if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[0], 250 ibd_dest_type, ibd_sm_id, srcport) < 0) 251 IBEXIT("can't resolve destination port %s", argv[0]); 252 253 if (with_grh) { 254 portid.grh_present = 1; 255 memcpy(&portid.gid, &dgid, sizeof(portid.gid)); 256 } 257 258 signal(SIGINT, report); 259 signal(SIGTERM, report); 260 261 start = cl_get_time_stamp(); 262 263 while (count-- > 0) { 264 ntrans++; 265 if ((rtt = ibping(&portid, flood)) == ~0ull) { 266 DEBUG("ibping to %s failed", portid2str(&portid)); 267 lost++; 268 } else { 269 if (rtt < minrtt) 270 minrtt = rtt; 271 if (rtt > maxrtt) 272 maxrtt = rtt; 273 total_rtt += rtt; 274 replied++; 275 } 276 277 if (!flood) 278 sleep(1); 279 } 280 281 report(0); 282 283 mad_rpc_close_port(srcport); 284 285 exit(-1); 286 } 287