remove xen support
[unleashed/tickless.git] / usr / src / cmd / mdb / common / modules / genunix / net.c
blob6b4c3c97e82eaee814f68ab23f1c4d7c3eaa67cb
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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 <../../../../kernel/fs/sockfs/socktpi_impl.h>
51 #include <net/bridge_impl.h>
52 #include <io/trill_impl.h>
53 #include <sys/mac_impl.h>
55 #define ADDR_V6_WIDTH 23
56 #define ADDR_V4_WIDTH 15
58 #define NETSTAT_ALL 0x01
59 #define NETSTAT_VERBOSE 0x02
60 #define NETSTAT_ROUTE 0x04
61 #define NETSTAT_V4 0x08
62 #define NETSTAT_V6 0x10
63 #define NETSTAT_UNIX 0x20
65 #define NETSTAT_FIRST 0x80000000u
67 typedef struct netstat_cb_data_s {
68 uint_t opts;
69 conn_t conn;
70 int af;
71 } netstat_cb_data_t;
73 int
74 icmp_stacks_walk_init(mdb_walk_state_t *wsp)
76 if (mdb_layered_walk("netstack", wsp) == -1) {
77 mdb_warn("can't walk 'netstack'");
78 return (WALK_ERR);
80 return (WALK_NEXT);
83 int
84 icmp_stacks_walk_step(mdb_walk_state_t *wsp)
86 uintptr_t kaddr;
87 netstack_t nss;
89 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
90 mdb_warn("can't read netstack at %p", wsp->walk_addr);
91 return (WALK_ERR);
93 kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP];
94 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
97 int
98 tcp_stacks_walk_init(mdb_walk_state_t *wsp)
100 if (mdb_layered_walk("netstack", wsp) == -1) {
101 mdb_warn("can't walk 'netstack'");
102 return (WALK_ERR);
104 return (WALK_NEXT);
108 tcp_stacks_walk_step(mdb_walk_state_t *wsp)
110 uintptr_t kaddr;
111 netstack_t nss;
113 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
114 mdb_warn("can't read netstack at %p", wsp->walk_addr);
115 return (WALK_ERR);
117 kaddr = (uintptr_t)nss.netstack_modules[NS_TCP];
118 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
122 udp_stacks_walk_init(mdb_walk_state_t *wsp)
124 if (mdb_layered_walk("netstack", wsp) == -1) {
125 mdb_warn("can't walk 'netstack'");
126 return (WALK_ERR);
128 return (WALK_NEXT);
132 udp_stacks_walk_step(mdb_walk_state_t *wsp)
134 uintptr_t kaddr;
135 netstack_t nss;
137 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) {
138 mdb_warn("can't read netstack at %p", wsp->walk_addr);
139 return (WALK_ERR);
141 kaddr = (uintptr_t)nss.netstack_modules[NS_UDP];
142 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata));
146 * Print an IPv4 address and port number in a compact and easy to read format
147 * The arguments are in network byte order
149 static void
150 net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport)
152 uint32_t naddr = V4_PART_OF_V6((*nipv6addr));
154 mdb_nhconvert(&nport, &nport, sizeof (nport));
155 mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport);
159 * Print an IPv6 address and port number in a compact and easy to read format
160 * The arguments are in network byte order
162 static void
163 net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport)
165 mdb_nhconvert(&nport, &nport, sizeof (nport));
166 mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport);
169 static int
170 net_tcp_active(const tcp_t *tcp)
172 return (tcp->tcp_state >= TCPS_ESTABLISHED);
175 static int
176 net_tcp_ipv4(const tcp_t *tcp)
178 return ((tcp->tcp_connp->conn_ipversion == IPV4_VERSION) ||
179 (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_connp->conn_laddr_v6) &&
180 (tcp->tcp_state <= TCPS_LISTEN)));
183 static int
184 net_tcp_ipv6(const tcp_t *tcp)
186 return (tcp->tcp_connp->conn_ipversion == IPV6_VERSION);
189 static int
190 net_udp_active(const udp_t *udp)
192 return ((udp->udp_state == TS_IDLE) ||
193 (udp->udp_state == TS_DATA_XFER));
196 static int
197 net_udp_ipv4(const udp_t *udp)
199 return ((udp->udp_connp->conn_ipversion == IPV4_VERSION) ||
200 (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_connp->conn_laddr_v6) &&
201 (udp->udp_state <= TS_IDLE)));
204 static int
205 net_udp_ipv6(const udp_t *udp)
207 return (udp->udp_connp->conn_ipversion == IPV6_VERSION);
211 sonode_walk_init(mdb_walk_state_t *wsp)
213 if (wsp->walk_addr == (uintptr_t)NULL) {
214 GElf_Sym sym;
215 struct socklist *slp;
217 if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) {
218 mdb_warn("failed to lookup sockfs`socklist");
219 return (WALK_ERR);
222 slp = (struct socklist *)(uintptr_t)sym.st_value;
224 if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr),
225 (uintptr_t)&slp->sl_list) == -1) {
226 mdb_warn("failed to read address of initial sonode "
227 "at %p", &slp->sl_list);
228 return (WALK_ERR);
232 wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP);
233 return (WALK_NEXT);
237 sonode_walk_step(mdb_walk_state_t *wsp)
239 int status;
240 struct sotpi_sonode *stp;
242 if (wsp->walk_addr == (uintptr_t)NULL)
243 return (WALK_DONE);
245 if (mdb_vread(wsp->walk_data, sizeof (struct sotpi_sonode),
246 wsp->walk_addr) == -1) {
247 mdb_warn("failed to read sonode at %p", wsp->walk_addr);
248 return (WALK_ERR);
251 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
252 wsp->walk_cbdata);
254 stp = wsp->walk_data;
256 wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so;
257 return (status);
260 void
261 sonode_walk_fini(mdb_walk_state_t *wsp)
263 mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode));
266 struct mi_walk_data {
267 uintptr_t mi_wd_miofirst;
268 MI_O mi_wd_miodata;
272 mi_walk_init(mdb_walk_state_t *wsp)
274 struct mi_walk_data *wdp;
276 if (wsp->walk_addr == (uintptr_t)NULL) {
277 mdb_warn("mi doesn't support global walks\n");
278 return (WALK_ERR);
281 wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP);
283 /* So that we do not immediately return WALK_DONE below */
284 wdp->mi_wd_miofirst = (uintptr_t)NULL;
286 wsp->walk_data = wdp;
287 return (WALK_NEXT);
291 mi_walk_step(mdb_walk_state_t *wsp)
293 struct mi_walk_data *wdp = wsp->walk_data;
294 MI_OP miop = &wdp->mi_wd_miodata;
295 int status;
297 /* Always false in the first iteration */
298 if ((wsp->walk_addr == (uintptr_t)NULL) ||
299 (wsp->walk_addr == wdp->mi_wd_miofirst)) {
300 return (WALK_DONE);
303 if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) {
304 mdb_warn("failed to read MI object at %p", wsp->walk_addr);
305 return (WALK_ERR);
308 /* Only true in the first iteration */
309 if (wdp->mi_wd_miofirst == (uintptr_t)NULL) {
310 wdp->mi_wd_miofirst = wsp->walk_addr;
311 status = WALK_NEXT;
312 } else {
313 status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O),
314 &miop[1], wsp->walk_cbdata);
317 wsp->walk_addr = (uintptr_t)miop->mi_o_next;
318 return (status);
321 void
322 mi_walk_fini(mdb_walk_state_t *wsp)
324 mdb_free(wsp->walk_data, sizeof (struct mi_walk_data));
327 typedef struct mi_payload_walk_arg_s {
328 const char *mi_pwa_walker; /* Underlying walker */
329 const off_t mi_pwa_head_off; /* Offset for mi_o_head_t * in stack */
330 const size_t mi_pwa_size; /* size of mi payload */
331 const uint_t mi_pwa_flags; /* device and/or module */
332 } mi_payload_walk_arg_t;
334 #define MI_PAYLOAD_DEVICE 0x1
335 #define MI_PAYLOAD_MODULE 0x2
338 mi_payload_walk_init(mdb_walk_state_t *wsp)
340 const mi_payload_walk_arg_t *arg = wsp->walk_arg;
342 if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) {
343 mdb_warn("can't walk '%s'", arg->mi_pwa_walker);
344 return (WALK_ERR);
346 return (WALK_NEXT);
350 mi_payload_walk_step(mdb_walk_state_t *wsp)
352 const mi_payload_walk_arg_t *arg = wsp->walk_arg;
353 uintptr_t kaddr;
355 kaddr = wsp->walk_addr + arg->mi_pwa_head_off;
357 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) {
358 mdb_warn("can't read address of mi head at %p for %s",
359 kaddr, arg->mi_pwa_walker);
360 return (WALK_ERR);
363 if (kaddr == (uintptr_t)NULL) {
364 /* Empty list */
365 return (WALK_DONE);
368 if (mdb_pwalk("genunix`mi", wsp->walk_callback,
369 wsp->walk_cbdata, kaddr) == -1) {
370 mdb_warn("failed to walk genunix`mi");
371 return (WALK_ERR);
373 return (WALK_NEXT);
376 const mi_payload_walk_arg_t mi_icmp_arg = {
377 "icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t),
378 MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE
382 sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
384 const char *optf = NULL;
385 const char *optt = NULL;
386 const char *optp = NULL;
387 int family, type, proto;
388 int filter = 0;
389 struct sonode so;
391 if (!(flags & DCMD_ADDRSPEC)) {
392 if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc,
393 argv) == -1) {
394 mdb_warn("failed to walk sonode");
395 return (DCMD_ERR);
398 return (DCMD_OK);
401 if (mdb_getopts(argc, argv,
402 'f', MDB_OPT_STR, &optf,
403 't', MDB_OPT_STR, &optt,
404 'p', MDB_OPT_STR, &optp,
405 NULL) != argc)
406 return (DCMD_USAGE);
408 if (optf != NULL) {
409 if (strcmp("inet", optf) == 0)
410 family = AF_INET;
411 else if (strcmp("inet6", optf) == 0)
412 family = AF_INET6;
413 else if (strcmp("unix", optf) == 0)
414 family = AF_UNIX;
415 else
416 family = mdb_strtoull(optf);
417 filter = 1;
420 if (optt != NULL) {
421 if (strcmp("stream", optt) == 0)
422 type = SOCK_STREAM;
423 else if (strcmp("dgram", optt) == 0)
424 type = SOCK_DGRAM;
425 else if (strcmp("raw", optt) == 0)
426 type = SOCK_RAW;
427 else
428 type = mdb_strtoull(optt);
429 filter = 1;
432 if (optp != NULL) {
433 proto = mdb_strtoull(optp);
434 filter = 1;
437 if (DCMD_HDRSPEC(flags) && !filter) {
438 mdb_printf("%<u>%-?s Family Type Proto State Mode Flag "
439 "AccessVP%</u>\n", "Sonode:");
442 if (mdb_vread(&so, sizeof (so), addr) == -1) {
443 mdb_warn("failed to read sonode at %p", addr);
444 return (DCMD_ERR);
447 if ((optf != NULL) && (so.so_family != family))
448 return (DCMD_OK);
450 if ((optt != NULL) && (so.so_type != type))
451 return (DCMD_OK);
453 if ((optp != NULL) && (so.so_protocol != proto))
454 return (DCMD_OK);
456 if (filter) {
457 mdb_printf("%0?p\n", addr);
458 return (DCMD_OK);
461 mdb_printf("%0?p ", addr);
463 switch (so.so_family) {
464 case AF_UNIX:
465 mdb_printf("unix ");
466 break;
467 case AF_INET:
468 mdb_printf("inet ");
469 break;
470 case AF_INET6:
471 mdb_printf("inet6 ");
472 break;
473 default:
474 mdb_printf("%6hi", so.so_family);
477 switch (so.so_type) {
478 case SOCK_STREAM:
479 mdb_printf(" strm");
480 break;
481 case SOCK_DGRAM:
482 mdb_printf(" dgrm");
483 break;
484 case SOCK_RAW:
485 mdb_printf(" raw ");
486 break;
487 default:
488 mdb_printf(" %4hi", so.so_type);
491 mdb_printf(" %5hi %05x %04x %04hx\n",
492 so.so_protocol, so.so_state, so.so_mode,
493 so.so_flag);
495 return (DCMD_OK);
498 #define MI_PAYLOAD 0x1
499 #define MI_DEVICE 0x2
500 #define MI_MODULE 0x4
503 mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
505 uint_t opts = 0;
506 MI_O mio;
508 if (!(flags & DCMD_ADDRSPEC))
509 return (DCMD_USAGE);
511 if (mdb_getopts(argc, argv,
512 'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts,
513 'd', MDB_OPT_SETBITS, MI_DEVICE, &opts,
514 'm', MDB_OPT_SETBITS, MI_MODULE, &opts,
515 NULL) != argc)
516 return (DCMD_USAGE);
518 if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) {
519 mdb_warn("at most one filter, d for devices or m "
520 "for modules, may be specified\n");
521 return (DCMD_USAGE);
524 if ((opts == 0) && (DCMD_HDRSPEC(flags))) {
525 mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n",
526 "MI_O", "Next", "Prev");
529 if (mdb_vread(&mio, sizeof (mio), addr) == -1) {
530 mdb_warn("failed to read mi object MI_O at %p", addr);
531 return (DCMD_ERR);
534 if (opts != 0) {
535 if (mio.mi_o_isdev == B_FALSE) {
536 /* mio is a module */
537 if (!(opts & MI_MODULE) && (opts & MI_DEVICE))
538 return (DCMD_OK);
539 } else {
540 /* mio is a device */
541 if (!(opts & MI_DEVICE) && (opts & MI_MODULE))
542 return (DCMD_OK);
545 if (opts & MI_PAYLOAD)
546 mdb_printf("%p\n", addr + sizeof (MI_O));
547 else
548 mdb_printf("%p\n", addr);
549 return (DCMD_OK);
552 mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev);
554 if (mio.mi_o_isdev == B_FALSE)
555 mdb_printf("FALSE");
556 else
557 mdb_printf("TRUE ");
559 mdb_printf(" %0?p\n", mio.mi_o_dev);
561 return (DCMD_OK);
564 static int
565 ns_to_stackid(uintptr_t kaddr)
567 netstack_t nss;
569 if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) {
570 mdb_warn("failed to read netstack_t %p", kaddr);
571 return (0);
573 return (nss.netstack_stackid);
578 static void
579 netstat_tcp_verbose_pr(const tcp_t *tcp)
581 mdb_printf(" %5i %08x %08x %5i %08x %08x %5li %5i\n",
582 tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd,
583 tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss);
586 /*ARGSUSED*/
587 static int
588 netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
590 netstat_cb_data_t *ncb = cb_data;
591 uint_t opts = ncb->opts;
592 int af = ncb->af;
593 uintptr_t tcp_kaddr;
594 conn_t *connp = &ncb->conn;
595 tcp_t tcps, *tcp;
597 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
598 mdb_warn("failed to read conn_t at %p", kaddr);
599 return (WALK_ERR);
602 tcp_kaddr = (uintptr_t)connp->conn_tcp;
603 if (mdb_vread(&tcps, sizeof (tcp_t), tcp_kaddr) == -1) {
604 mdb_warn("failed to read tcp_t at %p", tcp_kaddr);
605 return (WALK_ERR);
608 tcp = &tcps;
609 connp->conn_tcp = tcp;
610 tcp->tcp_connp = connp;
612 if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) ||
613 (af == AF_INET && !net_tcp_ipv4(tcp)) ||
614 (af == AF_INET6 && !net_tcp_ipv6(tcp))) {
615 return (WALK_NEXT);
618 mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state);
619 if (af == AF_INET) {
620 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
621 mdb_printf(" ");
622 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
623 } else if (af == AF_INET6) {
624 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
625 mdb_printf(" ");
626 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
628 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
629 mdb_printf(" %4i\n", connp->conn_zoneid);
630 if (opts & NETSTAT_VERBOSE)
631 netstat_tcp_verbose_pr(tcp);
633 return (WALK_NEXT);
636 /*ARGSUSED*/
637 static int
638 netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
640 netstat_cb_data_t *ncb = cb_data;
641 uint_t opts = ncb->opts;
642 int af = ncb->af;
643 udp_t udp;
644 conn_t *connp = &ncb->conn;
645 char *state;
646 uintptr_t udp_kaddr;
648 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
649 mdb_warn("failed to read conn_t at %p", kaddr);
650 return (WALK_ERR);
653 udp_kaddr = (uintptr_t)connp->conn_udp;
654 if (mdb_vread(&udp, sizeof (udp_t), udp_kaddr) == -1) {
655 mdb_warn("failed to read conn_udp at %p", udp_kaddr);
656 return (WALK_ERR);
659 /* Need to do these reassignments for the net_udp_*() routines below. */
660 connp->conn_udp = &udp;
661 udp.udp_connp = connp;
663 if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) ||
664 (af == AF_INET && !net_udp_ipv4(&udp)) ||
665 (af == AF_INET6 && !net_udp_ipv6(&udp))) {
666 return (WALK_NEXT);
669 if (udp.udp_state == TS_UNBND)
670 state = "UNBOUND";
671 else if (udp.udp_state == TS_IDLE)
672 state = "IDLE";
673 else if (udp.udp_state == TS_DATA_XFER)
674 state = "CONNECTED";
675 else
676 state = "UNKNOWN";
678 mdb_printf("%0?p %10s ", udp_kaddr, state);
679 if (af == AF_INET) {
680 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
681 mdb_printf(" ");
682 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
683 } else if (af == AF_INET6) {
684 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
685 mdb_printf(" ");
686 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
688 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
689 mdb_printf(" %4i\n", connp->conn_zoneid);
691 return (WALK_NEXT);
694 /*ARGSUSED*/
695 static int
696 netstat_icmp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
698 netstat_cb_data_t *ncb = cb_data;
699 int af = ncb->af;
700 icmp_t icmp;
701 conn_t *connp = &ncb->conn;
702 char *state;
704 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) {
705 mdb_warn("failed to read conn_t at %p", kaddr);
706 return (WALK_ERR);
709 if (mdb_vread(&icmp, sizeof (icmp_t),
710 (uintptr_t)connp->conn_icmp) == -1) {
711 mdb_warn("failed to read conn_icmp at %p",
712 (uintptr_t)connp->conn_icmp);
713 return (WALK_ERR);
716 connp->conn_icmp = &icmp;
717 icmp.icmp_connp = connp;
719 if ((af == AF_INET && connp->conn_ipversion != IPV4_VERSION) ||
720 (af == AF_INET6 && connp->conn_ipversion != IPV6_VERSION)) {
721 return (WALK_NEXT);
724 if (icmp.icmp_state == TS_UNBND)
725 state = "UNBOUND";
726 else if (icmp.icmp_state == TS_IDLE)
727 state = "IDLE";
728 else if (icmp.icmp_state == TS_DATA_XFER)
729 state = "CONNECTED";
730 else
731 state = "UNKNOWN";
733 mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state);
734 if (af == AF_INET) {
735 net_ipv4addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
736 mdb_printf(" ");
737 net_ipv4addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
738 } else if (af == AF_INET6) {
739 net_ipv6addrport_pr(&connp->conn_laddr_v6, connp->conn_lport);
740 mdb_printf(" ");
741 net_ipv6addrport_pr(&connp->conn_faddr_v6, connp->conn_fport);
743 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack));
744 mdb_printf(" %4i\n", connp->conn_zoneid);
746 return (WALK_NEXT);
750 * print the address of a unix domain socket
752 * so is the address of a AF_UNIX struct sonode in mdb's address space
753 * soa is the address of the struct soaddr to print
755 * returns 0 on success, -1 otherwise
757 static int
758 netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa)
760 const struct sonode *so = &st->st_sonode;
761 const char none[] = " (none)";
763 if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) {
764 if (st->st_info.sti_faddr_noxlate) {
765 mdb_printf("%-14s ", " (socketpair)");
766 } else {
767 if (soa->soa_len > sizeof (sa_family_t)) {
768 char addr[MAXPATHLEN + 1];
770 if (mdb_readstr(addr, sizeof (addr),
771 (uintptr_t)&soa->soa_sa->sa_data) == -1) {
772 mdb_warn("failed to read unix address "
773 "at %p", &soa->soa_sa->sa_data);
774 return (-1);
777 mdb_printf("%-14s ", addr);
778 } else {
779 mdb_printf("%-14s ", none);
782 } else {
783 mdb_printf("%-14s ", none);
786 return (0);
789 /* based on sockfs_snapshot */
790 /*ARGSUSED*/
791 static int
792 netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
794 const struct sotpi_sonode *st = walk_data;
795 const struct sonode *so = &st->st_sonode;
796 const struct sotpi_info *sti = &st->st_info;
798 if (so->so_count == 0)
799 return (WALK_NEXT);
801 if (so->so_family != AF_UNIX) {
802 mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr);
803 return (WALK_ERR);
806 mdb_printf("%-?p ", kaddr);
808 switch (sti->sti_serv_type) {
809 case T_CLTS:
810 mdb_printf("%-10s ", "dgram");
811 break;
812 case T_COTS:
813 mdb_printf("%-10s ", "stream");
814 break;
815 case T_COTS_ORD:
816 mdb_printf("%-10s ", "stream-ord");
817 break;
818 default:
819 mdb_printf("%-10i ", sti->sti_serv_type);
822 if ((so->so_state & SS_ISBOUND) &&
823 (sti->sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
824 mdb_printf("%0?p ", sti->sti_ux_laddr.soua_vp);
825 } else {
826 mdb_printf("%0?p ", NULL);
829 if ((so->so_state & SS_ISCONNECTED) &&
830 (sti->sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) {
831 mdb_printf("%0?p ", sti->sti_ux_faddr.soua_vp);
832 } else {
833 mdb_printf("%0?p ", NULL);
836 if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1)
837 return (WALK_ERR);
839 if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1)
840 return (WALK_ERR);
842 mdb_printf("%4i\n", so->so_zoneid);
844 return (WALK_NEXT);
847 static void
848 netstat_tcp_verbose_header_pr(void)
850 mdb_printf(" %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n",
851 "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss");
854 static void
855 get_ifname(const ire_t *ire, char *intf)
857 ill_t ill;
859 *intf = '\0';
860 if (ire->ire_ill != NULL) {
861 if (mdb_vread(&ill, sizeof (ill),
862 (uintptr_t)ire->ire_ill) == -1)
863 return;
864 (void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length),
865 (uintptr_t)ill.ill_name);
869 const in6_addr_t ipv6_all_ones =
870 IN6ADDR_INITIALIZER(0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu);
872 static void
873 get_ireflags(const ire_t *ire, char *flags)
875 (void) strcpy(flags, "U");
876 /* RTF_INDIRECT wins over RTF_GATEWAY - don't display both */
877 if (ire->ire_flags & RTF_INDIRECT)
878 (void) strcat(flags, "I");
879 else if (ire->ire_type & IRE_OFFLINK)
880 (void) strcat(flags, "G");
882 /* IRE_IF_CLONE wins over RTF_HOST - don't display both */
883 if (ire->ire_type & IRE_IF_CLONE)
884 (void) strcat(flags, "C");
885 else if (ire->ire_ipversion == IPV4_VERSION) {
886 if (ire->ire_mask == IP_HOST_MASK)
887 (void) strcat(flags, "H");
888 } else {
889 if (IN6_ARE_ADDR_EQUAL(&ire->ire_mask_v6, &ipv6_all_ones))
890 (void) strcat(flags, "H");
893 if (ire->ire_flags & RTF_DYNAMIC)
894 (void) strcat(flags, "D");
895 if (ire->ire_type == IRE_BROADCAST)
896 (void) strcat(flags, "b");
897 if (ire->ire_type == IRE_MULTICAST)
898 (void) strcat(flags, "m");
899 if (ire->ire_type == IRE_LOCAL)
900 (void) strcat(flags, "L");
901 if (ire->ire_type == IRE_NOROUTE)
902 (void) strcat(flags, "N");
903 if (ire->ire_flags & RTF_SETSRC)
904 (void) strcat(flags, "S");
905 if (ire->ire_flags & RTF_REJECT)
906 (void) strcat(flags, "R");
907 if (ire->ire_flags & RTF_BLACKHOLE)
908 (void) strcat(flags, "B");
911 static int
912 netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
914 const ire_t *ire = walk_data;
915 uint_t *opts = cb_data;
916 ipaddr_t gate;
917 char flags[10], intf[LIFNAMSIZ + 1];
919 if (ire->ire_ipversion != IPV4_VERSION)
920 return (WALK_NEXT);
922 /* Skip certain IREs by default */
923 if (!(*opts & NETSTAT_ALL) &&
924 (ire->ire_type &
925 (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
926 return (WALK_NEXT);
928 if (*opts & NETSTAT_FIRST) {
929 *opts &= ~NETSTAT_FIRST;
930 mdb_printf("%<u>%s Table: IPv4%</u>\n",
931 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
932 if (*opts & NETSTAT_VERBOSE) {
933 mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt "
934 " Ref Flg Out In/Fwd%</u>\n",
935 "Address", ADDR_V4_WIDTH, "Destination",
936 ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway");
937 } else {
938 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use "
939 "Interface%</u>\n",
940 "Address", ADDR_V4_WIDTH, "Destination",
941 ADDR_V4_WIDTH, "Gateway");
945 gate = ire->ire_gateway_addr;
947 get_ireflags(ire, flags);
949 get_ifname(ire, intf);
951 if (*opts & NETSTAT_VERBOSE) {
952 mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u "
953 "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH,
954 ire->ire_mask, ADDR_V4_WIDTH, gate, intf,
955 0, ' ',
956 ire->ire_metrics.iulp_rtt, ire->ire_refcnt, flags,
957 ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
958 } else {
959 mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr,
960 ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags,
961 ire->ire_refcnt,
962 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
965 return (WALK_NEXT);
969 ip_mask_to_plen_v6(const in6_addr_t *v6mask)
971 int plen;
972 int i;
973 uint32_t val;
975 for (i = 3; i >= 0; i--)
976 if (v6mask->s6_addr32[i] != 0)
977 break;
978 if (i < 0)
979 return (0);
980 plen = 32 + 32 * i;
981 val = v6mask->s6_addr32[i];
982 while (!(val & 1)) {
983 val >>= 1;
984 plen--;
987 return (plen);
990 static int
991 netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data)
993 const ire_t *ire = walk_data;
994 uint_t *opts = cb_data;
995 const in6_addr_t *gatep;
996 char deststr[ADDR_V6_WIDTH + 5];
997 char flags[10], intf[LIFNAMSIZ + 1];
998 int masklen;
1000 if (ire->ire_ipversion != IPV6_VERSION)
1001 return (WALK_NEXT);
1003 /* Skip certain IREs by default */
1004 if (!(*opts & NETSTAT_ALL) &&
1005 (ire->ire_type &
1006 (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE)))
1007 return (WALK_NEXT);
1009 if (*opts & NETSTAT_FIRST) {
1010 *opts &= ~NETSTAT_FIRST;
1011 mdb_printf("\n%<u>%s Table: IPv6%</u>\n",
1012 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing");
1013 if (*opts & NETSTAT_VERBOSE) {
1014 mdb_printf("%<u>%-?s %-*s %-*s If PMTU Rtt Ref "
1015 "Flags Out In/Fwd%</u>\n",
1016 "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
1017 ADDR_V6_WIDTH, "Gateway");
1018 } else {
1019 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use If"
1020 "%</u>\n",
1021 "Address", ADDR_V6_WIDTH+4, "Destination/Mask",
1022 ADDR_V6_WIDTH, "Gateway");
1026 gatep = &ire->ire_gateway_addr_v6;
1028 masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6);
1029 (void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d",
1030 &ire->ire_addr_v6, masklen);
1032 get_ireflags(ire, flags);
1034 get_ifname(ire, intf);
1036 if (*opts & NETSTAT_VERBOSE) {
1037 mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n",
1038 kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep,
1039 intf, 0, ' ',
1040 ire->ire_metrics.iulp_rtt, ire->ire_refcnt,
1041 flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count);
1042 } else {
1043 mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr,
1044 ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags,
1045 ire->ire_refcnt,
1046 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf);
1049 return (WALK_NEXT);
1052 static void
1053 netstat_header_v4(int proto)
1055 if (proto == IPPROTO_TCP)
1056 mdb_printf("%<u>%-?s ", "TCPv4");
1057 else if (proto == IPPROTO_UDP)
1058 mdb_printf("%<u>%-?s ", "UDPv4");
1059 else if (proto == IPPROTO_ICMP)
1060 mdb_printf("%<u>%-?s ", "ICMPv4");
1061 mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
1062 "", ADDR_V4_WIDTH, "Local Address",
1063 "", ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone");
1066 static void
1067 netstat_header_v6(int proto)
1069 if (proto == IPPROTO_TCP)
1070 mdb_printf("%<u>%-?s ", "TCPv6");
1071 else if (proto == IPPROTO_UDP)
1072 mdb_printf("%<u>%-?s ", "UDPv6");
1073 else if (proto == IPPROTO_ICMP)
1074 mdb_printf("%<u>%-?s ", "ICMPv6");
1075 mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n",
1076 "", ADDR_V6_WIDTH, "Local Address",
1077 "", ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone");
1080 static int
1081 netstat_print_conn(const char *cache, int proto, mdb_walk_cb_t cbfunc,
1082 void *cbdata)
1084 netstat_cb_data_t *ncb = cbdata;
1086 if ((ncb->opts & NETSTAT_VERBOSE) && proto == IPPROTO_TCP)
1087 netstat_tcp_verbose_header_pr();
1088 if (mdb_walk(cache, cbfunc, cbdata) == -1) {
1089 mdb_warn("failed to walk %s", cache);
1090 return (DCMD_ERR);
1092 return (DCMD_OK);
1095 static int
1096 netstat_print_common(const char *cache, int proto, mdb_walk_cb_t cbfunc,
1097 void *cbdata)
1099 netstat_cb_data_t *ncb = cbdata;
1100 int af = ncb->af;
1101 int status = DCMD_OK;
1103 if (af != AF_INET6) {
1104 ncb->af = AF_INET;
1105 netstat_header_v4(proto);
1106 status = netstat_print_conn(cache, proto, cbfunc, cbdata);
1108 if (status == DCMD_OK && af != AF_INET) {
1109 ncb->af = AF_INET6;
1110 netstat_header_v6(proto);
1111 status = netstat_print_conn(cache, proto, cbfunc, cbdata);
1113 ncb->af = af;
1114 return (status);
1117 /*ARGSUSED*/
1119 netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1121 uint_t opts = 0;
1122 const char *optf = NULL;
1123 const char *optP = NULL;
1124 netstat_cb_data_t *cbdata;
1125 int status;
1126 int af = 0;
1128 if (mdb_getopts(argc, argv,
1129 'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts,
1130 'f', MDB_OPT_STR, &optf,
1131 'P', MDB_OPT_STR, &optP,
1132 'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts,
1133 'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts,
1134 NULL) != argc)
1135 return (DCMD_USAGE);
1137 if (optP != NULL) {
1138 if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0) &&
1139 (strcmp("icmp", optP) != 0))
1140 return (DCMD_USAGE);
1141 if (opts & NETSTAT_ROUTE)
1142 return (DCMD_USAGE);
1145 if (optf == NULL)
1146 opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX;
1147 else if (strcmp("inet", optf) == 0)
1148 opts |= NETSTAT_V4;
1149 else if (strcmp("inet6", optf) == 0)
1150 opts |= NETSTAT_V6;
1151 else if (strcmp("unix", optf) == 0)
1152 opts |= NETSTAT_UNIX;
1153 else
1154 return (DCMD_USAGE);
1156 if (opts & NETSTAT_ROUTE) {
1157 if (!(opts & (NETSTAT_V4|NETSTAT_V6)))
1158 return (DCMD_USAGE);
1159 if (opts & NETSTAT_V4) {
1160 opts |= NETSTAT_FIRST;
1161 if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) {
1162 mdb_warn("failed to walk ip`ire");
1163 return (DCMD_ERR);
1166 if (opts & NETSTAT_V6) {
1167 opts |= NETSTAT_FIRST;
1168 if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) {
1169 mdb_warn("failed to walk ip`ire");
1170 return (DCMD_ERR);
1173 return (DCMD_OK);
1176 if ((opts & NETSTAT_UNIX) && (optP == NULL)) {
1177 /* Print Unix Domain Sockets */
1178 mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n",
1179 "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr",
1180 "Remote Addr", "Zone");
1182 if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) {
1183 mdb_warn("failed to walk genunix`sonode");
1184 return (DCMD_ERR);
1186 if (!(opts & (NETSTAT_V4 | NETSTAT_V6)))
1187 return (DCMD_OK);
1190 cbdata = mdb_alloc(sizeof (netstat_cb_data_t), UM_SLEEP);
1191 cbdata->opts = opts;
1192 if ((optf != NULL) && (opts & NETSTAT_V4))
1193 af = AF_INET;
1194 else if ((optf != NULL) && (opts & NETSTAT_V6))
1195 af = AF_INET6;
1197 cbdata->af = af;
1198 if ((optP == NULL) || (strcmp("tcp", optP) == 0)) {
1199 status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP,
1200 netstat_tcp_cb, cbdata);
1201 if (status != DCMD_OK)
1202 goto out;
1205 if ((optP == NULL) || (strcmp("udp", optP) == 0)) {
1206 status = netstat_print_common("udp_conn_cache", IPPROTO_UDP,
1207 netstat_udp_cb, cbdata);
1208 if (status != DCMD_OK)
1209 goto out;
1212 if ((optP == NULL) || (strcmp("icmp", optP) == 0)) {
1213 status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP,
1214 netstat_icmp_cb, cbdata);
1215 if (status != DCMD_OK)
1216 goto out;
1218 out:
1219 mdb_free(cbdata, sizeof (netstat_cb_data_t));
1220 return (status);
1224 * "::dladm show-bridge" support
1226 typedef struct {
1227 uint_t opt_l;
1228 uint_t opt_f;
1229 uint_t opt_t;
1230 const char *name;
1231 clock_t lbolt;
1232 boolean_t found;
1233 uint_t nlinks;
1234 uint_t nfwd;
1237 * These structures are kept inside the 'args' for allocation reasons.
1238 * They're all large data structures (over 1K), and may cause the stack
1239 * to explode. mdb and kmdb will fail in these cases, and thus we
1240 * allocate them from the heap.
1242 trill_inst_t ti;
1243 bridge_link_t bl;
1244 mac_impl_t mi;
1245 } show_bridge_args_t;
1247 static void
1248 show_vlans(const uint8_t *vlans)
1250 int i, bit;
1251 uint8_t val;
1252 int rstart = -1, rnext = -1;
1254 for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) {
1255 val = vlans[i];
1256 if (i == 0)
1257 val &= ~1;
1258 while ((bit = mdb_ffs(val)) != 0) {
1259 bit--;
1260 val &= ~(1 << bit);
1261 bit += i * sizeof (*vlans) * NBBY;
1262 if (bit != rnext) {
1263 if (rnext != -1 && rstart + 1 != rnext)
1264 mdb_printf("-%d", rnext - 1);
1265 if (rstart != -1)
1266 mdb_printf(",");
1267 mdb_printf("%d", bit);
1268 rstart = bit;
1270 rnext = bit + 1;
1273 if (rnext != -1 && rstart + 1 != rnext)
1274 mdb_printf("-%d", rnext - 1);
1275 mdb_printf("\n");
1279 * This callback is invoked by a walk of the links attached to a bridge. If
1280 * we're showing link details, then they're printed here. If not, then we just
1281 * count up the links for the bridge summary.
1283 static int
1284 do_bridge_links(uintptr_t addr, const void *data, void *ptr)
1286 show_bridge_args_t *args = ptr;
1287 const bridge_link_t *blp = data;
1288 char macaddr[ETHERADDRL * 3];
1289 const char *name;
1291 args->nlinks++;
1293 if (!args->opt_l)
1294 return (WALK_NEXT);
1296 if (mdb_vread(&args->mi, sizeof (args->mi),
1297 (uintptr_t)blp->bl_mh) == -1) {
1298 mdb_warn("cannot read mac data at %p", blp->bl_mh);
1299 name = "?";
1300 } else {
1301 name = args->mi.mi_name;
1304 mdb_mac_addr(blp->bl_local_mac, ETHERADDRL, macaddr,
1305 sizeof (macaddr));
1307 mdb_printf("%-?p %-16s %-17s %03X %-4d ", addr, name, macaddr,
1308 blp->bl_flags, blp->bl_pvid);
1310 if (blp->bl_trilldata == NULL) {
1311 switch (blp->bl_state) {
1312 case BLS_BLOCKLISTEN:
1313 name = "BLOCK";
1314 break;
1315 case BLS_LEARNING:
1316 name = "LEARN";
1317 break;
1318 case BLS_FORWARDING:
1319 name = "FWD";
1320 break;
1321 default:
1322 name = "?";
1324 mdb_printf("%-5s ", name);
1325 show_vlans(blp->bl_vlans);
1326 } else {
1327 show_vlans(blp->bl_afs);
1330 return (WALK_NEXT);
1334 * It seems a shame to duplicate this code, but merging it with the link
1335 * printing code above is more trouble than it would be worth.
1337 static void
1338 print_link_name(show_bridge_args_t *args, uintptr_t addr, char sep)
1340 const char *name;
1342 if (mdb_vread(&args->bl, sizeof (args->bl), addr) == -1) {
1343 mdb_warn("cannot read bridge link at %p", addr);
1344 return;
1347 if (mdb_vread(&args->mi, sizeof (args->mi),
1348 (uintptr_t)args->bl.bl_mh) == -1) {
1349 name = "?";
1350 } else {
1351 name = args->mi.mi_name;
1354 mdb_printf("%s%c", name, sep);
1357 static int
1358 do_bridge_fwd(uintptr_t addr, const void *data, void *ptr)
1360 show_bridge_args_t *args = ptr;
1361 const bridge_fwd_t *bfp = data;
1362 char macaddr[ETHERADDRL * 3];
1363 int i;
1364 #define MAX_FWD_LINKS 16
1365 bridge_link_t *links[MAX_FWD_LINKS];
1366 uint_t nlinks;
1368 args->nfwd++;
1370 if (!args->opt_f)
1371 return (WALK_NEXT);
1373 if ((nlinks = bfp->bf_nlinks) > MAX_FWD_LINKS)
1374 nlinks = MAX_FWD_LINKS;
1376 if (mdb_vread(links, sizeof (links[0]) * nlinks,
1377 (uintptr_t)bfp->bf_links) == -1) {
1378 mdb_warn("cannot read bridge forwarding links at %p",
1379 bfp->bf_links);
1380 return (WALK_ERR);
1383 mdb_mac_addr(bfp->bf_dest, ETHERADDRL, macaddr, sizeof (macaddr));
1385 mdb_printf("%-?p %-17s ", addr, macaddr);
1386 if (bfp->bf_flags & BFF_LOCALADDR)
1387 mdb_printf("%-7s", "[self]");
1388 else
1389 mdb_printf("t-%-5d", args->lbolt - bfp->bf_lastheard);
1390 mdb_printf(" %-7u ", bfp->bf_refs);
1392 if (bfp->bf_trill_nick != 0) {
1393 mdb_printf("%d\n", bfp->bf_trill_nick);
1394 } else {
1395 for (i = 0; i < bfp->bf_nlinks; i++) {
1396 print_link_name(args, (uintptr_t)links[i],
1397 i == bfp->bf_nlinks - 1 ? '\n' : ' ');
1401 return (WALK_NEXT);
1404 static int
1405 do_show_bridge(uintptr_t addr, const void *data, void *ptr)
1407 show_bridge_args_t *args = ptr;
1408 bridge_inst_t bi;
1409 const bridge_inst_t *bip;
1410 trill_node_t tn;
1411 trill_sock_t tsp;
1412 trill_nickinfo_t tni;
1413 char bname[MAXLINKNAMELEN];
1414 char macaddr[ETHERADDRL * 3];
1415 char *cp;
1416 uint_t nnicks;
1417 int i;
1419 if (data != NULL) {
1420 bip = data;
1421 } else {
1422 if (mdb_vread(&bi, sizeof (bi), addr) == -1) {
1423 mdb_warn("cannot read bridge instance at %p", addr);
1424 return (WALK_ERR);
1426 bip = &bi;
1429 (void) strncpy(bname, bip->bi_name, sizeof (bname) - 1);
1430 bname[MAXLINKNAMELEN - 1] = '\0';
1431 cp = bname + strlen(bname);
1432 if (cp > bname && cp[-1] == '0')
1433 cp[-1] = '\0';
1435 if (args->name != NULL && strcmp(args->name, bname) != 0)
1436 return (WALK_NEXT);
1438 args->found = B_TRUE;
1439 args->nlinks = args->nfwd = 0;
1441 if (args->opt_l) {
1442 mdb_printf("%-?s %-16s %-17s %3s %-4s ", "ADDR", "LINK",
1443 "MAC-ADDR", "FLG", "PVID");
1444 if (bip->bi_trilldata == NULL)
1445 mdb_printf("%-5s %s\n", "STATE", "VLANS");
1446 else
1447 mdb_printf("%s\n", "FWD-VLANS");
1450 if (!args->opt_f && !args->opt_t &&
1451 mdb_pwalk("list", do_bridge_links, args,
1452 addr + offsetof(bridge_inst_t, bi_links)) != DCMD_OK)
1453 return (WALK_ERR);
1455 if (args->opt_f)
1456 mdb_printf("%-?s %-17s %-7s %-7s %s\n", "ADDR", "DEST", "TIME",
1457 "REFS", "OUTPUT");
1459 if (!args->opt_l && !args->opt_t &&
1460 mdb_pwalk("avl", do_bridge_fwd, args,
1461 addr + offsetof(bridge_inst_t, bi_fwd)) != DCMD_OK)
1462 return (WALK_ERR);
1464 nnicks = 0;
1465 if (bip->bi_trilldata != NULL && !args->opt_l && !args->opt_f) {
1466 if (mdb_vread(&args->ti, sizeof (args->ti),
1467 (uintptr_t)bip->bi_trilldata) == -1) {
1468 mdb_warn("cannot read trill instance at %p",
1469 bip->bi_trilldata);
1470 return (WALK_ERR);
1472 if (args->opt_t)
1473 mdb_printf("%-?s %-5s %-17s %s\n", "ADDR",
1474 "NICK", "NEXT-HOP", "LINK");
1475 for (i = 0; i < RBRIDGE_NICKNAME_MAX; i++) {
1476 if (args->ti.ti_nodes[i] == NULL)
1477 continue;
1478 if (args->opt_t) {
1479 if (mdb_vread(&tn, sizeof (tn),
1480 (uintptr_t)args->ti.ti_nodes[i]) == -1) {
1481 mdb_warn("cannot read trill node %d at "
1482 "%p", i, args->ti.ti_nodes[i]);
1483 return (WALK_ERR);
1485 if (mdb_vread(&tni, sizeof (tni),
1486 (uintptr_t)tn.tn_ni) == -1) {
1487 mdb_warn("cannot read trill node info "
1488 "%d at %p", i, tn.tn_ni);
1489 return (WALK_ERR);
1491 mdb_mac_addr(tni.tni_adjsnpa, ETHERADDRL,
1492 macaddr, sizeof (macaddr));
1493 if (tni.tni_nick == args->ti.ti_nick) {
1494 (void) strcpy(macaddr, "[self]");
1496 mdb_printf("%-?p %-5u %-17s ",
1497 args->ti.ti_nodes[i], tni.tni_nick,
1498 macaddr);
1499 if (tn.tn_tsp != NULL) {
1500 if (mdb_vread(&tsp, sizeof (tsp),
1501 (uintptr_t)tn.tn_tsp) == -1) {
1502 mdb_warn("cannot read trill "
1503 "socket info at %p",
1504 tn.tn_tsp);
1505 return (WALK_ERR);
1507 if (tsp.ts_link != NULL) {
1508 print_link_name(args,
1509 (uintptr_t)tsp.ts_link,
1510 '\n');
1511 continue;
1514 mdb_printf("--\n");
1515 } else {
1516 nnicks++;
1519 } else {
1520 if (args->opt_t)
1521 mdb_printf("bridge is not running TRILL\n");
1524 if (!args->opt_l && !args->opt_f && !args->opt_t) {
1525 mdb_printf("%-?p %-7s %-16s %-7u %-7u", addr,
1526 bip->bi_trilldata == NULL ? "stp" : "trill", bname,
1527 args->nlinks, args->nfwd);
1528 if (bip->bi_trilldata != NULL)
1529 mdb_printf(" %-7u %u\n", nnicks, args->ti.ti_nick);
1530 else
1531 mdb_printf(" %-7s %s\n", "--", "--");
1533 return (WALK_NEXT);
1536 static int
1537 dladm_show_bridge(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1539 show_bridge_args_t *args;
1540 GElf_Sym sym;
1541 int i;
1543 args = mdb_zalloc(sizeof (*args), UM_SLEEP);
1545 i = mdb_getopts(argc, argv,
1546 'l', MDB_OPT_SETBITS, 1, &args->opt_l,
1547 'f', MDB_OPT_SETBITS, 1, &args->opt_f,
1548 't', MDB_OPT_SETBITS, 1, &args->opt_t,
1549 NULL);
1551 argc -= i;
1552 argv += i;
1554 if (argc > 1 || (argc == 1 && argv[0].a_type != MDB_TYPE_STRING)) {
1555 mdb_free(args, sizeof (*args));
1556 return (DCMD_USAGE);
1558 if (argc == 1)
1559 args->name = argv[0].a_un.a_str;
1561 if ((args->lbolt = mdb_get_lbolt()) == -1) {
1562 mdb_warn("failed to read lbolt");
1563 goto err;
1566 if (flags & DCMD_ADDRSPEC) {
1567 if (args->name != NULL) {
1568 mdb_printf("bridge name and address are mutually "
1569 "exclusive\n");
1570 goto err;
1572 if (!args->opt_l && !args->opt_f && !args->opt_t)
1573 mdb_printf("%-?s %-7s %-16s %-7s %-7s\n", "ADDR",
1574 "PROTECT", "NAME", "NLINKS", "NFWD");
1575 if (do_show_bridge(addr, NULL, args) != WALK_NEXT)
1576 goto err;
1577 mdb_free(args, sizeof (*args));
1578 return (DCMD_OK);
1579 } else {
1580 if ((args->opt_l || args->opt_f || args->opt_t) &&
1581 args->name == NULL) {
1582 mdb_printf("need bridge name or address with -[lft]\n");
1583 goto err;
1585 if (mdb_lookup_by_obj("bridge", "inst_list", &sym) == -1) {
1586 mdb_warn("failed to find 'bridge`inst_list'");
1587 goto err;
1589 if (!args->opt_l && !args->opt_f && !args->opt_t)
1590 mdb_printf("%-?s %-7s %-16s %-7s %-7s %-7s %s\n",
1591 "ADDR", "PROTECT", "NAME", "NLINKS", "NFWD",
1592 "NNICKS", "NICK");
1593 if (mdb_pwalk("list", do_show_bridge, args,
1594 (uintptr_t)sym.st_value) != DCMD_OK)
1595 goto err;
1596 if (!args->found && args->name != NULL) {
1597 mdb_printf("bridge instance %s not found\n",
1598 args->name);
1599 goto err;
1601 mdb_free(args, sizeof (*args));
1602 return (DCMD_OK);
1605 err:
1606 mdb_free(args, sizeof (*args));
1607 return (DCMD_ERR);
1611 * Support for the "::dladm" dcmd
1614 dladm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1616 if (argc < 1 || argv[0].a_type != MDB_TYPE_STRING)
1617 return (DCMD_USAGE);
1620 * This could be a bit more elaborate, once we support more of the
1621 * dladm show-* subcommands.
1623 argc--;
1624 argv++;
1625 if (strcmp(argv[-1].a_un.a_str, "show-bridge") == 0)
1626 return (dladm_show_bridge(addr, flags, argc, argv));
1628 return (DCMD_USAGE);
1631 void
1632 dladm_help(void)
1634 mdb_printf("Subcommands:\n"
1635 " show-bridge [-flt] [<name>]\n"
1636 "\t Show bridge information; -l for links and -f for "
1637 "forwarding\n"
1638 "\t entries, and -t for TRILL nicknames. Address is required "
1639 "if name\n"
1640 "\t is not specified.\n");