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 %20s\n", 288 addr, fe.fe_flow_name, flow_type, flow_flags, func_name); 289 break; 290 } 291 case MAC_FLOW_RX: { 292 uintptr_t rxaddr, rx_srs[MAX_RINGS_PER_GROUP] = {0}; 293 int i; 294 295 rxaddr = addr + OFFSETOF(flow_entry_t, fe_rx_srs); 296 (void) mdb_vread(rx_srs, MAC_RX_SRS_SIZE, rxaddr); 297 mdb_printf("%?p %-24s %3d ", 298 addr, fe.fe_flow_name, fe.fe_rx_srs_cnt); 299 for (i = 0; i < MAX_RINGS_PER_GROUP; i++) { 300 if (rx_srs[i] == 0) 301 continue; 302 mdb_printf("%p ", rx_srs[i]); 303 } 304 mdb_printf("\n"); 305 break; 306 } 307 case MAC_FLOW_TX: { 308 uintptr_t tx_srs = 0, txaddr; 309 310 txaddr = addr + OFFSETOF(flow_entry_t, fe_tx_srs); 311 (void) mdb_vread(&tx_srs, sizeof (uintptr_t), txaddr); 312 mdb_printf("%?p %-32s %?p\n", 313 addr, fe.fe_flow_name, fe.fe_tx_srs); 314 break; 315 } 316 case MAC_FLOW_STATS: { 317 mdb_printf("%?p %-32s %16llu %16llu\n", 318 addr, fe.fe_flow_name, fe.fe_flowstats.fs_rbytes, 319 fe.fe_flowstats.fs_obytes); 320 break; 321 } 322 } 323 return (DCMD_OK); 324 } 325 326 /* 327 * Parse the arguments passed to the dcmd and print all or one flow_entry_t 328 * structures 329 */ 330 static int 331 mac_flow_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 332 { 333 uint_t args = 0; 334 335 if (!(flags & DCMD_ADDRSPEC)) { 336 if (mdb_walk_dcmd("mac_flow", "mac_flow", argc, argv) == -1) { 337 mdb_warn("failed to walk 'mac_flow'"); 338 return (DCMD_ERR); 339 } 340 return (DCMD_OK); 341 } 342 if ((mdb_getopts(argc, argv, 343 'a', MDB_OPT_SETBITS, MAC_FLOW_ATTR, &args, 344 'p', MDB_OPT_SETBITS, MAC_FLOW_PROP, &args, 345 'm', MDB_OPT_SETBITS, MAC_FLOW_MISC, &args, 346 'r', MDB_OPT_SETBITS, MAC_FLOW_RX, &args, 347 't', MDB_OPT_SETBITS, MAC_FLOW_TX, &args, 348 's', MDB_OPT_SETBITS, MAC_FLOW_STATS, &args, 349 'u', MDB_OPT_SETBITS, MAC_FLOW_USER, &args) != argc)) { 350 return (DCMD_USAGE); 351 } 352 if (argc > 2 || (argc == 2 && !(args & MAC_FLOW_USER))) 353 return (DCMD_USAGE); 354 /* 355 * If no arguments was specified or just "-u" was specified then 356 * we default to printing basic information of flows. 357 */ 358 if (args == 0 || args == MAC_FLOW_USER) 359 args |= MAC_FLOW_NONE; 360 361 return (mac_flow_dcmd_output(addr, flags, args)); 362 } 363 364 static void 365 mac_flow_help(void) 366 { 367 mdb_printf("If an address is specified, then flow_entry structure at " 368 "that address is printed. Otherwise all the flows in the system " 369 "are printed.\n"); 370 mdb_printf("Options:\n" 371 "\t-u\tdisplay user defined link & vnic flows.\n" 372 "\t-a\tdisplay flow attributes\n" 373 "\t-p\tdisplay flow properties\n" 374 "\t-r\tdisplay rx side information\n" 375 "\t-t\tdisplay tx side information\n" 376 "\t-s\tdisplay flow statistics\n" 377 "\t-m\tdisplay miscellaneous flow information\n\n"); 378 mdb_printf("%<u>Interpreting Flow type and Flow flags output.%</u>\n"); 379 mdb_printf("Flow Types:\n"); 380 mdb_printf("\t P --> FLOW_PRIMARY_MAC\n"); 381 mdb_printf("\t V --> FLOW_VNIC_MAC\n"); 382 mdb_printf("\t M --> FLOW_MCAST\n"); 383 mdb_printf("\t O --> FLOW_OTHER\n"); 384 mdb_printf("\t U --> FLOW_USER\n"); 385 mdb_printf("\t NS --> FLOW_NO_STATS\n\n"); 386 mdb_printf("Flow Flags:\n"); 387 mdb_printf("\t Q --> FE_QUIESCE\n"); 388 mdb_printf("\t W --> FE_WAITER\n"); 389 mdb_printf("\t T --> FE_FLOW_TAB\n"); 390 mdb_printf("\t G --> FE_G_FLOW_HASH\n"); 391 mdb_printf("\t I --> FE_INCIPIENT\n"); 392 mdb_printf("\t C --> FE_CONDEMNED\n"); 393 mdb_printf("\t NU --> FE_UF_NO_DATAPATH\n"); 394 mdb_printf("\t NC --> FE_MC_NO_DATAPATH\n"); 395 } 396 397 /* 398 * called once by the debugger when the mac_flow walk begins. 399 */ 400 static int 401 mac_flow_walk_init(mdb_walk_state_t *wsp) 402 { 403 if (mdb_layered_walk(LAYERED_WALKER_FOR_FLOW, wsp) == -1) { 404 mdb_warn("failed to walk 'mac_flow'"); 405 return (WALK_ERR); 406 } 407 return (WALK_NEXT); 408 } 409 410 /* 411 * Common walker step funciton for flow_entry_t, mac_soft_ring_set_t and 412 * mac_ring_t. 413 * 414 * Steps through each flow_entry_t and calls the callback function. If the 415 * user executed ::walk mac_flow, it just prints the address or if the user 416 * executed ::mac_flow it displays selected fields of flow_entry_t structure 417 * by calling "mac_flow_dcmd" 418 */ 419 static int 420 mac_common_walk_step(mdb_walk_state_t *wsp) 421 { 422 int status; 423 424 if (wsp->walk_addr == NULL) 425 return (WALK_DONE); 426 427 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 428 wsp->walk_cbdata); 429 430 return (status); 431 } 432 433 static char * 434 mac_srs_txmode2str(mac_tx_srs_mode_t mode) 435 { 436 switch (mode) { 437 case SRS_TX_DEFAULT: 438 return ("DEF"); 439 case SRS_TX_SERIALIZE: 440 return ("SER"); 441 case SRS_TX_FANOUT: 442 return ("FO"); 443 case SRS_TX_BW: 444 return ("BW"); 445 case SRS_TX_BW_FANOUT: 446 return ("BWFO"); 447 } 448 return ("--"); 449 } 450 451 static void 452 mac_srs_help(void) 453 { 454 mdb_printf("If an address is specified, then mac_soft_ring_set " 455 "structure at that address is printed. Otherwise all the " 456 "SRS in the system are printed.\n"); 457 mdb_printf("Options:\n" 458 "\t-r\tdisplay recieve side SRS structures\n" 459 "\t-t\tdisplay transmit side SRS structures\n" 460 "\t-s\tdisplay statistics for RX or TX side\n" 461 "\t-c\tdisplay CPU binding for RX or TX side\n" 462 "\t-v\tverbose flag for CPU binding to list cpus\n" 463 "Note: use -r or -t (to specify RX or TX side respectively) along " 464 "with -c or -s\n"); 465 mdb_printf("\n%<u>Interpreting TX Modes%</u>\n"); 466 mdb_printf("\t DEF --> Default\n"); 467 mdb_printf("\t SER --> Serialize\n"); 468 mdb_printf("\t FO --> Fanout\n"); 469 mdb_printf("\t BW --> Bandwidth\n"); 470 mdb_printf("\tBWFO --> Bandwidth Fanout\n"); 471 } 472 473 /* 474 * In verbose mode "::mac_srs -rcv or ::mac_srs -tcv", we print the CPUs 475 * assigned to a link and CPUS assigned to the soft rings. 476 * 'len' is used for formatting the output and represents the number of 477 * spaces between CPU list and Fanout CPU list in the output. 478 */ 479 static boolean_t 480 mac_srs_print_cpu(int *i, uint32_t cnt, uint32_t *cpu_list, int *len) 481 { 482 int num = 0; 483 484 if (*i == 0) 485 mdb_printf("("); 486 else 487 mdb_printf(" "); 488 while (*i < cnt) { 489 /* We print 6 CPU's at a time to keep display within 80 cols */ 490 if (((num + 1) % 7) == 0) { 491 if (len != NULL) 492 *len = 2; 493 return (B_FALSE); 494 } 495 mdb_printf("%02x%c", cpu_list[*i], ((*i == cnt - 1)?')':',')); 496 ++*i; 497 ++num; 498 } 499 if (len != NULL) 500 *len = (7 - num) * 3; 501 return (B_TRUE); 502 } 503 504 static int 505 mac_srs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 506 { 507 uint_t args = MAC_SRS_NONE; 508 mac_soft_ring_set_t srs; 509 mac_client_impl_t mci; 510 511 if (!(flags & DCMD_ADDRSPEC)) { 512 if (mdb_walk_dcmd("mac_srs", "mac_srs", argc, argv) == -1) { 513 mdb_warn("failed to walk 'mac_srs'"); 514 return (DCMD_ERR); 515 } 516 return (DCMD_OK); 517 } 518 if (mdb_getopts(argc, argv, 519 'r', MDB_OPT_SETBITS, MAC_SRS_RX, &args, 520 't', MDB_OPT_SETBITS, MAC_SRS_TX, &args, 521 'c', MDB_OPT_SETBITS, MAC_SRS_CPU, &args, 522 'v', MDB_OPT_SETBITS, MAC_SRS_VERBOSE, &args, 523 's', MDB_OPT_SETBITS, MAC_SRS_STAT, &args) != argc) { 524 return (DCMD_USAGE); 525 } 526 527 if (argc > 2) 528 return (DCMD_USAGE); 529 530 if (mdb_vread(&srs, sizeof (srs), addr) == -1) { 531 mdb_warn("failed to read struct mac_soft_ring_set_s at %p", 532 addr); 533 return (DCMD_ERR); 534 } 535 if (mdb_vread(&mci, sizeof (mci), (uintptr_t)srs.srs_mcip) == -1) { 536 mdb_warn("failed to read struct mac_client_impl_t at %p " 537 "for SRS %p", srs.srs_mcip, addr); 538 return (DCMD_ERR); 539 } 540 541 switch (args) { 542 case MAC_SRS_RX: { 543 if (DCMD_HDRSPEC(flags)) { 544 mdb_printf("%?s %-20s %-8s %-8s %8s " 545 "%8s %3s\n", 546 "", "", "", "", "MBLK", 547 "Q", "SR"); 548 mdb_printf("%<u>%?s %-20s %-8s %-8s %8s " 549 "%8s %3s%</u>\n", 550 "ADDR", "LINK_NAME", "STATE", "TYPE", "CNT", 551 "BYTES", "CNT"); 552 } 553 if (srs.srs_type & SRST_TX) 554 return (DCMD_OK); 555 mdb_printf("%?p %-20s %08x %08x " 556 "%8d %8d %3d\n", 557 addr, mci.mci_name, srs.srs_state, srs.srs_type, 558 srs.srs_count, srs.srs_size, srs.srs_soft_ring_count); 559 break; 560 } 561 case MAC_SRS_TX: { 562 if (DCMD_HDRSPEC(flags)) { 563 mdb_printf("%?s %-16s %-4s %-8s " 564 "%-8s %8s %8s %3s\n", 565 "", "", "TX", "", 566 "", "MBLK", "Q", "SR"); 567 mdb_printf("%<u>%?s %-16s %-4s %-8s " 568 "%-8s %8s %8s %3s%</u>\n", 569 "ADDR", "LINK_NAME", "MODE", "STATE", 570 "TYPE", "CNT", "BYTES", "CNT"); 571 } 572 if (!(srs.srs_type & SRST_TX)) 573 return (DCMD_OK); 574 575 mdb_printf("%?p %-16s %-4s " 576 "%08x %08x %8d %8d %3d\n", 577 addr, mci.mci_name, mac_srs_txmode2str(srs.srs_tx.st_mode), 578 srs.srs_state, srs.srs_type, srs.srs_count, srs.srs_size, 579 srs.srs_oth_ring_count); 580 break; 581 } 582 case MAC_SRS_RXCPU: { 583 mac_cpus_t mc = srs.srs_cpu; 584 585 if (DCMD_HDRSPEC(flags)) { 586 mdb_printf("%?s %-20s %-4s %-4s " 587 "%-6s %-4s %-7s\n", 588 "", "", "NUM", "POLL", 589 "WORKER", "INTR", "FANOUT"); 590 mdb_printf("%<u>%?s %-20s %-4s %-4s " 591 "%-6s %-4s %-7s%</u>\n", 592 "ADDR", "LINK_NAME", "CPUS", "CPU", 593 "CPU", "CPU", "CPU_CNT"); 594 } 595 if ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX)) 596 return (DCMD_OK); 597 mdb_printf("%?p %-20s %-4d %-4d " 598 "%-6d %-4d %-7d\n", 599 addr, mci.mci_name, mc.mc_ncpus, mc.mc_pollid, 600 mc.mc_workerid, mc.mc_intr_cpu, mc.mc_fanout_cnt); 601 break; 602 603 } 604 case MAC_SRS_TXCPU: { 605 mac_cpus_t mc = srs.srs_cpu; 606 607 if (DCMD_HDRSPEC(flags)) { 608 mdb_printf("%?s %-20s %-4s %-6s " 609 "%-4s %-7s\n", 610 "", "", "NUM", "WORKER", 611 "INTR", "FANOUT"); 612 mdb_printf("%<u>%?s %-20s %-4s %-6s " 613 "%-4s %-7s%</u>\n", 614 "ADDR", "LINK_NAME", "CPUS", "CPU", 615 "CPU", "CPU_CNT"); 616 } 617 if ((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX)) 618 return (DCMD_OK); 619 mdb_printf("%?p %-20s %-4d " 620 "%-6d %-4d %-7d\n", 621 addr, mci.mci_name, mc.mc_ncpus, 622 mc.mc_workerid, mc.mc_intr_cpu, mc.mc_fanout_cnt); 623 break; 624 } 625 case MAC_SRS_RXCPUVERBOSE: 626 case MAC_SRS_TXCPUVERBOSE: { 627 mac_cpus_t mc = srs.srs_cpu; 628 int cpu_index = 0, fanout_index = 0, len = 0; 629 boolean_t cpu_done = B_FALSE, fanout_done = B_FALSE; 630 631 if (DCMD_HDRSPEC(flags)) { 632 mdb_printf("%?s %-20s %-20s %-20s\n", 633 "", "", "CPU_COUNT", "FANOUT_CPU_COUNT"); 634 mdb_printf("%<u>%?s %-20s " 635 "%-20s %-20s%</u>\n", 636 "ADDR", "LINK_NAME", 637 "(CPU_LIST)", "(CPU_LIST)"); 638 } 639 if (((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX)) || 640 ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX))) 641 return (DCMD_OK); 642 mdb_printf("%?p %-20s %-20d %-20d\n", addr, mci.mci_name, 643 mc.mc_ncpus, mc.mc_fanout_cnt); 644 if (mc.mc_ncpus == 0 && mc.mc_fanout_cnt == 0) 645 break; 646 /* print all cpus and cpus for soft rings */ 647 while (!cpu_done || !fanout_done) { 648 boolean_t old_value = cpu_done; 649 650 if (!cpu_done) { 651 mdb_printf("%?s %20s ", "", ""); 652 cpu_done = mac_srs_print_cpu(&cpu_index, 653 mc.mc_ncpus, mc.mc_cpus, &len); 654 } 655 if (!fanout_done) { 656 if (old_value) 657 mdb_printf("%?s %-40s", "", ""); 658 else 659 mdb_printf("%*s", len, ""); 660 fanout_done = mac_srs_print_cpu(&fanout_index, 661 mc.mc_fanout_cnt, mc.mc_fanout_cpus, NULL); 662 } 663 mdb_printf("\n"); 664 } 665 break; 666 } 667 case MAC_SRS_RXSTAT: { 668 mac_srs_rx_t srs_rx = srs.srs_rx; 669 670 if (DCMD_HDRSPEC(flags)) { 671 mdb_printf("%?s %-16s %8s %8s " 672 "%8s %8s %8s\n", 673 "", "", "INTR", "POLL", 674 "CHAIN", "CHAIN", "CHAIN"); 675 mdb_printf("%<u>%?s %-16s %8s %8s " 676 "%8s %8s %8s%</u>\n", 677 "ADDR", "LINK_NAME", "COUNT", "COUNT", 678 "<10", "10-50", ">50"); 679 } 680 if (srs.srs_type & SRST_TX) 681 return (DCMD_OK); 682 mdb_printf("%?p %-16s %8d " 683 "%8d %8d " 684 "%8d %8d\n", 685 addr, mci.mci_name, srs_rx.sr_intr_count, 686 srs_rx.sr_poll_count, srs_rx.sr_chain_cnt_undr10, 687 srs_rx.sr_chain_cnt_10to50, srs_rx.sr_chain_cnt_over50); 688 break; 689 } 690 case MAC_SRS_TXSTAT: { 691 mac_srs_tx_t srs_tx = srs.srs_tx; 692 mac_soft_ring_t *s_ringp, s_ring; 693 boolean_t first = B_TRUE; 694 695 if (DCMD_HDRSPEC(flags)) { 696 mdb_printf("%?s %-20s %?s %8s %8s %8s\n", 697 "", "", "SOFT", "DROP", "BLOCK", "UNBLOCK"); 698 mdb_printf("%<u>%?s %-20s %?s %8s %8s %8s%</u>\n", 699 "ADDR", "LINK_NAME", "RING", "COUNT", "COUNT", 700 "COUNT"); 701 } 702 if (!(srs.srs_type & SRST_TX)) 703 return (DCMD_OK); 704 705 mdb_printf("%?p %-20s ", addr, mci.mci_name); 706 707 /* 708 * Case of no soft rings, print the info from 709 * mac_srs_tx_t. 710 */ 711 if (srs.srs_oth_ring_count == 0) { 712 mdb_printf("%?p %8d %8d %8d\n", 713 0, srs_tx.st_drop_count, srs_tx.st_blocked_cnt, 714 srs_tx.st_unblocked_cnt); 715 break; 716 } 717 718 for (s_ringp = srs.srs_soft_ring_head; s_ringp != NULL; 719 s_ringp = s_ring.s_ring_next) { 720 (void) mdb_vread(&s_ring, sizeof (s_ring), 721 (uintptr_t)s_ringp); 722 if (first) { 723 mdb_printf("%?p %8d %8d %8d\n", 724 s_ringp, s_ring.s_ring_drops, 725 s_ring.s_ring_blocked_cnt, 726 s_ring.s_ring_unblocked_cnt); 727 first = B_FALSE; 728 continue; 729 } 730 mdb_printf("%?s %-20s %?p %8d %8d %8d\n", 731 "", "", s_ringp, s_ring.s_ring_drops, 732 s_ring.s_ring_blocked_cnt, 733 s_ring.s_ring_unblocked_cnt); 734 } 735 break; 736 } 737 case MAC_SRS_NONE: { 738 if (DCMD_HDRSPEC(flags)) { 739 mdb_printf("%<u>%?s %-20s %?s %?s %-3s%</u>\n", 740 "ADDR", "LINK_NAME", "FLENT", "HW RING", "DIR"); 741 } 742 mdb_printf("%?p %-20s %?p %?p " 743 "%-3s ", 744 addr, mci.mci_name, srs.srs_flent, srs.srs_ring, 745 (srs.srs_type & SRST_TX ? "TX" : "RX")); 746 break; 747 } 748 default: 749 return (DCMD_USAGE); 750 } 751 return (DCMD_OK); 752 } 753 754 static int 755 mac_srs_walk_init(mdb_walk_state_t *wsp) 756 { 757 if (mdb_layered_walk(LAYERED_WALKER_FOR_SRS, wsp) == -1) { 758 mdb_warn("failed to walk 'mac_srs'"); 759 return (WALK_ERR); 760 } 761 return (WALK_NEXT); 762 } 763 764 static char * 765 mac_ring_state2str(mac_ring_state_t state) 766 { 767 switch (state) { 768 case MR_FREE: 769 return ("free"); 770 case MR_NEWLY_ADDED: 771 return ("new"); 772 case MR_INUSE: 773 return ("inuse"); 774 } 775 return ("--"); 776 } 777 778 static char * 779 mac_ring_classify2str(mac_classify_type_t classify) 780 { 781 switch (classify) { 782 case MAC_NO_CLASSIFIER: 783 return ("no"); 784 case MAC_SW_CLASSIFIER: 785 return ("sw"); 786 case MAC_HW_CLASSIFIER: 787 return ("hw"); 788 } 789 return ("--"); 790 } 791 792 static int 793 mac_ring_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 794 { 795 mac_ring_t ring; 796 mac_group_t group; 797 flow_entry_t flent; 798 mac_soft_ring_set_t srs; 799 800 if (!(flags & DCMD_ADDRSPEC)) { 801 if (mdb_walk_dcmd("mac_ring", "mac_ring", argc, argv) == -1) { 802 mdb_warn("failed to walk 'mac_ring'"); 803 return (DCMD_ERR); 804 } 805 return (DCMD_OK); 806 } 807 if (mdb_vread(&ring, sizeof (ring), addr) == -1) { 808 mdb_warn("failed to read struct mac_ring_s at %p", addr); 809 return (DCMD_ERR); 810 } 811 bzero(&flent, sizeof (flent)); 812 if (mdb_vread(&srs, sizeof (srs), (uintptr_t)ring.mr_srs) != -1) { 813 (void) mdb_vread(&flent, sizeof (flent), 814 (uintptr_t)srs.srs_flent); 815 } 816 (void) mdb_vread(&group, sizeof (group), (uintptr_t)ring.mr_gh); 817 if (DCMD_HDRSPEC(flags)) { 818 mdb_printf("%<u>%?s %4s %5s %4s %?s " 819 "%5s %?s %?s %s %</u>\n", 820 "ADDR", "TYPE", "STATE", "FLAG", "GROUP", 821 "CLASS", "MIP", "SRS", "FLOW NAME"); 822 } 823 mdb_printf("%?p %-4s " 824 "%5s %04x " 825 "%?p %-5s " 826 "%?p %?p %s\n", 827 addr, ((ring.mr_type == 1)? "RX" : "TX"), 828 mac_ring_state2str(ring.mr_state), ring.mr_flag, 829 ring.mr_gh, mac_ring_classify2str(ring.mr_classify_type), 830 group.mrg_mh, ring.mr_srs, flent.fe_flow_name); 831 return (DCMD_OK); 832 } 833 834 static int 835 mac_ring_walk_init(mdb_walk_state_t *wsp) 836 { 837 if (mdb_layered_walk(LAYERED_WALKER_FOR_RING, wsp) == -1) { 838 mdb_warn("failed to walk `mac_ring`"); 839 return (WALK_ERR); 840 } 841 return (WALK_NEXT); 842 } 843 844 static void 845 mac_ring_help(void) 846 { 847 mdb_printf("If an address is specified, then mac_ring_t " 848 "structure at that address is printed. Otherwise all the " 849 "hardware rings in the system are printed.\n"); 850 } 851 852 /* Supported dee-commands */ 853 static const mdb_dcmd_t dcmds[] = { 854 {"mac_flow", "?[-u] [-aprtsm]", "display Flow Entry structures", 855 mac_flow_dcmd, mac_flow_help}, 856 {"mac_srs", "?[ -r[s|c[v]] | -t[s|c[v]] ]", "display MAC Soft Ring Set" 857 " structures", mac_srs_dcmd, mac_srs_help}, 858 {"mac_ring", "?", "display MAC ring (hardware) structures", 859 mac_ring_dcmd, mac_ring_help}, 860 { NULL } 861 }; 862 863 /* Supported walkers */ 864 static const mdb_walker_t walkers[] = { 865 {"mac_flow", "walk list of flow entry structures", mac_flow_walk_init, 866 mac_common_walk_step, NULL, NULL}, 867 {"mac_srs", "walk list of mac soft ring set structures", 868 mac_srs_walk_init, mac_common_walk_step, NULL, NULL}, 869 {"mac_ring", "walk list of mac ring structures", mac_ring_walk_init, 870 mac_common_walk_step, NULL, NULL}, 871 { NULL } 872 }; 873 874 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 875 876 const mdb_modinfo_t * 877 _mdb_init(void) 878 { 879 return (&modinfo); 880 } 881