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 <getopt.h> 43 44 #include <infiniband/umad.h> 45 #include <infiniband/mad.h> 46 47 #include <sys/sysctl.h> 48 49 #include "ibdiag_common.h" 50 51 #define MAX_CPUS 8 52 53 struct ibmad_port *srcport; 54 55 static ibmad_gid_t dgid; 56 static int with_grh; 57 58 enum ib_sysstat_attr_t { 59 IB_PING_ATTR = 0x10, 60 IB_HOSTINFO_ATTR = 0x11, 61 IB_CPUINFO_ATTR = 0x12, 62 }; 63 64 typedef struct cpu_info { 65 char *model; 66 char *mhz; 67 } cpu_info; 68 69 static cpu_info cpus[MAX_CPUS]; 70 static int host_ncpu; 71 static int server = 0, oui = IB_OPENIB_OUI; 72 73 static int server_respond(void *umad, int size) 74 { 75 ib_rpc_t rpc = { 0 }; 76 ib_rmpp_hdr_t rmpp = { 0 }; 77 ib_portid_t rport; 78 uint8_t *mad = umad_get_mad(umad); 79 ib_mad_addr_t *mad_addr; 80 81 if (!(mad_addr = umad_get_mad_addr(umad))) 82 return -1; 83 84 memset(&rport, 0, sizeof(rport)); 85 86 rport.lid = ntohs(mad_addr->lid); 87 rport.qp = ntohl(mad_addr->qpn); 88 rport.qkey = ntohl(mad_addr->qkey); 89 rport.sl = mad_addr->sl; 90 if (!rport.qkey && rport.qp == 1) 91 rport.qkey = IB_DEFAULT_QP1_QKEY; 92 rport.grh_present = mad_addr->grh_present; 93 if (rport.grh_present) 94 memcpy(rport.gid, mad_addr->gid, 16); 95 96 rpc.mgtclass = mad_get_field(mad, 0, IB_MAD_MGMTCLASS_F); 97 rpc.method = IB_MAD_METHOD_GET | IB_MAD_RESPONSE; 98 rpc.attr.id = mad_get_field(mad, 0, IB_MAD_ATTRID_F); 99 rpc.attr.mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); 100 rpc.oui = mad_get_field(mad, 0, IB_VEND2_OUI_F); 101 rpc.trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); 102 103 if (size > IB_MAD_SIZE) 104 rmpp.flags = IB_RMPP_FLAG_ACTIVE; 105 106 DEBUG("responding %d bytes to %s, attr 0x%x mod 0x%x qkey %x", 107 size, portid2str(&rport), rpc.attr.id, rpc.attr.mod, rport.qkey); 108 109 if (mad_build_pkt(umad, &rpc, &rport, &rmpp, 0) < 0) 110 return -1; 111 112 if (ibdebug > 1) 113 xdump(stderr, "mad respond pkt\n", mad, IB_MAD_SIZE); 114 115 if (umad_send(mad_rpc_portid(srcport), 116 mad_rpc_class_agent(srcport, rpc.mgtclass), umad, size, 117 rpc.timeout, 0) < 0) { 118 DEBUG("send failed; %m"); 119 return -1; 120 } 121 122 return 0; 123 } 124 125 static int mk_reply(int attr, void *data, int sz) 126 { 127 char *s = data; 128 int n, i, ret = 0; 129 130 switch (attr) { 131 case IB_PING_ATTR: 132 break; /* nothing to do here, just reply */ 133 case IB_HOSTINFO_ATTR: 134 if (gethostname(s, sz) < 0) 135 snprintf(s, sz, "?hostname?"); 136 s[sz - 1] = 0; 137 if ((n = strlen(s)) >= sz - 1) { 138 ret = sz; 139 break; 140 } 141 s[n] = '.'; 142 s += n + 1; 143 sz -= n + 1; 144 ret += n + 1; 145 if (getdomainname(s, sz) < 0) 146 snprintf(s, sz, "?domainname?"); 147 if ((n = strlen(s)) == 0) 148 s[-1] = 0; /* no domain */ 149 else 150 ret += n; 151 break; 152 case IB_CPUINFO_ATTR: 153 s[0] = '\0'; 154 for (i = 0; i < host_ncpu && sz > 0; i++) { 155 n = snprintf(s, sz, "cpu %d: model %s MHZ %s\n", 156 i, cpus[i].model, cpus[i].mhz); 157 if (n >= sz) { 158 IBWARN("cpuinfo truncated"); 159 ret = sz; 160 break; 161 } 162 sz -= n; 163 s += n; 164 ret += n; 165 } 166 ret++; 167 break; 168 default: 169 DEBUG("unknown attr %d", attr); 170 } 171 return ret; 172 } 173 174 static uint8_t buf[2048]; 175 176 static char *ibsystat_serv(void) 177 { 178 void *umad; 179 void *mad; 180 int attr, mod, size; 181 182 DEBUG("starting to serve..."); 183 184 while ((umad = mad_receive_via(buf, -1, srcport))) { 185 if (umad_status(buf)) { 186 DEBUG("drop mad with status %x: %s", umad_status(buf), 187 strerror(umad_status(buf))); 188 continue; 189 } 190 191 mad = umad_get_mad(umad); 192 193 attr = mad_get_field(mad, 0, IB_MAD_ATTRID_F); 194 mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); 195 196 DEBUG("got packet: attr 0x%x mod 0x%x", attr, mod); 197 198 size = 199 mk_reply(attr, (uint8_t *) mad + IB_VENDOR_RANGE2_DATA_OFFS, 200 sizeof(buf) - umad_size() - 201 IB_VENDOR_RANGE2_DATA_OFFS); 202 203 if (server_respond(umad, IB_VENDOR_RANGE2_DATA_OFFS + size) < 0) 204 DEBUG("respond failed"); 205 } 206 207 DEBUG("server out"); 208 return 0; 209 } 210 211 static int match_attr(char *str) 212 { 213 if (!strcmp(str, "ping")) 214 return IB_PING_ATTR; 215 if (!strcmp(str, "host")) 216 return IB_HOSTINFO_ATTR; 217 if (!strcmp(str, "cpu")) 218 return IB_CPUINFO_ATTR; 219 return -1; 220 } 221 222 static char *ibsystat(ib_portid_t * portid, int attr) 223 { 224 ib_rpc_t rpc = { 0 }; 225 int fd, agent, timeout, len; 226 void *data = (uint8_t *) umad_get_mad(buf) + IB_VENDOR_RANGE2_DATA_OFFS; 227 228 DEBUG("Sysstat ping.."); 229 230 rpc.mgtclass = IB_VENDOR_OPENIB_SYSSTAT_CLASS; 231 rpc.method = IB_MAD_METHOD_GET; 232 rpc.attr.id = attr; 233 rpc.attr.mod = 0; 234 rpc.oui = oui; 235 rpc.timeout = 0; 236 rpc.datasz = IB_VENDOR_RANGE2_DATA_SIZE; 237 rpc.dataoffs = IB_VENDOR_RANGE2_DATA_OFFS; 238 239 portid->qp = 1; 240 if (!portid->qkey) 241 portid->qkey = IB_DEFAULT_QP1_QKEY; 242 243 if ((len = mad_build_pkt(buf, &rpc, portid, NULL, NULL)) < 0) 244 IBPANIC("cannot build packet."); 245 246 fd = mad_rpc_portid(srcport); 247 agent = mad_rpc_class_agent(srcport, rpc.mgtclass); 248 timeout = ibd_timeout ? ibd_timeout : MAD_DEF_TIMEOUT_MS; 249 250 if (umad_send(fd, agent, buf, len, timeout, 0) < 0) 251 IBPANIC("umad_send failed."); 252 253 len = sizeof(buf) - umad_size(); 254 if (umad_recv(fd, buf, &len, timeout) < 0) 255 IBPANIC("umad_recv failed."); 256 257 if (umad_status(buf)) 258 return strerror(umad_status(buf)); 259 260 DEBUG("Got sysstat pong.."); 261 if (attr != IB_PING_ATTR) 262 puts(data); 263 else 264 printf("sysstat ping succeeded\n"); 265 return 0; 266 } 267 268 int build_cpuinfo(void) 269 { 270 int ret; 271 size_t size = sizeof(ret); 272 273 if (sysctlbyname("hw.ncpu", &ret, &size, NULL, 0) != 0 || ret < 1) 274 ret = 1; 275 return ret; 276 277 DEBUG("ncpu %d", ret); 278 } 279 280 static int process_opt(void *context, int ch, char *optarg) 281 { 282 switch (ch) { 283 case 'o': 284 oui = strtoul(optarg, 0, 0); 285 break; 286 case 'S': 287 server++; 288 break; 289 case 25: 290 if (!inet_pton(AF_INET6, optarg, &dgid)) { 291 fprintf(stderr, "dgid format is wrong!\n"); 292 ibdiag_show_usage(); 293 return 1; 294 } 295 with_grh = 1; 296 break; 297 default: 298 return -1; 299 } 300 return 0; 301 } 302 303 int main(int argc, char **argv) 304 { 305 int mgmt_classes[3] = 306 { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS }; 307 int sysstat_class = IB_VENDOR_OPENIB_SYSSTAT_CLASS; 308 ib_portid_t portid = { 0 }; 309 int attr = IB_PING_ATTR; 310 char *err; 311 312 const struct ibdiag_opt opts[] = { 313 {"oui", 'o', 1, NULL, "use specified OUI number"}, 314 {"Server", 'S', 0, NULL, "start in server mode"}, 315 {"dgid", 25, 1, NULL, "remote gid (IPv6 format)"}, 316 {0} 317 }; 318 char usage_args[] = "<dest lid|guid> [<op>]"; 319 320 ibdiag_process_opts(argc, argv, NULL, "DKy", opts, process_opt, 321 usage_args, NULL); 322 323 argc -= optind; 324 argv += optind; 325 326 if (!argc && !server) 327 ibdiag_show_usage(); 328 329 if (argc > 1 && (attr = match_attr(argv[1])) < 0) 330 ibdiag_show_usage(); 331 332 srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); 333 if (!srcport) 334 IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); 335 336 if (server) { 337 if (mad_register_server_via(sysstat_class, 1, 0, oui, srcport) < 338 0) 339 IBEXIT("can't serve class %d", sysstat_class); 340 341 host_ncpu = build_cpuinfo(); 342 343 if ((err = ibsystat_serv())) 344 IBEXIT("ibssystat to %s: %s", portid2str(&portid), 345 err); 346 exit(0); 347 } 348 349 if (mad_register_client_via(sysstat_class, 1, srcport) < 0) 350 IBEXIT("can't register to sysstat class %d", sysstat_class); 351 352 if (with_grh && ibd_dest_type != IB_DEST_LID) 353 IBEXIT("When using GRH, LID should be provided"); 354 if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[0], 355 ibd_dest_type, ibd_sm_id, srcport) < 0) 356 IBEXIT("can't resolve destination port %s", argv[0]); 357 if (with_grh) { 358 portid.grh_present = 1; 359 memcpy(&portid.gid, &dgid, sizeof(portid.gid)); 360 } 361 362 if ((err = ibsystat(&portid, attr))) 363 IBEXIT("ibsystat to %s: %s", portid2str(&portid), err); 364 365 mad_rpc_close_port(srcport); 366 exit(0); 367 } 368