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