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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/mdb_modapi.h> 27 #include <sys/types.h> 28 #include <inet/ip.h> 29 #include <inet/ip6.h> 30 31 #include <sys/mac.h> 32 #include <sys/mac_provider.h> 33 #include <sys/mac_client.h> 34 #include <sys/mac_client_impl.h> 35 #include <sys/mac_flow_impl.h> 36 #include <sys/mac_soft_ring.h> 37 38 #define STRSIZE 64 39 #define MAC_RX_SRS_SIZE (MAX_RINGS_PER_GROUP * sizeof (uintptr_t)) 40 41 #define LAYERED_WALKER_FOR_FLOW "flow_entry_cache" 42 #define LAYERED_WALKER_FOR_SRS "mac_srs_cache" 43 #define LAYERED_WALKER_FOR_RING "mac_ring_cache" 44 45 /* arguments passed to mac_flow dee-command */ 46 #define MAC_FLOW_NONE 0x01 47 #define MAC_FLOW_ATTR 0x02 48 #define MAC_FLOW_PROP 0x04 49 #define MAC_FLOW_RX 0x08 50 #define MAC_FLOW_TX 0x10 51 #define MAC_FLOW_USER 0x20 52 #define MAC_FLOW_STATS 0x40 53 #define MAC_FLOW_MISC 0x80 54 55 /* arguments passed to mac_srs dee-command */ 56 #define MAC_SRS_NONE 0x00 57 #define MAC_SRS_RX 0x01 58 #define MAC_SRS_TX 0x02 59 #define MAC_SRS_STAT 0x04 60 #define MAC_SRS_CPU 0x08 61 #define MAC_SRS_VERBOSE 0x10 62 #define MAC_SRS_RXSTAT (MAC_SRS_RX|MAC_SRS_STAT) 63 #define MAC_SRS_TXSTAT (MAC_SRS_TX|MAC_SRS_STAT) 64 #define MAC_SRS_RXCPU (MAC_SRS_RX|MAC_SRS_CPU) 65 #define MAC_SRS_TXCPU (MAC_SRS_TX|MAC_SRS_CPU) 66 #define MAC_SRS_RXCPUVERBOSE (MAC_SRS_RXCPU|MAC_SRS_VERBOSE) 67 #define MAC_SRS_TXCPUVERBOSE (MAC_SRS_TXCPU|MAC_SRS_VERBOSE) 68 69 static char * 70 mac_flow_proto2str(uint8_t protocol) 71 { 72 switch (protocol) { 73 case IPPROTO_TCP: 74 return ("tcp"); 75 case IPPROTO_UDP: 76 return ("udp"); 77 case IPPROTO_SCTP: 78 return ("sctp"); 79 case IPPROTO_ICMP: 80 return ("icmp"); 81 case IPPROTO_ICMPV6: 82 return ("icmpv6"); 83 default: 84 return ("--"); 85 } 86 } 87 88 static char * 89 mac_flow_priority2str(mac_priority_level_t prio) 90 { 91 switch (prio) { 92 case MPL_LOW: 93 return ("low"); 94 case MPL_MEDIUM: 95 return ("medium"); 96 case MPL_HIGH: 97 return ("high"); 98 case MPL_RESET: 99 return ("reset"); 100 default: 101 return ("--"); 102 } 103 } 104 105 /* 106 * Convert bandwidth in bps to a string in mpbs. 107 */ 108 static char * 109 mac_flow_bw2str(uint64_t bw, char *buf, ssize_t len) 110 { 111 int kbps, mbps; 112 113 kbps = (bw % 1000000)/1000; 114 mbps = bw/1000000; 115 if ((mbps == 0) && (kbps != 0)) 116 mdb_snprintf(buf, len, "0.%03u", kbps); 117 else 118 mdb_snprintf(buf, len, "%5u", mbps); 119 return (buf); 120 } 121 122 static void 123 mac_flow_print_header(uint_t args) 124 { 125 switch (args) { 126 case MAC_FLOW_NONE: 127 mdb_printf("%?s %-20s %4s %?s %?s %-16s\n", 128 "", "", "LINK", "", "", "MIP"); 129 mdb_printf("%<u>%?s %-20s %4s %?s %?s %-16s%</u>\n", 130 "ADDR", "FLOW NAME", "ID", "MCIP", "MIP", "NAME"); 131 break; 132 case MAC_FLOW_ATTR: 133 mdb_printf("%<u>%?s %-32s %-7s %6s " 134 "%-9s %s%</u>\n", 135 "ADDR", "FLOW NAME", "PROTO", "PORT", 136 "DSFLD:MSK", "IPADDR"); 137 break; 138 case MAC_FLOW_PROP: 139 mdb_printf("%<u>%?s %-32s %8s %9s%</u>\n", 140 "ADDR", "FLOW NAME", "MAXBW(M)", "PRIORITY"); 141 break; 142 case MAC_FLOW_MISC: 143 mdb_printf("%<u>%?s %-24s %10s %10s " 144 "%20s %4s%</u>\n", 145 "ADDR", "FLOW NAME", "TYPE", "FLAGS", 146 "MATCH_FN", "ZONE"); 147 break; 148 case MAC_FLOW_RX: 149 mdb_printf("%?s %-24s %3s %s\n", "", "", "SRS", "RX"); 150 mdb_printf("%<u>%?s %-24s %3s %s%</u>\n", 151 "ADDR", "FLOW NAME", "CNT", "SRS"); 152 break; 153 case MAC_FLOW_TX: 154 mdb_printf("%<u>%?s %-32s %?s %</u>\n", 155 "ADDR", "FLOW NAME", "TX_SRS"); 156 break; 157 case MAC_FLOW_STATS: 158 mdb_printf("%<u>%?s %-32s %16s %16s%</u>\n", 159 "ADDR", "FLOW NAME", "RBYTES", "OBYTES"); 160 break; 161 } 162 } 163 164 /* 165 * Display selected fields of the flow_entry_t structure 166 */ 167 static int 168 mac_flow_dcmd_output(uintptr_t addr, uint_t flags, uint_t args) 169 { 170 static const mdb_bitmask_t flow_type_bits[] = { 171 {"P", FLOW_PRIMARY_MAC, FLOW_PRIMARY_MAC}, 172 {"V", FLOW_VNIC_MAC, FLOW_VNIC_MAC}, 173 {"M", FLOW_MCAST, FLOW_MCAST}, 174 {"O", FLOW_OTHER, FLOW_OTHER}, 175 {"U", FLOW_USER, FLOW_USER}, 176 {"V", FLOW_VNIC, FLOW_VNIC}, 177 {"NS", FLOW_NO_STATS, FLOW_NO_STATS}, 178 { NULL, 0, 0 } 179 }; 180 #define FLOW_MAX_TYPE (sizeof (flow_type_bits) / sizeof (mdb_bitmask_t)) 181 182 static const mdb_bitmask_t flow_flag_bits[] = { 183 {"Q", FE_QUIESCE, FE_QUIESCE}, 184 {"W", FE_WAITER, FE_WAITER}, 185 {"T", FE_FLOW_TAB, FE_FLOW_TAB}, 186 {"G", FE_G_FLOW_HASH, FE_G_FLOW_HASH}, 187 {"I", FE_INCIPIENT, FE_INCIPIENT}, 188 {"C", FE_CONDEMNED, FE_CONDEMNED}, 189 {"NU", FE_UF_NO_DATAPATH, FE_UF_NO_DATAPATH}, 190 {"NC", FE_MC_NO_DATAPATH, FE_MC_NO_DATAPATH}, 191 { NULL, 0, 0 } 192 }; 193 #define FLOW_MAX_FLAGS (sizeof (flow_flag_bits) / sizeof (mdb_bitmask_t)) 194 flow_entry_t fe; 195 mac_client_impl_t mcip; 196 mac_impl_t mip; 197 198 if (mdb_vread(&fe, sizeof (fe), addr) == -1) { 199 mdb_warn("failed to read struct flow_entry_s at %p", addr); 200 return (DCMD_ERR); 201 } 202 if (args & MAC_FLOW_USER) { 203 args &= ~MAC_FLOW_USER; 204 if (fe.fe_type & FLOW_MCAST) { 205 if (DCMD_HDRSPEC(flags)) 206 mac_flow_print_header(args); 207 return (DCMD_OK); 208 } 209 } 210 if (DCMD_HDRSPEC(flags)) 211 mac_flow_print_header(args); 212 bzero(&mcip, sizeof (mcip)); 213 bzero(&mip, sizeof (mip)); 214 if (fe.fe_mcip != NULL && mdb_vread(&mcip, sizeof (mcip), 215 (uintptr_t)fe.fe_mcip) == sizeof (mcip)) { 216 (void) mdb_vread(&mip, sizeof (mip), (uintptr_t)mcip.mci_mip); 217 } 218 switch (args) { 219 case MAC_FLOW_NONE: { 220 mdb_printf("%?p %-20s %4d %?p " 221 "%?p %-16s\n", 222 addr, fe.fe_flow_name, fe.fe_link_id, fe.fe_mcip, 223 mcip.mci_mip, mip.mi_name); 224 break; 225 } 226 case MAC_FLOW_ATTR: { 227 struct in_addr in4; 228 uintptr_t desc_addr; 229 flow_desc_t fdesc; 230 231 desc_addr = addr + OFFSETOF(flow_entry_t, fe_flow_desc); 232 if (mdb_vread(&fdesc, sizeof (fdesc), desc_addr) == -1) { 233 mdb_warn("failed to read struct flow_description at %p", 234 desc_addr); 235 return (DCMD_ERR); 236 } 237 mdb_printf("%?p %-32s " 238 "%-7s %6d " 239 "%4d:%-4d ", 240 addr, fe.fe_flow_name, 241 mac_flow_proto2str(fdesc.fd_protocol), fdesc.fd_local_port, 242 fdesc.fd_dsfield, fdesc.fd_dsfield_mask); 243 if (fdesc.fd_ipversion == IPV4_VERSION) { 244 IN6_V4MAPPED_TO_INADDR(&fdesc.fd_local_addr, &in4); 245 mdb_printf("%I", in4.s_addr); 246 } else if (fdesc.fd_ipversion == IPV6_VERSION) { 247 mdb_printf("%N", &fdesc.fd_local_addr); 248 } else { 249 mdb_printf("%s", "--"); 250 } 251 mdb_printf("\n"); 252 break; 253 } 254 case MAC_FLOW_PROP: { 255 uintptr_t prop_addr; 256 char bwstr[STRSIZE]; 257 mac_resource_props_t fprop; 258 259 prop_addr = addr + OFFSETOF(flow_entry_t, fe_resource_props); 260 if (mdb_vread(&fprop, sizeof (fprop), prop_addr) == -1) { 261 mdb_warn("failed to read struct mac_resoource_props " 262 "at %p", prop_addr); 263 return (DCMD_ERR); 264 } 265 mdb_printf("%?p %-32s " 266 "%8s %9s\n", 267 addr, fe.fe_flow_name, 268 mac_flow_bw2str(fprop.mrp_maxbw, bwstr, STRSIZE), 269 mac_flow_priority2str(fprop.mrp_priority)); 270 break; 271 } 272 case MAC_FLOW_MISC: { 273 char flow_flags[2 * FLOW_MAX_FLAGS]; 274 char flow_type[2 * FLOW_MAX_TYPE]; 275 GElf_Sym sym; 276 char func_name[MDB_SYM_NAMLEN] = ""; 277 uintptr_t func, match_addr; 278 279 match_addr = addr + OFFSETOF(flow_entry_t, fe_match); 280 (void) mdb_vread(&func, sizeof (func), match_addr); 281 (void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name, 282 MDB_SYM_NAMLEN, &sym); 283 mdb_snprintf(flow_flags, 2 * FLOW_MAX_FLAGS, "%hb", 284 fe.fe_flags, flow_flag_bits); 285 mdb_snprintf(flow_type, 2 * FLOW_MAX_TYPE, "%hb", 286 fe.fe_type, flow_type_bits); 287 mdb_printf("%?p %-24s %10s %10s " 288 "%20s %4d\n", 289 addr, fe.fe_flow_name, flow_type, flow_flags, 290 func_name, fe.fe_zoneid); 291 break; 292 } 293 case MAC_FLOW_RX: { 294 uintptr_t rxaddr, rx_srs[MAX_RINGS_PER_GROUP] = {0}; 295 int i; 296 297 rxaddr = addr + OFFSETOF(flow_entry_t, fe_rx_srs); 298 (void) mdb_vread(rx_srs, MAC_RX_SRS_SIZE, rxaddr); 299 mdb_printf("%?p %-24s %3d ", 300 addr, fe.fe_flow_name, fe.fe_rx_srs_cnt); 301 for (i = 0; i < MAX_RINGS_PER_GROUP; i++) { 302 if (rx_srs[i] == 0) 303 continue; 304 mdb_printf("%p ", rx_srs[i]); 305 } 306 mdb_printf("\n"); 307 break; 308 } 309 case MAC_FLOW_TX: { 310 uintptr_t tx_srs = 0, txaddr; 311 312 txaddr = addr + OFFSETOF(flow_entry_t, fe_tx_srs); 313 (void) mdb_vread(&tx_srs, sizeof (uintptr_t), txaddr); 314 mdb_printf("%?p %-32s %?p\n", 315 addr, fe.fe_flow_name, fe.fe_tx_srs); 316 break; 317 } 318 case MAC_FLOW_STATS: { 319 mdb_printf("%?p %-32s %16llu %16llu\n", 320 addr, fe.fe_flow_name, fe.fe_flowstats.fs_rbytes, 321 fe.fe_flowstats.fs_obytes); 322 break; 323 } 324 } 325 return (DCMD_OK); 326 } 327 328 /* 329 * Parse the arguments passed to the dcmd and print all or one flow_entry_t 330 * structures 331 */ 332 static int 333 mac_flow_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 334 { 335 uint_t args = 0; 336 337 if (!(flags & DCMD_ADDRSPEC)) { 338 if (mdb_walk_dcmd("mac_flow", "mac_flow", argc, argv) == -1) { 339 mdb_warn("failed to walk 'mac_flow'"); 340 return (DCMD_ERR); 341 } 342 return (DCMD_OK); 343 } 344 if ((mdb_getopts(argc, argv, 345 'a', MDB_OPT_SETBITS, MAC_FLOW_ATTR, &args, 346 'p', MDB_OPT_SETBITS, MAC_FLOW_PROP, &args, 347 'm', MDB_OPT_SETBITS, MAC_FLOW_MISC, &args, 348 'r', MDB_OPT_SETBITS, MAC_FLOW_RX, &args, 349 't', MDB_OPT_SETBITS, MAC_FLOW_TX, &args, 350 's', MDB_OPT_SETBITS, MAC_FLOW_STATS, &args, 351 'u', MDB_OPT_SETBITS, MAC_FLOW_USER, &args) != argc)) { 352 return (DCMD_USAGE); 353 } 354 if (argc > 2 || (argc == 2 && !(args & MAC_FLOW_USER))) 355 return (DCMD_USAGE); 356 /* 357 * If no arguments was specified or just "-u" was specified then 358 * we default to printing basic information of flows. 359 */ 360 if (args == 0 || args == MAC_FLOW_USER) 361 args |= MAC_FLOW_NONE; 362 363 return (mac_flow_dcmd_output(addr, flags, args)); 364 } 365 366 static void 367 mac_flow_help(void) 368 { 369 mdb_printf("If an address is specified, then flow_entry structure at " 370 "that address is printed. Otherwise all the flows in the system " 371 "are printed.\n"); 372 mdb_printf("Options:\n" 373 "\t-u\tdisplay user defined link & vnic flows.\n" 374 "\t-a\tdisplay flow attributes\n" 375 "\t-p\tdisplay flow properties\n" 376 "\t-r\tdisplay rx side information\n" 377 "\t-t\tdisplay tx side information\n" 378 "\t-s\tdisplay flow statistics\n" 379 "\t-m\tdisplay miscellaneous flow information\n\n"); 380 mdb_printf("%<u>Interpreting Flow type and Flow flags output.%</u>\n"); 381 mdb_printf("Flow Types:\n"); 382 mdb_printf("\t P --> FLOW_PRIMARY_MAC\n"); 383 mdb_printf("\t V --> FLOW_VNIC_MAC\n"); 384 mdb_printf("\t M --> FLOW_MCAST\n"); 385 mdb_printf("\t O --> FLOW_OTHER\n"); 386 mdb_printf("\t U --> FLOW_USER\n"); 387 mdb_printf("\t NS --> FLOW_NO_STATS\n\n"); 388 mdb_printf("Flow Flags:\n"); 389 mdb_printf("\t Q --> FE_QUIESCE\n"); 390 mdb_printf("\t W --> FE_WAITER\n"); 391 mdb_printf("\t T --> FE_FLOW_TAB\n"); 392 mdb_printf("\t G --> FE_G_FLOW_HASH\n"); 393 mdb_printf("\t I --> FE_INCIPIENT\n"); 394 mdb_printf("\t C --> FE_CONDEMNED\n"); 395 mdb_printf("\t NU --> FE_UF_NO_DATAPATH\n"); 396 mdb_printf("\t NC --> FE_MC_NO_DATAPATH\n"); 397 } 398 399 /* 400 * called once by the debugger when the mac_flow walk begins. 401 */ 402 static int 403 mac_flow_walk_init(mdb_walk_state_t *wsp) 404 { 405 if (mdb_layered_walk(LAYERED_WALKER_FOR_FLOW, wsp) == -1) { 406 mdb_warn("failed to walk 'mac_flow'"); 407 return (WALK_ERR); 408 } 409 return (WALK_NEXT); 410 } 411 412 /* 413 * Common walker step funciton for flow_entry_t, mac_soft_ring_set_t and 414 * mac_ring_t. 415 * 416 * Steps through each flow_entry_t and calls the callback function. If the 417 * user executed ::walk mac_flow, it just prints the address or if the user 418 * executed ::mac_flow it displays selected fields of flow_entry_t structure 419 * by calling "mac_flow_dcmd" 420 */ 421 static int 422 mac_common_walk_step(mdb_walk_state_t *wsp) 423 { 424 int status; 425 426 if (wsp->walk_addr == NULL) 427 return (WALK_DONE); 428 429 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 430 wsp->walk_cbdata); 431 432 return (status); 433 } 434 435 static char * 436 mac_srs_txmode2str(mac_tx_srs_mode_t mode) 437 { 438 switch (mode) { 439 case SRS_TX_DEFAULT: 440 return ("DEF"); 441 case SRS_TX_SERIALIZE: 442 return ("SER"); 443 case SRS_TX_FANOUT: 444 return ("FO"); 445 case SRS_TX_BW: 446 return ("BW"); 447 case SRS_TX_BW_FANOUT: 448 return ("BWFO"); 449 } 450 return ("--"); 451 } 452 453 static void 454 mac_srs_help(void) 455 { 456 mdb_printf("If an address is specified, then mac_soft_ring_set " 457 "structure at that address is printed. Otherwise all the " 458 "SRS in the system are printed.\n"); 459 mdb_printf("Options:\n" 460 "\t-r\tdisplay recieve side SRS structures\n" 461 "\t-t\tdisplay transmit side SRS structures\n" 462 "\t-s\tdisplay statistics for RX or TX side\n" 463 "\t-c\tdisplay CPU binding for RX or TX side\n" 464 "\t-v\tverbose flag for CPU binding to list cpus\n" 465 "Note: use -r or -t (to specify RX or TX side respectively) along " 466 "with -c or -s\n"); 467 mdb_printf("\n%<u>Interpreting TX Modes%</u>\n"); 468 mdb_printf("\t DEF --> Default\n"); 469 mdb_printf("\t SER --> Serialize\n"); 470 mdb_printf("\t FO --> Fanout\n"); 471 mdb_printf("\t BW --> Bandwidth\n"); 472 mdb_printf("\tBWFO --> Bandwidth Fanout\n"); 473 } 474 475 /* 476 * In verbose mode "::mac_srs -rcv or ::mac_srs -tcv", we print the CPUs 477 * assigned to a link and CPUS assigned to the soft rings. 478 * 'len' is used for formatting the output and represents the number of 479 * spaces between CPU list and Fanout CPU list in the output. 480 */ 481 static boolean_t 482 mac_srs_print_cpu(int *i, uint32_t cnt, uint32_t *cpu_list, int *len) 483 { 484 int num = 0; 485 486 if (*i == 0) 487 mdb_printf("("); 488 else 489 mdb_printf(" "); 490 while (*i < cnt) { 491 /* We print 6 CPU's at a time to keep display within 80 cols */ 492 if (((num + 1) % 7) == 0) { 493 if (len != NULL) 494 *len = 2; 495 return (B_FALSE); 496 } 497 mdb_printf("%02x%c", cpu_list[*i], ((*i == cnt - 1)?')':',')); 498 ++*i; 499 ++num; 500 } 501 if (len != NULL) 502 *len = (7 - num) * 3; 503 return (B_TRUE); 504 } 505 506 static int 507 mac_srs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 508 { 509 uint_t args = MAC_SRS_NONE; 510 mac_soft_ring_set_t srs; 511 mac_client_impl_t mci; 512 513 if (!(flags & DCMD_ADDRSPEC)) { 514 if (mdb_walk_dcmd("mac_srs", "mac_srs", argc, argv) == -1) { 515 mdb_warn("failed to walk 'mac_srs'"); 516 return (DCMD_ERR); 517 } 518 return (DCMD_OK); 519 } 520 if (mdb_getopts(argc, argv, 521 'r', MDB_OPT_SETBITS, MAC_SRS_RX, &args, 522 't', MDB_OPT_SETBITS, MAC_SRS_TX, &args, 523 'c', MDB_OPT_SETBITS, MAC_SRS_CPU, &args, 524 'v', MDB_OPT_SETBITS, MAC_SRS_VERBOSE, &args, 525 's', MDB_OPT_SETBITS, MAC_SRS_STAT, &args) != argc) { 526 return (DCMD_USAGE); 527 } 528 529 if (argc > 2) 530 return (DCMD_USAGE); 531 532 if (mdb_vread(&srs, sizeof (srs), addr) == -1) { 533 mdb_warn("failed to read struct mac_soft_ring_set_s at %p", 534 addr); 535 return (DCMD_ERR); 536 } 537 if (mdb_vread(&mci, sizeof (mci), (uintptr_t)srs.srs_mcip) == -1) { 538 mdb_warn("failed to read struct mac_client_impl_t at %p " 539 "for SRS %p", srs.srs_mcip, addr); 540 return (DCMD_ERR); 541 } 542 543 switch (args) { 544 case MAC_SRS_RX: { 545 if (DCMD_HDRSPEC(flags)) { 546 mdb_printf("%?s %-20s %-8s %-8s %8s " 547 "%8s %3s\n", 548 "", "", "", "", "MBLK", 549 "Q", "SR"); 550 mdb_printf("%<u>%?s %-20s %-8s %-8s %8s " 551 "%8s %3s%</u>\n", 552 "ADDR", "LINK_NAME", "STATE", "TYPE", "CNT", 553 "BYTES", "CNT"); 554 } 555 if (srs.srs_type & SRST_TX) 556 return (DCMD_OK); 557 mdb_printf("%?p %-20s %08x %08x " 558 "%8d %8d %3d\n", 559 addr, mci.mci_name, srs.srs_state, srs.srs_type, 560 srs.srs_count, srs.srs_size, srs.srs_soft_ring_count); 561 break; 562 } 563 case MAC_SRS_TX: { 564 if (DCMD_HDRSPEC(flags)) { 565 mdb_printf("%?s %-16s %-4s %-8s " 566 "%-8s %8s %8s %3s\n", 567 "", "", "TX", "", 568 "", "MBLK", "Q", "SR"); 569 mdb_printf("%<u>%?s %-16s %-4s %-8s " 570 "%-8s %8s %8s %3s%</u>\n", 571 "ADDR", "LINK_NAME", "MODE", "STATE", 572 "TYPE", "CNT", "BYTES", "CNT"); 573 } 574 if (!(srs.srs_type & SRST_TX)) 575 return (DCMD_OK); 576 577 mdb_printf("%?p %-16s %-4s " 578 "%08x %08x %8d %8d %3d\n", 579 addr, mci.mci_name, mac_srs_txmode2str(srs.srs_tx.st_mode), 580 srs.srs_state, srs.srs_type, srs.srs_count, srs.srs_size, 581 srs.srs_oth_ring_count); 582 break; 583 } 584 case MAC_SRS_RXCPU: { 585 mac_cpus_t mc = srs.srs_cpu; 586 587 if (DCMD_HDRSPEC(flags)) { 588 mdb_printf("%?s %-20s %-4s %-4s " 589 "%-6s %-4s %-7s\n", 590 "", "", "NUM", "POLL", 591 "WORKER", "INTR", "FANOUT"); 592 mdb_printf("%<u>%?s %-20s %-4s %-4s " 593 "%-6s %-4s %-7s%</u>\n", 594 "ADDR", "LINK_NAME", "CPUS", "CPU", 595 "CPU", "CPU", "CPU_CNT"); 596 } 597 if ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX)) 598 return (DCMD_OK); 599 mdb_printf("%?p %-20s %-4d %-4d " 600 "%-6d %-4d %-7d\n", 601 addr, mci.mci_name, mc.mc_ncpus, mc.mc_pollid, 602 mc.mc_workerid, mc.mc_intr_cpu, mc.mc_fanout_cnt); 603 break; 604 605 } 606 case MAC_SRS_TXCPU: { 607 mac_cpus_t mc = srs.srs_cpu; 608 609 if (DCMD_HDRSPEC(flags)) { 610 mdb_printf("%?s %-20s %-4s %-6s " 611 "%-4s %-7s\n", 612 "", "", "NUM", "WORKER", 613 "INTR", "FANOUT"); 614 mdb_printf("%<u>%?s %-20s %-4s %-6s " 615 "%-4s %-7s%</u>\n", 616 "ADDR", "LINK_NAME", "CPUS", "CPU", 617 "CPU", "CPU_CNT"); 618 } 619 if ((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX)) 620 return (DCMD_OK); 621 mdb_printf("%?p %-20s %-4d " 622 "%-6d %-4d %-7d\n", 623 addr, mci.mci_name, mc.mc_ncpus, 624 mc.mc_workerid, mc.mc_intr_cpu, mc.mc_fanout_cnt); 625 break; 626 } 627 case MAC_SRS_RXCPUVERBOSE: 628 case MAC_SRS_TXCPUVERBOSE: { 629 mac_cpus_t mc = srs.srs_cpu; 630 int cpu_index = 0, fanout_index = 0, len = 0; 631 boolean_t cpu_done = B_FALSE, fanout_done = B_FALSE; 632 633 if (DCMD_HDRSPEC(flags)) { 634 mdb_printf("%?s %-20s %-20s %-20s\n", 635 "", "", "CPU_COUNT", "FANOUT_CPU_COUNT"); 636 mdb_printf("%<u>%?s %-20s " 637 "%-20s %-20s%</u>\n", 638 "ADDR", "LINK_NAME", 639 "(CPU_LIST)", "(CPU_LIST)"); 640 } 641 if (((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX)) || 642 ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX))) 643 return (DCMD_OK); 644 mdb_printf("%?p %-20s %-20d %-20d\n", addr, mci.mci_name, 645 mc.mc_ncpus, mc.mc_fanout_cnt); 646 if (mc.mc_ncpus == 0 && mc.mc_fanout_cnt == 0) 647 break; 648 /* print all cpus and cpus for soft rings */ 649 while (!cpu_done || !fanout_done) { 650 boolean_t old_value = cpu_done; 651 652 if (!cpu_done) { 653 mdb_printf("%?s %20s ", "", ""); 654 cpu_done = mac_srs_print_cpu(&cpu_index, 655 mc.mc_ncpus, mc.mc_cpus, &len); 656 } 657 if (!fanout_done) { 658 if (old_value) 659 mdb_printf("%?s %-40s", "", ""); 660 else 661 mdb_printf("%*s", len, ""); 662 fanout_done = mac_srs_print_cpu(&fanout_index, 663 mc.mc_fanout_cnt, mc.mc_fanout_cpus, NULL); 664 } 665 mdb_printf("\n"); 666 } 667 break; 668 } 669 case MAC_SRS_RXSTAT: { 670 mac_srs_rx_t srs_rx = srs.srs_rx; 671 672 if (DCMD_HDRSPEC(flags)) { 673 mdb_printf("%?s %-16s %8s %8s " 674 "%8s %8s %8s\n", 675 "", "", "INTR", "POLL", 676 "CHAIN", "CHAIN", "CHAIN"); 677 mdb_printf("%<u>%?s %-16s %8s %8s " 678 "%8s %8s %8s%</u>\n", 679 "ADDR", "LINK_NAME", "COUNT", "COUNT", 680 "<10", "10-50", ">50"); 681 } 682 if (srs.srs_type & SRST_TX) 683 return (DCMD_OK); 684 mdb_printf("%?p %-16s %8d " 685 "%8d %8d " 686 "%8d %8d\n", 687 addr, mci.mci_name, srs_rx.sr_intr_count, 688 srs_rx.sr_poll_count, srs_rx.sr_chain_cnt_undr10, 689 srs_rx.sr_chain_cnt_10to50, srs_rx.sr_chain_cnt_over50); 690 break; 691 } 692 case MAC_SRS_TXSTAT: { 693 mac_srs_tx_t srs_tx = srs.srs_tx; 694 mac_soft_ring_t *s_ringp, s_ring; 695 boolean_t first = B_TRUE; 696 697 if (DCMD_HDRSPEC(flags)) { 698 mdb_printf("%?s %-20s %?s %8s %8s %8s\n", 699 "", "", "SOFT", "DROP", "BLOCK", "UNBLOCK"); 700 mdb_printf("%<u>%?s %-20s %?s %8s %8s %8s%</u>\n", 701 "ADDR", "LINK_NAME", "RING", "COUNT", "COUNT", 702 "COUNT"); 703 } 704 if (!(srs.srs_type & SRST_TX)) 705 return (DCMD_OK); 706 707 mdb_printf("%?p %-20s ", addr, mci.mci_name); 708 709 /* 710 * Case of no soft rings, print the info from 711 * mac_srs_tx_t. 712 */ 713 if (srs.srs_oth_ring_count == 0) { 714 mdb_printf("%?p %8d %8d %8d\n", 715 0, srs_tx.st_drop_count, srs_tx.st_blocked_cnt, 716 srs_tx.st_unblocked_cnt); 717 break; 718 } 719 720 for (s_ringp = srs.srs_soft_ring_head; s_ringp != NULL; 721 s_ringp = s_ring.s_ring_next) { 722 (void) mdb_vread(&s_ring, sizeof (s_ring), 723 (uintptr_t)s_ringp); 724 if (first) { 725 mdb_printf("%?p %8d %8d %8d\n", 726 s_ringp, s_ring.s_ring_drops, 727 s_ring.s_ring_blocked_cnt, 728 s_ring.s_ring_unblocked_cnt); 729 first = B_FALSE; 730 continue; 731 } 732 mdb_printf("%?s %-20s %?p %8d %8d %8d\n", 733 "", "", s_ringp, s_ring.s_ring_drops, 734 s_ring.s_ring_blocked_cnt, 735 s_ring.s_ring_unblocked_cnt); 736 } 737 break; 738 } 739 case MAC_SRS_NONE: { 740 if (DCMD_HDRSPEC(flags)) { 741 mdb_printf("%<u>%?s %-20s %?s %?s %-3s%</u>\n", 742 "ADDR", "LINK_NAME", "FLENT", "HW RING", "DIR"); 743 } 744 mdb_printf("%?p %-20s %?p %?p " 745 "%-3s ", 746 addr, mci.mci_name, srs.srs_flent, srs.srs_ring, 747 (srs.srs_type & SRST_TX ? "TX" : "RX")); 748 break; 749 } 750 default: 751 return (DCMD_USAGE); 752 } 753 return (DCMD_OK); 754 } 755 756 static int 757 mac_srs_walk_init(mdb_walk_state_t *wsp) 758 { 759 if (mdb_layered_walk(LAYERED_WALKER_FOR_SRS, wsp) == -1) { 760 mdb_warn("failed to walk 'mac_srs'"); 761 return (WALK_ERR); 762 } 763 return (WALK_NEXT); 764 } 765 766 static char * 767 mac_ring_state2str(mac_ring_state_t state) 768 { 769 switch (state) { 770 case MR_FREE: 771 return ("free"); 772 case MR_NEWLY_ADDED: 773 return ("new"); 774 case MR_INUSE: 775 return ("inuse"); 776 } 777 return ("--"); 778 } 779 780 static char * 781 mac_ring_classify2str(mac_classify_type_t classify) 782 { 783 switch (classify) { 784 case MAC_NO_CLASSIFIER: 785 return ("no"); 786 case MAC_SW_CLASSIFIER: 787 return ("sw"); 788 case MAC_HW_CLASSIFIER: 789 return ("hw"); 790 } 791 return ("--"); 792 } 793 794 static int 795 mac_ring_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 796 { 797 mac_ring_t ring; 798 mac_group_t group; 799 flow_entry_t flent; 800 mac_soft_ring_set_t srs; 801 802 if (!(flags & DCMD_ADDRSPEC)) { 803 if (mdb_walk_dcmd("mac_ring", "mac_ring", argc, argv) == -1) { 804 mdb_warn("failed to walk 'mac_ring'"); 805 return (DCMD_ERR); 806 } 807 return (DCMD_OK); 808 } 809 if (mdb_vread(&ring, sizeof (ring), addr) == -1) { 810 mdb_warn("failed to read struct mac_ring_s at %p", addr); 811 return (DCMD_ERR); 812 } 813 bzero(&flent, sizeof (flent)); 814 if (mdb_vread(&srs, sizeof (srs), (uintptr_t)ring.mr_srs) != -1) { 815 (void) mdb_vread(&flent, sizeof (flent), 816 (uintptr_t)srs.srs_flent); 817 } 818 (void) mdb_vread(&group, sizeof (group), (uintptr_t)ring.mr_gh); 819 if (DCMD_HDRSPEC(flags)) { 820 mdb_printf("%<u>%?s %4s %5s %4s %?s " 821 "%5s %?s %?s %s %</u>\n", 822 "ADDR", "TYPE", "STATE", "FLAG", "GROUP", 823 "CLASS", "MIP", "SRS", "FLOW NAME"); 824 } 825 mdb_printf("%?p %-4s " 826 "%5s %04x " 827 "%?p %-5s " 828 "%?p %?p %s\n", 829 addr, ((ring.mr_type == 1)? "RX" : "TX"), 830 mac_ring_state2str(ring.mr_state), ring.mr_flag, 831 ring.mr_gh, mac_ring_classify2str(ring.mr_classify_type), 832 group.mrg_mh, ring.mr_srs, flent.fe_flow_name); 833 return (DCMD_OK); 834 } 835 836 static int 837 mac_ring_walk_init(mdb_walk_state_t *wsp) 838 { 839 if (mdb_layered_walk(LAYERED_WALKER_FOR_RING, wsp) == -1) { 840 mdb_warn("failed to walk `mac_ring`"); 841 return (WALK_ERR); 842 } 843 return (WALK_NEXT); 844 } 845 846 static void 847 mac_ring_help(void) 848 { 849 mdb_printf("If an address is specified, then mac_ring_t " 850 "structure at that address is printed. Otherwise all the " 851 "hardware rings in the system are printed.\n"); 852 } 853 854 /* Supported dee-commands */ 855 static const mdb_dcmd_t dcmds[] = { 856 {"mac_flow", "?[-u] [-aprtsm]", "display Flow Entry structures", 857 mac_flow_dcmd, mac_flow_help}, 858 {"mac_srs", "?[ -r[s|c[v]] | -t[s|c[v]] ]", "display MAC Soft Ring Set" 859 " structures", mac_srs_dcmd, mac_srs_help}, 860 {"mac_ring", "?", "display MAC ring (hardware) structures", 861 mac_ring_dcmd, mac_ring_help}, 862 { NULL } 863 }; 864 865 /* Supported walkers */ 866 static const mdb_walker_t walkers[] = { 867 {"mac_flow", "walk list of flow entry structures", mac_flow_walk_init, 868 mac_common_walk_step, NULL, NULL}, 869 {"mac_srs", "walk list of mac soft ring set structures", 870 mac_srs_walk_init, mac_common_walk_step, NULL, NULL}, 871 {"mac_ring", "walk list of mac ring structures", mac_ring_walk_init, 872 mac_common_walk_step, NULL, NULL}, 873 { NULL } 874 }; 875 876 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 877 878 const mdb_modinfo_t * 879 _mdb_init(void) 880 { 881 return (&modinfo); 882 } 883