/* * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. * Copyright (c) 2008 Lawrence Livermore National Lab. All rights reserved. * Copyright (c) 2010-2020 Mellanox Technologies LTD. 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. * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "ibdiag_common.h" #define LIST_CA_NODE (1 << IB_NODE_CA) #define LIST_SWITCH_NODE (1 << IB_NODE_SWITCH) #define LIST_ROUTER_NODE (1 << IB_NODE_ROUTER) #define DIFF_FLAG_SWITCH 0x01 #define DIFF_FLAG_CA 0x02 #define DIFF_FLAG_ROUTER 0x04 #define DIFF_FLAG_PORT_CONNECTION 0x08 #define DIFF_FLAG_LID 0x10 #define DIFF_FLAG_NODE_DESCRIPTION 0x20 #define DIFF_FLAG_DEFAULT (DIFF_FLAG_SWITCH | DIFF_FLAG_CA | DIFF_FLAG_ROUTER \ | DIFF_FLAG_PORT_CONNECTION) static FILE *f; static char *node_name_map_file = NULL; static nn_map_t *node_name_map = NULL; static char *cache_file = NULL; static char *load_cache_file = NULL; static char *diff_cache_file = NULL; static unsigned diffcheck_flags = DIFF_FLAG_DEFAULT; static int report_max_hops = 0; static int full_info; /** * Define our own conversion functions to maintain compatibility with the old * ibnetdiscover which did not use the ibmad conversion functions. */ static const char *dump_linkspeed_compat(uint32_t speed) { switch (speed) { case 1: return ("SDR"); break; case 2: return ("DDR"); break; case 4: return ("QDR"); break; } return ("???"); } static const char *dump_linkspeedext_compat(uint32_t espeed, uint32_t speed, uint32_t fdr10) { switch (espeed) { case 0: if (fdr10 & FDR10) return ("FDR10"); else return dump_linkspeed_compat(speed); break; case 1: return ("FDR"); break; case 2: return ("EDR"); break; case 4: return ("HDR"); break; case 8: return ("NDR"); /* case 16: non used value */ case 32: return ("XDR"); } return ("???"); } static const char *dump_linkwidth_compat(uint32_t width) { switch (width) { case 1: return ("1x"); break; case 2: return ("4x"); break; case 4: return ("8x"); break; case 8: return ("12x"); break; case 16: return ("2x"); break; } return ("??"); } static inline const char *ports_nt_str_compat(ibnd_node_t * node) { switch (node->type) { case IB_NODE_SWITCH: return "SW"; case IB_NODE_CA: return "CA"; case IB_NODE_ROUTER: return "RT"; } return "??"; } static char *node_name(ibnd_node_t * node) { static char buf[256]; switch (node->type) { case IB_NODE_SWITCH: sprintf(buf, "\"%s", "S"); break; case IB_NODE_CA: sprintf(buf, "\"%s", "H"); break; case IB_NODE_ROUTER: sprintf(buf, "\"%s", "R"); break; default: sprintf(buf, "\"%s", "?"); break; } sprintf(buf + 2, "-%016" PRIx64 "\"", node->guid); return buf; } static void list_node(ibnd_node_t *node, void *user_data) { const char *node_type; char *nodename = remap_node_name(node_name_map, node->guid, node->nodedesc); switch (node->type) { case IB_NODE_SWITCH: node_type = "Switch"; break; case IB_NODE_CA: node_type = "Ca"; break; case IB_NODE_ROUTER: node_type = "Router"; break; default: node_type = "???"; break; } fprintf(f, "%s\t : 0x%016" PRIx64 " ports %d devid 0x%x vendid 0x%x \"%s\"\n", node_type, node->guid, node->numports, mad_get_field(node->info, 0, IB_NODE_DEVID_F), mad_get_field(node->info, 0, IB_NODE_VENDORID_F), nodename); free(nodename); } static void list_nodes(ibnd_fabric_t *fabric, int list) { if (list & LIST_CA_NODE) ibnd_iter_nodes_type(fabric, list_node, IB_NODE_CA, NULL); if (list & LIST_SWITCH_NODE) ibnd_iter_nodes_type(fabric, list_node, IB_NODE_SWITCH, NULL); if (list & LIST_ROUTER_NODE) ibnd_iter_nodes_type(fabric, list_node, IB_NODE_ROUTER, NULL); } static void out_ids(ibnd_node_t *node, int group, char *chname, const char *out_prefix) { uint64_t sysimgguid = mad_get_field64(node->info, 0, IB_NODE_SYSTEM_GUID_F); fprintf(f, "\n%svendid=0x%x\n", out_prefix ? out_prefix : "", mad_get_field(node->info, 0, IB_NODE_VENDORID_F)); fprintf(f, "%sdevid=0x%x\n", out_prefix ? out_prefix : "", mad_get_field(node->info, 0, IB_NODE_DEVID_F)); if (sysimgguid) fprintf(f, "%ssysimgguid=0x%" PRIx64, out_prefix ? out_prefix : "", sysimgguid); if (group && node->chassis && node->chassis->chassisnum) { fprintf(f, "\t\t# Chassis %d", node->chassis->chassisnum); if (chname) fprintf(f, " (%s)", clean_nodedesc(chname)); if (ibnd_is_xsigo_tca(node->guid) && node->ports[1] && node->ports[1]->remoteport) fprintf(f, " slot %d", node->ports[1]->remoteport->portnum); } if (sysimgguid || (group && node->chassis && node->chassis->chassisnum)) fprintf(f, "\n"); } static uint64_t out_chassis(ibnd_fabric_t *fabric, unsigned char chassisnum) { uint64_t guid; fprintf(f, "\nChassis %u", chassisnum); guid = ibnd_get_chassis_guid(fabric, chassisnum); if (guid) fprintf(f, " (guid 0x%" PRIx64 ")", guid); fprintf(f, "\n"); return guid; } static void out_switch_detail(ibnd_node_t *node, const char *sw_prefix) { char *nodename = NULL; nodename = remap_node_name(node_name_map, node->guid, node->nodedesc); fprintf(f, "%sSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d", sw_prefix ? sw_prefix : "", node->numports, node_name(node), nodename, node->smaenhsp0 ? "enhanced" : "base", node->smalid, node->smalmc); free(nodename); } static void out_switch(ibnd_node_t *node, int group, char *chname, const char *id_prefix, const char *sw_prefix) { const char *str; char str2[256]; out_ids(node, group, chname, id_prefix); fprintf(f, "%sswitchguid=0x%" PRIx64, id_prefix ? id_prefix : "", node->guid); fprintf(f, "(%" PRIx64 ")", mad_get_field64(node->info, 0, IB_NODE_PORT_GUID_F)); if (group) { fprintf(f, "\t# "); str = ibnd_get_chassis_type(node); if (str) fprintf(f, "%s ", str); str = ibnd_get_chassis_slot_str(node, str2, 256); if (str) fprintf(f, "%s", str); } fprintf(f, "\n"); out_switch_detail(node, sw_prefix); fprintf(f, "\n"); } static void out_ca_detail(ibnd_node_t *node, const char *ca_prefix) { const char *node_type; switch (node->type) { case IB_NODE_CA: node_type = "Ca"; break; case IB_NODE_ROUTER: node_type = "Rt"; break; default: node_type = "???"; break; } fprintf(f, "%s%s\t%d %s\t\t# \"%s\"", ca_prefix ? ca_prefix : "", node_type, node->numports, node_name(node), clean_nodedesc(node->nodedesc)); } static void out_ca(ibnd_node_t *node, int group, char *chname, const char *id_prefix, const char *ca_prefix) { const char *node_type; out_ids(node, group, chname, id_prefix); switch (node->type) { case IB_NODE_CA: node_type = "ca"; break; case IB_NODE_ROUTER: node_type = "rt"; break; default: node_type = "???"; break; } fprintf(f, "%s%sguid=0x%" PRIx64 "\n", id_prefix ? id_prefix : "", node_type, node->guid); out_ca_detail(node, ca_prefix); if (group && ibnd_is_xsigo_hca(node->guid)) fprintf(f, " (scp)"); fprintf(f, "\n"); } #define OUT_BUFFER_SIZE 16 static char *out_ext_port(ibnd_port_t * port, int group) { static char mapping[OUT_BUFFER_SIZE]; if (group && port->ext_portnum != 0) { snprintf(mapping, OUT_BUFFER_SIZE, "[ext %d]", port->ext_portnum); return (mapping); } return (NULL); } static void out_switch_port(ibnd_port_t *port, int group, const char *out_prefix) { char *ext_port_str = NULL; char *rem_nodename = NULL; uint32_t iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F); uint32_t ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F); uint32_t vlcap = mad_get_field(port->info, 0, IB_PORT_VL_CAP_F); uint32_t fdr10 = mad_get_field(port->ext_info, 0, IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F); uint32_t espeed; DEBUG("port %p:%d remoteport %p\n", port, port->portnum, port->remoteport); fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum); ext_port_str = out_ext_port(port, group); if (ext_port_str) fprintf(f, "%s", ext_port_str); rem_nodename = remap_node_name(node_name_map, port->remoteport->node->guid, port->remoteport->node->nodedesc); ext_port_str = out_ext_port(port->remoteport, group); if (!port->node->ports[0]) { ispeed = 0; espeed = 0; } else espeed = ibnd_get_agg_linkspeedext(port->node->ports[0]->info, port->info); fprintf(f, "\t%s[%d]%s", node_name(port->remoteport->node), port->remoteport->portnum, ext_port_str ? ext_port_str : ""); if (port->remoteport->node->type != IB_NODE_SWITCH) fprintf(f, "(%" PRIx64 ") ", port->remoteport->guid); fprintf(f, "\t\t# \"%s\" lid %d %s%s", rem_nodename, port->remoteport->node->type == IB_NODE_SWITCH ? port->remoteport->node->smalid : port->remoteport->base_lid, dump_linkwidth_compat(iwidth), (ispeed != 4 && !espeed) ? dump_linkspeed_compat(ispeed) : dump_linkspeedext_compat(espeed, ispeed, fdr10)); if (full_info) fprintf(f, " s=%d w=%d v=%d", ispeed, iwidth, vlcap); if (ibnd_is_xsigo_tca(port->remoteport->guid)) fprintf(f, " slot %d", port->portnum); else if (ibnd_is_xsigo_hca(port->remoteport->guid)) fprintf(f, " (scp)"); fprintf(f, "\n"); free(rem_nodename); } static void out_ca_port(ibnd_port_t *port, int group, const char *out_prefix) { char *str = NULL; char *rem_nodename = NULL; uint32_t iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F); uint32_t ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F); uint32_t vlcap = mad_get_field(port->info, 0, IB_PORT_VL_CAP_F); uint32_t fdr10 = mad_get_field(port->ext_info, 0, IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F); uint32_t espeed; fprintf(f, "%s[%d]", out_prefix ? out_prefix : "", port->portnum); if (port->node->type != IB_NODE_SWITCH) fprintf(f, "(%" PRIx64 ") ", port->guid); fprintf(f, "\t%s[%d]", node_name(port->remoteport->node), port->remoteport->portnum); str = out_ext_port(port->remoteport, group); if (str) fprintf(f, "%s", str); if (port->remoteport->node->type != IB_NODE_SWITCH) fprintf(f, " (%" PRIx64 ") ", port->remoteport->guid); rem_nodename = remap_node_name(node_name_map, port->remoteport->node->guid, port->remoteport->node->nodedesc); espeed = ibnd_get_agg_linkspeedext(port->info, port->info); fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s", port->base_lid, port->lmc, rem_nodename, port->remoteport->node->type == IB_NODE_SWITCH ? port->remoteport->node->smalid : port->remoteport->base_lid, dump_linkwidth_compat(iwidth), (ispeed != 4 && !espeed) ? dump_linkspeed_compat(ispeed) : dump_linkspeedext_compat(espeed, ispeed, fdr10)); if (full_info) fprintf(f, " s=%d w=%d v=%d", ispeed, iwidth, vlcap); fprintf(f, "\n"); free(rem_nodename); } struct iter_user_data { int group; int skip_chassis_nodes; }; static void switch_iter_func(ibnd_node_t * node, void *iter_user_data) { ibnd_port_t *port; int p = 0; struct iter_user_data *data = (struct iter_user_data *)iter_user_data; DEBUG("SWITCH: node %p\n", node); /* skip chassis based switches if flagged */ if (data->skip_chassis_nodes && node->chassis && node->chassis->chassisnum) return; out_switch(node, data->group, NULL, NULL, NULL); for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (port && port->remoteport) out_switch_port(port, data->group, NULL); } } static void ca_iter_func(ibnd_node_t * node, void *iter_user_data) { ibnd_port_t *port; int p = 0; struct iter_user_data *data = (struct iter_user_data *)iter_user_data; DEBUG("CA: node %p\n", node); /* Now, skip chassis based CAs */ if (data->group && node->chassis && node->chassis->chassisnum) return; out_ca(node, data->group, NULL, NULL, NULL); for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (port && port->remoteport) out_ca_port(port, data->group, NULL); } } static void router_iter_func(ibnd_node_t * node, void *iter_user_data) { ibnd_port_t *port; int p = 0; struct iter_user_data *data = (struct iter_user_data *)iter_user_data; DEBUG("RT: node %p\n", node); /* Now, skip chassis based RTs */ if (data->group && node->chassis && node->chassis->chassisnum) return; out_ca(node, data->group, NULL, NULL, NULL); for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (port && port->remoteport) out_ca_port(port, data->group, NULL); } } static int dump_topology(int group, ibnd_fabric_t *fabric) { ibnd_node_t *node; ibnd_port_t *port; int i = 0, p = 0; time_t t = time(NULL); uint64_t chguid; char *chname = NULL; struct iter_user_data iter_user_data; fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t)); if (report_max_hops) fprintf(f, "# Reported max hops discovered: %u\n" "# Total MADs used: %u\n", fabric->maxhops_discovered, fabric->total_mads_used); fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n", fabric->from_node->guid, mad_get_field64(fabric->from_node->info, 0, IB_NODE_PORT_GUID_F)); /* Make pass on switches */ if (group) { ibnd_chassis_t *ch = NULL; /* Chassis based switches first */ for (ch = fabric->chassis; ch; ch = ch->next) { int n = 0; if (!ch->chassisnum) continue; chguid = out_chassis(fabric, ch->chassisnum); chname = NULL; if (ibnd_is_xsigo_guid(chguid)) { for (node = ch->nodes; node; node = node->next_chassis_node) { if (ibnd_is_xsigo_hca(node->guid)) { chname = node->nodedesc; fprintf(f, "Hostname: %s\n", clean_nodedesc (node->nodedesc)); } } } fprintf(f, "\n# Spine Nodes"); for (n = 1; n <= SPINES_MAX_NUM; n++) { if (ch->spinenode[n]) { out_switch(ch->spinenode[n], group, chname, NULL, NULL); for (p = 1; p <= ch->spinenode[n]->numports; p++) { port = ch->spinenode[n]->ports[p]; if (port && port->remoteport) out_switch_port(port, group, NULL); } } } fprintf(f, "\n# Line Nodes"); for (n = 1; n <= LINES_MAX_NUM; n++) { if (ch->linenode[n]) { out_switch(ch->linenode[n], group, chname, NULL, NULL); for (p = 1; p <= ch->linenode[n]->numports; p++) { port = ch->linenode[n]->ports[p]; if (port && port->remoteport) out_switch_port(port, group, NULL); } } } fprintf(f, "\n# Chassis Switches"); for (node = ch->nodes; node; node = node->next_chassis_node) { if (node->type == IB_NODE_SWITCH) { out_switch(node, group, chname, NULL, NULL); for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (port && port->remoteport) out_switch_port(port, group, NULL); } } } fprintf(f, "\n# Chassis CAs"); for (node = ch->nodes; node; node = node->next_chassis_node) { if (node->type == IB_NODE_CA) { out_ca(node, group, chname, NULL, NULL); for (p = 1; p <= node->numports; p++) { port = node->ports[p]; if (port && port->remoteport) out_ca_port(port, group, NULL); } } } } } else { /* !group */ iter_user_data.group = group; iter_user_data.skip_chassis_nodes = 0; ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH, &iter_user_data); } chname = NULL; if (group) { iter_user_data.group = group; iter_user_data.skip_chassis_nodes = 1; fprintf(f, "\nNon-Chassis Nodes\n"); ibnd_iter_nodes_type(fabric, switch_iter_func, IB_NODE_SWITCH, &iter_user_data); } iter_user_data.group = group; iter_user_data.skip_chassis_nodes = 0; /* Make pass on CAs */ ibnd_iter_nodes_type(fabric, ca_iter_func, IB_NODE_CA, &iter_user_data); /* Make pass on routers */ ibnd_iter_nodes_type(fabric, router_iter_func, IB_NODE_ROUTER, &iter_user_data); return i; } static void dump_ports_report(ibnd_node_t *node, void *user_data) { int p = 0; ibnd_port_t *port = NULL; char *nodename = NULL; char *rem_nodename = NULL; uint32_t espeed; /* for each port */ for (p = node->numports, port = node->ports[p]; p > 0; port = node->ports[--p]) { uint32_t iwidth, ispeed, fdr10; uint8_t *info = NULL; if (port == NULL) continue; iwidth = mad_get_field(port->info, 0, IB_PORT_LINK_WIDTH_ACTIVE_F); ispeed = mad_get_field(port->info, 0, IB_PORT_LINK_SPEED_ACTIVE_F); if (port->node->type == IB_NODE_SWITCH) { if (port->node->ports[0]) info = (uint8_t *)&port->node->ports[0]->info; } else info = (uint8_t *)&port->info; if (info) { espeed = ibnd_get_agg_linkspeedext(info, port->info); } else { ispeed = 0; iwidth = 0; espeed = 0; } fdr10 = mad_get_field(port->ext_info, 0, IB_MLNX_EXT_PORT_LINK_SPEED_ACTIVE_F); nodename = remap_node_name(node_name_map, port->node->guid, port->node->nodedesc); fprintf(stdout, "%2s %5d %2d 0x%016" PRIx64 " %s %s", ports_nt_str_compat(node), node->type == IB_NODE_SWITCH ? node->smalid : port->base_lid, port->portnum, port->guid, dump_linkwidth_compat(iwidth), (ispeed != 4 && !espeed) ? dump_linkspeed_compat(ispeed) : dump_linkspeedext_compat(espeed, ispeed, fdr10)); if (port->remoteport) { rem_nodename = remap_node_name(node_name_map, port->remoteport->node->guid, port->remoteport->node->nodedesc); fprintf(stdout, " - %2s %5d %2d 0x%016" PRIx64 " ( '%s' - '%s' )\n", ports_nt_str_compat(port->remoteport->node), port->remoteport->node->type == IB_NODE_SWITCH ? port->remoteport->node->smalid : port->remoteport->base_lid, port->remoteport->portnum, port->remoteport->guid, nodename, rem_nodename); free(rem_nodename); } else fprintf(stdout, "%36s'%s'\n", "", nodename); free(nodename); } } struct iter_diff_data { uint32_t diff_flags; ibnd_fabric_t *fabric1; ibnd_fabric_t *fabric2; const char *fabric1_prefix; const char *fabric2_prefix; void (*out_header)(ibnd_node_t *, int, char *, const char *, const char *); void (*out_header_detail)(ibnd_node_t *, const char *); void (*out_port)(ibnd_port_t *, int, const char *); }; static void diff_iter_out_header(ibnd_node_t * node, struct iter_diff_data *data, int *out_header_flag) { if (!(*out_header_flag)) { (*data->out_header) (node, 0, NULL, NULL, NULL); (*out_header_flag)++; } } static void diff_ports(ibnd_node_t * fabric1_node, ibnd_node_t * fabric2_node, int *out_header_flag, struct iter_diff_data *data) { ibnd_port_t *fabric1_port; ibnd_port_t *fabric2_port; int p; for (p = 1; p <= fabric1_node->numports; p++) { int fabric1_out = 0, fabric2_out = 0; fabric1_port = fabric1_node->ports[p]; fabric2_port = fabric2_node->ports[p]; if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION) { if ((fabric1_port && !fabric2_port) || ((fabric1_port && fabric2_port) && (fabric1_port->remoteport && !fabric2_port->remoteport))) fabric1_out++; else if ((!fabric1_port && fabric2_port) || ((fabric1_port && fabric2_port) && (!fabric1_port->remoteport && fabric2_port->remoteport))) fabric2_out++; else if ((fabric1_port && fabric2_port) && ((fabric1_port->guid != fabric2_port->guid) || ((fabric1_port->remoteport && fabric2_port->remoteport) && (fabric1_port->remoteport->guid != fabric2_port->remoteport->guid)))) { fabric1_out++; fabric2_out++; } } if ((data->diff_flags & DIFF_FLAG_LID) && fabric1_port && fabric2_port && fabric1_port->base_lid != fabric2_port->base_lid) { fabric1_out++; fabric2_out++; } if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION && data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION && fabric1_port && fabric2_port && fabric1_port->remoteport && fabric2_port->remoteport && memcmp(fabric1_port->remoteport->node->nodedesc, fabric2_port->remoteport->node->nodedesc, IB_SMP_DATA_SIZE)) { fabric1_out++; fabric2_out++; } if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION && data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION && fabric1_port && fabric2_port && fabric1_port->remoteport && fabric2_port->remoteport && memcmp(fabric1_port->remoteport->node->nodedesc, fabric2_port->remoteport->node->nodedesc, IB_SMP_DATA_SIZE)) { fabric1_out++; fabric2_out++; } if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION && data->diff_flags & DIFF_FLAG_LID && fabric1_port && fabric2_port && fabric1_port->remoteport && fabric2_port->remoteport && fabric1_port->remoteport->base_lid != fabric2_port->remoteport->base_lid) { fabric1_out++; fabric2_out++; } if (fabric1_out) { diff_iter_out_header(fabric1_node, data, out_header_flag); (*data->out_port) (fabric1_port, 0, data->fabric1_prefix); } if (fabric2_out) { diff_iter_out_header(fabric1_node, data, out_header_flag); (*data->out_port) (fabric2_port, 0, data->fabric2_prefix); } } } static void diff_iter_func(ibnd_node_t * fabric1_node, void *iter_user_data) { struct iter_diff_data *data = iter_user_data; ibnd_node_t *fabric2_node; ibnd_port_t *fabric1_port; int p; DEBUG("DEBUG: fabric1_node %p\n", fabric1_node); fabric2_node = ibnd_find_node_guid(data->fabric2, fabric1_node->guid); if (!fabric2_node) { (*data->out_header) (fabric1_node, 0, NULL, data->fabric1_prefix, data->fabric1_prefix); for (p = 1; p <= fabric1_node->numports; p++) { fabric1_port = fabric1_node->ports[p]; if (fabric1_port && fabric1_port->remoteport) (*data->out_port) (fabric1_port, 0, data->fabric1_prefix); } } else if (data->diff_flags & (DIFF_FLAG_PORT_CONNECTION | DIFF_FLAG_LID | DIFF_FLAG_NODE_DESCRIPTION)) { int out_header_flag = 0; if ((data->diff_flags & DIFF_FLAG_LID && fabric1_node->smalid != fabric2_node->smalid) || (data->diff_flags & DIFF_FLAG_NODE_DESCRIPTION && memcmp(fabric1_node->nodedesc, fabric2_node->nodedesc, IB_SMP_DATA_SIZE))) { (*data->out_header) (fabric1_node, 0, NULL, NULL, data->fabric1_prefix); (*data->out_header_detail) (fabric2_node, data->fabric2_prefix); fprintf(f, "\n"); out_header_flag++; } if (fabric1_node->numports != fabric2_node->numports) { diff_iter_out_header(fabric1_node, data, &out_header_flag); fprintf(f, "%snumports = %d\n", data->fabric1_prefix, fabric1_node->numports); fprintf(f, "%snumports = %d\n", data->fabric2_prefix, fabric2_node->numports); return; } if (data->diff_flags & DIFF_FLAG_PORT_CONNECTION || data->diff_flags & DIFF_FLAG_LID) diff_ports(fabric1_node, fabric2_node, &out_header_flag, data); } } static int diff_common(ibnd_fabric_t *orig_fabric, ibnd_fabric_t *new_fabric, int node_type, uint32_t diff_flags, void (*out_header)(ibnd_node_t *, int, char *, const char *, const char *), void (*out_header_detail)(ibnd_node_t *, const char *), void (*out_port)(ibnd_port_t *, int, const char *)) { struct iter_diff_data iter_diff_data; iter_diff_data.diff_flags = diff_flags; iter_diff_data.fabric1 = orig_fabric; iter_diff_data.fabric2 = new_fabric; iter_diff_data.fabric1_prefix = "< "; iter_diff_data.fabric2_prefix = "> "; iter_diff_data.out_header = out_header; iter_diff_data.out_header_detail = out_header_detail; iter_diff_data.out_port = out_port; ibnd_iter_nodes_type(orig_fabric, diff_iter_func, node_type, &iter_diff_data); /* Do opposite diff to find existence of node types * in new_fabric but not in orig_fabric. * * In this diff, we don't need to check port connections, * lids, or node descriptions since it has already been * done (i.e. checks are only done when guid exists on both * orig and new). */ iter_diff_data.diff_flags = diff_flags & ~DIFF_FLAG_PORT_CONNECTION; iter_diff_data.diff_flags &= ~DIFF_FLAG_LID; iter_diff_data.diff_flags &= ~DIFF_FLAG_NODE_DESCRIPTION; iter_diff_data.fabric1 = new_fabric; iter_diff_data.fabric2 = orig_fabric; iter_diff_data.fabric1_prefix = "> "; iter_diff_data.fabric2_prefix = "< "; iter_diff_data.out_header = out_header; iter_diff_data.out_header_detail = out_header_detail; iter_diff_data.out_port = out_port; ibnd_iter_nodes_type(new_fabric, diff_iter_func, node_type, &iter_diff_data); return 0; } static int diff(ibnd_fabric_t *orig_fabric, ibnd_fabric_t *new_fabric) { if (diffcheck_flags & DIFF_FLAG_SWITCH) diff_common(orig_fabric, new_fabric, IB_NODE_SWITCH, diffcheck_flags, out_switch, out_switch_detail, out_switch_port); if (diffcheck_flags & DIFF_FLAG_CA) diff_common(orig_fabric, new_fabric, IB_NODE_CA, diffcheck_flags, out_ca, out_ca_detail, out_ca_port); if (diffcheck_flags & DIFF_FLAG_ROUTER) diff_common(orig_fabric, new_fabric, IB_NODE_ROUTER, diffcheck_flags, out_ca, out_ca_detail, out_ca_port); return 0; } static int list, group, ports_report; static int process_opt(void *context, int ch) { struct ibnd_config *cfg = context; char *p; 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: cache_file = strdup(optarg); break; case 3: load_cache_file = strdup(optarg); break; case 4: diff_cache_file = strdup(optarg); break; case 5: diffcheck_flags = 0; p = strtok(optarg, ","); while (p) { if (!strcasecmp(p, "sw")) diffcheck_flags |= DIFF_FLAG_SWITCH; else if (!strcasecmp(p, "ca")) diffcheck_flags |= DIFF_FLAG_CA; else if (!strcasecmp(p, "router")) diffcheck_flags |= DIFF_FLAG_ROUTER; else if (!strcasecmp(p, "port")) diffcheck_flags |= DIFF_FLAG_PORT_CONNECTION; else if (!strcasecmp(p, "lid")) diffcheck_flags |= DIFF_FLAG_LID; else if (!strcasecmp(p, "nodedesc")) diffcheck_flags |= DIFF_FLAG_NODE_DESCRIPTION; else { fprintf(stderr, "invalid diff check key: %s\n", p); return -1; } p = strtok(NULL, ","); } break; case 's': cfg->show_progress = 1; break; case 'f': full_info = 1; break; case 'l': list = LIST_CA_NODE | LIST_SWITCH_NODE | LIST_ROUTER_NODE; break; case 'g': group = 1; break; case 'S': list = LIST_SWITCH_NODE; break; case 'H': list = LIST_CA_NODE; break; case 'R': list = LIST_ROUTER_NODE; break; case 'p': ports_report = 1; break; case 'm': report_max_hops = 1; break; case 'o': cfg->max_smps = strtoul(optarg, NULL, 0); break; default: return -1; } return 0; } int main(int argc, char **argv) { struct ibnd_config config = { 0 }; ibnd_fabric_t *fabric = NULL; ibnd_fabric_t *diff_fabric = NULL; const struct ibdiag_opt opts[] = { {"full", 'f', 0, NULL, "show full information (ports' speed and width, vlcap)"}, {"show", 's', 0, NULL, "show more information"}, {"list", 'l', 0, NULL, "list of connected nodes"}, {"grouping", 'g', 0, NULL, "show grouping"}, {"Hca_list", 'H', 0, NULL, "list of connected CAs"}, {"Switch_list", 'S', 0, NULL, "list of connected switches"}, {"Router_list", 'R', 0, NULL, "list of connected routers"}, {"node-name-map", 1, 1, "", "node name map file"}, {"cache", 2, 1, "", "filename to cache ibnetdiscover data to"}, {"load-cache", 3, 1, "", "filename of ibnetdiscover cache to load"}, {"diff", 4, 1, "", "filename of ibnetdiscover cache to diff"}, {"diffcheck", 5, 1, "", "specify checks to execute for --diff"}, {"ports", 'p', 0, NULL, "obtain a ports report"}, {"max_hops", 'm', 0, NULL, "report max hops discovered by the library"}, {"outstanding_smps", 'o', 1, NULL, "specify the number of outstanding SMP's which should be " "issued during the scan"}, {} }; char usage_args[] = "[topology-file]"; ibdiag_process_opts(argc, argv, &config, "DGKLs", opts, process_opt, usage_args, NULL); f = stdout; argc -= optind; argv += optind; if (ibd_timeout) config.timeout_ms = ibd_timeout; config.flags = ibd_ibnetdisc_flags; if (argc && !(f = fopen(argv[0], "w"))) IBEXIT("can't open file %s for writing", argv[0]); config.mkey = ibd_mkey; node_name_map = open_node_name_map(node_name_map_file); if (diff_cache_file && !(diff_fabric = ibnd_load_fabric(diff_cache_file, 0))) IBEXIT("loading cached fabric for diff failed\n"); if (load_cache_file) { if ((fabric = ibnd_load_fabric(load_cache_file, 0)) == NULL) IBEXIT("loading cached fabric failed\n"); } else { if ((fabric = ibnd_discover_fabric(ibd_ca, ibd_ca_port, NULL, &config)) == NULL) IBEXIT("discover failed\n"); } if (ports_report) ibnd_iter_nodes(fabric, dump_ports_report, NULL); else if (list) list_nodes(fabric, list); else if (diff_fabric) diff(diff_fabric, fabric); else dump_topology(group, fabric); if (cache_file) if (ibnd_cache_fabric(fabric, cache_file, 0) < 0) IBEXIT("caching ibnetdiscover data failed\n"); ibnd_destroy_fabric(fabric); if (diff_fabric) ibnd_destroy_fabric(diff_fabric); close_node_name_map(node_name_map); exit(0); }