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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*da14cebeSEric Cheng * Use is subject to license terms. 24*da14cebeSEric Cheng */ 25*da14cebeSEric Cheng 26*da14cebeSEric Cheng #include <stdio.h> 27*da14cebeSEric Cheng #include <stdlib.h> 28*da14cebeSEric Cheng #include <strings.h> 29*da14cebeSEric Cheng #include <err.h> 30*da14cebeSEric Cheng #include <errno.h> 31*da14cebeSEric Cheng #include <kstat.h> 32*da14cebeSEric Cheng #include <unistd.h> 33*da14cebeSEric Cheng #include <signal.h> 34*da14cebeSEric Cheng #include <sys/dld.h> 35*da14cebeSEric Cheng 36*da14cebeSEric Cheng #include <libdllink.h> 37*da14cebeSEric Cheng #include <libdlflow.h> 38*da14cebeSEric Cheng #include <libdlstat.h> 39*da14cebeSEric Cheng 40*da14cebeSEric Cheng /* 41*da14cebeSEric Cheng * x86 <sys/regs> ERR conflicts with <curses.h> ERR. 42*da14cebeSEric Cheng * Include curses.h last. 43*da14cebeSEric Cheng */ 44*da14cebeSEric Cheng #if defined(ERR) 45*da14cebeSEric Cheng #undef ERR 46*da14cebeSEric Cheng #endif 47*da14cebeSEric Cheng #include <curses.h> 48*da14cebeSEric Cheng 49*da14cebeSEric Cheng struct flowlist { 50*da14cebeSEric Cheng char flowname[MAXNAMELEN]; 51*da14cebeSEric Cheng datalink_id_t linkid; 52*da14cebeSEric Cheng uint_t ifspeed; 53*da14cebeSEric Cheng boolean_t first; 54*da14cebeSEric Cheng boolean_t display; 55*da14cebeSEric Cheng pktsum_t prevstats; 56*da14cebeSEric Cheng pktsum_t diffstats; 57*da14cebeSEric Cheng }; 58*da14cebeSEric Cheng 59*da14cebeSEric Cheng static int maxx, maxy, redraw = 0; 60*da14cebeSEric Cheng static volatile uint_t handle_resize = 0, handle_break = 0; 61*da14cebeSEric Cheng 62*da14cebeSEric Cheng pktsum_t totalstats; 63*da14cebeSEric Cheng struct flowlist *stattable = NULL; 64*da14cebeSEric Cheng static int statentry = -1, maxstatentries = 0; 65*da14cebeSEric Cheng 66*da14cebeSEric Cheng #define STATGROWSIZE 16 67*da14cebeSEric Cheng 68*da14cebeSEric Cheng 69*da14cebeSEric Cheng /* 70*da14cebeSEric Cheng * Search for flowlist entry in stattable which matches 71*da14cebeSEric Cheng * the flowname and linkide. If no match is found, use 72*da14cebeSEric Cheng * next available slot. If no slots are available, 73*da14cebeSEric Cheng * reallocate table with more slots. 74*da14cebeSEric Cheng * 75*da14cebeSEric Cheng * Return: *flowlist of matching flow 76*da14cebeSEric Cheng * NULL if realloc fails 77*da14cebeSEric Cheng */ 78*da14cebeSEric Cheng 79*da14cebeSEric Cheng static struct flowlist * 80*da14cebeSEric Cheng findstat(const char *flowname, datalink_id_t linkid) 81*da14cebeSEric Cheng { 82*da14cebeSEric Cheng int match = 0; 83*da14cebeSEric Cheng struct flowlist *flist; 84*da14cebeSEric Cheng 85*da14cebeSEric Cheng /* Look for match in the stattable */ 86*da14cebeSEric Cheng for (match = 0, flist = stattable; 87*da14cebeSEric Cheng match <= statentry; 88*da14cebeSEric Cheng match++, flist++) { 89*da14cebeSEric Cheng 90*da14cebeSEric Cheng if (flist == NULL) 91*da14cebeSEric Cheng break; 92*da14cebeSEric Cheng /* match the flowname */ 93*da14cebeSEric Cheng if (flowname != NULL) { 94*da14cebeSEric Cheng if (strncmp(flowname, flist->flowname, MAXNAMELEN) 95*da14cebeSEric Cheng == NULL) 96*da14cebeSEric Cheng return (flist); 97*da14cebeSEric Cheng /* match the linkid */ 98*da14cebeSEric Cheng } else { 99*da14cebeSEric Cheng if (linkid == flist->linkid) 100*da14cebeSEric Cheng return (flist); 101*da14cebeSEric Cheng } 102*da14cebeSEric Cheng } 103*da14cebeSEric Cheng 104*da14cebeSEric Cheng /* 105*da14cebeSEric Cheng * No match found in the table. Store statistics in the next slot. 106*da14cebeSEric Cheng * If necessary, make room for this entry. 107*da14cebeSEric Cheng */ 108*da14cebeSEric Cheng statentry++; 109*da14cebeSEric Cheng if ((maxstatentries == 0) || (maxstatentries == statentry)) { 110*da14cebeSEric Cheng maxstatentries += STATGROWSIZE; 111*da14cebeSEric Cheng stattable = realloc(stattable, 112*da14cebeSEric Cheng maxstatentries * sizeof (struct flowlist)); 113*da14cebeSEric Cheng if (stattable == NULL) { 114*da14cebeSEric Cheng perror("realloc"); 115*da14cebeSEric Cheng return (struct flowlist *)(NULL); 116*da14cebeSEric Cheng } 117*da14cebeSEric Cheng } 118*da14cebeSEric Cheng flist = &stattable[statentry]; 119*da14cebeSEric Cheng bzero(flist, sizeof (struct flowlist)); 120*da14cebeSEric Cheng flist->first = B_TRUE; 121*da14cebeSEric Cheng 122*da14cebeSEric Cheng if (flowname != NULL) 123*da14cebeSEric Cheng (void) strncpy(flist->flowname, flowname, MAXNAMELEN); 124*da14cebeSEric Cheng flist->linkid = linkid; 125*da14cebeSEric Cheng return (flist); 126*da14cebeSEric Cheng } 127*da14cebeSEric Cheng 128*da14cebeSEric Cheng static void 129*da14cebeSEric Cheng print_flow_stats(struct flowlist *flist) 130*da14cebeSEric Cheng { 131*da14cebeSEric Cheng struct flowlist *fcurr; 132*da14cebeSEric Cheng double ikbs, okbs; 133*da14cebeSEric Cheng double ipks, opks; 134*da14cebeSEric Cheng double dlt; 135*da14cebeSEric Cheng int fcount; 136*da14cebeSEric Cheng static boolean_t first = B_TRUE; 137*da14cebeSEric Cheng 138*da14cebeSEric Cheng if (first) { 139*da14cebeSEric Cheng first = B_FALSE; 140*da14cebeSEric Cheng (void) printw("please wait...\n"); 141*da14cebeSEric Cheng return; 142*da14cebeSEric Cheng } 143*da14cebeSEric Cheng 144*da14cebeSEric Cheng for (fcount = 0, fcurr = flist; 145*da14cebeSEric Cheng fcount <= statentry; 146*da14cebeSEric Cheng fcount++, fcurr++) { 147*da14cebeSEric Cheng if (fcurr->flowname && fcurr->display) { 148*da14cebeSEric Cheng char linkname[MAXNAMELEN]; 149*da14cebeSEric Cheng 150*da14cebeSEric Cheng (void) dladm_datalink_id2info(fcurr->linkid, NULL, NULL, 151*da14cebeSEric Cheng NULL, linkname, sizeof (linkname)); 152*da14cebeSEric Cheng dlt = (double)fcurr->diffstats.snaptime/(double)NANOSEC; 153*da14cebeSEric Cheng ikbs = fcurr->diffstats.rbytes * 8 / dlt / 1024; 154*da14cebeSEric Cheng okbs = fcurr->diffstats.obytes * 8 / dlt / 1024; 155*da14cebeSEric Cheng ipks = fcurr->diffstats.ipackets / dlt; 156*da14cebeSEric Cheng opks = fcurr->diffstats.opackets / dlt; 157*da14cebeSEric Cheng (void) printw("%-15.15s", fcurr->flowname); 158*da14cebeSEric Cheng (void) printw("%-10.10s", linkname); 159*da14cebeSEric Cheng (void) printw("%9.2f %9.2f %9.2f %9.2f ", 160*da14cebeSEric Cheng ikbs, okbs, ipks, opks); 161*da14cebeSEric Cheng (void) printw("\n"); 162*da14cebeSEric Cheng } 163*da14cebeSEric Cheng } 164*da14cebeSEric Cheng } 165*da14cebeSEric Cheng 166*da14cebeSEric Cheng /*ARGSUSED*/ 167*da14cebeSEric Cheng static int 168*da14cebeSEric Cheng flow_kstats(dladm_flow_attr_t *attr, void *arg) 169*da14cebeSEric Cheng { 170*da14cebeSEric Cheng kstat_ctl_t *kcp = (kstat_ctl_t *)arg; 171*da14cebeSEric Cheng kstat_t *ksp; 172*da14cebeSEric Cheng struct flowlist *flist; 173*da14cebeSEric Cheng pktsum_t currstats, *prevstats, *diffstats; 174*da14cebeSEric Cheng 175*da14cebeSEric Cheng flist = findstat(attr->fa_flowname, attr->fa_linkid); 176*da14cebeSEric Cheng if (flist != NULL) { 177*da14cebeSEric Cheng prevstats = &flist->prevstats; 178*da14cebeSEric Cheng diffstats = &flist->diffstats; 179*da14cebeSEric Cheng } else { 180*da14cebeSEric Cheng return (DLADM_STATUS_FAILED); 181*da14cebeSEric Cheng } 182*da14cebeSEric Cheng 183*da14cebeSEric Cheng /* lookup kstat entry */ 184*da14cebeSEric Cheng ksp = dladm_kstat_lookup(kcp, NULL, -1, attr->fa_flowname, "flow"); 185*da14cebeSEric Cheng 186*da14cebeSEric Cheng if (ksp == NULL) 187*da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 188*da14cebeSEric Cheng else 189*da14cebeSEric Cheng flist->display = B_TRUE; 190*da14cebeSEric Cheng 191*da14cebeSEric Cheng dladm_get_stats(kcp, ksp, &currstats); 192*da14cebeSEric Cheng if (flist->ifspeed == 0) 193*da14cebeSEric Cheng (void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64, 194*da14cebeSEric Cheng &flist->ifspeed); 195*da14cebeSEric Cheng 196*da14cebeSEric Cheng if (flist->first) 197*da14cebeSEric Cheng flist->first = B_FALSE; 198*da14cebeSEric Cheng else { 199*da14cebeSEric Cheng dladm_stats_diff(diffstats, &currstats, prevstats); 200*da14cebeSEric Cheng dladm_stats_total(&totalstats, diffstats, &totalstats); 201*da14cebeSEric Cheng } 202*da14cebeSEric Cheng 203*da14cebeSEric Cheng bcopy(&currstats, prevstats, sizeof (pktsum_t)); 204*da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 205*da14cebeSEric Cheng } 206*da14cebeSEric Cheng 207*da14cebeSEric Cheng static void 208*da14cebeSEric Cheng print_link_stats(struct flowlist *flist) 209*da14cebeSEric Cheng { 210*da14cebeSEric Cheng struct flowlist *fcurr; 211*da14cebeSEric Cheng double ikbs, okbs; 212*da14cebeSEric Cheng double ipks, opks; 213*da14cebeSEric Cheng double util; 214*da14cebeSEric Cheng double dlt; 215*da14cebeSEric Cheng int fcount; 216*da14cebeSEric Cheng static boolean_t first = B_TRUE; 217*da14cebeSEric Cheng 218*da14cebeSEric Cheng if (first) { 219*da14cebeSEric Cheng first = B_FALSE; 220*da14cebeSEric Cheng (void) printw("please wait...\n"); 221*da14cebeSEric Cheng return; 222*da14cebeSEric Cheng } 223*da14cebeSEric Cheng 224*da14cebeSEric Cheng for (fcount = 0, fcurr = flist; 225*da14cebeSEric Cheng fcount <= statentry; 226*da14cebeSEric Cheng fcount++, fcurr++) { 227*da14cebeSEric Cheng if ((fcurr->linkid != DATALINK_INVALID_LINKID) && 228*da14cebeSEric Cheng fcurr->display) { 229*da14cebeSEric Cheng char linkname[MAXNAMELEN]; 230*da14cebeSEric Cheng 231*da14cebeSEric Cheng (void) dladm_datalink_id2info(fcurr->linkid, NULL, NULL, 232*da14cebeSEric Cheng NULL, linkname, sizeof (linkname)); 233*da14cebeSEric Cheng dlt = (double)fcurr->diffstats.snaptime/(double)NANOSEC; 234*da14cebeSEric Cheng ikbs = (double)fcurr->diffstats.rbytes * 8 / dlt / 1024; 235*da14cebeSEric Cheng okbs = (double)fcurr->diffstats.obytes * 8 / dlt / 1024; 236*da14cebeSEric Cheng ipks = (double)fcurr->diffstats.ipackets / dlt; 237*da14cebeSEric Cheng opks = (double)fcurr->diffstats.opackets / dlt; 238*da14cebeSEric Cheng (void) printw("%-10.10s", linkname); 239*da14cebeSEric Cheng (void) printw("%9.2f %9.2f %9.2f %9.2f ", 240*da14cebeSEric Cheng ikbs, okbs, ipks, opks); 241*da14cebeSEric Cheng if (fcurr->ifspeed != 0) 242*da14cebeSEric Cheng util = ((ikbs + okbs) * 1024) * 243*da14cebeSEric Cheng 100/ fcurr->ifspeed; 244*da14cebeSEric Cheng else 245*da14cebeSEric Cheng util = (double)0; 246*da14cebeSEric Cheng (void) attron(A_BOLD); 247*da14cebeSEric Cheng (void) printw(" %6.2f", util); 248*da14cebeSEric Cheng (void) attroff(A_BOLD); 249*da14cebeSEric Cheng (void) printw("\n"); 250*da14cebeSEric Cheng } 251*da14cebeSEric Cheng } 252*da14cebeSEric Cheng } 253*da14cebeSEric Cheng 254*da14cebeSEric Cheng /* 255*da14cebeSEric Cheng * This function is called through the dladm_walk_datalink_id() walker and 256*da14cebeSEric Cheng * calls the dladm_walk_flow() walker. 257*da14cebeSEric Cheng */ 258*da14cebeSEric Cheng 259*da14cebeSEric Cheng /*ARGSUSED*/ 260*da14cebeSEric Cheng static int 261*da14cebeSEric Cheng link_flowstats(datalink_id_t linkid, void *arg) 262*da14cebeSEric Cheng { 263*da14cebeSEric Cheng return (dladm_walk_flow(flow_kstats, linkid, arg, B_FALSE)); 264*da14cebeSEric Cheng } 265*da14cebeSEric Cheng 266*da14cebeSEric Cheng /*ARGSUSED*/ 267*da14cebeSEric Cheng static int 268*da14cebeSEric Cheng link_kstats(datalink_id_t linkid, void *arg) 269*da14cebeSEric Cheng { 270*da14cebeSEric Cheng kstat_ctl_t *kcp = (kstat_ctl_t *)arg; 271*da14cebeSEric Cheng struct flowlist *flist; 272*da14cebeSEric Cheng pktsum_t currstats, *prevstats, *diffstats; 273*da14cebeSEric Cheng kstat_t *ksp; 274*da14cebeSEric Cheng char linkname[MAXNAMELEN]; 275*da14cebeSEric Cheng 276*da14cebeSEric Cheng /* find the flist entry */ 277*da14cebeSEric Cheng flist = findstat(NULL, linkid); 278*da14cebeSEric Cheng if (flist != NULL) { 279*da14cebeSEric Cheng prevstats = &flist->prevstats; 280*da14cebeSEric Cheng diffstats = &flist->diffstats; 281*da14cebeSEric Cheng } else { 282*da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 283*da14cebeSEric Cheng } 284*da14cebeSEric Cheng 285*da14cebeSEric Cheng /* lookup kstat entry */ 286*da14cebeSEric Cheng (void) dladm_datalink_id2info(linkid, NULL, NULL, NULL, linkname, 287*da14cebeSEric Cheng sizeof (linkname)); 288*da14cebeSEric Cheng 289*da14cebeSEric Cheng if (linkname == NULL) { 290*da14cebeSEric Cheng warn("no linkname for linkid"); 291*da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 292*da14cebeSEric Cheng } 293*da14cebeSEric Cheng 294*da14cebeSEric Cheng ksp = dladm_kstat_lookup(kcp, NULL, -1, linkname, "net"); 295*da14cebeSEric Cheng 296*da14cebeSEric Cheng if (ksp == NULL) 297*da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 298*da14cebeSEric Cheng else 299*da14cebeSEric Cheng flist->display = B_TRUE; 300*da14cebeSEric Cheng 301*da14cebeSEric Cheng /* read packet and byte stats */ 302*da14cebeSEric Cheng dladm_get_stats(kcp, ksp, &currstats); 303*da14cebeSEric Cheng 304*da14cebeSEric Cheng if (flist->ifspeed == 0) 305*da14cebeSEric Cheng (void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64, 306*da14cebeSEric Cheng &flist->ifspeed); 307*da14cebeSEric Cheng 308*da14cebeSEric Cheng if (flist->first == B_TRUE) 309*da14cebeSEric Cheng flist->first = B_FALSE; 310*da14cebeSEric Cheng else 311*da14cebeSEric Cheng dladm_stats_diff(diffstats, &currstats, prevstats); 312*da14cebeSEric Cheng 313*da14cebeSEric Cheng bcopy(&currstats, prevstats, sizeof (*prevstats)); 314*da14cebeSEric Cheng 315*da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 316*da14cebeSEric Cheng } 317*da14cebeSEric Cheng 318*da14cebeSEric Cheng /*ARGSUSED*/ 319*da14cebeSEric Cheng static void 320*da14cebeSEric Cheng sig_break(int s) 321*da14cebeSEric Cheng { 322*da14cebeSEric Cheng handle_break = 1; 323*da14cebeSEric Cheng } 324*da14cebeSEric Cheng 325*da14cebeSEric Cheng /*ARGSUSED*/ 326*da14cebeSEric Cheng static void 327*da14cebeSEric Cheng sig_resize(int s) 328*da14cebeSEric Cheng { 329*da14cebeSEric Cheng handle_resize = 1; 330*da14cebeSEric Cheng } 331*da14cebeSEric Cheng 332*da14cebeSEric Cheng static void 333*da14cebeSEric Cheng curses_init() 334*da14cebeSEric Cheng { 335*da14cebeSEric Cheng maxx = maxx; /* lint */ 336*da14cebeSEric Cheng maxy = maxy; /* lint */ 337*da14cebeSEric Cheng 338*da14cebeSEric Cheng /* Install signal handlers */ 339*da14cebeSEric Cheng (void) signal(SIGINT, sig_break); 340*da14cebeSEric Cheng (void) signal(SIGQUIT, sig_break); 341*da14cebeSEric Cheng (void) signal(SIGTERM, sig_break); 342*da14cebeSEric Cheng (void) signal(SIGWINCH, sig_resize); 343*da14cebeSEric Cheng 344*da14cebeSEric Cheng /* Initialize ncurses */ 345*da14cebeSEric Cheng (void) initscr(); 346*da14cebeSEric Cheng (void) cbreak(); 347*da14cebeSEric Cheng (void) noecho(); 348*da14cebeSEric Cheng (void) curs_set(0); 349*da14cebeSEric Cheng timeout(0); 350*da14cebeSEric Cheng getmaxyx(stdscr, maxy, maxx); 351*da14cebeSEric Cheng } 352*da14cebeSEric Cheng 353*da14cebeSEric Cheng static void 354*da14cebeSEric Cheng curses_fin() 355*da14cebeSEric Cheng { 356*da14cebeSEric Cheng (void) printw("\n"); 357*da14cebeSEric Cheng (void) curs_set(1); 358*da14cebeSEric Cheng (void) nocbreak(); 359*da14cebeSEric Cheng (void) endwin(); 360*da14cebeSEric Cheng 361*da14cebeSEric Cheng free(stattable); 362*da14cebeSEric Cheng } 363*da14cebeSEric Cheng 364*da14cebeSEric Cheng static void 365*da14cebeSEric Cheng stat_report(kstat_ctl_t *kcp, datalink_id_t linkid, const char *flowname, 366*da14cebeSEric Cheng int opt) 367*da14cebeSEric Cheng { 368*da14cebeSEric Cheng 369*da14cebeSEric Cheng double dlt, ikbs, okbs, ipks, opks; 370*da14cebeSEric Cheng 371*da14cebeSEric Cheng struct flowlist *fstable = stattable; 372*da14cebeSEric Cheng 373*da14cebeSEric Cheng if ((opt != LINK_REPORT) && (opt != FLOW_REPORT)) 374*da14cebeSEric Cheng return; 375*da14cebeSEric Cheng 376*da14cebeSEric Cheng /* Handle window resizes */ 377*da14cebeSEric Cheng if (handle_resize) { 378*da14cebeSEric Cheng (void) endwin(); 379*da14cebeSEric Cheng (void) initscr(); 380*da14cebeSEric Cheng (void) cbreak(); 381*da14cebeSEric Cheng (void) noecho(); 382*da14cebeSEric Cheng (void) curs_set(0); 383*da14cebeSEric Cheng timeout(0); 384*da14cebeSEric Cheng getmaxyx(stdscr, maxy, maxx); 385*da14cebeSEric Cheng redraw = 1; 386*da14cebeSEric Cheng handle_resize = 0; 387*da14cebeSEric Cheng } 388*da14cebeSEric Cheng 389*da14cebeSEric Cheng /* Print title */ 390*da14cebeSEric Cheng (void) erase(); 391*da14cebeSEric Cheng (void) attron(A_BOLD); 392*da14cebeSEric Cheng (void) move(0, 0); 393*da14cebeSEric Cheng if (opt == FLOW_REPORT) 394*da14cebeSEric Cheng (void) printw("%-15.15s", "Flow"); 395*da14cebeSEric Cheng (void) printw("%-10.10s", "Link"); 396*da14cebeSEric Cheng (void) printw("%9.9s %9.9s %9.9s %9.9s ", 397*da14cebeSEric Cheng "iKb/s", "oKb/s", "iPk/s", "oPk/s"); 398*da14cebeSEric Cheng if (opt == LINK_REPORT) 399*da14cebeSEric Cheng (void) printw(" %6.6s", "%Util"); 400*da14cebeSEric Cheng (void) printw("\n"); 401*da14cebeSEric Cheng (void) attroff(A_BOLD); 402*da14cebeSEric Cheng 403*da14cebeSEric Cheng (void) move(2, 0); 404*da14cebeSEric Cheng 405*da14cebeSEric Cheng /* Print stats for each link or flow */ 406*da14cebeSEric Cheng bzero(&totalstats, sizeof (totalstats)); 407*da14cebeSEric Cheng if (opt == LINK_REPORT) { 408*da14cebeSEric Cheng /* Display all links */ 409*da14cebeSEric Cheng if (linkid == DATALINK_ALL_LINKID) { 410*da14cebeSEric Cheng (void) dladm_walk_datalink_id(link_kstats, 411*da14cebeSEric Cheng (void *)kcp, DATALINK_CLASS_ALL, 412*da14cebeSEric Cheng DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 413*da14cebeSEric Cheng /* Display 1 link */ 414*da14cebeSEric Cheng } else { 415*da14cebeSEric Cheng (void) link_kstats(linkid, kcp); 416*da14cebeSEric Cheng } 417*da14cebeSEric Cheng print_link_stats(fstable); 418*da14cebeSEric Cheng 419*da14cebeSEric Cheng } else if (opt == FLOW_REPORT) { 420*da14cebeSEric Cheng /* Display 1 flow */ 421*da14cebeSEric Cheng if (flowname != NULL) { 422*da14cebeSEric Cheng dladm_flow_attr_t fattr; 423*da14cebeSEric Cheng if (dladm_flow_info(flowname, &fattr) != 424*da14cebeSEric Cheng DLADM_STATUS_OK) 425*da14cebeSEric Cheng return; 426*da14cebeSEric Cheng (void) flow_kstats(&fattr, kcp); 427*da14cebeSEric Cheng /* Display all flows on all links */ 428*da14cebeSEric Cheng } else if (linkid == DATALINK_ALL_LINKID) { 429*da14cebeSEric Cheng (void) dladm_walk_datalink_id(link_flowstats, 430*da14cebeSEric Cheng (void *)kcp, DATALINK_CLASS_ALL, 431*da14cebeSEric Cheng DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 432*da14cebeSEric Cheng /* Display all flows on a link */ 433*da14cebeSEric Cheng } else if (linkid != DATALINK_INVALID_LINKID) { 434*da14cebeSEric Cheng (void) dladm_walk_flow(flow_kstats, linkid, kcp, 435*da14cebeSEric Cheng B_FALSE); 436*da14cebeSEric Cheng } 437*da14cebeSEric Cheng print_flow_stats(fstable); 438*da14cebeSEric Cheng 439*da14cebeSEric Cheng /* Print totals */ 440*da14cebeSEric Cheng (void) attron(A_BOLD); 441*da14cebeSEric Cheng dlt = (double)totalstats.snaptime / (double)NANOSEC; 442*da14cebeSEric Cheng ikbs = totalstats.rbytes / dlt / 1024; 443*da14cebeSEric Cheng okbs = totalstats.obytes / dlt / 1024; 444*da14cebeSEric Cheng ipks = totalstats.ipackets / dlt; 445*da14cebeSEric Cheng opks = totalstats.opackets / dlt; 446*da14cebeSEric Cheng (void) printw("\n%-25.25s", "Totals"); 447*da14cebeSEric Cheng (void) printw("%9.2f %9.2f %9.2f %9.2f ", 448*da14cebeSEric Cheng ikbs, okbs, ipks, opks); 449*da14cebeSEric Cheng (void) attroff(A_BOLD); 450*da14cebeSEric Cheng } 451*da14cebeSEric Cheng 452*da14cebeSEric Cheng if (redraw) 453*da14cebeSEric Cheng (void) clearok(stdscr, 1); 454*da14cebeSEric Cheng 455*da14cebeSEric Cheng if (refresh() == ERR) 456*da14cebeSEric Cheng return; 457*da14cebeSEric Cheng 458*da14cebeSEric Cheng if (redraw) { 459*da14cebeSEric Cheng (void) clearok(stdscr, 0); 460*da14cebeSEric Cheng redraw = 0; 461*da14cebeSEric Cheng } 462*da14cebeSEric Cheng } 463*da14cebeSEric Cheng 464*da14cebeSEric Cheng /* Exported functions */ 465*da14cebeSEric Cheng 466*da14cebeSEric Cheng /* 467*da14cebeSEric Cheng * Continuously display link or flow statstics using a libcurses 468*da14cebeSEric Cheng * based display. 469*da14cebeSEric Cheng */ 470*da14cebeSEric Cheng 471*da14cebeSEric Cheng void 472*da14cebeSEric Cheng dladm_continuous(datalink_id_t linkid, const char *flowname, int interval, 473*da14cebeSEric Cheng int opt) 474*da14cebeSEric Cheng { 475*da14cebeSEric Cheng kstat_ctl_t *kcp; 476*da14cebeSEric Cheng 477*da14cebeSEric Cheng if ((kcp = kstat_open()) == NULL) { 478*da14cebeSEric Cheng warn("kstat open operation failed"); 479*da14cebeSEric Cheng return; 480*da14cebeSEric Cheng } 481*da14cebeSEric Cheng 482*da14cebeSEric Cheng curses_init(); 483*da14cebeSEric Cheng 484*da14cebeSEric Cheng for (;;) { 485*da14cebeSEric Cheng 486*da14cebeSEric Cheng if (handle_break) 487*da14cebeSEric Cheng break; 488*da14cebeSEric Cheng 489*da14cebeSEric Cheng stat_report(kcp, linkid, flowname, opt); 490*da14cebeSEric Cheng 491*da14cebeSEric Cheng (void) sleep(max(1, interval)); 492*da14cebeSEric Cheng } 493*da14cebeSEric Cheng 494*da14cebeSEric Cheng (void) curses_fin(); 495*da14cebeSEric Cheng (void) kstat_close(kcp); 496*da14cebeSEric Cheng } 497*da14cebeSEric Cheng 498*da14cebeSEric Cheng /* 499*da14cebeSEric Cheng * dladm_kstat_lookup() is a modified version of kstat_lookup which 500*da14cebeSEric Cheng * adds the class as a selector. 501*da14cebeSEric Cheng */ 502*da14cebeSEric Cheng 503*da14cebeSEric Cheng kstat_t * 504*da14cebeSEric Cheng dladm_kstat_lookup(kstat_ctl_t *kcp, const char *module, int instance, 505*da14cebeSEric Cheng const char *name, const char *class) 506*da14cebeSEric Cheng { 507*da14cebeSEric Cheng kstat_t *ksp = NULL; 508*da14cebeSEric Cheng 509*da14cebeSEric Cheng for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 510*da14cebeSEric Cheng if ((module == NULL || strcmp(ksp->ks_module, module) == 0) && 511*da14cebeSEric Cheng (instance == -1 || ksp->ks_instance == instance) && 512*da14cebeSEric Cheng (name == NULL || strcmp(ksp->ks_name, name) == 0) && 513*da14cebeSEric Cheng (class == NULL || strcmp(ksp->ks_class, class) == 0)) 514*da14cebeSEric Cheng return (ksp); 515*da14cebeSEric Cheng } 516*da14cebeSEric Cheng 517*da14cebeSEric Cheng errno = ENOENT; 518*da14cebeSEric Cheng return (NULL); 519*da14cebeSEric Cheng } 520*da14cebeSEric Cheng 521*da14cebeSEric Cheng /* 522*da14cebeSEric Cheng * dladm_get_stats() populates the supplied pktsum_t structure with 523*da14cebeSEric Cheng * the input and output packet and byte kstats from the kstat_t 524*da14cebeSEric Cheng * found with dladm_kstat_lookup. 525*da14cebeSEric Cheng */ 526*da14cebeSEric Cheng void 527*da14cebeSEric Cheng dladm_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, pktsum_t *stats) 528*da14cebeSEric Cheng { 529*da14cebeSEric Cheng 530*da14cebeSEric Cheng if (kstat_read(kcp, ksp, NULL) == -1) 531*da14cebeSEric Cheng return; 532*da14cebeSEric Cheng 533*da14cebeSEric Cheng stats->snaptime = gethrtime(); 534*da14cebeSEric Cheng 535*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 536*da14cebeSEric Cheng &stats->ipackets) < 0) { 537*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ipackets", KSTAT_DATA_UINT64, 538*da14cebeSEric Cheng &stats->ipackets) < 0) 539*da14cebeSEric Cheng return; 540*da14cebeSEric Cheng } 541*da14cebeSEric Cheng 542*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 543*da14cebeSEric Cheng &stats->opackets) < 0) { 544*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "opackets", KSTAT_DATA_UINT64, 545*da14cebeSEric Cheng &stats->opackets) < 0) 546*da14cebeSEric Cheng return; 547*da14cebeSEric Cheng } 548*da14cebeSEric Cheng 549*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 550*da14cebeSEric Cheng &stats->rbytes) < 0) { 551*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "rbytes", KSTAT_DATA_UINT64, 552*da14cebeSEric Cheng &stats->rbytes) < 0) 553*da14cebeSEric Cheng return; 554*da14cebeSEric Cheng } 555*da14cebeSEric Cheng 556*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 557*da14cebeSEric Cheng &stats->obytes) < 0) { 558*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "obytes", KSTAT_DATA_UINT64, 559*da14cebeSEric Cheng &stats->obytes) < 0) 560*da14cebeSEric Cheng return; 561*da14cebeSEric Cheng } 562*da14cebeSEric Cheng 563*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 564*da14cebeSEric Cheng &stats->ierrors) < 0) { 565*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT64, 566*da14cebeSEric Cheng &stats->ierrors) < 0) 567*da14cebeSEric Cheng return; 568*da14cebeSEric Cheng } 569*da14cebeSEric Cheng 570*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 571*da14cebeSEric Cheng &stats->oerrors) < 0) { 572*da14cebeSEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT64, 573*da14cebeSEric Cheng &stats->oerrors) < 0) 574*da14cebeSEric Cheng return; 575*da14cebeSEric Cheng } 576*da14cebeSEric Cheng } 577*da14cebeSEric Cheng 578*da14cebeSEric Cheng int 579*da14cebeSEric Cheng dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 580*da14cebeSEric Cheng { 581*da14cebeSEric Cheng kstat_named_t *knp; 582*da14cebeSEric Cheng 583*da14cebeSEric Cheng if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 584*da14cebeSEric Cheng return (-1); 585*da14cebeSEric Cheng 586*da14cebeSEric Cheng if (knp->data_type != type) 587*da14cebeSEric Cheng return (-1); 588*da14cebeSEric Cheng 589*da14cebeSEric Cheng switch (type) { 590*da14cebeSEric Cheng case KSTAT_DATA_UINT64: 591*da14cebeSEric Cheng *(uint64_t *)buf = knp->value.ui64; 592*da14cebeSEric Cheng break; 593*da14cebeSEric Cheng case KSTAT_DATA_UINT32: 594*da14cebeSEric Cheng *(uint32_t *)buf = knp->value.ui32; 595*da14cebeSEric Cheng break; 596*da14cebeSEric Cheng default: 597*da14cebeSEric Cheng return (-1); 598*da14cebeSEric Cheng } 599*da14cebeSEric Cheng 600*da14cebeSEric Cheng return (0); 601*da14cebeSEric Cheng } 602*da14cebeSEric Cheng 603*da14cebeSEric Cheng dladm_status_t 604*da14cebeSEric Cheng dladm_get_single_mac_stat(datalink_id_t linkid, const char *name, uint8_t type, 605*da14cebeSEric Cheng void *val) 606*da14cebeSEric Cheng { 607*da14cebeSEric Cheng kstat_ctl_t *kcp; 608*da14cebeSEric Cheng char module[DLPI_LINKNAME_MAX]; 609*da14cebeSEric Cheng uint_t instance; 610*da14cebeSEric Cheng char link[DLPI_LINKNAME_MAX]; 611*da14cebeSEric Cheng dladm_status_t status; 612*da14cebeSEric Cheng uint32_t flags, media; 613*da14cebeSEric Cheng kstat_t *ksp; 614*da14cebeSEric Cheng dladm_phys_attr_t dpap; 615*da14cebeSEric Cheng 616*da14cebeSEric Cheng if ((kcp = kstat_open()) == NULL) { 617*da14cebeSEric Cheng warn("kstat_open operation failed"); 618*da14cebeSEric Cheng return (-1); 619*da14cebeSEric Cheng } 620*da14cebeSEric Cheng 621*da14cebeSEric Cheng if ((status = dladm_datalink_id2info(linkid, &flags, NULL, &media, 622*da14cebeSEric Cheng link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) 623*da14cebeSEric Cheng return (status); 624*da14cebeSEric Cheng 625*da14cebeSEric Cheng if (media != DL_ETHER) 626*da14cebeSEric Cheng return (DLADM_STATUS_LINKINVAL); 627*da14cebeSEric Cheng 628*da14cebeSEric Cheng status = dladm_phys_info(linkid, &dpap, DLADM_OPT_PERSIST); 629*da14cebeSEric Cheng 630*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 631*da14cebeSEric Cheng return (status); 632*da14cebeSEric Cheng 633*da14cebeSEric Cheng status = dladm_parselink(dpap.dp_dev, module, &instance); 634*da14cebeSEric Cheng 635*da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 636*da14cebeSEric Cheng return (status); 637*da14cebeSEric Cheng 638*da14cebeSEric Cheng /* 639*da14cebeSEric Cheng * The kstat query could fail if the underlying MAC 640*da14cebeSEric Cheng * driver was already detached. 641*da14cebeSEric Cheng */ 642*da14cebeSEric Cheng if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 643*da14cebeSEric Cheng (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) 644*da14cebeSEric Cheng goto bail; 645*da14cebeSEric Cheng 646*da14cebeSEric Cheng if (kstat_read(kcp, ksp, NULL) == -1) 647*da14cebeSEric Cheng goto bail; 648*da14cebeSEric Cheng 649*da14cebeSEric Cheng if (dladm_kstat_value(ksp, name, type, val) < 0) 650*da14cebeSEric Cheng goto bail; 651*da14cebeSEric Cheng 652*da14cebeSEric Cheng (void) kstat_close(kcp); 653*da14cebeSEric Cheng return (DLADM_STATUS_OK); 654*da14cebeSEric Cheng 655*da14cebeSEric Cheng bail: 656*da14cebeSEric Cheng (void) kstat_close(kcp); 657*da14cebeSEric Cheng return (dladm_errno2status(errno)); 658*da14cebeSEric Cheng } 659*da14cebeSEric Cheng 660*da14cebeSEric Cheng /* Compute sum of 2 pktsums (s1 = s2 + s3) */ 661*da14cebeSEric Cheng void 662*da14cebeSEric Cheng dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 663*da14cebeSEric Cheng { 664*da14cebeSEric Cheng s1->rbytes = s2->rbytes + s3->rbytes; 665*da14cebeSEric Cheng s1->ipackets = s2->ipackets + s3->ipackets; 666*da14cebeSEric Cheng s1->ierrors = s2->ierrors + s3->ierrors; 667*da14cebeSEric Cheng s1->obytes = s2->obytes + s3->obytes; 668*da14cebeSEric Cheng s1->opackets = s2->opackets + s3->opackets; 669*da14cebeSEric Cheng s1->oerrors = s2->oerrors + s3->oerrors; 670*da14cebeSEric Cheng s1->snaptime = s2->snaptime; 671*da14cebeSEric Cheng } 672*da14cebeSEric Cheng 673*da14cebeSEric Cheng /* Compute differences between 2 pktsums (s1 = s2 - s3) */ 674*da14cebeSEric Cheng void 675*da14cebeSEric Cheng dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 676*da14cebeSEric Cheng { 677*da14cebeSEric Cheng s1->rbytes = s2->rbytes - s3->rbytes; 678*da14cebeSEric Cheng s1->ipackets = s2->ipackets - s3->ipackets; 679*da14cebeSEric Cheng s1->ierrors = s2->ierrors - s3->ierrors; 680*da14cebeSEric Cheng s1->obytes = s2->obytes - s3->obytes; 681*da14cebeSEric Cheng s1->opackets = s2->opackets - s3->opackets; 682*da14cebeSEric Cheng s1->oerrors = s2->oerrors - s3->oerrors; 683*da14cebeSEric Cheng s1->snaptime = s2->snaptime - s3->snaptime; 684*da14cebeSEric Cheng } 685