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