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.
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.
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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
40 #include <libdllink.h>
41 #include <libdlflow.h>
42 #include <libdlstat.h>
43 #include <libdlaggr.h>
46 char flowname
[MAXFLOWNAMELEN
];
47 char linkname
[MAXLINKNAMELEN
];
58 struct flowlist
*stattable
= NULL
;
60 #define STATGROWSIZE 16
62 /* Exported functions */
65 * dladm_kstat_lookup() is a modified version of kstat_lookup which
66 * adds the class as a selector.
69 dladm_kstat_lookup(kstat_ctl_t
*kcp
, const char *module
, int instance
,
70 const char *name
, const char *class)
74 for (ksp
= kcp
->kc_chain
; ksp
!= NULL
; ksp
= ksp
->ks_next
) {
75 if ((module
== NULL
|| strcmp(ksp
->ks_module
, module
) == 0) &&
76 (instance
== -1 || ksp
->ks_instance
== instance
) &&
77 (name
== NULL
|| strcmp(ksp
->ks_name
, name
) == 0) &&
78 (class == NULL
|| strcmp(ksp
->ks_class
, class) == 0))
87 * dladm_get_stats() populates the supplied pktsum_t structure with
88 * the input and output packet and byte kstats from the kstat_t
89 * found with dladm_kstat_lookup.
92 dladm_get_stats(kstat_ctl_t
*kcp
, kstat_t
*ksp
, pktsum_t
*stats
)
95 if (kstat_read(kcp
, ksp
, NULL
) == -1)
98 stats
->snaptime
= gethrtime();
100 if (dladm_kstat_value(ksp
, "ipackets64", KSTAT_DATA_UINT64
,
101 &stats
->ipackets
) < 0) {
102 if (dladm_kstat_value(ksp
, "ipackets", KSTAT_DATA_UINT64
,
103 &stats
->ipackets
) < 0)
107 if (dladm_kstat_value(ksp
, "opackets64", KSTAT_DATA_UINT64
,
108 &stats
->opackets
) < 0) {
109 if (dladm_kstat_value(ksp
, "opackets", KSTAT_DATA_UINT64
,
110 &stats
->opackets
) < 0)
114 if (dladm_kstat_value(ksp
, "rbytes64", KSTAT_DATA_UINT64
,
115 &stats
->rbytes
) < 0) {
116 if (dladm_kstat_value(ksp
, "rbytes", KSTAT_DATA_UINT64
,
121 if (dladm_kstat_value(ksp
, "obytes64", KSTAT_DATA_UINT64
,
122 &stats
->obytes
) < 0) {
123 if (dladm_kstat_value(ksp
, "obytes", KSTAT_DATA_UINT64
,
128 if (dladm_kstat_value(ksp
, "ierrors", KSTAT_DATA_UINT32
,
129 &stats
->ierrors
) < 0) {
130 if (dladm_kstat_value(ksp
, "ierrors", KSTAT_DATA_UINT64
,
131 &stats
->ierrors
) < 0)
135 if (dladm_kstat_value(ksp
, "oerrors", KSTAT_DATA_UINT32
,
136 &stats
->oerrors
) < 0) {
137 if (dladm_kstat_value(ksp
, "oerrors", KSTAT_DATA_UINT64
,
138 &stats
->oerrors
) < 0)
144 dladm_kstat_value(kstat_t
*ksp
, const char *name
, uint8_t type
, void *buf
)
148 if ((knp
= kstat_data_lookup(ksp
, (char *)name
)) == NULL
)
151 if (knp
->data_type
!= type
)
155 case KSTAT_DATA_UINT64
:
156 *(uint64_t *)buf
= knp
->value
.ui64
;
158 case KSTAT_DATA_UINT32
:
159 *(uint32_t *)buf
= knp
->value
.ui32
;
169 dladm_get_single_mac_stat(dladm_handle_t handle
, datalink_id_t linkid
,
170 const char *name
, uint8_t type
, void *val
)
173 char module
[DLPI_LINKNAME_MAX
];
175 char link
[DLPI_LINKNAME_MAX
];
176 dladm_status_t status
;
177 uint32_t flags
, media
;
179 dladm_phys_attr_t dpap
;
181 if ((status
= dladm_datalink_id2info(handle
, linkid
, &flags
, NULL
,
182 &media
, link
, DLPI_LINKNAME_MAX
)) != DLADM_STATUS_OK
)
185 if (media
!= DL_ETHER
)
186 return (DLADM_STATUS_LINKINVAL
);
188 status
= dladm_phys_info(handle
, linkid
, &dpap
, DLADM_OPT_PERSIST
);
190 if (status
!= DLADM_STATUS_OK
)
193 status
= dladm_parselink(dpap
.dp_dev
, module
, &instance
);
195 if (status
!= DLADM_STATUS_OK
)
198 if ((kcp
= kstat_open()) == NULL
) {
199 warn("kstat_open operation failed");
204 * The kstat query could fail if the underlying MAC
205 * driver was already detached.
207 if ((ksp
= kstat_lookup(kcp
, module
, instance
, "mac")) == NULL
&&
208 (ksp
= kstat_lookup(kcp
, module
, instance
, NULL
)) == NULL
)
211 if (kstat_read(kcp
, ksp
, NULL
) == -1)
214 if (dladm_kstat_value(ksp
, name
, type
, val
) < 0)
217 (void) kstat_close(kcp
);
218 return (DLADM_STATUS_OK
);
221 (void) kstat_close(kcp
);
222 return (dladm_errno2status(errno
));
225 /* Compute sum of 2 pktsums (s1 = s2 + s3) */
227 dladm_stats_total(pktsum_t
*s1
, pktsum_t
*s2
, pktsum_t
*s3
)
229 s1
->rbytes
= s2
->rbytes
+ s3
->rbytes
;
230 s1
->ipackets
= s2
->ipackets
+ s3
->ipackets
;
231 s1
->ierrors
= s2
->ierrors
+ s3
->ierrors
;
232 s1
->obytes
= s2
->obytes
+ s3
->obytes
;
233 s1
->opackets
= s2
->opackets
+ s3
->opackets
;
234 s1
->oerrors
= s2
->oerrors
+ s3
->oerrors
;
235 s1
->snaptime
= s2
->snaptime
;
238 #define DIFF_STAT(s2, s3) ((s2) > (s3) ? ((s2) - (s3)) : 0)
241 /* Compute differences between 2 pktsums (s1 = s2 - s3) */
243 dladm_stats_diff(pktsum_t
*s1
, pktsum_t
*s2
, pktsum_t
*s3
)
245 s1
->rbytes
= DIFF_STAT(s2
->rbytes
, s3
->rbytes
);
246 s1
->ipackets
= DIFF_STAT(s2
->ipackets
, s3
->ipackets
);
247 s1
->ierrors
= DIFF_STAT(s2
->ierrors
, s3
->ierrors
);
248 s1
->obytes
= DIFF_STAT(s2
->obytes
, s3
->obytes
);
249 s1
->opackets
= DIFF_STAT(s2
->opackets
, s3
->opackets
);
250 s1
->oerrors
= DIFF_STAT(s2
->oerrors
, s3
->oerrors
);
251 s1
->snaptime
= DIFF_STAT(s2
->snaptime
, s3
->snaptime
);
254 #define DLSTAT_MAC_RX_SWLANE "mac_rx_swlane"
255 #define DLSTAT_MAC_RX_HWLANE "mac_rx_hwlane"
256 #define DLSTAT_MAC_TX_SWLANE "mac_tx_swlane"
257 #define DLSTAT_MAC_TX_HWLANE "mac_tx_hwlane"
258 #define DLSTAT_MAC_MISC_STAT "mac_misc_stat"
259 #define DLSTAT_MAC_RX_RING "mac_rx_ring"
260 #define DLSTAT_MAC_TX_RING "mac_tx_ring"
261 #define DLSTAT_MAC_FANOUT "mac_rx_swlane0_fanout"
268 #define A_CNT(arr) (sizeof (arr) / sizeof (arr[0]))
270 /* Definitions for rx lane stats */
271 #define RL_OFF(f) (offsetof(rx_lane_stat_t, f))
273 static stat_info_t rx_hwlane_stats_list
[] = {
274 {"ipackets", RL_OFF(rl_ipackets
)},
275 {"rbytes", RL_OFF(rl_rbytes
)},
276 {"intrs", RL_OFF(rl_intrs
)},
277 {"intrbytes", RL_OFF(rl_intrbytes
)},
278 {"polls", RL_OFF(rl_polls
)},
279 {"pollbytes", RL_OFF(rl_pollbytes
)},
280 {"rxsdrops", RL_OFF(rl_sdrops
)},
281 {"chainunder10", RL_OFF(rl_chl10
)},
282 {"chain10to50", RL_OFF(rl_ch10_50
)},
283 {"chainover50", RL_OFF(rl_chg50
)}
285 #define RX_HWLANE_STAT_SIZE A_CNT(rx_hwlane_stats_list)
287 static stat_info_t rx_swlane_stats_list
[] = {
288 {"ipackets", RL_OFF(rl_ipackets
)},
289 {"rbytes", RL_OFF(rl_rbytes
)},
290 {"local", RL_OFF(rl_lclpackets
)},
291 {"localbytes", RL_OFF(rl_lclbytes
)},
292 {"intrs", RL_OFF(rl_intrs
)},
293 {"intrbytes", RL_OFF(rl_intrbytes
)},
294 {"rxsdrops", RL_OFF(rl_sdrops
)}
296 #define RX_SWLANE_STAT_SIZE A_CNT(rx_swlane_stats_list)
298 static stat_info_t rx_lane_stats_list
[] = {
299 {"ipackets", RL_OFF(rl_ipackets
)},
300 {"rbytes", RL_OFF(rl_rbytes
)},
301 {"local", RL_OFF(rl_lclpackets
)},
302 {"localbytes", RL_OFF(rl_lclbytes
)},
303 {"intrs", RL_OFF(rl_intrs
)},
304 {"intrbytes", RL_OFF(rl_intrbytes
)},
305 {"polls", RL_OFF(rl_polls
)},
306 {"rxsdrops", RL_OFF(rl_sdrops
)},
307 {"pollbytes", RL_OFF(rl_pollbytes
)},
308 {"chainunder10", RL_OFF(rl_chl10
)},
309 {"chain10to50", RL_OFF(rl_ch10_50
)},
310 {"chainover50", RL_OFF(rl_chg50
)}
312 #define RX_LANE_STAT_SIZE A_CNT(rx_lane_stats_list)
314 /* Definitions for tx lane stats */
315 #define TL_OFF(f) (offsetof(tx_lane_stat_t, f))
317 static stat_info_t tx_lane_stats_list
[] = {
318 {"opackets", TL_OFF(tl_opackets
)},
319 {"obytes", TL_OFF(tl_obytes
)},
320 {"blockcnt", TL_OFF(tl_blockcnt
)},
321 {"unblockcnt", TL_OFF(tl_unblockcnt
)},
322 {"txsdrops", TL_OFF(tl_sdrops
)}
324 #define TX_LANE_STAT_SIZE A_CNT(tx_lane_stats_list)
326 /* Definitions for tx/rx misc stats */
327 #define M_OFF(f) (offsetof(misc_stat_t, f))
329 static stat_info_t misc_stats_list
[] = {
330 {"multircv", M_OFF(ms_multircv
)},
331 {"brdcstrcv", M_OFF(ms_brdcstrcv
)},
332 {"multixmt", M_OFF(ms_multixmt
)},
333 {"brdcstxmt", M_OFF(ms_brdcstxmt
)},
334 {"multircvbytes", M_OFF(ms_multircvbytes
)},
335 {"brdcstrcvbytes", M_OFF(ms_brdcstrcvbytes
)},
336 {"multixmtbytes", M_OFF(ms_multixmtbytes
)},
337 {"brdcstxmtbytes", M_OFF(ms_brdcstxmtbytes
)},
338 {"txerrors", M_OFF(ms_txerrors
)},
339 {"macspoofed", M_OFF(ms_macspoofed
)},
340 {"ipspoofed", M_OFF(ms_ipspoofed
)},
341 {"dhcpspoofed", M_OFF(ms_dhcpspoofed
)},
342 {"restricted", M_OFF(ms_restricted
)},
343 {"ipackets", M_OFF(ms_ipackets
)},
344 {"rbytes", M_OFF(ms_rbytes
)},
345 {"local", M_OFF(ms_local
)},
346 {"localbytes", M_OFF(ms_localbytes
)},
347 {"intrs", M_OFF(ms_intrs
)},
348 {"intrbytes", M_OFF(ms_intrbytes
)},
349 {"polls", M_OFF(ms_polls
)},
350 {"pollbytes", M_OFF(ms_pollbytes
)},
351 {"rxsdrops", M_OFF(ms_rxsdrops
)},
352 {"chainunder10", M_OFF(ms_chainunder10
)},
353 {"chain10to50", M_OFF(ms_chain10to50
)},
354 {"chainover50", M_OFF(ms_chainover50
)},
355 {"obytes", M_OFF(ms_obytes
)},
356 {"opackets", M_OFF(ms_opackets
)},
357 {"blockcnt", M_OFF(ms_blockcnt
)},
358 {"unblockcnt", M_OFF(ms_unblockcnt
)},
359 {"txsdrops", M_OFF(ms_txsdrops
)}
361 #define MISC_STAT_SIZE A_CNT(misc_stats_list)
363 /* Definitions for rx ring stats */
364 #define R_OFF(f) (offsetof(ring_stat_t, f))
366 static stat_info_t rx_ring_stats_list
[] = {
367 {"ipackets", R_OFF(r_packets
)},
368 {"rbytes", R_OFF(r_bytes
)}
370 #define RX_RING_STAT_SIZE A_CNT(rx_ring_stats_list)
372 /* Definitions for tx ring stats */
373 static stat_info_t tx_ring_stats_list
[] = {
374 {"opackets", R_OFF(r_packets
)},
375 {"obytes", R_OFF(r_bytes
)}
377 #define TX_RING_STAT_SIZE A_CNT(tx_ring_stats_list)
379 /* Definitions for fanout stats */
380 #define F_OFF(f) (offsetof(fanout_stat_t, f))
382 static stat_info_t fanout_stats_list
[] = {
383 {"ipackets", F_OFF(f_ipackets
)},
384 {"rbytes", F_OFF(f_rbytes
)},
386 #define FANOUT_STAT_SIZE A_CNT(fanout_stats_list)
388 /* Definitions for total stats */
389 #define T_OFF(f) (offsetof(total_stat_t, f))
391 static stat_info_t total_stats_list
[] = {
392 {"ipackets", T_OFF(ts_ipackets
)},
393 {"rbytes", T_OFF(ts_rbytes
)},
394 {"opackets", T_OFF(ts_opackets
)},
395 {"obytes", T_OFF(ts_obytes
)}
397 #define TOTAL_STAT_SIZE A_CNT(total_stats_list)
399 /* Definitions for aggr stats */
400 #define AP_OFF(f) (offsetof(aggr_port_stat_t, f))
402 static stat_info_t aggr_port_stats_list
[] = {
403 {"ipackets64", AP_OFF(ap_ipackets
)},
404 {"rbytes64", AP_OFF(ap_rbytes
)},
405 {"opackets64", AP_OFF(ap_opackets
)},
406 {"obytes64", AP_OFF(ap_obytes
)}
408 #define AGGR_PORT_STAT_SIZE A_CNT(aggr_port_stats_list)
410 /* Definitions for flow stats */
411 #define FL_OFF(f) (offsetof(flow_stat_t, f))
413 static stat_info_t flow_stats_list
[] = {
414 {"ipackets", FL_OFF(fl_ipackets
)},
415 {"rbytes", FL_OFF(fl_rbytes
)},
416 {"opackets", FL_OFF(fl_opackets
)},
417 {"obytes", FL_OFF(fl_obytes
)}
419 #define FLOW_STAT_SIZE A_CNT(flow_stats_list)
421 /* Rx lane specific functions */
422 void * dlstat_rx_lane_stats(dladm_handle_t
, datalink_id_t
);
423 static boolean_t
i_dlstat_rx_lane_match(void *, void *);
424 static void * i_dlstat_rx_lane_stat_entry_diff(void *, void *);
426 /* Tx lane specific functions */
427 void * dlstat_tx_lane_stats(dladm_handle_t
, datalink_id_t
);
428 static boolean_t
i_dlstat_tx_lane_match(void *, void *);
429 static void * i_dlstat_tx_lane_stat_entry_diff(void *, void *);
431 /* Rx lane total specific functions */
432 void * dlstat_rx_lane_total_stats(dladm_handle_t
,
435 /* Tx lane total specific functions */
436 void * dlstat_tx_lane_total_stats(dladm_handle_t
,
439 /* Fanout specific functions */
440 void * dlstat_fanout_stats(dladm_handle_t
, datalink_id_t
);
441 static boolean_t
i_dlstat_fanout_match(void *, void *);
442 static void * i_dlstat_fanout_stat_entry_diff(void *, void *);
444 /* Rx ring specific functions */
445 void * dlstat_rx_ring_stats(dladm_handle_t
, datalink_id_t
);
446 static boolean_t
i_dlstat_rx_ring_match(void *, void *);
447 static void * i_dlstat_rx_ring_stat_entry_diff(void *, void *);
449 /* Tx ring specific functions */
450 void * dlstat_tx_ring_stats(dladm_handle_t
, datalink_id_t
);
451 static boolean_t
i_dlstat_tx_ring_match(void *, void *);
452 static void * i_dlstat_tx_ring_stat_entry_diff(void *, void *);
454 /* Rx ring total specific functions */
455 void * dlstat_rx_ring_total_stats(dladm_handle_t
,
458 /* Tx ring total specific functions */
459 void * dlstat_tx_ring_total_stats(dladm_handle_t
,
462 /* Summary specific functions */
463 void * dlstat_total_stats(dladm_handle_t
, datalink_id_t
);
464 static boolean_t
i_dlstat_total_match(void *, void *);
465 static void * i_dlstat_total_stat_entry_diff(void *, void *);
467 /* Aggr port specific functions */
468 void * dlstat_aggr_port_stats(dladm_handle_t
, datalink_id_t
);
469 static boolean_t
i_dlstat_aggr_port_match(void *, void *);
470 static void * i_dlstat_aggr_port_stat_entry_diff(void *, void *);
472 /* Misc stat specific functions */
473 void * dlstat_misc_stats(dladm_handle_t
, datalink_id_t
);
475 typedef void * dladm_stat_query_t(dladm_handle_t
, datalink_id_t
);
476 typedef boolean_t
dladm_stat_match_t(void *, void *);
477 typedef void * dladm_stat_diff_t(void *, void *);
479 typedef struct dladm_stat_desc_s
{
480 dladm_stat_type_t ds_stattype
;
481 dladm_stat_query_t
*ds_querystat
;
482 dladm_stat_match_t
*ds_matchstat
;
483 dladm_stat_diff_t
*ds_diffstat
;
485 stat_info_t
*ds_statlist
;
490 * dladm_stat_table has one entry for each supported stat. ds_querystat returns
491 * a chain of 'stat entries' for the queried stat.
492 * Each stat entry has set of identifiers (ids) and an object containing actual
493 * stat values. These stat entry objects are chained together in a linked list
494 * of datatype dladm_stat_chain_t. Head of this list is returned to the caller
495 * of dladm_link_stat_query.
497 * One node in the chain is shown below:
499 * -------------------------
504 * | | stat fields | |
506 * -------------------------
507 * | dc_next ---------|------> to next stat entry
508 * -------------------------
510 * In particular, for query DLADM_STAT_RX_LANE, dc_statentry carries pointer to
511 * object of type rx_lane_stat_entry_t.
513 * dladm_link_stat_query_all returns similar chain. However, instead of storing
514 * stat fields as raw numbers, it stores those as chain of <name, value> pairs.
515 * The resulting structure is depicted below:
517 * -------------------------
519 * | -------------- | ---------------
520 * | | nv_header | | | name, val |
521 * | -------------- | ---------------
522 * | | nve_stats---|----|-->| nv_nextstat--|---> to next name, val pair
523 * | -------------- | ---------------
524 * -------------------------
525 * | dc_next ---------|------> to next stat entry
526 * -------------------------
528 static dladm_stat_desc_t dladm_stat_table
[] = {
529 { DLADM_STAT_RX_LANE
, dlstat_rx_lane_stats
,
530 i_dlstat_rx_lane_match
, i_dlstat_rx_lane_stat_entry_diff
,
531 offsetof(rx_lane_stat_entry_t
, rle_stats
),
532 rx_lane_stats_list
, RX_LANE_STAT_SIZE
},
534 { DLADM_STAT_TX_LANE
, dlstat_tx_lane_stats
,
535 i_dlstat_tx_lane_match
, i_dlstat_tx_lane_stat_entry_diff
,
536 offsetof(tx_lane_stat_entry_t
, tle_stats
),
537 tx_lane_stats_list
, TX_LANE_STAT_SIZE
},
539 { DLADM_STAT_RX_LANE_TOTAL
, dlstat_rx_lane_total_stats
,
540 i_dlstat_rx_lane_match
, i_dlstat_rx_lane_stat_entry_diff
,
541 offsetof(rx_lane_stat_entry_t
, rle_stats
),
542 rx_lane_stats_list
, RX_LANE_STAT_SIZE
},
544 { DLADM_STAT_TX_LANE_TOTAL
, dlstat_tx_lane_total_stats
,
545 i_dlstat_tx_lane_match
, i_dlstat_tx_lane_stat_entry_diff
,
546 offsetof(tx_lane_stat_entry_t
, tle_stats
),
547 tx_lane_stats_list
, TX_LANE_STAT_SIZE
},
549 { DLADM_STAT_RX_LANE_FOUT
, dlstat_fanout_stats
,
550 i_dlstat_fanout_match
, i_dlstat_fanout_stat_entry_diff
,
551 offsetof(fanout_stat_entry_t
, fe_stats
),
552 fanout_stats_list
, FANOUT_STAT_SIZE
},
554 { DLADM_STAT_RX_RING
, dlstat_rx_ring_stats
,
555 i_dlstat_rx_ring_match
, i_dlstat_rx_ring_stat_entry_diff
,
556 offsetof(ring_stat_entry_t
, re_stats
),
557 rx_ring_stats_list
, RX_RING_STAT_SIZE
},
559 { DLADM_STAT_TX_RING
, dlstat_tx_ring_stats
,
560 i_dlstat_tx_ring_match
, i_dlstat_tx_ring_stat_entry_diff
,
561 offsetof(ring_stat_entry_t
, re_stats
),
562 tx_ring_stats_list
, TX_RING_STAT_SIZE
},
564 { DLADM_STAT_RX_RING_TOTAL
, dlstat_rx_ring_total_stats
,
565 i_dlstat_rx_ring_match
, i_dlstat_rx_ring_stat_entry_diff
,
566 offsetof(ring_stat_entry_t
, re_stats
),
567 rx_ring_stats_list
, RX_RING_STAT_SIZE
},
569 { DLADM_STAT_TX_RING_TOTAL
, dlstat_tx_ring_total_stats
,
570 i_dlstat_tx_ring_match
, i_dlstat_tx_ring_stat_entry_diff
,
571 offsetof(ring_stat_entry_t
, re_stats
),
572 tx_ring_stats_list
, TX_RING_STAT_SIZE
},
574 { DLADM_STAT_TOTAL
, dlstat_total_stats
,
575 i_dlstat_total_match
, i_dlstat_total_stat_entry_diff
,
576 offsetof(total_stat_entry_t
, tse_stats
),
577 total_stats_list
, TOTAL_STAT_SIZE
},
579 { DLADM_STAT_AGGR_PORT
, dlstat_aggr_port_stats
,
580 i_dlstat_aggr_port_match
, i_dlstat_aggr_port_stat_entry_diff
,
581 offsetof(aggr_port_stat_entry_t
, ape_stats
),
582 aggr_port_stats_list
, AGGR_PORT_STAT_SIZE
},
584 * We don't support -i <interval> query with misc stats. Several table fields
585 * are left uninitialized thus.
587 { DLADM_STAT_MISC
, dlstat_misc_stats
,
590 misc_stats_list
, MISC_STAT_SIZE
}
593 /* Internal functions */
595 dlstat_diff_stats(void *arg1
, void *arg2
, dladm_stat_type_t stattype
)
597 return (dladm_stat_table
[stattype
].ds_diffstat(arg1
, arg2
));
601 dlstat_match_stats(void *arg1
, void *arg2
, dladm_stat_type_t stattype
)
603 return (dladm_stat_table
[stattype
].ds_matchstat(arg1
, arg2
));
606 /* Diff between two stats */
608 i_dlstat_diff_stats(void *diff
, void *op1
, void *op2
,
609 stat_info_t stats_list
[], uint_t size
)
613 for (i
= 0; i
< size
; i
++) {
614 uint64_t *op1_val
= (void *)
615 ((uchar_t
*)op1
+ stats_list
[i
].si_offset
);
616 uint64_t *op2_val
= (void *)
617 ((uchar_t
*)op2
+ stats_list
[i
].si_offset
);
618 uint64_t *diff_val
= (void *)
619 ((uchar_t
*)diff
+ stats_list
[i
].si_offset
);
621 *diff_val
= DIFF_STAT(*op1_val
, *op2_val
);
626 * Perform diff = s1 - s2, where diff, s1, s2 are structure objects of same
627 * datatype. slist is list of offsets of the fields within the structure.
629 #define DLSTAT_DIFF_STAT(s1, s2, diff, f, slist, sz) { \
631 bcopy(&s1->f, &diff->f, sizeof (s1->f)); \
633 i_dlstat_diff_stats(&diff->f, &s1->f, \
634 &s2->f, slist, sz); \
640 i_dlstat_sum_stats(void *sum
, void *op1
, void *op2
,
641 stat_info_t stats_list
[], uint_t size
)
645 for (i
= 0; i
< size
; i
++) {
646 uint64_t *op1_val
= (void *)
647 ((uchar_t
*)op1
+ stats_list
[i
].si_offset
);
648 uint64_t *op2_val
= (void *)
649 ((uchar_t
*)op2
+ stats_list
[i
].si_offset
);
650 uint64_t *sum_val
= (void *)
651 ((uchar_t
*)sum
+ stats_list
[i
].si_offset
);
653 *sum_val
= *op1_val
+ *op2_val
;
657 /* Look up kstat value */
659 i_dlstat_get_stats(kstat_ctl_t
*kcp
, kstat_t
*ksp
, void *stats
,
660 stat_info_t stats_list
[], uint_t size
)
664 if (kstat_read(kcp
, ksp
, NULL
) == -1)
667 for (i
= 0; i
< size
; i
++) {
668 uint64_t *val
= (void *)
669 ((uchar_t
*)stats
+ stats_list
[i
].si_offset
);
671 if (dladm_kstat_value(ksp
, stats_list
[i
].si_name
,
672 KSTAT_DATA_UINT64
, val
) < 0)
677 /* Append linked list list1 to linked list list2 and return resulting list */
678 static dladm_stat_chain_t
*
679 i_dlstat_join_lists(dladm_stat_chain_t
*list1
, dladm_stat_chain_t
*list2
)
681 dladm_stat_chain_t
*curr
;
686 /* list1 has at least one element, find last element in list1 */
688 while (curr
->dc_next
!= NULL
)
689 curr
= curr
->dc_next
;
691 curr
->dc_next
= list2
;
695 uint_t default_idlist
[] = {0};
696 uint_t default_idlist_size
= 1;
699 DLSTAT_RX_RING_IDLIST
,
700 DLSTAT_TX_RING_IDLIST
,
701 DLSTAT_RX_HWLANE_IDLIST
,
702 DLSTAT_TX_HWLANE_IDLIST
,
704 } dlstat_idlist_type_t
;
707 dladm_sort_index_list(uint_t idlist
[], uint_t size
)
711 for (j
= 1; j
< size
; j
++) {
713 for (i
= j
- 1; (i
>= 0) && (idlist
[i
] > key
); i
--)
714 idlist
[i
+ 1] = idlist
[i
];
719 /* Support for legacy drivers */
721 i_query_legacy_stats(const char *linkname
, pktsum_t
*stats
)
726 bzero(stats
, sizeof (*stats
));
728 if ((kcp
= kstat_open()) == NULL
)
731 ksp
= dladm_kstat_lookup(kcp
, "link", 0, linkname
, NULL
);
734 dladm_get_stats(kcp
, ksp
, stats
);
736 (void) kstat_close(kcp
);
740 i_dlstat_legacy_rx_lane_stats(const char *linkname
)
742 dladm_stat_chain_t
*head
= NULL
;
744 rx_lane_stat_entry_t
*rx_lane_stat_entry
;
746 bzero(&stats
, sizeof (pktsum_t
));
748 /* Query for dls stats */
749 i_query_legacy_stats(linkname
, &stats
);
751 /* Convert to desired data type */
752 rx_lane_stat_entry
= calloc(1, sizeof (rx_lane_stat_entry_t
));
753 if (rx_lane_stat_entry
== NULL
)
756 rx_lane_stat_entry
->rle_index
= DLSTAT_INVALID_ENTRY
;
757 rx_lane_stat_entry
->rle_id
= L_SWLANE
;
759 rx_lane_stat_entry
->rle_stats
.rl_ipackets
= stats
.ipackets
;
760 rx_lane_stat_entry
->rle_stats
.rl_intrs
= stats
.ipackets
;
761 rx_lane_stat_entry
->rle_stats
.rl_rbytes
= stats
.rbytes
;
763 /* Allocate memory for wrapper */
764 head
= malloc(sizeof (dladm_stat_chain_t
));
766 free(rx_lane_stat_entry
);
770 head
->dc_statentry
= rx_lane_stat_entry
;
771 head
->dc_next
= NULL
;
777 i_dlstat_legacy_tx_lane_stats(const char *linkname
)
779 dladm_stat_chain_t
*head
= NULL
;
781 tx_lane_stat_entry_t
*tx_lane_stat_entry
;
783 bzero(&stats
, sizeof (pktsum_t
));
785 /* Query for dls stats */
786 i_query_legacy_stats(linkname
, &stats
);
788 /* Convert to desired data type */
789 tx_lane_stat_entry
= calloc(1, sizeof (tx_lane_stat_entry_t
));
790 if (tx_lane_stat_entry
== NULL
)
793 tx_lane_stat_entry
->tle_index
= DLSTAT_INVALID_ENTRY
;
794 tx_lane_stat_entry
->tle_id
= L_SWLANE
;
796 tx_lane_stat_entry
->tle_stats
.tl_opackets
= stats
.opackets
;
797 tx_lane_stat_entry
->tle_stats
.tl_obytes
= stats
.obytes
;
799 /* Allocate memory for wrapper */
800 head
= malloc(sizeof (dladm_stat_chain_t
));
802 free(tx_lane_stat_entry
);
806 head
->dc_statentry
= tx_lane_stat_entry
;
807 head
->dc_next
= NULL
;
813 * Ideally, we would want an ioctl to return list of ring-ids (or lane-ids)
814 * for a given data-link (or mac client). We could then query for specific
815 * kstats based on these ring-ids (lane-ids).
816 * Ring-ids (or lane-ids) could be returned like any other link properties
817 * queried by dladm show-linkprop. However, non-global zones do not have
818 * access to this information today.
819 * We thus opt for an implementation that relies heavily on kstat internals:
820 * i_dlstat_*search routines and i_dlstat_get_idlist.
822 /* rx hwlane specific */
824 i_dlstat_rx_hwlane_search(kstat_t
*ksp
)
826 return (ksp
->ks_instance
== 0 &&
827 strstr(ksp
->ks_name
, "mac_rx") != 0 &&
828 strstr(ksp
->ks_name
, "hwlane") != 0 &&
829 strstr(ksp
->ks_name
, "fanout") == 0 &&
830 strcmp(ksp
->ks_class
, "net") == 0);
833 /* tx hwlane specific */
835 i_dlstat_tx_hwlane_search(kstat_t
*ksp
)
837 return (ksp
->ks_instance
== 0 &&
838 strstr(ksp
->ks_name
, "mac_tx") != 0 &&
839 strstr(ksp
->ks_name
, "hwlane") != 0 &&
840 strcmp(ksp
->ks_class
, "net") == 0);
843 /* rx fanout specific */
845 i_dlstat_fanout_search(kstat_t
*ksp
)
847 return (ksp
->ks_instance
== 0 &&
848 strstr(ksp
->ks_name
, "mac_rx") != 0 &&
849 strstr(ksp
->ks_name
, "swlane") != 0 &&
850 strstr(ksp
->ks_name
, "fanout") != 0 &&
851 strcmp(ksp
->ks_class
, "net") == 0);
854 /* rx ring specific */
856 i_dlstat_rx_ring_search(kstat_t
*ksp
)
858 return (ksp
->ks_instance
== 0 &&
859 strstr(ksp
->ks_name
, "mac_rx") != 0 &&
860 strstr(ksp
->ks_name
, "ring") != 0 &&
861 strcmp(ksp
->ks_class
, "net") == 0);
864 /* tx ring specific */
866 i_dlstat_tx_ring_search(kstat_t
*ksp
)
868 return (ksp
->ks_instance
== 0) &&
869 strstr(ksp
->ks_name
, "mac_tx") != 0 &&
870 strstr(ksp
->ks_name
, "ring") != 0 &&
871 strcmp(ksp
->ks_class
, "net") == 0;
874 typedef boolean_t
dladm_search_kstat_t(kstat_t
*);
875 typedef struct dladm_extract_idlist_s
{
876 dlstat_idlist_type_t di_type
;
878 dladm_search_kstat_t
*di_searchkstat
;
879 } dladm_extract_idlist_t
;
881 static dladm_extract_idlist_t dladm_extract_idlist
[] = {
882 { DLSTAT_RX_RING_IDLIST
, DLSTAT_MAC_RX_RING
,
883 i_dlstat_rx_ring_search
},
884 { DLSTAT_TX_RING_IDLIST
, DLSTAT_MAC_TX_RING
,
885 i_dlstat_tx_ring_search
},
886 { DLSTAT_RX_HWLANE_IDLIST
, DLSTAT_MAC_RX_HWLANE
,
887 i_dlstat_rx_hwlane_search
},
888 { DLSTAT_TX_HWLANE_IDLIST
, DLSTAT_MAC_TX_HWLANE
,
889 i_dlstat_tx_hwlane_search
},
890 { DLSTAT_FANOUT_IDLIST
, DLSTAT_MAC_FANOUT
,
891 i_dlstat_fanout_search
}
895 i_dlstat_get_idlist(const char *modname
, dlstat_idlist_type_t idlist_type
,
896 uint_t idlist
[], uint_t
*size
)
902 boolean_t (*fptr_searchkstat
)(kstat_t
*);
906 if ((kcp
= kstat_open()) == NULL
) {
907 warn("kstat_open operation failed");
911 prefix
= dladm_extract_idlist
[idlist_type
].di_prefix
;
912 fptr_searchkstat
= dladm_extract_idlist
[idlist_type
].di_searchkstat
;
913 prefixlen
= strlen(prefix
);
914 for (ksp
= kcp
->kc_chain
; ksp
!= NULL
; ksp
= ksp
->ks_next
) {
915 if ((strcmp(ksp
->ks_module
, modname
) == 0) &&
916 fptr_searchkstat(ksp
)) {
917 idlist
[(*size
)++] = atoi(&ksp
->ks_name
[prefixlen
]);
920 dladm_sort_index_list(idlist
, *size
);
923 (void) kstat_close(kcp
);
926 static dladm_stat_chain_t
*
927 i_dlstat_query_stats(const char *modname
, const char *prefix
,
928 uint_t idlist
[], uint_t idlist_size
,
929 void * (*fn
)(kstat_ctl_t
*, kstat_t
*, int))
933 char statname
[MAXLINKNAMELEN
];
935 dladm_stat_chain_t
*head
= NULL
, *prev
= NULL
;
936 dladm_stat_chain_t
*curr
;
938 if ((kcp
= kstat_open()) == NULL
) {
939 warn("kstat_open operation failed");
943 for (i
= 0; i
< idlist_size
; i
++) {
944 uint_t index
= idlist
[i
];
946 (void) snprintf(statname
, sizeof (statname
), "%s%d", prefix
,
949 ksp
= dladm_kstat_lookup(kcp
, modname
, 0, statname
, NULL
);
953 curr
= malloc(sizeof (dladm_stat_chain_t
));
957 curr
->dc_statentry
= fn(kcp
, ksp
, index
);
958 if (curr
->dc_statentry
== NULL
) {
963 (void) strlcpy(curr
->dc_statheader
, statname
,
964 sizeof (curr
->dc_statheader
));
965 curr
->dc_next
= NULL
;
967 if (head
== NULL
) /* First node */
970 prev
->dc_next
= curr
;
975 (void) kstat_close(kcp
);
979 static misc_stat_entry_t
*
980 i_dlstat_misc_stats(const char *linkname
)
984 misc_stat_entry_t
*misc_stat_entry
= NULL
;
986 if ((kcp
= kstat_open()) == NULL
)
989 ksp
= dladm_kstat_lookup(kcp
, linkname
, 0, DLSTAT_MAC_MISC_STAT
, NULL
);
993 misc_stat_entry
= calloc(1, sizeof (misc_stat_entry_t
));
994 if (misc_stat_entry
== NULL
)
997 i_dlstat_get_stats(kcp
, ksp
, &misc_stat_entry
->mse_stats
,
998 misc_stats_list
, MISC_STAT_SIZE
);
1000 (void) kstat_close(kcp
);
1001 return (misc_stat_entry
);
1004 /* Rx lane statistic specific functions */
1006 i_dlstat_rx_lane_match(void *arg1
, void *arg2
)
1008 rx_lane_stat_entry_t
*s1
= arg1
;
1009 rx_lane_stat_entry_t
*s2
= arg2
;
1011 return (s1
->rle_index
== s2
->rle_index
&&
1012 s1
->rle_id
== s2
->rle_id
);
1016 i_dlstat_rx_lane_stat_entry_diff(void *arg1
, void *arg2
)
1018 rx_lane_stat_entry_t
*s1
= arg1
;
1019 rx_lane_stat_entry_t
*s2
= arg2
;
1020 rx_lane_stat_entry_t
*diff_entry
;
1022 diff_entry
= malloc(sizeof (rx_lane_stat_entry_t
));
1023 if (diff_entry
== NULL
)
1026 diff_entry
->rle_index
= s1
->rle_index
;
1027 diff_entry
->rle_id
= s1
->rle_id
;
1029 DLSTAT_DIFF_STAT(s1
, s2
, diff_entry
, rle_stats
, rx_lane_stats_list
,
1033 return (diff_entry
);
1037 i_dlstat_rx_hwlane_retrieve_stat(kstat_ctl_t
*kcp
, kstat_t
*ksp
, int i
)
1039 rx_lane_stat_entry_t
*rx_lane_stat_entry
;
1041 rx_lane_stat_entry
= calloc(1, sizeof (rx_lane_stat_entry_t
));
1042 if (rx_lane_stat_entry
== NULL
)
1045 rx_lane_stat_entry
->rle_index
= i
;
1046 rx_lane_stat_entry
->rle_id
= L_HWLANE
;
1048 i_dlstat_get_stats(kcp
, ksp
, &rx_lane_stat_entry
->rle_stats
,
1049 rx_hwlane_stats_list
, RX_HWLANE_STAT_SIZE
);
1052 return (rx_lane_stat_entry
);
1057 i_dlstat_rx_swlane_retrieve_stat(kstat_ctl_t
*kcp
, kstat_t
*ksp
, int i
)
1059 rx_lane_stat_entry_t
*rx_lane_stat_entry
;
1061 rx_lane_stat_entry
= calloc(1, sizeof (rx_lane_stat_entry_t
));
1062 if (rx_lane_stat_entry
== NULL
)
1065 rx_lane_stat_entry
->rle_index
= DLSTAT_INVALID_ENTRY
;
1066 rx_lane_stat_entry
->rle_id
= L_SWLANE
;
1068 i_dlstat_get_stats(kcp
, ksp
, &rx_lane_stat_entry
->rle_stats
,
1069 rx_swlane_stats_list
, RX_SWLANE_STAT_SIZE
);
1071 rx_lane_stat_entry
->rle_stats
.rl_ipackets
=
1072 rx_lane_stat_entry
->rle_stats
.rl_intrs
;
1073 rx_lane_stat_entry
->rle_stats
.rl_rbytes
=
1074 rx_lane_stat_entry
->rle_stats
.rl_intrbytes
;
1076 return (rx_lane_stat_entry
);
1081 i_dlstat_rx_local_retrieve_stat(kstat_ctl_t
*kcp
, kstat_t
*ksp
, int i
)
1083 rx_lane_stat_entry_t
*local_stat_entry
;
1084 rx_lane_stat_entry_t
*rx_lane_stat_entry
;
1086 rx_lane_stat_entry
= calloc(1, sizeof (rx_lane_stat_entry_t
));
1087 if (rx_lane_stat_entry
== NULL
)
1090 local_stat_entry
= calloc(1, sizeof (rx_lane_stat_entry_t
));
1091 if (local_stat_entry
== NULL
)
1094 local_stat_entry
->rle_index
= DLSTAT_INVALID_ENTRY
;
1095 local_stat_entry
->rle_id
= L_LOCAL
;
1097 i_dlstat_get_stats(kcp
, ksp
, &rx_lane_stat_entry
->rle_stats
,
1098 rx_swlane_stats_list
, RX_SWLANE_STAT_SIZE
);
1100 local_stat_entry
->rle_stats
.rl_ipackets
=
1101 rx_lane_stat_entry
->rle_stats
.rl_lclpackets
;
1102 local_stat_entry
->rle_stats
.rl_rbytes
=
1103 rx_lane_stat_entry
->rle_stats
.rl_lclbytes
;
1106 free(rx_lane_stat_entry
);
1107 return (local_stat_entry
);
1110 static dladm_stat_chain_t
*
1111 i_dlstat_rx_local_stats(const char *linkname
)
1113 dladm_stat_chain_t
*local_stats
= NULL
;
1115 local_stats
= i_dlstat_query_stats(linkname
, DLSTAT_MAC_RX_SWLANE
,
1116 default_idlist
, default_idlist_size
,
1117 i_dlstat_rx_local_retrieve_stat
);
1119 if (local_stats
!= NULL
) {
1120 (void) strlcpy(local_stats
->dc_statheader
, "mac_rx_local",
1121 sizeof (local_stats
->dc_statheader
));
1123 return (local_stats
);
1126 static dladm_stat_chain_t
*
1127 i_dlstat_rx_bcast_stats(const char *linkname
)
1129 misc_stat_entry_t
*misc_stat_entry
;
1130 dladm_stat_chain_t
*head
= NULL
;
1131 rx_lane_stat_entry_t
*rx_lane_stat_entry
;
1133 misc_stat_entry
= i_dlstat_misc_stats(linkname
);
1134 if (misc_stat_entry
== NULL
)
1137 rx_lane_stat_entry
= calloc(1, sizeof (rx_lane_stat_entry_t
));
1138 if (rx_lane_stat_entry
== NULL
)
1141 rx_lane_stat_entry
->rle_index
= DLSTAT_INVALID_ENTRY
;
1142 rx_lane_stat_entry
->rle_id
= L_BCAST
;
1144 rx_lane_stat_entry
->rle_stats
.rl_ipackets
=
1145 misc_stat_entry
->mse_stats
.ms_brdcstrcv
+
1146 misc_stat_entry
->mse_stats
.ms_multircv
;
1147 rx_lane_stat_entry
->rle_stats
.rl_intrs
=
1148 misc_stat_entry
->mse_stats
.ms_brdcstrcv
+
1149 misc_stat_entry
->mse_stats
.ms_multircv
;
1150 rx_lane_stat_entry
->rle_stats
.rl_rbytes
=
1151 misc_stat_entry
->mse_stats
.ms_brdcstrcvbytes
+
1152 misc_stat_entry
->mse_stats
.ms_multircvbytes
;
1154 head
= malloc(sizeof (dladm_stat_chain_t
));
1156 free(rx_lane_stat_entry
);
1160 head
->dc_statentry
= rx_lane_stat_entry
;
1161 head
->dc_next
= NULL
;
1163 free(misc_stat_entry
);
1168 static dladm_stat_chain_t
*
1169 i_dlstat_rx_defunctlane_stats(const char *linkname
)
1171 misc_stat_entry_t
*misc_stat_entry
;
1172 dladm_stat_chain_t
*head
= NULL
;
1173 rx_lane_stat_entry_t
*rx_lane_stat_entry
;
1175 misc_stat_entry
= i_dlstat_misc_stats(linkname
);
1176 if (misc_stat_entry
== NULL
)
1179 rx_lane_stat_entry
= calloc(1, sizeof (rx_lane_stat_entry_t
));
1180 if (rx_lane_stat_entry
== NULL
)
1183 rx_lane_stat_entry
->rle_index
= DLSTAT_INVALID_ENTRY
;
1184 rx_lane_stat_entry
->rle_id
= L_DFNCT
;
1186 rx_lane_stat_entry
->rle_stats
.rl_ipackets
=
1187 misc_stat_entry
->mse_stats
.ms_ipackets
;
1188 rx_lane_stat_entry
->rle_stats
.rl_rbytes
=
1189 misc_stat_entry
->mse_stats
.ms_rbytes
;
1190 rx_lane_stat_entry
->rle_stats
.rl_intrs
=
1191 misc_stat_entry
->mse_stats
.ms_intrs
;
1192 rx_lane_stat_entry
->rle_stats
.rl_polls
=
1193 misc_stat_entry
->mse_stats
.ms_polls
;
1194 rx_lane_stat_entry
->rle_stats
.rl_sdrops
=
1195 misc_stat_entry
->mse_stats
.ms_rxsdrops
;
1196 rx_lane_stat_entry
->rle_stats
.rl_chl10
=
1197 misc_stat_entry
->mse_stats
.ms_chainunder10
;
1198 rx_lane_stat_entry
->rle_stats
.rl_ch10_50
=
1199 misc_stat_entry
->mse_stats
.ms_chain10to50
;
1200 rx_lane_stat_entry
->rle_stats
.rl_chg50
=
1201 misc_stat_entry
->mse_stats
.ms_chainover50
;
1203 head
= malloc(sizeof (dladm_stat_chain_t
));
1205 free(rx_lane_stat_entry
);
1209 head
->dc_statentry
= rx_lane_stat_entry
;
1210 head
->dc_next
= NULL
;
1216 static dladm_stat_chain_t
*
1217 i_dlstat_rx_hwlane_stats(const char *linkname
)
1219 uint_t rx_hwlane_idlist
[MAX_RINGS_PER_GROUP
];
1220 uint_t rx_hwlane_idlist_size
;
1222 i_dlstat_get_idlist(linkname
, DLSTAT_RX_HWLANE_IDLIST
,
1223 rx_hwlane_idlist
, &rx_hwlane_idlist_size
);
1225 return (i_dlstat_query_stats(linkname
, DLSTAT_MAC_RX_HWLANE
,
1226 rx_hwlane_idlist
, rx_hwlane_idlist_size
,
1227 i_dlstat_rx_hwlane_retrieve_stat
));
1231 static dladm_stat_chain_t
*
1232 i_dlstat_rx_swlane_stats(dladm_handle_t dh
, datalink_id_t linkid
,
1233 const char *linkname
)
1235 return (i_dlstat_query_stats(linkname
, DLSTAT_MAC_RX_SWLANE
,
1236 default_idlist
, default_idlist_size
,
1237 i_dlstat_rx_swlane_retrieve_stat
));
1241 dlstat_rx_lane_stats(dladm_handle_t dh
, datalink_id_t linkid
)
1243 dladm_stat_chain_t
*head
= NULL
;
1244 dladm_stat_chain_t
*local_stats
= NULL
;
1245 dladm_stat_chain_t
*bcast_stats
= NULL
;
1246 dladm_stat_chain_t
*defunctlane_stats
= NULL
;
1247 dladm_stat_chain_t
*lane_stats
= NULL
;
1248 char linkname
[MAXLINKNAMELEN
];
1249 boolean_t is_legacy_driver
;
1251 if (dladm_datalink_id2info(dh
, linkid
, NULL
, NULL
, NULL
, linkname
,
1252 DLPI_LINKNAME_MAX
) != DLADM_STATUS_OK
) {
1256 /* Check if it is legacy driver */
1257 if (dladm_linkprop_is_set(dh
, linkid
, DLADM_PROP_VAL_CURRENT
,
1258 "_softmac", &is_legacy_driver
) != DLADM_STATUS_OK
) {
1262 if (is_legacy_driver
) {
1263 head
= i_dlstat_legacy_rx_lane_stats(linkname
);
1267 local_stats
= i_dlstat_rx_local_stats(linkname
);
1268 bcast_stats
= i_dlstat_rx_bcast_stats(linkname
);
1269 defunctlane_stats
= i_dlstat_rx_defunctlane_stats(linkname
);
1270 lane_stats
= i_dlstat_rx_hwlane_stats(linkname
);
1271 if (lane_stats
== NULL
)
1272 lane_stats
= i_dlstat_rx_swlane_stats(dh
, linkid
, linkname
);
1274 head
= i_dlstat_join_lists(local_stats
, bcast_stats
);
1275 head
= i_dlstat_join_lists(head
, defunctlane_stats
);
1276 head
= i_dlstat_join_lists(head
, lane_stats
);
1281 /* Tx lane statistic specific functions */
1283 i_dlstat_tx_lane_match(void *arg1
, void *arg2
)
1285 tx_lane_stat_entry_t
*s1
= arg1
;
1286 tx_lane_stat_entry_t
*s2
= arg2
;
1288 return (s1
->tle_index
== s2
->tle_index
&&
1289 s1
->tle_id
== s2
->tle_id
);
1293 i_dlstat_tx_lane_stat_entry_diff(void *arg1
, void *arg2
)
1295 tx_lane_stat_entry_t
*s1
= arg1
;
1296 tx_lane_stat_entry_t
*s2
= arg2
;
1297 tx_lane_stat_entry_t
*diff_entry
;
1299 diff_entry
= malloc(sizeof (tx_lane_stat_entry_t
));
1300 if (diff_entry
== NULL
)
1303 diff_entry
->tle_index
= s1
->tle_index
;
1304 diff_entry
->tle_id
= s1
->tle_id
;
1306 DLSTAT_DIFF_STAT(s1
, s2
, diff_entry
, tle_stats
, tx_lane_stats_list
,
1310 return (diff_entry
);
1314 i_dlstat_tx_hwlane_retrieve_stat(kstat_ctl_t
*kcp
, kstat_t
*ksp
, int i
)
1316 tx_lane_stat_entry_t
*tx_lane_stat_entry
;
1318 tx_lane_stat_entry
= calloc(1, sizeof (tx_lane_stat_entry_t
));
1319 if (tx_lane_stat_entry
== NULL
)
1322 tx_lane_stat_entry
->tle_index
= i
;
1323 tx_lane_stat_entry
->tle_id
= L_HWLANE
;
1325 i_dlstat_get_stats(kcp
, ksp
, &tx_lane_stat_entry
->tle_stats
,
1326 tx_lane_stats_list
, TX_LANE_STAT_SIZE
);
1329 return (tx_lane_stat_entry
);
1334 i_dlstat_tx_swlane_retrieve_stat(kstat_ctl_t
*kcp
, kstat_t
*ksp
, int i
)
1336 tx_lane_stat_entry_t
*tx_lane_stat_entry
;
1338 tx_lane_stat_entry
= calloc(1, sizeof (tx_lane_stat_entry_t
));
1339 if (tx_lane_stat_entry
== NULL
)
1342 tx_lane_stat_entry
->tle_index
= DLSTAT_INVALID_ENTRY
;
1343 tx_lane_stat_entry
->tle_id
= L_SWLANE
;
1345 i_dlstat_get_stats(kcp
, ksp
, &tx_lane_stat_entry
->tle_stats
,
1346 tx_lane_stats_list
, TX_LANE_STAT_SIZE
);
1349 return (tx_lane_stat_entry
);
1352 static dladm_stat_chain_t
*
1353 i_dlstat_tx_bcast_stats(const char *linkname
)
1355 misc_stat_entry_t
*misc_stat_entry
;
1356 dladm_stat_chain_t
*head
= NULL
;
1357 tx_lane_stat_entry_t
*tx_lane_stat_entry
;
1359 misc_stat_entry
= i_dlstat_misc_stats(linkname
);
1360 if (misc_stat_entry
== NULL
)
1363 tx_lane_stat_entry
= calloc(1, sizeof (tx_lane_stat_entry_t
));
1364 if (tx_lane_stat_entry
== NULL
)
1367 tx_lane_stat_entry
->tle_index
= DLSTAT_INVALID_ENTRY
;
1368 tx_lane_stat_entry
->tle_id
= L_BCAST
;
1370 tx_lane_stat_entry
->tle_stats
.tl_opackets
=
1371 misc_stat_entry
->mse_stats
.ms_brdcstxmt
+
1372 misc_stat_entry
->mse_stats
.ms_multixmt
;
1374 tx_lane_stat_entry
->tle_stats
.tl_obytes
=
1375 misc_stat_entry
->mse_stats
.ms_brdcstxmtbytes
+
1376 misc_stat_entry
->mse_stats
.ms_multixmtbytes
;
1378 head
= malloc(sizeof (dladm_stat_chain_t
));
1380 free(tx_lane_stat_entry
);
1384 head
->dc_statentry
= tx_lane_stat_entry
;
1385 head
->dc_next
= NULL
;
1387 free(misc_stat_entry
);
1392 static dladm_stat_chain_t
*
1393 i_dlstat_tx_defunctlane_stats(const char *linkname
)
1395 misc_stat_entry_t
*misc_stat_entry
;
1396 dladm_stat_chain_t
*head
= NULL
;
1397 tx_lane_stat_entry_t
*tx_lane_stat_entry
;
1399 misc_stat_entry
= i_dlstat_misc_stats(linkname
);
1400 if (misc_stat_entry
== NULL
)
1403 tx_lane_stat_entry
= calloc(1, sizeof (tx_lane_stat_entry_t
));
1404 if (tx_lane_stat_entry
== NULL
)
1407 tx_lane_stat_entry
->tle_index
= DLSTAT_INVALID_ENTRY
;
1408 tx_lane_stat_entry
->tle_id
= L_DFNCT
;
1410 tx_lane_stat_entry
->tle_stats
.tl_opackets
=
1411 misc_stat_entry
->mse_stats
.ms_opackets
;
1412 tx_lane_stat_entry
->tle_stats
.tl_obytes
=
1413 misc_stat_entry
->mse_stats
.ms_obytes
;
1414 tx_lane_stat_entry
->tle_stats
.tl_sdrops
=
1415 misc_stat_entry
->mse_stats
.ms_txsdrops
;
1417 head
= malloc(sizeof (dladm_stat_chain_t
));
1419 free(tx_lane_stat_entry
);
1423 head
->dc_statentry
= tx_lane_stat_entry
;
1424 head
->dc_next
= NULL
;
1430 static dladm_stat_chain_t
*
1431 i_dlstat_tx_hwlane_stats(const char *linkname
)
1433 uint_t tx_hwlane_idlist
[MAX_RINGS_PER_GROUP
];
1434 uint_t tx_hwlane_idlist_size
;
1436 i_dlstat_get_idlist(linkname
, DLSTAT_TX_HWLANE_IDLIST
,
1437 tx_hwlane_idlist
, &tx_hwlane_idlist_size
);
1439 return (i_dlstat_query_stats(linkname
, DLSTAT_MAC_TX_HWLANE
,
1440 tx_hwlane_idlist
, tx_hwlane_idlist_size
,
1441 i_dlstat_tx_hwlane_retrieve_stat
));
1445 static dladm_stat_chain_t
*
1446 i_dlstat_tx_swlane_stats(dladm_handle_t dh
, datalink_id_t linkid
,
1447 const char *linkname
)
1449 return (i_dlstat_query_stats(linkname
, DLSTAT_MAC_TX_SWLANE
,
1450 default_idlist
, default_idlist_size
,
1451 i_dlstat_tx_swlane_retrieve_stat
));
1455 dlstat_tx_lane_stats(dladm_handle_t dh
, datalink_id_t linkid
)
1457 dladm_stat_chain_t
*head
= NULL
;
1458 dladm_stat_chain_t
*bcast_stats
= NULL
;
1459 dladm_stat_chain_t
*defunctlane_stats
= NULL
;
1460 dladm_stat_chain_t
*lane_stats
;
1461 char linkname
[MAXLINKNAMELEN
];
1462 boolean_t is_legacy_driver
;
1464 if (dladm_datalink_id2info(dh
, linkid
, NULL
, NULL
, NULL
, linkname
,
1465 DLPI_LINKNAME_MAX
) != DLADM_STATUS_OK
) {
1469 /* Check if it is legacy driver */
1470 if (dladm_linkprop_is_set(dh
, linkid
, DLADM_PROP_VAL_CURRENT
,
1471 "_softmac", &is_legacy_driver
) != DLADM_STATUS_OK
) {
1475 if (is_legacy_driver
) {
1476 head
= i_dlstat_legacy_tx_lane_stats(linkname
);
1480 bcast_stats
= i_dlstat_tx_bcast_stats(linkname
);
1481 defunctlane_stats
= i_dlstat_tx_defunctlane_stats(linkname
);
1482 lane_stats
= i_dlstat_tx_hwlane_stats(linkname
);
1483 if (lane_stats
== NULL
)
1484 lane_stats
= i_dlstat_tx_swlane_stats(dh
, linkid
, linkname
);
1486 head
= i_dlstat_join_lists(bcast_stats
, defunctlane_stats
);
1487 head
= i_dlstat_join_lists(head
, lane_stats
);
1493 /* Rx lane total statistic specific functions */
1495 dlstat_rx_lane_total_stats(dladm_handle_t dh
, datalink_id_t linkid
)
1497 dladm_stat_chain_t
*total_head
= NULL
;
1498 dladm_stat_chain_t
*rx_lane_head
, *curr
;
1499 rx_lane_stat_entry_t
*total_stats
;
1501 /* Get per rx lane stats */
1502 rx_lane_head
= dlstat_rx_lane_stats(dh
, linkid
);
1503 if (rx_lane_head
== NULL
)
1506 total_stats
= calloc(1, sizeof (rx_lane_stat_entry_t
));
1507 if (total_stats
== NULL
)
1510 total_stats
->rle_index
= DLSTAT_INVALID_ENTRY
;
1511 total_stats
->rle_id
= DLSTAT_INVALID_ENTRY
;
1513 for (curr
= rx_lane_head
; curr
!= NULL
; curr
= curr
->dc_next
) {
1514 rx_lane_stat_entry_t
*curr_lane_stats
= curr
->dc_statentry
;
1516 i_dlstat_sum_stats(&total_stats
->rle_stats
,
1517 &curr_lane_stats
->rle_stats
, &total_stats
->rle_stats
,
1518 rx_lane_stats_list
, RX_LANE_STAT_SIZE
);
1521 total_head
= malloc(sizeof (dladm_stat_chain_t
));
1522 if (total_head
== NULL
) {
1527 total_head
->dc_statentry
= total_stats
;
1528 (void) strlcpy(total_head
->dc_statheader
, "mac_rx_lane_total",
1529 sizeof (total_head
->dc_statheader
));
1530 total_head
->dc_next
= NULL
;
1534 return (total_head
);
1537 /* Tx lane total statistic specific functions */
1539 dlstat_tx_lane_total_stats(dladm_handle_t dh
, datalink_id_t linkid
)
1541 dladm_stat_chain_t
*total_head
= NULL
;
1542 dladm_stat_chain_t
*tx_lane_head
, *curr
;
1543 tx_lane_stat_entry_t
*total_stats
;
1545 /* Get per tx lane stats */
1546 tx_lane_head
= dlstat_tx_lane_stats(dh
, linkid
);
1547 if (tx_lane_head
== NULL
)
1550 total_stats
= calloc(1, sizeof (tx_lane_stat_entry_t
));
1551 if (total_stats
== NULL
)
1554 total_stats
->tle_index
= DLSTAT_INVALID_ENTRY
;
1555 total_stats
->tle_id
= DLSTAT_INVALID_ENTRY
;
1557 for (curr
= tx_lane_head
; curr
!= NULL
; curr
= curr
->dc_next
) {
1558 tx_lane_stat_entry_t
*curr_lane_stats
= curr
->dc_statentry
;
1560 i_dlstat_sum_stats(&total_stats
->tle_stats
,
1561 &curr_lane_stats
->tle_stats
, &total_stats
->tle_stats
,
1562 tx_lane_stats_list
, TX_LANE_STAT_SIZE
);
1565 total_head
= malloc(sizeof (dladm_stat_chain_t
));
1566 if (total_head
== NULL
) {
1571 total_head
->dc_statentry
= total_stats
;
1572 (void) strlcpy(total_head
->dc_statheader
, "mac_tx_lane_total",
1573 sizeof (total_head
->dc_statheader
));
1574 total_head
->dc_next
= NULL
;
1578 return (total_head
);
1581 /* Fanout specific functions */
1583 i_dlstat_fanout_match(void *arg1
, void *arg2
)
1585 fanout_stat_entry_t
*s1
= arg1
;
1586 fanout_stat_entry_t
*s2
= arg2
;
1588 return (s1
->fe_index
== s2
->fe_index
&&
1589 s1
->fe_id
== s2
->fe_id
&&
1590 s1
->fe_foutindex
== s2
->fe_foutindex
);
1594 i_dlstat_fanout_stat_entry_diff(void *arg1
, void *arg2
)
1596 fanout_stat_entry_t
*s1
= arg1
;
1597 fanout_stat_entry_t
*s2
= arg2
;
1598 fanout_stat_entry_t
*diff_entry
;
1600 diff_entry
= malloc(sizeof (fanout_stat_entry_t
));
1601 if (diff_entry
== NULL
)
1604 diff_entry
->fe_index
= s1
->fe_index
;
1605 diff_entry
->fe_id
= s1
->fe_id
;
1606 diff_entry
->fe_foutindex
= s1
->fe_foutindex
;
1608 DLSTAT_DIFF_STAT(s1
, s2
, diff_entry
, fe_stats
, fanout_stats_list
,
1612 return (diff_entry
);
1616 i_dlstat_fanout_retrieve_stat(kstat_ctl_t
*kcp
, kstat_t
*ksp
, int i
)
1618 fanout_stat_entry_t
*fanout_stat_entry
;
1620 fanout_stat_entry
= calloc(1, sizeof (fanout_stat_entry_t
));
1621 if (fanout_stat_entry
== NULL
)
1624 /* Set by the caller later */
1625 fanout_stat_entry
->fe_index
= DLSTAT_INVALID_ENTRY
;
1626 fanout_stat_entry
->fe_id
= DLSTAT_INVALID_ENTRY
;
1628 fanout_stat_entry
->fe_foutindex
= i
;
1630 i_dlstat_get_stats(kcp
, ksp
, &fanout_stat_entry
->fe_stats
,
1631 fanout_stats_list
, FANOUT_STAT_SIZE
);
1634 return (fanout_stat_entry
);
1638 i_dlstat_query_fanout_stats(dladm_handle_t dh
, datalink_id_t linkid
,
1639 uint_t idlist
[], uint_t idlist_size
,
1640 const char *modname
, const char *prefix
)
1643 char statprefix
[MAXLINKNAMELEN
];
1644 char linkname
[MAXLINKNAMELEN
];
1645 dladm_stat_chain_t
*curr
, *curr_head
;
1646 dladm_stat_chain_t
*head
= NULL
, *prev
= NULL
;
1647 uint_t fanout_idlist
[MAX_RINGS_PER_GROUP
];
1648 uint_t fanout_idlist_size
;
1650 if (dladm_datalink_id2info(dh
, linkid
, NULL
, NULL
, NULL
, linkname
,
1651 DLPI_LINKNAME_MAX
) != DLADM_STATUS_OK
) {
1655 i_dlstat_get_idlist(linkname
, DLSTAT_FANOUT_IDLIST
,
1656 fanout_idlist
, &fanout_idlist_size
);
1658 for (i
= 0; i
< idlist_size
; i
++) {
1659 uint_t index
= idlist
[i
];
1661 (void) snprintf(statprefix
, sizeof (statprefix
), "%s%d_fanout",
1664 curr_head
= i_dlstat_query_stats(modname
, statprefix
,
1665 fanout_idlist
, fanout_idlist_size
,
1666 i_dlstat_fanout_retrieve_stat
);
1668 if (curr_head
== NULL
) /* Last lane */
1671 if (head
== NULL
) /* First lane */
1673 else /* Link new lane list to end of previous lane list */
1674 prev
->dc_next
= curr_head
;
1676 /* Walk new lane list and set ids */
1677 for (curr
= curr_head
; curr
!= NULL
; curr
= curr
->dc_next
) {
1678 fanout_stat_entry_t
*curr_stats
= curr
->dc_statentry
;
1680 curr_stats
->fe_index
= index
;
1681 curr_stats
->fe_id
= L_HWLANE
;
1683 * Save last pointer of previous linked list.
1684 * This pointer is used to chain linked lists
1685 * generated in each iteration.
1695 dlstat_fanout_swlane_and_local_stats(dladm_handle_t dh
, datalink_id_t linkid
,
1696 const char *linkname
)
1698 return (i_dlstat_query_fanout_stats(dh
, linkid
,
1699 default_idlist
, default_idlist_size
, linkname
,
1700 DLSTAT_MAC_RX_SWLANE
));
1704 dlstat_fanout_hwlane_stats(dladm_handle_t dh
, datalink_id_t linkid
,
1705 const char *linkname
)
1707 uint_t rx_hwlane_idlist
[MAX_RINGS_PER_GROUP
];
1708 uint_t rx_hwlane_idlist_size
;
1710 i_dlstat_get_idlist(linkname
, DLSTAT_RX_HWLANE_IDLIST
,
1711 rx_hwlane_idlist
, &rx_hwlane_idlist_size
);
1713 return (i_dlstat_query_fanout_stats(dh
, linkid
, rx_hwlane_idlist
,
1714 rx_hwlane_idlist_size
, linkname
, DLSTAT_MAC_RX_HWLANE
));
1718 dlstat_fanout_stats(dladm_handle_t dh
, datalink_id_t linkid
)
1720 dladm_stat_chain_t
*head
= NULL
;
1721 dladm_stat_chain_t
*fout_hwlane_stats
;
1722 dladm_stat_chain_t
*fout_swlane_and_local_stats
;
1723 fanout_stat_entry_t
*fout_stats
;
1724 char linkname
[MAXLINKNAMELEN
];
1726 if (dladm_datalink_id2info(dh
, linkid
, NULL
, NULL
, NULL
, linkname
,
1727 DLPI_LINKNAME_MAX
) != DLADM_STATUS_OK
) {
1731 fout_swlane_and_local_stats
=
1732 dlstat_fanout_swlane_and_local_stats(dh
, linkid
, linkname
);
1733 fout_hwlane_stats
= dlstat_fanout_hwlane_stats(dh
, linkid
, linkname
);
1735 if (fout_swlane_and_local_stats
== NULL
) {
1736 head
= fout_hwlane_stats
;
1740 fout_stats
= fout_swlane_and_local_stats
->dc_statentry
;
1742 if (fout_hwlane_stats
!= NULL
) { /* hwlane(s), only local traffic */
1743 fout_stats
->fe_id
= L_LOCAL
;
1744 fout_stats
->fe_index
= DLSTAT_INVALID_ENTRY
;
1745 } else { /* no hwlane, mix of local+sw classified */
1746 fout_stats
->fe_id
= L_LCLSWLANE
;
1747 fout_stats
->fe_index
= DLSTAT_INVALID_ENTRY
;
1750 fout_swlane_and_local_stats
->dc_next
= fout_hwlane_stats
;
1751 head
= fout_swlane_and_local_stats
;
1757 /* Rx ring statistic specific functions */
1759 i_dlstat_rx_ring_match(void *arg1
, void *arg2
)
1761 rx_lane_stat_entry_t
*s1
= arg1
;
1762 rx_lane_stat_entry_t
*s2
= arg2
;
1764 return (s1
->rle_index
== s2
->rle_index
);
1768 i_dlstat_rx_ring_stat_entry_diff(void *arg1
, void *arg2
)
1770 ring_stat_entry_t
*s1
= arg1
;
1771 ring_stat_entry_t
*s2
= arg2
;
1772 ring_stat_entry_t
*diff_entry
;
1774 diff_entry
= malloc(sizeof (ring_stat_entry_t
));
1775 if (diff_entry
== NULL
)
1778 diff_entry
->re_index
= s1
->re_index
;
1780 DLSTAT_DIFF_STAT(s1
, s2
, diff_entry
, re_stats
, rx_ring_stats_list
,
1784 return (diff_entry
);
1788 i_dlstat_rx_ring_retrieve_stat(kstat_ctl_t
*kcp
, kstat_t
*ksp
, int i
)
1790 ring_stat_entry_t
*rx_ring_stat_entry
;
1792 rx_ring_stat_entry
= calloc(1, sizeof (ring_stat_entry_t
));
1793 if (rx_ring_stat_entry
== NULL
)
1796 rx_ring_stat_entry
->re_index
= i
;
1798 i_dlstat_get_stats(kcp
, ksp
, &rx_ring_stat_entry
->re_stats
,
1799 rx_ring_stats_list
, RX_RING_STAT_SIZE
);
1802 return (rx_ring_stat_entry
);
1806 dlstat_rx_ring_stats(dladm_handle_t dh
, datalink_id_t linkid
)
1808 uint_t rx_ring_idlist
[MAX_RINGS_PER_GROUP
];
1809 uint_t rx_ring_idlist_size
;
1810 dladm_phys_attr_t dpa
;
1811 char linkname
[MAXLINKNAMELEN
];
1813 datalink_class_t
class;
1816 * kstats corresponding to physical device rings continue to use
1817 * device names even if the link is renamed using dladm rename-link.
1818 * Thus, given a linkid, we lookup the physical device name.
1819 * However, if an aggr is renamed, kstats corresponding to its
1820 * pseudo rings are renamed as well.
1822 if (dladm_datalink_id2info(dh
, linkid
, NULL
, &class, NULL
, linkname
,
1823 DLPI_LINKNAME_MAX
) != DLADM_STATUS_OK
) {
1827 if (class != DATALINK_CLASS_AGGR
) {
1828 if (dladm_phys_info(dh
, linkid
, &dpa
, DLADM_OPT_ACTIVE
) !=
1832 modname
= dpa
.dp_dev
;
1836 i_dlstat_get_idlist(modname
, DLSTAT_RX_RING_IDLIST
,
1837 rx_ring_idlist
, &rx_ring_idlist_size
);
1839 return (i_dlstat_query_stats(modname
, DLSTAT_MAC_RX_RING
,
1840 rx_ring_idlist
, rx_ring_idlist_size
,
1841 i_dlstat_rx_ring_retrieve_stat
));
1844 /* Tx ring statistic specific functions */
1846 i_dlstat_tx_ring_match(void *arg1
, void *arg2
)
1848 tx_lane_stat_entry_t
*s1
= arg1
;
1849 tx_lane_stat_entry_t
*s2
= arg2
;
1851 return (s1
->tle_index
== s2
->tle_index
);
1855 i_dlstat_tx_ring_stat_entry_diff(void *arg1
, void *arg2
)
1857 ring_stat_entry_t
*s1
= arg1
;
1858 ring_stat_entry_t
*s2
= arg2
;
1859 ring_stat_entry_t
*diff_entry
;
1861 diff_entry
= malloc(sizeof (ring_stat_entry_t
));
1862 if (diff_entry
== NULL
)
1865 diff_entry
->re_index
= s1
->re_index
;
1867 DLSTAT_DIFF_STAT(s1
, s2
, diff_entry
, re_stats
, tx_ring_stats_list
,
1871 return (diff_entry
);
1875 i_dlstat_tx_ring_retrieve_stat(kstat_ctl_t
*kcp
, kstat_t
*ksp
, int i
)
1877 ring_stat_entry_t
*tx_ring_stat_entry
;
1879 tx_ring_stat_entry
= calloc(1, sizeof (ring_stat_entry_t
));
1880 if (tx_ring_stat_entry
== NULL
)
1883 tx_ring_stat_entry
->re_index
= i
;
1885 i_dlstat_get_stats(kcp
, ksp
, &tx_ring_stat_entry
->re_stats
,
1886 tx_ring_stats_list
, TX_RING_STAT_SIZE
);
1889 return (tx_ring_stat_entry
);
1893 dlstat_tx_ring_stats(dladm_handle_t dh
, datalink_id_t linkid
)
1895 uint_t tx_ring_idlist
[MAX_RINGS_PER_GROUP
];
1896 uint_t tx_ring_idlist_size
;
1897 dladm_phys_attr_t dpa
;
1898 char linkname
[MAXLINKNAMELEN
];
1900 datalink_class_t
class;
1903 * kstats corresponding to physical device rings continue to use
1904 * device names even if the link is renamed using dladm rename-link.
1905 * Thus, given a linkid, we lookup the physical device name.
1906 * However, if an aggr is renamed, kstats corresponding to its
1907 * pseudo rings are renamed as well.
1909 if (dladm_datalink_id2info(dh
, linkid
, NULL
, &class, NULL
, linkname
,
1910 DLPI_LINKNAME_MAX
) != DLADM_STATUS_OK
) {
1914 if (class != DATALINK_CLASS_AGGR
) {
1915 if (dladm_phys_info(dh
, linkid
, &dpa
, DLADM_OPT_ACTIVE
) !=
1919 modname
= dpa
.dp_dev
;
1923 i_dlstat_get_idlist(modname
, DLSTAT_TX_RING_IDLIST
,
1924 tx_ring_idlist
, &tx_ring_idlist_size
);
1926 return (i_dlstat_query_stats(modname
, DLSTAT_MAC_TX_RING
,
1927 tx_ring_idlist
, tx_ring_idlist_size
,
1928 i_dlstat_tx_ring_retrieve_stat
));
1931 /* Rx ring total statistic specific functions */
1933 dlstat_rx_ring_total_stats(dladm_handle_t dh
, datalink_id_t linkid
)
1935 dladm_stat_chain_t
*total_head
= NULL
;
1936 dladm_stat_chain_t
*rx_ring_head
, *curr
;
1937 ring_stat_entry_t
*total_stats
;
1939 /* Get per rx ring stats */
1940 rx_ring_head
= dlstat_rx_ring_stats(dh
, linkid
);
1941 if (rx_ring_head
== NULL
)
1944 total_stats
= calloc(1, sizeof (ring_stat_entry_t
));
1945 if (total_stats
== NULL
)
1948 total_stats
->re_index
= DLSTAT_INVALID_ENTRY
;
1950 for (curr
= rx_ring_head
; curr
!= NULL
; curr
= curr
->dc_next
) {
1951 ring_stat_entry_t
*curr_ring_stats
= curr
->dc_statentry
;
1953 i_dlstat_sum_stats(&total_stats
->re_stats
,
1954 &curr_ring_stats
->re_stats
, &total_stats
->re_stats
,
1955 rx_ring_stats_list
, RX_RING_STAT_SIZE
);
1958 total_head
= malloc(sizeof (dladm_stat_chain_t
));
1959 if (total_head
== NULL
) {
1964 total_head
->dc_statentry
= total_stats
;
1965 (void) strlcpy(total_head
->dc_statheader
, "mac_rx_ring_total",
1966 sizeof (total_head
->dc_statheader
));
1967 total_head
->dc_next
= NULL
;
1971 return (total_head
);
1974 /* Tx ring total statistic specific functions */
1976 dlstat_tx_ring_total_stats(dladm_handle_t dh
, datalink_id_t linkid
)
1978 dladm_stat_chain_t
*total_head
= NULL
;
1979 dladm_stat_chain_t
*tx_ring_head
, *curr
;
1980 ring_stat_entry_t
*total_stats
;
1982 /* Get per tx ring stats */
1983 tx_ring_head
= dlstat_tx_ring_stats(dh
, linkid
);
1984 if (tx_ring_head
== NULL
)
1987 total_stats
= calloc(1, sizeof (ring_stat_entry_t
));
1988 if (total_stats
== NULL
)
1991 total_stats
->re_index
= DLSTAT_INVALID_ENTRY
;
1993 for (curr
= tx_ring_head
; curr
!= NULL
; curr
= curr
->dc_next
) {
1994 ring_stat_entry_t
*curr_ring_stats
= curr
->dc_statentry
;
1996 i_dlstat_sum_stats(&total_stats
->re_stats
,
1997 &curr_ring_stats
->re_stats
, &total_stats
->re_stats
,
1998 tx_ring_stats_list
, TX_RING_STAT_SIZE
);
2001 total_head
= malloc(sizeof (dladm_stat_chain_t
));
2002 if (total_head
== NULL
) {
2007 total_head
->dc_statentry
= total_stats
;
2008 (void) strlcpy(total_head
->dc_statheader
, "mac_tx_ring_total",
2009 sizeof (total_head
->dc_statheader
));
2010 total_head
->dc_next
= NULL
;
2014 return (total_head
);
2017 /* Summary statistic specific functions */
2020 i_dlstat_total_match(void *arg1
, void *arg2
)
2022 /* Always single entry for total */
2027 i_dlstat_total_stat_entry_diff(void *arg1
, void *arg2
)
2029 total_stat_entry_t
*s1
= arg1
;
2030 total_stat_entry_t
*s2
= arg2
;
2031 total_stat_entry_t
*diff_entry
;
2033 diff_entry
= malloc(sizeof (total_stat_entry_t
));
2034 if (diff_entry
== NULL
)
2037 DLSTAT_DIFF_STAT(s1
, s2
, diff_entry
, tse_stats
, total_stats_list
,
2041 return (diff_entry
);
2045 dlstat_total_stats(dladm_handle_t dh
, datalink_id_t linkid
)
2047 dladm_stat_chain_t
*head
= NULL
;
2048 dladm_stat_chain_t
*rx_total
;
2049 dladm_stat_chain_t
*tx_total
;
2050 total_stat_entry_t
*total_stat_entry
;
2051 rx_lane_stat_entry_t
*rx_lane_stat_entry
;
2052 tx_lane_stat_entry_t
*tx_lane_stat_entry
;
2054 /* Get total rx lane stats */
2055 rx_total
= dlstat_rx_lane_total_stats(dh
, linkid
);
2056 if (rx_total
== NULL
)
2059 /* Get total tx lane stats */
2060 tx_total
= dlstat_tx_lane_total_stats(dh
, linkid
);
2061 if (tx_total
== NULL
)
2064 /* Build total stat */
2065 total_stat_entry
= calloc(1, sizeof (total_stat_entry_t
));
2066 if (total_stat_entry
== NULL
)
2069 rx_lane_stat_entry
= rx_total
->dc_statentry
;
2070 tx_lane_stat_entry
= tx_total
->dc_statentry
;
2072 /* Extract total rx ipackets, rbytes */
2073 total_stat_entry
->tse_stats
.ts_ipackets
=
2074 rx_lane_stat_entry
->rle_stats
.rl_ipackets
;
2075 total_stat_entry
->tse_stats
.ts_rbytes
=
2076 rx_lane_stat_entry
->rle_stats
.rl_rbytes
;
2078 /* Extract total tx opackets, obytes */
2079 total_stat_entry
->tse_stats
.ts_opackets
=
2080 tx_lane_stat_entry
->tle_stats
.tl_opackets
;
2081 total_stat_entry
->tse_stats
.ts_obytes
=
2082 tx_lane_stat_entry
->tle_stats
.tl_obytes
;
2084 head
= malloc(sizeof (dladm_stat_chain_t
));
2086 free(total_stat_entry
);
2090 head
->dc_statentry
= total_stat_entry
;
2091 (void) strlcpy(head
->dc_statheader
, "mac_lane_total",
2092 sizeof (head
->dc_statheader
));
2093 head
->dc_next
= NULL
;
2101 /* Aggr total statistic(summed across all component ports) specific functions */
2103 dlstat_aggr_total_stats(dladm_stat_chain_t
*head
)
2105 dladm_stat_chain_t
*curr
;
2106 dladm_stat_chain_t
*total_head
;
2107 aggr_port_stat_entry_t
*total_stats
;
2109 total_stats
= calloc(1, sizeof (aggr_port_stat_entry_t
));
2110 if (total_stats
== NULL
)
2113 total_stats
->ape_portlinkid
= DATALINK_INVALID_LINKID
;
2115 for (curr
= head
; curr
!= NULL
; curr
= curr
->dc_next
) {
2116 aggr_port_stat_entry_t
*curr_aggr_port_stats
;
2118 curr_aggr_port_stats
= curr
->dc_statentry
;
2120 i_dlstat_sum_stats(&total_stats
->ape_stats
,
2121 &curr_aggr_port_stats
->ape_stats
, &total_stats
->ape_stats
,
2122 aggr_port_stats_list
, AGGR_PORT_STAT_SIZE
);
2125 total_head
= malloc(sizeof (dladm_stat_chain_t
));
2126 if (total_head
== NULL
) {
2131 total_head
->dc_statentry
= total_stats
;
2132 total_head
->dc_next
= NULL
;
2135 return (total_head
);
2138 /* Aggr port statistic specific functions */
2140 i_dlstat_aggr_port_match(void *arg1
, void *arg2
)
2142 aggr_port_stat_entry_t
*s1
= arg1
;
2143 aggr_port_stat_entry_t
*s2
= arg2
;
2145 return (s1
->ape_portlinkid
== s2
->ape_portlinkid
);
2149 i_dlstat_aggr_port_stat_entry_diff(void *arg1
, void *arg2
)
2151 aggr_port_stat_entry_t
*s1
= arg1
;
2152 aggr_port_stat_entry_t
*s2
= arg2
;
2153 aggr_port_stat_entry_t
*diff_entry
;
2155 diff_entry
= malloc(sizeof (aggr_port_stat_entry_t
));
2156 if (diff_entry
== NULL
)
2159 diff_entry
->ape_portlinkid
= s1
->ape_portlinkid
;
2161 DLSTAT_DIFF_STAT(s1
, s2
, diff_entry
, ape_stats
, aggr_port_stats_list
,
2162 AGGR_PORT_STAT_SIZE
);
2165 return (diff_entry
);
2169 * Query dls stats for the aggr port. This results in query for stats into
2170 * the corresponding device driver.
2172 static aggr_port_stat_entry_t
*
2173 i_dlstat_single_port_stats(const char *portname
, datalink_id_t linkid
)
2177 char module
[DLPI_LINKNAME_MAX
];
2179 aggr_port_stat_entry_t
*aggr_port_stat_entry
= NULL
;
2181 if (dladm_parselink(portname
, module
, &instance
) != DLADM_STATUS_OK
)
2184 if ((kcp
= kstat_open()) == NULL
) {
2185 warn("kstat open operation failed");
2189 ksp
= dladm_kstat_lookup(kcp
, module
, instance
, "mac", NULL
);
2193 aggr_port_stat_entry
= calloc(1, sizeof (aggr_port_stat_entry_t
));
2194 if (aggr_port_stat_entry
== NULL
)
2197 /* Save port's linkid */
2198 aggr_port_stat_entry
->ape_portlinkid
= linkid
;
2200 i_dlstat_get_stats(kcp
, ksp
, &aggr_port_stat_entry
->ape_stats
,
2201 aggr_port_stats_list
, AGGR_PORT_STAT_SIZE
);
2203 (void) kstat_close(kcp
);
2204 return (aggr_port_stat_entry
);
2208 dlstat_aggr_port_stats(dladm_handle_t dh
, datalink_id_t linkid
)
2210 dladm_aggr_grp_attr_t ginfo
;
2212 dladm_aggr_port_attr_t
*portp
;
2213 dladm_phys_attr_t dpa
;
2214 aggr_port_stat_entry_t
*aggr_port_stat_entry
;
2215 dladm_stat_chain_t
*head
= NULL
, *prev
= NULL
, *curr
;
2216 dladm_stat_chain_t
*total_stats
;
2219 bzero(&ginfo
, sizeof (dladm_aggr_grp_attr_t
));
2220 if (dladm_aggr_info(dh
, linkid
, &ginfo
, DLADM_OPT_ACTIVE
)
2223 /* For every port that is member of this aggr do */
2224 for (i
= 0; i
< ginfo
.lg_nports
; i
++) {
2225 portp
= &(ginfo
.lg_ports
[i
]);
2226 if (dladm_phys_info(dh
, portp
->lp_linkid
, &dpa
,
2227 DLADM_OPT_ACTIVE
) != DLADM_STATUS_OK
) {
2231 aggr_port_stat_entry
= i_dlstat_single_port_stats(dpa
.dp_dev
,
2234 /* Create dladm_stat_chain_t object for this stat */
2235 curr
= malloc(sizeof (dladm_stat_chain_t
));
2237 free(aggr_port_stat_entry
);
2240 (void) strlcpy(curr
->dc_statheader
, dpa
.dp_dev
,
2241 sizeof (curr
->dc_statheader
));
2242 curr
->dc_statentry
= aggr_port_stat_entry
;
2243 curr
->dc_next
= NULL
;
2245 /* Chain this aggr port stat entry */
2246 /* head of the stat list */
2250 prev
->dc_next
= curr
;
2255 * Prepend the stat list with cumulative aggr stats i.e. summed over all
2258 total_stats
= dlstat_aggr_total_stats(head
);
2259 if (total_stats
!= NULL
) {
2260 total_stats
->dc_next
= head
;
2265 free(ginfo
.lg_ports
);
2269 /* Misc stat specific functions */
2271 dlstat_misc_stats(dladm_handle_t dh
, datalink_id_t linkid
)
2273 misc_stat_entry_t
*misc_stat_entry
;
2274 dladm_stat_chain_t
*head
= NULL
;
2275 char linkname
[MAXLINKNAMELEN
];
2277 if (dladm_datalink_id2info(dh
, linkid
, NULL
, NULL
, NULL
, linkname
,
2278 DLPI_LINKNAME_MAX
) != DLADM_STATUS_OK
) {
2282 misc_stat_entry
= i_dlstat_misc_stats(linkname
);
2283 if (misc_stat_entry
== NULL
)
2286 head
= malloc(sizeof (dladm_stat_chain_t
));
2288 free(misc_stat_entry
);
2292 head
->dc_statentry
= misc_stat_entry
;
2293 (void) strlcpy(head
->dc_statheader
, "mac_misc_stat",
2294 sizeof (head
->dc_statheader
));
2295 head
->dc_next
= NULL
;
2301 /* Exported functions */
2302 dladm_stat_chain_t
*
2303 dladm_link_stat_query(dladm_handle_t dh
, datalink_id_t linkid
,
2304 dladm_stat_type_t stattype
)
2306 return (dladm_stat_table
[stattype
].ds_querystat(dh
, linkid
));
2309 dladm_stat_chain_t
*
2310 dladm_link_stat_diffchain(dladm_stat_chain_t
*op1
, dladm_stat_chain_t
*op2
,
2311 dladm_stat_type_t stattype
)
2313 dladm_stat_chain_t
*op1_curr
, *op2_curr
;
2314 dladm_stat_chain_t
*diff_curr
;
2315 dladm_stat_chain_t
*diff_prev
= NULL
, *diff_head
= NULL
;
2317 /* Perform op1 - op2, store result in diff */
2318 for (op1_curr
= op1
; op1_curr
!= NULL
; op1_curr
= op1_curr
->dc_next
) {
2319 for (op2_curr
= op2
; op2_curr
!= NULL
;
2320 op2_curr
= op2_curr
->dc_next
) {
2321 if (dlstat_match_stats(op1_curr
->dc_statentry
,
2322 op2_curr
->dc_statentry
, stattype
)) {
2326 diff_curr
= malloc(sizeof (dladm_stat_chain_t
));
2327 if (diff_curr
== NULL
)
2330 diff_curr
->dc_next
= NULL
;
2332 if (op2_curr
== NULL
) {
2333 /* prev iteration did not have this stat entry */
2334 diff_curr
->dc_statentry
=
2335 dlstat_diff_stats(op1_curr
->dc_statentry
,
2338 diff_curr
->dc_statentry
=
2339 dlstat_diff_stats(op1_curr
->dc_statentry
,
2340 op2_curr
->dc_statentry
, stattype
);
2343 if (diff_curr
->dc_statentry
== NULL
) {
2348 if (diff_prev
== NULL
) /* head of the diff stat list */
2349 diff_head
= diff_curr
;
2351 diff_prev
->dc_next
= diff_curr
;
2352 diff_prev
= diff_curr
;
2359 dladm_link_stat_free(dladm_stat_chain_t
*curr
)
2361 while (curr
!= NULL
) {
2362 dladm_stat_chain_t
*tofree
= curr
;
2364 curr
= curr
->dc_next
;
2365 free(tofree
->dc_statentry
);
2370 /* Query all link stats */
2371 static name_value_stat_t
*
2372 i_dlstat_convert_stats(void *stats
, stat_info_t stats_list
[], uint_t size
)
2375 name_value_stat_t
*head_stat
= NULL
, *prev_stat
= NULL
;
2376 name_value_stat_t
*curr_stat
;
2378 for (i
= 0; i
< size
; i
++) {
2379 uint64_t *val
= (void *)
2380 ((uchar_t
*)stats
+ stats_list
[i
].si_offset
);
2382 curr_stat
= calloc(1, sizeof (name_value_stat_t
));
2383 if (curr_stat
== NULL
)
2386 (void) strlcpy(curr_stat
->nv_statname
, stats_list
[i
].si_name
,
2387 sizeof (curr_stat
->nv_statname
));
2388 curr_stat
->nv_statval
= *val
;
2389 curr_stat
->nv_nextstat
= NULL
;
2391 if (head_stat
== NULL
) /* First node */
2392 head_stat
= curr_stat
;
2394 prev_stat
->nv_nextstat
= curr_stat
;
2396 prev_stat
= curr_stat
;
2402 build_nvs_entry(char *statheader
, void *statentry
, dladm_stat_type_t stattype
)
2404 name_value_stat_entry_t
*name_value_stat_entry
;
2405 dladm_stat_desc_t
*stattbl_ptr
;
2408 stattbl_ptr
= &dladm_stat_table
[stattype
];
2410 /* Allocate memory for query all stat entry */
2411 name_value_stat_entry
= calloc(1, sizeof (name_value_stat_entry_t
));
2412 if (name_value_stat_entry
== NULL
)
2415 /* Header for these stat fields */
2416 (void) strlcpy(name_value_stat_entry
->nve_header
, statheader
,
2417 sizeof (name_value_stat_entry
->nve_header
));
2419 /* Extract stat fields from the statentry */
2420 statfields
= (uchar_t
*)statentry
+
2421 dladm_stat_table
[stattype
].ds_offset
;
2423 /* Convert curr_stat to <statname, statval> pair */
2424 name_value_stat_entry
->nve_stats
=
2425 i_dlstat_convert_stats(statfields
,
2426 stattbl_ptr
->ds_statlist
, stattbl_ptr
->ds_statsize
);
2428 return (name_value_stat_entry
);
2432 i_walk_dlstat_chain(dladm_stat_chain_t
*stat_head
, dladm_stat_type_t stattype
)
2434 dladm_stat_chain_t
*curr
;
2435 dladm_stat_chain_t
*nvstat_head
= NULL
, *nvstat_prev
= NULL
;
2436 dladm_stat_chain_t
*nvstat_curr
;
2439 * For every stat in the chain, build header and convert all
2442 for (curr
= stat_head
; curr
!= NULL
; curr
= curr
->dc_next
) {
2443 nvstat_curr
= malloc(sizeof (dladm_stat_chain_t
));
2444 if (nvstat_curr
== NULL
)
2447 nvstat_curr
->dc_statentry
= build_nvs_entry(curr
->dc_statheader
,
2448 curr
->dc_statentry
, stattype
);
2450 if (nvstat_curr
->dc_statentry
== NULL
) {
2455 nvstat_curr
->dc_next
= NULL
;
2457 if (nvstat_head
== NULL
) /* First node */
2458 nvstat_head
= nvstat_curr
;
2460 nvstat_prev
->dc_next
= nvstat_curr
;
2462 nvstat_prev
= nvstat_curr
;
2465 return (nvstat_head
);
2468 dladm_stat_chain_t
*
2469 dladm_link_stat_query_all(dladm_handle_t dh
, datalink_id_t linkid
,
2470 dladm_stat_type_t stattype
)
2472 dladm_stat_chain_t
*stat_head
;
2473 dladm_stat_chain_t
*nvstat_head
= NULL
;
2475 /* Query the requested stat */
2476 stat_head
= dladm_link_stat_query(dh
, linkid
, stattype
);
2477 if (stat_head
== NULL
)
2481 * Convert every statfield in every stat-entry of stat chain to
2482 * <statname, statval> pair
2484 nvstat_head
= i_walk_dlstat_chain(stat_head
, stattype
);
2486 /* Free stat_head */
2487 dladm_link_stat_free(stat_head
);
2490 return (nvstat_head
);
2494 dladm_link_stat_query_all_free(dladm_stat_chain_t
*curr
)
2496 while (curr
!= NULL
) {
2497 dladm_stat_chain_t
*tofree
= curr
;
2498 name_value_stat_entry_t
*nv_entry
= curr
->dc_statentry
;
2499 name_value_stat_t
*nv_curr
= nv_entry
->nve_stats
;
2501 while (nv_curr
!= NULL
) {
2502 name_value_stat_t
*nv_tofree
= nv_curr
;
2504 nv_curr
= nv_curr
->nv_nextstat
;
2508 curr
= curr
->dc_next
;
2514 /* flow stats specific routines */
2516 dladm_flow_stat_query(const char *flowname
)
2520 flow_stat_t
*flow_stat
= NULL
;
2522 if ((kcp
= kstat_open()) == NULL
)
2525 flow_stat
= calloc(1, sizeof (flow_stat_t
));
2526 if (flow_stat
== NULL
)
2529 ksp
= dladm_kstat_lookup(kcp
, NULL
, -1, flowname
, "flow");
2532 i_dlstat_get_stats(kcp
, ksp
, flow_stat
, flow_stats_list
,
2537 (void) kstat_close(kcp
);
2542 dladm_flow_stat_diff(flow_stat_t
*op1
, flow_stat_t
*op2
)
2544 flow_stat_t
*diff_stat
;
2546 diff_stat
= calloc(1, sizeof (flow_stat_t
));
2547 if (diff_stat
== NULL
)
2551 bcopy(op1
, diff_stat
, sizeof (flow_stat_t
));
2553 i_dlstat_diff_stats(diff_stat
, op1
, op2
, flow_stats_list
,
2561 dladm_flow_stat_free(flow_stat_t
*curr
)
2566 /* Query all flow stats */
2567 name_value_stat_entry_t
*
2568 dladm_flow_stat_query_all(const char *flowname
)
2570 flow_stat_t
*flow_stat
;
2571 name_value_stat_entry_t
*name_value_stat_entry
= NULL
;
2573 /* Query flow stats */
2574 flow_stat
= dladm_flow_stat_query(flowname
);
2575 if (flow_stat
== NULL
)
2578 /* Allocate memory for query all stat entry */
2579 name_value_stat_entry
= calloc(1, sizeof (name_value_stat_entry_t
));
2580 if (name_value_stat_entry
== NULL
) {
2581 dladm_flow_stat_free(flow_stat
);
2585 /* Header for these stat fields */
2586 (void) strncpy(name_value_stat_entry
->nve_header
, flowname
,
2589 /* Convert every statfield in flow_stat to <statname, statval> pair */
2590 name_value_stat_entry
->nve_stats
=
2591 i_dlstat_convert_stats(flow_stat
, flow_stats_list
, FLOW_STAT_SIZE
);
2593 /* Free flow_stat */
2594 dladm_flow_stat_free(flow_stat
);
2597 return (name_value_stat_entry
);
2601 dladm_flow_stat_query_all_free(name_value_stat_entry_t
*curr
)
2603 name_value_stat_t
*nv_curr
= curr
->nve_stats
;
2605 while (nv_curr
!= NULL
) {
2606 name_value_stat_t
*nv_tofree
= nv_curr
;
2608 nv_curr
= nv_curr
->nv_nextstat
;