xref: /illumos-gate/usr/src/cmd/mdb/common/modules/ip/ip.c (revision d3d50737e566cade9a08d73d2af95105ac7cd960)
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