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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 * 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 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 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 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 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