osm_inform.c revision 321936
1/*
2 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2015 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 * Copyright (c) 2009 HNR Consulting. All rights reserved.
6 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
7 *
8 * This software is available to you under a choice of one of two
9 * licenses.  You may choose to be licensed under the terms of the GNU
10 * General Public License (GPL) Version 2, available from the file
11 * COPYING in the main directory of this source tree, or the
12 * OpenIB.org BSD license below:
13 *
14 *     Redistribution and use in source and binary forms, with or
15 *     without modification, are permitted provided that the following
16 *     conditions are met:
17 *
18 *      - Redistributions of source code must retain the above
19 *        copyright notice, this list of conditions and the following
20 *        disclaimer.
21 *
22 *      - Redistributions in binary form must reproduce the above
23 *        copyright notice, this list of conditions and the following
24 *        disclaimer in the documentation and/or other materials
25 *        provided with the distribution.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34 * SOFTWARE.
35 *
36 */
37
38/*
39 * Abstract:
40 *    Implementation of inform record functions.
41 */
42
43#if HAVE_CONFIG_H
44#  include <config.h>
45#endif				/* HAVE_CONFIG_H */
46
47#include <stdlib.h>
48#include <string.h>
49#include <arpa/inet.h>
50#include <sys/socket.h>
51#include <complib/cl_debug.h>
52#include <opensm/osm_file_ids.h>
53#define FILE_ID OSM_FILE_INFORM_C
54#include <opensm/osm_helper.h>
55#include <opensm/osm_inform.h>
56#include <vendor/osm_vendor_api.h>
57#include <opensm/osm_pkey.h>
58#include <opensm/osm_sa.h>
59#include <opensm/osm_opensm.h>
60
61typedef struct osm_infr_match_ctxt {
62	cl_list_t *p_remove_infr_list;
63	ib_mad_notice_attr_t *p_ntc;
64} osm_infr_match_ctxt_t;
65
66void osm_infr_delete(IN osm_infr_t * p_infr)
67{
68	free(p_infr);
69}
70
71osm_infr_t *osm_infr_new(IN const osm_infr_t * p_infr_rec)
72{
73	osm_infr_t *p_infr;
74
75	CL_ASSERT(p_infr_rec);
76
77	p_infr = (osm_infr_t *) malloc(sizeof(osm_infr_t));
78	if (p_infr)
79		memcpy(p_infr, p_infr_rec, sizeof(osm_infr_t));
80
81	return p_infr;
82}
83
84static void dump_all_informs(IN const osm_subn_t * p_subn, IN osm_log_t * p_log)
85{
86	cl_list_item_t *p_list_item;
87
88	if (!OSM_LOG_IS_ACTIVE_V2(p_log, OSM_LOG_DEBUG))
89		return;
90
91	p_list_item = cl_qlist_head(&p_subn->sa_infr_list);
92	while (p_list_item != cl_qlist_end(&p_subn->sa_infr_list)) {
93		osm_dump_inform_info_v2(p_log,
94				        &((osm_infr_t *) p_list_item)->
95				        inform_record.inform_info, FILE_ID, OSM_LOG_DEBUG);
96		p_list_item = cl_qlist_next(p_list_item);
97	}
98}
99
100/**********************************************************************
101 * Match an infr by the InformInfo and Address vector
102 **********************************************************************/
103static cl_status_t match_inf_rec(IN const cl_list_item_t * p_list_item,
104				 IN void *context)
105{
106	osm_infr_t *p_infr_rec = (osm_infr_t *) context;
107	osm_infr_t *p_infr = (osm_infr_t *) p_list_item;
108	ib_inform_info_t *p_ii_rec = &p_infr_rec->inform_record.inform_info;
109	ib_inform_info_t *p_ii = &p_infr->inform_record.inform_info;
110	osm_log_t *p_log = p_infr_rec->sa->p_log;
111	cl_status_t status = CL_NOT_FOUND;
112
113	OSM_LOG_ENTER(p_log);
114
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");
118		goto Exit;
119	}
120
121	/* if inform_info.gid is not zero, ignore lid range */
122	if (ib_gid_is_notzero(&p_ii_rec->gid)) {
123		if (memcmp(&p_ii->gid, &p_ii_rec->gid, sizeof(p_ii->gid))) {
124			OSM_LOG(p_log, OSM_LOG_DEBUG,
125				"Differ by InformInfo.gid\n");
126			goto Exit;
127		}
128	} else {
129		if ((p_ii->lid_range_begin != p_ii_rec->lid_range_begin) ||
130		    (p_ii->lid_range_end != p_ii_rec->lid_range_end)) {
131			OSM_LOG(p_log, OSM_LOG_DEBUG,
132				"Differ by InformInfo.LIDRange\n");
133			goto Exit;
134		}
135	}
136
137	if (p_ii->trap_type != p_ii_rec->trap_type) {
138		OSM_LOG(p_log, OSM_LOG_DEBUG,
139			"Differ by InformInfo.TrapType\n");
140		goto Exit;
141	}
142
143	if (p_ii->is_generic != p_ii_rec->is_generic) {
144		OSM_LOG(p_log, OSM_LOG_DEBUG,
145			"Differ by InformInfo.IsGeneric\n");
146		goto Exit;
147	}
148
149	if (p_ii->is_generic) {
150		if (p_ii->g_or_v.generic.trap_num !=
151		    p_ii_rec->g_or_v.generic.trap_num)
152			OSM_LOG(p_log, OSM_LOG_DEBUG,
153				"Differ by InformInfo.Generic.TrapNumber\n");
154		else if (p_ii->g_or_v.generic.qpn_resp_time_val !=
155			 p_ii_rec->g_or_v.generic.qpn_resp_time_val)
156			OSM_LOG(p_log, OSM_LOG_DEBUG,
157				"Differ by InformInfo.Generic.QPNRespTimeVal\n");
158		else if (p_ii->g_or_v.generic.node_type_msb !=
159			 p_ii_rec->g_or_v.generic.node_type_msb)
160			OSM_LOG(p_log, OSM_LOG_DEBUG,
161				"Differ by InformInfo.Generic.NodeTypeMSB\n");
162		else if (p_ii->g_or_v.generic.node_type_lsb !=
163			 p_ii_rec->g_or_v.generic.node_type_lsb)
164			OSM_LOG(p_log, OSM_LOG_DEBUG,
165				"Differ by InformInfo.Generic.NodeTypeLSB\n");
166		else
167			status = CL_SUCCESS;
168	} else {
169		if (p_ii->g_or_v.vend.dev_id != p_ii_rec->g_or_v.vend.dev_id)
170			OSM_LOG(p_log, OSM_LOG_DEBUG,
171				"Differ by InformInfo.Vendor.DeviceID\n");
172		else if (p_ii->g_or_v.vend.qpn_resp_time_val !=
173			 p_ii_rec->g_or_v.vend.qpn_resp_time_val)
174			OSM_LOG(p_log, OSM_LOG_DEBUG,
175				"Differ by InformInfo.Vendor.QPNRespTimeVal\n");
176		else if (p_ii->g_or_v.vend.vendor_id_msb !=
177			 p_ii_rec->g_or_v.vend.vendor_id_msb)
178			OSM_LOG(p_log, OSM_LOG_DEBUG,
179				"Differ by InformInfo.Vendor.VendorIdMSB\n");
180		else if (p_ii->g_or_v.vend.vendor_id_lsb !=
181			 p_ii_rec->g_or_v.vend.vendor_id_lsb)
182			OSM_LOG(p_log, OSM_LOG_DEBUG,
183				"Differ by InformInfo.Vendor.VendorIdLSB\n");
184		else
185			status = CL_SUCCESS;
186	}
187
188Exit:
189	OSM_LOG_EXIT(p_log);
190	return status;
191}
192
193osm_infr_t *osm_infr_get_by_rec(IN osm_subn_t const *p_subn,
194				IN osm_log_t * p_log,
195				IN osm_infr_t * p_infr_rec)
196{
197	cl_list_item_t *p_list_item;
198
199	OSM_LOG_ENTER(p_log);
200
201	dump_all_informs(p_subn, p_log);
202
203	OSM_LOG(p_log, OSM_LOG_DEBUG, "Looking for Inform Record\n");
204	osm_dump_inform_info_v2(p_log, &(p_infr_rec->inform_record.inform_info),
205			        FILE_ID, OSM_LOG_DEBUG);
206	OSM_LOG(p_log, OSM_LOG_DEBUG, "InformInfo list size %d\n",
207		cl_qlist_count(&p_subn->sa_infr_list));
208
209	p_list_item = cl_qlist_find_from_head(&p_subn->sa_infr_list,
210					      match_inf_rec, p_infr_rec);
211
212	if (p_list_item == cl_qlist_end(&p_subn->sa_infr_list))
213		p_list_item = NULL;
214
215	OSM_LOG_EXIT(p_log);
216	return (osm_infr_t *) p_list_item;
217}
218
219void osm_infr_insert_to_db(IN osm_subn_t * p_subn, IN osm_log_t * p_log,
220			   IN osm_infr_t * p_infr)
221{
222	OSM_LOG_ENTER(p_log);
223
224	OSM_LOG(p_log, OSM_LOG_DEBUG,
225		"Inserting new InformInfo Record into Database\n");
226	OSM_LOG(p_log, OSM_LOG_DEBUG, "Dump before insertion (size %d)\n",
227		cl_qlist_count(&p_subn->sa_infr_list));
228	dump_all_informs(p_subn, p_log);
229
230#if 0
231	osm_dump_inform_info_v2(p_log,
232			        &(p_infr->inform_record.inform_info),
233			        FILE_ID, OSM_LOG_DEBUG);
234#endif
235
236	cl_qlist_insert_head(&p_subn->sa_infr_list, &p_infr->list_item);
237	p_subn->p_osm->sa.dirty = TRUE;
238
239	OSM_LOG(p_log, OSM_LOG_DEBUG, "Dump after insertion (size %d)\n",
240		cl_qlist_count(&p_subn->sa_infr_list));
241	dump_all_informs(p_subn, p_log);
242	OSM_LOG_EXIT(p_log);
243}
244
245void osm_infr_remove_from_db(IN osm_subn_t * p_subn, IN osm_log_t * p_log,
246			     IN osm_infr_t * p_infr)
247{
248	char gid_str[INET6_ADDRSTRLEN];
249	OSM_LOG_ENTER(p_log);
250
251	OSM_LOG(p_log, OSM_LOG_DEBUG, "Removing InformInfo Subscribing GID:%s"
252		" Enum:0x%X from Database\n",
253		inet_ntop(AF_INET6, p_infr->inform_record.subscriber_gid.raw,
254			  gid_str, sizeof gid_str),
255		p_infr->inform_record.subscriber_enum);
256
257	osm_dump_inform_info_v2(p_log, &(p_infr->inform_record.inform_info),
258			        FILE_ID, OSM_LOG_DEBUG);
259
260	cl_qlist_remove_item(&p_subn->sa_infr_list, &p_infr->list_item);
261	p_subn->p_osm->sa.dirty = TRUE;
262
263	osm_infr_delete(p_infr);
264
265	OSM_LOG_EXIT(p_log);
266}
267
268ib_api_status_t osm_infr_remove_subscriptions(IN osm_subn_t * p_subn,
269					      IN osm_log_t * p_log,
270					      IN ib_net64_t port_guid)
271{
272	cl_list_item_t *p_list_item;
273	osm_infr_t *p_infr;
274	ib_api_status_t status = CL_NOT_FOUND;
275
276	OSM_LOG_ENTER(p_log);
277
278	/* go over all inform info available at the subnet */
279	/* match to the given GID and delete subscriptions if match */
280	p_list_item = cl_qlist_head(&p_subn->sa_infr_list);
281	while (p_list_item != cl_qlist_end(&p_subn->sa_infr_list)) {
282
283		p_infr = (osm_infr_t *)p_list_item;
284		p_list_item = cl_qlist_next(p_list_item);
285
286		if (port_guid != p_infr->inform_record.subscriber_gid.unicast.interface_id)
287			continue;
288
289		/* Remove this event subscription */
290		osm_infr_remove_from_db(p_subn, p_log, p_infr);
291
292		status = CL_SUCCESS;
293	}
294
295	OSM_LOG_EXIT(p_log);
296	return (status);
297}
298
299/**********************************************************************
300 * Send a report:
301 * Given a target address to send to and the notice.
302 * We need to send SubnAdmReport
303 **********************************************************************/
304static ib_api_status_t send_report(IN osm_infr_t * p_infr_rec,	/* the informinfo */
305				   IN ib_mad_notice_attr_t * p_ntc	/* notice to send */
306    )
307{
308	osm_madw_t *p_report_madw;
309	ib_mad_notice_attr_t *p_report_ntc;
310	ib_mad_t *p_mad;
311	ib_sa_mad_t *p_sa_mad;
312	static atomic32_t trap_fwd_trans_id = 0x02DAB000;
313	ib_api_status_t status = IB_SUCCESS;
314	osm_log_t *p_log = p_infr_rec->sa->p_log;
315	ib_net64_t tid;
316
317	OSM_LOG_ENTER(p_log);
318
319	/* HACK: who switches or uses the src and dest GIDs in the grh_info ?? */
320
321	/* it is better to use LIDs since the GIDs might not be there for SMI traps */
322	OSM_LOG(p_log, OSM_LOG_DEBUG, "Forwarding Notice Event from LID %u"
323		" to InformInfo LID %u GUID 0x%" PRIx64 ", TID 0x%X\n",
324		cl_ntoh16(p_ntc->issuer_lid),
325		cl_ntoh16(p_infr_rec->report_addr.dest_lid),
326		cl_ntoh64(p_infr_rec->inform_record.subscriber_gid.unicast.interface_id),
327		trap_fwd_trans_id);
328
329	/* get the MAD to send */
330	p_report_madw = osm_mad_pool_get(p_infr_rec->sa->p_mad_pool,
331					 p_infr_rec->h_bind, MAD_BLOCK_SIZE,
332					 &(p_infr_rec->report_addr));
333
334	if (!p_report_madw) {
335		OSM_LOG(p_log, OSM_LOG_ERROR, "ERR 0203: "
336			"Cannot send report to LID %u, osm_mad_pool_get failed\n",
337			cl_ntoh16(p_infr_rec->report_addr.dest_lid));
338		status = IB_ERROR;
339		goto Exit;
340	}
341
342	p_report_madw->resp_expected = TRUE;
343
344	/* advance trap trans id (cant simply ++ on some systems inside ntoh) */
345	tid = cl_hton64((uint64_t) cl_atomic_inc(&trap_fwd_trans_id) &
346			(uint64_t) (0xFFFFFFFF));
347	if (trap_fwd_trans_id == 0)
348		tid = cl_hton64((uint64_t) cl_atomic_inc(&trap_fwd_trans_id) &
349				(uint64_t) (0xFFFFFFFF));
350	p_mad = osm_madw_get_mad_ptr(p_report_madw);
351	ib_mad_init_new(p_mad, IB_MCLASS_SUBN_ADM, 2, IB_MAD_METHOD_REPORT,
352			tid, IB_MAD_ATTR_NOTICE, 0);
353
354	p_sa_mad = osm_madw_get_sa_mad_ptr(p_report_madw);
355
356	p_report_ntc = (ib_mad_notice_attr_t *) & (p_sa_mad->data);
357
358	/* copy the notice */
359	*p_report_ntc = *p_ntc;
360
361	/* The TRUE is for: response is expected */
362	osm_sa_send(p_infr_rec->sa, p_report_madw, TRUE);
363
364Exit:
365	OSM_LOG_EXIT(p_log);
366	return status;
367}
368
369static int is_access_permitted(osm_infr_t *p_infr_rec,
370			       osm_infr_match_ctxt_t *p_infr_match )
371{
372	cl_list_t *p_infr_to_remove_list = p_infr_match->p_remove_infr_list;
373	ib_inform_info_t *p_ii = &(p_infr_rec->inform_record.inform_info);
374	ib_mad_notice_attr_t *p_ntc = p_infr_match->p_ntc;
375	uint16_t trap_num = cl_ntoh16(p_ntc->g_or_v.generic.trap_num);
376	osm_subn_t *p_subn = p_infr_rec->sa->p_subn;
377	osm_log_t *p_log = p_infr_rec->sa->p_log;
378	osm_mgrp_t *p_mgrp;
379	ib_gid_t source_gid;
380	osm_port_t *p_src_port;
381	osm_port_t *p_dest_port;
382
383	/* In case of SM_GID_IN_SERVICE_TRAP(64) or SM_GID_OUT_OF_SERVICE_TRAP(65) traps
384	   the source gid comparison should be done on the trap source (saved
385	   as the gid in the data details field).
386	   For traps SM_MGID_CREATED_TRAP(66) or SM_MGID_DESTROYED_TRAP(67)
387	   the data details gid is the MGID.
388	   We need to check whether the subscriber has a compatible
389	   pkey with MC group.
390	   In all other cases the issuer gid is the trap source.
391	*/
392	if (trap_num >= SM_GID_IN_SERVICE_TRAP &&
393	    trap_num <= SM_MGID_DESTROYED_TRAP)
394		/* The issuer of these traps is the SM so source_gid
395		   is the gid saved on the data details */
396		source_gid = p_ntc->data_details.ntc_64_67.gid;
397	else
398		source_gid = p_ntc->issuer_gid;
399
400	p_dest_port = osm_get_port_by_lid(p_subn,
401					  p_infr_rec->report_addr.dest_lid);
402	if (!p_dest_port) {
403		OSM_LOG(p_log, OSM_LOG_INFO,
404			"Cannot find destination port with LID:%u\n",
405			cl_ntoh16(p_infr_rec->report_addr.dest_lid));
406		goto Exit;
407	}
408
409	/* Check if there is a pkey match. o13-17.1.1 */
410	switch (trap_num) {
411		case SM_MGID_CREATED_TRAP:
412		case SM_MGID_DESTROYED_TRAP:
413			p_mgrp = osm_get_mgrp_by_mgid(p_subn, &source_gid);
414			if (!p_mgrp) {
415				char gid_str[INET6_ADDRSTRLEN];
416				OSM_LOG(p_log, OSM_LOG_INFO,
417					"Cannot find MGID %s\n",
418					inet_ntop(AF_INET6, source_gid.raw, gid_str, sizeof gid_str));
419				goto Exit;
420			}
421
422			if (!osm_physp_has_pkey(p_log,
423						p_mgrp->mcmember_rec.pkey,
424						p_dest_port->p_physp)) {
425				char gid_str[INET6_ADDRSTRLEN];
426				OSM_LOG(p_log, OSM_LOG_INFO,
427					"MGID %s and port GUID:0x%016" PRIx64 " do not share same pkey\n",
428					inet_ntop(AF_INET6, source_gid.raw, gid_str, sizeof gid_str),
429					cl_ntoh64(p_dest_port->guid));
430				goto Exit;
431			}
432			break;
433
434		default:
435			p_src_port =
436			    osm_get_port_by_guid(p_subn, source_gid.unicast.interface_id);
437			if (!p_src_port) {
438				OSM_LOG(p_log, OSM_LOG_INFO,
439					"Cannot find source port with GUID:0x%016" PRIx64 "\n",
440					cl_ntoh64(source_gid.unicast.interface_id));
441				goto Exit;
442			}
443
444
445			if (osm_port_share_pkey(p_log, p_src_port, p_dest_port,
446						p_subn->opt.allow_both_pkeys) == FALSE) {
447				OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Pkey\n");
448				/* According to o13-17.1.2 - If this informInfo
449				   does not have lid_range_begin of 0xFFFF,
450				   then this informInfo request should be
451				   removed from database */
452				if (p_ii->lid_range_begin != 0xFFFF) {
453					OSM_LOG(p_log, OSM_LOG_VERBOSE,
454						"Pkey mismatch on lid_range_begin != 0xFFFF. "
455						"Need to remove this informInfo from db\n");
456					/* add the informInfo record to the remove_infr list */
457					cl_list_insert_tail(p_infr_to_remove_list, p_infr_rec);
458				}
459				goto Exit;
460			}
461			break;
462	}
463
464	return 1;
465Exit:
466	return 0;
467}
468
469
470/**********************************************************************
471 * This routine compares a given Notice and a ListItem of InformInfo type.
472 * PREREQUISITE:
473 * The Notice.GID should be pre-filled with the trap generator GID
474 **********************************************************************/
475static void match_notice_to_inf_rec(IN cl_list_item_t * p_list_item,
476				    IN void *context)
477{
478	osm_infr_match_ctxt_t *p_infr_match = (osm_infr_match_ctxt_t *) context;
479	ib_mad_notice_attr_t *p_ntc = p_infr_match->p_ntc;
480	osm_infr_t *p_infr_rec = (osm_infr_t *) p_list_item;
481	ib_inform_info_t *p_ii = &(p_infr_rec->inform_record.inform_info);
482	osm_log_t *p_log = p_infr_rec->sa->p_log;
483
484	OSM_LOG_ENTER(p_log);
485
486	/* matching rules
487	 * InformInfo   Notice
488	 * GID          IssuerGID    if non zero must match the trap
489	 * LIDRange     IssuerLID    apply only if GID=0
490	 * IsGeneric    IsGeneric    is compulsory and must match the trap
491	 * Type         Type         if not 0xFFFF must match
492	 * TrapNumber   TrapNumber   if not 0xFFFF must match
493	 * DeviceId     DeviceID     if not 0xFFFF must match
494	 * QPN dont care
495	 * ProducerType ProducerType match or 0xFFFFFF // EZ: actually my interpretation
496	 * VendorID     VendorID     match or 0xFFFFFF
497	 */
498
499	/* GID          IssuerGID    if non zero must match the trap  */
500	if (p_ii->gid.unicast.prefix != 0
501	    || p_ii->gid.unicast.interface_id != 0) {
502		/* match by GID */
503		if (memcmp(&(p_ii->gid), &(p_ntc->issuer_gid),
504			   sizeof(ib_gid_t))) {
505			OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by GID\n");
506			goto Exit;
507		}
508	} else {
509		/* LIDRange     IssuerLID    apply only if GID=0 */
510		/* If lid_range_begin of the informInfo is 0xFFFF - then it should be ignored. */
511		if (p_ii->lid_range_begin != 0xFFFF) {
512			/* a real lid range is given - check it */
513			if ((cl_hton16(p_ii->lid_range_begin) >
514			     cl_hton16(p_ntc->issuer_lid))
515			    || (cl_hton16(p_ntc->issuer_lid) >
516				cl_hton16(p_ii->lid_range_end))) {
517				OSM_LOG(p_log, OSM_LOG_DEBUG,
518					"Mismatch by LID Range. Needed: %u <= %u <= %u\n",
519					cl_hton16(p_ii->lid_range_begin),
520					cl_hton16(p_ntc->issuer_lid),
521					cl_hton16(p_ii->lid_range_end));
522				goto Exit;
523			}
524		}
525	}
526
527	/* IsGeneric    IsGeneric    is compulsory and must match the trap  */
528	if ((p_ii->is_generic && !ib_notice_is_generic(p_ntc)) ||
529	    (!p_ii->is_generic && ib_notice_is_generic(p_ntc))) {
530		OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Generic/Vendor\n");
531		goto Exit;
532	}
533
534	/* Type         Type         if not 0xFFFF must match */
535	if ((p_ii->trap_type != 0xFFFF) &&
536	    (cl_ntoh16(p_ii->trap_type) != ib_notice_get_type(p_ntc))) {
537		OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Type\n");
538		goto Exit;
539	}
540
541	/* based on generic type */
542	if (p_ii->is_generic) {
543		/* TrapNumber   TrapNumber   if not 0xFFFF must match */
544		if ((p_ii->g_or_v.generic.trap_num != 0xFFFF) &&
545		    (p_ii->g_or_v.generic.trap_num !=
546		     p_ntc->g_or_v.generic.trap_num)) {
547			OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Trap Num\n");
548			goto Exit;
549		}
550
551		/* ProducerType ProducerType match or 0xFFFFFF  */
552		if ((cl_ntoh32(ib_inform_info_get_prod_type(p_ii)) != 0xFFFFFF)
553		    && (ib_inform_info_get_prod_type(p_ii) !=
554			ib_notice_get_prod_type(p_ntc))) {
555			OSM_LOG(p_log, OSM_LOG_DEBUG,
556				"Mismatch by Node Type: II=0x%06X (%s) Trap=0x%06X (%s)\n",
557				cl_ntoh32(ib_inform_info_get_prod_type(p_ii)),
558				ib_get_producer_type_str
559				(ib_inform_info_get_prod_type(p_ii)),
560				cl_ntoh32(ib_notice_get_prod_type(p_ntc)),
561				ib_get_producer_type_str(ib_notice_get_prod_type
562							 (p_ntc)));
563			goto Exit;
564		}
565	} else {
566		/* DeviceId     DeviceID     if not 0xFFFF must match */
567		if ((p_ii->g_or_v.vend.dev_id != 0xFFFF) &&
568		    (p_ii->g_or_v.vend.dev_id != p_ntc->g_or_v.vend.dev_id)) {
569			OSM_LOG(p_log, OSM_LOG_DEBUG, "Mismatch by Dev Id\n");
570			goto Exit;
571		}
572
573		/* VendorID     VendorID     match or 0xFFFFFF  */
574		if ((ib_inform_info_get_vend_id(p_ii) != CL_HTON32(0xFFFFFF)) &&
575		    (ib_inform_info_get_vend_id(p_ii) !=
576		     ib_notice_get_vend_id(p_ntc))) {
577			OSM_LOG(p_log, OSM_LOG_DEBUG,
578				"Mismatch by Vendor ID\n");
579			goto Exit;
580		}
581	}
582
583	if (!is_access_permitted(p_infr_rec, p_infr_match))
584		goto Exit;
585
586	/* send the report to the address provided in the inform record */
587	OSM_LOG(p_log, OSM_LOG_DEBUG, "MATCH! Sending Report...\n");
588	send_report(p_infr_rec, p_ntc);
589
590Exit:
591	OSM_LOG_EXIT(p_log);
592}
593
594/**********************************************************************
595 * Once a Trap was received by osm_trap_rcv, or a Trap sourced by
596 * the SM was sent (Traps 64-67), this routine is called with a copy of
597 * the notice data.
598 * Given a notice attribute - compare and see if it matches the InformInfo
599 * element and if it does - call the Report(Notice) for the
600 * target QP registered by the address stored in the InformInfo element
601 **********************************************************************/
602static void log_notice(osm_log_t * log, osm_log_level_t level,
603		       ib_mad_notice_attr_t * ntc)
604{
605	char gid_str[INET6_ADDRSTRLEN], gid_str2[INET6_ADDRSTRLEN];
606	ib_gid_t *gid;
607	ib_gid_t *gid1, *gid2;
608
609	/* an official Event information log */
610	if (ib_notice_is_generic(ntc)) {
611		if ((ntc->g_or_v.generic.trap_num == CL_HTON16(SM_GID_IN_SERVICE_TRAP)) ||
612		    (ntc->g_or_v.generic.trap_num == CL_HTON16(SM_GID_OUT_OF_SERVICE_TRAP)) ||
613		    (ntc->g_or_v.generic.trap_num == CL_HTON16(SM_MGID_CREATED_TRAP)) ||
614		    (ntc->g_or_v.generic.trap_num == CL_HTON16(SM_MGID_DESTROYED_TRAP)))
615			gid = &ntc->data_details.ntc_64_67.gid;
616		else
617			gid = &ntc->issuer_gid;
618
619		switch (cl_ntoh16(ntc->g_or_v.generic.trap_num)) {
620		case SM_GID_IN_SERVICE_TRAP:
621		case SM_GID_OUT_OF_SERVICE_TRAP:
622			OSM_LOG(log, level,
623				"Reporting Informational Notice \"%s\", GID:%s\n",
624				ib_get_trap_str(ntc->g_or_v.generic.trap_num),
625				inet_ntop(AF_INET6, gid->raw, gid_str, sizeof gid_str));
626			break;
627		case SM_MGID_CREATED_TRAP:
628		case SM_MGID_DESTROYED_TRAP:
629			OSM_LOG(log, level,
630				"Reporting Informational Notice \"%s\", MGID:%s\n",
631				ib_get_trap_str(ntc->g_or_v.generic.trap_num),
632				inet_ntop(AF_INET6, gid->raw, gid_str, sizeof gid_str));
633			break;
634		case SM_UNPATH_TRAP:
635		case SM_REPATH_TRAP:
636			/* TODO: Fill in details once SM starts to use these traps */
637			OSM_LOG(log, level,
638				"Reporting Informational Notice \"%s\"n",
639				ib_get_trap_str(ntc->g_or_v.generic.trap_num));
640			break;
641		case SM_LINK_STATE_CHANGED_TRAP:
642			OSM_LOG(log, level,
643				"Reporting Urgent Notice \"%s\" from switch LID %u, "
644				"GUID 0x%016" PRIx64 "\n",
645				ib_get_trap_str(ntc->g_or_v.generic.trap_num),
646				cl_ntoh16(ntc->issuer_lid),
647				cl_ntoh64(gid->unicast.interface_id));
648			break;
649		case SM_LINK_INTEGRITY_THRESHOLD_TRAP:
650		case SM_BUFFER_OVERRUN_THRESHOLD_TRAP:
651		case SM_WATCHDOG_TIMER_EXPIRED_TRAP:
652			OSM_LOG(log, level,
653				"Reporting Urgent Notice \"%s\" from LID %u, "
654				"GUID 0x%016" PRIx64 ", port %u\n",
655				ib_get_trap_str(ntc->g_or_v.generic.trap_num),
656				cl_ntoh16(ntc->issuer_lid),
657				cl_ntoh64(gid->unicast.interface_id),
658				ntc->data_details.ntc_129_131.port_num);
659			break;
660		case SM_LOCAL_CHANGES_TRAP:
661			if (ntc->data_details.ntc_144.local_changes == 1)
662				OSM_LOG(log, level,
663					"Reporting Informational Notice \"%s\" from LID %u, "
664					"GUID 0x%016" PRIx64 ", ChangeFlags 0x%04x, "
665					"CapabilityMask2 0x%04x\n",
666					ib_get_trap_str(ntc->g_or_v.generic.trap_num),
667					cl_ntoh16(ntc->issuer_lid),
668					cl_ntoh64(gid->unicast.interface_id),
669					cl_ntoh16(ntc->data_details.ntc_144.change_flgs),
670					cl_ntoh16(ntc->data_details.ntc_144.cap_mask2));
671			else
672				OSM_LOG(log, level,
673					"Reporting Informational Notice \"%s\" from LID %u, "
674					"GUID 0x%016" PRIx64 ", new CapabilityMask 0x%08x\n",
675					ib_get_trap_str(ntc->g_or_v.generic.trap_num),
676					cl_ntoh16(ntc->issuer_lid),
677					cl_ntoh64(gid->unicast.interface_id),
678					cl_ntoh32(ntc->data_details.ntc_144.new_cap_mask));
679			break;
680		case SM_SYS_IMG_GUID_CHANGED_TRAP:
681			OSM_LOG(log, level,
682				"Reporting Informational Notice \"%s\" from LID %u, "
683				"GUID 0x%016" PRIx64 ", new SysImageGUID 0x%016" PRIx64 "\n",
684				ib_get_trap_str(ntc->g_or_v.generic.trap_num),
685				cl_ntoh16(ntc->issuer_lid),
686				cl_ntoh64(gid->unicast.interface_id),
687				cl_ntoh64(ntc->data_details.ntc_145.new_sys_guid));
688			break;
689		case SM_BAD_MKEY_TRAP:
690			OSM_LOG(log, level,
691				"Reporting Security Notice \"%s\" from LID %u, "
692				"GUID 0x%016" PRIx64 ", Method 0x%x, Attribute 0x%x, "
693				"AttrMod 0x%x, M_Key 0x%016" PRIx64 "\n",
694				ib_get_trap_str(ntc->g_or_v.generic.trap_num),
695				cl_ntoh16(ntc->issuer_lid),
696				cl_ntoh64(gid->unicast.interface_id),
697				ntc->data_details.ntc_256.method,
698				cl_ntoh16(ntc->data_details.ntc_256.attr_id),
699				cl_ntoh32(ntc->data_details.ntc_256.attr_mod),
700				cl_ntoh64(ntc->data_details.ntc_256.mkey));
701			break;
702		case SM_BAD_PKEY_TRAP:
703		case SM_BAD_QKEY_TRAP:
704			gid1 = &ntc->data_details.ntc_257_258.gid1;
705			gid2 = &ntc->data_details.ntc_257_258.gid2;
706			OSM_LOG(log, level,
707				"Reporting Security Notice \"%s\" from LID %u, "
708				"GUID 0x%016" PRIx64 " : LID1 %u, LID2 %u, %s 0x%x, "
709				"SL %d, QP1 0x%x, QP2 0x%x, GID1 %s, GID2 %s\n",
710				ib_get_trap_str(ntc->g_or_v.generic.trap_num),
711				cl_ntoh16(ntc->issuer_lid),
712				cl_ntoh64(gid->unicast.interface_id),
713				cl_ntoh16(ntc->data_details.ntc_257_258.lid1),
714				cl_ntoh16(ntc->data_details.ntc_257_258.lid2),
715				cl_ntoh16(ntc->g_or_v.generic.trap_num) == SM_BAD_QKEY_TRAP ?
716					"Q_Key" : "P_Key",
717				cl_ntoh32(ntc->data_details.ntc_257_258.key),
718				cl_ntoh32(ntc->data_details.ntc_257_258.qp1) >> 28,
719				cl_ntoh32(ntc->data_details.ntc_257_258.qp1) & 0xffffff,
720				cl_ntoh32(ntc->data_details.ntc_257_258.qp2) & 0xffffff,
721				inet_ntop(AF_INET6, gid1->raw, gid_str, sizeof gid_str),
722				inet_ntop(AF_INET6, gid2->raw, gid_str2, sizeof gid_str2));
723			break;
724		case SM_BAD_SWITCH_PKEY_TRAP:
725			gid1 = &ntc->data_details.ntc_259.gid1;
726			gid2 = &ntc->data_details.ntc_259.gid2;
727			OSM_LOG(log, level,
728				"Reporting Security Notice \"%s\" from switch LID %u, "
729				"GUID 0x%016" PRIx64 " port %d : data_valid 0x%04x, "
730				"LID1 %u, LID2 %u, PKey 0x%04x, "
731				"SL %d, QP1 0x%x, QP2 0x%x, GID1 %s, GID2 %s\n",
732				ib_get_trap_str(ntc->g_or_v.generic.trap_num),
733				cl_ntoh16(ntc->issuer_lid),
734				cl_ntoh64(gid->unicast.interface_id),
735				ntc->data_details.ntc_259.port_no,
736				cl_ntoh16(ntc->data_details.ntc_259.data_valid),
737				cl_ntoh16(ntc->data_details.ntc_259.lid1),
738				cl_ntoh16(ntc->data_details.ntc_259.lid2),
739				cl_ntoh16(ntc->data_details.ntc_257_258.key),
740				cl_ntoh32(ntc->data_details.ntc_259.sl_qp1) >> 28,
741				cl_ntoh32(ntc->data_details.ntc_259.sl_qp1) & 0xffffff,
742				cl_ntoh32(ntc->data_details.ntc_259.qp2),
743				inet_ntop(AF_INET6, gid1->raw, gid_str, sizeof gid_str),
744				inet_ntop(AF_INET6, gid2->raw, gid_str2, sizeof gid_str2));
745			break;
746		default:
747			OSM_LOG(log, level,
748				"Reporting Generic Notice type:%u num:%u (%s)"
749				" from LID:%u GID:%s\n",
750				ib_notice_get_type(ntc),
751				cl_ntoh16(ntc->g_or_v.generic.trap_num),
752				ib_get_trap_str(ntc->g_or_v.generic.trap_num),
753				cl_ntoh16(ntc->issuer_lid),
754				inet_ntop(AF_INET6, gid->raw, gid_str, sizeof gid_str));
755			break;
756		}
757	} else
758		OSM_LOG(log, level,
759			"Reporting Vendor Notice type:%u vend:%u dev:%u"
760			" from LID:%u GID:%s\n",
761			ib_notice_get_type(ntc),
762			cl_ntoh32(ib_notice_get_vend_id(ntc)),
763			cl_ntoh16(ntc->g_or_v.vend.dev_id),
764			cl_ntoh16(ntc->issuer_lid),
765			inet_ntop(AF_INET6, ntc->issuer_gid.raw, gid_str,
766				  sizeof gid_str));
767}
768
769ib_api_status_t osm_report_notice(IN osm_log_t * p_log, IN osm_subn_t * p_subn,
770				  IN ib_mad_notice_attr_t * p_ntc)
771{
772	osm_infr_match_ctxt_t context;
773	cl_list_t infr_to_remove_list;
774	osm_infr_t *p_infr_rec;
775	osm_infr_t *p_next_infr_rec;
776
777	OSM_LOG_ENTER(p_log);
778
779	/*
780	 * we must make sure we are ready for this...
781	 * note that the trap receivers might be initialized before
782	 * the osm_infr_init call is performed.
783	 */
784	if (p_subn->sa_infr_list.state != CL_INITIALIZED) {
785		OSM_LOG(p_log, OSM_LOG_DEBUG,
786			"Ignoring Notice Reports since Inform List is not initialized yet!\n");
787		return IB_ERROR;
788	}
789
790	if (OSM_LOG_IS_ACTIVE_V2(p_log, OSM_LOG_INFO))
791		log_notice(p_log, OSM_LOG_INFO, p_ntc);
792
793	/* Create a list that will hold all the infr records that should
794	   be removed due to violation. o13-17.1.2 */
795	cl_list_construct(&infr_to_remove_list);
796	cl_list_init(&infr_to_remove_list, 5);
797	context.p_remove_infr_list = &infr_to_remove_list;
798	context.p_ntc = p_ntc;
799
800	/* go over all inform info available at the subnet */
801	/* try match to the given notice and send if match */
802	cl_qlist_apply_func(&p_subn->sa_infr_list, match_notice_to_inf_rec,
803			    &context);
804
805	/* If we inserted items into the infr_to_remove_list - we need to
806	   remove them */
807	p_infr_rec = (osm_infr_t *) cl_list_remove_head(&infr_to_remove_list);
808	while (p_infr_rec != NULL) {
809		p_next_infr_rec =
810		    (osm_infr_t *) cl_list_remove_head(&infr_to_remove_list);
811		osm_infr_remove_from_db(p_subn, p_log, p_infr_rec);
812		p_infr_rec = p_next_infr_rec;
813	}
814	cl_list_destroy(&infr_to_remove_list);
815
816	/* report IB traps to plugin */
817	osm_opensm_report_event(p_subn->p_osm, OSM_EVENT_ID_TRAP, p_ntc);
818
819	OSM_LOG_EXIT(p_log);
820
821	return IB_SUCCESS;
822}
823