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