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