1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
28 */
29
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <kstat.h>
38 #include <limits.h>
39 #include <unistd.h>
40 #include <signal.h>
41 #include <sys/dld.h>
42 #include <sys/ddi.h>
43
44 #include <libdllink.h>
45 #include <libdlflow.h>
46 #include <libdlstat.h>
47 #include <libdlaggr.h>
48
49 struct flowlist {
50 char flowname[MAXFLOWNAMELEN];
51 char linkname[MAXLINKNAMELEN];
52 datalink_id_t linkid;
53 int fd;
54 uint64_t ifspeed;
55 boolean_t first;
56 boolean_t display;
57 pktsum_t prevstats;
58 pktsum_t diffstats;
59 };
60
61 pktsum_t totalstats;
62 struct flowlist *stattable = NULL;
63
64 #define STATGROWSIZE 16
65
66 /* Exported functions */
67
68 /*
69 * dladm_kstat_lookup() is a modified version of kstat_lookup which
70 * adds the class as a selector.
71 */
72 kstat_t *
dladm_kstat_lookup(kstat_ctl_t * kcp,const char * module,int instance,const char * name,const char * class)73 dladm_kstat_lookup(kstat_ctl_t *kcp, const char *module, int instance,
74 const char *name, const char *class)
75 {
76 kstat_t *ksp = NULL;
77
78 for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
79 if ((module == NULL || strcmp(ksp->ks_module, module) == 0) &&
80 (instance == -1 || ksp->ks_instance == instance) &&
81 (name == NULL || strcmp(ksp->ks_name, name) == 0) &&
82 (class == NULL || strcmp(ksp->ks_class, class) == 0))
83 return (ksp);
84 }
85
86 errno = ENOENT;
87 return (NULL);
88 }
89
90 /*
91 * dladm_get_stats() populates the supplied pktsum_t structure with
92 * the input and output packet and byte kstats from the kstat_t
93 * found with dladm_kstat_lookup.
94 */
95 void
dladm_get_stats(kstat_ctl_t * kcp,kstat_t * ksp,pktsum_t * stats)96 dladm_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, pktsum_t *stats)
97 {
98
99 if (kstat_read(kcp, ksp, NULL) == -1)
100 return;
101
102 stats->snaptime = gethrtime();
103
104 if (dladm_kstat_value(ksp, "ipackets64", KSTAT_DATA_UINT64,
105 &stats->ipackets) < 0) {
106 if (dladm_kstat_value(ksp, "ipackets", KSTAT_DATA_UINT64,
107 &stats->ipackets) < 0)
108 return;
109 }
110
111 if (dladm_kstat_value(ksp, "opackets64", KSTAT_DATA_UINT64,
112 &stats->opackets) < 0) {
113 if (dladm_kstat_value(ksp, "opackets", KSTAT_DATA_UINT64,
114 &stats->opackets) < 0)
115 return;
116 }
117
118 if (dladm_kstat_value(ksp, "rbytes64", KSTAT_DATA_UINT64,
119 &stats->rbytes) < 0) {
120 if (dladm_kstat_value(ksp, "rbytes", KSTAT_DATA_UINT64,
121 &stats->rbytes) < 0)
122 return;
123 }
124
125 if (dladm_kstat_value(ksp, "obytes64", KSTAT_DATA_UINT64,
126 &stats->obytes) < 0) {
127 if (dladm_kstat_value(ksp, "obytes", KSTAT_DATA_UINT64,
128 &stats->obytes) < 0)
129 return;
130 }
131
132 if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT32,
133 &stats->ierrors) < 0) {
134 if (dladm_kstat_value(ksp, "ierrors", KSTAT_DATA_UINT64,
135 &stats->ierrors) < 0)
136 return;
137 }
138
139 if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT32,
140 &stats->oerrors) < 0) {
141 if (dladm_kstat_value(ksp, "oerrors", KSTAT_DATA_UINT64,
142 &stats->oerrors) < 0)
143 return;
144 }
145 }
146
147 int
dladm_kstat_value(kstat_t * ksp,const char * name,uint8_t type,void * buf)148 dladm_kstat_value(kstat_t *ksp, const char *name, uint8_t type, void *buf)
149 {
150 kstat_named_t *knp;
151
152 if ((knp = kstat_data_lookup(ksp, (char *)name)) == NULL)
153 return (-1);
154
155 if (knp->data_type != type)
156 return (-1);
157
158 switch (type) {
159 case KSTAT_DATA_UINT64:
160 *(uint64_t *)buf = knp->value.ui64;
161 break;
162 case KSTAT_DATA_UINT32:
163 *(uint32_t *)buf = knp->value.ui32;
164 break;
165 default:
166 return (-1);
167 }
168
169 return (0);
170 }
171
172 dladm_status_t
dladm_get_single_mac_stat(dladm_handle_t handle,datalink_id_t linkid,const char * name,uint8_t type,void * val)173 dladm_get_single_mac_stat(dladm_handle_t handle, datalink_id_t linkid,
174 const char *name, uint8_t type, void *val)
175 {
176 char module[DLPI_LINKNAME_MAX];
177 uint_t instance;
178 char link[DLPI_LINKNAME_MAX];
179 dladm_status_t status;
180 uint32_t flags, media;
181 kstat_t *ksp;
182 dladm_phys_attr_t dpap;
183
184 if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
185 &media, link, DLPI_LINKNAME_MAX)) != DLADM_STATUS_OK)
186 return (status);
187
188 if (media != DL_ETHER)
189 return (DLADM_STATUS_LINKINVAL);
190
191 status = dladm_phys_info(handle, linkid, &dpap, DLADM_OPT_PERSIST);
192
193 if (status != DLADM_STATUS_OK)
194 return (status);
195
196 status = dladm_parselink(dpap.dp_dev, module, &instance);
197
198 if (status != DLADM_STATUS_OK)
199 return (status);
200
201 /*
202 * The kstat query could fail if the underlying MAC
203 * driver was already detached.
204 */
205 if (dladm_dld_kcp(handle) == NULL) {
206 warn("kstat_open operation failed");
207 return (-1);
208 }
209
210 if ((ksp = kstat_lookup(dladm_dld_kcp(handle), module, instance,
211 "mac")) == NULL &&
212 (ksp = kstat_lookup(dladm_dld_kcp(handle), module, instance,
213 NULL)) == NULL) {
214 goto bail;
215 }
216
217 if (kstat_read(dladm_dld_kcp(handle), ksp, NULL) == -1)
218 goto bail;
219
220 if (dladm_kstat_value(ksp, name, type, val) < 0)
221 goto bail;
222
223 return (DLADM_STATUS_OK);
224
225 bail:
226 return (dladm_errno2status(errno));
227 }
228
229 /* Compute sum of 2 pktsums (s1 = s2 + s3) */
230 void
dladm_stats_total(pktsum_t * s1,pktsum_t * s2,pktsum_t * s3)231 dladm_stats_total(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
232 {
233 s1->rbytes = s2->rbytes + s3->rbytes;
234 s1->ipackets = s2->ipackets + s3->ipackets;
235 s1->ierrors = s2->ierrors + s3->ierrors;
236 s1->obytes = s2->obytes + s3->obytes;
237 s1->opackets = s2->opackets + s3->opackets;
238 s1->oerrors = s2->oerrors + s3->oerrors;
239 s1->snaptime = s2->snaptime;
240 }
241
242 #define DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0)
243
244
245 /* Compute differences between 2 pktsums (s1 = s2 - s3) */
246 void
dladm_stats_diff(pktsum_t * s1,pktsum_t * s2,pktsum_t * s3)247 dladm_stats_diff(pktsum_t *s1, pktsum_t *s2, pktsum_t *s3)
248 {
249 s1->rbytes = DIFF_STAT(s2->rbytes, s3->rbytes);
250 s1->ipackets = DIFF_STAT(s2->ipackets, s3->ipackets);
251 s1->ierrors = DIFF_STAT(s2->ierrors, s3->ierrors);
252 s1->obytes = DIFF_STAT(s2->obytes, s3->obytes);
253 s1->opackets = DIFF_STAT(s2->opackets, s3->opackets);
254 s1->oerrors = DIFF_STAT(s2->oerrors, s3->oerrors);
255 s1->snaptime = DIFF_STAT(s2->snaptime, s3->snaptime);
256 }
257
258 #define DLSTAT_MAC_RX_SWLANE "mac_rx_swlane"
259 #define DLSTAT_MAC_RX_HWLANE "mac_rx_hwlane"
260 #define DLSTAT_MAC_TX_SWLANE "mac_tx_swlane"
261 #define DLSTAT_MAC_TX_HWLANE "mac_tx_hwlane"
262 #define DLSTAT_MAC_MISC_STAT "mac_misc_stat"
263 #define DLSTAT_MAC_RX_RING "mac_rx_ring"
264 #define DLSTAT_MAC_TX_RING "mac_tx_ring"
265 #define DLSTAT_MAC_FANOUT "mac_rx_swlane0_fanout"
266
267 typedef struct {
268 const char *si_name;
269 uint_t si_offset;
270 } stat_info_t;
271
272 #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0]))
273
274 /* Definitions for rx lane stats */
275 #define RL_OFF(f) (offsetof(rx_lane_stat_t, f))
276
277 static stat_info_t rx_hwlane_stats_list[] = {
278 {"ipackets", RL_OFF(rl_ipackets)},
279 {"rbytes", RL_OFF(rl_rbytes)},
280 {"intrs", RL_OFF(rl_intrs)},
281 {"intrbytes", RL_OFF(rl_intrbytes)},
282 {"polls", RL_OFF(rl_polls)},
283 {"pollbytes", RL_OFF(rl_pollbytes)},
284 {"rxsdrops", RL_OFF(rl_sdrops)},
285 {"chainunder10", RL_OFF(rl_chl10)},
286 {"chain10to50", RL_OFF(rl_ch10_50)},
287 {"chainover50", RL_OFF(rl_chg50)}
288 };
289 #define RX_HWLANE_STAT_SIZE A_CNT(rx_hwlane_stats_list)
290
291 static stat_info_t rx_swlane_stats_list[] = {
292 {"ipackets", RL_OFF(rl_ipackets)},
293 {"rbytes", RL_OFF(rl_rbytes)},
294 {"local", RL_OFF(rl_lclpackets)},
295 {"localbytes", RL_OFF(rl_lclbytes)},
296 {"intrs", RL_OFF(rl_intrs)},
297 {"intrbytes", RL_OFF(rl_intrbytes)},
298 {"rxsdrops", RL_OFF(rl_sdrops)}
299 };
300 #define RX_SWLANE_STAT_SIZE A_CNT(rx_swlane_stats_list)
301
302 static stat_info_t rx_lane_stats_list[] = {
303 {"ipackets", RL_OFF(rl_ipackets)},
304 {"rbytes", RL_OFF(rl_rbytes)},
305 {"local", RL_OFF(rl_lclpackets)},
306 {"localbytes", RL_OFF(rl_lclbytes)},
307 {"intrs", RL_OFF(rl_intrs)},
308 {"intrbytes", RL_OFF(rl_intrbytes)},
309 {"polls", RL_OFF(rl_polls)},
310 {"rxsdrops", RL_OFF(rl_sdrops)},
311 {"pollbytes", RL_OFF(rl_pollbytes)},
312 {"chainunder10", RL_OFF(rl_chl10)},
313 {"chain10to50", RL_OFF(rl_ch10_50)},
314 {"chainover50", RL_OFF(rl_chg50)}
315 };
316 #define RX_LANE_STAT_SIZE A_CNT(rx_lane_stats_list)
317
318 /* Definitions for tx lane stats */
319 #define TL_OFF(f) (offsetof(tx_lane_stat_t, f))
320
321 static stat_info_t tx_lane_stats_list[] = {
322 {"opackets", TL_OFF(tl_opackets)},
323 {"obytes", TL_OFF(tl_obytes)},
324 {"blockcnt", TL_OFF(tl_blockcnt)},
325 {"unblockcnt", TL_OFF(tl_unblockcnt)},
326 {"txsdrops", TL_OFF(tl_sdrops)}
327 };
328 #define TX_LANE_STAT_SIZE A_CNT(tx_lane_stats_list)
329
330 /* Definitions for tx/rx misc stats */
331 #define M_OFF(f) (offsetof(misc_stat_t, f))
332
333 static stat_info_t misc_stats_list[] = {
334 {"multircv", M_OFF(ms_multircv)},
335 {"brdcstrcv", M_OFF(ms_brdcstrcv)},
336 {"multixmt", M_OFF(ms_multixmt)},
337 {"brdcstxmt", M_OFF(ms_brdcstxmt)},
338 {"multircvbytes", M_OFF(ms_multircvbytes)},
339 {"brdcstrcvbytes", M_OFF(ms_brdcstrcvbytes)},
340 {"multixmtbytes", M_OFF(ms_multixmtbytes)},
341 {"brdcstxmtbytes", M_OFF(ms_brdcstxmtbytes)},
342 {"txerrors", M_OFF(ms_txerrors)},
343 {"macspoofed", M_OFF(ms_macspoofed)},
344 {"ipspoofed", M_OFF(ms_ipspoofed)},
345 {"dhcpspoofed", M_OFF(ms_dhcpspoofed)},
346 {"restricted", M_OFF(ms_restricted)},
347 {"ipackets", M_OFF(ms_ipackets)},
348 {"rbytes", M_OFF(ms_rbytes)},
349 {"local", M_OFF(ms_local)},
350 {"localbytes", M_OFF(ms_localbytes)},
351 {"intrs", M_OFF(ms_intrs)},
352 {"intrbytes", M_OFF(ms_intrbytes)},
353 {"polls", M_OFF(ms_polls)},
354 {"pollbytes", M_OFF(ms_pollbytes)},
355 {"rxsdrops", M_OFF(ms_rxsdrops)},
356 {"chainunder10", M_OFF(ms_chainunder10)},
357 {"chain10to50", M_OFF(ms_chain10to50)},
358 {"chainover50", M_OFF(ms_chainover50)},
359 {"obytes", M_OFF(ms_obytes)},
360 {"opackets", M_OFF(ms_opackets)},
361 {"blockcnt", M_OFF(ms_blockcnt)},
362 {"unblockcnt", M_OFF(ms_unblockcnt)},
363 {"txsdrops", M_OFF(ms_txsdrops)}
364 };
365 #define MISC_STAT_SIZE A_CNT(misc_stats_list)
366
367 /* Definitions for rx ring stats */
368 #define R_OFF(f) (offsetof(ring_stat_t, f))
369
370 static stat_info_t rx_ring_stats_list[] = {
371 {"ipackets", R_OFF(r_packets)},
372 {"rbytes", R_OFF(r_bytes)}
373 };
374 #define RX_RING_STAT_SIZE A_CNT(rx_ring_stats_list)
375
376 /* Definitions for tx ring stats */
377 static stat_info_t tx_ring_stats_list[] = {
378 {"opackets", R_OFF(r_packets)},
379 {"obytes", R_OFF(r_bytes)}
380 };
381 #define TX_RING_STAT_SIZE A_CNT(tx_ring_stats_list)
382
383 /* Definitions for fanout stats */
384 #define F_OFF(f) (offsetof(fanout_stat_t, f))
385
386 static stat_info_t fanout_stats_list[] = {
387 {"ipackets", F_OFF(f_ipackets)},
388 {"rbytes", F_OFF(f_rbytes)},
389 };
390 #define FANOUT_STAT_SIZE A_CNT(fanout_stats_list)
391
392 /* Definitions for total stats */
393 #define T_OFF(f) (offsetof(total_stat_t, f))
394
395 static stat_info_t total_stats_list[] = {
396 {"ipackets", T_OFF(ts_ipackets)},
397 {"rbytes", T_OFF(ts_rbytes)},
398 {"opackets", T_OFF(ts_opackets)},
399 {"obytes", T_OFF(ts_obytes)}
400 };
401 #define TOTAL_STAT_SIZE A_CNT(total_stats_list)
402
403 /* Definitions for aggr stats */
404 #define AP_OFF(f) (offsetof(aggr_port_stat_t, f))
405
406 static stat_info_t aggr_port_stats_list[] = {
407 {"ipackets64", AP_OFF(ap_ipackets)},
408 {"rbytes64", AP_OFF(ap_rbytes)},
409 {"opackets64", AP_OFF(ap_opackets)},
410 {"obytes64", AP_OFF(ap_obytes)}
411 };
412 #define AGGR_PORT_STAT_SIZE A_CNT(aggr_port_stats_list)
413
414 /* Definitions for flow stats */
415 #define FL_OFF(f) (offsetof(flow_stat_t, f))
416
417 static stat_info_t flow_stats_list[] = {
418 {"ipackets", FL_OFF(fl_ipackets)},
419 {"rbytes", FL_OFF(fl_rbytes)},
420 {"opackets", FL_OFF(fl_opackets)},
421 {"obytes", FL_OFF(fl_obytes)}
422 };
423 #define FLOW_STAT_SIZE A_CNT(flow_stats_list)
424
425 /* Rx lane specific functions */
426 void * dlstat_rx_lane_stats(dladm_handle_t, datalink_id_t);
427 static boolean_t i_dlstat_rx_lane_match(void *, void *);
428 static void * i_dlstat_rx_lane_stat_entry_diff(void *, void *);
429
430 /* Tx lane specific functions */
431 void * dlstat_tx_lane_stats(dladm_handle_t, datalink_id_t);
432 static boolean_t i_dlstat_tx_lane_match(void *, void *);
433 static void * i_dlstat_tx_lane_stat_entry_diff(void *, void *);
434
435 /* Rx lane total specific functions */
436 void * dlstat_rx_lane_total_stats(dladm_handle_t,
437 datalink_id_t);
438
439 /* Tx lane total specific functions */
440 void * dlstat_tx_lane_total_stats(dladm_handle_t,
441 datalink_id_t);
442
443 /* Fanout specific functions */
444 void * dlstat_fanout_stats(dladm_handle_t, datalink_id_t);
445 static boolean_t i_dlstat_fanout_match(void *, void *);
446 static void * i_dlstat_fanout_stat_entry_diff(void *, void *);
447
448 /* Rx ring specific functions */
449 void * dlstat_rx_ring_stats(dladm_handle_t, datalink_id_t);
450 static boolean_t i_dlstat_rx_ring_match(void *, void *);
451 static void * i_dlstat_rx_ring_stat_entry_diff(void *, void *);
452
453 /* Tx ring specific functions */
454 void * dlstat_tx_ring_stats(dladm_handle_t, datalink_id_t);
455 static boolean_t i_dlstat_tx_ring_match(void *, void *);
456 static void * i_dlstat_tx_ring_stat_entry_diff(void *, void *);
457
458 /* Rx ring total specific functions */
459 void * dlstat_rx_ring_total_stats(dladm_handle_t,
460 datalink_id_t);
461
462 /* Tx ring total specific functions */
463 void * dlstat_tx_ring_total_stats(dladm_handle_t,
464 datalink_id_t);
465
466 /* Summary specific functions */
467 void * dlstat_total_stats(dladm_handle_t, datalink_id_t);
468 static boolean_t i_dlstat_total_match(void *, void *);
469 static void * i_dlstat_total_stat_entry_diff(void *, void *);
470
471 /* Aggr port specific functions */
472 void * dlstat_aggr_port_stats(dladm_handle_t, datalink_id_t);
473 static boolean_t i_dlstat_aggr_port_match(void *, void *);
474 static void * i_dlstat_aggr_port_stat_entry_diff(void *, void *);
475
476 /* Misc stat specific functions */
477 void * dlstat_misc_stats(dladm_handle_t, datalink_id_t);
478
479 typedef void * dladm_stat_query_t(dladm_handle_t, datalink_id_t);
480 typedef boolean_t dladm_stat_match_t(void *, void *);
481 typedef void * dladm_stat_diff_t(void *, void *);
482
483 typedef struct dladm_stat_desc_s {
484 dladm_stat_type_t ds_stattype;
485 dladm_stat_query_t *ds_querystat;
486 dladm_stat_match_t *ds_matchstat;
487 dladm_stat_diff_t *ds_diffstat;
488 uint_t ds_offset;
489 stat_info_t *ds_statlist;
490 uint_t ds_statsize;
491 } dladm_stat_desc_t;
492
493 /*
494 * dladm_stat_table has one entry for each supported stat. ds_querystat returns
495 * a chain of 'stat entries' for the queried stat.
496 * Each stat entry has set of identifiers (ids) and an object containing actual
497 * stat values. These stat entry objects are chained together in a linked list
498 * of datatype dladm_stat_chain_t. Head of this list is returned to the caller
499 * of dladm_link_stat_query.
500 *
501 * One node in the chain is shown below:
502 *
503 * -------------------------
504 * | dc_statentry |
505 * | -------------- |
506 * | | ids | |
507 * | -------------- |
508 * | | stat fields | |
509 * | -------------- |
510 * -------------------------
511 * | dc_next ---------|------> to next stat entry
512 * -------------------------
513 *
514 * In particular, for query DLADM_STAT_RX_LANE, dc_statentry carries pointer to
515 * object of type rx_lane_stat_entry_t.
516 *
517 * dladm_link_stat_query_all returns similar chain. However, instead of storing
518 * stat fields as raw numbers, it stores those as chain of <name, value> pairs.
519 * The resulting structure is depicted below:
520 *
521 * -------------------------
522 * | dc_statentry |
523 * | -------------- | ---------------
524 * | | nv_header | | | name, val |
525 * | -------------- | ---------------
526 * | | nve_stats---|----|-->| nv_nextstat--|---> to next name, val pair
527 * | -------------- | ---------------
528 * -------------------------
529 * | dc_next ---------|------> to next stat entry
530 * -------------------------
531 */
532 static dladm_stat_desc_t dladm_stat_table[] = {
533 { DLADM_STAT_RX_LANE, dlstat_rx_lane_stats,
534 i_dlstat_rx_lane_match, i_dlstat_rx_lane_stat_entry_diff,
535 offsetof(rx_lane_stat_entry_t, rle_stats),
536 rx_lane_stats_list, RX_LANE_STAT_SIZE},
537
538 { DLADM_STAT_TX_LANE, dlstat_tx_lane_stats,
539 i_dlstat_tx_lane_match, i_dlstat_tx_lane_stat_entry_diff,
540 offsetof(tx_lane_stat_entry_t, tle_stats),
541 tx_lane_stats_list, TX_LANE_STAT_SIZE},
542
543 { DLADM_STAT_RX_LANE_TOTAL, dlstat_rx_lane_total_stats,
544 i_dlstat_rx_lane_match, i_dlstat_rx_lane_stat_entry_diff,
545 offsetof(rx_lane_stat_entry_t, rle_stats),
546 rx_lane_stats_list, RX_LANE_STAT_SIZE},
547
548 { DLADM_STAT_TX_LANE_TOTAL, dlstat_tx_lane_total_stats,
549 i_dlstat_tx_lane_match, i_dlstat_tx_lane_stat_entry_diff,
550 offsetof(tx_lane_stat_entry_t, tle_stats),
551 tx_lane_stats_list, TX_LANE_STAT_SIZE},
552
553 { DLADM_STAT_RX_LANE_FOUT, dlstat_fanout_stats,
554 i_dlstat_fanout_match, i_dlstat_fanout_stat_entry_diff,
555 offsetof(fanout_stat_entry_t, fe_stats),
556 fanout_stats_list, FANOUT_STAT_SIZE},
557
558 { DLADM_STAT_RX_RING, dlstat_rx_ring_stats,
559 i_dlstat_rx_ring_match, i_dlstat_rx_ring_stat_entry_diff,
560 offsetof(ring_stat_entry_t, re_stats),
561 rx_ring_stats_list, RX_RING_STAT_SIZE},
562
563 { DLADM_STAT_TX_RING, dlstat_tx_ring_stats,
564 i_dlstat_tx_ring_match, i_dlstat_tx_ring_stat_entry_diff,
565 offsetof(ring_stat_entry_t, re_stats),
566 tx_ring_stats_list, TX_RING_STAT_SIZE},
567
568 { DLADM_STAT_RX_RING_TOTAL, dlstat_rx_ring_total_stats,
569 i_dlstat_rx_ring_match, i_dlstat_rx_ring_stat_entry_diff,
570 offsetof(ring_stat_entry_t, re_stats),
571 rx_ring_stats_list, RX_RING_STAT_SIZE},
572
573 { DLADM_STAT_TX_RING_TOTAL, dlstat_tx_ring_total_stats,
574 i_dlstat_tx_ring_match, i_dlstat_tx_ring_stat_entry_diff,
575 offsetof(ring_stat_entry_t, re_stats),
576 tx_ring_stats_list, TX_RING_STAT_SIZE},
577
578 { DLADM_STAT_TOTAL, dlstat_total_stats,
579 i_dlstat_total_match, i_dlstat_total_stat_entry_diff,
580 offsetof(total_stat_entry_t, tse_stats),
581 total_stats_list, TOTAL_STAT_SIZE},
582
583 { DLADM_STAT_AGGR_PORT, dlstat_aggr_port_stats,
584 i_dlstat_aggr_port_match, i_dlstat_aggr_port_stat_entry_diff,
585 offsetof(aggr_port_stat_entry_t, ape_stats),
586 aggr_port_stats_list, AGGR_PORT_STAT_SIZE},
587 /*
588 * We don't support -i <interval> query with misc stats. Several table fields
589 * are left uninitialized thus.
590 */
591 { DLADM_STAT_MISC, dlstat_misc_stats,
592 NULL, NULL,
593 0,
594 misc_stats_list, MISC_STAT_SIZE}
595 };
596
597 /* Internal functions */
598 static void *
dlstat_diff_stats(void * arg1,void * arg2,dladm_stat_type_t stattype)599 dlstat_diff_stats(void *arg1, void *arg2, dladm_stat_type_t stattype)
600 {
601 return (dladm_stat_table[stattype].ds_diffstat(arg1, arg2));
602 }
603
604 static boolean_t
dlstat_match_stats(void * arg1,void * arg2,dladm_stat_type_t stattype)605 dlstat_match_stats(void *arg1, void *arg2, dladm_stat_type_t stattype)
606 {
607 return (dladm_stat_table[stattype].ds_matchstat(arg1, arg2));
608 }
609
610 /* Diff between two stats */
611 static void
i_dlstat_diff_stats(void * diff,void * op1,void * op2,stat_info_t stats_list[],uint_t size)612 i_dlstat_diff_stats(void *diff, void *op1, void *op2,
613 stat_info_t stats_list[], uint_t size)
614 {
615 uint_t i;
616
617 for (i = 0; i < size; i++) {
618 uint64_t *op1_val = (void *)
619 ((uchar_t *)op1 + stats_list[i].si_offset);
620 uint64_t *op2_val = (void *)
621 ((uchar_t *)op2 + stats_list[i].si_offset);
622 uint64_t *diff_val = (void *)
623 ((uchar_t *)diff + stats_list[i].si_offset);
624
625 *diff_val = DIFF_STAT(*op1_val, *op2_val);
626 }
627 }
628
629 /*
630 * Perform diff = s1 - s2, where diff, s1, s2 are structure objects of same
631 * datatype. slist is list of offsets of the fields within the structure.
632 */
633 #define DLSTAT_DIFF_STAT(s1, s2, diff, f, slist, sz) { \
634 if (s2 == NULL) { \
635 bcopy(&s1->f, &diff->f, sizeof (s1->f)); \
636 } else { \
637 i_dlstat_diff_stats(&diff->f, &s1->f, \
638 &s2->f, slist, sz); \
639 } \
640 }
641
642 /* Sum two stats */
643 static void
i_dlstat_sum_stats(void * sum,void * op1,void * op2,stat_info_t stats_list[],uint_t size)644 i_dlstat_sum_stats(void *sum, void *op1, void *op2,
645 stat_info_t stats_list[], uint_t size)
646 {
647 uint_t i;
648
649 for (i = 0; i < size; i++) {
650 uint64_t *op1_val = (void *)
651 ((uchar_t *)op1 + stats_list[i].si_offset);
652 uint64_t *op2_val = (void *)
653 ((uchar_t *)op2 + stats_list[i].si_offset);
654 uint64_t *sum_val = (void *)
655 ((uchar_t *)sum + stats_list[i].si_offset);
656
657 *sum_val = *op1_val + *op2_val;
658 }
659 }
660
661 /* Look up kstat value */
662 static void
i_dlstat_get_stats(kstat_ctl_t * kcp,kstat_t * ksp,void * stats,stat_info_t stats_list[],uint_t size)663 i_dlstat_get_stats(kstat_ctl_t *kcp, kstat_t *ksp, void *stats,
664 stat_info_t stats_list[], uint_t size)
665 {
666 uint_t i;
667
668 if (kstat_read(kcp, ksp, NULL) == -1)
669 return;
670
671 for (i = 0; i < size; i++) {
672 uint64_t *val = (void *)
673 ((uchar_t *)stats + stats_list[i].si_offset);
674
675 if (dladm_kstat_value(ksp, stats_list[i].si_name,
676 KSTAT_DATA_UINT64, val) < 0)
677 return;
678 }
679 }
680
681 /* Append linked list list1 to linked list list2 and return resulting list */
682 static dladm_stat_chain_t *
i_dlstat_join_lists(dladm_stat_chain_t * list1,dladm_stat_chain_t * list2)683 i_dlstat_join_lists(dladm_stat_chain_t *list1, dladm_stat_chain_t *list2)
684 {
685 dladm_stat_chain_t *curr;
686
687 if (list1 == NULL)
688 return (list2);
689
690 /* list1 has at least one element, find last element in list1 */
691 curr = list1;
692 while (curr->dc_next != NULL)
693 curr = curr->dc_next;
694
695 curr->dc_next = list2;
696 return (list1);
697 }
698
699 uint_t default_idlist[] = {0};
700 uint_t default_idlist_size = 1;
701
702 typedef enum {
703 DLSTAT_RX_RING_IDLIST,
704 DLSTAT_TX_RING_IDLIST,
705 DLSTAT_RX_HWLANE_IDLIST,
706 DLSTAT_TX_HWLANE_IDLIST,
707 DLSTAT_FANOUT_IDLIST
708 } dlstat_idlist_type_t;
709
710 void
dladm_sort_index_list(uint_t idlist[],uint_t size)711 dladm_sort_index_list(uint_t idlist[], uint_t size)
712 {
713 uint_t j;
714 int i;
715
716 for (j = 1; j < size; j++) {
717 uint_t key = idlist[j];
718
719 for (i = j - 1; (i >= 0) && (idlist[i] > key); i--)
720 idlist[i + 1] = idlist[i];
721 idlist[i + 1] = key;
722 }
723 }
724
725 /* Support for legacy drivers */
726 void
i_query_legacy_stats(dladm_handle_t dh,const char * linkname,pktsum_t * stats)727 i_query_legacy_stats(dladm_handle_t dh, const char *linkname, pktsum_t *stats)
728 {
729 kstat_t *ksp;
730
731 bzero(stats, sizeof (*stats));
732
733 if (dladm_dld_kcp(dh) == NULL)
734 return;
735
736 ksp = dladm_kstat_lookup(dladm_dld_kcp(dh), "link", 0, linkname, NULL);
737
738 if (ksp != NULL)
739 dladm_get_stats(dladm_dld_kcp(dh), ksp, stats);
740 }
741
742 void *
i_dlstat_legacy_rx_lane_stats(dladm_handle_t dh,const char * linkname)743 i_dlstat_legacy_rx_lane_stats(dladm_handle_t dh, const char *linkname)
744 {
745 dladm_stat_chain_t *head = NULL;
746 pktsum_t stats;
747 rx_lane_stat_entry_t *rx_lane_stat_entry;
748
749 bzero(&stats, sizeof (pktsum_t));
750
751 /* Query for dls stats */
752 i_query_legacy_stats(dh, linkname, &stats);
753
754 /* Convert to desired data type */
755 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
756 if (rx_lane_stat_entry == NULL)
757 goto done;
758
759 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
760 rx_lane_stat_entry->rle_id = L_SWLANE;
761
762 rx_lane_stat_entry->rle_stats.rl_ipackets = stats.ipackets;
763 rx_lane_stat_entry->rle_stats.rl_intrs = stats.ipackets;
764 rx_lane_stat_entry->rle_stats.rl_rbytes = stats.rbytes;
765
766 /* Allocate memory for wrapper */
767 head = malloc(sizeof (dladm_stat_chain_t));
768 if (head == NULL) {
769 free(rx_lane_stat_entry);
770 goto done;
771 }
772
773 head->dc_statentry = rx_lane_stat_entry;
774 head->dc_next = NULL;
775 done:
776 return (head);
777 }
778
779 void *
i_dlstat_legacy_tx_lane_stats(dladm_handle_t dh,const char * linkname)780 i_dlstat_legacy_tx_lane_stats(dladm_handle_t dh, const char *linkname)
781 {
782 dladm_stat_chain_t *head = NULL;
783 pktsum_t stats;
784 tx_lane_stat_entry_t *tx_lane_stat_entry;
785
786 bzero(&stats, sizeof (pktsum_t));
787
788 /* Query for dls stats */
789 i_query_legacy_stats(dh, linkname, &stats);
790
791 /* Convert to desired data type */
792 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
793 if (tx_lane_stat_entry == NULL)
794 goto done;
795
796 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
797 tx_lane_stat_entry->tle_id = L_SWLANE;
798
799 tx_lane_stat_entry->tle_stats.tl_opackets = stats.opackets;
800 tx_lane_stat_entry->tle_stats.tl_obytes = stats.obytes;
801
802 /* Allocate memory for wrapper */
803 head = malloc(sizeof (dladm_stat_chain_t));
804 if (head == NULL) {
805 free(tx_lane_stat_entry);
806 goto done;
807 }
808
809 head->dc_statentry = tx_lane_stat_entry;
810 head->dc_next = NULL;
811 done:
812 return (head);
813 }
814
815 /*
816 * Ideally, we would want an ioctl to return list of ring-ids (or lane-ids)
817 * for a given data-link (or mac client). We could then query for specific
818 * kstats based on these ring-ids (lane-ids).
819 * Ring-ids (or lane-ids) could be returned like any other link properties
820 * queried by dladm show-linkprop. However, non-global zones do not have
821 * access to this information today.
822 * We thus opt for an implementation that relies heavily on kstat internals:
823 * i_dlstat_*search routines and i_dlstat_get_idlist.
824 */
825 /* rx hwlane specific */
826 static boolean_t
i_dlstat_rx_hwlane_search(kstat_t * ksp)827 i_dlstat_rx_hwlane_search(kstat_t *ksp)
828 {
829 return (ksp->ks_instance == 0 &&
830 strstr(ksp->ks_name, "mac_rx") != 0 &&
831 strstr(ksp->ks_name, "hwlane") != 0 &&
832 strstr(ksp->ks_name, "fanout") == 0 &&
833 strcmp(ksp->ks_class, "net") == 0);
834 }
835
836 /* tx hwlane specific */
837 static boolean_t
i_dlstat_tx_hwlane_search(kstat_t * ksp)838 i_dlstat_tx_hwlane_search(kstat_t *ksp)
839 {
840 return (ksp->ks_instance == 0 &&
841 strstr(ksp->ks_name, "mac_tx") != 0 &&
842 strstr(ksp->ks_name, "hwlane") != 0 &&
843 strcmp(ksp->ks_class, "net") == 0);
844 }
845
846 /* rx fanout specific */
847 static boolean_t
i_dlstat_fanout_search(kstat_t * ksp)848 i_dlstat_fanout_search(kstat_t *ksp)
849 {
850 return (ksp->ks_instance == 0 &&
851 strstr(ksp->ks_name, "mac_rx") != 0 &&
852 strstr(ksp->ks_name, "swlane") != 0 &&
853 strstr(ksp->ks_name, "fanout") != 0 &&
854 strcmp(ksp->ks_class, "net") == 0);
855 }
856
857 /* rx ring specific */
858 static boolean_t
i_dlstat_rx_ring_search(kstat_t * ksp)859 i_dlstat_rx_ring_search(kstat_t *ksp)
860 {
861 return (ksp->ks_instance == 0 &&
862 strstr(ksp->ks_name, "mac_rx") != 0 &&
863 strstr(ksp->ks_name, "ring") != 0 &&
864 strcmp(ksp->ks_class, "net") == 0);
865 }
866
867 /* tx ring specific */
868 static boolean_t
i_dlstat_tx_ring_search(kstat_t * ksp)869 i_dlstat_tx_ring_search(kstat_t *ksp)
870 {
871 return (ksp->ks_instance == 0) &&
872 strstr(ksp->ks_name, "mac_tx") != 0 &&
873 strstr(ksp->ks_name, "ring") != 0 &&
874 strcmp(ksp->ks_class, "net") == 0;
875 }
876
877 typedef boolean_t dladm_search_kstat_t(kstat_t *);
878 typedef struct dladm_extract_idlist_s {
879 dlstat_idlist_type_t di_type;
880 char *di_prefix;
881 dladm_search_kstat_t *di_searchkstat;
882 } dladm_extract_idlist_t;
883
884 static dladm_extract_idlist_t dladm_extract_idlist[] = {
885 { DLSTAT_RX_RING_IDLIST, DLSTAT_MAC_RX_RING,
886 i_dlstat_rx_ring_search},
887 { DLSTAT_TX_RING_IDLIST, DLSTAT_MAC_TX_RING,
888 i_dlstat_tx_ring_search},
889 { DLSTAT_RX_HWLANE_IDLIST, DLSTAT_MAC_RX_HWLANE,
890 i_dlstat_rx_hwlane_search},
891 { DLSTAT_TX_HWLANE_IDLIST, DLSTAT_MAC_TX_HWLANE,
892 i_dlstat_tx_hwlane_search},
893 { DLSTAT_FANOUT_IDLIST, DLSTAT_MAC_FANOUT,
894 i_dlstat_fanout_search}
895 };
896
897 static void
i_dlstat_get_idlist(dladm_handle_t handle,const char * modname,dlstat_idlist_type_t idlist_type,uint_t idlist[],uint_t * size)898 i_dlstat_get_idlist(dladm_handle_t handle, const char *modname,
899 dlstat_idlist_type_t idlist_type,
900 uint_t idlist[], uint_t *size)
901 {
902 kstat_ctl_t *kcp = dladm_dld_kcp(handle);
903 kstat_t *ksp;
904 char *prefix;
905 int prefixlen;
906 boolean_t (*fptr_searchkstat)(kstat_t *);
907
908 *size = 0;
909
910 if (kcp == NULL) {
911 warn("kstat_open operation failed");
912 return;
913 }
914
915 prefix = dladm_extract_idlist[idlist_type].di_prefix;
916 fptr_searchkstat = dladm_extract_idlist[idlist_type].di_searchkstat;
917 prefixlen = strlen(prefix);
918 for (ksp = kcp->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
919 if ((strcmp(ksp->ks_module, modname) == 0) &&
920 fptr_searchkstat(ksp)) {
921 idlist[(*size)++] = atoi(&ksp->ks_name[prefixlen]);
922 }
923 }
924 dladm_sort_index_list(idlist, *size);
925 }
926
927 static dladm_stat_chain_t *
i_dlstat_query_stats(dladm_handle_t handle,const char * modname,const char * prefix,uint_t idlist[],uint_t idlist_size,void * (* fn)(kstat_ctl_t *,kstat_t *,int))928 i_dlstat_query_stats(dladm_handle_t handle, const char *modname,
929 const char *prefix, uint_t idlist[], uint_t idlist_size,
930 void * (*fn)(kstat_ctl_t *, kstat_t *, int))
931 {
932 kstat_t *ksp;
933 char statname[MAXLINKNAMELEN];
934 uint_t i;
935 dladm_stat_chain_t *head = NULL, *prev = NULL;
936 dladm_stat_chain_t *curr;
937
938 if (dladm_dld_kcp(handle) == NULL) {
939 warn("kstat_open operation failed");
940 return (NULL);
941 }
942
943 for (i = 0; i < idlist_size; i++) {
944 uint_t index = idlist[i];
945
946 (void) snprintf(statname, sizeof (statname), "%s%d", prefix,
947 index);
948
949 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), modname, 0,
950 statname, NULL);
951 if (ksp == NULL)
952 continue;
953
954 curr = malloc(sizeof (dladm_stat_chain_t));
955 if (curr == NULL)
956 break;
957
958 curr->dc_statentry = fn(dladm_dld_kcp(handle), ksp, index);
959 if (curr->dc_statentry == NULL) {
960 free(curr);
961 break;
962 }
963
964 (void) strlcpy(curr->dc_statheader, statname,
965 sizeof (curr->dc_statheader));
966 curr->dc_next = NULL;
967
968 if (head == NULL) /* First node */
969 head = curr;
970 else
971 prev->dc_next = curr;
972
973 prev = curr;
974 }
975 return (head);
976 }
977
978 static misc_stat_entry_t *
i_dlstat_misc_stats(dladm_handle_t handle,const char * linkname)979 i_dlstat_misc_stats(dladm_handle_t handle, const char *linkname)
980 {
981 kstat_t *ksp;
982 misc_stat_entry_t *misc_stat_entry = NULL;
983
984 if (dladm_dld_kcp(handle) == NULL)
985 return (NULL);
986
987 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), linkname, 0,
988 DLSTAT_MAC_MISC_STAT, NULL);
989 if (ksp == NULL)
990 goto done;
991
992 misc_stat_entry = calloc(1, sizeof (misc_stat_entry_t));
993 if (misc_stat_entry == NULL)
994 goto done;
995
996 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp,
997 &misc_stat_entry->mse_stats,
998 misc_stats_list, MISC_STAT_SIZE);
999 done:
1000 return (misc_stat_entry);
1001 }
1002
1003 /* Rx lane statistic specific functions */
1004 static boolean_t
i_dlstat_rx_lane_match(void * arg1,void * arg2)1005 i_dlstat_rx_lane_match(void *arg1, void *arg2)
1006 {
1007 rx_lane_stat_entry_t *s1 = arg1;
1008 rx_lane_stat_entry_t *s2 = arg2;
1009
1010 return (s1->rle_index == s2->rle_index &&
1011 s1->rle_id == s2->rle_id);
1012 }
1013
1014 static void *
i_dlstat_rx_lane_stat_entry_diff(void * arg1,void * arg2)1015 i_dlstat_rx_lane_stat_entry_diff(void *arg1, void *arg2)
1016 {
1017 rx_lane_stat_entry_t *s1 = arg1;
1018 rx_lane_stat_entry_t *s2 = arg2;
1019 rx_lane_stat_entry_t *diff_entry;
1020
1021 diff_entry = malloc(sizeof (rx_lane_stat_entry_t));
1022 if (diff_entry == NULL)
1023 goto done;
1024
1025 diff_entry->rle_index = s1->rle_index;
1026 diff_entry->rle_id = s1->rle_id;
1027
1028 DLSTAT_DIFF_STAT(s1, s2, diff_entry, rle_stats, rx_lane_stats_list,
1029 RX_LANE_STAT_SIZE);
1030
1031 done:
1032 return (diff_entry);
1033 }
1034
1035 static void *
i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1036 i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1037 {
1038 rx_lane_stat_entry_t *rx_lane_stat_entry;
1039
1040 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1041 if (rx_lane_stat_entry == NULL)
1042 goto done;
1043
1044 rx_lane_stat_entry->rle_index = i;
1045 rx_lane_stat_entry->rle_id = L_HWLANE;
1046
1047 i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1048 rx_hwlane_stats_list, RX_HWLANE_STAT_SIZE);
1049
1050 done:
1051 return (rx_lane_stat_entry);
1052 }
1053
1054 static void *
i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i __unused)1055 i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused)
1056 {
1057 rx_lane_stat_entry_t *rx_lane_stat_entry;
1058
1059 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1060 if (rx_lane_stat_entry == NULL)
1061 goto done;
1062
1063 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1064 rx_lane_stat_entry->rle_id = L_SWLANE;
1065
1066 i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1067 rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
1068
1069 rx_lane_stat_entry->rle_stats.rl_ipackets =
1070 rx_lane_stat_entry->rle_stats.rl_intrs;
1071 rx_lane_stat_entry->rle_stats.rl_rbytes =
1072 rx_lane_stat_entry->rle_stats.rl_intrbytes;
1073 done:
1074 return (rx_lane_stat_entry);
1075 }
1076
1077 static void *
i_dlstat_rx_local_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i __unused)1078 i_dlstat_rx_local_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused)
1079 {
1080 rx_lane_stat_entry_t *local_stat_entry = NULL;
1081 rx_lane_stat_entry_t *rx_lane_stat_entry;
1082
1083 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1084 if (rx_lane_stat_entry == NULL)
1085 goto done;
1086
1087 local_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1088 if (local_stat_entry == NULL)
1089 goto done;
1090
1091 local_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1092 local_stat_entry->rle_id = L_LOCAL;
1093
1094 i_dlstat_get_stats(kcp, ksp, &rx_lane_stat_entry->rle_stats,
1095 rx_swlane_stats_list, RX_SWLANE_STAT_SIZE);
1096
1097 local_stat_entry->rle_stats.rl_ipackets =
1098 rx_lane_stat_entry->rle_stats.rl_lclpackets;
1099 local_stat_entry->rle_stats.rl_rbytes =
1100 rx_lane_stat_entry->rle_stats.rl_lclbytes;
1101
1102 done:
1103 free(rx_lane_stat_entry);
1104 return (local_stat_entry);
1105 }
1106
1107 static dladm_stat_chain_t *
i_dlstat_rx_local_stats(dladm_handle_t handle,const char * linkname)1108 i_dlstat_rx_local_stats(dladm_handle_t handle, const char *linkname)
1109 {
1110 dladm_stat_chain_t *local_stats = NULL;
1111
1112 local_stats = i_dlstat_query_stats(handle, linkname,
1113 DLSTAT_MAC_RX_SWLANE,
1114 default_idlist, default_idlist_size,
1115 i_dlstat_rx_local_retrieve_stat);
1116
1117 if (local_stats != NULL) {
1118 (void) strlcpy(local_stats->dc_statheader, "mac_rx_local",
1119 sizeof (local_stats->dc_statheader));
1120 }
1121 return (local_stats);
1122 }
1123
1124 static dladm_stat_chain_t *
i_dlstat_rx_bcast_stats(dladm_handle_t handle,const char * linkname)1125 i_dlstat_rx_bcast_stats(dladm_handle_t handle, const char *linkname)
1126 {
1127 misc_stat_entry_t *misc_stat_entry;
1128 dladm_stat_chain_t *head = NULL;
1129 rx_lane_stat_entry_t *rx_lane_stat_entry;
1130
1131 misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
1132 if (misc_stat_entry == NULL)
1133 goto done;
1134
1135 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1136 if (rx_lane_stat_entry == NULL)
1137 goto done;
1138
1139 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1140 rx_lane_stat_entry->rle_id = L_BCAST;
1141
1142 rx_lane_stat_entry->rle_stats.rl_ipackets =
1143 misc_stat_entry->mse_stats.ms_brdcstrcv +
1144 misc_stat_entry->mse_stats.ms_multircv;
1145 rx_lane_stat_entry->rle_stats.rl_intrs =
1146 misc_stat_entry->mse_stats.ms_brdcstrcv +
1147 misc_stat_entry->mse_stats.ms_multircv;
1148 rx_lane_stat_entry->rle_stats.rl_rbytes =
1149 misc_stat_entry->mse_stats.ms_brdcstrcvbytes +
1150 misc_stat_entry->mse_stats.ms_multircvbytes;
1151
1152 head = malloc(sizeof (dladm_stat_chain_t));
1153 if (head == NULL) {
1154 free(rx_lane_stat_entry);
1155 goto done;
1156 }
1157
1158 head->dc_statentry = rx_lane_stat_entry;
1159 head->dc_next = NULL;
1160
1161 done:
1162 free(misc_stat_entry);
1163 return (head);
1164 }
1165
1166 static dladm_stat_chain_t *
i_dlstat_rx_defunctlane_stats(dladm_handle_t handle,const char * linkname)1167 i_dlstat_rx_defunctlane_stats(dladm_handle_t handle, const char *linkname)
1168 {
1169 misc_stat_entry_t *misc_stat_entry;
1170 dladm_stat_chain_t *head = NULL;
1171 rx_lane_stat_entry_t *rx_lane_stat_entry;
1172
1173 misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
1174 if (misc_stat_entry == NULL)
1175 goto done;
1176
1177 rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
1178 if (rx_lane_stat_entry == NULL)
1179 goto done;
1180
1181 rx_lane_stat_entry->rle_index = DLSTAT_INVALID_ENTRY;
1182 rx_lane_stat_entry->rle_id = L_DFNCT;
1183
1184 rx_lane_stat_entry->rle_stats.rl_ipackets =
1185 misc_stat_entry->mse_stats.ms_ipackets;
1186 rx_lane_stat_entry->rle_stats.rl_rbytes =
1187 misc_stat_entry->mse_stats.ms_rbytes;
1188 rx_lane_stat_entry->rle_stats.rl_intrs =
1189 misc_stat_entry->mse_stats.ms_intrs;
1190 rx_lane_stat_entry->rle_stats.rl_polls =
1191 misc_stat_entry->mse_stats.ms_polls;
1192 rx_lane_stat_entry->rle_stats.rl_sdrops =
1193 misc_stat_entry->mse_stats.ms_rxsdrops;
1194 rx_lane_stat_entry->rle_stats.rl_chl10 =
1195 misc_stat_entry->mse_stats.ms_chainunder10;
1196 rx_lane_stat_entry->rle_stats.rl_ch10_50 =
1197 misc_stat_entry->mse_stats.ms_chain10to50;
1198 rx_lane_stat_entry->rle_stats.rl_chg50 =
1199 misc_stat_entry->mse_stats.ms_chainover50;
1200
1201 head = malloc(sizeof (dladm_stat_chain_t));
1202 if (head == NULL) {
1203 free(rx_lane_stat_entry);
1204 goto done;
1205 }
1206
1207 head->dc_statentry = rx_lane_stat_entry;
1208 head->dc_next = NULL;
1209
1210 done:
1211 free(misc_stat_entry);
1212 return (head);
1213 }
1214
1215 static dladm_stat_chain_t *
i_dlstat_rx_hwlane_stats(dladm_handle_t handle,const char * linkname)1216 i_dlstat_rx_hwlane_stats(dladm_handle_t handle, const char *linkname)
1217 {
1218 uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1219 uint_t rx_hwlane_idlist_size;
1220
1221 i_dlstat_get_idlist(handle, linkname, DLSTAT_RX_HWLANE_IDLIST,
1222 rx_hwlane_idlist, &rx_hwlane_idlist_size);
1223
1224 return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_RX_HWLANE,
1225 rx_hwlane_idlist, rx_hwlane_idlist_size,
1226 i_dlstat_rx_hwlane_retrieve_stat));
1227 }
1228
1229 static dladm_stat_chain_t *
i_dlstat_rx_swlane_stats(dladm_handle_t dh,datalink_id_t linkid __unused,const char * linkname)1230 i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid __unused,
1231 const char *linkname)
1232 {
1233 return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_RX_SWLANE,
1234 default_idlist, default_idlist_size,
1235 i_dlstat_rx_swlane_retrieve_stat));
1236 }
1237
1238 void *
dlstat_rx_lane_stats(dladm_handle_t dh,datalink_id_t linkid)1239 dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1240 {
1241 dladm_stat_chain_t *head = NULL;
1242 dladm_stat_chain_t *local_stats = NULL;
1243 dladm_stat_chain_t *bcast_stats = NULL;
1244 dladm_stat_chain_t *defunctlane_stats = NULL;
1245 dladm_stat_chain_t *lane_stats = NULL;
1246 char linkname[MAXLINKNAMELEN];
1247 boolean_t is_legacy_driver;
1248
1249 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1250 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1251 goto done;
1252 }
1253
1254 /* Check if it is legacy driver */
1255 if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1256 "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1257 goto done;
1258 }
1259
1260 if (is_legacy_driver) {
1261 head = i_dlstat_legacy_rx_lane_stats(dh, linkname);
1262 goto done;
1263 }
1264
1265 local_stats = i_dlstat_rx_local_stats(dh, linkname);
1266 bcast_stats = i_dlstat_rx_bcast_stats(dh, linkname);
1267 defunctlane_stats = i_dlstat_rx_defunctlane_stats(dh, linkname);
1268 lane_stats = i_dlstat_rx_hwlane_stats(dh, linkname);
1269 if (lane_stats == NULL)
1270 lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname);
1271
1272 head = i_dlstat_join_lists(local_stats, bcast_stats);
1273 head = i_dlstat_join_lists(head, defunctlane_stats);
1274 head = i_dlstat_join_lists(head, lane_stats);
1275 done:
1276 return (head);
1277 }
1278
1279 /* Tx lane statistic specific functions */
1280 static boolean_t
i_dlstat_tx_lane_match(void * arg1,void * arg2)1281 i_dlstat_tx_lane_match(void *arg1, void *arg2)
1282 {
1283 tx_lane_stat_entry_t *s1 = arg1;
1284 tx_lane_stat_entry_t *s2 = arg2;
1285
1286 return (s1->tle_index == s2->tle_index &&
1287 s1->tle_id == s2->tle_id);
1288 }
1289
1290 static void *
i_dlstat_tx_lane_stat_entry_diff(void * arg1,void * arg2)1291 i_dlstat_tx_lane_stat_entry_diff(void *arg1, void *arg2)
1292 {
1293 tx_lane_stat_entry_t *s1 = arg1;
1294 tx_lane_stat_entry_t *s2 = arg2;
1295 tx_lane_stat_entry_t *diff_entry;
1296
1297 diff_entry = malloc(sizeof (tx_lane_stat_entry_t));
1298 if (diff_entry == NULL)
1299 goto done;
1300
1301 diff_entry->tle_index = s1->tle_index;
1302 diff_entry->tle_id = s1->tle_id;
1303
1304 DLSTAT_DIFF_STAT(s1, s2, diff_entry, tle_stats, tx_lane_stats_list,
1305 TX_LANE_STAT_SIZE);
1306
1307 done:
1308 return (diff_entry);
1309 }
1310
1311 static void *
i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1312 i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1313 {
1314 tx_lane_stat_entry_t *tx_lane_stat_entry;
1315
1316 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1317 if (tx_lane_stat_entry == NULL)
1318 goto done;
1319
1320 tx_lane_stat_entry->tle_index = i;
1321 tx_lane_stat_entry->tle_id = L_HWLANE;
1322
1323 i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
1324 tx_lane_stats_list, TX_LANE_STAT_SIZE);
1325
1326 done:
1327 return (tx_lane_stat_entry);
1328 }
1329
1330 static void *
i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i __unused)1331 i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused)
1332 {
1333 tx_lane_stat_entry_t *tx_lane_stat_entry;
1334
1335 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1336 if (tx_lane_stat_entry == NULL)
1337 goto done;
1338
1339 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1340 tx_lane_stat_entry->tle_id = L_SWLANE;
1341
1342 i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
1343 tx_lane_stats_list, TX_LANE_STAT_SIZE);
1344
1345 done:
1346 return (tx_lane_stat_entry);
1347 }
1348
1349 static dladm_stat_chain_t *
i_dlstat_tx_bcast_stats(dladm_handle_t handle,const char * linkname)1350 i_dlstat_tx_bcast_stats(dladm_handle_t handle, const char *linkname)
1351 {
1352 misc_stat_entry_t *misc_stat_entry;
1353 dladm_stat_chain_t *head = NULL;
1354 tx_lane_stat_entry_t *tx_lane_stat_entry;
1355
1356 misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
1357 if (misc_stat_entry == NULL)
1358 goto done;
1359
1360 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1361 if (tx_lane_stat_entry == NULL)
1362 goto done;
1363
1364 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1365 tx_lane_stat_entry->tle_id = L_BCAST;
1366
1367 tx_lane_stat_entry->tle_stats.tl_opackets =
1368 misc_stat_entry->mse_stats.ms_brdcstxmt +
1369 misc_stat_entry->mse_stats.ms_multixmt;
1370
1371 tx_lane_stat_entry->tle_stats.tl_obytes =
1372 misc_stat_entry->mse_stats.ms_brdcstxmtbytes +
1373 misc_stat_entry->mse_stats.ms_multixmtbytes;
1374
1375 head = malloc(sizeof (dladm_stat_chain_t));
1376 if (head == NULL) {
1377 free(tx_lane_stat_entry);
1378 goto done;
1379 }
1380
1381 head->dc_statentry = tx_lane_stat_entry;
1382 head->dc_next = NULL;
1383
1384 done:
1385 free(misc_stat_entry);
1386 return (head);
1387 }
1388
1389 static dladm_stat_chain_t *
i_dlstat_tx_defunctlane_stats(dladm_handle_t handle,const char * linkname)1390 i_dlstat_tx_defunctlane_stats(dladm_handle_t handle, const char *linkname)
1391 {
1392 misc_stat_entry_t *misc_stat_entry;
1393 dladm_stat_chain_t *head = NULL;
1394 tx_lane_stat_entry_t *tx_lane_stat_entry;
1395
1396 misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
1397 if (misc_stat_entry == NULL)
1398 goto done;
1399
1400 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1401 if (tx_lane_stat_entry == NULL)
1402 goto done;
1403
1404 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1405 tx_lane_stat_entry->tle_id = L_DFNCT;
1406
1407 tx_lane_stat_entry->tle_stats.tl_opackets =
1408 misc_stat_entry->mse_stats.ms_opackets;
1409 tx_lane_stat_entry->tle_stats.tl_obytes =
1410 misc_stat_entry->mse_stats.ms_obytes;
1411 tx_lane_stat_entry->tle_stats.tl_sdrops =
1412 misc_stat_entry->mse_stats.ms_txsdrops;
1413
1414 head = malloc(sizeof (dladm_stat_chain_t));
1415 if (head == NULL) {
1416 free(tx_lane_stat_entry);
1417 goto done;
1418 }
1419
1420 head->dc_statentry = tx_lane_stat_entry;
1421 head->dc_next = NULL;
1422
1423 done:
1424 free(misc_stat_entry);
1425 return (head);
1426 }
1427
1428 static dladm_stat_chain_t *
i_dlstat_tx_hwlane_stats(dladm_handle_t handle,const char * linkname)1429 i_dlstat_tx_hwlane_stats(dladm_handle_t handle, const char *linkname)
1430 {
1431 uint_t tx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1432 uint_t tx_hwlane_idlist_size;
1433
1434 i_dlstat_get_idlist(handle, linkname, DLSTAT_TX_HWLANE_IDLIST,
1435 tx_hwlane_idlist, &tx_hwlane_idlist_size);
1436
1437 return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_TX_HWLANE,
1438 tx_hwlane_idlist, tx_hwlane_idlist_size,
1439 i_dlstat_tx_hwlane_retrieve_stat));
1440 }
1441
1442 static dladm_stat_chain_t *
i_dlstat_tx_swlane_stats(dladm_handle_t dh,datalink_id_t linkid __unused,const char * linkname)1443 i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid __unused,
1444 const char *linkname)
1445 {
1446 return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_TX_SWLANE,
1447 default_idlist, default_idlist_size,
1448 i_dlstat_tx_swlane_retrieve_stat));
1449 }
1450
1451 void *
dlstat_tx_lane_stats(dladm_handle_t dh,datalink_id_t linkid)1452 dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1453 {
1454 dladm_stat_chain_t *head = NULL;
1455 dladm_stat_chain_t *bcast_stats = NULL;
1456 dladm_stat_chain_t *defunctlane_stats = NULL;
1457 dladm_stat_chain_t *lane_stats;
1458 char linkname[MAXLINKNAMELEN];
1459 boolean_t is_legacy_driver;
1460
1461 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1462 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1463 goto done;
1464 }
1465
1466 /* Check if it is legacy driver */
1467 if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1468 "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1469 goto done;
1470 }
1471
1472 if (is_legacy_driver) {
1473 head = i_dlstat_legacy_tx_lane_stats(dh, linkname);
1474 goto done;
1475 }
1476
1477 bcast_stats = i_dlstat_tx_bcast_stats(dh, linkname);
1478 defunctlane_stats = i_dlstat_tx_defunctlane_stats(dh, linkname);
1479 lane_stats = i_dlstat_tx_hwlane_stats(dh, linkname);
1480 if (lane_stats == NULL)
1481 lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname);
1482
1483 head = i_dlstat_join_lists(bcast_stats, defunctlane_stats);
1484 head = i_dlstat_join_lists(head, lane_stats);
1485
1486 done:
1487 return (head);
1488 }
1489
1490 /* Rx lane total statistic specific functions */
1491 void *
dlstat_rx_lane_total_stats(dladm_handle_t dh,datalink_id_t linkid)1492 dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1493 {
1494 dladm_stat_chain_t *total_head = NULL;
1495 dladm_stat_chain_t *rx_lane_head, *curr;
1496 rx_lane_stat_entry_t *total_stats;
1497
1498 /* Get per rx lane stats */
1499 rx_lane_head = dlstat_rx_lane_stats(dh, linkid);
1500 if (rx_lane_head == NULL)
1501 goto done;
1502
1503 total_stats = calloc(1, sizeof (rx_lane_stat_entry_t));
1504 if (total_stats == NULL)
1505 goto done;
1506
1507 total_stats->rle_index = DLSTAT_INVALID_ENTRY;
1508 total_stats->rle_id = DLSTAT_INVALID_ENTRY;
1509
1510 for (curr = rx_lane_head; curr != NULL; curr = curr->dc_next) {
1511 rx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry;
1512
1513 i_dlstat_sum_stats(&total_stats->rle_stats,
1514 &curr_lane_stats->rle_stats, &total_stats->rle_stats,
1515 rx_lane_stats_list, RX_LANE_STAT_SIZE);
1516 }
1517
1518 total_head = malloc(sizeof (dladm_stat_chain_t));
1519 if (total_head == NULL) {
1520 free(total_stats);
1521 goto done;
1522 }
1523
1524 total_head->dc_statentry = total_stats;
1525 (void) strlcpy(total_head->dc_statheader, "mac_rx_lane_total",
1526 sizeof (total_head->dc_statheader));
1527 total_head->dc_next = NULL;
1528
1529 done:
1530 dladm_link_stat_free(rx_lane_head);
1531 return (total_head);
1532 }
1533
1534 /* Tx lane total statistic specific functions */
1535 void *
dlstat_tx_lane_total_stats(dladm_handle_t dh,datalink_id_t linkid)1536 dlstat_tx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1537 {
1538 dladm_stat_chain_t *total_head = NULL;
1539 dladm_stat_chain_t *tx_lane_head, *curr;
1540 tx_lane_stat_entry_t *total_stats;
1541
1542 /* Get per tx lane stats */
1543 tx_lane_head = dlstat_tx_lane_stats(dh, linkid);
1544 if (tx_lane_head == NULL)
1545 goto done;
1546
1547 total_stats = calloc(1, sizeof (tx_lane_stat_entry_t));
1548 if (total_stats == NULL)
1549 goto done;
1550
1551 total_stats->tle_index = DLSTAT_INVALID_ENTRY;
1552 total_stats->tle_id = DLSTAT_INVALID_ENTRY;
1553
1554 for (curr = tx_lane_head; curr != NULL; curr = curr->dc_next) {
1555 tx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry;
1556
1557 i_dlstat_sum_stats(&total_stats->tle_stats,
1558 &curr_lane_stats->tle_stats, &total_stats->tle_stats,
1559 tx_lane_stats_list, TX_LANE_STAT_SIZE);
1560 }
1561
1562 total_head = malloc(sizeof (dladm_stat_chain_t));
1563 if (total_head == NULL) {
1564 free(total_stats);
1565 goto done;
1566 }
1567
1568 total_head->dc_statentry = total_stats;
1569 (void) strlcpy(total_head->dc_statheader, "mac_tx_lane_total",
1570 sizeof (total_head->dc_statheader));
1571 total_head->dc_next = NULL;
1572
1573 done:
1574 dladm_link_stat_free(tx_lane_head);
1575 return (total_head);
1576 }
1577
1578 /* Fanout specific functions */
1579 static boolean_t
i_dlstat_fanout_match(void * arg1,void * arg2)1580 i_dlstat_fanout_match(void *arg1, void *arg2)
1581 {
1582 fanout_stat_entry_t *s1 = arg1;
1583 fanout_stat_entry_t *s2 = arg2;
1584
1585 return (s1->fe_index == s2->fe_index &&
1586 s1->fe_id == s2->fe_id &&
1587 s1->fe_foutindex == s2->fe_foutindex);
1588 }
1589
1590 static void *
i_dlstat_fanout_stat_entry_diff(void * arg1,void * arg2)1591 i_dlstat_fanout_stat_entry_diff(void *arg1, void *arg2)
1592 {
1593 fanout_stat_entry_t *s1 = arg1;
1594 fanout_stat_entry_t *s2 = arg2;
1595 fanout_stat_entry_t *diff_entry;
1596
1597 diff_entry = malloc(sizeof (fanout_stat_entry_t));
1598 if (diff_entry == NULL)
1599 goto done;
1600
1601 diff_entry->fe_index = s1->fe_index;
1602 diff_entry->fe_id = s1->fe_id;
1603 diff_entry->fe_foutindex = s1->fe_foutindex;
1604
1605 DLSTAT_DIFF_STAT(s1, s2, diff_entry, fe_stats, fanout_stats_list,
1606 FANOUT_STAT_SIZE);
1607
1608 done:
1609 return (diff_entry);
1610 }
1611
1612 static void *
i_dlstat_fanout_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1613 i_dlstat_fanout_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1614 {
1615 fanout_stat_entry_t *fanout_stat_entry;
1616
1617 fanout_stat_entry = calloc(1, sizeof (fanout_stat_entry_t));
1618 if (fanout_stat_entry == NULL)
1619 goto done;
1620
1621 /* Set by the caller later */
1622 fanout_stat_entry->fe_index = DLSTAT_INVALID_ENTRY;
1623 fanout_stat_entry->fe_id = DLSTAT_INVALID_ENTRY;
1624
1625 fanout_stat_entry->fe_foutindex = i;
1626
1627 i_dlstat_get_stats(kcp, ksp, &fanout_stat_entry->fe_stats,
1628 fanout_stats_list, FANOUT_STAT_SIZE);
1629
1630 done:
1631 return (fanout_stat_entry);
1632 }
1633
1634 static void *
i_dlstat_query_fanout_stats(dladm_handle_t dh,datalink_id_t linkid,uint_t idlist[],uint_t idlist_size,const char * modname,const char * prefix)1635 i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid,
1636 uint_t idlist[], uint_t idlist_size,
1637 const char *modname, const char *prefix)
1638 {
1639 uint_t i;
1640 char statprefix[MAXLINKNAMELEN];
1641 char linkname[MAXLINKNAMELEN];
1642 dladm_stat_chain_t *curr, *curr_head;
1643 dladm_stat_chain_t *head = NULL, *prev = NULL;
1644 uint_t fanout_idlist[MAX_RINGS_PER_GROUP];
1645 uint_t fanout_idlist_size;
1646
1647 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1648 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1649 return (NULL);
1650 }
1651
1652 i_dlstat_get_idlist(dh, linkname, DLSTAT_FANOUT_IDLIST,
1653 fanout_idlist, &fanout_idlist_size);
1654
1655 for (i = 0; i < idlist_size; i++) {
1656 uint_t index = idlist[i];
1657
1658 (void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout",
1659 prefix, index);
1660
1661 curr_head = i_dlstat_query_stats(dh, modname, statprefix,
1662 fanout_idlist, fanout_idlist_size,
1663 i_dlstat_fanout_retrieve_stat);
1664
1665 if (curr_head == NULL) /* Last lane */
1666 break;
1667
1668 if (head == NULL) /* First lane */
1669 head = curr_head;
1670 else /* Link new lane list to end of previous lane list */
1671 prev->dc_next = curr_head;
1672
1673 /* Walk new lane list and set ids */
1674 for (curr = curr_head; curr != NULL; curr = curr->dc_next) {
1675 fanout_stat_entry_t *curr_stats = curr->dc_statentry;
1676
1677 curr_stats->fe_index = index;
1678 curr_stats->fe_id = L_HWLANE;
1679 /*
1680 * Save last pointer of previous linked list.
1681 * This pointer is used to chain linked lists
1682 * generated in each iteration.
1683 */
1684 prev = curr;
1685 }
1686 }
1687
1688 return (head);
1689 }
1690
1691 void *
dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh,datalink_id_t linkid,const char * linkname)1692 dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid,
1693 const char *linkname)
1694 {
1695 return (i_dlstat_query_fanout_stats(dh, linkid,
1696 default_idlist, default_idlist_size, linkname,
1697 DLSTAT_MAC_RX_SWLANE));
1698 }
1699
1700 void *
dlstat_fanout_hwlane_stats(dladm_handle_t dh,datalink_id_t linkid,const char * linkname)1701 dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1702 const char *linkname)
1703 {
1704 uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1705 uint_t rx_hwlane_idlist_size;
1706
1707 i_dlstat_get_idlist(dh, linkname, DLSTAT_RX_HWLANE_IDLIST,
1708 rx_hwlane_idlist, &rx_hwlane_idlist_size);
1709
1710 return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist,
1711 rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE));
1712 }
1713
1714 void *
dlstat_fanout_stats(dladm_handle_t dh,datalink_id_t linkid)1715 dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid)
1716 {
1717 dladm_stat_chain_t *head = NULL;
1718 dladm_stat_chain_t *fout_hwlane_stats;
1719 dladm_stat_chain_t *fout_swlane_and_local_stats;
1720 fanout_stat_entry_t *fout_stats;
1721 char linkname[MAXLINKNAMELEN];
1722
1723 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1724 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1725 goto done;
1726 }
1727
1728 fout_swlane_and_local_stats =
1729 dlstat_fanout_swlane_and_local_stats(dh, linkid, linkname);
1730 fout_hwlane_stats = dlstat_fanout_hwlane_stats(dh, linkid, linkname);
1731
1732 if (fout_swlane_and_local_stats == NULL) {
1733 head = fout_hwlane_stats;
1734 goto done;
1735 }
1736
1737 fout_stats = fout_swlane_and_local_stats->dc_statentry;
1738
1739 if (fout_hwlane_stats != NULL) { /* hwlane(s), only local traffic */
1740 fout_stats->fe_id = L_LOCAL;
1741 fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
1742 } else { /* no hwlane, mix of local+sw classified */
1743 fout_stats->fe_id = L_LCLSWLANE;
1744 fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
1745 }
1746
1747 fout_swlane_and_local_stats->dc_next = fout_hwlane_stats;
1748 head = fout_swlane_and_local_stats;
1749
1750 done:
1751 return (head);
1752 }
1753
1754 /* Rx ring statistic specific functions */
1755 static boolean_t
i_dlstat_rx_ring_match(void * arg1,void * arg2)1756 i_dlstat_rx_ring_match(void *arg1, void *arg2)
1757 {
1758 rx_lane_stat_entry_t *s1 = arg1;
1759 rx_lane_stat_entry_t *s2 = arg2;
1760
1761 return (s1->rle_index == s2->rle_index);
1762 }
1763
1764 static void *
i_dlstat_rx_ring_stat_entry_diff(void * arg1,void * arg2)1765 i_dlstat_rx_ring_stat_entry_diff(void *arg1, void *arg2)
1766 {
1767 ring_stat_entry_t *s1 = arg1;
1768 ring_stat_entry_t *s2 = arg2;
1769 ring_stat_entry_t *diff_entry;
1770
1771 diff_entry = malloc(sizeof (ring_stat_entry_t));
1772 if (diff_entry == NULL)
1773 goto done;
1774
1775 diff_entry->re_index = s1->re_index;
1776
1777 DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, rx_ring_stats_list,
1778 RX_RING_STAT_SIZE);
1779
1780 done:
1781 return (diff_entry);
1782 }
1783
1784 static void *
i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1785 i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1786 {
1787 ring_stat_entry_t *rx_ring_stat_entry;
1788
1789 rx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
1790 if (rx_ring_stat_entry == NULL)
1791 goto done;
1792
1793 rx_ring_stat_entry->re_index = i;
1794
1795 i_dlstat_get_stats(kcp, ksp, &rx_ring_stat_entry->re_stats,
1796 rx_ring_stats_list, RX_RING_STAT_SIZE);
1797
1798 done:
1799 return (rx_ring_stat_entry);
1800 }
1801
1802 void *
dlstat_rx_ring_stats(dladm_handle_t dh,datalink_id_t linkid)1803 dlstat_rx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
1804 {
1805 uint_t rx_ring_idlist[MAX_RINGS_PER_GROUP];
1806 uint_t rx_ring_idlist_size;
1807 dladm_phys_attr_t dpa;
1808 char linkname[MAXLINKNAMELEN];
1809 char *modname;
1810 datalink_class_t class;
1811
1812 /*
1813 * kstats corresponding to physical device rings continue to use
1814 * device names even if the link is renamed using dladm rename-link.
1815 * Thus, given a linkid, we lookup the physical device name.
1816 * However, if an aggr is renamed, kstats corresponding to its
1817 * pseudo rings are renamed as well.
1818 */
1819 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
1820 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1821 return (NULL);
1822 }
1823
1824 if (class != DATALINK_CLASS_AGGR) {
1825 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
1826 DLADM_STATUS_OK) {
1827 return (NULL);
1828 }
1829 modname = dpa.dp_dev;
1830 } else
1831 modname = linkname;
1832
1833 i_dlstat_get_idlist(dh, modname, DLSTAT_RX_RING_IDLIST,
1834 rx_ring_idlist, &rx_ring_idlist_size);
1835
1836 return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_RX_RING,
1837 rx_ring_idlist, rx_ring_idlist_size,
1838 i_dlstat_rx_ring_retrieve_stat));
1839 }
1840
1841 /* Tx ring statistic specific functions */
1842 static boolean_t
i_dlstat_tx_ring_match(void * arg1,void * arg2)1843 i_dlstat_tx_ring_match(void *arg1, void *arg2)
1844 {
1845 tx_lane_stat_entry_t *s1 = arg1;
1846 tx_lane_stat_entry_t *s2 = arg2;
1847
1848 return (s1->tle_index == s2->tle_index);
1849 }
1850
1851 static void *
i_dlstat_tx_ring_stat_entry_diff(void * arg1,void * arg2)1852 i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2)
1853 {
1854 ring_stat_entry_t *s1 = arg1;
1855 ring_stat_entry_t *s2 = arg2;
1856 ring_stat_entry_t *diff_entry;
1857
1858 diff_entry = malloc(sizeof (ring_stat_entry_t));
1859 if (diff_entry == NULL)
1860 goto done;
1861
1862 diff_entry->re_index = s1->re_index;
1863
1864 DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, tx_ring_stats_list,
1865 TX_RING_STAT_SIZE);
1866
1867 done:
1868 return (diff_entry);
1869 }
1870
1871 static void *
i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1872 i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1873 {
1874 ring_stat_entry_t *tx_ring_stat_entry;
1875
1876 tx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
1877 if (tx_ring_stat_entry == NULL)
1878 goto done;
1879
1880 tx_ring_stat_entry->re_index = i;
1881
1882 i_dlstat_get_stats(kcp, ksp, &tx_ring_stat_entry->re_stats,
1883 tx_ring_stats_list, TX_RING_STAT_SIZE);
1884
1885 done:
1886 return (tx_ring_stat_entry);
1887 }
1888
1889 void *
dlstat_tx_ring_stats(dladm_handle_t dh,datalink_id_t linkid)1890 dlstat_tx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
1891 {
1892 uint_t tx_ring_idlist[MAX_RINGS_PER_GROUP];
1893 uint_t tx_ring_idlist_size;
1894 dladm_phys_attr_t dpa;
1895 char linkname[MAXLINKNAMELEN];
1896 char *modname;
1897 datalink_class_t class;
1898
1899 /*
1900 * kstats corresponding to physical device rings continue to use
1901 * device names even if the link is renamed using dladm rename-link.
1902 * Thus, given a linkid, we lookup the physical device name.
1903 * However, if an aggr is renamed, kstats corresponding to its
1904 * pseudo rings are renamed as well.
1905 */
1906 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
1907 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1908 return (NULL);
1909 }
1910
1911 if (class != DATALINK_CLASS_AGGR) {
1912 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
1913 DLADM_STATUS_OK) {
1914 return (NULL);
1915 }
1916 modname = dpa.dp_dev;
1917 } else
1918 modname = linkname;
1919
1920 i_dlstat_get_idlist(dh, modname, DLSTAT_TX_RING_IDLIST,
1921 tx_ring_idlist, &tx_ring_idlist_size);
1922
1923 return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_TX_RING,
1924 tx_ring_idlist, tx_ring_idlist_size,
1925 i_dlstat_tx_ring_retrieve_stat));
1926 }
1927
1928 /* Rx ring total statistic specific functions */
1929 void *
dlstat_rx_ring_total_stats(dladm_handle_t dh,datalink_id_t linkid)1930 dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1931 {
1932 dladm_stat_chain_t *total_head = NULL;
1933 dladm_stat_chain_t *rx_ring_head, *curr;
1934 ring_stat_entry_t *total_stats;
1935
1936 /* Get per rx ring stats */
1937 rx_ring_head = dlstat_rx_ring_stats(dh, linkid);
1938 if (rx_ring_head == NULL)
1939 goto done;
1940
1941 total_stats = calloc(1, sizeof (ring_stat_entry_t));
1942 if (total_stats == NULL)
1943 goto done;
1944
1945 total_stats->re_index = DLSTAT_INVALID_ENTRY;
1946
1947 for (curr = rx_ring_head; curr != NULL; curr = curr->dc_next) {
1948 ring_stat_entry_t *curr_ring_stats = curr->dc_statentry;
1949
1950 i_dlstat_sum_stats(&total_stats->re_stats,
1951 &curr_ring_stats->re_stats, &total_stats->re_stats,
1952 rx_ring_stats_list, RX_RING_STAT_SIZE);
1953 }
1954
1955 total_head = malloc(sizeof (dladm_stat_chain_t));
1956 if (total_head == NULL) {
1957 free(total_stats);
1958 goto done;
1959 }
1960
1961 total_head->dc_statentry = total_stats;
1962 (void) strlcpy(total_head->dc_statheader, "mac_rx_ring_total",
1963 sizeof (total_head->dc_statheader));
1964 total_head->dc_next = NULL;
1965
1966 done:
1967 dladm_link_stat_free(rx_ring_head);
1968 return (total_head);
1969 }
1970
1971 /* Tx ring total statistic specific functions */
1972 void *
dlstat_tx_ring_total_stats(dladm_handle_t dh,datalink_id_t linkid)1973 dlstat_tx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1974 {
1975 dladm_stat_chain_t *total_head = NULL;
1976 dladm_stat_chain_t *tx_ring_head, *curr;
1977 ring_stat_entry_t *total_stats;
1978
1979 /* Get per tx ring stats */
1980 tx_ring_head = dlstat_tx_ring_stats(dh, linkid);
1981 if (tx_ring_head == NULL)
1982 goto done;
1983
1984 total_stats = calloc(1, sizeof (ring_stat_entry_t));
1985 if (total_stats == NULL)
1986 goto done;
1987
1988 total_stats->re_index = DLSTAT_INVALID_ENTRY;
1989
1990 for (curr = tx_ring_head; curr != NULL; curr = curr->dc_next) {
1991 ring_stat_entry_t *curr_ring_stats = curr->dc_statentry;
1992
1993 i_dlstat_sum_stats(&total_stats->re_stats,
1994 &curr_ring_stats->re_stats, &total_stats->re_stats,
1995 tx_ring_stats_list, TX_RING_STAT_SIZE);
1996 }
1997
1998 total_head = malloc(sizeof (dladm_stat_chain_t));
1999 if (total_head == NULL) {
2000 free(total_stats);
2001 goto done;
2002 }
2003
2004 total_head->dc_statentry = total_stats;
2005 (void) strlcpy(total_head->dc_statheader, "mac_tx_ring_total",
2006 sizeof (total_head->dc_statheader));
2007 total_head->dc_next = NULL;
2008
2009 done:
2010 dladm_link_stat_free(tx_ring_head);
2011 return (total_head);
2012 }
2013
2014 /* Summary statistic specific functions */
2015 static boolean_t
i_dlstat_total_match(void * arg1 __unused,void * arg2 __unused)2016 i_dlstat_total_match(void *arg1 __unused, void *arg2 __unused)
2017 {
2018 /* Always single entry for total */
2019 return (B_TRUE);
2020 }
2021
2022 static void *
i_dlstat_total_stat_entry_diff(void * arg1,void * arg2)2023 i_dlstat_total_stat_entry_diff(void *arg1, void *arg2)
2024 {
2025 total_stat_entry_t *s1 = arg1;
2026 total_stat_entry_t *s2 = arg2;
2027 total_stat_entry_t *diff_entry;
2028
2029 diff_entry = malloc(sizeof (total_stat_entry_t));
2030 if (diff_entry == NULL)
2031 goto done;
2032
2033 DLSTAT_DIFF_STAT(s1, s2, diff_entry, tse_stats, total_stats_list,
2034 TOTAL_STAT_SIZE);
2035
2036 done:
2037 return (diff_entry);
2038 }
2039
2040 void *
dlstat_total_stats(dladm_handle_t dh,datalink_id_t linkid)2041 dlstat_total_stats(dladm_handle_t dh, datalink_id_t linkid)
2042 {
2043 dladm_stat_chain_t *head = NULL;
2044 dladm_stat_chain_t *rx_total = NULL;
2045 dladm_stat_chain_t *tx_total = NULL;
2046 total_stat_entry_t *total_stat_entry;
2047 rx_lane_stat_entry_t *rx_lane_stat_entry;
2048 tx_lane_stat_entry_t *tx_lane_stat_entry;
2049
2050 /* Get total rx lane stats */
2051 rx_total = dlstat_rx_lane_total_stats(dh, linkid);
2052 if (rx_total == NULL)
2053 goto done;
2054
2055 /* Get total tx lane stats */
2056 tx_total = dlstat_tx_lane_total_stats(dh, linkid);
2057 if (tx_total == NULL)
2058 goto done;
2059
2060 /* Build total stat */
2061 total_stat_entry = calloc(1, sizeof (total_stat_entry_t));
2062 if (total_stat_entry == NULL)
2063 goto done;
2064
2065 rx_lane_stat_entry = rx_total->dc_statentry;
2066 tx_lane_stat_entry = tx_total->dc_statentry;
2067
2068 /* Extract total rx ipackets, rbytes */
2069 total_stat_entry->tse_stats.ts_ipackets =
2070 rx_lane_stat_entry->rle_stats.rl_ipackets;
2071 total_stat_entry->tse_stats.ts_rbytes =
2072 rx_lane_stat_entry->rle_stats.rl_rbytes;
2073
2074 /* Extract total tx opackets, obytes */
2075 total_stat_entry->tse_stats.ts_opackets =
2076 tx_lane_stat_entry->tle_stats.tl_opackets;
2077 total_stat_entry->tse_stats.ts_obytes =
2078 tx_lane_stat_entry->tle_stats.tl_obytes;
2079
2080 head = malloc(sizeof (dladm_stat_chain_t));
2081 if (head == NULL) {
2082 free(total_stat_entry);
2083 goto done;
2084 }
2085
2086 head->dc_statentry = total_stat_entry;
2087 (void) strlcpy(head->dc_statheader, "mac_lane_total",
2088 sizeof (head->dc_statheader));
2089 head->dc_next = NULL;
2090
2091 done:
2092 dladm_link_stat_free(rx_total);
2093 dladm_link_stat_free(tx_total);
2094 return (head);
2095 }
2096
2097 /* Aggr total statistic(summed across all component ports) specific functions */
2098 void *
dlstat_aggr_total_stats(dladm_stat_chain_t * head)2099 dlstat_aggr_total_stats(dladm_stat_chain_t *head)
2100 {
2101 dladm_stat_chain_t *curr;
2102 dladm_stat_chain_t *total_head = NULL;
2103 aggr_port_stat_entry_t *total_stats;
2104
2105 total_stats = calloc(1, sizeof (aggr_port_stat_entry_t));
2106 if (total_stats == NULL)
2107 goto done;
2108
2109 total_stats->ape_portlinkid = DATALINK_INVALID_LINKID;
2110
2111 for (curr = head; curr != NULL; curr = curr->dc_next) {
2112 aggr_port_stat_entry_t *curr_aggr_port_stats;
2113
2114 curr_aggr_port_stats = curr->dc_statentry;
2115
2116 i_dlstat_sum_stats(&total_stats->ape_stats,
2117 &curr_aggr_port_stats->ape_stats, &total_stats->ape_stats,
2118 aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
2119 }
2120
2121 total_head = malloc(sizeof (dladm_stat_chain_t));
2122 if (total_head == NULL) {
2123 free(total_stats);
2124 goto done;
2125 }
2126
2127 total_head->dc_statentry = total_stats;
2128 total_head->dc_next = NULL;
2129
2130 done:
2131 return (total_head);
2132 }
2133
2134 /* Aggr port statistic specific functions */
2135 static boolean_t
i_dlstat_aggr_port_match(void * arg1,void * arg2)2136 i_dlstat_aggr_port_match(void *arg1, void *arg2)
2137 {
2138 aggr_port_stat_entry_t *s1 = arg1;
2139 aggr_port_stat_entry_t *s2 = arg2;
2140
2141 return (s1->ape_portlinkid == s2->ape_portlinkid);
2142 }
2143
2144 static void *
i_dlstat_aggr_port_stat_entry_diff(void * arg1,void * arg2)2145 i_dlstat_aggr_port_stat_entry_diff(void *arg1, void *arg2)
2146 {
2147 aggr_port_stat_entry_t *s1 = arg1;
2148 aggr_port_stat_entry_t *s2 = arg2;
2149 aggr_port_stat_entry_t *diff_entry;
2150
2151 diff_entry = malloc(sizeof (aggr_port_stat_entry_t));
2152 if (diff_entry == NULL)
2153 goto done;
2154
2155 diff_entry->ape_portlinkid = s1->ape_portlinkid;
2156
2157 DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list,
2158 AGGR_PORT_STAT_SIZE);
2159
2160 done:
2161 return (diff_entry);
2162 }
2163
2164 /*
2165 * Query dls stats for the aggr port. This results in query for stats into
2166 * the corresponding device driver.
2167 */
2168 static aggr_port_stat_entry_t *
i_dlstat_single_port_stats(dladm_handle_t handle,const char * portname,datalink_id_t linkid)2169 i_dlstat_single_port_stats(dladm_handle_t handle, const char *portname,
2170 datalink_id_t linkid)
2171 {
2172 kstat_t *ksp;
2173 char module[DLPI_LINKNAME_MAX];
2174 uint_t instance;
2175 aggr_port_stat_entry_t *aggr_port_stat_entry = NULL;
2176
2177 if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK)
2178 goto done;
2179
2180 if (dladm_dld_kcp(handle) == NULL) {
2181 warn("kstat open operation failed");
2182 return (NULL);
2183 }
2184
2185 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), module, instance,
2186 "mac", NULL);
2187 if (ksp == NULL)
2188 goto done;
2189
2190 aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t));
2191 if (aggr_port_stat_entry == NULL)
2192 goto done;
2193
2194 /* Save port's linkid */
2195 aggr_port_stat_entry->ape_portlinkid = linkid;
2196
2197 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp,
2198 &aggr_port_stat_entry->ape_stats,
2199 aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
2200 done:
2201 return (aggr_port_stat_entry);
2202 }
2203
2204 void *
dlstat_aggr_port_stats(dladm_handle_t dh,datalink_id_t linkid)2205 dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid)
2206 {
2207 dladm_aggr_grp_attr_t ginfo;
2208 uint_t i;
2209 dladm_aggr_port_attr_t *portp;
2210 dladm_phys_attr_t dpa;
2211 aggr_port_stat_entry_t *aggr_port_stat_entry;
2212 dladm_stat_chain_t *head = NULL, *prev = NULL, *curr;
2213 dladm_stat_chain_t *total_stats;
2214
2215 /* Get aggr info */
2216 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
2217 if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE)
2218 != DLADM_STATUS_OK)
2219 goto done;
2220 /* For every port that is member of this aggr do */
2221 for (i = 0; i < ginfo.lg_nports; i++) {
2222 portp = &(ginfo.lg_ports[i]);
2223 if (dladm_phys_info(dh, portp->lp_linkid, &dpa,
2224 DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
2225 goto done;
2226 }
2227
2228 aggr_port_stat_entry = i_dlstat_single_port_stats(dh,
2229 dpa.dp_dev, portp->lp_linkid);
2230
2231 /* Create dladm_stat_chain_t object for this stat */
2232 curr = malloc(sizeof (dladm_stat_chain_t));
2233 if (curr == NULL) {
2234 free(aggr_port_stat_entry);
2235 goto done;
2236 }
2237 (void) strlcpy(curr->dc_statheader, dpa.dp_dev,
2238 sizeof (curr->dc_statheader));
2239 curr->dc_statentry = aggr_port_stat_entry;
2240 curr->dc_next = NULL;
2241
2242 /* Chain this aggr port stat entry */
2243 /* head of the stat list */
2244 if (prev == NULL)
2245 head = curr;
2246 else
2247 prev->dc_next = curr;
2248 prev = curr;
2249 }
2250
2251 /*
2252 * Prepend the stat list with cumulative aggr stats i.e. summed over all
2253 * component ports
2254 */
2255 total_stats = dlstat_aggr_total_stats(head);
2256 if (total_stats != NULL) {
2257 total_stats->dc_next = head;
2258 head = total_stats;
2259 }
2260
2261 done:
2262 free(ginfo.lg_ports);
2263 return (head);
2264 }
2265
2266 /* Misc stat specific functions */
2267 void *
dlstat_misc_stats(dladm_handle_t dh,datalink_id_t linkid)2268 dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid)
2269 {
2270 misc_stat_entry_t *misc_stat_entry;
2271 dladm_stat_chain_t *head = NULL;
2272 char linkname[MAXLINKNAMELEN];
2273
2274 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
2275 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2276 goto done;
2277 }
2278
2279 misc_stat_entry = i_dlstat_misc_stats(dh, linkname);
2280 if (misc_stat_entry == NULL)
2281 goto done;
2282
2283 head = malloc(sizeof (dladm_stat_chain_t));
2284 if (head == NULL) {
2285 free(misc_stat_entry);
2286 goto done;
2287 }
2288
2289 head->dc_statentry = misc_stat_entry;
2290 (void) strlcpy(head->dc_statheader, "mac_misc_stat",
2291 sizeof (head->dc_statheader));
2292 head->dc_next = NULL;
2293
2294 done:
2295 return (head);
2296 }
2297
2298 /* Exported functions */
2299 dladm_stat_chain_t *
dladm_link_stat_query(dladm_handle_t dh,datalink_id_t linkid,dladm_stat_type_t stattype)2300 dladm_link_stat_query(dladm_handle_t dh, datalink_id_t linkid,
2301 dladm_stat_type_t stattype)
2302 {
2303 return (dladm_stat_table[stattype].ds_querystat(dh, linkid));
2304 }
2305
2306 dladm_stat_chain_t *
dladm_link_stat_diffchain(dladm_stat_chain_t * op1,dladm_stat_chain_t * op2,dladm_stat_type_t stattype)2307 dladm_link_stat_diffchain(dladm_stat_chain_t *op1, dladm_stat_chain_t *op2,
2308 dladm_stat_type_t stattype)
2309 {
2310 dladm_stat_chain_t *op1_curr, *op2_curr;
2311 dladm_stat_chain_t *diff_curr;
2312 dladm_stat_chain_t *diff_prev = NULL, *diff_head = NULL;
2313
2314 /* Perform op1 - op2, store result in diff */
2315 for (op1_curr = op1; op1_curr != NULL; op1_curr = op1_curr->dc_next) {
2316 for (op2_curr = op2; op2_curr != NULL;
2317 op2_curr = op2_curr->dc_next) {
2318 if (dlstat_match_stats(op1_curr->dc_statentry,
2319 op2_curr->dc_statentry, stattype)) {
2320 break;
2321 }
2322 }
2323 diff_curr = malloc(sizeof (dladm_stat_chain_t));
2324 if (diff_curr == NULL)
2325 goto done;
2326
2327 diff_curr->dc_next = NULL;
2328
2329 if (op2_curr == NULL) {
2330 /* prev iteration did not have this stat entry */
2331 diff_curr->dc_statentry =
2332 dlstat_diff_stats(op1_curr->dc_statentry,
2333 NULL, stattype);
2334 } else {
2335 diff_curr->dc_statentry =
2336 dlstat_diff_stats(op1_curr->dc_statentry,
2337 op2_curr->dc_statentry, stattype);
2338 }
2339
2340 if (diff_curr->dc_statentry == NULL) {
2341 free(diff_curr);
2342 goto done;
2343 }
2344
2345 if (diff_prev == NULL) /* head of the diff stat list */
2346 diff_head = diff_curr;
2347 else
2348 diff_prev->dc_next = diff_curr;
2349 diff_prev = diff_curr;
2350 }
2351 done:
2352 return (diff_head);
2353 }
2354
2355 void
dladm_link_stat_free(dladm_stat_chain_t * curr)2356 dladm_link_stat_free(dladm_stat_chain_t *curr)
2357 {
2358 while (curr != NULL) {
2359 dladm_stat_chain_t *tofree = curr;
2360
2361 curr = curr->dc_next;
2362 free(tofree->dc_statentry);
2363 free(tofree);
2364 }
2365 }
2366
2367 /* Query all link stats */
2368 static name_value_stat_t *
i_dlstat_convert_stats(void * stats,stat_info_t stats_list[],uint_t size)2369 i_dlstat_convert_stats(void *stats, stat_info_t stats_list[], uint_t size)
2370 {
2371 uint_t i;
2372 name_value_stat_t *head_stat = NULL, *prev_stat = NULL;
2373 name_value_stat_t *curr_stat;
2374
2375 for (i = 0; i < size; i++) {
2376 uint64_t *val = (void *)
2377 ((uchar_t *)stats + stats_list[i].si_offset);
2378
2379 curr_stat = calloc(1, sizeof (name_value_stat_t));
2380 if (curr_stat == NULL)
2381 break;
2382
2383 (void) strlcpy(curr_stat->nv_statname, stats_list[i].si_name,
2384 sizeof (curr_stat->nv_statname));
2385 curr_stat->nv_statval = *val;
2386 curr_stat->nv_nextstat = NULL;
2387
2388 if (head_stat == NULL) /* First node */
2389 head_stat = curr_stat;
2390 else
2391 prev_stat->nv_nextstat = curr_stat;
2392
2393 prev_stat = curr_stat;
2394 }
2395 return (head_stat);
2396 }
2397
2398 void *
build_nvs_entry(char * statheader,void * statentry,dladm_stat_type_t stattype)2399 build_nvs_entry(char *statheader, void *statentry, dladm_stat_type_t stattype)
2400 {
2401 name_value_stat_entry_t *name_value_stat_entry;
2402 dladm_stat_desc_t *stattbl_ptr;
2403 void *statfields;
2404
2405 stattbl_ptr = &dladm_stat_table[stattype];
2406
2407 /* Allocate memory for query all stat entry */
2408 name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
2409 if (name_value_stat_entry == NULL)
2410 goto done;
2411
2412 /* Header for these stat fields */
2413 (void) strlcpy(name_value_stat_entry->nve_header, statheader,
2414 sizeof (name_value_stat_entry->nve_header));
2415
2416 /* Extract stat fields from the statentry */
2417 statfields = (uchar_t *)statentry +
2418 dladm_stat_table[stattype].ds_offset;
2419
2420 /* Convert curr_stat to <statname, statval> pair */
2421 name_value_stat_entry->nve_stats =
2422 i_dlstat_convert_stats(statfields,
2423 stattbl_ptr->ds_statlist, stattbl_ptr->ds_statsize);
2424 done:
2425 return (name_value_stat_entry);
2426 }
2427
2428 void *
i_walk_dlstat_chain(dladm_stat_chain_t * stat_head,dladm_stat_type_t stattype)2429 i_walk_dlstat_chain(dladm_stat_chain_t *stat_head, dladm_stat_type_t stattype)
2430 {
2431 dladm_stat_chain_t *curr;
2432 dladm_stat_chain_t *nvstat_head = NULL, *nvstat_prev = NULL;
2433 dladm_stat_chain_t *nvstat_curr;
2434
2435 /*
2436 * For every stat in the chain, build header and convert all
2437 * its stat fields
2438 */
2439 for (curr = stat_head; curr != NULL; curr = curr->dc_next) {
2440 nvstat_curr = malloc(sizeof (dladm_stat_chain_t));
2441 if (nvstat_curr == NULL)
2442 break;
2443
2444 nvstat_curr->dc_statentry = build_nvs_entry(curr->dc_statheader,
2445 curr->dc_statentry, stattype);
2446
2447 if (nvstat_curr->dc_statentry == NULL) {
2448 free(nvstat_curr);
2449 break;
2450 }
2451
2452 nvstat_curr->dc_next = NULL;
2453
2454 if (nvstat_head == NULL) /* First node */
2455 nvstat_head = nvstat_curr;
2456 else
2457 nvstat_prev->dc_next = nvstat_curr;
2458
2459 nvstat_prev = nvstat_curr;
2460 }
2461 return (nvstat_head);
2462 }
2463
2464 dladm_stat_chain_t *
dladm_link_stat_query_all(dladm_handle_t dh,datalink_id_t linkid,dladm_stat_type_t stattype)2465 dladm_link_stat_query_all(dladm_handle_t dh, datalink_id_t linkid,
2466 dladm_stat_type_t stattype)
2467 {
2468 dladm_stat_chain_t *stat_head;
2469 dladm_stat_chain_t *nvstat_head = NULL;
2470
2471 /* Query the requested stat */
2472 stat_head = dladm_link_stat_query(dh, linkid, stattype);
2473 if (stat_head == NULL)
2474 goto done;
2475
2476 /*
2477 * Convert every statfield in every stat-entry of stat chain to
2478 * <statname, statval> pair
2479 */
2480 nvstat_head = i_walk_dlstat_chain(stat_head, stattype);
2481
2482 /* Free stat_head */
2483 dladm_link_stat_free(stat_head);
2484
2485 done:
2486 return (nvstat_head);
2487 }
2488
2489 void
dladm_link_stat_query_all_free(dladm_stat_chain_t * curr)2490 dladm_link_stat_query_all_free(dladm_stat_chain_t *curr)
2491 {
2492 while (curr != NULL) {
2493 dladm_stat_chain_t *tofree = curr;
2494 name_value_stat_entry_t *nv_entry = curr->dc_statentry;
2495 name_value_stat_t *nv_curr = nv_entry->nve_stats;
2496
2497 while (nv_curr != NULL) {
2498 name_value_stat_t *nv_tofree = nv_curr;
2499
2500 nv_curr = nv_curr->nv_nextstat;
2501 free(nv_tofree);
2502 }
2503
2504 curr = curr->dc_next;
2505 free(nv_entry);
2506 free(tofree);
2507 }
2508 }
2509
2510 /* flow stats specific routines */
2511 flow_stat_t *
dladm_flow_stat_query(dladm_handle_t handle,const char * flowname)2512 dladm_flow_stat_query(dladm_handle_t handle, const char *flowname)
2513 {
2514 kstat_t *ksp;
2515 flow_stat_t *flow_stat = NULL;
2516
2517 if (dladm_dld_kcp(handle) == NULL)
2518 return (NULL);
2519
2520 flow_stat = calloc(1, sizeof (flow_stat_t));
2521 if (flow_stat == NULL)
2522 goto done;
2523
2524 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), NULL, -1, flowname,
2525 "flow");
2526
2527 if (ksp != NULL) {
2528 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp, flow_stat,
2529 flow_stats_list, FLOW_STAT_SIZE);
2530 }
2531
2532 done:
2533 return (flow_stat);
2534 }
2535
2536 flow_stat_t *
dladm_flow_stat_diff(flow_stat_t * op1,flow_stat_t * op2)2537 dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2)
2538 {
2539 flow_stat_t *diff_stat;
2540
2541 diff_stat = calloc(1, sizeof (flow_stat_t));
2542 if (diff_stat == NULL)
2543 goto done;
2544
2545 if (op2 == NULL) {
2546 bcopy(op1, diff_stat, sizeof (flow_stat_t));
2547 } else {
2548 i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list,
2549 FLOW_STAT_SIZE);
2550 }
2551 done:
2552 return (diff_stat);
2553 }
2554
2555 void
dladm_flow_stat_free(flow_stat_t * curr)2556 dladm_flow_stat_free(flow_stat_t *curr)
2557 {
2558 free(curr);
2559 }
2560
2561 /* Query all flow stats */
2562 name_value_stat_entry_t *
dladm_flow_stat_query_all(dladm_handle_t handle,const char * flowname)2563 dladm_flow_stat_query_all(dladm_handle_t handle, const char *flowname)
2564 {
2565 flow_stat_t *flow_stat;
2566 name_value_stat_entry_t *name_value_stat_entry = NULL;
2567
2568 /* Query flow stats */
2569 flow_stat = dladm_flow_stat_query(handle, flowname);
2570 if (flow_stat == NULL)
2571 goto done;
2572
2573 /* Allocate memory for query all stat entry */
2574 name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
2575 if (name_value_stat_entry == NULL) {
2576 dladm_flow_stat_free(flow_stat);
2577 goto done;
2578 }
2579
2580 /* Header for these stat fields */
2581 (void) strncpy(name_value_stat_entry->nve_header, flowname,
2582 MAXFLOWNAMELEN);
2583
2584 /* Convert every statfield in flow_stat to <statname, statval> pair */
2585 name_value_stat_entry->nve_stats =
2586 i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE);
2587
2588 /* Free flow_stat */
2589 dladm_flow_stat_free(flow_stat);
2590
2591 done:
2592 return (name_value_stat_entry);
2593 }
2594
2595 void
dladm_flow_stat_query_all_free(name_value_stat_entry_t * curr)2596 dladm_flow_stat_query_all_free(name_value_stat_entry_t *curr)
2597 {
2598 name_value_stat_t *nv_curr = curr->nve_stats;
2599
2600 while (nv_curr != NULL) {
2601 name_value_stat_t *nv_tofree = nv_curr;
2602
2603 nv_curr = nv_curr->nv_nextstat;
2604 free(nv_tofree);
2605 }
2606 }
2607