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 <fs/sockfs/socktpi_impl.h> 51 #include <net/bridge_impl.h> 52 #include <io/trill_impl.h> 53 #include <sys/mac_impl.h> 54 55 #define ADDR_V6_WIDTH 23 56 #define ADDR_V4_WIDTH 15 57 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 64 65 #define NETSTAT_FIRST 0x80000000u 66 67 typedef struct netstat_cb_data_s { 68 uint_t opts; 69 conn_t conn; 70 int af; 71 } netstat_cb_data_t; 72 73 int 74 icmp_stacks_walk_init(mdb_walk_state_t *wsp) 75 { 76 if (mdb_layered_walk("netstack", wsp) == -1) { 77 mdb_warn("can't walk 'netstack'"); 78 return (WALK_ERR); 79 } 80 return (WALK_NEXT); 81 } 82 83 int 84 icmp_stacks_walk_step(mdb_walk_state_t *wsp) 85 { 86 uintptr_t kaddr; 87 netstack_t nss; 88 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); 92 } 93 kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP]; 94 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 95 } 96 97 int 98 tcp_stacks_walk_init(mdb_walk_state_t *wsp) 99 { 100 if (mdb_layered_walk("netstack", wsp) == -1) { 101 mdb_warn("can't walk 'netstack'"); 102 return (WALK_ERR); 103 } 104 return (WALK_NEXT); 105 } 106 107 int 108 tcp_stacks_walk_step(mdb_walk_state_t *wsp) 109 { 110 uintptr_t kaddr; 111 netstack_t nss; 112 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); 116 } 117 kaddr = (uintptr_t)nss.netstack_modules[NS_TCP]; 118 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 119 } 120 121 int 122 udp_stacks_walk_init(mdb_walk_state_t *wsp) 123 { 124 if (mdb_layered_walk("netstack", wsp) == -1) { 125 mdb_warn("can't walk 'netstack'"); 126 return (WALK_ERR); 127 } 128 return (WALK_NEXT); 129 } 130 131 int 132 udp_stacks_walk_step(mdb_walk_state_t *wsp) 133 { 134 uintptr_t kaddr; 135 netstack_t nss; 136 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); 140 } 141 kaddr = (uintptr_t)nss.netstack_modules[NS_UDP]; 142 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 143 } 144 145 /* 146 * Print an IPv4 address and port number in a compact and easy to read format 147 * The arguments are in network byte order 148 */ 149 static void 150 net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport) 151 { 152 uint32_t naddr = V4_PART_OF_V6((*nipv6addr)); 153 154 mdb_nhconvert(&nport, &nport, sizeof (nport)); 155 mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport); 156 } 157 158 /* 159 * Print an IPv6 address and port number in a compact and easy to read format 160 * The arguments are in network byte order 161 */ 162 static void 163 net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport) 164 { 165 mdb_nhconvert(&nport, &nport, sizeof (nport)); 166 mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport); 167 } 168 169 static int 170 net_tcp_active(const tcp_t *tcp) 171 { 172 return (tcp->tcp_state >= TCPS_ESTABLISHED); 173 } 174 175 static int 176 net_tcp_ipv4(const tcp_t *tcp) 177 { 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))); 181 } 182 183 static int 184 net_tcp_ipv6(const tcp_t *tcp) 185 { 186 return (tcp->tcp_connp->conn_ipversion == IPV6_VERSION); 187 } 188 189 static int 190 net_udp_active(const udp_t *udp) 191 { 192 return ((udp->udp_state == TS_IDLE) || 193 (udp->udp_state == TS_DATA_XFER)); 194 } 195 196 static int 197 net_udp_ipv4(const udp_t *udp) 198 { 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))); 202 } 203 204 static int 205 net_udp_ipv6(const udp_t *udp) 206 { 207 return (udp->udp_connp->conn_ipversion == IPV6_VERSION); 208 } 209 210 int 211 sonode_walk_init(mdb_walk_state_t *wsp) 212 { 213 if (wsp->walk_addr == 0) { 214 GElf_Sym sym; 215 struct socklist *slp; 216 217 if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) { 218 mdb_warn("failed to lookup sockfs`socklist"); 219 return (WALK_ERR); 220 } 221 222 slp = (struct socklist *)(uintptr_t)sym.st_value; 223 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); 229 } 230 } 231 232 wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP); 233 return (WALK_NEXT); 234 } 235 236 int 237 sonode_walk_step(mdb_walk_state_t *wsp) 238 { 239 int status; 240 struct sotpi_sonode *stp; 241 242 if (wsp->walk_addr == 0) 243 return (WALK_DONE); 244 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); 249 } 250 251 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 252 wsp->walk_cbdata); 253 254 stp = wsp->walk_data; 255 256 wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so; 257 return (status); 258 } 259 260 void 261 sonode_walk_fini(mdb_walk_state_t *wsp) 262 { 263 mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode)); 264 } 265 266 struct mi_walk_data { 267 uintptr_t mi_wd_miofirst; 268 MI_O mi_wd_miodata; 269 }; 270 271 int 272 mi_walk_init(mdb_walk_state_t *wsp) 273 { 274 struct mi_walk_data *wdp; 275 276 if (wsp->walk_addr == 0) { 277 mdb_warn("mi doesn't support global walks\n"); 278 return (WALK_ERR); 279 } 280 281 wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP); 282 283 /* So that we do not immediately return WALK_DONE below */ 284 wdp->mi_wd_miofirst = 0; 285 286 wsp->walk_data = wdp; 287 return (WALK_NEXT); 288 } 289 290 int 291 mi_walk_step(mdb_walk_state_t *wsp) 292 { 293 struct mi_walk_data *wdp = wsp->walk_data; 294 MI_OP miop = &wdp->mi_wd_miodata; 295 int status; 296 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); 301 } 302 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); 306 } 307 308 /* Only true in the first iteration */ 309 if (wdp->mi_wd_miofirst == 0) { 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); 315 } 316 317 wsp->walk_addr = (uintptr_t)miop->mi_o_next; 318 return (status); 319 } 320 321 void 322 mi_walk_fini(mdb_walk_state_t *wsp) 323 { 324 mdb_free(wsp->walk_data, sizeof (struct mi_walk_data)); 325 } 326 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; 333 334 #define MI_PAYLOAD_DEVICE 0x1 335 #define MI_PAYLOAD_MODULE 0x2 336 337 int 338 mi_payload_walk_init(mdb_walk_state_t *wsp) 339 { 340 const mi_payload_walk_arg_t *arg = wsp->walk_arg; 341 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); 345 } 346 return (WALK_NEXT); 347 } 348 349 int 350 mi_payload_walk_step(mdb_walk_state_t *wsp) 351 { 352 const mi_payload_walk_arg_t *arg = wsp->walk_arg; 353 uintptr_t kaddr; 354 355 kaddr = wsp->walk_addr + arg->mi_pwa_head_off; 356 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); 361 } 362 363 if (kaddr == 0) { 364 /* Empty list */ 365 return (WALK_DONE); 366 } 367 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); 372 } 373 return (WALK_NEXT); 374 } 375 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 379 }; 380 381 int 382 sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 383 { 384 const char *optf = NULL; 385 const char *optt = NULL; 386 const char *optp = NULL; 387 int family = AF_UNSPEC, type = 0, proto = 0; 388 int filter = 0; 389 struct sonode so; 390 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); 396 } 397 398 return (DCMD_OK); 399 } 400 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); 407 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; 418 } 419 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; 430 } 431 432 if (optp != NULL) { 433 proto = mdb_strtoull(optp); 434 filter = 1; 435 } 436 437 if (DCMD_HDRSPEC(flags) && !filter) { 438 mdb_printf("%<u>%-?s Family Type Proto State Mode Flag " 439 "AccessVP%</u>\n", "Sonode:"); 440 } 441 442 if (mdb_vread(&so, sizeof (so), addr) == -1) { 443 mdb_warn("failed to read sonode at %p", addr); 444 return (DCMD_ERR); 445 } 446 447 if ((optf != NULL) && (so.so_family != family)) 448 return (DCMD_OK); 449 450 if ((optt != NULL) && (so.so_type != type)) 451 return (DCMD_OK); 452 453 if ((optp != NULL) && (so.so_protocol != proto)) 454 return (DCMD_OK); 455 456 if (filter) { 457 mdb_printf("%0?p\n", addr); 458 return (DCMD_OK); 459 } 460 461 mdb_printf("%0?p ", addr); 462 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); 475 } 476 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); 489 } 490 491 mdb_printf(" %5hi %05x %04x %04hx\n", 492 so.so_protocol, so.so_state, so.so_mode, 493 so.so_flag); 494 495 return (DCMD_OK); 496 } 497 498 #define MI_PAYLOAD 0x1 499 #define MI_DEVICE 0x2 500 #define MI_MODULE 0x4 501 502 int 503 mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 504 { 505 uint_t opts = 0; 506 MI_O mio; 507 508 if (!(flags & DCMD_ADDRSPEC)) 509 return (DCMD_USAGE); 510 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); 517 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); 522 } 523 524 if ((opts == 0) && (DCMD_HDRSPEC(flags))) { 525 mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n", 526 "MI_O", "Next", "Prev"); 527 } 528 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); 532 } 533 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); 543 } 544 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); 550 } 551 552 mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev); 553 554 if (mio.mi_o_isdev == B_FALSE) 555 mdb_printf("FALSE"); 556 else 557 mdb_printf("TRUE "); 558 559 mdb_printf(" %0?p\n", mio.mi_o_dev); 560 561 return (DCMD_OK); 562 } 563 564 static int 565 ns_to_stackid(uintptr_t kaddr) 566 { 567 netstack_t nss; 568 569 if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) { 570 mdb_warn("failed to read netstack_t %p", kaddr); 571 return (0); 572 } 573 return (nss.netstack_stackid); 574 } 575 576 577 578 static void 579 netstat_tcp_verbose_pr(const tcp_t *tcp) 580 { 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); 584 } 585 586 /*ARGSUSED*/ 587 static int 588 netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 589 { 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; 596 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); 600 } 601 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); 606 } 607 608 tcp = &tcps; 609 connp->conn_tcp = tcp; 610 tcp->tcp_connp = connp; 611 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); 616 } 617 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); 627 } 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); 632 633 return (WALK_NEXT); 634 } 635 636 /*ARGSUSED*/ 637 static int 638 netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 639 { 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; 647 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); 651 } 652 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); 657 } 658 659 /* Need to do these reassignments for the net_udp_*() routines below. */ 660 connp->conn_udp = &udp; 661 udp.udp_connp = connp; 662 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); 667 } 668 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"; 677 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); 687 } 688 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack)); 689 mdb_printf(" %4i\n", connp->conn_zoneid); 690 691 return (WALK_NEXT); 692 } 693 694 /*ARGSUSED*/ 695 static int 696 netstat_icmp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 697 { 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; 703 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); 707 } 708 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); 714 } 715 716 connp->conn_icmp = &icmp; 717 icmp.icmp_connp = connp; 718 719 if ((af == AF_INET && connp->conn_ipversion != IPV4_VERSION) || 720 (af == AF_INET6 && connp->conn_ipversion != IPV6_VERSION)) { 721 return (WALK_NEXT); 722 } 723 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"; 732 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); 742 } 743 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack)); 744 mdb_printf(" %4i\n", connp->conn_zoneid); 745 746 return (WALK_NEXT); 747 } 748 749 /* 750 * print the address of a unix domain socket 751 * 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 754 * 755 * returns 0 on success, -1 otherwise 756 */ 757 static int 758 netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa) 759 { 760 const struct sonode *so = &st->st_sonode; 761 const char none[] = " (none)"; 762 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]; 769 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); 775 } 776 777 mdb_printf("%-14s ", addr); 778 } else { 779 mdb_printf("%-14s ", none); 780 } 781 } 782 } else { 783 mdb_printf("%-14s ", none); 784 } 785 786 return (0); 787 } 788 789 /* based on sockfs_snapshot */ 790 /*ARGSUSED*/ 791 static int 792 netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 793 { 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; 797 798 if (so->so_count == 0) 799 return (WALK_NEXT); 800 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); 804 } 805 806 mdb_printf("%-?p ", kaddr); 807 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); 820 } 821 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); 827 } 828 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); 834 } 835 836 if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1) 837 return (WALK_ERR); 838 839 if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1) 840 return (WALK_ERR); 841 842 mdb_printf("%4i\n", so->so_zoneid); 843 844 return (WALK_NEXT); 845 } 846 847 static void 848 netstat_tcp_verbose_header_pr(void) 849 { 850 mdb_printf(" %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n", 851 "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss"); 852 } 853 854 static void 855 get_ifname(const ire_t *ire, char *intf) 856 { 857 ill_t ill; 858 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); 866 } 867 } 868 869 const in6_addr_t ipv6_all_ones = 870 { 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU }; 871 872 static void 873 get_ireflags(const ire_t *ire, char *flags) 874 { 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"); 881 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"); 891 } 892 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_MULTIRT) 904 (void) strcat(flags, "M"); 905 if (ire->ire_flags & RTF_SETSRC) 906 (void) strcat(flags, "S"); 907 if (ire->ire_flags & RTF_REJECT) 908 (void) strcat(flags, "R"); 909 if (ire->ire_flags & RTF_BLACKHOLE) 910 (void) strcat(flags, "B"); 911 } 912 913 static int 914 netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 915 { 916 const ire_t *ire = walk_data; 917 uint_t *opts = cb_data; 918 ipaddr_t gate; 919 char flags[10], intf[LIFNAMSIZ + 1]; 920 921 if (ire->ire_ipversion != IPV4_VERSION) 922 return (WALK_NEXT); 923 924 /* Skip certain IREs by default */ 925 if (!(*opts & NETSTAT_ALL) && 926 (ire->ire_type & 927 (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE))) 928 return (WALK_NEXT); 929 930 if (*opts & NETSTAT_FIRST) { 931 *opts &= ~NETSTAT_FIRST; 932 mdb_printf("%<u>%s Table: IPv4%</u>\n", 933 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing"); 934 if (*opts & NETSTAT_VERBOSE) { 935 mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt " 936 " Ref Flg Out In/Fwd%</u>\n", 937 "Address", ADDR_V4_WIDTH, "Destination", 938 ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway"); 939 } else { 940 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use " 941 "Interface%</u>\n", 942 "Address", ADDR_V4_WIDTH, "Destination", 943 ADDR_V4_WIDTH, "Gateway"); 944 } 945 } 946 947 gate = ire->ire_gateway_addr; 948 949 get_ireflags(ire, flags); 950 951 get_ifname(ire, intf); 952 953 if (*opts & NETSTAT_VERBOSE) { 954 mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u " 955 "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, 956 ire->ire_mask, ADDR_V4_WIDTH, gate, intf, 957 0, ' ', 958 ire->ire_metrics.iulp_rtt, ire->ire_refcnt, flags, 959 ire->ire_ob_pkt_count, ire->ire_ib_pkt_count); 960 } else { 961 mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr, 962 ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags, 963 ire->ire_refcnt, 964 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf); 965 } 966 967 return (WALK_NEXT); 968 } 969 970 int 971 ip_mask_to_plen_v6(const in6_addr_t *v6mask) 972 { 973 int plen; 974 int i; 975 uint32_t val; 976 977 for (i = 3; i >= 0; i--) 978 if (v6mask->s6_addr32[i] != 0) 979 break; 980 if (i < 0) 981 return (0); 982 plen = 32 + 32 * i; 983 val = v6mask->s6_addr32[i]; 984 while (!(val & 1)) { 985 val >>= 1; 986 plen--; 987 } 988 989 return (plen); 990 } 991 992 static int 993 netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 994 { 995 const ire_t *ire = walk_data; 996 uint_t *opts = cb_data; 997 const in6_addr_t *gatep; 998 char deststr[ADDR_V6_WIDTH + 5]; 999 char flags[10], intf[LIFNAMSIZ + 1]; 1000 int masklen; 1001 1002 if (ire->ire_ipversion != IPV6_VERSION) 1003 return (WALK_NEXT); 1004 1005 /* Skip certain IREs by default */ 1006 if (!(*opts & NETSTAT_ALL) && 1007 (ire->ire_type & 1008 (IRE_BROADCAST|IRE_LOCAL|IRE_MULTICAST|IRE_NOROUTE|IRE_IF_CLONE))) 1009 return (WALK_NEXT); 1010 1011 if (*opts & NETSTAT_FIRST) { 1012 *opts &= ~NETSTAT_FIRST; 1013 mdb_printf("\n%<u>%s Table: IPv6%</u>\n", 1014 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing"); 1015 if (*opts & NETSTAT_VERBOSE) { 1016 mdb_printf("%<u>%-?s %-*s %-*s If PMTU Rtt Ref " 1017 "Flags Out In/Fwd%</u>\n", 1018 "Address", ADDR_V6_WIDTH+4, "Destination/Mask", 1019 ADDR_V6_WIDTH, "Gateway"); 1020 } else { 1021 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use If" 1022 "%</u>\n", 1023 "Address", ADDR_V6_WIDTH+4, "Destination/Mask", 1024 ADDR_V6_WIDTH, "Gateway"); 1025 } 1026 } 1027 1028 gatep = &ire->ire_gateway_addr_v6; 1029 1030 masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6); 1031 (void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d", 1032 &ire->ire_addr_v6, masklen); 1033 1034 get_ireflags(ire, flags); 1035 1036 get_ifname(ire, intf); 1037 1038 if (*opts & NETSTAT_VERBOSE) { 1039 mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n", 1040 kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, 1041 intf, 0, ' ', 1042 ire->ire_metrics.iulp_rtt, ire->ire_refcnt, 1043 flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count); 1044 } else { 1045 mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr, 1046 ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags, 1047 ire->ire_refcnt, 1048 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf); 1049 } 1050 1051 return (WALK_NEXT); 1052 } 1053 1054 static void 1055 netstat_header_v4(int proto) 1056 { 1057 if (proto == IPPROTO_TCP) 1058 mdb_printf("%<u>%-?s ", "TCPv4"); 1059 else if (proto == IPPROTO_UDP) 1060 mdb_printf("%<u>%-?s ", "UDPv4"); 1061 else if (proto == IPPROTO_ICMP) 1062 mdb_printf("%<u>%-?s ", "ICMPv4"); 1063 mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n", 1064 "", ADDR_V4_WIDTH, "Local Address", 1065 "", ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone"); 1066 } 1067 1068 static void 1069 netstat_header_v6(int proto) 1070 { 1071 if (proto == IPPROTO_TCP) 1072 mdb_printf("%<u>%-?s ", "TCPv6"); 1073 else if (proto == IPPROTO_UDP) 1074 mdb_printf("%<u>%-?s ", "UDPv6"); 1075 else if (proto == IPPROTO_ICMP) 1076 mdb_printf("%<u>%-?s ", "ICMPv6"); 1077 mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n", 1078 "", ADDR_V6_WIDTH, "Local Address", 1079 "", ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone"); 1080 } 1081 1082 static int 1083 netstat_print_conn(const char *cache, int proto, mdb_walk_cb_t cbfunc, 1084 void *cbdata) 1085 { 1086 netstat_cb_data_t *ncb = cbdata; 1087 1088 if ((ncb->opts & NETSTAT_VERBOSE) && proto == IPPROTO_TCP) 1089 netstat_tcp_verbose_header_pr(); 1090 if (mdb_walk(cache, cbfunc, cbdata) == -1) { 1091 mdb_warn("failed to walk %s", cache); 1092 return (DCMD_ERR); 1093 } 1094 return (DCMD_OK); 1095 } 1096 1097 static int 1098 netstat_print_common(const char *cache, int proto, mdb_walk_cb_t cbfunc, 1099 void *cbdata) 1100 { 1101 netstat_cb_data_t *ncb = cbdata; 1102 int af = ncb->af; 1103 int status = DCMD_OK; 1104 1105 if (af != AF_INET6) { 1106 ncb->af = AF_INET; 1107 netstat_header_v4(proto); 1108 status = netstat_print_conn(cache, proto, cbfunc, cbdata); 1109 } 1110 if (status == DCMD_OK && af != AF_INET) { 1111 ncb->af = AF_INET6; 1112 netstat_header_v6(proto); 1113 status = netstat_print_conn(cache, proto, cbfunc, cbdata); 1114 } 1115 ncb->af = af; 1116 return (status); 1117 } 1118 1119 /*ARGSUSED*/ 1120 int 1121 netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1122 { 1123 uint_t opts = 0; 1124 const char *optf = NULL; 1125 const char *optP = NULL; 1126 netstat_cb_data_t *cbdata; 1127 int status; 1128 int af = 0; 1129 1130 if (mdb_getopts(argc, argv, 1131 'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts, 1132 'f', MDB_OPT_STR, &optf, 1133 'P', MDB_OPT_STR, &optP, 1134 'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts, 1135 'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts, 1136 NULL) != argc) 1137 return (DCMD_USAGE); 1138 1139 if (optP != NULL) { 1140 if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0) && 1141 (strcmp("icmp", optP) != 0)) 1142 return (DCMD_USAGE); 1143 if (opts & NETSTAT_ROUTE) 1144 return (DCMD_USAGE); 1145 } 1146 1147 if (optf == NULL) 1148 opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX; 1149 else if (strcmp("inet", optf) == 0) 1150 opts |= NETSTAT_V4; 1151 else if (strcmp("inet6", optf) == 0) 1152 opts |= NETSTAT_V6; 1153 else if (strcmp("unix", optf) == 0) 1154 opts |= NETSTAT_UNIX; 1155 else 1156 return (DCMD_USAGE); 1157 1158 if (opts & NETSTAT_ROUTE) { 1159 if (!(opts & (NETSTAT_V4|NETSTAT_V6))) 1160 return (DCMD_USAGE); 1161 if (opts & NETSTAT_V4) { 1162 opts |= NETSTAT_FIRST; 1163 if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) { 1164 mdb_warn("failed to walk ip`ire"); 1165 return (DCMD_ERR); 1166 } 1167 } 1168 if (opts & NETSTAT_V6) { 1169 opts |= NETSTAT_FIRST; 1170 if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) { 1171 mdb_warn("failed to walk ip`ire"); 1172 return (DCMD_ERR); 1173 } 1174 } 1175 return (DCMD_OK); 1176 } 1177 1178 if ((opts & NETSTAT_UNIX) && (optP == NULL)) { 1179 /* Print Unix Domain Sockets */ 1180 mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n", 1181 "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr", 1182 "Remote Addr", "Zone"); 1183 1184 if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) { 1185 mdb_warn("failed to walk genunix`sonode"); 1186 return (DCMD_ERR); 1187 } 1188 if (!(opts & (NETSTAT_V4 | NETSTAT_V6))) 1189 return (DCMD_OK); 1190 } 1191 1192 cbdata = mdb_alloc(sizeof (netstat_cb_data_t), UM_SLEEP); 1193 cbdata->opts = opts; 1194 if ((optf != NULL) && (opts & NETSTAT_V4)) 1195 af = AF_INET; 1196 else if ((optf != NULL) && (opts & NETSTAT_V6)) 1197 af = AF_INET6; 1198 1199 cbdata->af = af; 1200 if ((optP == NULL) || (strcmp("tcp", optP) == 0)) { 1201 status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP, 1202 netstat_tcp_cb, cbdata); 1203 if (status != DCMD_OK) 1204 goto out; 1205 } 1206 1207 if ((optP == NULL) || (strcmp("udp", optP) == 0)) { 1208 status = netstat_print_common("udp_conn_cache", IPPROTO_UDP, 1209 netstat_udp_cb, cbdata); 1210 if (status != DCMD_OK) 1211 goto out; 1212 } 1213 1214 if ((optP == NULL) || (strcmp("icmp", optP) == 0)) { 1215 status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP, 1216 netstat_icmp_cb, cbdata); 1217 if (status != DCMD_OK) 1218 goto out; 1219 } 1220 out: 1221 mdb_free(cbdata, sizeof (netstat_cb_data_t)); 1222 return (status); 1223 } 1224 1225 /* 1226 * "::dladm show-bridge" support 1227 */ 1228 typedef struct { 1229 uint_t opt_l; 1230 uint_t opt_f; 1231 uint_t opt_t; 1232 const char *name; 1233 clock_t lbolt; 1234 boolean_t found; 1235 uint_t nlinks; 1236 uint_t nfwd; 1237 1238 /* 1239 * These structures are kept inside the 'args' for allocation reasons. 1240 * They're all large data structures (over 1K), and may cause the stack 1241 * to explode. mdb and kmdb will fail in these cases, and thus we 1242 * allocate them from the heap. 1243 */ 1244 trill_inst_t ti; 1245 bridge_link_t bl; 1246 mac_impl_t mi; 1247 } show_bridge_args_t; 1248 1249 static void 1250 show_vlans(const uint8_t *vlans) 1251 { 1252 int i, bit; 1253 uint8_t val; 1254 int rstart = -1, rnext = -1; 1255 1256 for (i = 0; i < BRIDGE_VLAN_ARR_SIZE; i++) { 1257 val = vlans[i]; 1258 if (i == 0) 1259 val &= ~1; 1260 while ((bit = mdb_ffs(val)) != 0) { 1261 bit--; 1262 val &= ~(1 << bit); 1263 bit += i * sizeof (*vlans) * NBBY; 1264 if (bit != rnext) { 1265 if (rnext != -1 && rstart + 1 != rnext) 1266 mdb_printf("-%d", rnext - 1); 1267 if (rstart != -1) 1268 mdb_printf(","); 1269 mdb_printf("%d", bit); 1270 rstart = bit; 1271 } 1272 rnext = bit + 1; 1273 } 1274 } 1275 if (rnext != -1 && rstart + 1 != rnext) 1276 mdb_printf("-%d", rnext - 1); 1277 mdb_printf("\n"); 1278 } 1279 1280 /* 1281 * This callback is invoked by a walk of the links attached to a bridge. If 1282 * we're showing link details, then they're printed here. If not, then we just 1283 * count up the links for the bridge summary. 1284 */ 1285 static int 1286 do_bridge_links(uintptr_t addr, const void *data, void *ptr) 1287 { 1288 show_bridge_args_t *args = ptr; 1289 const bridge_link_t *blp = data; 1290 char macaddr[ETHERADDRL * 3]; 1291 const char *name; 1292 1293 args->nlinks++; 1294 1295 if (!args->opt_l) 1296 return (WALK_NEXT); 1297 1298 if (mdb_vread(&args->mi, sizeof (args->mi), 1299 (uintptr_t)blp->bl_mh) == -1) { 1300 mdb_warn("cannot read mac data at %p", blp->bl_mh); 1301 name = "?"; 1302 } else { 1303 name = args->mi.mi_name; 1304 } 1305 1306 mdb_mac_addr(blp->bl_local_mac, ETHERADDRL, macaddr, 1307 sizeof (macaddr)); 1308 1309 mdb_printf("%-?p %-16s %-17s %03X %-4d ", addr, name, macaddr, 1310 blp->bl_flags, blp->bl_pvid); 1311 1312 if (blp->bl_trilldata == NULL) { 1313 switch (blp->bl_state) { 1314 case BLS_BLOCKLISTEN: 1315 name = "BLOCK"; 1316 break; 1317 case BLS_LEARNING: 1318 name = "LEARN"; 1319 break; 1320 case BLS_FORWARDING: 1321 name = "FWD"; 1322 break; 1323 default: 1324 name = "?"; 1325 } 1326 mdb_printf("%-5s ", name); 1327 show_vlans(blp->bl_vlans); 1328 } else { 1329 show_vlans(blp->bl_afs); 1330 } 1331 1332 return (WALK_NEXT); 1333 } 1334 1335 /* 1336 * It seems a shame to duplicate this code, but merging it with the link 1337 * printing code above is more trouble than it would be worth. 1338 */ 1339 static void 1340 print_link_name(show_bridge_args_t *args, uintptr_t addr, char sep) 1341 { 1342 const char *name; 1343 1344 if (mdb_vread(&args->bl, sizeof (args->bl), addr) == -1) { 1345 mdb_warn("cannot read bridge link at %p", addr); 1346 return; 1347 } 1348 1349 if (mdb_vread(&args->mi, sizeof (args->mi), 1350 (uintptr_t)args->bl.bl_mh) == -1) { 1351 name = "?"; 1352 } else { 1353 name = args->mi.mi_name; 1354 } 1355 1356 mdb_printf("%s%c", name, sep); 1357 } 1358 1359 static int 1360 do_bridge_fwd(uintptr_t addr, const void *data, void *ptr) 1361 { 1362 show_bridge_args_t *args = ptr; 1363 const bridge_fwd_t *bfp = data; 1364 char macaddr[ETHERADDRL * 3]; 1365 int i; 1366 #define MAX_FWD_LINKS 16 1367 bridge_link_t *links[MAX_FWD_LINKS]; 1368 uint_t nlinks; 1369 1370 args->nfwd++; 1371 1372 if (!args->opt_f) 1373 return (WALK_NEXT); 1374 1375 if ((nlinks = bfp->bf_nlinks) > MAX_FWD_LINKS) 1376 nlinks = MAX_FWD_LINKS; 1377 1378 if (mdb_vread(links, sizeof (links[0]) * nlinks, 1379 (uintptr_t)bfp->bf_links) == -1) { 1380 mdb_warn("cannot read bridge forwarding links at %p", 1381 bfp->bf_links); 1382 return (WALK_ERR); 1383 } 1384 1385 mdb_mac_addr(bfp->bf_dest, ETHERADDRL, macaddr, sizeof (macaddr)); 1386 1387 mdb_printf("%-?p %-17s ", addr, macaddr); 1388 if (bfp->bf_flags & BFF_LOCALADDR) 1389 mdb_printf("%-7s", "[self]"); 1390 else 1391 mdb_printf("t-%-5d", args->lbolt - bfp->bf_lastheard); 1392 mdb_printf(" %-7u ", bfp->bf_refs); 1393 1394 if (bfp->bf_trill_nick != 0) { 1395 mdb_printf("%d\n", bfp->bf_trill_nick); 1396 } else { 1397 for (i = 0; i < bfp->bf_nlinks; i++) { 1398 print_link_name(args, (uintptr_t)links[i], 1399 i == bfp->bf_nlinks - 1 ? '\n' : ' '); 1400 } 1401 } 1402 1403 return (WALK_NEXT); 1404 } 1405 1406 static int 1407 do_show_bridge(uintptr_t addr, const void *data, void *ptr) 1408 { 1409 show_bridge_args_t *args = ptr; 1410 bridge_inst_t bi; 1411 const bridge_inst_t *bip; 1412 trill_node_t tn; 1413 trill_sock_t tsp; 1414 trill_nickinfo_t tni; 1415 char bname[MAXLINKNAMELEN]; 1416 char macaddr[ETHERADDRL * 3]; 1417 uint_t nnicks; 1418 int i; 1419 1420 if (data != NULL) { 1421 bip = data; 1422 } else { 1423 if (mdb_vread(&bi, sizeof (bi), addr) == -1) { 1424 mdb_warn("cannot read bridge instance at %p", addr); 1425 return (WALK_ERR); 1426 } 1427 bip = &bi; 1428 } 1429 1430 (void) strncpy(bname, bip->bi_name, sizeof (bname) - 1); 1431 bname[MAXLINKNAMELEN - 1] = '\0'; 1432 i = strlen(bname); 1433 if (i > 1 && bname[i - 1] == '0') 1434 bname[i - 1] = '\0'; 1435 1436 if (args->name != NULL && strcmp(args->name, bname) != 0) 1437 return (WALK_NEXT); 1438 1439 args->found = B_TRUE; 1440 args->nlinks = args->nfwd = 0; 1441 1442 if (args->opt_l) { 1443 mdb_printf("%-?s %-16s %-17s %3s %-4s ", "ADDR", "LINK", 1444 "MAC-ADDR", "FLG", "PVID"); 1445 if (bip->bi_trilldata == NULL) 1446 mdb_printf("%-5s %s\n", "STATE", "VLANS"); 1447 else 1448 mdb_printf("%s\n", "FWD-VLANS"); 1449 } 1450 1451 if (!args->opt_f && !args->opt_t && 1452 mdb_pwalk("list", do_bridge_links, args, 1453 addr + offsetof(bridge_inst_t, bi_links)) != DCMD_OK) 1454 return (WALK_ERR); 1455 1456 if (args->opt_f) 1457 mdb_printf("%-?s %-17s %-7s %-7s %s\n", "ADDR", "DEST", "TIME", 1458 "REFS", "OUTPUT"); 1459 1460 if (!args->opt_l && !args->opt_t && 1461 mdb_pwalk("avl", do_bridge_fwd, args, 1462 addr + offsetof(bridge_inst_t, bi_fwd)) != DCMD_OK) 1463 return (WALK_ERR); 1464 1465 nnicks = 0; 1466 if (bip->bi_trilldata != NULL && !args->opt_l && !args->opt_f) { 1467 if (mdb_vread(&args->ti, sizeof (args->ti), 1468 (uintptr_t)bip->bi_trilldata) == -1) { 1469 mdb_warn("cannot read trill instance at %p", 1470 bip->bi_trilldata); 1471 return (WALK_ERR); 1472 } 1473 if (args->opt_t) 1474 mdb_printf("%-?s %-5s %-17s %s\n", "ADDR", 1475 "NICK", "NEXT-HOP", "LINK"); 1476 for (i = 0; i < RBRIDGE_NICKNAME_MAX; i++) { 1477 if (args->ti.ti_nodes[i] == NULL) 1478 continue; 1479 if (args->opt_t) { 1480 if (mdb_vread(&tn, sizeof (tn), 1481 (uintptr_t)args->ti.ti_nodes[i]) == -1) { 1482 mdb_warn("cannot read trill node %d at " 1483 "%p", i, args->ti.ti_nodes[i]); 1484 return (WALK_ERR); 1485 } 1486 if (mdb_vread(&tni, sizeof (tni), 1487 (uintptr_t)tn.tn_ni) == -1) { 1488 mdb_warn("cannot read trill node info " 1489 "%d at %p", i, tn.tn_ni); 1490 return (WALK_ERR); 1491 } 1492 mdb_mac_addr(tni.tni_adjsnpa, ETHERADDRL, 1493 macaddr, sizeof (macaddr)); 1494 if (tni.tni_nick == args->ti.ti_nick) { 1495 (void) strcpy(macaddr, "[self]"); 1496 } 1497 mdb_printf("%-?p %-5u %-17s ", 1498 args->ti.ti_nodes[i], tni.tni_nick, 1499 macaddr); 1500 if (tn.tn_tsp != NULL) { 1501 if (mdb_vread(&tsp, sizeof (tsp), 1502 (uintptr_t)tn.tn_tsp) == -1) { 1503 mdb_warn("cannot read trill " 1504 "socket info at %p", 1505 tn.tn_tsp); 1506 return (WALK_ERR); 1507 } 1508 if (tsp.ts_link != NULL) { 1509 print_link_name(args, 1510 (uintptr_t)tsp.ts_link, 1511 '\n'); 1512 continue; 1513 } 1514 } 1515 mdb_printf("--\n"); 1516 } else { 1517 nnicks++; 1518 } 1519 } 1520 } else { 1521 if (args->opt_t) 1522 mdb_printf("bridge is not running TRILL\n"); 1523 } 1524 1525 if (!args->opt_l && !args->opt_f && !args->opt_t) { 1526 mdb_printf("%-?p %-7s %-16s %-7u %-7u", addr, 1527 bip->bi_trilldata == NULL ? "stp" : "trill", bname, 1528 args->nlinks, args->nfwd); 1529 if (bip->bi_trilldata != NULL) 1530 mdb_printf(" %-7u %u\n", nnicks, args->ti.ti_nick); 1531 else 1532 mdb_printf(" %-7s %s\n", "--", "--"); 1533 } 1534 return (WALK_NEXT); 1535 } 1536 1537 static int 1538 dladm_show_bridge(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1539 { 1540 show_bridge_args_t *args; 1541 GElf_Sym sym; 1542 int i; 1543 1544 args = mdb_zalloc(sizeof (*args), UM_SLEEP); 1545 1546 i = mdb_getopts(argc, argv, 1547 'l', MDB_OPT_SETBITS, 1, &args->opt_l, 1548 'f', MDB_OPT_SETBITS, 1, &args->opt_f, 1549 't', MDB_OPT_SETBITS, 1, &args->opt_t, 1550 NULL); 1551 1552 argc -= i; 1553 argv += i; 1554 1555 if (argc > 1 || (argc == 1 && argv[0].a_type != MDB_TYPE_STRING)) { 1556 mdb_free(args, sizeof (*args)); 1557 return (DCMD_USAGE); 1558 } 1559 if (argc == 1) 1560 args->name = argv[0].a_un.a_str; 1561 1562 if ((args->lbolt = mdb_get_lbolt()) == -1) { 1563 mdb_warn("failed to read lbolt"); 1564 goto err; 1565 } 1566 1567 if (flags & DCMD_ADDRSPEC) { 1568 if (args->name != NULL) { 1569 mdb_printf("bridge name and address are mutually " 1570 "exclusive\n"); 1571 goto err; 1572 } 1573 if (!args->opt_l && !args->opt_f && !args->opt_t) 1574 mdb_printf("%-?s %-7s %-16s %-7s %-7s\n", "ADDR", 1575 "PROTECT", "NAME", "NLINKS", "NFWD"); 1576 if (do_show_bridge(addr, NULL, args) != WALK_NEXT) 1577 goto err; 1578 mdb_free(args, sizeof (*args)); 1579 return (DCMD_OK); 1580 } else { 1581 if ((args->opt_l || args->opt_f || args->opt_t) && 1582 args->name == NULL) { 1583 mdb_printf("need bridge name or address with -[lft]\n"); 1584 goto err; 1585 } 1586 if (mdb_lookup_by_obj("bridge", "inst_list", &sym) == -1) { 1587 mdb_warn("failed to find 'bridge`inst_list'"); 1588 goto err; 1589 } 1590 if (!args->opt_l && !args->opt_f && !args->opt_t) 1591 mdb_printf("%-?s %-7s %-16s %-7s %-7s %-7s %s\n", 1592 "ADDR", "PROTECT", "NAME", "NLINKS", "NFWD", 1593 "NNICKS", "NICK"); 1594 if (mdb_pwalk("list", do_show_bridge, args, 1595 (uintptr_t)sym.st_value) != DCMD_OK) 1596 goto err; 1597 if (!args->found && args->name != NULL) { 1598 mdb_printf("bridge instance %s not found\n", 1599 args->name); 1600 goto err; 1601 } 1602 mdb_free(args, sizeof (*args)); 1603 return (DCMD_OK); 1604 } 1605 1606 err: 1607 mdb_free(args, sizeof (*args)); 1608 return (DCMD_ERR); 1609 } 1610 1611 /* 1612 * Support for the "::dladm" dcmd 1613 */ 1614 int 1615 dladm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1616 { 1617 if (argc < 1 || argv[0].a_type != MDB_TYPE_STRING) 1618 return (DCMD_USAGE); 1619 1620 /* 1621 * This could be a bit more elaborate, once we support more of the 1622 * dladm show-* subcommands. 1623 */ 1624 argc--; 1625 argv++; 1626 if (strcmp(argv[-1].a_un.a_str, "show-bridge") == 0) 1627 return (dladm_show_bridge(addr, flags, argc, argv)); 1628 1629 return (DCMD_USAGE); 1630 } 1631 1632 void 1633 dladm_help(void) 1634 { 1635 mdb_printf("Subcommands:\n" 1636 " show-bridge [-flt] [<name>]\n" 1637 "\t Show bridge information; -l for links and -f for " 1638 "forwarding\n" 1639 "\t entries, and -t for TRILL nicknames. Address is required " 1640 "if name\n" 1641 "\t is not specified.\n"); 1642 } 1643