18275SEric Cheng /* 28275SEric Cheng * CDDL HEADER START 38275SEric Cheng * 48275SEric Cheng * The contents of this file are subject to the terms of the 58275SEric Cheng * Common Development and Distribution License (the "License"). 68275SEric Cheng * You may not use this file except in compliance with the License. 78275SEric Cheng * 88275SEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98275SEric Cheng * or http://www.opensolaris.org/os/licensing. 108275SEric Cheng * See the License for the specific language governing permissions 118275SEric Cheng * and limitations under the License. 128275SEric Cheng * 138275SEric Cheng * When distributing Covered Code, include this CDDL HEADER in each 148275SEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158275SEric Cheng * If applicable, add the following below this CDDL HEADER, with the 168275SEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying 178275SEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner] 188275SEric Cheng * 198275SEric Cheng * CDDL HEADER END 208275SEric Cheng */ 218275SEric Cheng /* 228558SGirish.Moodalbail@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 238275SEric Cheng * Use is subject to license terms. 248275SEric Cheng */ 258275SEric Cheng 268275SEric Cheng #include <stdio.h> 278275SEric Cheng #include <stdlib.h> 288275SEric Cheng #include <strings.h> 298275SEric Cheng #include <err.h> 308275SEric Cheng #include <errno.h> 318275SEric Cheng #include <kstat.h> 328275SEric Cheng #include <unistd.h> 338275SEric Cheng #include <signal.h> 348275SEric Cheng #include <sys/dld.h> 358275SEric Cheng 368275SEric Cheng #include <libdllink.h> 378275SEric Cheng #include <libdlflow.h> 388275SEric Cheng #include <libdlstat.h> 398275SEric Cheng 408275SEric Cheng /* 418275SEric Cheng * x86 <sys/regs> ERR conflicts with <curses.h> ERR. 428275SEric Cheng * Include curses.h last. 438275SEric Cheng */ 448275SEric Cheng #if defined(ERR) 458275SEric Cheng #undef ERR 468275SEric Cheng #endif 478275SEric Cheng #include <curses.h> 488275SEric Cheng 498275SEric Cheng struct flowlist { 508558SGirish.Moodalbail@Sun.COM char flowname[MAXFLOWNAMELEN]; 518275SEric Cheng datalink_id_t linkid; 52*8957SMichael.Lim@Sun.COM uint64_t ifspeed; 538275SEric Cheng boolean_t first; 548275SEric Cheng boolean_t display; 558275SEric Cheng pktsum_t prevstats; 568275SEric Cheng pktsum_t diffstats; 578275SEric Cheng }; 588275SEric Cheng 598275SEric Cheng static int maxx, maxy, redraw = 0; 608275SEric Cheng static volatile uint_t handle_resize = 0, handle_break = 0; 618275SEric Cheng 628275SEric Cheng pktsum_t totalstats; 638275SEric Cheng struct flowlist *stattable = NULL; 648275SEric Cheng static int statentry = -1, maxstatentries = 0; 658275SEric Cheng 668275SEric Cheng #define STATGROWSIZE 16 678275SEric Cheng 688275SEric Cheng 698275SEric Cheng /* 708275SEric Cheng * Search for flowlist entry in stattable which matches 718275SEric Cheng * the flowname and linkide. If no match is found, use 728275SEric Cheng * next available slot. If no slots are available, 738275SEric Cheng * reallocate table with more slots. 748275SEric Cheng * 758275SEric Cheng * Return: *flowlist of matching flow 768275SEric Cheng * NULL if realloc fails 778275SEric Cheng */ 788275SEric Cheng 798275SEric Cheng static struct flowlist * 808275SEric Cheng findstat(const char *flowname, datalink_id_t linkid) 818275SEric Cheng { 828275SEric Cheng int match = 0; 838275SEric Cheng struct flowlist *flist; 848275SEric Cheng 858275SEric Cheng /* Look for match in the stattable */ 868275SEric Cheng for (match = 0, flist = stattable; 878275SEric Cheng match <= statentry; 888275SEric Cheng match++, flist++) { 898275SEric Cheng 908275SEric Cheng if (flist == NULL) 918275SEric Cheng break; 928275SEric Cheng /* match the flowname */ 938275SEric Cheng if (flowname != NULL) { 948558SGirish.Moodalbail@Sun.COM if (strncmp(flowname, flist->flowname, MAXFLOWNAMELEN) 958275SEric Cheng == NULL) 968275SEric Cheng return (flist); 978275SEric Cheng /* match the linkid */ 988275SEric Cheng } else { 998275SEric Cheng if (linkid == flist->linkid) 1008275SEric Cheng return (flist); 1018275SEric Cheng } 1028275SEric Cheng } 1038275SEric Cheng 1048275SEric Cheng /* 1058275SEric Cheng * No match found in the table. Store statistics in the next slot. 1068275SEric Cheng * If necessary, make room for this entry. 1078275SEric Cheng */ 1088275SEric Cheng statentry++; 1098275SEric Cheng if ((maxstatentries == 0) || (maxstatentries == statentry)) { 1108275SEric Cheng maxstatentries += STATGROWSIZE; 1118275SEric Cheng stattable = realloc(stattable, 1128275SEric Cheng maxstatentries * sizeof (struct flowlist)); 1138275SEric Cheng if (stattable == NULL) { 1148275SEric Cheng perror("realloc"); 1158275SEric Cheng return (struct flowlist *)(NULL); 1168275SEric Cheng } 1178275SEric Cheng } 1188275SEric Cheng flist = &stattable[statentry]; 1198275SEric Cheng bzero(flist, sizeof (struct flowlist)); 1208275SEric Cheng flist->first = B_TRUE; 1218275SEric Cheng 1228275SEric Cheng if (flowname != NULL) 1238558SGirish.Moodalbail@Sun.COM (void) strncpy(flist->flowname, flowname, MAXFLOWNAMELEN); 1248275SEric Cheng flist->linkid = linkid; 1258275SEric Cheng return (flist); 1268275SEric Cheng } 1278275SEric Cheng 1288275SEric Cheng static void 1298453SAnurag.Maskey@Sun.COM print_flow_stats(dladm_handle_t handle, struct flowlist *flist) 1308275SEric Cheng { 1318275SEric Cheng struct flowlist *fcurr; 1328275SEric Cheng double ikbs, okbs; 1338275SEric Cheng double ipks, opks; 1348275SEric Cheng double dlt; 1358275SEric Cheng int fcount; 1368275SEric Cheng static boolean_t first = B_TRUE; 1378275SEric Cheng 1388275SEric Cheng if (first) { 1398275SEric Cheng first = B_FALSE; 1408275SEric Cheng (void) printw("please wait...\n"); 1418275SEric Cheng return; 1428275SEric Cheng } 1438275SEric Cheng 1448275SEric Cheng for (fcount = 0, fcurr = flist; 1458275SEric Cheng fcount <= statentry; 1468275SEric Cheng fcount++, fcurr++) { 1478275SEric Cheng if (fcurr->flowname && fcurr->display) { 1488558SGirish.Moodalbail@Sun.COM char linkname[MAXLINKNAMELEN]; 1498275SEric Cheng 1508453SAnurag.Maskey@Sun.COM (void) dladm_datalink_id2info(handle, fcurr->linkid, 1518453SAnurag.Maskey@Sun.COM NULL, NULL, NULL, linkname, sizeof (linkname)); 1528275SEric Cheng dlt = (double)fcurr->diffstats.snaptime/(double)NANOSEC; 1538275SEric Cheng ikbs = fcurr->diffstats.rbytes * 8 / dlt / 1024; 1548275SEric Cheng okbs = fcurr->diffstats.obytes * 8 / dlt / 1024; 1558275SEric Cheng ipks = fcurr->diffstats.ipackets / dlt; 1568275SEric Cheng opks = fcurr->diffstats.opackets / dlt; 1578275SEric Cheng (void) printw("%-15.15s", fcurr->flowname); 1588275SEric Cheng (void) printw("%-10.10s", linkname); 1598275SEric Cheng (void) printw("%9.2f %9.2f %9.2f %9.2f ", 1608275SEric Cheng ikbs, okbs, ipks, opks); 1618275SEric Cheng (void) printw("\n"); 1628275SEric Cheng } 1638275SEric Cheng } 1648275SEric Cheng } 1658275SEric Cheng 1668275SEric Cheng /*ARGSUSED*/ 1678275SEric Cheng static int 1688275SEric Cheng flow_kstats(dladm_flow_attr_t *attr, void *arg) 1698275SEric Cheng { 1708275SEric Cheng kstat_ctl_t *kcp = (kstat_ctl_t *)arg; 1718275SEric Cheng kstat_t *ksp; 1728275SEric Cheng struct flowlist *flist; 1738275SEric Cheng pktsum_t currstats, *prevstats, *diffstats; 1748275SEric Cheng 1758275SEric Cheng flist = findstat(attr->fa_flowname, attr->fa_linkid); 1768275SEric Cheng if (flist != NULL) { 1778275SEric Cheng prevstats = &flist->prevstats; 1788275SEric Cheng diffstats = &flist->diffstats; 1798275SEric Cheng } else { 1808275SEric Cheng return (DLADM_STATUS_FAILED); 1818275SEric Cheng } 1828275SEric Cheng 1838275SEric Cheng /* lookup kstat entry */ 1848275SEric Cheng ksp = dladm_kstat_lookup(kcp, NULL, -1, attr->fa_flowname, "flow"); 1858275SEric Cheng 1868275SEric Cheng if (ksp == NULL) 1878275SEric Cheng return (DLADM_WALK_TERMINATE); 1888275SEric Cheng else 1898275SEric Cheng flist->display = B_TRUE; 1908275SEric Cheng 1918275SEric Cheng dladm_get_stats(kcp, ksp, &currstats); 1928275SEric Cheng if (flist->ifspeed == 0) 1938275SEric Cheng (void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64, 1948275SEric Cheng &flist->ifspeed); 1958275SEric Cheng 1968275SEric Cheng if (flist->first) 1978275SEric Cheng flist->first = B_FALSE; 1988275SEric Cheng else { 1998275SEric Cheng dladm_stats_diff(diffstats, &currstats, prevstats); 2008275SEric Cheng dladm_stats_total(&totalstats, diffstats, &totalstats); 2018275SEric Cheng } 2028275SEric Cheng 2038275SEric Cheng bcopy(&currstats, prevstats, sizeof (pktsum_t)); 2048275SEric Cheng return (DLADM_WALK_CONTINUE); 2058275SEric Cheng } 2068275SEric Cheng 2078275SEric Cheng static void 2088453SAnurag.Maskey@Sun.COM print_link_stats(dladm_handle_t handle, struct flowlist *flist) 2098275SEric Cheng { 2108275SEric Cheng struct flowlist *fcurr; 2118275SEric Cheng double ikbs, okbs; 2128275SEric Cheng double ipks, opks; 2138275SEric Cheng double util; 2148275SEric Cheng double dlt; 2158275SEric Cheng int fcount; 2168275SEric Cheng static boolean_t first = B_TRUE; 2178275SEric Cheng 2188275SEric Cheng if (first) { 2198275SEric Cheng first = B_FALSE; 2208275SEric Cheng (void) printw("please wait...\n"); 2218275SEric Cheng return; 2228275SEric Cheng } 2238275SEric Cheng 2248275SEric Cheng for (fcount = 0, fcurr = flist; 2258275SEric Cheng fcount <= statentry; 2268275SEric Cheng fcount++, fcurr++) { 2278275SEric Cheng if ((fcurr->linkid != DATALINK_INVALID_LINKID) && 2288275SEric Cheng fcurr->display) { 2298558SGirish.Moodalbail@Sun.COM char linkname[MAXLINKNAMELEN]; 2308275SEric Cheng 2318453SAnurag.Maskey@Sun.COM (void) dladm_datalink_id2info(handle, fcurr->linkid, 2328453SAnurag.Maskey@Sun.COM NULL, NULL, NULL, linkname, sizeof (linkname)); 2338275SEric Cheng dlt = (double)fcurr->diffstats.snaptime/(double)NANOSEC; 2348275SEric Cheng ikbs = (double)fcurr->diffstats.rbytes * 8 / dlt / 1024; 2358275SEric Cheng okbs = (double)fcurr->diffstats.obytes * 8 / dlt / 1024; 2368275SEric Cheng ipks = (double)fcurr->diffstats.ipackets / dlt; 2378275SEric Cheng opks = (double)fcurr->diffstats.opackets / dlt; 2388275SEric Cheng (void) printw("%-10.10s", linkname); 2398275SEric Cheng (void) printw("%9.2f %9.2f %9.2f %9.2f ", 2408275SEric Cheng ikbs, okbs, ipks, opks); 2418275SEric Cheng if (fcurr->ifspeed != 0) 2428275SEric Cheng util = ((ikbs + okbs) * 1024) * 2438275SEric Cheng 100/ fcurr->ifspeed; 2448275SEric Cheng else 2458275SEric Cheng util = (double)0; 2468275SEric Cheng (void) attron(A_BOLD); 2478275SEric Cheng (void) printw(" %6.2f", util); 2488275SEric Cheng (void) attroff(A_BOLD); 2498275SEric Cheng (void) printw("\n"); 2508275SEric Cheng } 2518275SEric Cheng } 2528275SEric Cheng } 2538275SEric Cheng 2548275SEric Cheng /* 2558275SEric Cheng * This function is called through the dladm_walk_datalink_id() walker and 2568275SEric Cheng * calls the dladm_walk_flow() walker. 2578275SEric Cheng */ 2588275SEric Cheng 2598275SEric Cheng /*ARGSUSED*/ 2608275SEric Cheng static int 2618453SAnurag.Maskey@Sun.COM link_flowstats(dladm_handle_t handle, datalink_id_t linkid, void *arg) 2628275SEric Cheng { 2638621SMichael.Lim@Sun.COM dladm_status_t status; 2648621SMichael.Lim@Sun.COM 2658621SMichael.Lim@Sun.COM status = dladm_walk_flow(flow_kstats, handle, linkid, arg, B_FALSE); 2668621SMichael.Lim@Sun.COM if (status == DLADM_STATUS_OK) 2678621SMichael.Lim@Sun.COM return (DLADM_WALK_CONTINUE); 2688621SMichael.Lim@Sun.COM else 2698621SMichael.Lim@Sun.COM return (DLADM_WALK_TERMINATE); 2708275SEric Cheng } 2718275SEric Cheng 2728275SEric Cheng /*ARGSUSED*/ 2738275SEric Cheng static int 2748453SAnurag.Maskey@Sun.COM link_kstats(dladm_handle_t handle, datalink_id_t linkid, void *arg) 2758275SEric Cheng { 2768275SEric Cheng kstat_ctl_t *kcp = (kstat_ctl_t *)arg; 2778275SEric Cheng struct flowlist *flist; 2788275SEric Cheng pktsum_t currstats, *prevstats, *diffstats; 2798275SEric Cheng kstat_t *ksp; 2808558SGirish.Moodalbail@Sun.COM char linkname[MAXLINKNAMELEN]; 2818275SEric Cheng 2828275SEric Cheng /* find the flist entry */ 2838275SEric Cheng flist = findstat(NULL, linkid); 2848275SEric Cheng if (flist != NULL) { 2858275SEric Cheng prevstats = &flist->prevstats; 2868275SEric Cheng diffstats = &flist->diffstats; 2878275SEric Cheng } else { 2888275SEric Cheng return (DLADM_WALK_CONTINUE); 2898275SEric Cheng } 2908275SEric Cheng 2918275SEric Cheng /* lookup kstat entry */ 2928453SAnurag.Maskey@Sun.COM (void) dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL, 2938453SAnurag.Maskey@Sun.COM linkname, sizeof (linkname)); 2948275SEric Cheng 2958275SEric Cheng if (linkname == NULL) { 2968275SEric Cheng warn("no linkname for linkid"); 2978275SEric Cheng return (DLADM_WALK_TERMINATE); 2988275SEric Cheng } 2998275SEric Cheng 3008275SEric Cheng ksp = dladm_kstat_lookup(kcp, NULL, -1, linkname, "net"); 3018275SEric Cheng 3028275SEric Cheng if (ksp == NULL) 3038275SEric Cheng return (DLADM_WALK_TERMINATE); 3048275SEric Cheng else 3058275SEric Cheng flist->display = B_TRUE; 3068275SEric Cheng 3078275SEric Cheng /* read packet and byte stats */ 3088275SEric Cheng dladm_get_stats(kcp, ksp, &currstats); 3098275SEric Cheng 3108275SEric Cheng if (flist->ifspeed == 0) 3118275SEric Cheng (void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64, 3128275SEric Cheng &flist->ifspeed); 3138275SEric Cheng 3148275SEric Cheng if (flist->first == B_TRUE) 3158275SEric Cheng flist->first = B_FALSE; 3168275SEric Cheng else 3178275SEric Cheng dladm_stats_diff(diffstats, &currstats, prevstats); 3188275SEric Cheng 3198275SEric Cheng bcopy(&currstats, prevstats, sizeof (*prevstats)); 3208275SEric Cheng 3218275SEric Cheng return (DLADM_WALK_CONTINUE); 3228275SEric Cheng } 3238275SEric Cheng 3248275SEric Cheng /*ARGSUSED*/ 3258275SEric Cheng static void 3268275SEric Cheng sig_break(int s) 3278275SEric Cheng { 3288275SEric Cheng handle_break = 1; 3298275SEric Cheng } 3308275SEric Cheng 3318275SEric Cheng /*ARGSUSED*/ 3328275SEric Cheng static void 3338275SEric Cheng sig_resize(int s) 3348275SEric Cheng { 3358275SEric Cheng handle_resize = 1; 3368275SEric Cheng } 3378275SEric Cheng 3388275SEric Cheng static void 3398275SEric Cheng curses_init() 3408275SEric Cheng { 3418275SEric Cheng maxx = maxx; /* lint */ 3428275SEric Cheng maxy = maxy; /* lint */ 3438275SEric Cheng 3448275SEric Cheng /* Install signal handlers */ 3458275SEric Cheng (void) signal(SIGINT, sig_break); 3468275SEric Cheng (void) signal(SIGQUIT, sig_break); 3478275SEric Cheng (void) signal(SIGTERM, sig_break); 3488275SEric Cheng (void) signal(SIGWINCH, sig_resize); 3498275SEric Cheng 3508275SEric Cheng /* Initialize ncurses */ 3518275SEric Cheng (void) initscr(); 3528275SEric Cheng (void) cbreak(); 3538275SEric Cheng (void) noecho(); 3548275SEric Cheng (void) curs_set(0); 3558275SEric Cheng timeout(0); 3568275SEric Cheng getmaxyx(stdscr, maxy, maxx); 3578275SEric Cheng } 3588275SEric Cheng 3598275SEric Cheng static void 3608275SEric Cheng curses_fin() 3618275SEric Cheng { 3628275SEric Cheng (void) printw("\n"); 3638275SEric Cheng (void) curs_set(1); 3648275SEric Cheng (void) nocbreak(); 3658275SEric Cheng (void) endwin(); 3668275SEric Cheng 3678275SEric Cheng free(stattable); 3688275SEric Cheng } 3698275SEric Cheng 3708275SEric Cheng static void 3718453SAnurag.Maskey@Sun.COM stat_report(dladm_handle_t handle, kstat_ctl_t *kcp, datalink_id_t linkid, 3728453SAnurag.Maskey@Sun.COM const char *flowname, int opt) 3738275SEric Cheng { 3748275SEric Cheng 3758275SEric Cheng double dlt, ikbs, okbs, ipks, opks; 3768275SEric Cheng 3778275SEric Cheng struct flowlist *fstable = stattable; 3788275SEric Cheng 3798275SEric Cheng if ((opt != LINK_REPORT) && (opt != FLOW_REPORT)) 3808275SEric Cheng return; 3818275SEric Cheng 3828275SEric Cheng /* Handle window resizes */ 3838275SEric Cheng if (handle_resize) { 3848275SEric Cheng (void) endwin(); 3858275SEric Cheng (void) initscr(); 3868275SEric Cheng (void) cbreak(); 3878275SEric Cheng (void) noecho(); 3888275SEric Cheng (void) curs_set(0); 3898275SEric Cheng timeout(0); 3908275SEric Cheng getmaxyx(stdscr, maxy, maxx); 3918275SEric Cheng redraw = 1; 3928275SEric Cheng handle_resize = 0; 3938275SEric Cheng } 3948275SEric Cheng 3958275SEric Cheng /* Print title */ 3968275SEric Cheng (void) erase(); 3978275SEric Cheng (void) attron(A_BOLD); 3988275SEric Cheng (void) move(0, 0); 3998275SEric Cheng if (opt == FLOW_REPORT) 4008275SEric Cheng (void) printw("%-15.15s", "Flow"); 4018275SEric Cheng (void) printw("%-10.10s", "Link"); 4028275SEric Cheng (void) printw("%9.9s %9.9s %9.9s %9.9s ", 4038275SEric Cheng "iKb/s", "oKb/s", "iPk/s", "oPk/s"); 4048275SEric Cheng if (opt == LINK_REPORT) 4058275SEric Cheng (void) printw(" %6.6s", "%Util"); 4068275SEric Cheng (void) printw("\n"); 4078275SEric Cheng (void) attroff(A_BOLD); 4088275SEric Cheng 4098275SEric Cheng (void) move(2, 0); 4108275SEric Cheng 4118275SEric Cheng /* Print stats for each link or flow */ 4128275SEric Cheng bzero(&totalstats, sizeof (totalstats)); 4138275SEric Cheng if (opt == LINK_REPORT) { 4148275SEric Cheng /* Display all links */ 4158275SEric Cheng if (linkid == DATALINK_ALL_LINKID) { 4168453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(link_kstats, handle, 4178275SEric Cheng (void *)kcp, DATALINK_CLASS_ALL, 4188275SEric Cheng DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 4198275SEric Cheng /* Display 1 link */ 4208275SEric Cheng } else { 4218453SAnurag.Maskey@Sun.COM (void) link_kstats(handle, linkid, kcp); 4228275SEric Cheng } 4238453SAnurag.Maskey@Sun.COM print_link_stats(handle, fstable); 4248275SEric Cheng 4258275SEric Cheng } else if (opt == FLOW_REPORT) { 4268275SEric Cheng /* Display 1 flow */ 4278275SEric Cheng if (flowname != NULL) { 4288275SEric Cheng dladm_flow_attr_t fattr; 4298453SAnurag.Maskey@Sun.COM if (dladm_flow_info(handle, flowname, &fattr) != 4308275SEric Cheng DLADM_STATUS_OK) 4318275SEric Cheng return; 4328275SEric Cheng (void) flow_kstats(&fattr, kcp); 4338275SEric Cheng /* Display all flows on all links */ 4348275SEric Cheng } else if (linkid == DATALINK_ALL_LINKID) { 4358453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(link_flowstats, handle, 4368275SEric Cheng (void *)kcp, DATALINK_CLASS_ALL, 4378275SEric Cheng DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 4388275SEric Cheng /* Display all flows on a link */ 4398275SEric Cheng } else if (linkid != DATALINK_INVALID_LINKID) { 4408453SAnurag.Maskey@Sun.COM (void) dladm_walk_flow(flow_kstats, handle, linkid, kcp, 4418275SEric Cheng B_FALSE); 4428275SEric Cheng } 4438453SAnurag.Maskey@Sun.COM print_flow_stats(handle, fstable); 4448275SEric Cheng 4458275SEric Cheng /* Print totals */ 4468275SEric Cheng (void) attron(A_BOLD); 4478275SEric Cheng dlt = (double)totalstats.snaptime / (double)NANOSEC; 4488275SEric Cheng ikbs = totalstats.rbytes / dlt / 1024; 4498275SEric Cheng okbs = totalstats.obytes / dlt / 1024; 4508275SEric Cheng ipks = totalstats.ipackets / dlt; 4518275SEric Cheng opks = totalstats.opackets / dlt; 4528275SEric Cheng (void) printw("\n%-25.25s", "Totals"); 4538275SEric Cheng (void) printw("%9.2f %9.2f %9.2f %9.2f ", 4548275SEric Cheng ikbs, okbs, ipks, opks); 4558275SEric Cheng (void) attroff(A_BOLD); 4568275SEric Cheng } 4578275SEric Cheng 4588275SEric Cheng if (redraw) 4598275SEric Cheng (void) clearok(stdscr, 1); 4608275SEric Cheng 4618275SEric Cheng if (refresh() == ERR) 4628275SEric Cheng return; 4638275SEric Cheng 4648275SEric Cheng if (redraw) { 4658275SEric Cheng (void) clearok(stdscr, 0); 4668275SEric Cheng redraw = 0; 4678275SEric Cheng } 4688275SEric Cheng } 4698275SEric Cheng 4708275SEric Cheng /* Exported functions */ 4718275SEric Cheng 4728275SEric Cheng /* 4738275SEric Cheng * Continuously display link or flow statstics using a libcurses 4748275SEric Cheng * based display. 4758275SEric Cheng */ 4768275SEric Cheng 4778275SEric Cheng void 4788453SAnurag.Maskey@Sun.COM dladm_continuous(dladm_handle_t handle, datalink_id_t linkid, 4798453SAnurag.Maskey@Sun.COM const char *flowname, int interval, int opt) 4808275SEric Cheng { 4818275SEric Cheng kstat_ctl_t *kcp; 4828275SEric Cheng 4838275SEric Cheng if ((kcp = kstat_open()) == NULL) { 4848275SEric Cheng warn("kstat open operation failed"); 4858275SEric Cheng return; 4868275SEric Cheng } 4878275SEric Cheng 4888275SEric Cheng curses_init(); 4898275SEric Cheng 4908275SEric Cheng for (;;) { 4918275SEric Cheng 4928275SEric Cheng if (handle_break) 4938275SEric Cheng break; 4948275SEric Cheng 4958453SAnurag.Maskey@Sun.COM stat_report(handle, kcp, linkid, flowname, opt); 4968275SEric Cheng 4978275SEric Cheng (void) sleep(max(1, interval)); 4988275SEric Cheng } 4998275SEric Cheng 5008275SEric Cheng (void) curses_fin(); 5018275SEric Cheng (void) kstat_close(kcp); 5028275SEric Cheng } 5038275SEric Cheng 5048275SEric Cheng /* 5058275SEric Cheng * dladm_kstat_lookup() is a modified version of kstat_lookup which 5068275SEric Cheng * adds the class as a selector. 5078275SEric Cheng */ 5088275SEric Cheng 5098275SEric Cheng kstat_t * 5108275SEric Cheng dladm_kstat_lookup(kstat_ctl_t *kcp, const char *module, int instance, 5118275SEric Cheng const char *name, const char *class) 5128275SEric Cheng { 5138275SEric Cheng kstat_t *ksp = NULL; 5148275SEric Cheng 5158275SEric Cheng for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 5168275SEric Cheng if ((module == NULL || strcmp(ksp->ks_module, module) == 0) && 5178275SEric Cheng (instance == -1 || ksp->ks_instance == instance) && 5188275SEric Cheng (name == NULL || strcmp(ksp->ks_name, name) == 0) && 5198275SEric Cheng (class == NULL || strcmp(ksp->ks_class, class) == 0)) 5208275SEric Cheng return (ksp); 5218275SEric Cheng } 5228275SEric Cheng 5238275SEric Cheng errno = ENOENT; 5248275SEric Cheng return (NULL); 5258275SEric Cheng } 5268275SEric Cheng 5278275SEric Cheng /* 5288275SEric Cheng * dladm_get_stats() populates the supplied pktsum_t structure with 5298275SEric Cheng * the input and output packet and byte kstats from the kstat_t 5308275SEric Cheng * found with dladm_kstat_lookup. 5318275SEric Cheng */ 5328275SEric Cheng void 5338275SEric Cheng dladm_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, pktsum_t *stats) 5348275SEric Cheng { 5358275SEric Cheng 5368275SEric Cheng if (kstat_read(kcp, ksp, NULL) == -1) 5378275SEric Cheng return; 5388275SEric Cheng 5398275SEric Cheng stats->snaptime = gethrtime(); 5408275SEric Cheng 5418275SEric Cheng if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 5428275SEric Cheng &stats->ipackets) < 0) { 5438275SEric Cheng if (dladm_kstat_value(ksp, "ipackets", KSTAT_DATA_UINT64, 5448275SEric Cheng &stats->ipackets) < 0) 5458275SEric Cheng return; 5468275SEric Cheng } 5478275SEric Cheng 5488275SEric Cheng if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 5498275SEric Cheng &stats->opackets) < 0) { 5508275SEric Cheng if (dladm_kstat_value(ksp, "opackets", KSTAT_DATA_UINT64, 5518275SEric Cheng &stats->opackets) < 0) 5528275SEric Cheng return; 5538275SEric Cheng } 5548275SEric Cheng 5558275SEric Cheng if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 5568275SEric Cheng &stats->rbytes) < 0) { 5578275SEric Cheng if (dladm_kstat_value(ksp, "rbytes", KSTAT_DATA_UINT64, 5588275SEric Cheng &stats->rbytes) < 0) 5598275SEric Cheng return; 5608275SEric Cheng } 5618275SEric Cheng 5628275SEric Cheng if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 5638275SEric Cheng &stats->obytes) < 0) { 5648275SEric Cheng if (dladm_kstat_value(ksp, "obytes", KSTAT_DATA_UINT64, 5658275SEric Cheng &stats->obytes) < 0) 5668275SEric Cheng return; 5678275SEric Cheng } 5688275SEric Cheng 5698275SEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 5708275SEric Cheng &stats->ierrors) < 0) { 5718275SEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT64, 5728275SEric Cheng &stats->ierrors) < 0) 5738275SEric Cheng return; 5748275SEric Cheng } 5758275SEric Cheng 5768275SEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 5778275SEric Cheng &stats->oerrors) < 0) { 5788275SEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT64, 5798275SEric Cheng &stats->oerrors) < 0) 5808275SEric Cheng return; 5818275SEric Cheng } 5828275SEric Cheng } 5838275SEric Cheng 5848275SEric Cheng int 5858275SEric Cheng dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 5868275SEric Cheng { 5878275SEric Cheng kstat_named_t *knp; 5888275SEric Cheng 5898275SEric Cheng if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 5908275SEric Cheng return (-1); 5918275SEric Cheng 5928275SEric Cheng if (knp->data_type != type) 5938275SEric Cheng return (-1); 5948275SEric Cheng 5958275SEric Cheng switch (type) { 5968275SEric Cheng case KSTAT_DATA_UINT64: 5978275SEric Cheng *(uint64_t *)buf = knp->value.ui64; 5988275SEric Cheng break; 5998275SEric Cheng case KSTAT_DATA_UINT32: 6008275SEric Cheng *(uint32_t *)buf = knp->value.ui32; 6018275SEric Cheng break; 6028275SEric Cheng default: 6038275SEric Cheng return (-1); 6048275SEric Cheng } 6058275SEric Cheng 6068275SEric Cheng return (0); 6078275SEric Cheng } 6088275SEric Cheng 6098275SEric Cheng dladm_status_t 6108453SAnurag.Maskey@Sun.COM dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid, 6118453SAnurag.Maskey@Sun.COM const char *name, uint8_t type, void *val) 6128275SEric Cheng { 6138275SEric Cheng kstat_ctl_t *kcp; 6148275SEric Cheng char module[DLPI_LINKNAME_MAX]; 6158275SEric Cheng uint_t instance; 6168275SEric Cheng char link[DLPI_LINKNAME_MAX]; 6178275SEric Cheng dladm_status_t status; 6188275SEric Cheng uint32_t flags, media; 6198275SEric Cheng kstat_t *ksp; 6208275SEric Cheng dladm_phys_attr_t dpap; 6218275SEric Cheng 6228275SEric Cheng if ((kcp = kstat_open()) == NULL) { 6238275SEric Cheng warn("kstat_open operation failed"); 6248275SEric Cheng return (-1); 6258275SEric Cheng } 6268275SEric Cheng 6278453SAnurag.Maskey@Sun.COM if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 6288453SAnurag.Maskey@Sun.COM &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) 6298275SEric Cheng return (status); 6308275SEric Cheng 6318275SEric Cheng if (media != DL_ETHER) 6328275SEric Cheng return (DLADM_STATUS_LINKINVAL); 6338275SEric Cheng 6348453SAnurag.Maskey@Sun.COM status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST); 6358275SEric Cheng 6368275SEric Cheng if (status != DLADM_STATUS_OK) 6378275SEric Cheng return (status); 6388275SEric Cheng 6398275SEric Cheng status = dladm_parselink(dpap.dp_dev, module, &instance); 6408275SEric Cheng 6418275SEric Cheng if (status != DLADM_STATUS_OK) 6428275SEric Cheng return (status); 6438275SEric Cheng 6448275SEric Cheng /* 6458275SEric Cheng * The kstat query could fail if the underlying MAC 6468275SEric Cheng * driver was already detached. 6478275SEric Cheng */ 6488275SEric Cheng if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 6498275SEric Cheng (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) 6508275SEric Cheng goto bail; 6518275SEric Cheng 6528275SEric Cheng if (kstat_read(kcp, ksp, NULL) == -1) 6538275SEric Cheng goto bail; 6548275SEric Cheng 6558275SEric Cheng if (dladm_kstat_value(ksp, name, type, val) < 0) 6568275SEric Cheng goto bail; 6578275SEric Cheng 6588275SEric Cheng (void) kstat_close(kcp); 6598275SEric Cheng return (DLADM_STATUS_OK); 6608275SEric Cheng 6618275SEric Cheng bail: 6628275SEric Cheng (void) kstat_close(kcp); 6638275SEric Cheng return (dladm_errno2status(errno)); 6648275SEric Cheng } 6658275SEric Cheng 6668275SEric Cheng /* Compute sum of 2 pktsums (s1 = s2 + s3) */ 6678275SEric Cheng void 6688275SEric Cheng dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 6698275SEric Cheng { 6708275SEric Cheng s1->rbytes = s2->rbytes + s3->rbytes; 6718275SEric Cheng s1->ipackets = s2->ipackets + s3->ipackets; 6728275SEric Cheng s1->ierrors = s2->ierrors + s3->ierrors; 6738275SEric Cheng s1->obytes = s2->obytes + s3->obytes; 6748275SEric Cheng s1->opackets = s2->opackets + s3->opackets; 6758275SEric Cheng s1->oerrors = s2->oerrors + s3->oerrors; 6768275SEric Cheng s1->snaptime = s2->snaptime; 6778275SEric Cheng } 6788275SEric Cheng 6798275SEric Cheng /* Compute differences between 2 pktsums (s1 = s2 - s3) */ 6808275SEric Cheng void 6818275SEric Cheng dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 6828275SEric Cheng { 6838275SEric Cheng s1->rbytes = s2->rbytes - s3->rbytes; 6848275SEric Cheng s1->ipackets = s2->ipackets - s3->ipackets; 6858275SEric Cheng s1->ierrors = s2->ierrors - s3->ierrors; 6868275SEric Cheng s1->obytes = s2->obytes - s3->obytes; 6878275SEric Cheng s1->opackets = s2->opackets - s3->opackets; 6888275SEric Cheng s1->oerrors = s2->oerrors - s3->oerrors; 6898275SEric Cheng s1->snaptime = s2->snaptime - s3->snaptime; 6908275SEric Cheng } 691