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 <sys/types.h> 29 #include <sys/stropts.h> 30 #include <sys/stream.h> 31 #include <sys/socket.h> 32 #include <sys/avl_impl.h> 33 #include <net/if.h> 34 #include <net/route.h> 35 #include <netinet/in.h> 36 #include <netinet/ip6.h> 37 #include <netinet/udp.h> 38 #include <netinet/sctp.h> 39 #include <inet/mib2.h> 40 #include <inet/common.h> 41 #include <inet/ip.h> 42 #include <inet/ip_ire.h> 43 #include <inet/ip6.h> 44 #include <inet/ipclassifier.h> 45 #include <inet/mi.h> 46 #include <sys/squeue_impl.h> 47 48 #include <mdb/mdb_modapi.h> 49 #include <mdb/mdb_ks.h> 50 51 #define ADDR_WIDTH 11 52 53 typedef struct { 54 const char *bit_name; /* name of bit */ 55 const char *bit_descr; /* description of bit's purpose */ 56 } bitname_t; 57 58 static const bitname_t squeue_states[] = { 59 { "SQS_PROC", "being processed" }, 60 { "SQS_WORKER", "... by a worker thread" }, 61 { "SQS_ENTER", "... by an squeue_enter() thread" }, 62 { "SQS_FAST", "... in fast-path mode" }, 63 { "SQS_USER", "A non interrupt user" }, 64 { "SQS_BOUND", "worker thread bound to CPU" }, 65 { "SQS_PROFILE", "profiling enabled" }, 66 { "SQS_REENTER", "re-entered thred" }, 67 { NULL } 68 }; 69 70 typedef struct illif_walk_data { 71 ill_g_head_t ill_g_heads[MAX_G_HEADS]; 72 int ill_list; 73 ill_if_t ill_if; 74 } illif_walk_data_t; 75 76 static int iphdr(uintptr_t, uint_t, int, const mdb_arg_t *); 77 static int ip6hdr(uintptr_t, uint_t, int, const mdb_arg_t *); 78 79 static int ire_format(uintptr_t addr, const ire_t *irep, uint_t *verbose); 80 81 /* 82 * Given the kernel address of an ip_stack_t, return the stackid 83 */ 84 static int 85 ips_to_stackid(uintptr_t kaddr) 86 { 87 ip_stack_t ipss; 88 netstack_t nss; 89 90 if (mdb_vread(&ipss, sizeof (ipss), kaddr) == -1) { 91 mdb_warn("failed to read ip_stack_t %p", kaddr); 92 return (0); 93 } 94 kaddr = (uintptr_t)ipss.ips_netstack; 95 if (mdb_vread(&nss, sizeof (nss), kaddr) == -1) { 96 mdb_warn("failed to read netstack_t %p", kaddr); 97 return (0); 98 } 99 return (nss.netstack_stackid); 100 } 101 102 int 103 ip_stacks_walk_init(mdb_walk_state_t *wsp) 104 { 105 if (mdb_layered_walk("netstack", wsp) == -1) { 106 mdb_warn("can't walk 'netstack'"); 107 return (WALK_ERR); 108 } 109 return (WALK_NEXT); 110 } 111 112 int 113 ip_stacks_walk_step(mdb_walk_state_t *wsp) 114 { 115 uintptr_t kaddr; 116 netstack_t nss; 117 118 #ifdef DEBUG 119 mdb_printf("DEBUG: ip_stacks_walk_step: addr %p\n", wsp->walk_addr); 120 #endif 121 if (mdb_vread(&nss, sizeof (nss), wsp->walk_addr) == -1) { 122 mdb_warn("can't read netstack at %p", wsp->walk_addr); 123 return (WALK_ERR); 124 } 125 kaddr = (uintptr_t)nss.netstack_modules[NS_IP]; 126 127 #ifdef DEBUG 128 mdb_printf("DEBUG: ip_stacks_walk_step: ip_stack_t at %p\n", kaddr); 129 #endif 130 return (wsp->walk_callback(kaddr, wsp->walk_layer, wsp->walk_cbdata)); 131 } 132 133 /* 134 * Called with walk_addr being the address of ips_ill_g_heads 135 */ 136 int 137 illif_stack_walk_init(mdb_walk_state_t *wsp) 138 { 139 illif_walk_data_t *iw; 140 141 if (wsp->walk_addr == NULL) { 142 mdb_warn("illif_stack supports only local walks\n"); 143 return (WALK_ERR); 144 } 145 146 iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP); 147 148 if (mdb_vread(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t), 149 wsp->walk_addr) == -1) { 150 mdb_warn("failed to read 'ips_ill_g_heads' at %p", 151 wsp->walk_addr); 152 mdb_free(iw, sizeof (illif_walk_data_t)); 153 return (WALK_ERR); 154 } 155 156 iw->ill_list = 0; 157 wsp->walk_addr = (uintptr_t)iw->ill_g_heads[0].ill_g_list_head; 158 wsp->walk_data = iw; 159 160 return (WALK_NEXT); 161 } 162 163 int 164 illif_stack_walk_step(mdb_walk_state_t *wsp) 165 { 166 uintptr_t addr = wsp->walk_addr; 167 illif_walk_data_t *iw = wsp->walk_data; 168 int list = iw->ill_list; 169 170 if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) { 171 mdb_warn("failed to read ill_if_t at %p", addr); 172 return (WALK_ERR); 173 } 174 175 wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next; 176 177 if (wsp->walk_addr == 178 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head) { 179 180 if (++list >= MAX_G_HEADS) 181 return (WALK_DONE); 182 183 iw->ill_list = list; 184 wsp->walk_addr = 185 (uintptr_t)iw->ill_g_heads[list].ill_g_list_head; 186 return (WALK_NEXT); 187 } 188 189 return (wsp->walk_callback(addr, iw, wsp->walk_cbdata)); 190 } 191 192 void 193 illif_stack_walk_fini(mdb_walk_state_t *wsp) 194 { 195 mdb_free(wsp->walk_data, sizeof (illif_walk_data_t)); 196 } 197 198 typedef struct illif_cbdata { 199 uint_t ill_flags; 200 uintptr_t ill_addr; 201 int ill_printlist; /* list to be printed (MAX_G_HEADS for all) */ 202 boolean_t ill_printed; 203 } illif_cbdata_t; 204 205 static int 206 illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id) 207 { 208 const char *version; 209 210 if (id->ill_printlist < MAX_G_HEADS && 211 id->ill_printlist != iw->ill_list) 212 return (WALK_NEXT); 213 214 if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr) 215 return (WALK_NEXT); 216 217 if (id->ill_flags & DCMD_PIPE_OUT) { 218 mdb_printf("%p\n", addr); 219 return (WALK_NEXT); 220 } 221 222 switch (iw->ill_list) { 223 case IP_V4_G_HEAD: version = "v4"; break; 224 case IP_V6_G_HEAD: version = "v6"; break; 225 default: version = "??"; break; 226 } 227 228 mdb_printf("%?p %2s %?p %10d %?p %s\n", 229 addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa), 230 iw->ill_if.illif_avl_by_ppa.avl_numnodes, 231 iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name); 232 233 id->ill_printed = TRUE; 234 235 return (WALK_NEXT); 236 } 237 238 int 239 illif_walk_init(mdb_walk_state_t *wsp) 240 { 241 if (mdb_layered_walk("ip_stacks", wsp) == -1) { 242 mdb_warn("can't walk 'ip_stacks'"); 243 return (WALK_ERR); 244 } 245 246 return (WALK_NEXT); 247 } 248 249 int 250 illif_walk_step(mdb_walk_state_t *wsp) 251 { 252 uintptr_t kaddr; 253 254 #ifdef DEBUG 255 mdb_printf("DEBUG: illif_walk_step: addr %p\n", wsp->walk_addr); 256 #endif 257 258 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ill_g_heads); 259 260 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 261 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 262 return (WALK_ERR); 263 } 264 #ifdef DEBUG 265 mdb_printf("DEBUG: illif_walk_step: ips_ill_g_heads %p\n", kaddr); 266 #endif 267 268 if (mdb_pwalk("illif_stack", wsp->walk_callback, 269 wsp->walk_cbdata, kaddr) == -1) { 270 mdb_warn("couldn't walk 'illif_stack' for ips_ill_g_heads %p", 271 kaddr); 272 return (WALK_ERR); 273 } 274 return (WALK_NEXT); 275 } 276 277 int 278 illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 279 { 280 illif_cbdata_t id; 281 ill_if_t ill_if; 282 const char *opt_P = NULL; 283 int printlist = MAX_G_HEADS; 284 285 if (mdb_getopts(argc, argv, 286 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 287 return (DCMD_USAGE); 288 289 if (opt_P != NULL) { 290 if (strcmp("v4", opt_P) == 0) { 291 printlist = IP_V4_G_HEAD; 292 } else if (strcmp("v6", opt_P) == 0) { 293 printlist = IP_V6_G_HEAD; 294 } else { 295 mdb_warn("invalid protocol '%s'\n", opt_P); 296 return (DCMD_USAGE); 297 } 298 } 299 300 if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) { 301 mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n", 302 "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME"); 303 } 304 305 id.ill_flags = flags; 306 id.ill_addr = addr; 307 id.ill_printlist = printlist; 308 id.ill_printed = FALSE; 309 310 if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) { 311 mdb_warn("can't walk ill_if_t structures"); 312 return (DCMD_ERR); 313 } 314 315 if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed) 316 return (DCMD_OK); 317 318 /* 319 * If an address is specified and the walk doesn't find it, 320 * print it anyway. 321 */ 322 if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) { 323 mdb_warn("failed to read ill_if_t at %p", addr); 324 return (DCMD_ERR); 325 } 326 327 mdb_printf("%?p %2s %?p %10d %?p %s\n", 328 addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa), 329 ill_if.illif_avl_by_ppa.avl_numnodes, 330 ill_if.illif_ppa_arena, ill_if.illif_name); 331 332 return (DCMD_OK); 333 } 334 335 static void 336 illif_help(void) 337 { 338 mdb_printf("Options:\n"); 339 mdb_printf("\t-P v4 | v6" 340 "\tfilter interface structures for the specified protocol\n"); 341 } 342 343 int 344 ire_walk_init(mdb_walk_state_t *wsp) 345 { 346 if (mdb_layered_walk("ire_cache", wsp) == -1) { 347 mdb_warn("can't walk 'ire_cache'"); 348 return (WALK_ERR); 349 } 350 351 return (WALK_NEXT); 352 } 353 354 int 355 ire_walk_step(mdb_walk_state_t *wsp) 356 { 357 ire_t ire; 358 359 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 360 mdb_warn("can't read ire at %p", wsp->walk_addr); 361 return (WALK_ERR); 362 } 363 364 return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata)); 365 } 366 367 int 368 ire_ctable_walk_init(mdb_walk_state_t *wsp) 369 { 370 if (mdb_layered_walk("ip_stacks", wsp) == -1) { 371 mdb_warn("can't walk 'ip_stacks'"); 372 return (WALK_ERR); 373 } 374 375 return (WALK_NEXT); 376 } 377 378 int 379 ire_ctable_walk_step(mdb_walk_state_t *wsp) 380 { 381 uintptr_t kaddr; 382 irb_t *irb; 383 int verbose = 0; 384 uint32_t cache_table_size; 385 int i; 386 387 #ifdef DEBUG 388 mdb_printf("DEBUG: ire_ctable_walk_step: addr %p\n", wsp->walk_addr); 389 #endif 390 391 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table_size); 392 393 if (mdb_vread(&cache_table_size, sizeof (uint32_t), kaddr) == -1) { 394 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 395 return (WALK_ERR); 396 } 397 #ifdef DEBUG 398 mdb_printf("DEBUG: ire_ctable_walk_step: ips_ip_cache_table_size %u\n", 399 cache_table_size); 400 #endif 401 402 kaddr = wsp->walk_addr + OFFSETOF(ip_stack_t, ips_ip_cache_table); 403 if (mdb_vread(&kaddr, sizeof (kaddr), kaddr) == -1) { 404 mdb_warn("can't read ips_ip_cache_table at %p", kaddr); 405 return (WALK_ERR); 406 } 407 #ifdef DEBUG 408 mdb_printf("DEBUG: ire_ctable_walk_step: ips_ip_cache_table %p\n", 409 kaddr); 410 #endif 411 412 irb = mdb_alloc(sizeof (irb_t) * cache_table_size, UM_SLEEP|UM_GC); 413 if (mdb_vread(irb, sizeof (irb_t) * cache_table_size, kaddr) == -1) { 414 mdb_warn("can't read irb at %p", kaddr); 415 return (WALK_ERR); 416 } 417 for (i = 0; i < cache_table_size; i++) { 418 kaddr = (uintptr_t)irb[i].irb_ire; 419 #ifdef DEBUG 420 mdb_printf("DEBUG: ire_ctable_walk_step: %d ire %p\n", 421 i, kaddr); 422 #endif 423 424 if (mdb_pwalk("ire_next", (mdb_walk_cb_t)ire_format, &verbose, 425 kaddr) == -1) { 426 mdb_warn("can't walk 'ire_next' for ire %p", kaddr); 427 return (WALK_ERR); 428 } 429 } 430 return (WALK_NEXT); 431 } 432 433 /* ARGSUSED */ 434 int 435 ire_next_walk_init(mdb_walk_state_t *wsp) 436 { 437 #ifdef DEBUG 438 mdb_printf("DEBUG: ire_next_walk_init: addr %p\n", wsp->walk_addr); 439 #endif 440 return (WALK_NEXT); 441 } 442 443 int 444 ire_next_walk_step(mdb_walk_state_t *wsp) 445 { 446 ire_t ire; 447 int status; 448 449 #ifdef DEBUG 450 mdb_printf("DEBUG: ire_next_walk_step: addr %p\n", wsp->walk_addr); 451 #endif 452 453 if (wsp->walk_addr == NULL) 454 return (WALK_DONE); 455 456 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 457 mdb_warn("can't read ire at %p", wsp->walk_addr); 458 return (WALK_ERR); 459 } 460 status = wsp->walk_callback(wsp->walk_addr, &ire, 461 wsp->walk_cbdata); 462 463 if (status != WALK_NEXT) 464 return (status); 465 466 wsp->walk_addr = (uintptr_t)ire.ire_next; 467 #ifdef DEBUG 468 mdb_printf("DEBUG: ire_ctable_walk_step: next %p\n", wsp->walk_addr); 469 #endif 470 return (status); 471 } 472 473 static int 474 ire_format(uintptr_t addr, const ire_t *irep, uint_t *verbose) 475 { 476 static const mdb_bitmask_t tmasks[] = { 477 { "BROADCAST", IRE_BROADCAST, IRE_BROADCAST }, 478 { "DEFAULT", IRE_DEFAULT, IRE_DEFAULT }, 479 { "LOCAL", IRE_LOCAL, IRE_LOCAL }, 480 { "LOOPBACK", IRE_LOOPBACK, IRE_LOOPBACK }, 481 { "PREFIX", IRE_PREFIX, IRE_PREFIX }, 482 { "CACHE", IRE_CACHE, IRE_CACHE }, 483 { "IF_NORESOLVER", IRE_IF_NORESOLVER, IRE_IF_NORESOLVER }, 484 { "IF_RESOLVER", IRE_IF_RESOLVER, IRE_IF_RESOLVER }, 485 { "HOST", IRE_HOST, IRE_HOST }, 486 { "HOST_REDIRECT", IRE_HOST_REDIRECT, IRE_HOST_REDIRECT }, 487 { "MIPRTUN", IRE_MIPRTUN, IRE_MIPRTUN }, 488 { NULL, 0, 0 } 489 }; 490 491 static const mdb_bitmask_t mmasks[] = { 492 { "CONDEMNED", IRE_MARK_CONDEMNED, IRE_MARK_CONDEMNED }, 493 { "NORECV", IRE_MARK_NORECV, IRE_MARK_NORECV }, 494 { "HIDDEN", IRE_MARK_HIDDEN, IRE_MARK_HIDDEN }, 495 { "NOADD", IRE_MARK_NOADD, IRE_MARK_NOADD }, 496 { "TEMPORARY", IRE_MARK_TEMPORARY, IRE_MARK_TEMPORARY }, 497 { NULL, 0, 0 } 498 }; 499 500 static const mdb_bitmask_t fmasks[] = { 501 { "UP", RTF_UP, RTF_UP }, 502 { "GATEWAY", RTF_GATEWAY, RTF_GATEWAY }, 503 { "HOST", RTF_HOST, RTF_HOST }, 504 { "REJECT", RTF_REJECT, RTF_REJECT }, 505 { "DYNAMIC", RTF_DYNAMIC, RTF_DYNAMIC }, 506 { "MODIFIED", RTF_MODIFIED, RTF_MODIFIED }, 507 { "DONE", RTF_DONE, RTF_DONE }, 508 { "MASK", RTF_MASK, RTF_MASK }, 509 { "CLONING", RTF_CLONING, RTF_CLONING }, 510 { "XRESOLVE", RTF_XRESOLVE, RTF_XRESOLVE }, 511 { "LLINFO", RTF_LLINFO, RTF_LLINFO }, 512 { "STATIC", RTF_STATIC, RTF_STATIC }, 513 { "BLACKHOLE", RTF_BLACKHOLE, RTF_BLACKHOLE }, 514 { "PRIVATE", RTF_PRIVATE, RTF_PRIVATE }, 515 { "PROTO2", RTF_PROTO2, RTF_PROTO2 }, 516 { "PROTO1", RTF_PROTO1, RTF_PROTO1 }, 517 { "MULTIRT", RTF_MULTIRT, RTF_MULTIRT }, 518 { "SETSRC", RTF_SETSRC, RTF_SETSRC }, 519 { NULL, 0, 0 } 520 }; 521 522 if (irep->ire_ipversion == 6 && *verbose) { 523 524 mdb_printf("%<b>%?p%</b> %40N <%hb>\n" 525 "%?s %40N <%hb>\n" 526 "%?s %40d %4d <%hb>\n", 527 addr, &irep->ire_src_addr_v6, irep->ire_type, tmasks, 528 "", &irep->ire_addr_v6, (ushort_t)irep->ire_marks, mmasks, 529 "", ips_to_stackid((uintptr_t)irep->ire_ipst), 530 irep->ire_zoneid, 531 irep->ire_flags, fmasks); 532 533 } else if (irep->ire_ipversion == 6) { 534 535 mdb_printf("%?p %30N %30N %5d %4d\n", 536 addr, &irep->ire_src_addr_v6, 537 &irep->ire_addr_v6, 538 ips_to_stackid((uintptr_t)irep->ire_ipst), 539 irep->ire_zoneid); 540 541 } else if (*verbose) { 542 543 mdb_printf("%<b>%?p%</b> %40I <%hb>\n" 544 "%?s %40I <%hb>\n" 545 "%?s %40d <%hb>\n", 546 addr, irep->ire_src_addr, irep->ire_type, tmasks, 547 "", irep->ire_addr, (ushort_t)irep->ire_marks, mmasks, 548 "", ips_to_stackid((uintptr_t)irep->ire_ipst), 549 irep->ire_zoneid, irep->ire_flags, fmasks); 550 551 } else { 552 553 mdb_printf("%?p %30I %30I %5d %4d\n", addr, irep->ire_src_addr, 554 irep->ire_addr, ips_to_stackid((uintptr_t)irep->ire_ipst), 555 irep->ire_zoneid); 556 } 557 558 return (WALK_NEXT); 559 } 560 561 /* 562 * There are faster ways to do this. Given the interactive nature of this 563 * use I don't think its worth much effort. 564 */ 565 static unsigned short 566 ipcksum(void *p, int len) 567 { 568 int32_t sum = 0; 569 570 while (len > 1) { 571 /* alignment */ 572 sum += *(uint16_t *)p; 573 p = (char *)p + sizeof (uint16_t); 574 if (sum & 0x80000000) 575 sum = (sum & 0xFFFF) + (sum >> 16); 576 len -= 2; 577 } 578 579 if (len) 580 sum += (uint16_t)*(unsigned char *)p; 581 582 while (sum >> 16) 583 sum = (sum & 0xFFFF) + (sum >> 16); 584 585 return (~sum); 586 } 587 588 static const mdb_bitmask_t tcp_flags[] = { 589 { "SYN", TH_SYN, TH_SYN }, 590 { "ACK", TH_ACK, TH_ACK }, 591 { "FIN", TH_FIN, TH_FIN }, 592 { "RST", TH_RST, TH_RST }, 593 { "PSH", TH_PUSH, TH_PUSH }, 594 { "ECE", TH_ECE, TH_ECE }, 595 { "CWR", TH_CWR, TH_CWR }, 596 { NULL, 0, 0 } 597 }; 598 599 static void 600 tcphdr_print(struct tcphdr *tcph) 601 { 602 in_port_t sport, dport; 603 tcp_seq seq, ack; 604 uint16_t win, urp; 605 606 mdb_printf("%<b>TCP header%</b>\n"); 607 608 mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport)); 609 mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport)); 610 mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq)); 611 mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack)); 612 mdb_nhconvert(&win, &tcph->th_win, sizeof (win)); 613 mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp)); 614 615 mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n", 616 "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP", 617 "FLAGS"); 618 mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n", 619 sport, dport, seq, ack, tcph->th_off << 2, win, 620 tcph->th_sum, urp, tcph->th_flags, tcp_flags); 621 mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n", 622 sport, dport, seq, ack); 623 } 624 625 /* ARGSUSED */ 626 static int 627 tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 628 { 629 struct tcphdr tcph; 630 631 if (!(flags & DCMD_ADDRSPEC)) 632 return (DCMD_USAGE); 633 634 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 635 mdb_warn("failed to read TCP header at %p", addr); 636 return (DCMD_ERR); 637 } 638 tcphdr_print(&tcph); 639 return (DCMD_OK); 640 } 641 642 static void 643 udphdr_print(struct udphdr *udph) 644 { 645 in_port_t sport, dport; 646 uint16_t hlen; 647 648 mdb_printf("%<b>UDP header%</b>\n"); 649 650 mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport)); 651 mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport)); 652 mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen)); 653 654 mdb_printf("%<u>%14s %14s %5s %6s%</u>\n", 655 "SPORT", "DPORT", "LEN", "CSUM"); 656 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport, 657 dport, dport, hlen, udph->uh_sum); 658 } 659 660 /* ARGSUSED */ 661 static int 662 udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 663 { 664 struct udphdr udph; 665 666 if (!(flags & DCMD_ADDRSPEC)) 667 return (DCMD_USAGE); 668 669 if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 670 mdb_warn("failed to read UDP header at %p", addr); 671 return (DCMD_ERR); 672 } 673 udphdr_print(&udph); 674 return (DCMD_OK); 675 } 676 677 static void 678 sctphdr_print(sctp_hdr_t *sctph) 679 { 680 in_port_t sport, dport; 681 682 mdb_printf("%<b>SCTP header%</b>\n"); 683 mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport)); 684 mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport)); 685 686 mdb_printf("%<u>%14s %14s %10s %10s%</u>\n", 687 "SPORT", "DPORT", "VTAG", "CHKSUM"); 688 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport, 689 dport, dport, sctph->sh_verf, sctph->sh_chksum); 690 } 691 692 /* ARGSUSED */ 693 static int 694 sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 695 { 696 sctp_hdr_t sctph; 697 698 if (!(flags & DCMD_ADDRSPEC)) 699 return (DCMD_USAGE); 700 701 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 702 mdb_warn("failed to read SCTP header at %p", addr); 703 return (DCMD_ERR); 704 } 705 706 sctphdr_print(&sctph); 707 return (DCMD_OK); 708 } 709 710 static int 711 transport_hdr(int proto, uintptr_t addr) 712 { 713 mdb_printf("\n"); 714 switch (proto) { 715 case IPPROTO_TCP: { 716 struct tcphdr tcph; 717 718 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 719 mdb_warn("failed to read TCP header at %p", addr); 720 return (DCMD_ERR); 721 } 722 tcphdr_print(&tcph); 723 break; 724 } 725 case IPPROTO_UDP: { 726 struct udphdr udph; 727 728 if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 729 mdb_warn("failed to read UDP header at %p", addr); 730 return (DCMD_ERR); 731 } 732 udphdr_print(&udph); 733 break; 734 } 735 case IPPROTO_SCTP: { 736 sctp_hdr_t sctph; 737 738 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 739 mdb_warn("failed to read SCTP header at %p", addr); 740 return (DCMD_ERR); 741 } 742 sctphdr_print(&sctph); 743 break; 744 } 745 default: 746 break; 747 } 748 749 return (DCMD_OK); 750 } 751 752 static const mdb_bitmask_t ip_flags[] = { 753 { "DF", IPH_DF, IPH_DF }, 754 { "MF", IPH_MF, IPH_MF }, 755 { NULL, 0, 0 } 756 }; 757 758 /* ARGSUSED */ 759 static int 760 iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 761 { 762 uint_t verbose = FALSE, force = FALSE; 763 ipha_t iph[1]; 764 uint16_t ver, totlen, hdrlen, ipid, off, csum; 765 uintptr_t nxt_proto; 766 char exp_csum[8]; 767 768 if (mdb_getopts(argc, argv, 769 'v', MDB_OPT_SETBITS, TRUE, &verbose, 770 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 771 return (DCMD_USAGE); 772 773 if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 774 mdb_warn("failed to read IPv4 header at %p", addr); 775 return (DCMD_ERR); 776 } 777 778 ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4; 779 if (ver != IPV4_VERSION) { 780 if (ver == IPV6_VERSION) { 781 return (ip6hdr(addr, flags, argc, argv)); 782 } else if (!force) { 783 mdb_warn("unknown IP version: %d\n", ver); 784 return (DCMD_ERR); 785 } 786 } 787 788 mdb_printf("%<b>IPv4 header%</b>\n"); 789 mdb_printf("%-34s %-34s\n" 790 "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n", 791 "SRC", "DST", 792 "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM", 793 "EXP-CSUM", "FLGS"); 794 795 hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2; 796 mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen)); 797 mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid)); 798 mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off)); 799 if (hdrlen == IP_SIMPLE_HDR_LENGTH) { 800 if ((csum = ipcksum(iph, sizeof (*iph))) != 0) 801 csum = ~(~csum + ~iph->ipha_hdr_checksum); 802 else 803 csum = iph->ipha_hdr_checksum; 804 mdb_snprintf(exp_csum, 8, "%u", csum); 805 } else { 806 mdb_snprintf(exp_csum, 8, "<n/a>"); 807 } 808 809 mdb_printf("%-34I %-34I%\n" 810 "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n", 811 iph->ipha_src, iph->ipha_dst, 812 hdrlen, iph->ipha_type_of_service, totlen, ipid, 813 (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol, 814 iph->ipha_hdr_checksum, exp_csum, off, ip_flags); 815 816 if (verbose) { 817 nxt_proto = addr + hdrlen; 818 return (transport_hdr(iph->ipha_protocol, nxt_proto)); 819 } else { 820 return (DCMD_OK); 821 } 822 } 823 824 /* ARGSUSED */ 825 static int 826 ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 827 { 828 uint_t verbose = FALSE, force = FALSE; 829 ip6_t iph[1]; 830 int ver, class, flow; 831 uint16_t plen; 832 uintptr_t nxt_proto; 833 834 if (mdb_getopts(argc, argv, 835 'v', MDB_OPT_SETBITS, TRUE, &verbose, 836 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 837 return (DCMD_USAGE); 838 839 if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 840 mdb_warn("failed to read IPv6 header at %p", addr); 841 return (DCMD_ERR); 842 } 843 844 ver = (iph->ip6_vfc & 0xf0) >> 4; 845 if (ver != IPV6_VERSION) { 846 if (ver == IPV4_VERSION) { 847 return (iphdr(addr, flags, argc, argv)); 848 } else if (!force) { 849 mdb_warn("unknown IP version: %d\n", ver); 850 return (DCMD_ERR); 851 } 852 } 853 854 mdb_printf("%<b>IPv6 header%</b>\n"); 855 mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n", 856 "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP"); 857 858 class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20; 859 mdb_nhconvert(&class, &class, sizeof (class)); 860 flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL; 861 mdb_nhconvert(&flow, &flow, sizeof (flow)); 862 mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen)); 863 864 mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n", 865 &iph->ip6_src, &iph->ip6_dst, 866 class, flow, plen, iph->ip6_nxt, iph->ip6_hlim); 867 868 if (verbose) { 869 nxt_proto = addr + sizeof (ip6_t); 870 return (transport_hdr(iph->ip6_nxt, nxt_proto)); 871 } else { 872 return (DCMD_OK); 873 } 874 } 875 876 int 877 ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 878 { 879 uint_t verbose = FALSE; 880 ire_t ire; 881 882 if (mdb_getopts(argc, argv, 883 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc) 884 return (DCMD_USAGE); 885 886 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 887 888 if (verbose) { 889 mdb_printf("%?s %40s %-20s%\n" 890 "%?s %40s %-20s%\n" 891 "%<u>%?s %40s %4s %-20s%</u>\n", 892 "ADDR", "SRC", "TYPE", 893 "", "DST", "MARKS", 894 "", "STACK", "ZONE", "FLAGS"); 895 } else { 896 mdb_printf("%<u>%?s %30s %30s %5s %4s%</u>\n", 897 "ADDR", "SRC", "DST", "STACK", "ZONE"); 898 } 899 } 900 901 if (flags & DCMD_ADDRSPEC) { 902 (void) mdb_vread(&ire, sizeof (ire_t), addr); 903 (void) ire_format(addr, &ire, &verbose); 904 } else if (mdb_walk("ire", (mdb_walk_cb_t)ire_format, &verbose) == -1) { 905 mdb_warn("failed to walk ire table"); 906 return (DCMD_ERR); 907 } 908 909 return (DCMD_OK); 910 } 911 912 static size_t 913 mi_osize(const queue_t *q) 914 { 915 /* 916 * The code in common/inet/mi.c allocates an extra word to store the 917 * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s. 918 */ 919 struct mi_block { 920 size_t mi_nbytes; 921 struct mi_o_s mi_o; 922 } m; 923 924 if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - 925 sizeof (m)) == sizeof (m)) 926 return (m.mi_nbytes - sizeof (m)); 927 928 return (0); 929 } 930 931 static void 932 ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes) 933 { 934 char name[32]; 935 ill_t ill; 936 937 if (mdb_vread(&ill, sizeof (ill), 938 (uintptr_t)q->q_ptr) == sizeof (ill) && 939 mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0) 940 (void) mdb_snprintf(buf, nbytes, "if: %s", name); 941 } 942 943 void 944 ip_qinfo(const queue_t *q, char *buf, size_t nbytes) 945 { 946 size_t size = mi_osize(q); 947 948 if (size == sizeof (ill_t)) 949 ip_ill_qinfo(q, buf, nbytes); 950 } 951 952 uintptr_t 953 ip_rnext(const queue_t *q) 954 { 955 size_t size = mi_osize(q); 956 ill_t ill; 957 958 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 959 (uintptr_t)q->q_ptr) == sizeof (ill)) 960 return ((uintptr_t)ill.ill_rq); 961 962 return (NULL); 963 } 964 965 uintptr_t 966 ip_wnext(const queue_t *q) 967 { 968 size_t size = mi_osize(q); 969 ill_t ill; 970 971 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 972 (uintptr_t)q->q_ptr) == sizeof (ill)) 973 return ((uintptr_t)ill.ill_wq); 974 975 return (NULL); 976 } 977 978 /* 979 * Print the core fields in an squeue_t. With the "-v" argument, 980 * provide more verbose output. 981 */ 982 static int 983 squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 984 { 985 unsigned int i; 986 unsigned int verbose = FALSE; 987 const int SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9); 988 boolean_t arm; 989 squeue_t squeue; 990 991 if (!(flags & DCMD_ADDRSPEC)) { 992 if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue", 993 argc, argv) == -1) { 994 mdb_warn("failed to walk squeue cache"); 995 return (DCMD_ERR); 996 } 997 return (DCMD_OK); 998 } 999 1000 if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) 1001 != argc) 1002 return (DCMD_USAGE); 1003 1004 if (!DCMD_HDRSPEC(flags) && verbose) 1005 mdb_printf("\n\n"); 1006 1007 if (DCMD_HDRSPEC(flags) || verbose) { 1008 mdb_printf("%?s %-5s %-3s %?s %?s %?s\n", 1009 "ADDR", "STATE", "CPU", 1010 "FIRST", "LAST", "WORKER"); 1011 } 1012 1013 if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) { 1014 mdb_warn("cannot read squeue_t at %p", addr); 1015 return (DCMD_ERR); 1016 } 1017 1018 mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n", 1019 addr, squeue.sq_state, squeue.sq_bind, 1020 squeue.sq_first, squeue.sq_last, squeue.sq_worker); 1021 1022 if (!verbose) 1023 return (DCMD_OK); 1024 1025 arm = B_TRUE; 1026 for (i = 0; squeue_states[i].bit_name != NULL; i++) { 1027 if (((squeue.sq_state) & (1 << i)) == 0) 1028 continue; 1029 1030 if (arm) { 1031 mdb_printf("%*s|\n", SQUEUE_STATEDELT, ""); 1032 mdb_printf("%*s+--> ", SQUEUE_STATEDELT, ""); 1033 arm = B_FALSE; 1034 } else 1035 mdb_printf("%*s ", SQUEUE_STATEDELT, ""); 1036 1037 mdb_printf("%-12s %s\n", squeue_states[i].bit_name, 1038 squeue_states[i].bit_descr); 1039 } 1040 1041 return (DCMD_OK); 1042 } 1043 1044 static void 1045 ip_squeue_help(void) 1046 { 1047 mdb_printf("Print the core information for a given NCA squeue_t.\n\n"); 1048 mdb_printf("Options:\n"); 1049 mdb_printf("\t-v\tbe verbose (more descriptive)\n"); 1050 } 1051 1052 static const mdb_dcmd_t dcmds[] = { 1053 { "illif", "?[-P v4 | v6]", 1054 "display or filter IP Lower Level InterFace structures", illif, 1055 illif_help }, 1056 { "iphdr", ":[-vf]", "display an IPv4 header", iphdr }, 1057 { "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr }, 1058 { "ire", "?[-v]", "display Internet Route Entry structures", ire }, 1059 { "squeue", ":[-v]", "print core squeue_t info", squeue, 1060 ip_squeue_help }, 1061 { "tcphdr", ":", "display a TCP header", tcphdr }, 1062 { "udphdr", ":", "display an UDP header", udphdr }, 1063 { "sctphdr", ":", "display an SCTP header", sctphdr }, 1064 { NULL } 1065 }; 1066 1067 static const mdb_walker_t walkers[] = { 1068 { "illif", "walk list of ill interface types for all stacks", 1069 illif_walk_init, illif_walk_step, NULL }, 1070 { "illif_stack", "walk list of ill interface types", 1071 illif_stack_walk_init, illif_stack_walk_step, 1072 illif_stack_walk_fini }, 1073 { "ire", "walk active ire_t structures", 1074 ire_walk_init, ire_walk_step, NULL }, 1075 { "ire_ctable", "walk ire_t structures in the ctable", 1076 ire_ctable_walk_init, ire_ctable_walk_step, NULL }, 1077 { "ire_next", "walk ire_t structures in the ctable", 1078 ire_next_walk_init, ire_next_walk_step, NULL }, 1079 { "ip_stacks", "walk all the ip_stack_t", 1080 ip_stacks_walk_init, ip_stacks_walk_step, NULL }, 1081 { NULL } 1082 }; 1083 1084 static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext }; 1085 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 1086 1087 const mdb_modinfo_t * 1088 _mdb_init(void) 1089 { 1090 GElf_Sym sym; 1091 1092 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 1093 mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value); 1094 1095 return (&modinfo); 1096 } 1097 1098 void 1099 _mdb_fini(void) 1100 { 1101 GElf_Sym sym; 1102 1103 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 1104 mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value); 1105 } 1106