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 /* 336 * Sum bytes for all Rx SRS. 337 */ 338 for (i = 0; i < fe.fe_rx_srs_cnt; i++) { 339 mac_srs = (mac_soft_ring_set_t *)(fe.fe_rx_srs[i]); 340 if (mdb_vread(&mac_rx_stat, sizeof (mac_rx_stats_t), 341 (uintptr_t)&mac_srs->srs_rx.sr_stat) == -1) { 342 mdb_warn("failed to read mac_rx_stats_t at %p", 343 &mac_srs->srs_rx.sr_stat); 344 return (DCMD_ERR); 345 } 346 347 totibytes += mac_rx_stat.mrs_intrbytes + 348 mac_rx_stat.mrs_pollbytes + 349 mac_rx_stat.mrs_lclbytes; 350 } 351 352 /* 353 * Sum bytes for Tx SRS. 354 */ 355 mac_srs = (mac_soft_ring_set_t *)(fe.fe_tx_srs); 356 if (mac_srs != NULL) { 357 if (mdb_vread(&mac_tx_stat, sizeof (mac_tx_stats_t), 358 (uintptr_t)&mac_srs->srs_tx.st_stat) == -1) { 359 mdb_warn("failed to read max_tx_stats_t at %p", 360 &mac_srs->srs_tx.st_stat); 361 return (DCMD_ERR); 362 } 363 364 totobytes = mac_tx_stat.mts_obytes; 365 } 366 367 mdb_printf("%?p %-32s %16llu %16llu\n", 368 addr, fe.fe_flow_name, totibytes, totobytes); 369 370 break; 371 } 372 } 373 return (DCMD_OK); 374 } 375 376 /* 377 * Parse the arguments passed to the dcmd and print all or one flow_entry_t 378 * structures 379 */ 380 static int 381 mac_flow_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 382 { 383 uint_t args = 0; 384 385 if (!(flags & DCMD_ADDRSPEC)) { 386 if (mdb_walk_dcmd("mac_flow", "mac_flow", argc, argv) == -1) { 387 mdb_warn("failed to walk 'mac_flow'"); 388 return (DCMD_ERR); 389 } 390 return (DCMD_OK); 391 } 392 if ((mdb_getopts(argc, argv, 393 'a', MDB_OPT_SETBITS, MAC_FLOW_ATTR, &args, 394 'p', MDB_OPT_SETBITS, MAC_FLOW_PROP, &args, 395 'm', MDB_OPT_SETBITS, MAC_FLOW_MISC, &args, 396 'r', MDB_OPT_SETBITS, MAC_FLOW_RX, &args, 397 't', MDB_OPT_SETBITS, MAC_FLOW_TX, &args, 398 's', MDB_OPT_SETBITS, MAC_FLOW_STATS, &args, 399 'u', MDB_OPT_SETBITS, MAC_FLOW_USER, &args, 400 NULL) != argc)) { 401 return (DCMD_USAGE); 402 } 403 if (argc > 2 || (argc == 2 && !(args & MAC_FLOW_USER))) 404 return (DCMD_USAGE); 405 /* 406 * If no arguments was specified or just "-u" was specified then 407 * we default to printing basic information of flows. 408 */ 409 if (args == 0 || args == MAC_FLOW_USER) 410 args |= MAC_FLOW_NONE; 411 412 return (mac_flow_dcmd_output(addr, flags, args)); 413 } 414 415 static void 416 mac_flow_help(void) 417 { 418 mdb_printf("If an address is specified, then flow_entry structure at " 419 "that address is printed. Otherwise all the flows in the system " 420 "are printed.\n"); 421 mdb_printf("Options:\n" 422 "\t-u\tdisplay user defined link & vnic flows.\n" 423 "\t-a\tdisplay flow attributes\n" 424 "\t-p\tdisplay flow properties\n" 425 "\t-r\tdisplay rx side information\n" 426 "\t-t\tdisplay tx side information\n" 427 "\t-s\tdisplay flow statistics\n" 428 "\t-m\tdisplay miscellaneous flow information\n\n"); 429 mdb_printf("%<u>Interpreting Flow type and Flow flags output.%</u>\n"); 430 mdb_printf("Flow Types:\n"); 431 mdb_printf("\t P --> FLOW_PRIMARY_MAC\n"); 432 mdb_printf("\t V --> FLOW_VNIC_MAC\n"); 433 mdb_printf("\t M --> FLOW_MCAST\n"); 434 mdb_printf("\t O --> FLOW_OTHER\n"); 435 mdb_printf("\t U --> FLOW_USER\n"); 436 mdb_printf("\t NS --> FLOW_NO_STATS\n\n"); 437 mdb_printf("Flow Flags:\n"); 438 mdb_printf("\t Q --> FE_QUIESCE\n"); 439 mdb_printf("\t W --> FE_WAITER\n"); 440 mdb_printf("\t T --> FE_FLOW_TAB\n"); 441 mdb_printf("\t G --> FE_G_FLOW_HASH\n"); 442 mdb_printf("\t I --> FE_INCIPIENT\n"); 443 mdb_printf("\t C --> FE_CONDEMNED\n"); 444 mdb_printf("\t NU --> FE_UF_NO_DATAPATH\n"); 445 mdb_printf("\t NC --> FE_MC_NO_DATAPATH\n"); 446 } 447 448 /* 449 * called once by the debugger when the mac_flow walk begins. 450 */ 451 static int 452 mac_flow_walk_init(mdb_walk_state_t *wsp) 453 { 454 if (mdb_layered_walk(LAYERED_WALKER_FOR_FLOW, wsp) == -1) { 455 mdb_warn("failed to walk 'mac_flow'"); 456 return (WALK_ERR); 457 } 458 return (WALK_NEXT); 459 } 460 461 /* 462 * Common walker step funciton for flow_entry_t, mac_soft_ring_set_t and 463 * mac_ring_t. 464 * 465 * Steps through each flow_entry_t and calls the callback function. If the 466 * user executed ::walk mac_flow, it just prints the address or if the user 467 * executed ::mac_flow it displays selected fields of flow_entry_t structure 468 * by calling "mac_flow_dcmd" 469 */ 470 static int 471 mac_common_walk_step(mdb_walk_state_t *wsp) 472 { 473 int status; 474 475 if (wsp->walk_addr == 0) 476 return (WALK_DONE); 477 478 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 479 wsp->walk_cbdata); 480 481 return (status); 482 } 483 484 static char * 485 mac_srs_txmode2str(mac_tx_srs_mode_t mode) 486 { 487 switch (mode) { 488 case SRS_TX_DEFAULT: 489 return ("DEF"); 490 case SRS_TX_SERIALIZE: 491 return ("SER"); 492 case SRS_TX_FANOUT: 493 return ("FO"); 494 case SRS_TX_BW: 495 return ("BW"); 496 case SRS_TX_BW_FANOUT: 497 return ("BWFO"); 498 case SRS_TX_AGGR: 499 return ("AG"); 500 case SRS_TX_BW_AGGR: 501 return ("BWAG"); 502 } 503 return ("--"); 504 } 505 506 static void 507 mac_srs_help(void) 508 { 509 mdb_printf("If an address is specified, then mac_soft_ring_set " 510 "structure at that address is printed. Otherwise all the " 511 "SRS in the system are printed.\n"); 512 mdb_printf("Options:\n" 513 "\t-r\tdisplay recieve side SRS structures\n" 514 "\t-t\tdisplay transmit side SRS structures\n" 515 "\t-s\tdisplay statistics for RX or TX side\n" 516 "\t-c\tdisplay CPU binding for RX or TX side\n" 517 "\t-v\tverbose flag for CPU binding to list cpus\n" 518 "\t-i\tdisplay mac_ring_t and interrupt information\n" 519 "Note: use -r or -t (to specify RX or TX side respectively) along " 520 "with -c or -s\n"); 521 mdb_printf("\n%<u>Interpreting TX Modes%</u>\n"); 522 mdb_printf("\t DEF --> Default\n"); 523 mdb_printf("\t SER --> Serialize\n"); 524 mdb_printf("\t FO --> Fanout\n"); 525 mdb_printf("\t BW --> Bandwidth\n"); 526 mdb_printf("\tBWFO --> Bandwidth Fanout\n"); 527 mdb_printf("\t AG --> Aggr\n"); 528 mdb_printf("\tBWAG --> Bandwidth Aggr\n"); 529 } 530 531 /* 532 * In verbose mode "::mac_srs -rcv or ::mac_srs -tcv", we print the CPUs 533 * assigned to a link and CPUS assigned to the soft rings. 534 * 'len' is used for formatting the output and represents the number of 535 * spaces between CPU list and Fanout CPU list in the output. 536 */ 537 static boolean_t 538 mac_srs_print_cpu(int *i, uint32_t cnt, uint32_t *cpu_list, int *len) 539 { 540 int num = 0; 541 542 if (*i == 0) 543 mdb_printf("("); 544 else 545 mdb_printf(" "); 546 while (*i < cnt) { 547 /* We print 6 CPU's at a time to keep display within 80 cols */ 548 if (((num + 1) % 7) == 0) { 549 if (len != NULL) 550 *len = 2; 551 return (B_FALSE); 552 } 553 mdb_printf("%02x%c", cpu_list[*i], ((*i == cnt - 1)?')':',')); 554 ++*i; 555 ++num; 556 } 557 if (len != NULL) 558 *len = (7 - num) * 3; 559 return (B_TRUE); 560 } 561 562 static int 563 mac_srs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 564 { 565 uint_t args = MAC_SRS_NONE; 566 mac_soft_ring_set_t srs; 567 mac_client_impl_t mci; 568 569 if (!(flags & DCMD_ADDRSPEC)) { 570 if (mdb_walk_dcmd("mac_srs", "mac_srs", argc, argv) == -1) { 571 mdb_warn("failed to walk 'mac_srs'"); 572 return (DCMD_ERR); 573 } 574 return (DCMD_OK); 575 } 576 if (mdb_getopts(argc, argv, 577 'r', MDB_OPT_SETBITS, MAC_SRS_RX, &args, 578 't', MDB_OPT_SETBITS, MAC_SRS_TX, &args, 579 'c', MDB_OPT_SETBITS, MAC_SRS_CPU, &args, 580 'v', MDB_OPT_SETBITS, MAC_SRS_VERBOSE, &args, 581 'i', MDB_OPT_SETBITS, MAC_SRS_INTR, &args, 582 's', MDB_OPT_SETBITS, MAC_SRS_STAT, &args, 583 NULL) != argc) { 584 return (DCMD_USAGE); 585 } 586 587 if (argc > 2) 588 return (DCMD_USAGE); 589 590 if (mdb_vread(&srs, sizeof (srs), addr) == -1) { 591 mdb_warn("failed to read struct mac_soft_ring_set_s at %p", 592 addr); 593 return (DCMD_ERR); 594 } 595 if (mdb_vread(&mci, sizeof (mci), (uintptr_t)srs.srs_mcip) == -1) { 596 mdb_warn("failed to read struct mac_client_impl_t at %p " 597 "for SRS %p", srs.srs_mcip, addr); 598 return (DCMD_ERR); 599 } 600 601 switch (args) { 602 case MAC_SRS_RX: { 603 if (DCMD_HDRSPEC(flags)) { 604 mdb_printf("%?s %-20s %-8s %-8s %8s " 605 "%8s %3s\n", 606 "", "", "", "", "MBLK", 607 "Q", "SR"); 608 mdb_printf("%<u>%?s %-20s %-8s %-8s %8s " 609 "%8s %3s%</u>\n", 610 "ADDR", "LINK_NAME", "STATE", "TYPE", "CNT", 611 "BYTES", "CNT"); 612 } 613 if (srs.srs_type & SRST_TX) 614 return (DCMD_OK); 615 mdb_printf("%?p %-20s %08x %08x " 616 "%8d %8d %3d\n", 617 addr, mci.mci_name, srs.srs_state, srs.srs_type, 618 srs.srs_count, srs.srs_size, srs.srs_soft_ring_count); 619 break; 620 } 621 case MAC_SRS_TX: { 622 if (DCMD_HDRSPEC(flags)) { 623 mdb_printf("%?s %-16s %-4s %-8s " 624 "%-8s %8s %8s %3s\n", 625 "", "", "TX", "", 626 "", "MBLK", "Q", "SR"); 627 mdb_printf("%<u>%?s %-16s %-4s %-8s " 628 "%-8s %8s %8s %3s%</u>\n", 629 "ADDR", "LINK_NAME", "MODE", "STATE", 630 "TYPE", "CNT", "BYTES", "CNT"); 631 } 632 if (!(srs.srs_type & SRST_TX)) 633 return (DCMD_OK); 634 635 mdb_printf("%?p %-16s %-4s " 636 "%08x %08x %8d %8d %3d\n", 637 addr, mci.mci_name, mac_srs_txmode2str(srs.srs_tx.st_mode), 638 srs.srs_state, srs.srs_type, srs.srs_count, srs.srs_size, 639 srs.srs_tx_ring_count); 640 break; 641 } 642 case MAC_SRS_RXCPU: { 643 mac_cpus_t mc = srs.srs_cpu; 644 645 if (DCMD_HDRSPEC(flags)) { 646 mdb_printf("%?s %-20s %-4s %-4s " 647 "%-6s %-4s %-7s\n", 648 "", "", "NUM", "POLL", 649 "WORKER", "INTR", "FANOUT"); 650 mdb_printf("%<u>%?s %-20s %-4s %-4s " 651 "%-6s %-4s %-7s%</u>\n", 652 "ADDR", "LINK_NAME", "CPUS", "CPU", 653 "CPU", "CPU", "CPU_CNT"); 654 } 655 if ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX)) 656 return (DCMD_OK); 657 mdb_printf("%?p %-20s %-4d %-4d " 658 "%-6d %-4d %-7d\n", 659 addr, mci.mci_name, mc.mc_ncpus, mc.mc_rx_pollid, 660 mc.mc_rx_workerid, mc.mc_rx_intr_cpu, mc.mc_rx_fanout_cnt); 661 break; 662 663 } 664 case MAC_SRS_TXCPU: { 665 mac_cpus_t mc = srs.srs_cpu; 666 mac_soft_ring_t *s_ringp, s_ring; 667 boolean_t first = B_TRUE; 668 int i; 669 670 if (DCMD_HDRSPEC(flags)) { 671 mdb_printf("%?s %-12s %?s %8s %8s %8s\n", 672 "", "", "SOFT", "WORKER", "INTR", "RETARGETED"); 673 mdb_printf("%<u>%?s %-12s %?s %8s %8s %8s%</u>\n", 674 "ADDR", "LINK_NAME", "RING", "CPU", "CPU", "CPU"); 675 } 676 if (!(srs.srs_type & SRST_TX)) 677 return (DCMD_OK); 678 679 mdb_printf("%?p %-12s ", addr, mci.mci_name); 680 681 /* 682 * Case of no soft rings, print the info from 683 * mac_srs_tx_t. 684 */ 685 if (srs.srs_tx_ring_count == 0) { 686 mdb_printf("%?p %8d %8d %8d\n", 687 0, mc.mc_tx_fanout_cpus[0], 688 mc.mc_tx_intr_cpu[0], 689 mc.mc_tx_retargeted_cpu[0]); 690 break; 691 } 692 693 for (s_ringp = srs.srs_soft_ring_head, i = 0; s_ringp != NULL; 694 s_ringp = s_ring.s_ring_next, i++) { 695 (void) mdb_vread(&s_ring, sizeof (s_ring), 696 (uintptr_t)s_ringp); 697 if (first) { 698 mdb_printf("%?p %8d %8d %8d\n", 699 s_ringp, mc.mc_tx_fanout_cpus[i], 700 mc.mc_tx_intr_cpu[i], 701 mc.mc_tx_retargeted_cpu[i]); 702 first = B_FALSE; 703 continue; 704 } 705 mdb_printf("%?s %-12s %?p %8d %8d %8d\n", 706 "", "", s_ringp, mc.mc_tx_fanout_cpus[i], 707 mc.mc_tx_intr_cpu[i], mc.mc_tx_retargeted_cpu[i]); 708 } 709 break; 710 } 711 case MAC_SRS_TXINTR: { 712 mac_cpus_t mc = srs.srs_cpu; 713 mac_soft_ring_t *s_ringp, s_ring; 714 mac_ring_t *m_ringp, m_ring; 715 boolean_t first = B_TRUE; 716 int i; 717 718 if (DCMD_HDRSPEC(flags)) { 719 mdb_printf("%?s %-12s %?s %8s %?s %6s %6s\n", 720 "", "", "SOFT", "WORKER", "MAC", "", "INTR"); 721 mdb_printf("%<u>%?s %-12s %?s %8s %?s %6s %6s%</u>\n", 722 "ADDR", "LINK_NAME", "RING", "CPU", "RING", 723 "SHARED", "CPU"); 724 } 725 if (!(srs.srs_type & SRST_TX)) 726 return (DCMD_OK); 727 728 mdb_printf("%?p %-12s ", addr, mci.mci_name); 729 730 /* 731 * Case of no soft rings, print the info from 732 * mac_srs_tx_t. 733 */ 734 if (srs.srs_tx_ring_count == 0) { 735 m_ringp = srs.srs_tx.st_arg2; 736 if (m_ringp != NULL) { 737 (void) mdb_vread(&m_ring, sizeof (m_ring), 738 (uintptr_t)m_ringp); 739 mdb_printf("%?p %8d %?p %6d %6d\n", 740 0, mc.mc_tx_fanout_cpus[0], m_ringp, 741 m_ring.mr_info.mri_intr.mi_ddi_shared, 742 mc.mc_tx_retargeted_cpu[0]); 743 } else { 744 mdb_printf("%?p %8d %?p %6d %6d\n", 745 0, mc.mc_tx_fanout_cpus[0], 0, 746 0, mc.mc_tx_retargeted_cpu[0]); 747 } 748 break; 749 } 750 751 for (s_ringp = srs.srs_soft_ring_head, i = 0; s_ringp != NULL; 752 s_ringp = s_ring.s_ring_next, i++) { 753 (void) mdb_vread(&s_ring, sizeof (s_ring), 754 (uintptr_t)s_ringp); 755 m_ringp = s_ring.s_ring_tx_arg2; 756 (void) mdb_vread(&m_ring, sizeof (m_ring), 757 (uintptr_t)m_ringp); 758 if (first) { 759 mdb_printf("%?p %8d %?p %6d %6d\n", 760 s_ringp, mc.mc_tx_fanout_cpus[i], 761 m_ringp, 762 m_ring.mr_info.mri_intr.mi_ddi_shared, 763 mc.mc_tx_retargeted_cpu[i]); 764 first = B_FALSE; 765 continue; 766 } 767 mdb_printf("%?s %-12s %?p %8d %?p %6d %6d\n", 768 "", "", s_ringp, mc.mc_tx_fanout_cpus[i], 769 m_ringp, m_ring.mr_info.mri_intr.mi_ddi_shared, 770 mc.mc_tx_retargeted_cpu[i]); 771 } 772 break; 773 } 774 case MAC_SRS_RXINTR: { 775 mac_cpus_t mc = srs.srs_cpu; 776 mac_ring_t *m_ringp, m_ring; 777 778 if (DCMD_HDRSPEC(flags)) { 779 mdb_printf("%?s %-12s %?s %8s %6s %6s\n", 780 "", "", "MAC", "", "POLL", "INTR"); 781 mdb_printf("%<u>%?s %-12s %?s %8s %6s %6s%</u>\n", 782 "ADDR", "LINK_NAME", "RING", "SHARED", "CPU", 783 "CPU"); 784 } 785 if ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX)) 786 return (DCMD_OK); 787 788 mdb_printf("%?p %-12s ", addr, mci.mci_name); 789 790 m_ringp = srs.srs_ring; 791 if (m_ringp != NULL) { 792 (void) mdb_vread(&m_ring, sizeof (m_ring), 793 (uintptr_t)m_ringp); 794 mdb_printf("%?p %8d %6d %6d\n", 795 m_ringp, m_ring.mr_info.mri_intr.mi_ddi_shared, 796 mc.mc_rx_pollid, mc.mc_rx_intr_cpu); 797 } else { 798 mdb_printf("%?p %8d %6d %6d\n", 799 0, 0, mc.mc_rx_pollid, mc.mc_rx_intr_cpu); 800 } 801 break; 802 } 803 case MAC_SRS_RXCPUVERBOSE: 804 case MAC_SRS_TXCPUVERBOSE: { 805 mac_cpus_t mc = srs.srs_cpu; 806 int cpu_index = 0, fanout_index = 0, len = 0; 807 boolean_t cpu_done = B_FALSE, fanout_done = B_FALSE; 808 809 if (DCMD_HDRSPEC(flags)) { 810 mdb_printf("%?s %-20s %-20s %-20s\n", 811 "", "", "CPU_COUNT", "FANOUT_CPU_COUNT"); 812 mdb_printf("%<u>%?s %-20s " 813 "%-20s %-20s%</u>\n", 814 "ADDR", "LINK_NAME", 815 "(CPU_LIST)", "(CPU_LIST)"); 816 } 817 if (((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX)) || 818 ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX))) 819 return (DCMD_OK); 820 mdb_printf("%?p %-20s %-20d %-20d\n", addr, mci.mci_name, 821 mc.mc_ncpus, mc.mc_rx_fanout_cnt); 822 if (mc.mc_ncpus == 0 && mc.mc_rx_fanout_cnt == 0) 823 break; 824 /* print all cpus and cpus for soft rings */ 825 while (!cpu_done || !fanout_done) { 826 boolean_t old_value = cpu_done; 827 828 if (!cpu_done) { 829 mdb_printf("%?s %20s ", "", ""); 830 cpu_done = mac_srs_print_cpu(&cpu_index, 831 mc.mc_ncpus, mc.mc_cpus, &len); 832 } 833 if (!fanout_done) { 834 if (old_value) 835 mdb_printf("%?s %-40s", "", ""); 836 else 837 mdb_printf("%*s", len, ""); 838 fanout_done = mac_srs_print_cpu(&fanout_index, 839 mc.mc_rx_fanout_cnt, 840 mc.mc_rx_fanout_cpus, NULL); 841 } 842 mdb_printf("\n"); 843 } 844 break; 845 } 846 case MAC_SRS_RXSTAT: { 847 mac_rx_stats_t *mac_rx_stat = &srs.srs_rx.sr_stat; 848 849 if (DCMD_HDRSPEC(flags)) { 850 mdb_printf("%?s %-16s %8s %8s " 851 "%8s %8s %8s\n", 852 "", "", "INTR", "POLL", 853 "CHAIN", "CHAIN", "CHAIN"); 854 mdb_printf("%<u>%?s %-16s %8s %8s " 855 "%8s %8s %8s%</u>\n", 856 "ADDR", "LINK_NAME", "COUNT", "COUNT", 857 "<10", "10-50", ">50"); 858 } 859 if (srs.srs_type & SRST_TX) 860 return (DCMD_OK); 861 mdb_printf("%?p %-16s %8d " 862 "%8d %8d " 863 "%8d %8d\n", 864 addr, mci.mci_name, mac_rx_stat->mrs_intrcnt, 865 mac_rx_stat->mrs_pollcnt, mac_rx_stat->mrs_chaincntundr10, 866 mac_rx_stat->mrs_chaincnt10to50, 867 mac_rx_stat->mrs_chaincntover50); 868 break; 869 } 870 case MAC_SRS_TXSTAT: { 871 mac_tx_stats_t *mac_tx_stat = &srs.srs_tx.st_stat; 872 mac_soft_ring_t *s_ringp, s_ring; 873 boolean_t first = B_TRUE; 874 875 if (DCMD_HDRSPEC(flags)) { 876 mdb_printf("%?s %-20s %?s %8s %8s %8s\n", 877 "", "", "SOFT", "DROP", "BLOCK", "UNBLOCK"); 878 mdb_printf("%<u>%?s %-20s %?s %8s %8s %8s%</u>\n", 879 "ADDR", "LINK_NAME", "RING", "COUNT", "COUNT", 880 "COUNT"); 881 } 882 if (!(srs.srs_type & SRST_TX)) 883 return (DCMD_OK); 884 885 mdb_printf("%?p %-20s ", addr, mci.mci_name); 886 887 /* 888 * Case of no soft rings, print the info from 889 * mac_srs_tx_t. 890 */ 891 if (srs.srs_tx_ring_count == 0) { 892 mdb_printf("%?p %8d %8d %8d\n", 893 0, mac_tx_stat->mts_sdrops, 894 mac_tx_stat->mts_blockcnt, 895 mac_tx_stat->mts_unblockcnt); 896 break; 897 } 898 899 for (s_ringp = srs.srs_soft_ring_head; s_ringp != NULL; 900 s_ringp = s_ring.s_ring_next) { 901 (void) mdb_vread(&s_ring, sizeof (s_ring), 902 (uintptr_t)s_ringp); 903 mac_tx_stat = &s_ring.s_st_stat; 904 if (first) { 905 mdb_printf("%?p %8d %8d %8d\n", 906 s_ringp, mac_tx_stat->mts_sdrops, 907 mac_tx_stat->mts_blockcnt, 908 mac_tx_stat->mts_unblockcnt); 909 first = B_FALSE; 910 continue; 911 } 912 mdb_printf("%?s %-20s %?p %8d %8d %8d\n", 913 "", "", s_ringp, mac_tx_stat->mts_sdrops, 914 mac_tx_stat->mts_blockcnt, 915 mac_tx_stat->mts_unblockcnt); 916 } 917 break; 918 } 919 case MAC_SRS_NONE: { 920 if (DCMD_HDRSPEC(flags)) { 921 mdb_printf("%<u>%?s %-20s %?s %?s %-3s%</u>\n", 922 "ADDR", "LINK_NAME", "FLENT", "HW RING", "DIR"); 923 } 924 mdb_printf("%?p %-20s %?p %?p " 925 "%-3s ", 926 addr, mci.mci_name, srs.srs_flent, srs.srs_ring, 927 (srs.srs_type & SRST_TX ? "TX" : "RX")); 928 break; 929 } 930 default: 931 return (DCMD_USAGE); 932 } 933 return (DCMD_OK); 934 } 935 936 static int 937 mac_srs_walk_init(mdb_walk_state_t *wsp) 938 { 939 if (mdb_layered_walk(LAYERED_WALKER_FOR_SRS, wsp) == -1) { 940 mdb_warn("failed to walk 'mac_srs'"); 941 return (WALK_ERR); 942 } 943 return (WALK_NEXT); 944 } 945 946 static char * 947 mac_ring_state2str(mac_ring_state_t state) 948 { 949 switch (state) { 950 case MR_FREE: 951 return ("free"); 952 case MR_NEWLY_ADDED: 953 return ("new"); 954 case MR_INUSE: 955 return ("inuse"); 956 } 957 return ("--"); 958 } 959 960 static char * 961 mac_ring_classify2str(mac_classify_type_t classify) 962 { 963 switch (classify) { 964 case MAC_NO_CLASSIFIER: 965 return ("no"); 966 case MAC_SW_CLASSIFIER: 967 return ("sw"); 968 case MAC_HW_CLASSIFIER: 969 return ("hw"); 970 } 971 return ("--"); 972 } 973 974 static int 975 mac_ring_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 976 { 977 mac_ring_t ring; 978 mac_group_t group; 979 flow_entry_t flent; 980 mac_soft_ring_set_t srs; 981 982 if (!(flags & DCMD_ADDRSPEC)) { 983 if (mdb_walk_dcmd("mac_ring", "mac_ring", argc, argv) == -1) { 984 mdb_warn("failed to walk 'mac_ring'"); 985 return (DCMD_ERR); 986 } 987 return (DCMD_OK); 988 } 989 if (mdb_vread(&ring, sizeof (ring), addr) == -1) { 990 mdb_warn("failed to read struct mac_ring_s at %p", addr); 991 return (DCMD_ERR); 992 } 993 bzero(&flent, sizeof (flent)); 994 if (mdb_vread(&srs, sizeof (srs), (uintptr_t)ring.mr_srs) != -1) { 995 (void) mdb_vread(&flent, sizeof (flent), 996 (uintptr_t)srs.srs_flent); 997 } 998 (void) mdb_vread(&group, sizeof (group), (uintptr_t)ring.mr_gh); 999 if (DCMD_HDRSPEC(flags)) { 1000 mdb_printf("%<u>%?s %4s %5s %4s %?s " 1001 "%5s %?s %?s %s %</u>\n", 1002 "ADDR", "TYPE", "STATE", "FLAG", "GROUP", 1003 "CLASS", "MIP", "SRS", "FLOW NAME"); 1004 } 1005 mdb_printf("%?p %-4s " 1006 "%5s %04x " 1007 "%?p %-5s " 1008 "%?p %?p %s\n", 1009 addr, ((ring.mr_type == 1)? "RX" : "TX"), 1010 mac_ring_state2str(ring.mr_state), ring.mr_flag, 1011 ring.mr_gh, mac_ring_classify2str(ring.mr_classify_type), 1012 group.mrg_mh, ring.mr_srs, flent.fe_flow_name); 1013 return (DCMD_OK); 1014 } 1015 1016 static int 1017 mac_ring_walk_init(mdb_walk_state_t *wsp) 1018 { 1019 if (mdb_layered_walk(LAYERED_WALKER_FOR_RING, wsp) == -1) { 1020 mdb_warn("failed to walk `mac_ring`"); 1021 return (WALK_ERR); 1022 } 1023 return (WALK_NEXT); 1024 } 1025 1026 static void 1027 mac_ring_help(void) 1028 { 1029 mdb_printf("If an address is specified, then mac_ring_t " 1030 "structure at that address is printed. Otherwise all the " 1031 "hardware rings in the system are printed.\n"); 1032 } 1033 1034 /* 1035 * To walk groups we have to have our own somewhat-complicated state machine. We 1036 * basically start by walking the mac_impl_t walker as all groups are stored off 1037 * of the various mac_impl_t in the system. The tx and rx rings are kept 1038 * separately. So we'll need to walk through all the rx rings and then all of 1039 * the tx rings. 1040 */ 1041 static int 1042 mac_group_walk_init(mdb_walk_state_t *wsp) 1043 { 1044 int ret; 1045 1046 if (wsp->walk_addr != 0) { 1047 mdb_warn("non-global walks are not supported\n"); 1048 return (WALK_ERR); 1049 } 1050 1051 if ((ret = mdb_layered_walk(LAYERED_WALKER_FOR_GROUP, wsp)) == -1) { 1052 mdb_warn("couldn't walk '%s'", LAYERED_WALKER_FOR_GROUP); 1053 return (ret); 1054 } 1055 1056 return (WALK_NEXT); 1057 } 1058 1059 static int 1060 mac_group_walk_step(mdb_walk_state_t *wsp) 1061 { 1062 int ret; 1063 mac_impl_t mi; 1064 mac_group_t mg; 1065 uintptr_t mgp; 1066 1067 /* 1068 * Nothing to do if we can't find the layer above us. But the kmem 1069 * walkers are a bit unsporting, they don't actually read in the data 1070 * for us. 1071 */ 1072 if (wsp->walk_addr == 0) 1073 return (WALK_DONE); 1074 1075 if (mdb_vread(&mi, sizeof (mac_impl_t), wsp->walk_addr) == -1) { 1076 mdb_warn("failed to read mac_impl_t at %p", wsp->walk_addr); 1077 return (DCMD_ERR); 1078 } 1079 1080 /* 1081 * First go for rx groups, then tx groups. 1082 */ 1083 mgp = (uintptr_t)mi.mi_rx_groups; 1084 while (mgp != 0) { 1085 if (mdb_vread(&mg, sizeof (mac_group_t), mgp) == -1) { 1086 mdb_warn("failed to read mac_group_t at %p", mgp); 1087 return (WALK_ERR); 1088 } 1089 1090 ret = wsp->walk_callback(mgp, &mg, wsp->walk_cbdata); 1091 if (ret != WALK_NEXT) 1092 return (ret); 1093 mgp = (uintptr_t)mg.mrg_next; 1094 } 1095 1096 mgp = (uintptr_t)mi.mi_tx_groups; 1097 while (mgp != 0) { 1098 if (mdb_vread(&mg, sizeof (mac_group_t), mgp) == -1) { 1099 mdb_warn("failed to read mac_group_t at %p", mgp); 1100 return (WALK_ERR); 1101 } 1102 1103 ret = wsp->walk_callback(mgp, &mg, wsp->walk_cbdata); 1104 if (ret != WALK_NEXT) 1105 return (ret); 1106 mgp = (uintptr_t)mg.mrg_next; 1107 } 1108 1109 return (WALK_NEXT); 1110 } 1111 1112 static int 1113 mac_group_count_clients(mac_group_t *mgp) 1114 { 1115 int clients = 0; 1116 uintptr_t mcp = (uintptr_t)mgp->mrg_clients; 1117 1118 while (mcp != 0) { 1119 mac_grp_client_t c; 1120 1121 if (mdb_vread(&c, sizeof (c), mcp) == -1) { 1122 mdb_warn("failed to read mac_grp_client_t at %p", mcp); 1123 return (-1); 1124 } 1125 clients++; 1126 mcp = (uintptr_t)c.mgc_next; 1127 } 1128 1129 return (clients); 1130 } 1131 1132 static const char * 1133 mac_group_type(mac_group_t *mgp) 1134 { 1135 const char *ret; 1136 1137 switch (mgp->mrg_type) { 1138 case MAC_RING_TYPE_RX: 1139 ret = "RECEIVE"; 1140 break; 1141 case MAC_RING_TYPE_TX: 1142 ret = "TRANSMIT"; 1143 break; 1144 default: 1145 ret = "UNKNOWN"; 1146 break; 1147 } 1148 1149 return (ret); 1150 } 1151 1152 static const char * 1153 mac_group_state(mac_group_t *mgp) 1154 { 1155 const char *ret; 1156 1157 switch (mgp->mrg_state) { 1158 case MAC_GROUP_STATE_UNINIT: 1159 ret = "UNINT"; 1160 break; 1161 case MAC_GROUP_STATE_REGISTERED: 1162 ret = "REGISTERED"; 1163 break; 1164 case MAC_GROUP_STATE_RESERVED: 1165 ret = "RESERVED"; 1166 break; 1167 case MAC_GROUP_STATE_SHARED: 1168 ret = "SHARED"; 1169 break; 1170 default: 1171 ret = "UNKNOWN"; 1172 break; 1173 } 1174 1175 return (ret); 1176 } 1177 1178 static int 1179 mac_group_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1180 { 1181 uint_t args = MAC_SRS_NONE; 1182 mac_group_t mg; 1183 int clients; 1184 1185 if (!(flags & DCMD_ADDRSPEC)) { 1186 if (mdb_walk_dcmd("mac_group", "mac_group", argc, argv) == -1) { 1187 mdb_warn("failed to walk 'mac_group'"); 1188 return (DCMD_ERR); 1189 } 1190 1191 return (DCMD_OK); 1192 } 1193 1194 if (mdb_getopts(argc, argv, 1195 'r', MDB_OPT_SETBITS, MAC_GROUP_RX, &args, 1196 't', MDB_OPT_SETBITS, MAC_GROUP_TX, &args, 1197 'u', MDB_OPT_SETBITS, MAC_GROUP_UNINIT, &args, 1198 NULL) != argc) 1199 return (DCMD_USAGE); 1200 1201 if (mdb_vread(&mg, sizeof (mac_group_t), addr) == -1) { 1202 mdb_warn("failed to read mac_group_t at %p", addr); 1203 return (DCMD_ERR); 1204 } 1205 1206 if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) { 1207 mdb_printf("%<u>%-?s %-8s %-10s %6s %8s %-?s%</u>\n", 1208 "ADDR", "TYPE", "STATE", "NRINGS", "NCLIENTS", "RINGS"); 1209 } 1210 1211 if ((args & MAC_GROUP_RX) != 0 && mg.mrg_type != MAC_RING_TYPE_RX) 1212 return (DCMD_OK); 1213 if ((args & MAC_GROUP_TX) != 0 && mg.mrg_type != MAC_RING_TYPE_TX) 1214 return (DCMD_OK); 1215 1216 /* 1217 * By default, don't show uninitialized groups. They're not very 1218 * interesting. They have no rings and no clients. 1219 */ 1220 if (mg.mrg_state == MAC_GROUP_STATE_UNINIT && 1221 (args & MAC_GROUP_UNINIT) == 0) 1222 return (DCMD_OK); 1223 1224 if (flags & DCMD_PIPE_OUT) { 1225 mdb_printf("%lr\n", addr); 1226 return (DCMD_OK); 1227 } 1228 1229 clients = mac_group_count_clients(&mg); 1230 mdb_printf("%?p %-8s %-10s %6d %8d %?p\n", addr, mac_group_type(&mg), 1231 mac_group_state(&mg), mg.mrg_cur_count, clients, mg.mrg_rings); 1232 1233 return (DCMD_OK); 1234 } 1235 1236 /* Supported dee-commands */ 1237 static const mdb_dcmd_t dcmds[] = { 1238 {"mac_flow", "?[-u] [-aprtsm]", "display Flow Entry structures", 1239 mac_flow_dcmd, mac_flow_help}, 1240 {"mac_group", "?[-rtu]", "display MAC Ring Groups", mac_group_dcmd, 1241 NULL }, 1242 {"mac_srs", "?[ -r[i|s|c[v]] | -t[i|s|c[v]] ]", 1243 "display MAC Soft Ring Set" " structures", mac_srs_dcmd, 1244 mac_srs_help}, 1245 {"mac_ring", "?", "display MAC ring (hardware) structures", 1246 mac_ring_dcmd, mac_ring_help}, 1247 { NULL } 1248 }; 1249 1250 /* Supported walkers */ 1251 static const mdb_walker_t walkers[] = { 1252 {"mac_flow", "walk list of flow entry structures", mac_flow_walk_init, 1253 mac_common_walk_step, NULL, NULL}, 1254 {"mac_group", "walk list of ring group structures", mac_group_walk_init, 1255 mac_group_walk_step, NULL, NULL}, 1256 {"mac_srs", "walk list of mac soft ring set structures", 1257 mac_srs_walk_init, mac_common_walk_step, NULL, NULL}, 1258 {"mac_ring", "walk list of mac ring structures", mac_ring_walk_init, 1259 mac_common_walk_step, NULL, NULL}, 1260 { NULL } 1261 }; 1262 1263 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 1264 1265 const mdb_modinfo_t * 1266 _mdb_init(void) 1267 { 1268 return (&modinfo); 1269 }