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*399dcf08Scarlos antonio neira bustos /*
27*399dcf08Scarlos antonio neira bustos * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
28*399dcf08Scarlos antonio neira bustos */
29*399dcf08Scarlos antonio neira bustos
3062ef8476SYuri Pankov #include <stddef.h>
31da14cebeSEric Cheng #include <stdio.h>
32da14cebeSEric Cheng #include <stdlib.h>
33da14cebeSEric Cheng #include <strings.h>
34da14cebeSEric Cheng #include <err.h>
35da14cebeSEric Cheng #include <errno.h>
36c3affd82SMichael Lim #include <fcntl.h>
37da14cebeSEric Cheng #include <kstat.h>
38c3affd82SMichael Lim #include <limits.h>
39da14cebeSEric Cheng #include <unistd.h>
40da14cebeSEric Cheng #include <signal.h>
41da14cebeSEric Cheng #include <sys/dld.h>
4282a2fc47SJames Carlson #include <sys/ddi.h>
43da14cebeSEric Cheng
44da14cebeSEric Cheng #include <libdllink.h>
45da14cebeSEric Cheng #include <libdlflow.h>
46da14cebeSEric Cheng #include <libdlstat.h>
470dc2366fSVenugopal Iyer #include <libdlaggr.h>
48da14cebeSEric Cheng
49da14cebeSEric Cheng struct flowlist {
50da000602SGirish Moodalbail char flowname[MAXFLOWNAMELEN];
51c3affd82SMichael Lim char linkname[MAXLINKNAMELEN];
52da14cebeSEric Cheng datalink_id_t linkid;
53c3affd82SMichael Lim int fd;
54285e94f9SMichael Lim uint64_t ifspeed;
55da14cebeSEric Cheng boolean_t first;
56da14cebeSEric Cheng boolean_t display;
57da14cebeSEric Cheng pktsum_t prevstats;
58da14cebeSEric Cheng pktsum_t diffstats;
59da14cebeSEric Cheng };
60da14cebeSEric Cheng
61da14cebeSEric Cheng pktsum_t totalstats;
62da14cebeSEric Cheng struct flowlist *stattable = NULL;
63da14cebeSEric Cheng
64da14cebeSEric Cheng #define STATGROWSIZE 16
65da14cebeSEric Cheng
66da14cebeSEric Cheng /* Exported functions */
67da14cebeSEric Cheng
68da14cebeSEric Cheng /*
69da14cebeSEric Cheng * dladm_kstat_lookup() is a modified version of kstat_lookup which
70da14cebeSEric Cheng * adds the class as a selector.
71da14cebeSEric Cheng */
72da14cebeSEric Cheng kstat_t *
dladm_kstat_lookup(kstat_ctl_t * kcp,const char * module,int instance,const char * name,const char * class)73da14cebeSEric Cheng dladm_kstat_lookup(kstat_ctl_t *kcp, const char *module, int instance,
74da14cebeSEric Cheng const char *name, const char *class)
75da14cebeSEric Cheng {
76da14cebeSEric Cheng kstat_t *ksp = NULL;
77da14cebeSEric Cheng
78da14cebeSEric Cheng for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
79da14cebeSEric Cheng if ((module == NULL || strcmp(ksp->ks_module, module) == 0) &&
80da14cebeSEric Cheng (instance == -1 || ksp->ks_instance == instance) &&
81da14cebeSEric Cheng (name == NULL || strcmp(ksp->ks_name, name) == 0) &&
82da14cebeSEric Cheng (class == NULL || strcmp(ksp->ks_class, class) == 0))
83da14cebeSEric Cheng return (ksp);
84da14cebeSEric Cheng }
85da14cebeSEric Cheng
86da14cebeSEric Cheng errno = ENOENT;
87da14cebeSEric Cheng return (NULL);
88da14cebeSEric Cheng }
89da14cebeSEric Cheng
90da14cebeSEric Cheng /*
91da14cebeSEric Cheng * dladm_get_stats() populates the supplied pktsum_t structure with
92da14cebeSEric Cheng * the input and output packet and byte kstats from the kstat_t
93da14cebeSEric Cheng * found with dladm_kstat_lookup.
94da14cebeSEric Cheng */
95da14cebeSEric Cheng void
dladm_get_stats(kstat_ctl_t * kcp,kstat_t * ksp,pktsum_t * stats)96da14cebeSEric Cheng dladm_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, pktsum_t *stats)
97da14cebeSEric Cheng {
98da14cebeSEric Cheng
99da14cebeSEric Cheng if (kstat_read(kcp, ksp, NULL) == -1)
100da14cebeSEric Cheng return;
101da14cebeSEric Cheng
102da14cebeSEric Cheng stats->snaptime = gethrtime();
103da14cebeSEric Cheng
104da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64,
105da14cebeSEric Cheng &stats->ipackets) < 0) {
106da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ipackets", KSTAT_DATA_UINT64,
107da14cebeSEric Cheng &stats->ipackets) < 0)
108da14cebeSEric Cheng return;
109da14cebeSEric Cheng }
110da14cebeSEric Cheng
111da14cebeSEric Cheng if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64,
112da14cebeSEric Cheng &stats->opackets) < 0) {
113da14cebeSEric Cheng if (dladm_kstat_value(ksp, "opackets", KSTAT_DATA_UINT64,
114da14cebeSEric Cheng &stats->opackets) < 0)
115da14cebeSEric Cheng return;
116da14cebeSEric Cheng }
117da14cebeSEric Cheng
118da14cebeSEric Cheng if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64,
119da14cebeSEric Cheng &stats->rbytes) < 0) {
120da14cebeSEric Cheng if (dladm_kstat_value(ksp, "rbytes", KSTAT_DATA_UINT64,
121da14cebeSEric Cheng &stats->rbytes) < 0)
122da14cebeSEric Cheng return;
123da14cebeSEric Cheng }
124da14cebeSEric Cheng
125da14cebeSEric Cheng if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64,
126da14cebeSEric Cheng &stats->obytes) < 0) {
127da14cebeSEric Cheng if (dladm_kstat_value(ksp, "obytes", KSTAT_DATA_UINT64,
128da14cebeSEric Cheng &stats->obytes) < 0)
129da14cebeSEric Cheng return;
130da14cebeSEric Cheng }
131da14cebeSEric Cheng
132da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32,
133da14cebeSEric Cheng &stats->ierrors) < 0) {
134da14cebeSEric Cheng if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT64,
135da14cebeSEric Cheng &stats->ierrors) < 0)
136da14cebeSEric Cheng return;
137da14cebeSEric Cheng }
138da14cebeSEric Cheng
139da14cebeSEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32,
140da14cebeSEric Cheng &stats->oerrors) < 0) {
141da14cebeSEric Cheng if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT64,
142da14cebeSEric Cheng &stats->oerrors) < 0)
143da14cebeSEric Cheng return;
144da14cebeSEric Cheng }
145da14cebeSEric Cheng }
146da14cebeSEric Cheng
147da14cebeSEric Cheng int
dladm_kstat_value(kstat_t * ksp,const char * name,uint8_t type,void * buf)148da14cebeSEric Cheng dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf)
149da14cebeSEric Cheng {
150da14cebeSEric Cheng kstat_named_t *knp;
151da14cebeSEric Cheng
152da14cebeSEric Cheng if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL)
153da14cebeSEric Cheng return (-1);
154da14cebeSEric Cheng
155da14cebeSEric Cheng if (knp->data_type != type)
156da14cebeSEric Cheng return (-1);
157da14cebeSEric Cheng
158da14cebeSEric Cheng switch (type) {
159da14cebeSEric Cheng case KSTAT_DATA_UINT64:
160da14cebeSEric Cheng *(uint64_t *)buf = knp->value.ui64;
161da14cebeSEric Cheng break;
162da14cebeSEric Cheng case KSTAT_DATA_UINT32:
163da14cebeSEric Cheng *(uint32_t *)buf = knp->value.ui32;
164da14cebeSEric Cheng break;
165da14cebeSEric Cheng default:
166da14cebeSEric Cheng return (-1);
167da14cebeSEric Cheng }
168da14cebeSEric Cheng
169da14cebeSEric Cheng return (0);
170da14cebeSEric Cheng }
171da14cebeSEric Cheng
172da14cebeSEric Cheng dladm_status_t
dladm_get_single_mac_stat(dladm_handle_t handle,datalink_id_t linkid,const char * name,uint8_t type,void * val)1734ac67f02SAnurag S. Maskey dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid,
1744ac67f02SAnurag S. Maskey const char *name, uint8_t type, void *val)
175da14cebeSEric Cheng {
176da14cebeSEric Cheng char module[DLPI_LINKNAME_MAX];
177da14cebeSEric Cheng uint_t instance;
178da14cebeSEric Cheng char link[DLPI_LINKNAME_MAX];
179da14cebeSEric Cheng dladm_status_t status;
180da14cebeSEric Cheng uint32_t flags, media;
181da14cebeSEric Cheng kstat_t *ksp;
182da14cebeSEric Cheng dladm_phys_attr_t dpap;
183da14cebeSEric Cheng
1844ac67f02SAnurag S. Maskey if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
1854ac67f02SAnurag S. Maskey &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK)
186da14cebeSEric Cheng return (status);
187da14cebeSEric Cheng
188da14cebeSEric Cheng if (media != DL_ETHER)
189da14cebeSEric Cheng return (DLADM_STATUS_LINKINVAL);
190da14cebeSEric Cheng
1914ac67f02SAnurag S. Maskey status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST);
192da14cebeSEric Cheng
193da14cebeSEric Cheng if (status != DLADM_STATUS_OK)
194da14cebeSEric Cheng return (status);
195da14cebeSEric Cheng
196da14cebeSEric Cheng status = dladm_parselink(dpap.dp_dev, module, &instance);
197da14cebeSEric Cheng
198da14cebeSEric Cheng if (status != DLADM_STATUS_OK)
199da14cebeSEric Cheng return (status);
200da14cebeSEric Cheng
201da14cebeSEric Cheng /*
202da14cebeSEric Cheng * The kstat query could fail if the underlying MAC
203da14cebeSEric Cheng * driver was already detached.
204da14cebeSEric Cheng */
205*399dcf08Scarlos antonio neira bustos if (dladm_dld_kcp(handle) == NULL) {
206*399dcf08Scarlos antonio neira bustos warn("kstat_open operation failed");
207*399dcf08Scarlos antonio neira bustos return (-1);
208*399dcf08Scarlos antonio neira bustos }
209*399dcf08Scarlos antonio neira bustos
210*399dcf08Scarlos antonio neira bustos if ((ksp = kstat_lookup(dladm_dld_kcp(handle), module, instance,
211*399dcf08Scarlos antonio neira bustos "mac")) == NULL &&
212*399dcf08Scarlos antonio neira bustos (ksp = kstat_lookup(dladm_dld_kcp(handle), module, instance,
213*399dcf08Scarlos antonio neira bustos NULL)) == NULL) {
214da14cebeSEric Cheng goto bail;
215*399dcf08Scarlos antonio neira bustos }
216da14cebeSEric Cheng
217*399dcf08Scarlos antonio neira bustos if (kstat_read(dladm_dld_kcp(handle), ksp, NULL) == -1)
218da14cebeSEric Cheng goto bail;
219da14cebeSEric Cheng
220da14cebeSEric Cheng if (dladm_kstat_value(ksp, name, type, val) < 0)
221da14cebeSEric Cheng goto bail;
222da14cebeSEric Cheng
223da14cebeSEric Cheng return (DLADM_STATUS_OK);
224da14cebeSEric Cheng
225da14cebeSEric Cheng bail:
226da14cebeSEric Cheng return (dladm_errno2status(errno));
227da14cebeSEric Cheng }
228da14cebeSEric Cheng
229da14cebeSEric Cheng /* Compute sum of 2 pktsums (s1 = s2 + s3) */
230da14cebeSEric Cheng void
dladm_stats_total(pktsum_t * s1,pktsum_t * s2,pktsum_t * s3)231da14cebeSEric Cheng dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
232da14cebeSEric Cheng {
233da14cebeSEric Cheng s1->rbytes = s2->rbytes + s3->rbytes;
234da14cebeSEric Cheng s1->ipackets = s2->ipackets + s3->ipackets;
235da14cebeSEric Cheng s1->ierrors = s2->ierrors + s3->ierrors;
236da14cebeSEric Cheng s1->obytes = s2->obytes + s3->obytes;
237da14cebeSEric Cheng s1->opackets = s2->opackets + s3->opackets;
238da14cebeSEric Cheng s1->oerrors = s2->oerrors + s3->oerrors;
239da14cebeSEric Cheng s1->snaptime = s2->snaptime;
240da14cebeSEric Cheng }
241da14cebeSEric Cheng
2420dc2366fSVenugopal Iyer #define DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0)
2432d40c3b2SPrakash Jalan
2442d40c3b2SPrakash Jalan
245da14cebeSEric Cheng /* Compute differences between 2 pktsums (s1 = s2 - s3) */
246da14cebeSEric Cheng void
dladm_stats_diff(pktsum_t * s1,pktsum_t * s2,pktsum_t * s3)247da14cebeSEric Cheng dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
248da14cebeSEric Cheng {
2492d40c3b2SPrakash Jalan s1->rbytes = DIFF_STAT(s2->rbytes, s3->rbytes);
2502d40c3b2SPrakash Jalan s1->ipackets = DIFF_STAT(s2->ipackets, s3->ipackets);
2512d40c3b2SPrakash Jalan s1->ierrors = DIFF_STAT(s2->ierrors, s3->ierrors);
2522d40c3b2SPrakash Jalan s1->obytes = DIFF_STAT(s2->obytes, s3->obytes);
2532d40c3b2SPrakash Jalan s1->opackets = DIFF_STAT(s2->opackets, s3->opackets);
2542d40c3b2SPrakash Jalan s1->oerrors = DIFF_STAT(s2->oerrors, s3->oerrors);
2552d40c3b2SPrakash Jalan s1->snaptime = DIFF_STAT(s2->snaptime, s3->snaptime);
256da14cebeSEric Cheng }
2570dc2366fSVenugopal Iyer
2580dc2366fSVenugopal Iyer #define DLSTAT_MAC_RX_SWLANE "mac_rx_swlane"
2590dc2366fSVenugopal Iyer #define DLSTAT_MAC_RX_HWLANE "mac_rx_hwlane"
2600dc2366fSVenugopal Iyer #define DLSTAT_MAC_TX_SWLANE "mac_tx_swlane"
2610dc2366fSVenugopal Iyer #define DLSTAT_MAC_TX_HWLANE "mac_tx_hwlane"
2620dc2366fSVenugopal Iyer #define DLSTAT_MAC_MISC_STAT "mac_misc_stat"
2630dc2366fSVenugopal Iyer #define DLSTAT_MAC_RX_RING "mac_rx_ring"
2640dc2366fSVenugopal Iyer #define DLSTAT_MAC_TX_RING "mac_tx_ring"
2650dc2366fSVenugopal Iyer #define DLSTAT_MAC_FANOUT "mac_rx_swlane0_fanout"
2660dc2366fSVenugopal Iyer
2670dc2366fSVenugopal Iyer typedef struct {
2680dc2366fSVenugopal Iyer const char *si_name;
2690dc2366fSVenugopal Iyer uint_t si_offset;
2700dc2366fSVenugopal Iyer } stat_info_t;
2710dc2366fSVenugopal Iyer
2720dc2366fSVenugopal Iyer #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0]))
2730dc2366fSVenugopal Iyer
2740dc2366fSVenugopal Iyer /* Definitions for rx lane stats */
2750dc2366fSVenugopal Iyer #define RL_OFF(f) (offsetof(rx_lane_stat_t, f))
2760dc2366fSVenugopal Iyer
2770dc2366fSVenugopal Iyer static stat_info_t rx_hwlane_stats_list[] = {
2780dc2366fSVenugopal Iyer {"ipackets", RL_OFF(rl_ipackets)},
2790dc2366fSVenugopal Iyer {"rbytes", RL_OFF(rl_rbytes)},
2800dc2366fSVenugopal Iyer {"intrs", RL_OFF(rl_intrs)},
2810dc2366fSVenugopal Iyer {"intrbytes", RL_OFF(rl_intrbytes)},
2820dc2366fSVenugopal Iyer {"polls", RL_OFF(rl_polls)},
2830dc2366fSVenugopal Iyer {"pollbytes", RL_OFF(rl_pollbytes)},
2840dc2366fSVenugopal Iyer {"rxsdrops", RL_OFF(rl_sdrops)},
2850dc2366fSVenugopal Iyer {"chainunder10", RL_OFF(rl_chl10)},
2860dc2366fSVenugopal Iyer {"chain10to50", RL_OFF(rl_ch10_50)},
2870dc2366fSVenugopal Iyer {"chainover50", RL_OFF(rl_chg50)}
2880dc2366fSVenugopal Iyer };
2890dc2366fSVenugopal Iyer #define RX_HWLANE_STAT_SIZE A_CNT(rx_hwlane_stats_list)
2900dc2366fSVenugopal Iyer
2910dc2366fSVenugopal Iyer static stat_info_t rx_swlane_stats_list[] = {
2920dc2366fSVenugopal Iyer {"ipackets", RL_OFF(rl_ipackets)},
2930dc2366fSVenugopal Iyer {"rbytes", RL_OFF(rl_rbytes)},
2940dc2366fSVenugopal Iyer {"local", RL_OFF(rl_lclpackets)},
2950dc2366fSVenugopal Iyer {"localbytes", RL_OFF(rl_lclbytes)},
2960dc2366fSVenugopal Iyer {"intrs", RL_OFF(rl_intrs)},
2970dc2366fSVenugopal Iyer {"intrbytes", RL_OFF(rl_intrbytes)},
2980dc2366fSVenugopal Iyer {"rxsdrops", RL_OFF(rl_sdrops)}
2990dc2366fSVenugopal Iyer };
3000dc2366fSVenugopal Iyer #define RX_SWLANE_STAT_SIZE A_CNT(rx_swlane_stats_list)
3010dc2366fSVenugopal Iyer
3020dc2366fSVenugopal Iyer static stat_info_t rx_lane_stats_list[] = {
3030dc2366fSVenugopal Iyer {"ipackets", RL_OFF(rl_ipackets)},
3040dc2366fSVenugopal Iyer {"rbytes", RL_OFF(rl_rbytes)},
305