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 53 #define ADDR_V6_WIDTH 23 54 #define ADDR_V4_WIDTH 15 55 56 #define NETSTAT_ALL 0x01 57 #define NETSTAT_VERBOSE 0x02 58 #define NETSTAT_ROUTE 0x04 59 #define NETSTAT_V4 0x08 60 #define NETSTAT_V6 0x10 61 #define NETSTAT_UNIX 0x20 62 63 #define NETSTAT_FIRST 0x80000000u 64 65 typedef struct netstat_cb_data_s { 66 uint_t opts; 67 conn_t conn; 68 int af; 69 } netstat_cb_data_t; 70 71 /* Walkers for various *_stack_t */ 72 int 73 ar_stacks_walk_init(mdb_walk_state_t *wsp) 74 { 75 if (mdb_layered_walk("netstack", wsp) == -1) { 76 mdb_warn("can't walk 'netstack'"); 77 return (WALK_ERR); 78 } 79 return (WALK_NEXT); 80 } 81 82 int 83 ar_stacks_walk_step(mdb_walk_state_t *wsp) 84 { 85 uintptr_t kaddr; 86 netstack_t nss; 87 88 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 89 mdb_warn("can't read netstack at %p", wsp->walk_addr); 90 return (WALK_ERR); 91 } 92 kaddr = (uintptr_t)nss.netstack_modules[NS_ARP]; 93 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 94 } 95 96 int 97 icmp_stacks_walk_init(mdb_walk_state_t *wsp) 98 { 99 if (mdb_layered_walk("netstack", wsp) == -1) { 100 mdb_warn("can't walk 'netstack'"); 101 return (WALK_ERR); 102 } 103 return (WALK_NEXT); 104 } 105 106 int 107 icmp_stacks_walk_step(mdb_walk_state_t *wsp) 108 { 109 uintptr_t kaddr; 110 netstack_t nss; 111 112 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 113 mdb_warn("can't read netstack at %p", wsp->walk_addr); 114 return (WALK_ERR); 115 } 116 kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP]; 117 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 118 } 119 120 int 121 tcp_stacks_walk_init(mdb_walk_state_t *wsp) 122 { 123 if (mdb_layered_walk("netstack", wsp) == -1) { 124 mdb_warn("can't walk 'netstack'"); 125 return (WALK_ERR); 126 } 127 return (WALK_NEXT); 128 } 129 130 int 131 tcp_stacks_walk_step(mdb_walk_state_t *wsp) 132 { 133 uintptr_t kaddr; 134 netstack_t nss; 135 136 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 137 mdb_warn("can't read netstack at %p", wsp->walk_addr); 138 return (WALK_ERR); 139 } 140 kaddr = (uintptr_t)nss.netstack_modules[NS_TCP]; 141 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 142 } 143 144 int 145 udp_stacks_walk_init(mdb_walk_state_t *wsp) 146 { 147 if (mdb_layered_walk("netstack", wsp) == -1) { 148 mdb_warn("can't walk 'netstack'"); 149 return (WALK_ERR); 150 } 151 return (WALK_NEXT); 152 } 153 154 int 155 udp_stacks_walk_step(mdb_walk_state_t *wsp) 156 { 157 uintptr_t kaddr; 158 netstack_t nss; 159 160 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 161 mdb_warn("can't read netstack at %p", wsp->walk_addr); 162 return (WALK_ERR); 163 } 164 kaddr = (uintptr_t)nss.netstack_modules[NS_UDP]; 165 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 166 } 167 168 /* 169 * Print an IPv4 address and port number in a compact and easy to read format 170 * The arguments are in network byte order 171 */ 172 static void 173 net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport) 174 { 175 uint32_t naddr = V4_PART_OF_V6((*nipv6addr)); 176 177 mdb_nhconvert(&nport, &nport, sizeof (nport)); 178 mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport); 179 } 180 181 /* 182 * Print an IPv6 address and port number in a compact and easy to read format 183 * The arguments are in network byte order 184 */ 185 static void 186 net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport) 187 { 188 mdb_nhconvert(&nport, &nport, sizeof (nport)); 189 mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport); 190 } 191 192 static int 193 net_tcp_active(const tcp_t *tcp) 194 { 195 return (tcp->tcp_state >= TCPS_ESTABLISHED); 196 } 197 198 static int 199 net_tcp_ipv4(const tcp_t *tcp) 200 { 201 return ((tcp->tcp_ipversion == IPV4_VERSION) || 202 (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_ip_src_v6) && 203 (tcp->tcp_state <= TCPS_LISTEN))); 204 } 205 206 static int 207 net_tcp_ipv6(const tcp_t *tcp) 208 { 209 return (tcp->tcp_ipversion == IPV6_VERSION); 210 } 211 212 static int 213 net_udp_active(const udp_t *udp) 214 { 215 return ((udp->udp_state == TS_IDLE) || 216 (udp->udp_state == TS_DATA_XFER)); 217 } 218 219 static int 220 net_udp_ipv4(const udp_t *udp) 221 { 222 return ((udp->udp_ipversion == IPV4_VERSION) || 223 (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src) && 224 (udp->udp_state <= TS_IDLE))); 225 } 226 227 static int 228 net_udp_ipv6(const udp_t *udp) 229 { 230 return (udp->udp_ipversion == IPV6_VERSION); 231 } 232 233 int 234 sonode_walk_init(mdb_walk_state_t *wsp) 235 { 236 if (wsp->walk_addr == NULL) { 237 GElf_Sym sym; 238 struct socklist *slp; 239 240 if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) { 241 mdb_warn("failed to lookup sockfs`socklist"); 242 return (WALK_ERR); 243 } 244 245 slp = (struct socklist *)(uintptr_t)sym.st_value; 246 247 if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr), 248 (uintptr_t)&slp->sl_list) == -1) { 249 mdb_warn("failed to read address of initial sonode " 250 "at %p", &slp->sl_list); 251 return (WALK_ERR); 252 } 253 } 254 255 wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP); 256 return (WALK_NEXT); 257 } 258 259 int 260 sonode_walk_step(mdb_walk_state_t *wsp) 261 { 262 int status; 263 struct sotpi_sonode *stp; 264 265 if (wsp->walk_addr == NULL) 266 return (WALK_DONE); 267 268 if (mdb_vread(wsp->walk_data, sizeof (struct sotpi_sonode), 269 wsp->walk_addr) == -1) { 270 mdb_warn("failed to read sonode at %p", wsp->walk_addr); 271 return (WALK_ERR); 272 } 273 274 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 275 wsp->walk_cbdata); 276 277 stp = wsp->walk_data; 278 279 wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so; 280 return (status); 281 } 282 283 void 284 sonode_walk_fini(mdb_walk_state_t *wsp) 285 { 286 mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode)); 287 } 288 289 struct mi_walk_data { 290 uintptr_t mi_wd_miofirst; 291 MI_O mi_wd_miodata; 292 }; 293 294 int 295 mi_walk_init(mdb_walk_state_t *wsp) 296 { 297 struct mi_walk_data *wdp; 298 299 if (wsp->walk_addr == NULL) { 300 mdb_warn("mi doesn't support global walks\n"); 301 return (WALK_ERR); 302 } 303 304 wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP); 305 306 /* So that we do not immediately return WALK_DONE below */ 307 wdp->mi_wd_miofirst = NULL; 308 309 wsp->walk_data = wdp; 310 return (WALK_NEXT); 311 } 312 313 int 314 mi_walk_step(mdb_walk_state_t *wsp) 315 { 316 struct mi_walk_data *wdp = wsp->walk_data; 317 MI_OP miop = &wdp->mi_wd_miodata; 318 int status; 319 320 /* Always false in the first iteration */ 321 if ((wsp->walk_addr == (uintptr_t)NULL) || 322 (wsp->walk_addr == wdp->mi_wd_miofirst)) { 323 return (WALK_DONE); 324 } 325 326 if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) { 327 mdb_warn("failed to read MI object at %p", wsp->walk_addr); 328 return (WALK_ERR); 329 } 330 331 /* Only true in the first iteration */ 332 if (wdp->mi_wd_miofirst == NULL) { 333 wdp->mi_wd_miofirst = wsp->walk_addr; 334 status = WALK_NEXT; 335 } else { 336 status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O), 337 &miop[1], wsp->walk_cbdata); 338 } 339 340 wsp->walk_addr = (uintptr_t)miop->mi_o_next; 341 return (status); 342 } 343 344 void 345 mi_walk_fini(mdb_walk_state_t *wsp) 346 { 347 mdb_free(wsp->walk_data, sizeof (struct mi_walk_data)); 348 } 349 350 typedef struct mi_payload_walk_arg_s { 351 const char *mi_pwa_walker; /* Underlying walker */ 352 const off_t mi_pwa_head_off; /* Offset for mi_o_head_t * in stack */ 353 const size_t mi_pwa_size; /* size of mi payload */ 354 const uint_t mi_pwa_flags; /* device and/or module */ 355 } mi_payload_walk_arg_t; 356 357 #define MI_PAYLOAD_DEVICE 0x1 358 #define MI_PAYLOAD_MODULE 0x2 359 360 int 361 mi_payload_walk_init(mdb_walk_state_t *wsp) 362 { 363 const mi_payload_walk_arg_t *arg = wsp->walk_arg; 364 365 if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) { 366 mdb_warn("can't walk '%s'", arg->mi_pwa_walker); 367 return (WALK_ERR); 368 } 369 return (WALK_NEXT); 370 } 371 372 int 373 mi_payload_walk_step(mdb_walk_state_t *wsp) 374 { 375 const mi_payload_walk_arg_t *arg = wsp->walk_arg; 376 uintptr_t kaddr; 377 378 kaddr = wsp->walk_addr + arg->mi_pwa_head_off; 379 380 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 381 mdb_warn("can't read address of mi head at %p for %s", 382 kaddr, arg->mi_pwa_walker); 383 return (WALK_ERR); 384 } 385 386 if (kaddr == 0) { 387 /* Empty list */ 388 return (WALK_DONE); 389 } 390 391 if (mdb_pwalk("genunix`mi", wsp->walk_callback, 392 wsp->walk_cbdata, kaddr) == -1) { 393 mdb_warn("failed to walk genunix`mi"); 394 return (WALK_ERR); 395 } 396 return (WALK_NEXT); 397 } 398 399 const mi_payload_walk_arg_t mi_ar_arg = { 400 "ar_stacks", OFFSETOF(arp_stack_t, as_head), sizeof (ar_t), 401 MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE 402 }; 403 404 const mi_payload_walk_arg_t mi_icmp_arg = { 405 "icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t), 406 MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE 407 }; 408 409 int 410 sonode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 411 { 412 const char *optf = NULL; 413 const char *optt = NULL; 414 const char *optp = NULL; 415 int family, type, proto; 416 int filter = 0; 417 struct sonode so; 418 419 if (!(flags & DCMD_ADDRSPEC)) { 420 if (mdb_walk_dcmd("genunix`sonode", "genunix`sonode", argc, 421 argv) == -1) { 422 mdb_warn("failed to walk sonode"); 423 return (DCMD_ERR); 424 } 425 426 return (DCMD_OK); 427 } 428 429 if (mdb_getopts(argc, argv, 430 'f', MDB_OPT_STR, &optf, 431 't', MDB_OPT_STR, &optt, 432 'p', MDB_OPT_STR, &optp, 433 NULL) != argc) 434 return (DCMD_USAGE); 435 436 if (optf != NULL) { 437 if (strcmp("inet", optf) == 0) 438 family = AF_INET; 439 else if (strcmp("inet6", optf) == 0) 440 family = AF_INET6; 441 else if (strcmp("unix", optf) == 0) 442 family = AF_UNIX; 443 else 444 family = mdb_strtoull(optf); 445 filter = 1; 446 } 447 448 if (optt != NULL) { 449 if (strcmp("stream", optt) == 0) 450 type = SOCK_STREAM; 451 else if (strcmp("dgram", optt) == 0) 452 type = SOCK_DGRAM; 453 else if (strcmp("raw", optt) == 0) 454 type = SOCK_RAW; 455 else 456 type = mdb_strtoull(optt); 457 filter = 1; 458 } 459 460 if (optp != NULL) { 461 proto = mdb_strtoull(optp); 462 filter = 1; 463 } 464 465 if (DCMD_HDRSPEC(flags) && !filter) { 466 mdb_printf("%<u>%-?s Family Type Proto State Mode Flag " 467 "AccessVP%</u>\n", "Sonode:"); 468 } 469 470 if (mdb_vread(&so, sizeof (so), addr) == -1) { 471 mdb_warn("failed to read sonode at %p", addr); 472 return (DCMD_ERR); 473 } 474 475 if ((optf != NULL) && (so.so_family != family)) 476 return (DCMD_OK); 477 478 if ((optt != NULL) && (so.so_type != type)) 479 return (DCMD_OK); 480 481 if ((optp != NULL) && (so.so_protocol != proto)) 482 return (DCMD_OK); 483 484 if (filter) { 485 mdb_printf("%0?p\n", addr); 486 return (DCMD_OK); 487 } 488 489 mdb_printf("%0?p ", addr); 490 491 switch (so.so_family) { 492 case AF_UNIX: 493 mdb_printf("unix "); 494 break; 495 case AF_INET: 496 mdb_printf("inet "); 497 break; 498 case AF_INET6: 499 mdb_printf("inet6 "); 500 break; 501 default: 502 mdb_printf("%6hi", so.so_family); 503 } 504 505 switch (so.so_type) { 506 case SOCK_STREAM: 507 mdb_printf(" strm"); 508 break; 509 case SOCK_DGRAM: 510 mdb_printf(" dgrm"); 511 break; 512 case SOCK_RAW: 513 mdb_printf(" raw "); 514 break; 515 default: 516 mdb_printf(" %4hi", so.so_type); 517 } 518 519 mdb_printf(" %5hi %05x %04x %04hx\n", 520 so.so_protocol, so.so_state, so.so_mode, 521 so.so_flag); 522 523 return (DCMD_OK); 524 } 525 526 #define MI_PAYLOAD 0x1 527 #define MI_DEVICE 0x2 528 #define MI_MODULE 0x4 529 530 int 531 mi(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 532 { 533 uint_t opts = 0; 534 MI_O mio; 535 536 if (!(flags & DCMD_ADDRSPEC)) 537 return (DCMD_USAGE); 538 539 if (mdb_getopts(argc, argv, 540 'p', MDB_OPT_SETBITS, MI_PAYLOAD, &opts, 541 'd', MDB_OPT_SETBITS, MI_DEVICE, &opts, 542 'm', MDB_OPT_SETBITS, MI_MODULE, &opts, 543 NULL) != argc) 544 return (DCMD_USAGE); 545 546 if ((opts & (MI_DEVICE | MI_MODULE)) == (MI_DEVICE | MI_MODULE)) { 547 mdb_warn("at most one filter, d for devices or m " 548 "for modules, may be specified\n"); 549 return (DCMD_USAGE); 550 } 551 552 if ((opts == 0) && (DCMD_HDRSPEC(flags))) { 553 mdb_printf("%<u>%-?s %-?s %-?s IsDev Dev%</u>\n", 554 "MI_O", "Next", "Prev"); 555 } 556 557 if (mdb_vread(&mio, sizeof (mio), addr) == -1) { 558 mdb_warn("failed to read mi object MI_O at %p", addr); 559 return (DCMD_ERR); 560 } 561 562 if (opts != 0) { 563 if (mio.mi_o_isdev == B_FALSE) { 564 /* mio is a module */ 565 if (!(opts & MI_MODULE) && (opts & MI_DEVICE)) 566 return (DCMD_OK); 567 } else { 568 /* mio is a device */ 569 if (!(opts & MI_DEVICE) && (opts & MI_MODULE)) 570 return (DCMD_OK); 571 } 572 573 if (opts & MI_PAYLOAD) 574 mdb_printf("%p\n", addr + sizeof (MI_O)); 575 else 576 mdb_printf("%p\n", addr); 577 return (DCMD_OK); 578 } 579 580 mdb_printf("%0?p %0?p %0?p ", addr, mio.mi_o_next, mio.mi_o_prev); 581 582 if (mio.mi_o_isdev == B_FALSE) 583 mdb_printf("FALSE"); 584 else 585 mdb_printf("TRUE "); 586 587 mdb_printf(" %0?p\n", mio.mi_o_dev); 588 589 return (DCMD_OK); 590 } 591 592 static int 593 ns_to_stackid(uintptr_t kaddr) 594 { 595 netstack_t nss; 596 597 if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) { 598 mdb_warn("failed to read netstack_t %p", kaddr); 599 return (0); 600 } 601 return (nss.netstack_stackid); 602 } 603 604 605 606 static void 607 netstat_tcp_verbose_pr(const tcp_t *tcp) 608 { 609 mdb_printf(" %5i %08x %08x %5i %08x %08x %5li %5i\n", 610 tcp->tcp_swnd, tcp->tcp_snxt, tcp->tcp_suna, tcp->tcp_rwnd, 611 tcp->tcp_rack, tcp->tcp_rnxt, tcp->tcp_rto, tcp->tcp_mss); 612 } 613 614 /*ARGSUSED*/ 615 static int 616 netstat_tcp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 617 { 618 netstat_cb_data_t *ncb = cb_data; 619 uint_t opts = ncb->opts; 620 int af = ncb->af; 621 uintptr_t tcp_kaddr; 622 conn_t *connp = &ncb->conn; 623 tcp_t tcps, *tcp; 624 625 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) { 626 mdb_warn("failed to read conn_t at %p", kaddr); 627 return (WALK_ERR); 628 } 629 630 tcp_kaddr = (uintptr_t)connp->conn_tcp; 631 if (mdb_vread(&tcps, sizeof (tcp_t), tcp_kaddr) == -1) { 632 mdb_warn("failed to read tcp_t at %p", kaddr); 633 return (WALK_ERR); 634 } 635 636 tcp = &tcps; 637 connp->conn_tcp = tcp; 638 tcp->tcp_connp = connp; 639 640 if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) || 641 (af == AF_INET && !net_tcp_ipv4(tcp)) || 642 (af == AF_INET6 && !net_tcp_ipv6(tcp))) { 643 return (WALK_NEXT); 644 } 645 646 mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state); 647 if (af == AF_INET) { 648 net_ipv4addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport); 649 mdb_printf(" "); 650 net_ipv4addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport); 651 } else if (af == AF_INET6) { 652 net_ipv6addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport); 653 mdb_printf(" "); 654 net_ipv6addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport); 655 } 656 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack)); 657 mdb_printf(" %4i\n", connp->conn_zoneid); 658 if (opts & NETSTAT_VERBOSE) 659 netstat_tcp_verbose_pr(tcp); 660 661 return (WALK_NEXT); 662 } 663 664 /*ARGSUSED*/ 665 static int 666 netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 667 { 668 netstat_cb_data_t *ncb = cb_data; 669 uint_t opts = ncb->opts; 670 int af = ncb->af; 671 udp_t udp; 672 conn_t *connp = &ncb->conn; 673 char *state; 674 675 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) { 676 mdb_warn("failed to read conn_t at %p", kaddr); 677 return (WALK_ERR); 678 } 679 680 if (mdb_vread(&udp, sizeof (udp_t), 681 (uintptr_t)connp->conn_udp) == -1) { 682 mdb_warn("failed to read conn_udp at %p", 683 (uintptr_t)connp->conn_udp); 684 return (WALK_ERR); 685 } 686 687 if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) || 688 (af == AF_INET && !net_udp_ipv4(&udp)) || 689 (af == AF_INET6 && !net_udp_ipv6(&udp))) { 690 return (WALK_NEXT); 691 } 692 693 if (udp.udp_state == TS_UNBND) 694 state = "UNBOUND"; 695 else if (udp.udp_state == TS_IDLE) 696 state = "IDLE"; 697 else if (udp.udp_state == TS_DATA_XFER) 698 state = "CONNECTED"; 699 else 700 state = "UNKNOWN"; 701 702 mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_udp, state); 703 if (af == AF_INET) { 704 net_ipv4addrport_pr(&udp.udp_v6src, udp.udp_port); 705 mdb_printf(" "); 706 net_ipv4addrport_pr(&udp.udp_v6dst, udp.udp_dstport); 707 } else if (af == AF_INET6) { 708 net_ipv6addrport_pr(&udp.udp_v6src, udp.udp_port); 709 mdb_printf(" "); 710 net_ipv6addrport_pr(&udp.udp_v6dst, udp.udp_dstport); 711 } 712 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack)); 713 mdb_printf(" %4i\n", connp->conn_zoneid); 714 715 return (WALK_NEXT); 716 } 717 718 /*ARGSUSED*/ 719 static int 720 netstat_icmp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 721 { 722 netstat_cb_data_t *ncb = cb_data; 723 int af = ncb->af; 724 icmp_t icmp; 725 conn_t *connp = &ncb->conn; 726 char *state; 727 728 if (mdb_vread(connp, sizeof (conn_t), kaddr) == -1) { 729 mdb_warn("failed to read conn_t at %p", kaddr); 730 return (WALK_ERR); 731 } 732 733 if (mdb_vread(&icmp, sizeof (icmp_t), 734 (uintptr_t)connp->conn_icmp) == -1) { 735 mdb_warn("failed to read conn_icmp at %p", 736 (uintptr_t)connp->conn_icmp); 737 return (WALK_ERR); 738 } 739 740 if ((af == AF_INET && icmp.icmp_ipversion != IPV4_VERSION) || 741 (af == AF_INET6 && icmp.icmp_ipversion != IPV6_VERSION)) { 742 return (WALK_NEXT); 743 } 744 745 if (icmp.icmp_state == TS_UNBND) 746 state = "UNBOUND"; 747 else if (icmp.icmp_state == TS_IDLE) 748 state = "IDLE"; 749 else if (icmp.icmp_state == TS_DATA_XFER) 750 state = "CONNECTED"; 751 else 752 state = "UNKNOWN"; 753 754 mdb_printf("%0?p %10s ", (uintptr_t)connp->conn_icmp, state); 755 if (af == AF_INET) { 756 mdb_printf("%*I ", ADDR_V4_WIDTH, 757 V4_PART_OF_V6((icmp.icmp_v6src))); 758 mdb_printf("%*I ", ADDR_V4_WIDTH, 759 V4_PART_OF_V6((icmp.icmp_v6dst.sin6_addr))); 760 } else if (af == AF_INET6) { 761 mdb_printf("%*N ", ADDR_V6_WIDTH, &icmp.icmp_v6src); 762 mdb_printf("%*N ", ADDR_V6_WIDTH, &icmp.icmp_v6dst); 763 } 764 mdb_printf(" %5i", ns_to_stackid((uintptr_t)connp->conn_netstack)); 765 mdb_printf(" %4i\n", icmp.icmp_zoneid); 766 767 return (WALK_NEXT); 768 } 769 770 /* 771 * print the address of a unix domain socket 772 * 773 * so is the address of a AF_UNIX struct sonode in mdb's address space 774 * soa is the address of the struct soaddr to print 775 * 776 * returns 0 on success, -1 otherwise 777 */ 778 static int 779 netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa) 780 { 781 const struct sonode *so = &st->st_sonode; 782 const char none[] = " (none)"; 783 784 if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) { 785 if (st->st_info.sti_faddr_noxlate) { 786 mdb_printf("%-14s ", " (socketpair)"); 787 } else { 788 if (soa->soa_len > sizeof (sa_family_t)) { 789 char addr[MAXPATHLEN + 1]; 790 791 if (mdb_readstr(addr, sizeof (addr), 792 (uintptr_t)&soa->soa_sa->sa_data) == -1) { 793 mdb_warn("failed to read unix address " 794 "at %p", &soa->soa_sa->sa_data); 795 return (-1); 796 } 797 798 mdb_printf("%-14s ", addr); 799 } else { 800 mdb_printf("%-14s ", none); 801 } 802 } 803 } else { 804 mdb_printf("%-14s ", none); 805 } 806 807 return (0); 808 } 809 810 /* based on sockfs_snapshot */ 811 /*ARGSUSED*/ 812 static int 813 netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 814 { 815 const struct sotpi_sonode *st = walk_data; 816 const struct sonode *so = &st->st_sonode; 817 const struct sotpi_info *sti = &st->st_info; 818 819 if (so->so_count == 0) 820 return (WALK_NEXT); 821 822 if (so->so_family != AF_UNIX) { 823 mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr); 824 return (WALK_ERR); 825 } 826 827 mdb_printf("%-?p ", kaddr); 828 829 switch (sti->sti_serv_type) { 830 case T_CLTS: 831 mdb_printf("%-10s ", "dgram"); 832 break; 833 case T_COTS: 834 mdb_printf("%-10s ", "stream"); 835 break; 836 case T_COTS_ORD: 837 mdb_printf("%-10s ", "stream-ord"); 838 break; 839 default: 840 mdb_printf("%-10i ", sti->sti_serv_type); 841 } 842 843 if ((so->so_state & SS_ISBOUND) && 844 (sti->sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) { 845 mdb_printf("%0?p ", sti->sti_ux_laddr.soua_vp); 846 } else { 847 mdb_printf("%0?p ", NULL); 848 } 849 850 if ((so->so_state & SS_ISCONNECTED) && 851 (sti->sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) { 852 mdb_printf("%0?p ", sti->sti_ux_faddr.soua_vp); 853 } else { 854 mdb_printf("%0?p ", NULL); 855 } 856 857 if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1) 858 return (WALK_ERR); 859 860 if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1) 861 return (WALK_ERR); 862 863 mdb_printf("%4i\n", so->so_zoneid); 864 865 return (WALK_NEXT); 866 } 867 868 static void 869 netstat_tcp_verbose_header_pr(void) 870 { 871 mdb_printf(" %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n", 872 "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss"); 873 } 874 875 static void 876 get_ifname(const ire_t *ire, char *intf) 877 { 878 ill_t ill; 879 880 *intf = '\0'; 881 if (ire->ire_type == IRE_CACHE) { 882 queue_t stq; 883 884 if (mdb_vread(&stq, sizeof (stq), (uintptr_t)ire->ire_stq) == 885 -1) 886 return; 887 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)stq.q_ptr) == -1) 888 return; 889 (void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length), 890 (uintptr_t)ill.ill_name); 891 } else if (ire->ire_ipif != NULL) { 892 ipif_t ipif; 893 char *cp; 894 895 if (mdb_vread(&ipif, sizeof (ipif), 896 (uintptr_t)ire->ire_ipif) == -1) 897 return; 898 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ipif.ipif_ill) == 899 -1) 900 return; 901 (void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length), 902 (uintptr_t)ill.ill_name); 903 if (ipif.ipif_id != 0) { 904 cp = intf + strlen(intf); 905 (void) mdb_snprintf(cp, LIFNAMSIZ + 1 - (cp - intf), 906 ":%u", ipif.ipif_id); 907 } 908 } 909 } 910 911 static void 912 get_v4flags(const ire_t *ire, char *flags) 913 { 914 (void) strcpy(flags, "U"); 915 if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX || 916 ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT) 917 (void) strcat(flags, "G"); 918 if (ire->ire_mask == IP_HOST_MASK) 919 (void) strcat(flags, "H"); 920 if (ire->ire_type == IRE_HOST_REDIRECT) 921 (void) strcat(flags, "D"); 922 if (ire->ire_type == IRE_CACHE) 923 (void) strcat(flags, "A"); 924 if (ire->ire_type == IRE_BROADCAST) 925 (void) strcat(flags, "B"); 926 if (ire->ire_type == IRE_LOCAL) 927 (void) strcat(flags, "L"); 928 if (ire->ire_flags & RTF_MULTIRT) 929 (void) strcat(flags, "M"); 930 if (ire->ire_flags & RTF_SETSRC) 931 (void) strcat(flags, "S"); 932 } 933 934 static int 935 netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 936 { 937 const ire_t *ire = walk_data; 938 uint_t *opts = cb_data; 939 ipaddr_t gate; 940 char flags[10], intf[LIFNAMSIZ + 1]; 941 942 if (ire->ire_ipversion != IPV4_VERSION) 943 return (WALK_NEXT); 944 945 if (!(*opts & NETSTAT_ALL) && (ire->ire_type == IRE_CACHE || 946 ire->ire_type == IRE_BROADCAST || ire->ire_type == IRE_LOCAL)) 947 return (WALK_NEXT); 948 949 if (*opts & NETSTAT_FIRST) { 950 *opts &= ~NETSTAT_FIRST; 951 mdb_printf("%<u>%s Table: IPv4%</u>\n", 952 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing"); 953 if (*opts & NETSTAT_VERBOSE) { 954 mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt " 955 " Ref Flg Out In/Fwd%</u>\n", 956 "Address", ADDR_V4_WIDTH, "Destination", 957 ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway"); 958 } else { 959 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use " 960 "Interface%</u>\n", 961 "Address", ADDR_V4_WIDTH, "Destination", 962 ADDR_V4_WIDTH, "Gateway"); 963 } 964 } 965 966 gate = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK|IRE_BROADCAST)) ? 967 ire->ire_src_addr : ire->ire_gateway_addr; 968 969 get_v4flags(ire, flags); 970 971 get_ifname(ire, intf); 972 973 if (*opts & NETSTAT_VERBOSE) { 974 mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u " 975 "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, 976 ire->ire_mask, ADDR_V4_WIDTH, gate, intf, 977 ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ', 978 ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, flags, 979 ire->ire_ob_pkt_count, ire->ire_ib_pkt_count); 980 } else { 981 mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr, 982 ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags, 983 ire->ire_refcnt, 984 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf); 985 } 986 987 return (WALK_NEXT); 988 } 989 990 int 991 ip_mask_to_plen_v6(const in6_addr_t *v6mask) 992 { 993 int plen; 994 int i; 995 uint32_t val; 996 997 for (i = 3; i >= 0; i--) 998 if (v6mask->s6_addr32[i] != 0) 999 break; 1000 if (i < 0) 1001 return (0); 1002 plen = 32 + 32 * i; 1003 val = v6mask->s6_addr32[i]; 1004 while (!(val & 1)) { 1005 val >>= 1; 1006 plen--; 1007 } 1008 1009 return (plen); 1010 } 1011 1012 static int 1013 netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 1014 { 1015 const ire_t *ire = walk_data; 1016 uint_t *opts = cb_data; 1017 const in6_addr_t *gatep; 1018 char deststr[ADDR_V6_WIDTH + 5]; 1019 char flags[10], intf[LIFNAMSIZ + 1]; 1020 int masklen; 1021 1022 if (ire->ire_ipversion != IPV6_VERSION) 1023 return (WALK_NEXT); 1024 1025 if (!(*opts & NETSTAT_ALL) && ire->ire_type == IRE_CACHE) 1026 return (WALK_NEXT); 1027 1028 if (*opts & NETSTAT_FIRST) { 1029 *opts &= ~NETSTAT_FIRST; 1030 mdb_printf("\n%<u>%s Table: IPv6%</u>\n", 1031 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing"); 1032 if (*opts & NETSTAT_VERBOSE) { 1033 mdb_printf("%<u>%-?s %-*s %-*s If PMTU Rtt Ref " 1034 "Flags Out In/Fwd%</u>\n", 1035 "Address", ADDR_V6_WIDTH+4, "Destination/Mask", 1036 ADDR_V6_WIDTH, "Gateway"); 1037 } else { 1038 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use If" 1039 "%</u>\n", 1040 "Address", ADDR_V6_WIDTH+4, "Destination/Mask", 1041 ADDR_V6_WIDTH, "Gateway"); 1042 } 1043 } 1044 1045 gatep = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK)) ? 1046 &ire->ire_src_addr_v6 : &ire->ire_gateway_addr_v6; 1047 1048 masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6); 1049 (void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d", 1050 &ire->ire_addr_v6, masklen); 1051 1052 (void) strcpy(flags, "U"); 1053 if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX || 1054 ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT) 1055 (void) strcat(flags, "G"); 1056 if (masklen == IPV6_ABITS) 1057 (void) strcat(flags, "H"); 1058 if (ire->ire_type == IRE_HOST_REDIRECT) 1059 (void) strcat(flags, "D"); 1060 if (ire->ire_type == IRE_CACHE) 1061 (void) strcat(flags, "A"); 1062 if (ire->ire_type == IRE_LOCAL) 1063 (void) strcat(flags, "L"); 1064 if (ire->ire_flags & RTF_MULTIRT) 1065 (void) strcat(flags, "M"); 1066 if (ire->ire_flags & RTF_SETSRC) 1067 (void) strcat(flags, "S"); 1068 1069 get_ifname(ire, intf); 1070 1071 if (*opts & NETSTAT_VERBOSE) { 1072 mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n", 1073 kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, 1074 intf, ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ', 1075 ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, 1076 flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count); 1077 } else { 1078 mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr, 1079 ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags, 1080 ire->ire_refcnt, 1081 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf); 1082 } 1083 1084 return (WALK_NEXT); 1085 } 1086 1087 static void 1088 netstat_header_v4(int proto) 1089 { 1090 if (proto == IPPROTO_TCP) 1091 mdb_printf("%<u>%-?s ", "TCPv4"); 1092 else if (proto == IPPROTO_UDP) 1093 mdb_printf("%<u>%-?s ", "UDPv4"); 1094 else if (proto == IPPROTO_ICMP) 1095 mdb_printf("%<u>%-?s ", "ICMPv4"); 1096 mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n", 1097 "", ADDR_V4_WIDTH, "Local Address", 1098 "", ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone"); 1099 } 1100 1101 static void 1102 netstat_header_v6(int proto) 1103 { 1104 if (proto == IPPROTO_TCP) 1105 mdb_printf("%<u>%-?s ", "TCPv6"); 1106 else if (proto == IPPROTO_UDP) 1107 mdb_printf("%<u>%-?s ", "UDPv6"); 1108 else if (proto == IPPROTO_ICMP) 1109 mdb_printf("%<u>%-?s ", "ICMPv6"); 1110 mdb_printf("State %6s%*s %6s%*s %-5s %-4s%</u>\n", 1111 "", ADDR_V6_WIDTH, "Local Address", 1112 "", ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone"); 1113 } 1114 1115 static int 1116 netstat_print_conn(const char *cache, int proto, mdb_walk_cb_t cbfunc, 1117 void *cbdata) 1118 { 1119 netstat_cb_data_t *ncb = cbdata; 1120 1121 if ((ncb->opts & NETSTAT_VERBOSE) && proto == IPPROTO_TCP) 1122 netstat_tcp_verbose_header_pr(); 1123 if (mdb_walk(cache, cbfunc, cbdata) == -1) { 1124 mdb_warn("failed to walk %s", cache); 1125 return (DCMD_ERR); 1126 } 1127 return (DCMD_OK); 1128 } 1129 1130 static int 1131 netstat_print_common(const char *cache, int proto, mdb_walk_cb_t cbfunc, 1132 void *cbdata) 1133 { 1134 netstat_cb_data_t *ncb = cbdata; 1135 int af = ncb->af; 1136 int status = DCMD_OK; 1137 1138 if (af != AF_INET6) { 1139 ncb->af = AF_INET; 1140 netstat_header_v4(proto); 1141 status = netstat_print_conn(cache, proto, cbfunc, cbdata); 1142 } 1143 if (status == DCMD_OK && af != AF_INET) { 1144 ncb->af = AF_INET6; 1145 netstat_header_v6(proto); 1146 status = netstat_print_conn(cache, proto, cbfunc, cbdata); 1147 } 1148 ncb->af = af; 1149 return (status); 1150 } 1151 1152 /*ARGSUSED*/ 1153 int 1154 netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1155 { 1156 uint_t opts = 0; 1157 const char *optf = NULL; 1158 const char *optP = NULL; 1159 netstat_cb_data_t *cbdata; 1160 int status; 1161 int af = 0; 1162 1163 if (mdb_getopts(argc, argv, 1164 'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts, 1165 'f', MDB_OPT_STR, &optf, 1166 'P', MDB_OPT_STR, &optP, 1167 'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts, 1168 'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts, 1169 NULL) != argc) 1170 return (DCMD_USAGE); 1171 1172 if (optP != NULL) { 1173 if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0) && 1174 (strcmp("icmp", optP) != 0)) 1175 return (DCMD_USAGE); 1176 if (opts & NETSTAT_ROUTE) 1177 return (DCMD_USAGE); 1178 } 1179 1180 if (optf == NULL) 1181 opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX; 1182 else if (strcmp("inet", optf) == 0) 1183 opts |= NETSTAT_V4; 1184 else if (strcmp("inet6", optf) == 0) 1185 opts |= NETSTAT_V6; 1186 else if (strcmp("unix", optf) == 0) 1187 opts |= NETSTAT_UNIX; 1188 else 1189 return (DCMD_USAGE); 1190 1191 if (opts & NETSTAT_ROUTE) { 1192 if (!(opts & (NETSTAT_V4|NETSTAT_V6))) 1193 return (DCMD_USAGE); 1194 if (opts & NETSTAT_V4) { 1195 opts |= NETSTAT_FIRST; 1196 if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) { 1197 mdb_warn("failed to walk ip`ire"); 1198 return (DCMD_ERR); 1199 } 1200 } 1201 if (opts & NETSTAT_V6) { 1202 opts |= NETSTAT_FIRST; 1203 if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) { 1204 mdb_warn("failed to walk ip`ire"); 1205 return (DCMD_ERR); 1206 } 1207 } 1208 return (DCMD_OK); 1209 } 1210 1211 if ((opts & NETSTAT_UNIX) && (optP == NULL)) { 1212 /* Print Unix Domain Sockets */ 1213 mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n", 1214 "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr", 1215 "Remote Addr", "Zone"); 1216 1217 if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) { 1218 mdb_warn("failed to walk genunix`sonode"); 1219 return (DCMD_ERR); 1220 } 1221 if (!(opts & (NETSTAT_V4 | NETSTAT_V6))) 1222 return (DCMD_OK); 1223 } 1224 1225 cbdata = mdb_alloc(sizeof (netstat_cb_data_t), UM_SLEEP); 1226 cbdata->opts = opts; 1227 if ((optf != NULL) && (opts & NETSTAT_V4)) 1228 af = AF_INET; 1229 else if ((optf != NULL) && (opts & NETSTAT_V6)) 1230 af = AF_INET6; 1231 1232 cbdata->af = af; 1233 if ((optP == NULL) || (strcmp("tcp", optP) == 0)) { 1234 status = netstat_print_common("tcp_conn_cache", IPPROTO_TCP, 1235 netstat_tcp_cb, cbdata); 1236 if (status != DCMD_OK) 1237 goto out; 1238 } 1239 1240 if ((optP == NULL) || (strcmp("udp", optP) == 0)) { 1241 status = netstat_print_common("udp_conn_cache", IPPROTO_UDP, 1242 netstat_udp_cb, cbdata); 1243 if (status != DCMD_OK) 1244 goto out; 1245 } 1246 1247 if ((optP == NULL) || (strcmp("icmp", optP) == 0)) { 1248 status = netstat_print_common("rawip_conn_cache", IPPROTO_ICMP, 1249 netstat_icmp_cb, cbdata); 1250 if (status != DCMD_OK) 1251 goto out; 1252 } 1253 out: 1254 mdb_free(cbdata, sizeof (netstat_cb_data_t)); 1255 return (status); 1256 } 1257