xref: /titanic_50/usr/src/lib/libdladm/common/usage.c (revision da14cebe459d3275048785f25bd869cb09b5307f)
1*da14cebeSEric Cheng /*
2*da14cebeSEric Cheng  * CDDL HEADER START
3*da14cebeSEric Cheng  *
4*da14cebeSEric Cheng  * The contents of this file are subject to the terms of the
5*da14cebeSEric Cheng  * Common Development and Distribution License (the "License").
6*da14cebeSEric Cheng  * You may not use this file except in compliance with the License.
7*da14cebeSEric Cheng  *
8*da14cebeSEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*da14cebeSEric Cheng  * or http://www.opensolaris.org/os/licensing.
10*da14cebeSEric Cheng  * See the License for the specific language governing permissions
11*da14cebeSEric Cheng  * and limitations under the License.
12*da14cebeSEric Cheng  *
13*da14cebeSEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
14*da14cebeSEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*da14cebeSEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
16*da14cebeSEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
17*da14cebeSEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
18*da14cebeSEric Cheng  *
19*da14cebeSEric Cheng  * CDDL HEADER END
20*da14cebeSEric Cheng  */
21*da14cebeSEric Cheng 
22*da14cebeSEric Cheng /*
23*da14cebeSEric Cheng  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*da14cebeSEric Cheng  * Use is subject to license terms.
25*da14cebeSEric Cheng  */
26*da14cebeSEric Cheng 
27*da14cebeSEric Cheng #include <fcntl.h>
28*da14cebeSEric Cheng #include <stdlib.h>
29*da14cebeSEric Cheng #include <strings.h>
30*da14cebeSEric Cheng #include <exacct.h>
31*da14cebeSEric Cheng #include <libdladm.h>
32*da14cebeSEric Cheng 
33*da14cebeSEric Cheng #define	TIMEBUFLEN	20
34*da14cebeSEric Cheng #define	GBIT		1000000000
35*da14cebeSEric Cheng #define	MBIT		1000000
36*da14cebeSEric Cheng #define	KBIT		1000
37*da14cebeSEric Cheng 
38*da14cebeSEric Cheng #define	NET_RESET_TOT(tbytes, ttime, tibytes, tobytes, step) {	\
39*da14cebeSEric Cheng 	(step) = 1;						\
40*da14cebeSEric Cheng 	(tbytes) = 0;						\
41*da14cebeSEric Cheng 	(ttime) = 0;						\
42*da14cebeSEric Cheng 	(tibytes) = 0;						\
43*da14cebeSEric Cheng 	(tobytes) = 0;						\
44*da14cebeSEric Cheng 	}
45*da14cebeSEric Cheng 
46*da14cebeSEric Cheng /* Flow/Link Descriptor */
47*da14cebeSEric Cheng typedef struct net_desc_s {
48*da14cebeSEric Cheng 	char		net_desc_name[LIFNAMSIZ];
49*da14cebeSEric Cheng 	char		net_desc_devname[LIFNAMSIZ];
50*da14cebeSEric Cheng 	uchar_t		net_desc_ehost[ETHERADDRL];
51*da14cebeSEric Cheng 	uchar_t		net_desc_edest[ETHERADDRL];
52*da14cebeSEric Cheng 	ushort_t	net_desc_vlan_tpid;
53*da14cebeSEric Cheng 	ushort_t	net_desc_vlan_tci;
54*da14cebeSEric Cheng 	ushort_t	net_desc_sap;
55*da14cebeSEric Cheng 	ushort_t	net_desc_cpuid;
56*da14cebeSEric Cheng 	ushort_t	net_desc_priority;
57*da14cebeSEric Cheng 	uint64_t	net_desc_bw_limit;
58*da14cebeSEric Cheng 	in6_addr_t	net_desc_saddr;
59*da14cebeSEric Cheng 	in6_addr_t	net_desc_daddr;
60*da14cebeSEric Cheng 	boolean_t	net_desc_isv4;
61*da14cebeSEric Cheng 	in_port_t	net_desc_sport;
62*da14cebeSEric Cheng 	in_port_t	net_desc_dport;
63*da14cebeSEric Cheng 	uint8_t		net_desc_protocol;
64*da14cebeSEric Cheng 	uint8_t		net_desc_dsfield;
65*da14cebeSEric Cheng 	boolean_t	net_desc_newrec;
66*da14cebeSEric Cheng } net_desc_t;
67*da14cebeSEric Cheng 
68*da14cebeSEric Cheng /* Time structure: Year, Month, Day, Hour, Min, Sec */
69*da14cebeSEric Cheng typedef struct net_time_s {
70*da14cebeSEric Cheng 	int	net_time_yr;
71*da14cebeSEric Cheng 	int	net_time_mon;
72*da14cebeSEric Cheng 	int	net_time_day;
73*da14cebeSEric Cheng 	int	net_time_hr;
74*da14cebeSEric Cheng 	int	net_time_min;
75*da14cebeSEric Cheng 	int	net_time_sec;
76*da14cebeSEric Cheng } net_time_t;
77*da14cebeSEric Cheng 
78*da14cebeSEric Cheng /* Flow/Link Stats */
79*da14cebeSEric Cheng typedef struct net_stat_s {
80*da14cebeSEric Cheng 	char			net_stat_name[LIFNAMSIZ];
81*da14cebeSEric Cheng 	uint64_t		net_stat_ibytes;
82*da14cebeSEric Cheng 	uint64_t		net_stat_obytes;
83*da14cebeSEric Cheng 	uint64_t		net_stat_ipackets;
84*da14cebeSEric Cheng 	uint64_t		net_stat_opackets;
85*da14cebeSEric Cheng 	uint64_t		net_stat_ierrors;
86*da14cebeSEric Cheng 	uint64_t		net_stat_oerrors;
87*da14cebeSEric Cheng 	uint64_t		net_stat_tibytes;
88*da14cebeSEric Cheng 	uint64_t		net_stat_tobytes;
89*da14cebeSEric Cheng 	uint64_t		net_stat_tipackets;
90*da14cebeSEric Cheng 	uint64_t		net_stat_topackets;
91*da14cebeSEric Cheng 	uint64_t		net_stat_tierrors;
92*da14cebeSEric Cheng 	uint64_t		net_stat_toerrors;
93*da14cebeSEric Cheng 	uint64_t		net_stat_ctime;
94*da14cebeSEric Cheng 	uint64_t		net_stat_tdiff;
95*da14cebeSEric Cheng 	net_time_t		net_stat_time;
96*da14cebeSEric Cheng 	struct net_stat_s	*net_stat_next;
97*da14cebeSEric Cheng 	net_desc_t		*net_stat_desc;
98*da14cebeSEric Cheng 	boolean_t		net_stat_isref;
99*da14cebeSEric Cheng } net_stat_t;
100*da14cebeSEric Cheng 
101*da14cebeSEric Cheng /* Used to create the [gnu]plot file */
102*da14cebeSEric Cheng typedef struct net_plot_entry_s {
103*da14cebeSEric Cheng 	char		*net_pe_name;
104*da14cebeSEric Cheng 	uint64_t	net_pe_tottime;
105*da14cebeSEric Cheng 	uint64_t	net_pe_totbytes;
106*da14cebeSEric Cheng 	uint64_t	net_pe_totibytes;
107*da14cebeSEric Cheng 	uint64_t	net_pe_totobytes;
108*da14cebeSEric Cheng 	uint64_t	net_pe_lasttime;
109*da14cebeSEric Cheng } net_plot_entry_t;
110*da14cebeSEric Cheng 
111*da14cebeSEric Cheng /* Stats entry */
112*da14cebeSEric Cheng typedef struct net_entry_s {
113*da14cebeSEric Cheng 	net_desc_t		*net_entry_desc;
114*da14cebeSEric Cheng 	net_stat_t		*net_entry_shead;
115*da14cebeSEric Cheng 	net_stat_t		*net_entry_stail;
116*da14cebeSEric Cheng 	int			net_entry_scount;
117*da14cebeSEric Cheng 	net_stat_t		*net_entry_sref;
118*da14cebeSEric Cheng 	net_stat_t		*net_entry_tstats;
119*da14cebeSEric Cheng 	uint64_t		net_entry_ttime;
120*da14cebeSEric Cheng 	struct net_entry_s	*net_entry_next;
121*da14cebeSEric Cheng } net_entry_t;
122*da14cebeSEric Cheng 
123*da14cebeSEric Cheng /* Time sorted list */
124*da14cebeSEric Cheng typedef struct net_time_entry_s {
125*da14cebeSEric Cheng 	net_stat_t	*my_time_stat;
126*da14cebeSEric Cheng 	struct net_time_entry_s *net_time_entry_next;
127*da14cebeSEric Cheng 	struct net_time_entry_s *net_time_entry_prev;
128*da14cebeSEric Cheng } net_time_entry_t;
129*da14cebeSEric Cheng 
130*da14cebeSEric Cheng /* The parsed table */
131*da14cebeSEric Cheng typedef	struct net_table_s {
132*da14cebeSEric Cheng 	/* List of stats */
133*da14cebeSEric Cheng 	net_entry_t		*net_table_head;
134*da14cebeSEric Cheng 	net_entry_t		*net_table_tail;
135*da14cebeSEric Cheng 	int			net_entries;
136*da14cebeSEric Cheng 
137*da14cebeSEric Cheng 	/*
138*da14cebeSEric Cheng 	 * Optimization I : List sorted by time, i.e:
139*da14cebeSEric Cheng 	 * Time		Resource	..
140*da14cebeSEric Cheng 	 * -------------------------------
141*da14cebeSEric Cheng 	 * 11.15.10	bge0
142*da14cebeSEric Cheng 	 * 11.15.10	ce0
143*da14cebeSEric Cheng 	 * 11.15.10	vnic1
144*da14cebeSEric Cheng 	 * 11.15.15	bge0
145*da14cebeSEric Cheng 	 * 11.15.15	ce0
146*da14cebeSEric Cheng 	 * 11.15.15	vnic1
147*da14cebeSEric Cheng 	 */
148*da14cebeSEric Cheng 	net_time_entry_t	*net_time_head;
149*da14cebeSEric Cheng 	net_time_entry_t	*net_time_tail;
150*da14cebeSEric Cheng 
151*da14cebeSEric Cheng 	/*
152*da14cebeSEric Cheng 	 * Optimization II : List sorted by resources
153*da14cebeSEric Cheng 	 * Time		Resource	..
154*da14cebeSEric Cheng 	 * -------------------------------
155*da14cebeSEric Cheng 	 * 11.15.10	bge0
156*da14cebeSEric Cheng 	 * 11.15.15	bge0
157*da14cebeSEric Cheng 	 * 11.15.10	ce0
158*da14cebeSEric Cheng 	 * 11.15.15	ce0
159*da14cebeSEric Cheng 	 * 11.15.10	vnic1
160*da14cebeSEric Cheng 	 * 11.15.15	vnic1
161*da14cebeSEric Cheng 	 */
162*da14cebeSEric Cheng 	net_time_entry_t	*net_ctime_head;
163*da14cebeSEric Cheng 	net_time_entry_t	*net_ctime_tail;
164*da14cebeSEric Cheng 
165*da14cebeSEric Cheng 	/* Common to both the above (sorted) lists. */
166*da14cebeSEric Cheng 	int			net_time_entries;
167*da14cebeSEric Cheng } net_table_t;
168*da14cebeSEric Cheng 
169*da14cebeSEric Cheng #define	NET_DATE_GREATER	0
170*da14cebeSEric Cheng #define	NET_DATE_LESSER		1
171*da14cebeSEric Cheng #define	NET_DATE_EQUAL		2
172*da14cebeSEric Cheng 
173*da14cebeSEric Cheng #define	NET_TIME_GREATER	0
174*da14cebeSEric Cheng #define	NET_TIME_LESSER		1
175*da14cebeSEric Cheng #define	NET_TIME_EQUAL		2
176*da14cebeSEric Cheng 
177*da14cebeSEric Cheng #ifndef _LP64
178*da14cebeSEric Cheng #define	FMT_UINT64	"%-15llu"
179*da14cebeSEric Cheng #else
180*da14cebeSEric Cheng #define	FMT_UINT64	"%-15lu"
181*da14cebeSEric Cheng #endif
182*da14cebeSEric Cheng 
183*da14cebeSEric Cheng /*
184*da14cebeSEric Cheng  * Given a timebuf of the form M/D/Y,H:M:S break it into individual elements.
185*da14cebeSEric Cheng  */
186*da14cebeSEric Cheng static void
187*da14cebeSEric Cheng dissect_time(char *tbuf, net_time_t *nt)
188*da14cebeSEric Cheng {
189*da14cebeSEric Cheng 	char	*d;
190*da14cebeSEric Cheng 	char	*t;
191*da14cebeSEric Cheng 	char	*dd;
192*da14cebeSEric Cheng 	char	*h;
193*da14cebeSEric Cheng 	char	*endp;
194*da14cebeSEric Cheng 
195*da14cebeSEric Cheng 	if (tbuf == NULL || nt == NULL)
196*da14cebeSEric Cheng 		return;
197*da14cebeSEric Cheng 
198*da14cebeSEric Cheng 	d = strtok(tbuf, ",");	/* Date */
199*da14cebeSEric Cheng 	t = strtok(NULL, ",");	/* Time */
200*da14cebeSEric Cheng 
201*da14cebeSEric Cheng 	/* Month */
202*da14cebeSEric Cheng 	dd = strtok(d, "/");
203*da14cebeSEric Cheng 	if (dd == NULL)
204*da14cebeSEric Cheng 		return;
205*da14cebeSEric Cheng 	nt->net_time_mon = strtol(dd, &endp, 10);
206*da14cebeSEric Cheng 
207*da14cebeSEric Cheng 	/* Day */
208*da14cebeSEric Cheng 	dd = strtok(NULL, "/");
209*da14cebeSEric Cheng 	if (dd == NULL)
210*da14cebeSEric Cheng 		return;
211*da14cebeSEric Cheng 	nt->net_time_day = strtol(dd, &endp, 10);
212*da14cebeSEric Cheng 
213*da14cebeSEric Cheng 	/* Year */
214*da14cebeSEric Cheng 	dd = strtok(NULL, "/");
215*da14cebeSEric Cheng 	if (dd == NULL)
216*da14cebeSEric Cheng 		return;
217*da14cebeSEric Cheng 	nt->net_time_yr = strtol(dd, &endp, 10);
218*da14cebeSEric Cheng 	if (strlen(dd) <= 2)
219*da14cebeSEric Cheng 		nt->net_time_yr += 2000;
220*da14cebeSEric Cheng 
221*da14cebeSEric Cheng 	if (t == NULL)
222*da14cebeSEric Cheng 		return;
223*da14cebeSEric Cheng 
224*da14cebeSEric Cheng 	/* Hour */
225*da14cebeSEric Cheng 	h = strtok(t, ":");
226*da14cebeSEric Cheng 	if (h == NULL)
227*da14cebeSEric Cheng 		return;
228*da14cebeSEric Cheng 	nt->net_time_hr = strtol(h, &endp, 10);
229*da14cebeSEric Cheng 
230*da14cebeSEric Cheng 	/* Min */
231*da14cebeSEric Cheng 	h = strtok(NULL, ":");
232*da14cebeSEric Cheng 	if (h == NULL)
233*da14cebeSEric Cheng 		return;
234*da14cebeSEric Cheng 	nt->net_time_min = strtol(h, &endp, 10);
235*da14cebeSEric Cheng 
236*da14cebeSEric Cheng 	/* Sec */
237*da14cebeSEric Cheng 	h = strtok(NULL, ":");
238*da14cebeSEric Cheng 	if (h == NULL)
239*da14cebeSEric Cheng 		return;
240*da14cebeSEric Cheng 	nt->net_time_sec = strtol(h, &endp, 10);
241*da14cebeSEric Cheng }
242*da14cebeSEric Cheng 
243*da14cebeSEric Cheng /* Get a stat item from an object in the exacct file */
244*da14cebeSEric Cheng static void
245*da14cebeSEric Cheng add_stat_item(ea_object_t *o, net_stat_t *ns)
246*da14cebeSEric Cheng {
247*da14cebeSEric Cheng 	switch (o->eo_catalog & EXT_TYPE_MASK) {
248*da14cebeSEric Cheng 	case EXT_STRING:
249*da14cebeSEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_STATS_NAME) {
250*da14cebeSEric Cheng 			(void) strncpy(ns->net_stat_name, o->eo_item.ei_string,
251*da14cebeSEric Cheng 			    strlen(o->eo_item.ei_string));
252*da14cebeSEric Cheng 		}
253*da14cebeSEric Cheng 		break;
254*da14cebeSEric Cheng 	case EXT_UINT64:
255*da14cebeSEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_STATS_CURTIME) {
256*da14cebeSEric Cheng 			time_t	_time;
257*da14cebeSEric Cheng 			char	timebuf[TIMEBUFLEN];
258*da14cebeSEric Cheng 
259*da14cebeSEric Cheng 			ns->net_stat_ctime = o->eo_item.ei_uint64;
260*da14cebeSEric Cheng 			_time = ns->net_stat_ctime;
261*da14cebeSEric Cheng 			(void) strftime(timebuf, sizeof (timebuf),
262*da14cebeSEric Cheng 			    "%m/%d/%Y,%T\n", localtime(&_time));
263*da14cebeSEric Cheng 			dissect_time(timebuf, &ns->net_stat_time);
264*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
265*da14cebeSEric Cheng 		    EXD_NET_STATS_IBYTES) {
266*da14cebeSEric Cheng 			ns->net_stat_ibytes = o->eo_item.ei_uint64;
267*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
268*da14cebeSEric Cheng 		    EXD_NET_STATS_OBYTES) {
269*da14cebeSEric Cheng 			ns->net_stat_obytes = o->eo_item.ei_uint64;
270*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
271*da14cebeSEric Cheng 		    EXD_NET_STATS_IPKTS) {
272*da14cebeSEric Cheng 			ns->net_stat_ipackets = o->eo_item.ei_uint64;
273*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
274*da14cebeSEric Cheng 		    EXD_NET_STATS_OPKTS) {
275*da14cebeSEric Cheng 			ns->net_stat_opackets = o->eo_item.ei_uint64;
276*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
277*da14cebeSEric Cheng 		    EXD_NET_STATS_IERRPKTS) {
278*da14cebeSEric Cheng 			ns->net_stat_ierrors = o->eo_item.ei_uint64;
279*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
280*da14cebeSEric Cheng 		    EXD_NET_STATS_OERRPKTS) {
281*da14cebeSEric Cheng 			ns->net_stat_oerrors = o->eo_item.ei_uint64;
282*da14cebeSEric Cheng 		}
283*da14cebeSEric Cheng 		break;
284*da14cebeSEric Cheng 	default:
285*da14cebeSEric Cheng 		break;
286*da14cebeSEric Cheng 	}
287*da14cebeSEric Cheng }
288*da14cebeSEric Cheng 
289*da14cebeSEric Cheng /* Get a description item from an object in the exacct file */
290*da14cebeSEric Cheng static void
291*da14cebeSEric Cheng add_desc_item(ea_object_t *o, net_desc_t *nd)
292*da14cebeSEric Cheng {
293*da14cebeSEric Cheng 	switch (o->eo_catalog & EXT_TYPE_MASK) {
294*da14cebeSEric Cheng 	case EXT_STRING:
295*da14cebeSEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_NAME) {
296*da14cebeSEric Cheng 			(void) strncpy(nd->net_desc_name, o->eo_item.ei_string,
297*da14cebeSEric Cheng 			    strlen(o->eo_item.ei_string));
298*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
299*da14cebeSEric Cheng 		    EXD_NET_DESC_DEVNAME) {
300*da14cebeSEric Cheng 			(void) strncpy(nd->net_desc_devname,
301*da14cebeSEric Cheng 			    o->eo_item.ei_string, strlen(o->eo_item.ei_string));
302*da14cebeSEric Cheng 		}
303*da14cebeSEric Cheng 		break;
304*da14cebeSEric Cheng 	case EXT_UINT8:
305*da14cebeSEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_PROTOCOL) {
306*da14cebeSEric Cheng 			nd->net_desc_protocol = o->eo_item.ei_uint8;
307*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
308*da14cebeSEric Cheng 		    EXD_NET_DESC_DSFIELD) {
309*da14cebeSEric Cheng 			nd->net_desc_dsfield = o->eo_item.ei_uint8;
310*da14cebeSEric Cheng 		}
311*da14cebeSEric Cheng 		break;
312*da14cebeSEric Cheng 	case EXT_UINT16:
313*da14cebeSEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_SPORT) {
314*da14cebeSEric Cheng 			nd->net_desc_sport = o->eo_item.ei_uint16;
315*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
316*da14cebeSEric Cheng 		    EXD_NET_DESC_DPORT) {
317*da14cebeSEric Cheng 			nd->net_desc_dport = o->eo_item.ei_uint16;
318*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
319*da14cebeSEric Cheng 		    EXD_NET_DESC_SAP) {
320*da14cebeSEric Cheng 			nd->net_desc_sap = o->eo_item.ei_uint16;
321*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
322*da14cebeSEric Cheng 		    EXD_NET_DESC_VLAN_TPID) {
323*da14cebeSEric Cheng 			nd->net_desc_vlan_tpid = o->eo_item.ei_uint16;
324*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
325*da14cebeSEric Cheng 		    EXD_NET_DESC_VLAN_TCI) {
326*da14cebeSEric Cheng 			nd->net_desc_vlan_tci = o->eo_item.ei_uint16;
327*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
328*da14cebeSEric Cheng 		    EXD_NET_DESC_PRIORITY) {
329*da14cebeSEric Cheng 			nd->net_desc_priority = o->eo_item.ei_uint16;
330*da14cebeSEric Cheng 		}
331*da14cebeSEric Cheng 		break;
332*da14cebeSEric Cheng 	case EXT_UINT32:
333*da14cebeSEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_V4SADDR ||
334*da14cebeSEric Cheng 		    (o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_V4DADDR) {
335*da14cebeSEric Cheng 				struct in_addr	addr;
336*da14cebeSEric Cheng 
337*da14cebeSEric Cheng 				addr.s_addr = htonl(o->eo_item.ei_uint32);
338*da14cebeSEric Cheng 
339*da14cebeSEric Cheng 				if ((o->eo_catalog & EXD_DATA_MASK) ==
340*da14cebeSEric Cheng 				    EXD_NET_DESC_V4SADDR) {
341*da14cebeSEric Cheng 					IN6_INADDR_TO_V4MAPPED(&addr,
342*da14cebeSEric Cheng 					    &nd->net_desc_saddr);
343*da14cebeSEric Cheng 				} else {
344*da14cebeSEric Cheng 					IN6_INADDR_TO_V4MAPPED(&addr,
345*da14cebeSEric Cheng 					    &nd->net_desc_daddr);
346*da14cebeSEric Cheng 				}
347*da14cebeSEric Cheng 		}
348*da14cebeSEric Cheng 		break;
349*da14cebeSEric Cheng 	case EXT_UINT64:
350*da14cebeSEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_BWLIMIT)
351*da14cebeSEric Cheng 			nd->net_desc_bw_limit = o->eo_item.ei_uint64;
352*da14cebeSEric Cheng 		break;
353*da14cebeSEric Cheng 	case EXT_RAW:
354*da14cebeSEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_V6SADDR ||
355*da14cebeSEric Cheng 		    (o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_V6DADDR) {
356*da14cebeSEric Cheng 			in6_addr_t	addr;
357*da14cebeSEric Cheng 
358*da14cebeSEric Cheng 			addr = *(in6_addr_t *)o->eo_item.ei_raw;
359*da14cebeSEric Cheng 			if ((o->eo_catalog & EXD_DATA_MASK) ==
360*da14cebeSEric Cheng 			    EXD_NET_DESC_V6SADDR) {
361*da14cebeSEric Cheng 				nd->net_desc_saddr = addr;
362*da14cebeSEric Cheng 			} else {
363*da14cebeSEric Cheng 				nd->net_desc_daddr = addr;
364*da14cebeSEric Cheng 			}
365*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
366*da14cebeSEric Cheng 		    EXD_NET_DESC_EHOST) {
367*da14cebeSEric Cheng 			bcopy((uchar_t *)o->eo_item.ei_raw, nd->net_desc_ehost,
368*da14cebeSEric Cheng 			    ETHERADDRL);
369*da14cebeSEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
370*da14cebeSEric Cheng 		    EXD_NET_DESC_EDEST) {
371*da14cebeSEric Cheng 			bcopy((uchar_t *)o->eo_item.ei_raw, nd->net_desc_edest,
372*da14cebeSEric Cheng 			    ETHERADDRL);
373*da14cebeSEric Cheng 		}
374*da14cebeSEric Cheng 		break;
375*da14cebeSEric Cheng 	default:
376*da14cebeSEric Cheng 		break;
377*da14cebeSEric Cheng 	}
378*da14cebeSEric Cheng }
379*da14cebeSEric Cheng 
380*da14cebeSEric Cheng /* Add a description item to the table */
381*da14cebeSEric Cheng static dladm_status_t
382*da14cebeSEric Cheng add_desc_to_tbl(net_table_t *net_table, net_desc_t *nd)
383*da14cebeSEric Cheng {
384*da14cebeSEric Cheng 	net_entry_t	*ne;
385*da14cebeSEric Cheng 
386*da14cebeSEric Cheng 	if ((ne = calloc(1, sizeof (net_entry_t))) == NULL)
387*da14cebeSEric Cheng 		return (DLADM_STATUS_NOMEM);
388*da14cebeSEric Cheng 
389*da14cebeSEric Cheng 	if ((ne->net_entry_tstats = calloc(1, sizeof (net_stat_t))) == NULL) {
390*da14cebeSEric Cheng 		free(ne);
391*da14cebeSEric Cheng 		return (DLADM_STATUS_NOMEM);
392*da14cebeSEric Cheng 	}
393*da14cebeSEric Cheng 
394*da14cebeSEric Cheng 	ne->net_entry_desc = nd;
395*da14cebeSEric Cheng 	ne->net_entry_shead = NULL;
396*da14cebeSEric Cheng 	ne->net_entry_stail = NULL;
397*da14cebeSEric Cheng 	ne->net_entry_scount = 0;
398*da14cebeSEric Cheng 
399*da14cebeSEric Cheng 	if (net_table->net_table_head == NULL) {
400*da14cebeSEric Cheng 		net_table->net_table_head = ne;
401*da14cebeSEric Cheng 		net_table->net_table_tail = ne;
402*da14cebeSEric Cheng 	} else {
403*da14cebeSEric Cheng 		net_table->net_table_tail->net_entry_next = ne;
404*da14cebeSEric Cheng 		net_table->net_table_tail = ne;
405*da14cebeSEric Cheng 	}
406*da14cebeSEric Cheng 	net_table->net_entries++;
407*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
408*da14cebeSEric Cheng }
409*da14cebeSEric Cheng 
410*da14cebeSEric Cheng /* Compare dates and return if t1 is equal, greater or lesser than t2 */
411*da14cebeSEric Cheng static int
412*da14cebeSEric Cheng compare_date(net_time_t *t1, net_time_t *t2)
413*da14cebeSEric Cheng {
414*da14cebeSEric Cheng 	if (t1->net_time_yr == t2->net_time_yr &&
415*da14cebeSEric Cheng 	    t1->net_time_mon == t2->net_time_mon &&
416*da14cebeSEric Cheng 	    t1->net_time_day == t2->net_time_day) {
417*da14cebeSEric Cheng 		return (NET_DATE_EQUAL);
418*da14cebeSEric Cheng 	}
419*da14cebeSEric Cheng 	if (t1->net_time_yr > t2->net_time_yr ||
420*da14cebeSEric Cheng 	    (t1->net_time_yr == t2->net_time_yr &&
421*da14cebeSEric Cheng 	    t1->net_time_mon > t2->net_time_mon) ||
422*da14cebeSEric Cheng 	    (t1->net_time_yr == t2->net_time_yr &&
423*da14cebeSEric Cheng 	    t1->net_time_mon == t2->net_time_mon &&
424*da14cebeSEric Cheng 	    t1->net_time_day > t2->net_time_day)) {
425*da14cebeSEric Cheng 		return (NET_DATE_GREATER);
426*da14cebeSEric Cheng 	}
427*da14cebeSEric Cheng 	return (NET_DATE_LESSER);
428*da14cebeSEric Cheng }
429*da14cebeSEric Cheng 
430*da14cebeSEric Cheng /* Compare times and return if t1 is equal, greater or lesser than t2 */
431*da14cebeSEric Cheng static int
432*da14cebeSEric Cheng compare_time(net_time_t *t1, net_time_t *t2)
433*da14cebeSEric Cheng {
434*da14cebeSEric Cheng 	int	cd;
435*da14cebeSEric Cheng 
436*da14cebeSEric Cheng 	cd = compare_date(t1, t2);
437*da14cebeSEric Cheng 
438*da14cebeSEric Cheng 	if (cd == NET_DATE_GREATER) {
439*da14cebeSEric Cheng 		return (NET_TIME_GREATER);
440*da14cebeSEric Cheng 	} else if (cd == NET_DATE_LESSER) {
441*da14cebeSEric Cheng 		return (NET_TIME_LESSER);
442*da14cebeSEric Cheng 	} else {
443*da14cebeSEric Cheng 		if (t1->net_time_hr == t2->net_time_hr &&
444*da14cebeSEric Cheng 		    t1->net_time_min == t2->net_time_min &&
445*da14cebeSEric Cheng 		    t1->net_time_sec == t2->net_time_sec) {
446*da14cebeSEric Cheng 			return (NET_TIME_EQUAL);
447*da14cebeSEric Cheng 		}
448*da14cebeSEric Cheng 		if (t1->net_time_hr > t2->net_time_hr ||
449*da14cebeSEric Cheng 		    (t1->net_time_hr == t2->net_time_hr &&
450*da14cebeSEric Cheng 		    t1->net_time_min > t2->net_time_min) ||
451*da14cebeSEric Cheng 		    (t1->net_time_hr == t2->net_time_hr &&
452*da14cebeSEric Cheng 		    t1->net_time_min == t2->net_time_min &&
453*da14cebeSEric Cheng 		    t1->net_time_sec > t2->net_time_sec)) {
454*da14cebeSEric Cheng 			return (NET_TIME_GREATER);
455*da14cebeSEric Cheng 		}
456*da14cebeSEric Cheng 	}
457*da14cebeSEric Cheng 	return (NET_TIME_LESSER);
458*da14cebeSEric Cheng }
459*da14cebeSEric Cheng 
460*da14cebeSEric Cheng /*
461*da14cebeSEric Cheng  * Given a start and end time and start and end entries check if the
462*da14cebeSEric Cheng  * times are within the range, and adjust, if needed.
463*da14cebeSEric Cheng  */
464*da14cebeSEric Cheng static dladm_status_t
465*da14cebeSEric Cheng chk_time_bound(net_time_t *s, net_time_t *e,  net_time_t *sns,
466*da14cebeSEric Cheng     net_time_t *ens)
467*da14cebeSEric Cheng {
468*da14cebeSEric Cheng 	if (s != NULL && e != NULL) {
469*da14cebeSEric Cheng 		if (compare_time(s, e) == NET_TIME_GREATER)
470*da14cebeSEric Cheng 			return (DLADM_STATUS_BADTIMEVAL);
471*da14cebeSEric Cheng 	}
472*da14cebeSEric Cheng 	if (s != NULL) {
473*da14cebeSEric Cheng 		if (compare_time(s, sns) == NET_TIME_LESSER) {
474*da14cebeSEric Cheng 			s->net_time_yr = sns->net_time_yr;
475*da14cebeSEric Cheng 			s->net_time_mon = sns->net_time_mon;
476*da14cebeSEric Cheng 			s->net_time_day = sns->net_time_day;
477*da14cebeSEric Cheng 			s->net_time_hr = sns->net_time_hr;
478*da14cebeSEric Cheng 			s->net_time_min = sns->net_time_min;
479*da14cebeSEric Cheng 			s->net_time_sec = sns->net_time_sec;
480*da14cebeSEric Cheng 		}
481*da14cebeSEric Cheng 	}
482*da14cebeSEric Cheng 	if (e != NULL) {
483*da14cebeSEric Cheng 		if (compare_time(e, ens) == NET_TIME_GREATER) {
484*da14cebeSEric Cheng 			e->net_time_yr = ens->net_time_yr;
485*da14cebeSEric Cheng 			e->net_time_mon = ens->net_time_mon;
486*da14cebeSEric Cheng 			e->net_time_day = ens->net_time_day;
487*da14cebeSEric Cheng 			e->net_time_hr = ens->net_time_hr;
488*da14cebeSEric Cheng 			e->net_time_min = ens->net_time_min;
489*da14cebeSEric Cheng 			e->net_time_sec = ens->net_time_sec;
490*da14cebeSEric Cheng 		}
491*da14cebeSEric Cheng 	}
492*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
493*da14cebeSEric Cheng }
494*da14cebeSEric Cheng 
495*da14cebeSEric Cheng /*
496*da14cebeSEric Cheng  * Given a start and end time (strings), convert them into net_time_t
497*da14cebeSEric Cheng  * and also check for the range given the head and tail of the list.
498*da14cebeSEric Cheng  * If stime is lower then head or etime is greated than tail, adjust.
499*da14cebeSEric Cheng  */
500*da14cebeSEric Cheng static dladm_status_t
501*da14cebeSEric Cheng get_time_range(net_time_entry_t *head, net_time_entry_t *tail,
502*da14cebeSEric Cheng     net_time_t *st, net_time_t *et, char *stime, char *etime)
503*da14cebeSEric Cheng {
504*da14cebeSEric Cheng 	bzero(st, sizeof (net_time_t));
505*da14cebeSEric Cheng 	bzero(et, sizeof (net_time_t));
506*da14cebeSEric Cheng 
507*da14cebeSEric Cheng 	if (stime == NULL && etime == NULL)
508*da14cebeSEric Cheng 		return (0);
509*da14cebeSEric Cheng 
510*da14cebeSEric Cheng 	if (stime != NULL)
511*da14cebeSEric Cheng 		dissect_time(stime, st);
512*da14cebeSEric Cheng 	if (etime != NULL)
513*da14cebeSEric Cheng 		dissect_time(etime, et);
514*da14cebeSEric Cheng 
515*da14cebeSEric Cheng 	if (stime != NULL || etime != NULL) {
516*da14cebeSEric Cheng 		return (chk_time_bound(stime == NULL ? NULL : st,
517*da14cebeSEric Cheng 		    etime == NULL ? NULL : et,
518*da14cebeSEric Cheng 		    &head->my_time_stat->net_stat_time,
519*da14cebeSEric Cheng 		    &tail->my_time_stat->net_stat_time));
520*da14cebeSEric Cheng 	}
521*da14cebeSEric Cheng 	return (0);
522*da14cebeSEric Cheng }
523*da14cebeSEric Cheng 
524*da14cebeSEric Cheng /*
525*da14cebeSEric Cheng  * Walk the list from a given starting point and return when we find
526*da14cebeSEric Cheng  * an entry that is greater or equal to st. lasttime will point to the
527*da14cebeSEric Cheng  * previous time entry.
528*da14cebeSEric Cheng  */
529*da14cebeSEric Cheng static void
530*da14cebeSEric Cheng get_starting_point(net_time_entry_t *head, net_time_entry_t **start,
531*da14cebeSEric Cheng     net_time_t *st, char *stime, uint64_t *lasttime)
532*da14cebeSEric Cheng {
533*da14cebeSEric Cheng 	net_time_entry_t	*next = head;
534*da14cebeSEric Cheng 
535*da14cebeSEric Cheng 	if (head == NULL) {
536*da14cebeSEric Cheng 		*start = NULL;
537*da14cebeSEric Cheng 		return;
538*da14cebeSEric Cheng 	}
539*da14cebeSEric Cheng 	if (stime == NULL) {
540*da14cebeSEric Cheng 		*start = head;
541*da14cebeSEric Cheng 		*lasttime = head->my_time_stat->net_stat_ctime;
542*da14cebeSEric Cheng 		return;
543*da14cebeSEric Cheng 	}
544*da14cebeSEric Cheng 	*start = NULL;
545*da14cebeSEric Cheng 	while (next != NULL) {
546*da14cebeSEric Cheng 		if (compare_time(st,
547*da14cebeSEric Cheng 		    &next->my_time_stat->net_stat_time) != NET_TIME_LESSER) {
548*da14cebeSEric Cheng 			*lasttime = next->my_time_stat->net_stat_ctime;
549*da14cebeSEric Cheng 			next = next->net_time_entry_next;
550*da14cebeSEric Cheng 			continue;
551*da14cebeSEric Cheng 		}
552*da14cebeSEric Cheng 		*start = next;
553*da14cebeSEric Cheng 		break;
554*da14cebeSEric Cheng 	}
555*da14cebeSEric Cheng }
556*da14cebeSEric Cheng 
557*da14cebeSEric Cheng /*
558*da14cebeSEric Cheng  * Point entry (pe) functions
559*da14cebeSEric Cheng  */
560*da14cebeSEric Cheng /* Clear all the counters. Done after the contents are written to the file */
561*da14cebeSEric Cheng static void
562*da14cebeSEric Cheng clear_pe(net_plot_entry_t *pe, int entries, int *pentries)
563*da14cebeSEric Cheng {
564*da14cebeSEric Cheng 	int	count;
565*da14cebeSEric Cheng 
566*da14cebeSEric Cheng 	for (count = 0; count < entries; count++) {
567*da14cebeSEric Cheng 		pe[count].net_pe_totbytes = 0;
568*da14cebeSEric Cheng 		pe[count].net_pe_totibytes = 0;
569*da14cebeSEric Cheng 		pe[count].net_pe_totobytes = 0;
570*da14cebeSEric Cheng 		pe[count].net_pe_tottime = 0;
571*da14cebeSEric Cheng 	}
572*da14cebeSEric Cheng 	*pentries = 0;
573*da14cebeSEric Cheng }
574*da14cebeSEric Cheng 
575*da14cebeSEric Cheng /* Update an entry in the point entry table */
576*da14cebeSEric Cheng static void
577*da14cebeSEric Cheng update_pe(net_plot_entry_t *pe, net_stat_t *nns, int nentries,
578*da14cebeSEric Cheng     int *pentries, uint64_t lasttime)
579*da14cebeSEric Cheng {
580*da14cebeSEric Cheng 	int	count;
581*da14cebeSEric Cheng 
582*da14cebeSEric Cheng 	for (count = 0; count < nentries; count++) {
583*da14cebeSEric Cheng 		if ((strlen(nns->net_stat_name) ==
584*da14cebeSEric Cheng 		    strlen(pe[count].net_pe_name)) &&
585*da14cebeSEric Cheng 		    (strncmp(pe[count].net_pe_name, nns->net_stat_name,
586*da14cebeSEric Cheng 		    strlen(nns->net_stat_name)) == 0)) {
587*da14cebeSEric Cheng 			break;
588*da14cebeSEric Cheng 		}
589*da14cebeSEric Cheng 	}
590*da14cebeSEric Cheng 	if (count == nentries)
591*da14cebeSEric Cheng 		return;
592*da14cebeSEric Cheng 
593*da14cebeSEric Cheng 	if (pe[count].net_pe_totbytes == 0)
594*da14cebeSEric Cheng 		pe[count].net_pe_lasttime = lasttime;
595*da14cebeSEric Cheng 
596*da14cebeSEric Cheng 	pe[count].net_pe_totbytes += nns->net_stat_ibytes +
597*da14cebeSEric Cheng 	    nns->net_stat_obytes;
598*da14cebeSEric Cheng 	pe[count].net_pe_tottime += nns->net_stat_tdiff;
599*da14cebeSEric Cheng 	pe[count].net_pe_totibytes += nns->net_stat_ibytes;
600*da14cebeSEric Cheng 	pe[count].net_pe_totobytes += nns->net_stat_obytes;
601*da14cebeSEric Cheng 	(*pentries)++;
602*da14cebeSEric Cheng }
603*da14cebeSEric Cheng 
604*da14cebeSEric Cheng /* Flush the contents of the point entry table to the file. */
605*da14cebeSEric Cheng static void
606*da14cebeSEric Cheng add_pe_to_file(int (*fn)(dladm_usage_t *, void *), net_plot_entry_t *pe,
607*da14cebeSEric Cheng     net_stat_t *ns, int entries, void *arg)
608*da14cebeSEric Cheng {
609*da14cebeSEric Cheng 	int		count;
610*da14cebeSEric Cheng 	dladm_usage_t	usage;
611*da14cebeSEric Cheng 	uint64_t	tottime;
612*da14cebeSEric Cheng 
613*da14cebeSEric Cheng 	bcopy(&ns->net_stat_ctime, &usage.du_etime, sizeof (usage.du_etime));
614*da14cebeSEric Cheng 	for (count = 0; count < entries; count++) {
615*da14cebeSEric Cheng 		bcopy(pe[count].net_pe_name, &usage.du_name,
616*da14cebeSEric Cheng 		    sizeof (usage.du_name));
617*da14cebeSEric Cheng 		bcopy(&pe[count].net_pe_lasttime, &usage.du_stime,
618*da14cebeSEric Cheng 		    sizeof (usage.du_stime));
619*da14cebeSEric Cheng 		usage.du_rbytes = pe[count].net_pe_totibytes;
620*da14cebeSEric Cheng 		usage.du_obytes = pe[count].net_pe_totobytes;
621*da14cebeSEric Cheng 		tottime = pe[count].net_pe_tottime;
622*da14cebeSEric Cheng 		usage.du_bandwidth = (tottime > 0) ?
623*da14cebeSEric Cheng 		    ((pe[count].net_pe_totbytes * 8) / tottime) : 0;
624*da14cebeSEric Cheng 		usage.du_last = (count == entries-1);
625*da14cebeSEric Cheng 		fn(&usage, arg);
626*da14cebeSEric Cheng 	}
627*da14cebeSEric Cheng }
628*da14cebeSEric Cheng 
629*da14cebeSEric Cheng /*
630*da14cebeSEric Cheng  * Net entry functions
631*da14cebeSEric Cheng  */
632*da14cebeSEric Cheng static net_entry_t *
633*da14cebeSEric Cheng get_ne_from_table(net_table_t *net_table, char *name)
634*da14cebeSEric Cheng {
635*da14cebeSEric Cheng 	int		count;
636*da14cebeSEric Cheng 	net_desc_t	*nd;
637*da14cebeSEric Cheng 	net_entry_t	*ne = net_table->net_table_head;
638*da14cebeSEric Cheng 
639*da14cebeSEric Cheng 	for (count = 0; count < net_table->net_entries; count++) {
640*da14cebeSEric Cheng 		nd = ne->net_entry_desc;
641*da14cebeSEric Cheng 		if ((strlen(name) == strlen(nd->net_desc_name)) &&
642*da14cebeSEric Cheng 		    (strncmp(name, nd->net_desc_name, strlen(name)) == 0)) {
643*da14cebeSEric Cheng 			return (ne);
644*da14cebeSEric Cheng 		}
645*da14cebeSEric Cheng 		ne = ne->net_entry_next;
646*da14cebeSEric Cheng 	}
647*da14cebeSEric Cheng 	return (NULL);
648*da14cebeSEric Cheng }
649*da14cebeSEric Cheng 
650*da14cebeSEric Cheng /*  Get the entry for the descriptor, if it exists */
651*da14cebeSEric Cheng static net_desc_t *
652*da14cebeSEric Cheng get_ndesc(net_table_t *net_table, net_desc_t *nd)
653*da14cebeSEric Cheng {
654*da14cebeSEric Cheng 	int		count;
655*da14cebeSEric Cheng 	net_desc_t	*nd1;
656*da14cebeSEric Cheng 	net_entry_t	*ne = net_table->net_table_head;
657*da14cebeSEric Cheng 
658*da14cebeSEric Cheng 	for (count = 0; count < net_table->net_entries; count++) {
659*da14cebeSEric Cheng 		nd1 = ne->net_entry_desc;
660*da14cebeSEric Cheng 		if (strlen(nd1->net_desc_name) == strlen(nd->net_desc_name) &&
661*da14cebeSEric Cheng 		    strlen(nd1->net_desc_devname) ==
662*da14cebeSEric Cheng 		    strlen(nd->net_desc_devname) &&
663*da14cebeSEric Cheng 		    strncmp(nd1->net_desc_name, nd->net_desc_name,
664*da14cebeSEric Cheng 		    strlen(nd1->net_desc_name)) == 0 &&
665*da14cebeSEric Cheng 		    strncmp(nd1->net_desc_devname, nd->net_desc_devname,
666*da14cebeSEric Cheng 		    strlen(nd1->net_desc_devname)) == 0 &&
667*da14cebeSEric Cheng 		    bcmp(nd1->net_desc_ehost, nd->net_desc_ehost,
668*da14cebeSEric Cheng 		    ETHERADDRL) == 0 &&
669*da14cebeSEric Cheng 		    bcmp(nd1->net_desc_edest, nd->net_desc_edest,
670*da14cebeSEric Cheng 		    ETHERADDRL) == 0 &&
671*da14cebeSEric Cheng 		    nd1->net_desc_vlan_tpid == nd->net_desc_vlan_tpid &&
672*da14cebeSEric Cheng 		    nd1->net_desc_vlan_tci == nd->net_desc_vlan_tci &&
673*da14cebeSEric Cheng 		    nd1->net_desc_sap == nd->net_desc_sap &&
674*da14cebeSEric Cheng 		    nd1->net_desc_cpuid == nd->net_desc_cpuid &&
675*da14cebeSEric Cheng 		    nd1->net_desc_priority == nd->net_desc_priority &&
676*da14cebeSEric Cheng 		    nd1->net_desc_bw_limit == nd->net_desc_bw_limit &&
677*da14cebeSEric Cheng 		    nd1->net_desc_sport == nd->net_desc_sport &&
678*da14cebeSEric Cheng 		    nd1->net_desc_dport == nd->net_desc_dport &&
679*da14cebeSEric Cheng 		    nd1->net_desc_protocol == nd->net_desc_protocol &&
680*da14cebeSEric Cheng 		    nd1->net_desc_dsfield == nd->net_desc_dsfield &&
681*da14cebeSEric Cheng 		    IN6_ARE_ADDR_EQUAL(&nd1->net_desc_saddr,
682*da14cebeSEric Cheng 		    &nd->net_desc_saddr) &&
683*da14cebeSEric Cheng 		    IN6_ARE_ADDR_EQUAL(&nd1->net_desc_daddr,
684*da14cebeSEric Cheng 		    &nd->net_desc_daddr)) {
685*da14cebeSEric Cheng 			return (nd1);
686*da14cebeSEric Cheng 		}
687*da14cebeSEric Cheng 		ne = ne->net_entry_next;
688*da14cebeSEric Cheng 	}
689*da14cebeSEric Cheng 	return (NULL);
690*da14cebeSEric Cheng }
691*da14cebeSEric Cheng 
692*da14cebeSEric Cheng /*
693*da14cebeSEric Cheng  * Update the stat entries. The stats in the file are cumulative, so in order
694*da14cebeSEric Cheng  * to have increments, we maintain a reference stat entry, which contains
695*da14cebeSEric Cheng  * the stats when the record was first written and a total stat entry, which
696*da14cebeSEric Cheng  * maintains the running count. When we want to add a stat entry, if it
697*da14cebeSEric Cheng  * the reference stat entry, we don't come here. For subsequent entries,
698*da14cebeSEric Cheng  * we get the increment by subtracting the current value from the reference
699*da14cebeSEric Cheng  * stat and the total stat.
700*da14cebeSEric Cheng  */
701*da14cebeSEric Cheng static void
702*da14cebeSEric Cheng update_stats(net_stat_t *ns1, net_entry_t *ne, net_stat_t *ref)
703*da14cebeSEric Cheng {
704*da14cebeSEric Cheng 
705*da14cebeSEric Cheng 	/* get the increment */
706*da14cebeSEric Cheng 	ns1->net_stat_ibytes -= (ref->net_stat_ibytes + ref->net_stat_tibytes);
707*da14cebeSEric Cheng 	ns1->net_stat_obytes -= (ref->net_stat_obytes + ref->net_stat_tobytes);
708*da14cebeSEric Cheng 	ns1->net_stat_ipackets -= (ref->net_stat_ipackets +
709*da14cebeSEric Cheng 	    ref->net_stat_tipackets);
710*da14cebeSEric Cheng 	ns1->net_stat_opackets -= (ref->net_stat_opackets +
711*da14cebeSEric Cheng 	    ref->net_stat_topackets);
712*da14cebeSEric Cheng 	ns1->net_stat_ierrors -= (ref->net_stat_ierrors +
713*da14cebeSEric Cheng 	    ref->net_stat_tierrors);
714*da14cebeSEric Cheng 	ns1->net_stat_oerrors -= (ref->net_stat_oerrors +
715*da14cebeSEric Cheng 	    ref->net_stat_toerrors);
716*da14cebeSEric Cheng 
717*da14cebeSEric Cheng 	/* update total bytes */
718*da14cebeSEric Cheng 	ref->net_stat_tibytes += ns1->net_stat_ibytes;
719*da14cebeSEric Cheng 	ref->net_stat_tobytes += ns1->net_stat_obytes;
720*da14cebeSEric Cheng 	ref->net_stat_tipackets += ns1->net_stat_ipackets;
721*da14cebeSEric Cheng 	ref->net_stat_topackets += ns1->net_stat_opackets;
722*da14cebeSEric Cheng 	ref->net_stat_tierrors += ns1->net_stat_ierrors;
723*da14cebeSEric Cheng 	ref->net_stat_toerrors  += ns1->net_stat_oerrors;
724*da14cebeSEric Cheng 
725*da14cebeSEric Cheng 	ne->net_entry_tstats->net_stat_ibytes += ns1->net_stat_ibytes;
726*da14cebeSEric Cheng 	ne->net_entry_tstats->net_stat_obytes += ns1->net_stat_obytes;
727*da14cebeSEric Cheng 	ne->net_entry_tstats->net_stat_ipackets += ns1->net_stat_ipackets;
728*da14cebeSEric Cheng 	ne->net_entry_tstats->net_stat_opackets += ns1->net_stat_opackets;
729*da14cebeSEric Cheng 	ne->net_entry_tstats->net_stat_ierrors += ns1->net_stat_ierrors;
730*da14cebeSEric Cheng 	ne->net_entry_tstats->net_stat_oerrors += ns1->net_stat_oerrors;
731*da14cebeSEric Cheng }
732*da14cebeSEric Cheng 
733*da14cebeSEric Cheng /* Add the stat entry into the table */
734*da14cebeSEric Cheng static dladm_status_t
735*da14cebeSEric Cheng add_stat_to_tbl(net_table_t *net_table, net_stat_t *ns)
736*da14cebeSEric Cheng {
737*da14cebeSEric Cheng 	net_entry_t	*ne;
738*da14cebeSEric Cheng 
739*da14cebeSEric Cheng 	ne = get_ne_from_table(net_table, ns->net_stat_name);
740*da14cebeSEric Cheng 	if (ne == NULL)
741*da14cebeSEric Cheng 		return (DLADM_STATUS_NOMEM);
742*da14cebeSEric Cheng 
743*da14cebeSEric Cheng 	/* Ptr to flow desc */
744*da14cebeSEric Cheng 	ns->net_stat_desc = ne->net_entry_desc;
745*da14cebeSEric Cheng 	if (ns->net_stat_desc->net_desc_newrec) {
746*da14cebeSEric Cheng 		ns->net_stat_desc->net_desc_newrec = B_FALSE;
747*da14cebeSEric Cheng 		ns->net_stat_isref = B_TRUE;
748*da14cebeSEric Cheng 		ne->net_entry_sref = ns;
749*da14cebeSEric Cheng 	} else if (ns->net_stat_ibytes < ne->net_entry_sref->net_stat_tibytes ||
750*da14cebeSEric Cheng 	    (ns->net_stat_obytes < ne->net_entry_sref->net_stat_tobytes)) {
751*da14cebeSEric Cheng 		ns->net_stat_isref = B_TRUE;
752*da14cebeSEric Cheng 		ne->net_entry_sref = ns;
753*da14cebeSEric Cheng 	} else {
754*da14cebeSEric Cheng 		ns->net_stat_isref = B_FALSE;
755*da14cebeSEric Cheng 		update_stats(ns, ne, ne->net_entry_sref);
756*da14cebeSEric Cheng 	}
757*da14cebeSEric Cheng 	if (ne->net_entry_shead == NULL) {
758*da14cebeSEric Cheng 		ne->net_entry_shead = ns;
759*da14cebeSEric Cheng 		ne->net_entry_stail = ns;
760*da14cebeSEric Cheng 	} else {
761*da14cebeSEric Cheng 		if (!ns->net_stat_isref) {
762*da14cebeSEric Cheng 			ne->net_entry_ttime += (ns->net_stat_ctime -
763*da14cebeSEric Cheng 			    ne->net_entry_stail->net_stat_ctime);
764*da14cebeSEric Cheng 			ns->net_stat_tdiff = ns->net_stat_ctime -
765*da14cebeSEric Cheng 			    ne->net_entry_stail->net_stat_ctime;
766*da14cebeSEric Cheng 		}
767*da14cebeSEric Cheng 		ne->net_entry_stail->net_stat_next = ns;
768*da14cebeSEric Cheng 		ne->net_entry_stail = ns;
769*da14cebeSEric Cheng 	}
770*da14cebeSEric Cheng 
771*da14cebeSEric Cheng 	ne->net_entry_scount++;
772*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
773*da14cebeSEric Cheng }
774*da14cebeSEric Cheng 
775*da14cebeSEric Cheng /* Add a flow/link descriptor record to the table */
776*da14cebeSEric Cheng static dladm_status_t
777*da14cebeSEric Cheng add_desc(net_table_t *net_table, ea_file_t *ef, int nobjs)
778*da14cebeSEric Cheng {
779*da14cebeSEric Cheng 	net_desc_t	*nd;
780*da14cebeSEric Cheng 	net_desc_t	*dnd;
781*da14cebeSEric Cheng 	int		count;
782*da14cebeSEric Cheng 	ea_object_t	scratch;
783*da14cebeSEric Cheng 
784*da14cebeSEric Cheng 	if ((nd = calloc(1, sizeof (net_desc_t))) == NULL)
785*da14cebeSEric Cheng 		return (DLADM_STATUS_NOMEM);
786*da14cebeSEric Cheng 	nd->net_desc_newrec = B_TRUE;
787*da14cebeSEric Cheng 
788*da14cebeSEric Cheng 	for (count = 0; count < nobjs; count++) {
789*da14cebeSEric Cheng 		if (ea_get_object(ef, &scratch) == -1) {
790*da14cebeSEric Cheng 			free(nd);
791*da14cebeSEric Cheng 			return (DLADM_STATUS_NOMEM);
792*da14cebeSEric Cheng 		}
793*da14cebeSEric Cheng 		add_desc_item(&scratch, nd);
794*da14cebeSEric Cheng 	}
795*da14cebeSEric Cheng 	if ((dnd = get_ndesc(net_table, nd)) != NULL) {
796*da14cebeSEric Cheng 		dnd->net_desc_newrec = B_TRUE;
797*da14cebeSEric Cheng 		free(nd);
798*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
799*da14cebeSEric Cheng 	}
800*da14cebeSEric Cheng 	if (add_desc_to_tbl(net_table, nd) != 0) {
801*da14cebeSEric Cheng 		free(nd);
802*da14cebeSEric Cheng 		return (DLADM_STATUS_NOMEM);
803*da14cebeSEric Cheng 	}
804*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
805*da14cebeSEric Cheng }
806*da14cebeSEric Cheng 
807*da14cebeSEric Cheng /* Make an entry into the time sorted list */
808*da14cebeSEric Cheng static void
809*da14cebeSEric Cheng addto_time_list(net_table_t *net_table, net_time_entry_t *nt,
810*da14cebeSEric Cheng     net_time_entry_t *ntc)
811*da14cebeSEric Cheng {
812*da14cebeSEric Cheng 	net_stat_t		*ns = nt->my_time_stat;
813*da14cebeSEric Cheng 	net_stat_t		*ns1;
814*da14cebeSEric Cheng 	net_time_entry_t	*end;
815*da14cebeSEric Cheng 	net_time_t		*t1;
816*da14cebeSEric Cheng 	int			count;
817*da14cebeSEric Cheng 
818*da14cebeSEric Cheng 	t1 = &ns->net_stat_time;
819*da14cebeSEric Cheng 
820*da14cebeSEric Cheng 	net_table->net_time_entries++;
821*da14cebeSEric Cheng 
822*da14cebeSEric Cheng 	if (net_table->net_time_head == NULL) {
823*da14cebeSEric Cheng 		net_table->net_time_head = nt;
824*da14cebeSEric Cheng 		net_table->net_time_tail = nt;
825*da14cebeSEric Cheng 	} else {
826*da14cebeSEric Cheng 		net_table->net_time_tail->net_time_entry_next = nt;
827*da14cebeSEric Cheng 		nt->net_time_entry_prev = net_table->net_time_tail;
828*da14cebeSEric Cheng 		net_table->net_time_tail = nt;
829*da14cebeSEric Cheng 	}
830*da14cebeSEric Cheng 
831*da14cebeSEric Cheng 	if (net_table->net_ctime_head == NULL) {
832*da14cebeSEric Cheng 		net_table->net_ctime_head = ntc;
833*da14cebeSEric Cheng 		net_table->net_ctime_tail = ntc;
834*da14cebeSEric Cheng 	} else {
835*da14cebeSEric Cheng 		end = net_table->net_ctime_tail;
836*da14cebeSEric Cheng 		count = 0;
837*da14cebeSEric Cheng 		while (count < net_table->net_time_entries - 1) {
838*da14cebeSEric Cheng 			ns1 = end->my_time_stat;
839*da14cebeSEric Cheng 			/* Just add it to the tail */
840*da14cebeSEric Cheng 			if (compare_date(t1, &ns1->net_stat_time) ==
841*da14cebeSEric Cheng 			    NET_DATE_GREATER) {
842*da14cebeSEric Cheng 				break;
843*da14cebeSEric Cheng 			}
844*da14cebeSEric Cheng 			if ((strlen(ns1->net_stat_name) ==
845*da14cebeSEric Cheng 			    strlen(ns->net_stat_name)) &&
846*da14cebeSEric Cheng 			    (strncmp(ns1->net_stat_name, ns->net_stat_name,
847*da14cebeSEric Cheng 			    strlen(ns1->net_stat_name)) == 0)) {
848*da14cebeSEric Cheng 				ntc->net_time_entry_next =
849*da14cebeSEric Cheng 				    end->net_time_entry_next;
850*da14cebeSEric Cheng 				if (end->net_time_entry_next != NULL) {
851*da14cebeSEric Cheng 					end->net_time_entry_next->
852*da14cebeSEric Cheng 					    net_time_entry_prev = ntc;
853*da14cebeSEric Cheng 				} else {
854*da14cebeSEric Cheng 					net_table->net_ctime_tail = ntc;
855*da14cebeSEric Cheng 				}
856*da14cebeSEric Cheng 				end->net_time_entry_next = ntc;
857*da14cebeSEric Cheng 				ntc->net_time_entry_prev = end;
858*da14cebeSEric Cheng 				return;
859*da14cebeSEric Cheng 			}
860*da14cebeSEric Cheng 			count++;
861*da14cebeSEric Cheng 			end = end->net_time_entry_prev;
862*da14cebeSEric Cheng 		}
863*da14cebeSEric Cheng 		net_table->net_ctime_tail->net_time_entry_next = ntc;
864*da14cebeSEric Cheng 		ntc->net_time_entry_prev = net_table->net_ctime_tail;
865*da14cebeSEric Cheng 		net_table->net_ctime_tail = ntc;
866*da14cebeSEric Cheng 	}
867*da14cebeSEric Cheng }
868*da14cebeSEric Cheng 
869*da14cebeSEric Cheng /* Add stat entry into the lists */
870*da14cebeSEric Cheng static dladm_status_t
871*da14cebeSEric Cheng add_stats(net_table_t *net_table, ea_file_t *ef, int nobjs)
872*da14cebeSEric Cheng {
873*da14cebeSEric Cheng 	net_stat_t		*ns;
874*da14cebeSEric Cheng 	int			count;
875*da14cebeSEric Cheng 	ea_object_t		scratch;
876*da14cebeSEric Cheng 	net_time_entry_t	*nt;
877*da14cebeSEric Cheng 	net_time_entry_t	*ntc;
878*da14cebeSEric Cheng 
879*da14cebeSEric Cheng 	if ((ns = calloc(1, sizeof (net_stat_t))) == NULL)
880*da14cebeSEric Cheng 		return (DLADM_STATUS_NOMEM);
881*da14cebeSEric Cheng 
882*da14cebeSEric Cheng 	if ((nt = calloc(1, sizeof (net_time_entry_t))) == NULL) {
883*da14cebeSEric Cheng 		free(ns);
884*da14cebeSEric Cheng 		return (DLADM_STATUS_NOMEM);
885*da14cebeSEric Cheng 	}
886*da14cebeSEric Cheng 	if ((ntc = calloc(1, sizeof (net_time_entry_t))) == NULL) {
887*da14cebeSEric Cheng 		free(ns);
888*da14cebeSEric Cheng 		free(nt);
889*da14cebeSEric Cheng 		return (DLADM_STATUS_NOMEM);
890*da14cebeSEric Cheng 	}
891*da14cebeSEric Cheng 
892*da14cebeSEric Cheng 	nt->my_time_stat = ns;
893*da14cebeSEric Cheng 	ntc->my_time_stat = ns;
894*da14cebeSEric Cheng 
895*da14cebeSEric Cheng 	for (count = 0; count < nobjs; count++) {
896*da14cebeSEric Cheng 		if (ea_get_object(ef, &scratch) == -1) {
897*da14cebeSEric Cheng 			free(ns);
898*da14cebeSEric Cheng 			free(nt);
899*da14cebeSEric Cheng 			free(ntc);
900*da14cebeSEric Cheng 			return (DLADM_STATUS_NOMEM);
901*da14cebeSEric Cheng 		}
902*da14cebeSEric Cheng 		add_stat_item(&scratch, ns);
903*da14cebeSEric Cheng 	}
904*da14cebeSEric Cheng 	if (add_stat_to_tbl(net_table, ns) != 0) {
905*da14cebeSEric Cheng 		free(ns);
906*da14cebeSEric Cheng 		free(nt);
907*da14cebeSEric Cheng 		free(ntc);
908*da14cebeSEric Cheng 		return (DLADM_STATUS_NOMEM);
909*da14cebeSEric Cheng 	}
910*da14cebeSEric Cheng 	addto_time_list(net_table, nt, ntc);
911*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
912*da14cebeSEric Cheng }
913*da14cebeSEric Cheng 
914*da14cebeSEric Cheng /* Free the entire table */
915*da14cebeSEric Cheng static void
916*da14cebeSEric Cheng free_logtable(net_table_t *net_table)
917*da14cebeSEric Cheng {
918*da14cebeSEric Cheng 	net_entry_t		*head;
919*da14cebeSEric Cheng 	net_entry_t		*next;
920*da14cebeSEric Cheng 	net_stat_t		*ns;
921*da14cebeSEric Cheng 	net_stat_t		*ns1;
922*da14cebeSEric Cheng 	net_time_entry_t	*thead;
923*da14cebeSEric Cheng 	net_time_entry_t	*tnext;
924*da14cebeSEric Cheng 
925*da14cebeSEric Cheng 	thead = net_table->net_time_head;
926*da14cebeSEric Cheng 	while (thead != NULL) {
927*da14cebeSEric Cheng 		thead->my_time_stat = NULL;
928*da14cebeSEric Cheng 		tnext = thead->net_time_entry_next;
929*da14cebeSEric Cheng 		thead->net_time_entry_next = NULL;
930*da14cebeSEric Cheng 		thead->net_time_entry_prev = NULL;
931*da14cebeSEric Cheng 		free(thead);
932*da14cebeSEric Cheng 		thead = tnext;
933*da14cebeSEric Cheng 	}
934*da14cebeSEric Cheng 	net_table->net_time_head = NULL;
935*da14cebeSEric Cheng 	net_table->net_time_tail = NULL;
936*da14cebeSEric Cheng 
937*da14cebeSEric Cheng 	thead = net_table->net_ctime_head;
938*da14cebeSEric Cheng 	while (thead != NULL) {
939*da14cebeSEric Cheng 		thead->my_time_stat = NULL;
940*da14cebeSEric Cheng 		tnext = thead->net_time_entry_next;
941*da14cebeSEric Cheng 		thead->net_time_entry_next = NULL;
942*da14cebeSEric Cheng 		thead->net_time_entry_prev = NULL;
943*da14cebeSEric Cheng 		free(thead);
944*da14cebeSEric Cheng 		thead = tnext;
945*da14cebeSEric Cheng 	}
946*da14cebeSEric Cheng 	net_table->net_ctime_head = NULL;
947*da14cebeSEric Cheng 	net_table->net_ctime_tail = NULL;
948*da14cebeSEric Cheng 
949*da14cebeSEric Cheng 	net_table->net_time_entries = 0;
950*da14cebeSEric Cheng 
951*da14cebeSEric Cheng 	head = net_table->net_table_head;
952*da14cebeSEric Cheng 	while (head != NULL) {
953*da14cebeSEric Cheng 		next = head->net_entry_next;
954*da14cebeSEric Cheng 		head->net_entry_next = NULL;
955*da14cebeSEric Cheng 		ns = head->net_entry_shead;
956*da14cebeSEric Cheng 		while (ns != NULL) {
957*da14cebeSEric Cheng 			ns1 = ns->net_stat_next;
958*da14cebeSEric Cheng 			free(ns);
959*da14cebeSEric Cheng 			ns = ns1;
960*da14cebeSEric Cheng 		}
961*da14cebeSEric Cheng 		head->net_entry_scount = 0;
962*da14cebeSEric Cheng 		head->net_entry_sref = NULL;
963*da14cebeSEric Cheng 		free(head->net_entry_desc);
964*da14cebeSEric Cheng 		free(head->net_entry_tstats);
965*da14cebeSEric Cheng 		free(head);
966*da14cebeSEric Cheng 		head = next;
967*da14cebeSEric Cheng 	}
968*da14cebeSEric Cheng 	net_table->net_table_head = NULL;
969*da14cebeSEric Cheng 	net_table->net_table_tail = NULL;
970*da14cebeSEric Cheng 	net_table->net_time_entries = 0;
971*da14cebeSEric Cheng 	free(net_table);
972*da14cebeSEric Cheng }
973*da14cebeSEric Cheng 
974*da14cebeSEric Cheng /* Parse the exacct file, and return the parsed table. */
975*da14cebeSEric Cheng static void *
976*da14cebeSEric Cheng parse_logfile(char *file, int logtype, dladm_status_t *status)
977*da14cebeSEric Cheng {
978*da14cebeSEric Cheng 	ea_file_t	ef;
979*da14cebeSEric Cheng 	ea_object_t	scratch;
980*da14cebeSEric Cheng 	net_table_t	*net_table;
981*da14cebeSEric Cheng 
982*da14cebeSEric Cheng 	*status = DLADM_STATUS_OK;
983*da14cebeSEric Cheng 	if ((net_table = calloc(1, sizeof (net_table_t))) == NULL) {
984*da14cebeSEric Cheng 		*status = DLADM_STATUS_NOMEM;
985*da14cebeSEric Cheng 		return (NULL);
986*da14cebeSEric Cheng 	}
987*da14cebeSEric Cheng 	if (ea_open(&ef, file, NULL, 0, O_RDONLY, 0) == -1) {
988*da14cebeSEric Cheng 		*status = DLADM_STATUS_BADARG;
989*da14cebeSEric Cheng 		free(net_table);
990*da14cebeSEric Cheng 		return (NULL);
991*da14cebeSEric Cheng 	}
992*da14cebeSEric Cheng 	bzero(&scratch, sizeof (ea_object_t));
993*da14cebeSEric Cheng 	while (ea_get_object(&ef, &scratch) != -1) {
994*da14cebeSEric Cheng 		if (scratch.eo_type != EO_GROUP) {
995*da14cebeSEric Cheng 			(void) ea_free_item(&scratch, EUP_ALLOC);
996*da14cebeSEric Cheng 			(void) bzero(&scratch, sizeof (ea_object_t));
997*da14cebeSEric Cheng 			continue;
998*da14cebeSEric Cheng 		}
999*da14cebeSEric Cheng 		/* Read Link Desc/Stat records */
1000*da14cebeSEric Cheng 		if (logtype == DLADM_LOGTYPE_FLOW) {
1001*da14cebeSEric Cheng 			/* Flow Descriptor */
1002*da14cebeSEric Cheng 			if ((scratch.eo_catalog &
1003*da14cebeSEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_FLOW_DESC) {
1004*da14cebeSEric Cheng 				(void) add_desc(net_table, &ef,
1005*da14cebeSEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
1006*da14cebeSEric Cheng 			/* Flow Stats */
1007*da14cebeSEric Cheng 			} else if ((scratch.eo_catalog &
1008*da14cebeSEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_FLOW_STATS) {
1009*da14cebeSEric Cheng 				(void) add_stats(net_table, &ef,
1010*da14cebeSEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
1011*da14cebeSEric Cheng 			}
1012*da14cebeSEric Cheng 		} else if (logtype == DLADM_LOGTYPE_LINK) {
1013*da14cebeSEric Cheng 			/* Link Descriptor */
1014*da14cebeSEric Cheng 			if ((scratch.eo_catalog &
1015*da14cebeSEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_LINK_DESC) {
1016*da14cebeSEric Cheng 				(void) add_desc(net_table, &ef,
1017*da14cebeSEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
1018*da14cebeSEric Cheng 			/* Link Stats */
1019*da14cebeSEric Cheng 			} else if ((scratch.eo_catalog &
1020*da14cebeSEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_LINK_STATS) {
1021*da14cebeSEric Cheng 				(void) add_stats(net_table, &ef,
1022*da14cebeSEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
1023*da14cebeSEric Cheng 			}
1024*da14cebeSEric Cheng 		} else {
1025*da14cebeSEric Cheng 			if (((scratch.eo_catalog & EXD_DATA_MASK) ==
1026*da14cebeSEric Cheng 			    EXD_GROUP_NET_LINK_DESC) || ((scratch.eo_catalog &
1027*da14cebeSEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_FLOW_DESC)) {
1028*da14cebeSEric Cheng 				(void) add_desc(net_table, &ef,
1029*da14cebeSEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
1030*da14cebeSEric Cheng 			} else if (((scratch.eo_catalog & EXD_DATA_MASK) ==
1031*da14cebeSEric Cheng 			    EXD_GROUP_NET_LINK_STATS) || ((scratch.eo_catalog &
1032*da14cebeSEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_FLOW_STATS)) {
1033*da14cebeSEric Cheng 				(void) add_stats(net_table, &ef,
1034*da14cebeSEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
1035*da14cebeSEric Cheng 			}
1036*da14cebeSEric Cheng 		}
1037*da14cebeSEric Cheng 		(void) ea_free_item(&scratch, EUP_ALLOC);
1038*da14cebeSEric Cheng 		(void) bzero(&scratch, sizeof (ea_object_t));
1039*da14cebeSEric Cheng 	}
1040*da14cebeSEric Cheng 
1041*da14cebeSEric Cheng 	(void) ea_close(&ef);
1042*da14cebeSEric Cheng 	return ((void *)net_table);
1043*da14cebeSEric Cheng }
1044*da14cebeSEric Cheng 
1045*da14cebeSEric Cheng /*
1046*da14cebeSEric Cheng  * Walk the ctime list.  This is used when looking for usage records
1047*da14cebeSEric Cheng  * based on a "resource" name.
1048*da14cebeSEric Cheng  */
1049*da14cebeSEric Cheng dladm_status_t
1050*da14cebeSEric Cheng dladm_walk_usage_res(int (*fn)(dladm_usage_t *, void *), int logtype,
1051*da14cebeSEric Cheng     char *logfile, char *resource, char *stime, char *etime, void *arg)
1052*da14cebeSEric Cheng {
1053*da14cebeSEric Cheng 	net_table_t		*net_table;
1054*da14cebeSEric Cheng 	net_time_t		st, et;
1055*da14cebeSEric Cheng 	net_time_entry_t	*start;
1056*da14cebeSEric Cheng 	net_stat_t		*ns = NULL;
1057*da14cebeSEric Cheng 	net_stat_t		*nns;
1058*da14cebeSEric Cheng 	uint64_t		tot_time = 0;
1059*da14cebeSEric Cheng 	uint64_t		last_time;
1060*da14cebeSEric Cheng 	uint64_t		tot_bytes = 0;
1061*da14cebeSEric Cheng 	uint64_t		tot_ibytes = 0;
1062*da14cebeSEric Cheng 	uint64_t		tot_obytes = 0;
1063*da14cebeSEric Cheng 	boolean_t		gotstart = B_FALSE;
1064*da14cebeSEric Cheng 	dladm_status_t		status;
1065*da14cebeSEric Cheng 	dladm_usage_t		usage;
1066*da14cebeSEric Cheng 	int			step = 1;
1067*da14cebeSEric Cheng 
1068*da14cebeSEric Cheng 	/* Parse the log file */
1069*da14cebeSEric Cheng 	net_table = parse_logfile(logfile, logtype, &status);
1070*da14cebeSEric Cheng 	if (net_table == NULL)
1071*da14cebeSEric Cheng 		return (status);
1072*da14cebeSEric Cheng 
1073*da14cebeSEric Cheng 	if (net_table->net_entries == 0)
1074*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
1075*da14cebeSEric Cheng 	start = net_table->net_ctime_head;
1076*da14cebeSEric Cheng 
1077*da14cebeSEric Cheng 	/* Time range */
1078*da14cebeSEric Cheng 	status = get_time_range(net_table->net_ctime_head,
1079*da14cebeSEric Cheng 	    net_table->net_ctime_tail, &st, &et, stime, etime);
1080*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1081*da14cebeSEric Cheng 		return (status);
1082*da14cebeSEric Cheng 
1083*da14cebeSEric Cheng 	while (start != NULL) {
1084*da14cebeSEric Cheng 		nns = start->my_time_stat;
1085*da14cebeSEric Cheng 
1086*da14cebeSEric Cheng 		/* Get to the resource we are interested in */
1087*da14cebeSEric Cheng 		if ((strlen(resource) != strlen(nns->net_stat_name)) ||
1088*da14cebeSEric Cheng 		    (strncmp(resource, nns->net_stat_name,
1089*da14cebeSEric Cheng 		    strlen(nns->net_stat_name)) != 0)) {
1090*da14cebeSEric Cheng 			start = start->net_time_entry_next;
1091*da14cebeSEric Cheng 			continue;
1092*da14cebeSEric Cheng 		}
1093*da14cebeSEric Cheng 
1094*da14cebeSEric Cheng 		/* Find the first record */
1095*da14cebeSEric Cheng 		if (!gotstart) {
1096*da14cebeSEric Cheng 			get_starting_point(start, &start, &st, stime,
1097*da14cebeSEric Cheng 			    &last_time);
1098*da14cebeSEric Cheng 			if (start == NULL)
1099*da14cebeSEric Cheng 				break;
1100*da14cebeSEric Cheng 			nns = start->my_time_stat;
1101*da14cebeSEric Cheng 			gotstart = B_TRUE;
1102*da14cebeSEric Cheng 		}
1103*da14cebeSEric Cheng 
1104*da14cebeSEric Cheng 		/* Write one entry and return if we are out of the range */
1105*da14cebeSEric Cheng 		if (etime != NULL && compare_time(&nns->net_stat_time, &et)
1106*da14cebeSEric Cheng 		    == NET_TIME_GREATER) {
1107*da14cebeSEric Cheng 			if (tot_bytes != 0) {
1108*da14cebeSEric Cheng 				bcopy(ns->net_stat_name, &usage.du_name,
1109*da14cebeSEric Cheng 				    sizeof (usage.du_name));
1110*da14cebeSEric Cheng 				bcopy(&last_time, &usage.du_stime,
1111*da14cebeSEric Cheng 				    sizeof (usage.du_stime));
1112*da14cebeSEric Cheng 				bcopy(&ns->net_stat_ctime, &usage.du_etime,
1113*da14cebeSEric Cheng 				    sizeof (usage.du_etime));
1114*da14cebeSEric Cheng 				usage.du_rbytes = tot_ibytes;
1115*da14cebeSEric Cheng 				usage.du_obytes = tot_obytes;
1116*da14cebeSEric Cheng 				usage.du_bandwidth = tot_bytes*8/tot_time;
1117*da14cebeSEric Cheng 				usage.du_last = B_TRUE;
1118*da14cebeSEric Cheng 				fn(&usage, arg);
1119*da14cebeSEric Cheng 			}
1120*da14cebeSEric Cheng 			return (DLADM_STATUS_OK);
1121*da14cebeSEric Cheng 		}
1122*da14cebeSEric Cheng 
1123*da14cebeSEric Cheng 		/*
1124*da14cebeSEric Cheng 		 * If this is a reference entry, just print what we have
1125*da14cebeSEric Cheng 		 * and proceed.
1126*da14cebeSEric Cheng 		 */
1127*da14cebeSEric Cheng 		if (nns->net_stat_isref) {
1128*da14cebeSEric Cheng 			if (tot_bytes != 0) {
1129*da14cebeSEric Cheng 				bcopy(&nns->net_stat_name, &usage.du_name,
1130*da14cebeSEric Cheng 				    sizeof (usage.du_name));
1131*da14cebeSEric Cheng 				bcopy(&nns->net_stat_ctime, &usage.du_stime,
1132*da14cebeSEric Cheng 				    sizeof (usage.du_stime));
1133*da14cebeSEric Cheng 				usage.du_rbytes = tot_ibytes;
1134*da14cebeSEric Cheng 				usage.du_obytes = tot_obytes;
1135*da14cebeSEric Cheng 				usage.du_bandwidth = tot_bytes*8/tot_time;
1136*da14cebeSEric Cheng 				usage.du_last = B_TRUE;
1137*da14cebeSEric Cheng 				fn(&usage, arg);
1138*da14cebeSEric Cheng 				NET_RESET_TOT(tot_bytes, tot_time, tot_ibytes,
1139*da14cebeSEric Cheng 				    tot_obytes, step);
1140*da14cebeSEric Cheng 			}
1141*da14cebeSEric Cheng 			last_time = nns->net_stat_ctime;
1142*da14cebeSEric Cheng 			start = start->net_time_entry_next;
1143*da14cebeSEric Cheng 			continue;
1144*da14cebeSEric Cheng 		}
1145*da14cebeSEric Cheng 
1146*da14cebeSEric Cheng 		ns = nns;
1147*da14cebeSEric Cheng 		if (--step == 0) {
1148*da14cebeSEric Cheng 			tot_bytes += ns->net_stat_ibytes + ns->net_stat_obytes;
1149*da14cebeSEric Cheng 			tot_ibytes += ns->net_stat_ibytes;
1150*da14cebeSEric Cheng 			tot_obytes += ns->net_stat_obytes;
1151*da14cebeSEric Cheng 			tot_time += ns->net_stat_tdiff;
1152*da14cebeSEric Cheng 			bcopy(&ns->net_stat_name, &usage.du_name,
1153*da14cebeSEric Cheng 			    sizeof (usage.du_name));
1154*da14cebeSEric Cheng 			bcopy(&last_time, &usage.du_stime,
1155*da14cebeSEric Cheng 			    sizeof (usage.du_stime));
1156*da14cebeSEric Cheng 			bcopy(&ns->net_stat_ctime, &usage.du_etime,
1157*da14cebeSEric Cheng 			    sizeof (usage.du_etime));
1158*da14cebeSEric Cheng 			usage.du_rbytes = tot_ibytes;
1159*da14cebeSEric Cheng 			usage.du_obytes = tot_obytes;
1160*da14cebeSEric Cheng 			usage.du_bandwidth = tot_bytes*8/tot_time;
1161*da14cebeSEric Cheng 			usage.du_last = B_TRUE;
1162*da14cebeSEric Cheng 			fn(&usage, arg);
1163*da14cebeSEric Cheng 
1164*da14cebeSEric Cheng 			NET_RESET_TOT(tot_bytes, tot_time, tot_ibytes,
1165*da14cebeSEric Cheng 			    tot_obytes, step);
1166*da14cebeSEric Cheng 			last_time = ns->net_stat_ctime;
1167*da14cebeSEric Cheng 		} else {
1168*da14cebeSEric Cheng 			tot_bytes += ns->net_stat_ibytes + ns->net_stat_obytes;
1169*da14cebeSEric Cheng 			tot_ibytes += ns->net_stat_ibytes;
1170*da14cebeSEric Cheng 			tot_obytes += ns->net_stat_obytes;
1171*da14cebeSEric Cheng 			tot_time += ns->net_stat_tdiff;
1172*da14cebeSEric Cheng 		}
1173*da14cebeSEric Cheng 		start = start->net_time_entry_next;
1174*da14cebeSEric Cheng 	}
1175*da14cebeSEric Cheng 
1176*da14cebeSEric Cheng 	if (tot_bytes != 0) {
1177*da14cebeSEric Cheng 		bcopy(&ns->net_stat_name, &usage.du_name,
1178*da14cebeSEric Cheng 		    sizeof (usage.du_name));
1179*da14cebeSEric Cheng 		bcopy(&last_time, &usage.du_stime,
1180*da14cebeSEric Cheng 		    sizeof (usage.du_stime));
1181*da14cebeSEric Cheng 		bcopy(&ns->net_stat_ctime, &usage.du_etime,
1182*da14cebeSEric Cheng 		    sizeof (usage.du_etime));
1183*da14cebeSEric Cheng 		usage.du_rbytes = tot_ibytes;
1184*da14cebeSEric Cheng 		usage.du_obytes = tot_obytes;
1185*da14cebeSEric Cheng 		usage.du_bandwidth = tot_bytes*8/tot_time;
1186*da14cebeSEric Cheng 		usage.du_last = B_TRUE;
1187*da14cebeSEric Cheng 		fn(&usage, arg);
1188*da14cebeSEric Cheng 	}
1189*da14cebeSEric Cheng 
1190*da14cebeSEric Cheng 	free_logtable(net_table);
1191*da14cebeSEric Cheng 	return (status);
1192*da14cebeSEric Cheng }
1193*da14cebeSEric Cheng 
1194*da14cebeSEric Cheng /*
1195*da14cebeSEric Cheng  * Walk the time sorted list if a resource is not specified.
1196*da14cebeSEric Cheng  */
1197*da14cebeSEric Cheng dladm_status_t
1198*da14cebeSEric Cheng dladm_walk_usage_time(int (*fn)(dladm_usage_t *, void *), int logtype,
1199*da14cebeSEric Cheng     char *logfile, char *stime, char *etime, void *arg)
1200*da14cebeSEric Cheng {
1201*da14cebeSEric Cheng 	net_table_t		*net_table;
1202*da14cebeSEric Cheng 	net_time_entry_t	*start;
1203*da14cebeSEric Cheng 	net_stat_t		*ns = NULL, *nns;
1204*da14cebeSEric Cheng 	net_time_t		st, et, *t1;
1205*da14cebeSEric Cheng 	net_desc_t		*nd;
1206*da14cebeSEric Cheng 	net_entry_t		*ne;
1207*da14cebeSEric Cheng 	net_plot_entry_t	*pe;
1208*da14cebeSEric Cheng 	int			count;
1209*da14cebeSEric Cheng 	int			step = 1;
1210*da14cebeSEric Cheng 	int			nentries = 0, pentries = 0;
1211*da14cebeSEric Cheng 	uint64_t		last_time;
1212*da14cebeSEric Cheng 	dladm_status_t		status;
1213*da14cebeSEric Cheng 
1214*da14cebeSEric Cheng 	/* Parse the log file */
1215*da14cebeSEric Cheng 	net_table = parse_logfile(logfile, logtype, &status);
1216*da14cebeSEric Cheng 	if (net_table == NULL)
1217*da14cebeSEric Cheng 		return (status);
1218*da14cebeSEric Cheng 
1219*da14cebeSEric Cheng 	if (net_table->net_entries == 0)
1220*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
1221*da14cebeSEric Cheng 	start = net_table->net_time_head;
1222*da14cebeSEric Cheng 
1223*da14cebeSEric Cheng 	/* Find the first and last records and starting point */
1224*da14cebeSEric Cheng 	status = get_time_range(net_table->net_time_head,
1225*da14cebeSEric Cheng 	    net_table->net_time_tail, &st, &et, stime, etime);
1226*da14cebeSEric Cheng 	if (status != DLADM_STATUS_OK)
1227*da14cebeSEric Cheng 		return (status);
1228*da14cebeSEric Cheng 	get_starting_point(start, &start, &st, stime, &last_time);
1229*da14cebeSEric Cheng 	/*
1230*da14cebeSEric Cheng 	 * Could assert to be non-null, since get_time_range()
1231*da14cebeSEric Cheng 	 * would have adjusted.
1232*da14cebeSEric Cheng 	 */
1233*da14cebeSEric Cheng 	if (start == NULL)
1234*da14cebeSEric Cheng 		return (DLADM_STATUS_BADTIMEVAL);
1235*da14cebeSEric Cheng 
1236*da14cebeSEric Cheng 	/*
1237*da14cebeSEric Cheng 	 * Collect entries for all resources in a time slot before
1238*da14cebeSEric Cheng 	 * writing to the file.
1239*da14cebeSEric Cheng 	 */
1240*da14cebeSEric Cheng 	nentries = net_table->net_entries;
1241*da14cebeSEric Cheng 
1242*da14cebeSEric Cheng 	pe = malloc(sizeof (net_plot_entry_t) * net_table->net_entries + 1);
1243*da14cebeSEric Cheng 	if (pe == NULL)
1244*da14cebeSEric Cheng 		return (DLADM_STATUS_NOMEM);
1245*da14cebeSEric Cheng 
1246*da14cebeSEric Cheng 	ne = net_table->net_table_head;
1247*da14cebeSEric Cheng 	for (count = 0; count < nentries; count++) {
1248*da14cebeSEric Cheng 		nd = ne->net_entry_desc;
1249*da14cebeSEric Cheng 		pe[count].net_pe_name = nd->net_desc_name;
1250*da14cebeSEric Cheng 		ne = ne->net_entry_next;
1251*da14cebeSEric Cheng 	}
1252*da14cebeSEric Cheng 
1253*da14cebeSEric Cheng 	clear_pe(pe, nentries, &pentries);
1254*da14cebeSEric Cheng 
1255*da14cebeSEric Cheng 	/* Write header to file */
1256*da14cebeSEric Cheng 	/* add_pe_to_file(fn, pe, ns, nentries, arg); */
1257*da14cebeSEric Cheng 
1258*da14cebeSEric Cheng 	t1 = &start->my_time_stat->net_stat_time;
1259*da14cebeSEric Cheng 
1260*da14cebeSEric Cheng 	while (start != NULL) {
1261*da14cebeSEric Cheng 
1262*da14cebeSEric Cheng 		nns = start->my_time_stat;
1263*da14cebeSEric Cheng 		/*
1264*da14cebeSEric Cheng 		 * We have crossed the time boundary, check if we need to
1265*da14cebeSEric Cheng 		 * print out now.
1266*da14cebeSEric Cheng 		 */
1267*da14cebeSEric Cheng 		if (compare_time(&nns->net_stat_time, t1) ==
1268*da14cebeSEric Cheng 		    NET_TIME_GREATER) {
1269*da14cebeSEric Cheng 			/* return if we are out of the range */
1270*da14cebeSEric Cheng 			if (etime != NULL &&
1271*da14cebeSEric Cheng 			    compare_time(&nns->net_stat_time, &et) ==
1272*da14cebeSEric Cheng 			    NET_TIME_GREATER) {
1273*da14cebeSEric Cheng 				if (pentries > 0) {
1274*da14cebeSEric Cheng 					add_pe_to_file(fn, pe, ns, nentries,
1275*da14cebeSEric Cheng 					    arg);
1276*da14cebeSEric Cheng 					clear_pe(pe, nentries, &pentries);
1277*da14cebeSEric Cheng 				}
1278*da14cebeSEric Cheng 				free(pe);
1279*da14cebeSEric Cheng 				return (DLADM_STATUS_OK);
1280*da14cebeSEric Cheng 			}
1281*da14cebeSEric Cheng 			/* update the stats from the ns. */
1282*da14cebeSEric Cheng 			t1 = &nns->net_stat_time;
1283*da14cebeSEric Cheng 			last_time = ns->net_stat_ctime;
1284*da14cebeSEric Cheng 			if (--step == 0) {
1285*da14cebeSEric Cheng 				if (pentries > 0) {
1286*da14cebeSEric Cheng 					add_pe_to_file(fn, pe, ns, nentries,
1287*da14cebeSEric Cheng 					    arg);
1288*da14cebeSEric Cheng 					clear_pe(pe, nentries, &pentries);
1289*da14cebeSEric Cheng 				}
1290*da14cebeSEric Cheng 				step = 1;
1291*da14cebeSEric Cheng 			}
1292*da14cebeSEric Cheng 		}
1293*da14cebeSEric Cheng 
1294*da14cebeSEric Cheng 		/*
1295*da14cebeSEric Cheng 		 * if this is a reference entry, just print what we have
1296*da14cebeSEric Cheng 		 * for this resource and proceed. We will end up writing
1297*da14cebeSEric Cheng 		 * the stats for all the entries when we hit a ref element,
1298*da14cebeSEric Cheng 		 * which means 'steps' for some might not be accurate, but
1299*da14cebeSEric Cheng 		 * that is fine, the alternative is to write only the
1300*da14cebeSEric Cheng 		 * resource for which we hit a reference entry.
1301*da14cebeSEric Cheng 		 */
1302*da14cebeSEric Cheng 		if (nns->net_stat_isref) {
1303*da14cebeSEric Cheng 			if (pentries > 0) {
1304*da14cebeSEric Cheng 				add_pe_to_file(fn, pe, ns, nentries, arg);
1305*da14cebeSEric Cheng 				clear_pe(pe, nentries, &pentries);
1306*da14cebeSEric Cheng 			}
1307*da14cebeSEric Cheng 			step = 1;
1308*da14cebeSEric Cheng 		} else {
1309*da14cebeSEric Cheng 			update_pe(pe, nns, nentries, &pentries, last_time);
1310*da14cebeSEric Cheng 		}
1311*da14cebeSEric Cheng 		ns = nns;
1312*da14cebeSEric Cheng 		start = start->net_time_entry_next;
1313*da14cebeSEric Cheng 	}
1314*da14cebeSEric Cheng 
1315*da14cebeSEric Cheng 	if (pentries > 0)
1316*da14cebeSEric Cheng 		add_pe_to_file(fn, pe, ns, nentries, arg);
1317*da14cebeSEric Cheng 
1318*da14cebeSEric Cheng 	free(pe);
1319*da14cebeSEric Cheng 	free_logtable(net_table);
1320*da14cebeSEric Cheng 
1321*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
1322*da14cebeSEric Cheng }
1323*da14cebeSEric Cheng 
1324*da14cebeSEric Cheng dladm_status_t
1325*da14cebeSEric Cheng dladm_usage_summary(int (*fn)(dladm_usage_t *, void *), int logtype,
1326*da14cebeSEric Cheng     char *logfile, void *arg)
1327*da14cebeSEric Cheng {
1328*da14cebeSEric Cheng 	net_table_t		*net_table;
1329*da14cebeSEric Cheng 	net_entry_t		*ne;
1330*da14cebeSEric Cheng 	net_desc_t		*nd;
1331*da14cebeSEric Cheng 	net_stat_t		*ns;
1332*da14cebeSEric Cheng 	int			count;
1333*da14cebeSEric Cheng 	dladm_usage_t		usage;
1334*da14cebeSEric Cheng 	dladm_status_t		status;
1335*da14cebeSEric Cheng 
1336*da14cebeSEric Cheng 	/* Parse the log file */
1337*da14cebeSEric Cheng 	net_table = parse_logfile(logfile, logtype, &status);
1338*da14cebeSEric Cheng 	if (net_table == NULL)
1339*da14cebeSEric Cheng 		return (status);
1340*da14cebeSEric Cheng 
1341*da14cebeSEric Cheng 	if (net_table->net_entries == 0)
1342*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
1343*da14cebeSEric Cheng 
1344*da14cebeSEric Cheng 	ne = net_table->net_table_head;
1345*da14cebeSEric Cheng 	for (count = 0; count < net_table->net_entries; count++) {
1346*da14cebeSEric Cheng 		ns = ne->net_entry_tstats;
1347*da14cebeSEric Cheng 		nd = ne->net_entry_desc;
1348*da14cebeSEric Cheng 
1349*da14cebeSEric Cheng 		if (ns->net_stat_ibytes + ns->net_stat_obytes == 0)
1350*da14cebeSEric Cheng 			continue;
1351*da14cebeSEric Cheng 		bcopy(&nd->net_desc_name, &usage.du_name,
1352*da14cebeSEric Cheng 		    sizeof (usage.du_name));
1353*da14cebeSEric Cheng 		usage.du_duration = ne->net_entry_ttime;
1354*da14cebeSEric Cheng 		usage.du_ipackets = ns->net_stat_ipackets;
1355*da14cebeSEric Cheng 		usage.du_rbytes = ns->net_stat_ibytes;
1356*da14cebeSEric Cheng 		usage.du_opackets = ns->net_stat_opackets;
1357*da14cebeSEric Cheng 		usage.du_obytes = ns->net_stat_obytes;
1358*da14cebeSEric Cheng 		usage.du_bandwidth =
1359*da14cebeSEric Cheng 		    (ns->net_stat_ibytes + ns->net_stat_obytes) * 8 /
1360*da14cebeSEric Cheng 		    usage.du_duration;
1361*da14cebeSEric Cheng 		usage.du_last = (count == net_table->net_entries-1);
1362*da14cebeSEric Cheng 		fn(&usage, arg);
1363*da14cebeSEric Cheng 
1364*da14cebeSEric Cheng 		ne = ne->net_entry_next;
1365*da14cebeSEric Cheng 	}
1366*da14cebeSEric Cheng 
1367*da14cebeSEric Cheng 	free_logtable(net_table);
1368*da14cebeSEric Cheng 	return (DLADM_STATUS_OK);
1369*da14cebeSEric Cheng }
1370*da14cebeSEric Cheng 
1371*da14cebeSEric Cheng /*
1372*da14cebeSEric Cheng  * Walk the ctime list and display the dates of the records.
1373*da14cebeSEric Cheng  */
1374*da14cebeSEric Cheng dladm_status_t
1375*da14cebeSEric Cheng dladm_usage_dates(int (*fn)(dladm_usage_t *, void *), int logtype,
1376*da14cebeSEric Cheng     char *logfile, char *resource, void *arg)
1377*da14cebeSEric Cheng {
1378*da14cebeSEric Cheng 	net_table_t		*net_table;
1379*da14cebeSEric Cheng 	net_time_entry_t	*start;
1380*da14cebeSEric Cheng 	net_stat_t		*nns;
1381*da14cebeSEric Cheng 	net_time_t		st;
1382*da14cebeSEric Cheng 	net_time_t		*lasttime = NULL;
1383*da14cebeSEric Cheng 	uint64_t		last_time;
1384*da14cebeSEric Cheng 	boolean_t		gotstart = B_FALSE;
1385*da14cebeSEric Cheng 	dladm_status_t		status;
1386*da14cebeSEric Cheng 	dladm_usage_t		usage;
1387*da14cebeSEric Cheng 
1388*da14cebeSEric Cheng 	/* Parse the log file */
1389*da14cebeSEric Cheng 	net_table = parse_logfile(logfile, logtype, &status);
1390*da14cebeSEric Cheng 	if (net_table == NULL)
1391*da14cebeSEric Cheng 		return (status);
1392*da14cebeSEric Cheng 
1393*da14cebeSEric Cheng 	if (net_table->net_entries == 0)
1394*da14cebeSEric Cheng 		return (DLADM_STATUS_OK);
1395*da14cebeSEric Cheng 
1396*da14cebeSEric Cheng 	start = net_table->net_ctime_head;
1397*da14cebeSEric Cheng 
1398*da14cebeSEric Cheng 	while (start != NULL) {
1399*da14cebeSEric Cheng 		nns = start->my_time_stat;
1400*da14cebeSEric Cheng 
1401*da14cebeSEric Cheng 		/* get to the resource we are interested in */
1402*da14cebeSEric Cheng 		if (resource != NULL) {
1403*da14cebeSEric Cheng 			if ((strlen(resource) != strlen(nns->net_stat_name)) ||
1404*da14cebeSEric Cheng 			    (strncmp(resource, nns->net_stat_name,
1405*da14cebeSEric Cheng 			    strlen(nns->net_stat_name)) != 0)) {
1406*da14cebeSEric Cheng 				start = start->net_time_entry_next;
1407*da14cebeSEric Cheng 				continue;
1408*da14cebeSEric Cheng 			}
1409*da14cebeSEric Cheng 		}
1410*da14cebeSEric Cheng 
1411*da14cebeSEric Cheng 		/* get the starting point in the logfile */
1412*da14cebeSEric Cheng 		if (!gotstart) {
1413*da14cebeSEric Cheng 			get_starting_point(start, &start, &st, NULL,
1414*da14cebeSEric Cheng 			    &last_time);
1415*da14cebeSEric Cheng 			if (start == NULL)
1416*da14cebeSEric Cheng 				break;
1417*da14cebeSEric Cheng 			nns = start->my_time_stat;
1418*da14cebeSEric Cheng 			gotstart = B_TRUE;
1419*da14cebeSEric Cheng 		}
1420*da14cebeSEric Cheng 
1421*da14cebeSEric Cheng 		if (lasttime == NULL ||
1422*da14cebeSEric Cheng 		    compare_date(&nns->net_stat_time, lasttime) ==
1423*da14cebeSEric Cheng 		    NET_DATE_GREATER) {
1424*da14cebeSEric Cheng 			bzero(&usage, sizeof (dladm_usage_t));
1425*da14cebeSEric Cheng 			bcopy(&nns->net_stat_ctime, &usage.du_stime,
1426*da14cebeSEric Cheng 			    sizeof (usage.du_stime));
1427*da14cebeSEric Cheng 			fn(&usage, arg);
1428*da14cebeSEric Cheng 			lasttime = &nns->net_stat_time;
1429*da14cebeSEric Cheng 		}
1430*da14cebeSEric Cheng 
1431*da14cebeSEric Cheng 		start = start->net_time_entry_next;
1432*da14cebeSEric Cheng 		continue;
1433*da14cebeSEric Cheng 	}
1434*da14cebeSEric Cheng 
1435*da14cebeSEric Cheng 	free_logtable(net_table);
1436*da14cebeSEric Cheng 	return (status);
1437*da14cebeSEric Cheng }
1438