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