1 /* 2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved. 3 * Copyright (c) 2002-2010 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 /* 38 * Abstract: 39 * Implementation of osm_nr_rcv_t. 40 * This object represents the NodeInfo Receiver object. 41 * This object is part of the opensm family of objects. 42 */ 43 44 #if HAVE_CONFIG_H 45 # include <config.h> 46 #endif /* HAVE_CONFIG_H */ 47 48 #include <string.h> 49 #include <iba/ib_types.h> 50 #include <complib/cl_debug.h> 51 #include <complib/cl_qlist.h> 52 #include <opensm/osm_file_ids.h> 53 #define FILE_ID OSM_FILE_SA_NODE_RECORD_C 54 #include <vendor/osm_vendor_api.h> 55 #include <opensm/osm_node.h> 56 #include <opensm/osm_helper.h> 57 #include <opensm/osm_pkey.h> 58 #include <opensm/osm_sa.h> 59 60 #define SA_NR_RESP_SIZE SA_ITEM_RESP_SIZE(node_rec) 61 62 typedef struct osm_nr_search_ctxt { 63 const ib_node_record_t *p_rcvd_rec; 64 ib_net64_t comp_mask; 65 cl_qlist_t *p_list; 66 osm_sa_t *sa; 67 const osm_physp_t *p_req_physp; 68 } osm_nr_search_ctxt_t; 69 70 static ib_api_status_t nr_rcv_new_nr(osm_sa_t * sa, 71 IN const osm_node_t * p_node, 72 IN cl_qlist_t * p_list, 73 IN ib_net64_t port_guid, IN ib_net16_t lid, 74 IN unsigned int port_num) 75 { 76 osm_sa_item_t *p_rec_item; 77 ib_api_status_t status = IB_SUCCESS; 78 79 OSM_LOG_ENTER(sa->p_log); 80 81 p_rec_item = malloc(SA_NR_RESP_SIZE); 82 if (p_rec_item == NULL) { 83 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1D02: " 84 "rec_item alloc failed\n"); 85 status = IB_INSUFFICIENT_RESOURCES; 86 goto Exit; 87 } 88 89 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 90 "New NodeRecord: node 0x%016" PRIx64 91 ", port 0x%016" PRIx64 ", lid %u\n", 92 cl_ntoh64(osm_node_get_node_guid(p_node)), 93 cl_ntoh64(port_guid), cl_ntoh16(lid)); 94 95 memset(p_rec_item, 0, SA_NR_RESP_SIZE); 96 97 p_rec_item->resp.node_rec.lid = lid; 98 99 p_rec_item->resp.node_rec.node_info = p_node->node_info; 100 p_rec_item->resp.node_rec.node_info.port_guid = port_guid; 101 p_rec_item->resp.node_rec.node_info.port_num_vendor_id = 102 (p_rec_item->resp.node_rec.node_info.port_num_vendor_id & IB_NODE_INFO_VEND_ID_MASK) | 103 ((port_num << IB_NODE_INFO_PORT_NUM_SHIFT) & IB_NODE_INFO_PORT_NUM_MASK); 104 memcpy(&(p_rec_item->resp.node_rec.node_desc), &(p_node->node_desc), 105 IB_NODE_DESCRIPTION_SIZE); 106 cl_qlist_insert_tail(p_list, &p_rec_item->list_item); 107 108 Exit: 109 OSM_LOG_EXIT(sa->p_log); 110 return status; 111 } 112 113 static void nr_rcv_create_nr(IN osm_sa_t * sa, IN osm_node_t * p_node, 114 IN cl_qlist_t * p_list, 115 IN ib_net64_t const match_port_guid, 116 IN ib_net16_t const match_lid, 117 IN unsigned int const match_port_num, 118 IN const osm_physp_t * p_req_physp, 119 IN const ib_net64_t comp_mask) 120 { 121 const osm_physp_t *p_physp; 122 uint8_t port_num; 123 uint8_t num_ports; 124 uint16_t match_lid_ho; 125 ib_net16_t base_lid; 126 ib_net16_t base_lid_ho; 127 ib_net16_t max_lid_ho; 128 uint8_t lmc; 129 ib_net64_t port_guid; 130 131 OSM_LOG_ENTER(sa->p_log); 132 133 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 134 "Looking for NodeRecord with LID: %u GUID: 0x%016" 135 PRIx64 "\n", cl_ntoh16(match_lid), cl_ntoh64(match_port_guid)); 136 137 /* 138 For switches, do not return the NodeInfo record 139 for each port on the switch, just for port 0. 140 */ 141 if (osm_node_get_type(p_node) == IB_NODE_TYPE_SWITCH) 142 num_ports = 1; 143 else 144 num_ports = osm_node_get_num_physp(p_node); 145 146 for (port_num = 0; port_num < num_ports; port_num++) { 147 p_physp = osm_node_get_physp_ptr(p_node, port_num); 148 if (!p_physp) 149 continue; 150 151 /* Check to see if the found p_physp and the requester physp 152 share a pkey. If not - continue */ 153 if (!osm_physp_share_pkey(sa->p_log, p_physp, p_req_physp, 154 sa->p_subn->opt.allow_both_pkeys)) 155 continue; 156 157 port_guid = osm_physp_get_port_guid(p_physp); 158 159 if ((comp_mask & IB_NR_COMPMASK_PORTGUID) 160 && (port_guid != match_port_guid)) 161 continue; 162 163 base_lid = osm_physp_get_base_lid(p_physp); 164 165 if (comp_mask & IB_NR_COMPMASK_LID) { 166 base_lid_ho = cl_ntoh16(base_lid); 167 lmc = osm_physp_get_lmc(p_physp); 168 max_lid_ho = (uint16_t) (base_lid_ho + (1 << lmc) - 1); 169 match_lid_ho = cl_ntoh16(match_lid); 170 171 /* 172 We validate that the lid belongs to this node. 173 */ 174 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 175 "Comparing LID: %u <= %u <= %u\n", 176 base_lid_ho, match_lid_ho, max_lid_ho); 177 178 if (match_lid_ho < base_lid_ho 179 || match_lid_ho > max_lid_ho) 180 continue; 181 } 182 183 if ((comp_mask & IB_NR_COMPMASK_PORTNUM) && 184 (port_num != match_port_num)) 185 continue; 186 187 nr_rcv_new_nr(sa, p_node, p_list, port_guid, base_lid, port_num); 188 } 189 190 OSM_LOG_EXIT(sa->p_log); 191 } 192 193 static void nr_rcv_by_comp_mask(IN cl_map_item_t * p_map_item, IN void *context) 194 { 195 const osm_nr_search_ctxt_t *p_ctxt = context; 196 osm_node_t *p_node = (osm_node_t *) p_map_item; 197 const ib_node_record_t *const p_rcvd_rec = p_ctxt->p_rcvd_rec; 198 const osm_physp_t *const p_req_physp = p_ctxt->p_req_physp; 199 osm_sa_t *sa = p_ctxt->sa; 200 ib_net64_t comp_mask = p_ctxt->comp_mask; 201 ib_net64_t match_port_guid = 0; 202 ib_net16_t match_lid = 0; 203 unsigned int match_port_num = 0; 204 205 OSM_LOG_ENTER(p_ctxt->sa->p_log); 206 207 osm_dump_node_info_v2(p_ctxt->sa->p_log, &p_node->node_info, 208 FILE_ID, OSM_LOG_DEBUG); 209 210 if (comp_mask & IB_NR_COMPMASK_LID) 211 match_lid = p_rcvd_rec->lid; 212 213 if (comp_mask & IB_NR_COMPMASK_NODEGUID) { 214 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 215 "Looking for node 0x%016" PRIx64 216 ", found 0x%016" PRIx64 "\n", 217 cl_ntoh64(p_rcvd_rec->node_info.node_guid), 218 cl_ntoh64(osm_node_get_node_guid(p_node))); 219 220 if (p_node->node_info.node_guid != 221 p_rcvd_rec->node_info.node_guid) 222 goto Exit; 223 } 224 225 if (comp_mask & IB_NR_COMPMASK_PORTGUID) 226 match_port_guid = p_rcvd_rec->node_info.port_guid; 227 228 if ((comp_mask & IB_NR_COMPMASK_SYSIMAGEGUID) && 229 p_node->node_info.sys_guid != p_rcvd_rec->node_info.sys_guid) 230 goto Exit; 231 232 if ((comp_mask & IB_NR_COMPMASK_BASEVERSION) && 233 p_node->node_info.base_version != 234 p_rcvd_rec->node_info.base_version) 235 goto Exit; 236 237 if ((comp_mask & IB_NR_COMPMASK_CLASSVERSION) && 238 p_node->node_info.class_version != 239 p_rcvd_rec->node_info.class_version) 240 goto Exit; 241 242 if ((comp_mask & IB_NR_COMPMASK_NODETYPE) && 243 p_node->node_info.node_type != p_rcvd_rec->node_info.node_type) 244 goto Exit; 245 246 if ((comp_mask & IB_NR_COMPMASK_NUMPORTS) && 247 p_node->node_info.num_ports != p_rcvd_rec->node_info.num_ports) 248 goto Exit; 249 250 if ((comp_mask & IB_NR_COMPMASK_PARTCAP) && 251 p_node->node_info.partition_cap != 252 p_rcvd_rec->node_info.partition_cap) 253 goto Exit; 254 255 if ((comp_mask & IB_NR_COMPMASK_DEVID) && 256 p_node->node_info.device_id != p_rcvd_rec->node_info.device_id) 257 goto Exit; 258 259 if ((comp_mask & IB_NR_COMPMASK_REV) && 260 p_node->node_info.revision != 261 p_rcvd_rec->node_info.revision) 262 goto Exit; 263 264 if (comp_mask & IB_NR_COMPMASK_PORTNUM) 265 match_port_num = ib_node_info_get_local_port_num(&p_rcvd_rec->node_info); 266 267 if ((comp_mask & IB_NR_COMPMASK_VENDID) && 268 ib_node_info_get_vendor_id(&p_node->node_info) != 269 ib_node_info_get_vendor_id(&p_rcvd_rec->node_info)) 270 goto Exit; 271 272 if ((comp_mask & IB_NR_COMPMASK_NODEDESC) && 273 strncmp((char *)&p_node->node_desc, (char *)&p_rcvd_rec->node_desc, 274 sizeof(ib_node_desc_t))) 275 goto Exit; 276 277 nr_rcv_create_nr(sa, p_node, p_ctxt->p_list, match_port_guid, 278 match_lid, match_port_num, p_req_physp, comp_mask); 279 280 Exit: 281 OSM_LOG_EXIT(p_ctxt->sa->p_log); 282 } 283 284 void osm_nr_rcv_process(IN void *ctx, IN void *data) 285 { 286 osm_sa_t *sa = ctx; 287 osm_madw_t *p_madw = data; 288 const ib_sa_mad_t *p_rcvd_mad; 289 const ib_node_record_t *p_rcvd_rec; 290 cl_qlist_t rec_list; 291 osm_nr_search_ctxt_t context; 292 osm_physp_t *p_req_physp; 293 294 CL_ASSERT(sa); 295 296 OSM_LOG_ENTER(sa->p_log); 297 298 CL_ASSERT(p_madw); 299 300 p_rcvd_mad = osm_madw_get_sa_mad_ptr(p_madw); 301 p_rcvd_rec = (ib_node_record_t *) ib_sa_mad_get_payload_ptr(p_rcvd_mad); 302 303 CL_ASSERT(p_rcvd_mad->attr_id == IB_MAD_ATTR_NODE_RECORD); 304 305 /* we only support SubnAdmGet and SubnAdmGetTable methods */ 306 if (p_rcvd_mad->method != IB_MAD_METHOD_GET && 307 p_rcvd_mad->method != IB_MAD_METHOD_GETTABLE) { 308 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1D05: " 309 "Unsupported Method (%s) for NodeRecord request\n", 310 ib_get_sa_method_str(p_rcvd_mad->method)); 311 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR); 312 goto Exit; 313 } 314 315 cl_plock_acquire(sa->p_lock); 316 317 /* update the requester physical port */ 318 p_req_physp = osm_get_physp_by_mad_addr(sa->p_log, sa->p_subn, 319 osm_madw_get_mad_addr_ptr 320 (p_madw)); 321 if (p_req_physp == NULL) { 322 cl_plock_release(sa->p_lock); 323 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1D04: " 324 "Cannot find requester physical port\n"); 325 goto Exit; 326 } 327 328 if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) { 329 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 330 "Requester port GUID 0x%" PRIx64 "\n", 331 cl_ntoh64(osm_physp_get_port_guid(p_req_physp))); 332 osm_dump_node_record_v2(sa->p_log, p_rcvd_rec, FILE_ID, OSM_LOG_DEBUG); 333 } 334 335 cl_qlist_init(&rec_list); 336 337 context.p_rcvd_rec = p_rcvd_rec; 338 context.p_list = &rec_list; 339 context.comp_mask = p_rcvd_mad->comp_mask; 340 context.sa = sa; 341 context.p_req_physp = p_req_physp; 342 343 cl_qmap_apply_func(&sa->p_subn->node_guid_tbl, nr_rcv_by_comp_mask, 344 &context); 345 346 cl_plock_release(sa->p_lock); 347 348 osm_sa_respond(sa, p_madw, sizeof(ib_node_record_t), &rec_list); 349 350 Exit: 351 OSM_LOG_EXIT(sa->p_log); 352 } 353