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