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