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