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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* 29 * etm.c FMA Event Transport Module implementation, a plugin of FMD 30 * for sun4v/Ontario 31 * 32 * plugin for sending/receiving FMA events to/from service processor 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 /* 38 * --------------------------------- includes -------------------------------- 39 */ 40 41 #include <sys/fm/protocol.h> 42 #include <sys/fm/util.h> 43 #include <netinet/in.h> 44 #include <fm/fmd_api.h> 45 46 #include "etm_xport_api.h" 47 #include "etm_etm_proto.h" 48 #include "etm_impl.h" 49 50 #include <pthread.h> 51 #include <signal.h> 52 #include <stropts.h> 53 #include <locale.h> 54 #include <strings.h> 55 #include <stdlib.h> 56 #include <unistd.h> 57 #include <limits.h> 58 #include <values.h> 59 #include <alloca.h> 60 #include <errno.h> 61 #include <fcntl.h> 62 #include <time.h> 63 64 /* 65 * ----------------------------- forward decls ------------------------------- 66 */ 67 68 static void 69 etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class); 70 71 /* 72 * ------------------------- data structs for FMD ---------------------------- 73 */ 74 75 static const fmd_hdl_ops_t fmd_ops = { 76 etm_recv, /* fmdo_recv */ 77 NULL, /* fmdo_timeout */ 78 NULL, /* fmdo_close */ 79 NULL, /* fmdo_stats */ 80 NULL, /* fmdo_gc */ 81 NULL, /* fmdo_send */ 82 }; 83 84 static const fmd_prop_t fmd_props[] = { 85 { ETM_PROP_NM_XPORT_ADDRS, FMD_TYPE_STRING, "" }, 86 { ETM_PROP_NM_DEBUG_LVL, FMD_TYPE_INT32, "0" }, 87 { ETM_PROP_NM_DEBUG_MAX_EV_CNT, FMD_TYPE_INT32, "-1" }, 88 { NULL, 0, NULL } 89 }; 90 91 static const fmd_hdl_info_t fmd_info = { 92 "FMA Event Transport Module", "1.0", &fmd_ops, fmd_props 93 }; 94 95 /* 96 * ----------------------- private consts and defns -------------------------- 97 */ 98 99 /* misc buffer for variable sized protocol header fields */ 100 101 #define ETM_MISC_BUF_SZ (4 * 1024) 102 103 /* try limit for IO operations w/ capped exp backoff sleep on retry */ 104 105 /* 106 * Design_Note: ETM will potentially retry forever IO operations that the 107 * transport fails with EAGAIN (aka EWOULDBLOCK) rather than 108 * giving up after some number of seconds. This avoids 109 * dropping FMA events while the service processor is down, 110 * but at the risk of pending fmdo_recv() forever and 111 * overflowing FMD's event queue for ETM. 112 * A future TBD enhancement would be to always recv 113 * and send each ETM msg in a single read/write() to reduce 114 * the risk of failure between ETM msg hdr and body, 115 * assuming the MTU_SZ is large enough. 116 */ 117 118 #define ETM_TRY_MAX_CNT (MAXINT - 1) 119 #define ETM_TRY_BACKOFF_RATE (4) 120 #define ETM_TRY_BACKOFF_CAP (60) 121 122 /* amount to increment protocol transaction id on each new send */ 123 124 #define ETM_XID_INC (2) 125 126 /* 127 * ---------------------------- global data ---------------------------------- 128 */ 129 130 static int 131 etm_debug_lvl = 0; /* debug level: 0 is off, 1 is on, 2 is more, etc */ 132 133 static int 134 etm_debug_max_ev_cnt = -1; /* max allowed event count for debugging */ 135 136 static fmd_xprt_t 137 *etm_fmd_xprt = NULL; /* FMD transport layer handle */ 138 139 static pthread_t 140 etm_svr_tid = NULL; /* thread id of connection acceptance server */ 141 142 static volatile int 143 etm_is_dying = 0; /* bool for dying (killing self) */ 144 145 static uint32_t 146 etm_xid_cur = 0; /* current transaction id for sends */ 147 148 static uint32_t 149 etm_xid_ping = 0; /* xid of last CONTROL msg sent requesting ping */ 150 151 static uint32_t 152 etm_xid_ver_negot = 0; /* xid of last CONTROL msg sent requesting ver negot */ 153 154 static uint32_t 155 etm_xid_posted_ev = 0; /* xid of last FMA_EVENT msg/event posted OK to FMD */ 156 157 static uint8_t 158 etm_resp_ver = ETM_PROTO_V1; /* proto ver [negotiated] for msg sends */ 159 160 static struct stats { 161 162 /* ETM msg counters */ 163 164 fmd_stat_t etm_rd_hdr_fmaevent; 165 fmd_stat_t etm_rd_hdr_control; 166 fmd_stat_t etm_rd_hdr_response; 167 fmd_stat_t etm_rd_body_fmaevent; 168 fmd_stat_t etm_rd_body_control; 169 fmd_stat_t etm_rd_body_response; 170 fmd_stat_t etm_wr_hdr_fmaevent; 171 fmd_stat_t etm_wr_hdr_control; 172 fmd_stat_t etm_wr_hdr_response; 173 fmd_stat_t etm_wr_body_fmaevent; 174 fmd_stat_t etm_wr_body_control; 175 fmd_stat_t etm_wr_body_response; 176 177 /* ETM byte counters */ 178 179 fmd_stat_t etm_wr_fmd_bytes; 180 fmd_stat_t etm_rd_fmd_bytes; 181 fmd_stat_t etm_wr_xport_bytes; 182 fmd_stat_t etm_rd_xport_bytes; 183 184 fmd_stat_t etm_magic_drop_bytes; 185 186 /* ETM [dropped] FMA event counters */ 187 188 fmd_stat_t etm_rd_fmd_fmaevent; 189 fmd_stat_t etm_wr_fmd_fmaevent; 190 191 fmd_stat_t etm_rd_drop_fmaevent; 192 fmd_stat_t etm_wr_drop_fmaevent; 193 194 fmd_stat_t etm_rd_dup_fmaevent; 195 fmd_stat_t etm_wr_dup_fmaevent; 196 197 /* ETM protocol failures */ 198 199 fmd_stat_t etm_magic_bad; 200 fmd_stat_t etm_ver_bad; 201 fmd_stat_t etm_msgtype_bad; 202 fmd_stat_t etm_subtype_bad; 203 fmd_stat_t etm_xid_bad; 204 fmd_stat_t etm_fmaeventlen_bad; 205 fmd_stat_t etm_respcode_bad; 206 fmd_stat_t etm_timeout_bad; 207 fmd_stat_t etm_evlens_bad; 208 209 /* IO operation failures */ 210 211 fmd_stat_t etm_xport_wr_fail; 212 fmd_stat_t etm_xport_rd_fail; 213 fmd_stat_t etm_xport_pk_fail; 214 215 /* IO operation retries */ 216 217 fmd_stat_t etm_xport_wr_retry; 218 fmd_stat_t etm_xport_rd_retry; 219 fmd_stat_t etm_xport_pk_retry; 220 221 /* system and library failures */ 222 223 fmd_stat_t etm_os_nvlist_pack_fail; 224 fmd_stat_t etm_os_nvlist_unpack_fail; 225 fmd_stat_t etm_os_nvlist_size_fail; 226 fmd_stat_t etm_os_pthread_create_fail; 227 228 /* xport API failures */ 229 230 fmd_stat_t etm_xport_get_ev_addrv_fail; 231 fmd_stat_t etm_xport_open_fail; 232 fmd_stat_t etm_xport_close_fail; 233 fmd_stat_t etm_xport_accept_fail; 234 fmd_stat_t etm_xport_open_retry; 235 236 /* FMD entry point bad arguments */ 237 238 fmd_stat_t etm_fmd_recv_badargs; 239 fmd_stat_t etm_fmd_init_badargs; 240 fmd_stat_t etm_fmd_fini_badargs; 241 242 } etm_stats = { 243 244 /* ETM msg counters */ 245 246 { "etm_rd_hdr_fmaevent", FMD_TYPE_UINT64, 247 "ETM fmaevent msg headers rcvd from xport" }, 248 { "etm_rd_hdr_control", FMD_TYPE_UINT64, 249 "ETM control msg headers rcvd from xport" }, 250 { "etm_rd_hdr_response", FMD_TYPE_UINT64, 251 "ETM response msg headers rcvd from xport" }, 252 { "etm_rd_body_fmaevent", FMD_TYPE_UINT64, 253 "ETM fmaevent msg bodies rcvd from xport" }, 254 { "etm_rd_body_control", FMD_TYPE_UINT64, 255 "ETM control msg bodies rcvd from xport" }, 256 { "etm_rd_body_response", FMD_TYPE_UINT64, 257 "ETM response msg bodies rcvd from xport" }, 258 { "etm_wr_hdr_fmaevent", FMD_TYPE_UINT64, 259 "ETM fmaevent msg headers sent to xport" }, 260 { "etm_wr_hdr_control", FMD_TYPE_UINT64, 261 "ETM control msg headers sent to xport" }, 262 { "etm_wr_hdr_response", FMD_TYPE_UINT64, 263 "ETM response msg headers sent to xport" }, 264 { "etm_wr_body_fmaevent", FMD_TYPE_UINT64, 265 "ETM fmaevent msg bodies sent to xport" }, 266 { "etm_wr_body_control", FMD_TYPE_UINT64, 267 "ETM control msg bodies sent to xport" }, 268 { "etm_wr_body_response", FMD_TYPE_UINT64, 269 "ETM response msg bodies sent to xport" }, 270 271 /* ETM byte counters */ 272 273 { "etm_wr_fmd_bytes", FMD_TYPE_UINT64, 274 "bytes of FMA events sent to FMD" }, 275 { "etm_rd_fmd_bytes", FMD_TYPE_UINT64, 276 "bytes of FMA events rcvd from FMD" }, 277 { "etm_wr_xport_bytes", FMD_TYPE_UINT64, 278 "bytes of FMA events sent to xport" }, 279 { "etm_rd_xport_bytes", FMD_TYPE_UINT64, 280 "bytes of FMA events rcvd from xport" }, 281 282 { "etm_magic_drop_bytes", FMD_TYPE_UINT64, 283 "bytes dropped from xport pre magic num" }, 284 285 /* ETM [dropped] FMA event counters */ 286 287 { "etm_rd_fmd_fmaevent", FMD_TYPE_UINT64, 288 "FMA events rcvd from FMD" }, 289 { "etm_wr_fmd_fmaevent", FMD_TYPE_UINT64, 290 "FMA events sent to FMD" }, 291 292 { "etm_rd_drop_fmaevent", FMD_TYPE_UINT64, 293 "dropped FMA events from xport" }, 294 { "etm_wr_drop_fmaevent", FMD_TYPE_UINT64, 295 "dropped FMA events to xport" }, 296 297 { "etm_rd_dup_fmaevent", FMD_TYPE_UINT64, 298 "duplicate FMA events from xport" }, 299 { "etm_wr_dup_fmaevent", FMD_TYPE_UINT64, 300 "duplicate FMA events to xport" }, 301 302 /* ETM protocol failures */ 303 304 { "etm_magic_bad", FMD_TYPE_UINT64, 305 "ETM msgs w/ invalid magic num" }, 306 { "etm_ver_bad", FMD_TYPE_UINT64, 307 "ETM msgs w/ invalid protocol version" }, 308 { "etm_msgtype_bad", FMD_TYPE_UINT64, 309 "ETM msgs w/ invalid message type" }, 310 { "etm_subtype_bad", FMD_TYPE_UINT64, 311 "ETM msgs w/ invalid sub type" }, 312 { "etm_xid_bad", FMD_TYPE_UINT64, 313 "ETM msgs w/ unmatched xid" }, 314 { "etm_fmaeventlen_bad", FMD_TYPE_UINT64, 315 "ETM msgs w/ invalid FMA event length" }, 316 { "etm_respcode_bad", FMD_TYPE_UINT64, 317 "ETM msgs w/ invalid response code" }, 318 { "etm_timeout_bad", FMD_TYPE_UINT64, 319 "ETM msgs w/ invalid timeout value" }, 320 { "etm_evlens_bad", FMD_TYPE_UINT64, 321 "ETM msgs w/ too many event lengths" }, 322 323 /* IO operation failures */ 324 325 { "etm_xport_wr_fail", FMD_TYPE_UINT64, 326 "xport write failures" }, 327 { "etm_xport_rd_fail", FMD_TYPE_UINT64, 328 "xport read failures" }, 329 { "etm_xport_pk_fail", FMD_TYPE_UINT64, 330 "xport peek failures" }, 331 332 /* IO operation retries */ 333 334 { "etm_xport_wr_retry", FMD_TYPE_UINT64, 335 "xport write retries" }, 336 { "etm_xport_rd_retry", FMD_TYPE_UINT64, 337 "xport read retries" }, 338 { "etm_xport_pk_retry", FMD_TYPE_UINT64, 339 "xport peek retries" }, 340 341 /* system and library failures */ 342 343 { "etm_os_nvlist_pack_fail", FMD_TYPE_UINT64, 344 "nvlist_pack failures" }, 345 { "etm_os_nvlist_unpack_fail", FMD_TYPE_UINT64, 346 "nvlist_unpack failures" }, 347 { "etm_os_nvlist_size_fail", FMD_TYPE_UINT64, 348 "nvlist_size failures" }, 349 { "etm_os_pthread_create_fail", FMD_TYPE_UINT64, 350 "pthread_create failures" }, 351 352 /* transport API failures */ 353 354 { "etm_xport_get_ev_addrv_fail", FMD_TYPE_UINT64, 355 "xport get event addrv API failures" }, 356 { "etm_xport_open_fail", FMD_TYPE_UINT64, 357 "xport open API failures" }, 358 { "etm_xport_close_fail", FMD_TYPE_UINT64, 359 "xport close API failures" }, 360 { "etm_xport_accept_fail", FMD_TYPE_UINT64, 361 "xport accept API failures" }, 362 { "etm_xport_open_retry", FMD_TYPE_UINT64, 363 "xport open API retries" }, 364 365 /* FMD entry point bad arguments */ 366 367 { "etm_fmd_recv_badargs", FMD_TYPE_UINT64, 368 "bad arguments from fmd_recv entry point" }, 369 { "etm_fmd_init_badargs", FMD_TYPE_UINT64, 370 "bad arguments from fmd_init entry point" }, 371 { "etm_fmd_fini_badargs", FMD_TYPE_UINT64, 372 "bad arguments from fmd_fini entry point" } 373 }; 374 375 /* 376 * -------------------------- support functions ------------------------------ 377 */ 378 379 /* 380 * Design_Note: Each failure worth reporting to FMD should be done using 381 * a single call to fmd_hdl_error() as it logs an FMA event 382 * for each call. Also be aware that all the fmd_hdl_*() 383 * format strings currently use platform specific *printf() 384 * routines; so "%p" under Solaris does not prepend "0x" to 385 * the outputted hex digits, while Linux and VxWorks do. 386 */ 387 388 /* 389 * etm_show_time - display the current time of day (for debugging) using 390 * the given FMD module handle and annotation string 391 */ 392 393 static void 394 etm_show_time(fmd_hdl_t *hdl, char *note_str) 395 { 396 struct timeval tmv; /* timeval */ 397 398 (void) gettimeofday(&tmv, NULL); 399 fmd_hdl_debug(hdl, "info: %s: cur Unix Epoch time %d.%06d\n", 400 note_str, tmv.tv_sec, tmv.tv_usec); 401 402 } /* etm_show_time() */ 403 404 /* 405 * etm_hexdump - hexdump the given buffer (for debugging) using 406 * the given FMD module handle 407 */ 408 409 static void 410 etm_hexdump(fmd_hdl_t *hdl, void *buf, size_t byte_cnt) 411 { 412 uint8_t *bp; /* byte ptr */ 413 int i, j; /* index */ 414 char cb[80]; /* char buf */ 415 unsigned int n; /* a byte of data for sprintf() */ 416 417 bp = buf; 418 j = 0; 419 420 /* 421 * Design_Note: fmd_hdl_debug() auto adds a newline if missing; 422 * hence cb exists to accumulate a longer string. 423 */ 424 425 for (i = 1; i <= byte_cnt; i++) { 426 n = *bp++; 427 (void) sprintf(&cb[j], "%2.2x ", n); 428 j += 3; 429 /* add a newline every 16 bytes or at the buffer's end */ 430 if (((i % 16) == 0) || (i >= byte_cnt)) { 431 cb[j-1] = '\0'; 432 fmd_hdl_debug(hdl, "%s\n", cb); 433 j = 0; 434 } 435 } /* for each byte in the buffer */ 436 437 } /* etm_hexdump() */ 438 439 /* 440 * etm_sleep - sleep the caller for the given number of seconds, 441 * return 0 or -errno value 442 * 443 * Design_Note: To avoid interfering with FMD's signal mask (SIGALRM) 444 * do not use [Solaris] sleep(3C) and instead use 445 * pthread_cond_wait() or nanosleep(), both of which 446 * are POSIX spec-ed to leave signal masks alone. 447 * This is needed for Solaris and Linux (domain and SP). 448 */ 449 450 static int 451 etm_sleep(unsigned sleep_sec) 452 { 453 struct timespec tms; /* for nanosleep() */ 454 455 tms.tv_sec = sleep_sec; 456 tms.tv_nsec = 0; 457 458 if (nanosleep(&tms, NULL) < 0) { 459 /* errno assumed set by above call */ 460 return (-errno); 461 } 462 return (0); 463 464 } /* etm_sleep() */ 465 466 /* 467 * etm_conn_open - open a connection to the given transport address, 468 * return 0 and the opened connection handle 469 * or -errno value 470 * 471 * caveats: the err_substr is used in failure cases for calling 472 * fmd_hdl_error() 473 */ 474 475 static int 476 etm_conn_open(fmd_hdl_t *hdl, char *err_substr, 477 etm_xport_addr_t addr, etm_xport_conn_t *connp) 478 { 479 etm_xport_conn_t conn; /* connection to return */ 480 int nev; /* -errno value */ 481 482 if ((conn = etm_xport_open(hdl, addr)) == NULL) { 483 nev = (-errno); 484 fmd_hdl_error(hdl, "error: %s: errno %d\n", 485 err_substr, errno); 486 etm_stats.etm_xport_open_fail.fmds_value.ui64++; 487 return (nev); 488 } else { 489 *connp = conn; 490 return (0); 491 } 492 } /* etm_conn_open() */ 493 494 /* 495 * etm_conn_close - close the given connection, 496 * return 0 or -errno value 497 * 498 * caveats: the err_substr is used in failure cases for calling 499 * fmd_hdl_error() 500 */ 501 502 static int 503 etm_conn_close(fmd_hdl_t *hdl, char *err_substr, etm_xport_conn_t conn) 504 { 505 int nev; /* -errno value */ 506 507 if (etm_xport_close(hdl, conn) == NULL) { 508 nev = (-errno); 509 fmd_hdl_error(hdl, "warning: %s: errno %d\n", 510 err_substr, errno); 511 etm_stats.etm_xport_close_fail.fmds_value.ui64++; 512 return (nev); 513 } else { 514 return (0); 515 } 516 } /* etm_conn_close() */ 517 518 /* 519 * etm_io_op - perform an IO operation on the given connection 520 * with the given buffer, 521 * accommodating MTU size and retrying op if needed, 522 * return how many bytes actually done by the op 523 * or -errno value 524 * 525 * caveats: the err_substr is used in failure cases for calling 526 * fmd_hdl_error() 527 */ 528 529 static ssize_t 530 etm_io_op(fmd_hdl_t *hdl, char *err_substr, etm_xport_conn_t conn, 531 void *buf, size_t byte_cnt, int io_op) 532 { 533 ssize_t rv; /* ret val / byte count */ 534 ssize_t n; /* gen use */ 535 uint8_t *datap; /* ptr to data */ 536 size_t mtu_sz; /* MTU size in bytes */ 537 int (*io_func_ptr)(fmd_hdl_t *, etm_xport_conn_t, 538 void *, size_t); 539 size_t io_sz; /* byte count for io_func_ptr */ 540 int try_cnt; /* number of tries done */ 541 int sleep_sec; /* exp backoff sleep period in sec */ 542 int sleep_rv; /* ret val from sleeping */ 543 fmd_stat_t io_retry_stat; /* IO retry stat to update */ 544 fmd_stat_t io_fail_stat; /* IO failure stat to update */ 545 546 if ((conn == NULL) || (buf == NULL)) { 547 return (-EINVAL); 548 } 549 switch (io_op) { 550 case ETM_IO_OP_RD: 551 io_func_ptr = etm_xport_read; 552 io_retry_stat = etm_stats.etm_xport_rd_retry; 553 io_fail_stat = etm_stats.etm_xport_rd_fail; 554 break; 555 case ETM_IO_OP_WR: 556 io_func_ptr = etm_xport_write; 557 io_retry_stat = etm_stats.etm_xport_wr_retry; 558 io_fail_stat = etm_stats.etm_xport_wr_fail; 559 break; 560 case ETM_IO_OP_PK: 561 io_func_ptr = etm_xport_peek; 562 io_retry_stat = etm_stats.etm_xport_pk_retry; 563 io_fail_stat = etm_stats.etm_xport_pk_fail; 564 break; 565 default: 566 return (-EINVAL); 567 } 568 if (byte_cnt == 0) { 569 return (byte_cnt); /* nop */ 570 } 571 572 /* obtain [current] MTU size */ 573 574 if ((n = etm_xport_get_opt(hdl, conn, ETM_XPORT_OPT_MTU_SZ)) < 0) { 575 mtu_sz = ETM_XPORT_MTU_SZ_DEF; 576 } else { 577 mtu_sz = n; 578 } 579 580 /* loop until all IO done, try limit exceeded, or real failure */ 581 582 rv = 0; 583 datap = buf; 584 while (rv < byte_cnt) { 585 io_sz = MIN((byte_cnt - rv), mtu_sz); 586 try_cnt = 0; 587 sleep_sec = 0; 588 589 /* when give up, return -errno value even if partly done */ 590 591 while ((n = (*io_func_ptr)(hdl, conn, datap, io_sz)) == 592 (-EAGAIN)) { 593 try_cnt++; 594 if (try_cnt > ETM_TRY_MAX_CNT) { 595 rv = n; 596 goto func_ret; 597 } 598 if (etm_is_dying) { 599 rv = (-EINTR); 600 goto func_ret; 601 } 602 if ((sleep_rv = etm_sleep(sleep_sec)) < 0) { 603 rv = sleep_rv; 604 goto func_ret; 605 } 606 sleep_sec = ((sleep_sec == 0) ? 1 : 607 (sleep_sec * ETM_TRY_BACKOFF_RATE)); 608 sleep_sec = MIN(sleep_sec, ETM_TRY_BACKOFF_CAP); 609 io_retry_stat.fmds_value.ui64++; 610 if (etm_debug_lvl >= 1) { 611 fmd_hdl_debug(hdl, "info: retrying io op %d " 612 "due to EAGAIN\n", io_op); 613 } 614 } /* while trying the io operation */ 615 616 if (etm_is_dying) { 617 rv = (-EINTR); 618 goto func_ret; 619 } 620 if (n < 0) { 621 rv = n; 622 goto func_ret; 623 } 624 /* avoid spinning CPU when given 0 bytes but no error */ 625 if (n == 0) { 626 if ((sleep_rv = etm_sleep(ETM_SLEEP_QUIK)) < 0) { 627 rv = sleep_rv; 628 goto func_ret; 629 } 630 } 631 rv += n; 632 datap += n; 633 } /* while still have more data */ 634 635 func_ret: 636 637 if (rv < 0) { 638 io_fail_stat.fmds_value.ui64++; 639 fmd_hdl_error(hdl, "error: %s: errno %d\n", 640 err_substr, (int)(-rv)); 641 } 642 if (etm_debug_lvl >= 3) { 643 fmd_hdl_debug(hdl, "info: io op %d ret %d of %d\n", 644 io_op, (int)rv, (int)byte_cnt); 645 } 646 return (rv); 647 648 } /* etm_io_op() */ 649 650 /* 651 * etm_magic_read - read the magic number of an ETM message header 652 * from the given connection into the given buffer, 653 * return 0 or -errno value 654 * 655 * Design_Note: This routine is intended to help protect ETM from protocol 656 * framing errors as might be caused by an SP reset / crash in 657 * the middle of an ETM message send; the connection will be 658 * read from for as many bytes as needed until the magic number 659 * is found using a sliding buffer for comparisons. 660 */ 661 662 static int 663 etm_magic_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, uint32_t *magic_ptr) 664 { 665 int rv; /* ret val */ 666 uint32_t magic_num; /* magic number */ 667 int byte_cnt; /* count of bytes read */ 668 uint8_t buf5[4+1]; /* sliding input buffer */ 669 int i, j; /* indices into buf5 */ 670 ssize_t n; /* gen use */ 671 uint8_t drop_buf[1024]; /* dropped bytes buffer */ 672 673 rv = 0; /* assume success */ 674 magic_num = 0; 675 byte_cnt = 0; 676 j = 0; 677 678 /* magic number bytes are sent in network (big endian) order */ 679 680 while (magic_num != ETM_PROTO_MAGIC_NUM) { 681 if ((n = etm_io_op(hdl, "bad io read on magic", 682 conn, &buf5[j], 1, ETM_IO_OP_RD)) < 0) { 683 rv = n; 684 goto func_ret; 685 } 686 byte_cnt++; 687 j = MIN((j + 1), sizeof (magic_num)); 688 if (byte_cnt < sizeof (magic_num)) { 689 continue; 690 } 691 692 if (byte_cnt > sizeof (magic_num)) { 693 etm_stats.etm_magic_drop_bytes.fmds_value.ui64++; 694 i = MIN(byte_cnt - j - 1, sizeof (drop_buf) - 1); 695 drop_buf[i] = buf5[0]; 696 for (i = 0; i < j; i++) { 697 buf5[i] = buf5[i+1]; 698 } /* for sliding the buffer contents */ 699 } 700 (void) memcpy(&magic_num, &buf5[0], sizeof (magic_num)); 701 magic_num = ntohl(magic_num); 702 } /* for reading bytes until find magic number */ 703 704 func_ret: 705 706 if (byte_cnt != sizeof (magic_num)) { 707 fmd_hdl_error(hdl, "warning: bad proto frame " 708 "implies corrupt/lost msg(s)\n"); 709 } 710 if ((byte_cnt > sizeof (magic_num)) && (etm_debug_lvl >= 2)) { 711 i = MIN(byte_cnt - sizeof (magic_num), sizeof (drop_buf)); 712 fmd_hdl_debug(hdl, "info: magic drop hexdump " 713 "first %d of %d bytes:\n", 714 i, byte_cnt - sizeof (magic_num)); 715 etm_hexdump(hdl, drop_buf, i); 716 } 717 718 if (rv == 0) { 719 *magic_ptr = magic_num; 720 } 721 return (rv); 722 723 } /* etm_magic_read() */ 724 725 /* 726 * etm_hdr_read - allocate, read, and validate a [variable sized] 727 * ETM message header from the given connection, 728 * return the allocated ETM message header 729 * (which is guaranteed to be large enough to reuse as a 730 * RESPONSE msg hdr) and its size 731 * or NULL and set errno on failure 732 */ 733 734 static void * 735 etm_hdr_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, size_t *szp) 736 { 737 uint8_t *hdrp; /* ptr to header to return */ 738 size_t hdr_sz; /* sizeof *hdrp */ 739 etm_proto_v1_pp_t pp; /* protocol preamble */ 740 etm_proto_v1_ev_hdr_t *ev_hdrp; /* for FMA_EVENT msg */ 741 etm_proto_v1_ctl_hdr_t *ctl_hdrp; /* for CONTROL msg */ 742 etm_proto_v1_resp_hdr_t *resp_hdrp; /* for RESPONSE msg */ 743 uint32_t *lenp; /* ptr to FMA event length */ 744 ssize_t i, n; /* gen use */ 745 uint8_t misc_buf[ETM_MISC_BUF_SZ]; /* for var sized hdrs */ 746 int dummy_int; /* dummy var to appease lint */ 747 748 hdrp = NULL; hdr_sz = 0; 749 750 /* read the magic number which starts the protocol preamble */ 751 752 if ((n = etm_magic_read(hdl, conn, &pp.pp_magic_num)) < 0) { 753 errno = (-n); 754 etm_stats.etm_magic_bad.fmds_value.ui64++; 755 return (NULL); 756 } 757 758 /* read the rest of the protocol preamble all at once */ 759 760 if ((n = etm_io_op(hdl, "bad io read on preamble", 761 conn, &pp.pp_proto_ver, 762 sizeof (pp) - sizeof (pp.pp_magic_num), 763 ETM_IO_OP_RD)) < 0) { 764 errno = (-n); 765 return (NULL); 766 } 767 768 /* 769 * Design_Note: The magic number was already network decoded; but 770 * some other preamble fields also need to be decoded, 771 * specifically pp_xid and pp_timeout. The rest of the 772 * preamble fields are byte sized and hence need no 773 * decoding. 774 */ 775 776 pp.pp_xid = ntohl(pp.pp_xid); 777 pp.pp_timeout = ntohl(pp.pp_timeout); 778 779 /* sanity check the header as best we can */ 780 781 if ((pp.pp_proto_ver < ETM_PROTO_V1) || 782 (pp.pp_proto_ver > ETM_PROTO_V2)) { 783 fmd_hdl_error(hdl, "error: bad proto ver %d\n", 784 (int)pp.pp_proto_ver); 785 errno = EPROTO; 786 etm_stats.etm_ver_bad.fmds_value.ui64++; 787 return (NULL); 788 } 789 790 dummy_int = pp.pp_msg_type; 791 if ((dummy_int <= ETM_MSG_TYPE_TOO_LOW) || 792 (dummy_int >= ETM_MSG_TYPE_TOO_BIG)) { 793 fmd_hdl_error(hdl, "error: bad msg type %d", dummy_int); 794 errno = EBADMSG; 795 etm_stats.etm_msgtype_bad.fmds_value.ui64++; 796 return (NULL); 797 } 798 799 /* handle [var sized] hdrs for FMA_EVENT, CONTROL, RESPONSE msgs */ 800 801 if (pp.pp_msg_type == ETM_MSG_TYPE_FMA_EVENT) { 802 803 ev_hdrp = (void*)&misc_buf[0]; 804 hdr_sz = sizeof (*ev_hdrp); 805 (void) memcpy(&ev_hdrp->ev_pp, &pp, sizeof (pp)); 806 807 /* sanity check the header's timeout */ 808 809 if ((ev_hdrp->ev_pp.pp_proto_ver == ETM_PROTO_V1) && 810 (ev_hdrp->ev_pp.pp_timeout != ETM_PROTO_V1_TIMEOUT_NONE)) { 811 errno = ETIME; 812 etm_stats.etm_timeout_bad.fmds_value.ui64++; 813 return (NULL); 814 } 815 816 /* get all FMA event lengths from the header */ 817 818 lenp = (uint32_t *)&ev_hdrp->ev_lens[0]; lenp--; 819 i = -1; /* cnt of length entries preceding 0 */ 820 do { 821 i++; lenp++; 822 if ((sizeof (*ev_hdrp) + (i * sizeof (*lenp))) >= 823 ETM_MISC_BUF_SZ) { 824 errno = E2BIG; /* ridiculous size */ 825 etm_stats.etm_evlens_bad.fmds_value.ui64++; 826 return (NULL); 827 } 828 if ((n = etm_io_op(hdl, "bad io read on event len", 829 conn, lenp, sizeof (*lenp), 830 ETM_IO_OP_RD)) < 0) { 831 errno = (-n); 832 return (NULL); 833 } 834 *lenp = ntohl(*lenp); 835 836 } while (*lenp != 0); 837 i += 0; /* first len already counted by sizeof(ev_hdr) */ 838 hdr_sz += (i * sizeof (*lenp)); 839 840 etm_stats.etm_rd_hdr_fmaevent.fmds_value.ui64++; 841 842 } else if (pp.pp_msg_type == ETM_MSG_TYPE_CONTROL) { 843 844 ctl_hdrp = (void*)&misc_buf[0]; 845 hdr_sz = sizeof (*ctl_hdrp); 846 (void) memcpy(&ctl_hdrp->ctl_pp, &pp, sizeof (pp)); 847 848 /* sanity check the header's sub type (control selector) */ 849 850 if ((ctl_hdrp->ctl_pp.pp_sub_type <= ETM_CTL_SEL_TOO_LOW) || 851 (ctl_hdrp->ctl_pp.pp_sub_type >= ETM_CTL_SEL_TOO_BIG)) { 852 fmd_hdl_error(hdl, "error: bad ctl sub type %d\n", 853 (int)ctl_hdrp->ctl_pp.pp_sub_type); 854 errno = EBADMSG; 855 etm_stats.etm_subtype_bad.fmds_value.ui64++; 856 return (NULL); 857 } 858 859 /* get the control length */ 860 861 if ((n = etm_io_op(hdl, "bad io read on ctl len", 862 conn, &ctl_hdrp->ctl_len, 863 sizeof (ctl_hdrp->ctl_len), 864 ETM_IO_OP_RD)) < 0) { 865 errno = (-n); 866 return (NULL); 867 } 868 869 ctl_hdrp->ctl_len = ntohl(ctl_hdrp->ctl_len); 870 871 etm_stats.etm_rd_hdr_control.fmds_value.ui64++; 872 873 } else if (pp.pp_msg_type == ETM_MSG_TYPE_RESPONSE) { 874 875 resp_hdrp = (void*)&misc_buf[0]; 876 hdr_sz = sizeof (*resp_hdrp); 877 (void) memcpy(&resp_hdrp->resp_pp, &pp, sizeof (pp)); 878 879 /* sanity check the header's timeout */ 880 881 if (resp_hdrp->resp_pp.pp_timeout != 882 ETM_PROTO_V1_TIMEOUT_NONE) { 883 errno = ETIME; 884 etm_stats.etm_timeout_bad.fmds_value.ui64++; 885 return (NULL); 886 } 887 888 /* get the response code and length */ 889 890 if ((n = etm_io_op(hdl, "bad io read on resp code+len", 891 conn, &resp_hdrp->resp_code, 892 sizeof (resp_hdrp->resp_code) + 893 sizeof (resp_hdrp->resp_len), 894 ETM_IO_OP_RD)) < 0) { 895 errno = (-n); 896 return (NULL); 897 } 898 899 resp_hdrp->resp_code = ntohl(resp_hdrp->resp_code); 900 resp_hdrp->resp_len = ntohl(resp_hdrp->resp_len); 901 902 etm_stats.etm_rd_hdr_response.fmds_value.ui64++; 903 904 } /* whether we have FMA_EVENT, CONTROL, RESPONSE msg */ 905 906 /* 907 * choose a header size that allows hdr reuse for RESPONSE msgs, 908 * allocate and populate the message header, and 909 * return alloc size to caller for later free of hdrp 910 */ 911 912 hdr_sz = MAX(hdr_sz, sizeof (*resp_hdrp)); 913 hdrp = fmd_hdl_zalloc(hdl, hdr_sz, FMD_SLEEP); 914 (void) memcpy(hdrp, misc_buf, hdr_sz); 915 916 if (etm_debug_lvl >= 3) { 917 fmd_hdl_debug(hdl, "info: msg hdr hexdump %d bytes:\n", 918 hdr_sz); 919 etm_hexdump(hdl, hdrp, hdr_sz); 920 } 921 *szp = hdr_sz; 922 return (hdrp); 923 924 } /* etm_hdr_read() */ 925 926 /* 927 * etm_hdr_write - create and write a [variable sized] ETM message header 928 * to the given connection appropriate for the given FMA event 929 * and type of nvlist encoding, 930 * return the allocated ETM message header and its size 931 * or NULL and set errno on failure 932 */ 933 934 static void* 935 etm_hdr_write(fmd_hdl_t *hdl, etm_xport_conn_t conn, nvlist_t *evp, 936 int encoding, size_t *szp) 937 { 938 etm_proto_v1_ev_hdr_t *hdrp; /* for FMA_EVENT msg */ 939 size_t hdr_sz; /* sizeof *hdrp */ 940 uint32_t *lenp; /* ptr to FMA event length */ 941 size_t evsz; /* packed FMA event size */ 942 ssize_t n; /* gen use */ 943 944 /* allocate and populate the message header for 1 FMA event */ 945 946 hdr_sz = sizeof (*hdrp) + (1 * sizeof (hdrp->ev_lens[0])); 947 948 hdrp = fmd_hdl_zalloc(hdl, hdr_sz, FMD_SLEEP); 949 950 /* 951 * Design_Note: Although the ETM protocol supports it, we do not (yet) 952 * want responses/ACKs on FMA events that we send. All 953 * such messages are sent with ETM_PROTO_V1_TIMEOUT_NONE. 954 */ 955 956 hdrp->ev_pp.pp_magic_num = ETM_PROTO_MAGIC_NUM; 957 hdrp->ev_pp.pp_magic_num = htonl(hdrp->ev_pp.pp_magic_num); 958 hdrp->ev_pp.pp_proto_ver = ETM_PROTO_V1; 959 hdrp->ev_pp.pp_msg_type = ETM_MSG_TYPE_FMA_EVENT; 960 hdrp->ev_pp.pp_sub_type = 0; 961 hdrp->ev_pp.pp_rsvd_pad = 0; 962 hdrp->ev_pp.pp_xid = etm_xid_cur; 963 hdrp->ev_pp.pp_xid = htonl(hdrp->ev_pp.pp_xid); 964 etm_xid_cur += ETM_XID_INC; 965 hdrp->ev_pp.pp_timeout = ETM_PROTO_V1_TIMEOUT_NONE; 966 hdrp->ev_pp.pp_timeout = htonl(hdrp->ev_pp.pp_timeout); 967 968 lenp = &hdrp->ev_lens[0]; 969 970 if ((n = nvlist_size(evp, &evsz, encoding)) != 0) { 971 errno = n; 972 fmd_hdl_free(hdl, hdrp, hdr_sz); 973 etm_stats.etm_os_nvlist_size_fail.fmds_value.ui64++; 974 return (NULL); 975 } 976 977 /* indicate 1 FMA event, network encode its length, and 0-terminate */ 978 979 *lenp = evsz; *lenp = htonl(*lenp); lenp++; 980 *lenp = 0; *lenp = htonl(*lenp); lenp++; 981 982 /* 983 * write the network encoded header to the transport, and 984 * return alloc size to caller for later free 985 */ 986 987 if ((n = etm_io_op(hdl, "bad io write on event hdr", 988 conn, hdrp, hdr_sz, ETM_IO_OP_WR)) < 0) { 989 errno = (-n); 990 fmd_hdl_free(hdl, hdrp, hdr_sz); 991 return (NULL); 992 } 993 994 *szp = hdr_sz; 995 return (hdrp); 996 997 } /* etm_hdr_write() */ 998 999 /* 1000 * etm_post_to_fmd - post the given FMA event to FMD 1001 * via a FMD transport API call, 1002 * return 0 or -errno value 1003 * 1004 * caveats: the FMA event (evp) is freed by FMD, 1005 * thus callers of this function should 1006 * immediately discard any ptr they have to the 1007 * nvlist without freeing or dereferencing it 1008 */ 1009 1010 static int 1011 etm_post_to_fmd(fmd_hdl_t *hdl, nvlist_t *evp) 1012 { 1013 ssize_t ev_sz; /* sizeof *evp */ 1014 1015 (void) nvlist_size(evp, (size_t *)&ev_sz, NV_ENCODE_XDR); 1016 1017 if (etm_debug_lvl >= 2) { 1018 etm_show_time(hdl, "ante ev post"); 1019 } 1020 fmd_xprt_post(hdl, etm_fmd_xprt, evp, 0); 1021 etm_stats.etm_wr_fmd_fmaevent.fmds_value.ui64++; 1022 etm_stats.etm_wr_fmd_bytes.fmds_value.ui64 += ev_sz; 1023 if (etm_debug_lvl >= 1) { 1024 fmd_hdl_debug(hdl, "info: event %p post ok to FMD\n", evp); 1025 } 1026 if (etm_debug_lvl >= 2) { 1027 etm_show_time(hdl, "post ev post"); 1028 } 1029 return (0); 1030 1031 } /* etm_post_to_fmd() */ 1032 1033 /* 1034 * etm_req_ver_negot - send an ETM control message to the other end requesting 1035 * that the ETM protocol version be negotiated/set 1036 */ 1037 1038 static void 1039 etm_req_ver_negot(fmd_hdl_t *hdl) 1040 { 1041 etm_xport_addr_t *addrv; /* default dst addr(s) */ 1042 etm_xport_conn_t conn; /* connection to other end */ 1043 etm_proto_v1_ctl_hdr_t *ctl_hdrp; /* for CONTROL msg */ 1044 size_t hdr_sz; /* sizeof header */ 1045 uint8_t *body_buf; /* msg body buffer */ 1046 uint32_t body_sz; /* sizeof *body_buf */ 1047 ssize_t i; /* gen use */ 1048 1049 /* populate an ETM control msg to send */ 1050 1051 hdr_sz = sizeof (*ctl_hdrp); 1052 body_sz = (2 + 1); /* version bytes plus null byte */ 1053 1054 ctl_hdrp = fmd_hdl_zalloc(hdl, hdr_sz + body_sz, FMD_SLEEP); 1055 1056 ctl_hdrp->ctl_pp.pp_magic_num = htonl(ETM_PROTO_MAGIC_NUM); 1057 ctl_hdrp->ctl_pp.pp_proto_ver = ETM_PROTO_V1; 1058 ctl_hdrp->ctl_pp.pp_msg_type = ETM_MSG_TYPE_CONTROL; 1059 ctl_hdrp->ctl_pp.pp_sub_type = ETM_CTL_SEL_VER_NEGOT_REQ; 1060 ctl_hdrp->ctl_pp.pp_rsvd_pad = 0; 1061 etm_xid_ver_negot = etm_xid_cur; 1062 etm_xid_cur += ETM_XID_INC; 1063 ctl_hdrp->ctl_pp.pp_xid = htonl(etm_xid_ver_negot); 1064 ctl_hdrp->ctl_pp.pp_timeout = htonl(ETM_PROTO_V1_TIMEOUT_FOREVER); 1065 ctl_hdrp->ctl_len = htonl(body_sz); 1066 1067 body_buf = (void*)&ctl_hdrp->ctl_len; 1068 body_buf += sizeof (ctl_hdrp->ctl_len); 1069 *body_buf++ = ETM_PROTO_V2; 1070 *body_buf++ = ETM_PROTO_V1; 1071 *body_buf++ = '\0'; 1072 1073 /* 1074 * open and close a connection to send the ETM control msg 1075 * to any/all of the default dst addrs 1076 */ 1077 1078 if ((addrv = etm_xport_get_ev_addrv(hdl, NULL)) == NULL) { 1079 fmd_hdl_error(hdl, 1080 "error: bad ctl dst addrs errno %d\n", errno); 1081 etm_stats.etm_xport_get_ev_addrv_fail.fmds_value.ui64++; 1082 goto func_ret; 1083 } 1084 1085 for (i = 0; addrv[i] != NULL; i++) { 1086 1087 if (etm_conn_open(hdl, "bad conn open during ver negot", 1088 addrv[i], &conn) < 0) { 1089 continue; 1090 } 1091 if (etm_io_op(hdl, "bad io write on ctl hdr+body", 1092 conn, ctl_hdrp, hdr_sz + body_sz, 1093 ETM_IO_OP_WR) >= 0) { 1094 etm_stats.etm_wr_hdr_control.fmds_value.ui64++; 1095 etm_stats.etm_wr_body_control.fmds_value.ui64++; 1096 } 1097 (void) etm_conn_close(hdl, "bad conn close during ver negot", 1098 conn); 1099 1100 } /* foreach dst addr */ 1101 1102 func_ret: 1103 1104 if (addrv != NULL) { 1105 etm_xport_free_addrv(hdl, addrv); 1106 } 1107 fmd_hdl_free(hdl, ctl_hdrp, hdr_sz + body_sz); 1108 1109 } /* etm_req_ver_negot() */ 1110 1111 /* 1112 * Design_Note: We rely on the fact that all message types have 1113 * a common protocol preamble; if this fact should 1114 * ever change it may break the code below. We also 1115 * rely on the fact that FMA_EVENT and CONTROL headers 1116 * returned will be sized large enough to reuse them 1117 * as RESPONSE headers if the remote endpt asked 1118 * for a response via the pp_timeout field. 1119 */ 1120 1121 /* 1122 * etm_maybe_send_response - check the given message header to see 1123 * whether a response has been requested, 1124 * if so then send an appropriate response 1125 * back on the given connection using the 1126 * given response code, 1127 * return 0 or -errno value 1128 */ 1129 1130 static ssize_t 1131 etm_maybe_send_response(fmd_hdl_t *hdl, etm_xport_conn_t conn, 1132 void *hdrp, int32_t resp_code) 1133 { 1134 ssize_t rv; /* ret val */ 1135 etm_proto_v1_pp_t *ppp; /* protocol preamble ptr */ 1136 etm_proto_v1_resp_hdr_t *resp_hdrp; /* for RESPONSE msg */ 1137 uint8_t resp_body[4]; /* response body if needed */ 1138 uint8_t *resp_msg; /* response hdr+body */ 1139 size_t hdr_sz; /* sizeof response hdr */ 1140 uint8_t orig_msg_type; /* orig hdr's message type */ 1141 uint32_t orig_timeout; /* orig hdr's timeout */ 1142 ssize_t n; /* gen use */ 1143 1144 rv = 0; /* default is success */ 1145 ppp = hdrp; 1146 orig_msg_type = ppp->pp_msg_type; 1147 orig_timeout = ppp->pp_timeout; 1148 1149 /* bail out now if no response is to be sent */ 1150 1151 if (orig_timeout == ETM_PROTO_V1_TIMEOUT_NONE) { 1152 return (0); 1153 } /* if a nop */ 1154 1155 if ((orig_msg_type != ETM_MSG_TYPE_FMA_EVENT) && 1156 (orig_msg_type != ETM_MSG_TYPE_CONTROL)) { 1157 return (-EINVAL); 1158 } /* if inappropriate hdr for a response msg */ 1159 1160 /* reuse the given header as a response header */ 1161 1162 if (etm_debug_lvl >= 2) { 1163 etm_show_time(hdl, "ante resp send"); 1164 } 1165 1166 resp_hdrp = hdrp; 1167 resp_hdrp->resp_code = resp_code; 1168 resp_hdrp->resp_len = 0; /* default is empty body */ 1169 1170 if ((orig_msg_type == ETM_MSG_TYPE_CONTROL) && 1171 (ppp->pp_sub_type == ETM_CTL_SEL_VER_NEGOT_REQ)) { 1172 resp_body[0] = ETM_PROTO_V2; 1173 resp_hdrp->resp_len = 1; 1174 } /* if should send our/negotiated proto ver in resp body */ 1175 1176 /* respond with the proto ver that was negotiated */ 1177 1178 resp_hdrp->resp_pp.pp_proto_ver = etm_resp_ver; 1179 resp_hdrp->resp_pp.pp_msg_type = ETM_MSG_TYPE_RESPONSE; 1180 resp_hdrp->resp_pp.pp_timeout = ETM_PROTO_V1_TIMEOUT_NONE; 1181 1182 /* 1183 * send the whole response msg in one write, header and body; 1184 * avoid the alloc-and-copy if we can reuse the hdr as the msg, 1185 * ie, if the body is empty 1186 * 1187 * update stats and note the xid associated with last ACKed FMA_EVENT 1188 * known to be successfully posted to FMD to aid duplicate filtering 1189 */ 1190 1191 hdr_sz = sizeof (etm_proto_v1_resp_hdr_t); 1192 1193 resp_msg = hdrp; 1194 if (resp_hdrp->resp_len > 0) { 1195 resp_msg = fmd_hdl_zalloc(hdl, hdr_sz + resp_hdrp->resp_len, 1196 FMD_SLEEP); 1197 (void) memcpy(resp_msg, resp_hdrp, hdr_sz); 1198 (void) memcpy(resp_msg + hdr_sz, resp_body, 1199 resp_hdrp->resp_len); 1200 } 1201 1202 if ((n = etm_io_op(hdl, "bad io write on resp msg", conn, 1203 resp_msg, hdr_sz + resp_hdrp->resp_len, ETM_IO_OP_WR)) < 0) { 1204 rv = n; 1205 goto func_ret; 1206 } 1207 1208 etm_stats.etm_wr_hdr_response.fmds_value.ui64++; 1209 etm_stats.etm_wr_body_response.fmds_value.ui64++; 1210 1211 if ((orig_msg_type == ETM_MSG_TYPE_FMA_EVENT) && 1212 (resp_code >= 0)) { 1213 etm_xid_posted_ev = resp_hdrp->resp_pp.pp_xid; 1214 } 1215 1216 fmd_hdl_debug(hdl, "info: sent V%u RESPONSE msg to xport " 1217 "xid 0x%x code %d len %u\n", 1218 (unsigned int)resp_hdrp->resp_pp.pp_proto_ver, 1219 resp_hdrp->resp_pp.pp_xid, resp_hdrp->resp_code, 1220 resp_hdrp->resp_len); 1221 func_ret: 1222 1223 if (resp_hdrp->resp_len > 0) { 1224 fmd_hdl_free(hdl, resp_msg, hdr_sz + resp_hdrp->resp_len); 1225 } 1226 if (etm_debug_lvl >= 2) { 1227 etm_show_time(hdl, "post resp send"); 1228 } 1229 return (rv); 1230 1231 } /* etm_maybe_send_response() */ 1232 1233 /* 1234 * etm_handle_new_conn - receive an ETM message sent from the other end via 1235 * the given open connection, pull out any FMA events 1236 * and post them to the local FMD (or handle any ETM 1237 * control or response msg); when done, close the 1238 * connection 1239 */ 1240 1241 static void 1242 etm_handle_new_conn(fmd_hdl_t *hdl, etm_xport_conn_t conn) 1243 { 1244 etm_proto_v1_ev_hdr_t *ev_hdrp; /* for FMA_EVENT msg */ 1245 etm_proto_v1_ctl_hdr_t *ctl_hdrp; /* for CONTROL msg */ 1246 etm_proto_v1_resp_hdr_t *resp_hdrp; /* for RESPONSE msg */ 1247 int32_t resp_code; /* response code */ 1248 size_t hdr_sz; /* sizeof header */ 1249 uint8_t *body_buf; /* msg body buffer */ 1250 uint32_t body_sz; /* sizeof body_buf */ 1251 uint32_t ev_cnt; /* count of FMA events */ 1252 uint8_t *bp; /* byte ptr within body_buf */ 1253 nvlist_t *evp; /* ptr to unpacked FMA event */ 1254 char *class; /* FMA event class */ 1255 ssize_t i, n; /* gen use */ 1256 1257 if (etm_debug_lvl >= 2) { 1258 etm_show_time(hdl, "ante conn handle"); 1259 } 1260 fmd_hdl_debug(hdl, "info: handling new conn %p\n", conn); 1261 1262 ev_hdrp = NULL; 1263 ctl_hdrp = NULL; 1264 resp_hdrp = NULL; 1265 body_buf = NULL; 1266 class = NULL; 1267 evp = NULL; 1268 resp_code = 0; /* default is success */ 1269 1270 /* read a network decoded message header from the connection */ 1271 1272 if ((ev_hdrp = etm_hdr_read(hdl, conn, &hdr_sz)) == NULL) { 1273 /* errno assumed set by above call */ 1274 fmd_hdl_error(hdl, "error: FMA event dropped: " 1275 "bad hdr read errno %d\n", errno); 1276 etm_stats.etm_rd_drop_fmaevent.fmds_value.ui64++; 1277 goto func_ret; 1278 } 1279 1280 /* 1281 * handle the message based on its preamble pp_msg_type 1282 * which is known to be valid from etm_hdr_read() checks 1283 */ 1284 1285 if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_FMA_EVENT) { 1286 1287 fmd_hdl_debug(hdl, "info: rcvd FMA_EVENT msg from xport\n"); 1288 1289 /* allocate buf large enough for whole body / all FMA events */ 1290 1291 body_sz = 0; 1292 for (i = 0; ev_hdrp->ev_lens[i] != 0; i++) { 1293 body_sz += ev_hdrp->ev_lens[i]; 1294 } /* for summing sizes of all FMA events */ 1295 ev_cnt = i; 1296 1297 if (etm_debug_lvl >= 1) { 1298 fmd_hdl_debug(hdl, "info: event lengths %u sum %u\n", 1299 ev_cnt, body_sz); 1300 } 1301 1302 body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP); 1303 1304 /* read all the FMA events at once */ 1305 1306 if ((n = etm_io_op(hdl, "FMA event dropped: " 1307 "bad io read on event bodies", 1308 conn, body_buf, body_sz, 1309 ETM_IO_OP_RD)) < 0) { 1310 etm_stats.etm_rd_drop_fmaevent.fmds_value.ui64++; 1311 goto func_ret; 1312 } 1313 1314 etm_stats.etm_rd_xport_bytes.fmds_value.ui64 += body_sz; 1315 etm_stats.etm_rd_body_fmaevent.fmds_value.ui64 += ev_cnt; 1316 1317 /* 1318 * check for dup msg/xid against last good response sent, 1319 * if a dup then resend response but skip repost to FMD 1320 */ 1321 1322 if (ev_hdrp->ev_pp.pp_xid == etm_xid_posted_ev) { 1323 (void) etm_maybe_send_response(hdl, conn, ev_hdrp, 0); 1324 fmd_hdl_debug(hdl, "info: skipping dup FMA event post " 1325 "xid 0x%x\n", etm_xid_posted_ev); 1326 etm_stats.etm_rd_dup_fmaevent.fmds_value.ui64++; 1327 goto func_ret; 1328 } 1329 1330 /* unpack each FMA event and post it to FMD */ 1331 1332 bp = body_buf; 1333 for (i = 0; ev_hdrp->ev_lens[i] != 0; i++) { 1334 if ((n = nvlist_unpack((char *)bp, 1335 ev_hdrp->ev_lens[i], &evp, 0)) != 0) { 1336 resp_code = (-n); 1337 (void) etm_maybe_send_response(hdl, conn, 1338 ev_hdrp, resp_code); 1339 fmd_hdl_error(hdl, "error: FMA event dropped: " 1340 "bad event body unpack " 1341 "errno %d\n", n); 1342 if (etm_debug_lvl >= 2) { 1343 fmd_hdl_debug(hdl, "info: FMA event " 1344 "hexdump %d bytes:\n", 1345 ev_hdrp->ev_lens[i]); 1346 etm_hexdump(hdl, bp, 1347 ev_hdrp->ev_lens[i]); 1348 } 1349 etm_stats.etm_os_nvlist_unpack_fail.fmds_value. 1350 ui64++; 1351 etm_stats.etm_rd_drop_fmaevent.fmds_value. 1352 ui64++; 1353 bp += ev_hdrp->ev_lens[i]; 1354 continue; 1355 } 1356 if (etm_debug_lvl >= 1) { 1357 (void) nvlist_lookup_string(evp, FM_CLASS, 1358 &class); 1359 if (class == NULL) { 1360 class = "NULL"; 1361 } 1362 fmd_hdl_debug(hdl, "info: FMA event %p " 1363 "class %s\n", evp, class); 1364 } 1365 resp_code = etm_post_to_fmd(hdl, evp); 1366 evp = NULL; 1367 (void) etm_maybe_send_response(hdl, conn, 1368 ev_hdrp, resp_code); 1369 bp += ev_hdrp->ev_lens[i]; 1370 } /* foreach FMA event in the body buffer */ 1371 1372 } else if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_CONTROL) { 1373 1374 ctl_hdrp = (void*)ev_hdrp; 1375 1376 fmd_hdl_debug(hdl, "info: rcvd CONTROL msg from xport\n"); 1377 if (etm_debug_lvl >= 1) { 1378 fmd_hdl_debug(hdl, "info: ctl sel %d xid 0x%x\n", 1379 (int)ctl_hdrp->ctl_pp.pp_sub_type, 1380 ctl_hdrp->ctl_pp.pp_xid); 1381 } 1382 1383 /* 1384 * if we have a VER_NEGOT_REQ read the body and validate 1385 * the protocol version set contained therein, 1386 * otherwise we have a PING_REQ (which has no body) 1387 * and we [also] fall thru to the code which sends a 1388 * response msg if the pp_timeout field requested one 1389 */ 1390 1391 if (ctl_hdrp->ctl_pp.pp_sub_type == ETM_CTL_SEL_VER_NEGOT_REQ) { 1392 1393 body_sz = ctl_hdrp->ctl_len; 1394 body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP); 1395 1396 if ((n = etm_io_op(hdl, "bad io read on ctl body", 1397 conn, body_buf, body_sz, 1398 ETM_IO_OP_RD)) < 0) { 1399 goto func_ret; 1400 } 1401 1402 /* complain if version set completely incompatible */ 1403 1404 for (i = 0; i < body_sz; i++) { 1405 if ((body_buf[i] == ETM_PROTO_V1) || 1406 (body_buf[i] == ETM_PROTO_V2)) { 1407 break; 1408 } 1409 } 1410 if (i >= body_sz) { 1411 etm_stats.etm_ver_bad.fmds_value.ui64++; 1412 resp_code = (-EPROTO); 1413 } 1414 1415 } /* if got version set request */ 1416 1417 etm_stats.etm_rd_body_control.fmds_value.ui64++; 1418 1419 (void) etm_maybe_send_response(hdl, conn, ctl_hdrp, resp_code); 1420 1421 } else if (ev_hdrp->ev_pp.pp_msg_type == ETM_MSG_TYPE_RESPONSE) { 1422 1423 resp_hdrp = (void*)ev_hdrp; 1424 1425 fmd_hdl_debug(hdl, "info: rcvd RESPONSE msg from xport\n"); 1426 if (etm_debug_lvl >= 1) { 1427 fmd_hdl_debug(hdl, "info: resp xid 0x%x\n", 1428 (int)resp_hdrp->resp_pp.pp_xid); 1429 } 1430 1431 body_sz = resp_hdrp->resp_len; 1432 body_buf = fmd_hdl_zalloc(hdl, body_sz, FMD_SLEEP); 1433 1434 if ((n = etm_io_op(hdl, "bad io read on resp len", 1435 conn, body_buf, body_sz, ETM_IO_OP_RD)) < 0) { 1436 goto func_ret; 1437 } 1438 1439 etm_stats.etm_rd_body_response.fmds_value.ui64++; 1440 1441 /* 1442 * look up the xid to interpret the response body 1443 * 1444 * ping is a nop; for ver negot confirm that a supported 1445 * protocol version was negotiated and remember which one 1446 */ 1447 1448 if ((resp_hdrp->resp_pp.pp_xid != etm_xid_ping) && 1449 (resp_hdrp->resp_pp.pp_xid != etm_xid_ver_negot)) { 1450 etm_stats.etm_xid_bad.fmds_value.ui64++; 1451 goto func_ret; 1452 } 1453 1454 if (resp_hdrp->resp_pp.pp_xid == etm_xid_ver_negot) { 1455 if ((body_buf[0] < ETM_PROTO_V1) || 1456 (body_buf[0] > ETM_PROTO_V2)) { 1457 etm_stats.etm_ver_bad.fmds_value.ui64++; 1458 goto func_ret; 1459 } 1460 etm_resp_ver = body_buf[0]; 1461 } /* if have resp to last req to negotiate proto ver */ 1462 1463 } /* whether we have a FMA_EVENT, CONTROL, or RESPONSE msg */ 1464 1465 func_ret: 1466 1467 (void) etm_conn_close(hdl, "bad conn close after msg recv", conn); 1468 1469 if (etm_debug_lvl >= 2) { 1470 etm_show_time(hdl, "post conn handle"); 1471 } 1472 if (ev_hdrp != NULL) { 1473 fmd_hdl_free(hdl, ev_hdrp, hdr_sz); 1474 } 1475 if (body_buf != NULL) { 1476 fmd_hdl_free(hdl, body_buf, body_sz); 1477 } 1478 } /* etm_handle_new_conn() */ 1479 1480 /* 1481 * etm_server - loop forever accepting new connections 1482 * using the given FMD handle, 1483 * handling any ETM msgs sent from the other side 1484 * via each such connection 1485 */ 1486 1487 static void 1488 etm_server(void *arg) 1489 { 1490 etm_xport_conn_t conn; /* connection handle */ 1491 ssize_t n; /* gen use */ 1492 fmd_hdl_t *hdl; /* FMD handle */ 1493 1494 hdl = arg; 1495 1496 fmd_hdl_debug(hdl, "info: connection server starting\n"); 1497 1498 while (!etm_is_dying) { 1499 1500 if ((conn = etm_xport_accept(hdl, NULL)) == NULL) { 1501 /* errno assumed set by above call */ 1502 n = errno; 1503 if (etm_is_dying) { 1504 break; 1505 } 1506 fmd_hdl_debug(hdl, 1507 "error: bad conn accept errno %d\n", n); 1508 etm_stats.etm_xport_accept_fail.fmds_value.ui64++; 1509 /* avoid spinning CPU */ 1510 (void) etm_sleep(ETM_SLEEP_SLOW); 1511 continue; 1512 } 1513 1514 /* 1515 * Design_Note: etm_handle_new_conn() will close the 1516 * accepted connection when done. In early designs 1517 * etm_handle_new_conn() was spawned as a 1518 * separate thread via pthread_create(); 1519 * however fmd_thr_create() constrains thread 1520 * creation to prevent spawned threads from 1521 * spawning others (ie, no grandchildren). 1522 * Hence etm_handle_new_conn() is now called 1523 * as a simple function [w/ multiple args]. 1524 */ 1525 1526 etm_handle_new_conn(hdl, conn); 1527 1528 } /* while accepting new connections until ETM dies */ 1529 1530 /* ETM is dying (probably due to "fmadm unload etm") */ 1531 1532 if (etm_debug_lvl >= 1) { 1533 fmd_hdl_debug(hdl, "info: connection server is dying\n"); 1534 } 1535 } /* etm_server() */ 1536 1537 /* 1538 * -------------------------- FMD entry points ------------------------------- 1539 */ 1540 1541 /* 1542 * _fmd_init - initialize the transport for use by ETM and start the 1543 * server daemon to accept new connections to us 1544 * 1545 * FMD will read our *.conf and subscribe us to FMA events 1546 */ 1547 1548 void 1549 _fmd_init(fmd_hdl_t *hdl) 1550 { 1551 struct timeval tmv; /* timeval */ 1552 ssize_t n; /* gen use */ 1553 1554 if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0) { 1555 return; /* invalid data in configuration file */ 1556 } 1557 1558 fmd_hdl_debug(hdl, "info: module initializing\n"); 1559 1560 /* setup statistics and properties from FMD */ 1561 1562 (void) fmd_stat_create(hdl, FMD_STAT_NOALLOC, 1563 sizeof (etm_stats) / sizeof (fmd_stat_t), 1564 (fmd_stat_t *)&etm_stats); 1565 1566 etm_debug_lvl = fmd_prop_get_int32(hdl, ETM_PROP_NM_DEBUG_LVL); 1567 etm_debug_max_ev_cnt = fmd_prop_get_int32(hdl, 1568 ETM_PROP_NM_DEBUG_MAX_EV_CNT); 1569 fmd_hdl_debug(hdl, "info: etm_debug_lvl %d " 1570 "etm_debug_max_ev_cnt %d\n", 1571 etm_debug_lvl, etm_debug_max_ev_cnt); 1572 1573 /* obtain an FMD transport handle so we can post FMA events later */ 1574 1575 etm_fmd_xprt = fmd_xprt_open(hdl, FMD_XPRT_RDONLY, NULL, NULL); 1576 1577 /* encourage protocol transaction id to be unique per module load */ 1578 1579 (void) gettimeofday(&tmv, NULL); 1580 etm_xid_cur = (uint32_t)((tmv.tv_sec << 10) | 1581 ((unsigned long)tmv.tv_usec >> 10)); 1582 1583 /* 1584 * init the transport, 1585 * start the connection acceptance server, and 1586 * request protocol version be negotiated 1587 */ 1588 1589 if ((n = etm_xport_init(hdl)) != 0) { 1590 fmd_hdl_error(hdl, "error: bad xport init errno %d\n", (-n)); 1591 fmd_hdl_unregister(hdl); 1592 return; 1593 } 1594 1595 etm_svr_tid = fmd_thr_create(hdl, etm_server, hdl); 1596 etm_req_ver_negot(hdl); 1597 1598 fmd_hdl_debug(hdl, "info: module initialized ok\n"); 1599 1600 } /* _fmd_init() */ 1601 1602 /* 1603 * etm_recv - receive an FMA event from FMD and transport it 1604 * to the remote endpoint 1605 */ 1606 1607 /*ARGSUSED*/ 1608 void 1609 etm_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *evp, const char *class) 1610 { 1611 etm_xport_addr_t *addrv; /* vector of transport addresses */ 1612 etm_xport_conn_t conn; /* connection handle */ 1613 etm_proto_v1_ev_hdr_t *hdrp; /* for FMA_EVENT msg */ 1614 ssize_t i, n; /* gen use */ 1615 size_t sz; /* header size */ 1616 size_t buflen; /* size of packed FMA event */ 1617 uint8_t *buf; /* tmp buffer for packed FMA event */ 1618 1619 buflen = 0; 1620 (void) nvlist_size(evp, &buflen, NV_ENCODE_XDR); 1621 etm_stats.etm_rd_fmd_bytes.fmds_value.ui64 += buflen; 1622 etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64++; 1623 1624 fmd_hdl_debug(hdl, "info: rcvd event %p from FMD\n", evp); 1625 fmd_hdl_debug(hdl, "info: cnt %llu class %s\n", 1626 etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64, class); 1627 1628 /* 1629 * if the debug limit has been set, avoid excessive traffic, 1630 * for example, an infinite cycle using loopback nodes 1631 */ 1632 1633 if ((etm_debug_max_ev_cnt >= 0) && 1634 (etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64 > 1635 etm_debug_max_ev_cnt)) { 1636 fmd_hdl_debug(hdl, "warning: FMA event dropped: " 1637 "event %p cnt %llu > debug max %d\n", evp, 1638 etm_stats.etm_rd_fmd_fmaevent.fmds_value.ui64, 1639 etm_debug_max_ev_cnt); 1640 etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++; 1641 return; 1642 } 1643 1644 /* allocate a buffer for the FMA event and nvlist pack it */ 1645 1646 buf = fmd_hdl_zalloc(hdl, buflen, FMD_SLEEP); 1647 1648 if ((n = nvlist_pack(evp, (char **)&buf, &buflen, 1649 NV_ENCODE_XDR, 0)) != 0) { 1650 fmd_hdl_error(hdl, "error: FMA event dropped: " 1651 "event pack errno %d\n", n); 1652 etm_stats.etm_os_nvlist_pack_fail.fmds_value.ui64++; 1653 etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++; 1654 fmd_hdl_free(hdl, buf, buflen); 1655 return; 1656 } 1657 1658 /* get vector of dst addrs and send the FMA event to each one */ 1659 1660 if ((addrv = etm_xport_get_ev_addrv(hdl, evp)) == NULL) { 1661 fmd_hdl_error(hdl, "error: FMA event dropped: " 1662 "bad event dst addrs errno %d\n", errno); 1663 etm_stats.etm_xport_get_ev_addrv_fail.fmds_value.ui64++; 1664 etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++; 1665 fmd_hdl_free(hdl, buf, buflen); 1666 return; 1667 } 1668 1669 for (i = 0; addrv[i] != NULL; i++) { 1670 1671 /* open a new connection to this dst addr */ 1672 1673 if ((n = etm_conn_open(hdl, "FMA event dropped: " 1674 "bad conn open on new ev", 1675 addrv[i], &conn)) < 0) { 1676 etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++; 1677 continue; 1678 } 1679 1680 /* write the ETM message header */ 1681 1682 if ((hdrp = etm_hdr_write(hdl, conn, evp, NV_ENCODE_XDR, 1683 &sz)) == NULL) { 1684 fmd_hdl_error(hdl, "error: FMA event dropped: " 1685 "bad hdr write errno %d\n", errno); 1686 (void) etm_conn_close(hdl, 1687 "bad conn close per bad hdr wr", conn); 1688 etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++; 1689 continue; 1690 } 1691 1692 fmd_hdl_free(hdl, hdrp, sz); /* header not needed */ 1693 etm_stats.etm_wr_hdr_fmaevent.fmds_value.ui64++; 1694 fmd_hdl_debug(hdl, "info: hdr xport write ok for event %p\n", 1695 evp); 1696 1697 /* write the ETM message body, ie, the packed nvlist */ 1698 1699 if ((n = etm_io_op(hdl, "FMA event dropped: " 1700 "bad io write on event", conn, 1701 buf, buflen, ETM_IO_OP_WR)) < 0) { 1702 (void) etm_conn_close(hdl, 1703 "bad conn close per bad body wr", conn); 1704 etm_stats.etm_wr_drop_fmaevent.fmds_value.ui64++; 1705 continue; 1706 } 1707 1708 etm_stats.etm_wr_body_fmaevent.fmds_value.ui64++; 1709 etm_stats.etm_wr_xport_bytes.fmds_value.ui64 += buflen; 1710 fmd_hdl_debug(hdl, "info: body xport write ok for event %p\n", 1711 evp); 1712 1713 /* close the connection */ 1714 1715 (void) etm_conn_close(hdl, "bad conn close after event send", 1716 conn); 1717 } /* foreach dst addr in the vector */ 1718 1719 etm_xport_free_addrv(hdl, addrv); 1720 fmd_hdl_free(hdl, buf, buflen); 1721 1722 } /* etm_recv() */ 1723 1724 /* 1725 * _fmd_fini - stop the server daemon and teardown the transport 1726 */ 1727 1728 void 1729 _fmd_fini(fmd_hdl_t *hdl) 1730 { 1731 ssize_t n; /* gen use */ 1732 1733 fmd_hdl_debug(hdl, "info: module finializing\n"); 1734 1735 /* kill the connection server ; wait for it to die */ 1736 1737 etm_is_dying = 1; 1738 1739 if (etm_svr_tid != NULL) { 1740 fmd_thr_signal(hdl, etm_svr_tid); 1741 fmd_thr_destroy(hdl, etm_svr_tid); 1742 etm_svr_tid = NULL; 1743 } /* if server thread was successfully created */ 1744 1745 /* teardown the transport */ 1746 1747 if ((n = etm_xport_fini(hdl)) != 0) { 1748 fmd_hdl_error(hdl, "warning: xport fini errno %d\n", (-n)); 1749 } 1750 if (etm_fmd_xprt != NULL) { 1751 fmd_xprt_close(hdl, etm_fmd_xprt); 1752 } 1753 1754 fmd_hdl_debug(hdl, "info: module finalized ok\n"); 1755 1756 } /* _fmd_fini() */ 1757