/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #define STRSIZE 64 #define MAC_RX_SRS_SIZE (MAX_RINGS_PER_GROUP * sizeof (uintptr_t)) #define LAYERED_WALKER_FOR_FLOW "flow_entry_cache" #define LAYERED_WALKER_FOR_SRS "mac_srs_cache" #define LAYERED_WALKER_FOR_RING "mac_ring_cache" /* arguments passed to mac_flow dee-command */ #define MAC_FLOW_NONE 0x01 #define MAC_FLOW_ATTR 0x02 #define MAC_FLOW_PROP 0x04 #define MAC_FLOW_RX 0x08 #define MAC_FLOW_TX 0x10 #define MAC_FLOW_USER 0x20 #define MAC_FLOW_STATS 0x40 #define MAC_FLOW_MISC 0x80 /* arguments passed to mac_srs dee-command */ #define MAC_SRS_NONE 0x00 #define MAC_SRS_RX 0x01 #define MAC_SRS_TX 0x02 #define MAC_SRS_STAT 0x04 #define MAC_SRS_CPU 0x08 #define MAC_SRS_VERBOSE 0x10 #define MAC_SRS_RXSTAT (MAC_SRS_RX|MAC_SRS_STAT) #define MAC_SRS_TXSTAT (MAC_SRS_TX|MAC_SRS_STAT) #define MAC_SRS_RXCPU (MAC_SRS_RX|MAC_SRS_CPU) #define MAC_SRS_TXCPU (MAC_SRS_TX|MAC_SRS_CPU) #define MAC_SRS_RXCPUVERBOSE (MAC_SRS_RXCPU|MAC_SRS_VERBOSE) #define MAC_SRS_TXCPUVERBOSE (MAC_SRS_TXCPU|MAC_SRS_VERBOSE) static char * mac_flow_proto2str(uint8_t protocol) { switch (protocol) { case IPPROTO_TCP: return ("tcp"); case IPPROTO_UDP: return ("udp"); case IPPROTO_SCTP: return ("sctp"); case IPPROTO_ICMP: return ("icmp"); case IPPROTO_ICMPV6: return ("icmpv6"); default: return ("--"); } } static char * mac_flow_priority2str(mac_priority_level_t prio) { switch (prio) { case MPL_LOW: return ("low"); case MPL_MEDIUM: return ("medium"); case MPL_HIGH: return ("high"); case MPL_RESET: return ("reset"); default: return ("--"); } } /* * Convert bandwidth in bps to a string in mpbs. */ static char * mac_flow_bw2str(uint64_t bw, char *buf, ssize_t len) { int kbps, mbps; kbps = (bw % 1000000)/1000; mbps = bw/1000000; if ((mbps == 0) && (kbps != 0)) mdb_snprintf(buf, len, "0.%03u", kbps); else mdb_snprintf(buf, len, "%5u", mbps); return (buf); } static void mac_flow_print_header(uint_t args) { switch (args) { case MAC_FLOW_NONE: mdb_printf("%%?s %-32s %-6s %?s %?s %-20s%\n", "ADDR", "FLOW NAME", "LINKID", "MCIP", "MIP", "MIP NAME"); break; case MAC_FLOW_ATTR: mdb_printf("%%?s %-32s %-7s %6s " "%-9s %s%\n", "ADDR", "FLOW NAME", "PROTO", "PORT", "DSFLD:MSK", "IPADDR"); break; case MAC_FLOW_PROP: mdb_printf("%%?s %-32s %8s %9s%\n", "ADDR", "FLOW NAME", "MAXBW(M)", "PRIORITY"); break; case MAC_FLOW_MISC: mdb_printf("%%?s %-32s %10s %10s " "%32s %s%\n", "ADDR", "FLOW NAME", "TYPE", "FLAGS", "MATCH_FN", "ZONE"); break; case MAC_FLOW_RX: mdb_printf("%%?s %-24s %7s %s%\n", "ADDR", "FLOW NAME", "SRS_CNT", "RX_SRS"); break; case MAC_FLOW_TX: mdb_printf("%%?s %-32s %?s %\n", "ADDR", "FLOW NAME", "TX_SRS"); break; case MAC_FLOW_STATS: mdb_printf("%%?s %-32s %?s %?s%\n", "ADDR", "FLOW NAME", "RBYTES", "OBYTES"); break; } } /* * Display selected fields of the flow_entry_t structure */ static int mac_flow_dcmd_output(uintptr_t addr, uint_t flags, uint_t args) { static const mdb_bitmask_t flow_type_bits[] = { {"P", FLOW_PRIMARY_MAC, FLOW_PRIMARY_MAC}, {"V", FLOW_VNIC_MAC, FLOW_VNIC_MAC}, {"M", FLOW_MCAST, FLOW_MCAST}, {"O", FLOW_OTHER, FLOW_OTHER}, {"U", FLOW_USER, FLOW_USER}, {"V", FLOW_VNIC, FLOW_VNIC}, {"NS", FLOW_NO_STATS, FLOW_NO_STATS}, { NULL, 0, 0 } }; #define FLOW_MAX_TYPE (sizeof (flow_type_bits) / sizeof (mdb_bitmask_t)) static const mdb_bitmask_t flow_flag_bits[] = { {"Q", FE_QUIESCE, FE_QUIESCE}, {"W", FE_WAITER, FE_WAITER}, {"T", FE_FLOW_TAB, FE_FLOW_TAB}, {"G", FE_G_FLOW_HASH, FE_G_FLOW_HASH}, {"I", FE_INCIPIENT, FE_INCIPIENT}, {"C", FE_CONDEMNED, FE_CONDEMNED}, {"NU", FE_UF_NO_DATAPATH, FE_UF_NO_DATAPATH}, {"NC", FE_MC_NO_DATAPATH, FE_MC_NO_DATAPATH}, { NULL, 0, 0 } }; #define FLOW_MAX_FLAGS (sizeof (flow_flag_bits) / sizeof (mdb_bitmask_t)) flow_entry_t fe; mac_client_impl_t mcip; mac_impl_t mip; if (mdb_vread(&fe, sizeof (fe), addr) == -1) { mdb_warn("failed to read struct flow_entry_s at %p", addr); return (DCMD_ERR); } if (args & MAC_FLOW_USER) { args &= ~MAC_FLOW_USER; if (fe.fe_type & FLOW_MCAST) { if (DCMD_HDRSPEC(flags)) mac_flow_print_header(args); return (DCMD_OK); } } if (DCMD_HDRSPEC(flags)) mac_flow_print_header(args); bzero(&mcip, sizeof (mcip)); bzero(&mip, sizeof (mip)); if (fe.fe_mcip != NULL && mdb_vread(&mcip, sizeof (mcip), (uintptr_t)fe.fe_mcip) == sizeof (mcip)) { (void) mdb_vread(&mip, sizeof (mip), (uintptr_t)mcip.mci_mip); } switch (args) { case MAC_FLOW_NONE: { mdb_printf("%?p %-32s %6d %?p " "%?p %-20s\n", addr, fe.fe_flow_name, fe.fe_link_id, fe.fe_mcip, mcip.mci_mip, mip.mi_name); break; } case MAC_FLOW_ATTR: { struct in_addr in4; uintptr_t desc_addr; flow_desc_t fdesc; desc_addr = addr + OFFSETOF(flow_entry_t, fe_flow_desc); if (mdb_vread(&fdesc, sizeof (fdesc), desc_addr) == -1) { mdb_warn("failed to read struct flow_description at %p", desc_addr); return (DCMD_ERR); } mdb_printf("%?p %-32s " "%-7s %6d" "%4d:%-4d ", addr, fe.fe_flow_name, mac_flow_proto2str(fdesc.fd_protocol), fdesc.fd_local_port, fdesc.fd_dsfield, fdesc.fd_dsfield_mask); if (fdesc.fd_ipversion == IPV4_VERSION) { IN6_V4MAPPED_TO_INADDR(&fdesc.fd_local_addr, &in4); mdb_printf("%I", in4.s_addr); } else if (fdesc.fd_ipversion == IPV6_VERSION) { mdb_printf("%N", &fdesc.fd_local_addr); } else { mdb_printf("%s", "--"); } mdb_printf("\n"); break; } case MAC_FLOW_PROP: { uintptr_t prop_addr; char bwstr[STRSIZE]; mac_resource_props_t fprop; prop_addr = addr + OFFSETOF(flow_entry_t, fe_resource_props); if (mdb_vread(&fprop, sizeof (fprop), prop_addr) == -1) { mdb_warn("failed to read struct mac_resoource_props " "at %p", prop_addr); return (DCMD_ERR); } mdb_printf("%?p %-32s " "%8s %9s\n", addr, fe.fe_flow_name, mac_flow_bw2str(fprop.mrp_maxbw, bwstr, STRSIZE), mac_flow_priority2str(fprop.mrp_priority)); break; } case MAC_FLOW_MISC: { char flow_flags[2 * FLOW_MAX_FLAGS]; char flow_type[2 * FLOW_MAX_TYPE]; GElf_Sym sym; char func_name[MDB_SYM_NAMLEN] = ""; uintptr_t func, match_addr; match_addr = addr + OFFSETOF(flow_entry_t, fe_match); (void) mdb_vread(&func, sizeof (func), match_addr); (void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name, MDB_SYM_NAMLEN, &sym); mdb_snprintf(flow_flags, 2 * FLOW_MAX_FLAGS, "%hb", fe.fe_flags, flow_flag_bits); mdb_snprintf(flow_type, 2 * FLOW_MAX_TYPE, "%hb", fe.fe_type, flow_type_bits); mdb_printf("%?p %-32s %10s %10s " "%32s %-d\n", addr, fe.fe_flow_name, flow_type, flow_flags, func_name, fe.fe_zoneid); break; } case MAC_FLOW_RX: { uintptr_t rxaddr, rx_srs[MAX_RINGS_PER_GROUP] = {0}; int i; rxaddr = addr + OFFSETOF(flow_entry_t, fe_rx_srs); (void) mdb_vread(rx_srs, MAC_RX_SRS_SIZE, rxaddr); mdb_printf("%?p %-24s %7d ", addr, fe.fe_flow_name, fe.fe_rx_srs_cnt); for (i = 0; i < MAX_RINGS_PER_GROUP; i++) { if (rx_srs[i] == 0) continue; mdb_printf("%p ", rx_srs[i]); } mdb_printf("\n"); break; } case MAC_FLOW_TX: { uintptr_t tx_srs = 0, txaddr; txaddr = addr + OFFSETOF(flow_entry_t, fe_tx_srs); (void) mdb_vread(&tx_srs, sizeof (uintptr_t), txaddr); mdb_printf("%?p %-32s %?p\n", addr, fe.fe_flow_name, fe.fe_tx_srs); break; } case MAC_FLOW_STATS: { mdb_printf("%?p %-32s %16llu %16llu\n", addr, fe.fe_flow_name, fe.fe_flowstats.fs_rbytes, fe.fe_flowstats.fs_obytes); break; } } return (DCMD_OK); } /* * Parse the arguments passed to the dcmd and print all or one flow_entry_t * structures */ static int mac_flow_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { uint_t args = 0; if (!(flags & DCMD_ADDRSPEC)) { if (mdb_walk_dcmd("mac_flow", "mac_flow", argc, argv) == -1) { mdb_warn("failed to walk 'mac_flow'"); return (DCMD_ERR); } return (DCMD_OK); } if ((mdb_getopts(argc, argv, 'a', MDB_OPT_SETBITS, MAC_FLOW_ATTR, &args, 'p', MDB_OPT_SETBITS, MAC_FLOW_PROP, &args, 'm', MDB_OPT_SETBITS, MAC_FLOW_MISC, &args, 'r', MDB_OPT_SETBITS, MAC_FLOW_RX, &args, 't', MDB_OPT_SETBITS, MAC_FLOW_TX, &args, 's', MDB_OPT_SETBITS, MAC_FLOW_STATS, &args, 'u', MDB_OPT_SETBITS, MAC_FLOW_USER, &args) != argc)) { return (DCMD_USAGE); } if (argc > 2 || (argc == 2 && !(args & MAC_FLOW_USER))) return (DCMD_USAGE); /* * If no arguments was specified or just "-u" was specified then * we default to printing basic information of flows. */ if (args == 0 || args == MAC_FLOW_USER) args |= MAC_FLOW_NONE; return (mac_flow_dcmd_output(addr, flags, args)); } static void mac_flow_help(void) { mdb_printf("If an address is specified, then flow_entry structure at " "that address is printed. Otherwise all the flows in the system " "are printed.\n"); mdb_printf("Options:\n" "\t-u\tdisplay user defined link & vnic flows.\n" "\t-a\tdisplay flow attributes\n" "\t-p\tdisplay flow properties\n" "\t-r\tdisplay rx side information\n" "\t-t\tdisplay tx side information\n" "\t-s\tdisplay flow statistics\n" "\t-m\tdisplay miscellaneous flow information\n\n"); mdb_printf("%Interpreting Flow type and Flow flags output.%\n"); mdb_printf("Flow Types:\n"); mdb_printf("\t P --> FLOW_PRIMARY_MAC\n"); mdb_printf("\t V --> FLOW_VNIC_MAC\n"); mdb_printf("\t M --> FLOW_MCAST\n"); mdb_printf("\t O --> FLOW_OTHER\n"); mdb_printf("\t U --> FLOW_USER\n"); mdb_printf("\t NS --> FLOW_NO_STATS\n\n"); mdb_printf("Flow Flags:\n"); mdb_printf("\t Q --> FE_QUIESCE\n"); mdb_printf("\t W --> FE_WAITER\n"); mdb_printf("\t T --> FE_FLOW_TAB\n"); mdb_printf("\t G --> FE_G_FLOW_HASH\n"); mdb_printf("\t I --> FE_INCIPIENT\n"); mdb_printf("\t C --> FE_CONDEMNED\n"); mdb_printf("\t NU --> FE_UF_NO_DATAPATH\n"); mdb_printf("\t NC --> FE_MC_NO_DATAPATH\n"); } /* * called once by the debugger when the mac_flow walk begins. */ static int mac_flow_walk_init(mdb_walk_state_t *wsp) { if (mdb_layered_walk(LAYERED_WALKER_FOR_FLOW, wsp) == -1) { mdb_warn("failed to walk 'mac_flow'"); return (WALK_ERR); } return (WALK_NEXT); } /* * Common walker step funciton for flow_entry_t, mac_soft_ring_set_t and * mac_ring_t. * * Steps through each flow_entry_t and calls the callback function. If the * user executed ::walk mac_flow, it just prints the address or if the user * executed ::mac_flow it displays selected fields of flow_entry_t structure * by calling "mac_flow_dcmd" */ static int mac_common_walk_step(mdb_walk_state_t *wsp) { int status; if (wsp->walk_addr == NULL) return (WALK_DONE); status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, wsp->walk_cbdata); return (status); } static char * mac_srs_txmode2str(mac_tx_srs_mode_t mode) { switch (mode) { case SRS_TX_DEFAULT: return ("DEF"); case SRS_TX_SERIALIZE: return ("SER"); case SRS_TX_FANOUT: return ("FO"); case SRS_TX_BW: return ("BW"); case SRS_TX_BW_FANOUT: return ("BWFO"); } return ("--"); } static void mac_srs_help(void) { mdb_printf("If an address is specified, then mac_soft_ring_set " "structure at that address is printed. Otherwise all the " "SRS in the system are printed.\n"); mdb_printf("Options:\n" "\t-r\tdisplay recieve side SRS structures\n" "\t-t\tdisplay transmit side SRS structures\n" "\t-s\tdisplay statistics for RX or TX side\n" "\t-c\tdisplay CPU binding for RX or TX side\n" "\t-v\tverbose flag for CPU binding to list cpus\n" "Note: use -r or -t (to specify RX or TX side respectively) along " "with -c or -s\n"); mdb_printf("\n%Interpreting TX Modes%\n"); mdb_printf("\t DEF --> Default\n"); mdb_printf("\t SER --> Serialize\n"); mdb_printf("\t FO --> Fanout\n"); mdb_printf("\t BW --> Bandwidth\n"); mdb_printf("\tBWFO --> Bandwidth Fanout\n"); } /* * In verbose mode "::mac_srs -rcv or ::mac_srs -tcv", we print the CPUs * assigned to a link and CPUS assigned to the soft rings. * 'len' is used for formatting the output and represents the number of * spaces between CPU list and Fanout CPU list in the output. */ static boolean_t mac_srs_print_cpu(int *i, uint32_t cnt, uint32_t *cpu_list, int *len) { int num = 0; if (*i == 0) mdb_printf("("); else mdb_printf(" "); while (*i < cnt) { /* We print 6 CPU's at a time to keep display within 80 cols */ if (((num + 1) % 7) == 0) { if (len != NULL) *len = 2; return (B_FALSE); } mdb_printf("%02x%c", cpu_list[*i], ((*i == cnt - 1)?')':',')); ++*i; ++num; } if (len != NULL) *len = (7 - num) * 3; return (B_TRUE); } static int mac_srs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { uint_t args = MAC_SRS_NONE; mac_soft_ring_set_t srs; mac_client_impl_t mci; if (!(flags & DCMD_ADDRSPEC)) { if (mdb_walk_dcmd("mac_srs", "mac_srs", argc, argv) == -1) { mdb_warn("failed to walk 'mac_srs'"); return (DCMD_ERR); } return (DCMD_OK); } if (mdb_getopts(argc, argv, 'r', MDB_OPT_SETBITS, MAC_SRS_RX, &args, 't', MDB_OPT_SETBITS, MAC_SRS_TX, &args, 'c', MDB_OPT_SETBITS, MAC_SRS_CPU, &args, 'v', MDB_OPT_SETBITS, MAC_SRS_VERBOSE, &args, 's', MDB_OPT_SETBITS, MAC_SRS_STAT, &args) != argc) { return (DCMD_USAGE); } if (argc > 2) return (DCMD_USAGE); if (mdb_vread(&srs, sizeof (srs), addr) == -1) { mdb_warn("failed to read struct mac_soft_ring_set_s at %p", addr); return (DCMD_ERR); } if (mdb_vread(&mci, sizeof (mci), (uintptr_t)srs.srs_mcip) == -1) { mdb_warn("failed to read struct mac_client_impl_t at %p " "for SRS %p", srs.srs_mcip, addr); return (DCMD_ERR); } switch (args) { case MAC_SRS_RX: { if (DCMD_HDRSPEC(flags)) { mdb_printf("%?s %-20s %-8s %-8s %-8s " "%-8s %-3s\n", "", "", "", "", "MBLK", "Q", "SR"); mdb_printf("%%?s %-20s %-8s %-8s %-8s " "%-8s %-3s%\n", "ADDR", "LINK_NAME", "STATE", "TYPE", "CNT", "BYTES", "CNT"); } if (srs.srs_type & SRST_TX) return (DCMD_OK); mdb_printf("%?p %-20s %08x %08x " "%-8d %-8d %-3d\n", addr, mci.mci_name, srs.srs_state, srs.srs_type, srs.srs_count, srs.srs_size, srs.srs_soft_ring_count); break; } case MAC_SRS_TX: { if (DCMD_HDRSPEC(flags)) { mdb_printf("%?s %-16s %-4s %-8s " "%-8s %-8s %-8s %-3s\n", "", "", "TX", "", "", "MBLK", "Q", "SR"); mdb_printf("%%?s %-16s %-4s %-8s " "%-8s %-8s %-8s %-3s%\n", "ADDR", "LINK_NAME", "MODE", "STATE", "TYPE", "CNT", "BYTES", "CNT"); } if (!(srs.srs_type & SRST_TX)) return (DCMD_OK); mdb_printf("%?p %-16s %-4s " "%08x %08x %-8d %-8d %-3d\n", addr, mci.mci_name, mac_srs_txmode2str(srs.srs_tx.st_mode), srs.srs_state, srs.srs_type, srs.srs_count, srs.srs_size, srs.srs_oth_ring_count); break; } case MAC_SRS_RXCPU: { mac_cpus_t mc = srs.srs_cpu; if (DCMD_HDRSPEC(flags)) { mdb_printf("%?s %-20s %-4s %-4s " "%-6s %-4s %-7s\n", "", "", "NUM", "POLL", "WORKER", "INTR", "FANOUT"); mdb_printf("%%?s %-20s %-4s %-4s " "%-6s %-4s %-7s%\n", "ADDR", "LINK_NAME", "CPUS", "CPU", "CPU", "CPU", "CPU_CNT"); } if ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX)) return (DCMD_OK); mdb_printf("%?p %-20s %-4d %-4d " "%-6d %-4d %-7d\n", addr, mci.mci_name, mc.mc_ncpus, mc.mc_pollid, mc.mc_workerid, mc.mc_intr_cpu, mc.mc_fanout_cnt); break; } case MAC_SRS_TXCPU: { mac_cpus_t mc = srs.srs_cpu; if (DCMD_HDRSPEC(flags)) { mdb_printf("%?s %-20s %-4s %-6s " "%-4s %-7s\n", "", "", "NUM", "WORKER", "INTR", "FANOUT"); mdb_printf("%%?s %-20s %-4s %-6s " "%-4s %-7s%\n", "ADDR", "LINK_NAME", "CPUS", "CPU", "CPU", "CPU_CNT"); } if ((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX)) return (DCMD_OK); mdb_printf("%?p %-20s %-4d " "%-6d %-4d %-7d\n", addr, mci.mci_name, mc.mc_ncpus, mc.mc_workerid, mc.mc_intr_cpu, mc.mc_fanout_cnt); break; } case MAC_SRS_RXCPUVERBOSE: case MAC_SRS_TXCPUVERBOSE: { mac_cpus_t mc = srs.srs_cpu; int cpu_index = 0, fanout_index = 0, len = 0; boolean_t cpu_done = B_FALSE, fanout_done = B_FALSE; if (DCMD_HDRSPEC(flags)) { mdb_printf("%?s %-20s %-20s %-20s\n", "", "", "CPU_COUNT", "FANOUT_CPU_COUNT"); mdb_printf("%%?s %-20s " "%-20s %-20s%\n", "ADDR", "LINK_NAME", "(CPU_LIST)", "(CPU_LIST)"); } if (((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX)) || ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX))) return (DCMD_OK); mdb_printf("%?p %-20s %-20d %-20d\n", addr, mci.mci_name, mc.mc_ncpus, mc.mc_fanout_cnt); if (mc.mc_ncpus == 0 && mc.mc_fanout_cnt == 0) break; /* print all cpus and cpus for soft rings */ while (!cpu_done || !fanout_done) { boolean_t old_value = cpu_done; if (!cpu_done) { mdb_printf("%?s %20s ", "", ""); cpu_done = mac_srs_print_cpu(&cpu_index, mc.mc_ncpus, mc.mc_cpus, &len); } if (!fanout_done) { if (old_value) mdb_printf("%?s %-40s", "", ""); else mdb_printf("%*s", len, ""); fanout_done = mac_srs_print_cpu(&fanout_index, mc.mc_fanout_cnt, mc.mc_fanout_cpus, NULL); } mdb_printf("\n"); } break; } case MAC_SRS_RXSTAT: { mac_srs_rx_t srs_rx = srs.srs_rx; if (DCMD_HDRSPEC(flags)) { mdb_printf("%?s %-16s %-8s %-8s " "%-8s %-8s %-8s\n", "", "", "INTR", "POLL", "CHAIN", "CHAIN", "CHAIN"); mdb_printf("%%?s %-16s %-8s %-8s " "%-8s %-8s %-8s%\n", "ADDR", "LINK_NAME", "COUNT", "COUNT", "<10", "10-50", ">50"); } if (srs.srs_type & SRST_TX) return (DCMD_OK); mdb_printf("%?p %-16s %-8d " "%-8d %-8d " "%-8d %-8d\n", addr, mci.mci_name, srs_rx.sr_intr_count, srs_rx.sr_poll_count, srs_rx.sr_chain_cnt_undr10, srs_rx.sr_chain_cnt_10to50, srs_rx.sr_chain_cnt_over50); break; } case MAC_SRS_TXSTAT: { mac_srs_tx_t srs_tx = srs.srs_tx; if (DCMD_HDRSPEC(flags)) { mdb_printf("%?s %-20s %-5s %-8s " "%-8s %-8s %-8s\n", "", "", "WOKEN", "MAX", "DROP", "BLOCK", "UNBLOCK"); mdb_printf("%%?s %-20s %-5s %-8s " "%-8s %-8s %-8s%\n", "ADDR", "LINK_NAME", "UP", "Q_COUNT", "COUNT", "COUNT", "COUNT"); } if (!(srs.srs_type & SRST_TX)) return (DCMD_OK); mdb_printf("%?p %-20s %-5d " "%-8d %-8d " "%-8d %-8d\n", addr, mci.mci_name, srs.srs_tx.st_woken_up, srs_tx.st_max_q_cnt, srs_tx.st_drop_count, srs_tx.st_blocked_cnt, srs_tx.st_unblocked_cnt); break; } case MAC_SRS_NONE: { if (DCMD_HDRSPEC(flags)) { mdb_printf("%%?s %-20s %?s %?s %-3s%\n", "ADDR", "LINK_NAME", "FLENT", "HW RING", "DIR"); } mdb_printf("%?p %-20s %?p %?p " "%-3s ", addr, mci.mci_name, srs.srs_flent, srs.srs_ring, (srs.srs_type & SRST_TX ? "TX" : "RX")); break; } default: return (DCMD_USAGE); } return (DCMD_OK); } static int mac_srs_walk_init(mdb_walk_state_t *wsp) { if (mdb_layered_walk(LAYERED_WALKER_FOR_SRS, wsp) == -1) { mdb_warn("failed to walk 'mac_srs'"); return (WALK_ERR); } return (WALK_NEXT); } static char * mac_ring_state2str(mac_ring_state_t state) { switch (state) { case MR_FREE: return ("free"); case MR_NEWLY_ADDED: return ("new"); case MR_INUSE: return ("inuse"); } return ("--"); } static char * mac_ring_classify2str(mac_classify_type_t classify) { switch (classify) { case MAC_NO_CLASSIFIER: return ("no"); case MAC_SW_CLASSIFIER: return ("sw"); case MAC_HW_CLASSIFIER: return ("hw"); } return ("--"); } static int mac_ring_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { mac_ring_t ring; mac_group_t group; flow_entry_t flent; mac_soft_ring_set_t srs; if (!(flags & DCMD_ADDRSPEC)) { if (mdb_walk_dcmd("mac_ring", "mac_ring", argc, argv) == -1) { mdb_warn("failed to walk 'mac_ring'"); return (DCMD_ERR); } return (DCMD_OK); } if (mdb_vread(&ring, sizeof (ring), addr) == -1) { mdb_warn("failed to read struct mac_ring_s at %p", addr); return (DCMD_ERR); } bzero(&flent, sizeof (flent)); if (mdb_vread(&srs, sizeof (srs), (uintptr_t)ring.mr_srs) != -1) { (void) mdb_vread(&flent, sizeof (flent), (uintptr_t)srs.srs_flent); } (void) mdb_vread(&group, sizeof (group), (uintptr_t)ring.mr_gh); if (DCMD_HDRSPEC(flags)) { mdb_printf("%%?s %4s %5s %4s %?s " "%5s %?s %?s %s %\n", "ADDR", "TYPE", "STATE", "FLAG", "GROUP", "CLASS", "MIP", "SRS", "FLOW NAME"); } mdb_printf("%?p %-4s " "%5s %04x " "%?p %-5s " "%?p %?p %s\n", addr, ((ring.mr_type == 1)? "RX" : "TX"), mac_ring_state2str(ring.mr_state), ring.mr_flag, ring.mr_gh, mac_ring_classify2str(ring.mr_classify_type), group.mrg_mh, ring.mr_srs, flent.fe_flow_name); return (DCMD_OK); } static int mac_ring_walk_init(mdb_walk_state_t *wsp) { if (mdb_layered_walk(LAYERED_WALKER_FOR_RING, wsp) == -1) { mdb_warn("failed to walk `mac_ring`"); return (WALK_ERR); } return (WALK_NEXT); } static void mac_ring_help(void) { mdb_printf("If an address is specified, then mac_ring_t " "structure at that address is printed. Otherwise all the " "hardware rings in the system are printed.\n"); } /* Supported dee-commands */ static const mdb_dcmd_t dcmds[] = { {"mac_flow", "?[-u] [-aprtsm]", "display Flow Entry structures", mac_flow_dcmd, mac_flow_help}, {"mac_srs", "?[ -r[s|c[v]] | -t[s|c[v]] ]", "display MAC Soft Ring Set" " structures", mac_srs_dcmd, mac_srs_help}, {"mac_ring", "?", "display MAC ring (hardware) structures", mac_ring_dcmd, mac_ring_help}, { NULL } }; /* Supported walkers */ static const mdb_walker_t walkers[] = { {"mac_flow", "walk list of flow entry structures", mac_flow_walk_init, mac_common_walk_step, NULL, NULL}, {"mac_srs", "walk list of mac soft ring set structures", mac_srs_walk_init, mac_common_walk_step, NULL, NULL}, {"mac_ring", "walk list of mac ring structures", mac_ring_walk_init, mac_common_walk_step, NULL, NULL}, { NULL } }; static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; const mdb_modinfo_t * _mdb_init(void) { return (&modinfo); }