]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/opensm/osm_sa_pkey_record.c
Merge llvm, clang, compiler-rt, libc++, lld, and lldb release_80 branch
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / opensm / osm_sa_pkey_record.c
1 /*
2  * Copyright (c) 2004-2009 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  * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
6  *
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:
12  *
13  *     Redistribution and use in source and binary forms, with or
14  *     without modification, are permitted provided that the following
15  *     conditions are met:
16  *
17  *      - Redistributions of source code must retain the above
18  *        copyright notice, this list of conditions and the following
19  *        disclaimer.
20  *
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.
25  *
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
33  * SOFTWARE.
34  *
35  */
36
37 #if HAVE_CONFIG_H
38 #  include <config.h>
39 #endif                          /* HAVE_CONFIG_H */
40
41 #include <string.h>
42 #include <iba/ib_types.h>
43 #include <complib/cl_qmap.h>
44 #include <complib/cl_passivelock.h>
45 #include <complib/cl_debug.h>
46 #include <complib/cl_qlist.h>
47 #include <opensm/osm_file_ids.h>
48 #define FILE_ID OSM_FILE_SA_PKEY_RECORD_C
49 #include <vendor/osm_vendor_api.h>
50 #include <opensm/osm_port.h>
51 #include <opensm/osm_node.h>
52 #include <opensm/osm_helper.h>
53 #include <opensm/osm_pkey.h>
54 #include <opensm/osm_sa.h>
55
56 #define SA_PKEY_RESP_SIZE SA_ITEM_RESP_SIZE(pkey_rec)
57
58 typedef struct osm_pkey_search_ctxt {
59         const ib_pkey_table_record_t *p_rcvd_rec;
60         ib_net64_t comp_mask;
61         uint16_t block_num;
62         cl_qlist_t *p_list;
63         osm_sa_t *sa;
64         const osm_physp_t *p_req_physp;
65 } osm_pkey_search_ctxt_t;
66
67 static void sa_pkey_create(IN osm_sa_t * sa, IN osm_physp_t * p_physp,
68                            IN osm_pkey_search_ctxt_t * p_ctxt,
69                            IN uint16_t block)
70 {
71         osm_sa_item_t *p_rec_item;
72         uint16_t lid;
73         ib_pkey_table_t *tbl;
74
75         OSM_LOG_ENTER(sa->p_log);
76
77         p_rec_item = malloc(SA_PKEY_RESP_SIZE);
78         if (p_rec_item == NULL) {
79                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4602: "
80                         "rec_item alloc failed\n");
81                 goto Exit;
82         }
83
84         if (p_physp->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH)
85                 lid = p_physp->port_info.base_lid;
86         else
87                 lid = osm_node_get_base_lid(p_physp->p_node, 0);
88
89         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
90                 "New P_Key table for: port 0x%016" PRIx64
91                 ", lid %u, port %u Block:%u\n",
92                 cl_ntoh64(osm_physp_get_port_guid(p_physp)),
93                 cl_ntoh16(lid), osm_physp_get_port_num(p_physp), block);
94
95         memset(p_rec_item, 0, SA_PKEY_RESP_SIZE);
96
97         p_rec_item->resp.pkey_rec.lid = lid;
98         p_rec_item->resp.pkey_rec.block_num = block;
99         p_rec_item->resp.pkey_rec.port_num = osm_physp_get_port_num(p_physp);
100         /* FIXME: There are ninf.PartitionCap or swinf.PartitionEnforcementCap
101            pkey entries so everything in that range is a valid block number
102            even if opensm is not using it. Return 0. However things outside
103            that range should return no entries. Not sure how to figure that
104            here? The range of pkey_tbl can be less than the cap, so
105            this falsely triggers. */
106         tbl = osm_pkey_tbl_block_get(osm_physp_get_pkey_tbl(p_physp), block);
107         if (tbl)
108                 p_rec_item->resp.pkey_rec.pkey_tbl = *tbl;
109
110         cl_qlist_insert_tail(p_ctxt->p_list, &p_rec_item->list_item);
111
112 Exit:
113         OSM_LOG_EXIT(sa->p_log);
114 }
115
116 static void sa_pkey_check_physp(IN osm_sa_t * sa, IN osm_physp_t * p_physp,
117                                 osm_pkey_search_ctxt_t * p_ctxt)
118 {
119         ib_net64_t comp_mask = p_ctxt->comp_mask;
120         uint16_t block, num_blocks;
121
122         OSM_LOG_ENTER(sa->p_log);
123
124         /* we got here with the phys port - all is left is to get the right block */
125         if (comp_mask & IB_PKEY_COMPMASK_BLOCK) {
126                 sa_pkey_create(sa, p_physp, p_ctxt, p_ctxt->block_num);
127         } else {
128                 num_blocks =
129                     osm_pkey_tbl_get_num_blocks(osm_physp_get_pkey_tbl
130                                                 (p_physp));
131                 for (block = 0; block < num_blocks; block++)
132                         sa_pkey_create(sa, p_physp, p_ctxt, block);
133         }
134
135         OSM_LOG_EXIT(sa->p_log);
136 }
137
138 static void sa_pkey_by_comp_mask(IN osm_sa_t * sa, IN const osm_port_t * p_port,
139                                  osm_pkey_search_ctxt_t * p_ctxt)
140 {
141         const ib_pkey_table_record_t *p_rcvd_rec;
142         ib_net64_t comp_mask;
143         osm_physp_t *p_physp;
144         uint8_t port_num;
145         uint8_t num_ports;
146         const osm_physp_t *p_req_physp;
147
148         OSM_LOG_ENTER(sa->p_log);
149
150         p_rcvd_rec = p_ctxt->p_rcvd_rec;
151         comp_mask = p_ctxt->comp_mask;
152         port_num = p_rcvd_rec->port_num;
153         p_req_physp = p_ctxt->p_req_physp;
154
155         /* if this is a switch port we can search all ports
156            otherwise we must be looking on port 0 */
157         if (p_port->p_node->node_info.node_type != IB_NODE_TYPE_SWITCH) {
158                 /* we put it in the comp mask and port num */
159                 port_num = p_port->p_physp->port_num;
160                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
161                         "Using Physical Default Port Number: 0x%X (for End Node)\n",
162                         port_num);
163                 comp_mask |= IB_PKEY_COMPMASK_PORT;
164         }
165
166         if (comp_mask & IB_PKEY_COMPMASK_PORT) {
167                 if (port_num < osm_node_get_num_physp(p_port->p_node)) {
168                         p_physp =
169                             osm_node_get_physp_ptr(p_port->p_node, port_num);
170                         /* Check that the p_physp is valid, and that is shares a pkey
171                            with the p_req_physp. */
172                         if (p_physp &&
173                             osm_physp_share_pkey(sa->p_log, p_req_physp,
174                                                  p_physp, sa->p_subn->opt.allow_both_pkeys))
175                                 sa_pkey_check_physp(sa, p_physp, p_ctxt);
176                 } else {
177                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4603: "
178                                 "Given Physical Port Number: 0x%X is out of range should be < 0x%X\n",
179                                 port_num,
180                                 osm_node_get_num_physp(p_port->p_node));
181                         goto Exit;
182                 }
183         } else {
184                 num_ports = osm_node_get_num_physp(p_port->p_node);
185                 for (port_num = 0; port_num < num_ports; port_num++) {
186                         p_physp =
187                             osm_node_get_physp_ptr(p_port->p_node, port_num);
188                         if (!p_physp)
189                                 continue;
190
191                         /* if the requester and the p_physp don't share a pkey -
192                            continue */
193                         if (!osm_physp_share_pkey
194                             (sa->p_log, p_req_physp, p_physp, sa->p_subn->opt.allow_both_pkeys))
195                                 continue;
196
197                         sa_pkey_check_physp(sa, p_physp, p_ctxt);
198                 }
199         }
200 Exit:
201         OSM_LOG_EXIT(sa->p_log);
202 }
203
204 static void sa_pkey_by_comp_mask_cb(IN cl_map_item_t * p_map_item, IN void *cxt)
205 {
206         const osm_port_t *p_port = (osm_port_t *) p_map_item;
207         osm_pkey_search_ctxt_t *p_ctxt = cxt;
208
209         sa_pkey_by_comp_mask(p_ctxt->sa, p_port, p_ctxt);
210 }
211
212 void osm_pkey_rec_rcv_process(IN void *ctx, IN void *data)
213 {
214         osm_sa_t *sa = ctx;
215         osm_madw_t *p_madw = data;
216         const ib_sa_mad_t *p_rcvd_mad;
217         const ib_pkey_table_record_t *p_rcvd_rec;
218         const osm_port_t *p_port = NULL;
219         cl_qlist_t rec_list;
220         osm_pkey_search_ctxt_t context;
221         ib_net64_t comp_mask;
222         osm_physp_t *p_req_physp;
223
224         CL_ASSERT(sa);
225
226         OSM_LOG_ENTER(sa->p_log);
227
228         CL_ASSERT(p_madw);
229
230         p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw);
231         p_rcvd_rec =
232             (ib_pkey_table_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad);
233         comp_mask = p_rcvd_mad->comp_mask;
234
235         CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_PKEY_TBL_RECORD);
236
237         /* we only support SubnAdmGet and SubnAdmGetTable methods */
238         if (p_rcvd_mad->method != IB_MAD_METHOD_GET &&
239             p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) {
240                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4605: "
241                         "Unsupported Method (%s) for PKeyRecord request\n",
242                         ib_get_sa_method_str(p_rcvd_mad->method));
243                 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
244                 goto Exit;
245         }
246
247         /*
248            p922 - P_KeyTableRecords shall only be provided in response
249            to trusted requests.
250            Check that the requester is a trusted one.
251          */
252         if (p_rcvd_mad->sm_key != sa->p_subn->opt.sa_key) {
253                 /* This is not a trusted requester! */
254                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4608: "
255                         "Ignoring PKeyRecord request from non-trusted requester"
256                         " with SM_Key 0x%016" PRIx64 "\n",
257                         cl_ntoh64(p_rcvd_mad->sm_key));
258                 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
259                 goto Exit;
260         }
261
262         cl_plock_acquire(sa->p_lock);
263
264         /* update the requester physical port */
265         p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn,
266                                                 osm_madw_get_mad_addr_ptr
267                                                 (p_madw));
268         if (p_req_physp == NULL) {
269                 cl_plock_release(sa->p_lock);
270                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4604: "
271                         "Cannot find requester physical port\n");
272                 goto Exit;
273         }
274         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
275                 "Requester port GUID 0x%" PRIx64 "\n",
276                 cl_ntoh64(osm_physp_get_port_guid(p_req_physp)));
277
278         cl_qlist_init(&rec_list);
279
280         context.p_rcvd_rec = p_rcvd_rec;
281         context.p_list = &rec_list;
282         context.comp_mask = p_rcvd_mad->comp_mask;
283         context.sa = sa;
284         context.block_num = cl_ntoh16(p_rcvd_rec->block_num);
285         context.p_req_physp = p_req_physp;
286
287         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
288                 "Got Query Lid:%u(%02X), Block:0x%02X(%02X), Port:0x%02X(%02X)\n",
289                 cl_ntoh16(p_rcvd_rec->lid),
290                 (comp_mask & IB_PKEY_COMPMASK_LID) != 0, p_rcvd_rec->port_num,
291                 (comp_mask & IB_PKEY_COMPMASK_PORT) != 0, context.block_num,
292                 (comp_mask & IB_PKEY_COMPMASK_BLOCK) != 0);
293
294         /*
295            If the user specified a LID, it obviously narrows our
296            work load, since we don't have to search every port
297          */
298         if (comp_mask & IB_PKEY_COMPMASK_LID) {
299                 p_port = osm_get_port_by_lid(sa->p_subn, p_rcvd_rec->lid);
300                 if (!p_port)
301                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 460B: "
302                                 "No port found with LID %u\n",
303                                 cl_ntoh16(p_rcvd_rec->lid));
304                 else
305                         sa_pkey_by_comp_mask(sa, p_port, &context);
306         } else
307                 cl_qmap_apply_func(&sa->p_subn->port_guid_tbl,
308                                    sa_pkey_by_comp_mask_cb, &context);
309
310         cl_plock_release(sa->p_lock);
311
312         osm_sa_respond(sa, p_madw, sizeof(ib_pkey_table_record_t), &rec_list);
313
314 Exit:
315         OSM_LOG_EXIT(sa->p_log);
316 }