Merge commit 'b4bf0cf0458759c67920a031021a9d96cd683cfe'
[unleashed.git] / usr / src / cmd / mdb / common / modules / ip / ip.c
blobf5ec1b6123fd1b63b4d7d7d634cb33ca332324f6
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
26 #include <sys/types.h>
27 #include <sys/stropts.h>
28 #include <sys/stream.h>
29 #include <sys/socket.h>
30 #include <sys/avl_impl.h>
31 #include <net/if_types.h>
32 #include <net/if.h>
33 #include <net/route.h>
34 #include <netinet/in.h>
35 #include <netinet/ip6.h>
36 #include <netinet/udp.h>
37 #include <netinet/sctp.h>
38 #include <inet/mib2.h>
39 #include <inet/common.h>
40 #include <inet/ip.h>
41 #include <inet/ip_ire.h>
42 #include <inet/ip6.h>
43 #include <inet/ipclassifier.h>
44 #include <inet/mi.h>
45 #include <sys/squeue_impl.h>
46 #include <sys/modhash_impl.h>
47 #include <inet/ip_ndp.h>
48 #include <inet/ip_if.h>
49 #include <ilb.h>
50 #include <ilb/ilb_impl.h>
51 #include <ilb/ilb_stack.h>
52 #include <ilb/ilb_nat.h>
53 #include <ilb/ilb_conn.h>
54 #include <sys/dlpi.h>
55 #include <sys/zone.h>
57 #include <mdb/mdb_modapi.h>
58 #include <mdb/mdb_ks.h>
60 #define ADDR_WIDTH 11
61 #define L2MAXADDRSTRLEN 255
62 #define MAX_SAP_LEN 255
63 #define DEFCOLS 80
65 typedef struct {
66 const char *bit_name; /* name of bit */
67 const char *bit_descr; /* description of bit's purpose */
68 } bitname_t;
70 static const bitname_t squeue_states[] = {
71 { "SQS_PROC", "being processed" },
72 { "SQS_WORKER", "... by a worker thread" },
73 { "SQS_ENTER", "... by an squeue_enter() thread" },
74 { "SQS_FAST", "... in fast-path mode" },
75 { "SQS_USER", "A non interrupt user" },
76 { "SQS_BOUND", "worker thread bound to CPU" },
77 { "SQS_PROFILE", "profiling enabled" },
78 { "SQS_REENTER", "re-entered thred" },
79 { NULL }
82 typedef struct illif_walk_data {
83 ill_g_head_t ill_g_heads[MAX_G_HEADS];
84 int ill_list;
85 ill_if_t ill_if;
86 } illif_walk_data_t;
88 typedef struct ncec_walk_data_s {
89 struct ndp_g_s ncec_ip_ndp;
90 int ncec_hash_tbl_index;
91 ncec_t ncec;
92 } ncec_walk_data_t;
94 typedef struct ncec_cbdata_s {
95 uintptr_t ncec_addr;
96 int ncec_ipversion;
97 } ncec_cbdata_t;
99 typedef struct nce_cbdata_s {
100 int nce_ipversion;
101 char nce_ill_name[LIFNAMSIZ];
102 } nce_cbdata_t;
104 typedef struct ire_cbdata_s {
105 int ire_ipversion;
106 boolean_t verbose;
107 } ire_cbdata_t;
109 typedef struct zi_cbdata_s {
110 const char *zone_name;
111 ip_stack_t *ipst;
112 boolean_t shared_ip_zone;
113 } zi_cbdata_t;
115 typedef struct th_walk_data {
116 uint_t thw_non_zero_only;
117 boolean_t thw_match;
118 uintptr_t thw_matchkey;
119 uintptr_t thw_ipst;
120 clock_t thw_lbolt;
121 } th_walk_data_t;
123 typedef struct ipcl_hash_walk_data_s {
124 conn_t *conn;
125 int connf_tbl_index;
126 uintptr_t hash_tbl;
127 int hash_tbl_size;
128 } ipcl_hash_walk_data_t;
130 typedef struct ill_walk_data_s {
131 ill_t ill;
132 } ill_walk_data_t;
134 typedef struct ill_cbdata_s {
135 uintptr_t ill_addr;
136 int ill_ipversion;
137 ip_stack_t *ill_ipst;
138 boolean_t verbose;
139 } ill_cbdata_t;
141 typedef struct ipif_walk_data_s {
142 ipif_t ipif;
143 } ipif_walk_data_t;
145 typedef struct ipif_cbdata_s {
146 ill_t ill;
147 int ipif_ipversion;
148 boolean_t verbose;
149 } ipif_cbdata_t;
151 typedef struct hash_walk_arg_s {
152 off_t tbl_off;
153 off_t size_off;
154 } hash_walk_arg_t;
156 static hash_walk_arg_t udp_hash_arg = {
157 OFFSETOF(ip_stack_t, ips_ipcl_udp_fanout),
158 OFFSETOF(ip_stack_t, ips_ipcl_udp_fanout_size)
161 static hash_walk_arg_t conn_hash_arg = {
162 OFFSETOF(ip_stack_t, ips_ipcl_conn_fanout),
163 OFFSETOF(ip_stack_t, ips_ipcl_conn_fanout_size)
166 static hash_walk_arg_t bind_hash_arg = {
167 OFFSETOF(ip_stack_t, ips_ipcl_bind_fanout),
168 OFFSETOF(ip_stack_t, ips_ipcl_bind_fanout_size)
171 static hash_walk_arg_t proto_hash_arg = {
172 OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v4),
176 static hash_walk_arg_t proto_v6_hash_arg = {
177 OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v6),
181 typedef struct ip_list_walk_data_s {
182 off_t nextoff;
183 } ip_list_walk_data_t;
185 typedef struct ip_list_walk_arg_s {
186 off_t off;
187 size_t size;
188 off_t nextp_off;
189 } ip_list_walk_arg_t;
191 static ip_list_walk_arg_t ipif_walk_arg = {
192 OFFSETOF(ill_t, ill_ipif),
193 sizeof (ipif_t),
194 OFFSETOF(ipif_t, ipif_next)
197 static ip_list_walk_arg_t srcid_walk_arg = {
198 OFFSETOF(ip_stack_t, ips_srcid_head),
199 sizeof (srcid_map_t),
200 OFFSETOF(srcid_map_t, sm_next)
203 static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *);
204 static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *);
206 static int ill(uintptr_t, uint_t, int, const mdb_arg_t *);
207 static void ill_help(void);
208 static int ill_walk_init(mdb_walk_state_t *);
209 static int ill_walk_step(mdb_walk_state_t *);
210 static int ill_format(uintptr_t, const void *, void *);
211 static void ill_header(boolean_t);
213 static int ipif(uintptr_t, uint_t, int, const mdb_arg_t *);
214 static void ipif_help(void);
215 static int ipif_walk_init(mdb_walk_state_t *);
216 static int ipif_walk_step(mdb_walk_state_t *);
217 static int ipif_format(uintptr_t, const void *, void *);
218 static void ipif_header(boolean_t);
220 static int ip_list_walk_init(mdb_walk_state_t *);
221 static int ip_list_walk_step(mdb_walk_state_t *);
222 static void ip_list_walk_fini(mdb_walk_state_t *);
223 static int srcid_walk_step(mdb_walk_state_t *);
225 static int ire_format(uintptr_t addr, const void *, void *);
226 static int ncec_format(uintptr_t addr, const ncec_t *ncec, int ipversion);
227 static int ncec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv);
228 static int ncec_walk_step(mdb_walk_state_t *wsp);
229 static int ncec_stack_walk_init(mdb_walk_state_t *wsp);
230 static int ncec_stack_walk_step(mdb_walk_state_t *wsp);
231 static void ncec_stack_walk_fini(mdb_walk_state_t *wsp);
232 static int ncec_cb(uintptr_t addr, const ncec_walk_data_t *iw,
233 ncec_cbdata_t *id);
234 static char *nce_l2_addr(const nce_t *, const ill_t *);
236 static int ipcl_hash_walk_init(mdb_walk_state_t *);
237 static int ipcl_hash_walk_step(mdb_walk_state_t *);
238 static void ipcl_hash_walk_fini(mdb_walk_state_t *);
240 static int conn_status_walk_step(mdb_walk_state_t *);
241 static int conn_status(uintptr_t, uint_t, int, const mdb_arg_t *);
242 static void conn_status_help(void);
244 static int srcid_status(uintptr_t, uint_t, int, const mdb_arg_t *);
246 static int ilb_stacks_walk_step(mdb_walk_state_t *);
247 static int ilb_rules_walk_init(mdb_walk_state_t *);
248 static int ilb_rules_walk_step(mdb_walk_state_t *);
249 static int ilb_servers_walk_init(mdb_walk_state_t *);
250 static int ilb_servers_walk_step(mdb_walk_state_t *);
251 static int ilb_nat_src_walk_init(mdb_walk_state_t *);
252 static int ilb_nat_src_walk_step(mdb_walk_state_t *);
253 static int ilb_conn_walk_init(mdb_walk_state_t *);
254 static int ilb_conn_walk_step(mdb_walk_state_t *);
255 static int ilb_sticky_walk_init(mdb_walk_state_t *);
256 static int ilb_sticky_walk_step(mdb_walk_state_t *);
257 static void ilb_common_walk_fini(mdb_walk_state_t *);
260 * Given the kernel address of an ip_stack_t, return the stackid
262 static int
263 ips_to_stackid(uintptr_t kaddr)
265 ip_stack_t ipss;
266 netstack_t nss;
268 if (mdb_vread(&ipss, sizeof (ipss), kaddr) == -1) {
269 mdb_warn("failed to read ip_stack_t %p", kaddr);
270 return (0);
272 kaddr = (uintptr_t)ipss.ips_netstack;
273 if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
274 mdb_warn("failed to read netstack_t %p", kaddr);
275 return (0);
277 return (nss.netstack_stackid);
280 /* ARGSUSED */
281 static int
282 zone_to_ips_cb(uintptr_t addr, const void *zi_arg, void *zi_cb_arg)
284 zi_cbdata_t *zi_cb = zi_cb_arg;
285 zone_t zone;
286 char zone_name[ZONENAME_MAX];
287 netstack_t ns;
289 if (mdb_vread(&zone, sizeof (zone_t), addr) == -1) {
290 mdb_warn("can't read zone at %p", addr);
291 return (WALK_ERR);
294 (void) mdb_readstr(zone_name, ZONENAME_MAX, (uintptr_t)zone.zone_name);
296 if (strcmp(zi_cb->zone_name, zone_name) != 0)
297 return (WALK_NEXT);
299 zi_cb->shared_ip_zone = (!(zone.zone_flags & ZF_NET_EXCL) &&
300 (strcmp(zone_name, "global") != 0));
302 if (mdb_vread(&ns, sizeof (netstack_t), (uintptr_t)zone.zone_netstack)
303 == -1) {
304 mdb_warn("can't read netstack at %p", zone.zone_netstack);
305 return (WALK_ERR);
308 zi_cb->ipst = ns.netstack_ip;
309 return (WALK_DONE);
312 static ip_stack_t *
313 zone_to_ips(const char *zone_name)
315 zi_cbdata_t zi_cb;
317 if (zone_name == NULL)
318 return (NULL);
320 zi_cb.zone_name = zone_name;
321 zi_cb.ipst = NULL;
322 zi_cb.shared_ip_zone = B_FALSE;
324 if (mdb_walk("zone", (mdb_walk_cb_t)zone_to_ips_cb, &zi_cb) == -1) {
325 mdb_warn("failed to walk zone");
326 return (NULL);
329 if (zi_cb.shared_ip_zone) {
330 mdb_warn("%s is a Shared-IP zone, try '-s global' instead\n",
331 zone_name);
332 return (NULL);
335 if (zi_cb.ipst == NULL) {
336 mdb_warn("failed to find zone %s\n", zone_name);
337 return (NULL);
340 return (zi_cb.ipst);
344 * Generic network stack walker initialization function. It is used by all
345 * other netwrok stack walkers.
348 ns_walk_init(mdb_walk_state_t *wsp)
350 if (mdb_layered_walk("netstack", wsp) == -1) {
351 mdb_warn("can't walk 'netstack'");
352 return (WALK_ERR);
354 return (WALK_NEXT);
358 * Generic network stack walker stepping function. It is used by all other
359 * network stack walkers. The which parameter differentiates the different
360 * walkers.
363 ns_walk_step(mdb_walk_state_t *wsp, int which)
365 uintptr_t kaddr;
366 netstack_t nss;
368 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
369 mdb_warn("can't read netstack at %p", wsp->walk_addr);
370 return (WALK_ERR);
372 kaddr = (uintptr_t)nss.netstack_modules[which];
374 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
378 * IP network stack walker stepping function.
381 ip_stacks_walk_step(mdb_walk_state_t *wsp)
383 return (ns_walk_step(wsp, NS_IP));
387 * TCP network stack walker stepping function.
390 tcp_stacks_walk_step(mdb_walk_state_t *wsp)
392 return (ns_walk_step(wsp, NS_TCP));
396 * SCTP network stack walker stepping function.
399 sctp_stacks_walk_step(mdb_walk_state_t *wsp)
401 return (ns_walk_step(wsp, NS_SCTP));
405 * UDP network stack walker stepping function.
408 udp_stacks_walk_step(mdb_walk_state_t *wsp)
410 return (ns_walk_step(wsp, NS_UDP));
414 * Initialization function for the per CPU TCP stats counter walker of a given
415 * TCP stack.
418 tcps_sc_walk_init(mdb_walk_state_t *wsp)
420 tcp_stack_t tcps;
422 if (wsp->walk_addr == (uintptr_t)NULL)
423 return (WALK_ERR);
425 if (mdb_vread(&tcps, sizeof (tcps), wsp->walk_addr) == -1) {
426 mdb_warn("failed to read tcp_stack_t at %p", wsp->walk_addr);
427 return (WALK_ERR);
429 if (tcps.tcps_sc_cnt == 0)
430 return (WALK_DONE);
433 * Store the tcp_stack_t pointer in walk_data. The stepping function
434 * used it to calculate if the end of the counter has reached.
436 wsp->walk_data = (void *)wsp->walk_addr;
437 wsp->walk_addr = (uintptr_t)tcps.tcps_sc;
438 return (WALK_NEXT);
442 * Stepping function for the per CPU TCP stats counterwalker.
445 tcps_sc_walk_step(mdb_walk_state_t *wsp)
447 int status;
448 tcp_stack_t tcps;
449 tcp_stats_cpu_t *stats;
450 char *next, *end;
452 if (mdb_vread(&tcps, sizeof (tcps), (uintptr_t)wsp->walk_data) == -1) {
453 mdb_warn("failed to read tcp_stack_t at %p", wsp->walk_addr);
454 return (WALK_ERR);
456 if (mdb_vread(&stats, sizeof (stats), wsp->walk_addr) == -1) {
457 mdb_warn("failed ot read tcp_stats_cpu_t at %p",
458 wsp->walk_addr);
459 return (WALK_ERR);
461 status = wsp->walk_callback((uintptr_t)stats, &stats, wsp->walk_cbdata);
462 if (status != WALK_NEXT)
463 return (status);
465 next = (char *)wsp->walk_addr + sizeof (tcp_stats_cpu_t *);
466 end = (char *)tcps.tcps_sc + tcps.tcps_sc_cnt *
467 sizeof (tcp_stats_cpu_t *);
468 if (next >= end)
469 return (WALK_DONE);
470 wsp->walk_addr = (uintptr_t)next;
471 return (WALK_NEXT);
475 th_hash_walk_init(mdb_walk_state_t *wsp)
477 GElf_Sym sym;
478 list_node_t *next;
480 if (wsp->walk_addr == (uintptr_t)NULL) {
481 if (mdb_lookup_by_obj("ip", "ip_thread_list", &sym) == 0) {
482 wsp->walk_addr = sym.st_value;
483 } else {
484 mdb_warn("unable to locate ip_thread_list\n");
485 return (WALK_ERR);
489 if (mdb_vread(&next, sizeof (next),
490 wsp->walk_addr + offsetof(list_t, list_head) +
491 offsetof(list_node_t, list_next)) == -1 ||
492 next == NULL) {
493 mdb_warn("non-DEBUG image; cannot walk th_hash list\n");
494 return (WALK_ERR);
497 if (mdb_layered_walk("list", wsp) == -1) {
498 mdb_warn("can't walk 'list'");
499 return (WALK_ERR);
500 } else {
501 return (WALK_NEXT);
506 th_hash_walk_step(mdb_walk_state_t *wsp)
508 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
509 wsp->walk_cbdata));
513 * Called with walk_addr being the address of ips_ill_g_heads
516 illif_stack_walk_init(mdb_walk_state_t *wsp)
518 illif_walk_data_t *iw;
520 if (wsp->walk_addr == (uintptr_t)NULL) {
521 mdb_warn("illif_stack supports only local walks\n");
522 return (WALK_ERR);
525 iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP);
527 if (mdb_vread(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t),
528 wsp->walk_addr) == -1) {
529 mdb_warn("failed to read 'ips_ill_g_heads' at %p",
530 wsp->walk_addr);
531 mdb_free(iw, sizeof (illif_walk_data_t));
532 return (WALK_ERR);
535 iw->ill_list = 0;
536 wsp->walk_addr = (uintptr_t)iw->ill_g_heads[0].ill_g_list_head;
537 wsp->walk_data = iw;
539 return (WALK_NEXT);
543 illif_stack_walk_step(mdb_walk_state_t *wsp)
545 uintptr_t addr = wsp->walk_addr;
546 illif_walk_data_t *iw = wsp->walk_data;
547 int list = iw->ill_list;
549 if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) {
550 mdb_warn("failed to read ill_if_t at %p", addr);
551 return (WALK_ERR);
554 wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next;
556 if (wsp->walk_addr ==
557 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head) {
559 if (++list >= MAX_G_HEADS)
560 return (WALK_DONE);
562 iw->ill_list = list;
563 wsp->walk_addr =
564 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head;
565 return (WALK_NEXT);
568 return (wsp->walk_callback(addr, iw, wsp->walk_cbdata));
571 void
572 illif_stack_walk_fini(mdb_walk_state_t *wsp)
574 mdb_free(wsp->walk_data, sizeof (illif_walk_data_t));
577 typedef struct illif_cbdata {
578 uint_t ill_flags;
579 uintptr_t ill_addr;
580 int ill_printlist; /* list to be printed (MAX_G_HEADS for all) */
581 boolean_t ill_printed;
582 } illif_cbdata_t;
584 static int
585 illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id)
587 const char *version;
589 if (id->ill_printlist < MAX_G_HEADS &&
590 id->ill_printlist != iw->ill_list)
591 return (WALK_NEXT);
593 if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr)
594 return (WALK_NEXT);
596 if (id->ill_flags & DCMD_PIPE_OUT) {
597 mdb_printf("%p\n", addr);
598 return (WALK_NEXT);
601 switch (iw->ill_list) {
602 case IP_V4_G_HEAD: version = "v4"; break;
603 case IP_V6_G_HEAD: version = "v6"; break;
604 default: version = "??"; break;
607 mdb_printf("%?p %2s %?p %10d %?p %s\n",
608 addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa),
609 iw->ill_if.illif_avl_by_ppa.avl_numnodes,
610 iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name);
612 id->ill_printed = TRUE;
614 return (WALK_NEXT);
618 ip_stacks_common_walk_init(mdb_walk_state_t *wsp)
620 if (mdb_layered_walk("ip_stacks", wsp) == -1) {
621 mdb_warn("can't walk 'ip_stacks'");
622 return (WALK_ERR);
625 return (WALK_NEXT);
629 illif_walk_step(mdb_walk_state_t *wsp)
631 uintptr_t kaddr;
633 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ill_g_heads);
635 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
636 mdb_warn("can't read ips_ip_cache_table at %p", kaddr);
637 return (WALK_ERR);
640 if (mdb_pwalk("illif_stack", wsp->walk_callback,
641 wsp->walk_cbdata, kaddr) == -1) {
642 mdb_warn("couldn't walk 'illif_stack' for ips_ill_g_heads %p",
643 kaddr);
644 return (WALK_ERR);
646 return (WALK_NEXT);
650 illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
652 illif_cbdata_t id;
653 ill_if_t ill_if;
654 const char *opt_P = NULL;
655 int printlist = MAX_G_HEADS;
657 if (mdb_getopts(argc, argv,
658 'P', MDB_OPT_STR, &opt_P, NULL) != argc)
659 return (DCMD_USAGE);
661 if (opt_P != NULL) {
662 if (strcmp("v4", opt_P) == 0) {
663 printlist = IP_V4_G_HEAD;
664 } else if (strcmp("v6", opt_P) == 0) {
665 printlist = IP_V6_G_HEAD;
666 } else {
667 mdb_warn("invalid protocol '%s'\n", opt_P);
668 return (DCMD_USAGE);
672 if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
673 mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n",
674 "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME");
677 id.ill_flags = flags;
678 id.ill_addr = addr;
679 id.ill_printlist = printlist;
680 id.ill_printed = FALSE;
682 if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) {
683 mdb_warn("can't walk ill_if_t structures");
684 return (DCMD_ERR);
687 if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed)
688 return (DCMD_OK);
691 * If an address is specified and the walk doesn't find it,
692 * print it anyway.
694 if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) {
695 mdb_warn("failed to read ill_if_t at %p", addr);
696 return (DCMD_ERR);
699 mdb_printf("%?p %2s %?p %10d %?p %s\n",
700 addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa),
701 ill_if.illif_avl_by_ppa.avl_numnodes,
702 ill_if.illif_ppa_arena, ill_if.illif_name);
704 return (DCMD_OK);
707 static void
708 illif_help(void)
710 mdb_printf("Options:\n");
711 mdb_printf("\t-P v4 | v6"
712 "\tfilter interface structures for the specified protocol\n");
716 nce_walk_init(mdb_walk_state_t *wsp)
718 if (mdb_layered_walk("nce_cache", wsp) == -1) {
719 mdb_warn("can't walk 'nce_cache'");
720 return (WALK_ERR);
723 return (WALK_NEXT);
727 nce_walk_step(mdb_walk_state_t *wsp)
729 nce_t nce;
731 if (mdb_vread(&nce, sizeof (nce), wsp->walk_addr) == -1) {
732 mdb_warn("can't read nce at %p", wsp->walk_addr);
733 return (WALK_ERR);
736 return (wsp->walk_callback(wsp->walk_addr, &nce, wsp->walk_cbdata));
739 static int
740 nce_format(uintptr_t addr, const nce_t *ncep, void *nce_cb_arg)
742 nce_cbdata_t *nce_cb = nce_cb_arg;
743 ill_t ill;
744 char ill_name[LIFNAMSIZ];
745 ncec_t ncec;
747 if (mdb_vread(&ncec, sizeof (ncec),
748 (uintptr_t)ncep->nce_common) == -1) {
749 mdb_warn("can't read ncec at %p", ncep->nce_common);
750 return (WALK_NEXT);
752 if (nce_cb->nce_ipversion != 0 &&
753 ncec.ncec_ipversion != nce_cb->nce_ipversion)
754 return (WALK_NEXT);
756 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ncep->nce_ill) == -1) {
757 mdb_snprintf(ill_name, sizeof (ill_name), "--");
758 } else {
759 (void) mdb_readstr(ill_name,
760 MIN(LIFNAMSIZ, ill.ill_name_length),
761 (uintptr_t)ill.ill_name);
764 if (nce_cb->nce_ill_name[0] != '\0' &&
765 strncmp(nce_cb->nce_ill_name, ill_name, LIFNAMSIZ) != 0)
766 return (WALK_NEXT);
768 if (ncec.ncec_ipversion == IPV6_VERSION) {
770 mdb_printf("%?p %5s %-18s %?p %6d %N\n",
771 addr, ill_name,
772 nce_l2_addr(ncep, &ill),
773 ncep->nce_fp_mp,
774 ncep->nce_refcnt,
775 &ncep->nce_addr);
777 } else {
778 struct in_addr nceaddr;
780 IN6_V4MAPPED_TO_INADDR(&ncep->nce_addr, &nceaddr);
781 mdb_printf("%?p %5s %-18s %?p %6d %I\n",
782 addr, ill_name,
783 nce_l2_addr(ncep, &ill),
784 ncep->nce_fp_mp,
785 ncep->nce_refcnt,
786 nceaddr.s_addr);
789 return (WALK_NEXT);
793 dce_walk_init(mdb_walk_state_t *wsp)
795 wsp->walk_data = (void *)wsp->walk_addr;
797 if (mdb_layered_walk("dce_cache", wsp) == -1) {
798 mdb_warn("can't walk 'dce_cache'");
799 return (WALK_ERR);
802 return (WALK_NEXT);
806 dce_walk_step(mdb_walk_state_t *wsp)
808 dce_t dce;
810 if (mdb_vread(&dce, sizeof (dce), wsp->walk_addr) == -1) {
811 mdb_warn("can't read dce at %p", wsp->walk_addr);
812 return (WALK_ERR);
815 /* If ip_stack_t is specified, skip DCEs that don't belong to it. */
816 if ((wsp->walk_data != NULL) && (wsp->walk_data != dce.dce_ipst))
817 return (WALK_NEXT);
819 return (wsp->walk_callback(wsp->walk_addr, &dce, wsp->walk_cbdata));
823 ire_walk_init(mdb_walk_state_t *wsp)
825 wsp->walk_data = (void *)wsp->walk_addr;
827 if (mdb_layered_walk("ire_cache", wsp) == -1) {
828 mdb_warn("can't walk 'ire_cache'");
829 return (WALK_ERR);
832 return (WALK_NEXT);
836 ire_walk_step(mdb_walk_state_t *wsp)
838 ire_t ire;
840 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) {
841 mdb_warn("can't read ire at %p", wsp->walk_addr);
842 return (WALK_ERR);
845 /* If ip_stack_t is specified, skip IREs that don't belong to it. */
846 if ((wsp->walk_data != NULL) && (wsp->walk_data != ire.ire_ipst))
847 return (WALK_NEXT);
849 return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata));
852 /* ARGSUSED */
854 ire_next_walk_init(mdb_walk_state_t *wsp)
856 return (WALK_NEXT);
860 ire_next_walk_step(mdb_walk_state_t *wsp)
862 ire_t ire;
863 int status;
866 if (wsp->walk_addr == (uintptr_t)NULL)
867 return (WALK_DONE);
869 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) {
870 mdb_warn("can't read ire at %p", wsp->walk_addr);
871 return (WALK_ERR);
873 status = wsp->walk_callback(wsp->walk_addr, &ire,
874 wsp->walk_cbdata);
876 if (status != WALK_NEXT)
877 return (status);
879 wsp->walk_addr = (uintptr_t)ire.ire_next;
880 return (status);
883 static int
884 ire_format(uintptr_t addr, const void *ire_arg, void *ire_cb_arg)
886 const ire_t *irep = ire_arg;
887 ire_cbdata_t *ire_cb = ire_cb_arg;
888 boolean_t verbose = ire_cb->verbose;
889 ill_t ill;
890 char ill_name[LIFNAMSIZ];
891 boolean_t condemned = irep->ire_generation == IRE_GENERATION_CONDEMNED;
893 static const mdb_bitmask_t tmasks[] = {
894 { "BROADCAST", IRE_BROADCAST, IRE_BROADCAST },
895 { "DEFAULT", IRE_DEFAULT, IRE_DEFAULT },
896 { "LOCAL", IRE_LOCAL, IRE_LOCAL },
897 { "LOOPBACK", IRE_LOOPBACK, IRE_LOOPBACK },
898 { "PREFIX", IRE_PREFIX, IRE_PREFIX },
899 { "MULTICAST", IRE_MULTICAST, IRE_MULTICAST },
900 { "NOROUTE", IRE_NOROUTE, IRE_NOROUTE },
901 { "IF_NORESOLVER", IRE_IF_NORESOLVER, IRE_IF_NORESOLVER },
902 { "IF_RESOLVER", IRE_IF_RESOLVER, IRE_IF_RESOLVER },
903 { "IF_CLONE", IRE_IF_CLONE, IRE_IF_CLONE },
904 { "HOST", IRE_HOST, IRE_HOST },
905 { NULL, 0, 0 }
908 static const mdb_bitmask_t fmasks[] = {
909 { "UP", RTF_UP, RTF_UP },
910 { "GATEWAY", RTF_GATEWAY, RTF_GATEWAY },
911 { "HOST", RTF_HOST, RTF_HOST },
912 { "REJECT", RTF_REJECT, RTF_REJECT },
913 { "DYNAMIC", RTF_DYNAMIC, RTF_DYNAMIC },
914 { "MODIFIED", RTF_MODIFIED, RTF_MODIFIED },
915 { "DONE", RTF_DONE, RTF_DONE },
916 { "MASK", RTF_MASK, RTF_MASK },
917 { "CLONING", RTF_CLONING, RTF_CLONING },
918 { "XRESOLVE", RTF_XRESOLVE, RTF_XRESOLVE },
919 { "LLINFO", RTF_LLINFO, RTF_LLINFO },
920 { "STATIC", RTF_STATIC, RTF_STATIC },
921 { "BLACKHOLE", RTF_BLACKHOLE, RTF_BLACKHOLE },
922 { "PRIVATE", RTF_PRIVATE, RTF_PRIVATE },
923 { "PROTO2", RTF_PROTO2, RTF_PROTO2 },
924 { "PROTO1", RTF_PROTO1, RTF_PROTO1 },
925 { "SETSRC", RTF_SETSRC, RTF_SETSRC },
926 { "INDIRECT", RTF_INDIRECT, RTF_INDIRECT },
927 { NULL, 0, 0 }
930 if (ire_cb->ire_ipversion != 0 &&
931 irep->ire_ipversion != ire_cb->ire_ipversion)
932 return (WALK_NEXT);
934 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)irep->ire_ill) == -1) {
935 mdb_snprintf(ill_name, sizeof (ill_name), "--");
936 } else {
937 (void) mdb_readstr(ill_name,
938 MIN(LIFNAMSIZ, ill.ill_name_length),
939 (uintptr_t)ill.ill_name);
942 if (irep->ire_ipversion == IPV6_VERSION && verbose) {
944 mdb_printf("%<b>%?p%</b>%3s %40N <%hb%s>\n"
945 "%?s %40N\n"
946 "%?s %40d %4d <%hb> %s\n",
947 addr, condemned ? "(C)" : "", &irep->ire_setsrc_addr_v6,
948 irep->ire_type, tmasks,
949 (irep->ire_testhidden ? ", HIDDEN" : ""),
950 "", &irep->ire_addr_v6,
951 "", ips_to_stackid((uintptr_t)irep->ire_ipst),
952 irep->ire_zoneid,
953 irep->ire_flags, fmasks, ill_name);
955 } else if (irep->ire_ipversion == IPV6_VERSION) {
957 mdb_printf("%?p%3s %30N %30N %5d %4d %s\n",
958 addr, condemned ? "(C)" : "", &irep->ire_setsrc_addr_v6,
959 &irep->ire_addr_v6,
960 ips_to_stackid((uintptr_t)irep->ire_ipst),
961 irep->ire_zoneid, ill_name);
963 } else if (verbose) {
965 mdb_printf("%<b>%?p%</b>%3s %40I <%hb%s>\n"
966 "%?s %40I\n"
967 "%?s %40d %4d <%hb> %s\n",
968 addr, condemned ? "(C)" : "", irep->ire_setsrc_addr,
969 irep->ire_type, tmasks,
970 (irep->ire_testhidden ? ", HIDDEN" : ""),
971 "", irep->ire_addr,
972 "", ips_to_stackid((uintptr_t)irep->ire_ipst),
973 irep->ire_zoneid, irep->ire_flags, fmasks, ill_name);
975 } else {
977 mdb_printf("%?p%3s %30I %30I %5d %4d %s\n", addr,
978 condemned ? "(C)" : "", irep->ire_setsrc_addr,
979 irep->ire_addr, ips_to_stackid((uintptr_t)irep->ire_ipst),
980 irep->ire_zoneid, ill_name);
983 return (WALK_NEXT);
987 * There are faster ways to do this. Given the interactive nature of this
988 * use I don't think its worth much effort.
990 static unsigned short
991 ipcksum(void *p, int len)
993 int32_t sum = 0;
995 while (len > 1) {
996 /* alignment */
997 sum += *(uint16_t *)p;
998 p = (char *)p + sizeof (uint16_t);
999 if (sum & 0x80000000)
1000 sum = (sum & 0xFFFF) + (sum >> 16);
1001 len -= 2;
1004 if (len)
1005 sum += (uint16_t)*(unsigned char *)p;
1007 while (sum >> 16)
1008 sum = (sum & 0xFFFF) + (sum >> 16);
1010 return (~sum);
1013 static const mdb_bitmask_t tcp_flags[] = {
1014 { "SYN", TH_SYN, TH_SYN },
1015 { "ACK", TH_ACK, TH_ACK },
1016 { "FIN", TH_FIN, TH_FIN },
1017 { "RST", TH_RST, TH_RST },
1018 { "PSH", TH_PUSH, TH_PUSH },
1019 { "ECE", TH_ECE, TH_ECE },
1020 { "CWR", TH_CWR, TH_CWR },
1021 { NULL, 0, 0 }
1024 /* TCP option length */
1025 #define TCPOPT_HEADER_LEN 2
1026 #define TCPOPT_MAXSEG_LEN 4
1027 #define TCPOPT_WS_LEN 3
1028 #define TCPOPT_TSTAMP_LEN 10
1029 #define TCPOPT_SACK_OK_LEN 2
1031 static void
1032 tcphdr_print_options(uint8_t *opts, uint32_t opts_len)
1034 uint8_t *endp;
1035 uint32_t len, val;
1037 mdb_printf("%<b>Options:%</b>");
1038 endp = opts + opts_len;
1039 while (opts < endp) {
1040 len = endp - opts;
1041 switch (*opts) {
1042 case TCPOPT_EOL:
1043 mdb_printf(" EOL");
1044 opts++;
1045 break;
1047 case TCPOPT_NOP:
1048 mdb_printf(" NOP");
1049 opts++;
1050 break;
1052 case TCPOPT_MAXSEG: {
1053 uint16_t mss;
1055 if (len < TCPOPT_MAXSEG_LEN ||
1056 opts[1] != TCPOPT_MAXSEG_LEN) {
1057 mdb_printf(" <Truncated MSS>\n");
1058 return;
1060 mdb_nhconvert(&mss, opts + TCPOPT_HEADER_LEN,
1061 sizeof (mss));
1062 mdb_printf(" MSS=%u", mss);
1063 opts += TCPOPT_MAXSEG_LEN;
1064 break;
1067 case TCPOPT_WSCALE:
1068 if (len < TCPOPT_WS_LEN || opts[1] != TCPOPT_WS_LEN) {
1069 mdb_printf(" <Truncated WS>\n");
1070 return;
1072 mdb_printf(" WS=%u", opts[2]);
1073 opts += TCPOPT_WS_LEN;
1074 break;
1076 case TCPOPT_TSTAMP: {
1077 if (len < TCPOPT_TSTAMP_LEN ||
1078 opts[1] != TCPOPT_TSTAMP_LEN) {
1079 mdb_printf(" <Truncated TS>\n");
1080 return;
1083 opts += TCPOPT_HEADER_LEN;
1084 mdb_nhconvert(&val, opts, sizeof (val));
1085 mdb_printf(" TS_VAL=%u,", val);
1087 opts += sizeof (val);
1088 mdb_nhconvert(&val, opts, sizeof (val));
1089 mdb_printf("TS_ECHO=%u", val);
1091 opts += sizeof (val);
1092 break;
1095 case TCPOPT_SACK_PERMITTED:
1096 if (len < TCPOPT_SACK_OK_LEN ||
1097 opts[1] != TCPOPT_SACK_OK_LEN) {
1098 mdb_printf(" <Truncated SACK_OK>\n");
1099 return;
1101 mdb_printf(" SACK_OK");
1102 opts += TCPOPT_SACK_OK_LEN;
1103 break;
1105 case TCPOPT_SACK: {
1106 uint32_t sack_len;
1108 if (len <= TCPOPT_HEADER_LEN || len < opts[1] ||
1109 opts[1] <= TCPOPT_HEADER_LEN) {
1110 mdb_printf(" <Truncated SACK>\n");
1111 return;
1113 sack_len = opts[1] - TCPOPT_HEADER_LEN;
1114 opts += TCPOPT_HEADER_LEN;
1116 mdb_printf(" SACK=");
1117 while (sack_len > 0) {
1118 if (opts + 2 * sizeof (val) > endp) {
1119 mdb_printf("<Truncated SACK>\n");
1120 opts = endp;
1121 break;
1124 mdb_nhconvert(&val, opts, sizeof (val));
1125 mdb_printf("<%u,", val);
1126 opts += sizeof (val);
1127 mdb_nhconvert(&val, opts, sizeof (val));
1128 mdb_printf("%u>", val);
1129 opts += sizeof (val);
1131 sack_len -= 2 * sizeof (val);
1133 break;
1136 default:
1137 mdb_printf(" Opts=<val=%u,len=%u>", *opts,
1138 opts[1]);
1139 opts += opts[1];
1140 break;
1143 mdb_printf("\n");
1146 static void
1147 tcphdr_print(struct tcphdr *tcph)
1149 in_port_t sport, dport;
1150 tcp_seq seq, ack;
1151 uint16_t win, urp;
1153 mdb_printf("%<b>TCP header%</b>\n");
1155 mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport));
1156 mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport));
1157 mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq));
1158 mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack));
1159 mdb_nhconvert(&win, &tcph->th_win, sizeof (win));
1160 mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp));
1162 mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n",
1163 "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP",
1164 "FLAGS");
1165 mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n",
1166 sport, dport, seq, ack, tcph->th_off << 2, win,
1167 tcph->th_sum, urp, tcph->th_flags, tcp_flags);
1168 mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n",
1169 sport, dport, seq, ack);
1172 /* ARGSUSED */
1173 static int
1174 tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
1176 struct tcphdr tcph;
1177 uint32_t opt_len;
1179 if (!(flags & DCMD_ADDRSPEC))
1180 return (DCMD_USAGE);
1182 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) {
1183 mdb_warn("failed to read TCP header at %p", addr);
1184 return (DCMD_ERR);
1186 tcphdr_print(&tcph);
1188 /* If there are options, print them out also. */
1189 opt_len = (tcph.th_off << 2) - TCP_MIN_HEADER_LENGTH;
1190 if (opt_len > 0) {
1191 uint8_t *opts, *opt_buf;
1193 opt_buf = mdb_alloc(opt_len, UM_SLEEP);
1194 opts = (uint8_t *)addr + sizeof (tcph);
1195 if (mdb_vread(opt_buf, opt_len, (uintptr_t)opts) == -1) {
1196 mdb_warn("failed to read TCP options at %p", opts);
1197 return (DCMD_ERR);
1199 tcphdr_print_options(opt_buf, opt_len);
1200 mdb_free(opt_buf, opt_len);
1203 return (DCMD_OK);
1206 static void
1207 udphdr_print(struct udphdr *udph)
1209 in_port_t sport, dport;
1210 uint16_t hlen;
1212 mdb_printf("%<b>UDP header%</b>\n");
1214 mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport));
1215 mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport));
1216 mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen));
1218 mdb_printf("%<u>%14s %14s %5s %6s%</u>\n",
1219 "SPORT", "DPORT", "LEN", "CSUM");
1220 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport,
1221 dport, dport, hlen, udph->uh_sum);
1224 /* ARGSUSED */
1225 static int
1226 udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
1228 struct udphdr udph;
1230 if (!(flags & DCMD_ADDRSPEC))
1231 return (DCMD_USAGE);
1233 if (mdb_vread(&udph, sizeof (udph), addr) == -1) {
1234 mdb_warn("failed to read UDP header at %p", addr);
1235 return (DCMD_ERR);
1237 udphdr_print(&udph);
1238 return (DCMD_OK);
1241 static void
1242 sctphdr_print(sctp_hdr_t *sctph)
1244 in_port_t sport, dport;
1246 mdb_printf("%<b>SCTP header%</b>\n");
1247 mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport));
1248 mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport));
1250 mdb_printf("%<u>%14s %14s %10s %10s%</u>\n",
1251 "SPORT", "DPORT", "VTAG", "CHKSUM");
1252 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport,
1253 dport, dport, sctph->sh_verf, sctph->sh_chksum);
1256 /* ARGSUSED */
1257 static int
1258 sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
1260 sctp_hdr_t sctph;
1262 if (!(flags & DCMD_ADDRSPEC))
1263 return (DCMD_USAGE);
1265 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) {
1266 mdb_warn("failed to read SCTP header at %p", addr);
1267 return (DCMD_ERR);
1270 sctphdr_print(&sctph);
1271 return (DCMD_OK);
1274 static int
1275 transport_hdr(int proto, uintptr_t addr)
1277 mdb_printf("\n");
1278 switch (proto) {
1279 case IPPROTO_TCP: {
1280 struct tcphdr tcph;
1282 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) {
1283 mdb_warn("failed to read TCP header at %p", addr);
1284 return (DCMD_ERR);
1286 tcphdr_print(&tcph);
1287 break;
1289 case IPPROTO_UDP: {
1290 struct udphdr udph;
1292 if (mdb_vread(&udph, sizeof (udph), addr) == -1) {
1293 mdb_warn("failed to read UDP header at %p", addr);
1294 return (DCMD_ERR);
1296 udphdr_print(&udph);
1297 break;
1299 case IPPROTO_SCTP: {
1300 sctp_hdr_t sctph;
1302 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) {
1303 mdb_warn("failed to read SCTP header at %p", addr);
1304 return (DCMD_ERR);
1306 sctphdr_print(&sctph);
1307 break;
1309 default:
1310 break;
1313 return (DCMD_OK);
1316 static const mdb_bitmask_t ip_flags[] = {
1317 { "DF", IPH_DF, IPH_DF },
1318 { "MF", IPH_MF, IPH_MF },
1319 { NULL, 0, 0 }
1322 /* ARGSUSED */
1323 static int
1324 iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1326 uint_t verbose = FALSE, force = FALSE;
1327 ipha_t iph[1];
1328 uint16_t ver, totlen, hdrlen, ipid, off, csum;
1329 uintptr_t nxt_proto;
1330 char exp_csum[8];
1332 if (mdb_getopts(argc, argv,
1333 'v', MDB_OPT_SETBITS, TRUE, &verbose,
1334 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc)
1335 return (DCMD_USAGE);
1337 if (mdb_vread(iph, sizeof (*iph), addr) == -1) {
1338 mdb_warn("failed to read IPv4 header at %p", addr);
1339 return (DCMD_ERR);
1342 ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4;
1343 if (ver != IPV4_VERSION) {
1344 if (ver == IPV6_VERSION) {
1345 return (ip6hdr(addr, flags, argc, argv));
1346 } else if (!force) {
1347 mdb_warn("unknown IP version: %d\n", ver);
1348 return (DCMD_ERR);
1352 mdb_printf("%<b>IPv4 header%</b>\n");
1353 mdb_printf("%-34s %-34s\n"
1354 "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n",
1355 "SRC", "DST",
1356 "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM",
1357 "EXP-CSUM", "FLGS");
1359 hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2;
1360 mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen));
1361 mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid));
1362 mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off));
1363 if (hdrlen == IP_SIMPLE_HDR_LENGTH) {
1364 if ((csum = ipcksum(iph, sizeof (*iph))) != 0)
1365 csum = ~(~csum + ~iph->ipha_hdr_checksum);
1366 else
1367 csum = iph->ipha_hdr_checksum;
1368 mdb_snprintf(exp_csum, 8, "%u", csum);
1369 } else {
1370 mdb_snprintf(exp_csum, 8, "<n/a>");
1373 mdb_printf("%-34I %-34I%\n"
1374 "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n",
1375 iph->ipha_src, iph->ipha_dst,
1376 hdrlen, iph->ipha_type_of_service, totlen, ipid,
1377 (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol,
1378 iph->ipha_hdr_checksum, exp_csum, off, ip_flags);
1380 if (verbose) {
1381 nxt_proto = addr + hdrlen;
1382 return (transport_hdr(iph->ipha_protocol, nxt_proto));
1383 } else {
1384 return (DCMD_OK);
1388 /* ARGSUSED */
1389 static int
1390 ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1392 uint_t verbose = FALSE, force = FALSE;
1393 ip6_t iph[1];
1394 int ver, class, flow;
1395 uint16_t plen;
1396 uintptr_t nxt_proto;
1398 if (mdb_getopts(argc, argv,
1399 'v', MDB_OPT_SETBITS, TRUE, &verbose,
1400 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc)
1401 return (DCMD_USAGE);
1403 if (mdb_vread(iph, sizeof (*iph), addr) == -1) {
1404 mdb_warn("failed to read IPv6 header at %p", addr);
1405 return (DCMD_ERR);
1408 ver = (iph->ip6_vfc & 0xf0) >> 4;
1409 if (ver != IPV6_VERSION) {
1410 if (ver == IPV4_VERSION) {
1411 return (iphdr(addr, flags, argc, argv));
1412 } else if (!force) {
1413 mdb_warn("unknown IP version: %d\n", ver);
1414 return (DCMD_ERR);
1418 mdb_printf("%<b>IPv6 header%</b>\n");
1419 mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n",
1420 "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP");
1422 class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20;
1423 mdb_nhconvert(&class, &class, sizeof (class));
1424 flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL;
1425 mdb_nhconvert(&flow, &flow, sizeof (flow));
1426 mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen));
1428 mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n",
1429 &iph->ip6_src, &iph->ip6_dst,
1430 class, flow, plen, iph->ip6_nxt, iph->ip6_hlim);
1432 if (verbose) {
1433 nxt_proto = addr + sizeof (ip6_t);
1434 return (transport_hdr(iph->ip6_nxt, nxt_proto));
1435 } else {
1436 return (DCMD_OK);
1441 nce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1443 nce_t nce;
1444 nce_cbdata_t nce_cb;
1445 int ipversion = 0;
1446 const char *opt_P = NULL, *opt_ill = NULL;
1448 if (mdb_getopts(argc, argv,
1449 'i', MDB_OPT_STR, &opt_ill,
1450 'P', MDB_OPT_STR, &opt_P, NULL) != argc)
1451 return (DCMD_USAGE);
1453 if (opt_P != NULL) {
1454 if (strcmp("v4", opt_P) == 0) {
1455 ipversion = IPV4_VERSION;
1456 } else if (strcmp("v6", opt_P) == 0) {
1457 ipversion = IPV6_VERSION;
1458 } else {
1459 mdb_warn("invalid protocol '%s'\n", opt_P);
1460 return (DCMD_USAGE);
1464 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
1465 mdb_printf("%<u>%?s %5s %18s %?s %s %s %</u>\n",
1466 "ADDR", "INTF", "LLADDR", "FP_MP", "REFCNT",
1467 "NCE_ADDR");
1470 bzero(&nce_cb, sizeof (nce_cb));
1471 if (opt_ill != NULL) {
1472 strcpy(nce_cb.nce_ill_name, opt_ill);
1474 nce_cb.nce_ipversion = ipversion;
1476 if (flags & DCMD_ADDRSPEC) {
1477 (void) mdb_vread(&nce, sizeof (nce_t), addr);
1478 (void) nce_format(addr, &nce, &nce_cb);
1479 } else if (mdb_walk("nce", (mdb_walk_cb_t)nce_format, &nce_cb) == -1) {
1480 mdb_warn("failed to walk ire table");
1481 return (DCMD_ERR);
1484 return (DCMD_OK);
1487 /* ARGSUSED */
1488 static int
1489 dce_format(uintptr_t addr, const dce_t *dcep, void *dce_cb_arg)
1491 static const mdb_bitmask_t dmasks[] = {
1492 { "D", DCEF_DEFAULT, DCEF_DEFAULT },
1493 { "P", DCEF_PMTU, DCEF_PMTU },
1494 { "U", DCEF_UINFO, DCEF_UINFO },
1495 { "S", DCEF_TOO_SMALL_PMTU, DCEF_TOO_SMALL_PMTU },
1496 { NULL, 0, 0 }
1498 char flagsbuf[2 * A_CNT(dmasks)];
1499 int ipversion = *(int *)dce_cb_arg;
1500 boolean_t condemned = dcep->dce_generation == DCE_GENERATION_CONDEMNED;
1502 if (ipversion != 0 && ipversion != dcep->dce_ipversion)
1503 return (WALK_NEXT);
1505 mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%b", dcep->dce_flags,
1506 dmasks);
1508 switch (dcep->dce_ipversion) {
1509 case IPV4_VERSION:
1510 mdb_printf("%<u>%?p%3s %8s %8d %30I %</u>\n", addr, condemned ?
1511 "(C)" : "", flagsbuf, dcep->dce_pmtu, &dcep->dce_v4addr);
1512 break;
1513 case IPV6_VERSION:
1514 mdb_printf("%<u>%?p%3s %8s %8d %30N %</u>\n", addr, condemned ?
1515 "(C)" : "", flagsbuf, dcep->dce_pmtu, &dcep->dce_v6addr);
1516 break;
1517 default:
1518 mdb_printf("%<u>%?p%3s %8s %8d %30s %</u>\n", addr, condemned ?
1519 "(C)" : "", flagsbuf, dcep->dce_pmtu, "");
1522 return (WALK_NEXT);
1526 dce(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1528 dce_t dce;
1529 const char *opt_P = NULL;
1530 const char *zone_name = NULL;
1531 ip_stack_t *ipst = NULL;
1532 int ipversion = 0;
1534 if (mdb_getopts(argc, argv,
1535 's', MDB_OPT_STR, &zone_name,
1536 'P', MDB_OPT_STR, &opt_P, NULL) != argc)
1537 return (DCMD_USAGE);
1539 /* Follow the specified zone name to find a ip_stack_t*. */
1540 if (zone_name != NULL) {
1541 ipst = zone_to_ips(zone_name);
1542 if (ipst == NULL)
1543 return (DCMD_USAGE);
1546 if (opt_P != NULL) {
1547 if (strcmp("v4", opt_P) == 0) {
1548 ipversion = IPV4_VERSION;
1549 } else if (strcmp("v6", opt_P) == 0) {
1550 ipversion = IPV6_VERSION;
1551 } else {
1552 mdb_warn("invalid protocol '%s'\n", opt_P);
1553 return (DCMD_USAGE);
1557 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
1558 mdb_printf("%<u>%?s%3s %8s %8s %30s %</u>\n",
1559 "ADDR", "", "FLAGS", "PMTU", "DST_ADDR");
1562 if (flags & DCMD_ADDRSPEC) {
1563 (void) mdb_vread(&dce, sizeof (dce_t), addr);
1564 (void) dce_format(addr, &dce, &ipversion);
1565 } else if (mdb_pwalk("dce", (mdb_walk_cb_t)dce_format, &ipversion,
1566 (uintptr_t)ipst) == -1) {
1567 mdb_warn("failed to walk dce cache");
1568 return (DCMD_ERR);
1571 return (DCMD_OK);
1575 ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1577 uint_t verbose = FALSE;
1578 ire_t ire;
1579 ire_cbdata_t ire_cb;
1580 int ipversion = 0;
1581 const char *opt_P = NULL;
1582 const char *zone_name = NULL;
1583 ip_stack_t *ipst = NULL;
1585 if (mdb_getopts(argc, argv,
1586 'v', MDB_OPT_SETBITS, TRUE, &verbose,
1587 's', MDB_OPT_STR, &zone_name,
1588 'P', MDB_OPT_STR, &opt_P, NULL) != argc)
1589 return (DCMD_USAGE);
1591 /* Follow the specified zone name to find a ip_stack_t*. */
1592 if (zone_name != NULL) {
1593 ipst = zone_to_ips(zone_name);
1594 if (ipst == NULL)
1595 return (DCMD_USAGE);
1598 if (opt_P != NULL) {
1599 if (strcmp("v4", opt_P) == 0) {
1600 ipversion = IPV4_VERSION;
1601 } else if (strcmp("v6", opt_P) == 0) {
1602 ipversion = IPV6_VERSION;
1603 } else {
1604 mdb_warn("invalid protocol '%s'\n", opt_P);
1605 return (DCMD_USAGE);
1609 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
1611 if (verbose) {
1612 mdb_printf("%?s %40s %-20s%\n"
1613 "%?s %40s %-20s%\n"
1614 "%<u>%?s %40s %4s %-20s %s%</u>\n",
1615 "ADDR", "SRC", "TYPE",
1616 "", "DST", "MARKS",
1617 "", "STACK", "ZONE", "FLAGS", "INTF");
1618 } else {
1619 mdb_printf("%<u>%?s %30s %30s %5s %4s %s%</u>\n",
1620 "ADDR", "SRC", "DST", "STACK", "ZONE", "INTF");
1624 ire_cb.verbose = (verbose == TRUE);
1625 ire_cb.ire_ipversion = ipversion;
1627 if (flags & DCMD_ADDRSPEC) {
1628 (void) mdb_vread(&ire, sizeof (ire_t), addr);
1629 (void) ire_format(addr, &ire, &ire_cb);
1630 } else if (mdb_pwalk("ire", (mdb_walk_cb_t)ire_format, &ire_cb,
1631 (uintptr_t)ipst) == -1) {
1632 mdb_warn("failed to walk ire table");
1633 return (DCMD_ERR);
1636 return (DCMD_OK);
1639 static size_t
1640 mi_osize(const queue_t *q)
1643 * The code in kernel/net/mi.c allocates an extra word to store the
1644 * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s.
1646 struct mi_block {
1647 size_t mi_nbytes;
1648 struct mi_o_s mi_o;
1649 } m;
1651 if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr -
1652 sizeof (m)) == sizeof (m))
1653 return (m.mi_nbytes - sizeof (m));
1655 return (0);
1658 static void
1659 ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes)
1661 char name[32];
1662 ill_t ill;
1664 if (mdb_vread(&ill, sizeof (ill),
1665 (uintptr_t)q->q_ptr) == sizeof (ill) &&
1666 mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0)
1667 (void) mdb_snprintf(buf, nbytes, "if: %s", name);
1670 void
1671 ip_qinfo(const queue_t *q, char *buf, size_t nbytes)
1673 size_t size = mi_osize(q);
1675 if (size == sizeof (ill_t))
1676 ip_ill_qinfo(q, buf, nbytes);
1679 uintptr_t
1680 ip_rnext(const queue_t *q)
1682 size_t size = mi_osize(q);
1683 ill_t ill;
1685 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill),
1686 (uintptr_t)q->q_ptr) == sizeof (ill))
1687 return ((uintptr_t)ill.ill_rq);
1689 return ((uintptr_t)NULL);
1692 uintptr_t
1693 ip_wnext(const queue_t *q)
1695 size_t size = mi_osize(q);
1696 ill_t ill;
1698 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill),
1699 (uintptr_t)q->q_ptr) == sizeof (ill))
1700 return ((uintptr_t)ill.ill_wq);
1702 return ((uintptr_t)NULL);
1706 * Print the core fields in an squeue_t. With the "-v" argument,
1707 * provide more verbose output.
1709 static int
1710 squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1712 unsigned int i;
1713 unsigned int verbose = FALSE;
1714 const int SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9);
1715 boolean_t arm;
1716 squeue_t squeue;
1718 if (!(flags & DCMD_ADDRSPEC)) {
1719 if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue",
1720 argc, argv) == -1) {
1721 mdb_warn("failed to walk squeue cache");
1722 return (DCMD_ERR);
1724 return (DCMD_OK);
1727 if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL)
1728 != argc)
1729 return (DCMD_USAGE);
1731 if (!DCMD_HDRSPEC(flags) && verbose)
1732 mdb_printf("\n\n");
1734 if (DCMD_HDRSPEC(flags) || verbose) {
1735 mdb_printf("%?s %-5s %-3s %?s %?s %?s\n",
1736 "ADDR", "STATE", "CPU",
1737 "FIRST", "LAST", "WORKER");
1740 if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) {
1741 mdb_warn("cannot read squeue_t at %p", addr);
1742 return (DCMD_ERR);
1745 mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n",
1746 addr, squeue.sq_state, squeue.sq_bind,
1747 squeue.sq_first, squeue.sq_last, squeue.sq_worker);
1749 if (!verbose)
1750 return (DCMD_OK);
1752 arm = B_TRUE;
1753 for (i = 0; squeue_states[i].bit_name != NULL; i++) {
1754 if (((squeue.sq_state) & (1 << i)) == 0)
1755 continue;
1757 if (arm) {
1758 mdb_printf("%*s|\n", SQUEUE_STATEDELT, "");
1759 mdb_printf("%*s+--> ", SQUEUE_STATEDELT, "");
1760 arm = B_FALSE;
1761 } else
1762 mdb_printf("%*s ", SQUEUE_STATEDELT, "");
1764 mdb_printf("%-12s %s\n", squeue_states[i].bit_name,
1765 squeue_states[i].bit_descr);
1768 return (DCMD_OK);
1771 static void
1772 ip_squeue_help(void)
1774 mdb_printf("Print the core information for a given NCA squeue_t.\n\n");
1775 mdb_printf("Options:\n");
1776 mdb_printf("\t-v\tbe verbose (more descriptive)\n");
1780 * This is called by ::th_trace (via a callback) when walking the th_hash
1781 * list. It calls modent to find the entries.
1783 /* ARGSUSED */
1784 static int
1785 modent_summary(uintptr_t addr, const void *data, void *private)
1787 th_walk_data_t *thw = private;
1788 const struct mod_hash_entry *mhe = data;
1789 th_trace_t th;
1791 if (mdb_vread(&th, sizeof (th), (uintptr_t)mhe->mhe_val) == -1) {
1792 mdb_warn("failed to read th_trace_t %p", mhe->mhe_val);
1793 return (WALK_ERR);
1796 if (th.th_refcnt == 0 && thw->thw_non_zero_only)
1797 return (WALK_NEXT);
1799 if (!thw->thw_match) {
1800 mdb_printf("%?p %?p %?p %8d %?p\n", thw->thw_ipst, mhe->mhe_key,
1801 mhe->mhe_val, th.th_refcnt, th.th_id);
1802 } else if (thw->thw_matchkey == (uintptr_t)mhe->mhe_key) {
1803 int i, j, k;
1804 tr_buf_t *tr;
1806 mdb_printf("Object %p in IP stack %p:\n", mhe->mhe_key,
1807 thw->thw_ipst);
1808 i = th.th_trace_lastref;
1809 mdb_printf("\tThread %p refcnt %d:\n", th.th_id,
1810 th.th_refcnt);
1811 for (j = TR_BUF_MAX; j > 0; j--) {
1812 tr = th.th_trbuf + i;
1813 if (tr->tr_depth == 0 || tr->tr_depth > TR_STACK_DEPTH)
1814 break;
1815 mdb_printf("\t T%+ld:\n", tr->tr_time -
1816 thw->thw_lbolt);
1817 for (k = 0; k < tr->tr_depth; k++)
1818 mdb_printf("\t\t%a\n", tr->tr_stack[k]);
1819 if (--i < 0)
1820 i = TR_BUF_MAX - 1;
1823 return (WALK_NEXT);
1827 * This is called by ::th_trace (via a callback) when walking the th_hash
1828 * list. It calls modent to find the entries.
1830 /* ARGSUSED */
1831 static int
1832 th_hash_summary(uintptr_t addr, const void *data, void *private)
1834 const th_hash_t *thh = data;
1835 th_walk_data_t *thw = private;
1837 thw->thw_ipst = (uintptr_t)thh->thh_ipst;
1838 return (mdb_pwalk("modent", modent_summary, private,
1839 (uintptr_t)thh->thh_hash));
1843 * Print or summarize the th_trace_t structures.
1845 static int
1846 th_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1848 th_walk_data_t thw;
1850 (void) memset(&thw, 0, sizeof (thw));
1852 if (mdb_getopts(argc, argv,
1853 'n', MDB_OPT_SETBITS, TRUE, &thw.thw_non_zero_only,
1854 NULL) != argc)
1855 return (DCMD_USAGE);
1857 if (!(flags & DCMD_ADDRSPEC)) {
1859 * No address specified. Walk all of the th_hash_t in the
1860 * system, and summarize the th_trace_t entries in each.
1862 mdb_printf("%?s %?s %?s %8s %?s\n",
1863 "IPSTACK", "OBJECT", "TRACE", "REFCNT", "THREAD");
1864 thw.thw_match = B_FALSE;
1865 } else {
1866 thw.thw_match = B_TRUE;
1867 thw.thw_matchkey = addr;
1869 if ((thw.thw_lbolt = (clock_t)mdb_get_lbolt()) == -1) {
1870 mdb_warn("failed to read lbolt");
1871 return (DCMD_ERR);
1874 if (mdb_pwalk("th_hash", th_hash_summary, &thw,
1875 (uintptr_t)NULL) == -1) {
1876 mdb_warn("can't walk th_hash entries");
1877 return (DCMD_ERR);
1879 return (DCMD_OK);
1882 static void
1883 th_trace_help(void)
1885 mdb_printf("If given an address of an ill_t, ipif_t, ire_t, or ncec_t, "
1886 "print the\n"
1887 "corresponding th_trace_t structure in detail. Otherwise, if no "
1888 "address is\n"
1889 "given, then summarize all th_trace_t structures.\n\n");
1890 mdb_printf("Options:\n"
1891 "\t-n\tdisplay only entries with non-zero th_refcnt\n");
1894 static const mdb_dcmd_t dcmds[] = {
1895 { "conn_status", ":",
1896 "display connection structures from ipcl hash tables",
1897 conn_status, conn_status_help },
1898 { "srcid_status", ":",
1899 "display connection structures from ipcl hash tables",
1900 srcid_status },
1901 { "ill", "?[-v] [-P v4 | v6] [-s exclusive-ip-zone-name]",
1902 "display ill_t structures", ill, ill_help },
1903 { "illif", "?[-P v4 | v6]",
1904 "display or filter IP Lower Level InterFace structures", illif,
1905 illif_help },
1906 { "iphdr", ":[-vf]", "display an IPv4 header", iphdr },
1907 { "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr },
1908 { "ipif", "?[-v] [-P v4 | v6]", "display ipif structures",
1909 ipif, ipif_help },
1910 { "ire", "?[-v] [-P v4|v6] [-s exclusive-ip-zone-name]",
1911 "display Internet Route Entry structures", ire },
1912 { "nce", "?[-P v4|v6] [-i <interface>]",
1913 "display interface-specific Neighbor Cache structures", nce },
1914 { "ncec", "?[-P v4 | v6]", "display Neighbor Cache Entry structures",
1915 ncec },
1916 { "dce", "?[-P v4|v6] [-s exclusive-ip-zone-name]",
1917 "display Destination Cache Entry structures", dce },
1918 { "squeue", ":[-v]", "print core squeue_t info", squeue,
1919 ip_squeue_help },
1920 { "tcphdr", ":", "display a TCP header", tcphdr },
1921 { "udphdr", ":", "display an UDP header", udphdr },
1922 { "sctphdr", ":", "display an SCTP header", sctphdr },
1923 { "th_trace", "?[-n]", "display th_trace_t structures", th_trace,
1924 th_trace_help },
1925 { NULL }
1928 static const mdb_walker_t walkers[] = {
1929 { "conn_status", "walk list of conn_t structures",
1930 ip_stacks_common_walk_init, conn_status_walk_step, NULL },
1931 { "illif", "walk list of ill interface types for all stacks",
1932 ip_stacks_common_walk_init, illif_walk_step, NULL },
1933 { "illif_stack", "walk list of ill interface types",
1934 illif_stack_walk_init, illif_stack_walk_step,
1935 illif_stack_walk_fini },
1936 { "ill", "walk active ill_t structures for all stacks",
1937 ill_walk_init, ill_walk_step, NULL },
1938 { "ipif", "walk list of ipif structures for all stacks",
1939 ipif_walk_init, ipif_walk_step, NULL },
1940 { "ipif_list", "walk the linked list of ipif structures "
1941 "for a given ill",
1942 ip_list_walk_init, ip_list_walk_step,
1943 ip_list_walk_fini, &ipif_walk_arg },
1944 { "srcid", "walk list of srcid_map structures for all stacks",
1945 ip_stacks_common_walk_init, srcid_walk_step, NULL },
1946 { "srcid_list", "walk list of srcid_map structures for a stack",
1947 ip_list_walk_init, ip_list_walk_step, ip_list_walk_fini,
1948 &srcid_walk_arg },
1949 { "ire", "walk active ire_t structures",
1950 ire_walk_init, ire_walk_step, NULL },
1951 { "ire_next", "walk ire_t structures in the ctable",
1952 ire_next_walk_init, ire_next_walk_step, NULL },
1953 { "nce", "walk active nce_t structures",
1954 nce_walk_init, nce_walk_step, NULL },
1955 { "dce", "walk active dce_t structures",
1956 dce_walk_init, dce_walk_step, NULL },
1957 { "ip_stacks", "walk all the ip_stack_t",
1958 ns_walk_init, ip_stacks_walk_step, NULL },
1959 { "tcp_stacks", "walk all the tcp_stack_t",
1960 ns_walk_init, tcp_stacks_walk_step, NULL },
1961 { "sctp_stacks", "walk all the sctp_stack_t",
1962 ns_walk_init, sctp_stacks_walk_step, NULL },
1963 { "udp_stacks", "walk all the udp_stack_t",
1964 ns_walk_init, udp_stacks_walk_step, NULL },
1965 { "th_hash", "walk all the th_hash_t entries",
1966 th_hash_walk_init, th_hash_walk_step, NULL },
1967 { "ncec", "walk list of ncec structures for all stacks",
1968 ip_stacks_common_walk_init, ncec_walk_step, NULL },
1969 { "ncec_stack", "walk list of ncec structures",
1970 ncec_stack_walk_init, ncec_stack_walk_step,
1971 ncec_stack_walk_fini},
1972 { "udp_hash", "walk list of conn_t structures in ips_ipcl_udp_fanout",
1973 ipcl_hash_walk_init, ipcl_hash_walk_step,
1974 ipcl_hash_walk_fini, &udp_hash_arg},
1975 { "conn_hash", "walk list of conn_t structures in ips_ipcl_conn_fanout",
1976 ipcl_hash_walk_init, ipcl_hash_walk_step,
1977 ipcl_hash_walk_fini, &conn_hash_arg},
1978 { "bind_hash", "walk list of conn_t structures in ips_ipcl_bind_fanout",
1979 ipcl_hash_walk_init, ipcl_hash_walk_step,
1980 ipcl_hash_walk_fini, &bind_hash_arg},
1981 { "proto_hash", "walk list of conn_t structures in "
1982 "ips_ipcl_proto_fanout",
1983 ipcl_hash_walk_init, ipcl_hash_walk_step,
1984 ipcl_hash_walk_fini, &proto_hash_arg},
1985 { "proto_v6_hash", "walk list of conn_t structures in "
1986 "ips_ipcl_proto_fanout_v6",
1987 ipcl_hash_walk_init, ipcl_hash_walk_step,
1988 ipcl_hash_walk_fini, &proto_v6_hash_arg},
1989 { "ilb_stacks", "walk all ilb_stack_t",
1990 ns_walk_init, ilb_stacks_walk_step, NULL },
1991 { "ilb_rules", "walk ilb rules in a given ilb_stack_t",
1992 ilb_rules_walk_init, ilb_rules_walk_step, NULL },
1993 { "ilb_servers", "walk server in a given ilb_rule_t",
1994 ilb_servers_walk_init, ilb_servers_walk_step, NULL },
1995 { "ilb_nat_src", "walk NAT source table of a given ilb_stack_t",
1996 ilb_nat_src_walk_init, ilb_nat_src_walk_step,
1997 ilb_common_walk_fini },
1998 { "ilb_conns", "walk NAT table of a given ilb_stack_t",
1999 ilb_conn_walk_init, ilb_conn_walk_step, ilb_common_walk_fini },
2000 { "ilb_stickys", "walk sticky table of a given ilb_stack_t",
2001 ilb_sticky_walk_init, ilb_sticky_walk_step,
2002 ilb_common_walk_fini },
2003 { "tcps_sc", "walk all the per CPU stats counters of a tcp_stack_t",
2004 tcps_sc_walk_init, tcps_sc_walk_step, NULL },
2005 { NULL }
2008 static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext };
2009 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
2011 const mdb_modinfo_t *
2012 _mdb_init(void)
2014 GElf_Sym sym;
2016 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0)
2017 mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value);
2019 return (&modinfo);
2022 void
2023 _mdb_fini(void)
2025 GElf_Sym sym;
2027 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0)
2028 mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value);
2031 static char *
2032 ncec_state(int ncec_state)
2034 switch (ncec_state) {
2035 case ND_UNCHANGED:
2036 return ("unchanged");
2037 case ND_INCOMPLETE:
2038 return ("incomplete");
2039 case ND_REACHABLE:
2040 return ("reachable");
2041 case ND_STALE:
2042 return ("stale");
2043 case ND_DELAY:
2044 return ("delay");
2045 case ND_PROBE:
2046 return ("probe");
2047 case ND_UNREACHABLE:
2048 return ("unreach");
2049 case ND_INITIAL:
2050 return ("initial");
2051 default:
2052 return ("??");
2056 static char *
2057 ncec_l2_addr(const ncec_t *ncec, const ill_t *ill)
2059 uchar_t *h;
2060 static char addr_buf[L2MAXADDRSTRLEN];
2062 if (ncec->ncec_lladdr == NULL) {
2063 return ("None");
2066 if (ill->ill_net_type == IRE_IF_RESOLVER) {
2068 if (ill->ill_phys_addr_length == 0)
2069 return ("None");
2070 h = mdb_zalloc(ill->ill_phys_addr_length, UM_SLEEP);
2071 if (mdb_vread(h, ill->ill_phys_addr_length,
2072 (uintptr_t)ncec->ncec_lladdr) == -1) {
2073 mdb_warn("failed to read hwaddr at %p",
2074 ncec->ncec_lladdr);
2075 return ("Unknown");
2077 mdb_mac_addr(h, ill->ill_phys_addr_length,
2078 addr_buf, sizeof (addr_buf));
2079 } else {
2080 return ("None");
2082 mdb_free(h, ill->ill_phys_addr_length);
2083 return (addr_buf);
2086 static char *
2087 nce_l2_addr(const nce_t *nce, const ill_t *ill)
2089 uchar_t *h;
2090 static char addr_buf[L2MAXADDRSTRLEN];
2091 mblk_t mp;
2092 size_t mblen;
2094 if (nce->nce_dlur_mp == NULL)
2095 return ("None");
2097 if (ill->ill_net_type == IRE_IF_RESOLVER) {
2098 if (mdb_vread(&mp, sizeof (mblk_t),
2099 (uintptr_t)nce->nce_dlur_mp) == -1) {
2100 mdb_warn("failed to read nce_dlur_mp at %p",
2101 nce->nce_dlur_mp);
2102 return ("None");
2104 if (ill->ill_phys_addr_length == 0)
2105 return ("None");
2106 mblen = mp.b_wptr - mp.b_rptr;
2107 if (mblen > (sizeof (dl_unitdata_req_t) + MAX_SAP_LEN) ||
2108 ill->ill_phys_addr_length > MAX_SAP_LEN ||
2109 (NCE_LL_ADDR_OFFSET(ill) +
2110 ill->ill_phys_addr_length) > mblen) {
2111 return ("Unknown");
2113 h = mdb_zalloc(mblen, UM_SLEEP);
2114 if (mdb_vread(h, mblen, (uintptr_t)(mp.b_rptr)) == -1) {
2115 mdb_warn("failed to read hwaddr at %p",
2116 mp.b_rptr + NCE_LL_ADDR_OFFSET(ill));
2117 return ("Unknown");
2119 mdb_mac_addr(h + NCE_LL_ADDR_OFFSET(ill),
2120 ill->ill_phys_addr_length, addr_buf, sizeof (addr_buf));
2121 } else {
2122 return ("None");
2124 mdb_free(h, mblen);
2125 return (addr_buf);
2128 static void
2129 ncec_header(uint_t flags)
2131 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) {
2133 mdb_printf("%<u>%?s %-20s %-10s %-8s %-5s %s%</u>\n",
2134 "ADDR", "HW_ADDR", "STATE", "FLAGS", "ILL", "IP ADDR");
2139 ncec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2141 ncec_t ncec;
2142 ncec_cbdata_t id;
2143 int ipversion = 0;
2144 const char *opt_P = NULL;
2146 if (mdb_getopts(argc, argv,
2147 'P', MDB_OPT_STR, &opt_P, NULL) != argc)
2148 return (DCMD_USAGE);
2150 if (opt_P != NULL) {
2151 if (strcmp("v4", opt_P) == 0) {
2152 ipversion = IPV4_VERSION;
2153 } else if (strcmp("v6", opt_P) == 0) {
2154 ipversion = IPV6_VERSION;
2155 } else {
2156 mdb_warn("invalid protocol '%s'\n", opt_P);
2157 return (DCMD_USAGE);
2161 if (flags & DCMD_ADDRSPEC) {
2163 if (mdb_vread(&ncec, sizeof (ncec_t), addr) == -1) {
2164 mdb_warn("failed to read ncec at %p\n", addr);
2165 return (DCMD_ERR);
2167 if (ipversion != 0 && ncec.ncec_ipversion != ipversion) {
2168 mdb_printf("IP Version mismatch\n");
2169 return (DCMD_ERR);
2171 ncec_header(flags);
2172 return (ncec_format(addr, &ncec, ipversion));
2174 } else {
2175 id.ncec_addr = addr;
2176 id.ncec_ipversion = ipversion;
2177 ncec_header(flags);
2178 if (mdb_walk("ncec", (mdb_walk_cb_t)ncec_cb, &id) == -1) {
2179 mdb_warn("failed to walk ncec table\n");
2180 return (DCMD_ERR);
2183 return (DCMD_OK);
2186 static int
2187 ncec_format(uintptr_t addr, const ncec_t *ncec, int ipversion)
2189 static const mdb_bitmask_t ncec_flags[] = {
2190 { "P", NCE_F_NONUD, NCE_F_NONUD },
2191 { "R", NCE_F_ISROUTER, NCE_F_ISROUTER },
2192 { "N", NCE_F_NONUD, NCE_F_NONUD },
2193 { "A", NCE_F_ANYCAST, NCE_F_ANYCAST },
2194 { "C", NCE_F_CONDEMNED, NCE_F_CONDEMNED },
2195 { "U", NCE_F_UNSOL_ADV, NCE_F_UNSOL_ADV },
2196 { "B", NCE_F_BCAST, NCE_F_BCAST },
2197 { NULL, 0, 0 }
2199 #define NCE_MAX_FLAGS (sizeof (ncec_flags) / sizeof (mdb_bitmask_t))
2200 struct in_addr nceaddr;
2201 ill_t ill;
2202 char ill_name[LIFNAMSIZ];
2203 char flagsbuf[NCE_MAX_FLAGS];
2205 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ncec->ncec_ill) == -1) {
2206 mdb_warn("failed to read ncec_ill at %p",
2207 ncec->ncec_ill);
2208 return (DCMD_ERR);
2211 (void) mdb_readstr(ill_name, MIN(LIFNAMSIZ, ill.ill_name_length),
2212 (uintptr_t)ill.ill_name);
2214 mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%hb",
2215 ncec->ncec_flags, ncec_flags);
2217 if (ipversion != 0 && ncec->ncec_ipversion != ipversion)
2218 return (DCMD_OK);
2220 if (ncec->ncec_ipversion == IPV4_VERSION) {
2221 IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &nceaddr);
2222 mdb_printf("%?p %-20s %-10s "
2223 "%-8s "
2224 "%-5s %I\n",
2225 addr, ncec_l2_addr(ncec, &ill),
2226 ncec_state(ncec->ncec_state),
2227 flagsbuf,
2228 ill_name, nceaddr.s_addr);
2229 } else {
2230 mdb_printf("%?p %-20s %-10s %-8s %-5s %N\n",
2231 addr, ncec_l2_addr(ncec, &ill),
2232 ncec_state(ncec->ncec_state),
2233 flagsbuf,
2234 ill_name, &ncec->ncec_addr);
2237 return (DCMD_OK);
2240 static uintptr_t
2241 ncec_get_next_hash_tbl(uintptr_t start, int *index, struct ndp_g_s ndp)
2243 uintptr_t addr = start;
2244 int i = *index;
2246 while (addr == (uintptr_t)NULL) {
2248 if (++i >= NCE_TABLE_SIZE)
2249 break;
2250 addr = (uintptr_t)ndp.nce_hash_tbl[i];
2252 *index = i;
2253 return (addr);
2256 static int
2257 ncec_walk_step(mdb_walk_state_t *wsp)
2259 uintptr_t kaddr4, kaddr6;
2261 kaddr4 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp4);
2262 kaddr6 = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ndp6);
2264 if (mdb_vread(&kaddr4, sizeof (kaddr4), kaddr4) == -1) {
2265 mdb_warn("can't read ips_ip_cache_table at %p", kaddr4);
2266 return (WALK_ERR);
2268 if (mdb_vread(&kaddr6, sizeof (kaddr6), kaddr6) == -1) {
2269 mdb_warn("can't read ips_ip_cache_table at %p", kaddr6);
2270 return (WALK_ERR);
2272 if (mdb_pwalk("ncec_stack", wsp->walk_callback, wsp->walk_cbdata,
2273 kaddr4) == -1) {
2274 mdb_warn("couldn't walk 'ncec_stack' for ips_ndp4 %p",
2275 kaddr4);
2276 return (WALK_ERR);
2278 if (mdb_pwalk("ncec_stack", wsp->walk_callback,
2279 wsp->walk_cbdata, kaddr6) == -1) {
2280 mdb_warn("couldn't walk 'ncec_stack' for ips_ndp6 %p",
2281 kaddr6);
2282 return (WALK_ERR);
2284 return (WALK_NEXT);
2287 static uintptr_t
2288 ipcl_hash_get_next_connf_tbl(ipcl_hash_walk_data_t *iw)
2290 struct connf_s connf;
2291 uintptr_t addr = (uintptr_t)NULL, next;
2292 int index = iw->connf_tbl_index;
2294 do {
2295 next = iw->hash_tbl + index * sizeof (struct connf_s);
2296 if (++index >= iw->hash_tbl_size) {
2297 addr = (uintptr_t)NULL;
2298 break;
2300 if (mdb_vread(&connf, sizeof (struct connf_s), next) == -1) {
2301 mdb_warn("failed to read conn_t at %p", next);
2302 return ((uintptr_t)NULL);
2304 addr = (uintptr_t)connf.connf_head;
2305 } while (addr == (uintptr_t)NULL);
2306 iw->connf_tbl_index = index;
2307 return (addr);
2310 static int
2311 ipcl_hash_walk_init(mdb_walk_state_t *wsp)
2313 const hash_walk_arg_t *arg = wsp->walk_arg;
2314 ipcl_hash_walk_data_t *iw;
2315 uintptr_t tbladdr;
2316 uintptr_t sizeaddr;
2318 iw = mdb_alloc(sizeof (ipcl_hash_walk_data_t), UM_SLEEP);
2319 iw->conn = mdb_alloc(sizeof (conn_t), UM_SLEEP);
2320 tbladdr = wsp->walk_addr + arg->tbl_off;
2321 sizeaddr = wsp->walk_addr + arg->size_off;
2323 if (mdb_vread(&iw->hash_tbl, sizeof (uintptr_t), tbladdr) == -1) {
2324 mdb_warn("can't read fanout table addr at %p", tbladdr);
2325 mdb_free(iw->conn, sizeof (conn_t));
2326 mdb_free(iw, sizeof (ipcl_hash_walk_data_t));
2327 return (WALK_ERR);
2329 if (arg->tbl_off == OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v4) ||
2330 arg->tbl_off == OFFSETOF(ip_stack_t, ips_ipcl_proto_fanout_v6)) {
2331 iw->hash_tbl_size = IPPROTO_MAX;
2332 } else {
2333 if (mdb_vread(&iw->hash_tbl_size, sizeof (int),
2334 sizeaddr) == -1) {
2335 mdb_warn("can't read fanout table size addr at %p",
2336 sizeaddr);
2337 mdb_free(iw->conn, sizeof (conn_t));
2338 mdb_free(iw, sizeof (ipcl_hash_walk_data_t));
2339 return (WALK_ERR);
2342 iw->connf_tbl_index = 0;
2343 wsp->walk_addr = ipcl_hash_get_next_connf_tbl(iw);
2344 wsp->walk_data = iw;
2346 if (wsp->walk_addr != (uintptr_t)NULL)
2347 return (WALK_NEXT);
2348 else
2349 return (WALK_DONE);
2352 static int
2353 ipcl_hash_walk_step(mdb_walk_state_t *wsp)
2355 uintptr_t addr = wsp->walk_addr;
2356 ipcl_hash_walk_data_t *iw = wsp->walk_data;
2357 conn_t *conn = iw->conn;
2358 int ret = WALK_DONE;
2360 while (addr != (uintptr_t)NULL) {
2361 if (mdb_vread(conn, sizeof (conn_t), addr) == -1) {
2362 mdb_warn("failed to read conn_t at %p", addr);
2363 return (WALK_ERR);
2365 ret = wsp->walk_callback(addr, iw, wsp->walk_cbdata);
2366 if (ret != WALK_NEXT)
2367 break;
2368 addr = (uintptr_t)conn->conn_next;
2370 if (ret == WALK_NEXT) {
2371 wsp->walk_addr = ipcl_hash_get_next_connf_tbl(iw);
2373 if (wsp->walk_addr != (uintptr_t)NULL)
2374 return (WALK_NEXT);
2375 else
2376 return (WALK_DONE);
2379 return (ret);
2382 static void
2383 ipcl_hash_walk_fini(mdb_walk_state_t *wsp)
2385 ipcl_hash_walk_data_t *iw = wsp->walk_data;
2387 mdb_free(iw->conn, sizeof (conn_t));
2388 mdb_free(iw, sizeof (ipcl_hash_walk_data_t));
2392 * Called with walk_addr being the address of ips_ndp{4,6}
2394 static int
2395 ncec_stack_walk_init(mdb_walk_state_t *wsp)
2397 ncec_walk_data_t *nw;
2399 if (wsp->walk_addr == (uintptr_t)NULL) {
2400 mdb_warn("ncec_stack requires ndp_g_s address\n");
2401 return (WALK_ERR);
2404 nw = mdb_alloc(sizeof (ncec_walk_data_t), UM_SLEEP);
2406 if (mdb_vread(&nw->ncec_ip_ndp, sizeof (struct ndp_g_s),
2407 wsp->walk_addr) == -1) {
2408 mdb_warn("failed to read 'ip_ndp' at %p",
2409 wsp->walk_addr);
2410 mdb_free(nw, sizeof (ncec_walk_data_t));
2411 return (WALK_ERR);
2415 * ncec_get_next_hash_tbl() starts at ++i , so initialize index to -1
2417 nw->ncec_hash_tbl_index = -1;
2418 wsp->walk_addr = ncec_get_next_hash_tbl((uintptr_t)NULL,
2419 &nw->ncec_hash_tbl_index, nw->ncec_ip_ndp);
2420 wsp->walk_data = nw;
2422 return (WALK_NEXT);
2425 static int
2426 ncec_stack_walk_step(mdb_walk_state_t *wsp)
2428 uintptr_t addr = wsp->walk_addr;
2429 ncec_walk_data_t *nw = wsp->walk_data;
2431 if (addr == (uintptr_t)NULL)
2432 return (WALK_DONE);
2434 if (mdb_vread(&nw->ncec, sizeof (ncec_t), addr) == -1) {
2435 mdb_warn("failed to read ncec_t at %p", addr);
2436 return (WALK_ERR);
2439 wsp->walk_addr = (uintptr_t)nw->ncec.ncec_next;
2441 wsp->walk_addr = ncec_get_next_hash_tbl(wsp->walk_addr,
2442 &nw->ncec_hash_tbl_index, nw->ncec_ip_ndp);
2444 return (wsp->walk_callback(addr, nw, wsp->walk_cbdata));
2447 static void
2448 ncec_stack_walk_fini(mdb_walk_state_t *wsp)
2450 mdb_free(wsp->walk_data, sizeof (ncec_walk_data_t));
2453 /* ARGSUSED */
2454 static int
2455 ncec_cb(uintptr_t addr, const ncec_walk_data_t *iw, ncec_cbdata_t *id)
2457 ncec_t ncec;
2459 if (mdb_vread(&ncec, sizeof (ncec_t), addr) == -1) {
2460 mdb_warn("failed to read ncec at %p", addr);
2461 return (WALK_NEXT);
2463 (void) ncec_format(addr, &ncec, id->ncec_ipversion);
2464 return (WALK_NEXT);
2467 static int
2468 ill_walk_init(mdb_walk_state_t *wsp)
2470 if (mdb_layered_walk("illif", wsp) == -1) {
2471 mdb_warn("can't walk 'illif'");
2472 return (WALK_ERR);
2474 return (WALK_NEXT);
2477 static int
2478 ill_walk_step(mdb_walk_state_t *wsp)
2480 ill_if_t ill_if;
2482 if (mdb_vread(&ill_if, sizeof (ill_if_t), wsp->walk_addr) == -1) {
2483 mdb_warn("can't read ill_if_t at %p", wsp->walk_addr);
2484 return (WALK_ERR);
2486 wsp->walk_addr = (uintptr_t)(wsp->walk_addr +
2487 offsetof(ill_if_t, illif_avl_by_ppa));
2488 if (mdb_pwalk("avl", wsp->walk_callback, wsp->walk_cbdata,
2489 wsp->walk_addr) == -1) {
2490 mdb_warn("can't walk 'avl'");
2491 return (WALK_ERR);
2494 return (WALK_NEXT);
2497 /* ARGSUSED */
2498 static int
2499 ill_cb(uintptr_t addr, const ill_walk_data_t *iw, ill_cbdata_t *id)
2501 ill_t ill;
2503 if (mdb_vread(&ill, sizeof (ill_t), (uintptr_t)addr) == -1) {
2504 mdb_warn("failed to read ill at %p", addr);
2505 return (WALK_NEXT);
2508 /* If ip_stack_t is specified, skip ILLs that don't belong to it. */
2509 if (id->ill_ipst != NULL && ill.ill_ipst != id->ill_ipst)
2510 return (WALK_NEXT);
2512 return (ill_format((uintptr_t)addr, &ill, id));
2515 static void
2516 ill_header(boolean_t verbose)
2518 if (verbose) {
2519 mdb_printf("%-?s %-8s %3s %-10s %-?s %-?s %-10s%</u>\n",
2520 "ADDR", "NAME", "VER", "TYPE", "WQ", "IPST", "FLAGS");
2521 mdb_printf("%-?s %4s%4s %-?s\n",
2522 "PHYINT", "CNT", "", "GROUP");
2523 mdb_printf("%<u>%80s%</u>\n", "");
2524 } else {
2525 mdb_printf("%<u>%-?s %-8s %-3s %-10s %4s %-?s %-10s%</u>\n",
2526 "ADDR", "NAME", "VER", "TYPE", "CNT", "WQ", "FLAGS");
2530 static int
2531 ill_format(uintptr_t addr, const void *illptr, void *ill_cb_arg)
2533 ill_t *ill = (ill_t *)illptr;
2534 ill_cbdata_t *illcb = ill_cb_arg;
2535 boolean_t verbose = illcb->verbose;
2536 phyint_t phyi;
2537 static const mdb_bitmask_t fmasks[] = {
2538 { "R", PHYI_RUNNING, PHYI_RUNNING },
2539 { "P", PHYI_PROMISC, PHYI_PROMISC },
2540 { "V", PHYI_VIRTUAL, PHYI_VIRTUAL },
2541 { "I", PHYI_IPMP, PHYI_IPMP },
2542 { "f", PHYI_FAILED, PHYI_FAILED },
2543 { "S", PHYI_STANDBY, PHYI_STANDBY },
2544 { "i", PHYI_INACTIVE, PHYI_INACTIVE },
2545 { "O", PHYI_OFFLINE, PHYI_OFFLINE },
2546 { "T", ILLF_NOTRAILERS, ILLF_NOTRAILERS },
2547 { "A", ILLF_NOARP, ILLF_NOARP },
2548 { "M", ILLF_MULTICAST, ILLF_MULTICAST },
2549 { "F", ILLF_ROUTER, ILLF_ROUTER },
2550 { "D", ILLF_NONUD, ILLF_NONUD },
2551 { "X", ILLF_NORTEXCH, ILLF_NORTEXCH },
2552 { NULL, 0, 0 }
2554 static const mdb_bitmask_t v_fmasks[] = {
2555 { "RUNNING", PHYI_RUNNING, PHYI_RUNNING },
2556 { "PROMISC", PHYI_PROMISC, PHYI_PROMISC },
2557 { "VIRTUAL", PHYI_VIRTUAL, PHYI_VIRTUAL },
2558 { "IPMP", PHYI_IPMP, PHYI_IPMP },
2559 { "FAILED", PHYI_FAILED, PHYI_FAILED },
2560 { "STANDBY", PHYI_STANDBY, PHYI_STANDBY },
2561 { "INACTIVE", PHYI_INACTIVE, PHYI_INACTIVE },
2562 { "OFFLINE", PHYI_OFFLINE, PHYI_OFFLINE },
2563 { "NOTRAILER", ILLF_NOTRAILERS, ILLF_NOTRAILERS },
2564 { "NOARP", ILLF_NOARP, ILLF_NOARP },
2565 { "MULTICAST", ILLF_MULTICAST, ILLF_MULTICAST },
2566 { "ROUTER", ILLF_ROUTER, ILLF_ROUTER },
2567 { "NONUD", ILLF_NONUD, ILLF_NONUD },
2568 { "NORTEXCH", ILLF_NORTEXCH, ILLF_NORTEXCH },
2569 { NULL, 0, 0 }
2571 char ill_name[LIFNAMSIZ];
2572 int cnt;
2573 char *typebuf;
2574 char sbuf[DEFCOLS];
2575 int ipver = illcb->ill_ipversion;
2577 if (ipver != 0) {
2578 if ((ipver == IPV4_VERSION && ill->ill_isv6) ||
2579 (ipver == IPV6_VERSION && !ill->ill_isv6)) {
2580 return (WALK_NEXT);
2583 if (mdb_vread(&phyi, sizeof (phyint_t),
2584 (uintptr_t)ill->ill_phyint) == -1) {
2585 mdb_warn("failed to read ill_phyint at %p",
2586 (uintptr_t)ill->ill_phyint);
2587 return (WALK_NEXT);
2589 (void) mdb_readstr(ill_name, MIN(LIFNAMSIZ, ill->ill_name_length),
2590 (uintptr_t)ill->ill_name);
2592 switch (ill->ill_type) {
2593 case 0:
2594 typebuf = "LOOPBACK";
2595 break;
2596 case IFT_ETHER:
2597 typebuf = "ETHER";
2598 break;
2599 case IFT_OTHER:
2600 typebuf = "OTHER";
2601 break;
2602 default:
2603 typebuf = NULL;
2604 break;
2606 cnt = ill->ill_refcnt + ill->ill_ire_cnt + ill->ill_nce_cnt +
2607 ill->ill_ilm_cnt + ill->ill_ncec_cnt;
2608 mdb_printf("%-?p %-8s %-3s ",
2609 addr, ill_name, ill->ill_isv6 ? "v6" : "v4");
2610 if (typebuf != NULL)
2611 mdb_printf("%-10s ", typebuf);
2612 else
2613 mdb_printf("%-10x ", ill->ill_type);
2614 if (verbose) {
2615 mdb_printf("%-?p %-?p %-llb\n",
2616 ill->ill_wq, ill->ill_ipst,
2617 ill->ill_flags | phyi.phyint_flags, v_fmasks);
2618 mdb_printf("%-?p %4d%4s %-?p\n",
2619 ill->ill_phyint, cnt, "", ill->ill_grp);
2620 mdb_snprintf(sbuf, sizeof (sbuf), "%*s %3s",
2621 sizeof (uintptr_t) * 2, "", "");
2622 mdb_printf("%s|\n%s+--> %3d %-18s "
2623 "references from active threads\n",
2624 sbuf, sbuf, ill->ill_refcnt, "ill_refcnt");
2625 mdb_printf("%*s %7d %-18s ires referencing this ill\n",
2626 strlen(sbuf), "", ill->ill_ire_cnt, "ill_ire_cnt");
2627 mdb_printf("%*s %7d %-18s nces referencing this ill\n",
2628 strlen(sbuf), "", ill->ill_nce_cnt, "ill_nce_cnt");
2629 mdb_printf("%*s %7d %-18s ncecs referencing this ill\n",
2630 strlen(sbuf), "", ill->ill_ncec_cnt, "ill_ncec_cnt");
2631 mdb_printf("%*s %7d %-18s ilms referencing this ill\n",
2632 strlen(sbuf), "", ill->ill_ilm_cnt, "ill_ilm_cnt");
2633 } else {
2634 mdb_printf("%4d %-?p %-llb\n",
2635 cnt, ill->ill_wq,
2636 ill->ill_flags | phyi.phyint_flags, fmasks);
2638 return (WALK_NEXT);
2641 static int
2642 ill(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2644 ill_t ill_data;
2645 ill_cbdata_t id;
2646 int ipversion = 0;
2647 const char *zone_name = NULL;
2648 const char *opt_P = NULL;
2649 uint_t verbose = FALSE;
2650 ip_stack_t *ipst = NULL;
2652 if (mdb_getopts(argc, argv,
2653 'v', MDB_OPT_SETBITS, TRUE, &verbose,
2654 's', MDB_OPT_STR, &zone_name,
2655 'P', MDB_OPT_STR, &opt_P, NULL) != argc)
2656 return (DCMD_USAGE);
2658 /* Follow the specified zone name to find a ip_stack_t*. */
2659 if (zone_name != NULL) {
2660 ipst = zone_to_ips(zone_name);
2661 if (ipst == NULL)
2662 return (DCMD_USAGE);
2665 if (opt_P != NULL) {
2666 if (strcmp("v4", opt_P) == 0) {
2667 ipversion = IPV4_VERSION;
2668 } else if (strcmp("v6", opt_P) == 0) {
2669 ipversion = IPV6_VERSION;
2670 } else {
2671 mdb_warn("invalid protocol '%s'\n", opt_P);
2672 return (DCMD_USAGE);
2676 id.verbose = verbose;
2677 id.ill_addr = addr;
2678 id.ill_ipversion = ipversion;
2679 id.ill_ipst = ipst;
2681 ill_header(verbose);
2682 if (flags & DCMD_ADDRSPEC) {
2683 if (mdb_vread(&ill_data, sizeof (ill_t), addr) == -1) {
2684 mdb_warn("failed to read ill at %p\n", addr);
2685 return (DCMD_ERR);
2687 (void) ill_format(addr, &ill_data, &id);
2688 } else {
2689 if (mdb_walk("ill", (mdb_walk_cb_t)ill_cb, &id) == -1) {
2690 mdb_warn("failed to walk ills\n");
2691 return (DCMD_ERR);
2694 return (DCMD_OK);
2697 static void
2698 ill_help(void)
2700 mdb_printf("Prints the following fields: ill ptr, name, "
2701 "IP version, count, ill type and ill flags.\n"
2702 "The count field is a sum of individual refcnts and is expanded "
2703 "with the -v option.\n\n");
2704 mdb_printf("Options:\n");
2705 mdb_printf("\t-P v4 | v6"
2706 "\tfilter ill structures for the specified protocol\n");
2709 static int
2710 ip_list_walk_init(mdb_walk_state_t *wsp)
2712 const ip_list_walk_arg_t *arg = wsp->walk_arg;
2713 ip_list_walk_data_t *iw;
2714 uintptr_t addr = (uintptr_t)(wsp->walk_addr + arg->off);
2716 if (wsp->walk_addr == (uintptr_t)NULL) {
2717 mdb_warn("only local walks supported\n");
2718 return (WALK_ERR);
2720 if (mdb_vread(&wsp->walk_addr, sizeof (uintptr_t),
2721 addr) == -1) {
2722 mdb_warn("failed to read list head at %p", addr);
2723 return (WALK_ERR);
2725 iw = mdb_alloc(sizeof (ip_list_walk_data_t), UM_SLEEP);
2726 iw->nextoff = arg->nextp_off;
2727 wsp->walk_data = iw;
2729 return (WALK_NEXT);
2732 static int
2733 ip_list_walk_step(mdb_walk_state_t *wsp)
2735 ip_list_walk_data_t *iw = wsp->walk_data;
2736 uintptr_t addr = wsp->walk_addr;
2738 if (addr == (uintptr_t)NULL)
2739 return (WALK_DONE);
2740 wsp->walk_addr = addr + iw->nextoff;
2741 if (mdb_vread(&wsp->walk_addr, sizeof (uintptr_t),
2742 wsp->walk_addr) == -1) {
2743 mdb_warn("failed to read list node at %p", addr);
2744 return (WALK_ERR);
2746 return (wsp->walk_callback(addr, iw, wsp->walk_cbdata));
2749 static void
2750 ip_list_walk_fini(mdb_walk_state_t *wsp)
2752 mdb_free(wsp->walk_data, sizeof (ip_list_walk_data_t));
2755 static int
2756 ipif_walk_init(mdb_walk_state_t *wsp)
2758 if (mdb_layered_walk("ill", wsp) == -1) {
2759 mdb_warn("can't walk 'ills'");
2760 return (WALK_ERR);
2762 return (WALK_NEXT);
2765 static int
2766 ipif_walk_step(mdb_walk_state_t *wsp)
2768 if (mdb_pwalk("ipif_list", wsp->walk_callback, wsp->walk_cbdata,
2769 wsp->walk_addr) == -1) {
2770 mdb_warn("can't walk 'ipif_list'");
2771 return (WALK_ERR);
2774 return (WALK_NEXT);
2777 /* ARGSUSED */
2778 static int
2779 ipif_cb(uintptr_t addr, const ipif_walk_data_t *iw, ipif_cbdata_t *id)
2781 ipif_t ipif;
2783 if (mdb_vread(&ipif, sizeof (ipif_t), (uintptr_t)addr) == -1) {
2784 mdb_warn("failed to read ipif at %p", addr);
2785 return (WALK_NEXT);
2787 if (mdb_vread(&id->ill, sizeof (ill_t),
2788 (uintptr_t)ipif.ipif_ill) == -1) {
2789 mdb_warn("failed to read ill at %p", ipif.ipif_ill);
2790 return (WALK_NEXT);
2792 (void) ipif_format((uintptr_t)addr, &ipif, id);
2793 return (WALK_NEXT);
2796 static void
2797 ipif_header(boolean_t verbose)
2799 if (verbose) {
2800 mdb_printf("%-?s %-10s %-3s %-?s %-8s %-30s\n",
2801 "ADDR", "NAME", "CNT", "ILL", "STFLAGS", "FLAGS");
2802 mdb_printf("%s\n%s\n",
2803 "LCLADDR", "BROADCAST");
2804 mdb_printf("%<u>%80s%</u>\n", "");
2805 } else {
2806 mdb_printf("%-?s %-10s %6s %-?s %-8s %-30s\n",
2807 "ADDR", "NAME", "CNT", "ILL", "STFLAGS", "FLAGS");
2808 mdb_printf("%s\n%<u>%80s%</u>\n", "LCLADDR", "");
2812 #ifdef _BIG_ENDIAN
2813 #define ip_ntohl_32(x) ((x) & 0xffffffff)
2814 #else
2815 #define ip_ntohl_32(x) (((uint32_t)(x) << 24) | \
2816 (((uint32_t)(x) << 8) & 0xff0000) | \
2817 (((uint32_t)(x) >> 8) & 0xff00) | \
2818 ((uint32_t)(x) >> 24))
2819 #endif
2822 mask_to_prefixlen(int af, const in6_addr_t *addr)
2824 int len = 0;
2825 int i;
2826 uint_t mask = 0;
2828 if (af == AF_INET6) {
2829 for (i = 0; i < 4; i++) {
2830 if (addr->s6_addr32[i] == 0xffffffff) {
2831 len += 32;
2832 } else {
2833 mask = addr->s6_addr32[i];
2834 break;
2837 } else {
2838 mask = V4_PART_OF_V6((*addr));
2840 if (mask > 0)
2841 len += (33 - mdb_ffs(ip_ntohl_32(mask)));
2842 return (len);
2845 static int
2846 ipif_format(uintptr_t addr, const void *ipifptr, void *ipif_cb_arg)
2848 const ipif_t *ipif = ipifptr;
2849 ipif_cbdata_t *ipifcb = ipif_cb_arg;
2850 boolean_t verbose = ipifcb->verbose;
2851 char ill_name[LIFNAMSIZ];
2852 char buf[LIFNAMSIZ];
2853 int cnt;
2854 static const mdb_bitmask_t sfmasks[] = {
2855 { "CO", IPIF_CONDEMNED, IPIF_CONDEMNED},
2856 { "CH", IPIF_CHANGING, IPIF_CHANGING},
2857 { "SL", IPIF_SET_LINKLOCAL, IPIF_SET_LINKLOCAL},
2858 { NULL, 0, 0 }
2860 static const mdb_bitmask_t fmasks[] = {
2861 { "UP", IPIF_UP, IPIF_UP },
2862 { "UNN", IPIF_UNNUMBERED, IPIF_UNNUMBERED},
2863 { "DHCP", IPIF_DHCPRUNNING, IPIF_DHCPRUNNING},
2864 { "PRIV", IPIF_PRIVATE, IPIF_PRIVATE},
2865 { "NOXMT", IPIF_NOXMIT, IPIF_NOXMIT},
2866 { "NOLCL", IPIF_NOLOCAL, IPIF_NOLOCAL},
2867 { "DEPR", IPIF_DEPRECATED, IPIF_DEPRECATED},
2868 { "PREF", IPIF_PREFERRED, IPIF_PREFERRED},
2869 { "TEMP", IPIF_TEMPORARY, IPIF_TEMPORARY},
2870 { "ACONF", IPIF_ADDRCONF, IPIF_ADDRCONF},
2871 { "ANY", IPIF_ANYCAST, IPIF_ANYCAST},
2872 { "NFAIL", IPIF_NOFAILOVER, IPIF_NOFAILOVER},
2873 { NULL, 0, 0 }
2875 char flagsbuf[2 * A_CNT(fmasks)];
2876 char bitfields[A_CNT(fmasks)];
2877 char sflagsbuf[A_CNT(sfmasks)];
2878 char sbuf[DEFCOLS], addrstr[INET6_ADDRSTRLEN];
2879 int ipver = ipifcb->ipif_ipversion;
2880 int af;
2882 if (ipver != 0) {
2883 if ((ipver == IPV4_VERSION && ipifcb->ill.ill_isv6) ||
2884 (ipver == IPV6_VERSION && !ipifcb->ill.ill_isv6)) {
2885 return (WALK_NEXT);
2888 if ((mdb_readstr(ill_name, MIN(LIFNAMSIZ,
2889 ipifcb->ill.ill_name_length),
2890 (uintptr_t)ipifcb->ill.ill_name)) == -1) {
2891 mdb_warn("failed to read ill_name of ill %p\n", ipifcb->ill);
2892 return (WALK_NEXT);
2894 if (ipif->ipif_id != 0) {
2895 mdb_snprintf(buf, LIFNAMSIZ, "%s:%d",
2896 ill_name, ipif->ipif_id);
2897 } else {
2898 mdb_snprintf(buf, LIFNAMSIZ, "%s", ill_name);
2900 mdb_snprintf(bitfields, sizeof (bitfields), "%s",
2901 ipif->ipif_addr_ready ? ",ADR" : "",
2902 ipif->ipif_was_up ? ",WU" : "",
2903 ipif->ipif_was_dup ? ",WD" : "");
2904 mdb_snprintf(flagsbuf, sizeof (flagsbuf), "%llb%s",
2905 ipif->ipif_flags, fmasks, bitfields);
2906 mdb_snprintf(sflagsbuf, sizeof (sflagsbuf), "%b",
2907 ipif->ipif_state_flags, sfmasks);
2909 cnt = ipif->ipif_refcnt;
2911 if (ipifcb->ill.ill_isv6) {
2912 mdb_snprintf(addrstr, sizeof (addrstr), "%N",
2913 &ipif->ipif_v6lcl_addr);
2914 af = AF_INET6;
2915 } else {
2916 mdb_snprintf(addrstr, sizeof (addrstr), "%I",
2917 V4_PART_OF_V6((ipif->ipif_v6lcl_addr)));
2918 af = AF_INET;
2921 if (verbose) {
2922 mdb_printf("%-?p %-10s %3d %-?p %-8s %-30s\n",
2923 addr, buf, cnt, ipif->ipif_ill,
2924 sflagsbuf, flagsbuf);
2925 mdb_snprintf(sbuf, sizeof (sbuf), "%*s %12s",
2926 sizeof (uintptr_t) * 2, "", "");
2927 mdb_printf("%s |\n%s +---> %4d %-15s "
2928 "Active consistent reader cnt\n",
2929 sbuf, sbuf, ipif->ipif_refcnt, "ipif_refcnt");
2930 mdb_printf("%-s/%d\n",
2931 addrstr, mask_to_prefixlen(af, &ipif->ipif_v6net_mask));
2932 if (ipifcb->ill.ill_isv6) {
2933 mdb_printf("%-N\n", &ipif->ipif_v6brd_addr);
2934 } else {
2935 mdb_printf("%-I\n",
2936 V4_PART_OF_V6((ipif->ipif_v6brd_addr)));
2938 } else {
2939 mdb_printf("%-?p %-10s %6d %-?p %-8s %-30s\n",
2940 addr, buf, cnt, ipif->ipif_ill,
2941 sflagsbuf, flagsbuf);
2942 mdb_printf("%-s/%d\n",
2943 addrstr, mask_to_prefixlen(af, &ipif->ipif_v6net_mask));
2946 return (WALK_NEXT);
2949 static int
2950 ipif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2952 ipif_t ipif;
2953 ipif_cbdata_t id;
2954 int ipversion = 0;
2955 const char *opt_P = NULL;
2956 uint_t verbose = FALSE;
2958 if (mdb_getopts(argc, argv,
2959 'v', MDB_OPT_SETBITS, TRUE, &verbose,
2960 'P', MDB_OPT_STR, &opt_P, NULL) != argc)
2961 return (DCMD_USAGE);
2963 if (opt_P != NULL) {
2964 if (strcmp("v4", opt_P) == 0) {
2965 ipversion = IPV4_VERSION;
2966 } else if (strcmp("v6", opt_P) == 0) {
2967 ipversion = IPV6_VERSION;
2968 } else {
2969 mdb_warn("invalid protocol '%s'\n", opt_P);
2970 return (DCMD_USAGE);
2974 id.verbose = verbose;
2975 id.ipif_ipversion = ipversion;
2977 if (flags & DCMD_ADDRSPEC) {
2978 if (mdb_vread(&ipif, sizeof (ipif_t), addr) == -1) {
2979 mdb_warn("failed to read ipif at %p\n", addr);
2980 return (DCMD_ERR);
2982 ipif_header(verbose);
2983 if (mdb_vread(&id.ill, sizeof (ill_t),
2984 (uintptr_t)ipif.ipif_ill) == -1) {
2985 mdb_warn("failed to read ill at %p", ipif.ipif_ill);
2986 return (WALK_NEXT);
2988 return (ipif_format(addr, &ipif, &id));
2989 } else {
2990 ipif_header(verbose);
2991 if (mdb_walk("ipif", (mdb_walk_cb_t)ipif_cb, &id) == -1) {
2992 mdb_warn("failed to walk ipifs\n");
2993 return (DCMD_ERR);
2996 return (DCMD_OK);
2999 static void
3000 ipif_help(void)
3002 mdb_printf("Prints the following fields: ipif ptr, name, "
3003 "count, ill ptr, state flags and ipif flags.\n"
3004 "The count field is a sum of individual refcnts and is expanded "
3005 "with the -v option.\n"
3006 "The flags field shows the following:"
3007 "\n\tUNN -> UNNUMBERED, DHCP -> DHCPRUNNING, PRIV -> PRIVATE, "
3008 "\n\tNOXMT -> NOXMIT, NOLCL -> NOLOCAL, DEPR -> DEPRECATED, "
3009 "\n\tPREF -> PREFERRED, TEMP -> TEMPORARY, ACONF -> ADDRCONF, "
3010 "\n\tANY -> ANYCAST, NFAIL -> NOFAILOVER, "
3011 "\n\tADR -> ipif_addr_ready, MU -> ipif_multicast_up, "
3012 "\n\tWU -> ipif_was_up, WD -> ipif_was_dup, "
3013 "JA -> ipif_joined_allhosts.\n\n");
3014 mdb_printf("Options:\n");
3015 mdb_printf("\t-P v4 | v6"
3016 "\tfilter ipif structures on ills for the specified protocol\n");
3019 static int
3020 conn_status_walk_fanout(uintptr_t addr, mdb_walk_state_t *wsp,
3021 const char *walkname)
3023 if (mdb_pwalk(walkname, wsp->walk_callback, wsp->walk_cbdata,
3024 addr) == -1) {
3025 mdb_warn("couldn't walk '%s' at %p", walkname, addr);
3026 return (WALK_ERR);
3028 return (WALK_NEXT);
3031 static int
3032 conn_status_walk_step(mdb_walk_state_t *wsp)
3034 uintptr_t addr = wsp->walk_addr;
3036 (void) conn_status_walk_fanout(addr, wsp, "udp_hash");
3037 (void) conn_status_walk_fanout(addr, wsp, "conn_hash");
3038 (void) conn_status_walk_fanout(addr, wsp, "bind_hash");
3039 (void) conn_status_walk_fanout(addr, wsp, "proto_hash");
3040 (void) conn_status_walk_fanout(addr, wsp, "proto_v6_hash");
3041 return (WALK_NEXT);
3044 /* ARGSUSED */
3045 static int
3046 conn_status_cb(uintptr_t addr, const void *walk_data, void *private)
3048 netstack_t nss;
3049 char src_addrstr[INET6_ADDRSTRLEN];
3050 char rem_addrstr[INET6_ADDRSTRLEN];
3051 const ipcl_hash_walk_data_t *iw = walk_data;
3052 conn_t c, *conn = &c;
3053 in_port_t lport, fport;
3055 if (iw != NULL)
3056 conn = iw->conn;
3057 else if (mdb_vread(conn, sizeof (conn_t), addr) == -1) {
3058 mdb_warn("failed to read conn_t at %p", addr);
3059 return (WALK_ERR);
3061 if (mdb_vread(&nss, sizeof (nss),
3062 (uintptr_t)conn->conn_netstack) == -1) {
3063 mdb_warn("failed to read netstack_t %p",
3064 conn->conn_netstack);
3065 return (WALK_ERR);
3067 mdb_printf("%-?p %-?p %?d %?d\n", addr, conn->conn_wq,
3068 nss.netstack_stackid, conn->conn_zoneid);
3070 if (conn->conn_family == AF_INET6) {
3071 mdb_snprintf(src_addrstr, sizeof (rem_addrstr), "%N",
3072 &conn->conn_laddr_v6);
3073 mdb_snprintf(rem_addrstr, sizeof (rem_addrstr), "%N",
3074 &conn->conn_faddr_v6);
3075 } else {
3076 mdb_snprintf(src_addrstr, sizeof (src_addrstr), "%I",
3077 V4_PART_OF_V6((conn->conn_laddr_v6)));
3078 mdb_snprintf(rem_addrstr, sizeof (rem_addrstr), "%I",
3079 V4_PART_OF_V6((conn->conn_faddr_v6)));
3081 mdb_nhconvert(&lport, &conn->conn_lport, sizeof (lport));
3082 mdb_nhconvert(&fport, &conn->conn_fport, sizeof (fport));
3083 mdb_printf("%s:%-5d\n%s:%-5d\n",
3084 src_addrstr, lport, rem_addrstr, fport);
3085 return (WALK_NEXT);
3088 static void
3089 conn_header(void)
3091 mdb_printf("%-?s %-?s %?s %?s\n%s\n%s\n",
3092 "ADDR", "WQ", "STACK", "ZONE", "SRC:PORT", "DEST:PORT");
3093 mdb_printf("%<u>%80s%</u>\n", "");
3096 /*ARGSUSED*/
3097 static int
3098 conn_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3100 conn_header();
3101 if (flags & DCMD_ADDRSPEC) {
3102 (void) conn_status_cb(addr, NULL, NULL);
3103 } else {
3104 if (mdb_walk("conn_status", (mdb_walk_cb_t)conn_status_cb,
3105 NULL) == -1) {
3106 mdb_warn("failed to walk conn_fanout");
3107 return (DCMD_ERR);
3110 return (DCMD_OK);
3113 static void
3114 conn_status_help(void)
3116 mdb_printf("Prints conn_t structures from the following hash tables: "
3117 "\n\tips_ipcl_udp_fanout\n\tips_ipcl_bind_fanout"
3118 "\n\tips_ipcl_conn_fanout\n\tips_ipcl_proto_fanout_v4"
3119 "\n\tips_ipcl_proto_fanout_v6\n");
3122 static int
3123 srcid_walk_step(mdb_walk_state_t *wsp)
3125 if (mdb_pwalk("srcid_list", wsp->walk_callback, wsp->walk_cbdata,
3126 wsp->walk_addr) == -1) {
3127 mdb_warn("can't walk 'srcid_list'");
3128 return (WALK_ERR);
3130 return (WALK_NEXT);
3133 /* ARGSUSED */
3134 static int
3135 srcid_status_cb(uintptr_t addr, const void *walk_data,
3136 void *private)
3138 srcid_map_t smp;
3140 if (mdb_vread(&smp, sizeof (srcid_map_t), addr) == -1) {
3141 mdb_warn("failed to read srcid_map at %p", addr);
3142 return (WALK_ERR);
3144 mdb_printf("%-?p %3d %4d %6d %N\n",
3145 addr, smp.sm_srcid, smp.sm_zoneid, smp.sm_refcnt,
3146 &smp.sm_addr);
3147 return (WALK_NEXT);
3150 static void
3151 srcid_header(void)
3153 mdb_printf("%-?s %3s %4s %6s %s\n",
3154 "ADDR", "ID", "ZONE", "REFCNT", "IPADDR");
3155 mdb_printf("%<u>%80s%</u>\n", "");
3158 /*ARGSUSED*/
3159 static int
3160 srcid_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3162 srcid_header();
3163 if (flags & DCMD_ADDRSPEC) {
3164 (void) srcid_status_cb(addr, NULL, NULL);
3165 } else {
3166 if (mdb_walk("srcid", (mdb_walk_cb_t)srcid_status_cb,
3167 NULL) == -1) {
3168 mdb_warn("failed to walk srcid_map");
3169 return (DCMD_ERR);
3172 return (DCMD_OK);
3175 static int
3176 ilb_stacks_walk_step(mdb_walk_state_t *wsp)
3178 return (ns_walk_step(wsp, NS_ILB));
3181 static int
3182 ilb_rules_walk_init(mdb_walk_state_t *wsp)
3184 ilb_stack_t ilbs;
3186 if (wsp->walk_addr == (uintptr_t)NULL)
3187 return (WALK_ERR);
3189 if (mdb_vread(&ilbs, sizeof (ilbs), wsp->walk_addr) == -1) {
3190 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr);
3191 return (WALK_ERR);
3193 if ((wsp->walk_addr = (uintptr_t)ilbs.ilbs_rule_head) !=
3194 (uintptr_t)NULL)
3195 return (WALK_NEXT);
3196 else
3197 return (WALK_DONE);
3200 static int
3201 ilb_rules_walk_step(mdb_walk_state_t *wsp)
3203 ilb_rule_t rule;
3204 int status;
3206 if (mdb_vread(&rule, sizeof (rule), wsp->walk_addr) == -1) {
3207 mdb_warn("failed to read ilb_rule_t at %p", wsp->walk_addr);
3208 return (WALK_ERR);
3210 status = wsp->walk_callback(wsp->walk_addr, &rule, wsp->walk_cbdata);
3211 if (status != WALK_NEXT)
3212 return (status);
3213 if ((wsp->walk_addr = (uintptr_t)rule.ir_next) == (uintptr_t)NULL)
3214 return (WALK_DONE);
3215 else
3216 return (WALK_NEXT);
3219 static int
3220 ilb_servers_walk_init(mdb_walk_state_t *wsp)
3222 ilb_rule_t rule;
3224 if (wsp->walk_addr == (uintptr_t)NULL)
3225 return (WALK_ERR);
3227 if (mdb_vread(&rule, sizeof (rule), wsp->walk_addr) == -1) {
3228 mdb_warn("failed to read ilb_rule_t at %p", wsp->walk_addr);
3229 return (WALK_ERR);
3231 if ((wsp->walk_addr = (uintptr_t)rule.ir_servers) != (uintptr_t)NULL)
3232 return (WALK_NEXT);
3233 else
3234 return (WALK_DONE);
3237 static int
3238 ilb_servers_walk_step(mdb_walk_state_t *wsp)
3240 ilb_server_t server;
3241 int status;
3243 if (mdb_vread(&server, sizeof (server), wsp->walk_addr) == -1) {
3244 mdb_warn("failed to read ilb_server_t at %p", wsp->walk_addr);
3245 return (WALK_ERR);
3247 status = wsp->walk_callback(wsp->walk_addr, &server, wsp->walk_cbdata);
3248 if (status != WALK_NEXT)
3249 return (status);
3250 if ((wsp->walk_addr = (uintptr_t)server.iser_next) == (uintptr_t)NULL)
3251 return (WALK_DONE);
3252 else
3253 return (WALK_NEXT);
3257 * Helper structure for ilb_nat_src walker. It stores the current index of the
3258 * nat src table.
3260 typedef struct {
3261 ilb_stack_t ilbs;
3262 int idx;
3263 } ilb_walk_t;
3265 /* Copy from list.c */
3266 #define list_object(a, node) ((void *)(((char *)node) - (a)->list_offset))
3268 static int
3269 ilb_nat_src_walk_init(mdb_walk_state_t *wsp)
3271 int i;
3272 ilb_walk_t *ns_walk;
3273 ilb_nat_src_entry_t *entry = NULL;
3275 if (wsp->walk_addr == (uintptr_t)NULL)
3276 return (WALK_ERR);
3278 ns_walk = mdb_alloc(sizeof (ilb_walk_t), UM_SLEEP);
3279 if (mdb_vread(&ns_walk->ilbs, sizeof (ns_walk->ilbs),
3280 wsp->walk_addr) == -1) {
3281 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr);
3282 mdb_free(ns_walk, sizeof (ilb_walk_t));
3283 return (WALK_ERR);
3286 if (ns_walk->ilbs.ilbs_nat_src == NULL) {
3287 mdb_free(ns_walk, sizeof (ilb_walk_t));
3288 return (WALK_DONE);
3291 wsp->walk_data = ns_walk;
3292 for (i = 0; i < ns_walk->ilbs.ilbs_nat_src_hash_size; i++) {
3293 list_t head;
3294 char *khead;
3296 /* Read in the nsh_head in the i-th element of the array. */
3297 khead = (char *)ns_walk->ilbs.ilbs_nat_src + i *
3298 sizeof (ilb_nat_src_hash_t);
3299 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3300 mdb_warn("failed to read ilbs_nat_src at %p\n", khead);
3301 return (WALK_ERR);
3305 * Note that list_next points to a kernel address and we need
3306 * to compare list_next with the kernel address of the list
3307 * head. So we need to calculate the address manually.
3309 if ((char *)head.list_head.list_next != khead +
3310 offsetof(list_t, list_head)) {
3311 entry = list_object(&head, head.list_head.list_next);
3312 break;
3316 if (entry == NULL)
3317 return (WALK_DONE);
3319 wsp->walk_addr = (uintptr_t)entry;
3320 ns_walk->idx = i;
3321 return (WALK_NEXT);
3324 static int
3325 ilb_nat_src_walk_step(mdb_walk_state_t *wsp)
3327 int status;
3328 ilb_nat_src_entry_t entry, *next_entry;
3329 ilb_walk_t *ns_walk;
3330 ilb_stack_t *ilbs;
3331 list_t head;
3332 char *khead;
3333 int i;
3335 if (mdb_vread(&entry, sizeof (ilb_nat_src_entry_t),
3336 wsp->walk_addr) == -1) {
3337 mdb_warn("failed to read ilb_nat_src_entry_t at %p",
3338 wsp->walk_addr);
3339 return (WALK_ERR);
3341 status = wsp->walk_callback(wsp->walk_addr, &entry, wsp->walk_cbdata);
3342 if (status != WALK_NEXT)
3343 return (status);
3345 ns_walk = (ilb_walk_t *)wsp->walk_data;
3346 ilbs = &ns_walk->ilbs;
3347 i = ns_walk->idx;
3349 /* Read in the nsh_head in the i-th element of the array. */
3350 khead = (char *)ilbs->ilbs_nat_src + i * sizeof (ilb_nat_src_hash_t);
3351 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3352 mdb_warn("failed to read ilbs_nat_src at %p\n", khead);
3353 return (WALK_ERR);
3357 * Check if there is still entry in the current list.
3359 * Note that list_next points to a kernel address and we need to
3360 * compare list_next with the kernel address of the list head.
3361 * So we need to calculate the address manually.
3363 if ((char *)entry.nse_link.list_next != khead + offsetof(list_t,
3364 list_head)) {
3365 wsp->walk_addr = (uintptr_t)list_object(&head,
3366 entry.nse_link.list_next);
3367 return (WALK_NEXT);
3370 /* Start with the next bucket in the array. */
3371 next_entry = NULL;
3372 for (i++; i < ilbs->ilbs_nat_src_hash_size; i++) {
3373 khead = (char *)ilbs->ilbs_nat_src + i *
3374 sizeof (ilb_nat_src_hash_t);
3375 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3376 mdb_warn("failed to read ilbs_nat_src at %p\n", khead);
3377 return (WALK_ERR);
3380 if ((char *)head.list_head.list_next != khead +
3381 offsetof(list_t, list_head)) {
3382 next_entry = list_object(&head,
3383 head.list_head.list_next);
3384 break;
3388 if (next_entry == NULL)
3389 return (WALK_DONE);
3391 wsp->walk_addr = (uintptr_t)next_entry;
3392 ns_walk->idx = i;
3393 return (WALK_NEXT);
3396 static void
3397 ilb_common_walk_fini(mdb_walk_state_t *wsp)
3399 ilb_walk_t *walk;
3401 walk = (ilb_walk_t *)wsp->walk_data;
3402 if (walk == NULL)
3403 return;
3404 mdb_free(walk, sizeof (ilb_walk_t *));
3407 static int
3408 ilb_conn_walk_init(mdb_walk_state_t *wsp)
3410 int i;
3411 ilb_walk_t *conn_walk;
3412 ilb_conn_hash_t head;
3414 if (wsp->walk_addr == (uintptr_t)NULL)
3415 return (WALK_ERR);
3417 conn_walk = mdb_alloc(sizeof (ilb_walk_t), UM_SLEEP);
3418 if (mdb_vread(&conn_walk->ilbs, sizeof (conn_walk->ilbs),
3419 wsp->walk_addr) == -1) {
3420 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr);
3421 mdb_free(conn_walk, sizeof (ilb_walk_t));
3422 return (WALK_ERR);
3425 if (conn_walk->ilbs.ilbs_c2s_conn_hash == NULL) {
3426 mdb_free(conn_walk, sizeof (ilb_walk_t));
3427 return (WALK_DONE);
3430 wsp->walk_data = conn_walk;
3431 for (i = 0; i < conn_walk->ilbs.ilbs_conn_hash_size; i++) {
3432 char *khead;
3434 /* Read in the nsh_head in the i-th element of the array. */
3435 khead = (char *)conn_walk->ilbs.ilbs_c2s_conn_hash + i *
3436 sizeof (ilb_conn_hash_t);
3437 if (mdb_vread(&head, sizeof (ilb_conn_hash_t),
3438 (uintptr_t)khead) == -1) {
3439 mdb_warn("failed to read ilbs_c2s_conn_hash at %p\n",
3440 khead);
3441 return (WALK_ERR);
3444 if (head.ilb_connp != NULL)
3445 break;
3448 if (head.ilb_connp == NULL)
3449 return (WALK_DONE);
3451 wsp->walk_addr = (uintptr_t)head.ilb_connp;
3452 conn_walk->idx = i;
3453 return (WALK_NEXT);
3456 static int
3457 ilb_conn_walk_step(mdb_walk_state_t *wsp)
3459 int status;
3460 ilb_conn_t conn;
3461 ilb_walk_t *conn_walk;
3462 ilb_stack_t *ilbs;
3463 ilb_conn_hash_t head;
3464 char *khead;
3465 int i;
3467 if (mdb_vread(&conn, sizeof (ilb_conn_t), wsp->walk_addr) == -1) {
3468 mdb_warn("failed to read ilb_conn_t at %p", wsp->walk_addr);
3469 return (WALK_ERR);
3472 status = wsp->walk_callback(wsp->walk_addr, &conn, wsp->walk_cbdata);
3473 if (status != WALK_NEXT)
3474 return (status);
3476 conn_walk = (ilb_walk_t *)wsp->walk_data;
3477 ilbs = &conn_walk->ilbs;
3478 i = conn_walk->idx;
3480 /* Check if there is still entry in the current list. */
3481 if (conn.conn_c2s_next != NULL) {
3482 wsp->walk_addr = (uintptr_t)conn.conn_c2s_next;
3483 return (WALK_NEXT);
3486 /* Start with the next bucket in the array. */
3487 for (i++; i < ilbs->ilbs_conn_hash_size; i++) {
3488 khead = (char *)ilbs->ilbs_c2s_conn_hash + i *
3489 sizeof (ilb_conn_hash_t);
3490 if (mdb_vread(&head, sizeof (ilb_conn_hash_t),
3491 (uintptr_t)khead) == -1) {
3492 mdb_warn("failed to read ilbs_c2s_conn_hash at %p\n",
3493 khead);
3494 return (WALK_ERR);
3497 if (head.ilb_connp != NULL)
3498 break;
3501 if (head.ilb_connp == NULL)
3502 return (WALK_DONE);
3504 wsp->walk_addr = (uintptr_t)head.ilb_connp;
3505 conn_walk->idx = i;
3506 return (WALK_NEXT);
3509 static int
3510 ilb_sticky_walk_init(mdb_walk_state_t *wsp)
3512 int i;
3513 ilb_walk_t *sticky_walk;
3514 ilb_sticky_t *st = NULL;
3516 if (wsp->walk_addr == (uintptr_t)NULL)
3517 return (WALK_ERR);
3519 sticky_walk = mdb_alloc(sizeof (ilb_walk_t), UM_SLEEP);
3520 if (mdb_vread(&sticky_walk->ilbs, sizeof (sticky_walk->ilbs),
3521 wsp->walk_addr) == -1) {
3522 mdb_warn("failed to read ilb_stack_t at %p", wsp->walk_addr);
3523 mdb_free(sticky_walk, sizeof (ilb_walk_t));
3524 return (WALK_ERR);
3527 if (sticky_walk->ilbs.ilbs_sticky_hash == NULL) {
3528 mdb_free(sticky_walk, sizeof (ilb_walk_t));
3529 return (WALK_DONE);
3532 wsp->walk_data = sticky_walk;
3533 for (i = 0; i < sticky_walk->ilbs.ilbs_sticky_hash_size; i++) {
3534 list_t head;
3535 char *khead;
3537 /* Read in the nsh_head in the i-th element of the array. */
3538 khead = (char *)sticky_walk->ilbs.ilbs_sticky_hash + i *
3539 sizeof (ilb_sticky_hash_t);
3540 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3541 mdb_warn("failed to read ilbs_sticky_hash at %p\n",
3542 khead);
3543 return (WALK_ERR);
3547 * Note that list_next points to a kernel address and we need
3548 * to compare list_next with the kernel address of the list
3549 * head. So we need to calculate the address manually.
3551 if ((char *)head.list_head.list_next != khead +
3552 offsetof(list_t, list_head)) {
3553 st = list_object(&head, head.list_head.list_next);
3554 break;
3558 if (st == NULL)
3559 return (WALK_DONE);
3561 wsp->walk_addr = (uintptr_t)st;
3562 sticky_walk->idx = i;
3563 return (WALK_NEXT);
3566 static int
3567 ilb_sticky_walk_step(mdb_walk_state_t *wsp)
3569 int status;
3570 ilb_sticky_t st, *st_next;
3571 ilb_walk_t *sticky_walk;
3572 ilb_stack_t *ilbs;
3573 list_t head;
3574 char *khead;
3575 int i;
3577 if (mdb_vread(&st, sizeof (ilb_sticky_t), wsp->walk_addr) == -1) {
3578 mdb_warn("failed to read ilb_sticky_t at %p", wsp->walk_addr);
3579 return (WALK_ERR);
3582 status = wsp->walk_callback(wsp->walk_addr, &st, wsp->walk_cbdata);
3583 if (status != WALK_NEXT)
3584 return (status);
3586 sticky_walk = (ilb_walk_t *)wsp->walk_data;
3587 ilbs = &sticky_walk->ilbs;
3588 i = sticky_walk->idx;
3590 /* Read in the nsh_head in the i-th element of the array. */
3591 khead = (char *)ilbs->ilbs_sticky_hash + i * sizeof (ilb_sticky_hash_t);
3592 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3593 mdb_warn("failed to read ilbs_sticky_hash at %p\n", khead);
3594 return (WALK_ERR);
3598 * Check if there is still entry in the current list.
3600 * Note that list_next points to a kernel address and we need to
3601 * compare list_next with the kernel address of the list head.
3602 * So we need to calculate the address manually.
3604 if ((char *)st.list.list_next != khead + offsetof(list_t,
3605 list_head)) {
3606 wsp->walk_addr = (uintptr_t)list_object(&head,
3607 st.list.list_next);
3608 return (WALK_NEXT);
3611 /* Start with the next bucket in the array. */
3612 st_next = NULL;
3613 for (i++; i < ilbs->ilbs_nat_src_hash_size; i++) {
3614 khead = (char *)ilbs->ilbs_sticky_hash + i *
3615 sizeof (ilb_sticky_hash_t);
3616 if (mdb_vread(&head, sizeof (list_t), (uintptr_t)khead) == -1) {
3617 mdb_warn("failed to read ilbs_sticky_hash at %p\n",
3618 khead);
3619 return (WALK_ERR);
3622 if ((char *)head.list_head.list_next != khead +
3623 offsetof(list_t, list_head)) {
3624 st_next = list_object(&head,
3625 head.list_head.list_next);
3626 break;
3630 if (st_next == NULL)
3631 return (WALK_DONE);
3633 wsp->walk_addr = (uintptr_t)st_next;
3634 sticky_walk->idx = i;
3635 return (WALK_NEXT);