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