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 2008 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 66 /* Walkers for various *_stack_t */ 67 int 68 ar_stacks_walk_init(mdb_walk_state_t *wsp) 69 { 70 if (mdb_layered_walk("netstack", wsp) == -1) { 71 mdb_warn("can't walk 'netstack'"); 72 return (WALK_ERR); 73 } 74 return (WALK_NEXT); 75 } 76 77 int 78 ar_stacks_walk_step(mdb_walk_state_t *wsp) 79 { 80 uintptr_t kaddr; 81 netstack_t nss; 82 83 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 84 mdb_warn("can't read netstack at %p", wsp->walk_addr); 85 return (WALK_ERR); 86 } 87 kaddr = (uintptr_t)nss.netstack_modules[NS_ARP]; 88 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 89 } 90 91 int 92 icmp_stacks_walk_init(mdb_walk_state_t *wsp) 93 { 94 if (mdb_layered_walk("netstack", wsp) == -1) { 95 mdb_warn("can't walk 'netstack'"); 96 return (WALK_ERR); 97 } 98 return (WALK_NEXT); 99 } 100 101 int 102 icmp_stacks_walk_step(mdb_walk_state_t *wsp) 103 { 104 uintptr_t kaddr; 105 netstack_t nss; 106 107 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 108 mdb_warn("can't read netstack at %p", wsp->walk_addr); 109 return (WALK_ERR); 110 } 111 kaddr = (uintptr_t)nss.netstack_modules[NS_ICMP]; 112 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 113 } 114 115 int 116 tcp_stacks_walk_init(mdb_walk_state_t *wsp) 117 { 118 if (mdb_layered_walk("netstack", wsp) == -1) { 119 mdb_warn("can't walk 'netstack'"); 120 return (WALK_ERR); 121 } 122 return (WALK_NEXT); 123 } 124 125 int 126 tcp_stacks_walk_step(mdb_walk_state_t *wsp) 127 { 128 uintptr_t kaddr; 129 netstack_t nss; 130 131 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 132 mdb_warn("can't read netstack at %p", wsp->walk_addr); 133 return (WALK_ERR); 134 } 135 kaddr = (uintptr_t)nss.netstack_modules[NS_TCP]; 136 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 137 } 138 139 int 140 udp_stacks_walk_init(mdb_walk_state_t *wsp) 141 { 142 if (mdb_layered_walk("netstack", wsp) == -1) { 143 mdb_warn("can't walk 'netstack'"); 144 return (WALK_ERR); 145 } 146 return (WALK_NEXT); 147 } 148 149 int 150 udp_stacks_walk_step(mdb_walk_state_t *wsp) 151 { 152 uintptr_t kaddr; 153 netstack_t nss; 154 155 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 156 mdb_warn("can't read netstack at %p", wsp->walk_addr); 157 return (WALK_ERR); 158 } 159 kaddr = (uintptr_t)nss.netstack_modules[NS_UDP]; 160 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 161 } 162 163 /* 164 * Print an IPv4 address and port number in a compact and easy to read format 165 * The arguments are in network byte order 166 */ 167 static void 168 net_ipv4addrport_pr(const in6_addr_t *nipv6addr, in_port_t nport) 169 { 170 uint32_t naddr = V4_PART_OF_V6((*nipv6addr)); 171 172 mdb_nhconvert(&nport, &nport, sizeof (nport)); 173 mdb_printf("%*I.%-5hu", ADDR_V4_WIDTH, naddr, nport); 174 } 175 176 /* 177 * Print an IPv6 address and port number in a compact and easy to read format 178 * The arguments are in network byte order 179 */ 180 static void 181 net_ipv6addrport_pr(const in6_addr_t *naddr, in_port_t nport) 182 { 183 mdb_nhconvert(&nport, &nport, sizeof (nport)); 184 mdb_printf("%*N.%-5hu", ADDR_V6_WIDTH, naddr, nport); 185 } 186 187 static int 188 net_tcp_active(const tcp_t *tcp) 189 { 190 return (tcp->tcp_state >= TCPS_ESTABLISHED); 191 } 192 193 static int 194 net_tcp_ipv4(const tcp_t *tcp) 195 { 196 return ((tcp->tcp_ipversion == IPV4_VERSION) || 197 (IN6_IS_ADDR_UNSPECIFIED(&tcp->tcp_ip_src_v6) && 198 (tcp->tcp_state <= TCPS_LISTEN))); 199 } 200 201 static int 202 net_tcp_ipv6(const tcp_t *tcp) 203 { 204 return (tcp->tcp_ipversion == IPV6_VERSION); 205 } 206 207 static int 208 net_udp_active(const udp_t *udp) 209 { 210 return ((udp->udp_state == TS_IDLE) || 211 (udp->udp_state == TS_DATA_XFER)); 212 } 213 214 static int 215 net_udp_ipv4(const udp_t *udp) 216 { 217 return ((udp->udp_ipversion == IPV4_VERSION) || 218 (IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src) && 219 (udp->udp_state <= TS_IDLE))); 220 } 221 222 static int 223 net_udp_ipv6(const udp_t *udp) 224 { 225 return (udp->udp_ipversion == IPV6_VERSION); 226 } 227 228 int 229 sonode_walk_init(mdb_walk_state_t *wsp) 230 { 231 if (wsp->walk_addr == NULL) { 232 GElf_Sym sym; 233 struct socklist *slp; 234 235 if (mdb_lookup_by_obj("sockfs", "socklist", &sym) == -1) { 236 mdb_warn("failed to lookup sockfs`socklist"); 237 return (WALK_ERR); 238 } 239 240 slp = (struct socklist *)(uintptr_t)sym.st_value; 241 242 if (mdb_vread(&wsp->walk_addr, sizeof (wsp->walk_addr), 243 (uintptr_t)&slp->sl_list) == -1) { 244 mdb_warn("failed to read address of initial sonode " 245 "at %p", &slp->sl_list); 246 return (WALK_ERR); 247 } 248 } 249 250 wsp->walk_data = mdb_alloc(sizeof (struct sotpi_sonode), UM_SLEEP); 251 return (WALK_NEXT); 252 } 253 254 int 255 sonode_walk_step(mdb_walk_state_t *wsp) 256 { 257 int status; 258 struct sotpi_sonode *stp; 259 260 if (wsp->walk_addr == NULL) 261 return (WALK_DONE); 262 263 if (mdb_vread(wsp->walk_data, sizeof (struct sotpi_sonode), 264 wsp->walk_addr) == -1) { 265 mdb_warn("failed to read sonode at %p", wsp->walk_addr); 266 return (WALK_ERR); 267 } 268 269 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 270 wsp->walk_cbdata); 271 272 stp = wsp->walk_data; 273 274 wsp->walk_addr = (uintptr_t)stp->st_info.sti_next_so; 275 return (status); 276 } 277 278 void 279 sonode_walk_fini(mdb_walk_state_t *wsp) 280 { 281 mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode)); 282 } 283 284 struct mi_walk_data { 285 uintptr_t mi_wd_miofirst; 286 MI_O mi_wd_miodata; 287 }; 288 289 int 290 mi_walk_init(mdb_walk_state_t *wsp) 291 { 292 struct mi_walk_data *wdp; 293 294 if (wsp->walk_addr == NULL) { 295 mdb_warn("mi doesn't support global walks\n"); 296 return (WALK_ERR); 297 } 298 299 wdp = mdb_alloc(sizeof (struct mi_walk_data), UM_SLEEP); 300 301 /* So that we do not immediately return WALK_DONE below */ 302 wdp->mi_wd_miofirst = NULL; 303 304 wsp->walk_data = wdp; 305 return (WALK_NEXT); 306 } 307 308 int 309 mi_walk_step(mdb_walk_state_t *wsp) 310 { 311 struct mi_walk_data *wdp = wsp->walk_data; 312 MI_OP miop = &wdp->mi_wd_miodata; 313 int status; 314 315 /* Always false in the first iteration */ 316 if ((wsp->walk_addr == (uintptr_t)NULL) || 317 (wsp->walk_addr == wdp->mi_wd_miofirst)) { 318 return (WALK_DONE); 319 } 320 321 if (mdb_vread(miop, sizeof (MI_O), wsp->walk_addr) == -1) { 322 mdb_warn("failed to read MI object at %p", wsp->walk_addr); 323 return (WALK_ERR); 324 } 325 326 /* Only true in the first iteration */ 327 if (wdp->mi_wd_miofirst == NULL) { 328 wdp->mi_wd_miofirst = wsp->walk_addr; 329 status = WALK_NEXT; 330 } else { 331 status = wsp->walk_callback(wsp->walk_addr + sizeof (MI_O), 332 &miop[1], wsp->walk_cbdata); 333 } 334 335 wsp->walk_addr = (uintptr_t)miop->mi_o_next; 336 return (status); 337 } 338 339 void 340 mi_walk_fini(mdb_walk_state_t *wsp) 341 { 342 mdb_free(wsp->walk_data, sizeof (struct mi_walk_data)); 343 } 344 345 typedef struct mi_payload_walk_arg_s { 346 const char *mi_pwa_walker; /* Underlying walker */ 347 const off_t mi_pwa_head_off; /* Offset for mi_o_head_t * in stack */ 348 const size_t mi_pwa_size; /* size of mi payload */ 349 const uint_t mi_pwa_flags; /* device and/or module */ 350 } mi_payload_walk_arg_t; 351 352 #define MI_PAYLOAD_DEVICE 0x1 353 #define MI_PAYLOAD_MODULE 0x2 354 355 int 356 mi_payload_walk_init(mdb_walk_state_t *wsp) 357 { 358 const mi_payload_walk_arg_t *arg = wsp->walk_arg; 359 360 if (mdb_layered_walk(arg->mi_pwa_walker, wsp) == -1) { 361 mdb_warn("can't walk '%s'", arg->mi_pwa_walker); 362 return (WALK_ERR); 363 } 364 return (WALK_NEXT); 365 } 366 367 int 368 mi_payload_walk_step(mdb_walk_state_t *wsp) 369 { 370 const mi_payload_walk_arg_t *arg = wsp->walk_arg; 371 uintptr_t kaddr; 372 373 kaddr = wsp->walk_addr + arg->mi_pwa_head_off; 374 375 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 376 mdb_warn("can't read address of mi head at %p for %s", 377 kaddr, arg->mi_pwa_walker); 378 return (WALK_ERR); 379 } 380 381 if (kaddr == 0) { 382 /* Empty list */ 383 return (WALK_DONE); 384 } 385 386 if (mdb_pwalk("genunix`mi", wsp->walk_callback, 387 wsp->walk_cbdata, kaddr) == -1) { 388 mdb_warn("failed to walk genunix`mi"); 389 return (WALK_ERR); 390 } 391 return (WALK_NEXT); 392 } 393 394 const mi_payload_walk_arg_t mi_ar_arg = { 395 "ar_stacks", OFFSETOF(arp_stack_t, as_head), sizeof (ar_t), 396 MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE 397 }; 398 399 const mi_payload_walk_arg_t mi_icmp_arg = { 400 "icmp_stacks", OFFSETOF(icmp_stack_t, is_head), sizeof (icmp_t), 401 MI_PAYLOAD_DEVICE | MI_PAYLOAD_MODULE 402 }; 403 404 const mi_payload_walk_arg_t mi_ill_arg = { 405 "ip_stacks", OFFSETOF(ip_stack_t, ips_ip_g_head), sizeof (ill_t), 406 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, int af) 617 { 618 const uintptr_t opts = (uintptr_t)cb_data; 619 uintptr_t tcp_kaddr; 620 conn_t conns, *connp; 621 tcp_t tcps, *tcp; 622 623 if (mdb_vread(&conns, sizeof (conn_t), kaddr) == -1) { 624 mdb_warn("failed to read conn_t at %p", kaddr); 625 return (WALK_ERR); 626 } 627 connp = &conns; 628 629 tcp_kaddr = (uintptr_t)connp->conn_tcp; 630 if (mdb_vread(&tcps, sizeof (tcp_t), tcp_kaddr) == -1) { 631 mdb_warn("failed to read tcp_t at %p", kaddr); 632 return (WALK_ERR); 633 } 634 635 tcp = &tcps; 636 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(" %4i", ns_to_stackid((uintptr_t)connp->conn_netstack)); 657 658 mdb_printf(" %4i\n", connp->conn_zoneid); 659 660 if (opts & NETSTAT_VERBOSE) 661 netstat_tcp_verbose_pr(tcp); 662 663 return (WALK_NEXT); 664 } 665 666 static int 667 netstat_tcpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 668 { 669 return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET)); 670 } 671 672 static int 673 netstat_tcpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 674 { 675 return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET6)); 676 } 677 678 /*ARGSUSED*/ 679 static int 680 netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data, int af) 681 { 682 const uintptr_t opts = (uintptr_t)cb_data; 683 udp_t udp; 684 conn_t conns; 685 686 if (mdb_vread(&conns, sizeof (conn_t), kaddr) == -1) { 687 mdb_warn("failed to read conn_t at %p", kaddr); 688 return (WALK_ERR); 689 } 690 691 if (mdb_vread(&udp, sizeof (udp_t), 692 (uintptr_t)conns.conn_udp) == -1) { 693 mdb_warn("failed to read conn_udp at %p", 694 (uintptr_t)conns.conn_udp); 695 return (WALK_ERR); 696 } 697 698 if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) || 699 (af == AF_INET && !net_udp_ipv4(&udp)) || 700 (af == AF_INET6 && !net_udp_ipv6(&udp))) { 701 return (WALK_NEXT); 702 } 703 704 mdb_printf("%0?p %2i ", kaddr, udp.udp_state); 705 if (af == AF_INET) { 706 net_ipv4addrport_pr(&udp.udp_v6src, udp.udp_port); 707 mdb_printf(" "); 708 net_ipv4addrport_pr(&udp.udp_v6dst, udp.udp_dstport); 709 } else if (af == AF_INET6) { 710 net_ipv6addrport_pr(&udp.udp_v6src, udp.udp_port); 711 mdb_printf(" "); 712 net_ipv6addrport_pr(&udp.udp_v6dst, udp.udp_dstport); 713 } 714 mdb_printf(" %4i", ns_to_stackid((uintptr_t)conns.conn_netstack)); 715 716 mdb_printf(" %4i\n", conns.conn_zoneid); 717 718 return (WALK_NEXT); 719 } 720 721 static int 722 netstat_udpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 723 { 724 return (netstat_udp_cb(kaddr, walk_data, cb_data, AF_INET)); 725 } 726 727 static int 728 netstat_udpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 729 { 730 return (netstat_udp_cb(kaddr, walk_data, cb_data, AF_INET6)); 731 } 732 733 /* 734 * print the address of a unix domain socket 735 * 736 * so is the address of a AF_UNIX struct sonode in mdb's address space 737 * soa is the address of the struct soaddr to print 738 * 739 * returns 0 on success, -1 otherwise 740 */ 741 static int 742 netstat_unix_name_pr(const struct sotpi_sonode *st, const struct soaddr *soa) 743 { 744 const struct sonode *so = &st->st_sonode; 745 const char none[] = " (none)"; 746 747 if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) { 748 if (st->st_info.sti_faddr_noxlate) { 749 mdb_printf("%-14s ", " (socketpair)"); 750 } else { 751 if (soa->soa_len > sizeof (sa_family_t)) { 752 char addr[MAXPATHLEN + 1]; 753 754 if (mdb_readstr(addr, sizeof (addr), 755 (uintptr_t)&soa->soa_sa->sa_data) == -1) { 756 mdb_warn("failed to read unix address " 757 "at %p", &soa->soa_sa->sa_data); 758 return (-1); 759 } 760 761 mdb_printf("%-14s ", addr); 762 } else { 763 mdb_printf("%-14s ", none); 764 } 765 } 766 } else { 767 mdb_printf("%-14s ", none); 768 } 769 770 return (0); 771 } 772 773 /* based on sockfs_snapshot */ 774 /*ARGSUSED*/ 775 static int 776 netstat_unix_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 777 { 778 const struct sotpi_sonode *st = walk_data; 779 const struct sonode *so = &st->st_sonode; 780 const struct sotpi_info *sti = &st->st_info; 781 782 if (so->so_count == 0) 783 return (WALK_NEXT); 784 785 if (so->so_family != AF_UNIX) { 786 mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr); 787 return (WALK_ERR); 788 } 789 790 mdb_printf("%-?p ", kaddr); 791 792 switch (sti->sti_serv_type) { 793 case T_CLTS: 794 mdb_printf("%-10s ", "dgram"); 795 break; 796 case T_COTS: 797 mdb_printf("%-10s ", "stream"); 798 break; 799 case T_COTS_ORD: 800 mdb_printf("%-10s ", "stream-ord"); 801 break; 802 default: 803 mdb_printf("%-10i ", sti->sti_serv_type); 804 } 805 806 if ((so->so_state & SS_ISBOUND) && 807 (sti->sti_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) { 808 mdb_printf("%0?p ", sti->sti_ux_laddr.soua_vp); 809 } else { 810 mdb_printf("%0?p ", NULL); 811 } 812 813 if ((so->so_state & SS_ISCONNECTED) && 814 (sti->sti_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) { 815 mdb_printf("%0?p ", sti->sti_ux_faddr.soua_vp); 816 } else { 817 mdb_printf("%0?p ", NULL); 818 } 819 820 if (netstat_unix_name_pr(st, &sti->sti_laddr) == -1) 821 return (WALK_ERR); 822 823 if (netstat_unix_name_pr(st, &sti->sti_faddr) == -1) 824 return (WALK_ERR); 825 826 mdb_printf("%4i\n", so->so_zoneid); 827 828 return (WALK_NEXT); 829 } 830 831 static void 832 netstat_tcp_verbose_header_pr(void) 833 { 834 mdb_printf(" %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n", 835 "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss"); 836 } 837 838 static void 839 get_ifname(const ire_t *ire, char *intf) 840 { 841 ill_t ill; 842 843 *intf = '\0'; 844 if (ire->ire_type == IRE_CACHE) { 845 queue_t stq; 846 847 if (mdb_vread(&stq, sizeof (stq), (uintptr_t)ire->ire_stq) == 848 -1) 849 return; 850 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)stq.q_ptr) == -1) 851 return; 852 (void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length), 853 (uintptr_t)ill.ill_name); 854 } else if (ire->ire_ipif != NULL) { 855 ipif_t ipif; 856 char *cp; 857 858 if (mdb_vread(&ipif, sizeof (ipif), 859 (uintptr_t)ire->ire_ipif) == -1) 860 return; 861 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ipif.ipif_ill) == 862 -1) 863 return; 864 (void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length), 865 (uintptr_t)ill.ill_name); 866 if (ipif.ipif_id != 0) { 867 cp = intf + strlen(intf); 868 (void) mdb_snprintf(cp, LIFNAMSIZ + 1 - (cp - intf), 869 ":%u", ipif.ipif_id); 870 } 871 } 872 } 873 874 static void 875 get_v4flags(const ire_t *ire, char *flags) 876 { 877 (void) strcpy(flags, "U"); 878 if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX || 879 ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT) 880 (void) strcat(flags, "G"); 881 if (ire->ire_mask == IP_HOST_MASK) 882 (void) strcat(flags, "H"); 883 if (ire->ire_type == IRE_HOST_REDIRECT) 884 (void) strcat(flags, "D"); 885 if (ire->ire_type == IRE_CACHE) 886 (void) strcat(flags, "A"); 887 if (ire->ire_type == IRE_BROADCAST) 888 (void) strcat(flags, "B"); 889 if (ire->ire_type == IRE_LOCAL) 890 (void) strcat(flags, "L"); 891 if (ire->ire_flags & RTF_MULTIRT) 892 (void) strcat(flags, "M"); 893 if (ire->ire_flags & RTF_SETSRC) 894 (void) strcat(flags, "S"); 895 } 896 897 static int 898 netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 899 { 900 const ire_t *ire = walk_data; 901 uint_t *opts = cb_data; 902 ipaddr_t gate; 903 char flags[10], intf[LIFNAMSIZ + 1]; 904 905 if (ire->ire_ipversion != IPV4_VERSION) 906 return (WALK_NEXT); 907 908 if (!(*opts & NETSTAT_ALL) && (ire->ire_type == IRE_CACHE || 909 ire->ire_type == IRE_BROADCAST || ire->ire_type == IRE_LOCAL)) 910 return (WALK_NEXT); 911 912 if (*opts & NETSTAT_FIRST) { 913 *opts &= ~NETSTAT_FIRST; 914 mdb_printf("%<u>%s Table: IPv4%</u>\n", 915 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing"); 916 if (*opts & NETSTAT_VERBOSE) { 917 mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt " 918 " Ref Flg Out In/Fwd%</u>\n", 919 "Address", ADDR_V4_WIDTH, "Destination", 920 ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway"); 921 } else { 922 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use " 923 "Interface%</u>\n", 924 "Address", ADDR_V4_WIDTH, "Destination", 925 ADDR_V4_WIDTH, "Gateway"); 926 } 927 } 928 929 gate = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK|IRE_BROADCAST)) ? 930 ire->ire_src_addr : ire->ire_gateway_addr; 931 932 get_v4flags(ire, flags); 933 934 get_ifname(ire, intf); 935 936 if (*opts & NETSTAT_VERBOSE) { 937 mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u " 938 "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, 939 ire->ire_mask, ADDR_V4_WIDTH, gate, intf, 940 ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ', 941 ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, flags, 942 ire->ire_ob_pkt_count, ire->ire_ib_pkt_count); 943 } else { 944 mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr, 945 ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags, 946 ire->ire_refcnt, 947 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf); 948 } 949 950 return (WALK_NEXT); 951 } 952 953 int 954 ip_mask_to_plen_v6(const in6_addr_t *v6mask) 955 { 956 int plen; 957 int i; 958 uint32_t val; 959 960 for (i = 3; i >= 0; i--) 961 if (v6mask->s6_addr32[i] != 0) 962 break; 963 if (i < 0) 964 return (0); 965 plen = 32 + 32 * i; 966 val = v6mask->s6_addr32[i]; 967 while (!(val & 1)) { 968 val >>= 1; 969 plen--; 970 } 971 972 return (plen); 973 } 974 975 static int 976 netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 977 { 978 const ire_t *ire = walk_data; 979 uint_t *opts = cb_data; 980 const in6_addr_t *gatep; 981 char deststr[ADDR_V6_WIDTH + 5]; 982 char flags[10], intf[LIFNAMSIZ + 1]; 983 int masklen; 984 985 if (ire->ire_ipversion != IPV6_VERSION) 986 return (WALK_NEXT); 987 988 if (!(*opts & NETSTAT_ALL) && ire->ire_type == IRE_CACHE) 989 return (WALK_NEXT); 990 991 if (*opts & NETSTAT_FIRST) { 992 *opts &= ~NETSTAT_FIRST; 993 mdb_printf("\n%<u>%s Table: IPv6%</u>\n", 994 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing"); 995 if (*opts & NETSTAT_VERBOSE) { 996 mdb_printf("%<u>%-?s %-*s %-*s If PMTU Rtt Ref " 997 "Flags Out In/Fwd%</u>\n", 998 "Address", ADDR_V6_WIDTH+4, "Destination/Mask", 999 ADDR_V6_WIDTH, "Gateway"); 1000 } else { 1001 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use If" 1002 "%</u>\n", 1003 "Address", ADDR_V6_WIDTH+4, "Destination/Mask", 1004 ADDR_V6_WIDTH, "Gateway"); 1005 } 1006 } 1007 1008 gatep = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK)) ? 1009 &ire->ire_src_addr_v6 : &ire->ire_gateway_addr_v6; 1010 1011 masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6); 1012 (void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d", 1013 &ire->ire_addr_v6, masklen); 1014 1015 (void) strcpy(flags, "U"); 1016 if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX || 1017 ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT) 1018 (void) strcat(flags, "G"); 1019 if (masklen == IPV6_ABITS) 1020 (void) strcat(flags, "H"); 1021 if (ire->ire_type == IRE_HOST_REDIRECT) 1022 (void) strcat(flags, "D"); 1023 if (ire->ire_type == IRE_CACHE) 1024 (void) strcat(flags, "A"); 1025 if (ire->ire_type == IRE_LOCAL) 1026 (void) strcat(flags, "L"); 1027 if (ire->ire_flags & RTF_MULTIRT) 1028 (void) strcat(flags, "M"); 1029 if (ire->ire_flags & RTF_SETSRC) 1030 (void) strcat(flags, "S"); 1031 1032 get_ifname(ire, intf); 1033 1034 if (*opts & NETSTAT_VERBOSE) { 1035 mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n", 1036 kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, 1037 intf, ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ', 1038 ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, 1039 flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count); 1040 } else { 1041 mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr, 1042 ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags, 1043 ire->ire_refcnt, 1044 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf); 1045 } 1046 1047 return (WALK_NEXT); 1048 } 1049 1050 /*ARGSUSED*/ 1051 int 1052 netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1053 { 1054 uint_t opts = 0; 1055 const char *optf = NULL; 1056 const char *optP = NULL; 1057 1058 if (mdb_getopts(argc, argv, 1059 'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts, 1060 'f', MDB_OPT_STR, &optf, 1061 'P', MDB_OPT_STR, &optP, 1062 'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts, 1063 'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts, 1064 NULL) != argc) 1065 return (DCMD_USAGE); 1066 1067 if (optP != NULL) { 1068 if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0)) 1069 return (DCMD_USAGE); 1070 if (opts & NETSTAT_ROUTE) 1071 return (DCMD_USAGE); 1072 } 1073 1074 if (optf == NULL) 1075 opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX; 1076 else if (strcmp("inet", optf) == 0) 1077 opts |= NETSTAT_V4; 1078 else if (strcmp("inet6", optf) == 0) 1079 opts |= NETSTAT_V6; 1080 else if (strcmp("unix", optf) == 0) 1081 opts |= NETSTAT_UNIX; 1082 else 1083 return (DCMD_USAGE); 1084 1085 if (opts & NETSTAT_ROUTE) { 1086 if (!(opts & (NETSTAT_V4|NETSTAT_V6))) 1087 return (DCMD_USAGE); 1088 if (opts & NETSTAT_V4) { 1089 opts |= NETSTAT_FIRST; 1090 if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) { 1091 mdb_warn("failed to walk ip`ire"); 1092 return (DCMD_ERR); 1093 } 1094 } 1095 if (opts & NETSTAT_V6) { 1096 opts |= NETSTAT_FIRST; 1097 if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) { 1098 mdb_warn("failed to walk ip`ire"); 1099 return (DCMD_ERR); 1100 } 1101 } 1102 return (DCMD_OK); 1103 } 1104 1105 if ((optP == NULL) || (strcmp("tcp", optP) == 0)) { 1106 if ((optf == NULL) || (strcmp("inet", optf) == 0)) { 1107 /* Print TCPv4 connection */ 1108 mdb_printf("%<u>%-?s St %*s %*s " 1109 "%s% %s%</u>\n", 1110 "TCPv4", ADDR_V4_WIDTH, "Local Address", 1111 ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone"); 1112 1113 if (opts & NETSTAT_VERBOSE) 1114 netstat_tcp_verbose_header_pr(); 1115 1116 if (mdb_walk("tcp_conn_cache", netstat_tcpv4_cb, 1117 (void *)(uintptr_t)opts) == -1) { 1118 mdb_warn("failed to walk tcp_conn_cache"); 1119 return (DCMD_ERR); 1120 } 1121 } 1122 1123 if ((optf == NULL) || (strcmp("inet6", optf) == 0)) { 1124 /* Print TCPv6 connection */ 1125 mdb_printf("%<u>%-?s St %*s %*s " 1126 "%s %s%\n%</u>", 1127 "TCPv6", ADDR_V6_WIDTH, "Local Address", 1128 ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone"); 1129 1130 if (opts & NETSTAT_VERBOSE) 1131 netstat_tcp_verbose_header_pr(); 1132 1133 if (mdb_walk("tcp_conn_cache", netstat_tcpv6_cb, 1134 (void *)(uintptr_t)opts) == -1) { 1135 mdb_warn("failed to walk tcp_conn_cache"); 1136 return (DCMD_ERR); 1137 } 1138 } 1139 } 1140 1141 if ((optP == NULL) || (strcmp("udp", optP) == 0)) { 1142 if ((optf == NULL) || (strcmp("inet", optf) == 0)) { 1143 /* Print UDPv4 connection */ 1144 mdb_printf("%<u>%-?s St %*s %*s " 1145 "%s %s%\n%</u>", 1146 "UDPv4", ADDR_V4_WIDTH, "Local Address", 1147 ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone"); 1148 1149 if (mdb_walk("udp_conn_cache", netstat_udpv4_cb, 1150 (void *)(uintptr_t)opts) == -1) { 1151 mdb_warn("failed to walk udp_conn_cache"); 1152 return (DCMD_ERR); 1153 } 1154 1155 } 1156 1157 if ((optf == NULL) || (strcmp("inet6", optf) == 0)) { 1158 /* Print UDPv6 connection */ 1159 mdb_printf("%<u>%-?s St %*s %*s " 1160 "%s %s%\n%</u>", 1161 "UDPv6", ADDR_V6_WIDTH, "Local Address", 1162 ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone"); 1163 1164 if (mdb_walk("udp_conn_cache", netstat_udpv6_cb, 1165 (void *)(uintptr_t)opts) == -1) { 1166 mdb_warn("failed to walk udp_conn_cache"); 1167 return (DCMD_ERR); 1168 } 1169 } 1170 } 1171 1172 if (((optf == NULL) || (strcmp("unix", optf) == 0)) && (optP == NULL)) { 1173 /* Print Unix Domain Sockets */ 1174 mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n", 1175 "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr", 1176 "Remote Addr", "Zone"); 1177 1178 if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) { 1179 mdb_warn("failed to walk genunix`sonode"); 1180 return (DCMD_ERR); 1181 } 1182 } 1183 1184 return (DCMD_OK); 1185 } 1186