/*
* 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
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/mdb_modapi.h>
#include <sys/mac_provider.h>
#include <sys/mac_client.h>
#include <sys/mac_client_impl.h>
#include <sys/mac_flow_impl.h>
#include <sys/mac_soft_ring.h>
#include <sys/mac_stat.h>
/* arguments passed to mac_flow dee-command */
/* arguments passed to mac_srs dee-command */
/* arguments passed to mac_group dcmd */
static char *
{
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 *
{
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 Mbps.
*/
static char *
{
else
return (buf);
}
static void
{
switch (args) {
case MAC_FLOW_NONE:
mdb_printf("%?s %-20s %4s %?s %?s %-16s\n",
"", "", "LINK", "", "", "MIP");
mdb_printf("%<u>%?s %-20s %4s %?s %?s %-16s%</u>\n",
"ADDR", "FLOW NAME", "ID", "MCIP", "MIP", "NAME");
break;
case MAC_FLOW_ATTR:
mdb_printf("%<u>%?s %-32s %-7s %6s "
"%-9s %s%</u>\n",
"ADDR", "FLOW NAME", "PROTO", "PORT",
"DSFLD:MSK", "IPADDR");
break;
case MAC_FLOW_PROP:
mdb_printf("%<u>%?s %-32s %8s %9s%</u>\n",
"ADDR", "FLOW NAME", "MAXBW(M)", "PRIORITY");
break;
case MAC_FLOW_MISC:
mdb_printf("%<u>%?s %-24s %10s %10s "
"%20s %4s%</u>\n",
"ADDR", "FLOW NAME", "TYPE", "FLAGS",
"MATCH_FN", "ZONE");
break;
case MAC_FLOW_RX:
mdb_printf("%<u>%?s %-24s %3s %s%</u>\n",
"ADDR", "FLOW NAME", "CNT", "SRS");
break;
case MAC_FLOW_TX:
mdb_printf("%<u>%?s %-32s %?s %</u>\n",
"ADDR", "FLOW NAME", "TX_SRS");
break;
case MAC_FLOW_STATS:
mdb_printf("%<u>%?s %-32s %16s %16s%</u>\n",
"ADDR", "FLOW NAME", "RBYTES", "OBYTES");
break;
}
}
/*
* Display selected fields of the flow_entry_t structure
*/
static int
{
{ NULL, 0, 0 }
};
{ NULL, 0, 0 }
};
return (DCMD_ERR);
}
if (args & MAC_FLOW_USER) {
args &= ~MAC_FLOW_USER;
if (DCMD_HDRSPEC(flags))
return (DCMD_OK);
}
}
if (DCMD_HDRSPEC(flags))
}
switch (args) {
case MAC_FLOW_NONE: {
mdb_printf("%?p %-20s %4d %?p "
"%?p %-16s\n",
break;
}
case MAC_FLOW_ATTR: {
mdb_warn("failed to read struct flow_description at %p",
return (DCMD_ERR);
}
mdb_printf("%?p %-32s "
"%-7s %6d "
"%4d:%-4d ",
} else {
}
mdb_printf("\n");
break;
}
case MAC_FLOW_PROP: {
mdb_warn("failed to read struct mac_resoource_props "
"at %p", prop_addr);
return (DCMD_ERR);
}
mdb_printf("%?p %-32s "
"%8s %9s\n",
break;
}
case MAC_FLOW_MISC: {
MDB_SYM_NAMLEN, &sym);
mdb_printf("%?p %-24s %10s %10s %20s\n",
break;
}
case MAC_FLOW_RX: {
int i;
mdb_printf("%?p %-24s %3d ",
for (i = 0; i < MAX_RINGS_PER_GROUP; i++) {
if (rx_srs[i] == 0)
continue;
}
mdb_printf("\n");
break;
}
case MAC_FLOW_TX: {
mdb_printf("%?p %-32s %?p\n",
break;
}
case MAC_FLOW_STATS: {
int i;
/*
* Sum bytes for all Rx SRS.
*/
for (i = 0; i < fe.fe_rx_srs_cnt; i++) {
mdb_warn("failed to read mac_rx_stats_t at %p",
return (DCMD_ERR);
}
}
/*
* Sum bytes for Tx SRS.
*/
mdb_warn("failed to read max_tx_stats_t at %p",
return (DCMD_ERR);
}
}
mdb_printf("%?p %-32s %16llu %16llu\n",
break;
}
}
return (DCMD_OK);
}
/*
* Parse the arguments passed to the dcmd and print all or one flow_entry_t
* structures
*/
static int
{
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("failed to walk 'mac_flow'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
return (DCMD_USAGE);
}
return (DCMD_USAGE);
/*
* If no arguments was specified or just "-u" was specified then
* we default to printing basic information of flows.
*/
args |= MAC_FLOW_NONE;
}
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("%<u>Interpreting Flow type and Flow flags output.%</u>\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
{
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
{
int status;
return (WALK_DONE);
wsp->walk_cbdata);
return (status);
}
static char *
{
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");
case SRS_TX_AGGR:
return ("AG");
case SRS_TX_BW_AGGR:
return ("BWAG");
}
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"
"\t-i\tdisplay mac_ring_t and interrupt information\n"
"Note: use -r or -t (to specify RX or TX side respectively) along "
"with -c or -s\n");
mdb_printf("\n%<u>Interpreting TX Modes%</u>\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");
mdb_printf("\t AG --> Aggr\n");
mdb_printf("\tBWAG --> Bandwidth Aggr\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
{
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 */
*len = 2;
return (B_FALSE);
}
++*i;
++num;
}
return (B_TRUE);
}
static int
{
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("failed to walk 'mac_srs'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
return (DCMD_USAGE);
}
if (argc > 2)
return (DCMD_USAGE);
mdb_warn("failed to read struct mac_soft_ring_set_s at %p",
addr);
return (DCMD_ERR);
}
mdb_warn("failed to read struct mac_client_impl_t at %p "
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("%<u>%?s %-20s %-8s %-8s %8s "
"%8s %3s%</u>\n",
"ADDR", "LINK_NAME", "STATE", "TYPE", "CNT",
"BYTES", "CNT");
}
return (DCMD_OK);
mdb_printf("%?p %-20s %08x %08x "
"%8d %8d %3d\n",
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("%<u>%?s %-16s %-4s %-8s "
"%-8s %8s %8s %3s%</u>\n",
"ADDR", "LINK_NAME", "MODE", "STATE",
"TYPE", "CNT", "BYTES", "CNT");
}
return (DCMD_OK);
mdb_printf("%?p %-16s %-4s "
"%08x %08x %8d %8d %3d\n",
break;
}
case MAC_SRS_RXCPU: {
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%?s %-20s %-4s %-4s "
"%-6s %-4s %-7s\n",
"", "", "NUM", "POLL",
"WORKER", "INTR", "FANOUT");
mdb_printf("%<u>%?s %-20s %-4s %-4s "
"%-6s %-4s %-7s%</u>\n",
"ADDR", "LINK_NAME", "CPUS", "CPU",
"CPU", "CPU", "CPU_CNT");
}
return (DCMD_OK);
mdb_printf("%?p %-20s %-4d %-4d "
"%-6d %-4d %-7d\n",
break;
}
case MAC_SRS_TXCPU: {
int i;
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%?s %-12s %?s %8s %8s %8s\n",
"", "", "SOFT", "WORKER", "INTR", "RETARGETED");
mdb_printf("%<u>%?s %-12s %?s %8s %8s %8s%</u>\n",
"ADDR", "LINK_NAME", "RING", "CPU", "CPU", "CPU");
}
return (DCMD_OK);
/*
* Case of no soft rings, print the info from
* mac_srs_tx_t.
*/
if (srs.srs_tx_ring_count == 0) {
mdb_printf("%?p %8d %8d %8d\n",
0, mc.mc_tx_fanout_cpus[0],
mc.mc_tx_intr_cpu[0],
mc.mc_tx_retargeted_cpu[0]);
break;
}
if (first) {
mdb_printf("%?p %8d %8d %8d\n",
mc.mc_tx_intr_cpu[i],
mc.mc_tx_retargeted_cpu[i]);
continue;
}
mdb_printf("%?s %-12s %?p %8d %8d %8d\n",
}
break;
}
case MAC_SRS_TXINTR: {
int i;
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%?s %-12s %?s %8s %?s %6s %6s\n",
"", "", "SOFT", "WORKER", "MAC", "", "INTR");
mdb_printf("%<u>%?s %-12s %?s %8s %?s %6s %6s%</u>\n",
"ADDR", "LINK_NAME", "RING", "CPU", "RING",
"SHARED", "CPU");
}
return (DCMD_OK);
/*
* Case of no soft rings, print the info from
* mac_srs_tx_t.
*/
if (srs.srs_tx_ring_count == 0) {
mdb_printf("%?p %8d %?p %6d %6d\n",
mc.mc_tx_retargeted_cpu[0]);
} else {
mdb_printf("%?p %8d %?p %6d %6d\n",
0, mc.mc_tx_fanout_cpus[0], 0,
0, mc.mc_tx_retargeted_cpu[0]);
}
break;
}
if (first) {
mdb_printf("%?p %8d %?p %6d %6d\n",
mc.mc_tx_retargeted_cpu[i]);
continue;
}
mdb_printf("%?s %-12s %?p %8d %?p %6d %6d\n",
mc.mc_tx_retargeted_cpu[i]);
}
break;
}
case MAC_SRS_RXINTR: {
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%?s %-12s %?s %8s %6s %6s\n",
"", "", "MAC", "", "POLL", "INTR");
mdb_printf("%<u>%?s %-12s %?s %8s %6s %6s%</u>\n",
"ADDR", "LINK_NAME", "RING", "SHARED", "CPU",
"CPU");
}
return (DCMD_OK);
mdb_printf("%?p %8d %6d %6d\n",
} else {
mdb_printf("%?p %8d %6d %6d\n",
}
break;
}
case MAC_SRS_RXCPUVERBOSE:
case MAC_SRS_TXCPUVERBOSE: {
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%?s %-20s %-20s %-20s\n",
"", "", "CPU_COUNT", "FANOUT_CPU_COUNT");
mdb_printf("%<u>%?s %-20s "
"%-20s %-20s%</u>\n",
"ADDR", "LINK_NAME",
"(CPU_LIST)", "(CPU_LIST)");
}
return (DCMD_OK);
break;
/* print all cpus and cpus for soft rings */
while (!cpu_done || !fanout_done) {
if (!cpu_done) {
}
if (!fanout_done) {
if (old_value)
else
}
mdb_printf("\n");
}
break;
}
case MAC_SRS_RXSTAT: {
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%?s %-16s %8s %8s "
"%8s %8s %8s\n",
"", "", "INTR", "POLL",
"CHAIN", "CHAIN", "CHAIN");
mdb_printf("%<u>%?s %-16s %8s %8s "
"%8s %8s %8s%</u>\n",
"ADDR", "LINK_NAME", "COUNT", "COUNT",
"<10", "10-50", ">50");
}
return (DCMD_OK);
mdb_printf("%?p %-16s %8d "
"%8d %8d "
"%8d %8d\n",
break;
}
case MAC_SRS_TXSTAT: {
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%?s %-20s %?s %8s %8s %8s\n",
"", "", "SOFT", "DROP", "BLOCK", "UNBLOCK");
mdb_printf("%<u>%?s %-20s %?s %8s %8s %8s%</u>\n",
"ADDR", "LINK_NAME", "RING", "COUNT", "COUNT",
"COUNT");
}
return (DCMD_OK);
/*
* Case of no soft rings, print the info from
* mac_srs_tx_t.
*/
if (srs.srs_tx_ring_count == 0) {
mdb_printf("%?p %8d %8d %8d\n",
0, mac_tx_stat->mts_sdrops,
break;
}
if (first) {
mdb_printf("%?p %8d %8d %8d\n",
continue;
}
mdb_printf("%?s %-20s %?p %8d %8d %8d\n",
}
break;
}
case MAC_SRS_NONE: {
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%?s %-20s %?s %?s %-3s%</u>\n",
"ADDR", "LINK_NAME", "FLENT", "HW RING", "DIR");
}
mdb_printf("%?p %-20s %?p %?p "
"%-3s ",
break;
}
default:
return (DCMD_USAGE);
}
return (DCMD_OK);
}
static int
{
mdb_warn("failed to walk 'mac_srs'");
return (WALK_ERR);
}
return (WALK_NEXT);
}
static char *
{
switch (state) {
case MR_FREE:
return ("free");
case MR_NEWLY_ADDED:
return ("new");
case MR_INUSE:
return ("inuse");
}
return ("--");
}
static char *
{
switch (classify) {
case MAC_NO_CLASSIFIER:
return ("no");
case MAC_SW_CLASSIFIER:
return ("sw");
case MAC_HW_CLASSIFIER:
return ("hw");
}
return ("--");
}
static int
{
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("failed to walk 'mac_ring'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
return (DCMD_ERR);
}
}
if (DCMD_HDRSPEC(flags)) {
mdb_printf("%<u>%?s %4s %5s %4s %?s "
"%5s %?s %?s %s %</u>\n",
"ADDR", "TYPE", "STATE", "FLAG", "GROUP",
"CLASS", "MIP", "SRS", "FLOW NAME");
}
mdb_printf("%?p %-4s "
"%5s %04x "
"%?p %-5s "
"%?p %?p %s\n",
return (DCMD_OK);
}
static int
{
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");
}
/*
* To walk groups we have to have our own somewhat-complicated state machine. We
* basically start by walking the mac_impl_t walker as all groups are stored off
* of the various mac_impl_t in the system. The tx and rx rings are kept
* separately. So we'll need to walk through all the rx rings and then all of
* the tx rings.
*/
static int
{
int ret;
mdb_warn("non-global walks are not supported\n");
return (WALK_ERR);
}
return (ret);
}
return (WALK_NEXT);
}
static int
{
int ret;
/*
* Nothing to do if we can't find the layer above us. But the kmem
* walkers are a bit unsporting, they don't actually read in the data
* for us.
*/
return (WALK_DONE);
return (DCMD_ERR);
}
/*
* First go for rx groups, then tx groups.
*/
return (WALK_ERR);
}
return (ret);
}
return (WALK_ERR);
}
return (ret);
}
return (WALK_NEXT);
}
static int
{
int clients = 0;
return (-1);
}
clients++;
}
return (clients);
}
static const char *
{
const char *ret;
case MAC_RING_TYPE_RX:
ret = "RECEIVE";
break;
case MAC_RING_TYPE_TX:
ret = "TRANSMIT";
break;
default:
ret = "UNKNOWN";
break;
}
return (ret);
}
static const char *
{
const char *ret;
case MAC_GROUP_STATE_UNINIT:
ret = "UNINT";
break;
ret = "REGISTERED";
break;
case MAC_GROUP_STATE_RESERVED:
ret = "RESERVED";
break;
case MAC_GROUP_STATE_SHARED:
ret = "SHARED";
break;
default:
ret = "UNKNOWN";
break;
}
return (ret);
}
static int
{
int clients;
if (!(flags & DCMD_ADDRSPEC)) {
mdb_warn("failed to walk 'mac_group'");
return (DCMD_ERR);
}
return (DCMD_OK);
}
return (DCMD_USAGE);
return (DCMD_ERR);
}
mdb_printf("%<u>%-?s %-8s %-10s %6s %8s %-?s%</u>\n",
"ADDR", "TYPE", "STATE", "NRINGS", "NCLIENTS", "RINGS");
}
return (DCMD_OK);
return (DCMD_OK);
/*
* By default, don't show uninitialized groups. They're not very
* interesting. They have no rings and no clients.
*/
(args & MAC_GROUP_UNINIT) == 0)
return (DCMD_OK);
if (flags & DCMD_PIPE_OUT) {
return (DCMD_OK);
}
return (DCMD_OK);
}
/* Supported dee-commands */
{"mac_flow", "?[-u] [-aprtsm]", "display Flow Entry structures",
NULL },
{"mac_srs", "?[ -r[i|s|c[v]] | -t[i|s|c[v]] ]",
"display MAC Soft Ring Set" " structures", mac_srs_dcmd,
{"mac_ring", "?", "display MAC ring (hardware) structures",
{ NULL }
};
/* Supported walkers */
{"mac_srs", "walk list of mac soft ring set structures",
{ NULL }
};
const mdb_modinfo_t *
_mdb_init(void)
{
return (&modinfo);
}