libibnetdisc: Convert to a multi-smp algorithm
PATCH v3 1/2 libibnetdisc: Convert to a multi-smp algorithm
From: Ira Weiny <[email protected]>
Date: Fri, 22 Jan 2010 17:33:30 -0800
Subject: [PATCH] libibnetdisc: Convert to a multi-smp algorithm
v3: change DEFAULT_MAX_SMP_ON_WIRE to 2
Allow for multiple SMP's to be on the wire at a single time. This algorithm splits the processing of SMP's to a small smp engine which may be useful to split out in the future.
--- infiniband-diags/libibnetdisc/Makefile.am | 2 +- infiniband-diags/libibnetdisc/src/ibnetdisc.c | 626 ++++++++++--------------- infiniband-diags/libibnetdisc/src/internal.h | 39 ++- infiniband-diags/libibnetdisc/src/query_smp.c | 249 ++++++++++ 4 files changed, 535 insertions(+), 381 deletions(-) create mode 100644 infiniband-diags/libibnetdisc/src/query_smp.c
infiniband-diags/libibnetdisc/Makefile.am +1 -1
@@ -23,7 +23,7 @@ libibnetdisc_version_script = endif libibnetdisc_la_SOURCES = src/ibnetdisc.c src/ibnetdisc_cache.c src/chassis.c \ - src/chassis.h src/internal.h + src/chassis.h src/internal.h src/query_smp.c libibnetdisc_la_CFLAGS = -Wall $(DBGFLAGS) libibnetdisc_la_LDFLAGS = -version-info $(ibnetdisc_api_version) \ -export-dynamic $(libibnetdisc_version_script) \
infiniband-diags/libibnetdisc/src/ibnetdisc.c +251 -375
717 lines not on this page · raw message
infiniband-diags/libibnetdisc/src/internal.h +34 -5
@@ -39,6 +39,7 @@#define _INTERNAL_H_#include <infiniband/ibnetdisc.h> +#include <complib/cl_qmap.h> #define IBND_DEBUG (fmt, ...) \ if (ibdebug) { \
@@ -52,16 +53,44 @@#define MAXHOPS 63 -typedef struct ibnd_node_scan { -ibnd_node_t *node; -struct ibnd_node_scan *dnext;/* nodesdist next */ -}ibnd_node_scan_t ; +#define DEFAULT_MAX_SMP_ON_WIRE 2typedef struct ibnd_scan { -ibnd_node_scan_t *nodesdist[MAXHOPS +1 ];ib_portid_t selfportid; +ibnd_fabric_t *fabric; }ibnd_scan_t ; + +typedef struct ibnd_smp ibnd_smp_t ; +typedef struct smp_engine smp_engine_t ; +typedef int (*smp_comp_cb_t )(smp_engine_t *engine,ibnd_smp_t * smp, +uint8_t *mad_resp,void *cb_data); +struct ibnd_smp { +cl_map_item_t on_wire; +struct ibnd_smp * qnext; +smp_comp_cb_t cb; +void * cb_data; +ib_portid_t path; +ib_rpc_t rpc; +}; +struct smp_engine { +struct ibmad_port *ibmad_port; +ibnd_smp_t *smp_queue_head; +ibnd_smp_t *smp_queue_tail; +void * user_data; +cl_qmap_t smps_on_wire; +int num_smps_outstanding; +int max_smps_on_wire; +}; + +void smp_engine_init (smp_engine_t * engine,struct ibmad_port *ibmad_port, +void * user_data,int max_smps_on_wire); +int issue_smp (smp_engine_t *engine,ib_portid_t * portid, +unsigned attrid,unsigned mod, +smp_comp_cb_t cb,void * cb_data); +int process_mads (smp_engine_t *engine); +void smp_engine_destroy (smp_engine_t *engine); +void add_to_nodeguid_hash (ibnd_node_t * node,ibnd_node_t * hash[]);void add_to_portguid_hash (ibnd_port_t * port,ibnd_port_t * hash[]);
infiniband-diags/libibnetdisc/src/query_smp.c new file +249 -0
249 lines not on this page · raw message
Signature · 6 lines
1.5.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Sasha Khapyorsky
AppliedQuoted 5 lines · Ira Weiny
From: Ira Weiny <[email protected]>
Date: Fri, 22 Jan 2010 17:33:30 -0800
Subject: [PATCH] libibnetdisc: Convert to a multi-smp algorithm
Quoted 7 lines
v3: change
DEFAULT_MAX_SMP_ON_WIREto 2Allow for multiple SMP's to be on the wire at a single time. This algorithm splits the processing of SMP's to a small smp engine which may be useful to split out in the future.
Signed-off-by Ira Weiny <[email protected]>
Applied. Thanks.
However see some comments and questions below.
Quoted 42 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +40
-1+static int recv_port_info (smp_engine_t *engine,ibnd_smp_t * smp, +uint8_t *mad,void *cb_data) +{ +ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric; +ibnd_node_t *node = (ibnd_node_t *)cb_data; +ibnd_port_t *port; +uint8_t *port_info = mad +IB_SMP_DATA_OFFS ; +uint8_t port_num, local_port; + + port_num =mad_get_field (mad,0 ,IB_MAD_ATTRMOD_F ); + local_port =mad_get_field (port_info,0 ,IB_PORT_LOCAL_PORT_F ); + +/* this may have been created before */ + port = node->ports[port_num]; +if (!port) { + port = node->ports[port_num] =calloc (1 ,sizeof (*port)); +if (!port) { +IBND_ERROR ("Failed to allocate port\n" ); +return -1 ; + } + } + +memcpy (port->info, port_info,sizeof (port->info)); + port->node = node; + port->portnum = port_num; + port->ext_portnum =0 ; + port->base_lid = (uint16_t )mad_get_field (port->info,0 ,IB_PORT_LID_F ); + port->lmc = (uint8_t )mad_get_field (port->info,0 ,IB_PORT_LMC_F ); + +if (port_num ==0 ) { + node->smalid = port->base_lid; + node->smalmc = port->lmc; + }else if (node->type ==IB_NODE_SWITCH ) { + port->base_lid = node->smalid; + port->lmc = node->smalmc; + } + +add_to_portguid_hash (port, fabric->portstbl); + +debug_port (&smp->path, port); -mad_dump_node_type (type,64 , &node->type,sizeof (int ));
infiniband-diags/libibnetdisc/src/ibnetdisc.c static int extend_dpath(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric, · line 211
Quoted 10 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +5
-5-printf ("%s -> %s %s {%016" PRIx64"} portnum %d base lid %d-%d\"%s\"\n" , -portid2str (path), prompt, type, node->guid, - node->type ==IB_NODE_SWITCH ?0 : port->portnum, - port->base_lid, - port->base_lid + (1 << port->lmc) -1 , node->nodedesc); +if (port_num && + (mad_get_field (port->info,0 ,IB_PORT_PHYS_STATE_F ) + ==IB_PORT_PHYS_STATE_LINKUP ) + && + (node->type ==IB_NODE_SWITCH || node == fabric->from_node)) {
What will happen when ibnetdiscover runs from host connected by two ports to different subnets? Wouldn't it run over both fabrics (following PortInfo querying loop in recv_node_info() below)?
Quoted 8 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +8
-0+ +ib_portid_t path = smp->path; +if (extend_dpath (engine, &path, port_num) !=-1 ) +query_node_info (engine, &path, node); + } + +return 0 ; +}
[snip]
Quoted 57 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +50
-4+static int recv_node_info (smp_engine_t *engine,ibnd_smp_t * smp, +uint8_t *mad,void *cb_data) +{ +ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric; +int i =0 ; +uint8_t *node_info = mad +IB_SMP_DATA_OFFS ; +ibnd_node_t * rem_node = (ibnd_node_t *)cb_data;ibnd_node_t *node; +int node_is_new =0 ; +uint64_t node_guid =mad_get_field64 (node_info,0 ,IB_NODE_GUID_F ); +uint64_t port_guid =mad_get_field64 (node_info,0 ,IB_NODE_PORT_GUID_F ); +int port_num =mad_get_field (node_info,0 ,IB_NODE_LOCAL_PORT_F ); +ibnd_port_t *port =NULL ; -for (node = fabric->nodestbl[hash]; node; node = node->htnext) -if (node->guid == new->guid) -return node; + node =ibnd_find_node_guid (fabric, node_guid); +if (!node) { + node =create_node (engine, &smp->path, node_info); +if (!node) +return -1 ; + node_is_new =1 ; + } +IBND_DEBUG ("Found %s node GUID %lx (%s)\n" , + (node_is_new) ?"new" :"old" , node->guid, +portid2str (&smp->path)); -return NULL ; + port = node->ports[port_num]; +if (!port) { +/* If we have not see this port before create a shell for it */ + port = node->ports[port_num] =calloc (1 ,sizeof (*port)); + port->node = node; + port->portnum = port_num; + } + port->guid = port_guid; + +if (rem_node ==NULL )/* this is the start node */ + fabric->from_node = node; +else { +/* link ports... */ +int rem_port_num =get_last_port (&smp->path); + +if (!rem_node->ports[rem_port_num]) { +IBND_ERROR ("Internal Error; " +"Node(%p) %lx Port %d no port created!?!?!?\n\n" , + rem_node, rem_node->guid, rem_port_num); +return (-1 ); + } + +link_ports (node, port, rem_node, rem_node->ports[rem_port_num]); + } + +if (!node_is_new) +return 0 ; +
infiniband-diags/libibnetdisc/src/ibnetdisc.c static int extend_dpath(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric, · line 346
Quoted 10 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +10
-0+query_node_desc (engine, &smp->path, node); + +if (node->type ==IB_NODE_SWITCH ) +query_switch_info (engine, &smp->path, node); + +/* process all the ports on this node */ +for (i = (node->type ==IB_NODE_SWITCH ) ?0 :1 ; + i <= node->numports; i++) { +query_port_info (engine, &smp->path, node, i); + }
This one.
Quoted 3 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +3
-0+ +return 0 ; +}
[snip]
infiniband-diags/libibnetdisc/src/internal.h line 42
Quoted 9 lines
infiniband-diags/libibnetdisc/src/internal.h +1
-0@@ -39,6 +39,7 @@#define _INTERNAL_H_#include <infiniband/ibnetdisc.h> +#include <complib/cl_qmap.h>
I'm not really happy with complib dependency introduction - we had an issues with it in the past.
Also I think that we can implement simpler transaction tracker (likely even more efficient) by storing sent MADs in cyclic array and encoding its index as part of TRID.
Quoted 177 lines
infiniband-diags/libibnetdisc/src/internal.h +33
-5#define IBND_DEBUG (fmt, ...) \ if (ibdebug) { \@@ -52,16 +53,44 @@#define MAXHOPS 63 -typedef struct ibnd_node_scan { -ibnd_node_t *node; -struct ibnd_node_scan *dnext;/* nodesdist next */ -}ibnd_node_scan_t ; +#define DEFAULT_MAX_SMP_ON_WIRE 2typedef struct ibnd_scan { -ibnd_node_scan_t *nodesdist[MAXHOPS +1 ];ib_portid_t selfportid; +ibnd_fabric_t *fabric; }ibnd_scan_t ; + +typedef struct ibnd_smp ibnd_smp_t ; +typedef struct smp_engine smp_engine_t ; +typedef int (*smp_comp_cb_t )(smp_engine_t *engine,ibnd_smp_t * smp, +uint8_t *mad_resp,void *cb_data); +struct ibnd_smp { +cl_map_item_t on_wire; +struct ibnd_smp * qnext; +smp_comp_cb_t cb; +void * cb_data; +ib_portid_t path; +ib_rpc_t rpc; +}; +struct smp_engine { +struct ibmad_port *ibmad_port; +ibnd_smp_t *smp_queue_head; +ibnd_smp_t *smp_queue_tail; +void * user_data; +cl_qmap_t smps_on_wire; +int num_smps_outstanding; +int max_smps_on_wire; +}; + +void smp_engine_init (smp_engine_t * engine,struct ibmad_port *ibmad_port, +void * user_data,int max_smps_on_wire); +int issue_smp (smp_engine_t *engine,ib_portid_t * portid, +unsigned attrid,unsigned mod, +smp_comp_cb_t cb,void * cb_data); +int process_mads (smp_engine_t *engine); +void smp_engine_destroy (smp_engine_t *engine); +void add_to_nodeguid_hash (ibnd_node_t * node,ibnd_node_t * hash[]);void add_to_portguid_hash (ibnd_port_t * port,ibnd_port_t * hash[]);infiniband-diags/libibnetdisc/src/query_smp.c new file +118
-0@@ -0,0 +1,249 @@ +/* +* Copyright (c) 2010 Lawrence Livermore National Laboratory +* +* 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 <errno.h> +#include <infiniband/ibnetdisc.h> +#include <infiniband/umad.h> +#include "internal.h" + +void +queue_smp (smp_engine_t *engine,ibnd_smp_t *smp) +{ + smp->qnext =NULL ; +if (!engine->smp_queue_head) { + engine->smp_queue_head = smp; + engine->smp_queue_tail = smp; + }else { + engine->smp_queue_tail->qnext = smp; + engine->smp_queue_tail = smp; + } +} + +ibnd_smp_t * +get_smp (smp_engine_t *engine) +{ +ibnd_smp_t *head = engine->smp_queue_head; +ibnd_smp_t *tail = engine->smp_queue_tail; +ibnd_smp_t *rc = head; +if (head) { +if (tail == head) + engine->smp_queue_tail =NULL ; + engine->smp_queue_head = head->qnext; + } +return rc; +} + +int send_smp (ibnd_smp_t * smp,struct ibmad_port *srcport) +{ +int rc =0 ; +uint8_t umad[1024 ]; +ib_rpc_t *rpc = &smp->rpc; + +memset (umad,0 ,umad_size () +IB_MAD_SIZE ); + +if ((rc =mad_build_pkt (umad, &smp->rpc, &smp->path,NULL ,NULL )) + <0 ) { +IBND_ERROR ("mad_build_pkt failed; %d" , rc); +return rc; + } + +if ((rc =umad_send (mad_rpc_portid (srcport), +mad_rpc_class_agent (srcport, rpc->mgtclass), + umad,IB_MAD_SIZE , +mad_get_timeout (srcport, rpc->timeout), +mad_get_retries (srcport))) <0 ) { +IBND_ERROR ("send failed; %d" , rc); +return rc; + } + +return 0 ; +} + +static int process_smp_queue (smp_engine_t *engine) +{ +int rc =0 ; +ibnd_smp_t *smp; +while (cl_qmap_count (&engine->smps_on_wire) < engine->max_smps_on_wire) { + smp =get_smp (engine); +if (!smp) +return 0 ; + +cl_qmap_insert (&engine->smps_on_wire, (uint32_t )smp->rpc.trid, + (cl_map_item_t *)smp); +if ((rc =send_smp (smp, engine->ibmad_port)) !=0 ) +return rc; + } +return 0 ; +} + +int issue_smp (smp_engine_t *engine,ib_portid_t * portid, +unsigned attrid,unsigned mod, +smp_comp_cb_t cb,void * cb_data) +{ +ibnd_smp_t *smp =calloc (1 ,sizeof *smp); +if (!smp) { +IBND_ERROR ("OOM" ); +return -ENOMEM ; + } +
infiniband-diags/libibnetdisc/src/query_smp.c line 128
Quoted 10 lines
infiniband-diags/libibnetdisc/src/query_smp.c new file +10
-0+ smp->cb = cb; + smp->cb_data = cb_data; + smp->path = *portid; + smp->rpc.method =IB_MAD_METHOD_GET ; + smp->rpc.attr.id = attrid; + smp->rpc.attr.mod = mod; + smp->rpc.timeout =mad_get_timeout (engine->ibmad_port,0 ); + smp->rpc.datasz =IB_SMP_DATA_SIZE ; + smp->rpc.dataoffs =IB_SMP_DATA_OFFS ; + smp->rpc.trid =mad_trid ();
BTW, by reviewing mad_trid() code in libibmad:
uint64_t mad_trid(void)
{
static uint64_t base;
static uint64_t trid;
uint64_t next;
if (!base) {
srandom((int)time(0) * getpid());
base = random();
trid = random();
}
next = ++trid | (base << 32);
return next;
}For me it doesn't look as thread safe function.
Quoted 104 lines
infiniband-diags/libibnetdisc/src/query_smp.c new file +104
-0+ +if ((portid->lid <=0 ) || + (portid->drpath.drslid ==0xffff ) || + (portid->drpath.drdlid ==0xffff )) + smp->rpc.mgtclass =IB_SMI_DIRECT_CLASS ;/* direct SMI */ +else + smp->rpc.mgtclass =IB_SMI_CLASS ;/* Lid routed SMI */ + + portid->sl =0 ; + portid->qp =0 ; + + engine->num_smps_outstanding++; +queue_smp (engine, smp); +return (process_smp_queue (engine)); +} + +int process_one_recv (smp_engine_t *engine) +{ +int rc =0 ; +int status =0 ; +ibnd_smp_t *smp; +uint8_t *mad; +uint32_t trid; +uint8_t umad[umad_size () +IB_MAD_SIZE ]; +int length =umad_size () +IB_MAD_SIZE ; + +memset (umad,0 ,sizeof (umad)); + +/* wait for the next message */ +if ((rc =umad_recv (mad_rpc_portid (engine->ibmad_port), umad, &length, +0 )) <0 ) { +if (rc == -EWOULDBLOCK ) +return 0 ; +IBND_ERROR ("umad_recv failed: %d\n" , rc); +return -1 ; + } + + rc =process_smp_queue (engine); + + mad =umad_get_mad (umad); + trid = (uint32_t )mad_get_field64 (mad,0 ,IB_MAD_TRID_F ); + + smp = (ibnd_smp_t *)cl_qmap_remove (&engine->smps_on_wire, trid); +if ((cl_map_item_t *)smp ==cl_qmap_end (&engine->smps_on_wire)) { +IBND_ERROR ("Failed to find matching smp for trid (%x)\n" , + trid); +return -1 ; + } + +if (rc) + goto error; + +if ((status =umad_status (umad))) { +IBND_ERROR ("umad (%s Attr 0x%x:%u) bad status %d; %s\n" , +portid2str (&smp->path), + smp->rpc.attr.id, smp->rpc.attr.mod, + status,strerror (status)); + }else if ((status =mad_get_field (mad,0 ,IB_DRSMP_STATUS_F ))) { +IBND_ERROR ("mad (%s Attr 0x%x:%u) bad status 0x%x\n" , +portid2str (&smp->path), + smp->rpc.attr.id, smp->rpc.attr.mod, + status); + }else + rc = smp->cb (engine, smp, mad, smp->cb_data); + +error: +free (smp); + engine->num_smps_outstanding--; +return (rc); +} + +void smp_engine_init (smp_engine_t * engine,struct ibmad_port *ibmad_port, +void * user_data,int max_smps_on_wire) +{ +memset (engine,'\0' ,sizeof (*engine)); + engine->ibmad_port = ibmad_port; + engine->user_data = user_data; +cl_qmap_init (&engine->smps_on_wire); + engine->num_smps_outstanding =0 ; + engine->max_smps_on_wire = max_smps_on_wire; +} + +void smp_engine_destroy (smp_engine_t *engine) +{ +cl_map_item_t *item; +ibnd_smp_t *smp; + +/* remove queued smps */ + smp =get_smp (engine); +if (smp) +IBND_ERROR ("outstanding SMP's\n" ); +for (/* */ ; smp; smp =get_smp (engine)) { +free (smp); + } + +/* remove smps from the wire queue */ + item =cl_qmap_head (&engine->smps_on_wire); +if (item !=cl_qmap_end (&engine->smps_on_wire)) +IBND_ERROR ("outstanding SMP's on wire\n" ); +for (/* */ ; item !=cl_qmap_end (&engine->smps_on_wire); + item =cl_qmap_head (&engine->smps_on_wire)) { +cl_qmap_remove_item (&engine->smps_on_wire, item); +free (item); + }
infiniband-diags/libibnetdisc/src/query_smp.c line 242
Quoted 10 lines
infiniband-diags/libibnetdisc/src/query_smp.c new file +10
-0+ + engine->num_smps_outstanding =0 ; +} + +int process_mads (smp_engine_t *engine) +{ +int rc =0 ; +while (engine->num_smps_outstanding >0 ) { +if ((rc =process_smp_queue (engine)) !=0 ) +return rc;
Is it really needed to run process_smp_queue() here (assuming that it is already executed in issue_smp() and process_one_recv())? Or this is just for handling process_one_recv() error case? If so wouldn't it better to run it there?
Sasha
Quoted 10 lines
infiniband-diags/libibnetdisc/src/query_smp.c new file +7
-0+while (!cl_is_qmap_empty (&engine->smps_on_wire)) +if ((rc =process_one_recv (engine)) !=0 ) +return rc; + } +return 0 ; +} +Signature · 1 line
1.5.4.5
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 2 lines · Sasha Khapyorsky
However see some comments and questions below.
Another thought. What about API like:
ibnd_discover_fabric(cosnt char *ca_name, unsigned port_num, struct ibnd_config *cfg);
So libibnetdisc will be responsible for opening and closing its own port and in this way will be fully reenterable?
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 11 lines · On Tue, 13 Apr 2010 16:25:31 +0300 Sasha Khapyorsky…
Quoted 2 lines · Sasha Khapyorsky
However see some comments and questions below.
Another thought. What about API like:
ibnd_discover_fabric(cosnt char *ca_name, unsigned port_num, struct ibnd_config *cfg);So libibnetdisc will be responsible for opening and closing its own port and in this way will be fully reenterable?
If we are going to do something like this why not more like a context?
Something like this?
ibqueryerrors.c
query_errors_ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4);
{
ibnd_context_t ctx;
ctx.ca_name = ibd_ca;
ctx.ca_port = ibd_ca_port;
ctx.portid = portid;
ctx.hops = hops;
fabric = ibnd_discover_fabric(&ctx); /* opens it's own ibmad_port */
}...
Ira
Quoted 2 lines
Sasha
Signature · 9 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 16 lines · Ira Weiny
If we are going to do something like this why not more like a context?
Something like this?
ibqueryerrors.cquery_errors_ibmad_port = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4); { ibnd_context_t ctx; ctx.ca_name = ibd_ca; ctx.ca_port = ibd_ca_port; ctx.portid = portid; ctx.hops = hops; fabric = ibnd_discover_fabric(&ctx); /* opens it's own ibmad_port */ }
Quoted 1 line
...
I didn't think about "context"-like, more as about few mandatory (explicit) parameters + optional config.
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 11 lines · On Tue, 13 Apr 2010 16:25:31 +0300 Sasha Khapyorsky…
Quoted 2 lines · Sasha Khapyorsky
However see some comments and questions below.
Another thought. What about API like:
ibnd_discover_fabric(cosnt char *ca_name, unsigned port_num, struct ibnd_config *cfg);So libibnetdisc will be responsible for opening and closing its own port and in this way will be fully reenterable?
I think we need this... But this alone will not fix ibnetdisc...
I found out why "iblinkinfo -S" is hanging for me. The new algorithm has the library using both libibmad and libibumad calls simultaneously.
These libraries were not designed to be used this way. Therefore, I don't think there is any direct bug in those layers. However, this is why I thought it was better for ibnetdisc to sit on top of ibmad and not use the umad layer.
Anyway, I think it is a mistake to pass an ibmad_port construct directly to this library now. Here is why.
umad_recv in query_smp.c and ib_resolve_self_via in ibnetdisc.c conflicted. The underlying call to _do_madrpc was discarding the response MAD which query_smp.c:umad_recv was expecting. This would result in a hang forever.[*] This will not happen unless you use -S because -S causes ibnetdisc.c to call ib_resolve_self_via to determine the "drslid". Basically ibnetdisc needs to open an ibmad_port for any libibmad call and a fd via umad_open_port for the parallel stuff.[#]
If we change the API to specify the ca name and port then the library can open 2 ports (or as many as it wants) and use them appropriately. I think this is the only solution which does not involve fixing libibmad.
So what about something like this:
int ibnd_discover_fabric(ibnd_fabric_t **fabric,
cosnt char *ca_name, <== could we even default this? struct ibnd_config *cfg);
I don't mind the ibnd_config_t struct but I don't think it should be visible to the user. Make it opaque and use "set" functions. Something like.
ibnd_fabric_t *fabric;ibnd_config_t cfg;ib_portid_t * from;
ibnd_set_hops(&cfg, hops); <== default -1ibnd_set_port_num(&cfg, port_num); <== default 1ibnd_set_max_smps(&cfg, max_smps); <== default 2ibnd_set_from_node(&cfg, from); <== default NULL
if (ibnd_discover_fabric(&fabric, "foo", &cfg)) { <== anything not in cfg is
defaulted here
fprintf(stderr, "Wow it failed\n");
}
This allows us to change ibnd_config structure any time we want without affecting the API. I don't think the "pad" you used is a good idea.
Also since we are breaking the API we might as well return the fabric as a parameter and have an error code. But I could go either way on this one.
Ira
[*] query_smp.c probably should have it's own timeout here but we can discuss later.
[#] What sucks about this is that libibmad already has the functionality to open the umad port and configure it (50 line function). Now we will be duplicating this functionality. I still maintain that making libibmad thread safe would be very beneficial, if not necessary. For example handling RMPP and redirection is already in libibmad. Why make people reimplement it on their own if they want concurrent execution of any kind? <sigh>
Signature · 9 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Hi Ira,
Quoted 24 lines · Ira Weiny
Quoted 11 lines · On Tue, 13 Apr 2010 16:25:31 +0300 Sasha Khapyorsky…
Quoted 2 lines · Sasha Khapyorsky
However see some comments and questions below.
Another thought. What about API like:
ibnd_discover_fabric(cosnt char *ca_name, unsigned port_num, struct ibnd_config *cfg);So libibnetdisc will be responsible for opening and closing its own port and in this way will be fully reenterable?
I think we need this... But this alone will not fix ibnetdisc...
I found out why "iblinkinfo -S" is hanging for me. The new algorithm has the library using both libibmad and libibumad calls simultaneously.
These libraries were not designed to be used this way. Therefore, I don't think there is any direct bug in those layers. However, this is why I thought it was better for ibnetdisc to sit on top of ibmad and not use the umad layer.
Quoted 6 lines
Anyway, I think it is a mistake to pass an
ibmad_portconstruct directly to this library now. Here is why.
umad_recvinquery_smp.candib_resolve_self_viainibnetdisc.cconflicted. The underlying call to_do_madrpcwas discarding the response MAD which query_smp.c:umad_recv was expecting.
This makes sense for me.
Quoted 8 lines
If we change the API to specify the ca name and port then the library can open 2 ports (or as many as it wants) and use them appropriately. I think this is the only solution which does not involve fixing libibmad.
So what about something like this:
int ibnd_discover_fabric(ibnd_fabric_t **fabric,
cosnt char *ca_name, <== could we even default this?
I would think about ca_name and port_number. And this is of course may have default (NULL, 0).
Quoted 1 line
struct ibnd_config *cfg);
What is wrong with current ibdn_fabric_t *ibnd_discover_fabric(...)? Why do we need an extra parameter?
Quoted 4 lines
I don't mind the
ibnd_config_tstruct but I don't think it should be visible to the user. Make it opaque and use "set" functions. Something like.
Quoted 8 lines
ibnd_fabric_t*fabric;ibnd_config_tcfg;ib_portid_t* from;
ibnd_set_hops(&cfg, hops); <== default -1ibnd_set_port_num(&cfg, port_num); <== default 1ibnd_set_max_smps(&cfg, max_smps); <== default 2ibnd_set_from_node(&cfg, from); <== default NULL
I would prefer to not complicate API with ibnd_set_this() helpers. It would be necessary to add new ones in the future which will lead to API changes.
Quoted 7 lines
if (
ibnd_discover_fabric(&fabric, "foo", &cfg)) { <== anything not in cfg is
defaulted here
fprintf(stderr, "Wow it failed\n");
}This allows us to change
ibnd_configstructure any time we want without affecting the API. I don't think the "pad" you used is a good idea.
Without padding we will break ABI each time when new field is added to the config structure.
Quoted 6 lines
Also since we are breaking the API we might as well return the fabric as a parameter and have an error code. But I could go either way on this one.
Ira
Quoted 6 lines
[*]
query_smp.cprobably should have it's own timeout here but we can discuss later.[#] What sucks about this is that libibmad already has the functionality to open the umad port and configure it (50 line function). Now we will be duplicating this functionality.
I think you can use mad_rpc_open_port(ca_name, port_number, ...) just fine (and so the rest of libibmad stuff) - it will open separate fd.
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 40 lines · On Fri, 7 May 2010 13:50:53 -0700 Sasha Khapyorsky…
Hi Ira,
Quoted 24 lines · Ira Weiny
Quoted 11 lines · On Tue, 13 Apr 2010 16:25:31 +0300 Sasha Khapyorsky…
Quoted 2 lines · Sasha Khapyorsky
However see some comments and questions below.
Another thought. What about API like:
ibnd_discover_fabric(cosnt char *ca_name, unsigned port_num, struct ibnd_config *cfg);So libibnetdisc will be responsible for opening and closing its own port and in this way will be fully reenterable?
I think we need this... But this alone will not fix ibnetdisc...
I found out why "iblinkinfo -S" is hanging for me. The new algorithm has the library using both libibmad and libibumad calls simultaneously.
These libraries were not designed to be used this way. Therefore, I don't think there is any direct bug in those layers. However, this is why I thought it was better for ibnetdisc to sit on top of ibmad and not use the umad layer.
Quoted 6 lines
Anyway, I think it is a mistake to pass an
ibmad_portconstruct directly to this library now. Here is why.
umad_recvinquery_smp.candib_resolve_self_viainibnetdisc.cconflicted. The underlying call to_do_madrpcwas discarding the response MAD which query_smp.c:umad_recv was expecting.This makes sense for me.
Quoted 4 lines
If we change the API to specify the ca name and port then the library can open 2 ports (or as many as it wants) and use them appropriately. I think this is the only solution which does not involve fixing libibmad.
Quoted 7 lines
Quoted 4 lines
So what about something like this:
int ibnd_discover_fabric(ibnd_fabric_t **fabric,
cosnt char *ca_name, <== could we even default this?I would think about
ca_nameandport_number. And this is of course may have default (NULL, 0).
Ok, ca_name and ca_port will be explicit.
Quoted 5 lines
Quoted 2 lines
struct ibnd_config *cfg);What is wrong with current
ibdn_fabric_t*ibnd_discover_fabric(...)? Why do we need an extra parameter?
Well we are breaking the interface again so I figure we might as well clean some things up. Returning an int allows us to have a reason for the failure returned to the caller rather than just "NULL". We have cleaned up most of the internals of the library to allow for this.
Quoted 9 lines
Quoted 9 lines
I don't mind the
ibnd_config_tstruct but I don't think it should be visible to the user. Make it opaque and use "set" functions. Something like.
ibnd_fabric_t*fabric;ibnd_config_tcfg;ib_portid_t* from;
Quoted 8 lines
Quoted 4 lines
ibnd_set_hops(&cfg, hops); <== default -1ibnd_set_port_num(&cfg, port_num); <== default 1ibnd_set_max_smps(&cfg, max_smps); <== default 2ibnd_set_from_node(&cfg, from); <== default NULLI would prefer to not complicate API with
ibnd_set_this()helpers. It would be necessary to add new ones in the future which will lead to API changes.
See below.
Quoted 11 lines
Quoted 8 lines
if (
ibnd_discover_fabric(&fabric, "foo", &cfg)) { <== anything not in cfg is
defaulted here
fprintf(stderr, "Wow it failed\n");
}This allows us to change
ibnd_configstructure any time we want without affecting the API. I don't think the "pad" you used is a good idea.Without padding we will break ABI each time when new field is added to the config structure.
No it does not iff you use the ibnd_set_this() helpers and make the config private.
Quoted 10 lines
Quoted 10 lines
Also since we are breaking the API we might as well return the fabric as a parameter and have an error code. But I could go either way on this one.
Ira
[*]
query_smp.cprobably should have it's own timeout here but we can discuss later.
Quoted 6 lines
Quoted 3 lines
[#] What sucks about this is that libibmad already has the functionality to open the umad port and configure it (50 line function). Now we will be duplicating this functionality.
I think you can use
mad_rpc_open_port(ca_name, port_number, ...)just fine (and so the rest of libibmad stuff) - it will open separate fd.
Yes for the libibmad functionality we can do that. I was speaking of the use of the umad layer. To use that layer we have to duplicate the functionality of mad_rpc_open_port in every tool which requires umad layer access, correct? Right now we are mixing the 2 layers (mad and umad) in saquery (get_bind_handle) as well as libibnetdisc.
I think we need to be careful we don't do this again!
Ira
Quoted 7 lines
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://*vger.kernel.org/majordomo-info.html
Signature · 9 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 10 lines · Ira Weiny
Quoted 6 lines
Quoted 3 lines
int ibnd_discover_fabric(ibnd_fabric_t **fabric,
cosnt char *ca_name, <== could we even default this?I would think about
ca_nameandport_number. And this is of course may have default (NULL, 0).Ok,
ca_nameandca_portwill be explicit.Quoted 1 line
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
struct ibnd_config *cfg);What is wrong with current
ibdn_fabric_t*ibnd_discover_fabric(...)? Why do we need an extra parameter?Well we are breaking the interface again so I figure we might as well clean some things up. Returning an int allows us to have a reason for the failure returned to the caller rather than just "NULL". We have cleaned up most of the internals of the library to allow for this.
But we want to keep API simple, no?
Quoted 27 lines
Quoted 10 lines
Quoted 10 lines
I don't mind the
ibnd_config_tstruct but I don't think it should be visible to the user. Make it opaque and use "set" functions. Something like.
ibnd_fabric_t*fabric;ibnd_config_tcfg;ib_portid_t* from;Quoted 8 lines
Quoted 4 lines
ibnd_set_hops(&cfg, hops); <== default -1ibnd_set_port_num(&cfg, port_num); <== default 1ibnd_set_max_smps(&cfg, max_smps); <== default 2ibnd_set_from_node(&cfg, from); <== default NULLI would prefer to not complicate API with
ibnd_set_this()helpers. It would be necessary to add new ones in the future which will lead to API changes.See below.
Quoted 6 lines
Quoted 6 lines
if (
ibnd_discover_fabric(&fabric, "foo", &cfg)) { <== anything not in cfg is
defaulted here
fprintf(stderr, "Wow it failed\n");
}
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
This allows us to change
ibnd_configstructure any time we want without affecting the API. I don't think the "pad" you used is a good idea.Without padding we will break ABI each time when new field is added to the config structure.
No it does not iff you use the
ibnd_set_this()helpers and make the config private.
In you example 'ibnd_config_t cfg' is on the stack... :)
I would really suggest to keep API simple and useful - to fill up a structure described in header files is much simpler than pass over various helpers calls.
Sasha
Quoted 25 lines
Quoted 11 lines
Quoted 11 lines
Also since we are breaking the API we might as well return the fabric as a parameter and have an error code. But I could go either way on this one.
Ira
[*]
query_smp.cprobably should have it's own timeout here but we can discuss later.Quoted 6 lines
Quoted 3 lines
[#] What sucks about this is that libibmad already has the functionality to open the umad port and configure it (50 line function). Now we will be duplicating this functionality.
I think you can use
mad_rpc_open_port(ca_name, port_number, ...)just fine (and so the rest of libibmad stuff) - it will open separate fd.Yes for the libibmad functionality we can do that. I was speaking of the use of the umad layer. To use that layer we have to duplicate the functionality of
mad_rpc_open_portin every tool which requires umad layer access, correct? Right now we are mixing the 2 layers (mad and umad) in saquery (get_bind_handle) as well as libibnetdisc.I think we need to be careful we don't do this again!
Ira
Quoted 1 line
Quoted 15 lines
Quoted 6 lines
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://*vger.kernel.org/majordomo-info.htmlSignature · 5 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected]
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 11 lines · On Tue, 11 May 2010 09:42:34 -0700 Sasha Khapyorsky…
Quoted 10 lines · Ira Weiny
Quoted 6 lines
Quoted 3 lines
int ibnd_discover_fabric(ibnd_fabric_t **fabric,
cosnt char *ca_name, <== could we even default this?I would think about
ca_nameandport_number. And this is of course may have default (NULL, 0).Ok,
ca_nameandca_portwill be explicit.Quoted 1 line
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
struct ibnd_config *cfg);What is wrong with current
ibdn_fabric_t*ibnd_discover_fabric(...)? Why do we need an extra parameter?Well we are breaking the interface again so I figure we might as well clean some things up. Returning an int allows us to have a reason for the failure returned to the caller rather than just "NULL". We have cleaned up most of the internals of the library to allow for this.
But we want to keep API simple, no?
Ok, patch to follow.
Quoted 31 lines
Quoted 31 lines
Quoted 11 lines
Quoted 11 lines
I don't mind the
ibnd_config_tstruct but I don't think it should be visible to the user. Make it opaque and use "set" functions. Something like.
ibnd_fabric_t*fabric;ibnd_config_tcfg;ib_portid_t* from;Quoted 8 lines
Quoted 4 lines
ibnd_set_hops(&cfg, hops); <== default -1ibnd_set_port_num(&cfg, port_num); <== default 1ibnd_set_max_smps(&cfg, max_smps); <== default 2ibnd_set_from_node(&cfg, from); <== default NULLI would prefer to not complicate API with
ibnd_set_this()helpers. It would be necessary to add new ones in the future which will lead to API changes.See below.
Quoted 9 lines
Quoted 8 lines
if (
ibnd_discover_fabric(&fabric, "foo", &cfg)) { <== anything not in cfg is
defaulted here
fprintf(stderr, "Wow it failed\n");
}This allows us to change
ibnd_configstructure any time we want without affecting the API. I don't think the "pad" you used is a good idea.
Quoted 6 lines
Quoted 4 lines
Quoted 2 lines
Without padding we will break ABI each time when new field is added to the config structure.
No it does not iff you use the
ibnd_set_this()helpers and make the config private.In you example '
ibnd_config_tcfg' is on the stack... :)
yes, bad example.
Quoted 4 lines
I would really suggest to keep API simple and useful - to fill up a structure described in header files is much simpler than pass over various helpers calls.
I disagree but since you are looking to branch I think this bug needs to be fixed.
A patch is following this email,
Ira
Quoted 48 lines
Sasha
Quoted 25 lines
Quoted 11 lines
Quoted 11 lines
Also since we are breaking the API we might as well return the fabric as a parameter and have an error code. But I could go either way on this one.
Ira
[*]
query_smp.cprobably should have it's own timeout here but we can discuss later.Quoted 6 lines
Quoted 3 lines
[#] What sucks about this is that libibmad already has the functionality to open the umad port and configure it (50 line function). Now we will be duplicating this functionality.
I think you can use
mad_rpc_open_port(ca_name, port_number, ...)just fine (and so the rest of libibmad stuff) - it will open separate fd.Yes for the libibmad functionality we can do that. I was speaking of the use of the umad layer. To use that layer we have to duplicate the functionality of
mad_rpc_open_portin every tool which requires umad layer access, correct? Right now we are mixing the 2 layers (mad and umad) in saquery (get_bind_handle) as well as libibnetdisc.I think we need to be careful we don't do this again!
Ira
Quoted 1 line
Quoted 15 lines
Quoted 6 lines
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://**vger.kernel.org/majordomo-info.htmlSignature · 5 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected]--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://*vger.kernel.org/majordomo-info.html
Signature · 9 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 42 lines · Sasha Khapyorsky
Quoted 42 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +40
-0+static int recv_port_info (smp_engine_t *engine,ibnd_smp_t * smp, +uint8_t *mad,void *cb_data) +{ +ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric; +ibnd_node_t *node = (ibnd_node_t *)cb_data; +ibnd_port_t *port; +uint8_t *port_info = mad +IB_SMP_DATA_OFFS ; +uint8_t port_num, local_port; + + port_num =mad_get_field (mad,0 ,IB_MAD_ATTRMOD_F ); + local_port =mad_get_field (port_info,0 ,IB_PORT_LOCAL_PORT_F ); + +/* this may have been created before */ + port = node->ports[port_num]; +if (!port) { + port = node->ports[port_num] =calloc (1 ,sizeof (*port)); +if (!port) { +IBND_ERROR ("Failed to allocate port\n" ); +return -1 ; + } + } + +memcpy (port->info, port_info,sizeof (port->info)); + port->node = node; + port->portnum = port_num; + port->ext_portnum =0 ; + port->base_lid = (uint16_t )mad_get_field (port->info,0 ,IB_PORT_LID_F ); + port->lmc = (uint8_t )mad_get_field (port->info,0 ,IB_PORT_LMC_F ); + +if (port_num ==0 ) { + node->smalid = port->base_lid; + node->smalmc = port->lmc; + }else if (node->type ==IB_NODE_SWITCH ) { + port->base_lid = node->smalid; + port->lmc = node->smalmc; + } + +add_to_portguid_hash (port, fabric->portstbl); + +debug_port (&smp->path, port);
Quoted 15 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c static int extend_dpath(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric, · line 211
Quoted 11 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +5
-6-mad_dump_node_type (type,64 , &node->type,sizeof (int )); -printf ("%s -> %s %s {%016" PRIx64"} portnum %d base lid %d-%d\"%s\"\n" , -portid2str (path), prompt, type, node->guid, - node->type ==IB_NODE_SWITCH ?0 : port->portnum, - port->base_lid, - port->base_lid + (1 << port->lmc) -1 , node->nodedesc); +if (port_num && + (mad_get_field (port->info,0 ,IB_PORT_PHYS_STATE_F ) + ==IB_PORT_PHYS_STATE_LINKUP ) + && + (node->type ==IB_NODE_SWITCH || node == fabric->from_node)) {What will happen when ibnetdiscover runs from host connected by two ports to different subnets? Wouldn't it run over both fabrics (following PortInfo querying loop in
recv_node_info()below)?
I tested with two connected ports. This doesn't work - it tries to cross another fabric from another port of local node, but failed to send (CA doesn't route MADs). So this case should be fixed as:
if (port_num && port_state == IB_PORT_PHYS_STATE_LINKUP && ((node->type == IB_NODE_SWITCH && port_num != local_port) || (node == fabric->from_node && port_num == local_port)))
Sasha
Quoted 9 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c static int extend_dpath(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric, · line 219
Quoted 9 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +8
-0+ +ib_portid_t path = smp->path; +if (extend_dpath (engine, &path, port_num) !=-1 ) +query_node_info (engine, &path, node); + } + +return 0 ; +}
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 libibnetdisc: don't try to cross discovery over CA
When discovery is running from CA node it shouldn't try to cross over all ports, but only via local one (send over non-local ports will fail since CA doesn't route MADs).
--- infiniband-diags/libibnetdisc/src/ibnetdisc.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
infiniband-diags/libibnetdisc/src/ibnetdisc.c +1 -1
@@ -200,7 +200,7 @@ static int recv_port_info(smp_engine_t * engine, ibnd_smp_t * smp,if (port_num &&mad_get_field (port->info,0 ,IB_PORT_PHYS_STATE_F ) ==IB_PORT_PHYS_STATE_LINKUP && ((node->type ==IB_NODE_SWITCH && port_num != local_port) || - node == fabric->from_node)) { + (node == fabric->from_node && port_num == local_port))) {ib_portid_t path = smp->path;if (extend_dpath (engine, &path, port_num) >0 )query_node_info (engine, &path, node);
Signature · 6 lines
1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 59 lines · On Tue, 13 Apr 2010 13:46:58 +0300 Sasha Khapyorsky…
Quoted 5 lines · Ira Weiny
From: Ira Weiny <[email protected]>
Date: Fri, 22 Jan 2010 17:33:30 -0800
Subject: [PATCH] libibnetdisc: Convert to a multi-smp algorithmQuoted 7 lines
v3: change
DEFAULT_MAX_SMP_ON_WIREto 2Allow for multiple SMP's to be on the wire at a single time. This algorithm splits the processing of SMP's to a small smp engine which may be useful to split out in the future.
Signed-off-by Ira Weiny <[email protected]>Applied. Thanks.
However see some comments and questions below.
Quoted 41 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +40
-0+static int recv_port_info (smp_engine_t *engine,ibnd_smp_t * smp, +uint8_t *mad,void *cb_data) +{ +ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric; +ibnd_node_t *node = (ibnd_node_t *)cb_data; +ibnd_port_t *port; +uint8_t *port_info = mad +IB_SMP_DATA_OFFS ; +uint8_t port_num, local_port; + + port_num =mad_get_field (mad,0 ,IB_MAD_ATTRMOD_F ); + local_port =mad_get_field (port_info,0 ,IB_PORT_LOCAL_PORT_F ); + +/* this may have been created before */ + port = node->ports[port_num]; +if (!port) { + port = node->ports[port_num] =calloc (1 ,sizeof (*port)); +if (!port) { +IBND_ERROR ("Failed to allocate port\n" ); +return -1 ; + } + } + +memcpy (port->info, port_info,sizeof (port->info)); + port->node = node; + port->portnum = port_num; + port->ext_portnum =0 ; + port->base_lid = (uint16_t )mad_get_field (port->info,0 ,IB_PORT_LID_F ); + port->lmc = (uint8_t )mad_get_field (port->info,0 ,IB_PORT_LMC_F ); + +if (port_num ==0 ) { + node->smalid = port->base_lid; + node->smalmc = port->lmc; + }else if (node->type ==IB_NODE_SWITCH ) { + port->base_lid = node->smalid; + port->lmc = node->smalmc; + } + +add_to_portguid_hash (port, fabric->portstbl); + +debug_port (&smp->path, port);
Quoted 15 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c static int extend_dpath(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric, · line 211
Quoted 11 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +5
-6-mad_dump_node_type (type,64 , &node->type,sizeof (int )); -printf ("%s -> %s %s {%016" PRIx64"} portnum %d base lid %d-%d\"%s\"\n" , -portid2str (path), prompt, type, node->guid, - node->type ==IB_NODE_SWITCH ?0 : port->portnum, - port->base_lid, - port->base_lid + (1 << port->lmc) -1 , node->nodedesc); +if (port_num && + (mad_get_field (port->info,0 ,IB_PORT_PHYS_STATE_F ) + ==IB_PORT_PHYS_STATE_LINKUP ) + && + (node->type ==IB_NODE_SWITCH || node == fabric->from_node)) {What will happen when ibnetdiscover runs from host connected by two ports to different subnets? Wouldn't it run over both fabrics (following PortInfo querying loop in
recv_node_info()below)?
Looking at the code I think you are right... In practice, this does not happen...
I am still trying to figure out exactly why.
Quoted 95 lines
Quoted 9 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +8
-0+ +ib_portid_t path = smp->path; +if (extend_dpath (engine, &path, port_num) !=-1 ) +query_node_info (engine, &path, node); + } + +return 0 ; +}[snip]
Quoted 57 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +50
-4+static int recv_node_info (smp_engine_t *engine,ibnd_smp_t * smp, +uint8_t *mad,void *cb_data) +{ +ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric; +int i =0 ; +uint8_t *node_info = mad +IB_SMP_DATA_OFFS ; +ibnd_node_t * rem_node = (ibnd_node_t *)cb_data;ibnd_node_t *node; +int node_is_new =0 ; +uint64_t node_guid =mad_get_field64 (node_info,0 ,IB_NODE_GUID_F ); +uint64_t port_guid =mad_get_field64 (node_info,0 ,IB_NODE_PORT_GUID_F ); +int port_num =mad_get_field (node_info,0 ,IB_NODE_LOCAL_PORT_F ); +ibnd_port_t *port =NULL ; -for (node = fabric->nodestbl[hash]; node; node = node->htnext) -if (node->guid == new->guid) -return node; + node =ibnd_find_node_guid (fabric, node_guid); +if (!node) { + node =create_node (engine, &smp->path, node_info); +if (!node) +return -1 ; + node_is_new =1 ; + } +IBND_DEBUG ("Found %s node GUID %lx (%s)\n" , + (node_is_new) ?"new" :"old" , node->guid, +portid2str (&smp->path)); -return NULL ; + port = node->ports[port_num]; +if (!port) { +/* If we have not see this port before create a shell for it */ + port = node->ports[port_num] =calloc (1 ,sizeof (*port)); + port->node = node; + port->portnum = port_num; + } + port->guid = port_guid; + +if (rem_node ==NULL )/* this is the start node */ + fabric->from_node = node; +else { +/* link ports... */ +int rem_port_num =get_last_port (&smp->path); + +if (!rem_node->ports[rem_port_num]) { +IBND_ERROR ("Internal Error; " +"Node(%p) %lx Port %d no port created!?!?!?\n\n" , + rem_node, rem_node->guid, rem_port_num); +return (-1 ); + } + +link_ports (node, port, rem_node, rem_node->ports[rem_port_num]); + } + +if (!node_is_new) +return 0 ; +infiniband-diags/libibnetdisc/src/ibnetdisc.c static int extend_dpath(struct ibmad_port *ibmad_port, ibnd_fabric_t * fabric, · line 346
Quoted 10 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +10
-0+query_node_desc (engine, &smp->path, node); + +if (node->type ==IB_NODE_SWITCH ) +query_switch_info (engine, &smp->path, node); + +/* process all the ports on this node */ +for (i = (node->type ==IB_NODE_SWITCH ) ?0 :1 ; + i <= node->numports; i++) { +query_port_info (engine, &smp->path, node, i); + }This one.
Quoted 3 lines
infiniband-diags/libibnetdisc/src/ibnetdisc.c +3
-0+ +return 0 ; +}[snip]
Quoted 7 lines
infiniband-diags/libibnetdisc/src/internal.h +0
-0@@ -39,6 +39,7 @@#define _INTERNAL_H_
Quoted 5 lines
infiniband-diags/libibnetdisc/src/internal.h line 42
Quoted 2 lines
infiniband-diags/libibnetdisc/src/internal.h +1
-0#include <infiniband/ibnetdisc.h> +#include <complib/cl_qmap.h> I'm not really happy with complib dependency introduction - we had an issues with it in the past.
I don't recall. infiniband-diags is already dependant on opensm-libs. We have, at least, the node name map dependency from complib already, so I did not think it was that big of a deal.
Quoted 4 lines
Also I think that we can implement simpler transaction tracker (likely even more efficient) by storing sent MADs in cyclic array and encoding its index as part of TRID.
I just thought code reuse was the way to go here.
Quoted 206 lines
Quoted 178 lines
infiniband-diags/libibnetdisc/src/internal.h +33
-5#define IBND_DEBUG (fmt, ...) \ if (ibdebug) { \@@ -52,16 +53,44 @@#define MAXHOPS 63 -typedef struct ibnd_node_scan { -ibnd_node_t *node; -struct ibnd_node_scan *dnext;/* nodesdist next */ -}ibnd_node_scan_t ; +#define DEFAULT_MAX_SMP_ON_WIRE 2typedef struct ibnd_scan { -ibnd_node_scan_t *nodesdist[MAXHOPS +1 ];ib_portid_t selfportid; +ibnd_fabric_t *fabric; }ibnd_scan_t ; + +typedef struct ibnd_smp ibnd_smp_t ; +typedef struct smp_engine smp_engine_t ; +typedef int (*smp_comp_cb_t )(smp_engine_t *engine,ibnd_smp_t * smp, +uint8_t *mad_resp,void *cb_data); +struct ibnd_smp { +cl_map_item_t on_wire; +struct ibnd_smp * qnext; +smp_comp_cb_t cb; +void * cb_data; +ib_portid_t path; +ib_rpc_t rpc; +}; +struct smp_engine { +struct ibmad_port *ibmad_port; +ibnd_smp_t *smp_queue_head; +ibnd_smp_t *smp_queue_tail; +void * user_data; +cl_qmap_t smps_on_wire; +int num_smps_outstanding; +int max_smps_on_wire; +}; + +void smp_engine_init (smp_engine_t * engine,struct ibmad_port *ibmad_port, +void * user_data,int max_smps_on_wire); +int issue_smp (smp_engine_t *engine,ib_portid_t * portid, +unsigned attrid,unsigned mod, +smp_comp_cb_t cb,void * cb_data); +int process_mads (smp_engine_t *engine); +void smp_engine_destroy (smp_engine_t *engine); +void add_to_nodeguid_hash (ibnd_node_t * node,ibnd_node_t * hash[]);void add_to_portguid_hash (ibnd_port_t * port,ibnd_port_t * hash[]);infiniband-diags/libibnetdisc/src/query_smp.c new file +118
-0@@ -0,0 +1,249 @@ +/* +* Copyright (c) 2010 Lawrence Livermore National Laboratory +* +* 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 <errno.h> +#include <infiniband/ibnetdisc.h> +#include <infiniband/umad.h> +#include "internal.h" + +void +queue_smp (smp_engine_t *engine,ibnd_smp_t *smp) +{ + smp->qnext =NULL ; +if (!engine->smp_queue_head) { + engine->smp_queue_head = smp; + engine->smp_queue_tail = smp; + }else { + engine->smp_queue_tail->qnext = smp; + engine->smp_queue_tail = smp; + } +} + +ibnd_smp_t * +get_smp (smp_engine_t *engine) +{ +ibnd_smp_t *head = engine->smp_queue_head; +ibnd_smp_t *tail = engine->smp_queue_tail; +ibnd_smp_t *rc = head; +if (head) { +if (tail == head) + engine->smp_queue_tail =NULL ; + engine->smp_queue_head = head->qnext; + } +return rc; +} + +int send_smp (ibnd_smp_t * smp,struct ibmad_port *srcport) +{ +int rc =0 ; +uint8_t umad[1024 ]; +ib_rpc_t *rpc = &smp->rpc; + +memset (umad,0 ,umad_size () +IB_MAD_SIZE ); + +if ((rc =mad_build_pkt (umad, &smp->rpc, &smp->path,NULL ,NULL )) + <0 ) { +IBND_ERROR ("mad_build_pkt failed; %d" , rc); +return rc; + } + +if ((rc =umad_send (mad_rpc_portid (srcport), +mad_rpc_class_agent (srcport, rpc->mgtclass), + umad,IB_MAD_SIZE , +mad_get_timeout (srcport, rpc->timeout), +mad_get_retries (srcport))) <0 ) { +IBND_ERROR ("send failed; %d" , rc); +return rc; + } + +return 0 ; +} + +static int process_smp_queue (smp_engine_t *engine) +{ +int rc =0 ; +ibnd_smp_t *smp; +while (cl_qmap_count (&engine->smps_on_wire) < engine->max_smps_on_wire) { + smp =get_smp (engine); +if (!smp) +return 0 ; + +cl_qmap_insert (&engine->smps_on_wire, (uint32_t )smp->rpc.trid, + (cl_map_item_t *)smp); +if ((rc =send_smp (smp, engine->ibmad_port)) !=0 ) +return rc; + } +return 0 ; +} + +int issue_smp (smp_engine_t *engine,ib_portid_t * portid, +unsigned attrid,unsigned mod, +smp_comp_cb_t cb,void * cb_data) +{ +ibnd_smp_t *smp =calloc (1 ,sizeof *smp); +if (!smp) { +IBND_ERROR ("OOM" ); +return -ENOMEM ; + } +infiniband-diags/libibnetdisc/src/query_smp.c line 128
Quoted 10 lines
infiniband-diags/libibnetdisc/src/query_smp.c new file +10
-0+ smp->cb = cb; + smp->cb_data = cb_data; + smp->path = *portid; + smp->rpc.method =IB_MAD_METHOD_GET ; + smp->rpc.attr.id = attrid; + smp->rpc.attr.mod = mod; + smp->rpc.timeout =mad_get_timeout (engine->ibmad_port,0 ); + smp->rpc.datasz =IB_SMP_DATA_SIZE ; + smp->rpc.dataoffs =IB_SMP_DATA_OFFS ; + smp->rpc.trid =mad_trid ();BTW, by reviewing
mad_trid()code in libibmad:
uint64_tmad_trid(void){ static uint64_t base; static uint64_t trid; uint64_t next; if (!base) { srandom((int)time(0) * getpid()); base = random(); trid = random(); } next = ++trid | (base << 32); return next; }
Quoted 1 line
For me it doesn't look as thread safe function.
It's not! The whole of libibmad is not thread safe! (Ok perhaps just the parts I was using before.) But we are not using threads here, right?
Quoted 112 lines
Quoted 112 lines
infiniband-diags/libibnetdisc/src/query_smp.c new file +111
-0+ +if ((portid->lid <=0 ) || + (portid->drpath.drslid ==0xffff ) || + (portid->drpath.drdlid ==0xffff )) + smp->rpc.mgtclass =IB_SMI_DIRECT_CLASS ;/* direct SMI */ +else + smp->rpc.mgtclass =IB_SMI_CLASS ;/* Lid routed SMI */ + + portid->sl =0 ; + portid->qp =0 ; + + engine->num_smps_outstanding++; +queue_smp (engine, smp); +return (process_smp_queue (engine)); +} + +int process_one_recv (smp_engine_t *engine) +{ +int rc =0 ; +int status =0 ; +ibnd_smp_t *smp; +uint8_t *mad; +uint32_t trid; +uint8_t umad[umad_size () +IB_MAD_SIZE ]; +int length =umad_size () +IB_MAD_SIZE ; + +memset (umad,0 ,sizeof (umad)); + +/* wait for the next message */ +if ((rc =umad_recv (mad_rpc_portid (engine->ibmad_port), umad, &length, +0 )) <0 ) { +if (rc == -EWOULDBLOCK ) +return 0 ; +IBND_ERROR ("umad_recv failed: %d\n" , rc); +return -1 ; + } + + rc =process_smp_queue (engine); + + mad =umad_get_mad (umad); + trid = (uint32_t )mad_get_field64 (mad,0 ,IB_MAD_TRID_F ); + + smp = (ibnd_smp_t *)cl_qmap_remove (&engine->smps_on_wire, trid); +if ((cl_map_item_t *)smp ==cl_qmap_end (&engine->smps_on_wire)) { +IBND_ERROR ("Failed to find matching smp for trid (%x)\n" , + trid); +return -1 ; + } + +if (rc) + goto error; + +if ((status =umad_status (umad))) { +IBND_ERROR ("umad (%s Attr 0x%x:%u) bad status %d; %s\n" , +portid2str (&smp->path), + smp->rpc.attr.id, smp->rpc.attr.mod, + status,strerror (status)); + }else if ((status =mad_get_field (mad,0 ,IB_DRSMP_STATUS_F ))) { +IBND_ERROR ("mad (%s Attr 0x%x:%u) bad status 0x%x\n" , +portid2str (&smp->path), + smp->rpc.attr.id, smp->rpc.attr.mod, + status); + }else + rc = smp->cb (engine, smp, mad, smp->cb_data); + +error: +free (smp); + engine->num_smps_outstanding--; +return (rc); +} + +void smp_engine_init (smp_engine_t * engine,struct ibmad_port *ibmad_port, +void * user_data,int max_smps_on_wire) +{ +memset (engine,'\0' ,sizeof (*engine)); + engine->ibmad_port = ibmad_port; + engine->user_data = user_data; +cl_qmap_init (&engine->smps_on_wire); + engine->num_smps_outstanding =0 ; + engine->max_smps_on_wire = max_smps_on_wire; +} + +void smp_engine_destroy (smp_engine_t *engine) +{ +cl_map_item_t *item; +ibnd_smp_t *smp; + +/* remove queued smps */ + smp =get_smp (engine); +if (smp) +IBND_ERROR ("outstanding SMP's\n" ); +for (/* */ ; smp; smp =get_smp (engine)) { +free (smp); + } + +/* remove smps from the wire queue */ + item =cl_qmap_head (&engine->smps_on_wire); +if (item !=cl_qmap_end (&engine->smps_on_wire)) +IBND_ERROR ("outstanding SMP's on wire\n" ); +for (/* */ ; item !=cl_qmap_end (&engine->smps_on_wire); + item =cl_qmap_head (&engine->smps_on_wire)) { +cl_qmap_remove_item (&engine->smps_on_wire, item); +free (item); + } + + engine->num_smps_outstanding =0 ; +} + +int process_mads (smp_engine_t *engine) +{ +int rc =0 ;
Quoted 8 lines
infiniband-diags/libibnetdisc/src/query_smp.c line 242
Quoted 3 lines
infiniband-diags/libibnetdisc/src/query_smp.c new file +3
-0+while (engine->num_smps_outstanding >0 ) { +if ((rc =process_smp_queue (engine)) !=0 ) +return rc;Is it really needed to run
process_smp_queue()here (assuming that it is already executed inissue_smp()andprocess_one_recv())? Or this is just for handlingprocess_one_recv()error case? If so wouldn't it better to run it there?
Yes I was looking at that yesterday. Since we are not threaded I just wanted to make sure that there were some messages on the wire before we went into the processing loop. I will send a patch after I have tested everything out.
Ira
Quoted 13 lines
Sasha
Quoted 10 lines
infiniband-diags/libibnetdisc/src/query_smp.c new file +7
-0+while (!cl_is_qmap_empty (&engine->smps_on_wire)) +if ((rc =process_one_recv (engine)) !=0 ) +return rc; + } +return 0 ; +} +Signature · 1 line
1.5.4.5
Signature · 9 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 60 lines · Sasha Khapyorsky
Quoted 60 lines
(quoted diff) +52
-4+static int recv_node_info(smp_engine_t *engine, ibnd_smp_t * smp, + uint8_t *mad, void *cb_data) +{ + ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric; + int i = 0; + uint8_t *node_info = mad + IB_SMP_DATA_OFFS; + ibnd_node_t * rem_node = (ibnd_node_t *)cb_data; ibnd_node_t *node; + int node_is_new = 0; + uint64_t node_guid = mad_get_field64(node_info, 0, IB_NODE_GUID_F); + uint64_t port_guid = mad_get_field64(node_info, 0, IB_NODE_PORT_GUID_F); + int port_num = mad_get_field(node_info, 0, IB_NODE_LOCAL_PORT_F); + ibnd_port_t *port = NULL; - for (node = fabric->nodestbl[hash]; node; node = node->htnext) - if (node->guid == new->guid) - return node; + node = ibnd_find_node_guid(fabric, node_guid); + if (!node) { + node = create_node(engine, &smp->path, node_info); + if (!node) + return -1; + node_is_new = 1; + } + IBND_DEBUG("Found %s node GUID %lx (%s)\n", + (node_is_new) ? "new": "old", node->guid, + portid2str(&smp->path)); - return NULL; + port = node->ports[port_num]; + if (!port) { + /* If we have not see this port before create a shell for it */ + port = node->ports[port_num] = calloc(1, sizeof(*port)); + port->node = node; + port->portnum = port_num; + } + port->guid = port_guid; + + if (rem_node == NULL) /* this is the start node */ + fabric->from_node = node; + else { + /* link ports... */ + int rem_port_num = get_last_port(&smp->path); + + if (!rem_node->ports[rem_port_num]) { + IBND_ERROR("Internal Error; " + "Node(%p) %lx Port %d no port created!?!?!?\n\n", + rem_node, rem_node->guid, rem_port_num); + return (-1); + } + + link_ports(node, port, rem_node, rem_node->ports[rem_port_num]); + } + + if (!node_is_new) + return 0; + + query_node_desc(engine, &smp->path, node); +
Quoted 8 lines
Review
Quoted 8 lines
(quoted diff) +8
-0+ if (node->type == IB_NODE_SWITCH) + query_switch_info(engine, &smp->path, node); + + /* process all the ports on this node */ + for (i = (node->type == IB_NODE_SWITCH) ? 0 : 1; + i <= node->numports; i++) { + query_port_info(engine, &smp->path, node, i); + }
Actually it seems possible to save some MADs by not querying CA/Router ports which is not connected to our fabric. Something like this:
infiniband-diags/libibnetdisc/src/ibnetdisc.c +9 -12
@@ -339,19 +339,16 @@ static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,link_ports (node, port, rem_node, rem_node->ports[rem_port_num]); } -if (!node_is_new) -return 0 ; - -query_node_desc (engine, &smp->path, node); - -if (node->type ==IB_NODE_SWITCH ) -query_switch_info (engine, &smp->path, node); +if (node_is_new) { +query_node_desc (engine, &smp->path, node); -/* process all the ports on this node */ -for (i = (node->type ==IB_NODE_SWITCH ) ?0 :1 ; - i <= node->numports; i++) { -query_port_info (engine, &smp->path, node, i); - } +if (node->type ==IB_NODE_SWITCH ) { +query_switch_info (engine, &smp->path, node); +for (i =0 ; i <= node->numports; i++) +query_port_info (engine, &smp->path, node, i); + } + }else if (node->type !=IB_NODE_SWITCH ) +query_port_info (engine, &smp->path, node, port_num);return 0 ; }
What do you think?
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 108 lines · On Tue, 13 Apr 2010 20:18:24 +0300 Sasha Khapyorsky…
Quoted 60 lines · Sasha Khapyorsky
Quoted 60 lines
(quoted diff) +52
-4+static int recv_node_info(smp_engine_t *engine, ibnd_smp_t * smp, + uint8_t *mad, void *cb_data) +{ + ibnd_fabric_t *fabric = ((ibnd_scan_t *)engine->user_data)->fabric; + int i = 0; + uint8_t *node_info = mad + IB_SMP_DATA_OFFS; + ibnd_node_t * rem_node = (ibnd_node_t *)cb_data; ibnd_node_t *node; + int node_is_new = 0; + uint64_t node_guid = mad_get_field64(node_info, 0, IB_NODE_GUID_F); + uint64_t port_guid = mad_get_field64(node_info, 0, IB_NODE_PORT_GUID_F); + int port_num = mad_get_field(node_info, 0, IB_NODE_LOCAL_PORT_F); + ibnd_port_t *port = NULL; - for (node = fabric->nodestbl[hash]; node; node = node->htnext) - if (node->guid == new->guid) - return node; + node = ibnd_find_node_guid(fabric, node_guid); + if (!node) { + node = create_node(engine, &smp->path, node_info); + if (!node) + return -1; + node_is_new = 1; + } + IBND_DEBUG("Found %s node GUID %lx (%s)\n", + (node_is_new) ? "new": "old", node->guid, + portid2str(&smp->path)); - return NULL; + port = node->ports[port_num]; + if (!port) { + /* If we have not see this port before create a shell for it */ + port = node->ports[port_num] = calloc(1, sizeof(*port)); + port->node = node; + port->portnum = port_num; + } + port->guid = port_guid; + + if (rem_node == NULL) /* this is the start node */ + fabric->from_node = node; + else { + /* link ports... */ + int rem_port_num = get_last_port(&smp->path); + + if (!rem_node->ports[rem_port_num]) { + IBND_ERROR("Internal Error; " + "Node(%p) %lx Port %d no port created!?!?!?\n\n", + rem_node, rem_node->guid, rem_port_num); + return (-1); + } + + link_ports(node, port, rem_node, rem_node->ports[rem_port_num]); + } + + if (!node_is_new) + return 0; + + query_node_desc(engine, &smp->path, node); +Quoted 8 lines
Review
Quoted 8 lines
(quoted diff) +8
-0+ if (node->type == IB_NODE_SWITCH) + query_switch_info(engine, &smp->path, node); + + /* process all the ports on this node */ + for (i = (node->type == IB_NODE_SWITCH) ? 0 : 1; + i <= node->numports; i++) { + query_port_info(engine, &smp->path, node, i); + }Actually it seems possible to save some MADs by not querying CA/Router ports which is not connected to our fabric. Something like this:
infiniband-diags/libibnetdisc/src/ibnetdisc.c +9
-12@@ -339,19 +339,16 @@ static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,link_ports (node, port, rem_node, rem_node->ports[rem_port_num]); } -if (!node_is_new) -return 0 ; - -query_node_desc (engine, &smp->path, node); - -if (node->type ==IB_NODE_SWITCH ) -query_switch_info (engine, &smp->path, node); +if (node_is_new) { +query_node_desc (engine, &smp->path, node); -/* process all the ports on this node */ -for (i = (node->type ==IB_NODE_SWITCH ) ?0 :1 ; - i <= node->numports; i++) { -query_port_info (engine, &smp->path, node, i); - } +if (node->type ==IB_NODE_SWITCH ) { +query_switch_info (engine, &smp->path, node); +for (i =0 ; i <= node->numports; i++) +query_port_info (engine, &smp->path, node, i); + } + }else if (node->type !=IB_NODE_SWITCH ) +query_port_info (engine, &smp->path, node, port_num);return 0 ; }
Quoted 1 line
What do you think?
I like this better.
Ira
Quoted 2 lines
Sasha
Signature · 9 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/1 libibnetdisc: don't query CA ports not connected to a fabric
We can save some amount of MADs by not querying CA/Router ports which is not connected to our fabric. When discovery reaches CA or Router node it will always get PortInfo for a port which was discovered and not others.
--- infiniband-diags/libibnetdisc/src/ibnetdisc.c | 21 ++++++++++----------- 1 files changed, 10 insertions(+), 11 deletions(-)
infiniband-diags/libibnetdisc/src/ibnetdisc.c +10 -11
@@ -339,19 +339,18 @@ static int recv_node_info(smp_engine_t * engine, ibnd_smp_t * smp,link_ports (node, port, rem_node, rem_node->ports[rem_port_num]); } -if (!node_is_new) -return 0 ; - -query_node_desc (engine, &smp->path, node); +if (node_is_new) { +query_node_desc (engine, &smp->path, node); -if (node->type ==IB_NODE_SWITCH ) -query_switch_info (engine, &smp->path, node); - -/* process all the ports on this node */ -for (i = (node->type ==IB_NODE_SWITCH ) ?0 :1 ; - i <= node->numports; i++) { -query_port_info (engine, &smp->path, node, i); +if (node->type ==IB_NODE_SWITCH ) { +query_switch_info (engine, &smp->path, node); +for (i =0 ; i <= node->numports; i++) +query_port_info (engine, &smp->path, node, i); + } } + +if (node->type !=IB_NODE_SWITCH ) +query_port_info (engine, &smp->path, node, port_num);return 0 ; }
Signature · 6 lines
1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 libibnetdisc: fix outstanding SMPs countung
In reply to a message not in the archivesend_smp() failure blocks whole discovery execution (it never returns). Fix this by updating all outstanding SMPs related counters only after successful MAD sending.
--- infiniband-diags/libibnetdisc/src/query_smp.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
infiniband-diags/libibnetdisc/src/query_smp.c +4 -4
@@ -96,10 +96,12 @@ static int process_smp_queue(smp_engine_t * engine)if (!smp)return 0 ; -cl_qmap_insert (&engine->smps_on_wire, (uint32_t ) smp->rpc.trid, - (cl_map_item_t *) smp);if ((rc =send_smp (smp, engine->ibmad_port)) !=0 )return rc; + engine->num_smps_outstanding++; +cl_qmap_insert (&engine->smps_on_wire, (uint32_t ) smp->rpc.trid, + (cl_map_item_t *) smp); + engine->total_smps++; }return 0 ; }
@@ -133,8 +135,6 @@ int issue_smp(smp_engine_t * engine, ib_portid_t * portid, portid->sl =0 ; portid->qp =0 ; - engine->total_smps++; - engine->num_smps_outstanding++;queue_smp (engine, smp);return process_smp_queue (engine); }
Signature · 6 lines
1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] libibnetdisc: fix outstanding SMPs countung
This changes the logic. "num_smps_outstanding" is NOT the number on the wire, but it appears you have made it so. This is the number which will cause process_smp_queue to continue being called.
If you are going to do this I think you need to change process_mads as well as process_one_recv. We discussed process_one_recv in the error case.
What were you trying to fix?
Ira
Quoted 46 lines · On Tue, 13 Apr 2010 19:38:36 +0300 Sasha Khapyorsky…
send_smp()failure blocks whole discovery execution (it never returns). Fix this by updating all outstanding SMPs related counters only after successful MAD sending.--- infiniband-diags/libibnetdisc/src/query_smp.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)infiniband-diags/libibnetdisc/src/query_smp.c +4
-4@@ -96,10 +96,12 @@ static int process_smp_queue(smp_engine_t * engine)if (!smp)return 0 ; -cl_qmap_insert (&engine->smps_on_wire, (uint32_t ) smp->rpc.trid, - (cl_map_item_t *) smp);if ((rc =send_smp (smp, engine->ibmad_port)) !=0 )return rc; + engine->num_smps_outstanding++; +cl_qmap_insert (&engine->smps_on_wire, (uint32_t ) smp->rpc.trid, + (cl_map_item_t *) smp); + engine->total_smps++; }return 0 ; }@@ -133,8 +135,6 @@ int issue_smp(smp_engine_t * engine, ib_portid_t * portid, portid->sl =0 ; portid->qp =0 ; - engine->total_smps++; - engine->num_smps_outstanding++;queue_smp (engine, smp);return process_smp_queue (engine); }Signature · 6 lines
1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://*vger.kernel.org/majordomo-info.html
Signature · 9 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH] libibnetdisc: fix outstanding SMPs countung
Quoted 5 lines · On Tue, 13 Apr 2010 13:38:26 -0700 Ira Weiny…
This changes the logic. "
num_smps_outstanding" is NOT the number on the wire, but it appears you have made it so. This is the number which will causeprocess_smp_queueto continue being called.If you are going to do this I think you need to change
process_madsas well asprocess_one_recv. We discussedprocess_one_recvin the error case.What were you trying to fix?
Ok, I think I see. We should move cl_qmap_insert to after a successful umad_send and putting total_smps here is ok. But num_smps_outstanding should be put back I think.
Ira
Quoted 60 lines
Ira
Quoted 46 lines · On Tue, 13 Apr 2010 19:38:36 +0300 Sasha Khapyorsky…
send_smp()failure blocks whole discovery execution (it never returns). Fix this by updating all outstanding SMPs related counters only after successful MAD sending.--- infiniband-diags/libibnetdisc/src/query_smp.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)infiniband-diags/libibnetdisc/src/query_smp.c +4
-4@@ -96,10 +96,12 @@ static int process_smp_queue(smp_engine_t * engine)if (!smp)return 0 ; -cl_qmap_insert (&engine->smps_on_wire, (uint32_t ) smp->rpc.trid, - (cl_map_item_t *) smp);if ((rc =send_smp (smp, engine->ibmad_port)) !=0 )return rc; + engine->num_smps_outstanding++; +cl_qmap_insert (&engine->smps_on_wire, (uint32_t ) smp->rpc.trid, + (cl_map_item_t *) smp); + engine->total_smps++; }return 0 ; }@@ -133,8 +135,6 @@ int issue_smp(smp_engine_t * engine, ib_portid_t * portid, portid->sl =0 ; portid->qp =0 ; - engine->total_smps++; - engine->num_smps_outstanding++;queue_smp (engine, smp);return process_smp_queue (engine); }Signature · 6 lines
1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://*vger.kernel.org/majordomo-info.htmlSignature · 5 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected]
Signature · 9 lines
Ira Weiny Math Programmer/Computer Scientist Lawrence Livermore National Lab 925-423-8008 [email protected] -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Re: [PATCH] libibnetdisc: fix outstanding SMPs countung
Quoted 2 lines · Ira Weiny
Quoted 2 lines
This changes the logic. "
num_smps_outstanding" is NOT the number on the wire, but it appears you have made it so.
Actually yes, it made it so.
Quoted 3 lines
Quoted 3 lines
This is the number which will cause
process_smp_queueto continue being called.If you are going to do this I think you need to change
process_madsas well asprocess_one_recv. We discussedprocess_one_recvin the error case.
process_one_recv() failure breaks the loop anyway.
Quoted 3 lines
Quoted 1 line
What were you trying to fix?
Ok, I think I see. We should move
cl_qmap_insertto after a successfulumad_sendand puttingtotal_smpshere is ok. Butnum_smps_outstandingshould be put back I think.
But then it blocks process_mads() to loop forever after single send_smp() failure (with all empty queues and umad_recv() running without timeout).
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] libibnetdisc: fix outstanding SMPs countung
Quoted 12 lines · Sasha Khapyorsky
Quoted 2 lines · Ira Weiny
Quoted 2 lines
This changes the logic. "
num_smps_outstanding" is NOT the number on the wire, but it appears you have made it so.Actually yes, it made it so.
Quoted 3 lines
Quoted 3 lines
This is the number which will cause
process_smp_queueto continue being called.If you are going to do this I think you need to change
process_madsas well asprocess_one_recv. We discussedprocess_one_recvin the error case.
process_one_recv()failure breaks the loop anyway.
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
What were you trying to fix?
Ok, I think I see. We should move
cl_qmap_insertto after a successfulumad_sendand puttingtotal_smpshere is ok. Butnum_smps_outstandingshould be put back I think.But then it blocks
process_mads()to loop forever after singlesend_smp()failure (with all empty queues andumad_recv()running without timeout).
But moving the cl_qmap_insert below the send call fixes that. However, it does cause a memory leak because the smp is no longer in the smp_queue_head list. It needs to be put back on that list to be retried with a limit on the retries (to prevent what you are saying here.) Are you seeing a hang?
I have seen a hang when running "iblinkinfo -S <guid>". However, the problem is not with send_smp. I am seeing the mad going on the wire and returning (according to madeye) but I am not receiving it from umad_recv. I don't know why. If I run with 1 outstanding mad it works???
Ira
Quoted 2 lines
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 0EEE4F40-F1DD-46A6-B756-3C46DA06B403-i2BcT+NCU+M@public.gmane.org
Re: [PATCH] libibnetdisc: fix outstanding SMPs countung
Quoted 6 lines · Ira Weiny
Quoted 4 lines
But then it blocks
process_mads()to loop forever after singlesend_smp()failure (with all empty queues andumad_recv()running without timeout).But moving the
cl_qmap_insertbelow the send call fixes that.
It doesn't:
int process_mads(smp_engine_t * engine)
{
int rc = 0;
while (engine->num_smps_outstanding > 0) {
if ((rc = process_smp_queue(engine)) != 0)
return rc;
while (!cl_is_qmap_empty(&engine->smps_on_wire))
if ((rc = process_one_recv(engine)) != 0)
return rc;
}
return 0;
}After send_smp() failure engine->num_smps_outstanding still be > 0 and will be never decreased (tested).
Quoted 2 lines
However, it does cause a memory leak because the smp is no longer in the
smp_queue_headlist.
This is correct about leaking.
Quoted 3 lines
It needs to be put back on that list to be
retried with a limit on the retries (to prevent what you are saying here.)
We have already retries mechanism implemented in umad_send(), so likely failed MAD should be just dropped and freed:
infiniband-diags/libibnetdisc/src/query_smp.c +3 -1
@@ -96,8 +96,10 @@ static int process_smp_queue(smp_engine_t * engine)if (!smp)return 0 ; -if ((rc =send_smp (smp, engine->ibmad_port)) !=0 ) +if ((rc =send_smp (smp, engine->ibmad_port)) !=0 ) { +free (smp);return rc; + } engine->num_smps_outstanding++;cl_qmap_insert (&engine->smps_on_wire, (uint32_t ) smp->rpc.trid, (cl_map_item_t *) smp);
Quoted 1 line
Are you seeing a hang?
I'm seeing endless loop.
Quoted 1 line
I have seen a hang when running "iblinkinfo -S <guid>".
What do you mean "hang"? Endless loop?
Quoted 5 lines
However, the
problem is not withsend_smp. I am seeing the mad going on the wire and returning (according to madeye) but I am not receiving it fromumad_recv. I don't know why. If I run with 1 outstanding mad it works???
Do you see this with current master (for me 'iblinkinfo -S' works fine, but I have only two switches).
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 libibnetdisc: fix memory leak in case of send_smps() failure
Free smp object in case of send_smp() failure - it is not on the send list already and not tracked anymore.
--- infiniband-diags/libibnetdisc/src/query_smp.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
infiniband-diags/libibnetdisc/src/query_smp.c +3 -1
@@ -96,8 +96,10 @@ static int process_smp_queue(smp_engine_t * engine)if (!smp)return 0 ; -if ((rc =send_smp (smp, engine->ibmad_port)) !=0 ) +if ((rc =send_smp (smp, engine->ibmad_port)) !=0 ) { +free (smp);return rc; + } engine->num_smps_outstanding++;cl_qmap_insert (&engine->smps_on_wire, (uint32_t ) smp->rpc.trid, (cl_map_item_t *) smp);
Signature · 6 lines
1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] libibnetdisc: fix outstanding SMPs countung
In reply to Sasha KhapyorskyQuoted 2 lines · Sasha Khapyorsky
I'm seeing endless loop.
Actually proposed fix is not enough, '-o 1' still be broken. To make it properly outstanding SMPs counters should be discounted in process_one_recv() before calling process_smp_queue() and smp receive callback. The patch soon...
Sasha
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 libibnetdiscover: more outstanding MADs counting fix
Decrease outstanding MADs counter before calling process_smp_queue() and smp receive callback, so that there will be room available for sending more MADs. This fixes 'ibnetdiscover -o 1' (max outstanding SMPs on a wire = 1) bug.
--- infiniband-diags/libibnetdisc/src/query_smp.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-)
infiniband-diags/libibnetdisc/src/query_smp.c +2 -3
@@ -160,8 +160,6 @@ static int process_one_recv(smp_engine_t * engine)return -1 ; } - rc =process_smp_queue (engine); - mad =umad_get_mad (umad); trid = (uint32_t )mad_get_field64 (mad,0 ,IB_MAD_TRID_F );
@@ -171,6 +169,8 @@ static int process_one_recv(smp_engine_t * engine)return -1 ; } + engine->num_smps_outstanding--; + rc =process_smp_queue (engine);if (rc) goto error;
@@ -187,7 +187,6 @@ static int process_one_recv(smp_engine_t * engine) error:free (smp); - engine->num_smps_outstanding--;return rc; }
Signature · 6 lines
1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 libibnetdisc: remove not needed process_smp_queue() call
process_smp_queue() is called initially in issue_smp() and post called in each process_one_recv() invocation. So no need in yet another call.
--- infiniband-diags/libibnetdisc/src/query_smp.c | 5 +---- 1 files changed, 1 insertions(+), 4 deletions(-)
infiniband-diags/libibnetdisc/src/query_smp.c +1 -4
@@ -231,12 +231,9 @@ void smp_engine_destroy(smp_engine_t * engine)int process_mads (smp_engine_t * engine) {int rc =0 ; -while (engine->num_smps_outstanding >0 ) { -if ((rc =process_smp_queue (engine)) !=0 ) -return rc; +while (engine->num_smps_outstanding >0 )while (!cl_is_qmap_empty (&engine->smps_on_wire))if ((rc =process_one_recv (engine)) !=0 )return rc; - }return 0 ; }
Signature · 6 lines
1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 1/1 libibnetdisc: remove not needed num_smps_outstanding counter
Now 'num_smps_outstanding' represents number of MADs on a wire, which is duplicates by using its qmap's cl_qmap_count() function.
--- infiniband-diags/libibnetdisc/src/internal.h | 1 - infiniband-diags/libibnetdisc/src/query_smp.c | 14 ++++---------- 2 files changed, 4 insertions(+), 11 deletions(-)
infiniband-diags/libibnetdisc/src/internal.h +0 -1
@@ -80,7 +80,6 @@ struct smp_engine {ibnd_smp_t *smp_queue_tail;void *user_data;cl_qmap_t smps_on_wire; -int num_smps_outstanding;int max_smps_on_wire;unsigned total_smps; };
infiniband-diags/libibnetdisc/src/query_smp.c +4 -10
@@ -100,7 +100,6 @@ static int process_smp_queue(smp_engine_t * engine)free (smp);return rc; } - engine->num_smps_outstanding++;cl_qmap_insert (&engine->smps_on_wire, (uint32_t ) smp->rpc.trid, (cl_map_item_t *) smp); engine->total_smps++;
@@ -171,7 +170,6 @@ static int process_one_recv(smp_engine_t * engine)return -1 ; } - engine->num_smps_outstanding--; rc =process_smp_queue (engine);if (rc) goto error;
@@ -199,7 +197,6 @@ void smp_engine_init(smp_engine_t * engine, struct ibmad_port *ibmad_port, engine->ibmad_port = ibmad_port; engine->user_data = user_data;cl_qmap_init (&engine->smps_on_wire); - engine->num_smps_outstanding =0 ; engine->max_smps_on_wire = max_smps_on_wire; }
@@ -224,16 +221,13 @@ void smp_engine_destroy(smp_engine_t * engine)cl_qmap_remove_item (&engine->smps_on_wire, item);free (item); } - - engine->num_smps_outstanding =0 ; }int process_mads (smp_engine_t * engine) { -int rc =0 ; -while (engine->num_smps_outstanding >0 ) -while (!cl_is_qmap_empty (&engine->smps_on_wire)) -if ((rc =process_one_recv (engine)) !=0 ) -return rc; +int rc; +while (!cl_is_qmap_empty (&engine->smps_on_wire)) +if ((rc =process_one_recv (engine)) !=0 ) +return rc;return 0 ; }
Signature · 6 lines
1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html