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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/types.h> 26 #include <sys/stropts.h> 27 #include <sys/stream.h> 28 #include <sys/socket.h> 29 #include <sys/avl_impl.h> 30 #include <net/if_types.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 <ilb.h> 49 #include <ilb/ilb_impl.h> 50 #include <ilb/ilb_stack.h> 51 #include <ilb/ilb_nat.h> 52 #include <ilb/ilb_conn.h> 53 #include <sys/dlpi.h> 54 #include <sys/zone.h> 55 56 #include <mdb/mdb_modapi.h> 57 #include <mdb/mdb_ks.h> 58 59 #define ADDR_WIDTH 11 60 #define L2MAXADDRSTRLEN 255 61 #define MAX_SAP_LEN 255 62 #define DEFCOLS 80 63 64 typedef struct { 65 const char *bit_name; /* name of bit */ 66 const char *bit_descr; /* description of bit's purpose */ 67 } bitname_t; 68 69 static const bitname_t squeue_states[] = { 70 { "SQS_PROC", "being processed" }, 71 { "SQS_WORKER", "... by a worker thread" }, 72 { "SQS_ENTER", "... by an squeue_enter() thread" }, 73 { "SQS_FAST", "... in fast-path mode" }, 74 { "SQS_USER", "A non interrupt user" }, 75 { "SQS_BOUND", "worker thread bound to CPU" }, 76 { "SQS_PROFILE", "profiling enabled" }, 77 { "SQS_REENTER", "re-entered thred" }, 78 { NULL } 79 }; 80 81 typedef struct illif_walk_data { 82 ill_g_head_t ill_g_heads[MAX_G_HEADS]; 83 int ill_list; 84 ill_if_t ill_if; 85 } illif_walk_data_t; 86 87 typedef struct ncec_walk_data_s { 88 struct ndp_g_s ncec_ip_ndp; 89 int ncec_hash_tbl_index; 90 ncec_t ncec; 91 } ncec_walk_data_t; 92 93 typedef struct ncec_cbdata_s { 94 uintptr_t ncec_addr; 95 int ncec_ipversion; 96 } ncec_cbdata_t; 97 98 typedef struct nce_cbdata_s { 99 int nce_ipversion; 100 char nce_ill_name[LIFNAMSIZ]; 101 } nce_cbdata_t; 102 103 typedef struct ire_cbdata_s { 104 int ire_ipversion; 105 boolean_t verbose; 106 } ire_cbdata_t; 107 108 typedef struct zi_cbdata_s { 109 const char *zone_name; 110 ip_stack_t *ipst; 111 boolean_t shared_ip_zone; 112 } zi_cbdata_t; 113 114 typedef struct th_walk_data { 115 uint_t thw_non_zero_only; 116 boolean_t thw_match; 117 uintptr_t thw_matchkey; 118 uintptr_t thw_ipst; 119 clock_t thw_lbolt; 120 } th_walk_data_t; 121 122 typedef struct ipcl_hash_walk_data_s { 123 conn_t *conn; 124 int connf_tbl_index; 125 uintptr_t hash_tbl; 126 int hash_tbl_size; 127 } ipcl_hash_walk_data_t; 128 129 typedef struct ill_walk_data_s { 130 ill_t ill; 131 } ill_walk_data_t; 132 133 typedef struct ill_cbdata_s { 134 uintptr_t ill_addr; 135 int ill_ipversion; 136 ip_stack_t *ill_ipst; 137 boolean_t verbose; 138 } ill_cbdata_t; 139 140 typedef struct ipif_walk_data_s { 141 ipif_t ipif; 142 } ipif_walk_data_t; 143 144 typedef struct ipif_cbdata_s { 145 ill_t ill; 146 int ipif_ipversion; 147 boolean_t verbose; 148 } ipif_cbdata_t; 149 150 typedef struct hash_walk_arg_s { 151 off_t tbl_off; 152 off_t size_off; 153 } hash_walk_arg_t; 154 155 static hash_walk_arg_t udp_hash_arg = { 156 OFFSETOF(ip_stack_t, ips_ipcl_udp_fanout), 157 OFFSETOF(ip_stack_t, ips_ipcl_udp_fanout_size) 158 }; 159 160 static hash_walk_arg_t conn_hash_arg = { 161 OFFSETOF(ip_stack_t, ips_ipcl_conn_fanout), 162 OFFSETOF(ip_stack_t, ips_ipcl_conn_fanout_size) 163 }; 164 165 static hash_walk_arg_t bind_hash_arg = { 166 OFFSETOF(ip_stack_t, ips_ipcl_bind_fanout), 167 OFFSETOF(ip_stack_t, ips_ipcl_bind_fanout_size) 168 }; 169 170 static hash_walk_arg_t proto_hash_arg = { 171 OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v4), 172 0 173 }; 174 175 static hash_walk_arg_t proto_v6_hash_arg = { 176 OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v6), 177 0 178 }; 179 180 typedef struct ip_list_walk_data_s { 181 off_t nextoff; 182 } ip_list_walk_data_t; 183 184 typedef struct ip_list_walk_arg_s { 185 off_t off; 186 size_t size; 187 off_t nextp_off; 188 } ip_list_walk_arg_t; 189 190 static ip_list_walk_arg_t ipif_walk_arg = { 191 OFFSETOF(ill_t, ill_ipif), 192 sizeof (ipif_t), 193 OFFSETOF(ipif_t, ipif_next) 194 }; 195 196 static ip_list_walk_arg_t srcid_walk_arg = { 197 OFFSETOF(ip_stack_t, ips_srcid_head), 198 sizeof (srcid_map_t), 199 OFFSETOF(srcid_map_t, sm_next) 200 }; 201 202 static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *); 203 static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *); 204 205 static int ill(uintptr_t, uint_t, int, const mdb_arg_t *); 206 static void ill_help(void); 207 static int ill_walk_init(mdb_walk_state_t *); 208 static int ill_walk_step(mdb_walk_state_t *); 209 static int ill_format(uintptr_t, const void *, void *); 210 static void ill_header(boolean_t); 211 212 static int ipif(uintptr_t, uint_t, int, const mdb_arg_t *); 213 static void ipif_help(void); 214 static int ipif_walk_init(mdb_walk_state_t *); 215 static int ipif_walk_step(mdb_walk_state_t *); 216 static int ipif_format(uintptr_t, const void *, void *); 217 static void ipif_header(boolean_t); 218 219 static int ip_list_walk_init(mdb_walk_state_t *); 220 static int ip_list_walk_step(mdb_walk_state_t *); 221 static void ip_list_walk_fini(mdb_walk_state_t *); 222 static int srcid_walk_step(mdb_walk_state_t *); 223 224 static int ire_format(uintptr_t addr, const void *, void *); 225 static int ncec_format(uintptr_t addr, const ncec_t *ncec, int ipversion); 226 static int ncec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv); 227 static int ncec_walk_step(mdb_walk_state_t *wsp); 228 static int ncec_stack_walk_init(mdb_walk_state_t *wsp); 229 static int ncec_stack_walk_step(mdb_walk_state_t *wsp); 230 static void ncec_stack_walk_fini(mdb_walk_state_t *wsp); 231 static int ncec_cb(uintptr_t addr, const ncec_walk_data_t *iw, 232 ncec_cbdata_t *id); 233 static char *nce_l2_addr(const nce_t *, const ill_t *); 234 235 static int ipcl_hash_walk_init(mdb_walk_state_t *); 236 static int ipcl_hash_walk_step(mdb_walk_state_t *); 237 static void ipcl_hash_walk_fini(mdb_walk_state_t *); 238 239 static int conn_status_walk_step(mdb_walk_state_t *); 240 static int conn_status(uintptr_t, uint_t, int, const mdb_arg_t *); 241 static void conn_status_help(void); 242 243 static int srcid_status(uintptr_t, uint_t, int, const mdb_arg_t *); 244 245 static int ilb_stacks_walk_step(mdb_walk_state_t *); 246 static int ilb_rules_walk_init(mdb_walk_state_t *); 247 static int ilb_rules_walk_step(mdb_walk_state_t *); 248 static int ilb_servers_walk_init(mdb_walk_state_t *); 249 static int ilb_servers_walk_step(mdb_walk_state_t *); 250 static int ilb_nat_src_walk_init(mdb_walk_state_t *); 251 static int ilb_nat_src_walk_step(mdb_walk_state_t *); 252 static int ilb_conn_walk_init(mdb_walk_state_t *); 253 static int ilb_conn_walk_step(mdb_walk_state_t *); 254 static int ilb_sticky_walk_init(mdb_walk_state_t *); 255 static int ilb_sticky_walk_step(mdb_walk_state_t *); 256 static void ilb_common_walk_fini(mdb_walk_state_t *); 257 258 /* 259 * Given the kernel address of an ip_stack_t, return the stackid 260 */ 261 static int 262 ips_to_stackid(uintptr_t kaddr) 263 { 264 ip_stack_t ipss; 265 netstack_t nss; 266 267 if (mdb_vread(&ipss, sizeof (ipss), kaddr) == -1) { 268 mdb_warn("failed to read ip_stack_t %p", kaddr); 269 return (0); 270 } 271 kaddr = (uintptr_t)ipss.ips_netstack; 272 if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) { 273 mdb_warn("failed to read netstack_t %p", kaddr); 274 return (0); 275 } 276 return (nss.netstack_stackid); 277 } 278 279 /* ARGSUSED */ 280 static int 281 zone_to_ips_cb(uintptr_t addr, const void *zi_arg, void *zi_cb_arg) 282 { 283 zi_cbdata_t *zi_cb = zi_cb_arg; 284 zone_t zone; 285 char zone_name[ZONENAME_MAX]; 286 netstack_t ns; 287 288 if (mdb_vread(&zone, sizeof (zone_t), addr) == -1) { 289 mdb_warn("can't read zone at %p", addr); 290 return (WALK_ERR); 291 } 292 293 (void) mdb_readstr(zone_name, ZONENAME_MAX, (uintptr_t)zone.zone_name); 294 295 if (strcmp(zi_cb->zone_name, zone_name) != 0) 296 return (WALK_NEXT); 297 298 zi_cb->shared_ip_zone = (!(zone.zone_flags & ZF_NET_EXCL) && 299 (strcmp(zone_name, "global") != 0)); 300 301 if (mdb_vread(&ns, sizeof (netstack_t), (uintptr_t)zone.zone_netstack) 302 == -1) { 303 mdb_warn("can't read netstack at %p", zone.zone_netstack); 304 return (WALK_ERR); 305 } 306 307 zi_cb->ipst = ns.netstack_ip; 308 return (WALK_DONE); 309 } 310 311 static ip_stack_t * 312 zone_to_ips(const char *zone_name) 313 { 314 zi_cbdata_t zi_cb; 315 316 if (zone_name == NULL) 317 return (NULL); 318 319 zi_cb.zone_name = zone_name; 320 zi_cb.ipst = NULL; 321 zi_cb.shared_ip_zone = B_FALSE; 322 323 if (mdb_walk("zone", (mdb_walk_cb_t)zone_to_ips_cb, &zi_cb) == -1) { 324 mdb_warn("failed to walk zone"); 325 return (NULL); 326 } 327 328 if (zi_cb.shared_ip_zone) { 329 mdb_warn("%s is a Shared-IP zone, try '-s global' instead\n", 330 zone_name); 331 return (NULL); 332 } 333 334 if (zi_cb.ipst == NULL) { 335 mdb_warn("failed to find zone %s\n", zone_name); 336 return (NULL); 337 } 338 339 return (zi_cb.ipst); 340 } 341 342 /* 343 * Generic network stack walker initialization function. It is used by all 344 * other netwrok stack walkers. 345 */ 346 int 347 ns_walk_init(mdb_walk_state_t *wsp) 348 { 349 if (mdb_layered_walk("netstack", wsp) == -1) { 350 mdb_warn("can't walk 'netstack'"); 351 return (WALK_ERR); 352 } 353 return (WALK_NEXT); 354 } 355 356 /* 357 * Generic network stack walker stepping function. It is used by all other 358 * network stack walkers. The which parameter differentiates the different 359 * walkers. 360 */ 361 int 362 ns_walk_step(mdb_walk_state_t *wsp, int which) 363 { 364 uintptr_t kaddr; 365 netstack_t nss; 366 367 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 368 mdb_warn("can't read netstack at %p", wsp->walk_addr); 369 return (WALK_ERR); 370 } 371 kaddr = (uintptr_t)nss.netstack_modules[which]; 372 373 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 374 } 375 376 /* 377 * IP network stack walker stepping function. 378 */ 379 int 380 ip_stacks_walk_step(mdb_walk_state_t *wsp) 381 { 382 return (ns_walk_step(wsp, NS_IP)); 383 } 384 385 /* 386 * TCP network stack walker stepping function. 387 */ 388 int 389 tcp_stacks_walk_step(mdb_walk_state_t *wsp) 390 { 391 return (ns_walk_step(wsp, NS_TCP)); 392 } 393 394 /* 395 * SCTP network stack walker stepping function. 396 */ 397 int 398 sctp_stacks_walk_step(mdb_walk_state_t *wsp) 399 { 400 return (ns_walk_step(wsp, NS_SCTP)); 401 } 402 403 /* 404 * UDP network stack walker stepping function. 405 */ 406 int 407 udp_stacks_walk_step(mdb_walk_state_t *wsp) 408 { 409 return (ns_walk_step(wsp, NS_UDP)); 410 } 411 412 /* 413 * Initialization function for the per CPU TCP stats counter walker of a given 414 * TCP stack. 415 */ 416 int 417 tcps_sc_walk_init(mdb_walk_state_t *wsp) 418 { 419 tcp_stack_t tcps; 420 421 if (wsp->walk_addr == NULL) 422 return (WALK_ERR); 423 424 if (mdb_vread(&tcps, sizeof (tcps), wsp->walk_addr) == -1) { 425 mdb_warn("failed to read tcp_stack_t at %p", wsp->walk_addr); 426 return (WALK_ERR); 427 } 428 if (tcps.tcps_sc_cnt == 0) 429 return (WALK_DONE); 430 431 /* 432 * Store the tcp_stack_t pointer in walk_data. The stepping function 433 * used it to calculate if the end of the counter has reached. 434 */ 435 wsp->walk_data = (void *)wsp->walk_addr; 436 wsp->walk_addr = (uintptr_t)tcps.tcps_sc; 437 return (WALK_NEXT); 438 } 439 440 /* 441 * Stepping function for the per CPU TCP stats counterwalker. 442 */ 443 int 444 tcps_sc_walk_step(mdb_walk_state_t *wsp) 445 { 446 int status; 447 tcp_stack_t tcps; 448 tcp_stats_cpu_t *stats; 449 char *next, *end; 450 451 if (mdb_vread(&tcps, sizeof (tcps), (uintptr_t)wsp->walk_data) == -1) { 452 mdb_warn("failed to read tcp_stack_t at %p", wsp->walk_addr); 453 return (WALK_ERR); 454 } 455 if (mdb_vread(&stats, sizeof (stats), wsp->walk_addr) == -1) { 456 mdb_warn("failed ot read tcp_stats_cpu_t at %p", 457 wsp->walk_addr); 458 return (WALK_ERR); 459 } 460 status = wsp->walk_callback((uintptr_t)stats, &stats, wsp->walk_cbdata); 461 if (status != WALK_NEXT) 462 return (status); 463 464 next = (char *)wsp->walk_addr + sizeof (tcp_stats_cpu_t *); 465 end = (char *)tcps.tcps_sc + tcps.tcps_sc_cnt * 466 sizeof (tcp_stats_cpu_t *); 467 if (next >= end) 468 return (WALK_DONE); 469 wsp->walk_addr = (uintptr_t)next; 470 return (WALK_NEXT); 471 } 472 473 int 474 th_hash_walk_init(mdb_walk_state_t *wsp) 475 { 476 GElf_Sym sym; 477 list_node_t *next; 478 479 if (wsp->walk_addr == NULL) { 480 if (mdb_lookup_by_obj("ip", "ip_thread_list", &sym) == 0) { 481 wsp->walk_addr = sym.st_value; 482 } else { 483 mdb_warn("unable to locate ip_thread_list\n"); 484 return (WALK_ERR); 485 } 486 } 487 488 if (mdb_vread(&next, sizeof (next), 489 wsp->walk_addr + offsetof(list_t, list_head) + 490 offsetof(list_node_t, list_next)) == -1 || 491 next == NULL) { 492 mdb_warn("non-DEBUG image; cannot walk th_hash list\n"); 493 return (WALK_ERR); 494 } 495 496 if (mdb_layered_walk("list", wsp) == -1) { 497 mdb_warn("can't walk 'list'"); 498 return (WALK_ERR); 499 } else { 500 return (WALK_NEXT); 501 } 502 } 503 504 int 505 th_hash_walk_step(mdb_walk_state_t *wsp) 506 { 507 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 508 wsp->walk_cbdata)); 509 } 510 511 /* 512 * Called with walk_addr being the address of ips_ill_g_heads 513 */ 514 int 515 illif_stack_walk_init(mdb_walk_state_t *wsp) 516 { 517 illif_walk_data_t *iw; 518 519 if (wsp->walk_addr == NULL) { 520 mdb_warn("illif_stack supports only local walks\n"); 521 return (WALK_ERR); 522 } 523 524 iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP); 525 526 if (mdb_vread(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t), 527 wsp->walk_addr) == -1) { 528 mdb_warn("failed to read 'ips_ill_g_heads' at %p", 529 wsp->walk_addr); 530 mdb_free(iw, sizeof (illif_walk_data_t)); 531 return (WALK_ERR); 532 } 533 534 iw->ill_list = 0; 535 wsp->walk_addr = (uintptr_t)iw->ill_g_heads[0].ill_g_list_head; 536 wsp->walk_data = iw; 537 538 return (WALK_NEXT); 539 } 540 541 int 542 illif_stack_walk_step(mdb_walk_state_t *wsp) 543 { 544 uintptr_t addr = wsp->walk_addr; 545 illif_walk_data_t *iw = wsp->walk_data; 546 int list = iw->ill_list; 547 548 if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) { 549 mdb_warn("failed to read ill_if_t at %p", addr); 550 return (WALK_ERR); 551 } 552 553 wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next; 554 555 if (wsp->walk_addr == 556 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head) { 557 558 if (++list >= MAX_G_HEADS) 559 return (WALK_DONE); 560 561 iw->ill_list = list; 562 wsp->walk_addr = 563 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head; 564 return (WALK_NEXT); 565 } 566 567 return (wsp->walk_callback(addr, iw, wsp->walk_cbdata)); 568 } 569 570 void 571 illif_stack_walk_fini(mdb_walk_state_t *wsp) 572 { 573 mdb_free(wsp->walk_data, sizeof (illif_walk_data_t)); 574 } 575 576 typedef struct illif_cbdata { 577 uint_t ill_flags; 578 uintptr_t ill_addr; 579 int ill_printlist; /* list to be printed (MAX_G_HEADS for all) */ 580 boolean_t ill_printed; 581 } illif_cbdata_t; 582 583 static int 584 illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id) 585 { 586 const char *version; 587 588 if (id->ill_printlist < MAX_G_HEADS && 589 id->ill_printlist != iw->ill_list) 590 return (WALK_NEXT); 591 592 if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr) 593 return (WALK_NEXT); 594 595 if (id->ill_flags & DCMD_PIPE_OUT) { 596 mdb_printf("%p\n", addr); 597 return (WALK_NEXT); 598 } 599 600 switch (iw->ill_list) { 601 case IP_V4_G_HEAD: version = "v4"; break; 602 case IP_V6_G_HEAD: version = "v6"; break; 603 default: version = "??"; break; 604 } 605 606 mdb_printf("%?p %2s %?p %10d %?p %s\n", 607 addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa), 608 iw->ill_if.illif_avl_by_ppa.avl_numnodes, 609 iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name); 610 611 id->ill_printed = TRUE; 612 613 return (WALK_NEXT); 614 } 615 616 int 617 ip_stacks_common_walk_init(mdb_walk_state_t *wsp) 618 { 619 if (mdb_layered_walk("ip_stacks", wsp) == -1) { 620 mdb_warn("can't walk 'ip_stacks'"); 621 return (WALK_ERR); 622 } 623 624 return (WALK_NEXT); 625 } 626 627 int 628 illif_walk_step(mdb_walk_state_t *wsp) 629 { 630 uintptr_t kaddr; 631 632 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ill_g_heads); 633 634 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 635 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 636 return (WALK_ERR); 637 } 638 639 if (mdb_pwalk("illif_stack", wsp->walk_callback, 640 wsp->walk_cbdata, kaddr) == -1) { 641 mdb_warn("couldn't walk 'illif_stack' for ips_ill_g_heads %p", 642 kaddr); 643 return (WALK_ERR); 644 } 645 return (WALK_NEXT); 646 } 647 648 int 649 illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 650 { 651 illif_cbdata_t id; 652 ill_if_t ill_if; 653 const char *opt_P = NULL; 654 int printlist = MAX_G_HEADS; 655 656 if (mdb_getopts(argc, argv, 657 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 658 return (DCMD_USAGE); 659 660 if (opt_P != NULL) { 661 if (strcmp("v4", opt_P) == 0) { 662 printlist = IP_V4_G_HEAD; 663 } else if (strcmp("v6", opt_P) == 0) { 664 printlist = IP_V6_G_HEAD; 665 } else { 666 mdb_warn("invalid protocol '%s'\n", opt_P); 667 return (DCMD_USAGE); 668 } 669 } 670 671 if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) { 672 mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n", 673 "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME"); 674 } 675 676 id.ill_flags = flags; 677 id.ill_addr = addr; 678 id.ill_printlist = printlist; 679 id.ill_printed = FALSE; 680 681 if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) { 682 mdb_warn("can't walk ill_if_t structures"); 683 return (DCMD_ERR); 684 } 685 686 if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed) 687 return (DCMD_OK); 688 689 /* 690 * If an address is specified and the walk doesn't find it, 691 * print it anyway. 692 */ 693 if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) { 694 mdb_warn("failed to read ill_if_t at %p", addr); 695 return (DCMD_ERR); 696 } 697 698 mdb_printf("%?p %2s %?p %10d %?p %s\n", 699 addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa), 700 ill_if.illif_avl_by_ppa.avl_numnodes, 701 ill_if.illif_ppa_arena, ill_if.illif_name); 702 703 return (DCMD_OK); 704 } 705 706 static void 707 illif_help(void) 708 { 709 mdb_printf("Options:\n"); 710 mdb_printf("\t-P v4 | v6" 711 "\tfilter interface structures for the specified protocol\n"); 712 } 713 714 int 715 nce_walk_init(mdb_walk_state_t *wsp) 716 { 717 if (mdb_layered_walk("nce_cache", wsp) == -1) { 718 mdb_warn("can't walk 'nce_cache'"); 719 return (WALK_ERR); 720 } 721 722 return (WALK_NEXT); 723 } 724 725 int 726 nce_walk_step(mdb_walk_state_t *wsp) 727 { 728 nce_t nce; 729 730 if (mdb_vread(&nce, sizeof (nce), wsp->walk_addr) == -1) { 731 mdb_warn("can't read nce at %p", wsp->walk_addr); 732 return (WALK_ERR); 733 } 734 735 return (wsp->walk_callback(wsp->walk_addr, &nce, wsp->walk_cbdata)); 736 } 737 738 static int 739 nce_format(uintptr_t addr, const nce_t *ncep, void *nce_cb_arg) 740 { 741 nce_cbdata_t *nce_cb = nce_cb_arg; 742 ill_t ill; 743 char ill_name[LIFNAMSIZ]; 744 ncec_t ncec; 745 746 if (mdb_vread(&ncec, sizeof (ncec), 747 (uintptr_t)ncep->nce_common) == -1) { 748 mdb_warn("can't read ncec at %p", ncep->nce_common); 749 return (WALK_NEXT); 750 } 751 if (nce_cb->nce_ipversion != 0 && 752 ncec.ncec_ipversion != nce_cb->nce_ipversion) 753 return (WALK_NEXT); 754 755 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ncep->nce_ill) == -1) { 756 mdb_snprintf(ill_name, sizeof (ill_name), "--"); 757 } else { 758 (void) mdb_readstr(ill_name, 759 MIN(LIFNAMSIZ, ill.ill_name_length), 760 (uintptr_t)ill.ill_name); 761 } 762 763 if (nce_cb->nce_ill_name[0] != '\0' && 764 strncmp(nce_cb->nce_ill_name, ill_name, LIFNAMSIZ) != 0) 765 return (WALK_NEXT); 766 767 if (ncec.ncec_ipversion == IPV6_VERSION) { 768 769 mdb_printf("%?p %5s %-18s %?p %6d %N\n", 770 addr, ill_name, 771 nce_l2_addr(ncep, &ill), 772 ncep->nce_fp_mp, 773 ncep->nce_refcnt, 774 &ncep->nce_addr); 775 776 } else { 777 struct in_addr nceaddr; 778 779 IN6_V4MAPPED_TO_INADDR(&ncep->nce_addr, &nceaddr); 780 mdb_printf("%?p %5s %-18s %?p %6d %I\n", 781 addr, ill_name, 782 nce_l2_addr(ncep, &ill), 783 ncep->nce_fp_mp, 784 ncep->nce_refcnt, 785 nceaddr.s_addr); 786 } 787 788 return (WALK_NEXT); 789 } 790 791 int 792 dce_walk_init(mdb_walk_state_t *wsp) 793 { 794 wsp->walk_data = (void *)wsp->walk_addr; 795 796 if (mdb_layered_walk("dce_cache", wsp) == -1) { 797 mdb_warn("can't walk 'dce_cache'"); 798 return (WALK_ERR); 799 } 800 801 return (WALK_NEXT); 802 } 803 804 int 805 dce_walk_step(mdb_walk_state_t *wsp) 806 { 807 dce_t dce; 808 809 if (mdb_vread(&dce, sizeof (dce), wsp->walk_addr) == -1) { 810 mdb_warn("can't read dce at %p", wsp->walk_addr); 811 return (WALK_ERR); 812 } 813 814 /* If ip_stack_t is specified, skip DCEs that don't belong to it. */ 815 if ((wsp->walk_data != NULL) && (wsp->walk_data != dce.dce_ipst)) 816 return (WALK_NEXT); 817 818 return (wsp->walk_callback(wsp->walk_addr, &dce, wsp->walk_cbdata)); 819 } 820 821 int 822 ire_walk_init(mdb_walk_state_t *wsp) 823 { 824 wsp->walk_data = (void *)wsp->walk_addr; 825 826 if (mdb_layered_walk("ire_cache", wsp) == -1) { 827 mdb_warn("can't walk 'ire_cache'"); 828 return (WALK_ERR); 829 } 830 831 return (WALK_NEXT); 832 } 833 834 int 835 ire_walk_step(mdb_walk_state_t *wsp) 836 { 837 ire_t ire; 838 839 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 840 mdb_warn("can't read ire at %p", wsp->walk_addr); 841 return (WALK_ERR); 842 } 843 844 /* If ip_stack_t is specified, skip IREs that don't belong to it. */ 845 if ((wsp->walk_data != NULL) && (wsp->walk_data != ire.ire_ipst)) 846 return (WALK_NEXT); 847 848 return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata)); 849 } 850 851 /* ARGSUSED */ 852 int 853 ire_next_walk_init(mdb_walk_state_t *wsp) 854 { 855 return (WALK_NEXT); 856 } 857 858 int 859 ire_next_walk_step(mdb_walk_state_t *wsp) 860 { 861 ire_t ire; 862 int status; 863 864 865 if (wsp->walk_addr == NULL) 866 return (WALK_DONE); 867 868 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 869 mdb_warn("can't read ire at %p", wsp->walk_addr); 870 return (WALK_ERR); 871 } 872 status = wsp->walk_callback(wsp->walk_addr, &ire, 873 wsp->walk_cbdata); 874 875 if (status != WALK_NEXT) 876 return (status); 877 878 wsp->walk_addr = (uintptr_t)ire.ire_next; 879 return (status); 880 } 881 882 static int 883 ire_format(uintptr_t addr, const void *ire_arg, void *ire_cb_arg) 884 { 885 const ire_t *irep = ire_arg; 886 ire_cbdata_t *ire_cb = ire_cb_arg; 887 boolean_t verbose = ire_cb->verbose; 888 ill_t ill; 889 char ill_name[LIFNAMSIZ]; 890 boolean_t condemned = irep->ire_generation == IRE_GENERATION_CONDEMNED; 891 892 static const mdb_bitmask_t tmasks[] = { 893 { "BROADCAST", IRE_BROADCAST, IRE_BROADCAST }, 894 { "DEFAULT", IRE_DEFAULT, IRE_DEFAULT }, 895 { "LOCAL", IRE_LOCAL, IRE_LOCAL }, 896 { "LOOPBACK", IRE_LOOPBACK, IRE_LOOPBACK }, 897 { "PREFIX", IRE_PREFIX, IRE_PREFIX }, 898 { "MULTICAST", IRE_MULTICAST, IRE_MULTICAST }, 899 { "NOROUTE", IRE_NOROUTE, IRE_NOROUTE }, 900 { "IF_NORESOLVER", IRE_IF_NORESOLVER, IRE_IF_NORESOLVER }, 901 { "IF_RESOLVER", IRE_IF_RESOLVER, IRE_IF_RESOLVER }, 902 { "IF_CLONE", IRE_IF_CLONE, IRE_IF_CLONE }, 903 { "HOST", IRE_HOST, IRE_HOST }, 904 { NULL, 0, 0 } 905 }; 906 907 static const mdb_bitmask_t fmasks[] = { 908 { "UP", RTF_UP, RTF_UP }, 909 { "GATEWAY", RTF_GATEWAY, RTF_GATEWAY }, 910 { "HOST", RTF_HOST, RTF_HOST }, 911 { "REJECT", RTF_REJECT, RTF_REJECT }, 912 { "DYNAMIC", RTF_DYNAMIC, RTF_DYNAMIC }, 913 { "MODIFIED", RTF_MODIFIED, RTF_MODIFIED }, 914 { "DONE", RTF_DONE, RTF_DONE }, 915 { "MASK", RTF_MASK, RTF_MASK }, 916 { "CLONING", RTF_CLONING, RTF_CLONING }, 917 { "XRESOLVE", RTF_XRESOLVE, RTF_XRESOLVE }, 918 { "LLINFO", RTF_LLINFO, RTF_LLINFO }, 919 { "STATIC", RTF_STATIC, RTF_STATIC }, 920 { "BLACKHOLE", RTF_BLACKHOLE, RTF_BLACKHOLE }, 921 { "PRIVATE", RTF_PRIVATE, RTF_PRIVATE }, 922 { "PROTO2", RTF_PROTO2, RTF_PROTO2 }, 923 { "PROTO1", RTF_PROTO1, RTF_PROTO1 }, 924 { "MULTIRT", RTF_MULTIRT, RTF_MULTIRT }, 925 { "SETSRC", RTF_SETSRC, RTF_SETSRC }, 926 { "INDIRECT", RTF_INDIRECT, RTF_INDIRECT }, 927 { NULL, 0, 0 } 928 }; 929 930 if (ire_cb->ire_ipversion != 0 && 931 irep->ire_ipversion != ire_cb->ire_ipversion) 932 return (WALK_NEXT); 933 934 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)irep->ire_ill) == -1) { 935 mdb_snprintf(ill_name, sizeof (ill_name), "--"); 936 } else { 937 (void) mdb_readstr(ill_name, 938 MIN(LIFNAMSIZ, ill.ill_name_length), 939 (uintptr_t)ill.ill_name); 940 } 941 942 if (irep->ire_ipversion == IPV6_VERSION && verbose) { 943 944 mdb_printf("%<b>%?p%</b>%3s %40N <%hb%s>\n" 945 "%?s %40N\n" 946 "%?s %40d %4d <%hb> %s\n", 947 addr, condemned ? "(C)" : "", &irep->ire_setsrc_addr_v6, 948 irep->ire_type, tmasks, 949 (irep->ire_testhidden ? ", HIDDEN" : ""), 950 "", &irep->ire_addr_v6, 951 "", ips_to_stackid((uintptr_t)irep->ire_ipst), 952 irep->ire_zoneid, 953 irep->ire_flags, fmasks, ill_name); 954 955 } else if (irep->ire_ipversion == IPV6_VERSION) { 956 957 mdb_printf("%?p%3s %30N %30N %5d %4d %s\n", 958 addr, condemned ? "(C)" : "", &irep->ire_setsrc_addr_v6, 959 &irep->ire_addr_v6, 960 ips_to_stackid((uintptr_t)irep->ire_ipst), 961 irep->ire_zoneid, ill_name); 962 963 } else if (verbose) { 964 965 mdb_printf("%<b>%?p%</b>%3s %40I <%hb%s>\n" 966 "%?s %40I\n" 967 "%?s %40d %4d <%hb> %s\n", 968 addr, condemned ? "(C)" : "", irep->ire_setsrc_addr, 969 irep->ire_type, tmasks, 970 (irep->ire_testhidden ? ", HIDDEN" : ""), 971 "", irep->ire_addr, 972 "", ips_to_stackid((uintptr_t)irep->ire_ipst), 973 irep->ire_zoneid, irep->ire_flags, fmasks, ill_name); 974 975 } else { 976 977 mdb_printf("%?p%3s %30I %30I %5d %4d %s\n", addr, 978 condemned ? "(C)" : "", irep->ire_setsrc_addr, 979 irep->ire_addr, ips_to_stackid((uintptr_t)irep->ire_ipst), 980 irep->ire_zoneid, ill_name); 981 } 982 983 return (WALK_NEXT); 984 } 985 986 /* 987 * There are faster ways to do this. Given the interactive nature of this 988 * use I don't think its worth much effort. 989 */ 990 static unsigned short 991 ipcksum(void *p, int len) 992 { 993 int32_t sum = 0; 994 995 while (len > 1) { 996 /* alignment */ 997 sum += *(uint16_t *)p; 998 p = (char *)p + sizeof (uint16_t); 999 if (sum & 0x80000000) 1000 sum = (sum & 0xFFFF) + (sum >> 16); 1001 len -= 2; 1002 } 1003 1004 if (len) 1005 sum += (uint16_t)*(unsigned char *)p; 1006 1007 while (sum >> 16) 1008 sum = (sum & 0xFFFF) + (sum >> 16); 1009 1010 return (~sum); 1011 } 1012 1013 static const mdb_bitmask_t tcp_flags[] = { 1014 { "SYN", TH_SYN, TH_SYN }, 1015 { "ACK", TH_ACK, TH_ACK }, 1016 { "FIN", TH_FIN, TH_FIN }, 1017 { "RST", TH_RST, TH_RST }, 1018 { "PSH", TH_PUSH, TH_PUSH }, 1019 { "ECE", TH_ECE, TH_ECE }, 1020 { "CWR", TH_CWR, TH_CWR }, 1021 { NULL, 0, 0 } 1022 }; 1023 1024 /* TCP option length */ 1025 #define TCPOPT_HEADER_LEN 2 1026 #define TCPOPT_MAXSEG_LEN 4 1027 #define TCPOPT_WS_LEN 3 1028 #define TCPOPT_TSTAMP_LEN 10 1029 #define TCPOPT_SACK_OK_LEN 2 1030 1031 static void 1032 tcphdr_print_options(uint8_t *opts, uint32_t opts_len) 1033 { 1034 uint8_t *endp; 1035 uint32_t len, val; 1036 1037 mdb_printf("%<b>Options:%</b>"); 1038 endp = opts + opts_len; 1039 while (opts < endp) { 1040 len = endp - opts; 1041 switch (*opts) { 1042 case TCPOPT_EOL: 1043 mdb_printf(" EOL"); 1044 opts++; 1045 break; 1046 1047 case TCPOPT_NOP: 1048 mdb_printf(" NOP"); 1049 opts++; 1050 break; 1051 1052 case TCPOPT_MAXSEG: { 1053 uint16_t mss; 1054 1055 if (len < TCPOPT_MAXSEG_LEN || 1056 opts[1] != TCPOPT_MAXSEG_LEN) { 1057 mdb_printf(" <Truncated MSS>\n"); 1058 return; 1059 } 1060 mdb_nhconvert(&mss, opts + TCPOPT_HEADER_LEN, 1061 sizeof (mss)); 1062 mdb_printf(" MSS=%u", mss); 1063 opts += TCPOPT_MAXSEG_LEN; 1064 break; 1065 } 1066 1067 case TCPOPT_WSCALE: 1068 if (len < TCPOPT_WS_LEN || opts[1] != TCPOPT_WS_LEN) { 1069 mdb_printf(" <Truncated WS>\n"); 1070 return; 1071 } 1072 mdb_printf(" WS=%u", opts[2]); 1073 opts += TCPOPT_WS_LEN; 1074 break; 1075 1076 case TCPOPT_TSTAMP: { 1077 if (len < TCPOPT_TSTAMP_LEN || 1078 opts[1] != TCPOPT_TSTAMP_LEN) { 1079 mdb_printf(" <Truncated TS>\n"); 1080 return; 1081 } 1082 1083 opts += TCPOPT_HEADER_LEN; 1084 mdb_nhconvert(&val, opts, sizeof (val)); 1085 mdb_printf(" TS_VAL=%u,", val); 1086 1087 opts += sizeof (val); 1088 mdb_nhconvert(&val, opts, sizeof (val)); 1089 mdb_printf("TS_ECHO=%u", val); 1090 1091 opts += sizeof (val); 1092 break; 1093 } 1094 1095 case TCPOPT_SACK_PERMITTED: 1096 if (len < TCPOPT_SACK_OK_LEN || 1097 opts[1] != TCPOPT_SACK_OK_LEN) { 1098 mdb_printf(" <Truncated SACK_OK>\n"); 1099 return; 1100 } 1101 mdb_printf(" SACK_OK"); 1102 opts += TCPOPT_SACK_OK_LEN; 1103 break; 1104 1105 case TCPOPT_SACK: { 1106 uint32_t sack_len; 1107 1108 if (len <= TCPOPT_HEADER_LEN || len < opts[1] || 1109 opts[1] <= TCPOPT_HEADER_LEN) { 1110 mdb_printf(" <Truncated SACK>\n"); 1111 return; 1112 } 1113 sack_len = opts[1] - TCPOPT_HEADER_LEN; 1114 opts += TCPOPT_HEADER_LEN; 1115 1116 mdb_printf(" SACK="); 1117 while (sack_len > 0) { 1118 if (opts + 2 * sizeof (val) > endp) { 1119 mdb_printf("<Truncated SACK>\n"); 1120 opts = endp; 1121 break; 1122 } 1123 1124 mdb_nhconvert(&val, opts, sizeof (val)); 1125 mdb_printf("<%u,", val); 1126 opts += sizeof (val); 1127 mdb_nhconvert(&val, opts, sizeof (val)); 1128 mdb_printf("%u>", val); 1129 opts += sizeof (val); 1130 1131 sack_len -= 2 * sizeof (val); 1132 } 1133 break; 1134 } 1135 1136 default: 1137 mdb_printf(" Opts=<val=%u,len=%u>", *opts, 1138 opts[1]); 1139 opts += opts[1]; 1140 break; 1141 } 1142 } 1143 mdb_printf("\n"); 1144 } 1145 1146 static void 1147 tcphdr_print(struct tcphdr *tcph) 1148 { 1149 in_port_t sport, dport; 1150 tcp_seq seq, ack; 1151 uint16_t win, urp; 1152 1153 mdb_printf("%<b>TCP header%</b>\n"); 1154 1155 mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport)); 1156 mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport)); 1157 mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq)); 1158 mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack)); 1159 mdb_nhconvert(&win, &tcph->th_win, sizeof (win)); 1160 mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp)); 1161 1162 mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n", 1163 "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP", 1164 "FLAGS"); 1165 mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n", 1166 sport, dport, seq, ack, tcph->th_off << 2, win, 1167 tcph->th_sum, urp, tcph->th_flags, tcp_flags); 1168 mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n", 1169 sport, dport, seq, ack); 1170 } 1171 1172 /* ARGSUSED */ 1173 static int 1174 tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 1175 { 1176 struct tcphdr tcph; 1177 uint32_t opt_len; 1178 1179 if (!(flags & DCMD_ADDRSPEC)) 1180 return (DCMD_USAGE); 1181 1182 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 1183 mdb_warn("failed to read TCP header at %p", addr); 1184 return (DCMD_ERR); 1185 } 1186 tcphdr_print(&tcph); 1187 1188 /* If there are options, print them out also. */ 1189 opt_len = (tcph.th_off << 2) - TCP_MIN_HEADER_LENGTH; 1190 if (opt_len > 0) { 1191 uint8_t *opts, *opt_buf; 1192 1193 opt_buf = mdb_alloc(opt_len, UM_SLEEP); 1194 opts = (uint8_t *)addr + sizeof (tcph); 1195 if (mdb_vread(opt_buf, opt_len, (uintptr_t)opts) == -1) { 1196 mdb_warn("failed to read TCP options at %p", opts); 1197 return (DCMD_ERR); 1198 } 1199 tcphdr_print_options(opt_buf, opt_len); 1200 mdb_free(opt_buf, opt_len); 1201 } 1202 1203 return (DCMD_OK); 1204 } 1205 1206 static void 1207 udphdr_print(struct udphdr *udph) 1208 { 1209 in_port_t sport, dport; 1210 uint16_t hlen; 1211 1212 mdb_printf("%<b>UDP header%</b>\n"); 1213 1214 mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport)); 1215 mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport)); 1216 mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen)); 1217 1218 mdb_printf("%<u>%14s %14s %5s %6s%</u>\n", 1219 "SPORT", "DPORT", "LEN", "CSUM"); 1220 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport, 1221 dport, dport, hlen, udph->uh_sum); 1222 } 1223 1224 /* ARGSUSED */ 1225 static int 1226 udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 1227 { 1228 struct udphdr udph; 1229 1230 if (!(flags & DCMD_ADDRSPEC)) 1231 return (DCMD_USAGE); 1232 1233 if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 1234 mdb_warn("failed to read UDP header at %p", addr); 1235 return (DCMD_ERR); 1236 } 1237 udphdr_print(&udph); 1238 return (DCMD_OK); 1239 } 1240 1241 static void 1242 sctphdr_print(sctp_hdr_t *sctph) 1243 { 1244 in_port_t sport, dport; 1245 1246 mdb_printf("%<b>SCTP header%</b>\n"); 1247 mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport)); 1248 mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport)); 1249 1250 mdb_printf("%<u>%14s %14s %10s %10s%</u>\n", 1251 "SPORT", "DPORT", "VTAG", "CHKSUM"); 1252 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport, 1253 dport, dport, sctph->sh_verf, sctph->sh_chksum); 1254 } 1255 1256 /* ARGSUSED */ 1257 static int 1258 sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 1259 { 1260 sctp_hdr_t sctph; 1261 1262 if (!(flags & DCMD_ADDRSPEC)) 1263 return (DCMD_USAGE); 1264 1265 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 1266 mdb_warn("failed to read SCTP header at %p", addr); 1267 return (DCMD_ERR); 1268 } 1269 1270 sctphdr_print(&sctph); 1271 return (DCMD_OK); 1272 } 1273 1274 static int 1275 transport_hdr(int proto, uintptr_t addr) 1276 { 1277 mdb_printf("\n"); 1278 switch (proto) { 1279 case IPPROTO_TCP: { 1280 struct tcphdr tcph; 1281 1282 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 1283 mdb_warn("failed to read TCP header at %p", addr); 1284 return (DCMD_ERR); 1285 } 1286 tcphdr_print(&tcph); 1287 break; 1288 } 1289 case IPPROTO_UDP: { 1290 struct udphdr udph; 1291 1292 if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 1293 mdb_warn("failed to read UDP header at %p", addr); 1294 return (DCMD_ERR); 1295 } 1296 udphdr_print(&udph); 1297 break; 1298 } 1299 case IPPROTO_SCTP: { 1300 sctp_hdr_t sctph; 1301 1302 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 1303 mdb_warn("failed to read SCTP header at %p", addr); 1304 return (DCMD_ERR); 1305 } 1306 sctphdr_print(&sctph); 1307 break; 1308 } 1309 default: 1310 break; 1311 } 1312 1313 return (DCMD_OK); 1314 } 1315 1316 static const mdb_bitmask_t ip_flags[] = { 1317 { "DF", IPH_DF, IPH_DF }, 1318 { "MF", IPH_MF, IPH_MF }, 1319 { NULL, 0, 0 } 1320 }; 1321 1322 /* ARGSUSED */ 1323 static int 1324 iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1325 { 1326 uint_t verbose = FALSE, force = FALSE; 1327 ipha_t iph[1]; 1328 uint16_t ver, totlen, hdrlen, ipid, off, csum; 1329 uintptr_t nxt_proto; 1330 char exp_csum[8]; 1331 1332 if (mdb_getopts(argc, argv, 1333 'v', MDB_OPT_SETBITS, TRUE, &verbose, 1334 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 1335 return (DCMD_USAGE); 1336 1337 if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 1338 mdb_warn("failed to read IPv4 header at %p", addr); 1339 return (DCMD_ERR); 1340 } 1341 1342 ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4; 1343 if (ver != IPV4_VERSION) { 1344 if (ver == IPV6_VERSION) { 1345 return (ip6hdr(addr, flags, argc, argv)); 1346 } else if (!force) { 1347 mdb_warn("unknown IP version: %d\n", ver); 1348 return (DCMD_ERR); 1349 } 1350 } 1351 1352 mdb_printf("%<b>IPv4 header%</b>\n"); 1353 mdb_printf("%-34s %-34s\n" 1354 "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n", 1355 "SRC", "DST", 1356 "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM", 1357 "EXP-CSUM", "FLGS"); 1358 1359 hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2; 1360 mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen)); 1361 mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid)); 1362 mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off)); 1363 if (hdrlen == IP_SIMPLE_HDR_LENGTH) { 1364 if ((csum = ipcksum(iph, sizeof (*iph))) != 0) 1365 csum = ~(~csum + ~iph->ipha_hdr_checksum); 1366 else 1367 csum = iph->ipha_hdr_checksum; 1368 mdb_snprintf(exp_csum, 8, "%u", csum); 1369 } else { 1370 mdb_snprintf(exp_csum, 8, "<n/a>"); 1371 } 1372 1373 mdb_printf("%-34I %-34I%\n" 1374 "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n", 1375 iph->ipha_src, iph->ipha_dst, 1376 hdrlen, iph->ipha_type_of_service, totlen, ipid, 1377 (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol, 1378 iph->ipha_hdr_checksum, exp_csum, off, ip_flags); 1379 1380 if (verbose) { 1381 nxt_proto = addr + hdrlen; 1382 return (transport_hdr(iph->ipha_protocol, nxt_proto)); 1383 } else { 1384 return (DCMD_OK); 1385 } 1386 } 1387 1388 /* ARGSUSED */ 1389 static int 1390 ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1391 { 1392 uint_t verbose = FALSE, force = FALSE; 1393 ip6_t iph[1]; 1394 int ver, class, flow; 1395 uint16_t plen; 1396 uintptr_t nxt_proto; 1397 1398 if (mdb_getopts(argc, argv, 1399 'v', MDB_OPT_SETBITS, TRUE, &verbose, 1400 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 1401 return (DCMD_USAGE); 1402 1403 if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 1404 mdb_warn("failed to read IPv6 header at %p", addr); 1405 return (DCMD_ERR); 1406 } 1407 1408 ver = (iph->ip6_vfc & 0xf0) >> 4; 1409 if (ver != IPV6_VERSION) { 1410 if (ver == IPV4_VERSION) { 1411 return (iphdr(addr, flags, argc, argv)); 1412 } else if (!force) { 1413 mdb_warn("unknown IP version: %d\n", ver); 1414 return (DCMD_ERR); 1415 } 1416 } 1417 1418 mdb_printf("%<b>IPv6 header%</b>\n"); 1419 mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n", 1420 "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP"); 1421 1422 class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20; 1423 mdb_nhconvert(&class, &class, sizeof (class)); 1424 flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL; 1425 mdb_nhconvert(&flow, &flow, sizeof (flow)); 1426 mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen)); 1427 1428 mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n", 1429 &iph->ip6_src, &iph->ip6_dst, 1430 class, flow, plen, iph->ip6_nxt, iph->ip6_hlim); 1431 1432 if (verbose) { 1433 nxt_proto = addr + sizeof (ip6_t); 1434 return (transport_hdr(iph->ip6_nxt, nxt_proto)); 1435 } else { 1436 return (DCMD_OK); 1437 } 1438 } 1439 1440 int 1441 nce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1442 { 1443 nce_t nce; 1444 nce_cbdata_t nce_cb; 1445 int ipversion = 0; 1446 const char *opt_P = NULL, *opt_ill = NULL; 1447 1448 if (mdb_getopts(argc, argv, 1449 'i', MDB_OPT_STR, &opt_ill, 1450 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 1451 return (DCMD_USAGE); 1452 1453 if (opt_P != NULL) { 1454 if (strcmp("v4", opt_P) == 0) { 1455 ipversion = IPV4_VERSION; 1456 } else if (strcmp("v6", opt_P) == 0) { 1457 ipversion = IPV6_VERSION; 1458 } else { 1459 mdb_warn("invalid protocol '%s'\n", opt_P); 1460 return (DCMD_USAGE); 1461 } 1462 } 1463 1464 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 1465 mdb_printf("%<u>%?s %5s %18s %?s %s %s %</u>\n", 1466 "ADDR", "INTF", "LLADDR", "FP_MP", "REFCNT", 1467 "NCE_ADDR"); 1468 } 1469 1470 bzero(&nce_cb, sizeof (nce_cb)); 1471 if (opt_ill != NULL) { 1472 strcpy(nce_cb.nce_ill_name, opt_ill); 1473 } 1474 nce_cb.nce_ipversion = ipversion; 1475 1476 if (flags & DCMD_ADDRSPEC) { 1477 (void) mdb_vread(&nce, sizeof (nce_t), addr); 1478 (void) nce_format(addr, &nce, &nce_cb); 1479 } else if (mdb_walk("nce", (mdb_walk_cb_t)nce_format, &nce_cb) == -1) { 1480 mdb_warn("failed to walk ire table"); 1481 return (DCMD_ERR); 1482 } 1483 1484 return (DCMD_OK); 1485 } 1486 1487 /* ARGSUSED */ 1488 static int 1489 dce_format(uintptr_t addr, const dce_t *dcep, void *dce_cb_arg) 1490 { 1491 static const mdb_bitmask_t dmasks[] = { 1492 { "D", DCEF_DEFAULT, DCEF_DEFAULT }, 1493 { "P", DCEF_PMTU, DCEF_PMTU }, 1494 { "U", DCEF_UINFO, DCEF_UINFO }, 1495 { "S", DCEF_TOO_SMALL_PMTU, DCEF_TOO_SMALL_PMTU }, 1496 { NULL, 0, 0 } 1497 }; 1498 char flagsbuf[2 * A_CNT(dmasks)]; 1499 int ipversion = *(int *)dce_cb_arg; 1500 boolean_t condemned = dcep->dce_generation == DCE_GENERATION_CONDEMNED; 1501 1502 if (ipversion != 0 && ipversion != dcep->dce_ipversion) 1503 return (WALK_NEXT); 1504 1505 mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%b", dcep->dce_flags, 1506 dmasks); 1507 1508 switch (dcep->dce_ipversion) { 1509 case IPV4_VERSION: 1510 mdb_printf("%<u>%?p%3s %8s %8d %30I %</u>\n", addr, condemned ? 1511 "(C)" : "", flagsbuf, dcep->dce_pmtu, &dcep->dce_v4addr); 1512 break; 1513 case IPV6_VERSION: 1514 mdb_printf("%<u>%?p%3s %8s %8d %30N %</u>\n", addr, condemned ? 1515 "(C)" : "", flagsbuf, dcep->dce_pmtu, &dcep->dce_v6addr); 1516 break; 1517 default: 1518 mdb_printf("%<u>%?p%3s %8s %8d %30s %</u>\n", addr, condemned ? 1519 "(C)" : "", flagsbuf, dcep->dce_pmtu, ""); 1520 } 1521 1522 return (WALK_NEXT); 1523 } 1524 1525 int 1526 dce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1527 { 1528 dce_t dce; 1529 const char *opt_P = NULL; 1530 const char *zone_name = NULL; 1531 ip_stack_t *ipst = NULL; 1532 int ipversion = 0; 1533 1534 if (mdb_getopts(argc, argv, 1535 's', MDB_OPT_STR, &zone_name, 1536 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 1537 return (DCMD_USAGE); 1538 1539 /* Follow the specified zone name to find a ip_stack_t*. */ 1540 if (zone_name != NULL) { 1541 ipst = zone_to_ips(zone_name); 1542 if (ipst == NULL) 1543 return (DCMD_USAGE); 1544 } 1545 1546 if (opt_P != NULL) { 1547 if (strcmp("v4", opt_P) == 0) { 1548 ipversion = IPV4_VERSION; 1549 } else if (strcmp("v6", opt_P) == 0) { 1550 ipversion = IPV6_VERSION; 1551 } else { 1552 mdb_warn("invalid protocol '%s'\n", opt_P); 1553 return (DCMD_USAGE); 1554 } 1555 } 1556 1557 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 1558 mdb_printf("%<u>%?s%3s %8s %8s %30s %</u>\n", 1559 "ADDR", "", "FLAGS", "PMTU", "DST_ADDR"); 1560 } 1561 1562 if (flags & DCMD_ADDRSPEC) { 1563 (void) mdb_vread(&dce, sizeof (dce_t), addr); 1564 (void) dce_format(addr, &dce, &ipversion); 1565 } else if (mdb_pwalk("dce", (mdb_walk_cb_t)dce_format, &ipversion, 1566 (uintptr_t)ipst) == -1) { 1567 mdb_warn("failed to walk dce cache"); 1568 return (DCMD_ERR); 1569 } 1570 1571 return (DCMD_OK); 1572 } 1573 1574 int 1575 ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1576 { 1577 uint_t verbose = FALSE; 1578 ire_t ire; 1579 ire_cbdata_t ire_cb; 1580 int ipversion = 0; 1581 const char *opt_P = NULL; 1582 const char *zone_name = NULL; 1583 ip_stack_t *ipst = NULL; 1584 1585 if (mdb_getopts(argc, argv, 1586 'v', MDB_OPT_SETBITS, TRUE, &verbose, 1587 's', MDB_OPT_STR, &zone_name, 1588 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 1589 return (DCMD_USAGE); 1590 1591 /* Follow the specified zone name to find a ip_stack_t*. */ 1592 if (zone_name != NULL) { 1593 ipst = zone_to_ips(zone_name); 1594 if (ipst == NULL) 1595 return (DCMD_USAGE); 1596 } 1597 1598 if (opt_P != NULL) { 1599 if (strcmp("v4", opt_P) == 0) { 1600 ipversion = IPV4_VERSION; 1601 } else if (strcmp("v6", opt_P) == 0) { 1602 ipversion = IPV6_VERSION; 1603 } else { 1604 mdb_warn("invalid protocol '%s'\n", opt_P); 1605 return (DCMD_USAGE); 1606 } 1607 } 1608 1609 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 1610 1611 if (verbose) { 1612 mdb_printf("%?s %40s %-20s%\n" 1613 "%?s %40s %-20s%\n" 1614 "%<u>%?s %40s %4s %-20s %s%</u>\n", 1615 "ADDR", "SRC", "TYPE", 1616 "", "DST", "MARKS", 1617 "", "STACK", "ZONE", "FLAGS", "INTF"); 1618 } else { 1619 mdb_printf("%<u>%?s %30s %30s %5s %4s %s%</u>\n", 1620 "ADDR", "SRC", "DST", "STACK", "ZONE", "INTF"); 1621 } 1622 } 1623 1624 ire_cb.verbose = (verbose == TRUE); 1625 ire_cb.ire_ipversion = ipversion; 1626 1627 if (flags & DCMD_ADDRSPEC) { 1628 (void) mdb_vread(&ire, sizeof (ire_t), addr); 1629 (void) ire_format(addr, &ire, &ire_cb); 1630 } else if (mdb_pwalk("ire", (mdb_walk_cb_t)ire_format, &ire_cb, 1631 (uintptr_t)ipst) == -1) { 1632 mdb_warn("failed to walk ire table"); 1633 return (DCMD_ERR); 1634 } 1635 1636 return (DCMD_OK); 1637 } 1638 1639 static size_t 1640 mi_osize(const queue_t *q) 1641 { 1642 /* 1643 * The code in common/inet/mi.c allocates an extra word to store the 1644 * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s. 1645 */ 1646 struct mi_block { 1647 size_t mi_nbytes; 1648 struct mi_o_s mi_o; 1649 } m; 1650 1651 if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - 1652 sizeof (m)) == sizeof (m)) 1653 return (m.mi_nbytes - sizeof (m)); 1654 1655 return (0); 1656 } 1657 1658 static void 1659 ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes) 1660 { 1661 char name[32]; 1662 ill_t ill; 1663 1664 if (mdb_vread(&ill, sizeof (ill), 1665 (uintptr_t)q->q_ptr) == sizeof (ill) && 1666 mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0) 1667 (void) mdb_snprintf(buf, nbytes, "if: %s", name); 1668 } 1669 1670 void 1671 ip_qinfo(const queue_t *q, char *buf, size_t nbytes) 1672 { 1673 size_t size = mi_osize(q); 1674 1675 if (size == sizeof (ill_t)) 1676 ip_ill_qinfo(q, buf, nbytes); 1677 } 1678 1679 uintptr_t 1680 ip_rnext(const queue_t *q) 1681 { 1682 size_t size = mi_osize(q); 1683 ill_t ill; 1684 1685 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 1686 (uintptr_t)q->q_ptr) == sizeof (ill)) 1687 return ((uintptr_t)ill.ill_rq); 1688 1689 return (NULL); 1690 } 1691 1692 uintptr_t 1693 ip_wnext(const queue_t *q) 1694 { 1695 size_t size = mi_osize(q); 1696 ill_t ill; 1697 1698 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 1699 (uintptr_t)q->q_ptr) == sizeof (ill)) 1700 return ((uintptr_t)ill.ill_wq); 1701 1702 return (NULL); 1703 } 1704 1705 /* 1706 * Print the core fields in an squeue_t. With the "-v" argument, 1707 * provide more verbose output. 1708 */ 1709 static int 1710 squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1711 { 1712 unsigned int i; 1713 unsigned int verbose = FALSE; 1714 const int SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9); 1715 boolean_t arm; 1716 squeue_t squeue; 1717 1718 if (!(flags & DCMD_ADDRSPEC)) { 1719 if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue", 1720 argc, argv) == -1) { 1721 mdb_warn("failed to walk squeue cache"); 1722 return (DCMD_ERR); 1723 } 1724 return (DCMD_OK); 1725 } 1726 1727 if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) 1728 != argc) 1729 return (DCMD_USAGE); 1730 1731 if (!DCMD_HDRSPEC(flags) && verbose) 1732 mdb_printf("\n\n"); 1733 1734 if (DCMD_HDRSPEC(flags) || verbose) { 1735 mdb_printf("%?s %-5s %-3s %?s %?s %?s\n", 1736 "ADDR", "STATE", "CPU", 1737 "FIRST", "LAST", "WORKER"); 1738 } 1739 1740 if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) { 1741 mdb_warn("cannot read squeue_t at %p", addr); 1742 return (DCMD_ERR); 1743 } 1744 1745 mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n", 1746 addr, squeue.sq_state, squeue.sq_bind, 1747 squeue.sq_first, squeue.sq_last, squeue.sq_worker); 1748 1749 if (!verbose) 1750 return (DCMD_OK); 1751 1752 arm = B_TRUE; 1753 for (i = 0; squeue_states[i].bit_name != NULL; i++) { 1754 if (((squeue.sq_state) & (1 << i)) == 0) 1755 continue; 1756 1757 if (arm) { 1758 mdb_printf("%*s|\n", SQUEUE_STATEDELT, ""); 1759 mdb_printf("%*s+--> ", SQUEUE_STATEDELT, ""); 1760 arm = B_FALSE; 1761 } else 1762 mdb_printf("%*s ", SQUEUE_STATEDELT, ""); 1763 1764 mdb_printf("%-12s %s\n", squeue_states[i].bit_name, 1765 squeue_states[i].bit_descr); 1766 } 1767 1768 return (DCMD_OK); 1769 } 1770 1771 static void 1772 ip_squeue_help(void) 1773 { 1774 mdb_printf("Print the core information for a given NCA squeue_t.\n\n"); 1775 mdb_printf("Options:\n"); 1776 mdb_printf("\t-v\tbe verbose (more descriptive)\n"); 1777 } 1778 1779 /* 1780 * This is called by ::th_trace (via a callback) when walking the th_hash 1781 * list. It calls modent to find the entries. 1782 */ 1783 /* ARGSUSED */ 1784 static int 1785 modent_summary(uintptr_t addr, const void *data, void *private) 1786 { 1787 th_walk_data_t *thw = private; 1788 const struct mod_hash_entry *mhe = data; 1789 th_trace_t th; 1790 1791 if (mdb_vread(&th, sizeof (th), (uintptr_t)mhe->mhe_val) == -1) { 1792 mdb_warn("failed to read th_trace_t %p", mhe->mhe_val); 1793 return (WALK_ERR); 1794 } 1795 1796 if (th.th_refcnt == 0 && thw->thw_non_zero_only) 1797 return (WALK_NEXT); 1798 1799 if (!thw->thw_match) { 1800 mdb_printf("%?p %?p %?p %8d %?p\n", thw->thw_ipst, mhe->mhe_key, 1801 mhe->mhe_val, th.th_refcnt, th.th_id); 1802 } else if (thw->thw_matchkey == (uintptr_t)mhe->mhe_key) { 1803 int i, j, k; 1804 tr_buf_t *tr; 1805 1806 mdb_printf("Object %p in IP stack %p:\n", mhe->mhe_key, 1807 thw->thw_ipst); 1808 i = th.th_trace_lastref; 1809 mdb_printf("\tThread %p refcnt %d:\n", th.th_id, 1810 th.th_refcnt); 1811 for (j = TR_BUF_MAX; j > 0; j--) { 1812 tr = th.th_trbuf + i; 1813 if (tr->tr_depth == 0 || tr->tr_depth > TR_STACK_DEPTH) 1814 break; 1815 mdb_printf("\t T%+ld:\n", tr->tr_time - 1816 thw->thw_lbolt); 1817 for (k = 0; k < tr->tr_depth; k++) 1818 mdb_printf("\t\t%a\n", tr->tr_stack[k]); 1819 if (--i < 0) 1820 i = TR_BUF_MAX - 1; 1821 } 1822 } 1823 return (WALK_NEXT); 1824 } 1825 1826 /* 1827 * This is called by ::th_trace (via a callback) when walking the th_hash 1828 * list. It calls modent to find the entries. 1829 */ 1830 /* ARGSUSED */ 1831 static int 1832 th_hash_summary(uintptr_t addr, const void *data, void *private) 1833 { 1834 const th_hash_t *thh = data; 1835 th_walk_data_t *thw = private; 1836 1837 thw->thw_ipst = (uintptr_t)thh->thh_ipst; 1838 return (mdb_pwalk("modent", modent_summary, private, 1839 (uintptr_t)thh->thh_hash)); 1840 } 1841 1842 /* 1843 * Print or summarize the th_trace_t structures. 1844 */ 1845 static int 1846 th_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1847 { 1848 th_walk_data_t thw; 1849 1850 (void) memset(&thw, 0, sizeof (thw)); 1851 1852 if (mdb_getopts(argc, argv, 1853 'n', MDB_OPT_SETBITS, TRUE, &thw.thw_non_zero_only, 1854 NULL) != argc) 1855 return (DCMD_USAGE); 1856 1857 if (!(flags & DCMD_ADDRSPEC)) { 1858 /* 1859 * No address specified. Walk all of the th_hash_t in the 1860 * system, and summarize the th_trace_t entries in each. 1861 */ 1862 mdb_printf("%?s %?s %?s %8s %?s\n", 1863 "IPSTACK", "OBJECT", "TRACE", "REFCNT", "THREAD"); 1864 thw.thw_match = B_FALSE; 1865 } else { 1866 thw.thw_match = B_TRUE; 1867 thw.thw_matchkey = addr; 1868 1869 if ((thw.thw_lbolt = (clock_t)mdb_get_lbolt()) == -1) { 1870 mdb_warn("failed to read lbolt"); 1871 return (DCMD_ERR); 1872 } 1873 } 1874 if (mdb_pwalk("th_hash", th_hash_summary, &thw, NULL) == -1) { 1875 mdb_warn("can't walk th_hash entries"); 1876 return (DCMD_ERR); 1877 } 1878 return (DCMD_OK); 1879 } 1880 1881 static void 1882 th_trace_help(void) 1883 { 1884 mdb_printf("If given an address of an ill_t, ipif_t, ire_t, or ncec_t, " 1885 "print the\n" 1886 "corresponding th_trace_t structure in detail. Otherwise, if no " 1887 "address is\n" 1888 "given, then summarize all th_trace_t structures.\n\n"); 1889 mdb_printf("Options:\n" 1890 "\t-n\tdisplay only entries with non-zero th_refcnt\n"); 1891 } 1892 1893 static const mdb_dcmd_t dcmds[] = { 1894 { "conn_status", ":", 1895 "display connection structures from ipcl hash tables", 1896 conn_status, conn_status_help }, 1897 { "srcid_status", ":", 1898 "display connection structures from ipcl hash tables", 1899 srcid_status }, 1900 { "ill", "?[-v] [-P v4 | v6] [-s exclusive-ip-zone-name]", 1901 "display ill_t structures", ill, ill_help }, 1902 { "illif", "?[-P v4 | v6]", 1903 "display or filter IP Lower Level InterFace structures", illif, 1904 illif_help }, 1905 { "iphdr", ":[-vf]", "display an IPv4 header", iphdr }, 1906 { "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr }, 1907 { "ipif", "?[-v] [-P v4 | v6]", "display ipif structures", 1908 ipif, ipif_help }, 1909 { "ire", "?[-v] [-P v4|v6] [-s exclusive-ip-zone-name]", 1910 "display Internet Route Entry structures", ire }, 1911 { "nce", "?[-P v4|v6] [-i <interface>]", 1912 "display interface-specific Neighbor Cache structures", nce }, 1913 { "ncec", "?[-P v4 | v6]", "display Neighbor Cache Entry structures", 1914 ncec }, 1915 { "dce", "?[-P v4|v6] [-s exclusive-ip-zone-name]", 1916 "display Destination Cache Entry structures", dce }, 1917 { "squeue", ":[-v]", "print core squeue_t info", squeue, 1918 ip_squeue_help }, 1919 { "tcphdr", ":", "display a TCP header", tcphdr }, 1920 { "udphdr", ":", "display an UDP header", udphdr }, 1921 { "sctphdr", ":", "display an SCTP header", sctphdr }, 1922 { "th_trace", "?[-n]", "display th_trace_t structures", th_trace, 1923 th_trace_help }, 1924 { NULL } 1925 }; 1926 1927 static const mdb_walker_t walkers[] = { 1928 { "conn_status", "walk list of conn_t structures", 1929 ip_stacks_common_walk_init, conn_status_walk_step, NULL }, 1930 { "illif", "walk list of ill interface types for all stacks", 1931 ip_stacks_common_walk_init, illif_walk_step, NULL }, 1932 { "illif_stack", "walk list of ill interface types", 1933 illif_stack_walk_init, illif_stack_walk_step, 1934 illif_stack_walk_fini }, 1935 { "ill", "walk active ill_t structures for all stacks", 1936 ill_walk_init, ill_walk_step, NULL }, 1937 { "ipif", "walk list of ipif structures for all stacks", 1938 ipif_walk_init, ipif_walk_step, NULL }, 1939 { "ipif_list", "walk the linked list of ipif structures " 1940 "for a given ill", 1941 ip_list_walk_init, ip_list_walk_step, 1942 ip_list_walk_fini, &ipif_walk_arg }, 1943 { "srcid", "walk list of srcid_map structures for all stacks", 1944 ip_stacks_common_walk_init, srcid_walk_step, NULL }, 1945 { "srcid_list", "walk list of srcid_map structures for a stack", 1946 ip_list_walk_init, ip_list_walk_step, ip_list_walk_fini, 1947 &srcid_walk_arg }, 1948 { "ire", "walk active ire_t structures", 1949 ire_walk_init, ire_walk_step, NULL }, 1950 { "ire_next", "walk ire_t structures in the ctable", 1951 ire_next_walk_init, ire_next_walk_step, NULL }, 1952 { "nce", "walk active nce_t structures", 1953 nce_walk_init, nce_walk_step, NULL }, 1954 { "dce", "walk active dce_t structures", 1955 dce_walk_init, dce_walk_step, NULL }, 1956 { "ip_stacks", "walk all the ip_stack_t", 1957 ns_walk_init, ip_stacks_walk_step, NULL }, 1958 { "tcp_stacks", "walk all the tcp_stack_t", 1959 ns_walk_init, tcp_stacks_walk_step, NULL }, 1960 { "sctp_stacks", "walk all the sctp_stack_t", 1961 ns_walk_init, sctp_stacks_walk_step, NULL }, 1962 { "udp_stacks", "walk all the udp_stack_t", 1963 ns_walk_init, udp_stacks_walk_step, NULL }, 1964 { "th_hash", "walk all the th_hash_t entries", 1965 th_hash_walk_init, th_hash_walk_step, NULL }, 1966 { "ncec", "walk list of ncec structures for all stacks", 1967 ip_stacks_common_walk_init, ncec_walk_step, NULL }, 1968 { "ncec_stack", "walk list of ncec structures", 1969 ncec_stack_walk_init, ncec_stack_walk_step, 1970 ncec_stack_walk_fini}, 1971 { "udp_hash", "walk list of conn_t structures in ips_ipcl_udp_fanout", 1972 ipcl_hash_walk_init, ipcl_hash_walk_step, 1973 ipcl_hash_walk_fini, &udp_hash_arg}, 1974 { "conn_hash", "walk list of conn_t structures in ips_ipcl_conn_fanout", 1975 ipcl_hash_walk_init, ipcl_hash_walk_step, 1976 ipcl_hash_walk_fini, &conn_hash_arg}, 1977 { "bind_hash", "walk list of conn_t structures in ips_ipcl_bind_fanout", 1978 ipcl_hash_walk_init, ipcl_hash_walk_step, 1979 ipcl_hash_walk_fini, &bind_hash_arg}, 1980 { "proto_hash", "walk list of conn_t structures in " 1981 "ips_ipcl_proto_fanout", 1982 ipcl_hash_walk_init, ipcl_hash_walk_step, 1983 ipcl_hash_walk_fini, &proto_hash_arg}, 1984 { "proto_v6_hash", "walk list of conn_t structures in " 1985 "ips_ipcl_proto_fanout_v6", 1986 ipcl_hash_walk_init, ipcl_hash_walk_step, 1987 ipcl_hash_walk_fini, &proto_v6_hash_arg}, 1988 { "ilb_stacks", "walk all ilb_stack_t", 1989 ns_walk_init, ilb_stacks_walk_step, NULL }, 1990 { "ilb_rules", "walk ilb rules in a given ilb_stack_t", 1991 ilb_rules_walk_init, ilb_rules_walk_step, NULL }, 1992 { "ilb_servers", "walk server in a given ilb_rule_t", 1993 ilb_servers_walk_init, ilb_servers_walk_step, NULL }, 1994 { "ilb_nat_src", "walk NAT source table of a given ilb_stack_t", 1995 ilb_nat_src_walk_init, ilb_nat_src_walk_step, 1996 ilb_common_walk_fini }, 1997 { "ilb_conns", "walk NAT table of a given ilb_stack_t", 1998 ilb_conn_walk_init, ilb_conn_walk_step, ilb_common_walk_fini }, 1999 { "ilb_stickys", "walk sticky table of a given ilb_stack_t", 2000 ilb_sticky_walk_init, ilb_sticky_walk_step, 2001 ilb_common_walk_fini }, 2002 { "tcps_sc", "walk all the per CPU stats counters of a tcp_stack_t", 2003 tcps_sc_walk_init, tcps_sc_walk_step, NULL }, 2004 { NULL } 2005 }; 2006 2007 static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext }; 2008 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 2009 2010 const mdb_modinfo_t * 2011 _mdb_init(void) 2012 { 2013 GElf_Sym sym; 2014 2015 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 2016 mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value); 2017 2018 return (&modinfo); 2019 } 2020 2021 void 2022 _mdb_fini(void) 2023 { 2024 GElf_Sym sym; 2025 2026 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 2027 mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value); 2028 } 2029 2030 static char * 2031 ncec_state(int ncec_state) 2032 { 2033 switch (ncec_state) { 2034 case ND_UNCHANGED: 2035 return ("unchanged"); 2036 case ND_INCOMPLETE: 2037 return ("incomplete"); 2038 case ND_REACHABLE: 2039 return ("reachable"); 2040 case ND_STALE: 2041 return ("stale"); 2042 case ND_DELAY: 2043 return ("delay"); 2044 case ND_PROBE: 2045 return ("probe"); 2046 case ND_UNREACHABLE: 2047 return ("unreach"); 2048 case ND_INITIAL: 2049 return ("initial"); 2050 default: 2051 return ("??"); 2052 } 2053 } 2054 2055 static char * 2056 ncec_l2_addr(const ncec_t *ncec, const ill_t *ill) 2057 { 2058 uchar_t *h; 2059 static char addr_buf[L2MAXADDRSTRLEN]; 2060 2061 if (ncec->ncec_lladdr == NULL) { 2062 return ("None"); 2063 } 2064 2065 if (ill->ill_net_type == IRE_IF_RESOLVER) { 2066 2067 if (ill->ill_phys_addr_length == 0) 2068 return ("None"); 2069 h = mdb_zalloc(ill->ill_phys_addr_length, UM_SLEEP); 2070 if (mdb_vread(h, ill->ill_phys_addr_length, 2071 (uintptr_t)ncec->ncec_lladdr) == -1) { 2072 mdb_warn("failed to read hwaddr at %p", 2073 ncec->ncec_lladdr); 2074 return ("Unknown"); 2075 } 2076 mdb_mac_addr(h, ill->ill_phys_addr_length, 2077 addr_buf, sizeof (addr_buf)); 2078 } else { 2079 return ("None"); 2080 } 2081 mdb_free(h, ill->ill_phys_addr_length); 2082 return (addr_buf); 2083 } 2084 2085 static char * 2086 nce_l2_addr(const nce_t *nce, const ill_t *ill) 2087 { 2088 uchar_t *h; 2089 static char addr_buf[L2MAXADDRSTRLEN]; 2090 mblk_t mp; 2091 size_t mblen; 2092 2093 if (nce->nce_dlur_mp == NULL) 2094 return ("None"); 2095 2096 if (ill->ill_net_type == IRE_IF_RESOLVER) { 2097 if (mdb_vread(&mp, sizeof (mblk_t), 2098 (uintptr_t)nce->nce_dlur_mp) == -1) { 2099 mdb_warn("failed to read nce_dlur_mp at %p", 2100 nce->nce_dlur_mp); 2101 return ("None"); 2102 } 2103 if (ill->ill_phys_addr_length == 0) 2104 return ("None"); 2105 mblen = mp.b_wptr - mp.b_rptr; 2106 if (mblen > (sizeof (dl_unitdata_req_t) + MAX_SAP_LEN) || 2107 ill->ill_phys_addr_length > MAX_SAP_LEN || 2108 (NCE_LL_ADDR_OFFSET(ill) + 2109 ill->ill_phys_addr_length) > mblen) { 2110 return ("Unknown"); 2111 } 2112 h = mdb_zalloc(mblen, UM_SLEEP); 2113 if (mdb_vread(h, mblen, (uintptr_t)(mp.b_rptr)) == -1) { 2114 mdb_warn("failed to read hwaddr at %p", 2115 mp.b_rptr + NCE_LL_ADDR_OFFSET(ill)); 2116 return ("Unknown"); 2117 } 2118 mdb_mac_addr(h + NCE_LL_ADDR_OFFSET(ill), 2119 ill->ill_phys_addr_length, addr_buf, sizeof (addr_buf)); 2120 } else { 2121 return ("None"); 2122 } 2123 mdb_free(h, mblen); 2124 return (addr_buf); 2125 } 2126 2127 static void 2128 ncec_header(uint_t flags) 2129 { 2130 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 2131 2132 mdb_printf("%<u>%?s %-20s %-10s %-8s %-5s %s%</u>\n", 2133 "ADDR", "HW_ADDR", "STATE", "FLAGS", "ILL", "IP ADDR"); 2134 } 2135 } 2136 2137 int 2138 ncec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2139 { 2140 ncec_t ncec; 2141 ncec_cbdata_t id; 2142 int ipversion = 0; 2143 const char *opt_P = NULL; 2144 2145 if (mdb_getopts(argc, argv, 2146 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 2147 return (DCMD_USAGE); 2148 2149 if (opt_P != NULL) { 2150 if (strcmp("v4", opt_P) == 0) { 2151 ipversion = IPV4_VERSION; 2152 } else if (strcmp("v6", opt_P) == 0) { 2153 ipversion = IPV6_VERSION; 2154 } else { 2155 mdb_warn("invalid protocol '%s'\n", opt_P); 2156 return (DCMD_USAGE); 2157 } 2158 } 2159 2160 if (flags & DCMD_ADDRSPEC) { 2161 2162 if (mdb_vread(&ncec, sizeof (ncec_t), addr) == -1) { 2163 mdb_warn("failed to read ncec at %p\n", addr); 2164 return (DCMD_ERR); 2165 } 2166 if (ipversion != 0 && ncec.ncec_ipversion != ipversion) { 2167 mdb_printf("IP Version mismatch\n"); 2168 return (DCMD_ERR); 2169 } 2170 ncec_header(flags); 2171 return (ncec_format(addr, &ncec, ipversion)); 2172 2173 } else { 2174 id.ncec_addr = addr; 2175 id.ncec_ipversion = ipversion; 2176 ncec_header(flags); 2177 if (mdb_walk("ncec", (mdb_walk_cb_t)ncec_cb, &id) == -1) { 2178 mdb_warn("failed to walk ncec table\n"); 2179 return (DCMD_ERR); 2180 } 2181 } 2182 return (DCMD_OK); 2183 } 2184 2185 static int 2186 ncec_format(uintptr_t addr, const ncec_t *ncec, int ipversion) 2187 { 2188 static const mdb_bitmask_t ncec_flags[] = { 2189 { "P", NCE_F_NONUD, NCE_F_NONUD }, 2190 { "R", NCE_F_ISROUTER, NCE_F_ISROUTER }, 2191 { "N", NCE_F_NONUD, NCE_F_NONUD }, 2192 { "A", NCE_F_ANYCAST, NCE_F_ANYCAST }, 2193 { "C", NCE_F_CONDEMNED, NCE_F_CONDEMNED }, 2194 { "U", NCE_F_UNSOL_ADV, NCE_F_UNSOL_ADV }, 2195 { "B", NCE_F_BCAST, NCE_F_BCAST }, 2196 { NULL, 0, 0 } 2197 }; 2198 #define NCE_MAX_FLAGS (sizeof (ncec_flags) / sizeof (mdb_bitmask_t)) 2199 struct in_addr nceaddr; 2200 ill_t ill; 2201 char ill_name[LIFNAMSIZ]; 2202 char flagsbuf[NCE_MAX_FLAGS]; 2203 2204 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ncec->ncec_ill) == -1) { 2205 mdb_warn("failed to read ncec_ill at %p", 2206 ncec->ncec_ill); 2207 return (DCMD_ERR); 2208 } 2209 2210 (void) mdb_readstr(ill_name, MIN(LIFNAMSIZ, ill.ill_name_length), 2211 (uintptr_t)ill.ill_name); 2212 2213 mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%hb", 2214 ncec->ncec_flags, ncec_flags); 2215 2216 if (ipversion != 0 && ncec->ncec_ipversion != ipversion) 2217 return (DCMD_OK); 2218 2219 if (ncec->ncec_ipversion == IPV4_VERSION) { 2220 IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &nceaddr); 2221 mdb_printf("%?p %-20s %-10s " 2222 "%-8s " 2223 "%-5s %I\n", 2224 addr, ncec_l2_addr(ncec, &ill), 2225 ncec_state(ncec->ncec_state), 2226 flagsbuf, 2227 ill_name, nceaddr.s_addr); 2228 } else { 2229 mdb_printf("%?p %-20s %-10s %-8s %-5s %N\n", 2230 addr, ncec_l2_addr(ncec, &ill), 2231 ncec_state(ncec->ncec_state), 2232 flagsbuf, 2233 ill_name, &ncec->ncec_addr); 2234 } 2235 2236 return (DCMD_OK); 2237 } 2238 2239 static uintptr_t 2240 ncec_get_next_hash_tbl(uintptr_t start, int *index, struct ndp_g_s ndp) 2241 { 2242 uintptr_t addr = start; 2243 int i = *index; 2244 2245 while (addr == NULL) { 2246 2247 if (++i >= NCE_TABLE_SIZE) 2248 break; 2249 addr = (uintptr_t)ndp.nce_hash_tbl[i]; 2250 } 2251 *index = i; 2252 return (addr); 2253 } 2254 2255 static int 2256 ncec_walk_step(mdb_walk_state_t *wsp) 2257 { 2258 uintptr_t kaddr4, kaddr6; 2259 2260 kaddr4 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp4); 2261 kaddr6 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp6); 2262 2263 if (mdb_vread(&kaddr4, sizeof (kaddr4), kaddr4) == -1) { 2264 mdb_warn("can't read ips_ip_cache_table at %p", kaddr4); 2265 return (WALK_ERR); 2266 } 2267 if (mdb_vread(&kaddr6, sizeof (kaddr6), kaddr6) == -1) { 2268 mdb_warn("can't read ips_ip_cache_table at %p", kaddr6); 2269 return (WALK_ERR); 2270 } 2271 if (mdb_pwalk("ncec_stack", wsp->walk_callback, wsp->walk_cbdata, 2272 kaddr4) == -1) { 2273 mdb_warn("couldn't walk 'ncec_stack' for ips_ndp4 %p", 2274 kaddr4); 2275 return (WALK_ERR); 2276 } 2277 if (mdb_pwalk("ncec_stack", wsp->walk_callback, 2278 wsp->walk_cbdata, kaddr6) == -1) { 2279 mdb_warn("couldn't walk 'ncec_stack' for ips_ndp6 %p", 2280 kaddr6); 2281 return (WALK_ERR); 2282 } 2283 return (WALK_NEXT); 2284 } 2285 2286 static uintptr_t 2287 ipcl_hash_get_next_connf_tbl(ipcl_hash_walk_data_t *iw) 2288 { 2289 struct connf_s connf; 2290 uintptr_t addr = NULL, next; 2291 int index = iw->connf_tbl_index; 2292 2293 do { 2294 next = iw->hash_tbl + index * sizeof (struct connf_s); 2295 if (++index >= iw->hash_tbl_size) { 2296 addr = NULL; 2297 break; 2298 } 2299 if (mdb_vread(&connf, sizeof (struct connf_s), next) == -1) { 2300 mdb_warn("failed to read conn_t at %p", next); 2301 return (NULL); 2302 } 2303 addr = (uintptr_t)connf.connf_head; 2304 } while (addr == NULL); 2305 iw->connf_tbl_index = index; 2306 return (addr); 2307 } 2308 2309 static int 2310 ipcl_hash_walk_init(mdb_walk_state_t *wsp) 2311 { 2312 const hash_walk_arg_t *arg = wsp->walk_arg; 2313 ipcl_hash_walk_data_t *iw; 2314 uintptr_t tbladdr; 2315 uintptr_t sizeaddr; 2316 2317 iw = mdb_alloc(sizeof (ipcl_hash_walk_data_t), UM_SLEEP); 2318 iw->conn = mdb_alloc(sizeof (conn_t), UM_SLEEP); 2319 tbladdr = wsp->walk_addr + arg->tbl_off; 2320 sizeaddr = wsp->walk_addr + arg->size_off; 2321 2322 if (mdb_vread(&iw->hash_tbl, sizeof (uintptr_t), tbladdr) == -1) { 2323 mdb_warn("can't read fanout table addr at %p", tbladdr); 2324 mdb_free(iw->conn, sizeof (conn_t)); 2325 mdb_free(iw, sizeof (ipcl_hash_walk_data_t)); 2326 return (WALK_ERR); 2327 } 2328 if (arg->tbl_off == OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v4) || 2329 arg->tbl_off == OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v6)) { 2330 iw->hash_tbl_size = IPPROTO_MAX; 2331 } else { 2332 if (mdb_vread(&iw->hash_tbl_size, sizeof (int), 2333 sizeaddr) == -1) { 2334 mdb_warn("can't read fanout table size addr at %p", 2335 sizeaddr); 2336 mdb_free(iw->conn, sizeof (conn_t)); 2337 mdb_free(iw, sizeof (ipcl_hash_walk_data_t)); 2338 return (WALK_ERR); 2339 } 2340 } 2341 iw->connf_tbl_index = 0; 2342 wsp->walk_addr = ipcl_hash_get_next_connf_tbl(iw); 2343 wsp->walk_data = iw; 2344 2345 if (wsp->walk_addr != NULL) 2346 return (WALK_NEXT); 2347 else 2348 return (WALK_DONE); 2349 } 2350 2351 static int 2352 ipcl_hash_walk_step(mdb_walk_state_t *wsp) 2353 { 2354 uintptr_t addr = wsp->walk_addr; 2355 ipcl_hash_walk_data_t *iw = wsp->walk_data; 2356 conn_t *conn = iw->conn; 2357 int ret = WALK_DONE; 2358 2359 while (addr != NULL) { 2360 if (mdb_vread(conn, sizeof (conn_t), addr) == -1) { 2361 mdb_warn("failed to read conn_t at %p", addr); 2362 return (WALK_ERR); 2363 } 2364 ret = wsp->walk_callback(addr, iw, wsp->walk_cbdata); 2365 if (ret != WALK_NEXT) 2366 break; 2367 addr = (uintptr_t)conn->conn_next; 2368 } 2369 if (ret == WALK_NEXT) { 2370 wsp->walk_addr = ipcl_hash_get_next_connf_tbl(iw); 2371 2372 if (wsp->walk_addr != NULL) 2373 return (WALK_NEXT); 2374 else 2375 return (WALK_DONE); 2376 } 2377 2378 return (ret); 2379 } 2380 2381 static void 2382 ipcl_hash_walk_fini(mdb_walk_state_t *wsp) 2383 { 2384 ipcl_hash_walk_data_t *iw = wsp->walk_data; 2385 2386 mdb_free(iw->conn, sizeof (conn_t)); 2387 mdb_free(iw, sizeof (ipcl_hash_walk_data_t)); 2388 } 2389 2390 /* 2391 * Called with walk_addr being the address of ips_ndp{4,6} 2392 */ 2393 static int 2394 ncec_stack_walk_init(mdb_walk_state_t *wsp) 2395 { 2396 ncec_walk_data_t *nw; 2397 2398 if (wsp->walk_addr == NULL) { 2399 mdb_warn("ncec_stack requires ndp_g_s address\n"); 2400 return (WALK_ERR); 2401 } 2402 2403 nw = mdb_alloc(sizeof (ncec_walk_data_t), UM_SLEEP); 2404 2405 if (mdb_vread(&nw->ncec_ip_ndp, sizeof (struct ndp_g_s), 2406 wsp->walk_addr) == -1) { 2407 mdb_warn("failed to read 'ip_ndp' at %p", 2408 wsp->walk_addr); 2409 mdb_free(nw, sizeof (ncec_walk_data_t)); 2410 return (WALK_ERR); 2411 } 2412 2413 /* 2414 * ncec_get_next_hash_tbl() starts at ++i , so initialize index to -1 2415 */ 2416 nw->ncec_hash_tbl_index = -1; 2417 wsp->walk_addr = ncec_get_next_hash_tbl(NULL, 2418 &nw->ncec_hash_tbl_index, nw->ncec_ip_ndp); 2419 wsp->walk_data = nw; 2420 2421 return (WALK_NEXT); 2422 } 2423 2424 static int 2425 ncec_stack_walk_step(mdb_walk_state_t *wsp) 2426 { 2427 uintptr_t addr = wsp->walk_addr; 2428 ncec_walk_data_t *nw = wsp->walk_data; 2429 2430 if (addr == NULL) 2431 return (WALK_DONE); 2432 2433 if (mdb_vread(&nw->ncec, sizeof (ncec_t), addr) == -1) { 2434 mdb_warn("failed to read ncec_t at %p", addr); 2435 return (WALK_ERR); 2436 } 2437 2438 wsp->walk_addr = (uintptr_t)nw->ncec.ncec_next; 2439 2440 wsp->walk_addr = ncec_get_next_hash_tbl(wsp->walk_addr, 2441 &nw->ncec_hash_tbl_index, nw->ncec_ip_ndp); 2442 2443 return (wsp->walk_callback(addr, nw, wsp->walk_cbdata)); 2444 } 2445 2446 static void 2447 ncec_stack_walk_fini(mdb_walk_state_t *wsp) 2448 { 2449 mdb_free(wsp->walk_data, sizeof (ncec_walk_data_t)); 2450 } 2451 2452 /* ARGSUSED */ 2453 static int 2454 ncec_cb(uintptr_t addr, const ncec_walk_data_t *iw, ncec_cbdata_t *id) 2455 { 2456 ncec_t ncec; 2457 2458 if (mdb_vread(&ncec, sizeof (ncec_t), addr) == -1) { 2459 mdb_warn("failed to read ncec at %p", addr); 2460 return (WALK_NEXT); 2461 } 2462 (void) ncec_format(addr, &ncec, id->ncec_ipversion); 2463 return (WALK_NEXT); 2464 } 2465 2466 static int 2467 ill_walk_init(mdb_walk_state_t *wsp) 2468 { 2469 if (mdb_layered_walk("illif", wsp) == -1) { 2470 mdb_warn("can't walk 'illif'"); 2471 return (WALK_ERR); 2472 } 2473 return (WALK_NEXT); 2474 } 2475 2476 static int 2477 ill_walk_step(mdb_walk_state_t *wsp) 2478 { 2479 ill_if_t ill_if; 2480 2481 if (mdb_vread(&ill_if, sizeof (ill_if_t), wsp->walk_addr) == -1) { 2482 mdb_warn("can't read ill_if_t at %p", wsp->walk_addr); 2483 return (WALK_ERR); 2484 } 2485 wsp->walk_addr = (uintptr_t)(wsp->walk_addr + 2486 offsetof(ill_if_t, illif_avl_by_ppa)); 2487 if (mdb_pwalk("avl", wsp->walk_callback, wsp->walk_cbdata, 2488 wsp->walk_addr) == -1) { 2489 mdb_warn("can't walk 'avl'"); 2490 return (WALK_ERR); 2491 } 2492 2493 return (WALK_NEXT); 2494 } 2495 2496 /* ARGSUSED */ 2497 static int 2498 ill_cb(uintptr_t addr, const ill_walk_data_t *iw, ill_cbdata_t *id) 2499 { 2500 ill_t ill; 2501 2502 if (mdb_vread(&ill, sizeof (ill_t), (uintptr_t)addr) == -1) { 2503 mdb_warn("failed to read ill at %p", addr); 2504 return (WALK_NEXT); 2505 } 2506 2507 /* If ip_stack_t is specified, skip ILLs that don't belong to it. */ 2508 if (id->ill_ipst != NULL && ill.ill_ipst != id->ill_ipst) 2509 return (WALK_NEXT); 2510 2511 return (ill_format((uintptr_t)addr, &ill, id)); 2512 } 2513 2514 static void 2515 ill_header(boolean_t verbose) 2516 { 2517 if (verbose) { 2518 mdb_printf("%-?s %-8s %3s %-10s %-?s %-?s %-10s%</u>\n", 2519 "ADDR", "NAME", "VER", "TYPE", "WQ", "IPST", "FLAGS"); 2520 mdb_printf("%-?s %4s%4s %-?s\n", 2521 "PHYINT", "CNT", "", "GROUP"); 2522 mdb_printf("%<u>%80s%</u>\n", ""); 2523 } else { 2524 mdb_printf("%<u>%-?s %-8s %-3s %-10s %4s %-?s %-10s%</u>\n", 2525 "ADDR", "NAME", "VER", "TYPE", "CNT", "WQ", "FLAGS"); 2526 } 2527 } 2528 2529 static int 2530 ill_format(uintptr_t addr, const void *illptr, void *ill_cb_arg) 2531 { 2532 ill_t *ill = (ill_t *)illptr; 2533 ill_cbdata_t *illcb = ill_cb_arg; 2534 boolean_t verbose = illcb->verbose; 2535 phyint_t phyi; 2536 static const mdb_bitmask_t fmasks[] = { 2537 { "R", PHYI_RUNNING, PHYI_RUNNING }, 2538 { "P", PHYI_PROMISC, PHYI_PROMISC }, 2539 { "V", PHYI_VIRTUAL, PHYI_VIRTUAL }, 2540 { "I", PHYI_IPMP, PHYI_IPMP }, 2541 { "f", PHYI_FAILED, PHYI_FAILED }, 2542 { "S", PHYI_STANDBY, PHYI_STANDBY }, 2543 { "i", PHYI_INACTIVE, PHYI_INACTIVE }, 2544 { "O", PHYI_OFFLINE, PHYI_OFFLINE }, 2545 { "T", ILLF_NOTRAILERS, ILLF_NOTRAILERS }, 2546 { "A", ILLF_NOARP, ILLF_NOARP }, 2547 { "M", ILLF_MULTICAST, ILLF_MULTICAST }, 2548 { "F", ILLF_ROUTER, ILLF_ROUTER }, 2549 { "D", ILLF_NONUD, ILLF_NONUD }, 2550 { "X", ILLF_NORTEXCH, ILLF_NORTEXCH }, 2551 { NULL, 0, 0 } 2552 }; 2553 static const mdb_bitmask_t v_fmasks[] = { 2554 { "RUNNING", PHYI_RUNNING, PHYI_RUNNING }, 2555 { "PROMISC", PHYI_PROMISC, PHYI_PROMISC }, 2556 { "VIRTUAL", PHYI_VIRTUAL, PHYI_VIRTUAL }, 2557 { "IPMP", PHYI_IPMP, PHYI_IPMP }, 2558 { "FAILED", PHYI_FAILED, PHYI_FAILED }, 2559 { "STANDBY", PHYI_STANDBY, PHYI_STANDBY }, 2560 { "INACTIVE", PHYI_INACTIVE, PHYI_INACTIVE }, 2561 { "OFFLINE", PHYI_OFFLINE, PHYI_OFFLINE }, 2562 { "NOTRAILER", ILLF_NOTRAILERS, ILLF_NOTRAILERS }, 2563 { "NOARP", ILLF_NOARP, ILLF_NOARP }, 2564 { "MULTICAST", ILLF_MULTICAST, ILLF_MULTICAST }, 2565 { "ROUTER", ILLF_ROUTER, ILLF_ROUTER }, 2566 { "NONUD", ILLF_NONUD, ILLF_NONUD }, 2567 { "NORTEXCH", ILLF_NORTEXCH, ILLF_NORTEXCH }, 2568 { NULL, 0, 0 } 2569 }; 2570 char ill_name[LIFNAMSIZ]; 2571 int cnt; 2572 char *typebuf; 2573 char sbuf[DEFCOLS]; 2574 int ipver = illcb->ill_ipversion; 2575 2576 if (ipver != 0) { 2577 if ((ipver == IPV4_VERSION && ill->ill_isv6) || 2578 (ipver == IPV6_VERSION && !ill->ill_isv6)) { 2579 return (WALK_NEXT); 2580 } 2581 } 2582 if (mdb_vread(&phyi, sizeof (phyint_t), 2583 (uintptr_t)ill->ill_phyint) == -1) { 2584 mdb_warn("failed to read ill_phyint at %p", 2585 (uintptr_t)ill->ill_phyint); 2586 return (WALK_NEXT); 2587 } 2588 (void) mdb_readstr(ill_name, MIN(LIFNAMSIZ, ill->ill_name_length), 2589 (uintptr_t)ill->ill_name); 2590 2591 switch (ill->ill_type) { 2592 case 0: 2593 typebuf = "LOOPBACK"; 2594 break; 2595 case IFT_ETHER: 2596 typebuf = "ETHER"; 2597 break; 2598 case IFT_OTHER: 2599 typebuf = "OTHER"; 2600 break; 2601 default: 2602 typebuf = NULL; 2603 break; 2604 } 2605 cnt = ill->ill_refcnt + ill->ill_ire_cnt + ill->ill_nce_cnt + 2606 ill->ill_ilm_cnt + ill->ill_ncec_cnt; 2607 mdb_printf("%-?p %-8s %-3s ", 2608 addr, ill_name, ill->ill_isv6 ? "v6" : "v4"); 2609 if (typebuf != NULL) 2610 mdb_printf("%-10s ", typebuf); 2611 else 2612 mdb_printf("%-10x ", ill->ill_type); 2613 if (verbose) { 2614 mdb_printf("%-?p %-?p %-llb\n", 2615 ill->ill_wq, ill->ill_ipst, 2616 ill->ill_flags | phyi.phyint_flags, v_fmasks); 2617 mdb_printf("%-?p %4d%4s %-?p\n", 2618 ill->ill_phyint, cnt, "", ill->ill_grp); 2619 mdb_snprintf(sbuf, sizeof (sbuf), "%*s %3s", 2620 sizeof (uintptr_t) * 2, "", ""); 2621 mdb_printf("%s|\n%s+--> %3d %-18s " 2622 "references from active threads\n", 2623 sbuf, sbuf, ill->ill_refcnt, "ill_refcnt"); 2624 mdb_printf("%*s %7d %-18s ires referencing this ill\n", 2625 strlen(sbuf), "", ill->ill_ire_cnt, "ill_ire_cnt"); 2626 mdb_printf("%*s %7d %-18s nces referencing this ill\n", 2627 strlen(sbuf), "", ill->ill_nce_cnt, "ill_nce_cnt"); 2628 mdb_printf("%*s %7d %-18s ncecs referencing this ill\n", 2629 strlen(sbuf), "", ill->ill_ncec_cnt, "ill_ncec_cnt"); 2630 mdb_printf("%*s %7d %-18s ilms referencing this ill\n", 2631 strlen(sbuf), "", ill->ill_ilm_cnt, "ill_ilm_cnt"); 2632 } else { 2633 mdb_printf("%4d %-?p %-llb\n", 2634 cnt, ill->ill_wq, 2635 ill->ill_flags | phyi.phyint_flags, fmasks); 2636 } 2637 return (WALK_NEXT); 2638 } 2639 2640 static int 2641 ill(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2642 { 2643 ill_t ill_data; 2644 ill_cbdata_t id; 2645 int ipversion = 0; 2646 const char *zone_name = NULL; 2647 const char *opt_P = NULL; 2648 uint_t verbose = FALSE; 2649 ip_stack_t *ipst = NULL; 2650 2651 if (mdb_getopts(argc, argv, 2652 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2653 's', MDB_OPT_STR, &zone_name, 2654 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 2655 return (DCMD_USAGE); 2656 2657 /* Follow the specified zone name to find a ip_stack_t*. */ 2658 if (zone_name != NULL) { 2659 ipst = zone_to_ips(zone_name); 2660 if (ipst == NULL) 2661 return (DCMD_USAGE); 2662 } 2663 2664 if (opt_P != NULL) { 2665 if (strcmp("v4", opt_P) == 0) { 2666 ipversion = IPV4_VERSION; 2667 } else if (strcmp("v6", opt_P) == 0) { 2668 ipversion = IPV6_VERSION; 2669 } else { 2670 mdb_warn("invalid protocol '%s'\n", opt_P); 2671 return (DCMD_USAGE); 2672 } 2673 } 2674 2675 id.verbose = verbose; 2676 id.ill_addr = addr; 2677 id.ill_ipversion = ipversion; 2678 id.ill_ipst = ipst; 2679 2680 ill_header(verbose); 2681 if (flags & DCMD_ADDRSPEC) { 2682 if (mdb_vread(&ill_data, sizeof (ill_t), addr) == -1) { 2683 mdb_warn("failed to read ill at %p\n", addr); 2684 return (DCMD_ERR); 2685 } 2686 (void) ill_format(addr, &ill_data, &id); 2687 } else { 2688 if (mdb_walk("ill", (mdb_walk_cb_t)ill_cb, &id) == -1) { 2689 mdb_warn("failed to walk ills\n"); 2690 return (DCMD_ERR); 2691 } 2692 } 2693 return (DCMD_OK); 2694 } 2695 2696 static void 2697 ill_help(void) 2698 { 2699 mdb_printf("Prints the following fields: ill ptr, name, " 2700 "IP version, count, ill type and ill flags.\n" 2701 "The count field is a sum of individual refcnts and is expanded " 2702 "with the -v option.\n\n"); 2703 mdb_printf("Options:\n"); 2704 mdb_printf("\t-P v4 | v6" 2705 "\tfilter ill structures for the specified protocol\n"); 2706 } 2707 2708 static int 2709 ip_list_walk_init(mdb_walk_state_t *wsp) 2710 { 2711 const ip_list_walk_arg_t *arg = wsp->walk_arg; 2712 ip_list_walk_data_t *iw; 2713 uintptr_t addr = (uintptr_t)(wsp->walk_addr + arg->off); 2714 2715 if (wsp->walk_addr == NULL) { 2716 mdb_warn("only local walks supported\n"); 2717 return (WALK_ERR); 2718 } 2719 if (mdb_vread(&wsp->walk_addr, sizeof (uintptr_t), 2720 addr) == -1) { 2721 mdb_warn("failed to read list head at %p", addr); 2722 return (WALK_ERR); 2723 } 2724 iw = mdb_alloc(sizeof (ip_list_walk_data_t), UM_SLEEP); 2725 iw->nextoff = arg->nextp_off; 2726 wsp->walk_data = iw; 2727 2728 return (WALK_NEXT); 2729 } 2730 2731 static int 2732 ip_list_walk_step(mdb_walk_state_t *wsp) 2733 { 2734 ip_list_walk_data_t *iw = wsp->walk_data; 2735 uintptr_t addr = wsp->walk_addr; 2736 2737 if (addr == NULL) 2738 return (WALK_DONE); 2739 wsp->walk_addr = addr + iw->nextoff; 2740 if (mdb_vread(&wsp->walk_addr, sizeof (uintptr_t), 2741 wsp->walk_addr) == -1) { 2742 mdb_warn("failed to read list node at %p", addr); 2743 return (WALK_ERR); 2744 } 2745 return (wsp->walk_callback(addr, iw, wsp->walk_cbdata)); 2746 } 2747 2748 static void 2749 ip_list_walk_fini(mdb_walk_state_t *wsp) 2750 { 2751 mdb_free(wsp->walk_data, sizeof (ip_list_walk_data_t)); 2752 } 2753 2754 static int 2755 ipif_walk_init(mdb_walk_state_t *wsp) 2756 { 2757 if (mdb_layered_walk("ill", wsp) == -1) { 2758 mdb_warn("can't walk 'ills'"); 2759 return (WALK_ERR); 2760 } 2761 return (WALK_NEXT); 2762 } 2763 2764 static int 2765 ipif_walk_step(mdb_walk_state_t *wsp) 2766 { 2767 if (mdb_pwalk("ipif_list", wsp->walk_callback, wsp->walk_cbdata, 2768 wsp->walk_addr) == -1) { 2769 mdb_warn("can't walk 'ipif_list'"); 2770 return (WALK_ERR); 2771 } 2772 2773 return (WALK_NEXT); 2774 } 2775 2776 /* ARGSUSED */ 2777 static int 2778 ipif_cb(uintptr_t addr, const ipif_walk_data_t *iw, ipif_cbdata_t *id) 2779 { 2780 ipif_t ipif; 2781 2782 if (mdb_vread(&ipif, sizeof (ipif_t), (uintptr_t)addr) == -1) { 2783 mdb_warn("failed to read ipif at %p", addr); 2784 return (WALK_NEXT); 2785 } 2786 if (mdb_vread(&id->ill, sizeof (ill_t), 2787 (uintptr_t)ipif.ipif_ill) == -1) { 2788 mdb_warn("failed to read ill at %p", ipif.ipif_ill); 2789 return (WALK_NEXT); 2790 } 2791 (void) ipif_format((uintptr_t)addr, &ipif, id); 2792 return (WALK_NEXT); 2793 } 2794 2795 static void 2796 ipif_header(boolean_t verbose) 2797 { 2798 if (verbose) { 2799 mdb_printf("%-?s %-10s %-3s %-?s %-8s %-30s\n", 2800 "ADDR", "NAME", "CNT", "ILL", "STFLAGS", "FLAGS"); 2801 mdb_printf("%s\n%s\n", 2802 "LCLADDR", "BROADCAST"); 2803 mdb_printf("%<u>%80s%</u>\n", ""); 2804 } else { 2805 mdb_printf("%-?s %-10s %6s %-?s %-8s %-30s\n", 2806 "ADDR", "NAME", "CNT", "ILL", "STFLAGS", "FLAGS"); 2807 mdb_printf("%s\n%<u>%80s%</u>\n", "LCLADDR", ""); 2808 } 2809 } 2810 2811 #ifdef _BIG_ENDIAN 2812 #define ip_ntohl_32(x) ((x) & 0xffffffff) 2813 #else 2814 #define ip_ntohl_32(x) (((uint32_t)(x) << 24) | \ 2815 (((uint32_t)(x) << 8) & 0xff0000) | \ 2816 (((uint32_t)(x) >> 8) & 0xff00) | \ 2817 ((uint32_t)(x) >> 24)) 2818 #endif 2819 2820 int 2821 mask_to_prefixlen(int af, const in6_addr_t *addr) 2822 { 2823 int len = 0; 2824 int i; 2825 uint_t mask = 0; 2826 2827 if (af == AF_INET6) { 2828 for (i = 0; i < 4; i++) { 2829 if (addr->s6_addr32[i] == 0xffffffff) { 2830 len += 32; 2831 } else { 2832 mask = addr->s6_addr32[i]; 2833 break; 2834 } 2835 } 2836 } else { 2837 mask = V4_PART_OF_V6((*addr)); 2838 } 2839 if (mask > 0) 2840 len += (33 - mdb_ffs(ip_ntohl_32(mask))); 2841 return (len); 2842 } 2843 2844 static int 2845 ipif_format(uintptr_t addr, const void *ipifptr, void *ipif_cb_arg) 2846 { 2847 const ipif_t *ipif = ipifptr; 2848 ipif_cbdata_t *ipifcb = ipif_cb_arg; 2849 boolean_t verbose = ipifcb->verbose; 2850 char ill_name[LIFNAMSIZ]; 2851 char buf[LIFNAMSIZ]; 2852 int cnt; 2853 static const mdb_bitmask_t sfmasks[] = { 2854 { "CO", IPIF_CONDEMNED, IPIF_CONDEMNED}, 2855 { "CH", IPIF_CHANGING, IPIF_CHANGING}, 2856 { "SL", IPIF_SET_LINKLOCAL, IPIF_SET_LINKLOCAL}, 2857 { NULL, 0, 0 } 2858 }; 2859 static const mdb_bitmask_t fmasks[] = { 2860 { "UP", IPIF_UP, IPIF_UP }, 2861 { "UNN", IPIF_UNNUMBERED, IPIF_UNNUMBERED}, 2862 { "DHCP", IPIF_DHCPRUNNING, IPIF_DHCPRUNNING}, 2863 { "PRIV", IPIF_PRIVATE, IPIF_PRIVATE}, 2864 { "NOXMT", IPIF_NOXMIT, IPIF_NOXMIT}, 2865 { "NOLCL", IPIF_NOLOCAL, IPIF_NOLOCAL}, 2866 { "DEPR", IPIF_DEPRECATED, IPIF_DEPRECATED}, 2867 { "PREF", IPIF_PREFERRED, IPIF_PREFERRED}, 2868 { "TEMP", IPIF_TEMPORARY, IPIF_TEMPORARY}, 2869 { "ACONF", IPIF_ADDRCONF, IPIF_ADDRCONF}, 2870 { "ANY", IPIF_ANYCAST, IPIF_ANYCAST}, 2871 { "NFAIL", IPIF_NOFAILOVER, IPIF_NOFAILOVER}, 2872 { NULL, 0, 0 } 2873 }; 2874 char flagsbuf[2 * A_CNT(fmasks)]; 2875 char bitfields[A_CNT(fmasks)]; 2876 char sflagsbuf[A_CNT(sfmasks)]; 2877 char sbuf[DEFCOLS], addrstr[INET6_ADDRSTRLEN]; 2878 int ipver = ipifcb->ipif_ipversion; 2879 int af; 2880 2881 if (ipver != 0) { 2882 if ((ipver == IPV4_VERSION && ipifcb->ill.ill_isv6) || 2883 (ipver == IPV6_VERSION && !ipifcb->ill.ill_isv6)) { 2884 return (WALK_NEXT); 2885 } 2886 } 2887 if ((mdb_readstr(ill_name, MIN(LIFNAMSIZ, 2888 ipifcb->ill.ill_name_length), 2889 (uintptr_t)ipifcb->ill.ill_name)) == -1) { 2890 mdb_warn("failed to read ill_name of ill %p\n", ipifcb->ill); 2891 return (WALK_NEXT); 2892 } 2893 if (ipif->ipif_id != 0) { 2894 mdb_snprintf(buf, LIFNAMSIZ, "%s:%d", 2895 ill_name, ipif->ipif_id); 2896 } else { 2897 mdb_snprintf(buf, LIFNAMSIZ, "%s", ill_name); 2898 } 2899 mdb_snprintf(bitfields, sizeof (bitfields), "%s", 2900 ipif->ipif_addr_ready ? ",ADR" : "", 2901 ipif->ipif_was_up ? ",WU" : "", 2902 ipif->ipif_was_dup ? ",WD" : ""); 2903 mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%llb%s", 2904 ipif->ipif_flags, fmasks, bitfields); 2905 mdb_snprintf(sflagsbuf, sizeof (sflagsbuf), "%b", 2906 ipif->ipif_state_flags, sfmasks); 2907 2908 cnt = ipif->ipif_refcnt; 2909 2910 if (ipifcb->ill.ill_isv6) { 2911 mdb_snprintf(addrstr, sizeof (addrstr), "%N", 2912 &ipif->ipif_v6lcl_addr); 2913 af = AF_INET6; 2914 } else { 2915 mdb_snprintf(addrstr, sizeof (addrstr), "%I", 2916 V4_PART_OF_V6((ipif->ipif_v6lcl_addr))); 2917 af = AF_INET; 2918 } 2919 2920 if (verbose) { 2921 mdb_printf("%-?p %-10s %3d %-?p %-8s %-30s\n", 2922 addr, buf, cnt, ipif->ipif_ill, 2923 sflagsbuf, flagsbuf); 2924 mdb_snprintf(sbuf, sizeof (sbuf), "%*s %12s", 2925 sizeof (uintptr_t) * 2, "", ""); 2926 mdb_printf("%s |\n%s +---> %4d %-15s " 2927 "Active consistent reader cnt\n", 2928 sbuf, sbuf, ipif->ipif_refcnt, "ipif_refcnt"); 2929 mdb_printf("%-s/%d\n", 2930 addrstr, mask_to_prefixlen(af, &ipif->ipif_v6net_mask)); 2931 if (ipifcb->ill.ill_isv6) { 2932 mdb_printf("%-N\n", &ipif->ipif_v6brd_addr); 2933 } else { 2934 mdb_printf("%-I\n", 2935 V4_PART_OF_V6((ipif->ipif_v6brd_addr))); 2936 } 2937 } else { 2938 mdb_printf("%-?p %-10s %6d %-?p %-8s %-30s\n", 2939 addr, buf, cnt, ipif->ipif_ill, 2940 sflagsbuf, flagsbuf); 2941 mdb_printf("%-s/%d\n", 2942 addrstr, mask_to_prefixlen(af, &ipif->ipif_v6net_mask)); 2943 } 2944 2945 return (WALK_NEXT); 2946 } 2947 2948 static int 2949 ipif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2950 { 2951 ipif_t ipif; 2952 ipif_cbdata_t id; 2953 int ipversion = 0; 2954 const char *opt_P = NULL; 2955 uint_t verbose = FALSE; 2956 2957 if (mdb_getopts(argc, argv, 2958 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2959 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 2960 return (DCMD_USAGE); 2961 2962 if (opt_P != NULL) { 2963 if (strcmp("v4", opt_P) == 0) { 2964 ipversion = IPV4_VERSION; 2965 } else if (strcmp("v6", opt_P) == 0) { 2966 ipversion = IPV6_VERSION; 2967 } else { 2968 mdb_warn("invalid protocol '%s'\n", opt_P); 2969 return (DCMD_USAGE); 2970 } 2971 } 2972 2973 id.verbose = verbose; 2974 id.ipif_ipversion = ipversion; 2975 2976 if (flags & DCMD_ADDRSPEC) { 2977 if (mdb_vread(&ipif, sizeof (ipif_t), addr) == -1) { 2978 mdb_warn("failed to read ipif at %p\n", addr); 2979 return (DCMD_ERR); 2980 } 2981 ipif_header(verbose); 2982 if (mdb_vread(&id.ill, sizeof (ill_t), 2983 (uintptr_t)ipif.ipif_ill) == -1) { 2984 mdb_warn("failed to read ill at %p", ipif.ipif_ill); 2985 return (WALK_NEXT); 2986 } 2987 return (ipif_format(addr, &ipif, &id)); 2988 } else { 2989 ipif_header(verbose); 2990 if (mdb_walk("ipif", (mdb_walk_cb_t)ipif_cb, &id) == -1) { 2991 mdb_warn("failed to walk ipifs\n"); 2992 return (DCMD_ERR); 2993 } 2994 } 2995 return (DCMD_OK); 2996 } 2997 2998 static void 2999 ipif_help(void) 3000 { 3001 mdb_printf("Prints the following fields: ipif ptr, name, " 3002 "count, ill ptr, state flags and ipif flags.\n" 3003 "The count field is a sum of individual refcnts and is expanded " 3004 "with the -v option.\n" 3005 "The flags field shows the following:" 3006 "\n\tUNN -> UNNUMBERED, DHCP -> DHCPRUNNING, PRIV -> PRIVATE, " 3007 "\n\tNOXMT -> NOXMIT, NOLCL -> NOLOCAL, DEPR -> DEPRECATED, " 3008 "\n\tPREF -> PREFERRED, TEMP -> TEMPORARY, ACONF -> ADDRCONF, " 3009 "\n\tANY -> ANYCAST, NFAIL -> NOFAILOVER, " 3010 "\n\tADR -> ipif_addr_ready, MU -> ipif_multicast_up, " 3011 "\n\tWU -> ipif_was_up, WD -> ipif_was_dup, " 3012 "JA -> ipif_joined_allhosts.\n\n"); 3013 mdb_printf("Options:\n"); 3014 mdb_printf("\t-P v4 | v6" 3015 "\tfilter ipif structures on ills for the specified protocol\n"); 3016 } 3017 3018 static int 3019 conn_status_walk_fanout(uintptr_t addr, mdb_walk_state_t *wsp, 3020 const char *walkname) 3021 { 3022 if (mdb_pwalk(walkname, wsp->walk_callback, wsp->walk_cbdata, 3023 addr) == -1) { 3024 mdb_warn("couldn't walk '%s' at %p", walkname, addr); 3025 return (WALK_ERR); 3026 } 3027 return (WALK_NEXT); 3028 } 3029 3030 static int 3031 conn_status_walk_step(mdb_walk_state_t *wsp) 3032 { 3033 uintptr_t addr = wsp->walk_addr; 3034 3035 (void) conn_status_walk_fanout(addr, wsp, "udp_hash"); 3036 (void) conn_status_walk_fanout(addr, wsp, "conn_hash"); 3037 (void) conn_status_walk_fanout(addr, wsp, "bind_hash"); 3038 (void) conn_status_walk_fanout(addr, wsp, "proto_hash"); 3039 (void) conn_status_walk_fanout(addr, wsp, "proto_v6_hash"); 3040 return (WALK_NEXT); 3041 } 3042 3043 /* ARGSUSED */ 3044 static int 3045 conn_status_cb(uintptr_t addr, const void *walk_data, 3046 void *private) 3047 { 3048 netstack_t nss; 3049 char src_addrstr[INET6_ADDRSTRLEN]; 3050 char rem_addrstr[INET6_ADDRSTRLEN]; 3051 const ipcl_hash_walk_data_t *iw = walk_data; 3052 conn_t *conn = iw->conn; 3053 3054 if (mdb_vread(conn, sizeof (conn_t), addr) == -1) { 3055 mdb_warn("failed to read conn_t at %p", addr); 3056 return (WALK_ERR); 3057 } 3058 if (mdb_vread(&nss, sizeof (nss), 3059 (uintptr_t)conn->conn_netstack) == -1) { 3060 mdb_warn("failed to read netstack_t %p", 3061 conn->conn_netstack); 3062 return (WALK_ERR); 3063 } 3064 mdb_printf("%-?p %-?p %?d %?d\n", addr, conn->conn_wq, 3065 nss.netstack_stackid, conn->conn_zoneid); 3066 3067 if (conn->conn_family == AF_INET6) { 3068 mdb_snprintf(src_addrstr, sizeof (rem_addrstr), "%N", 3069 &conn->conn_laddr_v6); 3070 mdb_snprintf(rem_addrstr, sizeof (rem_addrstr), "%N", 3071 &conn->conn_faddr_v6); 3072 } else { 3073 mdb_snprintf(src_addrstr, sizeof (src_addrstr), "%I", 3074 V4_PART_OF_V6((conn->conn_laddr_v6))); 3075 mdb_snprintf(rem_addrstr, sizeof (rem_addrstr), "%I", 3076 V4_PART_OF_V6((conn->conn_faddr_v6))); 3077 } 3078 mdb_printf("%s:%-5d\n%s:%-5d\n", 3079 src_addrstr, conn->conn_lport, rem_addrstr, conn->conn_fport); 3080 return (WALK_NEXT); 3081 } 3082 3083 static void 3084 conn_header(void) 3085 { 3086 mdb_printf("%-?s %-?s %?s %?s\n%s\n%s\n", 3087 "ADDR", "WQ", "STACK", "ZONE", "SRC:PORT", "DEST:PORT"); 3088 mdb_printf("%<u>%80s%</u>\n", ""); 3089 } 3090 3091 /*ARGSUSED*/ 3092 static int 3093 conn_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3094 { 3095 conn_header(); 3096 if (flags & DCMD_ADDRSPEC) { 3097 (void) conn_status_cb(addr, NULL, NULL); 3098 } else { 3099 if (mdb_walk("conn_status", (mdb_walk_cb_t)conn_status_cb, 3100 NULL) == -1) { 3101 mdb_warn("failed to walk conn_fanout"); 3102 return (DCMD_ERR); 3103 } 3104 } 3105 return (DCMD_OK); 3106 } 3107 3108 static void 3109 conn_status_help(void) 3110 { 3111 mdb_printf("Prints conn_t structures from the following hash tables: " 3112 "\n\tips_ipcl_udp_fanout\n\tips_ipcl_bind_fanout" 3113 "\n\tips_ipcl_conn_fanout\n\tips_ipcl_proto_fanout_v4" 3114 "\n\tips_ipcl_proto_fanout_v6\n"); 3115 } 3116 3117 static int 3118 srcid_walk_step(mdb_walk_state_t *wsp) 3119 { 3120 if (mdb_pwalk("srcid_list", wsp->walk_callback, wsp->walk_cbdata, 3121 wsp->walk_addr) == -1) { 3122 mdb_warn("can't walk 'srcid_list'"); 3123 return (WALK_ERR); 3124 } 3125 return (WALK_NEXT); 3126 } 3127 3128 /* ARGSUSED */ 3129 static int 3130 srcid_status_cb(uintptr_t addr, const void *walk_data, 3131 void *private) 3132 { 3133 srcid_map_t smp; 3134 3135 if (mdb_vread(&smp, sizeof (srcid_map_t), addr) == -1) { 3136 mdb_warn("failed to read srcid_map at %p", addr); 3137 return (WALK_ERR); 3138 } 3139 mdb_printf("%-?p %3d %4d %6d %N\n", 3140 addr, smp.sm_srcid, smp.sm_zoneid, smp.sm_refcnt, 3141 &smp.sm_addr); 3142 return (WALK_NEXT); 3143 } 3144 3145 static void 3146 srcid_header(void) 3147 { 3148 mdb_printf("%-?s %3s %4s %6s %s\n", 3149 "ADDR", "ID", "ZONE", "REFCNT", "IPADDR"); 3150 mdb_printf("%<u>%80s%</u>\n", ""); 3151 } 3152 3153 /*ARGSUSED*/ 3154 static int 3155 srcid_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3156 { 3157 srcid_header(); 3158 if (flags & DCMD_ADDRSPEC) { 3159 (void) srcid_status_cb(addr, NULL, NULL); 3160 } else { 3161 if (mdb_walk("srcid", (mdb_walk_cb_t)srcid_status_cb, 3162 NULL) == -1) { 3163 mdb_warn("failed to walk srcid_map"); 3164 return (DCMD_ERR); 3165 } 3166 } 3167 return (DCMD_OK); 3168 } 3169 3170 static int 3171 ilb_stacks_walk_step(mdb_walk_state_t *wsp) 3172 { 3173 return (ns_walk_step(wsp, NS_ILB)); 3174 } 3175 3176 static int 3177 ilb_rules_walk_init(mdb_walk_state_t *wsp) 3178 { 3179 ilb_stack_t ilbs; 3180 3181 if (wsp->walk_addr == NULL) 3182 return (WALK_ERR); 3183 3184 if (mdb_vread(&ilbs, sizeof (ilbs), wsp->walk_addr) == -1) { 3185 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr); 3186 return (WALK_ERR); 3187 } 3188 if ((wsp->walk_addr = (uintptr_t)ilbs.ilbs_rule_head) != NULL) 3189 return (WALK_NEXT); 3190 else 3191 return (WALK_DONE); 3192 } 3193 3194 static int 3195 ilb_rules_walk_step(mdb_walk_state_t *wsp) 3196 { 3197 ilb_rule_t rule; 3198 int status; 3199 3200 if (mdb_vread(&rule, sizeof (rule), wsp->walk_addr) == -1) { 3201 mdb_warn("failed to read ilb_rule_t at %p", wsp->walk_addr); 3202 return (WALK_ERR); 3203 } 3204 status = wsp->walk_callback(wsp->walk_addr, &rule, wsp->walk_cbdata); 3205 if (status != WALK_NEXT) 3206 return (status); 3207 if ((wsp->walk_addr = (uintptr_t)rule.ir_next) == NULL) 3208 return (WALK_DONE); 3209 else 3210 return (WALK_NEXT); 3211 } 3212 3213 static int 3214 ilb_servers_walk_init(mdb_walk_state_t *wsp) 3215 { 3216 ilb_rule_t rule; 3217 3218 if (wsp->walk_addr == NULL) 3219 return (WALK_ERR); 3220 3221 if (mdb_vread(&rule, sizeof (rule), wsp->walk_addr) == -1) { 3222 mdb_warn("failed to read ilb_rule_t at %p", wsp->walk_addr); 3223 return (WALK_ERR); 3224 } 3225 if ((wsp->walk_addr = (uintptr_t)rule.ir_servers) != NULL) 3226 return (WALK_NEXT); 3227 else 3228 return (WALK_DONE); 3229 } 3230 3231 static int 3232 ilb_servers_walk_step(mdb_walk_state_t *wsp) 3233 { 3234 ilb_server_t server; 3235 int status; 3236 3237 if (mdb_vread(&server, sizeof (server), wsp->walk_addr) == -1) { 3238 mdb_warn("failed to read ilb_server_t at %p", wsp->walk_addr); 3239 return (WALK_ERR); 3240 } 3241 status = wsp->walk_callback(wsp->walk_addr, &server, wsp->walk_cbdata); 3242 if (status != WALK_NEXT) 3243 return (status); 3244 if ((wsp->walk_addr = (uintptr_t)server.iser_next) == NULL) 3245 return (WALK_DONE); 3246 else 3247 return (WALK_NEXT); 3248 } 3249 3250 /* 3251 * Helper structure for ilb_nat_src walker. It stores the current index of the 3252 * nat src table. 3253 */ 3254 typedef struct { 3255 ilb_stack_t ilbs; 3256 int idx; 3257 } ilb_walk_t; 3258 3259 /* Copy from list.c */ 3260 #define list_object(a, node) ((void *)(((char *)node) - (a)->list_offset)) 3261 3262 static int 3263 ilb_nat_src_walk_init(mdb_walk_state_t *wsp) 3264 { 3265 int i; 3266 ilb_walk_t *ns_walk; 3267 ilb_nat_src_entry_t *entry = NULL; 3268 3269 if (wsp->walk_addr == NULL) 3270 return (WALK_ERR); 3271 3272 ns_walk = mdb_alloc(sizeof (ilb_walk_t), UM_SLEEP); 3273 if (mdb_vread(&ns_walk->ilbs, sizeof (ns_walk->ilbs), 3274 wsp->walk_addr) == -1) { 3275 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr); 3276 mdb_free(ns_walk, sizeof (ilb_walk_t)); 3277 return (WALK_ERR); 3278 } 3279 3280 if (ns_walk->ilbs.ilbs_nat_src == NULL) { 3281 mdb_free(ns_walk, sizeof (ilb_walk_t)); 3282 return (WALK_DONE); 3283 } 3284 3285 wsp->walk_data = ns_walk; 3286 for (i = 0; i < ns_walk->ilbs.ilbs_nat_src_hash_size; i++) { 3287 list_t head; 3288 char *khead; 3289 3290 /* Read in the nsh_head in the i-th element of the array. */ 3291 khead = (char *)ns_walk->ilbs.ilbs_nat_src + i * 3292 sizeof (ilb_nat_src_hash_t); 3293 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) { 3294 mdb_warn("failed to read ilbs_nat_src at %p\n", khead); 3295 return (WALK_ERR); 3296 } 3297 3298 /* 3299 * Note that list_next points to a kernel address and we need 3300 * to compare list_next with the kernel address of the list 3301 * head. So we need to calculate the address manually. 3302 */ 3303 if ((char *)head.list_head.list_next != khead + 3304 offsetof(list_t, list_head)) { 3305 entry = list_object(&head, head.list_head.list_next); 3306 break; 3307 } 3308 } 3309 3310 if (entry == NULL) 3311 return (WALK_DONE); 3312 3313 wsp->walk_addr = (uintptr_t)entry; 3314 ns_walk->idx = i; 3315 return (WALK_NEXT); 3316 } 3317 3318 static int 3319 ilb_nat_src_walk_step(mdb_walk_state_t *wsp) 3320 { 3321 int status; 3322 ilb_nat_src_entry_t entry, *next_entry; 3323 ilb_walk_t *ns_walk; 3324 ilb_stack_t *ilbs; 3325 list_t head; 3326 char *khead; 3327 int i; 3328 3329 if (mdb_vread(&entry, sizeof (ilb_nat_src_entry_t), 3330 wsp->walk_addr) == -1) { 3331 mdb_warn("failed to read ilb_nat_src_entry_t at %p", 3332 wsp->walk_addr); 3333 return (WALK_ERR); 3334 } 3335 status = wsp->walk_callback(wsp->walk_addr, &entry, wsp->walk_cbdata); 3336 if (status != WALK_NEXT) 3337 return (status); 3338 3339 ns_walk = (ilb_walk_t *)wsp->walk_data; 3340 ilbs = &ns_walk->ilbs; 3341 i = ns_walk->idx; 3342 3343 /* Read in the nsh_head in the i-th element of the array. */ 3344 khead = (char *)ilbs->ilbs_nat_src + i * sizeof (ilb_nat_src_hash_t); 3345 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) { 3346 mdb_warn("failed to read ilbs_nat_src at %p\n", khead); 3347 return (WALK_ERR); 3348 } 3349 3350 /* 3351 * Check if there is still entry in the current list. 3352 * 3353 * Note that list_next points to a kernel address and we need to 3354 * compare list_next with the kernel address of the list head. 3355 * So we need to calculate the address manually. 3356 */ 3357 if ((char *)entry.nse_link.list_next != khead + offsetof(list_t, 3358 list_head)) { 3359 wsp->walk_addr = (uintptr_t)list_object(&head, 3360 entry.nse_link.list_next); 3361 return (WALK_NEXT); 3362 } 3363 3364 /* Start with the next bucket in the array. */ 3365 next_entry = NULL; 3366 for (i++; i < ilbs->ilbs_nat_src_hash_size; i++) { 3367 khead = (char *)ilbs->ilbs_nat_src + i * 3368 sizeof (ilb_nat_src_hash_t); 3369 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) { 3370 mdb_warn("failed to read ilbs_nat_src at %p\n", khead); 3371 return (WALK_ERR); 3372 } 3373 3374 if ((char *)head.list_head.list_next != khead + 3375 offsetof(list_t, list_head)) { 3376 next_entry = list_object(&head, 3377 head.list_head.list_next); 3378 break; 3379 } 3380 } 3381 3382 if (next_entry == NULL) 3383 return (WALK_DONE); 3384 3385 wsp->walk_addr = (uintptr_t)next_entry; 3386 ns_walk->idx = i; 3387 return (WALK_NEXT); 3388 } 3389 3390 static void 3391 ilb_common_walk_fini(mdb_walk_state_t *wsp) 3392 { 3393 ilb_walk_t *walk; 3394 3395 walk = (ilb_walk_t *)wsp->walk_data; 3396 if (walk == NULL) 3397 return; 3398 mdb_free(walk, sizeof (ilb_walk_t *)); 3399 } 3400 3401 static int 3402 ilb_conn_walk_init(mdb_walk_state_t *wsp) 3403 { 3404 int i; 3405 ilb_walk_t *conn_walk; 3406 ilb_conn_hash_t head; 3407 3408 if (wsp->walk_addr == NULL) 3409 return (WALK_ERR); 3410 3411 conn_walk = mdb_alloc(sizeof (ilb_walk_t), UM_SLEEP); 3412 if (mdb_vread(&conn_walk->ilbs, sizeof (conn_walk->ilbs), 3413 wsp->walk_addr) == -1) { 3414 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr); 3415 mdb_free(conn_walk, sizeof (ilb_walk_t)); 3416 return (WALK_ERR); 3417 } 3418 3419 if (conn_walk->ilbs.ilbs_c2s_conn_hash == NULL) { 3420 mdb_free(conn_walk, sizeof (ilb_walk_t)); 3421 return (WALK_DONE); 3422 } 3423 3424 wsp->walk_data = conn_walk; 3425 for (i = 0; i < conn_walk->ilbs.ilbs_conn_hash_size; i++) { 3426 char *khead; 3427 3428 /* Read in the nsh_head in the i-th element of the array. */ 3429 khead = (char *)conn_walk->ilbs.ilbs_c2s_conn_hash + i * 3430 sizeof (ilb_conn_hash_t); 3431 if (mdb_vread(&head, sizeof (ilb_conn_hash_t), 3432 (uintptr_t)khead) == -1) { 3433 mdb_warn("failed to read ilbs_c2s_conn_hash at %p\n", 3434 khead); 3435 return (WALK_ERR); 3436 } 3437 3438 if (head.ilb_connp != NULL) 3439 break; 3440 } 3441 3442 if (head.ilb_connp == NULL) 3443 return (WALK_DONE); 3444 3445 wsp->walk_addr = (uintptr_t)head.ilb_connp; 3446 conn_walk->idx = i; 3447 return (WALK_NEXT); 3448 } 3449 3450 static int 3451 ilb_conn_walk_step(mdb_walk_state_t *wsp) 3452 { 3453 int status; 3454 ilb_conn_t conn; 3455 ilb_walk_t *conn_walk; 3456 ilb_stack_t *ilbs; 3457 ilb_conn_hash_t head; 3458 char *khead; 3459 int i; 3460 3461 if (mdb_vread(&conn, sizeof (ilb_conn_t), wsp->walk_addr) == -1) { 3462 mdb_warn("failed to read ilb_conn_t at %p", wsp->walk_addr); 3463 return (WALK_ERR); 3464 } 3465 3466 status = wsp->walk_callback(wsp->walk_addr, &conn, wsp->walk_cbdata); 3467 if (status != WALK_NEXT) 3468 return (status); 3469 3470 conn_walk = (ilb_walk_t *)wsp->walk_data; 3471 ilbs = &conn_walk->ilbs; 3472 i = conn_walk->idx; 3473 3474 /* Check if there is still entry in the current list. */ 3475 if (conn.conn_c2s_next != NULL) { 3476 wsp->walk_addr = (uintptr_t)conn.conn_c2s_next; 3477 return (WALK_NEXT); 3478 } 3479 3480 /* Start with the next bucket in the array. */ 3481 for (i++; i < ilbs->ilbs_conn_hash_size; i++) { 3482 khead = (char *)ilbs->ilbs_c2s_conn_hash + i * 3483 sizeof (ilb_conn_hash_t); 3484 if (mdb_vread(&head, sizeof (ilb_conn_hash_t), 3485 (uintptr_t)khead) == -1) { 3486 mdb_warn("failed to read ilbs_c2s_conn_hash at %p\n", 3487 khead); 3488 return (WALK_ERR); 3489 } 3490 3491 if (head.ilb_connp != NULL) 3492 break; 3493 } 3494 3495 if (head.ilb_connp == NULL) 3496 return (WALK_DONE); 3497 3498 wsp->walk_addr = (uintptr_t)head.ilb_connp; 3499 conn_walk->idx = i; 3500 return (WALK_NEXT); 3501 } 3502 3503 static int 3504 ilb_sticky_walk_init(mdb_walk_state_t *wsp) 3505 { 3506 int i; 3507 ilb_walk_t *sticky_walk; 3508 ilb_sticky_t *st = NULL; 3509 3510 if (wsp->walk_addr == NULL) 3511 return (WALK_ERR); 3512 3513 sticky_walk = mdb_alloc(sizeof (ilb_walk_t), UM_SLEEP); 3514 if (mdb_vread(&sticky_walk->ilbs, sizeof (sticky_walk->ilbs), 3515 wsp->walk_addr) == -1) { 3516 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr); 3517 mdb_free(sticky_walk, sizeof (ilb_walk_t)); 3518 return (WALK_ERR); 3519 } 3520 3521 if (sticky_walk->ilbs.ilbs_sticky_hash == NULL) { 3522 mdb_free(sticky_walk, sizeof (ilb_walk_t)); 3523 return (WALK_DONE); 3524 } 3525 3526 wsp->walk_data = sticky_walk; 3527 for (i = 0; i < sticky_walk->ilbs.ilbs_sticky_hash_size; i++) { 3528 list_t head; 3529 char *khead; 3530 3531 /* Read in the nsh_head in the i-th element of the array. */ 3532 khead = (char *)sticky_walk->ilbs.ilbs_sticky_hash + i * 3533 sizeof (ilb_sticky_hash_t); 3534 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) { 3535 mdb_warn("failed to read ilbs_sticky_hash at %p\n", 3536 khead); 3537 return (WALK_ERR); 3538 } 3539 3540 /* 3541 * Note that list_next points to a kernel address and we need 3542 * to compare list_next with the kernel address of the list 3543 * head. So we need to calculate the address manually. 3544 */ 3545 if ((char *)head.list_head.list_next != khead + 3546 offsetof(list_t, list_head)) { 3547 st = list_object(&head, head.list_head.list_next); 3548 break; 3549 } 3550 } 3551 3552 if (st == NULL) 3553 return (WALK_DONE); 3554 3555 wsp->walk_addr = (uintptr_t)st; 3556 sticky_walk->idx = i; 3557 return (WALK_NEXT); 3558 } 3559 3560 static int 3561 ilb_sticky_walk_step(mdb_walk_state_t *wsp) 3562 { 3563 int status; 3564 ilb_sticky_t st, *st_next; 3565 ilb_walk_t *sticky_walk; 3566 ilb_stack_t *ilbs; 3567 list_t head; 3568 char *khead; 3569 int i; 3570 3571 if (mdb_vread(&st, sizeof (ilb_sticky_t), wsp->walk_addr) == -1) { 3572 mdb_warn("failed to read ilb_sticky_t at %p", wsp->walk_addr); 3573 return (WALK_ERR); 3574 } 3575 3576 status = wsp->walk_callback(wsp->walk_addr, &st, wsp->walk_cbdata); 3577 if (status != WALK_NEXT) 3578 return (status); 3579 3580 sticky_walk = (ilb_walk_t *)wsp->walk_data; 3581 ilbs = &sticky_walk->ilbs; 3582 i = sticky_walk->idx; 3583 3584 /* Read in the nsh_head in the i-th element of the array. */ 3585 khead = (char *)ilbs->ilbs_sticky_hash + i * sizeof (ilb_sticky_hash_t); 3586 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) { 3587 mdb_warn("failed to read ilbs_sticky_hash at %p\n", khead); 3588 return (WALK_ERR); 3589 } 3590 3591 /* 3592 * Check if there is still entry in the current list. 3593 * 3594 * Note that list_next points to a kernel address and we need to 3595 * compare list_next with the kernel address of the list head. 3596 * So we need to calculate the address manually. 3597 */ 3598 if ((char *)st.list.list_next != khead + offsetof(list_t, 3599 list_head)) { 3600 wsp->walk_addr = (uintptr_t)list_object(&head, 3601 st.list.list_next); 3602 return (WALK_NEXT); 3603 } 3604 3605 /* Start with the next bucket in the array. */ 3606 st_next = NULL; 3607 for (i++; i < ilbs->ilbs_nat_src_hash_size; i++) { 3608 khead = (char *)ilbs->ilbs_sticky_hash + i * 3609 sizeof (ilb_sticky_hash_t); 3610 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) { 3611 mdb_warn("failed to read ilbs_sticky_hash at %p\n", 3612 khead); 3613 return (WALK_ERR); 3614 } 3615 3616 if ((char *)head.list_head.list_next != khead + 3617 offsetof(list_t, list_head)) { 3618 st_next = list_object(&head, 3619 head.list_head.list_next); 3620 break; 3621 } 3622 } 3623 3624 if (st_next == NULL) 3625 return (WALK_DONE); 3626 3627 wsp->walk_addr = (uintptr_t)st_next; 3628 sticky_walk->idx = i; 3629 return (WALK_NEXT); 3630 } 3631