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