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 2006 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 int 80 illif_walk_init(mdb_walk_state_t *wsp) 81 { 82 illif_walk_data_t *iw; 83 84 if (wsp->walk_addr != NULL) { 85 mdb_warn("illif supports only global walks\n"); 86 return (WALK_ERR); 87 } 88 89 iw = mdb_alloc(sizeof (illif_walk_data_t), UM_SLEEP); 90 91 if (mdb_readsym(iw->ill_g_heads, MAX_G_HEADS * sizeof (ill_g_head_t), 92 "ill_g_heads") == -1) { 93 mdb_warn("failed to read 'ill_g_heads'"); 94 mdb_free(iw, sizeof (illif_walk_data_t)); 95 return (WALK_ERR); 96 } 97 98 iw->ill_list = 0; 99 wsp->walk_addr = (uintptr_t)iw->IP_VX_ILL_G_LIST(0); 100 wsp->walk_data = iw; 101 102 return (WALK_NEXT); 103 } 104 105 int 106 illif_walk_step(mdb_walk_state_t *wsp) 107 { 108 uintptr_t addr = wsp->walk_addr; 109 illif_walk_data_t *iw = wsp->walk_data; 110 int list = iw->ill_list; 111 112 if (mdb_vread(&iw->ill_if, sizeof (ill_if_t), addr) == -1) { 113 mdb_warn("failed to read ill_if_t at %p", addr); 114 return (WALK_ERR); 115 } 116 117 wsp->walk_addr = (uintptr_t)iw->ill_if.illif_next; 118 119 if (wsp->walk_addr == (uintptr_t)iw->IP_VX_ILL_G_LIST(list)) { 120 121 if (++list >= MAX_G_HEADS) 122 return (WALK_DONE); 123 124 iw->ill_list = list; 125 wsp->walk_addr = (uintptr_t)iw->IP_VX_ILL_G_LIST(list); 126 return (WALK_NEXT); 127 } 128 129 return (wsp->walk_callback(addr, iw, wsp->walk_cbdata)); 130 } 131 132 void 133 illif_walk_fini(mdb_walk_state_t *wsp) 134 { 135 mdb_free(wsp->walk_data, sizeof (illif_walk_data_t)); 136 } 137 138 typedef struct illif_cbdata { 139 uint_t ill_flags; 140 uintptr_t ill_addr; 141 int ill_printlist; /* list to be printed (MAX_G_HEADS for all) */ 142 boolean_t ill_printed; 143 } illif_cbdata_t; 144 145 static int 146 illif_cb(uintptr_t addr, const illif_walk_data_t *iw, illif_cbdata_t *id) 147 { 148 const char *version; 149 150 if (id->ill_printlist < MAX_G_HEADS && 151 id->ill_printlist != iw->ill_list) 152 return (WALK_NEXT); 153 154 if (id->ill_flags & DCMD_ADDRSPEC && id->ill_addr != addr) 155 return (WALK_NEXT); 156 157 if (id->ill_flags & DCMD_PIPE_OUT) { 158 mdb_printf("%p\n", addr); 159 return (WALK_NEXT); 160 } 161 162 switch (iw->ill_list) { 163 case IP_V4_G_HEAD: version = "v4"; break; 164 case IP_V6_G_HEAD: version = "v6"; break; 165 default: version = "??"; break; 166 } 167 168 mdb_printf("%?p %2s %?p %10d %?p %s\n", 169 addr, version, addr + offsetof(ill_if_t, illif_avl_by_ppa), 170 iw->ill_if.illif_avl_by_ppa.avl_numnodes, 171 iw->ill_if.illif_ppa_arena, iw->ill_if.illif_name); 172 173 id->ill_printed = TRUE; 174 175 return (WALK_NEXT); 176 } 177 178 int 179 illif(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 180 { 181 illif_cbdata_t id; 182 ill_if_t ill_if; 183 const char *opt_P = NULL; 184 int printlist = MAX_G_HEADS; 185 186 if (mdb_getopts(argc, argv, 187 'P', MDB_OPT_STR, &opt_P, NULL) != argc) 188 return (DCMD_USAGE); 189 190 if (opt_P != NULL) { 191 if (strcmp("v4", opt_P) == 0) { 192 printlist = IP_V4_G_HEAD; 193 } else if (strcmp("v6", opt_P) == 0) { 194 printlist = IP_V6_G_HEAD; 195 } else { 196 mdb_warn("invalid protocol '%s'\n", opt_P); 197 return (DCMD_USAGE); 198 } 199 } 200 201 if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) { 202 mdb_printf("%<u>%?s %2s %?s %10s %?s %-10s%</u>\n", 203 "ADDR", "IP", "AVLADDR", "NUMNODES", "ARENA", "NAME"); 204 } 205 206 id.ill_flags = flags; 207 id.ill_addr = addr; 208 id.ill_printlist = printlist; 209 id.ill_printed = FALSE; 210 211 if (mdb_walk("illif", (mdb_walk_cb_t)illif_cb, &id) == -1) { 212 mdb_warn("can't walk ill_if_t structures"); 213 return (DCMD_ERR); 214 } 215 216 if (!(flags & DCMD_ADDRSPEC) || opt_P != NULL || id.ill_printed) 217 return (DCMD_OK); 218 219 /* 220 * If an address is specified and the walk doesn't find it, 221 * print it anyway. 222 */ 223 if (mdb_vread(&ill_if, sizeof (ill_if_t), addr) == -1) { 224 mdb_warn("failed to read ill_if_t at %p", addr); 225 return (DCMD_ERR); 226 } 227 228 mdb_printf("%?p %2s %?p %10d %?p %s\n", 229 addr, "??", addr + offsetof(ill_if_t, illif_avl_by_ppa), 230 ill_if.illif_avl_by_ppa.avl_numnodes, 231 ill_if.illif_ppa_arena, ill_if.illif_name); 232 233 return (DCMD_OK); 234 } 235 236 static void 237 illif_help(void) 238 { 239 mdb_printf("Options:\n"); 240 mdb_printf("\t-P v4 | v6" 241 "\tfilter interface structures for the specified protocol\n"); 242 } 243 244 int 245 ire_walk_init(mdb_walk_state_t *wsp) 246 { 247 if (mdb_layered_walk("ire_cache", wsp) == -1) { 248 mdb_warn("can't walk 'ire_cache'"); 249 return (WALK_ERR); 250 } 251 252 return (WALK_NEXT); 253 } 254 255 int 256 ire_walk_step(mdb_walk_state_t *wsp) 257 { 258 ire_t ire; 259 260 if (mdb_vread(&ire, sizeof (ire), wsp->walk_addr) == -1) { 261 mdb_warn("can't read ire at %p", wsp->walk_addr); 262 return (WALK_ERR); 263 } 264 265 return (wsp->walk_callback(wsp->walk_addr, &ire, wsp->walk_cbdata)); 266 } 267 268 static int 269 ire_format(uintptr_t addr, const ire_t *irep, uint_t *verbose) 270 { 271 static const mdb_bitmask_t tmasks[] = { 272 { "BROADCAST", IRE_BROADCAST, IRE_BROADCAST }, 273 { "DEFAULT", IRE_DEFAULT, IRE_DEFAULT }, 274 { "LOCAL", IRE_LOCAL, IRE_LOCAL }, 275 { "LOOPBACK", IRE_LOOPBACK, IRE_LOOPBACK }, 276 { "PREFIX", IRE_PREFIX, IRE_PREFIX }, 277 { "CACHE", IRE_CACHE, IRE_CACHE }, 278 { "IF_NORESOLVER", IRE_IF_NORESOLVER, IRE_IF_NORESOLVER }, 279 { "IF_RESOLVER", IRE_IF_RESOLVER, IRE_IF_RESOLVER }, 280 { "HOST", IRE_HOST, IRE_HOST }, 281 { "HOST_REDIRECT", IRE_HOST_REDIRECT, IRE_HOST_REDIRECT }, 282 { "MIPRTUN", IRE_MIPRTUN, IRE_MIPRTUN }, 283 { NULL, 0, 0 } 284 }; 285 286 static const mdb_bitmask_t mmasks[] = { 287 { "CONDEMNED", IRE_MARK_CONDEMNED, IRE_MARK_CONDEMNED }, 288 { "NORECV", IRE_MARK_NORECV, IRE_MARK_NORECV }, 289 { "HIDDEN", IRE_MARK_HIDDEN, IRE_MARK_HIDDEN }, 290 { "NOADD", IRE_MARK_NOADD, IRE_MARK_NOADD }, 291 { "TEMPORARY", IRE_MARK_TEMPORARY, IRE_MARK_TEMPORARY }, 292 { NULL, 0, 0 } 293 }; 294 295 static const mdb_bitmask_t fmasks[] = { 296 { "UP", RTF_UP, RTF_UP }, 297 { "GATEWAY", RTF_GATEWAY, RTF_GATEWAY }, 298 { "HOST", RTF_HOST, RTF_HOST }, 299 { "REJECT", RTF_REJECT, RTF_REJECT }, 300 { "DYNAMIC", RTF_DYNAMIC, RTF_DYNAMIC }, 301 { "MODIFIED", RTF_MODIFIED, RTF_MODIFIED }, 302 { "DONE", RTF_DONE, RTF_DONE }, 303 { "MASK", RTF_MASK, RTF_MASK }, 304 { "CLONING", RTF_CLONING, RTF_CLONING }, 305 { "XRESOLVE", RTF_XRESOLVE, RTF_XRESOLVE }, 306 { "LLINFO", RTF_LLINFO, RTF_LLINFO }, 307 { "STATIC", RTF_STATIC, RTF_STATIC }, 308 { "BLACKHOLE", RTF_BLACKHOLE, RTF_BLACKHOLE }, 309 { "PRIVATE", RTF_PRIVATE, RTF_PRIVATE }, 310 { "PROTO2", RTF_PROTO2, RTF_PROTO2 }, 311 { "PROTO1", RTF_PROTO1, RTF_PROTO1 }, 312 { "MULTIRT", RTF_MULTIRT, RTF_MULTIRT }, 313 { "SETSRC", RTF_SETSRC, RTF_SETSRC }, 314 { NULL, 0, 0 } 315 }; 316 317 if (irep->ire_ipversion == 6 && *verbose) { 318 319 mdb_printf("%<b>%?p%</b> %40N <%hb>\n" 320 "%?s %40N <%hb>\n" 321 "%?s %40d <%hb>\n", 322 addr, &irep->ire_src_addr_v6, irep->ire_type, tmasks, 323 "", &irep->ire_addr_v6, (ushort_t)irep->ire_marks, mmasks, 324 "", irep->ire_zoneid, irep->ire_flags, fmasks); 325 326 } else if (irep->ire_ipversion == 6) { 327 328 mdb_printf("%?p %30N %30N %4d\n", addr, &irep->ire_src_addr_v6, 329 &irep->ire_addr_v6, irep->ire_zoneid); 330 331 } else if (*verbose) { 332 333 mdb_printf("%<b>%?p%</b> %40I <%hb>\n" 334 "%?s %40I <%hb>\n" 335 "%?s %40d <%hb>\n", 336 addr, irep->ire_src_addr, irep->ire_type, tmasks, 337 "", irep->ire_addr, (ushort_t)irep->ire_marks, mmasks, 338 "", irep->ire_zoneid, irep->ire_flags, fmasks); 339 340 } else { 341 342 mdb_printf("%?p %30I %30I %4d\n", addr, irep->ire_src_addr, 343 irep->ire_addr, irep->ire_zoneid); 344 } 345 346 return (WALK_NEXT); 347 } 348 349 /* 350 * There are faster ways to do this. Given the interactive nature of this 351 * use I don't think its worth much effort. 352 */ 353 static unsigned short 354 ipcksum(void *p, int len) 355 { 356 int32_t sum = 0; 357 358 while (len > 1) { 359 /* alignment */ 360 sum += *(uint16_t *)p; 361 p = (char *)p + sizeof (uint16_t); 362 if (sum & 0x80000000) 363 sum = (sum & 0xFFFF) + (sum >> 16); 364 len -= 2; 365 } 366 367 if (len) 368 sum += (uint16_t)*(unsigned char *)p; 369 370 while (sum >> 16) 371 sum = (sum & 0xFFFF) + (sum >> 16); 372 373 return (~sum); 374 } 375 376 static const mdb_bitmask_t tcp_flags[] = { 377 { "SYN", TH_SYN, TH_SYN }, 378 { "ACK", TH_ACK, TH_ACK }, 379 { "FIN", TH_FIN, TH_FIN }, 380 { "RST", TH_RST, TH_RST }, 381 { "PSH", TH_PUSH, TH_PUSH }, 382 { "ECE", TH_ECE, TH_ECE }, 383 { "CWR", TH_CWR, TH_CWR }, 384 { NULL, 0, 0 } 385 }; 386 387 static void 388 tcphdr_print(struct tcphdr *tcph) 389 { 390 in_port_t sport, dport; 391 tcp_seq seq, ack; 392 uint16_t win, urp; 393 394 mdb_printf("%<b>TCP header%</b>\n"); 395 396 mdb_nhconvert(&sport, &tcph->th_sport, sizeof (sport)); 397 mdb_nhconvert(&dport, &tcph->th_dport, sizeof (dport)); 398 mdb_nhconvert(&seq, &tcph->th_seq, sizeof (seq)); 399 mdb_nhconvert(&ack, &tcph->th_ack, sizeof (ack)); 400 mdb_nhconvert(&win, &tcph->th_win, sizeof (win)); 401 mdb_nhconvert(&urp, &tcph->th_urp, sizeof (urp)); 402 403 mdb_printf("%<u>%6s %6s %10s %10s %4s %5s %5s %5s %-15s%</u>\n", 404 "SPORT", "DPORT", "SEQ", "ACK", "HLEN", "WIN", "CSUM", "URP", 405 "FLAGS"); 406 mdb_printf("%6hu %6hu %10u %10u %4d %5hu %5hu %5hu <%b>\n", 407 sport, dport, seq, ack, tcph->th_off << 2, win, 408 tcph->th_sum, urp, tcph->th_flags, tcp_flags); 409 mdb_printf("0x%04x 0x%04x 0x%08x 0x%08x\n\n", 410 sport, dport, seq, ack); 411 } 412 413 /* ARGSUSED */ 414 static int 415 tcphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 416 { 417 struct tcphdr tcph; 418 419 if (!(flags & DCMD_ADDRSPEC)) 420 return (DCMD_USAGE); 421 422 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 423 mdb_warn("failed to read TCP header at %p", addr); 424 return (DCMD_ERR); 425 } 426 tcphdr_print(&tcph); 427 return (DCMD_OK); 428 } 429 430 static void 431 udphdr_print(struct udphdr *udph) 432 { 433 in_port_t sport, dport; 434 uint16_t hlen; 435 436 mdb_printf("%<b>UDP header%</b>\n"); 437 438 mdb_nhconvert(&sport, &udph->uh_sport, sizeof (sport)); 439 mdb_nhconvert(&dport, &udph->uh_dport, sizeof (dport)); 440 mdb_nhconvert(&hlen, &udph->uh_ulen, sizeof (hlen)); 441 442 mdb_printf("%<u>%14s %14s %5s %6s%</u>\n", 443 "SPORT", "DPORT", "LEN", "CSUM"); 444 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %5hu 0x%04hx\n\n", sport, sport, 445 dport, dport, hlen, udph->uh_sum); 446 } 447 448 /* ARGSUSED */ 449 static int 450 udphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 451 { 452 struct udphdr udph; 453 454 if (!(flags & DCMD_ADDRSPEC)) 455 return (DCMD_USAGE); 456 457 if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 458 mdb_warn("failed to read UDP header at %p", addr); 459 return (DCMD_ERR); 460 } 461 udphdr_print(&udph); 462 return (DCMD_OK); 463 } 464 465 static void 466 sctphdr_print(sctp_hdr_t *sctph) 467 { 468 in_port_t sport, dport; 469 470 mdb_printf("%<b>SCTP header%</b>\n"); 471 mdb_nhconvert(&sport, &sctph->sh_sport, sizeof (sport)); 472 mdb_nhconvert(&dport, &sctph->sh_dport, sizeof (dport)); 473 474 mdb_printf("%<u>%14s %14s %10s %10s%</u>\n", 475 "SPORT", "DPORT", "VTAG", "CHKSUM"); 476 mdb_printf("%5hu (0x%04x) %5hu (0x%04x) %10u 0x%08x\n\n", sport, sport, 477 dport, dport, sctph->sh_verf, sctph->sh_chksum); 478 } 479 480 /* ARGSUSED */ 481 static int 482 sctphdr(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 483 { 484 sctp_hdr_t sctph; 485 486 if (!(flags & DCMD_ADDRSPEC)) 487 return (DCMD_USAGE); 488 489 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 490 mdb_warn("failed to read SCTP header at %p", addr); 491 return (DCMD_ERR); 492 } 493 494 sctphdr_print(&sctph); 495 return (DCMD_OK); 496 } 497 498 static int 499 transport_hdr(int proto, uintptr_t addr) 500 { 501 mdb_printf("\n"); 502 switch (proto) { 503 case IPPROTO_TCP: { 504 struct tcphdr tcph; 505 506 if (mdb_vread(&tcph, sizeof (tcph), addr) == -1) { 507 mdb_warn("failed to read TCP header at %p", addr); 508 return (DCMD_ERR); 509 } 510 tcphdr_print(&tcph); 511 break; 512 } 513 case IPPROTO_UDP: { 514 struct udphdr udph; 515 516 if (mdb_vread(&udph, sizeof (udph), addr) == -1) { 517 mdb_warn("failed to read UDP header at %p", addr); 518 return (DCMD_ERR); 519 } 520 udphdr_print(&udph); 521 break; 522 } 523 case IPPROTO_SCTP: { 524 sctp_hdr_t sctph; 525 526 if (mdb_vread(&sctph, sizeof (sctph), addr) == -1) { 527 mdb_warn("failed to read SCTP header at %p", addr); 528 return (DCMD_ERR); 529 } 530 sctphdr_print(&sctph); 531 break; 532 } 533 default: 534 break; 535 } 536 537 return (DCMD_OK); 538 } 539 540 static const mdb_bitmask_t ip_flags[] = { 541 { "DF", IPH_DF, IPH_DF }, 542 { "MF", IPH_MF, IPH_MF }, 543 { NULL, 0, 0 } 544 }; 545 546 /* ARGSUSED */ 547 static int 548 iphdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 549 { 550 uint_t verbose = FALSE, force = FALSE; 551 ipha_t iph[1]; 552 uint16_t ver, totlen, hdrlen, ipid, off, csum; 553 uintptr_t nxt_proto; 554 char exp_csum[8]; 555 556 if (mdb_getopts(argc, argv, 557 'v', MDB_OPT_SETBITS, TRUE, &verbose, 558 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 559 return (DCMD_USAGE); 560 561 if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 562 mdb_warn("failed to read IPv4 header at %p", addr); 563 return (DCMD_ERR); 564 } 565 566 ver = (iph->ipha_version_and_hdr_length & 0xf0) >> 4; 567 if (ver != IPV4_VERSION) { 568 if (ver == IPV6_VERSION) { 569 return (ip6hdr(addr, flags, argc, argv)); 570 } else if (!force) { 571 mdb_warn("unknown IP version: %d\n", ver); 572 return (DCMD_ERR); 573 } 574 } 575 576 mdb_printf("%<b>IPv4 header%</b>\n"); 577 mdb_printf("%-34s %-34s\n" 578 "%<u>%-4s %-4s %-5s %-5s %-6s %-5s %-5s %-6s %-8s %-6s%</u>\n", 579 "SRC", "DST", 580 "HLEN", "TOS", "LEN", "ID", "OFFSET", "TTL", "PROTO", "CHKSUM", 581 "EXP-CSUM", "FLGS"); 582 583 hdrlen = (iph->ipha_version_and_hdr_length & 0x0f) << 2; 584 mdb_nhconvert(&totlen, &iph->ipha_length, sizeof (totlen)); 585 mdb_nhconvert(&ipid, &iph->ipha_ident, sizeof (ipid)); 586 mdb_nhconvert(&off, &iph->ipha_fragment_offset_and_flags, sizeof (off)); 587 if (hdrlen == IP_SIMPLE_HDR_LENGTH) { 588 if ((csum = ipcksum(iph, sizeof (*iph))) != 0) 589 csum = ~(~csum + ~iph->ipha_hdr_checksum); 590 else 591 csum = iph->ipha_hdr_checksum; 592 mdb_snprintf(exp_csum, 8, "%u", csum); 593 } else { 594 mdb_snprintf(exp_csum, 8, "<n/a>"); 595 } 596 597 mdb_printf("%-34I %-34I%\n" 598 "%-4d %-4d %-5hu %-5hu %-6hu %-5hu %-5hu %-6u %-8s <%5hb>\n", 599 iph->ipha_src, iph->ipha_dst, 600 hdrlen, iph->ipha_type_of_service, totlen, ipid, 601 (off << 3) & 0xffff, iph->ipha_ttl, iph->ipha_protocol, 602 iph->ipha_hdr_checksum, exp_csum, off, ip_flags); 603 604 if (verbose) { 605 nxt_proto = addr + hdrlen; 606 return (transport_hdr(iph->ipha_protocol, nxt_proto)); 607 } else { 608 return (DCMD_OK); 609 } 610 } 611 612 /* ARGSUSED */ 613 static int 614 ip6hdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 615 { 616 uint_t verbose = FALSE, force = FALSE; 617 ip6_t iph[1]; 618 int ver, class, flow; 619 uint16_t plen; 620 uintptr_t nxt_proto; 621 622 if (mdb_getopts(argc, argv, 623 'v', MDB_OPT_SETBITS, TRUE, &verbose, 624 'f', MDB_OPT_SETBITS, TRUE, &force, NULL) != argc) 625 return (DCMD_USAGE); 626 627 if (mdb_vread(iph, sizeof (*iph), addr) == -1) { 628 mdb_warn("failed to read IPv6 header at %p", addr); 629 return (DCMD_ERR); 630 } 631 632 ver = (iph->ip6_vfc & 0xf0) >> 4; 633 if (ver != IPV6_VERSION) { 634 if (ver == IPV4_VERSION) { 635 return (iphdr(addr, flags, argc, argv)); 636 } else if (!force) { 637 mdb_warn("unknown IP version: %d\n", ver); 638 return (DCMD_ERR); 639 } 640 } 641 642 mdb_printf("%<b>IPv6 header%</b>\n"); 643 mdb_printf("%<u>%-26s %-26s %4s %7s %5s %3s %3s%</u>\n", 644 "SRC", "DST", "TCLS", "FLOW-ID", "PLEN", "NXT", "HOP"); 645 646 class = (iph->ip6_vcf & IPV6_FLOWINFO_TCLASS) >> 20; 647 mdb_nhconvert(&class, &class, sizeof (class)); 648 flow = iph->ip6_vcf & IPV6_FLOWINFO_FLOWLABEL; 649 mdb_nhconvert(&flow, &flow, sizeof (flow)); 650 mdb_nhconvert(&plen, &iph->ip6_plen, sizeof (plen)); 651 652 mdb_printf("%-26N %-26N %4d %7d %5hu %3d %3d\n", 653 &iph->ip6_src, &iph->ip6_dst, 654 class, flow, plen, iph->ip6_nxt, iph->ip6_hlim); 655 656 if (verbose) { 657 nxt_proto = addr + sizeof (ip6_t); 658 return (transport_hdr(iph->ip6_nxt, nxt_proto)); 659 } else { 660 return (DCMD_OK); 661 } 662 } 663 664 int 665 ire(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 666 { 667 uint_t verbose = FALSE; 668 ire_t ire; 669 670 if (mdb_getopts(argc, argv, 671 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc) 672 return (DCMD_USAGE); 673 674 if ((flags & DCMD_LOOPFIRST) || !(flags & DCMD_LOOP)) { 675 676 if (verbose) { 677 mdb_printf("%?s %40s %-20s%\n" 678 "%?s %40s %-20s%\n" 679 "%<u>%?s %40s %-20s%</u>\n", 680 "ADDR", "SRC", "TYPE", 681 "", "DST", "MARKS", 682 "", "ZONE", "FLAGS"); 683 } else { 684 mdb_printf("%<u>%?s %30s %30s %4s%</u>\n", 685 "ADDR", "SRC", "DST", "ZONE"); 686 } 687 } 688 689 if (flags & DCMD_ADDRSPEC) { 690 (void) mdb_vread(&ire, sizeof (ire_t), addr); 691 (void) ire_format(addr, &ire, &verbose); 692 } else if (mdb_walk("ire", (mdb_walk_cb_t)ire_format, &verbose) == -1) { 693 mdb_warn("failed to walk ire table"); 694 return (DCMD_ERR); 695 } 696 697 return (DCMD_OK); 698 } 699 700 static size_t 701 mi_osize(const queue_t *q) 702 { 703 /* 704 * The code in common/inet/mi.c allocates an extra word to store the 705 * size of the allocation. An mi_o_s is thus a size_t plus an mi_o_s. 706 */ 707 struct mi_block { 708 size_t mi_nbytes; 709 struct mi_o_s mi_o; 710 } m; 711 712 if (mdb_vread(&m, sizeof (m), (uintptr_t)q->q_ptr - 713 sizeof (m)) == sizeof (m)) 714 return (m.mi_nbytes - sizeof (m)); 715 716 return (0); 717 } 718 719 static void 720 ip_ill_qinfo(const queue_t *q, char *buf, size_t nbytes) 721 { 722 char name[32]; 723 ill_t ill; 724 725 if (mdb_vread(&ill, sizeof (ill), 726 (uintptr_t)q->q_ptr) == sizeof (ill) && 727 mdb_readstr(name, sizeof (name), (uintptr_t)ill.ill_name) > 0) 728 (void) mdb_snprintf(buf, nbytes, "if: %s", name); 729 } 730 731 void 732 ip_qinfo(const queue_t *q, char *buf, size_t nbytes) 733 { 734 size_t size = mi_osize(q); 735 736 if (size == sizeof (ill_t)) 737 ip_ill_qinfo(q, buf, nbytes); 738 } 739 740 uintptr_t 741 ip_rnext(const queue_t *q) 742 { 743 size_t size = mi_osize(q); 744 ill_t ill; 745 746 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 747 (uintptr_t)q->q_ptr) == sizeof (ill)) 748 return ((uintptr_t)ill.ill_rq); 749 750 return (NULL); 751 } 752 753 uintptr_t 754 ip_wnext(const queue_t *q) 755 { 756 size_t size = mi_osize(q); 757 ill_t ill; 758 759 if (size == sizeof (ill_t) && mdb_vread(&ill, sizeof (ill), 760 (uintptr_t)q->q_ptr) == sizeof (ill)) 761 return ((uintptr_t)ill.ill_wq); 762 763 return (NULL); 764 } 765 766 /* 767 * Print the core fields in an squeue_t. With the "-v" argument, 768 * provide more verbose output. 769 */ 770 static int 771 squeue(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 772 { 773 unsigned int i; 774 unsigned int verbose = FALSE; 775 const int SQUEUE_STATEDELT = (int)(sizeof (uintptr_t) + 9); 776 boolean_t arm; 777 squeue_t squeue; 778 779 if (!(flags & DCMD_ADDRSPEC)) { 780 if (mdb_walk_dcmd("genunix`squeue_cache", "ip`squeue", 781 argc, argv) == -1) { 782 mdb_warn("failed to walk squeue cache"); 783 return (DCMD_ERR); 784 } 785 return (DCMD_OK); 786 } 787 788 if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) 789 != argc) 790 return (DCMD_USAGE); 791 792 if (!DCMD_HDRSPEC(flags) && verbose) 793 mdb_printf("\n\n"); 794 795 if (DCMD_HDRSPEC(flags) || verbose) { 796 mdb_printf("%?s %-5s %-3s %?s %?s %?s\n", 797 "ADDR", "STATE", "CPU", 798 "FIRST", "LAST", "WORKER"); 799 } 800 801 if (mdb_vread(&squeue, sizeof (squeue_t), addr) == -1) { 802 mdb_warn("cannot read squeue_t at %p", addr); 803 return (DCMD_ERR); 804 } 805 806 mdb_printf("%0?p %05x %3d %0?p %0?p %0?p\n", 807 addr, squeue.sq_state, squeue.sq_bind, 808 squeue.sq_first, squeue.sq_last, squeue.sq_worker); 809 810 if (!verbose) 811 return (DCMD_OK); 812 813 arm = B_TRUE; 814 for (i = 0; squeue_states[i].bit_name != NULL; i++) { 815 if (((squeue.sq_state) & (1 << i)) == 0) 816 continue; 817 818 if (arm) { 819 mdb_printf("%*s|\n", SQUEUE_STATEDELT, ""); 820 mdb_printf("%*s+--> ", SQUEUE_STATEDELT, ""); 821 arm = B_FALSE; 822 } else 823 mdb_printf("%*s ", SQUEUE_STATEDELT, ""); 824 825 mdb_printf("%-12s %s\n", squeue_states[i].bit_name, 826 squeue_states[i].bit_descr); 827 } 828 829 return (DCMD_OK); 830 } 831 832 static void 833 ip_squeue_help(void) 834 { 835 mdb_printf("Print the core information for a given NCA squeue_t.\n\n"); 836 mdb_printf("Options:\n"); 837 mdb_printf("\t-v\tbe verbose (more descriptive)\n"); 838 } 839 840 static const mdb_dcmd_t dcmds[] = { 841 { "illif", "?[-P v4 | v6]", 842 "display or filter IP Lower Level InterFace structures", illif, 843 illif_help }, 844 { "iphdr", ":[-vf]", "display an IPv4 header", iphdr }, 845 { "ip6hdr", ":[-vf]", "display an IPv6 header", ip6hdr }, 846 { "ire", "?[-v]", "display Internet Route Entry structures", ire }, 847 { "squeue", ":[-v]", "print core squeue_t info", squeue, 848 ip_squeue_help }, 849 { "tcphdr", ":", "display a TCP header", tcphdr }, 850 { "udphdr", ":", "display an UDP header", udphdr }, 851 { "sctphdr", ":", "display an SCTP header", sctphdr }, 852 { NULL } 853 }; 854 855 static const mdb_walker_t walkers[] = { 856 { "illif", "walk list of ill interface types", 857 illif_walk_init, illif_walk_step, illif_walk_fini }, 858 { "ire", "walk active ire_t structures", 859 ire_walk_init, ire_walk_step, NULL }, 860 { NULL } 861 }; 862 863 static const mdb_qops_t ip_qops = { ip_qinfo, ip_rnext, ip_wnext }; 864 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 865 866 const mdb_modinfo_t * 867 _mdb_init(void) 868 { 869 GElf_Sym sym; 870 871 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 872 mdb_qops_install(&ip_qops, (uintptr_t)sym.st_value); 873 874 return (&modinfo); 875 } 876 877 void 878 _mdb_fini(void) 879 { 880 GElf_Sym sym; 881 882 if (mdb_lookup_by_obj("ip", "ipwinit", &sym) == 0) 883 mdb_qops_remove(&ip_qops, (uintptr_t)sym.st_value); 884 } 885