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