xref: /onnv-gate/usr/src/lib/libdladm/common/usage.c (revision 11878:ac93462db6d7)
18275SEric Cheng /*
28275SEric Cheng  * CDDL HEADER START
38275SEric Cheng  *
48275SEric Cheng  * The contents of this file are subject to the terms of the
58275SEric Cheng  * Common Development and Distribution License (the "License").
68275SEric Cheng  * You may not use this file except in compliance with the License.
78275SEric Cheng  *
88275SEric Cheng  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98275SEric Cheng  * or http://www.opensolaris.org/os/licensing.
108275SEric Cheng  * See the License for the specific language governing permissions
118275SEric Cheng  * and limitations under the License.
128275SEric Cheng  *
138275SEric Cheng  * When distributing Covered Code, include this CDDL HEADER in each
148275SEric Cheng  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158275SEric Cheng  * If applicable, add the following below this CDDL HEADER, with the
168275SEric Cheng  * fields enclosed by brackets "[]" replaced with your own identifying
178275SEric Cheng  * information: Portions Copyright [yyyy] [name of copyright owner]
188275SEric Cheng  *
198275SEric Cheng  * CDDL HEADER END
208275SEric Cheng  */
218275SEric Cheng 
228275SEric Cheng /*
23*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
248275SEric Cheng  * Use is subject to license terms.
258275SEric Cheng  */
268275SEric Cheng 
278275SEric Cheng #include <fcntl.h>
288275SEric Cheng #include <stdlib.h>
298275SEric Cheng #include <strings.h>
308275SEric Cheng #include <exacct.h>
319107Sjames.d.carlson@sun.com #include <net/if.h>
3210491SRishi.Srivatsavai@Sun.COM #include <sys/ethernet.h>
338275SEric Cheng #include <libdladm.h>
348275SEric Cheng 
358275SEric Cheng #define	TIMEBUFLEN	20
368275SEric Cheng #define	GBIT		1000000000
378275SEric Cheng #define	MBIT		1000000
388275SEric Cheng #define	KBIT		1000
398275SEric Cheng 
408275SEric Cheng #define	NET_RESET_TOT(tbytes, ttime, tibytes, tobytes, step) {	\
418275SEric Cheng 	(step) = 1;						\
428275SEric Cheng 	(tbytes) = 0;						\
438275SEric Cheng 	(ttime) = 0;						\
448275SEric Cheng 	(tibytes) = 0;						\
458275SEric Cheng 	(tobytes) = 0;						\
468275SEric Cheng 	}
478275SEric Cheng 
488275SEric Cheng /* Flow/Link Descriptor */
498275SEric Cheng typedef struct net_desc_s {
508275SEric Cheng 	char		net_desc_name[LIFNAMSIZ];
518275SEric Cheng 	char		net_desc_devname[LIFNAMSIZ];
528275SEric Cheng 	uchar_t		net_desc_ehost[ETHERADDRL];
538275SEric Cheng 	uchar_t		net_desc_edest[ETHERADDRL];
548275SEric Cheng 	ushort_t	net_desc_vlan_tpid;
558275SEric Cheng 	ushort_t	net_desc_vlan_tci;
568275SEric Cheng 	ushort_t	net_desc_sap;
578275SEric Cheng 	ushort_t	net_desc_cpuid;
588275SEric Cheng 	ushort_t	net_desc_priority;
598275SEric Cheng 	uint64_t	net_desc_bw_limit;
608275SEric Cheng 	in6_addr_t	net_desc_saddr;
618275SEric Cheng 	in6_addr_t	net_desc_daddr;
628275SEric Cheng 	boolean_t	net_desc_isv4;
638275SEric Cheng 	in_port_t	net_desc_sport;
648275SEric Cheng 	in_port_t	net_desc_dport;
658275SEric Cheng 	uint8_t		net_desc_protocol;
668275SEric Cheng 	uint8_t		net_desc_dsfield;
678275SEric Cheng 	boolean_t	net_desc_newrec;
688275SEric Cheng } net_desc_t;
698275SEric Cheng 
708275SEric Cheng /* Time structure: Year, Month, Day, Hour, Min, Sec */
718275SEric Cheng typedef struct net_time_s {
728275SEric Cheng 	int	net_time_yr;
738275SEric Cheng 	int	net_time_mon;
748275SEric Cheng 	int	net_time_day;
758275SEric Cheng 	int	net_time_hr;
768275SEric Cheng 	int	net_time_min;
778275SEric Cheng 	int	net_time_sec;
788275SEric Cheng } net_time_t;
798275SEric Cheng 
808275SEric Cheng /* Flow/Link Stats */
818275SEric Cheng typedef struct net_stat_s {
828275SEric Cheng 	char			net_stat_name[LIFNAMSIZ];
838275SEric Cheng 	uint64_t		net_stat_ibytes;
848275SEric Cheng 	uint64_t		net_stat_obytes;
858275SEric Cheng 	uint64_t		net_stat_ipackets;
868275SEric Cheng 	uint64_t		net_stat_opackets;
878275SEric Cheng 	uint64_t		net_stat_ierrors;
888275SEric Cheng 	uint64_t		net_stat_oerrors;
898275SEric Cheng 	uint64_t		net_stat_tibytes;
908275SEric Cheng 	uint64_t		net_stat_tobytes;
918275SEric Cheng 	uint64_t		net_stat_tipackets;
928275SEric Cheng 	uint64_t		net_stat_topackets;
938275SEric Cheng 	uint64_t		net_stat_tierrors;
948275SEric Cheng 	uint64_t		net_stat_toerrors;
958275SEric Cheng 	uint64_t		net_stat_ctime;
968275SEric Cheng 	uint64_t		net_stat_tdiff;
978275SEric Cheng 	net_time_t		net_stat_time;
988275SEric Cheng 	struct net_stat_s	*net_stat_next;
998275SEric Cheng 	net_desc_t		*net_stat_desc;
1008275SEric Cheng 	boolean_t		net_stat_isref;
1018275SEric Cheng } net_stat_t;
1028275SEric Cheng 
1038275SEric Cheng /* Used to create the [gnu]plot file */
1048275SEric Cheng typedef struct net_plot_entry_s {
1058275SEric Cheng 	char		*net_pe_name;
1068275SEric Cheng 	uint64_t	net_pe_tottime;
1078275SEric Cheng 	uint64_t	net_pe_totbytes;
1088275SEric Cheng 	uint64_t	net_pe_totibytes;
1098275SEric Cheng 	uint64_t	net_pe_totobytes;
1108275SEric Cheng 	uint64_t	net_pe_lasttime;
1118275SEric Cheng } net_plot_entry_t;
1128275SEric Cheng 
1138275SEric Cheng /* Stats entry */
1148275SEric Cheng typedef struct net_entry_s {
1158275SEric Cheng 	net_desc_t		*net_entry_desc;
1168275SEric Cheng 	net_stat_t		*net_entry_shead;
1178275SEric Cheng 	net_stat_t		*net_entry_stail;
1188275SEric Cheng 	int			net_entry_scount;
1198275SEric Cheng 	net_stat_t		*net_entry_sref;
1208275SEric Cheng 	net_stat_t		*net_entry_tstats;
1218275SEric Cheng 	uint64_t		net_entry_ttime;
1228275SEric Cheng 	struct net_entry_s	*net_entry_next;
1238275SEric Cheng } net_entry_t;
1248275SEric Cheng 
1258275SEric Cheng /* Time sorted list */
1268275SEric Cheng typedef struct net_time_entry_s {
1278275SEric Cheng 	net_stat_t	*my_time_stat;
1288275SEric Cheng 	struct net_time_entry_s *net_time_entry_next;
1298275SEric Cheng 	struct net_time_entry_s *net_time_entry_prev;
1308275SEric Cheng } net_time_entry_t;
1318275SEric Cheng 
1328275SEric Cheng /* The parsed table */
1338275SEric Cheng typedef	struct net_table_s {
1348275SEric Cheng 	/* List of stats */
1358275SEric Cheng 	net_entry_t		*net_table_head;
1368275SEric Cheng 	net_entry_t		*net_table_tail;
1378275SEric Cheng 	int			net_entries;
1388275SEric Cheng 
1398275SEric Cheng 	/*
1408275SEric Cheng 	 * Optimization I : List sorted by time, i.e:
1418275SEric Cheng 	 * Time		Resource	..
1428275SEric Cheng 	 * -------------------------------
1438275SEric Cheng 	 * 11.15.10	bge0
1448275SEric Cheng 	 * 11.15.10	ce0
1458275SEric Cheng 	 * 11.15.10	vnic1
1468275SEric Cheng 	 * 11.15.15	bge0
1478275SEric Cheng 	 * 11.15.15	ce0
1488275SEric Cheng 	 * 11.15.15	vnic1
1498275SEric Cheng 	 */
1508275SEric Cheng 	net_time_entry_t	*net_time_head;
1518275SEric Cheng 	net_time_entry_t	*net_time_tail;
1528275SEric Cheng 
1538275SEric Cheng 	/*
1548275SEric Cheng 	 * Optimization II : List sorted by resources
1558275SEric Cheng 	 * Time		Resource	..
1568275SEric Cheng 	 * -------------------------------
1578275SEric Cheng 	 * 11.15.10	bge0
1588275SEric Cheng 	 * 11.15.15	bge0
1598275SEric Cheng 	 * 11.15.10	ce0
1608275SEric Cheng 	 * 11.15.15	ce0
1618275SEric Cheng 	 * 11.15.10	vnic1
1628275SEric Cheng 	 * 11.15.15	vnic1
1638275SEric Cheng 	 */
1648275SEric Cheng 	net_time_entry_t	*net_ctime_head;
1658275SEric Cheng 	net_time_entry_t	*net_ctime_tail;
1668275SEric Cheng 
1678275SEric Cheng 	/* Common to both the above (sorted) lists. */
1688275SEric Cheng 	int			net_time_entries;
1698275SEric Cheng } net_table_t;
1708275SEric Cheng 
1718275SEric Cheng #define	NET_DATE_GREATER	0
1728275SEric Cheng #define	NET_DATE_LESSER		1
1738275SEric Cheng #define	NET_DATE_EQUAL		2
1748275SEric Cheng 
1758275SEric Cheng #define	NET_TIME_GREATER	0
1768275SEric Cheng #define	NET_TIME_LESSER		1
1778275SEric Cheng #define	NET_TIME_EQUAL		2
1788275SEric Cheng 
1798275SEric Cheng #ifndef _LP64
1808275SEric Cheng #define	FMT_UINT64	"%-15llu"
1818275SEric Cheng #else
1828275SEric Cheng #define	FMT_UINT64	"%-15lu"
1838275SEric Cheng #endif
1848275SEric Cheng 
1858275SEric Cheng /*
1868275SEric Cheng  * Given a timebuf of the form M/D/Y,H:M:S break it into individual elements.
1878275SEric Cheng  */
1888275SEric Cheng static void
dissect_time(char * tbuf,net_time_t * nt)1898275SEric Cheng dissect_time(char *tbuf, net_time_t *nt)
1908275SEric Cheng {
1918275SEric Cheng 	char	*d;
1928275SEric Cheng 	char	*t;
1938275SEric Cheng 	char	*dd;
1948275SEric Cheng 	char	*h;
1958275SEric Cheng 	char	*endp;
1968275SEric Cheng 
1978275SEric Cheng 	if (tbuf == NULL || nt == NULL)
1988275SEric Cheng 		return;
1998275SEric Cheng 
2008275SEric Cheng 	d = strtok(tbuf, ",");	/* Date */
2018275SEric Cheng 	t = strtok(NULL, ",");	/* Time */
2028275SEric Cheng 
2038275SEric Cheng 	/* Month */
2048275SEric Cheng 	dd = strtok(d, "/");
2058275SEric Cheng 	if (dd == NULL)
2068275SEric Cheng 		return;
2078275SEric Cheng 	nt->net_time_mon = strtol(dd, &endp, 10);
2088275SEric Cheng 
2098275SEric Cheng 	/* Day */
2108275SEric Cheng 	dd = strtok(NULL, "/");
2118275SEric Cheng 	if (dd == NULL)
2128275SEric Cheng 		return;
2138275SEric Cheng 	nt->net_time_day = strtol(dd, &endp, 10);
2148275SEric Cheng 
2158275SEric Cheng 	/* Year */
2168275SEric Cheng 	dd = strtok(NULL, "/");
2178275SEric Cheng 	if (dd == NULL)
2188275SEric Cheng 		return;
2198275SEric Cheng 	nt->net_time_yr = strtol(dd, &endp, 10);
2208275SEric Cheng 	if (strlen(dd) <= 2)
2218275SEric Cheng 		nt->net_time_yr += 2000;
2228275SEric Cheng 
2238275SEric Cheng 	if (t == NULL)
2248275SEric Cheng 		return;
2258275SEric Cheng 
2268275SEric Cheng 	/* Hour */
2278275SEric Cheng 	h = strtok(t, ":");
2288275SEric Cheng 	if (h == NULL)
2298275SEric Cheng 		return;
2308275SEric Cheng 	nt->net_time_hr = strtol(h, &endp, 10);
2318275SEric Cheng 
2328275SEric Cheng 	/* Min */
2338275SEric Cheng 	h = strtok(NULL, ":");
2348275SEric Cheng 	if (h == NULL)
2358275SEric Cheng 		return;
2368275SEric Cheng 	nt->net_time_min = strtol(h, &endp, 10);
2378275SEric Cheng 
2388275SEric Cheng 	/* Sec */
2398275SEric Cheng 	h = strtok(NULL, ":");
2408275SEric Cheng 	if (h == NULL)
2418275SEric Cheng 		return;
2428275SEric Cheng 	nt->net_time_sec = strtol(h, &endp, 10);
2438275SEric Cheng }
2448275SEric Cheng 
2458275SEric Cheng /* Get a stat item from an object in the exacct file */
2468275SEric Cheng static void
add_stat_item(ea_object_t * o,net_stat_t * ns)2478275SEric Cheng add_stat_item(ea_object_t *o, net_stat_t *ns)
2488275SEric Cheng {
2498275SEric Cheng 	switch (o->eo_catalog & EXT_TYPE_MASK) {
2508275SEric Cheng 	case EXT_STRING:
2518275SEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_STATS_NAME) {
2528275SEric Cheng 			(void) strncpy(ns->net_stat_name, o->eo_item.ei_string,
2538275SEric Cheng 			    strlen(o->eo_item.ei_string));
2548275SEric Cheng 		}
2558275SEric Cheng 		break;
2568275SEric Cheng 	case EXT_UINT64:
2578275SEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_STATS_CURTIME) {
2588275SEric Cheng 			time_t	_time;
2598275SEric Cheng 			char	timebuf[TIMEBUFLEN];
2608275SEric Cheng 
2618275SEric Cheng 			ns->net_stat_ctime = o->eo_item.ei_uint64;
2628275SEric Cheng 			_time = ns->net_stat_ctime;
2638275SEric Cheng 			(void) strftime(timebuf, sizeof (timebuf),
2648275SEric Cheng 			    "%m/%d/%Y,%T\n", localtime(&_time));
2658275SEric Cheng 			dissect_time(timebuf, &ns->net_stat_time);
2668275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
2678275SEric Cheng 		    EXD_NET_STATS_IBYTES) {
2688275SEric Cheng 			ns->net_stat_ibytes = o->eo_item.ei_uint64;
2698275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
2708275SEric Cheng 		    EXD_NET_STATS_OBYTES) {
2718275SEric Cheng 			ns->net_stat_obytes = o->eo_item.ei_uint64;
2728275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
2738275SEric Cheng 		    EXD_NET_STATS_IPKTS) {
2748275SEric Cheng 			ns->net_stat_ipackets = o->eo_item.ei_uint64;
2758275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
2768275SEric Cheng 		    EXD_NET_STATS_OPKTS) {
2778275SEric Cheng 			ns->net_stat_opackets = o->eo_item.ei_uint64;
2788275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
2798275SEric Cheng 		    EXD_NET_STATS_IERRPKTS) {
2808275SEric Cheng 			ns->net_stat_ierrors = o->eo_item.ei_uint64;
2818275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
2828275SEric Cheng 		    EXD_NET_STATS_OERRPKTS) {
2838275SEric Cheng 			ns->net_stat_oerrors = o->eo_item.ei_uint64;
2848275SEric Cheng 		}
2858275SEric Cheng 		break;
2868275SEric Cheng 	default:
2878275SEric Cheng 		break;
2888275SEric Cheng 	}
2898275SEric Cheng }
2908275SEric Cheng 
2918275SEric Cheng /* Get a description item from an object in the exacct file */
2928275SEric Cheng static void
add_desc_item(ea_object_t * o,net_desc_t * nd)2938275SEric Cheng add_desc_item(ea_object_t *o, net_desc_t *nd)
2948275SEric Cheng {
2958275SEric Cheng 	switch (o->eo_catalog & EXT_TYPE_MASK) {
2968275SEric Cheng 	case EXT_STRING:
2978275SEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_NAME) {
2988275SEric Cheng 			(void) strncpy(nd->net_desc_name, o->eo_item.ei_string,
2998275SEric Cheng 			    strlen(o->eo_item.ei_string));
3008275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
3018275SEric Cheng 		    EXD_NET_DESC_DEVNAME) {
3028275SEric Cheng 			(void) strncpy(nd->net_desc_devname,
3038275SEric Cheng 			    o->eo_item.ei_string, strlen(o->eo_item.ei_string));
3048275SEric Cheng 		}
3058275SEric Cheng 		break;
3068275SEric Cheng 	case EXT_UINT8:
3078275SEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_PROTOCOL) {
3088275SEric Cheng 			nd->net_desc_protocol = o->eo_item.ei_uint8;
3098275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
3108275SEric Cheng 		    EXD_NET_DESC_DSFIELD) {
3118275SEric Cheng 			nd->net_desc_dsfield = o->eo_item.ei_uint8;
3128275SEric Cheng 		}
3138275SEric Cheng 		break;
3148275SEric Cheng 	case EXT_UINT16:
3158275SEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_SPORT) {
3168275SEric Cheng 			nd->net_desc_sport = o->eo_item.ei_uint16;
3178275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
3188275SEric Cheng 		    EXD_NET_DESC_DPORT) {
3198275SEric Cheng 			nd->net_desc_dport = o->eo_item.ei_uint16;
3208275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
3218275SEric Cheng 		    EXD_NET_DESC_SAP) {
3228275SEric Cheng 			nd->net_desc_sap = o->eo_item.ei_uint16;
3238275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
3248275SEric Cheng 		    EXD_NET_DESC_VLAN_TPID) {
3258275SEric Cheng 			nd->net_desc_vlan_tpid = o->eo_item.ei_uint16;
3268275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
3278275SEric Cheng 		    EXD_NET_DESC_VLAN_TCI) {
3288275SEric Cheng 			nd->net_desc_vlan_tci = o->eo_item.ei_uint16;
3298275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
3308275SEric Cheng 		    EXD_NET_DESC_PRIORITY) {
3318275SEric Cheng 			nd->net_desc_priority = o->eo_item.ei_uint16;
3328275SEric Cheng 		}
3338275SEric Cheng 		break;
3348275SEric Cheng 	case EXT_UINT32:
3358275SEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_V4SADDR ||
3368275SEric Cheng 		    (o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_V4DADDR) {
3378275SEric Cheng 				struct in_addr	addr;
3388275SEric Cheng 
3398275SEric Cheng 				addr.s_addr = htonl(o->eo_item.ei_uint32);
3408275SEric Cheng 
3418275SEric Cheng 				if ((o->eo_catalog & EXD_DATA_MASK) ==
3428275SEric Cheng 				    EXD_NET_DESC_V4SADDR) {
3438275SEric Cheng 					IN6_INADDR_TO_V4MAPPED(&addr,
3448275SEric Cheng 					    &nd->net_desc_saddr);
3458275SEric Cheng 				} else {
3468275SEric Cheng 					IN6_INADDR_TO_V4MAPPED(&addr,
3478275SEric Cheng 					    &nd->net_desc_daddr);
3488275SEric Cheng 				}
3498275SEric Cheng 		}
3508275SEric Cheng 		break;
3518275SEric Cheng 	case EXT_UINT64:
3528275SEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_BWLIMIT)
3538275SEric Cheng 			nd->net_desc_bw_limit = o->eo_item.ei_uint64;
3548275SEric Cheng 		break;
3558275SEric Cheng 	case EXT_RAW:
3568275SEric Cheng 		if ((o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_V6SADDR ||
3578275SEric Cheng 		    (o->eo_catalog & EXD_DATA_MASK) == EXD_NET_DESC_V6DADDR) {
3588275SEric Cheng 			in6_addr_t	addr;
3598275SEric Cheng 
3608275SEric Cheng 			addr = *(in6_addr_t *)o->eo_item.ei_raw;
3618275SEric Cheng 			if ((o->eo_catalog & EXD_DATA_MASK) ==
3628275SEric Cheng 			    EXD_NET_DESC_V6SADDR) {
3638275SEric Cheng 				nd->net_desc_saddr = addr;
3648275SEric Cheng 			} else {
3658275SEric Cheng 				nd->net_desc_daddr = addr;
3668275SEric Cheng 			}
3678275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
3688275SEric Cheng 		    EXD_NET_DESC_EHOST) {
3698275SEric Cheng 			bcopy((uchar_t *)o->eo_item.ei_raw, nd->net_desc_ehost,
3708275SEric Cheng 			    ETHERADDRL);
3718275SEric Cheng 		} else if ((o->eo_catalog & EXD_DATA_MASK) ==
3728275SEric Cheng 		    EXD_NET_DESC_EDEST) {
3738275SEric Cheng 			bcopy((uchar_t *)o->eo_item.ei_raw, nd->net_desc_edest,
3748275SEric Cheng 			    ETHERADDRL);
3758275SEric Cheng 		}
3768275SEric Cheng 		break;
3778275SEric Cheng 	default:
3788275SEric Cheng 		break;
3798275SEric Cheng 	}
3808275SEric Cheng }
3818275SEric Cheng 
3828275SEric Cheng /* Add a description item to the table */
3838275SEric Cheng static dladm_status_t
add_desc_to_tbl(net_table_t * net_table,net_desc_t * nd)3848275SEric Cheng add_desc_to_tbl(net_table_t *net_table, net_desc_t *nd)
3858275SEric Cheng {
3868275SEric Cheng 	net_entry_t	*ne;
3878275SEric Cheng 
3888275SEric Cheng 	if ((ne = calloc(1, sizeof (net_entry_t))) == NULL)
3898275SEric Cheng 		return (DLADM_STATUS_NOMEM);
3908275SEric Cheng 
3918275SEric Cheng 	if ((ne->net_entry_tstats = calloc(1, sizeof (net_stat_t))) == NULL) {
3928275SEric Cheng 		free(ne);
3938275SEric Cheng 		return (DLADM_STATUS_NOMEM);
3948275SEric Cheng 	}
3958275SEric Cheng 
3968275SEric Cheng 	ne->net_entry_desc = nd;
3978275SEric Cheng 	ne->net_entry_shead = NULL;
3988275SEric Cheng 	ne->net_entry_stail = NULL;
3998275SEric Cheng 	ne->net_entry_scount = 0;
4008275SEric Cheng 
4018275SEric Cheng 	if (net_table->net_table_head == NULL) {
4028275SEric Cheng 		net_table->net_table_head = ne;
4038275SEric Cheng 		net_table->net_table_tail = ne;
4048275SEric Cheng 	} else {
4058275SEric Cheng 		net_table->net_table_tail->net_entry_next = ne;
4068275SEric Cheng 		net_table->net_table_tail = ne;
4078275SEric Cheng 	}
4088275SEric Cheng 	net_table->net_entries++;
4098275SEric Cheng 	return (DLADM_STATUS_OK);
4108275SEric Cheng }
4118275SEric Cheng 
4128275SEric Cheng /* Compare dates and return if t1 is equal, greater or lesser than t2 */
4138275SEric Cheng static int
compare_date(net_time_t * t1,net_time_t * t2)4148275SEric Cheng compare_date(net_time_t *t1, net_time_t *t2)
4158275SEric Cheng {
4168275SEric Cheng 	if (t1->net_time_yr == t2->net_time_yr &&
4178275SEric Cheng 	    t1->net_time_mon == t2->net_time_mon &&
4188275SEric Cheng 	    t1->net_time_day == t2->net_time_day) {
4198275SEric Cheng 		return (NET_DATE_EQUAL);
4208275SEric Cheng 	}
4218275SEric Cheng 	if (t1->net_time_yr > t2->net_time_yr ||
4228275SEric Cheng 	    (t1->net_time_yr == t2->net_time_yr &&
4238275SEric Cheng 	    t1->net_time_mon > t2->net_time_mon) ||
4248275SEric Cheng 	    (t1->net_time_yr == t2->net_time_yr &&
4258275SEric Cheng 	    t1->net_time_mon == t2->net_time_mon &&
4268275SEric Cheng 	    t1->net_time_day > t2->net_time_day)) {
4278275SEric Cheng 		return (NET_DATE_GREATER);
4288275SEric Cheng 	}
4298275SEric Cheng 	return (NET_DATE_LESSER);
4308275SEric Cheng }
4318275SEric Cheng 
4328275SEric Cheng /* Compare times and return if t1 is equal, greater or lesser than t2 */
4338275SEric Cheng static int
compare_time(net_time_t * t1,net_time_t * t2)4348275SEric Cheng compare_time(net_time_t *t1, net_time_t *t2)
4358275SEric Cheng {
4368275SEric Cheng 	int	cd;
4378275SEric Cheng 
4388275SEric Cheng 	cd = compare_date(t1, t2);
4398275SEric Cheng 
4408275SEric Cheng 	if (cd == NET_DATE_GREATER) {
4418275SEric Cheng 		return (NET_TIME_GREATER);
4428275SEric Cheng 	} else if (cd == NET_DATE_LESSER) {
4438275SEric Cheng 		return (NET_TIME_LESSER);
4448275SEric Cheng 	} else {
4458275SEric Cheng 		if (t1->net_time_hr == t2->net_time_hr &&
4468275SEric Cheng 		    t1->net_time_min == t2->net_time_min &&
4478275SEric Cheng 		    t1->net_time_sec == t2->net_time_sec) {
4488275SEric Cheng 			return (NET_TIME_EQUAL);
4498275SEric Cheng 		}
4508275SEric Cheng 		if (t1->net_time_hr > t2->net_time_hr ||
4518275SEric Cheng 		    (t1->net_time_hr == t2->net_time_hr &&
4528275SEric Cheng 		    t1->net_time_min > t2->net_time_min) ||
4538275SEric Cheng 		    (t1->net_time_hr == t2->net_time_hr &&
4548275SEric Cheng 		    t1->net_time_min == t2->net_time_min &&
4558275SEric Cheng 		    t1->net_time_sec > t2->net_time_sec)) {
4568275SEric Cheng 			return (NET_TIME_GREATER);
4578275SEric Cheng 		}
4588275SEric Cheng 	}
4598275SEric Cheng 	return (NET_TIME_LESSER);
4608275SEric Cheng }
4618275SEric Cheng 
4628275SEric Cheng /*
4638275SEric Cheng  * Given a start and end time and start and end entries check if the
4648275SEric Cheng  * times are within the range, and adjust, if needed.
4658275SEric Cheng  */
4668275SEric Cheng static dladm_status_t
chk_time_bound(net_time_t * s,net_time_t * e,net_time_t * sns,net_time_t * ens)4678275SEric Cheng chk_time_bound(net_time_t *s, net_time_t *e,  net_time_t *sns,
4688275SEric Cheng     net_time_t *ens)
4698275SEric Cheng {
4708275SEric Cheng 	if (s != NULL && e != NULL) {
4718275SEric Cheng 		if (compare_time(s, e) == NET_TIME_GREATER)
4728275SEric Cheng 			return (DLADM_STATUS_BADTIMEVAL);
4738275SEric Cheng 	}
4748275SEric Cheng 	if (s != NULL) {
4758275SEric Cheng 		if (compare_time(s, sns) == NET_TIME_LESSER) {
4768275SEric Cheng 			s->net_time_yr = sns->net_time_yr;
4778275SEric Cheng 			s->net_time_mon = sns->net_time_mon;
4788275SEric Cheng 			s->net_time_day = sns->net_time_day;
4798275SEric Cheng 			s->net_time_hr = sns->net_time_hr;
4808275SEric Cheng 			s->net_time_min = sns->net_time_min;
4818275SEric Cheng 			s->net_time_sec = sns->net_time_sec;
4828275SEric Cheng 		}
4838275SEric Cheng 	}
4848275SEric Cheng 	if (e != NULL) {
4858275SEric Cheng 		if (compare_time(e, ens) == NET_TIME_GREATER) {
4868275SEric Cheng 			e->net_time_yr = ens->net_time_yr;
4878275SEric Cheng 			e->net_time_mon = ens->net_time_mon;
4888275SEric Cheng 			e->net_time_day = ens->net_time_day;
4898275SEric Cheng 			e->net_time_hr = ens->net_time_hr;
4908275SEric Cheng 			e->net_time_min = ens->net_time_min;
4918275SEric Cheng 			e->net_time_sec = ens->net_time_sec;
4928275SEric Cheng 		}
4938275SEric Cheng 	}
4948275SEric Cheng 	return (DLADM_STATUS_OK);
4958275SEric Cheng }
4968275SEric Cheng 
4978275SEric Cheng /*
4988275SEric Cheng  * Given a start and end time (strings), convert them into net_time_t
4998275SEric Cheng  * and also check for the range given the head and tail of the list.
5008275SEric Cheng  * If stime is lower then head or etime is greated than tail, adjust.
5018275SEric Cheng  */
5028275SEric 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)5038275SEric Cheng get_time_range(net_time_entry_t *head, net_time_entry_t *tail,
5048275SEric Cheng     net_time_t *st, net_time_t *et, char *stime, char *etime)
5058275SEric Cheng {
5068275SEric Cheng 	bzero(st, sizeof (net_time_t));
5078275SEric Cheng 	bzero(et, sizeof (net_time_t));
5088275SEric Cheng 
5098275SEric Cheng 	if (stime == NULL && etime == NULL)
5108275SEric Cheng 		return (0);
5118275SEric Cheng 
5128275SEric Cheng 	if (stime != NULL)
5138275SEric Cheng 		dissect_time(stime, st);
5148275SEric Cheng 	if (etime != NULL)
5158275SEric Cheng 		dissect_time(etime, et);
5168275SEric Cheng 
5178275SEric Cheng 	if (stime != NULL || etime != NULL) {
5188275SEric Cheng 		return (chk_time_bound(stime == NULL ? NULL : st,
5198275SEric Cheng 		    etime == NULL ? NULL : et,
5208275SEric Cheng 		    &head->my_time_stat->net_stat_time,
5218275SEric Cheng 		    &tail->my_time_stat->net_stat_time));
5228275SEric Cheng 	}
5238275SEric Cheng 	return (0);
5248275SEric Cheng }
5258275SEric Cheng 
5268275SEric Cheng /*
5278275SEric Cheng  * Walk the list from a given starting point and return when we find
5288275SEric Cheng  * an entry that is greater or equal to st. lasttime will point to the
5298275SEric Cheng  * previous time entry.
5308275SEric Cheng  */
5318275SEric 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)5328275SEric Cheng get_starting_point(net_time_entry_t *head, net_time_entry_t **start,
5338275SEric Cheng     net_time_t *st, char *stime, uint64_t *lasttime)
5348275SEric Cheng {
5358275SEric Cheng 	net_time_entry_t	*next = head;
5368275SEric Cheng 
5378275SEric Cheng 	if (head == NULL) {
5388275SEric Cheng 		*start = NULL;
5398275SEric Cheng 		return;
5408275SEric Cheng 	}
5418275SEric Cheng 	if (stime == NULL) {
5428275SEric Cheng 		*start = head;
5438275SEric Cheng 		*lasttime = head->my_time_stat->net_stat_ctime;
5448275SEric Cheng 		return;
5458275SEric Cheng 	}
5468275SEric Cheng 	*start = NULL;
5478275SEric Cheng 	while (next != NULL) {
5488275SEric Cheng 		if (compare_time(st,
5498275SEric Cheng 		    &next->my_time_stat->net_stat_time) != NET_TIME_LESSER) {
5508275SEric Cheng 			*lasttime = next->my_time_stat->net_stat_ctime;
5518275SEric Cheng 			next = next->net_time_entry_next;
5528275SEric Cheng 			continue;
5538275SEric Cheng 		}
5548275SEric Cheng 		*start = next;
5558275SEric Cheng 		break;
5568275SEric Cheng 	}
5578275SEric Cheng }
5588275SEric Cheng 
5598275SEric Cheng /*
5608275SEric Cheng  * Point entry (pe) functions
5618275SEric Cheng  */
5628275SEric Cheng /* Clear all the counters. Done after the contents are written to the file */
5638275SEric Cheng static void
clear_pe(net_plot_entry_t * pe,int entries,int * pentries)5648275SEric Cheng clear_pe(net_plot_entry_t *pe, int entries, int *pentries)
5658275SEric Cheng {
5668275SEric Cheng 	int	count;
5678275SEric Cheng 
5688275SEric Cheng 	for (count = 0; count < entries; count++) {
5698275SEric Cheng 		pe[count].net_pe_totbytes = 0;
5708275SEric Cheng 		pe[count].net_pe_totibytes = 0;
5718275SEric Cheng 		pe[count].net_pe_totobytes = 0;
5728275SEric Cheng 		pe[count].net_pe_tottime = 0;
5738275SEric Cheng 	}
5748275SEric Cheng 	*pentries = 0;
5758275SEric Cheng }
5768275SEric Cheng 
5778275SEric Cheng /* Update an entry in the point entry table */
5788275SEric Cheng static void
update_pe(net_plot_entry_t * pe,net_stat_t * nns,int nentries,int * pentries,uint64_t lasttime)5798275SEric Cheng update_pe(net_plot_entry_t *pe, net_stat_t *nns, int nentries,
5808275SEric Cheng     int *pentries, uint64_t lasttime)
5818275SEric Cheng {
5828275SEric Cheng 	int	count;
5838275SEric Cheng 
5848275SEric Cheng 	for (count = 0; count < nentries; count++) {
5858833SVenu.Iyer@Sun.COM 		if (strcmp(pe[count].net_pe_name, nns->net_stat_name) == 0)
5868275SEric Cheng 			break;
5878275SEric Cheng 	}
5888275SEric Cheng 	if (count == nentries)
5898275SEric Cheng 		return;
5908275SEric Cheng 
5918275SEric Cheng 	if (pe[count].net_pe_totbytes == 0)
5928275SEric Cheng 		pe[count].net_pe_lasttime = lasttime;
5938275SEric Cheng 
5948275SEric Cheng 	pe[count].net_pe_totbytes += nns->net_stat_ibytes +
5958275SEric Cheng 	    nns->net_stat_obytes;
5968275SEric Cheng 	pe[count].net_pe_tottime += nns->net_stat_tdiff;
5978275SEric Cheng 	pe[count].net_pe_totibytes += nns->net_stat_ibytes;
5988275SEric Cheng 	pe[count].net_pe_totobytes += nns->net_stat_obytes;
5998275SEric Cheng 	(*pentries)++;
6008275SEric Cheng }
6018275SEric Cheng 
6028275SEric Cheng /* Flush the contents of the point entry table to the file. */
6038275SEric 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)6048275SEric Cheng add_pe_to_file(int (*fn)(dladm_usage_t *, void *), net_plot_entry_t *pe,
6058275SEric Cheng     net_stat_t *ns, int entries, void *arg)
6068275SEric Cheng {
6078275SEric Cheng 	int		count;
6088275SEric Cheng 	dladm_usage_t	usage;
6098275SEric Cheng 	uint64_t	tottime;
6108275SEric Cheng 
6118275SEric Cheng 	bcopy(&ns->net_stat_ctime, &usage.du_etime, sizeof (usage.du_etime));
6128275SEric Cheng 	for (count = 0; count < entries; count++) {
6138275SEric Cheng 		bcopy(pe[count].net_pe_name, &usage.du_name,
6148275SEric Cheng 		    sizeof (usage.du_name));
6158275SEric Cheng 		bcopy(&pe[count].net_pe_lasttime, &usage.du_stime,
6168275SEric Cheng 		    sizeof (usage.du_stime));
6178275SEric Cheng 		usage.du_rbytes = pe[count].net_pe_totibytes;
6188275SEric Cheng 		usage.du_obytes = pe[count].net_pe_totobytes;
6198275SEric Cheng 		tottime = pe[count].net_pe_tottime;
6208275SEric Cheng 		usage.du_bandwidth = (tottime > 0) ?
6218275SEric Cheng 		    ((pe[count].net_pe_totbytes * 8) / tottime) : 0;
6228275SEric Cheng 		usage.du_last = (count == entries-1);
6238275SEric Cheng 		fn(&usage, arg);
6248275SEric Cheng 	}
6258275SEric Cheng }
6268275SEric Cheng 
6278275SEric Cheng /*
6288275SEric Cheng  * Net entry functions
6298275SEric Cheng  */
6308275SEric Cheng static net_entry_t *
get_ne_from_table(net_table_t * net_table,char * name)6318275SEric Cheng get_ne_from_table(net_table_t *net_table, char *name)
6328275SEric Cheng {
6338275SEric Cheng 	int		count;
6348275SEric Cheng 	net_desc_t	*nd;
6358275SEric Cheng 	net_entry_t	*ne = net_table->net_table_head;
6368275SEric Cheng 
6378275SEric Cheng 	for (count = 0; count < net_table->net_entries; count++) {
6388275SEric Cheng 		nd = ne->net_entry_desc;
6398833SVenu.Iyer@Sun.COM 		if (strcmp(name, nd->net_desc_name) == 0)
6408275SEric Cheng 			return (ne);
6418275SEric Cheng 		ne = ne->net_entry_next;
6428275SEric Cheng 	}
6438275SEric Cheng 	return (NULL);
6448275SEric Cheng }
6458275SEric Cheng 
6468275SEric Cheng /*  Get the entry for the descriptor, if it exists */
6478275SEric Cheng static net_desc_t *
get_ndesc(net_table_t * net_table,net_desc_t * nd)6488275SEric Cheng get_ndesc(net_table_t *net_table, net_desc_t *nd)
6498275SEric Cheng {
6508275SEric Cheng 	int		count;
6518275SEric Cheng 	net_desc_t	*nd1;
6528275SEric Cheng 	net_entry_t	*ne = net_table->net_table_head;
6538275SEric Cheng 
6548275SEric Cheng 	for (count = 0; count < net_table->net_entries; count++) {
6558275SEric Cheng 		nd1 = ne->net_entry_desc;
6568833SVenu.Iyer@Sun.COM 		if (strcmp(nd1->net_desc_name, nd->net_desc_name) == 0 &&
6578833SVenu.Iyer@Sun.COM 		    strcmp(nd1->net_desc_devname, nd->net_desc_devname) == 0 &&
6588275SEric Cheng 		    bcmp(nd1->net_desc_ehost, nd->net_desc_ehost,
6598275SEric Cheng 		    ETHERADDRL) == 0 &&
6608275SEric Cheng 		    bcmp(nd1->net_desc_edest, nd->net_desc_edest,
6618275SEric Cheng 		    ETHERADDRL) == 0 &&
6628275SEric Cheng 		    nd1->net_desc_vlan_tpid == nd->net_desc_vlan_tpid &&
6638275SEric Cheng 		    nd1->net_desc_vlan_tci == nd->net_desc_vlan_tci &&
6648275SEric Cheng 		    nd1->net_desc_sap == nd->net_desc_sap &&
6658275SEric Cheng 		    nd1->net_desc_cpuid == nd->net_desc_cpuid &&
6668275SEric Cheng 		    nd1->net_desc_priority == nd->net_desc_priority &&
6678275SEric Cheng 		    nd1->net_desc_bw_limit == nd->net_desc_bw_limit &&
6688275SEric Cheng 		    nd1->net_desc_sport == nd->net_desc_sport &&
6698275SEric Cheng 		    nd1->net_desc_dport == nd->net_desc_dport &&
6708275SEric Cheng 		    nd1->net_desc_protocol == nd->net_desc_protocol &&
6718275SEric Cheng 		    nd1->net_desc_dsfield == nd->net_desc_dsfield &&
6728275SEric Cheng 		    IN6_ARE_ADDR_EQUAL(&nd1->net_desc_saddr,
6738275SEric Cheng 		    &nd->net_desc_saddr) &&
6748275SEric Cheng 		    IN6_ARE_ADDR_EQUAL(&nd1->net_desc_daddr,
6758275SEric Cheng 		    &nd->net_desc_daddr)) {
6768275SEric Cheng 			return (nd1);
6778275SEric Cheng 		}
6788275SEric Cheng 		ne = ne->net_entry_next;
6798275SEric Cheng 	}
6808275SEric Cheng 	return (NULL);
6818275SEric Cheng }
6828275SEric Cheng 
6838275SEric Cheng /*
6848275SEric Cheng  * Update the stat entries. The stats in the file are cumulative, so in order
6858275SEric Cheng  * to have increments, we maintain a reference stat entry, which contains
6868275SEric Cheng  * the stats when the record was first written and a total stat entry, which
6878275SEric Cheng  * maintains the running count. When we want to add a stat entry, if it
6888275SEric Cheng  * the reference stat entry, we don't come here. For subsequent entries,
6898275SEric Cheng  * we get the increment by subtracting the current value from the reference
6908275SEric Cheng  * stat and the total stat.
6918275SEric Cheng  */
6928275SEric Cheng static void
update_stats(net_stat_t * ns1,net_entry_t * ne,net_stat_t * ref)6938275SEric Cheng update_stats(net_stat_t *ns1, net_entry_t *ne, net_stat_t *ref)
6948275SEric Cheng {
6958275SEric Cheng 
6968275SEric Cheng 	/* get the increment */
6978275SEric Cheng 	ns1->net_stat_ibytes -= (ref->net_stat_ibytes + ref->net_stat_tibytes);
6988275SEric Cheng 	ns1->net_stat_obytes -= (ref->net_stat_obytes + ref->net_stat_tobytes);
6998275SEric Cheng 	ns1->net_stat_ipackets -= (ref->net_stat_ipackets +
7008275SEric Cheng 	    ref->net_stat_tipackets);
7018275SEric Cheng 	ns1->net_stat_opackets -= (ref->net_stat_opackets +
7028275SEric Cheng 	    ref->net_stat_topackets);
7038275SEric Cheng 	ns1->net_stat_ierrors -= (ref->net_stat_ierrors +
7048275SEric Cheng 	    ref->net_stat_tierrors);
7058275SEric Cheng 	ns1->net_stat_oerrors -= (ref->net_stat_oerrors +
7068275SEric Cheng 	    ref->net_stat_toerrors);
7078275SEric Cheng 
7088275SEric Cheng 	/* update total bytes */
7098275SEric Cheng 	ref->net_stat_tibytes += ns1->net_stat_ibytes;
7108275SEric Cheng 	ref->net_stat_tobytes += ns1->net_stat_obytes;
7118275SEric Cheng 	ref->net_stat_tipackets += ns1->net_stat_ipackets;
7128275SEric Cheng 	ref->net_stat_topackets += ns1->net_stat_opackets;
7138275SEric Cheng 	ref->net_stat_tierrors += ns1->net_stat_ierrors;
7148275SEric Cheng 	ref->net_stat_toerrors  += ns1->net_stat_oerrors;
7158275SEric Cheng 
7168275SEric Cheng 	ne->net_entry_tstats->net_stat_ibytes += ns1->net_stat_ibytes;
7178275SEric Cheng 	ne->net_entry_tstats->net_stat_obytes += ns1->net_stat_obytes;
7188275SEric Cheng 	ne->net_entry_tstats->net_stat_ipackets += ns1->net_stat_ipackets;
7198275SEric Cheng 	ne->net_entry_tstats->net_stat_opackets += ns1->net_stat_opackets;
7208275SEric Cheng 	ne->net_entry_tstats->net_stat_ierrors += ns1->net_stat_ierrors;
7218275SEric Cheng 	ne->net_entry_tstats->net_stat_oerrors += ns1->net_stat_oerrors;
7228275SEric Cheng }
7238275SEric Cheng 
7248275SEric Cheng /* Add the stat entry into the table */
7258275SEric Cheng static dladm_status_t
add_stat_to_tbl(net_table_t * net_table,net_stat_t * ns)7268275SEric Cheng add_stat_to_tbl(net_table_t *net_table, net_stat_t *ns)
7278275SEric Cheng {
7288275SEric Cheng 	net_entry_t	*ne;
7298275SEric Cheng 
7308275SEric Cheng 	ne = get_ne_from_table(net_table, ns->net_stat_name);
7318275SEric Cheng 	if (ne == NULL)
7328275SEric Cheng 		return (DLADM_STATUS_NOMEM);
7338275SEric Cheng 
7348275SEric Cheng 	/* Ptr to flow desc */
7358275SEric Cheng 	ns->net_stat_desc = ne->net_entry_desc;
7368275SEric Cheng 	if (ns->net_stat_desc->net_desc_newrec) {
7378275SEric Cheng 		ns->net_stat_desc->net_desc_newrec = B_FALSE;
7388275SEric Cheng 		ns->net_stat_isref = B_TRUE;
7398275SEric Cheng 		ne->net_entry_sref = ns;
7408275SEric Cheng 	} else if (ns->net_stat_ibytes < ne->net_entry_sref->net_stat_tibytes ||
7418275SEric Cheng 	    (ns->net_stat_obytes < ne->net_entry_sref->net_stat_tobytes)) {
7428275SEric Cheng 		ns->net_stat_isref = B_TRUE;
7438275SEric Cheng 		ne->net_entry_sref = ns;
7448275SEric Cheng 	} else {
7458275SEric Cheng 		ns->net_stat_isref = B_FALSE;
7468275SEric Cheng 		update_stats(ns, ne, ne->net_entry_sref);
7478275SEric Cheng 	}
7488275SEric Cheng 	if (ne->net_entry_shead == NULL) {
7498275SEric Cheng 		ne->net_entry_shead = ns;
7508275SEric Cheng 		ne->net_entry_stail = ns;
7518275SEric Cheng 	} else {
7528275SEric Cheng 		if (!ns->net_stat_isref) {
7538275SEric Cheng 			ne->net_entry_ttime += (ns->net_stat_ctime -
7548275SEric Cheng 			    ne->net_entry_stail->net_stat_ctime);
7558275SEric Cheng 			ns->net_stat_tdiff = ns->net_stat_ctime -
7568275SEric Cheng 			    ne->net_entry_stail->net_stat_ctime;
7578275SEric Cheng 		}
7588275SEric Cheng 		ne->net_entry_stail->net_stat_next = ns;
7598275SEric Cheng 		ne->net_entry_stail = ns;
7608275SEric Cheng 	}
7618275SEric Cheng 
7628275SEric Cheng 	ne->net_entry_scount++;
7638275SEric Cheng 	return (DLADM_STATUS_OK);
7648275SEric Cheng }
7658275SEric Cheng 
7668275SEric Cheng /* Add a flow/link descriptor record to the table */
7678275SEric Cheng static dladm_status_t
add_desc(net_table_t * net_table,ea_file_t * ef,int nobjs)7688275SEric Cheng add_desc(net_table_t *net_table, ea_file_t *ef, int nobjs)
7698275SEric Cheng {
7708275SEric Cheng 	net_desc_t	*nd;
7718275SEric Cheng 	net_desc_t	*dnd;
7728275SEric Cheng 	int		count;
7738275SEric Cheng 	ea_object_t	scratch;
7748275SEric Cheng 
7758275SEric Cheng 	if ((nd = calloc(1, sizeof (net_desc_t))) == NULL)
7768275SEric Cheng 		return (DLADM_STATUS_NOMEM);
7778275SEric Cheng 	nd->net_desc_newrec = B_TRUE;
7788275SEric Cheng 
7798275SEric Cheng 	for (count = 0; count < nobjs; count++) {
7808275SEric Cheng 		if (ea_get_object(ef, &scratch) == -1) {
7818275SEric Cheng 			free(nd);
7828275SEric Cheng 			return (DLADM_STATUS_NOMEM);
7838275SEric Cheng 		}
7848275SEric Cheng 		add_desc_item(&scratch, nd);
7858275SEric Cheng 	}
7868275SEric Cheng 	if ((dnd = get_ndesc(net_table, nd)) != NULL) {
7878275SEric Cheng 		dnd->net_desc_newrec = B_TRUE;
7888275SEric Cheng 		free(nd);
7898275SEric Cheng 		return (DLADM_STATUS_OK);
7908275SEric Cheng 	}
7918275SEric Cheng 	if (add_desc_to_tbl(net_table, nd) != 0) {
7928275SEric Cheng 		free(nd);
7938275SEric Cheng 		return (DLADM_STATUS_NOMEM);
7948275SEric Cheng 	}
7958275SEric Cheng 	return (DLADM_STATUS_OK);
7968275SEric Cheng }
7978275SEric Cheng 
7988275SEric Cheng /* Make an entry into the time sorted list */
7998275SEric Cheng static void
addto_time_list(net_table_t * net_table,net_time_entry_t * nt,net_time_entry_t * ntc)8008275SEric Cheng addto_time_list(net_table_t *net_table, net_time_entry_t *nt,
8018275SEric Cheng     net_time_entry_t *ntc)
8028275SEric Cheng {
8038275SEric Cheng 	net_stat_t		*ns = nt->my_time_stat;
8048275SEric Cheng 	net_stat_t		*ns1;
8058275SEric Cheng 	net_time_entry_t	*end;
8068275SEric Cheng 	net_time_t		*t1;
8078275SEric Cheng 	int			count;
8088275SEric Cheng 
8098275SEric Cheng 	t1 = &ns->net_stat_time;
8108275SEric Cheng 
8118275SEric Cheng 	net_table->net_time_entries++;
8128275SEric Cheng 
8138275SEric Cheng 	if (net_table->net_time_head == NULL) {
8148275SEric Cheng 		net_table->net_time_head = nt;
8158275SEric Cheng 		net_table->net_time_tail = nt;
8168275SEric Cheng 	} else {
8178275SEric Cheng 		net_table->net_time_tail->net_time_entry_next = nt;
8188275SEric Cheng 		nt->net_time_entry_prev = net_table->net_time_tail;
8198275SEric Cheng 		net_table->net_time_tail = nt;
8208275SEric Cheng 	}
8218275SEric Cheng 
8228275SEric Cheng 	if (net_table->net_ctime_head == NULL) {
8238275SEric Cheng 		net_table->net_ctime_head = ntc;
8248275SEric Cheng 		net_table->net_ctime_tail = ntc;
8258275SEric Cheng 	} else {
8268275SEric Cheng 		end = net_table->net_ctime_tail;
8278275SEric Cheng 		count = 0;
8288275SEric Cheng 		while (count < net_table->net_time_entries - 1) {
8298275SEric Cheng 			ns1 = end->my_time_stat;
8308275SEric Cheng 			/* Just add it to the tail */
8318275SEric Cheng 			if (compare_date(t1, &ns1->net_stat_time) ==
8328275SEric Cheng 			    NET_DATE_GREATER) {
8338275SEric Cheng 				break;
8348275SEric Cheng 			}
8358833SVenu.Iyer@Sun.COM 			if (strcmp(ns1->net_stat_name, ns->net_stat_name) ==
8368833SVenu.Iyer@Sun.COM 			    0) {
8378275SEric Cheng 				ntc->net_time_entry_next =
8388275SEric Cheng 				    end->net_time_entry_next;
8398275SEric Cheng 				if (end->net_time_entry_next != NULL) {
8408275SEric Cheng 					end->net_time_entry_next->
8418275SEric Cheng 					    net_time_entry_prev = ntc;
8428275SEric Cheng 				} else {
8438275SEric Cheng 					net_table->net_ctime_tail = ntc;
8448275SEric Cheng 				}
8458275SEric Cheng 				end->net_time_entry_next = ntc;
8468275SEric Cheng 				ntc->net_time_entry_prev = end;
8478275SEric Cheng 				return;
8488275SEric Cheng 			}
8498275SEric Cheng 			count++;
8508275SEric Cheng 			end = end->net_time_entry_prev;
8518275SEric Cheng 		}
8528275SEric Cheng 		net_table->net_ctime_tail->net_time_entry_next = ntc;
8538275SEric Cheng 		ntc->net_time_entry_prev = net_table->net_ctime_tail;
8548275SEric Cheng 		net_table->net_ctime_tail = ntc;
8558275SEric Cheng 	}
8568275SEric Cheng }
8578275SEric Cheng 
8588275SEric Cheng /* Add stat entry into the lists */
8598275SEric Cheng static dladm_status_t
add_stats(net_table_t * net_table,ea_file_t * ef,int nobjs)8608275SEric Cheng add_stats(net_table_t *net_table, ea_file_t *ef, int nobjs)
8618275SEric Cheng {
8628275SEric Cheng 	net_stat_t		*ns;
8638275SEric Cheng 	int			count;
8648275SEric Cheng 	ea_object_t		scratch;
8658275SEric Cheng 	net_time_entry_t	*nt;
8668275SEric Cheng 	net_time_entry_t	*ntc;
8678275SEric Cheng 
8688275SEric Cheng 	if ((ns = calloc(1, sizeof (net_stat_t))) == NULL)
8698275SEric Cheng 		return (DLADM_STATUS_NOMEM);
8708275SEric Cheng 
8718275SEric Cheng 	if ((nt = calloc(1, sizeof (net_time_entry_t))) == NULL) {
8728275SEric Cheng 		free(ns);
8738275SEric Cheng 		return (DLADM_STATUS_NOMEM);
8748275SEric Cheng 	}
8758275SEric Cheng 	if ((ntc = calloc(1, sizeof (net_time_entry_t))) == NULL) {
8768275SEric Cheng 		free(ns);
8778275SEric Cheng 		free(nt);
8788275SEric Cheng 		return (DLADM_STATUS_NOMEM);
8798275SEric Cheng 	}
8808275SEric Cheng 
8818275SEric Cheng 	nt->my_time_stat = ns;
8828275SEric Cheng 	ntc->my_time_stat = ns;
8838275SEric Cheng 
8848275SEric Cheng 	for (count = 0; count < nobjs; count++) {
8858275SEric Cheng 		if (ea_get_object(ef, &scratch) == -1) {
8868275SEric Cheng 			free(ns);
8878275SEric Cheng 			free(nt);
8888275SEric Cheng 			free(ntc);
8898275SEric Cheng 			return (DLADM_STATUS_NOMEM);
8908275SEric Cheng 		}
8918275SEric Cheng 		add_stat_item(&scratch, ns);
8928275SEric Cheng 	}
8938275SEric Cheng 	if (add_stat_to_tbl(net_table, ns) != 0) {
8948275SEric Cheng 		free(ns);
8958275SEric Cheng 		free(nt);
8968275SEric Cheng 		free(ntc);
8978275SEric Cheng 		return (DLADM_STATUS_NOMEM);
8988275SEric Cheng 	}
8998275SEric Cheng 	addto_time_list(net_table, nt, ntc);
9008275SEric Cheng 	return (DLADM_STATUS_OK);
9018275SEric Cheng }
9028275SEric Cheng 
9038275SEric Cheng /* Free the entire table */
9048275SEric Cheng static void
free_logtable(net_table_t * net_table)9058275SEric Cheng free_logtable(net_table_t *net_table)
9068275SEric Cheng {
9078275SEric Cheng 	net_entry_t		*head;
9088275SEric Cheng 	net_entry_t		*next;
9098275SEric Cheng 	net_stat_t		*ns;
9108275SEric Cheng 	net_stat_t		*ns1;
9118275SEric Cheng 	net_time_entry_t	*thead;
9128275SEric Cheng 	net_time_entry_t	*tnext;
9138275SEric Cheng 
9148275SEric Cheng 	thead = net_table->net_time_head;
9158275SEric Cheng 	while (thead != NULL) {
9168275SEric Cheng 		thead->my_time_stat = NULL;
9178275SEric Cheng 		tnext = thead->net_time_entry_next;
9188275SEric Cheng 		thead->net_time_entry_next = NULL;
9198275SEric Cheng 		thead->net_time_entry_prev = NULL;
9208275SEric Cheng 		free(thead);
9218275SEric Cheng 		thead = tnext;
9228275SEric Cheng 	}
9238275SEric Cheng 	net_table->net_time_head = NULL;
9248275SEric Cheng 	net_table->net_time_tail = NULL;
9258275SEric Cheng 
9268275SEric Cheng 	thead = net_table->net_ctime_head;
9278275SEric Cheng 	while (thead != NULL) {
9288275SEric Cheng 		thead->my_time_stat = NULL;
9298275SEric Cheng 		tnext = thead->net_time_entry_next;
9308275SEric Cheng 		thead->net_time_entry_next = NULL;
9318275SEric Cheng 		thead->net_time_entry_prev = NULL;
9328275SEric Cheng 		free(thead);
9338275SEric Cheng 		thead = tnext;
9348275SEric Cheng 	}
9358275SEric Cheng 	net_table->net_ctime_head = NULL;
9368275SEric Cheng 	net_table->net_ctime_tail = NULL;
9378275SEric Cheng 
9388275SEric Cheng 	net_table->net_time_entries = 0;
9398275SEric Cheng 
9408275SEric Cheng 	head = net_table->net_table_head;
9418275SEric Cheng 	while (head != NULL) {
9428275SEric Cheng 		next = head->net_entry_next;
9438275SEric Cheng 		head->net_entry_next = NULL;
9448275SEric Cheng 		ns = head->net_entry_shead;
9458275SEric Cheng 		while (ns != NULL) {
9468275SEric Cheng 			ns1 = ns->net_stat_next;
9478275SEric Cheng 			free(ns);
9488275SEric Cheng 			ns = ns1;
9498275SEric Cheng 		}
9508275SEric Cheng 		head->net_entry_scount = 0;
9518275SEric Cheng 		head->net_entry_sref = NULL;
9528275SEric Cheng 		free(head->net_entry_desc);
9538275SEric Cheng 		free(head->net_entry_tstats);
9548275SEric Cheng 		free(head);
9558275SEric Cheng 		head = next;
9568275SEric Cheng 	}
9578275SEric Cheng 	net_table->net_table_head = NULL;
9588275SEric Cheng 	net_table->net_table_tail = NULL;
9598275SEric Cheng 	net_table->net_time_entries = 0;
9608275SEric Cheng 	free(net_table);
9618275SEric Cheng }
9628275SEric Cheng 
9638275SEric Cheng /* Parse the exacct file, and return the parsed table. */
9648275SEric Cheng static void *
parse_logfile(char * file,int logtype,dladm_status_t * status)9658275SEric Cheng parse_logfile(char *file, int logtype, dladm_status_t *status)
9668275SEric Cheng {
9678275SEric Cheng 	ea_file_t	ef;
9688275SEric Cheng 	ea_object_t	scratch;
9698275SEric Cheng 	net_table_t	*net_table;
9708275SEric Cheng 
9718275SEric Cheng 	*status = DLADM_STATUS_OK;
9728275SEric Cheng 	if ((net_table = calloc(1, sizeof (net_table_t))) == NULL) {
9738275SEric Cheng 		*status = DLADM_STATUS_NOMEM;
9748275SEric Cheng 		return (NULL);
9758275SEric Cheng 	}
9768275SEric Cheng 	if (ea_open(&ef, file, NULL, 0, O_RDONLY, 0) == -1) {
9778275SEric Cheng 		*status = DLADM_STATUS_BADARG;
9788275SEric Cheng 		free(net_table);
9798275SEric Cheng 		return (NULL);
9808275SEric Cheng 	}
9818275SEric Cheng 	bzero(&scratch, sizeof (ea_object_t));
9828275SEric Cheng 	while (ea_get_object(&ef, &scratch) != -1) {
9838275SEric Cheng 		if (scratch.eo_type != EO_GROUP) {
9848275SEric Cheng 			(void) ea_free_item(&scratch, EUP_ALLOC);
9858275SEric Cheng 			(void) bzero(&scratch, sizeof (ea_object_t));
9868275SEric Cheng 			continue;
9878275SEric Cheng 		}
9888275SEric Cheng 		/* Read Link Desc/Stat records */
9898275SEric Cheng 		if (logtype == DLADM_LOGTYPE_FLOW) {
9908275SEric Cheng 			/* Flow Descriptor */
9918275SEric Cheng 			if ((scratch.eo_catalog &
9928275SEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_FLOW_DESC) {
9938275SEric Cheng 				(void) add_desc(net_table, &ef,
9948275SEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
9958275SEric Cheng 			/* Flow Stats */
9968275SEric Cheng 			} else if ((scratch.eo_catalog &
9978275SEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_FLOW_STATS) {
9988275SEric Cheng 				(void) add_stats(net_table, &ef,
9998275SEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
10008275SEric Cheng 			}
10018275SEric Cheng 		} else if (logtype == DLADM_LOGTYPE_LINK) {
10028275SEric Cheng 			/* Link Descriptor */
10038275SEric Cheng 			if ((scratch.eo_catalog &
10048275SEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_LINK_DESC) {
10058275SEric Cheng 				(void) add_desc(net_table, &ef,
10068275SEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
10078275SEric Cheng 			/* Link Stats */
10088275SEric Cheng 			} else if ((scratch.eo_catalog &
10098275SEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_LINK_STATS) {
10108275SEric Cheng 				(void) add_stats(net_table, &ef,
10118275SEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
10128275SEric Cheng 			}
10138275SEric Cheng 		} else {
10148275SEric Cheng 			if (((scratch.eo_catalog & EXD_DATA_MASK) ==
10158275SEric Cheng 			    EXD_GROUP_NET_LINK_DESC) || ((scratch.eo_catalog &
10168275SEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_FLOW_DESC)) {
10178275SEric Cheng 				(void) add_desc(net_table, &ef,
10188275SEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
10198275SEric Cheng 			} else if (((scratch.eo_catalog & EXD_DATA_MASK) ==
10208275SEric Cheng 			    EXD_GROUP_NET_LINK_STATS) || ((scratch.eo_catalog &
10218275SEric Cheng 			    EXD_DATA_MASK) == EXD_GROUP_NET_FLOW_STATS)) {
10228275SEric Cheng 				(void) add_stats(net_table, &ef,
10238275SEric Cheng 				    scratch.eo_group.eg_nobjs - 1);
10248275SEric Cheng 			}
10258275SEric Cheng 		}
10268275SEric Cheng 		(void) ea_free_item(&scratch, EUP_ALLOC);
10278275SEric Cheng 		(void) bzero(&scratch, sizeof (ea_object_t));
10288275SEric Cheng 	}
10298275SEric Cheng 
10308275SEric Cheng 	(void) ea_close(&ef);
10318275SEric Cheng 	return ((void *)net_table);
10328275SEric Cheng }
10338275SEric Cheng 
10348275SEric Cheng /*
10358275SEric Cheng  * Walk the ctime list.  This is used when looking for usage records
10368275SEric Cheng  * based on a "resource" name.
10378275SEric Cheng  */
10388275SEric 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)10398275SEric Cheng dladm_walk_usage_res(int (*fn)(dladm_usage_t *, void *), int logtype,
10408275SEric Cheng     char *logfile, char *resource, char *stime, char *etime, void *arg)
10418275SEric Cheng {
10428275SEric Cheng 	net_table_t		*net_table;
10438275SEric Cheng 	net_time_t		st, et;
10448275SEric Cheng 	net_time_entry_t	*start;
10458275SEric Cheng 	net_stat_t		*ns = NULL;
10468275SEric Cheng 	net_stat_t		*nns;
10478275SEric Cheng 	uint64_t		tot_time = 0;
10488275SEric Cheng 	uint64_t		last_time;
10498275SEric Cheng 	uint64_t		tot_bytes = 0;
10508275SEric Cheng 	uint64_t		tot_ibytes = 0;
10518275SEric Cheng 	uint64_t		tot_obytes = 0;
10528275SEric Cheng 	boolean_t		gotstart = B_FALSE;
10538275SEric Cheng 	dladm_status_t		status;
10548275SEric Cheng 	dladm_usage_t		usage;
10558275SEric Cheng 	int			step = 1;
10568275SEric Cheng 
10578275SEric Cheng 	/* Parse the log file */
10588275SEric Cheng 	net_table = parse_logfile(logfile, logtype, &status);
10598275SEric Cheng 	if (net_table == NULL)
10608275SEric Cheng 		return (status);
10618275SEric Cheng 
10628275SEric Cheng 	if (net_table->net_entries == 0)
10638275SEric Cheng 		return (DLADM_STATUS_OK);
10648275SEric Cheng 	start = net_table->net_ctime_head;
10658275SEric Cheng 
10668275SEric Cheng 	/* Time range */
10678275SEric Cheng 	status = get_time_range(net_table->net_ctime_head,
10688275SEric Cheng 	    net_table->net_ctime_tail, &st, &et, stime, etime);
10698275SEric Cheng 	if (status != DLADM_STATUS_OK)
10708275SEric Cheng 		return (status);
10718275SEric Cheng 
10728275SEric Cheng 	while (start != NULL) {
10738275SEric Cheng 		nns = start->my_time_stat;
10748275SEric Cheng 
10758275SEric Cheng 		/* Get to the resource we are interested in */
10768833SVenu.Iyer@Sun.COM 		if (strcmp(resource, nns->net_stat_name) != 0) {
10778275SEric Cheng 			start = start->net_time_entry_next;
10788275SEric Cheng 			continue;
10798275SEric Cheng 		}
10808275SEric Cheng 
10818275SEric Cheng 		/* Find the first record */
10828275SEric Cheng 		if (!gotstart) {
10838275SEric Cheng 			get_starting_point(start, &start, &st, stime,
10848275SEric Cheng 			    &last_time);
10858275SEric Cheng 			if (start == NULL)
10868275SEric Cheng 				break;
10878275SEric Cheng 			nns = start->my_time_stat;
10888275SEric Cheng 			gotstart = B_TRUE;
10898275SEric Cheng 		}
10908275SEric Cheng 
10918275SEric Cheng 		/* Write one entry and return if we are out of the range */
10928275SEric Cheng 		if (etime != NULL && compare_time(&nns->net_stat_time, &et)
10938275SEric Cheng 		    == NET_TIME_GREATER) {
10948275SEric Cheng 			if (tot_bytes != 0) {
10958275SEric Cheng 				bcopy(ns->net_stat_name, &usage.du_name,
10968275SEric Cheng 				    sizeof (usage.du_name));
10978275SEric Cheng 				bcopy(&last_time, &usage.du_stime,
10988275SEric Cheng 				    sizeof (usage.du_stime));
10998275SEric Cheng 				bcopy(&ns->net_stat_ctime, &usage.du_etime,
11008275SEric Cheng 				    sizeof (usage.du_etime));
11018275SEric Cheng 				usage.du_rbytes = tot_ibytes;
11028275SEric Cheng 				usage.du_obytes = tot_obytes;
11038275SEric Cheng 				usage.du_bandwidth = tot_bytes*8/tot_time;
11048275SEric Cheng 				usage.du_last = B_TRUE;
11058275SEric Cheng 				fn(&usage, arg);
11068275SEric Cheng 			}
11078275SEric Cheng 			return (DLADM_STATUS_OK);
11088275SEric Cheng 		}
11098275SEric Cheng 
11108275SEric Cheng 		/*
11118275SEric Cheng 		 * If this is a reference entry, just print what we have
11128275SEric Cheng 		 * and proceed.
11138275SEric Cheng 		 */
11148275SEric Cheng 		if (nns->net_stat_isref) {
11158275SEric Cheng 			if (tot_bytes != 0) {
11168275SEric Cheng 				bcopy(&nns->net_stat_name, &usage.du_name,
11178275SEric Cheng 				    sizeof (usage.du_name));
11188275SEric Cheng 				bcopy(&nns->net_stat_ctime, &usage.du_stime,
11198275SEric Cheng 				    sizeof (usage.du_stime));
11208275SEric Cheng 				usage.du_rbytes = tot_ibytes;
11218275SEric Cheng 				usage.du_obytes = tot_obytes;
11228275SEric Cheng 				usage.du_bandwidth = tot_bytes*8/tot_time;
11238275SEric Cheng 				usage.du_last = B_TRUE;
11248275SEric Cheng 				fn(&usage, arg);
11258275SEric Cheng 				NET_RESET_TOT(tot_bytes, tot_time, tot_ibytes,
11268275SEric Cheng 				    tot_obytes, step);
11278275SEric Cheng 			}
11288275SEric Cheng 			last_time = nns->net_stat_ctime;
11298275SEric Cheng 			start = start->net_time_entry_next;
11308275SEric Cheng 			continue;
11318275SEric Cheng 		}
11328275SEric Cheng 
11338275SEric Cheng 		ns = nns;
11348275SEric Cheng 		if (--step == 0) {
11358275SEric Cheng 			tot_bytes += ns->net_stat_ibytes + ns->net_stat_obytes;
11368275SEric Cheng 			tot_ibytes += ns->net_stat_ibytes;
11378275SEric Cheng 			tot_obytes += ns->net_stat_obytes;
11388275SEric Cheng 			tot_time += ns->net_stat_tdiff;
11398275SEric Cheng 			bcopy(&ns->net_stat_name, &usage.du_name,
11408275SEric Cheng 			    sizeof (usage.du_name));
11418275SEric Cheng 			bcopy(&last_time, &usage.du_stime,
11428275SEric Cheng 			    sizeof (usage.du_stime));
11438275SEric Cheng 			bcopy(&ns->net_stat_ctime, &usage.du_etime,
11448275SEric Cheng 			    sizeof (usage.du_etime));
11458275SEric Cheng 			usage.du_rbytes = tot_ibytes;
11468275SEric Cheng 			usage.du_obytes = tot_obytes;
11478275SEric Cheng 			usage.du_bandwidth = tot_bytes*8/tot_time;
11488275SEric Cheng 			usage.du_last = B_TRUE;
11498275SEric Cheng 			fn(&usage, arg);
11508275SEric Cheng 
11518275SEric Cheng 			NET_RESET_TOT(tot_bytes, tot_time, tot_ibytes,
11528275SEric Cheng 			    tot_obytes, step);
11538275SEric Cheng 			last_time = ns->net_stat_ctime;
11548275SEric Cheng 		} else {
11558275SEric Cheng 			tot_bytes += ns->net_stat_ibytes + ns->net_stat_obytes;
11568275SEric Cheng 			tot_ibytes += ns->net_stat_ibytes;
11578275SEric Cheng 			tot_obytes += ns->net_stat_obytes;
11588275SEric Cheng 			tot_time += ns->net_stat_tdiff;
11598275SEric Cheng 		}
11608275SEric Cheng 		start = start->net_time_entry_next;
11618275SEric Cheng 	}
11628275SEric Cheng 
11638275SEric Cheng 	if (tot_bytes != 0) {
11648275SEric Cheng 		bcopy(&ns->net_stat_name, &usage.du_name,
11658275SEric Cheng 		    sizeof (usage.du_name));
11668275SEric Cheng 		bcopy(&last_time, &usage.du_stime,
11678275SEric Cheng 		    sizeof (usage.du_stime));
11688275SEric Cheng 		bcopy(&ns->net_stat_ctime, &usage.du_etime,
11698275SEric Cheng 		    sizeof (usage.du_etime));
11708275SEric Cheng 		usage.du_rbytes = tot_ibytes;
11718275SEric Cheng 		usage.du_obytes = tot_obytes;
11728275SEric Cheng 		usage.du_bandwidth = tot_bytes*8/tot_time;
11738275SEric Cheng 		usage.du_last = B_TRUE;
11748275SEric Cheng 		fn(&usage, arg);
11758275SEric Cheng 	}
11768275SEric Cheng 
11778275SEric Cheng 	free_logtable(net_table);
11788275SEric Cheng 	return (status);
11798275SEric Cheng }
11808275SEric Cheng 
11818275SEric Cheng /*
11828275SEric Cheng  * Walk the time sorted list if a resource is not specified.
11838275SEric Cheng  */
11848275SEric Cheng dladm_status_t
dladm_walk_usage_time(int (* fn)(dladm_usage_t *,void *),int logtype,char * logfile,char * stime,char * etime,void * arg)11858275SEric Cheng dladm_walk_usage_time(int (*fn)(dladm_usage_t *, void *), int logtype,
11868275SEric Cheng     char *logfile, char *stime, char *etime, void *arg)
11878275SEric Cheng {
11888275SEric Cheng 	net_table_t		*net_table;
11898275SEric Cheng 	net_time_entry_t	*start;
11908275SEric Cheng 	net_stat_t		*ns = NULL, *nns;
11918275SEric Cheng 	net_time_t		st, et, *t1;
11928275SEric Cheng 	net_desc_t		*nd;
11938275SEric Cheng 	net_entry_t		*ne;
11948275SEric Cheng 	net_plot_entry_t	*pe;
11958275SEric Cheng 	int			count;
11968275SEric Cheng 	int			step = 1;
11978275SEric Cheng 	int			nentries = 0, pentries = 0;
11988275SEric Cheng 	uint64_t		last_time;
11998275SEric Cheng 	dladm_status_t		status;
12008275SEric Cheng 
12018275SEric Cheng 	/* Parse the log file */
12028275SEric Cheng 	net_table = parse_logfile(logfile, logtype, &status);
12038275SEric Cheng 	if (net_table == NULL)
12048275SEric Cheng 		return (status);
12058275SEric Cheng 
12068275SEric Cheng 	if (net_table->net_entries == 0)
12078275SEric Cheng 		return (DLADM_STATUS_OK);
12088275SEric Cheng 	start = net_table->net_time_head;
12098275SEric Cheng 
12108275SEric Cheng 	/* Find the first and last records and starting point */
12118275SEric Cheng 	status = get_time_range(net_table->net_time_head,
12128275SEric Cheng 	    net_table->net_time_tail, &st, &et, stime, etime);
12138275SEric Cheng 	if (status != DLADM_STATUS_OK)
12148275SEric Cheng 		return (status);
12158275SEric Cheng 	get_starting_point(start, &start, &st, stime, &last_time);
12168275SEric Cheng 	/*
12178275SEric Cheng 	 * Could assert to be non-null, since get_time_range()
12188275SEric Cheng 	 * would have adjusted.
12198275SEric Cheng 	 */
12208275SEric Cheng 	if (start == NULL)
12218275SEric Cheng 		return (DLADM_STATUS_BADTIMEVAL);
12228275SEric Cheng 
12238275SEric Cheng 	/*
12248275SEric Cheng 	 * Collect entries for all resources in a time slot before
12258275SEric Cheng 	 * writing to the file.
12268275SEric Cheng 	 */
12278275SEric Cheng 	nentries = net_table->net_entries;
12288275SEric Cheng 
12298275SEric Cheng 	pe = malloc(sizeof (net_plot_entry_t) * net_table->net_entries + 1);
12308275SEric Cheng 	if (pe == NULL)
12318275SEric Cheng 		return (DLADM_STATUS_NOMEM);
12328275SEric Cheng 
12338275SEric Cheng 	ne = net_table->net_table_head;
12348275SEric Cheng 	for (count = 0; count < nentries; count++) {
12358275SEric Cheng 		nd = ne->net_entry_desc;
12368275SEric Cheng 		pe[count].net_pe_name = nd->net_desc_name;
12378275SEric Cheng 		ne = ne->net_entry_next;
12388275SEric Cheng 	}
12398275SEric Cheng 
12408275SEric Cheng 	clear_pe(pe, nentries, &pentries);
12418275SEric Cheng 
12428275SEric Cheng 	/* Write header to file */
12438275SEric Cheng 	/* add_pe_to_file(fn, pe, ns, nentries, arg); */
12448275SEric Cheng 
12458275SEric Cheng 	t1 = &start->my_time_stat->net_stat_time;
12468275SEric Cheng 
12478275SEric Cheng 	while (start != NULL) {
12488275SEric Cheng 
12498275SEric Cheng 		nns = start->my_time_stat;
12508275SEric Cheng 		/*
12518275SEric Cheng 		 * We have crossed the time boundary, check if we need to
12528275SEric Cheng 		 * print out now.
12538275SEric Cheng 		 */
12548275SEric Cheng 		if (compare_time(&nns->net_stat_time, t1) ==
12558275SEric Cheng 		    NET_TIME_GREATER) {
12568275SEric Cheng 			/* return if we are out of the range */
12578275SEric Cheng 			if (etime != NULL &&
12588275SEric Cheng 			    compare_time(&nns->net_stat_time, &et) ==
12598275SEric Cheng 			    NET_TIME_GREATER) {
12608275SEric Cheng 				if (pentries > 0) {
12618275SEric Cheng 					add_pe_to_file(fn, pe, ns, nentries,
12628275SEric Cheng 					    arg);
12638275SEric Cheng 					clear_pe(pe, nentries, &pentries);
12648275SEric Cheng 				}
12658275SEric Cheng 				free(pe);
12668275SEric Cheng 				return (DLADM_STATUS_OK);
12678275SEric Cheng 			}
12688275SEric Cheng 			/* update the stats from the ns. */
12698275SEric Cheng 			t1 = &nns->net_stat_time;
12708275SEric Cheng 			last_time = ns->net_stat_ctime;
12718275SEric Cheng 			if (--step == 0) {
12728275SEric Cheng 				if (pentries > 0) {
12738275SEric Cheng 					add_pe_to_file(fn, pe, ns, nentries,
12748275SEric Cheng 					    arg);
12758275SEric Cheng 					clear_pe(pe, nentries, &pentries);
12768275SEric Cheng 				}
12778275SEric Cheng 				step = 1;
12788275SEric Cheng 			}
12798275SEric Cheng 		}
12808275SEric Cheng 
12818275SEric Cheng 		/*
12828275SEric Cheng 		 * if this is a reference entry, just print what we have
12838275SEric Cheng 		 * for this resource and proceed. We will end up writing
12848275SEric Cheng 		 * the stats for all the entries when we hit a ref element,
12858275SEric Cheng 		 * which means 'steps' for some might not be accurate, but
12868275SEric Cheng 		 * that is fine, the alternative is to write only the
12878275SEric Cheng 		 * resource for which we hit a reference entry.
12888275SEric Cheng 		 */
12898275SEric Cheng 		if (nns->net_stat_isref) {
12908275SEric Cheng 			if (pentries > 0) {
12918275SEric Cheng 				add_pe_to_file(fn, pe, ns, nentries, arg);
12928275SEric Cheng 				clear_pe(pe, nentries, &pentries);
12938275SEric Cheng 			}
12948275SEric Cheng 			step = 1;
12958275SEric Cheng 		} else {
12968275SEric Cheng 			update_pe(pe, nns, nentries, &pentries, last_time);
12978275SEric Cheng 		}
12988275SEric Cheng 		ns = nns;
12998275SEric Cheng 		start = start->net_time_entry_next;
13008275SEric Cheng 	}
13018275SEric Cheng 
13028275SEric Cheng 	if (pentries > 0)
13038275SEric Cheng 		add_pe_to_file(fn, pe, ns, nentries, arg);
13048275SEric Cheng 
13058275SEric Cheng 	free(pe);
13068275SEric Cheng 	free_logtable(net_table);
13078275SEric Cheng 
13088275SEric Cheng 	return (DLADM_STATUS_OK);
13098275SEric Cheng }
13108275SEric Cheng 
13118275SEric Cheng dladm_status_t
dladm_usage_summary(int (* fn)(dladm_usage_t *,void *),int logtype,char * logfile,void * arg)13128275SEric Cheng dladm_usage_summary(int (*fn)(dladm_usage_t *, void *), int logtype,
13138275SEric Cheng     char *logfile, void *arg)
13148275SEric Cheng {
13158275SEric Cheng 	net_table_t		*net_table;
13168275SEric Cheng 	net_entry_t		*ne;
13178275SEric Cheng 	net_desc_t		*nd;
13188275SEric Cheng 	net_stat_t		*ns;
13198275SEric Cheng 	int			count;
13208275SEric Cheng 	dladm_usage_t		usage;
13218275SEric Cheng 	dladm_status_t		status;
13228275SEric Cheng 
13238275SEric Cheng 	/* Parse the log file */
13248275SEric Cheng 	net_table = parse_logfile(logfile, logtype, &status);
13258275SEric Cheng 	if (net_table == NULL)
13268275SEric Cheng 		return (status);
13278275SEric Cheng 
13288275SEric Cheng 	if (net_table->net_entries == 0)
13298275SEric Cheng 		return (DLADM_STATUS_OK);
13308275SEric Cheng 
13318275SEric Cheng 	ne = net_table->net_table_head;
13328275SEric Cheng 	for (count = 0; count < net_table->net_entries; count++) {
13338275SEric Cheng 		ns = ne->net_entry_tstats;
13348275SEric Cheng 		nd = ne->net_entry_desc;
13358275SEric Cheng 
1336*11878SVenu.Iyer@Sun.COM 		if (ns->net_stat_ibytes + ns->net_stat_obytes == 0) {
1337*11878SVenu.Iyer@Sun.COM 			ne = ne->net_entry_next;
13388275SEric Cheng 			continue;
1339*11878SVenu.Iyer@Sun.COM 		}
13408275SEric Cheng 		bcopy(&nd->net_desc_name, &usage.du_name,
13418275SEric Cheng 		    sizeof (usage.du_name));
13428275SEric Cheng 		usage.du_duration = ne->net_entry_ttime;
13438275SEric Cheng 		usage.du_ipackets = ns->net_stat_ipackets;
13448275SEric Cheng 		usage.du_rbytes = ns->net_stat_ibytes;
13458275SEric Cheng 		usage.du_opackets = ns->net_stat_opackets;
13468275SEric Cheng 		usage.du_obytes = ns->net_stat_obytes;
13478275SEric Cheng 		usage.du_bandwidth =
13488275SEric Cheng 		    (ns->net_stat_ibytes + ns->net_stat_obytes) * 8 /
13498275SEric Cheng 		    usage.du_duration;
13508275SEric Cheng 		usage.du_last = (count == net_table->net_entries-1);
13518275SEric Cheng 		fn(&usage, arg);
13528275SEric Cheng 
13538275SEric Cheng 		ne = ne->net_entry_next;
13548275SEric Cheng 	}
13558275SEric Cheng 
13568275SEric Cheng 	free_logtable(net_table);
13578275SEric Cheng 	return (DLADM_STATUS_OK);
13588275SEric Cheng }
13598275SEric Cheng 
13608275SEric Cheng /*
13618275SEric Cheng  * Walk the ctime list and display the dates of the records.
13628275SEric Cheng  */
13638275SEric Cheng dladm_status_t
dladm_usage_dates(int (* fn)(dladm_usage_t *,void *),int logtype,char * logfile,char * resource,void * arg)13648275SEric Cheng dladm_usage_dates(int (*fn)(dladm_usage_t *, void *), int logtype,
13658275SEric Cheng     char *logfile, char *resource, void *arg)
13668275SEric Cheng {
13678275SEric Cheng 	net_table_t		*net_table;
13688275SEric Cheng 	net_time_entry_t	*start;
13698275SEric Cheng 	net_stat_t		*nns;
13708275SEric Cheng 	net_time_t		st;
13718275SEric Cheng 	net_time_t		*lasttime = NULL;
13728275SEric Cheng 	uint64_t		last_time;
13738275SEric Cheng 	boolean_t		gotstart = B_FALSE;
13748275SEric Cheng 	dladm_status_t		status;
13758275SEric Cheng 	dladm_usage_t		usage;
13768275SEric Cheng 
13778275SEric Cheng 	/* Parse the log file */
13788275SEric Cheng 	net_table = parse_logfile(logfile, logtype, &status);
13798275SEric Cheng 	if (net_table == NULL)
13808275SEric Cheng 		return (status);
13818275SEric Cheng 
13828275SEric Cheng 	if (net_table->net_entries == 0)
13838275SEric Cheng 		return (DLADM_STATUS_OK);
13848275SEric Cheng 
13858275SEric Cheng 	start = net_table->net_ctime_head;
13868275SEric Cheng 
13878275SEric Cheng 	while (start != NULL) {
13888275SEric Cheng 		nns = start->my_time_stat;
13898275SEric Cheng 
13908275SEric Cheng 		/* get to the resource we are interested in */
13918275SEric Cheng 		if (resource != NULL) {
13928833SVenu.Iyer@Sun.COM 			if (strcmp(resource, nns->net_stat_name) != 0) {
13938275SEric Cheng 				start = start->net_time_entry_next;
13948275SEric Cheng 				continue;
13958275SEric Cheng 			}
13968275SEric Cheng 		}
13978275SEric Cheng 
13988275SEric Cheng 		/* get the starting point in the logfile */
13998275SEric Cheng 		if (!gotstart) {
14008275SEric Cheng 			get_starting_point(start, &start, &st, NULL,
14018275SEric Cheng 			    &last_time);
14028275SEric Cheng 			if (start == NULL)
14038275SEric Cheng 				break;
14048275SEric Cheng 			nns = start->my_time_stat;
14058275SEric Cheng 			gotstart = B_TRUE;
14068275SEric Cheng 		}
14078275SEric Cheng 
14088275SEric Cheng 		if (lasttime == NULL ||
14098275SEric Cheng 		    compare_date(&nns->net_stat_time, lasttime) ==
14108275SEric Cheng 		    NET_DATE_GREATER) {
14118275SEric Cheng 			bzero(&usage, sizeof (dladm_usage_t));
14128833SVenu.Iyer@Sun.COM 			(void) strlcpy(usage.du_name, nns->net_stat_name,
14138833SVenu.Iyer@Sun.COM 			    sizeof (usage.du_name));
14148275SEric Cheng 			bcopy(&nns->net_stat_ctime, &usage.du_stime,
14158275SEric Cheng 			    sizeof (usage.du_stime));
14168275SEric Cheng 			fn(&usage, arg);
14178275SEric Cheng 			lasttime = &nns->net_stat_time;
14188275SEric Cheng 		}
14198275SEric Cheng 
14208275SEric Cheng 		start = start->net_time_entry_next;
14218275SEric Cheng 		continue;
14228275SEric Cheng 	}
14238275SEric Cheng 
14248275SEric Cheng 	free_logtable(net_table);
14258275SEric Cheng 	return (status);
14268275SEric Cheng }
1427