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