xref: /onnv-gate/usr/src/lib/libdladm/common/libdlstat.c (revision 11878:ac93462db6d7)
18275SEric Cheng /*
28275SEric Cheng  * CDDL HEADER START
38275SEric Cheng  *
48275SEric Cheng  * The contents of this file are subject to the terms of the
58275SEric Cheng  * Common Development and Distribution License (the "License").
68275SEric Cheng  * You may not use this file except in compliance with the License.
78275SEric Cheng  *
88275SEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98275SEric Cheng  * or http://www.opensolaris.org/os/licensing.
108275SEric Cheng  * See the License for the specific language governing permissions
118275SEric Cheng  * and limitations under the License.
128275SEric Cheng  *
138275SEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
148275SEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158275SEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
168275SEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
178275SEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
188275SEric Cheng  *
198275SEric Cheng  * CDDL HEADER END
208275SEric Cheng  */
218275SEric Cheng /*
22*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
238275SEric Cheng  * Use is subject to license terms.
248275SEric Cheng  */
258275SEric Cheng 
268275SEric Cheng #include <stdio.h>
278275SEric Cheng #include <stdlib.h>
288275SEric Cheng #include <strings.h>
298275SEric Cheng #include <err.h>
308275SEric Cheng #include <errno.h>
319421SMichael.Lim@Sun.COM #include <fcntl.h>
328275SEric Cheng #include <kstat.h>
339421SMichael.Lim@Sun.COM #include <limits.h>
348275SEric Cheng #include <unistd.h>
358275SEric Cheng #include <signal.h>
368275SEric Cheng #include <sys/dld.h>
379107Sjames.d.carlson@sun.com #include <sys/ddi.h>
388275SEric Cheng 
398275SEric Cheng #include <libdllink.h>
408275SEric Cheng #include <libdlflow.h>
418275SEric Cheng #include <libdlstat.h>
42*11878SVenu.Iyer@Sun.COM #include <libdlaggr.h>
438275SEric Cheng 
448275SEric Cheng /*
458275SEric Cheng  * x86 <sys/regs> ERR conflicts with <curses.h> ERR.
468275SEric Cheng  * Include curses.h last.
478275SEric Cheng  */
488275SEric Cheng #if	defined(ERR)
498275SEric Cheng #undef  ERR
508275SEric Cheng #endif
518275SEric Cheng #include <curses.h>
528275SEric Cheng 
538275SEric Cheng struct flowlist {
548558SGirish.Moodalbail@Sun.COM 	char		flowname[MAXFLOWNAMELEN];
559421SMichael.Lim@Sun.COM 	char		linkname[MAXLINKNAMELEN];
568275SEric Cheng 	datalink_id_t	linkid;
579421SMichael.Lim@Sun.COM 	int		fd;
588957SMichael.Lim@Sun.COM 	uint64_t	ifspeed;
598275SEric Cheng 	boolean_t	first;
608275SEric Cheng 	boolean_t	display;
618275SEric Cheng 	pktsum_t 	prevstats;
628275SEric Cheng 	pktsum_t	diffstats;
638275SEric Cheng };
648275SEric Cheng 
658275SEric Cheng static	int	maxx, maxy, redraw = 0;
668275SEric Cheng static	volatile uint_t handle_resize = 0, handle_break = 0;
678275SEric Cheng 
688275SEric Cheng pktsum_t		totalstats;
698275SEric Cheng struct flowlist		*stattable = NULL;
708275SEric Cheng static int		statentry = -1, maxstatentries = 0;
718275SEric Cheng 
728275SEric Cheng #define	STATGROWSIZE	16
738275SEric Cheng 
748275SEric Cheng /*
758275SEric Cheng  * Search for flowlist entry in stattable which matches
76*11878SVenu.Iyer@Sun.COM  * the flowname and linkid.  If no match is found, use
778275SEric Cheng  * next available slot.  If no slots are available,
788275SEric Cheng  * reallocate table with  more slots.
798275SEric Cheng  *
808275SEric Cheng  * Return: *flowlist of matching flow
818275SEric Cheng  *         NULL if realloc fails
828275SEric Cheng  */
838275SEric Cheng 
848275SEric Cheng static struct flowlist *
findstat(const char * flowname,datalink_id_t linkid)858275SEric Cheng findstat(const char *flowname, datalink_id_t linkid)
868275SEric Cheng {
878275SEric Cheng 	int match = 0;
888275SEric Cheng 	struct flowlist *flist;
898275SEric Cheng 
908275SEric Cheng 	/* Look for match in the stattable */
918275SEric Cheng 	for (match = 0, flist = stattable;
928275SEric Cheng 	    match <= statentry;
938275SEric Cheng 	    match++, flist++) {
948275SEric Cheng 
958275SEric Cheng 		if (flist == NULL)
968275SEric Cheng 			break;
978275SEric Cheng 		/* match the flowname */
988275SEric Cheng 		if (flowname != NULL) {
998558SGirish.Moodalbail@Sun.COM 			if (strncmp(flowname, flist->flowname, MAXFLOWNAMELEN)
1008275SEric Cheng 			    == NULL)
1018275SEric Cheng 				return (flist);
1028275SEric Cheng 		/* match the linkid */
1038275SEric Cheng 		} else {
1048275SEric Cheng 			if (linkid == flist->linkid)
1058275SEric Cheng 				return (flist);
1068275SEric Cheng 		}
1078275SEric Cheng 	}
1088275SEric Cheng 
1098275SEric Cheng 	/*
1108275SEric Cheng 	 * No match found in the table.  Store statistics in the next slot.
1118275SEric Cheng 	 * If necessary, make room for this entry.
1128275SEric Cheng 	 */
1138275SEric Cheng 	statentry++;
1148275SEric Cheng 	if ((maxstatentries == 0) || (maxstatentries == statentry)) {
1158275SEric Cheng 		maxstatentries += STATGROWSIZE;
1168275SEric Cheng 		stattable = realloc(stattable,
1178275SEric Cheng 		    maxstatentries * sizeof (struct flowlist));
1188275SEric Cheng 		if (stattable == NULL) {
1198275SEric Cheng 			perror("realloc");
1208275SEric Cheng 			return (struct flowlist *)(NULL);
1218275SEric Cheng 		}
1228275SEric Cheng 	}
1238275SEric Cheng 	flist = &stattable[statentry];
1248275SEric Cheng 	bzero(flist, sizeof (struct flowlist));
1258275SEric Cheng 
1268275SEric Cheng 	if (flowname != NULL)
1278558SGirish.Moodalbail@Sun.COM 		(void) strncpy(flist->flowname, flowname, MAXFLOWNAMELEN);
1288275SEric Cheng 	flist->linkid = linkid;
1299421SMichael.Lim@Sun.COM 	flist->fd = INT32_MAX;
1309421SMichael.Lim@Sun.COM 
1318275SEric Cheng 	return (flist);
1328275SEric Cheng }
1338275SEric Cheng 
1349421SMichael.Lim@Sun.COM /*ARGSUSED*/
1358275SEric Cheng static void
print_flow_stats(dladm_handle_t handle,struct flowlist * flist)1368453SAnurag.Maskey@Sun.COM print_flow_stats(dladm_handle_t handle, struct flowlist *flist)
1378275SEric Cheng {
1388275SEric Cheng 	struct flowlist *fcurr;
1398275SEric Cheng 	double ikbs, okbs;
1408275SEric Cheng 	double ipks, opks;
1418275SEric Cheng 	double dlt;
1428275SEric Cheng 	int fcount;
1438275SEric Cheng 	static boolean_t first = B_TRUE;
1448275SEric Cheng 
1458275SEric Cheng 	if (first) {
1468275SEric Cheng 		first = B_FALSE;
1478275SEric Cheng 		(void) printw("please wait...\n");
1488275SEric Cheng 		return;
1498275SEric Cheng 	}
1508275SEric Cheng 
1518275SEric Cheng 	for (fcount = 0, fcurr = flist;
1528275SEric Cheng 	    fcount <= statentry;
1538275SEric Cheng 	    fcount++, fcurr++) {
1548275SEric Cheng 		if (fcurr->flowname && fcurr->display) {
1558275SEric Cheng 			dlt = (double)fcurr->diffstats.snaptime/(double)NANOSEC;
1568275SEric Cheng 			ikbs = fcurr->diffstats.rbytes * 8 / dlt / 1024;
1578275SEric Cheng 			okbs = fcurr->diffstats.obytes * 8 / dlt / 1024;
1588275SEric Cheng 			ipks = fcurr->diffstats.ipackets / dlt;
1598275SEric Cheng 			opks = fcurr->diffstats.opackets / dlt;
1608275SEric Cheng 			(void) printw("%-15.15s", fcurr->flowname);
1619421SMichael.Lim@Sun.COM 			(void) printw("%-10.10s", fcurr->linkname);
1628275SEric Cheng 			(void) printw("%9.2f %9.2f %9.2f %9.2f ",
1638275SEric Cheng 			    ikbs, okbs, ipks, opks);
1648275SEric Cheng 			(void) printw("\n");
1658275SEric Cheng 		}
1668275SEric Cheng 	}
1678275SEric Cheng }
1688275SEric Cheng 
1698275SEric Cheng /*ARGSUSED*/
1708275SEric Cheng static int
flow_kstats(dladm_handle_t handle,dladm_flow_attr_t * attr,void * arg)1719421SMichael.Lim@Sun.COM flow_kstats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg)
1728275SEric Cheng {
1738275SEric Cheng 	kstat_ctl_t 	*kcp = (kstat_ctl_t *)arg;
1748275SEric Cheng 	kstat_t		*ksp;
1758275SEric Cheng 	struct flowlist	*flist;
1768275SEric Cheng 	pktsum_t	currstats, *prevstats, *diffstats;
1778275SEric Cheng 
1788275SEric Cheng 	flist = findstat(attr->fa_flowname, attr->fa_linkid);
1799421SMichael.Lim@Sun.COM 	if (flist == NULL)
1809421SMichael.Lim@Sun.COM 		return (DLADM_WALK_CONTINUE);
1819421SMichael.Lim@Sun.COM 
1829421SMichael.Lim@Sun.COM 	flist->display = B_FALSE;
1839421SMichael.Lim@Sun.COM 	prevstats = &flist->prevstats;
1849421SMichael.Lim@Sun.COM 	diffstats = &flist->diffstats;
1859421SMichael.Lim@Sun.COM 
1869421SMichael.Lim@Sun.COM 	(void) dladm_datalink_id2info(handle, attr->fa_linkid, NULL, NULL,
1879421SMichael.Lim@Sun.COM 	    NULL, flist->linkname, sizeof (flist->linkname));
1889421SMichael.Lim@Sun.COM 
1898275SEric Cheng 
1908275SEric Cheng 	/* lookup kstat entry */
1918275SEric Cheng 	ksp = dladm_kstat_lookup(kcp, NULL, -1, attr->fa_flowname, "flow");
1928275SEric Cheng 
1938275SEric Cheng 	if (ksp == NULL)
1949421SMichael.Lim@Sun.COM 		return (DLADM_WALK_CONTINUE);
1958275SEric Cheng 
1969421SMichael.Lim@Sun.COM 	/* read packet and byte stats */
1978275SEric Cheng 	dladm_get_stats(kcp, ksp, &currstats);
1989421SMichael.Lim@Sun.COM 
1998275SEric Cheng 	if (flist->ifspeed == 0)
2008275SEric Cheng 		(void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64,
2018275SEric Cheng 		    &flist->ifspeed);
2028275SEric Cheng 
2039421SMichael.Lim@Sun.COM 	if (flist->first) {
2048275SEric Cheng 		flist->first = B_FALSE;
2059421SMichael.Lim@Sun.COM 	} else {
2068275SEric Cheng 		dladm_stats_diff(diffstats, &currstats, prevstats);
2079421SMichael.Lim@Sun.COM 		if (diffstats->snaptime == 0)
2089421SMichael.Lim@Sun.COM 			return (DLADM_WALK_CONTINUE);
2098275SEric Cheng 		dladm_stats_total(&totalstats, diffstats, &totalstats);
2108275SEric Cheng 	}
2118275SEric Cheng 
2128275SEric Cheng 	bcopy(&currstats, prevstats, sizeof (pktsum_t));
2139421SMichael.Lim@Sun.COM 	flist->display = B_TRUE;
2149421SMichael.Lim@Sun.COM 
2158275SEric Cheng 	return (DLADM_WALK_CONTINUE);
2168275SEric Cheng }
2178275SEric Cheng 
2189421SMichael.Lim@Sun.COM /*ARGSUSED*/
2198275SEric Cheng static void
print_link_stats(dladm_handle_t handle,struct flowlist * flist)2208453SAnurag.Maskey@Sun.COM print_link_stats(dladm_handle_t handle, struct flowlist *flist)
2218275SEric Cheng {
2228275SEric Cheng 	struct flowlist *fcurr;
2238275SEric Cheng 	double ikbs, okbs;
2248275SEric Cheng 	double ipks, opks;
2258275SEric Cheng 	double util;
2268275SEric Cheng 	double dlt;
2278275SEric Cheng 	int fcount;
2288275SEric Cheng 	static boolean_t first = B_TRUE;
2298275SEric Cheng 
2308275SEric Cheng 	if (first) {
2318275SEric Cheng 		first = B_FALSE;
2328275SEric Cheng 		(void) printw("please wait...\n");
2338275SEric Cheng 		return;
2348275SEric Cheng 	}
2358275SEric Cheng 
2368275SEric Cheng 	for (fcount = 0, fcurr = flist;
2378275SEric Cheng 	    fcount <= statentry;
2388275SEric Cheng 	    fcount++, fcurr++) {
2398275SEric Cheng 		if ((fcurr->linkid != DATALINK_INVALID_LINKID) &&
2408275SEric Cheng 		    fcurr->display)  {
2418275SEric Cheng 			dlt = (double)fcurr->diffstats.snaptime/(double)NANOSEC;
2428275SEric Cheng 			ikbs = (double)fcurr->diffstats.rbytes * 8 / dlt / 1024;
2438275SEric Cheng 			okbs = (double)fcurr->diffstats.obytes * 8 / dlt / 1024;
2448275SEric Cheng 			ipks = (double)fcurr->diffstats.ipackets / dlt;
2458275SEric Cheng 			opks = (double)fcurr->diffstats.opackets / dlt;
2469421SMichael.Lim@Sun.COM 			(void) printw("%-10.10s", fcurr->linkname);
2478275SEric Cheng 			(void) printw("%9.2f %9.2f %9.2f %9.2f ",
2488275SEric Cheng 			    ikbs, okbs, ipks, opks);
2498275SEric Cheng 			if (fcurr->ifspeed != 0)
2508275SEric Cheng 				util = ((ikbs + okbs) * 1024) *
2518275SEric Cheng 				    100/ fcurr->ifspeed;
2528275SEric Cheng 			else
2538275SEric Cheng 				util = (double)0;
2548275SEric Cheng 			(void) attron(A_BOLD);
2558275SEric Cheng 			(void) printw("    %6.2f", util);
2568275SEric Cheng 			(void) attroff(A_BOLD);
2578275SEric Cheng 			(void) printw("\n");
2588275SEric Cheng 		}
2598275SEric Cheng 	}
2608275SEric Cheng }
2618275SEric Cheng 
2628275SEric Cheng /*
2638275SEric Cheng  * This function is called through the dladm_walk_datalink_id() walker and
2648275SEric Cheng  * calls the dladm_walk_flow() walker.
2658275SEric Cheng  */
2668275SEric Cheng 
2678275SEric Cheng /*ARGSUSED*/
2688275SEric Cheng static int
link_flowstats(dladm_handle_t handle,datalink_id_t linkid,void * arg)2698453SAnurag.Maskey@Sun.COM link_flowstats(dladm_handle_t handle, datalink_id_t linkid, void *arg)
2708275SEric Cheng {
2718621SMichael.Lim@Sun.COM 	dladm_status_t	status;
2728621SMichael.Lim@Sun.COM 
2738621SMichael.Lim@Sun.COM 	status = dladm_walk_flow(flow_kstats, handle, linkid, arg, B_FALSE);
2748621SMichael.Lim@Sun.COM 	if (status == DLADM_STATUS_OK)
2758621SMichael.Lim@Sun.COM 		return (DLADM_WALK_CONTINUE);
2768621SMichael.Lim@Sun.COM 	else
2778621SMichael.Lim@Sun.COM 		return (DLADM_WALK_TERMINATE);
2788275SEric Cheng }
2798275SEric Cheng 
2808275SEric Cheng /*ARGSUSED*/
2818275SEric Cheng static int
link_kstats(dladm_handle_t handle,datalink_id_t linkid,void * arg)2828453SAnurag.Maskey@Sun.COM link_kstats(dladm_handle_t handle, datalink_id_t linkid, void *arg)
2838275SEric Cheng {
2849421SMichael.Lim@Sun.COM 	kstat_ctl_t		*kcp = (kstat_ctl_t *)arg;
2859421SMichael.Lim@Sun.COM 	struct flowlist		*flist;
2869421SMichael.Lim@Sun.COM 	pktsum_t		currstats, *prevstats, *diffstats;
2879421SMichael.Lim@Sun.COM 	datalink_class_t	class;
2889421SMichael.Lim@Sun.COM 	kstat_t			*ksp;
2899421SMichael.Lim@Sun.COM 	char			dnlink[MAXPATHLEN];
2908275SEric Cheng 
2918275SEric Cheng 	/* find the flist entry */
2928275SEric Cheng 	flist = findstat(NULL, linkid);
2939421SMichael.Lim@Sun.COM 	flist->display = B_FALSE;
2948275SEric Cheng 	if (flist != NULL) {
2958275SEric Cheng 		prevstats = &flist->prevstats;
2968275SEric Cheng 		diffstats = &flist->diffstats;
2978275SEric Cheng 	} else {
2988275SEric Cheng 		return (DLADM_WALK_CONTINUE);
2998275SEric Cheng 	}
3008275SEric Cheng 
3019421SMichael.Lim@Sun.COM 	if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL,
3029421SMichael.Lim@Sun.COM 	    flist->linkname, sizeof (flist->linkname)) != DLADM_STATUS_OK)
3039421SMichael.Lim@Sun.COM 		return (DLADM_WALK_CONTINUE);
3048275SEric Cheng 
3059421SMichael.Lim@Sun.COM 	if (flist->fd == INT32_MAX) {
3069421SMichael.Lim@Sun.COM 		if (class == DATALINK_CLASS_PHYS) {
3079421SMichael.Lim@Sun.COM 			(void) snprintf(dnlink, MAXPATHLEN, "/dev/net/%s",
3089421SMichael.Lim@Sun.COM 			    flist->linkname);
3099421SMichael.Lim@Sun.COM 			if ((flist->fd = open(dnlink, O_RDWR)) < 0)
3109421SMichael.Lim@Sun.COM 				return (DLADM_WALK_CONTINUE);
3119421SMichael.Lim@Sun.COM 		} else {
3129421SMichael.Lim@Sun.COM 			flist->fd = -1;
3139421SMichael.Lim@Sun.COM 		}
3149421SMichael.Lim@Sun.COM 		(void) kstat_chain_update(kcp);
3158275SEric Cheng 	}
3168275SEric Cheng 
3179421SMichael.Lim@Sun.COM 	/* lookup kstat entry */
3189421SMichael.Lim@Sun.COM 	ksp = dladm_kstat_lookup(kcp, NULL, -1, flist->linkname, "net");
3198275SEric Cheng 
3208275SEric Cheng 	if (ksp == NULL)
3219421SMichael.Lim@Sun.COM 		return (DLADM_WALK_CONTINUE);
3228275SEric Cheng 
3238275SEric Cheng 	/* read packet and byte stats */
3248275SEric Cheng 	dladm_get_stats(kcp, ksp, &currstats);
3258275SEric Cheng 
3268275SEric Cheng 	if (flist->ifspeed == 0)
3278275SEric Cheng 		(void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64,
3288275SEric Cheng 		    &flist->ifspeed);
3298275SEric Cheng 
3309421SMichael.Lim@Sun.COM 	if (flist->first) {
3318275SEric Cheng 		flist->first = B_FALSE;
3329421SMichael.Lim@Sun.COM 	} else {
3338275SEric Cheng 		dladm_stats_diff(diffstats, &currstats, prevstats);
3349421SMichael.Lim@Sun.COM 		if (diffstats->snaptime == 0)
3359421SMichael.Lim@Sun.COM 			return (DLADM_WALK_CONTINUE);
3369421SMichael.Lim@Sun.COM 	}
3378275SEric Cheng 
3388275SEric Cheng 	bcopy(&currstats, prevstats, sizeof (*prevstats));
3399421SMichael.Lim@Sun.COM 	flist->display = B_TRUE;
3408275SEric Cheng 
3418275SEric Cheng 	return (DLADM_WALK_CONTINUE);
3428275SEric Cheng }
3438275SEric Cheng 
3449421SMichael.Lim@Sun.COM static void
closedevnet()3459421SMichael.Lim@Sun.COM closedevnet()
3469421SMichael.Lim@Sun.COM {
3479421SMichael.Lim@Sun.COM 	int index = 0;
3489421SMichael.Lim@Sun.COM 	struct flowlist *flist;
3499421SMichael.Lim@Sun.COM 
3509421SMichael.Lim@Sun.COM 	/* Close all open /dev/net/ files */
351*11878SVenu.Iyer@Sun.COM 
352*11878SVenu.Iyer@Sun.COM 	for (flist = stattable; index < maxstatentries; index++, flist++) {
3539421SMichael.Lim@Sun.COM 		if (flist->linkid == DATALINK_INVALID_LINKID)
3549421SMichael.Lim@Sun.COM 			break;
3559421SMichael.Lim@Sun.COM 		if (flist->fd != -1 && flist->fd != INT32_MAX)
3569421SMichael.Lim@Sun.COM 			(void) close(flist->fd);
3579421SMichael.Lim@Sun.COM 	}
3589421SMichael.Lim@Sun.COM }
3599421SMichael.Lim@Sun.COM 
3608275SEric Cheng /*ARGSUSED*/
3618275SEric Cheng static void
sig_break(int s)3628275SEric Cheng sig_break(int s)
3638275SEric Cheng {
3648275SEric Cheng 	handle_break = 1;
3658275SEric Cheng }
3668275SEric Cheng 
3678275SEric Cheng /*ARGSUSED*/
3688275SEric Cheng static void
sig_resize(int s)3698275SEric Cheng sig_resize(int s)
3708275SEric Cheng {
3718275SEric Cheng 	handle_resize = 1;
3728275SEric Cheng }
3738275SEric Cheng 
3748275SEric Cheng static void
curses_init()3758275SEric Cheng curses_init()
3768275SEric Cheng {
3778275SEric Cheng 	maxx = maxx;	/* lint */
3788275SEric Cheng 	maxy = maxy;	/* lint */
3798275SEric Cheng 
3808275SEric Cheng 	/* Install signal handlers */
3818275SEric Cheng 	(void) signal(SIGINT,  sig_break);
3828275SEric Cheng 	(void) signal(SIGQUIT, sig_break);
3838275SEric Cheng 	(void) signal(SIGTERM, sig_break);
3848275SEric Cheng 	(void) signal(SIGWINCH, sig_resize);
3858275SEric Cheng 
3868275SEric Cheng 	/* Initialize ncurses */
3878275SEric Cheng 	(void) initscr();
3888275SEric Cheng 	(void) cbreak();
3898275SEric Cheng 	(void) noecho();
3908275SEric Cheng 	(void) curs_set(0);
3918275SEric Cheng 	timeout(0);
3928275SEric Cheng 	getmaxyx(stdscr, maxy, maxx);
3938275SEric Cheng }
3948275SEric Cheng 
3958275SEric Cheng static void
curses_fin()3968275SEric Cheng curses_fin()
3978275SEric Cheng {
3988275SEric Cheng 	(void) printw("\n");
3998275SEric Cheng 	(void) curs_set(1);
4008275SEric Cheng 	(void) nocbreak();
4018275SEric Cheng 	(void) endwin();
4028275SEric Cheng 
4038275SEric Cheng 	free(stattable);
4048275SEric Cheng }
4058275SEric Cheng 
4068275SEric Cheng static void
stat_report(dladm_handle_t handle,kstat_ctl_t * kcp,datalink_id_t linkid,const char * flowname,int opt)4078453SAnurag.Maskey@Sun.COM stat_report(dladm_handle_t handle, kstat_ctl_t *kcp,  datalink_id_t linkid,
4088453SAnurag.Maskey@Sun.COM     const char *flowname, int opt)
4098275SEric Cheng {
4108275SEric Cheng 
4118275SEric Cheng 	double dlt, ikbs, okbs, ipks, opks;
4128275SEric Cheng 
4138275SEric Cheng 	struct flowlist *fstable = stattable;
4148275SEric Cheng 
4158275SEric Cheng 	if ((opt != LINK_REPORT) && (opt != FLOW_REPORT))
4168275SEric Cheng 		return;
4178275SEric Cheng 
4188275SEric Cheng 	/* Handle window resizes */
4198275SEric Cheng 	if (handle_resize) {
4208275SEric Cheng 		(void) endwin();
4218275SEric Cheng 		(void) initscr();
4228275SEric Cheng 		(void) cbreak();
4238275SEric Cheng 		(void) noecho();
4248275SEric Cheng 		(void) curs_set(0);
4258275SEric Cheng 		timeout(0);
4268275SEric Cheng 		getmaxyx(stdscr, maxy, maxx);
4278275SEric Cheng 		redraw = 1;
4288275SEric Cheng 		handle_resize = 0;
4298275SEric Cheng 	}
4308275SEric Cheng 
4318275SEric Cheng 	/* Print title */
4328275SEric Cheng 	(void) erase();
4338275SEric Cheng 	(void) attron(A_BOLD);
4348275SEric Cheng 	(void) move(0, 0);
4358275SEric Cheng 	if (opt == FLOW_REPORT)
4368275SEric Cheng 		(void) printw("%-15.15s", "Flow");
4378275SEric Cheng 	(void) printw("%-10.10s", "Link");
4388275SEric Cheng 	(void) printw("%9.9s %9.9s %9.9s %9.9s ",
4398275SEric Cheng 	    "iKb/s", "oKb/s", "iPk/s", "oPk/s");
4408275SEric Cheng 	if (opt == LINK_REPORT)
4418275SEric Cheng 		(void) printw("    %6.6s", "%Util");
4428275SEric Cheng 	(void) printw("\n");
4438275SEric Cheng 	(void) attroff(A_BOLD);
4448275SEric Cheng 
4458275SEric Cheng 	(void) move(2, 0);
4468275SEric Cheng 
4478275SEric Cheng 	/* Print stats for each link or flow */
4488275SEric Cheng 	bzero(&totalstats, sizeof (totalstats));
4498275SEric Cheng 	if (opt == LINK_REPORT) {
4508275SEric Cheng 		/* Display all links */
4518275SEric Cheng 		if (linkid == DATALINK_ALL_LINKID) {
4528453SAnurag.Maskey@Sun.COM 			(void) dladm_walk_datalink_id(link_kstats, handle,
4538275SEric Cheng 			    (void *)kcp, DATALINK_CLASS_ALL,
4548275SEric Cheng 			    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
4558275SEric Cheng 		/* Display 1 link */
4568275SEric Cheng 		} else {
4578453SAnurag.Maskey@Sun.COM 			(void) link_kstats(handle, linkid, kcp);
4588275SEric Cheng 		}
4598453SAnurag.Maskey@Sun.COM 		print_link_stats(handle, fstable);
4608275SEric Cheng 
4618275SEric Cheng 	} else if (opt == FLOW_REPORT) {
4628275SEric Cheng 		/* Display 1 flow */
4638275SEric Cheng 		if (flowname != NULL) {
4648275SEric Cheng 			dladm_flow_attr_t fattr;
4658453SAnurag.Maskey@Sun.COM 			if (dladm_flow_info(handle, flowname, &fattr) !=
4668275SEric Cheng 			    DLADM_STATUS_OK)
4678275SEric Cheng 				return;
4689421SMichael.Lim@Sun.COM 			(void) flow_kstats(handle, &fattr, kcp);
4698275SEric Cheng 		/* Display all flows on all links */
4708275SEric Cheng 		} else if (linkid == DATALINK_ALL_LINKID) {
4718453SAnurag.Maskey@Sun.COM 			(void) dladm_walk_datalink_id(link_flowstats, handle,
4728275SEric Cheng 			    (void *)kcp, DATALINK_CLASS_ALL,
4738275SEric Cheng 			    DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
4748275SEric Cheng 		/* Display all flows on a link */
4758275SEric Cheng 		} else if (linkid != DATALINK_INVALID_LINKID) {
4768453SAnurag.Maskey@Sun.COM 			(void) dladm_walk_flow(flow_kstats, handle, linkid, kcp,
4778275SEric Cheng 			    B_FALSE);
4788275SEric Cheng 		}
4798453SAnurag.Maskey@Sun.COM 		print_flow_stats(handle, fstable);
4808275SEric Cheng 
4818275SEric Cheng 		/* Print totals */
4828275SEric Cheng 		(void) attron(A_BOLD);
4838275SEric Cheng 		dlt = (double)totalstats.snaptime / (double)NANOSEC;
4848275SEric Cheng 		ikbs = totalstats.rbytes / dlt / 1024;
4858275SEric Cheng 		okbs = totalstats.obytes / dlt / 1024;
4868275SEric Cheng 		ipks = totalstats.ipackets / dlt;
4878275SEric Cheng 		opks = totalstats.opackets / dlt;
4888275SEric Cheng 		(void) printw("\n%-25.25s", "Totals");
4898275SEric Cheng 		(void) printw("%9.2f %9.2f %9.2f %9.2f ",
4908275SEric Cheng 		    ikbs, okbs, ipks, opks);
4918275SEric Cheng 		(void) attroff(A_BOLD);
4928275SEric Cheng 	}
4938275SEric Cheng 
4948275SEric Cheng 	if (redraw)
4958275SEric Cheng 		(void) clearok(stdscr, 1);
4968275SEric Cheng 
4978275SEric Cheng 	if (refresh() == ERR)
4988275SEric Cheng 		return;
4998275SEric Cheng 
5008275SEric Cheng 	if (redraw) {
5018275SEric Cheng 		(void) clearok(stdscr, 0);
5028275SEric Cheng 		redraw = 0;
5038275SEric Cheng 	}
5048275SEric Cheng }
5058275SEric Cheng 
5068275SEric Cheng /* Exported functions */
5078275SEric Cheng 
5088275SEric Cheng /*
5098275SEric Cheng  * Continuously display link or flow statstics using a libcurses
5108275SEric Cheng  * based display.
5118275SEric Cheng  */
5128275SEric Cheng 
5138275SEric Cheng void
dladm_continuous(dladm_handle_t handle,datalink_id_t linkid,const char * flowname,int interval,int opt)5148453SAnurag.Maskey@Sun.COM dladm_continuous(dladm_handle_t handle, datalink_id_t linkid,
5158453SAnurag.Maskey@Sun.COM     const char *flowname, int interval, int opt)
5168275SEric Cheng {
5178275SEric Cheng 	kstat_ctl_t *kcp;
5188275SEric Cheng 
5198275SEric Cheng 	if ((kcp = kstat_open()) == NULL) {
5208275SEric Cheng 		warn("kstat open operation failed");
5218275SEric Cheng 		return;
5228275SEric Cheng 	}
5238275SEric Cheng 
5248275SEric Cheng 	curses_init();
5258275SEric Cheng 
5268275SEric Cheng 	for (;;) {
5278275SEric Cheng 
5288275SEric Cheng 		if (handle_break)
5298275SEric Cheng 			break;
5308275SEric Cheng 
5318453SAnurag.Maskey@Sun.COM 		stat_report(handle, kcp, linkid, flowname, opt);
5328275SEric Cheng 
5338275SEric Cheng 		(void) sleep(max(1, interval));
5348275SEric Cheng 	}
5358275SEric Cheng 
5369421SMichael.Lim@Sun.COM 	closedevnet();
5379421SMichael.Lim@Sun.COM 	curses_fin();
5388275SEric Cheng 	(void) kstat_close(kcp);
5398275SEric Cheng }
5408275SEric Cheng 
5418275SEric Cheng /*
5428275SEric Cheng  * dladm_kstat_lookup() is a modified version of kstat_lookup which
5438275SEric Cheng  * adds the class as a selector.
5448275SEric Cheng  */
5458275SEric Cheng 
5468275SEric Cheng kstat_t *
dladm_kstat_lookup(kstat_ctl_t * kcp,const char * module,int instance,const char * name,const char * class)5478275SEric Cheng dladm_kstat_lookup(kstat_ctl_t *kcp, const char *module, int instance,
5488275SEric Cheng     const char *name, const char *class)
5498275SEric Cheng {
5508275SEric Cheng 	kstat_t *ksp = NULL;
5518275SEric Cheng 
5528275SEric Cheng 	for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
5538275SEric Cheng 		if ((module == NULL || strcmp(ksp->ks_module, module) == 0) &&
5548275SEric Cheng 		    (instance == -1 || ksp->ks_instance == instance) &&
5558275SEric Cheng 		    (name == NULL || strcmp(ksp->ks_name, name) == 0) &&
5568275SEric Cheng 		    (class == NULL || strcmp(ksp->ks_class, class) == 0))
5578275SEric Cheng 			return (ksp);
5588275SEric Cheng 	}
5598275SEric Cheng 
5608275SEric Cheng 	errno = ENOENT;
5618275SEric Cheng 	return (NULL);
5628275SEric Cheng }
5638275SEric Cheng 
5648275SEric Cheng /*
5658275SEric Cheng  * dladm_get_stats() populates the supplied pktsum_t structure with
5668275SEric Cheng  * the input and output  packet and byte kstats from the kstat_t
5678275SEric Cheng  * found with dladm_kstat_lookup.
5688275SEric Cheng  */
5698275SEric Cheng void
dladm_get_stats(kstat_ctl_t * kcp,kstat_t * ksp,pktsum_t * stats)5708275SEric Cheng dladm_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, pktsum_t *stats)
5718275SEric Cheng {
5728275SEric Cheng 
5738275SEric Cheng 	if (kstat_read(kcp, ksp, NULL) == -1)
5748275SEric Cheng 		return;
5758275SEric Cheng 
5768275SEric Cheng 	stats->snaptime = gethrtime();
5778275SEric Cheng 
5788275SEric Cheng 	if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64,
5798275SEric Cheng 	    &stats->ipackets) < 0) {
5808275SEric Cheng 		if (dladm_kstat_value(ksp, "ipackets", KSTAT_DATA_UINT64,
5818275SEric Cheng 		    &stats->ipackets) < 0)
5828275SEric Cheng 			return;
5838275SEric Cheng 	}
5848275SEric Cheng 
5858275SEric Cheng 	if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64,
5868275SEric Cheng 	    &stats->opackets) < 0) {
5878275SEric Cheng 		if (dladm_kstat_value(ksp, "opackets", KSTAT_DATA_UINT64,
5888275SEric Cheng 		    &stats->opackets) < 0)
5898275SEric Cheng 			return;
5908275SEric Cheng 	}
5918275SEric Cheng 
5928275SEric Cheng 	if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64,
5938275SEric Cheng 	    &stats->rbytes) < 0) {
5948275SEric Cheng 		if (dladm_kstat_value(ksp, "rbytes", KSTAT_DATA_UINT64,
5958275SEric Cheng 		    &stats->rbytes) < 0)
5968275SEric Cheng 			return;
5978275SEric Cheng 	}
5988275SEric Cheng 
5998275SEric Cheng 	if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64,
6008275SEric Cheng 	    &stats->obytes) < 0) {
6018275SEric Cheng 		if (dladm_kstat_value(ksp, "obytes", KSTAT_DATA_UINT64,
6028275SEric Cheng 		    &stats->obytes) < 0)
6038275SEric Cheng 			return;
6048275SEric Cheng 	}
6058275SEric Cheng 
6068275SEric Cheng 	if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32,
6078275SEric Cheng 	    &stats->ierrors) < 0) {
6088275SEric Cheng 		if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT64,
6098275SEric Cheng 		    &stats->ierrors) < 0)
6108275SEric Cheng 		return;
6118275SEric Cheng 	}
6128275SEric Cheng 
6138275SEric Cheng 	if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32,
6148275SEric Cheng 	    &stats->oerrors) < 0) {
6158275SEric Cheng 		if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT64,
6168275SEric Cheng 		    &stats->oerrors) < 0)
6178275SEric Cheng 			return;
6188275SEric Cheng 	}
6198275SEric Cheng }
6208275SEric Cheng 
6218275SEric Cheng int
dladm_kstat_value(kstat_t * ksp,const char * name,uint8_t type,void * buf)6228275SEric Cheng dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf)
6238275SEric Cheng {
6248275SEric Cheng 	kstat_named_t	*knp;
6258275SEric Cheng 
6268275SEric Cheng 	if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL)
6278275SEric Cheng 		return (-1);
6288275SEric Cheng 
6298275SEric Cheng 	if (knp->data_type != type)
6308275SEric Cheng 		return (-1);
6318275SEric Cheng 
6328275SEric Cheng 	switch (type) {
6338275SEric Cheng 	case KSTAT_DATA_UINT64:
6348275SEric Cheng 		*(uint64_t *)buf = knp->value.ui64;
6358275SEric Cheng 		break;
6368275SEric Cheng 	case KSTAT_DATA_UINT32:
6378275SEric Cheng 		*(uint32_t *)buf = knp->value.ui32;
6388275SEric Cheng 		break;
6398275SEric Cheng 	default:
6408275SEric Cheng 		return (-1);
6418275SEric Cheng 	}
6428275SEric Cheng 
6438275SEric Cheng 	return (0);
6448275SEric Cheng }
6458275SEric Cheng 
6468275SEric Cheng dladm_status_t
dladm_get_single_mac_stat(dladm_handle_t handle,datalink_id_t linkid,const char * name,uint8_t type,void * val)6478453SAnurag.Maskey@Sun.COM dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid,
6488453SAnurag.Maskey@Sun.COM     const char *name, uint8_t type, void *val)
6498275SEric Cheng {
6508275SEric Cheng 	kstat_ctl_t	*kcp;
6518275SEric Cheng 	char		module[DLPI_LINKNAME_MAX];
6528275SEric Cheng 	uint_t		instance;
6538275SEric Cheng 	char 		link[DLPI_LINKNAME_MAX];
6548275SEric Cheng 	dladm_status_t	status;
6558275SEric Cheng 	uint32_t	flags, media;
6568275SEric Cheng 	kstat_t		*ksp;
6578275SEric Cheng 	dladm_phys_attr_t dpap;
6588275SEric Cheng 
6598453SAnurag.Maskey@Sun.COM 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
6608453SAnurag.Maskey@Sun.COM 	    &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK)
6618275SEric Cheng 		return (status);
6628275SEric Cheng 
6638275SEric Cheng 	if (media != DL_ETHER)
6648275SEric Cheng 		return (DLADM_STATUS_LINKINVAL);
6658275SEric Cheng 
6668453SAnurag.Maskey@Sun.COM 	status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST);
6678275SEric Cheng 
6688275SEric Cheng 	if (status != DLADM_STATUS_OK)
6698275SEric Cheng 		return (status);
6708275SEric Cheng 
6718275SEric Cheng 	status = dladm_parselink(dpap.dp_dev, module, &instance);
6728275SEric Cheng 
6738275SEric Cheng 	if (status != DLADM_STATUS_OK)
6748275SEric Cheng 		return (status);
6758275SEric Cheng 
6769571SSowmini.Varadhan@Sun.COM 	if ((kcp = kstat_open()) == NULL) {
6779571SSowmini.Varadhan@Sun.COM 		warn("kstat_open operation failed");
6789571SSowmini.Varadhan@Sun.COM 		return (-1);
6799571SSowmini.Varadhan@Sun.COM 	}
6809571SSowmini.Varadhan@Sun.COM 
6818275SEric Cheng 	/*
6828275SEric Cheng 	 * The kstat query could fail if the underlying MAC
6838275SEric Cheng 	 * driver was already detached.
6848275SEric Cheng 	 */
6858275SEric Cheng 	if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL &&
6868275SEric Cheng 	    (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL)
6878275SEric Cheng 		goto bail;
6888275SEric Cheng 
6898275SEric Cheng 	if (kstat_read(kcp, ksp, NULL) == -1)
6908275SEric Cheng 		goto bail;
6918275SEric Cheng 
6928275SEric Cheng 	if (dladm_kstat_value(ksp, name, type, val) < 0)
6938275SEric Cheng 		goto bail;
6948275SEric Cheng 
6958275SEric Cheng 	(void) kstat_close(kcp);
6968275SEric Cheng 	return (DLADM_STATUS_OK);
6978275SEric Cheng 
6988275SEric Cheng bail:
6998275SEric Cheng 	(void) kstat_close(kcp);
7008275SEric Cheng 	return (dladm_errno2status(errno));
7018275SEric Cheng }
7028275SEric Cheng 
7038275SEric Cheng /* Compute sum of 2 pktsums (s1 = s2 + s3) */
7048275SEric Cheng void
dladm_stats_total(pktsum_t * s1,pktsum_t * s2,pktsum_t * s3)7058275SEric Cheng dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
7068275SEric Cheng {
7078275SEric Cheng 	s1->rbytes    = s2->rbytes    + s3->rbytes;
7088275SEric Cheng 	s1->ipackets  = s2->ipackets  + s3->ipackets;
7098275SEric Cheng 	s1->ierrors   = s2->ierrors   + s3->ierrors;
7108275SEric Cheng 	s1->obytes    = s2->obytes    + s3->obytes;
7118275SEric Cheng 	s1->opackets  = s2->opackets  + s3->opackets;
7128275SEric Cheng 	s1->oerrors   = s2->oerrors   + s3->oerrors;
7138275SEric Cheng 	s1->snaptime  = s2->snaptime;
7148275SEric Cheng }
7158275SEric Cheng 
716*11878SVenu.Iyer@Sun.COM #define	DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0)
7179220SPrakash.Jalan@Sun.COM 
7189220SPrakash.Jalan@Sun.COM 
7198275SEric Cheng /* Compute differences between 2 pktsums (s1 = s2 - s3) */
7208275SEric Cheng void
dladm_stats_diff(pktsum_t * s1,pktsum_t * s2,pktsum_t * s3)7218275SEric Cheng dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
7228275SEric Cheng {
7239220SPrakash.Jalan@Sun.COM 	s1->rbytes    = DIFF_STAT(s2->rbytes,   s3->rbytes);
7249220SPrakash.Jalan@Sun.COM 	s1->ipackets  = DIFF_STAT(s2->ipackets, s3->ipackets);
7259220SPrakash.Jalan@Sun.COM 	s1->ierrors   = DIFF_STAT(s2->ierrors,  s3->ierrors);
7269220SPrakash.Jalan@Sun.COM 	s1->obytes    = DIFF_STAT(s2->obytes,   s3->obytes);
7279220SPrakash.Jalan@Sun.COM 	s1->opackets  = DIFF_STAT(s2->opackets, s3->opackets);
7289220SPrakash.Jalan@Sun.COM 	s1->oerrors   = DIFF_STAT(s2->oerrors,  s3->oerrors);
7299220SPrakash.Jalan@Sun.COM 	s1->snaptime  = DIFF_STAT(s2->snaptime, s3->snaptime);
7308275SEric Cheng }
731*11878SVenu.Iyer@Sun.COM 
732*11878SVenu.Iyer@Sun.COM #define	DLSTAT_MAC_RX_SWLANE	"mac_rx_swlane"
733*11878SVenu.Iyer@Sun.COM #define	DLSTAT_MAC_RX_HWLANE	"mac_rx_hwlane"
734*11878SVenu.Iyer@Sun.COM #define	DLSTAT_MAC_TX_SWLANE	"mac_tx_swlane"
735*11878SVenu.Iyer@Sun.COM #define	DLSTAT_MAC_TX_HWLANE	"mac_tx_hwlane"
736*11878SVenu.Iyer@Sun.COM #define	DLSTAT_MAC_MISC_STAT	"mac_misc_stat"
737*11878SVenu.Iyer@Sun.COM #define	DLSTAT_MAC_RX_RING	"mac_rx_ring"
738*11878SVenu.Iyer@Sun.COM #define	DLSTAT_MAC_TX_RING	"mac_tx_ring"
739*11878SVenu.Iyer@Sun.COM #define	DLSTAT_MAC_FANOUT	"mac_rx_swlane0_fanout"
740*11878SVenu.Iyer@Sun.COM 
741*11878SVenu.Iyer@Sun.COM typedef struct {
742*11878SVenu.Iyer@Sun.COM 	const char	*si_name;
743*11878SVenu.Iyer@Sun.COM 	uint_t		si_offset;
744*11878SVenu.Iyer@Sun.COM } stat_info_t;
745*11878SVenu.Iyer@Sun.COM 
746*11878SVenu.Iyer@Sun.COM #define	A_CNT(arr)	(sizeof (arr) / sizeof (arr[0]))
747*11878SVenu.Iyer@Sun.COM 
748*11878SVenu.Iyer@Sun.COM /* Definitions for rx lane stats */
749*11878SVenu.Iyer@Sun.COM #define	RL_OFF(f)	(offsetof(rx_lane_stat_t, f))
750*11878SVenu.Iyer@Sun.COM 
751*11878SVenu.Iyer@Sun.COM static	stat_info_t	rx_hwlane_stats_list[] = {
752*11878SVenu.Iyer@Sun.COM 	{"ipackets",		RL_OFF(rl_ipackets)},
753*11878SVenu.Iyer@Sun.COM 	{"rbytes",		RL_OFF(rl_rbytes)},
754*11878SVenu.Iyer@Sun.COM 	{"intrs",		RL_OFF(rl_intrs)},
755*11878SVenu.Iyer@Sun.COM 	{"intrbytes",		RL_OFF(rl_intrbytes)},
756*11878SVenu.Iyer@Sun.COM 	{"polls",		RL_OFF(rl_polls)},
757*11878SVenu.Iyer@Sun.COM 	{"pollbytes",		RL_OFF(rl_pollbytes)},
758*11878SVenu.Iyer@Sun.COM 	{"rxsdrops",		RL_OFF(rl_sdrops)},
759*11878SVenu.Iyer@Sun.COM 	{"chainunder10",	RL_OFF(rl_chl10)},
760*11878SVenu.Iyer@Sun.COM 	{"chain10to50", 	RL_OFF(rl_ch10_50)},
761*11878SVenu.Iyer@Sun.COM 	{"chainover50", 	RL_OFF(rl_chg50)}
762*11878SVenu.Iyer@Sun.COM };
763*11878SVenu.Iyer@Sun.COM #define	RX_HWLANE_STAT_SIZE	A_CNT(rx_hwlane_stats_list)
764*11878SVenu.Iyer@Sun.COM 
765*11878SVenu.Iyer@Sun.COM static	stat_info_t	rx_swlane_stats_list[] = {
766*11878SVenu.Iyer@Sun.COM 	{"ipackets",		RL_OFF(rl_ipackets)},
767*11878SVenu.Iyer@Sun.COM 	{"rbytes",		RL_OFF(rl_rbytes)},
768*11878SVenu.Iyer@Sun.COM 	{"local",		RL_OFF(rl_lclpackets)},
769*11878SVenu.Iyer@Sun.COM 	{"localbytes",		RL_OFF(rl_lclbytes)},
770*11878SVenu.Iyer@Sun.COM 	{"intrs",		RL_OFF(rl_intrs)},
771*11878SVenu.Iyer@Sun.COM 	{"intrbytes",		RL_OFF(rl_intrbytes)},
772*11878SVenu.Iyer@Sun.COM 	{"rxsdrops",		RL_OFF(rl_sdrops)}
773*11878SVenu.Iyer@Sun.COM };
774*11878SVenu.Iyer@Sun.COM #define	RX_SWLANE_STAT_SIZE	A_CNT(rx_swlane_stats_list)
775*11878SVenu.Iyer@Sun.COM 
776*11878SVenu.Iyer@Sun.COM static	stat_info_t	rx_lane_stats_list[] = {
777*11878SVenu.Iyer@Sun.COM 	{"ipackets",		RL_OFF(rl_ipackets)},
778*11878SVenu.Iyer@Sun.COM 	{"rbytes",		RL_OFF(rl_rbytes)},
779*11878SVenu.Iyer@Sun.COM 	{"local",		RL_OFF(rl_lclpackets)},
780*11878SVenu.Iyer@Sun.COM 	{"localbytes",		RL_OFF(rl_lclbytes)},
781*11878SVenu.Iyer@Sun.COM 	{"intrs",		RL_OFF(rl_intrs)},
782*11878SVenu.Iyer@Sun.COM 	{"intrbytes",		RL_OFF(rl_intrbytes)},
783*11878SVenu.Iyer@Sun.COM 	{"polls",		RL_OFF(rl_polls)},
784*11878SVenu.Iyer@Sun.COM 	{"rxsdrops",		RL_OFF(rl_sdrops)},
785*11878SVenu.Iyer@Sun.COM 	{"pollbytes",		RL_OFF(rl_pollbytes)},
786*11878SVenu.Iyer@Sun.COM 	{"chainunder10",	RL_OFF(rl_chl10)},
787*11878SVenu.Iyer@Sun.COM 	{"chain10to50", 	RL_OFF(rl_ch10_50)},
788*11878SVenu.Iyer@Sun.COM 	{"chainover50", 	RL_OFF(rl_chg50)}
789*11878SVenu.Iyer@Sun.COM };
790*11878SVenu.Iyer@Sun.COM #define	RX_LANE_STAT_SIZE	A_CNT(rx_lane_stats_list)
791*11878SVenu.Iyer@Sun.COM 
792*11878SVenu.Iyer@Sun.COM /* Definitions for tx lane stats */
793*11878SVenu.Iyer@Sun.COM #define	TL_OFF(f)	(offsetof(tx_lane_stat_t, f))
794*11878SVenu.Iyer@Sun.COM 
795*11878SVenu.Iyer@Sun.COM static	stat_info_t	tx_lane_stats_list[] = {
796*11878SVenu.Iyer@Sun.COM 	{"opackets",	TL_OFF(tl_opackets)},
797*11878SVenu.Iyer@Sun.COM 	{"obytes",	TL_OFF(tl_obytes)},
798*11878SVenu.Iyer@Sun.COM 	{"blockcnt",	TL_OFF(tl_blockcnt)},
799*11878SVenu.Iyer@Sun.COM 	{"unblockcnt",	TL_OFF(tl_unblockcnt)},
800*11878SVenu.Iyer@Sun.COM 	{"txsdrops",	TL_OFF(tl_sdrops)}
801*11878SVenu.Iyer@Sun.COM };
802*11878SVenu.Iyer@Sun.COM #define	TX_LANE_STAT_SIZE	A_CNT(tx_lane_stats_list)
803*11878SVenu.Iyer@Sun.COM 
804*11878SVenu.Iyer@Sun.COM /* Definitions for tx/rx misc stats */
805*11878SVenu.Iyer@Sun.COM #define	M_OFF(f)	(offsetof(misc_stat_t, f))
806*11878SVenu.Iyer@Sun.COM 
807*11878SVenu.Iyer@Sun.COM static	stat_info_t	misc_stats_list[] = {
808*11878SVenu.Iyer@Sun.COM 	{"multircv",		M_OFF(ms_multircv)},
809*11878SVenu.Iyer@Sun.COM 	{"brdcstrcv",		M_OFF(ms_brdcstrcv)},
810*11878SVenu.Iyer@Sun.COM 	{"multixmt",		M_OFF(ms_multixmt)},
811*11878SVenu.Iyer@Sun.COM 	{"brdcstxmt",		M_OFF(ms_brdcstxmt)},
812*11878SVenu.Iyer@Sun.COM 	{"multircvbytes",	M_OFF(ms_multircvbytes)},
813*11878SVenu.Iyer@Sun.COM 	{"brdcstrcvbytes",	M_OFF(ms_brdcstrcvbytes)},
814*11878SVenu.Iyer@Sun.COM 	{"multixmtbytes",	M_OFF(ms_multixmtbytes)},
815*11878SVenu.Iyer@Sun.COM 	{"brdcstxmtbytes",	M_OFF(ms_brdcstxmtbytes)},
816*11878SVenu.Iyer@Sun.COM 	{"txerrors",		M_OFF(ms_txerrors)},
817*11878SVenu.Iyer@Sun.COM 	{"macspoofed",		M_OFF(ms_macspoofed)},
818*11878SVenu.Iyer@Sun.COM 	{"ipspoofed",		M_OFF(ms_ipspoofed)},
819*11878SVenu.Iyer@Sun.COM 	{"dhcpspoofed",		M_OFF(ms_dhcpspoofed)},
820*11878SVenu.Iyer@Sun.COM 	{"restricted",		M_OFF(ms_restricted)},
821*11878SVenu.Iyer@Sun.COM 	{"ipackets",		M_OFF(ms_ipackets)},
822*11878SVenu.Iyer@Sun.COM 	{"rbytes",		M_OFF(ms_rbytes)},
823*11878SVenu.Iyer@Sun.COM 	{"local",		M_OFF(ms_local)},
824*11878SVenu.Iyer@Sun.COM 	{"localbytes",		M_OFF(ms_localbytes)},
825*11878SVenu.Iyer@Sun.COM 	{"intrs",		M_OFF(ms_intrs)},
826*11878SVenu.Iyer@Sun.COM 	{"intrbytes",		M_OFF(ms_intrbytes)},
827*11878SVenu.Iyer@Sun.COM 	{"polls",		M_OFF(ms_polls)},
828*11878SVenu.Iyer@Sun.COM 	{"pollbytes",		M_OFF(ms_pollbytes)},
829*11878SVenu.Iyer@Sun.COM 	{"rxsdrops",		M_OFF(ms_rxsdrops)},
830*11878SVenu.Iyer@Sun.COM 	{"chainunder10",	M_OFF(ms_chainunder10)},
831*11878SVenu.Iyer@Sun.COM 	{"chain10to50",		M_OFF(ms_chain10to50)},
832*11878SVenu.Iyer@Sun.COM 	{"chainover50",		M_OFF(ms_chainover50)},
833*11878SVenu.Iyer@Sun.COM 	{"obytes",		M_OFF(ms_obytes)},
834*11878SVenu.Iyer@Sun.COM 	{"opackets",		M_OFF(ms_opackets)},
835*11878SVenu.Iyer@Sun.COM 	{"blockcnt",		M_OFF(ms_blockcnt)},
836*11878SVenu.Iyer@Sun.COM 	{"unblockcnt",		M_OFF(ms_unblockcnt)},
837*11878SVenu.Iyer@Sun.COM 	{"txsdrops",		M_OFF(ms_txsdrops)}
838*11878SVenu.Iyer@Sun.COM };
839*11878SVenu.Iyer@Sun.COM #define	MISC_STAT_SIZE		A_CNT(misc_stats_list)
840*11878SVenu.Iyer@Sun.COM 
841*11878SVenu.Iyer@Sun.COM /* Definitions for rx ring stats */
842*11878SVenu.Iyer@Sun.COM #define	R_OFF(f)	(offsetof(ring_stat_t, f))
843*11878SVenu.Iyer@Sun.COM 
844*11878SVenu.Iyer@Sun.COM static	stat_info_t	rx_ring_stats_list[] = {
845*11878SVenu.Iyer@Sun.COM 	{"ipackets",	R_OFF(r_packets)},
846*11878SVenu.Iyer@Sun.COM 	{"rbytes",	R_OFF(r_bytes)}
847*11878SVenu.Iyer@Sun.COM };
848*11878SVenu.Iyer@Sun.COM #define	RX_RING_STAT_SIZE	A_CNT(rx_ring_stats_list)
849*11878SVenu.Iyer@Sun.COM 
850*11878SVenu.Iyer@Sun.COM /* Definitions for tx ring stats */
851*11878SVenu.Iyer@Sun.COM static	stat_info_t	tx_ring_stats_list[] = {
852*11878SVenu.Iyer@Sun.COM 	{"opackets",	R_OFF(r_packets)},
853*11878SVenu.Iyer@Sun.COM 	{"obytes",	R_OFF(r_bytes)}
854*11878SVenu.Iyer@Sun.COM };
855*11878SVenu.Iyer@Sun.COM #define	TX_RING_STAT_SIZE	A_CNT(tx_ring_stats_list)
856*11878SVenu.Iyer@Sun.COM 
857*11878SVenu.Iyer@Sun.COM /* Definitions for fanout stats */
858*11878SVenu.Iyer@Sun.COM #define	F_OFF(f)	(offsetof(fanout_stat_t, f))
859*11878SVenu.Iyer@Sun.COM 
860*11878SVenu.Iyer@Sun.COM static	stat_info_t	fanout_stats_list[] = {
861*11878SVenu.Iyer@Sun.COM 	{"ipackets",	F_OFF(f_ipackets)},
862*11878SVenu.Iyer@Sun.COM 	{"rbytes",	F_OFF(f_rbytes)},
863*11878SVenu.Iyer@Sun.COM };
864*11878SVenu.Iyer@Sun.COM #define	FANOUT_STAT_SIZE	A_CNT(fanout_stats_list)
865*11878SVenu.Iyer@Sun.COM 
866*11878SVenu.Iyer@Sun.COM /* Definitions for total stats */
867*11878SVenu.Iyer@Sun.COM #define	T_OFF(f)	(offsetof(total_stat_t, f))
868*11878SVenu.Iyer@Sun.COM 
869*11878SVenu.Iyer@Sun.COM static	stat_info_t	total_stats_list[] = {
870*11878SVenu.Iyer@Sun.COM 	{"ipackets",	T_OFF(ts_ipackets)},
871*11878SVenu.Iyer@Sun.COM 	{"rbytes",	T_OFF(ts_rbytes)},
872*11878SVenu.Iyer@Sun.COM 	{"opackets",	T_OFF(ts_opackets)},
873*11878SVenu.Iyer@Sun.COM 	{"obytes",	T_OFF(ts_obytes)}
874*11878SVenu.Iyer@Sun.COM };
875*11878SVenu.Iyer@Sun.COM #define	TOTAL_STAT_SIZE		A_CNT(total_stats_list)
876*11878SVenu.Iyer@Sun.COM 
877*11878SVenu.Iyer@Sun.COM /* Definitions for aggr stats */
878*11878SVenu.Iyer@Sun.COM #define	AP_OFF(f)	(offsetof(aggr_port_stat_t, f))
879*11878SVenu.Iyer@Sun.COM 
880*11878SVenu.Iyer@Sun.COM static	stat_info_t	aggr_port_stats_list[] = {
881*11878SVenu.Iyer@Sun.COM 	{"ipackets64",	AP_OFF(ap_ipackets)},
882*11878SVenu.Iyer@Sun.COM 	{"rbytes64",	AP_OFF(ap_rbytes)},
883*11878SVenu.Iyer@Sun.COM 	{"opackets64",	AP_OFF(ap_opackets)},
884*11878SVenu.Iyer@Sun.COM 	{"obytes64",	AP_OFF(ap_obytes)}
885*11878SVenu.Iyer@Sun.COM };
886*11878SVenu.Iyer@Sun.COM #define	AGGR_PORT_STAT_SIZE	A_CNT(aggr_port_stats_list)
887*11878SVenu.Iyer@Sun.COM 
888*11878SVenu.Iyer@Sun.COM /* Definitions for flow stats */
889*11878SVenu.Iyer@Sun.COM #define	FL_OFF(f)	(offsetof(flow_stat_t, f))
890*11878SVenu.Iyer@Sun.COM 
891*11878SVenu.Iyer@Sun.COM static	stat_info_t	flow_stats_list[] = {
892*11878SVenu.Iyer@Sun.COM 	{"ipackets",	FL_OFF(fl_ipackets)},
893*11878SVenu.Iyer@Sun.COM 	{"rbytes",	FL_OFF(fl_rbytes)},
894*11878SVenu.Iyer@Sun.COM 	{"opackets",	FL_OFF(fl_opackets)},
895*11878SVenu.Iyer@Sun.COM 	{"obytes",	FL_OFF(fl_obytes)}
896*11878SVenu.Iyer@Sun.COM };
897*11878SVenu.Iyer@Sun.COM #define	FLOW_STAT_SIZE		A_CNT(flow_stats_list)
898*11878SVenu.Iyer@Sun.COM 
899*11878SVenu.Iyer@Sun.COM /* Rx lane specific functions */
900*11878SVenu.Iyer@Sun.COM void *			dlstat_rx_lane_stats(dladm_handle_t, datalink_id_t);
901*11878SVenu.Iyer@Sun.COM static boolean_t	i_dlstat_rx_lane_match(void *, void *);
902*11878SVenu.Iyer@Sun.COM static void *		i_dlstat_rx_lane_stat_entry_diff(void *, void *);
903*11878SVenu.Iyer@Sun.COM 
904*11878SVenu.Iyer@Sun.COM /* Tx lane specific functions */
905*11878SVenu.Iyer@Sun.COM void *			dlstat_tx_lane_stats(dladm_handle_t, datalink_id_t);
906*11878SVenu.Iyer@Sun.COM static boolean_t	i_dlstat_tx_lane_match(void *, void *);
907*11878SVenu.Iyer@Sun.COM static void *		i_dlstat_tx_lane_stat_entry_diff(void *, void *);
908*11878SVenu.Iyer@Sun.COM 
909*11878SVenu.Iyer@Sun.COM /* Rx lane total specific functions */
910*11878SVenu.Iyer@Sun.COM void *			dlstat_rx_lane_total_stats(dladm_handle_t,
911*11878SVenu.Iyer@Sun.COM 			    datalink_id_t);
912*11878SVenu.Iyer@Sun.COM 
913*11878SVenu.Iyer@Sun.COM /* Tx lane total specific functions */
914*11878SVenu.Iyer@Sun.COM void *			dlstat_tx_lane_total_stats(dladm_handle_t,
915*11878SVenu.Iyer@Sun.COM 			    datalink_id_t);
916*11878SVenu.Iyer@Sun.COM 
917*11878SVenu.Iyer@Sun.COM /* Fanout specific functions */
918*11878SVenu.Iyer@Sun.COM void *			dlstat_fanout_stats(dladm_handle_t, datalink_id_t);
919*11878SVenu.Iyer@Sun.COM static boolean_t	i_dlstat_fanout_match(void *, void *);
920*11878SVenu.Iyer@Sun.COM static void *		i_dlstat_fanout_stat_entry_diff(void *, void *);
921*11878SVenu.Iyer@Sun.COM 
922*11878SVenu.Iyer@Sun.COM /* Rx ring specific functions */
923*11878SVenu.Iyer@Sun.COM void *			dlstat_rx_ring_stats(dladm_handle_t, datalink_id_t);
924*11878SVenu.Iyer@Sun.COM static boolean_t	i_dlstat_rx_ring_match(void *, void *);
925*11878SVenu.Iyer@Sun.COM static void *		i_dlstat_rx_ring_stat_entry_diff(void *, void *);
926*11878SVenu.Iyer@Sun.COM 
927*11878SVenu.Iyer@Sun.COM /* Tx ring specific functions */
928*11878SVenu.Iyer@Sun.COM void *			dlstat_tx_ring_stats(dladm_handle_t, datalink_id_t);
929*11878SVenu.Iyer@Sun.COM static boolean_t	i_dlstat_tx_ring_match(void *, void *);
930*11878SVenu.Iyer@Sun.COM static void *		i_dlstat_tx_ring_stat_entry_diff(void *, void *);
931*11878SVenu.Iyer@Sun.COM 
932*11878SVenu.Iyer@Sun.COM /* Rx ring total specific functions */
933*11878SVenu.Iyer@Sun.COM void *			dlstat_rx_ring_total_stats(dladm_handle_t,
934*11878SVenu.Iyer@Sun.COM 			    datalink_id_t);
935*11878SVenu.Iyer@Sun.COM 
936*11878SVenu.Iyer@Sun.COM /* Tx ring total specific functions */
937*11878SVenu.Iyer@Sun.COM void *			dlstat_tx_ring_total_stats(dladm_handle_t,
938*11878SVenu.Iyer@Sun.COM 			    datalink_id_t);
939*11878SVenu.Iyer@Sun.COM 
940*11878SVenu.Iyer@Sun.COM /* Summary specific functions */
941*11878SVenu.Iyer@Sun.COM void *			dlstat_total_stats(dladm_handle_t, datalink_id_t);
942*11878SVenu.Iyer@Sun.COM static boolean_t	i_dlstat_total_match(void *, void *);
943*11878SVenu.Iyer@Sun.COM static void *		i_dlstat_total_stat_entry_diff(void *, void *);
944*11878SVenu.Iyer@Sun.COM 
945*11878SVenu.Iyer@Sun.COM /* Aggr port specific functions */
946*11878SVenu.Iyer@Sun.COM void *			dlstat_aggr_port_stats(dladm_handle_t, datalink_id_t);
947*11878SVenu.Iyer@Sun.COM static boolean_t	i_dlstat_aggr_port_match(void *, void *);
948*11878SVenu.Iyer@Sun.COM static void *		i_dlstat_aggr_port_stat_entry_diff(void *, void *);
949*11878SVenu.Iyer@Sun.COM 
950*11878SVenu.Iyer@Sun.COM /* Misc stat specific functions */
951*11878SVenu.Iyer@Sun.COM void *			dlstat_misc_stats(dladm_handle_t, datalink_id_t);
952*11878SVenu.Iyer@Sun.COM 
953*11878SVenu.Iyer@Sun.COM typedef void *		dladm_stat_query_t(dladm_handle_t, datalink_id_t);
954*11878SVenu.Iyer@Sun.COM typedef boolean_t	dladm_stat_match_t(void *, void *);
955*11878SVenu.Iyer@Sun.COM typedef void *		dladm_stat_diff_t(void *, void *);
956*11878SVenu.Iyer@Sun.COM 
957*11878SVenu.Iyer@Sun.COM typedef struct dladm_stat_desc_s {
958*11878SVenu.Iyer@Sun.COM 	dladm_stat_type_t	ds_stattype;
959*11878SVenu.Iyer@Sun.COM 	dladm_stat_query_t	*ds_querystat;
960*11878SVenu.Iyer@Sun.COM 	dladm_stat_match_t	*ds_matchstat;
961*11878SVenu.Iyer@Sun.COM 	dladm_stat_diff_t	*ds_diffstat;
962*11878SVenu.Iyer@Sun.COM 	uint_t			ds_offset;
963*11878SVenu.Iyer@Sun.COM 	stat_info_t		*ds_statlist;
964*11878SVenu.Iyer@Sun.COM 	uint_t			ds_statsize;
965*11878SVenu.Iyer@Sun.COM } dladm_stat_desc_t;
966*11878SVenu.Iyer@Sun.COM 
967*11878SVenu.Iyer@Sun.COM /*
968*11878SVenu.Iyer@Sun.COM  * dladm_stat_table has one entry for each supported stat. ds_querystat returns
969*11878SVenu.Iyer@Sun.COM  * a chain of 'stat entries' for the queried stat.
970*11878SVenu.Iyer@Sun.COM  * Each stat entry has set of identifiers (ids) and an object containing actual
971*11878SVenu.Iyer@Sun.COM  * stat values. These stat entry objects are chained together in a linked list
972*11878SVenu.Iyer@Sun.COM  * of datatype dladm_stat_chain_t. Head of this list is returned to the caller
973*11878SVenu.Iyer@Sun.COM  * of dladm_link_stat_query.
974*11878SVenu.Iyer@Sun.COM  *
975*11878SVenu.Iyer@Sun.COM  * One node in the chain is shown below:
976*11878SVenu.Iyer@Sun.COM  *
977*11878SVenu.Iyer@Sun.COM  *	-------------------------
978*11878SVenu.Iyer@Sun.COM  *	| dc_statentry	        |
979*11878SVenu.Iyer@Sun.COM  *	|    --------------     |
980*11878SVenu.Iyer@Sun.COM  *	|    |     ids     |	|
981*11878SVenu.Iyer@Sun.COM  *	|    --------------     |
982*11878SVenu.Iyer@Sun.COM  *	|    | stat fields |	|
983*11878SVenu.Iyer@Sun.COM  *	|    --------------     |
984*11878SVenu.Iyer@Sun.COM  *	-------------------------
985*11878SVenu.Iyer@Sun.COM  *	|      dc_next ---------|------> to next stat entry
986*11878SVenu.Iyer@Sun.COM  *	-------------------------
987*11878SVenu.Iyer@Sun.COM  *
988*11878SVenu.Iyer@Sun.COM  * In particular, for query DLADM_STAT_RX_LANE, dc_statentry carries pointer to
989*11878SVenu.Iyer@Sun.COM  * object of type rx_lane_stat_entry_t.
990*11878SVenu.Iyer@Sun.COM  *
991*11878SVenu.Iyer@Sun.COM  * dladm_link_stat_query_all returns similar chain. However, instead of storing
992*11878SVenu.Iyer@Sun.COM  * stat fields as raw numbers, it stores those as chain of <name, value> pairs.
993*11878SVenu.Iyer@Sun.COM  * The resulting structure is depicted below:
994*11878SVenu.Iyer@Sun.COM  *
995*11878SVenu.Iyer@Sun.COM  *	-------------------------
996*11878SVenu.Iyer@Sun.COM  *	| dc_statentry	        |
997*11878SVenu.Iyer@Sun.COM  *	|    --------------     |   ---------------
998*11878SVenu.Iyer@Sun.COM  *	|    |  nv_header  |	|   |   name, val  |
999*11878SVenu.Iyer@Sun.COM  *	|    --------------     |   ---------------
1000*11878SVenu.Iyer@Sun.COM  *	|    | nve_stats---|----|-->| nv_nextstat--|---> to next name, val pair
1001*11878SVenu.Iyer@Sun.COM  *	|    --------------     |   ---------------
1002*11878SVenu.Iyer@Sun.COM  *	-------------------------
1003*11878SVenu.Iyer@Sun.COM  *	|      dc_next ---------|------> to next stat entry
1004*11878SVenu.Iyer@Sun.COM  *	-------------------------
1005*11878SVenu.Iyer@Sun.COM  */
1006*11878SVenu.Iyer@Sun.COM static dladm_stat_desc_t  dladm_stat_table[] = {
1007*11878SVenu.Iyer@Sun.COM { DLADM_STAT_RX_LANE,		dlstat_rx_lane_stats,
1008*11878SVenu.Iyer@Sun.COM     i_dlstat_rx_lane_match,	i_dlstat_rx_lane_stat_entry_diff,
1009*11878SVenu.Iyer@Sun.COM     offsetof(rx_lane_stat_entry_t, rle_stats),
1010*11878SVenu.Iyer@Sun.COM     rx_lane_stats_list,		RX_LANE_STAT_SIZE},
1011*11878SVenu.Iyer@Sun.COM 
1012*11878SVenu.Iyer@Sun.COM { DLADM_STAT_TX_LANE,		dlstat_tx_lane_stats,
1013*11878SVenu.Iyer@Sun.COM     i_dlstat_tx_lane_match,	i_dlstat_tx_lane_stat_entry_diff,
1014*11878SVenu.Iyer@Sun.COM     offsetof(tx_lane_stat_entry_t, tle_stats),
1015*11878SVenu.Iyer@Sun.COM     tx_lane_stats_list,		TX_LANE_STAT_SIZE},
1016*11878SVenu.Iyer@Sun.COM 
1017*11878SVenu.Iyer@Sun.COM { DLADM_STAT_RX_LANE_TOTAL,	dlstat_rx_lane_total_stats,
1018*11878SVenu.Iyer@Sun.COM     i_dlstat_rx_lane_match,	i_dlstat_rx_lane_stat_entry_diff,
1019*11878SVenu.Iyer@Sun.COM     offsetof(rx_lane_stat_entry_t, rle_stats),
1020*11878SVenu.Iyer@Sun.COM     rx_lane_stats_list,		RX_LANE_STAT_SIZE},
1021*11878SVenu.Iyer@Sun.COM 
1022*11878SVenu.Iyer@Sun.COM { DLADM_STAT_TX_LANE_TOTAL,	dlstat_tx_lane_total_stats,
1023*11878SVenu.Iyer@Sun.COM     i_dlstat_tx_lane_match,	i_dlstat_tx_lane_stat_entry_diff,
1024*11878SVenu.Iyer@Sun.COM     offsetof(tx_lane_stat_entry_t, tle_stats),
1025*11878SVenu.Iyer@Sun.COM     tx_lane_stats_list,		TX_LANE_STAT_SIZE},
1026*11878SVenu.Iyer@Sun.COM 
1027*11878SVenu.Iyer@Sun.COM { DLADM_STAT_RX_LANE_FOUT,	dlstat_fanout_stats,
1028*11878SVenu.Iyer@Sun.COM     i_dlstat_fanout_match,	i_dlstat_fanout_stat_entry_diff,
1029*11878SVenu.Iyer@Sun.COM     offsetof(fanout_stat_entry_t, fe_stats),
1030*11878SVenu.Iyer@Sun.COM     fanout_stats_list,		FANOUT_STAT_SIZE},
1031*11878SVenu.Iyer@Sun.COM 
1032*11878SVenu.Iyer@Sun.COM { DLADM_STAT_RX_RING,		dlstat_rx_ring_stats,
1033*11878SVenu.Iyer@Sun.COM     i_dlstat_rx_ring_match,	i_dlstat_rx_ring_stat_entry_diff,
1034*11878SVenu.Iyer@Sun.COM     offsetof(ring_stat_entry_t, re_stats),
1035*11878SVenu.Iyer@Sun.COM     rx_ring_stats_list,		RX_RING_STAT_SIZE},
1036*11878SVenu.Iyer@Sun.COM 
1037*11878SVenu.Iyer@Sun.COM { DLADM_STAT_TX_RING,		dlstat_tx_ring_stats,
1038*11878SVenu.Iyer@Sun.COM     i_dlstat_tx_ring_match,	i_dlstat_tx_ring_stat_entry_diff,
1039*11878SVenu.Iyer@Sun.COM     offsetof(ring_stat_entry_t, re_stats),
1040*11878SVenu.Iyer@Sun.COM     tx_ring_stats_list,		TX_RING_STAT_SIZE},
1041*11878SVenu.Iyer@Sun.COM 
1042*11878SVenu.Iyer@Sun.COM { DLADM_STAT_RX_RING_TOTAL,	dlstat_rx_ring_total_stats,
1043*11878SVenu.Iyer@Sun.COM     i_dlstat_rx_ring_match,	i_dlstat_rx_ring_stat_entry_diff,
1044*11878SVenu.Iyer@Sun.COM     offsetof(ring_stat_entry_t, re_stats),
1045*11878SVenu.Iyer@Sun.COM     rx_ring_stats_list,		RX_RING_STAT_SIZE},
1046*11878SVenu.Iyer@Sun.COM 
1047*11878SVenu.Iyer@Sun.COM { DLADM_STAT_TX_RING_TOTAL,	dlstat_tx_ring_total_stats,
1048*11878SVenu.Iyer@Sun.COM     i_dlstat_tx_ring_match,	i_dlstat_tx_ring_stat_entry_diff,
1049*11878SVenu.Iyer@Sun.COM     offsetof(ring_stat_entry_t, re_stats),
1050*11878SVenu.Iyer@Sun.COM     tx_ring_stats_list,		TX_RING_STAT_SIZE},
1051*11878SVenu.Iyer@Sun.COM 
1052*11878SVenu.Iyer@Sun.COM { DLADM_STAT_TOTAL,		dlstat_total_stats,
1053*11878SVenu.Iyer@Sun.COM     i_dlstat_total_match,	i_dlstat_total_stat_entry_diff,
1054*11878SVenu.Iyer@Sun.COM     offsetof(total_stat_entry_t, tse_stats),
1055*11878SVenu.Iyer@Sun.COM     total_stats_list,		TOTAL_STAT_SIZE},
1056*11878SVenu.Iyer@Sun.COM 
1057*11878SVenu.Iyer@Sun.COM { DLADM_STAT_AGGR_PORT,		dlstat_aggr_port_stats,
1058*11878SVenu.Iyer@Sun.COM     i_dlstat_aggr_port_match,	i_dlstat_aggr_port_stat_entry_diff,
1059*11878SVenu.Iyer@Sun.COM     offsetof(aggr_port_stat_entry_t, ape_stats),
1060*11878SVenu.Iyer@Sun.COM     aggr_port_stats_list,	AGGR_PORT_STAT_SIZE},
1061*11878SVenu.Iyer@Sun.COM /*
1062*11878SVenu.Iyer@Sun.COM  * We don't support -i <interval> query with misc stats. Several table fields
1063*11878SVenu.Iyer@Sun.COM  * are left uninitialized thus.
1064*11878SVenu.Iyer@Sun.COM  */
1065*11878SVenu.Iyer@Sun.COM { DLADM_STAT_MISC,		dlstat_misc_stats,
1066*11878SVenu.Iyer@Sun.COM     NULL,			NULL,
1067*11878SVenu.Iyer@Sun.COM     0,
1068*11878SVenu.Iyer@Sun.COM     misc_stats_list,		MISC_STAT_SIZE}
1069*11878SVenu.Iyer@Sun.COM };
1070*11878SVenu.Iyer@Sun.COM 
1071*11878SVenu.Iyer@Sun.COM /* Internal functions */
1072*11878SVenu.Iyer@Sun.COM static void *
dlstat_diff_stats(void * arg1,void * arg2,dladm_stat_type_t stattype)1073*11878SVenu.Iyer@Sun.COM dlstat_diff_stats(void *arg1, void *arg2, dladm_stat_type_t stattype)
1074*11878SVenu.Iyer@Sun.COM {
1075*11878SVenu.Iyer@Sun.COM 	return (dladm_stat_table[stattype].ds_diffstat(arg1, arg2));
1076*11878SVenu.Iyer@Sun.COM }
1077*11878SVenu.Iyer@Sun.COM 
1078*11878SVenu.Iyer@Sun.COM static boolean_t
dlstat_match_stats(void * arg1,void * arg2,dladm_stat_type_t stattype)1079*11878SVenu.Iyer@Sun.COM dlstat_match_stats(void *arg1, void *arg2, dladm_stat_type_t stattype)
1080*11878SVenu.Iyer@Sun.COM {
1081*11878SVenu.Iyer@Sun.COM 	return (dladm_stat_table[stattype].ds_matchstat(arg1, arg2));
1082*11878SVenu.Iyer@Sun.COM }
1083*11878SVenu.Iyer@Sun.COM 
1084*11878SVenu.Iyer@Sun.COM /* Diff between two stats */
1085*11878SVenu.Iyer@Sun.COM static void
i_dlstat_diff_stats(void * diff,void * op1,void * op2,stat_info_t stats_list[],uint_t size)1086*11878SVenu.Iyer@Sun.COM i_dlstat_diff_stats(void *diff, void *op1, void *op2,
1087*11878SVenu.Iyer@Sun.COM     stat_info_t stats_list[], uint_t size)
1088*11878SVenu.Iyer@Sun.COM {
1089*11878SVenu.Iyer@Sun.COM 	int	i;
1090*11878SVenu.Iyer@Sun.COM 
1091*11878SVenu.Iyer@Sun.COM 	for (i = 0; i < size; i++) {
1092*11878SVenu.Iyer@Sun.COM 		uint64_t *op1_val  = (void *)
1093*11878SVenu.Iyer@Sun.COM 		    ((uchar_t *)op1 + stats_list[i].si_offset);
1094*11878SVenu.Iyer@Sun.COM 		uint64_t *op2_val = (void *)
1095*11878SVenu.Iyer@Sun.COM 		    ((uchar_t *)op2  + stats_list[i].si_offset);
1096*11878SVenu.Iyer@Sun.COM 		uint64_t *diff_val = (void *)
1097*11878SVenu.Iyer@Sun.COM 		    ((uchar_t *)diff + stats_list[i].si_offset);
1098*11878SVenu.Iyer@Sun.COM 
1099*11878SVenu.Iyer@Sun.COM 		*diff_val = DIFF_STAT(*op1_val, *op2_val);
1100*11878SVenu.Iyer@Sun.COM 	}
1101*11878SVenu.Iyer@Sun.COM }
1102*11878SVenu.Iyer@Sun.COM 
1103*11878SVenu.Iyer@Sun.COM /*
1104*11878SVenu.Iyer@Sun.COM  * Perform diff = s1 - s2,  where diff, s1, s2 are structure objects of same
1105*11878SVenu.Iyer@Sun.COM  * datatype. slist is list of offsets of the fields within the structure.
1106*11878SVenu.Iyer@Sun.COM  */
1107*11878SVenu.Iyer@Sun.COM #define	DLSTAT_DIFF_STAT(s1, s2, diff, f, slist, sz) {			\
1108*11878SVenu.Iyer@Sun.COM 	if (s2 == NULL) {						\
1109*11878SVenu.Iyer@Sun.COM 		bcopy(&s1->f, &diff->f, sizeof (s1->f));		\
1110*11878SVenu.Iyer@Sun.COM 	} else {							\
1111*11878SVenu.Iyer@Sun.COM 		i_dlstat_diff_stats(&diff->f, &s1->f,			\
1112*11878SVenu.Iyer@Sun.COM 		    &s2->f, slist, sz);					\
1113*11878SVenu.Iyer@Sun.COM 	}								\
1114*11878SVenu.Iyer@Sun.COM }
1115*11878SVenu.Iyer@Sun.COM 
1116*11878SVenu.Iyer@Sun.COM /* Sum two stats */
1117*11878SVenu.Iyer@Sun.COM static void
i_dlstat_sum_stats(void * sum,void * op1,void * op2,stat_info_t stats_list[],uint_t size)1118*11878SVenu.Iyer@Sun.COM i_dlstat_sum_stats(void *sum, void *op1, void *op2,
1119*11878SVenu.Iyer@Sun.COM     stat_info_t stats_list[], uint_t size)
1120*11878SVenu.Iyer@Sun.COM {
1121*11878SVenu.Iyer@Sun.COM 	int	i;
1122*11878SVenu.Iyer@Sun.COM 
1123*11878SVenu.Iyer@Sun.COM 	for (i = 0; i < size; i++) {
1124*11878SVenu.Iyer@Sun.COM 		uint64_t *op1_val = (void *)
1125*11878SVenu.Iyer@Sun.COM 		    ((uchar_t *)op1 + stats_list[i].si_offset);
1126*11878SVenu.Iyer@Sun.COM 		uint64_t *op2_val = (void *)
1127*11878SVenu.Iyer@Sun.COM 		    ((uchar_t *)op2 + stats_list[i].si_offset);
1128*11878SVenu.Iyer@Sun.COM 		uint64_t *sum_val = (void *)
1129*11878SVenu.Iyer@Sun.COM 		    ((uchar_t *)sum + stats_list[i].si_offset);
1130*11878SVenu.Iyer@Sun.COM 
1131*11878SVenu.Iyer@Sun.COM 		*sum_val =  *op1_val + *op2_val;
1132*11878SVenu.Iyer@Sun.COM 	}
1133*11878SVenu.Iyer@Sun.COM }
1134*11878SVenu.Iyer@Sun.COM 
1135*11878SVenu.Iyer@Sun.COM /* Look up kstat value */
1136*11878SVenu.Iyer@Sun.COM static void
i_dlstat_get_stats(kstat_ctl_t * kcp,kstat_t * ksp,void * stats,stat_info_t stats_list[],uint_t size)1137*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, void *stats,
1138*11878SVenu.Iyer@Sun.COM     stat_info_t stats_list[], uint_t size)
1139*11878SVenu.Iyer@Sun.COM {
1140*11878SVenu.Iyer@Sun.COM 	int	i;
1141*11878SVenu.Iyer@Sun.COM 
1142*11878SVenu.Iyer@Sun.COM 	if (kstat_read(kcp, ksp, NULL) == -1)
1143*11878SVenu.Iyer@Sun.COM 		return;
1144*11878SVenu.Iyer@Sun.COM 
1145*11878SVenu.Iyer@Sun.COM 	for (i = 0; i < size; i++) {
1146*11878SVenu.Iyer@Sun.COM 		uint64_t *val = (void *)
1147*11878SVenu.Iyer@Sun.COM 		    ((uchar_t *)stats + stats_list[i].si_offset);
1148*11878SVenu.Iyer@Sun.COM 
1149*11878SVenu.Iyer@Sun.COM 		if (dladm_kstat_value(ksp, stats_list[i].si_name,
1150*11878SVenu.Iyer@Sun.COM 		    KSTAT_DATA_UINT64, val) < 0)
1151*11878SVenu.Iyer@Sun.COM 			return;
1152*11878SVenu.Iyer@Sun.COM 	}
1153*11878SVenu.Iyer@Sun.COM }
1154*11878SVenu.Iyer@Sun.COM 
1155*11878SVenu.Iyer@Sun.COM /* Append linked list list1 to linked list list2 and return resulting list */
1156*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_join_lists(dladm_stat_chain_t * list1,dladm_stat_chain_t * list2)1157*11878SVenu.Iyer@Sun.COM i_dlstat_join_lists(dladm_stat_chain_t *list1, dladm_stat_chain_t *list2)
1158*11878SVenu.Iyer@Sun.COM {
1159*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*curr;
1160*11878SVenu.Iyer@Sun.COM 
1161*11878SVenu.Iyer@Sun.COM 	if (list1 == NULL)
1162*11878SVenu.Iyer@Sun.COM 		return (list2);
1163*11878SVenu.Iyer@Sun.COM 
1164*11878SVenu.Iyer@Sun.COM 	/* list1 has at least one element, find last element in list1 */
1165*11878SVenu.Iyer@Sun.COM 	curr = list1;
1166*11878SVenu.Iyer@Sun.COM 	while (curr->dc_next != NULL)
1167*11878SVenu.Iyer@Sun.COM 		curr = curr->dc_next;
1168*11878SVenu.Iyer@Sun.COM 
1169*11878SVenu.Iyer@Sun.COM 	curr->dc_next = list2;
1170*11878SVenu.Iyer@Sun.COM 	return (list1);
1171*11878SVenu.Iyer@Sun.COM }
1172*11878SVenu.Iyer@Sun.COM 
1173*11878SVenu.Iyer@Sun.COM uint_t default_idlist[] = {0};
1174*11878SVenu.Iyer@Sun.COM uint_t default_idlist_size = 1;
1175*11878SVenu.Iyer@Sun.COM 
1176*11878SVenu.Iyer@Sun.COM typedef enum {
1177*11878SVenu.Iyer@Sun.COM 	DLSTAT_RX_RING_IDLIST,
1178*11878SVenu.Iyer@Sun.COM 	DLSTAT_TX_RING_IDLIST,
1179*11878SVenu.Iyer@Sun.COM 	DLSTAT_RX_HWLANE_IDLIST,
1180*11878SVenu.Iyer@Sun.COM 	DLSTAT_TX_HWLANE_IDLIST,
1181*11878SVenu.Iyer@Sun.COM 	DLSTAT_FANOUT_IDLIST
1182*11878SVenu.Iyer@Sun.COM } dlstat_idlist_type_t;
1183*11878SVenu.Iyer@Sun.COM 
1184*11878SVenu.Iyer@Sun.COM void
dladm_sort_index_list(uint_t idlist[],uint_t size)1185*11878SVenu.Iyer@Sun.COM dladm_sort_index_list(uint_t idlist[], uint_t size)
1186*11878SVenu.Iyer@Sun.COM {
1187*11878SVenu.Iyer@Sun.COM 	int 	i, j;
1188*11878SVenu.Iyer@Sun.COM 
1189*11878SVenu.Iyer@Sun.COM 	for (j = 1; j < size; j++) {
1190*11878SVenu.Iyer@Sun.COM 		int key = idlist[j];
1191*11878SVenu.Iyer@Sun.COM 		for (i = j - 1; (i >= 0) && (idlist[i] > key); i--)
1192*11878SVenu.Iyer@Sun.COM 			idlist[i + 1] = idlist[i];
1193*11878SVenu.Iyer@Sun.COM 		idlist[i + 1] = key;
1194*11878SVenu.Iyer@Sun.COM 	}
1195*11878SVenu.Iyer@Sun.COM }
1196*11878SVenu.Iyer@Sun.COM 
1197*11878SVenu.Iyer@Sun.COM /* Support for legacy drivers */
1198*11878SVenu.Iyer@Sun.COM void
i_query_legacy_stats(const char * linkname,pktsum_t * stats)1199*11878SVenu.Iyer@Sun.COM i_query_legacy_stats(const char *linkname, pktsum_t *stats)
1200*11878SVenu.Iyer@Sun.COM {
1201*11878SVenu.Iyer@Sun.COM 	kstat_ctl_t	*kcp;
1202*11878SVenu.Iyer@Sun.COM 	kstat_t		*ksp;
1203*11878SVenu.Iyer@Sun.COM 
1204*11878SVenu.Iyer@Sun.COM 	bzero(stats, sizeof (*stats));
1205*11878SVenu.Iyer@Sun.COM 
1206*11878SVenu.Iyer@Sun.COM 	if ((kcp = kstat_open()) == NULL)
1207*11878SVenu.Iyer@Sun.COM 		return;
1208*11878SVenu.Iyer@Sun.COM 
1209*11878SVenu.Iyer@Sun.COM 	ksp = dladm_kstat_lookup(kcp, "link", 0, linkname, NULL);
1210*11878SVenu.Iyer@Sun.COM 
1211*11878SVenu.Iyer@Sun.COM 	if (ksp != NULL)
1212*11878SVenu.Iyer@Sun.COM 		dladm_get_stats(kcp, ksp, stats);
1213*11878SVenu.Iyer@Sun.COM 
1214*11878SVenu.Iyer@Sun.COM 	(void) kstat_close(kcp);
1215*11878SVenu.Iyer@Sun.COM }
1216*11878SVenu.Iyer@Sun.COM 
1217*11878SVenu.Iyer@Sun.COM void *
i_dlstat_legacy_rx_lane_stats(const char * linkname)1218*11878SVenu.Iyer@Sun.COM i_dlstat_legacy_rx_lane_stats(const char *linkname)
1219*11878SVenu.Iyer@Sun.COM {
1220*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
1221*11878SVenu.Iyer@Sun.COM 	pktsum_t		stats;
1222*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1223*11878SVenu.Iyer@Sun.COM 
1224*11878SVenu.Iyer@Sun.COM 	bzero(&stats, sizeof (pktsum_t));
1225*11878SVenu.Iyer@Sun.COM 
1226*11878SVenu.Iyer@Sun.COM 	/* Query for dls stats */
1227*11878SVenu.Iyer@Sun.COM 	i_query_legacy_stats(linkname, &stats);
1228*11878SVenu.Iyer@Sun.COM 
1229*11878SVenu.Iyer@Sun.COM 	/* Convert to desired data type */
1230*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1231*11878SVenu.Iyer@Sun.COM 	if (rx_lane_stat_entry == NULL)
1232*11878SVenu.Iyer@Sun.COM 		goto done;
1233*11878SVenu.Iyer@Sun.COM 
1234*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1235*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_id = L_SWLANE;
1236*11878SVenu.Iyer@Sun.COM 
1237*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets;
1238*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets;
1239*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes;
1240*11878SVenu.Iyer@Sun.COM 
1241*11878SVenu.Iyer@Sun.COM 	/* Allocate memory for wrapper */
1242*11878SVenu.Iyer@Sun.COM 	head = malloc(sizeof (dladm_stat_chain_t));
1243*11878SVenu.Iyer@Sun.COM 	if (head == NULL) {
1244*11878SVenu.Iyer@Sun.COM 		free(rx_lane_stat_entry);
1245*11878SVenu.Iyer@Sun.COM 		goto done;
1246*11878SVenu.Iyer@Sun.COM 	}
1247*11878SVenu.Iyer@Sun.COM 
1248*11878SVenu.Iyer@Sun.COM 	head->dc_statentry = rx_lane_stat_entry;
1249*11878SVenu.Iyer@Sun.COM 	head->dc_next = NULL;
1250*11878SVenu.Iyer@Sun.COM done:
1251*11878SVenu.Iyer@Sun.COM 	return (head);
1252*11878SVenu.Iyer@Sun.COM }
1253*11878SVenu.Iyer@Sun.COM 
1254*11878SVenu.Iyer@Sun.COM void *
i_dlstat_legacy_tx_lane_stats(const char * linkname)1255*11878SVenu.Iyer@Sun.COM i_dlstat_legacy_tx_lane_stats(const char *linkname)
1256*11878SVenu.Iyer@Sun.COM {
1257*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
1258*11878SVenu.Iyer@Sun.COM 	pktsum_t		stats;
1259*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
1260*11878SVenu.Iyer@Sun.COM 
1261*11878SVenu.Iyer@Sun.COM 	bzero(&stats, sizeof (pktsum_t));
1262*11878SVenu.Iyer@Sun.COM 
1263*11878SVenu.Iyer@Sun.COM 	/* Query for dls stats */
1264*11878SVenu.Iyer@Sun.COM 	i_query_legacy_stats(linkname, &stats);
1265*11878SVenu.Iyer@Sun.COM 
1266*11878SVenu.Iyer@Sun.COM 	/* Convert to desired data type */
1267*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1268*11878SVenu.Iyer@Sun.COM 	if (tx_lane_stat_entry == NULL)
1269*11878SVenu.Iyer@Sun.COM 		goto done;
1270*11878SVenu.Iyer@Sun.COM 
1271*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1272*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_id = L_SWLANE;
1273*11878SVenu.Iyer@Sun.COM 
1274*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets;
1275*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes;
1276*11878SVenu.Iyer@Sun.COM 
1277*11878SVenu.Iyer@Sun.COM 	/* Allocate memory for wrapper */
1278*11878SVenu.Iyer@Sun.COM 	head = malloc(sizeof (dladm_stat_chain_t));
1279*11878SVenu.Iyer@Sun.COM 	if (head == NULL) {
1280*11878SVenu.Iyer@Sun.COM 		free(tx_lane_stat_entry);
1281*11878SVenu.Iyer@Sun.COM 		goto done;
1282*11878SVenu.Iyer@Sun.COM 	}
1283*11878SVenu.Iyer@Sun.COM 
1284*11878SVenu.Iyer@Sun.COM 	head->dc_statentry = tx_lane_stat_entry;
1285*11878SVenu.Iyer@Sun.COM 	head->dc_next = NULL;
1286*11878SVenu.Iyer@Sun.COM done:
1287*11878SVenu.Iyer@Sun.COM 	return (head);
1288*11878SVenu.Iyer@Sun.COM }
1289*11878SVenu.Iyer@Sun.COM 
1290*11878SVenu.Iyer@Sun.COM /*
1291*11878SVenu.Iyer@Sun.COM  * Ideally, we would want an ioctl to return list of ring-ids (or lane-ids)
1292*11878SVenu.Iyer@Sun.COM  * for a given data-link (or mac client). We could then query for specific
1293*11878SVenu.Iyer@Sun.COM  * kstats based on these ring-ids (lane-ids).
1294*11878SVenu.Iyer@Sun.COM  * Ring-ids (or lane-ids) could be returned like any other link properties
1295*11878SVenu.Iyer@Sun.COM  * queried by dladm show-linkprop. However, non-global zones do not have
1296*11878SVenu.Iyer@Sun.COM  * access to this information today.
1297*11878SVenu.Iyer@Sun.COM  * We thus opt for an implementation that relies heavily on kstat internals:
1298*11878SVenu.Iyer@Sun.COM  * i_dlstat_*search routines and i_dlstat_get_idlist.
1299*11878SVenu.Iyer@Sun.COM  */
1300*11878SVenu.Iyer@Sun.COM /* rx hwlane specific */
1301*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_rx_hwlane_search(kstat_t * ksp)1302*11878SVenu.Iyer@Sun.COM i_dlstat_rx_hwlane_search(kstat_t *ksp)
1303*11878SVenu.Iyer@Sun.COM {
1304*11878SVenu.Iyer@Sun.COM 	return (ksp->ks_instance == 0 &&
1305*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
1306*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "hwlane") != 0 &&
1307*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "fanout") == 0 &&
1308*11878SVenu.Iyer@Sun.COM 	    strcmp(ksp->ks_class, "net") == 0);
1309*11878SVenu.Iyer@Sun.COM }
1310*11878SVenu.Iyer@Sun.COM 
1311*11878SVenu.Iyer@Sun.COM /* tx hwlane specific */
1312*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_tx_hwlane_search(kstat_t * ksp)1313*11878SVenu.Iyer@Sun.COM i_dlstat_tx_hwlane_search(kstat_t *ksp)
1314*11878SVenu.Iyer@Sun.COM {
1315*11878SVenu.Iyer@Sun.COM 	return (ksp->ks_instance == 0 &&
1316*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "mac_tx") != 0 &&
1317*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "hwlane") != 0 &&
1318*11878SVenu.Iyer@Sun.COM 	    strcmp(ksp->ks_class, "net") == 0);
1319*11878SVenu.Iyer@Sun.COM }
1320*11878SVenu.Iyer@Sun.COM 
1321*11878SVenu.Iyer@Sun.COM /* rx fanout specific */
1322*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_fanout_search(kstat_t * ksp)1323*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_search(kstat_t *ksp)
1324*11878SVenu.Iyer@Sun.COM {
1325*11878SVenu.Iyer@Sun.COM 	return (ksp->ks_instance == 0 &&
1326*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
1327*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "swlane") != 0 &&
1328*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "fanout") != 0 &&
1329*11878SVenu.Iyer@Sun.COM 	    strcmp(ksp->ks_class, "net") == 0);
1330*11878SVenu.Iyer@Sun.COM }
1331*11878SVenu.Iyer@Sun.COM 
1332*11878SVenu.Iyer@Sun.COM /* rx ring specific */
1333*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_rx_ring_search(kstat_t * ksp)1334*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_search(kstat_t *ksp)
1335*11878SVenu.Iyer@Sun.COM {
1336*11878SVenu.Iyer@Sun.COM 	return (ksp->ks_instance == 0 &&
1337*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
1338*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "ring") != 0 &&
1339*11878SVenu.Iyer@Sun.COM 	    strcmp(ksp->ks_class, "net") == 0);
1340*11878SVenu.Iyer@Sun.COM }
1341*11878SVenu.Iyer@Sun.COM 
1342*11878SVenu.Iyer@Sun.COM /* tx ring specific */
1343*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_tx_ring_search(kstat_t * ksp)1344*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_search(kstat_t *ksp)
1345*11878SVenu.Iyer@Sun.COM {
1346*11878SVenu.Iyer@Sun.COM 	return (ksp->ks_instance == 0) &&
1347*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "mac_tx") != 0 &&
1348*11878SVenu.Iyer@Sun.COM 	    strstr(ksp->ks_name, "ring") != 0 &&
1349*11878SVenu.Iyer@Sun.COM 	    strcmp(ksp->ks_class, "net") == 0;
1350*11878SVenu.Iyer@Sun.COM }
1351*11878SVenu.Iyer@Sun.COM 
1352*11878SVenu.Iyer@Sun.COM typedef	boolean_t	dladm_search_kstat_t(kstat_t *);
1353*11878SVenu.Iyer@Sun.COM typedef struct dladm_extract_idlist_s {
1354*11878SVenu.Iyer@Sun.COM 	dlstat_idlist_type_t	di_type;
1355*11878SVenu.Iyer@Sun.COM 	char			*di_prefix;
1356*11878SVenu.Iyer@Sun.COM 	dladm_search_kstat_t	*di_searchkstat;
1357*11878SVenu.Iyer@Sun.COM } dladm_extract_idlist_t;
1358*11878SVenu.Iyer@Sun.COM 
1359*11878SVenu.Iyer@Sun.COM static dladm_extract_idlist_t dladm_extract_idlist[] = {
1360*11878SVenu.Iyer@Sun.COM { DLSTAT_RX_RING_IDLIST,	DLSTAT_MAC_RX_RING,
1361*11878SVenu.Iyer@Sun.COM     i_dlstat_rx_ring_search},
1362*11878SVenu.Iyer@Sun.COM { DLSTAT_TX_RING_IDLIST,	DLSTAT_MAC_TX_RING,
1363*11878SVenu.Iyer@Sun.COM     i_dlstat_tx_ring_search},
1364*11878SVenu.Iyer@Sun.COM { DLSTAT_RX_HWLANE_IDLIST,	DLSTAT_MAC_RX_HWLANE,
1365*11878SVenu.Iyer@Sun.COM     i_dlstat_rx_hwlane_search},
1366*11878SVenu.Iyer@Sun.COM { DLSTAT_TX_HWLANE_IDLIST,	DLSTAT_MAC_TX_HWLANE,
1367*11878SVenu.Iyer@Sun.COM     i_dlstat_tx_hwlane_search},
1368*11878SVenu.Iyer@Sun.COM { DLSTAT_FANOUT_IDLIST,		DLSTAT_MAC_FANOUT,
1369*11878SVenu.Iyer@Sun.COM     i_dlstat_fanout_search}
1370*11878SVenu.Iyer@Sun.COM };
1371*11878SVenu.Iyer@Sun.COM 
1372*11878SVenu.Iyer@Sun.COM static void
i_dlstat_get_idlist(const char * modname,dlstat_idlist_type_t idlist_type,uint_t idlist[],uint_t * size)1373*11878SVenu.Iyer@Sun.COM i_dlstat_get_idlist(const char *modname, dlstat_idlist_type_t idlist_type,
1374*11878SVenu.Iyer@Sun.COM     uint_t idlist[], uint_t *size)
1375*11878SVenu.Iyer@Sun.COM {
1376*11878SVenu.Iyer@Sun.COM 	kstat_ctl_t	*kcp;
1377*11878SVenu.Iyer@Sun.COM 	kstat_t		*ksp;
1378*11878SVenu.Iyer@Sun.COM 	char		*prefix;
1379*11878SVenu.Iyer@Sun.COM 	int		prefixlen;
1380*11878SVenu.Iyer@Sun.COM 	boolean_t	(*fptr_searchkstat)(kstat_t *);
1381*11878SVenu.Iyer@Sun.COM 
1382*11878SVenu.Iyer@Sun.COM 	*size = 0;
1383*11878SVenu.Iyer@Sun.COM 
1384*11878SVenu.Iyer@Sun.COM 	if ((kcp = kstat_open()) == NULL) {
1385*11878SVenu.Iyer@Sun.COM 		warn("kstat_open operation failed");
1386*11878SVenu.Iyer@Sun.COM 		goto done;
1387*11878SVenu.Iyer@Sun.COM 	}
1388*11878SVenu.Iyer@Sun.COM 
1389*11878SVenu.Iyer@Sun.COM 	prefix = dladm_extract_idlist[idlist_type].di_prefix;
1390*11878SVenu.Iyer@Sun.COM 	fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat;
1391*11878SVenu.Iyer@Sun.COM 	prefixlen = strlen(prefix);
1392*11878SVenu.Iyer@Sun.COM 	for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
1393*11878SVenu.Iyer@Sun.COM 		if ((strcmp(ksp->ks_module, modname) == 0) &&
1394*11878SVenu.Iyer@Sun.COM 		    fptr_searchkstat(ksp)) {
1395*11878SVenu.Iyer@Sun.COM 			idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]);
1396*11878SVenu.Iyer@Sun.COM 		}
1397*11878SVenu.Iyer@Sun.COM 	}
1398*11878SVenu.Iyer@Sun.COM 	dladm_sort_index_list(idlist, *size);
1399*11878SVenu.Iyer@Sun.COM 
1400*11878SVenu.Iyer@Sun.COM done:
1401*11878SVenu.Iyer@Sun.COM 	(void) kstat_close(kcp);
1402*11878SVenu.Iyer@Sun.COM }
1403*11878SVenu.Iyer@Sun.COM 
1404*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_query_stats(const char * modname,const char * prefix,uint_t idlist[],uint_t idlist_size,void * (* fn)(kstat_ctl_t *,kstat_t *,int))1405*11878SVenu.Iyer@Sun.COM i_dlstat_query_stats(const char *modname, const char *prefix,
1406*11878SVenu.Iyer@Sun.COM     uint_t idlist[], uint_t idlist_size,
1407*11878SVenu.Iyer@Sun.COM     void * (*fn)(kstat_ctl_t *, kstat_t *, int))
1408*11878SVenu.Iyer@Sun.COM {
1409*11878SVenu.Iyer@Sun.COM 	kstat_ctl_t		*kcp;
1410*11878SVenu.Iyer@Sun.COM 	kstat_t			*ksp;
1411*11878SVenu.Iyer@Sun.COM 	char			statname[MAXLINKNAMELEN];
1412*11878SVenu.Iyer@Sun.COM 	int 			i = 0;
1413*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t 	*head = NULL, *prev = NULL;
1414*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*curr;
1415*11878SVenu.Iyer@Sun.COM 
1416*11878SVenu.Iyer@Sun.COM 	if ((kcp = kstat_open()) == NULL) {
1417*11878SVenu.Iyer@Sun.COM 		warn("kstat_open operation failed");
1418*11878SVenu.Iyer@Sun.COM 		return (NULL);
1419*11878SVenu.Iyer@Sun.COM 	}
1420*11878SVenu.Iyer@Sun.COM 
1421*11878SVenu.Iyer@Sun.COM 	for (i = 0; i < idlist_size; i++) {
1422*11878SVenu.Iyer@Sun.COM 		uint_t 	index = idlist[i];
1423*11878SVenu.Iyer@Sun.COM 
1424*11878SVenu.Iyer@Sun.COM 		(void) snprintf(statname, sizeof (statname), "%s%d", prefix,
1425*11878SVenu.Iyer@Sun.COM 		    index);
1426*11878SVenu.Iyer@Sun.COM 
1427*11878SVenu.Iyer@Sun.COM 		ksp = dladm_kstat_lookup(kcp, modname, 0, statname, NULL);
1428*11878SVenu.Iyer@Sun.COM 		if (ksp == NULL)
1429*11878SVenu.Iyer@Sun.COM 			continue;
1430*11878SVenu.Iyer@Sun.COM 
1431*11878SVenu.Iyer@Sun.COM 		curr = malloc(sizeof (dladm_stat_chain_t));
1432*11878SVenu.Iyer@Sun.COM 		if (curr == NULL)
1433*11878SVenu.Iyer@Sun.COM 			break;
1434*11878SVenu.Iyer@Sun.COM 
1435*11878SVenu.Iyer@Sun.COM 		curr->dc_statentry = fn(kcp, ksp, index);
1436*11878SVenu.Iyer@Sun.COM 		if (curr->dc_statentry == NULL) {
1437*11878SVenu.Iyer@Sun.COM 			free(curr);
1438*11878SVenu.Iyer@Sun.COM 			break;
1439*11878SVenu.Iyer@Sun.COM 		}
1440*11878SVenu.Iyer@Sun.COM 
1441*11878SVenu.Iyer@Sun.COM 		(void) strlcpy(curr->dc_statheader, statname,
1442*11878SVenu.Iyer@Sun.COM 		    sizeof (curr->dc_statheader));
1443*11878SVenu.Iyer@Sun.COM 		curr->dc_next = NULL;
1444*11878SVenu.Iyer@Sun.COM 
1445*11878SVenu.Iyer@Sun.COM 		if (head == NULL)	/* First node */
1446*11878SVenu.Iyer@Sun.COM 			head = curr;
1447*11878SVenu.Iyer@Sun.COM 		else
1448*11878SVenu.Iyer@Sun.COM 			prev->dc_next = curr;
1449*11878SVenu.Iyer@Sun.COM 
1450*11878SVenu.Iyer@Sun.COM 		prev = curr;
1451*11878SVenu.Iyer@Sun.COM 	}
1452*11878SVenu.Iyer@Sun.COM done:
1453*11878SVenu.Iyer@Sun.COM 	(void) kstat_close(kcp);
1454*11878SVenu.Iyer@Sun.COM 	return (head);
1455*11878SVenu.Iyer@Sun.COM }
1456*11878SVenu.Iyer@Sun.COM 
1457*11878SVenu.Iyer@Sun.COM static misc_stat_entry_t *
i_dlstat_misc_stats(const char * linkname)1458*11878SVenu.Iyer@Sun.COM i_dlstat_misc_stats(const char *linkname)
1459*11878SVenu.Iyer@Sun.COM {
1460*11878SVenu.Iyer@Sun.COM 	kstat_ctl_t		*kcp;
1461*11878SVenu.Iyer@Sun.COM 	kstat_t			*ksp;
1462*11878SVenu.Iyer@Sun.COM 	misc_stat_entry_t 	*misc_stat_entry = NULL;
1463*11878SVenu.Iyer@Sun.COM 
1464*11878SVenu.Iyer@Sun.COM 	if ((kcp = kstat_open()) == NULL)
1465*11878SVenu.Iyer@Sun.COM 		return (NULL);
1466*11878SVenu.Iyer@Sun.COM 
1467*11878SVenu.Iyer@Sun.COM 	ksp = dladm_kstat_lookup(kcp, linkname, 0, DLSTAT_MAC_MISC_STAT, NULL);
1468*11878SVenu.Iyer@Sun.COM 	if (ksp == NULL)
1469*11878SVenu.Iyer@Sun.COM 		goto done;
1470*11878SVenu.Iyer@Sun.COM 
1471*11878SVenu.Iyer@Sun.COM 	misc_stat_entry = calloc(1, sizeof (misc_stat_entry_t));
1472*11878SVenu.Iyer@Sun.COM 	if (misc_stat_entry == NULL)
1473*11878SVenu.Iyer@Sun.COM 		goto done;
1474*11878SVenu.Iyer@Sun.COM 
1475*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_stats(kcp, ksp, &misc_stat_entry->mse_stats,
1476*11878SVenu.Iyer@Sun.COM 	    misc_stats_list, MISC_STAT_SIZE);
1477*11878SVenu.Iyer@Sun.COM done:
1478*11878SVenu.Iyer@Sun.COM 	(void) kstat_close(kcp);
1479*11878SVenu.Iyer@Sun.COM 	return (misc_stat_entry);
1480*11878SVenu.Iyer@Sun.COM }
1481*11878SVenu.Iyer@Sun.COM 
1482*11878SVenu.Iyer@Sun.COM /* Rx lane statistic specific functions */
1483*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_rx_lane_match(void * arg1,void * arg2)1484*11878SVenu.Iyer@Sun.COM i_dlstat_rx_lane_match(void *arg1, void *arg2)
1485*11878SVenu.Iyer@Sun.COM {
1486*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t *s1 = arg1;
1487*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t *s2 = arg2;
1488*11878SVenu.Iyer@Sun.COM 
1489*11878SVenu.Iyer@Sun.COM 	return (s1->rle_index == s2->rle_index &&
1490*11878SVenu.Iyer@Sun.COM 	    s1->rle_id == s2->rle_id);
1491*11878SVenu.Iyer@Sun.COM }
1492*11878SVenu.Iyer@Sun.COM 
1493*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_rx_lane_stat_entry_diff(void * arg1,void * arg2)1494*11878SVenu.Iyer@Sun.COM i_dlstat_rx_lane_stat_entry_diff(void *arg1, void *arg2)
1495*11878SVenu.Iyer@Sun.COM {
1496*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t *s1 = arg1;
1497*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t *s2 = arg2;
1498*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t *diff_entry;
1499*11878SVenu.Iyer@Sun.COM 
1500*11878SVenu.Iyer@Sun.COM 	diff_entry = malloc(sizeof (rx_lane_stat_entry_t));
1501*11878SVenu.Iyer@Sun.COM 	if (diff_entry == NULL)
1502*11878SVenu.Iyer@Sun.COM 		goto done;
1503*11878SVenu.Iyer@Sun.COM 
1504*11878SVenu.Iyer@Sun.COM 	diff_entry->rle_index = s1->rle_index;
1505*11878SVenu.Iyer@Sun.COM 	diff_entry->rle_id = s1->rle_id;
1506*11878SVenu.Iyer@Sun.COM 
1507*11878SVenu.Iyer@Sun.COM 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, rle_stats, rx_lane_stats_list,
1508*11878SVenu.Iyer@Sun.COM 	    RX_LANE_STAT_SIZE);
1509*11878SVenu.Iyer@Sun.COM 
1510*11878SVenu.Iyer@Sun.COM done:
1511*11878SVenu.Iyer@Sun.COM 	return (diff_entry);
1512*11878SVenu.Iyer@Sun.COM }
1513*11878SVenu.Iyer@Sun.COM 
1514*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1515*11878SVenu.Iyer@Sun.COM i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1516*11878SVenu.Iyer@Sun.COM {
1517*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1518*11878SVenu.Iyer@Sun.COM 
1519*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1520*11878SVenu.Iyer@Sun.COM 	if (rx_lane_stat_entry == NULL)
1521*11878SVenu.Iyer@Sun.COM 		goto done;
1522*11878SVenu.Iyer@Sun.COM 
1523*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_index = i;
1524*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_id = L_HWLANE;
1525*11878SVenu.Iyer@Sun.COM 
1526*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1527*11878SVenu.Iyer@Sun.COM 	    rx_hwlane_stats_list, RX_HWLANE_STAT_SIZE);
1528*11878SVenu.Iyer@Sun.COM 
1529*11878SVenu.Iyer@Sun.COM done:
1530*11878SVenu.Iyer@Sun.COM 	return (rx_lane_stat_entry);
1531*11878SVenu.Iyer@Sun.COM }
1532*11878SVenu.Iyer@Sun.COM 
1533*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/
1534*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1535*11878SVenu.Iyer@Sun.COM i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1536*11878SVenu.Iyer@Sun.COM {
1537*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1538*11878SVenu.Iyer@Sun.COM 
1539*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1540*11878SVenu.Iyer@Sun.COM 	if (rx_lane_stat_entry == NULL)
1541*11878SVenu.Iyer@Sun.COM 		goto done;
1542*11878SVenu.Iyer@Sun.COM 
1543*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1544*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_id = L_SWLANE;
1545*11878SVenu.Iyer@Sun.COM 
1546*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1547*11878SVenu.Iyer@Sun.COM 	    rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
1548*11878SVenu.Iyer@Sun.COM 
1549*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_ipackets =
1550*11878SVenu.Iyer@Sun.COM 	    rx_lane_stat_entry->rle_stats.rl_intrs;
1551*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_rbytes =
1552*11878SVenu.Iyer@Sun.COM 	    rx_lane_stat_entry->rle_stats.rl_intrbytes;
1553*11878SVenu.Iyer@Sun.COM done:
1554*11878SVenu.Iyer@Sun.COM 	return (rx_lane_stat_entry);
1555*11878SVenu.Iyer@Sun.COM }
1556*11878SVenu.Iyer@Sun.COM 
1557*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/
1558*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_rx_local_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1559*11878SVenu.Iyer@Sun.COM i_dlstat_rx_local_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1560*11878SVenu.Iyer@Sun.COM {
1561*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*local_stat_entry;
1562*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1563*11878SVenu.Iyer@Sun.COM 
1564*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1565*11878SVenu.Iyer@Sun.COM 	if (rx_lane_stat_entry == NULL)
1566*11878SVenu.Iyer@Sun.COM 		goto done;
1567*11878SVenu.Iyer@Sun.COM 
1568*11878SVenu.Iyer@Sun.COM 	local_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1569*11878SVenu.Iyer@Sun.COM 	if (local_stat_entry == NULL)
1570*11878SVenu.Iyer@Sun.COM 		goto done;
1571*11878SVenu.Iyer@Sun.COM 
1572*11878SVenu.Iyer@Sun.COM 	local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1573*11878SVenu.Iyer@Sun.COM 	local_stat_entry->rle_id = L_LOCAL;
1574*11878SVenu.Iyer@Sun.COM 
1575*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1576*11878SVenu.Iyer@Sun.COM 	    rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
1577*11878SVenu.Iyer@Sun.COM 
1578*11878SVenu.Iyer@Sun.COM 	local_stat_entry->rle_stats.rl_ipackets =
1579*11878SVenu.Iyer@Sun.COM 	    rx_lane_stat_entry->rle_stats.rl_lclpackets;
1580*11878SVenu.Iyer@Sun.COM 	local_stat_entry->rle_stats.rl_rbytes =
1581*11878SVenu.Iyer@Sun.COM 	    rx_lane_stat_entry->rle_stats.rl_lclbytes;
1582*11878SVenu.Iyer@Sun.COM 
1583*11878SVenu.Iyer@Sun.COM done:
1584*11878SVenu.Iyer@Sun.COM 	free(rx_lane_stat_entry);
1585*11878SVenu.Iyer@Sun.COM 	return (local_stat_entry);
1586*11878SVenu.Iyer@Sun.COM }
1587*11878SVenu.Iyer@Sun.COM 
1588*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_rx_local_stats(const char * linkname)1589*11878SVenu.Iyer@Sun.COM i_dlstat_rx_local_stats(const char *linkname)
1590*11878SVenu.Iyer@Sun.COM {
1591*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*local_stats = NULL;
1592*11878SVenu.Iyer@Sun.COM 
1593*11878SVenu.Iyer@Sun.COM 	local_stats = i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_SWLANE,
1594*11878SVenu.Iyer@Sun.COM 	    default_idlist, default_idlist_size,
1595*11878SVenu.Iyer@Sun.COM 	    i_dlstat_rx_local_retrieve_stat);
1596*11878SVenu.Iyer@Sun.COM 
1597*11878SVenu.Iyer@Sun.COM 	if (local_stats != NULL) {
1598*11878SVenu.Iyer@Sun.COM 		(void) strlcpy(local_stats->dc_statheader, "mac_rx_local",
1599*11878SVenu.Iyer@Sun.COM 		    sizeof (local_stats->dc_statheader));
1600*11878SVenu.Iyer@Sun.COM 	}
1601*11878SVenu.Iyer@Sun.COM 	return (local_stats);
1602*11878SVenu.Iyer@Sun.COM }
1603*11878SVenu.Iyer@Sun.COM 
1604*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_rx_bcast_stats(const char * linkname)1605*11878SVenu.Iyer@Sun.COM i_dlstat_rx_bcast_stats(const char *linkname)
1606*11878SVenu.Iyer@Sun.COM {
1607*11878SVenu.Iyer@Sun.COM 	misc_stat_entry_t	*misc_stat_entry;
1608*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
1609*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1610*11878SVenu.Iyer@Sun.COM 
1611*11878SVenu.Iyer@Sun.COM 	misc_stat_entry = i_dlstat_misc_stats(linkname);
1612*11878SVenu.Iyer@Sun.COM 	if (misc_stat_entry == NULL)
1613*11878SVenu.Iyer@Sun.COM 		goto done;
1614*11878SVenu.Iyer@Sun.COM 
1615*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1616*11878SVenu.Iyer@Sun.COM 	if (rx_lane_stat_entry == NULL)
1617*11878SVenu.Iyer@Sun.COM 		goto done;
1618*11878SVenu.Iyer@Sun.COM 
1619*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1620*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_id = L_BCAST;
1621*11878SVenu.Iyer@Sun.COM 
1622*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_ipackets =
1623*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_brdcstrcv +
1624*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_multircv;
1625*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_intrs =
1626*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_brdcstrcv +
1627*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_multircv;
1628*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_rbytes =
1629*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_brdcstrcvbytes +
1630*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_multircvbytes;
1631*11878SVenu.Iyer@Sun.COM 
1632*11878SVenu.Iyer@Sun.COM 	head = malloc(sizeof (dladm_stat_chain_t));
1633*11878SVenu.Iyer@Sun.COM 	if (head == NULL) {
1634*11878SVenu.Iyer@Sun.COM 		free(rx_lane_stat_entry);
1635*11878SVenu.Iyer@Sun.COM 		goto done;
1636*11878SVenu.Iyer@Sun.COM 	}
1637*11878SVenu.Iyer@Sun.COM 
1638*11878SVenu.Iyer@Sun.COM 	head->dc_statentry = rx_lane_stat_entry;
1639*11878SVenu.Iyer@Sun.COM 	head->dc_next = NULL;
1640*11878SVenu.Iyer@Sun.COM 
1641*11878SVenu.Iyer@Sun.COM 	free(misc_stat_entry);
1642*11878SVenu.Iyer@Sun.COM done:
1643*11878SVenu.Iyer@Sun.COM 	return (head);
1644*11878SVenu.Iyer@Sun.COM }
1645*11878SVenu.Iyer@Sun.COM 
1646*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_rx_defunctlane_stats(const char * linkname)1647*11878SVenu.Iyer@Sun.COM i_dlstat_rx_defunctlane_stats(const char *linkname)
1648*11878SVenu.Iyer@Sun.COM {
1649*11878SVenu.Iyer@Sun.COM 	misc_stat_entry_t	*misc_stat_entry;
1650*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
1651*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
1652*11878SVenu.Iyer@Sun.COM 
1653*11878SVenu.Iyer@Sun.COM 	misc_stat_entry = i_dlstat_misc_stats(linkname);
1654*11878SVenu.Iyer@Sun.COM 	if (misc_stat_entry == NULL)
1655*11878SVenu.Iyer@Sun.COM 		goto done;
1656*11878SVenu.Iyer@Sun.COM 
1657*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1658*11878SVenu.Iyer@Sun.COM 	if (rx_lane_stat_entry == NULL)
1659*11878SVenu.Iyer@Sun.COM 		goto done;
1660*11878SVenu.Iyer@Sun.COM 
1661*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1662*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_id = L_DFNCT;
1663*11878SVenu.Iyer@Sun.COM 
1664*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_ipackets =
1665*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_ipackets;
1666*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_rbytes =
1667*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_rbytes;
1668*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_intrs =
1669*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_intrs;
1670*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_polls =
1671*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_polls;
1672*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_sdrops =
1673*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_rxsdrops;
1674*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_chl10 =
1675*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_chainunder10;
1676*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_ch10_50 =
1677*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_chain10to50;
1678*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry->rle_stats.rl_chg50 =
1679*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_chainover50;
1680*11878SVenu.Iyer@Sun.COM 
1681*11878SVenu.Iyer@Sun.COM 	head = malloc(sizeof (dladm_stat_chain_t));
1682*11878SVenu.Iyer@Sun.COM 	if (head == NULL) {
1683*11878SVenu.Iyer@Sun.COM 		free(rx_lane_stat_entry);
1684*11878SVenu.Iyer@Sun.COM 		goto done;
1685*11878SVenu.Iyer@Sun.COM 	}
1686*11878SVenu.Iyer@Sun.COM 
1687*11878SVenu.Iyer@Sun.COM 	head->dc_statentry = rx_lane_stat_entry;
1688*11878SVenu.Iyer@Sun.COM 	head->dc_next = NULL;
1689*11878SVenu.Iyer@Sun.COM 
1690*11878SVenu.Iyer@Sun.COM done:
1691*11878SVenu.Iyer@Sun.COM 	return (head);
1692*11878SVenu.Iyer@Sun.COM }
1693*11878SVenu.Iyer@Sun.COM 
1694*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_rx_hwlane_stats(const char * linkname)1695*11878SVenu.Iyer@Sun.COM i_dlstat_rx_hwlane_stats(const char *linkname)
1696*11878SVenu.Iyer@Sun.COM {
1697*11878SVenu.Iyer@Sun.COM 	uint_t	rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1698*11878SVenu.Iyer@Sun.COM 	uint_t	rx_hwlane_idlist_size;
1699*11878SVenu.Iyer@Sun.COM 
1700*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_idlist(linkname, DLSTAT_RX_HWLANE_IDLIST,
1701*11878SVenu.Iyer@Sun.COM 	    rx_hwlane_idlist, &rx_hwlane_idlist_size);
1702*11878SVenu.Iyer@Sun.COM 
1703*11878SVenu.Iyer@Sun.COM 	return (i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_HWLANE,
1704*11878SVenu.Iyer@Sun.COM 	    rx_hwlane_idlist, rx_hwlane_idlist_size,
1705*11878SVenu.Iyer@Sun.COM 	    i_dlstat_rx_hwlane_retrieve_stat));
1706*11878SVenu.Iyer@Sun.COM }
1707*11878SVenu.Iyer@Sun.COM 
1708*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/
1709*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_rx_swlane_stats(dladm_handle_t dh,datalink_id_t linkid,const char * linkname)1710*11878SVenu.Iyer@Sun.COM i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1711*11878SVenu.Iyer@Sun.COM     const char *linkname)
1712*11878SVenu.Iyer@Sun.COM {
1713*11878SVenu.Iyer@Sun.COM 	return (i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_SWLANE,
1714*11878SVenu.Iyer@Sun.COM 	    default_idlist, default_idlist_size,
1715*11878SVenu.Iyer@Sun.COM 	    i_dlstat_rx_swlane_retrieve_stat));
1716*11878SVenu.Iyer@Sun.COM }
1717*11878SVenu.Iyer@Sun.COM 
1718*11878SVenu.Iyer@Sun.COM void *
dlstat_rx_lane_stats(dladm_handle_t dh,datalink_id_t linkid)1719*11878SVenu.Iyer@Sun.COM dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1720*11878SVenu.Iyer@Sun.COM {
1721*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
1722*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t 	*local_stats = NULL;
1723*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t 	*bcast_stats = NULL;
1724*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t 	*defunctlane_stats = NULL;
1725*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t 	*lane_stats = NULL;
1726*11878SVenu.Iyer@Sun.COM 	char 			linkname[MAXLINKNAMELEN];
1727*11878SVenu.Iyer@Sun.COM 	boolean_t		is_legacy_driver;
1728*11878SVenu.Iyer@Sun.COM 
1729*11878SVenu.Iyer@Sun.COM 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1730*11878SVenu.Iyer@Sun.COM 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1731*11878SVenu.Iyer@Sun.COM 		goto done;
1732*11878SVenu.Iyer@Sun.COM 	}
1733*11878SVenu.Iyer@Sun.COM 
1734*11878SVenu.Iyer@Sun.COM 	/* Check if it is legacy driver */
1735*11878SVenu.Iyer@Sun.COM 	if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1736*11878SVenu.Iyer@Sun.COM 	    "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1737*11878SVenu.Iyer@Sun.COM 		goto done;
1738*11878SVenu.Iyer@Sun.COM 	}
1739*11878SVenu.Iyer@Sun.COM 
1740*11878SVenu.Iyer@Sun.COM 	if (is_legacy_driver) {
1741*11878SVenu.Iyer@Sun.COM 		head = i_dlstat_legacy_rx_lane_stats(linkname);
1742*11878SVenu.Iyer@Sun.COM 		goto done;
1743*11878SVenu.Iyer@Sun.COM 	}
1744*11878SVenu.Iyer@Sun.COM 
1745*11878SVenu.Iyer@Sun.COM 	local_stats = i_dlstat_rx_local_stats(linkname);
1746*11878SVenu.Iyer@Sun.COM 	bcast_stats = i_dlstat_rx_bcast_stats(linkname);
1747*11878SVenu.Iyer@Sun.COM 	defunctlane_stats = i_dlstat_rx_defunctlane_stats(linkname);
1748*11878SVenu.Iyer@Sun.COM 	lane_stats = i_dlstat_rx_hwlane_stats(linkname);
1749*11878SVenu.Iyer@Sun.COM 	if (lane_stats == NULL)
1750*11878SVenu.Iyer@Sun.COM 		lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname);
1751*11878SVenu.Iyer@Sun.COM 
1752*11878SVenu.Iyer@Sun.COM 	head = i_dlstat_join_lists(local_stats, bcast_stats);
1753*11878SVenu.Iyer@Sun.COM 	head = i_dlstat_join_lists(head, defunctlane_stats);
1754*11878SVenu.Iyer@Sun.COM 	head = i_dlstat_join_lists(head, lane_stats);
1755*11878SVenu.Iyer@Sun.COM done:
1756*11878SVenu.Iyer@Sun.COM 	return (head);
1757*11878SVenu.Iyer@Sun.COM }
1758*11878SVenu.Iyer@Sun.COM 
1759*11878SVenu.Iyer@Sun.COM /* Tx lane statistic specific functions */
1760*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_tx_lane_match(void * arg1,void * arg2)1761*11878SVenu.Iyer@Sun.COM i_dlstat_tx_lane_match(void *arg1, void *arg2)
1762*11878SVenu.Iyer@Sun.COM {
1763*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t *s1 = arg1;
1764*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t *s2 = arg2;
1765*11878SVenu.Iyer@Sun.COM 
1766*11878SVenu.Iyer@Sun.COM 	return (s1->tle_index == s2->tle_index &&
1767*11878SVenu.Iyer@Sun.COM 	    s1->tle_id == s2->tle_id);
1768*11878SVenu.Iyer@Sun.COM }
1769*11878SVenu.Iyer@Sun.COM 
1770*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_tx_lane_stat_entry_diff(void * arg1,void * arg2)1771*11878SVenu.Iyer@Sun.COM i_dlstat_tx_lane_stat_entry_diff(void *arg1, void *arg2)
1772*11878SVenu.Iyer@Sun.COM {
1773*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t *s1 = arg1;
1774*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t *s2 = arg2;
1775*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t *diff_entry;
1776*11878SVenu.Iyer@Sun.COM 
1777*11878SVenu.Iyer@Sun.COM 	diff_entry = malloc(sizeof (tx_lane_stat_entry_t));
1778*11878SVenu.Iyer@Sun.COM 	if (diff_entry == NULL)
1779*11878SVenu.Iyer@Sun.COM 		goto done;
1780*11878SVenu.Iyer@Sun.COM 
1781*11878SVenu.Iyer@Sun.COM 	diff_entry->tle_index = s1->tle_index;
1782*11878SVenu.Iyer@Sun.COM 	diff_entry->tle_id = s1->tle_id;
1783*11878SVenu.Iyer@Sun.COM 
1784*11878SVenu.Iyer@Sun.COM 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, tle_stats, tx_lane_stats_list,
1785*11878SVenu.Iyer@Sun.COM 	    TX_LANE_STAT_SIZE);
1786*11878SVenu.Iyer@Sun.COM 
1787*11878SVenu.Iyer@Sun.COM done:
1788*11878SVenu.Iyer@Sun.COM 	return (diff_entry);
1789*11878SVenu.Iyer@Sun.COM }
1790*11878SVenu.Iyer@Sun.COM 
1791*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1792*11878SVenu.Iyer@Sun.COM i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1793*11878SVenu.Iyer@Sun.COM {
1794*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
1795*11878SVenu.Iyer@Sun.COM 
1796*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1797*11878SVenu.Iyer@Sun.COM 	if (tx_lane_stat_entry == NULL)
1798*11878SVenu.Iyer@Sun.COM 		goto done;
1799*11878SVenu.Iyer@Sun.COM 
1800*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_index	= i;
1801*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_id	= L_HWLANE;
1802*11878SVenu.Iyer@Sun.COM 
1803*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
1804*11878SVenu.Iyer@Sun.COM 	    tx_lane_stats_list, TX_LANE_STAT_SIZE);
1805*11878SVenu.Iyer@Sun.COM 
1806*11878SVenu.Iyer@Sun.COM done:
1807*11878SVenu.Iyer@Sun.COM 	return (tx_lane_stat_entry);
1808*11878SVenu.Iyer@Sun.COM }
1809*11878SVenu.Iyer@Sun.COM 
1810*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/
1811*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1812*11878SVenu.Iyer@Sun.COM i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1813*11878SVenu.Iyer@Sun.COM {
1814*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
1815*11878SVenu.Iyer@Sun.COM 
1816*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1817*11878SVenu.Iyer@Sun.COM 	if (tx_lane_stat_entry == NULL)
1818*11878SVenu.Iyer@Sun.COM 		goto done;
1819*11878SVenu.Iyer@Sun.COM 
1820*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1821*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_id = L_SWLANE;
1822*11878SVenu.Iyer@Sun.COM 
1823*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
1824*11878SVenu.Iyer@Sun.COM 	    tx_lane_stats_list, TX_LANE_STAT_SIZE);
1825*11878SVenu.Iyer@Sun.COM 
1826*11878SVenu.Iyer@Sun.COM done:
1827*11878SVenu.Iyer@Sun.COM 	return (tx_lane_stat_entry);
1828*11878SVenu.Iyer@Sun.COM }
1829*11878SVenu.Iyer@Sun.COM 
1830*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_tx_bcast_stats(const char * linkname)1831*11878SVenu.Iyer@Sun.COM i_dlstat_tx_bcast_stats(const char *linkname)
1832*11878SVenu.Iyer@Sun.COM {
1833*11878SVenu.Iyer@Sun.COM 	misc_stat_entry_t	*misc_stat_entry;
1834*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
1835*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
1836*11878SVenu.Iyer@Sun.COM 
1837*11878SVenu.Iyer@Sun.COM 	misc_stat_entry = i_dlstat_misc_stats(linkname);
1838*11878SVenu.Iyer@Sun.COM 	if (misc_stat_entry == NULL)
1839*11878SVenu.Iyer@Sun.COM 		goto done;
1840*11878SVenu.Iyer@Sun.COM 
1841*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1842*11878SVenu.Iyer@Sun.COM 	if (tx_lane_stat_entry == NULL)
1843*11878SVenu.Iyer@Sun.COM 		goto done;
1844*11878SVenu.Iyer@Sun.COM 
1845*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1846*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_id = L_BCAST;
1847*11878SVenu.Iyer@Sun.COM 
1848*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_stats.tl_opackets =
1849*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_brdcstxmt +
1850*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_multixmt;
1851*11878SVenu.Iyer@Sun.COM 
1852*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_stats.tl_obytes =
1853*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_brdcstxmtbytes +
1854*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_multixmtbytes;
1855*11878SVenu.Iyer@Sun.COM 
1856*11878SVenu.Iyer@Sun.COM 	head = malloc(sizeof (dladm_stat_chain_t));
1857*11878SVenu.Iyer@Sun.COM 	if (head == NULL) {
1858*11878SVenu.Iyer@Sun.COM 		free(tx_lane_stat_entry);
1859*11878SVenu.Iyer@Sun.COM 		goto done;
1860*11878SVenu.Iyer@Sun.COM 	}
1861*11878SVenu.Iyer@Sun.COM 
1862*11878SVenu.Iyer@Sun.COM 	head->dc_statentry = tx_lane_stat_entry;
1863*11878SVenu.Iyer@Sun.COM 	head->dc_next = NULL;
1864*11878SVenu.Iyer@Sun.COM 
1865*11878SVenu.Iyer@Sun.COM 	free(misc_stat_entry);
1866*11878SVenu.Iyer@Sun.COM done:
1867*11878SVenu.Iyer@Sun.COM 	return (head);
1868*11878SVenu.Iyer@Sun.COM }
1869*11878SVenu.Iyer@Sun.COM 
1870*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_tx_defunctlane_stats(const char * linkname)1871*11878SVenu.Iyer@Sun.COM i_dlstat_tx_defunctlane_stats(const char *linkname)
1872*11878SVenu.Iyer@Sun.COM {
1873*11878SVenu.Iyer@Sun.COM 	misc_stat_entry_t	*misc_stat_entry;
1874*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
1875*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
1876*11878SVenu.Iyer@Sun.COM 
1877*11878SVenu.Iyer@Sun.COM 	misc_stat_entry = i_dlstat_misc_stats(linkname);
1878*11878SVenu.Iyer@Sun.COM 	if (misc_stat_entry == NULL)
1879*11878SVenu.Iyer@Sun.COM 		goto done;
1880*11878SVenu.Iyer@Sun.COM 
1881*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1882*11878SVenu.Iyer@Sun.COM 	if (tx_lane_stat_entry == NULL)
1883*11878SVenu.Iyer@Sun.COM 		goto done;
1884*11878SVenu.Iyer@Sun.COM 
1885*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1886*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_id = L_DFNCT;
1887*11878SVenu.Iyer@Sun.COM 
1888*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_stats.tl_opackets =
1889*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_opackets;
1890*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_stats.tl_obytes =
1891*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_obytes;
1892*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry->tle_stats.tl_sdrops =
1893*11878SVenu.Iyer@Sun.COM 	    misc_stat_entry->mse_stats.ms_txsdrops;
1894*11878SVenu.Iyer@Sun.COM 
1895*11878SVenu.Iyer@Sun.COM 	head = malloc(sizeof (dladm_stat_chain_t));
1896*11878SVenu.Iyer@Sun.COM 	if (head == NULL) {
1897*11878SVenu.Iyer@Sun.COM 		free(tx_lane_stat_entry);
1898*11878SVenu.Iyer@Sun.COM 		goto done;
1899*11878SVenu.Iyer@Sun.COM 	}
1900*11878SVenu.Iyer@Sun.COM 
1901*11878SVenu.Iyer@Sun.COM 	head->dc_statentry = tx_lane_stat_entry;
1902*11878SVenu.Iyer@Sun.COM 	head->dc_next = NULL;
1903*11878SVenu.Iyer@Sun.COM 
1904*11878SVenu.Iyer@Sun.COM done:
1905*11878SVenu.Iyer@Sun.COM 	return (head);
1906*11878SVenu.Iyer@Sun.COM }
1907*11878SVenu.Iyer@Sun.COM 
1908*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_tx_hwlane_stats(const char * linkname)1909*11878SVenu.Iyer@Sun.COM i_dlstat_tx_hwlane_stats(const char *linkname)
1910*11878SVenu.Iyer@Sun.COM {
1911*11878SVenu.Iyer@Sun.COM 	uint_t	tx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1912*11878SVenu.Iyer@Sun.COM 	uint_t	tx_hwlane_idlist_size;
1913*11878SVenu.Iyer@Sun.COM 
1914*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_idlist(linkname, DLSTAT_TX_HWLANE_IDLIST,
1915*11878SVenu.Iyer@Sun.COM 	    tx_hwlane_idlist, &tx_hwlane_idlist_size);
1916*11878SVenu.Iyer@Sun.COM 
1917*11878SVenu.Iyer@Sun.COM 	return (i_dlstat_query_stats(linkname, DLSTAT_MAC_TX_HWLANE,
1918*11878SVenu.Iyer@Sun.COM 	    tx_hwlane_idlist, tx_hwlane_idlist_size,
1919*11878SVenu.Iyer@Sun.COM 	    i_dlstat_tx_hwlane_retrieve_stat));
1920*11878SVenu.Iyer@Sun.COM }
1921*11878SVenu.Iyer@Sun.COM 
1922*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/
1923*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t *
i_dlstat_tx_swlane_stats(dladm_handle_t dh,datalink_id_t linkid,const char * linkname)1924*11878SVenu.Iyer@Sun.COM i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1925*11878SVenu.Iyer@Sun.COM     const char *linkname)
1926*11878SVenu.Iyer@Sun.COM {
1927*11878SVenu.Iyer@Sun.COM 	return (i_dlstat_query_stats(linkname, DLSTAT_MAC_TX_SWLANE,
1928*11878SVenu.Iyer@Sun.COM 	    default_idlist, default_idlist_size,
1929*11878SVenu.Iyer@Sun.COM 	    i_dlstat_tx_swlane_retrieve_stat));
1930*11878SVenu.Iyer@Sun.COM }
1931*11878SVenu.Iyer@Sun.COM 
1932*11878SVenu.Iyer@Sun.COM void *
dlstat_tx_lane_stats(dladm_handle_t dh,datalink_id_t linkid)1933*11878SVenu.Iyer@Sun.COM dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1934*11878SVenu.Iyer@Sun.COM {
1935*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
1936*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t 	*bcast_stats = NULL;
1937*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t 	*defunctlane_stats = NULL;
1938*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t 	*lane_stats;
1939*11878SVenu.Iyer@Sun.COM 	char 			linkname[MAXLINKNAMELEN];
1940*11878SVenu.Iyer@Sun.COM 	boolean_t		is_legacy_driver;
1941*11878SVenu.Iyer@Sun.COM 
1942*11878SVenu.Iyer@Sun.COM 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1943*11878SVenu.Iyer@Sun.COM 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1944*11878SVenu.Iyer@Sun.COM 		goto done;
1945*11878SVenu.Iyer@Sun.COM 	}
1946*11878SVenu.Iyer@Sun.COM 
1947*11878SVenu.Iyer@Sun.COM 	/* Check if it is legacy driver */
1948*11878SVenu.Iyer@Sun.COM 	if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1949*11878SVenu.Iyer@Sun.COM 	    "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1950*11878SVenu.Iyer@Sun.COM 		goto done;
1951*11878SVenu.Iyer@Sun.COM 	}
1952*11878SVenu.Iyer@Sun.COM 
1953*11878SVenu.Iyer@Sun.COM 	if (is_legacy_driver) {
1954*11878SVenu.Iyer@Sun.COM 		head = i_dlstat_legacy_tx_lane_stats(linkname);
1955*11878SVenu.Iyer@Sun.COM 		goto done;
1956*11878SVenu.Iyer@Sun.COM 	}
1957*11878SVenu.Iyer@Sun.COM 
1958*11878SVenu.Iyer@Sun.COM 	bcast_stats = i_dlstat_tx_bcast_stats(linkname);
1959*11878SVenu.Iyer@Sun.COM 	defunctlane_stats = i_dlstat_tx_defunctlane_stats(linkname);
1960*11878SVenu.Iyer@Sun.COM 	lane_stats = i_dlstat_tx_hwlane_stats(linkname);
1961*11878SVenu.Iyer@Sun.COM 	if (lane_stats == NULL)
1962*11878SVenu.Iyer@Sun.COM 		lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname);
1963*11878SVenu.Iyer@Sun.COM 
1964*11878SVenu.Iyer@Sun.COM 	head = i_dlstat_join_lists(bcast_stats, defunctlane_stats);
1965*11878SVenu.Iyer@Sun.COM 	head = i_dlstat_join_lists(head, lane_stats);
1966*11878SVenu.Iyer@Sun.COM 
1967*11878SVenu.Iyer@Sun.COM done:
1968*11878SVenu.Iyer@Sun.COM 	return (head);
1969*11878SVenu.Iyer@Sun.COM }
1970*11878SVenu.Iyer@Sun.COM 
1971*11878SVenu.Iyer@Sun.COM /* Rx lane total statistic specific functions */
1972*11878SVenu.Iyer@Sun.COM void *
dlstat_rx_lane_total_stats(dladm_handle_t dh,datalink_id_t linkid)1973*11878SVenu.Iyer@Sun.COM dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1974*11878SVenu.Iyer@Sun.COM {
1975*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*total_head = NULL;
1976*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*rx_lane_head, *curr;
1977*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*total_stats;
1978*11878SVenu.Iyer@Sun.COM 
1979*11878SVenu.Iyer@Sun.COM 	/* Get per rx lane stats */
1980*11878SVenu.Iyer@Sun.COM 	rx_lane_head = dlstat_rx_lane_stats(dh, linkid);
1981*11878SVenu.Iyer@Sun.COM 	if (rx_lane_head == NULL)
1982*11878SVenu.Iyer@Sun.COM 		goto done;
1983*11878SVenu.Iyer@Sun.COM 
1984*11878SVenu.Iyer@Sun.COM 	total_stats = calloc(1, sizeof (rx_lane_stat_entry_t));
1985*11878SVenu.Iyer@Sun.COM 	if (total_stats == NULL)
1986*11878SVenu.Iyer@Sun.COM 		goto done;
1987*11878SVenu.Iyer@Sun.COM 
1988*11878SVenu.Iyer@Sun.COM 	total_stats->rle_index = DLSTAT_INVALID_ENTRY;
1989*11878SVenu.Iyer@Sun.COM 	total_stats->rle_id = DLSTAT_INVALID_ENTRY;
1990*11878SVenu.Iyer@Sun.COM 
1991*11878SVenu.Iyer@Sun.COM 	for (curr = rx_lane_head; curr != NULL; curr = curr->dc_next) {
1992*11878SVenu.Iyer@Sun.COM 		rx_lane_stat_entry_t	*curr_lane_stats = curr->dc_statentry;
1993*11878SVenu.Iyer@Sun.COM 
1994*11878SVenu.Iyer@Sun.COM 		i_dlstat_sum_stats(&total_stats->rle_stats,
1995*11878SVenu.Iyer@Sun.COM 		    &curr_lane_stats->rle_stats, &total_stats->rle_stats,
1996*11878SVenu.Iyer@Sun.COM 		    rx_lane_stats_list, RX_LANE_STAT_SIZE);
1997*11878SVenu.Iyer@Sun.COM 	}
1998*11878SVenu.Iyer@Sun.COM 
1999*11878SVenu.Iyer@Sun.COM 	total_head = malloc(sizeof (dladm_stat_chain_t));
2000*11878SVenu.Iyer@Sun.COM 	if (total_head == NULL) {
2001*11878SVenu.Iyer@Sun.COM 		free(total_stats);
2002*11878SVenu.Iyer@Sun.COM 		goto done;
2003*11878SVenu.Iyer@Sun.COM 	}
2004*11878SVenu.Iyer@Sun.COM 
2005*11878SVenu.Iyer@Sun.COM 	total_head->dc_statentry = total_stats;
2006*11878SVenu.Iyer@Sun.COM 	(void) strlcpy(total_head->dc_statheader, "mac_rx_lane_total",
2007*11878SVenu.Iyer@Sun.COM 	    sizeof (total_head->dc_statheader));
2008*11878SVenu.Iyer@Sun.COM 	total_head->dc_next = NULL;
2009*11878SVenu.Iyer@Sun.COM 	free(rx_lane_head);
2010*11878SVenu.Iyer@Sun.COM 
2011*11878SVenu.Iyer@Sun.COM done:
2012*11878SVenu.Iyer@Sun.COM 	return (total_head);
2013*11878SVenu.Iyer@Sun.COM }
2014*11878SVenu.Iyer@Sun.COM 
2015*11878SVenu.Iyer@Sun.COM /* Tx lane total statistic specific functions */
2016*11878SVenu.Iyer@Sun.COM void *
dlstat_tx_lane_total_stats(dladm_handle_t dh,datalink_id_t linkid)2017*11878SVenu.Iyer@Sun.COM dlstat_tx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
2018*11878SVenu.Iyer@Sun.COM {
2019*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*total_head = NULL;
2020*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*tx_lane_head, *curr;
2021*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t	*total_stats;
2022*11878SVenu.Iyer@Sun.COM 
2023*11878SVenu.Iyer@Sun.COM 	/* Get per tx lane stats */
2024*11878SVenu.Iyer@Sun.COM 	tx_lane_head = dlstat_tx_lane_stats(dh, linkid);
2025*11878SVenu.Iyer@Sun.COM 	if (tx_lane_head == NULL)
2026*11878SVenu.Iyer@Sun.COM 		goto done;
2027*11878SVenu.Iyer@Sun.COM 
2028*11878SVenu.Iyer@Sun.COM 	total_stats = calloc(1, sizeof (tx_lane_stat_entry_t));
2029*11878SVenu.Iyer@Sun.COM 	if (total_stats == NULL)
2030*11878SVenu.Iyer@Sun.COM 		goto done;
2031*11878SVenu.Iyer@Sun.COM 
2032*11878SVenu.Iyer@Sun.COM 	total_stats->tle_index = DLSTAT_INVALID_ENTRY;
2033*11878SVenu.Iyer@Sun.COM 	total_stats->tle_id = DLSTAT_INVALID_ENTRY;
2034*11878SVenu.Iyer@Sun.COM 
2035*11878SVenu.Iyer@Sun.COM 	for (curr = tx_lane_head; curr != NULL; curr = curr->dc_next) {
2036*11878SVenu.Iyer@Sun.COM 		tx_lane_stat_entry_t	*curr_lane_stats = curr->dc_statentry;
2037*11878SVenu.Iyer@Sun.COM 
2038*11878SVenu.Iyer@Sun.COM 		i_dlstat_sum_stats(&total_stats->tle_stats,
2039*11878SVenu.Iyer@Sun.COM 		    &curr_lane_stats->tle_stats, &total_stats->tle_stats,
2040*11878SVenu.Iyer@Sun.COM 		    tx_lane_stats_list, TX_LANE_STAT_SIZE);
2041*11878SVenu.Iyer@Sun.COM 	}
2042*11878SVenu.Iyer@Sun.COM 
2043*11878SVenu.Iyer@Sun.COM 	total_head = malloc(sizeof (dladm_stat_chain_t));
2044*11878SVenu.Iyer@Sun.COM 	if (total_head == NULL) {
2045*11878SVenu.Iyer@Sun.COM 		free(total_stats);
2046*11878SVenu.Iyer@Sun.COM 		goto done;
2047*11878SVenu.Iyer@Sun.COM 	}
2048*11878SVenu.Iyer@Sun.COM 
2049*11878SVenu.Iyer@Sun.COM 	total_head->dc_statentry = total_stats;
2050*11878SVenu.Iyer@Sun.COM 	(void) strlcpy(total_head->dc_statheader, "mac_tx_lane_total",
2051*11878SVenu.Iyer@Sun.COM 	    sizeof (total_head->dc_statheader));
2052*11878SVenu.Iyer@Sun.COM 	total_head->dc_next = NULL;
2053*11878SVenu.Iyer@Sun.COM 	free(tx_lane_head);
2054*11878SVenu.Iyer@Sun.COM 
2055*11878SVenu.Iyer@Sun.COM done:
2056*11878SVenu.Iyer@Sun.COM 	return (total_head);
2057*11878SVenu.Iyer@Sun.COM }
2058*11878SVenu.Iyer@Sun.COM 
2059*11878SVenu.Iyer@Sun.COM /* Fanout specific functions */
2060*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_fanout_match(void * arg1,void * arg2)2061*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_match(void *arg1, void *arg2)
2062*11878SVenu.Iyer@Sun.COM {
2063*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry_t	*s1 = arg1;
2064*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry_t	*s2 = arg2;
2065*11878SVenu.Iyer@Sun.COM 
2066*11878SVenu.Iyer@Sun.COM 	return (s1->fe_index == s2->fe_index &&
2067*11878SVenu.Iyer@Sun.COM 	    s1->fe_id == s2->fe_id &&
2068*11878SVenu.Iyer@Sun.COM 	    s1->fe_foutindex == s2->fe_foutindex);
2069*11878SVenu.Iyer@Sun.COM }
2070*11878SVenu.Iyer@Sun.COM 
2071*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_fanout_stat_entry_diff(void * arg1,void * arg2)2072*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_stat_entry_diff(void *arg1, void *arg2)
2073*11878SVenu.Iyer@Sun.COM {
2074*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry_t	*s1 = arg1;
2075*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry_t	*s2 = arg2;
2076*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry_t	*diff_entry;
2077*11878SVenu.Iyer@Sun.COM 
2078*11878SVenu.Iyer@Sun.COM 	diff_entry = malloc(sizeof (fanout_stat_entry_t));
2079*11878SVenu.Iyer@Sun.COM 	if (diff_entry == NULL)
2080*11878SVenu.Iyer@Sun.COM 		goto done;
2081*11878SVenu.Iyer@Sun.COM 
2082*11878SVenu.Iyer@Sun.COM 	diff_entry->fe_index = s1->fe_index;
2083*11878SVenu.Iyer@Sun.COM 	diff_entry->fe_id = s1->fe_id;
2084*11878SVenu.Iyer@Sun.COM 	diff_entry->fe_foutindex = s1->fe_foutindex;
2085*11878SVenu.Iyer@Sun.COM 
2086*11878SVenu.Iyer@Sun.COM 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, fe_stats, fanout_stats_list,
2087*11878SVenu.Iyer@Sun.COM 	    FANOUT_STAT_SIZE);
2088*11878SVenu.Iyer@Sun.COM 
2089*11878SVenu.Iyer@Sun.COM done:
2090*11878SVenu.Iyer@Sun.COM 	return (diff_entry);
2091*11878SVenu.Iyer@Sun.COM }
2092*11878SVenu.Iyer@Sun.COM 
2093*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_fanout_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)2094*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
2095*11878SVenu.Iyer@Sun.COM {
2096*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry_t	*fanout_stat_entry;
2097*11878SVenu.Iyer@Sun.COM 
2098*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry = calloc(1, sizeof (fanout_stat_entry_t));
2099*11878SVenu.Iyer@Sun.COM 	if (fanout_stat_entry == NULL)
2100*11878SVenu.Iyer@Sun.COM 		goto done;
2101*11878SVenu.Iyer@Sun.COM 
2102*11878SVenu.Iyer@Sun.COM 					/* Set by the caller later */
2103*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry->fe_index = DLSTAT_INVALID_ENTRY;
2104*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry->fe_id = DLSTAT_INVALID_ENTRY;
2105*11878SVenu.Iyer@Sun.COM 
2106*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry->fe_foutindex = i;
2107*11878SVenu.Iyer@Sun.COM 
2108*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_stats(kcp, ksp, &fanout_stat_entry->fe_stats,
2109*11878SVenu.Iyer@Sun.COM 	    fanout_stats_list, FANOUT_STAT_SIZE);
2110*11878SVenu.Iyer@Sun.COM 
2111*11878SVenu.Iyer@Sun.COM done:
2112*11878SVenu.Iyer@Sun.COM 	return (fanout_stat_entry);
2113*11878SVenu.Iyer@Sun.COM }
2114*11878SVenu.Iyer@Sun.COM 
2115*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_query_fanout_stats(dladm_handle_t dh,datalink_id_t linkid,uint_t idlist[],uint_t idlist_size,const char * modname,const char * prefix)2116*11878SVenu.Iyer@Sun.COM i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid,
2117*11878SVenu.Iyer@Sun.COM     uint_t idlist[], uint_t idlist_size,
2118*11878SVenu.Iyer@Sun.COM     const char *modname, const char *prefix)
2119*11878SVenu.Iyer@Sun.COM {
2120*11878SVenu.Iyer@Sun.COM 	int			i;
2121*11878SVenu.Iyer@Sun.COM 	char			statprefix[MAXLINKNAMELEN];
2122*11878SVenu.Iyer@Sun.COM 	char			linkname[MAXLINKNAMELEN];
2123*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*curr, *curr_head;
2124*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL, *prev = NULL;
2125*11878SVenu.Iyer@Sun.COM 	uint_t 			fanout_idlist[MAX_RINGS_PER_GROUP];
2126*11878SVenu.Iyer@Sun.COM 	uint_t 			fanout_idlist_size;
2127*11878SVenu.Iyer@Sun.COM 
2128*11878SVenu.Iyer@Sun.COM 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
2129*11878SVenu.Iyer@Sun.COM 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2130*11878SVenu.Iyer@Sun.COM 		return (NULL);
2131*11878SVenu.Iyer@Sun.COM 	}
2132*11878SVenu.Iyer@Sun.COM 
2133*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_idlist(linkname, DLSTAT_FANOUT_IDLIST,
2134*11878SVenu.Iyer@Sun.COM 	    fanout_idlist, &fanout_idlist_size);
2135*11878SVenu.Iyer@Sun.COM 
2136*11878SVenu.Iyer@Sun.COM 	for (i = 0; i < idlist_size; i++) {
2137*11878SVenu.Iyer@Sun.COM 		uint_t	index = idlist[i];
2138*11878SVenu.Iyer@Sun.COM 
2139*11878SVenu.Iyer@Sun.COM 		(void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout",
2140*11878SVenu.Iyer@Sun.COM 		    prefix, index);
2141*11878SVenu.Iyer@Sun.COM 
2142*11878SVenu.Iyer@Sun.COM 		curr_head = i_dlstat_query_stats(modname, statprefix,
2143*11878SVenu.Iyer@Sun.COM 		    fanout_idlist, fanout_idlist_size,
2144*11878SVenu.Iyer@Sun.COM 		    i_dlstat_fanout_retrieve_stat);
2145*11878SVenu.Iyer@Sun.COM 
2146*11878SVenu.Iyer@Sun.COM 		if (curr_head == NULL)	/* Last lane */
2147*11878SVenu.Iyer@Sun.COM 			break;
2148*11878SVenu.Iyer@Sun.COM 
2149*11878SVenu.Iyer@Sun.COM 		if (head == NULL)	/* First lane */
2150*11878SVenu.Iyer@Sun.COM 			head = curr_head;
2151*11878SVenu.Iyer@Sun.COM 		else	/* Link new lane list to end of previous lane list */
2152*11878SVenu.Iyer@Sun.COM 			prev->dc_next = curr_head;
2153*11878SVenu.Iyer@Sun.COM 
2154*11878SVenu.Iyer@Sun.COM 		/* Walk new lane list and set ids */
2155*11878SVenu.Iyer@Sun.COM 		for (curr = curr_head; curr != NULL; curr = curr->dc_next) {
2156*11878SVenu.Iyer@Sun.COM 			fanout_stat_entry_t *curr_stats = curr->dc_statentry;
2157*11878SVenu.Iyer@Sun.COM 
2158*11878SVenu.Iyer@Sun.COM 			curr_stats->fe_index = index;
2159*11878SVenu.Iyer@Sun.COM 			curr_stats->fe_id = L_HWLANE;
2160*11878SVenu.Iyer@Sun.COM 			/*
2161*11878SVenu.Iyer@Sun.COM 			 * Save last pointer of previous linked list.
2162*11878SVenu.Iyer@Sun.COM 			 * This pointer is used to chain linked lists
2163*11878SVenu.Iyer@Sun.COM 			 * generated in each iteration.
2164*11878SVenu.Iyer@Sun.COM 			 */
2165*11878SVenu.Iyer@Sun.COM 			prev = curr;
2166*11878SVenu.Iyer@Sun.COM 		}
2167*11878SVenu.Iyer@Sun.COM 	}
2168*11878SVenu.Iyer@Sun.COM 
2169*11878SVenu.Iyer@Sun.COM 	return (head);
2170*11878SVenu.Iyer@Sun.COM }
2171*11878SVenu.Iyer@Sun.COM 
2172*11878SVenu.Iyer@Sun.COM void *
dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh,datalink_id_t linkid,const char * linkname)2173*11878SVenu.Iyer@Sun.COM dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid,
2174*11878SVenu.Iyer@Sun.COM     const char *linkname)
2175*11878SVenu.Iyer@Sun.COM {
2176*11878SVenu.Iyer@Sun.COM 	return (i_dlstat_query_fanout_stats(dh, linkid,
2177*11878SVenu.Iyer@Sun.COM 	    default_idlist, default_idlist_size, linkname,
2178*11878SVenu.Iyer@Sun.COM 	    DLSTAT_MAC_RX_SWLANE));
2179*11878SVenu.Iyer@Sun.COM }
2180*11878SVenu.Iyer@Sun.COM 
2181*11878SVenu.Iyer@Sun.COM void *
dlstat_fanout_hwlane_stats(dladm_handle_t dh,datalink_id_t linkid,const char * linkname)2182*11878SVenu.Iyer@Sun.COM dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid,
2183*11878SVenu.Iyer@Sun.COM     const char *linkname)
2184*11878SVenu.Iyer@Sun.COM {
2185*11878SVenu.Iyer@Sun.COM 	uint_t	rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
2186*11878SVenu.Iyer@Sun.COM 	uint_t	rx_hwlane_idlist_size;
2187*11878SVenu.Iyer@Sun.COM 
2188*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_idlist(linkname, DLSTAT_RX_HWLANE_IDLIST,
2189*11878SVenu.Iyer@Sun.COM 	    rx_hwlane_idlist, &rx_hwlane_idlist_size);
2190*11878SVenu.Iyer@Sun.COM 
2191*11878SVenu.Iyer@Sun.COM 	return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist,
2192*11878SVenu.Iyer@Sun.COM 	    rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE));
2193*11878SVenu.Iyer@Sun.COM }
2194*11878SVenu.Iyer@Sun.COM 
2195*11878SVenu.Iyer@Sun.COM void *
dlstat_fanout_stats(dladm_handle_t dh,datalink_id_t linkid)2196*11878SVenu.Iyer@Sun.COM dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid)
2197*11878SVenu.Iyer@Sun.COM {
2198*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
2199*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*fout_hwlane_stats;
2200*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*fout_swlane_and_local_stats;
2201*11878SVenu.Iyer@Sun.COM 	fanout_stat_entry_t	*fout_stats;
2202*11878SVenu.Iyer@Sun.COM 	char 			linkname[MAXLINKNAMELEN];
2203*11878SVenu.Iyer@Sun.COM 
2204*11878SVenu.Iyer@Sun.COM 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
2205*11878SVenu.Iyer@Sun.COM 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2206*11878SVenu.Iyer@Sun.COM 		goto done;
2207*11878SVenu.Iyer@Sun.COM 	}
2208*11878SVenu.Iyer@Sun.COM 
2209*11878SVenu.Iyer@Sun.COM 	fout_swlane_and_local_stats =
2210*11878SVenu.Iyer@Sun.COM 	    dlstat_fanout_swlane_and_local_stats(dh, linkid, linkname);
2211*11878SVenu.Iyer@Sun.COM 	fout_hwlane_stats = dlstat_fanout_hwlane_stats(dh, linkid, linkname);
2212*11878SVenu.Iyer@Sun.COM 
2213*11878SVenu.Iyer@Sun.COM 	if (fout_swlane_and_local_stats == NULL) {
2214*11878SVenu.Iyer@Sun.COM 		head = fout_hwlane_stats;
2215*11878SVenu.Iyer@Sun.COM 		goto done;
2216*11878SVenu.Iyer@Sun.COM 	}
2217*11878SVenu.Iyer@Sun.COM 
2218*11878SVenu.Iyer@Sun.COM 	fout_stats = fout_swlane_and_local_stats->dc_statentry;
2219*11878SVenu.Iyer@Sun.COM 
2220*11878SVenu.Iyer@Sun.COM 	if (fout_hwlane_stats != NULL) { /* hwlane(s), only local traffic */
2221*11878SVenu.Iyer@Sun.COM 		fout_stats->fe_id = L_LOCAL;
2222*11878SVenu.Iyer@Sun.COM 		fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
2223*11878SVenu.Iyer@Sun.COM 	} else { /* no hwlane, mix of local+sw classified */
2224*11878SVenu.Iyer@Sun.COM 		fout_stats->fe_id = L_LCLSWLANE;
2225*11878SVenu.Iyer@Sun.COM 		fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
2226*11878SVenu.Iyer@Sun.COM 	}
2227*11878SVenu.Iyer@Sun.COM 
2228*11878SVenu.Iyer@Sun.COM 	fout_swlane_and_local_stats->dc_next = fout_hwlane_stats;
2229*11878SVenu.Iyer@Sun.COM 	head = fout_swlane_and_local_stats;
2230*11878SVenu.Iyer@Sun.COM 
2231*11878SVenu.Iyer@Sun.COM done:
2232*11878SVenu.Iyer@Sun.COM 	return (head);
2233*11878SVenu.Iyer@Sun.COM }
2234*11878SVenu.Iyer@Sun.COM 
2235*11878SVenu.Iyer@Sun.COM /* Rx ring statistic specific functions */
2236*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_rx_ring_match(void * arg1,void * arg2)2237*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_match(void *arg1, void *arg2)
2238*11878SVenu.Iyer@Sun.COM {
2239*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*s1 = arg1;
2240*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*s2 = arg2;
2241*11878SVenu.Iyer@Sun.COM 
2242*11878SVenu.Iyer@Sun.COM 	return (s1->rle_index == s2->rle_index);
2243*11878SVenu.Iyer@Sun.COM }
2244*11878SVenu.Iyer@Sun.COM 
2245*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_rx_ring_stat_entry_diff(void * arg1,void * arg2)2246*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_stat_entry_diff(void *arg1, void *arg2)
2247*11878SVenu.Iyer@Sun.COM {
2248*11878SVenu.Iyer@Sun.COM 	ring_stat_entry_t 	*s1 = arg1;
2249*11878SVenu.Iyer@Sun.COM 	ring_stat_entry_t 	*s2 = arg2;
2250*11878SVenu.Iyer@Sun.COM 	ring_stat_entry_t 	*diff_entry;
2251*11878SVenu.Iyer@Sun.COM 
2252*11878SVenu.Iyer@Sun.COM 	diff_entry = malloc(sizeof (ring_stat_entry_t));
2253*11878SVenu.Iyer@Sun.COM 	if (diff_entry == NULL)
2254*11878SVenu.Iyer@Sun.COM 		goto done;
2255*11878SVenu.Iyer@Sun.COM 
2256*11878SVenu.Iyer@Sun.COM 	diff_entry->re_index	= s1->re_index;
2257*11878SVenu.Iyer@Sun.COM 
2258*11878SVenu.Iyer@Sun.COM 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, rx_ring_stats_list,
2259*11878SVenu.Iyer@Sun.COM 	    RX_RING_STAT_SIZE);
2260*11878SVenu.Iyer@Sun.COM 
2261*11878SVenu.Iyer@Sun.COM done:
2262*11878SVenu.Iyer@Sun.COM 	return (diff_entry);
2263*11878SVenu.Iyer@Sun.COM }
2264*11878SVenu.Iyer@Sun.COM 
2265*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)2266*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
2267*11878SVenu.Iyer@Sun.COM {
2268*11878SVenu.Iyer@Sun.COM 	ring_stat_entry_t	*rx_ring_stat_entry;
2269*11878SVenu.Iyer@Sun.COM 
2270*11878SVenu.Iyer@Sun.COM 	rx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
2271*11878SVenu.Iyer@Sun.COM 	if (rx_ring_stat_entry == NULL)
2272*11878SVenu.Iyer@Sun.COM 		goto done;
2273*11878SVenu.Iyer@Sun.COM 
2274*11878SVenu.Iyer@Sun.COM 	rx_ring_stat_entry->re_index	= i;
2275*11878SVenu.Iyer@Sun.COM 
2276*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_stats(kcp, ksp, &rx_ring_stat_entry->re_stats,
2277*11878SVenu.Iyer@Sun.COM 	    rx_ring_stats_list, RX_RING_STAT_SIZE);
2278*11878SVenu.Iyer@Sun.COM 
2279*11878SVenu.Iyer@Sun.COM done:
2280*11878SVenu.Iyer@Sun.COM 	return (rx_ring_stat_entry);
2281*11878SVenu.Iyer@Sun.COM }
2282*11878SVenu.Iyer@Sun.COM 
2283*11878SVenu.Iyer@Sun.COM void *
dlstat_rx_ring_stats(dladm_handle_t dh,datalink_id_t linkid)2284*11878SVenu.Iyer@Sun.COM dlstat_rx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
2285*11878SVenu.Iyer@Sun.COM {
2286*11878SVenu.Iyer@Sun.COM 	uint_t			rx_ring_idlist[MAX_RINGS_PER_GROUP];
2287*11878SVenu.Iyer@Sun.COM 	uint_t			rx_ring_idlist_size;
2288*11878SVenu.Iyer@Sun.COM 	dladm_phys_attr_t	dpa;
2289*11878SVenu.Iyer@Sun.COM 	char			linkname[MAXLINKNAMELEN];
2290*11878SVenu.Iyer@Sun.COM 	char			*modname;
2291*11878SVenu.Iyer@Sun.COM 	datalink_class_t	class;
2292*11878SVenu.Iyer@Sun.COM 
2293*11878SVenu.Iyer@Sun.COM 	/*
2294*11878SVenu.Iyer@Sun.COM 	 * kstats corresponding to physical device rings continue to use
2295*11878SVenu.Iyer@Sun.COM 	 * device names even if the link is renamed using dladm rename-link.
2296*11878SVenu.Iyer@Sun.COM 	 * Thus, given a linkid, we lookup the physical device name.
2297*11878SVenu.Iyer@Sun.COM 	 * However, if an aggr is renamed, kstats corresponding to its
2298*11878SVenu.Iyer@Sun.COM 	 * pseudo rings are renamed as well.
2299*11878SVenu.Iyer@Sun.COM 	 */
2300*11878SVenu.Iyer@Sun.COM 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
2301*11878SVenu.Iyer@Sun.COM 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2302*11878SVenu.Iyer@Sun.COM 		return (NULL);
2303*11878SVenu.Iyer@Sun.COM 	}
2304*11878SVenu.Iyer@Sun.COM 
2305*11878SVenu.Iyer@Sun.COM 	if (class != DATALINK_CLASS_AGGR) {
2306*11878SVenu.Iyer@Sun.COM 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
2307*11878SVenu.Iyer@Sun.COM 		    DLADM_STATUS_OK) {
2308*11878SVenu.Iyer@Sun.COM 			return (NULL);
2309*11878SVenu.Iyer@Sun.COM 		}
2310*11878SVenu.Iyer@Sun.COM 		modname = dpa.dp_dev;
2311*11878SVenu.Iyer@Sun.COM 	} else
2312*11878SVenu.Iyer@Sun.COM 		modname = linkname;
2313*11878SVenu.Iyer@Sun.COM 
2314*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_idlist(modname, DLSTAT_RX_RING_IDLIST,
2315*11878SVenu.Iyer@Sun.COM 	    rx_ring_idlist, &rx_ring_idlist_size);
2316*11878SVenu.Iyer@Sun.COM 
2317*11878SVenu.Iyer@Sun.COM 	return (i_dlstat_query_stats(modname, DLSTAT_MAC_RX_RING,
2318*11878SVenu.Iyer@Sun.COM 	    rx_ring_idlist, rx_ring_idlist_size,
2319*11878SVenu.Iyer@Sun.COM 	    i_dlstat_rx_ring_retrieve_stat));
2320*11878SVenu.Iyer@Sun.COM }
2321*11878SVenu.Iyer@Sun.COM 
2322*11878SVenu.Iyer@Sun.COM /* Tx ring statistic specific functions */
2323*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_tx_ring_match(void * arg1,void * arg2)2324*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_match(void *arg1, void *arg2)
2325*11878SVenu.Iyer@Sun.COM {
2326*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t	*s1 = arg1;
2327*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t	*s2 = arg2;
2328*11878SVenu.Iyer@Sun.COM 
2329*11878SVenu.Iyer@Sun.COM 	return (s1->tle_index == s2->tle_index);
2330*11878SVenu.Iyer@Sun.COM }
2331*11878SVenu.Iyer@Sun.COM 
2332*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_tx_ring_stat_entry_diff(void * arg1,void * arg2)2333*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2)
2334*11878SVenu.Iyer@Sun.COM {
2335*11878SVenu.Iyer@Sun.COM 	ring_stat_entry_t	*s1 = arg1;
2336*11878SVenu.Iyer@Sun.COM 	ring_stat_entry_t	*s2 = arg2;
2337*11878SVenu.Iyer@Sun.COM 	ring_stat_entry_t	*diff_entry;
2338*11878SVenu.Iyer@Sun.COM 
2339*11878SVenu.Iyer@Sun.COM 	diff_entry = malloc(sizeof (ring_stat_entry_t));
2340*11878SVenu.Iyer@Sun.COM 	if (diff_entry == NULL)
2341*11878SVenu.Iyer@Sun.COM 		goto done;
2342*11878SVenu.Iyer@Sun.COM 
2343*11878SVenu.Iyer@Sun.COM 	diff_entry->re_index	= s1->re_index;
2344*11878SVenu.Iyer@Sun.COM 
2345*11878SVenu.Iyer@Sun.COM 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, tx_ring_stats_list,
2346*11878SVenu.Iyer@Sun.COM 	    TX_RING_STAT_SIZE);
2347*11878SVenu.Iyer@Sun.COM 
2348*11878SVenu.Iyer@Sun.COM done:
2349*11878SVenu.Iyer@Sun.COM 	return (diff_entry);
2350*11878SVenu.Iyer@Sun.COM }
2351*11878SVenu.Iyer@Sun.COM 
2352*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)2353*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
2354*11878SVenu.Iyer@Sun.COM {
2355*11878SVenu.Iyer@Sun.COM 	ring_stat_entry_t	*tx_ring_stat_entry;
2356*11878SVenu.Iyer@Sun.COM 
2357*11878SVenu.Iyer@Sun.COM 	tx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
2358*11878SVenu.Iyer@Sun.COM 	if (tx_ring_stat_entry == NULL)
2359*11878SVenu.Iyer@Sun.COM 		goto done;
2360*11878SVenu.Iyer@Sun.COM 
2361*11878SVenu.Iyer@Sun.COM 	tx_ring_stat_entry->re_index	= i;
2362*11878SVenu.Iyer@Sun.COM 
2363*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_stats(kcp, ksp, &tx_ring_stat_entry->re_stats,
2364*11878SVenu.Iyer@Sun.COM 	    tx_ring_stats_list, TX_RING_STAT_SIZE);
2365*11878SVenu.Iyer@Sun.COM 
2366*11878SVenu.Iyer@Sun.COM done:
2367*11878SVenu.Iyer@Sun.COM 	return (tx_ring_stat_entry);
2368*11878SVenu.Iyer@Sun.COM }
2369*11878SVenu.Iyer@Sun.COM 
2370*11878SVenu.Iyer@Sun.COM void *
dlstat_tx_ring_stats(dladm_handle_t dh,datalink_id_t linkid)2371*11878SVenu.Iyer@Sun.COM dlstat_tx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
2372*11878SVenu.Iyer@Sun.COM {
2373*11878SVenu.Iyer@Sun.COM 	uint_t			tx_ring_idlist[MAX_RINGS_PER_GROUP];
2374*11878SVenu.Iyer@Sun.COM 	uint_t			tx_ring_idlist_size;
2375*11878SVenu.Iyer@Sun.COM 	dladm_phys_attr_t	dpa;
2376*11878SVenu.Iyer@Sun.COM 	char			linkname[MAXLINKNAMELEN];
2377*11878SVenu.Iyer@Sun.COM 	char			*modname;
2378*11878SVenu.Iyer@Sun.COM 	datalink_class_t	class;
2379*11878SVenu.Iyer@Sun.COM 
2380*11878SVenu.Iyer@Sun.COM 	/*
2381*11878SVenu.Iyer@Sun.COM 	 * kstats corresponding to physical device rings continue to use
2382*11878SVenu.Iyer@Sun.COM 	 * device names even if the link is renamed using dladm rename-link.
2383*11878SVenu.Iyer@Sun.COM 	 * Thus, given a linkid, we lookup the physical device name.
2384*11878SVenu.Iyer@Sun.COM 	 * However, if an aggr is renamed, kstats corresponding to its
2385*11878SVenu.Iyer@Sun.COM 	 * pseudo rings are renamed as well.
2386*11878SVenu.Iyer@Sun.COM 	 */
2387*11878SVenu.Iyer@Sun.COM 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
2388*11878SVenu.Iyer@Sun.COM 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2389*11878SVenu.Iyer@Sun.COM 		return (NULL);
2390*11878SVenu.Iyer@Sun.COM 	}
2391*11878SVenu.Iyer@Sun.COM 
2392*11878SVenu.Iyer@Sun.COM 	if (class != DATALINK_CLASS_AGGR) {
2393*11878SVenu.Iyer@Sun.COM 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
2394*11878SVenu.Iyer@Sun.COM 		    DLADM_STATUS_OK) {
2395*11878SVenu.Iyer@Sun.COM 			return (NULL);
2396*11878SVenu.Iyer@Sun.COM 		}
2397*11878SVenu.Iyer@Sun.COM 		modname = dpa.dp_dev;
2398*11878SVenu.Iyer@Sun.COM 	} else
2399*11878SVenu.Iyer@Sun.COM 		modname = linkname;
2400*11878SVenu.Iyer@Sun.COM 
2401*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_idlist(modname, DLSTAT_TX_RING_IDLIST,
2402*11878SVenu.Iyer@Sun.COM 	    tx_ring_idlist, &tx_ring_idlist_size);
2403*11878SVenu.Iyer@Sun.COM 
2404*11878SVenu.Iyer@Sun.COM 	return (i_dlstat_query_stats(modname, DLSTAT_MAC_TX_RING,
2405*11878SVenu.Iyer@Sun.COM 	    tx_ring_idlist, tx_ring_idlist_size,
2406*11878SVenu.Iyer@Sun.COM 	    i_dlstat_tx_ring_retrieve_stat));
2407*11878SVenu.Iyer@Sun.COM }
2408*11878SVenu.Iyer@Sun.COM 
2409*11878SVenu.Iyer@Sun.COM /* Rx ring total statistic specific functions */
2410*11878SVenu.Iyer@Sun.COM void *
dlstat_rx_ring_total_stats(dladm_handle_t dh,datalink_id_t linkid)2411*11878SVenu.Iyer@Sun.COM dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
2412*11878SVenu.Iyer@Sun.COM {
2413*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*total_head = NULL;
2414*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*rx_ring_head, *curr;
2415*11878SVenu.Iyer@Sun.COM 	ring_stat_entry_t	*total_stats;
2416*11878SVenu.Iyer@Sun.COM 
2417*11878SVenu.Iyer@Sun.COM 	/* Get per rx ring stats */
2418*11878SVenu.Iyer@Sun.COM 	rx_ring_head = dlstat_rx_ring_stats(dh, linkid);
2419*11878SVenu.Iyer@Sun.COM 	if (rx_ring_head == NULL)
2420*11878SVenu.Iyer@Sun.COM 		goto done;
2421*11878SVenu.Iyer@Sun.COM 
2422*11878SVenu.Iyer@Sun.COM 	total_stats = calloc(1, sizeof (ring_stat_entry_t));
2423*11878SVenu.Iyer@Sun.COM 	if (total_stats == NULL)
2424*11878SVenu.Iyer@Sun.COM 		goto done;
2425*11878SVenu.Iyer@Sun.COM 
2426*11878SVenu.Iyer@Sun.COM 	total_stats->re_index = DLSTAT_INVALID_ENTRY;
2427*11878SVenu.Iyer@Sun.COM 
2428*11878SVenu.Iyer@Sun.COM 	for (curr = rx_ring_head; curr != NULL; curr = curr->dc_next) {
2429*11878SVenu.Iyer@Sun.COM 		ring_stat_entry_t	*curr_ring_stats = curr->dc_statentry;
2430*11878SVenu.Iyer@Sun.COM 
2431*11878SVenu.Iyer@Sun.COM 		i_dlstat_sum_stats(&total_stats->re_stats,
2432*11878SVenu.Iyer@Sun.COM 		    &curr_ring_stats->re_stats, &total_stats->re_stats,
2433*11878SVenu.Iyer@Sun.COM 		    rx_ring_stats_list, RX_RING_STAT_SIZE);
2434*11878SVenu.Iyer@Sun.COM 	}
2435*11878SVenu.Iyer@Sun.COM 
2436*11878SVenu.Iyer@Sun.COM 	total_head = malloc(sizeof (dladm_stat_chain_t));
2437*11878SVenu.Iyer@Sun.COM 	if (total_head == NULL) {
2438*11878SVenu.Iyer@Sun.COM 		free(total_stats);
2439*11878SVenu.Iyer@Sun.COM 		goto done;
2440*11878SVenu.Iyer@Sun.COM 	}
2441*11878SVenu.Iyer@Sun.COM 
2442*11878SVenu.Iyer@Sun.COM 	total_head->dc_statentry = total_stats;
2443*11878SVenu.Iyer@Sun.COM 	(void) strlcpy(total_head->dc_statheader, "mac_rx_ring_total",
2444*11878SVenu.Iyer@Sun.COM 	    sizeof (total_head->dc_statheader));
2445*11878SVenu.Iyer@Sun.COM 	total_head->dc_next = NULL;
2446*11878SVenu.Iyer@Sun.COM 	free(rx_ring_head);
2447*11878SVenu.Iyer@Sun.COM 
2448*11878SVenu.Iyer@Sun.COM done:
2449*11878SVenu.Iyer@Sun.COM 	return (total_head);
2450*11878SVenu.Iyer@Sun.COM }
2451*11878SVenu.Iyer@Sun.COM 
2452*11878SVenu.Iyer@Sun.COM /* Tx ring total statistic specific functions */
2453*11878SVenu.Iyer@Sun.COM void *
dlstat_tx_ring_total_stats(dladm_handle_t dh,datalink_id_t linkid)2454*11878SVenu.Iyer@Sun.COM dlstat_tx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
2455*11878SVenu.Iyer@Sun.COM {
2456*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*total_head = NULL;
2457*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*tx_ring_head, *curr;
2458*11878SVenu.Iyer@Sun.COM 	ring_stat_entry_t	*total_stats;
2459*11878SVenu.Iyer@Sun.COM 
2460*11878SVenu.Iyer@Sun.COM 	/* Get per tx ring stats */
2461*11878SVenu.Iyer@Sun.COM 	tx_ring_head = dlstat_tx_ring_stats(dh, linkid);
2462*11878SVenu.Iyer@Sun.COM 	if (tx_ring_head == NULL)
2463*11878SVenu.Iyer@Sun.COM 		goto done;
2464*11878SVenu.Iyer@Sun.COM 
2465*11878SVenu.Iyer@Sun.COM 	total_stats = calloc(1, sizeof (ring_stat_entry_t));
2466*11878SVenu.Iyer@Sun.COM 	if (total_stats == NULL)
2467*11878SVenu.Iyer@Sun.COM 		goto done;
2468*11878SVenu.Iyer@Sun.COM 
2469*11878SVenu.Iyer@Sun.COM 	total_stats->re_index = DLSTAT_INVALID_ENTRY;
2470*11878SVenu.Iyer@Sun.COM 
2471*11878SVenu.Iyer@Sun.COM 	for (curr = tx_ring_head; curr != NULL; curr = curr->dc_next) {
2472*11878SVenu.Iyer@Sun.COM 		ring_stat_entry_t	*curr_ring_stats = curr->dc_statentry;
2473*11878SVenu.Iyer@Sun.COM 
2474*11878SVenu.Iyer@Sun.COM 		i_dlstat_sum_stats(&total_stats->re_stats,
2475*11878SVenu.Iyer@Sun.COM 		    &curr_ring_stats->re_stats, &total_stats->re_stats,
2476*11878SVenu.Iyer@Sun.COM 		    tx_ring_stats_list, TX_RING_STAT_SIZE);
2477*11878SVenu.Iyer@Sun.COM 	}
2478*11878SVenu.Iyer@Sun.COM 
2479*11878SVenu.Iyer@Sun.COM 	total_head = malloc(sizeof (dladm_stat_chain_t));
2480*11878SVenu.Iyer@Sun.COM 	if (total_head == NULL) {
2481*11878SVenu.Iyer@Sun.COM 		free(total_stats);
2482*11878SVenu.Iyer@Sun.COM 		goto done;
2483*11878SVenu.Iyer@Sun.COM 	}
2484*11878SVenu.Iyer@Sun.COM 
2485*11878SVenu.Iyer@Sun.COM 	total_head->dc_statentry = total_stats;
2486*11878SVenu.Iyer@Sun.COM 	(void) strlcpy(total_head->dc_statheader, "mac_tx_ring_total",
2487*11878SVenu.Iyer@Sun.COM 	    sizeof (total_head->dc_statheader));
2488*11878SVenu.Iyer@Sun.COM 	total_head->dc_next = NULL;
2489*11878SVenu.Iyer@Sun.COM 	free(tx_ring_head);
2490*11878SVenu.Iyer@Sun.COM 
2491*11878SVenu.Iyer@Sun.COM done:
2492*11878SVenu.Iyer@Sun.COM 	return (total_head);
2493*11878SVenu.Iyer@Sun.COM }
2494*11878SVenu.Iyer@Sun.COM 
2495*11878SVenu.Iyer@Sun.COM /* Summary statistic specific functions */
2496*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/
2497*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_total_match(void * arg1,void * arg2)2498*11878SVenu.Iyer@Sun.COM i_dlstat_total_match(void *arg1, void *arg2)
2499*11878SVenu.Iyer@Sun.COM {					/* Always single entry for total */
2500*11878SVenu.Iyer@Sun.COM 	return (B_TRUE);
2501*11878SVenu.Iyer@Sun.COM }
2502*11878SVenu.Iyer@Sun.COM 
2503*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_total_stat_entry_diff(void * arg1,void * arg2)2504*11878SVenu.Iyer@Sun.COM i_dlstat_total_stat_entry_diff(void *arg1, void *arg2)
2505*11878SVenu.Iyer@Sun.COM {
2506*11878SVenu.Iyer@Sun.COM 	total_stat_entry_t	*s1 = arg1;
2507*11878SVenu.Iyer@Sun.COM 	total_stat_entry_t	*s2 = arg2;
2508*11878SVenu.Iyer@Sun.COM 	total_stat_entry_t	*diff_entry;
2509*11878SVenu.Iyer@Sun.COM 
2510*11878SVenu.Iyer@Sun.COM 	diff_entry = malloc(sizeof (total_stat_entry_t));
2511*11878SVenu.Iyer@Sun.COM 	if (diff_entry == NULL)
2512*11878SVenu.Iyer@Sun.COM 		goto done;
2513*11878SVenu.Iyer@Sun.COM 
2514*11878SVenu.Iyer@Sun.COM 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, tse_stats, total_stats_list,
2515*11878SVenu.Iyer@Sun.COM 	    TOTAL_STAT_SIZE);
2516*11878SVenu.Iyer@Sun.COM 
2517*11878SVenu.Iyer@Sun.COM done:
2518*11878SVenu.Iyer@Sun.COM 	return (diff_entry);
2519*11878SVenu.Iyer@Sun.COM }
2520*11878SVenu.Iyer@Sun.COM 
2521*11878SVenu.Iyer@Sun.COM void *
dlstat_total_stats(dladm_handle_t dh,datalink_id_t linkid)2522*11878SVenu.Iyer@Sun.COM dlstat_total_stats(dladm_handle_t dh, datalink_id_t linkid)
2523*11878SVenu.Iyer@Sun.COM {
2524*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
2525*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*rx_total;
2526*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*tx_total;
2527*11878SVenu.Iyer@Sun.COM 	total_stat_entry_t	*total_stat_entry;
2528*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
2529*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
2530*11878SVenu.Iyer@Sun.COM 
2531*11878SVenu.Iyer@Sun.COM 	/* Get total rx lane stats */
2532*11878SVenu.Iyer@Sun.COM 	rx_total = dlstat_rx_lane_total_stats(dh, linkid);
2533*11878SVenu.Iyer@Sun.COM 	if (rx_total == NULL)
2534*11878SVenu.Iyer@Sun.COM 		goto done;
2535*11878SVenu.Iyer@Sun.COM 
2536*11878SVenu.Iyer@Sun.COM 	/* Get total tx lane stats */
2537*11878SVenu.Iyer@Sun.COM 	tx_total = dlstat_tx_lane_total_stats(dh, linkid);
2538*11878SVenu.Iyer@Sun.COM 	if (tx_total == NULL)
2539*11878SVenu.Iyer@Sun.COM 		goto done;
2540*11878SVenu.Iyer@Sun.COM 
2541*11878SVenu.Iyer@Sun.COM 	/* Build total stat */
2542*11878SVenu.Iyer@Sun.COM 	total_stat_entry = calloc(1, sizeof (total_stat_entry_t));
2543*11878SVenu.Iyer@Sun.COM 	if (total_stat_entry == NULL)
2544*11878SVenu.Iyer@Sun.COM 		goto done;
2545*11878SVenu.Iyer@Sun.COM 
2546*11878SVenu.Iyer@Sun.COM 	rx_lane_stat_entry = rx_total->dc_statentry;
2547*11878SVenu.Iyer@Sun.COM 	tx_lane_stat_entry = tx_total->dc_statentry;
2548*11878SVenu.Iyer@Sun.COM 
2549*11878SVenu.Iyer@Sun.COM 	/* Extract total rx ipackets, rbytes */
2550*11878SVenu.Iyer@Sun.COM 	total_stat_entry->tse_stats.ts_ipackets =
2551*11878SVenu.Iyer@Sun.COM 	    rx_lane_stat_entry->rle_stats.rl_ipackets;
2552*11878SVenu.Iyer@Sun.COM 	total_stat_entry->tse_stats.ts_rbytes =
2553*11878SVenu.Iyer@Sun.COM 	    rx_lane_stat_entry->rle_stats.rl_rbytes;
2554*11878SVenu.Iyer@Sun.COM 
2555*11878SVenu.Iyer@Sun.COM 	/* Extract total tx opackets, obytes */
2556*11878SVenu.Iyer@Sun.COM 	total_stat_entry->tse_stats.ts_opackets =
2557*11878SVenu.Iyer@Sun.COM 	    tx_lane_stat_entry->tle_stats.tl_opackets;
2558*11878SVenu.Iyer@Sun.COM 	total_stat_entry->tse_stats.ts_obytes =
2559*11878SVenu.Iyer@Sun.COM 	    tx_lane_stat_entry->tle_stats.tl_obytes;
2560*11878SVenu.Iyer@Sun.COM 
2561*11878SVenu.Iyer@Sun.COM 	head = malloc(sizeof (dladm_stat_chain_t));
2562*11878SVenu.Iyer@Sun.COM 	if (head == NULL) {
2563*11878SVenu.Iyer@Sun.COM 		free(total_stat_entry);
2564*11878SVenu.Iyer@Sun.COM 		goto done;
2565*11878SVenu.Iyer@Sun.COM 	}
2566*11878SVenu.Iyer@Sun.COM 
2567*11878SVenu.Iyer@Sun.COM 	head->dc_statentry = total_stat_entry;
2568*11878SVenu.Iyer@Sun.COM 	(void) strlcpy(head->dc_statheader, "mac_lane_total",
2569*11878SVenu.Iyer@Sun.COM 	    sizeof (head->dc_statheader));
2570*11878SVenu.Iyer@Sun.COM 	head->dc_next = NULL;
2571*11878SVenu.Iyer@Sun.COM 	free(rx_total);
2572*11878SVenu.Iyer@Sun.COM 	free(tx_total);
2573*11878SVenu.Iyer@Sun.COM 
2574*11878SVenu.Iyer@Sun.COM done:
2575*11878SVenu.Iyer@Sun.COM 	return (head);
2576*11878SVenu.Iyer@Sun.COM }
2577*11878SVenu.Iyer@Sun.COM 
2578*11878SVenu.Iyer@Sun.COM /* Aggr total statistic(summed across all component ports) specific functions */
2579*11878SVenu.Iyer@Sun.COM void *
dlstat_aggr_total_stats(dladm_stat_chain_t * head)2580*11878SVenu.Iyer@Sun.COM dlstat_aggr_total_stats(dladm_stat_chain_t *head)
2581*11878SVenu.Iyer@Sun.COM {
2582*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*curr;
2583*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*total_head;
2584*11878SVenu.Iyer@Sun.COM 	aggr_port_stat_entry_t	*total_stats;
2585*11878SVenu.Iyer@Sun.COM 
2586*11878SVenu.Iyer@Sun.COM 	total_stats = calloc(1, sizeof (aggr_port_stat_entry_t));
2587*11878SVenu.Iyer@Sun.COM 	if (total_stats == NULL)
2588*11878SVenu.Iyer@Sun.COM 		goto done;
2589*11878SVenu.Iyer@Sun.COM 
2590*11878SVenu.Iyer@Sun.COM 	total_stats->ape_portlinkid = DATALINK_INVALID_LINKID;
2591*11878SVenu.Iyer@Sun.COM 
2592*11878SVenu.Iyer@Sun.COM 	for (curr = head; curr != NULL; curr = curr->dc_next) {
2593*11878SVenu.Iyer@Sun.COM 		aggr_port_stat_entry_t	*curr_aggr_port_stats;
2594*11878SVenu.Iyer@Sun.COM 
2595*11878SVenu.Iyer@Sun.COM 		curr_aggr_port_stats = curr->dc_statentry;
2596*11878SVenu.Iyer@Sun.COM 
2597*11878SVenu.Iyer@Sun.COM 		i_dlstat_sum_stats(&total_stats->ape_stats,
2598*11878SVenu.Iyer@Sun.COM 		    &curr_aggr_port_stats->ape_stats, &total_stats->ape_stats,
2599*11878SVenu.Iyer@Sun.COM 		    aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
2600*11878SVenu.Iyer@Sun.COM 	}
2601*11878SVenu.Iyer@Sun.COM 
2602*11878SVenu.Iyer@Sun.COM 	total_head = malloc(sizeof (dladm_stat_chain_t));
2603*11878SVenu.Iyer@Sun.COM 	if (total_head == NULL) {
2604*11878SVenu.Iyer@Sun.COM 		free(total_stats);
2605*11878SVenu.Iyer@Sun.COM 		goto done;
2606*11878SVenu.Iyer@Sun.COM 	}
2607*11878SVenu.Iyer@Sun.COM 
2608*11878SVenu.Iyer@Sun.COM 	total_head->dc_statentry = total_stats;
2609*11878SVenu.Iyer@Sun.COM 	total_head->dc_next = NULL;
2610*11878SVenu.Iyer@Sun.COM 
2611*11878SVenu.Iyer@Sun.COM done:
2612*11878SVenu.Iyer@Sun.COM 	return (total_head);
2613*11878SVenu.Iyer@Sun.COM }
2614*11878SVenu.Iyer@Sun.COM 
2615*11878SVenu.Iyer@Sun.COM /* Aggr port statistic specific functions */
2616*11878SVenu.Iyer@Sun.COM static boolean_t
i_dlstat_aggr_port_match(void * arg1,void * arg2)2617*11878SVenu.Iyer@Sun.COM i_dlstat_aggr_port_match(void *arg1, void *arg2)
2618*11878SVenu.Iyer@Sun.COM {
2619*11878SVenu.Iyer@Sun.COM 	aggr_port_stat_entry_t *s1 = arg1;
2620*11878SVenu.Iyer@Sun.COM 	aggr_port_stat_entry_t *s2 = arg2;
2621*11878SVenu.Iyer@Sun.COM 
2622*11878SVenu.Iyer@Sun.COM 	return (s1->ape_portlinkid == s2->ape_portlinkid);
2623*11878SVenu.Iyer@Sun.COM }
2624*11878SVenu.Iyer@Sun.COM 
2625*11878SVenu.Iyer@Sun.COM static void *
i_dlstat_aggr_port_stat_entry_diff(void * arg1,void * arg2)2626*11878SVenu.Iyer@Sun.COM i_dlstat_aggr_port_stat_entry_diff(void *arg1, void *arg2)
2627*11878SVenu.Iyer@Sun.COM {
2628*11878SVenu.Iyer@Sun.COM 	aggr_port_stat_entry_t	*s1 = arg1;
2629*11878SVenu.Iyer@Sun.COM 	aggr_port_stat_entry_t	*s2 = arg2;
2630*11878SVenu.Iyer@Sun.COM 	aggr_port_stat_entry_t	*diff_entry;
2631*11878SVenu.Iyer@Sun.COM 
2632*11878SVenu.Iyer@Sun.COM 	diff_entry = malloc(sizeof (aggr_port_stat_entry_t));
2633*11878SVenu.Iyer@Sun.COM 	if (diff_entry == NULL)
2634*11878SVenu.Iyer@Sun.COM 		goto done;
2635*11878SVenu.Iyer@Sun.COM 
2636*11878SVenu.Iyer@Sun.COM 	diff_entry->ape_portlinkid = s1->ape_portlinkid;
2637*11878SVenu.Iyer@Sun.COM 
2638*11878SVenu.Iyer@Sun.COM 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list,
2639*11878SVenu.Iyer@Sun.COM 	    AGGR_PORT_STAT_SIZE);
2640*11878SVenu.Iyer@Sun.COM 
2641*11878SVenu.Iyer@Sun.COM done:
2642*11878SVenu.Iyer@Sun.COM 	return (diff_entry);
2643*11878SVenu.Iyer@Sun.COM }
2644*11878SVenu.Iyer@Sun.COM 
2645*11878SVenu.Iyer@Sun.COM /*
2646*11878SVenu.Iyer@Sun.COM  * Query dls stats for the aggr port. This results in query for stats into
2647*11878SVenu.Iyer@Sun.COM  * the corresponding device driver.
2648*11878SVenu.Iyer@Sun.COM  */
2649*11878SVenu.Iyer@Sun.COM static aggr_port_stat_entry_t *
i_dlstat_single_port_stats(const char * portname,datalink_id_t linkid)2650*11878SVenu.Iyer@Sun.COM i_dlstat_single_port_stats(const char *portname, datalink_id_t linkid)
2651*11878SVenu.Iyer@Sun.COM {
2652*11878SVenu.Iyer@Sun.COM 	kstat_ctl_t		*kcp;
2653*11878SVenu.Iyer@Sun.COM 	kstat_t			*ksp;
2654*11878SVenu.Iyer@Sun.COM 	char			module[DLPI_LINKNAME_MAX];
2655*11878SVenu.Iyer@Sun.COM 	uint_t			instance;
2656*11878SVenu.Iyer@Sun.COM 	aggr_port_stat_entry_t	*aggr_port_stat_entry = NULL;
2657*11878SVenu.Iyer@Sun.COM 
2658*11878SVenu.Iyer@Sun.COM 	if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK)
2659*11878SVenu.Iyer@Sun.COM 		goto done;
2660*11878SVenu.Iyer@Sun.COM 
2661*11878SVenu.Iyer@Sun.COM 	if ((kcp = kstat_open()) == NULL) {
2662*11878SVenu.Iyer@Sun.COM 		warn("kstat open operation failed");
2663*11878SVenu.Iyer@Sun.COM 		return (NULL);
2664*11878SVenu.Iyer@Sun.COM 	}
2665*11878SVenu.Iyer@Sun.COM 
2666*11878SVenu.Iyer@Sun.COM 	ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL);
2667*11878SVenu.Iyer@Sun.COM 	if (ksp == NULL)
2668*11878SVenu.Iyer@Sun.COM 		goto done;
2669*11878SVenu.Iyer@Sun.COM 
2670*11878SVenu.Iyer@Sun.COM 	aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t));
2671*11878SVenu.Iyer@Sun.COM 	if (aggr_port_stat_entry == NULL)
2672*11878SVenu.Iyer@Sun.COM 		goto done;
2673*11878SVenu.Iyer@Sun.COM 
2674*11878SVenu.Iyer@Sun.COM 	/* Save port's linkid */
2675*11878SVenu.Iyer@Sun.COM 	aggr_port_stat_entry->ape_portlinkid = linkid;
2676*11878SVenu.Iyer@Sun.COM 
2677*11878SVenu.Iyer@Sun.COM 	i_dlstat_get_stats(kcp, ksp, &aggr_port_stat_entry->ape_stats,
2678*11878SVenu.Iyer@Sun.COM 	    aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
2679*11878SVenu.Iyer@Sun.COM done:
2680*11878SVenu.Iyer@Sun.COM 	(void) kstat_close(kcp);
2681*11878SVenu.Iyer@Sun.COM 	return (aggr_port_stat_entry);
2682*11878SVenu.Iyer@Sun.COM }
2683*11878SVenu.Iyer@Sun.COM 
2684*11878SVenu.Iyer@Sun.COM void *
dlstat_aggr_port_stats(dladm_handle_t dh,datalink_id_t linkid)2685*11878SVenu.Iyer@Sun.COM dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid)
2686*11878SVenu.Iyer@Sun.COM {
2687*11878SVenu.Iyer@Sun.COM 	dladm_aggr_grp_attr_t	ginfo;
2688*11878SVenu.Iyer@Sun.COM 	int			i;
2689*11878SVenu.Iyer@Sun.COM 	dladm_aggr_port_attr_t	 *portp;
2690*11878SVenu.Iyer@Sun.COM 	dladm_phys_attr_t	dpa;
2691*11878SVenu.Iyer@Sun.COM 	aggr_port_stat_entry_t	*aggr_port_stat_entry;
2692*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL, *prev = NULL, *curr;
2693*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*total_stats;
2694*11878SVenu.Iyer@Sun.COM 
2695*11878SVenu.Iyer@Sun.COM 	/* Get aggr info */
2696*11878SVenu.Iyer@Sun.COM 	bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
2697*11878SVenu.Iyer@Sun.COM 	if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE)
2698*11878SVenu.Iyer@Sun.COM 	    != DLADM_STATUS_OK)
2699*11878SVenu.Iyer@Sun.COM 		goto done;
2700*11878SVenu.Iyer@Sun.COM 	/* For every port that is member of this aggr do */
2701*11878SVenu.Iyer@Sun.COM 	for (i = 0; i < ginfo.lg_nports; i++) {
2702*11878SVenu.Iyer@Sun.COM 		portp = &(ginfo.lg_ports[i]);
2703*11878SVenu.Iyer@Sun.COM 		if (dladm_phys_info(dh, portp->lp_linkid, &dpa,
2704*11878SVenu.Iyer@Sun.COM 		    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
2705*11878SVenu.Iyer@Sun.COM 			goto done;
2706*11878SVenu.Iyer@Sun.COM 		}
2707*11878SVenu.Iyer@Sun.COM 
2708*11878SVenu.Iyer@Sun.COM 		aggr_port_stat_entry = i_dlstat_single_port_stats(dpa.dp_dev,
2709*11878SVenu.Iyer@Sun.COM 		    portp->lp_linkid);
2710*11878SVenu.Iyer@Sun.COM 
2711*11878SVenu.Iyer@Sun.COM 		/* Create dladm_stat_chain_t object for this stat */
2712*11878SVenu.Iyer@Sun.COM 		curr = malloc(sizeof (dladm_stat_chain_t));
2713*11878SVenu.Iyer@Sun.COM 		if (curr == NULL) {
2714*11878SVenu.Iyer@Sun.COM 			free(aggr_port_stat_entry);
2715*11878SVenu.Iyer@Sun.COM 			goto done;
2716*11878SVenu.Iyer@Sun.COM 		}
2717*11878SVenu.Iyer@Sun.COM 		(void) strlcpy(curr->dc_statheader, dpa.dp_dev,
2718*11878SVenu.Iyer@Sun.COM 		    sizeof (curr->dc_statheader));
2719*11878SVenu.Iyer@Sun.COM 		curr->dc_statentry = aggr_port_stat_entry;
2720*11878SVenu.Iyer@Sun.COM 		curr->dc_next = NULL;
2721*11878SVenu.Iyer@Sun.COM 
2722*11878SVenu.Iyer@Sun.COM 		/* Chain this aggr port stat entry */
2723*11878SVenu.Iyer@Sun.COM 		/* head of the stat list */
2724*11878SVenu.Iyer@Sun.COM 		if (prev == NULL)
2725*11878SVenu.Iyer@Sun.COM 			head = curr;
2726*11878SVenu.Iyer@Sun.COM 		else
2727*11878SVenu.Iyer@Sun.COM 			prev->dc_next = curr;
2728*11878SVenu.Iyer@Sun.COM 		prev = curr;
2729*11878SVenu.Iyer@Sun.COM 	}
2730*11878SVenu.Iyer@Sun.COM 
2731*11878SVenu.Iyer@Sun.COM 	/*
2732*11878SVenu.Iyer@Sun.COM 	 * Prepend the stat list with cumulative aggr stats i.e. summed over all
2733*11878SVenu.Iyer@Sun.COM 	 * component ports
2734*11878SVenu.Iyer@Sun.COM 	 */
2735*11878SVenu.Iyer@Sun.COM 	total_stats = dlstat_aggr_total_stats(head);
2736*11878SVenu.Iyer@Sun.COM 	if (total_stats != NULL) {
2737*11878SVenu.Iyer@Sun.COM 		total_stats->dc_next = head;
2738*11878SVenu.Iyer@Sun.COM 		head = total_stats;
2739*11878SVenu.Iyer@Sun.COM 	}
2740*11878SVenu.Iyer@Sun.COM 
2741*11878SVenu.Iyer@Sun.COM done:
2742*11878SVenu.Iyer@Sun.COM 	free(ginfo.lg_ports);
2743*11878SVenu.Iyer@Sun.COM 	return (head);
2744*11878SVenu.Iyer@Sun.COM }
2745*11878SVenu.Iyer@Sun.COM 
2746*11878SVenu.Iyer@Sun.COM /* Misc stat specific functions */
2747*11878SVenu.Iyer@Sun.COM void *
dlstat_misc_stats(dladm_handle_t dh,datalink_id_t linkid)2748*11878SVenu.Iyer@Sun.COM dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid)
2749*11878SVenu.Iyer@Sun.COM {
2750*11878SVenu.Iyer@Sun.COM 	misc_stat_entry_t	*misc_stat_entry;
2751*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*head = NULL;
2752*11878SVenu.Iyer@Sun.COM 	char 			linkname[MAXLINKNAMELEN];
2753*11878SVenu.Iyer@Sun.COM 
2754*11878SVenu.Iyer@Sun.COM 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
2755*11878SVenu.Iyer@Sun.COM 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2756*11878SVenu.Iyer@Sun.COM 		goto done;
2757*11878SVenu.Iyer@Sun.COM 	}
2758*11878SVenu.Iyer@Sun.COM 
2759*11878SVenu.Iyer@Sun.COM 	misc_stat_entry = i_dlstat_misc_stats(linkname);
2760*11878SVenu.Iyer@Sun.COM 	if (misc_stat_entry == NULL)
2761*11878SVenu.Iyer@Sun.COM 		goto done;
2762*11878SVenu.Iyer@Sun.COM 
2763*11878SVenu.Iyer@Sun.COM 	head = malloc(sizeof (dladm_stat_chain_t));
2764*11878SVenu.Iyer@Sun.COM 	if (head == NULL) {
2765*11878SVenu.Iyer@Sun.COM 		free(misc_stat_entry);
2766*11878SVenu.Iyer@Sun.COM 		goto done;
2767*11878SVenu.Iyer@Sun.COM 	}
2768*11878SVenu.Iyer@Sun.COM 
2769*11878SVenu.Iyer@Sun.COM 	head->dc_statentry = misc_stat_entry;
2770*11878SVenu.Iyer@Sun.COM 	(void) strlcpy(head->dc_statheader, "mac_misc_stat",
2771*11878SVenu.Iyer@Sun.COM 	    sizeof (head->dc_statheader));
2772*11878SVenu.Iyer@Sun.COM 	head->dc_next = NULL;
2773*11878SVenu.Iyer@Sun.COM 
2774*11878SVenu.Iyer@Sun.COM done:
2775*11878SVenu.Iyer@Sun.COM 	return (head);
2776*11878SVenu.Iyer@Sun.COM }
2777*11878SVenu.Iyer@Sun.COM 
2778*11878SVenu.Iyer@Sun.COM /* Exported functions */
2779*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *
dladm_link_stat_query(dladm_handle_t dh,datalink_id_t linkid,dladm_stat_type_t stattype)2780*11878SVenu.Iyer@Sun.COM dladm_link_stat_query(dladm_handle_t dh, datalink_id_t linkid,
2781*11878SVenu.Iyer@Sun.COM     dladm_stat_type_t stattype)
2782*11878SVenu.Iyer@Sun.COM {
2783*11878SVenu.Iyer@Sun.COM 	return (dladm_stat_table[stattype].ds_querystat(dh, linkid));
2784*11878SVenu.Iyer@Sun.COM }
2785*11878SVenu.Iyer@Sun.COM 
2786*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *
dladm_link_stat_diffchain(dladm_stat_chain_t * op1,dladm_stat_chain_t * op2,dladm_stat_type_t stattype)2787*11878SVenu.Iyer@Sun.COM dladm_link_stat_diffchain(dladm_stat_chain_t *op1, dladm_stat_chain_t *op2,
2788*11878SVenu.Iyer@Sun.COM     dladm_stat_type_t stattype)
2789*11878SVenu.Iyer@Sun.COM {
2790*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*op1_curr, *op2_curr;
2791*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*diff_curr;
2792*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*diff_prev = NULL, *diff_head = NULL;
2793*11878SVenu.Iyer@Sun.COM 
2794*11878SVenu.Iyer@Sun.COM 				/* Perform op1 - op2, store result in diff */
2795*11878SVenu.Iyer@Sun.COM 	for (op1_curr = op1; op1_curr != NULL; op1_curr = op1_curr->dc_next) {
2796*11878SVenu.Iyer@Sun.COM 		for (op2_curr = op2; op2_curr != NULL;
2797*11878SVenu.Iyer@Sun.COM 		    op2_curr = op2_curr->dc_next) {
2798*11878SVenu.Iyer@Sun.COM 			if (dlstat_match_stats(op1_curr->dc_statentry,
2799*11878SVenu.Iyer@Sun.COM 			    op2_curr->dc_statentry, stattype)) {
2800*11878SVenu.Iyer@Sun.COM 				break;
2801*11878SVenu.Iyer@Sun.COM 			}
2802*11878SVenu.Iyer@Sun.COM 		}
2803*11878SVenu.Iyer@Sun.COM 		diff_curr = malloc(sizeof (dladm_stat_chain_t));
2804*11878SVenu.Iyer@Sun.COM 		if (diff_curr == NULL)
2805*11878SVenu.Iyer@Sun.COM 			goto done;
2806*11878SVenu.Iyer@Sun.COM 
2807*11878SVenu.Iyer@Sun.COM 		diff_curr->dc_next = NULL;
2808*11878SVenu.Iyer@Sun.COM 
2809*11878SVenu.Iyer@Sun.COM 		if (op2_curr == NULL) {
2810*11878SVenu.Iyer@Sun.COM 			/* prev iteration did not have this stat entry */
2811*11878SVenu.Iyer@Sun.COM 			diff_curr->dc_statentry =
2812*11878SVenu.Iyer@Sun.COM 			    dlstat_diff_stats(op1_curr->dc_statentry,
2813*11878SVenu.Iyer@Sun.COM 			    NULL, stattype);
2814*11878SVenu.Iyer@Sun.COM 		} else {
2815*11878SVenu.Iyer@Sun.COM 			diff_curr->dc_statentry =
2816*11878SVenu.Iyer@Sun.COM 			    dlstat_diff_stats(op1_curr->dc_statentry,
2817*11878SVenu.Iyer@Sun.COM 			    op2_curr->dc_statentry, stattype);
2818*11878SVenu.Iyer@Sun.COM 		}
2819*11878SVenu.Iyer@Sun.COM 
2820*11878SVenu.Iyer@Sun.COM 		if (diff_curr->dc_statentry == NULL) {
2821*11878SVenu.Iyer@Sun.COM 			free(diff_curr);
2822*11878SVenu.Iyer@Sun.COM 			goto done;
2823*11878SVenu.Iyer@Sun.COM 		}
2824*11878SVenu.Iyer@Sun.COM 
2825*11878SVenu.Iyer@Sun.COM 		if (diff_prev == NULL) /* head of the diff stat list */
2826*11878SVenu.Iyer@Sun.COM 			diff_head = diff_curr;
2827*11878SVenu.Iyer@Sun.COM 		else
2828*11878SVenu.Iyer@Sun.COM 			diff_prev->dc_next = diff_curr;
2829*11878SVenu.Iyer@Sun.COM 		diff_prev = diff_curr;
2830*11878SVenu.Iyer@Sun.COM 	}
2831*11878SVenu.Iyer@Sun.COM done:
2832*11878SVenu.Iyer@Sun.COM 	return (diff_head);
2833*11878SVenu.Iyer@Sun.COM }
2834*11878SVenu.Iyer@Sun.COM 
2835*11878SVenu.Iyer@Sun.COM void
dladm_link_stat_free(dladm_stat_chain_t * curr)2836*11878SVenu.Iyer@Sun.COM dladm_link_stat_free(dladm_stat_chain_t *curr)
2837*11878SVenu.Iyer@Sun.COM {
2838*11878SVenu.Iyer@Sun.COM 	while (curr != NULL) {
2839*11878SVenu.Iyer@Sun.COM 		dladm_stat_chain_t	*tofree = curr;
2840*11878SVenu.Iyer@Sun.COM 
2841*11878SVenu.Iyer@Sun.COM 		curr = curr->dc_next;
2842*11878SVenu.Iyer@Sun.COM 		free(tofree->dc_statentry);
2843*11878SVenu.Iyer@Sun.COM 		free(tofree);
2844*11878SVenu.Iyer@Sun.COM 	}
2845*11878SVenu.Iyer@Sun.COM }
2846*11878SVenu.Iyer@Sun.COM 
2847*11878SVenu.Iyer@Sun.COM /* Query all link stats */
2848*11878SVenu.Iyer@Sun.COM static name_value_stat_t *
i_dlstat_convert_stats(void * stats,stat_info_t stats_list[],uint_t size)2849*11878SVenu.Iyer@Sun.COM i_dlstat_convert_stats(void *stats, stat_info_t stats_list[], uint_t size)
2850*11878SVenu.Iyer@Sun.COM {
2851*11878SVenu.Iyer@Sun.COM 	int			i;
2852*11878SVenu.Iyer@Sun.COM 	name_value_stat_t	*head_stat = NULL, *prev_stat = NULL;
2853*11878SVenu.Iyer@Sun.COM 	name_value_stat_t	*curr_stat;
2854*11878SVenu.Iyer@Sun.COM 
2855*11878SVenu.Iyer@Sun.COM 	for (i = 0; i < size; i++) {
2856*11878SVenu.Iyer@Sun.COM 		uint64_t *val = (void *)
2857*11878SVenu.Iyer@Sun.COM 		    ((uchar_t *)stats + stats_list[i].si_offset);
2858*11878SVenu.Iyer@Sun.COM 
2859*11878SVenu.Iyer@Sun.COM 		curr_stat = calloc(1, sizeof (name_value_stat_t));
2860*11878SVenu.Iyer@Sun.COM 		if (curr_stat == NULL)
2861*11878SVenu.Iyer@Sun.COM 			break;
2862*11878SVenu.Iyer@Sun.COM 
2863*11878SVenu.Iyer@Sun.COM 		(void) strlcpy(curr_stat->nv_statname, stats_list[i].si_name,
2864*11878SVenu.Iyer@Sun.COM 		    sizeof (curr_stat->nv_statname));
2865*11878SVenu.Iyer@Sun.COM 		curr_stat->nv_statval = *val;
2866*11878SVenu.Iyer@Sun.COM 		curr_stat->nv_nextstat = NULL;
2867*11878SVenu.Iyer@Sun.COM 
2868*11878SVenu.Iyer@Sun.COM 		if (head_stat == NULL)	/* First node */
2869*11878SVenu.Iyer@Sun.COM 			head_stat = curr_stat;
2870*11878SVenu.Iyer@Sun.COM 		else
2871*11878SVenu.Iyer@Sun.COM 			prev_stat->nv_nextstat = curr_stat;
2872*11878SVenu.Iyer@Sun.COM 
2873*11878SVenu.Iyer@Sun.COM 		prev_stat = curr_stat;
2874*11878SVenu.Iyer@Sun.COM 	}
2875*11878SVenu.Iyer@Sun.COM 	return (head_stat);
2876*11878SVenu.Iyer@Sun.COM }
2877*11878SVenu.Iyer@Sun.COM 
2878*11878SVenu.Iyer@Sun.COM void *
build_nvs_entry(char * statheader,void * statentry,dladm_stat_type_t stattype)2879*11878SVenu.Iyer@Sun.COM build_nvs_entry(char *statheader, void *statentry, dladm_stat_type_t stattype)
2880*11878SVenu.Iyer@Sun.COM {
2881*11878SVenu.Iyer@Sun.COM 	name_value_stat_entry_t	*name_value_stat_entry;
2882*11878SVenu.Iyer@Sun.COM 	dladm_stat_desc_t	*stattbl_ptr;
2883*11878SVenu.Iyer@Sun.COM 	void			*statfields;
2884*11878SVenu.Iyer@Sun.COM 
2885*11878SVenu.Iyer@Sun.COM 	stattbl_ptr = &dladm_stat_table[stattype];
2886*11878SVenu.Iyer@Sun.COM 
2887*11878SVenu.Iyer@Sun.COM 	/* Allocate memory for query all stat entry */
2888*11878SVenu.Iyer@Sun.COM 	name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
2889*11878SVenu.Iyer@Sun.COM 	if (name_value_stat_entry == NULL)
2890*11878SVenu.Iyer@Sun.COM 		goto done;
2891*11878SVenu.Iyer@Sun.COM 
2892*11878SVenu.Iyer@Sun.COM 	/* Header for these stat fields */
2893*11878SVenu.Iyer@Sun.COM 	(void) strlcpy(name_value_stat_entry->nve_header, statheader,
2894*11878SVenu.Iyer@Sun.COM 	    sizeof (name_value_stat_entry->nve_header));
2895*11878SVenu.Iyer@Sun.COM 
2896*11878SVenu.Iyer@Sun.COM 	/* Extract stat fields from the statentry */
2897*11878SVenu.Iyer@Sun.COM 	statfields = (uchar_t *)statentry +
2898*11878SVenu.Iyer@Sun.COM 	    dladm_stat_table[stattype].ds_offset;
2899*11878SVenu.Iyer@Sun.COM 
2900*11878SVenu.Iyer@Sun.COM 	/* Convert curr_stat to <statname, statval> pair */
2901*11878SVenu.Iyer@Sun.COM 	name_value_stat_entry->nve_stats =
2902*11878SVenu.Iyer@Sun.COM 	    i_dlstat_convert_stats(statfields,
2903*11878SVenu.Iyer@Sun.COM 	    stattbl_ptr->ds_statlist, stattbl_ptr->ds_statsize);
2904*11878SVenu.Iyer@Sun.COM done:
2905*11878SVenu.Iyer@Sun.COM 	return (name_value_stat_entry);
2906*11878SVenu.Iyer@Sun.COM }
2907*11878SVenu.Iyer@Sun.COM 
2908*11878SVenu.Iyer@Sun.COM void *
i_walk_dlstat_chain(dladm_stat_chain_t * stat_head,dladm_stat_type_t stattype)2909*11878SVenu.Iyer@Sun.COM i_walk_dlstat_chain(dladm_stat_chain_t *stat_head, dladm_stat_type_t stattype)
2910*11878SVenu.Iyer@Sun.COM {
2911*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*curr;
2912*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*nvstat_head = NULL, *nvstat_prev = NULL;
2913*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*nvstat_curr;
2914*11878SVenu.Iyer@Sun.COM 
2915*11878SVenu.Iyer@Sun.COM 	/*
2916*11878SVenu.Iyer@Sun.COM 	 * For every stat in the chain, build header and convert all
2917*11878SVenu.Iyer@Sun.COM 	 * its stat fields
2918*11878SVenu.Iyer@Sun.COM 	 */
2919*11878SVenu.Iyer@Sun.COM 	for (curr = stat_head; curr != NULL; curr = curr->dc_next) {
2920*11878SVenu.Iyer@Sun.COM 		nvstat_curr = malloc(sizeof (dladm_stat_chain_t));
2921*11878SVenu.Iyer@Sun.COM 		if (nvstat_curr == NULL)
2922*11878SVenu.Iyer@Sun.COM 			break;
2923*11878SVenu.Iyer@Sun.COM 
2924*11878SVenu.Iyer@Sun.COM 		nvstat_curr->dc_statentry = build_nvs_entry(curr->dc_statheader,
2925*11878SVenu.Iyer@Sun.COM 		    curr->dc_statentry, stattype);
2926*11878SVenu.Iyer@Sun.COM 
2927*11878SVenu.Iyer@Sun.COM 		if (nvstat_curr->dc_statentry == NULL) {
2928*11878SVenu.Iyer@Sun.COM 			free(nvstat_curr);
2929*11878SVenu.Iyer@Sun.COM 			break;
2930*11878SVenu.Iyer@Sun.COM 		}
2931*11878SVenu.Iyer@Sun.COM 
2932*11878SVenu.Iyer@Sun.COM 		nvstat_curr->dc_next = NULL;
2933*11878SVenu.Iyer@Sun.COM 
2934*11878SVenu.Iyer@Sun.COM 		if (nvstat_head == NULL)	/* First node */
2935*11878SVenu.Iyer@Sun.COM 			nvstat_head = nvstat_curr;
2936*11878SVenu.Iyer@Sun.COM 		else
2937*11878SVenu.Iyer@Sun.COM 			nvstat_prev->dc_next = nvstat_curr;
2938*11878SVenu.Iyer@Sun.COM 
2939*11878SVenu.Iyer@Sun.COM 		nvstat_prev = nvstat_curr;
2940*11878SVenu.Iyer@Sun.COM 	}
2941*11878SVenu.Iyer@Sun.COM done:
2942*11878SVenu.Iyer@Sun.COM 	return (nvstat_head);
2943*11878SVenu.Iyer@Sun.COM }
2944*11878SVenu.Iyer@Sun.COM 
2945*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *
dladm_link_stat_query_all(dladm_handle_t dh,datalink_id_t linkid,dladm_stat_type_t stattype)2946*11878SVenu.Iyer@Sun.COM dladm_link_stat_query_all(dladm_handle_t dh, datalink_id_t linkid,
2947*11878SVenu.Iyer@Sun.COM     dladm_stat_type_t stattype)
2948*11878SVenu.Iyer@Sun.COM {
2949*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*stat_head;
2950*11878SVenu.Iyer@Sun.COM 	dladm_stat_chain_t	*nvstat_head = NULL;
2951*11878SVenu.Iyer@Sun.COM 
2952*11878SVenu.Iyer@Sun.COM 	/* Query the requested stat */
2953*11878SVenu.Iyer@Sun.COM 	stat_head = dladm_link_stat_query(dh, linkid, stattype);
2954*11878SVenu.Iyer@Sun.COM 	if (stat_head == NULL)
2955*11878SVenu.Iyer@Sun.COM 		goto done;
2956*11878SVenu.Iyer@Sun.COM 
2957*11878SVenu.Iyer@Sun.COM 	/*
2958*11878SVenu.Iyer@Sun.COM 	 * Convert every statfield in every stat-entry of stat chain to
2959*11878SVenu.Iyer@Sun.COM 	 * <statname, statval> pair
2960*11878SVenu.Iyer@Sun.COM 	 */
2961*11878SVenu.Iyer@Sun.COM 	nvstat_head = i_walk_dlstat_chain(stat_head, stattype);
2962*11878SVenu.Iyer@Sun.COM 
2963*11878SVenu.Iyer@Sun.COM 	/* Free stat_head */
2964*11878SVenu.Iyer@Sun.COM 	dladm_link_stat_free(stat_head);
2965*11878SVenu.Iyer@Sun.COM 
2966*11878SVenu.Iyer@Sun.COM done:
2967*11878SVenu.Iyer@Sun.COM 	return (nvstat_head);
2968*11878SVenu.Iyer@Sun.COM }
2969*11878SVenu.Iyer@Sun.COM 
2970*11878SVenu.Iyer@Sun.COM void
dladm_link_stat_query_all_free(dladm_stat_chain_t * curr)2971*11878SVenu.Iyer@Sun.COM dladm_link_stat_query_all_free(dladm_stat_chain_t *curr)
2972*11878SVenu.Iyer@Sun.COM {
2973*11878SVenu.Iyer@Sun.COM 	while (curr != NULL) {
2974*11878SVenu.Iyer@Sun.COM 		dladm_stat_chain_t	*tofree = curr;
2975*11878SVenu.Iyer@Sun.COM 		name_value_stat_entry_t	*nv_entry = curr->dc_statentry;
2976*11878SVenu.Iyer@Sun.COM 		name_value_stat_t	*nv_curr = nv_entry->nve_stats;
2977*11878SVenu.Iyer@Sun.COM 
2978*11878SVenu.Iyer@Sun.COM 		while (nv_curr != NULL) {
2979*11878SVenu.Iyer@Sun.COM 			name_value_stat_t	*nv_tofree = nv_curr;
2980*11878SVenu.Iyer@Sun.COM 
2981*11878SVenu.Iyer@Sun.COM 			nv_curr = nv_curr->nv_nextstat;
2982*11878SVenu.Iyer@Sun.COM 			free(nv_tofree);
2983*11878SVenu.Iyer@Sun.COM 		}
2984*11878SVenu.Iyer@Sun.COM 
2985*11878SVenu.Iyer@Sun.COM 		curr = curr->dc_next;
2986*11878SVenu.Iyer@Sun.COM 		free(nv_entry);
2987*11878SVenu.Iyer@Sun.COM 		free(tofree);
2988*11878SVenu.Iyer@Sun.COM 	}
2989*11878SVenu.Iyer@Sun.COM }
2990*11878SVenu.Iyer@Sun.COM 
2991*11878SVenu.Iyer@Sun.COM /* flow stats specific routines */
2992*11878SVenu.Iyer@Sun.COM flow_stat_t *
dladm_flow_stat_query(const char * flowname)2993*11878SVenu.Iyer@Sun.COM dladm_flow_stat_query(const char *flowname)
2994*11878SVenu.Iyer@Sun.COM {
2995*11878SVenu.Iyer@Sun.COM 	kstat_ctl_t	*kcp;
2996*11878SVenu.Iyer@Sun.COM 	kstat_t		*ksp;
2997*11878SVenu.Iyer@Sun.COM 	flow_stat_t	*flow_stat = NULL;
2998*11878SVenu.Iyer@Sun.COM 
2999*11878SVenu.Iyer@Sun.COM 	if ((kcp = kstat_open()) == NULL)
3000*11878SVenu.Iyer@Sun.COM 		return (NULL);
3001*11878SVenu.Iyer@Sun.COM 
3002*11878SVenu.Iyer@Sun.COM 	flow_stat = calloc(1, sizeof (flow_stat_t));
3003*11878SVenu.Iyer@Sun.COM 	if (flow_stat == NULL)
3004*11878SVenu.Iyer@Sun.COM 		goto done;
3005*11878SVenu.Iyer@Sun.COM 
3006*11878SVenu.Iyer@Sun.COM 	ksp = dladm_kstat_lookup(kcp, NULL, -1, flowname, "flow");
3007*11878SVenu.Iyer@Sun.COM 
3008*11878SVenu.Iyer@Sun.COM 	if (ksp != NULL) {
3009*11878SVenu.Iyer@Sun.COM 		i_dlstat_get_stats(kcp, ksp, flow_stat, flow_stats_list,
3010*11878SVenu.Iyer@Sun.COM 		    FLOW_STAT_SIZE);
3011*11878SVenu.Iyer@Sun.COM 	}
3012*11878SVenu.Iyer@Sun.COM 
3013*11878SVenu.Iyer@Sun.COM done:
3014*11878SVenu.Iyer@Sun.COM 	(void) kstat_close(kcp);
3015*11878SVenu.Iyer@Sun.COM 	return (flow_stat);
3016*11878SVenu.Iyer@Sun.COM }
3017*11878SVenu.Iyer@Sun.COM 
3018*11878SVenu.Iyer@Sun.COM flow_stat_t *
dladm_flow_stat_diff(flow_stat_t * op1,flow_stat_t * op2)3019*11878SVenu.Iyer@Sun.COM dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2)
3020*11878SVenu.Iyer@Sun.COM {
3021*11878SVenu.Iyer@Sun.COM 	flow_stat_t	*diff_stat;
3022*11878SVenu.Iyer@Sun.COM 
3023*11878SVenu.Iyer@Sun.COM 	diff_stat = calloc(1, sizeof (flow_stat_t));
3024*11878SVenu.Iyer@Sun.COM 	if (diff_stat == NULL)
3025*11878SVenu.Iyer@Sun.COM 		goto done;
3026*11878SVenu.Iyer@Sun.COM 
3027*11878SVenu.Iyer@Sun.COM 	if (op2 == NULL) {
3028*11878SVenu.Iyer@Sun.COM 		bcopy(op1, diff_stat, sizeof (flow_stat_t));
3029*11878SVenu.Iyer@Sun.COM 	} else {
3030*11878SVenu.Iyer@Sun.COM 		i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list,
3031*11878SVenu.Iyer@Sun.COM 		    FLOW_STAT_SIZE);
3032*11878SVenu.Iyer@Sun.COM 	}
3033*11878SVenu.Iyer@Sun.COM done:
3034*11878SVenu.Iyer@Sun.COM 	return (diff_stat);
3035*11878SVenu.Iyer@Sun.COM }
3036*11878SVenu.Iyer@Sun.COM 
3037*11878SVenu.Iyer@Sun.COM void
dladm_flow_stat_free(flow_stat_t * curr)3038*11878SVenu.Iyer@Sun.COM dladm_flow_stat_free(flow_stat_t *curr)
3039*11878SVenu.Iyer@Sun.COM {
3040*11878SVenu.Iyer@Sun.COM 	free(curr);
3041*11878SVenu.Iyer@Sun.COM }
3042*11878SVenu.Iyer@Sun.COM 
3043*11878SVenu.Iyer@Sun.COM /* Query all flow stats */
3044*11878SVenu.Iyer@Sun.COM name_value_stat_entry_t *
dladm_flow_stat_query_all(const char * flowname)3045*11878SVenu.Iyer@Sun.COM dladm_flow_stat_query_all(const char *flowname)
3046*11878SVenu.Iyer@Sun.COM {
3047*11878SVenu.Iyer@Sun.COM 	flow_stat_t		*flow_stat;
3048*11878SVenu.Iyer@Sun.COM 	name_value_stat_entry_t	*name_value_stat_entry = NULL;
3049*11878SVenu.Iyer@Sun.COM 
3050*11878SVenu.Iyer@Sun.COM 	/* Query flow stats */
3051*11878SVenu.Iyer@Sun.COM 	flow_stat =  dladm_flow_stat_query(flowname);
3052*11878SVenu.Iyer@Sun.COM 	if (flow_stat == NULL)
3053*11878SVenu.Iyer@Sun.COM 		goto done;
3054*11878SVenu.Iyer@Sun.COM 
3055*11878SVenu.Iyer@Sun.COM 	/* Allocate memory for query all stat entry */
3056*11878SVenu.Iyer@Sun.COM 	name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
3057*11878SVenu.Iyer@Sun.COM 	if (name_value_stat_entry == NULL) {
3058*11878SVenu.Iyer@Sun.COM 		dladm_flow_stat_free(flow_stat);
3059*11878SVenu.Iyer@Sun.COM 		goto done;
3060*11878SVenu.Iyer@Sun.COM 	}
3061*11878SVenu.Iyer@Sun.COM 
3062*11878SVenu.Iyer@Sun.COM 	/* Header for these stat fields */
3063*11878SVenu.Iyer@Sun.COM 	(void) strncpy(name_value_stat_entry->nve_header, flowname,
3064*11878SVenu.Iyer@Sun.COM 	    MAXFLOWNAMELEN);
3065*11878SVenu.Iyer@Sun.COM 
3066*11878SVenu.Iyer@Sun.COM 	/* Convert every statfield in flow_stat to <statname, statval> pair */
3067*11878SVenu.Iyer@Sun.COM 	name_value_stat_entry->nve_stats =
3068*11878SVenu.Iyer@Sun.COM 	    i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE);
3069*11878SVenu.Iyer@Sun.COM 
3070*11878SVenu.Iyer@Sun.COM 	/* Free flow_stat */
3071*11878SVenu.Iyer@Sun.COM 	dladm_flow_stat_free(flow_stat);
3072*11878SVenu.Iyer@Sun.COM 
3073*11878SVenu.Iyer@Sun.COM done:
3074*11878SVenu.Iyer@Sun.COM 	return (name_value_stat_entry);
3075*11878SVenu.Iyer@Sun.COM }
3076*11878SVenu.Iyer@Sun.COM 
3077*11878SVenu.Iyer@Sun.COM void
dladm_flow_stat_query_all_free(name_value_stat_entry_t * curr)3078*11878SVenu.Iyer@Sun.COM dladm_flow_stat_query_all_free(name_value_stat_entry_t *curr)
3079*11878SVenu.Iyer@Sun.COM {
3080*11878SVenu.Iyer@Sun.COM 	name_value_stat_t	*nv_curr = curr->nve_stats;
3081*11878SVenu.Iyer@Sun.COM 
3082*11878SVenu.Iyer@Sun.COM 	while (nv_curr != NULL) {
3083*11878SVenu.Iyer@Sun.COM 		name_value_stat_t	*nv_tofree = nv_curr;
3084*11878SVenu.Iyer@Sun.COM 
3085*11878SVenu.Iyer@Sun.COM 		nv_curr = nv_curr->nv_nextstat;
3086*11878SVenu.Iyer@Sun.COM 		free(nv_tofree);
3087*11878SVenu.Iyer@Sun.COM 	}
3088*11878SVenu.Iyer@Sun.COM }
3089