1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * FMD Transport Subsystem 28 * 29 * A transport module uses some underlying mechanism to transport events. 30 * This mechanism may use any underlying link-layer protocol and may support 31 * additional link-layer packets unrelated to FMA. Some appropriate link- 32 * layer mechanism to create the underlying connection is expected to be 33 * called prior to calling fmd_xprt_open() itself. Alternatively, a transport 34 * may be created in the suspended state by specifying the FMD_XPRT_SUSPENDED 35 * flag as part of the call to fmd_xprt_open(), and then may be resumed later. 36 * The underlying transport mechanism is *required* to provide ordering: that 37 * is, the sequences of bytes written across the transport must be read by 38 * the remote peer in the order that they are written, even across separate 39 * calls to fmdo_send(). As an example, the Internet TCP protocol would be 40 * a valid transport as it guarantees ordering, whereas the Internet UDP 41 * protocol would not because UDP datagrams may be delivered in any order 42 * as a result of delays introduced when datagrams pass through routers. 43 * 44 * Similar to sending events, a transport module receives events that are from 45 * its peer remote endpoint using some transport-specific mechanism that is 46 * unknown to FMD. As each event is received, the transport module is 47 * responsible for constructing a valid nvlist_t object from the data and then 48 * calling fmd_xprt_post() to post the event to the containing FMD's dispatch 49 * queue, making it available to all local modules that are not transport 50 * modules that have subscribed to the event. 51 * 52 * The following state machine is used for each transport. The initial state 53 * is either SYN, ACK, or RUN, depending on the flags specified to xprt_create. 54 * 55 * FMD_XPRT_ACCEPT !FMD_XPRT_ACCEPT 56 * | | 57 * waiting +--v--+ +--v--+ waiting 58 * for syn | SYN |--+ --+| ACK | for ack 59 * event +-----+ \ / +-----+ event 60 * | \ / | 61 * drop all +--v--+ X +--v--+ send subscriptions, 62 * events | ERR |<---+ +--->| SUB | recv subscriptions, 63 * +-----+ +-----+ wait for run event 64 * ^ | 65 * | +-----+ | 66 * +-----| RUN |<----+ 67 * +--^--+ 68 * | 69 * FMD_XPRT_RDONLY 70 * 71 * When fmd_xprt_open() is called without FMD_XPRT_ACCEPT, the Common Transport 72 * Layer enqueues a "syn" event for the module in its event queue and sets the 73 * state to ACK. In state ACK, we are waiting for the transport to get an 74 * "ack" event and call fmd_xprt_post() on this event. Other events will be 75 * discarded. If an "ack" is received, we transition to state SUB. If a 76 * configurable timeout occurs or if the "ack" is invalid (e.g. invalid version 77 * exchange), we transition to state ERR. Once in state ERR, no further 78 * operations are valid except fmd_xprt_close() and fmd_xprt_error() will 79 * return a non-zero value to the caller indicating the transport has failed. 80 * 81 * When fmd_xprt_open() is called with FMD_XPRT_ACCEPT, the Common Transport 82 * Layer assumes this transport is being used to accept a virtual connection 83 * from a remote peer that is sending a "syn", and sets the initial state to 84 * SYN. In this state, the transport waits for a "syn" event, validates it, 85 * and then transitions to state SUB if it is valid or state ERR if it is not. 86 * 87 * Once in state SUB, the transport module is expected to receive a sequence of 88 * zero or more "subscribe" events from the remote peer, followed by a "run" 89 * event. Once in state RUN, the transport is active and any events can be 90 * sent or received. The transport module is free to call fmd_xprt_close() 91 * from any state. The fmd_xprt_error() function will return zero if the 92 * transport is not in the ERR state, or non-zero if it is in the ERR state. 93 * 94 * Once the state machine reaches RUN, other FMA protocol events can be sent 95 * and received across the transport in addition to the various control events. 96 * 97 * Table of Common Transport Layer Control Events 98 * ============================================== 99 * 100 * FMA Class Payload 101 * --------- ------- 102 * resource.fm.xprt.uuclose string (uuid of case) 103 * resource.fm.xprt.uuresolved string (uuid of case) 104 * resource.fm.xprt.updated string (uuid of case) 105 * resource.fm.xprt.subscribe string (class pattern) 106 * resource.fm.xprt.unsubscribe string (class pattern) 107 * resource.fm.xprt.unsuback string (class pattern) 108 * resource.fm.xprt.syn version information 109 * resource.fm.xprt.ack version information 110 * resource.fm.xprt.run version information 111 * 112 * Control events are used to add and delete proxy subscriptions on the remote 113 * transport peer module, and to set up connections. When a "syn" event is 114 * sent, FMD will include in the payload the highest version of the FMA event 115 * protocol that is supported by the sender. When a "syn" event is received, 116 * the receiving FMD will use the minimum of this version and its version of 117 * the protocol, and reply with this new minimum version in the "ack" event. 118 * The receiver will then use this new minimum for subsequent event semantics. 119 */ 120 121 #include <sys/fm/protocol.h> 122 #include <strings.h> 123 #include <limits.h> 124 125 #include <fmd_alloc.h> 126 #include <fmd_error.h> 127 #include <fmd_conf.h> 128 #include <fmd_subr.h> 129 #include <fmd_string.h> 130 #include <fmd_protocol.h> 131 #include <fmd_thread.h> 132 #include <fmd_eventq.h> 133 #include <fmd_dispq.h> 134 #include <fmd_ctl.h> 135 #include <fmd_log.h> 136 #include <fmd_ustat.h> 137 #include <fmd_case.h> 138 #include <fmd_api.h> 139 #include <fmd_fmri.h> 140 #include <fmd_asru.h> 141 #include <fmd_xprt.h> 142 143 #include <fmd.h> 144 145 /* 146 * The states shown above in the transport state machine diagram are encoded 147 * using arrays of class patterns and a corresponding action function. These 148 * arrays are then passed to fmd_xprt_transition() to change transport states. 149 */ 150 151 const fmd_xprt_rule_t _fmd_xprt_state_syn[] = { 152 { "resource.fm.xprt.syn", fmd_xprt_event_syn }, 153 { "*", fmd_xprt_event_error }, 154 { NULL, NULL } 155 }; 156 157 const fmd_xprt_rule_t _fmd_xprt_state_ack[] = { 158 { "resource.fm.xprt.ack", fmd_xprt_event_ack }, 159 { "*", fmd_xprt_event_error }, 160 }; 161 162 const fmd_xprt_rule_t _fmd_xprt_state_err[] = { 163 { "*", fmd_xprt_event_drop }, 164 { NULL, NULL } 165 }; 166 167 const fmd_xprt_rule_t _fmd_xprt_state_sub[] = { 168 { "resource.fm.xprt.subscribe", fmd_xprt_event_sub }, 169 { "resource.fm.xprt.run", fmd_xprt_event_run }, 170 { "resource.fm.xprt.*", fmd_xprt_event_error }, 171 { "*", fmd_xprt_event_drop }, 172 { NULL, NULL } 173 }; 174 175 const fmd_xprt_rule_t _fmd_xprt_state_run[] = { 176 { "resource.fm.xprt.subscribe", fmd_xprt_event_sub }, 177 { "resource.fm.xprt.unsubscribe", fmd_xprt_event_unsub }, 178 { "resource.fm.xprt.unsuback", fmd_xprt_event_unsuback }, 179 { "resource.fm.xprt.uuclose", fmd_xprt_event_uuclose }, 180 { "resource.fm.xprt.uuresolved", fmd_xprt_event_uuresolved }, 181 { "resource.fm.xprt.updated", fmd_xprt_event_updated }, 182 { "resource.fm.xprt.*", fmd_xprt_event_error }, 183 { NULL, NULL } 184 }; 185 186 /* 187 * Template for per-transport statistics installed by fmd on behalf of each 188 * transport. These are used to initialize the per-transport xi_stats. For 189 * each statistic, the name is prepended with "fmd.xprt.%u", where %u is the 190 * transport ID (xi_id) and then are inserted into the per-module stats hash. 191 * The values in this array must match fmd_xprt_stat_t from <fmd_xprt.h>. 192 */ 193 static const fmd_xprt_stat_t _fmd_xprt_stat_tmpl = { 194 { 195 { "dispatched", FMD_TYPE_UINT64, "total events dispatched to transport" }, 196 { "dequeued", FMD_TYPE_UINT64, "total events dequeued by transport" }, 197 { "prdequeued", FMD_TYPE_UINT64, "protocol events dequeued by transport" }, 198 { "dropped", FMD_TYPE_UINT64, "total events dropped on queue overflow" }, 199 { "wcnt", FMD_TYPE_UINT32, "count of events waiting on queue" }, 200 { "wtime", FMD_TYPE_TIME, "total wait time on queue" }, 201 { "wlentime", FMD_TYPE_TIME, "total wait length * time product" }, 202 { "wlastupdate", FMD_TYPE_TIME, "hrtime of last wait queue update" }, 203 { "dtime", FMD_TYPE_TIME, "total processing time after dequeue" }, 204 { "dlastupdate", FMD_TYPE_TIME, "hrtime of last event dequeue completion" }, 205 }, 206 { "module", FMD_TYPE_STRING, "module that owns this transport" }, 207 { "authority", FMD_TYPE_STRING, "authority associated with this transport" }, 208 { "state", FMD_TYPE_STRING, "current transport state" }, 209 { "received", FMD_TYPE_UINT64, "events received by transport" }, 210 { "discarded", FMD_TYPE_UINT64, "bad events discarded by transport" }, 211 { "retried", FMD_TYPE_UINT64, "retries requested of transport" }, 212 { "replayed", FMD_TYPE_UINT64, "events replayed by transport" }, 213 { "lost", FMD_TYPE_UINT64, "events lost by transport" }, 214 { "timeouts", FMD_TYPE_UINT64, "events received by transport with ttl=0" }, 215 { "subscriptions", FMD_TYPE_UINT64, "subscriptions registered to transport" }, 216 }; 217 218 static void 219 fmd_xprt_class_hash_create(fmd_xprt_class_hash_t *xch, fmd_eventq_t *eq) 220 { 221 uint_t hashlen = fmd.d_str_buckets; 222 223 xch->xch_queue = eq; 224 xch->xch_hashlen = hashlen; 225 xch->xch_hash = fmd_zalloc(sizeof (void *) * hashlen, FMD_SLEEP); 226 } 227 228 static void 229 fmd_xprt_class_hash_destroy(fmd_xprt_class_hash_t *xch) 230 { 231 fmd_eventq_t *eq = xch->xch_queue; 232 fmd_xprt_class_t *xcp, *ncp; 233 uint_t i; 234 235 for (i = 0; i < xch->xch_hashlen; i++) { 236 for (xcp = xch->xch_hash[i]; xcp != NULL; xcp = ncp) { 237 ncp = xcp->xc_next; 238 239 if (eq != NULL) 240 fmd_dispq_delete(fmd.d_disp, eq, xcp->xc_class); 241 242 fmd_strfree(xcp->xc_class); 243 fmd_free(xcp, sizeof (fmd_xprt_class_t)); 244 } 245 } 246 247 fmd_free(xch->xch_hash, sizeof (void *) * xch->xch_hashlen); 248 } 249 250 /* 251 * Insert the specified class into the specified class hash, and return the 252 * reference count. A return value of one indicates this is the first insert. 253 * If an eventq is associated with the hash, insert a dispq subscription for it. 254 */ 255 static uint_t 256 fmd_xprt_class_hash_insert(fmd_xprt_impl_t *xip, 257 fmd_xprt_class_hash_t *xch, const char *class) 258 { 259 uint_t h = fmd_strhash(class) % xch->xch_hashlen; 260 fmd_xprt_class_t *xcp; 261 262 ASSERT(MUTEX_HELD(&xip->xi_lock)); 263 264 for (xcp = xch->xch_hash[h]; xcp != NULL; xcp = xcp->xc_next) { 265 if (strcmp(class, xcp->xc_class) == 0) 266 return (++xcp->xc_refs); 267 } 268 269 xcp = fmd_alloc(sizeof (fmd_xprt_class_t), FMD_SLEEP); 270 xcp->xc_class = fmd_strdup(class, FMD_SLEEP); 271 xcp->xc_next = xch->xch_hash[h]; 272 xcp->xc_refs = 1; 273 xch->xch_hash[h] = xcp; 274 275 if (xch->xch_queue != NULL) 276 fmd_dispq_insert(fmd.d_disp, xch->xch_queue, class); 277 278 return (xcp->xc_refs); 279 } 280 281 /* 282 * Delete the specified class from the specified class hash, and return the 283 * reference count. A return value of zero indicates the class was deleted. 284 * If an eventq is associated with the hash, delete the dispq subscription. 285 */ 286 static uint_t 287 fmd_xprt_class_hash_delete(fmd_xprt_impl_t *xip, 288 fmd_xprt_class_hash_t *xch, const char *class) 289 { 290 uint_t h = fmd_strhash(class) % xch->xch_hashlen; 291 fmd_xprt_class_t *xcp, **pp; 292 293 ASSERT(MUTEX_HELD(&xip->xi_lock)); 294 pp = &xch->xch_hash[h]; 295 296 for (xcp = *pp; xcp != NULL; xcp = xcp->xc_next) { 297 if (strcmp(class, xcp->xc_class) == 0) 298 break; 299 else 300 pp = &xcp->xc_next; 301 } 302 303 if (xcp == NULL) 304 return (-1U); /* explicitly permit an invalid delete */ 305 306 if (--xcp->xc_refs != 0) 307 return (xcp->xc_refs); 308 309 ASSERT(xcp->xc_refs == 0); 310 *pp = xcp->xc_next; 311 312 fmd_strfree(xcp->xc_class); 313 fmd_free(xcp, sizeof (fmd_xprt_class_t)); 314 315 if (xch->xch_queue != NULL) 316 fmd_dispq_delete(fmd.d_disp, xch->xch_queue, class); 317 318 return (0); 319 } 320 321 /* 322 * Queue subscribe events for the specified transport corresponding to all of 323 * the active module subscriptions. This is an extremely heavyweight operation 324 * that we expect to take place rarely (i.e. when loading a transport module 325 * or when it establishes a connection). We lock all of the known modules to 326 * prevent them from adding or deleting subscriptions, then snapshot their 327 * subscriptions, and then unlock all of the modules. We hold the modhash 328 * lock for the duration of this operation to prevent new modules from loading. 329 */ 330 static void 331 fmd_xprt_subscribe_modhash(fmd_xprt_impl_t *xip, fmd_modhash_t *mhp) 332 { 333 fmd_xprt_t *xp = (fmd_xprt_t *)xip; 334 const fmd_conf_path_t *pap; 335 fmd_module_t *mp; 336 uint_t i, j; 337 338 (void) pthread_rwlock_rdlock(&mhp->mh_lock); 339 340 for (i = 0; i < mhp->mh_hashlen; i++) { 341 for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next) 342 fmd_module_lock(mp); 343 } 344 345 (void) pthread_mutex_lock(&xip->xi_lock); 346 ASSERT(!(xip->xi_flags & FMD_XPRT_SUBSCRIBER)); 347 xip->xi_flags |= FMD_XPRT_SUBSCRIBER; 348 (void) pthread_mutex_unlock(&xip->xi_lock); 349 350 for (i = 0; i < mhp->mh_hashlen; i++) { 351 for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next) { 352 (void) fmd_conf_getprop(mp->mod_conf, 353 FMD_PROP_SUBSCRIPTIONS, &pap); 354 for (j = 0; j < pap->cpa_argc; j++) 355 fmd_xprt_subscribe(xp, pap->cpa_argv[j]); 356 } 357 } 358 359 for (i = 0; i < mhp->mh_hashlen; i++) { 360 for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next) 361 fmd_module_unlock(mp); 362 } 363 364 (void) pthread_rwlock_unlock(&mhp->mh_lock); 365 } 366 367 static void 368 fmd_xprt_transition(fmd_xprt_impl_t *xip, 369 const fmd_xprt_rule_t *state, const char *tag) 370 { 371 fmd_xprt_t *xp = (fmd_xprt_t *)xip; 372 fmd_event_t *e; 373 nvlist_t *nvl; 374 char *s; 375 376 TRACE((FMD_DBG_XPRT, "xprt %u -> %s\n", xip->xi_id, tag)); 377 378 xip->xi_state = state; 379 s = fmd_strdup(tag, FMD_SLEEP); 380 381 (void) pthread_mutex_lock(&xip->xi_stats_lock); 382 fmd_strfree(xip->xi_stats->xs_state.fmds_value.str); 383 xip->xi_stats->xs_state.fmds_value.str = s; 384 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 385 386 /* 387 * If we've reached the SUB state, take out the big hammer and snapshot 388 * all of the subscriptions of all of the loaded modules. Then queue a 389 * run event for our remote peer indicating that it can enter RUN. 390 */ 391 if (state == _fmd_xprt_state_sub) { 392 fmd_xprt_subscribe_modhash(xip, fmd.d_mod_hash); 393 394 /* 395 * For read-write transports, we always want to set up remote 396 * subscriptions to the bultin list.* events, regardless of 397 * whether any agents have subscribed to them. 398 */ 399 if (xip->xi_flags & FMD_XPRT_RDWR) { 400 fmd_xprt_subscribe(xp, FM_LIST_SUSPECT_CLASS); 401 fmd_xprt_subscribe(xp, FM_LIST_ISOLATED_CLASS); 402 fmd_xprt_subscribe(xp, FM_LIST_UPDATED_CLASS); 403 fmd_xprt_subscribe(xp, FM_LIST_RESOLVED_CLASS); 404 fmd_xprt_subscribe(xp, FM_LIST_REPAIRED_CLASS); 405 } 406 407 nvl = fmd_protocol_xprt_ctl(xip->xi_queue->eq_mod, 408 "resource.fm.xprt.run", xip->xi_version); 409 410 (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 411 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 412 fmd_eventq_insert_at_time(xip->xi_queue, e); 413 } 414 } 415 416 static void 417 fmd_xprt_authupdate(fmd_xprt_impl_t *xip) 418 { 419 char *s = fmd_fmri_auth2str(xip->xi_auth); 420 421 (void) pthread_mutex_lock(&xip->xi_stats_lock); 422 fmd_strfree(xip->xi_stats->xs_authority.fmds_value.str); 423 xip->xi_stats->xs_authority.fmds_value.str = s; 424 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 425 } 426 427 static int 428 fmd_xprt_vmismatch(fmd_xprt_impl_t *xip, nvlist_t *nvl, uint_t *rversionp) 429 { 430 uint8_t rversion; 431 432 if (nvlist_lookup_uint8(nvl, FM_VERSION, &rversion) != 0) { 433 (void) pthread_mutex_lock(&xip->xi_stats_lock); 434 xip->xi_stats->xs_discarded.fmds_value.ui64++; 435 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 436 437 fmd_xprt_transition(xip, _fmd_xprt_state_err, "ERR"); 438 return (1); 439 } 440 441 if (rversion > xip->xi_version) { 442 fmd_dprintf(FMD_DBG_XPRT, "xprt %u protocol mismatch: %u>%u\n", 443 xip->xi_id, rversion, xip->xi_version); 444 445 (void) pthread_mutex_lock(&xip->xi_stats_lock); 446 xip->xi_stats->xs_discarded.fmds_value.ui64++; 447 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 448 449 fmd_xprt_transition(xip, _fmd_xprt_state_err, "ERR"); 450 return (1); 451 } 452 453 if (rversionp != NULL) 454 *rversionp = rversion; 455 456 return (0); 457 } 458 459 void 460 fmd_xprt_event_syn(fmd_xprt_impl_t *xip, nvlist_t *nvl) 461 { 462 fmd_event_t *e; 463 uint_t vers; 464 char *class; 465 466 if (fmd_xprt_vmismatch(xip, nvl, &vers)) 467 return; /* transitioned to error state */ 468 469 /* 470 * If the transport module didn't specify an authority, extract the 471 * one that is passed along with the xprt.syn event and use that. 472 */ 473 if (xip->xi_auth == NULL && 474 nvlist_lookup_nvlist(nvl, FM_RSRC_RESOURCE, &nvl) == 0 && 475 nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &nvl) == 0) { 476 (void) nvlist_xdup(nvl, &xip->xi_auth, &fmd.d_nva); 477 fmd_xprt_authupdate(xip); 478 } 479 480 nvl = fmd_protocol_xprt_ctl(xip->xi_queue->eq_mod, 481 "resource.fm.xprt.ack", xip->xi_version); 482 483 (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 484 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 485 fmd_eventq_insert_at_time(xip->xi_queue, e); 486 487 xip->xi_version = MIN(FM_RSRC_XPRT_VERSION, vers); 488 fmd_xprt_transition(xip, _fmd_xprt_state_sub, "SUB"); 489 } 490 491 void 492 fmd_xprt_event_ack(fmd_xprt_impl_t *xip, nvlist_t *nvl) 493 { 494 uint_t vers; 495 496 if (fmd_xprt_vmismatch(xip, nvl, &vers)) 497 return; /* transitioned to error state */ 498 499 /* 500 * If the transport module didn't specify an authority, extract the 501 * one that is passed along with the xprt.syn event and use that. 502 */ 503 if (xip->xi_auth == NULL && 504 nvlist_lookup_nvlist(nvl, FM_RSRC_RESOURCE, &nvl) == 0 && 505 nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &nvl) == 0) { 506 (void) nvlist_xdup(nvl, &xip->xi_auth, &fmd.d_nva); 507 fmd_xprt_authupdate(xip); 508 } 509 510 xip->xi_version = MIN(FM_RSRC_XPRT_VERSION, vers); 511 fmd_xprt_transition(xip, _fmd_xprt_state_sub, "SUB"); 512 } 513 514 /* 515 * Upon transition to RUN, we take every solved case and resend a list.suspect 516 * event for it to our remote peer. If a case transitions from solved to a 517 * future state (CLOSE_WAIT, CLOSED, or REPAIRED) while we are iterating over 518 * the case hash, we will get it as part of examining the resource cache, next. 519 */ 520 static void 521 fmd_xprt_send_case(fmd_case_t *cp, void *arg) 522 { 523 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 524 fmd_xprt_impl_t *xip = arg; 525 526 fmd_event_t *e; 527 nvlist_t *nvl; 528 char *class; 529 530 if (cip->ci_state != FMD_CASE_SOLVED) 531 return; 532 533 nvl = fmd_case_mkevent(cp, FM_LIST_SUSPECT_CLASS); 534 (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 535 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 536 537 fmd_dprintf(FMD_DBG_XPRT, "re-send %s for %s to transport %u\n", 538 FM_LIST_SUSPECT_CLASS, cip->ci_uuid, xip->xi_id); 539 540 fmd_dispq_dispatch_gid(fmd.d_disp, e, class, xip->xi_queue->eq_sgid); 541 } 542 543 /* 544 * Similar to the above function, but for use with readonly transport. Puts 545 * the event on the module's queue such that it's fmdo_recv function can pick 546 * it up and send it if appropriate. 547 */ 548 static void 549 fmd_xprt_send_case_ro(fmd_case_t *cp, void *arg) 550 { 551 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 552 fmd_module_t *mp = arg; 553 554 fmd_event_t *e; 555 nvlist_t *nvl; 556 char *class; 557 558 if (cip->ci_state != FMD_CASE_SOLVED) 559 return; 560 561 nvl = fmd_case_mkevent(cp, FM_LIST_SUSPECT_CLASS); 562 (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 563 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 564 565 fmd_dprintf(FMD_DBG_XPRT, "re-send %s for %s to rdonly transport %s\n", 566 FM_LIST_SUSPECT_CLASS, cip->ci_uuid, mp->mod_name); 567 568 fmd_dispq_dispatch_gid(fmd.d_disp, e, class, mp->mod_queue->eq_sgid); 569 } 570 571 void 572 fmd_xprt_event_run(fmd_xprt_impl_t *xip, nvlist_t *nvl) 573 { 574 if (!fmd_xprt_vmismatch(xip, nvl, NULL)) { 575 fmd_xprt_transition(xip, _fmd_xprt_state_run, "RUN"); 576 fmd_case_hash_apply(fmd.d_cases, fmd_xprt_send_case, xip); 577 } 578 } 579 580 void 581 fmd_xprt_event_sub(fmd_xprt_impl_t *xip, nvlist_t *nvl) 582 { 583 char *class; 584 585 if (fmd_xprt_vmismatch(xip, nvl, NULL)) 586 return; /* transitioned to error state */ 587 588 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_SUBCLASS, &class) != 0) 589 return; /* malformed protocol event */ 590 591 (void) pthread_mutex_lock(&xip->xi_lock); 592 (void) fmd_xprt_class_hash_insert(xip, &xip->xi_lsub, class); 593 (void) pthread_mutex_unlock(&xip->xi_lock); 594 595 (void) pthread_mutex_lock(&xip->xi_stats_lock); 596 xip->xi_stats->xs_subscriptions.fmds_value.ui64++; 597 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 598 } 599 600 void 601 fmd_xprt_event_unsub(fmd_xprt_impl_t *xip, nvlist_t *nvl) 602 { 603 fmd_event_t *e; 604 char *class; 605 606 if (fmd_xprt_vmismatch(xip, nvl, NULL)) 607 return; /* transitioned to error state */ 608 609 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_SUBCLASS, &class) != 0) 610 return; /* malformed protocol event */ 611 612 (void) pthread_mutex_lock(&xip->xi_lock); 613 (void) fmd_xprt_class_hash_delete(xip, &xip->xi_lsub, class); 614 (void) pthread_mutex_unlock(&xip->xi_lock); 615 616 (void) pthread_mutex_lock(&xip->xi_stats_lock); 617 xip->xi_stats->xs_subscriptions.fmds_value.ui64--; 618 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 619 620 nvl = fmd_protocol_xprt_sub(xip->xi_queue->eq_mod, 621 "resource.fm.xprt.unsuback", xip->xi_version, class); 622 623 (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 624 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 625 fmd_eventq_insert_at_time(xip->xi_queue, e); 626 } 627 628 void 629 fmd_xprt_event_unsuback(fmd_xprt_impl_t *xip, nvlist_t *nvl) 630 { 631 char *class; 632 633 if (fmd_xprt_vmismatch(xip, nvl, NULL)) 634 return; /* transitioned to error state */ 635 636 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_SUBCLASS, &class) != 0) 637 return; /* malformed protocol event */ 638 639 (void) pthread_mutex_lock(&xip->xi_lock); 640 (void) fmd_xprt_class_hash_delete(xip, &xip->xi_usub, class); 641 (void) pthread_mutex_unlock(&xip->xi_lock); 642 } 643 644 /* 645 * on diagnosing side, receive a uuclose from the proxy. 646 */ 647 void 648 fmd_xprt_event_uuclose(fmd_xprt_impl_t *xip, nvlist_t *nvl) 649 { 650 fmd_case_t *cp; 651 char *uuid; 652 653 if (fmd_xprt_vmismatch(xip, nvl, NULL)) 654 return; /* transitioned to error state */ 655 656 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_UUID, &uuid) == 0 && 657 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 658 /* 659 * update resource cache status and transition case 660 */ 661 fmd_case_close_status(cp); 662 fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, FMD_CF_ISOLATED); 663 fmd_case_rele(cp); 664 } 665 } 666 667 /* 668 * on diagnosing side, receive a uuresolved from the proxy. 669 */ 670 void 671 fmd_xprt_event_uuresolved(fmd_xprt_impl_t *xip, nvlist_t *nvl) 672 { 673 fmd_case_t *cp; 674 char *uuid; 675 676 if (fmd_xprt_vmismatch(xip, nvl, NULL)) 677 return; /* transitioned to error state */ 678 679 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_UUID, &uuid) == 0 && 680 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 681 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 682 683 fmd_case_transition(cp, (cip->ci_state == FMD_CASE_REPAIRED) ? 684 FMD_CASE_RESOLVED : (cip->ci_state == FMD_CASE_CLOSED) ? 685 FMD_CASE_REPAIRED : FMD_CASE_CLOSE_WAIT, FMD_CF_RESOLVED); 686 fmd_case_rele(cp); 687 } 688 } 689 690 /* 691 * on diagnosing side, receive a repair/acquit from the proxy. 692 */ 693 void 694 fmd_xprt_event_updated(fmd_xprt_impl_t *xip, nvlist_t *nvl) 695 { 696 fmd_case_t *cp; 697 char *uuid; 698 699 if (fmd_xprt_vmismatch(xip, nvl, NULL)) 700 return; /* transitioned to error state */ 701 702 if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_UUID, &uuid) == 0 && 703 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 704 uint8_t *statusp, *proxy_asrup = NULL; 705 uint_t nelem = 0; 706 707 /* 708 * Only update status with new repairs if "no remote repair" 709 * is not set. Do the case_update anyway though (as this will 710 * refresh the status on the proxy side). 711 */ 712 if (!(xip->xi_flags & FMD_XPRT_NO_REMOTE_REPAIR)) { 713 if (nvlist_lookup_uint8_array(nvl, 714 FM_RSRC_XPRT_FAULT_STATUS, &statusp, &nelem) == 0 && 715 nelem != 0) { 716 (void) nvlist_lookup_uint8_array(nvl, 717 FM_RSRC_XPRT_FAULT_HAS_ASRU, &proxy_asrup, 718 &nelem); 719 fmd_case_update_status(cp, statusp, 720 proxy_asrup, NULL); 721 } 722 fmd_case_update_containees(cp); 723 } 724 fmd_case_update(cp); 725 fmd_case_rele(cp); 726 } 727 } 728 729 void 730 fmd_xprt_event_error(fmd_xprt_impl_t *xip, nvlist_t *nvl) 731 { 732 char *class = "<unknown>"; 733 734 (void) pthread_mutex_lock(&xip->xi_stats_lock); 735 xip->xi_stats->xs_discarded.fmds_value.ui64++; 736 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 737 738 (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 739 TRACE((FMD_DBG_XPRT, "xprt %u bad event %s\n", xip->xi_id, class)); 740 741 fmd_xprt_transition(xip, _fmd_xprt_state_err, "ERR"); 742 } 743 744 void 745 fmd_xprt_event_drop(fmd_xprt_impl_t *xip, nvlist_t *nvl) 746 { 747 char *class = "<unknown>"; 748 749 (void) pthread_mutex_lock(&xip->xi_stats_lock); 750 xip->xi_stats->xs_discarded.fmds_value.ui64++; 751 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 752 753 (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 754 TRACE((FMD_DBG_XPRT, "xprt %u drop event %s\n", xip->xi_id, class)); 755 756 } 757 758 fmd_xprt_t * 759 fmd_xprt_create(fmd_module_t *mp, uint_t flags, nvlist_t *auth, void *data) 760 { 761 fmd_xprt_impl_t *xip = fmd_zalloc(sizeof (fmd_xprt_impl_t), FMD_SLEEP); 762 fmd_stat_t *statv; 763 uint_t i, statc; 764 765 char buf[PATH_MAX]; 766 fmd_event_t *e; 767 nvlist_t *nvl; 768 char *s; 769 770 (void) pthread_mutex_init(&xip->xi_lock, NULL); 771 (void) pthread_cond_init(&xip->xi_cv, NULL); 772 (void) pthread_mutex_init(&xip->xi_stats_lock, NULL); 773 774 xip->xi_auth = auth; 775 xip->xi_data = data; 776 xip->xi_version = FM_RSRC_XPRT_VERSION; 777 xip->xi_flags = flags; 778 779 /* 780 * Grab fmd.d_xprt_lock to block fmd_xprt_suspend_all() and then create 781 * a transport ID and make it visible in fmd.d_xprt_ids. If transports 782 * were previously suspended, set the FMD_XPRT_DSUSPENDED flag on us to 783 * ensure that this transport will not run until fmd_xprt_resume_all(). 784 */ 785 (void) pthread_mutex_lock(&fmd.d_xprt_lock); 786 xip->xi_id = fmd_idspace_alloc(fmd.d_xprt_ids, xip); 787 788 if (fmd.d_xprt_suspend != 0) 789 xip->xi_flags |= FMD_XPRT_DSUSPENDED; 790 791 (void) pthread_mutex_unlock(&fmd.d_xprt_lock); 792 793 /* 794 * If the module has not yet finished _fmd_init(), set the ISUSPENDED 795 * bit so that fmdo_send() is not called until _fmd_init() completes. 796 */ 797 if (!(mp->mod_flags & FMD_MOD_INIT)) 798 xip->xi_flags |= FMD_XPRT_ISUSPENDED; 799 800 /* 801 * Initialize the transport statistics that we keep on behalf of fmd. 802 * These are set up using a template defined at the top of this file. 803 * We rename each statistic with a prefix ensuring its uniqueness. 804 */ 805 statc = sizeof (_fmd_xprt_stat_tmpl) / sizeof (fmd_stat_t); 806 statv = fmd_alloc(sizeof (_fmd_xprt_stat_tmpl), FMD_SLEEP); 807 bcopy(&_fmd_xprt_stat_tmpl, statv, sizeof (_fmd_xprt_stat_tmpl)); 808 809 for (i = 0; i < statc; i++) { 810 (void) snprintf(statv[i].fmds_name, 811 sizeof (statv[i].fmds_name), "fmd.xprt.%u.%s", xip->xi_id, 812 ((fmd_stat_t *)&_fmd_xprt_stat_tmpl + i)->fmds_name); 813 } 814 815 xip->xi_stats = (fmd_xprt_stat_t *)fmd_ustat_insert( 816 mp->mod_ustat, FMD_USTAT_NOALLOC, statc, statv, NULL); 817 818 if (xip->xi_stats == NULL) 819 fmd_panic("failed to create xi_stats (%p)\n", (void *)statv); 820 821 xip->xi_stats->xs_module.fmds_value.str = 822 fmd_strdup(mp->mod_name, FMD_SLEEP); 823 824 if (xip->xi_auth != NULL) 825 fmd_xprt_authupdate(xip); 826 827 /* 828 * Create the outbound eventq for this transport and link to its stats. 829 * If any suspend bits were set above, suspend the eventq immediately. 830 */ 831 xip->xi_queue = fmd_eventq_create(mp, &xip->xi_stats->xs_evqstat, 832 &xip->xi_stats_lock, mp->mod_stats->ms_xprtqlimit.fmds_value.ui32); 833 834 if (xip->xi_flags & FMD_XPRT_SMASK) 835 fmd_eventq_suspend(xip->xi_queue); 836 837 /* 838 * Create our subscription hashes: local subscriptions go to xi_queue, 839 * remote subscriptions are tracked only for protocol requests, and 840 * pending unsubscriptions are associated with the /dev/null eventq. 841 */ 842 fmd_xprt_class_hash_create(&xip->xi_lsub, xip->xi_queue); 843 fmd_xprt_class_hash_create(&xip->xi_rsub, NULL); 844 fmd_xprt_class_hash_create(&xip->xi_usub, fmd.d_rmod->mod_queue); 845 846 /* 847 * Determine our initial state based upon the creation flags. If we're 848 * read-only, go directly to RUN. If we're accepting a new connection, 849 * wait for a SYN. Otherwise send a SYN and wait for an ACK. 850 */ 851 if ((flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) { 852 /* 853 * Send the list.suspects across here for readonly transports. 854 * For read-write transport they will be sent on transition to 855 * RUN state in fmd_xprt_event_run(). 856 */ 857 fmd_case_hash_apply(fmd.d_cases, fmd_xprt_send_case_ro, mp); 858 fmd_xprt_transition(xip, _fmd_xprt_state_run, "RUN"); 859 } else if (flags & FMD_XPRT_ACCEPT) 860 fmd_xprt_transition(xip, _fmd_xprt_state_syn, "SYN"); 861 else 862 fmd_xprt_transition(xip, _fmd_xprt_state_ack, "ACK"); 863 864 /* 865 * If client.xprtlog is set to TRUE, create a debugging log for the 866 * events received by the transport in var/fm/fmd/xprt/. 867 */ 868 (void) fmd_conf_getprop(fmd.d_conf, "client.xprtlog", &i); 869 (void) fmd_conf_getprop(fmd.d_conf, "log.xprt", &s); 870 871 if (i) { 872 (void) snprintf(buf, sizeof (buf), "%s/%u.log", s, xip->xi_id); 873 xip->xi_log = fmd_log_open(fmd.d_rootdir, buf, FMD_LOG_XPRT); 874 } 875 876 ASSERT(fmd_module_locked(mp)); 877 fmd_list_append(&mp->mod_transports, xip); 878 879 (void) pthread_mutex_lock(&mp->mod_stats_lock); 880 mp->mod_stats->ms_xprtopen.fmds_value.ui32++; 881 (void) pthread_mutex_unlock(&mp->mod_stats_lock); 882 883 /* 884 * If this is a read-only transport, return without creating a send 885 * queue thread and setting up any connection events in our queue. 886 */ 887 if ((flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 888 goto out; 889 890 /* 891 * Once the transport is fully initialized, create a send queue thread 892 * and start any connect events flowing to complete our initialization. 893 */ 894 if ((xip->xi_thread = fmd_thread_create(mp, 895 (fmd_thread_f *)fmd_xprt_send, xip)) == NULL) { 896 897 fmd_error(EFMD_XPRT_THR, 898 "failed to create thread for transport %u", xip->xi_id); 899 900 fmd_xprt_destroy((fmd_xprt_t *)xip); 901 (void) fmd_set_errno(EFMD_XPRT_THR); 902 return (NULL); 903 } 904 905 /* 906 * If the transport is not being opened to accept an inbound connect, 907 * start an outbound connection by enqueuing a SYN event for our peer. 908 */ 909 if (!(flags & FMD_XPRT_ACCEPT)) { 910 nvl = fmd_protocol_xprt_ctl(mp, 911 "resource.fm.xprt.syn", FM_RSRC_XPRT_VERSION); 912 913 (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 914 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 915 fmd_eventq_insert_at_time(xip->xi_queue, e); 916 } 917 out: 918 fmd_dprintf(FMD_DBG_XPRT, "opened transport %u\n", xip->xi_id); 919 return ((fmd_xprt_t *)xip); 920 } 921 922 void 923 fmd_xprt_destroy(fmd_xprt_t *xp) 924 { 925 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 926 fmd_module_t *mp = xip->xi_queue->eq_mod; 927 uint_t id = xip->xi_id; 928 929 fmd_case_impl_t *cip, *nip; 930 fmd_stat_t *sp; 931 uint_t i, n; 932 933 ASSERT(fmd_module_locked(mp)); 934 fmd_list_delete(&mp->mod_transports, xip); 935 936 (void) pthread_mutex_lock(&mp->mod_stats_lock); 937 mp->mod_stats->ms_xprtopen.fmds_value.ui32--; 938 (void) pthread_mutex_unlock(&mp->mod_stats_lock); 939 940 (void) pthread_mutex_lock(&xip->xi_lock); 941 942 while (xip->xi_busy != 0) 943 (void) pthread_cond_wait(&xip->xi_cv, &xip->xi_lock); 944 945 /* 946 * Remove the transport from global visibility, cancel its send-side 947 * thread, join with it, and then remove the transport from module 948 * visibility. Once all this is done, destroy and free the transport. 949 */ 950 (void) fmd_idspace_free(fmd.d_xprt_ids, xip->xi_id); 951 952 if (xip->xi_thread != NULL) { 953 fmd_eventq_abort(xip->xi_queue); 954 fmd_module_unlock(mp); 955 fmd_thread_destroy(xip->xi_thread, FMD_THREAD_JOIN); 956 fmd_module_lock(mp); 957 } 958 959 if (xip->xi_log != NULL) 960 fmd_log_rele(xip->xi_log); 961 962 /* 963 * Release every case handle in the module that was cached by this 964 * transport. This will result in these cases disappearing from the 965 * local case hash so that fmd_case_uuclose() and fmd_case_repaired() 966 * etc can no longer be used. 967 */ 968 for (cip = fmd_list_next(&mp->mod_cases); cip != NULL; cip = nip) { 969 nip = fmd_list_next(cip); 970 if (cip->ci_xprt == xp) 971 fmd_case_discard((fmd_case_t *)cip, B_TRUE); 972 } 973 974 /* 975 * Destroy every class in the various subscription hashes and remove 976 * any corresponding subscriptions from the event dispatch queue. 977 */ 978 fmd_xprt_class_hash_destroy(&xip->xi_lsub); 979 fmd_xprt_class_hash_destroy(&xip->xi_rsub); 980 fmd_xprt_class_hash_destroy(&xip->xi_usub); 981 982 /* 983 * Uniquify the stat names exactly as was done in fmd_xprt_create() 984 * before calling fmd_ustat_insert(), otherwise fmd_ustat_delete() 985 * won't find the entries in the hash table. 986 */ 987 n = sizeof (_fmd_xprt_stat_tmpl) / sizeof (fmd_stat_t); 988 sp = fmd_alloc(sizeof (_fmd_xprt_stat_tmpl), FMD_SLEEP); 989 bcopy(&_fmd_xprt_stat_tmpl, sp, sizeof (_fmd_xprt_stat_tmpl)); 990 for (i = 0; i < n; i++) { 991 (void) snprintf(sp[i].fmds_name, 992 sizeof (sp[i].fmds_name), "fmd.xprt.%u.%s", xip->xi_id, 993 ((fmd_stat_t *)&_fmd_xprt_stat_tmpl + i)->fmds_name); 994 } 995 fmd_ustat_delete(mp->mod_ustat, n, sp); 996 fmd_free(sp, sizeof (_fmd_xprt_stat_tmpl)); 997 998 fmd_free(xip->xi_stats, sizeof (fmd_xprt_stat_t)); 999 fmd_eventq_destroy(xip->xi_queue); 1000 nvlist_free(xip->xi_auth); 1001 fmd_free(xip, sizeof (fmd_xprt_impl_t)); 1002 1003 fmd_dprintf(FMD_DBG_XPRT, "closed transport %u\n", id); 1004 } 1005 1006 void 1007 fmd_xprt_xsuspend(fmd_xprt_t *xp, uint_t flags) 1008 { 1009 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1010 uint_t oflags; 1011 1012 ASSERT((flags & ~FMD_XPRT_SMASK) == 0); 1013 (void) pthread_mutex_lock(&xip->xi_lock); 1014 1015 oflags = xip->xi_flags; 1016 xip->xi_flags |= flags; 1017 1018 if (!(oflags & FMD_XPRT_SMASK) && (xip->xi_flags & FMD_XPRT_SMASK) != 0) 1019 fmd_eventq_suspend(xip->xi_queue); 1020 1021 (void) pthread_cond_broadcast(&xip->xi_cv); 1022 1023 while (xip->xi_busy != 0) 1024 (void) pthread_cond_wait(&xip->xi_cv, &xip->xi_lock); 1025 1026 (void) pthread_mutex_unlock(&xip->xi_lock); 1027 } 1028 1029 void 1030 fmd_xprt_xresume(fmd_xprt_t *xp, uint_t flags) 1031 { 1032 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1033 uint_t oflags; 1034 1035 ASSERT((flags & ~FMD_XPRT_SMASK) == 0); 1036 (void) pthread_mutex_lock(&xip->xi_lock); 1037 1038 oflags = xip->xi_flags; 1039 xip->xi_flags &= ~flags; 1040 1041 if ((oflags & FMD_XPRT_SMASK) != 0 && !(xip->xi_flags & FMD_XPRT_SMASK)) 1042 fmd_eventq_resume(xip->xi_queue); 1043 1044 (void) pthread_cond_broadcast(&xip->xi_cv); 1045 (void) pthread_mutex_unlock(&xip->xi_lock); 1046 } 1047 1048 void 1049 fmd_xprt_send(fmd_xprt_t *xp) 1050 { 1051 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1052 fmd_module_t *mp = xip->xi_queue->eq_mod; 1053 fmd_event_t *ep; 1054 int err; 1055 1056 while ((ep = fmd_eventq_delete(xip->xi_queue)) != NULL) { 1057 if (FMD_EVENT_TTL(ep) == 0) { 1058 fmd_event_rele(ep); 1059 continue; 1060 } 1061 1062 fmd_dprintf(FMD_DBG_XPRT, "xprt %u sending %s\n", 1063 xip->xi_id, (char *)FMD_EVENT_DATA(ep)); 1064 1065 err = mp->mod_ops->mop_transport(mp, xp, ep); 1066 fmd_eventq_done(xip->xi_queue); 1067 1068 if (err == FMD_SEND_RETRY) { 1069 fmd_eventq_insert_at_time(xip->xi_queue, ep); 1070 (void) pthread_mutex_lock(&xip->xi_stats_lock); 1071 xip->xi_stats->xs_retried.fmds_value.ui64++; 1072 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1073 } 1074 1075 if (err != FMD_SEND_SUCCESS && err != FMD_SEND_RETRY) { 1076 (void) pthread_mutex_lock(&xip->xi_stats_lock); 1077 xip->xi_stats->xs_lost.fmds_value.ui64++; 1078 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1079 } 1080 1081 fmd_event_rele(ep); 1082 } 1083 } 1084 1085 /* 1086 * This function creates a local suspect list. This is used when a suspect list 1087 * is created directly by an external source like fminject. 1088 */ 1089 static void 1090 fmd_xprt_list_suspect_local(fmd_xprt_t *xp, nvlist_t *nvl) 1091 { 1092 nvlist_t **nvlp; 1093 nvlist_t *de_fmri, *de_fmri_dup = NULL; 1094 int64_t *diag_time; 1095 char *code = NULL; 1096 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1097 fmd_case_t *cp; 1098 uint_t nelem = 0, nelem2 = 0, i; 1099 boolean_t injected; 1100 1101 fmd_module_lock(xip->xi_queue->eq_mod); 1102 cp = fmd_case_create(xip->xi_queue->eq_mod, NULL, NULL); 1103 if (cp == NULL) { 1104 fmd_module_unlock(xip->xi_queue->eq_mod); 1105 return; 1106 } 1107 1108 /* 1109 * copy diag_code if present 1110 */ 1111 (void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &code); 1112 if (code != NULL) { 1113 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1114 1115 cip->ci_precanned = 1; 1116 fmd_case_setcode(cp, code); 1117 } 1118 1119 /* 1120 * copy suspects 1121 */ 1122 (void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, &nvlp, 1123 &nelem); 1124 for (i = 0; i < nelem; i++) { 1125 nvlist_t *flt_copy, *asru = NULL, *fru = NULL, *rsrc = NULL; 1126 topo_hdl_t *thp; 1127 char *loc = NULL; 1128 int err; 1129 1130 thp = fmd_fmri_topo_hold(TOPO_VERSION); 1131 (void) nvlist_xdup(nvlp[i], &flt_copy, &fmd.d_nva); 1132 (void) nvlist_lookup_nvlist(nvlp[i], FM_FAULT_RESOURCE, &rsrc); 1133 1134 /* 1135 * If no fru specified, get it from topo 1136 */ 1137 if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_FRU, &fru) != 0 && 1138 rsrc && topo_fmri_fru(thp, rsrc, &fru, &err) == 0) 1139 (void) nvlist_add_nvlist(flt_copy, FM_FAULT_FRU, fru); 1140 /* 1141 * If no asru specified, get it from topo 1142 */ 1143 if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_ASRU, &asru) != 0 && 1144 rsrc && topo_fmri_asru(thp, rsrc, &asru, &err) == 0) 1145 (void) nvlist_add_nvlist(flt_copy, FM_FAULT_ASRU, asru); 1146 /* 1147 * If no location specified, get it from topo 1148 */ 1149 if (nvlist_lookup_string(nvlp[i], FM_FAULT_LOCATION, 1150 &loc) != 0) { 1151 if (fru && topo_fmri_label(thp, fru, &loc, &err) == 0) 1152 (void) nvlist_add_string(flt_copy, 1153 FM_FAULT_LOCATION, loc); 1154 else if (rsrc && topo_fmri_label(thp, rsrc, &loc, 1155 &err) == 0) 1156 (void) nvlist_add_string(flt_copy, 1157 FM_FAULT_LOCATION, loc); 1158 if (loc) 1159 topo_hdl_strfree(thp, loc); 1160 } 1161 if (fru) 1162 nvlist_free(fru); 1163 if (asru) 1164 nvlist_free(asru); 1165 if (rsrc) 1166 nvlist_free(rsrc); 1167 fmd_fmri_topo_rele(thp); 1168 fmd_case_insert_suspect(cp, flt_copy); 1169 } 1170 1171 /* 1172 * copy diag_time if present 1173 */ 1174 if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME, &diag_time, 1175 &nelem2) == 0 && nelem2 >= 2) 1176 fmd_case_settime(cp, diag_time[0], diag_time[1]); 1177 1178 /* 1179 * copy DE fmri if present 1180 */ 1181 if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &de_fmri) == 0) { 1182 (void) nvlist_xdup(de_fmri, &de_fmri_dup, &fmd.d_nva); 1183 fmd_case_set_de_fmri(cp, de_fmri_dup); 1184 } 1185 1186 /* 1187 * copy injected if present 1188 */ 1189 if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED, 1190 &injected) == 0 && injected) 1191 fmd_case_set_injected(cp); 1192 1193 fmd_case_transition(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED); 1194 fmd_module_unlock(xip->xi_queue->eq_mod); 1195 } 1196 1197 /* 1198 * This function is called to create a proxy case on receipt of a list.suspect 1199 * from the diagnosing side of the transport. 1200 */ 1201 static void 1202 fmd_xprt_list_suspect(fmd_xprt_t *xp, nvlist_t *nvl) 1203 { 1204 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1205 nvlist_t **nvlp; 1206 uint_t nelem = 0, nelem2 = 0, i; 1207 int64_t *diag_time; 1208 topo_hdl_t *thp; 1209 char *class; 1210 nvlist_t *rsrc, *asru, *de_fmri, *de_fmri_dup = NULL; 1211 nvlist_t *flt_copy; 1212 int err; 1213 nvlist_t **asrua; 1214 uint8_t *proxy_asru = NULL; 1215 int got_proxy_asru = 0; 1216 int got_hc_rsrc = 0; 1217 int got_hc_asru = 0; 1218 int got_present_rsrc = 0; 1219 uint8_t *diag_asru = NULL; 1220 char *scheme; 1221 uint8_t *statusp; 1222 char *uuid, *code; 1223 fmd_case_t *cp; 1224 fmd_case_impl_t *cip; 1225 int need_update = 0; 1226 boolean_t injected; 1227 1228 if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) != 0) 1229 return; 1230 if (nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &code) != 0) 1231 return; 1232 (void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, &nvlp, 1233 &nelem); 1234 1235 /* 1236 * In order to implement FMD_XPRT_HCONLY and FMD_XPRT_HC_PRESENT_ONLY 1237 * etc we first scan the suspects to see if 1238 * - there was an asru in the received fault 1239 * - there was an hc-scheme resource in the received fault 1240 * - any hc-scheme resource in the received fault is present in the 1241 * local topology 1242 * - any hc-scheme resource in the received fault has an asru in the 1243 * local topology 1244 */ 1245 if (nelem > 0) { 1246 asrua = fmd_zalloc(sizeof (nvlist_t *) * nelem, FMD_SLEEP); 1247 proxy_asru = fmd_zalloc(sizeof (uint8_t) * nelem, FMD_SLEEP); 1248 diag_asru = fmd_zalloc(sizeof (uint8_t) * nelem, FMD_SLEEP); 1249 thp = fmd_fmri_topo_hold(TOPO_VERSION); 1250 for (i = 0; i < nelem; i++) { 1251 if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_ASRU, 1252 &asru) == 0 && asru != NULL) 1253 diag_asru[i] = 1; 1254 if (nvlist_lookup_string(nvlp[i], FM_CLASS, 1255 &class) != 0 || strncmp(class, "fault", 5) != 0) 1256 continue; 1257 /* 1258 * If there is an hc-scheme asru, use that to find the 1259 * real asru. Otherwise if there is an hc-scheme 1260 * resource, work out the old asru from that. 1261 * This order is to allow a two stage evaluation 1262 * of the asru where a fault in the diagnosing side 1263 * is in a component not visible to the proxy side, 1264 * but prevents a component that is visible from 1265 * working. So the diagnosing side sets the asru to 1266 * the latter component (in hc-scheme as the diagnosing 1267 * side doesn't know about the proxy side's virtual 1268 * schemes), and then the proxy side can convert that 1269 * to a suitable virtual scheme asru. 1270 */ 1271 if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_ASRU, 1272 &asru) == 0 && asru != NULL && 1273 nvlist_lookup_string(asru, FM_FMRI_SCHEME, 1274 &scheme) == 0 && 1275 strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) { 1276 got_hc_asru = 1; 1277 if (xip->xi_flags & FMD_XPRT_EXTERNAL) 1278 continue; 1279 if (topo_fmri_present(thp, asru, &err) != 0) 1280 got_present_rsrc = 1; 1281 if (topo_fmri_asru(thp, asru, &asrua[i], 1282 &err) == 0) { 1283 proxy_asru[i] = 1284 FMD_PROXY_ASRU_FROM_ASRU; 1285 got_proxy_asru = 1; 1286 } 1287 } else if (nvlist_lookup_nvlist(nvlp[i], 1288 FM_FAULT_RESOURCE, &rsrc) == 0 && rsrc != NULL && 1289 nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, 1290 &scheme) == 0 && 1291 strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) { 1292 got_hc_rsrc = 1; 1293 if (xip->xi_flags & FMD_XPRT_EXTERNAL) 1294 continue; 1295 if (topo_fmri_present(thp, rsrc, &err) != 0) 1296 got_present_rsrc = 1; 1297 if (topo_fmri_asru(thp, rsrc, &asrua[i], 1298 &err) == 0) { 1299 proxy_asru[i] = 1300 FMD_PROXY_ASRU_FROM_RSRC; 1301 got_proxy_asru = 1; 1302 } 1303 } 1304 } 1305 fmd_fmri_topo_rele(thp); 1306 } 1307 1308 /* 1309 * If we're set up only to report hc-scheme faults, and 1310 * there aren't any, then just drop the event. 1311 */ 1312 if (got_hc_rsrc == 0 && got_hc_asru == 0 && 1313 (xip->xi_flags & FMD_XPRT_HCONLY)) { 1314 if (nelem > 0) { 1315 fmd_free(proxy_asru, sizeof (uint8_t) * nelem); 1316 fmd_free(diag_asru, sizeof (uint8_t) * nelem); 1317 fmd_free(asrua, sizeof (nvlist_t *) * nelem); 1318 } 1319 return; 1320 } 1321 1322 /* 1323 * If we're set up only to report locally present hc-scheme 1324 * faults, and there aren't any, then just drop the event. 1325 */ 1326 if (got_present_rsrc == 0 && 1327 (xip->xi_flags & FMD_XPRT_HC_PRESENT_ONLY)) { 1328 if (nelem > 0) { 1329 for (i = 0; i < nelem; i++) 1330 if (asrua[i]) 1331 nvlist_free(asrua[i]); 1332 fmd_free(proxy_asru, sizeof (uint8_t) * nelem); 1333 fmd_free(diag_asru, sizeof (uint8_t) * nelem); 1334 fmd_free(asrua, sizeof (nvlist_t *) * nelem); 1335 } 1336 return; 1337 } 1338 1339 /* 1340 * If fmd_case_recreate() returns NULL, UUID is already known. 1341 */ 1342 fmd_module_lock(xip->xi_queue->eq_mod); 1343 if ((cp = fmd_case_recreate(xip->xi_queue->eq_mod, xp, 1344 FMD_CASE_UNSOLVED, uuid, code)) == NULL) { 1345 if (nelem > 0) { 1346 for (i = 0; i < nelem; i++) 1347 if (asrua[i]) 1348 nvlist_free(asrua[i]); 1349 fmd_free(proxy_asru, sizeof (uint8_t) * nelem); 1350 fmd_free(diag_asru, sizeof (uint8_t) * nelem); 1351 fmd_free(asrua, sizeof (nvlist_t *) * nelem); 1352 } 1353 fmd_module_unlock(xip->xi_queue->eq_mod); 1354 return; 1355 } 1356 1357 cip = (fmd_case_impl_t *)cp; 1358 cip->ci_diag_asru = diag_asru; 1359 cip->ci_proxy_asru = proxy_asru; 1360 for (i = 0; i < nelem; i++) { 1361 (void) nvlist_xdup(nvlp[i], &flt_copy, &fmd.d_nva); 1362 if (proxy_asru[i] != FMD_PROXY_ASRU_NOT_NEEDED) { 1363 /* 1364 * Copy suspects, but remove/replace asru first. Also if 1365 * the original asru was hc-scheme use that as resource. 1366 */ 1367 if (proxy_asru[i] == FMD_PROXY_ASRU_FROM_ASRU) { 1368 (void) nvlist_remove(flt_copy, 1369 FM_FAULT_RESOURCE, DATA_TYPE_NVLIST); 1370 (void) nvlist_lookup_nvlist(flt_copy, 1371 FM_FAULT_ASRU, &asru); 1372 (void) nvlist_add_nvlist(flt_copy, 1373 FM_FAULT_RESOURCE, asru); 1374 } 1375 (void) nvlist_remove(flt_copy, FM_FAULT_ASRU, 1376 DATA_TYPE_NVLIST); 1377 (void) nvlist_add_nvlist(flt_copy, FM_FAULT_ASRU, 1378 asrua[i]); 1379 nvlist_free(asrua[i]); 1380 } else if (got_hc_asru == 0 && 1381 nvlist_lookup_nvlist(flt_copy, FM_FAULT_ASRU, 1382 &asru) == 0 && asru != NULL) { 1383 /* 1384 * If we have an asru from diag side, but it's not 1385 * in hc scheme, then we can't be sure what it 1386 * represents, so mark as no retire. 1387 */ 1388 (void) nvlist_add_boolean_value(flt_copy, 1389 FM_SUSPECT_RETIRE, B_FALSE); 1390 } 1391 fmd_case_insert_suspect(cp, flt_copy); 1392 } 1393 /* 1394 * copy diag_time 1395 */ 1396 if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME, &diag_time, 1397 &nelem2) == 0 && nelem2 >= 2) 1398 fmd_case_settime(cp, diag_time[0], diag_time[1]); 1399 /* 1400 * copy DE fmri 1401 */ 1402 if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &de_fmri) == 0) { 1403 (void) nvlist_xdup(de_fmri, &de_fmri_dup, &fmd.d_nva); 1404 fmd_case_set_de_fmri(cp, de_fmri_dup); 1405 } 1406 1407 /* 1408 * copy injected if present 1409 */ 1410 if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED, 1411 &injected) == 0 && injected) 1412 fmd_case_set_injected(cp); 1413 1414 /* 1415 * Transition to solved. This will log the suspect list and create 1416 * the resource cache entries. 1417 */ 1418 fmd_case_transition(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED); 1419 1420 /* 1421 * Update status if it is not simply "all faulty" (can happen if 1422 * list.suspects are being re-sent when the transport has reconnected). 1423 */ 1424 (void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS, &statusp, 1425 &nelem); 1426 for (i = 0; i < nelem; i++) { 1427 if ((statusp[i] & (FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE | 1428 FM_SUSPECT_NOT_PRESENT | FM_SUSPECT_DEGRADED)) != 1429 FM_SUSPECT_FAULTY) 1430 need_update = 1; 1431 } 1432 if (need_update) { 1433 fmd_case_update_status(cp, statusp, cip->ci_proxy_asru, 1434 cip->ci_diag_asru); 1435 fmd_case_update_containees(cp); 1436 fmd_case_update(cp); 1437 } 1438 1439 /* 1440 * if asru on proxy side, send an update back to the diagnosing side to 1441 * update UNUSABLE/DEGRADED. 1442 */ 1443 if (got_proxy_asru) 1444 fmd_case_xprt_updated(cp); 1445 1446 if (nelem > 0) 1447 fmd_free(asrua, sizeof (nvlist_t *) * nelem); 1448 fmd_module_unlock(xip->xi_queue->eq_mod); 1449 } 1450 1451 void 1452 fmd_xprt_recv(fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt, boolean_t logonly) 1453 { 1454 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1455 const fmd_xprt_rule_t *xrp; 1456 fmd_t *dp = &fmd; 1457 1458 fmd_event_t *e; 1459 char *class, *uuid; 1460 boolean_t isproto, isereport, isireport, ishvireport, issysevent; 1461 1462 uint64_t *tod; 1463 uint8_t ttl; 1464 uint_t n; 1465 fmd_case_t *cp; 1466 1467 /* 1468 * Grab the transport lock and set the busy flag to indicate we are 1469 * busy receiving an event. If [DI]SUSPEND is pending, wait until fmd 1470 * resumes the transport before continuing on with the receive. 1471 */ 1472 (void) pthread_mutex_lock(&xip->xi_lock); 1473 1474 while (xip->xi_flags & (FMD_XPRT_DSUSPENDED | FMD_XPRT_ISUSPENDED)) { 1475 1476 if (fmd.d_signal != 0) { 1477 (void) pthread_mutex_unlock(&xip->xi_lock); 1478 return; /* fmd_destroy() is in progress */ 1479 } 1480 1481 (void) pthread_cond_wait(&xip->xi_cv, &xip->xi_lock); 1482 } 1483 1484 xip->xi_busy++; 1485 ASSERT(xip->xi_busy != 0); 1486 1487 (void) pthread_mutex_unlock(&xip->xi_lock); 1488 1489 (void) pthread_mutex_lock(&xip->xi_stats_lock); 1490 xip->xi_stats->xs_received.fmds_value.ui64++; 1491 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1492 1493 if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0) { 1494 fmd_error(EFMD_XPRT_PAYLOAD, "discarding nvlist %p: missing " 1495 "required \"%s\" payload element", (void *)nvl, FM_CLASS); 1496 1497 (void) pthread_mutex_lock(&xip->xi_stats_lock); 1498 xip->xi_stats->xs_discarded.fmds_value.ui64++; 1499 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1500 1501 nvlist_free(nvl); 1502 goto done; 1503 } 1504 1505 fmd_dprintf(FMD_DBG_XPRT, "xprt %u %s %s\n", xip->xi_id, 1506 ((logonly == FMD_B_TRUE) ? "logging" : "posting"), class); 1507 1508 isereport = (strncmp(class, FM_EREPORT_CLASS ".", 1509 sizeof (FM_EREPORT_CLASS)) == 0) ? FMD_B_TRUE : FMD_B_FALSE; 1510 1511 isireport = (strncmp(class, FM_IREPORT_CLASS ".", 1512 sizeof (FM_IREPORT_CLASS)) == 0) ? FMD_B_TRUE : FMD_B_FALSE; 1513 1514 issysevent = (strncmp(class, SYSEVENT_RSRC_CLASS, 1515 sizeof (SYSEVENT_RSRC_CLASS) - 1)) == 0 ? FMD_B_TRUE : FMD_B_FALSE; 1516 1517 if (isireport) { 1518 char *pri; 1519 1520 if (nvlist_lookup_string(nvl, FM_IREPORT_PRIORITY, &pri) == 0 && 1521 strncmp(pri, "high", 5) == 0) { 1522 ishvireport = 1; 1523 } else { 1524 ishvireport = 0; 1525 } 1526 } 1527 1528 /* 1529 * The logonly flag should only be set for ereports. 1530 */ 1531 if (logonly == FMD_B_TRUE && isereport == FMD_B_FALSE) { 1532 fmd_error(EFMD_XPRT_INVAL, "discarding nvlist %p: " 1533 "logonly flag is not valid for class %s", 1534 (void *)nvl, class); 1535 1536 (void) pthread_mutex_lock(&xip->xi_stats_lock); 1537 xip->xi_stats->xs_discarded.fmds_value.ui64++; 1538 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1539 1540 nvlist_free(nvl); 1541 goto done; 1542 } 1543 1544 /* 1545 * If a time-to-live value is present in the event and is zero, drop 1546 * the event and bump xs_timeouts. Otherwise decrement the TTL value. 1547 */ 1548 if (nvlist_lookup_uint8(nvl, FMD_EVN_TTL, &ttl) == 0) { 1549 if (ttl == 0) { 1550 fmd_dprintf(FMD_DBG_XPRT, "xprt %u nvlist %p (%s) " 1551 "timeout: event received with ttl=0\n", 1552 xip->xi_id, (void *)nvl, class); 1553 1554 (void) pthread_mutex_lock(&xip->xi_stats_lock); 1555 xip->xi_stats->xs_timeouts.fmds_value.ui64++; 1556 (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1557 1558 nvlist_free(nvl); 1559 goto done; 1560 } 1561 (void) nvlist_remove(nvl, FMD_EVN_TTL, DATA_TYPE_UINT8); 1562 (void) nvlist_add_uint8(nvl, FMD_EVN_TTL, ttl - 1); 1563 } 1564 1565 /* 1566 * If we are using the native system clock, the underlying transport 1567 * code can provide a tighter event time bound by telling us when the 1568 * event was enqueued. If we're using simulated clocks, this time 1569 * has no meaning to us, so just reset the value to use HRT_NOW. 1570 */ 1571 if (dp->d_clockops != &fmd_timeops_native) 1572 hrt = FMD_HRT_NOW; 1573 1574 /* 1575 * If an event's class is in the FMD_CTL_CLASS family, then create a 1576 * control event. If a FMD_EVN_TOD member is found, create a protocol 1577 * event using this time. Otherwise create a protocol event using hrt. 1578 */ 1579 isproto = (strncmp(class, FMD_CTL_CLASS, FMD_CTL_CLASS_LEN) == 0) ? 1580 FMD_B_FALSE : FMD_B_TRUE; 1581 if (isproto == FMD_B_FALSE) 1582 e = fmd_event_create(FMD_EVT_CTL, hrt, nvl, fmd_ctl_init(nvl)); 1583 else if (nvlist_lookup_uint64_array(nvl, FMD_EVN_TOD, &tod, &n) != 0) 1584 e = fmd_event_create(FMD_EVT_PROTOCOL, hrt, nvl, class); 1585 else { 1586 e = fmd_event_recreate(FMD_EVT_PROTOCOL, 1587 NULL, nvl, class, NULL, 0, 0); 1588 } 1589 1590 /* 1591 * If the debug log is enabled, create a temporary event, log it to the 1592 * debug log, and then reset the underlying state of the event. 1593 */ 1594 if (xip->xi_log != NULL) { 1595 fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 1596 1597 fmd_log_append(xip->xi_log, e, NULL); 1598 1599 ep->ev_flags |= FMD_EVF_VOLATILE; 1600 ep->ev_off = 0; 1601 ep->ev_len = 0; 1602 1603 if (ep->ev_log != NULL) { 1604 fmd_log_rele(ep->ev_log); 1605 ep->ev_log = NULL; 1606 } 1607 } 1608 1609 /* 1610 * Iterate over the rules for the current state trying to match the 1611 * event class to one of our special rules. If a rule is matched, the 1612 * event is consumed and not dispatched to other modules. If the rule 1613 * set ends without matching an event, we fall through to dispatching. 1614 */ 1615 for (xrp = xip->xi_state; xrp->xr_class != NULL; xrp++) { 1616 if (fmd_event_match(e, FMD_EVT_PROTOCOL, xrp->xr_class)) { 1617 fmd_event_hold(e); 1618 xrp->xr_func(xip, nvl); 1619 fmd_event_rele(e); 1620 goto done; 1621 } 1622 } 1623 1624 /* 1625 * Record ereports and ireports in the log. This code will 1626 * be replaced later with a per-transport intent log instead. 1627 */ 1628 if (isereport == FMD_B_TRUE || isireport == FMD_B_TRUE || 1629 issysevent == B_TRUE) { 1630 pthread_rwlock_t *lockp; 1631 fmd_log_t *lp; 1632 1633 if (isereport == FMD_B_TRUE) { 1634 lp = fmd.d_errlog; 1635 lockp = &fmd.d_log_lock; 1636 } else { 1637 if (ishvireport || issysevent) { 1638 lp = fmd.d_hvilog; 1639 lockp = &fmd.d_hvilog_lock; 1640 } else { 1641 lp = fmd.d_ilog; 1642 lockp = &fmd.d_ilog_lock; 1643 } 1644 } 1645 1646 (void) pthread_rwlock_rdlock(lockp); 1647 fmd_log_append(lp, e, NULL); 1648 (void) pthread_rwlock_unlock(lockp); 1649 } 1650 1651 /* 1652 * If a list.suspect event is received, create a case for the specified 1653 * UUID in the case hash, with the transport module as its owner. 1654 */ 1655 if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_SUSPECT_CLASS)) { 1656 if (xip->xi_flags & FMD_XPRT_CACHE_AS_LOCAL) 1657 fmd_xprt_list_suspect_local(xp, nvl); 1658 else 1659 fmd_xprt_list_suspect(xp, nvl); 1660 fmd_event_hold(e); 1661 fmd_event_rele(e); 1662 goto done; 1663 } 1664 1665 /* 1666 * If a list.updated or list.repaired event is received, update the 1667 * resource cache status and the local case. 1668 */ 1669 if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_REPAIRED_CLASS) || 1670 fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_UPDATED_CLASS)) { 1671 uint8_t *statusp; 1672 uint_t nelem = 0; 1673 1674 (void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS, 1675 &statusp, &nelem); 1676 fmd_module_lock(xip->xi_queue->eq_mod); 1677 if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) == 0 && 1678 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 1679 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1680 if (cip->ci_xprt != NULL) { 1681 fmd_case_update_status(cp, statusp, 1682 cip->ci_proxy_asru, cip->ci_diag_asru); 1683 fmd_case_update_containees(cp); 1684 fmd_case_update(cp); 1685 } 1686 fmd_case_rele(cp); 1687 } 1688 fmd_module_unlock(xip->xi_queue->eq_mod); 1689 fmd_event_hold(e); 1690 fmd_event_rele(e); 1691 goto done; 1692 } 1693 1694 /* 1695 * If a list.isolated event is received, update resource cache status 1696 */ 1697 if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_ISOLATED_CLASS)) { 1698 uint8_t *statusp; 1699 uint_t nelem = 0; 1700 1701 (void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS, 1702 &statusp, &nelem); 1703 fmd_module_lock(xip->xi_queue->eq_mod); 1704 if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) == 0 && 1705 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 1706 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1707 if (cip->ci_xprt != NULL) 1708 fmd_case_update_status(cp, statusp, 1709 cip->ci_proxy_asru, cip->ci_diag_asru); 1710 fmd_case_rele(cp); 1711 } 1712 fmd_module_unlock(xip->xi_queue->eq_mod); 1713 fmd_event_hold(e); 1714 fmd_event_rele(e); 1715 goto done; 1716 } 1717 1718 /* 1719 * If a list.resolved event is received, resolve the local case. 1720 */ 1721 if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_RESOLVED_CLASS)) { 1722 fmd_module_lock(xip->xi_queue->eq_mod); 1723 if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) == 0 && 1724 (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 1725 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1726 if (cip->ci_xprt != NULL) 1727 fmd_case_transition(cp, (cip->ci_state == 1728 FMD_CASE_REPAIRED) ? FMD_CASE_RESOLVED : 1729 (cip->ci_state == FMD_CASE_CLOSED) ? 1730 FMD_CASE_REPAIRED : FMD_CASE_CLOSE_WAIT, 1731 FMD_CF_RESOLVED); 1732 fmd_case_rele(cp); 1733 } 1734 fmd_module_unlock(xip->xi_queue->eq_mod); 1735 fmd_event_hold(e); 1736 fmd_event_rele(e); 1737 goto done; 1738 } 1739 1740 if (logonly == FMD_B_TRUE || (xip->xi_flags & FMD_XPRT_EXTERNAL)) { 1741 /* 1742 * Don't proxy ereports on an EXTERNAL transport - we won't 1743 * know how to diagnose them with the wrong topology. Note 1744 * that here (and above) we have to hold/release the event in 1745 * order for it to be freed. 1746 */ 1747 fmd_event_hold(e); 1748 fmd_event_rele(e); 1749 } else if (isproto == FMD_B_TRUE) 1750 fmd_dispq_dispatch(dp->d_disp, e, class); 1751 else 1752 fmd_modhash_dispatch(dp->d_mod_hash, e); 1753 done: 1754 (void) pthread_mutex_lock(&xip->xi_lock); 1755 1756 ASSERT(xip->xi_busy != 0); 1757 xip->xi_busy--; 1758 1759 (void) pthread_cond_broadcast(&xip->xi_cv); 1760 (void) pthread_mutex_unlock(&xip->xi_lock); 1761 } 1762 1763 void 1764 fmd_xprt_uuclose(fmd_xprt_t *xp, const char *uuid) 1765 { 1766 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1767 1768 fmd_event_t *e; 1769 nvlist_t *nvl; 1770 char *s; 1771 1772 if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 1773 return; /* read-only transports do not proxy uuclose */ 1774 1775 TRACE((FMD_DBG_XPRT, "xprt %u closing case %s\n", xip->xi_id, uuid)); 1776 1777 nvl = fmd_protocol_xprt_uuclose(xip->xi_queue->eq_mod, 1778 "resource.fm.xprt.uuclose", xip->xi_version, uuid); 1779 1780 (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 1781 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 1782 fmd_eventq_insert_at_time(xip->xi_queue, e); 1783 } 1784 1785 /* 1786 * On proxy side, send back uuresolved request to diagnosing side 1787 */ 1788 void 1789 fmd_xprt_uuresolved(fmd_xprt_t *xp, const char *uuid) 1790 { 1791 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1792 1793 fmd_event_t *e; 1794 nvlist_t *nvl; 1795 char *s; 1796 1797 if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 1798 return; /* read-only transports do not proxy uuresolved */ 1799 1800 TRACE((FMD_DBG_XPRT, "xprt %u resolving case %s\n", xip->xi_id, uuid)); 1801 1802 nvl = fmd_protocol_xprt_uuresolved(xip->xi_queue->eq_mod, 1803 "resource.fm.xprt.uuresolved", xip->xi_version, uuid); 1804 1805 (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 1806 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 1807 fmd_eventq_insert_at_time(xip->xi_queue, e); 1808 } 1809 1810 /* 1811 * On proxy side, send back repair/acquit/etc request to diagnosing side 1812 */ 1813 void 1814 fmd_xprt_updated(fmd_xprt_t *xp, const char *uuid, uint8_t *statusp, 1815 uint8_t *has_asrup, uint_t nelem) 1816 { 1817 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1818 1819 fmd_event_t *e; 1820 nvlist_t *nvl; 1821 char *s; 1822 1823 if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 1824 return; /* read-only transports do not support remote repairs */ 1825 1826 TRACE((FMD_DBG_XPRT, "xprt %u updating case %s\n", xip->xi_id, uuid)); 1827 1828 nvl = fmd_protocol_xprt_updated(xip->xi_queue->eq_mod, 1829 "resource.fm.xprt.updated", xip->xi_version, uuid, statusp, 1830 has_asrup, nelem); 1831 1832 (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 1833 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 1834 fmd_eventq_insert_at_time(xip->xi_queue, e); 1835 } 1836 1837 /* 1838 * Insert the specified class into our remote subscription hash. If the class 1839 * is already present, bump the reference count; otherwise add it to the hash 1840 * and then enqueue an event for our remote peer to proxy our subscription. 1841 */ 1842 void 1843 fmd_xprt_subscribe(fmd_xprt_t *xp, const char *class) 1844 { 1845 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1846 1847 uint_t refs; 1848 nvlist_t *nvl; 1849 fmd_event_t *e; 1850 char *s; 1851 1852 if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 1853 return; /* read-only transports do not proxy subscriptions */ 1854 1855 if (!(xip->xi_flags & FMD_XPRT_SUBSCRIBER)) 1856 return; /* transport is not yet an active subscriber */ 1857 1858 (void) pthread_mutex_lock(&xip->xi_lock); 1859 refs = fmd_xprt_class_hash_insert(xip, &xip->xi_rsub, class); 1860 (void) pthread_mutex_unlock(&xip->xi_lock); 1861 1862 if (refs > 1) 1863 return; /* we've already asked our peer for this subscription */ 1864 1865 fmd_dprintf(FMD_DBG_XPRT, 1866 "xprt %u subscribing to %s\n", xip->xi_id, class); 1867 1868 nvl = fmd_protocol_xprt_sub(xip->xi_queue->eq_mod, 1869 "resource.fm.xprt.subscribe", xip->xi_version, class); 1870 1871 (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 1872 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 1873 fmd_eventq_insert_at_time(xip->xi_queue, e); 1874 } 1875 1876 /* 1877 * Delete the specified class from the remote subscription hash. If the 1878 * reference count drops to zero, ask our remote peer to unsubscribe by proxy. 1879 */ 1880 void 1881 fmd_xprt_unsubscribe(fmd_xprt_t *xp, const char *class) 1882 { 1883 fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1884 1885 uint_t refs; 1886 nvlist_t *nvl; 1887 fmd_event_t *e; 1888 char *s; 1889 1890 if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 1891 return; /* read-only transports do not proxy subscriptions */ 1892 1893 if (!(xip->xi_flags & FMD_XPRT_SUBSCRIBER)) 1894 return; /* transport is not yet an active subscriber */ 1895 1896 /* 1897 * If the subscription reference count drops to zero in xi_rsub, insert 1898 * an entry into the xi_usub hash indicating we await an unsuback event. 1899 */ 1900 (void) pthread_mutex_lock(&xip->xi_lock); 1901 1902 if ((refs = fmd_xprt_class_hash_delete(xip, &xip->xi_rsub, class)) == 0) 1903 (void) fmd_xprt_class_hash_insert(xip, &xip->xi_usub, class); 1904 1905 (void) pthread_mutex_unlock(&xip->xi_lock); 1906 1907 if (refs != 0) 1908 return; /* other subscriptions for this class still active */ 1909 1910 fmd_dprintf(FMD_DBG_XPRT, 1911 "xprt %u unsubscribing from %s\n", xip->xi_id, class); 1912 1913 nvl = fmd_protocol_xprt_sub(xip->xi_queue->eq_mod, 1914 "resource.fm.xprt.unsubscribe", xip->xi_version, class); 1915 1916 (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 1917 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 1918 fmd_eventq_insert_at_time(xip->xi_queue, e); 1919 } 1920 1921 static void 1922 fmd_xprt_subscribe_xid(fmd_idspace_t *ids, id_t id, void *class) 1923 { 1924 fmd_xprt_t *xp; 1925 1926 if ((xp = fmd_idspace_hold(ids, id)) != NULL) { 1927 fmd_xprt_subscribe(xp, class); 1928 fmd_idspace_rele(ids, id); 1929 } 1930 } 1931 1932 void 1933 fmd_xprt_subscribe_all(const char *class) 1934 { 1935 fmd_idspace_t *ids = fmd.d_xprt_ids; 1936 1937 if (ids->ids_count != 0) 1938 fmd_idspace_apply(ids, fmd_xprt_subscribe_xid, (void *)class); 1939 } 1940 1941 static void 1942 fmd_xprt_unsubscribe_xid(fmd_idspace_t *ids, id_t id, void *class) 1943 { 1944 fmd_xprt_t *xp; 1945 1946 if ((xp = fmd_idspace_hold(ids, id)) != NULL) { 1947 fmd_xprt_unsubscribe(xp, class); 1948 fmd_idspace_rele(ids, id); 1949 } 1950 } 1951 1952 void 1953 fmd_xprt_unsubscribe_all(const char *class) 1954 { 1955 fmd_idspace_t *ids = fmd.d_xprt_ids; 1956 1957 if (ids->ids_count != 0) 1958 fmd_idspace_apply(ids, fmd_xprt_unsubscribe_xid, (void *)class); 1959 } 1960 1961 /*ARGSUSED*/ 1962 static void 1963 fmd_xprt_suspend_xid(fmd_idspace_t *ids, id_t id, void *arg) 1964 { 1965 fmd_xprt_t *xp; 1966 1967 if ((xp = fmd_idspace_hold(ids, id)) != NULL) { 1968 fmd_xprt_xsuspend(xp, FMD_XPRT_DSUSPENDED); 1969 fmd_idspace_rele(ids, id); 1970 } 1971 } 1972 1973 void 1974 fmd_xprt_suspend_all(void) 1975 { 1976 fmd_idspace_t *ids = fmd.d_xprt_ids; 1977 1978 (void) pthread_mutex_lock(&fmd.d_xprt_lock); 1979 1980 if (fmd.d_xprt_suspend++ != 0) { 1981 (void) pthread_mutex_unlock(&fmd.d_xprt_lock); 1982 return; /* already suspended */ 1983 } 1984 1985 if (ids->ids_count != 0) 1986 fmd_idspace_apply(ids, fmd_xprt_suspend_xid, NULL); 1987 1988 (void) pthread_mutex_unlock(&fmd.d_xprt_lock); 1989 } 1990 1991 /*ARGSUSED*/ 1992 static void 1993 fmd_xprt_resume_xid(fmd_idspace_t *ids, id_t id, void *arg) 1994 { 1995 fmd_xprt_t *xp; 1996 1997 if ((xp = fmd_idspace_hold(ids, id)) != NULL) { 1998 fmd_xprt_xresume(xp, FMD_XPRT_DSUSPENDED); 1999 fmd_idspace_rele(ids, id); 2000 } 2001 } 2002 2003 void 2004 fmd_xprt_resume_all(void) 2005 { 2006 fmd_idspace_t *ids = fmd.d_xprt_ids; 2007 2008 (void) pthread_mutex_lock(&fmd.d_xprt_lock); 2009 2010 if (fmd.d_xprt_suspend == 0) 2011 fmd_panic("fmd_xprt_suspend/resume_all mismatch\n"); 2012 2013 if (--fmd.d_xprt_suspend != 0) { 2014 (void) pthread_mutex_unlock(&fmd.d_xprt_lock); 2015 return; /* not ready to be resumed */ 2016 } 2017 2018 if (ids->ids_count != 0) 2019 fmd_idspace_apply(ids, fmd_xprt_resume_xid, NULL); 2020 2021 (void) pthread_mutex_unlock(&fmd.d_xprt_lock); 2022 } 2023