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