From: shefty Date: Thu, 15 Jan 2009 07:24:33 +0000 (+0000) Subject: ib-diags: initial port of IB diagnostic tools X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=0d5a35d3cb11f60db252b4e4fadea35f91602e3e;p=~shefty%2Frdma-win.git ib-diags: initial port of IB diagnostic tools Only select tools ported yet. Changes have not yet been merged into main git tree. Signed-off-by: Sean Hefty git-svn-id: svn://openib.tc.cornell.edu/gen1@1832 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- diff --git a/branches/winverbs/tools/infiniband_diags/dirs b/branches/winverbs/tools/infiniband_diags/dirs new file mode 100644 index 00000000..039a6eef --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/dirs @@ -0,0 +1,2 @@ +DIRS = \ + src \ No newline at end of file diff --git a/branches/winverbs/tools/infiniband_diags/include/grouping.h b/branches/winverbs/tools/infiniband_diags/include/grouping.h new file mode 100644 index 00000000..1044f3aa --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/include/grouping.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems 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. + * + */ + +#ifndef _GROUPING_H_ +#define _GROUPING_H_ + +/*========================================================*/ +/* FABRIC SCANNER SPECIFIC DATA */ +/*========================================================*/ + +#define SPINES_MAX_NUM 12 +#define LINES_MAX_NUM 36 + +typedef struct ChassisList ChassisList; +typedef struct AllChassisList AllChassisList; + +struct ChassisList { + ChassisList *next; + uint64_t chassisguid; + int chassisnum; + int chassistype; + int nodecount; /* used for grouping by SystemImageGUID */ + Node *spinenode[SPINES_MAX_NUM + 1]; + Node *linenode[LINES_MAX_NUM + 1]; +}; + +struct AllChassisList { + ChassisList *first; + ChassisList *current; + ChassisList *last; +}; + +/*========================================================*/ +/* CHASSIS RECOGNITION SPECIFIC DATA */ +/*========================================================*/ + +/* Device IDs */ +#define VTR_DEVID_IB_FC_ROUTER 0x5a00 +#define VTR_DEVID_IB_IP_ROUTER 0x5a01 +#define VTR_DEVID_ISR9600_SPINE 0x5a02 +#define VTR_DEVID_ISR9600_LEAF 0x5a03 +#define VTR_DEVID_HCA1 0x5a04 +#define VTR_DEVID_HCA2 0x5a44 +#define VTR_DEVID_HCA3 0x6278 +#define VTR_DEVID_SW_6IB4 0x5a05 +#define VTR_DEVID_ISR9024 0x5a06 +#define VTR_DEVID_ISR9288 0x5a07 +#define VTR_DEVID_SLB24 0x5a09 +#define VTR_DEVID_SFB12 0x5a08 +#define VTR_DEVID_SFB4 0x5a0b +#define VTR_DEVID_ISR9024_12 0x5a0c +#define VTR_DEVID_SLB8 0x5a0d +#define VTR_DEVID_RLX_SWITCH_BLADE 0x5a20 +#define VTR_DEVID_ISR9024_DDR 0x5a31 +#define VTR_DEVID_SFB12_DDR 0x5a32 +#define VTR_DEVID_SFB4_DDR 0x5a33 +#define VTR_DEVID_SLB24_DDR 0x5a34 +#define VTR_DEVID_SFB2012 0x5a37 +#define VTR_DEVID_SLB2024 0x5a38 +#define VTR_DEVID_ISR2012 0x5a39 +#define VTR_DEVID_SFB2004 0x5a40 +#define VTR_DEVID_ISR2004 0x5a41 + +enum ChassisType { UNRESOLVED_CT, ISR9288_CT, ISR9096_CT, ISR2012_CT, ISR2004_CT }; +enum ChassisSlot { UNRESOLVED_CS, LINE_CS, SPINE_CS, SRBD_CS }; + +/*========================================================*/ +/* External interface */ +/*========================================================*/ + +ChassisList *group_nodes(); +char *portmapstring(Port *port); +char *get_chassis_type(unsigned char chassistype); +char *get_chassis_slot(unsigned char chassisslot); +uint64_t get_chassis_guid(unsigned char chassisnum); + +int is_xsigo_guid(uint64_t guid); +int is_xsigo_tca(uint64_t guid); +int is_xsigo_hca(uint64_t guid); + +#endif /* _GROUPING_H_ */ diff --git a/branches/winverbs/tools/infiniband_diags/include/ibdiag_common.h b/branches/winverbs/tools/infiniband_diags/include/ibdiag_common.h new file mode 100644 index 00000000..1ed57587 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/include/ibdiag_common.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2006-2007 The Regents of the University of California. + * Copyright (c) 2004-2008 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. + * + */ + +#ifndef _IBDIAG_COMMON_H_ +#define _IBDIAG_COMMON_H_ + +#include + +#if !defined( __cplusplus ) +#define inline __inline +#endif + +extern char *argv0; +extern int ibdebug; + +/*========================================================*/ +/* External interface */ +/*========================================================*/ + +void iberror(const char *fn, char *msg, ...); + +#undef DEBUG +#define DEBUG if (ibdebug || verbose) IBWARN +#define VERBOSE if (ibdebug || verbose > 1) IBWARN +#define IBERROR(fmt, ...) iberror(__FUNCTION__, fmt, ## __VA_ARGS__) + +#include + +static inline const char* get_build_version(void) +{ + return "BUILD VERSION: " IBDIAG_VERSION " Build date: " __DATE__ " " __TIME__ ; +} + +#endif /* _IBDIAG_COMMON_H_ */ diff --git a/branches/winverbs/tools/infiniband_diags/include/ibdiag_version.h b/branches/winverbs/tools/infiniband_diags/include/ibdiag_version.h new file mode 100644 index 00000000..790385f5 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/include/ibdiag_version.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008 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. + * + */ + +#ifndef _IBDIAG_VERSION_H_ +#define _IBDIAG_VERSION_H_ + +#define IBDIAG_VERSION "1.4.2" + +#endif /* _IBDIAG_VERSION_H_ */ diff --git a/branches/winverbs/tools/infiniband_diags/include/ibdiag_version.h.in b/branches/winverbs/tools/infiniband_diags/include/ibdiag_version.h.in new file mode 100644 index 00000000..fd842e68 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/include/ibdiag_version.h.in @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008 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. + * + */ + +#ifndef _IBDIAG_VERSION_H_ +#define _IBDIAG_VERSION_H_ + +#define IBDIAG_VERSION "@VERSION@" + +#endif /* _IBDIAG_VERSION_H_ */ diff --git a/branches/winverbs/tools/infiniband_diags/include/ibnetdiscover.h b/branches/winverbs/tools/infiniband_diags/include/ibnetdiscover.h new file mode 100644 index 00000000..c52cad59 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/include/ibnetdiscover.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems 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. + * + */ + +#ifndef _IBNETDISCOVER_H_ +#define _IBNETDISCOVER_H_ + +#define MAXHOPS 63 + +#define CA_NODE 1 +#define SWITCH_NODE 2 +#define ROUTER_NODE 3 + +#define LIST_CA_NODE (1 << CA_NODE) +#define LIST_SWITCH_NODE (1 << SWITCH_NODE) +#define LIST_ROUTER_NODE (1 << ROUTER_NODE) + +/* Vendor IDs (for chassis based systems) */ +#define VTR_VENDOR_ID 0x8f1 /* Voltaire */ +#define TS_VENDOR_ID 0x5ad /* Cisco */ +#define SS_VENDOR_ID 0x66a /* InfiniCon */ +#define XS_VENDOR_ID 0x1397 /* Xsigo */ + + +typedef struct Port Port; +typedef struct Node Node; +typedef struct ChassisRecord ChassisRecord; + +struct ChassisRecord { + ChassisRecord *next; + + unsigned char chassisnum; + unsigned char anafanum; + unsigned char slotnum; + unsigned char chassistype; + unsigned char chassisslot; +}; + +struct Port { + Port *next; + uint64_t portguid; + int portnum; + int lid; + int lmc; + int state; + int physstate; + int linkwidth; + int linkspeed; + + Node *node; + Port *remoteport; /* null if SMA */ +}; + +struct Node { + Node *htnext; + Node *dnext; + Port *ports; + ib_portid_t path; + int type; + int dist; + int numports; + int localport; + int smalid; + int smalmc; + int smaenhsp0; + uint32_t devid; + uint32_t vendid; + uint64_t sysimgguid; + uint64_t nodeguid; + uint64_t portguid; + char nodedesc[64]; + uint8_t nodeinfo[64]; + + ChassisRecord *chrecord; +}; + +#endif /* _IBNETDISCOVER_H_ */ diff --git a/branches/winverbs/tools/infiniband_diags/src/dirs b/branches/winverbs/tools/infiniband_diags/src/dirs new file mode 100644 index 00000000..23d2382d --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/dirs @@ -0,0 +1,13 @@ +DIRS = \ + sminfo \ + ibstat \ + perfquery \ + vendstat \ + ibaddr + + + + + + + \ No newline at end of file diff --git a/branches/winverbs/tools/infiniband_diags/src/grouping.c b/branches/winverbs/tools/infiniband_diags/src/grouping.c new file mode 100644 index 00000000..93b6f09e --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/grouping.c @@ -0,0 +1,793 @@ +/* + * Copyright (c) 2004-2007 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems 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. + * + */ + +/*========================================================*/ +/* FABRIC SCANNER SPECIFIC DATA */ +/*========================================================*/ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#if defined(_WIN32) || defined(_WIN64) +#include +#include +#include "..\ibdiag_common.c" +#else +#include +#include +#endif + +#include +#include + +#include "ibnetdiscover.h" +#include "grouping.h" + +#define OUT_BUFFER_SIZE 16 + + +extern Node *nodesdist[MAXHOPS+1]; /* last is CA list */ +extern Node *mynode; +extern Port *myport; +extern int maxhops_discovered; + +AllChassisList mylist; + +char *ChassisTypeStr[5] = { "", "ISR9288", "ISR9096", "ISR2012", "ISR2004" }; +char *ChassisSlotStr[4] = { "", "Line", "Spine", "SRBD" }; + + +char *get_chassis_type(unsigned char chassistype) +{ + if (chassistype == UNRESOLVED_CT || chassistype > ISR2004_CT) + return NULL; + return ChassisTypeStr[chassistype]; +} + +char *get_chassis_slot(unsigned char chassisslot) +{ + if (chassisslot == UNRESOLVED_CS || chassisslot > SRBD_CS) + return NULL; + return ChassisSlotStr[chassisslot]; +} + +static struct ChassisList *find_chassisnum(unsigned char chassisnum) +{ + ChassisList *current; + + for (current = mylist.first; current; current = current->next) { + if (current->chassisnum == chassisnum) + return current; + } + + return NULL; +} + +static uint64_t topspin_chassisguid(uint64_t guid) +{ + /* Byte 3 in system image GUID is chassis type, and */ + /* Byte 4 is location ID (slot) so just mask off byte 4 */ + return guid & 0xffffffff00ffffffULL; +} + +int is_xsigo_guid(uint64_t guid) +{ + if ((guid & 0xffffff0000000000ULL) == 0x0013970000000000ULL) + return 1; + else + return 0; +} + +static int is_xsigo_leafone(uint64_t guid) +{ + if ((guid & 0xffffffffff000000ULL) == 0x0013970102000000ULL) + return 1; + else + return 0; +} + +int is_xsigo_hca(uint64_t guid) +{ + /* NodeType 2 is HCA */ + if ((guid & 0xffffffff00000000ULL) == 0x0013970200000000ULL) + return 1; + else + return 0; +} + +int is_xsigo_tca(uint64_t guid) +{ + /* NodeType 3 is TCA */ + if ((guid & 0xffffffff00000000ULL) == 0x0013970300000000ULL) + return 1; + else + return 0; +} + +static int is_xsigo_ca(uint64_t guid) +{ + if (is_xsigo_hca(guid) || is_xsigo_tca(guid)) + return 1; + else + return 0; +} + +static int is_xsigo_switch(uint64_t guid) +{ + if ((guid & 0xffffffff00000000ULL) == 0x0013970100000000ULL) + return 1; + else + return 0; +} + +static uint64_t xsigo_chassisguid(Node *node) +{ + if (!is_xsigo_ca(node->sysimgguid)) { + /* Byte 3 is NodeType and byte 4 is PortType */ + /* If NodeType is 1 (switch), PortType is masked */ + if (is_xsigo_switch(node->sysimgguid)) + return node->sysimgguid & 0xffffffff00ffffffULL; + else + return node->sysimgguid; + } else { + /* Is there a peer port ? */ + if (!node->ports->remoteport) + return node->sysimgguid; + + /* If peer port is Leaf 1, use its chassis GUID */ + if (is_xsigo_leafone(node->ports->remoteport->node->sysimgguid)) + return node->ports->remoteport->node->sysimgguid & + 0xffffffff00ffffffULL; + else + return node->sysimgguid; + } +} + +static uint64_t get_chassisguid(Node *node) +{ + if (node->vendid == TS_VENDOR_ID || node->vendid == SS_VENDOR_ID) + return topspin_chassisguid(node->sysimgguid); + else if (node->vendid == XS_VENDOR_ID || is_xsigo_guid(node->sysimgguid)) + return xsigo_chassisguid(node); + else + return node->sysimgguid; +} + +static struct ChassisList *find_chassisguid(Node *node) +{ + ChassisList *current; + uint64_t chguid; + + chguid = get_chassisguid(node); + for (current = mylist.first; current; current = current->next) { + if (current->chassisguid == chguid) + return current; + } + + return NULL; +} + +uint64_t get_chassis_guid(unsigned char chassisnum) +{ + ChassisList *chassis; + + chassis = find_chassisnum(chassisnum); + if (chassis) + return chassis->chassisguid; + else + return 0; +} + +static int is_router(Node *node) +{ + return (node->devid == VTR_DEVID_IB_FC_ROUTER || + node->devid == VTR_DEVID_IB_IP_ROUTER); +} + +static int is_spine_9096(Node *node) +{ + return (node->devid == VTR_DEVID_SFB4 || + node->devid == VTR_DEVID_SFB4_DDR); +} + +static int is_spine_9288(Node *node) +{ + return (node->devid == VTR_DEVID_SFB12 || + node->devid == VTR_DEVID_SFB12_DDR); +} + +static int is_spine_2004(Node *node) +{ + return (node->devid == VTR_DEVID_SFB2004); +} + +static int is_spine_2012(Node *node) +{ + return (node->devid == VTR_DEVID_SFB2012); +} + +static int is_spine(Node *node) +{ + return (is_spine_9096(node) || is_spine_9288(node) || + is_spine_2004(node) || is_spine_2012(node)); +} + +static int is_line_24(Node *node) +{ + return (node->devid == VTR_DEVID_SLB24 || + node->devid == VTR_DEVID_SLB24_DDR); +} + +static int is_line_8(Node *node) +{ + return (node->devid == VTR_DEVID_SLB8); +} + +static int is_line_2024(Node *node) +{ + return (node->devid == VTR_DEVID_SLB2024); +} + +static int is_line(Node *node) +{ + return (is_line_24(node) || is_line_8(node) || is_line_2024(node)); +} + +int is_chassis_switch(Node *node) +{ + return (is_spine(node) || is_line(node)); +} + +/* these structs help find Line (Anafa) slot number while using spine portnum */ +int line_slot_2_sfb4[25] = { 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4 }; +int anafa_line_slot_2_sfb4[25] = { 0, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 2, 2 }; +int line_slot_2_sfb12[25] = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10, 10, 11, 11, 12, 12 }; +int anafa_line_slot_2_sfb12[25] = { 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 }; + +/* IPR FCR modules connectivity while using sFB4 port as reference */ +int ipr_slot_2_sfb4_port[25] = { 0, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1, 3, 2, 1 }; + +/* these structs help find Spine (Anafa) slot number while using spine portnum */ +int spine12_slot_2_slb[25] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int anafa_spine12_slot_2_slb[25]= { 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int spine4_slot_2_slb[25] = { 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int anafa_spine4_slot_2_slb[25] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* reference { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */ + +static void get_sfb_slot(Node *node, Port *lineport) +{ + ChassisRecord *ch = node->chrecord; + + ch->chassisslot = SPINE_CS; + if (is_spine_9096(node)) { + ch->chassistype = ISR9096_CT; + ch->slotnum = spine4_slot_2_slb[lineport->portnum]; + ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; + } else if (is_spine_9288(node)) { + ch->chassistype = ISR9288_CT; + ch->slotnum = spine12_slot_2_slb[lineport->portnum]; + ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; + } else if (is_spine_2012(node)) { + ch->chassistype = ISR2012_CT; + ch->slotnum = spine12_slot_2_slb[lineport->portnum]; + ch->anafanum = anafa_spine12_slot_2_slb[lineport->portnum]; + } else if (is_spine_2004(node)) { + ch->chassistype = ISR2004_CT; + ch->slotnum = spine4_slot_2_slb[lineport->portnum]; + ch->anafanum = anafa_spine4_slot_2_slb[lineport->portnum]; + } else { + IBPANIC("Unexpected node found: guid 0x%016" PRIx64, node->nodeguid); + } +} + +static void get_router_slot(Node *node, Port *spineport) +{ + ChassisRecord *ch = node->chrecord; + int guessnum = 0; + + if (!ch) { + if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) + IBPANIC("out of mem"); + ch = node->chrecord; + } + + ch->chassisslot = SRBD_CS; + if (is_spine_9096(spineport->node)) { + ch->chassistype = ISR9096_CT; + ch->slotnum = line_slot_2_sfb4[spineport->portnum]; + ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; + } else if (is_spine_9288(spineport->node)) { + ch->chassistype = ISR9288_CT; + ch->slotnum = line_slot_2_sfb12[spineport->portnum]; + /* this is a smart guess based on nodeguids order on sFB-12 module */ + guessnum = spineport->node->nodeguid % 4; + /* module 1 <--> remote anafa 3 */ + /* module 2 <--> remote anafa 2 */ + /* module 3 <--> remote anafa 1 */ + ch->anafanum = (guessnum == 3 ? 1 : (guessnum == 1 ? 3 : 2)); + } else if (is_spine_2012(spineport->node)) { + ch->chassistype = ISR2012_CT; + ch->slotnum = line_slot_2_sfb12[spineport->portnum]; + /* this is a smart guess based on nodeguids order on sFB-12 module */ + guessnum = spineport->node->nodeguid % 4; + // module 1 <--> remote anafa 3 + // module 2 <--> remote anafa 2 + // module 3 <--> remote anafa 1 + ch->anafanum = (guessnum == 3? 1 : (guessnum == 1 ? 3 : 2)); + } else if (is_spine_2004(spineport->node)) { + ch->chassistype = ISR2004_CT; + ch->slotnum = line_slot_2_sfb4[spineport->portnum]; + ch->anafanum = ipr_slot_2_sfb4_port[spineport->portnum]; + } else { + IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid); + } +} + +static void get_slb_slot(ChassisRecord *ch, Port *spineport) +{ + ch->chassisslot = LINE_CS; + if (is_spine_9096(spineport->node)) { + ch->chassistype = ISR9096_CT; + ch->slotnum = line_slot_2_sfb4[spineport->portnum]; + ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; + } else if (is_spine_9288(spineport->node)) { + ch->chassistype = ISR9288_CT; + ch->slotnum = line_slot_2_sfb12[spineport->portnum]; + ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; + } else if (is_spine_2012(spineport->node)) { + ch->chassistype = ISR2012_CT; + ch->slotnum = line_slot_2_sfb12[spineport->portnum]; + ch->anafanum = anafa_line_slot_2_sfb12[spineport->portnum]; + } else if (is_spine_2004(spineport->node)) { + ch->chassistype = ISR2004_CT; + ch->slotnum = line_slot_2_sfb4[spineport->portnum]; + ch->anafanum = anafa_line_slot_2_sfb4[spineport->portnum]; + } else { + IBPANIC("Unexpected node found: guid 0x%016" PRIx64, spineport->node->nodeguid); + } +} + +/* + This function called for every Voltaire node in fabric + It could be optimized so, but time overhead is very small + and its only diag.util +*/ +static void fill_chassis_record(Node *node) +{ + Port *port; + Node *remnode = 0; + ChassisRecord *ch = 0; + + if (node->chrecord) /* somehow this node has already been passed */ + return; + + if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) + IBPANIC("out of mem"); + + ch = node->chrecord; + + /* node is router only in case of using unique lid */ + /* (which is lid of chassis router port) */ + /* in such case node->ports is actually a requested port... */ + if (is_router(node) && is_spine(node->ports->remoteport->node)) + get_router_slot(node, node->ports->remoteport); + else if (is_spine(node)) { + for (port = node->ports; port; port = port->next) { + if (!port->remoteport) + continue; + remnode = port->remoteport->node; + if (remnode->type != SWITCH_NODE) { + if (!remnode->chrecord) + get_router_slot(remnode, port); + continue; + } + if (!ch->chassistype) + /* we assume here that remoteport belongs to line */ + get_sfb_slot(node, port->remoteport); + + /* we could break here, but need to find if more routers connected */ + } + + } else if (is_line(node)) { + for (port = node->ports; port; port = port->next) { + if (port->portnum > 12) + continue; + if (!port->remoteport) + continue; + /* we assume here that remoteport belongs to spine */ + get_slb_slot(ch, port->remoteport); + break; + } + } + + return; +} + +static int get_line_index(Node *node) +{ + int retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum; + + if (retval > LINES_MAX_NUM || retval < 1) + IBPANIC("Internal error"); + return retval; +} + +static int get_spine_index(Node *node) +{ + int retval; + + if (is_spine_9288(node) || is_spine_2012(node)) + retval = 3 * (node->chrecord->slotnum - 1) + node->chrecord->anafanum; + else + retval = node->chrecord->slotnum; + + if (retval > SPINES_MAX_NUM || retval < 1) + IBPANIC("Internal error"); + return retval; +} + +static void insert_line_router(Node *node, ChassisList *chassislist) +{ + int i = get_line_index(node); + + if (chassislist->linenode[i]) + return; /* already filled slot */ + + chassislist->linenode[i] = node; + node->chrecord->chassisnum = chassislist->chassisnum; +} + +static void insert_spine(Node *node, ChassisList *chassislist) +{ + int i = get_spine_index(node); + + if (chassislist->spinenode[i]) + return; /* already filled slot */ + + chassislist->spinenode[i] = node; + node->chrecord->chassisnum = chassislist->chassisnum; +} + +static void pass_on_lines_catch_spines(ChassisList *chassislist) +{ + Node *node, *remnode; + Port *port; + int i; + + for (i = 1; i <= LINES_MAX_NUM; i++) { + node = chassislist->linenode[i]; + + if (!(node && is_line(node))) + continue; /* empty slot or router */ + + for (port = node->ports; port; port = port->next) { + if (port->portnum > 12) + continue; + + if (!port->remoteport) + continue; + remnode = port->remoteport->node; + + if (!remnode->chrecord) + continue; /* some error - spine not initialized ? FIXME */ + insert_spine(remnode, chassislist); + } + } +} + +static void pass_on_spines_catch_lines(ChassisList *chassislist) +{ + Node *node, *remnode; + Port *port; + int i; + + for (i = 1; i <= SPINES_MAX_NUM; i++) { + node = chassislist->spinenode[i]; + if (!node) + continue; /* empty slot */ + for (port = node->ports; port; port = port->next) { + if (!port->remoteport) + continue; + remnode = port->remoteport->node; + + if (!remnode->chrecord) + continue; /* some error - line/router not initialized ? FIXME */ + insert_line_router(remnode, chassislist); + } + } +} + +/* + Stupid interpolation algorithm... + But nothing to do - have to be compliant with VoltaireSM/NMS +*/ +static void pass_on_spines_interpolate_chguid(ChassisList *chassislist) +{ + Node *node; + int i; + + for (i = 1; i <= SPINES_MAX_NUM; i++) { + node = chassislist->spinenode[i]; + if (!node) + continue; /* skip the empty slots */ + + /* take first guid minus one to be consistent with SM */ + chassislist->chassisguid = node->nodeguid - 1; + break; + } +} + +/* + This function fills chassislist structure with all nodes + in that chassis + chassislist structure = structure of one standalone chassis +*/ +static void build_chassis(Node *node, ChassisList *chassislist) +{ + Node *remnode = 0; + Port *port = 0; + + /* we get here with node = chassis_spine */ + chassislist->chassistype = node->chrecord->chassistype; + insert_spine(node, chassislist); + + /* loop: pass on all ports of node */ + for (port = node->ports; port; port = port->next) { + if (!port->remoteport) + continue; + remnode = port->remoteport->node; + + if (!remnode->chrecord) + continue; /* some error - line or router not initialized ? FIXME */ + + insert_line_router(remnode, chassislist); + } + + pass_on_lines_catch_spines(chassislist); + /* this pass needed for to catch routers, since routers connected only */ + /* to spines in slot 1 or 4 and we could miss them first time */ + pass_on_spines_catch_lines(chassislist); + + /* additional 2 passes needed for to overcome a problem of pure "in-chassis" */ + /* connectivity - extra pass to ensure that all related chips/modules */ + /* inserted into the chassislist */ + pass_on_lines_catch_spines(chassislist); + pass_on_spines_catch_lines(chassislist); + pass_on_spines_interpolate_chguid(chassislist); +} + +/*========================================================*/ +/* INTERNAL TO EXTERNAL PORT MAPPING */ +/*========================================================*/ + +/* +Description : On ISR9288/9096 external ports indexing + is not matching the internal ( anafa ) port + indexes. Use this MAP to translate the data you get from + the OpenIB diagnostics (smpquery, ibroute, ibtracert, etc.) + + +Module : sLB-24 + anafa 1 anafa 2 +ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 +int port | 22 23 24 18 17 16 | 22 23 24 18 17 16 +ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 +int port | 19 20 21 15 14 13 | 19 20 21 15 14 13 +------------------------------------------------ + +Module : sLB-8 + anafa 1 anafa 2 +ext port | 13 14 15 16 17 18 | 19 20 21 22 23 24 +int port | 24 23 22 18 17 16 | 24 23 22 18 17 16 +ext port | 1 2 3 4 5 6 | 7 8 9 10 11 12 +int port | 21 20 19 15 14 13 | 21 20 19 15 14 13 + +-----------> + anafa 1 anafa 2 +ext port | - - 5 - - 6 | - - 7 - - 8 +int port | 24 23 22 18 17 16 | 24 23 22 18 17 16 +ext port | - - 1 - - 2 | - - 3 - - 4 +int port | 21 20 19 15 14 13 | 21 20 19 15 14 13 +------------------------------------------------ + +Module : sLB-2024 + +ext port | 13 14 15 16 17 18 19 20 21 22 23 24 +A1 int port| 13 14 15 16 17 18 19 20 21 22 23 24 +ext port | 1 2 3 4 5 6 7 8 9 10 11 12 +A2 int port| 13 14 15 16 17 18 19 20 21 22 23 24 +--------------------------------------------------- + +*/ + +int int2ext_map_slb24[2][25] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 5, 4, 18, 17, 16, 1, 2, 3, 13, 14, 15 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 11, 10, 24, 23, 22, 7, 8, 9, 19, 20, 21 } + }; +int int2ext_map_slb8[2][25] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 6, 6, 6, 1, 1, 1, 5, 5, 5 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 8, 8, 8, 3, 3, 3, 7, 7, 7 } + }; +int int2ext_map_slb2024[2][25] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 } + }; +/* reference { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }; */ + +/* + This function relevant only for line modules/chips + Returns string with external port index +*/ +char *portmapstring(Port *port) +{ + static char mapping[OUT_BUFFER_SIZE]; + ChassisRecord *ch = port->node->chrecord; + int portnum = port->portnum; + int chipnum = 0; + int pindex = 0; + Node *node = port->node; + + if (!ch || !is_line(node) || (portnum < 13 || portnum > 24)) + return NULL; + + if (ch->anafanum < 1 || ch->anafanum > 2) + return NULL; + + memset(mapping, 0, sizeof(mapping)); + + chipnum = ch->anafanum - 1; + + if (is_line_24(node)) + pindex = int2ext_map_slb24[chipnum][portnum]; + else if (is_line_2024(node)) + pindex = int2ext_map_slb2024[chipnum][portnum]; + else + pindex = int2ext_map_slb8[chipnum][portnum]; + + sprintf(mapping, "[ext %d]", pindex); + + return mapping; +} + +static void add_chassislist() +{ + if (!(mylist.current = calloc(1, sizeof(ChassisList)))) + IBPANIC("out of mem"); + + if (mylist.first == NULL) { + mylist.first = mylist.current; + mylist.last = mylist.current; + } else { + mylist.last->next = mylist.current; + mylist.current->next = NULL; + mylist.last = mylist.current; + } +} + +/* + Main grouping function + Algorithm: + 1. pass on every Voltaire node + 2. catch spine chip for every Voltaire node + 2.1 build/interpolate chassis around this chip + 2.2 go to 1. + 3. pass on non Voltaire nodes (SystemImageGUID based grouping) + 4. now group non Voltaire nodes by SystemImageGUID +*/ +ChassisList *group_nodes() +{ + Node *node; + int dist; + int chassisnum = 0; + struct ChassisList *chassis; + + mylist.first = NULL; + mylist.current = NULL; + mylist.last = NULL; + + /* first pass on switches and build for every Voltaire node */ + /* an appropriate chassis record (slotnum and position) */ + /* according to internal connectivity */ + /* not very efficient but clear code so... */ + for (dist = 0; dist <= maxhops_discovered; dist++) { + for (node = nodesdist[dist]; node; node = node->dnext) { + if (node->vendid == VTR_VENDOR_ID) + fill_chassis_record(node); + } + } + + /* separate every Voltaire chassis from each other and build linked list of them */ + /* algorithm: catch spine and find all surrounding nodes */ + for (dist = 0; dist <= maxhops_discovered; dist++) { + for (node = nodesdist[dist]; node; node = node->dnext) { + if (node->vendid != VTR_VENDOR_ID) + continue; + if (!node->chrecord || node->chrecord->chassisnum || !is_spine(node)) + continue; + add_chassislist(); + mylist.current->chassisnum = ++chassisnum; + build_chassis(node, mylist.current); + } + } + + /* now make pass on nodes for chassis which are not Voltaire */ + /* grouped by common SystemImageGUID */ + for (dist = 0; dist <= maxhops_discovered; dist++) { + for (node = nodesdist[dist]; node; node = node->dnext) { + if (node->vendid == VTR_VENDOR_ID) + continue; + if (node->sysimgguid) { + chassis = find_chassisguid(node); + if (chassis) + chassis->nodecount++; + else { + /* Possible new chassis */ + add_chassislist(); + mylist.current->chassisguid = get_chassisguid(node); + mylist.current->nodecount = 1; + } + } + } + } + + /* now, make another pass to see which nodes are part of chassis */ + /* (defined as chassis->nodecount > 1) */ + for (dist = 0; dist <= MAXHOPS; ) { + for (node = nodesdist[dist]; node; node = node->dnext) { + if (node->vendid == VTR_VENDOR_ID) + continue; + if (node->sysimgguid) { + chassis = find_chassisguid(node); + if (chassis && chassis->nodecount > 1) { + if (!chassis->chassisnum) + chassis->chassisnum = ++chassisnum; + if (!node->chrecord) { + if (!(node->chrecord = calloc(1, sizeof(ChassisRecord)))) + IBPANIC("out of mem"); + node->chrecord->chassisnum = chassis->chassisnum; + } + } + } + } + if (dist == maxhops_discovered) + dist = MAXHOPS; /* skip to CAs */ + else + dist++; + } + + return (mylist.first); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/ibaddr.c b/branches/winverbs/tools/infiniband_diags/src/ibaddr.c new file mode 100644 index 00000000..65e03080 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibaddr.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2004-2008 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. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#if defined(_WIN32) +#include +#include +#include +#include "..\..\..\..\etc\user\getopt.c" +#else +#include +#include +#include +#include +#endif + +#include +#include + +#include "ibdiag_common.h" + +char *argv0 = "ibaddr"; + +static int +ib_resolve_addr(ib_portid_t *portid, int portnum, int show_lid, int show_gid) +{ + char gid_str[INET6_ADDRSTRLEN]; + uint8_t portinfo[64]; + uint8_t nodeinfo[64]; + uint64_t guid, prefix; + ibmad_gid_t gid; + int lmc; + + if (!smp_query(nodeinfo, portid, IB_ATTR_NODE_INFO, 0, 0)) + return -1; + + if (!smp_query(portinfo, portid, IB_ATTR_PORT_INFO, portnum, 0)) + return -1; + + mad_decode_field(portinfo, IB_PORT_LID_F, &portid->lid); + mad_decode_field(portinfo, IB_PORT_GID_PREFIX_F, &prefix); + mad_decode_field(portinfo, IB_PORT_LMC_F, &lmc); + mad_decode_field(nodeinfo, IB_NODE_PORT_GUID_F, &guid); + + mad_encode_field(gid, IB_GID_PREFIX_F, &prefix); + mad_encode_field(gid, IB_GID_GUID_F, &guid); + + if (show_gid) { + printf("GID %s ", inet_ntop(AF_INET6, gid, gid_str, + sizeof gid_str)); + } + + if (show_lid > 0) + printf("LID start 0x%x end 0x%x", portid->lid, portid->lid + (1 << lmc) - 1); + else if (show_lid < 0) + printf("LID start %d end %d", portid->lid, portid->lid + (1 << lmc) - 1); + printf("\n"); + return 0; +} + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -D(irect) -G(uid) -l(id_show) -g(id_show) -s(m_port) sm_lid -C ca_name -P ca_port " + "-t(imeout) timeout_ms -V(ersion) -h(elp)] []\n", + basename); + fprintf(stderr, "\tExamples:\n"); + fprintf(stderr, "\t\t%s\t\t\t# local port's address\n", basename); + fprintf(stderr, "\t\t%s 32\t\t# show lid range and gid of lid 32\n", basename); + fprintf(stderr, "\t\t%s -G 0x8f1040023\t# same but using guid address\n", basename); + fprintf(stderr, "\t\t%s -l 32\t\t# show lid range only\n", basename); + fprintf(stderr, "\t\t%s -L 32\t\t# show decimal lid range only\n", basename); + fprintf(stderr, "\t\t%s -g 32\t\t# show gid address only\n", basename); + exit(-1); +} + +int __cdecl +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + ib_portid_t portid = {0}; + extern int ibdebug; + int dest_type = IB_DEST_LID; + int timeout = 0; /* use default */ + int show_lid = 0, show_gid = 0; + int port = 0; + char *ca = 0; + int ca_port = 0; + + static char str_opts[] = "C:P:t:s:dDGglLVhu"; + static struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "Direct", 0, 0, 'D'}, + { "Guid", 0, 0, 'G'}, + { "gid_show", 0, 0, 'g'}, + { "lid_show", 0, 0, 'l'}, + { "Lid_show", 0, 0, 'L'}, + { "timeout", 1, 0, 't'}, + { "sm_port", 1, 0, 's'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { 0 } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'g': + show_gid++; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'l': + show_lid++; + break; + case 'L': + show_lid = -100; + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + port = strtoul(argv[1], 0, 0); + + if (!show_lid && !show_gid) + show_lid = show_gid = 1; + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (argc) { + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_self(&portid, &port, 0) < 0) + IBERROR("can't resolve self port %s", argv[0]); + } + + if (ib_resolve_addr(&portid, port, show_lid, show_gid) < 0) + IBERROR("can't resolve requested address"); + exit(0); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/ibaddr/SOURCES b/branches/winverbs/tools/infiniband_diags/src/ibaddr/SOURCES new file mode 100644 index 00000000..cbaf51c1 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibaddr/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibaddr +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = ..\ibaddr.c ..\ibdiag_common.c + +INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + diff --git a/branches/winverbs/tools/infiniband_diags/src/ibdiag_common.c b/branches/winverbs/tools/infiniband_diags/src/ibdiag_common.c new file mode 100644 index 00000000..a78e4e12 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibdiag_common.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006-2007 The Regents of the University of California. + * Copyright (c) 2004-2006 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. + * + */ + +/** + * Define common functions which can be included in the various C based diags. + */ + +#include +#include + +#if defined(_WIN32) || defined(_WIN64) +#include +#include +#include +#if !defined(getpid) + #define getpid GetCurrentProcessId +#endif +#else +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "ibdiag_common.h" + +int ibdebug; + +void +iberror(const char *fn, char *msg, ...) +{ + char buf[512], *s; + va_list va; + int n; + + va_start(va, msg); + n = vsprintf(buf, msg, va); + va_end(va); + buf[n] = 0; + + if ((s = strrchr(argv0, '/'))) + argv0 = s + 1; + + if (ibdebug) + printf("%s: iberror: [pid %d] %s: failed: %s\n", argv0, getpid(), fn, buf); + else + printf("%s: iberror: failed: %s\n", argv0, buf); + + exit(-1); +} + diff --git a/branches/winverbs/tools/infiniband_diags/src/ibnetdiscover.c b/branches/winverbs/tools/infiniband_diags/src/ibnetdiscover.c new file mode 100644 index 00000000..faf89ece --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibnetdiscover.c @@ -0,0 +1,1051 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems 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. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ibnetdiscover.h" +#include "grouping.h" +#include "ibdiag_common.h" + +static char *node_type_str[] = { + "???", + "ca", + "switch", + "router", + "iwarp rnic" +}; + +static char *linkwidth_str[] = { + "??", + "1x", + "4x", + "??", + "8x", + "??", + "??", + "??", + "12x" +}; + +static char *linkspeed_str[] = { + "???", + "SDR", + "DDR", + "???", + "QDR" +}; + +static int timeout = 2000; /* ms */ +static int dumplevel = 0; +static int verbose; +static FILE *f; + +char *argv0 = "ibnetdiscover"; + +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; + +Node *nodesdist[MAXHOPS+1]; /* last is Ca list */ +Node *mynode; +int maxhops_discovered = 0; + +struct ChassisList *chassis = NULL; + +static char * +get_linkwidth_str(int linkwidth) +{ + if (linkwidth > 8) + return linkwidth_str[0]; + else + return linkwidth_str[linkwidth]; +} + +static char * +get_linkspeed_str(int linkspeed) +{ + if (linkspeed > 4) + return linkspeed_str[0]; + else + return linkspeed_str[linkspeed]; +} + +static inline const char* +node_type_str2(Node *node) +{ + switch(node->type) { + case SWITCH_NODE: return "SW"; + case CA_NODE: return "CA"; + case ROUTER_NODE: return "RT"; + } + return "??"; +} + +void +decode_port_info(void *pi, Port *port) +{ + 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); + mad_decode_field(pi, IB_PORT_LINK_WIDTH_ACTIVE_F, &port->linkwidth); + mad_decode_field(pi, IB_PORT_LINK_SPEED_ACTIVE_F, &port->linkspeed); +} + + +int +get_port(Port *port, int portnum, ib_portid_t *portid) +{ + char portinfo[64]; + void *pi = portinfo; + + port->portnum = portnum; + + if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout)) + return -1; + decode_port_info(pi, port); + + DEBUG("portid %s portnum %d: lid %d state %d physstate %d %s %s", + portid2str(portid), portnum, port->lid, port->state, port->physstate, get_linkwidth_str(port->linkwidth), get_linkspeed_str(port->linkspeed)); + return 1; +} +/* + * Returns 0 if non switch node is found, 1 if switch is found, -1 if error. + */ +int +get_node(Node *node, Port *port, ib_portid_t *portid) +{ + char portinfo[64]; + char switchinfo[64]; + void *pi = portinfo, *ni = node->nodeinfo, *nd = node->nodedesc; + void *si = switchinfo; + + if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, timeout)) + 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_DEVID_F, &node->devid); + mad_decode_field(ni, IB_NODE_VENDORID_F, &node->vendid); + mad_decode_field(ni, IB_NODE_SYSTEM_GUID_F, &node->sysimgguid); + mad_decode_field(ni, IB_NODE_PORT_GUID_F, &node->portguid); + mad_decode_field(ni, IB_NODE_LOCAL_PORT_F, &node->localport); + port->portnum = node->localport; + port->portguid = node->portguid; + + if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, timeout)) + return -1; + + if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, 0, timeout)) + return -1; + decode_port_info(pi, port); + + if (node->type != SWITCH_NODE) + return 0; + + node->smalid = port->lid; + node->smalmc = port->lmc; + + /* after we have the sma information find out the real PortInfo for this port */ + if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, node->localport, timeout)) + return -1; + decode_port_info(pi, port); + + if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout)) + node->smaenhsp0 = 0; /* assume base SP0 */ + else + mad_decode_field(si, IB_SW_ENHANCED_PORT0_F, &node->smaenhsp0); + + DEBUG("portid %s: got switch node %" PRIx64 " '%s'", + portid2str(portid), node->nodeguid, node->nodedesc); + return 1; +} + +static int +extend_dpath(ib_dr_path_t *path, int nextport) +{ + if (path->cnt+2 >= sizeof(path->p)) + return -1; + ++path->cnt; + if (path->cnt > maxhops_discovered) + maxhops_discovered = path->cnt; + path->p[path->cnt] = nextport; + return path->cnt; +} + +static void +dump_endnode(ib_portid_t *path, char *prompt, Node *node, Port *port) +{ + if (!dumplevel) + return; + + fprintf(f, "%s -> %s %s {%016" PRIx64 "} portnum %d lid %d-%d\"%s\"\n", + portid2str(path), prompt, + (node->type <= IB_NODE_MAX ? node_type_str[node->type] : "???"), + node->nodeguid, node->type == SWITCH_NODE ? 0 : port->portnum, + port->lid, port->lid + (1 << port->lmc) - 1, + clean_nodedesc(node->nodedesc)); +} + +#define HASHGUID(guid) ((uint32_t)(((uint32_t)(guid) * 101) ^ ((uint32_t)((guid) >> 32) * 103))) +#define HTSZ 137 + +static Node *nodestbl[HTSZ]; + +static Node * +find_node(Node *new) +{ + int hash = HASHGUID(new->nodeguid) % HTSZ; + Node *node; + + for (node = nodestbl[hash]; node; node = node->htnext) + if (node->nodeguid == new->nodeguid) + return node; + + return NULL; +} + +static Node * +create_node(Node *temp, ib_portid_t *path, int dist) +{ + Node *node; + int hash = HASHGUID(temp->nodeguid) % HTSZ; + + node = malloc(sizeof(*node)); + if (!node) + return NULL; + + memcpy(node, temp, sizeof(*node)); + node->dist = dist; + node->path = *path; + + node->htnext = nodestbl[hash]; + nodestbl[hash] = node; + + if (node->type != SWITCH_NODE) + dist = MAXHOPS; /* special Ca list */ + + node->dnext = nodesdist[dist]; + nodesdist[dist] = node; + + return node; +} + +static Port * +find_port(Node *node, Port *port) +{ + Port *old; + + for (old = node->ports; old; old = old->next) + if (old->portnum == port->portnum) + return old; + + return NULL; +} + +static Port * +create_port(Node *node, Port *temp) +{ + Port *port; + + port = malloc(sizeof(*port)); + if (!port) + return NULL; + + memcpy(port, temp, sizeof(*port)); + port->node = node; + port->next = node->ports; + node->ports = port; + + return port; +} + +static void +link_ports(Node *node, Port *port, Node *remotenode, Port *remoteport) +{ + DEBUG("linking: 0x%" PRIx64 " %p->%p:%u and 0x%" PRIx64 " %p->%p:%u", + node->nodeguid, node, port, port->portnum, + remotenode->nodeguid, remotenode, remoteport, remoteport->portnum); + if (port->remoteport) + port->remoteport->remoteport = NULL; + if (remoteport->remoteport) + remoteport->remoteport->remoteport = NULL; + port->remoteport = remoteport; + remoteport->remoteport = port; +} + +static int +handle_port(Node *node, Port *port, ib_portid_t *path, int portnum, int dist) +{ + Node node_buf; + Port port_buf; + Node *remotenode, *oldnode; + Port *remoteport, *oldport; + + memset(&node_buf, 0, sizeof(node_buf)); + memset(&port_buf, 0, sizeof(port_buf)); + + DEBUG("handle node %p port %p:%d dist %d", node, port, portnum, dist); + if (port->physstate != 5) /* LinkUp */ + return -1; + + if (extend_dpath(&path->drpath, portnum) < 0) + return -1; + + if (get_node(&node_buf, &port_buf, path) < 0) { + IBWARN("NodeInfo on %s failed, skipping port", + portid2str(path)); + path->drpath.cnt--; /* restore path */ + return -1; + } + + oldnode = find_node(&node_buf); + if (oldnode) + remotenode = oldnode; + else if (!(remotenode = create_node(&node_buf, path, dist + 1))) + IBERROR("no memory"); + + oldport = find_port(remotenode, &port_buf); + if (oldport) { + remoteport = oldport; + if (node != remotenode || port != remoteport) + IBWARN("port moving..."); + } else if (!(remoteport = create_port(remotenode, &port_buf))) + IBERROR("no memory"); + + dump_endnode(path, oldnode ? "known remote" : "new remote", + remotenode, remoteport); + + link_ports(node, port, remotenode, remoteport); + + path->drpath.cnt--; /* restore path */ + return 0; +} + +/* + * Return 1 if found, 0 if not, -1 on errors. + */ +static int +discover(ib_portid_t *from) +{ + Node node_buf; + Port port_buf; + Node *node; + Port *port; + int i; + int dist = 0; + ib_portid_t *path; + + DEBUG("from %s", portid2str(from)); + + memset(&node_buf, 0, sizeof(node_buf)); + memset(&port_buf, 0, sizeof(port_buf)); + + if (get_node(&node_buf, &port_buf, from) < 0) { + IBWARN("can't reach node %s", portid2str(from)); + return -1; + } + + node = create_node(&node_buf, from, 0); + if (!node) + IBERROR("out of memory"); + + mynode = node; + + port = create_port(node, &port_buf); + if (!port) + IBERROR("out of memory"); + + if (node->type != SWITCH_NODE && + handle_port(node, port, from, node->localport, 0) < 0) + return 0; + + for (dist = 0; dist < MAXHOPS; dist++) { + + for (node = nodesdist[dist]; node; node = node->dnext) { + + path = &node->path; + + DEBUG("dist %d node %p", dist, node); + dump_endnode(path, "processing", node, port); + + for (i = 1; i <= node->numports; i++) { + if (i == node->localport) + continue; + + if (get_port(&port_buf, i, path) < 0) { + IBWARN("can't reach node %s port %d", portid2str(path), i); + continue; + } + + port = find_port(node, &port_buf); + if (port) + continue; + + port = create_port(node, &port_buf); + if (!port) + IBERROR("out of memory"); + + /* If switch, set port GUID to node GUID */ + if (node->type == SWITCH_NODE) + port->portguid = node->portguid; + + handle_port(node, port, path, i, dist); + } + } + } + + return 0; +} + +char * +node_name(Node *node) +{ + static char buf[256]; + + switch(node->type) { + case SWITCH_NODE: + sprintf(buf, "\"%s", "S"); + break; + case CA_NODE: + sprintf(buf, "\"%s", "H"); + break; + case ROUTER_NODE: + sprintf(buf, "\"%s", "R"); + break; + default: + sprintf(buf, "\"%s", "?"); + break; + } + sprintf(buf+2, "-%016" PRIx64 "\"", node->nodeguid); + + return buf; +} + +void +list_node(Node *node) +{ + char *node_type; + char *nodename = remap_node_name(node_name_map, node->nodeguid, + node->nodedesc); + + switch(node->type) { + case SWITCH_NODE: + node_type = "Switch"; + break; + case CA_NODE: + node_type = "Ca"; + break; + case ROUTER_NODE: + 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->nodeguid, node->numports, node->devid, node->vendid, + nodename); + + free(nodename); +} + +void +out_ids(Node *node, int group, char *chname) +{ + fprintf(f, "\nvendid=0x%x\ndevid=0x%x\n", node->vendid, node->devid); + if (node->sysimgguid) + fprintf(f, "sysimgguid=0x%" PRIx64, node->sysimgguid); + if (group + && node->chrecord && node->chrecord->chassisnum) { + fprintf(f, "\t\t# Chassis %d", node->chrecord->chassisnum); + if (chname) + fprintf(f, " (%s)", chname); + if (is_xsigo_tca(node->nodeguid) && node->ports->remoteport) + fprintf(f, " slot %d", node->ports->remoteport->portnum); + } + fprintf(f, "\n"); +} + +uint64_t +out_chassis(int chassisnum) +{ + uint64_t guid; + + fprintf(f, "\nChassis %d", chassisnum); + guid = get_chassis_guid(chassisnum); + if (guid) + fprintf(f, " (guid 0x%" PRIx64 ")", guid); + fprintf(f, "\n"); + return guid; +} + +void +out_switch(Node *node, int group, char *chname) +{ + char *str; + char *nodename = NULL; + + out_ids(node, group, chname); + fprintf(f, "switchguid=0x%" PRIx64, node->nodeguid); + fprintf(f, "(%" PRIx64 ")", node->portguid); + /* Currently, only if Voltaire chassis */ + if (group + && node->chrecord && node->chrecord->chassisnum + && node->vendid == VTR_VENDOR_ID) { + str = get_chassis_type(node->chrecord->chassistype); + if (str) + fprintf(f, "%s ", str); + str = get_chassis_slot(node->chrecord->chassisslot); + if (str) + fprintf(f, "%s ", str); + fprintf(f, "%d Chip %d", node->chrecord->slotnum, node->chrecord->anafanum); + } + + nodename = remap_node_name(node_name_map, node->nodeguid, + node->nodedesc); + + fprintf(f, "\nSwitch\t%d %s\t\t# \"%s\" %s port 0 lid %d lmc %d\n", + node->numports, node_name(node), + nodename, + node->smaenhsp0 ? "enhanced" : "base", + node->smalid, node->smalmc); + + free(nodename); +} + +void +out_ca(Node *node, int group, char *chname) +{ + char *node_type; + char *node_type2; + char *nodename = remap_node_name(node_name_map, node->nodeguid, + node->nodedesc); + + out_ids(node, group, chname); + switch(node->type) { + case CA_NODE: + node_type = "ca"; + node_type2 = "Ca"; + break; + case ROUTER_NODE: + node_type = "rt"; + node_type2 = "Rt"; + break; + default: + node_type = "???"; + node_type2 = "???"; + break; + } + + fprintf(f, "%sguid=0x%" PRIx64 "\n", node_type, node->nodeguid); + fprintf(f, "%s\t%d %s\t\t# \"%s\"", + node_type2, node->numports, node_name(node), + nodename); + if (group && is_xsigo_hca(node->nodeguid)) + fprintf(f, " (scp)"); + fprintf(f, "\n"); + + free(nodename); +} + +static char * +out_ext_port(Port *port, int group) +{ + char *str = NULL; + + /* Currently, only if Voltaire chassis */ + if (group + && port->node->chrecord && port->node->vendid == VTR_VENDOR_ID) + str = portmapstring(port); + + return (str); +} + +void +out_switch_port(Port *port, int group) +{ + char *ext_port_str = NULL; + char *rem_nodename = NULL; + + DEBUG("port %p:%d remoteport %p", port, port->portnum, port->remoteport); + fprintf(f, "[%d]", 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->nodeguid, + port->remoteport->node->nodedesc); + + ext_port_str = out_ext_port(port->remoteport, group); + 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 != SWITCH_NODE) + fprintf(f, "(%" PRIx64 ") ", port->remoteport->portguid); + fprintf(f, "\t\t# \"%s\" lid %d %s%s", + rem_nodename, + port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid, + get_linkwidth_str(port->linkwidth), + get_linkspeed_str(port->linkspeed)); + + if (is_xsigo_tca(port->remoteport->portguid)) + fprintf(f, " slot %d", port->portnum); + else if (is_xsigo_hca(port->remoteport->portguid)) + fprintf(f, " (scp)"); + fprintf(f, "\n"); + + free(rem_nodename); +} + +void +out_ca_port(Port *port, int group) +{ + char *str = NULL; + char *rem_nodename = NULL; + + fprintf(f, "[%d]", port->portnum); + if (port->node->type != SWITCH_NODE) + fprintf(f, "(%" PRIx64 ") ", port->portguid); + 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 != SWITCH_NODE) + fprintf(f, " (%" PRIx64 ") ", port->remoteport->portguid); + + rem_nodename = remap_node_name(node_name_map, + port->remoteport->node->nodeguid, + port->remoteport->node->nodedesc); + + fprintf(f, "\t\t# lid %d lmc %d \"%s\" lid %d %s%s\n", + port->lid, port->lmc, rem_nodename, + port->remoteport->node->type == SWITCH_NODE ? port->remoteport->node->smalid : port->remoteport->lid, + get_linkwidth_str(port->linkwidth), + get_linkspeed_str(port->linkspeed)); + + free(rem_nodename); +} + +int +dump_topology(int listtype, int group) +{ + Node *node; + Port *port; + int i = 0, dist = 0; + time_t t = time(0); + uint64_t chguid; + char *chname = NULL; + + if (!listtype) { + fprintf(f, "#\n# Topology file: generated on %s#\n", ctime(&t)); + fprintf(f, "# Max of %d hops discovered\n", maxhops_discovered); + fprintf(f, "# Initiated from node %016" PRIx64 " port %016" PRIx64 "\n", mynode->nodeguid, mynode->portguid); + } + + /* Make pass on switches */ + if (group && !listtype) { + ChassisList *ch = NULL; + + /* Chassis based switches first */ + for (ch = chassis; ch; ch = ch->next) { + int n = 0; + + if (!ch->chassisnum) + continue; + chguid = out_chassis(ch->chassisnum); + if (chname) + free(chname); + chname = NULL; + if (is_xsigo_guid(chguid)) { + for (node = nodesdist[MAXHOPS]; node; node = node->dnext) { + if (!node->chrecord || + !node->chrecord->chassisnum) + continue; + + if (node->chrecord->chassisnum != ch->chassisnum) + continue; + + if (is_xsigo_hca(node->nodeguid)) { + chname = remap_node_name(node_name_map, + node->nodeguid, + node->nodedesc); + fprintf(f, "Hostname: %s\n", chname); + } + } + } + + fprintf(f, "\n# Spine Nodes"); + for (n = 1; n <= (SPINES_MAX_NUM+1); n++) { + if (ch->spinenode[n]) { + out_switch(ch->spinenode[n], group, chname); + for (port = ch->spinenode[n]->ports; port; port = port->next, i++) + if (port->remoteport) + out_switch_port(port, group); + } + } + fprintf(f, "\n# Line Nodes"); + for (n = 1; n <= (LINES_MAX_NUM+1); n++) { + if (ch->linenode[n]) { + out_switch(ch->linenode[n], group, chname); + for (port = ch->linenode[n]->ports; port; port = port->next, i++) + if (port->remoteport) + out_switch_port(port, group); + } + } + + fprintf(f, "\n# Chassis Switches"); + for (dist = 0; dist <= maxhops_discovered; dist++) { + + for (node = nodesdist[dist]; node; node = node->dnext) { + + /* Non Voltaire chassis */ + if (node->vendid == VTR_VENDOR_ID) + continue; + if (!node->chrecord || + !node->chrecord->chassisnum) + continue; + + if (node->chrecord->chassisnum != ch->chassisnum) + continue; + + out_switch(node, group, chname); + for (port = node->ports; port; port = port->next, i++) + if (port->remoteport) + out_switch_port(port, group); + + } + + } + + fprintf(f, "\n# Chassis CAs"); + for (node = nodesdist[MAXHOPS]; node; node = node->dnext) { + if (!node->chrecord || + !node->chrecord->chassisnum) + continue; + + if (node->chrecord->chassisnum != ch->chassisnum) + continue; + + out_ca(node, group, chname); + for (port = node->ports; port; port = port->next, i++) + if (port->remoteport) + out_ca_port(port, group); + + } + + } + + } else { + for (dist = 0; dist <= maxhops_discovered; dist++) { + + for (node = nodesdist[dist]; node; node = node->dnext) { + + DEBUG("SWITCH: dist %d node %p", dist, node); + if (!listtype) + out_switch(node, group, chname); + else { + if (listtype & LIST_SWITCH_NODE) + list_node(node); + continue; + } + + for (port = node->ports; port; port = port->next, i++) + if (port->remoteport) + out_switch_port(port, group); + } + } + } + + if (chname) + free(chname); + chname = NULL; + if (group && !listtype) { + + fprintf(f, "\nNon-Chassis Nodes\n"); + + for (dist = 0; dist <= maxhops_discovered; dist++) { + + for (node = nodesdist[dist]; node; node = node->dnext) { + + DEBUG("SWITCH: dist %d node %p", dist, node); + /* Now, skip chassis based switches */ + if (node->chrecord && + node->chrecord->chassisnum) + continue; + out_switch(node, group, chname); + + for (port = node->ports; port; port = port->next, i++) + if (port->remoteport) + out_switch_port(port, group); + } + + } + + } + + /* Make pass on CAs */ + for (node = nodesdist[MAXHOPS]; node; node = node->dnext) { + + DEBUG("CA: dist %d node %p", dist, node); + if (!listtype) { + /* Now, skip chassis based CAs */ + if (group && node->chrecord && + node->chrecord->chassisnum) + continue; + out_ca(node, group, chname); + } else { + if (((listtype & LIST_CA_NODE) && (node->type == CA_NODE)) || + ((listtype & LIST_ROUTER_NODE) && (node->type == ROUTER_NODE))) + list_node(node); + continue; + } + + for (port = node->ports; port; port = port->next, i++) + if (port->remoteport) + out_ca_port(port, group); + } + + if (chname) + free(chname); + + return i; +} + +void dump_ports_report () +{ + int b, n = 0, p; + Node *node; + Port *port; + + // If switch and LID == 0, search of other switch ports with + // valid LID and assign it to all ports of that switch + for (b = 0; b <= MAXHOPS; b++) + for (node = nodesdist[b]; node; node = node->dnext) + if (node->type == SWITCH_NODE) { + int swlid = 0; + for (p = 0, port = node->ports; + p < node->numports && port && !swlid; + port = port->next) + if (port->lid != 0) + swlid = port->lid; + for (p = 0, port = node->ports; + p < node->numports && port; + port = port->next) + port->lid = swlid; + } + + for (b = 0; b <= MAXHOPS; b++) + for (node = nodesdist[b]; node; node = node->dnext) { + for (p = 0, port = node->ports; + p < node->numports && port; + p++, port = port->next) { + fprintf(stdout, + "%2s %5d %2d 0x%016" PRIx64 " %s %s", + node_type_str2(port->node), port->lid, + port->portnum, + port->portguid, + get_linkwidth_str(port->linkwidth), + get_linkspeed_str(port->linkspeed)); + if (port->remoteport) + fprintf(stdout, + " - %2s %5d %2d 0x%016" PRIx64 + " ( '%s' - '%s' )\n", + node_type_str2(port->remoteport->node), + port->remoteport->lid, + port->remoteport->portnum, + port->remoteport->portguid, + port->node->nodedesc, + port->remoteport->node->nodedesc); + else + fprintf(stdout, "%36s'%s'\n", "", + port->node->nodedesc); + } + n++; + } +} + +void +usage(void) +{ + fprintf(stderr, "Usage: %s [-d(ebug)] -e(rr_show) -v(erbose) -s(how) -l(ist) -g(rouping) -H(ca_list) -S(witch_list) -R(outer_list) -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms --node-name-map node-name-map] -p(orts) []\n", + argv0); + fprintf(stderr, " --node-name-map specify a node name map file\n"); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS}; + ib_portid_t my_portid = {0}; + int udebug = 0, list = 0; + char *ca = 0; + int ca_port = 0; + int group = 0; + int ports_report = 0; + + static char const str_opts[] = "C:P:t:devslgHSRpVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "verbose", 0, 0, 'v'}, + { "show", 0, 0, 's'}, + { "list", 0, 0, 'l'}, + { "grouping", 0, 0, 'g'}, + { "Hca_list", 0, 0, 'H'}, + { "Switch_list", 0, 0, 'S'}, + { "Router_list", 0, 0, 'R'}, + { "timeout", 1, 0, 't'}, + { "node-name-map", 1, 0, 1}, + { "ports", 0, 0, 'p'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + f = stdout; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + break; + case 'v': + verbose++; + dumplevel++; + break; + case 's': + dumplevel = 1; + break; + case 'e': + madrpc_show_errors(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 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + case 'p': + ports_report = 1; + break; + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc && !(f = fopen(argv[0], "w"))) + IBERROR("can't open file %s for writing", argv[0]); + + madrpc_init(ca, ca_port, mgmt_classes, 2); + node_name_map = open_node_name_map(node_name_map_file); + + if (discover(&my_portid) < 0) + IBERROR("discover"); + + if (group) + chassis = group_nodes(); + + if (ports_report) + dump_ports_report(); + else + dump_topology(list, group); + + close_node_name_map(node_name_map); + exit(0); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/ibnetdiscover/SOURCES b/branches/winverbs/tools/infiniband_diags/src/ibnetdiscover/SOURCES new file mode 100644 index 00000000..849db8e0 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibnetdiscover/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibnetdiscover +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = ..\ibnetdiscover.c ..\ibdiag_common.c + +INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + diff --git a/branches/winverbs/tools/infiniband_diags/src/ibping.c b/branches/winverbs/tools/infiniband_diags/src/ibping.c new file mode 100644 index 00000000..767436b5 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibping.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2004-2008 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. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#if defined(_WIN32) +#include +#include +#include +#include "..\..\..\..\etc\user\getopt.c" +#else +#include +#include +#include +#include +#include +#include +#endif + +#include +#include + +#include "ibdiag_common.h" + +#undef DEBUG +#define DEBUG if (verbose) IBWARN + +static int dest_type = IB_DEST_LID; +static int verbose; +static char host_and_domain[IB_VENDOR_RANGE2_DATA_SIZE]; +static char last_host[IB_VENDOR_RANGE2_DATA_SIZE]; + +char *argv0 = "ibping"; + +static void +get_host_and_domain(char *data, int sz) +{ + char *s = data; + int n; + + if (gethostname(s, sz) < 0) + snprintf(s, sz, "?hostname?"); + + s[sz-1] = 0; + if ((n = strlen(s)) >= sz) + return; + s[n] = '.'; + s += n + 1; + sz -= n + 1; + + if (getdomainname(s, sz) < 0) + snprintf(s, sz, "?domainname?"); + if (strlen(s) == 0) + s[-1] = 0; /* no domain */ +} + +static char * +ibping_serv(void) +{ + void *umad; + void *mad; + char *data; + + DEBUG("starting to serve..."); + + while ((umad = mad_receive(0, -1))) { + + mad = umad_get_mad(umad); + data = (char *)mad + IB_VENDOR_RANGE2_DATA_OFFS; + + memcpy(data, host_and_domain, IB_VENDOR_RANGE2_DATA_SIZE); + + DEBUG("Pong: %s", data); + + if (mad_respond(umad, 0, 0) < 0) + DEBUG("respond failed"); + + mad_free(umad); + } + + DEBUG("server out"); + return 0; +} + +static uint64_t +ibping(ib_portid_t *portid, int quiet) +{ + char data[IB_VENDOR_RANGE2_DATA_SIZE] = {0}; + ib_vendor_call_t call; + uint64_t start, rtt; + + DEBUG("Ping.."); + + start = getcurrenttime(); + + call.method = IB_MAD_METHOD_GET; + call.mgmt_class = IB_VENDOR_OPENIB_PING_CLASS; + call.attrid = 0; + call.mod = 0; + call.oui = IB_OPENIB_OUI; + call.timeout = 0; + memset(&call.rmpp, 0, sizeof call.rmpp); + + if (!ib_vendor_call(data, portid, &call)) + return ~0llu; + + rtt = getcurrenttime() - start; + + if (!last_host[0]) + memcpy(last_host, data, sizeof last_host); + + if (!quiet) + printf("Pong from %s (%s): time %" PRIu64 ".%03" PRIu64 " ms\n", + data, portid2str(portid), rtt/1000, rtt%1000); + + return rtt; +} + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms -c ping_count -f(lood) -o oui -S(erver)] \n", + basename); + exit(-1); +} + +static uint64_t minrtt = ~0ull, maxrtt, total_rtt; +static uint64_t start, total_time, replied, lost, ntrans; +static ib_portid_t portid = {0}; + +void +report(int sig) +{ + total_time = getcurrenttime() - start; + + DEBUG("out due signal %d", sig); + + printf("\n--- %s (%s) ibping statistics ---\n", last_host, portid2str(&portid)); + printf("%" PRIu64 " packets transmitted, %" PRIu64 " received, %" PRIu64 "%% packet loss, time %" PRIu64 " ms\n", + ntrans, replied, + (lost != 0) ? lost * 100 / ntrans : 0, total_time / 1000); + printf("rtt min/avg/max = %" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" PRIu64 "/%" PRIu64 ".%03" PRIu64 " ms\n", + minrtt == ~0ull ? 0 : minrtt/1000, + minrtt == ~0ull ? 0 : minrtt%1000, + replied ? total_rtt/replied/1000 : 0, + replied ? (total_rtt/replied)%1000 : 0, + maxrtt/1000, maxrtt%1000); + + exit(0); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + int ping_class = IB_VENDOR_OPENIB_PING_CLASS; + ib_portid_t *sm_id = 0, sm_portid = {0}; + int timeout = 0, udebug = 0, server = 0, flood = 0; + int oui = IB_OPENIB_OUI; + uint64_t rtt; + uint count = ~0; + extern int ibdebug; + char *err; + char *ca = 0; + int ca_port = 0; + + static char str_opts[] = "C:P:t:s:c:o:devGfSVhu"; + static struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "verbose", 0, 0, 'v'}, + { "Guid", 0, 0, 'G'}, + { "s", 1, 0, 's'}, + { "timeout", 1, 0, 't'}, + { "c", 1, 0, 'c'}, + { "flood", 0, 0, 'f'}, + { "o", 1, 0, 'o'}, + { "Server", 0, 0, 'S'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { 0 } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'c': + count = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'f': + flood++; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'o': + oui = strtoul(optarg, 0, 0); + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 'S': + server++; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (!argc && !server) + usage(); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (server) { + if (mad_register_server(ping_class, 0, 0, oui) < 0) + IBERROR("can't serve class %d on this port", ping_class); + + get_host_and_domain(host_and_domain, sizeof host_and_domain); + + if ((err = ibping_serv())) + IBERROR("ibping to %s: %s", portid2str(&portid), err); + exit(0); + } + + if (mad_register_client(ping_class, 0) < 0) + IBERROR("can't register ping class %d on this port", ping_class); + + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + + signal(SIGINT, report); + signal(SIGTERM, report); + + start = getcurrenttime(); + + while (count-- > 0) { + ntrans++; + if ((rtt = ibping(&portid, flood)) == ~0ull) { + DEBUG("ibping to %s failed", portid2str(&portid)); + lost++; + } else { + if (rtt < minrtt) + minrtt = rtt; + if (rtt > maxrtt) + maxrtt = rtt; + total_rtt += rtt; + replied++; + } + + if (!flood) + sleep(1); + } + + report(0); + + exit(-1); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/ibping/SOURCES b/branches/winverbs/tools/infiniband_diags/src/ibping/SOURCES new file mode 100644 index 00000000..0d9d8964 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibping/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = ibping +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = ..\ibping.c ..\ibdiag_common.c + +INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + diff --git a/branches/winverbs/tools/infiniband_diags/src/ibportstate.c b/branches/winverbs/tools/infiniband_diags/src/ibportstate.c new file mode 100644 index 00000000..07d7a013 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibportstate.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2004-2008 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. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +#undef DEBUG +#define DEBUG if (verbose>1) IBWARN + +static int dest_type = IB_DEST_LID; +static int verbose; + +char *argv0 = "ibportstate"; + +/*******************************************/ + +static int +get_node_info(ib_portid_t *dest, uint8_t *data) +{ + int node_type; + + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return -1; + + node_type = mad_get_field(data, 0, IB_NODE_TYPE_F); + if (node_type == IB_NODE_SWITCH) /* Switch NodeType ? */ + return 0; + else + return 1; +} + +static int +get_port_info(ib_portid_t *dest, uint8_t *data, int portnum, int port_op) +{ + char buf[2048]; + char val[64]; + + if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) + return -1; + + if (port_op != 4) { + mad_dump_portstates(buf, sizeof buf, data, sizeof data); + mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, val); + mad_dump_field(IB_PORT_LINK_WIDTH_SUPPORTED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_WIDTH_ENABLED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, val); + mad_dump_field(IB_PORT_LINK_WIDTH_ACTIVE_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_SUPPORTED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ACTIVE_F, buf + strlen(buf), sizeof buf - strlen(buf), val); + sprintf(buf+strlen(buf), "%s", "\n"); + } else { + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf, val); + sprintf(buf+strlen(buf), "%s", "\n"); + } + + printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); + return 0; +} + +static int +set_port_info(ib_portid_t *dest, uint8_t *data, int portnum, int port_op) +{ + char buf[2048]; + char val[64]; + + if (!smp_set(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) + return -1; + + if (port_op != 4) + mad_dump_portstates(buf, sizeof buf, data, sizeof data); + else { + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, val); + mad_dump_field(IB_PORT_LINK_SPEED_ENABLED_F, buf, sizeof buf, val); + sprintf(buf+strlen(buf), "%s", "\n"); + } + + printf("\nAfter PortInfo set:\n"); + printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); + return 0; +} + +static int +get_link_width(int lwe, int lws) +{ + if (lwe == 255) + return lws; + else + return lwe; +} + +static int +get_link_speed(int lse, int lss) +{ + if (lse == 15) + return lss; + else + return lse; +} + +static void +validate_width(int width, int peerwidth, int lwa) +{ + if ((width & 0x8) && (peerwidth & 0x8)) { + if (lwa != 8) + IBWARN("Peer ports operating at active width %d rather than 8 (12x)", lwa); + } else { + if ((width & 0x4) && (peerwidth & 0x4)) { + if (lwa != 4) + IBWARN("Peer ports operating at active width %d rather than 4 (8x)", lwa); + } else { + if ((width & 0x2) && (peerwidth & 0x2)) { + if (lwa != 2) + IBWARN("Peer ports operating at active width %d rather than 2 (4x)", lwa); + } else { + if ((width & 0x1) && (peerwidth & 0x1)) { + if (lwa != 1) + IBWARN("Peer ports operating at active width %d rather than 1 (1x)", lwa); + } + } + } + } +} + +static void +validate_speed(int speed, int peerspeed, int lsa) +{ + if ((speed & 0x4) && (peerspeed & 0x4)) { + if (lsa != 4) + IBWARN("Peer ports operating at active speed %d rather than 4 (10.0 Gbps)", lsa); + } else { + if ((speed & 0x2) && (peerspeed & 0x2)) { + if (lsa != 2) + IBWARN("Peer ports operating at active speed %d rather than 2 (5.0 Gbps)", lsa); + } else { + if ((speed & 0x1) && (peerspeed & 0x1)) { + if (lsa != 1) + IBWARN("Peer ports operating at active speed %d rather than 1 (2.5 Gbps)", lsa); + } + } + } +} + +void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -D(irect) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms] []\n", + basename); + fprintf(stderr, "\tsupported ops: enable, disable, reset, speed, query\n"); + fprintf(stderr, "\n\texamples:\n"); + fprintf(stderr, "\t\t%s 3 1 disable\t\t\t# by lid\n", basename); + fprintf(stderr, "\t\t%s -G 0x2C9000100D051 1 enable\t# by guid\n", basename); + fprintf(stderr, "\t\t%s -D 0 1\t\t\t# (query) by direct route\n", basename); + fprintf(stderr, "\t\t%s 3 1 reset\t\t\t# by lid\n", basename); + fprintf(stderr, "\t\t%s 3 1 speed 1\t\t\t# by lid\n", basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + ib_portid_t portid = {0}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + extern int ibdebug; + int err; + int timeout = 0, udebug = 0; + char *ca = 0; + int ca_port = 0; + int port_op = 0; /* default to query */ + int speed = 15; + int is_switch = 1; + int state, physstate, lwe, lws, lwa, lse, lss, lsa; + int peerlocalportnum, peerlwe, peerlws, peerlwa, peerlse, peerlss, peerlsa; + int width, peerwidth, peerspeed; + uint8_t data[IB_SMP_DATA_SIZE]; + ib_portid_t peerportid = {0}; + int portnum = 0; + ib_portid_t selfportid = {0}; + int selfport = 0; + + static char const str_opts[] = "C:P:t:s:devDGVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "verbose", 0, 0, 'v'}, + { "Direct", 0, 0, 'D'}, + { "Guid", 0, 0, 'G'}, + { "timeout", 1, 0, 't'}, + { "s", 1, 0, 's'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + + /* First, make sure it is a switch port if it is a "set" */ + if (argc >= 3) { + if (!strcmp(argv[2], "enable")) + port_op = 1; + else if (!strcmp(argv[2], "disable")) + port_op = 2; + else if (!strcmp(argv[2], "reset")) + port_op = 3; + else if (!strcmp(argv[2], "speed")) { + if (argc < 4) + IBERROR("speed requires an additional parameter"); + port_op = 4; + /* Parse speed value */ + speed = strtoul(argv[3], 0, 0); + if (speed > 15) + IBERROR("invalid speed value %d", speed); + } + } + + err = get_node_info(&portid, data); + if (err < 0) + IBERROR("smp query nodeinfo failed"); + if (err) { /* not switch */ + if (port_op == 0) /* query op */ + is_switch = 0; + else if (port_op != 4) /* other than speed op */ + IBERROR("smp query nodeinfo: Node type not switch"); + } + + if (argc-1 > 0) + portnum = strtol(argv[1], 0, 0); + + if (port_op) + printf("Initial PortInfo:\n"); + else + printf("PortInfo:\n"); + err = get_port_info(&portid, data, portnum, port_op); + if (err < 0) + IBERROR("smp query portinfo failed"); + + /* Only if one of the "set" options is chosen */ + if (port_op) { + if (port_op == 1) /* Enable port */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2); /* Polling */ + else if ((port_op == 2) || (port_op == 3)) { /* Disable port */ + mad_set_field(data, 0, IB_PORT_STATE_F, 1); /* Down */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 3); /* Disabled */ + } else if (port_op == 4) { /* Set speed */ + mad_set_field(data, 0, IB_PORT_LINK_SPEED_ENABLED_F, speed); + mad_set_field(data, 0, IB_PORT_STATE_F, 0); + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 0); + } + + err = set_port_info(&portid, data, portnum, port_op); + if (err < 0) + IBERROR("smp set portinfo failed"); + + if (port_op == 3) { /* Reset port - so also enable */ + mad_set_field(data, 0, IB_PORT_PHYS_STATE_F, 2); /* Polling */ + err = set_port_info(&portid, data, portnum, port_op); + if (err < 0) + IBERROR("smp set portinfo failed"); + } + } else { /* query op */ + /* only compare peer port if switch port */ + if (is_switch) { + /* First, exclude SP0 */ + if (portnum) { + /* Now, make sure PortState is Active */ + /* Or is PortPhysicalState LinkUp sufficient ? */ + mad_decode_field(data, IB_PORT_STATE_F, &state); + mad_decode_field(data, IB_PORT_PHYS_STATE_F, &physstate); + if (state == 4) { /* Active */ + mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, &lwe ); + mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, &lws); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, &lwa); + mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, &lss); + mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, &lsa); + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, &lse); + + /* Setup portid for peer port */ + memcpy(&peerportid, &portid, sizeof(peerportid)); + peerportid.drpath.cnt = 1; + peerportid.drpath.p[1] = portnum; + + /* Set DrSLID to local lid */ + if (ib_resolve_self(&selfportid, &selfport, 0) < 0) + IBERROR("could not resolve self"); + peerportid.drpath.drslid = selfportid.lid; + peerportid.drpath.drdlid = 0xffff; + + /* Get peer port NodeInfo to obtain peer port number */ + err = get_node_info(&peerportid, data); + if (err < 0) + IBERROR("smp query nodeinfo failed"); + + mad_decode_field(data, IB_NODE_LOCAL_PORT_F, &peerlocalportnum); + + printf("Peer PortInfo:\n"); + /* Get peer port characteristics */ + err = get_port_info(&peerportid, data, peerlocalportnum, port_op); + if (err < 0) + IBERROR("smp query peer portinfofailed"); + + mad_decode_field(data, IB_PORT_LINK_WIDTH_ENABLED_F, &peerlwe ); + mad_decode_field(data, IB_PORT_LINK_WIDTH_SUPPORTED_F, &peerlws); + mad_decode_field(data, IB_PORT_LINK_WIDTH_ACTIVE_F, &peerlwa); + mad_decode_field(data, IB_PORT_LINK_SPEED_SUPPORTED_F, &peerlss); + mad_decode_field(data, IB_PORT_LINK_SPEED_ACTIVE_F, &peerlsa); + mad_decode_field(data, IB_PORT_LINK_SPEED_ENABLED_F, &peerlse); + + /* Now validate peer port characteristics */ + /* Examine Link Width */ + width = get_link_width(lwe, lws); + peerwidth = get_link_width(peerlwe, peerlws); + validate_width(width, peerwidth, lwa); + + /* Examine Link Speed */ + speed = get_link_speed(lse, lss); + peerspeed = get_link_speed(peerlse, peerlss); + validate_speed(speed, peerspeed, lsa); + } + } + } + } + + exit(0); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/ibroute.c b/branches/winverbs/tools/infiniband_diags/src/ibroute.c new file mode 100644 index 00000000..83e2142f --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibroute.c @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2004-2008 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. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ibdiag_common.h" + +static int dest_type = IB_DEST_LID; +static int brief; +static int verbose; +static int dump_all; + +char *argv0 = "ibroute"; + +/*******************************************/ + +char * +check_switch(ib_portid_t *portid, int *nports, uint64_t *guid, + uint8_t *sw, char *nd) +{ + uint8_t ni[IB_SMP_DATA_SIZE] = {0}; + int type; + + DEBUG("checking node type"); + if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, 0)) { + xdump(stderr, "nodeinfo\n", ni, sizeof ni); + return "node info failed: valid addr?"; + } + + if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, 0)) + return "node desc failed"; + + mad_decode_field(ni, IB_NODE_TYPE_F, &type); + if (type != IB_NODE_SWITCH) + return "not a switch"; + + DEBUG("Gathering information about switch"); + mad_decode_field(ni, IB_NODE_NPORTS_F, nports); + mad_decode_field(ni, IB_NODE_GUID_F, guid); + + if (!smp_query(sw, portid, IB_ATTR_SWITCH_INFO, 0, 0)) + return "switch info failed: is a switch node?"; + + return 0; +} + +#define IB_MLIDS_IN_BLOCK (IB_SMP_DATA_SIZE/2) + +int +dump_mlid(char *str, int strlen, int mlid, int nports, + uint16_t mft[16][IB_MLIDS_IN_BLOCK]) +{ + uint16_t mask; + int i, chunk, bit; + int nonzero = 0; + + if (brief) { + int n = 0, chunks = ALIGN(nports + 1, 16) / 16; + for (i = 0; i < chunks; i++) { + mask = ntohs(mft[i][mlid%IB_MLIDS_IN_BLOCK]); + if (mask) + nonzero++; + n += snprintf(str + n, strlen - n, "%04hx", mask); + if (n >= strlen) { + n = strlen; + break; + } + } + if (!nonzero && !dump_all) { + str[0] = 0; + return 0; + } + return n; + } + for (i = 0; i <= nports; i++) { + chunk = i / 16; + bit = i % 16; + + mask = ntohs(mft[chunk][mlid%IB_MLIDS_IN_BLOCK]); + if (mask) + nonzero++; + str[i*2] = (mask & (1 << bit)) ? 'x' : ' '; + str[i*2+1] = ' '; + } + if (!nonzero && !dump_all) { + str[0] = 0; + return 0; + } + str[i*2] = 0; + return i * 2; +} + +uint16_t mft[16][IB_MLIDS_IN_BLOCK]; + +char * +dump_multicast_tables(ib_portid_t *portid, int startlid, int endlid) +{ + char nd[IB_SMP_DATA_SIZE] = {0}; + uint8_t sw[IB_SMP_DATA_SIZE] = {0}; + char str[512]; + char *s; + uint64_t nodeguid; + uint32_t mod; + int block, i, j, e, nports, cap, chunks; + int n = 0, startblock, lastblock; + + if ((s = check_switch(portid, &nports, &nodeguid, sw, nd))) + return s; + + mad_decode_field(sw, IB_SW_MCAST_FDB_CAP_F, &cap); + + if (!endlid || endlid > IB_MIN_MCAST_LID + cap - 1) + endlid = IB_MIN_MCAST_LID + cap - 1; + + if (!startlid) + startlid = IB_MIN_MCAST_LID; + + if (startlid < IB_MIN_MCAST_LID) { + IBWARN("illegal start mlid %x, set to %x", startlid, IB_MIN_MCAST_LID); + startlid = IB_MIN_MCAST_LID; + } + + if (endlid > IB_MAX_MCAST_LID) { + IBWARN("illegal end mlid %x, truncate to %x", endlid, IB_MAX_MCAST_LID); + endlid = IB_MAX_MCAST_LID; + } + + printf("Multicast mlids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 " (%s):\n", + startlid, endlid, portid2str(portid), nodeguid, clean_nodedesc(nd)); + + if (brief) + printf(" MLid Port Mask\n"); + else { + if (nports > 9) { + for (i = 0, s = str; i <= nports; i++) { + *s++ = (i%10) ? ' ' : '0' + i/10; + *s++ = ' '; + } + *s = 0; + printf(" %s\n", str); + } + for (i = 0, s = str; i <= nports; i++) + s += sprintf(s, "%d ", i%10); + printf(" Ports: %s\n", str); + printf(" MLid\n"); + } + if (verbose) + printf("Switch muticast mlids capability is 0x%d\n", cap); + + chunks = ALIGN(nports + 1, 16) / 16; + + startblock = startlid / IB_MLIDS_IN_BLOCK; + lastblock = endlid / IB_MLIDS_IN_BLOCK; + for (block = startblock; block <= lastblock; block++) { + for (j = 0; j < chunks; j++) { + mod = (block - IB_MIN_MCAST_LID/IB_MLIDS_IN_BLOCK) | (j << 28); + + DEBUG("reading block %x chunk %d mod %x", block, j, mod); + if (!smp_query(mft + j, portid, IB_ATTR_MULTICASTFORWTBL, mod, 0)) + return "multicast forwarding table get failed"; + } + + i = block * IB_MLIDS_IN_BLOCK; + e = i + IB_MLIDS_IN_BLOCK; + if (i < startlid) + i = startlid; + if (e > endlid + 1) + e = endlid + 1; + + for (; i < e; i++) { + if (dump_mlid(str, sizeof str, i, nports, mft) == 0) + continue; + printf("0x%04x %s\n", i, str); + n++; + } + } + + printf("%d %smlids dumped \n", n, dump_all ? "" : "valid "); + return 0; +} + +int +dump_lid(char *str, int strlen, int lid, int valid) +{ + char nd[IB_SMP_DATA_SIZE] = {0}; + uint8_t ni[IB_SMP_DATA_SIZE] = {0}; + uint8_t pi[IB_SMP_DATA_SIZE] = {0}; + ib_portid_t lidport = {0}; + static int last_port_lid, base_port_lid; + char ntype[50], sguid[30], desc[64]; + static uint64_t portguid; + int baselid, lmc, type; + + if (brief) { + str[0] = 0; + return 0; + } + + if (lid <= last_port_lid) { + if (!valid) + return snprintf(str, strlen, ": (path #%d - illegal port)", + lid - base_port_lid); + else if (!portguid) + return snprintf(str, strlen, + ": (path #%d out of %d)", + lid - base_port_lid + 1, + last_port_lid - base_port_lid + 1); + else { + return snprintf(str, strlen, + ": (path #%d out of %d: portguid %s)", + lid - base_port_lid + 1, + last_port_lid - base_port_lid + 1, + mad_dump_val(IB_NODE_PORT_GUID_F, sguid, sizeof sguid, &portguid)); + } + } + + if (!valid) + return snprintf(str, strlen, ": (illegal port)"); + + portguid = 0; + lidport.lid = lid; + + if (!smp_query(nd, &lidport, IB_ATTR_NODE_DESC, 0, 100) || + !smp_query(pi, &lidport, IB_ATTR_PORT_INFO, 0, 100) || + !smp_query(ni, &lidport, IB_ATTR_NODE_INFO, 0, 100)) + return snprintf(str, strlen, ": (unknown node and type)"); + + mad_decode_field(ni, IB_NODE_PORT_GUID_F, &portguid); + mad_decode_field(ni, IB_NODE_TYPE_F, &type); + + mad_decode_field(pi, IB_PORT_LID_F, &baselid); + mad_decode_field(pi, IB_PORT_LMC_F, &lmc); + + if (lmc > 0) { + base_port_lid = baselid; + last_port_lid = baselid + (1 << lmc) - 1; + } + + return snprintf(str, strlen, ": (%s portguid %s: %s)", + mad_dump_val(IB_NODE_TYPE_F, ntype, sizeof ntype, &type), + mad_dump_val(IB_NODE_PORT_GUID_F, sguid, sizeof sguid, &portguid), + mad_dump_val(IB_NODE_DESC_F, desc, sizeof desc, clean_nodedesc(nd))); +} + +char * +dump_unicast_tables(ib_portid_t *portid, int startlid, int endlid) +{ + char lft[IB_SMP_DATA_SIZE]; + char nd[IB_SMP_DATA_SIZE]; + uint8_t sw[IB_SMP_DATA_SIZE]; + char str[200], *s; + uint64_t nodeguid; + int block, i, e, nports, top; + int n = 0, startblock, endblock; + + if ((s = check_switch(portid, &nports, &nodeguid, sw, nd))) + return s; + + mad_decode_field(sw, IB_SW_LINEAR_FDB_TOP_F, &top); + + if (!endlid || endlid > top) + endlid = top; + + if (endlid > IB_MAX_UCAST_LID) { + IBWARN("ilegal lft top %d, truncate to %d", endlid, IB_MAX_UCAST_LID); + endlid = IB_MAX_UCAST_LID; + } + + printf("Unicast lids [0x%x-0x%x] of switch %s guid 0x%016" PRIx64 " (%s):\n", + startlid, endlid, portid2str(portid), nodeguid, clean_nodedesc(nd)); + + DEBUG("Switch top is 0x%x\n", top); + + printf(" Lid Out Destination\n"); + printf(" Port Info \n"); + startblock = startlid / IB_SMP_DATA_SIZE; + endblock = ALIGN(endlid, IB_SMP_DATA_SIZE) / IB_SMP_DATA_SIZE; + for (block = startblock; block <= endblock; block++) { + DEBUG("reading block %d", block); + if (!smp_query(lft, portid, IB_ATTR_LINEARFORWTBL, block, 0)) + return "linear forwarding table get failed"; + i = block * IB_SMP_DATA_SIZE; + e = i + IB_SMP_DATA_SIZE; + if (i < startlid) + i = startlid; + if (e > endlid + 1) + e = endlid + 1; + + for (;i < e; i++) { + unsigned outport = lft[i % IB_SMP_DATA_SIZE]; + unsigned valid = (outport <= nports); + + if (!valid && !dump_all) + continue; + dump_lid(str, sizeof str, i, valid); + printf("0x%04x %03u %s\n", i, outport & 0xff, str); + n++; + } + } + + printf("%d %slids dumped \n", n, dump_all ? "" : "valid "); + return 0; +} + +void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug)] -a(ll) -n(o_dests) -v(erbose) -D(irect) -G(uid) -M(ulticast) -s smlid -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms] [ [ []]]\n", + basename); + fprintf(stderr, "\n\tUnicast examples:\n"); + fprintf(stderr, "\t\t%s 4\t# dump all lids with valid out ports of switch with lid 4\n", basename); + fprintf(stderr, "\t\t%s -a 4\t# same, but dump all lids, even with invalid out ports\n", basename); + fprintf(stderr, "\t\t%s -n 4\t# simple dump format - no destination resolving\n", basename); + fprintf(stderr, "\t\t%s 4 10\t# dump lids starting from 10\n", basename); + fprintf(stderr, "\t\t%s 4 0x10 0x20\t# dump lid range\n", basename); + fprintf(stderr, "\t\t%s -G 0x08f1040023\t# resolve switch by GUID\n", basename); + fprintf(stderr, "\t\t%s -D 0,1\t# resolve switch by direct path\n", basename); + + fprintf(stderr, "\n\tMulticast examples:\n"); + fprintf(stderr, "\t\t%s -M 4\t# dump all non empty mlids of switch with lid 4\n", basename); + fprintf(stderr, "\t\t%s -M 4 0xc010 0xc020\t# same, but with range\n", basename); + fprintf(stderr, "\t\t%s -M -n 4\t# simple dump format\n", basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + ib_portid_t portid = {0}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + int timeout; + int multicast = 0, startlid = 0, endlid = 0; + char *err; + char *ca = 0; + int ca_port = 0; + + static char const str_opts[] = "C:P:t:s:danvDGMVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "all", 0, 0, 'a'}, + { "no_dests", 0, 0, 'n'}, + { "verbose", 0, 0, 'v'}, + { "Direct", 0, 0, 'D'}, + { "Guid", 0, 0, 'G'}, + { "Multicast", 0, 0, 'M'}, + { "timeout", 1, 0, 't'}, + { "s", 1, 0, 's'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'a': + dump_all++; + break; + case 'd': + ibdebug++; + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'M': + multicast++; + break; + case 'n': + brief++; + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + madrpc_show_errors(1); + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (!argc) + usage(); + + if (argc > 1) + startlid = strtoul(argv[1], 0, 0); + if (argc > 2) + endlid = strtoul(argv[2], 0, 0); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (!argc) { + if (ib_resolve_self(&portid, 0, 0) < 0) + IBERROR("can't resolve self addr"); + } else { + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[1]); + } + + if (multicast) + err = dump_multicast_tables(&portid, startlid, endlid); + else + err = dump_unicast_tables(&portid, startlid, endlid); + + if (err) + IBERROR("dump tables: %s", err); + + exit(0); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/ibsendtrap.c b/branches/winverbs/tools/infiniband_diags/src/ibsendtrap.c new file mode 100644 index 00000000..47db29ad --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibsendtrap.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2008 Lawrence Livermore National Security + * + * Produced at Lawrence Livermore National Laboratory. + * Written by Ira Weiny . + * + * 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 + +#define _GNU_SOURCE +#include + +#include +#include + +#include "ibdiag_common.h" + +char *argv0 = ""; + +static int send_144_node_desc_update(void) +{ + ib_portid_t sm_port; + ib_portid_t selfportid; + int selfport; + ib_rpc_t trap_rpc; + ib_mad_notice_attr_t notice; + + if (ib_resolve_self(&selfportid, &selfport, NULL)) + IBERROR("can't resolve self"); + + if (ib_resolve_smlid(&sm_port, 0)) + IBERROR("can't resolve SM destination port"); + + memset(&trap_rpc, 0, sizeof(trap_rpc)); + trap_rpc.mgtclass = IB_SMI_CLASS; + trap_rpc.method = IB_MAD_METHOD_TRAP; + trap_rpc.trid = mad_trid(); + trap_rpc.attr.id = NOTICE; + trap_rpc.datasz = IB_SMP_DATA_SIZE; + trap_rpc.dataoffs = IB_SMP_DATA_OFFS; + + memset(¬ice, 0, sizeof(notice)); + notice.generic_type = 0x80 | IB_NOTICE_TYPE_INFO; + notice.g_or_v.generic.prod_type_lsb = cl_hton16(IB_NODE_TYPE_CA); + notice.g_or_v.generic.trap_num = cl_hton16(144); + notice.issuer_lid = cl_hton16(selfportid.lid); + notice.data_details.ntc_144.lid = cl_hton16(selfportid.lid); + notice.data_details.ntc_144.local_changes = + TRAP_144_MASK_OTHER_LOCAL_CHANGES; + notice.data_details.ntc_144.change_flgs = + TRAP_144_MASK_NODE_DESCRIPTION_CHANGE; + + return (mad_send(&trap_rpc, &sm_port, NULL, ¬ice)); +} + +typedef struct _trap_def { + char *trap_name; + int (*send_func) (void); +} trap_def_t; + +trap_def_t traps[2] = { + {"node_desc_change", send_144_node_desc_update}, + {NULL, NULL} +}; + +static void usage(void) +{ + int i; + + fprintf(stderr, "Usage: %s [-hV]" + " [-C ] [-P ] []\n", argv0); + fprintf(stderr, " -V print version\n"); + fprintf(stderr, " can be one of the following\n"); + for (i = 0; traps[i].trap_name; i++) { + fprintf(stderr, " %s\n", traps[i].trap_name); + } + fprintf(stderr, " default behavior is to send \"%s\"\n", + traps[0].trap_name); + + exit(-1); +} + +int send_trap(char *trap_name) +{ + int i; + + for (i = 0; traps[i].trap_name; i++) { + if (strcmp(traps[i].trap_name, trap_name) == 0) { + return (traps[i].send_func()); + } + } + usage(); + exit(1); +} + +int main(int argc, char **argv) +{ + int mgmt_classes[2] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS }; + int ch = 0; + char *trap_name = NULL; + char *ca = NULL; + int ca_port = 0; + + static char const str_opts[] = "hVP:C:"; + static const struct option long_opts[] = { + {"Version", 0, 0, 'V'}, + {"P", 1, 0, 'P'}, + {"C", 1, 0, 'C'}, + {"help", 0, 0, 'h'}, + {} + }; + + argv0 = argv[0]; + + while ((ch = getopt_long(argc, argv, str_opts, long_opts, NULL)) != -1) { + switch (ch) { + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version()); + exit(-1); + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, NULL, 0); + break; + case 'h': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (!argv[0]) { + trap_name = traps[0].trap_name; + } else { + trap_name = argv[0]; + } + + madrpc_show_errors(1); + madrpc_init(ca, ca_port, mgmt_classes, 2); + + return (send_trap(trap_name)); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/ibstat.c b/branches/winverbs/tools/infiniband_diags/src/ibstat.c new file mode 100644 index 00000000..8825277c --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibstat.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2004-2008 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 + +#if !defined(_WIN32) +#define _GNU_SOURCE + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include "..\..\..\..\etc\user\getopt.c" +#endif + +#include +#include +#include + +static int debug; + +char *argv0 = "ibstat"; + +static char *node_type_str[] = { + "???", + "CA", + "Switch", + "Router", + "iWARP RNIC" +}; + +static void +ca_dump(umad_ca_t *ca) +{ + if (!ca->node_type) + return; + printf("%s '%s'\n", ((unsigned int)ca->node_type <= IB_NODE_MAX ? node_type_str[ca->node_type] : "???"), ca->ca_name); + printf("\t%s type: %s\n", ((unsigned int)ca->node_type <= IB_NODE_MAX ? node_type_str[ca->node_type] : "???"),ca->ca_type); + printf("\tNumber of ports: %d\n", ca->numports); + printf("\tFirmware version: %s\n", ca->fw_ver); + printf("\tHardware version: %s\n", ca->hw_ver); + printf("\tNode GUID: 0x%016"PRIx64"\n", ntohll(ca->node_guid)); + printf("\tSystem image GUID: 0x%016"PRIx64"\n", ntohll(ca->system_guid)); +} + +static char *port_state_str[] = { + "???", + "Down", + "Initializing", + "Armed", + "Active" +}; + +static char *port_phy_state_str[] = { + "No state change", + "Sleep", + "Polling", + "Disabled", + "PortConfigurationTraining", + "LinkUp", + "LinkErrorRecovery", + "PhyTest" +}; + +static int +port_dump(umad_port_t *port, int alone) +{ + char *pre = ""; + char *hdrpre = ""; + + if (!port) + return -1; + + if (!alone) { + pre = " "; + hdrpre = " "; + } + + printf("%sPort %d:\n", hdrpre, port->portnum); + printf("%sState: %s\n", pre, (unsigned int)port->state <= 4 ? port_state_str[port->state] : "???"); + printf("%sPhysical state: %s\n", pre, (unsigned int)port->state <= 7 ? port_phy_state_str[port->phys_state] : "???"); + printf("%sRate: %d\n", pre, port->rate); + printf("%sBase lid: %d\n", pre, port->base_lid); + printf("%sLMC: %d\n", pre, port->lmc); + printf("%sSM lid: %d\n", pre, port->sm_lid); + printf("%sCapability mask: 0x%08x\n", pre, (unsigned int)ntohll(port->capmask)); + printf("%sPort GUID: 0x%016"PRIx64"\n", pre, (long long unsigned)ntohll(port->port_guid)); + return 0; +} + +static int +ca_stat(char *ca_name, int portnum, int no_ports) +{ + umad_ca_t ca; + int r; + + if ((r = umad_get_ca(ca_name, &ca)) < 0) + return r; + + if (!ca.node_type) + return 0; + + if (!no_ports && portnum >= 0) { + if (portnum > ca.numports || !ca.ports[portnum]) { + IBWARN("%s: '%s' has no port number %d - max (%d)", + ((unsigned int)ca.node_type <= IB_NODE_MAX ? node_type_str[ca.node_type] : "???"), + ca_name, portnum, ca.numports); + return -1; + } + printf("%s: '%s'\n", ((unsigned int)ca.node_type <= IB_NODE_MAX ? node_type_str[ca.node_type] : "???"), ca.ca_name); + port_dump(ca.ports[portnum], 1); + return 0; + } + + /* print ca header */ + ca_dump(&ca); + + if (no_ports) + return 0; + + for (portnum = 0; portnum < ca.numports; portnum++) + port_dump(ca.ports[portnum], 0); + + return 0; +} + +static int +ports_list(char names[][UMAD_CA_NAME_LEN], int n) +{ + uint64_t guids[64]; + int found, ports, i; + + for (i = 0, found = 0; i < n && found < 64; i++) { + if ((ports = umad_get_ca_portguids(names[i], guids + found, 64 - found)) < 0) + return -1; + found += ports; + } + + for (i = 0; i < found; i++) + if (guids[i]) + printf("0x%016"PRIx64"\n", (long long unsigned)ntohll(guids[i])); + return found; +} + +void +usage(void) +{ + fprintf(stderr, "Usage: %s [-d(ebug) -l(ist_of_cas) -s(hort) -p(ort_list) -V(ersion)] [portnum]\n", argv0); + fprintf(stderr, "\tExamples:\n"); + fprintf(stderr, "\t\t%s -l # list all IB devices\n", argv0); + fprintf(stderr, "\t\t%s mthca0 2 # stat port 2 of 'mthca0'\n", argv0); + exit(-1); +} + +int __cdecl +main(int argc, char *argv[]) +{ + char names[20][UMAD_CA_NAME_LEN]; + int dev_port = -1; + int list_only = 0, short_format = 0, list_ports = 0; + int n, i; + + static char str_opts[] = "dlspVhu"; + static struct option long_opts[] = { + { "debug", 0, 0, 'd'}, + { "list_of_cas", 0, 0, 'l'}, + { "short", 0, 0, 's'}, + { "port_list", 0, 0, 'p'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { 0 } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'd': + debug++; + break; + case 'l': + list_only++; + break; + case 's': + short_format++; + break; + case 'p': + list_ports++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + dev_port = strtol(argv[1], 0, 0); + + if (umad_init() < 0) + IBPANIC("can't init UMAD library"); + + if ((n = umad_get_cas_names((void *)names, UMAD_CA_NAME_LEN)) < 0) + IBPANIC("can't list IB device names"); + + if (argc) { + for (i = 0; i < n; i++) + if (!strncmp(names[i], argv[0], sizeof names[i])) + break; + if (i >= n) + IBPANIC("'%s' IB device can't be found", argv[0]); + + strncpy(names[i], argv[0], sizeof names[i]); + n = 1; + } + + if (list_ports) { + if (ports_list(names, n) < 0) + IBPANIC("can't list ports"); + return 0; + } + + if (!list_only && argc) { + if (ca_stat(argv[0], dev_port, short_format) < 0) + IBPANIC("stat of IB device '%s' failed", argv[0]); + return 0; + } + + for (i = 0; i < n; i++) { + if (list_only) + printf("%s\n", names[i]); + else + if (ca_stat(names[i], -1, short_format) < 0) + IBPANIC("stat of IB device '%s' failed", names[i]); + } + + return 0; +} diff --git a/branches/winverbs/tools/infiniband_diags/src/ibstat/SOURCES b/branches/winverbs/tools/infiniband_diags/src/ibstat/SOURCES new file mode 100644 index 00000000..4fc625fb --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibstat/SOURCES @@ -0,0 +1,32 @@ +TARGETNAME = ibstat +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = ..\ibstat.c ..\ibdiag_common.c + +INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + diff --git a/branches/winverbs/tools/infiniband_diags/src/ibsysstat.c b/branches/winverbs/tools/infiniband_diags/src/ibsysstat.c new file mode 100644 index 00000000..63e450c1 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibsysstat.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2004-2008 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. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ibdiag_common.h" + +#undef DEBUG +#define DEBUG if (verbose) IBWARN + +static int dest_type = IB_DEST_LID; +static int verbose; + +#define MAX_CPUS 8 + +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; + +char *argv0 = "ibsysstat"; + +static void +mk_reply(int attr, void *data, int sz) +{ + char *s = data; + int n, i; + + 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) + break; + s[n] = '.'; + s += n+1; + sz -= n+1; + if (getdomainname(s, sz) < 0) + snprintf(s, sz, "?domainname?"); + if (strlen(s) == 0) + s[-1] = 0; /* no domain */ + break; + case IB_CPUINFO_ATTR: + 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"); + break; + } + sz -= n; + s += n; + } + break; + default: + DEBUG("unknown attr %d", attr); + } +} + +static char * +ibsystat_serv(void) +{ + void *umad; + void *mad; + int attr, mod; + + DEBUG("starting to serve..."); + + while ((umad = mad_receive(0, -1))) { + + 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); + + mk_reply(attr, (char *)mad + IB_VENDOR_RANGE2_DATA_OFFS, IB_VENDOR_RANGE2_DATA_SIZE); + + if (mad_respond(umad, 0, 0) < 0) + DEBUG("respond failed"); + + mad_free(umad); + } + + DEBUG("server out"); + return 0; +} + +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) +{ + char data[IB_VENDOR_RANGE2_DATA_SIZE] = {0}; + ib_vendor_call_t call; + + DEBUG("Sysstat ping.."); + + call.method = IB_MAD_METHOD_GET; + call.mgmt_class = IB_VENDOR_OPENIB_SYSSTAT_CLASS; + call.attrid = attr; + call.mod = 0; + call.oui = IB_OPENIB_OUI; + call.timeout = 0; + memset(&call.rmpp, 0, sizeof call.rmpp); + + if (!ib_vendor_call(data, portid, &call)) + return "vendor call failed"; + + DEBUG("Got sysstat pong.."); + if (attr != IB_PING_ATTR) + puts(data); + else + printf("sysstat ping succeeded\n"); + return 0; +} + +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) + 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 void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms -o oui -S(erver)] []\n", + basename); + exit(-1); +} + +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}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + int timeout = 0, udebug = 0, server = 0; + int oui = IB_OPENIB_OUI, attr = IB_PING_ATTR; + extern int ibdebug; + char *err; + char *ca = 0; + int ca_port = 0; + + static char const str_opts[] = "C:P:t:s:o:devGSVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "verbose", 0, 0, 'v'}, + { "Guid", 0, 0, 'G'}, + { "timeout", 1, 0, 't'}, + { "s", 1, 0, 's'}, + { "o", 1, 0, 'o'}, + { "Server", 0, 0, 'S'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'o': + oui = strtoul(optarg, 0, 0); + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 'S': + server++; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (!argc && !server) + usage(); + + if (argc > 1 && (attr = match_attr(argv[1])) < 0) + usage(); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (server) { + if (mad_register_server(sysstat_class, 0, 0, oui) < 0) + IBERROR("can't serve class %d", sysstat_class); + + host_ncpu = build_cpuinfo(); + + if ((err = ibsystat_serv())) + IBERROR("ibssystat to %s: %s", portid2str(&portid), err); + exit(0); + } + + if (mad_register_client(sysstat_class, 0) < 0) + IBERROR("can't register to sysstat class %d", sysstat_class); + + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + + if ((err = ibsystat(&portid, attr))) + IBERROR("ibsystat to %s: %s", portid2str(&portid), err); + + exit(0); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/ibtracert.c b/branches/winverbs/tools/infiniband_diags/src/ibtracert.c new file mode 100644 index 00000000..724ac807 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/ibtracert.c @@ -0,0 +1,865 @@ +/* + * Copyright (c) 2004-2008 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. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ibdiag_common.h" + +#define MAXHOPS 63 + +static char *node_type_str[] = { + "???", + "ca", + "switch", + "router", + "iwarp rnic" +}; + +static int timeout = 0; /* ms */ +static int verbose; +static int force; +static FILE *f; + +char *argv0 = "ibtracert"; + +static char *node_name_map_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; + 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; /* also portguid */ + char nodedesc[64]; + char nodeinfo[64]; +}; + +Node *nodesdist[MAXHOPS]; +uint64_t target_portguid; + +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; + + if (!smp_query(ni, portid, IB_ATTR_NODE_INFO, 0, timeout)) + return -1; + + if (!smp_query(nd, portid, IB_ATTR_NODE_DESC, 0, timeout)) + return -1; + + for (s = nd, e = s + 64; s < e; s++) { + if (!*s) + break; + if (!isprint(*s)) + *s = ' '; + } + + if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, 0, timeout)) + 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; + + if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout)) + 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); + + if (lid > sw->linearcap && lid > sw->linearFDBtop) + return -1; + + if (!smp_query(fdb, portid, IB_ATTR_LINEARFORWTBL, lid / 64, timeout)) + 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] = nextport; + return path->cnt; +} + +static void +dump_endnode(int dump, 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 && !verbose) + 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; + + 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); + + while (maxhops--) { + if (port->state != 4) + goto badport; + + if (sameport(port, &toport)) + break; /* found */ + + outport = portnum; + if (node->type == IB_NODE_SWITCH) { + DEBUG("switch node"); + if ((outport = switch_lookup(&sw, from, to->lid)) < 0 || + outport > node->numports) + goto badtbl; + + 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; /* found SMA port */ + } + } else if ((node->type == IB_NODE_CA) || + (node->type == IB_NODE_ROUTER)) { + int ca_src = 0; + + 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; + } + /* we are at CA or router "from" - go one hop back to (hopefully) a switch */ + 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; + } + /* fix port num to be seen from the CA or router side */ + if (!ca_src) + nextport.portnum = from->drpath.p[from->drpath.cnt+1]; + } + port = &nextport; + if (port->state != 4) + 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; +} + + +/************************** + * MC span part + */ + +#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]; + void *pi = portinfo; + + port->portnum = portnum; + + if (!smp_query(pi, portid, IB_ATTR_PORT_INFO, portnum, timeout)) + 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; /* tag as target */ + link_port(port, node); + dump_endnode(verbose, "found target", node, port); + return 1; /* found; */ + } + + /* BFS search start with my self */ + if (insert_node(node) < 0) + return -1; /* known switch */ + + 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; + uint16_t *msets = (uint16_t *)mdb; + int maxsets, block, i, set; + + memset(map, 0, 256); + + if (!smp_query(si, portid, IB_ATTR_SWITCH_INFO, 0, timeout)) + 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; /* round up */ + + for (set = 0; set < maxsets; set++) { + if (!smp_query(mdb, portid, IB_ATTR_MULTICASTFORWTBL, + block | (set << 28), timeout)) + 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; +} + +/* + * Return 1 if found, 0 if not, -1 on errors. + */ +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)))) + IBERROR("out of memory"); + + if (!(port = calloc(1, sizeof(Port)))) + IBERROR("out of memory"); + + if (get_node(node, port, from) < 0) { + IBWARN("can't reach node %s", portid2str(from)); + return 0; + } + + node->upnode = 0; /* root */ + if ((r = new_node(node, port, from, 0)) > 0) { + if (node->type != IB_NODE_SWITCH) { + IBWARN("ibtracert from CA to CA is unsupported"); + return 0; /* ibtracert from host to itself is unsupported */ + } + + if (switch_mclookup(node, from, mlid, map) < 0 || + !map[0]) + return 0; + 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(verbose, "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; /* starting here */ + DEBUG("Starting from CA 0x%" PRIx64 " lid %d port %d (leafport %d)", + node->nodeguid, port->lid, port->portnum, leafport); + } else { /* switch */ + + /* if starting from a leaf port fix up port (up port) */ + 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)))) + IBERROR("out of memory"); + + if (get_port(port, i, path) < 0) { + IBWARN("can't reach node %s port %d", portid2str(path), i); + return 0; + } + + if (port->physstate != 5) { /* LinkUP */ + free(port); + continue; + } + +#if 0 + link_port(port, node); +#endif + + if (extend_dpath(&path->drpath, i) < 0) + return 0; + } + + if (!(remotenode = calloc(1, sizeof(Node)))) + IBERROR("out of memory"); + + if (!(remoteport = calloc(1, sizeof(Port)))) + IBERROR("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--; /* restore path */ + 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(verbose, "new remote", + remotenode, remoteport); + else if (remotenode->type == IB_NODE_SWITCH) + dump_endnode(2, "ERR: circle discovered at", + remotenode, remoteport); + + path->drpath.cnt--; /* restore path */ + } + } + } + + return 0; /* not found */ +} + +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) + /* target node */ + 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, const void *srcport) +{ + uint8_t portinfo[64]; + uint16_t lid; + + if (!smp_query_via(portinfo, portid, IB_ATTR_PORT_INFO, 0, 0, srcport)) + return -1; + mad_decode_field(portinfo, IB_PORT_LID_F, &lid); + + ib_portid_set(portid, lid, 0, 0); + + return 0; +} + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -v(erbose) -D(irect) -G(uids) -n(o_info) -C ca_name -P ca_port " + "-s smlid -t(imeout) timeout_ms -m mlid --node-name-map node-name-map ] \n", + basename); + fprintf(stderr, "\n\tUnicast examples:\n"); + fprintf(stderr, "\t\t%s 4 16\t\t\t# show path between lids 4 and 16\n", basename); + fprintf(stderr, "\t\t%s -n 4 16\t\t# same, but using simple output format\n", basename); + fprintf(stderr, "\t\t%s -G 0x8f1040396522d 0x002c9000100d051\t# use guid addresses\n", basename); + + fprintf(stderr, "\n\tMulticast example:\n"); + fprintf(stderr, "\t\t%s -m 0xc000 4 16\t# show multicast path of mlid 0xc000 between lids 4 and 16\n", basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + ib_portid_t my_portid = {0}; + ib_portid_t src_portid = {0}; + ib_portid_t dest_portid = {0}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + int dumplevel = 2, dest_type = IB_DEST_LID, multicast = 0, mlid = 0; + Node *endnode; + int udebug = 0; + char *ca = 0; + int ca_port = 0; + + static char const str_opts[] = "C:P:t:s:m:dvfDGnVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "verbose", 0, 0, 'v'}, + { "force", 0, 0, 'f'}, + { "Direct", 0, 0, 'D'}, + { "Guids", 0, 0, 'G'}, + { "no_info", 0, 0, 'n'}, + { "timeout", 1, 0, 't'}, + { "s", 1, 0, 's'}, + { "m", 1, 0, 'm'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { "node-name-map", 1, 0, 1}, + { } + }; + + argv0 = argv[0]; + + f = stdout; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'm': + multicast++; + mlid = strtoul(optarg, 0, 0); + break; + case 'f': + force++; + break; + case 'n': + dumplevel = 1; + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + madrpc_show_errors(1); + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + node_name_map = open_node_name_map(node_name_map_file); + + if (ib_resolve_portid_str(&src_portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve source port %s", argv[0]); + + if (ib_resolve_portid_str(&dest_portid, argv[1], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[1]); + + if (dest_type == IB_DEST_DRPATH) { + if (resolve_lid(&src_portid, NULL) < 0) + IBERROR("cannot resolve lid for port \'%s\'", + portid2str(&src_portid)); + if (resolve_lid(&dest_portid, NULL) < 0) + IBERROR("cannot resolve lid for port \'%s\'", + portid2str(&dest_portid)); + } + + if (dest_portid.lid == 0 || src_portid.lid == 0) { + IBWARN("bad src/dest lid"); + usage(); + } + + if (dest_type != IB_DEST_DRPATH) { + /* first find a direct path to the src port */ + if (find_route(&my_portid, &src_portid, 0) < 0) + IBERROR("can't find a route to the src port"); + + src_portid = my_portid; + } + + if (!multicast) { + if (find_route(&src_portid, &dest_portid, dumplevel) < 0) + IBERROR("can't find a route from src to dest"); + exit(0); + } else { + if (mlid < 0xc000) + IBWARN("invalid MLID; must be 0xc000 or larger"); + } + + if (!(target_portguid = find_target_portguid(&dest_portid))) + IBERROR("can't reach target lid %d", dest_portid.lid); + + if (!(endnode = find_mcpath(&src_portid, mlid))) + IBERROR("can't find a multicast route from src to dest"); + + /* dump multicast path */ + dump_mcpath(endnode, dumplevel); + + close_node_name_map(node_name_map); + exit(0); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/mcm_rereg_test.c b/branches/winverbs/tools/infiniband_diags/src/mcm_rereg_test.c new file mode 100644 index 00000000..1eb62ec3 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/mcm_rereg_test.c @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2006 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 + +#define info(fmt, arg...) fprintf(stderr, "INFO: " fmt, ##arg ) +#define err(fmt, arg...) fprintf(stderr, "ERR: " fmt, ##arg ) +#ifdef NOISY_DEBUG +#define dbg(fmt, arg...) fprintf(stderr, "DBG: " fmt, ##arg ) +#else +#define dbg(fmt, arg...) +#endif + +#define TMO 100 + +/* Multicast Member Record Component Masks */ +#define IB_MCR_COMPMASK_MGID (1ULL<<0) +#define IB_MCR_COMPMASK_PORT_GID (1ULL<<1) +#define IB_MCR_COMPMASK_QKEY (1ULL<<2) +#define IB_MCR_COMPMASK_MLID (1ULL<<3) +#define IB_MCR_COMPMASK_MTU_SEL (1ULL<<4) +#define IB_MCR_COMPMASK_MTU (1ULL<<5) +#define IB_MCR_COMPMASK_TCLASS (1ULL<<6) +#define IB_MCR_COMPMASK_PKEY (1ULL<<7) +#define IB_MCR_COMPMASK_RATE_SEL (1ULL<<8) +#define IB_MCR_COMPMASK_RATE (1ULL<<9) +#define IB_MCR_COMPMASK_LIFE_SEL (1ULL<<10) +#define IB_MCR_COMPMASK_LIFE (1ULL<<11) +#define IB_MCR_COMPMASK_SL (1ULL<<12) +#define IB_MCR_COMPMASK_FLOW (1ULL<<13) +#define IB_MCR_COMPMASK_HOP (1ULL<<14) +#define IB_MCR_COMPMASK_SCOPE (1ULL<<15) +#define IB_MCR_COMPMASK_JOIN_STATE (1ULL<<16) +#define IB_MCR_COMPMASK_PROXY (1ULL<<17) + +static ibmad_gid_t mgid_ipoib = { + 0xff, 0x12, 0x40, 0x1b, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff +}; + +uint64_t build_mcm_rec(uint8_t *data, ibmad_gid_t mgid, ibmad_gid_t port_gid) +{ + memset(data, 0, IB_SA_DATA_SIZE); + mad_set_array(data, 0, IB_SA_MCM_MGID_F, mgid); + mad_set_array(data, 0, IB_SA_MCM_PORTGID_F, port_gid); + mad_set_field(data, 0, IB_SA_MCM_JOIN_STATE_F, 1); + + return IB_MCR_COMPMASK_MGID|IB_MCR_COMPMASK_PORT_GID| + IB_MCR_COMPMASK_JOIN_STATE; +} + +static void build_mcm_rec_umad(void *umad, ib_portid_t *dport, int method, + uint64_t comp_mask, uint8_t *data) +{ + ib_rpc_t rpc; + + memset(&rpc, 0, sizeof(rpc)); + rpc.mgtclass = IB_SA_CLASS; + rpc.method = method; + rpc.attr.id = IB_SA_ATTR_MCRECORD; + rpc.attr.mod = 0; // ??? + rpc.mask = comp_mask; + rpc.datasz = IB_SA_DATA_SIZE; + rpc.dataoffs = IB_SA_DATA_OFFS; + + mad_build_pkt(umad, &rpc, dport, NULL, data); +} + +static int rereg_send(int port, int agent, ib_portid_t *dport, + uint8_t *umad, int len, int method, ibmad_gid_t port_gid) +{ + uint8_t data[IB_SA_DATA_SIZE]; + uint64_t comp_mask; + + comp_mask = build_mcm_rec(data, mgid_ipoib, port_gid); + + build_mcm_rec_umad(umad, dport, method, comp_mask, data); + if(umad_send(port, agent, umad, len, TMO, 0) < 0) { + err("umad_send leave failed: %s\n", strerror(errno)); + return -1; + } + dbg("umad_send %d: tid = 0x%016" PRIx64 "\n", method, + mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F)); + + return 0; +} + +static int rereg_port_gid(int port, int agent, ib_portid_t *dport, + uint8_t *umad, int len, ibmad_gid_t port_gid) +{ + uint8_t data[IB_SA_DATA_SIZE]; + uint64_t comp_mask; + + comp_mask = build_mcm_rec(data, mgid_ipoib, port_gid); + + build_mcm_rec_umad(umad, dport, IB_MAD_METHOD_DELETE, + comp_mask, data); + if(umad_send(port, agent, umad, len, TMO, 0) < 0) { + err("umad_send leave failed: %s\n", strerror(errno)); + return -1; + } + dbg("umad_send leave: tid = 0x%016" PRIx64 "\n", + mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F)); + + build_mcm_rec_umad(umad, dport, IB_MAD_METHOD_SET, + comp_mask, data); + if(umad_send(port, agent, umad, len, TMO, 0) < 0) { + err("umad_send join failed: %s\n", strerror(errno)); + return -1; + } + dbg("umad_send join: tid = 0x%016" PRIx64 "\n", + mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F)); + + return 0; +} + +struct guid_trid { + ibmad_gid_t gid; + uint64_t guid; + uint64_t trid; +}; + +static int rereg_send_all(int port, int agent, ib_portid_t *dport, + struct guid_trid *list, unsigned cnt) +{ + uint8_t *umad; + int len = umad_size() + 256; + int i, ret; + + info("rereg_send_all... cnt = %u\n", cnt); + + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + + for (i = 0; i < cnt; i++) { + ret = rereg_port_gid(port, agent, dport, umad, len, list[i].gid); + if (ret < 0) { + err("rereg_send_all: rereg_port_gid 0x%016" PRIx64 + " failed\n", list[i].guid); + continue; + } + list[i].trid = mad_get_field64(umad_get_mad(umad), 0, + IB_MAD_TRID_F); + } + + info("rereg_send_all: sent %u requests\n", cnt*2); + + free(umad); + + return 0; +} + +#if 0 +static int rereg_mcm_rec_send(int port, int agent, ib_portid_t *dport, int cnt) +{ + ib_portid_t portid; + ibmad_gid_t port_gid; + uint8_t *umad; + int len, ret = 0; + + ib_resolve_self(&portid, NULL, &port_gid); + + len = umad_size() + 256; + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + + while(cnt--) { + if (!rereg_port_gid(port, agent, dport, umad, len, port_gid)) + ret += 2; + } + + free(umad); + + return ret; +} +#endif + +static int rereg_recv(int port, int agent, ib_portid_t *dport, + uint8_t *umad, int length, int tmo) +{ + int ret, retry = 0; + int len = length; + + while((ret = umad_recv(port, umad, &len, tmo)) < 0 && + errno == ETIMEDOUT) { + if (retry++ > 3) + return 0; + } + if (ret < 0) { + err("umad_recv %d failed: %s\n", ret, strerror(errno)); + return -1; + } + dbg("umad_recv (retries %d), tid = 0x%016" PRIx64 ": len = %d, status = %d\n", + retry, + mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F), + len, umad_status(umad)); + + return 1; +} + +static int rereg_recv_all(int port, int agent, ib_portid_t *dport, + struct guid_trid *list, unsigned cnt) +{ + uint8_t *umad, *mad; + int len = umad_size() + 256; + uint64_t trid; + unsigned n, method, status; + int i; + + info("rereg_recv_all...\n"); + + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + + n = 0; + while (rereg_recv(port, agent, dport, umad, len, TMO) > 0) { + dbg("rereg_recv_all: done %d\n", n); + n++; + mad = umad_get_mad(umad); + + method = mad_get_field(mad, 0, IB_MAD_METHOD_F); + status = mad_get_field(mad, 0, IB_MAD_STATUS_F); + + if (status) + dbg("MAD status %x, method %x\n", status, method); + + if (status && + (method&0x7f) == (IB_MAD_METHOD_GET_RESPONSE&0x7f)) { + trid = mad_get_field64(mad, 0, IB_MAD_TRID_F); + for (i = 0; i < cnt; i++) + if (trid == list[i].trid) + break; + if (i == cnt) { + err("cannot find trid 0x%016" PRIx64 "\n", + trid); + continue; + } + info("guid 0x%016" PRIx64 ": method = %x status = %x. Resending\n", + ntohll(list[i].guid), method, status); + rereg_port_gid(port, agent, dport, umad, len, + list[i].gid); + list[i].trid = mad_get_field64(umad_get_mad(umad), 0, + IB_MAD_TRID_F); + } + } + + info("rereg_recv_all: got %u responses\n", n); + + free(umad); + return 0; +} + +static int rereg_query_all(int port, int agent, ib_portid_t *dport, + struct guid_trid *list, unsigned cnt) +{ + uint8_t *umad, *mad; + int len = umad_size() + 256; + unsigned method, status; + int i, ret; + + info("rereg_query_all...\n"); + + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + + for ( i = 0; i < cnt; i++ ) { + ret = rereg_send(port, agent, dport, umad, len, + IB_MAD_METHOD_GET, list[i].gid); + if (ret < 0) { + err("query_all: rereg_send failed.\n"); + continue; + } + + ret = rereg_recv(port, agent, dport, umad, len, TMO); + if (ret < 0) { + err("query_all: rereg_recv failed.\n"); + continue; + } + + mad = umad_get_mad(umad); + + method = mad_get_field(mad, 0, IB_MAD_METHOD_F); + status = mad_get_field(mad, 0, IB_MAD_STATUS_F); + + if (status) + info("guid 0x%016" PRIx64 ": status %x, method %x\n", + ntohll(list[i].guid), status, method); + } + + info("rereg_query_all: %u queried.\n", cnt); + + free(umad); + return 0; +} + +#if 0 +static int rereg_mcm_rec_recv(int port, int agent, int cnt) +{ + uint8_t *umad, *mad; + int len = umad_size() + 256; + int i; + + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + + for ( i = 0; i < cnt; i++ ) { + int retry; + retry = 0; + while (umad_recv(port, umad, &len, TMO) < 0 && + errno == ETIMEDOUT) + if (retry++ > 3) { + err("umad_recv %d failed: %s\n", + i, strerror(errno)); + free(umad); + return -1; + } + dbg("umad_recv %d (retries %d), tid = 0x%016" PRIx64 ": len = %d, status = %d\n", + i, retry, + mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F), + len, umad_status(umad)); + mad = umad_get_mad(umad); + } + + free(umad); + return 0; +} +#endif + +#define MAX_CLIENTS 50 + +static int rereg_and_test_port(char *guid_file, int port, int agent, ib_portid_t *dport, int timeout) +{ + char line[256]; + FILE *f; + ibmad_gid_t port_gid; + uint64_t prefix = htonll(0xfe80000000000000llu); + uint64_t guid = htonll(0x0002c90200223825llu); + struct guid_trid *list; + int i = 0; + + list = calloc(MAX_CLIENTS, sizeof(*list)); + if (!list) { + err("cannot alloc mem for guid/trid list: %s\n", strerror(errno)); + return -1; + } + + f = fopen(guid_file, "r"); + if (!f) { + err("cannot open %s: %s\n", guid_file, strerror(errno)); + return -1; + } + + while (fgets(line, sizeof(line), f)) { + guid = strtoull(line, NULL, 0); + guid = htonll(guid); + memcpy(&port_gid[0], &prefix, 8); + memcpy(&port_gid[8], &guid, 8); + + list[i].guid = guid; + memcpy(list[i].gid, port_gid, sizeof(list[i].gid)); + list[i].trid = 0; + if (++i >= MAX_CLIENTS) + break; + } + fclose(f); + + rereg_send_all(port, agent, dport, list, i); + rereg_recv_all(port, agent, dport, list, i); + + rereg_query_all(port, agent, dport, list, i); + + free(list); + return 0; +} + +int main(int argc, char **argv) +{ + char *guid_file = "port_guids.list"; + int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS}; + ib_portid_t dport_id; + int port, agent; + uint8_t *umad, *mad; + int len; + + if (argc > 1) + guid_file = argv[1]; + + madrpc_init(NULL, 0, mgmt_classes, 2); + +#if 1 + ib_resolve_smlid(&dport_id, TMO); +#else + memset(&dport_id, 0, sizeof(dport_id)); + dport_id.lid = 1; +#endif + dport_id.qp = 1; + if (!dport_id.qkey) + dport_id.qkey = IB_DEFAULT_QP1_QKEY; + + + len = umad_size() + 256; + umad = calloc(1, len); + if (!umad) { + err("cannot alloc mem for umad: %s\n", strerror(errno)); + return -1; + } + +#if 1 + port = madrpc_portid(); +#else + ret = umad_init(); + + port = umad_open_port(NULL, 0); + if (port < 0) { + err("umad_open_port failed: %s\n", strerror(errno)); + return port; + } +#endif + + agent = umad_register(port, IB_SA_CLASS, 2, 0, NULL); + +#if 0 + int cnt; + cnt = rereg_mcm_rec_send(port, agent, &dport_id, cnt); + + rereg_recv_all(port, agent, &dport_id); +#else + rereg_and_test_port(guid_file, port, agent, &dport_id, TMO); +#endif + mad = umad_get_mad(umad); + + free(umad); + umad_unregister(port, agent); + umad_close_port(port); + umad_done(); + + return 0; +} diff --git a/branches/winverbs/tools/infiniband_diags/src/perfquery.c b/branches/winverbs/tools/infiniband_diags/src/perfquery.c new file mode 100644 index 00000000..641e03a4 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/perfquery.c @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. + * Copyright (c) 2007 Xsigo Systems 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. + * + */ + +#if defined(_WIN32) +#include +#include +#include "..\..\..\..\etc\user\getopt.c" +#else + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#endif + +#include +#include + +#include "ibdiag_common.h" + +struct perf_count { + uint32_t portselect; + uint32_t counterselect; + uint32_t symbolerrors; + uint32_t linkrecovers; + uint32_t linkdowned; + uint32_t rcverrors; + uint32_t rcvremotephyerrors; + uint32_t rcvswrelayerrors; + uint32_t xmtdiscards; + uint32_t xmtconstrainterrors; + uint32_t rcvconstrainterrors; + uint32_t linkintegrityerrors; + uint32_t excbufoverrunerrors; + uint32_t vl15dropped; + uint32_t xmtdata; + uint32_t rcvdata; + uint32_t xmtpkts; + uint32_t rcvpkts; +}; + +struct perf_count_ext { + uint32_t portselect; + uint32_t counterselect; + uint64_t portxmitdata; + uint64_t portrcvdata; + uint64_t portxmitpkts; + uint64_t portrcvpkts; + uint64_t portunicastxmitpkts; + uint64_t portunicastrcvpkts; + uint64_t portmulticastxmitpkits; + uint64_t portmulticastrcvpkts; +}; + +static uint8_t pc[1024]; + +struct perf_count perf_count = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +struct perf_count_ext perf_count_ext = {0,0,0,0,0,0,0,0,0,0}; + +char *argv0 = "perfquery"; + +#define ALL_PORTS 0xFF + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -G(uid) -a(ll_ports) -l(oop_ports) -r(eset_after_read) -C ca_name -P ca_port " + "-R(eset_only) -t(imeout) timeout_ms -V(ersion) -h(elp)] [ [[port] [reset_mask]]]\n", + basename); + fprintf(stderr, "\tExamples:\n"); + fprintf(stderr, "\t\t%s\t\t# read local port's performance counters\n", basename); + fprintf(stderr, "\t\t%s 32 1\t\t# read performance counters from lid 32, port 1\n", basename); + fprintf(stderr, "\t\t%s -e 32 1\t# read extended performance counters from lid 32, port 1\n", basename); + fprintf(stderr, "\t\t%s -a 32\t\t# read performance counters from lid 32, all ports\n", basename); + fprintf(stderr, "\t\t%s -r 32 1\t# read performance counters and reset\n", basename); + fprintf(stderr, "\t\t%s -e -r 32 1\t# read extended performance counters and reset\n", basename); + fprintf(stderr, "\t\t%s -R 0x20 1\t# reset performance counters of port 1 only\n", basename); + fprintf(stderr, "\t\t%s -e -R 0x20 1\t# reset extended performance counters of port 1 only\n", basename); + fprintf(stderr, "\t\t%s -R -a 32\t# reset performance counters of all ports\n", basename); + fprintf(stderr, "\t\t%s -R 32 2 0x0fff\t# reset only error counters of port 2\n", basename); + fprintf(stderr, "\t\t%s -R 32 2 0xf000\t# reset only non-error counters of port 2\n", basename); + exit(-1); +} + +/* Notes: IB semantics is to cap counters if count has exceeded limits. + * Therefore we must check for overflows and cap the counters if necessary. + * + * mad_decode_field and mad_encode_field assume 32 bit integers passed in + * for fields < 32 bits in length. + */ + +static void aggregate_4bit(uint32_t *dest, uint32_t val) +{ + if ((((*dest) + val) < (*dest)) + || ((*dest) + val) > 0xf) + (*dest) = 0xf; + else + (*dest) = (*dest) + val; +} + +static void aggregate_8bit(uint32_t *dest, uint32_t val) +{ + if ((((*dest) + val) < (*dest)) + || ((*dest) + val) > 0xff) + (*dest) = 0xff; + else + (*dest) = (*dest) + val; +} + +static void aggregate_16bit(uint32_t *dest, uint32_t val) +{ + if ((((*dest) + val) < (*dest)) + || ((*dest) + val) > 0xffff) + (*dest) = 0xffff; + else + (*dest) = (*dest) + val; +} + +static void aggregate_32bit(uint32_t *dest, uint32_t val) +{ + if (((*dest) + val) < (*dest)) + (*dest) = 0xffffffff; + else + (*dest) = (*dest) + val; +} + +static void aggregate_64bit(uint64_t *dest, uint64_t val) +{ + if (((*dest) + val) < (*dest)) + (*dest) = 0xffffffffffffffffULL; + else + (*dest) = (*dest) + val; +} + +static void aggregate_perfcounters(void) +{ + uint32_t val; + + mad_decode_field(pc, IB_PC_PORT_SELECT_F, &val); + perf_count.portselect = val; + mad_decode_field(pc, IB_PC_COUNTER_SELECT_F, &val); + perf_count.counterselect = val; + mad_decode_field(pc, IB_PC_ERR_SYM_F, &val); + aggregate_16bit(&perf_count.symbolerrors, val); + mad_decode_field(pc, IB_PC_LINK_RECOVERS_F, &val); + aggregate_8bit(&perf_count.linkrecovers, val); + mad_decode_field(pc, IB_PC_LINK_DOWNED_F, &val); + aggregate_8bit(&perf_count.linkdowned, val); + mad_decode_field(pc, IB_PC_ERR_RCV_F, &val); + aggregate_16bit(&perf_count.rcverrors, val); + mad_decode_field(pc, IB_PC_ERR_PHYSRCV_F, &val); + aggregate_16bit(&perf_count.rcvremotephyerrors, val); + mad_decode_field(pc, IB_PC_ERR_SWITCH_REL_F, &val); + aggregate_16bit(&perf_count.rcvswrelayerrors, val); + mad_decode_field(pc, IB_PC_XMT_DISCARDS_F, &val); + aggregate_16bit(&perf_count.xmtdiscards, val); + mad_decode_field(pc, IB_PC_ERR_XMTCONSTR_F, &val); + aggregate_8bit(&perf_count.xmtconstrainterrors, val); + mad_decode_field(pc, IB_PC_ERR_RCVCONSTR_F, &val); + aggregate_8bit(&perf_count.rcvconstrainterrors, val); + mad_decode_field(pc, IB_PC_ERR_LOCALINTEG_F, &val); + aggregate_4bit(&perf_count.linkintegrityerrors, val); + mad_decode_field(pc, IB_PC_ERR_EXCESS_OVR_F, &val); + aggregate_4bit(&perf_count.excbufoverrunerrors, val); + mad_decode_field(pc, IB_PC_VL15_DROPPED_F, &val); + aggregate_16bit(&perf_count.vl15dropped, val); + mad_decode_field(pc, IB_PC_XMT_BYTES_F, &val); + aggregate_32bit(&perf_count.xmtdata, val); + mad_decode_field(pc, IB_PC_RCV_BYTES_F, &val); + aggregate_32bit(&perf_count.rcvdata, val); + mad_decode_field(pc, IB_PC_XMT_PKTS_F, &val); + aggregate_32bit(&perf_count.xmtpkts, val); + mad_decode_field(pc, IB_PC_RCV_PKTS_F, &val); + aggregate_32bit(&perf_count.rcvpkts, val); +} + +static void output_aggregate_perfcounters(ib_portid_t *portid) +{ + char buf[1024]; + uint32_t val = ALL_PORTS; + + /* set port_select to 255 to emulate AllPortSelect */ + mad_encode_field(pc, IB_PC_PORT_SELECT_F, &val); + mad_encode_field(pc, IB_PC_COUNTER_SELECT_F, &perf_count.counterselect); + mad_encode_field(pc, IB_PC_ERR_SYM_F, &perf_count.symbolerrors); + mad_encode_field(pc, IB_PC_LINK_RECOVERS_F, &perf_count.linkrecovers); + mad_encode_field(pc, IB_PC_LINK_DOWNED_F, &perf_count.linkdowned); + mad_encode_field(pc, IB_PC_ERR_RCV_F, &perf_count.rcverrors); + mad_encode_field(pc, IB_PC_ERR_PHYSRCV_F, &perf_count.rcvremotephyerrors); + mad_encode_field(pc, IB_PC_ERR_SWITCH_REL_F, &perf_count.rcvswrelayerrors); + mad_encode_field(pc, IB_PC_XMT_DISCARDS_F, &perf_count.xmtdiscards); + mad_encode_field(pc, IB_PC_ERR_XMTCONSTR_F, &perf_count.xmtconstrainterrors); + mad_encode_field(pc, IB_PC_ERR_RCVCONSTR_F, &perf_count.rcvconstrainterrors); + mad_encode_field(pc, IB_PC_ERR_LOCALINTEG_F, &perf_count.linkintegrityerrors); + mad_encode_field(pc, IB_PC_ERR_EXCESS_OVR_F, &perf_count.excbufoverrunerrors); + mad_encode_field(pc, IB_PC_VL15_DROPPED_F, &perf_count.vl15dropped); + mad_encode_field(pc, IB_PC_XMT_BYTES_F, &perf_count.xmtdata); + mad_encode_field(pc, IB_PC_RCV_BYTES_F, &perf_count.rcvdata); + mad_encode_field(pc, IB_PC_XMT_PKTS_F, &perf_count.xmtpkts); + mad_encode_field(pc, IB_PC_RCV_PKTS_F, &perf_count.rcvpkts); + + mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc); + + printf("# Port counters: %s port %d\n%s", portid2str(portid), ALL_PORTS, buf); +} + +static void aggregate_perfcounters_ext(void) +{ + uint32_t val; + uint64_t val64; + + mad_decode_field(pc, IB_PC_EXT_PORT_SELECT_F, &val); + perf_count_ext.portselect = val; + mad_decode_field(pc, IB_PC_EXT_COUNTER_SELECT_F, &val); + perf_count_ext.counterselect = val; + mad_decode_field(pc, IB_PC_EXT_XMT_BYTES_F, &val64); + aggregate_64bit(&perf_count_ext.portxmitdata, val64); + mad_decode_field(pc, IB_PC_EXT_RCV_BYTES_F, &val64); + aggregate_64bit(&perf_count_ext.portrcvdata, val64); + mad_decode_field(pc, IB_PC_EXT_XMT_PKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portxmitpkts, val64); + mad_decode_field(pc, IB_PC_EXT_RCV_PKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portrcvpkts, val64); + mad_decode_field(pc, IB_PC_EXT_XMT_UPKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portunicastxmitpkts, val64); + mad_decode_field(pc, IB_PC_EXT_RCV_UPKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portunicastrcvpkts, val64); + mad_decode_field(pc, IB_PC_EXT_XMT_MPKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portmulticastxmitpkits, val64); + mad_decode_field(pc, IB_PC_EXT_RCV_MPKTS_F, &val64); + aggregate_64bit(&perf_count_ext.portmulticastrcvpkts, val64); +} + +static void output_aggregate_perfcounters_ext(ib_portid_t *portid) +{ + char buf[1024]; + uint32_t val = ALL_PORTS; + + /* set port_select to 255 to emulate AllPortSelect */ + mad_encode_field(pc, IB_PC_EXT_PORT_SELECT_F, &val); + mad_encode_field(pc, IB_PC_EXT_COUNTER_SELECT_F, &perf_count_ext.counterselect); + mad_encode_field(pc, IB_PC_EXT_XMT_BYTES_F, &perf_count_ext.portxmitdata); + mad_encode_field(pc, IB_PC_EXT_RCV_BYTES_F, &perf_count_ext.portrcvdata); + mad_encode_field(pc, IB_PC_EXT_XMT_PKTS_F, &perf_count_ext.portxmitpkts); + mad_encode_field(pc, IB_PC_EXT_RCV_PKTS_F, &perf_count_ext.portrcvpkts); + mad_encode_field(pc, IB_PC_EXT_XMT_UPKTS_F, &perf_count_ext.portunicastxmitpkts); + mad_encode_field(pc, IB_PC_EXT_RCV_UPKTS_F, &perf_count_ext.portunicastrcvpkts); + mad_encode_field(pc, IB_PC_EXT_XMT_MPKTS_F, &perf_count_ext.portmulticastxmitpkits); + mad_encode_field(pc, IB_PC_EXT_RCV_MPKTS_F, &perf_count_ext.portmulticastrcvpkts); + + mad_dump_perfcounters_ext(buf, sizeof buf, pc, sizeof pc); + + printf("# Port counters: %s port %d\n%s", portid2str(portid), ALL_PORTS, buf); +} + +static void dump_perfcounters(int extended, int timeout, uint16_t cap_mask, ib_portid_t *portid, + int port, int aggregate) +{ + char buf[1024]; + + if (extended != 1) { + if (!port_performance_query(pc, portid, port, timeout)) + IBERROR("perfquery"); + if (aggregate) + aggregate_perfcounters(); + else + mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc); + } else { + if (!(cap_mask & 0x200)) /* 1.2 errata: bit 9 is extended counter support */ + IBWARN("PerfMgt ClassPortInfo 0x%x extended counters not indicated\n", cap_mask); + + if (!port_performance_ext_query(pc, portid, port, timeout)) + IBERROR("perfextquery"); + if (aggregate) + aggregate_perfcounters_ext(); + else + mad_dump_perfcounters_ext(buf, sizeof buf, pc, sizeof pc); + } + + if (!aggregate) + printf("# Port counters: %s port %d\n%s", portid2str(portid), port, buf); +} + +static void reset_counters(int extended, int timeout, int mask, ib_portid_t *portid, int port) +{ + if (extended != 1) { + if (!port_performance_reset(pc, portid, port, mask, timeout)) + IBERROR("perf reset"); + } else { + if (!port_performance_ext_reset(pc, portid, port, mask, timeout)) + IBERROR("perf ext reset"); + } +} + +int __cdecl +main(int argc, char **argv) +{ + int mgmt_classes[4] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, IB_PERFORMANCE_CLASS}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + ib_portid_t portid = {0}; + extern int ibdebug; + int dest_type = IB_DEST_LID; + int timeout = 0; /* use default */ + int mask = 0xffff, all_ports = 0; + int reset = 0, reset_only = 0; + int port = 0; + int udebug = 0; + char *ca = 0; + int ca_port = 0; + int extended = 0; + uint16_t cap_mask; + int all_ports_loop = 0; + int loop_ports = 0; + int node_type, num_ports = 0; + uint8_t data[IB_SMP_DATA_SIZE]; + int start_port = 1; + int enhancedport0; + int i; + + static char str_opts[] = "C:P:s:t:dGealrRVhu"; + static struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "Guid", 0, 0, 'G'}, + { "extended", 0, 0, 'e'}, + { "all_ports", 0, 0, 'a'}, + { "loop_ports", 0, 0, 'l'}, + { "reset_after_read", 0, 0, 'r'}, + { "Reset_only", 0, 0, 'R'}, + { "sm_portid", 1, 0, 's'}, + { "timeout", 1, 0, 't'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { 0 } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'e': + extended = 1; + break; + case 'a': + all_ports++; + port = ALL_PORTS; + break; + case 'l': + loop_ports++; + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 'r': + reset++; + break; + case 'R': + reset_only++; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + port = strtoul(argv[1], 0, 0); + if (argc > 2) + mask = strtoul(argv[2], 0, 0); + + madrpc_init(ca, ca_port, mgmt_classes, 4); + + if (argc) { + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_self(&portid, &port, 0) < 0) + IBERROR("can't resolve self port %s", argv[0]); + } + + /* PerfMgt ClassPortInfo is a required attribute */ + if (!perf_classportinfo_query(pc, &portid, port, timeout)) + IBERROR("classportinfo query"); + /* ClassPortInfo should be supported as part of libibmad */ + memcpy(&cap_mask, pc+2, sizeof(cap_mask)); /* CapabilityMask */ + cap_mask = ntohs(cap_mask); + if (!(cap_mask & 0x100)) { /* bit 8 is AllPortSelect */ + if (!all_ports && port == ALL_PORTS) + IBERROR("AllPortSelect not supported"); + if (all_ports) + all_ports_loop = 1; + } + + if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { + if (smp_query(data, &portid, IB_ATTR_NODE_INFO, 0, 0) < 0) + IBERROR("smp query nodeinfo failed"); + node_type = mad_get_field(data, 0, IB_NODE_TYPE_F); + mad_decode_field(data, IB_NODE_NPORTS_F, &num_ports); + if (!num_ports) + IBERROR("smp query nodeinfo: num ports invalid"); + + if (node_type == IB_NODE_SWITCH) { + if (smp_query(data, &portid, IB_ATTR_SWITCH_INFO, 0, 0) < 0) + IBERROR("smp query nodeinfo failed"); + enhancedport0 = mad_get_field(data, 0, IB_SW_ENHANCED_PORT0_F); + if (enhancedport0) + start_port = 0; + } + if (all_ports_loop && !loop_ports) + IBWARN("Emulating AllPortSelect by iterating through all ports"); + } + + if (reset_only) + goto do_reset; + + if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { + for (i = start_port; i <= num_ports; i++) + dump_perfcounters(extended, timeout, cap_mask, &portid, i, + (all_ports_loop && !loop_ports)); + if (all_ports_loop && !loop_ports) { + if (extended != 1) + output_aggregate_perfcounters(&portid); + else + output_aggregate_perfcounters_ext(&portid); + } + } + else + dump_perfcounters(extended, timeout, cap_mask, &portid, port, 0); + + if (!reset) + exit(0); + +do_reset: + + if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { + for (i = start_port; i <= num_ports; i++) + reset_counters(extended, timeout, mask, &portid, i); + } + else + reset_counters(extended, timeout, mask, &portid, port); + + exit(0); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/perfquery/SOURCES b/branches/winverbs/tools/infiniband_diags/src/perfquery/SOURCES new file mode 100644 index 00000000..30ebc335 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/perfquery/SOURCES @@ -0,0 +1,32 @@ +TARGETNAME = perfquery +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = ..\perfquery.c ..\ibdiag_common.c + +INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + diff --git a/branches/winverbs/tools/infiniband_diags/src/saquery.c b/branches/winverbs/tools/infiniband_diags/src/saquery.c new file mode 100644 index 00000000..fa895bb1 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/saquery.c @@ -0,0 +1,1830 @@ +/* + * Copyright (c) 2006,2007 The Regents of the University of California. + * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. + * + * Produced at Lawrence Livermore National Laboratory. + * Written by Ira Weiny . + * + * 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. + * + */ + +#if defined(_WIN32) || defined(_WIN64) + +#include +#include +#include +#include +#include +#include +#include +#include + +#else + +#include +#include +#include +#include +#include +#include +#include +#include + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#endif + +#include "ibdiag_common.h" + +struct query_cmd { + const char *name, *alias; + ib_net16_t query_type; + const char *usage; + int (*handler)(const struct query_cmd *q, osm_bind_handle_t bind_handle, + int argc, char *argv[]); +}; + +char *argv0 = "saquery"; + +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; +static ib_net64_t smkey = OSM_DEFAULT_SA_KEY; + +/** + * Declare some globals because I don't want this to be too complex. + */ +#define MAX_PORTS (8) +#define DEFAULT_SA_TIMEOUT_MS (1000) +osmv_query_res_t result; +osm_log_t log_osm; +osm_mad_pool_t mad_pool; +osm_vendor_t *vendor = NULL; +int osm_debug = 0; +uint32_t sa_timeout_ms = DEFAULT_SA_TIMEOUT_MS; +char *sa_hca_name = NULL; +uint32_t sa_port_num = 0; + +enum { + ALL, + LID_ONLY, + UNIQUE_LID_ONLY, + GUID_ONLY, + ALL_DESC, + NAME_OF_LID, + NAME_OF_GUID, +} node_print_desc = ALL; + +char *requested_name = NULL; +ib_net16_t requested_lid = 0; +int requested_lid_flag = 0; +ib_net64_t requested_guid = 0; +int requested_guid_flag = 0; + +/** + * Call back for the various record requests. + */ +static void +query_res_cb(osmv_query_res_t *res) +{ + result = *res; +} + +static void +print_node_desc(ib_node_record_t *node_record) +{ + ib_node_info_t *p_ni = &(node_record->node_info); + ib_node_desc_t *p_nd = &(node_record->node_desc); + + if (p_ni->node_type == IB_NODE_TYPE_CA) + { + printf("%6d \"%s\"\n", + cl_ntoh16(node_record->lid), + clean_nodedesc((char *)p_nd->description)); + } +} + +static void +print_node_record(ib_node_record_t *node_record) +{ + ib_node_info_t *p_ni = NULL; + ib_node_desc_t *p_nd = NULL; + char *name; + + p_ni = &(node_record->node_info); + p_nd = &(node_record->node_desc); + + switch (node_print_desc) { + case LID_ONLY: + case UNIQUE_LID_ONLY: + printf("%d\n", cl_ntoh16(node_record->lid)); + return; + case GUID_ONLY: + printf("0x%016" PRIx64 "\n", cl_ntoh64(p_ni->port_guid)); + return; + case NAME_OF_LID: + case NAME_OF_GUID: + name = remap_node_name(node_name_map, + cl_ntoh64(p_ni->node_guid), + (char *)p_nd->description); + printf("%s\n", name); + free(name); + return; + case ALL: + default: + break; + } + + printf("NodeRecord dump:\n" + "\t\tlid.....................0x%X\n" + "\t\treserved................0x%X\n" + "\t\tbase_version............0x%X\n" + "\t\tclass_version...........0x%X\n" + "\t\tnode_type...............%s\n" + "\t\tnum_ports...............0x%X\n" + "\t\tsys_guid................0x%016" PRIx64 "\n" + "\t\tnode_guid...............0x%016" PRIx64 "\n" + "\t\tport_guid...............0x%016" PRIx64 "\n" + "\t\tpartition_cap...........0x%X\n" + "\t\tdevice_id...............0x%X\n" + "\t\trevision................0x%X\n" + "\t\tport_num................0x%X\n" + "\t\tvendor_id...............0x%X\n" + "\t\tNodeDescription.........%s\n" + "", + cl_ntoh16(node_record->lid), + cl_ntoh16(node_record->resv), + p_ni->base_version, + p_ni->class_version, + ib_get_node_type_str( p_ni->node_type ), + p_ni->num_ports, + cl_ntoh64( p_ni->sys_guid ), + cl_ntoh64( p_ni->node_guid ), + cl_ntoh64( p_ni->port_guid ), + cl_ntoh16( p_ni->partition_cap ), + cl_ntoh16( p_ni->device_id ), + cl_ntoh32( p_ni->revision ), + ib_node_info_get_local_port_num( p_ni ), + cl_ntoh32( ib_node_info_get_vendor_id( p_ni )), + clean_nodedesc((char *)node_record->node_desc.description) + ); +} + +static void dump_path_record(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_path_rec_t *p_pr = data; + printf("PathRecord dump:\n" + "\t\tservice_id..............0x%016" PRIx64 "\n" + "\t\tdgid....................%s\n" + "\t\tsgid....................%s\n" + "\t\tdlid....................0x%X\n" + "\t\tslid....................0x%X\n" + "\t\thop_flow_raw............0x%X\n" + "\t\ttclass..................0x%X\n" + "\t\tnum_path_revers.........0x%X\n" + "\t\tpkey....................0x%X\n" + "\t\tqos_class...............0x%X\n" + "\t\tsl......................0x%X\n" + "\t\tmtu.....................0x%X\n" + "\t\trate....................0x%X\n" + "\t\tpkt_life................0x%X\n" + "\t\tpreference..............0x%X\n" + "\t\tresv2...................0x%X\n" + "\t\tresv3...................0x%X\n" + "", + cl_ntoh64( p_pr->service_id ), + inet_ntop(AF_INET6, p_pr->dgid.raw, gid_str, sizeof gid_str), + inet_ntop(AF_INET6, p_pr->sgid.raw, gid_str2, sizeof gid_str2), + cl_ntoh16( p_pr->dlid ), + cl_ntoh16( p_pr->slid ), + cl_ntoh32( p_pr->hop_flow_raw ), + p_pr->tclass, + p_pr->num_path, + cl_ntoh16( p_pr->pkey ), + ib_path_rec_qos_class( p_pr ), + ib_path_rec_sl( p_pr ), + p_pr->mtu, + p_pr->rate, + p_pr->pkt_life, + p_pr->preference, + *(uint32_t*)&p_pr->resv2, + *((uint16_t*)&p_pr->resv2 + 2) + ); +} + +static void dump_class_port_info(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_class_port_info_t *class_port_info = data; + + printf("SA ClassPortInfo:\n" + "\t\tBase version.............%d\n" + "\t\tClass version............%d\n" + "\t\tCapability mask..........0x%04X\n" + "\t\tCapability mask 2........0x%08X\n" + "\t\tResponse time value......0x%02X\n" + "\t\tRedirect GID.............%s\n" + "\t\tRedirect TC/SL/FL........0x%08X\n" + "\t\tRedirect LID.............0x%04X\n" + "\t\tRedirect PKey............0x%04X\n" + "\t\tRedirect QP..............0x%08X\n" + "\t\tRedirect QKey............0x%08X\n" + "\t\tTrap GID.................%s\n" + "\t\tTrap TC/SL/FL............0x%08X\n" + "\t\tTrap LID.................0x%04X\n" + "\t\tTrap PKey................0x%04X\n" + "\t\tTrap HL/QP...............0x%08X\n" + "\t\tTrap QKey................0x%08X\n" + "", + class_port_info->base_ver, + class_port_info->class_ver, + cl_ntoh16(class_port_info->cap_mask), + ib_class_cap_mask2(class_port_info), + ib_class_resp_time_val(class_port_info), + inet_ntop(AF_INET6, &(class_port_info->redir_gid), gid_str, + sizeof gid_str), + cl_ntoh32(class_port_info->redir_tc_sl_fl), + cl_ntoh16(class_port_info->redir_lid), + cl_ntoh16(class_port_info->redir_pkey), + cl_ntoh32(class_port_info->redir_qp), + cl_ntoh32(class_port_info->redir_qkey), + inet_ntop(AF_INET6, &(class_port_info->trap_gid), gid_str2, + sizeof gid_str2), + cl_ntoh32(class_port_info->trap_tc_sl_fl), + cl_ntoh16(class_port_info->trap_lid), + cl_ntoh16(class_port_info->trap_pkey), + cl_ntoh32(class_port_info->trap_hop_qp), + cl_ntoh32(class_port_info->trap_qkey) + ); +} + +static void dump_portinfo_record(void *data) +{ + ib_portinfo_record_t *p_pir = data; + const ib_port_info_t * const p_pi = &p_pir->port_info; + + printf("PortInfoRecord dump:\n" + "\t\tEndPortLid..............0x%X\n" + "\t\tPortNum.................0x%X\n" + "\t\tbase_lid................0x%X\n" + "\t\tmaster_sm_base_lid......0x%X\n" + "\t\tcapability_mask.........0x%X\n" + "", + cl_ntoh16(p_pir->lid), + p_pir->port_num, + cl_ntoh16( p_pi->base_lid ), + cl_ntoh16( p_pi->master_sm_base_lid ), + cl_ntoh32( p_pi->capability_mask ) + ); +} + +static void dump_multicast_group_record(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + ib_member_rec_t *p_mcmr = data; + uint8_t sl; + ib_member_get_sl_flow_hop(p_mcmr->sl_flow_hop, &sl, NULL, NULL); + printf("MCMemberRecord group dump:\n" + "\t\tMGID....................%s\n" + "\t\tMlid....................0x%X\n" + "\t\tMtu.....................0x%X\n" + "\t\tpkey....................0x%X\n" + "\t\tRate....................0x%X\n" + "\t\tSL......................0x%X\n" + "", + inet_ntop(AF_INET6, p_mcmr->mgid.raw, gid_str, sizeof gid_str), + cl_ntoh16( p_mcmr->mlid ), + p_mcmr->mtu, + cl_ntoh16( p_mcmr->pkey ), + p_mcmr->rate, + sl + ); +} + +static void dump_multicast_member_record(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_member_rec_t *p_mcmr = data; + uint16_t mlid = cl_ntoh16( p_mcmr->mlid ); + int i = 0; + char *node_name = ""; + + /* go through the node records searching for a port guid which matches + * this port gid interface id. + * This gives us a node name to print, if available. + */ + for (i = 0; i < result.result_cnt; i++) { + ib_node_record_t *nr = osmv_get_query_node_rec(result.p_result_madw, i); + if (nr->node_info.port_guid == p_mcmr->port_gid.unicast.interface_id) { + node_name = clean_nodedesc((char *)nr->node_desc.description); + break; + } + } + + if (requested_name) { + if (strtol(requested_name, NULL, 0) == mlid) { + printf("\t\tPortGid.................%s (%s)\n", + inet_ntop(AF_INET6, p_mcmr->port_gid.raw, + gid_str, sizeof gid_str), + node_name + ); + } + } else { + printf("MCMemberRecord member dump:\n" + "\t\tMGID....................%s\n" + "\t\tMlid....................0x%X\n" + "\t\tPortGid.................%s\n" + "\t\tScopeState..............0x%X\n" + "\t\tProxyJoin...............0x%X\n" + "\t\tNodeDescription.........%s\n" + "", + inet_ntop(AF_INET6, p_mcmr->mgid.raw, gid_str, + sizeof gid_str), + cl_ntoh16( p_mcmr->mlid ), + inet_ntop(AF_INET6, p_mcmr->port_gid.raw, + gid_str2, sizeof gid_str2), + p_mcmr->scope_state, + p_mcmr->proxy_join, + node_name + ); + } +} + +static void dump_service_record(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char buf_service_key[35]; + char buf_service_name[65]; + ib_service_record_t *p_sr = data; + + sprintf(buf_service_key, + "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + p_sr->service_key[0], + p_sr->service_key[1], + p_sr->service_key[2], + p_sr->service_key[3], + p_sr->service_key[4], + p_sr->service_key[5], + p_sr->service_key[6], + p_sr->service_key[7], + p_sr->service_key[8], + p_sr->service_key[9], + p_sr->service_key[10], + p_sr->service_key[11], + p_sr->service_key[12], + p_sr->service_key[13], + p_sr->service_key[14], + p_sr->service_key[15]); + strncpy(buf_service_name, (char *)p_sr->service_name, 64); + buf_service_name[64] = '\0'; + + printf("ServiceRecord dump:\n" + "\t\tServiceID...............0x%016" PRIx64 "\n" + "\t\tServiceGID..............%s\n" + "\t\tServiceP_Key............0x%X\n" + "\t\tServiceLease............0x%X\n" + "\t\tServiceKey..............%s\n" + "\t\tServiceName.............%s\n" + "\t\tServiceData8.1..........0x%X\n" + "\t\tServiceData8.2..........0x%X\n" + "\t\tServiceData8.3..........0x%X\n" + "\t\tServiceData8.4..........0x%X\n" + "\t\tServiceData8.5..........0x%X\n" + "\t\tServiceData8.6..........0x%X\n" + "\t\tServiceData8.7..........0x%X\n" + "\t\tServiceData8.8..........0x%X\n" + "\t\tServiceData8.9..........0x%X\n" + "\t\tServiceData8.10.........0x%X\n" + "\t\tServiceData8.11.........0x%X\n" + "\t\tServiceData8.12.........0x%X\n" + "\t\tServiceData8.13.........0x%X\n" + "\t\tServiceData8.14.........0x%X\n" + "\t\tServiceData8.15.........0x%X\n" + "\t\tServiceData8.16.........0x%X\n" + "\t\tServiceData16.1.........0x%X\n" + "\t\tServiceData16.2.........0x%X\n" + "\t\tServiceData16.3.........0x%X\n" + "\t\tServiceData16.4.........0x%X\n" + "\t\tServiceData16.5.........0x%X\n" + "\t\tServiceData16.6.........0x%X\n" + "\t\tServiceData16.7.........0x%X\n" + "\t\tServiceData16.8.........0x%X\n" + "\t\tServiceData32.1.........0x%X\n" + "\t\tServiceData32.2.........0x%X\n" + "\t\tServiceData32.3.........0x%X\n" + "\t\tServiceData32.4.........0x%X\n" + "\t\tServiceData64.1.........0x%016" PRIx64 "\n" + "\t\tServiceData64.2.........0x%016" PRIx64 "\n" + "", + cl_ntoh64( p_sr->service_id ), + inet_ntop(AF_INET6, p_sr->service_gid.raw, gid_str, + sizeof gid_str), + cl_ntoh16( p_sr->service_pkey ), + cl_ntoh32( p_sr->service_lease ), + buf_service_key, + buf_service_name, + p_sr->service_data8[0], p_sr->service_data8[1], + p_sr->service_data8[2], p_sr->service_data8[3], + p_sr->service_data8[4], p_sr->service_data8[5], + p_sr->service_data8[6], p_sr->service_data8[7], + p_sr->service_data8[8], p_sr->service_data8[9], + p_sr->service_data8[10], p_sr->service_data8[11], + p_sr->service_data8[12], p_sr->service_data8[13], + p_sr->service_data8[14], p_sr->service_data8[15], + cl_ntoh16( p_sr->service_data16[0] ), + cl_ntoh16( p_sr->service_data16[1] ), + cl_ntoh16( p_sr->service_data16[2] ), + cl_ntoh16( p_sr->service_data16[3] ), + cl_ntoh16( p_sr->service_data16[4] ), + cl_ntoh16( p_sr->service_data16[5] ), + cl_ntoh16( p_sr->service_data16[6] ), + cl_ntoh16( p_sr->service_data16[7] ), + cl_ntoh32( p_sr->service_data32[0] ), + cl_ntoh32( p_sr->service_data32[1] ), + cl_ntoh32( p_sr->service_data32[2] ), + cl_ntoh32( p_sr->service_data32[3] ), + cl_ntoh64( p_sr->service_data64[0] ), + cl_ntoh64( p_sr->service_data64[1] ) + ); +} + +static void dump_inform_info_record(void *data) +{ + char gid_str[INET6_ADDRSTRLEN]; + char gid_str2[INET6_ADDRSTRLEN]; + ib_inform_info_record_t *p_iir = data; + uint32_t qpn; + uint8_t resp_time_val; + + ib_inform_info_get_qpn_resp_time(p_iir->inform_info.g_or_v.generic.qpn_resp_time_val, &qpn, &resp_time_val); + + if (p_iir->inform_info.is_generic) { + printf("InformInfoRecord dump:\n" + "\t\tRID\n" + "\t\tSubscriberGID...........%s\n" + "\t\tSubscriberEnum..........0x%X\n" + "\t\tInformInfo dump:\n" + "\t\tgid.....................%s\n" + "\t\tlid_range_begin.........0x%X\n" + "\t\tlid_range_end...........0x%X\n" + "\t\tis_generic..............0x%X\n" + "\t\tsubscribe...............0x%X\n" + "\t\ttrap_type...............0x%X\n" + "\t\ttrap_num................%u\n" + "\t\tqpn.....................0x%06X\n" + "\t\tresp_time_val...........0x%X\n" + "\t\tnode_type...............0x%06X\n" + "", + inet_ntop(AF_INET6, p_iir->subscriber_gid.raw, gid_str, + sizeof gid_str), + cl_ntoh16( p_iir->subscriber_enum ), + inet_ntop(AF_INET6, p_iir->inform_info.gid.raw, gid_str2, + sizeof gid_str2), + cl_ntoh16( p_iir->inform_info.lid_range_begin ), + cl_ntoh16( p_iir->inform_info.lid_range_end ), + p_iir->inform_info.is_generic, + p_iir->inform_info.subscribe, + cl_ntoh16( p_iir->inform_info.trap_type ), + cl_ntoh16( p_iir->inform_info.g_or_v.generic.trap_num ), + cl_ntoh32( qpn ), + resp_time_val, + cl_ntoh32(ib_inform_info_get_prod_type( &p_iir->inform_info )) + ); + } else { + printf("InformInfoRecord dump:\n" + "\t\tRID\n" + "\t\tSubscriberGID...........%s\n" + "\t\tSubscriberEnum..........0x%X\n" + "\t\tInformInfo dump:\n" + "\t\tgid.....................%s\n" + "\t\tlid_range_begin.........0x%X\n" + "\t\tlid_range_end...........0x%X\n" + "\t\tis_generic..............0x%X\n" + "\t\tsubscribe...............0x%X\n" + "\t\ttrap_type...............0x%X\n" + "\t\tdev_id..................0x%X\n" + "\t\tqpn.....................0x%06X\n" + "\t\tresp_time_val...........0x%X\n" + "\t\tvendor_id...............0x%06X\n" + "", + inet_ntop(AF_INET6, p_iir->subscriber_gid.raw, gid_str, + sizeof gid_str), + cl_ntoh16( p_iir->subscriber_enum ), + inet_ntop(AF_INET6, p_iir->inform_info.gid.raw, + gid_str2, sizeof gid_str2), + cl_ntoh16( p_iir->inform_info.lid_range_begin ), + cl_ntoh16( p_iir->inform_info.lid_range_end ), + p_iir->inform_info.is_generic, + p_iir->inform_info.subscribe, + cl_ntoh16( p_iir->inform_info.trap_type ), + cl_ntoh16( p_iir->inform_info.g_or_v.vend.dev_id ), + cl_ntoh32( qpn ), + resp_time_val, + cl_ntoh32(ib_inform_info_get_prod_type( &p_iir->inform_info )) + ); + } +} + +static void dump_one_link_record(void *data) +{ + ib_link_record_t *lr = data; + printf("LinkRecord dump:\n" + "\t\tFromLID....................%u\n" + "\t\tFromPort...................%u\n" + "\t\tToPort.....................%u\n" + "\t\tToLID......................%u\n", + cl_ntoh16(lr->from_lid), lr->from_port_num, + lr->to_port_num, cl_ntoh16(lr->to_lid)); +} + +static void dump_one_slvl_record(void *data) +{ + ib_slvl_table_record_t *slvl = data; + ib_slvl_table_t *t = &slvl->slvl_tbl; + printf("SL2VLTableRecord dump:\n" + "\t\tLID........................%u\n" + "\t\tInPort.....................%u\n" + "\t\tOutPort....................%u\n" + "\t\tSL: 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|\n" + "\t\tVL:%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u" + "|%2u|%2u|%2u|\n", + cl_ntoh16(slvl->lid), slvl->in_port_num, slvl->out_port_num, + ib_slvl_table_get(t, 0), ib_slvl_table_get(t, 1), + ib_slvl_table_get(t, 2), ib_slvl_table_get(t, 3), + ib_slvl_table_get(t, 4), ib_slvl_table_get(t, 5), + ib_slvl_table_get(t, 6), ib_slvl_table_get(t, 7), + ib_slvl_table_get(t, 8), ib_slvl_table_get(t, 9), + ib_slvl_table_get(t, 10), ib_slvl_table_get(t, 11), + ib_slvl_table_get(t, 12), ib_slvl_table_get(t, 13), + ib_slvl_table_get(t, 14), ib_slvl_table_get(t, 15)); +} + +static void dump_one_vlarb_record(void *data) +{ + ib_vl_arb_table_record_t *vlarb = data; + ib_vl_arb_element_t *e = vlarb->vl_arb_tbl.vl_entry; + int i; + printf("VLArbTableRecord dump:\n" + "\t\tLID........................%u\n" + "\t\tPort.......................%u\n" + "\t\tBlock......................%u\n", + cl_ntoh16(vlarb->lid), vlarb->port_num, vlarb->block_num); + for (i = 0; i < 32 ; i += 16) { + printf("\t\tVL :%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|" + "%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|", + e[i + 0].vl, e[i + 1].vl, e[i + 2].vl, e[i + 3].vl, + e[i + 4].vl, e[i + 5].vl, e[i + 6].vl, e[i + 7].vl, + e[i + 8].vl, e[i + 9].vl, e[i + 10].vl, e[i + 11].vl, + e[i + 12].vl, e[i + 13].vl, e[i + 14].vl, e[i + 15].vl); + printf("\n\t\tWeight:%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|" + "%2u|%2u|%2u|%2u|%2u|%2u|%2u|%2u|", + e[i + 0].weight, e[i + 1].weight, e[i + 2].weight, + e[i + 3].weight, e[i + 4].weight, e[i + 5].weight, + e[i + 6].weight, e[i + 7].weight, e[i + 8].weight, + e[i + 9].weight, e[i + 10].weight, e[i + 11].weight, + e[i + 12].weight, e[i + 13].weight, e[i + 14].weight, + e[i + 15].weight); + printf("\n"); + } +} + +static void dump_one_pkey_tbl_record(void *data) +{ + ib_pkey_table_record_t *pktr = data; + ib_net16_t *p = pktr->pkey_tbl.pkey_entry; + int i; + printf("PKeyTableRecord dump:\n" + "\t\tLID........................%u\n" + "\t\tPort.......................%u\n" + "\t\tBlock......................%u\n" + "\t\tPKey Table:\n", + cl_ntoh16(pktr->lid), pktr->port_num, pktr->block_num); + for (i = 0; i < 32 ; i += 8) + printf("\t\t0x%04x 0x%04x 0x%04x 0x%04x" + " 0x%04x 0x%04x 0x%04x 0x%04x\n", + cl_ntoh16(p[i + 0]), cl_ntoh16(p[i + 1]), + cl_ntoh16(p[i + 2]), cl_ntoh16(p[i + 3]), + cl_ntoh16(p[i + 4]), cl_ntoh16(p[i + 5]), + cl_ntoh16(p[i + 6]), cl_ntoh16(p[i + 7])); + printf("\n"); +} + +static void dump_one_lft_record(void *data) +{ + ib_lft_record_t *lftr = data; + unsigned block = cl_ntoh16(lftr->block_num); + int i; + printf("LFT Record dump:\n" + "\t\tLID........................%u\n" + "\t\tBlock......................%u\n" + "\t\tLFT:\n\t\tLID\tPort Number\n", + cl_ntoh16(lftr->lid), block); + for (i = 0; i < 64 ; i++) + printf("\t\t%u\t%u\n", block*64 + i, lftr->lft[i]); + printf("\n"); +} + +static void dump_one_mft_record(void *data) +{ + ib_mft_record_t *mftr = data; + unsigned position = cl_ntoh16(mftr->position_block_num) >> 12; + unsigned block = cl_ntoh16(mftr->position_block_num) & + IB_MCAST_BLOCK_ID_MASK_HO; + int i; + printf("MFT Record dump:\n" + "\t\tLID........................%u\n" + "\t\tPosition...................%u\n" + "\t\tBlock......................%u\n" + "\t\tMFT:\n\t\tMLID\tPort Mask\n", + cl_ntoh16(mftr->lid), position, block); + for (i = 0; i < IB_MCAST_BLOCK_SIZE; i++) + printf("\t\t0x%x\t0x%x\n", IB_LID_MCAST_START_HO + block*64 + i, + cl_ntoh16(mftr->mft[i])); + printf("\n"); +} +static void dump_results(osmv_query_res_t *r, void (*dump_func)(void *)) +{ + int i; + for (i = 0; i < r->result_cnt; i++) { + void *data = osmv_get_query_result(r->p_result_madw, i); + dump_func(data); + } +} + +static void +return_mad(void) +{ + /* + * Return the IB query MAD to the pool as necessary. + */ + if (result.p_result_madw != NULL) { + osm_mad_pool_put(&mad_pool, result.p_result_madw); + result.p_result_madw = NULL; + } +} + +/** + * Get any record(s) + */ +static ib_api_status_t +get_any_records(osm_bind_handle_t bind_handle, + ib_net16_t attr_id, ib_net32_t attr_mod, ib_net64_t comp_mask, + void *attr, ib_net16_t attr_offset, + ib_net64_t sm_key) +{ + ib_api_status_t status; + osmv_query_req_t req; + osmv_user_query_t user; + + memset(&req, 0, sizeof(req)); + memset(&user, 0, sizeof(user)); + + user.attr_id = attr_id; + user.attr_offset = attr_offset; + user.attr_mod = attr_mod; + user.comp_mask = comp_mask; + user.p_attr = attr; + + req.query_type = OSMV_QUERY_USER_DEFINED; + req.timeout_ms = sa_timeout_ms; + req.retry_cnt = 1; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = NULL; + req.pfn_query_cb = query_res_cb; + req.p_query_input = &user; + req.sm_key = sm_key; + + if ((status = osmv_query_sa(bind_handle, &req)) != IB_SUCCESS) { + fprintf(stderr, "Query SA failed: %s\n", + ib_get_err_str(status)); + return status; + } + + if (result.status != IB_SUCCESS) { + fprintf(stderr, "Query result returned: %s\n", + ib_get_err_str(result.status)); + return result.status; + } + + return status; +} + +/** + * Get all the records available for requested query type. + */ +static ib_api_status_t +get_all_records(osm_bind_handle_t bind_handle, + ib_net16_t query_id, + ib_net16_t attr_offset, + int trusted) +{ + return get_any_records(bind_handle, query_id, 0, 0, NULL, attr_offset, + trusted ? smkey : 0); +} + +/** + * return the lid from the node descriptor (name) supplied + */ +static ib_api_status_t +get_lid_from_name(osm_bind_handle_t bind_handle, const char *name, ib_net16_t *lid) +{ + int i = 0; + ib_node_record_t *node_record = NULL; + ib_node_info_t *p_ni = NULL; + ib_net16_t attr_offset = ib_get_attr_offset(sizeof(*node_record)); + ib_api_status_t status; + + status = get_all_records(bind_handle, IB_MAD_ATTR_NODE_RECORD, attr_offset, 0); + if (status != IB_SUCCESS) + return (status); + + for (i = 0; i < result.result_cnt; i++) { + node_record = osmv_get_query_node_rec(result.p_result_madw, i); + p_ni = &(node_record->node_info); + if (name && strncmp(name, (char *)node_record->node_desc.description, + sizeof(node_record->node_desc.description)) == 0) { + *lid = cl_ntoh16(node_record->lid); + break; + } + } + return_mad(); + return (status); +} + +static ib_net16_t +get_lid(osm_bind_handle_t bind_handle, const char * name) +{ + ib_net16_t rc_lid = 0; + + if (!name) + return(0); + if (isalpha(name[0])) + assert(get_lid_from_name(bind_handle, name, &rc_lid) == IB_SUCCESS); + else + rc_lid = atoi(name); + if (rc_lid == 0) + fprintf(stderr, "Failed to find lid for \"%s\"\n", name); + return (rc_lid); +} + +static int parse_lid_and_ports(osm_bind_handle_t bind_handle, + char *str, int *lid, int *port1, int *port2) +{ + char *p, *e; + + if (port1) *port1 = -1; + if (port2) *port2 = -1; + + p = strchr(str, '/'); + if (p) *p = '\0'; + if (lid) + *lid = get_lid(bind_handle, str); + + if (!p) + return 0; + str = p + 1; + p = strchr(str, '/'); + if (p) *p = '\0'; + if (port1) { + *port1 = strtoul(str, &e, 0); + if (e == str) + *port1 = -1; + } + + if (!p) + return 0; + str = p + 1; + if (port2) { + *port2 = strtoul(str, &e, 0); + if (e == str) + *port2 = -1; + } + + return 0; +} + +/* + * Get the portinfo records available with IsSM or IsSMdisabled CapabilityMask bit on. + */ +static ib_api_status_t +get_issm_records(osm_bind_handle_t bind_handle, ib_net32_t capability_mask) +{ + ib_portinfo_record_t attr; + + memset( &attr, 0, sizeof ( attr ) ); + attr.port_info.capability_mask = capability_mask; + + return get_any_records(bind_handle, IB_MAD_ATTR_PORTINFO_RECORD, + cl_hton32(1 << 31), IB_PIR_COMPMASK_CAPMASK, + &attr, + ib_get_attr_offset(sizeof(ib_portinfo_record_t)), + 0); +} + +static ib_api_status_t +print_node_records(osm_bind_handle_t bind_handle) +{ + int i = 0; + ib_node_record_t *node_record = NULL; + ib_net16_t attr_offset = ib_get_attr_offset(sizeof(*node_record)); + ib_api_status_t status; + + status = get_all_records(bind_handle, IB_MAD_ATTR_NODE_RECORD, attr_offset, 0); + if (status != IB_SUCCESS) + return (status); + + if (node_print_desc == ALL_DESC) { + printf(" LID \"name\"\n"); + printf("================\n"); + } + for (i = 0; i < result.result_cnt; i++) { + node_record = osmv_get_query_node_rec(result.p_result_madw, i); + if (node_print_desc == ALL_DESC) { + print_node_desc(node_record); + } else if (node_print_desc == NAME_OF_LID) { + if (requested_lid == cl_ntoh16(node_record->lid)) { + print_node_record(node_record); + } + } else if (node_print_desc == NAME_OF_GUID) { + ib_node_info_t *p_ni = &(node_record->node_info); + + if (requested_guid == cl_ntoh64(p_ni->port_guid)) { + print_node_record(node_record); + } + } else { + if (!requested_name || + (strncmp(requested_name, + (char *)node_record->node_desc.description, + sizeof(node_record->node_desc.description)) == 0)) { + print_node_record(node_record); + if (node_print_desc == UNIQUE_LID_ONLY) { + return_mad(); + exit(0); + } + } + } + } + return_mad(); + return (status); +} + +static ib_api_status_t +get_print_path_rec_lid(osm_bind_handle_t bind_handle, + ib_net16_t src_lid, + ib_net16_t dst_lid) +{ + osmv_query_req_t req; + osmv_lid_pair_t lid_pair; + ib_api_status_t status; + + lid_pair.src_lid = cl_hton16(src_lid); + lid_pair.dest_lid = cl_hton16(dst_lid); + + memset( &req, 0, sizeof( req ) ); + + req.query_type = OSMV_QUERY_PATH_REC_BY_LIDS; + req.timeout_ms = sa_timeout_ms; + req.retry_cnt = 1; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = NULL; + req.pfn_query_cb = query_res_cb; + req.p_query_input = (void *)&lid_pair; + req.sm_key = 0; + + if ((status = osmv_query_sa(bind_handle, &req)) != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query SA failed: %s\n", + ib_get_err_str(status)); + return (status); + } + if (result.status != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query result returned: %s\n", + ib_get_err_str(result.status)); + return (result.status); + } + status = result.status; + dump_results(&result, dump_path_record); + return_mad(); + return (status); +} + +static ib_api_status_t +get_print_path_rec_gid(osm_bind_handle_t bind_handle, + const ib_gid_t *src_gid, + const ib_gid_t *dst_gid) +{ + osmv_query_req_t req; + osmv_gid_pair_t gid_pair; + ib_api_status_t status; + + gid_pair.src_gid = *src_gid; + gid_pair.dest_gid = *dst_gid; + + memset( &req, 0, sizeof( req ) ); + + req.query_type = OSMV_QUERY_PATH_REC_BY_GIDS; + req.timeout_ms = sa_timeout_ms; + req.retry_cnt = 1; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = NULL; + req.pfn_query_cb = query_res_cb; + req.p_query_input = (void *)&gid_pair; + req.sm_key = 0; + + if ((status = osmv_query_sa(bind_handle, &req)) != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query SA failed: %s\n", + ib_get_err_str(status)); + return (status); + } + if (result.status != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query result returned: %s\n", + ib_get_err_str(result.status)); + return (result.status); + } + status = result.status; + dump_results(&result, dump_path_record); + return_mad(); + return (status); +} + +static ib_api_status_t +get_print_class_port_info(osm_bind_handle_t bind_handle) +{ + osmv_query_req_t req; + ib_api_status_t status; + + memset( &req, 0, sizeof( req ) ); + + req.query_type = OSMV_QUERY_CLASS_PORT_INFO; + req.timeout_ms = sa_timeout_ms; + req.retry_cnt = 1; + req.flags = OSM_SA_FLAGS_SYNC; + req.query_context = NULL; + req.pfn_query_cb = query_res_cb; + req.p_query_input = NULL; + req.sm_key = 0; + + if ((status = osmv_query_sa(bind_handle, &req)) != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query SA failed: %s\n", + ib_get_err_str(status)); + return (status); + } + if (result.status != IB_SUCCESS) { + fprintf(stderr, "ERROR: Query result returned: %s\n", + ib_get_err_str(result.status)); + return (result.status); + } + status = result.status; + dump_results(&result, dump_class_port_info); + return_mad(); + return (status); +} + +static ib_api_status_t +print_path_records(osm_bind_handle_t bind_handle) +{ + ib_net16_t attr_offset = ib_get_attr_offset(sizeof(ib_path_rec_t)); + ib_api_status_t status; + + status = get_all_records(bind_handle, IB_MAD_ATTR_PATH_RECORD, attr_offset, 0); + if (status != IB_SUCCESS) + return (status); + + dump_results(&result, dump_path_record); + return_mad(); + return (status); +} + +static ib_api_status_t +print_portinfo_records(osm_bind_handle_t bind_handle) +{ + ib_api_status_t status; + + /* First, get IsSM records */ + status = get_issm_records(bind_handle, IB_PORT_CAP_IS_SM); + if (status != IB_SUCCESS) + return (status); + + printf("IsSM ports\n"); + dump_results(&result, dump_portinfo_record); + return_mad(); + + /* Now, get IsSMdisabled records */ + status = get_issm_records(bind_handle, IB_PORT_CAP_SM_DISAB); + if (status != IB_SUCCESS) + return (status); + + printf("\nIsSMdisabled ports\n"); + dump_results(&result, dump_portinfo_record); + return_mad(); + + return (status); +} + +static ib_api_status_t +print_multicast_member_records(osm_bind_handle_t bind_handle) +{ + osmv_query_res_t mc_group_result; + ib_api_status_t status; + + status = get_all_records(bind_handle, IB_MAD_ATTR_MCMEMBER_RECORD, + ib_get_attr_offset(sizeof(ib_member_rec_t)), 1); + if (status != IB_SUCCESS) + return (status); + + mc_group_result = result; + + status = get_all_records(bind_handle, IB_MAD_ATTR_NODE_RECORD, + ib_get_attr_offset(sizeof(ib_node_record_t)), 0); + if (status != IB_SUCCESS) + goto return_mc; + + dump_results(&mc_group_result, dump_multicast_member_record); + return_mad(); + +return_mc: + /* return_mad for the mc_group_result */ + if (mc_group_result.p_result_madw != NULL) { + osm_mad_pool_put(&mad_pool, mc_group_result.p_result_madw); + mc_group_result.p_result_madw = NULL; + } + + return (status); +} + +static ib_api_status_t +print_multicast_group_records(osm_bind_handle_t bind_handle) +{ + ib_api_status_t status; + + status = get_all_records(bind_handle, IB_MAD_ATTR_MCMEMBER_RECORD, + ib_get_attr_offset(sizeof(ib_member_rec_t)), 0); + if (status != IB_SUCCESS) + return (status); + + dump_results(&result, dump_multicast_group_record); + return_mad(); + return (status); +} + +static ib_api_status_t +print_service_records(osm_bind_handle_t bind_handle) +{ + ib_net16_t attr_offset = ib_get_attr_offset(sizeof(ib_service_record_t)); + ib_api_status_t status; + + status = get_all_records(bind_handle, IB_MAD_ATTR_SERVICE_RECORD, attr_offset, 0); + if (status != IB_SUCCESS) + return (status); + + dump_results(&result, dump_service_record); + return_mad(); + return (status); +} + +static ib_api_status_t +print_inform_info_records(osm_bind_handle_t bind_handle) +{ + ib_net16_t attr_offset = ib_get_attr_offset(sizeof(ib_inform_info_record_t)); + ib_api_status_t status; + + status = get_all_records(bind_handle, IB_MAD_ATTR_INFORM_INFO_RECORD, attr_offset, 0); + if (status != IB_SUCCESS) + return (status); + + dump_results(&result, dump_inform_info_record); + return_mad(); + return (status); +} + +static ib_api_status_t +print_link_records(osm_bind_handle_t bind_handle, int argc, char *argv[]) +{ + ib_link_record_t lr; + ib_net64_t comp_mask = 0; + int from_lid = 0, to_lid = 0, from_port = -1, to_port = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(bind_handle, argv[0], + &from_lid, &from_port, NULL); + + if (argc > 1) + parse_lid_and_ports(bind_handle, argv[1], + &to_lid, &to_port, NULL); + + memset(&lr, 0, sizeof(lr)); + + if (from_lid > 0) { + lr.from_lid = cl_hton16(from_lid); + comp_mask |= IB_LR_COMPMASK_FROM_LID; + } + if (from_port >= 0) { + lr.from_port_num = from_port; + comp_mask |= IB_LR_COMPMASK_FROM_PORT; + } + if (to_lid > 0) { + lr.to_lid = cl_hton16(to_lid); + comp_mask |= IB_LR_COMPMASK_TO_LID; + } + if (to_port >= 0) { + lr.to_port_num = to_port; + comp_mask |= IB_LR_COMPMASK_TO_PORT; + } + + status = get_any_records(bind_handle, IB_MAD_ATTR_LINK_RECORD, 0, + comp_mask, &lr, + ib_get_attr_offset(sizeof(lr)), 0); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_link_record); + return_mad(); + return status; +} + +static int +print_sl2vl_records(const struct query_cmd *q, osm_bind_handle_t bind_handle, + int argc, char *argv[]) +{ + ib_slvl_table_record_t slvl; + ib_net64_t comp_mask = 0; + int lid = 0, in_port = -1, out_port = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(bind_handle, argv[0], + &lid, &in_port, &out_port); + + memset(&slvl, 0, sizeof(slvl)); + + if (lid > 0) { + slvl.lid = cl_hton16(lid); + comp_mask |= IB_SLVL_COMPMASK_LID; + } + if (in_port >= 0) { + slvl.in_port_num = in_port; + comp_mask |= IB_SLVL_COMPMASK_IN_PORT; + } + if (out_port >= 0) { + slvl.out_port_num = out_port; + comp_mask |= IB_SLVL_COMPMASK_OUT_PORT; + } + + status = get_any_records(bind_handle, IB_MAD_ATTR_SLVL_RECORD, 0, + comp_mask, &slvl, + ib_get_attr_offset(sizeof(slvl)), 0); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_slvl_record); + return_mad(); + return status; +} + +static int +print_vlarb_records(const struct query_cmd *q, osm_bind_handle_t bind_handle, + int argc, char *argv[]) +{ + ib_vl_arb_table_record_t vlarb; + ib_net64_t comp_mask = 0; + int lid = 0, port = -1, block = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(bind_handle, argv[0], + &lid, &port, &block); + + memset(&vlarb, 0, sizeof(vlarb)); + + if (lid > 0) { + vlarb.lid = cl_hton16(lid); + comp_mask |= IB_VLA_COMPMASK_LID; + } + if (port >= 0) { + vlarb.port_num = port; + comp_mask |= IB_VLA_COMPMASK_OUT_PORT; + } + if (block >= 0) { + vlarb.block_num = block; + comp_mask |= IB_VLA_COMPMASK_BLOCK; + } + + status = get_any_records(bind_handle, IB_MAD_ATTR_VLARB_RECORD, 0, + comp_mask, &vlarb, + ib_get_attr_offset(sizeof(vlarb)), 0); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_vlarb_record); + return_mad(); + return status; +} + +static int +print_pkey_tbl_records(const struct query_cmd *q, osm_bind_handle_t bind_handle, + int argc, char *argv[]) +{ + ib_pkey_table_record_t pktr; + ib_net64_t comp_mask = 0; + int lid = 0, port = -1, block = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(bind_handle, argv[0], + &lid, &port, &block); + + memset(&pktr, 0, sizeof(pktr)); + + if (lid > 0) { + pktr.lid = cl_hton16(lid); + comp_mask |= IB_PKEY_COMPMASK_LID; + } + if (port >= 0) { + pktr.port_num = port; + comp_mask |= IB_PKEY_COMPMASK_PORT; + } + if (block >= 0) { + pktr.block_num = block; + comp_mask |= IB_PKEY_COMPMASK_BLOCK; + } + + status = get_any_records(bind_handle, IB_MAD_ATTR_PKEY_TBL_RECORD, 0, + comp_mask, &pktr, + ib_get_attr_offset(sizeof(pktr)), smkey); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_pkey_tbl_record); + return_mad(); + return status; +} + +static int +print_lft_records(const struct query_cmd *q, osm_bind_handle_t bind_handle, + int argc, char *argv[]) +{ + ib_lft_record_t lftr; + ib_net64_t comp_mask = 0; + int lid = 0, block = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(bind_handle, argv[0], + &lid, &block, NULL); + + memset(&lftr, 0, sizeof(lftr)); + + if (lid > 0) { + lftr.lid = cl_hton16(lid); + comp_mask |= IB_LFTR_COMPMASK_LID; + } + if (block >= 0) { + lftr.block_num = cl_hton16(block); + comp_mask |= IB_LFTR_COMPMASK_BLOCK; + } + + status = get_any_records(bind_handle, IB_MAD_ATTR_LFT_RECORD, 0, + comp_mask, &lftr, + ib_get_attr_offset(sizeof(lftr)), 0); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_lft_record); + return_mad(); + return status; +} + +static int +print_mft_records(const struct query_cmd *q, osm_bind_handle_t bind_handle, + int argc, char *argv[]) +{ + ib_mft_record_t mftr; + ib_net64_t comp_mask = 0; + int lid = 0, block = -1, position = -1; + ib_api_status_t status; + + if (argc > 0) + parse_lid_and_ports(bind_handle, argv[0], + &lid, &position, &block); + + memset(&mftr, 0, sizeof(mftr)); + + if (lid > 0) { + mftr.lid = cl_hton16(lid); + comp_mask |= IB_MFTR_COMPMASK_LID; + } + if (position >= 0) { + mftr.position_block_num = cl_hton16(position << 12); + comp_mask |= IB_MFTR_COMPMASK_POSITION; + } + if (block >= 0) { + mftr.position_block_num |= cl_hton16(block & IB_MCAST_BLOCK_ID_MASK_HO); + comp_mask |= IB_MFTR_COMPMASK_BLOCK; + } + + status = get_any_records(bind_handle, IB_MAD_ATTR_MFT_RECORD, 0, + comp_mask, &mftr, + ib_get_attr_offset(sizeof(mftr)), 0); + if (status != IB_SUCCESS) + return status; + + dump_results(&result, dump_one_mft_record); + return_mad(); + return status; +} + +static osm_bind_handle_t +get_bind_handle(void) +{ + uint32_t i = 0; + uint64_t port_guid = (uint64_t)-1; + osm_bind_handle_t bind_handle; + ib_api_status_t status; + ib_port_attr_t attr_array[MAX_PORTS]; + uint32_t num_ports = MAX_PORTS; + uint32_t ca_name_index = 0; + + complib_init(); + + osm_log_construct(&log_osm); + if ((status = osm_log_init_v2(&log_osm, TRUE, 0x0001, NULL, + 0, TRUE)) != IB_SUCCESS) { + fprintf(stderr, "Failed to init osm_log: %s\n", + ib_get_err_str(status)); + exit(-1); + } + osm_log_set_level(&log_osm, OSM_LOG_NONE); + if (osm_debug) + osm_log_set_level(&log_osm, OSM_LOG_DEFAULT_LEVEL); + + vendor = osm_vendor_new(&log_osm, sa_timeout_ms); + osm_mad_pool_construct(&mad_pool); + if ((status = osm_mad_pool_init(&mad_pool)) != IB_SUCCESS) { + fprintf(stderr, "Failed to init mad pool: %s\n", + ib_get_err_str(status)); + exit(-1); + } + + if ((status = osm_vendor_get_all_port_attr(vendor, attr_array, &num_ports)) != IB_SUCCESS) { + fprintf(stderr, "Failed to get port attributes: %s\n", + ib_get_err_str(status)); + exit(-1); + } + + for (i = 0; i < num_ports; i++) { + if (i > 1 && cl_ntoh64(attr_array[i].port_guid) + != (cl_ntoh64(attr_array[i-1].port_guid) + 1)) + ca_name_index++; + if (sa_port_num && sa_port_num != attr_array[i].port_num) + continue; + if (sa_hca_name + && strcmp(sa_hca_name, vendor->ca_names[ca_name_index]) != 0) + continue; + if (attr_array[i].link_state == IB_LINK_ACTIVE) { + port_guid = attr_array[i].port_guid; + break; + } + } + + if (port_guid == (uint64_t)-1) { + fprintf(stderr, "Failed to find active port, check port status with \"ibstat\"\n"); + exit(-1); + } + + bind_handle = osmv_bind_sa(vendor, &mad_pool, port_guid); + + if (bind_handle == OSM_BIND_INVALID_HANDLE) { + fprintf(stderr, "Failed to bind to SA\n"); + exit(-1); + } + return (bind_handle); +} + +static void +clean_up(void) +{ + osm_mad_pool_destroy(&mad_pool); + osm_vendor_delete(&vendor); +} + +static const struct query_cmd query_cmds[] = { + { "ClassPortInfo", "CPI", IB_MAD_ATTR_CLASS_PORT_INFO, }, + { "NodeRecord", "NR", IB_MAD_ATTR_NODE_RECORD, }, + { "PortInfoRecord", "PIR", IB_MAD_ATTR_PORTINFO_RECORD, }, + { "SL2VLTableRecord", "SL2VL", IB_MAD_ATTR_SLVL_RECORD, + "[[lid]/[in_port]/[out_port]]", + print_sl2vl_records }, + { "PKeyTableRecord", "PKTR", IB_MAD_ATTR_PKEY_TBL_RECORD, + "[[lid]/[port]/[block]]", + print_pkey_tbl_records }, + { "VLArbitrationTableRecord", "VLAR", IB_MAD_ATTR_VLARB_RECORD, + "[[lid]/[port]/[block]]", + print_vlarb_records }, + { "InformInfoRecord", "IIR", IB_MAD_ATTR_INFORM_INFO_RECORD, }, + { "LinkRecord", "LR", IB_MAD_ATTR_LINK_RECORD, + "[[from_lid]/[from_port]] [[to_lid]/[to_port]]", }, + { "ServiceRecord", "SR", IB_MAD_ATTR_SERVICE_RECORD, }, + { "PathRecord", "PR", IB_MAD_ATTR_PATH_RECORD, }, + { "MCMemberRecord", "MCMR", IB_MAD_ATTR_MCMEMBER_RECORD, }, + { "LFTRecord", "LFTR", IB_MAD_ATTR_LFT_RECORD, "[[lid]/[block]]", + print_lft_records }, + { "MFTRecord", "MFTR", IB_MAD_ATTR_MFT_RECORD, + "[[mlid]/[position]/[block]]", + print_mft_records }, + { 0 } +}; + +static const struct query_cmd *find_query(const char *name) +{ + const struct query_cmd *q; + unsigned len = strlen(name); + + for (q = query_cmds; q->name; q++) + if (!strncasecmp(name, q->name, len) || + (q->alias && !strncasecmp(name, q->alias, len))) + return q; + + return NULL; +} + +static void +usage(void) +{ + const struct query_cmd *q; + + fprintf(stderr, "Usage: %s [-h -d -p -N] [--list | -D] [-S -I -L -l -G" + " -O -U -c -s -g -m --src-to-dst --sgid-to-dgid " + "-C -P -t(imeout) ] [query-name] [ | | ]\n", + argv0); + fprintf(stderr, " Queries node records by default\n"); + fprintf(stderr, " -d enable debugging\n"); + fprintf(stderr, " -p get PathRecord info\n"); + fprintf(stderr, " -N get NodeRecord info\n"); + fprintf(stderr, " --list | -D the node desc of the CA's\n"); + fprintf(stderr, " -S get ServiceRecord info\n"); + fprintf(stderr, " -I get InformInfoRecord (subscription) info\n"); + fprintf(stderr, " -L return the Lids of the name specified\n"); + fprintf(stderr, " -l return the unique Lid of the name specified\n"); + fprintf(stderr, " -G return the Guids of the name specified\n"); + fprintf(stderr, " -O return name for the Lid specified\n"); + fprintf(stderr, " -U return name for the Guid specified\n"); + fprintf(stderr, " -c get the SA's class port info\n"); + fprintf(stderr, " -s return the PortInfoRecords with isSM or " + "isSMdisabled capability mask bit on\n"); + fprintf(stderr, " -g get multicast group info\n"); + fprintf(stderr, " -m get multicast member info\n"); + fprintf(stderr, " (if multicast group specified, list member GIDs" + " only for group specified\n"); + fprintf(stderr, " specified, for example 'saquery -m 0xC000')\n"); + fprintf(stderr, " -x get LinkRecord info\n"); + fprintf(stderr, " --src-to-dst get a PathRecord for \n" + " where src and dst are either node " + "names or LIDs\n"); + fprintf(stderr, " --sgid-to-dgid get a PathRecord for \n" + " where sgid and dgid are addresses in " + "IPv6 format\n"); + fprintf(stderr, " -C specify the SA query HCA\n"); + fprintf(stderr, " -P specify the SA query port\n"); + fprintf(stderr, " --smkey specify SM_Key value for the query." + " If non-numeric value \n" + " (like 'x') is specified then " + "saquery will prompt for a value\n"); + fprintf(stderr, " -t | --timeout specify the SA query " + "response timeout (default %u msec)\n", + DEFAULT_SA_TIMEOUT_MS); + fprintf(stderr, " --node-name-map specify a node name map\n"); + fprintf(stderr, "\n Supported query names (and aliases):\n"); + for (q = query_cmds; q->name; q++) + fprintf(stderr, " %s (%s) %s\n", q->name, + q->alias ? q->alias : "", q->usage ? q->usage : ""); + fprintf(stderr, "\n"); + + exit(-1); +} + +int +main(int argc, char **argv) +{ + int ch = 0; + int members = 0; + osm_bind_handle_t bind_handle; + const struct query_cmd *q = NULL; + char *src = NULL; + char *dst = NULL; + char *sgid = NULL; + char *dgid = NULL; + ib_net16_t query_type = 0; + ib_net16_t src_lid; + ib_net16_t dst_lid; + ib_api_status_t status; + + static char const str_opts[] = "pVNDLlGOUcSIsgmxdhP:C:t:"; + static const struct option long_opts [] = { + {"p", 0, 0, 'p'}, + {"Version", 0, 0, 'V'}, + {"N", 0, 0, 'N'}, + {"L", 0, 0, 'L'}, + {"l", 0, 0, 'l'}, + {"G", 0, 0, 'G'}, + {"O", 0, 0, 'O'}, + {"U", 0, 0, 'U'}, + {"s", 0, 0, 's'}, + {"g", 0, 0, 'g'}, + {"m", 0, 0, 'm'}, + {"x", 0, 0, 'x'}, + {"d", 0, 0, 'd'}, + {"c", 0, 0, 'c'}, + {"S", 0, 0, 'S'}, + {"I", 0, 0, 'I'}, + {"P", 1, 0, 'P'}, + {"C", 1, 0, 'C'}, + {"help", 0, 0, 'h'}, + {"list", 0, 0, 'D'}, + {"src-to-dst", 1, 0, 1}, + {"sgid-to-dgid", 1, 0, 2}, + {"timeout", 1, 0, 't'}, + {"node-name-map", 1, 0, 3}, + {"smkey", 1, 0, 4}, + { } + }; + + argv0 = argv[0]; + + while ((ch = getopt_long_only(argc, argv, str_opts, long_opts, NULL)) != -1) { + switch (ch) { + case 1: + { + char *opt = strdup(optarg); + char *ch = strchr(opt, ':'); + if (!ch) { + fprintf(stderr, + "ERROR: --src-to-dst :\n"); + usage(); + } + *ch++ = '\0'; + if (*opt) + src = strdup(opt); + if (*ch) + dst = strdup(ch); + free(opt); + query_type = IB_MAD_ATTR_PATH_RECORD; + break; + } + case 2: + { + char *opt = strdup(optarg); + char *tok1 = strtok(opt, "-"); + char *tok2 = strtok(NULL, "\0"); + + if (tok1 && tok2) { + sgid = strdup(tok1); + dgid = strdup(tok2); + } else { + fprintf(stderr, + "ERROR: --sgid-to-dgid -\n"); + usage(); + } + free(opt); + query_type = IB_MAD_ATTR_PATH_RECORD; + break; + } + case 3: + node_name_map_file = strdup(optarg); + break; + case 4: + if (!isxdigit(*optarg) && + !(optarg = getpass("SM_Key: "))) { + fprintf(stderr, "cannot get SM_Key\n"); + usage(); + } + smkey = cl_hton64(strtoull(optarg, NULL, 0)); + break; + case 'p': + query_type = IB_MAD_ATTR_PATH_RECORD; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version()); + exit(-1); + case 'D': + node_print_desc = ALL_DESC; + break; + case 'c': + query_type = IB_MAD_ATTR_CLASS_PORT_INFO; + break; + case 'S': + query_type = IB_MAD_ATTR_SERVICE_RECORD; + break; + case 'I': + query_type = IB_MAD_ATTR_INFORM_INFO_RECORD; + break; + case 'N': + query_type = IB_MAD_ATTR_NODE_RECORD; + break; + case 'L': + node_print_desc = LID_ONLY; + break; + case 'l': + node_print_desc = UNIQUE_LID_ONLY; + break; + case 'G': + node_print_desc = GUID_ONLY; + break; + case 'O': + node_print_desc = NAME_OF_LID; + break; + case 'U': + node_print_desc = NAME_OF_GUID; + break; + case 's': + query_type = IB_MAD_ATTR_PORTINFO_RECORD; + break; + case 'g': + query_type = IB_MAD_ATTR_MCMEMBER_RECORD; + break; + case 'm': + query_type = IB_MAD_ATTR_MCMEMBER_RECORD; + members = 1; + break; + case 'x': + query_type = IB_MAD_ATTR_LINK_RECORD; + break; + case 'd': + osm_debug = 1; + break; + case 'C': + sa_hca_name = optarg; + break; + case 'P': + sa_port_num = strtoul(optarg, NULL, 0); + break; + case 't': + sa_timeout_ms = strtoul(optarg, NULL, 0); + break; + case 'h': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (!query_type) { + if (!argc || !(q = find_query(argv[0]))) + query_type = IB_MAD_ATTR_NODE_RECORD; + else { + query_type = q->query_type; + argc--; + argv++; + } + } + + if (argc) { + if (node_print_desc == NAME_OF_LID) { + requested_lid = (ib_net16_t)strtoul(argv[0], NULL, 0); + requested_lid_flag++; + } else if (node_print_desc == NAME_OF_GUID) { + requested_guid = (ib_net64_t)strtoul(argv[0], NULL, 0); + requested_guid_flag++; + } else { + requested_name = argv[0]; + } + } + + if ((node_print_desc == LID_ONLY || + node_print_desc == UNIQUE_LID_ONLY || + node_print_desc == GUID_ONLY) && + !requested_name) { + fprintf(stderr, "ERROR: name not specified\n"); + usage(); + } + + if (node_print_desc == NAME_OF_LID && !requested_lid_flag) { + fprintf(stderr, "ERROR: lid not specified\n"); + usage(); + } + + if (node_print_desc == NAME_OF_GUID && !requested_guid_flag) { + fprintf(stderr, "ERROR: guid not specified\n"); + usage(); + } + + /* Note: lid cannot be 0; see infiniband spec 4.1.3 */ + if (node_print_desc == NAME_OF_LID && !requested_lid) { + fprintf(stderr, "ERROR: lid invalid\n"); + usage(); + } + + bind_handle = get_bind_handle(); + node_name_map = open_node_name_map(node_name_map_file); + + switch (query_type) { + case IB_MAD_ATTR_NODE_RECORD: + status = print_node_records(bind_handle); + break; + case IB_MAD_ATTR_PATH_RECORD: + if (src && dst) { + src_lid = get_lid(bind_handle, src); + dst_lid = get_lid(bind_handle, dst); + printf("Path record for %s -> %s\n", src, dst); + if (src_lid == 0 || dst_lid == 0) { + status = IB_UNKNOWN_ERROR; + } else { + status = get_print_path_rec_lid(bind_handle, src_lid, dst_lid); + } + } else if (sgid && dgid) { + struct in6_addr src_addr, dst_addr; + + if (inet_pton(AF_INET6, sgid, &src_addr) <= 0) { + fprintf(stderr, "invalid src gid: %s\n", sgid); + exit(-1); + } + if (inet_pton(AF_INET6, dgid, &dst_addr) <= 0) { + fprintf(stderr, "invalid dst gid: %s\n", dgid); + exit(-1); + } + status = get_print_path_rec_gid( + bind_handle, + (ib_gid_t *) &src_addr.s6_addr, + (ib_gid_t *) &dst_addr.s6_addr); + } else { + status = print_path_records(bind_handle); + } + break; + case IB_MAD_ATTR_CLASS_PORT_INFO: + status = get_print_class_port_info(bind_handle); + break; + case IB_MAD_ATTR_PORTINFO_RECORD: + status = print_portinfo_records(bind_handle); + break; + case IB_MAD_ATTR_MCMEMBER_RECORD: + if (members) + status = print_multicast_member_records(bind_handle); + else + status = print_multicast_group_records(bind_handle); + break; + case IB_MAD_ATTR_SERVICE_RECORD: + status = print_service_records(bind_handle); + break; + case IB_MAD_ATTR_INFORM_INFO_RECORD: + status = print_inform_info_records(bind_handle); + break; + case IB_MAD_ATTR_LINK_RECORD: + status = print_link_records(bind_handle, argc, argv); + break; + default: + if (q && q->handler) + status = q->handler(q, bind_handle, argc, argv); + else { + fprintf(stderr, "Unknown query type %d\n", query_type); + status = IB_UNKNOWN_ERROR; + } + break; + } + + if (src) + free(src); + if (dst) + free(dst); + clean_up(); + close_node_name_map(node_name_map); + return (status); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/saquery/SOURCES b/branches/winverbs/tools/infiniband_diags/src/saquery/SOURCES new file mode 100644 index 00000000..07378a6f --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/saquery/SOURCES @@ -0,0 +1,37 @@ +TARGETNAME = saquery +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = ..\saquery.c ..\ibdiag_common.c + +INCLUDES = ..;..\..\include; + ..\..\..\..\ulp\opensm\user\include; + ..\..\..\..\ulp\libibmad\include; + ..\..\..\..\ulp\libibumad\include; + ..\..\..\..\inc; + ..\..\..\..\inc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + diff --git a/branches/winverbs/tools/infiniband_diags/src/sminfo.c b/branches/winverbs/tools/infiniband_diags/src/sminfo.c new file mode 100644 index 00000000..18ae875e --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/sminfo.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2004-2008 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. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include + +#if !defined(_WIN32) +#include +#include +#include +#else +#include "..\..\..\..\etc\user\getopt.c" +#endif + +#include +#include + +#include "ibdiag_common.h" + +static uint8_t sminfo[1024]; + +char *argv0 = "sminfo"; + +static void +usage(void) +{ + fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -s state -p prio -a activity -D(irect) -G(uid) -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms] [modifier]\n", + argv0); + exit(-1); +} + +int strdata, xdata=1, bindata; +enum { + SMINFO_NOTACT, + SMINFO_DISCOVER, + SMINFO_STANDBY, + SMINFO_MASTER, + + SMINFO_STATE_LAST, +}; + +char *statestr[] = { + "SMINFO_NOTACT", + "SMINFO_DISCOVER", + "SMINFO_STANDBY", + "SMINFO_MASTER", +}; + +#define STATESTR(s) (((unsigned int)(s)) < SMINFO_STATE_LAST ? statestr[s] : "???") + +int __cdecl +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + int mod = 0; + ib_portid_t portid = {0}; + int timeout = 0; /* use default */ + uint8_t *p; + unsigned int act = 0; + int prio = 0, state = SMINFO_STANDBY; + uint64_t guid = 0, key = 0; + extern int ibdebug; + int dest_type = IB_DEST_LID; + int udebug = 0; + char *ca = 0; + int ca_port = 0; + + static char str_opts[] = "C:P:t:s:p:a:deDGVhu"; + static struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "s", 1, 0, 's'}, + { "p", 1, 0, 'p'}, + { "a", 1, 0, 'a'}, + { "Direct", 0, 0, 'D'}, + { "Guid", 0, 0, 'G'}, + { "Version", 0, 0, 'V'}, + { "timeout", 1, 0, 't'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { 0 } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'a': + act = strtoul(optarg, 0, 0); + break; + case 's': + state = strtoul(optarg, 0, 0); + break; + case 'p': + prio = strtoul(optarg, 0, 0); + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + mod = atoi(argv[1]); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + + if (argc) { + if (ib_resolve_portid_str(&portid, argv[0], dest_type, 0) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_smlid(&portid, timeout) < 0) + IBERROR("can't resolve sm port %s", argv[0]); + } + + mad_encode_field(sminfo, IB_SMINFO_GUID_F, &guid); + mad_encode_field(sminfo, IB_SMINFO_ACT_F, &act); + mad_encode_field(sminfo, IB_SMINFO_KEY_F, &key); + mad_encode_field(sminfo, IB_SMINFO_PRIO_F, &prio); + mad_encode_field(sminfo, IB_SMINFO_STATE_F, &state); + + if (mod) { + if (!(p = smp_set(sminfo, &portid, IB_ATTR_SMINFO, mod, timeout))) + IBERROR("set"); + } else + if (!(p = smp_query(sminfo, &portid, IB_ATTR_SMINFO, 0, timeout))) + IBERROR("query"); + + mad_decode_field(sminfo, IB_SMINFO_GUID_F, &guid); + mad_decode_field(sminfo, IB_SMINFO_ACT_F, &act); + mad_decode_field(sminfo, IB_SMINFO_KEY_F, &key); + mad_decode_field(sminfo, IB_SMINFO_PRIO_F, &prio); + mad_decode_field(sminfo, IB_SMINFO_STATE_F, &state); + + printf("sminfo: sm lid %d sm guid 0x%" PRIx64 ", activity count %u priority %d state %d %s\n", + portid.lid, guid, act, prio, state, STATESTR(state)); + + exit(0); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/sminfo/SOURCES b/branches/winverbs/tools/infiniband_diags/src/sminfo/SOURCES new file mode 100644 index 00000000..133f267d --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/sminfo/SOURCES @@ -0,0 +1,30 @@ +TARGETNAME = sminfo +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = ..\sminfo.c ..\ibdiag_common.c + +INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif + diff --git a/branches/winverbs/tools/infiniband_diags/src/smpdump.c b/branches/winverbs/tools/infiniband_diags/src/smpdump.c new file mode 100644 index 00000000..2272db00 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/smpdump.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2004-2008 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. + * + */ + +#define _GNU_SOURCE + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +static const uint8_t CLASS_SUBN_DIRECTED_ROUTE = 0x81; +static const uint8_t CLASS_SUBN_LID_ROUTE = 0x1; + +#define ATTR_NODE_DESC ((uint16_t)(htons(0x10))) +#define ATTR_NODE_INFO ((uint16_t)(htons(0x11))) +#define ATTR_PORT_INFO ((uint16_t)(htons(0x15))) + +static int mad_agent; +static int drmad_tid = 0x123; + +static int debug, verbose; + +char *argv0 = "smpdump"; + +typedef struct { + char path[64]; + int hop_cnt; +} DRPath; + +struct drsmp { + uint8_t base_version; + uint8_t mgmt_class; + uint8_t class_version; + uint8_t method; + uint16_t status; + uint8_t hop_ptr; + uint8_t hop_cnt; + uint64_t tid; + uint16_t attr_id; + uint16_t resv; + uint32_t attr_mod; + uint64_t mkey; + uint16_t dr_slid; + uint16_t dr_dlid; + uint8_t reserved[28]; + uint8_t data[64]; + uint8_t initial_path[64]; + uint8_t return_path[64]; +}; + +void +drsmp_get_init(void *umad, DRPath *path, int attr, int mod) +{ + struct drsmp *smp = (struct drsmp *)(umad_get_mad(umad)); + + memset(smp, 0, sizeof (*smp)); + + smp->base_version = 1; + smp->mgmt_class = CLASS_SUBN_DIRECTED_ROUTE; + smp->class_version = 1; + + smp->method = 1; + smp->attr_id = (uint16_t)htons((uint16_t)attr); + smp->attr_mod = htonl(mod); + smp->tid = htonll(drmad_tid++); + smp->dr_slid = 0xffff; + smp->dr_dlid = 0xffff; + + umad_set_addr(umad, 0xffff, 0, 0, 0); + + if (path) + memcpy(smp->initial_path, path->path, path->hop_cnt+1); + + smp->hop_cnt = path->hop_cnt; +} + +void +smp_get_init(void *umad, int lid, int attr, int mod) +{ + struct drsmp *smp = (struct drsmp *)(umad_get_mad(umad)); + + memset(smp, 0, sizeof (*smp)); + + smp->base_version = 1; + smp->mgmt_class = CLASS_SUBN_LID_ROUTE; + smp->class_version = 1; + + smp->method = 1; + smp->attr_id = (uint16_t)htons((uint16_t)attr); + smp->attr_mod = htonl(mod); + smp->tid = htonll(drmad_tid++); + + umad_set_addr(umad, lid, 0, 0xffff, 0); +} + +void +drsmp_set_init(void *umad, DRPath *path, int attr, int mod, void *data) +{ + struct drsmp *smp = (struct drsmp *)(umad_get_mad(umad)); + + memset(smp, 0, sizeof (*smp)); + + smp->method = 2; /* SET */ + smp->attr_id = (uint16_t)htons((uint16_t)attr); + smp->attr_mod = htonl(mod); + smp->tid = htonll(drmad_tid++); + smp->dr_slid = 0xffff; + smp->dr_dlid = 0xffff; + + umad_set_addr(umad, 0xffff, 0, 0, 0); + + if (path) + memcpy(smp->initial_path, path->path, path->hop_cnt+1); + + if (data) + memcpy(smp->data, data, sizeof smp->data); + + smp->hop_cnt = path->hop_cnt; +} + +char * +drmad_status_str(struct drsmp *drsmp) +{ + switch (drsmp->status) { + case 0: + return "success"; + case ETIMEDOUT: + return "timeout"; + } + return "unknown error"; +} + +int +str2DRPath(char *str, DRPath *path) +{ + char *s; + + path->hop_cnt = -1; + + DEBUG("DR str: %s", str); + while (str && *str) { + if ((s = strchr(str, ','))) + *s = 0; + path->path[++path->hop_cnt] = atoi(str); + if (!s) + break; + str = s+1; + } + +#if 0 + if (path->path[0] != 0 || + (path->hop_cnt > 0 && dev_port && path->path[1] != dev_port)) { + DEBUG("hop 0 != 0 or hop 1 != dev_port"); + return -1; + } +#endif + + return path->hop_cnt; +} + +void +usage(void) +{ + fprintf(stderr, "Usage: %s [-s(ring) -D(irect) -V(ersion) -C ca_name -P ca_port -t(imeout) timeout_ms] [mod]\n", argv0); + fprintf(stderr, "\tDR examples:\n"); + fprintf(stderr, "\t\t%s -D 0,1,2,3,5 16 # NODE DESC\n", argv0); + fprintf(stderr, "\t\t%s -D 0,1,2 0x15 2 # PORT INFO, port 2\n", argv0); + fprintf(stderr, "\n\tLID routed examples:\n"); + fprintf(stderr, "\t\t%s 3 0x15 2 # PORT INFO, lid 3 port 2\n", argv0); + fprintf(stderr, "\t\t%s 0xa0 0x11 # NODE INFO, lid 0xa0\n", argv0); + fprintf(stderr, "\n"); + exit(-1); +} + +int +main(int argc, char *argv[]) +{ + int dump_char = 0, timeout_ms = 1000; + int dev_port = 0, mgmt_class = CLASS_SUBN_LID_ROUTE, dlid = 0; + char *dev_name = 0; + void *umad; + struct drsmp *smp; + int i, portid, mod = 0, attr; + DRPath path; + uint8_t *desc; + int length; + + static char const str_opts[] = "C:P:t:dsDVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "sring", 0, 0, 's'}, + { "Direct", 0, 0, 'D'}, + { "timeout", 1, 0, 't'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 's': + dump_char++; + break; + case 'd': + debug++; + if (debug > 1) + umad_debug(debug-1); + break; + case 'D': + mgmt_class = CLASS_SUBN_DIRECTED_ROUTE; + break; + case 'C': + dev_name = optarg; + break; + case 'P': + dev_port = atoi(optarg); + break; + case 't': + timeout_ms = strtoul(optarg, 0, 0); + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + if (mgmt_class == CLASS_SUBN_DIRECTED_ROUTE && + str2DRPath(strdupa(argv[0]), &path) < 0) + IBPANIC("bad path str '%s'", argv[0]); + + if (mgmt_class == CLASS_SUBN_LID_ROUTE) + dlid = strtoul(argv[0], 0, 0); + + attr = strtoul(argv[1], 0, 0); + if (argc > 2) + mod = strtoul(argv[2], 0, 0); + + if (umad_init() < 0) + IBPANIC("can't init UMAD library"); + + if ((portid = umad_open_port(dev_name, dev_port)) < 0) + IBPANIC("can't open UMAD port (%s:%d)", dev_name, dev_port); + + if ((mad_agent = umad_register(portid, mgmt_class, 1, 0, 0)) < 0) + IBPANIC("Couldn't register agent for SMPs"); + + if (!(umad = umad_alloc(1, umad_size() + IB_MAD_SIZE))) + IBPANIC("can't alloc MAD"); + + smp = umad_get_mad(umad); + + if (mgmt_class == CLASS_SUBN_DIRECTED_ROUTE) + drsmp_get_init(umad, &path, attr, mod); + else + smp_get_init(umad, dlid, attr, mod); + + if (debug > 1) + xdump(stderr, "before send:\n", smp, 256); + + length = IB_MAD_SIZE; + if (umad_send(portid, mad_agent, umad, length, timeout_ms, 0) < 0) + IBPANIC("send failed"); + + if (umad_recv(portid, umad, &length, -1) != mad_agent) + IBPANIC("recv error: %s", drmad_status_str(smp)); + + if (!dump_char) { + xdump(stdout, 0, smp->data, 64); + if (smp->status) + fprintf(stdout, "SMP status: 0x%x\n", ntohs(smp->status)); + return 0; + } + + desc = smp->data; + for (i = 0; i < 64; ++i) { + if (!desc[i]) + break; + putchar(desc[i]); + } + putchar('\n'); + if (smp->status) + fprintf(stdout, "SMP status: 0x%x\n", ntohs(smp->status)); + return 0; +} diff --git a/branches/winverbs/tools/infiniband_diags/src/smpquery.c b/branches/winverbs/tools/infiniband_diags/src/smpquery.c new file mode 100644 index 00000000..2e8d369a --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/smpquery.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2004-2008 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. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define __STDC_FORMAT_MACROS +#include + +#include +#include +#include +#include + +#include "ibdiag_common.h" + +#undef DEBUG +#define DEBUG if (verbose>1) IBWARN + +static int dest_type = IB_DEST_LID; +static int verbose; + +typedef char *(op_fn_t)(ib_portid_t *dest, char **argv, int argc); + +typedef struct match_rec { + char *name; + op_fn_t *fn; + unsigned opt_portnum; +} match_rec_t; + +static op_fn_t node_desc, node_info, port_info, switch_info, pkey_table, + sl2vl_table, vlarb_table, guid_info; + +static const match_rec_t match_tbl[] = { + { "nodeinfo", node_info }, + { "nodedesc", node_desc }, + { "portinfo", port_info, 1 }, + { "switchinfo", switch_info }, + { "pkeys", pkey_table, 1 }, + { "sl2vl", sl2vl_table, 1 }, + { "vlarb", vlarb_table, 1 }, + { "guids", guid_info }, + {0} +}; + +char *argv0 = "smpquery"; +static char *node_name_map_file = NULL; +static nn_map_t *node_name_map = NULL; + +/*******************************************/ +static char * +node_desc(ib_portid_t *dest, char **argv, int argc) +{ + int node_type, l; + uint64_t node_guid; + char nd[IB_SMP_DATA_SIZE]; + uint8_t data[IB_SMP_DATA_SIZE]; + char dots[128]; + char *nodename = NULL; + + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return "node info query failed"; + + mad_decode_field(data, IB_NODE_TYPE_F, &node_type); + mad_decode_field(data, IB_NODE_GUID_F, &node_guid); + + if (!smp_query(nd, dest, IB_ATTR_NODE_DESC, 0, 0)) + return "node desc query failed"; + + nodename = remap_node_name(node_name_map, node_guid, nd); + + l = strlen(nodename); + if (l < 32) { + memset(dots, '.', 32 - l); + dots[32 - l] = '\0'; + } else { + dots[0] = '.'; + dots[1] = '\0'; + } + + printf("Node Description:%s%s\n", dots, nodename); + free(nodename); + return 0; +} + +static char * +node_info(ib_portid_t *dest, char **argv, int argc) +{ + char buf[2048]; + char data[IB_SMP_DATA_SIZE]; + + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return "node info query failed"; + + mad_dump_nodeinfo(buf, sizeof buf, data, sizeof data); + + printf("# Node info: %s\n%s", portid2str(dest), buf); + return 0; +} + +static char * +port_info(ib_portid_t *dest, char **argv, int argc) +{ + char buf[2048]; + char data[IB_SMP_DATA_SIZE]; + int portnum = 0; + + if (argc > 0) + portnum = strtol(argv[0], 0, 0); + + if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) + return "port info query failed"; + + mad_dump_portinfo(buf, sizeof buf, data, sizeof data); + + printf("# Port info: %s port %d\n%s", portid2str(dest), portnum, buf); + return 0; +} + +static char * +switch_info(ib_portid_t *dest, char **argv, int argc) +{ + char buf[2048]; + char data[IB_SMP_DATA_SIZE]; + + if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0)) + return "switch info query failed"; + + mad_dump_switchinfo(buf, sizeof buf, data, sizeof data); + + printf("# Switch info: %s\n%s", portid2str(dest), buf); + return 0; +} + +static char * +pkey_table(ib_portid_t *dest, char **argv, int argc) +{ + uint8_t data[IB_SMP_DATA_SIZE]; + uint32_t i, j, k; + uint16_t *p; + uint mod; + int n, t, phy_ports; + int portnum = 0; + + if (argc > 0) + portnum = strtol(argv[0], 0, 0); + + /* Get the partition capacity */ + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return "node info query failed"; + + mad_decode_field(data, IB_NODE_TYPE_F, &t); + mad_decode_field(data, IB_NODE_NPORTS_F, &phy_ports); + if (portnum > phy_ports) + return "invalid port number"; + + if ((t == IB_NODE_SWITCH) && (portnum != 0)) { + if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0)) + return "switch info failed"; + mad_decode_field(data, IB_SW_PARTITION_ENFORCE_CAP_F, &n); + } else + mad_decode_field(data, IB_NODE_PARTITION_CAP_F, &n); + + for (i = 0; i < (n + 31) / 32; i++) { + mod = i | (portnum << 16); + if (!smp_query(data, dest, IB_ATTR_PKEY_TBL, mod, 0)) + return "pkey table query failed"; + if (i + 1 == (n + 31) / 32) + k = ((n + 7 - i * 32) / 8) * 8; + else + k = 32; + p = (uint16_t *) data; + for (j = 0; j < k; j += 8, p += 8) { + printf("%4u: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", + (i * 32) + j, + ntohs(p[0]), ntohs(p[1]), + ntohs(p[2]), ntohs(p[3]), + ntohs(p[4]), ntohs(p[5]), + ntohs(p[6]), ntohs(p[7])); + } + } + printf("%d pkeys capacity for this port\n", n); + + return 0; +} + +static char *sl2vl_dump_table_entry(ib_portid_t *dest, int in, int out) +{ + char buf[2048]; + char data[IB_SMP_DATA_SIZE]; + int portnum = (in << 8) | out; + + if (!smp_query(data, dest, IB_ATTR_SLVL_TABLE, portnum, 0)) + return "slvl query failed"; + + mad_dump_sltovl(buf, sizeof buf, data, sizeof data); + printf("ports: in %2d, out %2d: ", in, out); + printf("%s", buf); + return 0; +} + +static char * +sl2vl_table(ib_portid_t *dest, char **argv, int argc) +{ + uint8_t data[IB_SMP_DATA_SIZE]; + int type, num_ports, portnum = 0; + int i; + char *ret; + + if (argc > 0) + portnum = strtol(argv[0], 0, 0); + + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return "node info query failed"; + + mad_decode_field(data, IB_NODE_TYPE_F, &type); + mad_decode_field(data, IB_NODE_NPORTS_F, &num_ports); + if (portnum > num_ports) + return "invalid port number"; + + printf("# SL2VL table: %s\n", portid2str(dest)); + printf("# SL: |"); + for (i = 0 ; i < 16 ; i++) + printf("%2d|", i); + printf("\n"); + + if (type != IB_NODE_SWITCH) + return sl2vl_dump_table_entry(dest, 0, 0); + + for (i = 0 ; i <= num_ports ; i++) { + ret = sl2vl_dump_table_entry(dest, i, portnum); + if (ret) + return ret; + } + return 0; +} + +static char *vlarb_dump_table_entry(ib_portid_t *dest, int portnum, int offset, unsigned cap) +{ + char buf[2048]; + char data[IB_SMP_DATA_SIZE]; + + if (!smp_query(data, dest, IB_ATTR_VL_ARBITRATION, + (offset << 16) | portnum, 0)) + return "vl arb query failed"; + mad_dump_vlarbitration(buf, sizeof(buf), data, cap * 2); + printf("%s", buf); + return 0; +} + +static char *vlarb_dump_table(ib_portid_t *dest, int portnum, + char *name, int offset, int cap) +{ + char *ret; + + printf("# %s priority VL Arbitration Table:", name); + ret = vlarb_dump_table_entry(dest, portnum, offset, + cap < 32 ? cap : 32); + if (!ret && cap > 32) + ret = vlarb_dump_table_entry(dest, portnum, offset + 1, + cap - 32); + return ret; +} + +static char * +vlarb_table(ib_portid_t *dest, char **argv, int argc) +{ + uint8_t data[IB_SMP_DATA_SIZE]; + int portnum = 0; + int type, enhsp0, lowcap, highcap; + char *ret = 0; + + if (argc > 0) + portnum = strtol(argv[0], 0, 0); + + /* port number of 0 could mean SP0 or port MAD arrives on */ + if (portnum == 0) { + if (!smp_query(data, dest, IB_ATTR_NODE_INFO, 0, 0)) + return "node info query failed"; + + mad_decode_field(data, IB_NODE_TYPE_F, &type); + if (type == IB_NODE_SWITCH) { + if (!smp_query(data, dest, IB_ATTR_SWITCH_INFO, 0, 0)) + return "switch info query failed"; + mad_decode_field(data, IB_SW_ENHANCED_PORT0_F, &enhsp0); + if (!enhsp0) { + printf("# No VLArbitration tables (BSP0): %s port %d\n", + portid2str(dest), 0); + return 0; + } + } + } + + if (!smp_query(data, dest, IB_ATTR_PORT_INFO, portnum, 0)) + return "port info query failed"; + + mad_decode_field(data, IB_PORT_VL_ARBITRATION_LOW_CAP_F, &lowcap); + mad_decode_field(data, IB_PORT_VL_ARBITRATION_HIGH_CAP_F,&highcap); + + printf("# VLArbitration tables: %s port %d LowCap %d HighCap %d\n", + portid2str(dest), portnum, lowcap, highcap); + + if (lowcap > 0) + ret = vlarb_dump_table(dest, portnum, "Low", 1, lowcap); + + if (!ret && highcap > 0) + ret = vlarb_dump_table(dest, portnum, "High", 3, highcap); + + return ret; +} + +static char * +guid_info(ib_portid_t *dest, char **argv, int argc) +{ + uint8_t data[IB_SMP_DATA_SIZE]; + uint32_t i, j, k; + uint64_t *p; + uint mod; + int n; + + /* Get the guid capacity */ + if (!smp_query(data, dest, IB_ATTR_PORT_INFO, 0, 0)) + return "port info failed"; + mad_decode_field(data, IB_PORT_GUID_CAP_F, &n); + + for (i = 0; i < (n + 7) / 8; i++) { + mod = i; + if (!smp_query(data, dest, IB_ATTR_GUID_INFO, mod, 0)) + return "guid info query failed"; + if (i + 1 == (n + 7) / 8) + k = ((n + 1 - i * 8) / 2) * 2; + else + k = 8; + p = (uint64_t *) data; + for (j = 0; j < k; j += 2, p += 2) { + printf("%4u: 0x%016"PRIx64" 0x%016"PRIx64"\n", + (i * 8) + j, + ntohll(p[0]), ntohll(p[1])); + } + } + printf("%d guids capacity for this port\n", n); + + return 0; +} + +static op_fn_t * +match_op(char *name) +{ + const match_rec_t *r; + for (r = match_tbl; r->name; r++) + if (!strcmp(r->name, name)) + return r->fn; + return 0; +} + +static void +usage(void) +{ + char *basename; + const match_rec_t *r; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -e(rr_show) -v(erbose) -D(irect) -G(uid) -s smlid -V(ersion) -C ca_name -P ca_port " + "-t(imeout) timeout_ms --node-name-map node-name-map] [op params]\n", + basename); + fprintf(stderr, "\tsupported ops:\n"); + for (r = match_tbl ; r->name ; r++) { + fprintf(stderr, "\t\t%s %s\n", r->name, + r->opt_portnum ? " []" : ""); + } + fprintf(stderr, "\n\texamples:\n"); + fprintf(stderr, "\t\t%s portinfo 3 1\t\t\t\t# portinfo by lid, with port modifier\n", basename); + fprintf(stderr, "\t\t%s -G switchinfo 0x2C9000100D051 1\t# switchinfo by guid\n", basename); + fprintf(stderr, "\t\t%s -D nodeinfo 0\t\t\t\t# nodeinfo by direct route\n", basename); + fprintf(stderr, "\t\t%s -c nodeinfo 6 0,12\t\t\t# nodeinfo by combined route\n", basename); + exit(-1); +} + +int +main(int argc, char **argv) +{ + int mgmt_classes[3] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS}; + ib_portid_t portid = {0}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + extern int ibdebug; + int timeout = 0, udebug = 0; + char *ca = 0; + int ca_port = 0; + char *err; + op_fn_t *fn; + + static char const str_opts[] = "C:P:t:s:devDcGVhu"; + static const struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "debug", 0, 0, 'd'}, + { "err_show", 0, 0, 'e'}, + { "verbose", 0, 0, 'v'}, + { "Direct", 0, 0, 'D'}, + { "combined", 0, 0, 'c'}, + { "Guid", 0, 0, 'G'}, + { "smlid", 1, 0, 's'}, + { "timeout", 1, 0, 't'}, + { "node-name-map", 1, 0, 1}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 1: + node_name_map_file = strdup(optarg); + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'e': + madrpc_show_errors(1); + break; + case 'D': + dest_type = IB_DEST_DRPATH; + break; + case 'c': + dest_type = IB_DEST_DRSLID; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'v': + verbose++; + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + if (!(fn = match_op(argv[0]))) + IBERROR("operation '%s' not supported", argv[0]); + + madrpc_init(ca, ca_port, mgmt_classes, 3); + node_name_map = open_node_name_map(node_name_map_file); + + if (dest_type != IB_DEST_DRSLID) { + if (ib_resolve_portid_str(&portid, argv[1], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[1]); + if ((err = fn(&portid, argv+2, argc-2))) + IBERROR("operation %s: %s", argv[0], err); + } else { + char concat[64]; + + memset(concat, 0, 64); + snprintf(concat, sizeof(concat), "%s %s", argv[1], argv[2]); + if (ib_resolve_portid_str(&portid, concat, dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", concat); + if ((err = fn(&portid, argv+3, argc-3))) + IBERROR("operation %s: %s", argv[0], err); + } + close_node_name_map(node_name_map); + exit(0); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/vendstat.c b/branches/winverbs/tools/infiniband_diags/src/vendstat.c new file mode 100644 index 00000000..4bbd7046 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/vendstat.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2004-2008 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. + * + */ + +#if HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include +#include +#if defined(_WIN32) +#include +#include +#include "..\..\..\..\etc\user\getopt.c" +#else +#include +#include +#include +#include +#endif + +#include +#include + +#include "ibdiag_common.h" + +#define IS3_DEVICE_ID 47396 + +#define IB_MLX_VENDOR_CLASS 10 +/* Vendor specific Attribute IDs */ +#define IB_MLX_IS3_GENERAL_INFO 0x17 +#define IB_MLX_IS3_CONFIG_SPACE_ACCESS 0x50 +/* Config space addresses */ +#define IB_MLX_IS3_PORT_XMIT_WAIT 0x10013C + +char *argv0 = "vendstat"; + +typedef struct { + uint16_t hw_revision; + uint16_t device_id; + uint8_t reserved[24]; + uint32_t uptime; +} is3_hw_info_t; + +typedef struct { + uint8_t resv1; + uint8_t major; + uint8_t minor; + uint8_t sub_minor; + uint32_t build_id; + uint8_t month; + uint8_t day; + uint16_t year; + uint16_t resv2; + uint16_t hour; + uint8_t psid[16]; + uint32_t ini_file_version; +} is3_fw_info_t; + +typedef struct { + uint8_t resv1; + uint8_t major; + uint8_t minor; + uint8_t sub_minor; + uint8_t resv2[28]; +} is3_sw_info_t; + +typedef struct { + uint8_t reserved[8]; + is3_hw_info_t hw_info; + is3_fw_info_t fw_info; + is3_sw_info_t sw_info; +} is3_general_info_t; + +typedef struct { + uint32_t address; + uint32_t data; + uint32_t mask; +} is3_record_t; + +typedef struct { + uint8_t reserved[8]; + is3_record_t record[18]; +} is3_config_space_t; + +static void +usage(void) +{ + char *basename; + + if (!(basename = strrchr(argv0, '/'))) + basename = argv0; + else + basename++; + + fprintf(stderr, "Usage: %s [-d(ebug) -N -w -G(uid) -C ca_name -P ca_port " + "-t(imeout) timeout_ms -V(ersion) -h(elp)] \n", + basename); + fprintf(stderr, "\tExamples:\n"); + fprintf(stderr, "\t\t%s -N 6\t\t# read IS3 general information\n", basename); + fprintf(stderr, "\t\t%s -w 6\t\t# read IS3 port xmit wait counters\n", basename); + exit(-1); +} + +int __cdecl +main(int argc, char **argv) +{ + int mgmt_classes[4] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, IB_MLX_VENDOR_CLASS}; + ib_portid_t *sm_id = 0, sm_portid = {0}; + ib_portid_t portid = {0}; + extern int ibdebug; + int dest_type = IB_DEST_LID; + int timeout = 0; /* use default */ + int port = 0; + char buf[1024]; + int udebug = 0; + char *ca = 0; + int ca_port = 0; + ib_vendor_call_t call; + is3_general_info_t *gi; + is3_config_space_t *cs; + int general_info = 0; + int xmit_wait = 0; + int i; + + static char str_opts[] = "C:P:s:t:dNwGVhu"; + static struct option long_opts[] = { + { "C", 1, 0, 'C'}, + { "P", 1, 0, 'P'}, + { "N", 1, 0, 'N'}, + { "w", 1, 0, 'w'}, + { "debug", 0, 0, 'd'}, + { "Guid", 0, 0, 'G'}, + { "sm_portid", 1, 0, 's'}, + { "timeout", 1, 0, 't'}, + { "Version", 0, 0, 'V'}, + { "help", 0, 0, 'h'}, + { "usage", 0, 0, 'u'}, + { 0 } + }; + + argv0 = argv[0]; + + while (1) { + int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); + if ( ch == -1 ) + break; + switch(ch) { + case 'C': + ca = optarg; + break; + case 'P': + ca_port = strtoul(optarg, 0, 0); + break; + case 'N': + general_info = 1; + break; + case 'w': + xmit_wait = 1; + break; + case 'd': + ibdebug++; + madrpc_show_errors(1); + umad_debug(udebug); + udebug++; + break; + case 'G': + dest_type = IB_DEST_GUID; + break; + case 's': + if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) + IBERROR("can't resolve SM destination port %s", optarg); + sm_id = &sm_portid; + break; + case 't': + timeout = strtoul(optarg, 0, 0); + madrpc_set_timeout(timeout); + break; + case 'V': + fprintf(stderr, "%s %s\n", argv0, get_build_version() ); + exit(-1); + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + port = strtoul(argv[1], 0, 0); + + madrpc_init(ca, ca_port, mgmt_classes, 4); + + if (argc) { + if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) + IBERROR("can't resolve destination port %s", argv[0]); + } else { + if (ib_resolve_self(&portid, &port, 0) < 0) + IBERROR("can't resolve self port %s", argv[0]); + } + + /* Only General Info and Port Xmit Wait Counters */ + /* queries are currently supported */ + if (!general_info && !xmit_wait) + IBERROR("at least one of -N and -w must be specified"); + + /* These are Mellanox specific vendor MADs */ + /* but vendors change the VendorId so how know for sure ? */ + /* Would need a list of these and it might not be complete */ + /* so for right now, punt on this */ + + memset(&call, 0, sizeof(call)); + call.mgmt_class = IB_MLX_VENDOR_CLASS; + call.method = IB_MAD_METHOD_GET; + call.timeout = timeout; + + memset(&buf, 0, sizeof(buf)); + /* vendor ClassPortInfo is required attribute if class supported */ + call.attrid = CLASS_PORT_INFO; + if (!ib_vendor_call(&buf, &portid, &call)) + IBERROR("classportinfo query"); + + memset(&buf, 0, sizeof(buf)); + call.attrid = IB_MLX_IS3_GENERAL_INFO; + if (!ib_vendor_call(&buf, &portid, &call)) + IBERROR("vendstat"); + gi = (is3_general_info_t *)&buf; + + if (general_info) { + /* dump IS3 general info here */ + printf("hw_dev_rev: 0x%04x\n", ntohs(gi->hw_info.hw_revision)); + printf("hw_dev_id: 0x%04x\n", ntohs(gi->hw_info.device_id)); + printf("hw_uptime: 0x%08x\n", ntohl(gi->hw_info.uptime)); + printf("fw_version: %02d.%02d.%02d\n", + gi->fw_info.major, gi->fw_info.minor, gi->fw_info.sub_minor); + printf("fw_build_id: 0x%04x\n", ntohl(gi->fw_info.build_id)); + printf("fw_date: %02d/%02d/%04x\n", + gi->fw_info.month, gi->fw_info.day, ntohs(gi->fw_info.year)); + printf("fw_psid: '%s'\n", gi->fw_info.psid); + printf("fw_ini_ver: %d\n", ntohl(gi->fw_info.ini_file_version)); + printf("sw_version: %02d.%02d.%02d\n", + gi->sw_info.major, gi->sw_info.minor, gi->sw_info.sub_minor); + } + + if (xmit_wait) { + if (ntohs(gi->hw_info.device_id) != IS3_DEVICE_ID) + IBERROR("Unsupported device ID 0x%x", ntohs(gi->hw_info.device_id)); + + memset(&buf, 0, sizeof(buf)); + call.attrid = IB_MLX_IS3_CONFIG_SPACE_ACCESS; + /* Limit of 18 accesses per MAD ? */ + call.mod = 2 << 22 | 16 << 16; /* 16 records */ + /* Set record addresses for each port */ + cs = (is3_config_space_t *)&buf; + for (i = 0; i < 16; i++) + cs->record[i].address = htonl(IB_MLX_IS3_PORT_XMIT_WAIT + ((i + 1) << 12)); + if (!ib_vendor_call(&buf, &portid, &call)) + IBERROR("vendstat"); + + for (i = 0; i < 16; i++) + if (cs->record[i].data) /* PortXmitWait is 32 bit counter */ + printf("Port %d: PortXmitWait 0x%x\n", i + 4, ntohl(cs->record[i].data)); /* port 4 is first port */ + + /* Last 8 ports is another query */ + memset(&buf, 0, sizeof(buf)); + call.attrid = IB_MLX_IS3_CONFIG_SPACE_ACCESS; + call.mod = 2 << 22 | 8 << 16; /* 8 records */ + /* Set record addresses for each port */ + cs = (is3_config_space_t *)&buf; + for (i = 0; i < 8; i++) + cs->record[i].address = htonl(IB_MLX_IS3_PORT_XMIT_WAIT + ((i + 17) << 12)); + if (!ib_vendor_call(&buf, &portid, &call)) + IBERROR("vendstat"); + + for (i = 0; i < 8; i++) + if (cs->record[i].data) /* PortXmitWait is 32 bit counter */ + printf("Port %d: PortXmitWait 0x%x\n", + i < 4 ? i + 21 : i - 3, + ntohl(cs->record[i].data)); + } + + exit(0); +} diff --git a/branches/winverbs/tools/infiniband_diags/src/vendstat/SOURCES b/branches/winverbs/tools/infiniband_diags/src/vendstat/SOURCES new file mode 100644 index 00000000..c61861f9 --- /dev/null +++ b/branches/winverbs/tools/infiniband_diags/src/vendstat/SOURCES @@ -0,0 +1,32 @@ +TARGETNAME = vendstat +TARGETPATH = ..\..\..\..\bin\user\obj$(BUILD_ALT_DIR) +TARGETTYPE = PROGRAM + +UMTYPE = console +UMENTRY = main + +USE_MSVCRT = 1 +USE_STL = 1 +USE_NATIVE_EH = 1 +USE_IOSTREAM = 1 + +SOURCES = ..\vendstat.c ..\ibdiag_common.c + +INCLUDES = ..;..\..\include;..\..\..\..\ulp\libibmad\include;..\..\..\..\ulp\libibumad\include;..\..\..\..\inc;..\..\..\..\inc\user; + +TARGETLIBS = \ + $(SDK_LIB_PATH)\kernel32.lib \ + $(SDK_LIB_PATH)\advapi32.lib \ + $(SDK_LIB_PATH)\user32.lib \ + $(SDK_LIB_PATH)\ole32.lib \ + $(SDK_LIB_PATH)\ws2_32.lib \ +!if $(FREEBUILD) + $(TARGETPATH)\*\complib.lib \ + $(TARGETPATH)\*\libibmad.lib \ + $(TARGETPATH)\*\libibumad.lib +!else + $(TARGETPATH)\*\complibd.lib \ + $(TARGETPATH)\*\libibmadd.lib \ + $(TARGETPATH)\*\libibumadd.lib +!endif +