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                 for (i = 0; i < fe.fe_rx_srs_cnt; i++) {
 336                         mac_srs = (mac_soft_ring_set_t *)(fe.fe_rx_srs[i]);
 337                         mac_rx_stat = &mac_srs->srs_rx.sr_stat;
 338                         totibytes += mac_rx_stat->mrs_intrbytes +
 339                             mac_rx_stat->mrs_pollbytes +
 340                             mac_rx_stat->mrs_lclbytes;
 341                 }
 342                 mac_srs = (mac_soft_ring_set_t *)(fe.fe_tx_srs);
 343                 if (mac_srs != NULL) {
 344                         mac_tx_stat = &mac_srs->srs_tx.st_stat;
 345                         totobytes = mac_tx_stat->mts_obytes;
 346                 }
 347                 mdb_printf("%?p %-32s %16llu %16llu\n",
 348                     addr, fe.fe_flow_name, totibytes, totobytes);
 349 
 350                 break;
 351         }
 352         }
 353         return (DCMD_OK);
 354 }
 355 
 356 /*
 357  * Parse the arguments passed to the dcmd and print all or one flow_entry_t
 358  * structures
 359  */
 360 static int
 361 mac_flow_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 362 {
 363         uint_t  args = 0;
 364 
 365         if (!(flags & DCMD_ADDRSPEC)) {
 366                 if (mdb_walk_dcmd("mac_flow", "mac_flow", argc, argv) == -1) {
 367                         mdb_warn("failed to walk 'mac_flow'");
 368                         return (DCMD_ERR);
 369                 }
 370                 return (DCMD_OK);
 371         }
 372         if ((mdb_getopts(argc, argv,
 373             'a', MDB_OPT_SETBITS, MAC_FLOW_ATTR, &args,
 374             'p', MDB_OPT_SETBITS, MAC_FLOW_PROP, &args,
 375             'm', MDB_OPT_SETBITS, MAC_FLOW_MISC, &args,
 376             'r', MDB_OPT_SETBITS, MAC_FLOW_RX, &args,
 377             't', MDB_OPT_SETBITS, MAC_FLOW_TX, &args,
 378             's', MDB_OPT_SETBITS, MAC_FLOW_STATS, &args,
 379             'u', MDB_OPT_SETBITS, MAC_FLOW_USER, &args,
 380             NULL) != argc)) {
 381                 return (DCMD_USAGE);
 382         }
 383         if (argc > 2 || (argc == 2 && !(args & MAC_FLOW_USER)))
 384                 return (DCMD_USAGE);
 385         /*
 386          * If no arguments was specified or just "-u" was specified then
 387          * we default to printing basic information of flows.
 388          */
 389         if (args == 0 || args == MAC_FLOW_USER)
 390                 args |= MAC_FLOW_NONE;
 391 
 392         return (mac_flow_dcmd_output(addr, flags, args));
 393 }
 394 
 395 static void
 396 mac_flow_help(void)
 397 {
 398         mdb_printf("If an address is specified, then flow_entry structure at "
 399             "that address is printed. Otherwise all the flows in the system "
 400             "are printed.\n");
 401         mdb_printf("Options:\n"
 402             "\t-u\tdisplay user defined link & vnic flows.\n"
 403             "\t-a\tdisplay flow attributes\n"
 404             "\t-p\tdisplay flow properties\n"
 405             "\t-r\tdisplay rx side information\n"
 406             "\t-t\tdisplay tx side information\n"
 407             "\t-s\tdisplay flow statistics\n"
 408             "\t-m\tdisplay miscellaneous flow information\n\n");
 409         mdb_printf("%<u>Interpreting Flow type and Flow flags output.%</u>\n");
 410         mdb_printf("Flow Types:\n");
 411         mdb_printf("\t  P --> FLOW_PRIMARY_MAC\n");
 412         mdb_printf("\t  V --> FLOW_VNIC_MAC\n");
 413         mdb_printf("\t  M --> FLOW_MCAST\n");
 414         mdb_printf("\t  O --> FLOW_OTHER\n");
 415         mdb_printf("\t  U --> FLOW_USER\n");
 416         mdb_printf("\t NS --> FLOW_NO_STATS\n\n");
 417         mdb_printf("Flow Flags:\n");
 418         mdb_printf("\t  Q --> FE_QUIESCE\n");
 419         mdb_printf("\t  W --> FE_WAITER\n");
 420         mdb_printf("\t  T --> FE_FLOW_TAB\n");
 421         mdb_printf("\t  G --> FE_G_FLOW_HASH\n");
 422         mdb_printf("\t  I --> FE_INCIPIENT\n");
 423         mdb_printf("\t  C --> FE_CONDEMNED\n");
 424         mdb_printf("\t NU --> FE_UF_NO_DATAPATH\n");
 425         mdb_printf("\t NC --> FE_MC_NO_DATAPATH\n");
 426 }
 427 
 428 /*
 429  * called once by the debugger when the mac_flow walk begins.
 430  */
 431 static int
 432 mac_flow_walk_init(mdb_walk_state_t *wsp)
 433 {
 434         if (mdb_layered_walk(LAYERED_WALKER_FOR_FLOW, wsp) == -1) {
 435                 mdb_warn("failed to walk 'mac_flow'");
 436                 return (WALK_ERR);
 437         }
 438         return (WALK_NEXT);
 439 }
 440 
 441 /*
 442  * Common walker step funciton for flow_entry_t, mac_soft_ring_set_t and
 443  * mac_ring_t.
 444  *
 445  * Steps through each flow_entry_t and calls the callback function. If the
 446  * user executed ::walk mac_flow, it just prints the address or if the user
 447  * executed ::mac_flow it displays selected fields of flow_entry_t structure
 448  * by calling "mac_flow_dcmd"
 449  */
 450 static int
 451 mac_common_walk_step(mdb_walk_state_t *wsp)
 452 {
 453         int status;
 454 
 455         if (wsp->walk_addr == NULL)
 456                 return (WALK_DONE);
 457 
 458         status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
 459             wsp->walk_cbdata);
 460 
 461         return (status);
 462 }
 463 
 464 static char *
 465 mac_srs_txmode2str(mac_tx_srs_mode_t mode)
 466 {
 467         switch (mode) {
 468         case SRS_TX_DEFAULT:
 469                 return ("DEF");
 470         case SRS_TX_SERIALIZE:
 471                 return ("SER");
 472         case SRS_TX_FANOUT:
 473                 return ("FO");
 474         case SRS_TX_BW:
 475                 return ("BW");
 476         case SRS_TX_BW_FANOUT:
 477                 return ("BWFO");
 478         case SRS_TX_AGGR:
 479                 return ("AG");
 480         case SRS_TX_BW_AGGR:
 481                 return ("BWAG");
 482         }
 483         return ("--");
 484 }
 485 
 486 static void
 487 mac_srs_help(void)
 488 {
 489         mdb_printf("If an address is specified, then mac_soft_ring_set "
 490             "structure at that address is printed. Otherwise all the "
 491             "SRS in the system are printed.\n");
 492         mdb_printf("Options:\n"
 493             "\t-r\tdisplay recieve side SRS structures\n"
 494             "\t-t\tdisplay transmit side SRS structures\n"
 495             "\t-s\tdisplay statistics for RX or TX side\n"
 496             "\t-c\tdisplay CPU binding for RX or TX side\n"
 497             "\t-v\tverbose flag for CPU binding to list cpus\n"
 498             "\t-i\tdisplay mac_ring_t and interrupt information\n"
 499             "Note: use -r or -t (to specify RX or TX side respectively) along "
 500             "with -c or -s\n");
 501         mdb_printf("\n%<u>Interpreting TX Modes%</u>\n");
 502         mdb_printf("\t DEF --> Default\n");
 503         mdb_printf("\t SER --> Serialize\n");
 504         mdb_printf("\t  FO --> Fanout\n");
 505         mdb_printf("\t  BW --> Bandwidth\n");
 506         mdb_printf("\tBWFO --> Bandwidth Fanout\n");
 507         mdb_printf("\t  AG --> Aggr\n");
 508         mdb_printf("\tBWAG --> Bandwidth Aggr\n");
 509 }
 510 
 511 /*
 512  * In verbose mode "::mac_srs -rcv or ::mac_srs -tcv", we print the CPUs
 513  * assigned to a link and CPUS assigned to the soft rings.
 514  * 'len' is used for formatting the output and represents the number of
 515  * spaces between CPU list and Fanout CPU list in the output.
 516  */
 517 static boolean_t
 518 mac_srs_print_cpu(int *i, uint32_t cnt, uint32_t *cpu_list, int *len)
 519 {
 520         int             num = 0;
 521 
 522         if (*i == 0)
 523                 mdb_printf("(");
 524         else
 525                 mdb_printf(" ");
 526         while (*i < cnt) {
 527                 /* We print 6 CPU's at a time to keep display within 80 cols */
 528                 if (((num + 1) % 7) == 0) {
 529                         if (len != NULL)
 530                                 *len = 2;
 531                         return (B_FALSE);
 532                 }
 533                 mdb_printf("%02x%c", cpu_list[*i], ((*i == cnt - 1)?')':','));
 534                 ++*i;
 535                 ++num;
 536         }
 537         if (len != NULL)
 538                 *len = (7 - num) * 3;
 539         return (B_TRUE);
 540 }
 541 
 542 static int
 543 mac_srs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 544 {
 545         uint_t                  args = MAC_SRS_NONE;
 546         mac_soft_ring_set_t     srs;
 547         mac_client_impl_t       mci;
 548 
 549         if (!(flags & DCMD_ADDRSPEC)) {
 550                 if (mdb_walk_dcmd("mac_srs", "mac_srs", argc, argv) == -1) {
 551                         mdb_warn("failed to walk 'mac_srs'");
 552                         return (DCMD_ERR);
 553                 }
 554                 return (DCMD_OK);
 555         }
 556         if (mdb_getopts(argc, argv,
 557             'r', MDB_OPT_SETBITS, MAC_SRS_RX, &args,
 558             't', MDB_OPT_SETBITS, MAC_SRS_TX, &args,
 559             'c', MDB_OPT_SETBITS, MAC_SRS_CPU, &args,
 560             'v', MDB_OPT_SETBITS, MAC_SRS_VERBOSE, &args,
 561             'i', MDB_OPT_SETBITS, MAC_SRS_INTR, &args,
 562             's', MDB_OPT_SETBITS, MAC_SRS_STAT, &args,
 563             NULL) != argc) {
 564                 return (DCMD_USAGE);
 565         }
 566 
 567         if (argc > 2)
 568                 return (DCMD_USAGE);
 569 
 570         if (mdb_vread(&srs, sizeof (srs), addr) == -1) {
 571                 mdb_warn("failed to read struct mac_soft_ring_set_s at %p",
 572                     addr);
 573                 return (DCMD_ERR);
 574         }
 575         if (mdb_vread(&mci, sizeof (mci), (uintptr_t)srs.srs_mcip) == -1) {
 576                 mdb_warn("failed to read struct mac_client_impl_t at %p "
 577                     "for SRS %p", srs.srs_mcip, addr);
 578                 return (DCMD_ERR);
 579         }
 580 
 581         switch (args) {
 582         case MAC_SRS_RX: {
 583                 if (DCMD_HDRSPEC(flags)) {
 584                         mdb_printf("%?s %-20s %-8s %-8s %8s "
 585                             "%8s %3s\n",
 586                             "", "", "", "", "MBLK",
 587                             "Q", "SR");
 588                         mdb_printf("%<u>%?s %-20s %-8s %-8s %8s "
 589                             "%8s %3s%</u>\n",
 590                             "ADDR", "LINK_NAME", "STATE", "TYPE", "CNT",
 591                             "BYTES", "CNT");
 592                 }
 593                 if (srs.srs_type & SRST_TX)
 594                         return (DCMD_OK);
 595                 mdb_printf("%?p %-20s %08x %08x "
 596                     "%8d %8d %3d\n",
 597                     addr, mci.mci_name, srs.srs_state, srs.srs_type,
 598                     srs.srs_count, srs.srs_size, srs.srs_soft_ring_count);
 599                 break;
 600         }
 601         case MAC_SRS_TX: {
 602                 if (DCMD_HDRSPEC(flags)) {
 603                         mdb_printf("%?s %-16s %-4s %-8s "
 604                             "%-8s %8s %8s %3s\n",
 605                             "", "", "TX", "",
 606                             "", "MBLK", "Q", "SR");
 607                         mdb_printf("%<u>%?s %-16s %-4s %-8s "
 608                             "%-8s %8s %8s %3s%</u>\n",
 609                             "ADDR", "LINK_NAME", "MODE", "STATE",
 610                             "TYPE", "CNT", "BYTES", "CNT");
 611                 }
 612                 if (!(srs.srs_type & SRST_TX))
 613                         return (DCMD_OK);
 614 
 615                 mdb_printf("%?p %-16s %-4s "
 616                     "%08x %08x %8d %8d %3d\n",
 617                     addr, mci.mci_name, mac_srs_txmode2str(srs.srs_tx.st_mode),
 618                     srs.srs_state, srs.srs_type, srs.srs_count, srs.srs_size,
 619                     srs.srs_tx_ring_count);
 620                 break;
 621         }
 622         case MAC_SRS_RXCPU: {
 623                 mac_cpus_t      mc = srs.srs_cpu;
 624 
 625                 if (DCMD_HDRSPEC(flags)) {
 626                         mdb_printf("%?s %-20s %-4s %-4s "
 627                             "%-6s %-4s %-7s\n",
 628                             "", "", "NUM", "POLL",
 629                             "WORKER", "INTR", "FANOUT");
 630                         mdb_printf("%<u>%?s %-20s %-4s %-4s "
 631                             "%-6s %-4s %-7s%</u>\n",
 632                             "ADDR", "LINK_NAME", "CPUS", "CPU",
 633                             "CPU", "CPU", "CPU_CNT");
 634                 }
 635                 if ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX))
 636                         return (DCMD_OK);
 637                 mdb_printf("%?p %-20s %-4d %-4d "
 638                     "%-6d %-4d %-7d\n",
 639                     addr, mci.mci_name, mc.mc_ncpus, mc.mc_rx_pollid,
 640                     mc.mc_rx_workerid, mc.mc_rx_intr_cpu, mc.mc_rx_fanout_cnt);
 641                 break;
 642 
 643         }
 644         case MAC_SRS_TXCPU: {
 645                 mac_cpus_t      mc = srs.srs_cpu;
 646                 mac_soft_ring_t *s_ringp, s_ring;
 647                 boolean_t       first = B_TRUE;
 648                 int             i;
 649 
 650                 if (DCMD_HDRSPEC(flags)) {
 651                         mdb_printf("%?s %-12s %?s %8s %8s %8s\n",
 652                             "", "", "SOFT", "WORKER", "INTR", "RETARGETED");
 653                         mdb_printf("%<u>%?s %-12s %?s %8s %8s %8s%</u>\n",
 654                             "ADDR", "LINK_NAME", "RING", "CPU", "CPU", "CPU");
 655                 }
 656                 if (!(srs.srs_type & SRST_TX))
 657                         return (DCMD_OK);
 658 
 659                 mdb_printf("%?p %-12s ", addr, mci.mci_name);
 660 
 661                 /*
 662                  * Case of no soft rings, print the info from
 663                  * mac_srs_tx_t.
 664                  */
 665                 if (srs.srs_tx_ring_count == 0) {
 666                         mdb_printf("%?p %8d %8d %8d\n",
 667                             0, mc.mc_tx_fanout_cpus[0],
 668                             mc.mc_tx_intr_cpu[0],
 669                             mc.mc_tx_retargeted_cpu[0]);
 670                         break;
 671                 }
 672 
 673                 for (s_ringp = srs.srs_soft_ring_head, i = 0; s_ringp != NULL;
 674                     s_ringp = s_ring.s_ring_next, i++) {
 675                         (void) mdb_vread(&s_ring, sizeof (s_ring),
 676                             (uintptr_t)s_ringp);
 677                         if (first) {
 678                                 mdb_printf("%?p %8d %8d %8d\n",
 679                                     s_ringp, mc.mc_tx_fanout_cpus[i],
 680                                     mc.mc_tx_intr_cpu[i],
 681                                     mc.mc_tx_retargeted_cpu[i]);
 682                                 first = B_FALSE;
 683                                 continue;
 684                         }
 685                         mdb_printf("%?s %-12s %?p %8d %8d %8d\n",
 686                             "", "", s_ringp, mc.mc_tx_fanout_cpus[i],
 687                             mc.mc_tx_intr_cpu[i], mc.mc_tx_retargeted_cpu[i]);
 688                 }
 689                 break;
 690         }
 691         case MAC_SRS_TXINTR: {
 692                 mac_cpus_t      mc = srs.srs_cpu;
 693                 mac_soft_ring_t *s_ringp, s_ring;
 694                 mac_ring_t      *m_ringp, m_ring;
 695                 boolean_t       first = B_TRUE;
 696                 int             i;
 697 
 698                 if (DCMD_HDRSPEC(flags)) {
 699                         mdb_printf("%?s %-12s %?s %8s %?s %6s %6s\n",
 700                             "", "", "SOFT", "WORKER", "MAC", "", "INTR");
 701                         mdb_printf("%<u>%?s %-12s %?s %8s %?s %6s %6s%</u>\n",
 702                             "ADDR", "LINK_NAME", "RING", "CPU", "RING",
 703                             "SHARED", "CPU");
 704                 }
 705                 if (!(srs.srs_type & SRST_TX))
 706                         return (DCMD_OK);
 707 
 708                 mdb_printf("%?p %-12s ", addr, mci.mci_name);
 709 
 710                 /*
 711                  * Case of no soft rings, print the info from
 712                  * mac_srs_tx_t.
 713                  */
 714                 if (srs.srs_tx_ring_count == 0) {
 715                         m_ringp = srs.srs_tx.st_arg2;
 716                         if (m_ringp != NULL) {
 717                                 (void) mdb_vread(&m_ring, sizeof (m_ring),
 718                                     (uintptr_t)m_ringp);
 719                                 mdb_printf("%?p %8d %?p %6d %6d\n",
 720                                     0, mc.mc_tx_fanout_cpus[0], m_ringp,
 721                                     m_ring.mr_info.mri_intr.mi_ddi_shared,
 722                                     mc.mc_tx_retargeted_cpu[0]);
 723                         } else {
 724                                 mdb_printf("%?p %8d %?p %6d %6d\n",
 725                                     0, mc.mc_tx_fanout_cpus[0], 0,
 726                                     0, mc.mc_tx_retargeted_cpu[0]);
 727                         }
 728                         break;
 729                 }
 730 
 731                 for (s_ringp = srs.srs_soft_ring_head, i = 0; s_ringp != NULL;
 732                     s_ringp = s_ring.s_ring_next, i++) {
 733                         (void) mdb_vread(&s_ring, sizeof (s_ring),
 734                             (uintptr_t)s_ringp);
 735                         m_ringp = s_ring.s_ring_tx_arg2;
 736                         (void) mdb_vread(&m_ring, sizeof (m_ring),
 737                             (uintptr_t)m_ringp);
 738                         if (first) {
 739                                 mdb_printf("%?p %8d %?p %6d %6d\n",
 740                                     s_ringp, mc.mc_tx_fanout_cpus[i],
 741                                     m_ringp,
 742                                     m_ring.mr_info.mri_intr.mi_ddi_shared,
 743                                     mc.mc_tx_retargeted_cpu[i]);
 744                                 first = B_FALSE;
 745                                 continue;
 746                         }
 747                         mdb_printf("%?s %-12s %?p %8d %?p %6d %6d\n",
 748                             "", "", s_ringp, mc.mc_tx_fanout_cpus[i],
 749                             m_ringp, m_ring.mr_info.mri_intr.mi_ddi_shared,
 750                             mc.mc_tx_retargeted_cpu[i]);
 751                 }
 752                 break;
 753         }
 754         case MAC_SRS_RXINTR: {
 755                 mac_cpus_t      mc = srs.srs_cpu;
 756                 mac_ring_t      *m_ringp, m_ring;
 757 
 758                 if (DCMD_HDRSPEC(flags)) {
 759                         mdb_printf("%?s %-12s %?s %8s %6s %6s\n",
 760                             "", "", "MAC", "", "POLL", "INTR");
 761                         mdb_printf("%<u>%?s %-12s %?s %8s %6s %6s%</u>\n",
 762                             "ADDR", "LINK_NAME", "RING", "SHARED", "CPU",
 763                             "CPU");
 764                 }
 765                 if ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX))
 766                         return (DCMD_OK);
 767 
 768                 mdb_printf("%?p %-12s ", addr, mci.mci_name);
 769 
 770                 m_ringp = srs.srs_ring;
 771                 if (m_ringp != NULL) {
 772                         (void) mdb_vread(&m_ring, sizeof (m_ring),
 773                             (uintptr_t)m_ringp);
 774                         mdb_printf("%?p %8d %6d %6d\n",
 775                             m_ringp, m_ring.mr_info.mri_intr.mi_ddi_shared,
 776                             mc.mc_rx_pollid, mc.mc_rx_intr_cpu);
 777                 } else {
 778                         mdb_printf("%?p %8d %6d %6d\n",
 779                             0, 0, mc.mc_rx_pollid, mc.mc_rx_intr_cpu);
 780                 }
 781                 break;
 782         }
 783         case MAC_SRS_RXCPUVERBOSE:
 784         case MAC_SRS_TXCPUVERBOSE: {
 785                 mac_cpus_t      mc = srs.srs_cpu;
 786                 int             cpu_index = 0, fanout_index = 0, len = 0;
 787                 boolean_t       cpu_done = B_FALSE, fanout_done = B_FALSE;
 788 
 789                 if (DCMD_HDRSPEC(flags)) {
 790                         mdb_printf("%?s %-20s %-20s %-20s\n",
 791                             "", "", "CPU_COUNT", "FANOUT_CPU_COUNT");
 792                         mdb_printf("%<u>%?s %-20s "
 793                             "%-20s %-20s%</u>\n",
 794                             "ADDR", "LINK_NAME",
 795                             "(CPU_LIST)", "(CPU_LIST)");
 796                 }
 797                 if (((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX)) ||
 798                     ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX)))
 799                         return (DCMD_OK);
 800                 mdb_printf("%?p %-20s %-20d %-20d\n", addr, mci.mci_name,
 801                     mc.mc_ncpus, mc.mc_rx_fanout_cnt);
 802                 if (mc.mc_ncpus == 0 && mc.mc_rx_fanout_cnt == 0)
 803                         break;
 804                 /* print all cpus and cpus for soft rings */
 805                 while (!cpu_done || !fanout_done) {
 806                         boolean_t old_value = cpu_done;
 807 
 808                         if (!cpu_done) {
 809                                 mdb_printf("%?s %20s ", "", "");
 810                                 cpu_done = mac_srs_print_cpu(&cpu_index,
 811                                     mc.mc_ncpus, mc.mc_cpus, &len);
 812                         }
 813                         if (!fanout_done) {
 814                                 if (old_value)
 815                                         mdb_printf("%?s %-40s", "", "");
 816                                 else
 817                                         mdb_printf("%*s", len, "");
 818                                 fanout_done = mac_srs_print_cpu(&fanout_index,
 819                                     mc.mc_rx_fanout_cnt,
 820                                     mc.mc_rx_fanout_cpus, NULL);
 821                         }
 822                         mdb_printf("\n");
 823                 }
 824                 break;
 825         }
 826         case MAC_SRS_RXSTAT: {
 827                 mac_rx_stats_t *mac_rx_stat = &srs.srs_rx.sr_stat;
 828 
 829                 if (DCMD_HDRSPEC(flags)) {
 830                         mdb_printf("%?s %-16s %8s %8s "
 831                             "%8s %8s %8s\n",
 832                             "", "", "INTR", "POLL",
 833                             "CHAIN", "CHAIN", "CHAIN");
 834                         mdb_printf("%<u>%?s %-16s %8s %8s "
 835                             "%8s %8s %8s%</u>\n",
 836                             "ADDR", "LINK_NAME", "COUNT", "COUNT",
 837                             "<10", "10-50", ">50");
 838                 }
 839                 if (srs.srs_type & SRST_TX)
 840                         return (DCMD_OK);
 841                 mdb_printf("%?p %-16s %8d "
 842                     "%8d %8d "
 843                     "%8d %8d\n",
 844                     addr, mci.mci_name, mac_rx_stat->mrs_intrcnt,
 845                     mac_rx_stat->mrs_pollcnt, mac_rx_stat->mrs_chaincntundr10,
 846                     mac_rx_stat->mrs_chaincnt10to50,
 847                     mac_rx_stat->mrs_chaincntover50);
 848                 break;
 849         }
 850         case MAC_SRS_TXSTAT: {
 851                 mac_tx_stats_t *mac_tx_stat = &srs.srs_tx.st_stat;
 852                 mac_soft_ring_t *s_ringp, s_ring;
 853                 boolean_t       first = B_TRUE;
 854 
 855                 if (DCMD_HDRSPEC(flags)) {
 856                         mdb_printf("%?s %-20s %?s %8s %8s %8s\n",
 857                             "", "", "SOFT", "DROP", "BLOCK", "UNBLOCK");
 858                         mdb_printf("%<u>%?s %-20s %?s %8s %8s %8s%</u>\n",
 859                             "ADDR", "LINK_NAME", "RING", "COUNT", "COUNT",
 860                             "COUNT");
 861                 }
 862                 if (!(srs.srs_type & SRST_TX))
 863                         return (DCMD_OK);
 864 
 865                 mdb_printf("%?p %-20s ", addr, mci.mci_name);
 866 
 867                 /*
 868                  * Case of no soft rings, print the info from
 869                  * mac_srs_tx_t.
 870                  */
 871                 if (srs.srs_tx_ring_count == 0) {
 872                         mdb_printf("%?p %8d %8d %8d\n",
 873                             0, mac_tx_stat->mts_sdrops,
 874                             mac_tx_stat->mts_blockcnt,
 875                             mac_tx_stat->mts_unblockcnt);
 876                         break;
 877                 }
 878 
 879                 for (s_ringp = srs.srs_soft_ring_head; s_ringp != NULL;
 880                     s_ringp = s_ring.s_ring_next) {
 881                         (void) mdb_vread(&s_ring, sizeof (s_ring),
 882                             (uintptr_t)s_ringp);
 883                         mac_tx_stat = &s_ring.s_st_stat;
 884                         if (first) {
 885                                 mdb_printf("%?p %8d %8d %8d\n",
 886                                     s_ringp, mac_tx_stat->mts_sdrops,
 887                                     mac_tx_stat->mts_blockcnt,
 888                                     mac_tx_stat->mts_unblockcnt);
 889                                 first = B_FALSE;
 890                                 continue;
 891                         }
 892                         mdb_printf("%?s %-20s %?p %8d %8d %8d\n",
 893                             "", "", s_ringp, mac_tx_stat->mts_sdrops,
 894                             mac_tx_stat->mts_blockcnt,
 895                             mac_tx_stat->mts_unblockcnt);
 896                 }
 897                 break;
 898         }
 899         case MAC_SRS_NONE: {
 900                 if (DCMD_HDRSPEC(flags)) {
 901                         mdb_printf("%<u>%?s %-20s %?s %?s %-3s%</u>\n",
 902                             "ADDR", "LINK_NAME", "FLENT", "HW RING", "DIR");
 903                 }
 904                 mdb_printf("%?p %-20s %?p %?p "
 905                     "%-3s ",
 906                     addr, mci.mci_name, srs.srs_flent, srs.srs_ring,
 907                     (srs.srs_type & SRST_TX ? "TX" : "RX"));
 908                 break;
 909         }
 910         default:
 911                 return (DCMD_USAGE);
 912         }
 913         return (DCMD_OK);
 914 }
 915 
 916 static int
 917 mac_srs_walk_init(mdb_walk_state_t *wsp)
 918 {
 919         if (mdb_layered_walk(LAYERED_WALKER_FOR_SRS, wsp) == -1) {
 920                 mdb_warn("failed to walk 'mac_srs'");
 921                 return (WALK_ERR);
 922         }
 923         return (WALK_NEXT);
 924 }
 925 
 926 static char *
 927 mac_ring_state2str(mac_ring_state_t state)
 928 {
 929         switch (state) {
 930         case MR_FREE:
 931                 return ("free");
 932         case MR_NEWLY_ADDED:
 933                 return ("new");
 934         case MR_INUSE:
 935                 return ("inuse");
 936         }
 937         return ("--");
 938 }
 939 
 940 static char *
 941 mac_ring_classify2str(mac_classify_type_t classify)
 942 {
 943         switch (classify) {
 944         case MAC_NO_CLASSIFIER:
 945                 return ("no");
 946         case MAC_SW_CLASSIFIER:
 947                 return ("sw");
 948         case MAC_HW_CLASSIFIER:
 949                 return ("hw");
 950         }
 951         return ("--");
 952 }
 953 
 954 static int
 955 mac_ring_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 956 {
 957         mac_ring_t              ring;
 958         mac_group_t             group;
 959         flow_entry_t            flent;
 960         mac_soft_ring_set_t     srs;
 961 
 962         if (!(flags & DCMD_ADDRSPEC)) {
 963                 if (mdb_walk_dcmd("mac_ring", "mac_ring", argc, argv) == -1) {
 964                         mdb_warn("failed to walk 'mac_ring'");
 965                         return (DCMD_ERR);
 966                 }
 967                 return (DCMD_OK);
 968         }
 969         if (mdb_vread(&ring, sizeof (ring), addr) == -1) {
 970                 mdb_warn("failed to read struct mac_ring_s at %p", addr);
 971                 return (DCMD_ERR);
 972         }
 973         bzero(&flent, sizeof (flent));
 974         if (mdb_vread(&srs, sizeof (srs), (uintptr_t)ring.mr_srs) != -1) {
 975                 (void) mdb_vread(&flent, sizeof (flent),
 976                     (uintptr_t)srs.srs_flent);
 977         }
 978         (void) mdb_vread(&group, sizeof (group), (uintptr_t)ring.mr_gh);
 979         if (DCMD_HDRSPEC(flags)) {
 980                 mdb_printf("%<u>%?s %4s %5s %4s %?s "
 981                     "%5s %?s %?s %s %</u>\n",
 982                     "ADDR", "TYPE", "STATE", "FLAG", "GROUP",
 983                     "CLASS", "MIP", "SRS", "FLOW NAME");
 984         }
 985         mdb_printf("%?p %-4s "
 986             "%5s %04x "
 987             "%?p %-5s "
 988             "%?p %?p %s\n",
 989             addr, ((ring.mr_type == 1)? "RX" : "TX"),
 990             mac_ring_state2str(ring.mr_state), ring.mr_flag,
 991             ring.mr_gh, mac_ring_classify2str(ring.mr_classify_type),
 992             group.mrg_mh, ring.mr_srs, flent.fe_flow_name);
 993         return (DCMD_OK);
 994 }
 995 
 996 static int
 997 mac_ring_walk_init(mdb_walk_state_t *wsp)
 998 {
 999         if (mdb_layered_walk(LAYERED_WALKER_FOR_RING, wsp) == -1) {
1000                 mdb_warn("failed to walk `mac_ring`");
1001                 return (WALK_ERR);
1002         }
1003         return (WALK_NEXT);
1004 }
1005 
1006 static void
1007 mac_ring_help(void)
1008 {
1009         mdb_printf("If an address is specified, then mac_ring_t "
1010             "structure at that address is printed. Otherwise all the "
1011             "hardware rings in the system are printed.\n");
1012 }
1013 
1014 /*
1015  * To walk groups we have to have our own somewhat-complicated state machine. We
1016  * basically start by walking the mac_impl_t walker as all groups are stored off
1017  * of the various mac_impl_t in the system. The tx and rx rings are kept
1018  * separately. So we'll need to walk through all the rx rings and then all of
1019  * the tx rings.
1020  */
1021 static int
1022 mac_group_walk_init(mdb_walk_state_t *wsp)
1023 {
1024         int ret;
1025 
1026         if (wsp->walk_addr != NULL) {
1027                 mdb_warn("non-global walks are not supported\n");
1028                 return (WALK_ERR);
1029         }
1030 
1031         if ((ret = mdb_layered_walk(LAYERED_WALKER_FOR_GROUP, wsp)) == -1) {
1032                 mdb_warn("couldn't walk '%s'", LAYERED_WALKER_FOR_GROUP);
1033                 return (ret);
1034         }
1035 
1036         return (WALK_NEXT);
1037 }
1038 
1039 static int
1040 mac_group_walk_step(mdb_walk_state_t *wsp)
1041 {
1042         int ret;
1043         mac_impl_t mi;
1044         mac_group_t mg;
1045         uintptr_t mgp;
1046 
1047         /*
1048          * Nothing to do if we can't find the layer above us. But the kmem
1049          * walkers are a bit unsporting, they don't actually read in the data
1050          * for us.
1051          */
1052         if (wsp->walk_addr == NULL)
1053                 return (WALK_DONE);
1054 
1055         if (mdb_vread(&mi, sizeof (mac_impl_t), wsp->walk_addr) == -1) {
1056                 mdb_warn("failed to read mac_impl_t at %p", wsp->walk_addr);
1057                 return (DCMD_ERR);
1058         }
1059 
1060         /*
1061          * First go for rx groups, then tx groups.
1062          */
1063         mgp = (uintptr_t)mi.mi_rx_groups;
1064         while (mgp != NULL) {
1065                 if (mdb_vread(&mg, sizeof (mac_group_t), mgp) == -1) {
1066                         mdb_warn("failed to read mac_group_t at %p", mgp);
1067                         return (WALK_ERR);
1068                 }
1069 
1070                 ret = wsp->walk_callback(mgp, &mg, wsp->walk_cbdata);
1071                 if (ret != WALK_NEXT)
1072                         return (ret);
1073                 mgp = (uintptr_t)mg.mrg_next;
1074         }
1075 
1076         mgp = (uintptr_t)mi.mi_tx_groups;
1077         while (mgp != NULL) {
1078                 if (mdb_vread(&mg, sizeof (mac_group_t), mgp) == -1) {
1079                         mdb_warn("failed to read mac_group_t at %p", mgp);
1080                         return (WALK_ERR);
1081                 }
1082 
1083                 ret = wsp->walk_callback(mgp, &mg, wsp->walk_cbdata);
1084                 if (ret != WALK_NEXT)
1085                         return (ret);
1086                 mgp = (uintptr_t)mg.mrg_next;
1087         }
1088 
1089         return (WALK_NEXT);
1090 }
1091 
1092 static int
1093 mac_group_count_clients(mac_group_t *mgp)
1094 {
1095         int clients = 0;
1096         uintptr_t mcp = (uintptr_t)mgp->mrg_clients;
1097 
1098         while (mcp != NULL) {
1099                 mac_grp_client_t c;
1100 
1101                 if (mdb_vread(&c, sizeof (c), mcp) == -1) {
1102                         mdb_warn("failed to read mac_grp_client_t at %p", mcp);
1103                         return (-1);
1104                 }
1105                 clients++;
1106                 mcp = (uintptr_t)c.mgc_next;
1107         }
1108 
1109         return (clients);
1110 }
1111 
1112 static const char *
1113 mac_group_type(mac_group_t *mgp)
1114 {
1115         const char *ret;
1116 
1117         switch (mgp->mrg_type) {
1118         case MAC_RING_TYPE_RX:
1119                 ret = "RECEIVE";
1120                 break;
1121         case MAC_RING_TYPE_TX:
1122                 ret = "TRANSMIT";
1123                 break;
1124         default:
1125                 ret = "UNKNOWN";
1126                 break;
1127         }
1128 
1129         return (ret);
1130 }
1131 
1132 static const char *
1133 mac_group_state(mac_group_t *mgp)
1134 {
1135         const char *ret;
1136 
1137         switch (mgp->mrg_state) {
1138         case MAC_GROUP_STATE_UNINIT:
1139                 ret = "UNINT";
1140                 break;
1141         case MAC_GROUP_STATE_REGISTERED:
1142                 ret = "REGISTERED";
1143                 break;
1144         case MAC_GROUP_STATE_RESERVED:
1145                 ret = "RESERVED";
1146                 break;
1147         case MAC_GROUP_STATE_SHARED:
1148                 ret = "SHARED";
1149                 break;
1150         default:
1151                 ret = "UNKNOWN";
1152                 break;
1153         }
1154 
1155         return (ret);
1156 }
1157 
1158 static int
1159 mac_group_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1160 {
1161         uint_t          args = MAC_SRS_NONE;
1162         mac_group_t     mg;
1163         int             clients;
1164 
1165         if (!(flags & DCMD_ADDRSPEC)) {
1166                 if (mdb_walk_dcmd("mac_group", "mac_group", argc, argv) == -1) {
1167                         mdb_warn("failed to walk 'mac_group'");
1168                         return (DCMD_ERR);
1169                 }
1170 
1171                 return (DCMD_OK);
1172         }
1173 
1174         if (mdb_getopts(argc, argv,
1175             'r', MDB_OPT_SETBITS, MAC_GROUP_RX, &args,
1176             't', MDB_OPT_SETBITS, MAC_GROUP_TX, &args,
1177             'u', MDB_OPT_SETBITS, MAC_GROUP_UNINIT, &args,
1178             NULL) != argc)
1179                 return (DCMD_USAGE);
1180 
1181         if (mdb_vread(&mg, sizeof (mac_group_t), addr) == -1) {
1182                 mdb_warn("failed to read mac_group_t at %p", addr);
1183                 return (DCMD_ERR);
1184         }
1185 
1186         if (DCMD_HDRSPEC(flags) && !(flags & DCMD_PIPE_OUT)) {
1187                 mdb_printf("%<u>%-?s %-8s %-10s %6s %8s %-?s%</u>\n",
1188                     "ADDR", "TYPE", "STATE", "NRINGS", "NCLIENTS", "RINGS");
1189         }
1190 
1191         if ((args & MAC_GROUP_RX) != 0 && mg.mrg_type != MAC_RING_TYPE_RX)
1192                 return (DCMD_OK);
1193         if ((args & MAC_GROUP_TX) != 0 && mg.mrg_type != MAC_RING_TYPE_TX)
1194                 return (DCMD_OK);
1195 
1196         /*
1197          * By default, don't show uninitialized groups. They're not very
1198          * interesting. They have no rings and no clients.
1199          */
1200         if (mg.mrg_state == MAC_GROUP_STATE_UNINIT &&
1201             (args & MAC_GROUP_UNINIT) == 0)
1202                 return (DCMD_OK);
1203 
1204         if (flags & DCMD_PIPE_OUT) {
1205                 mdb_printf("%lr\n", addr);
1206                 return (DCMD_OK);
1207         }
1208 
1209         clients = mac_group_count_clients(&mg);
1210         mdb_printf("%?p %-8s %-10s %6d %8d %?p\n", addr, mac_group_type(&mg),
1211             mac_group_state(&mg), mg.mrg_cur_count, clients, mg.mrg_rings);
1212 
1213         return (DCMD_OK);
1214 }
1215 
1216 /* Supported dee-commands */
1217 static const mdb_dcmd_t dcmds[] = {
1218         {"mac_flow", "?[-u] [-aprtsm]", "display Flow Entry structures",
1219             mac_flow_dcmd, mac_flow_help},
1220         {"mac_group", "?[-rtu]", "display MAC Ring Groups", mac_group_dcmd,
1221             NULL },
1222         {"mac_srs", "?[ -r[i|s|c[v]] | -t[i|s|c[v]] ]",
1223             "display MAC Soft Ring Set" " structures", mac_srs_dcmd,
1224             mac_srs_help},
1225         {"mac_ring", "?", "display MAC ring (hardware) structures",
1226             mac_ring_dcmd, mac_ring_help},
1227         { NULL }
1228 };
1229 
1230 /* Supported walkers */
1231 static const mdb_walker_t walkers[] = {
1232         {"mac_flow", "walk list of flow entry structures", mac_flow_walk_init,
1233             mac_common_walk_step, NULL, NULL},
1234         {"mac_group", "walk list of ring group structures", mac_group_walk_init,
1235             mac_group_walk_step, NULL, NULL},
1236         {"mac_srs", "walk list of mac soft ring set structures",
1237             mac_srs_walk_init, mac_common_walk_step, NULL, NULL},
1238         {"mac_ring", "walk list of mac ring structures", mac_ring_walk_init,
1239             mac_common_walk_step, NULL, NULL},
1240         { NULL }
1241 };
1242 
1243 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1244 
1245 const mdb_modinfo_t *
1246 _mdb_init(void)
1247 {
1248         return (&modinfo);
1249 }