1da14cebeSEric Cheng /* 2da14cebeSEric Cheng * CDDL HEADER START 3da14cebeSEric Cheng * 4da14cebeSEric Cheng * The contents of this file are subject to the terms of the 5da14cebeSEric Cheng * Common Development and Distribution License (the "License"). 6da14cebeSEric Cheng * You may not use this file except in compliance with the License. 7da14cebeSEric Cheng * 8da14cebeSEric Cheng * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da14cebeSEric Cheng * or http://www.opensolaris.org/os/licensing. 10da14cebeSEric Cheng * See the License for the specific language governing permissions 11da14cebeSEric Cheng * and limitations under the License. 12da14cebeSEric Cheng * 13da14cebeSEric Cheng * When distributing Covered Code, include this CDDL HEADER in each 14da14cebeSEric Cheng * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da14cebeSEric Cheng * If applicable, add the following below this CDDL HEADER, with the 16da14cebeSEric Cheng * fields enclosed by brackets "[]" replaced with your own identifying 17da14cebeSEric Cheng * information: Portions Copyright [yyyy] [name of copyright owner] 18da14cebeSEric Cheng * 19da14cebeSEric Cheng * CDDL HEADER END 20da14cebeSEric Cheng */ 21da14cebeSEric Cheng /* 220dc2366fSVenugopal Iyer * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23da14cebeSEric Cheng * Use is subject to license terms. 24da14cebeSEric Cheng */ 25da14cebeSEric Cheng 26*62ef8476SYuri Pankov #include <stddef.h> 27da14cebeSEric Cheng #include <stdio.h> 28da14cebeSEric Cheng #include <stdlib.h> 29da14cebeSEric Cheng #include <strings.h> 30da14cebeSEric Cheng #include <err.h> 31da14cebeSEric Cheng #include <errno.h> 32c3affd82SMichael Lim #include <fcntl.h> 33da14cebeSEric Cheng #include <kstat.h> 34c3affd82SMichael Lim #include <limits.h> 35da14cebeSEric Cheng #include <unistd.h> 36da14cebeSEric Cheng #include <signal.h> 37da14cebeSEric Cheng #include <sys/dld.h> 3882a2fc47SJames Carlson #include <sys/ddi.h> 39da14cebeSEric Cheng 40da14cebeSEric Cheng #include <libdllink.h> 41da14cebeSEric Cheng #include <libdlflow.h> 42da14cebeSEric Cheng #include <libdlstat.h> 430dc2366fSVenugopal Iyer #include <libdlaggr.h> 44da14cebeSEric Cheng 45da14cebeSEric Cheng struct flowlist { 46da000602SGirish Moodalbail char flowname[MAXFLOWNAMELEN]; 47c3affd82SMichael Lim char linkname[MAXLINKNAMELEN]; 48da14cebeSEric Cheng datalink_id_t linkid; 49c3affd82SMichael Lim int fd; 50285e94f9SMichael Lim uint64_t ifspeed; 51da14cebeSEric Cheng boolean_t first; 52da14cebeSEric Cheng boolean_t display; 53da14cebeSEric Cheng pktsum_t prevstats; 54da14cebeSEric Cheng pktsum_t diffstats; 55da14cebeSEric Cheng }; 56da14cebeSEric Cheng 57da14cebeSEric Cheng pktsum_t totalstats; 58da14cebeSEric Cheng struct flowlist *stattable = NULL; 59da14cebeSEric Cheng 60da14cebeSEric Cheng #define STATGROWSIZE 16 61da14cebeSEric Cheng 62da14cebeSEric Cheng /* Exported functions */ 63da14cebeSEric Cheng 64da14cebeSEric Cheng /* 65da14cebeSEric Cheng * dladm_kstat_lookup() is a modified version of kstat_lookup which 66da14cebeSEric Cheng * adds the class as a selector. 67da14cebeSEric Cheng */ 68da14cebeSEric Cheng kstat_t * 69da14cebeSEric Cheng dladm_kstat_lookup(kstat_ctl_t *kcp, const char *module, int instance, 70da14cebeSEric Cheng const char *name, const char *class) 71da14cebeSEric Cheng { 72da14cebeSEric Cheng kstat_t *ksp = NULL; 73da14cebeSEric Cheng 74da14cebeSEric Cheng for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 75da14cebeSEric Cheng if ((module == NULL || strcmp(ksp->ks_module, module) == 0) && 76da14cebeSEric Cheng (instance == -1 || ksp->ks_instance == instance) && 77da14cebeSEric Cheng (name == NULL || strcmp(ksp->ks_name, name) == 0) && 78da14cebeSEric Cheng (class == NULL || strcmp(ksp->ks_class, class) == 0)) 79da14cebeSEric Cheng return (ksp); 80da14cebeSEric Cheng } 81da14cebeSEric Cheng 82da14cebeSEric Cheng errno = ENOENT; 83da14cebeSEric Cheng return (NULL); 84da14cebeSEric Cheng } 85da14cebeSEric Cheng 86da14cebeSEric Cheng /* 87da14cebeSEric Cheng * dladm_get_stats() populates the supplied pktsum_t structure with 88da14cebeSEric Cheng * the input and output packet and byte kstats from the kstat_t 89da14cebeSEric Cheng * found with dladm_kstat_lookup. 90da14cebeSEric Cheng */ 91da14cebeSEric Cheng void 92da14cebeSEric Cheng dladm_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, pktsum_t *stats) 93da14cebeSEric Cheng { 94da14cebeSEric Cheng 95da14cebeSEric Cheng if (kstat_read(kcp, ksp, NULL) == -1) 96da14cebeSEric Cheng return; 97da14cebeSEric Cheng 98da14cebeSEric Cheng stats->snaptime = gethrtime(); 99da14cebeSEric Cheng 100da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64, 101da14cebeSEric Cheng &stats->ipackets) < 0) { 102da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ipackets", KSTAT_DATA_UINT64, 103da14cebeSEric Cheng &stats->ipackets) < 0) 104da14cebeSEric Cheng return; 105da14cebeSEric Cheng } 106da14cebeSEric Cheng 107da14cebeSEric Cheng if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64, 108da14cebeSEric Cheng &stats->opackets) < 0) { 109da14cebeSEric Cheng if (dladm_kstat_value(ksp, "opackets", KSTAT_DATA_UINT64, 110da14cebeSEric Cheng &stats->opackets) < 0) 111da14cebeSEric Cheng return; 112da14cebeSEric Cheng } 113da14cebeSEric Cheng 114da14cebeSEric Cheng if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64, 115da14cebeSEric Cheng &stats->rbytes) < 0) { 116da14cebeSEric Cheng if (dladm_kstat_value(ksp, "rbytes", KSTAT_DATA_UINT64, 117da14cebeSEric Cheng &stats->rbytes) < 0) 118da14cebeSEric Cheng return; 119da14cebeSEric Cheng } 120da14cebeSEric Cheng 121da14cebeSEric Cheng if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64, 122da14cebeSEric Cheng &stats->obytes) < 0) { 123da14cebeSEric Cheng if (dladm_kstat_value(ksp, "obytes", KSTAT_DATA_UINT64, 124da14cebeSEric Cheng &stats->obytes) < 0) 125da14cebeSEric Cheng return; 126da14cebeSEric Cheng } 127da14cebeSEric Cheng 128da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32, 129da14cebeSEric Cheng &stats->ierrors) < 0) { 130da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT64, 131da14cebeSEric Cheng &stats->ierrors) < 0) 132da14cebeSEric Cheng return; 133da14cebeSEric Cheng } 134da14cebeSEric Cheng 135da14cebeSEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32, 136da14cebeSEric Cheng &stats->oerrors) < 0) { 137da14cebeSEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT64, 138da14cebeSEric Cheng &stats->oerrors) < 0) 139da14cebeSEric Cheng return; 140da14cebeSEric Cheng } 141da14cebeSEric Cheng } 142da14cebeSEric Cheng 143da14cebeSEric Cheng int 144da14cebeSEric Cheng dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf) 145da14cebeSEric Cheng { 146da14cebeSEric Cheng kstat_named_t *knp; 147da14cebeSEric Cheng 148da14cebeSEric Cheng if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL) 149da14cebeSEric Cheng return (-1); 150da14cebeSEric Cheng 151da14cebeSEric Cheng if (knp->data_type != type) 152da14cebeSEric Cheng return (-1); 153da14cebeSEric Cheng 154da14cebeSEric Cheng switch (type) { 155da14cebeSEric Cheng case KSTAT_DATA_UINT64: 156da14cebeSEric Cheng *(uint64_t *)buf = knp->value.ui64; 157da14cebeSEric Cheng break; 158da14cebeSEric Cheng case KSTAT_DATA_UINT32: 159da14cebeSEric Cheng *(uint32_t *)buf = knp->value.ui32; 160da14cebeSEric Cheng break; 161da14cebeSEric Cheng default: 162da14cebeSEric Cheng return (-1); 163da14cebeSEric Cheng } 164da14cebeSEric Cheng 165da14cebeSEric Cheng return (0); 166da14cebeSEric Cheng } 167da14cebeSEric Cheng 168da14cebeSEric Cheng dladm_status_t 1694ac67f02SAnurag S. Maskey dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid, 1704ac67f02SAnurag S. Maskey const char *name, uint8_t type, void *val) 171da14cebeSEric Cheng { 172da14cebeSEric Cheng kstat_ctl_t *kcp; 173da14cebeSEric Cheng char module[DLPI_LINKNAME_MAX]; 174da14cebeSEric Cheng uint_t instance; 175da14cebeSEric Cheng char link[DLPI_LINKNAME_MAX]; 176da14cebeSEric Cheng dladm_status_t status; 177da14cebeSEric Cheng uint32_t flags, media; 178da14cebeSEric Cheng kstat_t *ksp; 179da14cebeSEric Cheng dladm_phys_attr_t dpap; 180da14cebeSEric Cheng 1814ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL, 1824ac67f02SAnurag S. Maskey &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK) 183da14cebeSEric Cheng return (status); 184da14cebeSEric Cheng 185da14cebeSEric Cheng if (media != DL_ETHER) 186da14cebeSEric Cheng return (DLADM_STATUS_LINKINVAL); 187da14cebeSEric Cheng 1884ac67f02SAnurag S. Maskey status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST); 189da14cebeSEric Cheng 190da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 191da14cebeSEric Cheng return (status); 192da14cebeSEric Cheng 193da14cebeSEric Cheng status = dladm_parselink(dpap.dp_dev, module, &instance); 194da14cebeSEric Cheng 195da14cebeSEric Cheng if (status != DLADM_STATUS_OK) 196da14cebeSEric Cheng return (status); 197da14cebeSEric Cheng 1983efde6d0SSowmini Varadhan if ((kcp = kstat_open()) == NULL) { 1993efde6d0SSowmini Varadhan warn("kstat_open operation failed"); 2003efde6d0SSowmini Varadhan return (-1); 2013efde6d0SSowmini Varadhan } 2023efde6d0SSowmini Varadhan 203da14cebeSEric Cheng /* 204da14cebeSEric Cheng * The kstat query could fail if the underlying MAC 205da14cebeSEric Cheng * driver was already detached. 206da14cebeSEric Cheng */ 207da14cebeSEric Cheng if ((ksp = kstat_lookup(kcp, module, instance, "mac")) == NULL && 208da14cebeSEric Cheng (ksp = kstat_lookup(kcp, module, instance, NULL)) == NULL) 209da14cebeSEric Cheng goto bail; 210da14cebeSEric Cheng 211da14cebeSEric Cheng if (kstat_read(kcp, ksp, NULL) == -1) 212da14cebeSEric Cheng goto bail; 213da14cebeSEric Cheng 214da14cebeSEric Cheng if (dladm_kstat_value(ksp, name, type, val) < 0) 215da14cebeSEric Cheng goto bail; 216da14cebeSEric Cheng 217da14cebeSEric Cheng (void) kstat_close(kcp); 218da14cebeSEric Cheng return (DLADM_STATUS_OK); 219da14cebeSEric Cheng 220da14cebeSEric Cheng bail: 221da14cebeSEric Cheng (void) kstat_close(kcp); 222da14cebeSEric Cheng return (dladm_errno2status(errno)); 223da14cebeSEric Cheng } 224da14cebeSEric Cheng 225da14cebeSEric Cheng /* Compute sum of 2 pktsums (s1 = s2 + s3) */ 226da14cebeSEric Cheng void 227da14cebeSEric Cheng dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 228da14cebeSEric Cheng { 229da14cebeSEric Cheng s1->rbytes = s2->rbytes + s3->rbytes; 230da14cebeSEric Cheng s1->ipackets = s2->ipackets + s3->ipackets; 231da14cebeSEric Cheng s1->ierrors = s2->ierrors + s3->ierrors; 232da14cebeSEric Cheng s1->obytes = s2->obytes + s3->obytes; 233da14cebeSEric Cheng s1->opackets = s2->opackets + s3->opackets; 234da14cebeSEric Cheng s1->oerrors = s2->oerrors + s3->oerrors; 235da14cebeSEric Cheng s1->snaptime = s2->snaptime; 236da14cebeSEric Cheng } 237da14cebeSEric Cheng 2380dc2366fSVenugopal Iyer #define DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0) 2392d40c3b2SPrakash Jalan 2402d40c3b2SPrakash Jalan 241da14cebeSEric Cheng /* Compute differences between 2 pktsums (s1 = s2 - s3) */ 242da14cebeSEric Cheng void 243da14cebeSEric Cheng dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3) 244da14cebeSEric Cheng { 2452d40c3b2SPrakash Jalan s1->rbytes = DIFF_STAT(s2->rbytes, s3->rbytes); 2462d40c3b2SPrakash Jalan s1->ipackets = DIFF_STAT(s2->ipackets, s3->ipackets); 2472d40c3b2SPrakash Jalan s1->ierrors = DIFF_STAT(s2->ierrors, s3->ierrors); 2482d40c3b2SPrakash Jalan s1->obytes = DIFF_STAT(s2->obytes, s3->obytes); 2492d40c3b2SPrakash Jalan s1->opackets = DIFF_STAT(s2->opackets, s3->opackets); 2502d40c3b2SPrakash Jalan s1->oerrors = DIFF_STAT(s2->oerrors, s3->oerrors); 2512d40c3b2SPrakash Jalan s1->snaptime = DIFF_STAT(s2->snaptime, s3->snaptime); 252da14cebeSEric Cheng } 2530dc2366fSVenugopal Iyer 2540dc2366fSVenugopal Iyer #define DLSTAT_MAC_RX_SWLANE "mac_rx_swlane" 2550dc2366fSVenugopal Iyer #define DLSTAT_MAC_RX_HWLANE "mac_rx_hwlane" 2560dc2366fSVenugopal Iyer #define DLSTAT_MAC_TX_SWLANE "mac_tx_swlane" 2570dc2366fSVenugopal Iyer #define DLSTAT_MAC_TX_HWLANE "mac_tx_hwlane" 2580dc2366fSVenugopal Iyer #define DLSTAT_MAC_MISC_STAT "mac_misc_stat" 2590dc2366fSVenugopal Iyer #define DLSTAT_MAC_RX_RING "mac_rx_ring" 2600dc2366fSVenugopal Iyer #define DLSTAT_MAC_TX_RING "mac_tx_ring" 2610dc2366fSVenugopal Iyer #define DLSTAT_MAC_FANOUT "mac_rx_swlane0_fanout" 2620dc2366fSVenugopal Iyer 2630dc2366fSVenugopal Iyer typedef struct { 2640dc2366fSVenugopal Iyer const char *si_name; 2650dc2366fSVenugopal Iyer uint_t si_offset; 2660dc2366fSVenugopal Iyer } stat_info_t; 2670dc2366fSVenugopal Iyer 2680dc2366fSVenugopal Iyer #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0])) 2690dc2366fSVenugopal Iyer 2700dc2366fSVenugopal Iyer /* Definitions for rx lane stats */ 2710dc2366fSVenugopal Iyer #define RL_OFF(f) (offsetof(rx_lane_stat_t, f)) 2720dc2366fSVenugopal Iyer 2730dc2366fSVenugopal Iyer static stat_info_t rx_hwlane_stats_list[] = { 2740dc2366fSVenugopal Iyer {"ipackets", RL_OFF(rl_ipackets)}, 2750dc2366fSVenugopal Iyer {"rbytes", RL_OFF(rl_rbytes)}, 2760dc2366fSVenugopal Iyer {"intrs", RL_OFF(rl_intrs)}, 2770dc2366fSVenugopal Iyer {"intrbytes", RL_OFF(rl_intrbytes)}, 2780dc2366fSVenugopal Iyer {"polls", RL_OFF(rl_polls)}, 2790dc2366fSVenugopal Iyer {"pollbytes", RL_OFF(rl_pollbytes)}, 2800dc2366fSVenugopal Iyer {"rxsdrops", RL_OFF(rl_sdrops)}, 2810dc2366fSVenugopal Iyer {"chainunder10", RL_OFF(rl_chl10)}, 2820dc2366fSVenugopal Iyer {"chain10to50", RL_OFF(rl_ch10_50)}, 2830dc2366fSVenugopal Iyer {"chainover50", RL_OFF(rl_chg50)} 2840dc2366fSVenugopal Iyer }; 2850dc2366fSVenugopal Iyer #define RX_HWLANE_STAT_SIZE A_CNT(rx_hwlane_stats_list) 2860dc2366fSVenugopal Iyer 2870dc2366fSVenugopal Iyer static stat_info_t rx_swlane_stats_list[] = { 2880dc2366fSVenugopal Iyer {"ipackets", RL_OFF(rl_ipackets)}, 2890dc2366fSVenugopal Iyer {"rbytes", RL_OFF(rl_rbytes)}, 2900dc2366fSVenugopal Iyer {"local", RL_OFF(rl_lclpackets)}, 2910dc2366fSVenugopal Iyer {"localbytes", RL_OFF(rl_lclbytes)}, 2920dc2366fSVenugopal Iyer {"intrs", RL_OFF(rl_intrs)}, 2930dc2366fSVenugopal Iyer {"intrbytes", RL_OFF(rl_intrbytes)}, 2940dc2366fSVenugopal Iyer {"rxsdrops", RL_OFF(rl_sdrops)} 2950dc2366fSVenugopal Iyer }; 2960dc2366fSVenugopal Iyer #define RX_SWLANE_STAT_SIZE A_CNT(rx_swlane_stats_list) 2970dc2366fSVenugopal Iyer 2980dc2366fSVenugopal Iyer static stat_info_t rx_lane_stats_list[] = { 2990dc2366fSVenugopal Iyer {"ipackets", RL_OFF(rl_ipackets)}, 3000dc2366fSVenugopal Iyer {"rbytes", RL_OFF(rl_rbytes)}, 3010dc2366fSVenugopal Iyer {"local", RL_OFF(rl_lclpackets)}, 3020dc2366fSVenugopal Iyer {"localbytes", RL_OFF(rl_lclbytes)}, 3030dc2366fSVenugopal Iyer {"intrs", RL_OFF(rl_intrs)}, 3040dc2366fSVenugopal Iyer {"intrbytes", RL_OFF(rl_intrbytes)}, 3050dc2366fSVenugopal Iyer {"polls", RL_OFF(rl_polls)}, 3060dc2366fSVenugopal Iyer {"rxsdrops", RL_OFF(rl_sdrops)}, 3070dc2366fSVenugopal Iyer {"pollbytes", RL_OFF(rl_pollbytes)}, 3080dc2366fSVenugopal Iyer {"chainunder10", RL_OFF(rl_chl10)}, 3090dc2366fSVenugopal Iyer {"chain10to50", RL_OFF(rl_ch10_50)}, 3100dc2366fSVenugopal Iyer {"chainover50", RL_OFF(rl_chg50)} 3110dc2366fSVenugopal Iyer }; 3120dc2366fSVenugopal Iyer #define RX_LANE_STAT_SIZE A_CNT(rx_lane_stats_list) 3130dc2366fSVenugopal Iyer 3140dc2366fSVenugopal Iyer /* Definitions for tx lane stats */ 3150dc2366fSVenugopal Iyer #define TL_OFF(f) (offsetof(tx_lane_stat_t, f)) 3160dc2366fSVenugopal Iyer 3170dc2366fSVenugopal Iyer static stat_info_t tx_lane_stats_list[] = { 3180dc2366fSVenugopal Iyer {"opackets", TL_OFF(tl_opackets)}, 3190dc2366fSVenugopal Iyer {"obytes", TL_OFF(tl_obytes)}, 3200dc2366fSVenugopal Iyer {"blockcnt", TL_OFF(tl_blockcnt)}, 3210dc2366fSVenugopal Iyer {"unblockcnt", TL_OFF(tl_unblockcnt)}, 3220dc2366fSVenugopal Iyer {"txsdrops", TL_OFF(tl_sdrops)} 3230dc2366fSVenugopal Iyer }; 3240dc2366fSVenugopal Iyer #define TX_LANE_STAT_SIZE A_CNT(tx_lane_stats_list) 3250dc2366fSVenugopal Iyer 3260dc2366fSVenugopal Iyer /* Definitions for tx/rx misc stats */ 3270dc2366fSVenugopal Iyer #define M_OFF(f) (offsetof(misc_stat_t, f)) 3280dc2366fSVenugopal Iyer 3290dc2366fSVenugopal Iyer static stat_info_t misc_stats_list[] = { 3300dc2366fSVenugopal Iyer {"multircv", M_OFF(ms_multircv)}, 3310dc2366fSVenugopal Iyer {"brdcstrcv", M_OFF(ms_brdcstrcv)}, 3320dc2366fSVenugopal Iyer {"multixmt", M_OFF(ms_multixmt)}, 3330dc2366fSVenugopal Iyer {"brdcstxmt", M_OFF(ms_brdcstxmt)}, 3340dc2366fSVenugopal Iyer {"multircvbytes", M_OFF(ms_multircvbytes)}, 3350dc2366fSVenugopal Iyer {"brdcstrcvbytes", M_OFF(ms_brdcstrcvbytes)}, 3360dc2366fSVenugopal Iyer {"multixmtbytes", M_OFF(ms_multixmtbytes)}, 3370dc2366fSVenugopal Iyer {"brdcstxmtbytes", M_OFF(ms_brdcstxmtbytes)}, 3380dc2366fSVenugopal Iyer {"txerrors", M_OFF(ms_txerrors)}, 3390dc2366fSVenugopal Iyer {"macspoofed", M_OFF(ms_macspoofed)}, 3400dc2366fSVenugopal Iyer {"ipspoofed", M_OFF(ms_ipspoofed)}, 3410dc2366fSVenugopal Iyer {"dhcpspoofed", M_OFF(ms_dhcpspoofed)}, 3420dc2366fSVenugopal Iyer {"restricted", M_OFF(ms_restricted)}, 3430dc2366fSVenugopal Iyer {"ipackets", M_OFF(ms_ipackets)}, 3440dc2366fSVenugopal Iyer {"rbytes", M_OFF(ms_rbytes)}, 3450dc2366fSVenugopal Iyer {"local", M_OFF(ms_local)}, 3460dc2366fSVenugopal Iyer {"localbytes", M_OFF(ms_localbytes)}, 3470dc2366fSVenugopal Iyer {"intrs", M_OFF(ms_intrs)}, 3480dc2366fSVenugopal Iyer {"intrbytes", M_OFF(ms_intrbytes)}, 3490dc2366fSVenugopal Iyer {"polls", M_OFF(ms_polls)}, 3500dc2366fSVenugopal Iyer {"pollbytes", M_OFF(ms_pollbytes)}, 3510dc2366fSVenugopal Iyer {"rxsdrops", M_OFF(ms_rxsdrops)}, 3520dc2366fSVenugopal Iyer {"chainunder10", M_OFF(ms_chainunder10)}, 3530dc2366fSVenugopal Iyer {"chain10to50", M_OFF(ms_chain10to50)}, 3540dc2366fSVenugopal Iyer {"chainover50", M_OFF(ms_chainover50)}, 3550dc2366fSVenugopal Iyer {"obytes", M_OFF(ms_obytes)}, 3560dc2366fSVenugopal Iyer {"opackets", M_OFF(ms_opackets)}, 3570dc2366fSVenugopal Iyer {"blockcnt", M_OFF(ms_blockcnt)}, 3580dc2366fSVenugopal Iyer {"unblockcnt", M_OFF(ms_unblockcnt)}, 3590dc2366fSVenugopal Iyer {"txsdrops", M_OFF(ms_txsdrops)} 3600dc2366fSVenugopal Iyer }; 3610dc2366fSVenugopal Iyer #define MISC_STAT_SIZE A_CNT(misc_stats_list) 3620dc2366fSVenugopal Iyer 3630dc2366fSVenugopal Iyer /* Definitions for rx ring stats */ 3640dc2366fSVenugopal Iyer #define R_OFF(f) (offsetof(ring_stat_t, f)) 3650dc2366fSVenugopal Iyer 3660dc2366fSVenugopal Iyer static stat_info_t rx_ring_stats_list[] = { 3670dc2366fSVenugopal Iyer {"ipackets", R_OFF(r_packets)}, 3680dc2366fSVenugopal Iyer {"rbytes", R_OFF(r_bytes)} 3690dc2366fSVenugopal Iyer }; 3700dc2366fSVenugopal Iyer #define RX_RING_STAT_SIZE A_CNT(rx_ring_stats_list) 3710dc2366fSVenugopal Iyer 3720dc2366fSVenugopal Iyer /* Definitions for tx ring stats */ 3730dc2366fSVenugopal Iyer static stat_info_t tx_ring_stats_list[] = { 3740dc2366fSVenugopal Iyer {"opackets", R_OFF(r_packets)}, 3750dc2366fSVenugopal Iyer {"obytes", R_OFF(r_bytes)} 3760dc2366fSVenugopal Iyer }; 3770dc2366fSVenugopal Iyer #define TX_RING_STAT_SIZE A_CNT(tx_ring_stats_list) 3780dc2366fSVenugopal Iyer 3790dc2366fSVenugopal Iyer /* Definitions for fanout stats */ 3800dc2366fSVenugopal Iyer #define F_OFF(f) (offsetof(fanout_stat_t, f)) 3810dc2366fSVenugopal Iyer 3820dc2366fSVenugopal Iyer static stat_info_t fanout_stats_list[] = { 3830dc2366fSVenugopal Iyer {"ipackets", F_OFF(f_ipackets)}, 3840dc2366fSVenugopal Iyer {"rbytes", F_OFF(f_rbytes)}, 3850dc2366fSVenugopal Iyer }; 3860dc2366fSVenugopal Iyer #define FANOUT_STAT_SIZE A_CNT(fanout_stats_list) 3870dc2366fSVenugopal Iyer 3880dc2366fSVenugopal Iyer /* Definitions for total stats */ 3890dc2366fSVenugopal Iyer #define T_OFF(f) (offsetof(total_stat_t, f)) 3900dc2366fSVenugopal Iyer 3910dc2366fSVenugopal Iyer static stat_info_t total_stats_list[] = { 3920dc2366fSVenugopal Iyer {"ipackets", T_OFF(ts_ipackets)}, 3930dc2366fSVenugopal Iyer {"rbytes", T_OFF(ts_rbytes)}, 3940dc2366fSVenugopal Iyer {"opackets", T_OFF(ts_opackets)}, 3950dc2366fSVenugopal Iyer {"obytes", T_OFF(ts_obytes)} 3960dc2366fSVenugopal Iyer }; 3970dc2366fSVenugopal Iyer #define TOTAL_STAT_SIZE A_CNT(total_stats_list) 3980dc2366fSVenugopal Iyer 3990dc2366fSVenugopal Iyer /* Definitions for aggr stats */ 4000dc2366fSVenugopal Iyer #define AP_OFF(f) (offsetof(aggr_port_stat_t, f)) 4010dc2366fSVenugopal Iyer 4020dc2366fSVenugopal Iyer static stat_info_t aggr_port_stats_list[] = { 4030dc2366fSVenugopal Iyer {"ipackets64", AP_OFF(ap_ipackets)}, 4040dc2366fSVenugopal Iyer {"rbytes64", AP_OFF(ap_rbytes)}, 4050dc2366fSVenugopal Iyer {"opackets64", AP_OFF(ap_opackets)}, 4060dc2366fSVenugopal Iyer {"obytes64", AP_OFF(ap_obytes)} 4070dc2366fSVenugopal Iyer }; 4080dc2366fSVenugopal Iyer #define AGGR_PORT_STAT_SIZE A_CNT(aggr_port_stats_list) 4090dc2366fSVenugopal Iyer 4100dc2366fSVenugopal Iyer /* Definitions for flow stats */ 4110dc2366fSVenugopal Iyer #define FL_OFF(f) (offsetof(flow_stat_t, f)) 4120dc2366fSVenugopal Iyer 4130dc2366fSVenugopal Iyer static stat_info_t flow_stats_list[] = { 4140dc2366fSVenugopal Iyer {"ipackets", FL_OFF(fl_ipackets)}, 4150dc2366fSVenugopal Iyer {"rbytes", FL_OFF(fl_rbytes)}, 4160dc2366fSVenugopal Iyer {"opackets", FL_OFF(fl_opackets)}, 4170dc2366fSVenugopal Iyer {"obytes", FL_OFF(fl_obytes)} 4180dc2366fSVenugopal Iyer }; 4190dc2366fSVenugopal Iyer #define FLOW_STAT_SIZE A_CNT(flow_stats_list) 4200dc2366fSVenugopal Iyer 4210dc2366fSVenugopal Iyer /* Rx lane specific functions */ 4220dc2366fSVenugopal Iyer void * dlstat_rx_lane_stats(dladm_handle_t, datalink_id_t); 4230dc2366fSVenugopal Iyer static boolean_t i_dlstat_rx_lane_match(void *, void *); 4240dc2366fSVenugopal Iyer static void * i_dlstat_rx_lane_stat_entry_diff(void *, void *); 4250dc2366fSVenugopal Iyer 4260dc2366fSVenugopal Iyer /* Tx lane specific functions */ 4270dc2366fSVenugopal Iyer void * dlstat_tx_lane_stats(dladm_handle_t, datalink_id_t); 4280dc2366fSVenugopal Iyer static boolean_t i_dlstat_tx_lane_match(void *, void *); 4290dc2366fSVenugopal Iyer static void * i_dlstat_tx_lane_stat_entry_diff(void *, void *); 4300dc2366fSVenugopal Iyer 4310dc2366fSVenugopal Iyer /* Rx lane total specific functions */ 4320dc2366fSVenugopal Iyer void * dlstat_rx_lane_total_stats(dladm_handle_t, 4330dc2366fSVenugopal Iyer datalink_id_t); 4340dc2366fSVenugopal Iyer 4350dc2366fSVenugopal Iyer /* Tx lane total specific functions */ 4360dc2366fSVenugopal Iyer void * dlstat_tx_lane_total_stats(dladm_handle_t, 4370dc2366fSVenugopal Iyer datalink_id_t); 4380dc2366fSVenugopal Iyer 4390dc2366fSVenugopal Iyer /* Fanout specific functions */ 4400dc2366fSVenugopal Iyer void * dlstat_fanout_stats(dladm_handle_t, datalink_id_t); 4410dc2366fSVenugopal Iyer static boolean_t i_dlstat_fanout_match(void *, void *); 4420dc2366fSVenugopal Iyer static void * i_dlstat_fanout_stat_entry_diff(void *, void *); 4430dc2366fSVenugopal Iyer 4440dc2366fSVenugopal Iyer /* Rx ring specific functions */ 4450dc2366fSVenugopal Iyer void * dlstat_rx_ring_stats(dladm_handle_t, datalink_id_t); 4460dc2366fSVenugopal Iyer static boolean_t i_dlstat_rx_ring_match(void *, void *); 4470dc2366fSVenugopal Iyer static void * i_dlstat_rx_ring_stat_entry_diff(void *, void *); 4480dc2366fSVenugopal Iyer 4490dc2366fSVenugopal Iyer /* Tx ring specific functions */ 4500dc2366fSVenugopal Iyer void * dlstat_tx_ring_stats(dladm_handle_t, datalink_id_t); 4510dc2366fSVenugopal Iyer static boolean_t i_dlstat_tx_ring_match(void *, void *); 4520dc2366fSVenugopal Iyer static void * i_dlstat_tx_ring_stat_entry_diff(void *, void *); 4530dc2366fSVenugopal Iyer 4540dc2366fSVenugopal Iyer /* Rx ring total specific functions */ 4550dc2366fSVenugopal Iyer void * dlstat_rx_ring_total_stats(dladm_handle_t, 4560dc2366fSVenugopal Iyer datalink_id_t); 4570dc2366fSVenugopal Iyer 4580dc2366fSVenugopal Iyer /* Tx ring total specific functions */ 4590dc2366fSVenugopal Iyer void * dlstat_tx_ring_total_stats(dladm_handle_t, 4600dc2366fSVenugopal Iyer datalink_id_t); 4610dc2366fSVenugopal Iyer 4620dc2366fSVenugopal Iyer /* Summary specific functions */ 4630dc2366fSVenugopal Iyer void * dlstat_total_stats(dladm_handle_t, datalink_id_t); 4640dc2366fSVenugopal Iyer static boolean_t i_dlstat_total_match(void *, void *); 4650dc2366fSVenugopal Iyer static void * i_dlstat_total_stat_entry_diff(void *, void *); 4660dc2366fSVenugopal Iyer 4670dc2366fSVenugopal Iyer /* Aggr port specific functions */ 4680dc2366fSVenugopal Iyer void * dlstat_aggr_port_stats(dladm_handle_t, datalink_id_t); 4690dc2366fSVenugopal Iyer static boolean_t i_dlstat_aggr_port_match(void *, void *); 4700dc2366fSVenugopal Iyer static void * i_dlstat_aggr_port_stat_entry_diff(void *, void *); 4710dc2366fSVenugopal Iyer 4720dc2366fSVenugopal Iyer /* Misc stat specific functions */ 4730dc2366fSVenugopal Iyer void * dlstat_misc_stats(dladm_handle_t, datalink_id_t); 4740dc2366fSVenugopal Iyer 4750dc2366fSVenugopal Iyer typedef void * dladm_stat_query_t(dladm_handle_t, datalink_id_t); 4760dc2366fSVenugopal Iyer typedef boolean_t dladm_stat_match_t(void *, void *); 4770dc2366fSVenugopal Iyer typedef void * dladm_stat_diff_t(void *, void *); 4780dc2366fSVenugopal Iyer 4790dc2366fSVenugopal Iyer typedef struct dladm_stat_desc_s { 4800dc2366fSVenugopal Iyer dladm_stat_type_t ds_stattype; 4810dc2366fSVenugopal Iyer dladm_stat_query_t *ds_querystat; 4820dc2366fSVenugopal Iyer dladm_stat_match_t *ds_matchstat; 4830dc2366fSVenugopal Iyer dladm_stat_diff_t *ds_diffstat; 4840dc2366fSVenugopal Iyer uint_t ds_offset; 4850dc2366fSVenugopal Iyer stat_info_t *ds_statlist; 4860dc2366fSVenugopal Iyer uint_t ds_statsize; 4870dc2366fSVenugopal Iyer } dladm_stat_desc_t; 4880dc2366fSVenugopal Iyer 4890dc2366fSVenugopal Iyer /* 4900dc2366fSVenugopal Iyer * dladm_stat_table has one entry for each supported stat. ds_querystat returns 4910dc2366fSVenugopal Iyer * a chain of 'stat entries' for the queried stat. 4920dc2366fSVenugopal Iyer * Each stat entry has set of identifiers (ids) and an object containing actual 4930dc2366fSVenugopal Iyer * stat values. These stat entry objects are chained together in a linked list 4940dc2366fSVenugopal Iyer * of datatype dladm_stat_chain_t. Head of this list is returned to the caller 4950dc2366fSVenugopal Iyer * of dladm_link_stat_query. 4960dc2366fSVenugopal Iyer * 4970dc2366fSVenugopal Iyer * One node in the chain is shown below: 4980dc2366fSVenugopal Iyer * 4990dc2366fSVenugopal Iyer * ------------------------- 5000dc2366fSVenugopal Iyer * | dc_statentry | 5010dc2366fSVenugopal Iyer * | -------------- | 5020dc2366fSVenugopal Iyer * | | ids | | 5030dc2366fSVenugopal Iyer * | -------------- | 5040dc2366fSVenugopal Iyer * | | stat fields | | 5050dc2366fSVenugopal Iyer * | -------------- | 5060dc2366fSVenugopal Iyer * ------------------------- 5070dc2366fSVenugopal Iyer * | dc_next ---------|------> to next stat entry 5080dc2366fSVenugopal Iyer * ------------------------- 5090dc2366fSVenugopal Iyer * 5100dc2366fSVenugopal Iyer * In particular, for query DLADM_STAT_RX_LANE, dc_statentry carries pointer to 5110dc2366fSVenugopal Iyer * object of type rx_lane_stat_entry_t. 5120dc2366fSVenugopal Iyer * 5130dc2366fSVenugopal Iyer * dladm_link_stat_query_all returns similar chain. However, instead of storing 5140dc2366fSVenugopal Iyer * stat fields as raw numbers, it stores those as chain of <name, value> pairs. 5150dc2366fSVenugopal Iyer * The resulting structure is depicted below: 5160dc2366fSVenugopal Iyer * 5170dc2366fSVenugopal Iyer * ------------------------- 5180dc2366fSVenugopal Iyer * | dc_statentry | 5190dc2366fSVenugopal Iyer * | -------------- | --------------- 5200dc2366fSVenugopal Iyer * | | nv_header | | | name, val | 5210dc2366fSVenugopal Iyer * | -------------- | --------------- 5220dc2366fSVenugopal Iyer * | | nve_stats---|----|-->| nv_nextstat--|---> to next name, val pair 5230dc2366fSVenugopal Iyer * | -------------- | --------------- 5240dc2366fSVenugopal Iyer * ------------------------- 5250dc2366fSVenugopal Iyer * | dc_next ---------|------> to next stat entry 5260dc2366fSVenugopal Iyer * ------------------------- 5270dc2366fSVenugopal Iyer */ 5280dc2366fSVenugopal Iyer static dladm_stat_desc_t dladm_stat_table[] = { 5290dc2366fSVenugopal Iyer { DLADM_STAT_RX_LANE, dlstat_rx_lane_stats, 5300dc2366fSVenugopal Iyer i_dlstat_rx_lane_match, i_dlstat_rx_lane_stat_entry_diff, 5310dc2366fSVenugopal Iyer offsetof(rx_lane_stat_entry_t, rle_stats), 5320dc2366fSVenugopal Iyer rx_lane_stats_list, RX_LANE_STAT_SIZE}, 5330dc2366fSVenugopal Iyer 5340dc2366fSVenugopal Iyer { DLADM_STAT_TX_LANE, dlstat_tx_lane_stats, 5350dc2366fSVenugopal Iyer i_dlstat_tx_lane_match, i_dlstat_tx_lane_stat_entry_diff, 5360dc2366fSVenugopal Iyer offsetof(tx_lane_stat_entry_t, tle_stats), 5370dc2366fSVenugopal Iyer tx_lane_stats_list, TX_LANE_STAT_SIZE}, 5380dc2366fSVenugopal Iyer 5390dc2366fSVenugopal Iyer { DLADM_STAT_RX_LANE_TOTAL, dlstat_rx_lane_total_stats, 5400dc2366fSVenugopal Iyer i_dlstat_rx_lane_match, i_dlstat_rx_lane_stat_entry_diff, 5410dc2366fSVenugopal Iyer offsetof(rx_lane_stat_entry_t, rle_stats), 5420dc2366fSVenugopal Iyer rx_lane_stats_list, RX_LANE_STAT_SIZE}, 5430dc2366fSVenugopal Iyer 5440dc2366fSVenugopal Iyer { DLADM_STAT_TX_LANE_TOTAL, dlstat_tx_lane_total_stats, 5450dc2366fSVenugopal Iyer i_dlstat_tx_lane_match, i_dlstat_tx_lane_stat_entry_diff, 5460dc2366fSVenugopal Iyer offsetof(tx_lane_stat_entry_t, tle_stats), 5470dc2366fSVenugopal Iyer tx_lane_stats_list, TX_LANE_STAT_SIZE}, 5480dc2366fSVenugopal Iyer 5490dc2366fSVenugopal Iyer { DLADM_STAT_RX_LANE_FOUT, dlstat_fanout_stats, 5500dc2366fSVenugopal Iyer i_dlstat_fanout_match, i_dlstat_fanout_stat_entry_diff, 5510dc2366fSVenugopal Iyer offsetof(fanout_stat_entry_t, fe_stats), 5520dc2366fSVenugopal Iyer fanout_stats_list, FANOUT_STAT_SIZE}, 5530dc2366fSVenugopal Iyer 5540dc2366fSVenugopal Iyer { DLADM_STAT_RX_RING, dlstat_rx_ring_stats, 5550dc2366fSVenugopal Iyer i_dlstat_rx_ring_match, i_dlstat_rx_ring_stat_entry_diff, 5560dc2366fSVenugopal Iyer offsetof(ring_stat_entry_t, re_stats), 5570dc2366fSVenugopal Iyer rx_ring_stats_list, RX_RING_STAT_SIZE}, 5580dc2366fSVenugopal Iyer 5590dc2366fSVenugopal Iyer { DLADM_STAT_TX_RING, dlstat_tx_ring_stats, 5600dc2366fSVenugopal Iyer i_dlstat_tx_ring_match, i_dlstat_tx_ring_stat_entry_diff, 5610dc2366fSVenugopal Iyer offsetof(ring_stat_entry_t, re_stats), 5620dc2366fSVenugopal Iyer tx_ring_stats_list, TX_RING_STAT_SIZE}, 5630dc2366fSVenugopal Iyer 5640dc2366fSVenugopal Iyer { DLADM_STAT_RX_RING_TOTAL, dlstat_rx_ring_total_stats, 5650dc2366fSVenugopal Iyer i_dlstat_rx_ring_match, i_dlstat_rx_ring_stat_entry_diff, 5660dc2366fSVenugopal Iyer offsetof(ring_stat_entry_t, re_stats), 5670dc2366fSVenugopal Iyer rx_ring_stats_list, RX_RING_STAT_SIZE}, 5680dc2366fSVenugopal Iyer 5690dc2366fSVenugopal Iyer { DLADM_STAT_TX_RING_TOTAL, dlstat_tx_ring_total_stats, 5700dc2366fSVenugopal Iyer i_dlstat_tx_ring_match, i_dlstat_tx_ring_stat_entry_diff, 5710dc2366fSVenugopal Iyer offsetof(ring_stat_entry_t, re_stats), 5720dc2366fSVenugopal Iyer tx_ring_stats_list, TX_RING_STAT_SIZE}, 5730dc2366fSVenugopal Iyer 5740dc2366fSVenugopal Iyer { DLADM_STAT_TOTAL, dlstat_total_stats, 5750dc2366fSVenugopal Iyer i_dlstat_total_match, i_dlstat_total_stat_entry_diff, 5760dc2366fSVenugopal Iyer offsetof(total_stat_entry_t, tse_stats), 5770dc2366fSVenugopal Iyer total_stats_list, TOTAL_STAT_SIZE}, 5780dc2366fSVenugopal Iyer 5790dc2366fSVenugopal Iyer { DLADM_STAT_AGGR_PORT, dlstat_aggr_port_stats, 5800dc2366fSVenugopal Iyer i_dlstat_aggr_port_match, i_dlstat_aggr_port_stat_entry_diff, 5810dc2366fSVenugopal Iyer offsetof(aggr_port_stat_entry_t, ape_stats), 5820dc2366fSVenugopal Iyer aggr_port_stats_list, AGGR_PORT_STAT_SIZE}, 5830dc2366fSVenugopal Iyer /* 5840dc2366fSVenugopal Iyer * We don't support -i <interval> query with misc stats. Several table fields 5850dc2366fSVenugopal Iyer * are left uninitialized thus. 5860dc2366fSVenugopal Iyer */ 5870dc2366fSVenugopal Iyer { DLADM_STAT_MISC, dlstat_misc_stats, 5880dc2366fSVenugopal Iyer NULL, NULL, 5890dc2366fSVenugopal Iyer 0, 5900dc2366fSVenugopal Iyer misc_stats_list, MISC_STAT_SIZE} 5910dc2366fSVenugopal Iyer }; 5920dc2366fSVenugopal Iyer 5930dc2366fSVenugopal Iyer /* Internal functions */ 5940dc2366fSVenugopal Iyer static void * 5950dc2366fSVenugopal Iyer dlstat_diff_stats(void *arg1, void *arg2, dladm_stat_type_t stattype) 5960dc2366fSVenugopal Iyer { 5970dc2366fSVenugopal Iyer return (dladm_stat_table[stattype].ds_diffstat(arg1, arg2)); 5980dc2366fSVenugopal Iyer } 5990dc2366fSVenugopal Iyer 6000dc2366fSVenugopal Iyer static boolean_t 6010dc2366fSVenugopal Iyer dlstat_match_stats(void *arg1, void *arg2, dladm_stat_type_t stattype) 6020dc2366fSVenugopal Iyer { 6030dc2366fSVenugopal Iyer return (dladm_stat_table[stattype].ds_matchstat(arg1, arg2)); 6040dc2366fSVenugopal Iyer } 6050dc2366fSVenugopal Iyer 6060dc2366fSVenugopal Iyer /* Diff between two stats */ 6070dc2366fSVenugopal Iyer static void 6080dc2366fSVenugopal Iyer i_dlstat_diff_stats(void *diff, void *op1, void *op2, 6090dc2366fSVenugopal Iyer stat_info_t stats_list[], uint_t size) 6100dc2366fSVenugopal Iyer { 6110dc2366fSVenugopal Iyer int i; 6120dc2366fSVenugopal Iyer 6130dc2366fSVenugopal Iyer for (i = 0; i < size; i++) { 6140dc2366fSVenugopal Iyer uint64_t *op1_val = (void *) 6150dc2366fSVenugopal Iyer ((uchar_t *)op1 + stats_list[i].si_offset); 6160dc2366fSVenugopal Iyer uint64_t *op2_val = (void *) 6170dc2366fSVenugopal Iyer ((uchar_t *)op2 + stats_list[i].si_offset); 6180dc2366fSVenugopal Iyer uint64_t *diff_val = (void *) 6190dc2366fSVenugopal Iyer ((uchar_t *)diff + stats_list[i].si_offset); 6200dc2366fSVenugopal Iyer 6210dc2366fSVenugopal Iyer *diff_val = DIFF_STAT(*op1_val, *op2_val); 6220dc2366fSVenugopal Iyer } 6230dc2366fSVenugopal Iyer } 6240dc2366fSVenugopal Iyer 6250dc2366fSVenugopal Iyer /* 6260dc2366fSVenugopal Iyer * Perform diff = s1 - s2, where diff, s1, s2 are structure objects of same 6270dc2366fSVenugopal Iyer * datatype. slist is list of offsets of the fields within the structure. 6280dc2366fSVenugopal Iyer */ 6290dc2366fSVenugopal Iyer #define DLSTAT_DIFF_STAT(s1, s2, diff, f, slist, sz) { \ 6300dc2366fSVenugopal Iyer if (s2 == NULL) { \ 6310dc2366fSVenugopal Iyer bcopy(&s1->f, &diff->f, sizeof (s1->f)); \ 6320dc2366fSVenugopal Iyer } else { \ 6330dc2366fSVenugopal Iyer i_dlstat_diff_stats(&diff->f, &s1->f, \ 6340dc2366fSVenugopal Iyer &s2->f, slist, sz); \ 6350dc2366fSVenugopal Iyer } \ 6360dc2366fSVenugopal Iyer } 6370dc2366fSVenugopal Iyer 6380dc2366fSVenugopal Iyer /* Sum two stats */ 6390dc2366fSVenugopal Iyer static void 6400dc2366fSVenugopal Iyer i_dlstat_sum_stats(void *sum, void *op1, void *op2, 6410dc2366fSVenugopal Iyer stat_info_t stats_list[], uint_t size) 6420dc2366fSVenugopal Iyer { 6430dc2366fSVenugopal Iyer int i; 6440dc2366fSVenugopal Iyer 6450dc2366fSVenugopal Iyer for (i = 0; i < size; i++) { 6460dc2366fSVenugopal Iyer uint64_t *op1_val = (void *) 6470dc2366fSVenugopal Iyer ((uchar_t *)op1 + stats_list[i].si_offset); 6480dc2366fSVenugopal Iyer uint64_t *op2_val = (void *) 6490dc2366fSVenugopal Iyer ((uchar_t *)op2 + stats_list[i].si_offset); 6500dc2366fSVenugopal Iyer uint64_t *sum_val = (void *) 6510dc2366fSVenugopal Iyer ((uchar_t *)sum + stats_list[i].si_offset); 6520dc2366fSVenugopal Iyer 6530dc2366fSVenugopal Iyer *sum_val = *op1_val + *op2_val; 6540dc2366fSVenugopal Iyer } 6550dc2366fSVenugopal Iyer } 6560dc2366fSVenugopal Iyer 6570dc2366fSVenugopal Iyer /* Look up kstat value */ 6580dc2366fSVenugopal Iyer static void 6590dc2366fSVenugopal Iyer i_dlstat_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, void *stats, 6600dc2366fSVenugopal Iyer stat_info_t stats_list[], uint_t size) 6610dc2366fSVenugopal Iyer { 6620dc2366fSVenugopal Iyer int i; 6630dc2366fSVenugopal Iyer 6640dc2366fSVenugopal Iyer if (kstat_read(kcp, ksp, NULL) == -1) 6650dc2366fSVenugopal Iyer return; 6660dc2366fSVenugopal Iyer 6670dc2366fSVenugopal Iyer for (i = 0; i < size; i++) { 6680dc2366fSVenugopal Iyer uint64_t *val = (void *) 6690dc2366fSVenugopal Iyer ((uchar_t *)stats + stats_list[i].si_offset); 6700dc2366fSVenugopal Iyer 6710dc2366fSVenugopal Iyer if (dladm_kstat_value(ksp, stats_list[i].si_name, 6720dc2366fSVenugopal Iyer KSTAT_DATA_UINT64, val) < 0) 6730dc2366fSVenugopal Iyer return; 6740dc2366fSVenugopal Iyer } 6750dc2366fSVenugopal Iyer } 6760dc2366fSVenugopal Iyer 6770dc2366fSVenugopal Iyer /* Append linked list list1 to linked list list2 and return resulting list */ 6780dc2366fSVenugopal Iyer static dladm_stat_chain_t * 6790dc2366fSVenugopal Iyer i_dlstat_join_lists(dladm_stat_chain_t *list1, dladm_stat_chain_t *list2) 6800dc2366fSVenugopal Iyer { 6810dc2366fSVenugopal Iyer dladm_stat_chain_t *curr; 6820dc2366fSVenugopal Iyer 6830dc2366fSVenugopal Iyer if (list1 == NULL) 6840dc2366fSVenugopal Iyer return (list2); 6850dc2366fSVenugopal Iyer 6860dc2366fSVenugopal Iyer /* list1 has at least one element, find last element in list1 */ 6870dc2366fSVenugopal Iyer curr = list1; 6880dc2366fSVenugopal Iyer while (curr->dc_next != NULL) 6890dc2366fSVenugopal Iyer curr = curr->dc_next; 6900dc2366fSVenugopal Iyer 6910dc2366fSVenugopal Iyer curr->dc_next = list2; 6920dc2366fSVenugopal Iyer return (list1); 6930dc2366fSVenugopal Iyer } 6940dc2366fSVenugopal Iyer 6950dc2366fSVenugopal Iyer uint_t default_idlist[] = {0}; 6960dc2366fSVenugopal Iyer uint_t default_idlist_size = 1; 6970dc2366fSVenugopal Iyer 6980dc2366fSVenugopal Iyer typedef enum { 6990dc2366fSVenugopal Iyer DLSTAT_RX_RING_IDLIST, 7000dc2366fSVenugopal Iyer DLSTAT_TX_RING_IDLIST, 7010dc2366fSVenugopal Iyer DLSTAT_RX_HWLANE_IDLIST, 7020dc2366fSVenugopal Iyer DLSTAT_TX_HWLANE_IDLIST, 7030dc2366fSVenugopal Iyer DLSTAT_FANOUT_IDLIST 7040dc2366fSVenugopal Iyer } dlstat_idlist_type_t; 7050dc2366fSVenugopal Iyer 7060dc2366fSVenugopal Iyer void 7070dc2366fSVenugopal Iyer dladm_sort_index_list(uint_t idlist[], uint_t size) 7080dc2366fSVenugopal Iyer { 7090dc2366fSVenugopal Iyer int i, j; 7100dc2366fSVenugopal Iyer 7110dc2366fSVenugopal Iyer for (j = 1; j < size; j++) { 7120dc2366fSVenugopal Iyer int key = idlist[j]; 7130dc2366fSVenugopal Iyer for (i = j - 1; (i >= 0) && (idlist[i] > key); i--) 7140dc2366fSVenugopal Iyer idlist[i + 1] = idlist[i]; 7150dc2366fSVenugopal Iyer idlist[i + 1] = key; 7160dc2366fSVenugopal Iyer } 7170dc2366fSVenugopal Iyer } 7180dc2366fSVenugopal Iyer 7190dc2366fSVenugopal Iyer /* Support for legacy drivers */ 7200dc2366fSVenugopal Iyer void 7210dc2366fSVenugopal Iyer i_query_legacy_stats(const char *linkname, pktsum_t *stats) 7220dc2366fSVenugopal Iyer { 7230dc2366fSVenugopal Iyer kstat_ctl_t *kcp; 7240dc2366fSVenugopal Iyer kstat_t *ksp; 7250dc2366fSVenugopal Iyer 7260dc2366fSVenugopal Iyer bzero(stats, sizeof (*stats)); 7270dc2366fSVenugopal Iyer 7280dc2366fSVenugopal Iyer if ((kcp = kstat_open()) == NULL) 7290dc2366fSVenugopal Iyer return; 7300dc2366fSVenugopal Iyer 7310dc2366fSVenugopal Iyer ksp = dladm_kstat_lookup(kcp, "link", 0, linkname, NULL); 7320dc2366fSVenugopal Iyer 7330dc2366fSVenugopal Iyer if (ksp != NULL) 7340dc2366fSVenugopal Iyer dladm_get_stats(kcp, ksp, stats); 7350dc2366fSVenugopal Iyer 7360dc2366fSVenugopal Iyer (void) kstat_close(kcp); 7370dc2366fSVenugopal Iyer } 7380dc2366fSVenugopal Iyer 7390dc2366fSVenugopal Iyer void * 7400dc2366fSVenugopal Iyer i_dlstat_legacy_rx_lane_stats(const char *linkname) 7410dc2366fSVenugopal Iyer { 7420dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 7430dc2366fSVenugopal Iyer pktsum_t stats; 7440dc2366fSVenugopal Iyer rx_lane_stat_entry_t *rx_lane_stat_entry; 7450dc2366fSVenugopal Iyer 7460dc2366fSVenugopal Iyer bzero(&stats, sizeof (pktsum_t)); 7470dc2366fSVenugopal Iyer 7480dc2366fSVenugopal Iyer /* Query for dls stats */ 7490dc2366fSVenugopal Iyer i_query_legacy_stats(linkname, &stats); 7500dc2366fSVenugopal Iyer 7510dc2366fSVenugopal Iyer /* Convert to desired data type */ 7520dc2366fSVenugopal Iyer rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 7530dc2366fSVenugopal Iyer if (rx_lane_stat_entry == NULL) 7540dc2366fSVenugopal Iyer goto done; 7550dc2366fSVenugopal Iyer 7560dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 7570dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_id = L_SWLANE; 7580dc2366fSVenugopal Iyer 7590dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets; 7600dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets; 7610dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes; 7620dc2366fSVenugopal Iyer 7630dc2366fSVenugopal Iyer /* Allocate memory for wrapper */ 7640dc2366fSVenugopal Iyer head = malloc(sizeof (dladm_stat_chain_t)); 7650dc2366fSVenugopal Iyer if (head == NULL) { 7660dc2366fSVenugopal Iyer free(rx_lane_stat_entry); 7670dc2366fSVenugopal Iyer goto done; 7680dc2366fSVenugopal Iyer } 7690dc2366fSVenugopal Iyer 7700dc2366fSVenugopal Iyer head->dc_statentry = rx_lane_stat_entry; 7710dc2366fSVenugopal Iyer head->dc_next = NULL; 7720dc2366fSVenugopal Iyer done: 7730dc2366fSVenugopal Iyer return (head); 7740dc2366fSVenugopal Iyer } 7750dc2366fSVenugopal Iyer 7760dc2366fSVenugopal Iyer void * 7770dc2366fSVenugopal Iyer i_dlstat_legacy_tx_lane_stats(const char *linkname) 7780dc2366fSVenugopal Iyer { 7790dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 7800dc2366fSVenugopal Iyer pktsum_t stats; 7810dc2366fSVenugopal Iyer tx_lane_stat_entry_t *tx_lane_stat_entry; 7820dc2366fSVenugopal Iyer 7830dc2366fSVenugopal Iyer bzero(&stats, sizeof (pktsum_t)); 7840dc2366fSVenugopal Iyer 7850dc2366fSVenugopal Iyer /* Query for dls stats */ 7860dc2366fSVenugopal Iyer i_query_legacy_stats(linkname, &stats); 7870dc2366fSVenugopal Iyer 7880dc2366fSVenugopal Iyer /* Convert to desired data type */ 7890dc2366fSVenugopal Iyer tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 7900dc2366fSVenugopal Iyer if (tx_lane_stat_entry == NULL) 7910dc2366fSVenugopal Iyer goto done; 7920dc2366fSVenugopal Iyer 7930dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 7940dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_id = L_SWLANE; 7950dc2366fSVenugopal Iyer 7960dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets; 7970dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes; 7980dc2366fSVenugopal Iyer 7990dc2366fSVenugopal Iyer /* Allocate memory for wrapper */ 8000dc2366fSVenugopal Iyer head = malloc(sizeof (dladm_stat_chain_t)); 8010dc2366fSVenugopal Iyer if (head == NULL) { 8020dc2366fSVenugopal Iyer free(tx_lane_stat_entry); 8030dc2366fSVenugopal Iyer goto done; 8040dc2366fSVenugopal Iyer } 8050dc2366fSVenugopal Iyer 8060dc2366fSVenugopal Iyer head->dc_statentry = tx_lane_stat_entry; 8070dc2366fSVenugopal Iyer head->dc_next = NULL; 8080dc2366fSVenugopal Iyer done: 8090dc2366fSVenugopal Iyer return (head); 8100dc2366fSVenugopal Iyer } 8110dc2366fSVenugopal Iyer 8120dc2366fSVenugopal Iyer /* 8130dc2366fSVenugopal Iyer * Ideally, we would want an ioctl to return list of ring-ids (or lane-ids) 8140dc2366fSVenugopal Iyer * for a given data-link (or mac client). We could then query for specific 8150dc2366fSVenugopal Iyer * kstats based on these ring-ids (lane-ids). 8160dc2366fSVenugopal Iyer * Ring-ids (or lane-ids) could be returned like any other link properties 8170dc2366fSVenugopal Iyer * queried by dladm show-linkprop. However, non-global zones do not have 8180dc2366fSVenugopal Iyer * access to this information today. 8190dc2366fSVenugopal Iyer * We thus opt for an implementation that relies heavily on kstat internals: 8200dc2366fSVenugopal Iyer * i_dlstat_*search routines and i_dlstat_get_idlist. 8210dc2366fSVenugopal Iyer */ 8220dc2366fSVenugopal Iyer /* rx hwlane specific */ 8230dc2366fSVenugopal Iyer static boolean_t 8240dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_search(kstat_t *ksp) 8250dc2366fSVenugopal Iyer { 8260dc2366fSVenugopal Iyer return (ksp->ks_instance == 0 && 8270dc2366fSVenugopal Iyer strstr(ksp->ks_name, "mac_rx") != 0 && 8280dc2366fSVenugopal Iyer strstr(ksp->ks_name, "hwlane") != 0 && 8290dc2366fSVenugopal Iyer strstr(ksp->ks_name, "fanout") == 0 && 8300dc2366fSVenugopal Iyer strcmp(ksp->ks_class, "net") == 0); 8310dc2366fSVenugopal Iyer } 8320dc2366fSVenugopal Iyer 8330dc2366fSVenugopal Iyer /* tx hwlane specific */ 8340dc2366fSVenugopal Iyer static boolean_t 8350dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_search(kstat_t *ksp) 8360dc2366fSVenugopal Iyer { 8370dc2366fSVenugopal Iyer return (ksp->ks_instance == 0 && 8380dc2366fSVenugopal Iyer strstr(ksp->ks_name, "mac_tx") != 0 && 8390dc2366fSVenugopal Iyer strstr(ksp->ks_name, "hwlane") != 0 && 8400dc2366fSVenugopal Iyer strcmp(ksp->ks_class, "net") == 0); 8410dc2366fSVenugopal Iyer } 8420dc2366fSVenugopal Iyer 8430dc2366fSVenugopal Iyer /* rx fanout specific */ 8440dc2366fSVenugopal Iyer static boolean_t 8450dc2366fSVenugopal Iyer i_dlstat_fanout_search(kstat_t *ksp) 8460dc2366fSVenugopal Iyer { 8470dc2366fSVenugopal Iyer return (ksp->ks_instance == 0 && 8480dc2366fSVenugopal Iyer strstr(ksp->ks_name, "mac_rx") != 0 && 8490dc2366fSVenugopal Iyer strstr(ksp->ks_name, "swlane") != 0 && 8500dc2366fSVenugopal Iyer strstr(ksp->ks_name, "fanout") != 0 && 8510dc2366fSVenugopal Iyer strcmp(ksp->ks_class, "net") == 0); 8520dc2366fSVenugopal Iyer } 8530dc2366fSVenugopal Iyer 8540dc2366fSVenugopal Iyer /* rx ring specific */ 8550dc2366fSVenugopal Iyer static boolean_t 8560dc2366fSVenugopal Iyer i_dlstat_rx_ring_search(kstat_t *ksp) 8570dc2366fSVenugopal Iyer { 8580dc2366fSVenugopal Iyer return (ksp->ks_instance == 0 && 8590dc2366fSVenugopal Iyer strstr(ksp->ks_name, "mac_rx") != 0 && 8600dc2366fSVenugopal Iyer strstr(ksp->ks_name, "ring") != 0 && 8610dc2366fSVenugopal Iyer strcmp(ksp->ks_class, "net") == 0); 8620dc2366fSVenugopal Iyer } 8630dc2366fSVenugopal Iyer 8640dc2366fSVenugopal Iyer /* tx ring specific */ 8650dc2366fSVenugopal Iyer static boolean_t 8660dc2366fSVenugopal Iyer i_dlstat_tx_ring_search(kstat_t *ksp) 8670dc2366fSVenugopal Iyer { 8680dc2366fSVenugopal Iyer return (ksp->ks_instance == 0) && 8690dc2366fSVenugopal Iyer strstr(ksp->ks_name, "mac_tx") != 0 && 8700dc2366fSVenugopal Iyer strstr(ksp->ks_name, "ring") != 0 && 8710dc2366fSVenugopal Iyer strcmp(ksp->ks_class, "net") == 0; 8720dc2366fSVenugopal Iyer } 8730dc2366fSVenugopal Iyer 8740dc2366fSVenugopal Iyer typedef boolean_t dladm_search_kstat_t(kstat_t *); 8750dc2366fSVenugopal Iyer typedef struct dladm_extract_idlist_s { 8760dc2366fSVenugopal Iyer dlstat_idlist_type_t di_type; 8770dc2366fSVenugopal Iyer char *di_prefix; 8780dc2366fSVenugopal Iyer dladm_search_kstat_t *di_searchkstat; 8790dc2366fSVenugopal Iyer } dladm_extract_idlist_t; 8800dc2366fSVenugopal Iyer 8810dc2366fSVenugopal Iyer static dladm_extract_idlist_t dladm_extract_idlist[] = { 8820dc2366fSVenugopal Iyer { DLSTAT_RX_RING_IDLIST, DLSTAT_MAC_RX_RING, 8830dc2366fSVenugopal Iyer i_dlstat_rx_ring_search}, 8840dc2366fSVenugopal Iyer { DLSTAT_TX_RING_IDLIST, DLSTAT_MAC_TX_RING, 8850dc2366fSVenugopal Iyer i_dlstat_tx_ring_search}, 8860dc2366fSVenugopal Iyer { DLSTAT_RX_HWLANE_IDLIST, DLSTAT_MAC_RX_HWLANE, 8870dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_search}, 8880dc2366fSVenugopal Iyer { DLSTAT_TX_HWLANE_IDLIST, DLSTAT_MAC_TX_HWLANE, 8890dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_search}, 8900dc2366fSVenugopal Iyer { DLSTAT_FANOUT_IDLIST, DLSTAT_MAC_FANOUT, 8910dc2366fSVenugopal Iyer i_dlstat_fanout_search} 8920dc2366fSVenugopal Iyer }; 8930dc2366fSVenugopal Iyer 8940dc2366fSVenugopal Iyer static void 8950dc2366fSVenugopal Iyer i_dlstat_get_idlist(const char *modname, dlstat_idlist_type_t idlist_type, 8960dc2366fSVenugopal Iyer uint_t idlist[], uint_t *size) 8970dc2366fSVenugopal Iyer { 8980dc2366fSVenugopal Iyer kstat_ctl_t *kcp; 8990dc2366fSVenugopal Iyer kstat_t *ksp; 9000dc2366fSVenugopal Iyer char *prefix; 9010dc2366fSVenugopal Iyer int prefixlen; 9020dc2366fSVenugopal Iyer boolean_t (*fptr_searchkstat)(kstat_t *); 9030dc2366fSVenugopal Iyer 9040dc2366fSVenugopal Iyer *size = 0; 9050dc2366fSVenugopal Iyer 9060dc2366fSVenugopal Iyer if ((kcp = kstat_open()) == NULL) { 9070dc2366fSVenugopal Iyer warn("kstat_open operation failed"); 9080dc2366fSVenugopal Iyer goto done; 9090dc2366fSVenugopal Iyer } 9100dc2366fSVenugopal Iyer 9110dc2366fSVenugopal Iyer prefix = dladm_extract_idlist[idlist_type].di_prefix; 9120dc2366fSVenugopal Iyer fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat; 9130dc2366fSVenugopal Iyer prefixlen = strlen(prefix); 9140dc2366fSVenugopal Iyer for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) { 9150dc2366fSVenugopal Iyer if ((strcmp(ksp->ks_module, modname) == 0) && 9160dc2366fSVenugopal Iyer fptr_searchkstat(ksp)) { 9170dc2366fSVenugopal Iyer idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]); 9180dc2366fSVenugopal Iyer } 9190dc2366fSVenugopal Iyer } 9200dc2366fSVenugopal Iyer dladm_sort_index_list(idlist, *size); 9210dc2366fSVenugopal Iyer 9220dc2366fSVenugopal Iyer done: 9230dc2366fSVenugopal Iyer (void) kstat_close(kcp); 9240dc2366fSVenugopal Iyer } 9250dc2366fSVenugopal Iyer 9260dc2366fSVenugopal Iyer static dladm_stat_chain_t * 9270dc2366fSVenugopal Iyer i_dlstat_query_stats(const char *modname, const char *prefix, 9280dc2366fSVenugopal Iyer uint_t idlist[], uint_t idlist_size, 9290dc2366fSVenugopal Iyer void * (*fn)(kstat_ctl_t *, kstat_t *, int)) 9300dc2366fSVenugopal Iyer { 9310dc2366fSVenugopal Iyer kstat_ctl_t *kcp; 9320dc2366fSVenugopal Iyer kstat_t *ksp; 9330dc2366fSVenugopal Iyer char statname[MAXLINKNAMELEN]; 9340dc2366fSVenugopal Iyer int i = 0; 9350dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL, *prev = NULL; 9360dc2366fSVenugopal Iyer dladm_stat_chain_t *curr; 9370dc2366fSVenugopal Iyer 9380dc2366fSVenugopal Iyer if ((kcp = kstat_open()) == NULL) { 9390dc2366fSVenugopal Iyer warn("kstat_open operation failed"); 9400dc2366fSVenugopal Iyer return (NULL); 9410dc2366fSVenugopal Iyer } 9420dc2366fSVenugopal Iyer 9430dc2366fSVenugopal Iyer for (i = 0; i < idlist_size; i++) { 9440dc2366fSVenugopal Iyer uint_t index = idlist[i]; 9450dc2366fSVenugopal Iyer 9460dc2366fSVenugopal Iyer (void) snprintf(statname, sizeof (statname), "%s%d", prefix, 9470dc2366fSVenugopal Iyer index); 9480dc2366fSVenugopal Iyer 9490dc2366fSVenugopal Iyer ksp = dladm_kstat_lookup(kcp, modname, 0, statname, NULL); 9500dc2366fSVenugopal Iyer if (ksp == NULL) 9510dc2366fSVenugopal Iyer continue; 9520dc2366fSVenugopal Iyer 9530dc2366fSVenugopal Iyer curr = malloc(sizeof (dladm_stat_chain_t)); 9540dc2366fSVenugopal Iyer if (curr == NULL) 9550dc2366fSVenugopal Iyer break; 9560dc2366fSVenugopal Iyer 9570dc2366fSVenugopal Iyer curr->dc_statentry = fn(kcp, ksp, index); 9580dc2366fSVenugopal Iyer if (curr->dc_statentry == NULL) { 9590dc2366fSVenugopal Iyer free(curr); 9600dc2366fSVenugopal Iyer break; 9610dc2366fSVenugopal Iyer } 9620dc2366fSVenugopal Iyer 9630dc2366fSVenugopal Iyer (void) strlcpy(curr->dc_statheader, statname, 9640dc2366fSVenugopal Iyer sizeof (curr->dc_statheader)); 9650dc2366fSVenugopal Iyer curr->dc_next = NULL; 9660dc2366fSVenugopal Iyer 9670dc2366fSVenugopal Iyer if (head == NULL) /* First node */ 9680dc2366fSVenugopal Iyer head = curr; 9690dc2366fSVenugopal Iyer else 9700dc2366fSVenugopal Iyer prev->dc_next = curr; 9710dc2366fSVenugopal Iyer 9720dc2366fSVenugopal Iyer prev = curr; 9730dc2366fSVenugopal Iyer } 9740dc2366fSVenugopal Iyer done: 9750dc2366fSVenugopal Iyer (void) kstat_close(kcp); 9760dc2366fSVenugopal Iyer return (head); 9770dc2366fSVenugopal Iyer } 9780dc2366fSVenugopal Iyer 9790dc2366fSVenugopal Iyer static misc_stat_entry_t * 9800dc2366fSVenugopal Iyer i_dlstat_misc_stats(const char *linkname) 9810dc2366fSVenugopal Iyer { 9820dc2366fSVenugopal Iyer kstat_ctl_t *kcp; 9830dc2366fSVenugopal Iyer kstat_t *ksp; 9840dc2366fSVenugopal Iyer misc_stat_entry_t *misc_stat_entry = NULL; 9850dc2366fSVenugopal Iyer 9860dc2366fSVenugopal Iyer if ((kcp = kstat_open()) == NULL) 9870dc2366fSVenugopal Iyer return (NULL); 9880dc2366fSVenugopal Iyer 9890dc2366fSVenugopal Iyer ksp = dladm_kstat_lookup(kcp, linkname, 0, DLSTAT_MAC_MISC_STAT, NULL); 9900dc2366fSVenugopal Iyer if (ksp == NULL) 9910dc2366fSVenugopal Iyer goto done; 9920dc2366fSVenugopal Iyer 9930dc2366fSVenugopal Iyer misc_stat_entry = calloc(1, sizeof (misc_stat_entry_t)); 9940dc2366fSVenugopal Iyer if (misc_stat_entry == NULL) 9950dc2366fSVenugopal Iyer goto done; 9960dc2366fSVenugopal Iyer 9970dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, &misc_stat_entry->mse_stats, 9980dc2366fSVenugopal Iyer misc_stats_list, MISC_STAT_SIZE); 9990dc2366fSVenugopal Iyer done: 10000dc2366fSVenugopal Iyer (void) kstat_close(kcp); 10010dc2366fSVenugopal Iyer return (misc_stat_entry); 10020dc2366fSVenugopal Iyer } 10030dc2366fSVenugopal Iyer 10040dc2366fSVenugopal Iyer /* Rx lane statistic specific functions */ 10050dc2366fSVenugopal Iyer static boolean_t 10060dc2366fSVenugopal Iyer i_dlstat_rx_lane_match(void *arg1, void *arg2) 10070dc2366fSVenugopal Iyer { 10080dc2366fSVenugopal Iyer rx_lane_stat_entry_t *s1 = arg1; 10090dc2366fSVenugopal Iyer rx_lane_stat_entry_t *s2 = arg2; 10100dc2366fSVenugopal Iyer 10110dc2366fSVenugopal Iyer return (s1->rle_index == s2->rle_index && 10120dc2366fSVenugopal Iyer s1->rle_id == s2->rle_id); 10130dc2366fSVenugopal Iyer } 10140dc2366fSVenugopal Iyer 10150dc2366fSVenugopal Iyer static void * 10160dc2366fSVenugopal Iyer i_dlstat_rx_lane_stat_entry_diff(void *arg1, void *arg2) 10170dc2366fSVenugopal Iyer { 10180dc2366fSVenugopal Iyer rx_lane_stat_entry_t *s1 = arg1; 10190dc2366fSVenugopal Iyer rx_lane_stat_entry_t *s2 = arg2; 10200dc2366fSVenugopal Iyer rx_lane_stat_entry_t *diff_entry; 10210dc2366fSVenugopal Iyer 10220dc2366fSVenugopal Iyer diff_entry = malloc(sizeof (rx_lane_stat_entry_t)); 10230dc2366fSVenugopal Iyer if (diff_entry == NULL) 10240dc2366fSVenugopal Iyer goto done; 10250dc2366fSVenugopal Iyer 10260dc2366fSVenugopal Iyer diff_entry->rle_index = s1->rle_index; 10270dc2366fSVenugopal Iyer diff_entry->rle_id = s1->rle_id; 10280dc2366fSVenugopal Iyer 10290dc2366fSVenugopal Iyer DLSTAT_DIFF_STAT(s1, s2, diff_entry, rle_stats, rx_lane_stats_list, 10300dc2366fSVenugopal Iyer RX_LANE_STAT_SIZE); 10310dc2366fSVenugopal Iyer 10320dc2366fSVenugopal Iyer done: 10330dc2366fSVenugopal Iyer return (diff_entry); 10340dc2366fSVenugopal Iyer } 10350dc2366fSVenugopal Iyer 10360dc2366fSVenugopal Iyer static void * 10370dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 10380dc2366fSVenugopal Iyer { 10390dc2366fSVenugopal Iyer rx_lane_stat_entry_t *rx_lane_stat_entry; 10400dc2366fSVenugopal Iyer 10410dc2366fSVenugopal Iyer rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 10420dc2366fSVenugopal Iyer if (rx_lane_stat_entry == NULL) 10430dc2366fSVenugopal Iyer goto done; 10440dc2366fSVenugopal Iyer 10450dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_index = i; 10460dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_id = L_HWLANE; 10470dc2366fSVenugopal Iyer 10480dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 10490dc2366fSVenugopal Iyer rx_hwlane_stats_list, RX_HWLANE_STAT_SIZE); 10500dc2366fSVenugopal Iyer 10510dc2366fSVenugopal Iyer done: 10520dc2366fSVenugopal Iyer return (rx_lane_stat_entry); 10530dc2366fSVenugopal Iyer } 10540dc2366fSVenugopal Iyer 10550dc2366fSVenugopal Iyer /*ARGSUSED*/ 10560dc2366fSVenugopal Iyer static void * 10570dc2366fSVenugopal Iyer i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 10580dc2366fSVenugopal Iyer { 10590dc2366fSVenugopal Iyer rx_lane_stat_entry_t *rx_lane_stat_entry; 10600dc2366fSVenugopal Iyer 10610dc2366fSVenugopal Iyer rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 10620dc2366fSVenugopal Iyer if (rx_lane_stat_entry == NULL) 10630dc2366fSVenugopal Iyer goto done; 10640dc2366fSVenugopal Iyer 10650dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 10660dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_id = L_SWLANE; 10670dc2366fSVenugopal Iyer 10680dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 10690dc2366fSVenugopal Iyer rx_swlane_stats_list, RX_SWLANE_STAT_SIZE); 10700dc2366fSVenugopal Iyer 10710dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_ipackets = 10720dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_intrs; 10730dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_rbytes = 10740dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_intrbytes; 10750dc2366fSVenugopal Iyer done: 10760dc2366fSVenugopal Iyer return (rx_lane_stat_entry); 10770dc2366fSVenugopal Iyer } 10780dc2366fSVenugopal Iyer 10790dc2366fSVenugopal Iyer /*ARGSUSED*/ 10800dc2366fSVenugopal Iyer static void * 10810dc2366fSVenugopal Iyer i_dlstat_rx_local_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 10820dc2366fSVenugopal Iyer { 10830dc2366fSVenugopal Iyer rx_lane_stat_entry_t *local_stat_entry; 10840dc2366fSVenugopal Iyer rx_lane_stat_entry_t *rx_lane_stat_entry; 10850dc2366fSVenugopal Iyer 10860dc2366fSVenugopal Iyer rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 10870dc2366fSVenugopal Iyer if (rx_lane_stat_entry == NULL) 10880dc2366fSVenugopal Iyer goto done; 10890dc2366fSVenugopal Iyer 10900dc2366fSVenugopal Iyer local_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 10910dc2366fSVenugopal Iyer if (local_stat_entry == NULL) 10920dc2366fSVenugopal Iyer goto done; 10930dc2366fSVenugopal Iyer 10940dc2366fSVenugopal Iyer local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 10950dc2366fSVenugopal Iyer local_stat_entry->rle_id = L_LOCAL; 10960dc2366fSVenugopal Iyer 10970dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats, 10980dc2366fSVenugopal Iyer rx_swlane_stats_list, RX_SWLANE_STAT_SIZE); 10990dc2366fSVenugopal Iyer 11000dc2366fSVenugopal Iyer local_stat_entry->rle_stats.rl_ipackets = 11010dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_lclpackets; 11020dc2366fSVenugopal Iyer local_stat_entry->rle_stats.rl_rbytes = 11030dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_lclbytes; 11040dc2366fSVenugopal Iyer 11050dc2366fSVenugopal Iyer done: 11060dc2366fSVenugopal Iyer free(rx_lane_stat_entry); 11070dc2366fSVenugopal Iyer return (local_stat_entry); 11080dc2366fSVenugopal Iyer } 11090dc2366fSVenugopal Iyer 11100dc2366fSVenugopal Iyer static dladm_stat_chain_t * 11110dc2366fSVenugopal Iyer i_dlstat_rx_local_stats(const char *linkname) 11120dc2366fSVenugopal Iyer { 11130dc2366fSVenugopal Iyer dladm_stat_chain_t *local_stats = NULL; 11140dc2366fSVenugopal Iyer 11150dc2366fSVenugopal Iyer local_stats = i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_SWLANE, 11160dc2366fSVenugopal Iyer default_idlist, default_idlist_size, 11170dc2366fSVenugopal Iyer i_dlstat_rx_local_retrieve_stat); 11180dc2366fSVenugopal Iyer 11190dc2366fSVenugopal Iyer if (local_stats != NULL) { 11200dc2366fSVenugopal Iyer (void) strlcpy(local_stats->dc_statheader, "mac_rx_local", 11210dc2366fSVenugopal Iyer sizeof (local_stats->dc_statheader)); 11220dc2366fSVenugopal Iyer } 11230dc2366fSVenugopal Iyer return (local_stats); 11240dc2366fSVenugopal Iyer } 11250dc2366fSVenugopal Iyer 11260dc2366fSVenugopal Iyer static dladm_stat_chain_t * 11270dc2366fSVenugopal Iyer i_dlstat_rx_bcast_stats(const char *linkname) 11280dc2366fSVenugopal Iyer { 11290dc2366fSVenugopal Iyer misc_stat_entry_t *misc_stat_entry; 11300dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 11310dc2366fSVenugopal Iyer rx_lane_stat_entry_t *rx_lane_stat_entry; 11320dc2366fSVenugopal Iyer 11330dc2366fSVenugopal Iyer misc_stat_entry = i_dlstat_misc_stats(linkname); 11340dc2366fSVenugopal Iyer if (misc_stat_entry == NULL) 11350dc2366fSVenugopal Iyer goto done; 11360dc2366fSVenugopal Iyer 11370dc2366fSVenugopal Iyer rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 11380dc2366fSVenugopal Iyer if (rx_lane_stat_entry == NULL) 11390dc2366fSVenugopal Iyer goto done; 11400dc2366fSVenugopal Iyer 11410dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 11420dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_id = L_BCAST; 11430dc2366fSVenugopal Iyer 11440dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_ipackets = 11450dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_brdcstrcv + 11460dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_multircv; 11470dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_intrs = 11480dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_brdcstrcv + 11490dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_multircv; 11500dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_rbytes = 11510dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_brdcstrcvbytes + 11520dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_multircvbytes; 11530dc2366fSVenugopal Iyer 11540dc2366fSVenugopal Iyer head = malloc(sizeof (dladm_stat_chain_t)); 11550dc2366fSVenugopal Iyer if (head == NULL) { 11560dc2366fSVenugopal Iyer free(rx_lane_stat_entry); 11570dc2366fSVenugopal Iyer goto done; 11580dc2366fSVenugopal Iyer } 11590dc2366fSVenugopal Iyer 11600dc2366fSVenugopal Iyer head->dc_statentry = rx_lane_stat_entry; 11610dc2366fSVenugopal Iyer head->dc_next = NULL; 11620dc2366fSVenugopal Iyer 11630dc2366fSVenugopal Iyer free(misc_stat_entry); 11640dc2366fSVenugopal Iyer done: 11650dc2366fSVenugopal Iyer return (head); 11660dc2366fSVenugopal Iyer } 11670dc2366fSVenugopal Iyer 11680dc2366fSVenugopal Iyer static dladm_stat_chain_t * 11690dc2366fSVenugopal Iyer i_dlstat_rx_defunctlane_stats(const char *linkname) 11700dc2366fSVenugopal Iyer { 11710dc2366fSVenugopal Iyer misc_stat_entry_t *misc_stat_entry; 11720dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 11730dc2366fSVenugopal Iyer rx_lane_stat_entry_t *rx_lane_stat_entry; 11740dc2366fSVenugopal Iyer 11750dc2366fSVenugopal Iyer misc_stat_entry = i_dlstat_misc_stats(linkname); 11760dc2366fSVenugopal Iyer if (misc_stat_entry == NULL) 11770dc2366fSVenugopal Iyer goto done; 11780dc2366fSVenugopal Iyer 11790dc2366fSVenugopal Iyer rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t)); 11800dc2366fSVenugopal Iyer if (rx_lane_stat_entry == NULL) 11810dc2366fSVenugopal Iyer goto done; 11820dc2366fSVenugopal Iyer 11830dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY; 11840dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_id = L_DFNCT; 11850dc2366fSVenugopal Iyer 11860dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_ipackets = 11870dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_ipackets; 11880dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_rbytes = 11890dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_rbytes; 11900dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_intrs = 11910dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_intrs; 11920dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_polls = 11930dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_polls; 11940dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_sdrops = 11950dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_rxsdrops; 11960dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_chl10 = 11970dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_chainunder10; 11980dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_ch10_50 = 11990dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_chain10to50; 12000dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_chg50 = 12010dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_chainover50; 12020dc2366fSVenugopal Iyer 12030dc2366fSVenugopal Iyer head = malloc(sizeof (dladm_stat_chain_t)); 12040dc2366fSVenugopal Iyer if (head == NULL) { 12050dc2366fSVenugopal Iyer free(rx_lane_stat_entry); 12060dc2366fSVenugopal Iyer goto done; 12070dc2366fSVenugopal Iyer } 12080dc2366fSVenugopal Iyer 12090dc2366fSVenugopal Iyer head->dc_statentry = rx_lane_stat_entry; 12100dc2366fSVenugopal Iyer head->dc_next = NULL; 12110dc2366fSVenugopal Iyer 12120dc2366fSVenugopal Iyer done: 12130dc2366fSVenugopal Iyer return (head); 12140dc2366fSVenugopal Iyer } 12150dc2366fSVenugopal Iyer 12160dc2366fSVenugopal Iyer static dladm_stat_chain_t * 12170dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_stats(const char *linkname) 12180dc2366fSVenugopal Iyer { 12190dc2366fSVenugopal Iyer uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 12200dc2366fSVenugopal Iyer uint_t rx_hwlane_idlist_size; 12210dc2366fSVenugopal Iyer 12220dc2366fSVenugopal Iyer i_dlstat_get_idlist(linkname, DLSTAT_RX_HWLANE_IDLIST, 12230dc2366fSVenugopal Iyer rx_hwlane_idlist, &rx_hwlane_idlist_size); 12240dc2366fSVenugopal Iyer 12250dc2366fSVenugopal Iyer return (i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_HWLANE, 12260dc2366fSVenugopal Iyer rx_hwlane_idlist, rx_hwlane_idlist_size, 12270dc2366fSVenugopal Iyer i_dlstat_rx_hwlane_retrieve_stat)); 12280dc2366fSVenugopal Iyer } 12290dc2366fSVenugopal Iyer 12300dc2366fSVenugopal Iyer /*ARGSUSED*/ 12310dc2366fSVenugopal Iyer static dladm_stat_chain_t * 12320dc2366fSVenugopal Iyer i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid, 12330dc2366fSVenugopal Iyer const char *linkname) 12340dc2366fSVenugopal Iyer { 12350dc2366fSVenugopal Iyer return (i_dlstat_query_stats(linkname, DLSTAT_MAC_RX_SWLANE, 12360dc2366fSVenugopal Iyer default_idlist, default_idlist_size, 12370dc2366fSVenugopal Iyer i_dlstat_rx_swlane_retrieve_stat)); 12380dc2366fSVenugopal Iyer } 12390dc2366fSVenugopal Iyer 12400dc2366fSVenugopal Iyer void * 12410dc2366fSVenugopal Iyer dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid) 12420dc2366fSVenugopal Iyer { 12430dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 12440dc2366fSVenugopal Iyer dladm_stat_chain_t *local_stats = NULL; 12450dc2366fSVenugopal Iyer dladm_stat_chain_t *bcast_stats = NULL; 12460dc2366fSVenugopal Iyer dladm_stat_chain_t *defunctlane_stats = NULL; 12470dc2366fSVenugopal Iyer dladm_stat_chain_t *lane_stats = NULL; 12480dc2366fSVenugopal Iyer char linkname[MAXLINKNAMELEN]; 12490dc2366fSVenugopal Iyer boolean_t is_legacy_driver; 12500dc2366fSVenugopal Iyer 12510dc2366fSVenugopal Iyer if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 12520dc2366fSVenugopal Iyer DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 12530dc2366fSVenugopal Iyer goto done; 12540dc2366fSVenugopal Iyer } 12550dc2366fSVenugopal Iyer 12560dc2366fSVenugopal Iyer /* Check if it is legacy driver */ 12570dc2366fSVenugopal Iyer if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT, 12580dc2366fSVenugopal Iyer "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) { 12590dc2366fSVenugopal Iyer goto done; 12600dc2366fSVenugopal Iyer } 12610dc2366fSVenugopal Iyer 12620dc2366fSVenugopal Iyer if (is_legacy_driver) { 12630dc2366fSVenugopal Iyer head = i_dlstat_legacy_rx_lane_stats(linkname); 12640dc2366fSVenugopal Iyer goto done; 12650dc2366fSVenugopal Iyer } 12660dc2366fSVenugopal Iyer 12670dc2366fSVenugopal Iyer local_stats = i_dlstat_rx_local_stats(linkname); 12680dc2366fSVenugopal Iyer bcast_stats = i_dlstat_rx_bcast_stats(linkname); 12690dc2366fSVenugopal Iyer defunctlane_stats = i_dlstat_rx_defunctlane_stats(linkname); 12700dc2366fSVenugopal Iyer lane_stats = i_dlstat_rx_hwlane_stats(linkname); 12710dc2366fSVenugopal Iyer if (lane_stats == NULL) 12720dc2366fSVenugopal Iyer lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname); 12730dc2366fSVenugopal Iyer 12740dc2366fSVenugopal Iyer head = i_dlstat_join_lists(local_stats, bcast_stats); 12750dc2366fSVenugopal Iyer head = i_dlstat_join_lists(head, defunctlane_stats); 12760dc2366fSVenugopal Iyer head = i_dlstat_join_lists(head, lane_stats); 12770dc2366fSVenugopal Iyer done: 12780dc2366fSVenugopal Iyer return (head); 12790dc2366fSVenugopal Iyer } 12800dc2366fSVenugopal Iyer 12810dc2366fSVenugopal Iyer /* Tx lane statistic specific functions */ 12820dc2366fSVenugopal Iyer static boolean_t 12830dc2366fSVenugopal Iyer i_dlstat_tx_lane_match(void *arg1, void *arg2) 12840dc2366fSVenugopal Iyer { 12850dc2366fSVenugopal Iyer tx_lane_stat_entry_t *s1 = arg1; 12860dc2366fSVenugopal Iyer tx_lane_stat_entry_t *s2 = arg2; 12870dc2366fSVenugopal Iyer 12880dc2366fSVenugopal Iyer return (s1->tle_index == s2->tle_index && 12890dc2366fSVenugopal Iyer s1->tle_id == s2->tle_id); 12900dc2366fSVenugopal Iyer } 12910dc2366fSVenugopal Iyer 12920dc2366fSVenugopal Iyer static void * 12930dc2366fSVenugopal Iyer i_dlstat_tx_lane_stat_entry_diff(void *arg1, void *arg2) 12940dc2366fSVenugopal Iyer { 12950dc2366fSVenugopal Iyer tx_lane_stat_entry_t *s1 = arg1; 12960dc2366fSVenugopal Iyer tx_lane_stat_entry_t *s2 = arg2; 12970dc2366fSVenugopal Iyer tx_lane_stat_entry_t *diff_entry; 12980dc2366fSVenugopal Iyer 12990dc2366fSVenugopal Iyer diff_entry = malloc(sizeof (tx_lane_stat_entry_t)); 13000dc2366fSVenugopal Iyer if (diff_entry == NULL) 13010dc2366fSVenugopal Iyer goto done; 13020dc2366fSVenugopal Iyer 13030dc2366fSVenugopal Iyer diff_entry->tle_index = s1->tle_index; 13040dc2366fSVenugopal Iyer diff_entry->tle_id = s1->tle_id; 13050dc2366fSVenugopal Iyer 13060dc2366fSVenugopal Iyer DLSTAT_DIFF_STAT(s1, s2, diff_entry, tle_stats, tx_lane_stats_list, 13070dc2366fSVenugopal Iyer TX_LANE_STAT_SIZE); 13080dc2366fSVenugopal Iyer 13090dc2366fSVenugopal Iyer done: 13100dc2366fSVenugopal Iyer return (diff_entry); 13110dc2366fSVenugopal Iyer } 13120dc2366fSVenugopal Iyer 13130dc2366fSVenugopal Iyer static void * 13140dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 13150dc2366fSVenugopal Iyer { 13160dc2366fSVenugopal Iyer tx_lane_stat_entry_t *tx_lane_stat_entry; 13170dc2366fSVenugopal Iyer 13180dc2366fSVenugopal Iyer tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 13190dc2366fSVenugopal Iyer if (tx_lane_stat_entry == NULL) 13200dc2366fSVenugopal Iyer goto done; 13210dc2366fSVenugopal Iyer 13220dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_index = i; 13230dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_id = L_HWLANE; 13240dc2366fSVenugopal Iyer 13250dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats, 13260dc2366fSVenugopal Iyer tx_lane_stats_list, TX_LANE_STAT_SIZE); 13270dc2366fSVenugopal Iyer 13280dc2366fSVenugopal Iyer done: 13290dc2366fSVenugopal Iyer return (tx_lane_stat_entry); 13300dc2366fSVenugopal Iyer } 13310dc2366fSVenugopal Iyer 13320dc2366fSVenugopal Iyer /*ARGSUSED*/ 13330dc2366fSVenugopal Iyer static void * 13340dc2366fSVenugopal Iyer i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 13350dc2366fSVenugopal Iyer { 13360dc2366fSVenugopal Iyer tx_lane_stat_entry_t *tx_lane_stat_entry; 13370dc2366fSVenugopal Iyer 13380dc2366fSVenugopal Iyer tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 13390dc2366fSVenugopal Iyer if (tx_lane_stat_entry == NULL) 13400dc2366fSVenugopal Iyer goto done; 13410dc2366fSVenugopal Iyer 13420dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 13430dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_id = L_SWLANE; 13440dc2366fSVenugopal Iyer 13450dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats, 13460dc2366fSVenugopal Iyer tx_lane_stats_list, TX_LANE_STAT_SIZE); 13470dc2366fSVenugopal Iyer 13480dc2366fSVenugopal Iyer done: 13490dc2366fSVenugopal Iyer return (tx_lane_stat_entry); 13500dc2366fSVenugopal Iyer } 13510dc2366fSVenugopal Iyer 13520dc2366fSVenugopal Iyer static dladm_stat_chain_t * 13530dc2366fSVenugopal Iyer i_dlstat_tx_bcast_stats(const char *linkname) 13540dc2366fSVenugopal Iyer { 13550dc2366fSVenugopal Iyer misc_stat_entry_t *misc_stat_entry; 13560dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 13570dc2366fSVenugopal Iyer tx_lane_stat_entry_t *tx_lane_stat_entry; 13580dc2366fSVenugopal Iyer 13590dc2366fSVenugopal Iyer misc_stat_entry = i_dlstat_misc_stats(linkname); 13600dc2366fSVenugopal Iyer if (misc_stat_entry == NULL) 13610dc2366fSVenugopal Iyer goto done; 13620dc2366fSVenugopal Iyer 13630dc2366fSVenugopal Iyer tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 13640dc2366fSVenugopal Iyer if (tx_lane_stat_entry == NULL) 13650dc2366fSVenugopal Iyer goto done; 13660dc2366fSVenugopal Iyer 13670dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 13680dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_id = L_BCAST; 13690dc2366fSVenugopal Iyer 13700dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_stats.tl_opackets = 13710dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_brdcstxmt + 13720dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_multixmt; 13730dc2366fSVenugopal Iyer 13740dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_stats.tl_obytes = 13750dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_brdcstxmtbytes + 13760dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_multixmtbytes; 13770dc2366fSVenugopal Iyer 13780dc2366fSVenugopal Iyer head = malloc(sizeof (dladm_stat_chain_t)); 13790dc2366fSVenugopal Iyer if (head == NULL) { 13800dc2366fSVenugopal Iyer free(tx_lane_stat_entry); 13810dc2366fSVenugopal Iyer goto done; 13820dc2366fSVenugopal Iyer } 13830dc2366fSVenugopal Iyer 13840dc2366fSVenugopal Iyer head->dc_statentry = tx_lane_stat_entry; 13850dc2366fSVenugopal Iyer head->dc_next = NULL; 13860dc2366fSVenugopal Iyer 13870dc2366fSVenugopal Iyer free(misc_stat_entry); 13880dc2366fSVenugopal Iyer done: 13890dc2366fSVenugopal Iyer return (head); 13900dc2366fSVenugopal Iyer } 13910dc2366fSVenugopal Iyer 13920dc2366fSVenugopal Iyer static dladm_stat_chain_t * 13930dc2366fSVenugopal Iyer i_dlstat_tx_defunctlane_stats(const char *linkname) 13940dc2366fSVenugopal Iyer { 13950dc2366fSVenugopal Iyer misc_stat_entry_t *misc_stat_entry; 13960dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 13970dc2366fSVenugopal Iyer tx_lane_stat_entry_t *tx_lane_stat_entry; 13980dc2366fSVenugopal Iyer 13990dc2366fSVenugopal Iyer misc_stat_entry = i_dlstat_misc_stats(linkname); 14000dc2366fSVenugopal Iyer if (misc_stat_entry == NULL) 14010dc2366fSVenugopal Iyer goto done; 14020dc2366fSVenugopal Iyer 14030dc2366fSVenugopal Iyer tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t)); 14040dc2366fSVenugopal Iyer if (tx_lane_stat_entry == NULL) 14050dc2366fSVenugopal Iyer goto done; 14060dc2366fSVenugopal Iyer 14070dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY; 14080dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_id = L_DFNCT; 14090dc2366fSVenugopal Iyer 14100dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_stats.tl_opackets = 14110dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_opackets; 14120dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_stats.tl_obytes = 14130dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_obytes; 14140dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_stats.tl_sdrops = 14150dc2366fSVenugopal Iyer misc_stat_entry->mse_stats.ms_txsdrops; 14160dc2366fSVenugopal Iyer 14170dc2366fSVenugopal Iyer head = malloc(sizeof (dladm_stat_chain_t)); 14180dc2366fSVenugopal Iyer if (head == NULL) { 14190dc2366fSVenugopal Iyer free(tx_lane_stat_entry); 14200dc2366fSVenugopal Iyer goto done; 14210dc2366fSVenugopal Iyer } 14220dc2366fSVenugopal Iyer 14230dc2366fSVenugopal Iyer head->dc_statentry = tx_lane_stat_entry; 14240dc2366fSVenugopal Iyer head->dc_next = NULL; 14250dc2366fSVenugopal Iyer 14260dc2366fSVenugopal Iyer done: 14270dc2366fSVenugopal Iyer return (head); 14280dc2366fSVenugopal Iyer } 14290dc2366fSVenugopal Iyer 14300dc2366fSVenugopal Iyer static dladm_stat_chain_t * 14310dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_stats(const char *linkname) 14320dc2366fSVenugopal Iyer { 14330dc2366fSVenugopal Iyer uint_t tx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 14340dc2366fSVenugopal Iyer uint_t tx_hwlane_idlist_size; 14350dc2366fSVenugopal Iyer 14360dc2366fSVenugopal Iyer i_dlstat_get_idlist(linkname, DLSTAT_TX_HWLANE_IDLIST, 14370dc2366fSVenugopal Iyer tx_hwlane_idlist, &tx_hwlane_idlist_size); 14380dc2366fSVenugopal Iyer 14390dc2366fSVenugopal Iyer return (i_dlstat_query_stats(linkname, DLSTAT_MAC_TX_HWLANE, 14400dc2366fSVenugopal Iyer tx_hwlane_idlist, tx_hwlane_idlist_size, 14410dc2366fSVenugopal Iyer i_dlstat_tx_hwlane_retrieve_stat)); 14420dc2366fSVenugopal Iyer } 14430dc2366fSVenugopal Iyer 14440dc2366fSVenugopal Iyer /*ARGSUSED*/ 14450dc2366fSVenugopal Iyer static dladm_stat_chain_t * 14460dc2366fSVenugopal Iyer i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid, 14470dc2366fSVenugopal Iyer const char *linkname) 14480dc2366fSVenugopal Iyer { 14490dc2366fSVenugopal Iyer return (i_dlstat_query_stats(linkname, DLSTAT_MAC_TX_SWLANE, 14500dc2366fSVenugopal Iyer default_idlist, default_idlist_size, 14510dc2366fSVenugopal Iyer i_dlstat_tx_swlane_retrieve_stat)); 14520dc2366fSVenugopal Iyer } 14530dc2366fSVenugopal Iyer 14540dc2366fSVenugopal Iyer void * 14550dc2366fSVenugopal Iyer dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid) 14560dc2366fSVenugopal Iyer { 14570dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 14580dc2366fSVenugopal Iyer dladm_stat_chain_t *bcast_stats = NULL; 14590dc2366fSVenugopal Iyer dladm_stat_chain_t *defunctlane_stats = NULL; 14600dc2366fSVenugopal Iyer dladm_stat_chain_t *lane_stats; 14610dc2366fSVenugopal Iyer char linkname[MAXLINKNAMELEN]; 14620dc2366fSVenugopal Iyer boolean_t is_legacy_driver; 14630dc2366fSVenugopal Iyer 14640dc2366fSVenugopal Iyer if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 14650dc2366fSVenugopal Iyer DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 14660dc2366fSVenugopal Iyer goto done; 14670dc2366fSVenugopal Iyer } 14680dc2366fSVenugopal Iyer 14690dc2366fSVenugopal Iyer /* Check if it is legacy driver */ 14700dc2366fSVenugopal Iyer if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT, 14710dc2366fSVenugopal Iyer "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) { 14720dc2366fSVenugopal Iyer goto done; 14730dc2366fSVenugopal Iyer } 14740dc2366fSVenugopal Iyer 14750dc2366fSVenugopal Iyer if (is_legacy_driver) { 14760dc2366fSVenugopal Iyer head = i_dlstat_legacy_tx_lane_stats(linkname); 14770dc2366fSVenugopal Iyer goto done; 14780dc2366fSVenugopal Iyer } 14790dc2366fSVenugopal Iyer 14800dc2366fSVenugopal Iyer bcast_stats = i_dlstat_tx_bcast_stats(linkname); 14810dc2366fSVenugopal Iyer defunctlane_stats = i_dlstat_tx_defunctlane_stats(linkname); 14820dc2366fSVenugopal Iyer lane_stats = i_dlstat_tx_hwlane_stats(linkname); 14830dc2366fSVenugopal Iyer if (lane_stats == NULL) 14840dc2366fSVenugopal Iyer lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname); 14850dc2366fSVenugopal Iyer 14860dc2366fSVenugopal Iyer head = i_dlstat_join_lists(bcast_stats, defunctlane_stats); 14870dc2366fSVenugopal Iyer head = i_dlstat_join_lists(head, lane_stats); 14880dc2366fSVenugopal Iyer 14890dc2366fSVenugopal Iyer done: 14900dc2366fSVenugopal Iyer return (head); 14910dc2366fSVenugopal Iyer } 14920dc2366fSVenugopal Iyer 14930dc2366fSVenugopal Iyer /* Rx lane total statistic specific functions */ 14940dc2366fSVenugopal Iyer void * 14950dc2366fSVenugopal Iyer dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid) 14960dc2366fSVenugopal Iyer { 14970dc2366fSVenugopal Iyer dladm_stat_chain_t *total_head = NULL; 14980dc2366fSVenugopal Iyer dladm_stat_chain_t *rx_lane_head, *curr; 14990dc2366fSVenugopal Iyer rx_lane_stat_entry_t *total_stats; 15000dc2366fSVenugopal Iyer 15010dc2366fSVenugopal Iyer /* Get per rx lane stats */ 15020dc2366fSVenugopal Iyer rx_lane_head = dlstat_rx_lane_stats(dh, linkid); 15030dc2366fSVenugopal Iyer if (rx_lane_head == NULL) 15040dc2366fSVenugopal Iyer goto done; 15050dc2366fSVenugopal Iyer 15060dc2366fSVenugopal Iyer total_stats = calloc(1, sizeof (rx_lane_stat_entry_t)); 15070dc2366fSVenugopal Iyer if (total_stats == NULL) 15080dc2366fSVenugopal Iyer goto done; 15090dc2366fSVenugopal Iyer 15100dc2366fSVenugopal Iyer total_stats->rle_index = DLSTAT_INVALID_ENTRY; 15110dc2366fSVenugopal Iyer total_stats->rle_id = DLSTAT_INVALID_ENTRY; 15120dc2366fSVenugopal Iyer 15130dc2366fSVenugopal Iyer for (curr = rx_lane_head; curr != NULL; curr = curr->dc_next) { 15140dc2366fSVenugopal Iyer rx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry; 15150dc2366fSVenugopal Iyer 15160dc2366fSVenugopal Iyer i_dlstat_sum_stats(&total_stats->rle_stats, 15170dc2366fSVenugopal Iyer &curr_lane_stats->rle_stats, &total_stats->rle_stats, 15180dc2366fSVenugopal Iyer rx_lane_stats_list, RX_LANE_STAT_SIZE); 15190dc2366fSVenugopal Iyer } 15200dc2366fSVenugopal Iyer 15210dc2366fSVenugopal Iyer total_head = malloc(sizeof (dladm_stat_chain_t)); 15220dc2366fSVenugopal Iyer if (total_head == NULL) { 15230dc2366fSVenugopal Iyer free(total_stats); 15240dc2366fSVenugopal Iyer goto done; 15250dc2366fSVenugopal Iyer } 15260dc2366fSVenugopal Iyer 15270dc2366fSVenugopal Iyer total_head->dc_statentry = total_stats; 15280dc2366fSVenugopal Iyer (void) strlcpy(total_head->dc_statheader, "mac_rx_lane_total", 15290dc2366fSVenugopal Iyer sizeof (total_head->dc_statheader)); 15300dc2366fSVenugopal Iyer total_head->dc_next = NULL; 15310dc2366fSVenugopal Iyer free(rx_lane_head); 15320dc2366fSVenugopal Iyer 15330dc2366fSVenugopal Iyer done: 15340dc2366fSVenugopal Iyer return (total_head); 15350dc2366fSVenugopal Iyer } 15360dc2366fSVenugopal Iyer 15370dc2366fSVenugopal Iyer /* Tx lane total statistic specific functions */ 15380dc2366fSVenugopal Iyer void * 15390dc2366fSVenugopal Iyer dlstat_tx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid) 15400dc2366fSVenugopal Iyer { 15410dc2366fSVenugopal Iyer dladm_stat_chain_t *total_head = NULL; 15420dc2366fSVenugopal Iyer dladm_stat_chain_t *tx_lane_head, *curr; 15430dc2366fSVenugopal Iyer tx_lane_stat_entry_t *total_stats; 15440dc2366fSVenugopal Iyer 15450dc2366fSVenugopal Iyer /* Get per tx lane stats */ 15460dc2366fSVenugopal Iyer tx_lane_head = dlstat_tx_lane_stats(dh, linkid); 15470dc2366fSVenugopal Iyer if (tx_lane_head == NULL) 15480dc2366fSVenugopal Iyer goto done; 15490dc2366fSVenugopal Iyer 15500dc2366fSVenugopal Iyer total_stats = calloc(1, sizeof (tx_lane_stat_entry_t)); 15510dc2366fSVenugopal Iyer if (total_stats == NULL) 15520dc2366fSVenugopal Iyer goto done; 15530dc2366fSVenugopal Iyer 15540dc2366fSVenugopal Iyer total_stats->tle_index = DLSTAT_INVALID_ENTRY; 15550dc2366fSVenugopal Iyer total_stats->tle_id = DLSTAT_INVALID_ENTRY; 15560dc2366fSVenugopal Iyer 15570dc2366fSVenugopal Iyer for (curr = tx_lane_head; curr != NULL; curr = curr->dc_next) { 15580dc2366fSVenugopal Iyer tx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry; 15590dc2366fSVenugopal Iyer 15600dc2366fSVenugopal Iyer i_dlstat_sum_stats(&total_stats->tle_stats, 15610dc2366fSVenugopal Iyer &curr_lane_stats->tle_stats, &total_stats->tle_stats, 15620dc2366fSVenugopal Iyer tx_lane_stats_list, TX_LANE_STAT_SIZE); 15630dc2366fSVenugopal Iyer } 15640dc2366fSVenugopal Iyer 15650dc2366fSVenugopal Iyer total_head = malloc(sizeof (dladm_stat_chain_t)); 15660dc2366fSVenugopal Iyer if (total_head == NULL) { 15670dc2366fSVenugopal Iyer free(total_stats); 15680dc2366fSVenugopal Iyer goto done; 15690dc2366fSVenugopal Iyer } 15700dc2366fSVenugopal Iyer 15710dc2366fSVenugopal Iyer total_head->dc_statentry = total_stats; 15720dc2366fSVenugopal Iyer (void) strlcpy(total_head->dc_statheader, "mac_tx_lane_total", 15730dc2366fSVenugopal Iyer sizeof (total_head->dc_statheader)); 15740dc2366fSVenugopal Iyer total_head->dc_next = NULL; 15750dc2366fSVenugopal Iyer free(tx_lane_head); 15760dc2366fSVenugopal Iyer 15770dc2366fSVenugopal Iyer done: 15780dc2366fSVenugopal Iyer return (total_head); 15790dc2366fSVenugopal Iyer } 15800dc2366fSVenugopal Iyer 15810dc2366fSVenugopal Iyer /* Fanout specific functions */ 15820dc2366fSVenugopal Iyer static boolean_t 15830dc2366fSVenugopal Iyer i_dlstat_fanout_match(void *arg1, void *arg2) 15840dc2366fSVenugopal Iyer { 15850dc2366fSVenugopal Iyer fanout_stat_entry_t *s1 = arg1; 15860dc2366fSVenugopal Iyer fanout_stat_entry_t *s2 = arg2; 15870dc2366fSVenugopal Iyer 15880dc2366fSVenugopal Iyer return (s1->fe_index == s2->fe_index && 15890dc2366fSVenugopal Iyer s1->fe_id == s2->fe_id && 15900dc2366fSVenugopal Iyer s1->fe_foutindex == s2->fe_foutindex); 15910dc2366fSVenugopal Iyer } 15920dc2366fSVenugopal Iyer 15930dc2366fSVenugopal Iyer static void * 15940dc2366fSVenugopal Iyer i_dlstat_fanout_stat_entry_diff(void *arg1, void *arg2) 15950dc2366fSVenugopal Iyer { 15960dc2366fSVenugopal Iyer fanout_stat_entry_t *s1 = arg1; 15970dc2366fSVenugopal Iyer fanout_stat_entry_t *s2 = arg2; 15980dc2366fSVenugopal Iyer fanout_stat_entry_t *diff_entry; 15990dc2366fSVenugopal Iyer 16000dc2366fSVenugopal Iyer diff_entry = malloc(sizeof (fanout_stat_entry_t)); 16010dc2366fSVenugopal Iyer if (diff_entry == NULL) 16020dc2366fSVenugopal Iyer goto done; 16030dc2366fSVenugopal Iyer 16040dc2366fSVenugopal Iyer diff_entry->fe_index = s1->fe_index; 16050dc2366fSVenugopal Iyer diff_entry->fe_id = s1->fe_id; 16060dc2366fSVenugopal Iyer diff_entry->fe_foutindex = s1->fe_foutindex; 16070dc2366fSVenugopal Iyer 16080dc2366fSVenugopal Iyer DLSTAT_DIFF_STAT(s1, s2, diff_entry, fe_stats, fanout_stats_list, 16090dc2366fSVenugopal Iyer FANOUT_STAT_SIZE); 16100dc2366fSVenugopal Iyer 16110dc2366fSVenugopal Iyer done: 16120dc2366fSVenugopal Iyer return (diff_entry); 16130dc2366fSVenugopal Iyer } 16140dc2366fSVenugopal Iyer 16150dc2366fSVenugopal Iyer static void * 16160dc2366fSVenugopal Iyer i_dlstat_fanout_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 16170dc2366fSVenugopal Iyer { 16180dc2366fSVenugopal Iyer fanout_stat_entry_t *fanout_stat_entry; 16190dc2366fSVenugopal Iyer 16200dc2366fSVenugopal Iyer fanout_stat_entry = calloc(1, sizeof (fanout_stat_entry_t)); 16210dc2366fSVenugopal Iyer if (fanout_stat_entry == NULL) 16220dc2366fSVenugopal Iyer goto done; 16230dc2366fSVenugopal Iyer 16240dc2366fSVenugopal Iyer /* Set by the caller later */ 16250dc2366fSVenugopal Iyer fanout_stat_entry->fe_index = DLSTAT_INVALID_ENTRY; 16260dc2366fSVenugopal Iyer fanout_stat_entry->fe_id = DLSTAT_INVALID_ENTRY; 16270dc2366fSVenugopal Iyer 16280dc2366fSVenugopal Iyer fanout_stat_entry->fe_foutindex = i; 16290dc2366fSVenugopal Iyer 16300dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, &fanout_stat_entry->fe_stats, 16310dc2366fSVenugopal Iyer fanout_stats_list, FANOUT_STAT_SIZE); 16320dc2366fSVenugopal Iyer 16330dc2366fSVenugopal Iyer done: 16340dc2366fSVenugopal Iyer return (fanout_stat_entry); 16350dc2366fSVenugopal Iyer } 16360dc2366fSVenugopal Iyer 16370dc2366fSVenugopal Iyer static void * 16380dc2366fSVenugopal Iyer i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid, 16390dc2366fSVenugopal Iyer uint_t idlist[], uint_t idlist_size, 16400dc2366fSVenugopal Iyer const char *modname, const char *prefix) 16410dc2366fSVenugopal Iyer { 16420dc2366fSVenugopal Iyer int i; 16430dc2366fSVenugopal Iyer char statprefix[MAXLINKNAMELEN]; 16440dc2366fSVenugopal Iyer char linkname[MAXLINKNAMELEN]; 16450dc2366fSVenugopal Iyer dladm_stat_chain_t *curr, *curr_head; 16460dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL, *prev = NULL; 16470dc2366fSVenugopal Iyer uint_t fanout_idlist[MAX_RINGS_PER_GROUP]; 16480dc2366fSVenugopal Iyer uint_t fanout_idlist_size; 16490dc2366fSVenugopal Iyer 16500dc2366fSVenugopal Iyer if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 16510dc2366fSVenugopal Iyer DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 16520dc2366fSVenugopal Iyer return (NULL); 16530dc2366fSVenugopal Iyer } 16540dc2366fSVenugopal Iyer 16550dc2366fSVenugopal Iyer i_dlstat_get_idlist(linkname, DLSTAT_FANOUT_IDLIST, 16560dc2366fSVenugopal Iyer fanout_idlist, &fanout_idlist_size); 16570dc2366fSVenugopal Iyer 16580dc2366fSVenugopal Iyer for (i = 0; i < idlist_size; i++) { 16590dc2366fSVenugopal Iyer uint_t index = idlist[i]; 16600dc2366fSVenugopal Iyer 16610dc2366fSVenugopal Iyer (void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout", 16620dc2366fSVenugopal Iyer prefix, index); 16630dc2366fSVenugopal Iyer 16640dc2366fSVenugopal Iyer curr_head = i_dlstat_query_stats(modname, statprefix, 16650dc2366fSVenugopal Iyer fanout_idlist, fanout_idlist_size, 16660dc2366fSVenugopal Iyer i_dlstat_fanout_retrieve_stat); 16670dc2366fSVenugopal Iyer 16680dc2366fSVenugopal Iyer if (curr_head == NULL) /* Last lane */ 16690dc2366fSVenugopal Iyer break; 16700dc2366fSVenugopal Iyer 16710dc2366fSVenugopal Iyer if (head == NULL) /* First lane */ 16720dc2366fSVenugopal Iyer head = curr_head; 16730dc2366fSVenugopal Iyer else /* Link new lane list to end of previous lane list */ 16740dc2366fSVenugopal Iyer prev->dc_next = curr_head; 16750dc2366fSVenugopal Iyer 16760dc2366fSVenugopal Iyer /* Walk new lane list and set ids */ 16770dc2366fSVenugopal Iyer for (curr = curr_head; curr != NULL; curr = curr->dc_next) { 16780dc2366fSVenugopal Iyer fanout_stat_entry_t *curr_stats = curr->dc_statentry; 16790dc2366fSVenugopal Iyer 16800dc2366fSVenugopal Iyer curr_stats->fe_index = index; 16810dc2366fSVenugopal Iyer curr_stats->fe_id = L_HWLANE; 16820dc2366fSVenugopal Iyer /* 16830dc2366fSVenugopal Iyer * Save last pointer of previous linked list. 16840dc2366fSVenugopal Iyer * This pointer is used to chain linked lists 16850dc2366fSVenugopal Iyer * generated in each iteration. 16860dc2366fSVenugopal Iyer */ 16870dc2366fSVenugopal Iyer prev = curr; 16880dc2366fSVenugopal Iyer } 16890dc2366fSVenugopal Iyer } 16900dc2366fSVenugopal Iyer 16910dc2366fSVenugopal Iyer return (head); 16920dc2366fSVenugopal Iyer } 16930dc2366fSVenugopal Iyer 16940dc2366fSVenugopal Iyer void * 16950dc2366fSVenugopal Iyer dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid, 16960dc2366fSVenugopal Iyer const char *linkname) 16970dc2366fSVenugopal Iyer { 16980dc2366fSVenugopal Iyer return (i_dlstat_query_fanout_stats(dh, linkid, 16990dc2366fSVenugopal Iyer default_idlist, default_idlist_size, linkname, 17000dc2366fSVenugopal Iyer DLSTAT_MAC_RX_SWLANE)); 17010dc2366fSVenugopal Iyer } 17020dc2366fSVenugopal Iyer 17030dc2366fSVenugopal Iyer void * 17040dc2366fSVenugopal Iyer dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid, 17050dc2366fSVenugopal Iyer const char *linkname) 17060dc2366fSVenugopal Iyer { 17070dc2366fSVenugopal Iyer uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP]; 17080dc2366fSVenugopal Iyer uint_t rx_hwlane_idlist_size; 17090dc2366fSVenugopal Iyer 17100dc2366fSVenugopal Iyer i_dlstat_get_idlist(linkname, DLSTAT_RX_HWLANE_IDLIST, 17110dc2366fSVenugopal Iyer rx_hwlane_idlist, &rx_hwlane_idlist_size); 17120dc2366fSVenugopal Iyer 17130dc2366fSVenugopal Iyer return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist, 17140dc2366fSVenugopal Iyer rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE)); 17150dc2366fSVenugopal Iyer } 17160dc2366fSVenugopal Iyer 17170dc2366fSVenugopal Iyer void * 17180dc2366fSVenugopal Iyer dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid) 17190dc2366fSVenugopal Iyer { 17200dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 17210dc2366fSVenugopal Iyer dladm_stat_chain_t *fout_hwlane_stats; 17220dc2366fSVenugopal Iyer dladm_stat_chain_t *fout_swlane_and_local_stats; 17230dc2366fSVenugopal Iyer fanout_stat_entry_t *fout_stats; 17240dc2366fSVenugopal Iyer char linkname[MAXLINKNAMELEN]; 17250dc2366fSVenugopal Iyer 17260dc2366fSVenugopal Iyer if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 17270dc2366fSVenugopal Iyer DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 17280dc2366fSVenugopal Iyer goto done; 17290dc2366fSVenugopal Iyer } 17300dc2366fSVenugopal Iyer 17310dc2366fSVenugopal Iyer fout_swlane_and_local_stats = 17320dc2366fSVenugopal Iyer dlstat_fanout_swlane_and_local_stats(dh, linkid, linkname); 17330dc2366fSVenugopal Iyer fout_hwlane_stats = dlstat_fanout_hwlane_stats(dh, linkid, linkname); 17340dc2366fSVenugopal Iyer 17350dc2366fSVenugopal Iyer if (fout_swlane_and_local_stats == NULL) { 17360dc2366fSVenugopal Iyer head = fout_hwlane_stats; 17370dc2366fSVenugopal Iyer goto done; 17380dc2366fSVenugopal Iyer } 17390dc2366fSVenugopal Iyer 17400dc2366fSVenugopal Iyer fout_stats = fout_swlane_and_local_stats->dc_statentry; 17410dc2366fSVenugopal Iyer 17420dc2366fSVenugopal Iyer if (fout_hwlane_stats != NULL) { /* hwlane(s), only local traffic */ 17430dc2366fSVenugopal Iyer fout_stats->fe_id = L_LOCAL; 17440dc2366fSVenugopal Iyer fout_stats->fe_index = DLSTAT_INVALID_ENTRY; 17450dc2366fSVenugopal Iyer } else { /* no hwlane, mix of local+sw classified */ 17460dc2366fSVenugopal Iyer fout_stats->fe_id = L_LCLSWLANE; 17470dc2366fSVenugopal Iyer fout_stats->fe_index = DLSTAT_INVALID_ENTRY; 17480dc2366fSVenugopal Iyer } 17490dc2366fSVenugopal Iyer 17500dc2366fSVenugopal Iyer fout_swlane_and_local_stats->dc_next = fout_hwlane_stats; 17510dc2366fSVenugopal Iyer head = fout_swlane_and_local_stats; 17520dc2366fSVenugopal Iyer 17530dc2366fSVenugopal Iyer done: 17540dc2366fSVenugopal Iyer return (head); 17550dc2366fSVenugopal Iyer } 17560dc2366fSVenugopal Iyer 17570dc2366fSVenugopal Iyer /* Rx ring statistic specific functions */ 17580dc2366fSVenugopal Iyer static boolean_t 17590dc2366fSVenugopal Iyer i_dlstat_rx_ring_match(void *arg1, void *arg2) 17600dc2366fSVenugopal Iyer { 17610dc2366fSVenugopal Iyer rx_lane_stat_entry_t *s1 = arg1; 17620dc2366fSVenugopal Iyer rx_lane_stat_entry_t *s2 = arg2; 17630dc2366fSVenugopal Iyer 17640dc2366fSVenugopal Iyer return (s1->rle_index == s2->rle_index); 17650dc2366fSVenugopal Iyer } 17660dc2366fSVenugopal Iyer 17670dc2366fSVenugopal Iyer static void * 17680dc2366fSVenugopal Iyer i_dlstat_rx_ring_stat_entry_diff(void *arg1, void *arg2) 17690dc2366fSVenugopal Iyer { 17700dc2366fSVenugopal Iyer ring_stat_entry_t *s1 = arg1; 17710dc2366fSVenugopal Iyer ring_stat_entry_t *s2 = arg2; 17720dc2366fSVenugopal Iyer ring_stat_entry_t *diff_entry; 17730dc2366fSVenugopal Iyer 17740dc2366fSVenugopal Iyer diff_entry = malloc(sizeof (ring_stat_entry_t)); 17750dc2366fSVenugopal Iyer if (diff_entry == NULL) 17760dc2366fSVenugopal Iyer goto done; 17770dc2366fSVenugopal Iyer 17780dc2366fSVenugopal Iyer diff_entry->re_index = s1->re_index; 17790dc2366fSVenugopal Iyer 17800dc2366fSVenugopal Iyer DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, rx_ring_stats_list, 17810dc2366fSVenugopal Iyer RX_RING_STAT_SIZE); 17820dc2366fSVenugopal Iyer 17830dc2366fSVenugopal Iyer done: 17840dc2366fSVenugopal Iyer return (diff_entry); 17850dc2366fSVenugopal Iyer } 17860dc2366fSVenugopal Iyer 17870dc2366fSVenugopal Iyer static void * 17880dc2366fSVenugopal Iyer i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 17890dc2366fSVenugopal Iyer { 17900dc2366fSVenugopal Iyer ring_stat_entry_t *rx_ring_stat_entry; 17910dc2366fSVenugopal Iyer 17920dc2366fSVenugopal Iyer rx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t)); 17930dc2366fSVenugopal Iyer if (rx_ring_stat_entry == NULL) 17940dc2366fSVenugopal Iyer goto done; 17950dc2366fSVenugopal Iyer 17960dc2366fSVenugopal Iyer rx_ring_stat_entry->re_index = i; 17970dc2366fSVenugopal Iyer 17980dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, &rx_ring_stat_entry->re_stats, 17990dc2366fSVenugopal Iyer rx_ring_stats_list, RX_RING_STAT_SIZE); 18000dc2366fSVenugopal Iyer 18010dc2366fSVenugopal Iyer done: 18020dc2366fSVenugopal Iyer return (rx_ring_stat_entry); 18030dc2366fSVenugopal Iyer } 18040dc2366fSVenugopal Iyer 18050dc2366fSVenugopal Iyer void * 18060dc2366fSVenugopal Iyer dlstat_rx_ring_stats(dladm_handle_t dh, datalink_id_t linkid) 18070dc2366fSVenugopal Iyer { 18080dc2366fSVenugopal Iyer uint_t rx_ring_idlist[MAX_RINGS_PER_GROUP]; 18090dc2366fSVenugopal Iyer uint_t rx_ring_idlist_size; 18100dc2366fSVenugopal Iyer dladm_phys_attr_t dpa; 18110dc2366fSVenugopal Iyer char linkname[MAXLINKNAMELEN]; 18120dc2366fSVenugopal Iyer char *modname; 18130dc2366fSVenugopal Iyer datalink_class_t class; 18140dc2366fSVenugopal Iyer 18150dc2366fSVenugopal Iyer /* 18160dc2366fSVenugopal Iyer * kstats corresponding to physical device rings continue to use 18170dc2366fSVenugopal Iyer * device names even if the link is renamed using dladm rename-link. 18180dc2366fSVenugopal Iyer * Thus, given a linkid, we lookup the physical device name. 18190dc2366fSVenugopal Iyer * However, if an aggr is renamed, kstats corresponding to its 18200dc2366fSVenugopal Iyer * pseudo rings are renamed as well. 18210dc2366fSVenugopal Iyer */ 18220dc2366fSVenugopal Iyer if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname, 18230dc2366fSVenugopal Iyer DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 18240dc2366fSVenugopal Iyer return (NULL); 18250dc2366fSVenugopal Iyer } 18260dc2366fSVenugopal Iyer 18270dc2366fSVenugopal Iyer if (class != DATALINK_CLASS_AGGR) { 18280dc2366fSVenugopal Iyer if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 18290dc2366fSVenugopal Iyer DLADM_STATUS_OK) { 18300dc2366fSVenugopal Iyer return (NULL); 18310dc2366fSVenugopal Iyer } 18320dc2366fSVenugopal Iyer modname = dpa.dp_dev; 18330dc2366fSVenugopal Iyer } else 18340dc2366fSVenugopal Iyer modname = linkname; 18350dc2366fSVenugopal Iyer 18360dc2366fSVenugopal Iyer i_dlstat_get_idlist(modname, DLSTAT_RX_RING_IDLIST, 18370dc2366fSVenugopal Iyer rx_ring_idlist, &rx_ring_idlist_size); 18380dc2366fSVenugopal Iyer 18390dc2366fSVenugopal Iyer return (i_dlstat_query_stats(modname, DLSTAT_MAC_RX_RING, 18400dc2366fSVenugopal Iyer rx_ring_idlist, rx_ring_idlist_size, 18410dc2366fSVenugopal Iyer i_dlstat_rx_ring_retrieve_stat)); 18420dc2366fSVenugopal Iyer } 18430dc2366fSVenugopal Iyer 18440dc2366fSVenugopal Iyer /* Tx ring statistic specific functions */ 18450dc2366fSVenugopal Iyer static boolean_t 18460dc2366fSVenugopal Iyer i_dlstat_tx_ring_match(void *arg1, void *arg2) 18470dc2366fSVenugopal Iyer { 18480dc2366fSVenugopal Iyer tx_lane_stat_entry_t *s1 = arg1; 18490dc2366fSVenugopal Iyer tx_lane_stat_entry_t *s2 = arg2; 18500dc2366fSVenugopal Iyer 18510dc2366fSVenugopal Iyer return (s1->tle_index == s2->tle_index); 18520dc2366fSVenugopal Iyer } 18530dc2366fSVenugopal Iyer 18540dc2366fSVenugopal Iyer static void * 18550dc2366fSVenugopal Iyer i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2) 18560dc2366fSVenugopal Iyer { 18570dc2366fSVenugopal Iyer ring_stat_entry_t *s1 = arg1; 18580dc2366fSVenugopal Iyer ring_stat_entry_t *s2 = arg2; 18590dc2366fSVenugopal Iyer ring_stat_entry_t *diff_entry; 18600dc2366fSVenugopal Iyer 18610dc2366fSVenugopal Iyer diff_entry = malloc(sizeof (ring_stat_entry_t)); 18620dc2366fSVenugopal Iyer if (diff_entry == NULL) 18630dc2366fSVenugopal Iyer goto done; 18640dc2366fSVenugopal Iyer 18650dc2366fSVenugopal Iyer diff_entry->re_index = s1->re_index; 18660dc2366fSVenugopal Iyer 18670dc2366fSVenugopal Iyer DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, tx_ring_stats_list, 18680dc2366fSVenugopal Iyer TX_RING_STAT_SIZE); 18690dc2366fSVenugopal Iyer 18700dc2366fSVenugopal Iyer done: 18710dc2366fSVenugopal Iyer return (diff_entry); 18720dc2366fSVenugopal Iyer } 18730dc2366fSVenugopal Iyer 18740dc2366fSVenugopal Iyer static void * 18750dc2366fSVenugopal Iyer i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i) 18760dc2366fSVenugopal Iyer { 18770dc2366fSVenugopal Iyer ring_stat_entry_t *tx_ring_stat_entry; 18780dc2366fSVenugopal Iyer 18790dc2366fSVenugopal Iyer tx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t)); 18800dc2366fSVenugopal Iyer if (tx_ring_stat_entry == NULL) 18810dc2366fSVenugopal Iyer goto done; 18820dc2366fSVenugopal Iyer 18830dc2366fSVenugopal Iyer tx_ring_stat_entry->re_index = i; 18840dc2366fSVenugopal Iyer 18850dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, &tx_ring_stat_entry->re_stats, 18860dc2366fSVenugopal Iyer tx_ring_stats_list, TX_RING_STAT_SIZE); 18870dc2366fSVenugopal Iyer 18880dc2366fSVenugopal Iyer done: 18890dc2366fSVenugopal Iyer return (tx_ring_stat_entry); 18900dc2366fSVenugopal Iyer } 18910dc2366fSVenugopal Iyer 18920dc2366fSVenugopal Iyer void * 18930dc2366fSVenugopal Iyer dlstat_tx_ring_stats(dladm_handle_t dh, datalink_id_t linkid) 18940dc2366fSVenugopal Iyer { 18950dc2366fSVenugopal Iyer uint_t tx_ring_idlist[MAX_RINGS_PER_GROUP]; 18960dc2366fSVenugopal Iyer uint_t tx_ring_idlist_size; 18970dc2366fSVenugopal Iyer dladm_phys_attr_t dpa; 18980dc2366fSVenugopal Iyer char linkname[MAXLINKNAMELEN]; 18990dc2366fSVenugopal Iyer char *modname; 19000dc2366fSVenugopal Iyer datalink_class_t class; 19010dc2366fSVenugopal Iyer 19020dc2366fSVenugopal Iyer /* 19030dc2366fSVenugopal Iyer * kstats corresponding to physical device rings continue to use 19040dc2366fSVenugopal Iyer * device names even if the link is renamed using dladm rename-link. 19050dc2366fSVenugopal Iyer * Thus, given a linkid, we lookup the physical device name. 19060dc2366fSVenugopal Iyer * However, if an aggr is renamed, kstats corresponding to its 19070dc2366fSVenugopal Iyer * pseudo rings are renamed as well. 19080dc2366fSVenugopal Iyer */ 19090dc2366fSVenugopal Iyer if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname, 19100dc2366fSVenugopal Iyer DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 19110dc2366fSVenugopal Iyer return (NULL); 19120dc2366fSVenugopal Iyer } 19130dc2366fSVenugopal Iyer 19140dc2366fSVenugopal Iyer if (class != DATALINK_CLASS_AGGR) { 19150dc2366fSVenugopal Iyer if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) != 19160dc2366fSVenugopal Iyer DLADM_STATUS_OK) { 19170dc2366fSVenugopal Iyer return (NULL); 19180dc2366fSVenugopal Iyer } 19190dc2366fSVenugopal Iyer modname = dpa.dp_dev; 19200dc2366fSVenugopal Iyer } else 19210dc2366fSVenugopal Iyer modname = linkname; 19220dc2366fSVenugopal Iyer 19230dc2366fSVenugopal Iyer i_dlstat_get_idlist(modname, DLSTAT_TX_RING_IDLIST, 19240dc2366fSVenugopal Iyer tx_ring_idlist, &tx_ring_idlist_size); 19250dc2366fSVenugopal Iyer 19260dc2366fSVenugopal Iyer return (i_dlstat_query_stats(modname, DLSTAT_MAC_TX_RING, 19270dc2366fSVenugopal Iyer tx_ring_idlist, tx_ring_idlist_size, 19280dc2366fSVenugopal Iyer i_dlstat_tx_ring_retrieve_stat)); 19290dc2366fSVenugopal Iyer } 19300dc2366fSVenugopal Iyer 19310dc2366fSVenugopal Iyer /* Rx ring total statistic specific functions */ 19320dc2366fSVenugopal Iyer void * 19330dc2366fSVenugopal Iyer dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid) 19340dc2366fSVenugopal Iyer { 19350dc2366fSVenugopal Iyer dladm_stat_chain_t *total_head = NULL; 19360dc2366fSVenugopal Iyer dladm_stat_chain_t *rx_ring_head, *curr; 19370dc2366fSVenugopal Iyer ring_stat_entry_t *total_stats; 19380dc2366fSVenugopal Iyer 19390dc2366fSVenugopal Iyer /* Get per rx ring stats */ 19400dc2366fSVenugopal Iyer rx_ring_head = dlstat_rx_ring_stats(dh, linkid); 19410dc2366fSVenugopal Iyer if (rx_ring_head == NULL) 19420dc2366fSVenugopal Iyer goto done; 19430dc2366fSVenugopal Iyer 19440dc2366fSVenugopal Iyer total_stats = calloc(1, sizeof (ring_stat_entry_t)); 19450dc2366fSVenugopal Iyer if (total_stats == NULL) 19460dc2366fSVenugopal Iyer goto done; 19470dc2366fSVenugopal Iyer 19480dc2366fSVenugopal Iyer total_stats->re_index = DLSTAT_INVALID_ENTRY; 19490dc2366fSVenugopal Iyer 19500dc2366fSVenugopal Iyer for (curr = rx_ring_head; curr != NULL; curr = curr->dc_next) { 19510dc2366fSVenugopal Iyer ring_stat_entry_t *curr_ring_stats = curr->dc_statentry; 19520dc2366fSVenugopal Iyer 19530dc2366fSVenugopal Iyer i_dlstat_sum_stats(&total_stats->re_stats, 19540dc2366fSVenugopal Iyer &curr_ring_stats->re_stats, &total_stats->re_stats, 19550dc2366fSVenugopal Iyer rx_ring_stats_list, RX_RING_STAT_SIZE); 19560dc2366fSVenugopal Iyer } 19570dc2366fSVenugopal Iyer 19580dc2366fSVenugopal Iyer total_head = malloc(sizeof (dladm_stat_chain_t)); 19590dc2366fSVenugopal Iyer if (total_head == NULL) { 19600dc2366fSVenugopal Iyer free(total_stats); 19610dc2366fSVenugopal Iyer goto done; 19620dc2366fSVenugopal Iyer } 19630dc2366fSVenugopal Iyer 19640dc2366fSVenugopal Iyer total_head->dc_statentry = total_stats; 19650dc2366fSVenugopal Iyer (void) strlcpy(total_head->dc_statheader, "mac_rx_ring_total", 19660dc2366fSVenugopal Iyer sizeof (total_head->dc_statheader)); 19670dc2366fSVenugopal Iyer total_head->dc_next = NULL; 19680dc2366fSVenugopal Iyer free(rx_ring_head); 19690dc2366fSVenugopal Iyer 19700dc2366fSVenugopal Iyer done: 19710dc2366fSVenugopal Iyer return (total_head); 19720dc2366fSVenugopal Iyer } 19730dc2366fSVenugopal Iyer 19740dc2366fSVenugopal Iyer /* Tx ring total statistic specific functions */ 19750dc2366fSVenugopal Iyer void * 19760dc2366fSVenugopal Iyer dlstat_tx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid) 19770dc2366fSVenugopal Iyer { 19780dc2366fSVenugopal Iyer dladm_stat_chain_t *total_head = NULL; 19790dc2366fSVenugopal Iyer dladm_stat_chain_t *tx_ring_head, *curr; 19800dc2366fSVenugopal Iyer ring_stat_entry_t *total_stats; 19810dc2366fSVenugopal Iyer 19820dc2366fSVenugopal Iyer /* Get per tx ring stats */ 19830dc2366fSVenugopal Iyer tx_ring_head = dlstat_tx_ring_stats(dh, linkid); 19840dc2366fSVenugopal Iyer if (tx_ring_head == NULL) 19850dc2366fSVenugopal Iyer goto done; 19860dc2366fSVenugopal Iyer 19870dc2366fSVenugopal Iyer total_stats = calloc(1, sizeof (ring_stat_entry_t)); 19880dc2366fSVenugopal Iyer if (total_stats == NULL) 19890dc2366fSVenugopal Iyer goto done; 19900dc2366fSVenugopal Iyer 19910dc2366fSVenugopal Iyer total_stats->re_index = DLSTAT_INVALID_ENTRY; 19920dc2366fSVenugopal Iyer 19930dc2366fSVenugopal Iyer for (curr = tx_ring_head; curr != NULL; curr = curr->dc_next) { 19940dc2366fSVenugopal Iyer ring_stat_entry_t *curr_ring_stats = curr->dc_statentry; 19950dc2366fSVenugopal Iyer 19960dc2366fSVenugopal Iyer i_dlstat_sum_stats(&total_stats->re_stats, 19970dc2366fSVenugopal Iyer &curr_ring_stats->re_stats, &total_stats->re_stats, 19980dc2366fSVenugopal Iyer tx_ring_stats_list, TX_RING_STAT_SIZE); 19990dc2366fSVenugopal Iyer } 20000dc2366fSVenugopal Iyer 20010dc2366fSVenugopal Iyer total_head = malloc(sizeof (dladm_stat_chain_t)); 20020dc2366fSVenugopal Iyer if (total_head == NULL) { 20030dc2366fSVenugopal Iyer free(total_stats); 20040dc2366fSVenugopal Iyer goto done; 20050dc2366fSVenugopal Iyer } 20060dc2366fSVenugopal Iyer 20070dc2366fSVenugopal Iyer total_head->dc_statentry = total_stats; 20080dc2366fSVenugopal Iyer (void) strlcpy(total_head->dc_statheader, "mac_tx_ring_total", 20090dc2366fSVenugopal Iyer sizeof (total_head->dc_statheader)); 20100dc2366fSVenugopal Iyer total_head->dc_next = NULL; 20110dc2366fSVenugopal Iyer free(tx_ring_head); 20120dc2366fSVenugopal Iyer 20130dc2366fSVenugopal Iyer done: 20140dc2366fSVenugopal Iyer return (total_head); 20150dc2366fSVenugopal Iyer } 20160dc2366fSVenugopal Iyer 20170dc2366fSVenugopal Iyer /* Summary statistic specific functions */ 20180dc2366fSVenugopal Iyer /*ARGSUSED*/ 20190dc2366fSVenugopal Iyer static boolean_t 20200dc2366fSVenugopal Iyer i_dlstat_total_match(void *arg1, void *arg2) 2021*62ef8476SYuri Pankov { 2022*62ef8476SYuri Pankov /* Always single entry for total */ 20230dc2366fSVenugopal Iyer return (B_TRUE); 20240dc2366fSVenugopal Iyer } 20250dc2366fSVenugopal Iyer 20260dc2366fSVenugopal Iyer static void * 20270dc2366fSVenugopal Iyer i_dlstat_total_stat_entry_diff(void *arg1, void *arg2) 20280dc2366fSVenugopal Iyer { 20290dc2366fSVenugopal Iyer total_stat_entry_t *s1 = arg1; 20300dc2366fSVenugopal Iyer total_stat_entry_t *s2 = arg2; 20310dc2366fSVenugopal Iyer total_stat_entry_t *diff_entry; 20320dc2366fSVenugopal Iyer 20330dc2366fSVenugopal Iyer diff_entry = malloc(sizeof (total_stat_entry_t)); 20340dc2366fSVenugopal Iyer if (diff_entry == NULL) 20350dc2366fSVenugopal Iyer goto done; 20360dc2366fSVenugopal Iyer 20370dc2366fSVenugopal Iyer DLSTAT_DIFF_STAT(s1, s2, diff_entry, tse_stats, total_stats_list, 20380dc2366fSVenugopal Iyer TOTAL_STAT_SIZE); 20390dc2366fSVenugopal Iyer 20400dc2366fSVenugopal Iyer done: 20410dc2366fSVenugopal Iyer return (diff_entry); 20420dc2366fSVenugopal Iyer } 20430dc2366fSVenugopal Iyer 20440dc2366fSVenugopal Iyer void * 20450dc2366fSVenugopal Iyer dlstat_total_stats(dladm_handle_t dh, datalink_id_t linkid) 20460dc2366fSVenugopal Iyer { 20470dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 20480dc2366fSVenugopal Iyer dladm_stat_chain_t *rx_total; 20490dc2366fSVenugopal Iyer dladm_stat_chain_t *tx_total; 20500dc2366fSVenugopal Iyer total_stat_entry_t *total_stat_entry; 20510dc2366fSVenugopal Iyer rx_lane_stat_entry_t *rx_lane_stat_entry; 20520dc2366fSVenugopal Iyer tx_lane_stat_entry_t *tx_lane_stat_entry; 20530dc2366fSVenugopal Iyer 20540dc2366fSVenugopal Iyer /* Get total rx lane stats */ 20550dc2366fSVenugopal Iyer rx_total = dlstat_rx_lane_total_stats(dh, linkid); 20560dc2366fSVenugopal Iyer if (rx_total == NULL) 20570dc2366fSVenugopal Iyer goto done; 20580dc2366fSVenugopal Iyer 20590dc2366fSVenugopal Iyer /* Get total tx lane stats */ 20600dc2366fSVenugopal Iyer tx_total = dlstat_tx_lane_total_stats(dh, linkid); 20610dc2366fSVenugopal Iyer if (tx_total == NULL) 20620dc2366fSVenugopal Iyer goto done; 20630dc2366fSVenugopal Iyer 20640dc2366fSVenugopal Iyer /* Build total stat */ 20650dc2366fSVenugopal Iyer total_stat_entry = calloc(1, sizeof (total_stat_entry_t)); 20660dc2366fSVenugopal Iyer if (total_stat_entry == NULL) 20670dc2366fSVenugopal Iyer goto done; 20680dc2366fSVenugopal Iyer 20690dc2366fSVenugopal Iyer rx_lane_stat_entry = rx_total->dc_statentry; 20700dc2366fSVenugopal Iyer tx_lane_stat_entry = tx_total->dc_statentry; 20710dc2366fSVenugopal Iyer 20720dc2366fSVenugopal Iyer /* Extract total rx ipackets, rbytes */ 20730dc2366fSVenugopal Iyer total_stat_entry->tse_stats.ts_ipackets = 20740dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_ipackets; 20750dc2366fSVenugopal Iyer total_stat_entry->tse_stats.ts_rbytes = 20760dc2366fSVenugopal Iyer rx_lane_stat_entry->rle_stats.rl_rbytes; 20770dc2366fSVenugopal Iyer 20780dc2366fSVenugopal Iyer /* Extract total tx opackets, obytes */ 20790dc2366fSVenugopal Iyer total_stat_entry->tse_stats.ts_opackets = 20800dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_stats.tl_opackets; 20810dc2366fSVenugopal Iyer total_stat_entry->tse_stats.ts_obytes = 20820dc2366fSVenugopal Iyer tx_lane_stat_entry->tle_stats.tl_obytes; 20830dc2366fSVenugopal Iyer 20840dc2366fSVenugopal Iyer head = malloc(sizeof (dladm_stat_chain_t)); 20850dc2366fSVenugopal Iyer if (head == NULL) { 20860dc2366fSVenugopal Iyer free(total_stat_entry); 20870dc2366fSVenugopal Iyer goto done; 20880dc2366fSVenugopal Iyer } 20890dc2366fSVenugopal Iyer 20900dc2366fSVenugopal Iyer head->dc_statentry = total_stat_entry; 20910dc2366fSVenugopal Iyer (void) strlcpy(head->dc_statheader, "mac_lane_total", 20920dc2366fSVenugopal Iyer sizeof (head->dc_statheader)); 20930dc2366fSVenugopal Iyer head->dc_next = NULL; 20940dc2366fSVenugopal Iyer free(rx_total); 20950dc2366fSVenugopal Iyer free(tx_total); 20960dc2366fSVenugopal Iyer 20970dc2366fSVenugopal Iyer done: 20980dc2366fSVenugopal Iyer return (head); 20990dc2366fSVenugopal Iyer } 21000dc2366fSVenugopal Iyer 21010dc2366fSVenugopal Iyer /* Aggr total statistic(summed across all component ports) specific functions */ 21020dc2366fSVenugopal Iyer void * 21030dc2366fSVenugopal Iyer dlstat_aggr_total_stats(dladm_stat_chain_t *head) 21040dc2366fSVenugopal Iyer { 21050dc2366fSVenugopal Iyer dladm_stat_chain_t *curr; 21060dc2366fSVenugopal Iyer dladm_stat_chain_t *total_head; 21070dc2366fSVenugopal Iyer aggr_port_stat_entry_t *total_stats; 21080dc2366fSVenugopal Iyer 21090dc2366fSVenugopal Iyer total_stats = calloc(1, sizeof (aggr_port_stat_entry_t)); 21100dc2366fSVenugopal Iyer if (total_stats == NULL) 21110dc2366fSVenugopal Iyer goto done; 21120dc2366fSVenugopal Iyer 21130dc2366fSVenugopal Iyer total_stats->ape_portlinkid = DATALINK_INVALID_LINKID; 21140dc2366fSVenugopal Iyer 21150dc2366fSVenugopal Iyer for (curr = head; curr != NULL; curr = curr->dc_next) { 21160dc2366fSVenugopal Iyer aggr_port_stat_entry_t *curr_aggr_port_stats; 21170dc2366fSVenugopal Iyer 21180dc2366fSVenugopal Iyer curr_aggr_port_stats = curr->dc_statentry; 21190dc2366fSVenugopal Iyer 21200dc2366fSVenugopal Iyer i_dlstat_sum_stats(&total_stats->ape_stats, 21210dc2366fSVenugopal Iyer &curr_aggr_port_stats->ape_stats, &total_stats->ape_stats, 21220dc2366fSVenugopal Iyer aggr_port_stats_list, AGGR_PORT_STAT_SIZE); 21230dc2366fSVenugopal Iyer } 21240dc2366fSVenugopal Iyer 21250dc2366fSVenugopal Iyer total_head = malloc(sizeof (dladm_stat_chain_t)); 21260dc2366fSVenugopal Iyer if (total_head == NULL) { 21270dc2366fSVenugopal Iyer free(total_stats); 21280dc2366fSVenugopal Iyer goto done; 21290dc2366fSVenugopal Iyer } 21300dc2366fSVenugopal Iyer 21310dc2366fSVenugopal Iyer total_head->dc_statentry = total_stats; 21320dc2366fSVenugopal Iyer total_head->dc_next = NULL; 21330dc2366fSVenugopal Iyer 21340dc2366fSVenugopal Iyer done: 21350dc2366fSVenugopal Iyer return (total_head); 21360dc2366fSVenugopal Iyer } 21370dc2366fSVenugopal Iyer 21380dc2366fSVenugopal Iyer /* Aggr port statistic specific functions */ 21390dc2366fSVenugopal Iyer static boolean_t 21400dc2366fSVenugopal Iyer i_dlstat_aggr_port_match(void *arg1, void *arg2) 21410dc2366fSVenugopal Iyer { 21420dc2366fSVenugopal Iyer aggr_port_stat_entry_t *s1 = arg1; 21430dc2366fSVenugopal Iyer aggr_port_stat_entry_t *s2 = arg2; 21440dc2366fSVenugopal Iyer 21450dc2366fSVenugopal Iyer return (s1->ape_portlinkid == s2->ape_portlinkid); 21460dc2366fSVenugopal Iyer } 21470dc2366fSVenugopal Iyer 21480dc2366fSVenugopal Iyer static void * 21490dc2366fSVenugopal Iyer i_dlstat_aggr_port_stat_entry_diff(void *arg1, void *arg2) 21500dc2366fSVenugopal Iyer { 21510dc2366fSVenugopal Iyer aggr_port_stat_entry_t *s1 = arg1; 21520dc2366fSVenugopal Iyer aggr_port_stat_entry_t *s2 = arg2; 21530dc2366fSVenugopal Iyer aggr_port_stat_entry_t *diff_entry; 21540dc2366fSVenugopal Iyer 21550dc2366fSVenugopal Iyer diff_entry = malloc(sizeof (aggr_port_stat_entry_t)); 21560dc2366fSVenugopal Iyer if (diff_entry == NULL) 21570dc2366fSVenugopal Iyer goto done; 21580dc2366fSVenugopal Iyer 21590dc2366fSVenugopal Iyer diff_entry->ape_portlinkid = s1->ape_portlinkid; 21600dc2366fSVenugopal Iyer 21610dc2366fSVenugopal Iyer DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list, 21620dc2366fSVenugopal Iyer AGGR_PORT_STAT_SIZE); 21630dc2366fSVenugopal Iyer 21640dc2366fSVenugopal Iyer done: 21650dc2366fSVenugopal Iyer return (diff_entry); 21660dc2366fSVenugopal Iyer } 21670dc2366fSVenugopal Iyer 21680dc2366fSVenugopal Iyer /* 21690dc2366fSVenugopal Iyer * Query dls stats for the aggr port. This results in query for stats into 21700dc2366fSVenugopal Iyer * the corresponding device driver. 21710dc2366fSVenugopal Iyer */ 21720dc2366fSVenugopal Iyer static aggr_port_stat_entry_t * 21730dc2366fSVenugopal Iyer i_dlstat_single_port_stats(const char *portname, datalink_id_t linkid) 21740dc2366fSVenugopal Iyer { 21750dc2366fSVenugopal Iyer kstat_ctl_t *kcp; 21760dc2366fSVenugopal Iyer kstat_t *ksp; 21770dc2366fSVenugopal Iyer char module[DLPI_LINKNAME_MAX]; 21780dc2366fSVenugopal Iyer uint_t instance; 21790dc2366fSVenugopal Iyer aggr_port_stat_entry_t *aggr_port_stat_entry = NULL; 21800dc2366fSVenugopal Iyer 21810dc2366fSVenugopal Iyer if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK) 21820dc2366fSVenugopal Iyer goto done; 21830dc2366fSVenugopal Iyer 21840dc2366fSVenugopal Iyer if ((kcp = kstat_open()) == NULL) { 21850dc2366fSVenugopal Iyer warn("kstat open operation failed"); 21860dc2366fSVenugopal Iyer return (NULL); 21870dc2366fSVenugopal Iyer } 21880dc2366fSVenugopal Iyer 21890dc2366fSVenugopal Iyer ksp = dladm_kstat_lookup(kcp, module, instance, "mac", NULL); 21900dc2366fSVenugopal Iyer if (ksp == NULL) 21910dc2366fSVenugopal Iyer goto done; 21920dc2366fSVenugopal Iyer 21930dc2366fSVenugopal Iyer aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t)); 21940dc2366fSVenugopal Iyer if (aggr_port_stat_entry == NULL) 21950dc2366fSVenugopal Iyer goto done; 21960dc2366fSVenugopal Iyer 21970dc2366fSVenugopal Iyer /* Save port's linkid */ 21980dc2366fSVenugopal Iyer aggr_port_stat_entry->ape_portlinkid = linkid; 21990dc2366fSVenugopal Iyer 22000dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, &aggr_port_stat_entry->ape_stats, 22010dc2366fSVenugopal Iyer aggr_port_stats_list, AGGR_PORT_STAT_SIZE); 22020dc2366fSVenugopal Iyer done: 22030dc2366fSVenugopal Iyer (void) kstat_close(kcp); 22040dc2366fSVenugopal Iyer return (aggr_port_stat_entry); 22050dc2366fSVenugopal Iyer } 22060dc2366fSVenugopal Iyer 22070dc2366fSVenugopal Iyer void * 22080dc2366fSVenugopal Iyer dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid) 22090dc2366fSVenugopal Iyer { 22100dc2366fSVenugopal Iyer dladm_aggr_grp_attr_t ginfo; 22110dc2366fSVenugopal Iyer int i; 22120dc2366fSVenugopal Iyer dladm_aggr_port_attr_t *portp; 22130dc2366fSVenugopal Iyer dladm_phys_attr_t dpa; 22140dc2366fSVenugopal Iyer aggr_port_stat_entry_t *aggr_port_stat_entry; 22150dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL, *prev = NULL, *curr; 22160dc2366fSVenugopal Iyer dladm_stat_chain_t *total_stats; 22170dc2366fSVenugopal Iyer 22180dc2366fSVenugopal Iyer /* Get aggr info */ 22190dc2366fSVenugopal Iyer bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t)); 22200dc2366fSVenugopal Iyer if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE) 22210dc2366fSVenugopal Iyer != DLADM_STATUS_OK) 22220dc2366fSVenugopal Iyer goto done; 22230dc2366fSVenugopal Iyer /* For every port that is member of this aggr do */ 22240dc2366fSVenugopal Iyer for (i = 0; i < ginfo.lg_nports; i++) { 22250dc2366fSVenugopal Iyer portp = &(ginfo.lg_ports[i]); 22260dc2366fSVenugopal Iyer if (dladm_phys_info(dh, portp->lp_linkid, &dpa, 22270dc2366fSVenugopal Iyer DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) { 22280dc2366fSVenugopal Iyer goto done; 22290dc2366fSVenugopal Iyer } 22300dc2366fSVenugopal Iyer 22310dc2366fSVenugopal Iyer aggr_port_stat_entry = i_dlstat_single_port_stats(dpa.dp_dev, 22320dc2366fSVenugopal Iyer portp->lp_linkid); 22330dc2366fSVenugopal Iyer 22340dc2366fSVenugopal Iyer /* Create dladm_stat_chain_t object for this stat */ 22350dc2366fSVenugopal Iyer curr = malloc(sizeof (dladm_stat_chain_t)); 22360dc2366fSVenugopal Iyer if (curr == NULL) { 22370dc2366fSVenugopal Iyer free(aggr_port_stat_entry); 22380dc2366fSVenugopal Iyer goto done; 22390dc2366fSVenugopal Iyer } 22400dc2366fSVenugopal Iyer (void) strlcpy(curr->dc_statheader, dpa.dp_dev, 22410dc2366fSVenugopal Iyer sizeof (curr->dc_statheader)); 22420dc2366fSVenugopal Iyer curr->dc_statentry = aggr_port_stat_entry; 22430dc2366fSVenugopal Iyer curr->dc_next = NULL; 22440dc2366fSVenugopal Iyer 22450dc2366fSVenugopal Iyer /* Chain this aggr port stat entry */ 22460dc2366fSVenugopal Iyer /* head of the stat list */ 22470dc2366fSVenugopal Iyer if (prev == NULL) 22480dc2366fSVenugopal Iyer head = curr; 22490dc2366fSVenugopal Iyer else 22500dc2366fSVenugopal Iyer prev->dc_next = curr; 22510dc2366fSVenugopal Iyer prev = curr; 22520dc2366fSVenugopal Iyer } 22530dc2366fSVenugopal Iyer 22540dc2366fSVenugopal Iyer /* 22550dc2366fSVenugopal Iyer * Prepend the stat list with cumulative aggr stats i.e. summed over all 22560dc2366fSVenugopal Iyer * component ports 22570dc2366fSVenugopal Iyer */ 22580dc2366fSVenugopal Iyer total_stats = dlstat_aggr_total_stats(head); 22590dc2366fSVenugopal Iyer if (total_stats != NULL) { 22600dc2366fSVenugopal Iyer total_stats->dc_next = head; 22610dc2366fSVenugopal Iyer head = total_stats; 22620dc2366fSVenugopal Iyer } 22630dc2366fSVenugopal Iyer 22640dc2366fSVenugopal Iyer done: 22650dc2366fSVenugopal Iyer free(ginfo.lg_ports); 22660dc2366fSVenugopal Iyer return (head); 22670dc2366fSVenugopal Iyer } 22680dc2366fSVenugopal Iyer 22690dc2366fSVenugopal Iyer /* Misc stat specific functions */ 22700dc2366fSVenugopal Iyer void * 22710dc2366fSVenugopal Iyer dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid) 22720dc2366fSVenugopal Iyer { 22730dc2366fSVenugopal Iyer misc_stat_entry_t *misc_stat_entry; 22740dc2366fSVenugopal Iyer dladm_stat_chain_t *head = NULL; 22750dc2366fSVenugopal Iyer char linkname[MAXLINKNAMELEN]; 22760dc2366fSVenugopal Iyer 22770dc2366fSVenugopal Iyer if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname, 22780dc2366fSVenugopal Iyer DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) { 22790dc2366fSVenugopal Iyer goto done; 22800dc2366fSVenugopal Iyer } 22810dc2366fSVenugopal Iyer 22820dc2366fSVenugopal Iyer misc_stat_entry = i_dlstat_misc_stats(linkname); 22830dc2366fSVenugopal Iyer if (misc_stat_entry == NULL) 22840dc2366fSVenugopal Iyer goto done; 22850dc2366fSVenugopal Iyer 22860dc2366fSVenugopal Iyer head = malloc(sizeof (dladm_stat_chain_t)); 22870dc2366fSVenugopal Iyer if (head == NULL) { 22880dc2366fSVenugopal Iyer free(misc_stat_entry); 22890dc2366fSVenugopal Iyer goto done; 22900dc2366fSVenugopal Iyer } 22910dc2366fSVenugopal Iyer 22920dc2366fSVenugopal Iyer head->dc_statentry = misc_stat_entry; 22930dc2366fSVenugopal Iyer (void) strlcpy(head->dc_statheader, "mac_misc_stat", 22940dc2366fSVenugopal Iyer sizeof (head->dc_statheader)); 22950dc2366fSVenugopal Iyer head->dc_next = NULL; 22960dc2366fSVenugopal Iyer 22970dc2366fSVenugopal Iyer done: 22980dc2366fSVenugopal Iyer return (head); 22990dc2366fSVenugopal Iyer } 23000dc2366fSVenugopal Iyer 23010dc2366fSVenugopal Iyer /* Exported functions */ 23020dc2366fSVenugopal Iyer dladm_stat_chain_t * 23030dc2366fSVenugopal Iyer dladm_link_stat_query(dladm_handle_t dh, datalink_id_t linkid, 23040dc2366fSVenugopal Iyer dladm_stat_type_t stattype) 23050dc2366fSVenugopal Iyer { 23060dc2366fSVenugopal Iyer return (dladm_stat_table[stattype].ds_querystat(dh, linkid)); 23070dc2366fSVenugopal Iyer } 23080dc2366fSVenugopal Iyer 23090dc2366fSVenugopal Iyer dladm_stat_chain_t * 23100dc2366fSVenugopal Iyer dladm_link_stat_diffchain(dladm_stat_chain_t *op1, dladm_stat_chain_t *op2, 23110dc2366fSVenugopal Iyer dladm_stat_type_t stattype) 23120dc2366fSVenugopal Iyer { 23130dc2366fSVenugopal Iyer dladm_stat_chain_t *op1_curr, *op2_curr; 23140dc2366fSVenugopal Iyer dladm_stat_chain_t *diff_curr; 23150dc2366fSVenugopal Iyer dladm_stat_chain_t *diff_prev = NULL, *diff_head = NULL; 23160dc2366fSVenugopal Iyer 23170dc2366fSVenugopal Iyer /* Perform op1 - op2, store result in diff */ 23180dc2366fSVenugopal Iyer for (op1_curr = op1; op1_curr != NULL; op1_curr = op1_curr->dc_next) { 23190dc2366fSVenugopal Iyer for (op2_curr = op2; op2_curr != NULL; 23200dc2366fSVenugopal Iyer op2_curr = op2_curr->dc_next) { 23210dc2366fSVenugopal Iyer if (dlstat_match_stats(op1_curr->dc_statentry, 23220dc2366fSVenugopal Iyer op2_curr->dc_statentry, stattype)) { 23230dc2366fSVenugopal Iyer break; 23240dc2366fSVenugopal Iyer } 23250dc2366fSVenugopal Iyer } 23260dc2366fSVenugopal Iyer diff_curr = malloc(sizeof (dladm_stat_chain_t)); 23270dc2366fSVenugopal Iyer if (diff_curr == NULL) 23280dc2366fSVenugopal Iyer goto done; 23290dc2366fSVenugopal Iyer 23300dc2366fSVenugopal Iyer diff_curr->dc_next = NULL; 23310dc2366fSVenugopal Iyer 23320dc2366fSVenugopal Iyer if (op2_curr == NULL) { 23330dc2366fSVenugopal Iyer /* prev iteration did not have this stat entry */ 23340dc2366fSVenugopal Iyer diff_curr->dc_statentry = 23350dc2366fSVenugopal Iyer dlstat_diff_stats(op1_curr->dc_statentry, 23360dc2366fSVenugopal Iyer NULL, stattype); 23370dc2366fSVenugopal Iyer } else { 23380dc2366fSVenugopal Iyer diff_curr->dc_statentry = 23390dc2366fSVenugopal Iyer dlstat_diff_stats(op1_curr->dc_statentry, 23400dc2366fSVenugopal Iyer op2_curr->dc_statentry, stattype); 23410dc2366fSVenugopal Iyer } 23420dc2366fSVenugopal Iyer 23430dc2366fSVenugopal Iyer if (diff_curr->dc_statentry == NULL) { 23440dc2366fSVenugopal Iyer free(diff_curr); 23450dc2366fSVenugopal Iyer goto done; 23460dc2366fSVenugopal Iyer } 23470dc2366fSVenugopal Iyer 23480dc2366fSVenugopal Iyer if (diff_prev == NULL) /* head of the diff stat list */ 23490dc2366fSVenugopal Iyer diff_head = diff_curr; 23500dc2366fSVenugopal Iyer else 23510dc2366fSVenugopal Iyer diff_prev->dc_next = diff_curr; 23520dc2366fSVenugopal Iyer diff_prev = diff_curr; 23530dc2366fSVenugopal Iyer } 23540dc2366fSVenugopal Iyer done: 23550dc2366fSVenugopal Iyer return (diff_head); 23560dc2366fSVenugopal Iyer } 23570dc2366fSVenugopal Iyer 23580dc2366fSVenugopal Iyer void 23590dc2366fSVenugopal Iyer dladm_link_stat_free(dladm_stat_chain_t *curr) 23600dc2366fSVenugopal Iyer { 23610dc2366fSVenugopal Iyer while (curr != NULL) { 23620dc2366fSVenugopal Iyer dladm_stat_chain_t *tofree = curr; 23630dc2366fSVenugopal Iyer 23640dc2366fSVenugopal Iyer curr = curr->dc_next; 23650dc2366fSVenugopal Iyer free(tofree->dc_statentry); 23660dc2366fSVenugopal Iyer free(tofree); 23670dc2366fSVenugopal Iyer } 23680dc2366fSVenugopal Iyer } 23690dc2366fSVenugopal Iyer 23700dc2366fSVenugopal Iyer /* Query all link stats */ 23710dc2366fSVenugopal Iyer static name_value_stat_t * 23720dc2366fSVenugopal Iyer i_dlstat_convert_stats(void *stats, stat_info_t stats_list[], uint_t size) 23730dc2366fSVenugopal Iyer { 23740dc2366fSVenugopal Iyer int i; 23750dc2366fSVenugopal Iyer name_value_stat_t *head_stat = NULL, *prev_stat = NULL; 23760dc2366fSVenugopal Iyer name_value_stat_t *curr_stat; 23770dc2366fSVenugopal Iyer 23780dc2366fSVenugopal Iyer for (i = 0; i < size; i++) { 23790dc2366fSVenugopal Iyer uint64_t *val = (void *) 23800dc2366fSVenugopal Iyer ((uchar_t *)stats + stats_list[i].si_offset); 23810dc2366fSVenugopal Iyer 23820dc2366fSVenugopal Iyer curr_stat = calloc(1, sizeof (name_value_stat_t)); 23830dc2366fSVenugopal Iyer if (curr_stat == NULL) 23840dc2366fSVenugopal Iyer break; 23850dc2366fSVenugopal Iyer 23860dc2366fSVenugopal Iyer (void) strlcpy(curr_stat->nv_statname, stats_list[i].si_name, 23870dc2366fSVenugopal Iyer sizeof (curr_stat->nv_statname)); 23880dc2366fSVenugopal Iyer curr_stat->nv_statval = *val; 23890dc2366fSVenugopal Iyer curr_stat->nv_nextstat = NULL; 23900dc2366fSVenugopal Iyer 23910dc2366fSVenugopal Iyer if (head_stat == NULL) /* First node */ 23920dc2366fSVenugopal Iyer head_stat = curr_stat; 23930dc2366fSVenugopal Iyer else 23940dc2366fSVenugopal Iyer prev_stat->nv_nextstat = curr_stat; 23950dc2366fSVenugopal Iyer 23960dc2366fSVenugopal Iyer prev_stat = curr_stat; 23970dc2366fSVenugopal Iyer } 23980dc2366fSVenugopal Iyer return (head_stat); 23990dc2366fSVenugopal Iyer } 24000dc2366fSVenugopal Iyer 24010dc2366fSVenugopal Iyer void * 24020dc2366fSVenugopal Iyer build_nvs_entry(char *statheader, void *statentry, dladm_stat_type_t stattype) 24030dc2366fSVenugopal Iyer { 24040dc2366fSVenugopal Iyer name_value_stat_entry_t *name_value_stat_entry; 24050dc2366fSVenugopal Iyer dladm_stat_desc_t *stattbl_ptr; 24060dc2366fSVenugopal Iyer void *statfields; 24070dc2366fSVenugopal Iyer 24080dc2366fSVenugopal Iyer stattbl_ptr = &dladm_stat_table[stattype]; 24090dc2366fSVenugopal Iyer 24100dc2366fSVenugopal Iyer /* Allocate memory for query all stat entry */ 24110dc2366fSVenugopal Iyer name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t)); 24120dc2366fSVenugopal Iyer if (name_value_stat_entry == NULL) 24130dc2366fSVenugopal Iyer goto done; 24140dc2366fSVenugopal Iyer 24150dc2366fSVenugopal Iyer /* Header for these stat fields */ 24160dc2366fSVenugopal Iyer (void) strlcpy(name_value_stat_entry->nve_header, statheader, 24170dc2366fSVenugopal Iyer sizeof (name_value_stat_entry->nve_header)); 24180dc2366fSVenugopal Iyer 24190dc2366fSVenugopal Iyer /* Extract stat fields from the statentry */ 24200dc2366fSVenugopal Iyer statfields = (uchar_t *)statentry + 24210dc2366fSVenugopal Iyer dladm_stat_table[stattype].ds_offset; 24220dc2366fSVenugopal Iyer 24230dc2366fSVenugopal Iyer /* Convert curr_stat to <statname, statval> pair */ 24240dc2366fSVenugopal Iyer name_value_stat_entry->nve_stats = 24250dc2366fSVenugopal Iyer i_dlstat_convert_stats(statfields, 24260dc2366fSVenugopal Iyer stattbl_ptr->ds_statlist, stattbl_ptr->ds_statsize); 24270dc2366fSVenugopal Iyer done: 24280dc2366fSVenugopal Iyer return (name_value_stat_entry); 24290dc2366fSVenugopal Iyer } 24300dc2366fSVenugopal Iyer 24310dc2366fSVenugopal Iyer void * 24320dc2366fSVenugopal Iyer i_walk_dlstat_chain(dladm_stat_chain_t *stat_head, dladm_stat_type_t stattype) 24330dc2366fSVenugopal Iyer { 24340dc2366fSVenugopal Iyer dladm_stat_chain_t *curr; 24350dc2366fSVenugopal Iyer dladm_stat_chain_t *nvstat_head = NULL, *nvstat_prev = NULL; 24360dc2366fSVenugopal Iyer dladm_stat_chain_t *nvstat_curr; 24370dc2366fSVenugopal Iyer 24380dc2366fSVenugopal Iyer /* 24390dc2366fSVenugopal Iyer * For every stat in the chain, build header and convert all 24400dc2366fSVenugopal Iyer * its stat fields 24410dc2366fSVenugopal Iyer */ 24420dc2366fSVenugopal Iyer for (curr = stat_head; curr != NULL; curr = curr->dc_next) { 24430dc2366fSVenugopal Iyer nvstat_curr = malloc(sizeof (dladm_stat_chain_t)); 24440dc2366fSVenugopal Iyer if (nvstat_curr == NULL) 24450dc2366fSVenugopal Iyer break; 24460dc2366fSVenugopal Iyer 24470dc2366fSVenugopal Iyer nvstat_curr->dc_statentry = build_nvs_entry(curr->dc_statheader, 24480dc2366fSVenugopal Iyer curr->dc_statentry, stattype); 24490dc2366fSVenugopal Iyer 24500dc2366fSVenugopal Iyer if (nvstat_curr->dc_statentry == NULL) { 24510dc2366fSVenugopal Iyer free(nvstat_curr); 24520dc2366fSVenugopal Iyer break; 24530dc2366fSVenugopal Iyer } 24540dc2366fSVenugopal Iyer 24550dc2366fSVenugopal Iyer nvstat_curr->dc_next = NULL; 24560dc2366fSVenugopal Iyer 24570dc2366fSVenugopal Iyer if (nvstat_head == NULL) /* First node */ 24580dc2366fSVenugopal Iyer nvstat_head = nvstat_curr; 24590dc2366fSVenugopal Iyer else 24600dc2366fSVenugopal Iyer nvstat_prev->dc_next = nvstat_curr; 24610dc2366fSVenugopal Iyer 24620dc2366fSVenugopal Iyer nvstat_prev = nvstat_curr; 24630dc2366fSVenugopal Iyer } 24640dc2366fSVenugopal Iyer done: 24650dc2366fSVenugopal Iyer return (nvstat_head); 24660dc2366fSVenugopal Iyer } 24670dc2366fSVenugopal Iyer 24680dc2366fSVenugopal Iyer dladm_stat_chain_t * 24690dc2366fSVenugopal Iyer dladm_link_stat_query_all(dladm_handle_t dh, datalink_id_t linkid, 24700dc2366fSVenugopal Iyer dladm_stat_type_t stattype) 24710dc2366fSVenugopal Iyer { 24720dc2366fSVenugopal Iyer dladm_stat_chain_t *stat_head; 24730dc2366fSVenugopal Iyer dladm_stat_chain_t *nvstat_head = NULL; 24740dc2366fSVenugopal Iyer 24750dc2366fSVenugopal Iyer /* Query the requested stat */ 24760dc2366fSVenugopal Iyer stat_head = dladm_link_stat_query(dh, linkid, stattype); 24770dc2366fSVenugopal Iyer if (stat_head == NULL) 24780dc2366fSVenugopal Iyer goto done; 24790dc2366fSVenugopal Iyer 24800dc2366fSVenugopal Iyer /* 24810dc2366fSVenugopal Iyer * Convert every statfield in every stat-entry of stat chain to 24820dc2366fSVenugopal Iyer * <statname, statval> pair 24830dc2366fSVenugopal Iyer */ 24840dc2366fSVenugopal Iyer nvstat_head = i_walk_dlstat_chain(stat_head, stattype); 24850dc2366fSVenugopal Iyer 24860dc2366fSVenugopal Iyer /* Free stat_head */ 24870dc2366fSVenugopal Iyer dladm_link_stat_free(stat_head); 24880dc2366fSVenugopal Iyer 24890dc2366fSVenugopal Iyer done: 24900dc2366fSVenugopal Iyer return (nvstat_head); 24910dc2366fSVenugopal Iyer } 24920dc2366fSVenugopal Iyer 24930dc2366fSVenugopal Iyer void 24940dc2366fSVenugopal Iyer dladm_link_stat_query_all_free(dladm_stat_chain_t *curr) 24950dc2366fSVenugopal Iyer { 24960dc2366fSVenugopal Iyer while (curr != NULL) { 24970dc2366fSVenugopal Iyer dladm_stat_chain_t *tofree = curr; 24980dc2366fSVenugopal Iyer name_value_stat_entry_t *nv_entry = curr->dc_statentry; 24990dc2366fSVenugopal Iyer name_value_stat_t *nv_curr = nv_entry->nve_stats; 25000dc2366fSVenugopal Iyer 25010dc2366fSVenugopal Iyer while (nv_curr != NULL) { 25020dc2366fSVenugopal Iyer name_value_stat_t *nv_tofree = nv_curr; 25030dc2366fSVenugopal Iyer 25040dc2366fSVenugopal Iyer nv_curr = nv_curr->nv_nextstat; 25050dc2366fSVenugopal Iyer free(nv_tofree); 25060dc2366fSVenugopal Iyer } 25070dc2366fSVenugopal Iyer 25080dc2366fSVenugopal Iyer curr = curr->dc_next; 25090dc2366fSVenugopal Iyer free(nv_entry); 25100dc2366fSVenugopal Iyer free(tofree); 25110dc2366fSVenugopal Iyer } 25120dc2366fSVenugopal Iyer } 25130dc2366fSVenugopal Iyer 25140dc2366fSVenugopal Iyer /* flow stats specific routines */ 25150dc2366fSVenugopal Iyer flow_stat_t * 25160dc2366fSVenugopal Iyer dladm_flow_stat_query(const char *flowname) 25170dc2366fSVenugopal Iyer { 25180dc2366fSVenugopal Iyer kstat_ctl_t *kcp; 25190dc2366fSVenugopal Iyer kstat_t *ksp; 25200dc2366fSVenugopal Iyer flow_stat_t *flow_stat = NULL; 25210dc2366fSVenugopal Iyer 25220dc2366fSVenugopal Iyer if ((kcp = kstat_open()) == NULL) 25230dc2366fSVenugopal Iyer return (NULL); 25240dc2366fSVenugopal Iyer 25250dc2366fSVenugopal Iyer flow_stat = calloc(1, sizeof (flow_stat_t)); 25260dc2366fSVenugopal Iyer if (flow_stat == NULL) 25270dc2366fSVenugopal Iyer goto done; 25280dc2366fSVenugopal Iyer 25290dc2366fSVenugopal Iyer ksp = dladm_kstat_lookup(kcp, NULL, -1, flowname, "flow"); 25300dc2366fSVenugopal Iyer 25310dc2366fSVenugopal Iyer if (ksp != NULL) { 25320dc2366fSVenugopal Iyer i_dlstat_get_stats(kcp, ksp, flow_stat, flow_stats_list, 25330dc2366fSVenugopal Iyer FLOW_STAT_SIZE); 25340dc2366fSVenugopal Iyer } 25350dc2366fSVenugopal Iyer 25360dc2366fSVenugopal Iyer done: 25370dc2366fSVenugopal Iyer (void) kstat_close(kcp); 25380dc2366fSVenugopal Iyer return (flow_stat); 25390dc2366fSVenugopal Iyer } 25400dc2366fSVenugopal Iyer 25410dc2366fSVenugopal Iyer flow_stat_t * 25420dc2366fSVenugopal Iyer dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2) 25430dc2366fSVenugopal Iyer { 25440dc2366fSVenugopal Iyer flow_stat_t *diff_stat; 25450dc2366fSVenugopal Iyer 25460dc2366fSVenugopal Iyer diff_stat = calloc(1, sizeof (flow_stat_t)); 25470dc2366fSVenugopal Iyer if (diff_stat == NULL) 25480dc2366fSVenugopal Iyer goto done; 25490dc2366fSVenugopal Iyer 25500dc2366fSVenugopal Iyer if (op2 == NULL) { 25510dc2366fSVenugopal Iyer bcopy(op1, diff_stat, sizeof (flow_stat_t)); 25520dc2366fSVenugopal Iyer } else { 25530dc2366fSVenugopal Iyer i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list, 25540dc2366fSVenugopal Iyer FLOW_STAT_SIZE); 25550dc2366fSVenugopal Iyer } 25560dc2366fSVenugopal Iyer done: 25570dc2366fSVenugopal Iyer return (diff_stat); 25580dc2366fSVenugopal Iyer } 25590dc2366fSVenugopal Iyer 25600dc2366fSVenugopal Iyer void 25610dc2366fSVenugopal Iyer dladm_flow_stat_free(flow_stat_t *curr) 25620dc2366fSVenugopal Iyer { 25630dc2366fSVenugopal Iyer free(curr); 25640dc2366fSVenugopal Iyer } 25650dc2366fSVenugopal Iyer 25660dc2366fSVenugopal Iyer /* Query all flow stats */ 25670dc2366fSVenugopal Iyer name_value_stat_entry_t * 25680dc2366fSVenugopal Iyer dladm_flow_stat_query_all(const char *flowname) 25690dc2366fSVenugopal Iyer { 25700dc2366fSVenugopal Iyer flow_stat_t *flow_stat; 25710dc2366fSVenugopal Iyer name_value_stat_entry_t *name_value_stat_entry = NULL; 25720dc2366fSVenugopal Iyer 25730dc2366fSVenugopal Iyer /* Query flow stats */ 25740dc2366fSVenugopal Iyer flow_stat = dladm_flow_stat_query(flowname); 25750dc2366fSVenugopal Iyer if (flow_stat == NULL) 25760dc2366fSVenugopal Iyer goto done; 25770dc2366fSVenugopal Iyer 25780dc2366fSVenugopal Iyer /* Allocate memory for query all stat entry */ 25790dc2366fSVenugopal Iyer name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t)); 25800dc2366fSVenugopal Iyer if (name_value_stat_entry == NULL) { 25810dc2366fSVenugopal Iyer dladm_flow_stat_free(flow_stat); 25820dc2366fSVenugopal Iyer goto done; 25830dc2366fSVenugopal Iyer } 25840dc2366fSVenugopal Iyer 25850dc2366fSVenugopal Iyer /* Header for these stat fields */ 25860dc2366fSVenugopal Iyer (void) strncpy(name_value_stat_entry->nve_header, flowname, 25870dc2366fSVenugopal Iyer MAXFLOWNAMELEN); 25880dc2366fSVenugopal Iyer 25890dc2366fSVenugopal Iyer /* Convert every statfield in flow_stat to <statname, statval> pair */ 25900dc2366fSVenugopal Iyer name_value_stat_entry->nve_stats = 25910dc2366fSVenugopal Iyer i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE); 25920dc2366fSVenugopal Iyer 25930dc2366fSVenugopal Iyer /* Free flow_stat */ 25940dc2366fSVenugopal Iyer dladm_flow_stat_free(flow_stat); 25950dc2366fSVenugopal Iyer 25960dc2366fSVenugopal Iyer done: 25970dc2366fSVenugopal Iyer return (name_value_stat_entry); 25980dc2366fSVenugopal Iyer } 25990dc2366fSVenugopal Iyer 26000dc2366fSVenugopal Iyer void 26010dc2366fSVenugopal Iyer dladm_flow_stat_query_all_free(name_value_stat_entry_t *curr) 26020dc2366fSVenugopal Iyer { 26030dc2366fSVenugopal Iyer name_value_stat_t *nv_curr = curr->nve_stats; 26040dc2366fSVenugopal Iyer 26050dc2366fSVenugopal Iyer while (nv_curr != NULL) { 26060dc2366fSVenugopal Iyer name_value_stat_t *nv_tofree = nv_curr; 26070dc2366fSVenugopal Iyer 26080dc2366fSVenugopal Iyer nv_curr = nv_curr->nv_nextstat; 26090dc2366fSVenugopal Iyer free(nv_tofree); 26100dc2366fSVenugopal Iyer } 26110dc2366fSVenugopal Iyer } 2612