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