10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 52546Scarlsonj * Common Development and Distribution License (the "License"). 62546Scarlsonj * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*5940Ssowmini * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include <sys/types.h> 290Sstevel@tonic-gate #include <sys/stropts.h> 300Sstevel@tonic-gate #include <sys/stream.h> 310Sstevel@tonic-gate #include <sys/socket.h> 320Sstevel@tonic-gate #include <sys/avl_impl.h> 330Sstevel@tonic-gate #include <net/if.h> 340Sstevel@tonic-gate #include <net/route.h> 350Sstevel@tonic-gate #include <netinet/in.h> 360Sstevel@tonic-gate #include <netinet/ip6.h> 370Sstevel@tonic-gate #include <netinet/udp.h> 380Sstevel@tonic-gate #include <netinet/sctp.h> 390Sstevel@tonic-gate #include <inet/mib2.h> 400Sstevel@tonic-gate #include <inet/common.h> 410Sstevel@tonic-gate #include <inet/ip.h> 420Sstevel@tonic-gate #include <inet/ip_ire.h> 430Sstevel@tonic-gate #include <inet/ip6.h> 440Sstevel@tonic-gate #include <inet/ipclassifier.h> 450Sstevel@tonic-gate #include <inet/mi.h> 460Sstevel@tonic-gate #include <sys/squeue_impl.h> 475023Scarlsonj #include <sys/modhash_impl.h> 48*5940Ssowmini #include <inet/ip_ndp.h> 49*5940Ssowmini #include <inet/ip_if.h> 50*5940Ssowmini #include <sys/dlpi.h> 510Sstevel@tonic-gate 520Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 530Sstevel@tonic-gate #include <mdb/mdb_ks.h> 540Sstevel@tonic-gate 550Sstevel@tonic-gate #define ADDR_WIDTH 11 56*5940Ssowmini #define L2MAXADDRSTRLEN 255 57*5940Ssowmini #define MAX_SAP_LEN 255 580Sstevel@tonic-gate 590Sstevel@tonic-gate typedef struct { 600Sstevel@tonic-gate const char *bit_name; /* name of bit */ 610Sstevel@tonic-gate const char *bit_descr; /* description of bit's purpose */ 620Sstevel@tonic-gate } bitname_t; 630Sstevel@tonic-gate 640Sstevel@tonic-gate static const bitname_t squeue_states[] = { 650Sstevel@tonic-gate { "SQS_PROC", "being processed" }, 660Sstevel@tonic-gate { "SQS_WORKER", "... by a worker thread" }, 670Sstevel@tonic-gate { "SQS_ENTER", "... by an squeue_enter() thread" }, 680Sstevel@tonic-gate { "SQS_FAST", "... in fast-path mode" }, 690Sstevel@tonic-gate { "SQS_USER", "A non interrupt user" }, 700Sstevel@tonic-gate { "SQS_BOUND", "worker thread bound to CPU" }, 710Sstevel@tonic-gate { "SQS_PROFILE", "profiling enabled" }, 720Sstevel@tonic-gate { "SQS_REENTER", "re-entered thred" }, 730Sstevel@tonic-gate { NULL } 740Sstevel@tonic-gate }; 750Sstevel@tonic-gate 760Sstevel@tonic-gate typedef struct illif_walk_data { 770Sstevel@tonic-gate ill_g_head_t ill_g_heads[MAX_G_HEADS]; 780Sstevel@tonic-gate int ill_list; 790Sstevel@tonic-gate ill_if_t ill_if; 800Sstevel@tonic-gate } illif_walk_data_t; 810Sstevel@tonic-gate 82*5940Ssowmini typedef struct nce_walk_data_s { 83*5940Ssowmini struct ndp_g_s nce_ip_ndp; 84*5940Ssowmini int nce_hash_tbl_index; 85*5940Ssowmini nce_t nce; 86*5940Ssowmini } nce_walk_data_t; 87*5940Ssowmini 88*5940Ssowmini typedef struct nce_cbdata_s { 89*5940Ssowmini uintptr_t nce_addr; 90*5940Ssowmini int nce_ipversion; 91*5940Ssowmini } nce_cbdata_t; 92*5940Ssowmini 93*5940Ssowmini typedef struct ire_cbdata_s { 94*5940Ssowmini int ire_ipversion; 95*5940Ssowmini boolean_t verbose; 96*5940Ssowmini } ire_cbdata_t; 97*5940Ssowmini 985023Scarlsonj typedef struct th_walk_data { 995023Scarlsonj uint_t thw_non_zero_only; 1005023Scarlsonj boolean_t thw_match; 1015023Scarlsonj uintptr_t thw_matchkey; 1025023Scarlsonj uintptr_t thw_ipst; 1035023Scarlsonj clock_t thw_lbolt; 1045023Scarlsonj } th_walk_data_t; 1055023Scarlsonj 1060Sstevel@tonic-gate static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *); 1070Sstevel@tonic-gate static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *); 1080Sstevel@tonic-gate 109*5940Ssowmini static int ire_format(uintptr_t addr, const void *, void *); 110*5940Ssowmini static int nce_format(uintptr_t addr, const nce_t *nce, int ipversion); 111*5940Ssowmini static int nce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv); 112*5940Ssowmini static int nce_walk_step(mdb_walk_state_t *wsp); 113*5940Ssowmini static int nce_stack_walk_init(mdb_walk_state_t *wsp); 114*5940Ssowmini static int nce_stack_walk_step(mdb_walk_state_t *wsp); 115*5940Ssowmini static void nce_stack_walk_fini(mdb_walk_state_t *wsp); 116*5940Ssowmini static int nce_cb(uintptr_t addr, const nce_walk_data_t *iw, nce_cbdata_t *id); 1173448Sdh155122 1183448Sdh155122 /* 1193448Sdh155122 * Given the kernel address of an ip_stack_t, return the stackid 1203448Sdh155122 */ 1213448Sdh155122 static int 1223448Sdh155122 ips_to_stackid(uintptr_t kaddr) 1233448Sdh155122 { 1243448Sdh155122 ip_stack_t ipss; 1253448Sdh155122 netstack_t nss; 1263448Sdh155122 1273448Sdh155122 if (mdb_vread(&ipss, sizeof (ipss), kaddr) == -1) { 1283448Sdh155122 mdb_warn("failed to read ip_stack_t %p", kaddr); 1293448Sdh155122 return (0); 1303448Sdh155122 } 1313448Sdh155122 kaddr = (uintptr_t)ipss.ips_netstack; 1323448Sdh155122 if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) { 1333448Sdh155122 mdb_warn("failed to read netstack_t %p", kaddr); 1343448Sdh155122 return (0); 1353448Sdh155122 } 1363448Sdh155122 return (nss.netstack_stackid); 1373448Sdh155122 } 1383448Sdh155122 1390Sstevel@tonic-gate int 1403448Sdh155122 ip_stacks_walk_init(mdb_walk_state_t *wsp) 1413448Sdh155122 { 1423448Sdh155122 if (mdb_layered_walk("netstack", wsp) == -1) { 1433448Sdh155122 mdb_warn("can't walk 'netstack'"); 1443448Sdh155122 return (WALK_ERR); 1453448Sdh155122 } 1463448Sdh155122 return (WALK_NEXT); 1473448Sdh155122 } 1483448Sdh155122 1493448Sdh155122 int 1503448Sdh155122 ip_stacks_walk_step(mdb_walk_state_t *wsp) 1513448Sdh155122 { 1523448Sdh155122 uintptr_t kaddr; 1533448Sdh155122 netstack_t nss; 1543448Sdh155122 1553448Sdh155122 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 1563448Sdh155122 mdb_warn("can't read netstack at %p", wsp->walk_addr); 1573448Sdh155122 return (WALK_ERR); 1583448Sdh155122 } 1593448Sdh155122 kaddr = (uintptr_t)nss.netstack_modules[NS_IP]; 1603448Sdh155122 1613448Sdh155122 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 1623448Sdh155122 } 1633448Sdh155122 1645023Scarlsonj int 1655023Scarlsonj th_hash_walk_init(mdb_walk_state_t *wsp) 1665023Scarlsonj { 1675023Scarlsonj GElf_Sym sym; 1685023Scarlsonj list_node_t *next; 1695023Scarlsonj 1705023Scarlsonj if (wsp->walk_addr == NULL) { 1715023Scarlsonj if (mdb_lookup_by_obj("ip", "ip_thread_list", &sym) == 0) { 1725023Scarlsonj wsp->walk_addr = sym.st_value; 1735023Scarlsonj } else { 1745023Scarlsonj mdb_warn("unable to locate ip_thread_list\n"); 1755023Scarlsonj return (WALK_ERR); 1765023Scarlsonj } 1775023Scarlsonj } 1785023Scarlsonj 1795023Scarlsonj if (mdb_vread(&next, sizeof (next), 1805023Scarlsonj wsp->walk_addr + offsetof(list_t, list_head) + 1815023Scarlsonj offsetof(list_node_t, list_next)) == -1 || 1825023Scarlsonj next == NULL) { 1835023Scarlsonj mdb_warn("non-DEBUG image; cannot walk th_hash list\n"); 1845023Scarlsonj return (WALK_ERR); 1855023Scarlsonj } 1865023Scarlsonj 1875023Scarlsonj if (mdb_layered_walk("list", wsp) == -1) { 1885023Scarlsonj mdb_warn("can't walk 'list'"); 1895023Scarlsonj return (WALK_ERR); 1905023Scarlsonj } else { 1915023Scarlsonj return (WALK_NEXT); 1925023Scarlsonj } 1935023Scarlsonj } 1945023Scarlsonj 1955023Scarlsonj int 1965023Scarlsonj th_hash_walk_step(mdb_walk_state_t *wsp) 1975023Scarlsonj { 1985023Scarlsonj return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, 1995023Scarlsonj wsp->walk_cbdata)); 2005023Scarlsonj } 2015023Scarlsonj 2023448Sdh155122 /* 2033448Sdh155122 * Called with walk_addr being the address of ips_ill_g_heads 2043448Sdh155122 */ 2053448Sdh155122 int 2063448Sdh155122 illif_stack_walk_init(mdb_walk_state_t *wsp) 2070Sstevel@tonic-gate { 2080Sstevel@tonic-gate illif_walk_data_t *iw; 2090Sstevel@tonic-gate 2103448Sdh155122 if (wsp->walk_addr == NULL) { 2113448Sdh155122 mdb_warn("illif_stack supports only local walks\n"); 2120Sstevel@tonic-gate return (WALK_ERR); 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate 2150Sstevel@tonic-gate iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP); 2160Sstevel@tonic-gate 2173448Sdh155122 if (mdb_vread(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t), 2183448Sdh155122 wsp->walk_addr) == -1) { 2193448Sdh155122 mdb_warn("failed to read 'ips_ill_g_heads' at %p", 2203448Sdh155122 wsp->walk_addr); 2210Sstevel@tonic-gate mdb_free(iw, sizeof (illif_walk_data_t)); 2220Sstevel@tonic-gate return (WALK_ERR); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate iw->ill_list = 0; 2263448Sdh155122 wsp->walk_addr = (uintptr_t)iw->ill_g_heads[0].ill_g_list_head; 2270Sstevel@tonic-gate wsp->walk_data = iw; 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate return (WALK_NEXT); 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate int 2333448Sdh155122 illif_stack_walk_step(mdb_walk_state_t *wsp) 2340Sstevel@tonic-gate { 2350Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 2360Sstevel@tonic-gate illif_walk_data_t *iw = wsp->walk_data; 2370Sstevel@tonic-gate int list = iw->ill_list; 2380Sstevel@tonic-gate 2390Sstevel@tonic-gate if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) { 2400Sstevel@tonic-gate mdb_warn("failed to read ill_if_t at %p", addr); 2410Sstevel@tonic-gate return (WALK_ERR); 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next; 2450Sstevel@tonic-gate 2463448Sdh155122 if (wsp->walk_addr == 2473448Sdh155122 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head) { 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate if (++list >= MAX_G_HEADS) 2500Sstevel@tonic-gate return (WALK_DONE); 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate iw->ill_list = list; 2533448Sdh155122 wsp->walk_addr = 2543448Sdh155122 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head; 2550Sstevel@tonic-gate return (WALK_NEXT); 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate return (wsp->walk_callback(addr, iw, wsp->walk_cbdata)); 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate void 2623448Sdh155122 illif_stack_walk_fini(mdb_walk_state_t *wsp) 2630Sstevel@tonic-gate { 2640Sstevel@tonic-gate mdb_free(wsp->walk_data, sizeof (illif_walk_data_t)); 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate typedef struct illif_cbdata { 2680Sstevel@tonic-gate uint_t ill_flags; 2690Sstevel@tonic-gate uintptr_t ill_addr; 2700Sstevel@tonic-gate int ill_printlist; /* list to be printed (MAX_G_HEADS for all) */ 2710Sstevel@tonic-gate boolean_t ill_printed; 2720Sstevel@tonic-gate } illif_cbdata_t; 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate static int 2750Sstevel@tonic-gate illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id) 2760Sstevel@tonic-gate { 2770Sstevel@tonic-gate const char *version; 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate if (id->ill_printlist < MAX_G_HEADS && 2800Sstevel@tonic-gate id->ill_printlist != iw->ill_list) 2810Sstevel@tonic-gate return (WALK_NEXT); 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr) 2840Sstevel@tonic-gate return (WALK_NEXT); 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate if (id->ill_flags & DCMD_PIPE_OUT) { 2870Sstevel@tonic-gate mdb_printf("%p\n", addr); 2880Sstevel@tonic-gate return (WALK_NEXT); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate switch (iw->ill_list) { 2920Sstevel@tonic-gate case IP_V4_G_HEAD: version = "v4"; break; 2930Sstevel@tonic-gate case IP_V6_G_HEAD: version = "v6"; break; 2940Sstevel@tonic-gate default: version = "??"; break; 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate mdb_printf("%?p %2s %?p %10d %?p %s\n", 2980Sstevel@tonic-gate addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa), 2990Sstevel@tonic-gate iw->ill_if.illif_avl_by_ppa.avl_numnodes, 3000Sstevel@tonic-gate iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name); 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate id->ill_printed = TRUE; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate return (WALK_NEXT); 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate int 308*5940Ssowmini ip_stacks_common_walk_init(mdb_walk_state_t *wsp) 3093448Sdh155122 { 3103448Sdh155122 if (mdb_layered_walk("ip_stacks", wsp) == -1) { 3113448Sdh155122 mdb_warn("can't walk 'ip_stacks'"); 3123448Sdh155122 return (WALK_ERR); 3133448Sdh155122 } 3143448Sdh155122 3153448Sdh155122 return (WALK_NEXT); 3163448Sdh155122 } 3173448Sdh155122 3183448Sdh155122 int 3193448Sdh155122 illif_walk_step(mdb_walk_state_t *wsp) 3203448Sdh155122 { 3213448Sdh155122 uintptr_t kaddr; 3223448Sdh155122 3233448Sdh155122 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ill_g_heads); 3243448Sdh155122 3253448Sdh155122 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 3263448Sdh155122 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 3273448Sdh155122 return (WALK_ERR); 3283448Sdh155122 } 3293448Sdh155122 3303448Sdh155122 if (mdb_pwalk("illif_stack", wsp->walk_callback, 3315023Scarlsonj wsp->walk_cbdata, kaddr) == -1) { 3323448Sdh155122 mdb_warn("couldn't walk 'illif_stack' for ips_ill_g_heads %p", 3333448Sdh155122 kaddr); 3343448Sdh155122 return (WALK_ERR); 3353448Sdh155122 } 3363448Sdh155122 return (WALK_NEXT); 3373448Sdh155122 } 3383448Sdh155122 3393448Sdh155122 int 3400Sstevel@tonic-gate illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3410Sstevel@tonic-gate { 3420Sstevel@tonic-gate illif_cbdata_t id; 3430Sstevel@tonic-gate ill_if_t ill_if; 3440Sstevel@tonic-gate const char *opt_P = NULL; 3450Sstevel@tonic-gate int printlist = MAX_G_HEADS; 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate if (mdb_getopts(argc, argv, 3480Sstevel@tonic-gate 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 3490Sstevel@tonic-gate return (DCMD_USAGE); 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate if (opt_P != NULL) { 3520Sstevel@tonic-gate if (strcmp("v4", opt_P) == 0) { 3530Sstevel@tonic-gate printlist = IP_V4_G_HEAD; 3540Sstevel@tonic-gate } else if (strcmp("v6", opt_P) == 0) { 3550Sstevel@tonic-gate printlist = IP_V6_G_HEAD; 3560Sstevel@tonic-gate } else { 3570Sstevel@tonic-gate mdb_warn("invalid protocol '%s'\n", opt_P); 3580Sstevel@tonic-gate return (DCMD_USAGE); 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) { 3630Sstevel@tonic-gate mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n", 3640Sstevel@tonic-gate "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME"); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate id.ill_flags = flags; 3680Sstevel@tonic-gate id.ill_addr = addr; 3690Sstevel@tonic-gate id.ill_printlist = printlist; 3700Sstevel@tonic-gate id.ill_printed = FALSE; 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) { 3730Sstevel@tonic-gate mdb_warn("can't walk ill_if_t structures"); 3740Sstevel@tonic-gate return (DCMD_ERR); 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed) 3780Sstevel@tonic-gate return (DCMD_OK); 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate /* 3810Sstevel@tonic-gate * If an address is specified and the walk doesn't find it, 3820Sstevel@tonic-gate * print it anyway. 3830Sstevel@tonic-gate */ 3840Sstevel@tonic-gate if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) { 3850Sstevel@tonic-gate mdb_warn("failed to read ill_if_t at %p", addr); 3860Sstevel@tonic-gate return (DCMD_ERR); 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate mdb_printf("%?p %2s %?p %10d %?p %s\n", 3900Sstevel@tonic-gate addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa), 3910Sstevel@tonic-gate ill_if.illif_avl_by_ppa.avl_numnodes, 3920Sstevel@tonic-gate ill_if.illif_ppa_arena, ill_if.illif_name); 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate return (DCMD_OK); 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate static void 3980Sstevel@tonic-gate illif_help(void) 3990Sstevel@tonic-gate { 4000Sstevel@tonic-gate mdb_printf("Options:\n"); 4010Sstevel@tonic-gate mdb_printf("\t-P v4 | v6" 4020Sstevel@tonic-gate "\tfilter interface structures for the specified protocol\n"); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate int 4060Sstevel@tonic-gate ire_walk_init(mdb_walk_state_t *wsp) 4070Sstevel@tonic-gate { 4080Sstevel@tonic-gate if (mdb_layered_walk("ire_cache", wsp) == -1) { 4090Sstevel@tonic-gate mdb_warn("can't walk 'ire_cache'"); 4100Sstevel@tonic-gate return (WALK_ERR); 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate return (WALK_NEXT); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate int 4170Sstevel@tonic-gate ire_walk_step(mdb_walk_state_t *wsp) 4180Sstevel@tonic-gate { 4190Sstevel@tonic-gate ire_t ire; 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 4220Sstevel@tonic-gate mdb_warn("can't read ire at %p", wsp->walk_addr); 4230Sstevel@tonic-gate return (WALK_ERR); 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata)); 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate 4293448Sdh155122 4303448Sdh155122 int 4313448Sdh155122 ire_ctable_walk_step(mdb_walk_state_t *wsp) 4323448Sdh155122 { 4333448Sdh155122 uintptr_t kaddr; 4343448Sdh155122 irb_t *irb; 4353448Sdh155122 uint32_t cache_table_size; 4363448Sdh155122 int i; 437*5940Ssowmini ire_cbdata_t ire_cb; 4383448Sdh155122 439*5940Ssowmini ire_cb.verbose = B_FALSE; 440*5940Ssowmini ire_cb.ire_ipversion = 0; 441*5940Ssowmini 4423448Sdh155122 4433448Sdh155122 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table_size); 4443448Sdh155122 4453448Sdh155122 if (mdb_vread(&cache_table_size, sizeof (uint32_t), kaddr) == -1) { 4463448Sdh155122 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 4473448Sdh155122 return (WALK_ERR); 4483448Sdh155122 } 4493448Sdh155122 4503448Sdh155122 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table); 4513448Sdh155122 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 4523448Sdh155122 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 4533448Sdh155122 return (WALK_ERR); 4543448Sdh155122 } 4553448Sdh155122 4563448Sdh155122 irb = mdb_alloc(sizeof (irb_t) * cache_table_size, UM_SLEEP|UM_GC); 4573448Sdh155122 if (mdb_vread(irb, sizeof (irb_t) * cache_table_size, kaddr) == -1) { 4583448Sdh155122 mdb_warn("can't read irb at %p", kaddr); 4593448Sdh155122 return (WALK_ERR); 4603448Sdh155122 } 4613448Sdh155122 for (i = 0; i < cache_table_size; i++) { 4623448Sdh155122 kaddr = (uintptr_t)irb[i].irb_ire; 4633448Sdh155122 464*5940Ssowmini if (mdb_pwalk("ire_next", ire_format, &ire_cb, 4655023Scarlsonj kaddr) == -1) { 4663448Sdh155122 mdb_warn("can't walk 'ire_next' for ire %p", kaddr); 4673448Sdh155122 return (WALK_ERR); 4683448Sdh155122 } 4693448Sdh155122 } 4703448Sdh155122 return (WALK_NEXT); 4713448Sdh155122 } 4723448Sdh155122 4733448Sdh155122 /* ARGSUSED */ 4743448Sdh155122 int 4753448Sdh155122 ire_next_walk_init(mdb_walk_state_t *wsp) 4763448Sdh155122 { 4773448Sdh155122 return (WALK_NEXT); 4783448Sdh155122 } 4793448Sdh155122 4803448Sdh155122 int 4813448Sdh155122 ire_next_walk_step(mdb_walk_state_t *wsp) 4823448Sdh155122 { 4833448Sdh155122 ire_t ire; 4843448Sdh155122 int status; 4853448Sdh155122 4863448Sdh155122 4873448Sdh155122 if (wsp->walk_addr == NULL) 4883448Sdh155122 return (WALK_DONE); 4893448Sdh155122 4903448Sdh155122 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 4913448Sdh155122 mdb_warn("can't read ire at %p", wsp->walk_addr); 4923448Sdh155122 return (WALK_ERR); 4933448Sdh155122 } 4943448Sdh155122 status = wsp->walk_callback(wsp->walk_addr, &ire, 4953448Sdh155122 wsp->walk_cbdata); 4963448Sdh155122 4973448Sdh155122 if (status != WALK_NEXT) 4983448Sdh155122 return (status); 4993448Sdh155122 5003448Sdh155122 wsp->walk_addr = (uintptr_t)ire.ire_next; 5013448Sdh155122 return (status); 5023448Sdh155122 } 5033448Sdh155122 5040Sstevel@tonic-gate static int 505*5940Ssowmini ire_format(uintptr_t addr, const void *ire_arg, void *ire_cb_arg) 5060Sstevel@tonic-gate { 507*5940Ssowmini const ire_t *irep = ire_arg; 508*5940Ssowmini ire_cbdata_t *ire_cb = ire_cb_arg; 509*5940Ssowmini boolean_t verbose = ire_cb->verbose; 510*5940Ssowmini 5110Sstevel@tonic-gate static const mdb_bitmask_t tmasks[] = { 5120Sstevel@tonic-gate { "BROADCAST", IRE_BROADCAST, IRE_BROADCAST }, 5130Sstevel@tonic-gate { "DEFAULT", IRE_DEFAULT, IRE_DEFAULT }, 5140Sstevel@tonic-gate { "LOCAL", IRE_LOCAL, IRE_LOCAL }, 5150Sstevel@tonic-gate { "LOOPBACK", IRE_LOOPBACK, IRE_LOOPBACK }, 5160Sstevel@tonic-gate { "PREFIX", IRE_PREFIX, IRE_PREFIX }, 5170Sstevel@tonic-gate { "CACHE", IRE_CACHE, IRE_CACHE }, 5180Sstevel@tonic-gate { "IF_NORESOLVER", IRE_IF_NORESOLVER, IRE_IF_NORESOLVER }, 5190Sstevel@tonic-gate { "IF_RESOLVER", IRE_IF_RESOLVER, IRE_IF_RESOLVER }, 5200Sstevel@tonic-gate { "HOST", IRE_HOST, IRE_HOST }, 5210Sstevel@tonic-gate { "HOST_REDIRECT", IRE_HOST_REDIRECT, IRE_HOST_REDIRECT }, 5220Sstevel@tonic-gate { NULL, 0, 0 } 5230Sstevel@tonic-gate }; 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate static const mdb_bitmask_t mmasks[] = { 5260Sstevel@tonic-gate { "CONDEMNED", IRE_MARK_CONDEMNED, IRE_MARK_CONDEMNED }, 5270Sstevel@tonic-gate { "NORECV", IRE_MARK_NORECV, IRE_MARK_NORECV }, 5280Sstevel@tonic-gate { "HIDDEN", IRE_MARK_HIDDEN, IRE_MARK_HIDDEN }, 5290Sstevel@tonic-gate { "NOADD", IRE_MARK_NOADD, IRE_MARK_NOADD }, 5300Sstevel@tonic-gate { "TEMPORARY", IRE_MARK_TEMPORARY, IRE_MARK_TEMPORARY }, 531*5940Ssowmini { "USESRC", IRE_MARK_USESRC_CHECK, IRE_MARK_USESRC_CHECK }, 532*5940Ssowmini { "PRIVATE", IRE_MARK_PRIVATE_ADDR, IRE_MARK_PRIVATE_ADDR }, 533*5940Ssowmini { "UNCACHED", IRE_MARK_UNCACHED, IRE_MARK_UNCACHED }, 5340Sstevel@tonic-gate { NULL, 0, 0 } 5350Sstevel@tonic-gate }; 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate static const mdb_bitmask_t fmasks[] = { 5380Sstevel@tonic-gate { "UP", RTF_UP, RTF_UP }, 5390Sstevel@tonic-gate { "GATEWAY", RTF_GATEWAY, RTF_GATEWAY }, 5400Sstevel@tonic-gate { "HOST", RTF_HOST, RTF_HOST }, 5410Sstevel@tonic-gate { "REJECT", RTF_REJECT, RTF_REJECT }, 5420Sstevel@tonic-gate { "DYNAMIC", RTF_DYNAMIC, RTF_DYNAMIC }, 5430Sstevel@tonic-gate { "MODIFIED", RTF_MODIFIED, RTF_MODIFIED }, 5440Sstevel@tonic-gate { "DONE", RTF_DONE, RTF_DONE }, 5450Sstevel@tonic-gate { "MASK", RTF_MASK, RTF_MASK }, 5460Sstevel@tonic-gate { "CLONING", RTF_CLONING, RTF_CLONING }, 5470Sstevel@tonic-gate { "XRESOLVE", RTF_XRESOLVE, RTF_XRESOLVE }, 5480Sstevel@tonic-gate { "LLINFO", RTF_LLINFO, RTF_LLINFO }, 5490Sstevel@tonic-gate { "STATIC", RTF_STATIC, RTF_STATIC }, 5500Sstevel@tonic-gate { "BLACKHOLE", RTF_BLACKHOLE, RTF_BLACKHOLE }, 5510Sstevel@tonic-gate { "PRIVATE", RTF_PRIVATE, RTF_PRIVATE }, 5520Sstevel@tonic-gate { "PROTO2", RTF_PROTO2, RTF_PROTO2 }, 5530Sstevel@tonic-gate { "PROTO1", RTF_PROTO1, RTF_PROTO1 }, 5540Sstevel@tonic-gate { "MULTIRT", RTF_MULTIRT, RTF_MULTIRT }, 5550Sstevel@tonic-gate { "SETSRC", RTF_SETSRC, RTF_SETSRC }, 5560Sstevel@tonic-gate { NULL, 0, 0 } 5570Sstevel@tonic-gate }; 5580Sstevel@tonic-gate 559*5940Ssowmini if (ire_cb->ire_ipversion != 0 && 560*5940Ssowmini irep->ire_ipversion != ire_cb->ire_ipversion) 561*5940Ssowmini return (WALK_NEXT); 562*5940Ssowmini 563*5940Ssowmini if (irep->ire_ipversion == IPV6_VERSION && verbose) { 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate mdb_printf("%<b>%?p%</b> %40N <%hb>\n" 5660Sstevel@tonic-gate "%?s %40N <%hb>\n" 5673448Sdh155122 "%?s %40d %4d <%hb>\n", 5680Sstevel@tonic-gate addr, &irep->ire_src_addr_v6, irep->ire_type, tmasks, 5690Sstevel@tonic-gate "", &irep->ire_addr_v6, (ushort_t)irep->ire_marks, mmasks, 5703448Sdh155122 "", ips_to_stackid((uintptr_t)irep->ire_ipst), 5713448Sdh155122 irep->ire_zoneid, 5723448Sdh155122 irep->ire_flags, fmasks); 5730Sstevel@tonic-gate 574*5940Ssowmini } else if (irep->ire_ipversion == IPV6_VERSION) { 5750Sstevel@tonic-gate 5763448Sdh155122 mdb_printf("%?p %30N %30N %5d %4d\n", 5773448Sdh155122 addr, &irep->ire_src_addr_v6, 5783448Sdh155122 &irep->ire_addr_v6, 5793448Sdh155122 ips_to_stackid((uintptr_t)irep->ire_ipst), 5803448Sdh155122 irep->ire_zoneid); 5810Sstevel@tonic-gate 582*5940Ssowmini } else if (verbose) { 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate mdb_printf("%<b>%?p%</b> %40I <%hb>\n" 5850Sstevel@tonic-gate "%?s %40I <%hb>\n" 586*5940Ssowmini "%?s %40d %4d <%hb>\n", 5870Sstevel@tonic-gate addr, irep->ire_src_addr, irep->ire_type, tmasks, 5880Sstevel@tonic-gate "", irep->ire_addr, (ushort_t)irep->ire_marks, mmasks, 5893448Sdh155122 "", ips_to_stackid((uintptr_t)irep->ire_ipst), 5903448Sdh155122 irep->ire_zoneid, irep->ire_flags, fmasks); 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate } else { 5930Sstevel@tonic-gate 5943448Sdh155122 mdb_printf("%?p %30I %30I %5d %4d\n", addr, irep->ire_src_addr, 5953448Sdh155122 irep->ire_addr, ips_to_stackid((uintptr_t)irep->ire_ipst), 5963448Sdh155122 irep->ire_zoneid); 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate return (WALK_NEXT); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate /* 6030Sstevel@tonic-gate * There are faster ways to do this. Given the interactive nature of this 6040Sstevel@tonic-gate * use I don't think its worth much effort. 6050Sstevel@tonic-gate */ 6060Sstevel@tonic-gate static unsigned short 6070Sstevel@tonic-gate ipcksum(void *p, int len) 6080Sstevel@tonic-gate { 6090Sstevel@tonic-gate int32_t sum = 0; 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate while (len > 1) { 6120Sstevel@tonic-gate /* alignment */ 6130Sstevel@tonic-gate sum += *(uint16_t *)p; 6140Sstevel@tonic-gate p = (char *)p + sizeof (uint16_t); 6150Sstevel@tonic-gate if (sum & 0x80000000) 6160Sstevel@tonic-gate sum = (sum & 0xFFFF) + (sum >> 16); 6170Sstevel@tonic-gate len -= 2; 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate if (len) 6210Sstevel@tonic-gate sum += (uint16_t)*(unsigned char *)p; 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate while (sum >> 16) 6240Sstevel@tonic-gate sum = (sum & 0xFFFF) + (sum >> 16); 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate return (~sum); 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate static const mdb_bitmask_t tcp_flags[] = { 6300Sstevel@tonic-gate { "SYN", TH_SYN, TH_SYN }, 6310Sstevel@tonic-gate { "ACK", TH_ACK, TH_ACK }, 6320Sstevel@tonic-gate { "FIN", TH_FIN, TH_FIN }, 6330Sstevel@tonic-gate { "RST", TH_RST, TH_RST }, 6340Sstevel@tonic-gate { "PSH", TH_PUSH, TH_PUSH }, 6350Sstevel@tonic-gate { "ECE", TH_ECE, TH_ECE }, 6360Sstevel@tonic-gate { "CWR", TH_CWR, TH_CWR }, 6370Sstevel@tonic-gate { NULL, 0, 0 } 6380Sstevel@tonic-gate }; 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate static void 6410Sstevel@tonic-gate tcphdr_print(struct tcphdr *tcph) 6420Sstevel@tonic-gate { 6430Sstevel@tonic-gate in_port_t sport, dport; 6440Sstevel@tonic-gate tcp_seq seq, ack; 6450Sstevel@tonic-gate uint16_t win, urp; 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate mdb_printf("%<b>TCP header%</b>\n"); 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport)); 6500Sstevel@tonic-gate mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport)); 6510Sstevel@tonic-gate mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq)); 6520Sstevel@tonic-gate mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack)); 6530Sstevel@tonic-gate mdb_nhconvert(&win, &tcph->th_win, sizeof (win)); 6540Sstevel@tonic-gate mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp)); 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n", 6570Sstevel@tonic-gate "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP", 6580Sstevel@tonic-gate "FLAGS"); 6590Sstevel@tonic-gate mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n", 6600Sstevel@tonic-gate sport, dport, seq, ack, tcph->th_off << 2, win, 6610Sstevel@tonic-gate tcph->th_sum, urp, tcph->th_flags, tcp_flags); 6620Sstevel@tonic-gate mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n", 6630Sstevel@tonic-gate sport, dport, seq, ack); 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate /* ARGSUSED */ 6670Sstevel@tonic-gate static int 6680Sstevel@tonic-gate tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 6690Sstevel@tonic-gate { 6700Sstevel@tonic-gate struct tcphdr tcph; 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 6730Sstevel@tonic-gate return (DCMD_USAGE); 6740Sstevel@tonic-gate 6750Sstevel@tonic-gate if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 6760Sstevel@tonic-gate mdb_warn("failed to read TCP header at %p", addr); 6770Sstevel@tonic-gate return (DCMD_ERR); 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate tcphdr_print(&tcph); 6800Sstevel@tonic-gate return (DCMD_OK); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate static void 6840Sstevel@tonic-gate udphdr_print(struct udphdr *udph) 6850Sstevel@tonic-gate { 6860Sstevel@tonic-gate in_port_t sport, dport; 6870Sstevel@tonic-gate uint16_t hlen; 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate mdb_printf("%<b>UDP header%</b>\n"); 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport)); 6920Sstevel@tonic-gate mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport)); 6930Sstevel@tonic-gate mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen)); 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate mdb_printf("%<u>%14s %14s %5s %6s%</u>\n", 6960Sstevel@tonic-gate "SPORT", "DPORT", "LEN", "CSUM"); 6970Sstevel@tonic-gate mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport, 6980Sstevel@tonic-gate dport, dport, hlen, udph->uh_sum); 6990Sstevel@tonic-gate } 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate /* ARGSUSED */ 7020Sstevel@tonic-gate static int 7030Sstevel@tonic-gate udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 7040Sstevel@tonic-gate { 7050Sstevel@tonic-gate struct udphdr udph; 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 7080Sstevel@tonic-gate return (DCMD_USAGE); 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 7110Sstevel@tonic-gate mdb_warn("failed to read UDP header at %p", addr); 7120Sstevel@tonic-gate return (DCMD_ERR); 7130Sstevel@tonic-gate } 7140Sstevel@tonic-gate udphdr_print(&udph); 7150Sstevel@tonic-gate return (DCMD_OK); 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate static void 7190Sstevel@tonic-gate sctphdr_print(sctp_hdr_t *sctph) 7200Sstevel@tonic-gate { 7210Sstevel@tonic-gate in_port_t sport, dport; 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate mdb_printf("%<b>SCTP header%</b>\n"); 7240Sstevel@tonic-gate mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport)); 7250Sstevel@tonic-gate mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport)); 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate mdb_printf("%<u>%14s %14s %10s %10s%</u>\n", 7280Sstevel@tonic-gate "SPORT", "DPORT", "VTAG", "CHKSUM"); 7290Sstevel@tonic-gate mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport, 7300Sstevel@tonic-gate dport, dport, sctph->sh_verf, sctph->sh_chksum); 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate 7330Sstevel@tonic-gate /* ARGSUSED */ 7340Sstevel@tonic-gate static int 7350Sstevel@tonic-gate sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 7360Sstevel@tonic-gate { 7370Sstevel@tonic-gate sctp_hdr_t sctph; 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) 7400Sstevel@tonic-gate return (DCMD_USAGE); 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 7430Sstevel@tonic-gate mdb_warn("failed to read SCTP header at %p", addr); 7440Sstevel@tonic-gate return (DCMD_ERR); 7450Sstevel@tonic-gate } 7460Sstevel@tonic-gate 7470Sstevel@tonic-gate sctphdr_print(&sctph); 7480Sstevel@tonic-gate return (DCMD_OK); 7490Sstevel@tonic-gate } 7500Sstevel@tonic-gate 7510Sstevel@tonic-gate static int 7520Sstevel@tonic-gate transport_hdr(int proto, uintptr_t addr) 7530Sstevel@tonic-gate { 7540Sstevel@tonic-gate mdb_printf("\n"); 7550Sstevel@tonic-gate switch (proto) { 7560Sstevel@tonic-gate case IPPROTO_TCP: { 7570Sstevel@tonic-gate struct tcphdr tcph; 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 7600Sstevel@tonic-gate mdb_warn("failed to read TCP header at %p", addr); 7610Sstevel@tonic-gate return (DCMD_ERR); 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate tcphdr_print(&tcph); 7640Sstevel@tonic-gate break; 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate case IPPROTO_UDP: { 7670Sstevel@tonic-gate struct udphdr udph; 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 7700Sstevel@tonic-gate mdb_warn("failed to read UDP header at %p", addr); 7710Sstevel@tonic-gate return (DCMD_ERR); 7720Sstevel@tonic-gate } 7730Sstevel@tonic-gate udphdr_print(&udph); 7740Sstevel@tonic-gate break; 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate case IPPROTO_SCTP: { 7770Sstevel@tonic-gate sctp_hdr_t sctph; 7780Sstevel@tonic-gate 7790Sstevel@tonic-gate if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 7800Sstevel@tonic-gate mdb_warn("failed to read SCTP header at %p", addr); 7810Sstevel@tonic-gate return (DCMD_ERR); 7820Sstevel@tonic-gate } 7830Sstevel@tonic-gate sctphdr_print(&sctph); 7840Sstevel@tonic-gate break; 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate default: 7870Sstevel@tonic-gate break; 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate return (DCMD_OK); 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate static const mdb_bitmask_t ip_flags[] = { 7940Sstevel@tonic-gate { "DF", IPH_DF, IPH_DF }, 7950Sstevel@tonic-gate { "MF", IPH_MF, IPH_MF }, 7960Sstevel@tonic-gate { NULL, 0, 0 } 7970Sstevel@tonic-gate }; 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate /* ARGSUSED */ 8000Sstevel@tonic-gate static int 8010Sstevel@tonic-gate iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 8020Sstevel@tonic-gate { 8030Sstevel@tonic-gate uint_t verbose = FALSE, force = FALSE; 8040Sstevel@tonic-gate ipha_t iph[1]; 8050Sstevel@tonic-gate uint16_t ver, totlen, hdrlen, ipid, off, csum; 8060Sstevel@tonic-gate uintptr_t nxt_proto; 8070Sstevel@tonic-gate char exp_csum[8]; 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate if (mdb_getopts(argc, argv, 8100Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, TRUE, &verbose, 8110Sstevel@tonic-gate 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 8120Sstevel@tonic-gate return (DCMD_USAGE); 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 8150Sstevel@tonic-gate mdb_warn("failed to read IPv4 header at %p", addr); 8160Sstevel@tonic-gate return (DCMD_ERR); 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate 8190Sstevel@tonic-gate ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4; 8200Sstevel@tonic-gate if (ver != IPV4_VERSION) { 8210Sstevel@tonic-gate if (ver == IPV6_VERSION) { 8220Sstevel@tonic-gate return (ip6hdr(addr, flags, argc, argv)); 8230Sstevel@tonic-gate } else if (!force) { 8240Sstevel@tonic-gate mdb_warn("unknown IP version: %d\n", ver); 8250Sstevel@tonic-gate return (DCMD_ERR); 8260Sstevel@tonic-gate } 8270Sstevel@tonic-gate } 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate mdb_printf("%<b>IPv4 header%</b>\n"); 8300Sstevel@tonic-gate mdb_printf("%-34s %-34s\n" 8310Sstevel@tonic-gate "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n", 8320Sstevel@tonic-gate "SRC", "DST", 8330Sstevel@tonic-gate "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM", 8340Sstevel@tonic-gate "EXP-CSUM", "FLGS"); 8350Sstevel@tonic-gate 8360Sstevel@tonic-gate hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2; 8370Sstevel@tonic-gate mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen)); 8380Sstevel@tonic-gate mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid)); 8390Sstevel@tonic-gate mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off)); 8400Sstevel@tonic-gate if (hdrlen == IP_SIMPLE_HDR_LENGTH) { 8410Sstevel@tonic-gate if ((csum = ipcksum(iph, sizeof (*iph))) != 0) 8420Sstevel@tonic-gate csum = ~(~csum + ~iph->ipha_hdr_checksum); 8430Sstevel@tonic-gate else 8440Sstevel@tonic-gate csum = iph->ipha_hdr_checksum; 8450Sstevel@tonic-gate mdb_snprintf(exp_csum, 8, "%u", csum); 8460Sstevel@tonic-gate } else { 8470Sstevel@tonic-gate mdb_snprintf(exp_csum, 8, "<n/a>"); 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate mdb_printf("%-34I %-34I%\n" 8510Sstevel@tonic-gate "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n", 8520Sstevel@tonic-gate iph->ipha_src, iph->ipha_dst, 8530Sstevel@tonic-gate hdrlen, iph->ipha_type_of_service, totlen, ipid, 8540Sstevel@tonic-gate (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol, 8550Sstevel@tonic-gate iph->ipha_hdr_checksum, exp_csum, off, ip_flags); 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate if (verbose) { 8580Sstevel@tonic-gate nxt_proto = addr + hdrlen; 8590Sstevel@tonic-gate return (transport_hdr(iph->ipha_protocol, nxt_proto)); 8600Sstevel@tonic-gate } else { 8610Sstevel@tonic-gate return (DCMD_OK); 8620Sstevel@tonic-gate } 8630Sstevel@tonic-gate } 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate /* ARGSUSED */ 8660Sstevel@tonic-gate static int 8670Sstevel@tonic-gate ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 8680Sstevel@tonic-gate { 8690Sstevel@tonic-gate uint_t verbose = FALSE, force = FALSE; 8700Sstevel@tonic-gate ip6_t iph[1]; 8710Sstevel@tonic-gate int ver, class, flow; 8720Sstevel@tonic-gate uint16_t plen; 8730Sstevel@tonic-gate uintptr_t nxt_proto; 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate if (mdb_getopts(argc, argv, 8760Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, TRUE, &verbose, 8770Sstevel@tonic-gate 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 8780Sstevel@tonic-gate return (DCMD_USAGE); 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 8810Sstevel@tonic-gate mdb_warn("failed to read IPv6 header at %p", addr); 8820Sstevel@tonic-gate return (DCMD_ERR); 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate ver = (iph->ip6_vfc & 0xf0) >> 4; 8860Sstevel@tonic-gate if (ver != IPV6_VERSION) { 8870Sstevel@tonic-gate if (ver == IPV4_VERSION) { 8880Sstevel@tonic-gate return (iphdr(addr, flags, argc, argv)); 8890Sstevel@tonic-gate } else if (!force) { 8900Sstevel@tonic-gate mdb_warn("unknown IP version: %d\n", ver); 8910Sstevel@tonic-gate return (DCMD_ERR); 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate mdb_printf("%<b>IPv6 header%</b>\n"); 8960Sstevel@tonic-gate mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n", 8970Sstevel@tonic-gate "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP"); 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20; 9000Sstevel@tonic-gate mdb_nhconvert(&class, &class, sizeof (class)); 9010Sstevel@tonic-gate flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL; 9020Sstevel@tonic-gate mdb_nhconvert(&flow, &flow, sizeof (flow)); 9030Sstevel@tonic-gate mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen)); 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n", 9060Sstevel@tonic-gate &iph->ip6_src, &iph->ip6_dst, 9070Sstevel@tonic-gate class, flow, plen, iph->ip6_nxt, iph->ip6_hlim); 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate if (verbose) { 9100Sstevel@tonic-gate nxt_proto = addr + sizeof (ip6_t); 9110Sstevel@tonic-gate return (transport_hdr(iph->ip6_nxt, nxt_proto)); 9120Sstevel@tonic-gate } else { 9130Sstevel@tonic-gate return (DCMD_OK); 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate int 9180Sstevel@tonic-gate ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 9190Sstevel@tonic-gate { 9200Sstevel@tonic-gate uint_t verbose = FALSE; 9210Sstevel@tonic-gate ire_t ire; 922*5940Ssowmini ire_cbdata_t ire_cb; 923*5940Ssowmini int ipversion = 0; 924*5940Ssowmini const char *opt_P = NULL; 9250Sstevel@tonic-gate 9260Sstevel@tonic-gate if (mdb_getopts(argc, argv, 927*5940Ssowmini 'v', MDB_OPT_SETBITS, TRUE, &verbose, 928*5940Ssowmini 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 9290Sstevel@tonic-gate return (DCMD_USAGE); 9300Sstevel@tonic-gate 931*5940Ssowmini if (opt_P != NULL) { 932*5940Ssowmini if (strcmp("v4", opt_P) == 0) { 933*5940Ssowmini ipversion = IPV4_VERSION; 934*5940Ssowmini } else if (strcmp("v6", opt_P) == 0) { 935*5940Ssowmini ipversion = IPV6_VERSION; 936*5940Ssowmini } else { 937*5940Ssowmini mdb_warn("invalid protocol '%s'\n", opt_P); 938*5940Ssowmini return (DCMD_USAGE); 939*5940Ssowmini } 940*5940Ssowmini } 941*5940Ssowmini 9420Sstevel@tonic-gate if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate if (verbose) { 9450Sstevel@tonic-gate mdb_printf("%?s %40s %-20s%\n" 9460Sstevel@tonic-gate "%?s %40s %-20s%\n" 9473448Sdh155122 "%<u>%?s %40s %4s %-20s%</u>\n", 9480Sstevel@tonic-gate "ADDR", "SRC", "TYPE", 9490Sstevel@tonic-gate "", "DST", "MARKS", 9503448Sdh155122 "", "STACK", "ZONE", "FLAGS"); 9510Sstevel@tonic-gate } else { 9523448Sdh155122 mdb_printf("%<u>%?s %30s %30s %5s %4s%</u>\n", 9533448Sdh155122 "ADDR", "SRC", "DST", "STACK", "ZONE"); 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate } 9560Sstevel@tonic-gate 957*5940Ssowmini ire_cb.verbose = (verbose == TRUE); 958*5940Ssowmini ire_cb.ire_ipversion = ipversion; 959*5940Ssowmini 9600Sstevel@tonic-gate if (flags & DCMD_ADDRSPEC) { 9610Sstevel@tonic-gate (void) mdb_vread(&ire, sizeof (ire_t), addr); 962*5940Ssowmini (void) ire_format(addr, &ire, &ire_cb); 963*5940Ssowmini } else if (mdb_walk("ire", (mdb_walk_cb_t)ire_format, &ire_cb) == -1) { 9640Sstevel@tonic-gate mdb_warn("failed to walk ire table"); 9650Sstevel@tonic-gate return (DCMD_ERR); 9660Sstevel@tonic-gate } 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate return (DCMD_OK); 9690Sstevel@tonic-gate } 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate static size_t 9720Sstevel@tonic-gate mi_osize(const queue_t *q) 9730Sstevel@tonic-gate { 9740Sstevel@tonic-gate /* 9750Sstevel@tonic-gate * The code in common/inet/mi.c allocates an extra word to store the 9760Sstevel@tonic-gate * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s. 9770Sstevel@tonic-gate */ 9780Sstevel@tonic-gate struct mi_block { 9790Sstevel@tonic-gate size_t mi_nbytes; 9800Sstevel@tonic-gate struct mi_o_s mi_o; 9810Sstevel@tonic-gate } m; 9820Sstevel@tonic-gate 9830Sstevel@tonic-gate if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - 9840Sstevel@tonic-gate sizeof (m)) == sizeof (m)) 9850Sstevel@tonic-gate return (m.mi_nbytes - sizeof (m)); 9860Sstevel@tonic-gate 9870Sstevel@tonic-gate return (0); 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate static void 9910Sstevel@tonic-gate ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes) 9920Sstevel@tonic-gate { 9930Sstevel@tonic-gate char name[32]; 9940Sstevel@tonic-gate ill_t ill; 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate if (mdb_vread(&ill, sizeof (ill), 9970Sstevel@tonic-gate (uintptr_t)q->q_ptr) == sizeof (ill) && 9980Sstevel@tonic-gate mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0) 9990Sstevel@tonic-gate (void) mdb_snprintf(buf, nbytes, "if: %s", name); 10000Sstevel@tonic-gate } 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate void 10030Sstevel@tonic-gate ip_qinfo(const queue_t *q, char *buf, size_t nbytes) 10040Sstevel@tonic-gate { 10050Sstevel@tonic-gate size_t size = mi_osize(q); 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate if (size == sizeof (ill_t)) 10080Sstevel@tonic-gate ip_ill_qinfo(q, buf, nbytes); 10090Sstevel@tonic-gate } 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate uintptr_t 10120Sstevel@tonic-gate ip_rnext(const queue_t *q) 10130Sstevel@tonic-gate { 10140Sstevel@tonic-gate size_t size = mi_osize(q); 10150Sstevel@tonic-gate ill_t ill; 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 10180Sstevel@tonic-gate (uintptr_t)q->q_ptr) == sizeof (ill)) 10190Sstevel@tonic-gate return ((uintptr_t)ill.ill_rq); 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate return (NULL); 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate uintptr_t 10250Sstevel@tonic-gate ip_wnext(const queue_t *q) 10260Sstevel@tonic-gate { 10270Sstevel@tonic-gate size_t size = mi_osize(q); 10280Sstevel@tonic-gate ill_t ill; 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 10310Sstevel@tonic-gate (uintptr_t)q->q_ptr) == sizeof (ill)) 10320Sstevel@tonic-gate return ((uintptr_t)ill.ill_wq); 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate return (NULL); 10350Sstevel@tonic-gate } 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate /* 10380Sstevel@tonic-gate * Print the core fields in an squeue_t. With the "-v" argument, 10390Sstevel@tonic-gate * provide more verbose output. 10400Sstevel@tonic-gate */ 10410Sstevel@tonic-gate static int 10420Sstevel@tonic-gate squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 10430Sstevel@tonic-gate { 10440Sstevel@tonic-gate unsigned int i; 10450Sstevel@tonic-gate unsigned int verbose = FALSE; 10460Sstevel@tonic-gate const int SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9); 10470Sstevel@tonic-gate boolean_t arm; 10480Sstevel@tonic-gate squeue_t squeue; 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 10510Sstevel@tonic-gate if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue", 10520Sstevel@tonic-gate argc, argv) == -1) { 10530Sstevel@tonic-gate mdb_warn("failed to walk squeue cache"); 10540Sstevel@tonic-gate return (DCMD_ERR); 10550Sstevel@tonic-gate } 10560Sstevel@tonic-gate return (DCMD_OK); 10570Sstevel@tonic-gate } 10580Sstevel@tonic-gate 10590Sstevel@tonic-gate if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) 10600Sstevel@tonic-gate != argc) 10610Sstevel@tonic-gate return (DCMD_USAGE); 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate if (!DCMD_HDRSPEC(flags) && verbose) 10640Sstevel@tonic-gate mdb_printf("\n\n"); 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate if (DCMD_HDRSPEC(flags) || verbose) { 10670Sstevel@tonic-gate mdb_printf("%?s %-5s %-3s %?s %?s %?s\n", 10680Sstevel@tonic-gate "ADDR", "STATE", "CPU", 10690Sstevel@tonic-gate "FIRST", "LAST", "WORKER"); 10700Sstevel@tonic-gate } 10710Sstevel@tonic-gate 10720Sstevel@tonic-gate if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) { 10730Sstevel@tonic-gate mdb_warn("cannot read squeue_t at %p", addr); 10740Sstevel@tonic-gate return (DCMD_ERR); 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate 10770Sstevel@tonic-gate mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n", 10780Sstevel@tonic-gate addr, squeue.sq_state, squeue.sq_bind, 10790Sstevel@tonic-gate squeue.sq_first, squeue.sq_last, squeue.sq_worker); 10800Sstevel@tonic-gate 10810Sstevel@tonic-gate if (!verbose) 10820Sstevel@tonic-gate return (DCMD_OK); 10830Sstevel@tonic-gate 10840Sstevel@tonic-gate arm = B_TRUE; 10850Sstevel@tonic-gate for (i = 0; squeue_states[i].bit_name != NULL; i++) { 10860Sstevel@tonic-gate if (((squeue.sq_state) & (1 << i)) == 0) 10870Sstevel@tonic-gate continue; 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate if (arm) { 10900Sstevel@tonic-gate mdb_printf("%*s|\n", SQUEUE_STATEDELT, ""); 10910Sstevel@tonic-gate mdb_printf("%*s+--> ", SQUEUE_STATEDELT, ""); 10920Sstevel@tonic-gate arm = B_FALSE; 10930Sstevel@tonic-gate } else 10940Sstevel@tonic-gate mdb_printf("%*s ", SQUEUE_STATEDELT, ""); 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate mdb_printf("%-12s %s\n", squeue_states[i].bit_name, 10970Sstevel@tonic-gate squeue_states[i].bit_descr); 10980Sstevel@tonic-gate } 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate return (DCMD_OK); 11010Sstevel@tonic-gate } 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate static void 11040Sstevel@tonic-gate ip_squeue_help(void) 11050Sstevel@tonic-gate { 11060Sstevel@tonic-gate mdb_printf("Print the core information for a given NCA squeue_t.\n\n"); 11070Sstevel@tonic-gate mdb_printf("Options:\n"); 11080Sstevel@tonic-gate mdb_printf("\t-v\tbe verbose (more descriptive)\n"); 11090Sstevel@tonic-gate } 11100Sstevel@tonic-gate 11115023Scarlsonj /* 11125023Scarlsonj * This is called by ::th_trace (via a callback) when walking the th_hash 11135023Scarlsonj * list. It calls modent to find the entries. 11145023Scarlsonj */ 11155023Scarlsonj /* ARGSUSED */ 11165023Scarlsonj static int 11175023Scarlsonj modent_summary(uintptr_t addr, const void *data, void *private) 11185023Scarlsonj { 11195023Scarlsonj th_walk_data_t *thw = private; 11205023Scarlsonj const struct mod_hash_entry *mhe = data; 11215023Scarlsonj th_trace_t th; 11225023Scarlsonj 11235023Scarlsonj if (mdb_vread(&th, sizeof (th), (uintptr_t)mhe->mhe_val) == -1) { 11245023Scarlsonj mdb_warn("failed to read th_trace_t %p", mhe->mhe_val); 11255023Scarlsonj return (WALK_ERR); 11265023Scarlsonj } 11275023Scarlsonj 11285023Scarlsonj if (th.th_refcnt == 0 && thw->thw_non_zero_only) 11295023Scarlsonj return (WALK_NEXT); 11305023Scarlsonj 11315023Scarlsonj if (!thw->thw_match) { 11325023Scarlsonj mdb_printf("%?p %?p %?p %8d %?p\n", thw->thw_ipst, mhe->mhe_key, 11335023Scarlsonj mhe->mhe_val, th.th_refcnt, th.th_id); 11345023Scarlsonj } else if (thw->thw_matchkey == (uintptr_t)mhe->mhe_key) { 11355023Scarlsonj int i, j, k; 11365023Scarlsonj tr_buf_t *tr; 11375023Scarlsonj 11385023Scarlsonj mdb_printf("Object %p in IP stack %p:\n", mhe->mhe_key, 11395023Scarlsonj thw->thw_ipst); 11405023Scarlsonj i = th.th_trace_lastref; 11415023Scarlsonj mdb_printf("\tThread %p refcnt %d:\n", th.th_id, 11425023Scarlsonj th.th_refcnt); 11435023Scarlsonj for (j = TR_BUF_MAX; j > 0; j--) { 11445023Scarlsonj tr = th.th_trbuf + i; 11455023Scarlsonj if (tr->tr_depth == 0 || tr->tr_depth > TR_STACK_DEPTH) 11465023Scarlsonj break; 11475023Scarlsonj mdb_printf("\t T%+ld:\n", tr->tr_time - 11485023Scarlsonj thw->thw_lbolt); 11495023Scarlsonj for (k = 0; k < tr->tr_depth; k++) 11505023Scarlsonj mdb_printf("\t\t%a\n", tr->tr_stack[k]); 11515023Scarlsonj if (--i < 0) 11525023Scarlsonj i = TR_BUF_MAX - 1; 11535023Scarlsonj } 11545023Scarlsonj } 11555023Scarlsonj return (WALK_NEXT); 11565023Scarlsonj } 11575023Scarlsonj 11585023Scarlsonj /* 11595023Scarlsonj * This is called by ::th_trace (via a callback) when walking the th_hash 11605023Scarlsonj * list. It calls modent to find the entries. 11615023Scarlsonj */ 11625023Scarlsonj /* ARGSUSED */ 11635023Scarlsonj static int 11645023Scarlsonj th_hash_summary(uintptr_t addr, const void *data, void *private) 11655023Scarlsonj { 11665023Scarlsonj const th_hash_t *thh = data; 11675023Scarlsonj th_walk_data_t *thw = private; 11685023Scarlsonj 11695023Scarlsonj thw->thw_ipst = (uintptr_t)thh->thh_ipst; 11705023Scarlsonj return (mdb_pwalk("modent", modent_summary, private, 11715023Scarlsonj (uintptr_t)thh->thh_hash)); 11725023Scarlsonj } 11735023Scarlsonj 11745023Scarlsonj /* 11755023Scarlsonj * Print or summarize the th_trace_t structures. 11765023Scarlsonj */ 11775023Scarlsonj static int 11785023Scarlsonj th_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 11795023Scarlsonj { 11805023Scarlsonj th_walk_data_t thw; 11815023Scarlsonj 11825023Scarlsonj (void) memset(&thw, 0, sizeof (thw)); 11835023Scarlsonj 11845023Scarlsonj if (mdb_getopts(argc, argv, 11855023Scarlsonj 'n', MDB_OPT_SETBITS, TRUE, &thw.thw_non_zero_only, 11865023Scarlsonj NULL) != argc) 11875023Scarlsonj return (DCMD_USAGE); 11885023Scarlsonj 11895023Scarlsonj if (!(flags & DCMD_ADDRSPEC)) { 11905023Scarlsonj /* 11915023Scarlsonj * No address specified. Walk all of the th_hash_t in the 11925023Scarlsonj * system, and summarize the th_trace_t entries in each. 11935023Scarlsonj */ 11945023Scarlsonj mdb_printf("%?s %?s %?s %8s %?s\n", 11955023Scarlsonj "IPSTACK", "OBJECT", "TRACE", "REFCNT", "THREAD"); 11965023Scarlsonj thw.thw_match = B_FALSE; 11975023Scarlsonj } else { 11985023Scarlsonj thw.thw_match = B_TRUE; 11995023Scarlsonj thw.thw_matchkey = addr; 12005023Scarlsonj if (mdb_readvar(&thw.thw_lbolt, 12015023Scarlsonj mdb_prop_postmortem ? "panic_lbolt" : "lbolt") == -1) { 12025023Scarlsonj mdb_warn("failed to read lbolt"); 12035023Scarlsonj return (DCMD_ERR); 12045023Scarlsonj } 12055023Scarlsonj } 12065023Scarlsonj if (mdb_pwalk("th_hash", th_hash_summary, &thw, NULL) == -1) { 12075023Scarlsonj mdb_warn("can't walk th_hash entries"); 12085023Scarlsonj return (DCMD_ERR); 12095023Scarlsonj } 12105023Scarlsonj return (DCMD_OK); 12115023Scarlsonj } 12125023Scarlsonj 12135023Scarlsonj static void 12145023Scarlsonj th_trace_help(void) 12155023Scarlsonj { 12165023Scarlsonj mdb_printf("If given an address of an ill_t, ipif_t, ire_t, or nce_t, " 12175023Scarlsonj "print the\n" 12185023Scarlsonj "corresponding th_trace_t structure in detail. Otherwise, if no " 12195023Scarlsonj "address is\n" 12205023Scarlsonj "given, then summarize all th_trace_t structures.\n\n"); 12215023Scarlsonj mdb_printf("Options:\n" 12225023Scarlsonj "\t-n\tdisplay only entries with non-zero th_refcnt\n"); 12235023Scarlsonj } 12245023Scarlsonj 12250Sstevel@tonic-gate static const mdb_dcmd_t dcmds[] = { 12260Sstevel@tonic-gate { "illif", "?[-P v4 | v6]", 12270Sstevel@tonic-gate "display or filter IP Lower Level InterFace structures", illif, 12280Sstevel@tonic-gate illif_help }, 12290Sstevel@tonic-gate { "iphdr", ":[-vf]", "display an IPv4 header", iphdr }, 12300Sstevel@tonic-gate { "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr }, 1231*5940Ssowmini { "ire", "?[-v] [-P v4|v6]", 1232*5940Ssowmini "display Internet Route Entry structures", ire }, 1233*5940Ssowmini { "nce", "?[-P v4 | v6]", "display Neighbor Cache Entry structures", 1234*5940Ssowmini nce }, 12350Sstevel@tonic-gate { "squeue", ":[-v]", "print core squeue_t info", squeue, 12360Sstevel@tonic-gate ip_squeue_help }, 12370Sstevel@tonic-gate { "tcphdr", ":", "display a TCP header", tcphdr }, 12380Sstevel@tonic-gate { "udphdr", ":", "display an UDP header", udphdr }, 12390Sstevel@tonic-gate { "sctphdr", ":", "display an SCTP header", sctphdr }, 12405023Scarlsonj { "th_trace", "?[-n]", "display th_trace_t structures", th_trace, 12415023Scarlsonj th_trace_help }, 12420Sstevel@tonic-gate { NULL } 12430Sstevel@tonic-gate }; 12440Sstevel@tonic-gate 12450Sstevel@tonic-gate static const mdb_walker_t walkers[] = { 12463448Sdh155122 { "illif", "walk list of ill interface types for all stacks", 1247*5940Ssowmini ip_stacks_common_walk_init, illif_walk_step, NULL }, 12483448Sdh155122 { "illif_stack", "walk list of ill interface types", 12493448Sdh155122 illif_stack_walk_init, illif_stack_walk_step, 12503448Sdh155122 illif_stack_walk_fini }, 12510Sstevel@tonic-gate { "ire", "walk active ire_t structures", 12520Sstevel@tonic-gate ire_walk_init, ire_walk_step, NULL }, 12533448Sdh155122 { "ire_ctable", "walk ire_t structures in the ctable", 1254*5940Ssowmini ip_stacks_common_walk_init, ire_ctable_walk_step, NULL }, 12553448Sdh155122 { "ire_next", "walk ire_t structures in the ctable", 12563448Sdh155122 ire_next_walk_init, ire_next_walk_step, NULL }, 12573448Sdh155122 { "ip_stacks", "walk all the ip_stack_t", 12583448Sdh155122 ip_stacks_walk_init, ip_stacks_walk_step, NULL }, 12595023Scarlsonj { "th_hash", "walk all the th_hash_t entries", 12605023Scarlsonj th_hash_walk_init, th_hash_walk_step, NULL }, 1261*5940Ssowmini { "nce", "walk list of nce structures for all stacks", 1262*5940Ssowmini ip_stacks_common_walk_init, nce_walk_step, NULL }, 1263*5940Ssowmini { "nce_stack", "walk list of nce structures", 1264*5940Ssowmini nce_stack_walk_init, nce_stack_walk_step, 1265*5940Ssowmini nce_stack_walk_fini}, 12660Sstevel@tonic-gate { NULL } 12670Sstevel@tonic-gate }; 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext }; 12700Sstevel@tonic-gate static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate const mdb_modinfo_t * 12730Sstevel@tonic-gate _mdb_init(void) 12740Sstevel@tonic-gate { 12750Sstevel@tonic-gate GElf_Sym sym; 12760Sstevel@tonic-gate 12772546Scarlsonj if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 12780Sstevel@tonic-gate mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value); 12790Sstevel@tonic-gate 12800Sstevel@tonic-gate return (&modinfo); 12810Sstevel@tonic-gate } 12820Sstevel@tonic-gate 12830Sstevel@tonic-gate void 12840Sstevel@tonic-gate _mdb_fini(void) 12850Sstevel@tonic-gate { 12860Sstevel@tonic-gate GElf_Sym sym; 12870Sstevel@tonic-gate 12882546Scarlsonj if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 12890Sstevel@tonic-gate mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value); 12900Sstevel@tonic-gate } 1291*5940Ssowmini 1292*5940Ssowmini static char * 1293*5940Ssowmini nce_state(int nce_state) 1294*5940Ssowmini { 1295*5940Ssowmini switch (nce_state) { 1296*5940Ssowmini case ND_UNCHANGED: 1297*5940Ssowmini return ("unchanged"); 1298*5940Ssowmini case ND_INCOMPLETE: 1299*5940Ssowmini return ("incomplete"); 1300*5940Ssowmini case ND_REACHABLE: 1301*5940Ssowmini return ("reachable"); 1302*5940Ssowmini case ND_STALE: 1303*5940Ssowmini return ("stale"); 1304*5940Ssowmini case ND_DELAY: 1305*5940Ssowmini return ("delay"); 1306*5940Ssowmini case ND_PROBE: 1307*5940Ssowmini return ("probe"); 1308*5940Ssowmini case ND_UNREACHABLE: 1309*5940Ssowmini return ("unreach"); 1310*5940Ssowmini case ND_INITIAL: 1311*5940Ssowmini return ("initial"); 1312*5940Ssowmini default: 1313*5940Ssowmini return ("??"); 1314*5940Ssowmini } 1315*5940Ssowmini } 1316*5940Ssowmini 1317*5940Ssowmini static char * 1318*5940Ssowmini nce_l2_addr(const nce_t *nce, const ill_t *ill) 1319*5940Ssowmini { 1320*5940Ssowmini uchar_t *h; 1321*5940Ssowmini static char addr_buf[L2MAXADDRSTRLEN]; 1322*5940Ssowmini mblk_t mp; 1323*5940Ssowmini size_t mblen; 1324*5940Ssowmini 1325*5940Ssowmini if (ill->ill_flags & ILLF_XRESOLV) { 1326*5940Ssowmini return ("XRESOLV"); 1327*5940Ssowmini } 1328*5940Ssowmini 1329*5940Ssowmini if (nce->nce_res_mp == NULL) { 1330*5940Ssowmini return ("None"); 1331*5940Ssowmini } 1332*5940Ssowmini 1333*5940Ssowmini if (ill->ill_net_type == IRE_IF_RESOLVER) { 1334*5940Ssowmini 1335*5940Ssowmini if (mdb_vread(&mp, sizeof (mblk_t), 1336*5940Ssowmini (uintptr_t)nce->nce_res_mp) == -1) { 1337*5940Ssowmini mdb_warn("failed to read nce_res_mp at %p", 1338*5940Ssowmini nce->nce_res_mp); 1339*5940Ssowmini } 1340*5940Ssowmini 1341*5940Ssowmini if (ill->ill_nd_lla_len == 0) 1342*5940Ssowmini return ("None"); 1343*5940Ssowmini mblen = mp.b_wptr - mp.b_rptr; 1344*5940Ssowmini if (mblen > (sizeof (dl_unitdata_req_t) + MAX_SAP_LEN) || 1345*5940Ssowmini ill->ill_nd_lla_len > MAX_SAP_LEN || 1346*5940Ssowmini NCE_LL_ADDR_OFFSET(ill) + ill->ill_nd_lla_len > mblen) { 1347*5940Ssowmini return ("Truncated"); 1348*5940Ssowmini } 1349*5940Ssowmini h = mdb_zalloc(mblen, UM_SLEEP); 1350*5940Ssowmini if (mdb_vread(h, mblen, (uintptr_t)(mp.b_rptr)) == -1) { 1351*5940Ssowmini mdb_warn("failed to read hwaddr at %p", 1352*5940Ssowmini mp.b_rptr + NCE_LL_ADDR_OFFSET(ill)); 1353*5940Ssowmini return ("Unknown"); 1354*5940Ssowmini } 1355*5940Ssowmini mdb_mac_addr(h + NCE_LL_ADDR_OFFSET(ill), ill->ill_nd_lla_len, 1356*5940Ssowmini addr_buf, sizeof (addr_buf)); 1357*5940Ssowmini } else { 1358*5940Ssowmini return ("None"); 1359*5940Ssowmini } 1360*5940Ssowmini mdb_free(h, mblen); 1361*5940Ssowmini return (addr_buf); 1362*5940Ssowmini } 1363*5940Ssowmini 1364*5940Ssowmini static void 1365*5940Ssowmini nce_header(uint_t flags) 1366*5940Ssowmini { 1367*5940Ssowmini if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 1368*5940Ssowmini 1369*5940Ssowmini mdb_printf("%<u>%?s %-20s %-10s %-8s %-5s %s%</u>\n", 1370*5940Ssowmini "ADDR", "HW_ADDR", "STATE", "FLAGS", "ILL", "IP ADDR"); 1371*5940Ssowmini } 1372*5940Ssowmini } 1373*5940Ssowmini 1374*5940Ssowmini int 1375*5940Ssowmini nce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1376*5940Ssowmini { 1377*5940Ssowmini nce_t nce; 1378*5940Ssowmini nce_cbdata_t id; 1379*5940Ssowmini int ipversion = 0; 1380*5940Ssowmini const char *opt_P = NULL; 1381*5940Ssowmini 1382*5940Ssowmini if (mdb_getopts(argc, argv, 1383*5940Ssowmini 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 1384*5940Ssowmini return (DCMD_USAGE); 1385*5940Ssowmini 1386*5940Ssowmini if (opt_P != NULL) { 1387*5940Ssowmini if (strcmp("v4", opt_P) == 0) { 1388*5940Ssowmini ipversion = IPV4_VERSION; 1389*5940Ssowmini } else if (strcmp("v6", opt_P) == 0) { 1390*5940Ssowmini ipversion = IPV6_VERSION; 1391*5940Ssowmini } else { 1392*5940Ssowmini mdb_warn("invalid protocol '%s'\n", opt_P); 1393*5940Ssowmini return (DCMD_USAGE); 1394*5940Ssowmini } 1395*5940Ssowmini } 1396*5940Ssowmini 1397*5940Ssowmini if (flags & DCMD_ADDRSPEC) { 1398*5940Ssowmini 1399*5940Ssowmini if (mdb_vread(&nce, sizeof (nce_t), addr) == -1) { 1400*5940Ssowmini mdb_warn("failed to read nce at %p\n", addr); 1401*5940Ssowmini return (DCMD_ERR); 1402*5940Ssowmini } 1403*5940Ssowmini if (ipversion != 0 && nce.nce_ipversion != ipversion) { 1404*5940Ssowmini mdb_printf("IP Version mismatch\n"); 1405*5940Ssowmini return (DCMD_ERR); 1406*5940Ssowmini } 1407*5940Ssowmini nce_header(flags); 1408*5940Ssowmini return (nce_format(addr, &nce, ipversion)); 1409*5940Ssowmini 1410*5940Ssowmini } else { 1411*5940Ssowmini id.nce_addr = addr; 1412*5940Ssowmini id.nce_ipversion = ipversion; 1413*5940Ssowmini nce_header(flags); 1414*5940Ssowmini if (mdb_walk("nce", (mdb_walk_cb_t)nce_cb, &id) == -1) { 1415*5940Ssowmini mdb_warn("failed to walk nce table\n"); 1416*5940Ssowmini return (DCMD_ERR); 1417*5940Ssowmini } 1418*5940Ssowmini } 1419*5940Ssowmini return (DCMD_OK); 1420*5940Ssowmini } 1421*5940Ssowmini 1422*5940Ssowmini static int 1423*5940Ssowmini nce_format(uintptr_t addr, const nce_t *nce, int ipversion) 1424*5940Ssowmini { 1425*5940Ssowmini static const mdb_bitmask_t nce_flags[] = { 1426*5940Ssowmini { "P", NCE_F_PERMANENT, NCE_F_PERMANENT }, 1427*5940Ssowmini { "R", NCE_F_ISROUTER, NCE_F_ISROUTER }, 1428*5940Ssowmini { "N", NCE_F_NONUD, NCE_F_NONUD }, 1429*5940Ssowmini { "A", NCE_F_ANYCAST, NCE_F_ANYCAST }, 1430*5940Ssowmini { "C", NCE_F_CONDEMNED, NCE_F_CONDEMNED }, 1431*5940Ssowmini { "U", NCE_F_UNSOL_ADV, NCE_F_UNSOL_ADV }, 1432*5940Ssowmini { "B", NCE_F_BCAST, NCE_F_BCAST }, 1433*5940Ssowmini { NULL, 0, 0 } 1434*5940Ssowmini }; 1435*5940Ssowmini #define NCE_MAX_FLAGS (sizeof (nce_flags) / sizeof (mdb_bitmask_t)) 1436*5940Ssowmini struct in_addr nceaddr; 1437*5940Ssowmini ill_t ill; 1438*5940Ssowmini char ill_name[LIFNAMSIZ]; 1439*5940Ssowmini char flagsbuf[NCE_MAX_FLAGS]; 1440*5940Ssowmini 1441*5940Ssowmini if (mdb_vread(&ill, sizeof (ill), (uintptr_t)nce->nce_ill) == -1) { 1442*5940Ssowmini mdb_warn("failed to read nce_ill at %p", 1443*5940Ssowmini nce->nce_ill); 1444*5940Ssowmini return (DCMD_ERR); 1445*5940Ssowmini } 1446*5940Ssowmini 1447*5940Ssowmini (void) mdb_readstr(ill_name, MIN(LIFNAMSIZ, ill.ill_name_length), 1448*5940Ssowmini (uintptr_t)ill.ill_name); 1449*5940Ssowmini 1450*5940Ssowmini mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%hb", 1451*5940Ssowmini nce->nce_flags, nce_flags); 1452*5940Ssowmini 1453*5940Ssowmini if (ipversion != 0 && nce->nce_ipversion != ipversion) 1454*5940Ssowmini return (DCMD_OK); 1455*5940Ssowmini 1456*5940Ssowmini if (nce->nce_ipversion == IPV4_VERSION) { 1457*5940Ssowmini IN6_V4MAPPED_TO_INADDR(&nce->nce_addr, &nceaddr); 1458*5940Ssowmini mdb_printf("%?p %-20s %-10s " 1459*5940Ssowmini "%-8s " 1460*5940Ssowmini "%-5s %I\n", 1461*5940Ssowmini addr, nce_l2_addr(nce, &ill), 1462*5940Ssowmini nce_state(nce->nce_state), 1463*5940Ssowmini flagsbuf, 1464*5940Ssowmini ill_name, nceaddr.s_addr); 1465*5940Ssowmini } else { 1466*5940Ssowmini mdb_printf("%?p %-20s %-10s %-8s %-5s %N\n", 1467*5940Ssowmini addr, nce_l2_addr(nce, &ill), 1468*5940Ssowmini nce_state(nce->nce_state), 1469*5940Ssowmini flagsbuf, 1470*5940Ssowmini ill_name, &nce->nce_addr); 1471*5940Ssowmini } 1472*5940Ssowmini 1473*5940Ssowmini return (DCMD_OK); 1474*5940Ssowmini } 1475*5940Ssowmini 1476*5940Ssowmini static uintptr_t 1477*5940Ssowmini nce_get_next_hash_tbl(uintptr_t start, int *index, struct ndp_g_s ndp) 1478*5940Ssowmini { 1479*5940Ssowmini uintptr_t addr = start; 1480*5940Ssowmini int i = *index; 1481*5940Ssowmini 1482*5940Ssowmini while (addr == NULL) { 1483*5940Ssowmini 1484*5940Ssowmini if (++i >= NCE_TABLE_SIZE) 1485*5940Ssowmini break; 1486*5940Ssowmini addr = (uintptr_t)ndp.nce_hash_tbl[i]; 1487*5940Ssowmini } 1488*5940Ssowmini *index = i; 1489*5940Ssowmini return (addr); 1490*5940Ssowmini } 1491*5940Ssowmini 1492*5940Ssowmini static int 1493*5940Ssowmini nce_walk_step(mdb_walk_state_t *wsp) 1494*5940Ssowmini { 1495*5940Ssowmini uintptr_t kaddr4, kaddr6; 1496*5940Ssowmini 1497*5940Ssowmini kaddr4 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp4); 1498*5940Ssowmini kaddr6 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp6); 1499*5940Ssowmini 1500*5940Ssowmini if (mdb_vread(&kaddr4, sizeof (kaddr4), kaddr4) == -1) { 1501*5940Ssowmini mdb_warn("can't read ips_ip_cache_table at %p", kaddr4); 1502*5940Ssowmini return (WALK_ERR); 1503*5940Ssowmini } 1504*5940Ssowmini if (mdb_vread(&kaddr6, sizeof (kaddr6), kaddr6) == -1) { 1505*5940Ssowmini mdb_warn("can't read ips_ip_cache_table at %p", kaddr6); 1506*5940Ssowmini return (WALK_ERR); 1507*5940Ssowmini } 1508*5940Ssowmini if (mdb_pwalk("nce_stack", wsp->walk_callback, wsp->walk_cbdata, 1509*5940Ssowmini kaddr4) == -1) { 1510*5940Ssowmini mdb_warn("couldn't walk 'nce_stack' for ips_ndp4 %p", 1511*5940Ssowmini kaddr4); 1512*5940Ssowmini return (WALK_ERR); 1513*5940Ssowmini } 1514*5940Ssowmini if (mdb_pwalk("nce_stack", wsp->walk_callback, 1515*5940Ssowmini wsp->walk_cbdata, kaddr6) == -1) { 1516*5940Ssowmini mdb_warn("couldn't walk 'nce_stack' for ips_ndp6 %p", 1517*5940Ssowmini kaddr6); 1518*5940Ssowmini return (WALK_ERR); 1519*5940Ssowmini } 1520*5940Ssowmini return (WALK_NEXT); 1521*5940Ssowmini } 1522*5940Ssowmini 1523*5940Ssowmini /* 1524*5940Ssowmini * Called with walk_addr being the address of ips_ndp{4,6} 1525*5940Ssowmini */ 1526*5940Ssowmini static int 1527*5940Ssowmini nce_stack_walk_init(mdb_walk_state_t *wsp) 1528*5940Ssowmini { 1529*5940Ssowmini nce_walk_data_t *nw; 1530*5940Ssowmini 1531*5940Ssowmini if (wsp->walk_addr == NULL) { 1532*5940Ssowmini mdb_warn("nce_stack requires ndp_g_s address\n"); 1533*5940Ssowmini return (WALK_ERR); 1534*5940Ssowmini } 1535*5940Ssowmini 1536*5940Ssowmini nw = mdb_alloc(sizeof (nce_walk_data_t), UM_SLEEP); 1537*5940Ssowmini 1538*5940Ssowmini if (mdb_vread(&nw->nce_ip_ndp, sizeof (struct ndp_g_s), 1539*5940Ssowmini wsp->walk_addr) == -1) { 1540*5940Ssowmini mdb_warn("failed to read 'ip_ndp' at %p", 1541*5940Ssowmini wsp->walk_addr); 1542*5940Ssowmini mdb_free(nw, sizeof (nce_walk_data_t)); 1543*5940Ssowmini return (WALK_ERR); 1544*5940Ssowmini } 1545*5940Ssowmini 1546*5940Ssowmini nw->nce_hash_tbl_index = 0; 1547*5940Ssowmini wsp->walk_addr = nce_get_next_hash_tbl(NULL, 1548*5940Ssowmini &nw->nce_hash_tbl_index, nw->nce_ip_ndp); 1549*5940Ssowmini wsp->walk_data = nw; 1550*5940Ssowmini 1551*5940Ssowmini return (WALK_NEXT); 1552*5940Ssowmini } 1553*5940Ssowmini 1554*5940Ssowmini static int 1555*5940Ssowmini nce_stack_walk_step(mdb_walk_state_t *wsp) 1556*5940Ssowmini { 1557*5940Ssowmini uintptr_t addr = wsp->walk_addr; 1558*5940Ssowmini nce_walk_data_t *nw = wsp->walk_data; 1559*5940Ssowmini 1560*5940Ssowmini if (addr == NULL) 1561*5940Ssowmini return (WALK_DONE); 1562*5940Ssowmini 1563*5940Ssowmini if (mdb_vread(&nw->nce, sizeof (nce_t), addr) == -1) { 1564*5940Ssowmini mdb_warn("failed to read nce_t at %p", addr); 1565*5940Ssowmini return (WALK_ERR); 1566*5940Ssowmini } 1567*5940Ssowmini 1568*5940Ssowmini wsp->walk_addr = (uintptr_t)nw->nce.nce_next; 1569*5940Ssowmini 1570*5940Ssowmini wsp->walk_addr = nce_get_next_hash_tbl(wsp->walk_addr, 1571*5940Ssowmini &nw->nce_hash_tbl_index, nw->nce_ip_ndp); 1572*5940Ssowmini 1573*5940Ssowmini return (wsp->walk_callback(addr, nw, wsp->walk_cbdata)); 1574*5940Ssowmini } 1575*5940Ssowmini 1576*5940Ssowmini static void 1577*5940Ssowmini nce_stack_walk_fini(mdb_walk_state_t *wsp) 1578*5940Ssowmini { 1579*5940Ssowmini mdb_free(wsp->walk_data, sizeof (nce_walk_data_t)); 1580*5940Ssowmini } 1581*5940Ssowmini 1582*5940Ssowmini /* ARGSUSED */ 1583*5940Ssowmini static int 1584*5940Ssowmini nce_cb(uintptr_t addr, const nce_walk_data_t *iw, nce_cbdata_t *id) 1585*5940Ssowmini { 1586*5940Ssowmini nce_t nce; 1587*5940Ssowmini 1588*5940Ssowmini if (mdb_vread(&nce, sizeof (nce_t), addr) == -1) { 1589*5940Ssowmini mdb_warn("failed to read nce at %p", addr); 1590*5940Ssowmini return (WALK_NEXT); 1591*5940Ssowmini } 1592*5940Ssowmini (void) nce_format(addr, &nce, id->nce_ipversion); 1593*5940Ssowmini return (WALK_NEXT); 1594*5940Ssowmini } 1595