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 *
mac_flow_proto2str(uint8_t protocol)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 *
mac_flow_priority2str(mac_priority_level_t prio)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 *
mac_flow_bw2str(uint64_t bw,char * buf,ssize_t len)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
mac_flow_print_header(uint_t args)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
mac_flow_dcmd_output(uintptr_t addr,uint_t flags,uint_t args)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
mac_flow_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mac_flow_help(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
mac_flow_walk_init(mdb_walk_state_t * wsp)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
mac_common_walk_step(mdb_walk_state_t * wsp)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 *
mac_srs_txmode2str(mac_tx_srs_mode_t mode)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
mac_srs_help(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
mac_srs_print_cpu(int * i,uint32_t cnt,uint32_t * cpu_list,int * len)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
mac_srs_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mac_srs_walk_init(mdb_walk_state_t * wsp)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 *
mac_ring_state2str(mac_ring_state_t state)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 *
mac_ring_classify2str(mac_classify_type_t classify)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
mac_ring_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mac_ring_walk_init(mdb_walk_state_t * wsp)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
mac_ring_help(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
mac_group_walk_init(mdb_walk_state_t * wsp)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
mac_group_walk_step(mdb_walk_state_t * wsp)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
mac_group_count_clients(mac_group_t * mgp)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 *
mac_group_type(mac_group_t * mgp)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 *
mac_group_state(mac_group_t * mgp)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
mac_group_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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 *
_mdb_init(void)1246 _mdb_init(void)
1247 {
1248 return (&modinfo);
1249 }
1250