xref: /illumos-gate/usr/src/cmd/mdb/common/modules/mac/mac.c (revision da14cebe459d3275048785f25bd869cb09b5307f)
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 2008 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_RX	0x01
57 #define	MAC_SRS_TX	0x02
58 
59 static char *
60 mac_flow_proto2str(uint8_t protocol)
61 {
62 	switch (protocol) {
63 	case IPPROTO_TCP:
64 		return ("tcp");
65 	case IPPROTO_UDP:
66 		return ("udp");
67 	case IPPROTO_SCTP:
68 		return ("sctp");
69 	case IPPROTO_ICMP:
70 		return ("icmp");
71 	case IPPROTO_ICMPV6:
72 		return ("icmpv6");
73 	default:
74 		return ("--");
75 	}
76 }
77 
78 static char *
79 mac_flow_priority2str(mac_priority_level_t prio)
80 {
81 	switch (prio) {
82 	case MPL_LOW:
83 		return ("low");
84 	case MPL_MEDIUM:
85 		return ("medium");
86 	case MPL_HIGH:
87 		return ("high");
88 	case MPL_RESET:
89 		return ("reset");
90 	default:
91 		return ("--");
92 	}
93 }
94 
95 /*
96  *  Convert bandwidth in bps to a string in mpbs.
97  */
98 static char *
99 mac_flow_bw2str(uint64_t bw, char *buf, ssize_t len)
100 {
101 	int kbps, mbps;
102 
103 	kbps = (bw % 1000000)/1000;
104 	mbps = bw/1000000;
105 	if ((mbps == 0) && (kbps != 0))
106 		mdb_snprintf(buf, len, "0.%03u", kbps);
107 	else
108 		mdb_snprintf(buf, len, "%5u", mbps);
109 	return (buf);
110 }
111 
112 static void
113 mac_flow_print_header(uint_t args)
114 {
115 	switch (args) {
116 	case MAC_FLOW_NONE:
117 		mdb_printf("%<u>%?s %-32s %-6s %?s %?s %-20s%</u>\n",
118 		    "ADDR", "FLOW NAME", "LINKID", "MCIP", "MIP",
119 		    "MIP NAME");
120 		break;
121 	case MAC_FLOW_ATTR:
122 		mdb_printf("%<u>%?s %-32s %-7s %6s "
123 		    "%-9s %s%</u>\n",
124 		    "ADDR", "FLOW NAME", "PROTO", "PORT",
125 		    "DSFLD:MSK", "IPADDR");
126 		break;
127 	case MAC_FLOW_PROP:
128 		mdb_printf("%<u>%?s %-32s %8s %9s%</u>\n",
129 		    "ADDR", "FLOW NAME", "MAXBW(M)", "PRIORITY");
130 		break;
131 	case MAC_FLOW_MISC:
132 		mdb_printf("%<u>%?s %-32s %10s %10s "
133 		    "%32s %s%</u>\n",
134 		    "ADDR", "FLOW NAME", "TYPE", "FLAGS",
135 		    "MATCH_FN", "ZONE");
136 		break;
137 	case MAC_FLOW_RX:
138 		mdb_printf("%<u>%?s %-24s %-30s %?s "
139 		    "%?s %7s %s%</u>\n",
140 		    "ADDR", "FLOW NAME", "CB_FUNC", "CB_ARG1",
141 		    "CB_ARG2", "SRS_CNT", "RX_SRS");
142 		break;
143 	case MAC_FLOW_TX:
144 		mdb_printf("%<u>%?s %-32s %?s %</u>\n",
145 		    "ADDR", "FLOW NAME", "TX_SRS");
146 		break;
147 	case MAC_FLOW_STATS:
148 		mdb_printf("%<u>%?s %-32s %?s %?s%</u>\n",
149 		    "ADDR", "FLOW NAME", "RBYTES", "OBYTES");
150 		break;
151 	}
152 }
153 
154 /*
155  * Display selected fields of the flow_entry_t structure
156  */
157 static int
158 mac_flow_dcmd_output(uintptr_t addr, uint_t flags, uint_t args)
159 {
160 	static const mdb_bitmask_t flow_type_bits[] = {
161 		{"P", FLOW_PRIMARY_MAC, FLOW_PRIMARY_MAC},
162 		{"V", FLOW_VNIC_MAC, FLOW_VNIC_MAC},
163 		{"M", FLOW_MCAST, FLOW_MCAST},
164 		{"O", FLOW_OTHER, FLOW_OTHER},
165 		{"U", FLOW_USER, FLOW_USER},
166 		{"V", FLOW_VNIC, FLOW_VNIC},
167 		{"NS", FLOW_NO_STATS, FLOW_NO_STATS},
168 		{ NULL, 0, 0 }
169 	};
170 #define	FLOW_MAX_TYPE	(sizeof (flow_type_bits) / sizeof (mdb_bitmask_t))
171 
172 	static const mdb_bitmask_t flow_flag_bits[] = {
173 		{"Q", FE_QUIESCE, FE_QUIESCE},
174 		{"W", FE_WAITER, FE_WAITER},
175 		{"T", FE_FLOW_TAB, FE_FLOW_TAB},
176 		{"G", FE_G_FLOW_HASH, FE_G_FLOW_HASH},
177 		{"I", FE_INCIPIENT, FE_INCIPIENT},
178 		{"C", FE_CONDEMNED, FE_CONDEMNED},
179 		{"NU", FE_UF_NO_DATAPATH, FE_UF_NO_DATAPATH},
180 		{"NC", FE_MC_NO_DATAPATH, FE_MC_NO_DATAPATH},
181 		{ NULL, 0, 0 }
182 	};
183 #define	FLOW_MAX_FLAGS	(sizeof (flow_flag_bits) / sizeof (mdb_bitmask_t))
184 	flow_entry_t		fe;
185 	mac_client_impl_t	mcip;
186 	mac_impl_t		mip;
187 
188 	if (mdb_vread(&fe, sizeof (fe), addr) == -1) {
189 		mdb_warn("failed to read struct flow_entry_s at %p", addr);
190 		return (DCMD_ERR);
191 	}
192 	if (args & MAC_FLOW_USER) {
193 		args &= ~MAC_FLOW_USER;
194 		if (fe.fe_type & FLOW_MCAST) {
195 			if (DCMD_HDRSPEC(flags))
196 				mac_flow_print_header(args);
197 			return (DCMD_OK);
198 		}
199 	}
200 	if (DCMD_HDRSPEC(flags))
201 		mac_flow_print_header(args);
202 	bzero(&mcip, sizeof (mcip));
203 	bzero(&mip, sizeof (mip));
204 	if (fe.fe_mcip != NULL && mdb_vread(&mcip, sizeof (mcip),
205 	    (uintptr_t)fe.fe_mcip) == sizeof (mcip)) {
206 		(void) mdb_vread(&mip, sizeof (mip), (uintptr_t)mcip.mci_mip);
207 	}
208 	switch (args) {
209 	case MAC_FLOW_NONE: {
210 		mdb_printf("%?p %-32s %6d %?p "
211 		    "%?p %-20s\n",
212 		    addr, fe.fe_flow_name, fe.fe_link_id, fe.fe_mcip,
213 		    mcip.mci_mip, mip.mi_name);
214 		break;
215 	}
216 	case MAC_FLOW_ATTR: {
217 		struct 	in_addr	in4;
218 		uintptr_t	desc_addr;
219 		flow_desc_t	fdesc;
220 
221 		desc_addr = addr + OFFSETOF(flow_entry_t, fe_flow_desc);
222 		if (mdb_vread(&fdesc, sizeof (fdesc), desc_addr) == -1) {
223 			mdb_warn("failed to read struct flow_description at %p",
224 			    desc_addr);
225 			return (DCMD_ERR);
226 		}
227 		mdb_printf("%?p %-32s "
228 		    "%-7s %6d"
229 		    "%4d:%-4d ",
230 		    addr, fe.fe_flow_name,
231 		    mac_flow_proto2str(fdesc.fd_protocol), fdesc.fd_local_port,
232 		    fdesc.fd_dsfield, fdesc.fd_dsfield_mask);
233 		if (fdesc.fd_ipversion == IPV4_VERSION) {
234 			IN6_V4MAPPED_TO_INADDR(&fdesc.fd_local_addr, &in4);
235 			mdb_printf("%I", in4.s_addr);
236 		} else if (fdesc.fd_ipversion == IPV6_VERSION) {
237 			mdb_printf("%N", &fdesc.fd_local_addr);
238 		} else {
239 			mdb_printf("%s", "--");
240 		}
241 		mdb_printf("\n");
242 		break;
243 	}
244 	case MAC_FLOW_PROP: {
245 		uintptr_t	prop_addr;
246 		char		bwstr[STRSIZE];
247 		mac_resource_props_t	fprop;
248 
249 		prop_addr = addr + OFFSETOF(flow_entry_t, fe_resource_props);
250 		if (mdb_vread(&fprop, sizeof (fprop), prop_addr) == -1) {
251 			mdb_warn("failed to read struct mac_resoource_props "
252 			    "at %p", prop_addr);
253 			return (DCMD_ERR);
254 		}
255 		mdb_printf("%?p %-32s "
256 		    "%8s %9s\n",
257 		    addr, fe.fe_flow_name,
258 		    mac_flow_bw2str(fprop.mrp_maxbw, bwstr, STRSIZE),
259 		    mac_flow_priority2str(fprop.mrp_priority));
260 		break;
261 	}
262 	case MAC_FLOW_MISC: {
263 		char		flow_flags[2 * FLOW_MAX_FLAGS];
264 		char		flow_type[2 * FLOW_MAX_TYPE];
265 		GElf_Sym 	sym;
266 		char		func_name[MDB_SYM_NAMLEN] = "";
267 		uintptr_t	func, match_addr;
268 
269 		match_addr = addr + OFFSETOF(flow_entry_t, fe_match);
270 		(void) mdb_vread(&func, sizeof (func), match_addr);
271 		(void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name,
272 		    MDB_SYM_NAMLEN, &sym);
273 		mdb_snprintf(flow_flags, 2 * FLOW_MAX_FLAGS, "%hb",
274 		    fe.fe_flags, flow_flag_bits);
275 		mdb_snprintf(flow_type, 2 * FLOW_MAX_TYPE, "%hb",
276 		    fe.fe_type, flow_type_bits);
277 		mdb_printf("%?p %-32s %10s %10s "
278 		    "%32s %-d\n",
279 		    addr, fe.fe_flow_name, flow_type, flow_flags,
280 		    func_name, fe.fe_zoneid);
281 		break;
282 	}
283 	case MAC_FLOW_RX: {
284 		uintptr_t	rx_srs[MAX_RINGS_PER_GROUP] = {0};
285 		char 		cb_fn[MDB_SYM_NAMLEN] = "";
286 		uintptr_t	cb_fnaddr, fnaddr, rxaddr;
287 		int		i;
288 		GElf_Sym 	sym;
289 
290 		rxaddr = addr + OFFSETOF(flow_entry_t, fe_rx_srs);
291 		(void) mdb_vread(rx_srs, MAC_RX_SRS_SIZE, rxaddr);
292 		fnaddr = addr + OFFSETOF(flow_entry_t, fe_cb_fn);
293 		(void) mdb_vread(&cb_fnaddr, sizeof (cb_fnaddr), fnaddr);
294 		(void) mdb_lookup_by_addr(cb_fnaddr, MDB_SYM_EXACT, cb_fn,
295 		    MDB_SYM_NAMLEN, &sym);
296 		mdb_printf("%?p %-24s %-30s %?p "
297 		    "%?p %7d ",
298 		    addr, fe.fe_flow_name, cb_fn, fe.fe_cb_arg1,
299 		    fe.fe_cb_arg2, fe.fe_rx_srs_cnt);
300 		for (i = 0; i < MAX_RINGS_PER_GROUP; i++) {
301 			if (rx_srs[i] == 0)
302 				continue;
303 			mdb_printf("%p ", rx_srs[i]);
304 		}
305 		mdb_printf("\n");
306 		break;
307 	}
308 	case MAC_FLOW_TX: {
309 		uintptr_t	tx_srs = 0, txaddr;
310 
311 		txaddr = addr + OFFSETOF(flow_entry_t, fe_tx_srs);
312 		(void) mdb_vread(&tx_srs, sizeof (uintptr_t), txaddr);
313 		mdb_printf("%?p %-32s %?p\n",
314 		    addr, fe.fe_flow_name, fe.fe_tx_srs);
315 		break;
316 	}
317 	case MAC_FLOW_STATS: {
318 		mdb_printf("%?p %-32s %16llu %16llu\n",
319 		    addr, fe.fe_flow_name, fe.fe_flowstats.fs_rbytes,
320 		    fe.fe_flowstats.fs_obytes);
321 		break;
322 	}
323 	}
324 	return (DCMD_OK);
325 }
326 
327 /*
328  * Parse the arguments passed to the dcmd and print all or one flow_entry_t
329  * structures
330  */
331 static int
332 mac_flow_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
333 {
334 	uint_t	args = 0;
335 
336 	if (!(flags & DCMD_ADDRSPEC)) {
337 		if (mdb_walk_dcmd("mac_flow", "mac_flow", argc, argv) == -1) {
338 			mdb_warn("failed to walk 'mac_flow'");
339 			return (DCMD_ERR);
340 		}
341 		return (DCMD_OK);
342 	}
343 	if ((mdb_getopts(argc, argv,
344 	    'a', MDB_OPT_SETBITS, MAC_FLOW_ATTR, &args,
345 	    'p', MDB_OPT_SETBITS, MAC_FLOW_PROP, &args,
346 	    'm', MDB_OPT_SETBITS, MAC_FLOW_MISC, &args,
347 	    'r', MDB_OPT_SETBITS, MAC_FLOW_RX, &args,
348 	    't', MDB_OPT_SETBITS, MAC_FLOW_TX, &args,
349 	    's', MDB_OPT_SETBITS, MAC_FLOW_STATS, &args,
350 	    'u', MDB_OPT_SETBITS, MAC_FLOW_USER, &args) != argc)) {
351 		return (DCMD_USAGE);
352 	}
353 	if (argc > 2 || (argc == 2 && !(args & MAC_FLOW_USER)))
354 		return (DCMD_USAGE);
355 	/*
356 	 * If no arguments was specified or just "-u" was specified then
357 	 * we default to printing basic information of flows.
358 	 */
359 	if (args == 0 || args == MAC_FLOW_USER)
360 		args |= MAC_FLOW_NONE;
361 
362 	return (mac_flow_dcmd_output(addr, flags, args));
363 }
364 
365 static void
366 mac_flow_help(void)
367 {
368 	mdb_printf("If an address is specified, then flow_entry structure at "
369 	    "that address is printed. Otherwise all the flows in the system "
370 	    "are printed.\n");
371 	mdb_printf("Options:\n"
372 	    "\t-u\tdisplay user defined link & vnic flows.\n"
373 	    "\t-a\tdisplay flow attributes\n"
374 	    "\t-p\tdisplay flow properties\n"
375 	    "\t-r\tdisplay rx side information\n"
376 	    "\t-t\tdisplay tx side information\n"
377 	    "\t-s\tdisplay flow statistics\n"
378 	    "\t-m\tdisplay miscellaneous flow information\n\n");
379 	mdb_printf("%<u>Interpreting Flow type and Flow flags output.%</u>\n");
380 	mdb_printf("Flow Types:\n");
381 	mdb_printf("\t  P --> FLOW_PRIMARY_MAC\n");
382 	mdb_printf("\t  V --> FLOW_VNIC_MAC\n");
383 	mdb_printf("\t  M --> FLOW_MCAST\n");
384 	mdb_printf("\t  O --> FLOW_OTHER\n");
385 	mdb_printf("\t  U --> FLOW_USER\n");
386 	mdb_printf("\t NS --> FLOW_NO_STATS\n\n");
387 	mdb_printf("Flow Flags:\n");
388 	mdb_printf("\t  Q --> FE_QUIESCE\n");
389 	mdb_printf("\t  W --> FE_WAITER\n");
390 	mdb_printf("\t  T --> FE_FLOW_TAB\n");
391 	mdb_printf("\t  G --> FE_G_FLOW_HASH\n");
392 	mdb_printf("\t  I --> FE_INCIPIENT\n");
393 	mdb_printf("\t  C --> FE_CONDEMNED\n");
394 	mdb_printf("\t NU --> FE_UF_NO_DATAPATH\n");
395 	mdb_printf("\t NC --> FE_MC_NO_DATAPATH\n");
396 }
397 
398 /*
399  * called once by the debugger when the mac_flow walk begins.
400  */
401 static int
402 mac_flow_walk_init(mdb_walk_state_t *wsp)
403 {
404 	if (mdb_layered_walk(LAYERED_WALKER_FOR_FLOW, wsp) == -1) {
405 		mdb_warn("failed to walk 'mac_flow'");
406 		return (WALK_ERR);
407 	}
408 	return (WALK_NEXT);
409 }
410 
411 /*
412  * Common walker step funciton for flow_entry_t, mac_soft_ring_set_t and
413  * mac_ring_t.
414  *
415  * Steps through each flow_entry_t and calls the callback function. If the
416  * user executed ::walk mac_flow, it just prints the address or if the user
417  * executed ::mac_flow it displays selected fields of flow_entry_t structure
418  * by calling "mac_flow_dcmd"
419  */
420 static int
421 mac_common_walk_step(mdb_walk_state_t *wsp)
422 {
423 	int status;
424 
425 	if (wsp->walk_addr == NULL)
426 		return (WALK_DONE);
427 
428 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
429 	    wsp->walk_cbdata);
430 
431 	return (status);
432 }
433 
434 static char *
435 mac_srs_txmode2str(mac_tx_srs_mode_t mode)
436 {
437 	switch (mode) {
438 	case SRS_TX_DEFAULT:
439 		return ("default");
440 	case SRS_TX_SERIALIZE:
441 		return ("serialize");
442 	case SRS_TX_FANOUT:
443 		return ("fanout");
444 	case SRS_TX_BW:
445 		return ("bw");
446 	case SRS_TX_BW_FANOUT:
447 		return ("bw fanout");
448 	}
449 	return ("--");
450 }
451 
452 static void
453 mac_srs_help(void)
454 {
455 	mdb_printf("If an address is specified, then mac_soft_ring_set "
456 	    "structure at that address is printed. Otherwise all the "
457 	    "SRS in the system are printed.\n");
458 	mdb_printf("Options:\n"
459 	    "\t-r\tdisplay recieve side SRS structures\n"
460 	    "\t-t\tdisplay transmit side SRS structures\n");
461 }
462 
463 static int
464 mac_srs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
465 {
466 	uint_t			args = 0;
467 	mac_soft_ring_set_t	srs;
468 
469 	if (!(flags & DCMD_ADDRSPEC)) {
470 		if (mdb_walk_dcmd("mac_srs", "mac_srs", argc, argv) == -1) {
471 			mdb_warn("failed to walk 'mac_srs'");
472 			return (DCMD_ERR);
473 		}
474 		return (DCMD_OK);
475 	}
476 	if ((mdb_getopts(argc, argv,
477 	    'r', MDB_OPT_SETBITS, MAC_SRS_RX, &args,
478 	    't', MDB_OPT_SETBITS, MAC_SRS_TX, &args) != argc)) {
479 		return (DCMD_USAGE);
480 	}
481 	if (argc > 1)
482 		return (DCMD_USAGE);
483 
484 	if (mdb_vread(&srs, sizeof (srs), addr) == -1) {
485 		mdb_warn("failed to read struct mac_soft_ring_set_s at %p",
486 		    addr);
487 		return (DCMD_ERR);
488 	}
489 
490 	switch (args) {
491 	case MAC_SRS_RX: {
492 		GElf_Sym 	sym;
493 		char		func_name[MDB_SYM_NAMLEN] = "";
494 		char		l_proc_name[MDB_SYM_NAMLEN] = "";
495 		uintptr_t	func, lproc, funcaddr, lprocaddr, rxaddr;
496 
497 		if (DCMD_HDRSPEC(flags)) {
498 			mdb_printf("%<u>%?s %8s %-8s "
499 			    "%8s %-20s %-s%</u>\n",
500 			    "ADDR", "MBLK_CNT", "Q_BYTES",
501 			    "POLL_CNT", "SR_FUNC", "SR_LOWER_FUNC");
502 		}
503 		if (srs.srs_type & SRST_TX)
504 			return (DCMD_OK);
505 		rxaddr = addr + OFFSETOF(mac_soft_ring_set_t, srs_rx);
506 		funcaddr = rxaddr + OFFSETOF(mac_srs_rx_t, sr_func);
507 		lprocaddr = rxaddr + OFFSETOF(mac_srs_rx_t, sr_lower_proc);
508 		(void) mdb_vread(&func, sizeof (func), funcaddr);
509 		(void) mdb_vread(&lproc, sizeof (lproc), lprocaddr);
510 		(void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name,
511 		    MDB_SYM_NAMLEN, &sym);
512 		(void) mdb_lookup_by_addr(lproc, MDB_SYM_EXACT, l_proc_name,
513 		    MDB_SYM_NAMLEN, &sym);
514 		mdb_printf("%?p %-8d %-8d "
515 		    "%-8d %-20s %-s\n",
516 		    addr, srs.srs_count, srs.srs_size,
517 		    srs.srs_rx.sr_poll_count, func_name, l_proc_name);
518 		break;
519 	}
520 	case MAC_SRS_TX: {
521 		if (DCMD_HDRSPEC(flags)) {
522 			mdb_printf("%<u>%?s %-10s %-5s %-7s %-7s "
523 			    "%-7s %-7s %-7s%</u>\n",
524 			    "ADDR", "TX_MODE", "WOKEN", "DROP", "BLOCK",
525 			    "UNBLOCK", "MBLK", "SR_CNT");
526 		}
527 		if (!(srs.srs_type & SRST_TX))
528 			return (DCMD_OK);
529 
530 		mdb_printf("%?p %-10s "
531 		    "%-5d %-7d "
532 		    "%-7d %-7d "
533 		    "%-7d %-7d\n",
534 		    addr, mac_srs_txmode2str(srs.srs_tx.st_mode),
535 		    srs.srs_tx.st_woken_up, srs.srs_tx.st_drop_count,
536 		    srs.srs_tx.st_blocked_cnt, srs.srs_tx.st_unblocked_cnt,
537 		    srs.srs_count, srs.srs_oth_ring_count);
538 		break;
539 	}
540 	default: {
541 		if (DCMD_HDRSPEC(flags)) {
542 			mdb_printf("%<u>%?s %?s %?s %?s %-3s "
543 			    "%-8s %-8s %-7s %</u>\n",
544 			    "ADDR", "MCIP", "FLENT", "RING", "DIR",
545 			    "TYPE", "STATE", "SR_CNT");
546 		}
547 		mdb_printf("%?p %?p %?p %?p "
548 		    "%-3s "
549 		    "%08x %08x %-7d \n",
550 		    addr, srs.srs_mcip, srs.srs_flent, srs.srs_ring,
551 		    (srs.srs_type & SRST_TX ? "TX" : "RX"),
552 		    srs.srs_type, srs.srs_state, srs.srs_soft_ring_count);
553 		break;
554 	}
555 	}
556 	return (DCMD_OK);
557 }
558 
559 static int
560 mac_srs_walk_init(mdb_walk_state_t *wsp)
561 {
562 	if (mdb_layered_walk(LAYERED_WALKER_FOR_SRS, wsp) == -1) {
563 		mdb_warn("failed to walk 'mac_srs'");
564 		return (WALK_ERR);
565 	}
566 	return (WALK_NEXT);
567 }
568 
569 static char *
570 mac_ring_state2str(mac_ring_state_t state)
571 {
572 	switch (state) {
573 	case MR_FREE:
574 		return ("free");
575 	case MR_NEWLY_ADDED:
576 		return ("new");
577 	case MR_INUSE:
578 		return ("inuse");
579 	}
580 	return ("--");
581 }
582 
583 static char *
584 mac_ring_classify2str(mac_classify_type_t classify)
585 {
586 	switch (classify) {
587 	case MAC_NO_CLASSIFIER:
588 		return ("no");
589 	case MAC_SW_CLASSIFIER:
590 		return ("sw");
591 	case MAC_HW_CLASSIFIER:
592 		return ("hw");
593 	}
594 	return ("--");
595 }
596 
597 static int
598 mac_ring_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
599 {
600 	mac_ring_t		ring;
601 	mac_group_t		group;
602 	flow_entry_t		flent;
603 	mac_soft_ring_set_t	srs;
604 
605 	if (!(flags & DCMD_ADDRSPEC)) {
606 		if (mdb_walk_dcmd("mac_ring", "mac_ring", argc, argv) == -1) {
607 			mdb_warn("failed to walk 'mac_ring'");
608 			return (DCMD_ERR);
609 		}
610 		return (DCMD_OK);
611 	}
612 	if (mdb_vread(&ring, sizeof (ring), addr) == -1) {
613 		mdb_warn("failed to read struct mac_ring_s at %p", addr);
614 		return (DCMD_ERR);
615 	}
616 	bzero(&flent, sizeof (flent));
617 	if (mdb_vread(&srs, sizeof (srs), (uintptr_t)ring.mr_srs) != -1) {
618 		(void) mdb_vread(&flent, sizeof (flent),
619 		    (uintptr_t)srs.srs_flent);
620 	}
621 	(void) mdb_vread(&group, sizeof (group), (uintptr_t)ring.mr_gh);
622 	if (DCMD_HDRSPEC(flags)) {
623 		mdb_printf("%<u>%?s %4s %5s %4s %?s "
624 		    "%5s %?s %?s %s %</u>\n",
625 		    "ADDR", "TYPE", "STATE", "FLAG", "GROUP",
626 		    "CLASS", "MIP", "SRS", "FLOW NAME");
627 	}
628 	mdb_printf("%?p %-4s "
629 	    "%5s %04x "
630 	    "%?p %-5s "
631 	    "%?p %?p %s\n",
632 	    addr, ((ring.mr_type == 1)? "RX" : "TX"),
633 	    mac_ring_state2str(ring.mr_state), ring.mr_flag,
634 	    ring.mr_gh, mac_ring_classify2str(ring.mr_classify_type),
635 	    group.mrg_mh, ring.mr_srs, flent.fe_flow_name);
636 	return (DCMD_OK);
637 }
638 
639 static int
640 mac_ring_walk_init(mdb_walk_state_t *wsp)
641 {
642 	if (mdb_layered_walk(LAYERED_WALKER_FOR_RING, wsp) == -1) {
643 		mdb_warn("failed to walk `mac_ring`");
644 		return (WALK_ERR);
645 	}
646 	return (WALK_NEXT);
647 }
648 
649 static void
650 mac_ring_help(void)
651 {
652 	mdb_printf("If an address is specified, then mac_ring_t "
653 	    "structure at that address is printed. Otherwise all the "
654 	    "hardware rings in the system are printed.\n");
655 }
656 
657 /* Supported dee-commands */
658 static const mdb_dcmd_t dcmds[] = {
659 	{"mac_flow", "?[-u] [-aprtsm]", "display Flow Entry structures",
660 	    mac_flow_dcmd, mac_flow_help},
661 	{"mac_srs", "?[-rt]", "display MAC Soft Ring Set structures",
662 	    mac_srs_dcmd, mac_srs_help},
663 	{"mac_ring", "?", "display MAC ring (hardware) structures",
664 	    mac_ring_dcmd, mac_ring_help},
665 	{ NULL }
666 };
667 
668 /* Supported walkers */
669 static const mdb_walker_t walkers[] = {
670 	{"mac_flow", "walk list of flow entry structures", mac_flow_walk_init,
671 	    mac_common_walk_step, NULL, NULL},
672 	{"mac_srs", "walk list of mac soft ring set structures",
673 	    mac_srs_walk_init, mac_common_walk_step, NULL, NULL},
674 	{"mac_ring", "walk list of mac ring structures", mac_ring_walk_init,
675 	    mac_common_walk_step, NULL, NULL},
676 	{ NULL }
677 };
678 
679 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
680 
681 const mdb_modinfo_t *
682 _mdb_init(void)
683 {
684 	return (&modinfo);
685 }
686