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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/mdb_modapi.h> 27 #include <sys/types.h> 28 #include <inet/ip.h> 29 #include <inet/ip6.h> 30 31 #include <sys/mac.h> 32 #include <sys/mac_provider.h> 33 #include <sys/mac_client.h> 34 #include <sys/mac_client_impl.h> 35 #include <sys/mac_flow_impl.h> 36 #include <sys/mac_soft_ring.h> 37 38 #define STRSIZE 64 39 #define MAC_RX_SRS_SIZE (MAX_RINGS_PER_GROUP * sizeof (uintptr_t)) 40 41 #define LAYERED_WALKER_FOR_FLOW "flow_entry_cache" 42 #define LAYERED_WALKER_FOR_SRS "mac_srs_cache" 43 #define LAYERED_WALKER_FOR_RING "mac_ring_cache" 44 45 /* arguments passed to mac_flow dee-command */ 46 #define MAC_FLOW_NONE 0x01 47 #define MAC_FLOW_ATTR 0x02 48 #define MAC_FLOW_PROP 0x04 49 #define MAC_FLOW_RX 0x08 50 #define MAC_FLOW_TX 0x10 51 #define MAC_FLOW_USER 0x20 52 #define MAC_FLOW_STATS 0x40 53 #define MAC_FLOW_MISC 0x80 54 55 /* arguments passed to mac_srs dee-command */ 56 #define MAC_SRS_RX 0x01 57 #define MAC_SRS_TX 0x02 58 59 static char * 60 mac_flow_proto2str(uint8_t protocol) 61 { 62 switch (protocol) { 63 case IPPROTO_TCP: 64 return ("tcp"); 65 case IPPROTO_UDP: 66 return ("udp"); 67 case IPPROTO_SCTP: 68 return ("sctp"); 69 case IPPROTO_ICMP: 70 return ("icmp"); 71 case IPPROTO_ICMPV6: 72 return ("icmpv6"); 73 default: 74 return ("--"); 75 } 76 } 77 78 static char * 79 mac_flow_priority2str(mac_priority_level_t prio) 80 { 81 switch (prio) { 82 case MPL_LOW: 83 return ("low"); 84 case MPL_MEDIUM: 85 return ("medium"); 86 case MPL_HIGH: 87 return ("high"); 88 case MPL_RESET: 89 return ("reset"); 90 default: 91 return ("--"); 92 } 93 } 94 95 /* 96 * Convert bandwidth in bps to a string in mpbs. 97 */ 98 static char * 99 mac_flow_bw2str(uint64_t bw, char *buf, ssize_t len) 100 { 101 int kbps, mbps; 102 103 kbps = (bw % 1000000)/1000; 104 mbps = bw/1000000; 105 if ((mbps == 0) && (kbps != 0)) 106 mdb_snprintf(buf, len, "0.%03u", kbps); 107 else 108 mdb_snprintf(buf, len, "%5u", mbps); 109 return (buf); 110 } 111 112 static void 113 mac_flow_print_header(uint_t args) 114 { 115 switch (args) { 116 case MAC_FLOW_NONE: 117 mdb_printf("%<u>%?s %-32s %-6s %?s %?s %-20s%</u>\n", 118 "ADDR", "FLOW NAME", "LINKID", "MCIP", "MIP", 119 "MIP NAME"); 120 break; 121 case MAC_FLOW_ATTR: 122 mdb_printf("%<u>%?s %-32s %-7s %6s " 123 "%-9s %s%</u>\n", 124 "ADDR", "FLOW NAME", "PROTO", "PORT", 125 "DSFLD:MSK", "IPADDR"); 126 break; 127 case MAC_FLOW_PROP: 128 mdb_printf("%<u>%?s %-32s %8s %9s%</u>\n", 129 "ADDR", "FLOW NAME", "MAXBW(M)", "PRIORITY"); 130 break; 131 case MAC_FLOW_MISC: 132 mdb_printf("%<u>%?s %-32s %10s %10s " 133 "%32s %s%</u>\n", 134 "ADDR", "FLOW NAME", "TYPE", "FLAGS", 135 "MATCH_FN", "ZONE"); 136 break; 137 case MAC_FLOW_RX: 138 mdb_printf("%<u>%?s %-24s %-30s %?s " 139 "%?s %7s %s%</u>\n", 140 "ADDR", "FLOW NAME", "CB_FUNC", "CB_ARG1", 141 "CB_ARG2", "SRS_CNT", "RX_SRS"); 142 break; 143 case MAC_FLOW_TX: 144 mdb_printf("%<u>%?s %-32s %?s %</u>\n", 145 "ADDR", "FLOW NAME", "TX_SRS"); 146 break; 147 case MAC_FLOW_STATS: 148 mdb_printf("%<u>%?s %-32s %?s %?s%</u>\n", 149 "ADDR", "FLOW NAME", "RBYTES", "OBYTES"); 150 break; 151 } 152 } 153 154 /* 155 * Display selected fields of the flow_entry_t structure 156 */ 157 static int 158 mac_flow_dcmd_output(uintptr_t addr, uint_t flags, uint_t args) 159 { 160 static const mdb_bitmask_t flow_type_bits[] = { 161 {"P", FLOW_PRIMARY_MAC, FLOW_PRIMARY_MAC}, 162 {"V", FLOW_VNIC_MAC, FLOW_VNIC_MAC}, 163 {"M", FLOW_MCAST, FLOW_MCAST}, 164 {"O", FLOW_OTHER, FLOW_OTHER}, 165 {"U", FLOW_USER, FLOW_USER}, 166 {"V", FLOW_VNIC, FLOW_VNIC}, 167 {"NS", FLOW_NO_STATS, FLOW_NO_STATS}, 168 { NULL, 0, 0 } 169 }; 170 #define FLOW_MAX_TYPE (sizeof (flow_type_bits) / sizeof (mdb_bitmask_t)) 171 172 static const mdb_bitmask_t flow_flag_bits[] = { 173 {"Q", FE_QUIESCE, FE_QUIESCE}, 174 {"W", FE_WAITER, FE_WAITER}, 175 {"T", FE_FLOW_TAB, FE_FLOW_TAB}, 176 {"G", FE_G_FLOW_HASH, FE_G_FLOW_HASH}, 177 {"I", FE_INCIPIENT, FE_INCIPIENT}, 178 {"C", FE_CONDEMNED, FE_CONDEMNED}, 179 {"NU", FE_UF_NO_DATAPATH, FE_UF_NO_DATAPATH}, 180 {"NC", FE_MC_NO_DATAPATH, FE_MC_NO_DATAPATH}, 181 { NULL, 0, 0 } 182 }; 183 #define FLOW_MAX_FLAGS (sizeof (flow_flag_bits) / sizeof (mdb_bitmask_t)) 184 flow_entry_t fe; 185 mac_client_impl_t mcip; 186 mac_impl_t mip; 187 188 if (mdb_vread(&fe, sizeof (fe), addr) == -1) { 189 mdb_warn("failed to read struct flow_entry_s at %p", addr); 190 return (DCMD_ERR); 191 } 192 if (args & MAC_FLOW_USER) { 193 args &= ~MAC_FLOW_USER; 194 if (fe.fe_type & FLOW_MCAST) { 195 if (DCMD_HDRSPEC(flags)) 196 mac_flow_print_header(args); 197 return (DCMD_OK); 198 } 199 } 200 if (DCMD_HDRSPEC(flags)) 201 mac_flow_print_header(args); 202 bzero(&mcip, sizeof (mcip)); 203 bzero(&mip, sizeof (mip)); 204 if (fe.fe_mcip != NULL && mdb_vread(&mcip, sizeof (mcip), 205 (uintptr_t)fe.fe_mcip) == sizeof (mcip)) { 206 (void) mdb_vread(&mip, sizeof (mip), (uintptr_t)mcip.mci_mip); 207 } 208 switch (args) { 209 case MAC_FLOW_NONE: { 210 mdb_printf("%?p %-32s %6d %?p " 211 "%?p %-20s\n", 212 addr, fe.fe_flow_name, fe.fe_link_id, fe.fe_mcip, 213 mcip.mci_mip, mip.mi_name); 214 break; 215 } 216 case MAC_FLOW_ATTR: { 217 struct in_addr in4; 218 uintptr_t desc_addr; 219 flow_desc_t fdesc; 220 221 desc_addr = addr + OFFSETOF(flow_entry_t, fe_flow_desc); 222 if (mdb_vread(&fdesc, sizeof (fdesc), desc_addr) == -1) { 223 mdb_warn("failed to read struct flow_description at %p", 224 desc_addr); 225 return (DCMD_ERR); 226 } 227 mdb_printf("%?p %-32s " 228 "%-7s %6d" 229 "%4d:%-4d ", 230 addr, fe.fe_flow_name, 231 mac_flow_proto2str(fdesc.fd_protocol), fdesc.fd_local_port, 232 fdesc.fd_dsfield, fdesc.fd_dsfield_mask); 233 if (fdesc.fd_ipversion == IPV4_VERSION) { 234 IN6_V4MAPPED_TO_INADDR(&fdesc.fd_local_addr, &in4); 235 mdb_printf("%I", in4.s_addr); 236 } else if (fdesc.fd_ipversion == IPV6_VERSION) { 237 mdb_printf("%N", &fdesc.fd_local_addr); 238 } else { 239 mdb_printf("%s", "--"); 240 } 241 mdb_printf("\n"); 242 break; 243 } 244 case MAC_FLOW_PROP: { 245 uintptr_t prop_addr; 246 char bwstr[STRSIZE]; 247 mac_resource_props_t fprop; 248 249 prop_addr = addr + OFFSETOF(flow_entry_t, fe_resource_props); 250 if (mdb_vread(&fprop, sizeof (fprop), prop_addr) == -1) { 251 mdb_warn("failed to read struct mac_resoource_props " 252 "at %p", prop_addr); 253 return (DCMD_ERR); 254 } 255 mdb_printf("%?p %-32s " 256 "%8s %9s\n", 257 addr, fe.fe_flow_name, 258 mac_flow_bw2str(fprop.mrp_maxbw, bwstr, STRSIZE), 259 mac_flow_priority2str(fprop.mrp_priority)); 260 break; 261 } 262 case MAC_FLOW_MISC: { 263 char flow_flags[2 * FLOW_MAX_FLAGS]; 264 char flow_type[2 * FLOW_MAX_TYPE]; 265 GElf_Sym sym; 266 char func_name[MDB_SYM_NAMLEN] = ""; 267 uintptr_t func, match_addr; 268 269 match_addr = addr + OFFSETOF(flow_entry_t, fe_match); 270 (void) mdb_vread(&func, sizeof (func), match_addr); 271 (void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name, 272 MDB_SYM_NAMLEN, &sym); 273 mdb_snprintf(flow_flags, 2 * FLOW_MAX_FLAGS, "%hb", 274 fe.fe_flags, flow_flag_bits); 275 mdb_snprintf(flow_type, 2 * FLOW_MAX_TYPE, "%hb", 276 fe.fe_type, flow_type_bits); 277 mdb_printf("%?p %-32s %10s %10s " 278 "%32s %-d\n", 279 addr, fe.fe_flow_name, flow_type, flow_flags, 280 func_name, fe.fe_zoneid); 281 break; 282 } 283 case MAC_FLOW_RX: { 284 uintptr_t rx_srs[MAX_RINGS_PER_GROUP] = {0}; 285 char cb_fn[MDB_SYM_NAMLEN] = ""; 286 uintptr_t cb_fnaddr, fnaddr, rxaddr; 287 int i; 288 GElf_Sym sym; 289 290 rxaddr = addr + OFFSETOF(flow_entry_t, fe_rx_srs); 291 (void) mdb_vread(rx_srs, MAC_RX_SRS_SIZE, rxaddr); 292 fnaddr = addr + OFFSETOF(flow_entry_t, fe_cb_fn); 293 (void) mdb_vread(&cb_fnaddr, sizeof (cb_fnaddr), fnaddr); 294 (void) mdb_lookup_by_addr(cb_fnaddr, MDB_SYM_EXACT, cb_fn, 295 MDB_SYM_NAMLEN, &sym); 296 mdb_printf("%?p %-24s %-30s %?p " 297 "%?p %7d ", 298 addr, fe.fe_flow_name, cb_fn, fe.fe_cb_arg1, 299 fe.fe_cb_arg2, fe.fe_rx_srs_cnt); 300 for (i = 0; i < MAX_RINGS_PER_GROUP; i++) { 301 if (rx_srs[i] == 0) 302 continue; 303 mdb_printf("%p ", rx_srs[i]); 304 } 305 mdb_printf("\n"); 306 break; 307 } 308 case MAC_FLOW_TX: { 309 uintptr_t tx_srs = 0, txaddr; 310 311 txaddr = addr + OFFSETOF(flow_entry_t, fe_tx_srs); 312 (void) mdb_vread(&tx_srs, sizeof (uintptr_t), txaddr); 313 mdb_printf("%?p %-32s %?p\n", 314 addr, fe.fe_flow_name, fe.fe_tx_srs); 315 break; 316 } 317 case MAC_FLOW_STATS: { 318 mdb_printf("%?p %-32s %16llu %16llu\n", 319 addr, fe.fe_flow_name, fe.fe_flowstats.fs_rbytes, 320 fe.fe_flowstats.fs_obytes); 321 break; 322 } 323 } 324 return (DCMD_OK); 325 } 326 327 /* 328 * Parse the arguments passed to the dcmd and print all or one flow_entry_t 329 * structures 330 */ 331 static int 332 mac_flow_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 333 { 334 uint_t args = 0; 335 336 if (!(flags & DCMD_ADDRSPEC)) { 337 if (mdb_walk_dcmd("mac_flow", "mac_flow", argc, argv) == -1) { 338 mdb_warn("failed to walk 'mac_flow'"); 339 return (DCMD_ERR); 340 } 341 return (DCMD_OK); 342 } 343 if ((mdb_getopts(argc, argv, 344 'a', MDB_OPT_SETBITS, MAC_FLOW_ATTR, &args, 345 'p', MDB_OPT_SETBITS, MAC_FLOW_PROP, &args, 346 'm', MDB_OPT_SETBITS, MAC_FLOW_MISC, &args, 347 'r', MDB_OPT_SETBITS, MAC_FLOW_RX, &args, 348 't', MDB_OPT_SETBITS, MAC_FLOW_TX, &args, 349 's', MDB_OPT_SETBITS, MAC_FLOW_STATS, &args, 350 'u', MDB_OPT_SETBITS, MAC_FLOW_USER, &args) != argc)) { 351 return (DCMD_USAGE); 352 } 353 if (argc > 2 || (argc == 2 && !(args & MAC_FLOW_USER))) 354 return (DCMD_USAGE); 355 /* 356 * If no arguments was specified or just "-u" was specified then 357 * we default to printing basic information of flows. 358 */ 359 if (args == 0 || args == MAC_FLOW_USER) 360 args |= MAC_FLOW_NONE; 361 362 return (mac_flow_dcmd_output(addr, flags, args)); 363 } 364 365 static void 366 mac_flow_help(void) 367 { 368 mdb_printf("If an address is specified, then flow_entry structure at " 369 "that address is printed. Otherwise all the flows in the system " 370 "are printed.\n"); 371 mdb_printf("Options:\n" 372 "\t-u\tdisplay user defined link & vnic flows.\n" 373 "\t-a\tdisplay flow attributes\n" 374 "\t-p\tdisplay flow properties\n" 375 "\t-r\tdisplay rx side information\n" 376 "\t-t\tdisplay tx side information\n" 377 "\t-s\tdisplay flow statistics\n" 378 "\t-m\tdisplay miscellaneous flow information\n\n"); 379 mdb_printf("%<u>Interpreting Flow type and Flow flags output.%</u>\n"); 380 mdb_printf("Flow Types:\n"); 381 mdb_printf("\t P --> FLOW_PRIMARY_MAC\n"); 382 mdb_printf("\t V --> FLOW_VNIC_MAC\n"); 383 mdb_printf("\t M --> FLOW_MCAST\n"); 384 mdb_printf("\t O --> FLOW_OTHER\n"); 385 mdb_printf("\t U --> FLOW_USER\n"); 386 mdb_printf("\t NS --> FLOW_NO_STATS\n\n"); 387 mdb_printf("Flow Flags:\n"); 388 mdb_printf("\t Q --> FE_QUIESCE\n"); 389 mdb_printf("\t W --> FE_WAITER\n"); 390 mdb_printf("\t T --> FE_FLOW_TAB\n"); 391 mdb_printf("\t G --> FE_G_FLOW_HASH\n"); 392 mdb_printf("\t I --> FE_INCIPIENT\n"); 393 mdb_printf("\t C --> FE_CONDEMNED\n"); 394 mdb_printf("\t NU --> FE_UF_NO_DATAPATH\n"); 395 mdb_printf("\t NC --> FE_MC_NO_DATAPATH\n"); 396 } 397 398 /* 399 * called once by the debugger when the mac_flow walk begins. 400 */ 401 static int 402 mac_flow_walk_init(mdb_walk_state_t *wsp) 403 { 404 if (mdb_layered_walk(LAYERED_WALKER_FOR_FLOW, wsp) == -1) { 405 mdb_warn("failed to walk 'mac_flow'"); 406 return (WALK_ERR); 407 } 408 return (WALK_NEXT); 409 } 410 411 /* 412 * Common walker step funciton for flow_entry_t, mac_soft_ring_set_t and 413 * mac_ring_t. 414 * 415 * Steps through each flow_entry_t and calls the callback function. If the 416 * user executed ::walk mac_flow, it just prints the address or if the user 417 * executed ::mac_flow it displays selected fields of flow_entry_t structure 418 * by calling "mac_flow_dcmd" 419 */ 420 static int 421 mac_common_walk_step(mdb_walk_state_t *wsp) 422 { 423 int status; 424 425 if (wsp->walk_addr == NULL) 426 return (WALK_DONE); 427 428 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 429 wsp->walk_cbdata); 430 431 return (status); 432 } 433 434 static char * 435 mac_srs_txmode2str(mac_tx_srs_mode_t mode) 436 { 437 switch (mode) { 438 case SRS_TX_DEFAULT: 439 return ("default"); 440 case SRS_TX_SERIALIZE: 441 return ("serialize"); 442 case SRS_TX_FANOUT: 443 return ("fanout"); 444 case SRS_TX_BW: 445 return ("bw"); 446 case SRS_TX_BW_FANOUT: 447 return ("bw fanout"); 448 } 449 return ("--"); 450 } 451 452 static void 453 mac_srs_help(void) 454 { 455 mdb_printf("If an address is specified, then mac_soft_ring_set " 456 "structure at that address is printed. Otherwise all the " 457 "SRS in the system are printed.\n"); 458 mdb_printf("Options:\n" 459 "\t-r\tdisplay recieve side SRS structures\n" 460 "\t-t\tdisplay transmit side SRS structures\n"); 461 } 462 463 static int 464 mac_srs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 465 { 466 uint_t args = 0; 467 mac_soft_ring_set_t srs; 468 469 if (!(flags & DCMD_ADDRSPEC)) { 470 if (mdb_walk_dcmd("mac_srs", "mac_srs", argc, argv) == -1) { 471 mdb_warn("failed to walk 'mac_srs'"); 472 return (DCMD_ERR); 473 } 474 return (DCMD_OK); 475 } 476 if ((mdb_getopts(argc, argv, 477 'r', MDB_OPT_SETBITS, MAC_SRS_RX, &args, 478 't', MDB_OPT_SETBITS, MAC_SRS_TX, &args) != argc)) { 479 return (DCMD_USAGE); 480 } 481 if (argc > 1) 482 return (DCMD_USAGE); 483 484 if (mdb_vread(&srs, sizeof (srs), addr) == -1) { 485 mdb_warn("failed to read struct mac_soft_ring_set_s at %p", 486 addr); 487 return (DCMD_ERR); 488 } 489 490 switch (args) { 491 case MAC_SRS_RX: { 492 GElf_Sym sym; 493 char func_name[MDB_SYM_NAMLEN] = ""; 494 char l_proc_name[MDB_SYM_NAMLEN] = ""; 495 uintptr_t func, lproc, funcaddr, lprocaddr, rxaddr; 496 497 if (DCMD_HDRSPEC(flags)) { 498 mdb_printf("%<u>%?s %8s %-8s " 499 "%8s %-20s %-s%</u>\n", 500 "ADDR", "MBLK_CNT", "Q_BYTES", 501 "POLL_CNT", "SR_FUNC", "SR_LOWER_FUNC"); 502 } 503 if (srs.srs_type & SRST_TX) 504 return (DCMD_OK); 505 rxaddr = addr + OFFSETOF(mac_soft_ring_set_t, srs_rx); 506 funcaddr = rxaddr + OFFSETOF(mac_srs_rx_t, sr_func); 507 lprocaddr = rxaddr + OFFSETOF(mac_srs_rx_t, sr_lower_proc); 508 (void) mdb_vread(&func, sizeof (func), funcaddr); 509 (void) mdb_vread(&lproc, sizeof (lproc), lprocaddr); 510 (void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name, 511 MDB_SYM_NAMLEN, &sym); 512 (void) mdb_lookup_by_addr(lproc, MDB_SYM_EXACT, l_proc_name, 513 MDB_SYM_NAMLEN, &sym); 514 mdb_printf("%?p %-8d %-8d " 515 "%-8d %-20s %-s\n", 516 addr, srs.srs_count, srs.srs_size, 517 srs.srs_rx.sr_poll_count, func_name, l_proc_name); 518 break; 519 } 520 case MAC_SRS_TX: { 521 if (DCMD_HDRSPEC(flags)) { 522 mdb_printf("%<u>%?s %-10s %-5s %-7s %-7s " 523 "%-7s %-7s %-7s%</u>\n", 524 "ADDR", "TX_MODE", "WOKEN", "DROP", "BLOCK", 525 "UNBLOCK", "MBLK", "SR_CNT"); 526 } 527 if (!(srs.srs_type & SRST_TX)) 528 return (DCMD_OK); 529 530 mdb_printf("%?p %-10s " 531 "%-5d %-7d " 532 "%-7d %-7d " 533 "%-7d %-7d\n", 534 addr, mac_srs_txmode2str(srs.srs_tx.st_mode), 535 srs.srs_tx.st_woken_up, srs.srs_tx.st_drop_count, 536 srs.srs_tx.st_blocked_cnt, srs.srs_tx.st_unblocked_cnt, 537 srs.srs_count, srs.srs_oth_ring_count); 538 break; 539 } 540 default: { 541 if (DCMD_HDRSPEC(flags)) { 542 mdb_printf("%<u>%?s %?s %?s %?s %-3s " 543 "%-8s %-8s %-7s %</u>\n", 544 "ADDR", "MCIP", "FLENT", "RING", "DIR", 545 "TYPE", "STATE", "SR_CNT"); 546 } 547 mdb_printf("%?p %?p %?p %?p " 548 "%-3s " 549 "%08x %08x %-7d \n", 550 addr, srs.srs_mcip, srs.srs_flent, srs.srs_ring, 551 (srs.srs_type & SRST_TX ? "TX" : "RX"), 552 srs.srs_type, srs.srs_state, srs.srs_soft_ring_count); 553 break; 554 } 555 } 556 return (DCMD_OK); 557 } 558 559 static int 560 mac_srs_walk_init(mdb_walk_state_t *wsp) 561 { 562 if (mdb_layered_walk(LAYERED_WALKER_FOR_SRS, wsp) == -1) { 563 mdb_warn("failed to walk 'mac_srs'"); 564 return (WALK_ERR); 565 } 566 return (WALK_NEXT); 567 } 568 569 static char * 570 mac_ring_state2str(mac_ring_state_t state) 571 { 572 switch (state) { 573 case MR_FREE: 574 return ("free"); 575 case MR_NEWLY_ADDED: 576 return ("new"); 577 case MR_INUSE: 578 return ("inuse"); 579 } 580 return ("--"); 581 } 582 583 static char * 584 mac_ring_classify2str(mac_classify_type_t classify) 585 { 586 switch (classify) { 587 case MAC_NO_CLASSIFIER: 588 return ("no"); 589 case MAC_SW_CLASSIFIER: 590 return ("sw"); 591 case MAC_HW_CLASSIFIER: 592 return ("hw"); 593 } 594 return ("--"); 595 } 596 597 static int 598 mac_ring_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 599 { 600 mac_ring_t ring; 601 mac_group_t group; 602 flow_entry_t flent; 603 mac_soft_ring_set_t srs; 604 605 if (!(flags & DCMD_ADDRSPEC)) { 606 if (mdb_walk_dcmd("mac_ring", "mac_ring", argc, argv) == -1) { 607 mdb_warn("failed to walk 'mac_ring'"); 608 return (DCMD_ERR); 609 } 610 return (DCMD_OK); 611 } 612 if (mdb_vread(&ring, sizeof (ring), addr) == -1) { 613 mdb_warn("failed to read struct mac_ring_s at %p", addr); 614 return (DCMD_ERR); 615 } 616 bzero(&flent, sizeof (flent)); 617 if (mdb_vread(&srs, sizeof (srs), (uintptr_t)ring.mr_srs) != -1) { 618 (void) mdb_vread(&flent, sizeof (flent), 619 (uintptr_t)srs.srs_flent); 620 } 621 (void) mdb_vread(&group, sizeof (group), (uintptr_t)ring.mr_gh); 622 if (DCMD_HDRSPEC(flags)) { 623 mdb_printf("%<u>%?s %4s %5s %4s %?s " 624 "%5s %?s %?s %s %</u>\n", 625 "ADDR", "TYPE", "STATE", "FLAG", "GROUP", 626 "CLASS", "MIP", "SRS", "FLOW NAME"); 627 } 628 mdb_printf("%?p %-4s " 629 "%5s %04x " 630 "%?p %-5s " 631 "%?p %?p %s\n", 632 addr, ((ring.mr_type == 1)? "RX" : "TX"), 633 mac_ring_state2str(ring.mr_state), ring.mr_flag, 634 ring.mr_gh, mac_ring_classify2str(ring.mr_classify_type), 635 group.mrg_mh, ring.mr_srs, flent.fe_flow_name); 636 return (DCMD_OK); 637 } 638 639 static int 640 mac_ring_walk_init(mdb_walk_state_t *wsp) 641 { 642 if (mdb_layered_walk(LAYERED_WALKER_FOR_RING, wsp) == -1) { 643 mdb_warn("failed to walk `mac_ring`"); 644 return (WALK_ERR); 645 } 646 return (WALK_NEXT); 647 } 648 649 static void 650 mac_ring_help(void) 651 { 652 mdb_printf("If an address is specified, then mac_ring_t " 653 "structure at that address is printed. Otherwise all the " 654 "hardware rings in the system are printed.\n"); 655 } 656 657 /* Supported dee-commands */ 658 static const mdb_dcmd_t dcmds[] = { 659 {"mac_flow", "?[-u] [-aprtsm]", "display Flow Entry structures", 660 mac_flow_dcmd, mac_flow_help}, 661 {"mac_srs", "?[-rt]", "display MAC Soft Ring Set structures", 662 mac_srs_dcmd, mac_srs_help}, 663 {"mac_ring", "?", "display MAC ring (hardware) structures", 664 mac_ring_dcmd, mac_ring_help}, 665 { NULL } 666 }; 667 668 /* Supported walkers */ 669 static const mdb_walker_t walkers[] = { 670 {"mac_flow", "walk list of flow entry structures", mac_flow_walk_init, 671 mac_common_walk_step, NULL, NULL}, 672 {"mac_srs", "walk list of mac soft ring set structures", 673 mac_srs_walk_init, mac_common_walk_step, NULL, NULL}, 674 {"mac_ring", "walk list of mac ring structures", mac_ring_walk_init, 675 mac_common_walk_step, NULL, NULL}, 676 { NULL } 677 }; 678 679 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 680 681 const mdb_modinfo_t * 682 _mdb_init(void) 683 { 684 return (&modinfo); 685 } 686