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 /* 22*da000602SGirish 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 { 50*da000602SGirish Moodalbail char flowname[MAXFLOWNAMELEN]; 51da14cebeSEric Cheng datalink_id_t linkid; 52da14cebeSEric Cheng uint_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) { 94*da000602SGirish 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) 123*da000602SGirish 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) { 148*da000602SGirish 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) { 229*da000602SGirish 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 { 2634ac67f02SAnurag S. Maskey return (dladm_walk_flow(flow_kstats, handle, linkid, arg, B_FALSE)); 264da14cebeSEric Cheng } 265da14cebeSEric Cheng 266da14cebeSEric Cheng /*ARGSUSED*/ 267da14cebeSEric Cheng static int 2684ac67f02SAnurag S. Maskey link_kstats(dladm_handle_t handle, datalink_id_t linkid, void *arg) 269da14cebeSEric Cheng { 270da14cebeSEric Cheng kstat_ctl_t *kcp = (kstat_ctl_t *)arg; 271da14cebeSEric Cheng struct flowlist *flist; 272da14cebeSEric Cheng pktsum_t currstats, *prevstats, *diffstats; 273da14cebeSEric Cheng kstat_t *ksp; 274*da000602SGirish Moodalbail char linkname[MAXLINKNAMELEN]; 275da14cebeSEric Cheng 276da14cebeSEric Cheng /* find the flist entry */ 277da14cebeSEric Cheng flist = findstat(NULL, linkid); 278da14cebeSEric Cheng if (flist != NULL) { 279da14cebeSEric Cheng prevstats = &flist->prevstats; 280da14cebeSEric Cheng diffstats = &flist->diffstats; 281da14cebeSEric Cheng } else { 282da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 283da14cebeSEric Cheng } 284da14cebeSEric Cheng 285da14cebeSEric Cheng /* lookup kstat entry */ 2864ac67f02SAnurag S. Maskey (void) dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL, 2874ac67f02SAnurag S. Maskey linkname, sizeof (linkname)); 288da14cebeSEric Cheng 289da14cebeSEric Cheng if (linkname == NULL) { 290da14cebeSEric Cheng warn("no linkname for linkid"); 291da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 292da14cebeSEric Cheng } 293da14cebeSEric Cheng 294da14cebeSEric Cheng ksp = dladm_kstat_lookup(kcp, NULL, -1, linkname, "net"); 295da14cebeSEric Cheng 296da14cebeSEric Cheng if (ksp == NULL) 297da14cebeSEric Cheng return (DLADM_WALK_TERMINATE); 298da14cebeSEric Cheng else 299da14cebeSEric Cheng flist->display = B_TRUE; 300da14cebeSEric Cheng 301da14cebeSEric Cheng /* read packet and byte stats */ 302da14cebeSEric Cheng dladm_get_stats(kcp, ksp, &currstats); 303da14cebeSEric Cheng 304da14cebeSEric Cheng if (flist->ifspeed == 0) 305da14cebeSEric Cheng (void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64, 306da14cebeSEric Cheng &flist->ifspeed); 307da14cebeSEric Cheng 308da14cebeSEric Cheng if (flist->first == B_TRUE) 309da14cebeSEric Cheng flist->first = B_FALSE; 310da14cebeSEric Cheng else 311da14cebeSEric Cheng dladm_stats_diff(diffstats, &currstats, prevstats); 312da14cebeSEric Cheng 313da14cebeSEric Cheng bcopy(&currstats, prevstats, sizeof (*prevstats)); 314da14cebeSEric Cheng 315da14cebeSEric Cheng return (DLADM_WALK_CONTINUE); 316da14cebeSEric Cheng } 317da14cebeSEric Cheng 318da14cebeSEric Cheng /*ARGSUSED*/ 319da14cebeSEric Cheng static void 320da14cebeSEric Cheng sig_break(int s) 321da14cebeSEric Cheng { 322da14cebeSEric Cheng handle_break = 1; 323da14cebeSEric Cheng } 324da14cebeSEric Cheng 325da14cebeSEric Cheng /*ARGSUSED*/ 326da14cebeSEric Cheng static void 327da14cebeSEric Cheng sig_resize(int s) 328da14cebeSEric Cheng { 329da14cebeSEric Cheng handle_resize = 1; 330da14cebeSEric Cheng } 331da14cebeSEric Cheng 332da14cebeSEric Cheng static void 333da14cebeSEric Cheng curses_init() 334da14cebeSEric Cheng { 335da14cebeSEric Cheng maxx = maxx; /* lint */ 336da14cebeSEric Cheng maxy = maxy; /* lint */ 337da14cebeSEric Cheng 338da14cebeSEric Cheng /* Install signal handlers */ 339da14cebeSEric Cheng (void) signal(SIGINT, sig_break); 340da14cebeSEric Cheng (void) signal(SIGQUIT, sig_break); 341da14cebeSEric Cheng (void) signal(SIGTERM, sig_break); 342da14cebeSEric Cheng (void) signal(SIGWINCH, sig_resize); 343da14cebeSEric Cheng 344da14cebeSEric Cheng /* Initialize ncurses */ 345da14cebeSEric Cheng (void) initscr(); 346da14cebeSEric Cheng (void) cbreak(); 347da14cebeSEric Cheng (void) noecho(); 348da14cebeSEric Cheng (void) curs_set(0); 349da14cebeSEric Cheng timeout(0); 350da14cebeSEric Cheng getmaxyx(stdscr, maxy, maxx); 351da14cebeSEric Cheng } 352da14cebeSEric Cheng 353da14cebeSEric Cheng static void 354da14cebeSEric Cheng curses_fin() 355da14cebeSEric Cheng { 356da14cebeSEric Cheng (void) printw("\n"); 357da14cebeSEric Cheng (void) curs_set(1); 358da14cebeSEric Cheng (void) nocbreak(); 359da14cebeSEric Cheng (void) endwin(); 360da14cebeSEric Cheng 361da14cebeSEric Cheng free(stattable); 362da14cebeSEric Cheng } 363da14cebeSEric Cheng 364da14cebeSEric Cheng static void 3654ac67f02SAnurag S. Maskey stat_report(dladm_handle_t handle, kstat_ctl_t *kcp, datalink_id_t linkid, 3664ac67f02SAnurag S. Maskey const char *flowname, int opt) 367da14cebeSEric Cheng { 368da14cebeSEric Cheng 369da14cebeSEric Cheng double dlt, ikbs, okbs, ipks, opks; 370da14cebeSEric Cheng 371da14cebeSEric Cheng struct flowlist *fstable = stattable; 372da14cebeSEric Cheng 373da14cebeSEric Cheng if ((opt != LINK_REPORT) && (opt != FLOW_REPORT)) 374da14cebeSEric Cheng return; 375da14cebeSEric Cheng 376da14cebeSEric Cheng /* Handle window resizes */ 377da14cebeSEric Cheng if (handle_resize) { 378da14cebeSEric Cheng (void) endwin(); 379da14cebeSEric Cheng (void) initscr(); 380da14cebeSEric Cheng (void) cbreak(); 381da14cebeSEric Cheng (void) noecho(); 382da14cebeSEric Cheng (void) curs_set(0); 383da14cebeSEric Cheng timeout(0); 384da14cebeSEric Cheng getmaxyx(stdscr, maxy, maxx); 385da14cebeSEric Cheng redraw = 1; 386da14cebeSEric Cheng handle_resize = 0; 387da14cebeSEric Cheng } 388da14cebeSEric Cheng 389da14cebeSEric Cheng /* Print title */ 390da14cebeSEric Cheng (void) erase(); 391da14cebeSEric Cheng (void) attron(A_BOLD); 392da14cebeSEric Cheng (void) move(0, 0); 393da14cebeSEric Cheng if (opt == FLOW_REPORT) 394da14cebeSEric Cheng (void) printw("%-15.15s", "Flow"); 395da14cebeSEric Cheng (void) printw("%-10.10s", "Link"); 396da14cebeSEric Cheng (void) printw("%9.9s %9.9s %9.9s %9.9s ", 397da14cebeSEric Cheng "iKb/s", "oKb/s", "iPk/s", "oPk/s"); 398da14cebeSEric Cheng if (opt == LINK_REPORT) 399da14cebeSEric Cheng (void) printw(" %6.6s", "%Util"); 400da14cebeSEric Cheng (void) printw("\n"); 401da14cebeSEric Cheng (void) attroff(A_BOLD); 402da14cebeSEric Cheng 403da14cebeSEric Cheng (void) move(2, 0); 404da14cebeSEric Cheng 405da14cebeSEric Cheng /* Print stats for each link or flow */ 406da14cebeSEric Cheng bzero(&totalstats, sizeof (totalstats)); 407da14cebeSEric Cheng if (opt == LINK_REPORT) { 408da14cebeSEric Cheng /* Display all links */ 409da14cebeSEric Cheng if (linkid == DATALINK_ALL_LINKID) { 4104ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(link_kstats, handle, 411da14cebeSEric Cheng (void *)kcp, DATALINK_CLASS_ALL, 412da14cebeSEric Cheng DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 413da14cebeSEric Cheng /* Display 1 link */ 414da14cebeSEric Cheng } else { 4154ac67f02SAnurag S. Maskey (void) link_kstats(handle, linkid, kcp); 416da14cebeSEric Cheng } 4174ac67f02SAnurag S. Maskey print_link_stats(handle, fstable); 418da14cebeSEric Cheng 419da14cebeSEric Cheng } else if (opt == FLOW_REPORT) { 420da14cebeSEric Cheng /* Display 1 flow */ 421da14cebeSEric Cheng if (flowname != NULL) { 422da14cebeSEric Cheng dladm_flow_attr_t fattr; 4234ac67f02SAnurag S. Maskey if (dladm_flow_info(handle, flowname, &fattr) != 424da14cebeSEric Cheng DLADM_STATUS_OK) 425da14cebeSEric Cheng return; 426da14cebeSEric Cheng (void) flow_kstats(&fattr, kcp); 427da14cebeSEric Cheng /* Display all flows on all links */ 428da14cebeSEric Cheng } else if (linkid == DATALINK_ALL_LINKID) { 4294ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(link_flowstats, handle, 430da14cebeSEric Cheng (void *)kcp, DATALINK_CLASS_ALL, 431da14cebeSEric Cheng DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 432da14cebeSEric Cheng /* Display all flows on a link */ 433da14cebeSEric Cheng } else if (linkid != DATALINK_INVALID_LINKID) { 4344ac67f02SAnurag S. Maskey (void) dladm_walk_flow(flow_kstats, handle, linkid, kcp, 435da14cebeSEric Cheng B_FALSE); 436da14cebeSEric Cheng } 4374ac67f02SAnurag S. Maskey print_flow_stats(handle, fstable); 438da14cebeSEric Cheng 439da14cebeSEric Cheng /* Print totals */ 440da14cebeSEric Cheng (void) attron(A_BOLD); 441da14cebeSEric Cheng dlt = (double)totalstats.snaptime / (double)NANOSEC; 442da14cebeSEric Cheng ikbs = totalstats.rbytes / dlt / 1024; 443da14cebeSEric Cheng okbs = totalstats.obytes / dlt / 1024; 444da14cebeSEric Cheng ipks = totalstats.ipackets / dlt; 445da14cebeSEric Cheng opks = totalstats.opackets / dlt; 446da14cebeSEric Cheng (void) printw("\n%-25.25s", "Totals"); 447da14cebeSEric Cheng (void) printw("%9.2f %9.2f %9.2f %9.2f ", 448da14cebeSEric Cheng ikbs, okbs, ipks, opks); 449da14cebeSEric Cheng (void) attroff(A_BOLD); 450da14cebeSEric Cheng } 451da14cebeSEric Cheng 452da14cebeSEric Cheng if (redraw) 453da14cebeSEric Cheng (void) clearok(stdscr, 1); 454da14cebeSEric Cheng 455da14cebeSEric Cheng if (refresh() == ERR) 456da14cebeSEric Cheng return; 457da14cebeSEric Cheng 458da14cebeSEric Cheng if (redraw) { 459da14cebeSEric Cheng (void) clearok(stdscr, 0); 460da14cebeSEric Cheng redraw = 0; 461da14cebeSEric Cheng } 462da14cebeSEric Cheng } 463da14cebeSEric Cheng 464da14cebeSEric Cheng /* Exported functions */ 465da14cebeSEric Cheng 466da14cebeSEric Cheng /* 467da14cebeSEric Cheng * Continuously display link or flow statstics using a libcurses 468da14cebeSEric Cheng * based display. 469da14cebeSEric Cheng */ 470da14cebeSEric Cheng 471da14cebeSEric Cheng void 4724ac67f02SAnurag S. Maskey dladm_continuous(dladm_handle_t handle, datalink_id_t linkid, 4734ac67f02SAnurag S. Maskey const char *flowname, int interval, int opt) 474da14cebeSEric Cheng { 475da14cebeSEric Cheng kstat_ctl_t *kcp; 476da14cebeSEric Cheng 477da14cebeSEric Cheng if ((kcp = kstat_open()) == NULL) { 478da14cebeSEric Cheng warn("kstat open operation failed"); 479da14cebeSEric Cheng return; 480da14cebeSEric Cheng } 481da14cebeSEric Cheng 482da14cebeSEric Cheng curses_init(); 483da14cebeSEric Cheng 484da14cebeSEric Cheng for (;;) { 485da14cebeSEric Cheng 486da14cebeSEric Cheng if (handle_break) 487da14cebeSEric Cheng break; 488da14cebeSEric Cheng 4894ac67f02SAnurag S. Maskey stat_report(handle, kcp, linkid, flowname, opt); 490da14cebeSEric Cheng 491da14cebeSEric Cheng (void) sleep(max(1, interval)); 492da14cebeSEric Cheng } 493da14cebeSEric Cheng 494da14cebeSEric Cheng (void) curses_fin(); 495da14cebeSEric Cheng (void) kstat_close(kcp); 496da14cebeSEric Cheng } 497da14cebeSEric Cheng 498da14cebeSEric Cheng /* 499da14cebeSEric Cheng * dladm_kstat_lookup() is a modified version of kstat_lookup which 500da14cebeSEric Cheng * adds the class as a selector. 501da14cebeSEric Cheng */ 502da14cebeSEric Cheng 503da14cebeSEric Cheng kstat_t * 504da14cebeSEric Cheng dladm_kstat_lookup(kstat_ctl_t *kcp, const char *module, int instance, 505da14cebeSEric Cheng const char *name, const char *class) 506da14cebeSEric Cheng { 507da14cebeSEric Cheng kstat_t *ksp = NULL; 508da14cebeSEric Cheng 509da14cebeSEric Cheng for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 510da14cebeSEric Cheng if ((module == NULL || strcmp(ksp->ks_module, module) == 0) && 511da14cebeSEric Cheng (instance == -1 || ksp->ks_instance == instance) && 512da14cebeSEric Cheng (name == NULL || strcmp(ksp->ks_name, name) == 0) && 513da14cebeSEric Cheng (class == NULL || strcmp(ksp->ks_class, class) == 0)) 514da14cebeSEric Cheng return (ksp); 515da14cebeSEric Cheng } 516da14cebeSEric Cheng 517da14cebeSEric Cheng errno = ENOENT; 518da14cebeSEric Cheng return (NULL); 519da14cebeSEric Cheng } 520da14cebeSEric Cheng 521da14cebeSEric Cheng /* 522da14cebeSEric Cheng * dladm_get_stats() populates the supplied pktsum_t structure with 523da14cebeSEric Cheng * the input and output packet and byte kstats from the kstat_t 524da14cebeSEric Cheng * found with dladm_kstat_lookup. 525da14cebeSEric Cheng */ 526da14cebeSEric Cheng void 527da14cebeSEric Cheng dladm_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, pktsum_t *stats) 528da14cebeSEric Cheng { 529da14cebeSEric Cheng 530da14cebeSEric Cheng if (kstat_read(kcp, ksp, NULL) == -1) 531da14cebeSEric Cheng return; 532da14cebeSEric Cheng 533da14cebeSEric Cheng stats->snaptime = gethrtime(); 534da14cebeSEric Cheng 535da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 536da14cebeSEric Cheng &stats->ipackets) < 0) { 537da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ipackets", KSTAT_DATA_UINT64, 538da14cebeSEric Cheng &stats->ipackets) < 0) 539da14cebeSEric Cheng return; 540da14cebeSEric Cheng } 541da14cebeSEric Cheng 542da14cebeSEric Cheng if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 543da14cebeSEric Cheng &stats->opackets) < 0) { 544da14cebeSEric Cheng if (dladm_kstat_value(ksp, "opackets", KSTAT_DATA_UINT64, 545da14cebeSEric Cheng &stats->opackets) < 0) 546da14cebeSEric Cheng return; 547da14cebeSEric Cheng } 548da14cebeSEric Cheng 549da14cebeSEric Cheng if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 550da14cebeSEric Cheng &stats->rbytes) < 0) { 551da14cebeSEric Cheng if (dladm_kstat_value(ksp, "rbytes", KSTAT_DATA_UINT64, 552da14cebeSEric Cheng &stats->rbytes) < 0) 553da14cebeSEric Cheng return; 554da14cebeSEric Cheng } 555da14cebeSEric Cheng 556da14cebeSEric Cheng if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 557da14cebeSEric Cheng &stats->obytes) < 0) { 558da14cebeSEric Cheng if (dladm_kstat_value(ksp, "obytes", KSTAT_DATA_UINT64, 559da14cebeSEric Cheng &stats->obytes) < 0) 560da14cebeSEric Cheng return; 561da14cebeSEric Cheng } 562da14cebeSEric Cheng 563da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 564da14cebeSEric Cheng &stats->ierrors) < 0) { 565da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT64, 566da14cebeSEric Cheng &stats->ierrors) < 0) 567da14cebeSEric Cheng return; 568da14cebeSEric Cheng } 569da14cebeSEric Cheng 570da14cebeSEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 571da14cebeSEric Cheng &stats->oerrors) < 0) { 572da14cebeSEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT64, 573da14cebeSEric Cheng &stats->oerrors) < 0) 574da14cebeSEric Cheng return; 575da14cebeSEric Cheng } 576da14cebeSEric Cheng } 577da14cebeSEric Cheng 578da14cebeSEric Cheng int 579da14cebeSEric Cheng dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 580da14cebeSEric Cheng { 581da14cebeSEric Cheng kstat_named_t *knp; 582da14cebeSEric Cheng 583da14cebeSEric Cheng if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 584da14cebeSEric Cheng return (-1); 585da14cebeSEric Cheng 586da14cebeSEric Cheng if (knp->data_type != type) 587da14cebeSEric Cheng return (-1); 588da14cebeSEric Cheng 589da14cebeSEric Cheng switch (type) { 590da14cebeSEric Cheng case KSTAT_DATA_UINT64: 591da14cebeSEric Cheng *(uint64_t *)buf = knp->value.ui64; 592da14cebeSEric Cheng break; 593da14cebeSEric Cheng case KSTAT_DATA_UINT32: 594da14cebeSEric Cheng *(uint32_t *)buf = knp->value.ui32; 595da14cebeSEric Cheng break; 596da14cebeSEric Cheng default: 597da14cebeSEric Cheng return (-1); 598da14cebeSEric Cheng } 599da14cebeSEric Cheng 600da14cebeSEric Cheng return (0); 601da14cebeSEric Cheng } 602da14cebeSEric Cheng 603da14cebeSEric Cheng dladm_status_t 6044ac67f02SAnurag S. Maskey dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid, 6054ac67f02SAnurag S. Maskey const char *name, uint8_t type, void *val) 606da14cebeSEric Cheng { 607da14cebeSEric Cheng kstat_ctl_t *kcp; 608da14cebeSEric Cheng char module[DLPI_LINKNAME_MAX]; 609da14cebeSEric Cheng uint_t instance; 610da14cebeSEric Cheng char link[DLPI_LINKNAME_MAX]; 611da14cebeSEric Cheng dladm_status_t status; 612da14cebeSEric Cheng uint32_t flags, media; 613da14cebeSEric Cheng kstat_t *ksp; 614da14cebeSEric Cheng dladm_phys_attr_t dpap; 615da14cebeSEric Cheng 616da14cebeSEric Cheng if ((kcp = kstat_open()) == NULL) { 617da14cebeSEric Cheng warn("kstat_open operation failed"); 618da14cebeSEric Cheng return (-1); 619da14cebeSEric Cheng } 620da14cebeSEric Cheng 6214ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 6224ac67f02SAnurag S. Maskey &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) 623da14cebeSEric Cheng return (status); 624da14cebeSEric Cheng 625da14cebeSEric Cheng if (media != DL_ETHER) 626da14cebeSEric Cheng return (DLADM_STATUS_LINKINVAL); 627da14cebeSEric Cheng 6284ac67f02SAnurag S. Maskey status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST); 629da14cebeSEric Cheng 630da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 631da14cebeSEric Cheng return (status); 632da14cebeSEric Cheng 633da14cebeSEric Cheng status = dladm_parselink(dpap.dp_dev, module, &instance); 634da14cebeSEric Cheng 635da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 636da14cebeSEric Cheng return (status); 637da14cebeSEric Cheng 638da14cebeSEric Cheng /* 639da14cebeSEric Cheng * The kstat query could fail if the underlying MAC 640da14cebeSEric Cheng * driver was already detached. 641da14cebeSEric Cheng */ 642da14cebeSEric Cheng if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 643da14cebeSEric Cheng (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) 644da14cebeSEric Cheng goto bail; 645da14cebeSEric Cheng 646da14cebeSEric Cheng if (kstat_read(kcp, ksp, NULL) == -1) 647da14cebeSEric Cheng goto bail; 648da14cebeSEric Cheng 649da14cebeSEric Cheng if (dladm_kstat_value(ksp, name, type, val) < 0) 650da14cebeSEric Cheng goto bail; 651da14cebeSEric Cheng 652da14cebeSEric Cheng (void) kstat_close(kcp); 653da14cebeSEric Cheng return (DLADM_STATUS_OK); 654da14cebeSEric Cheng 655da14cebeSEric Cheng bail: 656da14cebeSEric Cheng (void) kstat_close(kcp); 657da14cebeSEric Cheng return (dladm_errno2status(errno)); 658da14cebeSEric Cheng } 659da14cebeSEric Cheng 660da14cebeSEric Cheng /* Compute sum of 2 pktsums (s1 = s2 + s3) */ 661da14cebeSEric Cheng void 662da14cebeSEric Cheng dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 663da14cebeSEric Cheng { 664da14cebeSEric Cheng s1->rbytes = s2->rbytes + s3->rbytes; 665da14cebeSEric Cheng s1->ipackets = s2->ipackets + s3->ipackets; 666da14cebeSEric Cheng s1->ierrors = s2->ierrors + s3->ierrors; 667da14cebeSEric Cheng s1->obytes = s2->obytes + s3->obytes; 668da14cebeSEric Cheng s1->opackets = s2->opackets + s3->opackets; 669da14cebeSEric Cheng s1->oerrors = s2->oerrors + s3->oerrors; 670da14cebeSEric Cheng s1->snaptime = s2->snaptime; 671da14cebeSEric Cheng } 672da14cebeSEric Cheng 673da14cebeSEric Cheng /* Compute differences between 2 pktsums (s1 = s2 - s3) */ 674da14cebeSEric Cheng void 675da14cebeSEric Cheng dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 676da14cebeSEric Cheng { 677da14cebeSEric Cheng s1->rbytes = s2->rbytes - s3->rbytes; 678da14cebeSEric Cheng s1->ipackets = s2->ipackets - s3->ipackets; 679da14cebeSEric Cheng s1->ierrors = s2->ierrors - s3->ierrors; 680da14cebeSEric Cheng s1->obytes = s2->obytes - s3->obytes; 681da14cebeSEric Cheng s1->opackets = s2->opackets - s3->opackets; 682da14cebeSEric Cheng s1->oerrors = s2->oerrors - s3->oerrors; 683da14cebeSEric Cheng s1->snaptime = s2->snaptime - s3->snaptime; 684da14cebeSEric Cheng } 685