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