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 /* 22*11878SVenu.Iyer@Sun.COM * Copyright 2010 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> 319421SMichael.Lim@Sun.COM #include <fcntl.h> 328275SEric Cheng #include <kstat.h> 339421SMichael.Lim@Sun.COM #include <limits.h> 348275SEric Cheng #include <unistd.h> 358275SEric Cheng #include <signal.h> 368275SEric Cheng #include <sys/dld.h> 379107Sjames.d.carlson@sun.com #include <sys/ddi.h> 388275SEric Cheng 398275SEric Cheng #include <libdllink.h> 408275SEric Cheng #include <libdlflow.h> 418275SEric Cheng #include <libdlstat.h> 42*11878SVenu.Iyer@Sun.COM #include <libdlaggr.h> 438275SEric Cheng 448275SEric Cheng /* 458275SEric Cheng * x86 <sys/regs> ERR conflicts with <curses.h> ERR. 468275SEric Cheng * Include curses.h last. 478275SEric Cheng */ 488275SEric Cheng #if defined(ERR) 498275SEric Cheng #undef ERR 508275SEric Cheng #endif 518275SEric Cheng #include <curses.h> 528275SEric Cheng 538275SEric Cheng struct flowlist { 548558SGirish.Moodalbail@Sun.COM char flowname[MAXFLOWNAMELEN]; 559421SMichael.Lim@Sun.COM char linkname[MAXLINKNAMELEN]; 568275SEric Cheng datalink_id_t linkid; 579421SMichael.Lim@Sun.COM int fd; 588957SMichael.Lim@Sun.COM uint64_t ifspeed; 598275SEric Cheng boolean_t first; 608275SEric Cheng boolean_t display; 618275SEric Cheng pktsum_t prevstats; 628275SEric Cheng pktsum_t diffstats; 638275SEric Cheng }; 648275SEric Cheng 658275SEric Cheng static int maxx, maxy, redraw = 0; 668275SEric Cheng static volatile uint_t handle_resize = 0, handle_break = 0; 678275SEric Cheng 688275SEric Cheng pktsum_t totalstats; 698275SEric Cheng struct flowlist *stattable = NULL; 708275SEric Cheng static int statentry = -1, maxstatentries = 0; 718275SEric Cheng 728275SEric Cheng #define STATGROWSIZE 16 738275SEric Cheng 748275SEric Cheng /* 758275SEric Cheng * Search for flowlist entry in stattable which matches 76*11878SVenu.Iyer@Sun.COM * the flowname and linkid. If no match is found, use 778275SEric Cheng * next available slot. If no slots are available, 788275SEric Cheng * reallocate table with more slots. 798275SEric Cheng * 808275SEric Cheng * Return: *flowlist of matching flow 818275SEric Cheng * NULL if realloc fails 828275SEric Cheng */ 838275SEric Cheng 848275SEric Cheng static struct flowlist * 858275SEric Cheng findstat(const char *flowname, datalink_id_t linkid) 868275SEric Cheng { 878275SEric Cheng int match = 0; 888275SEric Cheng struct flowlist *flist; 898275SEric Cheng 908275SEric Cheng /* Look for match in the stattable */ 918275SEric Cheng for (match = 0, flist = stattable; 928275SEric Cheng match <= statentry; 938275SEric Cheng match++, flist++) { 948275SEric Cheng 958275SEric Cheng if (flist == NULL) 968275SEric Cheng break; 978275SEric Cheng /* match the flowname */ 988275SEric Cheng if (flowname != NULL) { 998558SGirish.Moodalbail@Sun.COM if (strncmp(flowname, flist->flowname, MAXFLOWNAMELEN) 1008275SEric Cheng == NULL) 1018275SEric Cheng return (flist); 1028275SEric Cheng /* match the linkid */ 1038275SEric Cheng } else { 1048275SEric Cheng if (linkid == flist->linkid) 1058275SEric Cheng return (flist); 1068275SEric Cheng } 1078275SEric Cheng } 1088275SEric Cheng 1098275SEric Cheng /* 1108275SEric Cheng * No match found in the table. Store statistics in the next slot. 1118275SEric Cheng * If necessary, make room for this entry. 1128275SEric Cheng */ 1138275SEric Cheng statentry++; 1148275SEric Cheng if ((maxstatentries == 0) || (maxstatentries == statentry)) { 1158275SEric Cheng maxstatentries += STATGROWSIZE; 1168275SEric Cheng stattable = realloc(stattable, 1178275SEric Cheng maxstatentries * sizeof (struct flowlist)); 1188275SEric Cheng if (stattable == NULL) { 1198275SEric Cheng perror("realloc"); 1208275SEric Cheng return (struct flowlist *)(NULL); 1218275SEric Cheng } 1228275SEric Cheng } 1238275SEric Cheng flist = &stattable[statentry]; 1248275SEric Cheng bzero(flist, sizeof (struct flowlist)); 1258275SEric Cheng 1268275SEric Cheng if (flowname != NULL) 1278558SGirish.Moodalbail@Sun.COM (void) strncpy(flist->flowname, flowname, MAXFLOWNAMELEN); 1288275SEric Cheng flist->linkid = linkid; 1299421SMichael.Lim@Sun.COM flist->fd = INT32_MAX; 1309421SMichael.Lim@Sun.COM 1318275SEric Cheng return (flist); 1328275SEric Cheng } 1338275SEric Cheng 1349421SMichael.Lim@Sun.COM /*ARGSUSED*/ 1358275SEric Cheng static void 1368453SAnurag.Maskey@Sun.COM print_flow_stats(dladm_handle_t handle, struct flowlist *flist) 1378275SEric Cheng { 1388275SEric Cheng struct flowlist *fcurr; 1398275SEric Cheng double ikbs, okbs; 1408275SEric Cheng double ipks, opks; 1418275SEric Cheng double dlt; 1428275SEric Cheng int fcount; 1438275SEric Cheng static boolean_t first = B_TRUE; 1448275SEric Cheng 1458275SEric Cheng if (first) { 1468275SEric Cheng first = B_FALSE; 1478275SEric Cheng (void) printw("please wait...\n"); 1488275SEric Cheng return; 1498275SEric Cheng } 1508275SEric Cheng 1518275SEric Cheng for (fcount = 0, fcurr = flist; 1528275SEric Cheng fcount <= statentry; 1538275SEric Cheng fcount++, fcurr++) { 1548275SEric Cheng if (fcurr->flowname && fcurr->display) { 1558275SEric Cheng dlt = (double)fcurr->diffstats.snaptime/(double)NANOSEC; 1568275SEric Cheng ikbs = fcurr->diffstats.rbytes * 8 / dlt / 1024; 1578275SEric Cheng okbs = fcurr->diffstats.obytes * 8 / dlt / 1024; 1588275SEric Cheng ipks = fcurr->diffstats.ipackets / dlt; 1598275SEric Cheng opks = fcurr->diffstats.opackets / dlt; 1608275SEric Cheng (void) printw("%-15.15s", fcurr->flowname); 1619421SMichael.Lim@Sun.COM (void) printw("%-10.10s", fcurr->linkname); 1628275SEric Cheng (void) printw("%9.2f %9.2f %9.2f %9.2f ", 1638275SEric Cheng ikbs, okbs, ipks, opks); 1648275SEric Cheng (void) printw("\n"); 1658275SEric Cheng } 1668275SEric Cheng } 1678275SEric Cheng } 1688275SEric Cheng 1698275SEric Cheng /*ARGSUSED*/ 1708275SEric Cheng static int 1719421SMichael.Lim@Sun.COM flow_kstats(dladm_handle_t handle, dladm_flow_attr_t *attr, void *arg) 1728275SEric Cheng { 1738275SEric Cheng kstat_ctl_t *kcp = (kstat_ctl_t *)arg; 1748275SEric Cheng kstat_t *ksp; 1758275SEric Cheng struct flowlist *flist; 1768275SEric Cheng pktsum_t currstats, *prevstats, *diffstats; 1778275SEric Cheng 1788275SEric Cheng flist = findstat(attr->fa_flowname, attr->fa_linkid); 1799421SMichael.Lim@Sun.COM if (flist == NULL) 1809421SMichael.Lim@Sun.COM return (DLADM_WALK_CONTINUE); 1819421SMichael.Lim@Sun.COM 1829421SMichael.Lim@Sun.COM flist->display = B_FALSE; 1839421SMichael.Lim@Sun.COM prevstats = &flist->prevstats; 1849421SMichael.Lim@Sun.COM diffstats = &flist->diffstats; 1859421SMichael.Lim@Sun.COM 1869421SMichael.Lim@Sun.COM (void) dladm_datalink_id2info(handle, attr->fa_linkid, NULL, NULL, 1879421SMichael.Lim@Sun.COM NULL, flist->linkname, sizeof (flist->linkname)); 1889421SMichael.Lim@Sun.COM 1898275SEric Cheng 1908275SEric Cheng /* lookup kstat entry */ 1918275SEric Cheng ksp = dladm_kstat_lookup(kcp, NULL, -1, attr->fa_flowname, "flow"); 1928275SEric Cheng 1938275SEric Cheng if (ksp == NULL) 1949421SMichael.Lim@Sun.COM return (DLADM_WALK_CONTINUE); 1958275SEric Cheng 1969421SMichael.Lim@Sun.COM /* read packet and byte stats */ 1978275SEric Cheng dladm_get_stats(kcp, ksp, &currstats); 1989421SMichael.Lim@Sun.COM 1998275SEric Cheng if (flist->ifspeed == 0) 2008275SEric Cheng (void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64, 2018275SEric Cheng &flist->ifspeed); 2028275SEric Cheng 2039421SMichael.Lim@Sun.COM if (flist->first) { 2048275SEric Cheng flist->first = B_FALSE; 2059421SMichael.Lim@Sun.COM } else { 2068275SEric Cheng dladm_stats_diff(diffstats, &currstats, prevstats); 2079421SMichael.Lim@Sun.COM if (diffstats->snaptime == 0) 2089421SMichael.Lim@Sun.COM return (DLADM_WALK_CONTINUE); 2098275SEric Cheng dladm_stats_total(&totalstats, diffstats, &totalstats); 2108275SEric Cheng } 2118275SEric Cheng 2128275SEric Cheng bcopy(&currstats, prevstats, sizeof (pktsum_t)); 2139421SMichael.Lim@Sun.COM flist->display = B_TRUE; 2149421SMichael.Lim@Sun.COM 2158275SEric Cheng return (DLADM_WALK_CONTINUE); 2168275SEric Cheng } 2178275SEric Cheng 2189421SMichael.Lim@Sun.COM /*ARGSUSED*/ 2198275SEric Cheng static void 2208453SAnurag.Maskey@Sun.COM print_link_stats(dladm_handle_t handle, struct flowlist *flist) 2218275SEric Cheng { 2228275SEric Cheng struct flowlist *fcurr; 2238275SEric Cheng double ikbs, okbs; 2248275SEric Cheng double ipks, opks; 2258275SEric Cheng double util; 2268275SEric Cheng double dlt; 2278275SEric Cheng int fcount; 2288275SEric Cheng static boolean_t first = B_TRUE; 2298275SEric Cheng 2308275SEric Cheng if (first) { 2318275SEric Cheng first = B_FALSE; 2328275SEric Cheng (void) printw("please wait...\n"); 2338275SEric Cheng return; 2348275SEric Cheng } 2358275SEric Cheng 2368275SEric Cheng for (fcount = 0, fcurr = flist; 2378275SEric Cheng fcount <= statentry; 2388275SEric Cheng fcount++, fcurr++) { 2398275SEric Cheng if ((fcurr->linkid != DATALINK_INVALID_LINKID) && 2408275SEric Cheng fcurr->display) { 2418275SEric Cheng dlt = (double)fcurr->diffstats.snaptime/(double)NANOSEC; 2428275SEric Cheng ikbs = (double)fcurr->diffstats.rbytes * 8 / dlt / 1024; 2438275SEric Cheng okbs = (double)fcurr->diffstats.obytes * 8 / dlt / 1024; 2448275SEric Cheng ipks = (double)fcurr->diffstats.ipackets / dlt; 2458275SEric Cheng opks = (double)fcurr->diffstats.opackets / dlt; 2469421SMichael.Lim@Sun.COM (void) printw("%-10.10s", fcurr->linkname); 2478275SEric Cheng (void) printw("%9.2f %9.2f %9.2f %9.2f ", 2488275SEric Cheng ikbs, okbs, ipks, opks); 2498275SEric Cheng if (fcurr->ifspeed != 0) 2508275SEric Cheng util = ((ikbs + okbs) * 1024) * 2518275SEric Cheng 100/ fcurr->ifspeed; 2528275SEric Cheng else 2538275SEric Cheng util = (double)0; 2548275SEric Cheng (void) attron(A_BOLD); 2558275SEric Cheng (void) printw(" %6.2f", util); 2568275SEric Cheng (void) attroff(A_BOLD); 2578275SEric Cheng (void) printw("\n"); 2588275SEric Cheng } 2598275SEric Cheng } 2608275SEric Cheng } 2618275SEric Cheng 2628275SEric Cheng /* 2638275SEric Cheng * This function is called through the dladm_walk_datalink_id() walker and 2648275SEric Cheng * calls the dladm_walk_flow() walker. 2658275SEric Cheng */ 2668275SEric Cheng 2678275SEric Cheng /*ARGSUSED*/ 2688275SEric Cheng static int 2698453SAnurag.Maskey@Sun.COM link_flowstats(dladm_handle_t handle, datalink_id_t linkid, void *arg) 2708275SEric Cheng { 2718621SMichael.Lim@Sun.COM dladm_status_t status; 2728621SMichael.Lim@Sun.COM 2738621SMichael.Lim@Sun.COM status = dladm_walk_flow(flow_kstats, handle, linkid, arg, B_FALSE); 2748621SMichael.Lim@Sun.COM if (status == DLADM_STATUS_OK) 2758621SMichael.Lim@Sun.COM return (DLADM_WALK_CONTINUE); 2768621SMichael.Lim@Sun.COM else 2778621SMichael.Lim@Sun.COM return (DLADM_WALK_TERMINATE); 2788275SEric Cheng } 2798275SEric Cheng 2808275SEric Cheng /*ARGSUSED*/ 2818275SEric Cheng static int 2828453SAnurag.Maskey@Sun.COM link_kstats(dladm_handle_t handle, datalink_id_t linkid, void *arg) 2838275SEric Cheng { 2849421SMichael.Lim@Sun.COM kstat_ctl_t *kcp = (kstat_ctl_t *)arg; 2859421SMichael.Lim@Sun.COM struct flowlist *flist; 2869421SMichael.Lim@Sun.COM pktsum_t currstats, *prevstats, *diffstats; 2879421SMichael.Lim@Sun.COM datalink_class_t class; 2889421SMichael.Lim@Sun.COM kstat_t *ksp; 2899421SMichael.Lim@Sun.COM char dnlink[MAXPATHLEN]; 2908275SEric Cheng 2918275SEric Cheng /* find the flist entry */ 2928275SEric Cheng flist = findstat(NULL, linkid); 2939421SMichael.Lim@Sun.COM flist->display = B_FALSE; 2948275SEric Cheng if (flist != NULL) { 2958275SEric Cheng prevstats = &flist->prevstats; 2968275SEric Cheng diffstats = &flist->diffstats; 2978275SEric Cheng } else { 2988275SEric Cheng return (DLADM_WALK_CONTINUE); 2998275SEric Cheng } 3008275SEric Cheng 3019421SMichael.Lim@Sun.COM if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 3029421SMichael.Lim@Sun.COM flist->linkname, sizeof (flist->linkname)) != DLADM_STATUS_OK) 3039421SMichael.Lim@Sun.COM return (DLADM_WALK_CONTINUE); 3048275SEric Cheng 3059421SMichael.Lim@Sun.COM if (flist->fd == INT32_MAX) { 3069421SMichael.Lim@Sun.COM if (class == DATALINK_CLASS_PHYS) { 3079421SMichael.Lim@Sun.COM (void) snprintf(dnlink, MAXPATHLEN, "/dev/net/%s", 3089421SMichael.Lim@Sun.COM flist->linkname); 3099421SMichael.Lim@Sun.COM if ((flist->fd = open(dnlink, O_RDWR)) < 0) 3109421SMichael.Lim@Sun.COM return (DLADM_WALK_CONTINUE); 3119421SMichael.Lim@Sun.COM } else { 3129421SMichael.Lim@Sun.COM flist->fd = -1; 3139421SMichael.Lim@Sun.COM } 3149421SMichael.Lim@Sun.COM (void) kstat_chain_update(kcp); 3158275SEric Cheng } 3168275SEric Cheng 3179421SMichael.Lim@Sun.COM /* lookup kstat entry */ 3189421SMichael.Lim@Sun.COM ksp = dladm_kstat_lookup(kcp, NULL, -1, flist->linkname, "net"); 3198275SEric Cheng 3208275SEric Cheng if (ksp == NULL) 3219421SMichael.Lim@Sun.COM return (DLADM_WALK_CONTINUE); 3228275SEric Cheng 3238275SEric Cheng /* read packet and byte stats */ 3248275SEric Cheng dladm_get_stats(kcp, ksp, &currstats); 3258275SEric Cheng 3268275SEric Cheng if (flist->ifspeed == 0) 3278275SEric Cheng (void) dladm_kstat_value(ksp, "ifspeed", KSTAT_DATA_UINT64, 3288275SEric Cheng &flist->ifspeed); 3298275SEric Cheng 3309421SMichael.Lim@Sun.COM if (flist->first) { 3318275SEric Cheng flist->first = B_FALSE; 3329421SMichael.Lim@Sun.COM } else { 3338275SEric Cheng dladm_stats_diff(diffstats, &currstats, prevstats); 3349421SMichael.Lim@Sun.COM if (diffstats->snaptime == 0) 3359421SMichael.Lim@Sun.COM return (DLADM_WALK_CONTINUE); 3369421SMichael.Lim@Sun.COM } 3378275SEric Cheng 3388275SEric Cheng bcopy(&currstats, prevstats, sizeof (*prevstats)); 3399421SMichael.Lim@Sun.COM flist->display = B_TRUE; 3408275SEric Cheng 3418275SEric Cheng return (DLADM_WALK_CONTINUE); 3428275SEric Cheng } 3438275SEric Cheng 3449421SMichael.Lim@Sun.COM static void 3459421SMichael.Lim@Sun.COM closedevnet() 3469421SMichael.Lim@Sun.COM { 3479421SMichael.Lim@Sun.COM int index = 0; 3489421SMichael.Lim@Sun.COM struct flowlist *flist; 3499421SMichael.Lim@Sun.COM 3509421SMichael.Lim@Sun.COM /* Close all open /dev/net/ files */ 351*11878SVenu.Iyer@Sun.COM 352*11878SVenu.Iyer@Sun.COM for (flist = stattable; index < maxstatentries; index++, flist++) { 3539421SMichael.Lim@Sun.COM if (flist->linkid == DATALINK_INVALID_LINKID) 3549421SMichael.Lim@Sun.COM break; 3559421SMichael.Lim@Sun.COM if (flist->fd != -1 && flist->fd != INT32_MAX) 3569421SMichael.Lim@Sun.COM (void) close(flist->fd); 3579421SMichael.Lim@Sun.COM } 3589421SMichael.Lim@Sun.COM } 3599421SMichael.Lim@Sun.COM 3608275SEric Cheng /*ARGSUSED*/ 3618275SEric Cheng static void 3628275SEric Cheng sig_break(int s) 3638275SEric Cheng { 3648275SEric Cheng handle_break = 1; 3658275SEric Cheng } 3668275SEric Cheng 3678275SEric Cheng /*ARGSUSED*/ 3688275SEric Cheng static void 3698275SEric Cheng sig_resize(int s) 3708275SEric Cheng { 3718275SEric Cheng handle_resize = 1; 3728275SEric Cheng } 3738275SEric Cheng 3748275SEric Cheng static void 3758275SEric Cheng curses_init() 3768275SEric Cheng { 3778275SEric Cheng maxx = maxx; /* lint */ 3788275SEric Cheng maxy = maxy; /* lint */ 3798275SEric Cheng 3808275SEric Cheng /* Install signal handlers */ 3818275SEric Cheng (void) signal(SIGINT, sig_break); 3828275SEric Cheng (void) signal(SIGQUIT, sig_break); 3838275SEric Cheng (void) signal(SIGTERM, sig_break); 3848275SEric Cheng (void) signal(SIGWINCH, sig_resize); 3858275SEric Cheng 3868275SEric Cheng /* Initialize ncurses */ 3878275SEric Cheng (void) initscr(); 3888275SEric Cheng (void) cbreak(); 3898275SEric Cheng (void) noecho(); 3908275SEric Cheng (void) curs_set(0); 3918275SEric Cheng timeout(0); 3928275SEric Cheng getmaxyx(stdscr, maxy, maxx); 3938275SEric Cheng } 3948275SEric Cheng 3958275SEric Cheng static void 3968275SEric Cheng curses_fin() 3978275SEric Cheng { 3988275SEric Cheng (void) printw("\n"); 3998275SEric Cheng (void) curs_set(1); 4008275SEric Cheng (void) nocbreak(); 4018275SEric Cheng (void) endwin(); 4028275SEric Cheng 4038275SEric Cheng free(stattable); 4048275SEric Cheng } 4058275SEric Cheng 4068275SEric Cheng static void 4078453SAnurag.Maskey@Sun.COM stat_report(dladm_handle_t handle, kstat_ctl_t *kcp, datalink_id_t linkid, 4088453SAnurag.Maskey@Sun.COM const char *flowname, int opt) 4098275SEric Cheng { 4108275SEric Cheng 4118275SEric Cheng double dlt, ikbs, okbs, ipks, opks; 4128275SEric Cheng 4138275SEric Cheng struct flowlist *fstable = stattable; 4148275SEric Cheng 4158275SEric Cheng if ((opt != LINK_REPORT) && (opt != FLOW_REPORT)) 4168275SEric Cheng return; 4178275SEric Cheng 4188275SEric Cheng /* Handle window resizes */ 4198275SEric Cheng if (handle_resize) { 4208275SEric Cheng (void) endwin(); 4218275SEric Cheng (void) initscr(); 4228275SEric Cheng (void) cbreak(); 4238275SEric Cheng (void) noecho(); 4248275SEric Cheng (void) curs_set(0); 4258275SEric Cheng timeout(0); 4268275SEric Cheng getmaxyx(stdscr, maxy, maxx); 4278275SEric Cheng redraw = 1; 4288275SEric Cheng handle_resize = 0; 4298275SEric Cheng } 4308275SEric Cheng 4318275SEric Cheng /* Print title */ 4328275SEric Cheng (void) erase(); 4338275SEric Cheng (void) attron(A_BOLD); 4348275SEric Cheng (void) move(0, 0); 4358275SEric Cheng if (opt == FLOW_REPORT) 4368275SEric Cheng (void) printw("%-15.15s", "Flow"); 4378275SEric Cheng (void) printw("%-10.10s", "Link"); 4388275SEric Cheng (void) printw("%9.9s %9.9s %9.9s %9.9s ", 4398275SEric Cheng "iKb/s", "oKb/s", "iPk/s", "oPk/s"); 4408275SEric Cheng if (opt == LINK_REPORT) 4418275SEric Cheng (void) printw(" %6.6s", "%Util"); 4428275SEric Cheng (void) printw("\n"); 4438275SEric Cheng (void) attroff(A_BOLD); 4448275SEric Cheng 4458275SEric Cheng (void) move(2, 0); 4468275SEric Cheng 4478275SEric Cheng /* Print stats for each link or flow */ 4488275SEric Cheng bzero(&totalstats, sizeof (totalstats)); 4498275SEric Cheng if (opt == LINK_REPORT) { 4508275SEric Cheng /* Display all links */ 4518275SEric Cheng if (linkid == DATALINK_ALL_LINKID) { 4528453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(link_kstats, handle, 4538275SEric Cheng (void *)kcp, DATALINK_CLASS_ALL, 4548275SEric Cheng DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 4558275SEric Cheng /* Display 1 link */ 4568275SEric Cheng } else { 4578453SAnurag.Maskey@Sun.COM (void) link_kstats(handle, linkid, kcp); 4588275SEric Cheng } 4598453SAnurag.Maskey@Sun.COM print_link_stats(handle, fstable); 4608275SEric Cheng 4618275SEric Cheng } else if (opt == FLOW_REPORT) { 4628275SEric Cheng /* Display 1 flow */ 4638275SEric Cheng if (flowname != NULL) { 4648275SEric Cheng dladm_flow_attr_t fattr; 4658453SAnurag.Maskey@Sun.COM if (dladm_flow_info(handle, flowname, &fattr) != 4668275SEric Cheng DLADM_STATUS_OK) 4678275SEric Cheng return; 4689421SMichael.Lim@Sun.COM (void) flow_kstats(handle, &fattr, kcp); 4698275SEric Cheng /* Display all flows on all links */ 4708275SEric Cheng } else if (linkid == DATALINK_ALL_LINKID) { 4718453SAnurag.Maskey@Sun.COM (void) dladm_walk_datalink_id(link_flowstats, handle, 4728275SEric Cheng (void *)kcp, DATALINK_CLASS_ALL, 4738275SEric Cheng DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); 4748275SEric Cheng /* Display all flows on a link */ 4758275SEric Cheng } else if (linkid != DATALINK_INVALID_LINKID) { 4768453SAnurag.Maskey@Sun.COM (void) dladm_walk_flow(flow_kstats, handle, linkid, kcp, 4778275SEric Cheng B_FALSE); 4788275SEric Cheng } 4798453SAnurag.Maskey@Sun.COM print_flow_stats(handle, fstable); 4808275SEric Cheng 4818275SEric Cheng /* Print totals */ 4828275SEric Cheng (void) attron(A_BOLD); 4838275SEric Cheng dlt = (double)totalstats.snaptime / (double)NANOSEC; 4848275SEric Cheng ikbs = totalstats.rbytes / dlt / 1024; 4858275SEric Cheng okbs = totalstats.obytes / dlt / 1024; 4868275SEric Cheng ipks = totalstats.ipackets / dlt; 4878275SEric Cheng opks = totalstats.opackets / dlt; 4888275SEric Cheng (void) printw("\n%-25.25s", "Totals"); 4898275SEric Cheng (void) printw("%9.2f %9.2f %9.2f %9.2f ", 4908275SEric Cheng ikbs, okbs, ipks, opks); 4918275SEric Cheng (void) attroff(A_BOLD); 4928275SEric Cheng } 4938275SEric Cheng 4948275SEric Cheng if (redraw) 4958275SEric Cheng (void) clearok(stdscr, 1); 4968275SEric Cheng 4978275SEric Cheng if (refresh() == ERR) 4988275SEric Cheng return; 4998275SEric Cheng 5008275SEric Cheng if (redraw) { 5018275SEric Cheng (void) clearok(stdscr, 0); 5028275SEric Cheng redraw = 0; 5038275SEric Cheng } 5048275SEric Cheng } 5058275SEric Cheng 5068275SEric Cheng /* Exported functions */ 5078275SEric Cheng 5088275SEric Cheng /* 5098275SEric Cheng * Continuously display link or flow statstics using a libcurses 5108275SEric Cheng * based display. 5118275SEric Cheng */ 5128275SEric Cheng 5138275SEric Cheng void 5148453SAnurag.Maskey@Sun.COM dladm_continuous(dladm_handle_t handle, datalink_id_t linkid, 5158453SAnurag.Maskey@Sun.COM const char *flowname, int interval, int opt) 5168275SEric Cheng { 5178275SEric Cheng kstat_ctl_t *kcp; 5188275SEric Cheng 5198275SEric Cheng if ((kcp = kstat_open()) == NULL) { 5208275SEric Cheng warn("kstat open operation failed"); 5218275SEric Cheng return; 5228275SEric Cheng } 5238275SEric Cheng 5248275SEric Cheng curses_init(); 5258275SEric Cheng 5268275SEric Cheng for (;;) { 5278275SEric Cheng 5288275SEric Cheng if (handle_break) 5298275SEric Cheng break; 5308275SEric Cheng 5318453SAnurag.Maskey@Sun.COM stat_report(handle, kcp, linkid, flowname, opt); 5328275SEric Cheng 5338275SEric Cheng (void) sleep(max(1, interval)); 5348275SEric Cheng } 5358275SEric Cheng 5369421SMichael.Lim@Sun.COM closedevnet(); 5379421SMichael.Lim@Sun.COM curses_fin(); 5388275SEric Cheng (void) kstat_close(kcp); 5398275SEric Cheng } 5408275SEric Cheng 5418275SEric Cheng /* 5428275SEric Cheng * dladm_kstat_lookup() is a modified version of kstat_lookup which 5438275SEric Cheng * adds the class as a selector. 5448275SEric Cheng */ 5458275SEric Cheng 5468275SEric Cheng kstat_t * 5478275SEric Cheng dladm_kstat_lookup(kstat_ctl_t *kcp, const char *module, int instance, 5488275SEric Cheng const char *name, const char *class) 5498275SEric Cheng { 5508275SEric Cheng kstat_t *ksp = NULL; 5518275SEric Cheng 5528275SEric Cheng for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 5538275SEric Cheng if ((module == NULL || strcmp(ksp->ks_module, module) == 0) && 5548275SEric Cheng (instance == -1 || ksp->ks_instance == instance) && 5558275SEric Cheng (name == NULL || strcmp(ksp->ks_name, name) == 0) && 5568275SEric Cheng (class == NULL || strcmp(ksp->ks_class, class) == 0)) 5578275SEric Cheng return (ksp); 5588275SEric Cheng } 5598275SEric Cheng 5608275SEric Cheng errno = ENOENT; 5618275SEric Cheng return (NULL); 5628275SEric Cheng } 5638275SEric Cheng 5648275SEric Cheng /* 5658275SEric Cheng * dladm_get_stats() populates the supplied pktsum_t structure with 5668275SEric Cheng * the input and output packet and byte kstats from the kstat_t 5678275SEric Cheng * found with dladm_kstat_lookup. 5688275SEric Cheng */ 5698275SEric Cheng void 5708275SEric Cheng dladm_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, pktsum_t *stats) 5718275SEric Cheng { 5728275SEric Cheng 5738275SEric Cheng if (kstat_read(kcp, ksp, NULL) == -1) 5748275SEric Cheng return; 5758275SEric Cheng 5768275SEric Cheng stats->snaptime = gethrtime(); 5778275SEric Cheng 5788275SEric Cheng if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 5798275SEric Cheng &stats->ipackets) < 0) { 5808275SEric Cheng if (dladm_kstat_value(ksp, "ipackets", KSTAT_DATA_UINT64, 5818275SEric Cheng &stats->ipackets) < 0) 5828275SEric Cheng return; 5838275SEric Cheng } 5848275SEric Cheng 5858275SEric Cheng if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 5868275SEric Cheng &stats->opackets) < 0) { 5878275SEric Cheng if (dladm_kstat_value(ksp, "opackets", KSTAT_DATA_UINT64, 5888275SEric Cheng &stats->opackets) < 0) 5898275SEric Cheng return; 5908275SEric Cheng } 5918275SEric Cheng 5928275SEric Cheng if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 5938275SEric Cheng &stats->rbytes) < 0) { 5948275SEric Cheng if (dladm_kstat_value(ksp, "rbytes", KSTAT_DATA_UINT64, 5958275SEric Cheng &stats->rbytes) < 0) 5968275SEric Cheng return; 5978275SEric Cheng } 5988275SEric Cheng 5998275SEric Cheng if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 6008275SEric Cheng &stats->obytes) < 0) { 6018275SEric Cheng if (dladm_kstat_value(ksp, "obytes", KSTAT_DATA_UINT64, 6028275SEric Cheng &stats->obytes) < 0) 6038275SEric Cheng return; 6048275SEric Cheng } 6058275SEric Cheng 6068275SEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 6078275SEric Cheng &stats->ierrors) < 0) { 6088275SEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT64, 6098275SEric Cheng &stats->ierrors) < 0) 6108275SEric Cheng return; 6118275SEric Cheng } 6128275SEric Cheng 6138275SEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 6148275SEric Cheng &stats->oerrors) < 0) { 6158275SEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT64, 6168275SEric Cheng &stats->oerrors) < 0) 6178275SEric Cheng return; 6188275SEric Cheng } 6198275SEric Cheng } 6208275SEric Cheng 6218275SEric Cheng int 6228275SEric Cheng dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 6238275SEric Cheng { 6248275SEric Cheng kstat_named_t *knp; 6258275SEric Cheng 6268275SEric Cheng if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 6278275SEric Cheng return (-1); 6288275SEric Cheng 6298275SEric Cheng if (knp->data_type != type) 6308275SEric Cheng return (-1); 6318275SEric Cheng 6328275SEric Cheng switch (type) { 6338275SEric Cheng case KSTAT_DATA_UINT64: 6348275SEric Cheng *(uint64_t *)buf = knp->value.ui64; 6358275SEric Cheng break; 6368275SEric Cheng case KSTAT_DATA_UINT32: 6378275SEric Cheng *(uint32_t *)buf = knp->value.ui32; 6388275SEric Cheng break; 6398275SEric Cheng default: 6408275SEric Cheng return (-1); 6418275SEric Cheng } 6428275SEric Cheng 6438275SEric Cheng return (0); 6448275SEric Cheng } 6458275SEric Cheng 6468275SEric Cheng dladm_status_t 6478453SAnurag.Maskey@Sun.COM dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid, 6488453SAnurag.Maskey@Sun.COM const char *name, uint8_t type, void *val) 6498275SEric Cheng { 6508275SEric Cheng kstat_ctl_t *kcp; 6518275SEric Cheng char module[DLPI_LINKNAME_MAX]; 6528275SEric Cheng uint_t instance; 6538275SEric Cheng char link[DLPI_LINKNAME_MAX]; 6548275SEric Cheng dladm_status_t status; 6558275SEric Cheng uint32_t flags, media; 6568275SEric Cheng kstat_t *ksp; 6578275SEric Cheng dladm_phys_attr_t dpap; 6588275SEric Cheng 6598453SAnurag.Maskey@Sun.COM if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 6608453SAnurag.Maskey@Sun.COM &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) 6618275SEric Cheng return (status); 6628275SEric Cheng 6638275SEric Cheng if (media != DL_ETHER) 6648275SEric Cheng return (DLADM_STATUS_LINKINVAL); 6658275SEric Cheng 6668453SAnurag.Maskey@Sun.COM status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST); 6678275SEric Cheng 6688275SEric Cheng if (status != DLADM_STATUS_OK) 6698275SEric Cheng return (status); 6708275SEric Cheng 6718275SEric Cheng status = dladm_parselink(dpap.dp_dev, module, &instance); 6728275SEric Cheng 6738275SEric Cheng if (status != DLADM_STATUS_OK) 6748275SEric Cheng return (status); 6758275SEric Cheng 6769571SSowmini.Varadhan@Sun.COM if ((kcp = kstat_open()) == NULL) { 6779571SSowmini.Varadhan@Sun.COM warn("kstat_open operation failed"); 6789571SSowmini.Varadhan@Sun.COM return (-1); 6799571SSowmini.Varadhan@Sun.COM } 6809571SSowmini.Varadhan@Sun.COM 6818275SEric Cheng /* 6828275SEric Cheng * The kstat query could fail if the underlying MAC 6838275SEric Cheng * driver was already detached. 6848275SEric Cheng */ 6858275SEric Cheng if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 6868275SEric Cheng (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) 6878275SEric Cheng goto bail; 6888275SEric Cheng 6898275SEric Cheng if (kstat_read(kcp, ksp, NULL) == -1) 6908275SEric Cheng goto bail; 6918275SEric Cheng 6928275SEric Cheng if (dladm_kstat_value(ksp, name, type, val) < 0) 6938275SEric Cheng goto bail; 6948275SEric Cheng 6958275SEric Cheng (void) kstat_close(kcp); 6968275SEric Cheng return (DLADM_STATUS_OK); 6978275SEric Cheng 6988275SEric Cheng bail: 6998275SEric Cheng (void) kstat_close(kcp); 7008275SEric Cheng return (dladm_errno2status(errno)); 7018275SEric Cheng } 7028275SEric Cheng 7038275SEric Cheng /* Compute sum of 2 pktsums (s1 = s2 + s3) */ 7048275SEric Cheng void 7058275SEric Cheng dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 7068275SEric Cheng { 7078275SEric Cheng s1->rbytes = s2->rbytes + s3->rbytes; 7088275SEric Cheng s1->ipackets = s2->ipackets + s3->ipackets; 7098275SEric Cheng s1->ierrors = s2->ierrors + s3->ierrors; 7108275SEric Cheng s1->obytes = s2->obytes + s3->obytes; 7118275SEric Cheng s1->opackets = s2->opackets + s3->opackets; 7128275SEric Cheng s1->oerrors = s2->oerrors + s3->oerrors; 7138275SEric Cheng s1->snaptime = s2->snaptime; 7148275SEric Cheng } 7158275SEric Cheng 716*11878SVenu.Iyer@Sun.COM #define DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0) 7179220SPrakash.Jalan@Sun.COM 7189220SPrakash.Jalan@Sun.COM 7198275SEric Cheng /* Compute differences between 2 pktsums (s1 = s2 - s3) */ 7208275SEric Cheng void 7218275SEric Cheng dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 7228275SEric Cheng { 7239220SPrakash.Jalan@Sun.COM s1->rbytes = DIFF_STAT(s2->rbytes, s3->rbytes); 7249220SPrakash.Jalan@Sun.COM s1->ipackets = DIFF_STAT(s2->ipackets, s3->ipackets); 7259220SPrakash.Jalan@Sun.COM s1->ierrors = DIFF_STAT(s2->ierrors, s3->ierrors); 7269220SPrakash.Jalan@Sun.COM s1->obytes = DIFF_STAT(s2->obytes, s3->obytes); 7279220SPrakash.Jalan@Sun.COM s1->opackets = DIFF_STAT(s2->opackets, s3->opackets); 7289220SPrakash.Jalan@Sun.COM s1->oerrors = DIFF_STAT(s2->oerrors, s3->oerrors); 7299220SPrakash.Jalan@Sun.COM s1->snaptime = DIFF_STAT(s2->snaptime, s3->snaptime); 7308275SEric Cheng } 731*11878SVenu.Iyer@Sun.COM 732*11878SVenu.Iyer@Sun.COM #define DLSTAT_MAC_RX_SWLANE "mac_rx_swlane" 733*11878SVenu.Iyer@Sun.COM #define DLSTAT_MAC_RX_HWLANE "mac_rx_hwlane" 734*11878SVenu.Iyer@Sun.COM #define DLSTAT_MAC_TX_SWLANE "mac_tx_swlane" 735*11878SVenu.Iyer@Sun.COM #define DLSTAT_MAC_TX_HWLANE "mac_tx_hwlane" 736*11878SVenu.Iyer@Sun.COM #define DLSTAT_MAC_MISC_STAT "mac_misc_stat" 737*11878SVenu.Iyer@Sun.COM #define DLSTAT_MAC_RX_RING "mac_rx_ring" 738*11878SVenu.Iyer@Sun.COM #define DLSTAT_MAC_TX_RING "mac_tx_ring" 739*11878SVenu.Iyer@Sun.COM #define DLSTAT_MAC_FANOUT "mac_rx_swlane0_fanout" 740*11878SVenu.Iyer@Sun.COM 741*11878SVenu.Iyer@Sun.COM typedef struct { 742*11878SVenu.Iyer@Sun.COM const char *si_name; 743*11878SVenu.Iyer@Sun.COM uint_t si_offset; 744*11878SVenu.Iyer@Sun.COM } stat_info_t; 745*11878SVenu.Iyer@Sun.COM 746*11878SVenu.Iyer@Sun.COM #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0])) 747*11878SVenu.Iyer@Sun.COM 748*11878SVenu.Iyer@Sun.COM /* Definitions for rx lane stats */ 749*11878SVenu.Iyer@Sun.COM #define RL_OFF(f) (offsetof(rx_lane_stat_t, f)) 750*11878SVenu.Iyer@Sun.COM 751*11878SVenu.Iyer@Sun.COM static stat_info_t rx_hwlane_stats_list[] = { 752*11878SVenu.Iyer@Sun.COM {"ipackets", RL_OFF(rl_ipackets)}, 753*11878SVenu.Iyer@Sun.COM {"rbytes", RL_OFF(rl_rbytes)}, 754*11878SVenu.Iyer@Sun.COM {"intrs", RL_OFF(rl_intrs)}, 755*11878SVenu.Iyer@Sun.COM {"intrbytes", RL_OFF(rl_intrbytes)}, 756*11878SVenu.Iyer@Sun.COM {"polls", RL_OFF(rl_polls)}, 757*11878SVenu.Iyer@Sun.COM {"pollbytes", RL_OFF(rl_pollbytes)}, 758*11878SVenu.Iyer@Sun.COM {"rxsdrops", RL_OFF(rl_sdrops)}, 759*11878SVenu.Iyer@Sun.COM {"chainunder10", RL_OFF(rl_chl10)}, 760*11878SVenu.Iyer@Sun.COM {"chain10to50", RL_OFF(rl_ch10_50)}, 761*11878SVenu.Iyer@Sun.COM {"chainover50", RL_OFF(rl_chg50)} 762*11878SVenu.Iyer@Sun.COM }; 763*11878SVenu.Iyer@Sun.COM #define RX_HWLANE_STAT_SIZE A_CNT(rx_hwlane_stats_list) 764*11878SVenu.Iyer@Sun.COM 765*11878SVenu.Iyer@Sun.COM static stat_info_t rx_swlane_stats_list[] = { 766*11878SVenu.Iyer@Sun.COM {"ipackets", RL_OFF(rl_ipackets)}, 767*11878SVenu.Iyer@Sun.COM {"rbytes", RL_OFF(rl_rbytes)}, 768*11878SVenu.Iyer@Sun.COM {"local", RL_OFF(rl_lclpackets)}, 769*11878SVenu.Iyer@Sun.COM {"localbytes", RL_OFF(rl_lclbytes)}, 770*11878SVenu.Iyer@Sun.COM {"intrs", RL_OFF(rl_intrs)}, 771*11878SVenu.Iyer@Sun.COM {"intrbytes", RL_OFF(rl_intrbytes)}, 772*11878SVenu.Iyer@Sun.COM {"rxsdrops", RL_OFF(rl_sdrops)} 773*11878SVenu.Iyer@Sun.COM }; 774*11878SVenu.Iyer@Sun.COM #define RX_SWLANE_STAT_SIZE A_CNT(rx_swlane_stats_list) 775*11878SVenu.Iyer@Sun.COM 776*11878SVenu.Iyer@Sun.COM static stat_info_t rx_lane_stats_list[] = { 777*11878SVenu.Iyer@Sun.COM {"ipackets", RL_OFF(rl_ipackets)}, 778*11878SVenu.Iyer@Sun.COM {"rbytes", RL_OFF(rl_rbytes)}, 779*11878SVenu.Iyer@Sun.COM {"local", RL_OFF(rl_lclpackets)}, 780*11878SVenu.Iyer@Sun.COM {"localbytes", RL_OFF(rl_lclbytes)}, 781*11878SVenu.Iyer@Sun.COM {"intrs", RL_OFF(rl_intrs)}, 782*11878SVenu.Iyer@Sun.COM {"intrbytes", RL_OFF(rl_intrbytes)}, 783*11878SVenu.Iyer@Sun.COM {"polls", RL_OFF(rl_polls)}, 784*11878SVenu.Iyer@Sun.COM {"rxsdrops", RL_OFF(rl_sdrops)}, 785*11878SVenu.Iyer@Sun.COM {"pollbytes", RL_OFF(rl_pollbytes)}, 786*11878SVenu.Iyer@Sun.COM {"chainunder10", RL_OFF(rl_chl10)}, 787*11878SVenu.Iyer@Sun.COM {"chain10to50", RL_OFF(rl_ch10_50)}, 788*11878SVenu.Iyer@Sun.COM {"chainover50", RL_OFF(rl_chg50)} 789*11878SVenu.Iyer@Sun.COM }; 790*11878SVenu.Iyer@Sun.COM #define RX_LANE_STAT_SIZE A_CNT(rx_lane_stats_list) 791*11878SVenu.Iyer@Sun.COM 792*11878SVenu.Iyer@Sun.COM /* Definitions for tx lane stats */ 793*11878SVenu.Iyer@Sun.COM #define TL_OFF(f) (offsetof(tx_lane_stat_t, f)) 794*11878SVenu.Iyer@Sun.COM 795*11878SVenu.Iyer@Sun.COM static stat_info_t tx_lane_stats_list[] = { 796*11878SVenu.Iyer@Sun.COM {"opackets", TL_OFF(tl_opackets)}, 797*11878SVenu.Iyer@Sun.COM {"obytes", TL_OFF(tl_obytes)}, 798*11878SVenu.Iyer@Sun.COM {"blockcnt", TL_OFF(tl_blockcnt)}, 799*11878SVenu.Iyer@Sun.COM {"unblockcnt", TL_OFF(tl_unblockcnt)}, 800*11878SVenu.Iyer@Sun.COM {"txsdrops", TL_OFF(tl_sdrops)} 801*11878SVenu.Iyer@Sun.COM }; 802*11878SVenu.Iyer@Sun.COM #define TX_LANE_STAT_SIZE A_CNT(tx_lane_stats_list) 803*11878SVenu.Iyer@Sun.COM 804*11878SVenu.Iyer@Sun.COM /* Definitions for tx/rx misc stats */ 805*11878SVenu.Iyer@Sun.COM #define M_OFF(f) (offsetof(misc_stat_t, f)) 806*11878SVenu.Iyer@Sun.COM 807*11878SVenu.Iyer@Sun.COM static stat_info_t misc_stats_list[] = { 808*11878SVenu.Iyer@Sun.COM {"multircv", M_OFF(ms_multircv)}, 809*11878SVenu.Iyer@Sun.COM {"brdcstrcv", M_OFF(ms_brdcstrcv)}, 810*11878SVenu.Iyer@Sun.COM {"multixmt", M_OFF(ms_multixmt)}, 811*11878SVenu.Iyer@Sun.COM {"brdcstxmt", M_OFF(ms_brdcstxmt)}, 812*11878SVenu.Iyer@Sun.COM {"multircvbytes", M_OFF(ms_multircvbytes)}, 813*11878SVenu.Iyer@Sun.COM {"brdcstrcvbytes", M_OFF(ms_brdcstrcvbytes)}, 814*11878SVenu.Iyer@Sun.COM {"multixmtbytes", M_OFF(ms_multixmtbytes)}, 815*11878SVenu.Iyer@Sun.COM {"brdcstxmtbytes", M_OFF(ms_brdcstxmtbytes)}, 816*11878SVenu.Iyer@Sun.COM {"txerrors", M_OFF(ms_txerrors)}, 817*11878SVenu.Iyer@Sun.COM {"macspoofed", M_OFF(ms_macspoofed)}, 818*11878SVenu.Iyer@Sun.COM {"ipspoofed", M_OFF(ms_ipspoofed)}, 819*11878SVenu.Iyer@Sun.COM {"dhcpspoofed", M_OFF(ms_dhcpspoofed)}, 820*11878SVenu.Iyer@Sun.COM {"restricted", M_OFF(ms_restricted)}, 821*11878SVenu.Iyer@Sun.COM {"ipackets", M_OFF(ms_ipackets)}, 822*11878SVenu.Iyer@Sun.COM {"rbytes", M_OFF(ms_rbytes)}, 823*11878SVenu.Iyer@Sun.COM {"local", M_OFF(ms_local)}, 824*11878SVenu.Iyer@Sun.COM {"localbytes", M_OFF(ms_localbytes)}, 825*11878SVenu.Iyer@Sun.COM {"intrs", M_OFF(ms_intrs)}, 826*11878SVenu.Iyer@Sun.COM {"intrbytes", M_OFF(ms_intrbytes)}, 827*11878SVenu.Iyer@Sun.COM {"polls", M_OFF(ms_polls)}, 828*11878SVenu.Iyer@Sun.COM {"pollbytes", M_OFF(ms_pollbytes)}, 829*11878SVenu.Iyer@Sun.COM {"rxsdrops", M_OFF(ms_rxsdrops)}, 830*11878SVenu.Iyer@Sun.COM {"chainunder10", M_OFF(ms_chainunder10)}, 831*11878SVenu.Iyer@Sun.COM {"chain10to50", M_OFF(ms_chain10to50)}, 832*11878SVenu.Iyer@Sun.COM {"chainover50", M_OFF(ms_chainover50)}, 833*11878SVenu.Iyer@Sun.COM {"obytes", M_OFF(ms_obytes)}, 834*11878SVenu.Iyer@Sun.COM {"opackets", M_OFF(ms_opackets)}, 835*11878SVenu.Iyer@Sun.COM {"blockcnt", M_OFF(ms_blockcnt)}, 836*11878SVenu.Iyer@Sun.COM {"unblockcnt", M_OFF(ms_unblockcnt)}, 837*11878SVenu.Iyer@Sun.COM {"txsdrops", M_OFF(ms_txsdrops)} 838*11878SVenu.Iyer@Sun.COM }; 839*11878SVenu.Iyer@Sun.COM #define MISC_STAT_SIZE A_CNT(misc_stats_list) 840*11878SVenu.Iyer@Sun.COM 841*11878SVenu.Iyer@Sun.COM /* Definitions for rx ring stats */ 842*11878SVenu.Iyer@Sun.COM #define R_OFF(f) (offsetof(ring_stat_t, f)) 843*11878SVenu.Iyer@Sun.COM 844*11878SVenu.Iyer@Sun.COM static stat_info_t rx_ring_stats_list[] = { 845*11878SVenu.Iyer@Sun.COM {"ipackets", R_OFF(r_packets)}, 846*11878SVenu.Iyer@Sun.COM {"rbytes", R_OFF(r_bytes)} 847*11878SVenu.Iyer@Sun.COM }; 848*11878SVenu.Iyer@Sun.COM #define RX_RING_STAT_SIZE A_CNT(rx_ring_stats_list) 849*11878SVenu.Iyer@Sun.COM 850*11878SVenu.Iyer@Sun.COM /* Definitions for tx ring stats */ 851*11878SVenu.Iyer@Sun.COM static stat_info_t tx_ring_stats_list[] = { 852*11878SVenu.Iyer@Sun.COM {"opackets", R_OFF(r_packets)}, 853*11878SVenu.Iyer@Sun.COM {"obytes", R_OFF(r_bytes)} 854*11878SVenu.Iyer@Sun.COM }; 855*11878SVenu.Iyer@Sun.COM #define TX_RING_STAT_SIZE A_CNT(tx_ring_stats_list) 856*11878SVenu.Iyer@Sun.COM 857*11878SVenu.Iyer@Sun.COM /* Definitions for fanout stats */ 858*11878SVenu.Iyer@Sun.COM #define F_OFF(f) (offsetof(fanout_stat_t, f)) 859*11878SVenu.Iyer@Sun.COM 860*11878SVenu.Iyer@Sun.COM static stat_info_t fanout_stats_list[] = { 861*11878SVenu.Iyer@Sun.COM {"ipackets", F_OFF(f_ipackets)}, 862*11878SVenu.Iyer@Sun.COM {"rbytes", F_OFF(f_rbytes)}, 863*11878SVenu.Iyer@Sun.COM }; 864*11878SVenu.Iyer@Sun.COM #define FANOUT_STAT_SIZE A_CNT(fanout_stats_list) 865*11878SVenu.Iyer@Sun.COM 866*11878SVenu.Iyer@Sun.COM /* Definitions for total stats */ 867*11878SVenu.Iyer@Sun.COM #define T_OFF(f) (offsetof(total_stat_t, f)) 868*11878SVenu.Iyer@Sun.COM 869*11878SVenu.Iyer@Sun.COM static stat_info_t total_stats_list[] = { 870*11878SVenu.Iyer@Sun.COM {"ipackets", T_OFF(ts_ipackets)}, 871*11878SVenu.Iyer@Sun.COM {"rbytes", T_OFF(ts_rbytes)}, 872*11878SVenu.Iyer@Sun.COM {"opackets", T_OFF(ts_opackets)}, 873*11878SVenu.Iyer@Sun.COM {"obytes", T_OFF(ts_obytes)} 874*11878SVenu.Iyer@Sun.COM }; 875*11878SVenu.Iyer@Sun.COM #define TOTAL_STAT_SIZE A_CNT(total_stats_list) 876*11878SVenu.Iyer@Sun.COM 877*11878SVenu.Iyer@Sun.COM /* Definitions for aggr stats */ 878*11878SVenu.Iyer@Sun.COM #define AP_OFF(f) (offsetof(aggr_port_stat_t, f)) 879*11878SVenu.Iyer@Sun.COM 880*11878SVenu.Iyer@Sun.COM static stat_info_t aggr_port_stats_list[] = { 881*11878SVenu.Iyer@Sun.COM {"ipackets64", AP_OFF(ap_ipackets)}, 882*11878SVenu.Iyer@Sun.COM {"rbytes64", AP_OFF(ap_rbytes)}, 883*11878SVenu.Iyer@Sun.COM {"opackets64", AP_OFF(ap_opackets)}, 884*11878SVenu.Iyer@Sun.COM {"obytes64", AP_OFF(ap_obytes)} 885*11878SVenu.Iyer@Sun.COM }; 886*11878SVenu.Iyer@Sun.COM #define AGGR_PORT_STAT_SIZE A_CNT(aggr_port_stats_list) 887*11878SVenu.Iyer@Sun.COM 888*11878SVenu.Iyer@Sun.COM /* Definitions for flow stats */ 889*11878SVenu.Iyer@Sun.COM #define FL_OFF(f) (offsetof(flow_stat_t, f)) 890*11878SVenu.Iyer@Sun.COM 891*11878SVenu.Iyer@Sun.COM static stat_info_t flow_stats_list[] = { 892*11878SVenu.Iyer@Sun.COM {"ipackets", FL_OFF(fl_ipackets)}, 893*11878SVenu.Iyer@Sun.COM {"rbytes", FL_OFF(fl_rbytes)}, 894*11878SVenu.Iyer@Sun.COM {"opackets", FL_OFF(fl_opackets)}, 895*11878SVenu.Iyer@Sun.COM {"obytes", FL_OFF(fl_obytes)} 896*11878SVenu.Iyer@Sun.COM }; 897*11878SVenu.Iyer@Sun.COM #define FLOW_STAT_SIZE A_CNT(flow_stats_list) 898*11878SVenu.Iyer@Sun.COM 899*11878SVenu.Iyer@Sun.COM /* Rx lane specific functions */ 900*11878SVenu.Iyer@Sun.COM void * dlstat_rx_lane_stats(dladm_handle_t, datalink_id_t); 901*11878SVenu.Iyer@Sun.COM static boolean_t i_dlstat_rx_lane_match(void *, void *); 902*11878SVenu.Iyer@Sun.COM static void * i_dlstat_rx_lane_stat_entry_diff(void *, void *); 903*11878SVenu.Iyer@Sun.COM 904*11878SVenu.Iyer@Sun.COM /* Tx lane specific functions */ 905*11878SVenu.Iyer@Sun.COM void * dlstat_tx_lane_stats(dladm_handle_t, datalink_id_t); 906*11878SVenu.Iyer@Sun.COM static boolean_t i_dlstat_tx_lane_match(void *, void *); 907*11878SVenu.Iyer@Sun.COM static void * i_dlstat_tx_lane_stat_entry_diff(void *, void *); 908*11878SVenu.Iyer@Sun.COM 909*11878SVenu.Iyer@Sun.COM /* Rx lane total specific functions */ 910*11878SVenu.Iyer@Sun.COM void * dlstat_rx_lane_total_stats(dladm_handle_t, 911*11878SVenu.Iyer@Sun.COM datalink_id_t); 912*11878SVenu.Iyer@Sun.COM 913*11878SVenu.Iyer@Sun.COM /* Tx lane total specific functions */ 914*11878SVenu.Iyer@Sun.COM void * dlstat_tx_lane_total_stats(dladm_handle_t, 915*11878SVenu.Iyer@Sun.COM datalink_id_t); 916*11878SVenu.Iyer@Sun.COM 917*11878SVenu.Iyer@Sun.COM /* Fanout specific functions */ 918*11878SVenu.Iyer@Sun.COM void * dlstat_fanout_stats(dladm_handle_t, datalink_id_t); 919*11878SVenu.Iyer@Sun.COM static boolean_t i_dlstat_fanout_match(void *, void *); 920*11878SVenu.Iyer@Sun.COM static void * i_dlstat_fanout_stat_entry_diff(void *, void *); 921*11878SVenu.Iyer@Sun.COM 922*11878SVenu.Iyer@Sun.COM /* Rx ring specific functions */ 923*11878SVenu.Iyer@Sun.COM void * dlstat_rx_ring_stats(dladm_handle_t, datalink_id_t); 924*11878SVenu.Iyer@Sun.COM static boolean_t i_dlstat_rx_ring_match(void *, void *); 925*11878SVenu.Iyer@Sun.COM static void * i_dlstat_rx_ring_stat_entry_diff(void *, void *); 926*11878SVenu.Iyer@Sun.COM 927*11878SVenu.Iyer@Sun.COM /* Tx ring specific functions */ 928*11878SVenu.Iyer@Sun.COM void * dlstat_tx_ring_stats(dladm_handle_t, datalink_id_t); 929*11878SVenu.Iyer@Sun.COM static boolean_t i_dlstat_tx_ring_match(void *, void *); 930*11878SVenu.Iyer@Sun.COM static void * i_dlstat_tx_ring_stat_entry_diff(void *, void *); 931*11878SVenu.Iyer@Sun.COM 932*11878SVenu.Iyer@Sun.COM /* Rx ring total specific functions */ 933*11878SVenu.Iyer@Sun.COM void * dlstat_rx_ring_total_stats(dladm_handle_t, 934*11878SVenu.Iyer@Sun.COM datalink_id_t); 935*11878SVenu.Iyer@Sun.COM 936*11878SVenu.Iyer@Sun.COM /* Tx ring total specific functions */ 937*11878SVenu.Iyer@Sun.COM void * dlstat_tx_ring_total_stats(dladm_handle_t, 938*11878SVenu.Iyer@Sun.COM datalink_id_t); 939*11878SVenu.Iyer@Sun.COM 940*11878SVenu.Iyer@Sun.COM /* Summary specific functions */ 941*11878SVenu.Iyer@Sun.COM void * dlstat_total_stats(dladm_handle_t, datalink_id_t); 942*11878SVenu.Iyer@Sun.COM static boolean_t i_dlstat_total_match(void *, void *); 943*11878SVenu.Iyer@Sun.COM static void * i_dlstat_total_stat_entry_diff(void *, void *); 944*11878SVenu.Iyer@Sun.COM 945*11878SVenu.Iyer@Sun.COM /* Aggr port specific functions */ 946*11878SVenu.Iyer@Sun.COM void * dlstat_aggr_port_stats(dladm_handle_t, datalink_id_t); 947*11878SVenu.Iyer@Sun.COM static boolean_t i_dlstat_aggr_port_match(void *, void *); 948*11878SVenu.Iyer@Sun.COM static void * i_dlstat_aggr_port_stat_entry_diff(void *, void *); 949*11878SVenu.Iyer@Sun.COM 950*11878SVenu.Iyer@Sun.COM /* Misc stat specific functions */ 951*11878SVenu.Iyer@Sun.COM void * dlstat_misc_stats(dladm_handle_t, datalink_id_t); 952*11878SVenu.Iyer@Sun.COM 953*11878SVenu.Iyer@Sun.COM typedef void * dladm_stat_query_t(dladm_handle_t, datalink_id_t); 954*11878SVenu.Iyer@Sun.COM typedef boolean_t dladm_stat_match_t(void *, void *); 955*11878SVenu.Iyer@Sun.COM typedef void * dladm_stat_diff_t(void *, void *); 956*11878SVenu.Iyer@Sun.COM 957*11878SVenu.Iyer@Sun.COM typedef struct dladm_stat_desc_s { 958*11878SVenu.Iyer@Sun.COM dladm_stat_type_t ds_stattype; 959*11878SVenu.Iyer@Sun.COM dladm_stat_query_t *ds_querystat; 960*11878SVenu.Iyer@Sun.COM dladm_stat_match_t *ds_matchstat; 961*11878SVenu.Iyer@Sun.COM dladm_stat_diff_t *ds_diffstat; 962*11878SVenu.Iyer@Sun.COM uint_t ds_offset; 963*11878SVenu.Iyer@Sun.COM stat_info_t *ds_statlist; 964*11878SVenu.Iyer@Sun.COM uint_t ds_statsize; 965*11878SVenu.Iyer@Sun.COM } dladm_stat_desc_t; 966*11878SVenu.Iyer@Sun.COM 967*11878SVenu.Iyer@Sun.COM /* 968*11878SVenu.Iyer@Sun.COM * dladm_stat_table has one entry for each supported stat. ds_querystat returns 969*11878SVenu.Iyer@Sun.COM * a chain of 'stat entries' for the queried stat. 970*11878SVenu.Iyer@Sun.COM * Each stat entry has set of identifiers (ids) and an object containing actual 971*11878SVenu.Iyer@Sun.COM * stat values. These stat entry objects are chained together in a linked list 972*11878SVenu.Iyer@Sun.COM * of datatype dladm_stat_chain_t. Head of this list is returned to the caller 973*11878SVenu.Iyer@Sun.COM * of dladm_link_stat_query. 974*11878SVenu.Iyer@Sun.COM * 975*11878SVenu.Iyer@Sun.COM * One node in the chain is shown below: 976*11878SVenu.Iyer@Sun.COM * 977*11878SVenu.Iyer@Sun.COM * ------------------------- 978*11878SVenu.Iyer@Sun.COM * | dc_statentry | 979*11878SVenu.Iyer@Sun.COM * | -------------- | 980*11878SVenu.Iyer@Sun.COM * | | ids | | 981*11878SVenu.Iyer@Sun.COM * | -------------- | 982*11878SVenu.Iyer@Sun.COM * | | stat fields | | 983*11878SVenu.Iyer@Sun.COM * | -------------- | 984*11878SVenu.Iyer@Sun.COM * ------------------------- 985*11878SVenu.Iyer@Sun.COM * | dc_next ---------|------> to next stat entry 986*11878SVenu.Iyer@Sun.COM * ------------------------- 987*11878SVenu.Iyer@Sun.COM * 988*11878SVenu.Iyer@Sun.COM * In particular, for query DLADM_STAT_RX_LANE, dc_statentry carries pointer to 989*11878SVenu.Iyer@Sun.COM * object of type rx_lane_stat_entry_t. 990*11878SVenu.Iyer@Sun.COM * 991*11878SVenu.Iyer@Sun.COM * dladm_link_stat_query_all returns similar chain. However, instead of storing 992*11878SVenu.Iyer@Sun.COM * stat fields as raw numbers, it stores those as chain of <name, value> pairs. 993*11878SVenu.Iyer@Sun.COM * The resulting structure is depicted below: 994*11878SVenu.Iyer@Sun.COM * 995*11878SVenu.Iyer@Sun.COM * ------------------------- 996*11878SVenu.Iyer@Sun.COM * | dc_statentry | 997*11878SVenu.Iyer@Sun.COM * | -------------- | --------------- 998*11878SVenu.Iyer@Sun.COM * | | nv_header | | | name, val | 999*11878SVenu.Iyer@Sun.COM * | -------------- | --------------- 1000*11878SVenu.Iyer@Sun.COM * | | nve_stats---|----|-->| nv_nextstat--|---> to next name, val pair 1001*11878SVenu.Iyer@Sun.COM * | -------------- | --------------- 1002*11878SVenu.Iyer@Sun.COM * ------------------------- 1003*11878SVenu.Iyer@Sun.COM * | dc_next ---------|------> to next stat entry 1004*11878SVenu.Iyer@Sun.COM * ------------------------- 1005*11878SVenu.Iyer@Sun.COM */ 1006*11878SVenu.Iyer@Sun.COM static dladm_stat_desc_t dladm_stat_table[] = { 1007*11878SVenu.Iyer@Sun.COM { DLADM_STAT_RX_LANE, dlstat_rx_lane_stats, 1008*11878SVenu.Iyer@Sun.COM i_dlstat_rx_lane_match, i_dlstat_rx_lane_stat_entry_diff, 1009*11878SVenu.Iyer@Sun.COM offsetof(rx_lane_stat_entry_t, rle_stats), 1010*11878SVenu.Iyer@Sun.COM rx_lane_stats_list, RX_LANE_STAT_SIZE}, 1011*11878SVenu.Iyer@Sun.COM 1012*11878SVenu.Iyer@Sun.COM { DLADM_STAT_TX_LANE, dlstat_tx_lane_stats, 1013*11878SVenu.Iyer@Sun.COM i_dlstat_tx_lane_match, i_dlstat_tx_lane_stat_entry_diff, 1014*11878SVenu.Iyer@Sun.COM offsetof(tx_lane_stat_entry_t, tle_stats), 1015*11878SVenu.Iyer@Sun.COM tx_lane_stats_list, TX_LANE_STAT_SIZE}, 1016*11878SVenu.Iyer@Sun.COM 1017*11878SVenu.Iyer@Sun.COM { DLADM_STAT_RX_LANE_TOTAL, dlstat_rx_lane_total_stats, 1018*11878SVenu.Iyer@Sun.COM i_dlstat_rx_lane_match, i_dlstat_rx_lane_stat_entry_diff, 1019*11878SVenu.Iyer@Sun.COM offsetof(rx_lane_stat_entry_t, rle_stats), 1020*11878SVenu.Iyer@Sun.COM rx_lane_stats_list, RX_LANE_STAT_SIZE}, 1021*11878SVenu.Iyer@Sun.COM 1022*11878SVenu.Iyer@Sun.COM { DLADM_STAT_TX_LANE_TOTAL, dlstat_tx_lane_total_stats, 1023*11878SVenu.Iyer@Sun.COM i_dlstat_tx_lane_match, i_dlstat_tx_lane_stat_entry_diff, 1024*11878SVenu.Iyer@Sun.COM offsetof(tx_lane_stat_entry_t, tle_stats), 1025*11878SVenu.Iyer@Sun.COM tx_lane_stats_list, TX_LANE_STAT_SIZE}, 1026*11878SVenu.Iyer@Sun.COM 1027*11878SVenu.Iyer@Sun.COM { DLADM_STAT_RX_LANE_FOUT, dlstat_fanout_stats, 1028*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_match, i_dlstat_fanout_stat_entry_diff, 1029*11878SVenu.Iyer@Sun.COM offsetof(fanout_stat_entry_t, fe_stats), 1030*11878SVenu.Iyer@Sun.COM fanout_stats_list, FANOUT_STAT_SIZE}, 1031*11878SVenu.Iyer@Sun.COM 1032*11878SVenu.Iyer@Sun.COM { DLADM_STAT_RX_RING, dlstat_rx_ring_stats, 1033*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_match, i_dlstat_rx_ring_stat_entry_diff, 1034*11878SVenu.Iyer@Sun.COM offsetof(ring_stat_entry_t, re_stats), 1035*11878SVenu.Iyer@Sun.COM rx_ring_stats_list, RX_RING_STAT_SIZE}, 1036*11878SVenu.Iyer@Sun.COM 1037*11878SVenu.Iyer@Sun.COM { DLADM_STAT_TX_RING, dlstat_tx_ring_stats, 1038*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_match, i_dlstat_tx_ring_stat_entry_diff, 1039*11878SVenu.Iyer@Sun.COM offsetof(ring_stat_entry_t, re_stats), 1040*11878SVenu.Iyer@Sun.COM tx_ring_stats_list, TX_RING_STAT_SIZE}, 1041*11878SVenu.Iyer@Sun.COM 1042*11878SVenu.Iyer@Sun.COM { DLADM_STAT_RX_RING_TOTAL, dlstat_rx_ring_total_stats, 1043*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_match, i_dlstat_rx_ring_stat_entry_diff, 1044*11878SVenu.Iyer@Sun.COM offsetof(ring_stat_entry_t, re_stats), 1045*11878SVenu.Iyer@Sun.COM rx_ring_stats_list, RX_RING_STAT_SIZE}, 1046*11878SVenu.Iyer@Sun.COM 1047*11878SVenu.Iyer@Sun.COM { DLADM_STAT_TX_RING_TOTAL, dlstat_tx_ring_total_stats, 1048*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_match, i_dlstat_tx_ring_stat_entry_diff, 1049*11878SVenu.Iyer@Sun.COM offsetof(ring_stat_entry_t, re_stats), 1050*11878SVenu.Iyer@Sun.COM tx_ring_stats_list, TX_RING_STAT_SIZE}, 1051*11878SVenu.Iyer@Sun.COM 1052*11878SVenu.Iyer@Sun.COM { DLADM_STAT_TOTAL, dlstat_total_stats, 1053*11878SVenu.Iyer@Sun.COM i_dlstat_total_match, i_dlstat_total_stat_entry_diff, 1054*11878SVenu.Iyer@Sun.COM offsetof(total_stat_entry_t, tse_stats), 1055*11878SVenu.Iyer@Sun.COM total_stats_list, TOTAL_STAT_SIZE}, 1056*11878SVenu.Iyer@Sun.COM 1057*11878SVenu.Iyer@Sun.COM { DLADM_STAT_AGGR_PORT, dlstat_aggr_port_stats, 1058*11878SVenu.Iyer@Sun.COM i_dlstat_aggr_port_match, i_dlstat_aggr_port_stat_entry_diff, 1059*11878SVenu.Iyer@Sun.COM offsetof(aggr_port_stat_entry_t, ape_stats), 1060*11878SVenu.Iyer@Sun.COM aggr_port_stats_list, AGGR_PORT_STAT_SIZE}, 1061*11878SVenu.Iyer@Sun.COM /* 1062*11878SVenu.Iyer@Sun.COM * We don't support -i <interval> query with misc stats. Several table fields 1063*11878SVenu.Iyer@Sun.COM * are left uninitialized thus. 1064*11878SVenu.Iyer@Sun.COM */ 1065*11878SVenu.Iyer@Sun.COM { DLADM_STAT_MISC, dlstat_misc_stats, 1066*11878SVenu.Iyer@Sun.COM NULL, NULL, 1067*11878SVenu.Iyer@Sun.COM 0, 1068*11878SVenu.Iyer@Sun.COM misc_stats_list, MISC_STAT_SIZE} 1069*11878SVenu.Iyer@Sun.COM }; 1070*11878SVenu.Iyer@Sun.COM 1071*11878SVenu.Iyer@Sun.COM /* Internal functions */ 1072*11878SVenu.Iyer@Sun.COM static void * 1073*11878SVenu.Iyer@Sun.COM dlstat_diff_stats(void *arg1, void *arg2, dladm_stat_type_t stattype) 1074*11878SVenu.Iyer@Sun.COM { 1075*11878SVenu.Iyer@Sun.COM return (dladm_stat_table[stattype].ds_diffstat(arg1, arg2)); 1076*11878SVenu.Iyer@Sun.COM } 1077*11878SVenu.Iyer@Sun.COM 1078*11878SVenu.Iyer@Sun.COM static boolean_t 1079*11878SVenu.Iyer@Sun.COM dlstat_match_stats(void *arg1, void *arg2, dladm_stat_type_t stattype) 1080*11878SVenu.Iyer@Sun.COM { 1081*11878SVenu.Iyer@Sun.COM return (dladm_stat_table[stattype].ds_matchstat(arg1, arg2)); 1082*11878SVenu.Iyer@Sun.COM } 1083*11878SVenu.Iyer@Sun.COM 1084*11878SVenu.Iyer@Sun.COM /* Diff between two stats */ 1085*11878SVenu.Iyer@Sun.COM static void 1086*11878SVenu.Iyer@Sun.COM i_dlstat_diff_stats(void *diff, void *op1, void *op2, 1087*11878SVenu.Iyer@Sun.COM stat_info_t stats_list[], uint_t size) 1088*11878SVenu.Iyer@Sun.COM { 1089*11878SVenu.Iyer@Sun.COM int i; 1090*11878SVenu.Iyer@Sun.COM 1091*11878SVenu.Iyer@Sun.COM for (i = 0; i < size; i++) { 1092*11878SVenu.Iyer@Sun.COM uint64_t *op1_val = (void *) 1093*11878SVenu.Iyer@Sun.COM ((uchar_t *)op1 + stats_list[i].si_offset); 1094*11878SVenu.Iyer@Sun.COM uint64_t *op2_val = (void *) 1095*11878SVenu.Iyer@Sun.COM ((uchar_t *)op2 + stats_list[i].si_offset); 1096*11878SVenu.Iyer@Sun.COM uint64_t *diff_val = (void *) 1097*11878SVenu.Iyer@Sun.COM ((uchar_t *)diff + stats_list[i].si_offset); 1098*11878SVenu.Iyer@Sun.COM 1099*11878SVenu.Iyer@Sun.COM *diff_val = DIFF_STAT(*op1_val, *op2_val); 1100*11878SVenu.Iyer@Sun.COM } 1101*11878SVenu.Iyer@Sun.COM } 1102*11878SVenu.Iyer@Sun.COM 1103*11878SVenu.Iyer@Sun.COM /* 1104*11878SVenu.Iyer@Sun.COM * Perform diff = s1 - s2, where diff, s1, s2 are structure objects of same 1105*11878SVenu.Iyer@Sun.COM * datatype. slist is list of offsets of the fields within the structure. 1106*11878SVenu.Iyer@Sun.COM */ 1107*11878SVenu.Iyer@Sun.COM #define DLSTAT_DIFF_STAT(s1, s2, diff, f, slist, sz) { \ 1108*11878SVenu.Iyer@Sun.COM if (s2 == NULL) { \ 1109*11878SVenu.Iyer@Sun.COM bcopy(&s1->f, &diff->f, sizeof (s1->f)); \ 1110*11878SVenu.Iyer@Sun.COM } else { \ 1111*11878SVenu.Iyer@Sun.COM i_dlstat_diff_stats(&diff->f, &s1->f, \ 1112*11878SVenu.Iyer@Sun.COM &s2->f, slist, sz); \ 1113*11878SVenu.Iyer@Sun.COM } \ 1114*11878SVenu.Iyer@Sun.COM } 1115*11878SVenu.Iyer@Sun.COM 1116*11878SVenu.Iyer@Sun.COM /* Sum two stats */ 1117*11878SVenu.Iyer@Sun.COM static void 1118*11878SVenu.Iyer@Sun.COM i_dlstat_sum_stats(void *sum, void *op1, void *op2, 1119*11878SVenu.Iyer@Sun.COM stat_info_t stats_list[], uint_t size) 1120*11878SVenu.Iyer@Sun.COM { 1121*11878SVenu.Iyer@Sun.COM int i; 1122*11878SVenu.Iyer@Sun.COM 1123*11878SVenu.Iyer@Sun.COM for (i = 0; i < size; i++) { 1124*11878SVenu.Iyer@Sun.COM uint64_t *op1_val = (void *) 1125*11878SVenu.Iyer@Sun.COM ((uchar_t *)op1 + stats_list[i].si_offset); 1126*11878SVenu.Iyer@Sun.COM uint64_t *op2_val = (void *) 1127*11878SVenu.Iyer@Sun.COM ((uchar_t *)op2 + stats_list[i].si_offset); 1128*11878SVenu.Iyer@Sun.COM uint64_t *sum_val = (void *) 1129*11878SVenu.Iyer@Sun.COM ((uchar_t *)sum + stats_list[i].si_offset); 1130*11878SVenu.Iyer@Sun.COM 1131*11878SVenu.Iyer@Sun.COM *sum_val = *op1_val + *op2_val; 1132*11878SVenu.Iyer@Sun.COM } 1133*11878SVenu.Iyer@Sun.COM } 1134*11878SVenu.Iyer@Sun.COM 1135*11878SVenu.Iyer@Sun.COM /* Look up kstat value */ 1136*11878SVenu.Iyer@Sun.COM static void 1137*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, void *stats, 1138*11878SVenu.Iyer@Sun.COM stat_info_t stats_list[], uint_t size) 1139*11878SVenu.Iyer@Sun.COM { 1140*11878SVenu.Iyer@Sun.COM int i; 1141*11878SVenu.Iyer@Sun.COM 1142*11878SVenu.Iyer@Sun.COM if (kstat_read(kcp, ksp, NULL) == -1) 1143*11878SVenu.Iyer@Sun.COM return; 1144*11878SVenu.Iyer@Sun.COM 1145*11878SVenu.Iyer@Sun.COM for (i = 0; i < size; i++) { 1146*11878SVenu.Iyer@Sun.COM uint64_t *val = (void *) 1147*11878SVenu.Iyer@Sun.COM ((uchar_t *)stats + stats_list[i].si_offset); 1148*11878SVenu.Iyer@Sun.COM 1149*11878SVenu.Iyer@Sun.COM if (dladm_kstat_value(ksp, stats_list[i].si_name, 1150*11878SVenu.Iyer@Sun.COM KSTAT_DATA_UINT64, val) < 0) 1151*11878SVenu.Iyer@Sun.COM return; 1152*11878SVenu.Iyer@Sun.COM } 1153*11878SVenu.Iyer@Sun.COM } 1154*11878SVenu.Iyer@Sun.COM 1155*11878SVenu.Iyer@Sun.COM /* Append linked list list1 to linked list list2 and return resulting list */ 1156*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1157*11878SVenu.Iyer@Sun.COM i_dlstat_join_lists(dladm_stat_chain_t *list1, dladm_stat_chain_t *list2) 1158*11878SVenu.Iyer@Sun.COM { 1159*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *curr; 1160*11878SVenu.Iyer@Sun.COM 1161*11878SVenu.Iyer@Sun.COM if (list1 == NULL) 1162*11878SVenu.Iyer@Sun.COM return (list2); 1163*11878SVenu.Iyer@Sun.COM 1164*11878SVenu.Iyer@Sun.COM /* list1 has at least one element, find last element in list1 */ 1165*11878SVenu.Iyer@Sun.COM curr = list1; 1166*11878SVenu.Iyer@Sun.COM while (curr->dc_next != NULL) 1167*11878SVenu.Iyer@Sun.COM curr = curr->dc_next; 1168*11878SVenu.Iyer@Sun.COM 1169*11878SVenu.Iyer@Sun.COM curr->dc_next = list2; 1170*11878SVenu.Iyer@Sun.COM return (list1); 1171*11878SVenu.Iyer@Sun.COM } 1172*11878SVenu.Iyer@Sun.COM 1173*11878SVenu.Iyer@Sun.COM uint_t default_idlist[] = {0}; 1174*11878SVenu.Iyer@Sun.COM uint_t default_idlist_size = 1; 1175*11878SVenu.Iyer@Sun.COM 1176*11878SVenu.Iyer@Sun.COM typedef enum { 1177*11878SVenu.Iyer@Sun.COM DLSTAT_RX_RING_IDLIST, 1178*11878SVenu.Iyer@Sun.COM DLSTAT_TX_RING_IDLIST, 1179*11878SVenu.Iyer@Sun.COM DLSTAT_RX_HWLANE_IDLIST, 1180*11878SVenu.Iyer@Sun.COM DLSTAT_TX_HWLANE_IDLIST, 1181*11878SVenu.Iyer@Sun.COM DLSTAT_FANOUT_IDLIST 1182*11878SVenu.Iyer@Sun.COM } dlstat_idlist_type_t; 1183*11878SVenu.Iyer@Sun.COM 1184*11878SVenu.Iyer@Sun.COM void 1185*11878SVenu.Iyer@Sun.COM dladm_sort_index_list(uint_t idlist[], uint_t size) 1186*11878SVenu.Iyer@Sun.COM { 1187*11878SVenu.Iyer@Sun.COM int i, j; 1188*11878SVenu.Iyer@Sun.COM 1189*11878SVenu.Iyer@Sun.COM for (j = 1; j < size; j++) { 1190*11878SVenu.Iyer@Sun.COM int key = idlist[j]; 1191*11878SVenu.Iyer@Sun.COM for (i = j - 1; (i >= 0) && (idlist[i] > key); i--) 1192*11878SVenu.Iyer@Sun.COM idlist[i + 1] = idlist[i]; 1193*11878SVenu.Iyer@Sun.COM idlist[i + 1] = key; 1194*11878SVenu.Iyer@Sun.COM } 1195*11878SVenu.Iyer@Sun.COM } 1196*11878SVenu.Iyer@Sun.COM 1197*11878SVenu.Iyer@Sun.COM /* Support for legacy drivers */ 1198*11878SVenu.Iyer@Sun.COM void 1199*11878SVenu.Iyer@Sun.COM i_query_legacy_stats(const char *linkname, pktsum_t *stats) 1200*11878SVenu.Iyer@Sun.COM { 1201*11878SVenu.Iyer@Sun.COM kstat_ctl_t *kcp; 1202*11878SVenu.Iyer@Sun.COM kstat_t *ksp; 1203*11878SVenu.Iyer@Sun.COM 1204*11878SVenu.Iyer@Sun.COM bzero(stats, sizeof (*stats)); 1205*11878SVenu.Iyer@Sun.COM 1206*11878SVenu.Iyer@Sun.COM if ((kcp = kstat_open()) == NULL) 1207*11878SVenu.Iyer@Sun.COM return; 1208*11878SVenu.Iyer@Sun.COM 1209*11878SVenu.Iyer@Sun.COM ksp = dladm_kstat_lookup(kcp, "link", 0, linkname, NULL); 1210*11878SVenu.Iyer@Sun.COM 1211*11878SVenu.Iyer@Sun.COM if (ksp != NULL) 1212*11878SVenu.Iyer@Sun.COM dladm_get_stats(kcp, ksp, stats); 1213*11878SVenu.Iyer@Sun.COM 1214*11878SVenu.Iyer@Sun.COM (void) kstat_close(kcp); 1215*11878SVenu.Iyer@Sun.COM } 1216*11878SVenu.Iyer@Sun.COM 1217*11878SVenu.Iyer@Sun.COM void * 1218*11878SVenu.Iyer@Sun.COM i_dlstat_legacy_rx_lane_stats(const char *linkname) 1219*11878SVenu.Iyer@Sun.COM { 1220*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 1221*11878SVenu.Iyer@Sun.COM pktsum_t stats; 1222*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *rx_lane_stat_entry; 1223*11878SVenu.Iyer@Sun.COM 1224*11878SVenu.Iyer@Sun.COM bzero(&stats, sizeof (pktsum_t)); 1225*11878SVenu.Iyer@Sun.COM 1226*11878SVenu.Iyer@Sun.COM /* Query for dls stats */ 1227*11878SVenu.Iyer@Sun.COM i_query_legacy_stats(linkname, &stats); 1228*11878SVenu.Iyer@Sun.COM 1229*11878SVenu.Iyer@Sun.COM /* Convert to desired data type */ 1230*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1231*11878SVenu.Iyer@Sun.COM if (rx_lane_stat_entry == NULL) 1232*11878SVenu.Iyer@Sun.COM goto done; 1233*11878SVenu.Iyer@Sun.COM 1234*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1235*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_id = L_SWLANE; 1236*11878SVenu.Iyer@Sun.COM 1237*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets; 1238*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets; 1239*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes; 1240*11878SVenu.Iyer@Sun.COM 1241*11878SVenu.Iyer@Sun.COM /* Allocate memory for wrapper */ 1242*11878SVenu.Iyer@Sun.COM head = malloc(sizeof (dladm_stat_chain_t)); 1243*11878SVenu.Iyer@Sun.COM if (head == NULL) { 1244*11878SVenu.Iyer@Sun.COM free(rx_lane_stat_entry); 1245*11878SVenu.Iyer@Sun.COM goto done; 1246*11878SVenu.Iyer@Sun.COM } 1247*11878SVenu.Iyer@Sun.COM 1248*11878SVenu.Iyer@Sun.COM head->dc_statentry = rx_lane_stat_entry; 1249*11878SVenu.Iyer@Sun.COM head->dc_next = NULL; 1250*11878SVenu.Iyer@Sun.COM done: 1251*11878SVenu.Iyer@Sun.COM return (head); 1252*11878SVenu.Iyer@Sun.COM } 1253*11878SVenu.Iyer@Sun.COM 1254*11878SVenu.Iyer@Sun.COM void * 1255*11878SVenu.Iyer@Sun.COM i_dlstat_legacy_tx_lane_stats(const char *linkname) 1256*11878SVenu.Iyer@Sun.COM { 1257*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 1258*11878SVenu.Iyer@Sun.COM pktsum_t stats; 1259*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *tx_lane_stat_entry; 1260*11878SVenu.Iyer@Sun.COM 1261*11878SVenu.Iyer@Sun.COM bzero(&stats, sizeof (pktsum_t)); 1262*11878SVenu.Iyer@Sun.COM 1263*11878SVenu.Iyer@Sun.COM /* Query for dls stats */ 1264*11878SVenu.Iyer@Sun.COM i_query_legacy_stats(linkname, &stats); 1265*11878SVenu.Iyer@Sun.COM 1266*11878SVenu.Iyer@Sun.COM /* Convert to desired data type */ 1267*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1268*11878SVenu.Iyer@Sun.COM if (tx_lane_stat_entry == NULL) 1269*11878SVenu.Iyer@Sun.COM goto done; 1270*11878SVenu.Iyer@Sun.COM 1271*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 1272*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_id = L_SWLANE; 1273*11878SVenu.Iyer@Sun.COM 1274*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets; 1275*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes; 1276*11878SVenu.Iyer@Sun.COM 1277*11878SVenu.Iyer@Sun.COM /* Allocate memory for wrapper */ 1278*11878SVenu.Iyer@Sun.COM head = malloc(sizeof (dladm_stat_chain_t)); 1279*11878SVenu.Iyer@Sun.COM if (head == NULL) { 1280*11878SVenu.Iyer@Sun.COM free(tx_lane_stat_entry); 1281*11878SVenu.Iyer@Sun.COM goto done; 1282*11878SVenu.Iyer@Sun.COM } 1283*11878SVenu.Iyer@Sun.COM 1284*11878SVenu.Iyer@Sun.COM head->dc_statentry = tx_lane_stat_entry; 1285*11878SVenu.Iyer@Sun.COM head->dc_next = NULL; 1286*11878SVenu.Iyer@Sun.COM done: 1287*11878SVenu.Iyer@Sun.COM return (head); 1288*11878SVenu.Iyer@Sun.COM } 1289*11878SVenu.Iyer@Sun.COM 1290*11878SVenu.Iyer@Sun.COM /* 1291*11878SVenu.Iyer@Sun.COM * Ideally, we would want an ioctl to return list of ring-ids (or lane-ids) 1292*11878SVenu.Iyer@Sun.COM * for a given data-link (or mac client). We could then query for specific 1293*11878SVenu.Iyer@Sun.COM * kstats based on these ring-ids (lane-ids). 1294*11878SVenu.Iyer@Sun.COM * Ring-ids (or lane-ids) could be returned like any other link properties 1295*11878SVenu.Iyer@Sun.COM * queried by dladm show-linkprop. However, non-global zones do not have 1296*11878SVenu.Iyer@Sun.COM * access to this information today. 1297*11878SVenu.Iyer@Sun.COM * We thus opt for an implementation that relies heavily on kstat internals: 1298*11878SVenu.Iyer@Sun.COM * i_dlstat_*search routines and i_dlstat_get_idlist. 1299*11878SVenu.Iyer@Sun.COM */ 1300*11878SVenu.Iyer@Sun.COM /* rx hwlane specific */ 1301*11878SVenu.Iyer@Sun.COM static boolean_t 1302*11878SVenu.Iyer@Sun.COM i_dlstat_rx_hwlane_search(kstat_t *ksp) 1303*11878SVenu.Iyer@Sun.COM { 1304*11878SVenu.Iyer@Sun.COM return (ksp->ks_instance == 0 && 1305*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "mac_rx") != 0 && 1306*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "hwlane") != 0 && 1307*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "fanout") == 0 && 1308*11878SVenu.Iyer@Sun.COM strcmp(ksp->ks_class, "net") == 0); 1309*11878SVenu.Iyer@Sun.COM } 1310*11878SVenu.Iyer@Sun.COM 1311*11878SVenu.Iyer@Sun.COM /* tx hwlane specific */ 1312*11878SVenu.Iyer@Sun.COM static boolean_t 1313*11878SVenu.Iyer@Sun.COM i_dlstat_tx_hwlane_search(kstat_t *ksp) 1314*11878SVenu.Iyer@Sun.COM { 1315*11878SVenu.Iyer@Sun.COM return (ksp->ks_instance == 0 && 1316*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "mac_tx") != 0 && 1317*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "hwlane") != 0 && 1318*11878SVenu.Iyer@Sun.COM strcmp(ksp->ks_class, "net") == 0); 1319*11878SVenu.Iyer@Sun.COM } 1320*11878SVenu.Iyer@Sun.COM 1321*11878SVenu.Iyer@Sun.COM /* rx fanout specific */ 1322*11878SVenu.Iyer@Sun.COM static boolean_t 1323*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_search(kstat_t *ksp) 1324*11878SVenu.Iyer@Sun.COM { 1325*11878SVenu.Iyer@Sun.COM return (ksp->ks_instance == 0 && 1326*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "mac_rx") != 0 && 1327*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "swlane") != 0 && 1328*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "fanout") != 0 && 1329*11878SVenu.Iyer@Sun.COM strcmp(ksp->ks_class, "net") == 0); 1330*11878SVenu.Iyer@Sun.COM } 1331*11878SVenu.Iyer@Sun.COM 1332*11878SVenu.Iyer@Sun.COM /* rx ring specific */ 1333*11878SVenu.Iyer@Sun.COM static boolean_t 1334*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_search(kstat_t *ksp) 1335*11878SVenu.Iyer@Sun.COM { 1336*11878SVenu.Iyer@Sun.COM return (ksp->ks_instance == 0 && 1337*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "mac_rx") != 0 && 1338*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "ring") != 0 && 1339*11878SVenu.Iyer@Sun.COM strcmp(ksp->ks_class, "net") == 0); 1340*11878SVenu.Iyer@Sun.COM } 1341*11878SVenu.Iyer@Sun.COM 1342*11878SVenu.Iyer@Sun.COM /* tx ring specific */ 1343*11878SVenu.Iyer@Sun.COM static boolean_t 1344*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_search(kstat_t *ksp) 1345*11878SVenu.Iyer@Sun.COM { 1346*11878SVenu.Iyer@Sun.COM return (ksp->ks_instance == 0) && 1347*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "mac_tx") != 0 && 1348*11878SVenu.Iyer@Sun.COM strstr(ksp->ks_name, "ring") != 0 && 1349*11878SVenu.Iyer@Sun.COM strcmp(ksp->ks_class, "net") == 0; 1350*11878SVenu.Iyer@Sun.COM } 1351*11878SVenu.Iyer@Sun.COM 1352*11878SVenu.Iyer@Sun.COM typedef boolean_t dladm_search_kstat_t(kstat_t *); 1353*11878SVenu.Iyer@Sun.COM typedef struct dladm_extract_idlist_s { 1354*11878SVenu.Iyer@Sun.COM dlstat_idlist_type_t di_type; 1355*11878SVenu.Iyer@Sun.COM char *di_prefix; 1356*11878SVenu.Iyer@Sun.COM dladm_search_kstat_t *di_searchkstat; 1357*11878SVenu.Iyer@Sun.COM } dladm_extract_idlist_t; 1358*11878SVenu.Iyer@Sun.COM 1359*11878SVenu.Iyer@Sun.COM static dladm_extract_idlist_t dladm_extract_idlist[] = { 1360*11878SVenu.Iyer@Sun.COM { DLSTAT_RX_RING_IDLIST, DLSTAT_MAC_RX_RING, 1361*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_search}, 1362*11878SVenu.Iyer@Sun.COM { DLSTAT_TX_RING_IDLIST, DLSTAT_MAC_TX_RING, 1363*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_search}, 1364*11878SVenu.Iyer@Sun.COM { DLSTAT_RX_HWLANE_IDLIST, DLSTAT_MAC_RX_HWLANE, 1365*11878SVenu.Iyer@Sun.COM i_dlstat_rx_hwlane_search}, 1366*11878SVenu.Iyer@Sun.COM { DLSTAT_TX_HWLANE_IDLIST, DLSTAT_MAC_TX_HWLANE, 1367*11878SVenu.Iyer@Sun.COM i_dlstat_tx_hwlane_search}, 1368*11878SVenu.Iyer@Sun.COM { DLSTAT_FANOUT_IDLIST, DLSTAT_MAC_FANOUT, 1369*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_search} 1370*11878SVenu.Iyer@Sun.COM }; 1371*11878SVenu.Iyer@Sun.COM 1372*11878SVenu.Iyer@Sun.COM static void 1373*11878SVenu.Iyer@Sun.COM i_dlstat_get_idlist(const char *modname, dlstat_idlist_type_t idlist_type, 1374*11878SVenu.Iyer@Sun.COM uint_t idlist[], uint_t *size) 1375*11878SVenu.Iyer@Sun.COM { 1376*11878SVenu.Iyer@Sun.COM kstat_ctl_t *kcp; 1377*11878SVenu.Iyer@Sun.COM kstat_t *ksp; 1378*11878SVenu.Iyer@Sun.COM char *prefix; 1379*11878SVenu.Iyer@Sun.COM int prefixlen; 1380*11878SVenu.Iyer@Sun.COM boolean_t (*fptr_searchkstat)(kstat_t *); 1381*11878SVenu.Iyer@Sun.COM 1382*11878SVenu.Iyer@Sun.COM *size = 0; 1383*11878SVenu.Iyer@Sun.COM 1384*11878SVenu.Iyer@Sun.COM if ((kcp = kstat_open()) == NULL) { 1385*11878SVenu.Iyer@Sun.COM warn("kstat_open operation failed"); 1386*11878SVenu.Iyer@Sun.COM goto done; 1387*11878SVenu.Iyer@Sun.COM } 1388*11878SVenu.Iyer@Sun.COM 1389*11878SVenu.Iyer@Sun.COM prefix = dladm_extract_idlist[idlist_type].di_prefix; 1390*11878SVenu.Iyer@Sun.COM fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat; 1391*11878SVenu.Iyer@Sun.COM prefixlen = strlen(prefix); 1392*11878SVenu.Iyer@Sun.COM for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 1393*11878SVenu.Iyer@Sun.COM if ((strcmp(ksp->ks_module, modname) == 0) && 1394*11878SVenu.Iyer@Sun.COM fptr_searchkstat(ksp)) { 1395*11878SVenu.Iyer@Sun.COM idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]); 1396*11878SVenu.Iyer@Sun.COM } 1397*11878SVenu.Iyer@Sun.COM } 1398*11878SVenu.Iyer@Sun.COM dladm_sort_index_list(idlist, *size); 1399*11878SVenu.Iyer@Sun.COM 1400*11878SVenu.Iyer@Sun.COM done: 1401*11878SVenu.Iyer@Sun.COM (void) kstat_close(kcp); 1402*11878SVenu.Iyer@Sun.COM } 1403*11878SVenu.Iyer@Sun.COM 1404*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1405*11878SVenu.Iyer@Sun.COM i_dlstat_query_stats(const char *modname, const char *prefix, 1406*11878SVenu.Iyer@Sun.COM uint_t idlist[], uint_t idlist_size, 1407*11878SVenu.Iyer@Sun.COM void * (*fn)(kstat_ctl_t *, kstat_t *, int)) 1408*11878SVenu.Iyer@Sun.COM { 1409*11878SVenu.Iyer@Sun.COM kstat_ctl_t *kcp; 1410*11878SVenu.Iyer@Sun.COM kstat_t *ksp; 1411*11878SVenu.Iyer@Sun.COM char statname[MAXLINKNAMELEN]; 1412*11878SVenu.Iyer@Sun.COM int i = 0; 1413*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL, *prev = NULL; 1414*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *curr; 1415*11878SVenu.Iyer@Sun.COM 1416*11878SVenu.Iyer@Sun.COM if ((kcp = kstat_open()) == NULL) { 1417*11878SVenu.Iyer@Sun.COM warn("kstat_open operation failed"); 1418*11878SVenu.Iyer@Sun.COM return (NULL); 1419*11878SVenu.Iyer@Sun.COM } 1420*11878SVenu.Iyer@Sun.COM 1421*11878SVenu.Iyer@Sun.COM for (i = 0; i < idlist_size; i++) { 1422*11878SVenu.Iyer@Sun.COM uint_t index = idlist[i]; 1423*11878SVenu.Iyer@Sun.COM 1424*11878SVenu.Iyer@Sun.COM (void) snprintf(statname, sizeof (statname), "%s%d", prefix, 1425*11878SVenu.Iyer@Sun.COM index); 1426*11878SVenu.Iyer@Sun.COM 1427*11878SVenu.Iyer@Sun.COM ksp = dladm_kstat_lookup(kcp, modname, 0, statname, NULL); 1428*11878SVenu.Iyer@Sun.COM if (ksp == NULL) 1429*11878SVenu.Iyer@Sun.COM continue; 1430*11878SVenu.Iyer@Sun.COM 1431*11878SVenu.Iyer@Sun.COM curr = malloc(sizeof (dladm_stat_chain_t)); 1432*11878SVenu.Iyer@Sun.COM if (curr == NULL) 1433*11878SVenu.Iyer@Sun.COM break; 1434*11878SVenu.Iyer@Sun.COM 1435*11878SVenu.Iyer@Sun.COM curr->dc_statentry = fn(kcp, ksp, index); 1436*11878SVenu.Iyer@Sun.COM if (curr->dc_statentry == NULL) { 1437*11878SVenu.Iyer@Sun.COM free(curr); 1438*11878SVenu.Iyer@Sun.COM break; 1439*11878SVenu.Iyer@Sun.COM } 1440*11878SVenu.Iyer@Sun.COM 1441*11878SVenu.Iyer@Sun.COM (void) strlcpy(curr->dc_statheader, statname, 1442*11878SVenu.Iyer@Sun.COM sizeof (curr->dc_statheader)); 1443*11878SVenu.Iyer@Sun.COM curr->dc_next = NULL; 1444*11878SVenu.Iyer@Sun.COM 1445*11878SVenu.Iyer@Sun.COM if (head == NULL) /* First node */ 1446*11878SVenu.Iyer@Sun.COM head = curr; 1447*11878SVenu.Iyer@Sun.COM else 1448*11878SVenu.Iyer@Sun.COM prev->dc_next = curr; 1449*11878SVenu.Iyer@Sun.COM 1450*11878SVenu.Iyer@Sun.COM prev = curr; 1451*11878SVenu.Iyer@Sun.COM } 1452*11878SVenu.Iyer@Sun.COM done: 1453*11878SVenu.Iyer@Sun.COM (void) kstat_close(kcp); 1454*11878SVenu.Iyer@Sun.COM return (head); 1455*11878SVenu.Iyer@Sun.COM } 1456*11878SVenu.Iyer@Sun.COM 1457*11878SVenu.Iyer@Sun.COM static misc_stat_entry_t * 1458*11878SVenu.Iyer@Sun.COM i_dlstat_misc_stats(const char *linkname) 1459*11878SVenu.Iyer@Sun.COM { 1460*11878SVenu.Iyer@Sun.COM kstat_ctl_t *kcp; 1461*11878SVenu.Iyer@Sun.COM kstat_t *ksp; 1462*11878SVenu.Iyer@Sun.COM misc_stat_entry_t *misc_stat_entry = NULL; 1463*11878SVenu.Iyer@Sun.COM 1464*11878SVenu.Iyer@Sun.COM if ((kcp = kstat_open()) == NULL) 1465*11878SVenu.Iyer@Sun.COM return (NULL); 1466*11878SVenu.Iyer@Sun.COM 1467*11878SVenu.Iyer@Sun.COM ksp = dladm_kstat_lookup(kcp, linkname, 0, DLSTAT_MAC_MISC_STAT, NULL); 1468*11878SVenu.Iyer@Sun.COM if (ksp == NULL) 1469*11878SVenu.Iyer@Sun.COM goto done; 1470*11878SVenu.Iyer@Sun.COM 1471*11878SVenu.Iyer@Sun.COM misc_stat_entry = calloc(1, sizeof (misc_stat_entry_t)); 1472*11878SVenu.Iyer@Sun.COM if (misc_stat_entry == NULL) 1473*11878SVenu.Iyer@Sun.COM goto done; 1474*11878SVenu.Iyer@Sun.COM 1475*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, &misc_stat_entry->mse_stats, 1476*11878SVenu.Iyer@Sun.COM misc_stats_list, MISC_STAT_SIZE); 1477*11878SVenu.Iyer@Sun.COM done: 1478*11878SVenu.Iyer@Sun.COM (void) kstat_close(kcp); 1479*11878SVenu.Iyer@Sun.COM return (misc_stat_entry); 1480*11878SVenu.Iyer@Sun.COM } 1481*11878SVenu.Iyer@Sun.COM 1482*11878SVenu.Iyer@Sun.COM /* Rx lane statistic specific functions */ 1483*11878SVenu.Iyer@Sun.COM static boolean_t 1484*11878SVenu.Iyer@Sun.COM i_dlstat_rx_lane_match(void *arg1, void *arg2) 1485*11878SVenu.Iyer@Sun.COM { 1486*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *s1 = arg1; 1487*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *s2 = arg2; 1488*11878SVenu.Iyer@Sun.COM 1489*11878SVenu.Iyer@Sun.COM return (s1->rle_index == s2->rle_index && 1490*11878SVenu.Iyer@Sun.COM s1->rle_id == s2->rle_id); 1491*11878SVenu.Iyer@Sun.COM } 1492*11878SVenu.Iyer@Sun.COM 1493*11878SVenu.Iyer@Sun.COM static void * 1494*11878SVenu.Iyer@Sun.COM i_dlstat_rx_lane_stat_entry_diff(void *arg1, void *arg2) 1495*11878SVenu.Iyer@Sun.COM { 1496*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *s1 = arg1; 1497*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *s2 = arg2; 1498*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *diff_entry; 1499*11878SVenu.Iyer@Sun.COM 1500*11878SVenu.Iyer@Sun.COM diff_entry = malloc(sizeof (rx_lane_stat_entry_t)); 1501*11878SVenu.Iyer@Sun.COM if (diff_entry == NULL) 1502*11878SVenu.Iyer@Sun.COM goto done; 1503*11878SVenu.Iyer@Sun.COM 1504*11878SVenu.Iyer@Sun.COM diff_entry->rle_index = s1->rle_index; 1505*11878SVenu.Iyer@Sun.COM diff_entry->rle_id = s1->rle_id; 1506*11878SVenu.Iyer@Sun.COM 1507*11878SVenu.Iyer@Sun.COM DLSTAT_DIFF_STAT(s1, s2, diff_entry, rle_stats, rx_lane_stats_list, 1508*11878SVenu.Iyer@Sun.COM RX_LANE_STAT_SIZE); 1509*11878SVenu.Iyer@Sun.COM 1510*11878SVenu.Iyer@Sun.COM done: 1511*11878SVenu.Iyer@Sun.COM return (diff_entry); 1512*11878SVenu.Iyer@Sun.COM } 1513*11878SVenu.Iyer@Sun.COM 1514*11878SVenu.Iyer@Sun.COM static void * 1515*11878SVenu.Iyer@Sun.COM i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1516*11878SVenu.Iyer@Sun.COM { 1517*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *rx_lane_stat_entry; 1518*11878SVenu.Iyer@Sun.COM 1519*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1520*11878SVenu.Iyer@Sun.COM if (rx_lane_stat_entry == NULL) 1521*11878SVenu.Iyer@Sun.COM goto done; 1522*11878SVenu.Iyer@Sun.COM 1523*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_index = i; 1524*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_id = L_HWLANE; 1525*11878SVenu.Iyer@Sun.COM 1526*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 1527*11878SVenu.Iyer@Sun.COM rx_hwlane_stats_list, RX_HWLANE_STAT_SIZE); 1528*11878SVenu.Iyer@Sun.COM 1529*11878SVenu.Iyer@Sun.COM done: 1530*11878SVenu.Iyer@Sun.COM return (rx_lane_stat_entry); 1531*11878SVenu.Iyer@Sun.COM } 1532*11878SVenu.Iyer@Sun.COM 1533*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/ 1534*11878SVenu.Iyer@Sun.COM static void * 1535*11878SVenu.Iyer@Sun.COM i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1536*11878SVenu.Iyer@Sun.COM { 1537*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *rx_lane_stat_entry; 1538*11878SVenu.Iyer@Sun.COM 1539*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1540*11878SVenu.Iyer@Sun.COM if (rx_lane_stat_entry == NULL) 1541*11878SVenu.Iyer@Sun.COM goto done; 1542*11878SVenu.Iyer@Sun.COM 1543*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1544*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_id = L_SWLANE; 1545*11878SVenu.Iyer@Sun.COM 1546*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 1547*11878SVenu.Iyer@Sun.COM rx_swlane_stats_list, RX_SWLANE_STAT_SIZE); 1548*11878SVenu.Iyer@Sun.COM 1549*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_ipackets = 1550*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_intrs; 1551*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_rbytes = 1552*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_intrbytes; 1553*11878SVenu.Iyer@Sun.COM done: 1554*11878SVenu.Iyer@Sun.COM return (rx_lane_stat_entry); 1555*11878SVenu.Iyer@Sun.COM } 1556*11878SVenu.Iyer@Sun.COM 1557*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/ 1558*11878SVenu.Iyer@Sun.COM static void * 1559*11878SVenu.Iyer@Sun.COM i_dlstat_rx_local_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1560*11878SVenu.Iyer@Sun.COM { 1561*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *local_stat_entry; 1562*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *rx_lane_stat_entry; 1563*11878SVenu.Iyer@Sun.COM 1564*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1565*11878SVenu.Iyer@Sun.COM if (rx_lane_stat_entry == NULL) 1566*11878SVenu.Iyer@Sun.COM goto done; 1567*11878SVenu.Iyer@Sun.COM 1568*11878SVenu.Iyer@Sun.COM local_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1569*11878SVenu.Iyer@Sun.COM if (local_stat_entry == NULL) 1570*11878SVenu.Iyer@Sun.COM goto done; 1571*11878SVenu.Iyer@Sun.COM 1572*11878SVenu.Iyer@Sun.COM local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1573*11878SVenu.Iyer@Sun.COM local_stat_entry->rle_id = L_LOCAL; 1574*11878SVenu.Iyer@Sun.COM 1575*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 1576*11878SVenu.Iyer@Sun.COM rx_swlane_stats_list, RX_SWLANE_STAT_SIZE); 1577*11878SVenu.Iyer@Sun.COM 1578*11878SVenu.Iyer@Sun.COM local_stat_entry->rle_stats.rl_ipackets = 1579*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_lclpackets; 1580*11878SVenu.Iyer@Sun.COM local_stat_entry->rle_stats.rl_rbytes = 1581*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_lclbytes; 1582*11878SVenu.Iyer@Sun.COM 1583*11878SVenu.Iyer@Sun.COM done: 1584*11878SVenu.Iyer@Sun.COM free(rx_lane_stat_entry); 1585*11878SVenu.Iyer@Sun.COM return (local_stat_entry); 1586*11878SVenu.Iyer@Sun.COM } 1587*11878SVenu.Iyer@Sun.COM 1588*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1589*11878SVenu.Iyer@Sun.COM i_dlstat_rx_local_stats(const char *linkname) 1590*11878SVenu.Iyer@Sun.COM { 1591*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *local_stats = NULL; 1592*11878SVenu.Iyer@Sun.COM 1593*11878SVenu.Iyer@Sun.COM local_stats = i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_SWLANE, 1594*11878SVenu.Iyer@Sun.COM default_idlist, default_idlist_size, 1595*11878SVenu.Iyer@Sun.COM i_dlstat_rx_local_retrieve_stat); 1596*11878SVenu.Iyer@Sun.COM 1597*11878SVenu.Iyer@Sun.COM if (local_stats != NULL) { 1598*11878SVenu.Iyer@Sun.COM (void) strlcpy(local_stats->dc_statheader, "mac_rx_local", 1599*11878SVenu.Iyer@Sun.COM sizeof (local_stats->dc_statheader)); 1600*11878SVenu.Iyer@Sun.COM } 1601*11878SVenu.Iyer@Sun.COM return (local_stats); 1602*11878SVenu.Iyer@Sun.COM } 1603*11878SVenu.Iyer@Sun.COM 1604*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1605*11878SVenu.Iyer@Sun.COM i_dlstat_rx_bcast_stats(const char *linkname) 1606*11878SVenu.Iyer@Sun.COM { 1607*11878SVenu.Iyer@Sun.COM misc_stat_entry_t *misc_stat_entry; 1608*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 1609*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *rx_lane_stat_entry; 1610*11878SVenu.Iyer@Sun.COM 1611*11878SVenu.Iyer@Sun.COM misc_stat_entry = i_dlstat_misc_stats(linkname); 1612*11878SVenu.Iyer@Sun.COM if (misc_stat_entry == NULL) 1613*11878SVenu.Iyer@Sun.COM goto done; 1614*11878SVenu.Iyer@Sun.COM 1615*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1616*11878SVenu.Iyer@Sun.COM if (rx_lane_stat_entry == NULL) 1617*11878SVenu.Iyer@Sun.COM goto done; 1618*11878SVenu.Iyer@Sun.COM 1619*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1620*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_id = L_BCAST; 1621*11878SVenu.Iyer@Sun.COM 1622*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_ipackets = 1623*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_brdcstrcv + 1624*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_multircv; 1625*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_intrs = 1626*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_brdcstrcv + 1627*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_multircv; 1628*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_rbytes = 1629*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_brdcstrcvbytes + 1630*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_multircvbytes; 1631*11878SVenu.Iyer@Sun.COM 1632*11878SVenu.Iyer@Sun.COM head = malloc(sizeof (dladm_stat_chain_t)); 1633*11878SVenu.Iyer@Sun.COM if (head == NULL) { 1634*11878SVenu.Iyer@Sun.COM free(rx_lane_stat_entry); 1635*11878SVenu.Iyer@Sun.COM goto done; 1636*11878SVenu.Iyer@Sun.COM } 1637*11878SVenu.Iyer@Sun.COM 1638*11878SVenu.Iyer@Sun.COM head->dc_statentry = rx_lane_stat_entry; 1639*11878SVenu.Iyer@Sun.COM head->dc_next = NULL; 1640*11878SVenu.Iyer@Sun.COM 1641*11878SVenu.Iyer@Sun.COM free(misc_stat_entry); 1642*11878SVenu.Iyer@Sun.COM done: 1643*11878SVenu.Iyer@Sun.COM return (head); 1644*11878SVenu.Iyer@Sun.COM } 1645*11878SVenu.Iyer@Sun.COM 1646*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1647*11878SVenu.Iyer@Sun.COM i_dlstat_rx_defunctlane_stats(const char *linkname) 1648*11878SVenu.Iyer@Sun.COM { 1649*11878SVenu.Iyer@Sun.COM misc_stat_entry_t *misc_stat_entry; 1650*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 1651*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *rx_lane_stat_entry; 1652*11878SVenu.Iyer@Sun.COM 1653*11878SVenu.Iyer@Sun.COM misc_stat_entry = i_dlstat_misc_stats(linkname); 1654*11878SVenu.Iyer@Sun.COM if (misc_stat_entry == NULL) 1655*11878SVenu.Iyer@Sun.COM goto done; 1656*11878SVenu.Iyer@Sun.COM 1657*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 1658*11878SVenu.Iyer@Sun.COM if (rx_lane_stat_entry == NULL) 1659*11878SVenu.Iyer@Sun.COM goto done; 1660*11878SVenu.Iyer@Sun.COM 1661*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 1662*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_id = L_DFNCT; 1663*11878SVenu.Iyer@Sun.COM 1664*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_ipackets = 1665*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_ipackets; 1666*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_rbytes = 1667*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_rbytes; 1668*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_intrs = 1669*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_intrs; 1670*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_polls = 1671*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_polls; 1672*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_sdrops = 1673*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_rxsdrops; 1674*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_chl10 = 1675*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_chainunder10; 1676*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_ch10_50 = 1677*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_chain10to50; 1678*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_chg50 = 1679*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_chainover50; 1680*11878SVenu.Iyer@Sun.COM 1681*11878SVenu.Iyer@Sun.COM head = malloc(sizeof (dladm_stat_chain_t)); 1682*11878SVenu.Iyer@Sun.COM if (head == NULL) { 1683*11878SVenu.Iyer@Sun.COM free(rx_lane_stat_entry); 1684*11878SVenu.Iyer@Sun.COM goto done; 1685*11878SVenu.Iyer@Sun.COM } 1686*11878SVenu.Iyer@Sun.COM 1687*11878SVenu.Iyer@Sun.COM head->dc_statentry = rx_lane_stat_entry; 1688*11878SVenu.Iyer@Sun.COM head->dc_next = NULL; 1689*11878SVenu.Iyer@Sun.COM 1690*11878SVenu.Iyer@Sun.COM done: 1691*11878SVenu.Iyer@Sun.COM return (head); 1692*11878SVenu.Iyer@Sun.COM } 1693*11878SVenu.Iyer@Sun.COM 1694*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1695*11878SVenu.Iyer@Sun.COM i_dlstat_rx_hwlane_stats(const char *linkname) 1696*11878SVenu.Iyer@Sun.COM { 1697*11878SVenu.Iyer@Sun.COM uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 1698*11878SVenu.Iyer@Sun.COM uint_t rx_hwlane_idlist_size; 1699*11878SVenu.Iyer@Sun.COM 1700*11878SVenu.Iyer@Sun.COM i_dlstat_get_idlist(linkname, DLSTAT_RX_HWLANE_IDLIST, 1701*11878SVenu.Iyer@Sun.COM rx_hwlane_idlist, &rx_hwlane_idlist_size); 1702*11878SVenu.Iyer@Sun.COM 1703*11878SVenu.Iyer@Sun.COM return (i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_HWLANE, 1704*11878SVenu.Iyer@Sun.COM rx_hwlane_idlist, rx_hwlane_idlist_size, 1705*11878SVenu.Iyer@Sun.COM i_dlstat_rx_hwlane_retrieve_stat)); 1706*11878SVenu.Iyer@Sun.COM } 1707*11878SVenu.Iyer@Sun.COM 1708*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/ 1709*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1710*11878SVenu.Iyer@Sun.COM i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid, 1711*11878SVenu.Iyer@Sun.COM const char *linkname) 1712*11878SVenu.Iyer@Sun.COM { 1713*11878SVenu.Iyer@Sun.COM return (i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_SWLANE, 1714*11878SVenu.Iyer@Sun.COM default_idlist, default_idlist_size, 1715*11878SVenu.Iyer@Sun.COM i_dlstat_rx_swlane_retrieve_stat)); 1716*11878SVenu.Iyer@Sun.COM } 1717*11878SVenu.Iyer@Sun.COM 1718*11878SVenu.Iyer@Sun.COM void * 1719*11878SVenu.Iyer@Sun.COM dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid) 1720*11878SVenu.Iyer@Sun.COM { 1721*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 1722*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *local_stats = NULL; 1723*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *bcast_stats = NULL; 1724*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *defunctlane_stats = NULL; 1725*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *lane_stats = NULL; 1726*11878SVenu.Iyer@Sun.COM char linkname[MAXLINKNAMELEN]; 1727*11878SVenu.Iyer@Sun.COM boolean_t is_legacy_driver; 1728*11878SVenu.Iyer@Sun.COM 1729*11878SVenu.Iyer@Sun.COM if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1730*11878SVenu.Iyer@Sun.COM DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1731*11878SVenu.Iyer@Sun.COM goto done; 1732*11878SVenu.Iyer@Sun.COM } 1733*11878SVenu.Iyer@Sun.COM 1734*11878SVenu.Iyer@Sun.COM /* Check if it is legacy driver */ 1735*11878SVenu.Iyer@Sun.COM if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT, 1736*11878SVenu.Iyer@Sun.COM "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) { 1737*11878SVenu.Iyer@Sun.COM goto done; 1738*11878SVenu.Iyer@Sun.COM } 1739*11878SVenu.Iyer@Sun.COM 1740*11878SVenu.Iyer@Sun.COM if (is_legacy_driver) { 1741*11878SVenu.Iyer@Sun.COM head = i_dlstat_legacy_rx_lane_stats(linkname); 1742*11878SVenu.Iyer@Sun.COM goto done; 1743*11878SVenu.Iyer@Sun.COM } 1744*11878SVenu.Iyer@Sun.COM 1745*11878SVenu.Iyer@Sun.COM local_stats = i_dlstat_rx_local_stats(linkname); 1746*11878SVenu.Iyer@Sun.COM bcast_stats = i_dlstat_rx_bcast_stats(linkname); 1747*11878SVenu.Iyer@Sun.COM defunctlane_stats = i_dlstat_rx_defunctlane_stats(linkname); 1748*11878SVenu.Iyer@Sun.COM lane_stats = i_dlstat_rx_hwlane_stats(linkname); 1749*11878SVenu.Iyer@Sun.COM if (lane_stats == NULL) 1750*11878SVenu.Iyer@Sun.COM lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname); 1751*11878SVenu.Iyer@Sun.COM 1752*11878SVenu.Iyer@Sun.COM head = i_dlstat_join_lists(local_stats, bcast_stats); 1753*11878SVenu.Iyer@Sun.COM head = i_dlstat_join_lists(head, defunctlane_stats); 1754*11878SVenu.Iyer@Sun.COM head = i_dlstat_join_lists(head, lane_stats); 1755*11878SVenu.Iyer@Sun.COM done: 1756*11878SVenu.Iyer@Sun.COM return (head); 1757*11878SVenu.Iyer@Sun.COM } 1758*11878SVenu.Iyer@Sun.COM 1759*11878SVenu.Iyer@Sun.COM /* Tx lane statistic specific functions */ 1760*11878SVenu.Iyer@Sun.COM static boolean_t 1761*11878SVenu.Iyer@Sun.COM i_dlstat_tx_lane_match(void *arg1, void *arg2) 1762*11878SVenu.Iyer@Sun.COM { 1763*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *s1 = arg1; 1764*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *s2 = arg2; 1765*11878SVenu.Iyer@Sun.COM 1766*11878SVenu.Iyer@Sun.COM return (s1->tle_index == s2->tle_index && 1767*11878SVenu.Iyer@Sun.COM s1->tle_id == s2->tle_id); 1768*11878SVenu.Iyer@Sun.COM } 1769*11878SVenu.Iyer@Sun.COM 1770*11878SVenu.Iyer@Sun.COM static void * 1771*11878SVenu.Iyer@Sun.COM i_dlstat_tx_lane_stat_entry_diff(void *arg1, void *arg2) 1772*11878SVenu.Iyer@Sun.COM { 1773*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *s1 = arg1; 1774*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *s2 = arg2; 1775*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *diff_entry; 1776*11878SVenu.Iyer@Sun.COM 1777*11878SVenu.Iyer@Sun.COM diff_entry = malloc(sizeof (tx_lane_stat_entry_t)); 1778*11878SVenu.Iyer@Sun.COM if (diff_entry == NULL) 1779*11878SVenu.Iyer@Sun.COM goto done; 1780*11878SVenu.Iyer@Sun.COM 1781*11878SVenu.Iyer@Sun.COM diff_entry->tle_index = s1->tle_index; 1782*11878SVenu.Iyer@Sun.COM diff_entry->tle_id = s1->tle_id; 1783*11878SVenu.Iyer@Sun.COM 1784*11878SVenu.Iyer@Sun.COM DLSTAT_DIFF_STAT(s1, s2, diff_entry, tle_stats, tx_lane_stats_list, 1785*11878SVenu.Iyer@Sun.COM TX_LANE_STAT_SIZE); 1786*11878SVenu.Iyer@Sun.COM 1787*11878SVenu.Iyer@Sun.COM done: 1788*11878SVenu.Iyer@Sun.COM return (diff_entry); 1789*11878SVenu.Iyer@Sun.COM } 1790*11878SVenu.Iyer@Sun.COM 1791*11878SVenu.Iyer@Sun.COM static void * 1792*11878SVenu.Iyer@Sun.COM i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1793*11878SVenu.Iyer@Sun.COM { 1794*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *tx_lane_stat_entry; 1795*11878SVenu.Iyer@Sun.COM 1796*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1797*11878SVenu.Iyer@Sun.COM if (tx_lane_stat_entry == NULL) 1798*11878SVenu.Iyer@Sun.COM goto done; 1799*11878SVenu.Iyer@Sun.COM 1800*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_index = i; 1801*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_id = L_HWLANE; 1802*11878SVenu.Iyer@Sun.COM 1803*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats, 1804*11878SVenu.Iyer@Sun.COM tx_lane_stats_list, TX_LANE_STAT_SIZE); 1805*11878SVenu.Iyer@Sun.COM 1806*11878SVenu.Iyer@Sun.COM done: 1807*11878SVenu.Iyer@Sun.COM return (tx_lane_stat_entry); 1808*11878SVenu.Iyer@Sun.COM } 1809*11878SVenu.Iyer@Sun.COM 1810*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/ 1811*11878SVenu.Iyer@Sun.COM static void * 1812*11878SVenu.Iyer@Sun.COM i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 1813*11878SVenu.Iyer@Sun.COM { 1814*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *tx_lane_stat_entry; 1815*11878SVenu.Iyer@Sun.COM 1816*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1817*11878SVenu.Iyer@Sun.COM if (tx_lane_stat_entry == NULL) 1818*11878SVenu.Iyer@Sun.COM goto done; 1819*11878SVenu.Iyer@Sun.COM 1820*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 1821*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_id = L_SWLANE; 1822*11878SVenu.Iyer@Sun.COM 1823*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats, 1824*11878SVenu.Iyer@Sun.COM tx_lane_stats_list, TX_LANE_STAT_SIZE); 1825*11878SVenu.Iyer@Sun.COM 1826*11878SVenu.Iyer@Sun.COM done: 1827*11878SVenu.Iyer@Sun.COM return (tx_lane_stat_entry); 1828*11878SVenu.Iyer@Sun.COM } 1829*11878SVenu.Iyer@Sun.COM 1830*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1831*11878SVenu.Iyer@Sun.COM i_dlstat_tx_bcast_stats(const char *linkname) 1832*11878SVenu.Iyer@Sun.COM { 1833*11878SVenu.Iyer@Sun.COM misc_stat_entry_t *misc_stat_entry; 1834*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 1835*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *tx_lane_stat_entry; 1836*11878SVenu.Iyer@Sun.COM 1837*11878SVenu.Iyer@Sun.COM misc_stat_entry = i_dlstat_misc_stats(linkname); 1838*11878SVenu.Iyer@Sun.COM if (misc_stat_entry == NULL) 1839*11878SVenu.Iyer@Sun.COM goto done; 1840*11878SVenu.Iyer@Sun.COM 1841*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1842*11878SVenu.Iyer@Sun.COM if (tx_lane_stat_entry == NULL) 1843*11878SVenu.Iyer@Sun.COM goto done; 1844*11878SVenu.Iyer@Sun.COM 1845*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 1846*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_id = L_BCAST; 1847*11878SVenu.Iyer@Sun.COM 1848*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_stats.tl_opackets = 1849*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_brdcstxmt + 1850*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_multixmt; 1851*11878SVenu.Iyer@Sun.COM 1852*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_stats.tl_obytes = 1853*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_brdcstxmtbytes + 1854*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_multixmtbytes; 1855*11878SVenu.Iyer@Sun.COM 1856*11878SVenu.Iyer@Sun.COM head = malloc(sizeof (dladm_stat_chain_t)); 1857*11878SVenu.Iyer@Sun.COM if (head == NULL) { 1858*11878SVenu.Iyer@Sun.COM free(tx_lane_stat_entry); 1859*11878SVenu.Iyer@Sun.COM goto done; 1860*11878SVenu.Iyer@Sun.COM } 1861*11878SVenu.Iyer@Sun.COM 1862*11878SVenu.Iyer@Sun.COM head->dc_statentry = tx_lane_stat_entry; 1863*11878SVenu.Iyer@Sun.COM head->dc_next = NULL; 1864*11878SVenu.Iyer@Sun.COM 1865*11878SVenu.Iyer@Sun.COM free(misc_stat_entry); 1866*11878SVenu.Iyer@Sun.COM done: 1867*11878SVenu.Iyer@Sun.COM return (head); 1868*11878SVenu.Iyer@Sun.COM } 1869*11878SVenu.Iyer@Sun.COM 1870*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1871*11878SVenu.Iyer@Sun.COM i_dlstat_tx_defunctlane_stats(const char *linkname) 1872*11878SVenu.Iyer@Sun.COM { 1873*11878SVenu.Iyer@Sun.COM misc_stat_entry_t *misc_stat_entry; 1874*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 1875*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *tx_lane_stat_entry; 1876*11878SVenu.Iyer@Sun.COM 1877*11878SVenu.Iyer@Sun.COM misc_stat_entry = i_dlstat_misc_stats(linkname); 1878*11878SVenu.Iyer@Sun.COM if (misc_stat_entry == NULL) 1879*11878SVenu.Iyer@Sun.COM goto done; 1880*11878SVenu.Iyer@Sun.COM 1881*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 1882*11878SVenu.Iyer@Sun.COM if (tx_lane_stat_entry == NULL) 1883*11878SVenu.Iyer@Sun.COM goto done; 1884*11878SVenu.Iyer@Sun.COM 1885*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 1886*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_id = L_DFNCT; 1887*11878SVenu.Iyer@Sun.COM 1888*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_stats.tl_opackets = 1889*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_opackets; 1890*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_stats.tl_obytes = 1891*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_obytes; 1892*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_stats.tl_sdrops = 1893*11878SVenu.Iyer@Sun.COM misc_stat_entry->mse_stats.ms_txsdrops; 1894*11878SVenu.Iyer@Sun.COM 1895*11878SVenu.Iyer@Sun.COM head = malloc(sizeof (dladm_stat_chain_t)); 1896*11878SVenu.Iyer@Sun.COM if (head == NULL) { 1897*11878SVenu.Iyer@Sun.COM free(tx_lane_stat_entry); 1898*11878SVenu.Iyer@Sun.COM goto done; 1899*11878SVenu.Iyer@Sun.COM } 1900*11878SVenu.Iyer@Sun.COM 1901*11878SVenu.Iyer@Sun.COM head->dc_statentry = tx_lane_stat_entry; 1902*11878SVenu.Iyer@Sun.COM head->dc_next = NULL; 1903*11878SVenu.Iyer@Sun.COM 1904*11878SVenu.Iyer@Sun.COM done: 1905*11878SVenu.Iyer@Sun.COM return (head); 1906*11878SVenu.Iyer@Sun.COM } 1907*11878SVenu.Iyer@Sun.COM 1908*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1909*11878SVenu.Iyer@Sun.COM i_dlstat_tx_hwlane_stats(const char *linkname) 1910*11878SVenu.Iyer@Sun.COM { 1911*11878SVenu.Iyer@Sun.COM uint_t tx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 1912*11878SVenu.Iyer@Sun.COM uint_t tx_hwlane_idlist_size; 1913*11878SVenu.Iyer@Sun.COM 1914*11878SVenu.Iyer@Sun.COM i_dlstat_get_idlist(linkname, DLSTAT_TX_HWLANE_IDLIST, 1915*11878SVenu.Iyer@Sun.COM tx_hwlane_idlist, &tx_hwlane_idlist_size); 1916*11878SVenu.Iyer@Sun.COM 1917*11878SVenu.Iyer@Sun.COM return (i_dlstat_query_stats(linkname, DLSTAT_MAC_TX_HWLANE, 1918*11878SVenu.Iyer@Sun.COM tx_hwlane_idlist, tx_hwlane_idlist_size, 1919*11878SVenu.Iyer@Sun.COM i_dlstat_tx_hwlane_retrieve_stat)); 1920*11878SVenu.Iyer@Sun.COM } 1921*11878SVenu.Iyer@Sun.COM 1922*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/ 1923*11878SVenu.Iyer@Sun.COM static dladm_stat_chain_t * 1924*11878SVenu.Iyer@Sun.COM i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid, 1925*11878SVenu.Iyer@Sun.COM const char *linkname) 1926*11878SVenu.Iyer@Sun.COM { 1927*11878SVenu.Iyer@Sun.COM return (i_dlstat_query_stats(linkname, DLSTAT_MAC_TX_SWLANE, 1928*11878SVenu.Iyer@Sun.COM default_idlist, default_idlist_size, 1929*11878SVenu.Iyer@Sun.COM i_dlstat_tx_swlane_retrieve_stat)); 1930*11878SVenu.Iyer@Sun.COM } 1931*11878SVenu.Iyer@Sun.COM 1932*11878SVenu.Iyer@Sun.COM void * 1933*11878SVenu.Iyer@Sun.COM dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid) 1934*11878SVenu.Iyer@Sun.COM { 1935*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 1936*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *bcast_stats = NULL; 1937*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *defunctlane_stats = NULL; 1938*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *lane_stats; 1939*11878SVenu.Iyer@Sun.COM char linkname[MAXLINKNAMELEN]; 1940*11878SVenu.Iyer@Sun.COM boolean_t is_legacy_driver; 1941*11878SVenu.Iyer@Sun.COM 1942*11878SVenu.Iyer@Sun.COM if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 1943*11878SVenu.Iyer@Sun.COM DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 1944*11878SVenu.Iyer@Sun.COM goto done; 1945*11878SVenu.Iyer@Sun.COM } 1946*11878SVenu.Iyer@Sun.COM 1947*11878SVenu.Iyer@Sun.COM /* Check if it is legacy driver */ 1948*11878SVenu.Iyer@Sun.COM if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT, 1949*11878SVenu.Iyer@Sun.COM "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) { 1950*11878SVenu.Iyer@Sun.COM goto done; 1951*11878SVenu.Iyer@Sun.COM } 1952*11878SVenu.Iyer@Sun.COM 1953*11878SVenu.Iyer@Sun.COM if (is_legacy_driver) { 1954*11878SVenu.Iyer@Sun.COM head = i_dlstat_legacy_tx_lane_stats(linkname); 1955*11878SVenu.Iyer@Sun.COM goto done; 1956*11878SVenu.Iyer@Sun.COM } 1957*11878SVenu.Iyer@Sun.COM 1958*11878SVenu.Iyer@Sun.COM bcast_stats = i_dlstat_tx_bcast_stats(linkname); 1959*11878SVenu.Iyer@Sun.COM defunctlane_stats = i_dlstat_tx_defunctlane_stats(linkname); 1960*11878SVenu.Iyer@Sun.COM lane_stats = i_dlstat_tx_hwlane_stats(linkname); 1961*11878SVenu.Iyer@Sun.COM if (lane_stats == NULL) 1962*11878SVenu.Iyer@Sun.COM lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname); 1963*11878SVenu.Iyer@Sun.COM 1964*11878SVenu.Iyer@Sun.COM head = i_dlstat_join_lists(bcast_stats, defunctlane_stats); 1965*11878SVenu.Iyer@Sun.COM head = i_dlstat_join_lists(head, lane_stats); 1966*11878SVenu.Iyer@Sun.COM 1967*11878SVenu.Iyer@Sun.COM done: 1968*11878SVenu.Iyer@Sun.COM return (head); 1969*11878SVenu.Iyer@Sun.COM } 1970*11878SVenu.Iyer@Sun.COM 1971*11878SVenu.Iyer@Sun.COM /* Rx lane total statistic specific functions */ 1972*11878SVenu.Iyer@Sun.COM void * 1973*11878SVenu.Iyer@Sun.COM dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid) 1974*11878SVenu.Iyer@Sun.COM { 1975*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *total_head = NULL; 1976*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *rx_lane_head, *curr; 1977*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *total_stats; 1978*11878SVenu.Iyer@Sun.COM 1979*11878SVenu.Iyer@Sun.COM /* Get per rx lane stats */ 1980*11878SVenu.Iyer@Sun.COM rx_lane_head = dlstat_rx_lane_stats(dh, linkid); 1981*11878SVenu.Iyer@Sun.COM if (rx_lane_head == NULL) 1982*11878SVenu.Iyer@Sun.COM goto done; 1983*11878SVenu.Iyer@Sun.COM 1984*11878SVenu.Iyer@Sun.COM total_stats = calloc(1, sizeof (rx_lane_stat_entry_t)); 1985*11878SVenu.Iyer@Sun.COM if (total_stats == NULL) 1986*11878SVenu.Iyer@Sun.COM goto done; 1987*11878SVenu.Iyer@Sun.COM 1988*11878SVenu.Iyer@Sun.COM total_stats->rle_index = DLSTAT_INVALID_ENTRY; 1989*11878SVenu.Iyer@Sun.COM total_stats->rle_id = DLSTAT_INVALID_ENTRY; 1990*11878SVenu.Iyer@Sun.COM 1991*11878SVenu.Iyer@Sun.COM for (curr = rx_lane_head; curr != NULL; curr = curr->dc_next) { 1992*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry; 1993*11878SVenu.Iyer@Sun.COM 1994*11878SVenu.Iyer@Sun.COM i_dlstat_sum_stats(&total_stats->rle_stats, 1995*11878SVenu.Iyer@Sun.COM &curr_lane_stats->rle_stats, &total_stats->rle_stats, 1996*11878SVenu.Iyer@Sun.COM rx_lane_stats_list, RX_LANE_STAT_SIZE); 1997*11878SVenu.Iyer@Sun.COM } 1998*11878SVenu.Iyer@Sun.COM 1999*11878SVenu.Iyer@Sun.COM total_head = malloc(sizeof (dladm_stat_chain_t)); 2000*11878SVenu.Iyer@Sun.COM if (total_head == NULL) { 2001*11878SVenu.Iyer@Sun.COM free(total_stats); 2002*11878SVenu.Iyer@Sun.COM goto done; 2003*11878SVenu.Iyer@Sun.COM } 2004*11878SVenu.Iyer@Sun.COM 2005*11878SVenu.Iyer@Sun.COM total_head->dc_statentry = total_stats; 2006*11878SVenu.Iyer@Sun.COM (void) strlcpy(total_head->dc_statheader, "mac_rx_lane_total", 2007*11878SVenu.Iyer@Sun.COM sizeof (total_head->dc_statheader)); 2008*11878SVenu.Iyer@Sun.COM total_head->dc_next = NULL; 2009*11878SVenu.Iyer@Sun.COM free(rx_lane_head); 2010*11878SVenu.Iyer@Sun.COM 2011*11878SVenu.Iyer@Sun.COM done: 2012*11878SVenu.Iyer@Sun.COM return (total_head); 2013*11878SVenu.Iyer@Sun.COM } 2014*11878SVenu.Iyer@Sun.COM 2015*11878SVenu.Iyer@Sun.COM /* Tx lane total statistic specific functions */ 2016*11878SVenu.Iyer@Sun.COM void * 2017*11878SVenu.Iyer@Sun.COM dlstat_tx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid) 2018*11878SVenu.Iyer@Sun.COM { 2019*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *total_head = NULL; 2020*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *tx_lane_head, *curr; 2021*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *total_stats; 2022*11878SVenu.Iyer@Sun.COM 2023*11878SVenu.Iyer@Sun.COM /* Get per tx lane stats */ 2024*11878SVenu.Iyer@Sun.COM tx_lane_head = dlstat_tx_lane_stats(dh, linkid); 2025*11878SVenu.Iyer@Sun.COM if (tx_lane_head == NULL) 2026*11878SVenu.Iyer@Sun.COM goto done; 2027*11878SVenu.Iyer@Sun.COM 2028*11878SVenu.Iyer@Sun.COM total_stats = calloc(1, sizeof (tx_lane_stat_entry_t)); 2029*11878SVenu.Iyer@Sun.COM if (total_stats == NULL) 2030*11878SVenu.Iyer@Sun.COM goto done; 2031*11878SVenu.Iyer@Sun.COM 2032*11878SVenu.Iyer@Sun.COM total_stats->tle_index = DLSTAT_INVALID_ENTRY; 2033*11878SVenu.Iyer@Sun.COM total_stats->tle_id = DLSTAT_INVALID_ENTRY; 2034*11878SVenu.Iyer@Sun.COM 2035*11878SVenu.Iyer@Sun.COM for (curr = tx_lane_head; curr != NULL; curr = curr->dc_next) { 2036*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry; 2037*11878SVenu.Iyer@Sun.COM 2038*11878SVenu.Iyer@Sun.COM i_dlstat_sum_stats(&total_stats->tle_stats, 2039*11878SVenu.Iyer@Sun.COM &curr_lane_stats->tle_stats, &total_stats->tle_stats, 2040*11878SVenu.Iyer@Sun.COM tx_lane_stats_list, TX_LANE_STAT_SIZE); 2041*11878SVenu.Iyer@Sun.COM } 2042*11878SVenu.Iyer@Sun.COM 2043*11878SVenu.Iyer@Sun.COM total_head = malloc(sizeof (dladm_stat_chain_t)); 2044*11878SVenu.Iyer@Sun.COM if (total_head == NULL) { 2045*11878SVenu.Iyer@Sun.COM free(total_stats); 2046*11878SVenu.Iyer@Sun.COM goto done; 2047*11878SVenu.Iyer@Sun.COM } 2048*11878SVenu.Iyer@Sun.COM 2049*11878SVenu.Iyer@Sun.COM total_head->dc_statentry = total_stats; 2050*11878SVenu.Iyer@Sun.COM (void) strlcpy(total_head->dc_statheader, "mac_tx_lane_total", 2051*11878SVenu.Iyer@Sun.COM sizeof (total_head->dc_statheader)); 2052*11878SVenu.Iyer@Sun.COM total_head->dc_next = NULL; 2053*11878SVenu.Iyer@Sun.COM free(tx_lane_head); 2054*11878SVenu.Iyer@Sun.COM 2055*11878SVenu.Iyer@Sun.COM done: 2056*11878SVenu.Iyer@Sun.COM return (total_head); 2057*11878SVenu.Iyer@Sun.COM } 2058*11878SVenu.Iyer@Sun.COM 2059*11878SVenu.Iyer@Sun.COM /* Fanout specific functions */ 2060*11878SVenu.Iyer@Sun.COM static boolean_t 2061*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_match(void *arg1, void *arg2) 2062*11878SVenu.Iyer@Sun.COM { 2063*11878SVenu.Iyer@Sun.COM fanout_stat_entry_t *s1 = arg1; 2064*11878SVenu.Iyer@Sun.COM fanout_stat_entry_t *s2 = arg2; 2065*11878SVenu.Iyer@Sun.COM 2066*11878SVenu.Iyer@Sun.COM return (s1->fe_index == s2->fe_index && 2067*11878SVenu.Iyer@Sun.COM s1->fe_id == s2->fe_id && 2068*11878SVenu.Iyer@Sun.COM s1->fe_foutindex == s2->fe_foutindex); 2069*11878SVenu.Iyer@Sun.COM } 2070*11878SVenu.Iyer@Sun.COM 2071*11878SVenu.Iyer@Sun.COM static void * 2072*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_stat_entry_diff(void *arg1, void *arg2) 2073*11878SVenu.Iyer@Sun.COM { 2074*11878SVenu.Iyer@Sun.COM fanout_stat_entry_t *s1 = arg1; 2075*11878SVenu.Iyer@Sun.COM fanout_stat_entry_t *s2 = arg2; 2076*11878SVenu.Iyer@Sun.COM fanout_stat_entry_t *diff_entry; 2077*11878SVenu.Iyer@Sun.COM 2078*11878SVenu.Iyer@Sun.COM diff_entry = malloc(sizeof (fanout_stat_entry_t)); 2079*11878SVenu.Iyer@Sun.COM if (diff_entry == NULL) 2080*11878SVenu.Iyer@Sun.COM goto done; 2081*11878SVenu.Iyer@Sun.COM 2082*11878SVenu.Iyer@Sun.COM diff_entry->fe_index = s1->fe_index; 2083*11878SVenu.Iyer@Sun.COM diff_entry->fe_id = s1->fe_id; 2084*11878SVenu.Iyer@Sun.COM diff_entry->fe_foutindex = s1->fe_foutindex; 2085*11878SVenu.Iyer@Sun.COM 2086*11878SVenu.Iyer@Sun.COM DLSTAT_DIFF_STAT(s1, s2, diff_entry, fe_stats, fanout_stats_list, 2087*11878SVenu.Iyer@Sun.COM FANOUT_STAT_SIZE); 2088*11878SVenu.Iyer@Sun.COM 2089*11878SVenu.Iyer@Sun.COM done: 2090*11878SVenu.Iyer@Sun.COM return (diff_entry); 2091*11878SVenu.Iyer@Sun.COM } 2092*11878SVenu.Iyer@Sun.COM 2093*11878SVenu.Iyer@Sun.COM static void * 2094*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 2095*11878SVenu.Iyer@Sun.COM { 2096*11878SVenu.Iyer@Sun.COM fanout_stat_entry_t *fanout_stat_entry; 2097*11878SVenu.Iyer@Sun.COM 2098*11878SVenu.Iyer@Sun.COM fanout_stat_entry = calloc(1, sizeof (fanout_stat_entry_t)); 2099*11878SVenu.Iyer@Sun.COM if (fanout_stat_entry == NULL) 2100*11878SVenu.Iyer@Sun.COM goto done; 2101*11878SVenu.Iyer@Sun.COM 2102*11878SVenu.Iyer@Sun.COM /* Set by the caller later */ 2103*11878SVenu.Iyer@Sun.COM fanout_stat_entry->fe_index = DLSTAT_INVALID_ENTRY; 2104*11878SVenu.Iyer@Sun.COM fanout_stat_entry->fe_id = DLSTAT_INVALID_ENTRY; 2105*11878SVenu.Iyer@Sun.COM 2106*11878SVenu.Iyer@Sun.COM fanout_stat_entry->fe_foutindex = i; 2107*11878SVenu.Iyer@Sun.COM 2108*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, &fanout_stat_entry->fe_stats, 2109*11878SVenu.Iyer@Sun.COM fanout_stats_list, FANOUT_STAT_SIZE); 2110*11878SVenu.Iyer@Sun.COM 2111*11878SVenu.Iyer@Sun.COM done: 2112*11878SVenu.Iyer@Sun.COM return (fanout_stat_entry); 2113*11878SVenu.Iyer@Sun.COM } 2114*11878SVenu.Iyer@Sun.COM 2115*11878SVenu.Iyer@Sun.COM static void * 2116*11878SVenu.Iyer@Sun.COM i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid, 2117*11878SVenu.Iyer@Sun.COM uint_t idlist[], uint_t idlist_size, 2118*11878SVenu.Iyer@Sun.COM const char *modname, const char *prefix) 2119*11878SVenu.Iyer@Sun.COM { 2120*11878SVenu.Iyer@Sun.COM int i; 2121*11878SVenu.Iyer@Sun.COM char statprefix[MAXLINKNAMELEN]; 2122*11878SVenu.Iyer@Sun.COM char linkname[MAXLINKNAMELEN]; 2123*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *curr, *curr_head; 2124*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL, *prev = NULL; 2125*11878SVenu.Iyer@Sun.COM uint_t fanout_idlist[MAX_RINGS_PER_GROUP]; 2126*11878SVenu.Iyer@Sun.COM uint_t fanout_idlist_size; 2127*11878SVenu.Iyer@Sun.COM 2128*11878SVenu.Iyer@Sun.COM if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 2129*11878SVenu.Iyer@Sun.COM DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2130*11878SVenu.Iyer@Sun.COM return (NULL); 2131*11878SVenu.Iyer@Sun.COM } 2132*11878SVenu.Iyer@Sun.COM 2133*11878SVenu.Iyer@Sun.COM i_dlstat_get_idlist(linkname, DLSTAT_FANOUT_IDLIST, 2134*11878SVenu.Iyer@Sun.COM fanout_idlist, &fanout_idlist_size); 2135*11878SVenu.Iyer@Sun.COM 2136*11878SVenu.Iyer@Sun.COM for (i = 0; i < idlist_size; i++) { 2137*11878SVenu.Iyer@Sun.COM uint_t index = idlist[i]; 2138*11878SVenu.Iyer@Sun.COM 2139*11878SVenu.Iyer@Sun.COM (void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout", 2140*11878SVenu.Iyer@Sun.COM prefix, index); 2141*11878SVenu.Iyer@Sun.COM 2142*11878SVenu.Iyer@Sun.COM curr_head = i_dlstat_query_stats(modname, statprefix, 2143*11878SVenu.Iyer@Sun.COM fanout_idlist, fanout_idlist_size, 2144*11878SVenu.Iyer@Sun.COM i_dlstat_fanout_retrieve_stat); 2145*11878SVenu.Iyer@Sun.COM 2146*11878SVenu.Iyer@Sun.COM if (curr_head == NULL) /* Last lane */ 2147*11878SVenu.Iyer@Sun.COM break; 2148*11878SVenu.Iyer@Sun.COM 2149*11878SVenu.Iyer@Sun.COM if (head == NULL) /* First lane */ 2150*11878SVenu.Iyer@Sun.COM head = curr_head; 2151*11878SVenu.Iyer@Sun.COM else /* Link new lane list to end of previous lane list */ 2152*11878SVenu.Iyer@Sun.COM prev->dc_next = curr_head; 2153*11878SVenu.Iyer@Sun.COM 2154*11878SVenu.Iyer@Sun.COM /* Walk new lane list and set ids */ 2155*11878SVenu.Iyer@Sun.COM for (curr = curr_head; curr != NULL; curr = curr->dc_next) { 2156*11878SVenu.Iyer@Sun.COM fanout_stat_entry_t *curr_stats = curr->dc_statentry; 2157*11878SVenu.Iyer@Sun.COM 2158*11878SVenu.Iyer@Sun.COM curr_stats->fe_index = index; 2159*11878SVenu.Iyer@Sun.COM curr_stats->fe_id = L_HWLANE; 2160*11878SVenu.Iyer@Sun.COM /* 2161*11878SVenu.Iyer@Sun.COM * Save last pointer of previous linked list. 2162*11878SVenu.Iyer@Sun.COM * This pointer is used to chain linked lists 2163*11878SVenu.Iyer@Sun.COM * generated in each iteration. 2164*11878SVenu.Iyer@Sun.COM */ 2165*11878SVenu.Iyer@Sun.COM prev = curr; 2166*11878SVenu.Iyer@Sun.COM } 2167*11878SVenu.Iyer@Sun.COM } 2168*11878SVenu.Iyer@Sun.COM 2169*11878SVenu.Iyer@Sun.COM return (head); 2170*11878SVenu.Iyer@Sun.COM } 2171*11878SVenu.Iyer@Sun.COM 2172*11878SVenu.Iyer@Sun.COM void * 2173*11878SVenu.Iyer@Sun.COM dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid, 2174*11878SVenu.Iyer@Sun.COM const char *linkname) 2175*11878SVenu.Iyer@Sun.COM { 2176*11878SVenu.Iyer@Sun.COM return (i_dlstat_query_fanout_stats(dh, linkid, 2177*11878SVenu.Iyer@Sun.COM default_idlist, default_idlist_size, linkname, 2178*11878SVenu.Iyer@Sun.COM DLSTAT_MAC_RX_SWLANE)); 2179*11878SVenu.Iyer@Sun.COM } 2180*11878SVenu.Iyer@Sun.COM 2181*11878SVenu.Iyer@Sun.COM void * 2182*11878SVenu.Iyer@Sun.COM dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid, 2183*11878SVenu.Iyer@Sun.COM const char *linkname) 2184*11878SVenu.Iyer@Sun.COM { 2185*11878SVenu.Iyer@Sun.COM uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 2186*11878SVenu.Iyer@Sun.COM uint_t rx_hwlane_idlist_size; 2187*11878SVenu.Iyer@Sun.COM 2188*11878SVenu.Iyer@Sun.COM i_dlstat_get_idlist(linkname, DLSTAT_RX_HWLANE_IDLIST, 2189*11878SVenu.Iyer@Sun.COM rx_hwlane_idlist, &rx_hwlane_idlist_size); 2190*11878SVenu.Iyer@Sun.COM 2191*11878SVenu.Iyer@Sun.COM return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist, 2192*11878SVenu.Iyer@Sun.COM rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE)); 2193*11878SVenu.Iyer@Sun.COM } 2194*11878SVenu.Iyer@Sun.COM 2195*11878SVenu.Iyer@Sun.COM void * 2196*11878SVenu.Iyer@Sun.COM dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid) 2197*11878SVenu.Iyer@Sun.COM { 2198*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 2199*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *fout_hwlane_stats; 2200*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *fout_swlane_and_local_stats; 2201*11878SVenu.Iyer@Sun.COM fanout_stat_entry_t *fout_stats; 2202*11878SVenu.Iyer@Sun.COM char linkname[MAXLINKNAMELEN]; 2203*11878SVenu.Iyer@Sun.COM 2204*11878SVenu.Iyer@Sun.COM if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 2205*11878SVenu.Iyer@Sun.COM DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2206*11878SVenu.Iyer@Sun.COM goto done; 2207*11878SVenu.Iyer@Sun.COM } 2208*11878SVenu.Iyer@Sun.COM 2209*11878SVenu.Iyer@Sun.COM fout_swlane_and_local_stats = 2210*11878SVenu.Iyer@Sun.COM dlstat_fanout_swlane_and_local_stats(dh, linkid, linkname); 2211*11878SVenu.Iyer@Sun.COM fout_hwlane_stats = dlstat_fanout_hwlane_stats(dh, linkid, linkname); 2212*11878SVenu.Iyer@Sun.COM 2213*11878SVenu.Iyer@Sun.COM if (fout_swlane_and_local_stats == NULL) { 2214*11878SVenu.Iyer@Sun.COM head = fout_hwlane_stats; 2215*11878SVenu.Iyer@Sun.COM goto done; 2216*11878SVenu.Iyer@Sun.COM } 2217*11878SVenu.Iyer@Sun.COM 2218*11878SVenu.Iyer@Sun.COM fout_stats = fout_swlane_and_local_stats->dc_statentry; 2219*11878SVenu.Iyer@Sun.COM 2220*11878SVenu.Iyer@Sun.COM if (fout_hwlane_stats != NULL) { /* hwlane(s), only local traffic */ 2221*11878SVenu.Iyer@Sun.COM fout_stats->fe_id = L_LOCAL; 2222*11878SVenu.Iyer@Sun.COM fout_stats->fe_index = DLSTAT_INVALID_ENTRY; 2223*11878SVenu.Iyer@Sun.COM } else { /* no hwlane, mix of local+sw classified */ 2224*11878SVenu.Iyer@Sun.COM fout_stats->fe_id = L_LCLSWLANE; 2225*11878SVenu.Iyer@Sun.COM fout_stats->fe_index = DLSTAT_INVALID_ENTRY; 2226*11878SVenu.Iyer@Sun.COM } 2227*11878SVenu.Iyer@Sun.COM 2228*11878SVenu.Iyer@Sun.COM fout_swlane_and_local_stats->dc_next = fout_hwlane_stats; 2229*11878SVenu.Iyer@Sun.COM head = fout_swlane_and_local_stats; 2230*11878SVenu.Iyer@Sun.COM 2231*11878SVenu.Iyer@Sun.COM done: 2232*11878SVenu.Iyer@Sun.COM return (head); 2233*11878SVenu.Iyer@Sun.COM } 2234*11878SVenu.Iyer@Sun.COM 2235*11878SVenu.Iyer@Sun.COM /* Rx ring statistic specific functions */ 2236*11878SVenu.Iyer@Sun.COM static boolean_t 2237*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_match(void *arg1, void *arg2) 2238*11878SVenu.Iyer@Sun.COM { 2239*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *s1 = arg1; 2240*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *s2 = arg2; 2241*11878SVenu.Iyer@Sun.COM 2242*11878SVenu.Iyer@Sun.COM return (s1->rle_index == s2->rle_index); 2243*11878SVenu.Iyer@Sun.COM } 2244*11878SVenu.Iyer@Sun.COM 2245*11878SVenu.Iyer@Sun.COM static void * 2246*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_stat_entry_diff(void *arg1, void *arg2) 2247*11878SVenu.Iyer@Sun.COM { 2248*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *s1 = arg1; 2249*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *s2 = arg2; 2250*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *diff_entry; 2251*11878SVenu.Iyer@Sun.COM 2252*11878SVenu.Iyer@Sun.COM diff_entry = malloc(sizeof (ring_stat_entry_t)); 2253*11878SVenu.Iyer@Sun.COM if (diff_entry == NULL) 2254*11878SVenu.Iyer@Sun.COM goto done; 2255*11878SVenu.Iyer@Sun.COM 2256*11878SVenu.Iyer@Sun.COM diff_entry->re_index = s1->re_index; 2257*11878SVenu.Iyer@Sun.COM 2258*11878SVenu.Iyer@Sun.COM DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, rx_ring_stats_list, 2259*11878SVenu.Iyer@Sun.COM RX_RING_STAT_SIZE); 2260*11878SVenu.Iyer@Sun.COM 2261*11878SVenu.Iyer@Sun.COM done: 2262*11878SVenu.Iyer@Sun.COM return (diff_entry); 2263*11878SVenu.Iyer@Sun.COM } 2264*11878SVenu.Iyer@Sun.COM 2265*11878SVenu.Iyer@Sun.COM static void * 2266*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 2267*11878SVenu.Iyer@Sun.COM { 2268*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *rx_ring_stat_entry; 2269*11878SVenu.Iyer@Sun.COM 2270*11878SVenu.Iyer@Sun.COM rx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t)); 2271*11878SVenu.Iyer@Sun.COM if (rx_ring_stat_entry == NULL) 2272*11878SVenu.Iyer@Sun.COM goto done; 2273*11878SVenu.Iyer@Sun.COM 2274*11878SVenu.Iyer@Sun.COM rx_ring_stat_entry->re_index = i; 2275*11878SVenu.Iyer@Sun.COM 2276*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, &rx_ring_stat_entry->re_stats, 2277*11878SVenu.Iyer@Sun.COM rx_ring_stats_list, RX_RING_STAT_SIZE); 2278*11878SVenu.Iyer@Sun.COM 2279*11878SVenu.Iyer@Sun.COM done: 2280*11878SVenu.Iyer@Sun.COM return (rx_ring_stat_entry); 2281*11878SVenu.Iyer@Sun.COM } 2282*11878SVenu.Iyer@Sun.COM 2283*11878SVenu.Iyer@Sun.COM void * 2284*11878SVenu.Iyer@Sun.COM dlstat_rx_ring_stats(dladm_handle_t dh, datalink_id_t linkid) 2285*11878SVenu.Iyer@Sun.COM { 2286*11878SVenu.Iyer@Sun.COM uint_t rx_ring_idlist[MAX_RINGS_PER_GROUP]; 2287*11878SVenu.Iyer@Sun.COM uint_t rx_ring_idlist_size; 2288*11878SVenu.Iyer@Sun.COM dladm_phys_attr_t dpa; 2289*11878SVenu.Iyer@Sun.COM char linkname[MAXLINKNAMELEN]; 2290*11878SVenu.Iyer@Sun.COM char *modname; 2291*11878SVenu.Iyer@Sun.COM datalink_class_t class; 2292*11878SVenu.Iyer@Sun.COM 2293*11878SVenu.Iyer@Sun.COM /* 2294*11878SVenu.Iyer@Sun.COM * kstats corresponding to physical device rings continue to use 2295*11878SVenu.Iyer@Sun.COM * device names even if the link is renamed using dladm rename-link. 2296*11878SVenu.Iyer@Sun.COM * Thus, given a linkid, we lookup the physical device name. 2297*11878SVenu.Iyer@Sun.COM * However, if an aggr is renamed, kstats corresponding to its 2298*11878SVenu.Iyer@Sun.COM * pseudo rings are renamed as well. 2299*11878SVenu.Iyer@Sun.COM */ 2300*11878SVenu.Iyer@Sun.COM if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname, 2301*11878SVenu.Iyer@Sun.COM DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2302*11878SVenu.Iyer@Sun.COM return (NULL); 2303*11878SVenu.Iyer@Sun.COM } 2304*11878SVenu.Iyer@Sun.COM 2305*11878SVenu.Iyer@Sun.COM if (class != DATALINK_CLASS_AGGR) { 2306*11878SVenu.Iyer@Sun.COM if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 2307*11878SVenu.Iyer@Sun.COM DLADM_STATUS_OK) { 2308*11878SVenu.Iyer@Sun.COM return (NULL); 2309*11878SVenu.Iyer@Sun.COM } 2310*11878SVenu.Iyer@Sun.COM modname = dpa.dp_dev; 2311*11878SVenu.Iyer@Sun.COM } else 2312*11878SVenu.Iyer@Sun.COM modname = linkname; 2313*11878SVenu.Iyer@Sun.COM 2314*11878SVenu.Iyer@Sun.COM i_dlstat_get_idlist(modname, DLSTAT_RX_RING_IDLIST, 2315*11878SVenu.Iyer@Sun.COM rx_ring_idlist, &rx_ring_idlist_size); 2316*11878SVenu.Iyer@Sun.COM 2317*11878SVenu.Iyer@Sun.COM return (i_dlstat_query_stats(modname, DLSTAT_MAC_RX_RING, 2318*11878SVenu.Iyer@Sun.COM rx_ring_idlist, rx_ring_idlist_size, 2319*11878SVenu.Iyer@Sun.COM i_dlstat_rx_ring_retrieve_stat)); 2320*11878SVenu.Iyer@Sun.COM } 2321*11878SVenu.Iyer@Sun.COM 2322*11878SVenu.Iyer@Sun.COM /* Tx ring statistic specific functions */ 2323*11878SVenu.Iyer@Sun.COM static boolean_t 2324*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_match(void *arg1, void *arg2) 2325*11878SVenu.Iyer@Sun.COM { 2326*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *s1 = arg1; 2327*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *s2 = arg2; 2328*11878SVenu.Iyer@Sun.COM 2329*11878SVenu.Iyer@Sun.COM return (s1->tle_index == s2->tle_index); 2330*11878SVenu.Iyer@Sun.COM } 2331*11878SVenu.Iyer@Sun.COM 2332*11878SVenu.Iyer@Sun.COM static void * 2333*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2) 2334*11878SVenu.Iyer@Sun.COM { 2335*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *s1 = arg1; 2336*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *s2 = arg2; 2337*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *diff_entry; 2338*11878SVenu.Iyer@Sun.COM 2339*11878SVenu.Iyer@Sun.COM diff_entry = malloc(sizeof (ring_stat_entry_t)); 2340*11878SVenu.Iyer@Sun.COM if (diff_entry == NULL) 2341*11878SVenu.Iyer@Sun.COM goto done; 2342*11878SVenu.Iyer@Sun.COM 2343*11878SVenu.Iyer@Sun.COM diff_entry->re_index = s1->re_index; 2344*11878SVenu.Iyer@Sun.COM 2345*11878SVenu.Iyer@Sun.COM DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, tx_ring_stats_list, 2346*11878SVenu.Iyer@Sun.COM TX_RING_STAT_SIZE); 2347*11878SVenu.Iyer@Sun.COM 2348*11878SVenu.Iyer@Sun.COM done: 2349*11878SVenu.Iyer@Sun.COM return (diff_entry); 2350*11878SVenu.Iyer@Sun.COM } 2351*11878SVenu.Iyer@Sun.COM 2352*11878SVenu.Iyer@Sun.COM static void * 2353*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 2354*11878SVenu.Iyer@Sun.COM { 2355*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *tx_ring_stat_entry; 2356*11878SVenu.Iyer@Sun.COM 2357*11878SVenu.Iyer@Sun.COM tx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t)); 2358*11878SVenu.Iyer@Sun.COM if (tx_ring_stat_entry == NULL) 2359*11878SVenu.Iyer@Sun.COM goto done; 2360*11878SVenu.Iyer@Sun.COM 2361*11878SVenu.Iyer@Sun.COM tx_ring_stat_entry->re_index = i; 2362*11878SVenu.Iyer@Sun.COM 2363*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, &tx_ring_stat_entry->re_stats, 2364*11878SVenu.Iyer@Sun.COM tx_ring_stats_list, TX_RING_STAT_SIZE); 2365*11878SVenu.Iyer@Sun.COM 2366*11878SVenu.Iyer@Sun.COM done: 2367*11878SVenu.Iyer@Sun.COM return (tx_ring_stat_entry); 2368*11878SVenu.Iyer@Sun.COM } 2369*11878SVenu.Iyer@Sun.COM 2370*11878SVenu.Iyer@Sun.COM void * 2371*11878SVenu.Iyer@Sun.COM dlstat_tx_ring_stats(dladm_handle_t dh, datalink_id_t linkid) 2372*11878SVenu.Iyer@Sun.COM { 2373*11878SVenu.Iyer@Sun.COM uint_t tx_ring_idlist[MAX_RINGS_PER_GROUP]; 2374*11878SVenu.Iyer@Sun.COM uint_t tx_ring_idlist_size; 2375*11878SVenu.Iyer@Sun.COM dladm_phys_attr_t dpa; 2376*11878SVenu.Iyer@Sun.COM char linkname[MAXLINKNAMELEN]; 2377*11878SVenu.Iyer@Sun.COM char *modname; 2378*11878SVenu.Iyer@Sun.COM datalink_class_t class; 2379*11878SVenu.Iyer@Sun.COM 2380*11878SVenu.Iyer@Sun.COM /* 2381*11878SVenu.Iyer@Sun.COM * kstats corresponding to physical device rings continue to use 2382*11878SVenu.Iyer@Sun.COM * device names even if the link is renamed using dladm rename-link. 2383*11878SVenu.Iyer@Sun.COM * Thus, given a linkid, we lookup the physical device name. 2384*11878SVenu.Iyer@Sun.COM * However, if an aggr is renamed, kstats corresponding to its 2385*11878SVenu.Iyer@Sun.COM * pseudo rings are renamed as well. 2386*11878SVenu.Iyer@Sun.COM */ 2387*11878SVenu.Iyer@Sun.COM if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname, 2388*11878SVenu.Iyer@Sun.COM DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2389*11878SVenu.Iyer@Sun.COM return (NULL); 2390*11878SVenu.Iyer@Sun.COM } 2391*11878SVenu.Iyer@Sun.COM 2392*11878SVenu.Iyer@Sun.COM if (class != DATALINK_CLASS_AGGR) { 2393*11878SVenu.Iyer@Sun.COM if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 2394*11878SVenu.Iyer@Sun.COM DLADM_STATUS_OK) { 2395*11878SVenu.Iyer@Sun.COM return (NULL); 2396*11878SVenu.Iyer@Sun.COM } 2397*11878SVenu.Iyer@Sun.COM modname = dpa.dp_dev; 2398*11878SVenu.Iyer@Sun.COM } else 2399*11878SVenu.Iyer@Sun.COM modname = linkname; 2400*11878SVenu.Iyer@Sun.COM 2401*11878SVenu.Iyer@Sun.COM i_dlstat_get_idlist(modname, DLSTAT_TX_RING_IDLIST, 2402*11878SVenu.Iyer@Sun.COM tx_ring_idlist, &tx_ring_idlist_size); 2403*11878SVenu.Iyer@Sun.COM 2404*11878SVenu.Iyer@Sun.COM return (i_dlstat_query_stats(modname, DLSTAT_MAC_TX_RING, 2405*11878SVenu.Iyer@Sun.COM tx_ring_idlist, tx_ring_idlist_size, 2406*11878SVenu.Iyer@Sun.COM i_dlstat_tx_ring_retrieve_stat)); 2407*11878SVenu.Iyer@Sun.COM } 2408*11878SVenu.Iyer@Sun.COM 2409*11878SVenu.Iyer@Sun.COM /* Rx ring total statistic specific functions */ 2410*11878SVenu.Iyer@Sun.COM void * 2411*11878SVenu.Iyer@Sun.COM dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid) 2412*11878SVenu.Iyer@Sun.COM { 2413*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *total_head = NULL; 2414*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *rx_ring_head, *curr; 2415*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *total_stats; 2416*11878SVenu.Iyer@Sun.COM 2417*11878SVenu.Iyer@Sun.COM /* Get per rx ring stats */ 2418*11878SVenu.Iyer@Sun.COM rx_ring_head = dlstat_rx_ring_stats(dh, linkid); 2419*11878SVenu.Iyer@Sun.COM if (rx_ring_head == NULL) 2420*11878SVenu.Iyer@Sun.COM goto done; 2421*11878SVenu.Iyer@Sun.COM 2422*11878SVenu.Iyer@Sun.COM total_stats = calloc(1, sizeof (ring_stat_entry_t)); 2423*11878SVenu.Iyer@Sun.COM if (total_stats == NULL) 2424*11878SVenu.Iyer@Sun.COM goto done; 2425*11878SVenu.Iyer@Sun.COM 2426*11878SVenu.Iyer@Sun.COM total_stats->re_index = DLSTAT_INVALID_ENTRY; 2427*11878SVenu.Iyer@Sun.COM 2428*11878SVenu.Iyer@Sun.COM for (curr = rx_ring_head; curr != NULL; curr = curr->dc_next) { 2429*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *curr_ring_stats = curr->dc_statentry; 2430*11878SVenu.Iyer@Sun.COM 2431*11878SVenu.Iyer@Sun.COM i_dlstat_sum_stats(&total_stats->re_stats, 2432*11878SVenu.Iyer@Sun.COM &curr_ring_stats->re_stats, &total_stats->re_stats, 2433*11878SVenu.Iyer@Sun.COM rx_ring_stats_list, RX_RING_STAT_SIZE); 2434*11878SVenu.Iyer@Sun.COM } 2435*11878SVenu.Iyer@Sun.COM 2436*11878SVenu.Iyer@Sun.COM total_head = malloc(sizeof (dladm_stat_chain_t)); 2437*11878SVenu.Iyer@Sun.COM if (total_head == NULL) { 2438*11878SVenu.Iyer@Sun.COM free(total_stats); 2439*11878SVenu.Iyer@Sun.COM goto done; 2440*11878SVenu.Iyer@Sun.COM } 2441*11878SVenu.Iyer@Sun.COM 2442*11878SVenu.Iyer@Sun.COM total_head->dc_statentry = total_stats; 2443*11878SVenu.Iyer@Sun.COM (void) strlcpy(total_head->dc_statheader, "mac_rx_ring_total", 2444*11878SVenu.Iyer@Sun.COM sizeof (total_head->dc_statheader)); 2445*11878SVenu.Iyer@Sun.COM total_head->dc_next = NULL; 2446*11878SVenu.Iyer@Sun.COM free(rx_ring_head); 2447*11878SVenu.Iyer@Sun.COM 2448*11878SVenu.Iyer@Sun.COM done: 2449*11878SVenu.Iyer@Sun.COM return (total_head); 2450*11878SVenu.Iyer@Sun.COM } 2451*11878SVenu.Iyer@Sun.COM 2452*11878SVenu.Iyer@Sun.COM /* Tx ring total statistic specific functions */ 2453*11878SVenu.Iyer@Sun.COM void * 2454*11878SVenu.Iyer@Sun.COM dlstat_tx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid) 2455*11878SVenu.Iyer@Sun.COM { 2456*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *total_head = NULL; 2457*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *tx_ring_head, *curr; 2458*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *total_stats; 2459*11878SVenu.Iyer@Sun.COM 2460*11878SVenu.Iyer@Sun.COM /* Get per tx ring stats */ 2461*11878SVenu.Iyer@Sun.COM tx_ring_head = dlstat_tx_ring_stats(dh, linkid); 2462*11878SVenu.Iyer@Sun.COM if (tx_ring_head == NULL) 2463*11878SVenu.Iyer@Sun.COM goto done; 2464*11878SVenu.Iyer@Sun.COM 2465*11878SVenu.Iyer@Sun.COM total_stats = calloc(1, sizeof (ring_stat_entry_t)); 2466*11878SVenu.Iyer@Sun.COM if (total_stats == NULL) 2467*11878SVenu.Iyer@Sun.COM goto done; 2468*11878SVenu.Iyer@Sun.COM 2469*11878SVenu.Iyer@Sun.COM total_stats->re_index = DLSTAT_INVALID_ENTRY; 2470*11878SVenu.Iyer@Sun.COM 2471*11878SVenu.Iyer@Sun.COM for (curr = tx_ring_head; curr != NULL; curr = curr->dc_next) { 2472*11878SVenu.Iyer@Sun.COM ring_stat_entry_t *curr_ring_stats = curr->dc_statentry; 2473*11878SVenu.Iyer@Sun.COM 2474*11878SVenu.Iyer@Sun.COM i_dlstat_sum_stats(&total_stats->re_stats, 2475*11878SVenu.Iyer@Sun.COM &curr_ring_stats->re_stats, &total_stats->re_stats, 2476*11878SVenu.Iyer@Sun.COM tx_ring_stats_list, TX_RING_STAT_SIZE); 2477*11878SVenu.Iyer@Sun.COM } 2478*11878SVenu.Iyer@Sun.COM 2479*11878SVenu.Iyer@Sun.COM total_head = malloc(sizeof (dladm_stat_chain_t)); 2480*11878SVenu.Iyer@Sun.COM if (total_head == NULL) { 2481*11878SVenu.Iyer@Sun.COM free(total_stats); 2482*11878SVenu.Iyer@Sun.COM goto done; 2483*11878SVenu.Iyer@Sun.COM } 2484*11878SVenu.Iyer@Sun.COM 2485*11878SVenu.Iyer@Sun.COM total_head->dc_statentry = total_stats; 2486*11878SVenu.Iyer@Sun.COM (void) strlcpy(total_head->dc_statheader, "mac_tx_ring_total", 2487*11878SVenu.Iyer@Sun.COM sizeof (total_head->dc_statheader)); 2488*11878SVenu.Iyer@Sun.COM total_head->dc_next = NULL; 2489*11878SVenu.Iyer@Sun.COM free(tx_ring_head); 2490*11878SVenu.Iyer@Sun.COM 2491*11878SVenu.Iyer@Sun.COM done: 2492*11878SVenu.Iyer@Sun.COM return (total_head); 2493*11878SVenu.Iyer@Sun.COM } 2494*11878SVenu.Iyer@Sun.COM 2495*11878SVenu.Iyer@Sun.COM /* Summary statistic specific functions */ 2496*11878SVenu.Iyer@Sun.COM /*ARGSUSED*/ 2497*11878SVenu.Iyer@Sun.COM static boolean_t 2498*11878SVenu.Iyer@Sun.COM i_dlstat_total_match(void *arg1, void *arg2) 2499*11878SVenu.Iyer@Sun.COM { /* Always single entry for total */ 2500*11878SVenu.Iyer@Sun.COM return (B_TRUE); 2501*11878SVenu.Iyer@Sun.COM } 2502*11878SVenu.Iyer@Sun.COM 2503*11878SVenu.Iyer@Sun.COM static void * 2504*11878SVenu.Iyer@Sun.COM i_dlstat_total_stat_entry_diff(void *arg1, void *arg2) 2505*11878SVenu.Iyer@Sun.COM { 2506*11878SVenu.Iyer@Sun.COM total_stat_entry_t *s1 = arg1; 2507*11878SVenu.Iyer@Sun.COM total_stat_entry_t *s2 = arg2; 2508*11878SVenu.Iyer@Sun.COM total_stat_entry_t *diff_entry; 2509*11878SVenu.Iyer@Sun.COM 2510*11878SVenu.Iyer@Sun.COM diff_entry = malloc(sizeof (total_stat_entry_t)); 2511*11878SVenu.Iyer@Sun.COM if (diff_entry == NULL) 2512*11878SVenu.Iyer@Sun.COM goto done; 2513*11878SVenu.Iyer@Sun.COM 2514*11878SVenu.Iyer@Sun.COM DLSTAT_DIFF_STAT(s1, s2, diff_entry, tse_stats, total_stats_list, 2515*11878SVenu.Iyer@Sun.COM TOTAL_STAT_SIZE); 2516*11878SVenu.Iyer@Sun.COM 2517*11878SVenu.Iyer@Sun.COM done: 2518*11878SVenu.Iyer@Sun.COM return (diff_entry); 2519*11878SVenu.Iyer@Sun.COM } 2520*11878SVenu.Iyer@Sun.COM 2521*11878SVenu.Iyer@Sun.COM void * 2522*11878SVenu.Iyer@Sun.COM dlstat_total_stats(dladm_handle_t dh, datalink_id_t linkid) 2523*11878SVenu.Iyer@Sun.COM { 2524*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 2525*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *rx_total; 2526*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *tx_total; 2527*11878SVenu.Iyer@Sun.COM total_stat_entry_t *total_stat_entry; 2528*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry_t *rx_lane_stat_entry; 2529*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry_t *tx_lane_stat_entry; 2530*11878SVenu.Iyer@Sun.COM 2531*11878SVenu.Iyer@Sun.COM /* Get total rx lane stats */ 2532*11878SVenu.Iyer@Sun.COM rx_total = dlstat_rx_lane_total_stats(dh, linkid); 2533*11878SVenu.Iyer@Sun.COM if (rx_total == NULL) 2534*11878SVenu.Iyer@Sun.COM goto done; 2535*11878SVenu.Iyer@Sun.COM 2536*11878SVenu.Iyer@Sun.COM /* Get total tx lane stats */ 2537*11878SVenu.Iyer@Sun.COM tx_total = dlstat_tx_lane_total_stats(dh, linkid); 2538*11878SVenu.Iyer@Sun.COM if (tx_total == NULL) 2539*11878SVenu.Iyer@Sun.COM goto done; 2540*11878SVenu.Iyer@Sun.COM 2541*11878SVenu.Iyer@Sun.COM /* Build total stat */ 2542*11878SVenu.Iyer@Sun.COM total_stat_entry = calloc(1, sizeof (total_stat_entry_t)); 2543*11878SVenu.Iyer@Sun.COM if (total_stat_entry == NULL) 2544*11878SVenu.Iyer@Sun.COM goto done; 2545*11878SVenu.Iyer@Sun.COM 2546*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry = rx_total->dc_statentry; 2547*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry = tx_total->dc_statentry; 2548*11878SVenu.Iyer@Sun.COM 2549*11878SVenu.Iyer@Sun.COM /* Extract total rx ipackets, rbytes */ 2550*11878SVenu.Iyer@Sun.COM total_stat_entry->tse_stats.ts_ipackets = 2551*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_ipackets; 2552*11878SVenu.Iyer@Sun.COM total_stat_entry->tse_stats.ts_rbytes = 2553*11878SVenu.Iyer@Sun.COM rx_lane_stat_entry->rle_stats.rl_rbytes; 2554*11878SVenu.Iyer@Sun.COM 2555*11878SVenu.Iyer@Sun.COM /* Extract total tx opackets, obytes */ 2556*11878SVenu.Iyer@Sun.COM total_stat_entry->tse_stats.ts_opackets = 2557*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_stats.tl_opackets; 2558*11878SVenu.Iyer@Sun.COM total_stat_entry->tse_stats.ts_obytes = 2559*11878SVenu.Iyer@Sun.COM tx_lane_stat_entry->tle_stats.tl_obytes; 2560*11878SVenu.Iyer@Sun.COM 2561*11878SVenu.Iyer@Sun.COM head = malloc(sizeof (dladm_stat_chain_t)); 2562*11878SVenu.Iyer@Sun.COM if (head == NULL) { 2563*11878SVenu.Iyer@Sun.COM free(total_stat_entry); 2564*11878SVenu.Iyer@Sun.COM goto done; 2565*11878SVenu.Iyer@Sun.COM } 2566*11878SVenu.Iyer@Sun.COM 2567*11878SVenu.Iyer@Sun.COM head->dc_statentry = total_stat_entry; 2568*11878SVenu.Iyer@Sun.COM (void) strlcpy(head->dc_statheader, "mac_lane_total", 2569*11878SVenu.Iyer@Sun.COM sizeof (head->dc_statheader)); 2570*11878SVenu.Iyer@Sun.COM head->dc_next = NULL; 2571*11878SVenu.Iyer@Sun.COM free(rx_total); 2572*11878SVenu.Iyer@Sun.COM free(tx_total); 2573*11878SVenu.Iyer@Sun.COM 2574*11878SVenu.Iyer@Sun.COM done: 2575*11878SVenu.Iyer@Sun.COM return (head); 2576*11878SVenu.Iyer@Sun.COM } 2577*11878SVenu.Iyer@Sun.COM 2578*11878SVenu.Iyer@Sun.COM /* Aggr total statistic(summed across all component ports) specific functions */ 2579*11878SVenu.Iyer@Sun.COM void * 2580*11878SVenu.Iyer@Sun.COM dlstat_aggr_total_stats(dladm_stat_chain_t *head) 2581*11878SVenu.Iyer@Sun.COM { 2582*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *curr; 2583*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *total_head; 2584*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry_t *total_stats; 2585*11878SVenu.Iyer@Sun.COM 2586*11878SVenu.Iyer@Sun.COM total_stats = calloc(1, sizeof (aggr_port_stat_entry_t)); 2587*11878SVenu.Iyer@Sun.COM if (total_stats == NULL) 2588*11878SVenu.Iyer@Sun.COM goto done; 2589*11878SVenu.Iyer@Sun.COM 2590*11878SVenu.Iyer@Sun.COM total_stats->ape_portlinkid = DATALINK_INVALID_LINKID; 2591*11878SVenu.Iyer@Sun.COM 2592*11878SVenu.Iyer@Sun.COM for (curr = head; curr != NULL; curr = curr->dc_next) { 2593*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry_t *curr_aggr_port_stats; 2594*11878SVenu.Iyer@Sun.COM 2595*11878SVenu.Iyer@Sun.COM curr_aggr_port_stats = curr->dc_statentry; 2596*11878SVenu.Iyer@Sun.COM 2597*11878SVenu.Iyer@Sun.COM i_dlstat_sum_stats(&total_stats->ape_stats, 2598*11878SVenu.Iyer@Sun.COM &curr_aggr_port_stats->ape_stats, &total_stats->ape_stats, 2599*11878SVenu.Iyer@Sun.COM aggr_port_stats_list, AGGR_PORT_STAT_SIZE); 2600*11878SVenu.Iyer@Sun.COM } 2601*11878SVenu.Iyer@Sun.COM 2602*11878SVenu.Iyer@Sun.COM total_head = malloc(sizeof (dladm_stat_chain_t)); 2603*11878SVenu.Iyer@Sun.COM if (total_head == NULL) { 2604*11878SVenu.Iyer@Sun.COM free(total_stats); 2605*11878SVenu.Iyer@Sun.COM goto done; 2606*11878SVenu.Iyer@Sun.COM } 2607*11878SVenu.Iyer@Sun.COM 2608*11878SVenu.Iyer@Sun.COM total_head->dc_statentry = total_stats; 2609*11878SVenu.Iyer@Sun.COM total_head->dc_next = NULL; 2610*11878SVenu.Iyer@Sun.COM 2611*11878SVenu.Iyer@Sun.COM done: 2612*11878SVenu.Iyer@Sun.COM return (total_head); 2613*11878SVenu.Iyer@Sun.COM } 2614*11878SVenu.Iyer@Sun.COM 2615*11878SVenu.Iyer@Sun.COM /* Aggr port statistic specific functions */ 2616*11878SVenu.Iyer@Sun.COM static boolean_t 2617*11878SVenu.Iyer@Sun.COM i_dlstat_aggr_port_match(void *arg1, void *arg2) 2618*11878SVenu.Iyer@Sun.COM { 2619*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry_t *s1 = arg1; 2620*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry_t *s2 = arg2; 2621*11878SVenu.Iyer@Sun.COM 2622*11878SVenu.Iyer@Sun.COM return (s1->ape_portlinkid == s2->ape_portlinkid); 2623*11878SVenu.Iyer@Sun.COM } 2624*11878SVenu.Iyer@Sun.COM 2625*11878SVenu.Iyer@Sun.COM static void * 2626*11878SVenu.Iyer@Sun.COM i_dlstat_aggr_port_stat_entry_diff(void *arg1, void *arg2) 2627*11878SVenu.Iyer@Sun.COM { 2628*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry_t *s1 = arg1; 2629*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry_t *s2 = arg2; 2630*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry_t *diff_entry; 2631*11878SVenu.Iyer@Sun.COM 2632*11878SVenu.Iyer@Sun.COM diff_entry = malloc(sizeof (aggr_port_stat_entry_t)); 2633*11878SVenu.Iyer@Sun.COM if (diff_entry == NULL) 2634*11878SVenu.Iyer@Sun.COM goto done; 2635*11878SVenu.Iyer@Sun.COM 2636*11878SVenu.Iyer@Sun.COM diff_entry->ape_portlinkid = s1->ape_portlinkid; 2637*11878SVenu.Iyer@Sun.COM 2638*11878SVenu.Iyer@Sun.COM DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list, 2639*11878SVenu.Iyer@Sun.COM AGGR_PORT_STAT_SIZE); 2640*11878SVenu.Iyer@Sun.COM 2641*11878SVenu.Iyer@Sun.COM done: 2642*11878SVenu.Iyer@Sun.COM return (diff_entry); 2643*11878SVenu.Iyer@Sun.COM } 2644*11878SVenu.Iyer@Sun.COM 2645*11878SVenu.Iyer@Sun.COM /* 2646*11878SVenu.Iyer@Sun.COM * Query dls stats for the aggr port. This results in query for stats into 2647*11878SVenu.Iyer@Sun.COM * the corresponding device driver. 2648*11878SVenu.Iyer@Sun.COM */ 2649*11878SVenu.Iyer@Sun.COM static aggr_port_stat_entry_t * 2650*11878SVenu.Iyer@Sun.COM i_dlstat_single_port_stats(const char *portname, datalink_id_t linkid) 2651*11878SVenu.Iyer@Sun.COM { 2652*11878SVenu.Iyer@Sun.COM kstat_ctl_t *kcp; 2653*11878SVenu.Iyer@Sun.COM kstat_t *ksp; 2654*11878SVenu.Iyer@Sun.COM char module[DLPI_LINKNAME_MAX]; 2655*11878SVenu.Iyer@Sun.COM uint_t instance; 2656*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry_t *aggr_port_stat_entry = NULL; 2657*11878SVenu.Iyer@Sun.COM 2658*11878SVenu.Iyer@Sun.COM if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK) 2659*11878SVenu.Iyer@Sun.COM goto done; 2660*11878SVenu.Iyer@Sun.COM 2661*11878SVenu.Iyer@Sun.COM if ((kcp = kstat_open()) == NULL) { 2662*11878SVenu.Iyer@Sun.COM warn("kstat open operation failed"); 2663*11878SVenu.Iyer@Sun.COM return (NULL); 2664*11878SVenu.Iyer@Sun.COM } 2665*11878SVenu.Iyer@Sun.COM 2666*11878SVenu.Iyer@Sun.COM ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 2667*11878SVenu.Iyer@Sun.COM if (ksp == NULL) 2668*11878SVenu.Iyer@Sun.COM goto done; 2669*11878SVenu.Iyer@Sun.COM 2670*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t)); 2671*11878SVenu.Iyer@Sun.COM if (aggr_port_stat_entry == NULL) 2672*11878SVenu.Iyer@Sun.COM goto done; 2673*11878SVenu.Iyer@Sun.COM 2674*11878SVenu.Iyer@Sun.COM /* Save port's linkid */ 2675*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry->ape_portlinkid = linkid; 2676*11878SVenu.Iyer@Sun.COM 2677*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, &aggr_port_stat_entry->ape_stats, 2678*11878SVenu.Iyer@Sun.COM aggr_port_stats_list, AGGR_PORT_STAT_SIZE); 2679*11878SVenu.Iyer@Sun.COM done: 2680*11878SVenu.Iyer@Sun.COM (void) kstat_close(kcp); 2681*11878SVenu.Iyer@Sun.COM return (aggr_port_stat_entry); 2682*11878SVenu.Iyer@Sun.COM } 2683*11878SVenu.Iyer@Sun.COM 2684*11878SVenu.Iyer@Sun.COM void * 2685*11878SVenu.Iyer@Sun.COM dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid) 2686*11878SVenu.Iyer@Sun.COM { 2687*11878SVenu.Iyer@Sun.COM dladm_aggr_grp_attr_t ginfo; 2688*11878SVenu.Iyer@Sun.COM int i; 2689*11878SVenu.Iyer@Sun.COM dladm_aggr_port_attr_t *portp; 2690*11878SVenu.Iyer@Sun.COM dladm_phys_attr_t dpa; 2691*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry_t *aggr_port_stat_entry; 2692*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL, *prev = NULL, *curr; 2693*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *total_stats; 2694*11878SVenu.Iyer@Sun.COM 2695*11878SVenu.Iyer@Sun.COM /* Get aggr info */ 2696*11878SVenu.Iyer@Sun.COM bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 2697*11878SVenu.Iyer@Sun.COM if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE) 2698*11878SVenu.Iyer@Sun.COM != DLADM_STATUS_OK) 2699*11878SVenu.Iyer@Sun.COM goto done; 2700*11878SVenu.Iyer@Sun.COM /* For every port that is member of this aggr do */ 2701*11878SVenu.Iyer@Sun.COM for (i = 0; i < ginfo.lg_nports; i++) { 2702*11878SVenu.Iyer@Sun.COM portp = &(ginfo.lg_ports[i]); 2703*11878SVenu.Iyer@Sun.COM if (dladm_phys_info(dh, portp->lp_linkid, &dpa, 2704*11878SVenu.Iyer@Sun.COM DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) { 2705*11878SVenu.Iyer@Sun.COM goto done; 2706*11878SVenu.Iyer@Sun.COM } 2707*11878SVenu.Iyer@Sun.COM 2708*11878SVenu.Iyer@Sun.COM aggr_port_stat_entry = i_dlstat_single_port_stats(dpa.dp_dev, 2709*11878SVenu.Iyer@Sun.COM portp->lp_linkid); 2710*11878SVenu.Iyer@Sun.COM 2711*11878SVenu.Iyer@Sun.COM /* Create dladm_stat_chain_t object for this stat */ 2712*11878SVenu.Iyer@Sun.COM curr = malloc(sizeof (dladm_stat_chain_t)); 2713*11878SVenu.Iyer@Sun.COM if (curr == NULL) { 2714*11878SVenu.Iyer@Sun.COM free(aggr_port_stat_entry); 2715*11878SVenu.Iyer@Sun.COM goto done; 2716*11878SVenu.Iyer@Sun.COM } 2717*11878SVenu.Iyer@Sun.COM (void) strlcpy(curr->dc_statheader, dpa.dp_dev, 2718*11878SVenu.Iyer@Sun.COM sizeof (curr->dc_statheader)); 2719*11878SVenu.Iyer@Sun.COM curr->dc_statentry = aggr_port_stat_entry; 2720*11878SVenu.Iyer@Sun.COM curr->dc_next = NULL; 2721*11878SVenu.Iyer@Sun.COM 2722*11878SVenu.Iyer@Sun.COM /* Chain this aggr port stat entry */ 2723*11878SVenu.Iyer@Sun.COM /* head of the stat list */ 2724*11878SVenu.Iyer@Sun.COM if (prev == NULL) 2725*11878SVenu.Iyer@Sun.COM head = curr; 2726*11878SVenu.Iyer@Sun.COM else 2727*11878SVenu.Iyer@Sun.COM prev->dc_next = curr; 2728*11878SVenu.Iyer@Sun.COM prev = curr; 2729*11878SVenu.Iyer@Sun.COM } 2730*11878SVenu.Iyer@Sun.COM 2731*11878SVenu.Iyer@Sun.COM /* 2732*11878SVenu.Iyer@Sun.COM * Prepend the stat list with cumulative aggr stats i.e. summed over all 2733*11878SVenu.Iyer@Sun.COM * component ports 2734*11878SVenu.Iyer@Sun.COM */ 2735*11878SVenu.Iyer@Sun.COM total_stats = dlstat_aggr_total_stats(head); 2736*11878SVenu.Iyer@Sun.COM if (total_stats != NULL) { 2737*11878SVenu.Iyer@Sun.COM total_stats->dc_next = head; 2738*11878SVenu.Iyer@Sun.COM head = total_stats; 2739*11878SVenu.Iyer@Sun.COM } 2740*11878SVenu.Iyer@Sun.COM 2741*11878SVenu.Iyer@Sun.COM done: 2742*11878SVenu.Iyer@Sun.COM free(ginfo.lg_ports); 2743*11878SVenu.Iyer@Sun.COM return (head); 2744*11878SVenu.Iyer@Sun.COM } 2745*11878SVenu.Iyer@Sun.COM 2746*11878SVenu.Iyer@Sun.COM /* Misc stat specific functions */ 2747*11878SVenu.Iyer@Sun.COM void * 2748*11878SVenu.Iyer@Sun.COM dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid) 2749*11878SVenu.Iyer@Sun.COM { 2750*11878SVenu.Iyer@Sun.COM misc_stat_entry_t *misc_stat_entry; 2751*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *head = NULL; 2752*11878SVenu.Iyer@Sun.COM char linkname[MAXLINKNAMELEN]; 2753*11878SVenu.Iyer@Sun.COM 2754*11878SVenu.Iyer@Sun.COM if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 2755*11878SVenu.Iyer@Sun.COM DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 2756*11878SVenu.Iyer@Sun.COM goto done; 2757*11878SVenu.Iyer@Sun.COM } 2758*11878SVenu.Iyer@Sun.COM 2759*11878SVenu.Iyer@Sun.COM misc_stat_entry = i_dlstat_misc_stats(linkname); 2760*11878SVenu.Iyer@Sun.COM if (misc_stat_entry == NULL) 2761*11878SVenu.Iyer@Sun.COM goto done; 2762*11878SVenu.Iyer@Sun.COM 2763*11878SVenu.Iyer@Sun.COM head = malloc(sizeof (dladm_stat_chain_t)); 2764*11878SVenu.Iyer@Sun.COM if (head == NULL) { 2765*11878SVenu.Iyer@Sun.COM free(misc_stat_entry); 2766*11878SVenu.Iyer@Sun.COM goto done; 2767*11878SVenu.Iyer@Sun.COM } 2768*11878SVenu.Iyer@Sun.COM 2769*11878SVenu.Iyer@Sun.COM head->dc_statentry = misc_stat_entry; 2770*11878SVenu.Iyer@Sun.COM (void) strlcpy(head->dc_statheader, "mac_misc_stat", 2771*11878SVenu.Iyer@Sun.COM sizeof (head->dc_statheader)); 2772*11878SVenu.Iyer@Sun.COM head->dc_next = NULL; 2773*11878SVenu.Iyer@Sun.COM 2774*11878SVenu.Iyer@Sun.COM done: 2775*11878SVenu.Iyer@Sun.COM return (head); 2776*11878SVenu.Iyer@Sun.COM } 2777*11878SVenu.Iyer@Sun.COM 2778*11878SVenu.Iyer@Sun.COM /* Exported functions */ 2779*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t * 2780*11878SVenu.Iyer@Sun.COM dladm_link_stat_query(dladm_handle_t dh, datalink_id_t linkid, 2781*11878SVenu.Iyer@Sun.COM dladm_stat_type_t stattype) 2782*11878SVenu.Iyer@Sun.COM { 2783*11878SVenu.Iyer@Sun.COM return (dladm_stat_table[stattype].ds_querystat(dh, linkid)); 2784*11878SVenu.Iyer@Sun.COM } 2785*11878SVenu.Iyer@Sun.COM 2786*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t * 2787*11878SVenu.Iyer@Sun.COM dladm_link_stat_diffchain(dladm_stat_chain_t *op1, dladm_stat_chain_t *op2, 2788*11878SVenu.Iyer@Sun.COM dladm_stat_type_t stattype) 2789*11878SVenu.Iyer@Sun.COM { 2790*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *op1_curr, *op2_curr; 2791*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *diff_curr; 2792*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *diff_prev = NULL, *diff_head = NULL; 2793*11878SVenu.Iyer@Sun.COM 2794*11878SVenu.Iyer@Sun.COM /* Perform op1 - op2, store result in diff */ 2795*11878SVenu.Iyer@Sun.COM for (op1_curr = op1; op1_curr != NULL; op1_curr = op1_curr->dc_next) { 2796*11878SVenu.Iyer@Sun.COM for (op2_curr = op2; op2_curr != NULL; 2797*11878SVenu.Iyer@Sun.COM op2_curr = op2_curr->dc_next) { 2798*11878SVenu.Iyer@Sun.COM if (dlstat_match_stats(op1_curr->dc_statentry, 2799*11878SVenu.Iyer@Sun.COM op2_curr->dc_statentry, stattype)) { 2800*11878SVenu.Iyer@Sun.COM break; 2801*11878SVenu.Iyer@Sun.COM } 2802*11878SVenu.Iyer@Sun.COM } 2803*11878SVenu.Iyer@Sun.COM diff_curr = malloc(sizeof (dladm_stat_chain_t)); 2804*11878SVenu.Iyer@Sun.COM if (diff_curr == NULL) 2805*11878SVenu.Iyer@Sun.COM goto done; 2806*11878SVenu.Iyer@Sun.COM 2807*11878SVenu.Iyer@Sun.COM diff_curr->dc_next = NULL; 2808*11878SVenu.Iyer@Sun.COM 2809*11878SVenu.Iyer@Sun.COM if (op2_curr == NULL) { 2810*11878SVenu.Iyer@Sun.COM /* prev iteration did not have this stat entry */ 2811*11878SVenu.Iyer@Sun.COM diff_curr->dc_statentry = 2812*11878SVenu.Iyer@Sun.COM dlstat_diff_stats(op1_curr->dc_statentry, 2813*11878SVenu.Iyer@Sun.COM NULL, stattype); 2814*11878SVenu.Iyer@Sun.COM } else { 2815*11878SVenu.Iyer@Sun.COM diff_curr->dc_statentry = 2816*11878SVenu.Iyer@Sun.COM dlstat_diff_stats(op1_curr->dc_statentry, 2817*11878SVenu.Iyer@Sun.COM op2_curr->dc_statentry, stattype); 2818*11878SVenu.Iyer@Sun.COM } 2819*11878SVenu.Iyer@Sun.COM 2820*11878SVenu.Iyer@Sun.COM if (diff_curr->dc_statentry == NULL) { 2821*11878SVenu.Iyer@Sun.COM free(diff_curr); 2822*11878SVenu.Iyer@Sun.COM goto done; 2823*11878SVenu.Iyer@Sun.COM } 2824*11878SVenu.Iyer@Sun.COM 2825*11878SVenu.Iyer@Sun.COM if (diff_prev == NULL) /* head of the diff stat list */ 2826*11878SVenu.Iyer@Sun.COM diff_head = diff_curr; 2827*11878SVenu.Iyer@Sun.COM else 2828*11878SVenu.Iyer@Sun.COM diff_prev->dc_next = diff_curr; 2829*11878SVenu.Iyer@Sun.COM diff_prev = diff_curr; 2830*11878SVenu.Iyer@Sun.COM } 2831*11878SVenu.Iyer@Sun.COM done: 2832*11878SVenu.Iyer@Sun.COM return (diff_head); 2833*11878SVenu.Iyer@Sun.COM } 2834*11878SVenu.Iyer@Sun.COM 2835*11878SVenu.Iyer@Sun.COM void 2836*11878SVenu.Iyer@Sun.COM dladm_link_stat_free(dladm_stat_chain_t *curr) 2837*11878SVenu.Iyer@Sun.COM { 2838*11878SVenu.Iyer@Sun.COM while (curr != NULL) { 2839*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *tofree = curr; 2840*11878SVenu.Iyer@Sun.COM 2841*11878SVenu.Iyer@Sun.COM curr = curr->dc_next; 2842*11878SVenu.Iyer@Sun.COM free(tofree->dc_statentry); 2843*11878SVenu.Iyer@Sun.COM free(tofree); 2844*11878SVenu.Iyer@Sun.COM } 2845*11878SVenu.Iyer@Sun.COM } 2846*11878SVenu.Iyer@Sun.COM 2847*11878SVenu.Iyer@Sun.COM /* Query all link stats */ 2848*11878SVenu.Iyer@Sun.COM static name_value_stat_t * 2849*11878SVenu.Iyer@Sun.COM i_dlstat_convert_stats(void *stats, stat_info_t stats_list[], uint_t size) 2850*11878SVenu.Iyer@Sun.COM { 2851*11878SVenu.Iyer@Sun.COM int i; 2852*11878SVenu.Iyer@Sun.COM name_value_stat_t *head_stat = NULL, *prev_stat = NULL; 2853*11878SVenu.Iyer@Sun.COM name_value_stat_t *curr_stat; 2854*11878SVenu.Iyer@Sun.COM 2855*11878SVenu.Iyer@Sun.COM for (i = 0; i < size; i++) { 2856*11878SVenu.Iyer@Sun.COM uint64_t *val = (void *) 2857*11878SVenu.Iyer@Sun.COM ((uchar_t *)stats + stats_list[i].si_offset); 2858*11878SVenu.Iyer@Sun.COM 2859*11878SVenu.Iyer@Sun.COM curr_stat = calloc(1, sizeof (name_value_stat_t)); 2860*11878SVenu.Iyer@Sun.COM if (curr_stat == NULL) 2861*11878SVenu.Iyer@Sun.COM break; 2862*11878SVenu.Iyer@Sun.COM 2863*11878SVenu.Iyer@Sun.COM (void) strlcpy(curr_stat->nv_statname, stats_list[i].si_name, 2864*11878SVenu.Iyer@Sun.COM sizeof (curr_stat->nv_statname)); 2865*11878SVenu.Iyer@Sun.COM curr_stat->nv_statval = *val; 2866*11878SVenu.Iyer@Sun.COM curr_stat->nv_nextstat = NULL; 2867*11878SVenu.Iyer@Sun.COM 2868*11878SVenu.Iyer@Sun.COM if (head_stat == NULL) /* First node */ 2869*11878SVenu.Iyer@Sun.COM head_stat = curr_stat; 2870*11878SVenu.Iyer@Sun.COM else 2871*11878SVenu.Iyer@Sun.COM prev_stat->nv_nextstat = curr_stat; 2872*11878SVenu.Iyer@Sun.COM 2873*11878SVenu.Iyer@Sun.COM prev_stat = curr_stat; 2874*11878SVenu.Iyer@Sun.COM } 2875*11878SVenu.Iyer@Sun.COM return (head_stat); 2876*11878SVenu.Iyer@Sun.COM } 2877*11878SVenu.Iyer@Sun.COM 2878*11878SVenu.Iyer@Sun.COM void * 2879*11878SVenu.Iyer@Sun.COM build_nvs_entry(char *statheader, void *statentry, dladm_stat_type_t stattype) 2880*11878SVenu.Iyer@Sun.COM { 2881*11878SVenu.Iyer@Sun.COM name_value_stat_entry_t *name_value_stat_entry; 2882*11878SVenu.Iyer@Sun.COM dladm_stat_desc_t *stattbl_ptr; 2883*11878SVenu.Iyer@Sun.COM void *statfields; 2884*11878SVenu.Iyer@Sun.COM 2885*11878SVenu.Iyer@Sun.COM stattbl_ptr = &dladm_stat_table[stattype]; 2886*11878SVenu.Iyer@Sun.COM 2887*11878SVenu.Iyer@Sun.COM /* Allocate memory for query all stat entry */ 2888*11878SVenu.Iyer@Sun.COM name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t)); 2889*11878SVenu.Iyer@Sun.COM if (name_value_stat_entry == NULL) 2890*11878SVenu.Iyer@Sun.COM goto done; 2891*11878SVenu.Iyer@Sun.COM 2892*11878SVenu.Iyer@Sun.COM /* Header for these stat fields */ 2893*11878SVenu.Iyer@Sun.COM (void) strlcpy(name_value_stat_entry->nve_header, statheader, 2894*11878SVenu.Iyer@Sun.COM sizeof (name_value_stat_entry->nve_header)); 2895*11878SVenu.Iyer@Sun.COM 2896*11878SVenu.Iyer@Sun.COM /* Extract stat fields from the statentry */ 2897*11878SVenu.Iyer@Sun.COM statfields = (uchar_t *)statentry + 2898*11878SVenu.Iyer@Sun.COM dladm_stat_table[stattype].ds_offset; 2899*11878SVenu.Iyer@Sun.COM 2900*11878SVenu.Iyer@Sun.COM /* Convert curr_stat to <statname, statval> pair */ 2901*11878SVenu.Iyer@Sun.COM name_value_stat_entry->nve_stats = 2902*11878SVenu.Iyer@Sun.COM i_dlstat_convert_stats(statfields, 2903*11878SVenu.Iyer@Sun.COM stattbl_ptr->ds_statlist, stattbl_ptr->ds_statsize); 2904*11878SVenu.Iyer@Sun.COM done: 2905*11878SVenu.Iyer@Sun.COM return (name_value_stat_entry); 2906*11878SVenu.Iyer@Sun.COM } 2907*11878SVenu.Iyer@Sun.COM 2908*11878SVenu.Iyer@Sun.COM void * 2909*11878SVenu.Iyer@Sun.COM i_walk_dlstat_chain(dladm_stat_chain_t *stat_head, dladm_stat_type_t stattype) 2910*11878SVenu.Iyer@Sun.COM { 2911*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *curr; 2912*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *nvstat_head = NULL, *nvstat_prev = NULL; 2913*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *nvstat_curr; 2914*11878SVenu.Iyer@Sun.COM 2915*11878SVenu.Iyer@Sun.COM /* 2916*11878SVenu.Iyer@Sun.COM * For every stat in the chain, build header and convert all 2917*11878SVenu.Iyer@Sun.COM * its stat fields 2918*11878SVenu.Iyer@Sun.COM */ 2919*11878SVenu.Iyer@Sun.COM for (curr = stat_head; curr != NULL; curr = curr->dc_next) { 2920*11878SVenu.Iyer@Sun.COM nvstat_curr = malloc(sizeof (dladm_stat_chain_t)); 2921*11878SVenu.Iyer@Sun.COM if (nvstat_curr == NULL) 2922*11878SVenu.Iyer@Sun.COM break; 2923*11878SVenu.Iyer@Sun.COM 2924*11878SVenu.Iyer@Sun.COM nvstat_curr->dc_statentry = build_nvs_entry(curr->dc_statheader, 2925*11878SVenu.Iyer@Sun.COM curr->dc_statentry, stattype); 2926*11878SVenu.Iyer@Sun.COM 2927*11878SVenu.Iyer@Sun.COM if (nvstat_curr->dc_statentry == NULL) { 2928*11878SVenu.Iyer@Sun.COM free(nvstat_curr); 2929*11878SVenu.Iyer@Sun.COM break; 2930*11878SVenu.Iyer@Sun.COM } 2931*11878SVenu.Iyer@Sun.COM 2932*11878SVenu.Iyer@Sun.COM nvstat_curr->dc_next = NULL; 2933*11878SVenu.Iyer@Sun.COM 2934*11878SVenu.Iyer@Sun.COM if (nvstat_head == NULL) /* First node */ 2935*11878SVenu.Iyer@Sun.COM nvstat_head = nvstat_curr; 2936*11878SVenu.Iyer@Sun.COM else 2937*11878SVenu.Iyer@Sun.COM nvstat_prev->dc_next = nvstat_curr; 2938*11878SVenu.Iyer@Sun.COM 2939*11878SVenu.Iyer@Sun.COM nvstat_prev = nvstat_curr; 2940*11878SVenu.Iyer@Sun.COM } 2941*11878SVenu.Iyer@Sun.COM done: 2942*11878SVenu.Iyer@Sun.COM return (nvstat_head); 2943*11878SVenu.Iyer@Sun.COM } 2944*11878SVenu.Iyer@Sun.COM 2945*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t * 2946*11878SVenu.Iyer@Sun.COM dladm_link_stat_query_all(dladm_handle_t dh, datalink_id_t linkid, 2947*11878SVenu.Iyer@Sun.COM dladm_stat_type_t stattype) 2948*11878SVenu.Iyer@Sun.COM { 2949*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *stat_head; 2950*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *nvstat_head = NULL; 2951*11878SVenu.Iyer@Sun.COM 2952*11878SVenu.Iyer@Sun.COM /* Query the requested stat */ 2953*11878SVenu.Iyer@Sun.COM stat_head = dladm_link_stat_query(dh, linkid, stattype); 2954*11878SVenu.Iyer@Sun.COM if (stat_head == NULL) 2955*11878SVenu.Iyer@Sun.COM goto done; 2956*11878SVenu.Iyer@Sun.COM 2957*11878SVenu.Iyer@Sun.COM /* 2958*11878SVenu.Iyer@Sun.COM * Convert every statfield in every stat-entry of stat chain to 2959*11878SVenu.Iyer@Sun.COM * <statname, statval> pair 2960*11878SVenu.Iyer@Sun.COM */ 2961*11878SVenu.Iyer@Sun.COM nvstat_head = i_walk_dlstat_chain(stat_head, stattype); 2962*11878SVenu.Iyer@Sun.COM 2963*11878SVenu.Iyer@Sun.COM /* Free stat_head */ 2964*11878SVenu.Iyer@Sun.COM dladm_link_stat_free(stat_head); 2965*11878SVenu.Iyer@Sun.COM 2966*11878SVenu.Iyer@Sun.COM done: 2967*11878SVenu.Iyer@Sun.COM return (nvstat_head); 2968*11878SVenu.Iyer@Sun.COM } 2969*11878SVenu.Iyer@Sun.COM 2970*11878SVenu.Iyer@Sun.COM void 2971*11878SVenu.Iyer@Sun.COM dladm_link_stat_query_all_free(dladm_stat_chain_t *curr) 2972*11878SVenu.Iyer@Sun.COM { 2973*11878SVenu.Iyer@Sun.COM while (curr != NULL) { 2974*11878SVenu.Iyer@Sun.COM dladm_stat_chain_t *tofree = curr; 2975*11878SVenu.Iyer@Sun.COM name_value_stat_entry_t *nv_entry = curr->dc_statentry; 2976*11878SVenu.Iyer@Sun.COM name_value_stat_t *nv_curr = nv_entry->nve_stats; 2977*11878SVenu.Iyer@Sun.COM 2978*11878SVenu.Iyer@Sun.COM while (nv_curr != NULL) { 2979*11878SVenu.Iyer@Sun.COM name_value_stat_t *nv_tofree = nv_curr; 2980*11878SVenu.Iyer@Sun.COM 2981*11878SVenu.Iyer@Sun.COM nv_curr = nv_curr->nv_nextstat; 2982*11878SVenu.Iyer@Sun.COM free(nv_tofree); 2983*11878SVenu.Iyer@Sun.COM } 2984*11878SVenu.Iyer@Sun.COM 2985*11878SVenu.Iyer@Sun.COM curr = curr->dc_next; 2986*11878SVenu.Iyer@Sun.COM free(nv_entry); 2987*11878SVenu.Iyer@Sun.COM free(tofree); 2988*11878SVenu.Iyer@Sun.COM } 2989*11878SVenu.Iyer@Sun.COM } 2990*11878SVenu.Iyer@Sun.COM 2991*11878SVenu.Iyer@Sun.COM /* flow stats specific routines */ 2992*11878SVenu.Iyer@Sun.COM flow_stat_t * 2993*11878SVenu.Iyer@Sun.COM dladm_flow_stat_query(const char *flowname) 2994*11878SVenu.Iyer@Sun.COM { 2995*11878SVenu.Iyer@Sun.COM kstat_ctl_t *kcp; 2996*11878SVenu.Iyer@Sun.COM kstat_t *ksp; 2997*11878SVenu.Iyer@Sun.COM flow_stat_t *flow_stat = NULL; 2998*11878SVenu.Iyer@Sun.COM 2999*11878SVenu.Iyer@Sun.COM if ((kcp = kstat_open()) == NULL) 3000*11878SVenu.Iyer@Sun.COM return (NULL); 3001*11878SVenu.Iyer@Sun.COM 3002*11878SVenu.Iyer@Sun.COM flow_stat = calloc(1, sizeof (flow_stat_t)); 3003*11878SVenu.Iyer@Sun.COM if (flow_stat == NULL) 3004*11878SVenu.Iyer@Sun.COM goto done; 3005*11878SVenu.Iyer@Sun.COM 3006*11878SVenu.Iyer@Sun.COM ksp = dladm_kstat_lookup(kcp, NULL, -1, flowname, "flow"); 3007*11878SVenu.Iyer@Sun.COM 3008*11878SVenu.Iyer@Sun.COM if (ksp != NULL) { 3009*11878SVenu.Iyer@Sun.COM i_dlstat_get_stats(kcp, ksp, flow_stat, flow_stats_list, 3010*11878SVenu.Iyer@Sun.COM FLOW_STAT_SIZE); 3011*11878SVenu.Iyer@Sun.COM } 3012*11878SVenu.Iyer@Sun.COM 3013*11878SVenu.Iyer@Sun.COM done: 3014*11878SVenu.Iyer@Sun.COM (void) kstat_close(kcp); 3015*11878SVenu.Iyer@Sun.COM return (flow_stat); 3016*11878SVenu.Iyer@Sun.COM } 3017*11878SVenu.Iyer@Sun.COM 3018*11878SVenu.Iyer@Sun.COM flow_stat_t * 3019*11878SVenu.Iyer@Sun.COM dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2) 3020*11878SVenu.Iyer@Sun.COM { 3021*11878SVenu.Iyer@Sun.COM flow_stat_t *diff_stat; 3022*11878SVenu.Iyer@Sun.COM 3023*11878SVenu.Iyer@Sun.COM diff_stat = calloc(1, sizeof (flow_stat_t)); 3024*11878SVenu.Iyer@Sun.COM if (diff_stat == NULL) 3025*11878SVenu.Iyer@Sun.COM goto done; 3026*11878SVenu.Iyer@Sun.COM 3027*11878SVenu.Iyer@Sun.COM if (op2 == NULL) { 3028*11878SVenu.Iyer@Sun.COM bcopy(op1, diff_stat, sizeof (flow_stat_t)); 3029*11878SVenu.Iyer@Sun.COM } else { 3030*11878SVenu.Iyer@Sun.COM i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list, 3031*11878SVenu.Iyer@Sun.COM FLOW_STAT_SIZE); 3032*11878SVenu.Iyer@Sun.COM } 3033*11878SVenu.Iyer@Sun.COM done: 3034*11878SVenu.Iyer@Sun.COM return (diff_stat); 3035*11878SVenu.Iyer@Sun.COM } 3036*11878SVenu.Iyer@Sun.COM 3037*11878SVenu.Iyer@Sun.COM void 3038*11878SVenu.Iyer@Sun.COM dladm_flow_stat_free(flow_stat_t *curr) 3039*11878SVenu.Iyer@Sun.COM { 3040*11878SVenu.Iyer@Sun.COM free(curr); 3041*11878SVenu.Iyer@Sun.COM } 3042*11878SVenu.Iyer@Sun.COM 3043*11878SVenu.Iyer@Sun.COM /* Query all flow stats */ 3044*11878SVenu.Iyer@Sun.COM name_value_stat_entry_t * 3045*11878SVenu.Iyer@Sun.COM dladm_flow_stat_query_all(const char *flowname) 3046*11878SVenu.Iyer@Sun.COM { 3047*11878SVenu.Iyer@Sun.COM flow_stat_t *flow_stat; 3048*11878SVenu.Iyer@Sun.COM name_value_stat_entry_t *name_value_stat_entry = NULL; 3049*11878SVenu.Iyer@Sun.COM 3050*11878SVenu.Iyer@Sun.COM /* Query flow stats */ 3051*11878SVenu.Iyer@Sun.COM flow_stat = dladm_flow_stat_query(flowname); 3052*11878SVenu.Iyer@Sun.COM if (flow_stat == NULL) 3053*11878SVenu.Iyer@Sun.COM goto done; 3054*11878SVenu.Iyer@Sun.COM 3055*11878SVenu.Iyer@Sun.COM /* Allocate memory for query all stat entry */ 3056*11878SVenu.Iyer@Sun.COM name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t)); 3057*11878SVenu.Iyer@Sun.COM if (name_value_stat_entry == NULL) { 3058*11878SVenu.Iyer@Sun.COM dladm_flow_stat_free(flow_stat); 3059*11878SVenu.Iyer@Sun.COM goto done; 3060*11878SVenu.Iyer@Sun.COM } 3061*11878SVenu.Iyer@Sun.COM 3062*11878SVenu.Iyer@Sun.COM /* Header for these stat fields */ 3063*11878SVenu.Iyer@Sun.COM (void) strncpy(name_value_stat_entry->nve_header, flowname, 3064*11878SVenu.Iyer@Sun.COM MAXFLOWNAMELEN); 3065*11878SVenu.Iyer@Sun.COM 3066*11878SVenu.Iyer@Sun.COM /* Convert every statfield in flow_stat to <statname, statval> pair */ 3067*11878SVenu.Iyer@Sun.COM name_value_stat_entry->nve_stats = 3068*11878SVenu.Iyer@Sun.COM i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE); 3069*11878SVenu.Iyer@Sun.COM 3070*11878SVenu.Iyer@Sun.COM /* Free flow_stat */ 3071*11878SVenu.Iyer@Sun.COM dladm_flow_stat_free(flow_stat); 3072*11878SVenu.Iyer@Sun.COM 3073*11878SVenu.Iyer@Sun.COM done: 3074*11878SVenu.Iyer@Sun.COM return (name_value_stat_entry); 3075*11878SVenu.Iyer@Sun.COM } 3076*11878SVenu.Iyer@Sun.COM 3077*11878SVenu.Iyer@Sun.COM void 3078*11878SVenu.Iyer@Sun.COM dladm_flow_stat_query_all_free(name_value_stat_entry_t *curr) 3079*11878SVenu.Iyer@Sun.COM { 3080*11878SVenu.Iyer@Sun.COM name_value_stat_t *nv_curr = curr->nve_stats; 3081*11878SVenu.Iyer@Sun.COM 3082*11878SVenu.Iyer@Sun.COM while (nv_curr != NULL) { 3083*11878SVenu.Iyer@Sun.COM name_value_stat_t *nv_tofree = nv_curr; 3084*11878SVenu.Iyer@Sun.COM 3085*11878SVenu.Iyer@Sun.COM nv_curr = nv_curr->nv_nextstat; 3086*11878SVenu.Iyer@Sun.COM free(nv_tofree); 3087*11878SVenu.Iyer@Sun.COM } 3088*11878SVenu.Iyer@Sun.COM } 3089