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