2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2007 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
7 * This software is available to you under a choice of one of two
8 * licenses. You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
17 * - Redistributions of source code must retain the above
18 * copyright notice, this list of conditions and the following
21 * - Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials
24 * provided with the distribution.
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 * Implementation of osm_lr_rcv_t.
40 * This object represents the LinkRecord Receiver object.
41 * This object is part of the opensm family of objects.
46 #endif /* HAVE_CONFIG_H */
49 #include <iba/ib_types.h>
50 #include <complib/cl_qmap.h>
51 #include <complib/cl_debug.h>
52 #include <opensm/osm_file_ids.h>
53 #define FILE_ID OSM_FILE_SA_LINK_RECORD_C
54 #include <vendor/osm_vendor_api.h>
55 #include <opensm/osm_node.h>
56 #include <opensm/osm_switch.h>
57 #include <opensm/osm_helper.h>
58 #include <opensm/osm_pkey.h>
59 #include <opensm/osm_sa.h>
61 #define SA_LR_RESP_SIZE SA_ITEM_RESP_SIZE(link_rec)
63 static void lr_rcv_build_physp_link(IN osm_sa_t * sa, IN ib_net16_t from_lid,
64 IN ib_net16_t to_lid, IN uint8_t from_port,
65 IN uint8_t to_port, IN cl_qlist_t * p_list)
67 osm_sa_item_t *p_lr_item;
69 p_lr_item = malloc(SA_LR_RESP_SIZE);
70 if (p_lr_item == NULL) {
71 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1801: "
72 "Unable to acquire link record\n"
73 "\t\t\t\tFrom port %u\n" "\t\t\t\tTo port %u\n"
74 "\t\t\t\tFrom lid %u\n" "\t\t\t\tTo lid %u\n",
76 cl_ntoh16(from_lid), cl_ntoh16(to_lid));
79 memset(p_lr_item, 0, SA_LR_RESP_SIZE);
81 p_lr_item->resp.link_rec.from_port_num = from_port;
82 p_lr_item->resp.link_rec.to_port_num = to_port;
83 p_lr_item->resp.link_rec.to_lid = to_lid;
84 p_lr_item->resp.link_rec.from_lid = from_lid;
86 cl_qlist_insert_tail(p_list, &p_lr_item->list_item);
89 static ib_net16_t get_base_lid(IN const osm_physp_t * p_physp)
91 if (p_physp->p_node->node_info.node_type == IB_NODE_TYPE_SWITCH)
92 p_physp = osm_node_get_physp_ptr(p_physp->p_node, 0);
93 return osm_physp_get_base_lid(p_physp);
96 static void lr_rcv_get_physp_link(IN osm_sa_t * sa,
97 IN const ib_link_record_t * p_lr,
98 IN const osm_physp_t * p_src_physp,
99 IN const osm_physp_t * p_dest_physp,
100 IN const ib_net64_t comp_mask,
101 IN cl_qlist_t * p_list,
102 IN const osm_physp_t * p_req_physp)
104 uint8_t src_port_num;
105 uint8_t dest_port_num;
106 ib_net16_t from_base_lid;
107 ib_net16_t to_base_lid;
110 OSM_LOG_ENTER(sa->p_log);
113 If only one end of the link is specified, determine
119 Ensure the two physp's are actually connected.
122 if (osm_physp_get_remote(p_src_physp) != p_dest_physp)
125 p_dest_physp = osm_physp_get_remote(p_src_physp);
126 if (p_dest_physp == NULL)
131 p_src_physp = osm_physp_get_remote(p_dest_physp);
132 if (p_src_physp == NULL)
135 goto Exit; /* no physp's, so nothing to do */
138 /* Check that the p_src_physp, p_dest_physp and p_req_physp
139 all share a pkey (doesn't have to be the same p_key). */
140 if (!osm_physp_share_pkey(sa->p_log, p_src_physp, p_dest_physp,
141 sa->p_subn->opt.allow_both_pkeys)) {
142 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
143 "Source and Dest PhysPorts do not share PKey\n");
146 if (!osm_physp_share_pkey(sa->p_log, p_src_physp, p_req_physp,
147 sa->p_subn->opt.allow_both_pkeys)) {
148 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
149 "Source and Requester PhysPorts do not share PKey\n");
152 if (!osm_physp_share_pkey(sa->p_log, p_req_physp, p_dest_physp,
153 sa->p_subn->opt.allow_both_pkeys)) {
154 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
155 "Requester and Dest PhysPorts do not share PKey\n");
159 src_port_num = osm_physp_get_port_num(p_src_physp);
160 dest_port_num = osm_physp_get_port_num(p_dest_physp);
162 if (comp_mask & IB_LR_COMPMASK_FROM_PORT)
163 if (src_port_num != p_lr->from_port_num)
166 if (comp_mask & IB_LR_COMPMASK_TO_PORT)
167 if (dest_port_num != p_lr->to_port_num)
170 from_base_lid = get_base_lid(p_src_physp);
171 to_base_lid = get_base_lid(p_dest_physp);
173 lmc_mask = ~((1 << sa->p_subn->opt.lmc) - 1);
174 lmc_mask = cl_hton16(lmc_mask);
176 if (comp_mask & IB_LR_COMPMASK_FROM_LID)
177 if (from_base_lid != (p_lr->from_lid & lmc_mask))
180 if (comp_mask & IB_LR_COMPMASK_TO_LID)
181 if (to_base_lid != (p_lr->to_lid & lmc_mask))
184 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Acquiring link record\n"
185 "\t\t\t\tsrc port 0x%" PRIx64 " (port %u)"
186 ", dest port 0x%" PRIx64 " (port %u)\n",
187 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)), src_port_num,
188 cl_ntoh64(osm_physp_get_port_guid(p_dest_physp)),
191 lr_rcv_build_physp_link(sa, from_base_lid, to_base_lid, src_port_num,
192 dest_port_num, p_list);
195 OSM_LOG_EXIT(sa->p_log);
198 static void lr_rcv_get_port_links(IN osm_sa_t * sa,
199 IN const ib_link_record_t * p_lr,
200 IN const osm_port_t * p_src_port,
201 IN const osm_port_t * p_dest_port,
202 IN const ib_net64_t comp_mask,
203 IN cl_qlist_t * p_list,
204 IN const osm_physp_t * p_req_physp)
206 const osm_physp_t *p_src_physp;
207 const osm_physp_t *p_dest_physp;
208 const cl_qmap_t *p_node_tbl;
212 uint8_t dest_num_ports;
213 uint8_t dest_port_num;
215 OSM_LOG_ENTER(sa->p_log);
220 Build an LR for every link connected between both ports.
221 The inner function will discard physp combinations
222 that do not actually connect. Don't bother screening
225 num_ports = osm_node_get_num_physp(p_src_port->p_node);
227 osm_node_get_num_physp(p_dest_port->p_node);
228 for (port_num = 1; port_num < num_ports; port_num++) {
230 osm_node_get_physp_ptr(p_src_port->p_node,
232 for (dest_port_num = 1;
233 dest_port_num < dest_num_ports;
236 osm_node_get_physp_ptr(p_dest_port->
239 /* both physical ports should be with data */
240 if (p_src_physp && p_dest_physp)
241 lr_rcv_get_physp_link
242 (sa, p_lr, p_src_physp,
243 p_dest_physp, comp_mask,
244 p_list, p_req_physp);
249 Build an LR for every link connected from the source port.
251 if (comp_mask & IB_LR_COMPMASK_FROM_PORT) {
252 port_num = p_lr->from_port_num;
253 /* If the port number is out of the range of the p_src_port, then
254 this couldn't be a relevant record. */
256 p_src_port->p_node->physp_tbl_size) {
258 osm_node_get_physp_ptr(p_src_port->
262 lr_rcv_get_physp_link
263 (sa, p_lr, p_src_physp,
264 NULL, comp_mask, p_list,
269 osm_node_get_num_physp(p_src_port->p_node);
270 for (port_num = 1; port_num < num_ports;
273 osm_node_get_physp_ptr(p_src_port->
277 lr_rcv_get_physp_link
278 (sa, p_lr, p_src_physp,
279 NULL, comp_mask, p_list,
287 Build an LR for every link connected to the dest port.
289 if (comp_mask & IB_LR_COMPMASK_TO_PORT) {
290 port_num = p_lr->to_port_num;
291 /* If the port number is out of the range of the p_dest_port, then
292 this couldn't be a relevant record. */
294 p_dest_port->p_node->physp_tbl_size) {
296 osm_node_get_physp_ptr(p_dest_port->
300 lr_rcv_get_physp_link
302 p_dest_physp, comp_mask,
303 p_list, p_req_physp);
307 osm_node_get_num_physp(p_dest_port->p_node);
308 for (port_num = 1; port_num < num_ports;
311 osm_node_get_physp_ptr(p_dest_port->
315 lr_rcv_get_physp_link
317 p_dest_physp, comp_mask,
318 p_list, p_req_physp);
323 Process the world (recurse once back into this function).
325 p_node_tbl = &sa->p_subn->node_guid_tbl;
326 p_node = (osm_node_t *) cl_qmap_head(p_node_tbl);
328 while (p_node != (osm_node_t *) cl_qmap_end(p_node_tbl)) {
329 num_ports = osm_node_get_num_physp(p_node);
330 for (port_num = 1; port_num < num_ports;
333 osm_node_get_physp_ptr(p_node,
336 lr_rcv_get_physp_link
337 (sa, p_lr, p_src_physp,
338 NULL, comp_mask, p_list,
341 p_node = (osm_node_t *) cl_qmap_next(&p_node->
347 OSM_LOG_EXIT(sa->p_log);
350 /**********************************************************************
351 Returns the SA status to return to the client.
352 **********************************************************************/
353 static ib_net16_t lr_rcv_get_end_points(IN osm_sa_t * sa,
354 IN const osm_madw_t * p_madw,
355 OUT const osm_port_t ** pp_src_port,
356 OUT const osm_port_t ** pp_dest_port)
358 const ib_link_record_t *p_lr;
359 const ib_sa_mad_t *p_sa_mad;
360 ib_net64_t comp_mask;
361 ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
363 OSM_LOG_ENTER(sa->p_log);
366 Determine what fields are valid and then get a pointer
367 to the source and destination port objects, if possible.
369 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
370 p_lr = (ib_link_record_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
372 comp_mask = p_sa_mad->comp_mask;
374 *pp_dest_port = NULL;
376 if (comp_mask & IB_LR_COMPMASK_FROM_LID) {
377 *pp_src_port = osm_get_port_by_lid(sa->p_subn, p_lr->from_lid);
380 This 'error' is the client's fault (bad lid) so
381 don't enter it as an error in our own log.
382 Return an error response to the client.
384 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
385 "No source port with LID %u\n",
386 cl_ntoh16(p_lr->from_lid));
388 sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
393 if (comp_mask & IB_LR_COMPMASK_TO_LID) {
394 *pp_dest_port = osm_get_port_by_lid(sa->p_subn, p_lr->to_lid);
395 if (!*pp_dest_port) {
397 This 'error' is the client's fault (bad lid) so
398 don't enter it as an error in our own log.
399 Return an error response to the client.
401 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
402 "No dest port with LID %u\n",
403 cl_ntoh16(p_lr->to_lid));
405 sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
411 OSM_LOG_EXIT(sa->p_log);
415 void osm_lr_rcv_process(IN void *context, IN void *data)
417 osm_sa_t *sa = context;
418 osm_madw_t *p_madw = data;
419 const ib_link_record_t *p_lr;
420 const ib_sa_mad_t *p_sa_mad;
421 const osm_port_t *p_src_port;
422 const osm_port_t *p_dest_port;
425 osm_physp_t *p_req_physp;
427 OSM_LOG_ENTER(sa->p_log);
431 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
432 p_lr = ib_sa_mad_get_payload_ptr(p_sa_mad);
434 CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_LINK_RECORD);
436 /* we only support SubnAdmGet and SubnAdmGetTable methods */
437 if (p_sa_mad->method != IB_MAD_METHOD_GET &&
438 p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
439 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1804: "
440 "Unsupported Method (%s) for LinkRecord request\n",
441 ib_get_sa_method_str(p_sa_mad->method));
442 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
446 cl_plock_acquire(sa->p_lock);
448 /* update the requester physical port */
449 p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
450 osm_madw_get_mad_addr_ptr
452 if (p_req_physp == NULL) {
453 cl_plock_release(sa->p_lock);
454 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1805: "
455 "Cannot find requester physical port\n");
459 if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
460 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
461 "Requester port GUID 0x%" PRIx64 "\n",
462 cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
463 osm_dump_link_record_v2(sa->p_log, p_lr, FILE_ID, OSM_LOG_DEBUG);
466 cl_qlist_init(&lr_list);
469 Most SA functions (including this one) are read-only on the
470 subnet object, so we grab the lock non-exclusively.
472 status = lr_rcv_get_end_points(sa, p_madw, &p_src_port, &p_dest_port);
474 if (status == IB_SA_MAD_STATUS_SUCCESS)
475 lr_rcv_get_port_links(sa, p_lr, p_src_port, p_dest_port,
476 p_sa_mad->comp_mask, &lr_list,
479 cl_plock_release(sa->p_lock);
481 osm_sa_respond(sa, p_madw, sizeof(ib_link_record_t), &lr_list);
484 OSM_LOG_EXIT(sa->p_log);