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