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