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