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
81static char *
82mac_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
100static char *
101mac_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 */
120static char *
121mac_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
134static void
135mac_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 */
179static int
180mac_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 */
381static int
382mac_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
416static void
417mac_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 */
452static int
453mac_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 */
471static int
472mac_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
485static char *
486mac_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
507static void
508mac_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 */
538static boolean_t
539mac_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
563static int
564mac_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
937static int
938mac_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
947static char *
948mac_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
961static char *
962mac_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
977static int
978mac_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
1019static int
1020mac_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
1029static void
1030mac_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 */
1044static int
1045mac_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
1062static int
1063mac_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
1115static int
1116mac_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
1135static const char *
1136mac_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
1155static const char *
1156mac_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
1181static int
1182mac_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 */
1240static 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 */
1254static 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
1266static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1267
1268const mdb_modinfo_t *
1269_mdb_init(void)
1270{
1271	return (&modinfo);
1272}
1273