infiniband-diags: initial port of linux ib diags
[mirror/winof/.git] / tools / infiniband_diags / src / mcm_rereg_test.c
1 /*\r
2  * Copyright (c) 2006 Voltaire, Inc. All rights reserved.\r
3  *\r
4  * This software is available to you under a choice of one of two\r
5  * licenses.  You may choose to be licensed under the terms of the GNU\r
6  * General Public License (GPL) Version 2, available from the file\r
7  * COPYING in the main directory of this source tree, or the\r
8  * OpenIB.org BSD license below:\r
9  *\r
10  *     Redistribution and use in source and binary forms, with or\r
11  *     without modification, are permitted provided that the following\r
12  *     conditions are met:\r
13  *\r
14  *      - Redistributions of source code must retain the above\r
15  *        copyright notice, this list of conditions and the following\r
16  *        disclaimer.\r
17  *\r
18  *      - Redistributions in binary form must reproduce the above\r
19  *        copyright notice, this list of conditions and the following\r
20  *        disclaimer in the documentation and/or other materials\r
21  *        provided with the distribution.\r
22  *\r
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
30  * SOFTWARE.\r
31  *\r
32  */\r
33 \r
34 #include <stdio.h>\r
35 #include <string.h>\r
36 #include <errno.h>\r
37 #include <inttypes.h>\r
38 \r
39 #include <infiniband/umad.h>\r
40 #include <infiniband/mad.h>\r
41 \r
42 #define info(fmt, arg...) fprintf(stderr, "INFO: " fmt, ##arg )\r
43 #define err(fmt, arg...) fprintf(stderr, "ERR: " fmt, ##arg )\r
44 #ifdef NOISY_DEBUG\r
45 #define dbg(fmt, arg...) fprintf(stderr, "DBG: " fmt, ##arg )\r
46 #else\r
47 #define dbg(fmt, arg...)\r
48 #endif\r
49 \r
50 #define TMO 100\r
51 \r
52 /* Multicast Member Record Component Masks */\r
53 #define IB_MCR_COMPMASK_MGID        (1ULL<<0)\r
54 #define IB_MCR_COMPMASK_PORT_GID    (1ULL<<1)\r
55 #define IB_MCR_COMPMASK_QKEY        (1ULL<<2)\r
56 #define IB_MCR_COMPMASK_MLID        (1ULL<<3)\r
57 #define IB_MCR_COMPMASK_MTU_SEL     (1ULL<<4)\r
58 #define IB_MCR_COMPMASK_MTU         (1ULL<<5)\r
59 #define IB_MCR_COMPMASK_TCLASS      (1ULL<<6)\r
60 #define IB_MCR_COMPMASK_PKEY        (1ULL<<7)\r
61 #define IB_MCR_COMPMASK_RATE_SEL    (1ULL<<8)\r
62 #define IB_MCR_COMPMASK_RATE        (1ULL<<9)\r
63 #define IB_MCR_COMPMASK_LIFE_SEL    (1ULL<<10)\r
64 #define IB_MCR_COMPMASK_LIFE        (1ULL<<11)\r
65 #define IB_MCR_COMPMASK_SL          (1ULL<<12)\r
66 #define IB_MCR_COMPMASK_FLOW        (1ULL<<13)\r
67 #define IB_MCR_COMPMASK_HOP         (1ULL<<14)\r
68 #define IB_MCR_COMPMASK_SCOPE       (1ULL<<15)\r
69 #define IB_MCR_COMPMASK_JOIN_STATE  (1ULL<<16)\r
70 #define IB_MCR_COMPMASK_PROXY       (1ULL<<17)\r
71 \r
72 static ibmad_gid_t mgid_ipoib = {\r
73         0xff, 0x12, 0x40, 0x1b, 0xff, 0xff, 0x00, 0x00,\r
74         0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff\r
75 };\r
76 \r
77 uint64_t build_mcm_rec(uint8_t *data, ibmad_gid_t mgid, ibmad_gid_t port_gid)\r
78 {\r
79         memset(data, 0, IB_SA_DATA_SIZE);\r
80         mad_set_array(data, 0, IB_SA_MCM_MGID_F, mgid);\r
81         mad_set_array(data, 0, IB_SA_MCM_PORTGID_F, port_gid);\r
82         mad_set_field(data, 0, IB_SA_MCM_JOIN_STATE_F, 1);\r
83 \r
84         return IB_MCR_COMPMASK_MGID|IB_MCR_COMPMASK_PORT_GID|\r
85                 IB_MCR_COMPMASK_JOIN_STATE;\r
86 }\r
87 \r
88 static void build_mcm_rec_umad(void *umad, ib_portid_t *dport, int method,\r
89                                uint64_t comp_mask, uint8_t *data)\r
90 {\r
91         ib_rpc_t rpc;\r
92 \r
93         memset(&rpc, 0, sizeof(rpc));\r
94         rpc.mgtclass = IB_SA_CLASS;\r
95         rpc.method = method;\r
96         rpc.attr.id = IB_SA_ATTR_MCRECORD;\r
97         rpc.attr.mod = 0; // ???\r
98         rpc.mask = comp_mask;\r
99         rpc.datasz = IB_SA_DATA_SIZE;\r
100         rpc.dataoffs = IB_SA_DATA_OFFS;\r
101 \r
102         mad_build_pkt(umad, &rpc, dport, NULL, data);\r
103 }\r
104 \r
105 static int rereg_send(int port, int agent, ib_portid_t *dport,\r
106                       uint8_t *umad, int len, int method, ibmad_gid_t port_gid)\r
107 {\r
108         uint8_t data[IB_SA_DATA_SIZE];\r
109         uint64_t comp_mask;\r
110 \r
111         comp_mask = build_mcm_rec(data, mgid_ipoib, port_gid);\r
112 \r
113         build_mcm_rec_umad(umad, dport, method, comp_mask, data);\r
114         if(umad_send(port, agent, umad, len, TMO, 0) < 0) {\r
115                 err("umad_send leave failed: %s\n", strerror(errno));\r
116                 return -1;\r
117         }\r
118         dbg("umad_send %d: tid = 0x%016" PRIx64 "\n", method,\r
119             mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F));\r
120 \r
121         return 0;\r
122 }\r
123 \r
124 static int rereg_port_gid(int port, int agent, ib_portid_t *dport,\r
125                           uint8_t *umad, int len, ibmad_gid_t port_gid)\r
126 {\r
127         uint8_t data[IB_SA_DATA_SIZE];\r
128         uint64_t comp_mask;\r
129 \r
130         comp_mask = build_mcm_rec(data, mgid_ipoib, port_gid);\r
131 \r
132         build_mcm_rec_umad(umad, dport, IB_MAD_METHOD_DELETE,\r
133                            comp_mask, data);\r
134         if(umad_send(port, agent, umad, len, TMO, 0) < 0) {\r
135                 err("umad_send leave failed: %s\n", strerror(errno));\r
136                 return -1;\r
137         }\r
138         dbg("umad_send leave: tid = 0x%016" PRIx64 "\n",\r
139             mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F));\r
140 \r
141         build_mcm_rec_umad(umad, dport, IB_MAD_METHOD_SET,\r
142                            comp_mask, data);\r
143         if(umad_send(port, agent, umad, len, TMO, 0) < 0) {\r
144                 err("umad_send join failed: %s\n", strerror(errno));\r
145                 return -1;\r
146         }\r
147         dbg("umad_send join: tid = 0x%016" PRIx64 "\n",\r
148             mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F));\r
149 \r
150         return 0;\r
151 }\r
152 \r
153 struct guid_trid {\r
154         ibmad_gid_t gid;\r
155         uint64_t guid;\r
156         uint64_t trid;\r
157 };\r
158 \r
159 static int rereg_send_all(int port, int agent, ib_portid_t *dport,\r
160                           struct guid_trid *list, unsigned cnt)\r
161 {\r
162         uint8_t *umad;\r
163         int len = umad_size() + 256;\r
164         int i, ret;\r
165 \r
166         info("rereg_send_all... cnt = %u\n", cnt);\r
167 \r
168         umad = calloc(1, len);\r
169         if (!umad) {\r
170                 err("cannot alloc mem for umad: %s\n", strerror(errno));\r
171                 return -1;\r
172         }\r
173 \r
174         for (i = 0; i < cnt; i++) {\r
175                 ret = rereg_port_gid(port, agent, dport, umad, len, list[i].gid);\r
176                 if (ret < 0) {\r
177                         err("rereg_send_all: rereg_port_gid 0x%016" PRIx64\r
178                             " failed\n", list[i].guid);\r
179                         continue;\r
180                 }\r
181                 list[i].trid = mad_get_field64(umad_get_mad(umad), 0,\r
182                                                IB_MAD_TRID_F);\r
183         }\r
184 \r
185         info("rereg_send_all: sent %u requests\n", cnt*2);\r
186 \r
187         free(umad);\r
188 \r
189         return 0;\r
190 }\r
191 \r
192 #if 0\r
193 static int rereg_mcm_rec_send(int port, int agent, ib_portid_t *dport, int cnt)\r
194 {\r
195         ib_portid_t portid;\r
196         ibmad_gid_t port_gid;\r
197         uint8_t *umad;\r
198         int len, ret = 0;\r
199 \r
200         ib_resolve_self(&portid, NULL, &port_gid);\r
201 \r
202         len = umad_size() + 256;\r
203         umad = calloc(1, len);\r
204         if (!umad) {\r
205                 err("cannot alloc mem for umad: %s\n", strerror(errno));\r
206                 return -1;\r
207         }\r
208 \r
209         while(cnt--) {\r
210                 if (!rereg_port_gid(port, agent, dport, umad, len, port_gid))\r
211                         ret += 2;\r
212         }\r
213 \r
214         free(umad);\r
215 \r
216         return ret;\r
217 }\r
218 #endif\r
219 \r
220 static int rereg_recv(int port, int agent, ib_portid_t *dport,\r
221                       uint8_t *umad, int length, int tmo)\r
222 {\r
223         int ret, retry = 0;\r
224         int len = length;\r
225 \r
226         while((ret = umad_recv(port, umad, &len, tmo)) < 0 &&\r
227               errno == ETIMEDOUT) {\r
228                 if (retry++ > 3)\r
229                         return 0;\r
230         }\r
231         if (ret < 0) {\r
232                 err("umad_recv %d failed: %s\n", ret, strerror(errno));\r
233                 return -1;\r
234         }\r
235         dbg("umad_recv (retries %d), tid = 0x%016" PRIx64 ": len = %d, status = %d\n",\r
236             retry,\r
237             mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F),\r
238             len, umad_status(umad));\r
239 \r
240         return 1;\r
241 }\r
242 \r
243 static int rereg_recv_all(int port, int agent, ib_portid_t *dport,\r
244                           struct guid_trid *list, unsigned cnt)\r
245 {\r
246         uint8_t *umad, *mad;\r
247         int len = umad_size() + 256;\r
248         uint64_t trid;\r
249         unsigned n, method, status;\r
250         int i;\r
251 \r
252         info("rereg_recv_all...\n");\r
253 \r
254         umad = calloc(1, len);\r
255         if (!umad) {\r
256                 err("cannot alloc mem for umad: %s\n", strerror(errno));\r
257                 return -1;\r
258         }\r
259 \r
260         n = 0;\r
261         while (rereg_recv(port, agent, dport, umad, len, TMO) > 0) {\r
262                 dbg("rereg_recv_all: done %d\n", n);\r
263                 n++;\r
264                 mad = umad_get_mad(umad);\r
265 \r
266                 method = mad_get_field(mad, 0, IB_MAD_METHOD_F);\r
267                 status = mad_get_field(mad, 0, IB_MAD_STATUS_F);\r
268 \r
269                 if (status)\r
270                         dbg("MAD status %x, method %x\n", status, method);\r
271 \r
272                 if (status &&\r
273                     (method&0x7f) == (IB_MAD_METHOD_GET_RESPONSE&0x7f)) {\r
274                         trid = mad_get_field64(mad, 0, IB_MAD_TRID_F);\r
275                         for (i = 0; i < cnt; i++)\r
276                                 if (trid == list[i].trid)\r
277                                         break;\r
278                         if (i == cnt) {\r
279                                 err("cannot find trid 0x%016" PRIx64 "\n",\r
280                                     trid);\r
281                                 continue;\r
282                         }\r
283                         info("guid 0x%016" PRIx64 ": method = %x status = %x. Resending\n",\r
284                              ntohll(list[i].guid), method, status);\r
285                         rereg_port_gid(port, agent, dport, umad, len,\r
286                                        list[i].gid);\r
287                         list[i].trid = mad_get_field64(umad_get_mad(umad), 0,\r
288                                                        IB_MAD_TRID_F);\r
289                 }\r
290         }\r
291 \r
292         info("rereg_recv_all: got %u responses\n", n);\r
293 \r
294         free(umad);\r
295         return 0;\r
296 }\r
297 \r
298 static int rereg_query_all(int port, int agent, ib_portid_t *dport,\r
299                            struct guid_trid *list, unsigned cnt)\r
300 {\r
301         uint8_t *umad, *mad;\r
302         int len = umad_size() + 256;\r
303         unsigned method, status;\r
304         int i, ret;\r
305 \r
306         info("rereg_query_all...\n");\r
307 \r
308         umad = calloc(1, len);\r
309         if (!umad) {\r
310                 err("cannot alloc mem for umad: %s\n", strerror(errno));\r
311                 return -1;\r
312         }\r
313 \r
314         for ( i = 0; i < cnt; i++ ) {\r
315                 ret = rereg_send(port, agent, dport, umad, len,\r
316                                  IB_MAD_METHOD_GET, list[i].gid);\r
317                 if (ret < 0) {\r
318                         err("query_all: rereg_send failed.\n");\r
319                         continue;\r
320                 }\r
321 \r
322                 ret = rereg_recv(port, agent, dport, umad, len, TMO);\r
323                 if (ret < 0) {\r
324                         err("query_all: rereg_recv failed.\n");\r
325                         continue;\r
326                 }\r
327 \r
328                 mad = umad_get_mad(umad);\r
329 \r
330                 method = mad_get_field(mad, 0, IB_MAD_METHOD_F);\r
331                 status = mad_get_field(mad, 0, IB_MAD_STATUS_F);\r
332 \r
333                 if (status)\r
334                         info("guid 0x%016" PRIx64 ": status %x, method %x\n",\r
335                              ntohll(list[i].guid), status, method);\r
336         }\r
337 \r
338         info("rereg_query_all: %u queried.\n", cnt);\r
339 \r
340         free(umad);\r
341         return 0;\r
342 }\r
343 \r
344 #if 0\r
345 static int rereg_mcm_rec_recv(int port, int agent, int cnt)\r
346 {\r
347         uint8_t *umad, *mad;\r
348         int len = umad_size() + 256;\r
349         int i;\r
350 \r
351         umad = calloc(1, len);\r
352         if (!umad) {\r
353                 err("cannot alloc mem for umad: %s\n", strerror(errno));\r
354                 return -1;\r
355         }\r
356 \r
357         for ( i = 0; i < cnt; i++ ) {\r
358                 int retry;\r
359                 retry = 0;\r
360                 while (umad_recv(port, umad, &len, TMO) < 0 &&\r
361                        errno == ETIMEDOUT)\r
362                         if (retry++ > 3) {\r
363                                 err("umad_recv %d failed: %s\n",\r
364                                     i, strerror(errno));\r
365                                 free(umad);\r
366                                 return -1;\r
367                         }\r
368                 dbg("umad_recv %d (retries %d), tid = 0x%016" PRIx64 ": len = %d, status = %d\n",\r
369                     i, retry,\r
370                     mad_get_field64(umad_get_mad(umad), 0, IB_MAD_TRID_F),\r
371                     len, umad_status(umad));\r
372                 mad = umad_get_mad(umad);\r
373         }\r
374 \r
375         free(umad);\r
376         return 0;\r
377 }\r
378 #endif\r
379 \r
380 #define MAX_CLIENTS 50\r
381 \r
382 static int rereg_and_test_port(char *guid_file, int port, int agent, ib_portid_t *dport, int timeout)\r
383 {\r
384         char line[256];\r
385         FILE *f;\r
386         ibmad_gid_t port_gid;\r
387         uint64_t prefix = htonll(0xfe80000000000000llu);\r
388         uint64_t guid = htonll(0x0002c90200223825llu);\r
389         struct guid_trid *list;\r
390         int i = 0;\r
391 \r
392         list = calloc(MAX_CLIENTS, sizeof(*list));\r
393         if (!list) {\r
394                 err("cannot alloc mem for guid/trid list: %s\n", strerror(errno));\r
395                 return -1;\r
396         }\r
397 \r
398         f = fopen(guid_file, "r");\r
399         if (!f) {\r
400                 err("cannot open %s: %s\n", guid_file, strerror(errno));\r
401                 return -1;\r
402         }\r
403 \r
404         while (fgets(line, sizeof(line), f)) {\r
405                 guid = strtoull(line, NULL, 0);\r
406                 guid = htonll(guid);\r
407                 memcpy(&port_gid[0], &prefix, 8);\r
408                 memcpy(&port_gid[8], &guid, 8);\r
409 \r
410                 list[i].guid = guid;\r
411                 memcpy(list[i].gid, port_gid, sizeof(list[i].gid));\r
412                 list[i].trid = 0;\r
413                 if (++i >= MAX_CLIENTS)\r
414                         break;\r
415         }\r
416         fclose(f);\r
417 \r
418         rereg_send_all(port, agent, dport, list, i);\r
419         rereg_recv_all(port, agent, dport, list, i);\r
420 \r
421         rereg_query_all(port, agent, dport, list, i);\r
422 \r
423         free(list);\r
424         return 0;\r
425 }\r
426 \r
427 int main(int argc, char **argv)\r
428 {\r
429         char *guid_file = "port_guids.list";\r
430         int mgmt_classes[2] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS};\r
431         ib_portid_t dport_id;\r
432         int port, agent;\r
433         uint8_t *umad, *mad;\r
434         int len;\r
435 \r
436         if (argc > 1)\r
437                 guid_file = argv[1];\r
438 \r
439         madrpc_init(NULL, 0, mgmt_classes, 2);\r
440 \r
441 #if 1\r
442         ib_resolve_smlid(&dport_id, TMO);\r
443 #else\r
444         memset(&dport_id, 0, sizeof(dport_id));\r
445         dport_id.lid = 1;\r
446 #endif\r
447         dport_id.qp = 1;\r
448         if (!dport_id.qkey)\r
449                 dport_id.qkey = IB_DEFAULT_QP1_QKEY;\r
450 \r
451 \r
452         len = umad_size() + 256;\r
453         umad = calloc(1, len);\r
454         if (!umad) {\r
455                 err("cannot alloc mem for umad: %s\n", strerror(errno));\r
456                 return -1;\r
457         }\r
458 \r
459 #if 1\r
460         port = madrpc_portid();\r
461 #else\r
462         ret = umad_init();\r
463 \r
464         port = umad_open_port(NULL, 0);\r
465         if (port < 0) {\r
466                 err("umad_open_port failed: %s\n", strerror(errno));\r
467                 return port;\r
468         }\r
469 #endif\r
470 \r
471         agent = umad_register(port, IB_SA_CLASS, 2, 0, NULL);\r
472 \r
473 #if 0\r
474         int cnt;\r
475         cnt = rereg_mcm_rec_send(port, agent, &dport_id, cnt);\r
476 \r
477         rereg_recv_all(port, agent, &dport_id);\r
478 #else\r
479         rereg_and_test_port(guid_file, port, agent, &dport_id, TMO);\r
480 #endif\r
481         mad = umad_get_mad(umad);\r
482 \r
483         free(umad);\r
484         umad_unregister(port, agent);\r
485         umad_close_port(port);\r
486         umad_done();\r
487 \r
488         return 0;\r
489 }\r