xref: /illumos-gate/usr/src/lib/libdladm/common/libdlstat.c (revision 20535e135f9f6ba565f11a01d3ed138cb179fa18)
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 *
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
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
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
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
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
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 *
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
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
6120dc2366fSVenugopal Iyer i_dlstat_diff_stats(void *diff, void *op1, void *op2,
6130dc2366fSVenugopal Iyer     stat_info_t stats_list[], uint_t size)
6140dc2366fSVenugopal Iyer {
6150dc2366fSVenugopal Iyer 	int	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
6440dc2366fSVenugopal Iyer i_dlstat_sum_stats(void *sum, void *op1, void *op2,
6450dc2366fSVenugopal Iyer     stat_info_t stats_list[], uint_t size)
6460dc2366fSVenugopal Iyer {
6470dc2366fSVenugopal Iyer 	int	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
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 {
6660dc2366fSVenugopal Iyer 	int	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 *
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
7110dc2366fSVenugopal Iyer dladm_sort_index_list(uint_t idlist[], uint_t size)
7120dc2366fSVenugopal Iyer {
7130dc2366fSVenugopal Iyer 	int	i, j;
7140dc2366fSVenugopal Iyer 
7150dc2366fSVenugopal Iyer 	for (j = 1; j < size; j++) {
7160dc2366fSVenugopal Iyer 		int key = idlist[j];
7170dc2366fSVenugopal Iyer 		for (i = j - 1; (i >= 0) && (idlist[i] > key); i--)
7180dc2366fSVenugopal Iyer 			idlist[i + 1] = idlist[i];
7190dc2366fSVenugopal Iyer 		idlist[i + 1] = key;
7200dc2366fSVenugopal Iyer 	}
7210dc2366fSVenugopal Iyer }
7220dc2366fSVenugopal Iyer 
7230dc2366fSVenugopal Iyer /* Support for legacy drivers */
7240dc2366fSVenugopal Iyer void
725399dcf08Scarlos antonio neira bustos i_query_legacy_stats(dladm_handle_t dh, const char *linkname, pktsum_t *stats)
7260dc2366fSVenugopal Iyer {
7270dc2366fSVenugopal Iyer 	kstat_t		*ksp;
7280dc2366fSVenugopal Iyer 
7290dc2366fSVenugopal Iyer 	bzero(stats, sizeof (*stats));
7300dc2366fSVenugopal Iyer 
731399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(dh) == NULL)
7320dc2366fSVenugopal Iyer 		return;
7330dc2366fSVenugopal Iyer 
734399dcf08Scarlos antonio neira bustos 	ksp = dladm_kstat_lookup(dladm_dld_kcp(dh), "link", 0, linkname, NULL);
7350dc2366fSVenugopal Iyer 
7360dc2366fSVenugopal Iyer 	if (ksp != NULL)
737399dcf08Scarlos antonio neira bustos 		dladm_get_stats(dladm_dld_kcp(dh), ksp, stats);
7380dc2366fSVenugopal Iyer }
7390dc2366fSVenugopal Iyer 
7400dc2366fSVenugopal Iyer void *
741399dcf08Scarlos antonio neira bustos i_dlstat_legacy_rx_lane_stats(dladm_handle_t dh, const char *linkname)
7420dc2366fSVenugopal Iyer {
7430dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
7440dc2366fSVenugopal Iyer 	pktsum_t		stats;
7450dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
7460dc2366fSVenugopal Iyer 
7470dc2366fSVenugopal Iyer 	bzero(&stats, sizeof (pktsum_t));
7480dc2366fSVenugopal Iyer 
7490dc2366fSVenugopal Iyer 	/* Query for dls stats */
750399dcf08Scarlos antonio neira bustos 	i_query_legacy_stats(dh, linkname, &stats);
7510dc2366fSVenugopal Iyer 
7520dc2366fSVenugopal Iyer 	/* Convert to desired data type */
7530dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
7540dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
7550dc2366fSVenugopal Iyer 		goto done;
7560dc2366fSVenugopal Iyer 
7570dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
7580dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_SWLANE;
7590dc2366fSVenugopal Iyer 
7600dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets;
7610dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets;
7620dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes;
7630dc2366fSVenugopal Iyer 
7640dc2366fSVenugopal Iyer 	/* Allocate memory for wrapper */
7650dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
7660dc2366fSVenugopal Iyer 	if (head == NULL) {
7670dc2366fSVenugopal Iyer 		free(rx_lane_stat_entry);
7680dc2366fSVenugopal Iyer 		goto done;
7690dc2366fSVenugopal Iyer 	}
7700dc2366fSVenugopal Iyer 
7710dc2366fSVenugopal Iyer 	head->dc_statentry = rx_lane_stat_entry;
7720dc2366fSVenugopal Iyer 	head->dc_next = NULL;
7730dc2366fSVenugopal Iyer done:
7740dc2366fSVenugopal Iyer 	return (head);
7750dc2366fSVenugopal Iyer }
7760dc2366fSVenugopal Iyer 
7770dc2366fSVenugopal Iyer void *
778399dcf08Scarlos antonio neira bustos i_dlstat_legacy_tx_lane_stats(dladm_handle_t dh, const char *linkname)
7790dc2366fSVenugopal Iyer {
7800dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
7810dc2366fSVenugopal Iyer 	pktsum_t		stats;
7820dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
7830dc2366fSVenugopal Iyer 
7840dc2366fSVenugopal Iyer 	bzero(&stats, sizeof (pktsum_t));
7850dc2366fSVenugopal Iyer 
7860dc2366fSVenugopal Iyer 	/* Query for dls stats */
787399dcf08Scarlos antonio neira bustos 	i_query_legacy_stats(dh, linkname, &stats);
7880dc2366fSVenugopal Iyer 
7890dc2366fSVenugopal Iyer 	/* Convert to desired data type */
7900dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
7910dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
7920dc2366fSVenugopal Iyer 		goto done;
7930dc2366fSVenugopal Iyer 
7940dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
7950dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_SWLANE;
7960dc2366fSVenugopal Iyer 
7970dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets;
7980dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes;
7990dc2366fSVenugopal Iyer 
8000dc2366fSVenugopal Iyer 	/* Allocate memory for wrapper */
8010dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
8020dc2366fSVenugopal Iyer 	if (head == NULL) {
8030dc2366fSVenugopal Iyer 		free(tx_lane_stat_entry);
8040dc2366fSVenugopal Iyer 		goto done;
8050dc2366fSVenugopal Iyer 	}
8060dc2366fSVenugopal Iyer 
8070dc2366fSVenugopal Iyer 	head->dc_statentry = tx_lane_stat_entry;
8080dc2366fSVenugopal Iyer 	head->dc_next = NULL;
8090dc2366fSVenugopal Iyer done:
8100dc2366fSVenugopal Iyer 	return (head);
8110dc2366fSVenugopal Iyer }
8120dc2366fSVenugopal Iyer 
8130dc2366fSVenugopal Iyer /*
8140dc2366fSVenugopal Iyer  * Ideally, we would want an ioctl to return list of ring-ids (or lane-ids)
8150dc2366fSVenugopal Iyer  * for a given data-link (or mac client). We could then query for specific
8160dc2366fSVenugopal Iyer  * kstats based on these ring-ids (lane-ids).
8170dc2366fSVenugopal Iyer  * Ring-ids (or lane-ids) could be returned like any other link properties
8180dc2366fSVenugopal Iyer  * queried by dladm show-linkprop. However, non-global zones do not have
8190dc2366fSVenugopal Iyer  * access to this information today.
8200dc2366fSVenugopal Iyer  * We thus opt for an implementation that relies heavily on kstat internals:
8210dc2366fSVenugopal Iyer  * i_dlstat_*search routines and i_dlstat_get_idlist.
8220dc2366fSVenugopal Iyer  */
8230dc2366fSVenugopal Iyer /* rx hwlane specific */
8240dc2366fSVenugopal Iyer static boolean_t
8250dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_search(kstat_t *ksp)
8260dc2366fSVenugopal Iyer {
8270dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
8280dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
8290dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "hwlane") != 0 &&
8300dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "fanout") == 0 &&
8310dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
8320dc2366fSVenugopal Iyer }
8330dc2366fSVenugopal Iyer 
8340dc2366fSVenugopal Iyer /* tx hwlane specific */
8350dc2366fSVenugopal Iyer static boolean_t
8360dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_search(kstat_t *ksp)
8370dc2366fSVenugopal Iyer {
8380dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
8390dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_tx") != 0 &&
8400dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "hwlane") != 0 &&
8410dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
8420dc2366fSVenugopal Iyer }
8430dc2366fSVenugopal Iyer 
8440dc2366fSVenugopal Iyer /* rx fanout specific */
8450dc2366fSVenugopal Iyer static boolean_t
8460dc2366fSVenugopal Iyer i_dlstat_fanout_search(kstat_t *ksp)
8470dc2366fSVenugopal Iyer {
8480dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
8490dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
8500dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "swlane") != 0 &&
8510dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "fanout") != 0 &&
8520dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
8530dc2366fSVenugopal Iyer }
8540dc2366fSVenugopal Iyer 
8550dc2366fSVenugopal Iyer /* rx ring specific */
8560dc2366fSVenugopal Iyer static boolean_t
8570dc2366fSVenugopal Iyer i_dlstat_rx_ring_search(kstat_t *ksp)
8580dc2366fSVenugopal Iyer {
8590dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0 &&
8600dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_rx") != 0 &&
8610dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "ring") != 0 &&
8620dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0);
8630dc2366fSVenugopal Iyer }
8640dc2366fSVenugopal Iyer 
8650dc2366fSVenugopal Iyer /* tx ring specific */
8660dc2366fSVenugopal Iyer static boolean_t
8670dc2366fSVenugopal Iyer i_dlstat_tx_ring_search(kstat_t *ksp)
8680dc2366fSVenugopal Iyer {
8690dc2366fSVenugopal Iyer 	return (ksp->ks_instance == 0) &&
8700dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "mac_tx") != 0 &&
8710dc2366fSVenugopal Iyer 	    strstr(ksp->ks_name, "ring") != 0 &&
8720dc2366fSVenugopal Iyer 	    strcmp(ksp->ks_class, "net") == 0;
8730dc2366fSVenugopal Iyer }
8740dc2366fSVenugopal Iyer 
8750dc2366fSVenugopal Iyer typedef	boolean_t	dladm_search_kstat_t(kstat_t *);
8760dc2366fSVenugopal Iyer typedef struct dladm_extract_idlist_s {
8770dc2366fSVenugopal Iyer 	dlstat_idlist_type_t	di_type;
8780dc2366fSVenugopal Iyer 	char			*di_prefix;
8790dc2366fSVenugopal Iyer 	dladm_search_kstat_t	*di_searchkstat;
8800dc2366fSVenugopal Iyer } dladm_extract_idlist_t;
8810dc2366fSVenugopal Iyer 
8820dc2366fSVenugopal Iyer static dladm_extract_idlist_t dladm_extract_idlist[] = {
8830dc2366fSVenugopal Iyer { DLSTAT_RX_RING_IDLIST,	DLSTAT_MAC_RX_RING,
8840dc2366fSVenugopal Iyer     i_dlstat_rx_ring_search},
8850dc2366fSVenugopal Iyer { DLSTAT_TX_RING_IDLIST,	DLSTAT_MAC_TX_RING,
8860dc2366fSVenugopal Iyer     i_dlstat_tx_ring_search},
8870dc2366fSVenugopal Iyer { DLSTAT_RX_HWLANE_IDLIST,	DLSTAT_MAC_RX_HWLANE,
8880dc2366fSVenugopal Iyer     i_dlstat_rx_hwlane_search},
8890dc2366fSVenugopal Iyer { DLSTAT_TX_HWLANE_IDLIST,	DLSTAT_MAC_TX_HWLANE,
8900dc2366fSVenugopal Iyer     i_dlstat_tx_hwlane_search},
8910dc2366fSVenugopal Iyer { DLSTAT_FANOUT_IDLIST,		DLSTAT_MAC_FANOUT,
8920dc2366fSVenugopal Iyer     i_dlstat_fanout_search}
8930dc2366fSVenugopal Iyer };
8940dc2366fSVenugopal Iyer 
8950dc2366fSVenugopal Iyer static void
896399dcf08Scarlos antonio neira bustos i_dlstat_get_idlist(dladm_handle_t handle, const char *modname,
897399dcf08Scarlos antonio neira bustos     dlstat_idlist_type_t idlist_type,
8980dc2366fSVenugopal Iyer     uint_t idlist[], uint_t *size)
8990dc2366fSVenugopal Iyer {
900399dcf08Scarlos antonio neira bustos 	kstat_ctl_t	*kcp = dladm_dld_kcp(handle);
9010dc2366fSVenugopal Iyer 	kstat_t		*ksp;
9020dc2366fSVenugopal Iyer 	char		*prefix;
9030dc2366fSVenugopal Iyer 	int		prefixlen;
9040dc2366fSVenugopal Iyer 	boolean_t	(*fptr_searchkstat)(kstat_t *);
9050dc2366fSVenugopal Iyer 
9060dc2366fSVenugopal Iyer 	*size = 0;
9070dc2366fSVenugopal Iyer 
908399dcf08Scarlos antonio neira bustos 	if (kcp == NULL) {
9090dc2366fSVenugopal Iyer 		warn("kstat_open operation failed");
910399dcf08Scarlos antonio neira bustos 		return;
9110dc2366fSVenugopal Iyer 	}
9120dc2366fSVenugopal Iyer 
9130dc2366fSVenugopal Iyer 	prefix = dladm_extract_idlist[idlist_type].di_prefix;
9140dc2366fSVenugopal Iyer 	fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat;
9150dc2366fSVenugopal Iyer 	prefixlen = strlen(prefix);
9160dc2366fSVenugopal Iyer 	for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
9170dc2366fSVenugopal Iyer 		if ((strcmp(ksp->ks_module, modname) == 0) &&
9180dc2366fSVenugopal Iyer 		    fptr_searchkstat(ksp)) {
9190dc2366fSVenugopal Iyer 			idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]);
9200dc2366fSVenugopal Iyer 		}
9210dc2366fSVenugopal Iyer 	}
9220dc2366fSVenugopal Iyer 	dladm_sort_index_list(idlist, *size);
9230dc2366fSVenugopal Iyer }
9240dc2366fSVenugopal Iyer 
9250dc2366fSVenugopal Iyer static dladm_stat_chain_t *
926399dcf08Scarlos antonio neira bustos i_dlstat_query_stats(dladm_handle_t handle, const char *modname,
927399dcf08Scarlos antonio neira bustos     const char *prefix, uint_t idlist[], uint_t idlist_size,
9280dc2366fSVenugopal Iyer     void * (*fn)(kstat_ctl_t *, kstat_t *, int))
9290dc2366fSVenugopal Iyer {
9300dc2366fSVenugopal Iyer 	kstat_t			*ksp;
9310dc2366fSVenugopal Iyer 	char			statname[MAXLINKNAMELEN];
9320dc2366fSVenugopal Iyer 	int			i = 0;
9330dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL, *prev = NULL;
9340dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
9350dc2366fSVenugopal Iyer 
936399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(handle) == NULL) {
9370dc2366fSVenugopal Iyer 		warn("kstat_open operation failed");
9380dc2366fSVenugopal Iyer 		return (NULL);
9390dc2366fSVenugopal Iyer 	}
9400dc2366fSVenugopal Iyer 
9410dc2366fSVenugopal Iyer 	for (i = 0; i < idlist_size; i++) {
9420dc2366fSVenugopal Iyer 		uint_t	index = idlist[i];
9430dc2366fSVenugopal Iyer 
9440dc2366fSVenugopal Iyer 		(void) snprintf(statname, sizeof (statname), "%s%d", prefix,
9450dc2366fSVenugopal Iyer 		    index);
9460dc2366fSVenugopal Iyer 
947399dcf08Scarlos antonio neira bustos 		ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), modname, 0,
948399dcf08Scarlos antonio neira bustos 		    statname, NULL);
9490dc2366fSVenugopal Iyer 		if (ksp == NULL)
9500dc2366fSVenugopal Iyer 			continue;
9510dc2366fSVenugopal Iyer 
9520dc2366fSVenugopal Iyer 		curr = malloc(sizeof (dladm_stat_chain_t));
9530dc2366fSVenugopal Iyer 		if (curr == NULL)
9540dc2366fSVenugopal Iyer 			break;
9550dc2366fSVenugopal Iyer 
956399dcf08Scarlos antonio neira bustos 		curr->dc_statentry = fn(dladm_dld_kcp(handle), ksp, index);
9570dc2366fSVenugopal Iyer 		if (curr->dc_statentry == NULL) {
9580dc2366fSVenugopal Iyer 			free(curr);
9590dc2366fSVenugopal Iyer 			break;
9600dc2366fSVenugopal Iyer 		}
9610dc2366fSVenugopal Iyer 
9620dc2366fSVenugopal Iyer 		(void) strlcpy(curr->dc_statheader, statname,
9630dc2366fSVenugopal Iyer 		    sizeof (curr->dc_statheader));
9640dc2366fSVenugopal Iyer 		curr->dc_next = NULL;
9650dc2366fSVenugopal Iyer 
9660dc2366fSVenugopal Iyer 		if (head == NULL)	/* First node */
9670dc2366fSVenugopal Iyer 			head = curr;
9680dc2366fSVenugopal Iyer 		else
9690dc2366fSVenugopal Iyer 			prev->dc_next = curr;
9700dc2366fSVenugopal Iyer 
9710dc2366fSVenugopal Iyer 		prev = curr;
9720dc2366fSVenugopal Iyer 	}
9730dc2366fSVenugopal Iyer 	return (head);
9740dc2366fSVenugopal Iyer }
9750dc2366fSVenugopal Iyer 
9760dc2366fSVenugopal Iyer static misc_stat_entry_t *
977399dcf08Scarlos antonio neira bustos i_dlstat_misc_stats(dladm_handle_t handle, const char *linkname)
9780dc2366fSVenugopal Iyer {
9790dc2366fSVenugopal Iyer 	kstat_t			*ksp;
9800dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry = NULL;
9810dc2366fSVenugopal Iyer 
982399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(handle) == NULL)
9830dc2366fSVenugopal Iyer 		return (NULL);
9840dc2366fSVenugopal Iyer 
985399dcf08Scarlos antonio neira bustos 	ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), linkname, 0,
986399dcf08Scarlos antonio neira bustos 	    DLSTAT_MAC_MISC_STAT, NULL);
9870dc2366fSVenugopal Iyer 	if (ksp == NULL)
9880dc2366fSVenugopal Iyer 		goto done;
9890dc2366fSVenugopal Iyer 
9900dc2366fSVenugopal Iyer 	misc_stat_entry = calloc(1, sizeof (misc_stat_entry_t));
9910dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
9920dc2366fSVenugopal Iyer 		goto done;
9930dc2366fSVenugopal Iyer 
994399dcf08Scarlos antonio neira bustos 	i_dlstat_get_stats(dladm_dld_kcp(handle), ksp,
995399dcf08Scarlos antonio neira bustos 	    &misc_stat_entry->mse_stats,
9960dc2366fSVenugopal Iyer 	    misc_stats_list, MISC_STAT_SIZE);
9970dc2366fSVenugopal Iyer done:
9980dc2366fSVenugopal Iyer 	return (misc_stat_entry);
9990dc2366fSVenugopal Iyer }
10000dc2366fSVenugopal Iyer 
10010dc2366fSVenugopal Iyer /* Rx lane statistic specific functions */
10020dc2366fSVenugopal Iyer static boolean_t
10030dc2366fSVenugopal Iyer i_dlstat_rx_lane_match(void *arg1, void *arg2)
10040dc2366fSVenugopal Iyer {
10050dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s1 = arg1;
10060dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s2 = arg2;
10070dc2366fSVenugopal Iyer 
10080dc2366fSVenugopal Iyer 	return (s1->rle_index == s2->rle_index &&
10090dc2366fSVenugopal Iyer 	    s1->rle_id == s2->rle_id);
10100dc2366fSVenugopal Iyer }
10110dc2366fSVenugopal Iyer 
10120dc2366fSVenugopal Iyer static void *
10130dc2366fSVenugopal Iyer i_dlstat_rx_lane_stat_entry_diff(void *arg1, void *arg2)
10140dc2366fSVenugopal Iyer {
10150dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s1 = arg1;
10160dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *s2 = arg2;
10170dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t *diff_entry;
10180dc2366fSVenugopal Iyer 
10190dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (rx_lane_stat_entry_t));
10200dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
10210dc2366fSVenugopal Iyer 		goto done;
10220dc2366fSVenugopal Iyer 
10230dc2366fSVenugopal Iyer 	diff_entry->rle_index = s1->rle_index;
10240dc2366fSVenugopal Iyer 	diff_entry->rle_id = s1->rle_id;
10250dc2366fSVenugopal Iyer 
10260dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, rle_stats, rx_lane_stats_list,
10270dc2366fSVenugopal Iyer 	    RX_LANE_STAT_SIZE);
10280dc2366fSVenugopal Iyer 
10290dc2366fSVenugopal Iyer done:
10300dc2366fSVenugopal Iyer 	return (diff_entry);
10310dc2366fSVenugopal Iyer }
10320dc2366fSVenugopal Iyer 
10330dc2366fSVenugopal Iyer static void *
10340dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
10350dc2366fSVenugopal Iyer {
10360dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
10370dc2366fSVenugopal Iyer 
10380dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
10390dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
10400dc2366fSVenugopal Iyer 		goto done;
10410dc2366fSVenugopal Iyer 
10420dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = i;
10430dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_HWLANE;
10440dc2366fSVenugopal Iyer 
10450dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
10460dc2366fSVenugopal Iyer 	    rx_hwlane_stats_list, RX_HWLANE_STAT_SIZE);
10470dc2366fSVenugopal Iyer 
10480dc2366fSVenugopal Iyer done:
10490dc2366fSVenugopal Iyer 	return (rx_lane_stat_entry);
10500dc2366fSVenugopal Iyer }
10510dc2366fSVenugopal Iyer 
10520dc2366fSVenugopal Iyer static void *
1053*20535e13SToomas Soome i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused)
10540dc2366fSVenugopal Iyer {
10550dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
10560dc2366fSVenugopal Iyer 
10570dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
10580dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
10590dc2366fSVenugopal Iyer 		goto done;
10600dc2366fSVenugopal Iyer 
10610dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
10620dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_SWLANE;
10630dc2366fSVenugopal Iyer 
10640dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
10650dc2366fSVenugopal Iyer 	    rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
10660dc2366fSVenugopal Iyer 
10670dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets =
10680dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_intrs;
10690dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes =
10700dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_intrbytes;
10710dc2366fSVenugopal Iyer done:
10720dc2366fSVenugopal Iyer 	return (rx_lane_stat_entry);
10730dc2366fSVenugopal Iyer }
10740dc2366fSVenugopal Iyer 
10750dc2366fSVenugopal Iyer static void *
1076*20535e13SToomas Soome i_dlstat_rx_local_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused)
10770dc2366fSVenugopal Iyer {
1078f7952617SToomas Soome 	rx_lane_stat_entry_t	*local_stat_entry = NULL;
10790dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
10800dc2366fSVenugopal Iyer 
10810dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
10820dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
10830dc2366fSVenugopal Iyer 		goto done;
10840dc2366fSVenugopal Iyer 
10850dc2366fSVenugopal Iyer 	local_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
10860dc2366fSVenugopal Iyer 	if (local_stat_entry == NULL)
10870dc2366fSVenugopal Iyer 		goto done;
10880dc2366fSVenugopal Iyer 
10890dc2366fSVenugopal Iyer 	local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
10900dc2366fSVenugopal Iyer 	local_stat_entry->rle_id = L_LOCAL;
10910dc2366fSVenugopal Iyer 
10920dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
10930dc2366fSVenugopal Iyer 	    rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
10940dc2366fSVenugopal Iyer 
10950dc2366fSVenugopal Iyer 	local_stat_entry->rle_stats.rl_ipackets =
10960dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_lclpackets;
10970dc2366fSVenugopal Iyer 	local_stat_entry->rle_stats.rl_rbytes =
10980dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_lclbytes;
10990dc2366fSVenugopal Iyer 
11000dc2366fSVenugopal Iyer done:
11010dc2366fSVenugopal Iyer 	free(rx_lane_stat_entry);
11020dc2366fSVenugopal Iyer 	return (local_stat_entry);
11030dc2366fSVenugopal Iyer }
11040dc2366fSVenugopal Iyer 
11050dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1106399dcf08Scarlos antonio neira bustos i_dlstat_rx_local_stats(dladm_handle_t handle, const char *linkname)
11070dc2366fSVenugopal Iyer {
11080dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*local_stats = NULL;
11090dc2366fSVenugopal Iyer 
1110399dcf08Scarlos antonio neira bustos 	local_stats = i_dlstat_query_stats(handle, linkname,
1111399dcf08Scarlos antonio neira bustos 	    DLSTAT_MAC_RX_SWLANE,
11120dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size,
11130dc2366fSVenugopal Iyer 	    i_dlstat_rx_local_retrieve_stat);
11140dc2366fSVenugopal Iyer 
11150dc2366fSVenugopal Iyer 	if (local_stats != NULL) {
11160dc2366fSVenugopal Iyer 		(void) strlcpy(local_stats->dc_statheader, "mac_rx_local",
11170dc2366fSVenugopal Iyer 		    sizeof (local_stats->dc_statheader));
11180dc2366fSVenugopal Iyer 	}
11190dc2366fSVenugopal Iyer 	return (local_stats);
11200dc2366fSVenugopal Iyer }
11210dc2366fSVenugopal Iyer 
11220dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1123399dcf08Scarlos antonio neira bustos i_dlstat_rx_bcast_stats(dladm_handle_t handle, const char *linkname)
11240dc2366fSVenugopal Iyer {
11250dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
11260dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
11270dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
11280dc2366fSVenugopal Iyer 
1129399dcf08Scarlos antonio neira bustos 	misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
11300dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
11310dc2366fSVenugopal Iyer 		goto done;
11320dc2366fSVenugopal Iyer 
11330dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
11340dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
11350dc2366fSVenugopal Iyer 		goto done;
11360dc2366fSVenugopal Iyer 
11370dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
11380dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_BCAST;
11390dc2366fSVenugopal Iyer 
11400dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets =
11410dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstrcv +
11420dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multircv;
11430dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_intrs =
11440dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstrcv +
11450dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multircv;
11460dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes =
11470dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstrcvbytes +
11480dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multircvbytes;
11490dc2366fSVenugopal Iyer 
11500dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
11510dc2366fSVenugopal Iyer 	if (head == NULL) {
11520dc2366fSVenugopal Iyer 		free(rx_lane_stat_entry);
11530dc2366fSVenugopal Iyer 		goto done;
11540dc2366fSVenugopal Iyer 	}
11550dc2366fSVenugopal Iyer 
11560dc2366fSVenugopal Iyer 	head->dc_statentry = rx_lane_stat_entry;
11570dc2366fSVenugopal Iyer 	head->dc_next = NULL;
11580dc2366fSVenugopal Iyer 
11590dc2366fSVenugopal Iyer 	free(misc_stat_entry);
11600dc2366fSVenugopal Iyer done:
11610dc2366fSVenugopal Iyer 	return (head);
11620dc2366fSVenugopal Iyer }
11630dc2366fSVenugopal Iyer 
11640dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1165399dcf08Scarlos antonio neira bustos i_dlstat_rx_defunctlane_stats(dladm_handle_t handle, const char *linkname)
11660dc2366fSVenugopal Iyer {
11670dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
11680dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
11690dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
11700dc2366fSVenugopal Iyer 
1171399dcf08Scarlos antonio neira bustos 	misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
11720dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
11730dc2366fSVenugopal Iyer 		goto done;
11740dc2366fSVenugopal Iyer 
11750dc2366fSVenugopal Iyer 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
11760dc2366fSVenugopal Iyer 	if (rx_lane_stat_entry == NULL)
11770dc2366fSVenugopal Iyer 		goto done;
11780dc2366fSVenugopal Iyer 
11790dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
11800dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_id = L_DFNCT;
11810dc2366fSVenugopal Iyer 
11820dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ipackets =
11830dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_ipackets;
11840dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_rbytes =
11850dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_rbytes;
11860dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_intrs =
11870dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_intrs;
11880dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_polls =
11890dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_polls;
11900dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_sdrops =
11910dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_rxsdrops;
11920dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_chl10 =
11930dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_chainunder10;
11940dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_ch10_50 =
11950dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_chain10to50;
11960dc2366fSVenugopal Iyer 	rx_lane_stat_entry->rle_stats.rl_chg50 =
11970dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_chainover50;
11980dc2366fSVenugopal Iyer 
11990dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
12000dc2366fSVenugopal Iyer 	if (head == NULL) {
12010dc2366fSVenugopal Iyer 		free(rx_lane_stat_entry);
12020dc2366fSVenugopal Iyer 		goto done;
12030dc2366fSVenugopal Iyer 	}
12040dc2366fSVenugopal Iyer 
12050dc2366fSVenugopal Iyer 	head->dc_statentry = rx_lane_stat_entry;
12060dc2366fSVenugopal Iyer 	head->dc_next = NULL;
12070dc2366fSVenugopal Iyer 
12080dc2366fSVenugopal Iyer done:
12090dc2366fSVenugopal Iyer 	return (head);
12100dc2366fSVenugopal Iyer }
12110dc2366fSVenugopal Iyer 
12120dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1213399dcf08Scarlos antonio neira bustos i_dlstat_rx_hwlane_stats(dladm_handle_t handle, const char *linkname)
12140dc2366fSVenugopal Iyer {
12150dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
12160dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist_size;
12170dc2366fSVenugopal Iyer 
1218399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(handle, linkname, DLSTAT_RX_HWLANE_IDLIST,
12190dc2366fSVenugopal Iyer 	    rx_hwlane_idlist, &rx_hwlane_idlist_size);
12200dc2366fSVenugopal Iyer 
1221399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_RX_HWLANE,
12220dc2366fSVenugopal Iyer 	    rx_hwlane_idlist, rx_hwlane_idlist_size,
12230dc2366fSVenugopal Iyer 	    i_dlstat_rx_hwlane_retrieve_stat));
12240dc2366fSVenugopal Iyer }
12250dc2366fSVenugopal Iyer 
12260dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1227*20535e13SToomas Soome i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid __unused,
12280dc2366fSVenugopal Iyer     const char *linkname)
12290dc2366fSVenugopal Iyer {
1230399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_RX_SWLANE,
12310dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size,
12320dc2366fSVenugopal Iyer 	    i_dlstat_rx_swlane_retrieve_stat));
12330dc2366fSVenugopal Iyer }
12340dc2366fSVenugopal Iyer 
12350dc2366fSVenugopal Iyer void *
12360dc2366fSVenugopal Iyer dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
12370dc2366fSVenugopal Iyer {
12380dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
12390dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*local_stats = NULL;
12400dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*bcast_stats = NULL;
12410dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*defunctlane_stats = NULL;
12420dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*lane_stats = NULL;
12430dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
12440dc2366fSVenugopal Iyer 	boolean_t		is_legacy_driver;
12450dc2366fSVenugopal Iyer 
12460dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
12470dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
12480dc2366fSVenugopal Iyer 		goto done;
12490dc2366fSVenugopal Iyer 	}
12500dc2366fSVenugopal Iyer 
12510dc2366fSVenugopal Iyer 	/* Check if it is legacy driver */
12520dc2366fSVenugopal Iyer 	if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
12530dc2366fSVenugopal Iyer 	    "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
12540dc2366fSVenugopal Iyer 		goto done;
12550dc2366fSVenugopal Iyer 	}
12560dc2366fSVenugopal Iyer 
12570dc2366fSVenugopal Iyer 	if (is_legacy_driver) {
1258399dcf08Scarlos antonio neira bustos 		head = i_dlstat_legacy_rx_lane_stats(dh, linkname);
12590dc2366fSVenugopal Iyer 		goto done;
12600dc2366fSVenugopal Iyer 	}
12610dc2366fSVenugopal Iyer 
1262399dcf08Scarlos antonio neira bustos 	local_stats = i_dlstat_rx_local_stats(dh, linkname);
1263399dcf08Scarlos antonio neira bustos 	bcast_stats = i_dlstat_rx_bcast_stats(dh, linkname);
1264399dcf08Scarlos antonio neira bustos 	defunctlane_stats = i_dlstat_rx_defunctlane_stats(dh, linkname);
1265399dcf08Scarlos antonio neira bustos 	lane_stats = i_dlstat_rx_hwlane_stats(dh, linkname);
12660dc2366fSVenugopal Iyer 	if (lane_stats == NULL)
12670dc2366fSVenugopal Iyer 		lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname);
12680dc2366fSVenugopal Iyer 
12690dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(local_stats, bcast_stats);
12700dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(head, defunctlane_stats);
12710dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(head, lane_stats);
12720dc2366fSVenugopal Iyer done:
12730dc2366fSVenugopal Iyer 	return (head);
12740dc2366fSVenugopal Iyer }
12750dc2366fSVenugopal Iyer 
12760dc2366fSVenugopal Iyer /* Tx lane statistic specific functions */
12770dc2366fSVenugopal Iyer static boolean_t
12780dc2366fSVenugopal Iyer i_dlstat_tx_lane_match(void *arg1, void *arg2)
12790dc2366fSVenugopal Iyer {
12800dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s1 = arg1;
12810dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s2 = arg2;
12820dc2366fSVenugopal Iyer 
12830dc2366fSVenugopal Iyer 	return (s1->tle_index == s2->tle_index &&
12840dc2366fSVenugopal Iyer 	    s1->tle_id == s2->tle_id);
12850dc2366fSVenugopal Iyer }
12860dc2366fSVenugopal Iyer 
12870dc2366fSVenugopal Iyer static void *
12880dc2366fSVenugopal Iyer i_dlstat_tx_lane_stat_entry_diff(void *arg1, void *arg2)
12890dc2366fSVenugopal Iyer {
12900dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s1 = arg1;
12910dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *s2 = arg2;
12920dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t *diff_entry;
12930dc2366fSVenugopal Iyer 
12940dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (tx_lane_stat_entry_t));
12950dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
12960dc2366fSVenugopal Iyer 		goto done;
12970dc2366fSVenugopal Iyer 
12980dc2366fSVenugopal Iyer 	diff_entry->tle_index = s1->tle_index;
12990dc2366fSVenugopal Iyer 	diff_entry->tle_id = s1->tle_id;
13000dc2366fSVenugopal Iyer 
13010dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, tle_stats, tx_lane_stats_list,
13020dc2366fSVenugopal Iyer 	    TX_LANE_STAT_SIZE);
13030dc2366fSVenugopal Iyer 
13040dc2366fSVenugopal Iyer done:
13050dc2366fSVenugopal Iyer 	return (diff_entry);
13060dc2366fSVenugopal Iyer }
13070dc2366fSVenugopal Iyer 
13080dc2366fSVenugopal Iyer static void *
13090dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
13100dc2366fSVenugopal Iyer {
13110dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
13120dc2366fSVenugopal Iyer 
13130dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
13140dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
13150dc2366fSVenugopal Iyer 		goto done;
13160dc2366fSVenugopal Iyer 
13170dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index	= i;
13180dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id	= L_HWLANE;
13190dc2366fSVenugopal Iyer 
13200dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
13210dc2366fSVenugopal Iyer 	    tx_lane_stats_list, TX_LANE_STAT_SIZE);
13220dc2366fSVenugopal Iyer 
13230dc2366fSVenugopal Iyer done:
13240dc2366fSVenugopal Iyer 	return (tx_lane_stat_entry);
13250dc2366fSVenugopal Iyer }
13260dc2366fSVenugopal Iyer 
13270dc2366fSVenugopal Iyer static void *
1328*20535e13SToomas Soome i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused)
13290dc2366fSVenugopal Iyer {
13300dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
13310dc2366fSVenugopal Iyer 
13320dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
13330dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
13340dc2366fSVenugopal Iyer 		goto done;
13350dc2366fSVenugopal Iyer 
13360dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
13370dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_SWLANE;
13380dc2366fSVenugopal Iyer 
13390dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
13400dc2366fSVenugopal Iyer 	    tx_lane_stats_list, TX_LANE_STAT_SIZE);
13410dc2366fSVenugopal Iyer 
13420dc2366fSVenugopal Iyer done:
13430dc2366fSVenugopal Iyer 	return (tx_lane_stat_entry);
13440dc2366fSVenugopal Iyer }
13450dc2366fSVenugopal Iyer 
13460dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1347399dcf08Scarlos antonio neira bustos i_dlstat_tx_bcast_stats(dladm_handle_t handle, const char *linkname)
13480dc2366fSVenugopal Iyer {
13490dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
13500dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
13510dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
13520dc2366fSVenugopal Iyer 
1353399dcf08Scarlos antonio neira bustos 	misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
13540dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
13550dc2366fSVenugopal Iyer 		goto done;
13560dc2366fSVenugopal Iyer 
13570dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
13580dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
13590dc2366fSVenugopal Iyer 		goto done;
13600dc2366fSVenugopal Iyer 
13610dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
13620dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_BCAST;
13630dc2366fSVenugopal Iyer 
13640dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_opackets =
13650dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstxmt +
13660dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multixmt;
13670dc2366fSVenugopal Iyer 
13680dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_obytes =
13690dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_brdcstxmtbytes +
13700dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_multixmtbytes;
13710dc2366fSVenugopal Iyer 
13720dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
13730dc2366fSVenugopal Iyer 	if (head == NULL) {
13740dc2366fSVenugopal Iyer 		free(tx_lane_stat_entry);
13750dc2366fSVenugopal Iyer 		goto done;
13760dc2366fSVenugopal Iyer 	}
13770dc2366fSVenugopal Iyer 
13780dc2366fSVenugopal Iyer 	head->dc_statentry = tx_lane_stat_entry;
13790dc2366fSVenugopal Iyer 	head->dc_next = NULL;
13800dc2366fSVenugopal Iyer 
13810dc2366fSVenugopal Iyer 	free(misc_stat_entry);
13820dc2366fSVenugopal Iyer done:
13830dc2366fSVenugopal Iyer 	return (head);
13840dc2366fSVenugopal Iyer }
13850dc2366fSVenugopal Iyer 
13860dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1387399dcf08Scarlos antonio neira bustos i_dlstat_tx_defunctlane_stats(dladm_handle_t handle, const char *linkname)
13880dc2366fSVenugopal Iyer {
13890dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
13900dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
13910dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
13920dc2366fSVenugopal Iyer 
1393399dcf08Scarlos antonio neira bustos 	misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
13940dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
13950dc2366fSVenugopal Iyer 		goto done;
13960dc2366fSVenugopal Iyer 
13970dc2366fSVenugopal Iyer 	tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
13980dc2366fSVenugopal Iyer 	if (tx_lane_stat_entry == NULL)
13990dc2366fSVenugopal Iyer 		goto done;
14000dc2366fSVenugopal Iyer 
14010dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
14020dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_id = L_DFNCT;
14030dc2366fSVenugopal Iyer 
14040dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_opackets =
14050dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_opackets;
14060dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_obytes =
14070dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_obytes;
14080dc2366fSVenugopal Iyer 	tx_lane_stat_entry->tle_stats.tl_sdrops =
14090dc2366fSVenugopal Iyer 	    misc_stat_entry->mse_stats.ms_txsdrops;
14100dc2366fSVenugopal Iyer 
14110dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
14120dc2366fSVenugopal Iyer 	if (head == NULL) {
14130dc2366fSVenugopal Iyer 		free(tx_lane_stat_entry);
14140dc2366fSVenugopal Iyer 		goto done;
14150dc2366fSVenugopal Iyer 	}
14160dc2366fSVenugopal Iyer 
14170dc2366fSVenugopal Iyer 	head->dc_statentry = tx_lane_stat_entry;
14180dc2366fSVenugopal Iyer 	head->dc_next = NULL;
14190dc2366fSVenugopal Iyer 
14200dc2366fSVenugopal Iyer done:
14210dc2366fSVenugopal Iyer 	return (head);
14220dc2366fSVenugopal Iyer }
14230dc2366fSVenugopal Iyer 
14240dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1425399dcf08Scarlos antonio neira bustos i_dlstat_tx_hwlane_stats(dladm_handle_t handle, const char *linkname)
14260dc2366fSVenugopal Iyer {
14270dc2366fSVenugopal Iyer 	uint_t	tx_hwlane_idlist[MAX_RINGS_PER_GROUP];
14280dc2366fSVenugopal Iyer 	uint_t	tx_hwlane_idlist_size;
14290dc2366fSVenugopal Iyer 
1430399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(handle, linkname, DLSTAT_TX_HWLANE_IDLIST,
14310dc2366fSVenugopal Iyer 	    tx_hwlane_idlist, &tx_hwlane_idlist_size);
14320dc2366fSVenugopal Iyer 
1433399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_TX_HWLANE,
14340dc2366fSVenugopal Iyer 	    tx_hwlane_idlist, tx_hwlane_idlist_size,
14350dc2366fSVenugopal Iyer 	    i_dlstat_tx_hwlane_retrieve_stat));
14360dc2366fSVenugopal Iyer }
14370dc2366fSVenugopal Iyer 
14380dc2366fSVenugopal Iyer static dladm_stat_chain_t *
1439*20535e13SToomas Soome i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid __unused,
14400dc2366fSVenugopal Iyer     const char *linkname)
14410dc2366fSVenugopal Iyer {
1442399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_TX_SWLANE,
14430dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size,
14440dc2366fSVenugopal Iyer 	    i_dlstat_tx_swlane_retrieve_stat));
14450dc2366fSVenugopal Iyer }
14460dc2366fSVenugopal Iyer 
14470dc2366fSVenugopal Iyer void *
14480dc2366fSVenugopal Iyer dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
14490dc2366fSVenugopal Iyer {
14500dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
14510dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*bcast_stats = NULL;
14520dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*defunctlane_stats = NULL;
14530dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*lane_stats;
14540dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
14550dc2366fSVenugopal Iyer 	boolean_t		is_legacy_driver;
14560dc2366fSVenugopal Iyer 
14570dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
14580dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
14590dc2366fSVenugopal Iyer 		goto done;
14600dc2366fSVenugopal Iyer 	}
14610dc2366fSVenugopal Iyer 
14620dc2366fSVenugopal Iyer 	/* Check if it is legacy driver */
14630dc2366fSVenugopal Iyer 	if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
14640dc2366fSVenugopal Iyer 	    "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
14650dc2366fSVenugopal Iyer 		goto done;
14660dc2366fSVenugopal Iyer 	}
14670dc2366fSVenugopal Iyer 
14680dc2366fSVenugopal Iyer 	if (is_legacy_driver) {
1469399dcf08Scarlos antonio neira bustos 		head = i_dlstat_legacy_tx_lane_stats(dh, linkname);
14700dc2366fSVenugopal Iyer 		goto done;
14710dc2366fSVenugopal Iyer 	}
14720dc2366fSVenugopal Iyer 
1473399dcf08Scarlos antonio neira bustos 	bcast_stats = i_dlstat_tx_bcast_stats(dh, linkname);
1474399dcf08Scarlos antonio neira bustos 	defunctlane_stats = i_dlstat_tx_defunctlane_stats(dh, linkname);
1475399dcf08Scarlos antonio neira bustos 	lane_stats = i_dlstat_tx_hwlane_stats(dh, linkname);
14760dc2366fSVenugopal Iyer 	if (lane_stats == NULL)
14770dc2366fSVenugopal Iyer 		lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname);
14780dc2366fSVenugopal Iyer 
14790dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(bcast_stats, defunctlane_stats);
14800dc2366fSVenugopal Iyer 	head = i_dlstat_join_lists(head, lane_stats);
14810dc2366fSVenugopal Iyer 
14820dc2366fSVenugopal Iyer done:
14830dc2366fSVenugopal Iyer 	return (head);
14840dc2366fSVenugopal Iyer }
14850dc2366fSVenugopal Iyer 
14860dc2366fSVenugopal Iyer /* Rx lane total statistic specific functions */
14870dc2366fSVenugopal Iyer void *
14880dc2366fSVenugopal Iyer dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
14890dc2366fSVenugopal Iyer {
14900dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
14910dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*rx_lane_head, *curr;
14920dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*total_stats;
14930dc2366fSVenugopal Iyer 
14940dc2366fSVenugopal Iyer 	/* Get per rx lane stats */
14950dc2366fSVenugopal Iyer 	rx_lane_head = dlstat_rx_lane_stats(dh, linkid);
14960dc2366fSVenugopal Iyer 	if (rx_lane_head == NULL)
14970dc2366fSVenugopal Iyer 		goto done;
14980dc2366fSVenugopal Iyer 
14990dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (rx_lane_stat_entry_t));
15000dc2366fSVenugopal Iyer 	if (total_stats == NULL)
15010dc2366fSVenugopal Iyer 		goto done;
15020dc2366fSVenugopal Iyer 
15030dc2366fSVenugopal Iyer 	total_stats->rle_index = DLSTAT_INVALID_ENTRY;
15040dc2366fSVenugopal Iyer 	total_stats->rle_id = DLSTAT_INVALID_ENTRY;
15050dc2366fSVenugopal Iyer 
15060dc2366fSVenugopal Iyer 	for (curr = rx_lane_head; curr != NULL; curr = curr->dc_next) {
15070dc2366fSVenugopal Iyer 		rx_lane_stat_entry_t	*curr_lane_stats = curr->dc_statentry;
15080dc2366fSVenugopal Iyer 
15090dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->rle_stats,
15100dc2366fSVenugopal Iyer 		    &curr_lane_stats->rle_stats, &total_stats->rle_stats,
15110dc2366fSVenugopal Iyer 		    rx_lane_stats_list, RX_LANE_STAT_SIZE);
15120dc2366fSVenugopal Iyer 	}
15130dc2366fSVenugopal Iyer 
15140dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
15150dc2366fSVenugopal Iyer 	if (total_head == NULL) {
15160dc2366fSVenugopal Iyer 		free(total_stats);
15170dc2366fSVenugopal Iyer 		goto done;
15180dc2366fSVenugopal Iyer 	}
15190dc2366fSVenugopal Iyer 
15200dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
15210dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_rx_lane_total",
15220dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
15230dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
15240dc2366fSVenugopal Iyer 	free(rx_lane_head);
15250dc2366fSVenugopal Iyer 
15260dc2366fSVenugopal Iyer done:
15270dc2366fSVenugopal Iyer 	return (total_head);
15280dc2366fSVenugopal Iyer }
15290dc2366fSVenugopal Iyer 
15300dc2366fSVenugopal Iyer /* Tx lane total statistic specific functions */
15310dc2366fSVenugopal Iyer void *
15320dc2366fSVenugopal Iyer dlstat_tx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
15330dc2366fSVenugopal Iyer {
15340dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
15350dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*tx_lane_head, *curr;
15360dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*total_stats;
15370dc2366fSVenugopal Iyer 
15380dc2366fSVenugopal Iyer 	/* Get per tx lane stats */
15390dc2366fSVenugopal Iyer 	tx_lane_head = dlstat_tx_lane_stats(dh, linkid);
15400dc2366fSVenugopal Iyer 	if (tx_lane_head == NULL)
15410dc2366fSVenugopal Iyer 		goto done;
15420dc2366fSVenugopal Iyer 
15430dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (tx_lane_stat_entry_t));
15440dc2366fSVenugopal Iyer 	if (total_stats == NULL)
15450dc2366fSVenugopal Iyer 		goto done;
15460dc2366fSVenugopal Iyer 
15470dc2366fSVenugopal Iyer 	total_stats->tle_index = DLSTAT_INVALID_ENTRY;
15480dc2366fSVenugopal Iyer 	total_stats->tle_id = DLSTAT_INVALID_ENTRY;
15490dc2366fSVenugopal Iyer 
15500dc2366fSVenugopal Iyer 	for (curr = tx_lane_head; curr != NULL; curr = curr->dc_next) {
15510dc2366fSVenugopal Iyer 		tx_lane_stat_entry_t	*curr_lane_stats = curr->dc_statentry;
15520dc2366fSVenugopal Iyer 
15530dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->tle_stats,
15540dc2366fSVenugopal Iyer 		    &curr_lane_stats->tle_stats, &total_stats->tle_stats,
15550dc2366fSVenugopal Iyer 		    tx_lane_stats_list, TX_LANE_STAT_SIZE);
15560dc2366fSVenugopal Iyer 	}
15570dc2366fSVenugopal Iyer 
15580dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
15590dc2366fSVenugopal Iyer 	if (total_head == NULL) {
15600dc2366fSVenugopal Iyer 		free(total_stats);
15610dc2366fSVenugopal Iyer 		goto done;
15620dc2366fSVenugopal Iyer 	}
15630dc2366fSVenugopal Iyer 
15640dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
15650dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_tx_lane_total",
15660dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
15670dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
15680dc2366fSVenugopal Iyer 	free(tx_lane_head);
15690dc2366fSVenugopal Iyer 
15700dc2366fSVenugopal Iyer done:
15710dc2366fSVenugopal Iyer 	return (total_head);
15720dc2366fSVenugopal Iyer }
15730dc2366fSVenugopal Iyer 
15740dc2366fSVenugopal Iyer /* Fanout specific functions */
15750dc2366fSVenugopal Iyer static boolean_t
15760dc2366fSVenugopal Iyer i_dlstat_fanout_match(void *arg1, void *arg2)
15770dc2366fSVenugopal Iyer {
15780dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s1 = arg1;
15790dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s2 = arg2;
15800dc2366fSVenugopal Iyer 
15810dc2366fSVenugopal Iyer 	return (s1->fe_index == s2->fe_index &&
15820dc2366fSVenugopal Iyer 	    s1->fe_id == s2->fe_id &&
15830dc2366fSVenugopal Iyer 	    s1->fe_foutindex == s2->fe_foutindex);
15840dc2366fSVenugopal Iyer }
15850dc2366fSVenugopal Iyer 
15860dc2366fSVenugopal Iyer static void *
15870dc2366fSVenugopal Iyer i_dlstat_fanout_stat_entry_diff(void *arg1, void *arg2)
15880dc2366fSVenugopal Iyer {
15890dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s1 = arg1;
15900dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*s2 = arg2;
15910dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*diff_entry;
15920dc2366fSVenugopal Iyer 
15930dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (fanout_stat_entry_t));
15940dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
15950dc2366fSVenugopal Iyer 		goto done;
15960dc2366fSVenugopal Iyer 
15970dc2366fSVenugopal Iyer 	diff_entry->fe_index = s1->fe_index;
15980dc2366fSVenugopal Iyer 	diff_entry->fe_id = s1->fe_id;
15990dc2366fSVenugopal Iyer 	diff_entry->fe_foutindex = s1->fe_foutindex;
16000dc2366fSVenugopal Iyer 
16010dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, fe_stats, fanout_stats_list,
16020dc2366fSVenugopal Iyer 	    FANOUT_STAT_SIZE);
16030dc2366fSVenugopal Iyer 
16040dc2366fSVenugopal Iyer done:
16050dc2366fSVenugopal Iyer 	return (diff_entry);
16060dc2366fSVenugopal Iyer }
16070dc2366fSVenugopal Iyer 
16080dc2366fSVenugopal Iyer static void *
16090dc2366fSVenugopal Iyer i_dlstat_fanout_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
16100dc2366fSVenugopal Iyer {
16110dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*fanout_stat_entry;
16120dc2366fSVenugopal Iyer 
16130dc2366fSVenugopal Iyer 	fanout_stat_entry = calloc(1, sizeof (fanout_stat_entry_t));
16140dc2366fSVenugopal Iyer 	if (fanout_stat_entry == NULL)
16150dc2366fSVenugopal Iyer 		goto done;
16160dc2366fSVenugopal Iyer 
16170dc2366fSVenugopal Iyer 					/* Set by the caller later */
16180dc2366fSVenugopal Iyer 	fanout_stat_entry->fe_index = DLSTAT_INVALID_ENTRY;
16190dc2366fSVenugopal Iyer 	fanout_stat_entry->fe_id = DLSTAT_INVALID_ENTRY;
16200dc2366fSVenugopal Iyer 
16210dc2366fSVenugopal Iyer 	fanout_stat_entry->fe_foutindex = i;
16220dc2366fSVenugopal Iyer 
16230dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &fanout_stat_entry->fe_stats,
16240dc2366fSVenugopal Iyer 	    fanout_stats_list, FANOUT_STAT_SIZE);
16250dc2366fSVenugopal Iyer 
16260dc2366fSVenugopal Iyer done:
16270dc2366fSVenugopal Iyer 	return (fanout_stat_entry);
16280dc2366fSVenugopal Iyer }
16290dc2366fSVenugopal Iyer 
16300dc2366fSVenugopal Iyer static void *
16310dc2366fSVenugopal Iyer i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid,
16320dc2366fSVenugopal Iyer     uint_t idlist[], uint_t idlist_size,
16330dc2366fSVenugopal Iyer     const char *modname, const char *prefix)
16340dc2366fSVenugopal Iyer {
16350dc2366fSVenugopal Iyer 	int			i;
16360dc2366fSVenugopal Iyer 	char			statprefix[MAXLINKNAMELEN];
16370dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
16380dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr, *curr_head;
16390dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL, *prev = NULL;
16400dc2366fSVenugopal Iyer 	uint_t			fanout_idlist[MAX_RINGS_PER_GROUP];
16410dc2366fSVenugopal Iyer 	uint_t			fanout_idlist_size;
16420dc2366fSVenugopal Iyer 
16430dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
16440dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
16450dc2366fSVenugopal Iyer 		return (NULL);
16460dc2366fSVenugopal Iyer 	}
16470dc2366fSVenugopal Iyer 
1648399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(dh, linkname, DLSTAT_FANOUT_IDLIST,
16490dc2366fSVenugopal Iyer 	    fanout_idlist, &fanout_idlist_size);
16500dc2366fSVenugopal Iyer 
16510dc2366fSVenugopal Iyer 	for (i = 0; i < idlist_size; i++) {
16520dc2366fSVenugopal Iyer 		uint_t	index = idlist[i];
16530dc2366fSVenugopal Iyer 
16540dc2366fSVenugopal Iyer 		(void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout",
16550dc2366fSVenugopal Iyer 		    prefix, index);
16560dc2366fSVenugopal Iyer 
1657399dcf08Scarlos antonio neira bustos 		curr_head = i_dlstat_query_stats(dh, modname, statprefix,
16580dc2366fSVenugopal Iyer 		    fanout_idlist, fanout_idlist_size,
16590dc2366fSVenugopal Iyer 		    i_dlstat_fanout_retrieve_stat);
16600dc2366fSVenugopal Iyer 
16610dc2366fSVenugopal Iyer 		if (curr_head == NULL)	/* Last lane */
16620dc2366fSVenugopal Iyer 			break;
16630dc2366fSVenugopal Iyer 
16640dc2366fSVenugopal Iyer 		if (head == NULL)	/* First lane */
16650dc2366fSVenugopal Iyer 			head = curr_head;
16660dc2366fSVenugopal Iyer 		else	/* Link new lane list to end of previous lane list */
16670dc2366fSVenugopal Iyer 			prev->dc_next = curr_head;
16680dc2366fSVenugopal Iyer 
16690dc2366fSVenugopal Iyer 		/* Walk new lane list and set ids */
16700dc2366fSVenugopal Iyer 		for (curr = curr_head; curr != NULL; curr = curr->dc_next) {
16710dc2366fSVenugopal Iyer 			fanout_stat_entry_t *curr_stats = curr->dc_statentry;
16720dc2366fSVenugopal Iyer 
16730dc2366fSVenugopal Iyer 			curr_stats->fe_index = index;
16740dc2366fSVenugopal Iyer 			curr_stats->fe_id = L_HWLANE;
16750dc2366fSVenugopal Iyer 			/*
16760dc2366fSVenugopal Iyer 			 * Save last pointer of previous linked list.
16770dc2366fSVenugopal Iyer 			 * This pointer is used to chain linked lists
16780dc2366fSVenugopal Iyer 			 * generated in each iteration.
16790dc2366fSVenugopal Iyer 			 */
16800dc2366fSVenugopal Iyer 			prev = curr;
16810dc2366fSVenugopal Iyer 		}
16820dc2366fSVenugopal Iyer 	}
16830dc2366fSVenugopal Iyer 
16840dc2366fSVenugopal Iyer 	return (head);
16850dc2366fSVenugopal Iyer }
16860dc2366fSVenugopal Iyer 
16870dc2366fSVenugopal Iyer void *
16880dc2366fSVenugopal Iyer dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid,
16890dc2366fSVenugopal Iyer     const char *linkname)
16900dc2366fSVenugopal Iyer {
16910dc2366fSVenugopal Iyer 	return (i_dlstat_query_fanout_stats(dh, linkid,
16920dc2366fSVenugopal Iyer 	    default_idlist, default_idlist_size, linkname,
16930dc2366fSVenugopal Iyer 	    DLSTAT_MAC_RX_SWLANE));
16940dc2366fSVenugopal Iyer }
16950dc2366fSVenugopal Iyer 
16960dc2366fSVenugopal Iyer void *
16970dc2366fSVenugopal Iyer dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid,
16980dc2366fSVenugopal Iyer     const char *linkname)
16990dc2366fSVenugopal Iyer {
17000dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
17010dc2366fSVenugopal Iyer 	uint_t	rx_hwlane_idlist_size;
17020dc2366fSVenugopal Iyer 
1703399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(dh, linkname, DLSTAT_RX_HWLANE_IDLIST,
17040dc2366fSVenugopal Iyer 	    rx_hwlane_idlist, &rx_hwlane_idlist_size);
17050dc2366fSVenugopal Iyer 
17060dc2366fSVenugopal Iyer 	return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist,
17070dc2366fSVenugopal Iyer 	    rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE));
17080dc2366fSVenugopal Iyer }
17090dc2366fSVenugopal Iyer 
17100dc2366fSVenugopal Iyer void *
17110dc2366fSVenugopal Iyer dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid)
17120dc2366fSVenugopal Iyer {
17130dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
17140dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*fout_hwlane_stats;
17150dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*fout_swlane_and_local_stats;
17160dc2366fSVenugopal Iyer 	fanout_stat_entry_t	*fout_stats;
17170dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
17180dc2366fSVenugopal Iyer 
17190dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
17200dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
17210dc2366fSVenugopal Iyer 		goto done;
17220dc2366fSVenugopal Iyer 	}
17230dc2366fSVenugopal Iyer 
17240dc2366fSVenugopal Iyer 	fout_swlane_and_local_stats =
17250dc2366fSVenugopal Iyer 	    dlstat_fanout_swlane_and_local_stats(dh, linkid, linkname);
17260dc2366fSVenugopal Iyer 	fout_hwlane_stats = dlstat_fanout_hwlane_stats(dh, linkid, linkname);
17270dc2366fSVenugopal Iyer 
17280dc2366fSVenugopal Iyer 	if (fout_swlane_and_local_stats == NULL) {
17290dc2366fSVenugopal Iyer 		head = fout_hwlane_stats;
17300dc2366fSVenugopal Iyer 		goto done;
17310dc2366fSVenugopal Iyer 	}
17320dc2366fSVenugopal Iyer 
17330dc2366fSVenugopal Iyer 	fout_stats = fout_swlane_and_local_stats->dc_statentry;
17340dc2366fSVenugopal Iyer 
17350dc2366fSVenugopal Iyer 	if (fout_hwlane_stats != NULL) { /* hwlane(s), only local traffic */
17360dc2366fSVenugopal Iyer 		fout_stats->fe_id = L_LOCAL;
17370dc2366fSVenugopal Iyer 		fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
17380dc2366fSVenugopal Iyer 	} else { /* no hwlane, mix of local+sw classified */
17390dc2366fSVenugopal Iyer 		fout_stats->fe_id = L_LCLSWLANE;
17400dc2366fSVenugopal Iyer 		fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
17410dc2366fSVenugopal Iyer 	}
17420dc2366fSVenugopal Iyer 
17430dc2366fSVenugopal Iyer 	fout_swlane_and_local_stats->dc_next = fout_hwlane_stats;
17440dc2366fSVenugopal Iyer 	head = fout_swlane_and_local_stats;
17450dc2366fSVenugopal Iyer 
17460dc2366fSVenugopal Iyer done:
17470dc2366fSVenugopal Iyer 	return (head);
17480dc2366fSVenugopal Iyer }
17490dc2366fSVenugopal Iyer 
17500dc2366fSVenugopal Iyer /* Rx ring statistic specific functions */
17510dc2366fSVenugopal Iyer static boolean_t
17520dc2366fSVenugopal Iyer i_dlstat_rx_ring_match(void *arg1, void *arg2)
17530dc2366fSVenugopal Iyer {
17540dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*s1 = arg1;
17550dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*s2 = arg2;
17560dc2366fSVenugopal Iyer 
17570dc2366fSVenugopal Iyer 	return (s1->rle_index == s2->rle_index);
17580dc2366fSVenugopal Iyer }
17590dc2366fSVenugopal Iyer 
17600dc2366fSVenugopal Iyer static void *
17610dc2366fSVenugopal Iyer i_dlstat_rx_ring_stat_entry_diff(void *arg1, void *arg2)
17620dc2366fSVenugopal Iyer {
17630dc2366fSVenugopal Iyer 	ring_stat_entry_t	*s1 = arg1;
17640dc2366fSVenugopal Iyer 	ring_stat_entry_t	*s2 = arg2;
17650dc2366fSVenugopal Iyer 	ring_stat_entry_t	*diff_entry;
17660dc2366fSVenugopal Iyer 
17670dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (ring_stat_entry_t));
17680dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
17690dc2366fSVenugopal Iyer 		goto done;
17700dc2366fSVenugopal Iyer 
17710dc2366fSVenugopal Iyer 	diff_entry->re_index	= s1->re_index;
17720dc2366fSVenugopal Iyer 
17730dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, rx_ring_stats_list,
17740dc2366fSVenugopal Iyer 	    RX_RING_STAT_SIZE);
17750dc2366fSVenugopal Iyer 
17760dc2366fSVenugopal Iyer done:
17770dc2366fSVenugopal Iyer 	return (diff_entry);
17780dc2366fSVenugopal Iyer }
17790dc2366fSVenugopal Iyer 
17800dc2366fSVenugopal Iyer static void *
17810dc2366fSVenugopal Iyer i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
17820dc2366fSVenugopal Iyer {
17830dc2366fSVenugopal Iyer 	ring_stat_entry_t	*rx_ring_stat_entry;
17840dc2366fSVenugopal Iyer 
17850dc2366fSVenugopal Iyer 	rx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
17860dc2366fSVenugopal Iyer 	if (rx_ring_stat_entry == NULL)
17870dc2366fSVenugopal Iyer 		goto done;
17880dc2366fSVenugopal Iyer 
17890dc2366fSVenugopal Iyer 	rx_ring_stat_entry->re_index	= i;
17900dc2366fSVenugopal Iyer 
17910dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &rx_ring_stat_entry->re_stats,
17920dc2366fSVenugopal Iyer 	    rx_ring_stats_list, RX_RING_STAT_SIZE);
17930dc2366fSVenugopal Iyer 
17940dc2366fSVenugopal Iyer done:
17950dc2366fSVenugopal Iyer 	return (rx_ring_stat_entry);
17960dc2366fSVenugopal Iyer }
17970dc2366fSVenugopal Iyer 
17980dc2366fSVenugopal Iyer void *
17990dc2366fSVenugopal Iyer dlstat_rx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
18000dc2366fSVenugopal Iyer {
18010dc2366fSVenugopal Iyer 	uint_t			rx_ring_idlist[MAX_RINGS_PER_GROUP];
18020dc2366fSVenugopal Iyer 	uint_t			rx_ring_idlist_size;
18030dc2366fSVenugopal Iyer 	dladm_phys_attr_t	dpa;
18040dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
18050dc2366fSVenugopal Iyer 	char			*modname;
18060dc2366fSVenugopal Iyer 	datalink_class_t	class;
18070dc2366fSVenugopal Iyer 
18080dc2366fSVenugopal Iyer 	/*
18090dc2366fSVenugopal Iyer 	 * kstats corresponding to physical device rings continue to use
18100dc2366fSVenugopal Iyer 	 * device names even if the link is renamed using dladm rename-link.
18110dc2366fSVenugopal Iyer 	 * Thus, given a linkid, we lookup the physical device name.
18120dc2366fSVenugopal Iyer 	 * However, if an aggr is renamed, kstats corresponding to its
18130dc2366fSVenugopal Iyer 	 * pseudo rings are renamed as well.
18140dc2366fSVenugopal Iyer 	 */
18150dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
18160dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
18170dc2366fSVenugopal Iyer 		return (NULL);
18180dc2366fSVenugopal Iyer 	}
18190dc2366fSVenugopal Iyer 
18200dc2366fSVenugopal Iyer 	if (class != DATALINK_CLASS_AGGR) {
18210dc2366fSVenugopal Iyer 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
18220dc2366fSVenugopal Iyer 		    DLADM_STATUS_OK) {
18230dc2366fSVenugopal Iyer 			return (NULL);
18240dc2366fSVenugopal Iyer 		}
18250dc2366fSVenugopal Iyer 		modname = dpa.dp_dev;
18260dc2366fSVenugopal Iyer 	} else
18270dc2366fSVenugopal Iyer 		modname = linkname;
18280dc2366fSVenugopal Iyer 
1829399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(dh, modname, DLSTAT_RX_RING_IDLIST,
18300dc2366fSVenugopal Iyer 	    rx_ring_idlist, &rx_ring_idlist_size);
18310dc2366fSVenugopal Iyer 
1832399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_RX_RING,
18330dc2366fSVenugopal Iyer 	    rx_ring_idlist, rx_ring_idlist_size,
18340dc2366fSVenugopal Iyer 	    i_dlstat_rx_ring_retrieve_stat));
18350dc2366fSVenugopal Iyer }
18360dc2366fSVenugopal Iyer 
18370dc2366fSVenugopal Iyer /* Tx ring statistic specific functions */
18380dc2366fSVenugopal Iyer static boolean_t
18390dc2366fSVenugopal Iyer i_dlstat_tx_ring_match(void *arg1, void *arg2)
18400dc2366fSVenugopal Iyer {
18410dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*s1 = arg1;
18420dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*s2 = arg2;
18430dc2366fSVenugopal Iyer 
18440dc2366fSVenugopal Iyer 	return (s1->tle_index == s2->tle_index);
18450dc2366fSVenugopal Iyer }
18460dc2366fSVenugopal Iyer 
18470dc2366fSVenugopal Iyer static void *
18480dc2366fSVenugopal Iyer i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2)
18490dc2366fSVenugopal Iyer {
18500dc2366fSVenugopal Iyer 	ring_stat_entry_t	*s1 = arg1;
18510dc2366fSVenugopal Iyer 	ring_stat_entry_t	*s2 = arg2;
18520dc2366fSVenugopal Iyer 	ring_stat_entry_t	*diff_entry;
18530dc2366fSVenugopal Iyer 
18540dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (ring_stat_entry_t));
18550dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
18560dc2366fSVenugopal Iyer 		goto done;
18570dc2366fSVenugopal Iyer 
18580dc2366fSVenugopal Iyer 	diff_entry->re_index	= s1->re_index;
18590dc2366fSVenugopal Iyer 
18600dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, tx_ring_stats_list,
18610dc2366fSVenugopal Iyer 	    TX_RING_STAT_SIZE);
18620dc2366fSVenugopal Iyer 
18630dc2366fSVenugopal Iyer done:
18640dc2366fSVenugopal Iyer 	return (diff_entry);
18650dc2366fSVenugopal Iyer }
18660dc2366fSVenugopal Iyer 
18670dc2366fSVenugopal Iyer static void *
18680dc2366fSVenugopal Iyer i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
18690dc2366fSVenugopal Iyer {
18700dc2366fSVenugopal Iyer 	ring_stat_entry_t	*tx_ring_stat_entry;
18710dc2366fSVenugopal Iyer 
18720dc2366fSVenugopal Iyer 	tx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
18730dc2366fSVenugopal Iyer 	if (tx_ring_stat_entry == NULL)
18740dc2366fSVenugopal Iyer 		goto done;
18750dc2366fSVenugopal Iyer 
18760dc2366fSVenugopal Iyer 	tx_ring_stat_entry->re_index	= i;
18770dc2366fSVenugopal Iyer 
18780dc2366fSVenugopal Iyer 	i_dlstat_get_stats(kcp, ksp, &tx_ring_stat_entry->re_stats,
18790dc2366fSVenugopal Iyer 	    tx_ring_stats_list, TX_RING_STAT_SIZE);
18800dc2366fSVenugopal Iyer 
18810dc2366fSVenugopal Iyer done:
18820dc2366fSVenugopal Iyer 	return (tx_ring_stat_entry);
18830dc2366fSVenugopal Iyer }
18840dc2366fSVenugopal Iyer 
18850dc2366fSVenugopal Iyer void *
18860dc2366fSVenugopal Iyer dlstat_tx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
18870dc2366fSVenugopal Iyer {
18880dc2366fSVenugopal Iyer 	uint_t			tx_ring_idlist[MAX_RINGS_PER_GROUP];
18890dc2366fSVenugopal Iyer 	uint_t			tx_ring_idlist_size;
18900dc2366fSVenugopal Iyer 	dladm_phys_attr_t	dpa;
18910dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
18920dc2366fSVenugopal Iyer 	char			*modname;
18930dc2366fSVenugopal Iyer 	datalink_class_t	class;
18940dc2366fSVenugopal Iyer 
18950dc2366fSVenugopal Iyer 	/*
18960dc2366fSVenugopal Iyer 	 * kstats corresponding to physical device rings continue to use
18970dc2366fSVenugopal Iyer 	 * device names even if the link is renamed using dladm rename-link.
18980dc2366fSVenugopal Iyer 	 * Thus, given a linkid, we lookup the physical device name.
18990dc2366fSVenugopal Iyer 	 * However, if an aggr is renamed, kstats corresponding to its
19000dc2366fSVenugopal Iyer 	 * pseudo rings are renamed as well.
19010dc2366fSVenugopal Iyer 	 */
19020dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
19030dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
19040dc2366fSVenugopal Iyer 		return (NULL);
19050dc2366fSVenugopal Iyer 	}
19060dc2366fSVenugopal Iyer 
19070dc2366fSVenugopal Iyer 	if (class != DATALINK_CLASS_AGGR) {
19080dc2366fSVenugopal Iyer 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
19090dc2366fSVenugopal Iyer 		    DLADM_STATUS_OK) {
19100dc2366fSVenugopal Iyer 			return (NULL);
19110dc2366fSVenugopal Iyer 		}
19120dc2366fSVenugopal Iyer 		modname = dpa.dp_dev;
19130dc2366fSVenugopal Iyer 	} else
19140dc2366fSVenugopal Iyer 		modname = linkname;
19150dc2366fSVenugopal Iyer 
1916399dcf08Scarlos antonio neira bustos 	i_dlstat_get_idlist(dh, modname, DLSTAT_TX_RING_IDLIST,
19170dc2366fSVenugopal Iyer 	    tx_ring_idlist, &tx_ring_idlist_size);
19180dc2366fSVenugopal Iyer 
1919399dcf08Scarlos antonio neira bustos 	return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_TX_RING,
19200dc2366fSVenugopal Iyer 	    tx_ring_idlist, tx_ring_idlist_size,
19210dc2366fSVenugopal Iyer 	    i_dlstat_tx_ring_retrieve_stat));
19220dc2366fSVenugopal Iyer }
19230dc2366fSVenugopal Iyer 
19240dc2366fSVenugopal Iyer /* Rx ring total statistic specific functions */
19250dc2366fSVenugopal Iyer void *
19260dc2366fSVenugopal Iyer dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
19270dc2366fSVenugopal Iyer {
19280dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
19290dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*rx_ring_head, *curr;
19300dc2366fSVenugopal Iyer 	ring_stat_entry_t	*total_stats;
19310dc2366fSVenugopal Iyer 
19320dc2366fSVenugopal Iyer 	/* Get per rx ring stats */
19330dc2366fSVenugopal Iyer 	rx_ring_head = dlstat_rx_ring_stats(dh, linkid);
19340dc2366fSVenugopal Iyer 	if (rx_ring_head == NULL)
19350dc2366fSVenugopal Iyer 		goto done;
19360dc2366fSVenugopal Iyer 
19370dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (ring_stat_entry_t));
19380dc2366fSVenugopal Iyer 	if (total_stats == NULL)
19390dc2366fSVenugopal Iyer 		goto done;
19400dc2366fSVenugopal Iyer 
19410dc2366fSVenugopal Iyer 	total_stats->re_index = DLSTAT_INVALID_ENTRY;
19420dc2366fSVenugopal Iyer 
19430dc2366fSVenugopal Iyer 	for (curr = rx_ring_head; curr != NULL; curr = curr->dc_next) {
19440dc2366fSVenugopal Iyer 		ring_stat_entry_t	*curr_ring_stats = curr->dc_statentry;
19450dc2366fSVenugopal Iyer 
19460dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->re_stats,
19470dc2366fSVenugopal Iyer 		    &curr_ring_stats->re_stats, &total_stats->re_stats,
19480dc2366fSVenugopal Iyer 		    rx_ring_stats_list, RX_RING_STAT_SIZE);
19490dc2366fSVenugopal Iyer 	}
19500dc2366fSVenugopal Iyer 
19510dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
19520dc2366fSVenugopal Iyer 	if (total_head == NULL) {
19530dc2366fSVenugopal Iyer 		free(total_stats);
19540dc2366fSVenugopal Iyer 		goto done;
19550dc2366fSVenugopal Iyer 	}
19560dc2366fSVenugopal Iyer 
19570dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
19580dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_rx_ring_total",
19590dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
19600dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
19610dc2366fSVenugopal Iyer 	free(rx_ring_head);
19620dc2366fSVenugopal Iyer 
19630dc2366fSVenugopal Iyer done:
19640dc2366fSVenugopal Iyer 	return (total_head);
19650dc2366fSVenugopal Iyer }
19660dc2366fSVenugopal Iyer 
19670dc2366fSVenugopal Iyer /* Tx ring total statistic specific functions */
19680dc2366fSVenugopal Iyer void *
19690dc2366fSVenugopal Iyer dlstat_tx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
19700dc2366fSVenugopal Iyer {
19710dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_head = NULL;
19720dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*tx_ring_head, *curr;
19730dc2366fSVenugopal Iyer 	ring_stat_entry_t	*total_stats;
19740dc2366fSVenugopal Iyer 
19750dc2366fSVenugopal Iyer 	/* Get per tx ring stats */
19760dc2366fSVenugopal Iyer 	tx_ring_head = dlstat_tx_ring_stats(dh, linkid);
19770dc2366fSVenugopal Iyer 	if (tx_ring_head == NULL)
19780dc2366fSVenugopal Iyer 		goto done;
19790dc2366fSVenugopal Iyer 
19800dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (ring_stat_entry_t));
19810dc2366fSVenugopal Iyer 	if (total_stats == NULL)
19820dc2366fSVenugopal Iyer 		goto done;
19830dc2366fSVenugopal Iyer 
19840dc2366fSVenugopal Iyer 	total_stats->re_index = DLSTAT_INVALID_ENTRY;
19850dc2366fSVenugopal Iyer 
19860dc2366fSVenugopal Iyer 	for (curr = tx_ring_head; curr != NULL; curr = curr->dc_next) {
19870dc2366fSVenugopal Iyer 		ring_stat_entry_t	*curr_ring_stats = curr->dc_statentry;
19880dc2366fSVenugopal Iyer 
19890dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->re_stats,
19900dc2366fSVenugopal Iyer 		    &curr_ring_stats->re_stats, &total_stats->re_stats,
19910dc2366fSVenugopal Iyer 		    tx_ring_stats_list, TX_RING_STAT_SIZE);
19920dc2366fSVenugopal Iyer 	}
19930dc2366fSVenugopal Iyer 
19940dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
19950dc2366fSVenugopal Iyer 	if (total_head == NULL) {
19960dc2366fSVenugopal Iyer 		free(total_stats);
19970dc2366fSVenugopal Iyer 		goto done;
19980dc2366fSVenugopal Iyer 	}
19990dc2366fSVenugopal Iyer 
20000dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
20010dc2366fSVenugopal Iyer 	(void) strlcpy(total_head->dc_statheader, "mac_tx_ring_total",
20020dc2366fSVenugopal Iyer 	    sizeof (total_head->dc_statheader));
20030dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
20040dc2366fSVenugopal Iyer 	free(tx_ring_head);
20050dc2366fSVenugopal Iyer 
20060dc2366fSVenugopal Iyer done:
20070dc2366fSVenugopal Iyer 	return (total_head);
20080dc2366fSVenugopal Iyer }
20090dc2366fSVenugopal Iyer 
20100dc2366fSVenugopal Iyer /* Summary statistic specific functions */
20110dc2366fSVenugopal Iyer static boolean_t
2012*20535e13SToomas Soome i_dlstat_total_match(void *arg1 __unused, void *arg2 __unused)
201362ef8476SYuri Pankov {
201462ef8476SYuri Pankov 	/* Always single entry for total */
20150dc2366fSVenugopal Iyer 	return (B_TRUE);
20160dc2366fSVenugopal Iyer }
20170dc2366fSVenugopal Iyer 
20180dc2366fSVenugopal Iyer static void *
20190dc2366fSVenugopal Iyer i_dlstat_total_stat_entry_diff(void *arg1, void *arg2)
20200dc2366fSVenugopal Iyer {
20210dc2366fSVenugopal Iyer 	total_stat_entry_t	*s1 = arg1;
20220dc2366fSVenugopal Iyer 	total_stat_entry_t	*s2 = arg2;
20230dc2366fSVenugopal Iyer 	total_stat_entry_t	*diff_entry;
20240dc2366fSVenugopal Iyer 
20250dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (total_stat_entry_t));
20260dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
20270dc2366fSVenugopal Iyer 		goto done;
20280dc2366fSVenugopal Iyer 
20290dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, tse_stats, total_stats_list,
20300dc2366fSVenugopal Iyer 	    TOTAL_STAT_SIZE);
20310dc2366fSVenugopal Iyer 
20320dc2366fSVenugopal Iyer done:
20330dc2366fSVenugopal Iyer 	return (diff_entry);
20340dc2366fSVenugopal Iyer }
20350dc2366fSVenugopal Iyer 
20360dc2366fSVenugopal Iyer void *
20370dc2366fSVenugopal Iyer dlstat_total_stats(dladm_handle_t dh, datalink_id_t linkid)
20380dc2366fSVenugopal Iyer {
20390dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
20400dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*rx_total;
20410dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*tx_total;
20420dc2366fSVenugopal Iyer 	total_stat_entry_t	*total_stat_entry;
20430dc2366fSVenugopal Iyer 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
20440dc2366fSVenugopal Iyer 	tx_lane_stat_entry_t	*tx_lane_stat_entry;
20450dc2366fSVenugopal Iyer 
20460dc2366fSVenugopal Iyer 	/* Get total rx lane stats */
20470dc2366fSVenugopal Iyer 	rx_total = dlstat_rx_lane_total_stats(dh, linkid);
20480dc2366fSVenugopal Iyer 	if (rx_total == NULL)
20490dc2366fSVenugopal Iyer 		goto done;
20500dc2366fSVenugopal Iyer 
20510dc2366fSVenugopal Iyer 	/* Get total tx lane stats */
20520dc2366fSVenugopal Iyer 	tx_total = dlstat_tx_lane_total_stats(dh, linkid);
20530dc2366fSVenugopal Iyer 	if (tx_total == NULL)
20540dc2366fSVenugopal Iyer 		goto done;
20550dc2366fSVenugopal Iyer 
20560dc2366fSVenugopal Iyer 	/* Build total stat */
20570dc2366fSVenugopal Iyer 	total_stat_entry = calloc(1, sizeof (total_stat_entry_t));
20580dc2366fSVenugopal Iyer 	if (total_stat_entry == NULL)
20590dc2366fSVenugopal Iyer 		goto done;
20600dc2366fSVenugopal Iyer 
20610dc2366fSVenugopal Iyer 	rx_lane_stat_entry = rx_total->dc_statentry;
20620dc2366fSVenugopal Iyer 	tx_lane_stat_entry = tx_total->dc_statentry;
20630dc2366fSVenugopal Iyer 
20640dc2366fSVenugopal Iyer 	/* Extract total rx ipackets, rbytes */
20650dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_ipackets =
20660dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_ipackets;
20670dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_rbytes =
20680dc2366fSVenugopal Iyer 	    rx_lane_stat_entry->rle_stats.rl_rbytes;
20690dc2366fSVenugopal Iyer 
20700dc2366fSVenugopal Iyer 	/* Extract total tx opackets, obytes */
20710dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_opackets =
20720dc2366fSVenugopal Iyer 	    tx_lane_stat_entry->tle_stats.tl_opackets;
20730dc2366fSVenugopal Iyer 	total_stat_entry->tse_stats.ts_obytes =
20740dc2366fSVenugopal Iyer 	    tx_lane_stat_entry->tle_stats.tl_obytes;
20750dc2366fSVenugopal Iyer 
20760dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
20770dc2366fSVenugopal Iyer 	if (head == NULL) {
20780dc2366fSVenugopal Iyer 		free(total_stat_entry);
20790dc2366fSVenugopal Iyer 		goto done;
20800dc2366fSVenugopal Iyer 	}
20810dc2366fSVenugopal Iyer 
20820dc2366fSVenugopal Iyer 	head->dc_statentry = total_stat_entry;
20830dc2366fSVenugopal Iyer 	(void) strlcpy(head->dc_statheader, "mac_lane_total",
20840dc2366fSVenugopal Iyer 	    sizeof (head->dc_statheader));
20850dc2366fSVenugopal Iyer 	head->dc_next = NULL;
20860dc2366fSVenugopal Iyer 	free(rx_total);
20870dc2366fSVenugopal Iyer 	free(tx_total);
20880dc2366fSVenugopal Iyer 
20890dc2366fSVenugopal Iyer done:
20900dc2366fSVenugopal Iyer 	return (head);
20910dc2366fSVenugopal Iyer }
20920dc2366fSVenugopal Iyer 
20930dc2366fSVenugopal Iyer /* Aggr total statistic(summed across all component ports) specific functions */
20940dc2366fSVenugopal Iyer void *
20950dc2366fSVenugopal Iyer dlstat_aggr_total_stats(dladm_stat_chain_t *head)
20960dc2366fSVenugopal Iyer {
20970dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
2098f7952617SToomas Soome 	dladm_stat_chain_t	*total_head = NULL;
20990dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*total_stats;
21000dc2366fSVenugopal Iyer 
21010dc2366fSVenugopal Iyer 	total_stats = calloc(1, sizeof (aggr_port_stat_entry_t));
21020dc2366fSVenugopal Iyer 	if (total_stats == NULL)
21030dc2366fSVenugopal Iyer 		goto done;
21040dc2366fSVenugopal Iyer 
21050dc2366fSVenugopal Iyer 	total_stats->ape_portlinkid = DATALINK_INVALID_LINKID;
21060dc2366fSVenugopal Iyer 
21070dc2366fSVenugopal Iyer 	for (curr = head; curr != NULL; curr = curr->dc_next) {
21080dc2366fSVenugopal Iyer 		aggr_port_stat_entry_t	*curr_aggr_port_stats;
21090dc2366fSVenugopal Iyer 
21100dc2366fSVenugopal Iyer 		curr_aggr_port_stats = curr->dc_statentry;
21110dc2366fSVenugopal Iyer 
21120dc2366fSVenugopal Iyer 		i_dlstat_sum_stats(&total_stats->ape_stats,
21130dc2366fSVenugopal Iyer 		    &curr_aggr_port_stats->ape_stats, &total_stats->ape_stats,
21140dc2366fSVenugopal Iyer 		    aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
21150dc2366fSVenugopal Iyer 	}
21160dc2366fSVenugopal Iyer 
21170dc2366fSVenugopal Iyer 	total_head = malloc(sizeof (dladm_stat_chain_t));
21180dc2366fSVenugopal Iyer 	if (total_head == NULL) {
21190dc2366fSVenugopal Iyer 		free(total_stats);
21200dc2366fSVenugopal Iyer 		goto done;
21210dc2366fSVenugopal Iyer 	}
21220dc2366fSVenugopal Iyer 
21230dc2366fSVenugopal Iyer 	total_head->dc_statentry = total_stats;
21240dc2366fSVenugopal Iyer 	total_head->dc_next = NULL;
21250dc2366fSVenugopal Iyer 
21260dc2366fSVenugopal Iyer done:
21270dc2366fSVenugopal Iyer 	return (total_head);
21280dc2366fSVenugopal Iyer }
21290dc2366fSVenugopal Iyer 
21300dc2366fSVenugopal Iyer /* Aggr port statistic specific functions */
21310dc2366fSVenugopal Iyer static boolean_t
21320dc2366fSVenugopal Iyer i_dlstat_aggr_port_match(void *arg1, void *arg2)
21330dc2366fSVenugopal Iyer {
21340dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t *s1 = arg1;
21350dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t *s2 = arg2;
21360dc2366fSVenugopal Iyer 
21370dc2366fSVenugopal Iyer 	return (s1->ape_portlinkid == s2->ape_portlinkid);
21380dc2366fSVenugopal Iyer }
21390dc2366fSVenugopal Iyer 
21400dc2366fSVenugopal Iyer static void *
21410dc2366fSVenugopal Iyer i_dlstat_aggr_port_stat_entry_diff(void *arg1, void *arg2)
21420dc2366fSVenugopal Iyer {
21430dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*s1 = arg1;
21440dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*s2 = arg2;
21450dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*diff_entry;
21460dc2366fSVenugopal Iyer 
21470dc2366fSVenugopal Iyer 	diff_entry = malloc(sizeof (aggr_port_stat_entry_t));
21480dc2366fSVenugopal Iyer 	if (diff_entry == NULL)
21490dc2366fSVenugopal Iyer 		goto done;
21500dc2366fSVenugopal Iyer 
21510dc2366fSVenugopal Iyer 	diff_entry->ape_portlinkid = s1->ape_portlinkid;
21520dc2366fSVenugopal Iyer 
21530dc2366fSVenugopal Iyer 	DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list,
21540dc2366fSVenugopal Iyer 	    AGGR_PORT_STAT_SIZE);
21550dc2366fSVenugopal Iyer 
21560dc2366fSVenugopal Iyer done:
21570dc2366fSVenugopal Iyer 	return (diff_entry);
21580dc2366fSVenugopal Iyer }
21590dc2366fSVenugopal Iyer 
21600dc2366fSVenugopal Iyer /*
21610dc2366fSVenugopal Iyer  * Query dls stats for the aggr port. This results in query for stats into
21620dc2366fSVenugopal Iyer  * the corresponding device driver.
21630dc2366fSVenugopal Iyer  */
21640dc2366fSVenugopal Iyer static aggr_port_stat_entry_t *
2165399dcf08Scarlos antonio neira bustos i_dlstat_single_port_stats(dladm_handle_t handle, const char *portname,
2166399dcf08Scarlos antonio neira bustos     datalink_id_t linkid)
21670dc2366fSVenugopal Iyer {
21680dc2366fSVenugopal Iyer 	kstat_t			*ksp;
21690dc2366fSVenugopal Iyer 	char			module[DLPI_LINKNAME_MAX];
21700dc2366fSVenugopal Iyer 	uint_t			instance;
21710dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*aggr_port_stat_entry = NULL;
21720dc2366fSVenugopal Iyer 
21730dc2366fSVenugopal Iyer 	if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK)
21740dc2366fSVenugopal Iyer 		goto done;
21750dc2366fSVenugopal Iyer 
2176399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(handle) == NULL) {
21770dc2366fSVenugopal Iyer 		warn("kstat open operation failed");
21780dc2366fSVenugopal Iyer 		return (NULL);
21790dc2366fSVenugopal Iyer 	}
21800dc2366fSVenugopal Iyer 
2181399dcf08Scarlos antonio neira bustos 	ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), module, instance,
2182399dcf08Scarlos antonio neira bustos 	    "mac", NULL);
21830dc2366fSVenugopal Iyer 	if (ksp == NULL)
21840dc2366fSVenugopal Iyer 		goto done;
21850dc2366fSVenugopal Iyer 
21860dc2366fSVenugopal Iyer 	aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t));
21870dc2366fSVenugopal Iyer 	if (aggr_port_stat_entry == NULL)
21880dc2366fSVenugopal Iyer 		goto done;
21890dc2366fSVenugopal Iyer 
21900dc2366fSVenugopal Iyer 	/* Save port's linkid */
21910dc2366fSVenugopal Iyer 	aggr_port_stat_entry->ape_portlinkid = linkid;
21920dc2366fSVenugopal Iyer 
2193399dcf08Scarlos antonio neira bustos 	i_dlstat_get_stats(dladm_dld_kcp(handle), ksp,
2194399dcf08Scarlos antonio neira bustos 	    &aggr_port_stat_entry->ape_stats,
21950dc2366fSVenugopal Iyer 	    aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
21960dc2366fSVenugopal Iyer done:
21970dc2366fSVenugopal Iyer 	return (aggr_port_stat_entry);
21980dc2366fSVenugopal Iyer }
21990dc2366fSVenugopal Iyer 
22000dc2366fSVenugopal Iyer void *
22010dc2366fSVenugopal Iyer dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid)
22020dc2366fSVenugopal Iyer {
22030dc2366fSVenugopal Iyer 	dladm_aggr_grp_attr_t	ginfo;
22040dc2366fSVenugopal Iyer 	int			i;
22050dc2366fSVenugopal Iyer 	dladm_aggr_port_attr_t	 *portp;
22060dc2366fSVenugopal Iyer 	dladm_phys_attr_t	dpa;
22070dc2366fSVenugopal Iyer 	aggr_port_stat_entry_t	*aggr_port_stat_entry;
22080dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL, *prev = NULL, *curr;
22090dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*total_stats;
22100dc2366fSVenugopal Iyer 
22110dc2366fSVenugopal Iyer 	/* Get aggr info */
22120dc2366fSVenugopal Iyer 	bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
22130dc2366fSVenugopal Iyer 	if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE)
22140dc2366fSVenugopal Iyer 	    != DLADM_STATUS_OK)
22150dc2366fSVenugopal Iyer 		goto done;
22160dc2366fSVenugopal Iyer 	/* For every port that is member of this aggr do */
22170dc2366fSVenugopal Iyer 	for (i = 0; i < ginfo.lg_nports; i++) {
22180dc2366fSVenugopal Iyer 		portp = &(ginfo.lg_ports[i]);
22190dc2366fSVenugopal Iyer 		if (dladm_phys_info(dh, portp->lp_linkid, &dpa,
22200dc2366fSVenugopal Iyer 		    DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
22210dc2366fSVenugopal Iyer 			goto done;
22220dc2366fSVenugopal Iyer 		}
22230dc2366fSVenugopal Iyer 
2224399dcf08Scarlos antonio neira bustos 		aggr_port_stat_entry = i_dlstat_single_port_stats(dh,
2225399dcf08Scarlos antonio neira bustos 		    dpa.dp_dev, portp->lp_linkid);
22260dc2366fSVenugopal Iyer 
22270dc2366fSVenugopal Iyer 		/* Create dladm_stat_chain_t object for this stat */
22280dc2366fSVenugopal Iyer 		curr = malloc(sizeof (dladm_stat_chain_t));
22290dc2366fSVenugopal Iyer 		if (curr == NULL) {
22300dc2366fSVenugopal Iyer 			free(aggr_port_stat_entry);
22310dc2366fSVenugopal Iyer 			goto done;
22320dc2366fSVenugopal Iyer 		}
22330dc2366fSVenugopal Iyer 		(void) strlcpy(curr->dc_statheader, dpa.dp_dev,
22340dc2366fSVenugopal Iyer 		    sizeof (curr->dc_statheader));
22350dc2366fSVenugopal Iyer 		curr->dc_statentry = aggr_port_stat_entry;
22360dc2366fSVenugopal Iyer 		curr->dc_next = NULL;
22370dc2366fSVenugopal Iyer 
22380dc2366fSVenugopal Iyer 		/* Chain this aggr port stat entry */
22390dc2366fSVenugopal Iyer 		/* head of the stat list */
22400dc2366fSVenugopal Iyer 		if (prev == NULL)
22410dc2366fSVenugopal Iyer 			head = curr;
22420dc2366fSVenugopal Iyer 		else
22430dc2366fSVenugopal Iyer 			prev->dc_next = curr;
22440dc2366fSVenugopal Iyer 		prev = curr;
22450dc2366fSVenugopal Iyer 	}
22460dc2366fSVenugopal Iyer 
22470dc2366fSVenugopal Iyer 	/*
22480dc2366fSVenugopal Iyer 	 * Prepend the stat list with cumulative aggr stats i.e. summed over all
22490dc2366fSVenugopal Iyer 	 * component ports
22500dc2366fSVenugopal Iyer 	 */
22510dc2366fSVenugopal Iyer 	total_stats = dlstat_aggr_total_stats(head);
22520dc2366fSVenugopal Iyer 	if (total_stats != NULL) {
22530dc2366fSVenugopal Iyer 		total_stats->dc_next = head;
22540dc2366fSVenugopal Iyer 		head = total_stats;
22550dc2366fSVenugopal Iyer 	}
22560dc2366fSVenugopal Iyer 
22570dc2366fSVenugopal Iyer done:
22580dc2366fSVenugopal Iyer 	free(ginfo.lg_ports);
22590dc2366fSVenugopal Iyer 	return (head);
22600dc2366fSVenugopal Iyer }
22610dc2366fSVenugopal Iyer 
22620dc2366fSVenugopal Iyer /* Misc stat specific functions */
22630dc2366fSVenugopal Iyer void *
22640dc2366fSVenugopal Iyer dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid)
22650dc2366fSVenugopal Iyer {
22660dc2366fSVenugopal Iyer 	misc_stat_entry_t	*misc_stat_entry;
22670dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*head = NULL;
22680dc2366fSVenugopal Iyer 	char			linkname[MAXLINKNAMELEN];
22690dc2366fSVenugopal Iyer 
22700dc2366fSVenugopal Iyer 	if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
22710dc2366fSVenugopal Iyer 	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
22720dc2366fSVenugopal Iyer 		goto done;
22730dc2366fSVenugopal Iyer 	}
22740dc2366fSVenugopal Iyer 
2275399dcf08Scarlos antonio neira bustos 	misc_stat_entry = i_dlstat_misc_stats(dh, linkname);
22760dc2366fSVenugopal Iyer 	if (misc_stat_entry == NULL)
22770dc2366fSVenugopal Iyer 		goto done;
22780dc2366fSVenugopal Iyer 
22790dc2366fSVenugopal Iyer 	head = malloc(sizeof (dladm_stat_chain_t));
22800dc2366fSVenugopal Iyer 	if (head == NULL) {
22810dc2366fSVenugopal Iyer 		free(misc_stat_entry);
22820dc2366fSVenugopal Iyer 		goto done;
22830dc2366fSVenugopal Iyer 	}
22840dc2366fSVenugopal Iyer 
22850dc2366fSVenugopal Iyer 	head->dc_statentry = misc_stat_entry;
22860dc2366fSVenugopal Iyer 	(void) strlcpy(head->dc_statheader, "mac_misc_stat",
22870dc2366fSVenugopal Iyer 	    sizeof (head->dc_statheader));
22880dc2366fSVenugopal Iyer 	head->dc_next = NULL;
22890dc2366fSVenugopal Iyer 
22900dc2366fSVenugopal Iyer done:
22910dc2366fSVenugopal Iyer 	return (head);
22920dc2366fSVenugopal Iyer }
22930dc2366fSVenugopal Iyer 
22940dc2366fSVenugopal Iyer /* Exported functions */
22950dc2366fSVenugopal Iyer dladm_stat_chain_t *
22960dc2366fSVenugopal Iyer dladm_link_stat_query(dladm_handle_t dh, datalink_id_t linkid,
22970dc2366fSVenugopal Iyer     dladm_stat_type_t stattype)
22980dc2366fSVenugopal Iyer {
22990dc2366fSVenugopal Iyer 	return (dladm_stat_table[stattype].ds_querystat(dh, linkid));
23000dc2366fSVenugopal Iyer }
23010dc2366fSVenugopal Iyer 
23020dc2366fSVenugopal Iyer dladm_stat_chain_t *
23030dc2366fSVenugopal Iyer dladm_link_stat_diffchain(dladm_stat_chain_t *op1, dladm_stat_chain_t *op2,
23040dc2366fSVenugopal Iyer     dladm_stat_type_t stattype)
23050dc2366fSVenugopal Iyer {
23060dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*op1_curr, *op2_curr;
23070dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*diff_curr;
23080dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*diff_prev = NULL, *diff_head = NULL;
23090dc2366fSVenugopal Iyer 
23100dc2366fSVenugopal Iyer 				/* Perform op1 - op2, store result in diff */
23110dc2366fSVenugopal Iyer 	for (op1_curr = op1; op1_curr != NULL; op1_curr = op1_curr->dc_next) {
23120dc2366fSVenugopal Iyer 		for (op2_curr = op2; op2_curr != NULL;
23130dc2366fSVenugopal Iyer 		    op2_curr = op2_curr->dc_next) {
23140dc2366fSVenugopal Iyer 			if (dlstat_match_stats(op1_curr->dc_statentry,
23150dc2366fSVenugopal Iyer 			    op2_curr->dc_statentry, stattype)) {
23160dc2366fSVenugopal Iyer 				break;
23170dc2366fSVenugopal Iyer 			}
23180dc2366fSVenugopal Iyer 		}
23190dc2366fSVenugopal Iyer 		diff_curr = malloc(sizeof (dladm_stat_chain_t));
23200dc2366fSVenugopal Iyer 		if (diff_curr == NULL)
23210dc2366fSVenugopal Iyer 			goto done;
23220dc2366fSVenugopal Iyer 
23230dc2366fSVenugopal Iyer 		diff_curr->dc_next = NULL;
23240dc2366fSVenugopal Iyer 
23250dc2366fSVenugopal Iyer 		if (op2_curr == NULL) {
23260dc2366fSVenugopal Iyer 			/* prev iteration did not have this stat entry */
23270dc2366fSVenugopal Iyer 			diff_curr->dc_statentry =
23280dc2366fSVenugopal Iyer 			    dlstat_diff_stats(op1_curr->dc_statentry,
23290dc2366fSVenugopal Iyer 			    NULL, stattype);
23300dc2366fSVenugopal Iyer 		} else {
23310dc2366fSVenugopal Iyer 			diff_curr->dc_statentry =
23320dc2366fSVenugopal Iyer 			    dlstat_diff_stats(op1_curr->dc_statentry,
23330dc2366fSVenugopal Iyer 			    op2_curr->dc_statentry, stattype);
23340dc2366fSVenugopal Iyer 		}
23350dc2366fSVenugopal Iyer 
23360dc2366fSVenugopal Iyer 		if (diff_curr->dc_statentry == NULL) {
23370dc2366fSVenugopal Iyer 			free(diff_curr);
23380dc2366fSVenugopal Iyer 			goto done;
23390dc2366fSVenugopal Iyer 		}
23400dc2366fSVenugopal Iyer 
23410dc2366fSVenugopal Iyer 		if (diff_prev == NULL) /* head of the diff stat list */
23420dc2366fSVenugopal Iyer 			diff_head = diff_curr;
23430dc2366fSVenugopal Iyer 		else
23440dc2366fSVenugopal Iyer 			diff_prev->dc_next = diff_curr;
23450dc2366fSVenugopal Iyer 		diff_prev = diff_curr;
23460dc2366fSVenugopal Iyer 	}
23470dc2366fSVenugopal Iyer done:
23480dc2366fSVenugopal Iyer 	return (diff_head);
23490dc2366fSVenugopal Iyer }
23500dc2366fSVenugopal Iyer 
23510dc2366fSVenugopal Iyer void
23520dc2366fSVenugopal Iyer dladm_link_stat_free(dladm_stat_chain_t *curr)
23530dc2366fSVenugopal Iyer {
23540dc2366fSVenugopal Iyer 	while (curr != NULL) {
23550dc2366fSVenugopal Iyer 		dladm_stat_chain_t	*tofree = curr;
23560dc2366fSVenugopal Iyer 
23570dc2366fSVenugopal Iyer 		curr = curr->dc_next;
23580dc2366fSVenugopal Iyer 		free(tofree->dc_statentry);
23590dc2366fSVenugopal Iyer 		free(tofree);
23600dc2366fSVenugopal Iyer 	}
23610dc2366fSVenugopal Iyer }
23620dc2366fSVenugopal Iyer 
23630dc2366fSVenugopal Iyer /* Query all link stats */
23640dc2366fSVenugopal Iyer static name_value_stat_t *
23650dc2366fSVenugopal Iyer i_dlstat_convert_stats(void *stats, stat_info_t stats_list[], uint_t size)
23660dc2366fSVenugopal Iyer {
23670dc2366fSVenugopal Iyer 	int			i;
23680dc2366fSVenugopal Iyer 	name_value_stat_t	*head_stat = NULL, *prev_stat = NULL;
23690dc2366fSVenugopal Iyer 	name_value_stat_t	*curr_stat;
23700dc2366fSVenugopal Iyer 
23710dc2366fSVenugopal Iyer 	for (i = 0; i < size; i++) {
23720dc2366fSVenugopal Iyer 		uint64_t *val = (void *)
23730dc2366fSVenugopal Iyer 		    ((uchar_t *)stats + stats_list[i].si_offset);
23740dc2366fSVenugopal Iyer 
23750dc2366fSVenugopal Iyer 		curr_stat = calloc(1, sizeof (name_value_stat_t));
23760dc2366fSVenugopal Iyer 		if (curr_stat == NULL)
23770dc2366fSVenugopal Iyer 			break;
23780dc2366fSVenugopal Iyer 
23790dc2366fSVenugopal Iyer 		(void) strlcpy(curr_stat->nv_statname, stats_list[i].si_name,
23800dc2366fSVenugopal Iyer 		    sizeof (curr_stat->nv_statname));
23810dc2366fSVenugopal Iyer 		curr_stat->nv_statval = *val;
23820dc2366fSVenugopal Iyer 		curr_stat->nv_nextstat = NULL;
23830dc2366fSVenugopal Iyer 
23840dc2366fSVenugopal Iyer 		if (head_stat == NULL)	/* First node */
23850dc2366fSVenugopal Iyer 			head_stat = curr_stat;
23860dc2366fSVenugopal Iyer 		else
23870dc2366fSVenugopal Iyer 			prev_stat->nv_nextstat = curr_stat;
23880dc2366fSVenugopal Iyer 
23890dc2366fSVenugopal Iyer 		prev_stat = curr_stat;
23900dc2366fSVenugopal Iyer 	}
23910dc2366fSVenugopal Iyer 	return (head_stat);
23920dc2366fSVenugopal Iyer }
23930dc2366fSVenugopal Iyer 
23940dc2366fSVenugopal Iyer void *
23950dc2366fSVenugopal Iyer build_nvs_entry(char *statheader, void *statentry, dladm_stat_type_t stattype)
23960dc2366fSVenugopal Iyer {
23970dc2366fSVenugopal Iyer 	name_value_stat_entry_t	*name_value_stat_entry;
23980dc2366fSVenugopal Iyer 	dladm_stat_desc_t	*stattbl_ptr;
23990dc2366fSVenugopal Iyer 	void			*statfields;
24000dc2366fSVenugopal Iyer 
24010dc2366fSVenugopal Iyer 	stattbl_ptr = &dladm_stat_table[stattype];
24020dc2366fSVenugopal Iyer 
24030dc2366fSVenugopal Iyer 	/* Allocate memory for query all stat entry */
24040dc2366fSVenugopal Iyer 	name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
24050dc2366fSVenugopal Iyer 	if (name_value_stat_entry == NULL)
24060dc2366fSVenugopal Iyer 		goto done;
24070dc2366fSVenugopal Iyer 
24080dc2366fSVenugopal Iyer 	/* Header for these stat fields */
24090dc2366fSVenugopal Iyer 	(void) strlcpy(name_value_stat_entry->nve_header, statheader,
24100dc2366fSVenugopal Iyer 	    sizeof (name_value_stat_entry->nve_header));
24110dc2366fSVenugopal Iyer 
24120dc2366fSVenugopal Iyer 	/* Extract stat fields from the statentry */
24130dc2366fSVenugopal Iyer 	statfields = (uchar_t *)statentry +
24140dc2366fSVenugopal Iyer 	    dladm_stat_table[stattype].ds_offset;
24150dc2366fSVenugopal Iyer 
24160dc2366fSVenugopal Iyer 	/* Convert curr_stat to <statname, statval> pair */
24170dc2366fSVenugopal Iyer 	name_value_stat_entry->nve_stats =
24180dc2366fSVenugopal Iyer 	    i_dlstat_convert_stats(statfields,
24190dc2366fSVenugopal Iyer 	    stattbl_ptr->ds_statlist, stattbl_ptr->ds_statsize);
24200dc2366fSVenugopal Iyer done:
24210dc2366fSVenugopal Iyer 	return (name_value_stat_entry);
24220dc2366fSVenugopal Iyer }
24230dc2366fSVenugopal Iyer 
24240dc2366fSVenugopal Iyer void *
24250dc2366fSVenugopal Iyer i_walk_dlstat_chain(dladm_stat_chain_t *stat_head, dladm_stat_type_t stattype)
24260dc2366fSVenugopal Iyer {
24270dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*curr;
24280dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*nvstat_head = NULL, *nvstat_prev = NULL;
24290dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*nvstat_curr;
24300dc2366fSVenugopal Iyer 
24310dc2366fSVenugopal Iyer 	/*
24320dc2366fSVenugopal Iyer 	 * For every stat in the chain, build header and convert all
24330dc2366fSVenugopal Iyer 	 * its stat fields
24340dc2366fSVenugopal Iyer 	 */
24350dc2366fSVenugopal Iyer 	for (curr = stat_head; curr != NULL; curr = curr->dc_next) {
24360dc2366fSVenugopal Iyer 		nvstat_curr = malloc(sizeof (dladm_stat_chain_t));
24370dc2366fSVenugopal Iyer 		if (nvstat_curr == NULL)
24380dc2366fSVenugopal Iyer 			break;
24390dc2366fSVenugopal Iyer 
24400dc2366fSVenugopal Iyer 		nvstat_curr->dc_statentry = build_nvs_entry(curr->dc_statheader,
24410dc2366fSVenugopal Iyer 		    curr->dc_statentry, stattype);
24420dc2366fSVenugopal Iyer 
24430dc2366fSVenugopal Iyer 		if (nvstat_curr->dc_statentry == NULL) {
24440dc2366fSVenugopal Iyer 			free(nvstat_curr);
24450dc2366fSVenugopal Iyer 			break;
24460dc2366fSVenugopal Iyer 		}
24470dc2366fSVenugopal Iyer 
24480dc2366fSVenugopal Iyer 		nvstat_curr->dc_next = NULL;
24490dc2366fSVenugopal Iyer 
24500dc2366fSVenugopal Iyer 		if (nvstat_head == NULL)	/* First node */
24510dc2366fSVenugopal Iyer 			nvstat_head = nvstat_curr;
24520dc2366fSVenugopal Iyer 		else
24530dc2366fSVenugopal Iyer 			nvstat_prev->dc_next = nvstat_curr;
24540dc2366fSVenugopal Iyer 
24550dc2366fSVenugopal Iyer 		nvstat_prev = nvstat_curr;
24560dc2366fSVenugopal Iyer 	}
24570dc2366fSVenugopal Iyer 	return (nvstat_head);
24580dc2366fSVenugopal Iyer }
24590dc2366fSVenugopal Iyer 
24600dc2366fSVenugopal Iyer dladm_stat_chain_t *
24610dc2366fSVenugopal Iyer dladm_link_stat_query_all(dladm_handle_t dh, datalink_id_t linkid,
24620dc2366fSVenugopal Iyer     dladm_stat_type_t stattype)
24630dc2366fSVenugopal Iyer {
24640dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*stat_head;
24650dc2366fSVenugopal Iyer 	dladm_stat_chain_t	*nvstat_head = NULL;
24660dc2366fSVenugopal Iyer 
24670dc2366fSVenugopal Iyer 	/* Query the requested stat */
24680dc2366fSVenugopal Iyer 	stat_head = dladm_link_stat_query(dh, linkid, stattype);
24690dc2366fSVenugopal Iyer 	if (stat_head == NULL)
24700dc2366fSVenugopal Iyer 		goto done;
24710dc2366fSVenugopal Iyer 
24720dc2366fSVenugopal Iyer 	/*
24730dc2366fSVenugopal Iyer 	 * Convert every statfield in every stat-entry of stat chain to
24740dc2366fSVenugopal Iyer 	 * <statname, statval> pair
24750dc2366fSVenugopal Iyer 	 */
24760dc2366fSVenugopal Iyer 	nvstat_head = i_walk_dlstat_chain(stat_head, stattype);
24770dc2366fSVenugopal Iyer 
24780dc2366fSVenugopal Iyer 	/* Free stat_head */
24790dc2366fSVenugopal Iyer 	dladm_link_stat_free(stat_head);
24800dc2366fSVenugopal Iyer 
24810dc2366fSVenugopal Iyer done:
24820dc2366fSVenugopal Iyer 	return (nvstat_head);
24830dc2366fSVenugopal Iyer }
24840dc2366fSVenugopal Iyer 
24850dc2366fSVenugopal Iyer void
24860dc2366fSVenugopal Iyer dladm_link_stat_query_all_free(dladm_stat_chain_t *curr)
24870dc2366fSVenugopal Iyer {
24880dc2366fSVenugopal Iyer 	while (curr != NULL) {
24890dc2366fSVenugopal Iyer 		dladm_stat_chain_t	*tofree = curr;
24900dc2366fSVenugopal Iyer 		name_value_stat_entry_t	*nv_entry = curr->dc_statentry;
24910dc2366fSVenugopal Iyer 		name_value_stat_t	*nv_curr = nv_entry->nve_stats;
24920dc2366fSVenugopal Iyer 
24930dc2366fSVenugopal Iyer 		while (nv_curr != NULL) {
24940dc2366fSVenugopal Iyer 			name_value_stat_t	*nv_tofree = nv_curr;
24950dc2366fSVenugopal Iyer 
24960dc2366fSVenugopal Iyer 			nv_curr = nv_curr->nv_nextstat;
24970dc2366fSVenugopal Iyer 			free(nv_tofree);
24980dc2366fSVenugopal Iyer 		}
24990dc2366fSVenugopal Iyer 
25000dc2366fSVenugopal Iyer 		curr = curr->dc_next;
25010dc2366fSVenugopal Iyer 		free(nv_entry);
25020dc2366fSVenugopal Iyer 		free(tofree);
25030dc2366fSVenugopal Iyer 	}
25040dc2366fSVenugopal Iyer }
25050dc2366fSVenugopal Iyer 
25060dc2366fSVenugopal Iyer /* flow stats specific routines */
25070dc2366fSVenugopal Iyer flow_stat_t *
2508399dcf08Scarlos antonio neira bustos dladm_flow_stat_query(dladm_handle_t handle, const char *flowname)
25090dc2366fSVenugopal Iyer {
25100dc2366fSVenugopal Iyer 	kstat_t		*ksp;
25110dc2366fSVenugopal Iyer 	flow_stat_t	*flow_stat = NULL;
25120dc2366fSVenugopal Iyer 
2513399dcf08Scarlos antonio neira bustos 	if (dladm_dld_kcp(handle) == NULL)
25140dc2366fSVenugopal Iyer 		return (NULL);
25150dc2366fSVenugopal Iyer 
25160dc2366fSVenugopal Iyer 	flow_stat = calloc(1, sizeof (flow_stat_t));
25170dc2366fSVenugopal Iyer 	if (flow_stat == NULL)
25180dc2366fSVenugopal Iyer 		goto done;
25190dc2366fSVenugopal Iyer 
2520399dcf08Scarlos antonio neira bustos 	ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), NULL, -1, flowname,
2521399dcf08Scarlos antonio neira bustos 	    "flow");
25220dc2366fSVenugopal Iyer 
25230dc2366fSVenugopal Iyer 	if (ksp != NULL) {
2524399dcf08Scarlos antonio neira bustos 		i_dlstat_get_stats(dladm_dld_kcp(handle), ksp, flow_stat,
2525399dcf08Scarlos antonio neira bustos 		    flow_stats_list, FLOW_STAT_SIZE);
25260dc2366fSVenugopal Iyer 	}
25270dc2366fSVenugopal Iyer 
25280dc2366fSVenugopal Iyer done:
25290dc2366fSVenugopal Iyer 	return (flow_stat);
25300dc2366fSVenugopal Iyer }
25310dc2366fSVenugopal Iyer 
25320dc2366fSVenugopal Iyer flow_stat_t *
25330dc2366fSVenugopal Iyer dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2)
25340dc2366fSVenugopal Iyer {
25350dc2366fSVenugopal Iyer 	flow_stat_t	*diff_stat;
25360dc2366fSVenugopal Iyer 
25370dc2366fSVenugopal Iyer 	diff_stat = calloc(1, sizeof (flow_stat_t));
25380dc2366fSVenugopal Iyer 	if (diff_stat == NULL)
25390dc2366fSVenugopal Iyer 		goto done;
25400dc2366fSVenugopal Iyer 
25410dc2366fSVenugopal Iyer 	if (op2 == NULL) {
25420dc2366fSVenugopal Iyer 		bcopy(op1, diff_stat, sizeof (flow_stat_t));
25430dc2366fSVenugopal Iyer 	} else {
25440dc2366fSVenugopal Iyer 		i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list,
25450dc2366fSVenugopal Iyer 		    FLOW_STAT_SIZE);
25460dc2366fSVenugopal Iyer 	}
25470dc2366fSVenugopal Iyer done:
25480dc2366fSVenugopal Iyer 	return (diff_stat);
25490dc2366fSVenugopal Iyer }
25500dc2366fSVenugopal Iyer 
25510dc2366fSVenugopal Iyer void
25520dc2366fSVenugopal Iyer dladm_flow_stat_free(flow_stat_t *curr)
25530dc2366fSVenugopal Iyer {
25540dc2366fSVenugopal Iyer 	free(curr);
25550dc2366fSVenugopal Iyer }
25560dc2366fSVenugopal Iyer 
25570dc2366fSVenugopal Iyer /* Query all flow stats */
25580dc2366fSVenugopal Iyer name_value_stat_entry_t *
2559399dcf08Scarlos antonio neira bustos dladm_flow_stat_query_all(dladm_handle_t handle, const char *flowname)
25600dc2366fSVenugopal Iyer {
25610dc2366fSVenugopal Iyer 	flow_stat_t		*flow_stat;
25620dc2366fSVenugopal Iyer 	name_value_stat_entry_t	*name_value_stat_entry = NULL;
25630dc2366fSVenugopal Iyer 
25640dc2366fSVenugopal Iyer 	/* Query flow stats */
2565399dcf08Scarlos antonio neira bustos 	flow_stat = dladm_flow_stat_query(handle, flowname);
25660dc2366fSVenugopal Iyer 	if (flow_stat == NULL)
25670dc2366fSVenugopal Iyer 		goto done;
25680dc2366fSVenugopal Iyer 
25690dc2366fSVenugopal Iyer 	/* Allocate memory for query all stat entry */
25700dc2366fSVenugopal Iyer 	name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
25710dc2366fSVenugopal Iyer 	if (name_value_stat_entry == NULL) {
25720dc2366fSVenugopal Iyer 		dladm_flow_stat_free(flow_stat);
25730dc2366fSVenugopal Iyer 		goto done;
25740dc2366fSVenugopal Iyer 	}
25750dc2366fSVenugopal Iyer 
25760dc2366fSVenugopal Iyer 	/* Header for these stat fields */
25770dc2366fSVenugopal Iyer 	(void) strncpy(name_value_stat_entry->nve_header, flowname,
25780dc2366fSVenugopal Iyer 	    MAXFLOWNAMELEN);
25790dc2366fSVenugopal Iyer 
25800dc2366fSVenugopal Iyer 	/* Convert every statfield in flow_stat to <statname, statval> pair */
25810dc2366fSVenugopal Iyer 	name_value_stat_entry->nve_stats =
25820dc2366fSVenugopal Iyer 	    i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE);
25830dc2366fSVenugopal Iyer 
25840dc2366fSVenugopal Iyer 	/* Free flow_stat */
25850dc2366fSVenugopal Iyer 	dladm_flow_stat_free(flow_stat);
25860dc2366fSVenugopal Iyer 
25870dc2366fSVenugopal Iyer done:
25880dc2366fSVenugopal Iyer 	return (name_value_stat_entry);
25890dc2366fSVenugopal Iyer }
25900dc2366fSVenugopal Iyer 
25910dc2366fSVenugopal Iyer void
25920dc2366fSVenugopal Iyer dladm_flow_stat_query_all_free(name_value_stat_entry_t *curr)
25930dc2366fSVenugopal Iyer {
25940dc2366fSVenugopal Iyer 	name_value_stat_t	*nv_curr = curr->nve_stats;
25950dc2366fSVenugopal Iyer 
25960dc2366fSVenugopal Iyer 	while (nv_curr != NULL) {
25970dc2366fSVenugopal Iyer 		name_value_stat_t	*nv_tofree = nv_curr;
25980dc2366fSVenugopal Iyer 
25990dc2366fSVenugopal Iyer 		nv_curr = nv_curr->nv_nextstat;
26000dc2366fSVenugopal Iyer 		free(nv_tofree);
26010dc2366fSVenugopal Iyer 	}
26020dc2366fSVenugopal Iyer }
2603