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