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