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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <mdb/mdb_modapi.h>
27 #include <mdb/mdb_ks.h>
28 #include <mdb/mdb_ctf.h>
29 #include <sys/types.h>
30 #include <sys/tihdr.h>
31 #include <inet/led.h>
32 #include <inet/common.h>
33 #include <netinet/in.h>
34 #include <netinet/ip6.h>
35 #include <netinet/icmp6.h>
36 #include <inet/ip.h>
37 #include <inet/ip6.h>
38 #include <inet/ipclassifier.h>
39 #include <inet/tcp.h>
40 #include <sys/stream.h>
41 #include <sys/vfs.h>
42 #include <sys/stropts.h>
43 #include <sys/tpicommon.h>
44 #include <sys/socket.h>
45 #include <sys/socketvar.h>
46 #include <sys/cred_impl.h>
47 #include <inet/udp_impl.h>
48 #include <inet/rawip_impl.h>
49 #include <inet/mi.h>
50 #include <inet/dccp_impl.h>
51 #include <fs/sockfs/socktpi_impl.h>
52 #include <net/bridge_impl.h>
53 #include <io/trill_impl.h>
54 #include <sys/mac_impl.h>
55
56 #define ADDR_V6_WIDTH 23
57 #define ADDR_V4_WIDTH 15
58
59 #define NETSTAT_ALL 0x01
60 #define NETSTAT_VERBOSE 0x02
61 #define NETSTAT_ROUTE 0x04
62 #define NETSTAT_V4 0x08
63 #define NETSTAT_V6 0x10
64 #define NETSTAT_UNIX 0x20
65
66 #define NETSTAT_FIRST 0x80000000u
67
68 typedef struct netstat_cb_data_s {
69 uint_t opts;
70 conn_t conn;
71 int af;
72 } netstat_cb_data_t;
73
74 int
75 icmp_stacks_walk_init(mdb_walk_state_t *wsp)
76 {
77 if (mdb_layered_walk("netstack", wsp) == -1) {
78 mdb_warn("can't walk 'netstack'");
79 return (WALK_ERR);
80 }
81 return (WALK_NEXT);
82 }
83
84 int
85 icmp_stacks_walk_step(mdb_walk_state_t *wsp)
86 {
87 uintptr_t kaddr;
88 netstack_t nss;
89
90 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
91 mdb_warn("can't read netstack at %p", wsp->walk_addr);
92 return (WALK_ERR);
93 }
94 kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP];
95 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
96 }
97
98 int
99 tcp_stacks_walk_init(mdb_walk_state_t *wsp)
100 {
101 if (mdb_layered_walk("netstack", wsp) == -1) {
102 mdb_warn("can't walk 'netstack'");
103 return (WALK_ERR);
104 }
105 return (WALK_NEXT);
106 }
107
108 int
109 tcp_stacks_walk_step(mdb_walk_state_t *wsp)
110 {
111 uintptr_t kaddr;
112 netstack_t nss;
113
114 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
115 mdb_warn("can't read netstack at %p", wsp->walk_addr);
116 return (WALK_ERR);
117 }
118 kaddr = (uintptr_t)nss.netstack_modules[NS_TCP];
119 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
120 }
121
122 int
123 udp_stacks_walk_init(mdb_walk_state_t *wsp)
124 {
125 if (mdb_layered_walk("netstack", wsp) == -1) {
126 mdb_warn("can't walk 'netstack'");
127 return (WALK_ERR);
128 }
129 return (WALK_NEXT);
130 }
131
132 int
133 udp_stacks_walk_step(mdb_walk_state_t *wsp)
134 {
135 uintptr_t kaddr;
136 netstack_t nss;
137
138 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
139 mdb_warn("can't read netstack at %p", wsp->walk_addr);
140 return (WALK_ERR);
141 }
142 kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
143 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
144 }
145
146 int
147 dccp_stacks_walk_init(mdb_walk_state_t *wsp)
148 {
149 if (mdb_layered_walk("netstack", wsp) == -1) {
150 mdb_warn("can't walk 'netstack'");
151 return (WALK_ERR);
152 }
153 return (WALK_NEXT);
154 }
155
156 int
157 dccp_stacks_walk_step(mdb_walk_state_t *wsp)
158 {
159 uintptr_t kaddr;
160 netstack_t nss;
161
162 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
163 mdb_warn("can't read netstack at %p", wsp->walk_addr);
164 return (WALK_ERR);
165 }
166 kaddr = (uintptr_t)nss.netstack_modules[NS_DCCP];
167 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
168 }
169
170 /*
171 * Print an IPv4 address and port number in a compact and easy to read format
172 * The arguments are in network byte order
173 */
174 static void
175 net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
176 {
177 uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
178
179 mdb_nhconvert(&nport, &nport, sizeof (nport));
180 mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
181 }
182
183 /*
184 * Print an IPv6 address and port number in a compact and easy to read format
185 * The arguments are in network byte order
186 */
187 static void
188 net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
189 {
190 mdb_nhconvert(&nport, &nport, sizeof (nport));
191 mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
192 }
193
194 static int
195 net_tcp_active(const tcp_t *tcp)
196 {
197 return (tcp->tcp_state >= TCPS_ESTABLISHED);
198 }
199
200 static int
201 net_tcp_ipv4(const tcp_t *tcp)
202 {
203 return ((tcp->tcp_connp->conn_ipversion == IPV4_VERSION) ||
204 (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_connp->conn_laddr_v6) &&
205 (tcp->tcp_state <= TCPS_LISTEN)));
206 }
207
208 static int
209 net_tcp_ipv6(const tcp_t *tcp)
210 {
211 return (tcp->tcp_connp->conn_ipversion == IPV6_VERSION);
212 }
213
214 static int
215 net_udp_active(const udp_t *udp)
216 {
217 return ((udp->udp_state == TS_IDLE) ||
218 (udp->udp_state == TS_DATA_XFER));
219 }
220
221 static int
222 net_udp_ipv4(const udp_t *udp)
223 {
224 return ((udp->udp_connp->conn_ipversion == IPV4_VERSION) ||
225 (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_connp->conn_laddr_v6) &&
226 (udp->udp_state <= TS_IDLE)));
227 }
228
229 static int
230 net_udp_ipv6(const udp_t *udp)
231 {
232 return (udp->udp_connp->conn_ipversion == IPV6_VERSION);
233 }
234
235 static int
236 net_dccp_active(const dccp_t *dccp)
237 {
238 return ((dccp->dccp_state == TS_IDLE) ||
239 (dccp->dccp_state == TS_DATA_XFER));
240 }
241
242 static int
243 net_dccp_ipv4(const dccp_t *dccp)
244 {
245 return ((dccp->dccp_connp->conn_ipversion == IPV4_VERSION) ||
246 (IN6_IS_ADDR_UNSPECIFIED(&dccp->dccp_connp->conn_laddr_v6) &&
247 (dccp->dccp_state <= DCCPS_LISTEN)));
248 }
249
250 static int
251 net_dccp_ipv6(const dccp_t *dccp)
252 {
253 return (dccp->dccp_connp->conn_ipversion == IPV6_VERSION);
254 }
255
256 int
257 sonode_walk_init(mdb_walk_state_t *wsp)
258 {
259 if (wsp->walk_addr == NULL) {
260 GElf_Sym sym;
261 struct socklist *slp;
262
263 if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
264 mdb_warn("failed to lookup sockfs`socklist");
265 return (WALK_ERR);
266 }
267
268 slp = (struct socklist *)(uintptr_t)sym.st_value;
269
270 if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
271 (uintptr_t)&slp->sl_list) == -1) {
272 mdb_warn("failed to read address of initial sonode "
273 "at %p", &slp->sl_list);
274 return (WALK_ERR);
275 }
276 }
277
278 wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP);
279 return (WALK_NEXT);
280 }
281
282 int
283 sonode_walk_step(mdb_walk_state_t *wsp)
284 {
285 int status;
286 struct sotpi_sonode *stp;
287
288 if (wsp->walk_addr == NULL)
289 return (WALK_DONE);
290
291 if (mdb_vread(wsp->walk_data, sizeof (struct sotpi_sonode),
292 wsp->walk_addr) == -1) {
293 mdb_warn("failed to read sonode at %p", wsp->walk_addr);
294 return (WALK_ERR);
295 }
296
297 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
298 wsp->walk_cbdata);
299
300 stp = wsp->walk_data;
301
302 wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so;
303 return (status);
304 }
305
306 void
307 sonode_walk_fini(mdb_walk_state_t *wsp)
308 {
309 mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode));
310 }
311
312 struct mi_walk_data {
313 uintptr_t mi_wd_miofirst;
314 MI_O mi_wd_miodata;
315 };
316
317 int
318 mi_walk_init(mdb_walk_state_t *wsp)
319 {
320 struct mi_walk_data *wdp;
321
322 if (wsp->walk_addr == NULL) {
323 mdb_warn("mi doesn't support global walks\n");
324 return (WALK_ERR);
325 }
326
327 wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
328
329 /* So that we do not immediately return WALK_DONE below */
330 wdp->mi_wd_miofirst = NULL;
331
332 wsp->walk_data = wdp;
333 return (WALK_NEXT);
334 }
335
336 int
337 mi_walk_step(mdb_walk_state_t *wsp)
338 {
339 struct mi_walk_data *wdp = wsp->walk_data;
340 MI_OP miop = &wdp->mi_wd_miodata;
341 int status;
342
343 /* Always false in the first iteration */
344 if ((wsp->walk_addr == (uintptr_t)NULL) ||
345 (wsp->walk_addr == wdp->mi_wd_miofirst)) {
346 return (WALK_DONE);
347 }
348
349 if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
350 mdb_warn("failed to read MI object at %p", wsp->walk_addr);
351 return (WALK_ERR);
352 }
353
354 /* Only true in the first iteration */
355 if (wdp->mi_wd_miofirst == NULL) {
356 wdp->mi_wd_miofirst = wsp->walk_addr;
357 status = WALK_NEXT;
358 } else {
359 status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O),
360 &miop[1], wsp->walk_cbdata);
361 }
362
363 wsp->walk_addr = (uintptr_t)miop->mi_o_next;
364 return (status);
365 }
366
367 void
368 mi_walk_fini(mdb_walk_state_t *wsp)
369 {
370 mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
371 }
372
373 typedef struct mi_payload_walk_arg_s {
374 const char *mi_pwa_walker; /* Underlying walker */
375 const off_t mi_pwa_head_off; /* Offset for mi_o_head_t * in stack */
376 const size_t mi_pwa_size; /* size of mi payload */
377 const uint_t mi_pwa_flags; /* device and/or module */
378 } mi_payload_walk_arg_t;
379
380 #define MI_PAYLOAD_DEVICE 0x1
381 #define MI_PAYLOAD_MODULE 0x2
382
383 int
384 mi_payload_walk_init(mdb_walk_state_t *wsp)
385 {
386 const mi_payload_walk_arg_t *arg = wsp->walk_arg;
387
388 if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) {
389 mdb_warn("can't walk '%s'", arg->mi_pwa_walker);
390 return (WALK_ERR);
391 }
392 return (WALK_NEXT);
393 }
394
395 int
396 mi_payload_walk_step(mdb_walk_state_t *wsp)
397 {
398 const mi_payload_walk_arg_t *arg = wsp->walk_arg;
399 uintptr_t kaddr;
400
401 kaddr = wsp->walk_addr + arg->mi_pwa_head_off;
402
403 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
404 mdb_warn("can't read address of mi head at %p for %s",
405 kaddr, arg->mi_pwa_walker);
406 return (WALK_ERR);
407 }
408
409 if (kaddr == 0) {
410 /* Empty list */
411 return (WALK_DONE);
412 }
413
414 if (mdb_pwalk("genunix`mi", wsp->walk_callback,
415 wsp->walk_cbdata, kaddr) == -1) {
416 mdb_warn("failed to walk genunix`mi");
417 return (WALK_ERR);
418 }
419 return (WALK_NEXT);
420 }
421
422 const mi_payload_walk_arg_t mi_icmp_arg = {
423 "icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t),
424 MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
425 };
426
427 int
428 sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
429 {
430 const char *optf = NULL;
431 const char *optt = NULL;
432 const char *optp = NULL;
433 int family, type, proto;
434 int filter = 0;
435 struct sonode so;
436
437 if (!(flags & DCMD_ADDRSPEC)) {
438 if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
439 argv) == -1) {
440 mdb_warn("failed to walk sonode");
441 return (DCMD_ERR);
442 }
443
444 return (DCMD_OK);
445 }
446
447 if (mdb_getopts(argc, argv,
448 'f', MDB_OPT_STR, &optf,
449 't', MDB_OPT_STR, &optt,
450 'p', MDB_OPT_STR, &optp,
451 NULL) != argc)
452 return (DCMD_USAGE);
453
454 if (optf != NULL) {
455 if (strcmp("inet", optf) == 0)
456 family = AF_INET;
457 else if (strcmp("inet6", optf) == 0)
458 family = AF_INET6;
459 else if (strcmp("unix", optf) == 0)
460 family = AF_UNIX;
461 else
462 family = mdb_strtoull(optf);
463 filter = 1;
464 }
465
466 if (optt != NULL) {
467 if (strcmp("stream", optt) == 0)
468 type = SOCK_STREAM;
469 else if (strcmp("dgram", optt) == 0)
470 type = SOCK_DGRAM;
471 else if (strcmp("raw", optt) == 0)
472 type = SOCK_RAW;
473 else
474 type = mdb_strtoull(optt);
475 filter = 1;
476 }
477
478 if (optp != NULL) {
479 proto = mdb_strtoull(optp);
480 filter = 1;
481 }
482
483 if (DCMD_HDRSPEC(flags) && !filter) {
484 mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
485 "AccessVP%</u>\n", "Sonode:");
486 }
487
488 if (mdb_vread(&so, sizeof (so), addr) == -1) {
489 mdb_warn("failed to read sonode at %p", addr);
490 return (DCMD_ERR);
491 }
492
493 if ((optf != NULL) && (so.so_family != family))
494 return (DCMD_OK);
495
496 if ((optt != NULL) && (so.so_type != type))
497 return (DCMD_OK);
498
499 if ((optp != NULL) && (so.so_protocol != proto))
500 return (DCMD_OK);
501
502 if (filter) {
503 mdb_printf("%0?p\n", addr);
504 return (DCMD_OK);
505 }
506
507 mdb_printf("%0?p ", addr);
508
509 switch (so.so_family) {
510 case AF_UNIX:
511 mdb_printf("unix ");
512 break;
513 case AF_INET:
514 mdb_printf("inet ");
515 break;
516 case AF_INET6:
517 mdb_printf("inet6 ");
518 break;
519 default:
520 mdb_printf("%6hi", so.so_family);
521 }
522
523 switch (so.so_type) {
524 case SOCK_STREAM:
525 mdb_printf(" strm");
526 break;
527 case SOCK_DGRAM:
528 mdb_printf(" dgrm");
529 break;
530 case SOCK_RAW:
531 mdb_printf(" raw ");
532 break;
533 default:
534 mdb_printf(" %4hi", so.so_type);
535 }
536
537 mdb_printf(" %5hi %05x %04x %04hx\n",
538 so.so_protocol, so.so_state, so.so_mode,
539 so.so_flag);
540
541 return (DCMD_OK);
542 }
543
544 #define MI_PAYLOAD 0x1
545 #define MI_DEVICE 0x2
546 #define MI_MODULE 0x4
547
548 int
549 mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
550 {
551 uint_t opts = 0;
552 MI_O mio;
553
554 if (!(flags & DCMD_ADDRSPEC))
555 return (DCMD_USAGE);
556
557 if (mdb_getopts(argc, argv,
558 'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
559 'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
560 'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
561 NULL) != argc)
562 return (DCMD_USAGE);
563
564 if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
565 mdb_warn("at most one filter, d for devices or m "
566 "for modules, may be specified\n");
567 return (DCMD_USAGE);
568 }
569
570 if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
571 mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
572 "MI_O", "Next", "Prev");
573 }
574
575 if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
576 mdb_warn("failed to read mi object MI_O at %p", addr);
577 return (DCMD_ERR);
578 }
579
580 if (opts != 0) {
581 if (mio.mi_o_isdev == B_FALSE) {
582 /* mio is a module */
583 if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
584 return (DCMD_OK);
585 } else {
586 /* mio is a device */
587 if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
588 return (DCMD_OK);
589 }
590
591 if (opts & MI_PAYLOAD)
592 mdb_printf("%p\n", addr + sizeof (MI_O));
593 else
594 mdb_printf("%p\n", addr);
595 return (DCMD_OK);
596 }
597
598 mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
599
600 if (mio.mi_o_isdev == B_FALSE)
601 mdb_printf("FALSE");
602 else
603 mdb_printf("TRUE ");
604
605 mdb_printf(" %0?p\n", mio.mi_o_dev);
606
607 return (DCMD_OK);
608 }
609
610 static int
611 ns_to_stackid(uintptr_t kaddr)
612 {
613 netstack_t nss;
614
615 if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
616 mdb_warn("failed to read netstack_t %p", kaddr);
617 return (0);
618 }
619 return (nss.netstack_stackid);
620 }
621
622
623
624 static void
625 netstat_tcp_verbose_pr(const tcp_t *tcp)
626 {
627 mdb_printf(" %5i %08x %08x %5i %08x %08x %5li %5i\n",
628 tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
629 tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
630 }
631
632 /*ARGSUSED*/
633 static int
634 netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
635 {
636 netstat_cb_data_t *ncb = cb_data;
637 uint_t opts = ncb->opts;
638 int af = ncb->af;
639 uintptr_t tcp_kaddr;
640 conn_t *connp = &ncb->conn;
641 tcp_t tcps, *tcp;
642
643 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
644 mdb_warn("failed to read conn_t at %p", kaddr);
645 return (WALK_ERR);
646 }
647
648 tcp_kaddr = (uintptr_t)connp->conn_tcp;
649 if (mdb_vread(&tcps, sizeof (tcp_t), tcp_kaddr) == -1) {
650 mdb_warn("failed to read tcp_t at %p", tcp_kaddr);
651 return (WALK_ERR);
652 }
653
654 tcp = &tcps;
655 connp->conn_tcp = tcp;
656 tcp->tcp_connp = connp;
657
658 if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) ||
659 (af == AF_INET && !net_tcp_ipv4(tcp)) ||
660 (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
661 return (WALK_NEXT);
662 }
663
664 mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
665 if (af == AF_INET) {
666 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
667 mdb_printf(" ");
668 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
669 } else if (af == AF_INET6) {
670 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
671 mdb_printf(" ");
672 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
673 }
674 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
675 mdb_printf(" %4i\n", connp->conn_zoneid);
676 if (opts & NETSTAT_VERBOSE)
677 netstat_tcp_verbose_pr(tcp);
678
679 return (WALK_NEXT);
680 }
681
682 /*ARGSUSED*/
683 static int
684 netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
685 {
686 netstat_cb_data_t *ncb = cb_data;
687 uint_t opts = ncb->opts;
688 int af = ncb->af;
689 udp_t udp;
690 conn_t *connp = &ncb->conn;
691 char *state;
692
693 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
694 mdb_warn("failed to read conn_t at %p", kaddr);
695 return (WALK_ERR);
696 }
697
698 if (mdb_vread(&udp, sizeof (udp_t),
699 (uintptr_t)connp->conn_udp) == -1) {
700 mdb_warn("failed to read conn_udp at %p",
701 (uintptr_t)connp->conn_udp);
702 return (WALK_ERR);
703 }
704
705 connp->conn_udp = &udp;
706 udp.udp_connp = connp;
707
708 if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) ||
709 (af == AF_INET && !net_udp_ipv4(&udp)) ||
710 (af == AF_INET6 && !net_udp_ipv6(&udp))) {
711 return (WALK_NEXT);
712 }
713
714 if (udp.udp_state == TS_UNBND)
715 state = "UNBOUND";
716 else if (udp.udp_state == TS_IDLE)
717 state = "IDLE";
718 else if (udp.udp_state == TS_DATA_XFER)
719 state = "CONNECTED";
720 else
721 state = "UNKNOWN";
722
723 mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_udp, state);
724 if (af == AF_INET) {
725 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
726 mdb_printf(" ");
727 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
728 } else if (af == AF_INET6) {
729 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
730 mdb_printf(" ");
731 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
732 }
733 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
734 mdb_printf(" %4i\n", connp->conn_zoneid);
735
736 return (WALK_NEXT);
737 }
738
739 /*ARGSUSED*/
740 static int
741 netstat_icmp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
742 {
743 netstat_cb_data_t *ncb = cb_data;
744 int af = ncb->af;
745 icmp_t icmp;
746 conn_t *connp = &ncb->conn;
747 char *state;
748
749 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
750 mdb_warn("failed to read conn_t at %p", kaddr);
751 return (WALK_ERR);
752 }
753
754 if (mdb_vread(&icmp, sizeof (icmp_t),
755 (uintptr_t)connp->conn_icmp) == -1) {
756 mdb_warn("failed to read conn_icmp at %p",
757 (uintptr_t)connp->conn_icmp);
758 return (WALK_ERR);
759 }
760
761 connp->conn_icmp = &icmp;
762 icmp.icmp_connp = connp;
763
764 if ((af == AF_INET && connp->conn_ipversion != IPV4_VERSION) ||
765 (af == AF_INET6 && connp->conn_ipversion != IPV6_VERSION)) {
766 return (WALK_NEXT);
767 }
768
769 if (icmp.icmp_state == TS_UNBND)
770 state = "UNBOUND";
771 else if (icmp.icmp_state == TS_IDLE)
772 state = "IDLE";
773 else if (icmp.icmp_state == TS_DATA_XFER)
774 state = "CONNECTED";
775 else
776 state = "UNKNOWN";
777
778 mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state);
779 if (af == AF_INET) {
780 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
781 mdb_printf(" ");
782 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
783 } else if (af == AF_INET6) {
784 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
785 mdb_printf(" ");
786 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
787 }
788 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
789 mdb_printf(" %4i\n", connp->conn_zoneid);
790
791 return (WALK_NEXT);
792 }
793
794 static void
795 netstat_dccp_verbose_pr(const dccp_t *dccp)
796 {
797 /* XXX:DCCP
798 mdb_printf(" %5i %08x %08x %5i %08x %08x %5li %5i\n",
799 tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
800 tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
801 */
802 }
803
804 /*ARGSUSED*/
805 static int
806 netstat_dccp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
807 {
808 netstat_cb_data_t *ncb = cb_data;
809 uint_t opts = ncb->opts;
810 int af = ncb->af;
811 uintptr_t dccp_kaddr;
812 conn_t *connp = &ncb->conn;
813 dccp_t dccps, *dccp;
814
815 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
816 mdb_warn("failed to read conn_t at %p", kaddr);
817 return (WALK_ERR);
818 }
819
820 dccp_kaddr = (uintptr_t)connp->conn_dccp;
821 if (mdb_vread(&dccps, sizeof (dccp_t), dccp_kaddr) == -1) {
822 mdb_warn("failed to read tcp_t at %p", dccp_kaddr);
823 return (WALK_ERR);
824 }
825
826 dccp = &dccps;
827 connp->conn_dccp = dccp;
828 dccp->dccp_connp = connp;
829
830 if (!((opts & NETSTAT_ALL) || net_dccp_active(dccp)) ||
831 (af == AF_INET && !net_dccp_ipv4(dccp)) ||
832 (af == AF_INET6 && !net_dccp_ipv6(dccp))) {
833 return (WALK_NEXT);
834 }
835
836 mdb_printf("%0?p %2i ", dccp_kaddr, dccp->dccp_state);
837 if (af == AF_INET) {
838 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
839 mdb_printf(" ");
840 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
841 } else if (af == AF_INET6) {
842 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
843 mdb_printf(" ");
844 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
845 }
846 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
847 mdb_printf(" %4i\n", connp->conn_zoneid);
848 if (opts & NETSTAT_VERBOSE)
849 netstat_dccp_verbose_pr(dccp);
850
851 return (WALK_NEXT);
852 }
853
854 /*
855 * print the address of a unix domain socket
856 *
857 * so is the address of a AF_UNIX struct sonode in mdb's address space
858 * soa is the address of the struct soaddr to print
859 *
860 * returns 0 on success, -1 otherwise
861 */
862 static int
863 netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa)
864 {
865 const struct sonode *so = &st->st_sonode;
866 const char none[] = " (none)";
867
868 if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
869 if (st->st_info.sti_faddr_noxlate) {
870 mdb_printf("%-14s ", " (socketpair)");
871 } else {
872 if (soa->soa_len > sizeof (sa_family_t)) {
873 char addr[MAXPATHLEN + 1];
874
875 if (mdb_readstr(addr, sizeof (addr),
876 (uintptr_t)&soa->soa_sa->sa_data) == -1) {
877 mdb_warn("failed to read unix address "
878 "at %p", &soa->soa_sa->sa_data);
879 return (-1);
880 }
881
882 mdb_printf("%-14s ", addr);
883 } else {
884 mdb_printf("%-14s ", none);
885 }
886 }
887 } else {
888 mdb_printf("%-14s ", none);
889 }
890
891 return (0);
892 }
893
894 /* based on sockfs_snapshot */
895 /*ARGSUSED*/
896 static int
897 netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
898 {
899 const struct sotpi_sonode *st = walk_data;
900 const struct sonode *so = &st->st_sonode;
901 const struct sotpi_info *sti = &st->st_info;
902
903 if (so->so_count == 0)
904 return (WALK_NEXT);
905
906 if (so->so_family != AF_UNIX) {
907 mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
908 return (WALK_ERR);
909 }
910
911 mdb_printf("%-?p ", kaddr);
912
913 switch (sti->sti_serv_type) {
914 case T_CLTS:
915 mdb_printf("%-10s ", "dgram");
916 break;
917 case T_COTS:
918 mdb_printf("%-10s ", "stream");
919 break;
920 case T_COTS_ORD:
921 mdb_printf("%-10s ", "stream-ord");
922 break;
923 default:
924 mdb_printf("%-10i ", sti->sti_serv_type);
925 }
926
927 if ((so->so_state & SS_ISBOUND) &&
928 (sti->sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
929 mdb_printf("%0?p ", sti->sti_ux_laddr.soua_vp);
930 } else {
931 mdb_printf("%0?p ", NULL);
932 }
933
934 if ((so->so_state & SS_ISCONNECTED) &&
935 (sti->sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
936 mdb_printf("%0?p ", sti->sti_ux_faddr.soua_vp);
937 } else {
938 mdb_printf("%0?p ", NULL);
939 }
940
941 if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1)
942 return (WALK_ERR);
943
944 if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1)
945 return (WALK_ERR);
946
947 mdb_printf("%4i\n", so->so_zoneid);
948
949 return (WALK_NEXT);
950 }
951
952 static void
953 netstat_tcp_verbose_header_pr(void)
954 {
955 mdb_printf(" %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
956 "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
957 }
958
959 static void
960 get_ifname(const ire_t *ire, char *intf)
961 {
962 ill_t ill;
963
964 *intf = '\0';
965 if (ire->ire_ill != NULL) {
966 if (mdb_vread(&ill, sizeof (ill),
967 (uintptr_t)ire->ire_ill) == -1)
968 return;
969 (void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
970 (uintptr_t)ill.ill_name);
971 }
972 }
973
974 const in6_addr_t ipv6_all_ones =
975 { 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU };
976
977 static void
978 get_ireflags(const ire_t *ire, char *flags)
979 {
980 (void) strcpy(flags, "U");
981 /* RTF_INDIRECT wins over RTF_GATEWAY - don't display both */
982 if (ire->ire_flags & RTF_INDIRECT)
983 (void) strcat(flags, "I");
984 else if (ire->ire_type & IRE_OFFLINK)
985 (void) strcat(flags, "G");
986
987 /* IRE_IF_CLONE wins over RTF_HOST - don't display both */
988 if (ire->ire_type & IRE_IF_CLONE)
989 (void) strcat(flags, "C");
990 else if (ire->ire_ipversion == IPV4_VERSION) {
991 if (ire->ire_mask == IP_HOST_MASK)
992 (void) strcat(flags, "H");
993 } else {
994 if (IN6_ARE_ADDR_EQUAL(&ire->ire_mask_v6, &ipv6_all_ones))
995 (void) strcat(flags, "H");
996 }
997
998 if (ire->ire_flags & RTF_DYNAMIC)
999 (void) strcat(flags, "D");
1000 if (ire->ire_type == IRE_BROADCAST)
1001 (void) strcat(flags, "b");
1002 if (ire->ire_type == IRE_MULTICAST)
1003 (void) strcat(flags, "m");
1004 if (ire->ire_type == IRE_LOCAL)
1005 (void) strcat(flags, "L");
1006 if (ire->ire_type == IRE_NOROUTE)
1007 (void) strcat(flags, "N");
1008 if (ire->ire_flags & RTF_MULTIRT)
1009 (void) strcat(flags, "M");
1010 if (ire->ire_flags & RTF_SETSRC)
1011 (void) strcat(flags, "S");
1012 if (ire->ire_flags & RTF_REJECT)
1013 (void) strcat(flags, "R");
1014 if (ire->ire_flags & RTF_BLACKHOLE)
1015 (void) strcat(flags, "B");
1016 }
1017
1018 static int
1019 netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
1020 {
1021 const ire_t *ire = walk_data;
1022 uint_t *opts = cb_data;
1023 ipaddr_t gate;
1024 char flags[10], intf[LIFNAMSIZ + 1];
1025
1026 if (ire->ire_ipversion != IPV4_VERSION)
1027 return (WALK_NEXT);
1028
1029 /* Skip certain IREs by default */
1030 if (!(*opts & NETSTAT_ALL) &&
1031 (ire->ire_type &
1032 (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
1033 return (WALK_NEXT);
1034
1035 if (*opts & NETSTAT_FIRST) {
1036 *opts &= ~NETSTAT_FIRST;
1037 mdb_printf("%<u>%s Table: IPv4%</u>\n",
1038 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
1039 if (*opts & NETSTAT_VERBOSE) {
1040 mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt "
1041 " Ref Flg Out In/Fwd%</u>\n",
1042 "Address", ADDR_V4_WIDTH, "Destination",
1043 ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway");
1044 } else {
1045 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use "
1046 "Interface%</u>\n",
1047 "Address", ADDR_V4_WIDTH, "Destination",
1048 ADDR_V4_WIDTH, "Gateway");
1049 }
1050 }
1051
1052 gate = ire->ire_gateway_addr;
1053
1054 get_ireflags(ire, flags);
1055
1056 get_ifname(ire, intf);
1057
1058 if (*opts & NETSTAT_VERBOSE) {
1059 mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
1060 "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH,
1061 ire->ire_mask, ADDR_V4_WIDTH, gate, intf,
1062 0, ' ',
1063 ire->ire_metrics.iulp_rtt, ire->ire_refcnt, flags,
1064 ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
1065 } else {
1066 mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr,
1067 ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags,
1068 ire->ire_refcnt,
1069 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
1070 }
1071
1072 return (WALK_NEXT);
1073 }
1074
1075 int
1076 ip_mask_to_plen_v6(const in6_addr_t *v6mask)
1077 {
1078 int plen;
1079 int i;
1080 uint32_t val;
1081
1082 for (i = 3; i >= 0; i--)
1083 if (v6mask->s6_addr32[i] != 0)
1084 break;
1085 if (i < 0)
1086 return (0);
1087 plen = 32 + 32 * i;
1088 val = v6mask->s6_addr32[i];
1089 while (!(val & 1)) {
1090 val >>= 1;
1091 plen--;
1092 }
1093
1094 return (plen);
1095 }
1096
1097 static int
1098 netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
1099 {
1100 const ire_t *ire = walk_data;
1101 uint_t *opts = cb_data;
1102 const in6_addr_t *gatep;
1103 char deststr[ADDR_V6_WIDTH + 5];
1104 char flags[10], intf[LIFNAMSIZ + 1];
1105 int masklen;
1106
1107 if (ire->ire_ipversion != IPV6_VERSION)
1108 return (WALK_NEXT);
1109
1110 /* Skip certain IREs by default */
1111 if (!(*opts & NETSTAT_ALL) &&
1112 (ire->ire_type &
1113 (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
1114 return (WALK_NEXT);
1115
1116 if (*opts & NETSTAT_FIRST) {
1117 *opts &= ~NETSTAT_FIRST;
1118 mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
1119 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
1120 if (*opts & NETSTAT_VERBOSE) {
1121 mdb_printf("%<u>%-?s %-*s %-*s If PMTU Rtt Ref "
1122 "Flags Out In/Fwd%</u>\n",
1123 "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
1124 ADDR_V6_WIDTH, "Gateway");
1125 } else {
1126 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use If"
1127 "%</u>\n",
1128 "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
1129 ADDR_V6_WIDTH, "Gateway");
1130 }
1131 }
1132
1133 gatep = &ire->ire_gateway_addr_v6;
1134
1135 masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6);
1136 (void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d",
1137 &ire->ire_addr_v6, masklen);
1138
1139 get_ireflags(ire, flags);
1140
1141 get_ifname(ire, intf);
1142
1143 if (*opts & NETSTAT_VERBOSE) {
1144 mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
1145 kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep,
1146 intf, 0, ' ',
1147 ire->ire_metrics.iulp_rtt, ire->ire_refcnt,
1148 flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
1149 } else {
1150 mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr,
1151 ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags,
1152 ire->ire_refcnt,
1153 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
1154 }
1155
1156 return (WALK_NEXT);
1157 }
1158
1159 static void
1160 netstat_header_v4(int proto)
1161 {
1162 if (proto == IPPROTO_TCP)
1163 mdb_printf("%<u>%-?s ", "TCPv4");
1164 else if (proto == IPPROTO_UDP)
1165 mdb_printf("%<u>%-?s ", "UDPv4");
1166 else if (proto == IPPROTO_ICMP)
1167 mdb_printf("%<u>%-?s ", "ICMPv4");
1168 mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
1169 "", ADDR_V4_WIDTH, "Local Address",
1170 "", ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone");
1171 }
1172
1173 static void
1174 netstat_header_v6(int proto)
1175 {
1176 if (proto == IPPROTO_TCP)
1177 mdb_printf("%<u>%-?s ", "TCPv6");
1178 else if (proto == IPPROTO_UDP)
1179 mdb_printf("%<u>%-?s ", "UDPv6");
1180 else if (proto == IPPROTO_ICMP)
1181 mdb_printf("%<u>%-?s ", "ICMPv6");
1182 mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
1183 "", ADDR_V6_WIDTH, "Local Address",
1184 "", ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone");
1185 }
1186
1187 static int
1188 netstat_print_conn(const char *cache, int proto, mdb_walk_cb_t cbfunc,
1189 void *cbdata)
1190 {
1191 netstat_cb_data_t *ncb = cbdata;
1192
1193 if ((ncb->opts & NETSTAT_VERBOSE) && proto == IPPROTO_TCP)
1194 netstat_tcp_verbose_header_pr();
1195 if (mdb_walk(cache, cbfunc, cbdata) == -1) {
1196 mdb_warn("failed to walk %s", cache);
1197 return (DCMD_ERR);
1198 }
1199 return (DCMD_OK);
1200 }
1201
1202 static int
1203 netstat_print_common(const char *cache, int proto, mdb_walk_cb_t cbfunc,
1204 void *cbdata)
1205 {
1206 netstat_cb_data_t *ncb = cbdata;
1207 int af = ncb->af;
1208 int status = DCMD_OK;
1209
1210 if (af != AF_INET6) {
1211 ncb->af = AF_INET;
1212 netstat_header_v4(proto);
1213 status = netstat_print_conn(cache, proto, cbfunc, cbdata);
1214 }
1215 if (status == DCMD_OK && af != AF_INET) {
1216 ncb->af = AF_INET6;
1217 netstat_header_v6(proto);
1218 status = netstat_print_conn(cache, proto, cbfunc, cbdata);
1219 }
1220 ncb->af = af;
1221 return (status);
1222 }
1223
1224 /*ARGSUSED*/
1225 int
1226 netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1227 {
1228 uint_t opts = 0;
1229 const char *optf = NULL;
1230 const char *optP = NULL;
1231 netstat_cb_data_t *cbdata;
1232 int status;
1233 int af = 0;
1234
1235 if (mdb_getopts(argc, argv,
1236 'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
1237 'f', MDB_OPT_STR, &optf,
1238 'P', MDB_OPT_STR, &optP,
1239 'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts,
1240 'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
1241 NULL) != argc)
1242 return (DCMD_USAGE);
1243
1244 if (optP != NULL) {
1245 if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0) &&
1246 (strcmp("icmp", optP) != 0))
1247 return (DCMD_USAGE);
1248 if (opts & NETSTAT_ROUTE)
1249 return (DCMD_USAGE);
1250 }
1251
1252 if (optf == NULL)
1253 opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX;
1254 else if (strcmp("inet", optf) == 0)
1255 opts |= NETSTAT_V4;
1256 else if (strcmp("inet6", optf) == 0)
1257 opts |= NETSTAT_V6;
1258 else if (strcmp("unix", optf) == 0)
1259 opts |= NETSTAT_UNIX;
1260 else
1261 return (DCMD_USAGE);
1262
1263 if (opts & NETSTAT_ROUTE) {
1264 if (!(opts & (NETSTAT_V4|NETSTAT_V6)))
1265 return (DCMD_USAGE);
1266 if (opts & NETSTAT_V4) {
1267 opts |= NETSTAT_FIRST;
1268 if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) {
1269 mdb_warn("failed to walk ip`ire");
1270 return (DCMD_ERR);
1271 }
1272 }
1273 if (opts & NETSTAT_V6) {
1274 opts |= NETSTAT_FIRST;
1275 if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) {
1276 mdb_warn("failed to walk ip`ire");
1277 return (DCMD_ERR);
1278 }
1279 }
1280 return (DCMD_OK);
1281 }
1282
1283 if ((opts & NETSTAT_UNIX) && (optP == NULL)) {
1284 /* Print Unix Domain Sockets */
1285 mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
1286 "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
1287 "Remote Addr", "Zone");
1288
1289 if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
1290 mdb_warn("failed to walk genunix`sonode");
1291 return (DCMD_ERR);
1292 }
1293 if (!(opts & (NETSTAT_V4 | NETSTAT_V6)))
1294 return (DCMD_OK);
1295 }
1296
1297 cbdata = mdb_alloc(sizeof (netstat_cb_data_t), UM_SLEEP);
1298 cbdata->opts = opts;
1299 if ((optf != NULL) && (opts & NETSTAT_V4))
1300 af = AF_INET;
1301 else if ((optf != NULL) && (opts & NETSTAT_V6))
1302 af = AF_INET6;
1303
1304 cbdata->af = af;
1305 if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
1306 status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP,
1307 netstat_tcp_cb, cbdata);
1308 if (status != DCMD_OK)
1309 goto out;
1310 }
1311
1312 if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
1313 status = netstat_print_common("udp_conn_cache", IPPROTO_UDP,
1314 netstat_udp_cb, cbdata);
1315 if (status != DCMD_OK)
1316 goto out;
1317 }
1318
1319 if ((optP == NULL) || (strcmp("icmp", optP) == 0)) {
1320 status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP,
1321 netstat_icmp_cb, cbdata);
1322 if (status != DCMD_OK)
1323 goto out;
1324 }
1325
1326 if ((optP == NULL) || (strcmp("dccp", optP) == 0)) {
1327 status = netstat_print_common("dccp_conn_cache", IPPROTO_DCCP,
1328 netstat_dccp_cb, cbdata);
1329 if (status != DCMD_OK)
1330 goto out;
1331 }
1332 out:
1333 mdb_free(cbdata, sizeof (netstat_cb_data_t));
1334 return (status);
1335 }
1336
1337 /*
1338 * "::dladm show-bridge" support
1339 */
1340 typedef struct {
1341 uint_t opt_l;
1342 uint_t opt_f;
1343 uint_t opt_t;
1344 const char *name;
1345 clock_t lbolt;
1346 boolean_t found;
1347 uint_t nlinks;
1348 uint_t nfwd;
1349
1350 /*
1351 * These structures are kept inside the 'args' for allocation reasons.
1352 * They're all large data structures (over 1K), and may cause the stack
1353 * to explode. mdb and kmdb will fail in these cases, and thus we
1354 * allocate them from the heap.
1355 */
1356 trill_inst_t ti;
1357 bridge_link_t bl;
1358 mac_impl_t mi;
1359 } show_bridge_args_t;
1360
1361 static void
1362 show_vlans(const uint8_t *vlans)
1363 {
1364 int i, bit;
1365 uint8_t val;
1366 int rstart = -1, rnext = -1;
1367
1368 for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) {
1369 val = vlans[i];
1370 if (i == 0)
1371 val &= ~1;
1372 while ((bit = mdb_ffs(val)) != 0) {
1373 bit--;
1374 val &= ~(1 << bit);
1375 bit += i * sizeof (*vlans) * NBBY;
1376 if (bit != rnext) {
1377 if (rnext != -1 && rstart + 1 != rnext)
1378 mdb_printf("-%d", rnext - 1);
1379 if (rstart != -1)
1380 mdb_printf(",");
1381 mdb_printf("%d", bit);
1382 rstart = bit;
1383 }
1384 rnext = bit + 1;
1385 }
1386 }
1387 if (rnext != -1 && rstart + 1 != rnext)
1388 mdb_printf("-%d", rnext - 1);
1389 mdb_printf("\n");
1390 }
1391
1392 /*
1393 * This callback is invoked by a walk of the links attached to a bridge. If
1394 * we're showing link details, then they're printed here. If not, then we just
1395 * count up the links for the bridge summary.
1396 */
1397 static int
1398 do_bridge_links(uintptr_t addr, const void *data, void *ptr)
1399 {
1400 show_bridge_args_t *args = ptr;
1401 const bridge_link_t *blp = data;
1402 char macaddr[ETHERADDRL * 3];
1403 const char *name;
1404
1405 args->nlinks++;
1406
1407 if (!args->opt_l)
1408 return (WALK_NEXT);
1409
1410 if (mdb_vread(&args->mi, sizeof (args->mi),
1411 (uintptr_t)blp->bl_mh) == -1) {
1412 mdb_warn("cannot read mac data at %p", blp->bl_mh);
1413 name = "?";
1414 } else {
1415 name = args->mi.mi_name;
1416 }
1417
1418 mdb_mac_addr(blp->bl_local_mac, ETHERADDRL, macaddr,
1419 sizeof (macaddr));
1420
1421 mdb_printf("%-?p %-16s %-17s %03X %-4d ", addr, name, macaddr,
1422 blp->bl_flags, blp->bl_pvid);
1423
1424 if (blp->bl_trilldata == NULL) {
1425 switch (blp->bl_state) {
1426 case BLS_BLOCKLISTEN:
1427 name = "BLOCK";
1428 break;
1429 case BLS_LEARNING:
1430 name = "LEARN";
1431 break;
1432 case BLS_FORWARDING:
1433 name = "FWD";
1434 break;
1435 default:
1436 name = "?";
1437 }
1438 mdb_printf("%-5s ", name);
1439 show_vlans(blp->bl_vlans);
1440 } else {
1441 show_vlans(blp->bl_afs);
1442 }
1443
1444 return (WALK_NEXT);
1445 }
1446
1447 /*
1448 * It seems a shame to duplicate this code, but merging it with the link
1449 * printing code above is more trouble than it would be worth.
1450 */
1451 static void
1452 print_link_name(show_bridge_args_t *args, uintptr_t addr, char sep)
1453 {
1454 const char *name;
1455
1456 if (mdb_vread(&args->bl, sizeof (args->bl), addr) == -1) {
1457 mdb_warn("cannot read bridge link at %p", addr);
1458 return;
1459 }
1460
1461 if (mdb_vread(&args->mi, sizeof (args->mi),
1462 (uintptr_t)args->bl.bl_mh) == -1) {
1463 name = "?";
1464 } else {
1465 name = args->mi.mi_name;
1466 }
1467
1468 mdb_printf("%s%c", name, sep);
1469 }
1470
1471 static int
1472 do_bridge_fwd(uintptr_t addr, const void *data, void *ptr)
1473 {
1474 show_bridge_args_t *args = ptr;
1475 const bridge_fwd_t *bfp = data;
1476 char macaddr[ETHERADDRL * 3];
1477 int i;
1478 #define MAX_FWD_LINKS 16
1479 bridge_link_t *links[MAX_FWD_LINKS];
1480 uint_t nlinks;
1481
1482 args->nfwd++;
1483
1484 if (!args->opt_f)
1485 return (WALK_NEXT);
1486
1487 if ((nlinks = bfp->bf_nlinks) > MAX_FWD_LINKS)
1488 nlinks = MAX_FWD_LINKS;
1489
1490 if (mdb_vread(links, sizeof (links[0]) * nlinks,
1491 (uintptr_t)bfp->bf_links) == -1) {
1492 mdb_warn("cannot read bridge forwarding links at %p",
1493 bfp->bf_links);
1494 return (WALK_ERR);
1495 }
1496
1497 mdb_mac_addr(bfp->bf_dest, ETHERADDRL, macaddr, sizeof (macaddr));
1498
1499 mdb_printf("%-?p %-17s ", addr, macaddr);
1500 if (bfp->bf_flags & BFF_LOCALADDR)
1501 mdb_printf("%-7s", "[self]");
1502 else
1503 mdb_printf("t-%-5d", args->lbolt - bfp->bf_lastheard);
1504 mdb_printf(" %-7u ", bfp->bf_refs);
1505
1506 if (bfp->bf_trill_nick != 0) {
1507 mdb_printf("%d\n", bfp->bf_trill_nick);
1508 } else {
1509 for (i = 0; i < bfp->bf_nlinks; i++) {
1510 print_link_name(args, (uintptr_t)links[i],
1511 i == bfp->bf_nlinks - 1 ? '\n' : ' ');
1512 }
1513 }
1514
1515 return (WALK_NEXT);
1516 }
1517
1518 static int
1519 do_show_bridge(uintptr_t addr, const void *data, void *ptr)
1520 {
1521 show_bridge_args_t *args = ptr;
1522 bridge_inst_t bi;
1523 const bridge_inst_t *bip;
1524 trill_node_t tn;
1525 trill_sock_t tsp;
1526 trill_nickinfo_t tni;
1527 char bname[MAXLINKNAMELEN];
1528 char macaddr[ETHERADDRL * 3];
1529 char *cp;
1530 uint_t nnicks;
1531 int i;
1532
1533 if (data != NULL) {
1534 bip = data;
1535 } else {
1536 if (mdb_vread(&bi, sizeof (bi), addr) == -1) {
1537 mdb_warn("cannot read bridge instance at %p", addr);
1538 return (WALK_ERR);
1539 }
1540 bip = &bi;
1541 }
1542
1543 (void) strncpy(bname, bip->bi_name, sizeof (bname) - 1);
1544 bname[MAXLINKNAMELEN - 1] = '\0';
1545 cp = bname + strlen(bname);
1546 if (cp > bname && cp[-1] == '0')
1547 cp[-1] = '\0';
1548
1549 if (args->name != NULL && strcmp(args->name, bname) != 0)
1550 return (WALK_NEXT);
1551
1552 args->found = B_TRUE;
1553 args->nlinks = args->nfwd = 0;
1554
1555 if (args->opt_l) {
1556 mdb_printf("%-?s %-16s %-17s %3s %-4s ", "ADDR", "LINK",
1557 "MAC-ADDR", "FLG", "PVID");
1558 if (bip->bi_trilldata == NULL)
1559 mdb_printf("%-5s %s\n", "STATE", "VLANS");
1560 else
1561 mdb_printf("%s\n", "FWD-VLANS");
1562 }
1563
1564 if (!args->opt_f && !args->opt_t &&
1565 mdb_pwalk("list", do_bridge_links, args,
1566 addr + offsetof(bridge_inst_t, bi_links)) != DCMD_OK)
1567 return (WALK_ERR);
1568
1569 if (args->opt_f)
1570 mdb_printf("%-?s %-17s %-7s %-7s %s\n", "ADDR", "DEST", "TIME",
1571 "REFS", "OUTPUT");
1572
1573 if (!args->opt_l && !args->opt_t &&
1574 mdb_pwalk("avl", do_bridge_fwd, args,
1575 addr + offsetof(bridge_inst_t, bi_fwd)) != DCMD_OK)
1576 return (WALK_ERR);
1577
1578 nnicks = 0;
1579 if (bip->bi_trilldata != NULL && !args->opt_l && !args->opt_f) {
1580 if (mdb_vread(&args->ti, sizeof (args->ti),
1581 (uintptr_t)bip->bi_trilldata) == -1) {
1582 mdb_warn("cannot read trill instance at %p",
1583 bip->bi_trilldata);
1584 return (WALK_ERR);
1585 }
1586 if (args->opt_t)
1587 mdb_printf("%-?s %-5s %-17s %s\n", "ADDR",
1588 "NICK", "NEXT-HOP", "LINK");
1589 for (i = 0; i < RBRIDGE_NICKNAME_MAX; i++) {
1590 if (args->ti.ti_nodes[i] == NULL)
1591 continue;
1592 if (args->opt_t) {
1593 if (mdb_vread(&tn, sizeof (tn),
1594 (uintptr_t)args->ti.ti_nodes[i]) == -1) {
1595 mdb_warn("cannot read trill node %d at "
1596 "%p", i, args->ti.ti_nodes[i]);
1597 return (WALK_ERR);
1598 }
1599 if (mdb_vread(&tni, sizeof (tni),
1600 (uintptr_t)tn.tn_ni) == -1) {
1601 mdb_warn("cannot read trill node info "
1602 "%d at %p", i, tn.tn_ni);
1603 return (WALK_ERR);
1604 }
1605 mdb_mac_addr(tni.tni_adjsnpa, ETHERADDRL,
1606 macaddr, sizeof (macaddr));
1607 if (tni.tni_nick == args->ti.ti_nick) {
1608 (void) strcpy(macaddr, "[self]");
1609 }
1610 mdb_printf("%-?p %-5u %-17s ",
1611 args->ti.ti_nodes[i], tni.tni_nick,
1612 macaddr);
1613 if (tn.tn_tsp != NULL) {
1614 if (mdb_vread(&tsp, sizeof (tsp),
1615 (uintptr_t)tn.tn_tsp) == -1) {
1616 mdb_warn("cannot read trill "
1617 "socket info at %p",
1618 tn.tn_tsp);
1619 return (WALK_ERR);
1620 }
1621 if (tsp.ts_link != NULL) {
1622 print_link_name(args,
1623 (uintptr_t)tsp.ts_link,
1624 '\n');
1625 continue;
1626 }
1627 }
1628 mdb_printf("--\n");
1629 } else {
1630 nnicks++;
1631 }
1632 }
1633 } else {
1634 if (args->opt_t)
1635 mdb_printf("bridge is not running TRILL\n");
1636 }
1637
1638 if (!args->opt_l && !args->opt_f && !args->opt_t) {
1639 mdb_printf("%-?p %-7s %-16s %-7u %-7u", addr,
1640 bip->bi_trilldata == NULL ? "stp" : "trill", bname,
1641 args->nlinks, args->nfwd);
1642 if (bip->bi_trilldata != NULL)
1643 mdb_printf(" %-7u %u\n", nnicks, args->ti.ti_nick);
1644 else
1645 mdb_printf(" %-7s %s\n", "--", "--");
1646 }
1647 return (WALK_NEXT);
1648 }
1649
1650 static int
1651 dladm_show_bridge(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1652 {
1653 show_bridge_args_t *args;
1654 GElf_Sym sym;
1655 int i;
1656
1657 args = mdb_zalloc(sizeof (*args), UM_SLEEP);
1658
1659 i = mdb_getopts(argc, argv,
1660 'l', MDB_OPT_SETBITS, 1, &args->opt_l,
1661 'f', MDB_OPT_SETBITS, 1, &args->opt_f,
1662 't', MDB_OPT_SETBITS, 1, &args->opt_t,
1663 NULL);
1664
1665 argc -= i;
1666 argv += i;
1667
1668 if (argc > 1 || (argc == 1 && argv[0].a_type != MDB_TYPE_STRING)) {
1669 mdb_free(args, sizeof (*args));
1670 return (DCMD_USAGE);
1671 }
1672 if (argc == 1)
1673 args->name = argv[0].a_un.a_str;
1674
1675 if ((args->lbolt = mdb_get_lbolt()) == -1) {
1676 mdb_warn("failed to read lbolt");
1677 goto err;
1678 }
1679
1680 if (flags & DCMD_ADDRSPEC) {
1681 if (args->name != NULL) {
1682 mdb_printf("bridge name and address are mutually "
1683 "exclusive\n");
1684 goto err;
1685 }
1686 if (!args->opt_l && !args->opt_f && !args->opt_t)
1687 mdb_printf("%-?s %-7s %-16s %-7s %-7s\n", "ADDR",
1688 "PROTECT", "NAME", "NLINKS", "NFWD");
1689 if (do_show_bridge(addr, NULL, args) != WALK_NEXT)
1690 goto err;
1691 mdb_free(args, sizeof (*args));
1692 return (DCMD_OK);
1693 } else {
1694 if ((args->opt_l || args->opt_f || args->opt_t) &&
1695 args->name == NULL) {
1696 mdb_printf("need bridge name or address with -[lft]\n");
1697 goto err;
1698 }
1699 if (mdb_lookup_by_obj("bridge", "inst_list", &sym) == -1) {
1700 mdb_warn("failed to find 'bridge`inst_list'");
1701 goto err;
1702 }
1703 if (!args->opt_l && !args->opt_f && !args->opt_t)
1704 mdb_printf("%-?s %-7s %-16s %-7s %-7s %-7s %s\n",
1705 "ADDR", "PROTECT", "NAME", "NLINKS", "NFWD",
1706 "NNICKS", "NICK");
1707 if (mdb_pwalk("list", do_show_bridge, args,
1708 (uintptr_t)sym.st_value) != DCMD_OK)
1709 goto err;
1710 if (!args->found && args->name != NULL) {
1711 mdb_printf("bridge instance %s not found\n",
1712 args->name);
1713 goto err;
1714 }
1715 mdb_free(args, sizeof (*args));
1716 return (DCMD_OK);
1717 }
1718
1719 err:
1720 mdb_free(args, sizeof (*args));
1721 return (DCMD_ERR);
1722 }
1723
1724 /*
1725 * Support for the "::dladm" dcmd
1726 */
1727 int
1728 dladm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1729 {
1730 if (argc < 1 || argv[0].a_type != MDB_TYPE_STRING)
1731 return (DCMD_USAGE);
1732
1733 /*
1734 * This could be a bit more elaborate, once we support more of the
1735 * dladm show-* subcommands.
1736 */
1737 argc--;
1738 argv++;
1739 if (strcmp(argv[-1].a_un.a_str, "show-bridge") == 0)
1740 return (dladm_show_bridge(addr, flags, argc, argv));
1741
1742 return (DCMD_USAGE);
1743 }
1744
1745 void
1746 dladm_help(void)
1747 {
1748 mdb_printf("Subcommands:\n"
1749 " show-bridge [-flt] [<name>]\n"
1750 "\t Show bridge information; -l for links and -f for "
1751 "forwarding\n"
1752 "\t entries, and -t for TRILL nicknames. Address is required "
1753 "if name\n"
1754 "\t is not specified.\n");
1755 }