xref: /illumos-gate/usr/src/lib/libdladm/common/libdlstat.c (revision 4202e8bf1d88e8c78515b9b8f0386471afe2bf77)
1da14cebeSEric Cheng /*
2da14cebeSEric Cheng  * CDDL HEADER START
3da14cebeSEric Cheng  *
4da14cebeSEric Cheng  * The contents of this file are subject to the terms of the
5da14cebeSEric Cheng  * Common Development and Distribution License (the "License").
6da14cebeSEric Cheng  * You may not use this file except in compliance with the License.
7da14cebeSEric Cheng  *
8da14cebeSEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da14cebeSEric Cheng  * or http://www.opensolaris.org/os/licensing.
10da14cebeSEric Cheng  * See the License for the specific language governing permissions
11da14cebeSEric Cheng  * and limitations under the License.
12da14cebeSEric Cheng  *
13da14cebeSEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
14da14cebeSEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da14cebeSEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
16da14cebeSEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
17da14cebeSEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
18da14cebeSEric Cheng  *
19da14cebeSEric Cheng  * CDDL HEADER END
20da14cebeSEric Cheng  */
21da14cebeSEric Cheng /*
220dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23da14cebeSEric Cheng  * Use is subject to license terms.
24da14cebeSEric Cheng  */
25da14cebeSEric Cheng 
26399dcf08Scarlos antonio neira bustos /*
27399dcf08Scarlos antonio neira bustos  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
28399dcf08Scarlos antonio neira bustos  */
29399dcf08Scarlos antonio neira bustos 
3062ef8476SYuri Pankov #include <stddef.h>
31da14cebeSEric Cheng #include <stdio.h>
32da14cebeSEric Cheng #include <stdlib.h>
33da14cebeSEric Cheng #include <strings.h>
34da14cebeSEric Cheng #include <err.h>
35da14cebeSEric Cheng #include <errno.h>
36c3affd82SMichael Lim #include <fcntl.h>
37da14cebeSEric Cheng #include <kstat.h>
38c3affd82SMichael Lim #include <limits.h>
39da14cebeSEric Cheng #include <unistd.h>
40da14cebeSEric Cheng #include <signal.h>
41da14cebeSEric Cheng #include <sys/dld.h>
4282a2fc47SJames Carlson #include <sys/ddi.h>
43da14cebeSEric Cheng 
44da14cebeSEric Cheng #include <libdllink.h>
45da14cebeSEric Cheng #include <libdlflow.h>
46da14cebeSEric Cheng #include <libdlstat.h>
470dc2366fSVenugopal Iyer #include <libdlaggr.h>
48da14cebeSEric Cheng 
49da14cebeSEric Cheng struct flowlist {
50da000602SGirish Moodalbail 	char		flowname[MAXFLOWNAMELEN];
51c3affd82SMichael Lim 	char		linkname[MAXLINKNAMELEN];
52da14cebeSEric Cheng 	datalink_id_t	linkid;
53c3affd82SMichael Lim 	int		fd;
54285e94f9SMichael Lim 	uint64_t	ifspeed;
55da14cebeSEric Cheng 	boolean_t	first;
56da14cebeSEric Cheng 	boolean_t	display;
57da14cebeSEric Cheng 	pktsum_t	prevstats;
58da14cebeSEric Cheng 	pktsum_t	diffstats;
59da14cebeSEric Cheng };
60da14cebeSEric Cheng 
61da14cebeSEric Cheng pktsum_t		totalstats;
62da14cebeSEric Cheng struct flowlist		*stattable = NULL;
63da14cebeSEric Cheng 
64da14cebeSEric Cheng #define	STATGROWSIZE	16
65da14cebeSEric Cheng 
66da14cebeSEric Cheng /* Exported functions */
67da14cebeSEric Cheng 
68da14cebeSEric Cheng /*
69da14cebeSEric Cheng  * dladm_kstat_lookup() is a modified version of kstat_lookup which
70da14cebeSEric Cheng  * adds the class as a selector.
71da14cebeSEric Cheng  */
72da14cebeSEric Cheng kstat_t *
dladm_kstat_lookup(kstat_ctl_t * kcp,const char * module,int instance,const char * name,const char * class)73da14cebeSEric Cheng dladm_kstat_lookup(kstat_ctl_t *kcp, const char *module, int instance,
74da14cebeSEric Cheng     const char *name, const char *class)
75da14cebeSEric Cheng {
76da14cebeSEric Cheng 	kstat_t *ksp = NULL;
77da14cebeSEric Cheng 
78da14cebeSEric Cheng 	for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
79da14cebeSEric Cheng 		if ((module == NULL || strcmp(ksp->ks_module, module) == 0) &&
80da14cebeSEric Cheng 		    (instance == -1 || ksp->ks_instance == instance) &&
81da14cebeSEric Cheng 		    (name == NULL || strcmp(ksp->ks_name, name) == 0) &&
82da14cebeSEric Cheng 		    (class == NULL || strcmp(ksp->ks_class, class) == 0))
83da14cebeSEric Cheng 			return (ksp);
84da14cebeSEric Cheng 	}
85da14cebeSEric Cheng 
86da14cebeSEric Cheng 	errno = ENOENT;
87da14cebeSEric Cheng 	return (NULL);
88da14cebeSEric Cheng }
89da14cebeSEric Cheng 
90da14cebeSEric Cheng /*
91da14cebeSEric Cheng  * dladm_get_stats() populates the supplied pktsum_t structure with
92da14cebeSEric Cheng  * the input and output  packet and byte kstats from the kstat_t
93da14cebeSEric Cheng  * found with dladm_kstat_lookup.
94da14cebeSEric Cheng  */
95da14cebeSEric Cheng void
dladm_get_stats(kstat_ctl_t * kcp,kstat_t * ksp,pktsum_t * stats)96da14cebeSEric Cheng dladm_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, pktsum_t *stats)
97da14cebeSEric Cheng {
98da14cebeSEric Cheng 
99da14cebeSEric Cheng 	if (kstat_read(kcp, ksp, NULL) == -1)
100da14cebeSEric Cheng 		return;
101da14cebeSEric Cheng 
102da14cebeSEric Cheng 	stats->snaptime = gethrtime();
103da14cebeSEric Cheng 
104da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64,
105da14cebeSEric Cheng 	    &stats->ipackets) < 0) {
106da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "ipackets", KSTAT_DATA_UINT64,
107da14cebeSEric Cheng 		    &stats->ipackets) < 0)
108da14cebeSEric Cheng 			return;
109da14cebeSEric Cheng 	}
110da14cebeSEric Cheng 
111da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64,
112da14cebeSEric Cheng 	    &stats->opackets) < 0) {
113da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "opackets", KSTAT_DATA_UINT64,
114da14cebeSEric Cheng 		    &stats->opackets) < 0)
115da14cebeSEric Cheng 			return;
116da14cebeSEric Cheng 	}
117da14cebeSEric Cheng 
118da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64,
119da14cebeSEric Cheng 	    &stats->rbytes) < 0) {
120da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "rbytes", KSTAT_DATA_UINT64,
121da14cebeSEric Cheng 		    &stats->rbytes) < 0)
122da14cebeSEric Cheng 			return;
123da14cebeSEric Cheng 	}
124da14cebeSEric Cheng 
125da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64,
126da14cebeSEric Cheng 	    &stats->obytes) < 0) {
127da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "obytes", KSTAT_DATA_UINT64,
128da14cebeSEric Cheng 		    &stats->obytes) < 0)
129da14cebeSEric Cheng 			return;
130da14cebeSEric Cheng 	}
131da14cebeSEric Cheng 
132da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32,
133da14cebeSEric Cheng 	    &stats->ierrors) < 0) {
134da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT64,
135da14cebeSEric Cheng 		    &stats->ierrors) < 0)
136da14cebeSEric Cheng 		return;
137da14cebeSEric Cheng 	}
138da14cebeSEric Cheng 
139da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32,
140da14cebeSEric Cheng 	    &stats->oerrors) < 0) {
141da14cebeSEric Cheng 		if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT64,
142da14cebeSEric Cheng 		    &stats->oerrors) < 0)
143da14cebeSEric Cheng 			return;
144da14cebeSEric Cheng 	}
145da14cebeSEric Cheng }
146da14cebeSEric Cheng 
147da14cebeSEric Cheng int
dladm_kstat_value(kstat_t * ksp,const char * name,uint8_t type,void * buf)148da14cebeSEric Cheng dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf)
149da14cebeSEric Cheng {
150da14cebeSEric Cheng 	kstat_named_t	*knp;
151da14cebeSEric Cheng 
152da14cebeSEric Cheng 	if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL)
153da14cebeSEric Cheng 		return (-1);
154da14cebeSEric Cheng 
155da14cebeSEric Cheng 	if (knp->data_type != type)
156da14cebeSEric Cheng 		return (-1);
157da14cebeSEric Cheng 
158da14cebeSEric Cheng 	switch (type) {
159da14cebeSEric Cheng 	case KSTAT_DATA_UINT64:
160da14cebeSEric Cheng 		*(uint64_t *)buf = knp->value.ui64;
161da14cebeSEric Cheng 		break;
162da14cebeSEric Cheng 	case KSTAT_DATA_UINT32:
163da14cebeSEric Cheng 		*(uint32_t *)buf = knp->value.ui32;
164da14cebeSEric Cheng 		break;
165da14cebeSEric Cheng 	default:
166da14cebeSEric Cheng 		return (-1);
167da14cebeSEric Cheng 	}
168da14cebeSEric Cheng 
169da14cebeSEric Cheng 	return (0);
170da14cebeSEric Cheng }
171da14cebeSEric Cheng 
172da14cebeSEric 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)1734ac67f02SAnurag S. Maskey dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid,
1744ac67f02SAnurag S. Maskey     const char *name, uint8_t type, void *val)
175da14cebeSEric Cheng {
176da14cebeSEric Cheng 	char		module[DLPI_LINKNAME_MAX];
177da14cebeSEric Cheng 	uint_t		instance;
178da14cebeSEric Cheng 	char		link[DLPI_LINKNAME_MAX];
179da14cebeSEric Cheng 	dladm_status_t	status;
180da14cebeSEric Cheng 	uint32_t	flags, media;
181da14cebeSEric Cheng 	kstat_t		*ksp;
182da14cebeSEric Cheng 	dladm_phys_attr_t dpap;
183da14cebeSEric Cheng 
1844ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
1854ac67f02SAnurag S. Maskey 	    &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK)
186da14cebeSEric Cheng 		return (status);
187da14cebeSEric Cheng 
188da14cebeSEric Cheng 	if (media != DL_ETHER)
189da14cebeSEric Cheng 		return (DLADM_STATUS_LINKINVAL);
190da14cebeSEric Cheng 
1914ac67f02SAnurag S. Maskey 	status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST);
192da14cebeSEric Cheng 
193da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
194da14cebeSEric Cheng 		return (status);
195da14cebeSEric Cheng 
196da14cebeSEric Cheng 	status = dladm_parselink(dpap.dp_dev, module, &instance);
197da14cebeSEric Cheng 
198da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
199da14cebeSEric Cheng 		return (status);
200da14cebeSEric Cheng 
201da14cebeSEric Cheng 	/*
202da14cebeSEric Cheng 	 * The kstat query could fail if the underlying MAC
203da14cebeSEric Cheng 	 * driver was already detached.
204da14cebeSEric Cheng 	 */
205399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(handle) == NULL) {
206399dcf08Scarlos antonio neira bustos 		warn("kstat_open operation failed");
207399dcf08Scarlos antonio neira bustos 		return (-1);
208399dcf08Scarlos antonio neira bustos 	}
209da14cebeSEric Cheng 
210399dcf08Scarlos antonio neira bustos 	if ((ksp = kstat_lookup(dladm_dld_kcp(handle), module, instance,
211399dcf08Scarlos antonio neira bustos 	    "mac")) == NULL &&
212399dcf08Scarlos antonio neira bustos 	    (ksp = kstat_lookup(dladm_dld_kcp(handle), module, instance,
213399dcf08Scarlos antonio neira bustos 	    NULL)) == NULL) {
214399dcf08Scarlos antonio neira bustos 		goto bail;
215399dcf08Scarlos antonio neira bustos 	}
216399dcf08Scarlos antonio neira bustos 
217399dcf08Scarlos antonio neira bustos 	if (kstat_read(dladm_dld_kcp(handle), ksp, NULL) == -1)
218da14cebeSEric Cheng 		goto bail;
219da14cebeSEric Cheng 
220da14cebeSEric Cheng 	if (dladm_kstat_value(ksp, name, type, val) < 0)
221da14cebeSEric Cheng 		goto bail;
222da14cebeSEric Cheng 
223da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
224da14cebeSEric Cheng 
225da14cebeSEric Cheng bail:
226da14cebeSEric Cheng 	return (dladm_errno2status(errno));
227da14cebeSEric Cheng }
228da14cebeSEric Cheng 
229da14cebeSEric Cheng /* Compute sum of 2 pktsums (s1 = s2 + s3) */
230da14cebeSEric Cheng void
dladm_stats_total(pktsum_t * s1,pktsum_t * s2,pktsum_t * s3)231da14cebeSEric Cheng dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
232da14cebeSEric Cheng {
233da14cebeSEric Cheng 	s1->rbytes    = s2->rbytes    + s3->rbytes;
234da14cebeSEric Cheng 	s1->ipackets  = s2->ipackets  + s3->ipackets;
235da14cebeSEric Cheng 	s1->ierrors   = s2->ierrors   + s3->ierrors;
236da14cebeSEric Cheng 	s1->obytes    = s2->obytes    + s3->obytes;
237da14cebeSEric Cheng 	s1->opackets  = s2->opackets  + s3->opackets;
238da14cebeSEric Cheng 	s1->oerrors   = s2->oerrors   + s3->oerrors;
239da14cebeSEric Cheng 	s1->snaptime  = s2->snaptime;
240da14cebeSEric Cheng }
241da14cebeSEric Cheng 
2420dc2366fSVenugopal Iyer #define	DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0)
2432d40c3b2SPrakash Jalan 
2442d40c3b2SPrakash Jalan 
245da14cebeSEric Cheng /* Compute differences between 2 pktsums (s1 = s2 - s3) */
246da14cebeSEric Cheng void
dladm_stats_diff(pktsum_t * s1,pktsum_t * s2,pktsum_t * s3)247da14cebeSEric Cheng dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
248da14cebeSEric Cheng {
2492d40c3b2SPrakash Jalan 	s1->rbytes    = DIFF_STAT(s2->rbytes,   s3->rbytes);
2502d40c3b2SPrakash Jalan 	s1->ipackets  = DIFF_STAT(s2->ipackets, s3->ipackets);
2512d40c3b2SPrakash Jalan 	s1->ierrors   = DIFF_STAT(s2->ierrors,  s3->ierrors);
2522d40c3b2SPrakash Jalan 	s1->obytes    = DIFF_STAT(s2->obytes,   s3->obytes);
2532d40c3b2SPrakash Jalan 	s1->opackets  = DIFF_STAT(s2->opackets, s3->opackets);
2542d40c3b2SPrakash Jalan 	s1->oerrors   = DIFF_STAT(s2->oerrors,  s3->oerrors);
2552d40c3b2SPrakash Jalan 	s1->snaptime  = DIFF_STAT(s2->snaptime, s3->snaptime);
256da14cebeSEric Cheng }
2570dc2366fSVenugopal Iyer 
2580dc2366fSVenugopal Iyer #define	DLSTAT_MAC_RX_SWLANE	"mac_rx_swlane"
2590dc2366fSVenugopal Iyer #define	DLSTAT_MAC_RX_HWLANE	"mac_rx_hwlane"
2600dc2366fSVenugopal Iyer #define	DLSTAT_MAC_TX_SWLANE	"mac_tx_swlane"
2610dc2366fSVenugopal Iyer #define	DLSTAT_MAC_TX_HWLANE	"mac_tx_hwlane"
2620dc2366fSVenugopal Iyer #define	DLSTAT_MAC_MISC_STAT	"mac_misc_stat"
2630dc2366fSVenugopal Iyer #define	DLSTAT_MAC_RX_RING	"mac_rx_ring"
2640dc2366fSVenugopal Iyer #define	DLSTAT_MAC_TX_RING	"mac_tx_ring"
2650dc2366fSVenugopal Iyer #define	DLSTAT_MAC_FANOUT	"mac_rx_swlane0_fanout"
2660dc2366fSVenugopal Iyer 
2670dc2366fSVenugopal Iyer typedef struct {
2680dc2366fSVenugopal Iyer 	const char	*si_name;
2690dc2366fSVenugopal Iyer 	uint_t		si_offset;
2700dc2366fSVenugopal Iyer } stat_info_t;
2710dc2366fSVenugopal Iyer 
2720dc2366fSVenugopal Iyer #define	A_CNT(arr)	(sizeof (arr) / sizeof (arr[0]))
2730dc2366fSVenugopal Iyer 
2740dc2366fSVenugopal Iyer /* Definitions for rx lane stats */
2750dc2366fSVenugopal Iyer #define	RL_OFF(f)	(offsetof(rx_lane_stat_t, f))
2760dc2366fSVenugopal Iyer 
2770dc2366fSVenugopal Iyer static	stat_info_t	rx_hwlane_stats_list[] = {
2780dc2366fSVenugopal Iyer 	{"ipackets",		RL_OFF(rl_ipackets)},
2790dc2366fSVenugopal Iyer 	{"rbytes",		RL_OFF(rl_rbytes)},
2800dc2366fSVenugopal Iyer 	{"intrs",		RL_OFF(rl_intrs)},
2810dc2366fSVenugopal Iyer 	{"intrbytes",		RL_OFF(rl_intrbytes)},
2820dc2366fSVenugopal Iyer 	{"polls",		RL_OFF(rl_polls)},
2830dc2366fSVenugopal Iyer 	{"pollbytes",		RL_OFF(rl_pollbytes)},
2840dc2366fSVenugopal Iyer 	{"rxsdrops",		RL_OFF(rl_sdrops)},
2850dc2366fSVenugopal Iyer 	{"chainunder10",	RL_OFF(rl_chl10)},
2860dc2366fSVenugopal Iyer 	{"chain10to50",		RL_OFF(rl_ch10_50)},
2870dc2366fSVenugopal Iyer 	{"chainover50",		RL_OFF(rl_chg50)}
2880dc2366fSVenugopal Iyer };
2890dc2366fSVenugopal Iyer #define	RX_HWLANE_STAT_SIZE	A_CNT(rx_hwlane_stats_list)
2900dc2366fSVenugopal Iyer 
2910dc2366fSVenugopal Iyer static	stat_info_t	rx_swlane_stats_list[] = {
2920dc2366fSVenugopal Iyer 	{"ipackets",		RL_OFF(rl_ipackets)},
2930dc2366fSVenugopal Iyer 	{"rbytes",		RL_OFF(rl_rbytes)},
2940dc2366fSVenugopal Iyer 	{"local",		RL_OFF(rl_lclpackets)},
2950dc2366fSVenugopal Iyer 	{"localbytes",		RL_OFF(rl_lclbytes)},
2960dc2366fSVenugopal Iyer 	{"intrs",		RL_OFF(rl_intrs)},
2970dc2366fSVenugopal Iyer 	{"intrbytes",		RL_OFF(rl_intrbytes)},
2980dc2366fSVenugopal Iyer 	{"rxsdrops",		RL_OFF(rl_sdrops)}
2990dc2366fSVenugopal Iyer };
3000dc2366fSVenugopal Iyer #define	RX_SWLANE_STAT_SIZE	A_CNT(rx_swlane_stats_list)
3010dc2366fSVenugopal Iyer 
3020dc2366fSVenugopal Iyer static	stat_info_t	rx_lane_stats_list[] = {
3030dc2366fSVenugopal Iyer 	{"ipackets",		RL_OFF(rl_ipackets)},
3040dc2366fSVenugopal Iyer 	{"rbytes",		RL_OFF(rl_rbytes)},
3050dc2366fSVenugopal Iyer 	{"local",		RL_OFF(rl_lclpackets)},
3060dc2366fSVenugopal Iyer 	{"localbytes",		RL_OFF(rl_lclbytes)},
3070dc2366fSVenugopal Iyer 	{"intrs",		RL_OFF(rl_intrs)},
3080dc2366fSVenugopal Iyer 	{"intrbytes",		RL_OFF(rl_intrbytes)},
3090dc2366fSVenugopal Iyer 	{"polls",		RL_OFF(rl_polls)},
3100dc2366fSVenugopal Iyer 	{"rxsdrops",		RL_OFF(rl_sdrops)},
3110dc2366fSVenugopal Iyer 	{"pollbytes",		RL_OFF(rl_pollbytes)},
3120dc2366fSVenugopal Iyer 	{"chainunder10",	RL_OFF(rl_chl10)},
3130dc2366fSVenugopal Iyer 	{"chain10to50",		RL_OFF(rl_ch10_50)},
3140dc2366fSVenugopal Iyer 	{"chainover50",		RL_OFF(rl_chg50)}
3150dc2366fSVenugopal Iyer };
3160dc2366fSVenugopal Iyer #define	RX_LANE_STAT_SIZE	A_CNT(rx_lane_stats_list)
3170dc2366fSVenugopal Iyer 
3180dc2366fSVenugopal Iyer /* Definitions for tx lane stats */
3190dc2366fSVenugopal Iyer #define	TL_OFF(f)	(offsetof(tx_lane_stat_t, f))
3200dc2366fSVenugopal Iyer 
3210dc2366fSVenugopal Iyer static	stat_info_t	tx_lane_stats_list[] = {
3220dc2366fSVenugopal Iyer 	{"opackets",	TL_OFF(tl_opackets)},
3230dc2366fSVenugopal Iyer 	{"obytes",	TL_OFF(tl_obytes)},
3240dc2366fSVenugopal Iyer 	{"blockcnt",	TL_OFF(tl_blockcnt)},
3250dc2366fSVenugopal Iyer 	{"unblockcnt",	TL_OFF(tl_unblockcnt)},
3260dc2366fSVenugopal Iyer 	{"txsdrops",	TL_OFF(tl_sdrops)}
3270dc2366fSVenugopal Iyer };
3280dc2366fSVenugopal Iyer #define	TX_LANE_STAT_SIZE	A_CNT(tx_lane_stats_list)
3290dc2366fSVenugopal Iyer 
3300dc2366fSVenugopal Iyer /* Definitions for tx/rx misc stats */
3310dc2366fSVenugopal Iyer #define	M_OFF(f)	(offsetof(misc_stat_t, f))
3320dc2366fSVenugopal Iyer 
3330dc2366fSVenugopal Iyer static	stat_info_t	misc_stats_list[] = {
3340dc2366fSVenugopal Iyer 	{"multircv",		M_OFF(ms_multircv)},
3350dc2366fSVenugopal Iyer 	{"brdcstrcv",		M_OFF(ms_brdcstrcv)},
3360dc2366fSVenugopal Iyer 	{"multixmt",		M_OFF(ms_multixmt)},
3370dc2366fSVenugopal Iyer 	{"brdcstxmt",		M_OFF(ms_brdcstxmt)},
3380dc2366fSVenugopal Iyer 	{"multircvbytes",	M_OFF(ms_multircvbytes)},
3390dc2366fSVenugopal Iyer 	{"brdcstrcvbytes",	M_OFF(ms_brdcstrcvbytes)},
3400dc2366fSVenugopal Iyer 	{"multixmtbytes",	M_OFF(ms_multixmtbytes)},
3410dc2366fSVenugopal Iyer 	{"brdcstxmtbytes",	M_OFF(ms_brdcstxmtbytes)},
3420dc2366fSVenugopal Iyer 	{"txerrors",		M_OFF(ms_txerrors)},
3430dc2366fSVenugopal Iyer 	{"macspoofed",		M_OFF(ms_macspoofed)},
3440dc2366fSVenugopal Iyer 	{"ipspoofed",		M_OFF(ms_ipspoofed)},
3450dc2366fSVenugopal Iyer 	{"dhcpspoofed",		M_OFF(ms_dhcpspoofed)},
3460dc2366fSVenugopal Iyer 	{"restricted",		M_OFF(ms_restricted)},
3470dc2366fSVenugopal Iyer 	{"ipackets",		M_OFF(ms_ipackets)},
3480dc2366fSVenugopal Iyer 	{"rbytes",		M_OFF(ms_rbytes)},
3490dc2366fSVenugopal Iyer 	{"local",		M_OFF(ms_local)},
3500dc2366fSVenugopal Iyer 	{"localbytes",		M_OFF(ms_localbytes)},
3510dc2366fSVenugopal Iyer 	{"intrs",		M_OFF(ms_intrs)},
3520dc2366fSVenugopal Iyer 	{"intrbytes",		M_OFF(ms_intrbytes)},
3530dc2366fSVenugopal Iyer 	{"polls",		M_OFF(ms_polls)},
3540dc2366fSVenugopal Iyer 	{"pollbytes",		M_OFF(ms_pollbytes)},
3550dc2366fSVenugopal Iyer 	{"rxsdrops",		M_OFF(ms_rxsdrops)},
3560dc2366fSVenugopal Iyer 	{"chainunder10",	M_OFF(ms_chainunder10)},
3570dc2366fSVenugopal Iyer 	{"chain10to50",		M_OFF(ms_chain10to50)},
3580dc2366fSVenugopal Iyer 	{"chainover50",		M_OFF(ms_chainover50)},
3590dc2366fSVenugopal Iyer 	{"obytes",		M_OFF(ms_obytes)},
3600dc2366fSVenugopal Iyer 	{"opackets",		M_OFF(ms_opackets)},
3610dc2366fSVenugopal Iyer 	{"blockcnt",		M_OFF(ms_blockcnt)},
3620dc2366fSVenugopal Iyer 	{"unblockcnt",		M_OFF(ms_unblockcnt)},
3630dc2366fSVenugopal Iyer 	{"txsdrops",		M_OFF(ms_txsdrops)}
3640dc2366fSVenugopal Iyer };
3650dc2366fSVenugopal Iyer #define	MISC_STAT_SIZE		A_CNT(misc_stats_list)
3660dc2366fSVenugopal Iyer 
3670dc2366fSVenugopal Iyer /* Definitions for rx ring stats */
3680dc2366fSVenugopal Iyer #define	R_OFF(f)	(offsetof(ring_stat_t, f))
3690dc2366fSVenugopal Iyer 
3700dc2366fSVenugopal Iyer static	stat_info_t	rx_ring_stats_list[] = {
3710dc2366fSVenugopal Iyer 	{"ipackets",	R_OFF(r_packets)},
3720dc2366fSVenugopal Iyer 	{"rbytes",	R_OFF(r_bytes)}
3730dc2366fSVenugopal Iyer };
3740dc2366fSVenugopal Iyer #define	RX_RING_STAT_SIZE	A_CNT(rx_ring_stats_list)
3750dc2366fSVenugopal Iyer 
3760dc2366fSVenugopal Iyer /* Definitions for tx ring stats */
3770dc2366fSVenugopal Iyer static	stat_info_t	tx_ring_stats_list[] = {
3780dc2366fSVenugopal Iyer 	{"opackets",	R_OFF(r_packets)},
3790dc2366fSVenugopal Iyer 	{"obytes",	R_OFF(r_bytes)}
3800dc2366fSVenugopal Iyer };
3810dc2366fSVenugopal Iyer #define	TX_RING_STAT_SIZE	A_CNT(tx_ring_stats_list)
3820dc2366fSVenugopal Iyer 
3830dc2366fSVenugopal Iyer /* Definitions for fanout stats */
3840dc2366fSVenugopal Iyer #define	F_OFF(f)	(offsetof(fanout_stat_t, f))
3850dc2366fSVenugopal Iyer 
3860dc2366fSVenugopal Iyer static	stat_info_t	fanout_stats_list[] = {
3870dc2366fSVenugopal Iyer 	{"ipackets",	F_OFF(f_ipackets)},
3880dc2366fSVenugopal Iyer 	{"rbytes",	F_OFF(f_rbytes)},
3890dc2366fSVenugopal Iyer };
3900dc2366fSVenugopal Iyer #define	FANOUT_STAT_SIZE	A_CNT(fanout_stats_list)
3910dc2366fSVenugopal Iyer 
3920dc2366fSVenugopal Iyer /* Definitions for total stats */
3930dc2366fSVenugopal Iyer #define	T_OFF(f)	(offsetof(total_stat_t, f))
3940dc2366fSVenugopal Iyer 
3950dc2366fSVenugopal Iyer static	stat_info_t	total_stats_list[] = {
3960dc2366fSVenugopal Iyer 	{"ipackets",	T_OFF(ts_ipackets)},
3970dc2366fSVenugopal Iyer 	{"rbytes",	T_OFF(ts_rbytes)},
3980dc2366fSVenugopal Iyer 	{"opackets",	T_OFF(ts_opackets)},
3990dc2366fSVenugopal Iyer 	{"obytes",	T_OFF(ts_obytes)}
4000dc2366fSVenugopal Iyer };
4010dc2366fSVenugopal Iyer #define	TOTAL_STAT_SIZE		A_CNT(total_stats_list)
4020dc2366fSVenugopal Iyer 
4030dc2366fSVenugopal Iyer /* Definitions for aggr stats */
4040dc2366fSVenugopal Iyer #define	AP_OFF(f)	(offsetof(aggr_port_stat_t, f))
4050dc2366fSVenugopal Iyer 
4060dc2366fSVenugopal Iyer static	stat_info_t	aggr_port_stats_list[] = {
4070dc2366fSVenugopal Iyer 	{"ipackets64",	AP_OFF(ap_ipackets)},
4080dc2366fSVenugopal Iyer 	{"rbytes64",	AP_OFF(ap_rbytes)},
4090dc2366fSVenugopal Iyer 	{"opackets64",	AP_OFF(ap_opackets)},
4100dc2366fSVenugopal Iyer 	{"obytes64",	AP_OFF(ap_obytes)}
4110dc2366fSVenugopal Iyer };
4120dc2366fSVenugopal Iyer #define	AGGR_PORT_STAT_SIZE	A_CNT(aggr_port_stats_list)
4130dc2366fSVenugopal Iyer 
4140dc2366fSVenugopal Iyer /* Definitions for flow stats */
4150dc2366fSVenugopal Iyer #define	FL_OFF(f)	(offsetof(flow_stat_t, f))
4160dc2366fSVenugopal Iyer 
4170dc2366fSVenugopal Iyer static	stat_info_t	flow_stats_list[] = {
4180dc2366fSVenugopal Iyer 	{"ipackets",	FL_OFF(fl_ipackets)},
4190dc2366fSVenugopal Iyer 	{"rbytes",	FL_OFF(fl_rbytes)},
4200dc2366fSVenugopal Iyer 	{"opackets",	FL_OFF(fl_opackets)},
4210dc2366fSVenugopal Iyer 	{"obytes",	FL_OFF(fl_obytes)}
4220dc2366fSVenugopal Iyer };
4230dc2366fSVenugopal Iyer #define	FLOW_STAT_SIZE		A_CNT(flow_stats_list)
4240dc2366fSVenugopal Iyer 
4250dc2366fSVenugopal Iyer /* Rx lane specific functions */
4260dc2366fSVenugopal Iyer void *			dlstat_rx_lane_stats(dladm_handle_t, datalink_id_t);
4270dc2366fSVenugopal Iyer static boolean_t	i_dlstat_rx_lane_match(void *, void *);
4280dc2366fSVenugopal Iyer static void *		i_dlstat_rx_lane_stat_entry_diff(void *, void *);
4290dc2366fSVenugopal Iyer 
4300dc2366fSVenugopal Iyer /* Tx lane specific functions */
4310dc2366fSVenugopal Iyer void *			dlstat_tx_lane_stats(dladm_handle_t, datalink_id_t);
4320dc2366fSVenugopal Iyer static boolean_t	i_dlstat_tx_lane_match(void *, void *);
4330dc2366fSVenugopal Iyer static void *		i_dlstat_tx_lane_stat_entry_diff(void *, void *);
4340dc2366fSVenugopal Iyer 
4350dc2366fSVenugopal Iyer /* Rx lane total specific functions */
4360dc2366fSVenugopal Iyer void *			dlstat_rx_lane_total_stats(dladm_handle_t,
4370dc2366fSVenugopal Iyer 			    datalink_id_t);
4380dc2366fSVenugopal Iyer 
4390dc2366fSVenugopal Iyer /* Tx lane total specific functions */
4400dc2366fSVenugopal Iyer void *			dlstat_tx_lane_total_stats(dladm_handle_t,
4410dc2366fSVenugopal Iyer 			    datalink_id_t);
4420dc2366fSVenugopal Iyer 
4430dc2366fSVenugopal Iyer /* Fanout specific functions */
4440dc2366fSVenugopal Iyer void *			dlstat_fanout_stats(dladm_handle_t, datalink_id_t);
4450dc2366fSVenugopal Iyer static boolean_t	i_dlstat_fanout_match(void *, void *);
4460dc2366fSVenugopal Iyer static void *		i_dlstat_fanout_stat_entry_diff(void *, void *);
4470dc2366fSVenugopal Iyer 
4480dc2366fSVenugopal Iyer /* Rx ring specific functions */
4490dc2366fSVenugopal Iyer void *			dlstat_rx_ring_stats(dladm_handle_t, datalink_id_t);
4500dc2366fSVenugopal Iyer static boolean_t	i_dlstat_rx_ring_match(void *, void *);
4510dc2366fSVenugopal Iyer static void *		i_dlstat_rx_ring_stat_entry_diff(void *, void *);
4520dc2366fSVenugopal Iyer 
4530dc2366fSVenugopal Iyer /* Tx ring specific functions */
4540dc2366fSVenugopal Iyer void *			dlstat_tx_ring_stats(dladm_handle_t, datalink_id_t);
4550dc2366fSVenugopal Iyer static boolean_t	i_dlstat_tx_ring_match(void *, void *);
4560dc2366fSVenugopal Iyer static void *		i_dlstat_tx_ring_stat_entry_diff(void *, void *);
4570dc2366fSVenugopal Iyer 
4580dc2366fSVenugopal Iyer /* Rx ring total specific functions */
4590dc2366fSVenugopal Iyer void *			dlstat_rx_ring_total_stats(dladm_handle_t,
4600dc2366fSVenugopal Iyer 			    datalink_id_t);
4610dc2366fSVenugopal Iyer 
4620dc2366fSVenugopal Iyer /* Tx ring total specific functions */
4630dc2366fSVenugopal Iyer void *			dlstat_tx_ring_total_stats(dladm_handle_t,
4640dc2366fSVenugopal Iyer 			    datalink_id_t);
4650dc2366fSVenugopal Iyer 
4660dc2366fSVenugopal Iyer /* Summary specific functions */
4670dc2366fSVenugopal Iyer void *			dlstat_total_stats(dladm_handle_t, datalink_id_t);
4680dc2366fSVenugopal Iyer static boolean_t	i_dlstat_total_match(void *, void *);
4690dc2366fSVenugopal Iyer static void *		i_dlstat_total_stat_entry_diff(void *, void *);
4700dc2366fSVenugopal Iyer 
4710dc2366fSVenugopal Iyer /* Aggr port specific functions */
4720dc2366fSVenugopal Iyer void *			dlstat_aggr_port_stats(dladm_handle_t, datalink_id_t);
4730dc2366fSVenugopal Iyer static boolean_t	i_dlstat_aggr_port_match(void *, void *);
4740dc2366fSVenugopal Iyer static void *		i_dlstat_aggr_port_stat_entry_diff(void *, void *);
4750dc2366fSVenugopal Iyer 
4760dc2366fSVenugopal Iyer /* Misc stat specific functions */
4770dc2366fSVenugopal Iyer void *			dlstat_misc_stats(dladm_handle_t, datalink_id_t);
4780dc2366fSVenugopal Iyer 
4790dc2366fSVenugopal Iyer typedef void *		dladm_stat_query_t(dladm_handle_t, datalink_id_t);
4800dc2366fSVenugopal Iyer typedef boolean_t	dladm_stat_match_t(void *, void *);
4810dc2366fSVenugopal Iyer typedef void *		dladm_stat_diff_t(void *, void *);
4820dc2366fSVenugopal Iyer 
4830dc2366fSVenugopal Iyer typedef struct dladm_stat_desc_s {
4840dc2366fSVenugopal Iyer 	dladm_stat_type_t	ds_stattype;
4850dc2366fSVenugopal Iyer 	dladm_stat_query_t	*ds_querystat;
4860dc2366fSVenugopal Iyer 	dladm_stat_match_t	*ds_matchstat;
4870dc2366fSVenugopal Iyer 	dladm_stat_diff_t	*ds_diffstat;
4880dc2366fSVenugopal Iyer 	uint_t			ds_offset;
4890dc2366fSVenugopal Iyer 	stat_info_t		*ds_statlist;
4900dc2366fSVenugopal Iyer 	uint_t			ds_statsize;
4910dc2366fSVenugopal Iyer } dladm_stat_desc_t;
4920dc2366fSVenugopal Iyer 
4930dc2366fSVenugopal Iyer /*
4940dc2366fSVenugopal Iyer  * dladm_stat_table has one entry for each supported stat. ds_querystat returns
4950dc2366fSVenugopal Iyer  * a chain of 'stat entries' for the queried stat.
4960dc2366fSVenugopal Iyer  * Each stat entry has set of identifiers (ids) and an object containing actual
4970dc2366fSVenugopal Iyer  * stat values. These stat entry objects are chained together in a linked list
4980dc2366fSVenugopal Iyer  * of datatype dladm_stat_chain_t. Head of this list is returned to the caller
4990dc2366fSVenugopal Iyer  * of dladm_link_stat_query.
5000dc2366fSVenugopal Iyer  *
5010dc2366fSVenugopal Iyer  * One node in the chain is shown below:
5020dc2366fSVenugopal Iyer  *
5030dc2366fSVenugopal Iyer  *	-------------------------
5040dc2366fSVenugopal Iyer  *	| dc_statentry	        |
5050dc2366fSVenugopal Iyer  *	|    --------------     |
5060dc2366fSVenugopal Iyer  *	|    |     ids     |	|
5070dc2366fSVenugopal Iyer  *	|    --------------     |
5080dc2366fSVenugopal Iyer  *	|    | stat fields |	|
5090dc2366fSVenugopal Iyer  *	|    --------------     |
5100dc2366fSVenugopal Iyer  *	-------------------------
5110dc2366fSVenugopal Iyer  *	|      dc_next ---------|------> to next stat entry
5120dc2366fSVenugopal Iyer  *	-------------------------
5130dc2366fSVenugopal Iyer  *
5140dc2366fSVenugopal Iyer  * In particular, for query DLADM_STAT_RX_LANE, dc_statentry carries pointer to
5150dc2366fSVenugopal Iyer  * object of type rx_lane_stat_entry_t.
5160dc2366fSVenugopal Iyer  *
5170dc2366fSVenugopal Iyer  * dladm_link_stat_query_all returns similar chain. However, instead of storing
5180dc2366fSVenugopal Iyer  * stat fields as raw numbers, it stores those as chain of <name, value> pairs.
5190dc2366fSVenugopal Iyer  * The resulting structure is depicted below:
5200dc2366fSVenugopal Iyer  *
5210dc2366fSVenugopal Iyer  *	-------------------------
5220dc2366fSVenugopal Iyer  *	| dc_statentry	        |
5230dc2366fSVenugopal Iyer  *	|    --------------     |   ---------------
5240dc2366fSVenugopal Iyer  *	|    |  nv_header  |	|   |   name, val  |
5250dc2366fSVenugopal Iyer  *	|    --------------     |   ---------------
5260dc2366fSVenugopal Iyer  *	|    | nve_stats---|----|-->| nv_nextstat--|---> to next name, val pair
5270dc2366fSVenugopal Iyer  *	|    --------------     |   ---------------
5280dc2366fSVenugopal Iyer  *	-------------------------
5290dc2366fSVenugopal Iyer  *	|      dc_next ---------|------> to next stat entry
5300dc2366fSVenugopal Iyer  *	-------------------------
5310dc2366fSVenugopal Iyer  */
5320dc2366fSVenugopal Iyer static dladm_stat_desc_t  dladm_stat_table[] = {
5330dc2366fSVenugopal Iyer { DLADM_STAT_RX_LANE,		dlstat_rx_lane_stats,
5340dc2366fSVenugopal Iyer     i_dlstat_rx_lane_match,	i_dlstat_rx_lane_stat_entry_diff,
5350dc2366fSVenugopal Iyer     offsetof(rx_lane_stat_entry_t, rle_stats),
5360dc2366fSVenugopal Iyer     rx_lane_stats_list,		RX_LANE_STAT_SIZE},
5370dc2366fSVenugopal Iyer 
5380dc2366fSVenugopal Iyer { DLADM_STAT_TX_LANE,		dlstat_tx_lane_stats,
5390dc2366fSVenugopal Iyer     i_dlstat_tx_lane_match,	i_dlstat_tx_lane_stat_entry_diff,
5400dc2366fSVenugopal Iyer     offsetof(tx_lane_stat_entry_t, tle_stats),
5410dc2366fSVenugopal Iyer     tx_lane_stats_list,		TX_LANE_STAT_SIZE},
5420dc2366fSVenugopal Iyer 
5430dc2366fSVenugopal Iyer { DLADM_STAT_RX_LANE_TOTAL,	dlstat_rx_lane_total_stats,
5440dc2366fSVenugopal Iyer     i_dlstat_rx_lane_match,	i_dlstat_rx_lane_stat_entry_diff,
5450dc2366fSVenugopal Iyer     offsetof(rx_lane_stat_entry_t, rle_stats),
5460dc2366fSVenugopal Iyer     rx_lane_stats_list,		RX_LANE_STAT_SIZE},
5470dc2366fSVenugopal Iyer 
5480dc2366fSVenugopal Iyer { DLADM_STAT_TX_LANE_TOTAL,	dlstat_tx_lane_total_stats,
5490dc2366fSVenugopal Iyer     i_dlstat_tx_lane_match,	i_dlstat_tx_lane_stat_entry_diff,
5500dc2366fSVenugopal Iyer     offsetof(tx_lane_stat_entry_t, tle_stats),
5510dc2366fSVenugopal Iyer     tx_lane_stats_list,		TX_LANE_STAT_SIZE},
5520dc2366fSVenugopal Iyer 
5530dc2366fSVenugopal Iyer { DLADM_STAT_RX_LANE_FOUT,	dlstat_fanout_stats,
5540dc2366fSVenugopal Iyer     i_dlstat_fanout_match,	i_dlstat_fanout_stat_entry_diff,
5550dc2366fSVenugopal Iyer     offsetof(fanout_stat_entry_t, fe_stats),
5560dc2366fSVenugopal Iyer     fanout_stats_list,		FANOUT_STAT_SIZE},
5570dc2366fSVenugopal Iyer 
5580dc2366fSVenugopal Iyer { DLADM_STAT_RX_RING,		dlstat_rx_ring_stats,
5590dc2366fSVenugopal Iyer     i_dlstat_rx_ring_match,	i_dlstat_rx_ring_stat_entry_diff,
5600dc2366fSVenugopal Iyer     offsetof(ring_stat_entry_t, re_stats),
5610dc2366fSVenugopal Iyer     rx_ring_stats_list,		RX_RING_STAT_SIZE},
5620dc2366fSVenugopal Iyer 
5630dc2366fSVenugopal Iyer { DLADM_STAT_TX_RING,		dlstat_tx_ring_stats,
5640dc2366fSVenugopal Iyer     i_dlstat_tx_ring_match,	i_dlstat_tx_ring_stat_entry_diff,
5650dc2366fSVenugopal Iyer     offsetof(ring_stat_entry_t, re_stats),
5660dc2366fSVenugopal Iyer     tx_ring_stats_list,		TX_RING_STAT_SIZE},
5670dc2366fSVenugopal Iyer 
5680dc2366fSVenugopal Iyer { DLADM_STAT_RX_RING_TOTAL,	dlstat_rx_ring_total_stats,
5690dc2366fSVenugopal Iyer     i_dlstat_rx_ring_match,	i_dlstat_rx_ring_stat_entry_diff,
5700dc2366fSVenugopal Iyer     offsetof(ring_stat_entry_t, re_stats),
5710dc2366fSVenugopal Iyer     rx_ring_stats_list,		RX_RING_STAT_SIZE},
5720dc2366fSVenugopal Iyer 
5730dc2366fSVenugopal Iyer { DLADM_STAT_TX_RING_TOTAL,	dlstat_tx_ring_total_stats,
5740dc2366fSVenugopal Iyer     i_dlstat_tx_ring_match,	i_dlstat_tx_ring_stat_entry_diff,
5750dc2366fSVenugopal Iyer     offsetof(ring_stat_entry_t, re_stats),
5760dc2366fSVenugopal Iyer     tx_ring_stats_list,		TX_RING_STAT_SIZE},
5770dc2366fSVenugopal Iyer 
5780dc2366fSVenugopal Iyer { DLADM_STAT_TOTAL,		dlstat_total_stats,
5790dc2366fSVenugopal Iyer     i_dlstat_total_match,	i_dlstat_total_stat_entry_diff,
5800dc2366fSVenugopal Iyer     offsetof(total_stat_entry_t, tse_stats),
5810dc2366fSVenugopal Iyer     total_stats_list,		TOTAL_STAT_SIZE},
5820dc2366fSVenugopal Iyer 
5830dc2366fSVenugopal Iyer { DLADM_STAT_AGGR_PORT,		dlstat_aggr_port_stats,
5840dc2366fSVenugopal Iyer     i_dlstat_aggr_port_match,	i_dlstat_aggr_port_stat_entry_diff,
5850dc2366fSVenugopal Iyer     offsetof(aggr_port_stat_entry_t, ape_stats),
5860dc2366fSVenugopal Iyer     aggr_port_stats_list,	AGGR_PORT_STAT_SIZE},
5870dc2366fSVenugopal Iyer /*
5880dc2366fSVenugopal Iyer  * We don't support -i <interval> query with misc stats. Several table fields
5890dc2366fSVenugopal Iyer  * are left uninitialized thus.
5900dc2366fSVenugopal Iyer  */
5910dc2366fSVenugopal Iyer { DLADM_STAT_MISC,		dlstat_misc_stats,
5920dc2366fSVenugopal Iyer     NULL,			NULL,
5930dc2366fSVenugopal Iyer     0,
5940dc2366fSVenugopal Iyer     misc_stats_list,		MISC_STAT_SIZE}
5950dc2366fSVenugopal Iyer };
5960dc2366fSVenugopal Iyer 
5970dc2366fSVenugopal Iyer /* Internal functions */
5980dc2366fSVenugopal Iyer static void *
dlstat_diff_stats(void * arg1,void * arg2,dladm_stat_type_t stattype)5990dc2366fSVenugopal Iyer dlstat_diff_stats(void *arg1, void *arg2, dladm_stat_type_t stattype)
6000dc2366fSVenugopal Iyer {
6010dc2366fSVenugopal Iyer 	return (dladm_stat_table[stattype].ds_diffstat(arg1, arg2));
6020dc2366fSVenugopal Iyer }
6030dc2366fSVenugopal Iyer 
6040dc2366fSVenugopal Iyer static boolean_t
dlstat_match_stats(void * arg1,void * arg2,dladm_stat_type_t stattype)6050dc2366fSVenugopal Iyer dlstat_match_stats(void *arg1, void *arg2, dladm_stat_type_t stattype)
6060dc2366fSVenugopal Iyer {
6070dc2366fSVenugopal Iyer 	return (dladm_stat_table[stattype].ds_matchstat(arg1, arg2));
6080dc2366fSVenugopal Iyer }
6090dc2366fSVenugopal Iyer 
6100dc2366fSVenugopal Iyer /* Diff between two stats */
6110dc2366fSVenugopal Iyer static void
i_dlstat_diff_stats(void * diff,void * op1,void * op2,stat_info_t stats_list[],uint_t size)6120dc2366fSVenugopal Iyer i_dlstat_diff_stats(void *diff, void *op1, void *op2,
6130dc2366fSVenugopal Iyer     stat_info_t stats_list[], uint_t size)
6140dc2366fSVenugopal Iyer {
615*4202e8bfSToomas Soome 	uint_t	i;
6160dc2366fSVenugopal Iyer 
6170dc2366fSVenugopal Iyer 	for (i = 0; i < size; i++) {
6180dc2366fSVenugopal Iyer 		uint64_t *op1_val  = (void *)
6190dc2366fSVenugopal Iyer 		    ((uchar_t *)op1 + stats_list[i].si_offset);
6200dc2366fSVenugopal Iyer 		uint64_t *op2_val = (void *)
6210dc2366fSVenugopal Iyer 		    ((uchar_t *)op2  + stats_list[i].si_offset);
6220dc2366fSVenugopal Iyer 		uint64_t *diff_val = (void *)
6230dc2366fSVenugopal Iyer 		    ((uchar_t *)diff + stats_list[i].si_offset);
6240dc2366fSVenugopal Iyer 
6250dc2366fSVenugopal Iyer 		*diff_val = DIFF_STAT(*op1_val, *op2_val);
6260dc2366fSVenugopal Iyer 	}
6270dc2366fSVenugopal Iyer }
6280dc2366fSVenugopal Iyer 
6290dc2366fSVenugopal Iyer /*
6300dc2366fSVenugopal Iyer  * Perform diff = s1 - s2,  where diff, s1, s2 are structure objects of same
6310dc2366fSVenugopal Iyer  * datatype. slist is list of offsets of the fields within the structure.
6320dc2366fSVenugopal Iyer  */
6330dc2366fSVenugopal Iyer #define	DLSTAT_DIFF_STAT(s1, s2, diff, f, slist, sz) {			\
6340dc2366fSVenugopal Iyer 	if (s2 == NULL) {						\
6350dc2366fSVenugopal Iyer 		bcopy(&s1->f, &diff->f, sizeof (s1->f));		\
6360dc2366fSVenugopal Iyer 	} else {							\
6370dc2366fSVenugopal Iyer 		i_dlstat_diff_stats(&diff->f, &s1->f,			\
6380dc2366fSVenugopal Iyer 		    &s2->f, slist, sz);					\
6390dc2366fSVenugopal Iyer 	}								\
6400dc2366fSVenugopal Iyer }
6410dc2366fSVenugopal Iyer 
6420dc2366fSVenugopal Iyer /* Sum two stats */
6430dc2366fSVenugopal Iyer static void
i_dlstat_sum_stats(void * sum,void * op1,void * op2,stat_info_t stats_list[],uint_t size)6440dc2366fSVenugopal Iyer i_dlstat_sum_stats(void *sum, void *op1, void *op2,
6450dc2366fSVenugopal Iyer     stat_info_t stats_list[], uint_t size)
6460dc2366fSVenugopal Iyer {
647*4202e8bfSToomas Soome 	uint_t	i;
6480dc2366fSVenugopal Iyer 
6490dc2366fSVenugopal Iyer 	for (i = 0; i < size; i++) {
6500dc2366fSVenugopal Iyer 		uint64_t *op1_val = (void *)
6510dc2366fSVenugopal Iyer 		    ((uchar_t *)op1 + stats_list[i].si_offset);
6520dc2366fSVenugopal Iyer 		uint64_t *op2_val = (void *)
6530dc2366fSVenugopal Iyer 		    ((uchar_t *)op2 + stats_list[i].si_offset);
6540dc2366fSVenugopal Iyer 		uint64_t *sum_val = (void *)
6550dc2366fSVenugopal Iyer 		    ((uchar_t *)sum + stats_list[i].si_offset);
6560dc2366fSVenugopal Iyer 
6570dc2366fSVenugopal Iyer 		*sum_val =  *op1_val + *op2_val;
6580dc2366fSVenugopal Iyer 	}
6590dc2366fSVenugopal Iyer }
6600dc2366fSVenugopal Iyer 
6610dc2366fSVenugopal Iyer /* Look up kstat value */
6620dc2366fSVenugopal Iyer static void
i_dlstat_get_stats(kstat_ctl_t * kcp,kstat_t * ksp,void * stats,stat_info_t stats_list[],uint_t size)6630dc2366fSVenugopal Iyer i_dlstat_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, void *stats,
6640dc2366fSVenugopal Iyer     stat_info_t stats_list[], uint_t size)
6650dc2366fSVenugopal Iyer {
666*4202e8bfSToomas Soome 	uint_t	i;
6670dc2366fSVenugopal Iyer 
6680dc2366fSVenugopal Iyer 	if (kstat_read(kcp, ksp, NULL) == -1)
6690dc2366fSVenugopal Iyer 		return;
6700dc2366fSVenugopal Iyer 
6710dc2366fSVenugopal Iyer 	for (i = 0; i < size; i++) {
6720dc2366fSVenugopal Iyer 		uint64_t *val = (void *)
6730dc2366fSVenugopal Iyer 		    ((uchar_t *)stats + stats_list[i].si_offset);
6740dc2366fSVenugopal Iyer 
6750dc2366fSVenugopal Iyer 		if (dladm_kstat_value(ksp, stats_list[i].si_name,
6760dc2366fSVenugopal Iyer 		    KSTAT_DATA_UINT64, val) < 0)
6770dc2366fSVenugopal Iyer 			return;
6780dc2366fSVenugopal Iyer 	}
6790dc2366fSVenugopal Iyer }
6800dc2366fSVenugopal Iyer 
6810dc2366fSVenugopal Iyer /* Append linked list list1 to linked list list2 and return resulting list */
6820dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_join_lists(dladm_stat_chain_t * list1,dladm_stat_chain_t * list2)6830dc2366fSVenugopal Iyer i_dlstat_join_lists(dladm_stat_chain_t *list1, dladm_stat_chain_t *list2)
6840dc2366fSVenugopal Iyer {
6850dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
6860dc2366fSVenugopal Iyer 
6870dc2366fSVenugopal Iyer 	if (list1 == NULL)
6880dc2366fSVenugopal Iyer 		return (list2);
6890dc2366fSVenugopal Iyer 
6900dc2366fSVenugopal Iyer 	/* list1 has at least one element, find last element in list1 */
6910dc2366fSVenugopal Iyer 	curr = list1;
6920dc2366fSVenugopal Iyer 	while (curr->dc_next != NULL)
6930dc2366fSVenugopal Iyer 		curr = curr->dc_next;
6940dc2366fSVenugopal Iyer 
6950dc2366fSVenugopal Iyer 	curr->dc_next = list2;
6960dc2366fSVenugopal Iyer 	return (list1);
6970dc2366fSVenugopal Iyer }
6980dc2366fSVenugopal Iyer 
6990dc2366fSVenugopal Iyer uint_t default_idlist[] = {0};
7000dc2366fSVenugopal Iyer uint_t default_idlist_size = 1;
7010dc2366fSVenugopal Iyer 
7020dc2366fSVenugopal Iyer typedef enum {
7030dc2366fSVenugopal Iyer 	DLSTAT_RX_RING_IDLIST,
7040dc2366fSVenugopal Iyer 	DLSTAT_TX_RING_IDLIST,
7050dc2366fSVenugopal Iyer 	DLSTAT_RX_HWLANE_IDLIST,
7060dc2366fSVenugopal Iyer 	DLSTAT_TX_HWLANE_IDLIST,
7070dc2366fSVenugopal Iyer 	DLSTAT_FANOUT_IDLIST
7080dc2366fSVenugopal Iyer } dlstat_idlist_type_t;
7090dc2366fSVenugopal Iyer 
7100dc2366fSVenugopal Iyer void
dladm_sort_index_list(uint_t idlist[],uint_t size)7110dc2366fSVenugopal Iyer dladm_sort_index_list(uint_t idlist[], uint_t size)
7120dc2366fSVenugopal Iyer {
713*4202e8bfSToomas Soome 	uint_t	j;
714*4202e8bfSToomas Soome 	int i;
7150dc2366fSVenugopal Iyer 
7160dc2366fSVenugopal Iyer 	for (j = 1; j < size; j++) {
717*4202e8bfSToomas Soome 		uint_t key = idlist[j];
718*4202e8bfSToomas Soome 
7190dc2366fSVenugopal Iyer 		for (i = j - 1; (i >= 0) && (idlist[i] > key); i--)
7200dc2366fSVenugopal Iyer 			idlist[i + 1] = idlist[i];
7210dc2366fSVenugopal Iyer 		idlist[i + 1] = key;
7220dc2366fSVenugopal Iyer 	}
7230dc2366fSVenugopal Iyer }
7240dc2366fSVenugopal Iyer 
7250dc2366fSVenugopal Iyer /* Support for legacy drivers */
7260dc2366fSVenugopal Iyer void
i_query_legacy_stats(dladm_handle_t dh,const char * linkname,pktsum_t * stats)727399dcf08Scarlos antonio neira bustos i_query_legacy_stats(dladm_handle_t dh, const char *linkname, pktsum_t *stats)
7280dc2366fSVenugopal Iyer {
7290dc2366fSVenugopal Iyer 	kstat_t		*ksp;
7300dc2366fSVenugopal Iyer 
7310dc2366fSVenugopal Iyer 	bzero(stats, sizeof (*stats));
7320dc2366fSVenugopal Iyer 
733399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(dh) == NULL)
7340dc2366fSVenugopal Iyer 		return;
7350dc2366fSVenugopal Iyer 
736399dcf08Scarlos antonio neira bustos 	ksp = dladm_kstat_lookup(dladm_dld_kcp(dh), "link", 0, linkname, NULL);
7370dc2366fSVenugopal Iyer 
7380dc2366fSVenugopal Iyer 	if (ksp != NULL)
739399dcf08Scarlos antonio neira bustos 		dladm_get_stats(dladm_dld_kcp(dh), ksp, stats);
7400dc2366fSVenugopal Iyer }
7410dc2366fSVenugopal Iyer 
7420dc2366fSVenugopal Iyer void *
i_dlstat_legacy_rx_lane_stats(dladm_handle_t dh,const char * linkname)743399dcf08Scarlos antonio neira bustos i_dlstat_legacy_rx_lane_stats(dladm_handle_t dh, const char *linkname)
7440dc2366fSVenugopal Iyer {
7450dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
7460dc2366fSVenugopal Iyer 	pktsum_t		stats;
7470dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
7480dc2366fSVenugopal Iyer 
7490dc2366fSVenugopal Iyer 	bzero(&stats, sizeof (pktsum_t));
7500dc2366fSVenugopal Iyer 
7510dc2366fSVenugopal Iyer 	/* Query for dls stats */
752399dcf08Scarlos antonio neira bustos 	i_query_legacy_stats(dh, linkname, &stats);
7530dc2366fSVenugopal Iyer 
7540dc2366fSVenugopal Iyer 	/* Convert to desired data type */
7550dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
7560dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
7570dc2366fSVenugopal Iyer 		goto done;
7580dc2366fSVenugopal Iyer 
7590dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
7600dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_SWLANE;
7610dc2366fSVenugopal Iyer 
7620dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets;
7630dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets;
7640dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes;
7650dc2366fSVenugopal Iyer 
7660dc2366fSVenugopal Iyer 	/* Allocate memory for wrapper */
7670dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
7680dc2366fSVenugopal Iyer 	if (head == NULL) {
7690dc2366fSVenugopal Iyer 		free(rx_lane_stat_entry);
7700dc2366fSVenugopal Iyer 		goto done;
7710dc2366fSVenugopal Iyer 	}
7720dc2366fSVenugopal Iyer 
7730dc2366fSVenugopal Iyer 	head->dc_statentry = rx_lane_stat_entry;
7740dc2366fSVenugopal Iyer 	head->dc_next = NULL;
7750dc2366fSVenugopal Iyer done:
7760dc2366fSVenugopal Iyer 	return (head);
7770dc2366fSVenugopal Iyer }
7780dc2366fSVenugopal Iyer 
7790dc2366fSVenugopal Iyer void *
i_dlstat_legacy_tx_lane_stats(dladm_handle_t dh,const char * linkname)780399dcf08Scarlos antonio neira bustos i_dlstat_legacy_tx_lane_stats(dladm_handle_t dh, const char *linkname)
7810dc2366fSVenugopal Iyer {
7820dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
7830dc2366fSVenugopal Iyer 	pktsum_t		stats;
7840dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
7850dc2366fSVenugopal Iyer 
7860dc2366fSVenugopal Iyer 	bzero(&stats, sizeof (pktsum_t));
7870dc2366fSVenugopal Iyer 
7880dc2366fSVenugopal Iyer 	/* Query for dls stats */
789399dcf08Scarlos antonio neira bustos 	i_query_legacy_stats(dh, linkname, &stats);
7900dc2366fSVenugopal Iyer 
7910dc2366fSVenugopal Iyer 	/* Convert to desired data type */
7920dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
7930dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
7940dc2366fSVenugopal Iyer 		goto done;
7950dc2366fSVenugopal Iyer 
7960dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
7970dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_SWLANE;
7980dc2366fSVenugopal Iyer 
7990dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets;
8000dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes;
8010dc2366fSVenugopal Iyer 
8020dc2366fSVenugopal Iyer 	/* Allocate memory for wrapper */
8030dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
8040dc2366fSVenugopal Iyer 	if (head == NULL) {
8050dc2366fSVenugopal Iyer 		free(tx_lane_stat_entry);
8060dc2366fSVenugopal Iyer 		goto done;
8070dc2366fSVenugopal Iyer 	}
8080dc2366fSVenugopal Iyer 
8090dc2366fSVenugopal Iyer 	head->dc_statentry = tx_lane_stat_entry;
8100dc2366fSVenugopal Iyer 	head->dc_next = NULL;
8110dc2366fSVenugopal Iyer done:
8120dc2366fSVenugopal Iyer 	return (head);
8130dc2366fSVenugopal Iyer }
8140dc2366fSVenugopal Iyer 
8150dc2366fSVenugopal Iyer /*
8160dc2366fSVenugopal Iyer  * Ideally, we would want an ioctl to return list of ring-ids (or lane-ids)
8170dc2366fSVenugopal Iyer  * for a given data-link (or mac client). We could then query for specific
8180dc2366fSVenugopal Iyer  * kstats based on these ring-ids (lane-ids).
8190dc2366fSVenugopal Iyer  * Ring-ids (or lane-ids) could be returned like any other link properties
8200dc2366fSVenugopal Iyer  * queried by dladm show-linkprop. However, non-global zones do not have
8210dc2366fSVenugopal Iyer  * access to this information today.
8220dc2366fSVenugopal Iyer  * We thus opt for an implementation that relies heavily on kstat internals:
8230dc2366fSVenugopal Iyer  * i_dlstat_*search routines and i_dlstat_get_idlist.
8240dc2366fSVenugopal Iyer  */
8250dc2366fSVenugopal Iyer /* rx hwlane specific */
8260dc2366fSVenugopal Iyer static boolean_t
i_dlstat_rx_hwlane_search(kstat_t * ksp)8270dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_search(kstat_t *ksp)
8280dc2366fSVenugopal Iyer {
8290dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
8300dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
8310dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "hwlane") != 0 &&
8320dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "fanout") == 0 &&
8330dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
8340dc2366fSVenugopal Iyer }
8350dc2366fSVenugopal Iyer 
8360dc2366fSVenugopal Iyer /* tx hwlane specific */
8370dc2366fSVenugopal Iyer static boolean_t
i_dlstat_tx_hwlane_search(kstat_t * ksp)8380dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_search(kstat_t *ksp)
8390dc2366fSVenugopal Iyer {
8400dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
8410dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_tx") != 0 &&
8420dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "hwlane") != 0 &&
8430dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
8440dc2366fSVenugopal Iyer }
8450dc2366fSVenugopal Iyer 
8460dc2366fSVenugopal Iyer /* rx fanout specific */
8470dc2366fSVenugopal Iyer static boolean_t
i_dlstat_fanout_search(kstat_t * ksp)8480dc2366fSVenugopal Iyer i_dlstat_fanout_search(kstat_t *ksp)
8490dc2366fSVenugopal Iyer {
8500dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
8510dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
8520dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "swlane") != 0 &&
8530dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "fanout") != 0 &&
8540dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
8550dc2366fSVenugopal Iyer }
8560dc2366fSVenugopal Iyer 
8570dc2366fSVenugopal Iyer /* rx ring specific */
8580dc2366fSVenugopal Iyer static boolean_t
i_dlstat_rx_ring_search(kstat_t * ksp)8590dc2366fSVenugopal Iyer i_dlstat_rx_ring_search(kstat_t *ksp)
8600dc2366fSVenugopal Iyer {
8610dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
8620dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
8630dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "ring") != 0 &&
8640dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
8650dc2366fSVenugopal Iyer }
8660dc2366fSVenugopal Iyer 
8670dc2366fSVenugopal Iyer /* tx ring specific */
8680dc2366fSVenugopal Iyer static boolean_t
i_dlstat_tx_ring_search(kstat_t * ksp)8690dc2366fSVenugopal Iyer i_dlstat_tx_ring_search(kstat_t *ksp)
8700dc2366fSVenugopal Iyer {
8710dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0) &&
8720dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_tx") != 0 &&
8730dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "ring") != 0 &&
8740dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0;
8750dc2366fSVenugopal Iyer }
8760dc2366fSVenugopal Iyer 
8770dc2366fSVenugopal Iyer typedef	boolean_t	dladm_search_kstat_t(kstat_t *);
8780dc2366fSVenugopal Iyer typedef struct dladm_extract_idlist_s {
8790dc2366fSVenugopal Iyer 	dlstat_idlist_type_t	di_type;
8800dc2366fSVenugopal Iyer 	char			*di_prefix;
8810dc2366fSVenugopal Iyer 	dladm_search_kstat_t	*di_searchkstat;
8820dc2366fSVenugopal Iyer } dladm_extract_idlist_t;
8830dc2366fSVenugopal Iyer 
8840dc2366fSVenugopal Iyer static dladm_extract_idlist_t dladm_extract_idlist[] = {
8850dc2366fSVenugopal Iyer { DLSTAT_RX_RING_IDLIST,	DLSTAT_MAC_RX_RING,
8860dc2366fSVenugopal Iyer     i_dlstat_rx_ring_search},
8870dc2366fSVenugopal Iyer { DLSTAT_TX_RING_IDLIST,	DLSTAT_MAC_TX_RING,
8880dc2366fSVenugopal Iyer     i_dlstat_tx_ring_search},
8890dc2366fSVenugopal Iyer { DLSTAT_RX_HWLANE_IDLIST,	DLSTAT_MAC_RX_HWLANE,
8900dc2366fSVenugopal Iyer     i_dlstat_rx_hwlane_search},
8910dc2366fSVenugopal Iyer { DLSTAT_TX_HWLANE_IDLIST,	DLSTAT_MAC_TX_HWLANE,
8920dc2366fSVenugopal Iyer     i_dlstat_tx_hwlane_search},
8930dc2366fSVenugopal Iyer { DLSTAT_FANOUT_IDLIST,		DLSTAT_MAC_FANOUT,
8940dc2366fSVenugopal Iyer     i_dlstat_fanout_search}
8950dc2366fSVenugopal Iyer };
8960dc2366fSVenugopal Iyer 
8970dc2366fSVenugopal Iyer static void
i_dlstat_get_idlist(dladm_handle_t handle,const char * modname,dlstat_idlist_type_t idlist_type,uint_t idlist[],uint_t * size)898399dcf08Scarlos antonio neira bustos i_dlstat_get_idlist(dladm_handle_t handle, const char *modname,
899399dcf08Scarlos antonio neira bustos     dlstat_idlist_type_t idlist_type,
9000dc2366fSVenugopal Iyer     uint_t idlist[], uint_t *size)
9010dc2366fSVenugopal Iyer {
902399dcf08Scarlos antonio neira bustos 	kstat_ctl_t	*kcp = dladm_dld_kcp(handle);
9030dc2366fSVenugopal Iyer 	kstat_t		*ksp;
9040dc2366fSVenugopal Iyer 	char		*prefix;
9050dc2366fSVenugopal Iyer 	int		prefixlen;
9060dc2366fSVenugopal Iyer 	boolean_t	(*fptr_searchkstat)(kstat_t *);
9070dc2366fSVenugopal Iyer 
9080dc2366fSVenugopal Iyer 	*size = 0;
9090dc2366fSVenugopal Iyer 
910399dcf08Scarlos antonio neira bustos 	if (kcp == NULL) {
9110dc2366fSVenugopal Iyer 		warn("kstat_open operation failed");
912399dcf08Scarlos antonio neira bustos 		return;
9130dc2366fSVenugopal Iyer 	}
9140dc2366fSVenugopal Iyer 
9150dc2366fSVenugopal Iyer 	prefix = dladm_extract_idlist[idlist_type].di_prefix;
9160dc2366fSVenugopal Iyer 	fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat;
9170dc2366fSVenugopal Iyer 	prefixlen = strlen(prefix);
9180dc2366fSVenugopal Iyer 	for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
9190dc2366fSVenugopal Iyer 		if ((strcmp(ksp->ks_module, modname) == 0) &&
9200dc2366fSVenugopal Iyer 		    fptr_searchkstat(ksp)) {
9210dc2366fSVenugopal Iyer 			idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]);
9220dc2366fSVenugopal Iyer 		}
9230dc2366fSVenugopal Iyer 	}
9240dc2366fSVenugopal Iyer 	dladm_sort_index_list(idlist, *size);
9250dc2366fSVenugopal Iyer }
9260dc2366fSVenugopal Iyer 
9270dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_query_stats(dladm_handle_t handle,const char * modname,const char * prefix,uint_t idlist[],uint_t idlist_size,void * (* fn)(kstat_ctl_t *,kstat_t *,int))928399dcf08Scarlos antonio neira bustos i_dlstat_query_stats(dladm_handle_t handle, const char *modname,
929399dcf08Scarlos antonio neira bustos     const char *prefix, uint_t idlist[], uint_t idlist_size,
9300dc2366fSVenugopal Iyer     void * (*fn)(kstat_ctl_t *, kstat_t *, int))
9310dc2366fSVenugopal Iyer {
9320dc2366fSVenugopal Iyer 	kstat_t			*ksp;
9330dc2366fSVenugopal Iyer 	char			statname[MAXLINKNAMELEN];
934*4202e8bfSToomas Soome 	uint_t			i;
9350dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL, *prev = NULL;
9360dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
9370dc2366fSVenugopal Iyer 
938399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(handle) == NULL) {
9390dc2366fSVenugopal Iyer 		warn("kstat_open operation failed");
9400dc2366fSVenugopal Iyer 		return (NULL);
9410dc2366fSVenugopal Iyer 	}
9420dc2366fSVenugopal Iyer 
9430dc2366fSVenugopal Iyer 	for (i = 0; i < idlist_size; i++) {
9440dc2366fSVenugopal Iyer 		uint_t	index = idlist[i];
9450dc2366fSVenugopal Iyer 
9460dc2366fSVenugopal Iyer 		(void) snprintf(statname, sizeof (statname), "%s%d", prefix,
9470dc2366fSVenugopal Iyer 		    index);
9480dc2366fSVenugopal Iyer 
949399dcf08Scarlos antonio neira bustos 		ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), modname, 0,
950399dcf08Scarlos antonio neira bustos 		    statname, NULL);
9510dc2366fSVenugopal Iyer 		if (ksp == NULL)
9520dc2366fSVenugopal Iyer 			continue;
9530dc2366fSVenugopal Iyer 
9540dc2366fSVenugopal Iyer 		curr = malloc(sizeof (dladm_stat_chain_t));
9550dc2366fSVenugopal Iyer 		if (curr == NULL)
9560dc2366fSVenugopal Iyer 			break;
9570dc2366fSVenugopal Iyer 
958399dcf08Scarlos antonio neira bustos 		curr->dc_statentry = fn(dladm_dld_kcp(handle), ksp, index);
9590dc2366fSVenugopal Iyer 		if (curr->dc_statentry == NULL) {
9600dc2366fSVenugopal Iyer 			free(curr);
9610dc2366fSVenugopal Iyer 			break;
9620dc2366fSVenugopal Iyer 		}
9630dc2366fSVenugopal Iyer 
9640dc2366fSVenugopal Iyer 		(void) strlcpy(curr->dc_statheader, statname,
9650dc2366fSVenugopal Iyer 		    sizeof (curr->dc_statheader));
9660dc2366fSVenugopal Iyer 		curr->dc_next = NULL;
9670dc2366fSVenugopal Iyer 
9680dc2366fSVenugopal Iyer 		if (head == NULL)	/* First node */
9690dc2366fSVenugopal Iyer 			head = curr;
9700dc2366fSVenugopal Iyer 		else
9710dc2366fSVenugopal Iyer 			prev->dc_next = curr;
9720dc2366fSVenugopal Iyer 
9730dc2366fSVenugopal Iyer 		prev = curr;
9740dc2366fSVenugopal Iyer 	}
9750dc2366fSVenugopal Iyer 	return (head);
9760dc2366fSVenugopal Iyer }
9770dc2366fSVenugopal Iyer 
9780dc2366fSVenugopal Iyer static misc_stat_entry_t *
i_dlstat_misc_stats(dladm_handle_t handle,const char * linkname)979399dcf08Scarlos antonio neira bustos i_dlstat_misc_stats(dladm_handle_t handle, const char *linkname)
9800dc2366fSVenugopal Iyer {
9810dc2366fSVenugopal Iyer 	kstat_t			*ksp;
9820dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry = NULL;
9830dc2366fSVenugopal Iyer 
984399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(handle) == NULL)
9850dc2366fSVenugopal Iyer 		return (NULL);
9860dc2366fSVenugopal Iyer 
987399dcf08Scarlos antonio neira bustos 	ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), linkname, 0,
988399dcf08Scarlos antonio neira bustos 	    DLSTAT_MAC_MISC_STAT, NULL);
9890dc2366fSVenugopal Iyer 	if (ksp == NULL)
9900dc2366fSVenugopal Iyer 		goto done;
9910dc2366fSVenugopal Iyer 
9920dc2366fSVenugopal Iyer 	misc_stat_entry = calloc(1, sizeof (misc_stat_entry_t));
9930dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
9940dc2366fSVenugopal Iyer 		goto done;
9950dc2366fSVenugopal Iyer 
996399dcf08Scarlos antonio neira bustos 	i_dlstat_get_stats(dladm_dld_kcp(handle), ksp,
997399dcf08Scarlos antonio neira bustos 	    &misc_stat_entry->mse_stats,
9980dc2366fSVenugopal Iyer 	    misc_stats_list, MISC_STAT_SIZE);
9990dc2366fSVenugopal Iyer done:
10000dc2366fSVenugopal Iyer 	return (misc_stat_entry);
10010dc2366fSVenugopal Iyer }
10020dc2366fSVenugopal Iyer 
10030dc2366fSVenugopal Iyer /* Rx lane statistic specific functions */
10040dc2366fSVenugopal Iyer static boolean_t
i_dlstat_rx_lane_match(void * arg1,void * arg2)10050dc2366fSVenugopal Iyer i_dlstat_rx_lane_match(void *arg1, void *arg2)
10060dc2366fSVenugopal Iyer {
10070dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s1 = arg1;
10080dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s2 = arg2;
10090dc2366fSVenugopal Iyer 
10100dc2366fSVenugopal Iyer 	return (s1->rle_index == s2->rle_index &&
10110dc2366fSVenugopal Iyer 	    s1->rle_id == s2->rle_id);
10120dc2366fSVenugopal Iyer }
10130dc2366fSVenugopal Iyer 
10140dc2366fSVenugopal Iyer static void *
i_dlstat_rx_lane_stat_entry_diff(void * arg1,void * arg2)10150dc2366fSVenugopal Iyer i_dlstat_rx_lane_stat_entry_diff(void *arg1, void *arg2)
10160dc2366fSVenugopal Iyer {
10170dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s1 = arg1;
10180dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s2 = arg2;
10190dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *diff_entry;
10200dc2366fSVenugopal Iyer 
10210dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (rx_lane_stat_entry_t));
10220dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
10230dc2366fSVenugopal Iyer 		goto done;
10240dc2366fSVenugopal Iyer 
10250dc2366fSVenugopal Iyer 	diff_entry->rle_index = s1->rle_index;
10260dc2366fSVenugopal Iyer 	diff_entry->rle_id = s1->rle_id;
10270dc2366fSVenugopal Iyer 
10280dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, rle_stats, rx_lane_stats_list,
10290dc2366fSVenugopal Iyer 	    RX_LANE_STAT_SIZE);
10300dc2366fSVenugopal Iyer 
10310dc2366fSVenugopal Iyer done:
10320dc2366fSVenugopal Iyer 	return (diff_entry);
10330dc2366fSVenugopal Iyer }
10340dc2366fSVenugopal Iyer 
10350dc2366fSVenugopal Iyer static void *
i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)10360dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
10370dc2366fSVenugopal Iyer {
10380dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
10390dc2366fSVenugopal Iyer 
10400dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
10410dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
10420dc2366fSVenugopal Iyer 		goto done;
10430dc2366fSVenugopal Iyer 
10440dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = i;
10450dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_HWLANE;
10460dc2366fSVenugopal Iyer 
10470dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
10480dc2366fSVenugopal Iyer 	    rx_hwlane_stats_list, RX_HWLANE_STAT_SIZE);
10490dc2366fSVenugopal Iyer 
10500dc2366fSVenugopal Iyer done:
10510dc2366fSVenugopal Iyer 	return (rx_lane_stat_entry);
10520dc2366fSVenugopal Iyer }
10530dc2366fSVenugopal Iyer 
10540dc2366fSVenugopal Iyer static void *
i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i __unused)105520535e13SToomas Soome i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused)
10560dc2366fSVenugopal Iyer {
10570dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
10580dc2366fSVenugopal Iyer 
10590dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
10600dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
10610dc2366fSVenugopal Iyer 		goto done;
10620dc2366fSVenugopal Iyer 
10630dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
10640dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_SWLANE;
10650dc2366fSVenugopal Iyer 
10660dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
10670dc2366fSVenugopal Iyer 	    rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
10680dc2366fSVenugopal Iyer 
10690dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets =
10700dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_intrs;
10710dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes =
10720dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_intrbytes;
10730dc2366fSVenugopal Iyer done:
10740dc2366fSVenugopal Iyer 	return (rx_lane_stat_entry);
10750dc2366fSVenugopal Iyer }
10760dc2366fSVenugopal Iyer 
10770dc2366fSVenugopal Iyer static void *
i_dlstat_rx_local_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i __unused)107820535e13SToomas Soome i_dlstat_rx_local_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused)
10790dc2366fSVenugopal Iyer {
1080f7952617SToomas Soome 	rx_lane_stat_entry_t	*local_stat_entry = NULL;
10810dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
10820dc2366fSVenugopal Iyer 
10830dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
10840dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
10850dc2366fSVenugopal Iyer 		goto done;
10860dc2366fSVenugopal Iyer 
10870dc2366fSVenugopal Iyer 	local_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
10880dc2366fSVenugopal Iyer 	if (local_stat_entry == NULL)
10890dc2366fSVenugopal Iyer 		goto done;
10900dc2366fSVenugopal Iyer 
10910dc2366fSVenugopal Iyer 	local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
10920dc2366fSVenugopal Iyer 	local_stat_entry->rle_id = L_LOCAL;
10930dc2366fSVenugopal Iyer 
10940dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
10950dc2366fSVenugopal Iyer 	    rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
10960dc2366fSVenugopal Iyer 
10970dc2366fSVenugopal Iyer 	local_stat_entry->rle_stats.rl_ipackets =
10980dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_lclpackets;
10990dc2366fSVenugopal Iyer 	local_stat_entry->rle_stats.rl_rbytes =
11000dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_lclbytes;
11010dc2366fSVenugopal Iyer 
11020dc2366fSVenugopal Iyer done:
11030dc2366fSVenugopal Iyer 	free(rx_lane_stat_entry);
11040dc2366fSVenugopal Iyer 	return (local_stat_entry);
11050dc2366fSVenugopal Iyer }
11060dc2366fSVenugopal Iyer 
11070dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_rx_local_stats(dladm_handle_t handle,const char * linkname)1108399dcf08Scarlos antonio neira bustos i_dlstat_rx_local_stats(dladm_handle_t handle, const char *linkname)
11090dc2366fSVenugopal Iyer {
11100dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*local_stats = NULL;
11110dc2366fSVenugopal Iyer 
1112399dcf08Scarlos antonio neira bustos 	local_stats = i_dlstat_query_stats(handle, linkname,
1113399dcf08Scarlos antonio neira bustos 	    DLSTAT_MAC_RX_SWLANE,
11140dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size,
11150dc2366fSVenugopal Iyer 	    i_dlstat_rx_local_retrieve_stat);
11160dc2366fSVenugopal Iyer 
11170dc2366fSVenugopal Iyer 	if (local_stats != NULL) {
11180dc2366fSVenugopal Iyer 		(void) strlcpy(local_stats->dc_statheader, "mac_rx_local",
11190dc2366fSVenugopal Iyer 		    sizeof (local_stats->dc_statheader));
11200dc2366fSVenugopal Iyer 	}
11210dc2366fSVenugopal Iyer 	return (local_stats);
11220dc2366fSVenugopal Iyer }
11230dc2366fSVenugopal Iyer 
11240dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_rx_bcast_stats(dladm_handle_t handle,const char * linkname)1125399dcf08Scarlos antonio neira bustos i_dlstat_rx_bcast_stats(dladm_handle_t handle, const char *linkname)
11260dc2366fSVenugopal Iyer {
11270dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
11280dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
11290dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
11300dc2366fSVenugopal Iyer 
1131399dcf08Scarlos antonio neira bustos 	misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
11320dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
11330dc2366fSVenugopal Iyer 		goto done;
11340dc2366fSVenugopal Iyer 
11350dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
11360dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
11370dc2366fSVenugopal Iyer 		goto done;
11380dc2366fSVenugopal Iyer 
11390dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
11400dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_BCAST;
11410dc2366fSVenugopal Iyer 
11420dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets =
11430dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstrcv +
11440dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multircv;
11450dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_intrs =
11460dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstrcv +
11470dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multircv;
11480dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes =
11490dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstrcvbytes +
11500dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multircvbytes;
11510dc2366fSVenugopal Iyer 
11520dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
11530dc2366fSVenugopal Iyer 	if (head == NULL) {
11540dc2366fSVenugopal Iyer 		free(rx_lane_stat_entry);
11550dc2366fSVenugopal Iyer 		goto done;
11560dc2366fSVenugopal Iyer 	}
11570dc2366fSVenugopal Iyer 
11580dc2366fSVenugopal Iyer 	head->dc_statentry = rx_lane_stat_entry;
11590dc2366fSVenugopal Iyer 	head->dc_next = NULL;
11600dc2366fSVenugopal Iyer 
11610dc2366fSVenugopal Iyer 	free(misc_stat_entry);
11620dc2366fSVenugopal Iyer done:
11630dc2366fSVenugopal Iyer 	return (head);
11640dc2366fSVenugopal Iyer }
11650dc2366fSVenugopal Iyer 
11660dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_rx_defunctlane_stats(dladm_handle_t handle,const char * linkname)1167399dcf08Scarlos antonio neira bustos i_dlstat_rx_defunctlane_stats(dladm_handle_t handle, const char *linkname)
11680dc2366fSVenugopal Iyer {
11690dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
11700dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
11710dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
11720dc2366fSVenugopal Iyer 
1173399dcf08Scarlos antonio neira bustos 	misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
11740dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
11750dc2366fSVenugopal Iyer 		goto done;
11760dc2366fSVenugopal Iyer 
11770dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
11780dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
11790dc2366fSVenugopal Iyer 		goto done;
11800dc2366fSVenugopal Iyer 
11810dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
11820dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_DFNCT;
11830dc2366fSVenugopal Iyer 
11840dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets =
11850dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_ipackets;
11860dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes =
11870dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_rbytes;
11880dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_intrs =
11890dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_intrs;
11900dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_polls =
11910dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_polls;
11920dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_sdrops =
11930dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_rxsdrops;
11940dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_chl10 =
11950dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_chainunder10;
11960dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ch10_50 =
11970dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_chain10to50;
11980dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_chg50 =
11990dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_chainover50;
12000dc2366fSVenugopal Iyer 
12010dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
12020dc2366fSVenugopal Iyer 	if (head == NULL) {
12030dc2366fSVenugopal Iyer 		free(rx_lane_stat_entry);
12040dc2366fSVenugopal Iyer 		goto done;
12050dc2366fSVenugopal Iyer 	}
12060dc2366fSVenugopal Iyer 
12070dc2366fSVenugopal Iyer 	head->dc_statentry = rx_lane_stat_entry;
12080dc2366fSVenugopal Iyer 	head->dc_next = NULL;
12090dc2366fSVenugopal Iyer 
12100dc2366fSVenugopal Iyer done:
12110dc2366fSVenugopal Iyer 	return (head);
12120dc2366fSVenugopal Iyer }
12130dc2366fSVenugopal Iyer 
12140dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_rx_hwlane_stats(dladm_handle_t handle,const char * linkname)1215399dcf08Scarlos antonio neira bustos i_dlstat_rx_hwlane_stats(dladm_handle_t handle, const char *linkname)
12160dc2366fSVenugopal Iyer {
12170dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
12180dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist_size;
12190dc2366fSVenugopal Iyer 
1220399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(handle, linkname, DLSTAT_RX_HWLANE_IDLIST,
12210dc2366fSVenugopal Iyer 	    rx_hwlane_idlist, &rx_hwlane_idlist_size);
12220dc2366fSVenugopal Iyer 
1223399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_RX_HWLANE,
12240dc2366fSVenugopal Iyer 	    rx_hwlane_idlist, rx_hwlane_idlist_size,
12250dc2366fSVenugopal Iyer 	    i_dlstat_rx_hwlane_retrieve_stat));
12260dc2366fSVenugopal Iyer }
12270dc2366fSVenugopal Iyer 
12280dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_rx_swlane_stats(dladm_handle_t dh,datalink_id_t linkid __unused,const char * linkname)122920535e13SToomas Soome i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid __unused,
12300dc2366fSVenugopal Iyer     const char *linkname)
12310dc2366fSVenugopal Iyer {
1232399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_RX_SWLANE,
12330dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size,
12340dc2366fSVenugopal Iyer 	    i_dlstat_rx_swlane_retrieve_stat));
12350dc2366fSVenugopal Iyer }
12360dc2366fSVenugopal Iyer 
12370dc2366fSVenugopal Iyer void *
dlstat_rx_lane_stats(dladm_handle_t dh,datalink_id_t linkid)12380dc2366fSVenugopal Iyer dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
12390dc2366fSVenugopal Iyer {
12400dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
12410dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*local_stats = NULL;
12420dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*bcast_stats = NULL;
12430dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*defunctlane_stats = NULL;
12440dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*lane_stats = NULL;
12450dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
12460dc2366fSVenugopal Iyer 	boolean_t		is_legacy_driver;
12470dc2366fSVenugopal Iyer 
12480dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
12490dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
12500dc2366fSVenugopal Iyer 		goto done;
12510dc2366fSVenugopal Iyer 	}
12520dc2366fSVenugopal Iyer 
12530dc2366fSVenugopal Iyer 	/* Check if it is legacy driver */
12540dc2366fSVenugopal Iyer 	if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
12550dc2366fSVenugopal Iyer 	    "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
12560dc2366fSVenugopal Iyer 		goto done;
12570dc2366fSVenugopal Iyer 	}
12580dc2366fSVenugopal Iyer 
12590dc2366fSVenugopal Iyer 	if (is_legacy_driver) {
1260399dcf08Scarlos antonio neira bustos 		head = i_dlstat_legacy_rx_lane_stats(dh, linkname);
12610dc2366fSVenugopal Iyer 		goto done;
12620dc2366fSVenugopal Iyer 	}
12630dc2366fSVenugopal Iyer 
1264399dcf08Scarlos antonio neira bustos 	local_stats = i_dlstat_rx_local_stats(dh, linkname);
1265399dcf08Scarlos antonio neira bustos 	bcast_stats = i_dlstat_rx_bcast_stats(dh, linkname);
1266399dcf08Scarlos antonio neira bustos 	defunctlane_stats = i_dlstat_rx_defunctlane_stats(dh, linkname);
1267399dcf08Scarlos antonio neira bustos 	lane_stats = i_dlstat_rx_hwlane_stats(dh, linkname);
12680dc2366fSVenugopal Iyer 	if (lane_stats == NULL)
12690dc2366fSVenugopal Iyer 		lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname);
12700dc2366fSVenugopal Iyer 
12710dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(local_stats, bcast_stats);
12720dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(head, defunctlane_stats);
12730dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(head, lane_stats);
12740dc2366fSVenugopal Iyer done:
12750dc2366fSVenugopal Iyer 	return (head);
12760dc2366fSVenugopal Iyer }
12770dc2366fSVenugopal Iyer 
12780dc2366fSVenugopal Iyer /* Tx lane statistic specific functions */
12790dc2366fSVenugopal Iyer static boolean_t
i_dlstat_tx_lane_match(void * arg1,void * arg2)12800dc2366fSVenugopal Iyer i_dlstat_tx_lane_match(void *arg1, void *arg2)
12810dc2366fSVenugopal Iyer {
12820dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s1 = arg1;
12830dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s2 = arg2;
12840dc2366fSVenugopal Iyer 
12850dc2366fSVenugopal Iyer 	return (s1->tle_index == s2->tle_index &&
12860dc2366fSVenugopal Iyer 	    s1->tle_id == s2->tle_id);
12870dc2366fSVenugopal Iyer }
12880dc2366fSVenugopal Iyer 
12890dc2366fSVenugopal Iyer static void *
i_dlstat_tx_lane_stat_entry_diff(void * arg1,void * arg2)12900dc2366fSVenugopal Iyer i_dlstat_tx_lane_stat_entry_diff(void *arg1, void *arg2)
12910dc2366fSVenugopal Iyer {
12920dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s1 = arg1;
12930dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s2 = arg2;
12940dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *diff_entry;
12950dc2366fSVenugopal Iyer 
12960dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (tx_lane_stat_entry_t));
12970dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
12980dc2366fSVenugopal Iyer 		goto done;
12990dc2366fSVenugopal Iyer 
13000dc2366fSVenugopal Iyer 	diff_entry->tle_index = s1->tle_index;
13010dc2366fSVenugopal Iyer 	diff_entry->tle_id = s1->tle_id;
13020dc2366fSVenugopal Iyer 
13030dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, tle_stats, tx_lane_stats_list,
13040dc2366fSVenugopal Iyer 	    TX_LANE_STAT_SIZE);
13050dc2366fSVenugopal Iyer 
13060dc2366fSVenugopal Iyer done:
13070dc2366fSVenugopal Iyer 	return (diff_entry);
13080dc2366fSVenugopal Iyer }
13090dc2366fSVenugopal Iyer 
13100dc2366fSVenugopal Iyer static void *
i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)13110dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
13120dc2366fSVenugopal Iyer {
13130dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
13140dc2366fSVenugopal Iyer 
13150dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
13160dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
13170dc2366fSVenugopal Iyer 		goto done;
13180dc2366fSVenugopal Iyer 
13190dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index	= i;
13200dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id	= L_HWLANE;
13210dc2366fSVenugopal Iyer 
13220dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
13230dc2366fSVenugopal Iyer 	    tx_lane_stats_list, TX_LANE_STAT_SIZE);
13240dc2366fSVenugopal Iyer 
13250dc2366fSVenugopal Iyer done:
13260dc2366fSVenugopal Iyer 	return (tx_lane_stat_entry);
13270dc2366fSVenugopal Iyer }
13280dc2366fSVenugopal Iyer 
13290dc2366fSVenugopal Iyer static void *
i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i __unused)133020535e13SToomas Soome i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused)
13310dc2366fSVenugopal Iyer {
13320dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
13330dc2366fSVenugopal Iyer 
13340dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
13350dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
13360dc2366fSVenugopal Iyer 		goto done;
13370dc2366fSVenugopal Iyer 
13380dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
13390dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_SWLANE;
13400dc2366fSVenugopal Iyer 
13410dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
13420dc2366fSVenugopal Iyer 	    tx_lane_stats_list, TX_LANE_STAT_SIZE);
13430dc2366fSVenugopal Iyer 
13440dc2366fSVenugopal Iyer done:
13450dc2366fSVenugopal Iyer 	return (tx_lane_stat_entry);
13460dc2366fSVenugopal Iyer }
13470dc2366fSVenugopal Iyer 
13480dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_tx_bcast_stats(dladm_handle_t handle,const char * linkname)1349399dcf08Scarlos antonio neira bustos i_dlstat_tx_bcast_stats(dladm_handle_t handle, const char *linkname)
13500dc2366fSVenugopal Iyer {
13510dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
13520dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
13530dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
13540dc2366fSVenugopal Iyer 
1355399dcf08Scarlos antonio neira bustos 	misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
13560dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
13570dc2366fSVenugopal Iyer 		goto done;
13580dc2366fSVenugopal Iyer 
13590dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
13600dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
13610dc2366fSVenugopal Iyer 		goto done;
13620dc2366fSVenugopal Iyer 
13630dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
13640dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_BCAST;
13650dc2366fSVenugopal Iyer 
13660dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_opackets =
13670dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstxmt +
13680dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multixmt;
13690dc2366fSVenugopal Iyer 
13700dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_obytes =
13710dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstxmtbytes +
13720dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multixmtbytes;
13730dc2366fSVenugopal Iyer 
13740dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
13750dc2366fSVenugopal Iyer 	if (head == NULL) {
13760dc2366fSVenugopal Iyer 		free(tx_lane_stat_entry);
13770dc2366fSVenugopal Iyer 		goto done;
13780dc2366fSVenugopal Iyer 	}
13790dc2366fSVenugopal Iyer 
13800dc2366fSVenugopal Iyer 	head->dc_statentry = tx_lane_stat_entry;
13810dc2366fSVenugopal Iyer 	head->dc_next = NULL;
13820dc2366fSVenugopal Iyer 
13830dc2366fSVenugopal Iyer 	free(misc_stat_entry);
13840dc2366fSVenugopal Iyer done:
13850dc2366fSVenugopal Iyer 	return (head);
13860dc2366fSVenugopal Iyer }
13870dc2366fSVenugopal Iyer 
13880dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_tx_defunctlane_stats(dladm_handle_t handle,const char * linkname)1389399dcf08Scarlos antonio neira bustos i_dlstat_tx_defunctlane_stats(dladm_handle_t handle, const char *linkname)
13900dc2366fSVenugopal Iyer {
13910dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
13920dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
13930dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
13940dc2366fSVenugopal Iyer 
1395399dcf08Scarlos antonio neira bustos 	misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
13960dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
13970dc2366fSVenugopal Iyer 		goto done;
13980dc2366fSVenugopal Iyer 
13990dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
14000dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
14010dc2366fSVenugopal Iyer 		goto done;
14020dc2366fSVenugopal Iyer 
14030dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
14040dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_DFNCT;
14050dc2366fSVenugopal Iyer 
14060dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_opackets =
14070dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_opackets;
14080dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_obytes =
14090dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_obytes;
14100dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_sdrops =
14110dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_txsdrops;
14120dc2366fSVenugopal Iyer 
14130dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
14140dc2366fSVenugopal Iyer 	if (head == NULL) {
14150dc2366fSVenugopal Iyer 		free(tx_lane_stat_entry);
14160dc2366fSVenugopal Iyer 		goto done;
14170dc2366fSVenugopal Iyer 	}
14180dc2366fSVenugopal Iyer 
14190dc2366fSVenugopal Iyer 	head->dc_statentry = tx_lane_stat_entry;
14200dc2366fSVenugopal Iyer 	head->dc_next = NULL;
14210dc2366fSVenugopal Iyer 
14220dc2366fSVenugopal Iyer done:
14230dc2366fSVenugopal Iyer 	return (head);
14240dc2366fSVenugopal Iyer }
14250dc2366fSVenugopal Iyer 
14260dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_tx_hwlane_stats(dladm_handle_t handle,const char * linkname)1427399dcf08Scarlos antonio neira bustos i_dlstat_tx_hwlane_stats(dladm_handle_t handle, const char *linkname)
14280dc2366fSVenugopal Iyer {
14290dc2366fSVenugopal Iyer 	uint_t	tx_hwlane_idlist[MAX_RINGS_PER_GROUP];
14300dc2366fSVenugopal Iyer 	uint_t	tx_hwlane_idlist_size;
14310dc2366fSVenugopal Iyer 
1432399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(handle, linkname, DLSTAT_TX_HWLANE_IDLIST,
14330dc2366fSVenugopal Iyer 	    tx_hwlane_idlist, &tx_hwlane_idlist_size);
14340dc2366fSVenugopal Iyer 
1435399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_TX_HWLANE,
14360dc2366fSVenugopal Iyer 	    tx_hwlane_idlist, tx_hwlane_idlist_size,
14370dc2366fSVenugopal Iyer 	    i_dlstat_tx_hwlane_retrieve_stat));
14380dc2366fSVenugopal Iyer }
14390dc2366fSVenugopal Iyer 
14400dc2366fSVenugopal Iyer static dladm_stat_chain_t *
i_dlstat_tx_swlane_stats(dladm_handle_t dh,datalink_id_t linkid __unused,const char * linkname)144120535e13SToomas Soome i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid __unused,
14420dc2366fSVenugopal Iyer     const char *linkname)
14430dc2366fSVenugopal Iyer {
1444399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_TX_SWLANE,
14450dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size,
14460dc2366fSVenugopal Iyer 	    i_dlstat_tx_swlane_retrieve_stat));
14470dc2366fSVenugopal Iyer }
14480dc2366fSVenugopal Iyer 
14490dc2366fSVenugopal Iyer void *
dlstat_tx_lane_stats(dladm_handle_t dh,datalink_id_t linkid)14500dc2366fSVenugopal Iyer dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
14510dc2366fSVenugopal Iyer {
14520dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
14530dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*bcast_stats = NULL;
14540dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*defunctlane_stats = NULL;
14550dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*lane_stats;
14560dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
14570dc2366fSVenugopal Iyer 	boolean_t		is_legacy_driver;
14580dc2366fSVenugopal Iyer 
14590dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
14600dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
14610dc2366fSVenugopal Iyer 		goto done;
14620dc2366fSVenugopal Iyer 	}
14630dc2366fSVenugopal Iyer 
14640dc2366fSVenugopal Iyer 	/* Check if it is legacy driver */
14650dc2366fSVenugopal Iyer 	if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
14660dc2366fSVenugopal Iyer 	    "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
14670dc2366fSVenugopal Iyer 		goto done;
14680dc2366fSVenugopal Iyer 	}
14690dc2366fSVenugopal Iyer 
14700dc2366fSVenugopal Iyer 	if (is_legacy_driver) {
1471399dcf08Scarlos antonio neira bustos 		head = i_dlstat_legacy_tx_lane_stats(dh, linkname);
14720dc2366fSVenugopal Iyer 		goto done;
14730dc2366fSVenugopal Iyer 	}
14740dc2366fSVenugopal Iyer 
1475399dcf08Scarlos antonio neira bustos 	bcast_stats = i_dlstat_tx_bcast_stats(dh, linkname);
1476399dcf08Scarlos antonio neira bustos 	defunctlane_stats = i_dlstat_tx_defunctlane_stats(dh, linkname);
1477399dcf08Scarlos antonio neira bustos 	lane_stats = i_dlstat_tx_hwlane_stats(dh, linkname);
14780dc2366fSVenugopal Iyer 	if (lane_stats == NULL)
14790dc2366fSVenugopal Iyer 		lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname);
14800dc2366fSVenugopal Iyer 
14810dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(bcast_stats, defunctlane_stats);
14820dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(head, lane_stats);
14830dc2366fSVenugopal Iyer 
14840dc2366fSVenugopal Iyer done:
14850dc2366fSVenugopal Iyer 	return (head);
14860dc2366fSVenugopal Iyer }
14870dc2366fSVenugopal Iyer 
14880dc2366fSVenugopal Iyer /* Rx lane total statistic specific functions */
14890dc2366fSVenugopal Iyer void *
dlstat_rx_lane_total_stats(dladm_handle_t dh,datalink_id_t linkid)14900dc2366fSVenugopal Iyer dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
14910dc2366fSVenugopal Iyer {
14920dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
14930dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*rx_lane_head, *curr;
14940dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*total_stats;
14950dc2366fSVenugopal Iyer 
14960dc2366fSVenugopal Iyer 	/* Get per rx lane stats */
14970dc2366fSVenugopal Iyer 	rx_lane_head = dlstat_rx_lane_stats(dh, linkid);
14980dc2366fSVenugopal Iyer 	if (rx_lane_head == NULL)
14990dc2366fSVenugopal Iyer 		goto done;
15000dc2366fSVenugopal Iyer 
15010dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (rx_lane_stat_entry_t));
15020dc2366fSVenugopal Iyer 	if (total_stats == NULL)
15030dc2366fSVenugopal Iyer 		goto done;
15040dc2366fSVenugopal Iyer 
15050dc2366fSVenugopal Iyer 	total_stats->rle_index = DLSTAT_INVALID_ENTRY;
15060dc2366fSVenugopal Iyer 	total_stats->rle_id = DLSTAT_INVALID_ENTRY;
15070dc2366fSVenugopal Iyer 
15080dc2366fSVenugopal Iyer 	for (curr = rx_lane_head; curr != NULL; curr = curr->dc_next) {
15090dc2366fSVenugopal Iyer 		rx_lane_stat_entry_t	*curr_lane_stats = curr->dc_statentry;
15100dc2366fSVenugopal Iyer 
15110dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->rle_stats,
15120dc2366fSVenugopal Iyer 		    &curr_lane_stats->rle_stats, &total_stats->rle_stats,
15130dc2366fSVenugopal Iyer 		    rx_lane_stats_list, RX_LANE_STAT_SIZE);
15140dc2366fSVenugopal Iyer 	}
15150dc2366fSVenugopal Iyer 
15160dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
15170dc2366fSVenugopal Iyer 	if (total_head == NULL) {
15180dc2366fSVenugopal Iyer 		free(total_stats);
15190dc2366fSVenugopal Iyer 		goto done;
15200dc2366fSVenugopal Iyer 	}
15210dc2366fSVenugopal Iyer 
15220dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
15230dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_rx_lane_total",
15240dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
15250dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
15260dc2366fSVenugopal Iyer 	free(rx_lane_head);
15270dc2366fSVenugopal Iyer 
15280dc2366fSVenugopal Iyer done:
15290dc2366fSVenugopal Iyer 	return (total_head);
15300dc2366fSVenugopal Iyer }
15310dc2366fSVenugopal Iyer 
15320dc2366fSVenugopal Iyer /* Tx lane total statistic specific functions */
15330dc2366fSVenugopal Iyer void *
dlstat_tx_lane_total_stats(dladm_handle_t dh,datalink_id_t linkid)15340dc2366fSVenugopal Iyer dlstat_tx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
15350dc2366fSVenugopal Iyer {
15360dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
15370dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*tx_lane_head, *curr;
15380dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*total_stats;
15390dc2366fSVenugopal Iyer 
15400dc2366fSVenugopal Iyer 	/* Get per tx lane stats */
15410dc2366fSVenugopal Iyer 	tx_lane_head = dlstat_tx_lane_stats(dh, linkid);
15420dc2366fSVenugopal Iyer 	if (tx_lane_head == NULL)
15430dc2366fSVenugopal Iyer 		goto done;
15440dc2366fSVenugopal Iyer 
15450dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (tx_lane_stat_entry_t));
15460dc2366fSVenugopal Iyer 	if (total_stats == NULL)
15470dc2366fSVenugopal Iyer 		goto done;
15480dc2366fSVenugopal Iyer 
15490dc2366fSVenugopal Iyer 	total_stats->tle_index = DLSTAT_INVALID_ENTRY;
15500dc2366fSVenugopal Iyer 	total_stats->tle_id = DLSTAT_INVALID_ENTRY;
15510dc2366fSVenugopal Iyer 
15520dc2366fSVenugopal Iyer 	for (curr = tx_lane_head; curr != NULL; curr = curr->dc_next) {
15530dc2366fSVenugopal Iyer 		tx_lane_stat_entry_t	*curr_lane_stats = curr->dc_statentry;
15540dc2366fSVenugopal Iyer 
15550dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->tle_stats,
15560dc2366fSVenugopal Iyer 		    &curr_lane_stats->tle_stats, &total_stats->tle_stats,
15570dc2366fSVenugopal Iyer 		    tx_lane_stats_list, TX_LANE_STAT_SIZE);
15580dc2366fSVenugopal Iyer 	}
15590dc2366fSVenugopal Iyer 
15600dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
15610dc2366fSVenugopal Iyer 	if (total_head == NULL) {
15620dc2366fSVenugopal Iyer 		free(total_stats);
15630dc2366fSVenugopal Iyer 		goto done;
15640dc2366fSVenugopal Iyer 	}
15650dc2366fSVenugopal Iyer 
15660dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
15670dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_tx_lane_total",
15680dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
15690dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
15700dc2366fSVenugopal Iyer 	free(tx_lane_head);
15710dc2366fSVenugopal Iyer 
15720dc2366fSVenugopal Iyer done:
15730dc2366fSVenugopal Iyer 	return (total_head);
15740dc2366fSVenugopal Iyer }
15750dc2366fSVenugopal Iyer 
15760dc2366fSVenugopal Iyer /* Fanout specific functions */
15770dc2366fSVenugopal Iyer static boolean_t
i_dlstat_fanout_match(void * arg1,void * arg2)15780dc2366fSVenugopal Iyer i_dlstat_fanout_match(void *arg1, void *arg2)
15790dc2366fSVenugopal Iyer {
15800dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s1 = arg1;
15810dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s2 = arg2;
15820dc2366fSVenugopal Iyer 
15830dc2366fSVenugopal Iyer 	return (s1->fe_index == s2->fe_index &&
15840dc2366fSVenugopal Iyer 	    s1->fe_id == s2->fe_id &&
15850dc2366fSVenugopal Iyer 	    s1->fe_foutindex == s2->fe_foutindex);
15860dc2366fSVenugopal Iyer }
15870dc2366fSVenugopal Iyer 
15880dc2366fSVenugopal Iyer static void *
i_dlstat_fanout_stat_entry_diff(void * arg1,void * arg2)15890dc2366fSVenugopal Iyer i_dlstat_fanout_stat_entry_diff(void *arg1, void *arg2)
15900dc2366fSVenugopal Iyer {
15910dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s1 = arg1;
15920dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s2 = arg2;
15930dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*diff_entry;
15940dc2366fSVenugopal Iyer 
15950dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (fanout_stat_entry_t));
15960dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
15970dc2366fSVenugopal Iyer 		goto done;
15980dc2366fSVenugopal Iyer 
15990dc2366fSVenugopal Iyer 	diff_entry->fe_index = s1->fe_index;
16000dc2366fSVenugopal Iyer 	diff_entry->fe_id = s1->fe_id;
16010dc2366fSVenugopal Iyer 	diff_entry->fe_foutindex = s1->fe_foutindex;
16020dc2366fSVenugopal Iyer 
16030dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, fe_stats, fanout_stats_list,
16040dc2366fSVenugopal Iyer 	    FANOUT_STAT_SIZE);
16050dc2366fSVenugopal Iyer 
16060dc2366fSVenugopal Iyer done:
16070dc2366fSVenugopal Iyer 	return (diff_entry);
16080dc2366fSVenugopal Iyer }
16090dc2366fSVenugopal Iyer 
16100dc2366fSVenugopal Iyer static void *
i_dlstat_fanout_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)16110dc2366fSVenugopal Iyer i_dlstat_fanout_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
16120dc2366fSVenugopal Iyer {
16130dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*fanout_stat_entry;
16140dc2366fSVenugopal Iyer 
16150dc2366fSVenugopal Iyer 	fanout_stat_entry = calloc(1, sizeof (fanout_stat_entry_t));
16160dc2366fSVenugopal Iyer 	if (fanout_stat_entry == NULL)
16170dc2366fSVenugopal Iyer 		goto done;
16180dc2366fSVenugopal Iyer 
16190dc2366fSVenugopal Iyer 					/* Set by the caller later */
16200dc2366fSVenugopal Iyer 	fanout_stat_entry->fe_index = DLSTAT_INVALID_ENTRY;
16210dc2366fSVenugopal Iyer 	fanout_stat_entry->fe_id = DLSTAT_INVALID_ENTRY;
16220dc2366fSVenugopal Iyer 
16230dc2366fSVenugopal Iyer 	fanout_stat_entry->fe_foutindex = i;
16240dc2366fSVenugopal Iyer 
16250dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &fanout_stat_entry->fe_stats,
16260dc2366fSVenugopal Iyer 	    fanout_stats_list, FANOUT_STAT_SIZE);
16270dc2366fSVenugopal Iyer 
16280dc2366fSVenugopal Iyer done:
16290dc2366fSVenugopal Iyer 	return (fanout_stat_entry);
16300dc2366fSVenugopal Iyer }
16310dc2366fSVenugopal Iyer 
16320dc2366fSVenugopal Iyer 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)16330dc2366fSVenugopal Iyer i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid,
16340dc2366fSVenugopal Iyer     uint_t idlist[], uint_t idlist_size,
16350dc2366fSVenugopal Iyer     const char *modname, const char *prefix)
16360dc2366fSVenugopal Iyer {
1637*4202e8bfSToomas Soome 	uint_t			i;
16380dc2366fSVenugopal Iyer 	char			statprefix[MAXLINKNAMELEN];
16390dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
16400dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr, *curr_head;
16410dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL, *prev = NULL;
16420dc2366fSVenugopal Iyer 	uint_t			fanout_idlist[MAX_RINGS_PER_GROUP];
16430dc2366fSVenugopal Iyer 	uint_t			fanout_idlist_size;
16440dc2366fSVenugopal Iyer 
16450dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
16460dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
16470dc2366fSVenugopal Iyer 		return (NULL);
16480dc2366fSVenugopal Iyer 	}
16490dc2366fSVenugopal Iyer 
1650399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(dh, linkname, DLSTAT_FANOUT_IDLIST,
16510dc2366fSVenugopal Iyer 	    fanout_idlist, &fanout_idlist_size);
16520dc2366fSVenugopal Iyer 
16530dc2366fSVenugopal Iyer 	for (i = 0; i < idlist_size; i++) {
16540dc2366fSVenugopal Iyer 		uint_t	index = idlist[i];
16550dc2366fSVenugopal Iyer 
16560dc2366fSVenugopal Iyer 		(void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout",
16570dc2366fSVenugopal Iyer 		    prefix, index);
16580dc2366fSVenugopal Iyer 
1659399dcf08Scarlos antonio neira bustos 		curr_head = i_dlstat_query_stats(dh, modname, statprefix,
16600dc2366fSVenugopal Iyer 		    fanout_idlist, fanout_idlist_size,
16610dc2366fSVenugopal Iyer 		    i_dlstat_fanout_retrieve_stat);
16620dc2366fSVenugopal Iyer 
16630dc2366fSVenugopal Iyer 		if (curr_head == NULL)	/* Last lane */
16640dc2366fSVenugopal Iyer 			break;
16650dc2366fSVenugopal Iyer 
16660dc2366fSVenugopal Iyer 		if (head == NULL)	/* First lane */
16670dc2366fSVenugopal Iyer 			head = curr_head;
16680dc2366fSVenugopal Iyer 		else	/* Link new lane list to end of previous lane list */
16690dc2366fSVenugopal Iyer 			prev->dc_next = curr_head;
16700dc2366fSVenugopal Iyer 
16710dc2366fSVenugopal Iyer 		/* Walk new lane list and set ids */
16720dc2366fSVenugopal Iyer 		for (curr = curr_head; curr != NULL; curr = curr->dc_next) {
16730dc2366fSVenugopal Iyer 			fanout_stat_entry_t *curr_stats = curr->dc_statentry;
16740dc2366fSVenugopal Iyer 
16750dc2366fSVenugopal Iyer 			curr_stats->fe_index = index;
16760dc2366fSVenugopal Iyer 			curr_stats->fe_id = L_HWLANE;
16770dc2366fSVenugopal Iyer 			/*
16780dc2366fSVenugopal Iyer 			 * Save last pointer of previous linked list.
16790dc2366fSVenugopal Iyer 			 * This pointer is used to chain linked lists
16800dc2366fSVenugopal Iyer 			 * generated in each iteration.
16810dc2366fSVenugopal Iyer 			 */
16820dc2366fSVenugopal Iyer 			prev = curr;
16830dc2366fSVenugopal Iyer 		}
16840dc2366fSVenugopal Iyer 	}
16850dc2366fSVenugopal Iyer 
16860dc2366fSVenugopal Iyer 	return (head);
16870dc2366fSVenugopal Iyer }
16880dc2366fSVenugopal Iyer 
16890dc2366fSVenugopal Iyer void *
dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh,datalink_id_t linkid,const char * linkname)16900dc2366fSVenugopal Iyer dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid,
16910dc2366fSVenugopal Iyer     const char *linkname)
16920dc2366fSVenugopal Iyer {
16930dc2366fSVenugopal Iyer 	return (i_dlstat_query_fanout_stats(dh, linkid,
16940dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size, linkname,
16950dc2366fSVenugopal Iyer 	    DLSTAT_MAC_RX_SWLANE));
16960dc2366fSVenugopal Iyer }
16970dc2366fSVenugopal Iyer 
16980dc2366fSVenugopal Iyer void *
dlstat_fanout_hwlane_stats(dladm_handle_t dh,datalink_id_t linkid,const char * linkname)16990dc2366fSVenugopal Iyer dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid,
17000dc2366fSVenugopal Iyer     const char *linkname)
17010dc2366fSVenugopal Iyer {
17020dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
17030dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist_size;
17040dc2366fSVenugopal Iyer 
1705399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(dh, linkname, DLSTAT_RX_HWLANE_IDLIST,
17060dc2366fSVenugopal Iyer 	    rx_hwlane_idlist, &rx_hwlane_idlist_size);
17070dc2366fSVenugopal Iyer 
17080dc2366fSVenugopal Iyer 	return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist,
17090dc2366fSVenugopal Iyer 	    rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE));
17100dc2366fSVenugopal Iyer }
17110dc2366fSVenugopal Iyer 
17120dc2366fSVenugopal Iyer void *
dlstat_fanout_stats(dladm_handle_t dh,datalink_id_t linkid)17130dc2366fSVenugopal Iyer dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid)
17140dc2366fSVenugopal Iyer {
17150dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
17160dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*fout_hwlane_stats;
17170dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*fout_swlane_and_local_stats;
17180dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*fout_stats;
17190dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
17200dc2366fSVenugopal Iyer 
17210dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
17220dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
17230dc2366fSVenugopal Iyer 		goto done;
17240dc2366fSVenugopal Iyer 	}
17250dc2366fSVenugopal Iyer 
17260dc2366fSVenugopal Iyer 	fout_swlane_and_local_stats =
17270dc2366fSVenugopal Iyer 	    dlstat_fanout_swlane_and_local_stats(dh, linkid, linkname);
17280dc2366fSVenugopal Iyer 	fout_hwlane_stats = dlstat_fanout_hwlane_stats(dh, linkid, linkname);
17290dc2366fSVenugopal Iyer 
17300dc2366fSVenugopal Iyer 	if (fout_swlane_and_local_stats == NULL) {
17310dc2366fSVenugopal Iyer 		head = fout_hwlane_stats;
17320dc2366fSVenugopal Iyer 		goto done;
17330dc2366fSVenugopal Iyer 	}
17340dc2366fSVenugopal Iyer 
17350dc2366fSVenugopal Iyer 	fout_stats = fout_swlane_and_local_stats->dc_statentry;
17360dc2366fSVenugopal Iyer 
17370dc2366fSVenugopal Iyer 	if (fout_hwlane_stats != NULL) { /* hwlane(s), only local traffic */
17380dc2366fSVenugopal Iyer 		fout_stats->fe_id = L_LOCAL;
17390dc2366fSVenugopal Iyer 		fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
17400dc2366fSVenugopal Iyer 	} else { /* no hwlane, mix of local+sw classified */
17410dc2366fSVenugopal Iyer 		fout_stats->fe_id = L_LCLSWLANE;
17420dc2366fSVenugopal Iyer 		fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
17430dc2366fSVenugopal Iyer 	}
17440dc2366fSVenugopal Iyer 
17450dc2366fSVenugopal Iyer 	fout_swlane_and_local_stats->dc_next = fout_hwlane_stats;
17460dc2366fSVenugopal Iyer 	head = fout_swlane_and_local_stats;
17470dc2366fSVenugopal Iyer 
17480dc2366fSVenugopal Iyer done:
17490dc2366fSVenugopal Iyer 	return (head);
17500dc2366fSVenugopal Iyer }
17510dc2366fSVenugopal Iyer 
17520dc2366fSVenugopal Iyer /* Rx ring statistic specific functions */
17530dc2366fSVenugopal Iyer static boolean_t
i_dlstat_rx_ring_match(void * arg1,void * arg2)17540dc2366fSVenugopal Iyer i_dlstat_rx_ring_match(void *arg1, void *arg2)
17550dc2366fSVenugopal Iyer {
17560dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*s1 = arg1;
17570dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*s2 = arg2;
17580dc2366fSVenugopal Iyer 
17590dc2366fSVenugopal Iyer 	return (s1->rle_index == s2->rle_index);
17600dc2366fSVenugopal Iyer }
17610dc2366fSVenugopal Iyer 
17620dc2366fSVenugopal Iyer static void *
i_dlstat_rx_ring_stat_entry_diff(void * arg1,void * arg2)17630dc2366fSVenugopal Iyer i_dlstat_rx_ring_stat_entry_diff(void *arg1, void *arg2)
17640dc2366fSVenugopal Iyer {
17650dc2366fSVenugopal Iyer 	ring_stat_entry_t	*s1 = arg1;
17660dc2366fSVenugopal Iyer 	ring_stat_entry_t	*s2 = arg2;
17670dc2366fSVenugopal Iyer 	ring_stat_entry_t	*diff_entry;
17680dc2366fSVenugopal Iyer 
17690dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (ring_stat_entry_t));
17700dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
17710dc2366fSVenugopal Iyer 		goto done;
17720dc2366fSVenugopal Iyer 
17730dc2366fSVenugopal Iyer 	diff_entry->re_index	= s1->re_index;
17740dc2366fSVenugopal Iyer 
17750dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, rx_ring_stats_list,
17760dc2366fSVenugopal Iyer 	    RX_RING_STAT_SIZE);
17770dc2366fSVenugopal Iyer 
17780dc2366fSVenugopal Iyer done:
17790dc2366fSVenugopal Iyer 	return (diff_entry);
17800dc2366fSVenugopal Iyer }
17810dc2366fSVenugopal Iyer 
17820dc2366fSVenugopal Iyer static void *
i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)17830dc2366fSVenugopal Iyer i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
17840dc2366fSVenugopal Iyer {
17850dc2366fSVenugopal Iyer 	ring_stat_entry_t	*rx_ring_stat_entry;
17860dc2366fSVenugopal Iyer 
17870dc2366fSVenugopal Iyer 	rx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
17880dc2366fSVenugopal Iyer 	if (rx_ring_stat_entry == NULL)
17890dc2366fSVenugopal Iyer 		goto done;
17900dc2366fSVenugopal Iyer 
17910dc2366fSVenugopal Iyer 	rx_ring_stat_entry->re_index	= i;
17920dc2366fSVenugopal Iyer 
17930dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_ring_stat_entry->re_stats,
17940dc2366fSVenugopal Iyer 	    rx_ring_stats_list, RX_RING_STAT_SIZE);
17950dc2366fSVenugopal Iyer 
17960dc2366fSVenugopal Iyer done:
17970dc2366fSVenugopal Iyer 	return (rx_ring_stat_entry);
17980dc2366fSVenugopal Iyer }
17990dc2366fSVenugopal Iyer 
18000dc2366fSVenugopal Iyer void *
dlstat_rx_ring_stats(dladm_handle_t dh,datalink_id_t linkid)18010dc2366fSVenugopal Iyer dlstat_rx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
18020dc2366fSVenugopal Iyer {
18030dc2366fSVenugopal Iyer 	uint_t			rx_ring_idlist[MAX_RINGS_PER_GROUP];
18040dc2366fSVenugopal Iyer 	uint_t			rx_ring_idlist_size;
18050dc2366fSVenugopal Iyer 	dladm_phys_attr_t	dpa;
18060dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
18070dc2366fSVenugopal Iyer 	char			*modname;
18080dc2366fSVenugopal Iyer 	datalink_class_t	class;
18090dc2366fSVenugopal Iyer 
18100dc2366fSVenugopal Iyer 	/*
18110dc2366fSVenugopal Iyer 	 * kstats corresponding to physical device rings continue to use
18120dc2366fSVenugopal Iyer 	 * device names even if the link is renamed using dladm rename-link.
18130dc2366fSVenugopal Iyer 	 * Thus, given a linkid, we lookup the physical device name.
18140dc2366fSVenugopal Iyer 	 * However, if an aggr is renamed, kstats corresponding to its
18150dc2366fSVenugopal Iyer 	 * pseudo rings are renamed as well.
18160dc2366fSVenugopal Iyer 	 */
18170dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
18180dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
18190dc2366fSVenugopal Iyer 		return (NULL);
18200dc2366fSVenugopal Iyer 	}
18210dc2366fSVenugopal Iyer 
18220dc2366fSVenugopal Iyer 	if (class != DATALINK_CLASS_AGGR) {
18230dc2366fSVenugopal Iyer 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
18240dc2366fSVenugopal Iyer 		    DLADM_STATUS_OK) {
18250dc2366fSVenugopal Iyer 			return (NULL);
18260dc2366fSVenugopal Iyer 		}
18270dc2366fSVenugopal Iyer 		modname = dpa.dp_dev;
18280dc2366fSVenugopal Iyer 	} else
18290dc2366fSVenugopal Iyer 		modname = linkname;
18300dc2366fSVenugopal Iyer 
1831399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(dh, modname, DLSTAT_RX_RING_IDLIST,
18320dc2366fSVenugopal Iyer 	    rx_ring_idlist, &rx_ring_idlist_size);
18330dc2366fSVenugopal Iyer 
1834399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_RX_RING,
18350dc2366fSVenugopal Iyer 	    rx_ring_idlist, rx_ring_idlist_size,
18360dc2366fSVenugopal Iyer 	    i_dlstat_rx_ring_retrieve_stat));
18370dc2366fSVenugopal Iyer }
18380dc2366fSVenugopal Iyer 
18390dc2366fSVenugopal Iyer /* Tx ring statistic specific functions */
18400dc2366fSVenugopal Iyer static boolean_t
i_dlstat_tx_ring_match(void * arg1,void * arg2)18410dc2366fSVenugopal Iyer i_dlstat_tx_ring_match(void *arg1, void *arg2)
18420dc2366fSVenugopal Iyer {
18430dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*s1 = arg1;
18440dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*s2 = arg2;
18450dc2366fSVenugopal Iyer 
18460dc2366fSVenugopal Iyer 	return (s1->tle_index == s2->tle_index);
18470dc2366fSVenugopal Iyer }
18480dc2366fSVenugopal Iyer 
18490dc2366fSVenugopal Iyer static void *
i_dlstat_tx_ring_stat_entry_diff(void * arg1,void * arg2)18500dc2366fSVenugopal Iyer i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2)
18510dc2366fSVenugopal Iyer {
18520dc2366fSVenugopal Iyer 	ring_stat_entry_t	*s1 = arg1;
18530dc2366fSVenugopal Iyer 	ring_stat_entry_t	*s2 = arg2;
18540dc2366fSVenugopal Iyer 	ring_stat_entry_t	*diff_entry;
18550dc2366fSVenugopal Iyer 
18560dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (ring_stat_entry_t));
18570dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
18580dc2366fSVenugopal Iyer 		goto done;
18590dc2366fSVenugopal Iyer 
18600dc2366fSVenugopal Iyer 	diff_entry->re_index	= s1->re_index;
18610dc2366fSVenugopal Iyer 
18620dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, tx_ring_stats_list,
18630dc2366fSVenugopal Iyer 	    TX_RING_STAT_SIZE);
18640dc2366fSVenugopal Iyer 
18650dc2366fSVenugopal Iyer done:
18660dc2366fSVenugopal Iyer 	return (diff_entry);
18670dc2366fSVenugopal Iyer }
18680dc2366fSVenugopal Iyer 
18690dc2366fSVenugopal Iyer static void *
i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)18700dc2366fSVenugopal Iyer i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
18710dc2366fSVenugopal Iyer {
18720dc2366fSVenugopal Iyer 	ring_stat_entry_t	*tx_ring_stat_entry;
18730dc2366fSVenugopal Iyer 
18740dc2366fSVenugopal Iyer 	tx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
18750dc2366fSVenugopal Iyer 	if (tx_ring_stat_entry == NULL)
18760dc2366fSVenugopal Iyer 		goto done;
18770dc2366fSVenugopal Iyer 
18780dc2366fSVenugopal Iyer 	tx_ring_stat_entry->re_index	= i;
18790dc2366fSVenugopal Iyer 
18800dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &tx_ring_stat_entry->re_stats,
18810dc2366fSVenugopal Iyer 	    tx_ring_stats_list, TX_RING_STAT_SIZE);
18820dc2366fSVenugopal Iyer 
18830dc2366fSVenugopal Iyer done:
18840dc2366fSVenugopal Iyer 	return (tx_ring_stat_entry);
18850dc2366fSVenugopal Iyer }
18860dc2366fSVenugopal Iyer 
18870dc2366fSVenugopal Iyer void *
dlstat_tx_ring_stats(dladm_handle_t dh,datalink_id_t linkid)18880dc2366fSVenugopal Iyer dlstat_tx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
18890dc2366fSVenugopal Iyer {
18900dc2366fSVenugopal Iyer 	uint_t			tx_ring_idlist[MAX_RINGS_PER_GROUP];
18910dc2366fSVenugopal Iyer 	uint_t			tx_ring_idlist_size;
18920dc2366fSVenugopal Iyer 	dladm_phys_attr_t	dpa;
18930dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
18940dc2366fSVenugopal Iyer 	char			*modname;
18950dc2366fSVenugopal Iyer 	datalink_class_t	class;
18960dc2366fSVenugopal Iyer 
18970dc2366fSVenugopal Iyer 	/*
18980dc2366fSVenugopal Iyer 	 * kstats corresponding to physical device rings continue to use
18990dc2366fSVenugopal Iyer 	 * device names even if the link is renamed using dladm rename-link.
19000dc2366fSVenugopal Iyer 	 * Thus, given a linkid, we lookup the physical device name.
19010dc2366fSVenugopal Iyer 	 * However, if an aggr is renamed, kstats corresponding to its
19020dc2366fSVenugopal Iyer 	 * pseudo rings are renamed as well.
19030dc2366fSVenugopal Iyer 	 */
19040dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
19050dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
19060dc2366fSVenugopal Iyer 		return (NULL);
19070dc2366fSVenugopal Iyer 	}
19080dc2366fSVenugopal Iyer 
19090dc2366fSVenugopal Iyer 	if (class != DATALINK_CLASS_AGGR) {
19100dc2366fSVenugopal Iyer 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
19110dc2366fSVenugopal Iyer 		    DLADM_STATUS_OK) {
19120dc2366fSVenugopal Iyer 			return (NULL);
19130dc2366fSVenugopal Iyer 		}
19140dc2366fSVenugopal Iyer 		modname = dpa.dp_dev;
19150dc2366fSVenugopal Iyer 	} else
19160dc2366fSVenugopal Iyer 		modname = linkname;
19170dc2366fSVenugopal Iyer 
1918399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(dh, modname, DLSTAT_TX_RING_IDLIST,
19190dc2366fSVenugopal Iyer 	    tx_ring_idlist, &tx_ring_idlist_size);
19200dc2366fSVenugopal Iyer 
1921399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_TX_RING,
19220dc2366fSVenugopal Iyer 	    tx_ring_idlist, tx_ring_idlist_size,
19230dc2366fSVenugopal Iyer 	    i_dlstat_tx_ring_retrieve_stat));
19240dc2366fSVenugopal Iyer }
19250dc2366fSVenugopal Iyer 
19260dc2366fSVenugopal Iyer /* Rx ring total statistic specific functions */
19270dc2366fSVenugopal Iyer void *
dlstat_rx_ring_total_stats(dladm_handle_t dh,datalink_id_t linkid)19280dc2366fSVenugopal Iyer dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
19290dc2366fSVenugopal Iyer {
19300dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
19310dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*rx_ring_head, *curr;
19320dc2366fSVenugopal Iyer 	ring_stat_entry_t	*total_stats;
19330dc2366fSVenugopal Iyer 
19340dc2366fSVenugopal Iyer 	/* Get per rx ring stats */
19350dc2366fSVenugopal Iyer 	rx_ring_head = dlstat_rx_ring_stats(dh, linkid);
19360dc2366fSVenugopal Iyer 	if (rx_ring_head == NULL)
19370dc2366fSVenugopal Iyer 		goto done;
19380dc2366fSVenugopal Iyer 
19390dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (ring_stat_entry_t));
19400dc2366fSVenugopal Iyer 	if (total_stats == NULL)
19410dc2366fSVenugopal Iyer 		goto done;
19420dc2366fSVenugopal Iyer 
19430dc2366fSVenugopal Iyer 	total_stats->re_index = DLSTAT_INVALID_ENTRY;
19440dc2366fSVenugopal Iyer 
19450dc2366fSVenugopal Iyer 	for (curr = rx_ring_head; curr != NULL; curr = curr->dc_next) {
19460dc2366fSVenugopal Iyer 		ring_stat_entry_t	*curr_ring_stats = curr->dc_statentry;
19470dc2366fSVenugopal Iyer 
19480dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->re_stats,
19490dc2366fSVenugopal Iyer 		    &curr_ring_stats->re_stats, &total_stats->re_stats,
19500dc2366fSVenugopal Iyer 		    rx_ring_stats_list, RX_RING_STAT_SIZE);
19510dc2366fSVenugopal Iyer 	}
19520dc2366fSVenugopal Iyer 
19530dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
19540dc2366fSVenugopal Iyer 	if (total_head == NULL) {
19550dc2366fSVenugopal Iyer 		free(total_stats);
19560dc2366fSVenugopal Iyer 		goto done;
19570dc2366fSVenugopal Iyer 	}
19580dc2366fSVenugopal Iyer 
19590dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
19600dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_rx_ring_total",
19610dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
19620dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
19630dc2366fSVenugopal Iyer 	free(rx_ring_head);
19640dc2366fSVenugopal Iyer 
19650dc2366fSVenugopal Iyer done:
19660dc2366fSVenugopal Iyer 	return (total_head);
19670dc2366fSVenugopal Iyer }
19680dc2366fSVenugopal Iyer 
19690dc2366fSVenugopal Iyer /* Tx ring total statistic specific functions */
19700dc2366fSVenugopal Iyer void *
dlstat_tx_ring_total_stats(dladm_handle_t dh,datalink_id_t linkid)19710dc2366fSVenugopal Iyer dlstat_tx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
19720dc2366fSVenugopal Iyer {
19730dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
19740dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*tx_ring_head, *curr;
19750dc2366fSVenugopal Iyer 	ring_stat_entry_t	*total_stats;
19760dc2366fSVenugopal Iyer 
19770dc2366fSVenugopal Iyer 	/* Get per tx ring stats */
19780dc2366fSVenugopal Iyer 	tx_ring_head = dlstat_tx_ring_stats(dh, linkid);
19790dc2366fSVenugopal Iyer 	if (tx_ring_head == NULL)
19800dc2366fSVenugopal Iyer 		goto done;
19810dc2366fSVenugopal Iyer 
19820dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (ring_stat_entry_t));
19830dc2366fSVenugopal Iyer 	if (total_stats == NULL)
19840dc2366fSVenugopal Iyer 		goto done;
19850dc2366fSVenugopal Iyer 
19860dc2366fSVenugopal Iyer 	total_stats->re_index = DLSTAT_INVALID_ENTRY;
19870dc2366fSVenugopal Iyer 
19880dc2366fSVenugopal Iyer 	for (curr = tx_ring_head; curr != NULL; curr = curr->dc_next) {
19890dc2366fSVenugopal Iyer 		ring_stat_entry_t	*curr_ring_stats = curr->dc_statentry;
19900dc2366fSVenugopal Iyer 
19910dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->re_stats,
19920dc2366fSVenugopal Iyer 		    &curr_ring_stats->re_stats, &total_stats->re_stats,
19930dc2366fSVenugopal Iyer 		    tx_ring_stats_list, TX_RING_STAT_SIZE);
19940dc2366fSVenugopal Iyer 	}
19950dc2366fSVenugopal Iyer 
19960dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
19970dc2366fSVenugopal Iyer 	if (total_head == NULL) {
19980dc2366fSVenugopal Iyer 		free(total_stats);
19990dc2366fSVenugopal Iyer 		goto done;
20000dc2366fSVenugopal Iyer 	}
20010dc2366fSVenugopal Iyer 
20020dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
20030dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_tx_ring_total",
20040dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
20050dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
20060dc2366fSVenugopal Iyer 	free(tx_ring_head);
20070dc2366fSVenugopal Iyer 
20080dc2366fSVenugopal Iyer done:
20090dc2366fSVenugopal Iyer 	return (total_head);
20100dc2366fSVenugopal Iyer }
20110dc2366fSVenugopal Iyer 
20120dc2366fSVenugopal Iyer /* Summary statistic specific functions */
20130dc2366fSVenugopal Iyer static boolean_t
i_dlstat_total_match(void * arg1 __unused,void * arg2 __unused)201420535e13SToomas Soome i_dlstat_total_match(void *arg1 __unused, void *arg2 __unused)
201562ef8476SYuri Pankov {
201662ef8476SYuri Pankov 	/* Always single entry for total */
20170dc2366fSVenugopal Iyer 	return (B_TRUE);
20180dc2366fSVenugopal Iyer }
20190dc2366fSVenugopal Iyer 
20200dc2366fSVenugopal Iyer static void *
i_dlstat_total_stat_entry_diff(void * arg1,void * arg2)20210dc2366fSVenugopal Iyer i_dlstat_total_stat_entry_diff(void *arg1, void *arg2)
20220dc2366fSVenugopal Iyer {
20230dc2366fSVenugopal Iyer 	total_stat_entry_t	*s1 = arg1;
20240dc2366fSVenugopal Iyer 	total_stat_entry_t	*s2 = arg2;
20250dc2366fSVenugopal Iyer 	total_stat_entry_t	*diff_entry;
20260dc2366fSVenugopal Iyer 
20270dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (total_stat_entry_t));
20280dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
20290dc2366fSVenugopal Iyer 		goto done;
20300dc2366fSVenugopal Iyer 
20310dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, tse_stats, total_stats_list,
20320dc2366fSVenugopal Iyer 	    TOTAL_STAT_SIZE);
20330dc2366fSVenugopal Iyer 
20340dc2366fSVenugopal Iyer done:
20350dc2366fSVenugopal Iyer 	return (diff_entry);
20360dc2366fSVenugopal Iyer }
20370dc2366fSVenugopal Iyer 
20380dc2366fSVenugopal Iyer void *
dlstat_total_stats(dladm_handle_t dh,datalink_id_t linkid)20390dc2366fSVenugopal Iyer dlstat_total_stats(dladm_handle_t dh, datalink_id_t linkid)
20400dc2366fSVenugopal Iyer {
20410dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
20420dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*rx_total;
20430dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*tx_total;
20440dc2366fSVenugopal Iyer 	total_stat_entry_t	*total_stat_entry;
20450dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
20460dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
20470dc2366fSVenugopal Iyer 
20480dc2366fSVenugopal Iyer 	/* Get total rx lane stats */
20490dc2366fSVenugopal Iyer 	rx_total = dlstat_rx_lane_total_stats(dh, linkid);
20500dc2366fSVenugopal Iyer 	if (rx_total == NULL)
20510dc2366fSVenugopal Iyer 		goto done;
20520dc2366fSVenugopal Iyer 
20530dc2366fSVenugopal Iyer 	/* Get total tx lane stats */
20540dc2366fSVenugopal Iyer 	tx_total = dlstat_tx_lane_total_stats(dh, linkid);
20550dc2366fSVenugopal Iyer 	if (tx_total == NULL)
20560dc2366fSVenugopal Iyer 		goto done;
20570dc2366fSVenugopal Iyer 
20580dc2366fSVenugopal Iyer 	/* Build total stat */
20590dc2366fSVenugopal Iyer 	total_stat_entry = calloc(1, sizeof (total_stat_entry_t));
20600dc2366fSVenugopal Iyer 	if (total_stat_entry == NULL)
20610dc2366fSVenugopal Iyer 		goto done;
20620dc2366fSVenugopal Iyer 
20630dc2366fSVenugopal Iyer 	rx_lane_stat_entry = rx_total->dc_statentry;
20640dc2366fSVenugopal Iyer 	tx_lane_stat_entry = tx_total->dc_statentry;
20650dc2366fSVenugopal Iyer 
20660dc2366fSVenugopal Iyer 	/* Extract total rx ipackets, rbytes */
20670dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_ipackets =
20680dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_ipackets;
20690dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_rbytes =
20700dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_rbytes;
20710dc2366fSVenugopal Iyer 
20720dc2366fSVenugopal Iyer 	/* Extract total tx opackets, obytes */
20730dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_opackets =
20740dc2366fSVenugopal Iyer 	    tx_lane_stat_entry->tle_stats.tl_opackets;
20750dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_obytes =
20760dc2366fSVenugopal Iyer 	    tx_lane_stat_entry->tle_stats.tl_obytes;
20770dc2366fSVenugopal Iyer 
20780dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
20790dc2366fSVenugopal Iyer 	if (head == NULL) {
20800dc2366fSVenugopal Iyer 		free(total_stat_entry);
20810dc2366fSVenugopal Iyer 		goto done;
20820dc2366fSVenugopal Iyer 	}
20830dc2366fSVenugopal Iyer 
20840dc2366fSVenugopal Iyer 	head->dc_statentry = total_stat_entry;
20850dc2366fSVenugopal Iyer 	(void) strlcpy(head->dc_statheader, "mac_lane_total",
20860dc2366fSVenugopal Iyer 	    sizeof (head->dc_statheader));
20870dc2366fSVenugopal Iyer 	head->dc_next = NULL;
20880dc2366fSVenugopal Iyer 	free(rx_total);
20890dc2366fSVenugopal Iyer 	free(tx_total);
20900dc2366fSVenugopal Iyer 
20910dc2366fSVenugopal Iyer done:
20920dc2366fSVenugopal Iyer 	return (head);
20930dc2366fSVenugopal Iyer }
20940dc2366fSVenugopal Iyer 
20950dc2366fSVenugopal Iyer /* Aggr total statistic(summed across all component ports) specific functions */
20960dc2366fSVenugopal Iyer void *
dlstat_aggr_total_stats(dladm_stat_chain_t * head)20970dc2366fSVenugopal Iyer dlstat_aggr_total_stats(dladm_stat_chain_t *head)
20980dc2366fSVenugopal Iyer {
20990dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
2100f7952617SToomas Soome 	dladm_stat_chain_t	*total_head = NULL;
21010dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*total_stats;
21020dc2366fSVenugopal Iyer 
21030dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (aggr_port_stat_entry_t));
21040dc2366fSVenugopal Iyer 	if (total_stats == NULL)
21050dc2366fSVenugopal Iyer 		goto done;
21060dc2366fSVenugopal Iyer 
21070dc2366fSVenugopal Iyer 	total_stats->ape_portlinkid = DATALINK_INVALID_LINKID;
21080dc2366fSVenugopal Iyer 
21090dc2366fSVenugopal Iyer 	for (curr = head; curr != NULL; curr = curr->dc_next) {
21100dc2366fSVenugopal Iyer 		aggr_port_stat_entry_t	*curr_aggr_port_stats;
21110dc2366fSVenugopal Iyer 
21120dc2366fSVenugopal Iyer 		curr_aggr_port_stats = curr->dc_statentry;
21130dc2366fSVenugopal Iyer 
21140dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->ape_stats,
21150dc2366fSVenugopal Iyer 		    &curr_aggr_port_stats->ape_stats, &total_stats->ape_stats,
21160dc2366fSVenugopal Iyer 		    aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
21170dc2366fSVenugopal Iyer 	}
21180dc2366fSVenugopal Iyer 
21190dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
21200dc2366fSVenugopal Iyer 	if (total_head == NULL) {
21210dc2366fSVenugopal Iyer 		free(total_stats);
21220dc2366fSVenugopal Iyer 		goto done;
21230dc2366fSVenugopal Iyer 	}
21240dc2366fSVenugopal Iyer 
21250dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
21260dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
21270dc2366fSVenugopal Iyer 
21280dc2366fSVenugopal Iyer done:
21290dc2366fSVenugopal Iyer 	return (total_head);
21300dc2366fSVenugopal Iyer }
21310dc2366fSVenugopal Iyer 
21320dc2366fSVenugopal Iyer /* Aggr port statistic specific functions */
21330dc2366fSVenugopal Iyer static boolean_t
i_dlstat_aggr_port_match(void * arg1,void * arg2)21340dc2366fSVenugopal Iyer i_dlstat_aggr_port_match(void *arg1, void *arg2)
21350dc2366fSVenugopal Iyer {
21360dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t *s1 = arg1;
21370dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t *s2 = arg2;
21380dc2366fSVenugopal Iyer 
21390dc2366fSVenugopal Iyer 	return (s1->ape_portlinkid == s2->ape_portlinkid);
21400dc2366fSVenugopal Iyer }
21410dc2366fSVenugopal Iyer 
21420dc2366fSVenugopal Iyer static void *
i_dlstat_aggr_port_stat_entry_diff(void * arg1,void * arg2)21430dc2366fSVenugopal Iyer i_dlstat_aggr_port_stat_entry_diff(void *arg1, void *arg2)
21440dc2366fSVenugopal Iyer {
21450dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*s1 = arg1;
21460dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*s2 = arg2;
21470dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*diff_entry;
21480dc2366fSVenugopal Iyer 
21490dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (aggr_port_stat_entry_t));
21500dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
21510dc2366fSVenugopal Iyer 		goto done;
21520dc2366fSVenugopal Iyer 
21530dc2366fSVenugopal Iyer 	diff_entry->ape_portlinkid = s1->ape_portlinkid;
21540dc2366fSVenugopal Iyer 
21550dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list,
21560dc2366fSVenugopal Iyer 	    AGGR_PORT_STAT_SIZE);
21570dc2366fSVenugopal Iyer 
21580dc2366fSVenugopal Iyer done:
21590dc2366fSVenugopal Iyer 	return (diff_entry);
21600dc2366fSVenugopal Iyer }
21610dc2366fSVenugopal Iyer 
21620dc2366fSVenugopal Iyer /*
21630dc2366fSVenugopal Iyer  * Query dls stats for the aggr port. This results in query for stats into
21640dc2366fSVenugopal Iyer  * the corresponding device driver.
21650dc2366fSVenugopal Iyer  */
21660dc2366fSVenugopal Iyer static aggr_port_stat_entry_t *
i_dlstat_single_port_stats(dladm_handle_t handle,const char * portname,datalink_id_t linkid)2167399dcf08Scarlos antonio neira bustos i_dlstat_single_port_stats(dladm_handle_t handle, const char *portname,
2168399dcf08Scarlos antonio neira bustos     datalink_id_t linkid)
21690dc2366fSVenugopal Iyer {
21700dc2366fSVenugopal Iyer 	kstat_t			*ksp;
21710dc2366fSVenugopal Iyer 	char			module[DLPI_LINKNAME_MAX];
21720dc2366fSVenugopal Iyer 	uint_t			instance;
21730dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*aggr_port_stat_entry = NULL;
21740dc2366fSVenugopal Iyer 
21750dc2366fSVenugopal Iyer 	if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK)
21760dc2366fSVenugopal Iyer 		goto done;
21770dc2366fSVenugopal Iyer 
2178399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(handle) == NULL) {
21790dc2366fSVenugopal Iyer 		warn("kstat open operation failed");
21800dc2366fSVenugopal Iyer 		return (NULL);
21810dc2366fSVenugopal Iyer 	}
21820dc2366fSVenugopal Iyer 
2183399dcf08Scarlos antonio neira bustos 	ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), module, instance,
2184399dcf08Scarlos antonio neira bustos 	    "mac", NULL);
21850dc2366fSVenugopal Iyer 	if (ksp == NULL)
21860dc2366fSVenugopal Iyer 		goto done;
21870dc2366fSVenugopal Iyer 
21880dc2366fSVenugopal Iyer 	aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t));
21890dc2366fSVenugopal Iyer 	if (aggr_port_stat_entry == NULL)
21900dc2366fSVenugopal Iyer 		goto done;
21910dc2366fSVenugopal Iyer 
21920dc2366fSVenugopal Iyer 	/* Save port's linkid */
21930dc2366fSVenugopal Iyer 	aggr_port_stat_entry->ape_portlinkid = linkid;
21940dc2366fSVenugopal Iyer 
2195399dcf08Scarlos antonio neira bustos 	i_dlstat_get_stats(dladm_dld_kcp(handle), ksp,
2196399dcf08Scarlos antonio neira bustos 	    &aggr_port_stat_entry->ape_stats,
21970dc2366fSVenugopal Iyer 	    aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
21980dc2366fSVenugopal Iyer done:
21990dc2366fSVenugopal Iyer 	return (aggr_port_stat_entry);
22000dc2366fSVenugopal Iyer }
22010dc2366fSVenugopal Iyer 
22020dc2366fSVenugopal Iyer void *
dlstat_aggr_port_stats(dladm_handle_t dh,datalink_id_t linkid)22030dc2366fSVenugopal Iyer dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid)
22040dc2366fSVenugopal Iyer {
22050dc2366fSVenugopal Iyer 	dladm_aggr_grp_attr_t	ginfo;
2206*4202e8bfSToomas Soome 	uint_t			i;
22070dc2366fSVenugopal Iyer 	dladm_aggr_port_attr_t	 *portp;
22080dc2366fSVenugopal Iyer 	dladm_phys_attr_t	dpa;
22090dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*aggr_port_stat_entry;
22100dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL, *prev = NULL, *curr;
22110dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_stats;
22120dc2366fSVenugopal Iyer 
22130dc2366fSVenugopal Iyer 	/* Get aggr info */
22140dc2366fSVenugopal Iyer 	bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
22150dc2366fSVenugopal Iyer 	if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE)
22160dc2366fSVenugopal Iyer 	    != DLADM_STATUS_OK)
22170dc2366fSVenugopal Iyer 		goto done;
22180dc2366fSVenugopal Iyer 	/* For every port that is member of this aggr do */
22190dc2366fSVenugopal Iyer 	for (i = 0; i < ginfo.lg_nports; i++) {
22200dc2366fSVenugopal Iyer 		portp = &(ginfo.lg_ports[i]);
22210dc2366fSVenugopal Iyer 		if (dladm_phys_info(dh, portp->lp_linkid, &dpa,
22220dc2366fSVenugopal Iyer 		    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
22230dc2366fSVenugopal Iyer 			goto done;
22240dc2366fSVenugopal Iyer 		}
22250dc2366fSVenugopal Iyer 
2226399dcf08Scarlos antonio neira bustos 		aggr_port_stat_entry = i_dlstat_single_port_stats(dh,
2227399dcf08Scarlos antonio neira bustos 		    dpa.dp_dev, portp->lp_linkid);
22280dc2366fSVenugopal Iyer 
22290dc2366fSVenugopal Iyer 		/* Create dladm_stat_chain_t object for this stat */
22300dc2366fSVenugopal Iyer 		curr = malloc(sizeof (dladm_stat_chain_t));
22310dc2366fSVenugopal Iyer 		if (curr == NULL) {
22320dc2366fSVenugopal Iyer 			free(aggr_port_stat_entry);
22330dc2366fSVenugopal Iyer 			goto done;
22340dc2366fSVenugopal Iyer 		}
22350dc2366fSVenugopal Iyer 		(void) strlcpy(curr->dc_statheader, dpa.dp_dev,
22360dc2366fSVenugopal Iyer 		    sizeof (curr->dc_statheader));
22370dc2366fSVenugopal Iyer 		curr->dc_statentry = aggr_port_stat_entry;
22380dc2366fSVenugopal Iyer 		curr->dc_next = NULL;
22390dc2366fSVenugopal Iyer 
22400dc2366fSVenugopal Iyer 		/* Chain this aggr port stat entry */
22410dc2366fSVenugopal Iyer 		/* head of the stat list */
22420dc2366fSVenugopal Iyer 		if (prev == NULL)
22430dc2366fSVenugopal Iyer 			head = curr;
22440dc2366fSVenugopal Iyer 		else
22450dc2366fSVenugopal Iyer 			prev->dc_next = curr;
22460dc2366fSVenugopal Iyer 		prev = curr;
22470dc2366fSVenugopal Iyer 	}
22480dc2366fSVenugopal Iyer 
22490dc2366fSVenugopal Iyer 	/*
22500dc2366fSVenugopal Iyer 	 * Prepend the stat list with cumulative aggr stats i.e. summed over all
22510dc2366fSVenugopal Iyer 	 * component ports
22520dc2366fSVenugopal Iyer 	 */
22530dc2366fSVenugopal Iyer 	total_stats = dlstat_aggr_total_stats(head);
22540dc2366fSVenugopal Iyer 	if (total_stats != NULL) {
22550dc2366fSVenugopal Iyer 		total_stats->dc_next = head;
22560dc2366fSVenugopal Iyer 		head = total_stats;
22570dc2366fSVenugopal Iyer 	}
22580dc2366fSVenugopal Iyer 
22590dc2366fSVenugopal Iyer done:
22600dc2366fSVenugopal Iyer 	free(ginfo.lg_ports);
22610dc2366fSVenugopal Iyer 	return (head);
22620dc2366fSVenugopal Iyer }
22630dc2366fSVenugopal Iyer 
22640dc2366fSVenugopal Iyer /* Misc stat specific functions */
22650dc2366fSVenugopal Iyer void *
dlstat_misc_stats(dladm_handle_t dh,datalink_id_t linkid)22660dc2366fSVenugopal Iyer dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid)
22670dc2366fSVenugopal Iyer {
22680dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
22690dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
22700dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
22710dc2366fSVenugopal Iyer 
22720dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
22730dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
22740dc2366fSVenugopal Iyer 		goto done;
22750dc2366fSVenugopal Iyer 	}
22760dc2366fSVenugopal Iyer 
2277399dcf08Scarlos antonio neira bustos 	misc_stat_entry = i_dlstat_misc_stats(dh, linkname);
22780dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
22790dc2366fSVenugopal Iyer 		goto done;
22800dc2366fSVenugopal Iyer 
22810dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
22820dc2366fSVenugopal Iyer 	if (head == NULL) {
22830dc2366fSVenugopal Iyer 		free(misc_stat_entry);
22840dc2366fSVenugopal Iyer 		goto done;
22850dc2366fSVenugopal Iyer 	}
22860dc2366fSVenugopal Iyer 
22870dc2366fSVenugopal Iyer 	head->dc_statentry = misc_stat_entry;
22880dc2366fSVenugopal Iyer 	(void) strlcpy(head->dc_statheader, "mac_misc_stat",
22890dc2366fSVenugopal Iyer 	    sizeof (head->dc_statheader));
22900dc2366fSVenugopal Iyer 	head->dc_next = NULL;
22910dc2366fSVenugopal Iyer 
22920dc2366fSVenugopal Iyer done:
22930dc2366fSVenugopal Iyer 	return (head);
22940dc2366fSVenugopal Iyer }
22950dc2366fSVenugopal Iyer 
22960dc2366fSVenugopal Iyer /* Exported functions */
22970dc2366fSVenugopal Iyer dladm_stat_chain_t *
dladm_link_stat_query(dladm_handle_t dh,datalink_id_t linkid,dladm_stat_type_t stattype)22980dc2366fSVenugopal Iyer dladm_link_stat_query(dladm_handle_t dh, datalink_id_t linkid,
22990dc2366fSVenugopal Iyer     dladm_stat_type_t stattype)
23000dc2366fSVenugopal Iyer {
23010dc2366fSVenugopal Iyer 	return (dladm_stat_table[stattype].ds_querystat(dh, linkid));
23020dc2366fSVenugopal Iyer }
23030dc2366fSVenugopal Iyer 
23040dc2366fSVenugopal Iyer dladm_stat_chain_t *
dladm_link_stat_diffchain(dladm_stat_chain_t * op1,dladm_stat_chain_t * op2,dladm_stat_type_t stattype)23050dc2366fSVenugopal Iyer dladm_link_stat_diffchain(dladm_stat_chain_t *op1, dladm_stat_chain_t *op2,
23060dc2366fSVenugopal Iyer     dladm_stat_type_t stattype)
23070dc2366fSVenugopal Iyer {
23080dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*op1_curr, *op2_curr;
23090dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*diff_curr;
23100dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*diff_prev = NULL, *diff_head = NULL;
23110dc2366fSVenugopal Iyer 
23120dc2366fSVenugopal Iyer 				/* Perform op1 - op2, store result in diff */
23130dc2366fSVenugopal Iyer 	for (op1_curr = op1; op1_curr != NULL; op1_curr = op1_curr->dc_next) {
23140dc2366fSVenugopal Iyer 		for (op2_curr = op2; op2_curr != NULL;
23150dc2366fSVenugopal Iyer 		    op2_curr = op2_curr->dc_next) {
23160dc2366fSVenugopal Iyer 			if (dlstat_match_stats(op1_curr->dc_statentry,
23170dc2366fSVenugopal Iyer 			    op2_curr->dc_statentry, stattype)) {
23180dc2366fSVenugopal Iyer 				break;
23190dc2366fSVenugopal Iyer 			}
23200dc2366fSVenugopal Iyer 		}
23210dc2366fSVenugopal Iyer 		diff_curr = malloc(sizeof (dladm_stat_chain_t));
23220dc2366fSVenugopal Iyer 		if (diff_curr == NULL)
23230dc2366fSVenugopal Iyer 			goto done;
23240dc2366fSVenugopal Iyer 
23250dc2366fSVenugopal Iyer 		diff_curr->dc_next = NULL;
23260dc2366fSVenugopal Iyer 
23270dc2366fSVenugopal Iyer 		if (op2_curr == NULL) {
23280dc2366fSVenugopal Iyer 			/* prev iteration did not have this stat entry */
23290dc2366fSVenugopal Iyer 			diff_curr->dc_statentry =
23300dc2366fSVenugopal Iyer 			    dlstat_diff_stats(op1_curr->dc_statentry,
23310dc2366fSVenugopal Iyer 			    NULL, stattype);
23320dc2366fSVenugopal Iyer 		} else {
23330dc2366fSVenugopal Iyer 			diff_curr->dc_statentry =
23340dc2366fSVenugopal Iyer 			    dlstat_diff_stats(op1_curr->dc_statentry,
23350dc2366fSVenugopal Iyer 			    op2_curr->dc_statentry, stattype);
23360dc2366fSVenugopal Iyer 		}
23370dc2366fSVenugopal Iyer 
23380dc2366fSVenugopal Iyer 		if (diff_curr->dc_statentry == NULL) {
23390dc2366fSVenugopal Iyer 			free(diff_curr);
23400dc2366fSVenugopal Iyer 			goto done;
23410dc2366fSVenugopal Iyer 		}
23420dc2366fSVenugopal Iyer 
23430dc2366fSVenugopal Iyer 		if (diff_prev == NULL) /* head of the diff stat list */
23440dc2366fSVenugopal Iyer 			diff_head = diff_curr;
23450dc2366fSVenugopal Iyer 		else
23460dc2366fSVenugopal Iyer 			diff_prev->dc_next = diff_curr;
23470dc2366fSVenugopal Iyer 		diff_prev = diff_curr;
23480dc2366fSVenugopal Iyer 	}
23490dc2366fSVenugopal Iyer done:
23500dc2366fSVenugopal Iyer 	return (diff_head);
23510dc2366fSVenugopal Iyer }
23520dc2366fSVenugopal Iyer 
23530dc2366fSVenugopal Iyer void
dladm_link_stat_free(dladm_stat_chain_t * curr)23540dc2366fSVenugopal Iyer dladm_link_stat_free(dladm_stat_chain_t *curr)
23550dc2366fSVenugopal Iyer {
23560dc2366fSVenugopal Iyer 	while (curr != NULL) {
23570dc2366fSVenugopal Iyer 		dladm_stat_chain_t	*tofree = curr;
23580dc2366fSVenugopal Iyer 
23590dc2366fSVenugopal Iyer 		curr = curr->dc_next;
23600dc2366fSVenugopal Iyer 		free(tofree->dc_statentry);
23610dc2366fSVenugopal Iyer 		free(tofree);
23620dc2366fSVenugopal Iyer 	}
23630dc2366fSVenugopal Iyer }
23640dc2366fSVenugopal Iyer 
23650dc2366fSVenugopal Iyer /* Query all link stats */
23660dc2366fSVenugopal Iyer static name_value_stat_t *
i_dlstat_convert_stats(void * stats,stat_info_t stats_list[],uint_t size)23670dc2366fSVenugopal Iyer i_dlstat_convert_stats(void *stats, stat_info_t stats_list[], uint_t size)
23680dc2366fSVenugopal Iyer {
2369*4202e8bfSToomas Soome 	uint_t			i;
23700dc2366fSVenugopal Iyer 	name_value_stat_t	*head_stat = NULL, *prev_stat = NULL;
23710dc2366fSVenugopal Iyer 	name_value_stat_t	*curr_stat;
23720dc2366fSVenugopal Iyer 
23730dc2366fSVenugopal Iyer 	for (i = 0; i < size; i++) {
23740dc2366fSVenugopal Iyer 		uint64_t *val = (void *)
23750dc2366fSVenugopal Iyer 		    ((uchar_t *)stats + stats_list[i].si_offset);
23760dc2366fSVenugopal Iyer 
23770dc2366fSVenugopal Iyer 		curr_stat = calloc(1, sizeof (name_value_stat_t));
23780dc2366fSVenugopal Iyer 		if (curr_stat == NULL)
23790dc2366fSVenugopal Iyer 			break;
23800dc2366fSVenugopal Iyer 
23810dc2366fSVenugopal Iyer 		(void) strlcpy(curr_stat->nv_statname, stats_list[i].si_name,
23820dc2366fSVenugopal Iyer 		    sizeof (curr_stat->nv_statname));
23830dc2366fSVenugopal Iyer 		curr_stat->nv_statval = *val;
23840dc2366fSVenugopal Iyer 		curr_stat->nv_nextstat = NULL;
23850dc2366fSVenugopal Iyer 
23860dc2366fSVenugopal Iyer 		if (head_stat == NULL)	/* First node */
23870dc2366fSVenugopal Iyer 			head_stat = curr_stat;
23880dc2366fSVenugopal Iyer 		else
23890dc2366fSVenugopal Iyer 			prev_stat->nv_nextstat = curr_stat;
23900dc2366fSVenugopal Iyer 
23910dc2366fSVenugopal Iyer 		prev_stat = curr_stat;
23920dc2366fSVenugopal Iyer 	}
23930dc2366fSVenugopal Iyer 	return (head_stat);
23940dc2366fSVenugopal Iyer }
23950dc2366fSVenugopal Iyer 
23960dc2366fSVenugopal Iyer void *
build_nvs_entry(char * statheader,void * statentry,dladm_stat_type_t stattype)23970dc2366fSVenugopal Iyer build_nvs_entry(char *statheader, void *statentry, dladm_stat_type_t stattype)
23980dc2366fSVenugopal Iyer {
23990dc2366fSVenugopal Iyer 	name_value_stat_entry_t	*name_value_stat_entry;
24000dc2366fSVenugopal Iyer 	dladm_stat_desc_t	*stattbl_ptr;
24010dc2366fSVenugopal Iyer 	void			*statfields;
24020dc2366fSVenugopal Iyer 
24030dc2366fSVenugopal Iyer 	stattbl_ptr = &dladm_stat_table[stattype];
24040dc2366fSVenugopal Iyer 
24050dc2366fSVenugopal Iyer 	/* Allocate memory for query all stat entry */
24060dc2366fSVenugopal Iyer 	name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
24070dc2366fSVenugopal Iyer 	if (name_value_stat_entry == NULL)
24080dc2366fSVenugopal Iyer 		goto done;
24090dc2366fSVenugopal Iyer 
24100dc2366fSVenugopal Iyer 	/* Header for these stat fields */
24110dc2366fSVenugopal Iyer 	(void) strlcpy(name_value_stat_entry->nve_header, statheader,
24120dc2366fSVenugopal Iyer 	    sizeof (name_value_stat_entry->nve_header));
24130dc2366fSVenugopal Iyer 
24140dc2366fSVenugopal Iyer 	/* Extract stat fields from the statentry */
24150dc2366fSVenugopal Iyer 	statfields = (uchar_t *)statentry +
24160dc2366fSVenugopal Iyer 	    dladm_stat_table[stattype].ds_offset;
24170dc2366fSVenugopal Iyer 
24180dc2366fSVenugopal Iyer 	/* Convert curr_stat to <statname, statval> pair */
24190dc2366fSVenugopal Iyer 	name_value_stat_entry->nve_stats =
24200dc2366fSVenugopal Iyer 	    i_dlstat_convert_stats(statfields,
24210dc2366fSVenugopal Iyer 	    stattbl_ptr->ds_statlist, stattbl_ptr->ds_statsize);
24220dc2366fSVenugopal Iyer done:
24230dc2366fSVenugopal Iyer 	return (name_value_stat_entry);
24240dc2366fSVenugopal Iyer }
24250dc2366fSVenugopal Iyer 
24260dc2366fSVenugopal Iyer void *
i_walk_dlstat_chain(dladm_stat_chain_t * stat_head,dladm_stat_type_t stattype)24270dc2366fSVenugopal Iyer i_walk_dlstat_chain(dladm_stat_chain_t *stat_head, dladm_stat_type_t stattype)
24280dc2366fSVenugopal Iyer {
24290dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
24300dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*nvstat_head = NULL, *nvstat_prev = NULL;
24310dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*nvstat_curr;
24320dc2366fSVenugopal Iyer 
24330dc2366fSVenugopal Iyer 	/*
24340dc2366fSVenugopal Iyer 	 * For every stat in the chain, build header and convert all
24350dc2366fSVenugopal Iyer 	 * its stat fields
24360dc2366fSVenugopal Iyer 	 */
24370dc2366fSVenugopal Iyer 	for (curr = stat_head; curr != NULL; curr = curr->dc_next) {
24380dc2366fSVenugopal Iyer 		nvstat_curr = malloc(sizeof (dladm_stat_chain_t));
24390dc2366fSVenugopal Iyer 		if (nvstat_curr == NULL)
24400dc2366fSVenugopal Iyer 			break;
24410dc2366fSVenugopal Iyer 
24420dc2366fSVenugopal Iyer 		nvstat_curr->dc_statentry = build_nvs_entry(curr->dc_statheader,
24430dc2366fSVenugopal Iyer 		    curr->dc_statentry, stattype);
24440dc2366fSVenugopal Iyer 
24450dc2366fSVenugopal Iyer 		if (nvstat_curr->dc_statentry == NULL) {
24460dc2366fSVenugopal Iyer 			free(nvstat_curr);
24470dc2366fSVenugopal Iyer 			break;
24480dc2366fSVenugopal Iyer 		}
24490dc2366fSVenugopal Iyer 
24500dc2366fSVenugopal Iyer 		nvstat_curr->dc_next = NULL;
24510dc2366fSVenugopal Iyer 
24520dc2366fSVenugopal Iyer 		if (nvstat_head == NULL)	/* First node */
24530dc2366fSVenugopal Iyer 			nvstat_head = nvstat_curr;
24540dc2366fSVenugopal Iyer 		else
24550dc2366fSVenugopal Iyer 			nvstat_prev->dc_next = nvstat_curr;
24560dc2366fSVenugopal Iyer 
24570dc2366fSVenugopal Iyer 		nvstat_prev = nvstat_curr;
24580dc2366fSVenugopal Iyer 	}
24590dc2366fSVenugopal Iyer 	return (nvstat_head);
24600dc2366fSVenugopal Iyer }
24610dc2366fSVenugopal Iyer 
24620dc2366fSVenugopal Iyer dladm_stat_chain_t *
dladm_link_stat_query_all(dladm_handle_t dh,datalink_id_t linkid,dladm_stat_type_t stattype)24630dc2366fSVenugopal Iyer dladm_link_stat_query_all(dladm_handle_t dh, datalink_id_t linkid,
24640dc2366fSVenugopal Iyer     dladm_stat_type_t stattype)
24650dc2366fSVenugopal Iyer {
24660dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*stat_head;
24670dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*nvstat_head = NULL;
24680dc2366fSVenugopal Iyer 
24690dc2366fSVenugopal Iyer 	/* Query the requested stat */
24700dc2366fSVenugopal Iyer 	stat_head = dladm_link_stat_query(dh, linkid, stattype);
24710dc2366fSVenugopal Iyer 	if (stat_head == NULL)
24720dc2366fSVenugopal Iyer 		goto done;
24730dc2366fSVenugopal Iyer 
24740dc2366fSVenugopal Iyer 	/*
24750dc2366fSVenugopal Iyer 	 * Convert every statfield in every stat-entry of stat chain to
24760dc2366fSVenugopal Iyer 	 * <statname, statval> pair
24770dc2366fSVenugopal Iyer 	 */
24780dc2366fSVenugopal Iyer 	nvstat_head = i_walk_dlstat_chain(stat_head, stattype);
24790dc2366fSVenugopal Iyer 
24800dc2366fSVenugopal Iyer 	/* Free stat_head */
24810dc2366fSVenugopal Iyer 	dladm_link_stat_free(stat_head);
24820dc2366fSVenugopal Iyer 
24830dc2366fSVenugopal Iyer done:
24840dc2366fSVenugopal Iyer 	return (nvstat_head);
24850dc2366fSVenugopal Iyer }
24860dc2366fSVenugopal Iyer 
24870dc2366fSVenugopal Iyer void
dladm_link_stat_query_all_free(dladm_stat_chain_t * curr)24880dc2366fSVenugopal Iyer dladm_link_stat_query_all_free(dladm_stat_chain_t *curr)
24890dc2366fSVenugopal Iyer {
24900dc2366fSVenugopal Iyer 	while (curr != NULL) {
24910dc2366fSVenugopal Iyer 		dladm_stat_chain_t	*tofree = curr;
24920dc2366fSVenugopal Iyer 		name_value_stat_entry_t	*nv_entry = curr->dc_statentry;
24930dc2366fSVenugopal Iyer 		name_value_stat_t	*nv_curr = nv_entry->nve_stats;
24940dc2366fSVenugopal Iyer 
24950dc2366fSVenugopal Iyer 		while (nv_curr != NULL) {
24960dc2366fSVenugopal Iyer 			name_value_stat_t	*nv_tofree = nv_curr;
24970dc2366fSVenugopal Iyer 
24980dc2366fSVenugopal Iyer 			nv_curr = nv_curr->nv_nextstat;
24990dc2366fSVenugopal Iyer 			free(nv_tofree);
25000dc2366fSVenugopal Iyer 		}
25010dc2366fSVenugopal Iyer 
25020dc2366fSVenugopal Iyer 		curr = curr->dc_next;
25030dc2366fSVenugopal Iyer 		free(nv_entry);
25040dc2366fSVenugopal Iyer 		free(tofree);
25050dc2366fSVenugopal Iyer 	}
25060dc2366fSVenugopal Iyer }
25070dc2366fSVenugopal Iyer 
25080dc2366fSVenugopal Iyer /* flow stats specific routines */
25090dc2366fSVenugopal Iyer flow_stat_t *
dladm_flow_stat_query(dladm_handle_t handle,const char * flowname)2510399dcf08Scarlos antonio neira bustos dladm_flow_stat_query(dladm_handle_t handle, const char *flowname)
25110dc2366fSVenugopal Iyer {
25120dc2366fSVenugopal Iyer 	kstat_t		*ksp;
25130dc2366fSVenugopal Iyer 	flow_stat_t	*flow_stat = NULL;
25140dc2366fSVenugopal Iyer 
2515399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(handle) == NULL)
25160dc2366fSVenugopal Iyer 		return (NULL);
25170dc2366fSVenugopal Iyer 
25180dc2366fSVenugopal Iyer 	flow_stat = calloc(1, sizeof (flow_stat_t));
25190dc2366fSVenugopal Iyer 	if (flow_stat == NULL)
25200dc2366fSVenugopal Iyer 		goto done;
25210dc2366fSVenugopal Iyer 
2522399dcf08Scarlos antonio neira bustos 	ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), NULL, -1, flowname,
2523399dcf08Scarlos antonio neira bustos 	    "flow");
25240dc2366fSVenugopal Iyer 
25250dc2366fSVenugopal Iyer 	if (ksp != NULL) {
2526399dcf08Scarlos antonio neira bustos 		i_dlstat_get_stats(dladm_dld_kcp(handle), ksp, flow_stat,
2527399dcf08Scarlos antonio neira bustos 		    flow_stats_list, FLOW_STAT_SIZE);
25280dc2366fSVenugopal Iyer 	}
25290dc2366fSVenugopal Iyer 
25300dc2366fSVenugopal Iyer done:
25310dc2366fSVenugopal Iyer 	return (flow_stat);
25320dc2366fSVenugopal Iyer }
25330dc2366fSVenugopal Iyer 
25340dc2366fSVenugopal Iyer flow_stat_t *
dladm_flow_stat_diff(flow_stat_t * op1,flow_stat_t * op2)25350dc2366fSVenugopal Iyer dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2)
25360dc2366fSVenugopal Iyer {
25370dc2366fSVenugopal Iyer 	flow_stat_t	*diff_stat;
25380dc2366fSVenugopal Iyer 
25390dc2366fSVenugopal Iyer 	diff_stat = calloc(1, sizeof (flow_stat_t));
25400dc2366fSVenugopal Iyer 	if (diff_stat == NULL)
25410dc2366fSVenugopal Iyer 		goto done;
25420dc2366fSVenugopal Iyer 
25430dc2366fSVenugopal Iyer 	if (op2 == NULL) {
25440dc2366fSVenugopal Iyer 		bcopy(op1, diff_stat, sizeof (flow_stat_t));
25450dc2366fSVenugopal Iyer 	} else {
25460dc2366fSVenugopal Iyer 		i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list,
25470dc2366fSVenugopal Iyer 		    FLOW_STAT_SIZE);
25480dc2366fSVenugopal Iyer 	}
25490dc2366fSVenugopal Iyer done:
25500dc2366fSVenugopal Iyer 	return (diff_stat);
25510dc2366fSVenugopal Iyer }
25520dc2366fSVenugopal Iyer 
25530dc2366fSVenugopal Iyer void
dladm_flow_stat_free(flow_stat_t * curr)25540dc2366fSVenugopal Iyer dladm_flow_stat_free(flow_stat_t *curr)
25550dc2366fSVenugopal Iyer {
25560dc2366fSVenugopal Iyer 	free(curr);
25570dc2366fSVenugopal Iyer }
25580dc2366fSVenugopal Iyer 
25590dc2366fSVenugopal Iyer /* Query all flow stats */
25600dc2366fSVenugopal Iyer name_value_stat_entry_t *
dladm_flow_stat_query_all(dladm_handle_t handle,const char * flowname)2561399dcf08Scarlos antonio neira bustos dladm_flow_stat_query_all(dladm_handle_t handle, const char *flowname)
25620dc2366fSVenugopal Iyer {
25630dc2366fSVenugopal Iyer 	flow_stat_t		*flow_stat;
25640dc2366fSVenugopal Iyer 	name_value_stat_entry_t	*name_value_stat_entry = NULL;
25650dc2366fSVenugopal Iyer 
25660dc2366fSVenugopal Iyer 	/* Query flow stats */
2567399dcf08Scarlos antonio neira bustos 	flow_stat = dladm_flow_stat_query(handle, flowname);
25680dc2366fSVenugopal Iyer 	if (flow_stat == NULL)
25690dc2366fSVenugopal Iyer 		goto done;
25700dc2366fSVenugopal Iyer 
25710dc2366fSVenugopal Iyer 	/* Allocate memory for query all stat entry */
25720dc2366fSVenugopal Iyer 	name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
25730dc2366fSVenugopal Iyer 	if (name_value_stat_entry == NULL) {
25740dc2366fSVenugopal Iyer 		dladm_flow_stat_free(flow_stat);
25750dc2366fSVenugopal Iyer 		goto done;
25760dc2366fSVenugopal Iyer 	}
25770dc2366fSVenugopal Iyer 
25780dc2366fSVenugopal Iyer 	/* Header for these stat fields */
25790dc2366fSVenugopal Iyer 	(void) strncpy(name_value_stat_entry->nve_header, flowname,
25800dc2366fSVenugopal Iyer 	    MAXFLOWNAMELEN);
25810dc2366fSVenugopal Iyer 
25820dc2366fSVenugopal Iyer 	/* Convert every statfield in flow_stat to <statname, statval> pair */
25830dc2366fSVenugopal Iyer 	name_value_stat_entry->nve_stats =
25840dc2366fSVenugopal Iyer 	    i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE);
25850dc2366fSVenugopal Iyer 
25860dc2366fSVenugopal Iyer 	/* Free flow_stat */
25870dc2366fSVenugopal Iyer 	dladm_flow_stat_free(flow_stat);
25880dc2366fSVenugopal Iyer 
25890dc2366fSVenugopal Iyer done:
25900dc2366fSVenugopal Iyer 	return (name_value_stat_entry);
25910dc2366fSVenugopal Iyer }
25920dc2366fSVenugopal Iyer 
25930dc2366fSVenugopal Iyer void
dladm_flow_stat_query_all_free(name_value_stat_entry_t * curr)25940dc2366fSVenugopal Iyer dladm_flow_stat_query_all_free(name_value_stat_entry_t *curr)
25950dc2366fSVenugopal Iyer {
25960dc2366fSVenugopal Iyer 	name_value_stat_t	*nv_curr = curr->nve_stats;
25970dc2366fSVenugopal Iyer 
25980dc2366fSVenugopal Iyer 	while (nv_curr != NULL) {
25990dc2366fSVenugopal Iyer 		name_value_stat_t	*nv_tofree = nv_curr;
26000dc2366fSVenugopal Iyer 
26010dc2366fSVenugopal Iyer 		nv_curr = nv_curr->nv_nextstat;
26020dc2366fSVenugopal Iyer 		free(nv_tofree);
26030dc2366fSVenugopal Iyer 	}
26040dc2366fSVenugopal Iyer }
2605