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