]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_sa_link_record.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_sa_link_record.c
1 /*
2  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35
36 /*
37  * Abstract:
38  *    Implementation of osm_lr_rcv_t.
39  * This object represents the LinkRecord Receiver object.
40  * This object is part of the opensm family of objects.
41  */
42
43 #if HAVE_CONFIG_H
44 #  include <config.h>
45 #endif                          /* HAVE_CONFIG_H */
46
47 #include <string.h>
48 #include <iba/ib_types.h>
49 #include <complib/cl_qmap.h>
50 #include <complib/cl_debug.h>
51 #include <vendor/osm_vendor_api.h>
52 #include <opensm/osm_node.h>
53 #include <opensm/osm_switch.h>
54 #include <opensm/osm_helper.h>
55 #include <opensm/osm_pkey.h>
56 #include <opensm/osm_sa.h>
57
58 typedef struct osm_lr_item {
59         cl_list_item_t list_item;
60         ib_link_record_t link_rec;
61 } osm_lr_item_t;
62
63 /**********************************************************************
64  **********************************************************************/
65 static void
66 __osm_lr_rcv_build_physp_link(IN osm_sa_t * sa,
67                               IN const ib_net16_t from_lid,
68                               IN const ib_net16_t to_lid,
69                               IN const uint8_t from_port,
70                               IN const uint8_t to_port, IN cl_qlist_t * p_list)
71 {
72         osm_lr_item_t *p_lr_item;
73
74         p_lr_item = malloc(sizeof(*p_lr_item));
75         if (p_lr_item == NULL) {
76                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1801: "
77                         "Unable to acquire link record\n"
78                         "\t\t\t\tFrom port %u\n"
79                         "\t\t\t\tTo port   %u\n"
80                         "\t\t\t\tFrom lid  %u\n"
81                         "\t\t\t\tTo lid    %u\n",
82                         from_port, to_port,
83                         cl_ntoh16(from_lid), cl_ntoh16(to_lid));
84                 return;
85         }
86         memset(p_lr_item, 0, sizeof(*p_lr_item));
87
88         p_lr_item->link_rec.from_port_num = from_port;
89         p_lr_item->link_rec.to_port_num = to_port;
90         p_lr_item->link_rec.to_lid = to_lid;
91         p_lr_item->link_rec.from_lid = from_lid;
92
93         cl_qlist_insert_tail(p_list, &p_lr_item->list_item);
94 }
95
96 /**********************************************************************
97  **********************************************************************/
98 static void
99 __get_base_lid(IN const osm_physp_t * p_physp, OUT ib_net16_t * p_base_lid)
100 {
101         if (p_physp->p_node->node_info.node_type == IB_NODE_TYPE_SWITCH)
102                 *p_base_lid = osm_physp_get_base_lid
103                               (osm_node_get_physp_ptr(p_physp->p_node, 0));
104         else
105                 *p_base_lid = osm_physp_get_base_lid(p_physp);
106 }
107
108 /**********************************************************************
109  **********************************************************************/
110 static void
111 __osm_lr_rcv_get_physp_link(IN osm_sa_t * sa,
112                             IN const ib_link_record_t * const p_lr,
113                             IN const osm_physp_t * p_src_physp,
114                             IN const osm_physp_t * p_dest_physp,
115                             IN const ib_net64_t comp_mask,
116                             IN cl_qlist_t * const p_list,
117                             IN const osm_physp_t * p_req_physp)
118 {
119         uint8_t src_port_num;
120         uint8_t dest_port_num;
121         ib_net16_t from_base_lid;
122         ib_net16_t to_base_lid;
123         ib_net16_t lmc_mask;
124
125         OSM_LOG_ENTER(sa->p_log);
126
127         /*
128            If only one end of the link is specified, determine
129            the other side.
130          */
131         if (p_src_physp) {
132                 if (p_dest_physp) {
133                         /*
134                            Ensure the two physp's are actually connected.
135                            If not, bail out.
136                          */
137                         if (osm_physp_get_remote(p_src_physp) != p_dest_physp)
138                                 goto Exit;
139                 } else {
140                         p_dest_physp = osm_physp_get_remote(p_src_physp);
141                         if (p_dest_physp == NULL)
142                                 goto Exit;
143                 }
144         } else {
145                 if (p_dest_physp) {
146                         p_src_physp = osm_physp_get_remote(p_dest_physp);
147                         if (p_src_physp == NULL)
148                                 goto Exit;
149                 } else
150                         goto Exit;      /* no physp's, so nothing to do */
151         }
152
153         /* Check that the p_src_physp, p_dest_physp and p_req_physp
154            all share a pkey (doesn't have to be the same p_key). */
155         if (!osm_physp_share_pkey(sa->p_log, p_src_physp, p_dest_physp)) {
156                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
157                         "Source and Dest PhysPorts do not share PKey\n");
158                 goto Exit;
159         }
160         if (!osm_physp_share_pkey(sa->p_log, p_src_physp, p_req_physp)) {
161                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
162                         "Source and Requester PhysPorts do not share PKey\n");
163                 goto Exit;
164         }
165         if (!osm_physp_share_pkey(sa->p_log, p_req_physp, p_dest_physp)) {
166                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
167                         "Requester and Dest PhysPorts do not share PKey\n");
168                 goto Exit;
169         }
170
171         src_port_num = osm_physp_get_port_num(p_src_physp);
172         dest_port_num = osm_physp_get_port_num(p_dest_physp);
173
174         if (comp_mask & IB_LR_COMPMASK_FROM_PORT)
175                 if (src_port_num != p_lr->from_port_num)
176                         goto Exit;
177
178         if (comp_mask & IB_LR_COMPMASK_TO_PORT)
179                 if (dest_port_num != p_lr->to_port_num)
180                         goto Exit;
181
182         __get_base_lid(p_src_physp, &from_base_lid);
183         __get_base_lid(p_dest_physp, &to_base_lid);
184
185         lmc_mask = ~((1 << sa->p_subn->opt.lmc) - 1);
186         lmc_mask = cl_hton16(lmc_mask);
187
188         if (comp_mask & IB_LR_COMPMASK_FROM_LID)
189                 if (from_base_lid != (p_lr->from_lid & lmc_mask))
190                         goto Exit;
191
192         if (comp_mask & IB_LR_COMPMASK_TO_LID)
193                 if (to_base_lid != (p_lr->to_lid & lmc_mask))
194                         goto Exit;
195
196         OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Acquiring link record\n"
197                 "\t\t\t\tsrc port 0x%" PRIx64 " (port %u)"
198                 ", dest port 0x%" PRIx64 " (port %u)\n",
199                 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)), src_port_num,
200                 cl_ntoh64(osm_physp_get_port_guid(p_dest_physp)),
201                 dest_port_num);
202
203
204         __osm_lr_rcv_build_physp_link(sa, from_base_lid, to_base_lid,
205                                       src_port_num, dest_port_num, p_list);
206
207 Exit:
208         OSM_LOG_EXIT(sa->p_log);
209 }
210
211 /**********************************************************************
212  **********************************************************************/
213 static void
214 __osm_lr_rcv_get_port_links(IN osm_sa_t * sa,
215                             IN const ib_link_record_t * const p_lr,
216                             IN const osm_port_t * p_src_port,
217                             IN const osm_port_t * p_dest_port,
218                             IN const ib_net64_t comp_mask,
219                             IN cl_qlist_t * const p_list,
220                             IN const osm_physp_t * p_req_physp)
221 {
222         const osm_physp_t *p_src_physp;
223         const osm_physp_t *p_dest_physp;
224         const cl_qmap_t *p_node_tbl;
225         osm_node_t * p_node;
226         uint8_t port_num;
227         uint8_t num_ports;
228         uint8_t dest_num_ports;
229         uint8_t dest_port_num;
230
231         OSM_LOG_ENTER(sa->p_log);
232
233         if (p_src_port) {
234                 if (p_dest_port) {
235                         /*
236                            Build an LR for every link connected between both ports.
237                            The inner function will discard physp combinations
238                            that do not actually connect.  Don't bother screening
239                            for that here.
240                          */
241                         num_ports = osm_node_get_num_physp(p_src_port->p_node);
242                         dest_num_ports =
243                             osm_node_get_num_physp(p_dest_port->p_node);
244                         for (port_num = 1; port_num < num_ports; port_num++) {
245                                 p_src_physp =
246                                     osm_node_get_physp_ptr(p_src_port->p_node,
247                                                            port_num);
248                                 for (dest_port_num = 1;
249                                      dest_port_num < dest_num_ports;
250                                      dest_port_num++) {
251                                         p_dest_physp =
252                                             osm_node_get_physp_ptr(p_dest_port->
253                                                                    p_node,
254                                                                    dest_port_num);
255                                         /* both physical ports should be with data */
256                                         if (p_src_physp && p_dest_physp)
257                                                 __osm_lr_rcv_get_physp_link
258                                                     (sa, p_lr, p_src_physp,
259                                                      p_dest_physp, comp_mask,
260                                                      p_list, p_req_physp);
261                                 }
262                         }
263                 } else {
264                         /*
265                            Build an LR for every link connected from the source port.
266                          */
267                         if (comp_mask & IB_LR_COMPMASK_FROM_PORT) {
268                                 port_num = p_lr->from_port_num;
269                                 /* If the port number is out of the range of the p_src_port, then
270                                    this couldn't be a relevant record. */
271                                 if (port_num <
272                                     p_src_port->p_node->physp_tbl_size) {
273                                         p_src_physp =
274                                             osm_node_get_physp_ptr(p_src_port->
275                                                                    p_node,
276                                                                    port_num);
277                                         if (p_src_physp)
278                                                 __osm_lr_rcv_get_physp_link
279                                                     (sa, p_lr, p_src_physp,
280                                                      NULL, comp_mask, p_list,
281                                                      p_req_physp);
282                                 }
283                         } else {
284                                 num_ports =
285                                     osm_node_get_num_physp(p_src_port->p_node);
286                                 for (port_num = 1; port_num < num_ports;
287                                      port_num++) {
288                                         p_src_physp =
289                                             osm_node_get_physp_ptr(p_src_port->
290                                                                    p_node,
291                                                                    port_num);
292                                         if (p_src_physp)
293                                                 __osm_lr_rcv_get_physp_link
294                                                     (sa, p_lr, p_src_physp,
295                                                      NULL, comp_mask, p_list,
296                                                      p_req_physp);
297                                 }
298                         }
299                 }
300         } else {
301                 if (p_dest_port) {
302                         /*
303                            Build an LR for every link connected to the dest port.
304                          */
305                         if (comp_mask & IB_LR_COMPMASK_TO_PORT) {
306                                 port_num = p_lr->to_port_num;
307                                 /* If the port number is out of the range of the p_dest_port, then
308                                    this couldn't be a relevant record. */
309                                 if (port_num <
310                                     p_dest_port->p_node->physp_tbl_size) {
311                                         p_dest_physp =
312                                             osm_node_get_physp_ptr(p_dest_port->
313                                                                    p_node,
314                                                                    port_num);
315                                         if (p_dest_physp)
316                                                 __osm_lr_rcv_get_physp_link
317                                                     (sa, p_lr, NULL,
318                                                      p_dest_physp, comp_mask,
319                                                      p_list, p_req_physp);
320                                 }
321                         } else {
322                                 num_ports =
323                                     osm_node_get_num_physp(p_dest_port->p_node);
324                                 for (port_num = 1; port_num < num_ports;
325                                      port_num++) {
326                                         p_dest_physp =
327                                             osm_node_get_physp_ptr(p_dest_port->
328                                                                    p_node,
329                                                                    port_num);
330                                         if (p_dest_physp)
331                                                 __osm_lr_rcv_get_physp_link
332                                                     (sa, p_lr, NULL,
333                                                      p_dest_physp, comp_mask,
334                                                      p_list, p_req_physp);
335                                 }
336                         }
337                 } else {
338                         /*
339                            Process the world (recurse once back into this function).
340                          */
341                         p_node_tbl = &sa->p_subn->node_guid_tbl;
342                         p_node = (osm_node_t *)cl_qmap_head(p_node_tbl);
343
344                         while (p_node != (osm_node_t *)cl_qmap_end(p_node_tbl)) {
345                                 num_ports = osm_node_get_num_physp(p_node);
346                                 for (port_num = 1; port_num < num_ports;
347                                      port_num++) {
348                                         p_src_physp =
349                                             osm_node_get_physp_ptr(p_node,
350                                                                    port_num);
351                                         if (p_src_physp)
352                                                 __osm_lr_rcv_get_physp_link
353                                                     (sa, p_lr, p_src_physp,
354                                                      NULL, comp_mask, p_list,
355                                                      p_req_physp);
356                                 }
357                                 p_node = (osm_node_t *) cl_qmap_next(&p_node->
358                                                                      map_item);
359                         }
360                 }
361         }
362
363         OSM_LOG_EXIT(sa->p_log);
364 }
365
366 /**********************************************************************
367  Returns the SA status to return to the client.
368  **********************************************************************/
369 static ib_net16_t
370 __osm_lr_rcv_get_end_points(IN osm_sa_t * sa,
371                             IN const osm_madw_t * const p_madw,
372                             OUT const osm_port_t ** const pp_src_port,
373                             OUT const osm_port_t ** const pp_dest_port)
374 {
375         const ib_link_record_t *p_lr;
376         const ib_sa_mad_t *p_sa_mad;
377         ib_net64_t comp_mask;
378         ib_api_status_t status;
379         ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
380
381         OSM_LOG_ENTER(sa->p_log);
382
383         /*
384            Determine what fields are valid and then get a pointer
385            to the source and destination port objects, if possible.
386          */
387         p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
388         p_lr = (ib_link_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
389
390         comp_mask = p_sa_mad->comp_mask;
391         *pp_src_port = NULL;
392         *pp_dest_port = NULL;
393
394         if (p_sa_mad->comp_mask & IB_LR_COMPMASK_FROM_LID) {
395                 status = osm_get_port_by_base_lid(sa->p_subn,
396                                                   p_lr->from_lid, pp_src_port);
397
398                 if ((status != IB_SUCCESS) || (*pp_src_port == NULL)) {
399                         /*
400                            This 'error' is the client's fault (bad lid) so
401                            don't enter it as an error in our own log.
402                            Return an error response to the client.
403                          */
404                         OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
405                                 "No source port with LID %u\n",
406                                 cl_ntoh16(p_lr->from_lid));
407
408                         sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
409                         goto Exit;
410                 }
411         }
412
413         if (p_sa_mad->comp_mask & IB_LR_COMPMASK_TO_LID) {
414                 status = osm_get_port_by_base_lid(sa->p_subn,
415                                                   p_lr->to_lid, pp_dest_port);
416
417                 if ((status != IB_SUCCESS) || (*pp_dest_port == NULL)) {
418                         /*
419                            This 'error' is the client's fault (bad lid) so
420                            don't enter it as an error in our own log.
421                            Return an error response to the client.
422                          */
423                         OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
424                                 "No dest port with LID %u\n",
425                                 cl_ntoh16(p_lr->to_lid));
426
427                         sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
428                         goto Exit;
429                 }
430         }
431
432 Exit:
433         OSM_LOG_EXIT(sa->p_log);
434         return (sa_status);
435 }
436
437 /**********************************************************************
438  **********************************************************************/
439 void osm_lr_rcv_process(IN void *context, IN void *data)
440 {
441         osm_sa_t *sa = context;
442         osm_madw_t *p_madw = data;
443         const ib_link_record_t *p_lr;
444         const ib_sa_mad_t *p_sa_mad;
445         const osm_port_t *p_src_port;
446         const osm_port_t *p_dest_port;
447         cl_qlist_t lr_list;
448         ib_net16_t sa_status;
449         osm_physp_t *p_req_physp;
450
451         OSM_LOG_ENTER(sa->p_log);
452
453         CL_ASSERT(p_madw);
454
455         p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
456         p_lr = (ib_link_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
457
458         CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_LINK_RECORD);
459
460         /* we only support SubnAdmGet and SubnAdmGetTable methods */
461         if (p_sa_mad->method != IB_MAD_METHOD_GET &&
462             p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
463                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1804: "
464                         "Unsupported Method (%s)\n",
465                         ib_get_sa_method_str(p_sa_mad->method));
466                 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
467                 goto Exit;
468         }
469
470         /* update the requester physical port. */
471         p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
472                                                 osm_madw_get_mad_addr_ptr
473                                                 (p_madw));
474         if (p_req_physp == NULL) {
475                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1805: "
476                         "Cannot find requester physical port\n");
477                 goto Exit;
478         }
479
480         if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG))
481                 osm_dump_link_record(sa->p_log, p_lr, OSM_LOG_DEBUG);
482
483         cl_qlist_init(&lr_list);
484
485         /*
486            Most SA functions (including this one) are read-only on the
487            subnet object, so we grab the lock non-exclusively.
488          */
489         cl_plock_acquire(sa->p_lock);
490
491         sa_status = __osm_lr_rcv_get_end_points(sa, p_madw,
492                                                 &p_src_port, &p_dest_port);
493
494         if (sa_status == IB_SA_MAD_STATUS_SUCCESS)
495                 __osm_lr_rcv_get_port_links(sa, p_lr, p_src_port,
496                                             p_dest_port, p_sa_mad->comp_mask,
497                                             &lr_list, p_req_physp);
498
499         cl_plock_release(sa->p_lock);
500
501         osm_sa_respond(sa, p_madw, sizeof(ib_link_record_t), &lr_list);
502
503 Exit:
504         OSM_LOG_EXIT(sa->p_log);
505 }