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