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