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