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.
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:
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
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.
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
38 * Implementation of inform record functions.
43 #endif /* HAVE_CONFIG_H */
47 #include <arpa/inet.h>
48 #include <complib/cl_debug.h>
49 #include <opensm/osm_helper.h>
50 #include <opensm/osm_inform.h>
51 #include <vendor/osm_vendor_api.h>
52 #include <opensm/osm_pkey.h>
53 #include <opensm/osm_sa.h>
54 #include <sys/socket.h>
56 typedef struct osm_infr_match_ctxt {
57 cl_list_t *p_remove_infr_list;
58 ib_mad_notice_attr_t *p_ntc;
59 } osm_infr_match_ctxt_t;
61 /**********************************************************************
62 **********************************************************************/
63 void osm_infr_delete(IN osm_infr_t * const p_infr)
68 /**********************************************************************
69 **********************************************************************/
70 osm_infr_t *osm_infr_new(IN const osm_infr_t * p_infr_rec)
74 CL_ASSERT(p_infr_rec);
76 p_infr = (osm_infr_t *) malloc(sizeof(osm_infr_t));
78 memcpy(p_infr, p_infr_rec, sizeof(osm_infr_t));
83 /**********************************************************************
84 **********************************************************************/
85 static void dump_all_informs(IN osm_subn_t const *p_subn, IN osm_log_t * p_log)
87 cl_list_item_t *p_list_item;
89 if (!osm_log_is_active(p_log, OSM_LOG_DEBUG))
92 p_list_item = cl_qlist_head(&p_subn->sa_infr_list);
93 while (p_list_item != cl_qlist_end(&p_subn->sa_infr_list)) {
94 osm_dump_inform_info(p_log,
95 &((osm_infr_t *) p_list_item)->
96 inform_record.inform_info, OSM_LOG_DEBUG);
97 p_list_item = cl_qlist_next(p_list_item);
101 /**********************************************************************
102 * Match an infr by the InformInfo and Address vector
103 **********************************************************************/
105 __match_inf_rec(IN const cl_list_item_t * const p_list_item, IN void *context)
107 osm_infr_t *p_infr_rec = (osm_infr_t *) context;
108 osm_infr_t *p_infr = (osm_infr_t *) p_list_item;
109 osm_log_t *p_log = p_infr_rec->sa->p_log;
110 cl_status_t status = CL_NOT_FOUND;
111 ib_gid_t all_zero_gid;
113 OSM_LOG_ENTER(p_log);
115 if (memcmp(&p_infr->report_addr, &p_infr_rec->report_addr,
116 sizeof(p_infr_rec->report_addr))) {
117 OSM_LOG(p_log, OSM_LOG_DEBUG, "Differ by Address\n");
121 memset(&all_zero_gid, 0, sizeof(ib_gid_t));
123 /* if inform_info.gid is not zero, ignore lid range */
124 if (!memcmp(&p_infr_rec->inform_record.inform_info.gid, &all_zero_gid,
125 sizeof(p_infr_rec->inform_record.inform_info.gid))) {
126 if (memcmp(&p_infr->inform_record.inform_info.gid,
127 &p_infr_rec->inform_record.inform_info.gid,
128 sizeof(p_infr->inform_record.inform_info.gid))) {
129 OSM_LOG(p_log, OSM_LOG_DEBUG,
130 "Differ by InformInfo.gid\n");
134 if ((p_infr->inform_record.inform_info.lid_range_begin !=
135 p_infr_rec->inform_record.inform_info.lid_range_begin) ||
136 (p_infr->inform_record.inform_info.lid_range_end !=
137 p_infr_rec->inform_record.inform_info.lid_range_end)) {
138 OSM_LOG(p_log, OSM_LOG_DEBUG,
139 "Differ by InformInfo.LIDRange\n");
144 if (p_infr->inform_record.inform_info.trap_type !=
145 p_infr_rec->inform_record.inform_info.trap_type) {
146 OSM_LOG(p_log, OSM_LOG_DEBUG,
147 "Differ by InformInfo.TrapType\n");
151 if (p_infr->inform_record.inform_info.is_generic !=
152 p_infr_rec->inform_record.inform_info.is_generic) {
153 OSM_LOG(p_log, OSM_LOG_DEBUG,
154 "Differ by InformInfo.IsGeneric\n");
158 if (p_infr->inform_record.inform_info.is_generic) {
159 if (p_infr->inform_record.inform_info.g_or_v.generic.trap_num !=
160 p_infr_rec->inform_record.inform_info.g_or_v.generic.
162 OSM_LOG(p_log, OSM_LOG_DEBUG,
163 "Differ by InformInfo.Generic.TrapNumber\n");
164 else if (p_infr->inform_record.inform_info.g_or_v.generic.
166 p_infr_rec->inform_record.inform_info.g_or_v.generic.
168 OSM_LOG(p_log, OSM_LOG_DEBUG,
169 "Differ by InformInfo.Generic.QPNRespTimeVal\n");
170 else if (p_infr->inform_record.inform_info.g_or_v.generic.
172 p_infr_rec->inform_record.inform_info.g_or_v.generic.
174 OSM_LOG(p_log, OSM_LOG_DEBUG,
175 "Differ by InformInfo.Generic.NodeTypeMSB\n");
176 else if (p_infr->inform_record.inform_info.g_or_v.generic.
178 p_infr_rec->inform_record.inform_info.g_or_v.generic.
180 OSM_LOG(p_log, OSM_LOG_DEBUG,
181 "Differ by InformInfo.Generic.NodeTypeLSB\n");
185 if (p_infr->inform_record.inform_info.g_or_v.vend.dev_id !=
186 p_infr_rec->inform_record.inform_info.g_or_v.vend.dev_id)
187 OSM_LOG(p_log, OSM_LOG_DEBUG,
188 "Differ by InformInfo.Vendor.DeviceID\n");
189 else if (p_infr->inform_record.inform_info.g_or_v.vend.
191 p_infr_rec->inform_record.inform_info.g_or_v.vend.
193 OSM_LOG(p_log, OSM_LOG_DEBUG,
194 "Differ by InformInfo.Vendor.QPNRespTimeVal\n");
195 else if (p_infr->inform_record.inform_info.g_or_v.vend.
197 p_infr_rec->inform_record.inform_info.g_or_v.vend.
199 OSM_LOG(p_log, OSM_LOG_DEBUG,
200 "Differ by InformInfo.Vendor.VendorIdMSB\n");
201 else if (p_infr->inform_record.inform_info.g_or_v.vend.
203 p_infr_rec->inform_record.inform_info.g_or_v.vend.
205 OSM_LOG(p_log, OSM_LOG_DEBUG,
206 "Differ by InformInfo.Vendor.VendorIdLSB\n");
216 /**********************************************************************
217 **********************************************************************/
218 osm_infr_t *osm_infr_get_by_rec(IN osm_subn_t const *p_subn,
219 IN osm_log_t * p_log,
220 IN osm_infr_t * const p_infr_rec)
222 cl_list_item_t *p_list_item;
224 OSM_LOG_ENTER(p_log);
226 dump_all_informs(p_subn, p_log);
228 OSM_LOG(p_log, OSM_LOG_DEBUG, "Looking for Inform Record\n");
229 osm_dump_inform_info(p_log, &(p_infr_rec->inform_record.inform_info),
231 OSM_LOG(p_log, OSM_LOG_DEBUG, "InformInfo list size %d\n",
232 cl_qlist_count(&p_subn->sa_infr_list));
234 p_list_item = cl_qlist_find_from_head(&p_subn->sa_infr_list,
235 __match_inf_rec, p_infr_rec);
237 if (p_list_item == cl_qlist_end(&p_subn->sa_infr_list))
241 return (osm_infr_t *) p_list_item;
244 /**********************************************************************
245 **********************************************************************/
247 osm_infr_insert_to_db(IN osm_subn_t * p_subn,
248 IN osm_log_t * p_log, IN osm_infr_t * p_infr)
250 OSM_LOG_ENTER(p_log);
252 OSM_LOG(p_log, OSM_LOG_DEBUG,
253 "Inserting new InformInfo Record into Database\n");
254 OSM_LOG(p_log, OSM_LOG_DEBUG, "Dump before insertion (size %d)\n",
255 cl_qlist_count(&p_subn->sa_infr_list));
256 dump_all_informs(p_subn, p_log);
259 osm_dump_inform_info(p_log,
260 &(p_infr->inform_record.inform_info),
264 cl_qlist_insert_head(&p_subn->sa_infr_list, &p_infr->list_item);
266 OSM_LOG(p_log, OSM_LOG_DEBUG, "Dump after insertion (size %d)\n",
267 cl_qlist_count(&p_subn->sa_infr_list));
268 dump_all_informs(p_subn, p_log);
272 /**********************************************************************
273 **********************************************************************/
275 osm_infr_remove_from_db(IN osm_subn_t * p_subn,
276 IN osm_log_t * p_log, IN osm_infr_t * p_infr)
278 char gid_str[INET6_ADDRSTRLEN];
279 OSM_LOG_ENTER(p_log);
281 OSM_LOG(p_log, OSM_LOG_DEBUG, "Removing InformInfo Subscribing GID:%s"
282 " Enum:0x%X from Database\n",
283 inet_ntop(AF_INET6, p_infr->inform_record.subscriber_gid.raw,
284 gid_str, sizeof gid_str),
285 p_infr->inform_record.subscriber_enum);
287 osm_dump_inform_info(p_log, &(p_infr->inform_record.inform_info),
290 cl_qlist_remove_item(&p_subn->sa_infr_list, &p_infr->list_item);
292 osm_infr_delete(p_infr);
297 /**********************************************************************
299 * Given a target address to send to and the notice.
300 * We need to send SubnAdmReport
301 **********************************************************************/
302 static ib_api_status_t __osm_send_report(IN osm_infr_t * p_infr_rec, /* the informinfo */
303 IN ib_mad_notice_attr_t * p_ntc /* notice to send */
306 osm_madw_t *p_report_madw;
307 ib_mad_notice_attr_t *p_report_ntc;
309 ib_sa_mad_t *p_sa_mad;
310 static atomic32_t trap_fwd_trans_id = 0x02DAB000;
311 ib_api_status_t status = IB_SUCCESS;
312 osm_log_t *p_log = p_infr_rec->sa->p_log;
314 OSM_LOG_ENTER(p_log);
316 /* HACK: who switches or uses the src and dest GIDs in the grh_info ?? */
318 /* it is better to use LIDs since the GIDs might not be there for SMI traps */
319 OSM_LOG(p_log, OSM_LOG_DEBUG, "Forwarding Notice Event from LID:%u"
320 " to InformInfo LID: %u TID:0x%X\n",
321 cl_ntoh16(p_ntc->issuer_lid),
322 cl_ntoh16(p_infr_rec->report_addr.dest_lid), trap_fwd_trans_id);
324 /* get the MAD to send */
325 p_report_madw = osm_mad_pool_get(p_infr_rec->sa->p_mad_pool,
326 p_infr_rec->h_bind, MAD_BLOCK_SIZE,
327 &(p_infr_rec->report_addr));
329 p_report_madw->resp_expected = TRUE;
331 if (!p_report_madw) {
332 OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0203"
333 "osm_mad_pool_get failed\n");
338 /* advance trap trans id (cant simply ++ on some systems inside ntoh) */
339 p_mad = osm_madw_get_mad_ptr(p_report_madw);
340 ib_mad_init_new(p_mad, IB_MCLASS_SUBN_ADM, 2, IB_MAD_METHOD_REPORT,
341 cl_hton64((uint64_t) cl_atomic_inc(&trap_fwd_trans_id)),
342 IB_MAD_ATTR_NOTICE, 0);
344 p_sa_mad = osm_madw_get_sa_mad_ptr(p_report_madw);
346 p_report_ntc = (ib_mad_notice_attr_t *) & (p_sa_mad->data);
348 /* copy the notice */
349 *p_report_ntc = *p_ntc;
351 /* The TRUE is for: response is expected */
352 osm_sa_send(p_infr_rec->sa, p_report_madw, TRUE);
359 /**********************************************************************
360 * This routine compares a given Notice and a ListItem of InformInfo type.
362 * The Notice.GID should be pre-filled with the trap generator GID
363 **********************************************************************/
365 __match_notice_to_inf_rec(IN cl_list_item_t * const p_list_item,
368 osm_infr_match_ctxt_t *p_infr_match = (osm_infr_match_ctxt_t *) context;
369 ib_mad_notice_attr_t *p_ntc = p_infr_match->p_ntc;
370 cl_list_t *p_infr_to_remove_list = p_infr_match->p_remove_infr_list;
371 osm_infr_t *p_infr_rec = (osm_infr_t *) p_list_item;
372 ib_inform_info_t *p_ii = &(p_infr_rec->inform_record.inform_info);
373 cl_status_t status = CL_NOT_FOUND;
374 osm_log_t *p_log = p_infr_rec->sa->p_log;
375 osm_subn_t *p_subn = p_infr_rec->sa->p_subn;
377 osm_port_t *p_src_port;
378 osm_port_t *p_dest_port;
380 OSM_LOG_ENTER(p_log);
384 * GID IssuerGID if non zero must match the trap
385 * LIDRange IssuerLID apply only if GID=0
386 * IsGeneric IsGeneric is compulsory and must match the trap
387 * Type Type if not 0xFFFF must match
388 * TrapNumber TrapNumber if not 0xFFFF must match
389 * DeviceId DeviceID if not 0xFFFF must match
391 * ProducerType ProducerType match or 0xFFFFFF // EZ: actually my interpretation
392 * VendorID VendorID match or 0xFFFFFF
395 /* GID IssuerGID if non zero must match the trap */
396 if (p_ii->gid.unicast.prefix != 0
397 || p_ii->gid.unicast.interface_id != 0) {
399 if (memcmp(&(p_ii->gid), &(p_ntc->issuer_gid),
401 OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by GID\n");
405 /* LIDRange IssuerLID apply only if GID=0 */
406 /* If lid_range_begin of the informInfo is 0xFFFF - then it should be ignored. */
407 if (p_ii->lid_range_begin != 0xFFFF) {
408 /* a real lid range is given - check it */
409 if ((cl_hton16(p_ii->lid_range_begin) >
410 cl_hton16(p_ntc->issuer_lid))
411 || (cl_hton16(p_ntc->issuer_lid) >
412 cl_hton16(p_ii->lid_range_end))) {
413 OSM_LOG(p_log, OSM_LOG_DEBUG,
414 "Mismatch by LID Range. Needed: %u <= %u <= %u\n",
415 cl_hton16(p_ii->lid_range_begin),
416 cl_hton16(p_ntc->issuer_lid),
417 cl_hton16(p_ii->lid_range_end));
423 /* IsGeneric IsGeneric is compulsory and must match the trap */
424 if ((p_ii->is_generic && !ib_notice_is_generic(p_ntc)) ||
425 (!p_ii->is_generic && ib_notice_is_generic(p_ntc))) {
426 OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Generic/Vendor\n");
430 /* Type Type if not 0xFFFF must match */
431 if ((p_ii->trap_type != 0xFFFF) &&
432 (cl_ntoh16(p_ii->trap_type) != ib_notice_get_type(p_ntc))) {
433 OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Type\n");
437 /* based on generic type */
438 if (p_ii->is_generic) {
439 /* TrapNumber TrapNumber if not 0xFFFF must match */
440 if ((p_ii->g_or_v.generic.trap_num != 0xFFFF) &&
441 (p_ii->g_or_v.generic.trap_num !=
442 p_ntc->g_or_v.generic.trap_num)) {
443 OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Trap Num\n");
447 /* ProducerType ProducerType match or 0xFFFFFF */
448 if ((cl_ntoh32(ib_inform_info_get_prod_type(p_ii)) != 0xFFFFFF)
449 && (ib_inform_info_get_prod_type(p_ii) !=
450 ib_notice_get_prod_type(p_ntc))) {
451 OSM_LOG(p_log, OSM_LOG_DEBUG,
452 "Mismatch by Node Type: II=0x%06X (%s) Trap=0x%06X (%s)\n",
453 cl_ntoh32(ib_inform_info_get_prod_type(p_ii)),
454 ib_get_producer_type_str
455 (ib_inform_info_get_prod_type(p_ii)),
456 cl_ntoh32(ib_notice_get_prod_type(p_ntc)),
457 ib_get_producer_type_str(ib_notice_get_prod_type
462 /* DeviceId DeviceID if not 0xFFFF must match */
463 if ((p_ii->g_or_v.vend.dev_id != 0xFFFF) &&
464 (p_ii->g_or_v.vend.dev_id != p_ntc->g_or_v.vend.dev_id)) {
465 OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Dev Id\n");
469 /* VendorID VendorID match or 0xFFFFFF */
470 if ((ib_inform_info_get_vend_id(p_ii) != CL_HTON32(0xFFFFFF)) &&
471 (ib_inform_info_get_vend_id(p_ii) !=
472 ib_notice_get_vend_id(p_ntc))) {
473 OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Vendor ID\n");
478 /* Check if there is a pkey match. o13-17.1.1 */
479 /* Check if the issuer of the trap is the SM. If it is, then the gid
480 comparison should be done on the trap source (saved as the gid in the
482 If the issuer gid is not the SM - then it is the guid of the trap
484 if ((cl_ntoh64(p_ntc->issuer_gid.unicast.prefix) ==
485 p_subn->opt.subnet_prefix)
486 && (cl_ntoh64(p_ntc->issuer_gid.unicast.interface_id) ==
487 p_subn->sm_port_guid))
488 /* The issuer is the SM then this is trap 64-67 - compare the gid
489 with the gid saved on the data details */
490 source_gid = p_ntc->data_details.ntc_64_67.gid;
492 source_gid = p_ntc->issuer_gid;
495 osm_get_port_by_guid(p_subn, source_gid.unicast.interface_id);
497 OSM_LOG(p_log, OSM_LOG_INFO,
498 "Cannot find source port with GUID:0x%016" PRIx64 "\n",
499 cl_ntoh64(source_gid.unicast.interface_id));
504 cl_ptr_vector_get(&p_subn->port_lid_tbl,
505 cl_ntoh16(p_infr_rec->report_addr.dest_lid));
507 OSM_LOG(p_log, OSM_LOG_INFO,
508 "Cannot find destination port with LID:%u\n",
509 cl_ntoh16(p_infr_rec->report_addr.dest_lid));
513 if (osm_port_share_pkey(p_log, p_src_port, p_dest_port) == FALSE) {
514 OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Pkey\n");
515 /* According to o13-17.1.2 - If this informInfo does not have
516 lid_range_begin of 0xFFFF, then this informInfo request
517 should be removed from database */
518 if (p_ii->lid_range_begin != 0xFFFF) {
519 OSM_LOG(p_log, OSM_LOG_VERBOSE,
520 "Pkey mismatch on lid_range_begin != 0xFFFF. "
521 "Need to remove this informInfo from db\n");
522 /* add the informInfo record to the remove_infr list */
523 cl_list_insert_tail(p_infr_to_remove_list, p_infr_rec);
528 /* send the report to the address provided in the inform record */
529 OSM_LOG(p_log, OSM_LOG_DEBUG, "MATCH! Sending Report...\n");
530 __osm_send_report(p_infr_rec, p_ntc);
537 /**********************************************************************
538 * Once a Trap was received by osm_trap_rcv, or a Trap sourced by
539 * the SM was sent (Traps 64-67), this routine is called with a copy of
541 * Given a notice attribute - compare and see if it matches the InformInfo
542 * element and if it does - call the Report(Notice) for the
543 * target QP registered by the address stored in the InformInfo element
544 **********************************************************************/
546 osm_report_notice(IN osm_log_t * const p_log,
547 IN osm_subn_t * p_subn, IN ib_mad_notice_attr_t * p_ntc)
549 char gid_str[INET6_ADDRSTRLEN];
550 osm_infr_match_ctxt_t context;
551 cl_list_t infr_to_remove_list;
552 osm_infr_t *p_infr_rec;
553 osm_infr_t *p_next_infr_rec;
555 OSM_LOG_ENTER(p_log);
558 * we must make sure we are ready for this...
559 * note that the trap receivers might be initialized before
560 * the osm_infr_init call is performed.
562 if (p_subn->sa_infr_list.state != CL_INITIALIZED) {
563 OSM_LOG(p_log, OSM_LOG_DEBUG,
564 "Ignoring Notice Reports since Inform List is not initialized yet!\n");
568 /* an official Event information log */
569 if (ib_notice_is_generic(p_ntc))
570 OSM_LOG(p_log, OSM_LOG_INFO,
571 "Reporting Generic Notice type:%u num:%u (%s)"
572 " from LID:%u GID:%s\n",
573 ib_notice_get_type(p_ntc),
574 cl_ntoh16(p_ntc->g_or_v.generic.trap_num),
575 ib_get_trap_str(p_ntc->g_or_v.generic.trap_num),
576 cl_ntoh16(p_ntc->issuer_lid),
577 inet_ntop(AF_INET6, p_ntc->issuer_gid.raw, gid_str,
580 OSM_LOG(p_log, OSM_LOG_INFO,
581 "Reporting Vendor Notice type:%u vend:%u dev:%u"
582 " from LID:%u GID:%s\n",
583 ib_notice_get_type(p_ntc),
584 cl_ntoh32(ib_notice_get_vend_id(p_ntc)),
585 cl_ntoh16(p_ntc->g_or_v.vend.dev_id),
586 cl_ntoh16(p_ntc->issuer_lid),
587 inet_ntop(AF_INET6, p_ntc->issuer_gid.raw, gid_str,
590 /* Create a list that will hold all the infr records that should
591 be removed due to violation. o13-17.1.2 */
592 cl_list_construct(&infr_to_remove_list);
593 cl_list_init(&infr_to_remove_list, 5);
594 context.p_remove_infr_list = &infr_to_remove_list;
595 context.p_ntc = p_ntc;
597 /* go over all inform info available at the subnet */
598 /* try match to the given notice and send if match */
599 cl_qlist_apply_func(&(p_subn->sa_infr_list),
600 __match_notice_to_inf_rec, &context);
602 /* If we inserted items into the infr_to_remove_list - we need to
604 p_infr_rec = (osm_infr_t *) cl_list_remove_head(&infr_to_remove_list);
605 while (p_infr_rec != NULL) {
607 (osm_infr_t *) cl_list_remove_head(&infr_to_remove_list);
608 osm_infr_remove_from_db(p_subn, p_log, p_infr_rec);
609 p_infr_rec = p_next_infr_rec;
611 cl_list_destroy(&infr_to_remove_list);