net.c revision 8348:4137e18bfaf0
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 */ 67int 68ar_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 77int 78ar_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 91int 92icmp_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 101int 102icmp_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 115int 116tcp_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 125int 126tcp_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 139int 140udp_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 149int 150udp_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 */ 167static void 168net_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 */ 180static void 181net_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 187static int 188net_tcp_active(const tcp_t *tcp) 189{ 190 return (tcp->tcp_state >= TCPS_ESTABLISHED); 191} 192 193static int 194net_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 201static int 202net_tcp_ipv6(const tcp_t *tcp) 203{ 204 return (tcp->tcp_ipversion == IPV6_VERSION); 205} 206 207static int 208net_udp_active(const udp_t *udp) 209{ 210 return ((udp->udp_state == TS_IDLE) || 211 (udp->udp_state == TS_DATA_XFER)); 212} 213 214static int 215net_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 222static int 223net_udp_ipv6(const udp_t *udp) 224{ 225 return (udp->udp_ipversion == IPV6_VERSION); 226} 227 228int 229sonode_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 254int 255sonode_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 278void 279sonode_walk_fini(mdb_walk_state_t *wsp) 280{ 281 mdb_free(wsp->walk_data, sizeof (struct sotpi_sonode)); 282} 283 284struct mi_walk_data { 285 uintptr_t mi_wd_miofirst; 286 MI_O mi_wd_miodata; 287}; 288 289int 290mi_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 308int 309mi_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 339void 340mi_walk_fini(mdb_walk_state_t *wsp) 341{ 342 mdb_free(wsp->walk_data, sizeof (struct mi_walk_data)); 343} 344 345typedef 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 355int 356mi_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 367int 368mi_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 394const 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 399const 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 404const 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 409int 410sonode(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 530int 531mi(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 592static int 593ns_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 606static void 607netstat_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*/ 615static int 616netstat_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 666static int 667netstat_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 672static int 673netstat_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*/ 679static int 680netstat_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 721static int 722netstat_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 727static int 728netstat_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 */ 741static int 742netstat_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*/ 775static int 776netstat_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 831static void 832netstat_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 838static void 839get_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 874static void 875get_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 897static int 898netstat_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 953int 954ip_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 975static int 976netstat_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*/ 1051int 1052netstat(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