| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #define _GNU_SOURCE |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <ctype.h> |
| #include <netinet/in.h> |
| #include <inttypes.h> |
| |
| #include <infiniband/umad.h> |
| #include <infiniband/mad.h> |
| #include <util/node_name_map.h> |
| |
| #include "ibdiag_common.h" |
| |
| static struct ibmad_port *srcport; |
| |
| #define MAXHOPS 63 |
| |
| static const char * const node_type_str[] = { |
| "???", |
| "ca", |
| "switch", |
| "router", |
| "iwarp rnic" |
| }; |
| |
| static int timeout = 0; |
| static int force; |
| static FILE *f; |
| static FILE *ports_fd; |
| |
| static char *node_name_map_file = NULL; |
| static char *ports_file = NULL; |
| static nn_map_t *node_name_map = NULL; |
| |
| typedef struct Port Port; |
| typedef struct Switch Switch; |
| typedef struct Node Node; |
| |
| struct Port { |
| Port *next; |
| Port *remoteport; |
| uint64_t portguid; |
| int portnum; |
| int lid; |
| int lmc; |
| int state; |
| int physstate; |
| char portinfo[64]; |
| }; |
| |
| struct Switch { |
| int linearcap; |
| int mccap; |
| int linearFDBtop; |
| int fdb_base; |
| int enhsp0; |
| int8_t fdb[64]; |
| char switchinfo[64]; |
| }; |
| |
| struct Node { |
| Node *htnext; |
| Node *dnext; |
| Port *ports; |
| ib_portid_t path; |
| int type; |
| int dist; |
| int numports; |
| int upport; |
| Node *upnode; |
| uint64_t nodeguid; |
| char nodedesc[64]; |
| char nodeinfo[64]; |
| }; |
| |
| static Node *nodesdist[MAXHOPS]; |
| static uint64_t target_portguid; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int is_port_inactive(Node * node, Port * port, Switch * sw) |
| { |
| int res = 0; |
| if (port->state != 4 && |
| (node->type != IB_NODE_SWITCH || |
| (node->type == IB_NODE_SWITCH && sw->enhsp0))) |
| res = 1; |
| return res; |
| } |
| |
| static int get_node(Node * node, Port * port, ib_portid_t * portid) |
| { |
| void *pi = port->portinfo, *ni = node->nodeinfo, *nd = node->nodedesc; |
| char *s, *e; |
| |
| memset(ni, 0, sizeof(node->nodeinfo)); |
| if (!smp_query_via(ni, portid, IB_ATTR_NODE_INFO, 0, timeout, srcport)) |
| return -1; |
| |
| memset(nd, 0, sizeof(node->nodedesc)); |
| if (!smp_query_via(nd, portid, IB_ATTR_NODE_DESC, 0, timeout, srcport)) |
| return -1; |
| |
| for (s = nd, e = s + 64; s < e; s++) { |
| if (!*s) |
| break; |
| if (!isprint(*s)) |
| *s = ' '; |
| } |
| |
| memset(pi, 0, sizeof(port->portinfo)); |
| if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, 0, timeout, srcport)) |
| return -1; |
| |
| mad_decode_field(ni, IB_NODE_GUID_F, &node->nodeguid); |
| mad_decode_field(ni, IB_NODE_TYPE_F, &node->type); |
| mad_decode_field(ni, IB_NODE_NPORTS_F, &node->numports); |
| |
| mad_decode_field(ni, IB_NODE_PORT_GUID_F, &port->portguid); |
| mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &port->portnum); |
| mad_decode_field(pi, IB_PORT_LID_F, &port->lid); |
| mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc); |
| mad_decode_field(pi, IB_PORT_STATE_F, &port->state); |
| |
| DEBUG("portid %s: got node %" PRIx64 " '%s'", portid2str(portid), |
| node->nodeguid, node->nodedesc); |
| return 0; |
| } |
| |
| static int switch_lookup(Switch * sw, ib_portid_t * portid, int lid) |
| { |
| void *si = sw->switchinfo, *fdb = sw->fdb; |
| |
| memset(si, 0, sizeof(sw->switchinfo)); |
| if (!smp_query_via(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout, |
| srcport)) |
| return -1; |
| |
| mad_decode_field(si, IB_SW_LINEAR_FDB_CAP_F, &sw->linearcap); |
| mad_decode_field(si, IB_SW_LINEAR_FDB_TOP_F, &sw->linearFDBtop); |
| mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &sw->enhsp0); |
| |
| if (lid >= sw->linearcap && lid > sw->linearFDBtop) |
| return -1; |
| |
| memset(fdb, 0, sizeof(sw->fdb)); |
| if (!smp_query_via(fdb, portid, IB_ATTR_LINEARFORWTBL, lid / 64, |
| timeout, srcport)) |
| return -1; |
| |
| DEBUG("portid %s: forward lid %d to port %d", |
| portid2str(portid), lid, sw->fdb[lid % 64]); |
| return sw->fdb[lid % 64]; |
| } |
| |
| static int sameport(Port * a, Port * b) |
| { |
| return a->portguid == b->portguid || (force && a->lid == b->lid); |
| } |
| |
| static int extend_dpath(ib_dr_path_t * path, int nextport) |
| { |
| if (path->cnt + 2 >= sizeof(path->p)) |
| return -1; |
| ++path->cnt; |
| path->p[path->cnt] = (uint8_t) nextport; |
| return path->cnt; |
| } |
| |
| static void dump_endnode(int dump, const char *prompt, Node *node, Port *port) |
| { |
| char *nodename = NULL; |
| |
| if (!dump) |
| return; |
| if (dump == 1) { |
| fprintf(f, "%s {0x%016" PRIx64 "}[%d]\n", |
| prompt, node->nodeguid, |
| node->type == IB_NODE_SWITCH ? 0 : port->portnum); |
| return; |
| } |
| |
| nodename = |
| remap_node_name(node_name_map, node->nodeguid, node->nodedesc); |
| |
| fprintf(f, "%s %s {0x%016" PRIx64 "} portnum %d lid %u-%u \"%s\"\n", |
| prompt, |
| (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), |
| node->nodeguid, |
| node->type == IB_NODE_SWITCH ? 0 : port->portnum, port->lid, |
| port->lid + (1 << port->lmc) - 1, nodename); |
| |
| free(nodename); |
| } |
| |
| static void dump_route(int dump, Node * node, int outport, Port * port) |
| { |
| char *nodename = NULL; |
| |
| if (!dump && !ibverbose) |
| return; |
| |
| nodename = |
| remap_node_name(node_name_map, node->nodeguid, node->nodedesc); |
| |
| if (dump == 1) |
| fprintf(f, "[%d] -> {0x%016" PRIx64 "}[%d]\n", |
| outport, port->portguid, port->portnum); |
| else |
| fprintf(f, "[%d] -> %s port {0x%016" PRIx64 |
| "}[%d] lid %u-%u \"%s\"\n", outport, |
| (node->type <= |
| IB_NODE_MAX ? node_type_str[node->type] : "???"), |
| port->portguid, port->portnum, port->lid, |
| port->lid + (1 << port->lmc) - 1, nodename); |
| |
| free(nodename); |
| } |
| |
| static int find_route(ib_portid_t * from, ib_portid_t * to, int dump) |
| { |
| Node *node, fromnode, tonode, nextnode; |
| Port *port, fromport, toport, nextport; |
| Switch sw; |
| int maxhops = MAXHOPS; |
| int portnum, outport = 255, next_sw_outport = 255; |
| |
| memset(&fromnode,0,sizeof(Node)); |
| memset(&tonode,0,sizeof(Node)); |
| memset(&nextnode,0,sizeof(Node)); |
| memset(&fromport,0,sizeof(Port)); |
| memset(&toport,0,sizeof(Port)); |
| memset(&nextport,0,sizeof(Port)); |
| |
| DEBUG("from %s", portid2str(from)); |
| |
| if (get_node(&fromnode, &fromport, from) < 0 || |
| get_node(&tonode, &toport, to) < 0) { |
| IBWARN("can't reach to/from ports"); |
| if (!force) |
| return -1; |
| if (to->lid > 0) |
| toport.lid = to->lid; |
| IBWARN("Force: look for lid %d", to->lid); |
| } |
| |
| node = &fromnode; |
| port = &fromport; |
| portnum = port->portnum; |
| |
| dump_endnode(dump, "From", node, port); |
| if (node->type == IB_NODE_SWITCH) { |
| next_sw_outport = switch_lookup(&sw, from, to->lid); |
| if (next_sw_outport < 0 || next_sw_outport > node->numports) { |
| |
| outport = next_sw_outport; |
| goto badtbl; |
| } |
| } |
| |
| while (maxhops--) { |
| if (is_port_inactive(node, port, &sw)) |
| goto badport; |
| |
| if (sameport(port, &toport)) |
| break; |
| |
| if (node->type == IB_NODE_SWITCH) { |
| DEBUG("switch node"); |
| outport = next_sw_outport; |
| |
| if (extend_dpath(&from->drpath, outport) < 0) |
| goto badpath; |
| |
| if (get_node(&nextnode, &nextport, from) < 0) { |
| IBWARN("can't reach port at %s", |
| portid2str(from)); |
| return -1; |
| } |
| if (outport == 0) { |
| if (!sameport(&nextport, &toport)) |
| goto badtbl; |
| else |
| break; |
| } |
| } else if ((node->type == IB_NODE_CA) || |
| (node->type == IB_NODE_ROUTER)) { |
| int ca_src = 0; |
| |
| outport = portnum; |
| DEBUG("ca or router node"); |
| if (!sameport(port, &fromport)) { |
| IBWARN |
| ("can't continue: reached CA or router port %" |
| PRIx64 ", lid %d", port->portguid, |
| port->lid); |
| return -1; |
| } |
| |
| if (from->drpath.cnt > 0) { |
| DEBUG("ca or router node - return back 1 hop"); |
| from->drpath.cnt--; |
| } else { |
| ca_src = 1; |
| if (portnum |
| && extend_dpath(&from->drpath, portnum) < 0) |
| goto badpath; |
| } |
| if (get_node(&nextnode, &nextport, from) < 0) { |
| IBWARN("can't reach port at %s", |
| portid2str(from)); |
| return -1; |
| } |
| |
| if (!ca_src) |
| nextport.portnum = |
| from->drpath.p[from->drpath.cnt + 1]; |
| } |
| |
| if (nextnode.type == IB_NODE_SWITCH) { |
| next_sw_outport = switch_lookup(&sw, from, to->lid); |
| if (next_sw_outport < 0 || |
| next_sw_outport > nextnode.numports) { |
| |
| outport = next_sw_outport; |
| goto badtbl; |
| } |
| } |
| |
| port = &nextport; |
| if (is_port_inactive(&nextnode, port, &sw)) |
| goto badoutport; |
| node = &nextnode; |
| portnum = port->portnum; |
| dump_route(dump, node, outport, port); |
| } |
| |
| if (maxhops <= 0) { |
| IBWARN("no route found after %d hops", MAXHOPS); |
| return -1; |
| } |
| dump_endnode(dump, "To", node, port); |
| return 0; |
| |
| badport: |
| IBWARN("Bad port state found: node \"%s\" port %d state %d", |
| clean_nodedesc(node->nodedesc), portnum, port->state); |
| return -1; |
| badoutport: |
| IBWARN("Bad out port state found: node \"%s\" outport %d state %d", |
| clean_nodedesc(node->nodedesc), outport, port->state); |
| return -1; |
| badtbl: |
| IBWARN |
| ("Bad forwarding table entry found at: node \"%s\" lid entry %d is %d (top %d)", |
| clean_nodedesc(node->nodedesc), to->lid, outport, sw.linearFDBtop); |
| return -1; |
| badpath: |
| IBWARN("Direct path too long!"); |
| return -1; |
| } |
| |
| |
| |
| |
| |
| #define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103))) |
| #define HTSZ 137 |
| |
| static int insert_node(Node * new) |
| { |
| static Node *nodestbl[HTSZ]; |
| int hash = HASHGUID(new->nodeguid) % HTSZ; |
| Node *node; |
| |
| for (node = nodestbl[hash]; node; node = node->htnext) |
| if (node->nodeguid == new->nodeguid) { |
| DEBUG("node %" PRIx64 " already exists", new->nodeguid); |
| return -1; |
| } |
| |
| new->htnext = nodestbl[hash]; |
| nodestbl[hash] = new; |
| |
| return 0; |
| } |
| |
| static int get_port(Port * port, int portnum, ib_portid_t * portid) |
| { |
| char portinfo[64] = { 0 }; |
| void *pi = portinfo; |
| |
| port->portnum = portnum; |
| |
| if (!smp_query_via(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout, |
| srcport)) |
| return -1; |
| |
| mad_decode_field(pi, IB_PORT_LID_F, &port->lid); |
| mad_decode_field(pi, IB_PORT_LMC_F, &port->lmc); |
| mad_decode_field(pi, IB_PORT_STATE_F, &port->state); |
| mad_decode_field(pi, IB_PORT_PHYS_STATE_F, &port->physstate); |
| |
| VERBOSE("portid %s portnum %d: lid %d state %d physstate %d", |
| portid2str(portid), portnum, port->lid, port->state, |
| port->physstate); |
| return 1; |
| } |
| |
| static void link_port(Port * port, Node * node) |
| { |
| port->next = node->ports; |
| node->ports = port; |
| } |
| |
| static int new_node(Node * node, Port * port, ib_portid_t * path, int dist) |
| { |
| if (port->portguid == target_portguid) { |
| node->dist = -1; |
| link_port(port, node); |
| dump_endnode(ibverbose, "found target", node, port); |
| return 1; |
| } |
| |
| |
| if (insert_node(node) < 0) |
| return -1; |
| |
| VERBOSE("insert dist %d node %p port %d lid %d", dist, node, |
| port->portnum, port->lid); |
| |
| link_port(port, node); |
| |
| node->dist = dist; |
| node->path = *path; |
| node->dnext = nodesdist[dist]; |
| nodesdist[dist] = node; |
| |
| return 0; |
| } |
| |
| static int switch_mclookup(Node * node, ib_portid_t * portid, int mlid, |
| char *map) |
| { |
| Switch sw; |
| char mdb[64]; |
| void *si = sw.switchinfo; |
| __be16 *msets = (__be16 *) mdb; |
| int maxsets, block, i, set; |
| |
| memset(map, 0, 256); |
| |
| memset(si, 0, sizeof(sw.switchinfo)); |
| if (!smp_query_via(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout, |
| srcport)) |
| return -1; |
| |
| mlid -= 0xc000; |
| |
| mad_decode_field(si, IB_SW_MCAST_FDB_CAP_F, &sw.mccap); |
| |
| if (mlid >= sw.mccap) |
| return -1; |
| |
| block = mlid / 32; |
| maxsets = (node->numports + 15) / 16; |
| |
| for (set = 0; set < maxsets; set++) { |
| memset(mdb, 0, sizeof(mdb)); |
| if (!smp_query_via(mdb, portid, IB_ATTR_MULTICASTFORWTBL, |
| block | (set << 28), timeout, srcport)) |
| return -1; |
| |
| for (i = 0; i < 16; i++, map++) { |
| uint16_t mask = ntohs(msets[mlid % 32]); |
| if (mask & (1 << i)) |
| *map = 1; |
| else |
| continue; |
| VERBOSE("Switch guid 0x%" PRIx64 |
| ": mlid 0x%x is forwarded to port %d", |
| node->nodeguid, mlid + 0xc000, i + set * 16); |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| |
| static Node *find_mcpath(ib_portid_t * from, int mlid) |
| { |
| Node *node, *remotenode; |
| Port *port, *remoteport; |
| char map[256]; |
| int r, i; |
| int dist = 0, leafport = 0; |
| ib_portid_t *path; |
| |
| DEBUG("from %s", portid2str(from)); |
| |
| if (!(node = calloc(1, sizeof(Node)))) |
| IBEXIT("out of memory"); |
| |
| if (!(port = calloc(1, sizeof(Port)))) |
| IBEXIT("out of memory"); |
| |
| if (get_node(node, port, from) < 0) { |
| IBWARN("can't reach node %s", portid2str(from)); |
| free(node); |
| free(port); |
| return NULL; |
| } |
| |
| node->upnode = NULL; |
| if ((r = new_node(node, port, from, 0)) > 0) { |
| if (node->type != IB_NODE_SWITCH) { |
| IBWARN("ibtracert from CA to CA is unsupported"); |
| free(node); |
| free(port); |
| return NULL; |
| } |
| |
| if (switch_mclookup(node, from, mlid, map) < 0 || !map[0]) |
| return NULL; |
| return node; |
| } |
| |
| for (dist = 0; dist < MAXHOPS; dist++) { |
| |
| for (node = nodesdist[dist]; node; node = node->dnext) { |
| |
| path = &node->path; |
| |
| VERBOSE("dist %d node %p", dist, node); |
| dump_endnode(ibverbose, "processing", node, |
| node->ports); |
| |
| memset(map, 0, sizeof(map)); |
| |
| if (node->type != IB_NODE_SWITCH) { |
| if (dist) |
| continue; |
| leafport = path->drpath.p[path->drpath.cnt]; |
| map[port->portnum] = 1; |
| node->upport = 0; |
| DEBUG("Starting from CA 0x%" PRIx64 |
| " lid %d port %d (leafport %d)", |
| node->nodeguid, port->lid, port->portnum, |
| leafport); |
| } else { |
| |
| |
| if (dist == 1 && leafport) |
| node->upport = leafport; |
| |
| if (switch_mclookup(node, path, mlid, map) < 0) { |
| IBWARN("skipping bad Switch 0x%" PRIx64 |
| "", node->nodeguid); |
| continue; |
| } |
| } |
| |
| for (i = 1; i <= node->numports; i++) { |
| if (!map[i] || i == node->upport) |
| continue; |
| |
| if (dist == 0 && leafport) { |
| if (from->drpath.cnt > 0) |
| path->drpath.cnt--; |
| } else { |
| if (!(port = calloc(1, sizeof(Port)))) |
| IBEXIT("out of memory"); |
| |
| if (get_port(port, i, path) < 0) { |
| IBWARN |
| ("can't reach node %s port %d", |
| portid2str(path), i); |
| free(port); |
| return NULL; |
| } |
| |
| if (port->physstate != 5) { |
| free(port); |
| continue; |
| } |
| #if 0 |
| link_port(port, node); |
| #endif |
| |
| if (extend_dpath(&path->drpath, i) < 0) { |
| free(port); |
| return NULL; |
| } |
| } |
| |
| if (!(remotenode = calloc(1, sizeof(Node)))) |
| IBEXIT("out of memory"); |
| |
| if (!(remoteport = calloc(1, sizeof(Port)))) |
| IBEXIT("out of memory"); |
| |
| if (get_node(remotenode, remoteport, path) < 0) { |
| IBWARN |
| ("NodeInfo on %s port %d failed, skipping port", |
| portid2str(path), i); |
| path->drpath.cnt--; |
| free(remotenode); |
| free(remoteport); |
| continue; |
| } |
| |
| remotenode->upnode = node; |
| remotenode->upport = remoteport->portnum; |
| remoteport->remoteport = port; |
| |
| if ((r = new_node(remotenode, remoteport, path, |
| dist + 1)) > 0) |
| return remotenode; |
| |
| if (r == 0) |
| dump_endnode(ibverbose, "new remote", |
| remotenode, remoteport); |
| else if (remotenode->type == IB_NODE_SWITCH) |
| dump_endnode(2, |
| "ERR: circle discovered at", |
| remotenode, remoteport); |
| |
| path->drpath.cnt--; |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| static uint64_t find_target_portguid(ib_portid_t * to) |
| { |
| Node tonode; |
| Port toport; |
| |
| if (get_node(&tonode, &toport, to) < 0) { |
| IBWARN("can't find to port\n"); |
| return -1; |
| } |
| |
| return toport.portguid; |
| } |
| |
| static void dump_mcpath(Node * node, int dumplevel) |
| { |
| char *nodename = NULL; |
| |
| if (node->upnode) |
| dump_mcpath(node->upnode, dumplevel); |
| |
| nodename = |
| remap_node_name(node_name_map, node->nodeguid, node->nodedesc); |
| |
| if (!node->dist) { |
| printf("From %s 0x%" PRIx64 " port %d lid %u-%u \"%s\"\n", |
| (node->type <= |
| IB_NODE_MAX ? node_type_str[node->type] : "???"), |
| node->nodeguid, node->ports->portnum, node->ports->lid, |
| node->ports->lid + (1 << node->ports->lmc) - 1, |
| nodename); |
| goto free_name; |
| } |
| |
| if (node->dist) { |
| if (dumplevel == 1) |
| printf("[%d] -> %s {0x%016" PRIx64 "}[%d]\n", |
| node->ports->remoteport->portnum, |
| (node->type <= |
| IB_NODE_MAX ? node_type_str[node->type] : |
| "???"), node->nodeguid, node->upport); |
| else |
| printf("[%d] -> %s 0x%" PRIx64 "[%d] lid %u \"%s\"\n", |
| node->ports->remoteport->portnum, |
| (node->type <= |
| IB_NODE_MAX ? node_type_str[node->type] : |
| "???"), node->nodeguid, node->upport, |
| node->ports->lid, nodename); |
| } |
| |
| if (node->dist < 0) |
| |
| printf("To %s 0x%" PRIx64 " port %d lid %u-%u \"%s\"\n", |
| (node->type <= |
| IB_NODE_MAX ? node_type_str[node->type] : "???"), |
| node->nodeguid, node->ports->portnum, node->ports->lid, |
| node->ports->lid + (1 << node->ports->lmc) - 1, |
| nodename); |
| |
| free_name: |
| free(nodename); |
| } |
| |
| static int resolve_lid(ib_portid_t *portid) |
| { |
| uint8_t portinfo[64] = { 0 }; |
| uint16_t lid; |
| |
| if (!smp_query_via(portinfo, portid, IB_ATTR_PORT_INFO, 0, 0, NULL)) |
| return -1; |
| mad_decode_field(portinfo, IB_PORT_LID_F, &lid); |
| |
| ib_portid_set(portid, lid, 0, 0); |
| |
| return 0; |
| } |
| |
| static int dumplevel = 2, multicast, mlid; |
| |
| static int process_opt(void *context, int ch) |
| { |
| switch (ch) { |
| case 1: |
| node_name_map_file = strdup(optarg); |
| if (node_name_map_file == NULL) |
| IBEXIT("out of memory, strdup for node_name_map_file name failed"); |
| break; |
| case 2: |
| ports_file = strdup(optarg); |
| if (ports_file == NULL) |
| IBEXIT("out of memory, strdup for ports_file name failed"); |
| break; |
| case 'm': |
| multicast++; |
| mlid = strtoul(optarg, NULL, 0); |
| break; |
| case 'f': |
| force++; |
| break; |
| case 'n': |
| dumplevel = 1; |
| break; |
| default: |
| return -1; |
| } |
| return 0; |
| } |
| |
| static int get_route(char *srcid, char *dstid) { |
| ib_portid_t my_portid = { 0 }; |
| ib_portid_t src_portid = { 0 }; |
| ib_portid_t dest_portid = { 0 }; |
| Node *endnode; |
| |
| if (resolve_portid_str(ibd_ca, ibd_ca_port, &src_portid, srcid, |
| ibd_dest_type, ibd_sm_id, srcport) < 0) { |
| IBWARN("can't resolve source port %s", srcid); |
| return -1; |
| } |
| |
| if (resolve_portid_str(ibd_ca, ibd_ca_port, &dest_portid, dstid, |
| ibd_dest_type, ibd_sm_id, srcport) < 0) { |
| IBWARN("can't resolve destination port %s", dstid); |
| return -1; |
| } |
| |
| if (ibd_dest_type == IB_DEST_DRPATH) { |
| if (resolve_lid(&src_portid) < 0) { |
| IBWARN("cannot resolve lid for port \'%s\'", |
| portid2str(&src_portid)); |
| return -1; |
| } |
| if (resolve_lid(&dest_portid) < 0) { |
| IBWARN("cannot resolve lid for port \'%s\'", |
| portid2str(&dest_portid)); |
| return -1; |
| } |
| } |
| |
| if (dest_portid.lid == 0 || src_portid.lid == 0) { |
| IBWARN("bad src/dest lid"); |
| ibdiag_show_usage(); |
| } |
| |
| if (ibd_dest_type != IB_DEST_DRPATH) { |
| |
| if (find_route(&my_portid, &src_portid, 0) < 0) { |
| IBWARN("can't find a route to the src port"); |
| return -1; |
| } |
| |
| src_portid = my_portid; |
| } |
| |
| if (!multicast) { |
| if (find_route(&src_portid, &dest_portid, dumplevel) < 0) { |
| IBWARN("can't find a route from src to dest"); |
| return -1; |
| } |
| return 0; |
| } else { |
| if (mlid < 0xc000) |
| IBWARN("invalid MLID; must be 0xc000 or larger"); |
| } |
| |
| if (!(target_portguid = find_target_portguid(&dest_portid))) { |
| IBWARN("can't reach target lid %d", dest_portid.lid); |
| return -1; |
| } |
| |
| if (!(endnode = find_mcpath(&src_portid, mlid))) { |
| IBWARN("can't find a multicast route from src to dest"); |
| return -1; |
| } |
| |
| |
| dump_mcpath(endnode, dumplevel); |
| |
| return 0; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| char dstbuf[21]; |
| char srcbuf[21]; |
| char portsbuf[80]; |
| char *p_first; |
| int len, i; |
| int line_count = 0; |
| int num_port_pairs = 0; |
| int mgmt_classes[3] = |
| { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS }; |
| |
| const struct ibdiag_opt opts[] = { |
| {"force", 'f', 0, NULL, "force"}, |
| {"no_info", 'n', 0, NULL, "simple format"}, |
| {"mlid", 'm', 1, "<mlid>", "multicast trace of the mlid"}, |
| {"node-name-map", 1, 1, "<file>", "node name map file"}, |
| {"ports-file", 2, 1, "<file>", "port pairs file"}, |
| {} |
| }; |
| char usage_args[] = "<src-addr> <dest-addr>"; |
| const char *usage_examples[] = { |
| "- Unicast examples:", |
| "4 16\t\t\t# show path between lids 4 and 16", |
| "-n 4 16\t\t# same, but using simple output format", |
| "-G 0x8f1040396522d 0x002c9000100d051\t# use guid addresses", |
| |
| " - Multicast examples:", |
| "-m 0xc000 4 16\t# show multicast path of mlid 0xc000 between lids 4 and 16", |
| NULL, |
| }; |
| |
| ibdiag_process_opts(argc, argv, NULL, "DK", opts, process_opt, |
| usage_args, usage_examples); |
| |
| f = stdout; |
| argc -= optind; |
| argv += optind; |
| |
| if (argc < 2 && ports_file == NULL) |
| ibdiag_show_usage(); |
| |
| if (ibd_timeout) |
| timeout = ibd_timeout; |
| |
| 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); |
| |
| smp_mkey_set(srcport, ibd_mkey); |
| |
| node_name_map = open_node_name_map(node_name_map_file); |
| |
| if (ports_file == NULL) { |
| |
| if (get_route(argv[0], argv[1]) != 0) |
| IBEXIT("Failed to get route information"); |
| } else { |
| |
| ports_fd = fopen(ports_file, "r"); |
| if (!ports_fd) |
| IBEXIT("cannot open ports-file %s", ports_file); |
| |
| while (fgets(portsbuf, sizeof(portsbuf), ports_fd) != NULL) { |
| line_count++; |
| p_first = strtok(portsbuf, "\n"); |
| if (!p_first) |
| continue; |
| |
| len = (int) strlen(p_first); |
| for (i = 0; i < len; i++) { |
| if (!isspace(p_first[i])) |
| break; |
| } |
| if (i == len) |
| continue; |
| if (p_first[i] == '#') |
| continue; |
| |
| if (sscanf(portsbuf, "%20s %20s", srcbuf, dstbuf) != 2) |
| IBEXIT("ports-file, %s, at line %i contains bad data", |
| ports_file, line_count); |
| num_port_pairs++; |
| if (get_route(srcbuf, dstbuf) != 0) |
| IBEXIT("Failed to get route information at line %i", |
| line_count); |
| } |
| printf("%i lid/guid pairs processed from %s\n", |
| num_port_pairs, ports_file); |
| } |
| close_node_name_map(node_name_map); |
| |
| mad_rpc_close_port(srcport); |
| |
| exit(0); |
| } |