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