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