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