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