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 uintptr_t tcp_kaddr; 621 conn_t conns, *connp; 622 tcp_t tcps, *tcp; 623 624 if (mdb_vread(&conns, sizeof (conn_t), kaddr) == -1) { 625 mdb_warn("failed to read conn_t at %p", kaddr); 626 return (WALK_ERR); 627 } 628 connp = &conns; 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 638 connp->conn_tcp = tcp; 639 tcp->tcp_connp = connp; 640 641 if (!((opts & NETSTAT_ALL) || net_tcp_active(tcp)) || 642 (af == AF_INET && !net_tcp_ipv4(tcp)) || 643 (af == AF_INET6 && !net_tcp_ipv6(tcp))) { 644 return (WALK_NEXT); 645 } 646 647 mdb_printf("%0?p %2i ", tcp_kaddr, tcp->tcp_state); 648 if (af == AF_INET) { 649 net_ipv4addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport); 650 mdb_printf(" "); 651 net_ipv4addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport); 652 } else if (af == AF_INET6) { 653 net_ipv6addrport_pr(&tcp->tcp_ip_src_v6, tcp->tcp_lport); 654 mdb_printf(" "); 655 net_ipv6addrport_pr(&tcp->tcp_remote_v6, tcp->tcp_fport); 656 } 657 mdb_printf(" %4i", ns_to_stackid((uintptr_t)connp->conn_netstack)); 658 659 mdb_printf(" %4i\n", connp->conn_zoneid); 660 661 if (opts & NETSTAT_VERBOSE) 662 netstat_tcp_verbose_pr(tcp); 663 664 return (WALK_NEXT); 665 } 666 667 static int 668 netstat_tcpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 669 { 670 return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET)); 671 } 672 673 static int 674 netstat_tcpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 675 { 676 return (netstat_tcp_cb(kaddr, walk_data, cb_data, AF_INET6)); 677 } 678 679 /*ARGSUSED*/ 680 static int 681 netstat_udp_cb(uintptr_t kaddr, const void *walk_data, void *cb_data, int af) 682 { 683 const uintptr_t opts = (uintptr_t)cb_data; 684 udp_t udp; 685 conn_t conns; 686 687 if (mdb_vread(&conns, sizeof (conn_t), kaddr) == -1) { 688 mdb_warn("failed to read conn_t at %p", kaddr); 689 return (WALK_ERR); 690 } 691 692 if (mdb_vread(&udp, sizeof (udp_t), 693 (uintptr_t)conns.conn_udp) == -1) { 694 mdb_warn("failed to read conn_udp at %p", 695 (uintptr_t)conns.conn_udp); 696 return (WALK_ERR); 697 } 698 699 if (!((opts & NETSTAT_ALL) || net_udp_active(&udp)) || 700 (af == AF_INET && !net_udp_ipv4(&udp)) || 701 (af == AF_INET6 && !net_udp_ipv6(&udp))) { 702 return (WALK_NEXT); 703 } 704 705 mdb_printf("%0?p %2i ", kaddr, udp.udp_state); 706 if (af == AF_INET) { 707 net_ipv4addrport_pr(&udp.udp_v6src, udp.udp_port); 708 mdb_printf(" "); 709 net_ipv4addrport_pr(&udp.udp_v6dst, udp.udp_dstport); 710 } else if (af == AF_INET6) { 711 net_ipv6addrport_pr(&udp.udp_v6src, udp.udp_port); 712 mdb_printf(" "); 713 net_ipv6addrport_pr(&udp.udp_v6dst, udp.udp_dstport); 714 } 715 mdb_printf(" %4i", ns_to_stackid((uintptr_t)conns.conn_netstack)); 716 717 mdb_printf(" %4i\n", conns.conn_zoneid); 718 719 return (WALK_NEXT); 720 } 721 722 static int 723 netstat_udpv4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 724 { 725 return (netstat_udp_cb(kaddr, walk_data, cb_data, AF_INET)); 726 } 727 728 static int 729 netstat_udpv6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 730 { 731 return (netstat_udp_cb(kaddr, walk_data, cb_data, AF_INET6)); 732 } 733 734 /* 735 * print the address of a unix domain socket 736 * 737 * so is the address of a AF_UNIX struct sonode in mdb's address space 738 * soa is the address of the struct soaddr to print 739 * 740 * returns 0 on success, -1 otherwise 741 */ 742 static int 743 netstat_unix_name_pr(const struct sonode *so, const struct soaddr *soa) 744 { 745 const char none[] = " (none)"; 746 747 if ((so->so_state & SS_ISBOUND) && (soa->soa_len != 0)) { 748 if (so->so_state & SS_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 sonode *so = walk_data; 779 780 if (so->so_accessvp == NULL) 781 return (WALK_NEXT); 782 783 if (so->so_family != AF_UNIX) { 784 mdb_warn("sonode of family %hi at %p\n", so->so_family, kaddr); 785 return (WALK_ERR); 786 } 787 788 mdb_printf("%-?p ", kaddr); 789 790 switch (so->so_serv_type) { 791 case T_CLTS: 792 mdb_printf("%-10s ", "dgram"); 793 break; 794 case T_COTS: 795 mdb_printf("%-10s ", "stream"); 796 break; 797 case T_COTS_ORD: 798 mdb_printf("%-10s ", "stream-ord"); 799 break; 800 default: 801 mdb_printf("%-10i ", so->so_serv_type); 802 } 803 804 if ((so->so_state & SS_ISBOUND) && 805 (so->so_ux_laddr.soua_magic == SOU_MAGIC_EXPLICIT)) { 806 mdb_printf("%0?p ", so->so_ux_laddr.soua_vp); 807 } else { 808 mdb_printf("%0?p ", NULL); 809 } 810 811 if ((so->so_state & SS_ISCONNECTED) && 812 (so->so_ux_faddr.soua_magic == SOU_MAGIC_EXPLICIT)) { 813 mdb_printf("%0?p ", so->so_ux_faddr.soua_vp); 814 } else { 815 mdb_printf("%0?p ", NULL); 816 } 817 818 if (netstat_unix_name_pr(so, &so->so_laddr) == -1) 819 return (WALK_ERR); 820 821 if (netstat_unix_name_pr(so, &so->so_faddr) == -1) 822 return (WALK_ERR); 823 824 mdb_printf("%4i\n", so->so_zoneid); 825 826 return (WALK_NEXT); 827 } 828 829 static void 830 netstat_tcp_verbose_header_pr(void) 831 { 832 mdb_printf(" %<u>%-5s %-8s %-8s %-5s %-8s %-8s %5s %5s%</u>\n", 833 "Swind", "Snext", "Suna", "Rwind", "Rack", "Rnext", "Rto", "Mss"); 834 } 835 836 static void 837 get_ifname(const ire_t *ire, char *intf) 838 { 839 ill_t ill; 840 841 *intf = '\0'; 842 if (ire->ire_type == IRE_CACHE) { 843 queue_t stq; 844 845 if (mdb_vread(&stq, sizeof (stq), (uintptr_t)ire->ire_stq) == 846 -1) 847 return; 848 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)stq.q_ptr) == -1) 849 return; 850 (void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length), 851 (uintptr_t)ill.ill_name); 852 } else if (ire->ire_ipif != NULL) { 853 ipif_t ipif; 854 char *cp; 855 856 if (mdb_vread(&ipif, sizeof (ipif), 857 (uintptr_t)ire->ire_ipif) == -1) 858 return; 859 if (mdb_vread(&ill, sizeof (ill), (uintptr_t)ipif.ipif_ill) == 860 -1) 861 return; 862 (void) mdb_readstr(intf, MIN(LIFNAMSIZ, ill.ill_name_length), 863 (uintptr_t)ill.ill_name); 864 if (ipif.ipif_id != 0) { 865 cp = intf + strlen(intf); 866 (void) mdb_snprintf(cp, LIFNAMSIZ + 1 - (cp - intf), 867 ":%u", ipif.ipif_id); 868 } 869 } 870 } 871 872 static void 873 get_v4flags(const ire_t *ire, char *flags) 874 { 875 (void) strcpy(flags, "U"); 876 if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX || 877 ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT) 878 (void) strcat(flags, "G"); 879 if (ire->ire_mask == IP_HOST_MASK) 880 (void) strcat(flags, "H"); 881 if (ire->ire_type == IRE_HOST_REDIRECT) 882 (void) strcat(flags, "D"); 883 if (ire->ire_type == IRE_CACHE) 884 (void) strcat(flags, "A"); 885 if (ire->ire_type == IRE_BROADCAST) 886 (void) strcat(flags, "B"); 887 if (ire->ire_type == IRE_LOCAL) 888 (void) strcat(flags, "L"); 889 if (ire->ire_flags & RTF_MULTIRT) 890 (void) strcat(flags, "M"); 891 if (ire->ire_flags & RTF_SETSRC) 892 (void) strcat(flags, "S"); 893 } 894 895 static int 896 netstat_irev4_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 897 { 898 const ire_t *ire = walk_data; 899 uint_t *opts = cb_data; 900 ipaddr_t gate; 901 char flags[10], intf[LIFNAMSIZ + 1]; 902 903 if (ire->ire_ipversion != IPV4_VERSION) 904 return (WALK_NEXT); 905 906 if (!(*opts & NETSTAT_ALL) && (ire->ire_type == IRE_CACHE || 907 ire->ire_type == IRE_BROADCAST || ire->ire_type == IRE_LOCAL)) 908 return (WALK_NEXT); 909 910 if (*opts & NETSTAT_FIRST) { 911 *opts &= ~NETSTAT_FIRST; 912 mdb_printf("%<u>%s Table: IPv4%</u>\n", 913 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing"); 914 if (*opts & NETSTAT_VERBOSE) { 915 mdb_printf("%<u>%-?s %-*s %-*s %-*s Device Mxfrg Rtt " 916 " Ref Flg Out In/Fwd%</u>\n", 917 "Address", ADDR_V4_WIDTH, "Destination", 918 ADDR_V4_WIDTH, "Mask", ADDR_V4_WIDTH, "Gateway"); 919 } else { 920 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use " 921 "Interface%</u>\n", 922 "Address", ADDR_V4_WIDTH, "Destination", 923 ADDR_V4_WIDTH, "Gateway"); 924 } 925 } 926 927 gate = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK|IRE_BROADCAST)) ? 928 ire->ire_src_addr : ire->ire_gateway_addr; 929 930 get_v4flags(ire, flags); 931 932 get_ifname(ire, intf); 933 934 if (*opts & NETSTAT_VERBOSE) { 935 mdb_printf("%?p %-*I %-*I %-*I %-6s %5u%c %4u %3u %-3s %5u " 936 "%u\n", kaddr, ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, 937 ire->ire_mask, ADDR_V4_WIDTH, gate, intf, 938 ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ', 939 ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, flags, 940 ire->ire_ob_pkt_count, ire->ire_ib_pkt_count); 941 } else { 942 mdb_printf("%?p %-*I %-*I %-5s %4u %5u %s\n", kaddr, 943 ADDR_V4_WIDTH, ire->ire_addr, ADDR_V4_WIDTH, gate, flags, 944 ire->ire_refcnt, 945 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf); 946 } 947 948 return (WALK_NEXT); 949 } 950 951 int 952 ip_mask_to_plen_v6(const in6_addr_t *v6mask) 953 { 954 int plen; 955 int i; 956 uint32_t val; 957 958 for (i = 3; i >= 0; i--) 959 if (v6mask->s6_addr32[i] != 0) 960 break; 961 if (i < 0) 962 return (0); 963 plen = 32 + 32 * i; 964 val = v6mask->s6_addr32[i]; 965 while (!(val & 1)) { 966 val >>= 1; 967 plen--; 968 } 969 970 return (plen); 971 } 972 973 static int 974 netstat_irev6_cb(uintptr_t kaddr, const void *walk_data, void *cb_data) 975 { 976 const ire_t *ire = walk_data; 977 uint_t *opts = cb_data; 978 const in6_addr_t *gatep; 979 char deststr[ADDR_V6_WIDTH + 5]; 980 char flags[10], intf[LIFNAMSIZ + 1]; 981 int masklen; 982 983 if (ire->ire_ipversion != IPV6_VERSION) 984 return (WALK_NEXT); 985 986 if (!(*opts & NETSTAT_ALL) && ire->ire_type == IRE_CACHE) 987 return (WALK_NEXT); 988 989 if (*opts & NETSTAT_FIRST) { 990 *opts &= ~NETSTAT_FIRST; 991 mdb_printf("\n%<u>%s Table: IPv6%</u>\n", 992 (*opts & NETSTAT_VERBOSE) ? "IRE" : "Routing"); 993 if (*opts & NETSTAT_VERBOSE) { 994 mdb_printf("%<u>%-?s %-*s %-*s If PMTU Rtt Ref " 995 "Flags Out In/Fwd%</u>\n", 996 "Address", ADDR_V6_WIDTH+4, "Destination/Mask", 997 ADDR_V6_WIDTH, "Gateway"); 998 } else { 999 mdb_printf("%<u>%-?s %-*s %-*s Flags Ref Use If" 1000 "%</u>\n", 1001 "Address", ADDR_V6_WIDTH+4, "Destination/Mask", 1002 ADDR_V6_WIDTH, "Gateway"); 1003 } 1004 } 1005 1006 gatep = (ire->ire_type & (IRE_INTERFACE|IRE_LOOPBACK)) ? 1007 &ire->ire_src_addr_v6 : &ire->ire_gateway_addr_v6; 1008 1009 masklen = ip_mask_to_plen_v6(&ire->ire_mask_v6); 1010 (void) mdb_snprintf(deststr, sizeof (deststr), "%N/%d", 1011 &ire->ire_addr_v6, masklen); 1012 1013 (void) strcpy(flags, "U"); 1014 if (ire->ire_type == IRE_DEFAULT || ire->ire_type == IRE_PREFIX || 1015 ire->ire_type == IRE_HOST || ire->ire_type == IRE_HOST_REDIRECT) 1016 (void) strcat(flags, "G"); 1017 if (masklen == IPV6_ABITS) 1018 (void) strcat(flags, "H"); 1019 if (ire->ire_type == IRE_HOST_REDIRECT) 1020 (void) strcat(flags, "D"); 1021 if (ire->ire_type == IRE_CACHE) 1022 (void) strcat(flags, "A"); 1023 if (ire->ire_type == IRE_LOCAL) 1024 (void) strcat(flags, "L"); 1025 if (ire->ire_flags & RTF_MULTIRT) 1026 (void) strcat(flags, "M"); 1027 if (ire->ire_flags & RTF_SETSRC) 1028 (void) strcat(flags, "S"); 1029 1030 get_ifname(ire, intf); 1031 1032 if (*opts & NETSTAT_VERBOSE) { 1033 mdb_printf("%?p %-*s %-*N %-5s %5u%c %5u %3u %-5s %6u %u\n", 1034 kaddr, ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, 1035 intf, ire->ire_max_frag, ire->ire_frag_flag ? '*' : ' ', 1036 ire->ire_uinfo.iulp_rtt, ire->ire_refcnt, 1037 flags, ire->ire_ob_pkt_count, ire->ire_ib_pkt_count); 1038 } else { 1039 mdb_printf("%?p %-*s %-*N %-5s %3u %6u %s\n", kaddr, 1040 ADDR_V6_WIDTH+4, deststr, ADDR_V6_WIDTH, gatep, flags, 1041 ire->ire_refcnt, 1042 ire->ire_ob_pkt_count + ire->ire_ib_pkt_count, intf); 1043 } 1044 1045 return (WALK_NEXT); 1046 } 1047 1048 /*ARGSUSED*/ 1049 int 1050 netstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1051 { 1052 uint_t opts = 0; 1053 const char *optf = NULL; 1054 const char *optP = NULL; 1055 1056 if (mdb_getopts(argc, argv, 1057 'a', MDB_OPT_SETBITS, NETSTAT_ALL, &opts, 1058 'f', MDB_OPT_STR, &optf, 1059 'P', MDB_OPT_STR, &optP, 1060 'r', MDB_OPT_SETBITS, NETSTAT_ROUTE, &opts, 1061 'v', MDB_OPT_SETBITS, NETSTAT_VERBOSE, &opts, 1062 NULL) != argc) 1063 return (DCMD_USAGE); 1064 1065 if (optP != NULL) { 1066 if ((strcmp("tcp", optP) != 0) && (strcmp("udp", optP) != 0)) 1067 return (DCMD_USAGE); 1068 if (opts & NETSTAT_ROUTE) 1069 return (DCMD_USAGE); 1070 } 1071 1072 if (optf == NULL) 1073 opts |= NETSTAT_V4 | NETSTAT_V6 | NETSTAT_UNIX; 1074 else if (strcmp("inet", optf) == 0) 1075 opts |= NETSTAT_V4; 1076 else if (strcmp("inet6", optf) == 0) 1077 opts |= NETSTAT_V6; 1078 else if (strcmp("unix", optf) == 0) 1079 opts |= NETSTAT_UNIX; 1080 else 1081 return (DCMD_USAGE); 1082 1083 if (opts & NETSTAT_ROUTE) { 1084 if (!(opts & (NETSTAT_V4|NETSTAT_V6))) 1085 return (DCMD_USAGE); 1086 if (opts & NETSTAT_V4) { 1087 opts |= NETSTAT_FIRST; 1088 if (mdb_walk("ip`ire", netstat_irev4_cb, &opts) == -1) { 1089 mdb_warn("failed to walk ip`ire"); 1090 return (DCMD_ERR); 1091 } 1092 } 1093 if (opts & NETSTAT_V6) { 1094 opts |= NETSTAT_FIRST; 1095 if (mdb_walk("ip`ire", netstat_irev6_cb, &opts) == -1) { 1096 mdb_warn("failed to walk ip`ire"); 1097 return (DCMD_ERR); 1098 } 1099 } 1100 return (DCMD_OK); 1101 } 1102 1103 if ((optP == NULL) || (strcmp("tcp", optP) == 0)) { 1104 if ((optf == NULL) || (strcmp("inet", optf) == 0)) { 1105 /* Print TCPv4 connection */ 1106 mdb_printf("%<u>%-?s St %*s %*s " 1107 "%s% %s%</u>\n", 1108 "TCPv4", ADDR_V4_WIDTH, "Local Address", 1109 ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone"); 1110 1111 if (opts & NETSTAT_VERBOSE) 1112 netstat_tcp_verbose_header_pr(); 1113 1114 if (mdb_walk("tcp_conn_cache", netstat_tcpv4_cb, 1115 (void *)(uintptr_t)opts) == -1) { 1116 mdb_warn("failed to walk tcp_conn_cache"); 1117 return (DCMD_ERR); 1118 } 1119 } 1120 1121 if ((optf == NULL) || (strcmp("inet6", optf) == 0)) { 1122 /* Print TCPv6 connection */ 1123 mdb_printf("%<u>%-?s St %*s %*s " 1124 "%s %s%\n%</u>", 1125 "TCPv6", ADDR_V6_WIDTH, "Local Address", 1126 ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone"); 1127 1128 if (opts & NETSTAT_VERBOSE) 1129 netstat_tcp_verbose_header_pr(); 1130 1131 if (mdb_walk("tcp_conn_cache", netstat_tcpv6_cb, 1132 (void *)(uintptr_t)opts) == -1) { 1133 mdb_warn("failed to walk tcp_conn_cache"); 1134 return (DCMD_ERR); 1135 } 1136 } 1137 } 1138 1139 if ((optP == NULL) || (strcmp("udp", optP) == 0)) { 1140 if ((optf == NULL) || (strcmp("inet", optf) == 0)) { 1141 /* Print UDPv4 connection */ 1142 mdb_printf("%<u>%-?s St %*s %*s " 1143 "%s %s%\n%</u>", 1144 "UDPv4", ADDR_V4_WIDTH, "Local Address", 1145 ADDR_V4_WIDTH, "Remote Address", "Stack", "Zone"); 1146 1147 if (mdb_walk("udp_conn_cache", netstat_udpv4_cb, 1148 (void *)(uintptr_t)opts) == -1) { 1149 mdb_warn("failed to walk udp_conn_cache"); 1150 return (DCMD_ERR); 1151 } 1152 1153 } 1154 1155 if ((optf == NULL) || (strcmp("inet6", optf) == 0)) { 1156 /* Print UDPv6 connection */ 1157 mdb_printf("%<u>%-?s St %*s %*s " 1158 "%s %s%\n%</u>", 1159 "UDPv6", ADDR_V6_WIDTH, "Local Address", 1160 ADDR_V6_WIDTH, "Remote Address", "Stack", "Zone"); 1161 1162 if (mdb_walk("udp_conn_cache", netstat_udpv6_cb, 1163 (void *)(uintptr_t)opts) == -1) { 1164 mdb_warn("failed to walk udp_conn_cache"); 1165 return (DCMD_ERR); 1166 } 1167 } 1168 } 1169 1170 if (((optf == NULL) || (strcmp("unix", optf) == 0)) && (optP == NULL)) { 1171 /* Print Unix Domain Sockets */ 1172 mdb_printf("%<u>%-?s %-10s %-?s %-?s %-14s %-14s %s%</u>\n", 1173 "AF_UNIX", "Type", "Vnode", "Conn", "Local Addr", 1174 "Remote Addr", "Zone"); 1175 1176 if (mdb_walk("genunix`sonode", netstat_unix_cb, NULL) == -1) { 1177 mdb_warn("failed to walk genunix`sonode"); 1178 return (DCMD_ERR); 1179 } 1180 } 1181 1182 return (DCMD_OK); 1183 } 1184