/* * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include #include #include #include #include #include #include "ibdiag_common.h" #define MAX_CPUS 256 static struct ibmad_port *srcport; enum ib_sysstat_attr_t { IB_PING_ATTR = 0x10, IB_HOSTINFO_ATTR = 0x11, IB_CPUINFO_ATTR = 0x12, }; typedef struct cpu_info { char *model; char *mhz; } cpu_info; static cpu_info cpus[MAX_CPUS]; static int host_ncpu; static int server = 0, oui = IB_OPENIB_OUI; static int server_respond(void *umad, int size) { ib_rpc_t rpc = { 0 }; ib_rmpp_hdr_t rmpp = { 0 }; ib_portid_t rport; uint8_t *mad = umad_get_mad(umad); ib_mad_addr_t *mad_addr; if (!(mad_addr = umad_get_mad_addr(umad))) return -1; memset(&rport, 0, sizeof(rport)); rport.lid = ntohs(mad_addr->lid); rport.qp = ntohl(mad_addr->qpn); rport.qkey = ntohl(mad_addr->qkey); rport.sl = mad_addr->sl; if (!rport.qkey && rport.qp == 1) rport.qkey = IB_DEFAULT_QP1_QKEY; rpc.mgtclass = mad_get_field(mad, 0, IB_MAD_MGMTCLASS_F); rpc.method = IB_MAD_METHOD_GET | IB_MAD_RESPONSE; rpc.attr.id = mad_get_field(mad, 0, IB_MAD_ATTRID_F); rpc.attr.mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); rpc.oui = mad_get_field(mad, 0, IB_VEND2_OUI_F); rpc.trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); if (size > IB_MAD_SIZE) rmpp.flags = IB_RMPP_FLAG_ACTIVE; DEBUG("responding %d bytes to %s, attr 0x%x mod 0x%x qkey %x", size, portid2str(&rport), rpc.attr.id, rpc.attr.mod, rport.qkey); if (mad_build_pkt(umad, &rpc, &rport, &rmpp, NULL) < 0) return -1; if (ibdebug > 1) xdump(stderr, "mad respond pkt\n", mad, IB_MAD_SIZE); if (umad_send(mad_rpc_portid(srcport), mad_rpc_class_agent(srcport, rpc.mgtclass), umad, size, rpc.timeout, 0) < 0) { DEBUG("send failed; %m"); return -1; } return 0; } static int mk_reply(int attr, void *data, int sz) { char *s = data; int n, i, ret = 0; switch (attr) { case IB_PING_ATTR: break; /* nothing to do here, just reply */ case IB_HOSTINFO_ATTR: if (gethostname(s, sz) < 0) snprintf(s, sz, "?hostname?"); s[sz - 1] = 0; if ((n = strlen(s)) >= sz - 1) { ret = sz; break; } s[n] = '.'; s += n + 1; sz -= n + 1; ret += n + 1; if (getdomainname(s, sz) < 0) snprintf(s, sz, "?domainname?"); if ((n = strlen(s)) == 0) s[-1] = 0; /* no domain */ else ret += n; break; case IB_CPUINFO_ATTR: s[0] = '\0'; for (i = 0; i < host_ncpu && sz > 0; i++) { n = snprintf(s, sz, "cpu %d: model %s MHZ %s\n", i, cpus[i].model, cpus[i].mhz); if (n >= sz) { IBWARN("cpuinfo truncated"); ret = sz; break; } sz -= n; s += n; ret += n; } ret++; break; default: DEBUG("unknown attr %d", attr); } return ret; } static uint8_t buf[2048 * 32]; static char *ibsystat_serv(void) { void *umad; void *mad; int attr, mod, size; DEBUG("starting to serve..."); while ((umad = mad_receive_via(buf, -1, srcport))) { if (umad_status(buf)) { DEBUG("drop mad with status %x: %s", umad_status(buf), strerror(umad_status(buf))); continue; } mad = umad_get_mad(umad); attr = mad_get_field(mad, 0, IB_MAD_ATTRID_F); mod = mad_get_field(mad, 0, IB_MAD_ATTRMOD_F); DEBUG("got packet: attr 0x%x mod 0x%x", attr, mod); size = mk_reply(attr, (uint8_t *) mad + IB_VENDOR_RANGE2_DATA_OFFS, sizeof(buf) - umad_size() - IB_VENDOR_RANGE2_DATA_OFFS); if (server_respond(umad, IB_VENDOR_RANGE2_DATA_OFFS + size) < 0) DEBUG("respond failed"); } DEBUG("server out"); return NULL; } static int match_attr(char *str) { if (!strcmp(str, "ping")) return IB_PING_ATTR; if (!strcmp(str, "host")) return IB_HOSTINFO_ATTR; if (!strcmp(str, "cpu")) return IB_CPUINFO_ATTR; return -1; } static char *ibsystat(ib_portid_t * portid, int attr) { ib_rpc_t rpc = { 0 }; int fd, agent, timeout, len; void *data = (uint8_t *) umad_get_mad(buf) + IB_VENDOR_RANGE2_DATA_OFFS; DEBUG("Sysstat ping.."); rpc.mgtclass = IB_VENDOR_OPENIB_SYSSTAT_CLASS; rpc.method = IB_MAD_METHOD_GET; rpc.attr.id = attr; rpc.attr.mod = 0; rpc.oui = oui; rpc.timeout = 0; rpc.datasz = IB_VENDOR_RANGE2_DATA_SIZE; rpc.dataoffs = IB_VENDOR_RANGE2_DATA_OFFS; portid->qp = 1; if (!portid->qkey) portid->qkey = IB_DEFAULT_QP1_QKEY; if ((len = mad_build_pkt(buf, &rpc, portid, NULL, NULL)) < 0) IBPANIC("cannot build packet."); fd = mad_rpc_portid(srcport); agent = mad_rpc_class_agent(srcport, rpc.mgtclass); timeout = ibd_timeout ? ibd_timeout : MAD_DEF_TIMEOUT_MS; if (umad_send(fd, agent, buf, len, timeout, 0) < 0) IBPANIC("umad_send failed."); len = sizeof(buf) - umad_size(); if (umad_recv(fd, buf, &len, timeout) < 0) IBPANIC("umad_recv failed."); if (umad_status(buf)) return strerror(umad_status(buf)); DEBUG("Got sysstat pong.."); if (attr != IB_PING_ATTR) puts(data); else printf("sysstat ping succeeded\n"); return NULL; } static int build_cpuinfo(void) { char line[1024] = { 0 }, *s, *e; FILE *f; int ncpu = 0; if (!(f = fopen("/proc/cpuinfo", "r"))) { IBWARN("couldn't open /proc/cpuinfo"); return 0; } while (fgets(line, sizeof(line) - 1, f)) { if (!strncmp(line, "processor\t", 10)) { ncpu++; if (ncpu > MAX_CPUS) { fclose(f); return MAX_CPUS; } continue; } if (!ncpu || !(s = strchr(line, ':'))) continue; if ((e = strchr(s, '\n'))) *e = 0; if (!strncmp(line, "model name\t", 11)) cpus[ncpu - 1].model = strdup(s + 1); else if (!strncmp(line, "cpu MHz\t", 8)) cpus[ncpu - 1].mhz = strdup(s + 1); } fclose(f); DEBUG("ncpu %d", ncpu); return ncpu; } static int process_opt(void *context, int ch) { switch (ch) { case 'o': oui = strtoul(optarg, NULL, 0); break; case 'S': server++; break; default: return -1; } return 0; } int main(int argc, char **argv) { int mgmt_classes[3] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS }; int sysstat_class = IB_VENDOR_OPENIB_SYSSTAT_CLASS; ib_portid_t portid = { 0 }; int attr = IB_PING_ATTR; char *err; const struct ibdiag_opt opts[] = { {"oui", 'o', 1, NULL, "use specified OUI number"}, {"Server", 'S', 0, NULL, "start in server mode"}, {} }; char usage_args[] = " []"; ibdiag_process_opts(argc, argv, NULL, "DKy", opts, process_opt, usage_args, NULL); argc -= optind; argv += optind; if (!argc && !server) ibdiag_show_usage(); if (argc > 1 && (attr = match_attr(argv[1])) < 0) ibdiag_show_usage(); srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); if (!srcport) IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); if (server) { if (mad_register_server_via(sysstat_class, 1, NULL, oui, srcport) < 0) IBEXIT("can't serve class %d", sysstat_class); host_ncpu = build_cpuinfo(); if ((err = ibsystat_serv())) IBEXIT("ibssystat to %s: %s", portid2str(&portid), err); exit(0); } if (mad_register_client_via(sysstat_class, 1, srcport) < 0) IBEXIT("can't register to sysstat class %d", sysstat_class); if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[0], ibd_dest_type, ibd_sm_id, srcport) < 0) IBEXIT("can't resolve destination port %s", argv[0]); if ((err = ibsystat(&portid, attr))) IBEXIT("ibsystat to %s: %s", portid2str(&portid), err); mad_rpc_close_port(srcport); exit(0); }