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