xref: /illumos-gate/usr/src/cmd/mdb/common/modules/mac/mac.c (revision fcff38eb)
1da14cebeSEric Cheng /*
2da14cebeSEric Cheng  * CDDL HEADER START
3da14cebeSEric Cheng  *
4da14cebeSEric Cheng  * The contents of this file are subject to the terms of the
5da14cebeSEric Cheng  * Common Development and Distribution License (the "License").
6da14cebeSEric Cheng  * You may not use this file except in compliance with the License.
7da14cebeSEric Cheng  *
8da14cebeSEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da14cebeSEric Cheng  * or http://www.opensolaris.org/os/licensing.
10da14cebeSEric Cheng  * See the License for the specific language governing permissions
11da14cebeSEric Cheng  * and limitations under the License.
12da14cebeSEric Cheng  *
13da14cebeSEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
14da14cebeSEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da14cebeSEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
16da14cebeSEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
17da14cebeSEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
18da14cebeSEric Cheng  *
19da14cebeSEric Cheng  * CDDL HEADER END
20da14cebeSEric Cheng  */
21da14cebeSEric Cheng /*
222ae51e79SGirish Moodalbail  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da14cebeSEric Cheng  * Use is subject to license terms.
24da14cebeSEric Cheng  */
25da14cebeSEric Cheng 
26da14cebeSEric Cheng #include <sys/mdb_modapi.h>
27da14cebeSEric Cheng #include <sys/types.h>
28da14cebeSEric Cheng #include <inet/ip.h>
29da14cebeSEric Cheng #include <inet/ip6.h>
30da14cebeSEric Cheng 
31da14cebeSEric Cheng #include <sys/mac.h>
32da14cebeSEric Cheng #include <sys/mac_provider.h>
33da14cebeSEric Cheng #include <sys/mac_client.h>
34da14cebeSEric Cheng #include <sys/mac_client_impl.h>
35da14cebeSEric Cheng #include <sys/mac_flow_impl.h>
36da14cebeSEric Cheng #include <sys/mac_soft_ring.h>
37da14cebeSEric Cheng 
38da14cebeSEric Cheng #define	STRSIZE	64
39da14cebeSEric Cheng #define	MAC_RX_SRS_SIZE	 (MAX_RINGS_PER_GROUP * sizeof (uintptr_t))
40da14cebeSEric Cheng 
41da14cebeSEric Cheng #define	LAYERED_WALKER_FOR_FLOW	"flow_entry_cache"
42da14cebeSEric Cheng #define	LAYERED_WALKER_FOR_SRS	"mac_srs_cache"
43da14cebeSEric Cheng #define	LAYERED_WALKER_FOR_RING	"mac_ring_cache"
44da14cebeSEric Cheng 
45da14cebeSEric Cheng /* arguments passed to mac_flow dee-command */
46da14cebeSEric Cheng #define	MAC_FLOW_NONE	0x01
47da14cebeSEric Cheng #define	MAC_FLOW_ATTR	0x02
48da14cebeSEric Cheng #define	MAC_FLOW_PROP	0x04
49da14cebeSEric Cheng #define	MAC_FLOW_RX	0x08
50da14cebeSEric Cheng #define	MAC_FLOW_TX	0x10
51da14cebeSEric Cheng #define	MAC_FLOW_USER	0x20
52da14cebeSEric Cheng #define	MAC_FLOW_STATS	0x40
53da14cebeSEric Cheng #define	MAC_FLOW_MISC	0x80
54da14cebeSEric Cheng 
55da14cebeSEric Cheng /* arguments passed to mac_srs dee-command */
562ae51e79SGirish Moodalbail #define	MAC_SRS_NONE		0x00
572ae51e79SGirish Moodalbail #define	MAC_SRS_RX		0x01
582ae51e79SGirish Moodalbail #define	MAC_SRS_TX		0x02
592ae51e79SGirish Moodalbail #define	MAC_SRS_STAT		0x04
602ae51e79SGirish Moodalbail #define	MAC_SRS_CPU		0x08
612ae51e79SGirish Moodalbail #define	MAC_SRS_VERBOSE		0x10
622ae51e79SGirish Moodalbail #define	MAC_SRS_RXSTAT		(MAC_SRS_RX|MAC_SRS_STAT)
632ae51e79SGirish Moodalbail #define	MAC_SRS_TXSTAT		(MAC_SRS_TX|MAC_SRS_STAT)
642ae51e79SGirish Moodalbail #define	MAC_SRS_RXCPU		(MAC_SRS_RX|MAC_SRS_CPU)
652ae51e79SGirish Moodalbail #define	MAC_SRS_TXCPU		(MAC_SRS_TX|MAC_SRS_CPU)
662ae51e79SGirish Moodalbail #define	MAC_SRS_RXCPUVERBOSE	(MAC_SRS_RXCPU|MAC_SRS_VERBOSE)
672ae51e79SGirish Moodalbail #define	MAC_SRS_TXCPUVERBOSE	(MAC_SRS_TXCPU|MAC_SRS_VERBOSE)
68da14cebeSEric Cheng 
69da14cebeSEric Cheng static char *
70da14cebeSEric Cheng mac_flow_proto2str(uint8_t protocol)
71da14cebeSEric Cheng {
72da14cebeSEric Cheng 	switch (protocol) {
73da14cebeSEric Cheng 	case IPPROTO_TCP:
74da14cebeSEric Cheng 		return ("tcp");
75da14cebeSEric Cheng 	case IPPROTO_UDP:
76da14cebeSEric Cheng 		return ("udp");
77da14cebeSEric Cheng 	case IPPROTO_SCTP:
78da14cebeSEric Cheng 		return ("sctp");
79da14cebeSEric Cheng 	case IPPROTO_ICMP:
80da14cebeSEric Cheng 		return ("icmp");
81da14cebeSEric Cheng 	case IPPROTO_ICMPV6:
82da14cebeSEric Cheng 		return ("icmpv6");
83da14cebeSEric Cheng 	default:
84da14cebeSEric Cheng 		return ("--");
85da14cebeSEric Cheng 	}
86da14cebeSEric Cheng }
87da14cebeSEric Cheng 
88da14cebeSEric Cheng static char *
89da14cebeSEric Cheng mac_flow_priority2str(mac_priority_level_t prio)
90da14cebeSEric Cheng {
91da14cebeSEric Cheng 	switch (prio) {
92da14cebeSEric Cheng 	case MPL_LOW:
93da14cebeSEric Cheng 		return ("low");
94da14cebeSEric Cheng 	case MPL_MEDIUM:
95da14cebeSEric Cheng 		return ("medium");
96da14cebeSEric Cheng 	case MPL_HIGH:
97da14cebeSEric Cheng 		return ("high");
98da14cebeSEric Cheng 	case MPL_RESET:
99da14cebeSEric Cheng 		return ("reset");
100da14cebeSEric Cheng 	default:
101da14cebeSEric Cheng 		return ("--");
102da14cebeSEric Cheng 	}
103da14cebeSEric Cheng }
104da14cebeSEric Cheng 
105da14cebeSEric Cheng /*
106da14cebeSEric Cheng  *  Convert bandwidth in bps to a string in mpbs.
107da14cebeSEric Cheng  */
108da14cebeSEric Cheng static char *
109da14cebeSEric Cheng mac_flow_bw2str(uint64_t bw, char *buf, ssize_t len)
110da14cebeSEric Cheng {
111da14cebeSEric Cheng 	int kbps, mbps;
112da14cebeSEric Cheng 
113da14cebeSEric Cheng 	kbps = (bw % 1000000)/1000;
114da14cebeSEric Cheng 	mbps = bw/1000000;
115da14cebeSEric Cheng 	if ((mbps == 0) && (kbps != 0))
116da14cebeSEric Cheng 		mdb_snprintf(buf, len, "0.%03u", kbps);
117da14cebeSEric Cheng 	else
118da14cebeSEric Cheng 		mdb_snprintf(buf, len, "%5u", mbps);
119da14cebeSEric Cheng 	return (buf);
120da14cebeSEric Cheng }
121da14cebeSEric Cheng 
122da14cebeSEric Cheng static void
123da14cebeSEric Cheng mac_flow_print_header(uint_t args)
124da14cebeSEric Cheng {
125da14cebeSEric Cheng 	switch (args) {
126da14cebeSEric Cheng 	case MAC_FLOW_NONE:
127*fcff38ebSGirish Moodalbail 		mdb_printf("%?s %-20s %4s %?s %?s %-16s\n",
128*fcff38ebSGirish Moodalbail 		    "", "", "LINK", "", "", "MIP");
129*fcff38ebSGirish Moodalbail 		mdb_printf("%<u>%?s %-20s %4s %?s %?s %-16s%</u>\n",
130*fcff38ebSGirish Moodalbail 		    "ADDR", "FLOW NAME", "ID", "MCIP", "MIP", "NAME");
131da14cebeSEric Cheng 		break;
132da14cebeSEric Cheng 	case MAC_FLOW_ATTR:
133da14cebeSEric Cheng 		mdb_printf("%<u>%?s %-32s %-7s %6s "
134da14cebeSEric Cheng 		    "%-9s %s%</u>\n",
135da14cebeSEric Cheng 		    "ADDR", "FLOW NAME", "PROTO", "PORT",
136da14cebeSEric Cheng 		    "DSFLD:MSK", "IPADDR");
137da14cebeSEric Cheng 		break;
138da14cebeSEric Cheng 	case MAC_FLOW_PROP:
139da14cebeSEric Cheng 		mdb_printf("%<u>%?s %-32s %8s %9s%</u>\n",
140da14cebeSEric Cheng 		    "ADDR", "FLOW NAME", "MAXBW(M)", "PRIORITY");
141da14cebeSEric Cheng 		break;
142da14cebeSEric Cheng 	case MAC_FLOW_MISC:
143*fcff38ebSGirish Moodalbail 		mdb_printf("%<u>%?s %-24s %10s %10s "
144*fcff38ebSGirish Moodalbail 		    "%20s %4s%</u>\n",
145da14cebeSEric Cheng 		    "ADDR", "FLOW NAME", "TYPE", "FLAGS",
146da14cebeSEric Cheng 		    "MATCH_FN", "ZONE");
147da14cebeSEric Cheng 		break;
148da14cebeSEric Cheng 	case MAC_FLOW_RX:
149*fcff38ebSGirish Moodalbail 		mdb_printf("%?s %-24s %3s %s\n", "", "", "SRS", "RX");
150*fcff38ebSGirish Moodalbail 		mdb_printf("%<u>%?s %-24s %3s %s%</u>\n",
151*fcff38ebSGirish Moodalbail 		    "ADDR", "FLOW NAME", "CNT", "SRS");
152da14cebeSEric Cheng 		break;
153da14cebeSEric Cheng 	case MAC_FLOW_TX:
154da14cebeSEric Cheng 		mdb_printf("%<u>%?s %-32s %?s %</u>\n",
155da14cebeSEric Cheng 		    "ADDR", "FLOW NAME", "TX_SRS");
156da14cebeSEric Cheng 		break;
157da14cebeSEric Cheng 	case MAC_FLOW_STATS:
158*fcff38ebSGirish Moodalbail 		mdb_printf("%<u>%?s %-32s %16s %16s%</u>\n",
159da14cebeSEric Cheng 		    "ADDR", "FLOW NAME", "RBYTES", "OBYTES");
160da14cebeSEric Cheng 		break;
161da14cebeSEric Cheng 	}
162da14cebeSEric Cheng }
163da14cebeSEric Cheng 
164da14cebeSEric Cheng /*
165da14cebeSEric Cheng  * Display selected fields of the flow_entry_t structure
166da14cebeSEric Cheng  */
167da14cebeSEric Cheng static int
168da14cebeSEric Cheng mac_flow_dcmd_output(uintptr_t addr, uint_t flags, uint_t args)
169da14cebeSEric Cheng {
170da14cebeSEric Cheng 	static const mdb_bitmask_t flow_type_bits[] = {
171da14cebeSEric Cheng 		{"P", FLOW_PRIMARY_MAC, FLOW_PRIMARY_MAC},
172da14cebeSEric Cheng 		{"V", FLOW_VNIC_MAC, FLOW_VNIC_MAC},
173da14cebeSEric Cheng 		{"M", FLOW_MCAST, FLOW_MCAST},
174da14cebeSEric Cheng 		{"O", FLOW_OTHER, FLOW_OTHER},
175da14cebeSEric Cheng 		{"U", FLOW_USER, FLOW_USER},
176da14cebeSEric Cheng 		{"V", FLOW_VNIC, FLOW_VNIC},
177da14cebeSEric Cheng 		{"NS", FLOW_NO_STATS, FLOW_NO_STATS},
178da14cebeSEric Cheng 		{ NULL, 0, 0 }
179da14cebeSEric Cheng 	};
180da14cebeSEric Cheng #define	FLOW_MAX_TYPE	(sizeof (flow_type_bits) / sizeof (mdb_bitmask_t))
181da14cebeSEric Cheng 
182da14cebeSEric Cheng 	static const mdb_bitmask_t flow_flag_bits[] = {
183da14cebeSEric Cheng 		{"Q", FE_QUIESCE, FE_QUIESCE},
184da14cebeSEric Cheng 		{"W", FE_WAITER, FE_WAITER},
185da14cebeSEric Cheng 		{"T", FE_FLOW_TAB, FE_FLOW_TAB},
186da14cebeSEric Cheng 		{"G", FE_G_FLOW_HASH, FE_G_FLOW_HASH},
187da14cebeSEric Cheng 		{"I", FE_INCIPIENT, FE_INCIPIENT},
188da14cebeSEric Cheng 		{"C", FE_CONDEMNED, FE_CONDEMNED},
189da14cebeSEric Cheng 		{"NU", FE_UF_NO_DATAPATH, FE_UF_NO_DATAPATH},
190da14cebeSEric Cheng 		{"NC", FE_MC_NO_DATAPATH, FE_MC_NO_DATAPATH},
191da14cebeSEric Cheng 		{ NULL, 0, 0 }
192da14cebeSEric Cheng 	};
193da14cebeSEric Cheng #define	FLOW_MAX_FLAGS	(sizeof (flow_flag_bits) / sizeof (mdb_bitmask_t))
194da14cebeSEric Cheng 	flow_entry_t		fe;
195da14cebeSEric Cheng 	mac_client_impl_t	mcip;
196da14cebeSEric Cheng 	mac_impl_t		mip;
197da14cebeSEric Cheng 
198da14cebeSEric Cheng 	if (mdb_vread(&fe, sizeof (fe), addr) == -1) {
199da14cebeSEric Cheng 		mdb_warn("failed to read struct flow_entry_s at %p", addr);
200da14cebeSEric Cheng 		return (DCMD_ERR);
201da14cebeSEric Cheng 	}
202da14cebeSEric Cheng 	if (args & MAC_FLOW_USER) {
203da14cebeSEric Cheng 		args &= ~MAC_FLOW_USER;
204da14cebeSEric Cheng 		if (fe.fe_type & FLOW_MCAST) {
205da14cebeSEric Cheng 			if (DCMD_HDRSPEC(flags))
206da14cebeSEric Cheng 				mac_flow_print_header(args);
207da14cebeSEric Cheng 			return (DCMD_OK);
208da14cebeSEric Cheng 		}
209da14cebeSEric Cheng 	}
210da14cebeSEric Cheng 	if (DCMD_HDRSPEC(flags))
211da14cebeSEric Cheng 		mac_flow_print_header(args);
212da14cebeSEric Cheng 	bzero(&mcip, sizeof (mcip));
213da14cebeSEric Cheng 	bzero(&mip, sizeof (mip));
214da14cebeSEric Cheng 	if (fe.fe_mcip != NULL && mdb_vread(&mcip, sizeof (mcip),
215da14cebeSEric Cheng 	    (uintptr_t)fe.fe_mcip) == sizeof (mcip)) {
216da14cebeSEric Cheng 		(void) mdb_vread(&mip, sizeof (mip), (uintptr_t)mcip.mci_mip);
217da14cebeSEric Cheng 	}
218da14cebeSEric Cheng 	switch (args) {
219da14cebeSEric Cheng 	case MAC_FLOW_NONE: {
220*fcff38ebSGirish Moodalbail 		mdb_printf("%?p %-20s %4d %?p "
221*fcff38ebSGirish Moodalbail 		    "%?p %-16s\n",
222da14cebeSEric Cheng 		    addr, fe.fe_flow_name, fe.fe_link_id, fe.fe_mcip,
223da14cebeSEric Cheng 		    mcip.mci_mip, mip.mi_name);
224da14cebeSEric Cheng 		break;
225da14cebeSEric Cheng 	}
226da14cebeSEric Cheng 	case MAC_FLOW_ATTR: {
227da14cebeSEric Cheng 		struct 	in_addr	in4;
228da14cebeSEric Cheng 		uintptr_t	desc_addr;
229da14cebeSEric Cheng 		flow_desc_t	fdesc;
230da14cebeSEric Cheng 
231da14cebeSEric Cheng 		desc_addr = addr + OFFSETOF(flow_entry_t, fe_flow_desc);
232da14cebeSEric Cheng 		if (mdb_vread(&fdesc, sizeof (fdesc), desc_addr) == -1) {
233da14cebeSEric Cheng 			mdb_warn("failed to read struct flow_description at %p",
234da14cebeSEric Cheng 			    desc_addr);
235da14cebeSEric Cheng 			return (DCMD_ERR);
236da14cebeSEric Cheng 		}
237da14cebeSEric Cheng 		mdb_printf("%?p %-32s "
238*fcff38ebSGirish Moodalbail 		    "%-7s %6d "
239da14cebeSEric Cheng 		    "%4d:%-4d ",
240da14cebeSEric Cheng 		    addr, fe.fe_flow_name,
241da14cebeSEric Cheng 		    mac_flow_proto2str(fdesc.fd_protocol), fdesc.fd_local_port,
242da14cebeSEric Cheng 		    fdesc.fd_dsfield, fdesc.fd_dsfield_mask);
243da14cebeSEric Cheng 		if (fdesc.fd_ipversion == IPV4_VERSION) {
244da14cebeSEric Cheng 			IN6_V4MAPPED_TO_INADDR(&fdesc.fd_local_addr, &in4);
245da14cebeSEric Cheng 			mdb_printf("%I", in4.s_addr);
246da14cebeSEric Cheng 		} else if (fdesc.fd_ipversion == IPV6_VERSION) {
247da14cebeSEric Cheng 			mdb_printf("%N", &fdesc.fd_local_addr);
248da14cebeSEric Cheng 		} else {
249da14cebeSEric Cheng 			mdb_printf("%s", "--");
250da14cebeSEric Cheng 		}
251da14cebeSEric Cheng 		mdb_printf("\n");
252da14cebeSEric Cheng 		break;
253da14cebeSEric Cheng 	}
254da14cebeSEric Cheng 	case MAC_FLOW_PROP: {
255da14cebeSEric Cheng 		uintptr_t	prop_addr;
256da14cebeSEric Cheng 		char		bwstr[STRSIZE];
257da14cebeSEric Cheng 		mac_resource_props_t	fprop;
258da14cebeSEric Cheng 
259da14cebeSEric Cheng 		prop_addr = addr + OFFSETOF(flow_entry_t, fe_resource_props);
260da14cebeSEric Cheng 		if (mdb_vread(&fprop, sizeof (fprop), prop_addr) == -1) {
261da14cebeSEric Cheng 			mdb_warn("failed to read struct mac_resoource_props "
262da14cebeSEric Cheng 			    "at %p", prop_addr);
263da14cebeSEric Cheng 			return (DCMD_ERR);
264da14cebeSEric Cheng 		}
265da14cebeSEric Cheng 		mdb_printf("%?p %-32s "
266da14cebeSEric Cheng 		    "%8s %9s\n",
267da14cebeSEric Cheng 		    addr, fe.fe_flow_name,
268da14cebeSEric Cheng 		    mac_flow_bw2str(fprop.mrp_maxbw, bwstr, STRSIZE),
269da14cebeSEric Cheng 		    mac_flow_priority2str(fprop.mrp_priority));
270da14cebeSEric Cheng 		break;
271da14cebeSEric Cheng 	}
272da14cebeSEric Cheng 	case MAC_FLOW_MISC: {
273da14cebeSEric Cheng 		char		flow_flags[2 * FLOW_MAX_FLAGS];
274da14cebeSEric Cheng 		char		flow_type[2 * FLOW_MAX_TYPE];
275da14cebeSEric Cheng 		GElf_Sym 	sym;
276da14cebeSEric Cheng 		char		func_name[MDB_SYM_NAMLEN] = "";
277da14cebeSEric Cheng 		uintptr_t	func, match_addr;
278da14cebeSEric Cheng 
279da14cebeSEric Cheng 		match_addr = addr + OFFSETOF(flow_entry_t, fe_match);
280da14cebeSEric Cheng 		(void) mdb_vread(&func, sizeof (func), match_addr);
281da14cebeSEric Cheng 		(void) mdb_lookup_by_addr(func, MDB_SYM_EXACT, func_name,
282da14cebeSEric Cheng 		    MDB_SYM_NAMLEN, &sym);
283da14cebeSEric Cheng 		mdb_snprintf(flow_flags, 2 * FLOW_MAX_FLAGS, "%hb",
284da14cebeSEric Cheng 		    fe.fe_flags, flow_flag_bits);
285da14cebeSEric Cheng 		mdb_snprintf(flow_type, 2 * FLOW_MAX_TYPE, "%hb",
286da14cebeSEric Cheng 		    fe.fe_type, flow_type_bits);
287*fcff38ebSGirish Moodalbail 		mdb_printf("%?p %-24s %10s %10s "
288*fcff38ebSGirish Moodalbail 		    "%20s %4d\n",
289da14cebeSEric Cheng 		    addr, fe.fe_flow_name, flow_type, flow_flags,
290da14cebeSEric Cheng 		    func_name, fe.fe_zoneid);
291da14cebeSEric Cheng 		break;
292da14cebeSEric Cheng 	}
293da14cebeSEric Cheng 	case MAC_FLOW_RX: {
2942ae51e79SGirish Moodalbail 		uintptr_t	rxaddr, rx_srs[MAX_RINGS_PER_GROUP] = {0};
295da14cebeSEric Cheng 		int		i;
296da14cebeSEric Cheng 
297da14cebeSEric Cheng 		rxaddr = addr + OFFSETOF(flow_entry_t, fe_rx_srs);
298da14cebeSEric Cheng 		(void) mdb_vread(rx_srs, MAC_RX_SRS_SIZE, rxaddr);
299*fcff38ebSGirish Moodalbail 		mdb_printf("%?p %-24s %3d ",
3002ae51e79SGirish Moodalbail 		    addr, fe.fe_flow_name, fe.fe_rx_srs_cnt);
301da14cebeSEric Cheng 		for (i = 0; i < MAX_RINGS_PER_GROUP; i++) {
302da14cebeSEric Cheng 			if (rx_srs[i] == 0)
303da14cebeSEric Cheng 				continue;
304da14cebeSEric Cheng 			mdb_printf("%p ", rx_srs[i]);
305da14cebeSEric Cheng 		}
306da14cebeSEric Cheng 		mdb_printf("\n");
307da14cebeSEric Cheng 		break;
308da14cebeSEric Cheng 	}
309da14cebeSEric Cheng 	case MAC_FLOW_TX: {
310da14cebeSEric Cheng 		uintptr_t	tx_srs = 0, txaddr;
311da14cebeSEric Cheng 
312da14cebeSEric Cheng 		txaddr = addr + OFFSETOF(flow_entry_t, fe_tx_srs);
313da14cebeSEric Cheng 		(void) mdb_vread(&tx_srs, sizeof (uintptr_t), txaddr);
314da14cebeSEric Cheng 		mdb_printf("%?p %-32s %?p\n",
315da14cebeSEric Cheng 		    addr, fe.fe_flow_name, fe.fe_tx_srs);
316da14cebeSEric Cheng 		break;
317da14cebeSEric Cheng 	}
318da14cebeSEric Cheng 	case MAC_FLOW_STATS: {
319da14cebeSEric Cheng 		mdb_printf("%?p %-32s %16llu %16llu\n",
320da14cebeSEric Cheng 		    addr, fe.fe_flow_name, fe.fe_flowstats.fs_rbytes,
321da14cebeSEric Cheng 		    fe.fe_flowstats.fs_obytes);
322da14cebeSEric Cheng 		break;
323da14cebeSEric Cheng 	}
324da14cebeSEric Cheng 	}
325da14cebeSEric Cheng 	return (DCMD_OK);
326da14cebeSEric Cheng }
327da14cebeSEric Cheng 
328da14cebeSEric Cheng /*
329da14cebeSEric Cheng  * Parse the arguments passed to the dcmd and print all or one flow_entry_t
330da14cebeSEric Cheng  * structures
331da14cebeSEric Cheng  */
332da14cebeSEric Cheng static int
333da14cebeSEric Cheng mac_flow_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
334da14cebeSEric Cheng {
335da14cebeSEric Cheng 	uint_t	args = 0;
336da14cebeSEric Cheng 
337da14cebeSEric Cheng 	if (!(flags & DCMD_ADDRSPEC)) {
338da14cebeSEric Cheng 		if (mdb_walk_dcmd("mac_flow", "mac_flow", argc, argv) == -1) {
339da14cebeSEric Cheng 			mdb_warn("failed to walk 'mac_flow'");
340da14cebeSEric Cheng 			return (DCMD_ERR);
341da14cebeSEric Cheng 		}
342da14cebeSEric Cheng 		return (DCMD_OK);
343da14cebeSEric Cheng 	}
344da14cebeSEric Cheng 	if ((mdb_getopts(argc, argv,
345da14cebeSEric Cheng 	    'a', MDB_OPT_SETBITS, MAC_FLOW_ATTR, &args,
346da14cebeSEric Cheng 	    'p', MDB_OPT_SETBITS, MAC_FLOW_PROP, &args,
347da14cebeSEric Cheng 	    'm', MDB_OPT_SETBITS, MAC_FLOW_MISC, &args,
348da14cebeSEric Cheng 	    'r', MDB_OPT_SETBITS, MAC_FLOW_RX, &args,
349da14cebeSEric Cheng 	    't', MDB_OPT_SETBITS, MAC_FLOW_TX, &args,
350da14cebeSEric Cheng 	    's', MDB_OPT_SETBITS, MAC_FLOW_STATS, &args,
351da14cebeSEric Cheng 	    'u', MDB_OPT_SETBITS, MAC_FLOW_USER, &args) != argc)) {
352da14cebeSEric Cheng 		return (DCMD_USAGE);
353da14cebeSEric Cheng 	}
354da14cebeSEric Cheng 	if (argc > 2 || (argc == 2 && !(args & MAC_FLOW_USER)))
355da14cebeSEric Cheng 		return (DCMD_USAGE);
356da14cebeSEric Cheng 	/*
357da14cebeSEric Cheng 	 * If no arguments was specified or just "-u" was specified then
358da14cebeSEric Cheng 	 * we default to printing basic information of flows.
359da14cebeSEric Cheng 	 */
360da14cebeSEric Cheng 	if (args == 0 || args == MAC_FLOW_USER)
361da14cebeSEric Cheng 		args |= MAC_FLOW_NONE;
362da14cebeSEric Cheng 
363da14cebeSEric Cheng 	return (mac_flow_dcmd_output(addr, flags, args));
364da14cebeSEric Cheng }
365da14cebeSEric Cheng 
366da14cebeSEric Cheng static void
367da14cebeSEric Cheng mac_flow_help(void)
368da14cebeSEric Cheng {
369da14cebeSEric Cheng 	mdb_printf("If an address is specified, then flow_entry structure at "
370da14cebeSEric Cheng 	    "that address is printed. Otherwise all the flows in the system "
371da14cebeSEric Cheng 	    "are printed.\n");
372da14cebeSEric Cheng 	mdb_printf("Options:\n"
373da14cebeSEric Cheng 	    "\t-u\tdisplay user defined link & vnic flows.\n"
374da14cebeSEric Cheng 	    "\t-a\tdisplay flow attributes\n"
375da14cebeSEric Cheng 	    "\t-p\tdisplay flow properties\n"
376da14cebeSEric Cheng 	    "\t-r\tdisplay rx side information\n"
377da14cebeSEric Cheng 	    "\t-t\tdisplay tx side information\n"
378da14cebeSEric Cheng 	    "\t-s\tdisplay flow statistics\n"
379da14cebeSEric Cheng 	    "\t-m\tdisplay miscellaneous flow information\n\n");
380da14cebeSEric Cheng 	mdb_printf("%<u>Interpreting Flow type and Flow flags output.%</u>\n");
381da14cebeSEric Cheng 	mdb_printf("Flow Types:\n");
382da14cebeSEric Cheng 	mdb_printf("\t  P --> FLOW_PRIMARY_MAC\n");
383da14cebeSEric Cheng 	mdb_printf("\t  V --> FLOW_VNIC_MAC\n");
384da14cebeSEric Cheng 	mdb_printf("\t  M --> FLOW_MCAST\n");
385da14cebeSEric Cheng 	mdb_printf("\t  O --> FLOW_OTHER\n");
386da14cebeSEric Cheng 	mdb_printf("\t  U --> FLOW_USER\n");
387da14cebeSEric Cheng 	mdb_printf("\t NS --> FLOW_NO_STATS\n\n");
388da14cebeSEric Cheng 	mdb_printf("Flow Flags:\n");
389da14cebeSEric Cheng 	mdb_printf("\t  Q --> FE_QUIESCE\n");
390da14cebeSEric Cheng 	mdb_printf("\t  W --> FE_WAITER\n");
391da14cebeSEric Cheng 	mdb_printf("\t  T --> FE_FLOW_TAB\n");
392da14cebeSEric Cheng 	mdb_printf("\t  G --> FE_G_FLOW_HASH\n");
393da14cebeSEric Cheng 	mdb_printf("\t  I --> FE_INCIPIENT\n");
394da14cebeSEric Cheng 	mdb_printf("\t  C --> FE_CONDEMNED\n");
395da14cebeSEric Cheng 	mdb_printf("\t NU --> FE_UF_NO_DATAPATH\n");
396da14cebeSEric Cheng 	mdb_printf("\t NC --> FE_MC_NO_DATAPATH\n");
397da14cebeSEric Cheng }
398da14cebeSEric Cheng 
399da14cebeSEric Cheng /*
400da14cebeSEric Cheng  * called once by the debugger when the mac_flow walk begins.
401da14cebeSEric Cheng  */
402da14cebeSEric Cheng static int
403da14cebeSEric Cheng mac_flow_walk_init(mdb_walk_state_t *wsp)
404da14cebeSEric Cheng {
405da14cebeSEric Cheng 	if (mdb_layered_walk(LAYERED_WALKER_FOR_FLOW, wsp) == -1) {
406da14cebeSEric Cheng 		mdb_warn("failed to walk 'mac_flow'");
407da14cebeSEric Cheng 		return (WALK_ERR);
408da14cebeSEric Cheng 	}
409da14cebeSEric Cheng 	return (WALK_NEXT);
410da14cebeSEric Cheng }
411da14cebeSEric Cheng 
412da14cebeSEric Cheng /*
413da14cebeSEric Cheng  * Common walker step funciton for flow_entry_t, mac_soft_ring_set_t and
414da14cebeSEric Cheng  * mac_ring_t.
415da14cebeSEric Cheng  *
416da14cebeSEric Cheng  * Steps through each flow_entry_t and calls the callback function. If the
417da14cebeSEric Cheng  * user executed ::walk mac_flow, it just prints the address or if the user
418da14cebeSEric Cheng  * executed ::mac_flow it displays selected fields of flow_entry_t structure
419da14cebeSEric Cheng  * by calling "mac_flow_dcmd"
420da14cebeSEric Cheng  */
421da14cebeSEric Cheng static int
422da14cebeSEric Cheng mac_common_walk_step(mdb_walk_state_t *wsp)
423da14cebeSEric Cheng {
424da14cebeSEric Cheng 	int status;
425da14cebeSEric Cheng 
426da14cebeSEric Cheng 	if (wsp->walk_addr == NULL)
427da14cebeSEric Cheng 		return (WALK_DONE);
428da14cebeSEric Cheng 
429da14cebeSEric Cheng 	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
430da14cebeSEric Cheng 	    wsp->walk_cbdata);
431da14cebeSEric Cheng 
432da14cebeSEric Cheng 	return (status);
433da14cebeSEric Cheng }
434da14cebeSEric Cheng 
435da14cebeSEric Cheng static char *
436da14cebeSEric Cheng mac_srs_txmode2str(mac_tx_srs_mode_t mode)
437da14cebeSEric Cheng {
438da14cebeSEric Cheng 	switch (mode) {
439da14cebeSEric Cheng 	case SRS_TX_DEFAULT:
4402ae51e79SGirish Moodalbail 		return ("DEF");
441da14cebeSEric Cheng 	case SRS_TX_SERIALIZE:
4422ae51e79SGirish Moodalbail 		return ("SER");
443da14cebeSEric Cheng 	case SRS_TX_FANOUT:
4442ae51e79SGirish Moodalbail 		return ("FO");
445da14cebeSEric Cheng 	case SRS_TX_BW:
4462ae51e79SGirish Moodalbail 		return ("BW");
447da14cebeSEric Cheng 	case SRS_TX_BW_FANOUT:
4482ae51e79SGirish Moodalbail 		return ("BWFO");
449da14cebeSEric Cheng 	}
450da14cebeSEric Cheng 	return ("--");
451da14cebeSEric Cheng }
452da14cebeSEric Cheng 
453da14cebeSEric Cheng static void
454da14cebeSEric Cheng mac_srs_help(void)
455da14cebeSEric Cheng {
456da14cebeSEric Cheng 	mdb_printf("If an address is specified, then mac_soft_ring_set "
457da14cebeSEric Cheng 	    "structure at that address is printed. Otherwise all the "
458da14cebeSEric Cheng 	    "SRS in the system are printed.\n");
459da14cebeSEric Cheng 	mdb_printf("Options:\n"
460da14cebeSEric Cheng 	    "\t-r\tdisplay recieve side SRS structures\n"
4612ae51e79SGirish Moodalbail 	    "\t-t\tdisplay transmit side SRS structures\n"
4622ae51e79SGirish Moodalbail 	    "\t-s\tdisplay statistics for RX or TX side\n"
4632ae51e79SGirish Moodalbail 	    "\t-c\tdisplay CPU binding for RX or TX side\n"
4642ae51e79SGirish Moodalbail 	    "\t-v\tverbose flag for CPU binding to list cpus\n"
4652ae51e79SGirish Moodalbail 	    "Note: use -r or -t (to specify RX or TX side respectively) along "
4662ae51e79SGirish Moodalbail 	    "with -c or -s\n");
4672ae51e79SGirish Moodalbail 	mdb_printf("\n%<u>Interpreting TX Modes%</u>\n");
4682ae51e79SGirish Moodalbail 	mdb_printf("\t DEF --> Default\n");
4692ae51e79SGirish Moodalbail 	mdb_printf("\t SER --> Serialize\n");
4702ae51e79SGirish Moodalbail 	mdb_printf("\t  FO --> Fanout\n");
4712ae51e79SGirish Moodalbail 	mdb_printf("\t  BW --> Bandwidth\n");
4722ae51e79SGirish Moodalbail 	mdb_printf("\tBWFO --> Bandwidth Fanout\n");
4732ae51e79SGirish Moodalbail }
4742ae51e79SGirish Moodalbail 
4752ae51e79SGirish Moodalbail /*
4762ae51e79SGirish Moodalbail  * In verbose mode "::mac_srs -rcv or ::mac_srs -tcv", we print the CPUs
4772ae51e79SGirish Moodalbail  * assigned to a link and CPUS assigned to the soft rings.
4782ae51e79SGirish Moodalbail  * 'len' is used for formatting the output and represents the number of
4792ae51e79SGirish Moodalbail  * spaces between CPU list and Fanout CPU list in the output.
4802ae51e79SGirish Moodalbail  */
4812ae51e79SGirish Moodalbail static boolean_t
4822ae51e79SGirish Moodalbail mac_srs_print_cpu(int *i, uint32_t cnt, uint32_t *cpu_list, int *len)
4832ae51e79SGirish Moodalbail {
4842ae51e79SGirish Moodalbail 	int		num = 0;
4852ae51e79SGirish Moodalbail 
4862ae51e79SGirish Moodalbail 	if (*i == 0)
4872ae51e79SGirish Moodalbail 		mdb_printf("(");
4882ae51e79SGirish Moodalbail 	else
4892ae51e79SGirish Moodalbail 		mdb_printf(" ");
4902ae51e79SGirish Moodalbail 	while (*i < cnt) {
4912ae51e79SGirish Moodalbail 		/* We print 6 CPU's at a time to keep display within 80 cols */
4922ae51e79SGirish Moodalbail 		if (((num + 1) % 7) == 0) {
4932ae51e79SGirish Moodalbail 			if (len != NULL)
4942ae51e79SGirish Moodalbail 				*len = 2;
4952ae51e79SGirish Moodalbail 			return (B_FALSE);
4962ae51e79SGirish Moodalbail 		}
4972ae51e79SGirish Moodalbail 		mdb_printf("%02x%c", cpu_list[*i], ((*i == cnt - 1)?')':','));
4982ae51e79SGirish Moodalbail 		++*i;
4992ae51e79SGirish Moodalbail 		++num;
5002ae51e79SGirish Moodalbail 	}
5012ae51e79SGirish Moodalbail 	if (len != NULL)
5022ae51e79SGirish Moodalbail 		*len = (7 - num) * 3;
5032ae51e79SGirish Moodalbail 	return (B_TRUE);
504da14cebeSEric Cheng }
505da14cebeSEric Cheng 
506da14cebeSEric Cheng static int
507da14cebeSEric Cheng mac_srs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
508da14cebeSEric Cheng {
5092ae51e79SGirish Moodalbail 	uint_t			args = MAC_SRS_NONE;
510da14cebeSEric Cheng 	mac_soft_ring_set_t	srs;
5112ae51e79SGirish Moodalbail 	mac_client_impl_t	mci;
512da14cebeSEric Cheng 
513da14cebeSEric Cheng 	if (!(flags & DCMD_ADDRSPEC)) {
514da14cebeSEric Cheng 		if (mdb_walk_dcmd("mac_srs", "mac_srs", argc, argv) == -1) {
515da14cebeSEric Cheng 			mdb_warn("failed to walk 'mac_srs'");
516da14cebeSEric Cheng 			return (DCMD_ERR);
517da14cebeSEric Cheng 		}
518da14cebeSEric Cheng 		return (DCMD_OK);
519da14cebeSEric Cheng 	}
5202ae51e79SGirish Moodalbail 	if (mdb_getopts(argc, argv,
521da14cebeSEric Cheng 	    'r', MDB_OPT_SETBITS, MAC_SRS_RX, &args,
5222ae51e79SGirish Moodalbail 	    't', MDB_OPT_SETBITS, MAC_SRS_TX, &args,
5232ae51e79SGirish Moodalbail 	    'c', MDB_OPT_SETBITS, MAC_SRS_CPU, &args,
5242ae51e79SGirish Moodalbail 	    'v', MDB_OPT_SETBITS, MAC_SRS_VERBOSE, &args,
5252ae51e79SGirish Moodalbail 	    's', MDB_OPT_SETBITS, MAC_SRS_STAT, &args) != argc) {
526da14cebeSEric Cheng 		return (DCMD_USAGE);
527da14cebeSEric Cheng 	}
5282ae51e79SGirish Moodalbail 
5292ae51e79SGirish Moodalbail 	if (argc > 2)
530da14cebeSEric Cheng 		return (DCMD_USAGE);
531da14cebeSEric Cheng 
532da14cebeSEric Cheng 	if (mdb_vread(&srs, sizeof (srs), addr) == -1) {
533da14cebeSEric Cheng 		mdb_warn("failed to read struct mac_soft_ring_set_s at %p",
534da14cebeSEric Cheng 		    addr);
535da14cebeSEric Cheng 		return (DCMD_ERR);
536da14cebeSEric Cheng 	}
5372ae51e79SGirish Moodalbail 	if (mdb_vread(&mci, sizeof (mci), (uintptr_t)srs.srs_mcip) == -1) {
5382ae51e79SGirish Moodalbail 		mdb_warn("failed to read struct mac_client_impl_t at %p "
5392ae51e79SGirish Moodalbail 		    "for SRS %p", srs.srs_mcip, addr);
5402ae51e79SGirish Moodalbail 		return (DCMD_ERR);
5412ae51e79SGirish Moodalbail 	}
542da14cebeSEric Cheng 
543da14cebeSEric Cheng 	switch (args) {
544da14cebeSEric Cheng 	case MAC_SRS_RX: {
545da14cebeSEric Cheng 		if (DCMD_HDRSPEC(flags)) {
546*fcff38ebSGirish Moodalbail 			mdb_printf("%?s %-20s %-8s %-8s %8s "
547*fcff38ebSGirish Moodalbail 			    "%8s %3s\n",
5482ae51e79SGirish Moodalbail 			    "", "", "", "", "MBLK",
5492ae51e79SGirish Moodalbail 			    "Q", "SR");
550*fcff38ebSGirish Moodalbail 			mdb_printf("%<u>%?s %-20s %-8s %-8s %8s "
551*fcff38ebSGirish Moodalbail 			    "%8s %3s%</u>\n",
5522ae51e79SGirish Moodalbail 			    "ADDR", "LINK_NAME", "STATE", "TYPE", "CNT",
5532ae51e79SGirish Moodalbail 			    "BYTES", "CNT");
554da14cebeSEric Cheng 		}
555da14cebeSEric Cheng 		if (srs.srs_type & SRST_TX)
556da14cebeSEric Cheng 			return (DCMD_OK);
5572ae51e79SGirish Moodalbail 		mdb_printf("%?p %-20s %08x %08x "
558*fcff38ebSGirish Moodalbail 		    "%8d %8d %3d\n",
5592ae51e79SGirish Moodalbail 		    addr, mci.mci_name, srs.srs_state, srs.srs_type,
5602ae51e79SGirish Moodalbail 		    srs.srs_count, srs.srs_size, srs.srs_soft_ring_count);
561da14cebeSEric Cheng 		break;
562da14cebeSEric Cheng 	}
563da14cebeSEric Cheng 	case MAC_SRS_TX: {
564da14cebeSEric Cheng 		if (DCMD_HDRSPEC(flags)) {
5652ae51e79SGirish Moodalbail 			mdb_printf("%?s %-16s %-4s %-8s "
566*fcff38ebSGirish Moodalbail 			    "%-8s %8s %8s %3s\n",
5672ae51e79SGirish Moodalbail 			    "", "", "TX", "",
5682ae51e79SGirish Moodalbail 			    "", "MBLK", "Q", "SR");
5692ae51e79SGirish Moodalbail 			mdb_printf("%<u>%?s %-16s %-4s %-8s "
570*fcff38ebSGirish Moodalbail 			    "%-8s %8s %8s %3s%</u>\n",
5712ae51e79SGirish Moodalbail 			    "ADDR", "LINK_NAME", "MODE", "STATE",
5722ae51e79SGirish Moodalbail 			    "TYPE", "CNT", "BYTES", "CNT");
5732ae51e79SGirish Moodalbail 		}
5742ae51e79SGirish Moodalbail 		if (!(srs.srs_type & SRST_TX))
5752ae51e79SGirish Moodalbail 			return (DCMD_OK);
5762ae51e79SGirish Moodalbail 
5772ae51e79SGirish Moodalbail 		mdb_printf("%?p %-16s %-4s "
578*fcff38ebSGirish Moodalbail 		    "%08x %08x %8d %8d %3d\n",
5792ae51e79SGirish Moodalbail 		    addr, mci.mci_name, mac_srs_txmode2str(srs.srs_tx.st_mode),
5802ae51e79SGirish Moodalbail 		    srs.srs_state, srs.srs_type, srs.srs_count, srs.srs_size,
5812ae51e79SGirish Moodalbail 		    srs.srs_oth_ring_count);
5822ae51e79SGirish Moodalbail 		break;
5832ae51e79SGirish Moodalbail 	}
5842ae51e79SGirish Moodalbail 	case MAC_SRS_RXCPU: {
5852ae51e79SGirish Moodalbail 		mac_cpus_t	mc = srs.srs_cpu;
5862ae51e79SGirish Moodalbail 
5872ae51e79SGirish Moodalbail 		if (DCMD_HDRSPEC(flags)) {
5882ae51e79SGirish Moodalbail 			mdb_printf("%?s %-20s %-4s %-4s "
5892ae51e79SGirish Moodalbail 			    "%-6s %-4s %-7s\n",
5902ae51e79SGirish Moodalbail 			    "", "", "NUM", "POLL",
5912ae51e79SGirish Moodalbail 			    "WORKER", "INTR", "FANOUT");
5922ae51e79SGirish Moodalbail 			mdb_printf("%<u>%?s %-20s %-4s %-4s "
5932ae51e79SGirish Moodalbail 			    "%-6s %-4s %-7s%</u>\n",
5942ae51e79SGirish Moodalbail 			    "ADDR", "LINK_NAME", "CPUS", "CPU",
5952ae51e79SGirish Moodalbail 			    "CPU", "CPU", "CPU_CNT");
5962ae51e79SGirish Moodalbail 		}
5972ae51e79SGirish Moodalbail 		if ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX))
5982ae51e79SGirish Moodalbail 			return (DCMD_OK);
5992ae51e79SGirish Moodalbail 		mdb_printf("%?p %-20s %-4d %-4d "
6002ae51e79SGirish Moodalbail 		    "%-6d %-4d %-7d\n",
6012ae51e79SGirish Moodalbail 		    addr, mci.mci_name, mc.mc_ncpus, mc.mc_pollid,
6022ae51e79SGirish Moodalbail 		    mc.mc_workerid, mc.mc_intr_cpu, mc.mc_fanout_cnt);
6032ae51e79SGirish Moodalbail 		break;
6042ae51e79SGirish Moodalbail 
6052ae51e79SGirish Moodalbail 	}
6062ae51e79SGirish Moodalbail 	case MAC_SRS_TXCPU: {
6072ae51e79SGirish Moodalbail 		mac_cpus_t	mc = srs.srs_cpu;
6082ae51e79SGirish Moodalbail 
6092ae51e79SGirish Moodalbail 		if (DCMD_HDRSPEC(flags)) {
6102ae51e79SGirish Moodalbail 			mdb_printf("%?s %-20s %-4s %-6s "
6112ae51e79SGirish Moodalbail 			    "%-4s %-7s\n",
6122ae51e79SGirish Moodalbail 			    "", "", "NUM", "WORKER",
6132ae51e79SGirish Moodalbail 			    "INTR", "FANOUT");
6142ae51e79SGirish Moodalbail 			mdb_printf("%<u>%?s %-20s %-4s %-6s "
6152ae51e79SGirish Moodalbail 			    "%-4s %-7s%</u>\n",
6162ae51e79SGirish Moodalbail 			    "ADDR", "LINK_NAME", "CPUS", "CPU",
6172ae51e79SGirish Moodalbail 			    "CPU", "CPU_CNT");
6182ae51e79SGirish Moodalbail 		}
6192ae51e79SGirish Moodalbail 		if ((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX))
6202ae51e79SGirish Moodalbail 			return (DCMD_OK);
6212ae51e79SGirish Moodalbail 		mdb_printf("%?p %-20s %-4d "
6222ae51e79SGirish Moodalbail 		    "%-6d %-4d %-7d\n",
6232ae51e79SGirish Moodalbail 		    addr, mci.mci_name, mc.mc_ncpus,
6242ae51e79SGirish Moodalbail 		    mc.mc_workerid, mc.mc_intr_cpu, mc.mc_fanout_cnt);
6252ae51e79SGirish Moodalbail 		break;
6262ae51e79SGirish Moodalbail 	}
6272ae51e79SGirish Moodalbail 	case MAC_SRS_RXCPUVERBOSE:
6282ae51e79SGirish Moodalbail 	case MAC_SRS_TXCPUVERBOSE: {
6292ae51e79SGirish Moodalbail 		mac_cpus_t	mc = srs.srs_cpu;
6302ae51e79SGirish Moodalbail 		int		cpu_index = 0, fanout_index = 0, len = 0;
6312ae51e79SGirish Moodalbail 		boolean_t	cpu_done = B_FALSE, fanout_done = B_FALSE;
6322ae51e79SGirish Moodalbail 
6332ae51e79SGirish Moodalbail 		if (DCMD_HDRSPEC(flags)) {
6342ae51e79SGirish Moodalbail 			mdb_printf("%?s %-20s %-20s %-20s\n",
6352ae51e79SGirish Moodalbail 			    "", "", "CPU_COUNT", "FANOUT_CPU_COUNT");
6362ae51e79SGirish Moodalbail 			mdb_printf("%<u>%?s %-20s "
6372ae51e79SGirish Moodalbail 			    "%-20s %-20s%</u>\n",
6382ae51e79SGirish Moodalbail 			    "ADDR", "LINK_NAME",
6392ae51e79SGirish Moodalbail 			    "(CPU_LIST)", "(CPU_LIST)");
6402ae51e79SGirish Moodalbail 		}
6412ae51e79SGirish Moodalbail 		if (((args & MAC_SRS_TX) && !(srs.srs_type & SRST_TX)) ||
6422ae51e79SGirish Moodalbail 		    ((args & MAC_SRS_RX) && (srs.srs_type & SRST_TX)))
6432ae51e79SGirish Moodalbail 			return (DCMD_OK);
6442ae51e79SGirish Moodalbail 		mdb_printf("%?p %-20s %-20d %-20d\n", addr, mci.mci_name,
6452ae51e79SGirish Moodalbail 		    mc.mc_ncpus, mc.mc_fanout_cnt);
6462ae51e79SGirish Moodalbail 		if (mc.mc_ncpus == 0 && mc.mc_fanout_cnt == 0)
6472ae51e79SGirish Moodalbail 			break;
6482ae51e79SGirish Moodalbail 		/* print all cpus and cpus for soft rings */
6492ae51e79SGirish Moodalbail 		while (!cpu_done || !fanout_done) {
6502ae51e79SGirish Moodalbail 			boolean_t old_value = cpu_done;
6512ae51e79SGirish Moodalbail 
6522ae51e79SGirish Moodalbail 			if (!cpu_done) {
6532ae51e79SGirish Moodalbail 				mdb_printf("%?s %20s ", "", "");
6542ae51e79SGirish Moodalbail 				cpu_done = mac_srs_print_cpu(&cpu_index,
6552ae51e79SGirish Moodalbail 				    mc.mc_ncpus, mc.mc_cpus, &len);
6562ae51e79SGirish Moodalbail 			}
6572ae51e79SGirish Moodalbail 			if (!fanout_done) {
6582ae51e79SGirish Moodalbail 				if (old_value)
6592ae51e79SGirish Moodalbail 					mdb_printf("%?s %-40s", "", "");
6602ae51e79SGirish Moodalbail 				else
6612ae51e79SGirish Moodalbail 					mdb_printf("%*s", len, "");
6622ae51e79SGirish Moodalbail 				fanout_done = mac_srs_print_cpu(&fanout_index,
6632ae51e79SGirish Moodalbail 				    mc.mc_fanout_cnt, mc.mc_fanout_cpus, NULL);
6642ae51e79SGirish Moodalbail 			}
6652ae51e79SGirish Moodalbail 			mdb_printf("\n");
6662ae51e79SGirish Moodalbail 		}
6672ae51e79SGirish Moodalbail 		break;
6682ae51e79SGirish Moodalbail 	}
6692ae51e79SGirish Moodalbail 	case MAC_SRS_RXSTAT: {
6702ae51e79SGirish Moodalbail 		mac_srs_rx_t srs_rx = srs.srs_rx;
6712ae51e79SGirish Moodalbail 
6722ae51e79SGirish Moodalbail 		if (DCMD_HDRSPEC(flags)) {
673*fcff38ebSGirish Moodalbail 			mdb_printf("%?s %-16s %8s %8s "
674*fcff38ebSGirish Moodalbail 			    "%8s %8s %8s\n",
6752ae51e79SGirish Moodalbail 			    "", "", "INTR", "POLL",
6762ae51e79SGirish Moodalbail 			    "CHAIN", "CHAIN", "CHAIN");
677*fcff38ebSGirish Moodalbail 			mdb_printf("%<u>%?s %-16s %8s %8s "
678*fcff38ebSGirish Moodalbail 			    "%8s %8s %8s%</u>\n",
6792ae51e79SGirish Moodalbail 			    "ADDR", "LINK_NAME", "COUNT", "COUNT",
6802ae51e79SGirish Moodalbail 			    "<10", "10-50", ">50");
6812ae51e79SGirish Moodalbail 		}
6822ae51e79SGirish Moodalbail 		if (srs.srs_type & SRST_TX)
6832ae51e79SGirish Moodalbail 			return (DCMD_OK);
684*fcff38ebSGirish Moodalbail 		mdb_printf("%?p %-16s %8d "
685*fcff38ebSGirish Moodalbail 		    "%8d %8d "
686*fcff38ebSGirish Moodalbail 		    "%8d %8d\n",
6872ae51e79SGirish Moodalbail 		    addr, mci.mci_name, srs_rx.sr_intr_count,
6882ae51e79SGirish Moodalbail 		    srs_rx.sr_poll_count, srs_rx.sr_chain_cnt_undr10,
6892ae51e79SGirish Moodalbail 		    srs_rx.sr_chain_cnt_10to50, srs_rx.sr_chain_cnt_over50);
6902ae51e79SGirish Moodalbail 		break;
6912ae51e79SGirish Moodalbail 	}
6922ae51e79SGirish Moodalbail 	case MAC_SRS_TXSTAT: {
6932ae51e79SGirish Moodalbail 		mac_srs_tx_t srs_tx = srs.srs_tx;
694*fcff38ebSGirish Moodalbail 		mac_soft_ring_t *s_ringp, s_ring;
695*fcff38ebSGirish Moodalbail 		boolean_t	first = B_TRUE;
6962ae51e79SGirish Moodalbail 
6972ae51e79SGirish Moodalbail 		if (DCMD_HDRSPEC(flags)) {
698*fcff38ebSGirish Moodalbail 			mdb_printf("%?s %-20s %?s %8s %8s %8s\n",
699*fcff38ebSGirish Moodalbail 			    "", "", "SOFT", "DROP", "BLOCK", "UNBLOCK");
700*fcff38ebSGirish Moodalbail 			mdb_printf("%<u>%?s %-20s %?s %8s %8s %8s%</u>\n",
701*fcff38ebSGirish Moodalbail 			    "ADDR", "LINK_NAME", "RING", "COUNT", "COUNT",
702*fcff38ebSGirish Moodalbail 			    "COUNT");
703da14cebeSEric Cheng 		}
704da14cebeSEric Cheng 		if (!(srs.srs_type & SRST_TX))
705da14cebeSEric Cheng 			return (DCMD_OK);
706da14cebeSEric Cheng 
707*fcff38ebSGirish Moodalbail 		mdb_printf("%?p %-20s ", addr, mci.mci_name);
708*fcff38ebSGirish Moodalbail 
709*fcff38ebSGirish Moodalbail 		/*
710*fcff38ebSGirish Moodalbail 		 * Case of no soft rings, print the info from
711*fcff38ebSGirish Moodalbail 		 * mac_srs_tx_t.
712*fcff38ebSGirish Moodalbail 		 */
713*fcff38ebSGirish Moodalbail 		if (srs.srs_oth_ring_count == 0) {
714*fcff38ebSGirish Moodalbail 			mdb_printf("%?p %8d %8d %8d\n",
715*fcff38ebSGirish Moodalbail 			    0, srs_tx.st_drop_count, srs_tx.st_blocked_cnt,
716*fcff38ebSGirish Moodalbail 			    srs_tx.st_unblocked_cnt);
717*fcff38ebSGirish Moodalbail 			break;
718*fcff38ebSGirish Moodalbail 		}
719*fcff38ebSGirish Moodalbail 
720*fcff38ebSGirish Moodalbail 		for (s_ringp = srs.srs_soft_ring_head; s_ringp != NULL;
721*fcff38ebSGirish Moodalbail 		    s_ringp = s_ring.s_ring_next) {
722*fcff38ebSGirish Moodalbail 			(void) mdb_vread(&s_ring, sizeof (s_ring),
723*fcff38ebSGirish Moodalbail 			    (uintptr_t)s_ringp);
724*fcff38ebSGirish Moodalbail 			if (first) {
725*fcff38ebSGirish Moodalbail 				mdb_printf("%?p %8d %8d %8d\n",
726*fcff38ebSGirish Moodalbail 				    s_ringp, s_ring.s_ring_drops,
727*fcff38ebSGirish Moodalbail 				    s_ring.s_ring_blocked_cnt,
728*fcff38ebSGirish Moodalbail 				    s_ring.s_ring_unblocked_cnt);
729*fcff38ebSGirish Moodalbail 				first = B_FALSE;
730*fcff38ebSGirish Moodalbail 				continue;
731*fcff38ebSGirish Moodalbail 			}
732*fcff38ebSGirish Moodalbail 			mdb_printf("%?s %-20s %?p %8d %8d %8d\n",
733*fcff38ebSGirish Moodalbail 			    "", "", s_ringp, s_ring.s_ring_drops,
734*fcff38ebSGirish Moodalbail 			    s_ring.s_ring_blocked_cnt,
735*fcff38ebSGirish Moodalbail 			    s_ring.s_ring_unblocked_cnt);
736*fcff38ebSGirish Moodalbail 		}
737da14cebeSEric Cheng 		break;
738da14cebeSEric Cheng 	}
7392ae51e79SGirish Moodalbail 	case MAC_SRS_NONE: {
740da14cebeSEric Cheng 		if (DCMD_HDRSPEC(flags)) {
7412ae51e79SGirish Moodalbail 			mdb_printf("%<u>%?s %-20s %?s %?s %-3s%</u>\n",
7422ae51e79SGirish Moodalbail 			    "ADDR", "LINK_NAME", "FLENT", "HW RING", "DIR");
743da14cebeSEric Cheng 		}
7442ae51e79SGirish Moodalbail 		mdb_printf("%?p %-20s %?p %?p "
7452ae51e79SGirish Moodalbail 		    "%-3s ",
7462ae51e79SGirish Moodalbail 		    addr, mci.mci_name, srs.srs_flent, srs.srs_ring,
7472ae51e79SGirish Moodalbail 		    (srs.srs_type & SRST_TX ? "TX" : "RX"));
748da14cebeSEric Cheng 		break;
749da14cebeSEric Cheng 	}
7502ae51e79SGirish Moodalbail 	default:
7512ae51e79SGirish Moodalbail 		return (DCMD_USAGE);
752da14cebeSEric Cheng 	}
753da14cebeSEric Cheng 	return (DCMD_OK);
754da14cebeSEric Cheng }
755da14cebeSEric Cheng 
756da14cebeSEric Cheng static int
757da14cebeSEric Cheng mac_srs_walk_init(mdb_walk_state_t *wsp)
758da14cebeSEric Cheng {
759da14cebeSEric Cheng 	if (mdb_layered_walk(LAYERED_WALKER_FOR_SRS, wsp) == -1) {
760da14cebeSEric Cheng 		mdb_warn("failed to walk 'mac_srs'");
761da14cebeSEric Cheng 		return (WALK_ERR);
762da14cebeSEric Cheng 	}
763da14cebeSEric Cheng 	return (WALK_NEXT);
764da14cebeSEric Cheng }
765da14cebeSEric Cheng 
766da14cebeSEric Cheng static char *
767da14cebeSEric Cheng mac_ring_state2str(mac_ring_state_t state)
768da14cebeSEric Cheng {
769da14cebeSEric Cheng 	switch (state) {
770da14cebeSEric Cheng 	case MR_FREE:
771da14cebeSEric Cheng 		return ("free");
772da14cebeSEric Cheng 	case MR_NEWLY_ADDED:
773da14cebeSEric Cheng 		return ("new");
774da14cebeSEric Cheng 	case MR_INUSE:
775da14cebeSEric Cheng 		return ("inuse");
776da14cebeSEric Cheng 	}
777da14cebeSEric Cheng 	return ("--");
778da14cebeSEric Cheng }
779da14cebeSEric Cheng 
780da14cebeSEric Cheng static char *
781da14cebeSEric Cheng mac_ring_classify2str(mac_classify_type_t classify)
782da14cebeSEric Cheng {
783da14cebeSEric Cheng 	switch (classify) {
784da14cebeSEric Cheng 	case MAC_NO_CLASSIFIER:
785da14cebeSEric Cheng 		return ("no");
786da14cebeSEric Cheng 	case MAC_SW_CLASSIFIER:
787da14cebeSEric Cheng 		return ("sw");
788da14cebeSEric Cheng 	case MAC_HW_CLASSIFIER:
789da14cebeSEric Cheng 		return ("hw");
790da14cebeSEric Cheng 	}
791da14cebeSEric Cheng 	return ("--");
792da14cebeSEric Cheng }
793da14cebeSEric Cheng 
794da14cebeSEric Cheng static int
795da14cebeSEric Cheng mac_ring_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
796da14cebeSEric Cheng {
797da14cebeSEric Cheng 	mac_ring_t		ring;
798da14cebeSEric Cheng 	mac_group_t		group;
799da14cebeSEric Cheng 	flow_entry_t		flent;
800da14cebeSEric Cheng 	mac_soft_ring_set_t	srs;
801da14cebeSEric Cheng 
802da14cebeSEric Cheng 	if (!(flags & DCMD_ADDRSPEC)) {
803da14cebeSEric Cheng 		if (mdb_walk_dcmd("mac_ring", "mac_ring", argc, argv) == -1) {
804da14cebeSEric Cheng 			mdb_warn("failed to walk 'mac_ring'");
805da14cebeSEric Cheng 			return (DCMD_ERR);
806da14cebeSEric Cheng 		}
807da14cebeSEric Cheng 		return (DCMD_OK);
808da14cebeSEric Cheng 	}
809da14cebeSEric Cheng 	if (mdb_vread(&ring, sizeof (ring), addr) == -1) {
810da14cebeSEric Cheng 		mdb_warn("failed to read struct mac_ring_s at %p", addr);
811da14cebeSEric Cheng 		return (DCMD_ERR);
812da14cebeSEric Cheng 	}
813da14cebeSEric Cheng 	bzero(&flent, sizeof (flent));
814da14cebeSEric Cheng 	if (mdb_vread(&srs, sizeof (srs), (uintptr_t)ring.mr_srs) != -1) {
815da14cebeSEric Cheng 		(void) mdb_vread(&flent, sizeof (flent),
816da14cebeSEric Cheng 		    (uintptr_t)srs.srs_flent);
817da14cebeSEric Cheng 	}
818da14cebeSEric Cheng 	(void) mdb_vread(&group, sizeof (group), (uintptr_t)ring.mr_gh);
819da14cebeSEric Cheng 	if (DCMD_HDRSPEC(flags)) {
820da14cebeSEric Cheng 		mdb_printf("%<u>%?s %4s %5s %4s %?s "
821da14cebeSEric Cheng 		    "%5s %?s %?s %s %</u>\n",
822da14cebeSEric Cheng 		    "ADDR", "TYPE", "STATE", "FLAG", "GROUP",
823da14cebeSEric Cheng 		    "CLASS", "MIP", "SRS", "FLOW NAME");
824da14cebeSEric Cheng 	}
825da14cebeSEric Cheng 	mdb_printf("%?p %-4s "
826da14cebeSEric Cheng 	    "%5s %04x "
827da14cebeSEric Cheng 	    "%?p %-5s "
828da14cebeSEric Cheng 	    "%?p %?p %s\n",
829da14cebeSEric Cheng 	    addr, ((ring.mr_type == 1)? "RX" : "TX"),
830da14cebeSEric Cheng 	    mac_ring_state2str(ring.mr_state), ring.mr_flag,
831da14cebeSEric Cheng 	    ring.mr_gh, mac_ring_classify2str(ring.mr_classify_type),
832da14cebeSEric Cheng 	    group.mrg_mh, ring.mr_srs, flent.fe_flow_name);
833da14cebeSEric Cheng 	return (DCMD_OK);
834da14cebeSEric Cheng }
835da14cebeSEric Cheng 
836da14cebeSEric Cheng static int
837da14cebeSEric Cheng mac_ring_walk_init(mdb_walk_state_t *wsp)
838da14cebeSEric Cheng {
839da14cebeSEric Cheng 	if (mdb_layered_walk(LAYERED_WALKER_FOR_RING, wsp) == -1) {
840da14cebeSEric Cheng 		mdb_warn("failed to walk `mac_ring`");
841da14cebeSEric Cheng 		return (WALK_ERR);
842da14cebeSEric Cheng 	}
843da14cebeSEric Cheng 	return (WALK_NEXT);
844da14cebeSEric Cheng }
845da14cebeSEric Cheng 
846da14cebeSEric Cheng static void
847da14cebeSEric Cheng mac_ring_help(void)
848da14cebeSEric Cheng {
849da14cebeSEric Cheng 	mdb_printf("If an address is specified, then mac_ring_t "
850da14cebeSEric Cheng 	    "structure at that address is printed. Otherwise all the "
851da14cebeSEric Cheng 	    "hardware rings in the system are printed.\n");
852da14cebeSEric Cheng }
853da14cebeSEric Cheng 
854da14cebeSEric Cheng /* Supported dee-commands */
855da14cebeSEric Cheng static const mdb_dcmd_t dcmds[] = {
856da14cebeSEric Cheng 	{"mac_flow", "?[-u] [-aprtsm]", "display Flow Entry structures",
857da14cebeSEric Cheng 	    mac_flow_dcmd, mac_flow_help},
8582ae51e79SGirish Moodalbail 	{"mac_srs", "?[ -r[s|c[v]] | -t[s|c[v]] ]", "display MAC Soft Ring Set"
8592ae51e79SGirish Moodalbail 	    " structures", mac_srs_dcmd, mac_srs_help},
860da14cebeSEric Cheng 	{"mac_ring", "?", "display MAC ring (hardware) structures",
861da14cebeSEric Cheng 	    mac_ring_dcmd, mac_ring_help},
862da14cebeSEric Cheng 	{ NULL }
863da14cebeSEric Cheng };
864da14cebeSEric Cheng 
865da14cebeSEric Cheng /* Supported walkers */
866da14cebeSEric Cheng static const mdb_walker_t walkers[] = {
867da14cebeSEric Cheng 	{"mac_flow", "walk list of flow entry structures", mac_flow_walk_init,
868da14cebeSEric Cheng 	    mac_common_walk_step, NULL, NULL},
869da14cebeSEric Cheng 	{"mac_srs", "walk list of mac soft ring set structures",
870da14cebeSEric Cheng 	    mac_srs_walk_init, mac_common_walk_step, NULL, NULL},
871da14cebeSEric Cheng 	{"mac_ring", "walk list of mac ring structures", mac_ring_walk_init,
872da14cebeSEric Cheng 	    mac_common_walk_step, NULL, NULL},
873da14cebeSEric Cheng 	{ NULL }
874da14cebeSEric Cheng };
875da14cebeSEric Cheng 
876da14cebeSEric Cheng static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
877da14cebeSEric Cheng 
878da14cebeSEric Cheng const mdb_modinfo_t *
879da14cebeSEric Cheng _mdb_init(void)
880da14cebeSEric Cheng {
881da14cebeSEric Cheng 	return (&modinfo);
882da14cebeSEric Cheng }
883