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 free(misc_stat_entry);
1162 done:
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 return (head);
1212 }
1213
1214 static dladm_stat_chain_t *
i_dlstat_rx_hwlane_stats(dladm_handle_t handle,const char * linkname)1215 i_dlstat_rx_hwlane_stats(dladm_handle_t handle, const char *linkname)
1216 {
1217 uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1218 uint_t rx_hwlane_idlist_size;
1219
1220 i_dlstat_get_idlist(handle, linkname, DLSTAT_RX_HWLANE_IDLIST,
1221 rx_hwlane_idlist, &rx_hwlane_idlist_size);
1222
1223 return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_RX_HWLANE,
1224 rx_hwlane_idlist, rx_hwlane_idlist_size,
1225 i_dlstat_rx_hwlane_retrieve_stat));
1226 }
1227
1228 static dladm_stat_chain_t *
i_dlstat_rx_swlane_stats(dladm_handle_t dh,datalink_id_t linkid __unused,const char * linkname)1229 i_dlstat_rx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid __unused,
1230 const char *linkname)
1231 {
1232 return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_RX_SWLANE,
1233 default_idlist, default_idlist_size,
1234 i_dlstat_rx_swlane_retrieve_stat));
1235 }
1236
1237 void *
dlstat_rx_lane_stats(dladm_handle_t dh,datalink_id_t linkid)1238 dlstat_rx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1239 {
1240 dladm_stat_chain_t *head = NULL;
1241 dladm_stat_chain_t *local_stats = NULL;
1242 dladm_stat_chain_t *bcast_stats = NULL;
1243 dladm_stat_chain_t *defunctlane_stats = NULL;
1244 dladm_stat_chain_t *lane_stats = NULL;
1245 char linkname[MAXLINKNAMELEN];
1246 boolean_t is_legacy_driver;
1247
1248 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1249 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1250 goto done;
1251 }
1252
1253 /* Check if it is legacy driver */
1254 if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1255 "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1256 goto done;
1257 }
1258
1259 if (is_legacy_driver) {
1260 head = i_dlstat_legacy_rx_lane_stats(dh, linkname);
1261 goto done;
1262 }
1263
1264 local_stats = i_dlstat_rx_local_stats(dh, linkname);
1265 bcast_stats = i_dlstat_rx_bcast_stats(dh, linkname);
1266 defunctlane_stats = i_dlstat_rx_defunctlane_stats(dh, linkname);
1267 lane_stats = i_dlstat_rx_hwlane_stats(dh, linkname);
1268 if (lane_stats == NULL)
1269 lane_stats = i_dlstat_rx_swlane_stats(dh, linkid, linkname);
1270
1271 head = i_dlstat_join_lists(local_stats, bcast_stats);
1272 head = i_dlstat_join_lists(head, defunctlane_stats);
1273 head = i_dlstat_join_lists(head, lane_stats);
1274 done:
1275 return (head);
1276 }
1277
1278 /* Tx lane statistic specific functions */
1279 static boolean_t
i_dlstat_tx_lane_match(void * arg1,void * arg2)1280 i_dlstat_tx_lane_match(void *arg1, void *arg2)
1281 {
1282 tx_lane_stat_entry_t *s1 = arg1;
1283 tx_lane_stat_entry_t *s2 = arg2;
1284
1285 return (s1->tle_index == s2->tle_index &&
1286 s1->tle_id == s2->tle_id);
1287 }
1288
1289 static void *
i_dlstat_tx_lane_stat_entry_diff(void * arg1,void * arg2)1290 i_dlstat_tx_lane_stat_entry_diff(void *arg1, void *arg2)
1291 {
1292 tx_lane_stat_entry_t *s1 = arg1;
1293 tx_lane_stat_entry_t *s2 = arg2;
1294 tx_lane_stat_entry_t *diff_entry;
1295
1296 diff_entry = malloc(sizeof (tx_lane_stat_entry_t));
1297 if (diff_entry == NULL)
1298 goto done;
1299
1300 diff_entry->tle_index = s1->tle_index;
1301 diff_entry->tle_id = s1->tle_id;
1302
1303 DLSTAT_DIFF_STAT(s1, s2, diff_entry, tle_stats, tx_lane_stats_list,
1304 TX_LANE_STAT_SIZE);
1305
1306 done:
1307 return (diff_entry);
1308 }
1309
1310 static void *
i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1311 i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1312 {
1313 tx_lane_stat_entry_t *tx_lane_stat_entry;
1314
1315 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1316 if (tx_lane_stat_entry == NULL)
1317 goto done;
1318
1319 tx_lane_stat_entry->tle_index = i;
1320 tx_lane_stat_entry->tle_id = L_HWLANE;
1321
1322 i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
1323 tx_lane_stats_list, TX_LANE_STAT_SIZE);
1324
1325 done:
1326 return (tx_lane_stat_entry);
1327 }
1328
1329 static void *
i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i __unused)1330 i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i __unused)
1331 {
1332 tx_lane_stat_entry_t *tx_lane_stat_entry;
1333
1334 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1335 if (tx_lane_stat_entry == NULL)
1336 goto done;
1337
1338 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1339 tx_lane_stat_entry->tle_id = L_SWLANE;
1340
1341 i_dlstat_get_stats(kcp, ksp, &tx_lane_stat_entry->tle_stats,
1342 tx_lane_stats_list, TX_LANE_STAT_SIZE);
1343
1344 done:
1345 return (tx_lane_stat_entry);
1346 }
1347
1348 static dladm_stat_chain_t *
i_dlstat_tx_bcast_stats(dladm_handle_t handle,const char * linkname)1349 i_dlstat_tx_bcast_stats(dladm_handle_t handle, const char *linkname)
1350 {
1351 misc_stat_entry_t *misc_stat_entry;
1352 dladm_stat_chain_t *head = NULL;
1353 tx_lane_stat_entry_t *tx_lane_stat_entry;
1354
1355 misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
1356 if (misc_stat_entry == NULL)
1357 goto done;
1358
1359 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1360 if (tx_lane_stat_entry == NULL)
1361 goto done;
1362
1363 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1364 tx_lane_stat_entry->tle_id = L_BCAST;
1365
1366 tx_lane_stat_entry->tle_stats.tl_opackets =
1367 misc_stat_entry->mse_stats.ms_brdcstxmt +
1368 misc_stat_entry->mse_stats.ms_multixmt;
1369
1370 tx_lane_stat_entry->tle_stats.tl_obytes =
1371 misc_stat_entry->mse_stats.ms_brdcstxmtbytes +
1372 misc_stat_entry->mse_stats.ms_multixmtbytes;
1373
1374 head = malloc(sizeof (dladm_stat_chain_t));
1375 if (head == NULL) {
1376 free(tx_lane_stat_entry);
1377 goto done;
1378 }
1379
1380 head->dc_statentry = tx_lane_stat_entry;
1381 head->dc_next = NULL;
1382
1383 free(misc_stat_entry);
1384 done:
1385 return (head);
1386 }
1387
1388 static dladm_stat_chain_t *
i_dlstat_tx_defunctlane_stats(dladm_handle_t handle,const char * linkname)1389 i_dlstat_tx_defunctlane_stats(dladm_handle_t handle, const char *linkname)
1390 {
1391 misc_stat_entry_t *misc_stat_entry;
1392 dladm_stat_chain_t *head = NULL;
1393 tx_lane_stat_entry_t *tx_lane_stat_entry;
1394
1395 misc_stat_entry = i_dlstat_misc_stats(handle, linkname);
1396 if (misc_stat_entry == NULL)
1397 goto done;
1398
1399 tx_lane_stat_entry = calloc(1, sizeof (tx_lane_stat_entry_t));
1400 if (tx_lane_stat_entry == NULL)
1401 goto done;
1402
1403 tx_lane_stat_entry->tle_index = DLSTAT_INVALID_ENTRY;
1404 tx_lane_stat_entry->tle_id = L_DFNCT;
1405
1406 tx_lane_stat_entry->tle_stats.tl_opackets =
1407 misc_stat_entry->mse_stats.ms_opackets;
1408 tx_lane_stat_entry->tle_stats.tl_obytes =
1409 misc_stat_entry->mse_stats.ms_obytes;
1410 tx_lane_stat_entry->tle_stats.tl_sdrops =
1411 misc_stat_entry->mse_stats.ms_txsdrops;
1412
1413 head = malloc(sizeof (dladm_stat_chain_t));
1414 if (head == NULL) {
1415 free(tx_lane_stat_entry);
1416 goto done;
1417 }
1418
1419 head->dc_statentry = tx_lane_stat_entry;
1420 head->dc_next = NULL;
1421
1422 done:
1423 return (head);
1424 }
1425
1426 static dladm_stat_chain_t *
i_dlstat_tx_hwlane_stats(dladm_handle_t handle,const char * linkname)1427 i_dlstat_tx_hwlane_stats(dladm_handle_t handle, const char *linkname)
1428 {
1429 uint_t tx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1430 uint_t tx_hwlane_idlist_size;
1431
1432 i_dlstat_get_idlist(handle, linkname, DLSTAT_TX_HWLANE_IDLIST,
1433 tx_hwlane_idlist, &tx_hwlane_idlist_size);
1434
1435 return (i_dlstat_query_stats(handle, linkname, DLSTAT_MAC_TX_HWLANE,
1436 tx_hwlane_idlist, tx_hwlane_idlist_size,
1437 i_dlstat_tx_hwlane_retrieve_stat));
1438 }
1439
1440 static dladm_stat_chain_t *
i_dlstat_tx_swlane_stats(dladm_handle_t dh,datalink_id_t linkid __unused,const char * linkname)1441 i_dlstat_tx_swlane_stats(dladm_handle_t dh, datalink_id_t linkid __unused,
1442 const char *linkname)
1443 {
1444 return (i_dlstat_query_stats(dh, linkname, DLSTAT_MAC_TX_SWLANE,
1445 default_idlist, default_idlist_size,
1446 i_dlstat_tx_swlane_retrieve_stat));
1447 }
1448
1449 void *
dlstat_tx_lane_stats(dladm_handle_t dh,datalink_id_t linkid)1450 dlstat_tx_lane_stats(dladm_handle_t dh, datalink_id_t linkid)
1451 {
1452 dladm_stat_chain_t *head = NULL;
1453 dladm_stat_chain_t *bcast_stats = NULL;
1454 dladm_stat_chain_t *defunctlane_stats = NULL;
1455 dladm_stat_chain_t *lane_stats;
1456 char linkname[MAXLINKNAMELEN];
1457 boolean_t is_legacy_driver;
1458
1459 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1460 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1461 goto done;
1462 }
1463
1464 /* Check if it is legacy driver */
1465 if (dladm_linkprop_is_set(dh, linkid, DLADM_PROP_VAL_CURRENT,
1466 "_softmac", &is_legacy_driver) != DLADM_STATUS_OK) {
1467 goto done;
1468 }
1469
1470 if (is_legacy_driver) {
1471 head = i_dlstat_legacy_tx_lane_stats(dh, linkname);
1472 goto done;
1473 }
1474
1475 bcast_stats = i_dlstat_tx_bcast_stats(dh, linkname);
1476 defunctlane_stats = i_dlstat_tx_defunctlane_stats(dh, linkname);
1477 lane_stats = i_dlstat_tx_hwlane_stats(dh, linkname);
1478 if (lane_stats == NULL)
1479 lane_stats = i_dlstat_tx_swlane_stats(dh, linkid, linkname);
1480
1481 head = i_dlstat_join_lists(bcast_stats, defunctlane_stats);
1482 head = i_dlstat_join_lists(head, lane_stats);
1483
1484 done:
1485 return (head);
1486 }
1487
1488 /* Rx lane total statistic specific functions */
1489 void *
dlstat_rx_lane_total_stats(dladm_handle_t dh,datalink_id_t linkid)1490 dlstat_rx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1491 {
1492 dladm_stat_chain_t *total_head = NULL;
1493 dladm_stat_chain_t *rx_lane_head, *curr;
1494 rx_lane_stat_entry_t *total_stats;
1495
1496 /* Get per rx lane stats */
1497 rx_lane_head = dlstat_rx_lane_stats(dh, linkid);
1498 if (rx_lane_head == NULL)
1499 goto done;
1500
1501 total_stats = calloc(1, sizeof (rx_lane_stat_entry_t));
1502 if (total_stats == NULL)
1503 goto done;
1504
1505 total_stats->rle_index = DLSTAT_INVALID_ENTRY;
1506 total_stats->rle_id = DLSTAT_INVALID_ENTRY;
1507
1508 for (curr = rx_lane_head; curr != NULL; curr = curr->dc_next) {
1509 rx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry;
1510
1511 i_dlstat_sum_stats(&total_stats->rle_stats,
1512 &curr_lane_stats->rle_stats, &total_stats->rle_stats,
1513 rx_lane_stats_list, RX_LANE_STAT_SIZE);
1514 }
1515
1516 total_head = malloc(sizeof (dladm_stat_chain_t));
1517 if (total_head == NULL) {
1518 free(total_stats);
1519 goto done;
1520 }
1521
1522 total_head->dc_statentry = total_stats;
1523 (void) strlcpy(total_head->dc_statheader, "mac_rx_lane_total",
1524 sizeof (total_head->dc_statheader));
1525 total_head->dc_next = NULL;
1526 free(rx_lane_head);
1527
1528 done:
1529 return (total_head);
1530 }
1531
1532 /* Tx lane total statistic specific functions */
1533 void *
dlstat_tx_lane_total_stats(dladm_handle_t dh,datalink_id_t linkid)1534 dlstat_tx_lane_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1535 {
1536 dladm_stat_chain_t *total_head = NULL;
1537 dladm_stat_chain_t *tx_lane_head, *curr;
1538 tx_lane_stat_entry_t *total_stats;
1539
1540 /* Get per tx lane stats */
1541 tx_lane_head = dlstat_tx_lane_stats(dh, linkid);
1542 if (tx_lane_head == NULL)
1543 goto done;
1544
1545 total_stats = calloc(1, sizeof (tx_lane_stat_entry_t));
1546 if (total_stats == NULL)
1547 goto done;
1548
1549 total_stats->tle_index = DLSTAT_INVALID_ENTRY;
1550 total_stats->tle_id = DLSTAT_INVALID_ENTRY;
1551
1552 for (curr = tx_lane_head; curr != NULL; curr = curr->dc_next) {
1553 tx_lane_stat_entry_t *curr_lane_stats = curr->dc_statentry;
1554
1555 i_dlstat_sum_stats(&total_stats->tle_stats,
1556 &curr_lane_stats->tle_stats, &total_stats->tle_stats,
1557 tx_lane_stats_list, TX_LANE_STAT_SIZE);
1558 }
1559
1560 total_head = malloc(sizeof (dladm_stat_chain_t));
1561 if (total_head == NULL) {
1562 free(total_stats);
1563 goto done;
1564 }
1565
1566 total_head->dc_statentry = total_stats;
1567 (void) strlcpy(total_head->dc_statheader, "mac_tx_lane_total",
1568 sizeof (total_head->dc_statheader));
1569 total_head->dc_next = NULL;
1570 free(tx_lane_head);
1571
1572 done:
1573 return (total_head);
1574 }
1575
1576 /* Fanout specific functions */
1577 static boolean_t
i_dlstat_fanout_match(void * arg1,void * arg2)1578 i_dlstat_fanout_match(void *arg1, void *arg2)
1579 {
1580 fanout_stat_entry_t *s1 = arg1;
1581 fanout_stat_entry_t *s2 = arg2;
1582
1583 return (s1->fe_index == s2->fe_index &&
1584 s1->fe_id == s2->fe_id &&
1585 s1->fe_foutindex == s2->fe_foutindex);
1586 }
1587
1588 static void *
i_dlstat_fanout_stat_entry_diff(void * arg1,void * arg2)1589 i_dlstat_fanout_stat_entry_diff(void *arg1, void *arg2)
1590 {
1591 fanout_stat_entry_t *s1 = arg1;
1592 fanout_stat_entry_t *s2 = arg2;
1593 fanout_stat_entry_t *diff_entry;
1594
1595 diff_entry = malloc(sizeof (fanout_stat_entry_t));
1596 if (diff_entry == NULL)
1597 goto done;
1598
1599 diff_entry->fe_index = s1->fe_index;
1600 diff_entry->fe_id = s1->fe_id;
1601 diff_entry->fe_foutindex = s1->fe_foutindex;
1602
1603 DLSTAT_DIFF_STAT(s1, s2, diff_entry, fe_stats, fanout_stats_list,
1604 FANOUT_STAT_SIZE);
1605
1606 done:
1607 return (diff_entry);
1608 }
1609
1610 static void *
i_dlstat_fanout_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1611 i_dlstat_fanout_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1612 {
1613 fanout_stat_entry_t *fanout_stat_entry;
1614
1615 fanout_stat_entry = calloc(1, sizeof (fanout_stat_entry_t));
1616 if (fanout_stat_entry == NULL)
1617 goto done;
1618
1619 /* Set by the caller later */
1620 fanout_stat_entry->fe_index = DLSTAT_INVALID_ENTRY;
1621 fanout_stat_entry->fe_id = DLSTAT_INVALID_ENTRY;
1622
1623 fanout_stat_entry->fe_foutindex = i;
1624
1625 i_dlstat_get_stats(kcp, ksp, &fanout_stat_entry->fe_stats,
1626 fanout_stats_list, FANOUT_STAT_SIZE);
1627
1628 done:
1629 return (fanout_stat_entry);
1630 }
1631
1632 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)1633 i_dlstat_query_fanout_stats(dladm_handle_t dh, datalink_id_t linkid,
1634 uint_t idlist[], uint_t idlist_size,
1635 const char *modname, const char *prefix)
1636 {
1637 uint_t i;
1638 char statprefix[MAXLINKNAMELEN];
1639 char linkname[MAXLINKNAMELEN];
1640 dladm_stat_chain_t *curr, *curr_head;
1641 dladm_stat_chain_t *head = NULL, *prev = NULL;
1642 uint_t fanout_idlist[MAX_RINGS_PER_GROUP];
1643 uint_t fanout_idlist_size;
1644
1645 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1646 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1647 return (NULL);
1648 }
1649
1650 i_dlstat_get_idlist(dh, linkname, DLSTAT_FANOUT_IDLIST,
1651 fanout_idlist, &fanout_idlist_size);
1652
1653 for (i = 0; i < idlist_size; i++) {
1654 uint_t index = idlist[i];
1655
1656 (void) snprintf(statprefix, sizeof (statprefix), "%s%d_fanout",
1657 prefix, index);
1658
1659 curr_head = i_dlstat_query_stats(dh, modname, statprefix,
1660 fanout_idlist, fanout_idlist_size,
1661 i_dlstat_fanout_retrieve_stat);
1662
1663 if (curr_head == NULL) /* Last lane */
1664 break;
1665
1666 if (head == NULL) /* First lane */
1667 head = curr_head;
1668 else /* Link new lane list to end of previous lane list */
1669 prev->dc_next = curr_head;
1670
1671 /* Walk new lane list and set ids */
1672 for (curr = curr_head; curr != NULL; curr = curr->dc_next) {
1673 fanout_stat_entry_t *curr_stats = curr->dc_statentry;
1674
1675 curr_stats->fe_index = index;
1676 curr_stats->fe_id = L_HWLANE;
1677 /*
1678 * Save last pointer of previous linked list.
1679 * This pointer is used to chain linked lists
1680 * generated in each iteration.
1681 */
1682 prev = curr;
1683 }
1684 }
1685
1686 return (head);
1687 }
1688
1689 void *
dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh,datalink_id_t linkid,const char * linkname)1690 dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh, datalink_id_t linkid,
1691 const char *linkname)
1692 {
1693 return (i_dlstat_query_fanout_stats(dh, linkid,
1694 default_idlist, default_idlist_size, linkname,
1695 DLSTAT_MAC_RX_SWLANE));
1696 }
1697
1698 void *
dlstat_fanout_hwlane_stats(dladm_handle_t dh,datalink_id_t linkid,const char * linkname)1699 dlstat_fanout_hwlane_stats(dladm_handle_t dh, datalink_id_t linkid,
1700 const char *linkname)
1701 {
1702 uint_t rx_hwlane_idlist[MAX_RINGS_PER_GROUP];
1703 uint_t rx_hwlane_idlist_size;
1704
1705 i_dlstat_get_idlist(dh, linkname, DLSTAT_RX_HWLANE_IDLIST,
1706 rx_hwlane_idlist, &rx_hwlane_idlist_size);
1707
1708 return (i_dlstat_query_fanout_stats(dh, linkid, rx_hwlane_idlist,
1709 rx_hwlane_idlist_size, linkname, DLSTAT_MAC_RX_HWLANE));
1710 }
1711
1712 void *
dlstat_fanout_stats(dladm_handle_t dh,datalink_id_t linkid)1713 dlstat_fanout_stats(dladm_handle_t dh, datalink_id_t linkid)
1714 {
1715 dladm_stat_chain_t *head = NULL;
1716 dladm_stat_chain_t *fout_hwlane_stats;
1717 dladm_stat_chain_t *fout_swlane_and_local_stats;
1718 fanout_stat_entry_t *fout_stats;
1719 char linkname[MAXLINKNAMELEN];
1720
1721 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1722 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1723 goto done;
1724 }
1725
1726 fout_swlane_and_local_stats =
1727 dlstat_fanout_swlane_and_local_stats(dh, linkid, linkname);
1728 fout_hwlane_stats = dlstat_fanout_hwlane_stats(dh, linkid, linkname);
1729
1730 if (fout_swlane_and_local_stats == NULL) {
1731 head = fout_hwlane_stats;
1732 goto done;
1733 }
1734
1735 fout_stats = fout_swlane_and_local_stats->dc_statentry;
1736
1737 if (fout_hwlane_stats != NULL) { /* hwlane(s), only local traffic */
1738 fout_stats->fe_id = L_LOCAL;
1739 fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
1740 } else { /* no hwlane, mix of local+sw classified */
1741 fout_stats->fe_id = L_LCLSWLANE;
1742 fout_stats->fe_index = DLSTAT_INVALID_ENTRY;
1743 }
1744
1745 fout_swlane_and_local_stats->dc_next = fout_hwlane_stats;
1746 head = fout_swlane_and_local_stats;
1747
1748 done:
1749 return (head);
1750 }
1751
1752 /* Rx ring statistic specific functions */
1753 static boolean_t
i_dlstat_rx_ring_match(void * arg1,void * arg2)1754 i_dlstat_rx_ring_match(void *arg1, void *arg2)
1755 {
1756 rx_lane_stat_entry_t *s1 = arg1;
1757 rx_lane_stat_entry_t *s2 = arg2;
1758
1759 return (s1->rle_index == s2->rle_index);
1760 }
1761
1762 static void *
i_dlstat_rx_ring_stat_entry_diff(void * arg1,void * arg2)1763 i_dlstat_rx_ring_stat_entry_diff(void *arg1, void *arg2)
1764 {
1765 ring_stat_entry_t *s1 = arg1;
1766 ring_stat_entry_t *s2 = arg2;
1767 ring_stat_entry_t *diff_entry;
1768
1769 diff_entry = malloc(sizeof (ring_stat_entry_t));
1770 if (diff_entry == NULL)
1771 goto done;
1772
1773 diff_entry->re_index = s1->re_index;
1774
1775 DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, rx_ring_stats_list,
1776 RX_RING_STAT_SIZE);
1777
1778 done:
1779 return (diff_entry);
1780 }
1781
1782 static void *
i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1783 i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1784 {
1785 ring_stat_entry_t *rx_ring_stat_entry;
1786
1787 rx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
1788 if (rx_ring_stat_entry == NULL)
1789 goto done;
1790
1791 rx_ring_stat_entry->re_index = i;
1792
1793 i_dlstat_get_stats(kcp, ksp, &rx_ring_stat_entry->re_stats,
1794 rx_ring_stats_list, RX_RING_STAT_SIZE);
1795
1796 done:
1797 return (rx_ring_stat_entry);
1798 }
1799
1800 void *
dlstat_rx_ring_stats(dladm_handle_t dh,datalink_id_t linkid)1801 dlstat_rx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
1802 {
1803 uint_t rx_ring_idlist[MAX_RINGS_PER_GROUP];
1804 uint_t rx_ring_idlist_size;
1805 dladm_phys_attr_t dpa;
1806 char linkname[MAXLINKNAMELEN];
1807 char *modname;
1808 datalink_class_t class;
1809
1810 /*
1811 * kstats corresponding to physical device rings continue to use
1812 * device names even if the link is renamed using dladm rename-link.
1813 * Thus, given a linkid, we lookup the physical device name.
1814 * However, if an aggr is renamed, kstats corresponding to its
1815 * pseudo rings are renamed as well.
1816 */
1817 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
1818 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1819 return (NULL);
1820 }
1821
1822 if (class != DATALINK_CLASS_AGGR) {
1823 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
1824 DLADM_STATUS_OK) {
1825 return (NULL);
1826 }
1827 modname = dpa.dp_dev;
1828 } else
1829 modname = linkname;
1830
1831 i_dlstat_get_idlist(dh, modname, DLSTAT_RX_RING_IDLIST,
1832 rx_ring_idlist, &rx_ring_idlist_size);
1833
1834 return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_RX_RING,
1835 rx_ring_idlist, rx_ring_idlist_size,
1836 i_dlstat_rx_ring_retrieve_stat));
1837 }
1838
1839 /* Tx ring statistic specific functions */
1840 static boolean_t
i_dlstat_tx_ring_match(void * arg1,void * arg2)1841 i_dlstat_tx_ring_match(void *arg1, void *arg2)
1842 {
1843 tx_lane_stat_entry_t *s1 = arg1;
1844 tx_lane_stat_entry_t *s2 = arg2;
1845
1846 return (s1->tle_index == s2->tle_index);
1847 }
1848
1849 static void *
i_dlstat_tx_ring_stat_entry_diff(void * arg1,void * arg2)1850 i_dlstat_tx_ring_stat_entry_diff(void *arg1, void *arg2)
1851 {
1852 ring_stat_entry_t *s1 = arg1;
1853 ring_stat_entry_t *s2 = arg2;
1854 ring_stat_entry_t *diff_entry;
1855
1856 diff_entry = malloc(sizeof (ring_stat_entry_t));
1857 if (diff_entry == NULL)
1858 goto done;
1859
1860 diff_entry->re_index = s1->re_index;
1861
1862 DLSTAT_DIFF_STAT(s1, s2, diff_entry, re_stats, tx_ring_stats_list,
1863 TX_RING_STAT_SIZE);
1864
1865 done:
1866 return (diff_entry);
1867 }
1868
1869 static void *
i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t * kcp,kstat_t * ksp,int i)1870 i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
1871 {
1872 ring_stat_entry_t *tx_ring_stat_entry;
1873
1874 tx_ring_stat_entry = calloc(1, sizeof (ring_stat_entry_t));
1875 if (tx_ring_stat_entry == NULL)
1876 goto done;
1877
1878 tx_ring_stat_entry->re_index = i;
1879
1880 i_dlstat_get_stats(kcp, ksp, &tx_ring_stat_entry->re_stats,
1881 tx_ring_stats_list, TX_RING_STAT_SIZE);
1882
1883 done:
1884 return (tx_ring_stat_entry);
1885 }
1886
1887 void *
dlstat_tx_ring_stats(dladm_handle_t dh,datalink_id_t linkid)1888 dlstat_tx_ring_stats(dladm_handle_t dh, datalink_id_t linkid)
1889 {
1890 uint_t tx_ring_idlist[MAX_RINGS_PER_GROUP];
1891 uint_t tx_ring_idlist_size;
1892 dladm_phys_attr_t dpa;
1893 char linkname[MAXLINKNAMELEN];
1894 char *modname;
1895 datalink_class_t class;
1896
1897 /*
1898 * kstats corresponding to physical device rings continue to use
1899 * device names even if the link is renamed using dladm rename-link.
1900 * Thus, given a linkid, we lookup the physical device name.
1901 * However, if an aggr is renamed, kstats corresponding to its
1902 * pseudo rings are renamed as well.
1903 */
1904 if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, linkname,
1905 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1906 return (NULL);
1907 }
1908
1909 if (class != DATALINK_CLASS_AGGR) {
1910 if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
1911 DLADM_STATUS_OK) {
1912 return (NULL);
1913 }
1914 modname = dpa.dp_dev;
1915 } else
1916 modname = linkname;
1917
1918 i_dlstat_get_idlist(dh, modname, DLSTAT_TX_RING_IDLIST,
1919 tx_ring_idlist, &tx_ring_idlist_size);
1920
1921 return (i_dlstat_query_stats(dh, modname, DLSTAT_MAC_TX_RING,
1922 tx_ring_idlist, tx_ring_idlist_size,
1923 i_dlstat_tx_ring_retrieve_stat));
1924 }
1925
1926 /* Rx ring total statistic specific functions */
1927 void *
dlstat_rx_ring_total_stats(dladm_handle_t dh,datalink_id_t linkid)1928 dlstat_rx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1929 {
1930 dladm_stat_chain_t *total_head = NULL;
1931 dladm_stat_chain_t *rx_ring_head, *curr;
1932 ring_stat_entry_t *total_stats;
1933
1934 /* Get per rx ring stats */
1935 rx_ring_head = dlstat_rx_ring_stats(dh, linkid);
1936 if (rx_ring_head == NULL)
1937 goto done;
1938
1939 total_stats = calloc(1, sizeof (ring_stat_entry_t));
1940 if (total_stats == NULL)
1941 goto done;
1942
1943 total_stats->re_index = DLSTAT_INVALID_ENTRY;
1944
1945 for (curr = rx_ring_head; curr != NULL; curr = curr->dc_next) {
1946 ring_stat_entry_t *curr_ring_stats = curr->dc_statentry;
1947
1948 i_dlstat_sum_stats(&total_stats->re_stats,
1949 &curr_ring_stats->re_stats, &total_stats->re_stats,
1950 rx_ring_stats_list, RX_RING_STAT_SIZE);
1951 }
1952
1953 total_head = malloc(sizeof (dladm_stat_chain_t));
1954 if (total_head == NULL) {
1955 free(total_stats);
1956 goto done;
1957 }
1958
1959 total_head->dc_statentry = total_stats;
1960 (void) strlcpy(total_head->dc_statheader, "mac_rx_ring_total",
1961 sizeof (total_head->dc_statheader));
1962 total_head->dc_next = NULL;
1963 free(rx_ring_head);
1964
1965 done:
1966 return (total_head);
1967 }
1968
1969 /* Tx ring total statistic specific functions */
1970 void *
dlstat_tx_ring_total_stats(dladm_handle_t dh,datalink_id_t linkid)1971 dlstat_tx_ring_total_stats(dladm_handle_t dh, datalink_id_t linkid)
1972 {
1973 dladm_stat_chain_t *total_head = NULL;
1974 dladm_stat_chain_t *tx_ring_head, *curr;
1975 ring_stat_entry_t *total_stats;
1976
1977 /* Get per tx ring stats */
1978 tx_ring_head = dlstat_tx_ring_stats(dh, linkid);
1979 if (tx_ring_head == NULL)
1980 goto done;
1981
1982 total_stats = calloc(1, sizeof (ring_stat_entry_t));
1983 if (total_stats == NULL)
1984 goto done;
1985
1986 total_stats->re_index = DLSTAT_INVALID_ENTRY;
1987
1988 for (curr = tx_ring_head; curr != NULL; curr = curr->dc_next) {
1989 ring_stat_entry_t *curr_ring_stats = curr->dc_statentry;
1990
1991 i_dlstat_sum_stats(&total_stats->re_stats,
1992 &curr_ring_stats->re_stats, &total_stats->re_stats,
1993 tx_ring_stats_list, TX_RING_STAT_SIZE);
1994 }
1995
1996 total_head = malloc(sizeof (dladm_stat_chain_t));
1997 if (total_head == NULL) {
1998 free(total_stats);
1999 goto done;
2000 }
2001
2002 total_head->dc_statentry = total_stats;
2003 (void) strlcpy(total_head->dc_statheader, "mac_tx_ring_total",
2004 sizeof (total_head->dc_statheader));
2005 total_head->dc_next = NULL;
2006 free(tx_ring_head);
2007
2008 done:
2009 return (total_head);
2010 }
2011
2012 /* Summary statistic specific functions */
2013 static boolean_t
i_dlstat_total_match(void * arg1 __unused,void * arg2 __unused)2014 i_dlstat_total_match(void *arg1 __unused, void *arg2 __unused)
2015 {
2016 /* Always single entry for total */
2017 return (B_TRUE);
2018 }
2019
2020 static void *
i_dlstat_total_stat_entry_diff(void * arg1,void * arg2)2021 i_dlstat_total_stat_entry_diff(void *arg1, void *arg2)
2022 {
2023 total_stat_entry_t *s1 = arg1;
2024 total_stat_entry_t *s2 = arg2;
2025 total_stat_entry_t *diff_entry;
2026
2027 diff_entry = malloc(sizeof (total_stat_entry_t));
2028 if (diff_entry == NULL)
2029 goto done;
2030
2031 DLSTAT_DIFF_STAT(s1, s2, diff_entry, tse_stats, total_stats_list,
2032 TOTAL_STAT_SIZE);
2033
2034 done:
2035 return (diff_entry);
2036 }
2037
2038 void *
dlstat_total_stats(dladm_handle_t dh,datalink_id_t linkid)2039 dlstat_total_stats(dladm_handle_t dh, datalink_id_t linkid)
2040 {
2041 dladm_stat_chain_t *head = NULL;
2042 dladm_stat_chain_t *rx_total;
2043 dladm_stat_chain_t *tx_total;
2044 total_stat_entry_t *total_stat_entry;
2045 rx_lane_stat_entry_t *rx_lane_stat_entry;
2046 tx_lane_stat_entry_t *tx_lane_stat_entry;
2047
2048 /* Get total rx lane stats */
2049 rx_total = dlstat_rx_lane_total_stats(dh, linkid);
2050 if (rx_total == NULL)
2051 goto done;
2052
2053 /* Get total tx lane stats */
2054 tx_total = dlstat_tx_lane_total_stats(dh, linkid);
2055 if (tx_total == NULL)
2056 goto done;
2057
2058 /* Build total stat */
2059 total_stat_entry = calloc(1, sizeof (total_stat_entry_t));
2060 if (total_stat_entry == NULL)
2061 goto done;
2062
2063 rx_lane_stat_entry = rx_total->dc_statentry;
2064 tx_lane_stat_entry = tx_total->dc_statentry;
2065
2066 /* Extract total rx ipackets, rbytes */
2067 total_stat_entry->tse_stats.ts_ipackets =
2068 rx_lane_stat_entry->rle_stats.rl_ipackets;
2069 total_stat_entry->tse_stats.ts_rbytes =
2070 rx_lane_stat_entry->rle_stats.rl_rbytes;
2071
2072 /* Extract total tx opackets, obytes */
2073 total_stat_entry->tse_stats.ts_opackets =
2074 tx_lane_stat_entry->tle_stats.tl_opackets;
2075 total_stat_entry->tse_stats.ts_obytes =
2076 tx_lane_stat_entry->tle_stats.tl_obytes;
2077
2078 head = malloc(sizeof (dladm_stat_chain_t));
2079 if (head == NULL) {
2080 free(total_stat_entry);
2081 goto done;
2082 }
2083
2084 head->dc_statentry = total_stat_entry;
2085 (void) strlcpy(head->dc_statheader, "mac_lane_total",
2086 sizeof (head->dc_statheader));
2087 head->dc_next = NULL;
2088 free(rx_total);
2089 free(tx_total);
2090
2091 done:
2092 return (head);
2093 }
2094
2095 /* Aggr total statistic(summed across all component ports) specific functions */
2096 void *
dlstat_aggr_total_stats(dladm_stat_chain_t * head)2097 dlstat_aggr_total_stats(dladm_stat_chain_t *head)
2098 {
2099 dladm_stat_chain_t *curr;
2100 dladm_stat_chain_t *total_head = NULL;
2101 aggr_port_stat_entry_t *total_stats;
2102
2103 total_stats = calloc(1, sizeof (aggr_port_stat_entry_t));
2104 if (total_stats == NULL)
2105 goto done;
2106
2107 total_stats->ape_portlinkid = DATALINK_INVALID_LINKID;
2108
2109 for (curr = head; curr != NULL; curr = curr->dc_next) {
2110 aggr_port_stat_entry_t *curr_aggr_port_stats;
2111
2112 curr_aggr_port_stats = curr->dc_statentry;
2113
2114 i_dlstat_sum_stats(&total_stats->ape_stats,
2115 &curr_aggr_port_stats->ape_stats, &total_stats->ape_stats,
2116 aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
2117 }
2118
2119 total_head = malloc(sizeof (dladm_stat_chain_t));
2120 if (total_head == NULL) {
2121 free(total_stats);
2122 goto done;
2123 }
2124
2125 total_head->dc_statentry = total_stats;
2126 total_head->dc_next = NULL;
2127
2128 done:
2129 return (total_head);
2130 }
2131
2132 /* Aggr port statistic specific functions */
2133 static boolean_t
i_dlstat_aggr_port_match(void * arg1,void * arg2)2134 i_dlstat_aggr_port_match(void *arg1, void *arg2)
2135 {
2136 aggr_port_stat_entry_t *s1 = arg1;
2137 aggr_port_stat_entry_t *s2 = arg2;
2138
2139 return (s1->ape_portlinkid == s2->ape_portlinkid);
2140 }
2141
2142 static void *
i_dlstat_aggr_port_stat_entry_diff(void * arg1,void * arg2)2143 i_dlstat_aggr_port_stat_entry_diff(void *arg1, void *arg2)
2144 {
2145 aggr_port_stat_entry_t *s1 = arg1;
2146 aggr_port_stat_entry_t *s2 = arg2;
2147 aggr_port_stat_entry_t *diff_entry;
2148
2149 diff_entry = malloc(sizeof (aggr_port_stat_entry_t));
2150 if (diff_entry == NULL)
2151 goto done;
2152
2153 diff_entry->ape_portlinkid = s1->ape_portlinkid;
2154
2155 DLSTAT_DIFF_STAT(s1, s2, diff_entry, ape_stats, aggr_port_stats_list,
2156 AGGR_PORT_STAT_SIZE);
2157
2158 done:
2159 return (diff_entry);
2160 }
2161
2162 /*
2163 * Query dls stats for the aggr port. This results in query for stats into
2164 * the corresponding device driver.
2165 */
2166 static aggr_port_stat_entry_t *
i_dlstat_single_port_stats(dladm_handle_t handle,const char * portname,datalink_id_t linkid)2167 i_dlstat_single_port_stats(dladm_handle_t handle, const char *portname,
2168 datalink_id_t linkid)
2169 {
2170 kstat_t *ksp;
2171 char module[DLPI_LINKNAME_MAX];
2172 uint_t instance;
2173 aggr_port_stat_entry_t *aggr_port_stat_entry = NULL;
2174
2175 if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK)
2176 goto done;
2177
2178 if (dladm_dld_kcp(handle) == NULL) {
2179 warn("kstat open operation failed");
2180 return (NULL);
2181 }
2182
2183 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), module, instance,
2184 "mac", NULL);
2185 if (ksp == NULL)
2186 goto done;
2187
2188 aggr_port_stat_entry = calloc(1, sizeof (aggr_port_stat_entry_t));
2189 if (aggr_port_stat_entry == NULL)
2190 goto done;
2191
2192 /* Save port's linkid */
2193 aggr_port_stat_entry->ape_portlinkid = linkid;
2194
2195 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp,
2196 &aggr_port_stat_entry->ape_stats,
2197 aggr_port_stats_list, AGGR_PORT_STAT_SIZE);
2198 done:
2199 return (aggr_port_stat_entry);
2200 }
2201
2202 void *
dlstat_aggr_port_stats(dladm_handle_t dh,datalink_id_t linkid)2203 dlstat_aggr_port_stats(dladm_handle_t dh, datalink_id_t linkid)
2204 {
2205 dladm_aggr_grp_attr_t ginfo;
2206 uint_t i;
2207 dladm_aggr_port_attr_t *portp;
2208 dladm_phys_attr_t dpa;
2209 aggr_port_stat_entry_t *aggr_port_stat_entry;
2210 dladm_stat_chain_t *head = NULL, *prev = NULL, *curr;
2211 dladm_stat_chain_t *total_stats;
2212
2213 /* Get aggr info */
2214 bzero(&ginfo, sizeof (dladm_aggr_grp_attr_t));
2215 if (dladm_aggr_info(dh, linkid, &ginfo, DLADM_OPT_ACTIVE)
2216 != DLADM_STATUS_OK)
2217 goto done;
2218 /* For every port that is member of this aggr do */
2219 for (i = 0; i < ginfo.lg_nports; i++) {
2220 portp = &(ginfo.lg_ports[i]);
2221 if (dladm_phys_info(dh, portp->lp_linkid, &dpa,
2222 DLADM_OPT_ACTIVE) != DLADM_STATUS_OK) {
2223 goto done;
2224 }
2225
2226 aggr_port_stat_entry = i_dlstat_single_port_stats(dh,
2227 dpa.dp_dev, portp->lp_linkid);
2228
2229 /* Create dladm_stat_chain_t object for this stat */
2230 curr = malloc(sizeof (dladm_stat_chain_t));
2231 if (curr == NULL) {
2232 free(aggr_port_stat_entry);
2233 goto done;
2234 }
2235 (void) strlcpy(curr->dc_statheader, dpa.dp_dev,
2236 sizeof (curr->dc_statheader));
2237 curr->dc_statentry = aggr_port_stat_entry;
2238 curr->dc_next = NULL;
2239
2240 /* Chain this aggr port stat entry */
2241 /* head of the stat list */
2242 if (prev == NULL)
2243 head = curr;
2244 else
2245 prev->dc_next = curr;
2246 prev = curr;
2247 }
2248
2249 /*
2250 * Prepend the stat list with cumulative aggr stats i.e. summed over all
2251 * component ports
2252 */
2253 total_stats = dlstat_aggr_total_stats(head);
2254 if (total_stats != NULL) {
2255 total_stats->dc_next = head;
2256 head = total_stats;
2257 }
2258
2259 done:
2260 free(ginfo.lg_ports);
2261 return (head);
2262 }
2263
2264 /* Misc stat specific functions */
2265 void *
dlstat_misc_stats(dladm_handle_t dh,datalink_id_t linkid)2266 dlstat_misc_stats(dladm_handle_t dh, datalink_id_t linkid)
2267 {
2268 misc_stat_entry_t *misc_stat_entry;
2269 dladm_stat_chain_t *head = NULL;
2270 char linkname[MAXLINKNAMELEN];
2271
2272 if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
2273 DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
2274 goto done;
2275 }
2276
2277 misc_stat_entry = i_dlstat_misc_stats(dh, linkname);
2278 if (misc_stat_entry == NULL)
2279 goto done;
2280
2281 head = malloc(sizeof (dladm_stat_chain_t));
2282 if (head == NULL) {
2283 free(misc_stat_entry);
2284 goto done;
2285 }
2286
2287 head->dc_statentry = misc_stat_entry;
2288 (void) strlcpy(head->dc_statheader, "mac_misc_stat",
2289 sizeof (head->dc_statheader));
2290 head->dc_next = NULL;
2291
2292 done:
2293 return (head);
2294 }
2295
2296 /* Exported functions */
2297 dladm_stat_chain_t *
dladm_link_stat_query(dladm_handle_t dh,datalink_id_t linkid,dladm_stat_type_t stattype)2298 dladm_link_stat_query(dladm_handle_t dh, datalink_id_t linkid,
2299 dladm_stat_type_t stattype)
2300 {
2301 return (dladm_stat_table[stattype].ds_querystat(dh, linkid));
2302 }
2303
2304 dladm_stat_chain_t *
dladm_link_stat_diffchain(dladm_stat_chain_t * op1,dladm_stat_chain_t * op2,dladm_stat_type_t stattype)2305 dladm_link_stat_diffchain(dladm_stat_chain_t *op1, dladm_stat_chain_t *op2,
2306 dladm_stat_type_t stattype)
2307 {
2308 dladm_stat_chain_t *op1_curr, *op2_curr;
2309 dladm_stat_chain_t *diff_curr;
2310 dladm_stat_chain_t *diff_prev = NULL, *diff_head = NULL;
2311
2312 /* Perform op1 - op2, store result in diff */
2313 for (op1_curr = op1; op1_curr != NULL; op1_curr = op1_curr->dc_next) {
2314 for (op2_curr = op2; op2_curr != NULL;
2315 op2_curr = op2_curr->dc_next) {
2316 if (dlstat_match_stats(op1_curr->dc_statentry,
2317 op2_curr->dc_statentry, stattype)) {
2318 break;
2319 }
2320 }
2321 diff_curr = malloc(sizeof (dladm_stat_chain_t));
2322 if (diff_curr == NULL)
2323 goto done;
2324
2325 diff_curr->dc_next = NULL;
2326
2327 if (op2_curr == NULL) {
2328 /* prev iteration did not have this stat entry */
2329 diff_curr->dc_statentry =
2330 dlstat_diff_stats(op1_curr->dc_statentry,
2331 NULL, stattype);
2332 } else {
2333 diff_curr->dc_statentry =
2334 dlstat_diff_stats(op1_curr->dc_statentry,
2335 op2_curr->dc_statentry, stattype);
2336 }
2337
2338 if (diff_curr->dc_statentry == NULL) {
2339 free(diff_curr);
2340 goto done;
2341 }
2342
2343 if (diff_prev == NULL) /* head of the diff stat list */
2344 diff_head = diff_curr;
2345 else
2346 diff_prev->dc_next = diff_curr;
2347 diff_prev = diff_curr;
2348 }
2349 done:
2350 return (diff_head);
2351 }
2352
2353 void
dladm_link_stat_free(dladm_stat_chain_t * curr)2354 dladm_link_stat_free(dladm_stat_chain_t *curr)
2355 {
2356 while (curr != NULL) {
2357 dladm_stat_chain_t *tofree = curr;
2358
2359 curr = curr->dc_next;
2360 free(tofree->dc_statentry);
2361 free(tofree);
2362 }
2363 }
2364
2365 /* Query all link stats */
2366 static name_value_stat_t *
i_dlstat_convert_stats(void * stats,stat_info_t stats_list[],uint_t size)2367 i_dlstat_convert_stats(void *stats, stat_info_t stats_list[], uint_t size)
2368 {
2369 uint_t i;
2370 name_value_stat_t *head_stat = NULL, *prev_stat = NULL;
2371 name_value_stat_t *curr_stat;
2372
2373 for (i = 0; i < size; i++) {
2374 uint64_t *val = (void *)
2375 ((uchar_t *)stats + stats_list[i].si_offset);
2376
2377 curr_stat = calloc(1, sizeof (name_value_stat_t));
2378 if (curr_stat == NULL)
2379 break;
2380
2381 (void) strlcpy(curr_stat->nv_statname, stats_list[i].si_name,
2382 sizeof (curr_stat->nv_statname));
2383 curr_stat->nv_statval = *val;
2384 curr_stat->nv_nextstat = NULL;
2385
2386 if (head_stat == NULL) /* First node */
2387 head_stat = curr_stat;
2388 else
2389 prev_stat->nv_nextstat = curr_stat;
2390
2391 prev_stat = curr_stat;
2392 }
2393 return (head_stat);
2394 }
2395
2396 void *
build_nvs_entry(char * statheader,void * statentry,dladm_stat_type_t stattype)2397 build_nvs_entry(char *statheader, void *statentry, dladm_stat_type_t stattype)
2398 {
2399 name_value_stat_entry_t *name_value_stat_entry;
2400 dladm_stat_desc_t *stattbl_ptr;
2401 void *statfields;
2402
2403 stattbl_ptr = &dladm_stat_table[stattype];
2404
2405 /* Allocate memory for query all stat entry */
2406 name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
2407 if (name_value_stat_entry == NULL)
2408 goto done;
2409
2410 /* Header for these stat fields */
2411 (void) strlcpy(name_value_stat_entry->nve_header, statheader,
2412 sizeof (name_value_stat_entry->nve_header));
2413
2414 /* Extract stat fields from the statentry */
2415 statfields = (uchar_t *)statentry +
2416 dladm_stat_table[stattype].ds_offset;
2417
2418 /* Convert curr_stat to <statname, statval> pair */
2419 name_value_stat_entry->nve_stats =
2420 i_dlstat_convert_stats(statfields,
2421 stattbl_ptr->ds_statlist, stattbl_ptr->ds_statsize);
2422 done:
2423 return (name_value_stat_entry);
2424 }
2425
2426 void *
i_walk_dlstat_chain(dladm_stat_chain_t * stat_head,dladm_stat_type_t stattype)2427 i_walk_dlstat_chain(dladm_stat_chain_t *stat_head, dladm_stat_type_t stattype)
2428 {
2429 dladm_stat_chain_t *curr;
2430 dladm_stat_chain_t *nvstat_head = NULL, *nvstat_prev = NULL;
2431 dladm_stat_chain_t *nvstat_curr;
2432
2433 /*
2434 * For every stat in the chain, build header and convert all
2435 * its stat fields
2436 */
2437 for (curr = stat_head; curr != NULL; curr = curr->dc_next) {
2438 nvstat_curr = malloc(sizeof (dladm_stat_chain_t));
2439 if (nvstat_curr == NULL)
2440 break;
2441
2442 nvstat_curr->dc_statentry = build_nvs_entry(curr->dc_statheader,
2443 curr->dc_statentry, stattype);
2444
2445 if (nvstat_curr->dc_statentry == NULL) {
2446 free(nvstat_curr);
2447 break;
2448 }
2449
2450 nvstat_curr->dc_next = NULL;
2451
2452 if (nvstat_head == NULL) /* First node */
2453 nvstat_head = nvstat_curr;
2454 else
2455 nvstat_prev->dc_next = nvstat_curr;
2456
2457 nvstat_prev = nvstat_curr;
2458 }
2459 return (nvstat_head);
2460 }
2461
2462 dladm_stat_chain_t *
dladm_link_stat_query_all(dladm_handle_t dh,datalink_id_t linkid,dladm_stat_type_t stattype)2463 dladm_link_stat_query_all(dladm_handle_t dh, datalink_id_t linkid,
2464 dladm_stat_type_t stattype)
2465 {
2466 dladm_stat_chain_t *stat_head;
2467 dladm_stat_chain_t *nvstat_head = NULL;
2468
2469 /* Query the requested stat */
2470 stat_head = dladm_link_stat_query(dh, linkid, stattype);
2471 if (stat_head == NULL)
2472 goto done;
2473
2474 /*
2475 * Convert every statfield in every stat-entry of stat chain to
2476 * <statname, statval> pair
2477 */
2478 nvstat_head = i_walk_dlstat_chain(stat_head, stattype);
2479
2480 /* Free stat_head */
2481 dladm_link_stat_free(stat_head);
2482
2483 done:
2484 return (nvstat_head);
2485 }
2486
2487 void
dladm_link_stat_query_all_free(dladm_stat_chain_t * curr)2488 dladm_link_stat_query_all_free(dladm_stat_chain_t *curr)
2489 {
2490 while (curr != NULL) {
2491 dladm_stat_chain_t *tofree = curr;
2492 name_value_stat_entry_t *nv_entry = curr->dc_statentry;
2493 name_value_stat_t *nv_curr = nv_entry->nve_stats;
2494
2495 while (nv_curr != NULL) {
2496 name_value_stat_t *nv_tofree = nv_curr;
2497
2498 nv_curr = nv_curr->nv_nextstat;
2499 free(nv_tofree);
2500 }
2501
2502 curr = curr->dc_next;
2503 free(nv_entry);
2504 free(tofree);
2505 }
2506 }
2507
2508 /* flow stats specific routines */
2509 flow_stat_t *
dladm_flow_stat_query(dladm_handle_t handle,const char * flowname)2510 dladm_flow_stat_query(dladm_handle_t handle, const char *flowname)
2511 {
2512 kstat_t *ksp;
2513 flow_stat_t *flow_stat = NULL;
2514
2515 if (dladm_dld_kcp(handle) == NULL)
2516 return (NULL);
2517
2518 flow_stat = calloc(1, sizeof (flow_stat_t));
2519 if (flow_stat == NULL)
2520 goto done;
2521
2522 ksp = dladm_kstat_lookup(dladm_dld_kcp(handle), NULL, -1, flowname,
2523 "flow");
2524
2525 if (ksp != NULL) {
2526 i_dlstat_get_stats(dladm_dld_kcp(handle), ksp, flow_stat,
2527 flow_stats_list, FLOW_STAT_SIZE);
2528 }
2529
2530 done:
2531 return (flow_stat);
2532 }
2533
2534 flow_stat_t *
dladm_flow_stat_diff(flow_stat_t * op1,flow_stat_t * op2)2535 dladm_flow_stat_diff(flow_stat_t *op1, flow_stat_t *op2)
2536 {
2537 flow_stat_t *diff_stat;
2538
2539 diff_stat = calloc(1, sizeof (flow_stat_t));
2540 if (diff_stat == NULL)
2541 goto done;
2542
2543 if (op2 == NULL) {
2544 bcopy(op1, diff_stat, sizeof (flow_stat_t));
2545 } else {
2546 i_dlstat_diff_stats(diff_stat, op1, op2, flow_stats_list,
2547 FLOW_STAT_SIZE);
2548 }
2549 done:
2550 return (diff_stat);
2551 }
2552
2553 void
dladm_flow_stat_free(flow_stat_t * curr)2554 dladm_flow_stat_free(flow_stat_t *curr)
2555 {
2556 free(curr);
2557 }
2558
2559 /* Query all flow stats */
2560 name_value_stat_entry_t *
dladm_flow_stat_query_all(dladm_handle_t handle,const char * flowname)2561 dladm_flow_stat_query_all(dladm_handle_t handle, const char *flowname)
2562 {
2563 flow_stat_t *flow_stat;
2564 name_value_stat_entry_t *name_value_stat_entry = NULL;
2565
2566 /* Query flow stats */
2567 flow_stat = dladm_flow_stat_query(handle, flowname);
2568 if (flow_stat == NULL)
2569 goto done;
2570
2571 /* Allocate memory for query all stat entry */
2572 name_value_stat_entry = calloc(1, sizeof (name_value_stat_entry_t));
2573 if (name_value_stat_entry == NULL) {
2574 dladm_flow_stat_free(flow_stat);
2575 goto done;
2576 }
2577
2578 /* Header for these stat fields */
2579 (void) strncpy(name_value_stat_entry->nve_header, flowname,
2580 MAXFLOWNAMELEN);
2581
2582 /* Convert every statfield in flow_stat to <statname, statval> pair */
2583 name_value_stat_entry->nve_stats =
2584 i_dlstat_convert_stats(flow_stat, flow_stats_list, FLOW_STAT_SIZE);
2585
2586 /* Free flow_stat */
2587 dladm_flow_stat_free(flow_stat);
2588
2589 done:
2590 return (name_value_stat_entry);
2591 }
2592
2593 void
dladm_flow_stat_query_all_free(name_value_stat_entry_t * curr)2594 dladm_flow_stat_query_all_free(name_value_stat_entry_t *curr)
2595 {
2596 name_value_stat_t *nv_curr = curr->nve_stats;
2597
2598 while (nv_curr != NULL) {
2599 name_value_stat_t *nv_tofree = nv_curr;
2600
2601 nv_curr = nv_curr->nv_nextstat;
2602 free(nv_tofree);
2603 }
2604 }
2605