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