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