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 2010 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 #include <sys/mac_stat.h> 38 39 #define STRSIZE 64 40 #define MAC_RX_SRS_SIZE (MAX_RINGS_PER_GROUP * sizeof (uintptr_t)) 41 42 #define LAYERED_WALKER_FOR_FLOW "flow_entry_cache" 43 #define LAYERED_WALKER_FOR_SRS "mac_srs_cache" 44 #define LAYERED_WALKER_FOR_RING "mac_ring_cache" 45 #define LAYERED_WALKER_FOR_GROUP "mac_impl_cache" 46 47 /* arguments passed to mac_flow dee-command */ 48 #define MAC_FLOW_NONE 0x01 49 #define MAC_FLOW_ATTR 0x02 50 #define MAC_FLOW_PROP 0x04 51 #define MAC_FLOW_RX 0x08 52 #define MAC_FLOW_TX 0x10 53 #define MAC_FLOW_USER 0x20 54 #define MAC_FLOW_STATS 0x40 55 #define MAC_FLOW_MISC 0x80 56 57 /* arguments passed to mac_srs dee-command */ 58 #define MAC_SRS_NONE 0x00 59 #define MAC_SRS_RX 0x01 60 #define MAC_SRS_TX 0x02 61 #define MAC_SRS_STAT 0x04 62 #define MAC_SRS_CPU 0x08 63 #define MAC_SRS_VERBOSE 0x10 64 #define MAC_SRS_INTR 0x20 65 #define MAC_SRS_RXSTAT (MAC_SRS_RX|MAC_SRS_STAT) 66 #define MAC_SRS_TXSTAT (MAC_SRS_TX|MAC_SRS_STAT) 67 #define MAC_SRS_RXCPU (MAC_SRS_RX|MAC_SRS_CPU) 68 #define MAC_SRS_TXCPU (MAC_SRS_TX|MAC_SRS_CPU) 69 #define MAC_SRS_RXCPUVERBOSE (MAC_SRS_RXCPU|MAC_SRS_VERBOSE) 70 #define MAC_SRS_TXCPUVERBOSE (MAC_SRS_TXCPU|MAC_SRS_VERBOSE) 71 #define MAC_SRS_RXINTR (MAC_SRS_RX|MAC_SRS_INTR) 72 #define MAC_SRS_TXINTR (MAC_SRS_TX|MAC_SRS_INTR) 73 74 /* arguments passed to mac_group dcmd */ 75 #define MAC_GROUP_NONE 0x00 76 #define MAC_GROUP_RX 0x01 77 #define MAC_GROUP_TX 0x02 78 #define MAC_GROUP_UNINIT 0x04 79 80 static char * 81 mac_flow_proto2str(uint8_t protocol) 82 { 83 switch (protocol) { 84 case IPPROTO_TCP: 85 return ("tcp"); 86 case IPPROTO_UDP: 87 return ("udp"); 88 case IPPROTO_SCTP: 89 return ("sctp"); 90 case IPPROTO_ICMP: 91 return ("icmp"); 92 case IPPROTO_ICMPV6: 93 return ("icmpv6"); 94 default: 95 return ("--"); 96 } 97 } 98 99 static char * 100 mac_flow_priority2str(mac_priority_level_t prio) 101 { 102 switch (prio) { 103 case MPL_LOW: 104 return ("low"); 105 case MPL_MEDIUM: 106 return ("medium"); 107 case MPL_HIGH: 108 return ("high"); 109 case MPL_RESET: 110 return ("reset"); 111 default: 112 return ("--"); 113 } 114 } 115 116 /* 117 * Convert bandwidth in bps to a string in Mbps. 118 */ 119 static char * 120 mac_flow_bw2str(uint64_t bw, char *buf, ssize_t len) 121 { 122 int kbps, mbps; 123 124 kbps = (bw % 1000000)/1000; 125 mbps = bw/1000000; 126 if ((mbps == 0) && (kbps != 0)) 127 mdb_snprintf(buf, len, "0.%03u", kbps); 128 else 129 mdb_snprintf(buf, len, "%5u", mbps); 130 return (buf); 131 } 132 133 static void 134 mac_flow_print_header(uint_t args) 135 { 136 switch (args) { 137 case MAC_FLOW_NONE: 138 mdb_printf("%?s %-20s %4s %?s %?s %-16s\n", 139 "", "", "LINK", "", "", "MIP"); 140 mdb_printf("%<u>%?s %-20s %4s %?s %?s %-16s%</u>\n", 141 "ADDR", "FLOW NAME", "ID", "MCIP", "MIP", "NAME"); 142 break; 143 case MAC_FLOW_ATTR: 144 mdb_printf("%<u>%?s %-32s %-7s %6s " 145 "%-9s %s%</u>\n", 146 "ADDR", "FLOW NAME", "PROTO", "PORT", 147 "DSFLD:MSK", "IPADDR"); 148 break; 149 case MAC_FLOW_PROP: 150 mdb_printf("%<u>%?s %-32s %8s %9s%</u>\n", 151 "ADDR", "FLOW NAME", "MAXBW(M)", "PRIORITY"); 152 break; 153 case MAC_FLOW_MISC: 154 mdb_printf("%<u>%?s %-24s %10s %10s " 155 "%20s %4s%</u>\n", 156 "ADDR", "FLOW NAME", "TYPE", "FLAGS", 157 "MATCH_FN", "ZONE"); 158 break; 159 case MAC_FLOW_RX: 160 mdb_printf("%?s %-24s %3s %s\n", "", "", "SRS", "RX"); 161 mdb_printf("%<u>%?s %-24s %3s %s%</u>\n", 162 "ADDR", "FLOW NAME", "CNT", "SRS"); 163 break; 164 case MAC_FLOW_TX: 165 mdb_printf("%<u>%?s %-32s %?s %</u>\n", 166 "ADDR", "FLOW NAME", "TX_SRS"); 167 break; 168 case MAC_FLOW_STATS: 169 mdb_printf("%<u>%?s %-32s %16s %16s%</u>\n", 170 "ADDR", "FLOW NAME", "RBYTES", "OBYTES"); 171 break; 172 } 173 } 174 175 /* 176 * Display selected fields of the flow_entry_t structure 177 */ 178 static int 179 mac_flow_dcmd_output(uintptr_t addr, uint_t flags, uint_t args) 180 { 181 static const mdb_bitmask_t flow_type_bits[] = { 182 {"P", FLOW_PRIMARY_MAC, FLOW_PRIMARY_MAC}, 183 {"V", FLOW_VNIC_MAC, FLOW_VNIC_MAC}, 184 {"M", FLOW_MCAST, FLOW_MCAST}, 185 {"O", FLOW_OTHER, FLOW_OTHER}, 186 {"U", FLOW_USER, FLOW_USER}, 187 {"V", FLOW_VNIC, FLOW_VNIC}, 188 {"NS", FLOW_NO_STATS, FLOW_NO_STATS}, 189 { NULL, 0, 0 } 190 }; 191 #define FLOW_MAX_TYPE (sizeof (flow_type_bits) / sizeof (mdb_bitmask_t)) 192 193 static const mdb_bitmask_t flow_flag_bits[] = { 194 {"Q", FE_QUIESCE, FE_QUIESCE}, 195 {"W", FE_WAITER, FE_WAITER}, 196 {"T", FE_FLOW_TAB, FE_FLOW_TAB}, 197 {"G", FE_G_FLOW_HASH, FE_G_FLOW_HASH}, 198 {"I", FE_INCIPIENT, FE_INCIPIENT}, 199 {"C", FE_CONDEMNED, FE_CONDEMNED}, 200 {"NU", FE_UF_NO_DATAPATH, FE_UF_NO_DATAPATH}, 201 {"NC", FE_MC_NO_DATAPATH, FE_MC_NO_DATAPATH}, 202 { NULL, 0, 0 } 203 }; 204 #define FLOW_MAX_FLAGS (sizeof (flow_flag_bits) / sizeof (mdb_bitmask_t)) 205 flow_entry_t fe; 206 mac_client_impl_t mcip; 207 mac_impl_t mip; 208 209 if (mdb_vread(&fe, sizeof (fe), addr) == -1) { 210 mdb_warn("failed to read struct flow_entry_s at %p", addr); 211 return (DCMD_ERR); 212 } 213 if (args & MAC_FLOW_USER) { 214 args &= ~MAC_FLOW_USER; 215 if (fe.fe_type & FLOW_MCAST) { 216 if (DCMD_HDRSPEC(flags)) 217 mac_flow_print_header(args); 218 return (DCMD_OK); 219 } 220 } 221 if (DCMD_HDRSPEC(flags)) 222 mac_flow_print_header(args); 223 bzero(&mcip, sizeof (mcip)); 224 bzero(&mip, sizeof (mip)); 225 if (fe.fe_mcip != NULL && mdb_vread(&mcip, sizeof (mcip), 226 (uintptr_t)fe.fe_mcip) == sizeof (mcip)) { 227 (void) mdb_vread(&mip, sizeof (mip), (uintptr_t)mcip.mci_mip); 228 } 229 switch (args) { 230 case MAC_FLOW_NONE: { 231 mdb_printf("%?p %-20s %4d %?p " 232 "%?p %-16s\n", 233 addr, fe.fe_flow_name, fe.fe_link_id, fe.fe_mcip, 234 mcip.mci_mip, mip.mi_name); 235 break; 236 } 237 case MAC_FLOW_ATTR: { 238 struct in_addr in4; 239 uintptr_t desc_addr; 240 flow_desc_t fdesc; 241 242 desc_addr = addr + OFFSETOF(flow_entry_t, fe_flow_desc); 243 if (mdb_vread(&fdesc, sizeof (fdesc), desc_addr) == -1) { 244 mdb_warn("failed to read struct flow_description at %p", 245 desc_addr); 246 return (DCMD_ERR); 247 } 248 mdb_printf("%?p %-32s " 249 "%-7s %6d " 250 "%4d:%-4d ", 251 addr, fe.fe_flow_name, 252 mac_flow_proto2str(fdesc.fd_protocol), fdesc.fd_local_port, 253 fdesc.fd_dsfield, fdesc.fd_dsfield_mask); 254 if (fdesc.fd_ipversion == IPV4_VERSION) { 255 IN6_V4MAPPED_TO_INADDR(&fdesc.fd_local_addr, &in4); 256 mdb_printf("%I", in4.s_addr); 257 } else if (fdesc.fd_ipversion == IPV6_VERSION) { 258 mdb_printf("%N", &fdesc.fd_local_addr); 259 } else { 260 mdb_printf("%s", "--"); 261 } 262 mdb_printf("\n"); 263 break; 264 } 265 case MAC_FLOW_PROP: { 266 uintptr_t prop_addr; 267 char bwstr[STRSIZE]; 268 mac_resource_props_t fprop; 269 270 prop_addr = addr + OFFSETOF(flow_entry_t, fe_resource_props); 271 if (mdb_vread(&fprop, sizeof (fprop), prop_addr) == -1) { 272 mdb_warn("failed to read struct mac_resoource_props " 273 "at %p", prop_addr); 274 return (DCMD_ERR); 275 } 276 mdb_printf("%?p %-32s " 277 "%8s %9s\n", 278 addr, fe.fe_flow_name, 279 mac_flow_bw2str(fprop.mrp_maxbw, bwstr, STRSIZE), 280 mac_flow_priority2str(fprop.mrp_priority)); 281 break; 282 } 283 case MAC_FLOW_MISC: { 284 char flow_flags[2 * FLOW_MAX_FLAGS]; 285 char flow_type[2 * FLOW_MAX_TYPE]; 286 GElf_Sym sym; 287 char func_name[MDB_SYM_NAMLEN] = ""; 288 uintptr_t func, match_addr; 289 290 match_addr = addr + OFFSETOF(flow_entry_t, fe_match); 291 (void) mdb_vread(&func, sizeof (func), match_addr); 292 (void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name, 293 MDB_SYM_NAMLEN, &sym); 294 mdb_snprintf(flow_flags, 2 * FLOW_MAX_FLAGS, "%hb", 295 fe.fe_flags, flow_flag_bits); 296 mdb_snprintf(flow_type, 2 * FLOW_MAX_TYPE, "%hb", 297 fe.fe_type, flow_type_bits); 298 mdb_printf("%?p %-24s %10s %10s %20s\n", 299 addr, fe.fe_flow_name, flow_type, flow_flags, func_name); 300 break; 301 } 302 case MAC_FLOW_RX: { 303 uintptr_t rxaddr, rx_srs[MAX_RINGS_PER_GROUP] = {0}; 304 int i; 305 306 rxaddr = addr + OFFSETOF(flow_entry_t, fe_rx_srs); 307 (void) mdb_vread(rx_srs, MAC_RX_SRS_SIZE, rxaddr); 308 mdb_printf("%?p %-24s %3d ", 309 addr, fe.fe_flow_name, fe.fe_rx_srs_cnt); 310 for (i = 0; i < MAX_RINGS_PER_GROUP; i++) { 311 if (rx_srs[i] == 0) 312 continue; 313 mdb_printf("%p ", rx_srs[i]); 314 } 315 mdb_printf("\n"); 316 break; 317 } 318 case MAC_FLOW_TX: { 319 uintptr_t tx_srs = 0, txaddr; 320 321 txaddr = addr + OFFSETOF(flow_entry_t, fe_tx_srs); 322 (void) mdb_vread(&tx_srs, sizeof (uintptr_t), txaddr); 323 mdb_printf("%?p %-32s %?p\n", 324 addr, fe.fe_flow_name, fe.fe_tx_srs); 325 break; 326 } 327 case MAC_FLOW_STATS: { 328 uint64_t totibytes = 0; 329 uint64_t totobytes = 0; 330 mac_soft_ring_set_t *mac_srs; 331 mac_rx_stats_t *mac_rx_stat; 332 mac_tx_stats_t *mac_tx_stat; 333 int i; 334 335 for (i = 0; i < fe.fe_rx_srs_cnt; i++) { 336 mac_srs = (mac_soft_ring_set_t *)(fe.fe_rx_srs[i]); 337 mac_rx_stat = &mac_srs->srs_rx.sr_stat; 338 totibytes += mac_rx_stat->mrs_intrbytes + 339 mac_rx_stat->mrs_pollbytes + 340 mac_rx_stat->mrs_lclbytes; 341 } 342 mac_srs = (mac_soft_ring_set_t *)(fe.fe_tx_srs); 343 if (mac_srs != NULL) { 344 mac_tx_stat = &mac_srs->srs_tx.st_stat; 345 totobytes = mac_tx_stat->mts_obytes; 346 } 347 mdb_printf("%?p %-32s %16llu %16llu\n", 348 addr, fe.fe_flow_name, totibytes, totobytes); 349 350 break; 351 } 352 } 353 return (DCMD_OK); 354 } 355 356 /* 357 * Parse the arguments passed to the dcmd and print all or one flow_entry_t 358 * structures 359 */ 360 static int 361 mac_flow_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 362 { 363 uint_t args = 0; 364 365 if (!(flags & DCMD_ADDRSPEC)) { 366 if (mdb_walk_dcmd("mac_flow", "mac_flow", argc, argv) == -1) { 367 mdb_warn("failed to walk 'mac_flow'"); 368 return (DCMD_ERR); 369 } 370 return (DCMD_OK); 371 } 372 if ((mdb_getopts(argc, argv, 373 'a', MDB_OPT_SETBITS, MAC_FLOW_ATTR, &args, 374 'p', MDB_OPT_SETBITS, MAC_FLOW_PROP, &args, 375 'm', MDB_OPT_SETBITS, MAC_FLOW_MISC, &args, 376 'r', MDB_OPT_SETBITS, MAC_FLOW_RX, &args, 377 't', MDB_OPT_SETBITS, MAC_FLOW_TX, &args, 378 's', MDB_OPT_SETBITS, MAC_FLOW_STATS, &args, 379 'u', MDB_OPT_SETBITS, MAC_FLOW_USER, &args, 380 NULL) != argc)) { 381 return (DCMD_USAGE); 382 } 383 if (argc > 2 || (argc == 2 && !(args & MAC_FLOW_USER))) 384 return (DCMD_USAGE); 385 /* 386 * If no arguments was specified or just "-u" was specified then 387 * we default to printing basic information of flows. 388 */ 389 if (args == 0 || args == MAC_FLOW_USER) 390 args |= MAC_FLOW_NONE; 391 392 return (mac_flow_dcmd_output(addr, flags, args)); 393 } 394 395 static void 396 mac_flow_help(void) 397 { 398 mdb_printf("If an address is specified, then flow_entry structure at " 399 "that address is printed. Otherwise all the flows in the system " 400 "are printed.\n"); 401 mdb_printf("Options:\n" 402 "\t-u\tdisplay user defined link & vnic flows.\n" 403 "\t-a\tdisplay flow attributes\n" 404 "\t-p\tdisplay flow properties\n" 405 "\t-r\tdisplay rx side information\n" 406 "\t-t\tdisplay tx side information\n" 407 "\t-s\tdisplay flow statistics\n" 408 "\t-m\tdisplay miscellaneous flow information\n\n"); 409 mdb_printf("%<u>Interpreting Flow type and Flow flags output.%</u>\n"); 410 mdb_printf("Flow Types:\n"); 411 mdb_printf("\t P --> FLOW_PRIMARY_MAC\n"); 412 mdb_printf("\t V --> FLOW_VNIC_MAC\n"); 413 mdb_printf("\t M --> FLOW_MCAST\n"); 414 mdb_printf("\t O --> FLOW_OTHER\n"); 415 mdb_printf("\t U --> FLOW_USER\n"); 416 mdb_printf("\t NS --> FLOW_NO_STATS\n\n"); 417 mdb_printf("Flow Flags:\n"); 418 mdb_printf("\t Q --> FE_QUIESCE\n"); 419 mdb_printf("\t W --> FE_WAITER\n"); 420 mdb_printf("\t T --> FE_FLOW_TAB\n"); 421 mdb_printf("\t G --> FE_G_FLOW_HASH\n"); 422 mdb_printf("\t I --> FE_INCIPIENT\n"); 423 mdb_printf("\t C --> FE_CONDEMNED\n"); 424 mdb_printf("\t NU --> FE_UF_NO_DATAPATH\n"); 425 mdb_printf("\t NC --> FE_MC_NO_DATAPATH\n"); 426 } 427 428 /* 429 * called once by the debugger when the mac_flow walk begins. 430 */ 431 static int 432 mac_flow_walk_init(mdb_walk_state_t *wsp) 433 { 434 if (mdb_layered_walk(LAYERED_WALKER_FOR_FLOW, wsp) == -1) { 435 mdb_warn("failed to walk 'mac_flow'"); 436 return (WALK_ERR); 437 } 438 return (WALK_NEXT); 439 } 440 441 /* 442 * Common walker step funciton for flow_entry_t, mac_soft_ring_set_t and 443 * mac_ring_t. 444 * 445 * Steps through each flow_entry_t and calls the callback function. If the 446 * user executed ::walk mac_flow, it just prints the address or if the user 447 * executed ::mac_flow it displays selected fields of flow_entry_t structure 448 * by calling "mac_flow_dcmd" 449 */ 450 static int 451 mac_common_walk_step(mdb_walk_state_t *wsp) 452 { 453 int status; 454 455 if (wsp->walk_addr == NULL) 456 return (WALK_DONE); 457 458 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 459 wsp->walk_cbdata); 460 461 return (status); 462 } 463 464 static char * 465 mac_srs_txmode2str(mac_tx_srs_mode_t mode) 466 { 467 switch (mode) { 468 case SRS_TX_DEFAULT: 469 return ("DEF"); 470 case SRS_TX_SERIALIZE: 471 return ("SER"); 472 case SRS_TX_FANOUT: 473 return ("FO"); 474 case SRS_TX_BW: 475 return ("BW"); 476 case SRS_TX_BW_FANOUT: 477 return ("BWFO"); 478 case SRS_TX_AGGR: 479 return ("AG"); 480 case SRS_TX_BW_AGGR: 481 return ("BWAG"); 482 } 483 return ("--"); 484 } 485 486 static void 487 mac_srs_help(void) 488 { 489 mdb_printf("If an address is specified, then mac_soft_ring_set " 490 "structure at that address is printed. Otherwise all the " 491 "SRS in the system are printed.\n"); 492 mdb_printf("Options:\n" 493 "\t-r\tdisplay recieve side SRS structures\n" 494 "\t-t\tdisplay transmit side SRS structures\n" 495 "\t-s\tdisplay statistics for RX or TX side\n" 496 "\t-c\tdisplay CPU binding for RX or TX side\n" 497 "\t-v\tverbose flag for CPU binding to list cpus\n" 498 "\t-i\tdisplay mac_ring_t and interrupt information\n" 499 "Note: use -r or -t (to specify RX or TX side respectively) along " 500 "with -c or -s\n"); 501 mdb_printf("\n%<u>Interpreting TX Modes%</u>\n"); 502 mdb_printf("\t DEF --> Default\n"); 503 mdb_printf("\t SER --> Serialize\n"); 504 mdb_printf("\t FO --> Fanout\n"); 505 mdb_printf("\t BW --> Bandwidth\n"); 506 mdb_printf("\tBWFO --> Bandwidth Fanout\n"); 507 mdb_printf("\t AG --> Aggr\n"); 508 mdb_printf("\tBWAG --> Bandwidth Aggr\n"); 509 } 510 511 /* 512 * In verbose mode "::mac_srs -rcv or ::mac_srs -tcv", we print the CPUs 513 * assigned to a link and CPUS assigned to the soft rings. 514 * 'len' is used for formatting the output and represents the number of 515 * spaces between CPU list and Fanout CPU list in the output. 516 */ 517 static boolean_t 518 mac_srs_print_cpu(int *i, uint32_t cnt, uint32_t *cpu_list, int *len) 519 { 520 int num = 0; 521 522 if (*i == 0) 523 mdb_printf("("); 524 else 525 mdb_printf(" "); 526 while (*i < cnt) { 527 /* We print 6 CPU's at a time to keep display within 80 cols */ 528 if (((num + 1) % 7) == 0) { 529 if (len != NULL) 530 *len = 2; 531 return (B_FALSE); 532 } 533 mdb_printf("%02x%c", cpu_list[*i], ((*i == cnt - 1)?')':',')); 534 ++*i; 535 ++num; 536 } 537 if (len != NULL) 538 *len = (7 - num) * 3; 539 return (B_TRUE); 540 } 541 542 static int 543 mac_srs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 544 { 545 uint_t args = MAC_SRS_NONE; 546 mac_soft_ring_set_t srs; 547 mac_client_impl_t mci; 548 549 if (!(flags & DCMD_ADDRSPEC)) { 550 if (mdb_walk_dcmd("mac_srs", "mac_srs", argc, argv) == -1) { 551 mdb_warn("failed to walk 'mac_srs'"); 552 return (DCMD_ERR); 553 } 554 return (DCMD_OK); 555 } 556 if (mdb_getopts(argc, argv, 557 'r', MDB_OPT_SETBITS, MAC_SRS_RX, &args, 558 't', MDB_OPT_SETBITS, MAC_SRS_TX, &args, 559 'c', MDB_OPT_SETBITS, MAC_SRS_CPU, &args, 560 'v', MDB_OPT_SETBITS, MAC_SRS_VERBOSE, &args, 561 'i', MDB_OPT_SETBITS, MAC_SRS_INTR, &args, 562 's', MDB_OPT_SETBITS, MAC_SRS_STAT, &args, 563 NULL) != argc) { 564 return (DCMD_USAGE); 565 } 566 567 if (argc > 2) 568 return (DCMD_USAGE); 569 570 if (mdb_vread(&srs, sizeof (srs), addr) == -1) { 571 mdb_warn("failed to read struct mac_soft_ring_set_s at %p", 572 addr); 573 return (DCMD_ERR); 574 } 575 if (mdb_vread(&mci, sizeof (mci), (uintptr_t)srs.srs_mcip) == -1) { 576 mdb_warn("failed to read struct mac_client_impl_t at %p " 577 "for SRS %p", srs.srs_mcip, addr); 578 return (DCMD_ERR); 579 } 580 581 switch (args) { 582 case MAC_SRS_RX: { 583 if (DCMD_HDRSPEC(flags)) { 584 mdb_printf("%?s %-20s %-8s %-8s %8s " 585 "%8s %3s\n", 586 "", "", "", "", "MBLK", 587 "Q", "SR"); 588 mdb_printf("%<u>%?s %-20s %-8s %-8s %8s " 589 "%8s %3s%</u>\n", 590 "ADDR", "LINK_NAME", "STATE", "TYPE", "CNT", 591 "BYTES", "CNT"); 592 } 593 if (srs.srs_type & SRST_TX) 594 return (DCMD_OK); 595 mdb_printf("%?p %-20s %08x %08x " 596 "%8d %8d %3d\n", 597 addr, mci.mci_name, srs.srs_state, srs.srs_type, 598 srs.srs_count, srs.srs_size, srs.srs_soft_ring_count); 599 break; 600 } 601 case MAC_SRS_TX: { 602 if (DCMD_HDRSPEC(flags)) { 603 mdb_printf("%?s %-16s %-4s %-8s " 604 "%-8s %8s %8s %3s\n", 605 "", "", "TX", "", 606 "", "MBLK", "Q", "SR"); 607 mdb_printf("%<u>%?s %-16s %-4s %-8s " 608 "%-8s %8s %8s %3s%</u>\n", 609 "ADDR", "LINK_NAME", "MODE", "STATE", 610 "TYPE", "CNT", "BYTES", "CNT"); 611 } 612 if (!(srs.srs_type & SRST_TX)) 613 return (DCMD_OK); 614 615 mdb_printf("%?p %-16s %-4s " 616 "%08x %08x %8d %8d %3d\n", 617 addr, mci.mci_name, mac_srs_txmode2str(srs.srs_tx.st_mode), 618 srs.srs_state, srs.srs_type, srs.srs_count, srs.srs_size, 619 srs.srs_tx_ring_count); 620 break; 621 } 622 case MAC_SRS_RXCPU: { 623 mac_cpus_t mc = srs.srs_cpu; 624 625 if (DCMD_HDRSPEC(flags)) { 626 mdb_printf("%?s %-20s %-4s %-4s " 627 "%-6s %-4s %-7s\n", 628 "", "", "NUM", "POLL", 629 "WORKER", "INTR", "FANOUT"); 630 mdb_printf("%<u>%?s %-20s %-4s %-4s " 631 "%-6s %-4s %-7s%</u>\n", 632 "ADDR", "LINK_NAME", "CPUS", "CPU", 633 "CPU", "CPU", "CPU_CNT"); 634 } 635 if ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX)) 636 return (DCMD_OK); 637 mdb_printf("%?p %-20s %-4d %-4d " 638 "%-6d %-4d %-7d\n", 639 addr, mci.mci_name, mc.mc_ncpus, mc.mc_rx_pollid, 640 mc.mc_rx_workerid, mc.mc_rx_intr_cpu, mc.mc_rx_fanout_cnt); 641 break; 642 643 } 644 case MAC_SRS_TXCPU: { 645 mac_cpus_t mc = srs.srs_cpu; 646 mac_soft_ring_t *s_ringp, s_ring; 647 boolean_t first = B_TRUE; 648 int i; 649 650 if (DCMD_HDRSPEC(flags)) { 651 mdb_printf("%?s %-12s %?s %8s %8s %8s\n", 652 "", "", "SOFT", "WORKER", "INTR", "RETARGETED"); 653 mdb_printf("%<u>%?s %-12s %?s %8s %8s %8s%</u>\n", 654 "ADDR", "LINK_NAME", "RING", "CPU", "CPU", "CPU"); 655 } 656 if (!(srs.srs_type & SRST_TX)) 657 return (DCMD_OK); 658 659 mdb_printf("%?p %-12s ", addr, mci.mci_name); 660 661 /* 662 * Case of no soft rings, print the info from 663 * mac_srs_tx_t. 664 */ 665 if (srs.srs_tx_ring_count == 0) { 666 mdb_printf("%?p %8d %8d %8d\n", 667 0, mc.mc_tx_fanout_cpus[0], 668 mc.mc_tx_intr_cpu[0], 669 mc.mc_tx_retargeted_cpu[0]); 670 break; 671 } 672 673 for (s_ringp = srs.srs_soft_ring_head, i = 0; s_ringp != NULL; 674 s_ringp = s_ring.s_ring_next, i++) { 675 (void) mdb_vread(&s_ring, sizeof (s_ring), 676 (uintptr_t)s_ringp); 677 if (first) { 678 mdb_printf("%?p %8d %8d %8d\n", 679 s_ringp, mc.mc_tx_fanout_cpus[i], 680 mc.mc_tx_intr_cpu[i], 681 mc.mc_tx_retargeted_cpu[i]); 682 first = B_FALSE; 683 continue; 684 } 685 mdb_printf("%?s %-12s %?p %8d %8d %8d\n", 686 "", "", s_ringp, mc.mc_tx_fanout_cpus[i], 687 mc.mc_tx_intr_cpu[i], mc.mc_tx_retargeted_cpu[i]); 688 } 689 break; 690 } 691 case MAC_SRS_TXINTR: { 692 mac_cpus_t mc = srs.srs_cpu; 693 mac_soft_ring_t *s_ringp, s_ring; 694 mac_ring_t *m_ringp, m_ring; 695 boolean_t first = B_TRUE; 696 int i; 697 698 if (DCMD_HDRSPEC(flags)) { 699 mdb_printf("%?s %-12s %?s %8s %?s %6s %6s\n", 700 "", "", "SOFT", "WORKER", "MAC", "", "INTR"); 701 mdb_printf("%<u>%?s %-12s %?s %8s %?s %6s %6s%</u>\n", 702 "ADDR", "LINK_NAME", "RING", "CPU", "RING", 703 "SHARED", "CPU"); 704 } 705 if (!(srs.srs_type & SRST_TX)) 706 return (DCMD_OK); 707 708 mdb_printf("%?p %-12s ", addr, mci.mci_name); 709 710 /* 711 * Case of no soft rings, print the info from 712 * mac_srs_tx_t. 713 */ 714 if (srs.srs_tx_ring_count == 0) { 715 m_ringp = srs.srs_tx.st_arg2; 716 if (m_ringp != NULL) { 717 (void) mdb_vread(&m_ring, sizeof (m_ring), 718 (uintptr_t)m_ringp); 719 mdb_printf("%?p %8d %?p %6d %6d\n", 720 0, mc.mc_tx_fanout_cpus[0], m_ringp, 721 m_ring.mr_info.mri_intr.mi_ddi_shared, 722 mc.mc_tx_retargeted_cpu[0]); 723 } else { 724 mdb_printf("%?p %8d %?p %6d %6d\n", 725 0, mc.mc_tx_fanout_cpus[0], 0, 726 0, mc.mc_tx_retargeted_cpu[0]); 727 } 728 break; 729 } 730 731 for (s_ringp = srs.srs_soft_ring_head, i = 0; s_ringp != NULL; 732 s_ringp = s_ring.s_ring_next, i++) { 733 (void) mdb_vread(&s_ring, sizeof (s_ring), 734 (uintptr_t)s_ringp); 735 m_ringp = s_ring.s_ring_tx_arg2; 736 (void) mdb_vread(&m_ring, sizeof (m_ring), 737 (uintptr_t)m_ringp); 738 if (first) { 739 mdb_printf("%?p %8d %?p %6d %6d\n", 740 s_ringp, mc.mc_tx_fanout_cpus[i], 741 m_ringp, 742 m_ring.mr_info.mri_intr.mi_ddi_shared, 743 mc.mc_tx_retargeted_cpu[i]); 744 first = B_FALSE; 745 continue; 746 } 747 mdb_printf("%?s %-12s %?p %8d %?p %6d %6d\n", 748 "", "", s_ringp, mc.mc_tx_fanout_cpus[i], 749 m_ringp, m_ring.mr_info.mri_intr.mi_ddi_shared, 750 mc.mc_tx_retargeted_cpu[i]); 751 } 752 break; 753 } 754 case MAC_SRS_RXINTR: { 755 mac_cpus_t mc = srs.srs_cpu; 756 mac_ring_t *m_ringp, m_ring; 757 758 if (DCMD_HDRSPEC(flags)) { 759 mdb_printf("%?s %-12s %?s %8s %6s %6s\n", 760 "", "", "MAC", "", "POLL", "INTR"); 761 mdb_printf("%<u>%?s %-12s %?s %8s %6s %6s%</u>\n", 762 "ADDR", "LINK_NAME", "RING", "SHARED", "CPU", 763 "CPU"); 764 } 765 if ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX)) 766 return (DCMD_OK); 767 768 mdb_printf("%?p %-12s ", addr, mci.mci_name); 769 770 m_ringp = srs.srs_ring; 771 if (m_ringp != NULL) { 772 (void) mdb_vread(&m_ring, sizeof (m_ring), 773 (uintptr_t)m_ringp); 774 mdb_printf("%?p %8d %6d %6d\n", 775 m_ringp, m_ring.mr_info.mri_intr.mi_ddi_shared, 776 mc.mc_rx_pollid, mc.mc_rx_intr_cpu); 777 } else { 778 mdb_printf("%?p %8d %6d %6d\n", 779 0, 0, mc.mc_rx_pollid, mc.mc_rx_intr_cpu); 780 } 781 break; 782 } 783 case MAC_SRS_RXCPUVERBOSE: 784 case MAC_SRS_TXCPUVERBOSE: { 785 mac_cpus_t mc = srs.srs_cpu; 786 int cpu_index = 0, fanout_index = 0, len = 0; 787 boolean_t cpu_done = B_FALSE, fanout_done = B_FALSE; 788 789 if (DCMD_HDRSPEC(flags)) { 790 mdb_printf("%?s %-20s %-20s %-20s\n", 791 "", "", "CPU_COUNT", "FANOUT_CPU_COUNT"); 792 mdb_printf("%<u>%?s %-20s " 793 "%-20s %-20s%</u>\n", 794 "ADDR", "LINK_NAME", 795 "(CPU_LIST)", "(CPU_LIST)"); 796 } 797 if (((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX)) || 798 ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX))) 799 return (DCMD_OK); 800 mdb_printf("%?p %-20s %-20d %-20d\n", addr, mci.mci_name, 801 mc.mc_ncpus, mc.mc_rx_fanout_cnt); 802 if (mc.mc_ncpus == 0 && mc.mc_rx_fanout_cnt == 0) 803 break; 804 /* print all cpus and cpus for soft rings */ 805 while (!cpu_done || !fanout_done) { 806 boolean_t old_value = cpu_done; 807 808 if (!cpu_done) { 809 mdb_printf("%?s %20s ", "", ""); 810 cpu_done = mac_srs_print_cpu(&cpu_index, 811 mc.mc_ncpus, mc.mc_cpus, &len); 812 } 813 if (!fanout_done) { 814 if (old_value) 815 mdb_printf("%?s %-40s", "", ""); 816 else 817 mdb_printf("%*s", len, ""); 818 fanout_done = mac_srs_print_cpu(&fanout_index, 819 mc.mc_rx_fanout_cnt, 820 mc.mc_rx_fanout_cpus, NULL); 821 } 822 mdb_printf("\n"); 823 } 824 break; 825 } 826 case MAC_SRS_RXSTAT: { 827 mac_rx_stats_t *mac_rx_stat = &srs.srs_rx.sr_stat; 828 829 if (DCMD_HDRSPEC(flags)) { 830 mdb_printf("%?s %-16s %8s %8s " 831 "%8s %8s %8s\n", 832 "", "", "INTR", "POLL", 833 "CHAIN", "CHAIN", "CHAIN"); 834 mdb_printf("%<u>%?s %-16s %8s %8s " 835 "%8s %8s %8s%</u>\n", 836 "ADDR", "LINK_NAME", "COUNT", "COUNT", 837 "<10", "10-50", ">50"); 838 } 839 if (srs.srs_type & SRST_TX) 840 return (DCMD_OK); 841 mdb_printf("%?p %-16s %8d " 842 "%8d %8d " 843 "%8d %8d\n", 844 addr, mci.mci_name, mac_rx_stat->mrs_intrcnt, 845 mac_rx_stat->mrs_pollcnt, mac_rx_stat->mrs_chaincntundr10, 846 mac_rx_stat->mrs_chaincnt10to50, 847 mac_rx_stat->mrs_chaincntover50); 848 break; 849 } 850 case MAC_SRS_TXSTAT: { 851 mac_tx_stats_t *mac_tx_stat = &srs.srs_tx.st_stat; 852 mac_soft_ring_t *s_ringp, s_ring; 853 boolean_t first = B_TRUE; 854 855 if (DCMD_HDRSPEC(flags)) { 856 mdb_printf("%?s %-20s %?s %8s %8s %8s\n", 857 "", "", "SOFT", "DROP", "BLOCK", "UNBLOCK"); 858 mdb_printf("%<u>%?s %-20s %?s %8s %8s %8s%</u>\n", 859 "ADDR", "LINK_NAME", "RING", "COUNT", "COUNT", 860 "COUNT"); 861 } 862 if (!(srs.srs_type & SRST_TX)) 863 return (DCMD_OK); 864 865 mdb_printf("%?p %-20s ", addr, mci.mci_name); 866 867 /* 868 * Case of no soft rings, print the info from 869 * mac_srs_tx_t. 870 */ 871 if (srs.srs_tx_ring_count == 0) { 872 mdb_printf("%?p %8d %8d %8d\n", 873 0, mac_tx_stat->mts_sdrops, 874 mac_tx_stat->mts_blockcnt, 875 mac_tx_stat->mts_unblockcnt); 876 break; 877 } 878 879 for (s_ringp = srs.srs_soft_ring_head; s_ringp != NULL; 880 s_ringp = s_ring.s_ring_next) { 881 (void) mdb_vread(&s_ring, sizeof (s_ring), 882 (uintptr_t)s_ringp); 883 mac_tx_stat = &s_ring.s_st_stat; 884 if (first) { 885 mdb_printf("%?p %8d %8d %8d\n", 886 s_ringp, mac_tx_stat->mts_sdrops, 887 mac_tx_stat->mts_blockcnt, 888 mac_tx_stat->mts_unblockcnt); 889 first = B_FALSE; 890 continue; 891 } 892 mdb_printf("%?s %-20s %?p %8d %8d %8d\n", 893 "", "", s_ringp, mac_tx_stat->mts_sdrops, 894 mac_tx_stat->mts_blockcnt, 895 mac_tx_stat->mts_unblockcnt); 896 } 897 break; 898 } 899 case MAC_SRS_NONE: { 900 if (DCMD_HDRSPEC(flags)) { 901 mdb_printf("%<u>%?s %-20s %?s %?s %-3s%</u>\n", 902 "ADDR", "LINK_NAME", "FLENT", "HW RING", "DIR"); 903 } 904 mdb_printf("%?p %-20s %?p %?p " 905 "%-3s ", 906 addr, mci.mci_name, srs.srs_flent, srs.srs_ring, 907 (srs.srs_type & SRST_TX ? "TX" : "RX")); 908 break; 909 } 910 default: 911 return (DCMD_USAGE); 912 } 913 return (DCMD_OK); 914 } 915 916 static int 917 mac_srs_walk_init(mdb_walk_state_t *wsp) 918 { 919 if (mdb_layered_walk(LAYERED_WALKER_FOR_SRS, wsp) == -1) { 920 mdb_warn("failed to walk 'mac_srs'"); 921 return (WALK_ERR); 922 } 923 return (WALK_NEXT); 924 } 925 926 static char * 927 mac_ring_state2str(mac_ring_state_t state) 928 { 929 switch (state) { 930 case MR_FREE: 931 return ("free"); 932 case MR_NEWLY_ADDED: 933 return ("new"); 934 case MR_INUSE: 935 return ("inuse"); 936 } 937 return ("--"); 938 } 939 940 static char * 941 mac_ring_classify2str(mac_classify_type_t classify) 942 { 943 switch (classify) { 944 case MAC_NO_CLASSIFIER: 945 return ("no"); 946 case MAC_SW_CLASSIFIER: 947 return ("sw"); 948 case MAC_HW_CLASSIFIER: 949 return ("hw"); 950 } 951 return ("--"); 952 } 953 954 static int 955 mac_ring_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 956 { 957 mac_ring_t ring; 958 mac_group_t group; 959 flow_entry_t flent; 960 mac_soft_ring_set_t srs; 961 962 if (!(flags & DCMD_ADDRSPEC)) { 963 if (mdb_walk_dcmd("mac_ring", "mac_ring", argc, argv) == -1) { 964 mdb_warn("failed to walk 'mac_ring'"); 965 return (DCMD_ERR); 966 } 967 return (DCMD_OK); 968 } 969 if (mdb_vread(&ring, sizeof (ring), addr) == -1) { 970 mdb_warn("failed to read struct mac_ring_s at %p", addr); 971 return (DCMD_ERR); 972 } 973 bzero(&flent, sizeof (flent)); 974 if (mdb_vread(&srs, sizeof (srs), (uintptr_t)ring.mr_srs) != -1) { 975 (void) mdb_vread(&flent, sizeof (flent), 976 (uintptr_t)srs.srs_flent); 977 } 978 (void) mdb_vread(&group, sizeof (group), (uintptr_t)ring.mr_gh); 979 if (DCMD_HDRSPEC(flags)) { 980 mdb_printf("%<u>%?s %4s %5s %4s %?s " 981 "%5s %?s %?s %s %</u>\n", 982 "ADDR", "TYPE", "STATE", "FLAG", "GROUP", 983 "CLASS", "MIP", "SRS", "FLOW NAME"); 984 } 985 mdb_printf("%?p %-4s " 986 "%5s %04x " 987 "%?p %-5s " 988 "%?p %?p %s\n", 989 addr, ((ring.mr_type == 1)? "RX" : "TX"), 990 mac_ring_state2str(ring.mr_state), ring.mr_flag, 991 ring.mr_gh, mac_ring_classify2str(ring.mr_classify_type), 992 group.mrg_mh, ring.mr_srs, flent.fe_flow_name); 993 return (DCMD_OK); 994 } 995 996 static int 997 mac_ring_walk_init(mdb_walk_state_t *wsp) 998 { 999 if (mdb_layered_walk(LAYERED_WALKER_FOR_RING, wsp) == -1) { 1000 mdb_warn("failed to walk `mac_ring`"); 1001 return (WALK_ERR); 1002 } 1003 return (WALK_NEXT); 1004 } 1005 1006 static void 1007 mac_ring_help(void) 1008 { 1009 mdb_printf("If an address is specified, then mac_ring_t " 1010 "structure at that address is printed. Otherwise all the " 1011 "hardware rings in the system are printed.\n"); 1012 } 1013 1014 /* 1015 * To walk groups we have to have our own somewhat-complicated state machine. We 1016 * basically start by walking the mac_impl_t walker as all groups are stored off 1017 * of the various mac_impl_t in the system. The tx and rx rings are kept 1018 * separately. So we'll need to walk through all the rx rings and then all of 1019 * the tx rings. 1020 */ 1021 static int 1022 mac_group_walk_init(mdb_walk_state_t *wsp) 1023 { 1024 int ret; 1025 1026 if (wsp->walk_addr != NULL) { 1027 mdb_warn("non-global walks are not supported\n"); 1028 return (WALK_ERR); 1029 } 1030 1031 if ((ret = mdb_layered_walk(LAYERED_WALKER_FOR_GROUP, wsp)) == -1) { 1032 mdb_warn("couldn't walk '%s'", LAYERED_WALKER_FOR_GROUP); 1033 return (ret); 1034 } 1035 1036 return (WALK_NEXT); 1037 } 1038 1039 static int 1040 mac_group_walk_step(mdb_walk_state_t *wsp) 1041 { 1042 int ret; 1043 mac_impl_t mi; 1044 mac_group_t mg; 1045 uintptr_t mgp; 1046 1047 /* 1048 * Nothing to do if we can't find the layer above us. But the kmem 1049 * walkers are a bit unsporting, they don't actually read in the data 1050 * for us. 1051 */ 1052 if (wsp->walk_addr == NULL) 1053 return (WALK_DONE); 1054 1055 if (mdb_vread(&mi, sizeof (mac_impl_t), wsp->walk_addr) == -1) { 1056 mdb_warn("failed to read mac_impl_t at %p", wsp->walk_addr); 1057 return (DCMD_ERR); 1058 } 1059 1060 /* 1061 * First go for rx groups, then tx groups. 1062 */ 1063 mgp = (uintptr_t)mi.mi_rx_groups; 1064 while (mgp != NULL) { 1065 if (mdb_vread(&mg, sizeof (mac_group_t), mgp) == -1) { 1066 mdb_warn("failed to read mac_group_t at %p", mgp); 1067 return (WALK_ERR); 1068 } 1069 1070 ret = wsp->walk_callback(mgp, &mg, wsp->walk_cbdata); 1071 if (ret != WALK_NEXT) 1072 return (ret); 1073 mgp = (uintptr_t)mg.mrg_next; 1074 } 1075 1076 mgp = (uintptr_t)mi.mi_tx_groups; 1077 while (mgp != NULL) { 1078 if (mdb_vread(&mg, sizeof (mac_group_t), mgp) == -1) { 1079 mdb_warn("failed to read mac_group_t at %p", mgp); 1080 return (WALK_ERR); 1081 } 1082 1083 ret = wsp->walk_callback(mgp, &mg, wsp->walk_cbdata); 1084 if (ret != WALK_NEXT) 1085 return (ret); 1086 mgp = (uintptr_t)mg.mrg_next; 1087 } 1088 1089 return (WALK_NEXT); 1090 } 1091 1092 static int 1093 mac_group_count_clients(mac_group_t *mgp) 1094 { 1095 int clients = 0; 1096 uintptr_t mcp = (uintptr_t)mgp->mrg_clients; 1097 1098 while (mcp != NULL) { 1099 mac_grp_client_t c; 1100 1101 if (mdb_vread(&c, sizeof (c), mcp) == -1) { 1102 mdb_warn("failed to read mac_grp_client_t at %p", mcp); 1103 return (-1); 1104 } 1105 clients++; 1106 mcp = (uintptr_t)c.mgc_next; 1107 } 1108 1109 return (clients); 1110 } 1111 1112 static const char * 1113 mac_group_type(mac_group_t *mgp) 1114 { 1115 const char *ret; 1116 1117 switch (mgp->mrg_type) { 1118 case MAC_RING_TYPE_RX: 1119 ret = "RECEIVE"; 1120 break; 1121 case MAC_RING_TYPE_TX: 1122 ret = "TRANSMIT"; 1123 break; 1124 default: 1125 ret = "UNKNOWN"; 1126 break; 1127 } 1128 1129 return (ret); 1130 } 1131 1132 static const char * 1133 mac_group_state(mac_group_t *mgp) 1134 { 1135 const char *ret; 1136 1137 switch (mgp->mrg_state) { 1138 case MAC_GROUP_STATE_UNINIT: 1139 ret = "UNINT"; 1140 break; 1141 case MAC_GROUP_STATE_REGISTERED: 1142 ret = "REGISTERED"; 1143 break; 1144 case MAC_GROUP_STATE_RESERVED: 1145 ret = "RESERVED"; 1146 break; 1147 case MAC_GROUP_STATE_SHARED: 1148 ret = "SHARED"; 1149 break; 1150 default: 1151 ret = "UNKNOWN"; 1152 break; 1153 } 1154 1155 return (ret); 1156 } 1157 1158 static int 1159 mac_group_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1160 { 1161 uint_t args = MAC_SRS_NONE; 1162 mac_group_t mg; 1163 int clients; 1164 1165 if (!(flags & DCMD_ADDRSPEC)) { 1166 if (mdb_walk_dcmd("mac_group", "mac_group", argc, argv) == -1) { 1167 mdb_warn("failed to walk 'mac_group'"); 1168 return (DCMD_ERR); 1169 } 1170 1171 return (DCMD_OK); 1172 } 1173 1174 if (mdb_getopts(argc, argv, 1175 'r', MDB_OPT_SETBITS, MAC_GROUP_RX, &args, 1176 't', MDB_OPT_SETBITS, MAC_GROUP_TX, &args, 1177 'u', MDB_OPT_SETBITS, MAC_GROUP_UNINIT, &args, 1178 NULL) != argc) 1179 return (DCMD_USAGE); 1180 1181 if (mdb_vread(&mg, sizeof (mac_group_t), addr) == -1) { 1182 mdb_warn("failed to read mac_group_t at %p", addr); 1183 return (DCMD_ERR); 1184 } 1185 1186 if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 1187 mdb_printf("%<u>%-?s %-8s %-10s %6s %8s %-?s%</u>\n", 1188 "ADDR", "TYPE", "STATE", "NRINGS", "NCLIENTS", "RINGS"); 1189 } 1190 1191 if ((args & MAC_GROUP_RX) != 0 && mg.mrg_type != MAC_RING_TYPE_RX) 1192 return (DCMD_OK); 1193 if ((args & MAC_GROUP_TX) != 0 && mg.mrg_type != MAC_RING_TYPE_TX) 1194 return (DCMD_OK); 1195 1196 /* 1197 * By default, don't show uninitialized groups. They're not very 1198 * interesting. They have no rings and no clients. 1199 */ 1200 if (mg.mrg_state == MAC_GROUP_STATE_UNINIT && 1201 (args & MAC_GROUP_UNINIT) == 0) 1202 return (DCMD_OK); 1203 1204 if (flags & DCMD_PIPE_OUT) { 1205 mdb_printf("%lr\n", addr); 1206 return (DCMD_OK); 1207 } 1208 1209 clients = mac_group_count_clients(&mg); 1210 mdb_printf("%?p %-8s %-10s %6d %8d %?p\n", addr, mac_group_type(&mg), 1211 mac_group_state(&mg), mg.mrg_cur_count, clients, mg.mrg_rings); 1212 1213 return (DCMD_OK); 1214 } 1215 1216 /* Supported dee-commands */ 1217 static const mdb_dcmd_t dcmds[] = { 1218 {"mac_flow", "?[-u] [-aprtsm]", "display Flow Entry structures", 1219 mac_flow_dcmd, mac_flow_help}, 1220 {"mac_group", "?[-rtu]", "display MAC Ring Groups", mac_group_dcmd, 1221 NULL }, 1222 {"mac_srs", "?[ -r[i|s|c[v]] | -t[i|s|c[v]] ]", 1223 "display MAC Soft Ring Set" " structures", mac_srs_dcmd, 1224 mac_srs_help}, 1225 {"mac_ring", "?", "display MAC ring (hardware) structures", 1226 mac_ring_dcmd, mac_ring_help}, 1227 { NULL } 1228 }; 1229 1230 /* Supported walkers */ 1231 static const mdb_walker_t walkers[] = { 1232 {"mac_flow", "walk list of flow entry structures", mac_flow_walk_init, 1233 mac_common_walk_step, NULL, NULL}, 1234 {"mac_group", "walk list of ring group structures", mac_group_walk_init, 1235 mac_group_walk_step, NULL, NULL}, 1236 {"mac_srs", "walk list of mac soft ring set structures", 1237 mac_srs_walk_init, mac_common_walk_step, NULL, NULL}, 1238 {"mac_ring", "walk list of mac ring structures", mac_ring_walk_init, 1239 mac_common_walk_step, NULL, NULL}, 1240 { NULL } 1241 }; 1242 1243 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 1244 1245 const mdb_modinfo_t * 1246 _mdb_init(void) 1247 { 1248 return (&modinfo); 1249 } 1250