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