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 /*
22*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23da14cebeSEric Cheng  * Use is subject to license terms.
24da14cebeSEric Cheng  */
25da14cebeSEric Cheng 
26da14cebeSEric Cheng #include <stdio.h>
27da14cebeSEric Cheng #include <stdlib.h>
28da14cebeSEric Cheng #include <strings.h>
29da14cebeSEric Cheng #include <err.h>
30da14cebeSEric Cheng #include <errno.h>
31c3affd82SMichael Lim #include <fcntl.h>
32da14cebeSEric Cheng #include <kstat.h>
33c3affd82SMichael Lim #include <limits.h>
34da14cebeSEric Cheng #include <unistd.h>
35da14cebeSEric Cheng #include <signal.h>
36da14cebeSEric Cheng #include <sys/dld.h>
3782a2fc47SJames Carlson #include <sys/ddi.h>
38da14cebeSEric Cheng 
39da14cebeSEric Cheng #include <libdllink.h>
40da14cebeSEric Cheng #include <libdlflow.h>
41da14cebeSEric Cheng #include <libdlstat.h>
42*0dc2366fSVenugopal Iyer #include <libdlaggr.h>
43da14cebeSEric Cheng 
44da14cebeSEric Cheng /*
45da14cebeSEric Cheng  * x86 <sys/regs> ERR conflicts with <curses.h> ERR.
46da14cebeSEric Cheng  * Include curses.h last.
47da14cebeSEric Cheng  */
48da14cebeSEric Cheng #if	defined(ERR)
49da14cebeSEric Cheng #undef  ERR
50da14cebeSEric Cheng #endif
51da14cebeSEric Cheng #include <curses.h>
52da14cebeSEric Cheng 
53da14cebeSEric Cheng struct flowlist {
54da000602SGirish Moodalbail 	char		flowname[MAXFLOWNAMELEN];
55c3affd82SMichael Lim 	char		linkname[MAXLINKNAMELEN];
56da14cebeSEric Cheng 	datalink_id_t	linkid;
57c3affd82SMichael Lim 	int		fd;
58285e94f9SMichael Lim 	uint64_t	ifspeed;
59da14cebeSEric Cheng 	boolean_t	first;
60da14cebeSEric Cheng 	boolean_t	display;
61da14cebeSEric Cheng 	pktsum_t 	prevstats;
62da14cebeSEric Cheng 	pktsum_t	diffstats;
63da14cebeSEric Cheng };
64da14cebeSEric Cheng 
65da14cebeSEric Cheng static	int	maxx, maxy, redraw = 0;
66da14cebeSEric Cheng static	volatile uint_t handle_resize = 0, handle_break = 0;
67da14cebeSEric Cheng 
68da14cebeSEric Cheng pktsum_t		totalstats;
69da14cebeSEric Cheng struct flowlist		*stattable = NULL;
70da14cebeSEric Cheng static int		statentry = -1, maxstatentries = 0;
71da14cebeSEric Cheng 
72da14cebeSEric Cheng #define	STATGROWSIZE	16
73da14cebeSEric Cheng 
74da14cebeSEric Cheng /*
75da14cebeSEric Cheng  * Search for flowlist entry in stattable which matches
76*0dc2366fSVenugopal Iyer  * the flowname and linkid.  If no match is found, use
77da14cebeSEric Cheng  * next available slot.  If no slots are available,
78da14cebeSEric Cheng  * reallocate table with  more slots.
79da14cebeSEric Cheng  *
80da14cebeSEric Cheng  * Return: *flowlist of matching flow
81da14cebeSEric Cheng  *         NULL if realloc fails
82da14cebeSEric Cheng  */
83da14cebeSEric Cheng 
84da14cebeSEric Cheng static struct flowlist *
85da14cebeSEric Cheng findstat(const char *flowname, datalink_id_t linkid)
86da14cebeSEric Cheng {
87da14cebeSEric Cheng 	int match = 0;
88da14cebeSEric Cheng 	struct flowlist *flist;
89da14cebeSEric Cheng 
90da14cebeSEric Cheng 	/* Look for match in the stattable */
91da14cebeSEric Cheng 	for (match = 0, flist = stattable;
92da14cebeSEric Cheng 	    match <= statentry;
93da14cebeSEric Cheng 	    match++, flist++) {
94da14cebeSEric Cheng 
95da14cebeSEric Cheng 		if (flist == NULL)
96da14cebeSEric Cheng 			break;
97da14cebeSEric Cheng 		/* match the flowname */
98da14cebeSEric Cheng 		if (flowname != NULL) {
99da000602SGirish Moodalbail 			if (strncmp(flowname, flist->flowname, MAXFLOWNAMELEN)
100da14cebeSEric Cheng 			    == NULL)
101da14cebeSEric Cheng 				return (flist);
102da14cebeSEric Cheng 		/* match the linkid */
103da14cebeSEric Cheng 		} else {
104da14cebeSEric Cheng 			if (linkid == flist->linkid)
105da14cebeSEric Cheng 				return (flist);
106da14cebeSEric Cheng 		}
107da14cebeSEric Cheng 	}
108da14cebeSEric Cheng 
109da14cebeSEric Cheng 	/*
110da14cebeSEric Cheng 	 * No match found in the table.  Store statistics in the next slot.
111da14cebeSEric Cheng 	 * If necessary, make room for this entry.
112da14cebeSEric Cheng 	 */
113da14cebeSEric Cheng 	statentry++;
114da14cebeSEric Cheng 	if ((maxstatentries == 0) || (maxstatentries == statentry)) {
115da14cebeSEric Cheng 		maxstatentries += STATGROWSIZE;
116da14cebeSEric Cheng 		stattable = realloc(stattable,
117da14cebeSEric Cheng 		    maxstatentries * sizeof (struct flowlist));
118da14cebeSEric Cheng 		if (stattable == NULL) {
119da14cebeSEric Cheng 			perror("realloc");
120da14cebeSEric Cheng 			return (struct flowlist *)(NULL);
121da14cebeSEric Cheng 		}
122da14cebeSEric Cheng 	}
123da14cebeSEric Cheng 	flist = &stattable[statentry];
124da14cebeSEric Cheng 	bzero(flist, sizeof (struct flowlist));
125da14cebeSEric Cheng 
126da14cebeSEric Cheng 	if (flowname != NULL)
127da000602SGirish Moodalbail 		(void) strncpy(flist->flowname, flowname, MAXFLOWNAMELEN);
128da14cebeSEric Cheng 	flist->linkid = linkid;
129c3affd82SMichael Lim 	flist->fd = INT32_MAX;
130c3affd82SMichael Lim 
131da14cebeSEric Cheng 	return (flist);
132da14cebeSEric Cheng }
133da14cebeSEric Cheng 
134c3affd82SMichael Lim /*ARGSUSED*/
135da14cebeSEric Cheng static void
1364ac67f02SAnurag S. Maskey print_flow_stats(dladm_handle_t handle, struct flowlist *flist)
137da14cebeSEric Cheng {
138da14cebeSEric Cheng 	struct flowlist *fcurr;
139da14cebeSEric Cheng 	double ikbs, okbs;
140da14cebeSEric Cheng 	double ipks, opks;
141da14cebeSEric Cheng 	double dlt;
142da14cebeSEric Cheng 	int fcount;
143da14cebeSEric Cheng 	static boolean_t first = B_TRUE;
144da14cebeSEric Cheng 
145da14cebeSEric Cheng 	if (first) {
146da14cebeSEric Cheng 		first = B_FALSE;
147da14cebeSEric Cheng 		(void) printw("please wait...\n");
148da14cebeSEric Cheng 		return;
149da14cebeSEric Cheng 	}
150da14cebeSEric Cheng 
151da14cebeSEric Cheng 	for (fcount = 0, fcurr = flist;
152da14cebeSEric Cheng 	    fcount <= statentry;
153da14cebeSEric Cheng 	    fcount++, fcurr++) {
154da14cebeSEric Cheng 		if (fcurr->flowname && fcurr->display) {
155da14cebeSEric Cheng 			dlt = (double)fcurr->diffstats.snaptime/(double)NANOSEC;
156da14cebeSEric Cheng 			ikbs = fcurr->diffstats.rbytes * 8 / dlt / 1024;
157da14cebeSEric Cheng 			okbs = fcurr->diffstats.obytes * 8 / dlt / 1024;
158da14cebeSEric Cheng 			ipks = fcurr->diffstats.ipackets / dlt;
159da14cebeSEric Cheng 			opks = fcurr->diffstats.opackets / dlt;
160da14cebeSEric Cheng 			(void) printw("%-15.15s", fcurr->flowname);
161c3affd82SMichael Lim 			(void) printw("%-10.10s", fcurr->linkname);
162da14cebeSEric Cheng 			(void) printw("%9.2f %9.2f %9.2f %9.2f ",
163da14cebeSEric Cheng 			    ikbs, okbs, ipks, opks);
164da14cebeSEric Cheng 			(void) printw("\n");
165da14cebeSEric Cheng 		}
166da14cebeSEric Cheng 	}
167da14cebeSEric Cheng }
168da14cebeSEric Cheng 
169da14cebeSEric Cheng /*ARGSUSED*/
170da14cebeSEric Cheng static int
171c3affd82SMichael Lim flow_kstats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
172da14cebeSEric Cheng {
173da14cebeSEric Cheng 	kstat_ctl_t 	*kcp = (kstat_ctl_t *)arg;
174da14cebeSEric Cheng 	kstat_t		*ksp;
175da14cebeSEric Cheng 	struct flowlist	*flist;
176da14cebeSEric Cheng 	pktsum_t	currstats, *prevstats, *diffstats;
177da14cebeSEric Cheng 
178da14cebeSEric Cheng 	flist = findstat(attr->fa_flowname, attr->fa_linkid);
179c3affd82SMichael Lim 	if (flist == NULL)
180c3affd82SMichael Lim 		return (DLADM_WALK_CONTINUE);
181c3affd82SMichael Lim 
182c3affd82SMichael Lim 	flist->display = B_FALSE;
183c3affd82SMichael Lim 	prevstats = &flist->prevstats;
184c3affd82SMichael Lim 	diffstats = &flist->diffstats;
185c3affd82SMichael Lim 
186c3affd82SMichael Lim 	(void) dladm_datalink_id2info(handle, attr->fa_linkid, NULL, NULL,
187c3affd82SMichael Lim 	    NULL, flist->linkname, sizeof (flist->linkname));
188c3affd82SMichael Lim 
189da14cebeSEric Cheng 
190da14cebeSEric Cheng 	/* lookup kstat entry */
191da14cebeSEric Cheng 	ksp = dladm_kstat_lookup(kcp, NULL, -1, attr->fa_flowname, "flow");
192da14cebeSEric Cheng 
193da14cebeSEric Cheng 	if (ksp == NULL)
194c3affd82SMichael Lim 		return (DLADM_WALK_CONTINUE);
195da14cebeSEric Cheng 
196c3affd82SMichael Lim 	/* read packet and byte stats */
197da14cebeSEric Cheng 	dladm_get_stats(kcp, ksp, &currstats);
198c3affd82SMichael Lim 
199da14cebeSEric Cheng 	if (flist->ifspeed == 0)
200da14cebeSEric Cheng 		(void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64,
201da14cebeSEric Cheng 		    &flist->ifspeed);
202da14cebeSEric Cheng 
203c3affd82SMichael Lim 	if (flist->first) {
204da14cebeSEric Cheng 		flist->first = B_FALSE;
205c3affd82SMichael Lim 	} else {
206da14cebeSEric Cheng 		dladm_stats_diff(diffstats, &currstats, prevstats);
207c3affd82SMichael Lim 		if (diffstats->snaptime == 0)
208c3affd82SMichael Lim 			return (DLADM_WALK_CONTINUE);
209da14cebeSEric Cheng 		dladm_stats_total(&totalstats, diffstats, &totalstats);
210da14cebeSEric Cheng 	}
211da14cebeSEric Cheng 
212da14cebeSEric Cheng 	bcopy(&currstats, prevstats, sizeof (pktsum_t));
213c3affd82SMichael Lim 	flist->display = B_TRUE;
214c3affd82SMichael Lim 
215da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
216da14cebeSEric Cheng }
217da14cebeSEric Cheng 
218c3affd82SMichael Lim /*ARGSUSED*/
219da14cebeSEric Cheng static void
2204ac67f02SAnurag S. Maskey print_link_stats(dladm_handle_t handle, struct flowlist *flist)
221da14cebeSEric Cheng {
222da14cebeSEric Cheng 	struct flowlist *fcurr;
223da14cebeSEric Cheng 	double ikbs, okbs;
224da14cebeSEric Cheng 	double ipks, opks;
225da14cebeSEric Cheng 	double util;
226da14cebeSEric Cheng 	double dlt;
227da14cebeSEric Cheng 	int fcount;
228da14cebeSEric Cheng 	static boolean_t first = B_TRUE;
229da14cebeSEric Cheng 
230da14cebeSEric Cheng 	if (first) {
231da14cebeSEric Cheng 		first = B_FALSE;
232da14cebeSEric Cheng 		(void) printw("please wait...\n");
233da14cebeSEric Cheng 		return;
234da14cebeSEric Cheng 	}
235da14cebeSEric Cheng 
236da14cebeSEric Cheng 	for (fcount = 0, fcurr = flist;
237da14cebeSEric Cheng 	    fcount <= statentry;
238da14cebeSEric Cheng 	    fcount++, fcurr++) {
239da14cebeSEric Cheng 		if ((fcurr->linkid != DATALINK_INVALID_LINKID) &&
240da14cebeSEric Cheng 		    fcurr->display)  {
241da14cebeSEric Cheng 			dlt = (double)fcurr->diffstats.snaptime/(double)NANOSEC;
242da14cebeSEric Cheng 			ikbs = (double)fcurr->diffstats.rbytes * 8 / dlt / 1024;
243da14cebeSEric Cheng 			okbs = (double)fcurr->diffstats.obytes * 8 / dlt / 1024;
244da14cebeSEric Cheng 			ipks = (double)fcurr->diffstats.ipackets / dlt;
245da14cebeSEric Cheng 			opks = (double)fcurr->diffstats.opackets / dlt;
246c3affd82SMichael Lim 			(void) printw("%-10.10s", fcurr->linkname);
247da14cebeSEric Cheng 			(void) printw("%9.2f %9.2f %9.2f %9.2f ",
248da14cebeSEric Cheng 			    ikbs, okbs, ipks, opks);
249da14cebeSEric Cheng 			if (fcurr->ifspeed != 0)
250da14cebeSEric Cheng 				util = ((ikbs + okbs) * 1024) *
251da14cebeSEric Cheng 				    100/ fcurr->ifspeed;
252da14cebeSEric Cheng 			else
253da14cebeSEric Cheng 				util = (double)0;
254da14cebeSEric Cheng 			(void) attron(A_BOLD);
255da14cebeSEric Cheng 			(void) printw("    %6.2f", util);
256da14cebeSEric Cheng 			(void) attroff(A_BOLD);
257da14cebeSEric Cheng 			(void) printw("\n");
258da14cebeSEric Cheng 		}
259da14cebeSEric Cheng 	}
260da14cebeSEric Cheng }
261da14cebeSEric Cheng 
262da14cebeSEric Cheng /*
263da14cebeSEric Cheng  * This function is called through the dladm_walk_datalink_id() walker and
264da14cebeSEric Cheng  * calls the dladm_walk_flow() walker.
265da14cebeSEric Cheng  */
266da14cebeSEric Cheng 
267da14cebeSEric Cheng /*ARGSUSED*/
268da14cebeSEric Cheng static int
2694ac67f02SAnurag S. Maskey link_flowstats(dladm_handle_t handle, datalink_id_t linkid, void *arg)
270da14cebeSEric Cheng {
271ad091ee1SMichael Lim 	dladm_status_t	status;
272ad091ee1SMichael Lim 
273ad091ee1SMichael Lim 	status = dladm_walk_flow(flow_kstats, handle, linkid, arg, B_FALSE);
274ad091ee1SMichael Lim 	if (status == DLADM_STATUS_OK)
275ad091ee1SMichael Lim 		return (DLADM_WALK_CONTINUE);
276ad091ee1SMichael Lim 	else
277ad091ee1SMichael Lim 		return (DLADM_WALK_TERMINATE);
278da14cebeSEric Cheng }
279da14cebeSEric Cheng 
280da14cebeSEric Cheng /*ARGSUSED*/
281da14cebeSEric Cheng static int
2824ac67f02SAnurag S. Maskey link_kstats(dladm_handle_t handle, datalink_id_t linkid, void *arg)
283da14cebeSEric Cheng {
284c3affd82SMichael Lim 	kstat_ctl_t		*kcp = (kstat_ctl_t *)arg;
285c3affd82SMichael Lim 	struct flowlist		*flist;
286c3affd82SMichael Lim 	pktsum_t		currstats, *prevstats, *diffstats;
287c3affd82SMichael Lim 	datalink_class_t	class;
288c3affd82SMichael Lim 	kstat_t			*ksp;
289c3affd82SMichael Lim 	char			dnlink[MAXPATHLEN];
290da14cebeSEric Cheng 
291da14cebeSEric Cheng 	/* find the flist entry */
292da14cebeSEric Cheng 	flist = findstat(NULL, linkid);
293c3affd82SMichael Lim 	flist->display = B_FALSE;
294da14cebeSEric Cheng 	if (flist != NULL) {
295da14cebeSEric Cheng 		prevstats = &flist->prevstats;
296da14cebeSEric Cheng 		diffstats = &flist->diffstats;
297da14cebeSEric Cheng 	} else {
298da14cebeSEric Cheng 		return (DLADM_WALK_CONTINUE);
299da14cebeSEric Cheng 	}
300da14cebeSEric Cheng 
301c3affd82SMichael Lim 	if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
302c3affd82SMichael Lim 	    flist->linkname, sizeof (flist->linkname)) != DLADM_STATUS_OK)
303c3affd82SMichael Lim 		return (DLADM_WALK_CONTINUE);
304da14cebeSEric Cheng 
305c3affd82SMichael Lim 	if (flist->fd == INT32_MAX) {
306c3affd82SMichael Lim 		if (class == DATALINK_CLASS_PHYS) {
307c3affd82SMichael Lim 			(void) snprintf(dnlink, MAXPATHLEN, "/dev/net/%s",
308c3affd82SMichael Lim 			    flist->linkname);
309c3affd82SMichael Lim 			if ((flist->fd = open(dnlink, O_RDWR)) < 0)
310c3affd82SMichael Lim 				return (DLADM_WALK_CONTINUE);
311c3affd82SMichael Lim 		} else {
312c3affd82SMichael Lim 			flist->fd = -1;
313c3affd82SMichael Lim 		}
314c3affd82SMichael Lim 		(void) kstat_chain_update(kcp);
315da14cebeSEric Cheng 	}
316da14cebeSEric Cheng 
317c3affd82SMichael Lim 	/* lookup kstat entry */
318c3affd82SMichael Lim 	ksp = dladm_kstat_lookup(kcp, NULL, -1, flist->linkname, "net");
319da14cebeSEric Cheng 
320da14cebeSEric Cheng 	if (ksp == NULL)
321c3affd82SMichael Lim 		return (DLADM_WALK_CONTINUE);
322da14cebeSEric Cheng 
323da14cebeSEric Cheng 	/* read packet and byte stats */
324da14cebeSEric Cheng 	dladm_get_stats(kcp, ksp, &currstats);
325da14cebeSEric Cheng 
326da14cebeSEric Cheng 	if (flist->ifspeed == 0)
327da14cebeSEric Cheng 		(void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64,
328da14cebeSEric Cheng 		    &flist->ifspeed);
329da14cebeSEric Cheng 
330c3affd82SMichael Lim 	if (flist->first) {
331da14cebeSEric Cheng 		flist->first = B_FALSE;
332c3affd82SMichael Lim 	} else {
333da14cebeSEric Cheng 		dladm_stats_diff(diffstats, &currstats, prevstats);
334c3affd82SMichael Lim 		if (diffstats->snaptime == 0)
335c3affd82SMichael Lim 			return (DLADM_WALK_CONTINUE);
336c3affd82SMichael Lim 	}
337da14cebeSEric Cheng 
338da14cebeSEric Cheng 	bcopy(&currstats, prevstats, sizeof (*prevstats));
339c3affd82SMichael Lim 	flist->display = B_TRUE;
340da14cebeSEric Cheng 
341da14cebeSEric Cheng 	return (DLADM_WALK_CONTINUE);
342da14cebeSEric Cheng }
343da14cebeSEric Cheng 
344c3affd82SMichael Lim static void
345c3affd82SMichael Lim closedevnet()
346c3affd82SMichael Lim {
347c3affd82SMichael Lim 	int index = 0;
348c3affd82SMichael Lim 	struct flowlist *flist;
349c3affd82SMichael Lim 
350c3affd82SMichael Lim 	/* Close all open /dev/net/ files */
351*0dc2366fSVenugopal Iyer 
352*0dc2366fSVenugopal Iyer 	for (flist = stattable; index < maxstatentries; index++, flist++) {
353c3affd82SMichael Lim 		if (flist->linkid == DATALINK_INVALID_LINKID)
354c3affd82SMichael Lim 			break;
355c3affd82SMichael Lim 		if (flist->fd != -1 && flist->fd != INT32_MAX)
356c3affd82SMichael Lim 			(void) close(flist->fd);
357c3affd82SMichael Lim 	}
358c3affd82SMichael Lim }
359c3affd82SMichael Lim 
360da14cebeSEric Cheng /*ARGSUSED*/
361da14cebeSEric Cheng static void
362da14cebeSEric Cheng sig_break(int s)
363da14cebeSEric Cheng {
364da14cebeSEric Cheng 	handle_break = 1;
365da14cebeSEric Cheng }
366da14cebeSEric Cheng 
367da14cebeSEric Cheng /*ARGSUSED*/
368da14cebeSEric Cheng static void
369da14cebeSEric Cheng sig_resize(int s)
370da14cebeSEric Cheng {
371da14cebeSEric Cheng 	handle_resize = 1;
372da14cebeSEric Cheng }
373da14cebeSEric Cheng 
374da14cebeSEric Cheng static void
375da14cebeSEric Cheng curses_init()
376da14cebeSEric Cheng {
377da14cebeSEric Cheng 	maxx = maxx;	/* lint */
378da14cebeSEric Cheng 	maxy = maxy;	/* lint */
379da14cebeSEric Cheng 
380da14cebeSEric Cheng 	/* Install signal handlers */
381da14cebeSEric Cheng 	(void) signal(SIGINT,  sig_break);
382da14cebeSEric Cheng 	(void) signal(SIGQUIT, sig_break);
383da14cebeSEric Cheng 	(void) signal(SIGTERM, sig_break);
384da14cebeSEric Cheng 	(void) signal(SIGWINCH, sig_resize);
385da14cebeSEric Cheng 
386da14cebeSEric Cheng 	/* Initialize ncurses */
387da14cebeSEric Cheng 	(void) initscr();
388da14cebeSEric Cheng 	(void) cbreak();
389da14cebeSEric Cheng 	(void) noecho();
390da14cebeSEric Cheng 	(void) curs_set(0);
391da14cebeSEric Cheng 	timeout(0);
392da14cebeSEric Cheng 	getmaxyx(stdscr, maxy, maxx);
393da14cebeSEric Cheng }
394da14cebeSEric Cheng 
395da14cebeSEric Cheng static void
396da14cebeSEric Cheng curses_fin()
397da14cebeSEric Cheng {
398da14cebeSEric Cheng 	(void) printw("\n");
399da14cebeSEric Cheng 	(void) curs_set(1);
400da14cebeSEric Cheng 	(void) nocbreak();
401da14cebeSEric Cheng 	(void) endwin();
402da14cebeSEric Cheng 
403da14cebeSEric Cheng 	free(stattable);
404da14cebeSEric Cheng }
405da14cebeSEric Cheng 
406da14cebeSEric Cheng static void
4074ac67f02SAnurag S. Maskey stat_report(dladm_handle_t handle, kstat_ctl_t *kcp,  datalink_id_t linkid,
4084ac67f02SAnurag S. Maskey     const char *flowname, int opt)
409da14cebeSEric Cheng {
410da14cebeSEric Cheng 
411da14cebeSEric Cheng 	double dlt, ikbs, okbs, ipks, opks;
412da14cebeSEric Cheng 
413da14cebeSEric Cheng 	struct flowlist *fstable = stattable;
414da14cebeSEric Cheng 
415da14cebeSEric Cheng 	if ((opt != LINK_REPORT) && (opt != FLOW_REPORT))
416da14cebeSEric Cheng 		return;
417da14cebeSEric Cheng 
418da14cebeSEric Cheng 	/* Handle window resizes */
419da14cebeSEric Cheng 	if (handle_resize) {
420da14cebeSEric Cheng 		(void) endwin();
421da14cebeSEric Cheng 		(void) initscr();
422da14cebeSEric Cheng 		(void) cbreak();
423da14cebeSEric Cheng 		(void) noecho();
424da14cebeSEric Cheng 		(void) curs_set(0);
425da14cebeSEric Cheng 		timeout(0);
426da14cebeSEric Cheng 		getmaxyx(stdscr, maxy, maxx);
427da14cebeSEric Cheng 		redraw = 1;
428da14cebeSEric Cheng 		handle_resize = 0;
429da14cebeSEric Cheng 	}
430da14cebeSEric Cheng 
431da14cebeSEric Cheng 	/* Print title */
432da14cebeSEric Cheng 	(void) erase();
433da14cebeSEric Cheng 	(void) attron(A_BOLD);
434da14cebeSEric Cheng 	(void) move(0, 0);
435da14cebeSEric Cheng 	if (opt == FLOW_REPORT)
436da14cebeSEric Cheng 		(void) printw("%-15.15s", "Flow");
437da14cebeSEric Cheng 	(void) printw("%-10.10s", "Link");
438da14cebeSEric Cheng 	(void) printw("%9.9s %9.9s %9.9s %9.9s ",
439da14cebeSEric Cheng 	    "iKb/s", "oKb/s", "iPk/s", "oPk/s");
440da14cebeSEric Cheng 	if (opt == LINK_REPORT)
441da14cebeSEric Cheng 		(void) printw("    %6.6s", "%Util");
442da14cebeSEric Cheng 	(void) printw("\n");
443da14cebeSEric Cheng 	(void) attroff(A_BOLD);
444da14cebeSEric Cheng 
445da14cebeSEric Cheng 	(void) move(2, 0);
446da14cebeSEric Cheng 
447da14cebeSEric Cheng 	/* Print stats for each link or flow */
448da14cebeSEric Cheng 	bzero(&totalstats, sizeof (totalstats));
449da14cebeSEric Cheng 	if (opt == LINK_REPORT) {
450da14cebeSEric Cheng 		/* Display all links */
451da14cebeSEric Cheng 		if (linkid == DATALINK_ALL_LINKID) {
4524ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(link_kstats, handle,
453da14cebeSEric Cheng 			    (void *)kcp, DATALINK_CLASS_ALL,
454da14cebeSEric Cheng 			    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
455da14cebeSEric Cheng 		/* Display 1 link */
456da14cebeSEric Cheng 		} else {
4574ac67f02SAnurag S. Maskey 			(void) link_kstats(handle, linkid, kcp);
458da14cebeSEric Cheng 		}
4594ac67f02SAnurag S. Maskey 		print_link_stats(handle, fstable);
460da14cebeSEric Cheng 
461da14cebeSEric Cheng 	} else if (opt == FLOW_REPORT) {
462da14cebeSEric Cheng 		/* Display 1 flow */
463da14cebeSEric Cheng 		if (flowname != NULL) {
464da14cebeSEric Cheng 			dladm_flow_attr_t fattr;
4654ac67f02SAnurag S. Maskey 			if (dladm_flow_info(handle, flowname, &fattr) !=
466da14cebeSEric Cheng 			    DLADM_STATUS_OK)
467da14cebeSEric Cheng 				return;
468c3affd82SMichael Lim 			(void) flow_kstats(handle, &fattr, kcp);
469da14cebeSEric Cheng 		/* Display all flows on all links */
470da14cebeSEric Cheng 		} else if (linkid == DATALINK_ALL_LINKID) {
4714ac67f02SAnurag S. Maskey 			(void) dladm_walk_datalink_id(link_flowstats, handle,
472da14cebeSEric Cheng 			    (void *)kcp, DATALINK_CLASS_ALL,
473da14cebeSEric Cheng 			    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
474da14cebeSEric Cheng 		/* Display all flows on a link */
475da14cebeSEric Cheng 		} else if (linkid != DATALINK_INVALID_LINKID) {
4764ac67f02SAnurag S. Maskey 			(void) dladm_walk_flow(flow_kstats, handle, linkid, kcp,
477da14cebeSEric Cheng 			    B_FALSE);
478da14cebeSEric Cheng 		}
4794ac67f02SAnurag S. Maskey 		print_flow_stats(handle, fstable);
480da14cebeSEric Cheng 
481da14cebeSEric Cheng 		/* Print totals */
482da14cebeSEric Cheng 		(void) attron(A_BOLD);
483da14cebeSEric Cheng 		dlt = (double)totalstats.snaptime / (double)NANOSEC;
484da14cebeSEric Cheng 		ikbs = totalstats.rbytes / dlt / 1024;
485da14cebeSEric Cheng 		okbs = totalstats.obytes / dlt / 1024;
486da14cebeSEric Cheng 		ipks = totalstats.ipackets / dlt;
487da14cebeSEric Cheng 		opks = totalstats.opackets / dlt;
488da14cebeSEric Cheng 		(void) printw("\n%-25.25s", "Totals");
489da14cebeSEric Cheng 		(void) printw("%9.2f %9.2f %9.2f %9.2f ",
490da14cebeSEric Cheng 		    ikbs, okbs, ipks, opks);
491da14cebeSEric Cheng 		(void) attroff(A_BOLD);
492da14cebeSEric Cheng 	}
493da14cebeSEric Cheng 
494da14cebeSEric Cheng 	if (redraw)
495da14cebeSEric Cheng 		(void) clearok(stdscr, 1);
496da14cebeSEric Cheng 
497da14cebeSEric Cheng 	if (refresh() == ERR)
498da14cebeSEric Cheng 		return;
499da14cebeSEric Cheng 
500da14cebeSEric Cheng 	if (redraw) {
501da14cebeSEric Cheng 		(void) clearok(stdscr, 0);
502da14cebeSEric Cheng 		redraw = 0;
503da14cebeSEric Cheng 	}
504da14cebeSEric Cheng }
505da14cebeSEric Cheng 
506da14cebeSEric Cheng /* Exported functions */
507da14cebeSEric Cheng 
508da14cebeSEric Cheng /*
509da14cebeSEric Cheng  * Continuously display link or flow statstics using a libcurses
510da14cebeSEric Cheng  * based display.
511da14cebeSEric Cheng  */
512da14cebeSEric Cheng 
513da14cebeSEric Cheng void
5144ac67f02SAnurag S. Maskey dladm_continuous(dladm_handle_t handle, datalink_id_t linkid,
5154ac67f02SAnurag S. Maskey     const char *flowname, int interval, int opt)
516da14cebeSEric Cheng {
517da14cebeSEric Cheng 	kstat_ctl_t *kcp;
518da14cebeSEric Cheng 
519da14cebeSEric Cheng 	if ((kcp = kstat_open()) == NULL) {
520da14cebeSEric Cheng 		warn("kstat open operation failed");
521da14cebeSEric Cheng 		return;
522da14cebeSEric Cheng 	}
523da14cebeSEric Cheng 
524da14cebeSEric Cheng 	curses_init();
525da14cebeSEric Cheng 
526da14cebeSEric Cheng 	for (;;) {
527da14cebeSEric Cheng 
528da14cebeSEric Cheng 		if (handle_break)
529da14cebeSEric Cheng 			break;
530da14cebeSEric Cheng 
5314ac67f02SAnurag S. Maskey 		stat_report(handle, kcp, linkid, flowname, opt);
532da14cebeSEric Cheng 
533da14cebeSEric Cheng 		(void) sleep(max(1, interval));
534da14cebeSEric Cheng 	}
535da14cebeSEric Cheng 
536c3affd82SMichael Lim 	closedevnet();
537c3affd82SMichael Lim 	curses_fin();
538da14cebeSEric Cheng 	(void) kstat_close(kcp);
539da14cebeSEric Cheng }
540da14cebeSEric Cheng 
541da14cebeSEric Cheng /*
542da14cebeSEric Cheng  * dladm_kstat_lookup() is a modified version of kstat_lookup which
543da14cebeSEric Cheng  * adds the class as a selector.
544da14cebeSEric Cheng  */
545da14cebeSEric Cheng 
546da14cebeSEric Cheng kstat_t *
547da14cebeSEric Cheng dladm_kstat_lookup(kstat_ctl_t *kcp, const char *module, int instance,
548da14cebeSEric Cheng     const char *name, const char *class)
549da14cebeSEric Cheng {
550da14cebeSEric Cheng 	kstat_t *ksp = NULL;
551da14cebeSEric Cheng 
552da14cebeSEric Cheng 	for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
553da14cebeSEric Cheng 		if ((module == NULL || strcmp(ksp->ks_module, module) == 0) &&
554da14cebeSEric Cheng 		    (instance == -1 || ksp->ks_instance == instance) &&
555da14cebeSEric Cheng 		    (name == NULL || strcmp(ksp->ks_name, name) == 0) &&
556da14cebeSEric Cheng 		    (class == NULL || strcmp(ksp->ks_class, class) == 0))
557da14cebeSEric Cheng 			return (ksp);
558da14cebeSEric Cheng 	}
559da14cebeSEric Cheng 
560da14cebeSEric Cheng 	errno = ENOENT;
561da14cebeSEric Cheng 	return (NULL);
562da14cebeSEric Cheng }
563da14cebeSEric Cheng 
564da14cebeSEric Cheng /*
565da14cebeSEric Cheng  * dladm_get_stats() populates the supplied pktsum_t structure with
566da14cebeSEric Cheng  * the input and output  packet and byte kstats from the kstat_t
567da14cebeSEric Cheng  * found with dladm_kstat_lookup.
568da14cebeSEric Cheng  */
569da14cebeSEric Cheng void
570da14cebeSEric Cheng dladm_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, pktsum_t *stats)
571da14cebeSEric Cheng {
572da14cebeSEric Cheng 
573da14cebeSEric Cheng 	if (kstat_read(kcp, ksp, NULL) == -1)
574da14cebeSEric Cheng 		return;
575da14cebeSEric Cheng 
576da14cebeSEric Cheng 	stats->snaptime = gethrtime();
577da14cebeSEric Cheng 
578da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64,
579da14cebeSEric Cheng 	    &stats->ipackets) < 0) {
580da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "ipackets", KSTAT_DATA_UINT64,
581da14cebeSEric Cheng 		    &stats->ipackets) < 0)
582da14cebeSEric Cheng 			return;
583da14cebeSEric Cheng 	}
584da14cebeSEric Cheng 
585da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64,
586da14cebeSEric Cheng 	    &stats->opackets) < 0) {
587da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "opackets", KSTAT_DATA_UINT64,
588da14cebeSEric Cheng 		    &stats->opackets) < 0)
589da14cebeSEric Cheng 			return;
590da14cebeSEric Cheng 	}
591da14cebeSEric Cheng 
592da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64,
593da14cebeSEric Cheng 	    &stats->rbytes) < 0) {
594da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "rbytes", KSTAT_DATA_UINT64,
595da14cebeSEric Cheng 		    &stats->rbytes) < 0)
596da14cebeSEric Cheng 			return;
597da14cebeSEric Cheng 	}
598da14cebeSEric Cheng 
599da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64,
600da14cebeSEric Cheng 	    &stats->obytes) < 0) {
601da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "obytes", KSTAT_DATA_UINT64,
602da14cebeSEric Cheng 		    &stats->obytes) < 0)
603da14cebeSEric Cheng 			return;
604da14cebeSEric Cheng 	}
605da14cebeSEric Cheng 
606da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32,
607da14cebeSEric Cheng 	    &stats->ierrors) < 0) {
608da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT64,
609da14cebeSEric Cheng 		    &stats->ierrors) < 0)
610da14cebeSEric Cheng 		return;
611da14cebeSEric Cheng 	}
612da14cebeSEric Cheng 
613da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32,
614da14cebeSEric Cheng 	    &stats->oerrors) < 0) {
615da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT64,
616da14cebeSEric Cheng 		    &stats->oerrors) < 0)
617da14cebeSEric Cheng 			return;
618da14cebeSEric Cheng 	}
619da14cebeSEric Cheng }
620da14cebeSEric Cheng 
621da14cebeSEric Cheng int
622da14cebeSEric Cheng dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf)
623da14cebeSEric Cheng {
624da14cebeSEric Cheng 	kstat_named_t	*knp;
625da14cebeSEric Cheng 
626da14cebeSEric Cheng 	if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL)
627da14cebeSEric Cheng 		return (-1);
628da14cebeSEric Cheng 
629da14cebeSEric Cheng 	if (knp->data_type != type)
630da14cebeSEric Cheng 		return (-1);
631da14cebeSEric Cheng 
632da14cebeSEric Cheng 	switch (type) {
633da14cebeSEric Cheng 	case KSTAT_DATA_UINT64:
634da14cebeSEric Cheng 		*(uint64_t *)buf = knp->value.ui64;
635da14cebeSEric Cheng 		break;
636da14cebeSEric Cheng 	case KSTAT_DATA_UINT32:
637da14cebeSEric Cheng 		*(uint32_t *)buf = knp->value.ui32;
638da14cebeSEric Cheng 		break;
639da14cebeSEric Cheng 	default:
640da14cebeSEric Cheng 		return (-1);
641da14cebeSEric Cheng 	}
642da14cebeSEric Cheng 
643da14cebeSEric Cheng 	return (0);
644da14cebeSEric Cheng }
645da14cebeSEric Cheng 
646da14cebeSEric Cheng dladm_status_t
6474ac67f02SAnurag S. Maskey dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid,
6484ac67f02SAnurag S. Maskey     const char *name, uint8_t type, void *val)
649da14cebeSEric Cheng {
650da14cebeSEric Cheng 	kstat_ctl_t	*kcp;
651da14cebeSEric Cheng 	char		module[DLPI_LINKNAME_MAX];
652da14cebeSEric Cheng 	uint_t		instance;
653da14cebeSEric Cheng 	char 		link[DLPI_LINKNAME_MAX];
654da14cebeSEric Cheng 	dladm_status_t	status;
655da14cebeSEric Cheng 	uint32_t	flags, media;
656da14cebeSEric Cheng 	kstat_t		*ksp;
657da14cebeSEric Cheng 	dladm_phys_attr_t dpap;
658da14cebeSEric Cheng 
6594ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
6604ac67f02SAnurag S. Maskey 	    &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK)
661da14cebeSEric Cheng 		return (status);
662da14cebeSEric Cheng 
663da14cebeSEric Cheng 	if (media != DL_ETHER)
664da14cebeSEric Cheng 		return (DLADM_STATUS_LINKINVAL);
665da14cebeSEric Cheng 
6664ac67f02SAnurag S. Maskey 	status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST);
667da14cebeSEric Cheng 
668da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
669da14cebeSEric Cheng 		return (status);
670da14cebeSEric Cheng 
671da14cebeSEric Cheng 	status = dladm_parselink(dpap.dp_dev, module, &instance);
672da14cebeSEric Cheng 
673da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
674da14cebeSEric Cheng 		return (status);
675da14cebeSEric Cheng 
6763efde6d0SSowmini Varadhan 	if ((kcp = kstat_open()) == NULL) {
6773efde6d0SSowmini Varadhan 		warn("kstat_open operation failed");
6783efde6d0SSowmini Varadhan 		return (-1);
6793efde6d0SSowmini Varadhan 	}
6803efde6d0SSowmini Varadhan 
681da14cebeSEric Cheng 	/*
682da14cebeSEric Cheng 	 * The kstat query could fail if the underlying MAC
683da14cebeSEric Cheng 	 * driver was already detached.
684da14cebeSEric Cheng 	 */
685da14cebeSEric Cheng 	if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL &&
686da14cebeSEric Cheng 	    (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL)
687da14cebeSEric Cheng 		goto bail;
688da14cebeSEric Cheng 
689da14cebeSEric Cheng 	if (kstat_read(kcp, ksp, NULL) == -1)
690da14cebeSEric Cheng 		goto bail;
691da14cebeSEric Cheng 
692da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, name, type, val) < 0)
693da14cebeSEric Cheng 		goto bail;
694da14cebeSEric Cheng 
695da14cebeSEric Cheng 	(void) kstat_close(kcp);
696da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
697da14cebeSEric Cheng 
698da14cebeSEric Cheng bail:
699da14cebeSEric Cheng 	(void) kstat_close(kcp);
700da14cebeSEric Cheng 	return (dladm_errno2status(errno));
701da14cebeSEric Cheng }
702da14cebeSEric Cheng 
703da14cebeSEric Cheng /* Compute sum of 2 pktsums (s1 = s2 + s3) */
704da14cebeSEric Cheng void
705da14cebeSEric Cheng dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
706da14cebeSEric Cheng {
707da14cebeSEric Cheng 	s1->rbytes    = s2->rbytes    + s3->rbytes;
708da14cebeSEric Cheng 	s1->ipackets  = s2->ipackets  + s3->ipackets;
709da14cebeSEric Cheng 	s1->ierrors   = s2->ierrors   + s3->ierrors;
710da14cebeSEric Cheng 	s1->obytes    = s2->obytes    + s3->obytes;
711da14cebeSEric Cheng 	s1->opackets  = s2->opackets  + s3->opackets;
712da14cebeSEric Cheng 	s1->oerrors   = s2->oerrors   + s3->oerrors;
713da14cebeSEric Cheng 	s1->snaptime  = s2->snaptime;
714da14cebeSEric Cheng }
715da14cebeSEric Cheng 
716*0dc2366fSVenugopal Iyer #define	DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0)
7172d40c3b2SPrakash Jalan 
7182d40c3b2SPrakash Jalan 
719da14cebeSEric Cheng /* Compute differences between 2 pktsums (s1 = s2 - s3) */
720da14cebeSEric Cheng void
721da14cebeSEric Cheng dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
722da14cebeSEric Cheng {
7232d40c3b2SPrakash Jalan 	s1->rbytes    = DIFF_STAT(s2->rbytes,   s3->rbytes);
7242d40c3b2SPrakash Jalan 	s1->ipackets  = DIFF_STAT(s2->ipackets, s3->ipackets);
7252d40c3b2SPrakash Jalan 	s1->ierrors   = DIFF_STAT(s2->ierrors,  s3->ierrors);
7262d40c3b2SPrakash Jalan 	s1->obytes    = DIFF_STAT(s2->obytes,   s3->obytes);
7272d40c3b2SPrakash Jalan 	s1->opackets  = DIFF_STAT(s2->opackets, s3->opackets);
7282d40c3b2SPrakash Jalan 	s1->oerrors   = DIFF_STAT(s2->oerrors,  s3->oerrors);
7292d40c3b2SPrakash Jalan 	s1->snaptime  = DIFF_STAT(s2->snaptime, s3->snaptime);
730da14cebeSEric Cheng }
731*0dc2366fSVenugopal Iyer 
732*0dc2366fSVenugopal Iyer #define	DLSTAT_MAC_RX_SWLANE	"mac_rx_swlane"
733*0dc2366fSVenugopal Iyer #define	DLSTAT_MAC_RX_HWLANE	"mac_rx_hwlane"
734*0dc2366fSVenugopal Iyer #define	DLSTAT_MAC_TX_SWLANE	"mac_tx_swlane"
735*0dc2366fSVenugopal Iyer #define	DLSTAT_MAC_TX_HWLANE	"mac_tx_hwlane"
736*0dc2366fSVenugopal Iyer #define	DLSTAT_MAC_MISC_STAT	"mac_misc_stat"
737*0dc2366fSVenugopal Iyer #define	DLSTAT_MAC_RX_RING	"mac_rx_ring"
738*0dc2366fSVenugopal Iyer #define	DLSTAT_MAC_TX_RING	"mac_tx_ring"
739*0dc2366fSVenugopal Iyer #define	DLSTAT_MAC_FANOUT	"mac_rx_swlane0_fanout"
740*0dc2366fSVenugopal Iyer 
741*0dc2366fSVenugopal Iyer typedef struct {
742*0dc2366fSVenugopal Iyer 	const char	*si_name;
743*0dc2366fSVenugopal Iyer 	uint_t		si_offset;
744*0dc2366fSVenugopal Iyer } stat_info_t;
745*0dc2366fSVenugopal Iyer 
746*0dc2366fSVenugopal Iyer #define	A_CNT(arr)	(sizeof (arr) / sizeof (arr[0]))
747*0dc2366fSVenugopal Iyer 
748*0dc2366fSVenugopal Iyer /* Definitions for rx lane stats */
749*0dc2366fSVenugopal Iyer #define	RL_OFF(f)	(offsetof(rx_lane_stat_t, f))
750*0dc2366fSVenugopal Iyer 
751*0dc2366fSVenugopal Iyer static	stat_info_t	rx_hwlane_stats_list[] = {
752*0dc2366fSVenugopal Iyer 	{"ipackets",		RL_OFF(rl_ipackets)},
753*0dc2366fSVenugopal Iyer 	{"rbytes",		RL_OFF(rl_rbytes)},
754*0dc2366fSVenugopal Iyer 	{"intrs",		RL_OFF(rl_intrs)},
755*0dc2366fSVenugopal Iyer 	{"intrbytes",		RL_OFF(rl_intrbytes)},
756*0dc2366fSVenugopal Iyer 	{"polls",		RL_OFF(rl_polls)},
757*0dc2366fSVenugopal Iyer 	{"pollbytes",		RL_OFF(rl_pollbytes)},
758*0dc2366fSVenugopal Iyer 	{"rxsdrops",		RL_OFF(rl_sdrops)},
759*0dc2366fSVenugopal Iyer 	{"chainunder10",	RL_OFF(rl_chl10)},
760*0dc2366fSVenugopal Iyer 	{"chain10to50", 	RL_OFF(rl_ch10_50)},
761*0dc2366fSVenugopal Iyer 	{"chainover50", 	RL_OFF(rl_chg50)}
762*0dc2366fSVenugopal Iyer };
763*0dc2366fSVenugopal Iyer #define	RX_HWLANE_STAT_SIZE	A_CNT(rx_hwlane_stats_list)
764*0dc2366fSVenugopal Iyer 
765*0dc2366fSVenugopal Iyer static	stat_info_t	rx_swlane_stats_list[] = {
766*0dc2366fSVenugopal Iyer 	{"ipackets",		RL_OFF(rl_ipackets)},
767*0dc2366fSVenugopal Iyer 	{"rbytes",		RL_OFF(rl_rbytes)},
768*0dc2366fSVenugopal Iyer 	{"local",		RL_OFF(rl_lclpackets)},
769*0dc2366fSVenugopal Iyer 	{"localbytes",		RL_OFF(rl_lclbytes)},
770*0dc2366fSVenugopal Iyer 	{"intrs",		RL_OFF(rl_intrs)},
771*0dc2366fSVenugopal Iyer 	{"intrbytes",		RL_OFF(rl_intrbytes)},
772*0dc2366fSVenugopal Iyer 	{"rxsdrops",		RL_OFF(rl_sdrops)}
773*0dc2366fSVenugopal Iyer };
774*0dc2366fSVenugopal Iyer #define	RX_SWLANE_STAT_SIZE	A_CNT(rx_swlane_stats_list)
775*0dc2366fSVenugopal Iyer 
776*0dc2366fSVenugopal Iyer static	stat_info_t	rx_lane_stats_list[] = {
777*0dc2366fSVenugopal Iyer 	{"ipackets",		RL_OFF(rl_ipackets)},
778*0dc2366fSVenugopal Iyer 	{"rbytes",		RL_OFF(rl_rbytes)},
779*0dc2366fSVenugopal Iyer 	{"local",		RL_OFF(rl_lclpackets)},
780*0dc2366fSVenugopal Iyer 	{"localbytes",		RL_OFF(rl_lclbytes)},
781*0dc2366fSVenugopal Iyer 	{"intrs",		RL_OFF(rl_intrs)},
782*0dc2366fSVenugopal Iyer 	{"intrbytes",		RL_OFF(rl_intrbytes)},
783*0dc2366fSVenugopal Iyer 	{"polls",		RL_OFF(rl_polls)},
784*0dc2366fSVenugopal Iyer 	{"rxsdrops",		RL_OFF(rl_sdrops)},
785*0dc2366fSVenugopal Iyer 	{"pollbytes",		RL_OFF(rl_pollbytes)},
786*0dc2366fSVenugopal Iyer 	{"chainunder10",	RL_OFF(rl_chl10)},
787*0dc2366fSVenugopal Iyer 	{"chain10to50", 	RL_OFF(rl_ch10_50)},
788*0dc2366fSVenugopal Iyer 	{"chainover50", 	RL_OFF(rl_chg50)}
789*0dc2366fSVenugopal Iyer };
790*0dc2366fSVenugopal Iyer #define	RX_LANE_STAT_SIZE	A_CNT(rx_lane_stats_list)
791*0dc2366fSVenugopal Iyer 
792*0dc2366fSVenugopal Iyer /* Definitions for tx lane stats */
793*0dc2366fSVenugopal Iyer #define	TL_OFF(f)	(offsetof(tx_lane_stat_t, f))
794*0dc2366fSVenugopal Iyer 
795*0dc2366fSVenugopal Iyer static	stat_info_t	tx_lane_stats_list[] = {
796*0dc2366fSVenugopal Iyer 	{"opackets",	TL_OFF(tl_opackets)},
797*0dc2366fSVenugopal Iyer 	{"obytes",	TL_OFF(tl_obytes)},
798*0dc2366fSVenugopal Iyer 	{"blockcnt",	TL_OFF(tl_blockcnt)},
799*0dc2366fSVenugopal Iyer 	{"unblockcnt",	TL_OFF(tl_unblockcnt)},
800*0dc2366fSVenugopal Iyer 	{"txsdrops",	TL_OFF(tl_sdrops)}
801*0dc2366fSVenugopal Iyer };
802*0dc2366fSVenugopal Iyer #define	TX_LANE_STAT_SIZE	A_CNT(tx_lane_stats_list)
803*0dc2366fSVenugopal Iyer 
804*0dc2366fSVenugopal Iyer /* Definitions for tx/rx misc stats */
805*0dc2366fSVenugopal Iyer #define	M_OFF(f)	(offsetof(misc_stat_t, f))
806*0dc2366fSVenugopal Iyer 
807*0dc2366fSVenugopal Iyer static	stat_info_t	misc_stats_list[] = {
808*0dc2366fSVenugopal Iyer 	{"multircv",		M_OFF(ms_multircv)},
809*0dc2366fSVenugopal Iyer 	{"brdcstrcv",		M_OFF(ms_brdcstrcv)},
810*0dc2366fSVenugopal Iyer 	{"multixmt",		M_OFF(ms_multixmt)},
811*0dc2366fSVenugopal Iyer 	{"brdcstxmt",		M_OFF(ms_brdcstxmt)},
812*0dc2366fSVenugopal Iyer 	{"multircvbytes",	M_OFF(ms_multircvbytes)},
813*0dc2366fSVenugopal Iyer 	{"brdcstrcvbytes",	M_OFF(ms_brdcstrcvbytes)},
814*0dc2366fSVenugopal Iyer 	{"multixmtbytes",	M_OFF(ms_multixmtbytes)},
815*0dc2366fSVenugopal Iyer 	{"brdcstxmtbytes",	M_OFF(ms_brdcstxmtbytes)},
816*0dc2366fSVenugopal Iyer 	{"txerrors",		M_OFF(ms_txerrors)},
817*0dc2366fSVenugopal Iyer 	{"macspoofed",		M_OFF(ms_macspoofed)},
818*0dc2366fSVenugopal Iyer 	{"ipspoofed",		M_OFF(ms_ipspoofed)},
819*0dc2366fSVenugopal Iyer 	{"dhcpspoofed",		M_OFF(ms_dhcpspoofed)},
820*0dc2366fSVenugopal Iyer 	{"restricted",		M_OFF(ms_restricted)},
821*0dc2366fSVenugopal Iyer 	{"ipackets",		M_OFF(ms_ipackets)},
822*0dc2366fSVenugopal Iyer 	{"rbytes",		M_OFF(ms_rbytes)},
823*0dc2366fSVenugopal Iyer 	{"local",		M_OFF(ms_local)},
824*0dc2366fSVenugopal Iyer 	{"localbytes",		M_OFF(ms_localbytes)},
825*0dc2366fSVenugopal Iyer 	{"intrs",		M_OFF(ms_intrs)},
826*0dc2366fSVenugopal Iyer 	{"intrbytes",		M_OFF(ms_intrbytes)},
827*0dc2366fSVenugopal Iyer 	{"polls",		M_OFF(ms_polls)},
828*0dc2366fSVenugopal Iyer 	{"pollbytes",		M_OFF(ms_pollbytes)},
829*0dc2366fSVenugopal Iyer 	{"rxsdrops",		M_OFF(ms_rxsdrops)},
830*0dc2366fSVenugopal Iyer 	{"chainunder10",	M_OFF(ms_chainunder10)},
831*0dc2366fSVenugopal Iyer 	{"chain10to50",		M_OFF(ms_chain10to50)},
832*0dc2366fSVenugopal Iyer 	{"chainover50",		M_OFF(ms_chainover50)},
833*0dc2366fSVenugopal Iyer 	{"obytes",		M_OFF(ms_obytes)},
834*0dc2366fSVenugopal Iyer 	{"opackets",		M_OFF(ms_opackets)},
835*0dc2366fSVenugopal Iyer 	{"blockcnt",		M_OFF(ms_blockcnt)},
836*0dc2366fSVenugopal Iyer 	{"unblockcnt",		M_OFF(ms_unblockcnt)},
837*0dc2366fSVenugopal Iyer 	{"txsdrops",		M_OFF(ms_txsdrops)}
838*0dc2366fSVenugopal Iyer };
839*0dc2366fSVenugopal Iyer #define	MISC_STAT_SIZE		A_CNT(misc_stats_list)
840*0dc2366fSVenugopal Iyer 
841*0dc2366fSVenugopal Iyer /* Definitions for rx ring stats */
842*0dc2366fSVenugopal Iyer #define	R_OFF(f)	(offsetof(ring_stat_t, f))
843*0dc2366fSVenugopal Iyer 
844*0dc2366fSVenugopal Iyer static	stat_info_t	rx_ring_stats_list[] = {
845*0dc2366fSVenugopal Iyer 	{"ipackets",	R_OFF(r_packets)},
846*0dc2366fSVenugopal Iyer 	{"rbytes",	R_OFF(r_bytes)}
847*0dc2366fSVenugopal Iyer };
848*0dc2366fSVenugopal Iyer #define	RX_RING_STAT_SIZE	A_CNT(rx_ring_stats_list)
849*0dc2366fSVenugopal Iyer 
850*0dc2366fSVenugopal Iyer /* Definitions for tx ring stats */
851*0dc2366fSVenugopal Iyer static	stat_info_t	tx_ring_stats_list[] = {
852*0dc2366fSVenugopal Iyer 	{"opackets",	R_OFF(r_packets)},
853*0dc2366fSVenugopal Iyer 	{"obytes",	R_OFF(r_bytes)}
854*0dc2366fSVenugopal Iyer };
855*0dc2366fSVenugopal Iyer #define	TX_RING_STAT_SIZE	A_CNT(tx_ring_stats_list)
856*0dc2366fSVenugopal Iyer 
857*0dc2366fSVenugopal Iyer /* Definitions for fanout stats */
858*0dc2366fSVenugopal Iyer #define	F_OFF(f)	(offsetof(fanout_stat_t, f))
859*0dc2366fSVenugopal Iyer 
860*0dc2366fSVenugopal Iyer static	stat_info_t	fanout_stats_list[] = {
861*0dc2366fSVenugopal Iyer 	{"ipackets",	F_OFF(f_ipackets)},
862*0dc2366fSVenugopal Iyer 	{"rbytes",	F_OFF(f_rbytes)},
863*0dc2366fSVenugopal Iyer };
864*0dc2366fSVenugopal Iyer #define	FANOUT_STAT_SIZE	A_CNT(fanout_stats_list)
865*0dc2366fSVenugopal Iyer 
866*0dc2366fSVenugopal Iyer /* Definitions for total stats */
867*0dc2366fSVenugopal Iyer #define	T_OFF(f)	(offsetof(total_stat_t, f))
868*0dc2366fSVenugopal Iyer 
869*0dc2366fSVenugopal Iyer static	stat_info_t	total_stats_list[] = {
870*0dc2366fSVenugopal Iyer 	{"ipackets",	T_OFF(ts_ipackets)},
871*0dc2366fSVenugopal Iyer 	{"rbytes",	T_OFF(ts_rbytes)},
872*0dc2366fSVenugopal Iyer 	{"opackets",	T_OFF(ts_opackets)},
873*0dc2366fSVenugopal Iyer 	{"obytes",	T_OFF(ts_obytes)}
874*0dc2366fSVenugopal Iyer };
875*0dc2366fSVenugopal Iyer #define	TOTAL_STAT_SIZE		A_CNT(total_stats_list)
876*0dc2366fSVenugopal Iyer 
877*0dc2366fSVenugopal Iyer /* Definitions for aggr stats */
878*0dc2366fSVenugopal Iyer #define	AP_OFF(f)	(offsetof(aggr_port_stat_t, f))
879*0dc2366fSVenugopal Iyer 
880*0dc2366fSVenugopal Iyer static	stat_info_t	aggr_port_stats_list[] = {
881*0dc2366fSVenugopal Iyer 	{"ipackets64",	AP_OFF(ap_ipackets)},
882*0dc2366fSVenugopal Iyer 	{"rbytes64",	AP_OFF(ap_rbytes)},
883*0dc2366fSVenugopal Iyer 	{"opackets64",	AP_OFF(ap_opackets)},
884*0dc2366fSVenugopal Iyer 	{"obytes64",	AP_OFF(ap_obytes)}
885*0dc2366fSVenugopal Iyer };
886*0dc2366fSVenugopal Iyer #define	AGGR_PORT_STAT_SIZE	A_CNT(aggr_port_stats_list)
887*0dc2366fSVenugopal Iyer 
888*0dc2366fSVenugopal Iyer /* Definitions for flow stats */
889*0dc2366fSVenugopal Iyer #define	FL_OFF(f)	(offsetof(flow_stat_t, f))
890*0dc2366fSVenugopal Iyer 
891*0dc2366fSVenugopal Iyer static	stat_info_t	flow_stats_list[] = {
892*0dc2366fSVenugopal Iyer 	{"ipackets",	FL_OFF(fl_ipackets)},
893*0dc2366fSVenugopal Iyer 	{"rbytes",	FL_OFF(fl_rbytes)},
894*0dc2366fSVenugopal Iyer 	{"opackets",	FL_OFF(fl_opackets)},
895*0dc2366fSVenugopal Iyer 	{"obytes",	FL_OFF(fl_obytes)}
896*0dc2366fSVenugopal Iyer };
897*0dc2366fSVenugopal Iyer #define	FLOW_STAT_SIZE		A_CNT(flow_stats_list)
898*0dc2366fSVenugopal Iyer 
899*0dc2366fSVenugopal Iyer /* Rx lane specific functions */
900*0dc2366fSVenugopal Iyer void *			dlstat_rx_lane_stats(dladm_handle_t, datalink_id_t);
901*0dc2366fSVenugopal Iyer static boolean_t	i_dlstat_rx_lane_match(void *, void *);
902*0dc2366fSVenugopal Iyer static void *		i_dlstat_rx_lane_stat_entry_diff(void *, void *);
903*0dc2366fSVenugopal Iyer 
904*0dc2366fSVenugopal Iyer /* Tx lane specific functions */
905*0dc2366fSVenugopal Iyer void *			dlstat_tx_lane_stats(dladm_handle_t, datalink_id_t);
906*0dc2366fSVenugopal Iyer static boolean_t	i_dlstat_tx_lane_match(void *, void *);
907*0dc2366fSVenugopal Iyer static void *		i_dlstat_tx_lane_stat_entry_diff(void *, void *);
908*0dc2366fSVenugopal Iyer 
909*0dc2366fSVenugopal Iyer /* Rx lane total specific functions */
910*0dc2366fSVenugopal Iyer void *			dlstat_rx_lane_total_stats(dladm_handle_t,
911*0dc2366fSVenugopal Iyer 			    datalink_id_t);
912*0dc2366fSVenugopal Iyer 
913*0dc2366fSVenugopal Iyer /* Tx lane total specific functions */
914*0dc2366fSVenugopal Iyer void *			dlstat_tx_lane_total_stats(dladm_handle_t,
915*0dc2366fSVenugopal Iyer 			    datalink_id_t);
916*0dc2366fSVenugopal Iyer 
917*0dc2366fSVenugopal Iyer /* Fanout specific functions */
918*0dc2366fSVenugopal Iyer void *			dlstat_fanout_stats(dladm_handle_t, datalink_id_t);
919*0dc2366fSVenugopal Iyer static boolean_t	i_dlstat_fanout_match(void *, void *);
920*0dc2366fSVenugopal Iyer static void *		i_dlstat_fanout_stat_entry_diff(void *, void *);
921*0dc2366fSVenugopal Iyer 
922*0dc2366fSVenugopal Iyer /* Rx ring specific functions */
923*0dc2366fSVenugopal Iyer void *			dlstat_rx_ring_stats(dladm_handle_t, datalink_id_t);
924*0dc2366fSVenugopal Iyer static boolean_t	i_dlstat_rx_ring_match(void *, void *);
925*0dc2366fSVenugopal Iyer static void *		i_dlstat_rx_ring_stat_entry_diff(void *, void *);
926*0dc2366fSVenugopal Iyer 
927*0dc2366fSVenugopal Iyer /* Tx ring specific functions */
928*0dc2366fSVenugopal Iyer void *			dlstat_tx_ring_stats(dladm_handle_t, datalink_id_t);
929*0dc2366fSVenugopal Iyer static boolean_t	i_dlstat_tx_ring_match(void *, void *);
930*0dc2366fSVenugopal Iyer static void *		i_dlstat_tx_ring_stat_entry_diff(void *, void *);
931*0dc2366fSVenugopal Iyer 
932*0dc2366fSVenugopal Iyer /* Rx ring total specific functions */
933*0dc2366fSVenugopal Iyer void *			dlstat_rx_ring_total_stats(dladm_handle_t,
934*0dc2366fSVenugopal Iyer 			    datalink_id_t);
935*0dc2366fSVenugopal Iyer 
936*0dc2366fSVenugopal Iyer /* Tx ring total specific functions */
937*0dc2366fSVenugopal Iyer void *			dlstat_tx_ring_total_stats(dladm_handle_t,
938*0dc2366fSVenugopal Iyer 			    datalink_id_t);
939*0dc2366fSVenugopal Iyer 
940*0dc2366fSVenugopal Iyer /* Summary specific functions */
941*0dc2366fSVenugopal Iyer void *			dlstat_total_stats(dladm_handle_t, datalink_id_t);
942*0dc2366fSVenugopal Iyer static boolean_t	i_dlstat_total_match(void *, void *);
943*0dc2366fSVenugopal Iyer static void *		i_dlstat_total_stat_entry_diff(void *, void *);
944*0dc2366fSVenugopal Iyer 
945*0dc2366fSVenugopal Iyer /* Aggr port specific functions */
946*0dc2366fSVenugopal Iyer void *			dlstat_aggr_port_stats(dladm_handle_t, datalink_id_t);
947*0dc2366fSVenugopal Iyer static boolean_t	i_dlstat_aggr_port_match(void *, void *);
948*0dc2366fSVenugopal Iyer static void *		i_dlstat_aggr_port_stat_entry_diff(void *, void *);
949*0dc2366fSVenugopal Iyer 
950*0dc2366fSVenugopal Iyer /* Misc stat specific functions */
951*0dc2366fSVenugopal Iyer void *			dlstat_misc_stats(dladm_handle_t, datalink_id_t);
952*0dc2366fSVenugopal Iyer 
953*0dc2366fSVenugopal Iyer typedef void *		dladm_stat_query_t(dladm_handle_t, datalink_id_t);
954*0dc2366fSVenugopal Iyer typedef boolean_t	dladm_stat_match_t(void *, void *);
955*0dc2366fSVenugopal Iyer typedef void *		dladm_stat_diff_t(void *, void *);
956*0dc2366fSVenugopal Iyer 
957*0dc2366fSVenugopal Iyer typedef struct dladm_stat_desc_s {
958*0dc2366fSVenugopal Iyer 	dladm_stat_type_t	ds_stattype;
959*0dc2366fSVenugopal Iyer 	dladm_stat_query_t	*ds_querystat;
960*0dc2366fSVenugopal Iyer 	dladm_stat_match_t	*ds_matchstat;
961*0dc2366fSVenugopal Iyer 	dladm_stat_diff_t	*ds_diffstat;
962*0dc2366fSVenugopal Iyer 	uint_t			ds_offset;
963*0dc2366fSVenugopal Iyer 	stat_info_t		*ds_statlist;
964*0dc2366fSVenugopal Iyer 	uint_t			ds_statsize;
965*0dc2366fSVenugopal Iyer } dladm_stat_desc_t;
966*0dc2366fSVenugopal Iyer 
967*0dc2366fSVenugopal Iyer /*
968*0dc2366fSVenugopal Iyer  * dladm_stat_table has one entry for each supported stat. ds_querystat returns
969*0dc2366fSVenugopal Iyer  * a chain of 'stat entries' for the queried stat.
970*0dc2366fSVenugopal Iyer  * Each stat entry has set of identifiers (ids) and an object containing actual
971*0dc2366fSVenugopal Iyer  * stat values. These stat entry objects are chained together in a linked list
972*0dc2366fSVenugopal Iyer  * of datatype dladm_stat_chain_t. Head of this list is returned to the caller
973*0dc2366fSVenugopal Iyer  * of dladm_link_stat_query.
974*0dc2366fSVenugopal Iyer  *
975*0dc2366fSVenugopal Iyer  * One node in the chain is shown below:
976*0dc2366fSVenugopal Iyer  *
977*0dc2366fSVenugopal Iyer  *	-------------------------
978*0dc2366fSVenugopal Iyer  *	| dc_statentry	        |
979*0dc2366fSVenugopal Iyer  *	|    --------------     |
980*0dc2366fSVenugopal Iyer  *	|    |     ids     |	|
981*0dc2366fSVenugopal Iyer  *	|    --------------     |
982*0dc2366fSVenugopal Iyer  *	|    | stat fields |	|
983*0dc2366fSVenugopal Iyer  *	|    --------------     |
984*0dc2366fSVenugopal Iyer  *	-------------------------
985*0dc2366fSVenugopal Iyer  *	|      dc_next ---------|------> to next stat entry
986*0dc2366fSVenugopal Iyer  *	-------------------------
987*0dc2366fSVenugopal Iyer  *
988*0dc2366fSVenugopal Iyer  * In particular, for query DLADM_STAT_RX_LANE, dc_statentry carries pointer to
989*0dc2366fSVenugopal Iyer  * object of type rx_lane_stat_entry_t.
990*0dc2366fSVenugopal Iyer  *
991*0dc2366fSVenugopal Iyer  * dladm_link_stat_query_all returns similar chain. However, instead of storing
992*0dc2366fSVenugopal Iyer  * stat fields as raw numbers, it stores those as chain of <name, value> pairs.
993*0dc2366fSVenugopal Iyer  * The resulting structure is depicted below:
994*0dc2366fSVenugopal Iyer  *
995*0dc2366fSVenugopal Iyer  *	-------------------------
996*0dc2366fSVenugopal Iyer  *	| dc_statentry	        |
997*0dc2366fSVenugopal Iyer  *	|    --------------     |   ---------------
998*0dc2366fSVenugopal Iyer  *	|    |  nv_header  |	|   |   name, val  |
999*0dc2366fSVenugopal Iyer  *	|    --------------     |   ---------------
1000*0dc2366fSVenugopal Iyer  *	|    | nve_stats---|----|-->| nv_nextstat--|---> to next name, val pair
1001*0dc2366fSVenugopal Iyer  *	|    --------------     |   ---------------
1002*0dc2366fSVenugopal Iyer  *	-------------------------
1003*0dc2366fSVenugopal Iyer  *	|      dc_next ---------|------> to next stat entry
1004*0dc2366fSVenugopal Iyer  *	-------------------------
1005*0dc2366fSVenugopal Iyer  */
1006*0dc2366fSVenugopal Iyer static dladm_stat_desc_t  dladm_stat_table[] = {
1007*0dc2366fSVenugopal Iyer { DLADM_STAT_RX_LANE,		dlstat_rx_lane_stats,
1008*0dc2366fSVenugopal Iyer     i_dlstat_rx_lane_match,	i_dlstat_rx_lane_stat_entry_diff,
1009*0dc2366fSVenugopal Iyer     offsetof(rx_lane_stat_entry_t, rle_stats),
1010*0dc2366fSVenugopal Iyer     rx_lane_stats_list,		RX_LANE_STAT_SIZE},
1011*0dc2366fSVenugopal Iyer 
1012*0dc2366fSVenugopal Iyer { DLADM_STAT_TX_LANE,		dlstat_tx_lane_stats,
1013*0dc2366fSVenugopal Iyer     i_dlstat_tx_lane_match,	i_dlstat_tx_lane_stat_entry_diff,
1014*0dc2366fSVenugopal Iyer     offsetof(tx_lane_stat_entry_t, tle_stats),
1015*0dc2366fSVenugopal Iyer     tx_lane_stats_list,		TX_LANE_STAT_SIZE},
1016*0dc2366fSVenugopal Iyer 
1017*0dc2366fSVenugopal Iyer { DLADM_STAT_RX_LANE_TOTAL,	dlstat_rx_lane_total_stats,
1018*0dc2366fSVenugopal Iyer     i_dlstat_rx_lane_match,	i_dlstat_rx_lane_stat_entry_diff,
1019*0dc2366fSVenugopal Iyer     offsetof(rx_lane_stat_entry_t, rle_stats),
1020*0dc2366fSVenugopal Iyer     rx_lane_stats_list,		RX_LANE_STAT_SIZE},
1021*0dc2366fSVenugopal Iyer 
1022*0dc2366fSVenugopal Iyer { DLADM_STAT_TX_LANE_TOTAL,	dlstat_tx_lane_total_stats,
1023*0dc2366fSVenugopal Iyer     i_dlstat_tx_lane_match,	i_dlstat_tx_lane_stat_entry_diff,
1024*0dc2366fSVenugopal Iyer     offsetof(tx_lane_stat_entry_t, tle_stats),
1025*0dc2366fSVenugopal Iyer     tx_lane_stats_list,		TX_LANE_STAT_SIZE},
1026*0dc2366fSVenugopal Iyer 
1027*0dc2366fSVenugopal Iyer { DLADM_STAT_RX_LANE_FOUT,	dlstat_fanout_stats,
1028*0dc2366fSVenugopal Iyer     i_dlstat_fanout_match,	i_dlstat_fanout_stat_entry_diff,
1029*0dc2366fSVenugopal Iyer     offsetof(fanout_stat_entry_t, fe_stats),
1030*0dc2366fSVenugopal Iyer     fanout_stats_list,		FANOUT_STAT_SIZE},
1031*0dc2366fSVenugopal Iyer 
1032*0dc2366fSVenugopal Iyer { DLADM_STAT_RX_RING,		dlstat_rx_ring_stats,
1033*0dc2366fSVenugopal Iyer     i_dlstat_rx_ring_match,	i_dlstat_rx_ring_stat_entry_diff,
1034*0dc2366fSVenugopal Iyer     offsetof(ring_stat_entry_t, re_stats),
1035*0dc2366fSVenugopal Iyer     rx_ring_stats_list,		RX_RING_STAT_SIZE},
1036*0dc2366fSVenugopal Iyer 
1037*0dc2366fSVenugopal Iyer { DLADM_STAT_TX_RING,		dlstat_tx_ring_stats,
1038*0dc2366fSVenugopal Iyer     i_dlstat_tx_ring_match,	i_dlstat_tx_ring_stat_entry_diff,
1039*0dc2366fSVenugopal Iyer     offsetof(ring_stat_entry_t, re_stats),
1040*0dc2366fSVenugopal Iyer     tx_ring_stats_list,		TX_RING_STAT_SIZE},
1041*0dc2366fSVenugopal Iyer 
1042*0dc2366fSVenugopal Iyer { DLADM_STAT_RX_RING_TOTAL,	dlstat_rx_ring_total_stats,
1043*0dc2366fSVenugopal Iyer     i_dlstat_rx_ring_match,	i_dlstat_rx_ring_stat_entry_diff,
1044*0dc2366fSVenugopal Iyer     offsetof(ring_stat_entry_t, re_stats),
1045*0dc2366fSVenugopal Iyer     rx_ring_stats_list,		RX_RING_STAT_SIZE},
1046*0dc2366fSVenugopal Iyer 
1047*0dc2366fSVenugopal Iyer { DLADM_STAT_TX_RING_TOTAL,	dlstat_tx_ring_total_stats,
1048*0dc2366fSVenugopal Iyer     i_dlstat_tx_ring_match,	i_dlstat_tx_ring_stat_entry_diff,
1049*0dc2366fSVenugopal Iyer     offsetof(ring_stat_entry_t, re_stats),
1050*0dc2366fSVenugopal Iyer     tx_ring_stats_list,		TX_RING_STAT_SIZE},
1051*0dc2366fSVenugopal Iyer 
1052*0dc2366fSVenugopal Iyer { DLADM_STAT_TOTAL,		dlstat_total_stats,
1053*0dc2366fSVenugopal Iyer     i_dlstat_total_match,	i_dlstat_total_stat_entry_diff,
1054*0dc2366fSVenugopal Iyer     offsetof(total_stat_entry_t, tse_stats),
1055*0dc2366fSVenugopal Iyer     total_stats_list,		TOTAL_STAT_SIZE},
1056*0dc2366fSVenugopal Iyer 
1057*0dc2366fSVenugopal Iyer { DLADM_STAT_AGGR_PORT,		dlstat_aggr_port_stats,
1058*0dc2366fSVenugopal Iyer     i_dlstat_aggr_port_match,	i_dlstat_aggr_port_stat_entry_diff,
1059*0dc2366fSVenugopal Iyer     offsetof(aggr_port_stat_entry_t, ape_stats),
1060*0dc2366fSVenugopal Iyer     aggr_port_stats_list,	AGGR_PORT_STAT_SIZE},
1061*0dc2366fSVenugopal Iyer /*
1062*0dc2366fSVenugopal Iyer  * We don't support -i <interval> query with misc stats. Several table fields
1063*0dc2366fSVenugopal Iyer  * are left uninitialized thus.
1064*0dc2366fSVenugopal Iyer  */
1065*0dc2366fSVenugopal Iyer { DLADM_STAT_MISC,		dlstat_misc_stats,
1066*0dc2366fSVenugopal Iyer     NULL,			NULL,
1067*0dc2366fSVenugopal Iyer     0,
1068*0dc2366fSVenugopal Iyer     misc_stats_list,		MISC_STAT_SIZE}
1069*0dc2366fSVenugopal Iyer };
1070*0dc2366fSVenugopal Iyer 
1071*0dc2366fSVenugopal Iyer /* Internal functions */
1072*0dc2366fSVenugopal Iyer static void *
1073*0dc2366fSVenugopal Iyer dlstat_diff_stats(void *arg1, void *arg2, dladm_stat_type_t stattype)
1074*0dc2366fSVenugopal Iyer {
1075*0dc2366fSVenugopal Iyer 	return (dladm_stat_table[stattype].ds_diffstat(arg1, arg2));
1076*0dc2366fSVenugopal Iyer }
1077*0dc2366fSVenugopal Iyer 
1078*0dc2366fSVenugopal Iyer static boolean_t
1079*0dc2366fSVenugopal Iyer dlstat_match_stats(void *arg1, void *arg2, dladm_stat_type_t stattype)
1080*0dc2366fSVenugopal Iyer {
1081*0dc2366fSVenugopal Iyer 	return (dladm_stat_table[stattype].ds_matchstat(arg1, arg2));
1082*0dc2366fSVenugopal Iyer }
1083*0dc2366fSVenugopal Iyer 
1084*0dc2366fSVenugopal Iyer /* Diff between two stats */
1085*0dc2366fSVenugopal Iyer static void
1086*0dc2366fSVenugopal Iyer i_dlstat_diff_stats(void *diff, void *op1, void *op2,
1087*0dc2366fSVenugopal Iyer     stat_info_t stats_list[], uint_t size)
1088*0dc2366fSVenugopal Iyer {
1089*0dc2366fSVenugopal Iyer 	int	i;
1090*0dc2366fSVenugopal Iyer 
1091*0dc2366fSVenugopal Iyer 	for (i = 0; i < size; i++) {
1092*0dc2366fSVenugopal Iyer 		uint64_t *op1_val  = (void *)
1093*0dc2366fSVenugopal Iyer 		    ((uchar_t *)op1 + stats_list[i].si_offset);
1094*0dc2366fSVenugopal Iyer 		uint64_t *op2_val = (void *)
1095*0dc2366fSVenugopal Iyer 		    ((uchar_t *)op2  + stats_list[i].si_offset);
1096*0dc2366fSVenugopal Iyer 		uint64_t *diff_val = (void *)
1097*0dc2366fSVenugopal Iyer 		    ((uchar_t *)diff + stats_list[i].si_offset);
1098*0dc2366fSVenugopal Iyer 
1099*0dc2366fSVenugopal Iyer 		*diff_val = DIFF_STAT(*op1_val, *op2_val);
1100*0dc2366fSVenugopal Iyer 	}
1101*0dc2366fSVenugopal Iyer }
1102*0dc2366fSVenugopal Iyer 
1103*0dc2366fSVenugopal Iyer /*
1104*0dc2366fSVenugopal Iyer  * Perform diff = s1 - s2,  where diff, s1, s2 are structure objects of same
1105*0dc2366fSVenugopal Iyer  * datatype. slist is list of offsets of the fields within the structure.
1106*0dc2366fSVenugopal Iyer  */
1107*0dc2366fSVenugopal Iyer #define	DLSTAT_DIFF_STAT(s1, s2, diff, f, slist, sz) {			\
1108*0dc2366fSVenugopal Iyer 	if (s2 == NULL) {						\
1109*0dc2366fSVenugopal Iyer 		bcopy(&s1->f, &diff->f, sizeof (s1->f));		\
1110*0dc2366fSVenugopal Iyer 	} else {							\
1111*0dc2366fSVenugopal Iyer 		i_dlstat_diff_stats(&diff->f, &s1->f,			\
1112*0dc2366fSVenugopal Iyer 		    &s2->f, slist, sz);					\
1113*0dc2366fSVenugopal Iyer 	}								\
1114*0dc2366fSVenugopal Iyer }
1115*0dc2366fSVenugopal Iyer 
1116*0dc2366fSVenugopal Iyer /* Sum two stats */
1117*0dc2366fSVenugopal Iyer static void
1118*0dc2366fSVenugopal Iyer i_dlstat_sum_stats(void *sum, void *op1, void *op2,
1119*0dc2366fSVenugopal Iyer     stat_info_t stats_list[], uint_t size)
1120*0dc2366fSVenugopal Iyer {
1121*0dc2366fSVenugopal Iyer 	int	i;
1122*0dc2366fSVenugopal Iyer 
1123*0dc2366fSVenugopal Iyer 	for (i = 0; i < size; i++) {
1124*0dc2366fSVenugopal Iyer 		uint64_t *op1_val = (void *)
1125*0dc2366fSVenugopal Iyer 		    ((uchar_t *)op1 + stats_list[i].si_offset);
1126*0dc2366fSVenugopal Iyer 		uint64_t *op2_val = (void *)
1127*0dc2366fSVenugopal Iyer 		    ((uchar_t *)op2 + stats_list[i].si_offset);
1128*0dc2366fSVenugopal Iyer 		uint64_t *sum_val = (void *)
1129*0dc2366fSVenugopal Iyer 		    ((uchar_t *)sum + stats_list[i].si_offset);
1130*0dc2366fSVenugopal Iyer 
1131*0dc2366fSVenugopal Iyer 		*sum_val =  *op1_val + *op2_val;
1132*0dc2366fSVenugopal Iyer 	}
1133*0dc2366fSVenugopal Iyer }
1134*0dc2366fSVenugopal Iyer 
1135*0dc2366fSVenugopal Iyer /* Look up kstat value */
1136*0dc2366fSVenugopal Iyer static void
1137*0dc2366fSVenugopal Iyer i_dlstat_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, void *stats,
1138*0dc2366fSVenugopal Iyer     stat_info_t stats_list[], uint_t size)
1139*0dc2366fSVenugopal Iyer {
1140*0dc2366fSVenugopal Iyer 	int	i;
1141*0dc2366fSVenugopal Iyer 
1142*0dc2366fSVenugopal Iyer 	if (kstat_read(kcp, ksp, NULL) == -1)
1143*0dc2366fSVenugopal Iyer 		return;
1144*0dc2366fSVenugopal Iyer 
1145*0dc2366fSVenugopal Iyer 	for (i = 0; i < size; i++) {
1146*0dc2366fSVenugopal Iyer 		uint64_t *val = (void *)
1147*0dc2366fSVenugopal Iyer 		    ((uchar_t *)stats + stats_list[i].si_offset);
1148*0dc2366fSVenugopal Iyer 
1149*0dc2366fSVenugopal Iyer 		if (dladm_kstat_value(ksp, stats_list[i].si_name,
1150*0dc2366fSVenugopal Iyer 		    KSTAT_DATA_UINT64, val) < 0)
1151*0dc2366fSVenugopal Iyer 			return;
1152*0dc2366fSVenugopal Iyer 	}
1153*0dc2366fSVenugopal Iyer }
1154*0dc2366fSVenugopal Iyer 
1155*0dc2366fSVenugopal Iyer /* Append linked list list1 to linked list list2 and return resulting list */
1156*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1157*0dc2366fSVenugopal Iyer i_dlstat_join_lists(dladm_stat_chain_t *list1, dladm_stat_chain_t *list2)
1158*0dc2366fSVenugopal Iyer {
1159*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
1160*0dc2366fSVenugopal Iyer 
1161*0dc2366fSVenugopal Iyer 	if (list1 == NULL)
1162*0dc2366fSVenugopal Iyer 		return (list2);
1163*0dc2366fSVenugopal Iyer 
1164*0dc2366fSVenugopal Iyer 	/* list1 has at least one element, find last element in list1 */
1165*0dc2366fSVenugopal Iyer 	curr = list1;
1166*0dc2366fSVenugopal Iyer 	while (curr->dc_next != NULL)
1167*0dc2366fSVenugopal Iyer 		curr = curr->dc_next;
1168*0dc2366fSVenugopal Iyer 
1169*0dc2366fSVenugopal Iyer 	curr->dc_next = list2;
1170*0dc2366fSVenugopal Iyer 	return (list1);
1171*0dc2366fSVenugopal Iyer }
1172*0dc2366fSVenugopal Iyer 
1173*0dc2366fSVenugopal Iyer uint_t default_idlist[] = {0};
1174*0dc2366fSVenugopal Iyer uint_t default_idlist_size = 1;
1175*0dc2366fSVenugopal Iyer 
1176*0dc2366fSVenugopal Iyer typedef enum {
1177*0dc2366fSVenugopal Iyer 	DLSTAT_RX_RING_IDLIST,
1178*0dc2366fSVenugopal Iyer 	DLSTAT_TX_RING_IDLIST,
1179*0dc2366fSVenugopal Iyer 	DLSTAT_RX_HWLANE_IDLIST,
1180*0dc2366fSVenugopal Iyer 	DLSTAT_TX_HWLANE_IDLIST,
1181*0dc2366fSVenugopal Iyer 	DLSTAT_FANOUT_IDLIST
1182*0dc2366fSVenugopal Iyer } dlstat_idlist_type_t;
1183*0dc2366fSVenugopal Iyer 
1184*0dc2366fSVenugopal Iyer void
1185*0dc2366fSVenugopal Iyer dladm_sort_index_list(uint_t idlist[], uint_t size)
1186*0dc2366fSVenugopal Iyer {
1187*0dc2366fSVenugopal Iyer 	int 	i, j;
1188*0dc2366fSVenugopal Iyer 
1189*0dc2366fSVenugopal Iyer 	for (j = 1; j < size; j++) {
1190*0dc2366fSVenugopal Iyer 		int key = idlist[j];
1191*0dc2366fSVenugopal Iyer 		for (i = j - 1; (i >= 0) && (idlist[i] > key); i--)
1192*0dc2366fSVenugopal Iyer 			idlist[i + 1] = idlist[i];
1193*0dc2366fSVenugopal Iyer 		idlist[i + 1] = key;
1194*0dc2366fSVenugopal Iyer 	}
1195*0dc2366fSVenugopal Iyer }
1196*0dc2366fSVenugopal Iyer 
1197*0dc2366fSVenugopal Iyer /* Support for legacy drivers */
1198*0dc2366fSVenugopal Iyer void
1199*0dc2366fSVenugopal Iyer i_query_legacy_stats(const char *linkname, pktsum_t *stats)
1200*0dc2366fSVenugopal Iyer {
1201*0dc2366fSVenugopal Iyer 	kstat_ctl_t	*kcp;
1202*0dc2366fSVenugopal Iyer 	kstat_t		*ksp;
1203*0dc2366fSVenugopal Iyer 
1204*0dc2366fSVenugopal Iyer 	bzero(stats, sizeof (*stats));
1205*0dc2366fSVenugopal Iyer 
1206*0dc2366fSVenugopal Iyer 	if ((kcp = kstat_open()) == NULL)
1207*0dc2366fSVenugopal Iyer 		return;
1208*0dc2366fSVenugopal Iyer 
1209*0dc2366fSVenugopal Iyer 	ksp = dladm_kstat_lookup(kcp, "link", 0, linkname, NULL);
1210*0dc2366fSVenugopal Iyer 
1211*0dc2366fSVenugopal Iyer 	if (ksp != NULL)
1212*0dc2366fSVenugopal Iyer 		dladm_get_stats(kcp, ksp, stats);
1213*0dc2366fSVenugopal Iyer 
1214*0dc2366fSVenugopal Iyer 	(void) kstat_close(kcp);
1215*0dc2366fSVenugopal Iyer }
1216*0dc2366fSVenugopal Iyer 
1217*0dc2366fSVenugopal Iyer void *
1218*0dc2366fSVenugopal Iyer i_dlstat_legacy_rx_lane_stats(const char *linkname)
1219*0dc2366fSVenugopal Iyer {
1220*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
1221*0dc2366fSVenugopal Iyer 	pktsum_t		stats;
1222*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1223*0dc2366fSVenugopal Iyer 
1224*0dc2366fSVenugopal Iyer 	bzero(&stats, sizeof (pktsum_t));
1225*0dc2366fSVenugopal Iyer 
1226*0dc2366fSVenugopal Iyer 	/* Query for dls stats */
1227*0dc2366fSVenugopal Iyer 	i_query_legacy_stats(linkname, &stats);
1228*0dc2366fSVenugopal Iyer 
1229*0dc2366fSVenugopal Iyer 	/* Convert to desired data type */
1230*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1231*0dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
1232*0dc2366fSVenugopal Iyer 		goto done;
1233*0dc2366fSVenugopal Iyer 
1234*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1235*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_SWLANE;
1236*0dc2366fSVenugopal Iyer 
1237*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets;
1238*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets;
1239*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes;
1240*0dc2366fSVenugopal Iyer 
1241*0dc2366fSVenugopal Iyer 	/* Allocate memory for wrapper */
1242*0dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
1243*0dc2366fSVenugopal Iyer 	if (head == NULL) {
1244*0dc2366fSVenugopal Iyer 		free(rx_lane_stat_entry);
1245*0dc2366fSVenugopal Iyer 		goto done;
1246*0dc2366fSVenugopal Iyer 	}
1247*0dc2366fSVenugopal Iyer 
1248*0dc2366fSVenugopal Iyer 	head->dc_statentry = rx_lane_stat_entry;
1249*0dc2366fSVenugopal Iyer 	head->dc_next = NULL;
1250*0dc2366fSVenugopal Iyer done:
1251*0dc2366fSVenugopal Iyer 	return (head);
1252*0dc2366fSVenugopal Iyer }
1253*0dc2366fSVenugopal Iyer 
1254*0dc2366fSVenugopal Iyer void *
1255*0dc2366fSVenugopal Iyer i_dlstat_legacy_tx_lane_stats(const char *linkname)
1256*0dc2366fSVenugopal Iyer {
1257*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
1258*0dc2366fSVenugopal Iyer 	pktsum_t		stats;
1259*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
1260*0dc2366fSVenugopal Iyer 
1261*0dc2366fSVenugopal Iyer 	bzero(&stats, sizeof (pktsum_t));
1262*0dc2366fSVenugopal Iyer 
1263*0dc2366fSVenugopal Iyer 	/* Query for dls stats */
1264*0dc2366fSVenugopal Iyer 	i_query_legacy_stats(linkname, &stats);
1265*0dc2366fSVenugopal Iyer 
1266*0dc2366fSVenugopal Iyer 	/* Convert to desired data type */
1267*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1268*0dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
1269*0dc2366fSVenugopal Iyer 		goto done;
1270*0dc2366fSVenugopal Iyer 
1271*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1272*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_SWLANE;
1273*0dc2366fSVenugopal Iyer 
1274*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets;
1275*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes;
1276*0dc2366fSVenugopal Iyer 
1277*0dc2366fSVenugopal Iyer 	/* Allocate memory for wrapper */
1278*0dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
1279*0dc2366fSVenugopal Iyer 	if (head == NULL) {
1280*0dc2366fSVenugopal Iyer 		free(tx_lane_stat_entry);
1281*0dc2366fSVenugopal Iyer 		goto done;
1282*0dc2366fSVenugopal Iyer 	}
1283*0dc2366fSVenugopal Iyer 
1284*0dc2366fSVenugopal Iyer 	head->dc_statentry = tx_lane_stat_entry;
1285*0dc2366fSVenugopal Iyer 	head->dc_next = NULL;
1286*0dc2366fSVenugopal Iyer done:
1287*0dc2366fSVenugopal Iyer 	return (head);
1288*0dc2366fSVenugopal Iyer }
1289*0dc2366fSVenugopal Iyer 
1290*0dc2366fSVenugopal Iyer /*
1291*0dc2366fSVenugopal Iyer  * Ideally, we would want an ioctl to return list of ring-ids (or lane-ids)
1292*0dc2366fSVenugopal Iyer  * for a given data-link (or mac client). We could then query for specific
1293*0dc2366fSVenugopal Iyer  * kstats based on these ring-ids (lane-ids).
1294*0dc2366fSVenugopal Iyer  * Ring-ids (or lane-ids) could be returned like any other link properties
1295*0dc2366fSVenugopal Iyer  * queried by dladm show-linkprop. However, non-global zones do not have
1296*0dc2366fSVenugopal Iyer  * access to this information today.
1297*0dc2366fSVenugopal Iyer  * We thus opt for an implementation that relies heavily on kstat internals:
1298*0dc2366fSVenugopal Iyer  * i_dlstat_*search routines and i_dlstat_get_idlist.
1299*0dc2366fSVenugopal Iyer  */
1300*0dc2366fSVenugopal Iyer /* rx hwlane specific */
1301*0dc2366fSVenugopal Iyer static boolean_t
1302*0dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_search(kstat_t *ksp)
1303*0dc2366fSVenugopal Iyer {
1304*0dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
1305*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
1306*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "hwlane") != 0 &&
1307*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "fanout") == 0 &&
1308*0dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
1309*0dc2366fSVenugopal Iyer }
1310*0dc2366fSVenugopal Iyer 
1311*0dc2366fSVenugopal Iyer /* tx hwlane specific */
1312*0dc2366fSVenugopal Iyer static boolean_t
1313*0dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_search(kstat_t *ksp)
1314*0dc2366fSVenugopal Iyer {
1315*0dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
1316*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_tx") != 0 &&
1317*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "hwlane") != 0 &&
1318*0dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
1319*0dc2366fSVenugopal Iyer }
1320*0dc2366fSVenugopal Iyer 
1321*0dc2366fSVenugopal Iyer /* rx fanout specific */
1322*0dc2366fSVenugopal Iyer static boolean_t
1323*0dc2366fSVenugopal Iyer i_dlstat_fanout_search(kstat_t *ksp)
1324*0dc2366fSVenugopal Iyer {
1325*0dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
1326*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
1327*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "swlane") != 0 &&
1328*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "fanout") != 0 &&
1329*0dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
1330*0dc2366fSVenugopal Iyer }
1331*0dc2366fSVenugopal Iyer 
1332*0dc2366fSVenugopal Iyer /* rx ring specific */
1333*0dc2366fSVenugopal Iyer static boolean_t
1334*0dc2366fSVenugopal Iyer i_dlstat_rx_ring_search(kstat_t *ksp)
1335*0dc2366fSVenugopal Iyer {
1336*0dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
1337*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
1338*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "ring") != 0 &&
1339*0dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
1340*0dc2366fSVenugopal Iyer }
1341*0dc2366fSVenugopal Iyer 
1342*0dc2366fSVenugopal Iyer /* tx ring specific */
1343*0dc2366fSVenugopal Iyer static boolean_t
1344*0dc2366fSVenugopal Iyer i_dlstat_tx_ring_search(kstat_t *ksp)
1345*0dc2366fSVenugopal Iyer {
1346*0dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0) &&
1347*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_tx") != 0 &&
1348*0dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "ring") != 0 &&
1349*0dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0;
1350*0dc2366fSVenugopal Iyer }
1351*0dc2366fSVenugopal Iyer 
1352*0dc2366fSVenugopal Iyer typedef	boolean_t	dladm_search_kstat_t(kstat_t *);
1353*0dc2366fSVenugopal Iyer typedef struct dladm_extract_idlist_s {
1354*0dc2366fSVenugopal Iyer 	dlstat_idlist_type_t	di_type;
1355*0dc2366fSVenugopal Iyer 	char			*di_prefix;
1356*0dc2366fSVenugopal Iyer 	dladm_search_kstat_t	*di_searchkstat;
1357*0dc2366fSVenugopal Iyer } dladm_extract_idlist_t;
1358*0dc2366fSVenugopal Iyer 
1359*0dc2366fSVenugopal Iyer static dladm_extract_idlist_t dladm_extract_idlist[] = {
1360*0dc2366fSVenugopal Iyer { DLSTAT_RX_RING_IDLIST,	DLSTAT_MAC_RX_RING,
1361*0dc2366fSVenugopal Iyer     i_dlstat_rx_ring_search},
1362*0dc2366fSVenugopal Iyer { DLSTAT_TX_RING_IDLIST,	DLSTAT_MAC_TX_RING,
1363*0dc2366fSVenugopal Iyer     i_dlstat_tx_ring_search},
1364*0dc2366fSVenugopal Iyer { DLSTAT_RX_HWLANE_IDLIST,	DLSTAT_MAC_RX_HWLANE,
1365*0dc2366fSVenugopal Iyer     i_dlstat_rx_hwlane_search},
1366*0dc2366fSVenugopal Iyer { DLSTAT_TX_HWLANE_IDLIST,	DLSTAT_MAC_TX_HWLANE,
1367*0dc2366fSVenugopal Iyer     i_dlstat_tx_hwlane_search},
1368*0dc2366fSVenugopal Iyer { DLSTAT_FANOUT_IDLIST,		DLSTAT_MAC_FANOUT,
1369*0dc2366fSVenugopal Iyer     i_dlstat_fanout_search}
1370*0dc2366fSVenugopal Iyer };
1371*0dc2366fSVenugopal Iyer 
1372*0dc2366fSVenugopal Iyer static void
1373*0dc2366fSVenugopal Iyer i_dlstat_get_idlist(const char *modname, dlstat_idlist_type_t idlist_type,
1374*0dc2366fSVenugopal Iyer     uint_t idlist[], uint_t *size)
1375*0dc2366fSVenugopal Iyer {
1376*0dc2366fSVenugopal Iyer 	kstat_ctl_t	*kcp;
1377*0dc2366fSVenugopal Iyer 	kstat_t		*ksp;
1378*0dc2366fSVenugopal Iyer 	char		*prefix;
1379*0dc2366fSVenugopal Iyer 	int		prefixlen;
1380*0dc2366fSVenugopal Iyer 	boolean_t	(*fptr_searchkstat)(kstat_t *);
1381*0dc2366fSVenugopal Iyer 
1382*0dc2366fSVenugopal Iyer 	*size = 0;
1383*0dc2366fSVenugopal Iyer 
1384*0dc2366fSVenugopal Iyer 	if ((kcp = kstat_open()) == NULL) {
1385*0dc2366fSVenugopal Iyer 		warn("kstat_open operation failed");
1386*0dc2366fSVenugopal Iyer 		goto done;
1387*0dc2366fSVenugopal Iyer 	}
1388*0dc2366fSVenugopal Iyer 
1389*0dc2366fSVenugopal Iyer 	prefix = dladm_extract_idlist[idlist_type].di_prefix;
1390*0dc2366fSVenugopal Iyer 	fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat;
1391*0dc2366fSVenugopal Iyer 	prefixlen = strlen(prefix);
1392*0dc2366fSVenugopal Iyer 	for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
1393*0dc2366fSVenugopal Iyer 		if ((strcmp(ksp->ks_module, modname) == 0) &&
1394*0dc2366fSVenugopal Iyer 		    fptr_searchkstat(ksp)) {
1395*0dc2366fSVenugopal Iyer 			idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]);
1396*0dc2366fSVenugopal Iyer 		}
1397*0dc2366fSVenugopal Iyer 	}
1398*0dc2366fSVenugopal Iyer 	dladm_sort_index_list(idlist, *size);
1399*0dc2366fSVenugopal Iyer 
1400*0dc2366fSVenugopal Iyer done:
1401*0dc2366fSVenugopal Iyer 	(void) kstat_close(kcp);
1402*0dc2366fSVenugopal Iyer }
1403*0dc2366fSVenugopal Iyer 
1404*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1405*0dc2366fSVenugopal Iyer i_dlstat_query_stats(const char *modname, const char *prefix,
1406*0dc2366fSVenugopal Iyer     uint_t idlist[], uint_t idlist_size,
1407*0dc2366fSVenugopal Iyer     void * (*fn)(kstat_ctl_t *, kstat_t *, int))
1408*0dc2366fSVenugopal Iyer {
1409*0dc2366fSVenugopal Iyer 	kstat_ctl_t		*kcp;
1410*0dc2366fSVenugopal Iyer 	kstat_t			*ksp;
1411*0dc2366fSVenugopal Iyer 	char			statname[MAXLINKNAMELEN];
1412*0dc2366fSVenugopal Iyer 	int 			i = 0;
1413*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t 	*head = NULL, *prev = NULL;
1414*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
1415*0dc2366fSVenugopal Iyer 
1416*0dc2366fSVenugopal Iyer 	if ((kcp = kstat_open()) == NULL) {
1417*0dc2366fSVenugopal Iyer 		warn("kstat_open operation failed");
1418*0dc2366fSVenugopal Iyer 		return (NULL);
1419*0dc2366fSVenugopal Iyer 	}
1420*0dc2366fSVenugopal Iyer 
1421*0dc2366fSVenugopal Iyer 	for (i = 0; i < idlist_size; i++) {
1422*0dc2366fSVenugopal Iyer 		uint_t 	index = idlist[i];
1423*0dc2366fSVenugopal Iyer 
1424*0dc2366fSVenugopal Iyer 		(void) snprintf(statname, sizeof (statname), "%s%d", prefix,
1425*0dc2366fSVenugopal Iyer 		    index);
1426*0dc2366fSVenugopal Iyer 
1427*0dc2366fSVenugopal Iyer 		ksp = dladm_kstat_lookup(kcp, modname, 0, statname, NULL);
1428*0dc2366fSVenugopal Iyer 		if (ksp == NULL)
1429*0dc2366fSVenugopal Iyer 			continue;
1430*0dc2366fSVenugopal Iyer 
1431*0dc2366fSVenugopal Iyer 		curr = malloc(sizeof (dladm_stat_chain_t));
1432*0dc2366fSVenugopal Iyer 		if (curr == NULL)
1433*0dc2366fSVenugopal Iyer 			break;
1434*0dc2366fSVenugopal Iyer 
1435*0dc2366fSVenugopal Iyer 		curr->dc_statentry = fn(kcp, ksp, index);
1436*0dc2366fSVenugopal Iyer 		if (curr->dc_statentry == NULL) {
1437*0dc2366fSVenugopal Iyer 			free(curr);
1438*0dc2366fSVenugopal Iyer 			break;
1439*0dc2366fSVenugopal Iyer 		}
1440*0dc2366fSVenugopal Iyer 
1441*0dc2366fSVenugopal Iyer 		(void) strlcpy(curr->dc_statheader, statname,
1442*0dc2366fSVenugopal Iyer 		    sizeof (curr->dc_statheader));
1443*0dc2366fSVenugopal Iyer 		curr->dc_next = NULL;
1444*0dc2366fSVenugopal Iyer 
1445*0dc2366fSVenugopal Iyer 		if (head == NULL)	/* First node */
1446*0dc2366fSVenugopal Iyer 			head = curr;
1447*0dc2366fSVenugopal Iyer 		else
1448*0dc2366fSVenugopal Iyer 			prev->dc_next = curr;
1449*0dc2366fSVenugopal Iyer 
1450*0dc2366fSVenugopal Iyer 		prev = curr;
1451*0dc2366fSVenugopal Iyer 	}
1452*0dc2366fSVenugopal Iyer done:
1453*0dc2366fSVenugopal Iyer 	(void) kstat_close(kcp);
1454*0dc2366fSVenugopal Iyer 	return (head);
1455*0dc2366fSVenugopal Iyer }
1456*0dc2366fSVenugopal Iyer 
1457*0dc2366fSVenugopal Iyer static misc_stat_entry_t *
1458*0dc2366fSVenugopal Iyer i_dlstat_misc_stats(const char *linkname)
1459*0dc2366fSVenugopal Iyer {
1460*0dc2366fSVenugopal Iyer 	kstat_ctl_t		*kcp;
1461*0dc2366fSVenugopal Iyer 	kstat_t			*ksp;
1462*0dc2366fSVenugopal Iyer 	misc_stat_entry_t 	*misc_stat_entry = NULL;
1463*0dc2366fSVenugopal Iyer 
1464*0dc2366fSVenugopal Iyer 	if ((kcp = kstat_open()) == NULL)
1465*0dc2366fSVenugopal Iyer 		return (NULL);
1466*0dc2366fSVenugopal Iyer 
1467*0dc2366fSVenugopal Iyer 	ksp = dladm_kstat_lookup(kcp, linkname, 0, DLSTAT_MAC_MISC_STAT, NULL);
1468*0dc2366fSVenugopal Iyer 	if (ksp == NULL)
1469*0dc2366fSVenugopal Iyer 		goto done;
1470*0dc2366fSVenugopal Iyer 
1471*0dc2366fSVenugopal Iyer 	misc_stat_entry = calloc(1, sizeof (misc_stat_entry_t));
1472*0dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
1473*0dc2366fSVenugopal Iyer 		goto done;
1474*0dc2366fSVenugopal Iyer 
1475*0dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &misc_stat_entry->mse_stats,
1476*0dc2366fSVenugopal Iyer 	    misc_stats_list, MISC_STAT_SIZE);
1477*0dc2366fSVenugopal Iyer done:
1478*0dc2366fSVenugopal Iyer 	(void) kstat_close(kcp);
1479*0dc2366fSVenugopal Iyer 	return (misc_stat_entry);
1480*0dc2366fSVenugopal Iyer }
1481*0dc2366fSVenugopal Iyer 
1482*0dc2366fSVenugopal Iyer /* Rx lane statistic specific functions */
1483*0dc2366fSVenugopal Iyer static boolean_t
1484*0dc2366fSVenugopal Iyer i_dlstat_rx_lane_match(void *arg1, void *arg2)
1485*0dc2366fSVenugopal Iyer {
1486*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s1 = arg1;
1487*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s2 = arg2;
1488*0dc2366fSVenugopal Iyer 
1489*0dc2366fSVenugopal Iyer 	return (s1->rle_index == s2->rle_index &&
1490*0dc2366fSVenugopal Iyer 	    s1->rle_id == s2->rle_id);
1491*0dc2366fSVenugopal Iyer }
1492*0dc2366fSVenugopal Iyer 
1493*0dc2366fSVenugopal Iyer static void *
1494*0dc2366fSVenugopal Iyer i_dlstat_rx_lane_stat_entry_diff(void *arg1, void *arg2)
1495*0dc2366fSVenugopal Iyer {
1496*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s1 = arg1;
1497*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s2 = arg2;
1498*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *diff_entry;
1499*0dc2366fSVenugopal Iyer 
1500*0dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (rx_lane_stat_entry_t));
1501*0dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
1502*0dc2366fSVenugopal Iyer 		goto done;
1503*0dc2366fSVenugopal Iyer 
1504*0dc2366fSVenugopal Iyer 	diff_entry->rle_index = s1->rle_index;
1505*0dc2366fSVenugopal Iyer 	diff_entry->rle_id = s1->rle_id;
1506*0dc2366fSVenugopal Iyer 
1507*0dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, rle_stats, rx_lane_stats_list,
1508*0dc2366fSVenugopal Iyer 	    RX_LANE_STAT_SIZE);
1509*0dc2366fSVenugopal Iyer 
1510*0dc2366fSVenugopal Iyer done:
1511*0dc2366fSVenugopal Iyer 	return (diff_entry);
1512*0dc2366fSVenugopal Iyer }
1513*0dc2366fSVenugopal Iyer 
1514*0dc2366fSVenugopal Iyer static void *
1515*0dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1516*0dc2366fSVenugopal Iyer {
1517*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1518*0dc2366fSVenugopal Iyer 
1519*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1520*0dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
1521*0dc2366fSVenugopal Iyer 		goto done;
1522*0dc2366fSVenugopal Iyer 
1523*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = i;
1524*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_HWLANE;
1525*0dc2366fSVenugopal Iyer 
1526*0dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1527*0dc2366fSVenugopal Iyer 	    rx_hwlane_stats_list, RX_HWLANE_STAT_SIZE);
1528*0dc2366fSVenugopal Iyer 
1529*0dc2366fSVenugopal Iyer done:
1530*0dc2366fSVenugopal Iyer 	return (rx_lane_stat_entry);
1531*0dc2366fSVenugopal Iyer }
1532*0dc2366fSVenugopal Iyer 
1533*0dc2366fSVenugopal Iyer /*ARGSUSED*/
1534*0dc2366fSVenugopal Iyer static void *
1535*0dc2366fSVenugopal Iyer i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1536*0dc2366fSVenugopal Iyer {
1537*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1538*0dc2366fSVenugopal Iyer 
1539*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1540*0dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
1541*0dc2366fSVenugopal Iyer 		goto done;
1542*0dc2366fSVenugopal Iyer 
1543*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1544*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_SWLANE;
1545*0dc2366fSVenugopal Iyer 
1546*0dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1547*0dc2366fSVenugopal Iyer 	    rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
1548*0dc2366fSVenugopal Iyer 
1549*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets =
1550*0dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_intrs;
1551*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes =
1552*0dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_intrbytes;
1553*0dc2366fSVenugopal Iyer done:
1554*0dc2366fSVenugopal Iyer 	return (rx_lane_stat_entry);
1555*0dc2366fSVenugopal Iyer }
1556*0dc2366fSVenugopal Iyer 
1557*0dc2366fSVenugopal Iyer /*ARGSUSED*/
1558*0dc2366fSVenugopal Iyer static void *
1559*0dc2366fSVenugopal Iyer i_dlstat_rx_local_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1560*0dc2366fSVenugopal Iyer {
1561*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*local_stat_entry;
1562*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1563*0dc2366fSVenugopal Iyer 
1564*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1565*0dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
1566*0dc2366fSVenugopal Iyer 		goto done;
1567*0dc2366fSVenugopal Iyer 
1568*0dc2366fSVenugopal Iyer 	local_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1569*0dc2366fSVenugopal Iyer 	if (local_stat_entry == NULL)
1570*0dc2366fSVenugopal Iyer 		goto done;
1571*0dc2366fSVenugopal Iyer 
1572*0dc2366fSVenugopal Iyer 	local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1573*0dc2366fSVenugopal Iyer 	local_stat_entry->rle_id = L_LOCAL;
1574*0dc2366fSVenugopal Iyer 
1575*0dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1576*0dc2366fSVenugopal Iyer 	    rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
1577*0dc2366fSVenugopal Iyer 
1578*0dc2366fSVenugopal Iyer 	local_stat_entry->rle_stats.rl_ipackets =
1579*0dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_lclpackets;
1580*0dc2366fSVenugopal Iyer 	local_stat_entry->rle_stats.rl_rbytes =
1581*0dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_lclbytes;
1582*0dc2366fSVenugopal Iyer 
1583*0dc2366fSVenugopal Iyer done:
1584*0dc2366fSVenugopal Iyer 	free(rx_lane_stat_entry);
1585*0dc2366fSVenugopal Iyer 	return (local_stat_entry);
1586*0dc2366fSVenugopal Iyer }
1587*0dc2366fSVenugopal Iyer 
1588*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1589*0dc2366fSVenugopal Iyer i_dlstat_rx_local_stats(const char *linkname)
1590*0dc2366fSVenugopal Iyer {
1591*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*local_stats = NULL;
1592*0dc2366fSVenugopal Iyer 
1593*0dc2366fSVenugopal Iyer 	local_stats = i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_SWLANE,
1594*0dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size,
1595*0dc2366fSVenugopal Iyer 	    i_dlstat_rx_local_retrieve_stat);
1596*0dc2366fSVenugopal Iyer 
1597*0dc2366fSVenugopal Iyer 	if (local_stats != NULL) {
1598*0dc2366fSVenugopal Iyer 		(void) strlcpy(local_stats->dc_statheader, "mac_rx_local",
1599*0dc2366fSVenugopal Iyer 		    sizeof (local_stats->dc_statheader));
1600*0dc2366fSVenugopal Iyer 	}
1601*0dc2366fSVenugopal Iyer 	return (local_stats);
1602*0dc2366fSVenugopal Iyer }
1603*0dc2366fSVenugopal Iyer 
1604*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1605*0dc2366fSVenugopal Iyer i_dlstat_rx_bcast_stats(const char *linkname)
1606*0dc2366fSVenugopal Iyer {
1607*0dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
1608*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
1609*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1610*0dc2366fSVenugopal Iyer 
1611*0dc2366fSVenugopal Iyer 	misc_stat_entry = i_dlstat_misc_stats(linkname);
1612*0dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
1613*0dc2366fSVenugopal Iyer 		goto done;
1614*0dc2366fSVenugopal Iyer 
1615*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1616*0dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
1617*0dc2366fSVenugopal Iyer 		goto done;
1618*0dc2366fSVenugopal Iyer 
1619*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1620*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_BCAST;
1621*0dc2366fSVenugopal Iyer 
1622*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets =
1623*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstrcv +
1624*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multircv;
1625*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_intrs =
1626*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstrcv +
1627*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multircv;
1628*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes =
1629*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstrcvbytes +
1630*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multircvbytes;
1631*0dc2366fSVenugopal Iyer 
1632*0dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
1633*0dc2366fSVenugopal Iyer 	if (head == NULL) {
1634*0dc2366fSVenugopal Iyer 		free(rx_lane_stat_entry);
1635*0dc2366fSVenugopal Iyer 		goto done;
1636*0dc2366fSVenugopal Iyer 	}
1637*0dc2366fSVenugopal Iyer 
1638*0dc2366fSVenugopal Iyer 	head->dc_statentry = rx_lane_stat_entry;
1639*0dc2366fSVenugopal Iyer 	head->dc_next = NULL;
1640*0dc2366fSVenugopal Iyer 
1641*0dc2366fSVenugopal Iyer 	free(misc_stat_entry);
1642*0dc2366fSVenugopal Iyer done:
1643*0dc2366fSVenugopal Iyer 	return (head);
1644*0dc2366fSVenugopal Iyer }
1645*0dc2366fSVenugopal Iyer 
1646*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1647*0dc2366fSVenugopal Iyer i_dlstat_rx_defunctlane_stats(const char *linkname)
1648*0dc2366fSVenugopal Iyer {
1649*0dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
1650*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
1651*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1652*0dc2366fSVenugopal Iyer 
1653*0dc2366fSVenugopal Iyer 	misc_stat_entry = i_dlstat_misc_stats(linkname);
1654*0dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
1655*0dc2366fSVenugopal Iyer 		goto done;
1656*0dc2366fSVenugopal Iyer 
1657*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1658*0dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
1659*0dc2366fSVenugopal Iyer 		goto done;
1660*0dc2366fSVenugopal Iyer 
1661*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1662*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_DFNCT;
1663*0dc2366fSVenugopal Iyer 
1664*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets =
1665*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_ipackets;
1666*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes =
1667*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_rbytes;
1668*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_intrs =
1669*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_intrs;
1670*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_polls =
1671*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_polls;
1672*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_sdrops =
1673*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_rxsdrops;
1674*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_chl10 =
1675*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_chainunder10;
1676*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ch10_50 =
1677*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_chain10to50;
1678*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_chg50 =
1679*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_chainover50;
1680*0dc2366fSVenugopal Iyer 
1681*0dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
1682*0dc2366fSVenugopal Iyer 	if (head == NULL) {
1683*0dc2366fSVenugopal Iyer 		free(rx_lane_stat_entry);
1684*0dc2366fSVenugopal Iyer 		goto done;
1685*0dc2366fSVenugopal Iyer 	}
1686*0dc2366fSVenugopal Iyer 
1687*0dc2366fSVenugopal Iyer 	head->dc_statentry = rx_lane_stat_entry;
1688*0dc2366fSVenugopal Iyer 	head->dc_next = NULL;
1689*0dc2366fSVenugopal Iyer 
1690*0dc2366fSVenugopal Iyer done:
1691*0dc2366fSVenugopal Iyer 	return (head);
1692*0dc2366fSVenugopal Iyer }
1693*0dc2366fSVenugopal Iyer 
1694*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1695*0dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_stats(const char *linkname)
1696*0dc2366fSVenugopal Iyer {
1697*0dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1698*0dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist_size;
1699*0dc2366fSVenugopal Iyer 
1700*0dc2366fSVenugopal Iyer 	i_dlstat_get_idlist(linkname, DLSTAT_RX_HWLANE_IDLIST,
1701*0dc2366fSVenugopal Iyer 	    rx_hwlane_idlist, &rx_hwlane_idlist_size);
1702*0dc2366fSVenugopal Iyer 
1703*0dc2366fSVenugopal Iyer 	return (i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_HWLANE,
1704*0dc2366fSVenugopal Iyer 	    rx_hwlane_idlist, rx_hwlane_idlist_size,
1705*0dc2366fSVenugopal Iyer 	    i_dlstat_rx_hwlane_retrieve_stat));
1706*0dc2366fSVenugopal Iyer }
1707*0dc2366fSVenugopal Iyer 
1708*0dc2366fSVenugopal Iyer /*ARGSUSED*/
1709*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1710*0dc2366fSVenugopal Iyer i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1711*0dc2366fSVenugopal Iyer     const char *linkname)
1712*0dc2366fSVenugopal Iyer {
1713*0dc2366fSVenugopal Iyer 	return (i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_SWLANE,
1714*0dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size,
1715*0dc2366fSVenugopal Iyer 	    i_dlstat_rx_swlane_retrieve_stat));
1716*0dc2366fSVenugopal Iyer }
1717*0dc2366fSVenugopal Iyer 
1718*0dc2366fSVenugopal Iyer void *
1719*0dc2366fSVenugopal Iyer dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1720*0dc2366fSVenugopal Iyer {
1721*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
1722*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t 	*local_stats = NULL;
1723*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t 	*bcast_stats = NULL;
1724*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t 	*defunctlane_stats = NULL;
1725*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t 	*lane_stats = NULL;
1726*0dc2366fSVenugopal Iyer 	char 			linkname[MAXLINKNAMELEN];
1727*0dc2366fSVenugopal Iyer 	boolean_t		is_legacy_driver;
1728*0dc2366fSVenugopal Iyer 
1729*0dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1730*0dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1731*0dc2366fSVenugopal Iyer 		goto done;
1732*0dc2366fSVenugopal Iyer 	}
1733*0dc2366fSVenugopal Iyer 
1734*0dc2366fSVenugopal Iyer 	/* Check if it is legacy driver */
1735*0dc2366fSVenugopal Iyer 	if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1736*0dc2366fSVenugopal Iyer 	    "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1737*0dc2366fSVenugopal Iyer 		goto done;
1738*0dc2366fSVenugopal Iyer 	}
1739*0dc2366fSVenugopal Iyer 
1740*0dc2366fSVenugopal Iyer 	if (is_legacy_driver) {
1741*0dc2366fSVenugopal Iyer 		head = i_dlstat_legacy_rx_lane_stats(linkname);
1742*0dc2366fSVenugopal Iyer 		goto done;
1743*0dc2366fSVenugopal Iyer 	}
1744*0dc2366fSVenugopal Iyer 
1745*0dc2366fSVenugopal Iyer 	local_stats = i_dlstat_rx_local_stats(linkname);
1746*0dc2366fSVenugopal Iyer 	bcast_stats = i_dlstat_rx_bcast_stats(linkname);
1747*0dc2366fSVenugopal Iyer 	defunctlane_stats = i_dlstat_rx_defunctlane_stats(linkname);
1748*0dc2366fSVenugopal Iyer 	lane_stats = i_dlstat_rx_hwlane_stats(linkname);
1749*0dc2366fSVenugopal Iyer 	if (lane_stats == NULL)
1750*0dc2366fSVenugopal Iyer 		lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname);
1751*0dc2366fSVenugopal Iyer 
1752*0dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(local_stats, bcast_stats);
1753*0dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(head, defunctlane_stats);
1754*0dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(head, lane_stats);
1755*0dc2366fSVenugopal Iyer done:
1756*0dc2366fSVenugopal Iyer 	return (head);
1757*0dc2366fSVenugopal Iyer }
1758*0dc2366fSVenugopal Iyer 
1759*0dc2366fSVenugopal Iyer /* Tx lane statistic specific functions */
1760*0dc2366fSVenugopal Iyer static boolean_t
1761*0dc2366fSVenugopal Iyer i_dlstat_tx_lane_match(void *arg1, void *arg2)
1762*0dc2366fSVenugopal Iyer {
1763*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s1 = arg1;
1764*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s2 = arg2;
1765*0dc2366fSVenugopal Iyer 
1766*0dc2366fSVenugopal Iyer 	return (s1->tle_index == s2->tle_index &&
1767*0dc2366fSVenugopal Iyer 	    s1->tle_id == s2->tle_id);
1768*0dc2366fSVenugopal Iyer }
1769*0dc2366fSVenugopal Iyer 
1770*0dc2366fSVenugopal Iyer static void *
1771*0dc2366fSVenugopal Iyer i_dlstat_tx_lane_stat_entry_diff(void *arg1, void *arg2)
1772*0dc2366fSVenugopal Iyer {
1773*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s1 = arg1;
1774*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s2 = arg2;
1775*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *diff_entry;
1776*0dc2366fSVenugopal Iyer 
1777*0dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (tx_lane_stat_entry_t));
1778*0dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
1779*0dc2366fSVenugopal Iyer 		goto done;
1780*0dc2366fSVenugopal Iyer 
1781*0dc2366fSVenugopal Iyer 	diff_entry->tle_index = s1->tle_index;
1782*0dc2366fSVenugopal Iyer 	diff_entry->tle_id = s1->tle_id;
1783*0dc2366fSVenugopal Iyer 
1784*0dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, tle_stats, tx_lane_stats_list,
1785*0dc2366fSVenugopal Iyer 	    TX_LANE_STAT_SIZE);
1786*0dc2366fSVenugopal Iyer 
1787*0dc2366fSVenugopal Iyer done:
1788*0dc2366fSVenugopal Iyer 	return (diff_entry);
1789*0dc2366fSVenugopal Iyer }
1790*0dc2366fSVenugopal Iyer 
1791*0dc2366fSVenugopal Iyer static void *
1792*0dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1793*0dc2366fSVenugopal Iyer {
1794*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
1795*0dc2366fSVenugopal Iyer 
1796*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1797*0dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
1798*0dc2366fSVenugopal Iyer 		goto done;
1799*0dc2366fSVenugopal Iyer 
1800*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index	= i;
1801*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id	= L_HWLANE;
1802*0dc2366fSVenugopal Iyer 
1803*0dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
1804*0dc2366fSVenugopal Iyer 	    tx_lane_stats_list, TX_LANE_STAT_SIZE);
1805*0dc2366fSVenugopal Iyer 
1806*0dc2366fSVenugopal Iyer done:
1807*0dc2366fSVenugopal Iyer 	return (tx_lane_stat_entry);
1808*0dc2366fSVenugopal Iyer }
1809*0dc2366fSVenugopal Iyer 
1810*0dc2366fSVenugopal Iyer /*ARGSUSED*/
1811*0dc2366fSVenugopal Iyer static void *
1812*0dc2366fSVenugopal Iyer i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1813*0dc2366fSVenugopal Iyer {
1814*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
1815*0dc2366fSVenugopal Iyer 
1816*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1817*0dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
1818*0dc2366fSVenugopal Iyer 		goto done;
1819*0dc2366fSVenugopal Iyer 
1820*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1821*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_SWLANE;
1822*0dc2366fSVenugopal Iyer 
1823*0dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
1824*0dc2366fSVenugopal Iyer 	    tx_lane_stats_list, TX_LANE_STAT_SIZE);
1825*0dc2366fSVenugopal Iyer 
1826*0dc2366fSVenugopal Iyer done:
1827*0dc2366fSVenugopal Iyer 	return (tx_lane_stat_entry);
1828*0dc2366fSVenugopal Iyer }
1829*0dc2366fSVenugopal Iyer 
1830*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1831*0dc2366fSVenugopal Iyer i_dlstat_tx_bcast_stats(const char *linkname)
1832*0dc2366fSVenugopal Iyer {
1833*0dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
1834*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
1835*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
1836*0dc2366fSVenugopal Iyer 
1837*0dc2366fSVenugopal Iyer 	misc_stat_entry = i_dlstat_misc_stats(linkname);
1838*0dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
1839*0dc2366fSVenugopal Iyer 		goto done;
1840*0dc2366fSVenugopal Iyer 
1841*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1842*0dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
1843*0dc2366fSVenugopal Iyer 		goto done;
1844*0dc2366fSVenugopal Iyer 
1845*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1846*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_BCAST;
1847*0dc2366fSVenugopal Iyer 
1848*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_opackets =
1849*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstxmt +
1850*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multixmt;
1851*0dc2366fSVenugopal Iyer 
1852*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_obytes =
1853*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstxmtbytes +
1854*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multixmtbytes;
1855*0dc2366fSVenugopal Iyer 
1856*0dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
1857*0dc2366fSVenugopal Iyer 	if (head == NULL) {
1858*0dc2366fSVenugopal Iyer 		free(tx_lane_stat_entry);
1859*0dc2366fSVenugopal Iyer 		goto done;
1860*0dc2366fSVenugopal Iyer 	}
1861*0dc2366fSVenugopal Iyer 
1862*0dc2366fSVenugopal Iyer 	head->dc_statentry = tx_lane_stat_entry;
1863*0dc2366fSVenugopal Iyer 	head->dc_next = NULL;
1864*0dc2366fSVenugopal Iyer 
1865*0dc2366fSVenugopal Iyer 	free(misc_stat_entry);
1866*0dc2366fSVenugopal Iyer done:
1867*0dc2366fSVenugopal Iyer 	return (head);
1868*0dc2366fSVenugopal Iyer }
1869*0dc2366fSVenugopal Iyer 
1870*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1871*0dc2366fSVenugopal Iyer i_dlstat_tx_defunctlane_stats(const char *linkname)
1872*0dc2366fSVenugopal Iyer {
1873*0dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
1874*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
1875*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
1876*0dc2366fSVenugopal Iyer 
1877*0dc2366fSVenugopal Iyer 	misc_stat_entry = i_dlstat_misc_stats(linkname);
1878*0dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
1879*0dc2366fSVenugopal Iyer 		goto done;
1880*0dc2366fSVenugopal Iyer 
1881*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1882*0dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
1883*0dc2366fSVenugopal Iyer 		goto done;
1884*0dc2366fSVenugopal Iyer 
1885*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1886*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_DFNCT;
1887*0dc2366fSVenugopal Iyer 
1888*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_opackets =
1889*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_opackets;
1890*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_obytes =
1891*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_obytes;
1892*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_sdrops =
1893*0dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_txsdrops;
1894*0dc2366fSVenugopal Iyer 
1895*0dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
1896*0dc2366fSVenugopal Iyer 	if (head == NULL) {
1897*0dc2366fSVenugopal Iyer 		free(tx_lane_stat_entry);
1898*0dc2366fSVenugopal Iyer 		goto done;
1899*0dc2366fSVenugopal Iyer 	}
1900*0dc2366fSVenugopal Iyer 
1901*0dc2366fSVenugopal Iyer 	head->dc_statentry = tx_lane_stat_entry;
1902*0dc2366fSVenugopal Iyer 	head->dc_next = NULL;
1903*0dc2366fSVenugopal Iyer 
1904*0dc2366fSVenugopal Iyer done:
1905*0dc2366fSVenugopal Iyer 	return (head);
1906*0dc2366fSVenugopal Iyer }
1907*0dc2366fSVenugopal Iyer 
1908*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1909*0dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_stats(const char *linkname)
1910*0dc2366fSVenugopal Iyer {
1911*0dc2366fSVenugopal Iyer 	uint_t	tx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1912*0dc2366fSVenugopal Iyer 	uint_t	tx_hwlane_idlist_size;
1913*0dc2366fSVenugopal Iyer 
1914*0dc2366fSVenugopal Iyer 	i_dlstat_get_idlist(linkname, DLSTAT_TX_HWLANE_IDLIST,
1915*0dc2366fSVenugopal Iyer 	    tx_hwlane_idlist, &tx_hwlane_idlist_size);
1916*0dc2366fSVenugopal Iyer 
1917*0dc2366fSVenugopal Iyer 	return (i_dlstat_query_stats(linkname, DLSTAT_MAC_TX_HWLANE,
1918*0dc2366fSVenugopal Iyer 	    tx_hwlane_idlist, tx_hwlane_idlist_size,
1919*0dc2366fSVenugopal Iyer 	    i_dlstat_tx_hwlane_retrieve_stat));
1920*0dc2366fSVenugopal Iyer }
1921*0dc2366fSVenugopal Iyer 
1922*0dc2366fSVenugopal Iyer /*ARGSUSED*/
1923*0dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1924*0dc2366fSVenugopal Iyer i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1925*0dc2366fSVenugopal Iyer     const char *linkname)
1926*0dc2366fSVenugopal Iyer {
1927*0dc2366fSVenugopal Iyer 	return (i_dlstat_query_stats(linkname, DLSTAT_MAC_TX_SWLANE,
1928*0dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size,
1929*0dc2366fSVenugopal Iyer 	    i_dlstat_tx_swlane_retrieve_stat));
1930*0dc2366fSVenugopal Iyer }
1931*0dc2366fSVenugopal Iyer 
1932*0dc2366fSVenugopal Iyer void *
1933*0dc2366fSVenugopal Iyer dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1934*0dc2366fSVenugopal Iyer {
1935*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
1936*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t 	*bcast_stats = NULL;
1937*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t 	*defunctlane_stats = NULL;
1938*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t 	*lane_stats;
1939*0dc2366fSVenugopal Iyer 	char 			linkname[MAXLINKNAMELEN];
1940*0dc2366fSVenugopal Iyer 	boolean_t		is_legacy_driver;
1941*0dc2366fSVenugopal Iyer 
1942*0dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1943*0dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1944*0dc2366fSVenugopal Iyer 		goto done;
1945*0dc2366fSVenugopal Iyer 	}
1946*0dc2366fSVenugopal Iyer 
1947*0dc2366fSVenugopal Iyer 	/* Check if it is legacy driver */
1948*0dc2366fSVenugopal Iyer 	if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1949*0dc2366fSVenugopal Iyer 	    "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1950*0dc2366fSVenugopal Iyer 		goto done;
1951*0dc2366fSVenugopal Iyer 	}
1952*0dc2366fSVenugopal Iyer 
1953*0dc2366fSVenugopal Iyer 	if (is_legacy_driver) {
1954*0dc2366fSVenugopal Iyer 		head = i_dlstat_legacy_tx_lane_stats(linkname);
1955*0dc2366fSVenugopal Iyer 		goto done;
1956*0dc2366fSVenugopal Iyer 	}
1957*0dc2366fSVenugopal Iyer 
1958*0dc2366fSVenugopal Iyer 	bcast_stats = i_dlstat_tx_bcast_stats(linkname);
1959*0dc2366fSVenugopal Iyer 	defunctlane_stats = i_dlstat_tx_defunctlane_stats(linkname);
1960*0dc2366fSVenugopal Iyer 	lane_stats = i_dlstat_tx_hwlane_stats(linkname);
1961*0dc2366fSVenugopal Iyer 	if (lane_stats == NULL)
1962*0dc2366fSVenugopal Iyer 		lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname);
1963*0dc2366fSVenugopal Iyer 
1964*0dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(bcast_stats, defunctlane_stats);
1965*0dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(head, lane_stats);
1966*0dc2366fSVenugopal Iyer 
1967*0dc2366fSVenugopal Iyer done:
1968*0dc2366fSVenugopal Iyer 	return (head);
1969*0dc2366fSVenugopal Iyer }
1970*0dc2366fSVenugopal Iyer 
1971*0dc2366fSVenugopal Iyer /* Rx lane total statistic specific functions */
1972*0dc2366fSVenugopal Iyer void *
1973*0dc2366fSVenugopal Iyer dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1974*0dc2366fSVenugopal Iyer {
1975*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
1976*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*rx_lane_head, *curr;
1977*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*total_stats;
1978*0dc2366fSVenugopal Iyer 
1979*0dc2366fSVenugopal Iyer 	/* Get per rx lane stats */
1980*0dc2366fSVenugopal Iyer 	rx_lane_head = dlstat_rx_lane_stats(dh, linkid);
1981*0dc2366fSVenugopal Iyer 	if (rx_lane_head == NULL)
1982*0dc2366fSVenugopal Iyer 		goto done;
1983*0dc2366fSVenugopal Iyer 
1984*0dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (rx_lane_stat_entry_t));
1985*0dc2366fSVenugopal Iyer 	if (total_stats == NULL)
1986*0dc2366fSVenugopal Iyer 		goto done;
1987*0dc2366fSVenugopal Iyer 
1988*0dc2366fSVenugopal Iyer 	total_stats->rle_index = DLSTAT_INVALID_ENTRY;
1989*0dc2366fSVenugopal Iyer 	total_stats->rle_id = DLSTAT_INVALID_ENTRY;
1990*0dc2366fSVenugopal Iyer 
1991*0dc2366fSVenugopal Iyer 	for (curr = rx_lane_head; curr != NULL; curr = curr->dc_next) {
1992*0dc2366fSVenugopal Iyer 		rx_lane_stat_entry_t	*curr_lane_stats = curr->dc_statentry;
1993*0dc2366fSVenugopal Iyer 
1994*0dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->rle_stats,
1995*0dc2366fSVenugopal Iyer 		    &curr_lane_stats->rle_stats, &total_stats->rle_stats,
1996*0dc2366fSVenugopal Iyer 		    rx_lane_stats_list, RX_LANE_STAT_SIZE);
1997*0dc2366fSVenugopal Iyer 	}
1998*0dc2366fSVenugopal Iyer 
1999*0dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
2000*0dc2366fSVenugopal Iyer 	if (total_head == NULL) {
2001*0dc2366fSVenugopal Iyer 		free(total_stats);
2002*0dc2366fSVenugopal Iyer 		goto done;
2003*0dc2366fSVenugopal Iyer 	}
2004*0dc2366fSVenugopal Iyer 
2005*0dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
2006*0dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_rx_lane_total",
2007*0dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
2008*0dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
2009*0dc2366fSVenugopal Iyer 	free(rx_lane_head);
2010*0dc2366fSVenugopal Iyer 
2011*0dc2366fSVenugopal Iyer done:
2012*0dc2366fSVenugopal Iyer 	return (total_head);
2013*0dc2366fSVenugopal Iyer }
2014*0dc2366fSVenugopal Iyer 
2015*0dc2366fSVenugopal Iyer /* Tx lane total statistic specific functions */
2016*0dc2366fSVenugopal Iyer void *
2017*0dc2366fSVenugopal Iyer dlstat_tx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
2018*0dc2366fSVenugopal Iyer {
2019*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
2020*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*tx_lane_head, *curr;
2021*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*total_stats;
2022*0dc2366fSVenugopal Iyer 
2023*0dc2366fSVenugopal Iyer 	/* Get per tx lane stats */
2024*0dc2366fSVenugopal Iyer 	tx_lane_head = dlstat_tx_lane_stats(dh, linkid);
2025*0dc2366fSVenugopal Iyer 	if (tx_lane_head == NULL)
2026*0dc2366fSVenugopal Iyer 		goto done;
2027*0dc2366fSVenugopal Iyer 
2028*0dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (tx_lane_stat_entry_t));
2029*0dc2366fSVenugopal Iyer 	if (total_stats == NULL)
2030*0dc2366fSVenugopal Iyer 		goto done;
2031*0dc2366fSVenugopal Iyer 
2032*0dc2366fSVenugopal Iyer 	total_stats->tle_index = DLSTAT_INVALID_ENTRY;
2033*0dc2366fSVenugopal Iyer 	total_stats->tle_id = DLSTAT_INVALID_ENTRY;
2034*0dc2366fSVenugopal Iyer 
2035*0dc2366fSVenugopal Iyer 	for (curr = tx_lane_head; curr != NULL; curr = curr->dc_next) {
2036*0dc2366fSVenugopal Iyer 		tx_lane_stat_entry_t	*curr_lane_stats = curr->dc_statentry;
2037*0dc2366fSVenugopal Iyer 
2038*0dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->tle_stats,
2039*0dc2366fSVenugopal Iyer 		    &curr_lane_stats->tle_stats, &total_stats->tle_stats,
2040*0dc2366fSVenugopal Iyer 		    tx_lane_stats_list, TX_LANE_STAT_SIZE);
2041*0dc2366fSVenugopal Iyer 	}
2042*0dc2366fSVenugopal Iyer 
2043*0dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
2044*0dc2366fSVenugopal Iyer 	if (total_head == NULL) {
2045*0dc2366fSVenugopal Iyer 		free(total_stats);
2046*0dc2366fSVenugopal Iyer 		goto done;
2047*0dc2366fSVenugopal Iyer 	}
2048*0dc2366fSVenugopal Iyer 
2049*0dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
2050*0dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_tx_lane_total",
2051*0dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
2052*0dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
2053*0dc2366fSVenugopal Iyer 	free(tx_lane_head);
2054*0dc2366fSVenugopal Iyer 
2055*0dc2366fSVenugopal Iyer done:
2056*0dc2366fSVenugopal Iyer 	return (total_head);
2057*0dc2366fSVenugopal Iyer }
2058*0dc2366fSVenugopal Iyer 
2059*0dc2366fSVenugopal Iyer /* Fanout specific functions */
2060*0dc2366fSVenugopal Iyer static boolean_t
2061*0dc2366fSVenugopal Iyer i_dlstat_fanout_match(void *arg1, void *arg2)
2062*0dc2366fSVenugopal Iyer {
2063*0dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s1 = arg1;
2064*0dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s2 = arg2;
2065*0dc2366fSVenugopal Iyer 
2066*0dc2366fSVenugopal Iyer 	return (s1->fe_index == s2->fe_index &&
2067*0dc2366fSVenugopal Iyer 	    s1->fe_id == s2->fe_id &&
2068*0dc2366fSVenugopal Iyer 	    s1->fe_foutindex == s2->fe_foutindex);
2069*0dc2366fSVenugopal Iyer }
2070*0dc2366fSVenugopal Iyer 
2071*0dc2366fSVenugopal Iyer static void *
2072*0dc2366fSVenugopal Iyer i_dlstat_fanout_stat_entry_diff(void *arg1, void *arg2)
2073*0dc2366fSVenugopal Iyer {
2074*0dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s1 = arg1;
2075*0dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s2 = arg2;
2076*0dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*diff_entry;
2077*0dc2366fSVenugopal Iyer 
2078*0dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (fanout_stat_entry_t));
2079*0dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
2080*0dc2366fSVenugopal Iyer 		goto done;
2081*0dc2366fSVenugopal Iyer 
2082*0dc2366fSVenugopal Iyer 	diff_entry->fe_index = s1->fe_index;
2083*0dc2366fSVenugopal Iyer 	diff_entry->fe_id = s1->fe_id;
2084*0dc2366fSVenugopal Iyer 	diff_entry->fe_foutindex = s1->fe_foutindex;
2085*0dc2366fSVenugopal Iyer 
2086*0dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, fe_stats, fanout_stats_list,
2087*0dc2366fSVenugopal Iyer 	    FANOUT_STAT_SIZE);
2088*0dc2366fSVenugopal Iyer 
2089*0dc2366fSVenugopal Iyer done:
2090*0dc2366fSVenugopal Iyer 	return (diff_entry);
2091*0dc2366fSVenugopal Iyer }
2092*0dc2366fSVenugopal Iyer 
2093*0dc2366fSVenugopal Iyer static void *
2094*0dc2366fSVenugopal Iyer i_dlstat_fanout_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
2095*0dc2366fSVenugopal Iyer {
2096*0dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*fanout_stat_entry;
2097*0dc2366fSVenugopal Iyer 
2098*0dc2366fSVenugopal Iyer 	fanout_stat_entry = calloc(1, sizeof (fanout_stat_entry_t));
2099*0dc2366fSVenugopal Iyer 	if (fanout_stat_entry == NULL)
2100*0dc2366fSVenugopal Iyer 		goto done;
2101*0dc2366fSVenugopal Iyer 
2102*0dc2366fSVenugopal Iyer 					/* Set by the caller later */
2103*0dc2366fSVenugopal Iyer 	fanout_stat_entry->fe_index = DLSTAT_INVALID_ENTRY;
2104*0dc2366fSVenugopal Iyer 	fanout_stat_entry->fe_id = DLSTAT_INVALID_ENTRY;
2105*0dc2366fSVenugopal Iyer 
2106*0dc2366fSVenugopal Iyer 	fanout_stat_entry->fe_foutindex = i;
2107*0dc2366fSVenugopal Iyer 
2108*0dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &fanout_stat_entry->fe_stats,
2109*0dc2366fSVenugopal Iyer 	    fanout_stats_list, FANOUT_STAT_SIZE);
2110*0dc2366fSVenugopal Iyer 
2111*0dc2366fSVenugopal Iyer done:
2112*0dc2366fSVenugopal Iyer 	return (fanout_stat_entry);
2113*0dc2366fSVenugopal Iyer }
2114*0dc2366fSVenugopal Iyer 
2115*0dc2366fSVenugopal Iyer static void *
2116*0dc2366fSVenugopal Iyer i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid,
2117*0dc2366fSVenugopal Iyer     uint_t idlist[], uint_t idlist_size,
2118*0dc2366fSVenugopal Iyer     const char *modname, const char *prefix)
2119*0dc2366fSVenugopal Iyer {
2120*0dc2366fSVenugopal Iyer 	int			i;
2121*0dc2366fSVenugopal Iyer 	char			statprefix[MAXLINKNAMELEN];
2122*0dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
2123*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr, *curr_head;
2124*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL, *prev = NULL;
2125*0dc2366fSVenugopal Iyer 	uint_t 			fanout_idlist[MAX_RINGS_PER_GROUP];
2126*0dc2366fSVenugopal Iyer 	uint_t 			fanout_idlist_size;
2127*0dc2366fSVenugopal Iyer 
2128*0dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
2129*0dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2130*0dc2366fSVenugopal Iyer 		return (NULL);
2131*0dc2366fSVenugopal Iyer 	}
2132*0dc2366fSVenugopal Iyer 
2133*0dc2366fSVenugopal Iyer 	i_dlstat_get_idlist(linkname, DLSTAT_FANOUT_IDLIST,
2134*0dc2366fSVenugopal Iyer 	    fanout_idlist, &fanout_idlist_size);
2135*0dc2366fSVenugopal Iyer 
2136*0dc2366fSVenugopal Iyer 	for (i = 0; i < idlist_size; i++) {
2137*0dc2366fSVenugopal Iyer 		uint_t	index = idlist[i];
2138*0dc2366fSVenugopal Iyer 
2139*0dc2366fSVenugopal Iyer 		(void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout",
2140*0dc2366fSVenugopal Iyer 		    prefix, index);
2141*0dc2366fSVenugopal Iyer 
2142*0dc2366fSVenugopal Iyer 		curr_head = i_dlstat_query_stats(modname, statprefix,
2143*0dc2366fSVenugopal Iyer 		    fanout_idlist, fanout_idlist_size,
2144*0dc2366fSVenugopal Iyer 		    i_dlstat_fanout_retrieve_stat);
2145*0dc2366fSVenugopal Iyer 
2146*0dc2366fSVenugopal Iyer 		if (curr_head == NULL)	/* Last lane */
2147*0dc2366fSVenugopal Iyer 			break;
2148*0dc2366fSVenugopal Iyer 
2149*0dc2366fSVenugopal Iyer 		if (head == NULL)	/* First lane */
2150*0dc2366fSVenugopal Iyer 			head = curr_head;
2151*0dc2366fSVenugopal Iyer 		else	/* Link new lane list to end of previous lane list */
2152*0dc2366fSVenugopal Iyer 			prev->dc_next = curr_head;
2153*0dc2366fSVenugopal Iyer 
2154*0dc2366fSVenugopal Iyer 		/* Walk new lane list and set ids */
2155*0dc2366fSVenugopal Iyer 		for (curr = curr_head; curr != NULL; curr = curr->dc_next) {
2156*0dc2366fSVenugopal Iyer 			fanout_stat_entry_t *curr_stats = curr->dc_statentry;
2157*0dc2366fSVenugopal Iyer 
2158*0dc2366fSVenugopal Iyer 			curr_stats->fe_index = index;
2159*0dc2366fSVenugopal Iyer 			curr_stats->fe_id = L_HWLANE;
2160*0dc2366fSVenugopal Iyer 			/*
2161*0dc2366fSVenugopal Iyer 			 * Save last pointer of previous linked list.
2162*0dc2366fSVenugopal Iyer 			 * This pointer is used to chain linked lists
2163*0dc2366fSVenugopal Iyer 			 * generated in each iteration.
2164*0dc2366fSVenugopal Iyer 			 */
2165*0dc2366fSVenugopal Iyer 			prev = curr;
2166*0dc2366fSVenugopal Iyer 		}
2167*0dc2366fSVenugopal Iyer 	}
2168*0dc2366fSVenugopal Iyer 
2169*0dc2366fSVenugopal Iyer 	return (head);
2170*0dc2366fSVenugopal Iyer }
2171*0dc2366fSVenugopal Iyer 
2172*0dc2366fSVenugopal Iyer void *
2173*0dc2366fSVenugopal Iyer dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid,
2174*0dc2366fSVenugopal Iyer     const char *linkname)
2175*0dc2366fSVenugopal Iyer {
2176*0dc2366fSVenugopal Iyer 	return (i_dlstat_query_fanout_stats(dh, linkid,
2177*0dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size, linkname,
2178*0dc2366fSVenugopal Iyer 	    DLSTAT_MAC_RX_SWLANE));
2179*0dc2366fSVenugopal Iyer }
2180*0dc2366fSVenugopal Iyer 
2181*0dc2366fSVenugopal Iyer void *
2182*0dc2366fSVenugopal Iyer dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid,
2183*0dc2366fSVenugopal Iyer     const char *linkname)
2184*0dc2366fSVenugopal Iyer {
2185*0dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
2186*0dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist_size;
2187*0dc2366fSVenugopal Iyer 
2188*0dc2366fSVenugopal Iyer 	i_dlstat_get_idlist(linkname, DLSTAT_RX_HWLANE_IDLIST,
2189*0dc2366fSVenugopal Iyer 	    rx_hwlane_idlist, &rx_hwlane_idlist_size);
2190*0dc2366fSVenugopal Iyer 
2191*0dc2366fSVenugopal Iyer 	return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist,
2192*0dc2366fSVenugopal Iyer 	    rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE));
2193*0dc2366fSVenugopal Iyer }
2194*0dc2366fSVenugopal Iyer 
2195*0dc2366fSVenugopal Iyer void *
2196*0dc2366fSVenugopal Iyer dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid)
2197*0dc2366fSVenugopal Iyer {
2198*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
2199*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*fout_hwlane_stats;
2200*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*fout_swlane_and_local_stats;
2201*0dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*fout_stats;
2202*0dc2366fSVenugopal Iyer 	char 			linkname[MAXLINKNAMELEN];
2203*0dc2366fSVenugopal Iyer 
2204*0dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
2205*0dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2206*0dc2366fSVenugopal Iyer 		goto done;
2207*0dc2366fSVenugopal Iyer 	}
2208*0dc2366fSVenugopal Iyer 
2209*0dc2366fSVenugopal Iyer 	fout_swlane_and_local_stats =
2210*0dc2366fSVenugopal Iyer 	    dlstat_fanout_swlane_and_local_stats(dh, linkid, linkname);
2211*0dc2366fSVenugopal Iyer 	fout_hwlane_stats = dlstat_fanout_hwlane_stats(dh, linkid, linkname);
2212*0dc2366fSVenugopal Iyer 
2213*0dc2366fSVenugopal Iyer 	if (fout_swlane_and_local_stats == NULL) {
2214*0dc2366fSVenugopal Iyer 		head = fout_hwlane_stats;
2215*0dc2366fSVenugopal Iyer 		goto done;
2216*0dc2366fSVenugopal Iyer 	}
2217*0dc2366fSVenugopal Iyer 
2218*0dc2366fSVenugopal Iyer 	fout_stats = fout_swlane_and_local_stats->dc_statentry;
2219*0dc2366fSVenugopal Iyer 
2220*0dc2366fSVenugopal Iyer 	if (fout_hwlane_stats != NULL) { /* hwlane(s), only local traffic */
2221*0dc2366fSVenugopal Iyer 		fout_stats->fe_id = L_LOCAL;
2222*0dc2366fSVenugopal Iyer 		fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
2223*0dc2366fSVenugopal Iyer 	} else { /* no hwlane, mix of local+sw classified */
2224*0dc2366fSVenugopal Iyer 		fout_stats->fe_id = L_LCLSWLANE;
2225*0dc2366fSVenugopal Iyer 		fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
2226*0dc2366fSVenugopal Iyer 	}
2227*0dc2366fSVenugopal Iyer 
2228*0dc2366fSVenugopal Iyer 	fout_swlane_and_local_stats->dc_next = fout_hwlane_stats;
2229*0dc2366fSVenugopal Iyer 	head = fout_swlane_and_local_stats;
2230*0dc2366fSVenugopal Iyer 
2231*0dc2366fSVenugopal Iyer done:
2232*0dc2366fSVenugopal Iyer 	return (head);
2233*0dc2366fSVenugopal Iyer }
2234*0dc2366fSVenugopal Iyer 
2235*0dc2366fSVenugopal Iyer /* Rx ring statistic specific functions */
2236*0dc2366fSVenugopal Iyer static boolean_t
2237*0dc2366fSVenugopal Iyer i_dlstat_rx_ring_match(void *arg1, void *arg2)
2238*0dc2366fSVenugopal Iyer {
2239*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*s1 = arg1;
2240*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*s2 = arg2;
2241*0dc2366fSVenugopal Iyer 
2242*0dc2366fSVenugopal Iyer 	return (s1->rle_index == s2->rle_index);
2243*0dc2366fSVenugopal Iyer }
2244*0dc2366fSVenugopal Iyer 
2245*0dc2366fSVenugopal Iyer static void *
2246*0dc2366fSVenugopal Iyer i_dlstat_rx_ring_stat_entry_diff(void *arg1, void *arg2)
2247*0dc2366fSVenugopal Iyer {
2248*0dc2366fSVenugopal Iyer 	ring_stat_entry_t 	*s1 = arg1;
2249*0dc2366fSVenugopal Iyer 	ring_stat_entry_t 	*s2 = arg2;
2250*0dc2366fSVenugopal Iyer 	ring_stat_entry_t 	*diff_entry;
2251*0dc2366fSVenugopal Iyer 
2252*0dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (ring_stat_entry_t));
2253*0dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
2254*0dc2366fSVenugopal Iyer 		goto done;
2255*0dc2366fSVenugopal Iyer 
2256*0dc2366fSVenugopal Iyer 	diff_entry->re_index	= s1->re_index;
2257*0dc2366fSVenugopal Iyer 
2258*0dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, rx_ring_stats_list,
2259*0dc2366fSVenugopal Iyer 	    RX_RING_STAT_SIZE);
2260*0dc2366fSVenugopal Iyer 
2261*0dc2366fSVenugopal Iyer done:
2262*0dc2366fSVenugopal Iyer 	return (diff_entry);
2263*0dc2366fSVenugopal Iyer }
2264*0dc2366fSVenugopal Iyer 
2265*0dc2366fSVenugopal Iyer static void *
2266*0dc2366fSVenugopal Iyer i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
2267*0dc2366fSVenugopal Iyer {
2268*0dc2366fSVenugopal Iyer 	ring_stat_entry_t	*rx_ring_stat_entry;
2269*0dc2366fSVenugopal Iyer 
2270*0dc2366fSVenugopal Iyer 	rx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
2271*0dc2366fSVenugopal Iyer 	if (rx_ring_stat_entry == NULL)
2272*0dc2366fSVenugopal Iyer 		goto done;
2273*0dc2366fSVenugopal Iyer 
2274*0dc2366fSVenugopal Iyer 	rx_ring_stat_entry->re_index	= i;
2275*0dc2366fSVenugopal Iyer 
2276*0dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_ring_stat_entry->re_stats,
2277*0dc2366fSVenugopal Iyer 	    rx_ring_stats_list, RX_RING_STAT_SIZE);
2278*0dc2366fSVenugopal Iyer 
2279*0dc2366fSVenugopal Iyer done:
2280*0dc2366fSVenugopal Iyer 	return (rx_ring_stat_entry);
2281*0dc2366fSVenugopal Iyer }
2282*0dc2366fSVenugopal Iyer 
2283*0dc2366fSVenugopal Iyer void *
2284*0dc2366fSVenugopal Iyer dlstat_rx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
2285*0dc2366fSVenugopal Iyer {
2286*0dc2366fSVenugopal Iyer 	uint_t			rx_ring_idlist[MAX_RINGS_PER_GROUP];
2287*0dc2366fSVenugopal Iyer 	uint_t			rx_ring_idlist_size;
2288*0dc2366fSVenugopal Iyer 	dladm_phys_attr_t	dpa;
2289*0dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
2290*0dc2366fSVenugopal Iyer 	char			*modname;
2291*0dc2366fSVenugopal Iyer 	datalink_class_t	class;
2292*0dc2366fSVenugopal Iyer 
2293*0dc2366fSVenugopal Iyer 	/*
2294*0dc2366fSVenugopal Iyer 	 * kstats corresponding to physical device rings continue to use
2295*0dc2366fSVenugopal Iyer 	 * device names even if the link is renamed using dladm rename-link.
2296*0dc2366fSVenugopal Iyer 	 * Thus, given a linkid, we lookup the physical device name.
2297*0dc2366fSVenugopal Iyer 	 * However, if an aggr is renamed, kstats corresponding to its
2298*0dc2366fSVenugopal Iyer 	 * pseudo rings are renamed as well.
2299*0dc2366fSVenugopal Iyer 	 */
2300*0dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
2301*0dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2302*0dc2366fSVenugopal Iyer 		return (NULL);
2303*0dc2366fSVenugopal Iyer 	}
2304*0dc2366fSVenugopal Iyer 
2305*0dc2366fSVenugopal Iyer 	if (class != DATALINK_CLASS_AGGR) {
2306*0dc2366fSVenugopal Iyer 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
2307*0dc2366fSVenugopal Iyer 		    DLADM_STATUS_OK) {
2308*0dc2366fSVenugopal Iyer 			return (NULL);
2309*0dc2366fSVenugopal Iyer 		}
2310*0dc2366fSVenugopal Iyer 		modname = dpa.dp_dev;
2311*0dc2366fSVenugopal Iyer 	} else
2312*0dc2366fSVenugopal Iyer 		modname = linkname;
2313*0dc2366fSVenugopal Iyer 
2314*0dc2366fSVenugopal Iyer 	i_dlstat_get_idlist(modname, DLSTAT_RX_RING_IDLIST,
2315*0dc2366fSVenugopal Iyer 	    rx_ring_idlist, &rx_ring_idlist_size);
2316*0dc2366fSVenugopal Iyer 
2317*0dc2366fSVenugopal Iyer 	return (i_dlstat_query_stats(modname, DLSTAT_MAC_RX_RING,
2318*0dc2366fSVenugopal Iyer 	    rx_ring_idlist, rx_ring_idlist_size,
2319*0dc2366fSVenugopal Iyer 	    i_dlstat_rx_ring_retrieve_stat));
2320*0dc2366fSVenugopal Iyer }
2321*0dc2366fSVenugopal Iyer 
2322*0dc2366fSVenugopal Iyer /* Tx ring statistic specific functions */
2323*0dc2366fSVenugopal Iyer static boolean_t
2324*0dc2366fSVenugopal Iyer i_dlstat_tx_ring_match(void *arg1, void *arg2)
2325*0dc2366fSVenugopal Iyer {
2326*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*s1 = arg1;
2327*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*s2 = arg2;
2328*0dc2366fSVenugopal Iyer 
2329*0dc2366fSVenugopal Iyer 	return (s1->tle_index == s2->tle_index);
2330*0dc2366fSVenugopal Iyer }
2331*0dc2366fSVenugopal Iyer 
2332*0dc2366fSVenugopal Iyer static void *
2333*0dc2366fSVenugopal Iyer i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2)
2334*0dc2366fSVenugopal Iyer {
2335*0dc2366fSVenugopal Iyer 	ring_stat_entry_t	*s1 = arg1;
2336*0dc2366fSVenugopal Iyer 	ring_stat_entry_t	*s2 = arg2;
2337*0dc2366fSVenugopal Iyer 	ring_stat_entry_t	*diff_entry;
2338*0dc2366fSVenugopal Iyer 
2339*0dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (ring_stat_entry_t));
2340*0dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
2341*0dc2366fSVenugopal Iyer 		goto done;
2342*0dc2366fSVenugopal Iyer 
2343*0dc2366fSVenugopal Iyer 	diff_entry->re_index	= s1->re_index;
2344*0dc2366fSVenugopal Iyer 
2345*0dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, tx_ring_stats_list,
2346*0dc2366fSVenugopal Iyer 	    TX_RING_STAT_SIZE);
2347*0dc2366fSVenugopal Iyer 
2348*0dc2366fSVenugopal Iyer done:
2349*0dc2366fSVenugopal Iyer 	return (diff_entry);
2350*0dc2366fSVenugopal Iyer }
2351*0dc2366fSVenugopal Iyer 
2352*0dc2366fSVenugopal Iyer static void *
2353*0dc2366fSVenugopal Iyer i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
2354*0dc2366fSVenugopal Iyer {
2355*0dc2366fSVenugopal Iyer 	ring_stat_entry_t	*tx_ring_stat_entry;
2356*0dc2366fSVenugopal Iyer 
2357*0dc2366fSVenugopal Iyer 	tx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
2358*0dc2366fSVenugopal Iyer 	if (tx_ring_stat_entry == NULL)
2359*0dc2366fSVenugopal Iyer 		goto done;
2360*0dc2366fSVenugopal Iyer 
2361*0dc2366fSVenugopal Iyer 	tx_ring_stat_entry->re_index	= i;
2362*0dc2366fSVenugopal Iyer 
2363*0dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &tx_ring_stat_entry->re_stats,
2364*0dc2366fSVenugopal Iyer 	    tx_ring_stats_list, TX_RING_STAT_SIZE);
2365*0dc2366fSVenugopal Iyer 
2366*0dc2366fSVenugopal Iyer done:
2367*0dc2366fSVenugopal Iyer 	return (tx_ring_stat_entry);
2368*0dc2366fSVenugopal Iyer }
2369*0dc2366fSVenugopal Iyer 
2370*0dc2366fSVenugopal Iyer void *
2371*0dc2366fSVenugopal Iyer dlstat_tx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
2372*0dc2366fSVenugopal Iyer {
2373*0dc2366fSVenugopal Iyer 	uint_t			tx_ring_idlist[MAX_RINGS_PER_GROUP];
2374*0dc2366fSVenugopal Iyer 	uint_t			tx_ring_idlist_size;
2375*0dc2366fSVenugopal Iyer 	dladm_phys_attr_t	dpa;
2376*0dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
2377*0dc2366fSVenugopal Iyer 	char			*modname;
2378*0dc2366fSVenugopal Iyer 	datalink_class_t	class;
2379*0dc2366fSVenugopal Iyer 
2380*0dc2366fSVenugopal Iyer 	/*
2381*0dc2366fSVenugopal Iyer 	 * kstats corresponding to physical device rings continue to use
2382*0dc2366fSVenugopal Iyer 	 * device names even if the link is renamed using dladm rename-link.
2383*0dc2366fSVenugopal Iyer 	 * Thus, given a linkid, we lookup the physical device name.
2384*0dc2366fSVenugopal Iyer 	 * However, if an aggr is renamed, kstats corresponding to its
2385*0dc2366fSVenugopal Iyer 	 * pseudo rings are renamed as well.
2386*0dc2366fSVenugopal Iyer 	 */
2387*0dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
2388*0dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2389*0dc2366fSVenugopal Iyer 		return (NULL);
2390*0dc2366fSVenugopal Iyer 	}
2391*0dc2366fSVenugopal Iyer 
2392*0dc2366fSVenugopal Iyer 	if (class != DATALINK_CLASS_AGGR) {
2393*0dc2366fSVenugopal Iyer 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
2394*0dc2366fSVenugopal Iyer 		    DLADM_STATUS_OK) {
2395*0dc2366fSVenugopal Iyer 			return (NULL);
2396*0dc2366fSVenugopal Iyer 		}
2397*0dc2366fSVenugopal Iyer 		modname = dpa.dp_dev;
2398*0dc2366fSVenugopal Iyer 	} else
2399*0dc2366fSVenugopal Iyer 		modname = linkname;
2400*0dc2366fSVenugopal Iyer 
2401*0dc2366fSVenugopal Iyer 	i_dlstat_get_idlist(modname, DLSTAT_TX_RING_IDLIST,
2402*0dc2366fSVenugopal Iyer 	    tx_ring_idlist, &tx_ring_idlist_size);
2403*0dc2366fSVenugopal Iyer 
2404*0dc2366fSVenugopal Iyer 	return (i_dlstat_query_stats(modname, DLSTAT_MAC_TX_RING,
2405*0dc2366fSVenugopal Iyer 	    tx_ring_idlist, tx_ring_idlist_size,
2406*0dc2366fSVenugopal Iyer 	    i_dlstat_tx_ring_retrieve_stat));
2407*0dc2366fSVenugopal Iyer }
2408*0dc2366fSVenugopal Iyer 
2409*0dc2366fSVenugopal Iyer /* Rx ring total statistic specific functions */
2410*0dc2366fSVenugopal Iyer void *
2411*0dc2366fSVenugopal Iyer dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
2412*0dc2366fSVenugopal Iyer {
2413*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
2414*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*rx_ring_head, *curr;
2415*0dc2366fSVenugopal Iyer 	ring_stat_entry_t	*total_stats;
2416*0dc2366fSVenugopal Iyer 
2417*0dc2366fSVenugopal Iyer 	/* Get per rx ring stats */
2418*0dc2366fSVenugopal Iyer 	rx_ring_head = dlstat_rx_ring_stats(dh, linkid);
2419*0dc2366fSVenugopal Iyer 	if (rx_ring_head == NULL)
2420*0dc2366fSVenugopal Iyer 		goto done;
2421*0dc2366fSVenugopal Iyer 
2422*0dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (ring_stat_entry_t));
2423*0dc2366fSVenugopal Iyer 	if (total_stats == NULL)
2424*0dc2366fSVenugopal Iyer 		goto done;
2425*0dc2366fSVenugopal Iyer 
2426*0dc2366fSVenugopal Iyer 	total_stats->re_index = DLSTAT_INVALID_ENTRY;
2427*0dc2366fSVenugopal Iyer 
2428*0dc2366fSVenugopal Iyer 	for (curr = rx_ring_head; curr != NULL; curr = curr->dc_next) {
2429*0dc2366fSVenugopal Iyer 		ring_stat_entry_t	*curr_ring_stats = curr->dc_statentry;
2430*0dc2366fSVenugopal Iyer 
2431*0dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->re_stats,
2432*0dc2366fSVenugopal Iyer 		    &curr_ring_stats->re_stats, &total_stats->re_stats,
2433*0dc2366fSVenugopal Iyer 		    rx_ring_stats_list, RX_RING_STAT_SIZE);
2434*0dc2366fSVenugopal Iyer 	}
2435*0dc2366fSVenugopal Iyer 
2436*0dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
2437*0dc2366fSVenugopal Iyer 	if (total_head == NULL) {
2438*0dc2366fSVenugopal Iyer 		free(total_stats);
2439*0dc2366fSVenugopal Iyer 		goto done;
2440*0dc2366fSVenugopal Iyer 	}
2441*0dc2366fSVenugopal Iyer 
2442*0dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
2443*0dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_rx_ring_total",
2444*0dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
2445*0dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
2446*0dc2366fSVenugopal Iyer 	free(rx_ring_head);
2447*0dc2366fSVenugopal Iyer 
2448*0dc2366fSVenugopal Iyer done:
2449*0dc2366fSVenugopal Iyer 	return (total_head);
2450*0dc2366fSVenugopal Iyer }
2451*0dc2366fSVenugopal Iyer 
2452*0dc2366fSVenugopal Iyer /* Tx ring total statistic specific functions */
2453*0dc2366fSVenugopal Iyer void *
2454*0dc2366fSVenugopal Iyer dlstat_tx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
2455*0dc2366fSVenugopal Iyer {
2456*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
2457*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*tx_ring_head, *curr;
2458*0dc2366fSVenugopal Iyer 	ring_stat_entry_t	*total_stats;
2459*0dc2366fSVenugopal Iyer 
2460*0dc2366fSVenugopal Iyer 	/* Get per tx ring stats */
2461*0dc2366fSVenugopal Iyer 	tx_ring_head = dlstat_tx_ring_stats(dh, linkid);
2462*0dc2366fSVenugopal Iyer 	if (tx_ring_head == NULL)
2463*0dc2366fSVenugopal Iyer 		goto done;
2464*0dc2366fSVenugopal Iyer 
2465*0dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (ring_stat_entry_t));
2466*0dc2366fSVenugopal Iyer 	if (total_stats == NULL)
2467*0dc2366fSVenugopal Iyer 		goto done;
2468*0dc2366fSVenugopal Iyer 
2469*0dc2366fSVenugopal Iyer 	total_stats->re_index = DLSTAT_INVALID_ENTRY;
2470*0dc2366fSVenugopal Iyer 
2471*0dc2366fSVenugopal Iyer 	for (curr = tx_ring_head; curr != NULL; curr = curr->dc_next) {
2472*0dc2366fSVenugopal Iyer 		ring_stat_entry_t	*curr_ring_stats = curr->dc_statentry;
2473*0dc2366fSVenugopal Iyer 
2474*0dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->re_stats,
2475*0dc2366fSVenugopal Iyer 		    &curr_ring_stats->re_stats, &total_stats->re_stats,
2476*0dc2366fSVenugopal Iyer 		    tx_ring_stats_list, TX_RING_STAT_SIZE);
2477*0dc2366fSVenugopal Iyer 	}
2478*0dc2366fSVenugopal Iyer 
2479*0dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
2480*0dc2366fSVenugopal Iyer 	if (total_head == NULL) {
2481*0dc2366fSVenugopal Iyer 		free(total_stats);
2482*0dc2366fSVenugopal Iyer 		goto done;
2483*0dc2366fSVenugopal Iyer 	}
2484*0dc2366fSVenugopal Iyer 
2485*0dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
2486*0dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_tx_ring_total",
2487*0dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
2488*0dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
2489*0dc2366fSVenugopal Iyer 	free(tx_ring_head);
2490*0dc2366fSVenugopal Iyer 
2491*0dc2366fSVenugopal Iyer done:
2492*0dc2366fSVenugopal Iyer 	return (total_head);
2493*0dc2366fSVenugopal Iyer }
2494*0dc2366fSVenugopal Iyer 
2495*0dc2366fSVenugopal Iyer /* Summary statistic specific functions */
2496*0dc2366fSVenugopal Iyer /*ARGSUSED*/
2497*0dc2366fSVenugopal Iyer static boolean_t
2498*0dc2366fSVenugopal Iyer i_dlstat_total_match(void *arg1, void *arg2)
2499*0dc2366fSVenugopal Iyer {					/* Always single entry for total */
2500*0dc2366fSVenugopal Iyer 	return (B_TRUE);
2501*0dc2366fSVenugopal Iyer }
2502*0dc2366fSVenugopal Iyer 
2503*0dc2366fSVenugopal Iyer static void *
2504*0dc2366fSVenugopal Iyer i_dlstat_total_stat_entry_diff(void *arg1, void *arg2)
2505*0dc2366fSVenugopal Iyer {
2506*0dc2366fSVenugopal Iyer 	total_stat_entry_t	*s1 = arg1;
2507*0dc2366fSVenugopal Iyer 	total_stat_entry_t	*s2 = arg2;
2508*0dc2366fSVenugopal Iyer 	total_stat_entry_t	*diff_entry;
2509*0dc2366fSVenugopal Iyer 
2510*0dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (total_stat_entry_t));
2511*0dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
2512*0dc2366fSVenugopal Iyer 		goto done;
2513*0dc2366fSVenugopal Iyer 
2514*0dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, tse_stats, total_stats_list,
2515*0dc2366fSVenugopal Iyer 	    TOTAL_STAT_SIZE);
2516*0dc2366fSVenugopal Iyer 
2517*0dc2366fSVenugopal Iyer done:
2518*0dc2366fSVenugopal Iyer 	return (diff_entry);
2519*0dc2366fSVenugopal Iyer }
2520*0dc2366fSVenugopal Iyer 
2521*0dc2366fSVenugopal Iyer void *
2522*0dc2366fSVenugopal Iyer dlstat_total_stats(dladm_handle_t dh, datalink_id_t linkid)
2523*0dc2366fSVenugopal Iyer {
2524*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
2525*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*rx_total;
2526*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*tx_total;
2527*0dc2366fSVenugopal Iyer 	total_stat_entry_t	*total_stat_entry;
2528*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
2529*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
2530*0dc2366fSVenugopal Iyer 
2531*0dc2366fSVenugopal Iyer 	/* Get total rx lane stats */
2532*0dc2366fSVenugopal Iyer 	rx_total = dlstat_rx_lane_total_stats(dh, linkid);
2533*0dc2366fSVenugopal Iyer 	if (rx_total == NULL)
2534*0dc2366fSVenugopal Iyer 		goto done;
2535*0dc2366fSVenugopal Iyer 
2536*0dc2366fSVenugopal Iyer 	/* Get total tx lane stats */
2537*0dc2366fSVenugopal Iyer 	tx_total = dlstat_tx_lane_total_stats(dh, linkid);
2538*0dc2366fSVenugopal Iyer 	if (tx_total == NULL)
2539*0dc2366fSVenugopal Iyer 		goto done;
2540*0dc2366fSVenugopal Iyer 
2541*0dc2366fSVenugopal Iyer 	/* Build total stat */
2542*0dc2366fSVenugopal Iyer 	total_stat_entry = calloc(1, sizeof (total_stat_entry_t));
2543*0dc2366fSVenugopal Iyer 	if (total_stat_entry == NULL)
2544*0dc2366fSVenugopal Iyer 		goto done;
2545*0dc2366fSVenugopal Iyer 
2546*0dc2366fSVenugopal Iyer 	rx_lane_stat_entry = rx_total->dc_statentry;
2547*0dc2366fSVenugopal Iyer 	tx_lane_stat_entry = tx_total->dc_statentry;
2548*0dc2366fSVenugopal Iyer 
2549*0dc2366fSVenugopal Iyer 	/* Extract total rx ipackets, rbytes */
2550*0dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_ipackets =
2551*0dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_ipackets;
2552*0dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_rbytes =
2553*0dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_rbytes;
2554*0dc2366fSVenugopal Iyer 
2555*0dc2366fSVenugopal Iyer 	/* Extract total tx opackets, obytes */
2556*0dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_opackets =
2557*0dc2366fSVenugopal Iyer 	    tx_lane_stat_entry->tle_stats.tl_opackets;
2558*0dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_obytes =
2559*0dc2366fSVenugopal Iyer 	    tx_lane_stat_entry->tle_stats.tl_obytes;
2560*0dc2366fSVenugopal Iyer 
2561*0dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
2562*0dc2366fSVenugopal Iyer 	if (head == NULL) {
2563*0dc2366fSVenugopal Iyer 		free(total_stat_entry);
2564*0dc2366fSVenugopal Iyer 		goto done;
2565*0dc2366fSVenugopal Iyer 	}
2566*0dc2366fSVenugopal Iyer 
2567*0dc2366fSVenugopal Iyer 	head->dc_statentry = total_stat_entry;
2568*0dc2366fSVenugopal Iyer 	(void) strlcpy(head->dc_statheader, "mac_lane_total",
2569*0dc2366fSVenugopal Iyer 	    sizeof (head->dc_statheader));
2570*0dc2366fSVenugopal Iyer 	head->dc_next = NULL;
2571*0dc2366fSVenugopal Iyer 	free(rx_total);
2572*0dc2366fSVenugopal Iyer 	free(tx_total);
2573*0dc2366fSVenugopal Iyer 
2574*0dc2366fSVenugopal Iyer done:
2575*0dc2366fSVenugopal Iyer 	return (head);
2576*0dc2366fSVenugopal Iyer }
2577*0dc2366fSVenugopal Iyer 
2578*0dc2366fSVenugopal Iyer /* Aggr total statistic(summed across all component ports) specific functions */
2579*0dc2366fSVenugopal Iyer void *
2580*0dc2366fSVenugopal Iyer dlstat_aggr_total_stats(dladm_stat_chain_t *head)
2581*0dc2366fSVenugopal Iyer {
2582*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
2583*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head;
2584*0dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*total_stats;
2585*0dc2366fSVenugopal Iyer 
2586*0dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (aggr_port_stat_entry_t));
2587*0dc2366fSVenugopal Iyer 	if (total_stats == NULL)
2588*0dc2366fSVenugopal Iyer 		goto done;
2589*0dc2366fSVenugopal Iyer 
2590*0dc2366fSVenugopal Iyer 	total_stats->ape_portlinkid = DATALINK_INVALID_LINKID;
2591*0dc2366fSVenugopal Iyer 
2592*0dc2366fSVenugopal Iyer 	for (curr = head; curr != NULL; curr = curr->dc_next) {
2593*0dc2366fSVenugopal Iyer 		aggr_port_stat_entry_t	*curr_aggr_port_stats;
2594*0dc2366fSVenugopal Iyer 
2595*0dc2366fSVenugopal Iyer 		curr_aggr_port_stats = curr->dc_statentry;
2596*0dc2366fSVenugopal Iyer 
2597*0dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->ape_stats,
2598*0dc2366fSVenugopal Iyer 		    &curr_aggr_port_stats->ape_stats, &total_stats->ape_stats,
2599*0dc2366fSVenugopal Iyer 		    aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
2600*0dc2366fSVenugopal Iyer 	}
2601*0dc2366fSVenugopal Iyer 
2602*0dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
2603*0dc2366fSVenugopal Iyer 	if (total_head == NULL) {
2604*0dc2366fSVenugopal Iyer 		free(total_stats);
2605*0dc2366fSVenugopal Iyer 		goto done;
2606*0dc2366fSVenugopal Iyer 	}
2607*0dc2366fSVenugopal Iyer 
2608*0dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
2609*0dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
2610*0dc2366fSVenugopal Iyer 
2611*0dc2366fSVenugopal Iyer done:
2612*0dc2366fSVenugopal Iyer 	return (total_head);
2613*0dc2366fSVenugopal Iyer }
2614*0dc2366fSVenugopal Iyer 
2615*0dc2366fSVenugopal Iyer /* Aggr port statistic specific functions */
2616*0dc2366fSVenugopal Iyer static boolean_t
2617*0dc2366fSVenugopal Iyer i_dlstat_aggr_port_match(void *arg1, void *arg2)
2618*0dc2366fSVenugopal Iyer {
2619*0dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t *s1 = arg1;
2620*0dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t *s2 = arg2;
2621*0dc2366fSVenugopal Iyer 
2622*0dc2366fSVenugopal Iyer 	return (s1->ape_portlinkid == s2->ape_portlinkid);
2623*0dc2366fSVenugopal Iyer }
2624*0dc2366fSVenugopal Iyer 
2625*0dc2366fSVenugopal Iyer static void *
2626*0dc2366fSVenugopal Iyer i_dlstat_aggr_port_stat_entry_diff(void *arg1, void *arg2)
2627*0dc2366fSVenugopal Iyer {
2628*0dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*s1 = arg1;
2629*0dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*s2 = arg2;
2630*0dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*diff_entry;
2631*0dc2366fSVenugopal Iyer 
2632*0dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (aggr_port_stat_entry_t));
2633*0dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
2634*0dc2366fSVenugopal Iyer 		goto done;
2635*0dc2366fSVenugopal Iyer 
2636*0dc2366fSVenugopal Iyer 	diff_entry->ape_portlinkid = s1->ape_portlinkid;
2637*0dc2366fSVenugopal Iyer 
2638*0dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list,
2639*0dc2366fSVenugopal Iyer 	    AGGR_PORT_STAT_SIZE);
2640*0dc2366fSVenugopal Iyer 
2641*0dc2366fSVenugopal Iyer done:
2642*0dc2366fSVenugopal Iyer 	return (diff_entry);
2643*0dc2366fSVenugopal Iyer }
2644*0dc2366fSVenugopal Iyer 
2645*0dc2366fSVenugopal Iyer /*
2646*0dc2366fSVenugopal Iyer  * Query dls stats for the aggr port. This results in query for stats into
2647*0dc2366fSVenugopal Iyer  * the corresponding device driver.
2648*0dc2366fSVenugopal Iyer  */
2649*0dc2366fSVenugopal Iyer static aggr_port_stat_entry_t *
2650*0dc2366fSVenugopal Iyer i_dlstat_single_port_stats(const char *portname, datalink_id_t linkid)
2651*0dc2366fSVenugopal Iyer {
2652*0dc2366fSVenugopal Iyer 	kstat_ctl_t		*kcp;
2653*0dc2366fSVenugopal Iyer 	kstat_t			*ksp;
2654*0dc2366fSVenugopal Iyer 	char			module[DLPI_LINKNAME_MAX];
2655*0dc2366fSVenugopal Iyer 	uint_t			instance;
2656*0dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*aggr_port_stat_entry = NULL;
2657*0dc2366fSVenugopal Iyer 
2658*0dc2366fSVenugopal Iyer 	if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK)
2659*0dc2366fSVenugopal Iyer 		goto done;
2660*0dc2366fSVenugopal Iyer 
2661*0dc2366fSVenugopal Iyer 	if ((kcp = kstat_open()) == NULL) {
2662*0dc2366fSVenugopal Iyer 		warn("kstat open operation failed");
2663*0dc2366fSVenugopal Iyer 		return (NULL);
2664*0dc2366fSVenugopal Iyer 	}
2665*0dc2366fSVenugopal Iyer 
2666*0dc2366fSVenugopal Iyer 	ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);
2667*0dc2366fSVenugopal Iyer 	if (ksp == NULL)
2668*0dc2366fSVenugopal Iyer 		goto done;
2669*0dc2366fSVenugopal Iyer 
2670*0dc2366fSVenugopal Iyer 	aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t));
2671*0dc2366fSVenugopal Iyer 	if (aggr_port_stat_entry == NULL)
2672*0dc2366fSVenugopal Iyer 		goto done;
2673*0dc2366fSVenugopal Iyer 
2674*0dc2366fSVenugopal Iyer 	/* Save port's linkid */
2675*0dc2366fSVenugopal Iyer 	aggr_port_stat_entry->ape_portlinkid = linkid;
2676*0dc2366fSVenugopal Iyer 
2677*0dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &aggr_port_stat_entry->ape_stats,
2678*0dc2366fSVenugopal Iyer 	    aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
2679*0dc2366fSVenugopal Iyer done:
2680*0dc2366fSVenugopal Iyer 	(void) kstat_close(kcp);
2681*0dc2366fSVenugopal Iyer 	return (aggr_port_stat_entry);
2682*0dc2366fSVenugopal Iyer }
2683*0dc2366fSVenugopal Iyer 
2684*0dc2366fSVenugopal Iyer void *
2685*0dc2366fSVenugopal Iyer dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid)
2686*0dc2366fSVenugopal Iyer {
2687*0dc2366fSVenugopal Iyer 	dladm_aggr_grp_attr_t	ginfo;
2688*0dc2366fSVenugopal Iyer 	int			i;
2689*0dc2366fSVenugopal Iyer 	dladm_aggr_port_attr_t	 *portp;
2690*0dc2366fSVenugopal Iyer 	dladm_phys_attr_t	dpa;
2691*0dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*aggr_port_stat_entry;
2692*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL, *prev = NULL, *curr;
2693*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_stats;
2694*0dc2366fSVenugopal Iyer 
2695*0dc2366fSVenugopal Iyer 	/* Get aggr info */
2696*0dc2366fSVenugopal Iyer 	bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
2697*0dc2366fSVenugopal Iyer 	if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE)
2698*0dc2366fSVenugopal Iyer 	    != DLADM_STATUS_OK)
2699*0dc2366fSVenugopal Iyer 		goto done;
2700*0dc2366fSVenugopal Iyer 	/* For every port that is member of this aggr do */
2701*0dc2366fSVenugopal Iyer 	for (i = 0; i < ginfo.lg_nports; i++) {
2702*0dc2366fSVenugopal Iyer 		portp = &(ginfo.lg_ports[i]);
2703*0dc2366fSVenugopal Iyer 		if (dladm_phys_info(dh, portp->lp_linkid, &dpa,
2704*0dc2366fSVenugopal Iyer 		    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
2705*0dc2366fSVenugopal Iyer 			goto done;
2706*0dc2366fSVenugopal Iyer 		}
2707*0dc2366fSVenugopal Iyer 
2708*0dc2366fSVenugopal Iyer 		aggr_port_stat_entry = i_dlstat_single_port_stats(dpa.dp_dev,
2709*0dc2366fSVenugopal Iyer 		    portp->lp_linkid);
2710*0dc2366fSVenugopal Iyer 
2711*0dc2366fSVenugopal Iyer 		/* Create dladm_stat_chain_t object for this stat */
2712*0dc2366fSVenugopal Iyer 		curr = malloc(sizeof (dladm_stat_chain_t));
2713*0dc2366fSVenugopal Iyer 		if (curr == NULL) {
2714*0dc2366fSVenugopal Iyer 			free(aggr_port_stat_entry);
2715*0dc2366fSVenugopal Iyer 			goto done;
2716*0dc2366fSVenugopal Iyer 		}
2717*0dc2366fSVenugopal Iyer 		(void) strlcpy(curr->dc_statheader, dpa.dp_dev,
2718*0dc2366fSVenugopal Iyer 		    sizeof (curr->dc_statheader));
2719*0dc2366fSVenugopal Iyer 		curr->dc_statentry = aggr_port_stat_entry;
2720*0dc2366fSVenugopal Iyer 		curr->dc_next = NULL;
2721*0dc2366fSVenugopal Iyer 
2722*0dc2366fSVenugopal Iyer 		/* Chain this aggr port stat entry */
2723*0dc2366fSVenugopal Iyer 		/* head of the stat list */
2724*0dc2366fSVenugopal Iyer 		if (prev == NULL)
2725*0dc2366fSVenugopal Iyer 			head = curr;
2726*0dc2366fSVenugopal Iyer 		else
2727*0dc2366fSVenugopal Iyer 			prev->dc_next = curr;
2728*0dc2366fSVenugopal Iyer 		prev = curr;
2729*0dc2366fSVenugopal Iyer 	}
2730*0dc2366fSVenugopal Iyer 
2731*0dc2366fSVenugopal Iyer 	/*
2732*0dc2366fSVenugopal Iyer 	 * Prepend the stat list with cumulative aggr stats i.e. summed over all
2733*0dc2366fSVenugopal Iyer 	 * component ports
2734*0dc2366fSVenugopal Iyer 	 */
2735*0dc2366fSVenugopal Iyer 	total_stats = dlstat_aggr_total_stats(head);
2736*0dc2366fSVenugopal Iyer 	if (total_stats != NULL) {
2737*0dc2366fSVenugopal Iyer 		total_stats->dc_next = head;
2738*0dc2366fSVenugopal Iyer 		head = total_stats;
2739*0dc2366fSVenugopal Iyer 	}
2740*0dc2366fSVenugopal Iyer 
2741*0dc2366fSVenugopal Iyer done:
2742*0dc2366fSVenugopal Iyer 	free(ginfo.lg_ports);
2743*0dc2366fSVenugopal Iyer 	return (head);
2744*0dc2366fSVenugopal Iyer }
2745*0dc2366fSVenugopal Iyer 
2746*0dc2366fSVenugopal Iyer /* Misc stat specific functions */
2747*0dc2366fSVenugopal Iyer void *
2748*0dc2366fSVenugopal Iyer dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid)
2749*0dc2366fSVenugopal Iyer {
2750*0dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
2751*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
2752*0dc2366fSVenugopal Iyer 	char 			linkname[MAXLINKNAMELEN];
2753*0dc2366fSVenugopal Iyer 
2754*0dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
2755*0dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2756*0dc2366fSVenugopal Iyer 		goto done;
2757*0dc2366fSVenugopal Iyer 	}
2758*0dc2366fSVenugopal Iyer 
2759*0dc2366fSVenugopal Iyer 	misc_stat_entry = i_dlstat_misc_stats(linkname);
2760*0dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
2761*0dc2366fSVenugopal Iyer 		goto done;
2762*0dc2366fSVenugopal Iyer 
2763*0dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
2764*0dc2366fSVenugopal Iyer 	if (head == NULL) {
2765*0dc2366fSVenugopal Iyer 		free(misc_stat_entry);
2766*0dc2366fSVenugopal Iyer 		goto done;
2767*0dc2366fSVenugopal Iyer 	}
2768*0dc2366fSVenugopal Iyer 
2769*0dc2366fSVenugopal Iyer 	head->dc_statentry = misc_stat_entry;
2770*0dc2366fSVenugopal Iyer 	(void) strlcpy(head->dc_statheader, "mac_misc_stat",
2771*0dc2366fSVenugopal Iyer 	    sizeof (head->dc_statheader));
2772*0dc2366fSVenugopal Iyer 	head->dc_next = NULL;
2773*0dc2366fSVenugopal Iyer 
2774*0dc2366fSVenugopal Iyer done:
2775*0dc2366fSVenugopal Iyer 	return (head);
2776*0dc2366fSVenugopal Iyer }
2777*0dc2366fSVenugopal Iyer 
2778*0dc2366fSVenugopal Iyer /* Exported functions */
2779*0dc2366fSVenugopal Iyer dladm_stat_chain_t *
2780*0dc2366fSVenugopal Iyer dladm_link_stat_query(dladm_handle_t dh, datalink_id_t linkid,
2781*0dc2366fSVenugopal Iyer     dladm_stat_type_t stattype)
2782*0dc2366fSVenugopal Iyer {
2783*0dc2366fSVenugopal Iyer 	return (dladm_stat_table[stattype].ds_querystat(dh, linkid));
2784*0dc2366fSVenugopal Iyer }
2785*0dc2366fSVenugopal Iyer 
2786*0dc2366fSVenugopal Iyer dladm_stat_chain_t *
2787*0dc2366fSVenugopal Iyer dladm_link_stat_diffchain(dladm_stat_chain_t *op1, dladm_stat_chain_t *op2,
2788*0dc2366fSVenugopal Iyer     dladm_stat_type_t stattype)
2789*0dc2366fSVenugopal Iyer {
2790*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*op1_curr, *op2_curr;
2791*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*diff_curr;
2792*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*diff_prev = NULL, *diff_head = NULL;
2793*0dc2366fSVenugopal Iyer 
2794*0dc2366fSVenugopal Iyer 				/* Perform op1 - op2, store result in diff */
2795*0dc2366fSVenugopal Iyer 	for (op1_curr = op1; op1_curr != NULL; op1_curr = op1_curr->dc_next) {
2796*0dc2366fSVenugopal Iyer 		for (op2_curr = op2; op2_curr != NULL;
2797*0dc2366fSVenugopal Iyer 		    op2_curr = op2_curr->dc_next) {
2798*0dc2366fSVenugopal Iyer 			if (dlstat_match_stats(op1_curr->dc_statentry,
2799*0dc2366fSVenugopal Iyer 			    op2_curr->dc_statentry, stattype)) {
2800*0dc2366fSVenugopal Iyer 				break;
2801*0dc2366fSVenugopal Iyer 			}
2802*0dc2366fSVenugopal Iyer 		}
2803*0dc2366fSVenugopal Iyer 		diff_curr = malloc(sizeof (dladm_stat_chain_t));
2804*0dc2366fSVenugopal Iyer 		if (diff_curr == NULL)
2805*0dc2366fSVenugopal Iyer 			goto done;
2806*0dc2366fSVenugopal Iyer 
2807*0dc2366fSVenugopal Iyer 		diff_curr->dc_next = NULL;
2808*0dc2366fSVenugopal Iyer 
2809*0dc2366fSVenugopal Iyer 		if (op2_curr == NULL) {
2810*0dc2366fSVenugopal Iyer 			/* prev iteration did not have this stat entry */
2811*0dc2366fSVenugopal Iyer 			diff_curr->dc_statentry =
2812*0dc2366fSVenugopal Iyer 			    dlstat_diff_stats(op1_curr->dc_statentry,
2813*0dc2366fSVenugopal Iyer 			    NULL, stattype);
2814*0dc2366fSVenugopal Iyer 		} else {
2815*0dc2366fSVenugopal Iyer 			diff_curr->dc_statentry =
2816*0dc2366fSVenugopal Iyer 			    dlstat_diff_stats(op1_curr->dc_statentry,
2817*0dc2366fSVenugopal Iyer 			    op2_curr->dc_statentry, stattype);
2818*0dc2366fSVenugopal Iyer 		}
2819*0dc2366fSVenugopal Iyer 
2820*0dc2366fSVenugopal Iyer 		if (diff_curr->dc_statentry == NULL) {
2821*0dc2366fSVenugopal Iyer 			free(diff_curr);
2822*0dc2366fSVenugopal Iyer 			goto done;
2823*0dc2366fSVenugopal Iyer 		}
2824*0dc2366fSVenugopal Iyer 
2825*0dc2366fSVenugopal Iyer 		if (diff_prev == NULL) /* head of the diff stat list */
2826*0dc2366fSVenugopal Iyer 			diff_head = diff_curr;
2827*0dc2366fSVenugopal Iyer 		else
2828*0dc2366fSVenugopal Iyer 			diff_prev->dc_next = diff_curr;
2829*0dc2366fSVenugopal Iyer 		diff_prev = diff_curr;
2830*0dc2366fSVenugopal Iyer 	}
2831*0dc2366fSVenugopal Iyer done:
2832*0dc2366fSVenugopal Iyer 	return (diff_head);
2833*0dc2366fSVenugopal Iyer }
2834*0dc2366fSVenugopal Iyer 
2835*0dc2366fSVenugopal Iyer void
2836*0dc2366fSVenugopal Iyer dladm_link_stat_free(dladm_stat_chain_t *curr)
2837*0dc2366fSVenugopal Iyer {
2838*0dc2366fSVenugopal Iyer 	while (curr != NULL) {
2839*0dc2366fSVenugopal Iyer 		dladm_stat_chain_t	*tofree = curr;
2840*0dc2366fSVenugopal Iyer 
2841*0dc2366fSVenugopal Iyer 		curr = curr->dc_next;
2842*0dc2366fSVenugopal Iyer 		free(tofree->dc_statentry);
2843*0dc2366fSVenugopal Iyer 		free(tofree);
2844*0dc2366fSVenugopal Iyer 	}
2845*0dc2366fSVenugopal Iyer }
2846*0dc2366fSVenugopal Iyer 
2847*0dc2366fSVenugopal Iyer /* Query all link stats */
2848*0dc2366fSVenugopal Iyer static name_value_stat_t *
2849*0dc2366fSVenugopal Iyer i_dlstat_convert_stats(void *stats, stat_info_t stats_list[], uint_t size)
2850*0dc2366fSVenugopal Iyer {
2851*0dc2366fSVenugopal Iyer 	int			i;
2852*0dc2366fSVenugopal Iyer 	name_value_stat_t	*head_stat = NULL, *prev_stat = NULL;
2853*0dc2366fSVenugopal Iyer 	name_value_stat_t	*curr_stat;
2854*0dc2366fSVenugopal Iyer 
2855*0dc2366fSVenugopal Iyer 	for (i = 0; i < size; i++) {
2856*0dc2366fSVenugopal Iyer 		uint64_t *val = (void *)
2857*0dc2366fSVenugopal Iyer 		    ((uchar_t *)stats + stats_list[i].si_offset);
2858*0dc2366fSVenugopal Iyer 
2859*0dc2366fSVenugopal Iyer 		curr_stat = calloc(1, sizeof (name_value_stat_t));
2860*0dc2366fSVenugopal Iyer 		if (curr_stat == NULL)
2861*0dc2366fSVenugopal Iyer 			break;
2862*0dc2366fSVenugopal Iyer 
2863*0dc2366fSVenugopal Iyer 		(void) strlcpy(curr_stat->nv_statname, stats_list[i].si_name,
2864*0dc2366fSVenugopal Iyer 		    sizeof (curr_stat->nv_statname));
2865*0dc2366fSVenugopal Iyer 		curr_stat->nv_statval = *val;
2866*0dc2366fSVenugopal Iyer 		curr_stat->nv_nextstat = NULL;
2867*0dc2366fSVenugopal Iyer 
2868*0dc2366fSVenugopal Iyer 		if (head_stat == NULL)	/* First node */
2869*0dc2366fSVenugopal Iyer 			head_stat = curr_stat;
2870*0dc2366fSVenugopal Iyer 		else
2871*0dc2366fSVenugopal Iyer 			prev_stat->nv_nextstat = curr_stat;
2872*0dc2366fSVenugopal Iyer 
2873*0dc2366fSVenugopal Iyer 		prev_stat = curr_stat;
2874*0dc2366fSVenugopal Iyer 	}
2875*0dc2366fSVenugopal Iyer 	return (head_stat);
2876*0dc2366fSVenugopal Iyer }
2877*0dc2366fSVenugopal Iyer 
2878*0dc2366fSVenugopal Iyer void *
2879*0dc2366fSVenugopal Iyer build_nvs_entry(char *statheader, void *statentry, dladm_stat_type_t stattype)
2880*0dc2366fSVenugopal Iyer {
2881*0dc2366fSVenugopal Iyer 	name_value_stat_entry_t	*name_value_stat_entry;
2882*0dc2366fSVenugopal Iyer 	dladm_stat_desc_t	*stattbl_ptr;
2883*0dc2366fSVenugopal Iyer 	void			*statfields;
2884*0dc2366fSVenugopal Iyer 
2885*0dc2366fSVenugopal Iyer 	stattbl_ptr = &dladm_stat_table[stattype];
2886*0dc2366fSVenugopal Iyer 
2887*0dc2366fSVenugopal Iyer 	/* Allocate memory for query all stat entry */
2888*0dc2366fSVenugopal Iyer 	name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
2889*0dc2366fSVenugopal Iyer 	if (name_value_stat_entry == NULL)
2890*0dc2366fSVenugopal Iyer 		goto done;
2891*0dc2366fSVenugopal Iyer 
2892*0dc2366fSVenugopal Iyer 	/* Header for these stat fields */
2893*0dc2366fSVenugopal Iyer 	(void) strlcpy(name_value_stat_entry->nve_header, statheader,
2894*0dc2366fSVenugopal Iyer 	    sizeof (name_value_stat_entry->nve_header));
2895*0dc2366fSVenugopal Iyer 
2896*0dc2366fSVenugopal Iyer 	/* Extract stat fields from the statentry */
2897*0dc2366fSVenugopal Iyer 	statfields = (uchar_t *)statentry +
2898*0dc2366fSVenugopal Iyer 	    dladm_stat_table[stattype].ds_offset;
2899*0dc2366fSVenugopal Iyer 
2900*0dc2366fSVenugopal Iyer 	/* Convert curr_stat to <statname, statval> pair */
2901*0dc2366fSVenugopal Iyer 	name_value_stat_entry->nve_stats =
2902*0dc2366fSVenugopal Iyer 	    i_dlstat_convert_stats(statfields,
2903*0dc2366fSVenugopal Iyer 	    stattbl_ptr->ds_statlist, stattbl_ptr->ds_statsize);
2904*0dc2366fSVenugopal Iyer done:
2905*0dc2366fSVenugopal Iyer 	return (name_value_stat_entry);
2906*0dc2366fSVenugopal Iyer }
2907*0dc2366fSVenugopal Iyer 
2908*0dc2366fSVenugopal Iyer void *
2909*0dc2366fSVenugopal Iyer i_walk_dlstat_chain(dladm_stat_chain_t *stat_head, dladm_stat_type_t stattype)
2910*0dc2366fSVenugopal Iyer {
2911*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
2912*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*nvstat_head = NULL, *nvstat_prev = NULL;
2913*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*nvstat_curr;
2914*0dc2366fSVenugopal Iyer 
2915*0dc2366fSVenugopal Iyer 	/*
2916*0dc2366fSVenugopal Iyer 	 * For every stat in the chain, build header and convert all
2917*0dc2366fSVenugopal Iyer 	 * its stat fields
2918*0dc2366fSVenugopal Iyer 	 */
2919*0dc2366fSVenugopal Iyer 	for (curr = stat_head; curr != NULL; curr = curr->dc_next) {
2920*0dc2366fSVenugopal Iyer 		nvstat_curr = malloc(sizeof (dladm_stat_chain_t));
2921*0dc2366fSVenugopal Iyer 		if (nvstat_curr == NULL)
2922*0dc2366fSVenugopal Iyer 			break;
2923*0dc2366fSVenugopal Iyer 
2924*0dc2366fSVenugopal Iyer 		nvstat_curr->dc_statentry = build_nvs_entry(curr->dc_statheader,
2925*0dc2366fSVenugopal Iyer 		    curr->dc_statentry, stattype);
2926*0dc2366fSVenugopal Iyer 
2927*0dc2366fSVenugopal Iyer 		if (nvstat_curr->dc_statentry == NULL) {
2928*0dc2366fSVenugopal Iyer 			free(nvstat_curr);
2929*0dc2366fSVenugopal Iyer 			break;
2930*0dc2366fSVenugopal Iyer 		}
2931*0dc2366fSVenugopal Iyer 
2932*0dc2366fSVenugopal Iyer 		nvstat_curr->dc_next = NULL;
2933*0dc2366fSVenugopal Iyer 
2934*0dc2366fSVenugopal Iyer 		if (nvstat_head == NULL)	/* First node */
2935*0dc2366fSVenugopal Iyer 			nvstat_head = nvstat_curr;
2936*0dc2366fSVenugopal Iyer 		else
2937*0dc2366fSVenugopal Iyer 			nvstat_prev->dc_next = nvstat_curr;
2938*0dc2366fSVenugopal Iyer 
2939*0dc2366fSVenugopal Iyer 		nvstat_prev = nvstat_curr;
2940*0dc2366fSVenugopal Iyer 	}
2941*0dc2366fSVenugopal Iyer done:
2942*0dc2366fSVenugopal Iyer 	return (nvstat_head);
2943*0dc2366fSVenugopal Iyer }
2944*0dc2366fSVenugopal Iyer 
2945*0dc2366fSVenugopal Iyer dladm_stat_chain_t *
2946*0dc2366fSVenugopal Iyer dladm_link_stat_query_all(dladm_handle_t dh, datalink_id_t linkid,
2947*0dc2366fSVenugopal Iyer     dladm_stat_type_t stattype)
2948*0dc2366fSVenugopal Iyer {
2949*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*stat_head;
2950*0dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*nvstat_head = NULL;
2951*0dc2366fSVenugopal Iyer 
2952*0dc2366fSVenugopal Iyer 	/* Query the requested stat */
2953*0dc2366fSVenugopal Iyer 	stat_head = dladm_link_stat_query(dh, linkid, stattype);
2954*0dc2366fSVenugopal Iyer 	if (stat_head == NULL)
2955*0dc2366fSVenugopal Iyer 		goto done;
2956*0dc2366fSVenugopal Iyer 
2957*0dc2366fSVenugopal Iyer 	/*
2958*0dc2366fSVenugopal Iyer 	 * Convert every statfield in every stat-entry of stat chain to
2959*0dc2366fSVenugopal Iyer 	 * <statname, statval> pair
2960*0dc2366fSVenugopal Iyer 	 */
2961*0dc2366fSVenugopal Iyer 	nvstat_head = i_walk_dlstat_chain(stat_head, stattype);
2962*0dc2366fSVenugopal Iyer 
2963*0dc2366fSVenugopal Iyer 	/* Free stat_head */
2964*0dc2366fSVenugopal Iyer 	dladm_link_stat_free(stat_head);
2965*0dc2366fSVenugopal Iyer 
2966*0dc2366fSVenugopal Iyer done:
2967*0dc2366fSVenugopal Iyer 	return (nvstat_head);
2968*0dc2366fSVenugopal Iyer }
2969*0dc2366fSVenugopal Iyer 
2970*0dc2366fSVenugopal Iyer void
2971*0dc2366fSVenugopal Iyer dladm_link_stat_query_all_free(dladm_stat_chain_t *curr)
2972*0dc2366fSVenugopal Iyer {
2973*0dc2366fSVenugopal Iyer 	while (curr != NULL) {
2974*0dc2366fSVenugopal Iyer 		dladm_stat_chain_t	*tofree = curr;
2975*0dc2366fSVenugopal Iyer 		name_value_stat_entry_t	*nv_entry = curr->dc_statentry;
2976*0dc2366fSVenugopal Iyer 		name_value_stat_t	*nv_curr = nv_entry->nve_stats;
2977*0dc2366fSVenugopal Iyer 
2978*0dc2366fSVenugopal Iyer 		while (nv_curr != NULL) {
2979*0dc2366fSVenugopal Iyer 			name_value_stat_t	*nv_tofree = nv_curr;
2980*0dc2366fSVenugopal Iyer 
2981*0dc2366fSVenugopal Iyer 			nv_curr = nv_curr->nv_nextstat;
2982*0dc2366fSVenugopal Iyer 			free(nv_tofree);
2983*0dc2366fSVenugopal Iyer 		}
2984*0dc2366fSVenugopal Iyer 
2985*0dc2366fSVenugopal Iyer 		curr = curr->dc_next;
2986*0dc2366fSVenugopal Iyer 		free(nv_entry);
2987*0dc2366fSVenugopal Iyer 		free(tofree);
2988*0dc2366fSVenugopal Iyer 	}
2989*0dc2366fSVenugopal Iyer }
2990*0dc2366fSVenugopal Iyer 
2991*0dc2366fSVenugopal Iyer /* flow stats specific routines */
2992*0dc2366fSVenugopal Iyer flow_stat_t *
2993*0dc2366fSVenugopal Iyer dladm_flow_stat_query(const char *flowname)
2994*0dc2366fSVenugopal Iyer {
2995*0dc2366fSVenugopal Iyer 	kstat_ctl_t	*kcp;
2996*0dc2366fSVenugopal Iyer 	kstat_t		*ksp;
2997*0dc2366fSVenugopal Iyer 	flow_stat_t	*flow_stat = NULL;
2998*0dc2366fSVenugopal Iyer 
2999*0dc2366fSVenugopal Iyer 	if ((kcp = kstat_open()) == NULL)
3000*0dc2366fSVenugopal Iyer 		return (NULL);
3001*0dc2366fSVenugopal Iyer 
3002*0dc2366fSVenugopal Iyer 	flow_stat = calloc(1, sizeof (flow_stat_t));
3003*0dc2366fSVenugopal Iyer 	if (flow_stat == NULL)
3004*0dc2366fSVenugopal Iyer 		goto done;
3005*0dc2366fSVenugopal Iyer 
3006*0dc2366fSVenugopal Iyer 	ksp = dladm_kstat_lookup(kcp, NULL, -1, flowname, "flow");
3007*0dc2366fSVenugopal Iyer 
3008*0dc2366fSVenugopal Iyer 	if (ksp != NULL) {
3009*0dc2366fSVenugopal Iyer 		i_dlstat_get_stats(kcp, ksp, flow_stat, flow_stats_list,
3010*0dc2366fSVenugopal Iyer 		    FLOW_STAT_SIZE);
3011*0dc2366fSVenugopal Iyer 	}
3012*0dc2366fSVenugopal Iyer 
3013*0dc2366fSVenugopal Iyer done:
3014*0dc2366fSVenugopal Iyer 	(void) kstat_close(kcp);
3015*0dc2366fSVenugopal Iyer 	return (flow_stat);
3016*0dc2366fSVenugopal Iyer }
3017*0dc2366fSVenugopal Iyer 
3018*0dc2366fSVenugopal Iyer flow_stat_t *
3019*0dc2366fSVenugopal Iyer dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2)
3020*0dc2366fSVenugopal Iyer {
3021*0dc2366fSVenugopal Iyer 	flow_stat_t	*diff_stat;
3022*0dc2366fSVenugopal Iyer 
3023*0dc2366fSVenugopal Iyer 	diff_stat = calloc(1, sizeof (flow_stat_t));
3024*0dc2366fSVenugopal Iyer 	if (diff_stat == NULL)
3025*0dc2366fSVenugopal Iyer 		goto done;
3026*0dc2366fSVenugopal Iyer 
3027*0dc2366fSVenugopal Iyer 	if (op2 == NULL) {
3028*0dc2366fSVenugopal Iyer 		bcopy(op1, diff_stat, sizeof (flow_stat_t));
3029*0dc2366fSVenugopal Iyer 	} else {
3030*0dc2366fSVenugopal Iyer 		i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list,
3031*0dc2366fSVenugopal Iyer 		    FLOW_STAT_SIZE);
3032*0dc2366fSVenugopal Iyer 	}
3033*0dc2366fSVenugopal Iyer done:
3034*0dc2366fSVenugopal Iyer 	return (diff_stat);
3035*0dc2366fSVenugopal Iyer }
3036*0dc2366fSVenugopal Iyer 
3037*0dc2366fSVenugopal Iyer void
3038*0dc2366fSVenugopal Iyer dladm_flow_stat_free(flow_stat_t *curr)
3039*0dc2366fSVenugopal Iyer {
3040*0dc2366fSVenugopal Iyer 	free(curr);
3041*0dc2366fSVenugopal Iyer }
3042*0dc2366fSVenugopal Iyer 
3043*0dc2366fSVenugopal Iyer /* Query all flow stats */
3044*0dc2366fSVenugopal Iyer name_value_stat_entry_t *
3045*0dc2366fSVenugopal Iyer dladm_flow_stat_query_all(const char *flowname)
3046*0dc2366fSVenugopal Iyer {
3047*0dc2366fSVenugopal Iyer 	flow_stat_t		*flow_stat;
3048*0dc2366fSVenugopal Iyer 	name_value_stat_entry_t	*name_value_stat_entry = NULL;
3049*0dc2366fSVenugopal Iyer 
3050*0dc2366fSVenugopal Iyer 	/* Query flow stats */
3051*0dc2366fSVenugopal Iyer 	flow_stat =  dladm_flow_stat_query(flowname);
3052*0dc2366fSVenugopal Iyer 	if (flow_stat == NULL)
3053*0dc2366fSVenugopal Iyer 		goto done;
3054*0dc2366fSVenugopal Iyer 
3055*0dc2366fSVenugopal Iyer 	/* Allocate memory for query all stat entry */
3056*0dc2366fSVenugopal Iyer 	name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
3057*0dc2366fSVenugopal Iyer 	if (name_value_stat_entry == NULL) {
3058*0dc2366fSVenugopal Iyer 		dladm_flow_stat_free(flow_stat);
3059*0dc2366fSVenugopal Iyer 		goto done;
3060*0dc2366fSVenugopal Iyer 	}
3061*0dc2366fSVenugopal Iyer 
3062*0dc2366fSVenugopal Iyer 	/* Header for these stat fields */
3063*0dc2366fSVenugopal Iyer 	(void) strncpy(name_value_stat_entry->nve_header, flowname,
3064*0dc2366fSVenugopal Iyer 	    MAXFLOWNAMELEN);
3065*0dc2366fSVenugopal Iyer 
3066*0dc2366fSVenugopal Iyer 	/* Convert every statfield in flow_stat to <statname, statval> pair */
3067*0dc2366fSVenugopal Iyer 	name_value_stat_entry->nve_stats =
3068*0dc2366fSVenugopal Iyer 	    i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE);
3069*0dc2366fSVenugopal Iyer 
3070*0dc2366fSVenugopal Iyer 	/* Free flow_stat */
3071*0dc2366fSVenugopal Iyer 	dladm_flow_stat_free(flow_stat);
3072*0dc2366fSVenugopal Iyer 
3073*0dc2366fSVenugopal Iyer done:
3074*0dc2366fSVenugopal Iyer 	return (name_value_stat_entry);
3075*0dc2366fSVenugopal Iyer }
3076*0dc2366fSVenugopal Iyer 
3077*0dc2366fSVenugopal Iyer void
3078*0dc2366fSVenugopal Iyer dladm_flow_stat_query_all_free(name_value_stat_entry_t *curr)
3079*0dc2366fSVenugopal Iyer {
3080*0dc2366fSVenugopal Iyer 	name_value_stat_t	*nv_curr = curr->nve_stats;
3081*0dc2366fSVenugopal Iyer 
3082*0dc2366fSVenugopal Iyer 	while (nv_curr != NULL) {
3083*0dc2366fSVenugopal Iyer 		name_value_stat_t	*nv_tofree = nv_curr;
3084*0dc2366fSVenugopal Iyer 
3085*0dc2366fSVenugopal Iyer 		nv_curr = nv_curr->nv_nextstat;
3086*0dc2366fSVenugopal Iyer 		free(nv_tofree);
3087*0dc2366fSVenugopal Iyer 	}
3088*0dc2366fSVenugopal Iyer }
3089