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