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