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