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