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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/stropts.h> 28 #include <sys/stream.h> 29 #include <sys/socket.h> 30 #include <sys/avl_impl.h> 31 #include <net/if.h> 32 #include <net/route.h> 33 #include <netinet/in.h> 34 #include <netinet/ip6.h> 35 #include <netinet/udp.h> 36 #include <netinet/sctp.h> 37 #include <inet/mib2.h> 38 #include <inet/common.h> 39 #include <inet/ip.h> 40 #include <inet/ip_ire.h> 41 #include <inet/ip6.h> 42 #include <inet/ipclassifier.h> 43 #include <inet/mi.h> 44 #include <sys/squeue_impl.h> 45 #include <sys/modhash_impl.h> 46 #include <inet/ip_ndp.h> 47 #include <inet/ip_if.h> 48 #include <sys/dlpi.h> 49 50 #include <mdb/mdb_modapi.h> 51 #include <mdb/mdb_ks.h> 52 53 #define ADDR_WIDTH 11 54 #define L2MAXADDRSTRLEN 255 55 #define MAX_SAP_LEN 255 56 57 typedef struct { 58 const char *bit_name; /* name of bit */ 59 const char *bit_descr; /* description of bit's purpose */ 60 } bitname_t; 61 62 static const bitname_t squeue_states[] = { 63 { "SQS_PROC", "being processed" }, 64 { "SQS_WORKER", "... by a worker thread" }, 65 { "SQS_ENTER", "... by an squeue_enter() thread" }, 66 { "SQS_FAST", "... in fast-path mode" }, 67 { "SQS_USER", "A non interrupt user" }, 68 { "SQS_BOUND", "worker thread bound to CPU" }, 69 { "SQS_PROFILE", "profiling enabled" }, 70 { "SQS_REENTER", "re-entered thred" }, 71 { NULL } 72 }; 73 74 typedef struct illif_walk_data { 75 ill_g_head_t ill_g_heads[MAX_G_HEADS]; 76 int ill_list; 77 ill_if_t ill_if; 78 } illif_walk_data_t; 79 80 typedef struct nce_walk_data_s { 81 struct ndp_g_s nce_ip_ndp; 82 int nce_hash_tbl_index; 83 nce_t nce; 84 } nce_walk_data_t; 85 86 typedef struct nce_cbdata_s { 87 uintptr_t nce_addr; 88 int nce_ipversion; 89 } nce_cbdata_t; 90 91 typedef struct ire_cbdata_s { 92 int ire_ipversion; 93 boolean_t verbose; 94 } ire_cbdata_t; 95 96 typedef struct th_walk_data { 97 uint_t thw_non_zero_only; 98 boolean_t thw_match; 99 uintptr_t thw_matchkey; 100 uintptr_t thw_ipst; 101 clock_t thw_lbolt; 102 } th_walk_data_t; 103 104 static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *); 105 static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *); 106 107 static int ire_format(uintptr_t addr, const void *, void *); 108 static int nce_format(uintptr_t addr, const nce_t *nce, int ipversion); 109 static int nce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv); 110 static int nce_walk_step(mdb_walk_state_t *wsp); 111 static int nce_stack_walk_init(mdb_walk_state_t *wsp); 112 static int nce_stack_walk_step(mdb_walk_state_t *wsp); 113 static void nce_stack_walk_fini(mdb_walk_state_t *wsp); 114 static int nce_cb(uintptr_t addr, const nce_walk_data_t *iw, nce_cbdata_t *id); 115 116 /* 117 * Given the kernel address of an ip_stack_t, return the stackid 118 */ 119 static int 120 ips_to_stackid(uintptr_t kaddr) 121 { 122 ip_stack_t ipss; 123 netstack_t nss; 124 125 if (mdb_vread(&ipss, sizeof (ipss), kaddr) == -1) { 126 mdb_warn("failed to read ip_stack_t %p", kaddr); 127 return (0); 128 } 129 kaddr = (uintptr_t)ipss.ips_netstack; 130 if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) { 131 mdb_warn("failed to read netstack_t %p", kaddr); 132 return (0); 133 } 134 return (nss.netstack_stackid); 135 } 136 137 int 138 ip_stacks_walk_init(mdb_walk_state_t *wsp) 139 { 140 if (mdb_layered_walk("netstack", wsp) == -1) { 141 mdb_warn("can't walk 'netstack'"); 142 return (WALK_ERR); 143 } 144 return (WALK_NEXT); 145 } 146 147 int 148 ip_stacks_walk_step(mdb_walk_state_t *wsp) 149 { 150 uintptr_t kaddr; 151 netstack_t nss; 152 153 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 154 mdb_warn("can't read netstack at %p", wsp->walk_addr); 155 return (WALK_ERR); 156 } 157 kaddr = (uintptr_t)nss.netstack_modules[NS_IP]; 158 159 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 160 } 161 162 int 163 th_hash_walk_init(mdb_walk_state_t *wsp) 164 { 165 GElf_Sym sym; 166 list_node_t *next; 167 168 if (wsp->walk_addr == NULL) { 169 if (mdb_lookup_by_obj("ip", "ip_thread_list", &sym) == 0) { 170 wsp->walk_addr = sym.st_value; 171 } else { 172 mdb_warn("unable to locate ip_thread_list\n"); 173 return (WALK_ERR); 174 } 175 } 176 177 if (mdb_vread(&next, sizeof (next), 178 wsp->walk_addr + offsetof(list_t, list_head) + 179 offsetof(list_node_t, list_next)) == -1 || 180 next == NULL) { 181 mdb_warn("non-DEBUG image; cannot walk th_hash list\n"); 182 return (WALK_ERR); 183 } 184 185 if (mdb_layered_walk("list", wsp) == -1) { 186 mdb_warn("can't walk 'list'"); 187 return (WALK_ERR); 188 } else { 189 return (WALK_NEXT); 190 } 191 } 192 193 int 194 th_hash_walk_step(mdb_walk_state_t *wsp) 195 { 196 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 197 wsp->walk_cbdata)); 198 } 199 200 /* 201 * Called with walk_addr being the address of ips_ill_g_heads 202 */ 203 int 204 illif_stack_walk_init(mdb_walk_state_t *wsp) 205 { 206 illif_walk_data_t *iw; 207 208 if (wsp->walk_addr == NULL) { 209 mdb_warn("illif_stack supports only local walks\n"); 210 return (WALK_ERR); 211 } 212 213 iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP); 214 215 if (mdb_vread(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t), 216 wsp->walk_addr) == -1) { 217 mdb_warn("failed to read 'ips_ill_g_heads' at %p", 218 wsp->walk_addr); 219 mdb_free(iw, sizeof (illif_walk_data_t)); 220 return (WALK_ERR); 221 } 222 223 iw->ill_list = 0; 224 wsp->walk_addr = (uintptr_t)iw->ill_g_heads[0].ill_g_list_head; 225 wsp->walk_data = iw; 226 227 return (WALK_NEXT); 228 } 229 230 int 231 illif_stack_walk_step(mdb_walk_state_t *wsp) 232 { 233 uintptr_t addr = wsp->walk_addr; 234 illif_walk_data_t *iw = wsp->walk_data; 235 int list = iw->ill_list; 236 237 if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) { 238 mdb_warn("failed to read ill_if_t at %p", addr); 239 return (WALK_ERR); 240 } 241 242 wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next; 243 244 if (wsp->walk_addr == 245 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head) { 246 247 if (++list >= MAX_G_HEADS) 248 return (WALK_DONE); 249 250 iw->ill_list = list; 251 wsp->walk_addr = 252 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head; 253 return (WALK_NEXT); 254 } 255 256 return (wsp->walk_callback(addr, iw, wsp->walk_cbdata)); 257 } 258 259 void 260 illif_stack_walk_fini(mdb_walk_state_t *wsp) 261 { 262 mdb_free(wsp->walk_data, sizeof (illif_walk_data_t)); 263 } 264 265 typedef struct illif_cbdata { 266 uint_t ill_flags; 267 uintptr_t ill_addr; 268 int ill_printlist; /* list to be printed (MAX_G_HEADS for all) */ 269 boolean_t ill_printed; 270 } illif_cbdata_t; 271 272 static int 273 illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id) 274 { 275 const char *version; 276 277 if (id->ill_printlist < MAX_G_HEADS && 278 id->ill_printlist != iw->ill_list) 279 return (WALK_NEXT); 280 281 if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr) 282 return (WALK_NEXT); 283 284 if (id->ill_flags & DCMD_PIPE_OUT) { 285 mdb_printf("%p\n", addr); 286 return (WALK_NEXT); 287 } 288 289 switch (iw->ill_list) { 290 case IP_V4_G_HEAD: version = "v4"; break; 291 case IP_V6_G_HEAD: version = "v6"; break; 292 default: version = "??"; break; 293 } 294 295 mdb_printf("%?p %2s %?p %10d %?p %s\n", 296 addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa), 297 iw->ill_if.illif_avl_by_ppa.avl_numnodes, 298 iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name); 299 300 id->ill_printed = TRUE; 301 302 return (WALK_NEXT); 303 } 304 305 int 306 ip_stacks_common_walk_init(mdb_walk_state_t *wsp) 307 { 308 if (mdb_layered_walk("ip_stacks", wsp) == -1) { 309 mdb_warn("can't walk 'ip_stacks'"); 310 return (WALK_ERR); 311 } 312 313 return (WALK_NEXT); 314 } 315 316 int 317 illif_walk_step(mdb_walk_state_t *wsp) 318 { 319 uintptr_t kaddr; 320 321 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ill_g_heads); 322 323 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 324 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 325 return (WALK_ERR); 326 } 327 328 if (mdb_pwalk("illif_stack", wsp->walk_callback, 329 wsp->walk_cbdata, kaddr) == -1) { 330 mdb_warn("couldn't walk 'illif_stack' for ips_ill_g_heads %p", 331 kaddr); 332 return (WALK_ERR); 333 } 334 return (WALK_NEXT); 335 } 336 337 int 338 illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 339 { 340 illif_cbdata_t id; 341 ill_if_t ill_if; 342 const char *opt_P = NULL; 343 int printlist = MAX_G_HEADS; 344 345 if (mdb_getopts(argc, argv, 346 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 347 return (DCMD_USAGE); 348 349 if (opt_P != NULL) { 350 if (strcmp("v4", opt_P) == 0) { 351 printlist = IP_V4_G_HEAD; 352 } else if (strcmp("v6", opt_P) == 0) { 353 printlist = IP_V6_G_HEAD; 354 } else { 355 mdb_warn("invalid protocol '%s'\n", opt_P); 356 return (DCMD_USAGE); 357 } 358 } 359 360 if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) { 361 mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n", 362 "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME"); 363 } 364 365 id.ill_flags = flags; 366 id.ill_addr = addr; 367 id.ill_printlist = printlist; 368 id.ill_printed = FALSE; 369 370 if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) { 371 mdb_warn("can't walk ill_if_t structures"); 372 return (DCMD_ERR); 373 } 374 375 if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed) 376 return (DCMD_OK); 377 378 /* 379 * If an address is specified and the walk doesn't find it, 380 * print it anyway. 381 */ 382 if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) { 383 mdb_warn("failed to read ill_if_t at %p", addr); 384 return (DCMD_ERR); 385 } 386 387 mdb_printf("%?p %2s %?p %10d %?p %s\n", 388 addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa), 389 ill_if.illif_avl_by_ppa.avl_numnodes, 390 ill_if.illif_ppa_arena, ill_if.illif_name); 391 392 return (DCMD_OK); 393 } 394 395 static void 396 illif_help(void) 397 { 398 mdb_printf("Options:\n"); 399 mdb_printf("\t-P v4 | v6" 400 "\tfilter interface structures for the specified protocol\n"); 401 } 402 403 int 404 ire_walk_init(mdb_walk_state_t *wsp) 405 { 406 if (mdb_layered_walk("ire_cache", wsp) == -1) { 407 mdb_warn("can't walk 'ire_cache'"); 408 return (WALK_ERR); 409 } 410 411 return (WALK_NEXT); 412 } 413 414 int 415 ire_walk_step(mdb_walk_state_t *wsp) 416 { 417 ire_t ire; 418 419 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 420 mdb_warn("can't read ire at %p", wsp->walk_addr); 421 return (WALK_ERR); 422 } 423 424 return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata)); 425 } 426 427 428 int 429 ire_ctable_walk_step(mdb_walk_state_t *wsp) 430 { 431 uintptr_t kaddr; 432 irb_t *irb; 433 uint32_t cache_table_size; 434 int i; 435 ire_cbdata_t ire_cb; 436 437 ire_cb.verbose = B_FALSE; 438 ire_cb.ire_ipversion = 0; 439 440 441 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table_size); 442 443 if (mdb_vread(&cache_table_size, sizeof (uint32_t), kaddr) == -1) { 444 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 445 return (WALK_ERR); 446 } 447 448 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table); 449 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 450 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 451 return (WALK_ERR); 452 } 453 454 irb = mdb_alloc(sizeof (irb_t) * cache_table_size, UM_SLEEP|UM_GC); 455 if (mdb_vread(irb, sizeof (irb_t) * cache_table_size, kaddr) == -1) { 456 mdb_warn("can't read irb at %p", kaddr); 457 return (WALK_ERR); 458 } 459 for (i = 0; i < cache_table_size; i++) { 460 kaddr = (uintptr_t)irb[i].irb_ire; 461 462 if (mdb_pwalk("ire_next", ire_format, &ire_cb, 463 kaddr) == -1) { 464 mdb_warn("can't walk 'ire_next' for ire %p", kaddr); 465 return (WALK_ERR); 466 } 467 } 468 return (WALK_NEXT); 469 } 470 471 /* ARGSUSED */ 472 int 473 ire_next_walk_init(mdb_walk_state_t *wsp) 474 { 475 return (WALK_NEXT); 476 } 477 478 int 479 ire_next_walk_step(mdb_walk_state_t *wsp) 480 { 481 ire_t ire; 482 int status; 483 484 485 if (wsp->walk_addr == NULL) 486 return (WALK_DONE); 487 488 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 489 mdb_warn("can't read ire at %p", wsp->walk_addr); 490 return (WALK_ERR); 491 } 492 status = wsp->walk_callback(wsp->walk_addr, &ire, 493 wsp->walk_cbdata); 494 495 if (status != WALK_NEXT) 496 return (status); 497 498 wsp->walk_addr = (uintptr_t)ire.ire_next; 499 return (status); 500 } 501 502 static int 503 ire_format(uintptr_t addr, const void *ire_arg, void *ire_cb_arg) 504 { 505 const ire_t *irep = ire_arg; 506 ire_cbdata_t *ire_cb = ire_cb_arg; 507 boolean_t verbose = ire_cb->verbose; 508 509 static const mdb_bitmask_t tmasks[] = { 510 { "BROADCAST", IRE_BROADCAST, IRE_BROADCAST }, 511 { "DEFAULT", IRE_DEFAULT, IRE_DEFAULT }, 512 { "LOCAL", IRE_LOCAL, IRE_LOCAL }, 513 { "LOOPBACK", IRE_LOOPBACK, IRE_LOOPBACK }, 514 { "PREFIX", IRE_PREFIX, IRE_PREFIX }, 515 { "CACHE", IRE_CACHE, IRE_CACHE }, 516 { "IF_NORESOLVER", IRE_IF_NORESOLVER, IRE_IF_NORESOLVER }, 517 { "IF_RESOLVER", IRE_IF_RESOLVER, IRE_IF_RESOLVER }, 518 { "HOST", IRE_HOST, IRE_HOST }, 519 { "HOST_REDIRECT", IRE_HOST_REDIRECT, IRE_HOST_REDIRECT }, 520 { NULL, 0, 0 } 521 }; 522 523 static const mdb_bitmask_t mmasks[] = { 524 { "CONDEMNED", IRE_MARK_CONDEMNED, IRE_MARK_CONDEMNED }, 525 { "TESTHIDDEN", IRE_MARK_TESTHIDDEN, IRE_MARK_TESTHIDDEN }, 526 { "NOADD", IRE_MARK_NOADD, IRE_MARK_NOADD }, 527 { "TEMPORARY", IRE_MARK_TEMPORARY, IRE_MARK_TEMPORARY }, 528 { "USESRC", IRE_MARK_USESRC_CHECK, IRE_MARK_USESRC_CHECK }, 529 { "PRIVATE", IRE_MARK_PRIVATE_ADDR, IRE_MARK_PRIVATE_ADDR }, 530 { "UNCACHED", IRE_MARK_UNCACHED, IRE_MARK_UNCACHED }, 531 { NULL, 0, 0 } 532 }; 533 534 static const mdb_bitmask_t fmasks[] = { 535 { "UP", RTF_UP, RTF_UP }, 536 { "GATEWAY", RTF_GATEWAY, RTF_GATEWAY }, 537 { "HOST", RTF_HOST, RTF_HOST }, 538 { "REJECT", RTF_REJECT, RTF_REJECT }, 539 { "DYNAMIC", RTF_DYNAMIC, RTF_DYNAMIC }, 540 { "MODIFIED", RTF_MODIFIED, RTF_MODIFIED }, 541 { "DONE", RTF_DONE, RTF_DONE }, 542 { "MASK", RTF_MASK, RTF_MASK }, 543 { "CLONING", RTF_CLONING, RTF_CLONING }, 544 { "XRESOLVE", RTF_XRESOLVE, RTF_XRESOLVE }, 545 { "LLINFO", RTF_LLINFO, RTF_LLINFO }, 546 { "STATIC", RTF_STATIC, RTF_STATIC }, 547 { "BLACKHOLE", RTF_BLACKHOLE, RTF_BLACKHOLE }, 548 { "PRIVATE", RTF_PRIVATE, RTF_PRIVATE }, 549 { "PROTO2", RTF_PROTO2, RTF_PROTO2 }, 550 { "PROTO1", RTF_PROTO1, RTF_PROTO1 }, 551 { "MULTIRT", RTF_MULTIRT, RTF_MULTIRT }, 552 { "SETSRC", RTF_SETSRC, RTF_SETSRC }, 553 { NULL, 0, 0 } 554 }; 555 556 if (ire_cb->ire_ipversion != 0 && 557 irep->ire_ipversion != ire_cb->ire_ipversion) 558 return (WALK_NEXT); 559 560 if (irep->ire_ipversion == IPV6_VERSION && verbose) { 561 562 mdb_printf("%<b>%?p%</b> %40N <%hb>\n" 563 "%?s %40N <%hb>\n" 564 "%?s %40d %4d <%hb>\n", 565 addr, &irep->ire_src_addr_v6, irep->ire_type, tmasks, 566 "", &irep->ire_addr_v6, (ushort_t)irep->ire_marks, mmasks, 567 "", ips_to_stackid((uintptr_t)irep->ire_ipst), 568 irep->ire_zoneid, 569 irep->ire_flags, fmasks); 570 571 } else if (irep->ire_ipversion == IPV6_VERSION) { 572 573 mdb_printf("%?p %30N %30N %5d %4d\n", 574 addr, &irep->ire_src_addr_v6, 575 &irep->ire_addr_v6, 576 ips_to_stackid((uintptr_t)irep->ire_ipst), 577 irep->ire_zoneid); 578 579 } else if (verbose) { 580 581 mdb_printf("%<b>%?p%</b> %40I <%hb>\n" 582 "%?s %40I <%hb>\n" 583 "%?s %40d %4d <%hb>\n", 584 addr, irep->ire_src_addr, irep->ire_type, tmasks, 585 "", irep->ire_addr, (ushort_t)irep->ire_marks, mmasks, 586 "", ips_to_stackid((uintptr_t)irep->ire_ipst), 587 irep->ire_zoneid, irep->ire_flags, fmasks); 588 589 } else { 590 591 mdb_printf("%?p %30I %30I %5d %4d\n", addr, irep->ire_src_addr, 592 irep->ire_addr, ips_to_stackid((uintptr_t)irep->ire_ipst), 593 irep->ire_zoneid); 594 } 595 596 return (WALK_NEXT); 597 } 598 599 /* 600 * There are faster ways to do this. Given the interactive nature of this 601 * use I don't think its worth much effort. 602 */ 603 static unsigned short 604 ipcksum(void *p, int len) 605 { 606 int32_t sum = 0; 607 608 while (len > 1) { 609 /* alignment */ 610 sum += *(uint16_t *)p; 611 p = (char *)p + sizeof (uint16_t); 612 if (sum & 0x80000000) 613 sum = (sum & 0xFFFF) + (sum >> 16); 614 len -= 2; 615 } 616 617 if (len) 618 sum += (uint16_t)*(unsigned char *)p; 619 620 while (sum >> 16) 621 sum = (sum & 0xFFFF) + (sum >> 16); 622 623 return (~sum); 624 } 625 626 static const mdb_bitmask_t tcp_flags[] = { 627 { "SYN", TH_SYN, TH_SYN }, 628 { "ACK", TH_ACK, TH_ACK }, 629 { "FIN", TH_FIN, TH_FIN }, 630 { "RST", TH_RST, TH_RST }, 631 { "PSH", TH_PUSH, TH_PUSH }, 632 { "ECE", TH_ECE, TH_ECE }, 633 { "CWR", TH_CWR, TH_CWR }, 634 { NULL, 0, 0 } 635 }; 636 637 static void 638 tcphdr_print(struct tcphdr *tcph) 639 { 640 in_port_t sport, dport; 641 tcp_seq seq, ack; 642 uint16_t win, urp; 643 644 mdb_printf("%<b>TCP header%</b>\n"); 645 646 mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport)); 647 mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport)); 648 mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq)); 649 mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack)); 650 mdb_nhconvert(&win, &tcph->th_win, sizeof (win)); 651 mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp)); 652 653 mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n", 654 "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP", 655 "FLAGS"); 656 mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n", 657 sport, dport, seq, ack, tcph->th_off << 2, win, 658 tcph->th_sum, urp, tcph->th_flags, tcp_flags); 659 mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n", 660 sport, dport, seq, ack); 661 } 662 663 /* ARGSUSED */ 664 static int 665 tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 666 { 667 struct tcphdr tcph; 668 669 if (!(flags & DCMD_ADDRSPEC)) 670 return (DCMD_USAGE); 671 672 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 673 mdb_warn("failed to read TCP header at %p", addr); 674 return (DCMD_ERR); 675 } 676 tcphdr_print(&tcph); 677 return (DCMD_OK); 678 } 679 680 static void 681 udphdr_print(struct udphdr *udph) 682 { 683 in_port_t sport, dport; 684 uint16_t hlen; 685 686 mdb_printf("%<b>UDP header%</b>\n"); 687 688 mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport)); 689 mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport)); 690 mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen)); 691 692 mdb_printf("%<u>%14s %14s %5s %6s%</u>\n", 693 "SPORT", "DPORT", "LEN", "CSUM"); 694 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport, 695 dport, dport, hlen, udph->uh_sum); 696 } 697 698 /* ARGSUSED */ 699 static int 700 udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 701 { 702 struct udphdr udph; 703 704 if (!(flags & DCMD_ADDRSPEC)) 705 return (DCMD_USAGE); 706 707 if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 708 mdb_warn("failed to read UDP header at %p", addr); 709 return (DCMD_ERR); 710 } 711 udphdr_print(&udph); 712 return (DCMD_OK); 713 } 714 715 static void 716 sctphdr_print(sctp_hdr_t *sctph) 717 { 718 in_port_t sport, dport; 719 720 mdb_printf("%<b>SCTP header%</b>\n"); 721 mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport)); 722 mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport)); 723 724 mdb_printf("%<u>%14s %14s %10s %10s%</u>\n", 725 "SPORT", "DPORT", "VTAG", "CHKSUM"); 726 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport, 727 dport, dport, sctph->sh_verf, sctph->sh_chksum); 728 } 729 730 /* ARGSUSED */ 731 static int 732 sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 733 { 734 sctp_hdr_t sctph; 735 736 if (!(flags & DCMD_ADDRSPEC)) 737 return (DCMD_USAGE); 738 739 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 740 mdb_warn("failed to read SCTP header at %p", addr); 741 return (DCMD_ERR); 742 } 743 744 sctphdr_print(&sctph); 745 return (DCMD_OK); 746 } 747 748 static int 749 transport_hdr(int proto, uintptr_t addr) 750 { 751 mdb_printf("\n"); 752 switch (proto) { 753 case IPPROTO_TCP: { 754 struct tcphdr tcph; 755 756 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 757 mdb_warn("failed to read TCP header at %p", addr); 758 return (DCMD_ERR); 759 } 760 tcphdr_print(&tcph); 761 break; 762 } 763 case IPPROTO_UDP: { 764 struct udphdr udph; 765 766 if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 767 mdb_warn("failed to read UDP header at %p", addr); 768 return (DCMD_ERR); 769 } 770 udphdr_print(&udph); 771 break; 772 } 773 case IPPROTO_SCTP: { 774 sctp_hdr_t sctph; 775 776 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 777 mdb_warn("failed to read SCTP header at %p", addr); 778 return (DCMD_ERR); 779 } 780 sctphdr_print(&sctph); 781 break; 782 } 783 default: 784 break; 785 } 786 787 return (DCMD_OK); 788 } 789 790 static const mdb_bitmask_t ip_flags[] = { 791 { "DF", IPH_DF, IPH_DF }, 792 { "MF", IPH_MF, IPH_MF }, 793 { NULL, 0, 0 } 794 }; 795 796 /* ARGSUSED */ 797 static int 798 iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 799 { 800 uint_t verbose = FALSE, force = FALSE; 801 ipha_t iph[1]; 802 uint16_t ver, totlen, hdrlen, ipid, off, csum; 803 uintptr_t nxt_proto; 804 char exp_csum[8]; 805 806 if (mdb_getopts(argc, argv, 807 'v', MDB_OPT_SETBITS, TRUE, &verbose, 808 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 809 return (DCMD_USAGE); 810 811 if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 812 mdb_warn("failed to read IPv4 header at %p", addr); 813 return (DCMD_ERR); 814 } 815 816 ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4; 817 if (ver != IPV4_VERSION) { 818 if (ver == IPV6_VERSION) { 819 return (ip6hdr(addr, flags, argc, argv)); 820 } else if (!force) { 821 mdb_warn("unknown IP version: %d\n", ver); 822 return (DCMD_ERR); 823 } 824 } 825 826 mdb_printf("%<b>IPv4 header%</b>\n"); 827 mdb_printf("%-34s %-34s\n" 828 "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n", 829 "SRC", "DST", 830 "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM", 831 "EXP-CSUM", "FLGS"); 832 833 hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2; 834 mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen)); 835 mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid)); 836 mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off)); 837 if (hdrlen == IP_SIMPLE_HDR_LENGTH) { 838 if ((csum = ipcksum(iph, sizeof (*iph))) != 0) 839 csum = ~(~csum + ~iph->ipha_hdr_checksum); 840 else 841 csum = iph->ipha_hdr_checksum; 842 mdb_snprintf(exp_csum, 8, "%u", csum); 843 } else { 844 mdb_snprintf(exp_csum, 8, "<n/a>"); 845 } 846 847 mdb_printf("%-34I %-34I%\n" 848 "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n", 849 iph->ipha_src, iph->ipha_dst, 850 hdrlen, iph->ipha_type_of_service, totlen, ipid, 851 (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol, 852 iph->ipha_hdr_checksum, exp_csum, off, ip_flags); 853 854 if (verbose) { 855 nxt_proto = addr + hdrlen; 856 return (transport_hdr(iph->ipha_protocol, nxt_proto)); 857 } else { 858 return (DCMD_OK); 859 } 860 } 861 862 /* ARGSUSED */ 863 static int 864 ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 865 { 866 uint_t verbose = FALSE, force = FALSE; 867 ip6_t iph[1]; 868 int ver, class, flow; 869 uint16_t plen; 870 uintptr_t nxt_proto; 871 872 if (mdb_getopts(argc, argv, 873 'v', MDB_OPT_SETBITS, TRUE, &verbose, 874 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 875 return (DCMD_USAGE); 876 877 if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 878 mdb_warn("failed to read IPv6 header at %p", addr); 879 return (DCMD_ERR); 880 } 881 882 ver = (iph->ip6_vfc & 0xf0) >> 4; 883 if (ver != IPV6_VERSION) { 884 if (ver == IPV4_VERSION) { 885 return (iphdr(addr, flags, argc, argv)); 886 } else if (!force) { 887 mdb_warn("unknown IP version: %d\n", ver); 888 return (DCMD_ERR); 889 } 890 } 891 892 mdb_printf("%<b>IPv6 header%</b>\n"); 893 mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n", 894 "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP"); 895 896 class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20; 897 mdb_nhconvert(&class, &class, sizeof (class)); 898 flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL; 899 mdb_nhconvert(&flow, &flow, sizeof (flow)); 900 mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen)); 901 902 mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n", 903 &iph->ip6_src, &iph->ip6_dst, 904 class, flow, plen, iph->ip6_nxt, iph->ip6_hlim); 905 906 if (verbose) { 907 nxt_proto = addr + sizeof (ip6_t); 908 return (transport_hdr(iph->ip6_nxt, nxt_proto)); 909 } else { 910 return (DCMD_OK); 911 } 912 } 913 914 int 915 ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 916 { 917 uint_t verbose = FALSE; 918 ire_t ire; 919 ire_cbdata_t ire_cb; 920 int ipversion = 0; 921 const char *opt_P = NULL; 922 923 if (mdb_getopts(argc, argv, 924 'v', MDB_OPT_SETBITS, TRUE, &verbose, 925 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 926 return (DCMD_USAGE); 927 928 if (opt_P != NULL) { 929 if (strcmp("v4", opt_P) == 0) { 930 ipversion = IPV4_VERSION; 931 } else if (strcmp("v6", opt_P) == 0) { 932 ipversion = IPV6_VERSION; 933 } else { 934 mdb_warn("invalid protocol '%s'\n", opt_P); 935 return (DCMD_USAGE); 936 } 937 } 938 939 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 940 941 if (verbose) { 942 mdb_printf("%?s %40s %-20s%\n" 943 "%?s %40s %-20s%\n" 944 "%<u>%?s %40s %4s %-20s%</u>\n", 945 "ADDR", "SRC", "TYPE", 946 "", "DST", "MARKS", 947 "", "STACK", "ZONE", "FLAGS"); 948 } else { 949 mdb_printf("%<u>%?s %30s %30s %5s %4s%</u>\n", 950 "ADDR", "SRC", "DST", "STACK", "ZONE"); 951 } 952 } 953 954 ire_cb.verbose = (verbose == TRUE); 955 ire_cb.ire_ipversion = ipversion; 956 957 if (flags & DCMD_ADDRSPEC) { 958 (void) mdb_vread(&ire, sizeof (ire_t), addr); 959 (void) ire_format(addr, &ire, &ire_cb); 960 } else if (mdb_walk("ire", (mdb_walk_cb_t)ire_format, &ire_cb) == -1) { 961 mdb_warn("failed to walk ire table"); 962 return (DCMD_ERR); 963 } 964 965 return (DCMD_OK); 966 } 967 968 static size_t 969 mi_osize(const queue_t *q) 970 { 971 /* 972 * The code in common/inet/mi.c allocates an extra word to store the 973 * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s. 974 */ 975 struct mi_block { 976 size_t mi_nbytes; 977 struct mi_o_s mi_o; 978 } m; 979 980 if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - 981 sizeof (m)) == sizeof (m)) 982 return (m.mi_nbytes - sizeof (m)); 983 984 return (0); 985 } 986 987 static void 988 ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes) 989 { 990 char name[32]; 991 ill_t ill; 992 993 if (mdb_vread(&ill, sizeof (ill), 994 (uintptr_t)q->q_ptr) == sizeof (ill) && 995 mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0) 996 (void) mdb_snprintf(buf, nbytes, "if: %s", name); 997 } 998 999 void 1000 ip_qinfo(const queue_t *q, char *buf, size_t nbytes) 1001 { 1002 size_t size = mi_osize(q); 1003 1004 if (size == sizeof (ill_t)) 1005 ip_ill_qinfo(q, buf, nbytes); 1006 } 1007 1008 uintptr_t 1009 ip_rnext(const queue_t *q) 1010 { 1011 size_t size = mi_osize(q); 1012 ill_t ill; 1013 1014 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 1015 (uintptr_t)q->q_ptr) == sizeof (ill)) 1016 return ((uintptr_t)ill.ill_rq); 1017 1018 return (NULL); 1019 } 1020 1021 uintptr_t 1022 ip_wnext(const queue_t *q) 1023 { 1024 size_t size = mi_osize(q); 1025 ill_t ill; 1026 1027 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 1028 (uintptr_t)q->q_ptr) == sizeof (ill)) 1029 return ((uintptr_t)ill.ill_wq); 1030 1031 return (NULL); 1032 } 1033 1034 /* 1035 * Print the core fields in an squeue_t. With the "-v" argument, 1036 * provide more verbose output. 1037 */ 1038 static int 1039 squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1040 { 1041 unsigned int i; 1042 unsigned int verbose = FALSE; 1043 const int SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9); 1044 boolean_t arm; 1045 squeue_t squeue; 1046 1047 if (!(flags & DCMD_ADDRSPEC)) { 1048 if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue", 1049 argc, argv) == -1) { 1050 mdb_warn("failed to walk squeue cache"); 1051 return (DCMD_ERR); 1052 } 1053 return (DCMD_OK); 1054 } 1055 1056 if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) 1057 != argc) 1058 return (DCMD_USAGE); 1059 1060 if (!DCMD_HDRSPEC(flags) && verbose) 1061 mdb_printf("\n\n"); 1062 1063 if (DCMD_HDRSPEC(flags) || verbose) { 1064 mdb_printf("%?s %-5s %-3s %?s %?s %?s\n", 1065 "ADDR", "STATE", "CPU", 1066 "FIRST", "LAST", "WORKER"); 1067 } 1068 1069 if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) { 1070 mdb_warn("cannot read squeue_t at %p", addr); 1071 return (DCMD_ERR); 1072 } 1073 1074 mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n", 1075 addr, squeue.sq_state, squeue.sq_bind, 1076 squeue.sq_first, squeue.sq_last, squeue.sq_worker); 1077 1078 if (!verbose) 1079 return (DCMD_OK); 1080 1081 arm = B_TRUE; 1082 for (i = 0; squeue_states[i].bit_name != NULL; i++) { 1083 if (((squeue.sq_state) & (1 << i)) == 0) 1084 continue; 1085 1086 if (arm) { 1087 mdb_printf("%*s|\n", SQUEUE_STATEDELT, ""); 1088 mdb_printf("%*s+--> ", SQUEUE_STATEDELT, ""); 1089 arm = B_FALSE; 1090 } else 1091 mdb_printf("%*s ", SQUEUE_STATEDELT, ""); 1092 1093 mdb_printf("%-12s %s\n", squeue_states[i].bit_name, 1094 squeue_states[i].bit_descr); 1095 } 1096 1097 return (DCMD_OK); 1098 } 1099 1100 static void 1101 ip_squeue_help(void) 1102 { 1103 mdb_printf("Print the core information for a given NCA squeue_t.\n\n"); 1104 mdb_printf("Options:\n"); 1105 mdb_printf("\t-v\tbe verbose (more descriptive)\n"); 1106 } 1107 1108 /* 1109 * This is called by ::th_trace (via a callback) when walking the th_hash 1110 * list. It calls modent to find the entries. 1111 */ 1112 /* ARGSUSED */ 1113 static int 1114 modent_summary(uintptr_t addr, const void *data, void *private) 1115 { 1116 th_walk_data_t *thw = private; 1117 const struct mod_hash_entry *mhe = data; 1118 th_trace_t th; 1119 1120 if (mdb_vread(&th, sizeof (th), (uintptr_t)mhe->mhe_val) == -1) { 1121 mdb_warn("failed to read th_trace_t %p", mhe->mhe_val); 1122 return (WALK_ERR); 1123 } 1124 1125 if (th.th_refcnt == 0 && thw->thw_non_zero_only) 1126 return (WALK_NEXT); 1127 1128 if (!thw->thw_match) { 1129 mdb_printf("%?p %?p %?p %8d %?p\n", thw->thw_ipst, mhe->mhe_key, 1130 mhe->mhe_val, th.th_refcnt, th.th_id); 1131 } else if (thw->thw_matchkey == (uintptr_t)mhe->mhe_key) { 1132 int i, j, k; 1133 tr_buf_t *tr; 1134 1135 mdb_printf("Object %p in IP stack %p:\n", mhe->mhe_key, 1136 thw->thw_ipst); 1137 i = th.th_trace_lastref; 1138 mdb_printf("\tThread %p refcnt %d:\n", th.th_id, 1139 th.th_refcnt); 1140 for (j = TR_BUF_MAX; j > 0; j--) { 1141 tr = th.th_trbuf + i; 1142 if (tr->tr_depth == 0 || tr->tr_depth > TR_STACK_DEPTH) 1143 break; 1144 mdb_printf("\t T%+ld:\n", tr->tr_time - 1145 thw->thw_lbolt); 1146 for (k = 0; k < tr->tr_depth; k++) 1147 mdb_printf("\t\t%a\n", tr->tr_stack[k]); 1148 if (--i < 0) 1149 i = TR_BUF_MAX - 1; 1150 } 1151 } 1152 return (WALK_NEXT); 1153 } 1154 1155 /* 1156 * This is called by ::th_trace (via a callback) when walking the th_hash 1157 * list. It calls modent to find the entries. 1158 */ 1159 /* ARGSUSED */ 1160 static int 1161 th_hash_summary(uintptr_t addr, const void *data, void *private) 1162 { 1163 const th_hash_t *thh = data; 1164 th_walk_data_t *thw = private; 1165 1166 thw->thw_ipst = (uintptr_t)thh->thh_ipst; 1167 return (mdb_pwalk("modent", modent_summary, private, 1168 (uintptr_t)thh->thh_hash)); 1169 } 1170 1171 /* 1172 * Print or summarize the th_trace_t structures. 1173 */ 1174 static int 1175 th_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1176 { 1177 th_walk_data_t thw; 1178 1179 (void) memset(&thw, 0, sizeof (thw)); 1180 1181 if (mdb_getopts(argc, argv, 1182 'n', MDB_OPT_SETBITS, TRUE, &thw.thw_non_zero_only, 1183 NULL) != argc) 1184 return (DCMD_USAGE); 1185 1186 if (!(flags & DCMD_ADDRSPEC)) { 1187 /* 1188 * No address specified. Walk all of the th_hash_t in the 1189 * system, and summarize the th_trace_t entries in each. 1190 */ 1191 mdb_printf("%?s %?s %?s %8s %?s\n", 1192 "IPSTACK", "OBJECT", "TRACE", "REFCNT", "THREAD"); 1193 thw.thw_match = B_FALSE; 1194 } else { 1195 thw.thw_match = B_TRUE; 1196 thw.thw_matchkey = addr; 1197 if (mdb_readvar(&thw.thw_lbolt, 1198 mdb_prop_postmortem ? "panic_lbolt" : "lbolt") == -1) { 1199 mdb_warn("failed to read lbolt"); 1200 return (DCMD_ERR); 1201 } 1202 } 1203 if (mdb_pwalk("th_hash", th_hash_summary, &thw, NULL) == -1) { 1204 mdb_warn("can't walk th_hash entries"); 1205 return (DCMD_ERR); 1206 } 1207 return (DCMD_OK); 1208 } 1209 1210 static void 1211 th_trace_help(void) 1212 { 1213 mdb_printf("If given an address of an ill_t, ipif_t, ire_t, or nce_t, " 1214 "print the\n" 1215 "corresponding th_trace_t structure in detail. Otherwise, if no " 1216 "address is\n" 1217 "given, then summarize all th_trace_t structures.\n\n"); 1218 mdb_printf("Options:\n" 1219 "\t-n\tdisplay only entries with non-zero th_refcnt\n"); 1220 } 1221 1222 static const mdb_dcmd_t dcmds[] = { 1223 { "illif", "?[-P v4 | v6]", 1224 "display or filter IP Lower Level InterFace structures", illif, 1225 illif_help }, 1226 { "iphdr", ":[-vf]", "display an IPv4 header", iphdr }, 1227 { "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr }, 1228 { "ire", "?[-v] [-P v4|v6]", 1229 "display Internet Route Entry structures", ire }, 1230 { "nce", "?[-P v4 | v6]", "display Neighbor Cache Entry structures", 1231 nce }, 1232 { "squeue", ":[-v]", "print core squeue_t info", squeue, 1233 ip_squeue_help }, 1234 { "tcphdr", ":", "display a TCP header", tcphdr }, 1235 { "udphdr", ":", "display an UDP header", udphdr }, 1236 { "sctphdr", ":", "display an SCTP header", sctphdr }, 1237 { "th_trace", "?[-n]", "display th_trace_t structures", th_trace, 1238 th_trace_help }, 1239 { NULL } 1240 }; 1241 1242 static const mdb_walker_t walkers[] = { 1243 { "illif", "walk list of ill interface types for all stacks", 1244 ip_stacks_common_walk_init, illif_walk_step, NULL }, 1245 { "illif_stack", "walk list of ill interface types", 1246 illif_stack_walk_init, illif_stack_walk_step, 1247 illif_stack_walk_fini }, 1248 { "ire", "walk active ire_t structures", 1249 ire_walk_init, ire_walk_step, NULL }, 1250 { "ire_ctable", "walk ire_t structures in the ctable", 1251 ip_stacks_common_walk_init, ire_ctable_walk_step, NULL }, 1252 { "ire_next", "walk ire_t structures in the ctable", 1253 ire_next_walk_init, ire_next_walk_step, NULL }, 1254 { "ip_stacks", "walk all the ip_stack_t", 1255 ip_stacks_walk_init, ip_stacks_walk_step, NULL }, 1256 { "th_hash", "walk all the th_hash_t entries", 1257 th_hash_walk_init, th_hash_walk_step, NULL }, 1258 { "nce", "walk list of nce structures for all stacks", 1259 ip_stacks_common_walk_init, nce_walk_step, NULL }, 1260 { "nce_stack", "walk list of nce structures", 1261 nce_stack_walk_init, nce_stack_walk_step, 1262 nce_stack_walk_fini}, 1263 { NULL } 1264 }; 1265 1266 static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext }; 1267 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 1268 1269 const mdb_modinfo_t * 1270 _mdb_init(void) 1271 { 1272 GElf_Sym sym; 1273 1274 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 1275 mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value); 1276 1277 return (&modinfo); 1278 } 1279 1280 void 1281 _mdb_fini(void) 1282 { 1283 GElf_Sym sym; 1284 1285 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 1286 mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value); 1287 } 1288 1289 static char * 1290 nce_state(int nce_state) 1291 { 1292 switch (nce_state) { 1293 case ND_UNCHANGED: 1294 return ("unchanged"); 1295 case ND_INCOMPLETE: 1296 return ("incomplete"); 1297 case ND_REACHABLE: 1298 return ("reachable"); 1299 case ND_STALE: 1300 return ("stale"); 1301 case ND_DELAY: 1302 return ("delay"); 1303 case ND_PROBE: 1304 return ("probe"); 1305 case ND_UNREACHABLE: 1306 return ("unreach"); 1307 case ND_INITIAL: 1308 return ("initial"); 1309 default: 1310 return ("??"); 1311 } 1312 } 1313 1314 static char * 1315 nce_l2_addr(const nce_t *nce, const ill_t *ill) 1316 { 1317 uchar_t *h; 1318 static char addr_buf[L2MAXADDRSTRLEN]; 1319 mblk_t mp; 1320 size_t mblen; 1321 1322 if (ill->ill_flags & ILLF_XRESOLV) { 1323 return ("XRESOLV"); 1324 } 1325 1326 if (nce->nce_res_mp == NULL) { 1327 return ("None"); 1328 } 1329 1330 if (ill->ill_net_type == IRE_IF_RESOLVER) { 1331 1332 if (mdb_vread(&mp, sizeof (mblk_t), 1333 (uintptr_t)nce->nce_res_mp) == -1) { 1334 mdb_warn("failed to read nce_res_mp at %p", 1335 nce->nce_res_mp); 1336 } 1337 1338 if (ill->ill_nd_lla_len == 0) 1339 return ("None"); 1340 mblen = mp.b_wptr - mp.b_rptr; 1341 if (mblen > (sizeof (dl_unitdata_req_t) + MAX_SAP_LEN) || 1342 ill->ill_nd_lla_len > MAX_SAP_LEN || 1343 NCE_LL_ADDR_OFFSET(ill) + ill->ill_nd_lla_len > mblen) { 1344 return ("Truncated"); 1345 } 1346 h = mdb_zalloc(mblen, UM_SLEEP); 1347 if (mdb_vread(h, mblen, (uintptr_t)(mp.b_rptr)) == -1) { 1348 mdb_warn("failed to read hwaddr at %p", 1349 mp.b_rptr + NCE_LL_ADDR_OFFSET(ill)); 1350 return ("Unknown"); 1351 } 1352 mdb_mac_addr(h + NCE_LL_ADDR_OFFSET(ill), ill->ill_nd_lla_len, 1353 addr_buf, sizeof (addr_buf)); 1354 } else { 1355 return ("None"); 1356 } 1357 mdb_free(h, mblen); 1358 return (addr_buf); 1359 } 1360 1361 static void 1362 nce_header(uint_t flags) 1363 { 1364 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 1365 1366 mdb_printf("%<u>%?s %-20s %-10s %-8s %-5s %s%</u>\n", 1367 "ADDR", "HW_ADDR", "STATE", "FLAGS", "ILL", "IP ADDR"); 1368 } 1369 } 1370 1371 int 1372 nce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1373 { 1374 nce_t nce; 1375 nce_cbdata_t id; 1376 int ipversion = 0; 1377 const char *opt_P = NULL; 1378 1379 if (mdb_getopts(argc, argv, 1380 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 1381 return (DCMD_USAGE); 1382 1383 if (opt_P != NULL) { 1384 if (strcmp("v4", opt_P) == 0) { 1385 ipversion = IPV4_VERSION; 1386 } else if (strcmp("v6", opt_P) == 0) { 1387 ipversion = IPV6_VERSION; 1388 } else { 1389 mdb_warn("invalid protocol '%s'\n", opt_P); 1390 return (DCMD_USAGE); 1391 } 1392 } 1393 1394 if (flags & DCMD_ADDRSPEC) { 1395 1396 if (mdb_vread(&nce, sizeof (nce_t), addr) == -1) { 1397 mdb_warn("failed to read nce at %p\n", addr); 1398 return (DCMD_ERR); 1399 } 1400 if (ipversion != 0 && nce.nce_ipversion != ipversion) { 1401 mdb_printf("IP Version mismatch\n"); 1402 return (DCMD_ERR); 1403 } 1404 nce_header(flags); 1405 return (nce_format(addr, &nce, ipversion)); 1406 1407 } else { 1408 id.nce_addr = addr; 1409 id.nce_ipversion = ipversion; 1410 nce_header(flags); 1411 if (mdb_walk("nce", (mdb_walk_cb_t)nce_cb, &id) == -1) { 1412 mdb_warn("failed to walk nce table\n"); 1413 return (DCMD_ERR); 1414 } 1415 } 1416 return (DCMD_OK); 1417 } 1418 1419 static int 1420 nce_format(uintptr_t addr, const nce_t *nce, int ipversion) 1421 { 1422 static const mdb_bitmask_t nce_flags[] = { 1423 { "P", NCE_F_PERMANENT, NCE_F_PERMANENT }, 1424 { "R", NCE_F_ISROUTER, NCE_F_ISROUTER }, 1425 { "N", NCE_F_NONUD, NCE_F_NONUD }, 1426 { "A", NCE_F_ANYCAST, NCE_F_ANYCAST }, 1427 { "C", NCE_F_CONDEMNED, NCE_F_CONDEMNED }, 1428 { "U", NCE_F_UNSOL_ADV, NCE_F_UNSOL_ADV }, 1429 { "B", NCE_F_BCAST, NCE_F_BCAST }, 1430 { NULL, 0, 0 } 1431 }; 1432 #define NCE_MAX_FLAGS (sizeof (nce_flags) / sizeof (mdb_bitmask_t)) 1433 struct in_addr nceaddr; 1434 ill_t ill; 1435 char ill_name[LIFNAMSIZ]; 1436 char flagsbuf[NCE_MAX_FLAGS]; 1437 1438 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)nce->nce_ill) == -1) { 1439 mdb_warn("failed to read nce_ill at %p", 1440 nce->nce_ill); 1441 return (DCMD_ERR); 1442 } 1443 1444 (void) mdb_readstr(ill_name, MIN(LIFNAMSIZ, ill.ill_name_length), 1445 (uintptr_t)ill.ill_name); 1446 1447 mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%hb", 1448 nce->nce_flags, nce_flags); 1449 1450 if (ipversion != 0 && nce->nce_ipversion != ipversion) 1451 return (DCMD_OK); 1452 1453 if (nce->nce_ipversion == IPV4_VERSION) { 1454 IN6_V4MAPPED_TO_INADDR(&nce->nce_addr, &nceaddr); 1455 mdb_printf("%?p %-20s %-10s " 1456 "%-8s " 1457 "%-5s %I\n", 1458 addr, nce_l2_addr(nce, &ill), 1459 nce_state(nce->nce_state), 1460 flagsbuf, 1461 ill_name, nceaddr.s_addr); 1462 } else { 1463 mdb_printf("%?p %-20s %-10s %-8s %-5s %N\n", 1464 addr, nce_l2_addr(nce, &ill), 1465 nce_state(nce->nce_state), 1466 flagsbuf, 1467 ill_name, &nce->nce_addr); 1468 } 1469 1470 return (DCMD_OK); 1471 } 1472 1473 static uintptr_t 1474 nce_get_next_hash_tbl(uintptr_t start, int *index, struct ndp_g_s ndp) 1475 { 1476 uintptr_t addr = start; 1477 int i = *index; 1478 1479 while (addr == NULL) { 1480 1481 if (++i >= NCE_TABLE_SIZE) 1482 break; 1483 addr = (uintptr_t)ndp.nce_hash_tbl[i]; 1484 } 1485 *index = i; 1486 return (addr); 1487 } 1488 1489 static int 1490 nce_walk_step(mdb_walk_state_t *wsp) 1491 { 1492 uintptr_t kaddr4, kaddr6; 1493 1494 kaddr4 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp4); 1495 kaddr6 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp6); 1496 1497 if (mdb_vread(&kaddr4, sizeof (kaddr4), kaddr4) == -1) { 1498 mdb_warn("can't read ips_ip_cache_table at %p", kaddr4); 1499 return (WALK_ERR); 1500 } 1501 if (mdb_vread(&kaddr6, sizeof (kaddr6), kaddr6) == -1) { 1502 mdb_warn("can't read ips_ip_cache_table at %p", kaddr6); 1503 return (WALK_ERR); 1504 } 1505 if (mdb_pwalk("nce_stack", wsp->walk_callback, wsp->walk_cbdata, 1506 kaddr4) == -1) { 1507 mdb_warn("couldn't walk 'nce_stack' for ips_ndp4 %p", 1508 kaddr4); 1509 return (WALK_ERR); 1510 } 1511 if (mdb_pwalk("nce_stack", wsp->walk_callback, 1512 wsp->walk_cbdata, kaddr6) == -1) { 1513 mdb_warn("couldn't walk 'nce_stack' for ips_ndp6 %p", 1514 kaddr6); 1515 return (WALK_ERR); 1516 } 1517 return (WALK_NEXT); 1518 } 1519 1520 /* 1521 * Called with walk_addr being the address of ips_ndp{4,6} 1522 */ 1523 static int 1524 nce_stack_walk_init(mdb_walk_state_t *wsp) 1525 { 1526 nce_walk_data_t *nw; 1527 1528 if (wsp->walk_addr == NULL) { 1529 mdb_warn("nce_stack requires ndp_g_s address\n"); 1530 return (WALK_ERR); 1531 } 1532 1533 nw = mdb_alloc(sizeof (nce_walk_data_t), UM_SLEEP); 1534 1535 if (mdb_vread(&nw->nce_ip_ndp, sizeof (struct ndp_g_s), 1536 wsp->walk_addr) == -1) { 1537 mdb_warn("failed to read 'ip_ndp' at %p", 1538 wsp->walk_addr); 1539 mdb_free(nw, sizeof (nce_walk_data_t)); 1540 return (WALK_ERR); 1541 } 1542 1543 nw->nce_hash_tbl_index = 0; 1544 wsp->walk_addr = nce_get_next_hash_tbl(NULL, 1545 &nw->nce_hash_tbl_index, nw->nce_ip_ndp); 1546 wsp->walk_data = nw; 1547 1548 return (WALK_NEXT); 1549 } 1550 1551 static int 1552 nce_stack_walk_step(mdb_walk_state_t *wsp) 1553 { 1554 uintptr_t addr = wsp->walk_addr; 1555 nce_walk_data_t *nw = wsp->walk_data; 1556 1557 if (addr == NULL) 1558 return (WALK_DONE); 1559 1560 if (mdb_vread(&nw->nce, sizeof (nce_t), addr) == -1) { 1561 mdb_warn("failed to read nce_t at %p", addr); 1562 return (WALK_ERR); 1563 } 1564 1565 wsp->walk_addr = (uintptr_t)nw->nce.nce_next; 1566 1567 wsp->walk_addr = nce_get_next_hash_tbl(wsp->walk_addr, 1568 &nw->nce_hash_tbl_index, nw->nce_ip_ndp); 1569 1570 return (wsp->walk_callback(addr, nw, wsp->walk_cbdata)); 1571 } 1572 1573 static void 1574 nce_stack_walk_fini(mdb_walk_state_t *wsp) 1575 { 1576 mdb_free(wsp->walk_data, sizeof (nce_walk_data_t)); 1577 } 1578 1579 /* ARGSUSED */ 1580 static int 1581 nce_cb(uintptr_t addr, const nce_walk_data_t *iw, nce_cbdata_t *id) 1582 { 1583 nce_t nce; 1584 1585 if (mdb_vread(&nce, sizeof (nce_t), addr) == -1) { 1586 mdb_warn("failed to read nce at %p", addr); 1587 return (WALK_NEXT); 1588 } 1589 (void) nce_format(addr, &nce, id->nce_ipversion); 1590 return (WALK_NEXT); 1591 } 1592